OpenCores
URL https://opencores.org/ocsvn/yahamm/yahamm/trunk

Subversion Repositories yahamm

[/] [yahamm/] [trunk/] [rtl/] [vhdl/] [yahamm_dec.vhd] - Blame information for rev 5

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 ndesimone
-------------------------------------------------------------------------------
2
-- Yahamm IP core
3
--
4
-- This file is part of the Yahamm project
5
-- http://www.opencores.org/cores/yahamm
6
--
7
-- Description
8
-- A hamming encoder and decoder with single-error correcting and
9
-- double-error detecting capability. The message length can be configured
10
-- through a generic. Both the code generator matrix and the parity-check
11
-- matrix are computed in the VHDL itself.
12
--
13
-- To Do:
14
-- - write docs
15
--
16
-- Author:
17
-- - Nicola De Simone, ndesimone@opencores.org
18
--
19
-------------------------------------------------------------------------------
20
--
21
-- Copyright (C) 2017 Authors and OPENCORES.ORG
22
--
23
-- This source file may be used and distributed without
24
-- restriction provided that this copyright statement is not
25
-- removed from the file and that any derivative work contains
26
-- the original copyright notice and the associated disclaimer.
27
--
28
-- This source file is free software; you can redistribute it
29
-- and/or modify it under the terms of the GNU Lesser General
30
-- Public License as published by the Free Software Foundation;
31
-- either version 2.1 of the License, or (at your option) any
32
-- later version.
33
--
34
-- This source is distributed in the hope that it will be
35
-- useful, but WITHOUT ANY WARRANTY; without even the implied
36
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
37
-- PURPOSE. See the GNU Lesser General Public License for more
38
-- details.
39
--
40
--- You should have received a copy of the GNU Lesser General
41
-- Public License along with this source; if not, download it
42
-- from http://www.opencores.org/lgpl.shtml
43
--
44
-------------------------------------------------------------------------------
45
 
46 2 ndesimone
library ieee;
47
use ieee.std_logic_1164.all;
48
use ieee.numeric_std.all;
49
 
50
library yahamm;
51
use yahamm.matrix_pkg.all;
52
use yahamm.yahamm_pkg.all;
53
 
54
library std;
55
use std.textio.all;
56
 
57
-- There are two monitor counters:
58
--
59
-- cnt_errors_corrected: number of error correction performed.
60
-- cnt_errors_detected: numbers of errors detected but not corrected.
61
--
62
-- The two never count together and they don't overflow.  If CORRECT
63
-- is false, no correction is performed cnt_errors_corrected never counts.
64
-- If CORRECT is true and EXTRA_PARITY_BIT is true, cnt_errors_detected
65
-- never counts because all errors (supposedly single-bit errors) are
66
-- corrected.
67
--
68
-- ERROR_LEN: width of the cnt_errors_corrected and cnt_errors_detected counters.
69
--
70 5 ndesimone
-- dout_valid_o: dout data valid, it's the en input pipelined.  It takes into
71 2 ndesimone
-- account the total latency.
72
--
73
entity yahamm_dec is
74
  generic (
75
    MESSAGE_LENGTH       : natural := 5;
76
    CORRECT : boolean := true;
77
    EXTRA_PARITY_BIT : natural range 0 to 1 := 1;
78
    ONE_PARITY_BIT : boolean := false;
79
    ERROR_LEN : natural := 16
80
    );
81
  port(
82 5 ndesimone
    clk_i, rst_i : in  std_logic;
83
    cnt_clr_i : in std_logic := '0';             -- Clear monitor counters.
84
    en_i       : in  std_logic := '1';          -- Input enable.
85
    data_i        : in  std_logic_vector(MESSAGE_LENGTH - 1 downto 0);  -- Input data.
86
    parity_i   : in std_logic_vector(calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT) + EXTRA_PARITY_BIT - 1 downto 0);    -- Parity bits.
87
    data_o        : out std_logic_vector(MESSAGE_LENGTH - 1 downto 0);  -- Out data.
88
    dout_valid_o : out std_logic;                                          -- data_o valid.
89
    cnt_errors_corrected_o, cnt_errors_detected_o : out std_logic_vector(ERROR_LEN - 1 downto 0);
90
    log_wrong_bit_pos_data_o : out std_logic_vector(MESSAGE_LENGTH - 1 downto 0);
