Thursday, 7 September 2017

Verilog code for checksum

I have never used Verilog (well I am used to VerilogA), and back during my undergraduate days HDL was VHDL for me. The industry at large seems to prefer Verilog, and I decided to catch up on the basics before I head out to Leuven.
Looking for problem, I came across a slide from NCSU. The problem was:

//There are 9 bytes of data.
//The first byte is the packet identifier. 2'h55 indicates a valid data packet containing 7 data bytes and // one checksum byte is following.
//The next seven bytes are data bytes.
//The last byte is the checksum
//If the sum of the 7 data bytes truncated to 8 bits do not match the checksum byte,
//the error signal is to be asserted and kept high until the next valid data byte starts appearing

This was the code I wrote:

`timescale 1ns / 1ps
//There are 9 bytes of data.
//The first byte is the packet identifier. 2'h55 indicates a valid data packet is follwoing
//The next seven bytes are data bytes.
//The last byte is the checksum
//If the sum of the 7 data bytes truncated to 8 bits do not match the checksum byte,
//the error signal is to be asserted and kept high until the next valid data byte starts appearing
module check_sum(
    input clk,
    input reset_bar,
    input [7:0] data,
    output error
    );
    reg [7:0]internal_sum;
    reg [2:0]state_vec;
    reg [3:0]byte_count;
    reg error_state;
    always @(posedge clk or negedge reset_bar) begin
        if (~reset_bar) begin
            state_vec=3'b000;
            error_state=1'b0;
            internal_sum=0;
            byte_count=0;
        end
        else if (state_vec == 3'b000) begin
                //this means it is waiting for new data frame
                //check whether the data is 2'h55 or not.
                internal_sum=0; //since we are wiating for a new data frame, sum is set to zero
                if (data==8'b01010101)begin
                    state_vec=3'b001; //1 indicates that it is ready to receive the data
                    error_state=0;
                end
                else begin
                    state_vec=3'b100; //4 indicates that it is in invalid data frame and should be ignored
                end
                byte_count=0;
            end
        else if (state_vec==3'b001) begin
                //increment byte counter
                byte_count=byte_count+1;
                internal_sum=internal_sum+data;
                if (byte_count==4'b0111) begin
                    //all seven bytes have been received. the next byte will be the checksum
                    state_vec=3'b010; //a value of 2 for the state vector indicates that it is ready for checksum cehck.
                end
         end
         else if (state_vec==3'b010) begin
                //reset the byte count
                byte_count=4'b0000;
                if (internal_sum != data)
                    error_state=1'b1;
                else
                    error_state=1'b0;
                state_vec=3'b000;
         end
         else if (state_vec==3'b100) begin
                //nothing to do really other than increment the byte counter
                byte_count=byte_count+1;
                if (byte_count==4'b1000) 
                    //received all the 7 bytes of data plus one checksum byte
                    state_vec=3'b000;
                else
                    state_vec=3'b100;
         end
     end
    assign error=error_state?1'b1:1'b0;
     
endmodule


The test bench that I used was:
`timescale 1ns / 1ps
module test_check_sum;
    reg [7:0]data;
    reg reset_bar;
    reg clk;
    wire error;
    integer i;
    integer k;
    reg [7:0]data_sum;
    check_sum DUT (clk,reset_bar,data,error);
    initial begin
        reset_bar=1'b1;
        data_sum=0;
        #10
        reset_bar=1'b0;
        #10
        reset_bar=1'b1;
        #5
        //we will run the simulation for 5 different data packets.
        for(i=0;i<5;i=i+1) begin
            data_sum=0;
            //data=8'h55; //to indicate the start of the packet
            if (i==1)
                data=8'h56;
            else
                data=8'h55;
            #40
            for(k=1;k<=7;k=k+1) begin
                data=$urandom_range(0,255);
                data_sum=data_sum+data;
                #40;
            end
            data=data_sum+1;
            #40;
        end
    end
    always begin
        clk=1'b0;
        #45
        clk=1'b1;
        forever begin
            #20
            clk=~clk;
        end
    end    
 endmodule

Here is a snap of the waveform:


1 comment: