I try to create a CRC module on Verilog.
The CRC calculating use an LFSR and can be fully-sequential (with two cycles), semi-sequential (with one cycle) or parallel. I have already made sequential module. And I try to create a fully-parallel. There is some code-generators for fixed methods (like "CRC-16 modbus" or "CRC-32 Ethernet"). But I want to create an universal parametrizade parallel module.
With for-loop expression I create a prametrized LFSR.
module main
#(
parameter LFSR_SIZE = 16,
parameter START_VALUE = 'hFFFF,
parameter POLYNOME = 'h8005)
(
input clk,
input n_reset,
output reg [LFSR_SIZE-1:0]lfsr);
integer lfsr_index;
always @(posedge clk) begin
if(n_reset) begin
lfsr[0] <= lfsr[LFSR_SIZE - 1];
for(lfsr_index = 1; lfsr_index < LFSR_SIZE; lfsr_index = lfsr_index + 1) begin
if( ((1 << lfsr_index) & POLYNOME) == 0) begin
lfsr[lfsr_index] <= lfsr[lfsr_index - 1];
end
else begin
lfsr[lfsr_index] <= lfsr[lfsr_index - 1] ^ lfsr[LFSR_SIZE - 1];
end
end
end
else begin
lfsr <= START_VALUE;
end
end
endmodule
Is it possible to generate number of shifts of the LFSR with a nested loop (two loops, one inside other)? If answer is "no" does the nested loop usefull expression in some case?
-
\$\begingroup\$ What's wrong with simply nesting loops if that's what you want? I've never used Verilog but it works fine in VHDL so it ought to be OK. \$\endgroup\$user16324– user163242020年10月05日 11:25:15 +00:00Commented Oct 5, 2020 at 11:25
-
\$\begingroup\$ @Brian Drummond Sorry, I'm not good at terminology. I use the word "folded" instead of "nested". \$\endgroup\$Arseniy– Arseniy2020年10月05日 11:31:19 +00:00Commented Oct 5, 2020 at 11:31
1 Answer 1
The essential thing of a for-loop in HDL is the nonblocking assignment. With nonblocking assignments you can direct some wires through the loop and direct other wires around the loop.
data_internal = data_in;
crc_shift = crc_internal ^ (data_internal << (CRC_SIZE - DATA_SIZE));
for(int data_index = 0; data_index < DATA_SIZE; data_index++) begin
msb = crc_shift[CRC_SIZE-1];
crc_lfsr = (crc_shift << 1);
for(int crc_index = 1; crc_index < CRC_SIZE; crc_index++) begin
if(((1 << crc_index) & POLYNOME) != 0) begin
crc_lfsr[crc_index] = crc_lfsr[crc_index] ^ msb;
end
end
crc_lfsr[0] = msb;
crc_shift = crc_lfsr;
end
crc_internal = crc_shift;
crc_out = crc_shift;
But in you case there is no need to use two cycles. You can replace the inner cycle with the following expression:
crc_lfsr = crc_lfsr ^ ({CRC_SIZE{msb}} & POLYNOME);
Completely it will look like this:
module main
#(
parameter IS_CRC_REVERSED = 1,
parameter IS_DATA_REVERSED = 1,
parameter DATA_SIZE = 8,
parameter CRC_SIZE = 16,
parameter START_VALUE = 'hFFFF,
parameter POLYNOME = 'h8005)
(
input clk,
input n_reset,
input [DATA_SIZE-1:0]data_in,
output reg [CRC_SIZE-1 :0]crc_out);
reg [CRC_SIZE-1 :0]crc_internal;
reg [DATA_SIZE-1:0]data_internal;
reg msb;
reg [CRC_SIZE-1 :0]crc_shift;
reg [CRC_SIZE-1 :0]crc_lfsr;
always @(posedge clk) begin
if(n_reset) begin
// data reverse
if(IS_DATA_REVERSED) begin
for(int i = 0; i < DATA_SIZE; i++) begin
data_internal[i] = data_in[DATA_SIZE - 1 - i];
end
end
else begin
data_internal = data_in;
end
// CRC calculating
crc_shift = crc_internal ^ (data_internal << (CRC_SIZE - DATA_SIZE));
for(int data_index = 0; data_index < DATA_SIZE; data_index++) begin
msb = crc_shift[CRC_SIZE-1];
crc_lfsr = (crc_shift << 1);
crc_lfsr = crc_lfsr ^ ({CRC_SIZE{msb}} & POLYNOME);
crc_lfsr[0] = msb;
crc_shift = crc_lfsr;
end
crc_internal = crc_shift;
// CRC reverse
if(IS_CRC_REVERSED) begin
for(int i = 0; i < CRC_SIZE; i++) begin
crc_out[i] = crc_shift[CRC_SIZE - 1 - i];
end
end
else begin
crc_out = crc_shift;
end
end
else begin
crc_internal = START_VALUE;
end
end
endmodule