ossc/ip/nios2_hw_crc/hdl/CRC_Component.v

315 lines
12 KiB
Verilog

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