while
loops in
VerilogVerilog 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.
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)
[idx] = 1;
qelse
[idx] = 0;
qend
end
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
= 16;
idx while ((a[idx-1] == 0)&&(idx > 0))
= idx - 1;
idx = idx;
q 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
.
`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.
Open src/thermometer_encoder.v
and src/thermometer_decoder.v
in a text editor. Make the following revisions:
K
and W
K
and W
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:
`K=3
sw
to the lowest seven
(right-most) switchessel
to the highest
switch (15)led
to the lowest seven
LEDssel
is 0:
a
is assigned the lowest
three switch valuesled
is assigned b
sel
is 1:
b
is assigned the seven
switch values (bypassing the encoder)led
are assigned c
, and the higher
bits are zero.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:
sel=0
,
a=7'b0000011
sel=0
,
a=7'b0000110
sel=1
,
a=7'b0011111
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.