Notice
Recent Posts
Recent Comments
Link
관리 메뉴

거북이처럼 천천히

Verilog RTL 설계(7월 18일 - 5, Stop Watch - 4) 본문

RTL Design/Verilog RTL 설계

Verilog RTL 설계(7월 18일 - 5, Stop Watch - 4)

유로 청년 2024. 7. 22. 08:40

1. 4초 때 리셋 버튼을 누른 뒤, 다시  Stop watch를 실행하니 56초때 분값이 증가한다.

 

 

1.1. 문제 현상

  • 4초 때 리셋 버튼을 누른 뒤, 다시 Stop Watch를 실행하니 56초때 분값이 증가하는 현상을 확인할 수 있다.

 

 

 

 

 

1.2. 문제 원인 

  • BCD 60진 Counter를 통해 현재까지 Counter가 counting한 값을 초기화 시켜줌으로서 cur_time 값을 초기화시켜주었으며, lap_time도 btn_clear가 활성화되면 초기화시켜줌으로서 0분 0초로 만들어 주었다.
  • 그러나, BCD 60진 Counter가 Counting함에 있어 기준 펄스가 되는 clk_sec와 clk_min에 대해서 초기화를 시켜주지 않았다.
  • 따라서 clk_sec과 clk_min 펄스파는 clear 된 것과 상관없이 계속 초기화전 상태의 펄스파를 만들어 냄으로서 BCD 60진 Counter는 해당 펄스 파형에 따라 Counting하여 이러한 문제점이 발생한 것이다. 

 

 

 

 

1.3. 문제 해결 방안

  • reset 버튼이 눌렸을 경우, 모드에 대한 초기화, 시간에 대한 초기화 뿐만 아니라 clk_sec와 clk_min에 대한 초기화도 필요하다.
  • 따라서 아래와 같이 수정함으로서 reset_p 뿐만 아니라 reset 버튼이 눌렸을 경우 clk_sec와 clk_min이 초기화 되도록 설계할 필요가 있다.

 

 

 

 

1.4. 수정된 코드

 

< 수정 전, 코드 >

clk_div_n clk_div_sec(.clk(clk), .reset_p(reset_p), .clk_source(clk_usec), .prescale(1000000), .clk_div_n_nedge(clk_sec));
clk_div_n clk_div_min(.clk(clk), .reset_p(reset_p), .clk_source(clk_sec), .prescale(60), .clk_div_n_nedge(clk_min));

 

< 수정 후, 코드 >

clk_div_n clk_div_sec(.clk(clk), .reset_p(reset_start), .clk_source(clk_usec), .prescale(1000000), .clk_div_n_nedge(clk_sec));
clk_div_n clk_div_min(.clk(clk), .reset_p(reset_start), .clk_source(clk_sec), .prescale(60), .clk_div_n_nedge(clk_min));

 

 

 

 

 

1.5. 구현 영상

 

 

 

 

 

2. Stop Watch의 전체 소스 코드

module Stop_Watch(
    input clk, reset_p,
    input [2:0] btn,
    output [3:0] com,
    output [7:0] seg_7 );
    
    // Control Stop Watch
    wire btn_start, btn_lap, btn_clear;
    button_cntr control_btn_set (.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_nedge(btn_start));
    button_cntr control_btn_lap (.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_nedge(btn_lap));
    button_cntr control_btn_clear (.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_nedge(btn_clear));
    
    // Control Start / Stop mode.
    wire reset_start = reset_p | btn_clear;
    wire start_stop;
    t_flip_flop t_flip_flop_0 (.clk(clk), .reset_p(reset_start), .t(btn_start), .q(start_stop));
    
    // Control Lap mode
    wire lap;
    t_flip_flop t_flip_flop1 (.clk(clk), .reset_p(reset_start), .t(btn_lap), .q(lap));
    
    // Control clk.
    wire clk_start;
    assign clk_start = (start_stop)? clk : 0;
    
    // Get One Cycle Pulse of Second    , Minute
    wire clk_usec, clk_sec, clk_min;
    clk_div_100 clk_div_usec (.clk(clk_start), .reset_p(reset_p), .clk_div_100(clk_usec));
    clk_div_n clk_div_sec(.clk(clk), .reset_p(reset_start), .clk_source(clk_usec), .prescale(1000000), .clk_div_n_nedge(clk_sec));
    clk_div_n clk_div_min(.clk(clk), .reset_p(reset_start), .clk_source(clk_sec), .prescale(60), .clk_div_n_nedge(clk_min));
    
    // BCD 60 Counter (add claer function)
    wire [3:0] min10, min1, sec10, sec1;
    counter_bcd_60_clear counter_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .clear(btn_clear), .bcd1(sec1), .bcd10(sec10));
    counter_bcd_60_clear counter_min(.clk(clk), .reset_p(reset_p), .clk_time(clk_min), .clear(btn_clear), .bcd1(min1), .bcd10(min10));
    
    // Combine data.
    wire [15:0] hex_value, cur_time;
    reg [15:0] lap_time;
    assign cur_time = {min10, min1, sec10, sec1};
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p | btn_clear) lap_time = 0;
        else if(btn_lap) lap_time = cur_time;
    end
    
    assign hex_value = (lap)? lap_time : cur_time;
      
    fnd_cntr fnd(.clk(clk), .reset_p(reset_p), .value(hex_value), .com(com), .seg_7(seg_7));
    
