.Проектирование устройств и систем с высокоскоростными соединениями
.pdfdata_11_4<=data_in12(11 downto 4); when "10"=>
data8<=data_11_4; when others=>
null; end case;
end if; end process;
end conv_2_12_to_3_8;
Реализуем следующий узел с интерфейсом Serializer (рис. 3.9), используя модель программно-управляемого автомата (модель программно-управляемого автомата подробно рассмотрена в главе 7).
|
|
Serializer |
|
|
|
|
hs_clock |
|
Rdr |
|
|
|
data_in10(1111…0 ) |
rd_mode(1…0) |
|
||
|
_ |
…0 ) |
rd mode(1…0) |
|
|
|
idle |
|
op |
…0) |
|
|
|
op codecode(2…0) |
|
||
|
|
|
|
en |
|
|
|
|
|
en |
|
|
|
|
|
rd fifo |
|
|
|
|
|
||
Рис. 3.9. Интерфейс узла |
Serializer |
||||
На вход hs_clock |
подается тактовый |
сигнал частотой |
2,5 ГГц, под действием которого параллельные 10-битные символы, поступающие на вход данных data_in10 от «Кодер 8b/10b», преобразуются в выходной последовательный поток tx. Остальные выходные сигналы необходимы для работы узлов «FIFO передачи», «Преобразование 12/8 бит» и «Кодер 8b/10b».
Представим процесс формирования кадра в виде синхронного автомата (рис. 3.10), в котором состояния интерпретируются следующим образом:
SF1 – формирование первого символа стартового маркера кадра;
SF2 – формирование второго символа стартового маркера кадра;
DATA0 – 8b/10b кодирование данных этап 0; DATA1 – 8b/10b кодирование данных этап 1; DATA2 – 8b/10b кодирование данных этап 2;
EF1 – формирование первого символа конечного маркера кадра;
61
EF2 – формирование второго символа конечного маркера кадра;
IDLE1 – формирование первого символа маркера ожидания кадра;
IDLE2 – формирование второго символа маркера ожидания кадра.
Рис. 3.10. Автомат формирования кадра
На вход symbol_counter поступает число переданных пар символов, а вход idle удерживается в 1 для передачи необходимого количества символов ожидания.
Ниже приведена программа-спецификация на VHDL узла
Serializer, содержащая два процесса – COUNTER_0_TO_9 и STATE_MACINE.
VHDL программа-спецификация узла Serializer
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all; use IEEE.NUMERIC_STD.all;
entity Serializer is port(
reset_n : in STD_LOGIC; hs_clock : in STD_LOGIC;
data_in10 : in STD_LOGIC_VECTOR(9 downto 0); idle : in STD_LOGIC;
62
op_code : out STD_LOGIC_VECTOR(2 downto 0); en : out STD_LOGIC;
rd : out STD_LOGIC; rd_fifo : out STD_LOGIC;
rd_mode : out STD_LOGIC_VECTOR(1 downto 0); tx : out STD_LOGIC
);
end Serializer;
architecture Serializer of Serializer is
type TYPE_STATE is (SF1, SF2,DATA0,DATA1, DATA2,EF1,EF2, IDLE1,IDLE2); signal state:TYPE_STATE;
signal bit_counter: unsigned (3 downto 0); |
|
|||
signal symbol_counter: STD_LOGIC_VECTOR (3 downto 0); |
|
|||
signal symbol,sreg: STD_LOGIC_VECTOR (9 downto 0); |
|
|||
begin |
|
|
|
|
op_code<="000" when state=SF1 or state=SF2 else |
-- K28.5 |
|||
"001" when |
state=DATA0 |
or |
state=DATA1 or state=DATA2 else -- дан- |
|
ные |
|
|
|
|
"010" when |
state=EF1 |
else |
|
-- K28.0 |
"011" when |
state=EF2 |
else |
|
-- D0.0 |
"100" when |
state=IDLE1 else |
|
-- K29.7 |
|
"000"; |
|
|
|
|
rd_mode<="00" when state=DATA0 else |
|
|||
"01" when |
state=DATA1 else |
|
|
|
"10" when |
state=DATA2 else |
|
|
|
"11"; |
|
|
|
|
Tx<=sreg(0); |
|
|
|
|
COUNTER_0_TO_9: process(reset_n,hs_clock) |
|
|||
begin |
|
|
|
|
if reset_n='0' then |
|
|
|
|
bit_counter<=(others=>'0'); |
|
|||
rd<='0'; |
|
|
|
|
rd_fifo<='0'; |
|
|
|
|
en<='0'; |
|
|
|
|
symbol<=(others=>'0'); |
|
|
||
sreg<= (others=>'0'); |
|
|
||
elsif rising_edge(hs_clock) |
then |
|
||
if |
bit_counter=9 then |
|
||
|
bit_counter<=(others=>'0'); |
|
||
|
sreg<= symbol; |
-- параллельная загрузка |
else
sreg(8 downto 0)<=sreg(9 downto 1); -- сериализация bit_counter<=bit_counter+1;
case to_integer(bit_counter) is when 0 =>
63
if state=data0 or state=data1 or state=data2 then rd<='1';
end if;
if state=data0 or state=data1 then rd_fifo<='1';
end if; when 2 =>
rd<='0'; rd_fifo<='0';
when 4 => en<='1';
when 6 => en<='0';
symbol<=data_in10; when others =>
null; end case;
end if; end if;
end process;
STATE_MACHINE: process(reset_n,hs_clock) begin
if reset_n='0' then state<=SF1;
symbol_counter<= (others=>'0');
elsif rising_edge(hs_clock) |
then |
if bit_counter=9 then |
|
case state is |
|
when SF1 => |
|
state<=SF2; |
|
when SF2 => |
|
state<=DATA0; |
|
when DATA0 => |
|
state<=DATA1; |
|
when DATA1 => |
|
state<=DATA2; |
|
when DATA2 =>
if symbol_counter=7 then state<=EF1;
else
state<=DATA0; symbol_counter<=symbol_counter+1;
end if; when EF1 =>
state<=EF2;
64
symbol_counter<= (others=>'0'); when EF2 =>
state<=IDLE1; when IDLE1 =>
state<=IDLE2; when IDLE2 =>
if idle='1' then state<=IDLE1;
else
state<=SF1; end if;
when others => null;
end case; end if;
end if; end process; end Serializer;
Процесс STATE_MACINE реализует граф переходов автомата путем изменения значений сигнала state, кодирующего состояние автомата. Процесс COUNTER_0_TO_9 выполняет деление на 10-тактовой частоте hs_clock. 10 тактов – это время передачи символа кода 8b/10b на частоте hs_clock. В 9-м такте (счет идет от 0 до 9) каждого цикла делителя (сигнал bit_ counter) инициируется переход в автомате. В процессе формируются такие выходные сигналы, как rd и en. На рис. 3.11 приведена временная диаграмма формирования этих сигналов. В STATE_MACINE также выполняется операция сериализации: параллельная загрузка в 9-м такте и сдвиг в сторону младших разрядов сигнала sreg в остальных тактах. Младший разряд sreg(0) подключен к выходу Tx.
Рис. 3.11. Временная диаграмма формирования сигналов rd, rd_mode, en и op_code
65
Из диаграммы видны моменты времени переключения сигналов для трехэтапного преобразования в узле «Преобразование 12/8 бит». 12-разрядные данные считываются по сигналу rd, если значение сигнала rd_mode равно 0 или 1.
Сигнал op_code, сопровождаемый сигналом en, сообщает узлу «Кодер 8b/10b» тип формируемых символов (управляющие или данные). Значения сигналов op_code и rd_mode определяются только состояниями автомата (STATE_MACINE является автоматом Мура) и формируются условными параллельными операторами присвоения.
На рис. 3.12 приведен интерфейс coder_8b10b узла «Кодер 8b/10b», а ниже – программа-спецификация узла на VHDL.
coder_8b10b
op_code (2…0 ) |
data_out10 (9…0) |
en |
|
data_in8 (7…0 ) |
|
Рис. 3.12. Интерфейс узла «Кодер 8b/10»
VHDL программа-спецификация узла «Кодер 8b/10b»
library IEEE;
use IEEE.STD_LOGIC_1164.all; use IEEE.NUMERIC_STD.all; entity coder_8b10b is
port(
reset_n : in STD_LOGIC; en : in STD_LOGIC;
op_code : in STD_LOGIC_VECTOR(2 downto 0); data_in8 : in STD_LOGIC_VECTOR(7 downto 0); data_out10 : out STD_LOGIC_VECTOR(9 downto 0)
);
end coder_8b10b;
architecture coder_8b10b of coder_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
66
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;
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"; 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 D_of_Code5b6b_type is array (0 to 31) of STD_LOGIC; constant D_of_Code5b6b : D_of_Code5b6b_type := (
'1','1','1','0','1','0','0','1','1','0','0','0','0','0','0',‘1', '1','0', '0','0','0','0', '0','1','1', '0','0', '1','0', '1','1', '1');
67
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), |
|
||
4=> |
not Code3b4b_ROM_RDm(4), |
|
||
5=> |
"1010", 6=> |
"0110", |
|
|
7=> |
not Code3b4b_ROM_RDm(7) ); |
|
type D_of_Code3b4b_type is array (0 to 7) of STD_LOGIC; constant D_of_Code3b4b : D_of_Code3b4b_type := (
0=> |
'1',1=> |
'0',2=> |
'0', |
3=> |
'1', |
4=> |
'1',5=> |
'0',6=> |
'0', |
7=> |
'1'); |
signal RD:std_logic; begin
CODER_8B_10B: process(reset_n, en) variable v_RD: std_logic;
variable v_data_out: std_logic_vector(9 downto 0); begin
if reset_n='0' then RD<='0';
data_out10<=(others=>'0'); elsif rising_edge(en) then
v_RD:=RD; case op_code is
when "000" => if RD='0' then
data_out10<=K28_5_RDm; else
data_out10<=not K28_5_RDm; end if;
when "001"
if D_of_Code5b6b(TO_INTEGER(unsigned(data_in8(4 downto 0))))='0' then
v_data_out(5 downto ) := cross_6(Code5b6b_ROM_RDm (TO_INTEGER(unsigned(data_in8(4 downto 0)))));
else
if v_RD='0' then
v_data_out(5 downto 0) :=cross_6(Code5b6b_ROM_RDm (TO_INTEGER(unsigned(data_in8(4 downto 0)))));
else
v_data_out(5 downto 0) :=cross_6(Code5b6b_ROM_RDp
68
(TO_INTEGER(unsigned(data_in8(4 downto 0)))));
end if;
if TO_INTEGER(unsigned(data_in8(4 downto 0)))/=7 then vRD:=not vRD;
end if;
end if;
if D_of_Code3b4b(TO_INTEGER(unsigned(data_in8(7 downto 5))))='0' then y(9 downto 6):=Cross_4(Code3b4b_ROM_RDm
(TO_INTEGER(unsigned(data_in8(7 downto 5)))));
else
if TO_INTEGER(unsigned(data_in8(7 downto 5)))/=7 then if vRd='0' then
y(9 downto 6):=Cross_4(Code3b4b_ROM_RDm (TO_INTEGER(unsigned(data_in8(7 downto 5)))));
else
y(9 downto 6):=Cross_4(Code3b4b_ROM_RDp (TO_INTEGER(unsigned(data_in8(7 downto 5)))));
end if;
if TO_INTEGER(unsigned(data_in8(7 downto 5)))/=3 then vRD:=not vRD;
end if;
else
if vRd='0' then
if TO_INTEGER(unsigned(data_in8(4 downto 0)))=17 or TO_INTEGER(unsigned(data_in8(4 downto 0)))=18 or TO_INTEGER(unsigned(data_in8(4 downto 0)))=20 then y(9 downto 6):=Cross_4(Code3b4b_ROM_RDp
(TO_INTEGER(unsigned(data_in8(7 downto 5)))));
else
y(9downto 6):=Cross_4(Code3b4b_ROM_RDm (TO_INTEGER(unsigned(data_in8(7 downto 5)))));
end if; else
if TO_INTEGER(unsigned(data_in8(4 downto 0)))=11 or TO_INTEGER(unsigned(data_in8(4 downto 0)))=13 or TO_INTEGER(unsigned(data_in8(4 downto 0)))=14 then
y(9 downto 6):=Cross_4(Code3b4b_ROM_RDm (TO_INTEGER(unsigned(data_in8(7 downto 5)))));
else
y(9 downto 6):=Cross_4(Code3b4b_ROM_RDp (TO_INTEGER(unsigned(data_in8(7 downot 5)))));
end if; end if;
vRD:=not vRD; end if;
69
end if; RD<=vRD; data_out10<=y;
when "100" => data_out10<=K29_7_RDm;
when others =>
if RD='0' then data_out10<=K28_5_RDm;
else
data_out10<=not K28_5_RDm; end if;
RD:=not RD;
end case; end if;
end process; end coder_8b10b;
В программе определены константы K28_5_RDm, K28_0_ RDm и K29_7_RDm К-символов, массивы констант Code5b6b_
ROM_RDm, Code5b6b_ROM_RDp, Code3b4b_ROM_RDm,
Code3b4b_ROM_RDp D-символов, представляющих таблицы соответствия кода 8b10b. Массивы констант D_of_Code5b6b и D_of_Code3b4b представляют сведения о дисбалансе соответствующих кодовых комбинаций.
Значения кода для данных на входе data_in8 появляются на выходе data_out10 по фронту сигнала en. Значение 0 на входе op_code вызывает формирование К-символа K28.5, значение 1 – D-символов, значение 2 – К-символа K28.0 и значение 3 – D-сим- вола D 0.0. Сигнал RD сохраняет текущее значение дисбаланса. Функции cross_6 и cross_4 выполняют перестановку бит кода для их выдачи в линию связи в правильной последовательности и не требуют аппаратных затрат.
Сиспользованием модели ПУА реализуем узел Deserializer
синтерфейсом на рис. 3.13.
На вход ddr_clock подается тактовый сигнал частотой 1,25 ГГц (ddr – удвоенная скорость), полученный выделителем тактовой частоты из входного сигнала Rx. Под действием ddr_clock последовательные данные Rx выравниваются и преобразуются в параллельные 10-битные символы data_out10. Выходные сигналы en и op_code необходимы для работы узла «Декодер 8b/10b», а выходной сигнал wr – для узла «FIFO приема».
70