OpenCores

Parallel CRC Generator

Issue List
Incorrect checksum #4
Open pela opened this issue over 6 years agoBug
pela commented over 6 years ago

The computed checksums for the polynomial I have tested is not correct. Polynomial: 1+x^5+x^12+x^16, 8 bit data, 16 bit CRC.

The VHDL code was generated in Windows 7 64-bit, with the command crc-gen\crc-gen vhdl 8 16 1021 > csi2_crc.vhd

I have generated a testbench file (enclosed below), which contains two sequences of bytes, and their expected CRC sums. The transcript in ModelSim looks as follows:

** Error: Assertion violation.

Time: 435 ns Iteration: 1 Instance: /tb_csi2_crc_gen

** Error: Checksum mismatch for TESTDATA_1. Got 5105 Expected 00F0

Time: 435 ns Iteration: 1 Instance: /tb_csi2_crc_gen

** Error: Assertion violation.

Time: 715 ns Iteration: 1 Instance: /tb_csi2_crc_gen

** Error: Checksum mismatch for TESTDATA_2. Got E6A4 Expected E569

Time: 715 ns Iteration: 1 Instance: /tb_csi2_crc_gen

Generated VHDL code:


-- Copyright (C) 2009 OutputLogic.com -- 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 PROVIDED "AS IS" AND WITHOUT ANY EXPRESS -- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED

-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

--// CRC module for --// data(7:0) --// crc(15:0)=1+x^5+x^12+x^16; --// library ieee;
use ieee.std_logic_1164.all;


entity crc is port ( data_in : in std_logic_vector (7 downto 0); crc_en , rst, clk : in std_logic; crc_out : out std_logic_vector (15 downto 0)); end crc;

architecture imp_crc of crc is signal lfsr_q: std_logic_vector (15 downto 0); signal lfsr_c: std_logic_vector (15 downto 0); begin
crc_out <= lfsr_q;

lfsr_c(0) <= lfsr_q(8) xor lfsr_q(12) xor data_in(0) xor data_in(4);
lfsr_c(1) <= lfsr_q(9) xor lfsr_q(13) xor data_in(1) xor data_in(5);
lfsr_c(2) <= lfsr_q(10) xor lfsr_q(14) xor data_in(2) xor data_in(6);
lfsr_c(3) <= lfsr_q(11) xor lfsr_q(15) xor data_in(3) xor data_in(7);
lfsr_c(4) <= lfsr_q(12) xor data_in(4);
lfsr_c(5) <= lfsr_q(8) xor lfsr_q(12) xor lfsr_q(13) xor data_in(0) xor data_in(4) xor data_in(5);
lfsr_c(6) <= lfsr_q(9) xor lfsr_q(13) xor lfsr_q(14) xor data_in(1) xor data_in(5) xor data_in(6);
lfsr_c(7) <= lfsr_q(10) xor lfsr_q(14) xor lfsr_q(15) xor data_in(2) xor data_in(6) xor data_in(7);
lfsr_c(8) <= lfsr_q(0) xor lfsr_q(11) xor lfsr_q(15) xor data_in(3) xor data_in(7);
lfsr_c(9) <= lfsr_q(1) xor lfsr_q(12) xor data_in(4);
lfsr_c(10) <= lfsr_q(2) xor lfsr_q(13) xor data_in(5);
lfsr_c(11) <= lfsr_q(3) xor lfsr_q(14) xor data_in(6);
lfsr_c(12) <= lfsr_q(4) xor lfsr_q(8) xor lfsr_q(12) xor lfsr_q(15) xor data_in(0) xor data_in(4) xor data_in(7);
lfsr_c(13) <= lfsr_q(5) xor lfsr_q(9) xor lfsr_q(13) xor data_in(1) xor data_in(5);
lfsr_c(14) <= lfsr_q(6) xor lfsr_q(10) xor lfsr_q(14) xor data_in(2) xor data_in(6);
lfsr_c(15) <= lfsr_q(7) xor lfsr_q(11) xor lfsr_q(15) xor data_in(3) xor data_in(7);

