VHDL coding tips and tricks: VHDL code for Cyclic Reduntancy Check(CRC)

## Sunday, November 15, 2015

### VHDL code for Cyclic Reduntancy Check(CRC)

A Cyclic Redundancy Check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data. There are many CRC polynomials available, used depending on the specific application.
The CRC polynomial I have implemented here is 8 bit in size and is known as CRC-8-CCITT. The polynomial is represented by the polynomial equation,

P(x) = x8+ x2+ x1+ x0

To generate the circuit diagram for any CRC polynomial I find the following link very useful. The service also generates a Verilog code. The advantage of the circuit generated is that, the input is assumed to be serially fed into the circuit. This means the input can be really long and still the fpga resource usage will remain the same.

Circuit Diagram generated by the online tool:

CRC - 8 bit:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity CRC8 is
port( Clk: in std_logic;
reset : in std_logic; --active high reset
size_data : in unsigned(15 downto 0);  --the size of input stream in bits.
Data_in : in std_logic; --serial input
crc_out : out unsigned(7 downto 0); --8 bit crc checksum
crc_ready : out std_logic --high when the calculation is done.
);
end CRC8;

architecture Behavioral of CRC8 is

signal count : unsigned(15 downto 0) := (others => '0');
signal crc_temp : unsigned(7 downto 0) := (others => '0');

begin

process(Clk,reset)
begin
if(reset = '1') then
crc_temp <= (others => '0');
count <= (others => '0');
crc_ready <= '0';
elsif(rising_edge(Clk)) then
--crc calculation in the next four lines.
crc_temp(0) <= Data_in xor crc_temp(7);
crc_temp(1) <= crc_temp(0) xor crc_temp(7);
crc_temp(2) <= crc_temp(1) xor crc_temp(7);
crc_temp(7 downto 3) <= crc_temp(6 downto 2);

count <= count + 1; --keeps track of the number of rounds
if(count = size_data + 7) then --check when to finish the calculations
count <= (others => '0');
crc_ready <= '1';
end if;
end if;
end process;

crc_out <= crc_temp;

end Behavioral;

Testbench code for CRC:

For testing the design I send two different input streams to the crc calculating module. The first stream is 8 bits in size and the second stream is 16 bits in size.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY tb IS
END tb;

ARCHITECTURE behavior OF tb IS

-- CRC Component Declaration for testing.
COMPONENT CRC8
port( Clk: in std_logic;
reset : in std_logic;
size_data : in unsigned(15 downto 0);
Data_in : in std_logic;
crc_out : out unsigned(7 downto 0);
crc_ready : out std_logic
);
END COMPONENT;

--Inputs
signal Clk : std_logic := '0';
signal reset : std_logic := '0';
signal Data_in : std_logic := '0';
signal size_data : unsigned(15 downto 0) := (others => '0');
--Outputs
signal crc_out : unsigned(7 downto 0);
signal crc_ready : std_logic;
-- Clock period definitions
constant Clk_period : time := 10 ns;

BEGIN

-- Instantiate the Unit Under Test (UUT)
uut: CRC8 PORT MAP (
Clk => Clk,
reset => reset,
size_data => size_data,
Data_in => Data_in,
crc_out => crc_out,
crc_ready => crc_ready
);

-- 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
reset <= '1';
wait for 100 ns;
--Data stream(in hex) : 78
size_data <= to_unsigned(8,16);  --data stream is 8 bits in size
wait until falling_edge(Clk);
reset <= '0';
Data_in <= '0'; wait for Clk_period;
Data_in <= '1'; wait for Clk_period;
Data_in <= '1'; wait for Clk_period;
Data_in <= '1'; wait for Clk_period;
Data_in <= '1'; wait for Clk_period;
Data_in <= '0'; wait for Clk_period;
wait until crc_ready = '1'; wait for Clk_period;
reset <= '1';

wait for 100 ns;
--Data stream(in hex) : B800
size_data <= to_unsigned(16,16); --data stream is 16 bits in size
wait until falling_edge(Clk);
reset <= '0';
Data_in <= '1'; wait for Clk_period;
Data_in <= '0'; wait for Clk_period;
Data_in <= '1'; wait for Clk_period;
Data_in <= '1'; wait for Clk_period;
Data_in <= '1'; wait for Clk_period;
Data_in <= '0'; wait for Clk_period;
wait until crc_ready = '1'; wait for Clk_period;
reset <= '1';
wait;
end process;

END;

Simulation waveform:

The codes were compiled and simulated using Xilinx ISE 13.1. The waveform results were verified as per the results obtained in here.

Synthesis Results:

The code was successfully synthesised in Xilinx XST for Virtex 4 fpga. The tool showed a maximum frequency of 300 MHz for the design.

#### 1 comment:

1. I'd expect the data input xor'ed with all bits:

crc_temp(0) <= Data_in xor crc_temp(7);
crc_temp(1) <= crc_temp(0) xor crc_temp(7) xor Data_in;
crc_temp(2) <= crc_temp(1) xor crc_temp(7) xor Data_in;
crc_temp(7 downto 3) <= crc_temp(6 downto 2);

Do I miss something?