거북이처럼 천천히

Stop Watch - 1 본문

RTL Design/Verilog 연습

Stop Watch - 1

유로 청년 2024. 8. 7. 15:48

1. Stop Watch

  • 이번에 구현한 Stop Watch 코드는 본인 스스로 구현한 것이기 때문에 아래 게시글에서 구현한 Stop Watch 코드와 약간의 차이가 있을 수 있으나, 알고리즘 관점에서는 큰 차이를 갖지 않는다.
  • Stop Watch의 동작 원리 및 자세한 코드 설명은 아래 게시글을 참고하길 바란다.

 

 

 

2. Source code of Stop Watch

< Source,  Clock divider 10 >

// Clock divider 10.
module clk_div_10 (
    input clk, reset_p,
    input clk_source,
    output clk_div_10,
    output clk_div_10_nedge, clk_div_10_pedge );
    
    wire clk_source_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
    
    reg [3:0] count;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) count = 0;
        else if(clk_source_nedge) begin
            if(count >= 9) count = 0;
            else count = count + 1; 
        end
    end
    
    assign clk_div_10 = (count < 5)? 0 : 1;
    
    edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_10), .n_edge(clk_div_10_nedge), .p_edge(clk_div_10_pedge));
endmodule

 

 

 

< Source, BCD 100진 Counter >

// BCD 100진 Counter.
module bcd_100_counter (
    input clk, reset_p,
    input clk_resource,
    output reg [3:0] bcd10, bcd1 );
    
    wire clk_resource_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_resource), .n_edge(clk_resource_nedge)); 
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) begin bcd10 = 0; bcd1 = 0; end
        else if(clk_resource_nedge) begin
            if(bcd1 >= 9) begin
                bcd1 = 0;
                
                if(bcd10 >= 9) bcd10 = 0;
                else bcd10 = bcd10 + 1;
            end
            else bcd1 = bcd1 + 1;
        end
    end  
endmodule

 

 

 

< Source, BCD 60진 Counter >

// BCD 60진 Counter.
module bcd_60_counter (
    input clk, reset_p,
    input clk_resource,
    output reg [3:0] bcd10, bcd1 );
    
    wire clk_resource_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_resource), .n_edge(clk_resource_nedge)); 
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) begin bcd10 = 0; bcd1 = 0; end
        else if(clk_resource_nedge) begin
            if(bcd1 >= 9) begin
                bcd1 = 0;
                
                if(bcd10 >= 5) bcd10 = 0;
                else bcd10 = bcd10 + 1;
            end
            else bcd1 = bcd1 + 1;
        end
    end  
endmodule

 

 

 

< Source, Top Module of Stop Watch >

module Stop_Watch_0(
    input clk, reset_p,
    input [2:0] btn,
    output [3:0] com,
    output [7:0] seg_7 );
    
    // Get One Cycle Pulse of button.
    wire btn_start, btn_lap, btn_clear;
    button_cntr button_start_control (.clk(clk), .reset_p(reset_p), .button_source(btn[0]), .button_pedge(btn_start));
    button_cntr button_lap_control (.clk(clk), .reset_p(reset_p), .button_source(btn[1]), .button_pedge(btn_lap));
    button_cntr button_clear_control (.clk(clk), .reset_p(reset_p), .button_source(btn[2]), .button_pedge(btn_clear));
    
    // Declare Reset Variable & new clk signal
    wire new_reset = btn_clear | reset_p;
    wire new_clk = start_stop_mode & clk;
    
    // Declare Mode 
    wire start_stop_mode;
    t_flip_flop t_flip_flop_mode (.clk(clk), .reset_p(new_reset), .button(btn_start), .q(start_stop_mode));
    
    // Get One cycle pulse of msec, sec.
    wire clk_1usec, clk_1msec, clk_10msec, clk_1sec;
    clk_div_100 clk_div_1usec (.clk(new_clk), .reset_p(new_reset), .clk_div_100(clk_1usec));
    clk_div_1000 (.clk(clk), .reset_p(new_reset), .clk_source(clk_1usec), .clk_div_1000(clk_1msec));
    clk_div_10 (.clk(clk), .reset_p(new_reset), .clk_source(clk_1msec), .clk_div_10_nedge(clk_10msec));
    clk_div_1000 (.clk(clk), .reset_p(new_reset), .clk_source(clk_1msec), .clk_div_1000_nedge(clk_1sec));
    
    // BCD Counter
    wire [3:0] bcd10_sec, bcd1_sec, bcd10_msec, bcd1_msec;
    bcd_60_counter bcd_60_counter_0 (.clk(clk), .reset_p(new_reset), .clk_resource(clk_1sec), .bcd10(bcd10_sec), .bcd1(bcd1_sec));
    bcd_100_counter bcd_100_counter_0 (.clk(clk), .reset_p(new_reset), .clk_resource(clk_10msec), .bcd10(bcd10_msec), .bcd1(bcd1_msec));
    
    // Data of time
    wire [15:0] current_time;
    reg [15:0] lap_time;
    assign current_time = {bcd10_sec, bcd1_sec, bcd10_msec, bcd1_msec};
    
    // Declare Lap time
    always @(posedge clk or posedge reset_p) begin
        if(reset_p | btn_clear) lap_time = 16'b0;
        else if(btn_lap) lap_time = current_time;
        else lap_time = lap_time;
    end
    
    // Select data of time
    wire stopWatch_Lap_mode;
    t_flip_flop t_flip_flop_lap (.clk(clk), .reset_p(new_reset), .button(btn_lap), .q(stopWatch_Lap_mode));
    wire [15:0] hex_value = (stopWatch_Lap_mode)? lap_time : current_time;
    
    // Print the time to FND.
    fnd_cntr control_fnd (.clk(clk), .reset_p(reset_p), .hex_value(hex_value), .com(com), .seg_7(seg_7));
