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

Subversion Repositories yahamm

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /yahamm/trunk
    from Rev 4 to Rev 5
    Reverse comparison

Rev 4 → Rev 5

/yahamm_dec.vhd File deleted
/yahamm_pkg.vhd File deleted
/yahamm_enc.vhd File deleted
/matrix_pkg.vhd File deleted
/Makefile File deleted
/bench/vhdl/Makefile
0,0 → 1,33
# This Makefile requires that you have ghdl compiled with gcc backend
# (objects files *.o and executable targets don't make sense
# otherwise).
#
# Compile matrix_pkg yahamm_pkg in the main root before compiling he
# tests-benches.
 
 
VIEWER=gtkwave
LIBPREFIX=libs
 
ifndef ROOTDIR
ROOTDIR=..
endif
 
VPATH = $(ROOTDIR)/$(LIBPREFIX)/yahamm
GHDLFLAGS=--std=08 --workdir=$(ROOTDIR)/$(LIBPREFIX)/sim -P$(ROOTDIR)/$(LIBPREFIX)/yahamm --work=work
 
all: yahamm_tb0 yahamm_tb1 yahamm_tb2 yahamm_tb3
 
%: %.o
ghdl -e $(GHDLFLAGS) $@
./$@ --vcdgz=$(ROOTDIR)/$(LIBPREFIX)/sim/$@.vcdgz
 
%.o: %.vhd
mkdir -p $(ROOTDIR)/$(LIBPREFIX)/sim
ghdl -a $(GHDLFLAGS) $<
 
view:
gunzip -c $(ROOTDIR)/$(LIBPREFIX)/sim/$@.vcdgz | $(VIEWER) --vcd
 
clean:
@ghdl --remove $(GHDLFLAGS)
/bench/vhdl/yahamm_tb0.vhd
0,0 → 1,261
-------------------------------------------------------------------------------
-- 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
--
-------------------------------------------------------------------------------
 
-- Testbench with one bit parity check.
-- CORRECT false
-- EXTRA_PARITY_BIT 0
-- ONE_PARITY_BIT true
--
 
library std;
use std.env.all;
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
use ieee.numeric_std.all;
 
library yahamm;
use yahamm.yahamm_pkg.all;
use yahamm.matrix_pkg.all;
 
-------------------------------------------------------------------------------
 
entity yahamm_tb0 is
 
end entity yahamm_tb0;
 
-------------------------------------------------------------------------------
 
architecture tb of yahamm_tb0 is
 
-- component ports
signal chken, enc_en : std_logic := '1';
 
-- Cannot use here MESSAGE_LENGTH > 30 otherwise datamax overflows. This is
-- just a limitation of this testbench.
constant MESSAGE_LENGTH : natural := 30;
constant DATAMAX : natural := 2**MESSAGE_LENGTH - 1;
 
constant CORRECT : boolean := false;
constant EXTRA_PARITY_BIT : natural := 0;
 
constant ONE_PARITY_BIT : boolean := true;
constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);
constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);
constant ERROR_LEN : natural := 16;
 
constant NITERATIONS : natural := 1000; -- number of iterations for each test
signal data_enc_in, data_enc_out, data_enc_to_dec, data_dec_out : std_logic_vector(MESSAGE_LENGTH - 1 downto 0) := (others => '0');
signal
data_enc_in_q0,
data_enc_in_q1,
data_enc_in_q2 : std_logic_vector(data_enc_in'range);
signal dec_cnt_clr : std_logic; -- clear counters
signal parity_enc_to_dec : std_logic_vector(NPARITY_BITS + EXTRA_PARITY_BIT - 1 downto 0);
signal cnt_errors_corrected, cnt_errors_detected : std_logic_vector(ERROR_LEN - 1 downto 0);
 
-- clock
signal clk, rst : std_logic := '1';
 
signal wrong_bit0_position, wrong_bit1_position, wrong_bit2_position : natural := 0;
begin -- architecture tb
 
--instance "yahamm_enc_1"
yahamm_enc_1: entity yahamm.yahamm_enc
generic map (
MESSAGE_LENGTH => MESSAGE_LENGTH,
EXTRA_PARITY_BIT => EXTRA_PARITY_BIT,
ONE_PARITY_BIT => ONE_PARITY_BIT)
port map (
clk_i => clk,
rst_i => rst,
en_i => enc_en,
data_i => data_enc_in,
data_o => data_enc_out,
parity_o => parity_enc_to_dec);
 
yahamm_dec_1: entity yahamm.yahamm_dec
generic map (
MESSAGE_LENGTH => MESSAGE_LENGTH,
CORRECT => CORRECT,
EXTRA_PARITY_BIT => EXTRA_PARITY_BIT,
ONE_PARITY_BIT => ONE_PARITY_BIT,
ERROR_LEN => ERROR_LEN)
port map (
clk_i => clk,
rst_i => rst,
cnt_clr_i => dec_cnt_clr,
en_i => enc_en,
data_i => data_enc_to_dec,
parity_i => parity_enc_to_dec,
data_o => data_dec_out,
cnt_errors_corrected_o => cnt_errors_corrected,
cnt_errors_detected_o => cnt_errors_detected
);
-- clock generation
clk <= not clk after 10 ns;
 
-- purpose: delay inputs for later comparison with outputs.
delays: process (clk, rst) is
begin -- process delays
if rst = '1' then -- asynchronous reset (active high)
data_enc_in_q0 <= (others => '0');
data_enc_in_q1 <= (others => '0');
data_enc_in_q2 <= (others => '0');
elsif rising_edge(clk) then -- rising clock edge
data_enc_in_q0 <= data_enc_in;
data_enc_in_q1 <= data_enc_in_q0;
data_enc_in_q2 <= data_enc_in_q1;
end if;
end process delays;
 
-- purpose: flip bits of the decoder inputs to produce errors.
-- type : combinational
flip_bits_proc: process (data_enc_out, wrong_bit0_position, wrong_bit1_position) is
begin -- process flip_bits_proc
data_enc_to_dec <= data_enc_out;
if wrong_bit0_position > 0 then
-- flip one bit
data_enc_to_dec(wrong_bit0_position - 1) <= not data_enc_out(wrong_bit0_position - 1);
end if;
if wrong_bit1_position > 0 then
-- flit another bit (can also randomly be the same one)
data_enc_to_dec(wrong_bit1_position - 1) <= not data_enc_out(wrong_bit1_position - 1);
end if;
end process flip_bits_proc;
-- waveform generation
WaveGen_Proc: process
variable random : real;
variable seed1, seed2 : positive := 1;
variable test0_errors, test1_errors, test2_errors, test_clear : natural := 0;
begin
 
dec_cnt_clr <= '0';
rst <= '1';
wait until rising_edge(clk);
rst <= '0';
 
-- TEST #0
-- Without transmission errors.
wrong_bit0_position <= 0;
wrong_bit1_position <= 0;
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
wait until rising_edge(clk);
assert data_enc_in_q2 = data_dec_out report "Encoder input (" & to_hstring(data_enc_in_q2) & ") != decoder output (" & to_hstring(data_dec_out) & ")." severity error;
 
if data_enc_in_q2 /= data_dec_out then
test0_errors := test0_errors + 1;
end if;
end loop;
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) = 0 report "Test #0: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0." severity error;
assert to_integer(unsigned(cnt_errors_detected)) = 0 report "Test #0: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be 0." severity error;
 
