본문 바로가기
하만 세미콘 아카데미/Verilog HDL

Verilog HDL 실습 (Stop_Watch)

by smileww 2024. 5. 31.

오늘은 간단한 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