Jitter-less 20 bits Digital-to-Analog  Converter

 

Project Description

 

 

S.V. Smirnov, Moscow, 2003


 

Настоящий документ представляет собой описание выносного блока цифро-аналогового преобразования (ЦАП) под условным названием ClockXtream.

Основные особенности конструкции:

 

 

 

 

Упрощенная функциональная блок-схема устройства представлена на рис.1

 

Рисунок 1

 

 

 

 

 


Особенности конструкции

 

Конструктивно, блок ЦАП предполагается выполнить в виде двух плат – основной платы ЦАП и платы первичных стабилизаторов напряжения. Силовые трансформаторы (для питания цифровой, аналоговой частей и схемы тактового генератора) располагаются на шасси корпуса ЦАП.

На задней стенке шасси расположены:

 

На передней панели блока ЦАП расположены:

 

Предусмотрено подключение платы управления и индикации через специальный разъем на основной плате. В отсутствии платы управления и индикации, управление режимами работы блока ЦАП осуществляется либо с помощью перемычек (Jumpers), либо через интерфейс RS-232 командами с удаленного компьютера. Подробное описание управляющих перемычек (Jumpers) и команд управления  интерфейса RS-232 приведены в соответствующих разделах. Индикация основных режимов работы осуществляется светодиодами, установленными на передней панели.

Подключение дополнительных источников (DVD-A), предусмотрено через дополнительную плату приемника S/PDIF, через специальный разъем, установленный на основной плате ЦАП.

 

Конструктивно, основная плата представляет собой 4-х слойную печатную плату (диэлектрик – FR4, толщина проводников - ). Цифровая и аналоговая части развязаны гальванически с помощью оптоэлектронных трансиверов ISO150. При этом, задающий тактовый генератор и триггеры конечной синхронизации располагаются в аналоговой части платы, в непосредственной близости от м\с ЦАП. Тактовый сигнал CLK (256x), необходимый для работы цифровой части (цифрового фильтра, приемника аудиоданных, FPGA и тд), передается из аналоговой части в цифровую по одному из каналов  ISO150. Цифровая часть содержит все необходимые элементы для приема аудиоданных (CS8412), передискретизации (PMD-100), управления режимами работы (FPGA и MCU) и индикации. Для уменьшения влияния цифровой части на аналоговую и задающий генератор, предусмотрена возможность электрического экранирования цифровой и аналоговой частей отдельными экранами. Кроме того, модуль задающего генератора дополнительно экранирован внешним эканом.

 

 

Данное устройство обладает возможностью коммутации различных источников цифрового сигнала:

 


Выбор реализации Функциональных Элементов Блока ЦАП

 

Выбор Приемника аудиоданных

 

Наличие режима Slave, и доступность на рынке, определили выбор в пользу CS8412.

 

Выбор Цифрового Фильтра

 

Был выбран фильтр PMD-100 (HDCD) фирмы Pacific Microsonics. Данный фильтр многими оценивается как один из лучших для формата CD, и, кроме того, обладает широким набором дополнительных функций, доступных через программное управление (регулировка громкости,  семь уровней псевдошума (dither), режимы 2Х, 4Х). Как альтернатива, может быть использован любой цифровой фильтр передискретизации (SM5842, SM5803, DF1700 …) с соответствующей коррекцией схемы.

 

Выбор схемы Тактового генератора

 

Выбор схемы Тактового генератора и топологии доставки тактовых сигналов до м\с ЦАП – ключевое место в решении проблемы джиттера. Кардинальным решением представлялся бы  выбор высокостабильного термостабилизированного (OCXO)  генератора с синусоидальным выходным сигналом, преобразование сигнала генератора в ЭСЛ формат, построение драйвера тактовых сигналов и триггеров конечной пересинхронизации на ЭСЛ логике, преобразование сигналов в ТТЛ\КМОП непосредственно на входе м\с ЦАП. К сожалению генераторы OCXO крайне дороги и, как правило, разрабатываются на несколько стандартных частот (5, 10, 20 МГц). Как альтернатива  OCXO, возможно использование более дешевого термокомпенсированного генератора (TCXO). При наличии высококачественного кристалла кварца, имеет смысл разработать малошумящий тактовый генератор на дискретных элементах. В любом случае, кварц или всю плату генератора следует изолировать механически от основной платы ЦАП и задемпфировать. Учитывая отсутствие отдельного кристалла кварца на необходимую частоту, и предложение Сергея Васянина (SN.Vasyanin@VAZ.RU) поделиться  TCXO генератором на частоту 512х (22,5792 МГц), как начальный вариант, был выбран генератор TCXO с последующим делением частоты на два. При этом сохраняется возможность подключить вместо исходного генератора TCXO любой другой, более высококачественный генератор.

 

Выбор топологии тактовых сигналов

 

Ввиду отсутствия опыта работы с ЭСЛ и желания сократить временные затраты на разработку, было решено строить схему пересинхронизации на КМОП элементах серий АСТ\НСТ. Серия НСТ характеризуется ограниченным быстродействием, малыми искажениями формы сигналов и малыми излучениями на ВЧ. Среднеквадратичная величина джиттера на один вентиль составляет около 2.2 нс [??]. Серия АСТ характеризуется большим быстродействием (меньшей длительностью фронтов), но в тоже время требует приложения определенных усилий для предотвращения искажения сигнала (выбросов на фронтах). Среднеквадратичная величина джиттера на один вентиль составляет около 1 нс [??].

 

Тактовый сигнал с выхода TCXO генератора поступает на делитель на два, и далее – на коммутатор тактовых сигналов. Данный коммутатор (мультиплексор) необходим для обеспечения работы ЦАП либо от внутреннего TCXO генератора, либо от транспорта, либо от внешнего синхронизирующего сигнала.  Драйвер, стоящий после мультиплексора, размножает тактовый сигнал на несколько отдельных сигналов. Каждый из входных сигналов м\с ЦАП пересинхронизируется на отдельном триггере. Таким образом, каждый триггер тактируется отдельным сигналом, поступающим от драйвера тактового сигнала. Данное построение представляет своего рода компромисс, так как увеличивает число цифровых устройств на пути тактового сигнала.

 

Выбор м\с ЦАП

 

При выборе м\с ЦАП симпатии были на стороне ”мультибитовых” ЦАП. Кроме субъективных оценок, которые, как правило, положительны, данный тип ЦАП обладает тем преимуществом, что позволяет работать с частотами дискретизации от 44.1 до 400 кГц. К примеру, можно реализовать как режим 1х (Fs=44.1 кГц) без применения цифровой фильтрации, так и режим 8х (Fs=352.8 кГц), используя промышленный или программный фильтр-интерполятор. В случае использования источника DVD-A 192 kHz, возможно обойтись без использования цифровой фильтрации при ц\а преобразовании, подав сигнал непосредственно на ЦАП.

Среди ”мультибитовых” ЦАП, наверное, самым достойным является модуль Ultra Analog D20400, обеспечивающий “честные” 20 бит разрядности при частоте дискретизации 400 кГц. В качестве альтернативы редким и уже не выпускающимся ЦАП Ultra Analog D20400 можно применить м\с PCM63 и PCM1702 с соответствующей коррекцией схемы питания, схемы преобразования ток-напряжение и топологии печатной платы. Для понижения уровня шумов квантования (и соответственно увеличения динамического диапазона), можно применить параллельное включение нескольких одинаковых ЦАП. Удвоение числа ЦАП дает около 3 дБ выигрыша в силу некоррелированности шумов квантования отдельных ЦАП. Реальный же выигрыш, скорее всего будет ниже.

 


Выбор схемы аналоговой постфильтрации

 

Не имея собственного опыта прослушивания различных вариантов схем аналоговой постфильтрации, и основываясь исключительно на отзывах сторонних разработчиков ЦАП, было решено делать два параллельных варианта фильтров. Первый – пассивный L-C фильтр Баттерворта третьего, четвертого или пятого порядка [??]. Конкретный порядок фильтра, а так же тип используемых компонентов будет определяться в процессе настройки и прослушивания. Предполагается обеспечить максимальную гибкость в установке различных элементов фильтра на плате на этапе разводки.

