Home : I/O Peripherals Library | ADAT Peripheral

Description

<TODO>

Naming Conventions

<TODO>

Interface Functions

<TODO>

Example Usage

<TODO>

Configuration

<TODO>

Source Files

xperipherals_adat.h ADAT peripheral interface
xperipherals_adat_tx_1.xc ADAT output peripheral #1 implementation
xperipherals_adat_tx_2.xc ADAT output peripheral #2 implementation
xperipherals_adat_rx_1.xc ADAT input peripheral #1 implementation
xperipherals_adat_rx_2.xc ADAT input peripheral #2 implementation

Source Listings

xperipherals_adat.h

#ifndef XPERIPHERALS_ADAT__INCLUDED
#define XPERIPHERALS_ADAT__INCLUDED

// ADAT Wire Format:
//
// One ADAT block consists of eight frames (frame 0 ... frame 7).
// One ADAT block contains eight 24-bit samples and 4 user bits.
//
// Each frame contains part of a 24-bit sample, bits set to 1, and user bits (last frame).
// The 'ones' in each frame prevent a run of more than four zeros.
// Samples are placed in the frame MSB first (bit 0 is MSB, bit 23 is LSB).
// The last frame is contain the only occurance of a run of more than four zeros.
// The last frame's zeros are used for synchronization.
//
// The diagram belos shows one complete block where:
//   ***1 represents a bit that's set to one.
//   ***0 represents a bit that's set to zero.
//   The N:MM represents (sample number):(sample bit)
//
// Frame 0 |***1|0:00|0:01|0:02|0:03|***1|0:04|0:05|0:06|0:07|***1|0:08|0:09|0:10|0:11|***1|
//         |0:12|0:13|0:14|0:15|***1|0:16|0:17|0:18|0:19|***1|0:20|0:21|0:22|0:23|***1|1:00|
//
// Frame 1 |1:01|1:02|1:03|***1|1:04|1:05|1:06|1:07|***1|1:08|1:09|1:10|1:11|***1|1:12|1:13|
//         |1:14|1:15|***1|1:16|1:17|1:18|1:19|***1|1:20|1:21|1:22|1:23|***1|2:00|2:01|2:02|
//
// Frame 2 |2:03|***1|2:04|2:05|2:06|2:07|***1|2:08|2:09|2:10|2:11|***1|2:12|2:13|2:14|2:15|
//         |***1|2:16|2:17|2:18|2:19|***1|2:20|2:21|2:22|2:23|***1|3:00|3:01|3:02|3:03|***1|
//
// Frame 3 |3:04|3:05|3:06|3:07|***1|3:08|3:09|3:10|3:11|***1|3:12|3:13|3:14|3:15|***1|3:16|
//         |3:17|3:18|3:19|***1|3:20|3:21|3:22|3:23|***1|4:00|4:01|4:02|4:03|***1|4:04|4:05|
//
// Frame 4 |4:06|4:07|***1|4:08|4:09|4:10|4:11|***1|4:12|4:13|4:14|4:15|***1|4:16|4:17|4:18|
//         |4:19|***1|4:20|4:21|4:22|4:23|***1|5:00|5:01|5:02|5:03|***1|5:04|5:05|5:06|5:07|
//
// Frame 5 |***1|5:08|5:09|5:10|5:11|***1|5:12|5:13|5:14|5:15|***1|5:16|5:17|5:18|5:19|***1|
//         |5:20|5:21|5:22|5:23|***1|6:00|6:01|6:02|6:03|***1|6:04|6:05|6:06|6:07|***1|6:08|
//
// Frame 6 |6:09|6:10|6:11|***1|6:12|6:13|6:14|6:15|***1|6:16|6:17|6:18|6:19|***1|6:20|6:21|
//         |6:22|6:23|***1|7:00|7:01|7:02|7:03|***1|7:04|7:05|7:06|7:07|***1|7:08|7:09|7:10|
//
// Frame 7 |7:11|***1|7:12|7:13|7:14|7:15|***1|7:16|7:17|7:18|7:19|***1|7:20|7:21|7:22|7:23|
//         |***1|***0|***0|***0|***0|***0|***0|***0|***0|***0|***0|***1|Usr0|Usr1|Usr2|Usr3|
//
// The bit-stream at the phyiscal level representing an ADAT block is NRZI encoded.

#include "xsystem_types.h"

// These must be defined in "xconfig.h" for each peripheral bus being used
//
// XPERIPHERALS_ADAT_TX_n                No value
// XPERIPHERALS_ADAT_TX_n__TILE_NUMBER   Integer, XS1 tile number
// XPERIPHERALS_ADAT_TX_n__TXD_PORT      XS1 port identifier

#define XPERIPHERALS_ADAT_TX__INTERFACE( N ) \
\
void  xperipherals_adat_tx_##N##__initialize( xuint bclk_divider ); \
void  xperipherals_adat_tx_##N##__configure ( clock bit_clock ); \
void  xperipherals_adat_tx_##N##__transfer  ( xsint wordA, xsint wordB );

XPERIPHERALS_ADAT_TX__INTERFACE( 1 )
XPERIPHERALS_ADAT_TX__INTERFACE( 2 )

// These must be defined in "xconfig.h" for each peripheral bus being used
//
// XPERIPHERALS_ADAT_RX_n                No value
// XPERIPHERALS_ADAT_RX_n__TILE_NUMBER   Integer, XS1 tile number
// XPERIPHERALS_ADAT_RX_n__RXD_PORT      XS1 port identifier

#define XPERIPHERALS_ADAT_RX__INTERFACE( N ) \
\
void  xperipherals_adat_rx_##N##__init  ( xuint bclk_divider ); \
void  xperipherals_adat_rx_##N##__config( clock bit_clock ); \
xbool xperipherals_adat_rx_##N##__phase0( xsint& sample_0, xsint& sample_1 ); \
xbool xperipherals_adat_rx_##N##__phase1( xsint& sample_1, xsint& sample_2 ); \
xbool xperipherals_adat_rx_##N##__phase2( xsint& sample_2, xsint& sample_3 ); \
xbool xperipherals_adat_rx_##N##__phase3( xsint& sample_3, xsint& sample_4 ); \
xbool xperipherals_adat_rx_##N##__phase4( xsint& sample_4, xsint& sample_5 ); \
xbool xperipherals_adat_rx_##N##__phase5( xsint& sample_5, xsint& sample_6 ); \
xbool xperipherals_adat_rx_##N##__phase6( xsint& sample_6, xsint& sample_7 ); \
xbool xperipherals_adat_rx_##N##__phase7( xsint& sample_7, xuint& userdata );

XPERIPHERALS_ADAT_RX__INTERFACE( 1 )
XPERIPHERALS_ADAT_RX__INTERFACE( 2 )

#endif

xperipherals_adat_tx_1.xc

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

#include "xperipherals_adat.h"

