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

Subversion Repositories yahamm

[/] [yahamm/] [trunk/] [rtl/] [vhdl/] [yahamm_pkg.vhd] - Rev 8

Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
-- Yahamm IP core
--
-- This file is part of the Yahamm project
-- http://www.opencores.org/cores/yahamm
--
-- Description
-- A hamming encoder and decoder with single-error correcting and
-- double-error detecting capability. The message length can be configured
-- through a generic. Both the code generator matrix and the parity-check
-- matrix are computed in the VHDL itself.
--
-- Author:
-- - Nicola De Simone, ndesimone@opencores.org
--
-------------------------------------------------------------------------------
--
-- Copyright (C) 2017 Authors and OPENCORES.ORG
--
-- This source file may be used and distributed without
-- restriction provided that this copyright statement is not
-- removed from the file and that any derivative work contains
-- the original copyright notice and the associated disclaimer.
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
--- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.opencores.org/lgpl.shtml
--
-------------------------------------------------------------------------------
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
use ieee.numeric_std.all;
 
library yahamm;
use yahamm.matrix_pkg.all;
 
package yahamm_pkg is
 
  component yahamm_dec is
    generic (
      MESSAGE_LENGTH   : natural;
      CORRECT          : boolean;
      EXTRA_PARITY_BIT : natural range 0 to 1;
      ONE_PARITY_BIT   : boolean;
      ERROR_LEN        : natural;
      NPARITY_BITS     : natural;
      BLOCK_LENGTH     : natural);
    port (
      clk, rst                                  : in  std_logic;
      en                                        : in  std_logic;
      din                                       : in  std_logic_vector(MESSAGE_LENGTH - 1 downto 0);
      parity                                    : in  std_logic_vector(NPARITY_BITS + EXTRA_PARITY_BIT - 1 downto 0);
      dout                                      : out std_logic_vector(MESSAGE_LENGTH - 1 downto 0);
      cnt_errors_corrected, cnt_errors_detected : out std_logic_vector(ERROR_LEN - 1 downto 0));
  end component yahamm_dec;
 
  component yahamm_enc is
    generic (
      MESSAGE_LENGTH   : natural;
      EXTRA_PARITY_BIT : natural range 0 to 1;
      ONE_PARITY_BIT   : boolean;
      NPARITY_BITS     : natural;
      BLOCK_LENGTH     : natural);
    port (
      clk, rst : in  std_logic;
      en       : in  std_logic := '1';
      din      : in  std_logic_vector(MESSAGE_LENGTH - 1 downto 0);
      dout     : out std_logic_vector(MESSAGE_LENGTH - 1 downto 0);
      parity   : out std_logic_vector(NPARITY_BITS + EXTRA_PARITY_BIT - 1 downto 0));
  end component yahamm_enc;
 
  function get_parity_check_matrix (
    MESSAGE_LENGTH : natural;
    EXTRA_PARITY : natural range 0 to 1  := 1;
    ONE_PARITY_BIT : boolean := false)
    return matrix_t;
 
  function get_code_generator_matrix (
    MESSAGE_LENGTH : natural;
    EXTRA_PARITY : natural range 0 to 1 := 1;       -- number of data (non parity) bits
    ONE_PARITY_BIT : boolean := false)
    return matrix_t;
 
  function calc_nparity_bits (
    k : natural;
    ONE_PARITY_BIT : boolean := false)
    return natural;
 
  function calc_block_length (
    k : natural;
    ONE_PARITY_BIT : boolean := false)
    return natural;
 
  procedure check_parameters (
    constant BLOCK_LENGTH     : in natural;
    constant NPARITY_BITS     : in natural;
    constant MESSAGE_LENGTH   : in natural;
    constant EXTRA_PARITY_BIT : in natural;
    constant ONE_PARITY_BIT : in boolean;
    constant CORRECT : in boolean := false
    );
 
  function xor_multiply (
    A : matrix_t;
    B : matrix_t)
    return matrix_t;
 
  function xor_multiply_vec (
    A : matrix_t;
    x : bit_vector)
    return bit_vector;
 
  function get_form_swap_matrix (
    MESSAGE_LENGTH : natural;
    EXTRA_PARITY : natural;
    ONE_PARITY_BIT : boolean := false)
    return matrix_t;
 
end package yahamm_pkg;
 