Второй вариант фильтра - активный фильтр Бесселя 7-го порядка на GIC элементах. Данная схема (вместе с выходным буфером) была позаимствована из Application Notes фирмы Analog Devices [??]. При желании, данная схема может быть трансформирована в GIC фильтр более низкого порядка (естественно, с соответствующим перерасчетом номиналов элементов). Выход данного фильтра представляет собой дифференциальный сигнал.

 

 

Выбор схемы буферного каскада

 

Для пассивного L-C фильтра предполагается использовать буферный каскад (“параллельный” повторитель) на дискретных элементах. Поскольку выход м\с представляет собой источник напряжения (с размахом сигнала 5В), возникло желание обойтись без традиционного усилителя напряжения, сократив таким образом число активных компонентов в цепи аналогового сигнала. Недостатком данного решения видится уменьшение амплитуды сигнала в два раза, что потребует наличия запаса по усилению последующего УНЧ. Данные потери обусловлены желанием иметь симметричный по нагрузкам входа\выхода фильтр. При этом, выходное сопротивление источника сигнала для фильтра реализуется последовательным включением резистора  на выходе ЦАП.

Режимы работы транзисторов выбраны из условия работы буфера на низкоомную нагрузку (30 Ом) при малом сигнале (около 100 мВт). Данное условие определено желанием иметь возможность  подключения низкоомных головных телефонов (типа Grado SR-125) непосредственно на выход буферного каскада.

 

Выбор схем питания цифровых устройств

 

Для питания цифровых устройств использованы интегральные стабилизаторы MIC5205 (Micrel). Данные стабилизаторы обладают хорошей стабильностью, малыми потерями и низкими шумами. Единственный недостаток – небольшой выходной ток (не более 200 мА). Поэтому для относительно сильноточных устройств (как фильтр PMD100 и светодиоды) использованы стабилизаторы MC78M05 (500mA). Вся цифровая часть условно разбита на несколько узлов, каждый из которых питается от отдельного стабилизатора. Наиболее пристальное внимание питанию было уделено в схемах задающего генератора, драйвера тактовых импульсов и триггеров пересинхронизации непосредственно перед модулем ЦАП. Каждая микросхема запитывается через локальный фильтр, состоящий из “ferrite bead” и керамической емкости.

 

Выбор схем питания аналоговых устройств

 

Питание аналоговой части ЦАП и последующих каскадов предполагается осуществлять с помощью быстродействующих параллельных стабилизаторов, питающихся, в свою очередь, от источника тока. В качестве генераторов опорного напряжения активно использованы устройства TL431. В качестве альтернативы, в случае неудовлетворительной работы данных стабилизаторов, имеется возможность задействовать традиционные параметрические стабилизаторы.

 

 

Построение цифровой части устройства

 

Всю цифровую часть можно разбить на собственно цифровую (содержащую специализированные СБИС, микроконтроллер и программируемую логическую матрицу - FPGA) и аналоговую часть, содержащую тактовый генератор, и схему пересинхронизации. В отличие от других проектов [??], раздел между  цифровой и аналоговой частями был проведен на входе конечных триггеров пересинхронизации. Принципиальным моментом здесь является то, что между тактовым генератором и цифровыми входами м\с ЦАП должно быть минимум цифровых устройств, и не должно содержаться никаких цифро-аналоговых трансляторов сигнала (типа оптопар, развязок ISO-150 и др.). Исходя из данных на разброс параметра задержки оптоизолятора ISO-150, можно сделать вывод о гораздо большем вкладе в увеличение фазовых флюктуаций фронтов этих устройств, чем типовых цифровых КМОП устройств (серий АСТ и НСТ).

Таким образом, тактовый генератор, и схема конечной пересинхронизации отделена от остальной (основной) цифровой части и располагается в непосредственной близи от м\с ЦАП. Вопрос взаимовлияния тактового генератора, схемы пересинхронизации и аналоговых каскадов (включая сам ЦАП) будет решен конструктивно, выбором соответствующей топологии печатной платы.

Собственно цифровая часть содержит приемник аудиоданных, цифровой фильтр, чип FPGA, контроллер, чип преобразователя уровней интерфейса RS-232, отдельные логические элементы, необходимые для работы платы, ГУН – формирователь частоты 384*Fs, буферы выходных синхросигналов.

 

Входной поток аудиоданных поступает на вход приемника CS8412 через импульсный трансформатор. Предполагается использование одного из двух входов для связи с источником аудиоданных – либо 50-ти омный BNC разъем, либо 75-ти омный RCA  разъем. Одновременное подключение источников к двум входам не допускается. Приемник CS8412 включен по традиционной схеме, за исключением режима SLAVE, что подразумевает использования выводов SCK и FSYNC как входов для внешнего генератора тактовых сеток (64*Fs, Fs). Сигналы SCK и FSYNC поступают от FPGA, где реализован основной объем логических элементов. Используются два сигнала управления режимами работы приемника CS8412:

 

Подключение цифрового фильтра PMD-100 к CS8412 традиционно, за исключением следующего:

 

Для уменьшения интерференции с основным тактовым сигналом (MCLK), тактовый сигнал, выделенный приемником из потока аудиоданных (MCK) блокируется вентилем U105, когда ЦАП работает в режиме MASTER (сигнал M/S_SEL = “0”). В случае, когда ЦАП работает в режиме SLAVE (тактируется от транспорта), сигнал MCK[R] поступает в аналоговую часть на коммутатор тактового сигнала и далее возвращается обратно в цифровую часть под видом основного тактового сигнала MCLK.

 

В цифровом фильтре использованы практически все возможности управления режимами работы. При этом, в зависимости от того, используется ли процессорное управление, или управление с помощью перемычек, фильтр PMD-100 как же переходит либо в режим Program, либо в режим Stand Alone.

 

Чип FPGA управляется контроллером (MCU) через 8-ми разрядную шину данных. В отсутствии контроллера и каждый раз после включения питания, все внутренние регистры FPGA, устанавливаются в определенное исходное состояние (см. описание FPGA).

 

Микроконтроллер тактируется сигналом MCU_CLK (сигнал SCK), частотой MCLK/4=Fs*64 (2.8224 МГц, в случае использования основного тактового генератора с частотой 11.2896 МГц, или 3.072, в случае использования основного тактового генератора с частотой 12.288 МГц). Это позволяет использовать встроенный в микроконтроллер UART на скорости 1200 бит\с в первом случае или 19200 бит\с во втором без рассогласования частот интерфейса.

 

 

 

 


Описание внутренней структуры FPGA

 

Большая часть логических элементов, необходимых для выполнения системных функций управления блоком ЦАП, реализована в виде программируемой логической матрицы (FPGA) EPF6016ATC144-3 фирмы Altera. Выбор конкретного чипа был обусловлен его наличием на этапе проектирования. Может быть использован другой чип FPGA (фирм Altera, Xilinx …) достаточного объема и быстродействия. Исходный код написан на языке Verilog, что упрощает его перенос на чипы других производителей FPGA/PLD. Исходтый текст программы для всех модулей приведен в приложении 1.

Функциональная блок-схема модулей FPGA приведена ниже:

 

 

 