// 256-Bit ADAT Packet
//
// The packet structure below shows [Channel Number]:[Sample Bit Pos] for audio samples.
// The 256-bit sequence is NRZI encoded when transmitting and NRZI decoded when receiving.
// Samples are serialized MSB first (:00 represents MSB and :23 represents LSB)
//
// Note: Bit stuffing with 'ones' every fifth bit and NRZI encoding prevents long runs
// of zeros. The zero's at the end of the frame are used for frame synchronization.
//
// 0 |one |0:00|0:01|0:02|0:03|one |0:04|0:05|0:06|0:07|one |0:08|0:09|0:10|0:11|one |
//   |0:12|0:13|0:14|0:15|one |0:16|0:17|0:18|0:19|one |0:20|0:21|0:22|0:23|one |1:00|
// 1 |1:01|1:02|1:03|one |1:04|1:05|1:06|1:07|one |1:08|1:09|1:10|1:11|one |1:12|1:13|
//   |1:14|1:15|one |1:16|1:17|1:18|1:19|one |1:20|1:21|1:22|1:23|one |2:00|2:01|2:02|
// 2 |2:03|one |2:04|2:05|2:06|2:07|one |2:08|2:09|2:10|2:11|one |2:12|2:13|2:14|2:15|
//   |one |2:16|2:17|2:18|2:19|one |2:20|2:21|2:22|2:23|one |3:00|3:01|3:02|3:03|one |
// 3 |3:04|3:05|3:06|3:07|one |3:08|3:09|3:10|3:11|one |3:12|3:13|3:14|3:15|one |3:16|
//   |3:17|3:18|3:19|one |3:20|3:21|3:22|3:23|one |4:00|4:01|4:02|4:03|one |4:04|4:05|
// 4 |4:06|4:07|one |4:08|4:09|4:10|4:11|one |4:12|4:13|4:14|4:15|one |4:16|4:17|4:18|
//   |4:19|one |4:20|4:21|4:22|4:23|one |5:00|5:01|5:02|5:03|one |5:04|5:05|5:06|5:07|
// 5 |one |5:08|5:09|5:10|5:11|one |5:12|5:13|5:14|5:15|one |5:16|5:17|5:18|5:19|one |
//   |5:20|5:21|5:22|5:23|one |6:00|6:01|6:02|6:03|one |6:04|6:05|6:06|6:07|one |6:08|
// 6 |6:09|6:10|6:11|one |6:12|6:13|6:14|6:15|one |6:16|6:17|6:18|6:19|one |6:20|6:21|
//   |6:22|6:23|one |7:00|7:01|7:02|7:03|one |7:04|7:05|7:06|7:07|one |7:08|7:09|7:10|
// 7 |7:11|one |7:12|7:13|7:14|7:15|one |7:16|7:17|7:18|7:19|one |7:20|7:21|7:22|7:23|
//   |one |zero|zero|zero|zero|zero|zero|zero|zero|zero|zero|one |usr0|usr1|usr2|usr3|

#ifdef XSTREAMM_IO__ADAT_TX_1

on tile[XPERIPHERALS_ADAT_TX_1__TILE_NUMBER] :
out buffered port:32 _xperipherals_adat_tx_1__port_txd = XPERIPHERALS_ADAT_TX_1__TXD_PORT;

static xuint _bclk_divider;
static xuint _encode_lut1[256];
static xbyte _encode_lut2[256];
static xuint _enc_word;
//static xuint _tx_carry;
//static xuint _tx_stage;
static xuint _slot_number;
static xuint _step_number = 0;

void xperipherals_adat_tx_1__initialize( xuint bclk_divider )
{
    _bclk_divider = bclk_divider;
    _enc_word = 0;
    //_tx_carry = 0;
    //_tx_stage = 0;
    _slot_number = 0;

    // bit clock frequency = 1 * ADAT bit rate = 12.288 / 11.2896 MHz
    for( int j = 0; j < 256; ++j ) {
        xuint carry = 0;
        xuint data = 0b1000010000 | ((j & 0xF0) << 1) | (j & 0x0F);
        _encode_lut1[j] = 0;
        for( int i = 0; i < 10; ++i, data <<= 1 ) {
            if( data & 0b1000000000 ) carry = !carry;
            _encode_lut1[j] = (_encode_lut1[j] << 1) | carry;
        }
    }
    // bit clock frequency = 2 * ADAT bit rate = 24.576 / 22.5792 MHz
    if( bclk_divider == 1 ) {
        for( int j = 0; j < 256; ++j ) {
            xuint x = _encode_lut1[j];
             _encode_lut1[j] = 0;
            for( int i = 9; i >= 0; --i ) {
                if( x & (1 << i) ) _encode_lut1[j] |= 3 << (2*i);
            }
        }
    }
    // bit clock frequency = 4 * ADAT bit rate = 49.152 / 45.1584 MHz
    if( bclk_divider == 2 ) {
        for( int j = 0; j < 256; ++j ) {
            xuint x = _encode_lut1[j];
            _encode_lut1[j] = _encode_lut2[j] = 0;
            for( int i = 9; i >= 8; --i ) {
                if( x & (1 << i) ) _encode_lut2[j] |= 15 << (4*(i-8));
            }
            for( int i = 7; i >= 0; --i ) {
                if( x & (1 << i) ) _encode_lut1[j] |= 15 << (4*i);
            }
            //printf( "%05x %02x%08x\n", x, _encode_lut2[j], _encode_lut1[j] );
        }
    }
}

void xperipherals_adat_tx_1__configure( clock bit_clock )
{
        configure_out_port_no_ready( _xperipherals_adat_tx_1__port_txd, bit_clock, 0 );
        clearbuf( _xperipherals_adat_tx_1__port_txd );
    _enc_word = 0;
    //_tx_carry = 0;
    //_tx_stage = 0;
    _slot_number = 0;
}

#if XPERIPHERALS_ADAT_TX_1__BCLK_SPEED == 1

static void _encode_data( xuint sample, xuint byte_num )
{
    int shift = 8 * (3 - byte_num);
    if( _enc_word & 1 ) _enc_word = ~_encode_lut1[255 & (sample >> shift)] & 0x3FF;
    else _enc_word = _encode_lut1[255 & (sample >> shift)] & 0x3FF;
}

#elif XPERIPHERALS_ADAT_TX_1__BCLK_SPEED == 2

static void _encode_data( xuint sample, xuint byte_num )
{
    int shift = 8 * (3 - byte_num);
    if( _enc_word & 1 ) _enc_word = ~_encode_lut1[255 & (sample >> shift)] & 0xFFFFF;
    else _enc_word = _encode_lut1[255 & (sample >> shift)] & 0xFFFFF;
}

#elif XPERIPHERALS_ADAT_TX_1__BCLK_SPEED == 3

static void _encode_data( xuint sample, xuint byte_num )
{
}

#endif

// 0.42 usec + 0.34 usec * 7 = 2.8 usec
// 2.7 usec

#if XPERIPHERALS_ADAT_TX_1__BCLK_SPEED == 1