-- TEST #1
-- Test the correction with 1 bit transmission error on a random bit
wrong_bit1_position <= 0;
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
-- produce an error flipping a random bit in the encoder output. 0 means
-- don't flip, so we have to add 1.
uniform(seed1, seed2, random);
wrong_bit0_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
 
if data_enc_in_q2 /= data_dec_out then
test1_errors := test1_errors + 1;
end if;
wait until rising_edge(clk);
end loop;
wrong_bit0_position <= 0;
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) = 0 report "Test #1: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0." severity error;
assert to_integer(unsigned(cnt_errors_detected)) > 0 report "Test #1: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be > 0." severity error;
 
-- clear decoder counters
dec_cnt_clr <= '1';
wait until rising_edge(clk);
dec_cnt_clr <= '0';
wait until rising_edge(clk);
-- check the clear
if to_integer(unsigned(cnt_errors_corrected)) /= 0 then
report "Unexepcted cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0 after clear." severity error;
test_clear := 1;
end if;
if to_integer(unsigned(cnt_errors_detected)) /= 0 then
report "Unexepcted cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be 0 after clear." severity error;
test_clear := 1;
end if;
assert test0_errors = 0 and test1_errors > 0 and test_clear = 0 report "TB0 unsuccessful." severity failure;
 
assert false report "OK" severity note;
stop(0);
 
end process WaveGen_Proc;
 
end architecture tb;
/bench/vhdl/yahamm_tb1.vhd
0,0 → 1,279
-------------------------------------------------------------------------------
-- 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
--
-------------------------------------------------------------------------------
 
-- Testbench with Single Error Corrected.
-- CORRECT true
-- EXTRA_PARITY_BIT 0
-- ONE_PARITY_BIT false
--
 
library std;
use std.env.all;
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
use ieee.numeric_std.all;
 
library yahamm;
use yahamm.yahamm_pkg.all;
use yahamm.matrix_pkg.all;
 
-------------------------------------------------------------------------------
 
entity yahamm_tb1 is
 
end entity yahamm_tb1;
 
-------------------------------------------------------------------------------
 
architecture tb of yahamm_tb1 is
 
-- component ports
signal chken, enc_en : std_logic := '1';
 
-- Cannot use here MESSAGE_LENGTH > 30 otherwise datamax overflows. This is
-- just a limitation of this testbench.
constant MESSAGE_LENGTH : natural := 30;
constant DATAMAX : natural := 2**MESSAGE_LENGTH - 1;
 
constant CORRECT : boolean := true;
constant EXTRA_PARITY_BIT : natural := 0;
 
constant ONE_PARITY_BIT : boolean := false;
 
constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);
constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);
constant ERROR_LEN : natural := 16;
 
constant NITERATIONS : natural := 1000; -- number of iterations for each test
 
signal data_enc_in, data_enc_out, data_enc_to_dec, data_dec_out : std_logic_vector(MESSAGE_LENGTH - 1 downto 0) := (others => '0');
signal
data_enc_in_q0,
data_enc_in_q1,
data_enc_in_q2 : std_logic_vector(data_enc_in'range);
signal dec_cnt_clr : std_logic; -- clear counters
signal parity_enc_to_dec : std_logic_vector(NPARITY_BITS + EXTRA_PARITY_BIT - 1 downto 0);
signal cnt_errors_corrected, cnt_errors_detected : std_logic_vector(ERROR_LEN - 1 downto 0);
 
-- clock
signal clk, rst : std_logic := '1';
 
signal wrong_bit0_position, wrong_bit1_position, wrong_bit2_position : natural := 0;
 
begin -- architecture tb
 
--instance "yahamm_enc_1"
yahamm_enc_1 : entity yahamm.yahamm_enc
generic map (
MESSAGE_LENGTH => MESSAGE_LENGTH,
EXTRA_PARITY_BIT => EXTRA_PARITY_BIT,
ONE_PARITY_BIT => ONE_PARITY_BIT)
port map (
clk_i => clk,
rst_i => rst,
en_i => enc_en,
data_i => data_enc_in,
data_o => data_enc_out,
parity_o => parity_enc_to_dec);
 
yahamm_dec_1 : entity yahamm.yahamm_dec
generic map (
MESSAGE_LENGTH => MESSAGE_LENGTH,
CORRECT => CORRECT,
EXTRA_PARITY_BIT => EXTRA_PARITY_BIT,
ONE_PARITY_BIT => ONE_PARITY_BIT,
ERROR_LEN => ERROR_LEN)
port map (
clk_i => clk,
rst_i => rst,
cnt_clr_i => dec_cnt_clr,
en_i => enc_en,
data_i => data_enc_to_dec,
parity_i => parity_enc_to_dec,
data_o => data_dec_out,
cnt_errors_corrected_o => cnt_errors_corrected,
cnt_errors_detected_o => cnt_errors_detected
);
 
-- clock generation
clk <= not clk after 10 ns;
 
-- purpose: delay inputs for later comparison with outputs.
delays : process (clk, rst) is
begin -- process delays
if rst = '1' then -- asynchronous reset (active high)
data_enc_in_q0 <= (others => '0');
data_enc_in_q1 <= (others => '0');
data_enc_in_q2 <= (others => '0');
elsif rising_edge(clk) then -- rising clock edge
data_enc_in_q0 <= data_enc_in;
data_enc_in_q1 <= data_enc_in_q0;
data_enc_in_q2 <= data_enc_in_q1;
end if;
end process delays;
 
-- purpose: flit bits of the decoder inputs to produce errors.
-- type : combinational
flip_bits_proc : process (data_enc_out, wrong_bit0_position, wrong_bit1_position) is
begin -- process flip_bits_proc
data_enc_to_dec <= data_enc_out;
 
if wrong_bit0_position > 0 then
-- flip one bit
data_enc_to_dec(wrong_bit0_position - 1) <= not data_enc_out(wrong_bit0_position - 1);
end if;
 
if wrong_bit1_position > 0 then
-- flit another bit (can also randomly be the same one)
data_enc_to_dec(wrong_bit1_position - 1) <= not data_enc_out(wrong_bit1_position - 1);
end if;
end process flip_bits_proc;
 
-- waveform generation
WaveGen_Proc : process
variable random : real;
variable seed1, seed2 : positive := 1;
variable test0_errors, test1_errors, test2_errors, test_clear : natural := 0;
begin
 
dec_cnt_clr <= '0';
rst <= '1';
wait until rising_edge(clk);
rst <= '0';
 
-- TEST #0
-- Without transmission errors.
wrong_bit0_position <= 0;
wrong_bit1_position <= 0;
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
 
wait until rising_edge(clk);
assert data_enc_in_q2 = data_dec_out report "Test #0: Encoder input (" & to_hstring(data_enc_in_q2) & ") != decoder output (" & to_hstring(data_dec_out) & ")." severity error;
 
if data_enc_in_q2 /= data_dec_out then
test0_errors := test0_errors + 1;
end if;
 
end loop;
 
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) = 0 report "Test #0: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0." severity error;
assert to_integer(unsigned(cnt_errors_detected)) = 0 report "Test #0: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be 0." severity error;
 
-- TEST #1
-- Test the correction with 1 bit transmission error on a random bit
wrong_bit1_position <= 0;
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
 
-- produce an error flipping a random bit in the encoder output. 0 means
-- don't flip, so we have to add 1.
uniform(seed1, seed2, random);
wrong_bit0_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
 
