Implementing a Countdown Timer in Verilog Without Reset Logic
A friend asked for help with an old Cyclone I board that lacks reset buttons, switches, or any other reset mechanisms. The board has only four common cathode seven-segment displays and 16 LED lights. The task was to write a Verilog code to test the board.
The requirements are as follows:
(1) The input port is a clock signal clk, and the output signals are four-bit digit select (sel) and eight-bit segment select (seg); (2) On power-up, the four seven-segment displays show 0000. Then, the left two displays show 59 (representing 59 minutes), and the right two display 59 (representing 59 seconds). Every second, the seconds counter decreases by one until it reaches 0000. This effectively creates a countdown of one hour, repeating continuously.
The logic is straightforward, primarily using counters. The challenge lies in the absence of a reset mechanism, whether synchronous or aysnchronous. To address this, the initial value asssignment using the initial statement is utilized. For example, initial count = 4'd0;
The experiment confirmed that even without a reset, it's possible to imlpement the logic, and the initial statement can be synthesized in certain scenarios.
Verilog code:
// *********************************************************************************
// Project Name :
// Email :
// Create Time : 2020// :
// Module Name :
// editor : Qing
// Version : Rev1.0.0
// *********************************************************************************
module count_disp(
input clk ,
output reg[3:0] sel ,
output reg[7:0] seg
);
//========================================================================\
// =========== Define Parameter and Internal signals ===========
//========================================================================/
reg [27:0] cnt ;
reg [7:0] cnt_miao ;
reg [7:0] cnt_fen ;
reg [15:0] cnt_move ;
reg [2:0] cnt_sel ;
reg [3:0] disp_data ;
wire [3:0] l_miao ;
wire [3:0] h_miao ;
wire [3:0] l_fen ;
wire [3:0] h_fen ;
//=============================================================================
//**************************** Main Code *******************************
//=============================================================================
initial cnt_move = 16'd0;
always @(posedge clk) begin
if(cnt_move == 49999) // 49999
cnt_move <= 16'd0;
else
cnt_move <= cnt_move + 1'b1;
end
initial cnt_sel = 3'd0;
always @(posedge clk) begin
if(cnt_move == 49999) begin
if(cnt_sel == 3'd3)
cnt_sel <= 3'd0;
else
cnt_sel <= cnt_sel + 1'b1;
end
else
cnt_sel <= cnt_sel;
end
initial cnt = 28'd0;
always @(posedge clk ) begin
if(cnt == 49999999) // 49999999
cnt <= 28'd0;
else
cnt <= cnt + 1'b1;
end
initial cnt_miao = 8'd59;
always @(posedge clk) begin
if(cnt == 49999999) begin //////////////
if(cnt_miao == 0)
cnt_miao <= 59;
else
cnt_miao <= cnt_miao - 1'b1;
end
else
cnt_miao <= cnt_miao;
end
initial cnt_fen = 8'd59;
always @(posedge clk ) begin
if((cnt_miao == 0) && (cnt == 49999999)) begin //////////
if(cnt_fen == 0)
cnt_fen <= 8'd59;
else
cnt_fen <= cnt_fen - 1'b1;
end
else
cnt_fen <= cnt_fen;
end
assign l_miao = cnt_miao % 10;
assign h_miao = cnt_miao / 10 % 10;
assign l_fen = cnt_fen % 10;
assign h_fen = cnt_fen / 10 % 10;
initial sel = 4'b1111;
initial disp_data = 4'd0;
always @(posedge clk) begin
if(cnt_move == 49999) begin
case(cnt_sel)
0: begin sel <= 4'b0001; disp_data <= l_miao; end // common cathode
1: begin sel <= 4'b0010; disp_data <= h_miao; end
2: begin sel <= 4'b0100; disp_data <= l_fen ; end
3: begin sel <= 4'b1000; disp_data <= h_fen ; end
default: begin sel <= 4'b1111; disp_data <= 4'd0; end
endcase
end
end
always @(posedge clk) begin
case(disp_data)
0: seg <= 8'h3f;
1: seg <= 8'h06;
2: seg <= 8'h5B;
3: seg <= 8'h4F;
4: seg <= 8'h66;
5: seg <= 8'h6D;
6: seg <= 8'h7D;
7: seg <= 8'h07;
8: seg <= 8'h7F;
9: seg <= 8'h6F;
default: seg <= 8'h3f;
endcase
end
endmodule
Testbench code:
`timescale 1ns/1ps
module count_disp_tb;
reg clk ; // clock signal
wire [3:0] sel ; // digit select signal
wire [7:0] seg ; // segment select signal
count_disp count_disp_inst(
.clk ( clk ),
.sel ( sel ),
.seg ( seg )
);
initial
clk = 1'b0;
always #10 clk = ~clk;
endmodule