Verilog
We’ll be working in the verilog
directory.
There are some solutions in verilog/spoilers
, but as the name suggests, you
shouldn’t look there before trying to solve the exercises yourself.
Prerequisites
First, initialize the Git submodule with libraries:
git submodule update --init
You will need the following:
- An editor that understands Verilog. Atom or Sublime Text should be fine.
- Icarus Verilog. Your system should have it
packaged:
apt install iverilog
brew install icarus-verilog
- …
- Optionally GTKWave. This should also be available from your system.
Makefile targets
To run adder_tb.v
, use:
make run V=adder_tb.v
To run adder.v
and view the results in GTKWave, use:
make sim V=adder_tb.v
Adders
On paper
We’ll try to add some binary numbers (101010 + 111). How does it work? Draw a single bit adder circuit, and connect 4 of them to have a 4-bit adder.
Now we move on to hexadecimal addition. Try adding 7FFA + 3048. How does a single 4-bit adder look like, and how do we connect more of them?
Let’s look closer at a 4-bit adder. The adder will have the following ports:
- input numbers (4 bit):
x
,y
, - carry-in:
c_in
, - sum (4 bit):
s
, - carry-out:
c_out
.
Trace what it will do for some inputs (for instance, 10 + 8). How would we write the adder in pseudocode?
Now, let’s try to design the same for decimal digits and BCD (binary-coded decimals). What kind of inputs and outputs we’ll have? Again, let’s write pseudocode.
In Verilog
In adder.v
, there is a 4-bit and 8-bit adder implemented. Run the
testbench (make run V=adder_tb.v
) and see the values. View the
waveform (make sim V=adder_tb.v
).
Now, try to implement a BCD adder. Expand it to build a 4-digit (16-bit) BCD adder. Test it using the provided testbench.
Latch and flip-flop
Let’s go back to NAND game and examine latch and data flip-flop.
There is a simple data flip-flop (DFF) implemented in dff.v
. Let’s read it,
and draw a wave diagram.
Modify the testbench (dff_tb.v
) to check if it works as it should.
Now, create a data flip-flop with an en
(enable) input. The value should
change only if en
is set to 1. Test it using the provided testbench.
module dff_en(input wire clk,
input wire en,
input wire data,
output wire out);
Counter
Implement a counter:
module counter(input wire clk,
input wire en,
input wire rst,
output reg [3:0] count);
You can use the provided counter.v
and counter_tb.v
.
The counter should increase on a positive clock edge whenever en
(enable) is
set, and reset to 0 whenever rst
(reset) is set:
Clock divider
Given a clock signal, output a clock signal that is 4 times slower.
module clock_divider(input wire clk_in,
output wire clk_out);
In other words, we should get:
Can you do the same, but 1024 times slower? (1024 = 2 to the 10th power, or
1 << 10
).
Traffic light controller
module traffic(input wire clk,
input wire go,
output wire red,
output wire yellow,
output wire green);
You can use the provided traffic.v
and traffic_tb.v
.
- Initially, the
red
light should be lit (1). - When
go
is set to 1, you should light upred
andyellow
for 3 cycles, then switch togreen
. - When
go
is set back to 0, you should lightyellow
for 3 cycles, then switch tored
.
Parallel to serial
Write a module that receives an 8-bit value and converts it to single bits.
module serial(input wire clk,
input wire in,
input wire [7:0] data,
output wire ready,
output wire out);
- Normally,
out
should be 0. - The user should raise
in
to 1 for a single cycle, and setdata
to a desired value in the same cycle. After that,in
will go back to 0. - Then, during the following 8 cycles,
out
should contain consecutive bits ofdata
(highest to lowest). - After that,
out
should go back to 0. ready
should be 1 whenever we’re not sending, and 0 when we’re sending.
Memory module
Implement a 256-byte memory module with read and write ports.
module memory(input wire clk,
input wire ren,
input wire [7:0] raddr,
output reg [7:0] rdata,
input wire wen,
input wire [7:0] waddr,
input wire [7:0] wdata);
- When
ren
(read enable) is set, in the next cycle setrdata
to the byte atraddr
address. - When
wen
(write enable) is set, in the next cycle set the byte atwaddr
address towdata
. - Both operations (read and write) can happen in the same cycle.
Write a test bench. What will be the result of reading uninitialized memory? How to initialize the memory to 0?
Hint: You can use a $display
statement to print debug messages while the
module is working (for instance, "Storing byte XX at address YY"
).
Links
- Verilog cheatsheet (PDF)
- HDLBits - online, interactive Verilog exercises
- Verilog Beginner’s Tutorial by ZipCPU author