~ruther/jesd204b-vhdl

ref: 92031bce86510b9486a5a8705a6d0b340cf73791 jesd204b-vhdl/src/data_link/ilas_parser.vhd -rw-r--r-- 11.0 KiB
92031bce — František Boháček fix: deassert sync on LMFC falling edge to match the standard 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
-------------------------------------------------------------------------------
-- Title      : ilas parser
-------------------------------------------------------------------------------
-- File       : ilas_parser.vhd
-------------------------------------------------------------------------------
-- Description: Parses ilas, outputs it's config and checks
-- that everything is correct.
-------------------------------------------------------------------------------

library ieee;
use work.data_link_pkg.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity ilas_parser is
  generic (
    F                 : integer range 1 to 256;  -- Number of octets in a frame
    K                 : integer range 1 to 32;  -- Number of frames in a multiframe
    K_character       : std_logic_vector(7 downto 0) := "10111100";  -- Character
                                        -- for syncing
    R_character       : std_logic_vector(7 downto 0) := "00011100";  -- ILAS
                                        -- multiframe
                                        -- start character
    A_character       : std_logic_vector(7 downto 0) := "01111100";  -- ILAS
                                        -- multiframe
                                        -- end character
    Q_character       : std_logic_vector(7 downto 0) := "10011100";  -- ILAS 2nd
                                        -- multiframe
                                        -- 2nd character
    multiframes_count : integer range 1 to 32        := 4);

  port (
    ci_char_clk        : in  std_logic;  -- Character clock
    ci_reset           : in  std_logic;  -- Reset (asynchonous, active low)
    ci_state           : in  link_state;  -- State of the lane
    di_char            : in  character_vector;  -- Character from 8b10b decoder
    do_config          : out link_config;  -- Config found in ILAS
    co_finished        : out std_logic;  -- The ILAS was received correctly
    co_error           : out std_logic;  -- The ILAS was not received correctly
    co_wrong_chksum    : out std_logic;  -- There was a wrong checksum in the ILAS
    co_unexpected_char : out std_logic);  -- There was a character at
                                          -- unexpected location in the ILAS

end entity ilas_parser;

architecture a1 of ilas_parser is
  constant link_config_length : integer := 112;
  signal octets_in_multiframe : integer range 0 to 8192 := 0;
  signal link_config_data : std_logic_vector(link_config_length-1 downto 0) := (others => '0');
  signal reg_processing_ilas : std_logic := '0';
  signal reg_multiframe_index : integer range 0 to multiframes_count+1 := 0;
  signal reg_octet_index : integer range 0 to F*K+5 := 0;

  signal next_processing_ilas : std_logic := '0';
  signal next_multiframe_index : integer range 0 to multiframes_count+1 := 0;
  signal next_octet_index : integer range 0 to F*K+5 := 0;

  signal finished : std_logic := '0';
  signal err : std_logic := '0';


  function getOctetUpIndex (
    octet_index : integer range 0 to F*K+5)
    return integer is
  begin  -- function getByteUpIndex
    return link_config_length - 1 - 8 * octet_index;
  end function getOctetUpIndex;

  function getDataByIndex (
    data        : std_logic_vector(link_config_length-1 downto 0);
    octet_index : integer range 0 to F*K+5;
    bit_index   : integer range 0 to 7;
    length      : integer range 1 to 8)
    return std_logic_vector is
    variable up_index : integer;
  begin  -- function getDataByIndex
    up_index := getOctetUpIndex(octet_index);
    return data(up_index - 7 + bit_index + length - 1 downto up_index - 7 + bit_index);
  end function getDataByIndex;

  function getBitByIndex (
    data        : std_logic_vector(link_config_length-1 downto 0);
    octet_index : integer range 0 to F*K+5;
    bit_index   : integer range 0 to 7)
    return std_logic is
    variable up_index : integer;
  begin  -- function getBitByIndex
    up_index := getOctetUpIndex(octet_index);
    return data(up_index - 7 + bit_index);
  end function getBitByIndex;
