~ruther/jesd204b-vhdl

ref: a6e4dd85d3ac9bc447062b9566793e97262e76c9 jesd204b-vhdl/src/data_link/an8b10b_decoder.vhd -rw-r--r-- 9.1 KiB
a6e4dd85 — František Boháček feat: add possibility to specify order of input to LSB (only MSB was supported) 1 year, 10 months 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
231
232
233
234
235
236
237
238
239
240
241
242
243
-------------------------------------------------------------------------------
-- Title      : 8b10b decoder
-------------------------------------------------------------------------------
-- File       : an8b10b_decoder.vhd
-------------------------------------------------------------------------------
-- Description: Decodes 8b10b encoding, outputs 8bit. Expects aligned characters
-- at input. Outputs do_char with disparity error and missing (not in table) errors.
-- For first character it's possible to get a disparity error.
-------------------------------------------------------------------------------


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

entity an8b10b_decoder is
  generic (
    REVERSE : std_logic := '1' -- Whether to expect characters reversed
  );
  port (
    ci_char_clk : in  std_logic;        -- The character clock
    ci_reset    : in  std_logic;        -- The reset (asynchronous active low)
    di_10b      : in  std_logic_vector(9 downto 0);  -- The 8b10b encoded input data
    do_char     : out link_character;  -- The output decoded 8b data
    co_error    : out std_logic);       -- Whether there is an error (disparity
                                        -- or missing)
end entity an8b10b_decoder;

architecture a1 of an8b10b_decoder is
  type a5b6b_array is array (0 to 63) of std_logic_vector(4 downto 0);
  type a3b4b_array is array (0 to 15) of std_logic_vector(2 downto 0);
  constant a5b6b_alphabet : a5b6b_array := (
    39 => "00000", 24 => "00000", 29 => "00001", 34 => "00001",
    45 => "00010", 18 => "00010", 49 => "00011", 53 => "00100",
    10 => "00100", 41 => "00101", 25 => "00110", 56 => "00111",
    7 => "00111", 57 => "01000", 6 => "01000", 37 => "01001",
    21 => "01010", 52 => "01011", 13 => "01100", 44 => "01101",
    28 => "01110", 23 => "01111", 40 => "01111", 27 => "10000",
    36 => "10000", 35 => "10001", 19 => "10010", 50 => "10011",
    11 => "10100", 42 => "10101", 26 => "10110", 58 => "10111",
    5 => "10111", 51 => "11000", 12 => "11000", 38 => "11001",
    22 => "11010", 54 => "11011", 9 => "11011", 14 => "11100",
    46 => "11101", 17 => "11101", 30 => "11110", 33 => "11110",
    43 => "11111", 20 => "11111",
    others => (others => '0'));  -- Alphabet for decoding 5b6b code
  constant a3b4b_alphabet : a3b4b_array := (
    4 => "000", 11 => "000", 9 => "001", 5 => "010",
    3 => "011", 12 => "011", 2 => "100", 13 => "100",
    10 => "101", 6 => "110", 1 => "111", 14 => "111",
    8 => "111", 7 => "111",
    others => (others => '0'));  -- Alphabet for decoding 3b4b code
  constant ctrl_3b4b_alphabet : a3b4b_array := (
    4 => "000", 9 => "001", 5 => "010",
    3 => "011", 2 => "100", 10 => "101",
    6 => "110", 8 => "111",
    others => (others => '0'));         -- Alphabet for decoding control 3b4b code
  constant ctrl_5b6b_alphabet : a5b6b_array := (
    15 => "11100", 58 => "10111", 54 => "11011",
    46 => "11101", 30 => "11110",
    others => (others => '0'));         -- Alphabet for decoding control 5b6b code

  signal reg_do_8b : std_logic_vector(7 downto 0) := (others => '0');
  signal reg_rd : std_logic := '0';         -- The current running disparity
                                            -- (0 for RD = -1)

  signal next_disparity_error : std_logic;
  signal next_missing_error : std_logic;
  signal next_error : std_logic;
  signal next_kout : std_logic := '0';
  signal next_rd : std_logic := '0';
  signal change_rd : std_logic := '0';
  signal next_do_8b : std_logic_vector(7 downto 0) := (others => '0');

  signal data_4b : std_logic_vector(3 downto 0) := "0000";
  signal data_6b : std_logic_vector(5 downto 0) := "000000";
  signal data_4b_int : integer range 0 to 15 := 0;
  signal data_6b_int : integer range 0 to 63 := 0;
  signal data_4b_int_neg : integer range 0 to 15 := 0;
  signal data_6b_int_neg : integer range 0 to 63 := 0;

  signal di_10b_reversed : std_logic_vector(9 downto 0);

  signal di_10b_actual : std_logic_vector(9 downto 0);

  function IsMissingCharacter(
    cdata_4b_int : integer range 0 to 15;
    cdata_6b_int : integer range 0 to 63
  ) return std_logic is
    variable d : std_logic;
  begin
    if cdata_4b_int = 0 or cdata_4b_int = 15 then
      return '1';
    end if;
    if cdata_6b_int < 5 then
      return '1';
    end if;
    if cdata_6b_int > 58 then
      return '1';
    end if;

    if cdata_6b_int = 8 or cdata_6b_int = 16 or cdata_6b_int = 47 or cdata_6b_int = 55 then
      return '1';
    end if;

    return '0';
  end function;

  function IsControlCharacter (
    data : std_logic_vector(9 downto 0)) return std_logic is
  begin
    if data(9 downto 4) = "001111" or data(9 downto 4) = "110000" then
      return '1';
    end if;

    if data = "1110101000" or data = "1101101000" or data = "1011101000" or data = "0111101000" then
      return '1';
    end if;
    if data = not "1110101000" or data = not "1101101000" or data = not "1011101000" or data = not "0111101000" then
      return '1';
    end if;
    return '0';
  end function;

  function IsDisparityCorrect (
    cdata_4b : std_logic_vector(3 downto 0);
    cdata_6b : std_logic_vector(5 downto 0);
    rd   : std_logic)
    return std_logic is
    variable ones_6b : integer range 0 to 63 := 0;
    variable ones_4b : integer range 0 to 15 := 0;
    variable correct_rd : std_logic;
  begin  -- function IsDisparityCorrect
    correct_rd := rd;

    for i in 0 to 5 loop
      if cdata_6b(i) = '1' then
        ones_6b := ones_6b + 1;
      end if;

      if i < 4 and cdata_4b(i) = '1' then
        ones_4b := ones_4b + 1;
      end if;
    end loop;  -- i

    if ones_6b + ones_4b > 6 or ones_6b + ones_4b < 4 then
      return '0';
    end if;

    if ones_6b > 3 then
      correct_rd := '0';
    elsif ones_6b < 3 then
      correct_rd := '1';
    else
      if ones_4b > 2 then
        correct_rd := '0';
      elsif ones_4b < 2 then
        correct_rd := '1';
      else
        if cdata_6b = "000111" then
          correct_rd := '1';
        elsif cdata_6b = "111000" then
          correct_rd := '0';
        elsif cdata_4b = "0011" then
          correct_rd := '1';
        elsif cdata_4b = "1100" then
          correct_rd := '0';
        end if;
      end if;
    end if;

    if correct_rd = rd then
      return '1';
    else
      return '0';
    end if;
  end function IsDisparityCorrect;