void xperipherals_adat_tx_1__transfer( xsint wordA, xsint wordB )
{
    xuint data;
    switch( _slot_number )
    {
        // | 1 |0:0|0:0|0:0|0:0| 1 |0:0|0:0|0:0|0:0| 1 |0:1|0:1|0:1|0:1| 1 |
        // |0:1|0:1|0:1|0:1| 1 |0:2|0:2|0:2|0:2| 1 |0:2|0:2|0:2|0:2| 1 |1:0|
        case 0: _encode_data( wordA, 0 ); data  = _enc_word << 22;
                _encode_data( wordA, 1 ); data |= _enc_word << 12;
                _encode_data( wordA, 2 ); data |= _enc_word <<  2;
                _encode_data( wordB, 0 ); data |= _enc_word >>  8;
        break;
        // |1:0|1:0|1:0| 1 |1:0|1:0|1:0|1:0| 1 |1:1|1:1|1:1|1:1| 1 |1:1|1:1|
        // |1:1|1:1| 1 |1:2|1:2|1:2|1:2| 1 |1:2|1:2|1:2|1:2| 1 |2:0|2:0|2:0|
        case 1: /* Word from prev step */ data  = _enc_word << 24;
                _encode_data( wordA, 1 ); data |= _enc_word << 14;
                _encode_data( wordA, 2 ); data |= _enc_word <<  4;
                _encode_data( wordB, 0 ); data |= _enc_word >>  6;
        break;
        // |2:0| 1 |2:0|2:0|2:0|2:0| 1 |2:1|2:1|2:1|2:1| 1 |2:1|2:1|2:1|2:1|
        // | 1 |2:2|2:2|2:2|2:2| 1 |2:2|2:2|2:2|2:2| 1 |3:0|3:0|3:0|3:0| 1 |
        case 2: /* Word from prev step */ data  = _enc_word << 26;
                _encode_data( wordA, 1 ); data |= _enc_word << 16;
                _encode_data( wordA, 2 ); data |= _enc_word <<  6;
                _encode_data( wordB, 0 ); data |= _enc_word >>  4;
        break;
        // |3:0|3:0|3:0|3:0| 1 |3:1|3:1|3:1|3:1| 1 |3:1|3:1|3:1|3:1| 1 |3:2|
        // |3:2|3:2|3:2| 1 |3:2|3:2|3:2|3:2| 1 |4:0|4:0|4:0|4:0| 1 |4:0|4:0|
        case 3: /* Word from prev step */ data  = _enc_word << 28;
                _encode_data( wordA, 1 ); data |= _enc_word << 18;
                _encode_data( wordA, 2 ); data |= _enc_word <<  8;
                _encode_data( wordB, 0 ); data |= _enc_word >>  2;
        break;
        // |4:0|4:0| 1 |4:1|4:1|4:1|4:1| 1 |4:1|4:1|4:1|4:1| 1 |4:2|4:2|4:2|
        // |4:2| 1 |4:2|4:2|4:2|4:2| 1 |5:0|5:0|5:0|5:0| 1 |5:0|5:0|5:0|5:0|
        case 4: /* Word from prev step */ data  = _enc_word << 30;
                _encode_data( wordA, 1 ); data |= _enc_word << 20;
                _encode_data( wordA, 2 ); data |= _enc_word << 10;
                _encode_data( wordB, 0 ); data |= _enc_word >>  0;
        break;
        // | 1 |5:1|5:1|5:1|5:1| 1 |5:1|5:1|5:1|5:1| 1 |5:2|5:2|5:2|5:2| 1 |
        // |5:2|5:2|5:2|5:2| 1 |6:0|6:0|6:0|6:0| 1 |6:0|6:0|6:0|6:0| 1 |6:1|
        case 5: _encode_data( wordA, 1 ); data  = _enc_word << 22;
                _encode_data( wordA, 2 ); data |= _enc_word << 12;
                _encode_data( wordB, 0 ); data |= _enc_word <<  2;
                _encode_data( wordB, 1 ); data |= _enc_word >>  8;
        break;
        // |6:1|6:1|6:1| 1 |6:1|6:1|6:1|6:1| 1 |6:2|6:2|6:2|6:2| 1 |6:2|6:2|
        // |6:2|6:2| 1 |7:0|7:0|7:0|7:0| 1 |7:0|7:0|7:0|7:0| 1 |7:1|7:1|7:1|
        case 6: /* Word from prev step */ data  = _enc_word << 24;
                _encode_data( wordA, 2 ); data |= _enc_word << 14;
                _encode_data( wordB, 0 ); data |= _enc_word <<  4;
                _encode_data( wordB, 1 ); data |= _enc_word >>  6;
        break;
        // |7:1| 1 |7:1|7:1|7:1|7:1| 1 |7:2|7:2|7:2|7:2| 1 |7:2|7:2|7:2|7:2|
        // | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |ub0|ub1|ub2|ub3|
        case 7: /* Word from prev step */ data  = _enc_word << 26;
                _encode_data( wordA, 2 ); data |= _enc_word << 16;
                // TODO - encode user data rather than hard-coding zeros
                //if( _enc_word & 1 ) _tx_carry = data |= 0b0000000000011111;
                if( _enc_word & 1 ) data |= 0b0000000000011111;
                else _enc_word = data |= 0b1111111111100000;
                _enc_word = data;
        break;
    }
    _xperipherals_adat_tx_1__port_txd <: bitrev( data );
    if( ++_slot_number == 8 ) _slot_number = 0;
}

#elif XPERIPHERALS_ADAT_TX_1__BCLK_SPEED == 2

void xperipherals_adat_tx_1__transfer_slot( xsint wordA, xsint wordB )
{
    switch( _slot_number )
    {
        case 0: switch( _step_number )
        {
            // | 1 | 1 |0:0|0:0|0:0|0:0|0:0|0:0|0:0|0:0| 1 | 1 |0:0|0:0|0:0|0:0|
            // |0:0|0:0|0:0|0:0| 1 | 1 |0:1|0:1|0:1|0:1|0:1|0:1|0:1|0:1| 1 | 1 |
            case 0: _encode_data( wordA, 0 ); data  = _enc_word << 12;
                    _encode_data( wordA, 1 ); data |= _enc_word >>  8; break;
            // |0:1|0:1|0:1|0:1|0:1|0:1|0:1|0:1| 1 | 1 |0:2|0:2|0:2|0:2|0:2|0:2|
            // |0:2|0:2| 1 | 1 |0:2|0:2|0:2|0:2|0:2|0:2|0:2|0:2| 1 | 1 |1:0|1:0|
            case 1: /* Word from prev step */ data  = _enc_word << 24;
                    _encode_data( wordA, 2 ); data |= _enc_word <<  4;
                    _encode_data( wordB, 0 ); data |= _enc_word >>  8; break;
        } break;
        case 1:  switch( _step_number )
        {
            // |1:0|1:0|1:0|1:0|1:0|1:0| 1 | 1 |1:0|1:0|1:0|1:0|1:0|1:0|1:0|1:0|
            // | 1 | 1 |1:1|1:1|1:1|1:1|1:1|1:1|1:1|1:1| 1 | 1 |1:1|1:1|1:1|1:1|
            case 1: /* Word from prev step */ data  = _enc_word << 16;
                    _encode_data( wordA, 1 ); data |= _enc_word >>  4; break;
            // |1:1|1:1|1:1|1:1| 1 | 1 |1:2|1:2|1:2|1:2|1:2|1:2|1:2|1:2| 1 | 1 |
            // |1:2|1:2|1:2|1:2|1:2|1:2|1:2|1:2| 1 | 1 |2:0|2:0|2:0|2:0|2:0|2:0|
            case 1:
                    _encode_data( wordA, 1 ); data |= _enc_word << 28;
                    _encode_data( wordB, 24 ); data |= _enc_word >>  6; break;
        } break;
        // |2:0| 1 |2:0|2:0|2:0|2:0| 1 |2:1|2:1|2:1|2:1| 1 |2:1|2:1|2:1|2:1|
        // | 1 |2:2|2:2|2:2|2:2| 1 |2:2|2:2|2:2|2:2| 1 |3:0|3:0|3:0|3:0| 1 |
        case 2: /* Word from prev step  */ data  = _enc_word << 26;
                _encode_data( wordA, 16 ); data |= _enc_word << 16;
                _encode_data( wordA,  8 ); data |= _enc_word <<  6;
                _encode_data( wordB, 24 ); data |= _enc_word >>  4;
        break;
        // |3:0|3:0|3:0|3:0| 1 |3:1|3:1|3:1|3:1| 1 |3:1|3:1|3:1|3:1| 1 |3:2|
        // |3:2|3:2|3:2| 1 |3:2|3:2|3:2|3:2| 1 |4:0|4:0|4:0|4:0| 1 |4:0|4:0|
        case 3: /* Word from prev step  */ data  = _enc_word << 28;
                _encode_data( wordA, 16 ); data |= _enc_word << 18;
                _encode_data( wordA,  8 ); data |= _enc_word <<  8;
                _encode_data( wordB, 24 ); data |= _enc_word >>  2;
        break;
        // |4:0|4:0| 1 |4:1|4:1|4:1|4:1| 1 |4:1|4:1|4:1|4:1| 1 |4:2|4:2|4:2|
        // |4:2| 1 |4:2|4:2|4:2|4:2| 1 |5:0|5:0|5:0|5:0| 1 |5:0|5:0|5:0|5:0|
        case 4: /* Word from prev step  */ data  = _enc_word << 30;
                _encode_data( wordA, 16 ); data |= _enc_word << 20;
                _encode_data( wordA,  8 ); data |= _enc_word << 10;
                _encode_data( wordB, 24 ); data |= _enc_word >>  0;
        break;
        // | 1 |5:1|5:1|5:1|5:1| 1 |5:1|5:1|5:1|5:1| 1 |5:2|5:2|5:2|5:2| 1 |
        // |5:2|5:2|5:2|5:2| 1 |6:0|6:0|6:0|6:0| 1 |6:0|6:0|6:0|6:0| 1 |6:1|
        case 5: _encode_data( wordA, 16 ); data  = _enc_word << 22;
                _encode_data( wordA,  8 ); data |= _enc_word << 12;
                _encode_data( wordB, 24 ); data |= _enc_word <<  2;
                _encode_data( wordB, 16 ); data |= _enc_word >>  8;
        break;
        // |6:1|6:1|6:1| 1 |6:1|6:1|6:1|6:1| 1 |6:2|6:2|6:2|6:2| 1 |6:2|6:2|
        // |6:2|6:2| 1 |7:0|7:0|7:0|7:0| 1 |7:0|7:0|7:0|7:0| 1 |7:1|7:1|7:1|
        case 6: /* Word from prev step  */ data  = _enc_word << 24;
                _encode_data( wordA,  8 ); data |= _enc_word << 14;
                _encode_data( wordB, 24 ); data |= _enc_word <<  4;
                _encode_data( wordB, 16 ); data |= _enc_word >>  6;
        break;
        // |7:1| 1 |7:1|7:1|7:1|7:1| 1 |7:2|7:2|7:2|7:2| 1 |7:2|7:2|7:2|7:2|
        // | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |ub0|ub1|ub2|ub3|
        case 7: /* Word from prev step  */ data  = _enc_word << 26;
                _encode_data( wordA,  8 ); data |= _enc_word << 16;
                // TODO - encode user data rather than hard-coding zeros
                //if( _enc_word & 1 ) _tx_carry = data |= 0b0000000000011111;
                if( _enc_word & 1 ) data |= 0b0000000000011111;
                else _enc_word = data |= 0b1111111111100000;
                _enc_word = data;
        break;
    }
    _xperipherals_adat_tx_1__port_txd <: bitrev( data );
}

