Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

.Проектирование устройств и систем с высокоскоростными соединениями

.pdf
Скачиваний:
41
Добавлен:
15.11.2022
Размер:
21.68 Mб
Скачать

 

Deserializer

ddr_clock

Wr

 

op_code (1…0)

Rx

en

 

data_out10(9…0)

 

 

Рис. 3.13. Интерфейс узла Deserializer

Представим процесс разбора кадра в виде синхронного автомата (рис. 3.14), в котором состояния интерпретируются следующим образом:

wait_comma1 – ожидание первого символа стартового маркера кадра;

wait_comma2 – ожидание второго символа стартового маркера кадра;

data_0 – прием первого символа поля данных;

data_i – прием последующих символов поля данных и выдача всех принятых символов поля данных;

wait_end – обнаружен первый символ конечного маркера кадра;

wait_idle – обнаружен второй символ конечного маркера кадра или второй символ маркера ожидания кадра;

wait_idle_next – обнаружен первый символ маркера ожидания кадра;

lock_up – состояние блокировки приема кадра из-за искажения его структуры.

Рис. 3.14. Автомат разбора кадра

71

Ниже приведена программа-спецификация на VHDL узла «Десериалайзер», содержащая процессы WALKING_ONE_

EVEN, WALKING_ONE_ODD, SERIAL_TO_PARALLEL и STATE_MACHINE.

VHDL программа-спецификация узла «Десериалайзер»

library IEEE;

use IEEE.STD_LOGIC_1164.all;

use IEEE.STD_LOGIC_UNSIGNED.all; use IEEE.NUMERIC_STD.all;

entity Deserializer is

port( ddr_clock : in STD_LOGIC; reset_n : in STD_LOGIC; Rx : in STD_LOGIC;

en : out STD_LOGIC;

op_code : out STD_LOGIC_VECTOR(1 downto 0); wr: out STD_LOGIC;

data_out10 : out STD_LOGIC_VECTOR(9 downto 0)

);

end Deserializer;

architecture Deserializer of Deserializer is

constant K28_5_RDm : STD_LOGIC_VECTOR(9 downto 0) := "0101111100"; constant K28_0_RDm : STD_LOGIC_VECTOR(9 downto 0) := "0010111100"; constant K29_7_RDm : STD_LOGIC_VECTOR(9 downto 0) := "0001011101"; function cross_6 (x: std_logic_vector(5 downto 0)) return std_logic_vector is

variable y: std_logic_vector(5 downto 0); begin

for I in 0 to 5 loop y(I):=x(5-I); end loop; return y;

end;

function cross_4 (x: std_logic_vector(3 downto 0)) return std_logic_vector is variable y: std_logic_vector(3 downto 0);

begin

for I in 0 to 3 loop y(I):=x(3-I); end loop; return y;

end;

function comma_detect (x: std_logic_vector(19 downto 0)) return unsigned is variable TEMP: unsigned(3 downto 0);

begin TEMP:="0000"; for I in 0 to 9 loop

if x(9+i downto i)= K28_5_RDm or x(9+i downto i)= not K28_5_RDm then return TEMP+i;

72

end if; end loop;

return "1010";

end;

signal phase: STD_LOGIC_VECTOR(4 downto 0); signal clock: STD_LOGIC_VECTOR(9 downto 0); signal sreg: STD_LOGIC_VECTOR(9 downto 0); signal data20: STD_LOGIC_VECTOR(19 downto 0); signal offset: STD_LOGIC_VECTOR(3 downto 0);

type TYPE_STATE is (wait_comma1, wait_comma2, data_0,data_i, wait_end, wait_idle, wait_idle_next, lock_up);

signal state: TYPE_STATE;

signal op_code_t : STD_LOGIC_VECTOR(1 downto 0); begin

en<=clock(0) when state= data_i else '0';

wr<=clock(4) when state= data_i and (op_code_t="01" or op_code_t="10") else '0'; op_code<=op_code_t;

WALKING_ONE_EVEN: process(ddr_clock,reset_n) begin

if reset_n='0' then phase<="00001"; clock(0)<='0'; clock(2)<='0'; clock(4)<='0'; clock(6)<='0'; clock(8)<='0';