Функциональное описание модулей:

 


  • Asi_1x_conv       Преобразователь последовательного потока аудиоданных, поступающего от платы приемника CS8416, в формат данных ЦАП. Поддерживает режимы 1х, 2х, 4х частоты дискретизации (соответственно  48кГц,  96кГц, 192кГц при частоте задающего генератора равной 12,288 МГц). Кроме того, модуль формирует сигнал De-Glitch (asi_dg) на основе значений dgi_rise, dgi_fall.

 

 


  • Cs8412_1x_conv                             Преобразователь последовательного потока аудиоданных, поступающего от приемника CS8412, в формат данных ЦАП. Используется только режим 1х (44.1кГц при частоте задающего генератора равной 11,2896 МГц). Кроме того, модуль формирует сигнал De-Glitch (cs8412_dg) на основе значений dgi_rise, dgi_fall.

 

 


  • Dsp_dg_conv      Формирователь сигнала De-Glitch для потока аудиоданных, поступающего от внешней платы DSP, на основе значений dgi_rise, dgi_fall. Предполагается, что остальные сигналы от внешней платы DSP соответствуют формату  данных ЦАП.

 

 


  • Sync_out_former             Формирователь (мультиплексор) выходного цифрового сигнала синхронизации. Может быть выбран один из режимов – 1х, 2х, 32х, 64х, 128х, 256х (CLK), или запрет сигнала синхронизации (по умолчанию). Кроме того, в данном модуле реализован делитель на 3, необходимый для работы генератора сигнала 384*Fs.

 

 

 


 

 

 

 

 

 


Внутренние регистры FPGA

 

Внутренне адресное пространство FPGA  состоит из пяти 8-ми разрядных регистров:

 

Address

R/W

Function

Description

0

R/W

Data_Control_Register_0

d[2:0] Audio Data Source Select:

0 – PMD-100. The 8x oversampling mode as default. The 4x, 2x mode are available by PMD-100 program control from MCU.

1 – CS8412 (CD-DA 1x mode);

2 – DSP (external). The sampling frequency is equal Fclk/32, which corresponds to 8x mode for CD-DA source.

3 – reserved;

4 – ASI (External, 1x mode, 48kHz);

5 – ASI (External, 2x mode, 96kHz);

6 – ASI (External, 4x mode, 192 kHz);

7 – reserved;

d[3] Phase Reverse

0 – Data as is;

1 – Data Phase is Reversed;

d[4] Soft Mute by PMD-100.

Operating when PMD-100 Data Source is selected.

0 – No Mute;

1 – Soft Mute is ON;

d[5] Hard Mute by PMD-100.

Operating when PMD-100 Data Source is selected.

0 – Hard Mute is ON;

1 – No Mute;

d[6] Dither by PMD-100.

Operating when PMD-100 Data Source is selected.

0 – Dither OFF;

1 – Dither ON;

[7] Non-HDCD signal Scaling  method by PMD-100.

Scaling (decreasing by 2 time) method selection for Standard (Non HDCD) signals.

Operating when PMD-100 Data Source is selected.

0 – Scaling in Digital domain (degrading of CD-DA resolution to 15 bit!). In this case, the loudness will be similar for regular and HDCD tracks;

1 – Scaling in Analog Domain (if realized). This feature have not been realized, so regular CD-DA signals passes through as is, and sounds two time louder then HDCD tracks;

 

The default value after reset: [7:0] 11100000


 

1

R/W

Data_Control_Register_1

d[2:0] Digital_Sync_Out_Select

Defines the frequency at the Digital Sync Output

0 – Digital Sync is disabled;

1 – Fs (Focs/256);

2 – 2*Fs;

3 – 32*Fs;

4 – 64*Fs;

5 – 128*Fs;

6 – 256*Fs;

7 – 384*Fs;

d[3] CS8412 Mode

0 – Normal Mode;

1 – Special Mode (No repeat data samples on ERRORs);

d[4] CS8412 Output Codes Mode .

0 – ERROR Code is presented on E0/C0, E1/CA, E2/CB outputs;

1 – Channel Status Code is presented on F0/CC and other outputs. Used for De-Emphasis automatic control.

d[5] DAC Unit Synchronization mode.

Defines the Master/Slave mode for ClockXtream DAC unit.

0 – DAC is Master;

1 – DAC is Slave;

d[6] Hardware Control Mode.

Defines the type of hardware and signal control mode.

0 – Processor Control. Available only when J103 is closed.

1 – Jumpers Control;

[7] ASI Bit Clock Phase Select

Defines the SCKI signal phase referenced to FSI signal.

0 – Each bit clock sample burst begins with falling edge of SCKI signal. The data bits are latched to FPGA by  rising edge of SCKI;

1 – Each bit clock sample burst begins with rising edge of SCKI signal. The data bits are latched to FPGA by  falling edge of SCKI

 

The default value after reset: [7:0] 00010000

2

R/W

De-Glitch_Control_0

d[4:0] De-Glitch Strobe. Rising Edge position of DG signal. The 5’b00000 value corresponds to position of rising edge of DG signal at the falling edge of WCKO sample clock signal (D/A conversion begins).

d[7:5] Reserved

3

R/W

De-Glitch_Control_1

d[4:0] De-Glitch Strobe. Falling Edge position of DG signal. The 5’b00000 value corresponds to position of falling edge of DG signal at the falling edge of WCKO sample clock signal (D/A conversion begins).

d[7:5] Reserved

4

R/W

GPO_Register

D[7:0] General Purpose Register. Defines the value at the GP7…GP0 output pins of FPGA. This pins connected to P218…P225 test pins of the pc board.

5…7

-

No

 

 

 

 

 

Выбор контроллера (MCU)

 

Для управления режимами работы ЦАП был использован микроконтроллер AT90LS8535-4AC фирмы ATMEL.  Параметры микроконтроллера, определившие выбор:

·       8 K bytes FLASH с возможностью программирования через SPI (используя принтерный порт РС);

·       512 bytes SRAM;

·       UART;

·       32 I/O Lines;

·       Low Cost ($4)

 

 

Команды управления блоком ЦАП по интерфейсу RS-232

TBD

 

Описание разъемов аппаратного управления (jumpers)

 

J101

Сост.

Название перемычки

Описание положений

1

2

Open

FPGA Reset

Нормальное функционирование FPGA

Close

Сброс  FPGA

 

J103

Сост.

Название перемычки

Описание положений

1

2

Open

Control Mode

Аппаратное управление (jumpers control)

Close

Программное управление (при состоянии сигнала PROC_CTR в “0”)

 

 

J401

Сост.

Название перемычки

Описание положений

1

2

Open

MSB_X

Выравнивание слова данных на входе ЦАП (MSB first)

Close

Выравнивание слова данных на входе ЦАП (LSB first)

 

 

J402/403

Сост.

Название перемычки

Описание положений

1

2

Open

Passive Filter

Should be Close when Passive Filter is used

Close

3

4

Open

Active Filter 1

Should be Close when Active Filter 1 is used

Close

5

6

Open

Active Filter 2

Should be Close when Active Filter 2 is used

Close

 

 

J501

Сост.

Название перемычки

Описание положений

1

2

Open

Output Data for DSP

Данные на интерфейсном разъеме J502 запрещены (Z-состояние)

Close

Данные на интерфейсном разъеме J502 разрешены

 

 

J505

Сост.

Название перемычки

Описание положений

1

2

Open

DITHER

Dither ON

Close

Dither OFF

3

4

Open

HARD MUTE

Hard MUTE is ON

Close

Hard MUTE is OFF (normal operation)

5

6

Open

SOFT MUTE

Soft MUTE is ON

Close

Soft MUTE is OFF (normal operation)

7

8

Open

CS8412 MODE

Special audio port mode (No repeat on Error)

Close

Normal audio port mode (L/R, 16-24 bits)

13

14

Open

Non HDCD Signal

6dB Gain Scaling

Analog Gain Scaling (not realized)

Close

Gain Scaling is performed in the Digital domain of PMD-100

 

 

J506

Сост.

Название перемычки

Описание положений

1

2

Open

PMD-100

Output word size

Should be Close for 20-bits output

Close

3

4

Open

Should be Open for 20-bits output

Close

5

6

Open

PMD-100

Output data format

2’s complement  (default)

Close

Complementary offset binary

7

8

Open

PMD-100

Input data justification

Data right justified 16 bits

Close

Data assumed to be left justified up to 24 bits in length

9

10

Open

PMD-100

Input data latching

Input data latched on falling edge of BCKI

Close

Input data latched on rising edge of BCKI