#elif XPERIPHERALS_ADAT_TX_1__BCLK_SPEED == 4

#endif

#endif

xperipherals_adat_tx_2.xc

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

#include "xperipherals_adat.h"

// 256-Bit ADAT Packet
//
// The packet structure below shows [Channel Number]:[Sample Bit Pos] for audio samples.
// The 256-bit sequence is NRZI encoded when transmitting and NRZI decoded when receiving.
// Samples are serialized MSB first (:00 represents MSB and :23 represents LSB)
//
// Note: Bit stuffing with 'ones' every fifth bit and NRZI encoding prevents long runs
// of zeros. The zero's at the end of the frame are used for frame synchronization.
//
// 0 |one |0:00|0:01|0:02|0:03|one |0:04|0:05|0:06|0:07|one |0:08|0:09|0:10|0:11|one |
//   |0:12|0:13|0:14|0:15|one |0:16|0:17|0:18|0:19|one |0:20|0:21|0:22|0:23|one |1:00|
// 1 |1:01|1:02|1:03|one |1:04|1:05|1:06|1:07|one |1:08|1:09|1:10|1:11|one |1:12|1:13|
//   |1:14|1:15|one |1:16|1:17|1:18|1:19|one |1:20|1:21|1:22|1:23|one |2:00|2:01|2:02|
// 2 |2:03|one |2:04|2:05|2:06|2:07|one |2:08|2:09|2:10|2:11|one |2:12|2:13|2:14|2:15|
//   |one |2:16|2:17|2:18|2:19|one |2:20|2:21|2:22|2:23|one |3:00|3:01|3:02|3:03|one |
// 3 |3:04|3:05|3:06|3:07|one |3:08|3:09|3:10|3:11|one |3:12|3:13|3:14|3:15|one |3:16|
//   |3:17|3:18|3:19|one |3:20|3:21|3:22|3:23|one |4:00|4:01|4:02|4:03|one |4:04|4:05|
// 4 |4:06|4:07|one |4:08|4:09|4:10|4:11|one |4:12|4:13|4:14|4:15|one |4:16|4:17|4:18|
//   |4:19|one |4:20|4:21|4:22|4:23|one |5:00|5:01|5:02|5:03|one |5:04|5:05|5:06|5:07|
// 5 |one |5:08|5:09|5:10|5:11|one |5:12|5:13|5:14|5:15|one |5:16|5:17|5:18|5:19|one |
//   |5:20|5:21|5:22|5:23|one |6:00|6:01|6:02|6:03|one |6:04|6:05|6:06|6:07|one |6:08|
// 6 |6:09|6:10|6:11|one |6:12|6:13|6:14|6:15|one |6:16|6:17|6:18|6:19|one |6:20|6:21|
//   |6:22|6:23|one |7:00|7:01|7:02|7:03|one |7:04|7:05|7:06|7:07|one |7:08|7:09|7:10|
// 7 |7:11|one |7:12|7:13|7:14|7:15|one |7:16|7:17|7:18|7:19|one |7:20|7:21|7:22|7:23|
//   |one |zero|zero|zero|zero|zero|zero|zero|zero|zero|zero|one |usr0|usr1|usr2|usr3|

#ifdef XSTREAMM_IO__ADAT_TX_2

on tile[XPERIPHERALS_ADAT_TX_2__TILE_NUMBER] :
out buffered port:32 _xperipherals_adat_tx_2__port_txd = XPERIPHERALS_ADAT_TX_2__TXD_PORT;

static xuint _bclk_divider;
static xuint _encode_lut1[256];
static xbyte _encode_lut2[256];
static xuint _enc_word;
//static xuint _tx_carry;
//static xuint _tx_stage;
static xuint _slot_number;
static xuint _step_number = 0;

void xperipherals_adat_tx_2__initialize( xuint bclk_divider )
{
    _bclk_divider = bclk_divider;
    _enc_word = 0;
    //_tx_carry = 0;
    //_tx_stage = 0;
    _slot_number = 0;

    // bit clock frequency = 1 * ADAT bit rate = 12.288 / 11.2896 MHz
    for( int j = 0; j < 256; ++j ) {
        xuint carry = 0;
        xuint data = 0b1000010000 | ((j & 0xF0) << 1) | (j & 0x0F);
        _encode_lut1[j] = 0;
        for( int i = 0; i < 10; ++i, data <<= 1 ) {
            if( data & 0b1000000000 ) carry = !carry;
            _encode_lut1[j] = (_encode_lut1[j] << 1) | carry;
        }
    }
    // bit clock frequency = 2 * ADAT bit rate = 24.576 / 22.5792 MHz
    if( bclk_divider == 1 ) {
        for( int j = 0; j < 256; ++j ) {
            xuint x = _encode_lut1[j];
             _encode_lut1[j] = 0;
            for( int i = 9; i >= 0; --i ) {
                if( x & (1 << i) ) _encode_lut1[j] |= 3 << (2*i);
            }
        }
    }
    // bit clock frequency = 4 * ADAT bit rate = 49.152 / 45.1584 MHz
    if( bclk_divider == 2 ) {
        for( int j = 0; j < 256; ++j ) {
            xuint x = _encode_lut1[j];
            _encode_lut1[j] = _encode_lut2[j] = 0;
            for( int i = 9; i >= 8; --i ) {
                if( x & (1 << i) ) _encode_lut2[j] |= 15 << (4*(i-8));
            }
            for( int i = 7; i >= 0; --i ) {
                if( x & (1 << i) ) _encode_lut1[j] |= 15 << (4*i);
            }
            //printf( "%05x %02x%08x\n", x, _encode_lut2[j], _encode_lut1[j] );
        }
    }
}