begin  -- architecture a1
  di_10b_reversed <= di_10b(0) & di_10b(1) & di_10b(2) & di_10b(3) & di_10b(4) & di_10b(5) & di_10b(6) & di_10b(7) & di_10b(8) & di_10b(9);

  -- purpose: Set next states
  -- type   : sequential
  -- inputs : ci_char_clk, ci_reset
  -- outputs: co_error, co_disparity_error, co_missing_error, reg_do_8b,
  -- reg_rd, co_kout
  set_next: process (ci_char_clk, ci_reset) is
  begin  -- process set_next
    if ci_reset = '0' then              -- asynchronous reset (active low)
      co_error <= '0';
      do_char.disparity_error <= '0';
      do_char.missing_error <= '0';
      do_char.kout <= '0';
      do_char.user_data <= '0';
      reg_do_8b <= (others => '0');
      reg_rd <= '0';
    elsif ci_char_clk'event and ci_char_clk = '1' then  -- rising clock edge
      co_error <= next_error;
      do_char.disparity_error <= next_disparity_error;
      do_char.missing_error <= next_missing_error;
      do_char.kout <= next_kout;
      do_char.user_data <= '0';
      reg_do_8b <= next_do_8b;
      reg_rd <= next_rd;
    end if;
  end process set_next;

  WITHOUT_REVERSE: if REVERSE = '0' generate
    di_10b_actual <= di_10b;
  end generate;
  REVERSED: if REVERSE = '1' generate
    di_10b_actual <= di_10b_reversed;
  end generate;
  data_4b <= di_10b_actual(3 downto 0);
  data_6b <= di_10b_actual(9 downto 4);
  data_4b_int <= to_integer(unsigned(data_4b));
  data_6b_int <= to_integer(unsigned(data_6b));
  data_4b_int_neg <= to_integer(unsigned(not data_4b));
  data_6b_int_neg <= to_integer(unsigned(not data_6b));

  -- running disparity
  -- change in case the number of 0s doesn't match nubmer of 1s (xor_reduce
  -- will output 1 ... it's basically an odd parity)
  -- synchronize in case of disparity error (can be either at the beginning of
  -- communication or the last character was loaded incorrectly)
  change_rd <= (not xor_reduce(di_10b_actual) or next_disparity_error) and not (not xor_reduce(di_10b_actual) and next_disparity_error);
  next_rd <= (not reg_rd and change_rd) or (reg_rd and not change_rd);

  -- control characters
  next_kout <= IsControlCharacter(di_10b_actual);

  -- errors
  next_missing_error <= IsMissingCharacter(data_4b_int, data_6b_int) and not next_kout;
  next_disparity_error <= not IsDisparityCorrect(data_4b, data_6b, reg_rd);
  next_error <= next_missing_error or next_disparity_error;

  next_do_8b <= a3b4b_alphabet(data_4b_int) & a5b6b_alphabet(data_6b_int) when next_kout = '0' else
                ctrl_3b4b_alphabet(data_4b_int_neg) & ctrl_5b6b_alphabet(data_6b_int_neg) when (reg_rd = '1' and next_disparity_error = '0') else
                ctrl_3b4b_alphabet(data_4b_int) & ctrl_5b6b_alphabet(data_6b_int) when (reg_rd = '1' or next_disparity_error = '0') else
                ctrl_3b4b_alphabet(data_4b_int_neg) & ctrl_5b6b_alphabet(data_6b_int_neg);
  do_char.d8b <= reg_do_8b;
end architecture a1;
Do not follow this link