Home : I/O Peripherals Library | SPDIF/AES3 Peripheral

Description

<TODO>

Naming Conventions

<TODO>

Interface Functions

<TODO>

Example Usage

<TODO>

Configuration

<TODO>

Source Files

xperipherals_spdif.h SPDIF peripheral interface
xperipherals_spdif_1.xc SPDIF peripheral #1 implementation
xperipherals_spdif_2.xc SPDIF peripheral #2 implementation

Source Listings

xperipherals_spdif.h

#ifndef XPERIPHERALS_SPDIF__INCLUDED
#define XPERIPHERALS_SPDIF__INCLUDED

#include "xsystem_types.h"

// These must be defined in "xconfig.h" for each peripheral bus being used
//
// USES_XPERIPHERALS_SPDIF_n           No value
//
// XPERIPHERALS_SPDIF_n__SUPPORT_TX    TRUE or FALSE
// XPERIPHERALS_SPDIF_n__SUPPORT_RX    TRUE or FALSE
// XPERIPHERALS_SPDIF_n__TILE_NUMBER   integer, XS1 tile number
// XPERIPHERALS_SPDIF_n__TXD_PORT      XS1 port identifier
// XPERIPHERALS_SPDIF_n__RXD_PORT      XS1 port identifier

// Stereo Data Transfer Sequence for One Audio Cycle.
//
// Note: Two transfers (BEG and END) are required to complete a full sample I/O.
// Note: The output data and input data represent the four non-audio bits in the SPDIF sub-frame
//
//   transfer_beg( left  output sample,    left  output data, left  input data ref );
//   transfer_end( left  input sample ref, left  output data, left  input data ref );
//   transfer_beg( right output sample,    right output data, right input data ref );
//   transfer_end( right input sample ref, right output data, right input data ref );
//
//  Stereo Data Transfer Sequence for Combined I2S and SPDIF with Same Sample Rates (One Audio Cycle)

#define XPERIPHERALS_SPDIF__INTERFACE( N ) \
\
void xperipherals_spdif_##N##__initialize  ( void ); \
void xperipherals_spdif_##N##__configure   ( clock bit_clock ); \
void xperipherals_spdif_##N##__transfer_beg( xsint  tx_sample, xuint  tx_data, xuint& rx_data ); \
void xperipherals_spdif_##N##__transfer_end( xsint& rx_sample, xuint  tx_data, xuint& rx_data );

XPERIPHERALS_SPDIF__INTERFACE( 1 )
XPERIPHERALS_SPDIF__INTERFACE( 2 )

#endif

xperipherals_spdif_1.xc

#include <xs1.h>
#include <platform.h>
#include <xclib.h>
#include <print.h>
#include <stdio.h>

#include "xperipherals_spdif.h"

#ifdef XPERIPHERALS_SPDIF_1

extern in port master_audio_clock_port;
extern clock   master_audio_clock_block;

#if XPERIPHERALS_SPDIF_1__SUPPORT_TX
on tile[XPERIPHERALS_SPDIF_1__TILE_NUMBER] :
out buffered port:32 _xperipherals_spdif_1__tx_port = XPERIPHERALS_SPDIF_1__TXD_PORT;
#endif

#if XPERIPHERALS_SPDIF_1__SUPPORT_RX
on tile[XPERIPHERALS_SPDIF_1__TILE_NUMBER] :
in buffered port:32 _xperipherals_spdif_1__rx_port  = XPERIPHERALS_SPDIF_1__RXD_PORT;
#endif

static xuint _xperipherals_spdif_1__frame = 0;
static xuint _xperipherals_spdif_1__tx_flags = 0;
static xuint _xperipherals_spdif_1__rx_flags = 0;
#if XPERIPHERALS_SPDIF_1__SUPPORT_TX
static xuint _xperipherals_spdif_1__tx_data  = 0;
#endif
#if XPERIPHERALS_SPDIF_1__SUPPORT_RX
static xuint _xperipherals_spdif_1__rx_data  = 0;
#endif
static xuint _xperipherals_spdif_1__syncstate = 0;
static xuint _xperipherals_spdif_1__synctime;

#if XPERIPHERALS_SPDIF_1__SUPPORT_TX

