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

Subversion Repositories yahamm

[/] [yahamm/] [trunk/] [rtl/] [vhdl/] [yahamm_pkg.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.math_real.all;
46
use ieee.numeric_std.all;
47
 
48
library yahamm;
49
use yahamm.matrix_pkg.all;
50
 
51
package yahamm_pkg is
52
 
53
  component yahamm_dec is
54
    generic (
55
      MESSAGE_LENGTH   : natural;
56
      CORRECT          : boolean;
57
      EXTRA_PARITY_BIT : natural range 0 to 1;
58
      ONE_PARITY_BIT   : boolean;
59
      ERROR_LEN        : natural;
60
      NPARITY_BITS     : natural;
61
      BLOCK_LENGTH     : natural);
62
    port (
63
      clk, rst                                  : in  std_logic;
64
      en                                        : in  std_logic;
65
      din                                       : in  std_logic_vector(MESSAGE_LENGTH - 1 downto 0);
66
      parity                                    : in  std_logic_vector(NPARITY_BITS + EXTRA_PARITY_BIT - 1 downto 0);
67
      dout                                      : out std_logic_vector(MESSAGE_LENGTH - 1 downto 0);
68
      cnt_errors_corrected, cnt_errors_detected : out std_logic_vector(ERROR_LEN - 1 downto 0));
69
  end component yahamm_dec;
70
 
71
  component yahamm_enc is
72
    generic (
73
      MESSAGE_LENGTH   : natural;
74
      EXTRA_PARITY_BIT : natural range 0 to 1;
75
      ONE_PARITY_BIT   : boolean;
76
      NPARITY_BITS     : natural;
77
      BLOCK_LENGTH     : natural);
78
    port (
79
      clk, rst : in  std_logic;
80
      en       : in  std_logic := '1';
81
      din      : in  std_logic_vector(MESSAGE_LENGTH - 1 downto 0);
82
      dout     : out std_logic_vector(MESSAGE_LENGTH - 1 downto 0);
83
      parity   : out std_logic_vector(NPARITY_BITS + EXTRA_PARITY_BIT - 1 downto 0));
84
  end component yahamm_enc;
85
 
86
  function get_parity_check_matrix (
87
    MESSAGE_LENGTH : natural;
88
    EXTRA_PARITY : natural range 0 to 1  := 1;
89
    ONE_PARITY_BIT : boolean := false)
90
    return matrix_t;
91
 
92
  function get_code_generator_matrix (
93
    MESSAGE_LENGTH : natural;
94 4 ndesimone
    EXTRA_PARITY : natural range 0 to 1 := 1;       -- number of data (non parity) bits
95 2 ndesimone
    ONE_PARITY_BIT : boolean := false)
96
    return matrix_t;
97
 
98
  function calc_nparity_bits (
99 4 ndesimone
    k : natural;
100 2 ndesimone
    ONE_PARITY_BIT : boolean := false)
101
    return natural;
102
 
103
  function calc_block_length (
104 4 ndesimone
    k : natural;
105 2 ndesimone
    ONE_PARITY_BIT : boolean := false)
106
    return natural;
107
 
108
  procedure check_parameters (
109
    constant BLOCK_LENGTH     : in natural;
110
    constant NPARITY_BITS     : in natural;
111
    constant MESSAGE_LENGTH   : in natural;
112
    constant EXTRA_PARITY_BIT : in natural;
113
    constant ONE_PARITY_BIT : in boolean;
114
    constant CORRECT : in boolean := false
115
    );
116 4 ndesimone
 
117 2 ndesimone
  function xor_multiply (
118
    A : matrix_t;
119 4 ndesimone
    B : matrix_t)
120 2 ndesimone
    return matrix_t;
121
 
122
  function xor_multiply_vec (
123
    A : matrix_t;
124 4 ndesimone
    x : bit_vector)
125 2 ndesimone
    return bit_vector;
126
 
127
  function get_form_swap_matrix (
128
    MESSAGE_LENGTH : natural;
129
    EXTRA_PARITY : natural;
130
    ONE_PARITY_BIT : boolean := false)
131
    return matrix_t;
132
 
133
end package yahamm_pkg;
134
 
135
package body yahamm_pkg is
136 4 ndesimone
 
137 2 ndesimone
  -- purpose: Return a matrix S that can be used to tranform a parity
138
  -- check matrix or a code generator matrix M from non-systematic
139
  -- form to systematic form MS and viceversa (because S = S
140
  -- transposed = S^-1).  Use as as MS = M x S.
141
  -- Also works for M with extra parity bit: set EXTRA_PARITY to 1 and
142
  -- the swap matrix increases of one extra column and one extra row
143
  -- (as the parity check matrix) and the extra column is not swapped.
144
  function get_form_swap_matrix (
145
    MESSAGE_LENGTH : natural;
146 4 ndesimone
    EXTRA_PARITY : natural;
147 2 ndesimone
    ONE_PARITY_BIT : boolean := false)
148
    return matrix_t is
149
 
150
    constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);
