오늘은 간단한 Stop_watch를 만들어보도록 하겠습니다. Stop_watch는 매우 훌륭한 실습 프로그램으로 전반적인 RTL 설계 능력을 향상시킬것이며 먼저 스톱워치를 만들기 전에 필요한 기능에 대해서 생각해보도록 하겠습니다.
1. 시작 / 정지 기능 구현
먼저 버튼으로 스톱워치를 통제할 수 있는 기능을 만들어야 합니다. 이는 플립플롭을 이용하여 엣지를 검출하는 방식으로 만들어 보도록 하겠습니다.
2. 시간 초 증가
시간을 증가시킬 수 있는 기능은 많은데 저는 tick 신호를 만들어 카운터가 일정한 시간까지 세면 해당 부분에서 값을 할당하는 방식으로 초 증가를 만들어보도록 하겠습니다.
3. 세그먼트 출력
만든 스톱워치를 세그먼트에 출력으로 표시해주려고 합니다. 그에 따라 세그먼트 모듈도 제작했습니다.
Verilog HDL Code
Key_interface Module
`timescale 1ns / 1ps
module key_proc(
input RST,
input CLK,
input KEY,
output reg STR_STP //start : 1, stop :0
);
reg ss_1d, ss_2d;
wire enable;
always @(posedge CLK)
begin
ss_1d <= KEY;
ss_2d <= ss_1d;
end
assign enable = ss_1d & ~ss_2d;
always @(posedge CLK)
begin
if (RST)
STR_STP <= 1'b0;
else if (enable)
STR_STP <= ~STR_STP;
end
endmodule
Stop_Watch Module
`timescale 1ns / 1ps
module stopwatch(
input RST,
input CLK,
input START,
output reg [3:0] NUM_1S,
output reg [2:0] NUM_10S
);
parameter CLK_FREQ = 125_000_000;
reg [26:0] cnt;
wire tick_1s;
always @(posedge CLK)
begin
if(RST || ~START)
cnt <= 27'd0;
else if(cnt == (CLK_FREQ - 1))
cnt <= 27'd0;
else
cnt <= cnt + 1;
end
assign tick_1s = cnt == (CLK_FREQ - 1);
always @(posedge CLK)
begin
if (RST)
NUM_1S <= 4'd0;
else if(tick_1s) begin
if(NUM_1S == 4'd9)
NUM_1S <= 4'd0;
else
NUM_1S <= NUM_1S + 1;
end
end //slways
always @(posedge CLK)
begin
if (RST)
NUM_10S <= 3'd0;
else if(tick_1s && (NUM_1S == 4'd9)) begin
if(NUM_10S == 3'd5)
NUM_10S <= 3'd0;
else
NUM_10S <= NUM_10S + 1;
end
end //slways
endmodule
display_inst Module
`timescale 1ns / 1ps
module display_inf(
input RST,
input CLK, // 125 Mhz
input [3:0] NUM_1S,
input [2:0] NUM_10S,
output reg CA,
output reg [6:0] AN
);
parameter CLK_FREQ = 125_000_000;
parameter CNT_MAX = CLK_FREQ / 1000_000;
reg [26:0] clk_cnt;
wire enable;
always @(posedge CLK)
begin
if(RST)
clk_cnt <= 27'd0;
else begin
if( clk_cnt == (CNT_MAX -1))
clk_cnt <= 27'd0;
else
clk_cnt <= clk_cnt + 1;
end
end
assign enable = (clk_cnt == (CNT_MAX -1));
always @(posedge CLK)
if(RST)
CA <= 1'b0;
else if (enable)
CA <= ~CA;
always @(CA, NUM_1S, NUM_10S)
begin
if (CA) begin
case (NUM_10S)
3'd0 : AN = 7'h7e;
3'd1 : AN = 7'h30;
3'd2 : AN = 7'h6d;
3'd3 : AN = 7'h79;
3'd4 : AN = 7'h33;
3'd5 : AN = 7'h5b;
default : AN = 7'h00;
endcase
end else begin
case (NUM_1S)
4'd0 : AN = 8'h7e;
4'd1 : AN = 8'h30;
4'd2 : AN = 8'h6d;
4'd3 : AN = 8'h79;
4'd4 : AN = 7'h33;
4'd5 : AN = 7'h5b;
4'd6 : AN = 7'h5f;
4'd7 : AN = 7'h70;
4'd8 : AN = 7'h7f;
4'd9 : AN = 7'h7b;
default : AN = 8'h00;
endcase
end
end
endmodule
Stop_Watch Top Module
`timescale 1ns / 1ps
module stopwatch_top(
input RST,
input CLK,
input KEY,
output CA,
output [6:0] AN
);
wire [3:0] num_1s;
wire [2:0] num_10s;
wire start_stop;
key_proc key_inst (
.RST (RST),
.CLK (CLK),
.KEY (KEY),
.STR_STP (start_stop) //start : 1, stop :0
);
stopwatch stopwatch_inst (
.RST (RST),
.CLK (CLK),
.START (start_stop),
.NUM_1S (num_1s),
.NUM_10S (num_10s)
);
display_inf display_inst(
.RST (RST),
.CLK (CLK), // 125 Mhz
.NUM_1S (num_1s),
.NUM_10S (num_10s),
.CA (CA),
.AN (AN)
);
endmodule
Key_proc Testbench
`timescale 1ns / 1ps
module key_proc_tb();
parameter CLK_PD = 10.0;
reg CLK, RST, KEY;
wire start_stop;
key_proc uut (
.RST (RST),
.CLK (CLK),
.KEY (KEY),
.STR_STP (start_stop) //start : 1, stop :0
);
initial begin
RST = 1'b1;
#(CLK_PD*10);
RST = 1'b0;
end
initial CLK = 1'b0;
always #(CLK_PD/2) CLK = ~CLK;
initial begin
KEY = 1'b0;
wait (RST == 1'b0);
#(CLK_PD*40);
KEY = 1'b1;
#(CLK_PD*40);
KEY = 1'b0;
#(CLK_PD*40);
KEY = 1'b1;
#(CLK_PD*40);
KEY = 1'b0;
#(CLK_PD*100);
$finish;
end
endmodule
Stop_watch Testbench
`timescale 1ns / 1ps
module stopwatch_top(
input RST,
input CLK,
input KEY,
output CA,
output [6:0] AN
);
wire [3:0] num_1s;
wire [2:0] num_10s;
wire start_stop;
key_proc key_inst (
.RST (RST),
.CLK (CLK),
.KEY (KEY),
.STR_STP (start_stop) //start : 1, stop :0
);
stopwatch stopwatch_inst (
.RST (RST),
.CLK (CLK),
.START (start_stop),
.NUM_1S (num_1s),
.NUM_10S (num_10s)
);
display_inf display_inst(
.RST (RST),
.CLK (CLK), // 125 Mhz
.NUM_1S (num_1s),
.NUM_10S (num_10s),
.CA (CA),
.AN (AN)
);
endmodule
Key_proc Simulation
입력신호 KEY의 엣지를 두 개의 지연 레지스터를 사용하여 enable 신호를 생성합니다. ss_1d가 1이고 ss_2d가 0일 때 1이 될 때, 즉 key 신호가 0에서 1로 바뀌는 상승 엣지에서 enable이 활성화 됩니다.
상승 엣지에서 enable 신호가 활성화되면 STR_STP 출력은 현재 상태의 반대로 토글 됩니다. (시작/정지 버튼 구현)
Stop_watch Simulation 1-1
Stop_watch 시간 시뮬레이션 입니다. Test를 위해 cnt 신호를 테스트벤치에서 감소하여 Simulation 하였습니다.
Stop_watch Simulation 1-2
cnt가 일정 숫자까지 증가하면 tick 신호를 활성화 합니다. tick 신호가 활성화가 도면 Num_1S를 하나 증가하여 초 카운터를 생성합니다. 초 카운터가 10까지 증가하면 다시 0으로 초기화하고 Num_10S를 하나 증가시켜 10초 카운터를 생성합니다.
Stop_watch Simulation 1-3
10초 카운터가 5까지 증가후 6이 되기 전에 0으로 초기화하여 1분 Stop_watch를 만듭니다.
Synthesis를 진행하고 마찬가지로 Pin을 설정해줍니다. 핀 설정에서는 세그먼트와 Clock, 리셋 버튼과 Start / Stop 버튼을 설정해주시면 됩니다. (각 보드마다 Schematic을 참고해서 설정해주세요)
'하만 세미콘 아카데미 > Verilog HDL' 카테고리의 다른 글
Verilog HDL 실습 (UART) (0) | 2024.05.31 |
---|---|
UART 이론 (수업시간 내용 정리) (0) | 2024.05.31 |
Verilog HDL 실습 (Traffic) (0) | 2024.05.31 |
Verilog HDL 실습 (Security) (0) | 2024.05.31 |
Verilog HDL 실습 (FSM) (0) | 2024.05.31 |