본문 바로가기

RTL Design/Verilog RTL 설계

Verilog RTL 설계(7월 18일 - 2, Stop Watch - 1)

1. Stop Watch 

  • 이전 게시글에서 다루었던 Clock 지식을 기반으로 Stop Watch을 구현해보도록 하겠다.
  • 단계별로 기능을 하나씩 추가해 나아가도록 하겠다.

 

 

 

2. Basic Stop Watch

  • 기본적인 Stop Watch는 다음과 같이 동작한다.
    - 초기에는 00 : 00초로 시작하며, 시작 버튼을 누르기 전까지는 시계는 동작하지 않는다.
    - btn[0], btn_start을 누르면 시계가 동작하며, 다시 btn_start을 누르면 다시 시계가 멈춘다.

 

 

2.1. Stop watch에서 시계를 어떻게 멈추게 할 것인가?

  • Basys3의 기본 클럭 펄스를 기반으로 분주화를 통해 1sec / 1min을 주기로 갖는 One Cycle Pulse를 얻는다.
  • 이 과정에서 기본 클럭 펄스 대신 0을 주게된다면 항상 Low Level이기 때문에 분주 모듈내에 Counter는 동작하지 않을 것이며, 이로 인해 시계는 더 이상 분과 초 값을 바꾸지 못해 시계가 멈추게 된다.
  • 그러고 다시 0값 대신 기본 클럭 펄스를 주게 되면 분주 모듈내에 Counter가 클럭 펄스에 따라 Counting을 시작하며, 분과 초 값이 바뀌면서 시계가 움직이게 된다.

 

 

2.2. 기본 Clock 모듈을 기반으로 설계하겠다.

  • 기본적인 시계 기능을 수행하는 모듈을 베이스로 할 것이기 때문에 기계 기능을 수행하는 모듈에 관한 게시글을 한 번 읽고, 오는 것을 추천한다.
    https://jbhdeve.tistory.com/264
 

Verilog RTL 설계(7월 17일 - 3, Clock Mode)

1. Clock Pulse를 이용하여 Clock 만들기basys3의 기본 클럭 펄스의 주기는 10ns이다. 이를 활용하여 시계를 만들고자 한다.다음과 같이 동작한다.- 4개의 FND를 이용하여 첫 번째, 두 번째 FND는 초 단위,

jbhdeve.tistory.com

 

 

 

2.3. 기본 Clock 모듈과 비교하였을 때, 다른 소스 코드를 중심으로 설명하겠다.

 

< Source, Get One Cycle Pulse of btn_start >

// Control Stop Watch
wire btn_start;
button_cntr control_btn_set (.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_nedge(btn_start));

 

  • chattering 현상을 해결하기 위해 D Flip-Flop를 이용하여 delay time을 갖고, button 값을 읽도록 하겠다.
  • btn[0] : Watch 모드와 Stop 모드를 컨트롤하는 버튼
  • btn_start : start 버튼의 One Cycle Pulse
    - One Cycle Pulse를 통해 해당 버튼이 눌려졌는지 여부를 확인할 수 있다.

 

 

< Source, Control Start / Stop mode >

// Control mode.
wire start_stop;
t_flip_flop t_flip_flop_0 (.clk(clk), .reset_p(reset_p), .t(btn_start), .q(start_stop));
  • start_stop : 현재 스톱 워치가 start 상태인지, stop 상태인지를 나타내는 변수
    - start_stop이 1인 경우 : start mode
    - start_stop이 0인 경우 : stop mode
  • btn[0]이 눌러 btn_start가 활성화되면 T Flip-Flop을 통해 현재 모드를 Toggle시키게 된다.

 

 

< Source, Control Clock Pulse >

// Control clk.
wire clk_start;
assign clk_start = (start_stop)? clk : 0;
  • MUX를 통해 현재 모드에 따라 분주 모듈의 argument 값으로 clk 값을 줄지, 0을 줄지를 결정한다.
  • clk 값을 주게 되면 분주 모듈내에 있는 Counter가 정상적으로 clk에 따라 Counting을 할 수 있지만,
    0을 주게 되면 항상 비활성화 상태이기 때문에 Counter는 정상적으로 Counting 할 수 없다.

 

 

< Source, Prescale >

// 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_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 값을 주는 것이 아닌 모드에 따라 0 값과 clk 값을 선택하여 줌으로서 모드에 따라 시계를 멈출 수 있다.

 

 

< Source, 현재까지의 소스 코드 >

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;
    button_cntr control_btn_set (.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_nedge(btn_start));
    
    // Control mode.
    wire start_stop;
    t_flip_flop t_flip_flop_0 (.clk(clk), .reset_p(reset_p), .t(btn_start), .q(start_stop));
    
    // 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_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));
    
    // BCD 60 Counter
    wire [3:0] min10, min1, sec10, sec1;
    counter_bcd_60 counter_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .bcd1(sec1), .bcd10(sec10));
    counter_bcd_60 counter_min(.clk(clk), .reset_p(reset_p), .clk_time(clk_min), .bcd1(min1), .bcd10(min10));
    
    // Combine data.
    wire [15:0] hex_value;
    assign hex_value = {min10, min1, sec10, sec1};
    
    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

// 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

 

 

 

 

 

 

2.4. 구현 영상