begin  -- architecture a1
  octets_in_multiframe <= F * K;
  -- ILAS
    -- one multiframe is sent
    -- 4 frames in a multiframe
    -- second frame contains ILAS at third character
    -- each start of a frame should have /R/
    -- each end of a frame should have /A/
    -- second frame:
      -- second_character: /K28.0/
      -- third_character: starts ILAS

  -- if anything does not match (/R/, /A/, /K28.0/, checksum), set error
  -- and co_wrong_chksum or co_unexpected_char. Stop processing.
  -- The controller will then request new synchronization try.

  set_next: process (ci_char_clk, ci_reset) is
  begin  -- process set_next
    if ci_reset = '0' then              -- asynchronous reset (active low)
      reg_octet_index <= 0;
      reg_multiframe_index <= 0;
      reg_processing_ilas <= '0';
    elsif ci_char_clk'event and ci_char_clk = '1' then  -- rising clock edge
      reg_octet_index <= next_octet_index;
      reg_multiframe_index <= next_multiframe_index;
      reg_processing_ilas <=  next_processing_ilas;
    end if;
  end process set_next;

  check_chars: process (ci_char_clk, ci_reset) is
    variable up_index : integer range 7 to link_config_length-1;
    variable processing_ilas : std_logic;
  begin  -- process check_chars
    processing_ilas := next_processing_ilas or reg_processing_ilas;
    if ci_reset = '0' then              -- asynchronous reset (active low)
      err <= '0';
      co_unexpected_char <= '0';
      co_wrong_chksum <= '0';
      finished <= '0';
      link_config_data <= (others => '0');
    elsif ci_char_clk'event and ci_char_clk = '1' and (processing_ilas = '0' or ci_state = INIT) then
      err <= '0';
      co_unexpected_char <= '0';
      co_wrong_chksum <= '0';

      if ci_state /= DATA and ci_state /= ILS then
        link_config_data <= (others => '0');
        finished <= '0';
      end if;
    elsif ci_char_clk'event and ci_char_clk = '1' and err = '1' then
      if next_processing_ilas = '0' then
        err <= '0';
        co_unexpected_char <= '0';
        co_wrong_chksum <= '0';
      end if;
      -- If there is an error, stop processing.
    elsif ci_char_clk'event and ci_char_clk = '1' and processing_ilas = '1' then  -- rising clock edge
      if reg_octet_index = 0 then       -- Should be /R/
        if di_char.d8b /= R_character or di_char.kout = '0' then
          err <= '1';
          co_unexpected_char <= '1';
        end if;
      elsif di_char.d8b = R_character and di_char.kout = '1' then
        err <= '1';
        co_unexpected_char <= '1';
      elsif reg_octet_index = octets_in_multiframe - 1 then
        if di_char.d8b /= A_character or di_char.kout = '0' then  -- Should be /A/
          err <= '1';
          co_unexpected_char <= '1';
        elsif reg_multiframe_index = 3 and err = '0' then
          finished <= '1';
        end if;
      elsif di_char.d8b = A_character and di_char.kout = '1' then
        err <= '1';
        co_unexpected_char <= '1';
      elsif reg_multiframe_index = 1 then
        if reg_octet_index = 1 and (di_char.d8b /= Q_character or di_char.kout = '0') then  -- Should be /Q/
          err <= '1';
          co_unexpected_char <= '1';
        elsif reg_octet_index > 1 and reg_octet_index < 16 then    -- This is config data
          up_index := getOctetUpIndex(reg_octet_index - 2);
          link_config_data(up_index downto up_index - 7) <= di_char.d8b;
        end if;

        if reg_octet_index = 15 then    -- This is a checksum
          -- TODO: calculate checksum. Probably not necessary checksum will be
          -- precalculated and has to be matched, we do not need to calculate it
          -- if di_char.d8b = "00000000" then
          --  co_wrong_chksum <=  '1';
          --  err <= '1';
          -- end if;
        end if;
      elsif reg_multiframe_index > 3 then
        err <= '1';
      end if;
    end if;
  end process check_chars;

  co_finished <= '1' when finished = '1' or (di_char.kout = '1' and di_char.d8b = A_character and reg_octet_index = octets_in_multiframe - 1 and reg_multiframe_index = 3) else '0';
  co_error <= '1' when err = '1' and ci_state = ILS else '0';

  next_processing_ilas <= '0' when ci_state = INIT or finished = '1' else
                          '0' when ci_state = CGS and reg_processing_ilas = '1' else
                          '0' when reg_multiframe_index = 3 and reg_octet_index = octets_in_multiframe - 1 else
                          '1' when ci_state = CGS and not (di_char.d8b = K_character and di_char.kout = '1') else
                          '1' when reg_processing_ilas = '1' or ci_state = ILS else
                          '0';

  -- octet, multiframe index
  next_multiframe_index <= 0 when reg_processing_ilas = '0' and next_processing_ilas = '0' else
                           (reg_multiframe_index + 1) when reg_octet_index = octets_in_multiframe - 1 else
                           reg_multiframe_index;
  next_octet_index <= 0 when (next_processing_ilas = '0' and reg_processing_ilas = '0') or (next_processing_ilas = '0' and reg_processing_ilas = '1') else
                      (reg_octet_index + 1) mod octets_in_multiframe;

  -- config
  do_config.DID <= to_integer(unsigned(getDataByIndex(link_config_data, 0, 0, 8)));
  do_config.ADJDIR <= getBitByIndex(link_config_data, 2, 6);
  do_config.ADJCNT <= to_integer(unsigned(getDataByIndex(link_config_data, 1, 4, 4)));
  do_config.BID <= to_integer(unsigned(getDataByIndex(link_config_data, 1, 0, 4)));
  do_config.PHADJ <= getBitByIndex(link_config_data, 2, 5);
  do_config.LID <= to_integer(unsigned(getDataByIndex(link_config_data, 2, 0, 5)));
  do_config.SCR <= getBitByIndex(link_config_data, 3, 7);
  do_config.L <= to_integer(unsigned(getDataByIndex(link_config_data, 3, 0, 5))) + 1;
  do_config.F <= to_integer(unsigned(getDataByIndex(link_config_data, 4, 0, 8))) + 1;
  do_config.K <= to_integer(unsigned(getDataByIndex(link_config_data, 5, 0, 5))) + 1;
  do_config.M <= to_integer(unsigned(getDataByIndex(link_config_data, 6, 0, 8))) + 1;
  do_config.CS <= to_integer(unsigned(getDataByIndex(link_config_data, 7, 6, 2)));
  do_config.N <= to_integer(unsigned(getDataByIndex(link_config_data, 7, 0, 5))) + 1;
  do_config.SUBCLASSV <= to_integer(unsigned(getDataByIndex(link_config_data, 8, 5, 3)));
  do_config.Nn <= to_integer(unsigned(getDataByIndex(link_config_data, 8, 0, 5))) + 1;
  do_config.JESDV <= to_integer(unsigned(getDataByIndex(link_config_data, 9, 5, 3)));
  do_config.S <= to_integer(unsigned(getDataByIndex(link_config_data, 9, 0, 5))) + 1;
  do_config.HD <= getBitByIndex(link_config_data, 10, 7);
  do_config.CF <= to_integer(unsigned(getDataByIndex(link_config_data, 9, 0, 5)));
  do_config.RES1 <= getDataByIndex(link_config_data, 11, 0, 8);
  do_config.RES2 <= getDataByIndex(link_config_data, 12, 0, 8);
  do_config.CHKSUM <= to_integer(unsigned(getDataByIndex(link_config_data, 13, 0, 8)));
  do_config.X <=  getBitByIndex(link_config_data, 2, 7) & getDataByIndex(link_config_data, 3, 5, 2) & getDataByIndex(link_config_data, 5, 5, 3) & getBitByIndex(link_config_data, 7, 5) & getDataByIndex(link_config_data, 10, 5, 2);
end architecture a1;
Do not follow this link