11

12

Open

DAC

Synchronization Mode

DAC is SLAVE

Close

DAC is MASTER

13

14

Open

CS8412 Status/Errors Outputs mode

Channel Status displays on CA…CE (emphasis control)

Close

ERROR information displays on E0…E2

 

 

 

 

 


Описание Интерфейсных разъемов

 

J201

J502

J503

J504

J507

J508

J404

J405

J406

 

 

Параметры блока ЦАП

 

 

 



Приложение 1. Исходные коды для модулей FPGA (Verilog)

 

 

// Sergey V. Smirnov

//`include "sys_logic.v"

//`include "error_decoder.v"

//`include "clks_former.v"

//`include "cs8412_1x_conv.v"

//`include "asi_1x_conv.v"

//`include "dsp_dg_conv.v"

//`include "sync_out_former.v"

//`include "out_data_mux.v"

 

module top( data, address, oe, wr, clk, rst,    // Data, Address, Read, Write, Master Clock

            bck_en, wcko_o, dat_l, dat_r,

            dg_o,                           // Re-Clocked Output Data for DAC

            bcko, wcko, dol, dor, dg,       // Input Data from PD-100

            sdata, fsync, sck,              // Input Data from SC8412, Data Clocks for CS8412

            sdi, scki, fsi,                 // External data from up to 192kSps source, clocks for external ASI chip (CS8416)

            dsp_dl, dsp_dr, dsp_wck, dsp_bcken, // External data from DSP

            m3, sel,                        // CS8412 Mode Control

            ms_sel, proc_ctrl,              // Sysrem Hardware Control

            dig_sync_out,                   // Digital Sync Output (1x, 2x, 32x, 64x, 128x, 256x, 384x, disable)

            h_mute, s_mute, dither, scal,   // PD-100 Hardware Control

            vco_out, pd_ref, pd_osc,        // 384x PLL VCO signals

            gp0, gp1, gp2, gp3,

            gp4, gp5, gp6, gp7,             // General Purpose Outputs

            e0, e1, e2,                     // Error Code from CS8412

            vbh, cf, sls, pari, bpce, nl    // Decoded Errors signals to LEDs

            );

 

inout [7:0] data;

input [2:0] address;

input oe, wr, clk, rst,

      bcko, wcko, dol, dor, dg,

      dsp_dl, dsp_dr, dsp_wck, dsp_bcken,

      sdata, sdi,

      vco_out;              // 384*Fs signal

input e0, e1, e2;           // Error Code from CS8412

 

output bck_en, wcko_o, dat_l, dat_r, dg_o,      // Re-Clocked Output Data for DAC

       fsync, sck,          // Fs and 64*Fs for CS8412 Receiver

       fsi, scki,           // Fs and 64*Fs for External ASI Receiver chip (CS8416)

       m3, sel,             // CS8412 Mode Control

       dig_sync_out,        // Synchronization Output Clock for Transport

       ms_sel, proc_ctrl,               // Sysrem Hardware Control

       h_mute, s_mute, dither, scal,    // PD-100 Hardware Control

       pd_ref, pd_osc;                  // 384x PLL VCO signals

 

output vbh, cf, sls, pari, bpce, nl,            // LEDs

       gp0, gp1, gp2, gp3, gp4, gp5, gp6, gp7;  // General Purpose Outputs

 

wire oe, wr, clk, rst;

wire [7:0] data_in, data_out;

 

wire fsync, sck, m3, sel, dig_sync_out,

     ms_sel, proc_ctrl, h_mute, s_mute, dither, scal,

     pd_ref, pd_osc, phase_rev;

 

wire bck_en, wcko_o, dat_l, dat_r, dg_o;

 

wire clk1x, clk2x, clk32x, clk4x, clk8x, clk16x, clk64x, clk128x, clk384x;

wire cs8412_dl, cs8412_dr, cs8412_wck, cs8412_bcken, cs8412_dg;

wire asi_dl, asi_dr, asi_wck, asi_bcken, asi_dg;

wire dsp_dl, dsp_dr, dsp_wck, dsp_bcken, dsp_dg;

wire fsync_strb, sck_strb, fsi_strb, scki_strb, bcphase;

wire [2:0] data_source_sel, sync_out_sel;

wire [4:0] dgi_rise, dgi_fall;

 

assign pd_ref = clk128x;

 

assign data_in = data;

assign data = oe ? 8'bz : data_out;

 

/////

//assign

 

//ctsroota1 clocktree_0(.Y(clk), .A(clk_in));

 

sys_logic sys_logic_0 ( data_in, data_out, address, wr, rst,

                        data_source_sel, sync_out_sel, phase_rev, bcphase,

                        h_mute, s_mute, dither, scal,

                        m3, sel, ms_sel, proc_ctrl,

                        dgi_rise, dgi_fall,             // De-Glitch strobe, Edges Position (resolution is 1/32 of Fs)

                        gp0, gp1, gp2, gp3, gp4, gp5, gp6, gp7 );   // General Purpose Outputs

 

error_decoder error_decoder_0(e0, e1, e2,                       // Error Code

                              vbh, cf, sls, pari, bpce, nl);    // Decoded signals to LEDs

 

sync_out_former sync_out_former_0(  clk, rst, vco_out, pd_osc, dig_sync_out,    // CLK = 256*Fs, VCO_OUT = 384*Fs

                                    clk1x, clk2x, clk32x, clk64x, clk128x,      //

                                    sync_out_sel );

 

clks_former clks_former_0(  clk, rst, clk1x, clk2x, clk4x, clk8x, clk16x, clk32x, clk64x, clk128x,

                            fsync, sck, fsync_strb, sck_strb,

                            scki, fsi, fsi_strb, scki_strb,

                            bcphase, data_source_sel);

 

cs8412_1x_conv cs8412_1x_conv_0( clk, rst, sdata, fsync, clk2x, clk4x, clk8x, clk16x,

                                fsync_strb, sck_strb,

                                dgi_rise, dgi_fall,

                                cs8412_dl, cs8412_dr, cs8412_wck, cs8412_bcken, cs8412_dg );

 

asi_1x_conv asi_1x_conv_0(  clk, rst, data_source_sel,

                            clk2x, clk4x, clk8x, clk16x, clk32x, clk64x,

                            sdi, fsi, fsi_strb, scki_strb,

                            dgi_rise, dgi_fall,

                            asi_dl, asi_dr, asi_wck, asi_bcken, asi_dg );

 

dsp_dg_conv dsp_dg_conv_0(  clk, rst,

                            dgi_rise, dgi_fall,

                            dsp_wck, dsp_dg );

 

out_data_mux out_data_mux_0( dat_l, dat_r, bck_en, wcko_o, dg_o,    // Output Signals to DAC

                            data_source_sel, clk, rst, phase_rev,

                            dol, dor, bcko, wcko, dg,              // From PD-100 Digital Filter

                            cs8412_dl, cs8412_dr, cs8412_wck, cs8412_bcken, cs8412_dg,   // From CS8412 S/PDIF Receiver (1x Mode)

                            asi_dl, asi_dr, asi_wck, asi_bcken, asi_dg,  // From external S/PDIF Receiver (like CS8416)

                            dsp_dl, dsp_dr, dsp_wck, dsp_bcken, dsp_dg );  // From external DSP (Fs= up to 384 kHz)

 

 

endmodule


//

 

module asi_1x_conv( clk, rst, data_source_sel,

                    clk2x, clk4x, clk8x, clk16x, clk32x, clk64x,

                    sdi, fsi, fsi_strb, scki_strb,

                    dgi_rise, dgi_fall,

                    asi_dl, asi_dr, asi_wck, asi_bcken, asi_dg );

 

input   clk, rst;   // Global Clock and Reset

input [2:0] data_source_sel;

input   sdi, fsi, clk2x, clk4x, clk8x, clk16x, clk32x, clk64x,

        fsi_strb, scki_strb;   // Strobes for save the data from External Receiver

 

