/* Legal Notice: (C)2006 Altera Corporation. All rights reserved. Your use of Altera Corporation's design tools, logic functions and other software and tools, and its AMPP partner logic functions, and any output files any of the foregoing (including device programming or simulation files), and any associated documentation or information are expressly subject to the terms and conditions of the Altera Program License Subscription Agreement or other applicable license agreement, including, without limitation, that your use is for the sole purpose of programming logic devices manufactured by Altera and sold by Altera or its authorized distributors. Please refer to the applicable agreement for further details. */ /* This component supports 8, 16, 24, and 32 bit little endian data and any CRC standard between 1 to 128 bits. Through parameterization you can change the CRC standard which will take effect after you regenerate your system in SOPC Builder. Register Map: 000 -> reset the CRC peripheral to the inital value (data and byte enables ignored) 001 -> data write between 1-32 bits 010 -> reserved 011 -> reserved 100 -> read bits 1-32 of the crc result 101 -> read bits 33-64 of the crc result (where applicable) 110 -> read bits 65-96 of the crc result (where applicable) 111 -> read bits 97-128 of the crc result (where applicable) Write latency = 0 Read latency = 1 Note: This component uses four blocks of eight bits of data in cascade. To improve the timing of logic you can create seperate cascades for 8, 16, 24, and 32 bit data which will allow for smaller area and a shorter combinational depth. Since CRC logic consumes power even when not in use you can also add a logic disable feature using the chipselect signal. Even though the registered CRC value is held constant when the circuit is not in use the input data will change during this time and cause the CRC cascade logic to react. */ module CRC_Component (clk, reset, address, writedata, byteenable, write, read, chipselect, readdata); /* Using these parameters you can create any CRC ranging from one bit (parity checker) up to 128 bits. The following list describes the function of each parameter: crc_width: The width of the registered CRC result, this value is typically apart of the name of the standard (CRC32 is 32 bits wide). Adjusting this value will impact the logic resource usage. polynomial_initial: The initial value set for the CRC result register. By writing any data to address 0 this value will be stored in the result register thereby clearing any previously existing value. This value must be the same width as 'crc_width' polynomial: This is the divisor value used on the input data. Typically shown in polynomial format the value symbolizes the placement of xor operation on the input data. In synthesis, the polynomial bits that are '1' will create a not gate, whereas the bits that are '0' will simply create a wire. Even with 32 stages of these operations cascaded, the simple logic will not become a significant factor on logic utilization or fmax. This value must be the same width as 'crc_width' reflected_input: Some CRC standards require that all the input bits be reflected around the center point. This option is enabled with '1' and disabled with '0'. Typically this option is enabled or disabled with 'reflected_output'. reflected_output: Some CRC standards require that all the output bits be reflected around the center point. This operation occurs before the final optional xor output step. This option is enabled with '1' and disabled with '0'. Typically this option is enabled or disabled with 'reflected_input' (to undo the input reversal typically). xor_output: This is the value used to bitwise xor the CRC result. Most standards use either all zeros or all ones for this value. When zeros are used the CRC result is passed directly and when ones are used the CRC result is inverted. Since it's no mandatory that this value be all ones or zeros, this operation occurs before the output reflection when applicable. */ parameter crc_width = 32; parameter polynomial_inital = 32'hFFFFFFFF; parameter polynomial = 32'h04C11DB7; parameter reflected_input = 1; parameter reflected_output = 1; parameter xor_output = 32'hFFFFFFFF; input clk; input reset; input [2:0] address; input [31:0] writedata; input [3:0] byteenable; input write; input read; input chipselect; output [31:0] readdata; reg [crc_width-1:0] crc_value; wire [crc_width-1:0] poly = polynomial; wire [crc_width-1:0] cascade [3:0]; wire [7:0] block0_data, block1_data, block2_data, block3_data; wire [crc_width-1:0] result, result_xored; wire [31:0] mux_result; reg [31:0] readdata; /* Some standards like CRC16 and CRC32 require this bitreversal for serial devices like ethernet, uarts, usb, etc... */ genvar index; generate if (reflected_input == 1) begin for(index = 0; index < 8; index = index + 1) begin: input_reflection assign block0_data[index] = writedata[7-index]; assign block1_data[index] = writedata[15-index]; assign block2_data[index] = writedata[23-index]; assign block3_data[index] = writedata[31-index]; end end else begin assign block0_data = writedata[7:0]; assign block1_data = writedata[15:8]; assign block2_data = writedata[23:16]; assign block3_data = writedata[31:24]; end endgenerate /* Control for the registered events. It assumes that either 8, 16, 24, or 32 bit data is being written using byte enables. It is important that the data be in little endian format and no gaps of byte enables be present (like 1011 or 1101 for example) */ always @ (posedge clk or posedge reset) begin if(reset == 1) begin crc_value <= 0; end else begin if(write && chipselect && (address == 3'b000)) begin crc_value <= polynomial_inital; // reset the crc to the initial value end else if(write && chipselect && (address == 3'b001)) begin if(byteenable == 4'b0001) // 8 bit data input begin crc_value <= cascade[0]; end else if(byteenable == 4'b0011) // 16 bit data input begin crc_value <= cascade[1]; end else if(byteenable == 4'b0111) // 24 bit data input begin crc_value <= cascade[2]; end else if(byteenable == 4'b1111) // 32 bit data input begin crc_value <= cascade[3]; end end end end /* four stages of cascade blocks (each block is crc_width x 8 bits) */ XOR_Shift_Block cascade_block0(.block_input(crc_value), .poly(poly), .data_input(block0_data), .block_output(cascade[0])); defparam cascade_block0.crc_width = crc_width; XOR_Shift_Block cascade_block1(.block_input(cascade[0]), .poly(poly), .data_input(block1_data), .block_output(cascade[1])); defparam cascade_block1.crc_width = crc_width; XOR_Shift_Block cascade_block2(.block_input(cascade[1]), .poly(poly), .data_input(block2_data), .block_output(cascade[2])); defparam cascade_block2.crc_width = crc_width; XOR_Shift_Block cascade_block3(.block_input(cascade[2]), .poly(poly), .data_input(block3_data), .block_output(cascade[3])); defparam cascade_block3.crc_width = crc_width; /* Some standards like CRC16 and CRC32 require this bitreversal. This is to better support serial devices like uarts, ethernet, usb, etc...) */ generate if (reflected_output == 1) begin for(index = 0; index < crc_width; index = index + 1) begin: output_reflection32 assign result[index] = crc_value[(crc_width-1)-index]; end end else begin assign result = crc_value; end endgenerate /* This final xor operation occurs after the bit swap */ assign result_xored = result ^ xor_output; /* Generates the appropriate MUX logic depending on the CRC width */ generate if((crc_width > 32) && (crc_width < 65)) begin assign mux_result = (address == 3'b100)? result_xored[31:0] : result_xored[crc_width-1:32]; end else if((crc_width > 64) && (crc_width < 97)) begin assign mux_result = (address == 3'b100)? result_xored[31:0] : ((address == 3'b101)? result_xored[63:32] : result_xored[crc_width-1:64]); end else if((crc_width > 96) && (crc_width < 129)) begin assign mux_result = (address == 3'b100)? result_xored[31:0] : ((address == 3'b101)? result_xored[63:32] : ((address == 3'b110)? result_xored[95:64] : result_xored[crc_width-1:96])); end else begin assign mux_result = result_xored; end endgenerate /* Registering the return path of the CRC data (32 bits of it) */ always @ (posedge clk or posedge reset) begin if(reset == 1) begin readdata <= 0; end else if((read == 1) && (chipselect == 1)) begin readdata <= mux_result; end end endmodule /* a single cascade block of width: crc_width and a length of eight input bits */ module XOR_Shift_Block(block_input, poly, data_input, block_output); parameter crc_width = 32; input [(crc_width-1):0] block_input; input [(crc_width-1):0] poly; input [7:0] data_input; output [(crc_width-1):0] block_output; wire [(crc_width-1):0] cascade [7:0]; XOR_Shift bit_0(.stage_input(block_input), .poly(poly), .new_bit(data_input[7]), .stage_output(cascade[0])); defparam bit_0.crc_width = crc_width; XOR_Shift bit_1(.stage_input(cascade[0]), .poly(poly), .new_bit(data_input[6]), .stage_output(cascade[1])); defparam bit_1.crc_width = crc_width; XOR_Shift bit_2(.stage_input(cascade[1]), .poly(poly), .new_bit(data_input[5]), .stage_output(cascade[2])); defparam bit_2.crc_width = crc_width; XOR_Shift bit_3(.stage_input(cascade[2]), .poly(poly), .new_bit(data_input[4]), .stage_output(cascade[3])); defparam bit_3.crc_width = crc_width; XOR_Shift bit_4(.stage_input(cascade[3]), .poly(poly), .new_bit(data_input[3]), .stage_output(cascade[4])); defparam bit_4.crc_width = crc_width; XOR_Shift bit_5(.stage_input(cascade[4]), .poly(poly), .new_bit(data_input[2]), .stage_output(cascade[5])); defparam bit_5.crc_width = crc_width; XOR_Shift bit_6(.stage_input(cascade[5]), .poly(poly), .new_bit(data_input[1]), .stage_output(cascade[6])); defparam bit_6.crc_width = crc_width; XOR_Shift bit_7(.stage_input(cascade[6]), .poly(poly), .new_bit(data_input[0]), .stage_output(cascade[7])); defparam bit_7.crc_width = crc_width; assign block_output = cascade[7]; endmodule /* performs the 'new_bit' stuffing, shifting, and XOR operations for a single input bit */ module XOR_Shift (stage_input, poly, new_bit, stage_output); parameter crc_width = 32; input [crc_width-1:0] stage_input; input [crc_width-1:0] poly; input new_bit; output [crc_width-1:0] stage_output; assign stage_output[0] = new_bit ^ stage_input[crc_width-1]; assign stage_output[crc_width-1:1] = stage_input[crc_width-2:0] ^ ({crc_width-1{stage_output[0]}} & poly[crc_width-1:1]); endmodule