151
    constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);
152
 
153
    variable idmatrix : matrix_t(0 to BLOCK_LENGTH + EXTRA_PARITY - 1, 0 to BLOCK_LENGTH + EXTRA_PARITY - 1) := (others => (others => '0'));
154
    variable swap_matrix : matrix_t(0 to BLOCK_LENGTH + EXTRA_PARITY - 1, 0 to BLOCK_LENGTH + EXTRA_PARITY - 1); -- output
155
 
156
  begin  -- function get_systematic_swap_matrix
157
 
158
    -- Fill up the identity matrix idmatrix.  It's initialized to zeros, so
159
    -- just write ones on the diagonal.
160
    for irow in idmatrix'range(1) loop
161
      for icol in idmatrix'range(2) loop
162
        if irow = icol then
163
          idmatrix(irow, icol) := '1';
164
        end if;
165
      end loop;
166
    end loop;
167
 
168
    -- Swap columns corresponding to parity bits position in the
169
    -- parity check matrix (0, 1, 3, 7 etc...) with the right-most
170
    -- columns (starting with inner possibile rightmost).  E.g. let's
171
    -- say that, with the given message length, BLOCK_LENGTH is 7 and
172
    -- the parity bits are in positions 0, 1 and 3.  The swap will be:
173
    -- 0 <-> 5
174
    -- 1 <-> 6
175
    -- 3 <-> 7
176
    --
177
    -- Note: if EXTRA_PARITY is set, last colum is ignored because is not to be
178
    -- swapped.
179
    swap_matrix := idmatrix;
180
    for np in 0 to NPARITY_BITS-1 loop
181
      swap_cols(swap_matrix, 2**np - 1, BLOCK_LENGTH - NPARITY_BITS + np);
182
    end loop;  -- np
183
 
184
    return swap_matrix;
185
 
186
  end function get_form_swap_matrix;
187
 
188
  -- purpose: Return the result of the matrix M x vector v product.  Internal sums are
189
  -- replaced by xor operations.  E.g.:
190
  -- [1 1; 0 1] * [a; b] = [a xor b; b]
191
  -- [1 1; 0 1] * [1 1; 1 0] = [0 1; 1 0]
192
  function xor_multiply (
193
    A : matrix_t;
194
    B : matrix_t)
195
    return matrix_t is
196
 
197
    --variable y : bit_vector(A'reverse_range(1));
198
    variable y : matrix_t(A'range(1), B'range(2));
199
    variable element : bit;
200
 
201
  begin  -- function matrix_multiply
202
 
203
    --report "xor_multiply: Matrix A sized "
204
    --  & integer'image(A'length(1)) & "x" & integer'image(A'length(2))
205
    --  & ". Matrix B sized "
206
    --  & integer'image(B'length(1)) & "x" & integer'image(B'length(2)) & "."
207
    --  severity note;
208
 
209
    assert A'length(2) = B'length(1)
210
      report "Cannot multiply matrix A sized "
211
      & integer'image(A'length(1)) & "x" & integer'image(A'length(2))