assert data_enc_in_q2 = data_dec_out report "Test #1: Encoder input (" & to_hstring(data_enc_in_q2) & ") != decoder output (" & to_hstring(data_dec_out) & ")." severity error;
 
if data_enc_in_q2 /= data_dec_out then
test1_errors := test1_errors + 1;
end if;
 
wait until rising_edge(clk);
end loop;
 
wrong_bit0_position <= 0;
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) = NITERATIONS report "Test #1: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be " & integer'image(NITERATIONS) severity error;
assert to_integer(unsigned(cnt_errors_detected)) = 0 report "Test #1: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be 0." severity error;
 
-- clear decoder counters
dec_cnt_clr <= '1';
wait until rising_edge(clk);
dec_cnt_clr <= '0';
wait until rising_edge(clk);
 
-- check the clear
if to_integer(unsigned(cnt_errors_corrected)) /= 0 then
report "Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0 after clear." severity error;
test_clear := 1;
end if;
 
-- TEST #2
-- Test the non working correction with 2 bit transmission error.
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
 
-- produce an error flipping a random bit in the encoder output. 0 means
-- don't flip, so we have to add 1.
uniform(seed1, seed2, random);
wrong_bit0_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
uniform(seed1, seed2, random);
wrong_bit1_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
 
if data_enc_in_q2 /= data_dec_out then
test2_errors := test2_errors + 1;
end if;
 
wait until rising_edge(clk);
end loop;
 
assert test0_errors = 0 and test1_errors = 0 and test2_errors > 0 and test_clear = 0 report "Test #2: TB1 unsuccessful." severity failure;
 
assert false report "OK" severity note;
stop(0);
 
end process WaveGen_Proc;
 
 
end architecture tb;
/bench/vhdl/yahamm_tb2.vhd
0,0 → 1,306
-------------------------------------------------------------------------------
-- 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
--
-------------------------------------------------------------------------------
 
-- Testbench with Single Error Corrected, Double Error Detected
-- CORRECT true
-- EXTRA_PARITY_BIT 1
-- ONE_PARITY_BIT false
--
 
library std;
use std.env.all;
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
use ieee.numeric_std.all;
 
library yahamm;
use yahamm.yahamm_pkg.all;
use yahamm.matrix_pkg.all;
 
-------------------------------------------------------------------------------
 
entity yahamm_tb2 is
 
end entity yahamm_tb2;
 
-------------------------------------------------------------------------------
 
architecture tb of yahamm_tb2 is
 
-- component ports
signal chken, enc_en : std_logic := '1';
 
-- Cannot use here MESSAGE_LENGTH > 30 otherwise datamax overflows. This is
-- just a limitation of this testbench.
constant MESSAGE_LENGTH : natural := 3;
constant DATAMAX : natural := 2**MESSAGE_LENGTH - 1;
 
constant CORRECT : boolean := true;
constant EXTRA_PARITY_BIT : natural := 1;
 
constant ONE_PARITY_BIT : boolean := false;
 
constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);
constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);
constant ERROR_LEN : natural := 16;
 
constant NITERATIONS : natural := 1000; -- number of iterations for each test
 
signal data_enc_in, data_enc_out, data_enc_to_dec, data_dec_out : std_logic_vector(MESSAGE_LENGTH - 1 downto 0) := (others => '0');
signal
data_enc_in_q0,
data_enc_in_q1,
data_enc_in_q2 : std_logic_vector(data_enc_in'range);
signal dec_cnt_clr : std_logic; -- clear counters
signal parity_enc_out, parity_enc_to_dec : std_logic_vector(NPARITY_BITS + EXTRA_PARITY_BIT - 1 downto 0);
signal cnt_errors_corrected, cnt_errors_detected : std_logic_vector(ERROR_LEN - 1 downto 0);
 
-- clock
signal clk, rst : std_logic := '1';
 
signal wrong_bit0_data_position, wrong_bit1_data_position : natural := 0;
signal wrong_bit0_parity_position, wrong_bit1_parity_position : natural := 0;
 
begin -- architecture tb
 
--instance "yahamm_enc_1"
yahamm_enc_1 : entity yahamm.yahamm_enc
generic map (
MESSAGE_LENGTH => MESSAGE_LENGTH,
EXTRA_PARITY_BIT => EXTRA_PARITY_BIT,
ONE_PARITY_BIT => ONE_PARITY_BIT)
port map (
clk_i => clk,
rst_i => rst,
en_i => enc_en,
data_i => data_enc_in,
data_o => data_enc_out,
parity_o => parity_enc_out);
 
yahamm_dec_1 : entity yahamm.yahamm_dec
generic map (
MESSAGE_LENGTH => MESSAGE_LENGTH,
CORRECT => CORRECT,
EXTRA_PARITY_BIT => EXTRA_PARITY_BIT,
ONE_PARITY_BIT => ONE_PARITY_BIT,
ERROR_LEN => ERROR_LEN)
port map (
clk_i => clk,
rst_i => rst,
cnt_clr_i => dec_cnt_clr,
en_i => enc_en,
data_i => data_enc_to_dec,
parity_i => parity_enc_to_dec,
data_o => data_dec_out,
cnt_errors_corrected_o => cnt_errors_corrected,
cnt_errors_detected_o => cnt_errors_detected
);
 
-- clock generation
clk <= not clk after 10 ns;
 
-- purpose: delay inputs for later comparison with outputs.
delays : process (clk, rst) is
begin -- process delays
if rst = '1' then -- asynchronous reset (active high)
data_enc_in_q0 <= (others => '0');
data_enc_in_q1 <= (others => '0');
data_enc_in_q2 <= (others => '0');
elsif rising_edge(clk) then -- rising clock edge
data_enc_in_q0 <= data_enc_in;
data_enc_in_q1 <= data_enc_in_q0;
data_enc_in_q2 <= data_enc_in_q1;
end if;
end process delays;
 
-- purpose: flit bits of the decoder inputs to produce errors.
-- type : combinational
flip_bits_proc : process (data_enc_out,
wrong_bit0_data_position, wrong_bit1_data_position,
wrong_bit0_parity_position, wrong_bit1_parity_position) is
begin -- process flip_bits_proc
data_enc_to_dec <= data_enc_out;
parity_enc_to_dec <= parity_enc_out;
 
if wrong_bit0_data_position > 0 then
-- flip one bit
data_enc_to_dec(wrong_bit0_data_position - 1) <= not data_enc_out(wrong_bit0_data_position - 1);
end if;
 
if wrong_bit1_data_position > 0 then
-- flip another bit (it can also randomly be the same one)
data_enc_to_dec(wrong_bit1_data_position - 1) <= not data_enc_out(wrong_bit1_data_position - 1);
end if;
 
if wrong_bit0_parity_position > 0 then
-- flip one bit
parity_enc_to_dec(wrong_bit0_parity_position - 1) <= not parity_enc_out(wrong_bit0_parity_position - 1);
end if;
 
if wrong_bit1_parity_position > 0 then
-- flip another bit (it can also randomly be the same one)
parity_enc_to_dec(wrong_bit1_parity_position - 1) <= not parity_enc_out(wrong_bit1_parity_position - 1);
end if;
 
end process flip_bits_proc;
 
-- waveform generation
WaveGen_Proc : process
variable random : real;
variable seed1, seed2 : positive := 1;
variable test0_errors, test1_errors, test2_errors, test_clear : natural := 0;
begin
 
dec_cnt_clr <= '0';
rst <= '1';
wait until rising_edge(clk);
rst <= '0';
 
-- TEST #0
-- Without transmission errors.
wrong_bit0_data_position <= 0;
wrong_bit1_data_position <= 0;
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
 
wait until rising_edge(clk);
assert data_enc_in_q2 = data_dec_out report "Test #0: Encoder input (" & to_hstring(data_enc_in_q2) & ") != decoder output (" & to_hstring(data_dec_out) & ")." severity error;
 
if data_enc_in_q2 /= data_dec_out then
test0_errors := test0_errors + 1;
end if;
 
end loop;
 
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) = 0 report "Test #0: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0." severity error;
assert to_integer(unsigned(cnt_errors_detected)) = 0 report "Test #0: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be 0." severity error;
 
