0
votes

I am trying to simulate a code in ModelSim for 16-bit CRC generator of 8 bit data. The logic for generating CRC byte is below, 1. Create a 16 bit crc register and initialize it to all zero's. 2. Now compare each bit of the data byte with the bit 0 of crc register i.e. (data[counter] == crc[0]) 3. If the compare is true, then shift right crc register i.e. crc >> 1 and save it to crc register. 4. If the compare is false, then shift right crc register and xor the result with 16'h1021 (polynomial generator).

Now i am not sure if my implementation of iterating across the data byte through FOR loop inside the always block is correct; in my simulation, the for loop iterates through the data byte on the first positive edge of the clock as seen in the simulation block.

My results is also wrong for the CRC generation.

i.e. Data = 0xF881 Correct CRC = 0x1CED

Below is the Verilog Code (Serial_CRC) with test bench and the simulation results.

//http://www.asic-world.com/examples/verilog/serial_crc.html#Serial_CRC

`timescale 1ns/1ns
`define WIDTH 16
//**************************************************************************
module Serial_CRC_wTB();
//**************************************************************************

    reg in_enable;
    reg in_clk;
    reg in_rst_n;
    reg [`WIDTH-9:0] in_data;
    wire [`WIDTH-1:0] out_crcOutput;

    Serial_CRC TS (.i_data(in_data), .o_crcOutput(out_crcOutput), .i_clk(in_clk), .i_rst_n(in_rst_n), .i_enable(in_enable));

    initial
        begin
            in_clk = 1'b0 ;in_enable = 1'b0; in_rst_n = 1'b1;
            #1 in_rst_n = 1'b0;
            #2 in_rst_n = 1'b1; in_enable = 1'b1;
            @(negedge in_clk) in_data = 8'hF8;
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(negedge in_clk) in_data = 8'h81;
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            #20 $finish;
        end 

    always 
        #1 in_clk = ~in_clk;

endmodule // Serial_CRC_wTB


//**************************************************************************
module Serial_CRC (input [`WIDTH-9:0] i_data,input i_clk,input i_rst_n,input i_enable, output [`WIDTH-1:0] o_crcOutput);
//**************************************************************************

reg [`WIDTH-1:0] crc;
reg [`WIDTH-9:0] d; 

integer counter;

always @ (posedge i_clk)    begin
    if (~i_rst_n)   begin
        crc <= {16{1'b0}};
        d   <= {8{1'b0}};
    end 
    else if (i_rst_n && i_enable) begin
        d <= i_data;
        for (counter = 0 ; counter <= `WIDTH-9 ; counter = counter + 1) begin 
            if (d[counter] == crc[0])
                crc <= crc >> 1;
            else if (d[counter] != crc[0]) begin
                crc <= crc >> 1;
                crc <= crc ^ 16'h1021; 
            end // else if block
        end // for loop block
    end  // else if block
end // always block


assign o_crcOutput = crc;

endmodule // Serial_CRC

Snapshot from ModelSim

2

2 Answers

0
votes

i guess you misused non-blocking assignments in here:

           crc <= crc >> 1;
           crc <= crc ^ 16'h1021; 

The first line will not make an immediate change to crc and the second line will operate on the old value of crc

you need something like the following instead:

reg [`WIDTH-1:0]tmp ;
...
else if (d[counter] != crc[0]) begin
            tmp = crc >> 1;
            crc <= tmp ^ 16'h1021; 
        end // else if block 

or make it into a single line:

crc <= (crc >> 1) ^ 16'h1021; 
0
votes

I got it working through FSM and posting this answer is a learning curve, challenges still remain on initialization of CRC register and timing of introduction of the data byte.

The answer from the simulation is show here.

Crc Output :0000 Crc Output :0000 Crc Output :0000 Crc Output :0000 Crc Output :1021 Crc Output :0810 Crc Output :1429 Crc Output :0a14 Crc Output :152b Crc Output :0a95 Crc Output :156b Crc Output :1a94 Crc Output :0d4a Crc Output :06a5 Crc Output :1373 Crc Output :1998 Crc Output :1ced

//http://www.asic-world.com/examples/verilog/serial_crc.html#Serial_CRC

`timescale 1ns/1ns
`define WIDTH 16
//**************************************************************************
module Serial_CRC_wTB();
//**************************************************************************

    //reg in_enable;
    reg in_clk;
    reg in_rst_n;
    reg [`WIDTH-9:0] in_data;
    wire [`WIDTH-1:0] out_crcOutput;

    Serial_CRC TS (.i_data(in_data), .o_crcOutput(out_crcOutput), .i_clk(in_clk), .i_rst_n(in_rst_n));

    initial
        begin
            in_clk = 1'b0 ; in_rst_n = 1'b0; in_data = 8'hF8;
            #1 in_rst_n = 1'b0;
            #2 in_rst_n = 1'b1;
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput); // 0 
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput); // 1
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput); // 2
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput); // 3
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput); // 4
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput); // 5
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput); // 6
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput); // 7
            @(negedge in_clk) in_data = 8'h81;
            @(posedge in_clk) $display("Crc Output :%h",out_crcOutput); // 8
            //@(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
             @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
             @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
             @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
             @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
             @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
             @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
             @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
             @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
             //@(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            // @(posedge in_clk) $display("Crc Output :%h",out_crcOutput);
            #1 $finish;
        end 

    always 
        #1 in_clk = ~in_clk;

