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

Subversion Repositories yahamm

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

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

powered by: WebSVN 2.1.0

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