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:
-- 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
--// 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;
========================================================================
-- Company:
-- 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
-- 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
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;
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.
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.