void xperipherals_adat_tx_2__configure( clock bit_clock )
{
        configure_out_port_no_ready( _xperipherals_adat_tx_2__port_txd, bit_clock, 0 );
        clearbuf( _xperipherals_adat_tx_2__port_txd );
    _enc_word = 0;
    //_tx_carry = 0;
    //_tx_stage = 0;
    _slot_number = 0;
}

#if XPERIPHERALS_ADAT_TX_2__BCLK_SPEED == 1

static void _encode_data( xuint sample, xuint byte_num )
{
    int shift = 8 * (3 - byte_num);
    if( _enc_word & 1 ) _enc_word = ~_encode_lut1[255 & (sample >> shift)] & 0x3FF;
    else _enc_word = _encode_lut1[255 & (sample >> shift)] & 0x3FF;
}

#elif XPERIPHERALS_ADAT_TX_2__BCLK_SPEED == 2

static void _encode_data( xuint sample, xuint byte_num )
{
    int shift = 8 * (3 - byte_num);
    if( _enc_word & 1 ) _enc_word = ~_encode_lut1[255 & (sample >> shift)] & 0xFFFFF;
    else _enc_word = _encode_lut1[255 & (sample >> shift)] & 0xFFFFF;
}

#elif XPERIPHERALS_ADAT_TX_2__BCLK_SPEED == 3

static void _encode_data( xuint sample, xuint byte_num )
{
}

#endif

// 0.42 usec + 0.34 usec * 7 = 2.8 usec
// 2.7 usec

#if XPERIPHERALS_ADAT_TX_2__BCLK_SPEED == 1

void xperipherals_adat_tx_2__transfer( xsint wordA, xsint wordB )
{
    xuint data;
    switch( _slot_number )
    {
        // | 1 |0:0|0:0|0:0|0:0| 1 |0:0|0:0|0:0|0:0| 1 |0:1|0:1|0:1|0:1| 1 |
        // |0:1|0:1|0:1|0:1| 1 |0:2|0:2|0:2|0:2| 1 |0:2|0:2|0:2|0:2| 1 |1:0|
        case 0: _encode_data( wordA, 0 ); data  = _enc_word << 22;
                _encode_data( wordA, 1 ); data |= _enc_word << 12;
                _encode_data( wordA, 2 ); data |= _enc_word <<  2;
                _encode_data( wordB, 0 ); data |= _enc_word >>  8;
        break;
        // |1:0|1:0|1:0| 1 |1:0|1:0|1:0|1:0| 1 |1:1|1:1|1:1|1:1| 1 |1:1|1:1|
        // |1:1|1:1| 1 |1:2|1:2|1:2|1:2| 1 |1:2|1:2|1:2|1:2| 1 |2:0|2:0|2:0|
        case 1: /* Word from prev step */ data  = _enc_word << 24;
                _encode_data( wordA, 1 ); data |= _enc_word << 14;
                _encode_data( wordA, 2 ); data |= _enc_word <<  4;
                _encode_data( wordB, 0 ); data |= _enc_word >>  6;
        break;
        // |2:0| 1 |2:0|2:0|2:0|2:0| 1 |2:1|2:1|2:1|2:1| 1 |2:1|2:1|2:1|2:1|
        // | 1 |2:2|2:2|2:2|2:2| 1 |2:2|2:2|2:2|2:2| 1 |3:0|3:0|3:0|3:0| 1 |
        case 2: /* Word from prev step */ data  = _enc_word << 26;
                _encode_data( wordA, 1 ); data |= _enc_word << 16;
                _encode_data( wordA, 2 ); data |= _enc_word <<  6;
                _encode_data( wordB, 0 ); data |= _enc_word >>  4;
        break;
        // |3:0|3:0|3:0|3:0| 1 |3:1|3:1|3:1|3:1| 1 |3:1|3:1|3:1|3:1| 1 |3:2|
        // |3:2|3:2|3:2| 1 |3:2|3:2|3:2|3:2| 1 |4:0|4:0|4:0|4:0| 1 |4:0|4:0|
        case 3: /* Word from prev step */ data  = _enc_word << 28;
                _encode_data( wordA, 1 ); data |= _enc_word << 18;
                _encode_data( wordA, 2 ); data |= _enc_word <<  8;
                _encode_data( wordB, 0 ); data |= _enc_word >>  2;
        break;
        // |4:0|4:0| 1 |4:1|4:1|4:1|4:1| 1 |4:1|4:1|4:1|4:1| 1 |4:2|4:2|4:2|
        // |4:2| 1 |4:2|4:2|4:2|4:2| 1 |5:0|5:0|5:0|5:0| 1 |5:0|5:0|5:0|5:0|
        case 4: /* Word from prev step */ data  = _enc_word << 30;
                _encode_data( wordA, 1 ); data |= _enc_word << 20;
                _encode_data( wordA, 2 ); data |= _enc_word << 10;
                _encode_data( wordB, 0 ); data |= _enc_word >>  0;
        break;
        // | 1 |5:1|5:1|5:1|5:1| 1 |5:1|5:1|5:1|5:1| 1 |5:2|5:2|5:2|5:2| 1 |
        // |5:2|5:2|5:2|5:2| 1 |6:0|6:0|6:0|6:0| 1 |6:0|6:0|6:0|6:0| 1 |6:1|
        case 5: _encode_data( wordA, 1 ); data  = _enc_word << 22;
                _encode_data( wordA, 2 ); data |= _enc_word << 12;
                _encode_data( wordB, 0 ); data |= _enc_word <<  2;
                _encode_data( wordB, 1 ); data |= _enc_word >>  8;
        break;
        // |6:1|6:1|6:1| 1 |6:1|6:1|6:1|6:1| 1 |6:2|6:2|6:2|6:2| 1 |6:2|6:2|
        // |6:2|6:2| 1 |7:0|7:0|7:0|7:0| 1 |7:0|7:0|7:0|7:0| 1 |7:1|7:1|7:1|
        case 6: /* Word from prev step */ data  = _enc_word << 24;
                _encode_data( wordA, 2 ); data |= _enc_word << 14;
                _encode_data( wordB, 0 ); data |= _enc_word <<  4;
                _encode_data( wordB, 1 ); data |= _enc_word >>  6;
        break;
        // |7:1| 1 |7:1|7:1|7:1|7:1| 1 |7:2|7:2|7:2|7:2| 1 |7:2|7:2|7:2|7:2|
        // | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |ub0|ub1|ub2|ub3|
        case 7: /* Word from prev step */ data  = _enc_word << 26;
                _encode_data( wordA, 2 ); data |= _enc_word << 16;
                // TODO - encode user data rather than hard-coding zeros
                //if( _enc_word & 1 ) _tx_carry = data |= 0b0000000000011111;
                if( _enc_word & 1 ) data |= 0b0000000000011111;
                else _enc_word = data |= 0b1111111111100000;
                _enc_word = data;
        break;
    }
    _xperipherals_adat_tx_2__port_txd <: bitrev( data );
    if( ++_slot_number == 8 ) _slot_number = 0;
}

#elif XPERIPHERALS_ADAT_TX_2__BCLK_SPEED == 2