-- TEST #1
-- Test the correction with 1 bit transmission error on a random bit
wrong_bit1_data_position <= 0;
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
 
-- produce an error flipping a random bit in the encoder output. 0 means
-- don't flip, so we have to add 1.
uniform(seed1, seed2, random);
wrong_bit0_data_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
 
assert data_enc_in_q2 = data_dec_out report "Test #1: Encoder input (" & to_hstring(data_enc_in_q2) & ") != decoder output (" & to_hstring(data_dec_out) & ")." severity error;
 
if data_enc_in_q2 /= data_dec_out then
test1_errors := test1_errors + 1;
end if;
 
wait until rising_edge(clk);
end loop;
 
wrong_bit0_data_position <= 0;
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) = NITERATIONS report "Test #1: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be " & integer'image(NITERATIONS) severity error;
assert to_integer(unsigned(cnt_errors_detected)) = 0 report "Test #1: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be 0." severity error;
 
-- TEST #2
-- Test the non working correction with 2 bit transmission error.
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
 
-- produce an error flipping a random bit in the encoder output. 0 means
-- don't flip, so we have to add 1.
uniform(seed1, seed2, random);
wrong_bit0_data_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
uniform(seed1, seed2, random);
wrong_bit1_data_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
 
if data_enc_in_q2 /= data_dec_out then
test2_errors := test2_errors + 1;
end if;
 
wait until rising_edge(clk);
end loop;
 
wrong_bit0_data_position <= 0;
wrong_bit1_data_position <= 0;
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) > 0 report "Test #2: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be > 0." severity error;
assert to_integer(unsigned(cnt_errors_detected)) > 0 report "Test #2: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be > 0." severity error;
 
-- clear decoder counters
dec_cnt_clr <= '1';
wait until rising_edge(clk);
dec_cnt_clr <= '0';
wait until rising_edge(clk);
 
-- check the clear
if to_integer(unsigned(cnt_errors_corrected)) /= 0 then
report "Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0 after clear." severity error;
test_clear := 1;
end if;
if to_integer(unsigned(cnt_errors_detected)) /= 0 then
report "Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be 0 after clear." severity error;
test_clear := 1;
end if;
 
assert test0_errors = 0 and test1_errors = 0 and test2_errors > 0 and test_clear = 0 report "TB2 unsuccessful." severity failure;
 
assert false report "OK" severity note;
stop(0);
 
end process WaveGen_Proc;
 
 
end architecture tb;
/bench/vhdl/yahamm_tb3.vhd
0,0 → 1,339
-------------------------------------------------------------------------------
-- 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
--
-------------------------------------------------------------------------------
 
-- Testbench with Triple Error Detected
-- CORRECT false
-- EXTRA_PARITY_BIT 1
-- ONE_PARITY_BIT false
--
 
library std;
use std.env.all;
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
use ieee.numeric_std.all;
 
library yahamm;
use yahamm.yahamm_pkg.all;
use yahamm.matrix_pkg.all;
 
-------------------------------------------------------------------------------
 
entity yahamm_tb3 is
 
end entity yahamm_tb3;
 
-------------------------------------------------------------------------------
 
architecture tb of yahamm_tb3 is
 
-- component ports
signal chken, enc_en : std_logic := '1';
 
-- Cannot use here MESSAGE_LENGTH > 30 otherwise datamax overflows. This is
-- just a limitation of this testbench.
constant MESSAGE_LENGTH : natural := 30;
constant DATAMAX : natural := 2**MESSAGE_LENGTH - 1;
 
constant CORRECT : boolean := false;
constant EXTRA_PARITY_BIT : natural := 1;
 
constant ONE_PARITY_BIT : boolean := false;
 
constant NPARITY_BITS : natural := calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT);
constant BLOCK_LENGTH : natural := calc_block_length(MESSAGE_LENGTH, ONE_PARITY_BIT);
constant ERROR_LEN : natural := 16;
 
constant NITERATIONS : natural := 1000; -- number of iterations for each test
 
signal data_enc_in, data_enc_out, data_enc_to_dec, data_dec_out : std_logic_vector(MESSAGE_LENGTH - 1 downto 0) := (others => '0');
signal
data_enc_in_q0,
data_enc_in_q1,
data_enc_in_q2 : std_logic_vector(data_enc_in'range);
signal dec_cnt_clr : std_logic; -- clear counters
signal parity_enc_to_dec : std_logic_vector(NPARITY_BITS + EXTRA_PARITY_BIT - 1 downto 0);
signal cnt_errors_corrected, cnt_errors_detected : std_logic_vector(ERROR_LEN - 1 downto 0);
 
-- clock
signal clk, rst : std_logic := '1';
 
signal wrong_bit0_position, wrong_bit1_position, wrong_bit2_position : natural := 0;
 
begin -- architecture tb
 
--instance "yahamm_enc_1"
yahamm_enc_1 : entity yahamm.yahamm_enc
generic map (
MESSAGE_LENGTH => MESSAGE_LENGTH,
EXTRA_PARITY_BIT => EXTRA_PARITY_BIT,
ONE_PARITY_BIT => ONE_PARITY_BIT)
port map (
clk_i => clk,
rst_i => rst,
en_i => enc_en,
data_i => data_enc_in,
data_o => data_enc_out,
parity_o => parity_enc_to_dec);
 
yahamm_dec_1 : entity yahamm.yahamm_dec
generic map (
MESSAGE_LENGTH => MESSAGE_LENGTH,
CORRECT => CORRECT,
EXTRA_PARITY_BIT => EXTRA_PARITY_BIT,
ONE_PARITY_BIT => ONE_PARITY_BIT,
ERROR_LEN => ERROR_LEN)
port map (
clk_i => clk,
rst_i => rst,
cnt_clr_i => dec_cnt_clr,
en_i => enc_en,
data_i => data_enc_to_dec,
parity_i => parity_enc_to_dec,
data_o => data_dec_out,
cnt_errors_corrected_o => cnt_errors_corrected,
cnt_errors_detected_o => cnt_errors_detected
);
 
-- clock generation
clk <= not clk after 10 ns;
 
-- purpose: delay inputs for later comparison with outputs.
delays : process (clk, rst) is
begin -- process delays
if rst = '1' then -- asynchronous reset (active high)
data_enc_in_q0 <= (others => '0');
data_enc_in_q1 <= (others => '0');
data_enc_in_q2 <= (others => '0');
elsif rising_edge(clk) then -- rising clock edge
data_enc_in_q0 <= data_enc_in;
data_enc_in_q1 <= data_enc_in_q0;
data_enc_in_q2 <= data_enc_in_q1;
end if;
end process delays;
 
-- purpose: flit bits of the decoder inputs to produce errors.
-- type : combinational
flip_bits_proc : process (data_enc_out, wrong_bit0_position, wrong_bit1_position) is
begin -- process flip_bits_proc
data_enc_to_dec <= data_enc_out;
 
if wrong_bit0_position > 0 then
-- flip one bit
data_enc_to_dec(wrong_bit0_position - 1) <= not data_enc_out(wrong_bit0_position - 1);
end if;
 
if wrong_bit1_position > 0 then
-- flit another bit (can also randomly be the same one)
data_enc_to_dec(wrong_bit1_position - 1) <= not data_enc_out(wrong_bit1_position - 1);
end if;
 
if wrong_bit2_position > 0 then
-- flit another bit (can also randomly be the same one)
data_enc_to_dec(wrong_bit2_position - 1) <= not data_enc_out(wrong_bit2_position - 1);
end if;
end process flip_bits_proc;
 
-- waveform generation
WaveGen_Proc : process
variable random : real;
variable seed1, seed2 : positive := 1;
variable test0_errors, test1_errors, test2_errors, test3_errors, test_clear : natural := 0;
begin
 
dec_cnt_clr <= '0';
rst <= '1';
wait until rising_edge(clk);
rst <= '0';
 
-- TEST #0
-- Without transmission errors.
wrong_bit0_position <= 0;
wrong_bit1_position <= 0;
wrong_bit2_position <= 0;
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
 
wait until rising_edge(clk);
assert data_enc_in_q2 = data_dec_out report "Test #0: Encoder input (" & to_hstring(data_enc_in_q2) & ") != decoder output (" & to_hstring(data_dec_out) & ")." severity error;
 
if data_enc_in_q2 /= data_dec_out then
test0_errors := test0_errors + 1;
end if;
 
end loop;
 
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) = 0 report "Test #0: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0." severity error;
assert to_integer(unsigned(cnt_errors_detected)) = 0 report "Test #0: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be 0." severity error;
 