input [4:0] dgi_rise, dgi_fall;     // De-Glitch Interval, rise and fall edge values

 

output  asi_dl, asi_dr, asi_wck, asi_bcken, asi_dg;  // Output to Output Multiplexer

 

reg [19:0] reg_l, reg_r;    // Registers for separate storing of left and right channel data from CS8416 receiver

reg [19:0] dat_l, dat_r;    // Registers for outgoing the L/R data to DAC

reg [4:0]  wcko_reg;        // Counter for WCKO and BCK_EN strobes forming register

reg [1:0]  bck_en_reg;      // Register for shifting of BCK_EN strobe for two Clocks

reg dg;                     // De-Glitch Interval Trigger

 

reg [4:0] dg_int;          // De-Glitch Interval counter

 

// De-Glitch Interval counter depends on Fs

always @(fsi or clk2x or clk4x or clk8x or clk16x or clk32x or clk64x or data_source_sel)

begin

  case (data_source_sel)

    3'd4 : dg_int = {~fsi, clk2x, clk4x, clk8x, clk16x};        // for Fs = 48 kHz (if MCLK = 12,288 MHz)

 

    3'd5 : dg_int = {~fsi, clk4x, clk8x, clk16x, clk32x};       // for Fs = 96 kHz (if MCLK = 12,288 MHz)

 

    3'd6 : dg_int = {~fsi, clk8x, clk16x, clk32x, clk64x};      // for Fs = 192 kHz (if MCLK = 12,288 MHz)

 

    default dg_int = 5'b0;

  endcase

end

 

 

wire bcko;                  // BitClock Strobe, undelayed

assign bcko = |wcko_reg;    // BCKO will be 16+4=20 clocks of CLK

 

assign asi_wck = ~(wcko_reg[4] | (wcko_reg[3] & wcko_reg[2] & (wcko_reg[1] | wcko_reg[0])));

assign asi_dl = dat_l[19];

assign asi_dr = dat_r[19];

assign asi_bcken = bck_en_reg[1];   // Delayed by two clocks after WCK negedge

assign asi_dg = dg;

 

 

// Save Left Data to intermediate register

wire scki_strb_fsi;

assign scki_strb_fsi = scki_strb & fsi;

 

always @(posedge clk or negedge rst)

  if (~rst)

    reg_l <= 20'b0;

  else if (scki_strb_fsi)

    reg_l <= {reg_l[18:0], sdi};  // Save data during first half of FSI strobe

  else

    reg_l <= reg_l;

 

// Save Right Data to intermediate register

wire scki_strb_notfsi;

assign scki_strb_notfsi = scki_strb & ~fsi;

 

always @(posedge clk or negedge rst)

  if (~rst)

    reg_r <= 20'b0;

  else if (scki_strb_notfsi)

    reg_r <= {reg_r[18:0], sdi};  // Save data during second half of FSI strobe

  else

    reg_r <= reg_r;

 

// Remove Left Data from intermediate register to output DAT_L register, and shifting out when BCK_EN

always @(posedge clk or negedge rst)

  if (~rst)

    dat_l <= 20'b0;

  else if (fsi_strb)                  // Remove data from REG_L to DAT_L

    dat_l <= reg_l;

  else if (asi_bcken)                // BCK_EN duration is 20 clocks

    dat_l <= {dat_l[18:0], dat_l[0]};   // Shift out data and leave the least bit as filled value

  else

    dat_l <= dat_l;

 

// Remove Right Data from intermediate register to output DAT_Rregister, and shifting out when BCK_EN

always @(posedge clk or negedge rst)

  if (~rst)

    dat_r <= 20'b0;

  else if (fsi_strb)

    dat_r <= reg_r;

  else if (asi_bcken)

    dat_r <= {dat_r[18:0], dat_r[0]};

  else

    dat_r <= dat_r;

 

// WCKO and BCK_EN strobe former

wire state0;       // High, when WCKO_REG will reach the state = 19,

assign state0 = ~(|wcko_reg);

 

always @(posedge clk)

  if (~rst)

    wcko_reg <= 5'd20;

  else if (fsi_strb)          // Beginning of counting

    wcko_reg <= 5'd20;

  else if (state0)              // State = 0 ??

    wcko_reg <= wcko_reg;       // Save the (00000) state until the new FCYNC_STRB strobe will come

  else                          // So, the WCKO is 8 clocks of CLK, ~BCK_EN is 20 clocks of CLK

    wcko_reg <= wcko_reg - 1;   // Counting down during the 20 clocks

 

// BCK_EN strobe shifting

always @(posedge clk or negedge rst)

  if (~rst)

    bck_en_reg <= 2'b0;         // Just Global reset

  else

    bck_en_reg <= {bck_en_reg[0], bcko};    // Shifting the BCKO strobe by two clocks

 

// De-Glitch interval former

wire set, reset;

assign set = (dg_int == dgi_rise);

assign reset = (dg_int == dgi_fall);

 

always @(negedge clk or negedge rst)    // DeGlitch R-S Trigger

  if (~rst)

    dg <= 1'b0;

  else if (set)

    dg <= 1'b1;

  else if (reset)

    dg <= 1'b0;

  else

    dg <= dg;

 

endmodule

 


//

 

module clks_former ( clk, rst, clk1x, clk2x, clk4x, clk8x, clk16x, clk32x, clk64x, clk128x,

                     fsync, sck, fsync_strb, sck_strb,

                     scki, fsi, fsi_strb, scki_strb,

                     bcphase, data_source_sel);

 

input   clk, rst,   // Global Clock and Reset

        bcphase;    // Bit Clock Phase of External Audio Serial Interface (ASI)

input [2:0] data_source_sel;

 

output  clk1x, clk2x, clk4x, clk8x, clk16x, clk32x, clk64x, clk128x,

        fsync, sck, // Bit Clock and Frame Clock (Fs) of CS8412 Receiver

        scki, fsi;  // Bit Clock and Frame Clock (Fs) of External Audio Serial Interface (ASI)

output  fsync_strb, sck_strb,   // Strobes for save the 1x data from CS8412

        fsi_strb, scki_strb;    // Strobes for save the data from External S/PDIF Receiver

 

reg [7:0] div256;

 

wire clk1x, clk2x, clk4x, clk8x, clk16x, clk32x, clk64x, clk128x;

 

always @(posedge clk or negedge rst)

  if (~rst)

    div256 <= 8'b0;

  else

    div256 <= div256 + 1;

 

assign  clk1x = div256[7],

        clk2x = div256[6],

        clk4x = div256[5],

        clk8x = div256[4],

        clk16x = div256[3],

        clk32x = div256[2],

        clk64x = div256[1],

        clk128x = div256[0];

 

assign  fsync = div256[7],

        sck  = ~div256[1],

        fsync_strb = div256[0] & div256[1] & div256[2] & div256[3] & div256[4] & div256[5] & div256[6] & ~div256[7],

                                // Strobe before FSYNC pos edge

        sck_strb = div256[0] & ~div256[1] & ~div256[6];

                                // Strobes for SCK (first 16 bits after every edge of FSYNC)

 

/////// Multiplexer for External ASI Clock Signals

//////   SCKI and FSI are used as source for External S/PDIF Receiver

reg scki, fsi, fsi_strb, scki_strb;

 

