Verilog Coding Tips and Tricks: November 2017

Sunday, November 5, 2017

File Reading and Writing(line by line) in Verilog - Part 2

File reading and writing is a very useful thing to know in Verilog. The possibility to read test input values from files, and write output values for later verification makes testbench codes easy to write and understand.

There are few ways to read or write files in Verilog. I have already explained one method in my last post, File Reading and Writing in Verilog - Part 1. The method described in this new post will help you to read the contents of a file line by line, instead of reading everything together. This is helpful when the size of file is too big.

In this post, we will learn:
  • How to read hexadecimal/binary/decimal values from a file using fopen and fscanf function.
  • How to write a file with hexadecimal/binary/decimal values using fopen and fdisplay.

Verilog code for File Read and Write:

`timescale 1ns / 1ps

module tb();

    reg [7:0] A; //register declaration for storing each line of file.
    integer outfile0,outfile1,outfile2,outfile3; //file descriptors

initial begin
    
    //The $fopen function opens a file and returns a multi-channel descriptor 
    //in the format of an unsized integer. 
    outfile0=$fopen("A_hex.txt","r");   //"r" means reading and "w" means writing
    outfile1=$fopen("A_write_dec.txt","w");
    outfile2=$fopen("A_write_bin.txt","w");
    outfile3=$fopen("A_write_hex.txt","w");
    
    //read the contents of the file A_hex.txt as hexadecimal values into register "A".
    while (! $feof(outfile0)) begin //read until an "end of file" is reached.
        $fscanf(outfile0,"%h\n",A); //scan each line and get the value as an hexadecimal
    //Write the read value into text files.
        $fdisplay(outfile1,"%d",A); //write as decimal
        $fdisplay(outfile2,"%b",A); //write as binary
        $fdisplay(outfile3,"%h",A); //write as hexadecimal
        #10;
    end 
    //once reading and writing is finished, close all the files.
    $fclose(outfile0);
    $fclose(outfile1);
    $fclose(outfile2);
    $fclose(outfile3);
    //wait and then stop the simulation.
    #100;
    $stop;
end    
      
endmodule

The above code is for reading a hexadecimal file and writing hex, binary and decimal numbers to a file. But with small changes we can make it read binary or decimal numbers too.

For Reading Binary numbers from the file,

Replace the line outfile0=$fopen("A_hex.txt","r");
with    outfile0=$fopen("A_bin.txt","r");     to change the name of the file.
Replace the line $fscanf(outfile0,"%h\n",A);
with    $fscanf(outfile0,"%b\n",A);     to change the type of data read from the file.


Similarly for Reading Decimal numbers from the file, 

Replace the line outfile0=$fopen("A_hex.txt","r");
with    outfile0=$fopen("A_dec.txt","r");     to change the name of the file.
Replace the line $fscanf(outfile0,"%h\n",A);
with    $fscanf(outfile0,"%d\n",A);     to change the type of data read from the file.


 That's all! The output files should look the same in both the cases.

A screenshot of input files and output files is given below:


The input files can be downloaded from here,



The code was tested using Xilinx ISE 14.6 tool.

File Reading and Writing in Verilog - Part 1

File reading and writing is a very useful thing to know in Verilog. The possibility to read test input values from files, and write output values for later verification makes testbench codes easy to write and understand.

There are few ways to read or write files in Verilog. So I will explain the whole thing in few different posts. In this first part we will learn the following things,

  • How to read hexadecimal values from a file using readmemh function.
  • How to read binary values from a file using readmemb function.
  • How to write a file with binary values using fopen and fdisplay.
  • How to write a file with decimal values using fopen and fdisplay.
  • How to write a file with hexadecimal values using fopen and fdisplay.

Verilog code for File Read and Write:

`timescale 1ns / 1ps

module tb();

    reg [7:0] A [0:15]; //memory declaration for storing the contents of file.
    integer outfile1,outfile2,outfile3; //file descriptors
    integer i;  //index used in "for" loop