xuint _xperipherals_spdif_1__encode[2][16] =
{{
    0b11001100, 0b11001101, 0b11001011, 0b11001010,
    0b11010011, 0b11010010, 0b11010100, 0b11010101,
    0b10110011, 0b10110010, 0b10110100, 0b10110101,
    0b10101100, 0b10101101, 0b10101011, 0b10101010,
},{
    0b00110011, 0b00110010, 0b00110100, 0b00110101,
    0b00101100, 0b00101101, 0b00101011, 0b00101010,
    0b01001100, 0b01001101, 0b01001011, 0b01001010,
    0b01010011, 0b01010010, 0b01010100, 0b01010101,
}};

#endif

xuint _xperipherals_spdif_1__header_1   [2] = {0b11101000, 0b00010111};
xuint _xperipherals_spdif_1__header_N[2][2] = {{0b11100010, 0b00011101},{0b11100100,0b00011011}};

#if XPERIPHERALS_SPDIF_1__SUPPORT_RX

xuint _xperipherals_spdif_1__decode[256] =
{
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0111, 0b0110, 0b0100, 0b0101, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0001, 0b0000, 0b0010, 0b0011, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b1011, 0b1010, 0b1000, 0b1001, 0b0000, 0b0000,
    0b0000, 0b0000, 0b1101, 0b1100, 0b1110, 0b1111, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b1111, 0b1110, 0b1100, 0b1101, 0b0000, 0b0000,
    0b0000, 0b0000, 0b1001, 0b1000, 0b1010, 0b1011, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0011, 0b0010, 0b0000, 0b0001, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0101, 0b0100, 0b0110, 0b0111, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
    0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000, 0b0000,
};

#endif

xbyte _xperipherals_spdif_1__parity[256] =
{
    0,1,1,0,1,0,0,1,  1,0,0,1,0,1,1,0,  1,0,0,1,0,1,1,0,  0,1,1,0,1,0,0,1,
    0,1,1,0,1,0,0,1,  1,0,0,1,0,1,1,0,  1,0,0,1,0,1,1,0,  0,1,1,0,1,0,0,1,
    0,1,1,0,1,0,0,1,  1,0,0,1,0,1,1,0,  1,0,0,1,0,1,1,0,  0,1,1,0,1,0,0,1,
    0,1,1,0,1,0,0,1,  1,0,0,1,0,1,1,0,  1,0,0,1,0,1,1,0,  0,1,1,0,1,0,0,1,
    0,1,1,0,1,0,0,1,  1,0,0,1,0,1,1,0,  1,0,0,1,0,1,1,0,  0,1,1,0,1,0,0,1,
    0,1,1,0,1,0,0,1,  1,0,0,1,0,1,1,0,  1,0,0,1,0,1,1,0,  0,1,1,0,1,0,0,1,
    0,1,1,0,1,0,0,1,  1,0,0,1,0,1,1,0,  1,0,0,1,0,1,1,0,  0,1,1,0,1,0,0,1,
    0,1,1,0,1,0,0,1,  1,0,0,1,0,1,1,0,  1,0,0,1,0,1,1,0,  0,1,1,0,1,0,0,1,
};

xbool _xperipherals_spdif_1__calc_parity( xuint data )
{
    return _xperipherals_spdif_1__parity[ (xbyte)(data >> 24) ] ^
           _xperipherals_spdif_1__parity[ (xbyte)(data >> 16) ] ^
           _xperipherals_spdif_1__parity[ (xbyte)(data >>  8) ] ^
           _xperipherals_spdif_1__parity[ (xbyte)(data >>  0) ];
}

void XPERIPHERALS_spdif_1__initialize( void )
{
    _xperipherals_spdif_1__frame = 0;
    _xperipherals_spdif_1__syncstate = 1;
}

void XPERIPHERALS_spdif_1__configure( clock bit_clock )
{
        #if XPERIPHERALS_SPDIF_1__SUPPORT_TX
    configure_out_port_no_ready( _xperipherals_spdif_1__tx_port, bit_clock, 0 );
    clearbuf( _xperipherals_spdif_1__tx_port );
    #endif
        #if XPERIPHERALS_SPDIF_1__SUPPORT_RX
    configure_in_port_no_ready( _xperipherals_spdif_1__rx_port, bit_clock );
    clearbuf( _xperipherals_spdif_1__rx_port );
    #endif
}

