`timescale 1ns / 1ps
// THIS IS GENERATED VERILOG CODE.
// https://bues.ch/h/crcgen
// 
// This code is Public Domain.
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted.
// 
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
// RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
// USE OR PERFORMANCE OF THIS SOFTWARE.

// CRC polynomial coefficients: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
//                              0xEDB88320 (hex)
// CRC width:                   32 bits
// CRC shift direction:         right (little endian)
// Input word width:            8 bits

module crc32(
	input wire clk,
	input wire rst,
	input wire clear,
	
	input wire [7:0] data_in,
	input wire crc_en,
	output wire [31:0] crc_out
);

	reg [31:0] result;

	function automatic [31:0] crc;
		 input [31:0] crcIn;
		 input [7:0] data_in;
	begin
		 crc[0] = crcIn[2] ^ crcIn[8] ^ data_in[2];
		 crc[1] = crcIn[0] ^ crcIn[3] ^ crcIn[9] ^ data_in[0] ^ data_in[3];
		 crc[2] = crcIn[0] ^ crcIn[1] ^ crcIn[4] ^ crcIn[10] ^ data_in[0] ^ data_in[1] ^ data_in[4];
		 crc[3] = crcIn[1] ^ crcIn[2] ^ crcIn[5] ^ crcIn[11] ^ data_in[1] ^ data_in[2] ^ data_in[5];
		 crc[4] = crcIn[0] ^ crcIn[2] ^ crcIn[3] ^ crcIn[6] ^ crcIn[12] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[6];
		 crc[5] = crcIn[1] ^ crcIn[3] ^ crcIn[4] ^ crcIn[7] ^ crcIn[13] ^ data_in[1] ^ data_in[3] ^ data_in[4] ^ data_in[7];
		 crc[6] = crcIn[4] ^ crcIn[5] ^ crcIn[14] ^ data_in[4] ^ data_in[5];
		 crc[7] = crcIn[0] ^ crcIn[5] ^ crcIn[6] ^ crcIn[15] ^ data_in[0] ^ data_in[5] ^ data_in[6];
		 crc[8] = crcIn[1] ^ crcIn[6] ^ crcIn[7] ^ crcIn[16] ^ data_in[1] ^ data_in[6] ^ data_in[7];
		 crc[9] = crcIn[7] ^ crcIn[17] ^ data_in[7];
		 crc[10] = crcIn[2] ^ crcIn[18] ^ data_in[2];
		 crc[11] = crcIn[3] ^ crcIn[19] ^ data_in[3];
		 crc[12] = crcIn[0] ^ crcIn[4] ^ crcIn[20] ^ data_in[0] ^ data_in[4];
		 crc[13] = crcIn[0] ^ crcIn[1] ^ crcIn[5] ^ crcIn[21] ^ data_in[0] ^ data_in[1] ^ data_in[5];
		 crc[14] = crcIn[1] ^ crcIn[2] ^ crcIn[6] ^ crcIn[22] ^ data_in[1] ^ data_in[2] ^ data_in[6];
		 crc[15] = crcIn[2] ^ crcIn[3] ^ crcIn[7] ^ crcIn[23] ^ data_in[2] ^ data_in[3] ^ data_in[7];
		 crc[16] = crcIn[0] ^ crcIn[2] ^ crcIn[3] ^ crcIn[4] ^ crcIn[24] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[4];
		 crc[17] = crcIn[0] ^ crcIn[1] ^ crcIn[3] ^ crcIn[4] ^ crcIn[5] ^ crcIn[25] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[4] ^ data_in[5];
		 crc[18] = crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[4] ^ crcIn[5] ^ crcIn[6] ^ crcIn[26] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[5] ^ data_in[6];
		 crc[19] = crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[5] ^ crcIn[6] ^ crcIn[7] ^ crcIn[27] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[5] ^ data_in[6] ^ data_in[7];
		 crc[20] = crcIn[3] ^ crcIn[4] ^ crcIn[6] ^ crcIn[7] ^ crcIn[28] ^ data_in[3] ^ data_in[4] ^ data_in[6] ^ data_in[7];
		 crc[21] = crcIn[2] ^ crcIn[4] ^ crcIn[5] ^ crcIn[7] ^ crcIn[29] ^ data_in[2] ^ data_in[4] ^ data_in[5] ^ data_in[7];
		 crc[22] = crcIn[2] ^ crcIn[3] ^ crcIn[5] ^ crcIn[6] ^ crcIn[30] ^ data_in[2] ^ data_in[3] ^ data_in[5] ^ data_in[6];
		 crc[23] = crcIn[3] ^ crcIn[4] ^ crcIn[6] ^ crcIn[7] ^ crcIn[31] ^ data_in[3] ^ data_in[4] ^ data_in[6] ^ data_in[7];
		 crc[24] = crcIn[0] ^ crcIn[2] ^ crcIn[4] ^ crcIn[5] ^ crcIn[7] ^ data_in[0] ^ data_in[2] ^ data_in[4] ^ data_in[5] ^ data_in[7];
		 crc[25] = crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[5] ^ crcIn[6] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[5] ^ data_in[6];
		 crc[26] = crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[4] ^ crcIn[6] ^ crcIn[7] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[6] ^ data_in[7];
		 crc[27] = crcIn[1] ^ crcIn[3] ^ crcIn[4] ^ crcIn[5] ^ crcIn[7] ^ data_in[1] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[7];
		 crc[28] = crcIn[0] ^ crcIn[4] ^ crcIn[5] ^ crcIn[6] ^ data_in[0] ^ data_in[4] ^ data_in[5] ^ data_in[6];
		 crc[29] = crcIn[0] ^ crcIn[1] ^ crcIn[5] ^ crcIn[6] ^ crcIn[7] ^ data_in[0] ^ data_in[1] ^ data_in[5] ^ data_in[6] ^ data_in[7];
		 crc[30] = crcIn[0] ^ crcIn[1] ^ crcIn[6] ^ crcIn[7] ^ data_in[0] ^ data_in[1] ^ data_in[6] ^ data_in[7];
		 crc[31] = crcIn[1] ^ crcIn[7] ^ data_in[1] ^ data_in[7];
	end
	endfunction

	always @(posedge clk) begin
	 if(rst | clear) begin
		result <= 32'hFFFFFFFF;
	 end
	 else begin
		result <= crc_en ? crc(result, data_in) : result;
	 end
	end // always
	
	assign crc_out = ~result;
endmodule // crc32