-- TEST #1
-- Test the correction with 1 bit transmission error on a random bit
wrong_bit1_position <= 0;
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
 
-- produce an error flipping a random bit in the encoder output. 0 means
-- don't flip, so we have to add 1.
uniform(seed1, seed2, random);
wrong_bit0_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
 
if data_enc_in_q2 /= data_dec_out then
test1_errors := test1_errors + 1;
end if;
 
wait until rising_edge(clk);
end loop;
 
wrong_bit0_position <= 0;
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) = 0 report "Test #1: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0." severity error;
assert to_integer(unsigned(cnt_errors_detected)) = NITERATIONS report "Test #1: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be " & integer'image(NITERATIONS) & "." severity error;
 
-- clear decoder counters
dec_cnt_clr <= '1';
wait until rising_edge(clk);
dec_cnt_clr <= '0';
wait until rising_edge(clk);
 
-- TEST #2
-- Test the correction with 2 bit transmission error on random bits
wrong_bit2_position <= 0;
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
 
-- produce 2 errors flipping random bits in the encoder output. 0 means
-- don't flip, so we have to add 1.
uniform(seed1, seed2, random);
wrong_bit0_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
uniform(seed1, seed2, random);
wrong_bit1_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
 
if data_enc_in_q2 /= data_dec_out then
test2_errors := test2_errors + 1;
end if;
 
wait until rising_edge(clk);
end loop;
 
wrong_bit0_position <= 0;
wrong_bit1_position <= 0;
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) = 0 report "Test #2: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0." severity error;
assert to_integer(unsigned(cnt_errors_detected)) = NITERATIONS report "Test #2: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be " & integer'image(NITERATIONS) & "." severity error;
 
-- clear decoder counters
dec_cnt_clr <= '1';
wait until rising_edge(clk);
dec_cnt_clr <= '0';
wait until rising_edge(clk);
 
-- TEST #3
-- Test the correction with 3 bit transmission error on random bits
for itest in 0 to NITERATIONS-1 loop
uniform(seed1, seed2, random);
data_enc_in <= std_logic_vector(to_unsigned(integer(round(random*real(DATAMAX))), MESSAGE_LENGTH));
 
-- produce 3 errors flipping random bits in the encoder output. 0 means
-- don't flip, so we have to add 1.
uniform(seed1, seed2, random);
wrong_bit0_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
uniform(seed1, seed2, random);
wrong_bit1_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
uniform(seed1, seed2, random);
wrong_bit2_position <= natural(trunc(random*real(MESSAGE_LENGTH))) + 1;
 
if data_enc_in_q2 /= data_dec_out then
test3_errors := test3_errors + 1;
end if;
 
wait until rising_edge(clk);
end loop;
 
wrong_bit0_position <= 0;
wrong_bit1_position <= 0;
wrong_bit2_position <= 0;
wait until rising_edge(clk);
wait until rising_edge(clk);
 
assert to_integer(unsigned(cnt_errors_corrected)) = 0 report "Test #3: Unexpected cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0." severity error;
assert to_integer(unsigned(cnt_errors_detected)) = NITERATIONS report "Test #3: Unexpected cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be " & integer'image(NITERATIONS) & "." severity error;
 
-- clear decoder counters
dec_cnt_clr <= '1';
wait until rising_edge(clk);
dec_cnt_clr <= '0';
wait until rising_edge(clk);
 
-- check the clear
if to_integer(unsigned(cnt_errors_corrected)) /= 0 then
report "Unexepcted cnt_errors_corrected " & integer'image(to_integer(unsigned(cnt_errors_corrected))) & ". Should be 0 after clear." severity error;
test_clear := 1;
end if;
if to_integer(unsigned(cnt_errors_detected)) /= 0 then
report "Unexepcted cnt_errors_detected " & integer'image(to_integer(unsigned(cnt_errors_detected))) & ". Should be 0 after clear." severity error;
test_clear := 1;
end if;
 
assert test0_errors = 0 and test1_errors > 0 and test2_errors > 0 and test3_errors > 0 and test_clear = 0 report "TB2 unsuccessful." severity failure;
 
assert false report "OK" severity note;
stop(0);
 
end process WaveGen_Proc;
 
 
end architecture tb;
/rtl/vhdl/Makefile
0,0 → 1,26
# This Makefile requires that you have ghdl compiled with gcc backend
# (objects files *.o and executable targets don't make sense
# otherwise).
 
LIBPREFIX=libs
VPATH = $(LIBPREFIX)/yahamm
 
GHDLFLAGS=--std=08 --workdir=$(LIBPREFIX)/yahamm --work=yahamm
 
all: yahamm_enc.o yahamm_dec.o
 
 
yahamm_dec: matrix_pkg.o yahamm_pkg.o
yahamm_enc: matrix_pkg.o yahamm_pkg.o
 
%: %.o
ghdl -e $(GHDLFLAGS) $@
 
%.o: %.vhd
@mkdir -p $(LIBPREFIX)/yahamm
ghdl -a $(GHDLFLAGS) $<
 
clean:
ghdl --remove $(GHDLFLAGS)
 
.PHONY: sim
/rtl/vhdl/matrix_pkg.vhd
0,0 → 1,273
-------------------------------------------------------------------------------
-- 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 std.textio.all;
 