elsif rising_edge(ddr_clock) then

phase(4 downto 1)<=phase(3 downto 0); phase(0)<=phase(4); clock(0)<=phase(0); clock(2)<=phase(1); clock(4)<=phase(2); clock(6)<=phase(3); clock(8)<=phase(4);

end if; end process;

WALKING_ONE_ODD:process(ddr_clock,reset_n) begin

if reset_n='0' then clock(1)<='0'; clock(3)<='0'; clock(5)<='0'; clock(7)<='0'; clock(9)<='0';

elsif falling_edge(ddr_clock) then

73

clock(1)<=phase(1);

clock(3)<=phase(2);

clock(5)<=phase(3);

clock(7)<=phase(4);

clock(9)<=phase(0); end if;

end process; SERIAL_TO_PARALLEL:process(clock,reset_n) begin

if reset_n='0' then sreg<=(others=>'0');

else

for I in 0 to 9 loop

if clock(i)'event and clock(i)='1' then sreg(i)<= Rx;

end if; end loop;

end if; end process;

DESERIALIZER_STATE_MACHINE: process(clock(0),reset_n,clock(3)) variable v_offset: STD_LOGIC_VECTOR(3 downto 0);

variable v_data10:

STD_LOGIC_VECTOR(9 downto 0);

begin

 

if reset_n='0' then

 

data_out10<=(others=>'0'); offset<="1010"; data20<=(others=>'0'); op_code_t<=(others=>'0');

elsif clock(3)='1' then

elsif rising_edge(clock(0)) then data20(19 downto 10)<=sreg;

data20(9 downto 0)<=data20(19 downto 10); v_offset:=

STD_LOGIC_VECTOR(comma_detect (sreg&data20(19 downto 10))); if v_offset /= "1010" then

offset<=v_offset; end if; BOUNDARY_ALIGN: case offset is

when x"0" => v_data10:=data20(9 downto 0);

when x"1" => v_data10:=data20(10 downto 1);

when x"2" => v_data10:=data20(11 downto 2);

74

when x"3" => v_data10:=data20(12 downto 3);

when x"4" => v_data10:=data20(13 downto 4);

when x"5" =>

v_data10:=data20(14 downto 5); when x"6" =>

v_data10:=data20(15 downto 6); when x"7" =>

v_data10:=data20(16 downto 7); when x"8" =>

v_data10:=data20(17 downto 8); when x"9" =>

v_data10:=data20(18 downto 9); when others =>

v_data10:=data20(9 downto 0); end case;

data_out10<=v_data10; RX_FRAME_STATE_MACHINE: case state is

when wait_comma1 =>

if

(v_data10 =K28_5_RDm) or (v_data10 =not K28_5_RDm) then

 

state<= wait_comma2;

end if;

op_code_t<=(others=>'0');

when wait_comma2 =>

if

(v_data10 =K28_5_RDm) or (v_data10 =not K28_5_RDm) then

 

state<= data_0;

else

state<= lock_up; end if;

when data_0 => state<= data_i;

when data_i =>

if v_data10 =K28_0_RDm then state<= wait_end;

end if;

if op_code_t=2 then op_code_t<=(others=>'0');

else

op_code_t<= op_code_t+1; end if;

when wait_end =>

if (v_data10(5 downto 0)= cross_6("100111") and v_data10(9 downto 6)=cross_4("1011")) or

75

(v_data10(5 downto 0)= cross_6("100111") and v_data10(9 downto 6)=cross_4(not"1011")) or (v_data10(5 downto 0)= cross_6(not"100111") and v_data10(9 downto 6)=cross_4("1011")) or (v_data10(5 downto 0)= cross_6(not"100111") and v_data10(9 downto 6)=cross_4(not"1011")) then

state<=

wait_idle;

else

 

state<=lock_up;

end if;

when wait_idle =>

if v_data10 =K29_7_RDm then state<= wait_idle_next;

elsif (v_data10 =K28_5_RDm) or (v_data10 =not K28_5_RDm) then state<= wait_comma2;

else

 

state<=lock_up;

 

end if;

 

when wait_idle_next

=>