process (clk,rst) begin if (rst = '1') then lfsr_q <= b"1111111111111111"; elsif (clk'EVENT and clk = '1') then if (crc_en = '1') then lfsr_q <= lfsr_c; end if; end if;
end process; end architecture imp_crc;

========================================================================

Testbench code:

-- Company:

-- Engineer:

-- Create Date:
-- Design Name:
-- Module Name:
-- Project Name:
-- Target Device:
-- Tool versions:
-- Description:
-- -- VHDL Test Bench Created by ISE for module: crc -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created

-- Additional Comments:

-- Notes: -- This testbench has been automatically generated using types std_logic and -- std_logic_vector for the ports of the unit under test. Xilinx recommends -- that these types always be used for the top-level I/O of a design in order -- to guarantee that the testbench will bind correctly to the post-implementation

-- simulation model.

library ieee; use ieee.std_logic_1164.all; use std.env.all; use work.txt_util.all; -- From http://stefanvhdl.com/vhdl/vhdl/txt_util.vhd

entity tb_csi2_crc_gen is end tb_csi2_crc_gen;

architecture behavior of tb_csi2_crc_gen is

-- Component Declaration for the Unit Under Test (UUT)

component crc
port(
     data_in : in  std_logic_vector(7 downto 0);
     crc_en : in  std_logic;
     rst : in  std_logic;
     clk : in  std_logic;
     crc_out : out  std_logic_vector(15 downto 0)
    );
end component;

--Inputs signal data_in : std_logic_vector(7 downto 0) := (others => '0'); signal crc_en : std_logic := '0'; signal rst : std_logic := '1'; signal clk : std_logic := '0';

--Outputs signal crc_out : std_logic_vector(15 downto 0);

-- Clock period definitions constant clk_period : time := 10 ns;

type slv_vector_t is array (natural range <>) of std_logic_vector(7 downto 0);

-- Ref 1 section 9.6 page 55 constant C_NUM_BYTES : integer := 24; constant C_TESTDATA_1 : slv_vector_t(0 to C_NUM_BYTES-1) := ( x"FF", x"00", x"00", x"02", x"B9", x"DC", x"F3", x"72", x"BB", x"D4", x"B8", x"5A", x"C8", x"75", x"C2", x"7C", x"81", x"F8", x"05", x"DF", x"FF", x"00", x"00", x"01" ); constant C_CRC_1 : std_logic_vector(15 downto 0) := x"00F0"; constant C_TESTDATA_2 : slv_vector_t(0 to C_NUM_BYTES-1) := ( x"FF", x"00", x"00", x"00", x"1E", x"F0", x"1E", x"C7", x"4F", x"82", x"78", x"C5", x"82", x"E0", x"8C", x"70", x"D2", x"3C", x"78", x"E9", x"FF", x"00", x"00", x"01" ); constant C_CRC_2 : std_logic_vector(15 downto 0) := x"E569";

begin

-- Instantiate the Unit Under Test (UUT)

uut: crc port map ( data_in => data_in, crc_en => crc_en, rst => rst, clk => clk, crc_out => crc_out );

-- Clock process definitions clk_process :process begin clk <= '0'; wait for clk_period/2; clk <= '1'; wait for clk_period/2; end process;

-- Stimulus process stim_proc: process begin rst <= '1'; -- hold reset state for 100 ns. wait for 100 ns; rst <= '0';

  for i in 0 to 9 loop
    wait until rising_edge(clk);
  end loop;
  
  crc_en <= '1';
  for i in 0 to C_NUM_BYTES-1 loop
    data_in <= C_TESTDATA_1(i);
    wait until rising_edge(clk);
  end loop;
  crc_en <= '0';      
  assert crc_out = C_CRC_1;
    report "Checksum mismatch for TESTDATA_1. Got " & hstr(crc_out) & " Expected " & hstr(C_CRC_1)
    severity error;
    
  wait until rising_edge(clk);
  rst <= '1';
  wait until rising_edge(clk);
  rst <= '0';
  wait until rising_edge(clk);
  wait until rising_edge(clk);
  
  crc_en <= '1';
  for i in 0 to C_NUM_BYTES-1 loop
    data_in <= C_TESTDATA_2(i);
    wait until rising_edge(clk);
  end loop;
  crc_en <= '0';      
  assert crc_out = C_CRC_2;
    report "Checksum mismatch for TESTDATA_2. Got " & hstr(crc_out) & " Expected " & hstr(C_CRC_2)
    severity error;   
    
  wait for clk_period*10;
  
  --finish;
  assert false
  report "Not a failure, just forcing the simulation to stop..."
  severity failure;
  wait;

end process;

end;

pela commented over 5 years ago

Sorry, there is no bug, but perhaps a documentation issue.

It seems like the CRC generator assumes an interface where the most significant bit of each byte is sent first. But in the interface that I use, the least significant bit is sent first.

If I swap the bits of the byte before feeding data into the CRC generator, and swap the bits of the word from the checksum output, it works correctly.

It would be nice if it was documented that the generator assumes most significant bit first, and present a work-around if the user need least significant bit first.

Or, even better, a switch which sets least or most significant bit first.

evgeni commented about 5 years ago

There are lots of comments in this thread: http://outputlogic.com/?p=158

They might be helpful to users dealing with the issue of byte/bit ordering and CRC LFSR initialization.