212
      & " with matrix B sized "
213
      & integer'image(B'length(1)) & "x" & integer'image(B'length(2)) & "."
214
      severity error;
215
 
216
    for Arow in A'range(1) loop
217
      for Bcol in B'range(2) loop
218
 
219
        element := '0';
220
        for Acol in A'range(2) loop
221
          element := element xor (A(Arow, Acol) and B(Acol, Bcol));
222
        end loop;  -- i
223
 
224
        y(Arow, Bcol) := element;
225
 
226
        --report
227
        --  "(" & integer'image(Arow) & ", " & integer'image(Bcol) & "): " &
228
        --  "y(Arow, Bcol) :=  " & bit'image(element)
229
        --  severity note;
230
 
231
      end loop;  -- Bcol
232
 
233
      --assert false report "y(" & integer'image(y'length-Arow-1) & ") := " & bit'image(y(y'length-Arow-1)) severity note;
234
    end loop;
235
 
236
    --pretty_print_matrix(A);
237
    --pretty_print_matrix(B);    
238
    --pretty_print_matrix(y);
239
 
240
    return y;
241
 
242
  end function xor_multiply;
243
 
244
 
245
  -- purpose: Return the result of the matrix operation y = A*x using
246
  -- xor_multiply function.  See xor_multiply comment for details.
247
  function xor_multiply_vec (
248
    A : matrix_t;
249
    x : bit_vector)
250
    return bit_vector is
251
 
252
    variable B : matrix_t(x'range, 0 to 0);
253
    variable C : matrix_t(A'range(1), 0 to 0);
254
 
255
    variable y : bit_vector(A'reverse_range(1)); -- output
256
 
257
  begin  -- function matrix_multiply
258
 
259
    assert A'length(2) = x'length
260
      report "Cannot multiply matrix A sized "
261
      & integer'image(A'length(1)) & "x" & integer'image(A'length(2))
262
      & " with vector x of length "
263
      & integer'image(x'length) & "."
264
      severity error;
265
 
266
    -- Transform bit_vector x into a 1-column matrix_t.
267
    for i in x'range loop
268
      B(i, 0) := x(i);
269
    end loop;  -- i
270
 
271
    C := xor_multiply(A, B);
272
 
273
    -- Transform the 1-column matrix_t C into a bit_vector.
274
    for i in C'range(1) loop
275
      y(i) := C(i, 0);
276
    end loop;  -- i
277
 
278
    --report "xor_multiply_vec: Matrix A sized "
279
    --  & integer'image(A'length(1)) & "x" & integer'image(A'length(2))
280
    --  & ". Matrix B sized "
281
    --  & integer'image(B'length(1)) & "x" & integer'image(B'length(2)) & "."
282
    --  severity note;
283
 
284
    --pretty_print_matrix(A);
285
    --pretty_print_matrix(B);
286
    --pretty_print_matrix(C);
287
    --pretty_print_vector(y);
288
 
289
    return y;
290
 
291
  end function xor_multiply_vec;
292
 
293
  -- purpose: Generate the parity check matrix for a given message length.  The
294
  -- matrix is in non-systematic form.
295
  function get_parity_check_matrix (
296
    MESSAGE_LENGTH : natural;
297
    EXTRA_PARITY : natural range 0 to 1  := 1; -- increase hamming distance to 4
298
    ONE_PARITY_BIT : boolean := false)
299
    return matrix_t is
300
 
301
    constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);
302
    constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);
303
 
304
    variable m     : matrix_t(0 to NPARITY_BITS-1, 0 to BLOCK_LENGTH-1);
305
    variable parity, bit_pos : natural;
306
    variable ubit_pos : unsigned(BLOCK_LENGTH - 1 downto 0);
307
 
308
    -- add 1 row and 1 column respect to m to build a parity check
309
    -- matrix with extra parity bit.
310
    variable m_extra     : matrix_t(0 to m'length(1), 0 to m'length(2));