if (v_data10 =K28_5_RDm) or (v_data10 =not K28_5_RDm) then state<= wait_idle;

else state<=lock_up;

end if; when others =>

null; end case;

end if; end process;

end Deserializer;

Процессы WALKING_ONE_EVEN и WALKING_ONE_ ODD из ddr_clock формируют сигналы многофазной синхронизации clock(0), …, clock(9), так что сигналы с четными индексами инициируются фронтом ddr_clock, а с нечетными – срезом

ddr_clock.

Процесс SERIAL_TO_PARALLEL преобразует последовательные входные данные в параллельные с помощью 10-битного сигнала sreg и многофазного синхросигнала clock.

Процесс STATE_MACHINE выполняет разбор структуры кадра, выделяя символы из поля данных для их последующего декодирования. В процессе постоянно отслеживаются границы 10-битных символов с помощью функции comma_detect. Эта

76

функция определяет положение К-символа К28.5 («запятая»)

впоследних принятых 20 битах кадра относительно clock(0). Найденное смещение используется для формирования выходных символов data_out10 с помощью оператора case, помеченного

впрограмме как BOUNDARY_ALIGN.

Узел «Декодер 8b/10b» выполняет преобразование 10-бит- ных символов кода 8b/10b в 8-битные данные и сборку из них 12-разрядных данных. На рис. 3.15 приведен интерфейс decoder_ 8b10b узла «Декодер 8b/10b», а ниже – программа-спецификация узла на VHDL.

decoder_8b10b

op_code (1…0 )

data_out12 (11…0)

en

 

data_in8 (7…0 )

 

Рис. 3.15. Интерфейс узла decoder_8b10b

VHDL программа-спецификация узла «Декодер 8b/10b»

library IEEE;

use IEEE.STD_LOGIC_1164.all; use IEEE.NUMERIC_STD.all; entity decoder_8b10b is

port(

reset_n : in STD_LOGIC; en : in STD_LOGIC;

data_in : in STD_LOGIC_VECTOR(9 downto 0); op_code : in STD_LOGIC_VECTOR(1 downto 0); data_out12 : out STD_LOGIC_VECTOR(11 downto 0)

);

end decoder_8b10b;

architecture decoder_8b10b of decoder_8b10b is

function cross_6 (x: std_logic_vector(5 downto 0)) return std_logic_vector is variable y: std_logic_vector(5 downto 0);

begin

for I in 0 to 5 loop y(I):=x(5-I); end loop; return y;

end;

function cross_4 (x: std_logic_vector(3 downto 0)) return std_logic_vector is variable y: std_logic_vector(3 downto 0);

77

begin

for I in 0 to 3 loop y(I):=x(3-I); end loop; return y;

end;

type Code5b6b_type is array (0 to 31) of STD_LOGIC_VECTOR(5 downto 0);

constant Code5b6b_ROM_RDm : Code5b6b_type := (

 

"100111",

"011101",

 

"101101", "110001",

 

 

"110101", "101001",

"011001", "111000",

 

 

"111001",

"100101",

 

"010101", "110100",

 

 

"001101",

"101100",

 

"011100", "010111",

 

 

"011011",

"100011", "010011",

"110010",

 

 

"001011",

"101010",

 

"011010", "111010",

 

 

"110011", "100110", "010110","110110",

 

 

"001110", "101110", "011110", "101011" );

 

 

constant Code5b6b_ROM_RDp : Code5b6b_type := (

 

0=>

not Code5b6b_ROM_RDm(0),

 

 

 

1=>

not Code5b6b_ROM_RDm(1),

 

 

 

2=>

not Code5b6b_ROM_RDm(2),

 

 

 

3=>

"110001",

 

 

 

 

 

 

4=>

not Code5b6b_ROM_RDm(4),

 

 

 

5=>

"101001", 6=>

 

"011001",

 

 

 

 

7=>

not Code5b6b_ROM_RDm(7),

 

 

 

8=>

not Code5b6b_ROM_RDm(8),

 

 

 

9=>

"100101", 10=>

 

"010101",

11=>

"110100", 12=>

"001101",

13=>

"101100", 14=>

"011100",

 

 

 

15=>

not Code5b6b_ROM_RDm(15),

 

 

16=>

not Code5b6b_ROM_RDm(16),

 

 

17=>

"100011",18=>

 

"010011",

19=>

"110010",20=>

"001011",

21=>

"101010",22=>

 

"011010",

 

 

 

23=>

not Code5b6b_ROM_RDm(23),

 

 

24=>

not Code5b6b_ROM_RDm(24),

 

 

25=>

"100110",26=>

 

"010110",

 

 

 

27=>

not Code5b6b_ROM_RDm(27),

 

 

28=>

"001110",

 

 

 

 

 

 

29=>

not Code5b6b_ROM_RDm(29),

 

 

30=>

not Code5b6b_ROM_RDm(30),

 

 

31=>

not Code5b6b_ROM_RDm(31) );

 

 