void xperipherals_adat_tx_2__transfer_slot( xsint wordA, xsint wordB )
{
    switch( _slot_number )
    {
        case 0: switch( _step_number )
        {
            // | 1 | 1 |0:0|0:0|0:0|0:0|0:0|0:0|0:0|0:0| 1 | 1 |0:0|0:0|0:0|0:0|
            // |0:0|0:0|0:0|0:0| 1 | 1 |0:1|0:1|0:1|0:1|0:1|0:1|0:1|0:1| 1 | 1 |
            case 0: _encode_data( wordA, 0 ); data  = _enc_word << 12;
                    _encode_data( wordA, 1 ); data |= _enc_word >>  8; break;
            // |0:1|0:1|0:1|0:1|0:1|0:1|0:1|0:1| 1 | 1 |0:2|0:2|0:2|0:2|0:2|0:2|
            // |0:2|0:2| 1 | 1 |0:2|0:2|0:2|0:2|0:2|0:2|0:2|0:2| 1 | 1 |1:0|1:0|
            case 1: /* Word from prev step */ data  = _enc_word << 24;
                    _encode_data( wordA, 2 ); data |= _enc_word <<  4;
                    _encode_data( wordB, 0 ); data |= _enc_word >>  8; break;
        } break;
        case 1:  switch( _step_number )
        {
            // |1:0|1:0|1:0|1:0|1:0|1:0| 1 | 1 |1:0|1:0|1:0|1:0|1:0|1:0|1:0|1:0|
            // | 1 | 1 |1:1|1:1|1:1|1:1|1:1|1:1|1:1|1:1| 1 | 1 |1:1|1:1|1:1|1:1|
            case 1: /* Word from prev step */ data  = _enc_word << 16;
                    _encode_data( wordA, 1 ); data |= _enc_word >>  4; break;
            // |1:1|1:1|1:1|1:1| 1 | 1 |1:2|1:2|1:2|1:2|1:2|1:2|1:2|1:2| 1 | 1 |
            // |1:2|1:2|1:2|1:2|1:2|1:2|1:2|1:2| 1 | 1 |2:0|2:0|2:0|2:0|2:0|2:0|
            case 1:
                    _encode_data( wordA, 1 ); data |= _enc_word << 28;
                    _encode_data( wordB, 24 ); data |= _enc_word >>  6; break;
        } break;
        // |2:0| 1 |2:0|2:0|2:0|2:0| 1 |2:1|2:1|2:1|2:1| 1 |2:1|2:1|2:1|2:1|
        // | 1 |2:2|2:2|2:2|2:2| 1 |2:2|2:2|2:2|2:2| 1 |3:0|3:0|3:0|3:0| 1 |
        case 2: /* Word from prev step  */ data  = _enc_word << 26;
                _encode_data( wordA, 16 ); data |= _enc_word << 16;
                _encode_data( wordA,  8 ); data |= _enc_word <<  6;
                _encode_data( wordB, 24 ); data |= _enc_word >>  4;
        break;
        // |3:0|3:0|3:0|3:0| 1 |3:1|3:1|3:1|3:1| 1 |3:1|3:1|3:1|3:1| 1 |3:2|
        // |3:2|3:2|3:2| 1 |3:2|3:2|3:2|3:2| 1 |4:0|4:0|4:0|4:0| 1 |4:0|4:0|
        case 3: /* Word from prev step  */ data  = _enc_word << 28;
                _encode_data( wordA, 16 ); data |= _enc_word << 18;
                _encode_data( wordA,  8 ); data |= _enc_word <<  8;
                _encode_data( wordB, 24 ); data |= _enc_word >>  2;
        break;
        // |4:0|4:0| 1 |4:1|4:1|4:1|4:1| 1 |4:1|4:1|4:1|4:1| 1 |4:2|4:2|4:2|
        // |4:2| 1 |4:2|4:2|4:2|4:2| 1 |5:0|5:0|5:0|5:0| 1 |5:0|5:0|5:0|5:0|
        case 4: /* Word from prev step  */ data  = _enc_word << 30;
                _encode_data( wordA, 16 ); data |= _enc_word << 20;
                _encode_data( wordA,  8 ); data |= _enc_word << 10;
                _encode_data( wordB, 24 ); data |= _enc_word >>  0;
        break;
        // | 1 |5:1|5:1|5:1|5:1| 1 |5:1|5:1|5:1|5:1| 1 |5:2|5:2|5:2|5:2| 1 |
        // |5:2|5:2|5:2|5:2| 1 |6:0|6:0|6:0|6:0| 1 |6:0|6:0|6:0|6:0| 1 |6:1|
        case 5: _encode_data( wordA, 16 ); data  = _enc_word << 22;
                _encode_data( wordA,  8 ); data |= _enc_word << 12;
                _encode_data( wordB, 24 ); data |= _enc_word <<  2;
                _encode_data( wordB, 16 ); data |= _enc_word >>  8;
        break;
        // |6:1|6:1|6:1| 1 |6:1|6:1|6:1|6:1| 1 |6:2|6:2|6:2|6:2| 1 |6:2|6:2|
        // |6:2|6:2| 1 |7:0|7:0|7:0|7:0| 1 |7:0|7:0|7:0|7:0| 1 |7:1|7:1|7:1|
        case 6: /* Word from prev step  */ data  = _enc_word << 24;
                _encode_data( wordA,  8 ); data |= _enc_word << 14;
                _encode_data( wordB, 24 ); data |= _enc_word <<  4;
                _encode_data( wordB, 16 ); data |= _enc_word >>  6;
        break;
        // |7:1| 1 |7:1|7:1|7:1|7:1| 1 |7:2|7:2|7:2|7:2| 1 |7:2|7:2|7:2|7:2|
        // | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |ub0|ub1|ub2|ub3|
        case 7: /* Word from prev step  */ data  = _enc_word << 26;
                _encode_data( wordA,  8 ); data |= _enc_word << 16;
                // TODO - encode user data rather than hard-coding zeros
                //if( _enc_word & 1 ) _tx_carry = data |= 0b0000000000011111;
                if( _enc_word & 1 ) data |= 0b0000000000011111;
                else _enc_word = data |= 0b1111111111100000;
                _enc_word = data;
        break;
    }
    _xperipherals_adat_tx_2__port_txd <: bitrev( data );
}

#elif XPERIPHERALS_ADAT_TX_2__BCLK_SPEED == 4

#endif

#endif

xperipherals_adat_rx_1.xc

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

#include "xperipherals_adat.h"

// 256-Bit ADAT Packet
//
// The packet structure below shows [Channel Number]:[Sample Bit Pos] for audio samples.
// The 256-bit sequence is NRZI encoded when transmitting and NRZI decoded when receiving.
// Samples are serialized MSB first (:00 represents MSB and :23 represents LSB)
//
// Note: Bit stuffing with 'ones' every fifth bit and NRZI encoding prevents long runs
// of zeros. The zero's at the end of the frame are used for frame synchronization.
//
// 0 |one |0:00|0:01|0:02|0:03|one |0:04|0:05|0:06|0:07|one |0:08|0:09|0:10|0:11|one |
//   |0:12|0:13|0:14|0:15|one |0:16|0:17|0:18|0:19|one |0:20|0:21|0:22|0:23|one |1:00|
// 1 |1:01|1:02|1:03|one |1:04|1:05|1:06|1:07|one |1:08|1:09|1:10|1:11|one |1:12|1:13|
//   |1:14|1:15|one |1:16|1:17|1:18|1:19|one |1:20|1:21|1:22|1:23|one |2:00|2:01|2:02|
// 2 |2:03|one |2:04|2:05|2:06|2:07|one |2:08|2:09|2:10|2:11|one |2:12|2:13|2:14|2:15|
//   |one |2:16|2:17|2:18|2:19|one |2:20|2:21|2:22|2:23|one |3:00|3:01|3:02|3:03|one |
// 3 |3:04|3:05|3:06|3:07|one |3:08|3:09|3:10|3:11|one |3:12|3:13|3:14|3:15|one |3:16|
//   |3:17|3:18|3:19|one |3:20|3:21|3:22|3:23|one |4:00|4:01|4:02|4:03|one |4:04|4:05|
// 4 |4:06|4:07|one |4:08|4:09|4:10|4:11|one |4:12|4:13|4:14|4:15|one |4:16|4:17|4:18|
//   |4:19|one |4:20|4:21|4:22|4:23|one |5:00|5:01|5:02|5:03|one |5:04|5:05|5:06|5:07|
// 5 |one |5:08|5:09|5:10|5:11|one |5:12|5:13|5:14|5:15|one |5:16|5:17|5:18|5:19|one |
//   |5:20|5:21|5:22|5:23|one |6:00|6:01|6:02|6:03|one |6:04|6:05|6:06|6:07|one |6:08|
// 6 |6:09|6:10|6:11|one |6:12|6:13|6:14|6:15|one |6:16|6:17|6:18|6:19|one |6:20|6:21|
//   |6:22|6:23|one |7:00|7:01|7:02|7:03|one |7:04|7:05|7:06|7:07|one |7:08|7:09|7:10|
// 7 |7:11|one |7:12|7:13|7:14|7:15|one |7:16|7:17|7:18|7:19|one |7:20|7:21|7:22|7:23|
//   |one |zero|zero|zero|zero|zero|zero|zero|zero|zero|zero|one |usr0|usr1|usr2|usr3|

