Parallel CRC Generator
Generate a synthesizable parallel (one word per clock) CRC module in Verilog and VHDL from any polynomial. Presets for CRC-8, CRC-16-CCITT, CRC-16-IBM and CRC-32. Pure XOR logic, no lookup tables.
Results
- Polynomial
- 0x04C11DB7 (top bit implicit)
- CRC width / data width
- 32 / 8 bits
- Init value
- 0xFFFFFFFF
- 2-input XOR count (approx.)
- 220
Notes
- One full data word is folded into the CRC every enabled clock cycle.
- Not reflected: for reflected protocols (Ethernet CRC-32, SD/MMC), bit-reverse each input byte and bit-reverse + invert the final CRC.
- For CRC-32 the final value is usually XORed with 0xFFFFFFFF before transmission; do that outside this module.
// Parallel CRC: poly=0x04C11DB7 (+ implicit top bit), width=32, data=8 bits/clk
// Data shifted in MSB first, not reflected. Generated by libfpga.com/tools/crc-generator
module crc32_d8 (
input wire clk,
input wire rst, // sync reset, loads INIT
input wire en, // process data_in this cycle
input wire [7:0] data_in,
output reg [31:0] crc_out
);
localparam [31:0] INIT = 32'hFFFFFFFF;
wire [31:0] c = crc_out;
wire [31:0] crc_next;
assign crc_next[0] = c[30] ^ c[24] ^ data_in[6] ^ data_in[0];
assign crc_next[1] = c[31] ^ c[30] ^ c[25] ^ c[24] ^ data_in[7] ^ data_in[6] ^ data_in[1] ^ data_in[0];
assign crc_next[2] = c[31] ^ c[30] ^ c[26] ^ c[25] ^ c[24] ^ data_in[7] ^ data_in[6] ^ data_in[2] ^ data_in[1] ^ data_in[0];
assign crc_next[3] = c[31] ^ c[27] ^ c[26] ^ c[25] ^ data_in[7] ^ data_in[3] ^ data_in[2] ^ data_in[1];
assign crc_next[4] = c[30] ^ c[28] ^ c[27] ^ c[26] ^ c[24] ^ data_in[6] ^ data_in[4] ^ data_in[3] ^ data_in[2] ^ data_in[0];
assign crc_next[5] = c[31] ^ c[30] ^ c[29] ^ c[28] ^ c[27] ^ c[25] ^ c[24] ^ data_in[7] ^ data_in[6] ^ data_in[5] ^ data_in[4] ^ data_in[3] ^ data_in[1] ^ data_in[0];
assign crc_next[6] = c[31] ^ c[30] ^ c[29] ^ c[28] ^ c[26] ^ c[25] ^ data_in[7] ^ data_in[6] ^ data_in[5] ^ data_in[4] ^ data_in[2] ^ data_in[1];
assign crc_next[7] = c[31] ^ c[29] ^ c[27] ^ c[26] ^ c[24] ^ data_in[7] ^ data_in[5] ^ data_in[3] ^ data_in[2] ^ data_in[0];
assign crc_next[8] = c[28] ^ c[27] ^ c[25] ^ c[24] ^ c[0] ^ data_in[4] ^ data_in[3] ^ data_in[1] ^ data_in[0];
assign crc_next[9] = c[29] ^ c[28] ^ c[26] ^ c[25] ^ c[1] ^ data_in[5] ^ data_in[4] ^ data_in[2] ^ data_in[1];
assign crc_next[10] = c[29] ^ c[27] ^ c[26] ^ c[24] ^ c[2] ^ data_in[5] ^ data_in[3] ^ data_in[2] ^ data_in[0];
assign crc_next[11] = c[28] ^ c[27] ^ c[25] ^ c[24] ^ c[3] ^ data_in[4] ^ data_in[3] ^ data_in[1] ^ data_in[0];
assign crc_next[12] = c[30] ^ c[29] ^ c[28] ^ c[26] ^ c[25] ^ c[24] ^ c[4] ^ data_in[6] ^ data_in[5] ^ data_in[4] ^ data_in[2] ^ data_in[1] ^ data_in[0];
assign crc_next[13] = c[31] ^ c[30] ^ c[29] ^ c[27] ^ c[26] ^ c[25] ^ c[5] ^ data_in[7] ^ data_in[6] ^ data_in[5] ^ data_in[3] ^ data_in[2] ^ data_in[1];
assign crc_next[14] = c[31] ^ c[30] ^ c[28] ^ c[27] ^ c[26] ^ c[6] ^ data_in[7] ^ data_in[6] ^ data_in[4] ^ data_in[3] ^ data_in[2];
assign crc_next[15] = c[31] ^ c[29] ^ c[28] ^ c[27] ^ c[7] ^ data_in[7] ^ data_in[5] ^ data_in[4] ^ data_in[3];
assign crc_next[16] = c[29] ^ c[28] ^ c[24] ^ c[8] ^ data_in[5] ^ data_in[4] ^ data_in[0];
assign crc_next[17] = c[30] ^ c[29] ^ c[25] ^ c[9] ^ data_in[6] ^ data_in[5] ^ data_in[1];
assign crc_next[18] = c[31] ^ c[30] ^ c[26] ^ c[10] ^ data_in[7] ^ data_in[6] ^ data_in[2];
assign crc_next[19] = c[31] ^ c[27] ^ c[11] ^ data_in[7] ^ data_in[3];
assign crc_next[20] = c[28] ^ c[12] ^ data_in[4];
assign crc_next[21] = c[29] ^ c[13] ^ data_in[5];
assign crc_next[22] = c[24] ^ c[14] ^ data_in[0];
assign crc_next[23] = c[30] ^ c[25] ^ c[24] ^ c[15] ^ data_in[6] ^ data_in[1] ^ data_in[0];
assign crc_next[24] = c[31] ^ c[26] ^ c[25] ^ c[16] ^ data_in[7] ^ data_in[2] ^ data_in[1];
assign crc_next[25] = c[27] ^ c[26] ^ c[17] ^ data_in[3] ^ data_in[2];
assign crc_next[26] = c[30] ^ c[28] ^ c[27] ^ c[24] ^ c[18] ^ data_in[6] ^ data_in[4] ^ data_in[3] ^ data_in[0];
assign crc_next[27] = c[31] ^ c[29] ^ c[28] ^ c[25] ^ c[19] ^ data_in[7] ^ data_in[5] ^ data_in[4] ^ data_in[1];
assign crc_next[28] = c[30] ^ c[29] ^ c[26] ^ c[20] ^ data_in[6] ^ data_in[5] ^ data_in[2];
assign crc_next[29] = c[31] ^ c[30] ^ c[27] ^ c[21] ^ data_in[7] ^ data_in[6] ^ data_in[3];
assign crc_next[30] = c[31] ^ c[28] ^ c[22] ^ data_in[7] ^ data_in[4];
assign crc_next[31] = c[29] ^ c[23] ^ data_in[5];
always @(posedge clk) begin
if (rst) crc_out <= INIT;
else if (en) crc_out <= crc_next;
end
endmodule
-- Parallel CRC: poly=0x04C11DB7 (+ implicit top bit), width=32, data=8 bits/clk
-- Data shifted in MSB first, not reflected. Generated by libfpga.com/tools/crc-generator
library ieee;
use ieee.std_logic_1164.all;
entity crc32_d8 is
port (
clk : in std_logic;
rst : in std_logic; -- sync reset, loads INIT
en : in std_logic;
data_in : in std_logic_vector(7 downto 0);
crc_out : out std_logic_vector(31 downto 0)
);
end entity;
architecture rtl of crc32_d8 is
constant INIT : std_logic_vector(31 downto 0) := "11111111111111111111111111111111";
signal c : std_logic_vector(31 downto 0) := INIT;
begin
crc_out <= c;
process (clk)
variable n : std_logic_vector(31 downto 0);
begin
if rising_edge(clk) then
if rst = '1' then
c <= INIT;
elsif en = '1' then
n(0) := c(30) xor c(24) xor data_in(6) xor data_in(0);
n(1) := c(31) xor c(30) xor c(25) xor c(24) xor data_in(7) xor data_in(6) xor data_in(1) xor data_in(0);
n(2) := c(31) xor c(30) xor c(26) xor c(25) xor c(24) xor data_in(7) xor data_in(6) xor data_in(2) xor data_in(1) xor data_in(0);
n(3) := c(31) xor c(27) xor c(26) xor c(25) xor data_in(7) xor data_in(3) xor data_in(2) xor data_in(1);
n(4) := c(30) xor c(28) xor c(27) xor c(26) xor c(24) xor data_in(6) xor data_in(4) xor data_in(3) xor data_in(2) xor data_in(0);
n(5) := c(31) xor c(30) xor c(29) xor c(28) xor c(27) xor c(25) xor c(24) xor data_in(7) xor data_in(6) xor data_in(5) xor data_in(4) xor data_in(3) xor data_in(1) xor data_in(0);
n(6) := c(31) xor c(30) xor c(29) xor c(28) xor c(26) xor c(25) xor data_in(7) xor data_in(6) xor data_in(5) xor data_in(4) xor data_in(2) xor data_in(1);
n(7) := c(31) xor c(29) xor c(27) xor c(26) xor c(24) xor data_in(7) xor data_in(5) xor data_in(3) xor data_in(2) xor data_in(0);
n(8) := c(28) xor c(27) xor c(25) xor c(24) xor c(0) xor data_in(4) xor data_in(3) xor data_in(1) xor data_in(0);
n(9) := c(29) xor c(28) xor c(26) xor c(25) xor c(1) xor data_in(5) xor data_in(4) xor data_in(2) xor data_in(1);
n(10) := c(29) xor c(27) xor c(26) xor c(24) xor c(2) xor data_in(5) xor data_in(3) xor data_in(2) xor data_in(0);
n(11) := c(28) xor c(27) xor c(25) xor c(24) xor c(3) xor data_in(4) xor data_in(3) xor data_in(1) xor data_in(0);
n(12) := c(30) xor c(29) xor c(28) xor c(26) xor c(25) xor c(24) xor c(4) xor data_in(6) xor data_in(5) xor data_in(4) xor data_in(2) xor data_in(1) xor data_in(0);
n(13) := c(31) xor c(30) xor c(29) xor c(27) xor c(26) xor c(25) xor c(5) xor data_in(7) xor data_in(6) xor data_in(5) xor data_in(3) xor data_in(2) xor data_in(1);
n(14) := c(31) xor c(30) xor c(28) xor c(27) xor c(26) xor c(6) xor data_in(7) xor data_in(6) xor data_in(4) xor data_in(3) xor data_in(2);
n(15) := c(31) xor c(29) xor c(28) xor c(27) xor c(7) xor data_in(7) xor data_in(5) xor data_in(4) xor data_in(3);
n(16) := c(29) xor c(28) xor c(24) xor c(8) xor data_in(5) xor data_in(4) xor data_in(0);
n(17) := c(30) xor c(29) xor c(25) xor c(9) xor data_in(6) xor data_in(5) xor data_in(1);
n(18) := c(31) xor c(30) xor c(26) xor c(10) xor data_in(7) xor data_in(6) xor data_in(2);
n(19) := c(31) xor c(27) xor c(11) xor data_in(7) xor data_in(3);
n(20) := c(28) xor c(12) xor data_in(4);
n(21) := c(29) xor c(13) xor data_in(5);
n(22) := c(24) xor c(14) xor data_in(0);
n(23) := c(30) xor c(25) xor c(24) xor c(15) xor data_in(6) xor data_in(1) xor data_in(0);
n(24) := c(31) xor c(26) xor c(25) xor c(16) xor data_in(7) xor data_in(2) xor data_in(1);
n(25) := c(27) xor c(26) xor c(17) xor data_in(3) xor data_in(2);
n(26) := c(30) xor c(28) xor c(27) xor c(24) xor c(18) xor data_in(6) xor data_in(4) xor data_in(3) xor data_in(0);
n(27) := c(31) xor c(29) xor c(28) xor c(25) xor c(19) xor data_in(7) xor data_in(5) xor data_in(4) xor data_in(1);
n(28) := c(30) xor c(29) xor c(26) xor c(20) xor data_in(6) xor data_in(5) xor data_in(2);
n(29) := c(31) xor c(30) xor c(27) xor c(21) xor data_in(7) xor data_in(6) xor data_in(3);
n(30) := c(31) xor c(28) xor c(22) xor data_in(7) xor data_in(4);
n(31) := c(29) xor c(23) xor data_in(5);
c <= n;
end if;
end if;
end process;
end architecture;
About this tool
A serial CRC processes one bit per clock; at a gigabit line rate that would need a gigahertz clock. The standard trick is to unroll: advance the shift register a whole word per cycle by computing, symbolically, what each CRC bit would be after N serial steps. Each next-state bit collapses to an XOR of current CRC bits and data bits, which synthesizes to a few levels of LUTs. This generator does that unrolling for any polynomial and data width and emits the resulting equations as a Verilog or VHDL module, the same approach as the classic easics generator, verified in our test suite against a bit-serial reference. Watch the reflection convention: Ethernet and SD/MMC shift bits in LSB-first, so reverse input bytes and the final CRC as noted on the page.
Cores that use this
Open FPGA IP from the registry you can drop in instead of building from scratch.