#if XPERIPHERALS_SPDIF_1__SUPPORT_RX

void XPERIPHERALS_spdif_1__synchronize( xuint phase )
{
    _xperipherals_spdif_1__syncstate = 0;
    return;

    if( _xperipherals_spdif_1__syncstate == 1 )
    {
        _xperipherals_spdif_1__rx_port :> _xperipherals_spdif_1__rx_data @ _xperipherals_spdif_1__synctime;
        _xperipherals_spdif_1__synctime += 32;
        _xperipherals_spdif_1__syncstate++;
    }

    // Find a subframe - look for subrame header and skip one clock cycle per sub-frame
    // to account for headers on non 32-bit boundaries.

    else if( _xperipherals_spdif_1__syncstate == 2 )
    {
        _xperipherals_spdif_1__rx_port :> _xperipherals_spdif_1__rx_data @ _xperipherals_spdif_1__synctime;
        _xperipherals_spdif_1__rx_data = bitrev( _xperipherals_spdif_1__rx_data ) >> 24;

        if( _xperipherals_spdif_1__rx_data == 0xE8 || _xperipherals_spdif_1__rx_data == 0xE2 ||
            _xperipherals_spdif_1__rx_data == 0x17 || _xperipherals_spdif_1__rx_data == 0x1D )
        {
            _xperipherals_spdif_1__synctime += 32;
            if( phase != 0 ) _xperipherals_spdif_1__synctime += 32;
            _xperipherals_spdif_1__syncstate = 3;
        }
        else if( _xperipherals_spdif_1__rx_data == 0xE4 || _xperipherals_spdif_1__rx_data == 0x1B )
        {
            _xperipherals_spdif_1__synctime += 32;
            if( phase != 1 ) _xperipherals_spdif_1__synctime += 32;
            _xperipherals_spdif_1__syncstate = 3;
        }
        else _xperipherals_spdif_1__synctime += 33;
    }

    // Traverse sub-frames and synchronize to the first sub-frame (find sub-frame #1)

    else if( _xperipherals_spdif_1__syncstate == 3 )
    {
        _xperipherals_spdif_1__rx_port :> _xperipherals_spdif_1__rx_data @ _xperipherals_spdif_1__synctime;
        _xperipherals_spdif_1__rx_data = bitrev( _xperipherals_spdif_1__rx_data ) >> 24;

        if( phase == 0 && (_xperipherals_spdif_1__rx_data == 0xE8 || _xperipherals_spdif_1__rx_data == 0x17) )
        {
            asm("setpt res[%0], %1"::"r"(_xperipherals_spdif_1__rx_port),"r"(_xperipherals_spdif_1__synctime+32));
            _xperipherals_spdif_1__syncstate = 0;
        }
        _xperipherals_spdif_1__synctime += 32;
    }
}

#endif

// last=0, pre=B, word=000000000000         --> 11101000 11001100 11001100 11001100 = E8CCCCCC
//         pre=B, word=000000000000, f=0001 --> 11100100 11001100 11001100 11001101 = CCCCCCCD
// last=1, pre=W, word=000000000000         --> 00011011 00110011 00110011 00110011 = 1B333333
//         pre=W, word=000000000000, f=0001 --> 00110011 00110011 00110011 00110010 = 33333332
// last=0, pre=M, word=000000000000         --> 11100010 11001100 11001100 11001100 = E2CCCCCC
//         pre=M, word=000000000000, f=0001 --> 11100100 11001100 11001100 11001101 = CCCCCCCD
// last=1, pre=W, word=000000000000         --> 00011011 00110011 00110011 00110011 = 1B333333
//         pre=W, word=000000000000, f=0001 --> 00110011 00110011 00110011 00110010 = 33333332

