while loops in Verilog

While Loops in Verilog

Verilog supports while loops much like other programming languages. In this assignment, you will design a thermometer encoder and decoder using while and for loops. A thermometer code is a vector representation where all bits are 1 up to the encoded value, and 0 above that value:

Decimal Thermometer
0 0000000
1 1000000
2 1100000
3 1110000
4 1111000
5 1111100
6 1111110
7 1111111

Thermometer codes are used in some output displays, and in some electronics such as high-speed “Flash” analog-to-digital converters.

Thermometer Encoder

To convert a binary number with K bits, the thermometer code needs W = 2K − 1 bits. So if K=4 then W=15.

module thermometer_encoder
  (
     input      [3:0]  a,
     output reg [14:0] q
   );

Next we’ll use a for loop to perform the encoding:

   integer    idx;
   
   always @(a) begin
      for (idx=0; idx<15; idx=idx+1) begin
         if (idx < a)
            q[idx] = 1;
         else
            q[idx] = 0;
         end
   end

Thermometer Decoder

To reverse the thermometer code, the input has W bits and the output should have K=log2(W+1) bits. So if W=15 then K=4. We will use a while loop to perform the decoding:

   integer     idx;
   
   always @(a) begin
      idx = 16;
      while ((a[idx-1] == 0)&&(idx > 0))
         idx = idx - 1;
      q = idx;
   end

In this loop, the index variable idx is initialized to the maximum value, and then decremented until a non-zero bit is detected. The output q is the index of the highest non-zero bit in a.

Testbench and `define

Open src/testbench.v and notice the first few lines:

`define K 4
`define W 2**`K-1

module testbench ();
   
   // DECLARE SIGNALS
   reg  clk;     
   reg  [`K-1:0]  a; 
   wire [`W-1:0]  b;
   wire [`K-1:0]  c;

In Verilog, the `define statement is analogous to #define in C. It defines a global macro treated as a constant by the simulator and synthesis tool. After `K is declared as a macro, any reference to `K is substituted with the macro text 4.

The next `define statement uses the exponentiation operator:

`define W 2**`K-1

Verilog permits the syntax A**B meaning AB. This syntax is usually non-synthesizable, but can be syntheisable if used to compute constants or parameters. The result `W is called a “design-time constant”, since it is computed before synthesis and does not change during operation of the module. The tool treats it like a number.

Assigned Tasks

Open src/thermometer_encoder.v and src/thermometer_decoder.v in a text editor. Make the following revisions:

Then edit src/testbench.v and use the defparam syntax to define set the module parameters:

   defparam TE1.W = `W;
   defparam TE1.K = `K;
   defparam TD1.W = `W;
   defparam TD1.K = `K;
   

Change `K to 5 and run the simulation. Verify that it works properly. Then change `K to 3 and verify again.

Next, create a top module in src/top.v to contain instances of both thermometer_encoder and thermometer_decoder. The top module should have inputs sw, sel, and output led. The top module should be designed to these specifications:

Modify src/testbench.v to fully test your design (test all possible values of sw and sel). Verify the design in simulation.

Create an XDC constraint file (copy from the Basys3_Master.xdc template) and a build.tcl script (copy from a previous assignment), implement the design and program onto the Basys3 board.

On the Basys3 board, test these cases:

  1. sel=0, a=7'b0000011
  2. sel=0, a=7'b0000110
  3. sel=1, a=7'b0011111
  4. sel=1, a=7'b0000111

Photograph the test cases and save the photos in the working directory as case1, case2, etc. Turn in your work using git:

git add case* src/*.v *.rpt *.txt *.tcl *.bit *.xdc
git commit . -m "Complete"
git push origin main

Indicate on Canvas that your assignment is done.