Verilog – How to Create a Nested For-Loop in Verilog

crclfsrverilog

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?

Best Answer

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