endmodule

 

 

 

 

 

3. 구현 영상 

 

 

 

 

4. 전체 소스 코드

// Top Module
module Stop_Watch_0(
    input clk, reset_p,
    input [2:0] btn,
    output [3:0] com,
    output [7:0] seg_7 );
    
    // Get One Cycle Pulse of button.
    wire btn_start, btn_lap, btn_clear;
    button_cntr button_start_control (.clk(clk), .reset_p(reset_p), .button_source(btn[0]), .button_pedge(btn_start));
    button_cntr button_lap_control (.clk(clk), .reset_p(reset_p), .button_source(btn[1]), .button_pedge(btn_lap));
    button_cntr button_clear_control (.clk(clk), .reset_p(reset_p), .button_source(btn[2]), .button_pedge(btn_clear));
    
    // Declare Reset Variable & new clk signal
    wire new_reset = btn_clear | reset_p;
    wire new_clk = start_stop_mode & clk;
    
    // Declare Mode 
    wire start_stop_mode;
    t_flip_flop t_flip_flop_mode (.clk(clk), .reset_p(new_reset), .button(btn_start), .q(start_stop_mode));
    
    // Get One cycle pulse of msec, sec.
    wire clk_1usec, clk_1msec, clk_10msec, clk_1sec;
    clk_div_100 clk_div_1usec (.clk(new_clk), .reset_p(new_reset), .clk_div_100(clk_1usec));
    clk_div_1000 (.clk(clk), .reset_p(new_reset), .clk_source(clk_1usec), .clk_div_1000(clk_1msec));
    clk_div_10 (.clk(clk), .reset_p(new_reset), .clk_source(clk_1msec), .clk_div_10_nedge(clk_10msec));
    clk_div_1000 (.clk(clk), .reset_p(new_reset), .clk_source(clk_1msec), .clk_div_1000_nedge(clk_1sec));
    
    // BCD Counter
    wire [3:0] bcd10_sec, bcd1_sec, bcd10_msec, bcd1_msec;
    bcd_60_counter bcd_60_counter_0 (.clk(clk), .reset_p(new_reset), .clk_resource(clk_1sec), .bcd10(bcd10_sec), .bcd1(bcd1_sec));
    bcd_100_counter bcd_100_counter_0 (.clk(clk), .reset_p(new_reset), .clk_resource(clk_10msec), .bcd10(bcd10_msec), .bcd1(bcd1_msec));
    
    // Data of time
    wire [15:0] current_time;
    reg [15:0] lap_time;
    assign current_time = {bcd10_sec, bcd1_sec, bcd10_msec, bcd1_msec};
    
    // Declare Lap time
    always @(posedge clk or posedge reset_p) begin
        if(reset_p | btn_clear) lap_time = 16'b0;
        else if(btn_lap) lap_time = current_time;
        else lap_time = lap_time;
    end
    
    // Select data of time
    wire stopWatch_Lap_mode;
    t_flip_flop t_flip_flop_lap (.clk(clk), .reset_p(new_reset), .button(btn_lap), .q(stopWatch_Lap_mode));
    wire [15:0] hex_value = (stopWatch_Lap_mode)? lap_time : current_time;
    
    // Print the time to FND.
    fnd_cntr control_fnd (.clk(clk), .reset_p(reset_p), .hex_value(hex_value), .com(com), .seg_7(seg_7));