always @(div256 or clk1x or clk2x or clk32x or clk64x or clk128x or clk or data_source_sel or bcphase)

  case (data_source_sel)

    3'd4 :  begin                       // for Fs = 48 kHz (if MCLK = 12,288 MHz)

              fsi  = clk1x;

              scki = clk64x ^ bcphase;

              fsi_strb = fsync_strb;

              scki_strb = div256[0] & ~div256[1] & ~(div256[6] & (div256[5] | div256[4]));  // 20 scki clocks

            end

    3'd5 :  begin                       // for Fs = 96 kHz (if MCLK = 12,288 MHz)

              fsi  = clk2x;

              scki = clk128x ^ bcphase;

              fsi_strb = div256[0] & div256[1] & div256[2] & div256[3] & div256[4] & div256[5] & ~div256[6];

              scki_strb = div256[0] & ~(div256[5] & (div256[4] | div256[3]));   // 20 scki clocks

            end

    3'd6 :  begin                       // for Fs = 192 kHz (if MCLK = 12,288 MHz)

              fsi  = div256[5];    // Clk4x = 192 kHz

              scki = ~clk ^ bcphase;

              fsi_strb = div256[0] & div256[1] & div256[2] & div256[3] & div256[4] & ~div256[5];

              scki_strb = ~(div256[4] & (div256[3] | div256[2]));   // 20 scki clocks

            end

    default begin               // Clocks are disabled when External ASI have not selected

              fsi  = 1'b0;

              scki = 1'b0;

              fsi_strb = 1'b0;

              scki_strb = 1'b0;

            end

endcase

 

 

endmodule

 


//

 

module cs8412_1x_conv ( clk, rst, sdata, fsync, clk2x, clk4x, clk8x, clk16x,

                        fsync_strb, sck_strb,

                        dgi_rise, dgi_fall,

                        cs8412_dl, cs8412_dr, cs8412_wck, cs8412_bcken, cs8412_dg );

 

input   clk, rst;   // Global Clock and Reset

 

input   sdata, fsync, clk2x, clk4x, clk8x, clk16x, fsync_strb, sck_strb;   // Strobes for save the 1x data from CS8412

 

input [4:0] dgi_rise, dgi_fall;     // De-Glitch Interval, rise and fall edge values

 

output  cs8412_dl, cs8412_dr, cs8412_wck, cs8412_bcken, cs8412_dg;  // Output to Output Multiplexer

 

reg [15:0] reg_l, reg_r;    // Registers for separate storing of left and right channel data from CS8412 receiver

reg [15:0] dat_l, dat_r;    // Registers for outgoing the L/R data to DAC

reg [4:0]  wcko_reg;        // Counter for WCKO and BCK_EN strobes forming register

reg [1:0]  bck_en_reg;      // Register for shifting of BCK_EN strobe for two Clocks

reg dg;                     // De-Glitch Interval Trigger

 

wire [4:0] dg_int;          // De-Glitch Interval counter

assign dg_int = {~fsync, clk2x, clk4x, clk8x, clk16x};

 

wire bcko;                  // BitClock Strobe, undelayed

assign bcko = |wcko_reg;    // BCKO will be 16+4=20 clocks of CLK

 

assign cs8412_wck = ~(wcko_reg[4] | (wcko_reg[3] & wcko_reg[2] & (wcko_reg[1] | wcko_reg[0])));

assign cs8412_dl = dat_l[15];

assign cs8412_dr = dat_r[15];

assign cs8412_bcken = bck_en_reg[1];

assign cs8412_dg = dg;

 

 

// Save Left Data to intermediate register

wire sck_strb_fsync;

assign sck_strb_fsync = sck_strb & fsync;

 

always @(posedge clk or negedge rst)

  if (~rst)

    reg_l <= 16'b0;

  else if (sck_strb_fsync)

    reg_l <= {reg_l[14:0], sdata};  // Save data during first half of FSYNC strobe

  else

    reg_l <= reg_l;

 

// Save Right Data to intermediate register

wire sck_strb_notfsync;

assign sck_strb_notfsync = sck_strb & ~fsync;

 

always @(posedge clk or negedge rst)

  if (~rst)

    reg_r <= 16'b0;

  else if (sck_strb_notfsync)

    reg_r <= {reg_r[14:0], sdata};  // Save data during second half of FSYNC strobe

  else

    reg_r <= reg_r;

 

// Remove Left Data from intermediate register to output DAT_L register, and shifting out when BCK_EN

always @(posedge clk or negedge rst)

  if (~rst)

    dat_l <= 16'b0;

  else if (fsync_strb)                  // Remove data from REG_L to DAT_L

    dat_l <= reg_l;

  else if (cs8412_bcken)                // BCK_EN duration is 20 clocks

    dat_l <= {dat_l[14:0], dat_l[0]};   // Shift out data and leave the least bit as filled value

  else

    dat_l <= dat_l;

 

// Remove Right Data from intermediate register to output DAT_Rregister, and shifting out when BCK_EN

always @(posedge clk or negedge rst)

  if (~rst)

    dat_r <= 16'b0;

  else if (fsync_strb)

    dat_r <= reg_r;

  else if (cs8412_bcken)

    dat_r <= {dat_r[14:0], dat_r[0]};

  else

    dat_r <= dat_r;

 

// WCKO and BCK_EN strobe former

//wire state19;       // High, when WCKO_REG will reach the state = 19,

//assign state19 = wcko_reg[4] & ~wcko_reg[3] & ~wcko_reg[2] & wcko_reg[1] & wcko_reg[0];

wire state0;       // High, when WCKO_REG will reach the state = 19,

assign state0 = ~(|wcko_reg);

 

always @(posedge clk)

  if (~rst)

    wcko_reg <= 5'd20;

  else if (fsync_strb)          // Beginning of counting

    wcko_reg <= 5'd20;

  else if (state0)              // State = 0 ??

    wcko_reg <= wcko_reg;       // Save the (00000) state until the new FCYNC_STRB strobe will come

  else                          // So, the WCKO is 8 clocks of CLK, ~BCK_EN is 20 clocks of CLK

    wcko_reg <= wcko_reg - 1;   // Counting down during the 20 clocks

 

// BCK_EN strobe shifting

always @(posedge clk or negedge rst)

  if (~rst)

    bck_en_reg <= 2'b0;         // Just Global reset

  else

    bck_en_reg <= {bck_en_reg[0], bcko};    // Shifting the BCKO strobe by two clocks

 

// De-Glitch interval former

wire set, reset;

assign set = (dg_int == dgi_rise);

assign reset = (dg_int == dgi_fall);

 

always @(negedge clk or negedge rst)    // DeGlitch R-S Trigger

  if (~rst)

    dg <= 1'b0;

  else if (set)

    dg <= 1'b1;

  else if (reset)

    dg <= 1'b0;

  else

    dg <= dg;

 

endmodule

 


//

 

module dsp_dg_conv( clk, rst,

                    dgi_rise, dgi_fall,

                    dsp_wck, dsp_dg );

 

input   clk, rst;   // Global Clock and Reset

input   dsp_wck;    // Strobes for save the 1x data from External Receiver

 

input [4:0] dgi_rise, dgi_fall;     // De-Glitch Interval, rise and fall edge values

 

output  dsp_dg;             // Output to Output Multiplexer

 

reg [4:0]  dg_cnt;          // Counter for WCKO and BCK_EN strobes forming register

reg wck_strb_reg;           // Register for shifting of BCK_EN strobe for two Clocks

reg dg;                     // De-Glitch Interval Trigger

 

wire wck_strb;              // De-Glitch Interval counter

 

assign dsp_dg = dg;

assign wck_strb = wck_strb_reg & ~dsp_wck;  // Strobe is One CLK period after negedge of DSP_WCKO

 

 

// Be ginning of WCKO strobe

always @(posedge clk or negedge rst)

  if (~rst)

    wck_strb_reg <= 2'b0;       // Just Global reset

  else

    wck_strb_reg <= dsp_wck;    // Shifting the DSP_WCKO strobe by one clock

 

 

// DG Interval Counter

always @(posedge clk)

  if (~rst)

    dg_cnt <= 5'b00001;

  else if (wck_strb)        // Set to the second state (00001), because wck_strb is delayed by one CLK after

    dg_cnt <= 5'b00001;     //      beginning of WCKO interval

  else

    dg_cnt <= dg_cnt + 1;   // Counting during the 32 clocks

 

 

// De-Glitch interval former

wire set, reset;

assign set = (dg_cnt == dgi_rise);

assign reset = (dg_cnt == dgi_fall);

 

