Lab 03
Introduction
Clock
We have first encounterd the clock in NUS CG2111A! Now we met them again! We can go back to review the notes from CG2111A to get a better view about the clock. Unlike the ATmega328p, our FPGA has a clock built in, which runs at 100 MHz — that is, it completes a full period (on and then off) 100 million times a second (or every 10 nanoseconds).
Registers
Register is something we have learned already from the textbook! Technically speaking, the register we used here is a 1-bit D Flip-Flop. And still remember the very important sentence about the D flip-flop?
A D flip-flop copies D to Q on the rising edge of the clock, and remembers its state at all other times until the next rising edge comes, then it will update its state.
That's essentially the soul of a D flip-flop/1-bit register! Now, let's look at the verilog implementation of register, remember that we have used an always statement.
The keyword
alwaysis as the name implies; it means that any behaviour defined inside this block will be repeated till the end of time (or until you turn off/reprogram the FPGA, whichever comes first). This is the same behaviour as combinational logic — once you define a combinational logic circuit, it performs the same function till the end of time.
And this is again the soul of an always statement, both in combinational and sequential logic.
Activity 1: Create a simple counter
Customized Speed Counter
Following the instructions on the lab manual strictly, the code for our simple counter will be as follows,
module Counter #(
parameter int OUTPUT_BITS = 8, // width of main counter
parameter int CLK_HZ = 100_000_000, // FPGA input clock frequency (100 MHz default)
parameter int TARGET_HZ = 4 // desired output frequency (Hz)
) (
input clk,
input rst, // active-low reset
input up_down, // 0 = count up, 1 = count down
output reg [OUTPUT_BITS-1:0] count
);
// Calculate number of input clock cycles per output increment
localparam int N_COUNTS = CLK_HZ / TARGET_HZ;
// Calculate number of bits needed for divider
localparam int N_BITS = $clog2(N_COUNTS);
// Clock divider counter
logic [N_BITS-1:0] clk_cnt;
always @(posedge clk) begin
// Main counter
if (!rst) begin
count <= 0;
clk_cnt <= 0;
end else begin
// Second counter
clk_cnt <= (clk_cnt == N_COUNTS - 1) ? 0 : (clk_cnt + 1);
if (clk_cnt == 0) count <= (up_down == 0) ? (count + 1) : (count - 1);
end
end
endmoduleCode Explanation
This is a template for a customized speed counter which can count at the specified
CLK_HZ.In the second counter, the checking condition is
N_COUNTS-1because you can think of the case when we reach the maximum, we still use one count to count to 0. Thus, we need to minus 1 fromN_COUNTS.
And follow the requirements for the testbench on the lab manual, we have our testbench to be,
Code Explanation
Note that in Line 21, the delay is
#10and not#1(specified in the document) as 1 nanosecnod is not enough to let the counter reach the first posedge ofclk. (See more from this issue)
Activity 2: Display the counter on seven-segment display
To get a preview of what we will design in this activity, please go to the last part.
Taking advantage of persistence of vision
We may have seen from Lab 02 that the seven-segment display can only display one unique digit at any time. However, we can play some tricks on our eyes. This is done by changing the display used very fast so that we can create the illusion of different displays showing different characters.

Putting everything together
Once again, before we make everything, make sure we are aware of what each module does, and the inputs and outputs of each module. And most importantly, bare in the golden rule about RTL Coding Steps!
RTL Code
Here, we will use the SevenSegDecoder.sv we have implemented in Lab 02 and the Counter.sv we have implemented in activity 1 in this lab. Besides that, we still need to design our own Top.sv and a SlowCounter.sv (to acheieve the persistence of vision mentioned above)
Code Explanation
In our slow counter, as specified by the design specification, we skip 2 and 5 in our case statement so that in our seven-segment display the digit 2 and 5 will be blank.
Constraints
In our constraints file, remember to enable the clk, which is from Line 6-10! This is very important and easy to forget as it is our first time to enable clk on our Nexys 4 FPGA! Not doing so will cause failure to generate the bitstream file!
The fruits of our labour
Last updated