endmodule // Serial_CRC_wTB


//**************************************************************************
module Serial_CRC (input [`WIDTH-9:0] i_data,input i_clk,input i_rst_n, output [`WIDTH-1:0] o_crcOutput);
//**************************************************************************

    parameter         S0 = 3'b000;      //BIT[0]
    parameter         S1 = 3'b001;      //BIT[1]
    parameter         S2 = 3'b010;      //BIT[2]
    parameter         S3 = 3'b011;      //BIT[3]
    parameter         S4 = 3'b100;      //BIT[4]
    parameter         S5 = 3'b101;      //BIT[5]
    parameter         S6 = 3'b110;      //BIT[6]
    parameter         S7 = 3'b111;      //BIT[7]

    reg [2:0] curr_state;
    reg [2:0] next_state;

    reg [7:0] d;
    reg [15:0] crc;

    // Sequential logic for storing current state
    always @ (posedge i_clk, negedge i_rst_n) begin
        if (~i_rst_n) begin 
            curr_state <= S0;
            crc <= {16{1'b0}}; end
        else 
            curr_state <= next_state;
    end 

    always @ (curr_state, d) begin
        case (curr_state)
            S0: next_state <= S1;

            S1: next_state <= S2;

            S2: next_state <= S3;   

            S3: next_state <= S4;

            S4: next_state <= S5;

            S5: next_state <= S6;

            S6: next_state <= S7;

            S7: next_state <= S0;                       
        endcase // curr_state
    end 

 // need to fix the blocking versus the non-blocking case on the state variables
    // Output Logic
    always @ (posedge i_clk) begin 

        case(curr_state)
            S0: begin 
                d = i_data;

                if (d[0] == crc[0])
                    crc = crc >> 1'b1;
                else if (d[0] != crc[0]) begin
                        crc = crc >> 1'b1;
                        crc = crc ^ 16'h1021; end 
                    end // S0
            S1: begin 
                if (d[1] == crc[0])
                    crc = crc >> 1'b1;
                else if (d[1] != crc[0]) begin
                        crc = crc >> 1'b1;
                        crc = crc ^ 16'h1021; end 
                    end // S1
            S2: begin 
                if (d[2] == crc[0])
                    crc = crc >> 1'b1;
                else if (d[2] != crc[0]) begin
                        crc = crc >> 1'b1;
                        crc = crc ^ 16'h1021; end 
                    end // S2
            S3: begin 
                if (d[3] == crc[0])
                    crc = crc >> 1'b1;
                else if (d[3] != crc[0]) begin
                        crc = crc >> 1'b1;
                        crc = crc ^ 16'h1021; end 
                    end // S3
            S4: begin 
                if (d[4] == crc[0])
                    crc = crc >> 1'b1;
                else if (d[4] != crc[0]) begin
                        crc = crc >> 1'b1;
                        crc = crc ^ 16'h1021; end 
                    end // S4
            S5: begin 
                if (d[5] == crc[0])
                    crc = crc >> 1'b1;
                else if (d[5] != crc[0]) begin
                        crc = crc >> 1'b1;
                        crc = crc ^ 16'h1021; end 
                    end // S5
            S6: begin 
                if (d[6] == crc[0])
                    crc = crc >> 1'b1;
                else if (d[6] != crc[0]) begin
                        crc = crc >> 1'b1;
                        crc = crc ^ 16'h1021; end 
                    end // S6
            S7: begin 
                if (d[7] == crc[0])
                    crc = crc >> 1'b1;
                else if (d[7] != crc[0]) begin
                        crc = crc >> 1'b1;
                        crc = crc ^ 16'h1021; end 
                    end // S7
        endcase // curr_state
        end //always

assign o_crcOutput = crc;       
endmodule // Serial_CRC

And the simulation timing diagram. Snap 1

Snap2