endmodule

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

// Control Button.
module button_cntr (
    input clk, reset_p,
    input btn,
    output btn_pedge, btn_nedge);
  
  // Get 1ms One Cycle Pulse
   reg [16:0] counter;
   always @(posedge clk or posedge reset_p) begin
        if(reset_p) counter = 0;
        else begin
            if(counter >= 99999) counter = 0;
            else counter = counter + 1;
        end
   end

   wire clk_1ms, clk_1ms_nedge;
   assign clk_1ms = (counter < 50000) ? 0 : 1;
   edge_detector_n edge_dector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_1ms), .n_edge(clk_1ms_nedge));
   
   //  D Flip-Flop을 이용한 button 값 읽기 
   reg debounced_btn;
   
   always @(posedge clk or posedge reset_p) begin
        if(reset_p) debounced_btn = 0;
        else if(clk_1ms_nedge) debounced_btn = btn;
   end
   
   edge_detector_n edge_dector_1 (.clk(clk), .reset_p(reset_p), .cp(debounced_btn), .n_edge(btn_nedge), .p_edge(btn_pedge));
  
endmodule

module counter_bcd_60_clear (
    input clk, reset_p,
    input clk_time, 
    input clear,
    output reg [3:0] bcd1, bcd10 );
    
    wire clk_time_nedge;
    edge_detector_n edge_dector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_time), .n_edge(clk_time_nedge));
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p | clear) begin
            bcd1 = 0;
            bcd10 = 0;
        end
        else if(clk_time_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 60 Counter.
module counter_bcd_60(
    input clk, reset_p,
    input clk_time,
    output reg [3:0] bcd1, bcd10 );
    
    // Get One Cycle of clk_time
    wire clk_time_nedge;
    edge_detector_n edge_dector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_time), .n_edge(clk_time_nedge));
    
    // Counter
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) begin
            bcd1 = 0;
            bcd10 = 0;
        end
        else if(clk_time_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

// Prescaler n
module clk_div_n (
    input clk, reset_p,
    input clk_source,
    input [31:0] prescale,
    output clk_div_n, clk_div_n_nedge );
    
    // Get one cycle pulse of clk_source
    wire clk_source_nedge;
    edge_detector_n edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
    
    // Counting
    integer counter;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) counter = 0;
        else if(clk_source_nedge) begin
            if(counter >= prescale-1) counter = 0;
            else counter = counter + 1;
        end 
    end
    
    // Get clk_div_n wave, One cycle pulse of clk_div_n.
    assign clk_div_n = (counter < prescale / 2)? 0 : 1;
    edge_detector_n edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_n), .n_edge(clk_div_n_nedge));
    
endmodule

// Prescaler 100.
module clk_div_100 (
    input clk, reset_p,
    input clk_div_100,
    input clk_div_100_nedge );
    
    reg [6:0] counter;
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) counter = 0;
        else begin
            if(counter >= 99) counter = 0;
            else counter = counter + 1;
        end
    end
    
    assign clk_div_100 = (counter < 50)? 0 : 1;
    edge_detector_n edge_dector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_div_100), .n_edge(clk_div_100_nedge));
    
endmodule

// Control FND
module fnd_cntr (
    input clk, reset_p,
    input [15:0] value,
    output reg [3:0] com,
    output [7:0] seg_7 );
    
    // prescaler 100000
    reg[16:0] counter;
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) counter = 0;
        else begin
            if(counter >= 99999) counter = 0;
            else counter = counter + 1;
        end
    end
    
    wire clk_1ms, clk_1ms_nedge;
    assign clk_1ms = (counter < 50000)? 0 : 1;
    edge_detector_n edge_dector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_1ms), .n_edge(clk_1ms_nedge));
    
    // Shifting com.
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) com = 4'b1110;
        else if(clk_1ms_nedge) begin
            if(com == 4'b0111) com = 4'b1110;
            else com = {com[2:0], 1'b1};
        end
    end
    
    // Get FND data.
    reg [3:0] hex_value;
    
    always @(com) begin
        case(com)
            4'b1110 : hex_value = value[3:0];
            4'b1101 : hex_value = value[7:4];
            4'b1011 : hex_value = value[11:8];
            4'b0111 : hex_value = value[15:12];
            default : hex_value = hex_value;
        endcase
    end
    
    decoder_7seg fnd(.hex_value(hex_value), .seg_7(seg_7));
endmodule

// Decoder of 7-Segment.
module decoder_7seg (
    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_n (
    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 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