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
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- 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;
|
|
|
No newline at end of file
|
No newline at end of file
|