// last=1, pre=B, word=000000000000         --> 00010111 00110011 00110011 00110011 = 17333333
//         pre=B, word=000000000000, f=0001 --> 00110011 00110011 00110011 00110010 = 33333332
// last=0, pre=W, word=000000000000         --> 11100100 11001100 11001100 11001100 = E4CCCCCC
//         pre=W, word=000000000000, f=0001 --> 11001100 11001100 11001100 11001101 = CCCCCCCD
// last=1, pre=M, word=000000000000         --> 00011101 00110011 00110011 00110011 = 1D333333
//         pre=M, word=000000000000, f=0001 --> 00110011 00110011 00110011 00110010 = 33333332
// last=0, pre=W, word=000000000000         --> 11100100 11001100 11001100 11001100 = E4CCCCCC
//         pre=W, word=000000000000, f=0001 --> 11001100 11001100 11001100 11001101 = CCCCCCCD

void _xperipherals_spdif_1__phase1_write( xuint tx_value )
{
    // Encode and transmit first 32-bit portion of BMC encoded 32-bit word

    #if XPERIPHERALS_SPDIF_1__SUPPORT_TX

    if( _xperipherals_spdif_1__frame == 0 )
        _xperipherals_spdif_1__tx_data = _xperipherals_spdif_1__header_1[_xperipherals_spdif_1__tx_data & 1];

    else _xperipherals_spdif_1__tx_data =
        _xperipherals_spdif_1__header_N[_xperipherals_spdif_1__frame & 1][_xperipherals_spdif_1__tx_data & 1];

    _xperipherals_spdif_1__tx_data =
        (_xperipherals_spdif_1__tx_data << 24) +
        (_xperipherals_spdif_1__encode[_xperipherals_spdif_1__tx_data & 1][(tx_value >> 28) & 15] << 16) +
        (_xperipherals_spdif_1__encode[_xperipherals_spdif_1__tx_data & 1][(tx_value >> 24) & 15] <<  8) +
        (_xperipherals_spdif_1__encode[_xperipherals_spdif_1__tx_data & 1][(tx_value >> 20) & 15] <<  0);

    _xperipherals_spdif_1__tx_port <: bitrev( _xperipherals_spdif_1__tx_data );

    printf( "%05i 1 %08X\n", _xperipherals_spdif_1__frame, _xperipherals_spdif_1__tx_data );

    #endif
}

void _xperipherals_spdif_1__phase2_write( xuint tx_value )
{
    // Encode and transmit second 32-bit portion of BMC encoded 32-bit word

    #if XPERIPHERALS_SPDIF_1__SUPPORT_TX

    _xperipherals_spdif_1__tx_data =
        (_xperipherals_spdif_1__encode[_xperipherals_spdif_1__tx_data & 1][(tx_value >> 16) & 15] << 24) +
        (_xperipherals_spdif_1__encode[_xperipherals_spdif_1__tx_data & 1][(tx_value >> 12) & 15] << 16) +
        (_xperipherals_spdif_1__encode[_xperipherals_spdif_1__tx_data & 1][(tx_value >>  8) & 15] <<  8) +
        (_xperipherals_spdif_1__encode[_xperipherals_spdif_1__tx_data & 1][(tx_value >>  0) & 15] <<  0);

    _xperipherals_spdif_1__tx_port <: bitrev( _xperipherals_spdif_1__tx_data );

    printf( "%05i 2 %08X\n", _xperipherals_spdif_1__frame, _xperipherals_spdif_1__tx_data );

    #endif
}

void _xperipherals_spdif_1__phase1_read( xuint& rx_sample )
{
    // Receive and decode first 32-bit portion of BMC encoded 32-bit word

    #if XPERIPHERALS_SPDIF_1__SUPPORT_RX

    if( _xperipherals_spdif_1__syncstate < 3 ) XPERIPHERALS_spdif_1__synchronize( 0 );
    else
    {
        _xperipherals_spdif_1__rx_port :> _xperipherals_spdif_1__rx_data;
        _xperipherals_spdif_1__rx_data = bitrev( _xperipherals_spdif_1__rx_data );

        //if( (_xperipherals_spdif_1__rx_data >> 28) != 0xE && (_xperipherals_spdif_1__rx_data >> 28) != 0x1 ) {
        //     _xperipherals_spdif_1__syncstate = 1;
        //     return;
        //}

        rx_sample = (_xperipherals_spdif_1__decode[(_xperipherals_spdif_1__rx_data >> 16) & 255] << 28) +
                    (_xperipherals_spdif_1__decode[(_xperipherals_spdif_1__rx_data >>  8) & 255] << 24) +
                    (_xperipherals_spdif_1__decode[(_xperipherals_spdif_1__rx_data >>  0) & 255] << 20);
    }

    #endif
}