always @(negedge clk or negedge rst)    // DeGlitch R-S Trigger

  if (~rst)

    dg <= 1'b0;

  else if (set)

    dg <= 1'b1;

  else if (reset)

    dg <= 1'b0;

  else

    dg <= dg;

 

endmodule

 


//

 

module error_decoder (e0, e1, e2,                       // Error Code

                      vbh, cf, sls, pari, bpce, nl);    // Decoded signals to LEDs

 

input  e0, e1, e2;

output vbh, cf, sls, pari, bpce, nl;

 

reg [5:0] leds;

wire [2:0] error_code;

assign error_code = {e2, e1, e0};

 

always @(error_code)

begin

  case (error_code)

    3'd0 : leds = 6'b000000;    // No Error

    3'd1 : leds = 6'b000001;    // Validity Bit High

    3'd2 : leds = 6'b000010;    // Confidence Flag

    3'd3 : leds = 6'b000100;    // Slipped Sample

    3'd5 : leds = 6'b001000;    // Parity Error

    3'd6 : leds = 6'b010000;    // Bi-Phase Coding Error

    3'd7 : leds = 6'b100000;    // No Lock

    default leds = 6'b0;

  endcase

end

 

assign  vbh     = leds[0],

        cf      = leds[1],

        sls     = leds[2],

        pari    = leds[3],

        bpce    = leds[4],

        nl      = leds[5];

 

 

endmodule

 


//

 

module out_data_mux (dat_l, dat_r, bck_en, wcko_o, dg_o,    // Output Signals to DAC

                     data_source_sel, clk, rst, phase_rev,

                     dol, dor, bcko, wcko, dg,              // From PD-100 Digital Filter

                     cs8412_dl, cs8412_dr, cs8412_wck, cs8412_bcken, cs8412_dg,   // From CS8412 S/PDIF Receiver (1x Mode)

                     asi_dl, asi_dr, asi_wck, asi_bcken, asi_dg,  // From external S/PDIF Receiver (like CS8416)

                     dsp_dl, dsp_dr, dsp_wck, dsp_bcken, dsp_dg   // From external DSP (Fs= up to 384 kHz)

                     );

 

input [2:0] data_source_sel;

input clk, rst, phase_rev, dol, dor, bcko, wcko, dg,

      cs8412_dl, cs8412_dr, cs8412_wck, cs8412_bcken, cs8412_dg,

      asi_dl, asi_dr, asi_wck, asi_bcken, asi_dg,

      dsp_dl, dsp_dr, dsp_wck, dsp_bcken, dsp_dg;

 

output dat_l, dat_r, bck_en, wcko_o, dg_o;

 

reg dat_l, dat_r, bck_en, wcko_o, dg_o;     // First Re-Clock Triggers (FPGA Outputs)

reg dl_n1, dr_n1, bc_n1, wc_n1, dg_n1;      // Local nets beetween MUX and Re-Clock Triggers

 

reg phase;      // Phase of output data

 

reg tr1, tr2;   // Bit Clock Enable Strobe Former

                // TR1 - Pulses beetween BCKO and CLK Positive Edges

reg dl_pre, dr_pre, wcko_pre, dg_pre;

 

 

///////////// First Re-Clocking of Input Data from PMD-100

always @(posedge clk)

  begin

    dl_pre <= dol;

    dr_pre <= dor;

    wcko_pre <= wcko;

    dg_pre <= dg;

  end

 

///////////// BCK_EN Strobe Former

wire bcken;

assign bcken = tr1;

 

wire tr_rst;

assign tr_rst = rst & ~tr2;

 

always @(posedge bcko or negedge tr_rst)

  if (~tr_rst)

    tr1 <= 1'b0;

  else

    tr1 <= 1'b1;

 

always @(posedge clk or negedge tr_rst)

  if (~tr_rst)

    tr2 <= 1'b0;

  else

    tr2 <= tr1;

 

// Phase Reverse control signal is synchronized with negative edge of WCKO

always @(negedge wcko_o or negedge rst)

  if (~rst)

    phase <= 1'b0;

  else

    phase <= phase_rev;

 

// Output Multiplexer for DATA_LEFT

always @(data_source_sel or dol or cs8412_dl or dsp_dl /*or tpatt_dl*/ or asi_dl)

begin

  case (data_source_sel)

    3'd0 : dl_n1 = phase ^ dl_pre;

    3'd1 : dl_n1 = phase ^ cs8412_dl;

    3'd2 : dl_n1 = phase ^ dsp_dl;

    3'd4 : dl_n1 = phase ^ asi_dl;

    3'd5 : dl_n1 = phase ^ asi_dl;

    3'd6 : dl_n1 = phase ^ asi_dl;

    default dl_n1 = 1'b0;

  endcase

end

 

// Output Multiplexer for DATA_RIGHT

always @(data_source_sel or dor or cs8412_dr or dsp_dr or asi_dr)

begin

  case (data_source_sel)

    3'd0 : dr_n1 = phase ^ dr_pre;

    3'd1 : dr_n1 = phase ^ cs8412_dr;

    3'd2 : dr_n1 = phase ^ dsp_dr;

    3'd4 : dr_n1 = phase ^ asi_dr;

    3'd5 : dr_n1 = phase ^ asi_dr;

    3'd6 : dr_n1 = phase ^ asi_dr;

    default dr_n1 = 1'b0;

  endcase

end

 

// Output Multiplexer for WCKO

always @(data_source_sel or wcko or cs8412_wck or dsp_wck or asi_wck)

begin

  case (data_source_sel)

    3'd0 : wc_n1 = wcko_pre;

    3'd1 : wc_n1 = cs8412_wck;

    3'd2 : wc_n1 = dsp_wck;

    3'd4 : wc_n1 = asi_wck;

    3'd5 : wc_n1 = asi_wck;

    3'd6 : wc_n1 = asi_wck;

    default wc_n1 = 1'b0;

  endcase

end

 

// Output Multiplexer for BCK_EN

always @(data_source_sel or bcken or cs8412_bcken or dsp_bcken or asi_bcken)

begin

  case (data_source_sel)

    3'd0 : bc_n1 = bcken;

    3'd1 : bc_n1 = cs8412_bcken;

    3'd2 : bc_n1 = dsp_bcken;

    3'd4 : bc_n1 = asi_bcken;

    3'd5 : bc_n1 = asi_bcken;

    3'd6 : bc_n1 = asi_bcken;

    default bc_n1 = 1'b0;

  endcase

end

 

// Output Multiplexer for DG

always @(data_source_sel or dg or cs8412_dg or dsp_dg or asi_dg)

begin

  case (data_source_sel)

    3'd0 : dg_n1 = dg_pre;

    3'd1 : dg_n1 = cs8412_dg;

    3'd2 : dg_n1 = dsp_dg;

    3'd4 : dg_n1 = asi_dg;

    3'd5 : dg_n1 = asi_dg;

    3'd6 : dg_n1 = asi_dg;

    default dg_n1 = 1'b0;

  endcase

end

 

// Re-Clocking at the Output of FPGA - dat_l, dat_r, bck_en, wcko_o, dg_o;  (First Re-Clock Triggers )

// after Output Data Multiplexer

always @(posedge clk or negedge rst)

  if (~rst)

    dat_l <= 1'b0;

  else

    dat_l <= dl_n1;

 

always @(posedge clk or negedge rst)

  if (~rst)

    dat_r <= 1'b0;

  else

    dat_r <= dr_n1;

 

always @(posedge clk or negedge rst)

  if (~rst)

    wcko_o <= 1'b0;

  else

    wcko_o <= wc_n1;

 

always @(posedge clk or negedge rst)

  if (~rst)

    bck_en <= 1'b0;

  else

    bck_en <= bc_n1;

 

always @(posedge clk or negedge rst)

  if (~rst)

    dg_o <= 1'b0;

  else

    dg_o <= dg_n1;

 

 

 

endmodule


//

 

module sync_out_former( clk, rst, vco_out, pd_osc, dig_sync_out,

                        clk1x, clk2x, clk32x, clk64x, clk128x,

                        sync_out_sel );

 