#ifdef XPERIPHERALS_ADAT_RX_1

on tile[XPERIPHERALS_ADAT_RX_1__TILE_NUMBER] :
out buffered port:32 _xperipherals_adat_rx_1__port_rxd = XPERIPHERALS_ADAT_RX_1__RXD_PORT;

static xuint _bclk_divider;
static xuint _encode_lut[256];
static xuint _enc_word;
static xuint _tx_carry;

void xperipherals_adat_rx_1__init( xuint bclk_divider )
{
    _bclk_divider = bclk_divider;
    _enc_word = _tx_carry = 0;

    switch( _bclk_divider )
    {
        case 1: // bit clock frequency = 1 * ADAT bit rate = 12.288 / 11.2896 MHz
        for( int j = 0; j < 256; ++j ) {
            xuint carry = 0; xuint data = 0b1000010000 | ((j & 0xF0) << 1) | (j & 0x0F);
            _encode_lut[j] = 0;
            for( int i = 0; i < 10; ++i, data <<= 1 ) {
                if( data & 0b1000000000 ) carry = !carry;
                _encode_lut[j] = (_encode_lut[j] << 1) | carry;
            }
        }
        break;

        case 2: // bit clock frequency = 2 * ADAT bit rate = 24.576 / 22.5792 MHz
        // TODO
        break;

        case 4: // bit clock frequency = 4 * ADAT bit rate = 49.152 / 45.1584 MHz
        // TODO
        break;
    }
}

void xperipherals_adat_rx_1__config( clock bit_clock )
{
        configure_out_port_no_ready( _xperipherals_adat_rx_1__port_rxd, bit_clock, 0 );
        clearbuf( _xperipherals_adat_rx_1__port_rxd );
}

#pragma unsafe arrays
static void _decode_data( xuint sample, xuint shift )
{
}

// |one |0:00|0:01|0:02|0:03|one |0:04|0:05|0:06|0:07|one |0:08|0:09|0:10|0:11|one |
// |0:12|0:13|0:14|0:15|one |0:16|0:17|0:18|0:19|one |0:20|0:21|0:22|0:23|one |1:00|

void xperipherals_adat_rx_1__phase0( xsint& sample_0, xsint& sample_1 )
{
    xuint data;
    _xperipherals_adat_rx_1__port_rxd :> data; data = bitrev( data );
}

// |1:01|1:02|1:03|one |1:04|1:05|1:06|1:07|one |1:08|1:09|1:10|1:11|one |1:12|1:13|
// |1:14|1:15|one |1:16|1:17|1:18|1:19|one |1:20|1:21|1:22|1:23|one |2:00|2:01|2:02|

void xperipherals_adat_rx_1__phase1( xsint& sample_1, xsint& sample_2 )
{
    xuint data;
    _xperipherals_adat_rx_1__port_rxd :> data; data = bitrev( data );
}

// |2:03|one |2:04|2:05|2:06|2:07|one |2:08|2:09|2:10|2:11|one |2:12|2:13|2:14|2:15|
// |one |2:16|2:17|2:18|2:19|one |2:20|2:21|2:22|2:23|one |3:00|3:01|3:02|3:03|one |

void xperipherals_adat_rx_1__phase2( xsint& sample_2, xsint& sample_3 )
{
    xuint data;
    _xperipherals_adat_rx_1__port_rxd :> data; data = bitrev( data );
}

// |3:04|3:05|3:06|3:07|one |3:08|3:09|3:10|3:11|one |3:12|3:13|3:14|3:15|one |3:16|
// |3:17|3:18|3:19|one |3:20|3:21|3:22|3:23|one |4:00|4:01|4:02|4:03|one |4:04|4:05|

void xperipherals_adat_rx_1__phase3( xsint& sample_3, xsint& sample_4 )
{
    xuint data;
    _xperipherals_adat_rx_1__port_rxd :> data; data = bitrev( data );
}

// |4:06|4:07|one |4:08|4:09|4:10|4:11|one |4:12|4:13|4:14|4:15|one |4:16|4:17|4:18|
// |4:19|one |4:20|4:21|4:22|4:23|one |5:00|5:01|5:02|5:03|one |5:04|5:05|5:06|5:07|

void xperipherals_adat_rx_1__phase4( xsint& sample_4, xsint& sample_5 )
{
    xuint data;
    _xperipherals_adat_rx_1__port_rxd :> data; data = bitrev( data );
}

// |one |5:08|5:09|5:10|5:11|one |5:12|5:13|5:14|5:15|one |5:16|5:17|5:18|5:19|one |
// |5:20|5:21|5:22|5:23|one |6:00|6:01|6:02|6:03|one |6:04|6:05|6:06|6:07|one |6:08|

void xio_adat_tx_1__phase5( xsint& sample_5, xsint& sample_6 )
{
    xuint data;
    _xperipherals_adat_rx_1__port_rxd :> data; data = bitrev( data );
}

// |6:09|6:10|6:11|one |6:12|6:13|6:14|6:15|one |6:16|6:17|6:18|6:19|one |6:20|6:21|
// |6:22|6:23|one |7:00|7:01|7:02|7:03|one |7:04|7:05|7:06|7:07|one |7:08|7:09|7:10|

void xio_adat_tx_1__phase6( xsint& sample_6, xsint& sample_7 )
{
    xuint data;
    _xperipherals_adat_rx_1__port_rxd :> data; data = bitrev( data );
}

// |7:11|one |7:12|7:13|7:14|7:15|one |7:16|7:17|7:18|7:19|one |7:20|7:21|7:22|7:23|
// |one |zero|zero|zero|zero|zero|zero|zero|zero|zero|zero|one |Usr0|Usr1|Usr2|Usr3|

void xio_adat_tx_1__phase7( xsint& sample_7, xuint& userdata )
{
    xuint data;
    _xperipherals_adat_rx_1__port_rxd :> data; data = bitrev( data );
}

#endif

xperipherals_adat_rx_2.xc

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

#include "xperipherals_adat.h"