void _xperipherals_spdif_1__phase2_read( xuint& rx_sample )
{
    // Receive and decode second 32-bit portion of BMC encoded 32-bit word

    #if XPERIPHERALS_SPDIF_1__SUPPORT_RX

    if( _xperipherals_spdif_1__syncstate < 3 ) XPERIPHERALS_spdif_1__synchronize( 1 );
    else
    {
        _xperipherals_spdif_1__rx_port :> _xperipherals_spdif_1__rx_data;
        _xperipherals_spdif_1__rx_data = bitrev( _xperipherals_spdif_1__rx_data );

        rx_sample += (_xperipherals_spdif_1__decode[(_xperipherals_spdif_1__rx_data >> 24) & 255] << 16) +
                     (_xperipherals_spdif_1__decode[(_xperipherals_spdif_1__rx_data >> 16) & 255] << 12) +
                     (_xperipherals_spdif_1__decode[(_xperipherals_spdif_1__rx_data >>  8) & 255] <<  8);
    }

    #endif
}

xuint _xperipherals_spdif_1__tx_value;
xuint _xperipherals_spdif_1__rx_value;

void XPERIPHERALS_spdif_1__transfer_beg( xsint tx_sample, xuint tx_data, xuint& rx_data )
{
    _xperipherals_spdif_1__tx_value = (tx_sample & ~15) | (tx_data & 15);
    _xperipherals_spdif_1__tx_flags = 1;
    _xperipherals_spdif_1__phase1_write( _xperipherals_spdif_1__tx_value );
    _xperipherals_spdif_1__phase1_read( _xperipherals_spdif_1__rx_value );
}

void XPERIPHERALS_spdif_1__transfer_end( xsint& rx_sample, xuint tx_data, xuint& rx_data )
{
    _xperipherals_spdif_1__phase2_write( _xperipherals_spdif_1__tx_value );
    _xperipherals_spdif_1__phase2_read( _xperipherals_spdif_1__rx_value );
    if( ++_xperipherals_spdif_1__frame == 384 ) _xperipherals_spdif_1__frame = 0;
    rx_sample = _xperipherals_spdif_1__rx_value & ~15;
    rx_data = _xperipherals_spdif_1__rx_value & 15;
}

#endif

xperipherals_spdif_2.xc

#include <xs1.h>
#include <platform.h>
#include <xclib.h>
#include <print.h>

#include "xperipherals_spdif.h"

#ifdef XPERIPHERALS_SPDIF_2

extern in port master_audio_clock_port;
extern clock   master_audio_clock_block;

#if XPERIPHERALS_SPDIF_2__SUPPORT_TX
on tile[XPERIPHERALS_SPDIF_2__TILE_NUMBER] : out buffered port:32 _xperipherals_spdif_2__tx_port = XPERIPHERALS_SPDIF_2__TXD_PORT;
#endif

#if XPERIPHERALS_SPDIF_2__SUPPORT_RX
on tile[XPERIPHERALS_SPDIF_2__TILE_NUMBER] : in buffered port:32 _xperipherals_spdif_2__rx_port  = XPERIPHERALS_SPDIF_2__RXD_PORT;
#endif

static xuint _xperipherals_spdif_2__stage = 0;
static xuint _xperipherals_spdif_2__subframe = 0;
#if XPERIPHERALS_SPDIF_2__SUPPORT_TX
static xuint _xperipherals_spdif_2__tx_data  = 0;
#endif
#if XPERIPHERALS_SPDIF_2__SUPPORT_RX
static xuint _xperipherals_spdif_2__rx_data  = 0;
#endif
static xuint _xperipherals_spdif_2__syncstate = 0;
static xuint _xperipherals_spdif_2__synctime;

#if XPERIPHERALS_SPDIF_2__SUPPORT_TX

