blob: 762fd48cb3862d124a2d061476832e31d7a26353 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// CRC32 calculator
//
// This module takes in n-bits data words (n defined by BytePerWord parameter) and updates an
// internally stored CRC with each valid data word. The polynomial used is the standard CRC32 IEEE
// one. An interface is provided to set the internal CRC to an arbitrary value. The output CRC is an
// inverted version of the internally stored CRC and the input CRC is inverted before being stored.
// This is done so results match existing widely used software libraries (e.g. the crc32
// functionality available in Python). Note that a initial CRC of 0x0 (corresponding to an internal
// CRC of 0xffffffff) must be used to match results generated elsewhere.
module prim_crc32 #(
parameter int unsigned BytesPerWord = 4
) (
input logic clk_i,
input logic rst_ni,
input logic set_crc_i,
input logic [31:0] crc_in_i,
input logic data_valid_i,
input logic [BytesPerWord*8-1:0] data_i,
output logic [31:0] crc_out_o
);
// Generated using hw/ip/prim/util/prim_crc32_table_gen.py
function automatic logic [31:0] crc32_byte_calc(logic [7:0] b);
unique case (b)
8'hff: crc32_byte_calc = 32'h2d02ef8d;
8'hfe: crc32_byte_calc = 32'h5a05df1b;
8'hfd: crc32_byte_calc = 32'hc30c8ea1;
8'hfc: crc32_byte_calc = 32'hb40bbe37;
8'hfb: crc32_byte_calc = 32'h2a6f2b94;
8'hfa: crc32_byte_calc = 32'h5d681b02;
8'hf9: crc32_byte_calc = 32'hc4614ab8;
8'hf8: crc32_byte_calc = 32'hb3667a2e;
8'hf7: crc32_byte_calc = 32'h23d967bf;
8'hf6: crc32_byte_calc = 32'h54de5729;
8'hf5: crc32_byte_calc = 32'hcdd70693;
8'hf4: crc32_byte_calc = 32'hbad03605;
8'hf3: crc32_byte_calc = 32'h24b4a3a6;
8'hf2: crc32_byte_calc = 32'h53b39330;
8'hf1: crc32_byte_calc = 32'hcabac28a;
8'hf0: crc32_byte_calc = 32'hbdbdf21c;
8'hef: crc32_byte_calc = 32'h30b5ffe9;
8'hee: crc32_byte_calc = 32'h47b2cf7f;
8'hed: crc32_byte_calc = 32'hdebb9ec5;
8'hec: crc32_byte_calc = 32'ha9bcae53;
8'heb: crc32_byte_calc = 32'h37d83bf0;
8'hea: crc32_byte_calc = 32'h40df0b66;
8'he9: crc32_byte_calc = 32'hd9d65adc;
8'he8: crc32_byte_calc = 32'haed16a4a;
8'he7: crc32_byte_calc = 32'h3e6e77db;
8'he6: crc32_byte_calc = 32'h4969474d;
8'he5: crc32_byte_calc = 32'hd06016f7;
8'he4: crc32_byte_calc = 32'ha7672661;
8'he3: crc32_byte_calc = 32'h3903b3c2;
8'he2: crc32_byte_calc = 32'h4e048354;
8'he1: crc32_byte_calc = 32'hd70dd2ee;
8'he0: crc32_byte_calc = 32'ha00ae278;
8'hdf: crc32_byte_calc = 32'h166ccf45;
8'hde: crc32_byte_calc = 32'h616bffd3;
8'hdd: crc32_byte_calc = 32'hf862ae69;
8'hdc: crc32_byte_calc = 32'h8f659eff;
8'hdb: crc32_byte_calc = 32'h11010b5c;
8'hda: crc32_byte_calc = 32'h66063bca;
8'hd9: crc32_byte_calc = 32'hff0f6a70;
8'hd8: crc32_byte_calc = 32'h88085ae6;
8'hd7: crc32_byte_calc = 32'h18b74777;
8'hd6: crc32_byte_calc = 32'h6fb077e1;
8'hd5: crc32_byte_calc = 32'hf6b9265b;
8'hd4: crc32_byte_calc = 32'h81be16cd;
8'hd3: crc32_byte_calc = 32'h1fda836e;
8'hd2: crc32_byte_calc = 32'h68ddb3f8;
8'hd1: crc32_byte_calc = 32'hf1d4e242;
8'hd0: crc32_byte_calc = 32'h86d3d2d4;
8'hcf: crc32_byte_calc = 32'h0bdbdf21;
8'hce: crc32_byte_calc = 32'h7cdcefb7;
8'hcd: crc32_byte_calc = 32'he5d5be0d;
8'hcc: crc32_byte_calc = 32'h92d28e9b;
8'hcb: crc32_byte_calc = 32'h0cb61b38;
8'hca: crc32_byte_calc = 32'h7bb12bae;
8'hc9: crc32_byte_calc = 32'he2b87a14;
8'hc8: crc32_byte_calc = 32'h95bf4a82;
8'hc7: crc32_byte_calc = 32'h05005713;
8'hc6: crc32_byte_calc = 32'h72076785;
8'hc5: crc32_byte_calc = 32'heb0e363f;
8'hc4: crc32_byte_calc = 32'h9c0906a9;
8'hc3: crc32_byte_calc = 32'h026d930a;
8'hc2: crc32_byte_calc = 32'h756aa39c;
8'hc1: crc32_byte_calc = 32'hec63f226;
8'hc0: crc32_byte_calc = 32'h9b64c2b0;
8'hbf: crc32_byte_calc = 32'h5bdeae1d;
8'hbe: crc32_byte_calc = 32'h2cd99e8b;
8'hbd: crc32_byte_calc = 32'hb5d0cf31;
8'hbc: crc32_byte_calc = 32'hc2d7ffa7;
8'hbb: crc32_byte_calc = 32'h5cb36a04;
8'hba: crc32_byte_calc = 32'h2bb45a92;
8'hb9: crc32_byte_calc = 32'hb2bd0b28;
8'hb8: crc32_byte_calc = 32'hc5ba3bbe;
8'hb7: crc32_byte_calc = 32'h5505262f;
8'hb6: crc32_byte_calc = 32'h220216b9;
8'hb5: crc32_byte_calc = 32'hbb0b4703;
8'hb4: crc32_byte_calc = 32'hcc0c7795;
8'hb3: crc32_byte_calc = 32'h5268e236;
8'hb2: crc32_byte_calc = 32'h256fd2a0;
8'hb1: crc32_byte_calc = 32'hbc66831a;
8'hb0: crc32_byte_calc = 32'hcb61b38c;
8'haf: crc32_byte_calc = 32'h4669be79;
8'hae: crc32_byte_calc = 32'h316e8eef;
8'had: crc32_byte_calc = 32'ha867df55;
8'hac: crc32_byte_calc = 32'hdf60efc3;
8'hab: crc32_byte_calc = 32'h41047a60;
8'haa: crc32_byte_calc = 32'h36034af6;
8'ha9: crc32_byte_calc = 32'haf0a1b4c;
8'ha8: crc32_byte_calc = 32'hd80d2bda;
8'ha7: crc32_byte_calc = 32'h48b2364b;
8'ha6: crc32_byte_calc = 32'h3fb506dd;
8'ha5: crc32_byte_calc = 32'ha6bc5767;
8'ha4: crc32_byte_calc = 32'hd1bb67f1;
8'ha3: crc32_byte_calc = 32'h4fdff252;
8'ha2: crc32_byte_calc = 32'h38d8c2c4;
8'ha1: crc32_byte_calc = 32'ha1d1937e;
8'ha0: crc32_byte_calc = 32'hd6d6a3e8;
8'h9f: crc32_byte_calc = 32'h60b08ed5;
8'h9e: crc32_byte_calc = 32'h17b7be43;
8'h9d: crc32_byte_calc = 32'h8ebeeff9;
8'h9c: crc32_byte_calc = 32'hf9b9df6f;
8'h9b: crc32_byte_calc = 32'h67dd4acc;
8'h9a: crc32_byte_calc = 32'h10da7a5a;
8'h99: crc32_byte_calc = 32'h89d32be0;
8'h98: crc32_byte_calc = 32'hfed41b76;
8'h97: crc32_byte_calc = 32'h6e6b06e7;
8'h96: crc32_byte_calc = 32'h196c3671;
8'h95: crc32_byte_calc = 32'h806567cb;
8'h94: crc32_byte_calc = 32'hf762575d;
8'h93: crc32_byte_calc = 32'h6906c2fe;
8'h92: crc32_byte_calc = 32'h1e01f268;
8'h91: crc32_byte_calc = 32'h8708a3d2;
8'h90: crc32_byte_calc = 32'hf00f9344;
8'h8f: crc32_byte_calc = 32'h7d079eb1;
8'h8e: crc32_byte_calc = 32'h0a00ae27;
8'h8d: crc32_byte_calc = 32'h9309ff9d;
8'h8c: crc32_byte_calc = 32'he40ecf0b;
8'h8b: crc32_byte_calc = 32'h7a6a5aa8;
8'h8a: crc32_byte_calc = 32'h0d6d6a3e;
8'h89: crc32_byte_calc = 32'h94643b84;
8'h88: crc32_byte_calc = 32'he3630b12;
8'h87: crc32_byte_calc = 32'h73dc1683;
8'h86: crc32_byte_calc = 32'h04db2615;
8'h85: crc32_byte_calc = 32'h9dd277af;
8'h84: crc32_byte_calc = 32'head54739;
8'h83: crc32_byte_calc = 32'h74b1d29a;
8'h82: crc32_byte_calc = 32'h03b6e20c;
8'h81: crc32_byte_calc = 32'h9abfb3b6;
8'h80: crc32_byte_calc = 32'hedb88320;
8'h7f: crc32_byte_calc = 32'hc0ba6cad;
8'h7e: crc32_byte_calc = 32'hb7bd5c3b;
8'h7d: crc32_byte_calc = 32'h2eb40d81;
8'h7c: crc32_byte_calc = 32'h59b33d17;
8'h7b: crc32_byte_calc = 32'hc7d7a8b4;
8'h7a: crc32_byte_calc = 32'hb0d09822;
8'h79: crc32_byte_calc = 32'h29d9c998;
8'h78: crc32_byte_calc = 32'h5edef90e;
8'h77: crc32_byte_calc = 32'hce61e49f;
8'h76: crc32_byte_calc = 32'hb966d409;
8'h75: crc32_byte_calc = 32'h206f85b3;
8'h74: crc32_byte_calc = 32'h5768b525;
8'h73: crc32_byte_calc = 32'hc90c2086;
8'h72: crc32_byte_calc = 32'hbe0b1010;
8'h71: crc32_byte_calc = 32'h270241aa;
8'h70: crc32_byte_calc = 32'h5005713c;
8'h6f: crc32_byte_calc = 32'hdd0d7cc9;
8'h6e: crc32_byte_calc = 32'haa0a4c5f;
8'h6d: crc32_byte_calc = 32'h33031de5;
8'h6c: crc32_byte_calc = 32'h44042d73;
8'h6b: crc32_byte_calc = 32'hda60b8d0;
8'h6a: crc32_byte_calc = 32'had678846;
8'h69: crc32_byte_calc = 32'h346ed9fc;
8'h68: crc32_byte_calc = 32'h4369e96a;
8'h67: crc32_byte_calc = 32'hd3d6f4fb;
8'h66: crc32_byte_calc = 32'ha4d1c46d;
8'h65: crc32_byte_calc = 32'h3dd895d7;
8'h64: crc32_byte_calc = 32'h4adfa541;
8'h63: crc32_byte_calc = 32'hd4bb30e2;
8'h62: crc32_byte_calc = 32'ha3bc0074;
8'h61: crc32_byte_calc = 32'h3ab551ce;
8'h60: crc32_byte_calc = 32'h4db26158;
8'h5f: crc32_byte_calc = 32'hfbd44c65;
8'h5e: crc32_byte_calc = 32'h8cd37cf3;
8'h5d: crc32_byte_calc = 32'h15da2d49;
8'h5c: crc32_byte_calc = 32'h62dd1ddf;
8'h5b: crc32_byte_calc = 32'hfcb9887c;
8'h5a: crc32_byte_calc = 32'h8bbeb8ea;
8'h59: crc32_byte_calc = 32'h12b7e950;
8'h58: crc32_byte_calc = 32'h65b0d9c6;
8'h57: crc32_byte_calc = 32'hf50fc457;
8'h56: crc32_byte_calc = 32'h8208f4c1;
8'h55: crc32_byte_calc = 32'h1b01a57b;
8'h54: crc32_byte_calc = 32'h6c0695ed;
8'h53: crc32_byte_calc = 32'hf262004e;
8'h52: crc32_byte_calc = 32'h856530d8;
8'h51: crc32_byte_calc = 32'h1c6c6162;
8'h50: crc32_byte_calc = 32'h6b6b51f4;
8'h4f: crc32_byte_calc = 32'he6635c01;
8'h4e: crc32_byte_calc = 32'h91646c97;
8'h4d: crc32_byte_calc = 32'h086d3d2d;
8'h4c: crc32_byte_calc = 32'h7f6a0dbb;
8'h4b: crc32_byte_calc = 32'he10e9818;
8'h4a: crc32_byte_calc = 32'h9609a88e;
8'h49: crc32_byte_calc = 32'h0f00f934;
8'h48: crc32_byte_calc = 32'h7807c9a2;
8'h47: crc32_byte_calc = 32'he8b8d433;
8'h46: crc32_byte_calc = 32'h9fbfe4a5;
8'h45: crc32_byte_calc = 32'h06b6b51f;
8'h44: crc32_byte_calc = 32'h71b18589;
8'h43: crc32_byte_calc = 32'hefd5102a;
8'h42: crc32_byte_calc = 32'h98d220bc;
8'h41: crc32_byte_calc = 32'h01db7106;
8'h40: crc32_byte_calc = 32'h76dc4190;
8'h3f: crc32_byte_calc = 32'hb6662d3d;
8'h3e: crc32_byte_calc = 32'hc1611dab;
8'h3d: crc32_byte_calc = 32'h58684c11;
8'h3c: crc32_byte_calc = 32'h2f6f7c87;
8'h3b: crc32_byte_calc = 32'hb10be924;
8'h3a: crc32_byte_calc = 32'hc60cd9b2;
8'h39: crc32_byte_calc = 32'h5f058808;
8'h38: crc32_byte_calc = 32'h2802b89e;
8'h37: crc32_byte_calc = 32'hb8bda50f;
8'h36: crc32_byte_calc = 32'hcfba9599;
8'h35: crc32_byte_calc = 32'h56b3c423;
8'h34: crc32_byte_calc = 32'h21b4f4b5;
8'h33: crc32_byte_calc = 32'hbfd06116;
8'h32: crc32_byte_calc = 32'hc8d75180;
8'h31: crc32_byte_calc = 32'h51de003a;
8'h30: crc32_byte_calc = 32'h26d930ac;
8'h2f: crc32_byte_calc = 32'habd13d59;
8'h2e: crc32_byte_calc = 32'hdcd60dcf;
8'h2d: crc32_byte_calc = 32'h45df5c75;
8'h2c: crc32_byte_calc = 32'h32d86ce3;
8'h2b: crc32_byte_calc = 32'hacbcf940;
8'h2a: crc32_byte_calc = 32'hdbbbc9d6;
8'h29: crc32_byte_calc = 32'h42b2986c;
8'h28: crc32_byte_calc = 32'h35b5a8fa;
8'h27: crc32_byte_calc = 32'ha50ab56b;
8'h26: crc32_byte_calc = 32'hd20d85fd;
8'h25: crc32_byte_calc = 32'h4b04d447;
8'h24: crc32_byte_calc = 32'h3c03e4d1;
8'h23: crc32_byte_calc = 32'ha2677172;
8'h22: crc32_byte_calc = 32'hd56041e4;
8'h21: crc32_byte_calc = 32'h4c69105e;
8'h20: crc32_byte_calc = 32'h3b6e20c8;
8'h1f: crc32_byte_calc = 32'h8d080df5;
8'h1e: crc32_byte_calc = 32'hfa0f3d63;
8'h1d: crc32_byte_calc = 32'h63066cd9;
8'h1c: crc32_byte_calc = 32'h14015c4f;
8'h1b: crc32_byte_calc = 32'h8a65c9ec;
8'h1a: crc32_byte_calc = 32'hfd62f97a;
8'h19: crc32_byte_calc = 32'h646ba8c0;
8'h18: crc32_byte_calc = 32'h136c9856;
8'h17: crc32_byte_calc = 32'h83d385c7;
8'h16: crc32_byte_calc = 32'hf4d4b551;
8'h15: crc32_byte_calc = 32'h6ddde4eb;
8'h14: crc32_byte_calc = 32'h1adad47d;
8'h13: crc32_byte_calc = 32'h84be41de;
8'h12: crc32_byte_calc = 32'hf3b97148;
8'h11: crc32_byte_calc = 32'h6ab020f2;
8'h10: crc32_byte_calc = 32'h1db71064;
8'h0f: crc32_byte_calc = 32'h90bf1d91;
8'h0e: crc32_byte_calc = 32'he7b82d07;
8'h0d: crc32_byte_calc = 32'h7eb17cbd;
8'h0c: crc32_byte_calc = 32'h09b64c2b;
8'h0b: crc32_byte_calc = 32'h97d2d988;
8'h0a: crc32_byte_calc = 32'he0d5e91e;
8'h09: crc32_byte_calc = 32'h79dcb8a4;
8'h08: crc32_byte_calc = 32'h0edb8832;
8'h07: crc32_byte_calc = 32'h9e6495a3;
8'h06: crc32_byte_calc = 32'he963a535;
8'h05: crc32_byte_calc = 32'h706af48f;
8'h04: crc32_byte_calc = 32'h076dc419;
8'h03: crc32_byte_calc = 32'h990951ba;
8'h02: crc32_byte_calc = 32'hee0e612c;
8'h01: crc32_byte_calc = 32'h77073096;
8'h00: crc32_byte_calc = 32'h00000000;
default: crc32_byte_calc = '0;
endcase
endfunction
logic [31:0] crc_d, crc_q;
logic crc_en;
logic [31:0] crc_stages[BytesPerWord + 1];
assign crc_en = set_crc_i | data_valid_i;
assign crc_stages[0] = crc_q;
for (genvar i = 0;i < BytesPerWord; ++i) begin : g_crc_stages
assign crc_stages[i + 1] =
{8'h00, crc_stages[i][31:8]} ^
crc32_byte_calc(crc_stages[i][7:0] ^ data_i[i * 8 +: 8]);
end
always_comb begin
if (set_crc_i) begin
crc_d = ~crc_in_i;
end else begin
crc_d = crc_stages[BytesPerWord];
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
crc_q <= 32'hFFFFFFFF;
end else if (crc_en) begin
crc_q <= crc_d;
end
end
assign crc_out_o = ~crc_q;
endmodule