// 256-Bit ADAT Packet
//
// The packet structure below shows [Channel Number]:[Sample Bit Pos] for audio samples.
// The 256-bit sequence is NRZI encoded when transmitting and NRZI decoded when receiving.
// Samples are serialized MSB first (:00 represents MSB and :23 represents LSB)
//
// Note: Bit stuffing with 'ones' every fifth bit and NRZI encoding prevents long runs
// of zeros. The zero's at the end of the frame are used for frame synchronization.
//
// 0 |one |0:00|0:01|0:02|0:03|one |0:04|0:05|0:06|0:07|one |0:08|0:09|0:10|0:11|one |
//   |0:12|0:13|0:14|0:15|one |0:16|0:17|0:18|0:19|one |0:20|0:21|0:22|0:23|one |1:00|
// 1 |1:01|1:02|1:03|one |1:04|1:05|1:06|1:07|one |1:08|1:09|1:10|1:11|one |1:12|1:13|
//   |1:14|1:15|one |1:16|1:17|1:18|1:19|one |1:20|1:21|1:22|1:23|one |2:00|2:01|2:02|
// 2 |2:03|one |2:04|2:05|2:06|2:07|one |2:08|2:09|2:10|2:11|one |2:12|2:13|2:14|2:15|
//   |one |2:16|2:17|2:18|2:19|one |2:20|2:21|2:22|2:23|one |3:00|3:01|3:02|3:03|one |
// 3 |3:04|3:05|3:06|3:07|one |3:08|3:09|3:10|3:11|one |3:12|3:13|3:14|3:15|one |3:16|
//   |3:17|3:18|3:19|one |3:20|3:21|3:22|3:23|one |4:00|4:01|4:02|4:03|one |4:04|4:05|
// 4 |4:06|4:07|one |4:08|4:09|4:10|4:11|one |4:12|4:13|4:14|4:15|one |4:16|4:17|4:18|
//   |4:19|one |4:20|4:21|4:22|4:23|one |5:00|5:01|5:02|5:03|one |5:04|5:05|5:06|5:07|
// 5 |one |5:08|5:09|5:10|5:11|one |5:12|5:13|5:14|5:15|one |5:16|5:17|5:18|5:19|one |
//   |5:20|5:21|5:22|5:23|one |6:00|6:01|6:02|6:03|one |6:04|6:05|6:06|6:07|one |6:08|
// 6 |6:09|6:10|6:11|one |6:12|6:13|6:14|6:15|one |6:16|6:17|6:18|6:19|one |6:20|6:21|
//   |6:22|6:23|one |7:00|7:01|7:02|7:03|one |7:04|7:05|7:06|7:07|one |7:08|7:09|7:10|
// 7 |7:11|one |7:12|7:13|7:14|7:15|one |7:16|7:17|7:18|7:19|one |7:20|7:21|7:22|7:23|
//   |one |zero|zero|zero|zero|zero|zero|zero|zero|zero|zero|one |usr0|usr1|usr2|usr3|

#ifdef XPERIPHERALS_ADAT_RX_2

on tile[XPERIPHERALS_ADAT_RX_2__TILE_NUMBER] :
out buffered port:32 _xperipherals_adat_rx_2__port_rxd = XPERIPHERALS_ADAT_RX_2__RXD_PORT;

static xuint _bclk_divider;
static xuint _encode_lut[256];
static xuint _enc_word;
static xuint _tx_carry;

void xperipherals_adat_rx_2__init( xuint bclk_divider )
{
    _bclk_divider = bclk_divider;
    _enc_word = _tx_carry = 0;

    switch( _bclk_divider )
    {
        case 1: // bit clock frequency = 1 * ADAT bit rate = 12.288 / 11.2896 MHz
        for( int j = 0; j < 256; ++j ) {
            xuint carry = 0; xuint data = 0b1000010000 | ((j & 0xF0) << 1) | (j & 0x0F);
            _encode_lut[j] = 0;
            for( int i = 0; i < 10; ++i, data <<= 1 ) {
                if( data & 0b1000000000 ) carry = !carry;
                _encode_lut[j] = (_encode_lut[j] << 1) | carry;
            }
        }
        break;

        case 2: // bit clock frequency = 2 * ADAT bit rate = 24.576 / 22.5792 MHz
        // TODO
        break;

        case 4: // bit clock frequency = 4 * ADAT bit rate = 49.152 / 45.1584 MHz
        // TODO
        break;
    }
}

void xperipherals_adat_rx_2__config( clock bit_clock )
{
        configure_out_port_no_ready( _xperipherals_adat_rx_2__port_rxd, bit_clock, 0 );
        clearbuf( _xperipherals_adat_rx_2__port_rxd );
}

#pragma unsafe arrays
static void _decode_data( xuint sample, xuint shift )
{
}

// |one |0:00|0:01|0:02|0:03|one |0:04|0:05|0:06|0:07|one |0:08|0:09|0:10|0:11|one |
// |0:12|0:13|0:14|0:15|one |0:16|0:17|0:18|0:19|one |0:20|0:21|0:22|0:23|one |1:00|

void xperipherals_adat_rx_2__phase0( xsint& sample_0, xsint& sample_1 )
{
    xuint data;
    _xperipherals_adat_rx_2__port_rxd :> data; data = bitrev( data );
}

// |1:01|1:02|1:03|one |1:04|1:05|1:06|1:07|one |1:08|1:09|1:10|1:11|one |1:12|1:13|
// |1:14|1:15|one |1:16|1:17|1:18|1:19|one |1:20|1:21|1:22|1:23|one |2:00|2:01|2:02|

void xperipherals_adat_rx_2__phase1( xsint& sample_1, xsint& sample_2 )
{
    xuint data;
    _xperipherals_adat_rx_2__port_rxd :> data; data = bitrev( data );
}

// |2:03|one |2:04|2:05|2:06|2:07|one |2:08|2:09|2:10|2:11|one |2:12|2:13|2:14|2:15|
// |one |2:16|2:17|2:18|2:19|one |2:20|2:21|2:22|2:23|one |3:00|3:01|3:02|3:03|one |

void xperipherals_adat_rx_2__phase2( xsint& sample_2, xsint& sample_3 )
{
    xuint data;
    _xperipherals_adat_rx_2__port_rxd :> data; data = bitrev( data );
}

// |3:04|3:05|3:06|3:07|one |3:08|3:09|3:10|3:11|one |3:12|3:13|3:14|3:15|one |3:16|
// |3:17|3:18|3:19|one |3:20|3:21|3:22|3:23|one |4:00|4:01|4:02|4:03|one |4:04|4:05|

void xperipherals_adat_rx_2__phase3( xsint& sample_3, xsint& sample_4 )
{
    xuint data;
    _xperipherals_adat_rx_2__port_rxd :> data; data = bitrev( data );
}

// |4:06|4:07|one |4:08|4:09|4:10|4:11|one |4:12|4:13|4:14|4:15|one |4:16|4:17|4:18|
// |4:19|one |4:20|4:21|4:22|4:23|one |5:00|5:01|5:02|5:03|one |5:04|5:05|5:06|5:07|

void xperipherals_adat_rx_2__phase4( xsint& sample_4, xsint& sample_5 )
{
    xuint data;
    _xperipherals_adat_rx_2__port_rxd :> data; data = bitrev( data );
}

// |one |5:08|5:09|5:10|5:11|one |5:12|5:13|5:14|5:15|one |5:16|5:17|5:18|5:19|one |
// |5:20|5:21|5:22|5:23|one |6:00|6:01|6:02|6:03|one |6:04|6:05|6:06|6:07|one |6:08|

void xio_adat_tx_2__phase5( xsint& sample_5, xsint& sample_6 )
{
    xuint data;
    _xperipherals_adat_rx_2__port_rxd :> data; data = bitrev( data );
}

// |6:09|6:10|6:11|one |6:12|6:13|6:14|6:15|one |6:16|6:17|6:18|6:19|one |6:20|6:21|
// |6:22|6:23|one |7:00|7:01|7:02|7:03|one |7:04|7:05|7:06|7:07|one |7:08|7:09|7:10|

void xio_adat_tx_2__phase6( xsint& sample_6, xsint& sample_7 )
{
    xuint data;
    _xperipherals_adat_rx_2__port_rxd :> data; data = bitrev( data );
}

// |7:11|one |7:12|7:13|7:14|7:15|one |7:16|7:17|7:18|7:19|one |7:20|7:21|7:22|7:23|
// |one |zero|zero|zero|zero|zero|zero|zero|zero|zero|zero|one |Usr0|Usr1|Usr2|Usr3|

void xio_adat_tx_2__phase7( xsint& sample_7, xuint& userdata )
{
    xuint data;
    _xperipherals_adat_rx_2__port_rxd :> data; data = bitrev( data );
}

#endif