static xuint _xperipherals_spdif_2__lut_encode[2][16] =
{{
    0b11001100, 0b11001101, 0b11001011, 0b11001010, 0b11010011, 0b11010010, 0b11010100, 0b11010101,
    0b10110011, 0b10110010, 0b10110100, 0b10110101, 0b10101100, 0b10101101, 0b10101011, 0b10101010,
},{
    0b00110011, 0b00110010, 0b00110100, 0b00110101, 0b00101100, 0b00101101, 0b00101011, 0b00101010,
    0b01001100, 0b01001101, 0b01001011, 0b01001010, 0b01010011, 0b01010010, 0b01010100, 0b01010101,
}};

#endif

static xuint _xperipherals_spdif_2__lut_header_1   [2] = {0b11101000, 0b00010111};
static xuint _xperipherals_spdif_2__lut_header_N[2][2] = {{0b11100010, 0b00011101}, {0b11100100, 0b00011011}};

#if XPERIPHERALS_SPDIF_2__SUPPORT_RX

static xuint _xperipherals_spdif_2__lut_decode[256] =
{
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0111,0b0110,0b0100,0b0101,0b0000,0b0000,
    0b0000,0b0000,0b0001,0b0000,0b0010,0b0011,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b1011,0b1010,0b1000,0b1001,0b0000,0b0000,
    0b0000,0b0000,0b1101,0b1100,0b1110,0b1111,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b1111,0b1110,0b1100,0b1101,0b0000,0b0000,
    0b0000,0b0000,0b1001,0b1000,0b1010,0b1011,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0011,0b0010,0b0000,0b0001,0b0000,0b0000,
    0b0000,0b0000,0b0101,0b0100,0b0110,0b0111,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
    0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000,
};

#endif

void XPERIPHERALS_spdif_2__initialize( void )
{
    _xperipherals_spdif_2__subframe = 0;
    _xperipherals_spdif_2__syncstate = 1;

        #if XPERIPHERALS_SPDIF_2__SUPPORT_TX
    configure_out_port_no_ready( _xperipherals_spdif_2__tx_port, master_audio_clock_block, 0 );
    clearbuf( _xperipherals_spdif_2__tx_port );
    #endif
        #if XPERIPHERALS_SPDIF_2__SUPPORT_RX
    configure_in_port_no_ready( _xperipherals_spdif_2__rx_port, master_audio_clock_block );
    clearbuf( _xperipherals_spdif_2__rx_port );
    #endif
}

#if XPERIPHERALS_SPDIF_2__SUPPORT_RX

static void _xperipherals_spdif_2__synchronize( xuint phase )
{
    _xperipherals_spdif_2__syncstate = 0;
    return;

    if( _xperipherals_spdif_2__syncstate == 1 )
    {
        _xperipherals_spdif_2__rx_port :> _xperipherals_spdif_2__rx_data @ _xperipherals_spdif_2__synctime;
        _xperipherals_spdif_2__synctime += 32;
        _xperipherals_spdif_2__syncstate++;
    }

    // Find a subframe - look for subrame header and skip one clock cycle per sub-frame to account for
    // headers on non 32-bit boundaries.

    else if( _xperipherals_spdif_2__syncstate == 2 )
    {
        _xperipherals_spdif_2__rx_port :> _xperipherals_spdif_2__rx_data @ _xperipherals_spdif_2__synctime;
        _xperipherals_spdif_2__rx_data = bitrev( _xperipherals_spdif_2__rx_data ) >> 24;

        if( _xperipherals_spdif_2__rx_data == 0xE8 || _xperipherals_spdif_2__rx_data == 0xE2 || _xperipherals_spdif_2__rx_data == 0x17 || _xperipherals_spdif_2__rx_data == 0x1D )
        {
            _xperipherals_spdif_2__synctime += 32;
            if( phase != 0 ) _xperipherals_spdif_2__synctime += 32;
            _xperipherals_spdif_2__syncstate = 3;
        }
        else if( _xperipherals_spdif_2__rx_data == 0xE4 || _xperipherals_spdif_2__rx_data == 0x1B )
        {
            _xperipherals_spdif_2__synctime += 32;
            if( phase != 1 ) _xperipherals_spdif_2__synctime += 32;
            _xperipherals_spdif_2__syncstate = 3;
        }
        else _xperipherals_spdif_2__synctime += 33;
    }

    // Traverse sub-frames and synchronize to the first sub-frame (find sub-frame #1)

    else if( _xperipherals_spdif_2__syncstate == 3 )
    {
        _xperipherals_spdif_2__rx_port :> _xperipherals_spdif_2__rx_data @ _xperipherals_spdif_2__synctime;
        _xperipherals_spdif_2__rx_data = bitrev( _xperipherals_spdif_2__rx_data ) >> 24;

        if( phase == 0 && (_xperipherals_spdif_2__rx_data == 0xE8 || _xperipherals_spdif_2__rx_data == 0x17) )
        {
            asm("setpt res[%0], %1"::"r"(_xperipherals_spdif_2__rx_port),"r"(_xperipherals_spdif_2__synctime+32));
            _xperipherals_spdif_2__syncstate = 0;
        }
        _xperipherals_spdif_2__synctime += 32;
    }
}