311
    variable hecol : bit_vector(m_extra'range(1));
312
 
313
  begin  -- function get_parity_check_matrix
314
 
315
    if ONE_PARITY_BIT then
316
      m := (0 => (others => '1'));
317
      return m;
318
    end if;
319
 
320
    for iparity in m'range(1) loop
321
      parity := 2**iparity;
322
 
323
      if parity >= 2 then
324
        for bit_pos in 0 to parity-2 loop
325
          m(iparity, bit_pos) := '0';
326
        end loop;
327
      end if;
328
 
329
      for bit_pos in parity-1 to m'length(2)-1 loop
330
        ubit_pos := to_unsigned(bit_pos+1, BLOCK_LENGTH);
331
 
332
        m(iparity, bit_pos) := to_bit(ubit_pos(iparity));
333
 
334
      end loop;  -- bit_pos
335
    end loop;  -- iparity
336
 
337
    if EXTRA_PARITY = 0 then
338
          return m;
339
    else
340
      -- m_extra is the parity check matrix with extra parity bits.
341
      -- It is constructed from m in 2 steps.  m_extra has an extra
342
      -- row and extra column respect to m.
343
 
344
      -- 1. copy m in m_extra.
345
      for irow in m'range(1) loop
346
        for icol in m'range(2) loop
347
          m_extra(irow, icol) := m(irow, icol);
348
        end loop;
349
      end loop;
350
 
351
      -- 2. Add extra row with '1'.
352
      for icol in m_extra'range(2) loop
353
        m_extra(m_extra'high(1), icol) := '1';
354
      end loop;
355
 
356
      return m_extra;
357
    end if;
358
 
359
  end function get_parity_check_matrix;
360
 
361
  -- purpose: Create the code generator matrix in systematic form.
362
  function get_code_generator_matrix (
363
    MESSAGE_LENGTH : natural;
364
    EXTRA_PARITY : natural range 0 to 1  := 1;  -- increase hamming ndistance to 4
365
    ONE_PARITY_BIT : boolean := false)
366
 
367
    return matrix_t is
368
 
369
    constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);
370
    constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);
371
 
372
    -- The only reason the code generator matrix is systematic is because H
373
    -- returned from get_code_generator_matrix is systematic (see
374
    -- make_systematic in code_generator_matrix).
375
    variable H    : matrix_t(0 to NPARITY_BITS + EXTRA_PARITY - 1,
376
 
377
                                                                                              EXTRA_PARITY,
378
                                                                                              ONE_PARITY_BIT);
379
 
380
    -- G is the code generator matrix.
381
    variable G : matrix_t(0 to BLOCK_LENGTH - NPARITY_BITS - 1, 0 to BLOCK_LENGTH + EXTRA_PARITY - 1);
382
    -- GT is G transposed.
383
    variable GT : matrix_t(G'range(2), G'range(1));
384
 