--library ieee_proposed;
--use ieee_proposed.std_logic_1164_additions.all;
--use ieee_proposed.standard_additions.all;
---- pragma synthesis_off
--use ieee_proposed.standard_textio_additions.all;
---- pragma synthesis_on
 
package matrix_pkg is
 
-----------------------------------------------------------------------------
-- Here 2D arrays are used to implement matrices. There are various
-- limitations to the use of 2D arrays (e.g. limited easy slicing)
-- that would maybe suggest an implementation with 1Dx1D matrices.
-- But anyway this would make easy slicing either rows or columns
-- but not both. The approach used here is implementing functions
-- to handle various matrix operations. Having a 2D type allows to
-- use one type definition for any matrix.
-----------------------------------------------------------------------------
 
type matrix_t is array (integer range <>, integer range<>) of bit;
 
function get_row (
constant matrix : matrix_t;
constant row : natural)
return bit_vector;
 
function get_col (
constant matrix : matrix_t;
constant col : natural)
return bit_vector;
 
procedure set_col (
variable M : inout matrix_t;
constant icol : natural;
constant col : bit_vector);
 
-- pragma synthesis_off
procedure pretty_print_matrix (
constant matrix : in matrix_t);
 
procedure pretty_print_vector (
constant vin : in bit_vector);
-- pragma synthesis_on
 
function find_col (
constant M : matrix_t;
constant col : bit_vector)
return integer;
 
procedure swap_cols (
variable M : inout matrix_t;
constant icol1, icol2 : in natural);
 
function and_reduce (L : BIT_VECTOR) return BIT;
function or_reduce (L : BIT_VECTOR) return BIT;
function xor_reduce (L : BIT_VECTOR) return BIT;
 
end package matrix_pkg;
 
package body matrix_pkg is
 
-- purpose: Return matrix M with columns at positions col1 and col2
-- swapped.
procedure swap_cols (
variable M : inout matrix_t;
constant icol1, icol2 : in natural) is
variable col1, col2 : bit_vector(M'range(1));
variable Mout : matrix_t(M'range(1), M'range(2));
begin
col1 := get_col(M, icol1);
col2 := get_col(M, icol2);
set_col(M, icol1, col2);
set_col(M, icol2, col1);
end procedure swap_cols;
-- purpose: Return the matrix row.
function get_row (
constant matrix : matrix_t;
constant row : natural)
return bit_vector is
variable y : bit_vector(matrix'range(2));
begin -- function get_row
 
for col in matrix'range(2) loop
y(col) := matrix(row, col);
end loop; -- irow
 
return y;
end function get_row;
 
-- purpose: Return the matrix col.
function get_col (
constant matrix : matrix_t;
constant col : natural)
return bit_vector is
variable y : bit_vector(matrix'range(1));
begin -- function get_col
 
for row in matrix'range(1) loop
y(row) := matrix(row, col);
end loop; -- irow
 
return y;
end function get_col;
 
-- purpose: Set the matrix column icol to col.
procedure set_col (
variable M : inout matrix_t;
constant icol : natural;
constant col : bit_vector) is
begin -- function get_col
for row in M'range(1) loop
M(row, icol) := col(row);
end loop; -- irow
 
end procedure set_col;
 
-- pragma synthesis_off
-- purpose: Print out matrix for debugging.
procedure pretty_print_matrix (
constant matrix : in matrix_t) is
variable l : line;
 
begin -- procedure pretty_print_matrix
 
for row in matrix'range(1) loop
 
for col in matrix'range(2) loop
write(l, matrix(row, col));
swrite(l, " ");
end loop; -- col
 
writeline(output, l);
end loop; -- row
 
writeline(output, l); -- blank line
 
end procedure pretty_print_matrix;
 
-- purpose: Print out vector for debugging.
procedure pretty_print_vector (
constant vin : in bit_vector) is
variable l : line;
 
begin -- procedure pretty_print_matrix
 
swrite(l, integer'image(vin'left));
swrite(l, " to/downto ");
swrite(l, integer'image(vin'right));
swrite(l, ": ");
for i in vin'range loop
write(l, vin(i));
swrite(l, " ");
end loop; -- i
 
writeline(output, l);
writeline(output, l); -- blank line
 
end procedure pretty_print_vector;
 
-- pragma synthesis_on
-- purpose: Return the position of col in M or -1 if not found.
function find_col (
constant M : matrix_t; -- Any matrix
constant col : bit_vector) -- The column to find
return integer is
variable match : boolean;
begin -- function find_col
for icol in M'range(2) loop
match := true;
for j in col'range loop
if col(j) /= M(j, icol) then
match := false;
end if;
end loop;
 
if match then
return icol;
end if;
end loop;
 
-- not found
return -1;
end function find_col;
function and_reduce (L : BIT_VECTOR) return BIT is
variable result : BIT := '1';
begin
for i in l'reverse_range loop
result := l(i) and result;
end loop;
return result;
end function and_reduce;
 
function or_reduce (L : BIT_VECTOR) return BIT is
variable result : BIT := '0';
begin
for i in l'reverse_range loop
result := l(i) or result;
end loop;
return result;
end function or_reduce;
function xor_reduce (L : BIT_VECTOR) return BIT is
variable result : BIT := '0';
begin
for i in l'reverse_range loop
result := l(i) xor result;
end loop;
return result;
end function xor_reduce;
 
end package body matrix_pkg;
/rtl/vhdl/yahamm_dec.vhd
0,0 → 1,324
-------------------------------------------------------------------------------
-- 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.numeric_std.all;
 
library yahamm;
use yahamm.matrix_pkg.all;
use yahamm.yahamm_pkg.all;
 
library std;
use std.textio.all;
 
-- There are two monitor counters:
--
-- cnt_errors_corrected: number of error correction performed.
-- cnt_errors_detected: numbers of errors detected but not corrected.
--
-- The two never count together and they don't overflow. If CORRECT
-- is false, no correction is performed cnt_errors_corrected never counts.
-- If CORRECT is true and EXTRA_PARITY_BIT is true, cnt_errors_detected
-- never counts because all errors (supposedly single-bit errors) are
-- corrected.
--
-- ERROR_LEN: width of the cnt_errors_corrected and cnt_errors_detected counters.
--
-- dout_valid_o: dout data valid, it's the en input pipelined. It takes into
-- account the total latency.
--
entity yahamm_dec is
generic (
MESSAGE_LENGTH : natural := 5;
CORRECT : boolean := true;
EXTRA_PARITY_BIT : natural range 0 to 1 := 1;
ONE_PARITY_BIT : boolean := false;
ERROR_LEN : natural := 16
);
port(
clk_i, rst_i : in std_logic;
cnt_clr_i : in std_logic := '0'; -- Clear monitor counters.
en_i : in std_logic := '1'; -- Input enable.
data_i : in std_logic_vector(MESSAGE_LENGTH - 1 downto 0); -- Input data.
parity_i : in std_logic_vector(calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT) + EXTRA_PARITY_BIT - 1 downto 0); -- Parity bits.
data_o : out std_logic_vector(MESSAGE_LENGTH - 1 downto 0); -- Out data.
dout_valid_o : out std_logic; -- data_o valid.
cnt_errors_corrected_o, cnt_errors_detected_o : out std_logic_vector(ERROR_LEN - 1 downto 0);
log_wrong_bit_pos_data_o : out std_logic_vector(MESSAGE_LENGTH - 1 downto 0);
log_wrong_bit_pos_parity_o : out std_logic_vector(calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT) + EXTRA_PARITY_BIT - 1 downto 0)
);
 