#endif

//#include <stdio.h>

//static xuint _xperipherals_spdif_2__trace2_buffer[6][8];
//static xuint _xperipherals_spdif_2__trace2_count = 0;

static void _xperipherals_spdif_2__cycle_begin( void )
{
}

static void _xperipherals_spdif_2__phase1_write( xuint tx_sample )
{
    // Encode and transmit first 32-bit portion of BMC encoded 32-bit word

    #if XPERIPHERALS_SPDIF_2__SUPPORT_TX

    //_xperipherals_spdif_2__trace2_buffer[0][_xperipherals_spdif_2__trace2_count] = tx_sample;

    if( _xperipherals_spdif_2__subframe == 0 ) _xperipherals_spdif_2__tx_data = _xperipherals_spdif_2__lut_header_1[_xperipherals_spdif_2__tx_data & 1];
    else _xperipherals_spdif_2__tx_data = _xperipherals_spdif_2__lut_header_N[_xperipherals_spdif_2__subframe & 1][_xperipherals_spdif_2__tx_data & 1];

    _xperipherals_spdif_2__tx_data = (_xperipherals_spdif_2__tx_data << 24)
                             + (_xperipherals_spdif_2__lut_encode[_xperipherals_spdif_2__tx_data & 1][(tx_sample >> 28) & 15] << 16)
                             + (_xperipherals_spdif_2__lut_encode[_xperipherals_spdif_2__tx_data & 1][(tx_sample >> 24) & 15] <<  8)
                             + (_xperipherals_spdif_2__lut_encode[_xperipherals_spdif_2__tx_data & 1][(tx_sample >> 20) & 15] <<  0);

    _xperipherals_spdif_2__tx_port <: bitrev( _xperipherals_spdif_2__tx_data );
    //_xperipherals_spdif_2__trace2_buffer[1][_xperipherals_spdif_2__trace2_count] = _xperipherals_spdif_2__tx_data;

    #endif
}

static void _xperipherals_spdif_2__phase2_write( xuint tx_sample )
{
    // Encode and transmit second 32-bit portion of BMC encoded 32-bit word

    #if XPERIPHERALS_SPDIF_2__SUPPORT_TX

    _xperipherals_spdif_2__tx_data = (_xperipherals_spdif_2__lut_encode[_xperipherals_spdif_2__tx_data & 1][(tx_sample >> 16) & 15] << 24)
                             + (_xperipherals_spdif_2__lut_encode[_xperipherals_spdif_2__tx_data & 1][(tx_sample >> 12) & 15] << 16)
                             + (_xperipherals_spdif_2__lut_encode[_xperipherals_spdif_2__tx_data & 1][(tx_sample >>  8) & 15] <<  8)
                             + (0 << 0); // <TODO> Flags

    _xperipherals_spdif_2__tx_port <: bitrev( _xperipherals_spdif_2__tx_data );
    //_xperipherals_spdif_2__trace2_buffer[2][_xperipherals_spdif_2__trace2_count] = _xperipherals_spdif_2__tx_data;

    #endif
}

