| // 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 |