input  clk, rst, vco_out;

input  clk1x, clk2x, clk32x, clk64x, clk128x;

input [2:0] sync_out_sel;

output pd_osc, dig_sync_out;

 

reg [1:0] div3;

reg dig_sync_out;

 

wire state2;

assign pd_osc = div3[0];

 

always @(sync_out_sel or clk1x or clk2x or clk32x or clk64x or clk128x or clk or vco_out)

begin

  case (sync_out_sel )

    3'd0 : dig_sync_out = 1'b0;

    3'd1 : dig_sync_out = clk1x;

    3'd2 : dig_sync_out = clk2x;

    3'd3 : dig_sync_out = clk32x;

    3'd4 : dig_sync_out = clk64x;

    3'd5 : dig_sync_out = clk128x;

    3'd6 : dig_sync_out = clk;      // CLK = 256xFs

    3'd7 : dig_sync_out = vco_out;  // VCO_OUT = 384xFs

//    default dig_sync_out = 1'b0;

  endcase

end

 

//////// Divider by 3

assign state2 = ~div3[0] & div3[1];     // State2 = 1 when div3 = 2

always @(posedge vco_out or negedge rst)

  if (~rst)

    div3 <= 2'b0;

  else if (state2)

    div3 <= 2'b0;

  else

    div3 <= div3 + 1;

 

endmodule

 

 

 


//

 

module sys_logic ( data_in, data_out, address, wr, rst,

                   data_source_sel, sync_out_sel, phase_rev, bcphase,

                   h_mute, s_mute, dither, scal,

                   m3, sel, ms_sel, proc_ctrl,

                   dgi_rise, dgi_fall,

                   gp0, gp1, gp2, gp3, gp4, gp5, gp6, gp7 );

 

input  [7:0] data_in;

output [7:0] data_out;

input  [2:0] address;

input  wr, rst;

 

output [2:0] data_source_sel, sync_out_sel;

output phase_rev, h_mute, s_mute, dither, scal,

       m3, sel, ms_sel, proc_ctrl, bcphase,

       gp0, gp1, gp2, gp3, gp4, gp5, gp6, gp7;

 

output [4:0] dgi_rise, dgi_fall;

 

////////// System Registers

reg [7:0] sys_reg0, sys_reg1, sys_reg4;

reg [4:0] sys_reg2, sys_reg3;

 

///// Assign of Control signals from System Registers, (! First state is Default at Reset !)

assign  data_source_sel =   sys_reg0[2:0],  // 0:PMD-100, 1:CS8412(1x), 2:DSP(external), 3:TestPattern,

                                            // 4:ASI/1x_External, 5:ASI/2x_External, 6:ASI/4x_External, 7:Reserved

        phase_rev =         sys_reg0[3],    // 0:AsIs, 1:Phase_Reverse

        s_mute =            sys_reg0[4],    // 0:NO_Mute, 1:Soft_Mute_ON

        h_mute =            sys_reg0[5],    // 1:NO_Mute, 0:Hard_Mute_ON

        dither =            sys_reg0[6],    // 1:Dither_ON, 0:Dither_OFF

        scal =              sys_reg0[7],    // 1:Analog_Scaling, 0:Digital_Scaling

        sync_out_sel =      sys_reg1[2:0],  //      Dig_Sync_Out_Select

                                            // 0:Sync_Signal is disabled,

                                            //  1:Fs, 2:2*Fs, 3:32*Fs, 4:64*Fs, 5:128*Fs, 6:256*Fs, 7:384*Fs

        m3 =                sys_reg1[3],    // CS8412 Mode: 0:Normal, 1:Special(NO_Repeat on Errors)

        sel =               sys_reg1[4],    // CS8412 Out_Code: 1:Channel_Status, 0:Error_Code_on_E0...E2

        ms_sel =            sys_reg1[5],    // 0:DAC is Master, 1:DAC is Slaver

        proc_ctrl =         sys_reg1[6],    // 0:Processor Control, 1:Jumpers Control

        bcphase  =          sys_reg1[7],    // Bit Clock Phase of External Audio Serial Interface (ASI)

        dgi_rise =          sys_reg2[4:0],  // De-Glitch strobe, Rising Edge Position

        dgi_fall =          sys_reg3[4:0],  // De-Glitch strobe, Falling Edge Position

        gp0 = sys_reg4[0],  // General Purpose Outputs

        gp1 = sys_reg4[1],

        gp2 = sys_reg4[2],

        gp3 = sys_reg4[3],

        gp4 = sys_reg4[4],

        gp5 = sys_reg4[5],

        gp6 = sys_reg4[6],

        gp7 = sys_reg4[7];

 

////////// Data Read Multiplexer

reg [7:0] data_out;

 

always @(sys_reg0 or sys_reg1 or sys_reg2 or sys_reg3 or sys_reg4 or address)

begin

  case (address)

    4'd0 : data_out = sys_reg0;

    4'd1 : data_out = sys_reg1;

    4'd2 : data_out = {3'b0, sys_reg2};

    4'd3 : data_out = {3'b0, sys_reg3};

    4'd4 : data_out = sys_reg4;

    default : data_out = 8'b0;

  endcase

end

 

////////// Address Decoder

reg [4:0] fn;

 

wire fn0, fn1, fn2, fn3, fn4;

assign  fn0 = fn[0],

        fn1 = fn[1],

        fn2 = fn[2],

        fn3 = fn[3],

        fn4 = fn[4];

 

always @(address)

begin

  case (address)

    4'd0 : fn = 5'b00001;

    4'd1 : fn = 5'b00010;

    4'd2 : fn = 5'b00100;

    4'd3 : fn = 5'b01000;

    4'd4 : fn = 5'b10000;

    default fn = 5'b0;

  endcase

end

 

////////// Data Write to each System Register

always @( posedge wr or  negedge rst )

  if (~rst)

    sys_reg0 <= 8'b11100000;

  else if (fn0)

    sys_reg0 <= data_in;

 

always @( posedge wr or  negedge rst )

  if (~rst)

    sys_reg1 <= 8'b00010000;

  else if (fn1)

    sys_reg1 <= data_in;

 

always @( posedge wr or  negedge rst )

  if (~rst)

    sys_reg2 <= 5'b0;

  else if (fn2)

    sys_reg2 <= data_in[4:0];

 

always @( posedge wr or  negedge rst )

  if (~rst)

    sys_reg3 <= 5'b0;

  else if (fn3)

    sys_reg3 <= data_in[4:0];

 

always @( posedge wr or  negedge rst )

  if (~rst)

    sys_reg4 <= 8'b0;

  else if (fn4)

    sys_reg4 <= data_in;

 

endmodule

 



Литература и ссылки

 

[1] http://www.hdcd.com

[2] http://www.mp3projects.com/digital/chimp/bins/i2s.pdf

[3] http://www.npcproducts.com/

[4] http://www.wima.com/

[5] http://www.analog.com/

[6] http://www.crystal.com/

[7] http://www.phyast.pitt.edu/~charng/schematic.html

[8] http://www.diyaudio.de/index.html

[9] http://members.brabant.chello.nl/~m.heijligers/DAChtml/dactop.htm

[10] http://www.geocities.com/ResearchTriangle/8231/cdplayer/index.html

[11] http://galstar.com/~ntracy/ACG/Xdac/ADreply/harley1.htm

[12] http://www.jitter.de/english/engc_navfr.html

[13] http://www.sound.au.com/misclink.htm

[14] http://www.megabaud.fi/~jtolonen/projects/jt-dac_no.3/jt-dac_no.3.html

[15] http://www.clarkson.edu/~stokessd/dac.html

[16] http://www.zeuslab.newmail.ru/

[17] http://users.cybercity.dk/~ida2439/athome/builddac.htm

[18] http://www.tnt-audio.com/clinica/tweaks.html

[19] http://www.digido.com/

 

 

 

Hosted by uCoz