static void _xperipherals_spdif_2__phase1_read( xuint& rx_sample )
{
    // Receive and decode first 32-bit portion of BMC encoded 32-bit word

    #if XPERIPHERALS_SPDIF_2__SUPPORT_RX

    if( _xperipherals_spdif_2__syncstate < 3 ) _xperipherals_spdif_2__synchronize( 0 );
    else
    {
        _xperipherals_spdif_2__rx_port :> _xperipherals_spdif_2__rx_data;
        _xperipherals_spdif_2__rx_data = bitrev( _xperipherals_spdif_2__rx_data );

        //_xperipherals_spdif_2__trace2_buffer[4][_xperipherals_spdif_2__trace2_count] = _xperipherals_spdif_2__rx_data;

 //       if( (_xperipherals_spdif_2__rx_data >> 28) != 0xE && (_xperipherals_spdif_2__rx_data >> 28) != 0x1 ) {_xperipherals_spdif_2__syncstate = 1; return;}

        rx_sample = (_xperipherals_spdif_2__lut_decode[(_xperipherals_spdif_2__rx_data >> 16) & 255] << 28) +
                    (_xperipherals_spdif_2__lut_decode[(_xperipherals_spdif_2__rx_data >>  8) & 255] << 24) +
                    (_xperipherals_spdif_2__lut_decode[(_xperipherals_spdif_2__rx_data >>  0) & 255] << 20);
    }

    #endif
}

static void _xperipherals_spdif_2__phase2_read( xuint& rx_sample )
{
    // Receive and decode second 32-bit portion of BMC encoded 32-bit word

    #if XPERIPHERALS_SPDIF_2__SUPPORT_RX

    if( _xperipherals_spdif_2__syncstate < 3 ) _xperipherals_spdif_2__synchronize( 1 );
    else
    {
        _xperipherals_spdif_2__rx_port :> _xperipherals_spdif_2__rx_data;
        _xperipherals_spdif_2__rx_data = bitrev( _xperipherals_spdif_2__rx_data );
        //_xperipherals_spdif_2__trace2_buffer[5][_xperipherals_spdif_2__trace2_count] = _xperipherals_spdif_2__rx_data;

        rx_sample += (_xperipherals_spdif_2__lut_decode[(_xperipherals_spdif_2__rx_data >> 24) & 255] << 16) +
                     (_xperipherals_spdif_2__lut_decode[(_xperipherals_spdif_2__rx_data >> 16) & 255] << 12) +
                     (_xperipherals_spdif_2__lut_decode[(_xperipherals_spdif_2__rx_data >>  8) & 255] <<  8);
    }

    //_xperipherals_spdif_2__trace2_buffer[3][_xperipherals_spdif_2__trace2_count] = rx_sample;

    #endif
}

static void _xperipherals_spdif_2__cycle_end( void )
{
    //if( ++_xperipherals_spdif_2__trace2_count == 8 ) for( int i=0; i<8; ++i )
    //    printf( "TXD = %08X (%08X:%08X), RXD = %08X (%08X:%08X)\n",
    //        _xperipherals_spdif_2__trace2_buffer[0][i], _xperipherals_spdif_2__trace2_buffer[1][i], _xperipherals_spdif_2__trace2_buffer[2][i],
    //        _xperipherals_spdif_2__trace2_buffer[3][i], _xperipherals_spdif_2__trace2_buffer[4][i], _xperipherals_spdif_2__trace2_buffer[5][i] );

    if( ++_xperipherals_spdif_2__subframe == 384 ) _xperipherals_spdif_2__subframe = 0;;
}

void XPERIPHERALS_spdif_2__transfer_part1( xuint tx_sample, xuint& rx_sample )
{
    _xperipherals_spdif_2__start_cycle();
    _xperipherals_spdif_2__write_phase1( tx_sample );
    //_xperipherals_spdif_2__read_phase1( rx_sample );
}

void XPERIPHERALS_spdif_2__transfer_part2( xuint tx_sample, xuint& rx_sample )
{
    _xperipherals_spdif_2__write_phase2( tx_sample );
    //_xperipherals_spdif_2__read_phase2( rx_sample );
    _xperipherals_spdif_2__end_cycle();
}

#endif