package body yahamm_pkg is
 
  -- purpose: Return a matrix S that can be used to tranform a parity
  -- check matrix or a code generator matrix M from non-systematic
  -- form to systematic form MS and viceversa (because S = S
  -- transposed = S^-1).  Use as as MS = M x S.
  -- Also works for M with extra parity bit: set EXTRA_PARITY to 1 and
  -- the swap matrix increases of one extra column and one extra row
  -- (as the parity check matrix) and the extra column is not swapped.
  function get_form_swap_matrix (
    MESSAGE_LENGTH : natural;
    EXTRA_PARITY : natural;
    ONE_PARITY_BIT : boolean := false)
    return matrix_t is
 
    constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);
    constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);    
 
    variable idmatrix : matrix_t(0 to BLOCK_LENGTH + EXTRA_PARITY - 1, 0 to BLOCK_LENGTH + EXTRA_PARITY - 1) := (others => (others => '0'));
    variable swap_matrix : matrix_t(0 to BLOCK_LENGTH + EXTRA_PARITY - 1, 0 to BLOCK_LENGTH + EXTRA_PARITY - 1); -- output
 
  begin  -- function get_systematic_swap_matrix
 
    -- Fill up the identity matrix idmatrix.  It's initialized to zeros, so
    -- just write ones on the diagonal.
    for irow in idmatrix'range(1) loop    
      for icol in idmatrix'range(2) loop
        if irow = icol then
          idmatrix(irow, icol) := '1';
        end if;
      end loop;
    end loop;
 
    -- Swap columns corresponding to parity bits position in the
    -- parity check matrix (0, 1, 3, 7 etc...) with the right-most
    -- columns (starting with inner possibile rightmost).  E.g. let's
    -- say that, with the given message length, BLOCK_LENGTH is 7 and
    -- the parity bits are in positions 0, 1 and 3.  The swap will be:
    -- 0 <-> 5
    -- 1 <-> 6
    -- 3 <-> 7
    --
    -- Note: if EXTRA_PARITY is set, last colum is ignored because is not to be
    -- swapped.
    swap_matrix := idmatrix;
    for np in 0 to NPARITY_BITS-1 loop
      swap_cols(swap_matrix, 2**np - 1, BLOCK_LENGTH - NPARITY_BITS + np);
    end loop;  -- np
 
    return swap_matrix;
 
  end function get_form_swap_matrix;
 
  -- purpose: Return the result of the matrix M x vector v product.  Internal sums are
  -- replaced by xor operations.  E.g.:
  -- [1 1; 0 1] * [a; b] = [a xor b; b]
  -- [1 1; 0 1] * [1 1; 1 0] = [0 1; 1 0]
  function xor_multiply (
    A : matrix_t;
    B : matrix_t)
    return matrix_t is
 
    --variable y : bit_vector(A'reverse_range(1));
    variable y : matrix_t(A'range(1), B'range(2));
    variable element : bit;
 
  begin  -- function matrix_multiply
 
    --report "xor_multiply: Matrix A sized "
    --  & integer'image(A'length(1)) & "x" & integer'image(A'length(2))
    --  & ". Matrix B sized "
    --  & integer'image(B'length(1)) & "x" & integer'image(B'length(2)) & "."
    --  severity note;
 
    assert A'length(2) = B'length(1)
      report "Cannot multiply matrix A sized "
      & integer'image(A'length(1)) & "x" & integer'image(A'length(2))
      & " with matrix B sized "
      & integer'image(B'length(1)) & "x" & integer'image(B'length(2)) & "."
      severity error;
 
    for Arow in A'range(1) loop
      for Bcol in B'range(2) loop
 
        element := '0';
        for Acol in A'range(2) loop
          element := element xor (A(Arow, Acol) and B(Acol, Bcol));
        end loop;  -- i
 
        y(Arow, Bcol) := element;
 
        --report
        --  "(" & integer'image(Arow) & ", " & integer'image(Bcol) & "): " &
        --  "y(Arow, Bcol) :=  " & bit'image(element)
        --  severity note;
 
      end loop;  -- Bcol
 
      --assert false report "y(" & integer'image(y'length-Arow-1) & ") := " & bit'image(y(y'length-Arow-1)) severity note;
    end loop;
 
    --pretty_print_matrix(A);
    --pretty_print_matrix(B);    
    --pretty_print_matrix(y);
 
    return y;
 
  end function xor_multiply;
 
 
  -- purpose: Return the result of the matrix operation y = A*x using
  -- xor_multiply function.  See xor_multiply comment for details.
  function xor_multiply_vec (
    A : matrix_t;
    x : bit_vector)
    return bit_vector is
 
    variable B : matrix_t(x'range, 0 to 0);
    variable C : matrix_t(A'range(1), 0 to 0);
 
    variable y : bit_vector(A'reverse_range(1)); -- output
 
  begin  -- function matrix_multiply
 
    assert A'length(2) = x'length
      report "Cannot multiply matrix A sized "
      & integer'image(A'length(1)) & "x" & integer'image(A'length(2))
      & " with vector x of length "
      & integer'image(x'length) & "."
      severity error;
 
    -- Transform bit_vector x into a 1-column matrix_t.
    for i in x'range loop
      B(i, 0) := x(i);
    end loop;  -- i
 
    C := xor_multiply(A, B);
 
    -- Transform the 1-column matrix_t C into a bit_vector.
    for i in C'range(1) loop
      y(i) := C(i, 0);      
    end loop;  -- i
 
    --report "xor_multiply_vec: Matrix A sized "
    --  & integer'image(A'length(1)) & "x" & integer'image(A'length(2))
    --  & ". Matrix B sized "
    --  & integer'image(B'length(1)) & "x" & integer'image(B'length(2)) & "."
    --  severity note;
 
    --pretty_print_matrix(A);
    --pretty_print_matrix(B);
    --pretty_print_matrix(C);
    --pretty_print_vector(y);
 
    return y;
 
  end function xor_multiply_vec;
 
  -- purpose: Generate the parity check matrix for a given message length.  The
  -- matrix is in non-systematic form.
  function get_parity_check_matrix (
    MESSAGE_LENGTH : natural;
    EXTRA_PARITY : natural range 0 to 1  := 1; -- increase hamming distance to 4
    ONE_PARITY_BIT : boolean := false)
    return matrix_t is
 
    constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);    
    constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);
 
    variable m     : matrix_t(0 to NPARITY_BITS-1, 0 to BLOCK_LENGTH-1);
    variable parity, bit_pos : natural;
    variable ubit_pos : unsigned(BLOCK_LENGTH - 1 downto 0);
 
    -- add 1 row and 1 column respect to m to build a parity check
    -- matrix with extra parity bit.
    variable m_extra     : matrix_t(0 to m'length(1), 0 to m'length(2));
    variable hecol : bit_vector(m_extra'range(1));
 
  begin  -- function get_parity_check_matrix
 
    if ONE_PARITY_BIT then
      m := (0 => (others => '1'));
      return m;
    end if;
 
    for iparity in m'range(1) loop
      parity := 2**iparity;
 
      if parity >= 2 then
        for bit_pos in 0 to parity-2 loop
          m(iparity, bit_pos) := '0';
        end loop;
      end if;
 
      for bit_pos in parity-1 to m'length(2)-1 loop
        ubit_pos := to_unsigned(bit_pos+1, BLOCK_LENGTH);
 
        m(iparity, bit_pos) := to_bit(ubit_pos(iparity));
 
      end loop;  -- bit_pos
    end loop;  -- iparity
 
    if EXTRA_PARITY = 0 then
          return m;
    else
      -- m_extra is the parity check matrix with extra parity bits.
      -- It is constructed from m in 2 steps.  m_extra has an extra
      -- row and extra column respect to m.
 
      -- 1. copy m in m_extra.
      for irow in m'range(1) loop
        for icol in m'range(2) loop
          m_extra(irow, icol) := m(irow, icol);
        end loop;
      end loop;      
 
      -- 2. Add extra row with '1'.
      for icol in m_extra'range(2) loop
        m_extra(m_extra'high(1), icol) := '1';
      end loop;
 
      return m_extra;
    end if;
 
  end function get_parity_check_matrix;
 
  -- purpose: Create the code generator matrix in systematic form.
  function get_code_generator_matrix (
    MESSAGE_LENGTH : natural;
    EXTRA_PARITY : natural range 0 to 1  := 1;  -- increase hamming ndistance to 4
    ONE_PARITY_BIT : boolean := false)
 
    return matrix_t is
 
    constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);    
    constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);    
 
    -- The only reason the code generator matrix is systematic is because H
    -- returned from get_code_generator_matrix is systematic (see
    -- make_systematic in code_generator_matrix).
    variable H    : matrix_t(0 to NPARITY_BITS + EXTRA_PARITY - 1,
                             0 to BLOCK_LENGTH + EXTRA_PARITY - 1) := get_parity_check_matrix(MESSAGE_LENGTH,
                                                                                              EXTRA_PARITY,
                                                                                              ONE_PARITY_BIT);
 
    -- G is the code generator matrix.
    variable G : matrix_t(0 to BLOCK_LENGTH - NPARITY_BITS - 1, 0 to BLOCK_LENGTH + EXTRA_PARITY - 1);
    -- GT is G transposed.
    variable GT : matrix_t(G'range(2), G'range(1));
 
    variable gcol : bit_vector(H'range(2)); -- G matrix column
    variable hcol : bit_vector(H'range(1)); -- H matrix column
 
    variable swap_matrix : matrix_t(0 to BLOCK_LENGTH + EXTRA_PARITY - 1, 0 to BLOCK_LENGTH + EXTRA_PARITY - 1);
 
  begin  -- function get_code_generator_matrix
 
    -- Identity submatrix on the left (I_k)
    for col in 0 to BLOCK_LENGTH - NPARITY_BITS - 1 loop
      gcol := (others => '0');
      gcol(col) := '1';
      set_col(G, col, gcol);
    end loop;  -- col
 
    -- transform H in systematic form
    swap_matrix := get_form_swap_matrix(MESSAGE_LENGTH, EXTRA_PARITY, ONE_PARITY_BIT);
    H := xor_multiply(H, swap_matrix);
 
    if EXTRA_PARITY = 1 then
      -- This is a trick that avoids a very tedious row reduction.
 
      for icol in H'range(2) loop
        hcol := get_col(H, icol);
        if xor_reduce(hcol) = '0' then
          H(H'high(1), icol) := '0';
        end if;
      end loop;  -- icol
 
    end if;
 
    --pretty_print_matrix(H);
    --pretty_print_matrix(xor_multiply(H, swap_matrix));
 
    -- Submatrix A transposed.
    for col in BLOCK_LENGTH - NPARITY_BITS to BLOCK_LENGTH + EXTRA_PARITY - 1 loop
      for row in 0 to BLOCK_LENGTH - NPARITY_BITS - 1 loop
        G(row, col) := H(col-(BLOCK_LENGTH-NPARITY_BITS), row);
      end loop;
    end loop;
 
    -- transpose G
    for irow in G'range(1) loop
      for icol in G'range(2) loop
        GT(icol, irow) := G(irow, icol);
      end loop;
    end loop;
 
    return GT;
 
  end function get_code_generator_matrix;
 
  -- purpose: Calculate the number of parity bits (r) needed for the
  -- specified message length (k).  The code has k = 2^r - r - 1 for r >= 2.
  function calc_nparity_bits (
    k : natural;
    ONE_PARITY_BIT : boolean := false)
    return natural is
    variable r : natural := 0;
  begin  -- function calc_nparity_bits
 
--    assert k > 0 report "Code construction not implement for message length 0." severity failure;
 
    if ONE_PARITY_BIT then
      return 1;
    end if;
 
    r := 0;
    while true loop
      if 2**r - r - 1 >= k then
        return r;
      end if;
 
      r := r + 1;
    end loop;
 
    report "This should never happen." severity failure;
    return 0;
 
  end function calc_nparity_bits;
 
  -- purpose: Calculate the code block length n for the specified
  -- message length (k).  The code has n = 2^r - 1 for r >= 2.
  function calc_block_length (
    k : natural;
    ONE_PARITY_BIT : boolean := false)
    return natural is
    variable r : natural := 0;
  begin  -- function calc_nparity_bits
 
--    assert k > 0 report "Code construction not implement for message length 0." severity failure;
 
    if ONE_PARITY_BIT then
      return k + 1;
    end if;
 
    r := calc_nparity_bits(k);
 
    return 2**r - 1;
 
  end function calc_block_length;
 
  procedure check_parameters (
    constant BLOCK_LENGTH     : in natural;
    constant NPARITY_BITS     : in natural;
    constant MESSAGE_LENGTH   : in natural;
    constant EXTRA_PARITY_BIT : in natural;
    constant ONE_PARITY_BIT : in boolean;
    constant CORRECT : in boolean := false) is
    begin
      assert BLOCK_LENGTH = calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT) report "Invalid parameter value BLOCK_LENGTH := " & natural'image(BLOCK_LENGTH) severity failure;
      assert NPARITY_BITS = calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT) report "Invalid parameter value NPARITY_BITS := " & natural'image(NPARITY_BITS) severity failure;
 
      if ONE_PARITY_BIT then
        assert EXTRA_PARITY_BIT = 0 report "EXTRA_PARITY_BIT 1 is not compatible with ONE_PARITY_BIT true." severity failure;
        assert CORRECT = false report "CORRECT true is not compatible with ONE_PARITY_BIT true." severity failure;
      end if;
 
    end procedure check_parameters;
 
end package body yahamm_pkg;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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