91
    log_wrong_bit_pos_parity_o : out std_logic_vector(calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT) + EXTRA_PARITY_BIT - 1 downto 0)
92 2 ndesimone
    );
93
 
94
end yahamm_dec;
95
 
96
architecture std of yahamm_dec is
97
 
98
  constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);
99
  constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);
100
 
101
  constant H : matrix_t(0 to NPARITY_BITS + EXTRA_PARITY_BIT - 1,
102
 
103
    get_parity_check_matrix(MESSAGE_LENGTH, EXTRA_PARITY_BIT, ONE_PARITY_BIT);
104
 
105 5 ndesimone
  signal data_i_padded : bit_vector(BLOCK_LENGTH - NPARITY_BITS - 1 downto 0);
106 2 ndesimone
  signal code_sys, code_nonsys, code_nonsys_q : bit_vector(BLOCK_LENGTH + EXTRA_PARITY_BIT - 1 downto 0);
107
  signal syndrome : bit_vector(NPARITY_BITS + EXTRA_PARITY_BIT - 1 downto 0);
108
  signal wrong_bit : integer range 0 to code_sys'length;
109
 
110
  constant SWAPM : matrix_t(0 to BLOCK_LENGTH + EXTRA_PARITY_BIT - 1,
111
 
112
    get_form_swap_matrix(MESSAGE_LENGTH, EXTRA_PARITY_BIT, ONE_PARITY_BIT);
113
 
114
  signal correction_en : boolean;
115 5 ndesimone
  signal cnt_errors_corrected_o_int, cnt_errors_detected_o_int : unsigned(ERROR_LEN - 1 downto 0);
116
  signal log_wrong_bit_pos_data_o_sys, log_wrong_bit_pos_data_o_nonsys : bit_vector(BLOCK_LENGTH + EXTRA_PARITY_BIT - 1 downto 0);
117 2 ndesimone
 
118 5 ndesimone
  signal dout_valid_o_p0 : std_logic;
119 2 ndesimone
 
120
begin
121
 
122
  check_parameters(BLOCK_LENGTH, NPARITY_BITS, MESSAGE_LENGTH, EXTRA_PARITY_BIT, ONE_PARITY_BIT, CORRECT);
123
 
124 5 ndesimone
  cnt_errors_corrected_o <= std_logic_vector(cnt_errors_corrected_o_int);
125
  cnt_errors_detected_o <= std_logic_vector(cnt_errors_detected_o_int);
126 2 ndesimone
 
127 5 ndesimone
  -- Pad data_i with zeros on the left, so that data_i_padded'length = BLOCK_LENGTH.
128
  -- This allow the user to reduce data_i width.
129
  data_i_padded(MESSAGE_LENGTH - 1 downto 0) <= to_bitvector(data_i);
130
  gen_padding: if BLOCK_LENGTH - NPARITY_BITS > MESSAGE_LENGTH generate
131
    data_i_padded(BLOCK_LENGTH - NPARITY_BITS - 1 downto MESSAGE_LENGTH) <= (others => '0');
132
  end generate gen_padding;
133 2 ndesimone
 
134
  -- Wire data and parity inputs in the systematic code code_sys (data
135
  -- on LSB, parity on MSB).
136 5 ndesimone
  code_sys <= to_bitvector(parity_i) & data_i_padded;
137 2 ndesimone
 
138
  -- Get the non-systematic code code_nonsys by swapping the
139
  -- systematic code code_sys.  The non-systematic code is needed to
140
  -- obtain an immediately meaningful syndrome.  This is timing-safe:
141
  -- no logic here, it's purely wiring.
142
  code_nonsys <= xor_multiply_vec(SWAPM, code_sys);
143
 
144
  -- Output log_wrong_bit_pos_log, uses log_wrong_bit_pos_log_nonsys is padded
145 5 ndesimone
  -- as data_i_padded
146
  log_wrong_bit_pos_data_o_sys <= xor_multiply_vec(SWAPM, log_wrong_bit_pos_data_o_nonsys);
147
  log_wrong_bit_pos_data_o <= To_StdLogicVector(log_wrong_bit_pos_data_o_sys(MESSAGE_LENGTH-1 downto 0));
148
  log_wrong_bit_pos_parity_o <= To_StdLogicVector(log_wrong_bit_pos_data_o_sys(BLOCK_LENGTH + EXTRA_PARITY_BIT - 1 downto BLOCK_LENGTH - NPARITY_BITS));
149 2 ndesimone
 
150
  -- purpose: Compute error syndrome from the non-systematic code
151
  -- (input) and the non-systemacic parity check matrix H.  Also delay
152
  -- code_nonsys to have code_nonsys_q synchronous with syndrome.  And start
153
  -- pipelining en input.
154
  -- type   : sequential
155 5 ndesimone
  -- inputs : clk_i, rst_i, code_nonsys
156 2 ndesimone
  -- outputs: syndrome
157 5 ndesimone
  syndrome_proc: process (clk_i, rst_i) is
158 2 ndesimone
  begin  -- process syndrome_proc
159 5 ndesimone
    if rst_i = '1' then                   -- asynchronous reset (active high)
160 2 ndesimone
      syndrome <= (others => '0');
161
      code_nonsys_q <= (others => '0');
162 5 ndesimone
      dout_valid_o_p0 <= '0';
163
    elsif rising_edge(clk_i) then         -- rising clock edge
164 2 ndesimone
      syndrome <= xor_multiply_vec(H, code_nonsys);
165
      code_nonsys_q <= code_nonsys;
166 5 ndesimone
      dout_valid_o_p0 <= en_i;
167 2 ndesimone
    end if;
168
  end process syndrome_proc;
169
 
170
  -- purpose: Enable error correction (signal correction_en) for a single bit
171
  -- error.  Dependent from the generic parameters.  If correction is enabled
172
  -- wrong_bit signal is assigned the position of the wrong bit.
173
  -- type   : combinational
174
  -- inputs : syndrome
175
  -- outputs: correction_enabled
176
  correction_enable_proc: process (syndrome) is
177
  begin  -- process correction_enable_proc
178
    wrong_bit <= 0;
179
 
180
    case CORRECT is
181
      when false =>
182
        -- Entity does not implement correction.                
183
        correction_en <= false;
184
 
185
      when true =>
186
        -- Entity implements correction.
187
 
188
        case EXTRA_PARITY_BIT is
189
          when 0 =>
190
            -- SEC case (see table).  Always correct.            
191
            correction_en <= true;
192
 
193
            -- The wrong bit is the syndrome itself.
194
            wrong_bit <= to_integer(unsigned(To_StdULogicVector(syndrome)));
195
 
196
          when 1 =>
197
            -- SECDED case (see table).  The error, if any, is a single error to be
198
            -- corrected if the extra parity bit in the syndrome is '1'.
199
            if syndrome(syndrome'high) = '0' then
200
              -- Double error: don't correct.
201
              correction_en <= false;
202
            else
203
              -- Single error: correct.        
204
              correction_en <= true;
205
 
206
              -- The wrong bit is not just the syndrome, because the
207
              -- syndrome has the extra parity bit as MSB bit.
208
              if or_reduce(syndrome(syndrome'high-1 downto 0)) = '0' then
209
                -- No other error.  So the extra parity bit itself is
210
                -- wrong, that in this implementation is the MSB of
211
                -- the non-systematic code word.
212
                wrong_bit <= code_nonsys_q'length;
213
              else
214
                -- Extra parity bit '1', ignore it for wrong_bit position.
215
                wrong_bit <= to_integer(unsigned(To_StdULogicVector(syndrome(NPARITY_BITS-1 downto 0))));
216
              end if;
217
            end if;
218
        end case;
219
 
220
    end case;
221
 
222
  end process correction_enable_proc;
223
 
224
  -- purpose: Decode the non systematic code code_nonsys_q and drive
225 5 ndesimone
  -- output data_o.  Single error correction is performed, depending on
226 2 ndesimone
  -- the configuration.
227
  -- type   : sequential
228 5 ndesimone
  -- inputs : clk_i, rst_i, code_nonsys_q, syndrome
229
  -- outputs: data_o
230
  decode_proc: process (clk_i, rst_i) is
231 2 ndesimone
    variable iserror : boolean;         -- parity error condition
232
    variable code_sys_dec, code_nonsys_dec : bit_vector(code_sys'range);
233
  begin  -- process decode_proc
234 5 ndesimone
    if rst_i = '1' then                   -- asynchronous reset (active high)
235
      data_o <= (others => '0');
236
      dout_valid_o <= '0';
237
    elsif rising_edge(clk_i) then         -- rising clock edge
238 2 ndesimone
 
239 5 ndesimone
      if dout_valid_o_p0 = '0' then
240
        data_o <= (others => '0');
241
        dout_valid_o <= '0';
242 2 ndesimone
      else
243
 
244
        code_nonsys_dec := code_nonsys_q;
245
        iserror := or_reduce(syndrome) = '1';
246
 
247
        if correction_en and iserror then
248
          code_nonsys_dec(wrong_bit-1) := not code_nonsys_q(wrong_bit-1);
249
        end if;
250
 
251
        code_sys_dec := xor_multiply_vec(SWAPM, code_nonsys_dec);
252 5 ndesimone
        data_o <= To_StdLogicVector(code_sys_dec(MESSAGE_LENGTH - 1 downto 0));
253
        dout_valid_o <= '1';
254 2 ndesimone
 
255
      end if;
256
    end if;
257
  end process decode_proc;
258
 
259
  -- purpose: Monitor counters.
260
  -- type   : sequential
261 5 ndesimone
  -- inputs : clk_i, rst_i, syndrome, correction_en
262
  -- outputs: cnt_errors_corrected_o_int, cnt_errors_detected_o_int, log_wrong_bit_pos_log
263
  cnt_proc: process (clk_i, rst_i) is
264 2 ndesimone
    variable iserror : boolean;         -- parity error condition
265
  begin  -- process cnt_proc
266 5 ndesimone
    if rst_i = '1' then                   -- asynchronous reset (active high)
267
      cnt_errors_detected_o_int <= (others => '0');
268
      cnt_errors_corrected_o_int <= (others => '0');
269
    elsif rising_edge(clk_i) then         -- rising clock edge
270
      if cnt_clr_i = '1' then
271 2 ndesimone
        -- synchronous clear
272 5 ndesimone
        cnt_errors_detected_o_int <= (others => '0');
273
        cnt_errors_corrected_o_int <= (others => '0');
274 2 ndesimone
      else
275
        iserror := or_reduce(syndrome) = '1';
276
 
277
        if iserror then
278
          if correction_en then
279 5 ndesimone
            if and_reduce(to_bitvector(std_logic_vector(cnt_errors_corrected_o_int))) /= '1' then
280
              cnt_errors_corrected_o_int <= cnt_errors_corrected_o_int + 1;
281 2 ndesimone
            end if;
282
          else
283 5 ndesimone
            if and_reduce(to_bitvector(std_logic_vector(cnt_errors_detected_o_int))) /= '1' then
284
              cnt_errors_detected_o_int <= cnt_errors_detected_o_int + 1;
285 2 ndesimone
            end if;
286
          end if;
287
        end if;
288
      end if;
289
 
290
    end if;
291
  end process cnt_proc;
292
 
293
  -- purpose: Monitor counters.
294
  -- type   : sequential
295 5 ndesimone
  -- inputs : clk_i, rst_i, syndrome, correction_en
296
  -- outputs: cnt_errors_corrected_o_int, cnt_errors_detected_o_int, log_wrong_bit_pos_log
297 2 ndesimone
  log_wrong_bit_gen: if CORRECT generate
298 5 ndesimone
    log_wrong_bit_proc: process (clk_i, rst_i) is
299 2 ndesimone
      variable iserror : boolean;         -- parity error condition
300
    begin  -- process cnt_proc
301 5 ndesimone
      if rst_i = '1' then
302
        log_wrong_bit_pos_data_o_nonsys <= (others => '0');
303
      elsif rising_edge(clk_i) then
304
        if cnt_clr_i = '1' then
305
          log_wrong_bit_pos_data_o_nonsys <= (others => '0');
306 2 ndesimone
        else
307
          iserror := or_reduce(syndrome) = '1';
308
 
309
          if iserror then
310
            if correction_en then
311
 
312
              -- Note: wrong_bit refers to the wrong bit of the code in
313
              -- non-systematic form.  Indeed this is swapped to
314
              -- systematic form for the output.
315 5 ndesimone
              log_wrong_bit_pos_data_o_nonsys(wrong_bit-1) <= '1';
316 2 ndesimone
 
317
            end if;
318
          end if;
319
        end if;
320
        end if;
321
      end process log_wrong_bit_proc;
322
    end generate log_wrong_bit_gen;
323
 
324
end architecture std;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.