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

Subversion Repositories yahamm

[/] [yahamm/] [trunk/] [rtl/] [vhdl/] [yahamm_pkg.vhd] - Diff between revs 4 and 5

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 4 Rev 5
Line 1... Line 1...
 
-------------------------------------------------------------------------------
 
-- 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.
 
--
 
-- To Do:
 
-- - write docs
 
--
 
-- 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 m = 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;
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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