end yahamm_dec;
 
architecture std of yahamm_dec 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);
constant H : matrix_t(0 to NPARITY_BITS + EXTRA_PARITY_BIT - 1,
0 to BLOCK_LENGTH + EXTRA_PARITY_BIT - 1) :=
get_parity_check_matrix(MESSAGE_LENGTH, EXTRA_PARITY_BIT, ONE_PARITY_BIT);
 
signal data_i_padded : bit_vector(BLOCK_LENGTH - NPARITY_BITS - 1 downto 0);
signal code_sys, code_nonsys, code_nonsys_q : bit_vector(BLOCK_LENGTH + EXTRA_PARITY_BIT - 1 downto 0);
signal syndrome : bit_vector(NPARITY_BITS + EXTRA_PARITY_BIT - 1 downto 0);
signal wrong_bit : integer range 0 to code_sys'length;
constant SWAPM : matrix_t(0 to BLOCK_LENGTH + EXTRA_PARITY_BIT - 1,
0 to BLOCK_LENGTH + EXTRA_PARITY_BIT - 1) :=
get_form_swap_matrix(MESSAGE_LENGTH, EXTRA_PARITY_BIT, ONE_PARITY_BIT);
 
signal correction_en : boolean;
signal cnt_errors_corrected_o_int, cnt_errors_detected_o_int : unsigned(ERROR_LEN - 1 downto 0);
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);
 
signal dout_valid_o_p0 : std_logic;
begin
 
check_parameters(BLOCK_LENGTH, NPARITY_BITS, MESSAGE_LENGTH, EXTRA_PARITY_BIT, ONE_PARITY_BIT, CORRECT);
 
cnt_errors_corrected_o <= std_logic_vector(cnt_errors_corrected_o_int);
cnt_errors_detected_o <= std_logic_vector(cnt_errors_detected_o_int);
-- Pad data_i with zeros on the left, so that data_i_padded'length = BLOCK_LENGTH.
-- This allow the user to reduce data_i width.
data_i_padded(MESSAGE_LENGTH - 1 downto 0) <= to_bitvector(data_i);
gen_padding: if BLOCK_LENGTH - NPARITY_BITS > MESSAGE_LENGTH generate
data_i_padded(BLOCK_LENGTH - NPARITY_BITS - 1 downto MESSAGE_LENGTH) <= (others => '0');
end generate gen_padding;
 
-- Wire data and parity inputs in the systematic code code_sys (data
-- on LSB, parity on MSB).
code_sys <= to_bitvector(parity_i) & data_i_padded;
-- Get the non-systematic code code_nonsys by swapping the
-- systematic code code_sys. The non-systematic code is needed to
-- obtain an immediately meaningful syndrome. This is timing-safe:
-- no logic here, it's purely wiring.
code_nonsys <= xor_multiply_vec(SWAPM, code_sys);
 
-- Output log_wrong_bit_pos_log, uses log_wrong_bit_pos_log_nonsys is padded
-- as data_i_padded
log_wrong_bit_pos_data_o_sys <= xor_multiply_vec(SWAPM, log_wrong_bit_pos_data_o_nonsys);
log_wrong_bit_pos_data_o <= To_StdLogicVector(log_wrong_bit_pos_data_o_sys(MESSAGE_LENGTH-1 downto 0));
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));
-- purpose: Compute error syndrome from the non-systematic code
-- (input) and the non-systemacic parity check matrix H. Also delay
-- code_nonsys to have code_nonsys_q synchronous with syndrome. And start
-- pipelining en input.
-- type : sequential
-- inputs : clk_i, rst_i, code_nonsys
-- outputs: syndrome
syndrome_proc: process (clk_i, rst_i) is
begin -- process syndrome_proc
if rst_i = '1' then -- asynchronous reset (active high)
syndrome <= (others => '0');
code_nonsys_q <= (others => '0');
dout_valid_o_p0 <= '0';
elsif rising_edge(clk_i) then -- rising clock edge
syndrome <= xor_multiply_vec(H, code_nonsys);
code_nonsys_q <= code_nonsys;
dout_valid_o_p0 <= en_i;
end if;
end process syndrome_proc;
 
-- purpose: Enable error correction (signal correction_en) for a single bit
-- error. Dependent from the generic parameters. If correction is enabled
-- wrong_bit signal is assigned the position of the wrong bit.
-- type : combinational
-- inputs : syndrome
-- outputs: correction_enabled
correction_enable_proc: process (syndrome) is
begin -- process correction_enable_proc
wrong_bit <= 0;
case CORRECT is
when false =>
-- Entity does not implement correction.
correction_en <= false;
when true =>
-- Entity implements correction.
 
case EXTRA_PARITY_BIT is
when 0 =>
-- SEC case (see table). Always correct.
correction_en <= true;
 