385
    variable gcol : bit_vector(H'range(2)); -- G matrix column
386
    variable hcol : bit_vector(H'range(1)); -- H matrix column
387
 
388
    variable swap_matrix : matrix_t(0 to BLOCK_LENGTH + EXTRA_PARITY - 1, 0 to BLOCK_LENGTH + EXTRA_PARITY - 1);
389
 
390
  begin  -- function get_code_generator_matrix
391 4 ndesimone
 
392 2 ndesimone
    -- Identity submatrix on the left (I_k)
393
    for col in 0 to BLOCK_LENGTH - NPARITY_BITS - 1 loop
394
      gcol := (others => '0');
395
      gcol(col) := '1';
396
      set_col(G, col, gcol);
397
    end loop;  -- col
398
 
399
    -- transform H in systematic form
400
    swap_matrix := get_form_swap_matrix(MESSAGE_LENGTH, EXTRA_PARITY, ONE_PARITY_BIT);
401
    H := xor_multiply(H, swap_matrix);
402
 
403
    if EXTRA_PARITY = 1 then
404
      -- This is a trick that avoids a very tedious row reduction.
405
 
406
      for icol in H'range(2) loop
407
        hcol := get_col(H, icol);
408 4 ndesimone
        if xor_reduce(hcol) = '0' then
409 2 ndesimone
          H(H'high(1), icol) := '0';
410
        end if;
411
      end loop;  -- icol
412
 
413
    end if;
414
 
415
    --pretty_print_matrix(H);
416
    --pretty_print_matrix(xor_multiply(H, swap_matrix));
417
 
418
    -- Submatrix A transposed.
419
    for col in BLOCK_LENGTH - NPARITY_BITS to BLOCK_LENGTH + EXTRA_PARITY - 1 loop
420
      for row in 0 to BLOCK_LENGTH - NPARITY_BITS - 1 loop
421
        G(row, col) := H(col-(BLOCK_LENGTH-NPARITY_BITS), row);
422
      end loop;
423
    end loop;
424
 
425
    -- transpose G
426
    for irow in G'range(1) loop
427
      for icol in G'range(2) loop
428
        GT(icol, irow) := G(irow, icol);
429
      end loop;
430
    end loop;
431
 
432
    return GT;
433
 
434
  end function get_code_generator_matrix;
435
 
436
  -- purpose: Calculate the number of parity bits (r) needed for the
437 8 ndesimone
  -- specified message length (k).  The code has k = 2^r - r - 1 for r >= 2.
438 2 ndesimone
  function calc_nparity_bits (
439
    k : natural;
440
    ONE_PARITY_BIT : boolean := false)
441
    return natural is
442
    variable r : natural := 0;
443
  begin  -- function calc_nparity_bits
444
 
445
--    assert k > 0 report "Code construction not implement for message length 0." severity failure;
446
 
447
    if ONE_PARITY_BIT then
448
      return 1;
449
    end if;
450
 
451
    r := 0;
452
    while true loop
453
      if 2**r - r - 1 >= k then
454
        return r;
455
      end if;
456
 
457
      r := r + 1;
458
    end loop;
459
 
460
    report "This should never happen." severity failure;
461
    return 0;
462
 
463
  end function calc_nparity_bits;
464
 
465
  -- purpose: Calculate the code block length n for the specified
466
  -- message length (k).  The code has n = 2^r - 1 for r >= 2.
467
  function calc_block_length (
468 4 ndesimone
    k : natural;
469 2 ndesimone
    ONE_PARITY_BIT : boolean := false)
470
    return natural is
471
    variable r : natural := 0;
472
  begin  -- function calc_nparity_bits
473
 
474
--    assert k > 0 report "Code construction not implement for message length 0." severity failure;
475
 
476
    if ONE_PARITY_BIT then
477
      return k + 1;
478
    end if;
479
 
480
    r := calc_nparity_bits(k);
481
 
482
    return 2**r - 1;
483
 
484
  end function calc_block_length;
485
 
486
  procedure check_parameters (
487
    constant BLOCK_LENGTH     : in natural;
488
    constant NPARITY_BITS     : in natural;
489
    constant MESSAGE_LENGTH   : in natural;
490
    constant EXTRA_PARITY_BIT : in natural;
491
    constant ONE_PARITY_BIT : in boolean;
492
    constant CORRECT : in boolean := false) is
493
    begin
494
      assert BLOCK_LENGTH = calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT) report "Invalid parameter value BLOCK_LENGTH := " & natural'image(BLOCK_LENGTH) severity failure;
495
      assert NPARITY_BITS = calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT) report "Invalid parameter value NPARITY_BITS := " & natural'image(NPARITY_BITS) severity failure;
496
 
497
      if ONE_PARITY_BIT then
498
        assert EXTRA_PARITY_BIT = 0 report "EXTRA_PARITY_BIT 1 is not compatible with ONE_PARITY_BIT true." severity failure;
499
        assert CORRECT = false report "CORRECT true is not compatible with ONE_PARITY_BIT true." severity failure;
500
      end if;
501
 
502
    end procedure check_parameters;
503
 
504
end package body yahamm_pkg;

powered by: WebSVN 2.1.0

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