type Code3b4b_type is array (0 to 7) of STD_LOGIC_VECTOR(3 downto 0); constant Code3b4b_ROM_RDm : Code3b4b_type := (

0=>

"1011",1=>

"1001", 2=>

"0101",3=>

"1100",

4=>

"1101",5=>

"1010", 6=>

"0110",7=>

"1110");

constant Code3b4b_ROM_RDp : Code3b4b_type := ( 0=> not Code3b4b_ROM_RDm(0),

1=> "1001", 2=> "0101",

3=> not Code3b4b_ROM_RDm(3),

78

4=> not Code3b4b_ROM_RDm(4), 5=> "1010", 6=> "0110",

7=> not Code3b4b_ROM_RDm(7) );

function Decoder5b6b (x: std_logic_vector(5 downto 0)) return std_logic_vector is variable y: std_logic_vector(4 downto 0);

begin y:="00000";

for I in 0 to 31 loop

if x=cross_6(Code5b6b_ROM_RDm(i)))or(x=cross_6(Code5b6b_ROM_ RDp(i))) then

y:= std_logic_vector(to_unsigned(i,5)); return y;

end if; end loop;

return y; end;

function Decoder3b4b (x: std_logic_vector(3 downto 0)) return std_logic_vector is variable y: std_logic_vector(2 downto 0);

begin y:="000";

for I in 0 to 7 loop

if (x=cross_4(Code3b4b_ROM_RDm(i))) or (x=cross_4(Code3b4b_ ROM_RDp(i)))

then

y:= std_logic_vector(to_unsigned(i,3)); return y;

end if; end loop; return y;

end;

signal data8: std_logic_vector(7 downto 0); begin

DECODER_8B_10B: process(reset_n,en) variable v_code8: std_logic_vector(7 downto 0); begin

if reset_n='0' then data_out12<=x"000"; data8<=(others =>'0');

elsif falling_edge(en) then

v_code8(4 downto 0):= Decoder5b6b( data_in(5 downto 0)); v_code8(7 downto 5):= Decoder3b4b( data_in(9 downto 6)); case op_code is

when "00"=> data8<=v_code8;

when "01"=>

data_out12(7 downto 0)<=data8;

79

data_out12(11 downto 8)<=v_code8(3 downto 0); data8(3 downto 0)<=v_code8(7 downto 4);

when "10"=>

data_out12(3 downto 0)<=data8(3 downto 0); data_out12(11 downto 4)<=v_code8;

when others=> null;

end case; end if;

end process;

end decoder_8b10b;

Функции Decoder5b6b и Decoder3b4b представляют комбинационную составляющую ассоциативной памяти, позволяющей за один такт выполнить декодирование символа кода 8b/10b. В процессе DECODER_8B_10B по срезу сигнала en выполняется декодирование и сборка 12-разрядных данных. Сигнал на входе op_code определяет один из трех этапов преобразования.

На рис. 3.16 приведена модель трансивера с пользовательским протоколом, в которой для целей отладки выход Tx соединен со входом Rx. Узел CDR является цифроаналоговым элементом, который не может быть полноценно представлен в рамках данной модели. Поэтому CDR моделируется просто делителем на два частоты входного потока rx_clock (частота передачи на противоположной стороне). Узел Power_on моделирует сброс системы в начальное состояние при включении питания.

Рис. 3.16. Модель верхнего уровня трансивера с пользовательским протоколом

80

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]