-- The wrong bit is the syndrome itself.
wrong_bit <= to_integer(unsigned(To_StdULogicVector(syndrome)));
when 1 =>
-- SECDED case (see table). The error, if any, is a single error to be
-- corrected if the extra parity bit in the syndrome is '1'.
if syndrome(syndrome'high) = '0' then
-- Double error: don't correct.
correction_en <= false;
else
-- Single error: correct.
correction_en <= true;
 
-- The wrong bit is not just the syndrome, because the
-- syndrome has the extra parity bit as MSB bit.
if or_reduce(syndrome(syndrome'high-1 downto 0)) = '0' then
-- No other error. So the extra parity bit itself is
-- wrong, that in this implementation is the MSB of
-- the non-systematic code word.
wrong_bit <= code_nonsys_q'length;
else
-- Extra parity bit '1', ignore it for wrong_bit position.
wrong_bit <= to_integer(unsigned(To_StdULogicVector(syndrome(NPARITY_BITS-1 downto 0))));
end if;
end if;
end case;
end case;
 
end process correction_enable_proc;
 
-- purpose: Decode the non systematic code code_nonsys_q and drive
-- output data_o. Single error correction is performed, depending on
-- the configuration.
-- type : sequential
-- inputs : clk_i, rst_i, code_nonsys_q, syndrome
-- outputs: data_o
decode_proc: process (clk_i, rst_i) is
variable iserror : boolean; -- parity error condition
variable code_sys_dec, code_nonsys_dec : bit_vector(code_sys'range);
begin -- process decode_proc
if rst_i = '1' then -- asynchronous reset (active high)
data_o <= (others => '0');
dout_valid_o <= '0';
elsif rising_edge(clk_i) then -- rising clock edge
 
if dout_valid_o_p0 = '0' then
data_o <= (others => '0');
dout_valid_o <= '0';
else
code_nonsys_dec := code_nonsys_q;
iserror := or_reduce(syndrome) = '1';
if correction_en and iserror then
code_nonsys_dec(wrong_bit-1) := not code_nonsys_q(wrong_bit-1);
end if;
code_sys_dec := xor_multiply_vec(SWAPM, code_nonsys_dec);
data_o <= To_StdLogicVector(code_sys_dec(MESSAGE_LENGTH - 1 downto 0));
dout_valid_o <= '1';
end if;
end if;
end process decode_proc;
 
-- purpose: Monitor counters.
-- type : sequential
-- inputs : clk_i, rst_i, syndrome, correction_en
-- outputs: cnt_errors_corrected_o_int, cnt_errors_detected_o_int, log_wrong_bit_pos_log
cnt_proc: process (clk_i, rst_i) is
variable iserror : boolean; -- parity error condition
begin -- process cnt_proc
if rst_i = '1' then -- asynchronous reset (active high)
cnt_errors_detected_o_int <= (others => '0');
cnt_errors_corrected_o_int <= (others => '0');
elsif rising_edge(clk_i) then -- rising clock edge
if cnt_clr_i = '1' then
-- synchronous clear
cnt_errors_detected_o_int <= (others => '0');
cnt_errors_corrected_o_int <= (others => '0');
else
iserror := or_reduce(syndrome) = '1';
if iserror then
if correction_en then
if and_reduce(to_bitvector(std_logic_vector(cnt_errors_corrected_o_int))) /= '1' then
cnt_errors_corrected_o_int <= cnt_errors_corrected_o_int + 1;
end if;
else
if and_reduce(to_bitvector(std_logic_vector(cnt_errors_detected_o_int))) /= '1' then
cnt_errors_detected_o_int <= cnt_errors_detected_o_int + 1;
end if;
end if;
end if;
end if;
end if;
end process cnt_proc;
 
-- purpose: Monitor counters.
-- type : sequential
-- inputs : clk_i, rst_i, syndrome, correction_en
-- outputs: cnt_errors_corrected_o_int, cnt_errors_detected_o_int, log_wrong_bit_pos_log
log_wrong_bit_gen: if CORRECT generate
log_wrong_bit_proc: process (clk_i, rst_i) is
variable iserror : boolean; -- parity error condition
begin -- process cnt_proc
if rst_i = '1' then
log_wrong_bit_pos_data_o_nonsys <= (others => '0');
elsif rising_edge(clk_i) then
if cnt_clr_i = '1' then
log_wrong_bit_pos_data_o_nonsys <= (others => '0');
else
iserror := or_reduce(syndrome) = '1';
if iserror then
if correction_en then
 
-- Note: wrong_bit refers to the wrong bit of the code in
-- non-systematic form. Indeed this is swapped to
-- systematic form for the output.
log_wrong_bit_pos_data_o_nonsys(wrong_bit-1) <= '1';
 
end if;
end if;
end if;
end if;
end process log_wrong_bit_proc;
end generate log_wrong_bit_gen;
end architecture std;
/rtl/vhdl/yahamm_enc.vhd
0,0 → 1,148
-------------------------------------------------------------------------------
-- 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
--
-------------------------------------------------------------------------------
 
-- CORRECT: set to true to correct errors at the cost of decreasing error
-- detection (see table).
--
-- SEC = single bit error corrected
-- SED = single bit error detected
-- DED = double bit error detected
-- TED = triple bit error detected
--
-- EXTRA_PARITY_BIT | CORRECT FALSE TRUE
-------------------------------------------------------------------------------
-- FALSE | SED-DED SEC
-- -----------------------------------------------------------
-- TRUE | SED-DED-TED SEC-DED
-------------------------------------------------------------------------------
--
-- Note that, for example, SEC-DED (EXTRA_PARITY_BIT = true, CORRECT =
-- true) means that triple bit errors are not detected and messages
-- will be wrongly corrected because the correction corrects toward
-- the code word within the smaller hamming distance. Practically you
-- usually know that something is very wrong with your communication
-- channel because you will also see double bit errors. Then you
-- should not trust corrected data at all.
 
library ieee;
use ieee.std_logic_1164.all;
 
library yahamm;
use yahamm.matrix_pkg.all;
use yahamm.yahamm_pkg.all;
 
entity yahamm_enc is
generic (
MESSAGE_LENGTH : natural := 5;
EXTRA_PARITY_BIT : natural range 0 to 1 := 1;
ONE_PARITY_BIT : boolean := false
);
port(
clk_i, rst_i : in std_logic;
en_i : in std_logic := '1'; -- Synchronous output enable .
data_i : in std_logic_vector(MESSAGE_LENGTH - 1 downto 0); -- Input data.
data_o : out std_logic_vector(MESSAGE_LENGTH - 1 downto 0); -- Out data.
data_valid_o : out std_logic;
parity_o : out std_logic_vector(calc_nparity_bits(MESSAGE_LENGTH, ONE_PARITY_BIT) + EXTRA_PARITY_BIT - 1 downto 0) -- Parity bits.
);
 
end yahamm_enc;
 
architecture std of yahamm_enc 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);
constant G : matrix_t(0 to BLOCK_LENGTH + EXTRA_PARITY_BIT - 1,
0 to BLOCK_LENGTH - NPARITY_BITS - 1) :=
get_code_generator_matrix(MESSAGE_LENGTH, EXTRA_PARITY_BIT, ONE_PARITY_BIT);
 
-- G'reverse_range(1) doesn't work in ghdl 0.34
--signal code_sys : std_ulogic_vector(G'reverse_range(1)); -- systematic code
signal code_sys : std_ulogic_vector(BLOCK_LENGTH + EXTRA_PARITY_BIT -1 downto 0); -- systematic code
signal data_i_padded : bit_vector(BLOCK_LENGTH - NPARITY_BITS - 1 downto 0);
begin
 
check_parameters(BLOCK_LENGTH, NPARITY_BITS, MESSAGE_LENGTH, EXTRA_PARITY_BIT, ONE_PARITY_BIT);
 
data_i_padded(MESSAGE_LENGTH - 1 downto 0) <= to_bitvector(data_i);
pad_gen: if MESSAGE_LENGTH < BLOCK_LENGTH - NPARITY_BITS generate
-- Pad data_i with zeros on the left, so that data_i_padded'length = BLOCK_LENGTH.
-- This allow the user to reduce data_i width.
data_i_padded(BLOCK_LENGTH - NPARITY_BITS - 1 downto MESSAGE_LENGTH) <= (others => '0');
end generate pad_gen;
-- Wire systematic code signal code_sys on data_o and parity_o output ports.
-- Because of the form of the code generator matrix G, data are the LSB part
-- of code and parity the MSB part.
parity_o <= to_slv(code_sys(code_sys'high downto code_sys'high - (EXTRA_PARITY_BIT + NPARITY_BITS) + 1));
data_o <= to_slv(code_sys(MESSAGE_LENGTH - 1 downto 0));
-- purpose: Sequentially encode input with output enable.
-- type : sequential
-- inputs : clk_i, rst_i, d_sig
-- outputs: msg_sys
encode_proc: process (clk_i, rst_i) is
begin -- process encode_proc
if rst_i = '1' then -- asynchronous reset (active high)
code_sys <= (others => '0');
data_valid_o <= '0';
elsif rising_edge(clk_i) then -- rising clock edge
 
if en_i = '0' then -- syncronous output enable
code_sys <= (others => '0');
data_valid_o <= '0';
else
code_sys <= To_StdULogicVector(xor_multiply_vec(G, data_i_padded));
data_valid_o <= '1';
end if;
end if;
end process encode_proc;
 
end architecture std;
/rtl/vhdl/yahamm_pkg.vhd
0,0 → 1,507
-------------------------------------------------------------------------------
-- 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;
/sim/Makefile File deleted
/sim/yahamm_tb0.vhd File deleted
/sim/yahamm_tb1.vhd File deleted
/sim/yahamm_tb2.vhd File deleted
/sim/yahamm_tb3.vhd File deleted

powered by: WebSVN 2.1.0

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