initial begin
    //read the contents of the file A_hex.txt as hexadecimal values into memory "A".
    $readmemh("A_hex.txt",A);
    //The $fopen function opens a file and returns a multi-channel descriptor 
    //in the format of an unsized integer. 
    outfile1=$fopen("A_write_dec.txt","w");
    outfile2=$fopen("A_write_bin.txt","w");
    outfile3=$fopen("A_write_hex.txt","w");
    
    //Write one by one the contents of vector "A" into text files.
    for (= 0; i < 16; i = i +1) begin
        $fdisplay(outfile1,"%d",A[i]);  //write as decimal
        $fdisplay(outfile2,"%b",A[i]);  //write as binary
        $fdisplay(outfile3,"%h",A[i]);  //write as hexadecimal
    end 
    //once writing is finished, close all the files.
    $fclose(outfile1);
    $fclose(outfile2);
    $fclose(outfile3);
    //wait and then stop the simulation.
    #100;
    $stop;
end 

Now if you want to read a binary file instead of hex file you just have to replace a single line in the above code,

Replace the line $readmemh("A_hex.txt",A);
with $readmemb("A_bin.txt",A);

 That's all! The output files should look the same in both the cases.

A screenshot of input files and output files are given below:


The input files can be downloaded from here,

The code was tested using Xilinx ISE 14.6 tool.

Saturday, November 4, 2017

Count the number of 1's in a Binary number - Verilog Implementation with Testbench

Suppose you have a binary number, how do you count the number of one's in it? There are more than one way to do it. We will see two ways to do it and compare their performances.

Let's take a 16 bit binary number. The output of our design will have a width of 5 bits, to include the maximum value of output, which is 16("10000").

For example,

Input = "1010_0010_1011_0010" =>  Output = "00111" ( 7 in decimal)
Input = "1110_1010_1001_1010" =>  Output = "01001" ( 9 in decimal)
Input = "0011_0110_1000_1011" =>  Output = "01000" ( 8 in decimal)

Design 1 - A simple Verilog code can be written to achieve this:

module num_ones_for(
    input [15:0] A,
    output reg [4:0] ones
    );

integer i;

always@(A)
begin
    ones = 0;  //initialize count variable.
    for(i=0;i<16;i=i+1)   //check for all the bits.
        if(A[i] == 1'b1)    //check if the bit is '1'
            ones = ones + 1;    //if its one, increment the count.
end

endmodule

The code isn't that big and the logic is easy to understand. But it's less efficient and uses much more resources than the customized design I will present next.

Another way to achieve our purpose, would be to add all the bits in our input. Think of it as a sequence of 16 one bit-adders. The zeros in the input vector will not change the sum, and effectively we get the sum as the number of ones in the vector.

***Design 2 -See the Verilog code below to get what I meant:

module num_ones_for(
    input [15:0] A,
    output reg [4:0] ones
    );

integer i;

always@(A)
begin
    ones = 0;  //initialize count variable.
    for(i=0;i<16;i=i+1)   //for all the bits.
        ones = ones + A[i]; //Add the bit to the count.
end

endmodule


Testbench(same for both the designs):

module tb;

    // Inputs
    reg [15:0] A;

    // Outputs
    wire [4:0] ones;

    // Instantiate the Unit Under Test (UUT)
    num_ones_for uut (
        .A(A), 
        .ones(ones)
    );

    initial begin
        A = 16'hFFFF;   #100;
        A = 16'hF56F;   #100;
        A = 16'h3FFF;   #100;
        A = 16'h0001;   #100;
        A = 16'hF10F;   #100;
        A = 16'h7822;   #100;
        A = 16'h7ABC;   #100;   
    end
      
endmodule

Well, design 2 looks much more simpler than design 1 and the synthesis results showed that its much more faster and uses less number of LUT's. See the table below to see how the performance have improved.

Comparison:-

Name of Design
Combination delay
Number of Slice LUT’s used
Design 1
5.632 ns
47
Design 2
2.597 ns
20
As you can see Design 2 is much better than Design 1.