Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: THEend8_
DS 2023 Project Assignment
According to Wikipedia, the first digital electronic watch was made in 1970, as a pro-
totype, and was available to the consumer in 1972. By the 1980s, digital watches were
ubiquitous. Back then, I remember a friend’s watch having the game Pac-Man on it.
The aim of this project, which comprises four assignments, is to design and implement
the functionality of a watch, just like digital watches of old. This includes a clock (with
the ability to set the time), an alarm, a stop-watch, a timer and possibly a game or
two.
This project follows on from the Practical Assignments 1 to 4. The skills learnt there
will be needed here.
Report Requirements
Refer to Practical Assignment 1 for report requirements.
Final Project Submission
In addition to the four project reports, you will also be required to submit your Quartus
project containing your final code, as a single Zip archive.
The Importance of Debugging
An essential part of being a good programmer is having the ability to find where the
mistakes are with your own code. Debugging is an essential skill to have. The lectures
and practical assignments have demonstrated how test benches along with $display
1
statements allow us to probe what is happening in the code. Another trick is developing
code one small step at a time and testing at each step, so if the code suddenly stops
working, you know it has to do with the last small step. If you are faced with a larger
chunk of code that is not working, then break it into smaller parts and test each part.
1 Time Display
1.1 Seconds Display
Our first objective is to implement a counter that counts from 0 to 59 once a second,
displaying the result to HEX[1] and HEX[0]. Forethought suggests it would be useful to
have generic up/down counters that can be used for other purposes (such as a stop-watch
with 1/100th of a second accuracy and a countdown timer).
Verilog has a parametrised module feature that allows us to create a family of modules.
This will allow us to specify what number the counter counts to. A minor challenge
though is that the number of bits needed to store the count will depend on this maximum
value.
Task 1
Write down a formula for the number of bits needed to store any number between
0 and N inclusive. You may make use of the function “ceil” which rounds a
number up to the nearest integer as well as any other standard functions.
Hint: With n bits, we can store any number between 0 and 2n − 1 inclusive.
Run the following code in an online Verilog simulator.
1 module test;
2 reg clk = 0;
3 initial forever #1 clk = !clk;
4
5 // Change the value of N
6 localparam N = 12;
7 localparam BW = $clog2(N+1);
8 wire [BW -1:0] cnt;
9 Counter #(. MAX(N), .WIDTH(BW))
10 cntr(.clk(clk), .enable(1’b1), .cnt(cnt ));
11
12 initial begin
13 #0 $display(cnt);
14 repeat (2*N+1)
15 #2 $display(cnt);
16 $stop;
17 end
2
18 endmodule
19
20 module Counter
21 #( parameter MAX=1, WIDTH =1) (
22 input clk ,
23 input enable ,
24 output reg [WIDTH -1:0] cnt
25 );
26
27 initial cnt = 0;
28
29 reg [WIDTH -1:0] next_cnt;
30
31 always @(posedge clk)
32 if (enable) cnt <= next_cnt;
33
34 always @(*)
35 next_cnt = (cnt == MAX) ? 1’d0 : (cnt + 1’d1);
36 endmodule
Task 2
Explain all aspects of the above code. Do not be afraid to google things like
“$clog2 verilog”.
Add an extra parameter to Counter, called UP. If UP is true (the default) then the
counter should count up; if UP is false the counter should count down (e.g., 9 8 7 6 5 4
3 2 1 0 9 8 . . . ). Make sure to test it works.
Task 3
Once tested, write down your module Counter.
To be able to count the number of seconds that have elapsed, we actually need two
counters. The first counter is needed to divide the 50 MHz clock into an enable pulse
that will enable the second counter once per second.
Since we now care about tracking time accurately, we use a ‘timescale statement in
our test bench. Complete the following code. Do not forget to include your Counter
module.
Test Bench
1 ‘timescale 1ns/1ns
2
3 module test;
4 // Generate a 50 MHz clock
5 reg clk = 0;
6 initial forever #... clk = !clk;
3
7
8 wire [5:0] out;
9 Time t(.clk(clk), .secs(out ));
10
11 initial begin
12 #0 $display(out);
13 repeat (120)
14 #500 _000_000 $display(out);
15 $stop;
16 end
17 endmodule
Top-level Module
1 module Watch(input CLOCK_50 );
2 wire [5:0] secs;
3 Time time(.clk(CLOCK_50), .secs(secs ));
4 endmodule
Time Module
1 module Time(input clk , output [5:0] secs);
2 localparam N = ...;
3 localparam BW = $clog2(N);
4 wire [BW -1:0] tick;
5 Counter #(. MAX(N-1), .WIDTH(BW))
6 divider (.clk(clk), .enable(1’b1), .cnt(tick ));
7 Counter #(. MAX(59), .WIDTH (6))
8 cs(.clk(clk), .enable(tick ==0), .cnt(secs ));
9 endmodule
Task 4
If you attempt to simulate the code as it is, you will find simulators will (normally)
time out. Therefore, apply the trick from lectures, namely, simulate a 50 Hz clock.
This necessitates changing your Time module to account for the fact the clock is
now 50 Hz and not 50 MHz. One the code works, copy the code as well as the
output of your test bench to your report. Justify why the output of the test bench
is correct.
Next we want to display the seconds on HEX[1] and HEX[0]. You will need the 7-segment
decoder module that you wrote earlier in your practical assignments. You will also need
to figure out mathematically how to take a number between 0 and 59 and find the first
digit and the second digit. Get this latter bit working first in an online Verilog simulator.
(Since you can draw a truth table for this, it can be implemented using combinational
logic.)
1 module jdoodle;
2 reg [5:0] sec;
4
3 reg [3:0] d1 , d2;
4 initial begin
5 sec = 32; // Change this number several times ,
6 // making sure each number works
7 d1 = ...; // Formula for determining first digit of sec
8 d2 = ...; // Formula for determining second digit of sec
9 $display("The first digit of ", sec , " is ", d1);
10 $display("The second digit of ", sec , " is ", d2);
11 end
12 endmodule
Hint: You can use arithmetic expressions to find the first and second digits. First read
up about how integer division (/) and the modulo operator (%) work.
Returning to your Quartus project, modify your top-level module to the following then
check it works on the board. You will need to fill in the details.
1 module Watch(input CLOCK_50 , output [6:0] HEX1 , HEX0);
2 wire [5:0] secs;
3 wire [3:0] secs_d1 = ...;
4 wire [3:0] secs_d2 = ...;
5 Time time(.clk(CLOCK_50), .secs(secs ));
6 SSeg ss0(. digit(secs_d1), .sseg(HEX1 ));
7 SSeg ss1(. digit(secs_d2), .sseg(HEX0 ));
8 endmodule
Task 5
Write down the completed modules Watch and SSeg.
1.2 Hours and Minutes Displays
Next we want to display the minutes as well as the seconds.
There is a minor problem to think about. We want the minutes to increment when the
seconds change from 59 to 0. A first idea might be to use secs == 0 but this will be true
for many cycles of the clock. Another idea might be secs == 0 && tick == 0, but will
this work?
Get the following code to work, and use a test bench to show that the minutes change
at precisely the same time as the seconds change from 59 to 0.
1 module Time(input clk , output [5:0] mins , secs);
2 localparam N = ...;
3 localparam BW = $clog2(N);
4 wire [BW -1:0] tick;
5 Counter #(. MAX(N-1), .WIDTH(BW))
6 divider (.clk(clk), .enable(1’b1), .cnt(tick ));
5
7 Counter #(. MAX(59), .WIDTH (6))
8 cs(.clk(clk), .enable(tick ==0), .cnt(secs ));
9 Counter #(. MAX(59), .WIDTH (6))
10 cm(.clk(clk), .enable (...), .cnt(mins ));
11 endmodule
Task 6
Copy the working module Time to your report, as well as the test bench and its
output that was used to verify that minutes updates at precisely the right time.