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

Subversion Repositories yahamm

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