endmodule

// BCD 60진 Counter.
module bcd_60_counter (
    input clk, reset_p,
    input clk_resource,
    output reg [3:0] bcd10, bcd1 );
    
    wire clk_resource_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_resource), .n_edge(clk_resource_nedge)); 
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) begin bcd10 = 0; bcd1 = 0; end
        else if(clk_resource_nedge) begin
            if(bcd1 >= 9) begin
                bcd1 = 0;
                
                if(bcd10 >= 5) bcd10 = 0;
                else bcd10 = bcd10 + 1;
            end
            else bcd1 = bcd1 + 1;
        end
    end  
endmodule

// BCD 100진 Counter.
module bcd_100_counter (
    input clk, reset_p,
    input clk_resource,
    output reg [3:0] bcd10, bcd1 );
    
    wire clk_resource_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_resource), .n_edge(clk_resource_nedge)); 
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) begin bcd10 = 0; bcd1 = 0; end
        else if(clk_resource_nedge) begin
            if(bcd1 >= 9) begin
                bcd1 = 0;
                
                if(bcd10 >= 9) bcd10 = 0;
                else bcd10 = bcd10 + 1;
            end
            else bcd1 = bcd1 + 1;
        end
    end  
endmodule

// Button control
module button_cntr (
    input clk, reset_p,
    input button_source,
    output reg button, 
    output button_pedge, button_nedge );
    
    reg [16:0] count;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) count = 0;
        else begin
            if(count >= 99999) count = 0;
            else count = count + 1;
        end
    end
    
    wire clk_1ms;
    assign clk_1ms = (count < 50000)? 0 : 1;
    
    wire clk_1ms_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_1ms), .n_edge(clk_1ms_nedge));
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) button = 0;
        else if(clk_1ms_nedge) button = button_source;
        else button = button;
    end
    
    edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(button), .p_edge(button_pedge), .n_edge(button_nedge));
    
endmodule


// T Flip - Flop
module t_flip_flop (
    input clk, reset_p,
    input button,
    output reg q);
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) q = 0;
        else if(button) q = ~ q;
        else q = q;
    end
    
endmodule


// Control FND.
module fnd_cntr ( 
    input clk, reset_p,
    input [15:0] hex_value,
    output [3:0] com,
    output [7:0] seg_7 );
    
    // Ring counter of com value
    ring_counter ring_counter_0 (.clk(clk), .reset_p(reset_p), .com(com));
    
    // Selecting  seg_7 value
    reg [3:0] value;
    always @(*) begin
           case (com)
                4'b1110 : value = hex_value[3:0];
                4'b1101 : value = hex_value[7:4];
                4'b1011 : value = hex_value[11:8];
                4'b0111 : value = hex_value[15:12];
                default : value = value;
           endcase
    end
    
    decoder_of_seg_7 decoder_7_segment (.hex_value(value), .seg_7(seg_7));
endmodule

// Ring Counter
module ring_counter (
    input clk, reset_p,
    output reg [3:0] com );
    
    wire clk_1usec, clk_1msec;
    clk_div_100 clk_usec (.clk(clk), .reset_p(reset_p), .clk_div_100(clk_1usec));
    clk_div_1000 clk_msec(.clk(clk), .reset_p(reset_p), .clk_source(clk_1usec), .clk_div_1000_nedge(clk_1msec));
    
    always @(posedge clk or posedge reset_p) begin
    if(reset_p) com = 4'b1110;
    else if(clk_1msec) begin
        if(com == 4'b0111) com = 4'b1110;
        else com = {com[2:0], 1'b1};
    end
end
    
endmodule

// Clock divider 10.
module clk_div_10 (
    input clk, reset_p,
    input clk_source,
    output clk_div_10,
    output clk_div_10_nedge, clk_div_10_pedge );
    
    wire clk_source_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
    
    reg [3:0] count;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) count = 0;
        else if(clk_source_nedge) begin
            if(count >= 9) count = 0;
            else count = count + 1; 
        end
    end
    
    assign clk_div_10 = (count < 5)? 0 : 1;
    
    edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_10), .n_edge(clk_div_10_nedge), .p_edge(clk_div_10_pedge));
endmodule

// Clock divider 60.
module clk_div_60 (
    input clk, reset_p,
    input clk_source,
    output clk_div_60,
    output clk_div_60_nedge, clk_div_60_pedge );
    
    wire clk_source_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
    
    reg [5:0] clk_div_60_count;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) clk_div_60_count = 0;
        else if(clk_source_nedge) begin
            if(clk_div_60_count >= 59) clk_div_60_count = 0;
            else clk_div_60_count = clk_div_60_count + 1;
        end
    end
    
    assign clk_div_60 = (clk_div_60_count < 30)? 0 : 1;
    edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_60), .n_edge(clk_div_60_nedge), .p_edge(clk_div_60_pedge));
endmodule

// Clock divider 100.
module clk_div_100 (
    input clk, reset_p,
    output clk_div_100,
    output clk_div_100_nedge, clk_div_100_pedge );
    
    reg [6:0] clk_div_100_count;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) clk_div_100_count = 0;
        else begin
            if(clk_div_100_count >= 99) clk_div_100_count = 0;
            else clk_div_100_count = clk_div_100_count + 1;
        end
    end
    
    assign clk_div_100 = (clk_div_100_count < 50)? 0 : 1;
    edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_100), .n_edge(clk_div_100_nedge), .p_edge(clk_div_100_pedge));
endmodule

// Clock divider 1000.
module clk_div_1000 (
    input clk, reset_p,
    input clk_source,
    output clk_div_1000,
    output clk_div_1000_nedge, clk_div_1000_pedge );
    
    wire clk_source_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
    
    reg [9:0] clk_div_1000_count;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) clk_div_1000_count = 0;
        else if(clk_source_nedge) begin
            if(clk_div_1000_count >= 999) clk_div_1000_count = 0;
            else clk_div_1000_count = clk_div_1000_count + 1;
        end
    end
    
    assign clk_div_1000 = (clk_div_1000_count < 500)? 0 : 1;
    edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_1000), .n_edge(clk_div_1000_nedge), .p_edge(clk_div_1000_pedge));
endmodule

// Decoder of 7-segment.
module decoder_of_seg_7 (
    input [3:0] hex_value,
    output reg [7:0] seg_7);
    
    always @(hex_value) begin
        case (hex_value)
            0  : seg_7 = 8'b0000_0011; //common anode, 0이 켜지는거임 
            1  : seg_7 = 8'b1001_1111;  // 1
            2  : seg_7 = 8'b0010_0101;  // 2
            3  : seg_7 = 8'b0000_1101;  // 3
            4  : seg_7 = 8'b1001_1001;  // 4
            5  : seg_7 = 8'b0100_1001;  // 5
            6  : seg_7 = 8'b0100_0001;  // 6
            7  : seg_7 = 8'b0001_1111;  // 7
            8  : seg_7 = 8'b0000_0001;  // 8
            9  : seg_7 = 8'b0000_1001;  // 9
            10 : seg_7 = 8'b0001_0001;  // A
            11 : seg_7 = 8'b1100_0001;  // b
            12 : seg_7 = 8'b0110_0011;  // C
            13 : seg_7 = 8'b1000_0101;  // d
            14 : seg_7 = 8'b0110_0001;  // E
            15 : seg_7 = 8'b0111_0001;  // F
        endcase
    end
    
endmodule

// Edge detector.
module edge_detector (
    input clk, reset_p,
    input cp,
    output n_edge, p_edge );
    
    reg flip_flop_current, flip_flop_old;
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) begin flip_flop_current <= 0; flip_flop_old <=0; end
        else begin
            flip_flop_current <= cp;
            flip_flop_old <= flip_flop_current;
        end
    end
    
    assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10)? 1 : 0;
    assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01)? 1 : 0;
    
endmodule

'RTL Design > Verilog 연습' 카테고리의 다른 글

4X4 Matrix KeyPad - 2  (0) 2024.08.10
4X4 Matrix KeyPad - 1  (0) 2024.08.09
Advanced Clock  (0) 2024.08.06
Normal Clock  (0) 2024.08.04
비동기식 카운터 (Asynchronous counter)  (0) 2024.07.11