본문 바로가기

RTL Design/Verilog RTL 설계

Verilog RTL 설계(7월 16일 - 2, Prescaler)

1. Prescaler

  • basys3의 기본 Clock Pulse의 주기는 10ns를 갖는다.
  • 짧은 주기를 갖는 Clock pulse를 가지고 이보다 긴 펄스파형을 생성하거나 낮은 주파수를 갖는 파형을 생성하고 싶을 때, Prescaler 기법을 사용할 수 있다.

  • Prescaler의 주요 기능에 대해서 요약하면 다음과 같다.
    ▶ 고주파 클럭 신호를 낮은 주파수를 갖는 신호로 변환하고자 하는 경우
    ▶ 짧은 주기를 갖는 클럭 신호를 상대적으로 더 긴 주기를 갖는 신호로 변환하고자 하는 경우
    ▶ 입력 클럭 주파수를 일정한 비율로 나누고자 하는 경우

 

  • Q) Prescaler 기법은 어떻게 기본 Clock Pulse를 주기가 더 긴 파형으로 변환할 수 있는가?
    A) 여러 개의 펄스 파형을 하나의 묶음으로 묶은 뒤, 이를 하나의 펄스 파형으로 인식하고, 이렇게 새롭게 정의된 펄스 파형을 Counting하게 되면 기본 Clock Pulse의 주기보다 긴 파형으로 변환할 수 있고, 이를 이용하여 Counter가 카운트 할 수 있는 범위를 늘릴 수 있다.

 

 

 

 

2. 100 분주비 (100 Prescaler)

  • basys3는 기본 클럭 펄스의 주기는 10ns이다. 
  • basys3의 기본 클럭 펄스를 분주시켜 주기를 1us 갖는 새로운 펄스 파형을 만들고자 한다.
  • 1us를 10ns로 나누게 되면 1us / 10ns = 100 이라는 값이 나오게 되며, 해당 값이 분주비가 되는 것이다.
  • 주기가 10ns인 클럭을 100분주한다는 것은 하나의 10ns 펄스를 100개로 묶어 하나의 주기가 10ns인 새로운 펄스 만든다는 것을 의미한다,
  • 따라서 주기가 10ns인 클럭을 100분주함으로서 주기가 1us인 펄스를 생성할 수 있는 것이다.

 

 

 

2.1. 그럼, 어떻게 분주를 통해 새로운 펄스파를 생성할 수 있는것인가?

  • 바로 Counter를 사용하는 것이다.
  • Clock Pulse의 edge을 감지하여 edge 마다 Counter값을 1씩 늘려간다.
  • 따라서 Counter 값이 0 ~ 49일 때까지는 0을 출력하고, 50 ~ 99일 때까지는 1을 출력하게 되면 0 ~ 490ns 까지는 Low 레벨을 갖고, 500ns ~ 990ns 까지는 High 레벨을 갖는 1us 펄스파가 생성되게 된다.
  • 위 과정을 통해 알 수 있듯이 이렇게 생성된 펄스파는 Duty cycle을 50% 갖게 된다.

 

 

 

2.2. Vivado를 통한 100 Prescale

 

< Source >

module Prescaler_100_CP_10ns(
    input clk, enable, reset_p,
    output clk_div_100 );
    
    reg [6:0] counter;
    
    always @(negedge clk or posedge reset_p) begin
           if(reset_p) counter = 0;
           else if(enable) begin 
                if(counter >=99) counter = 0;
                else counter = counter + 1;
           end
    end
    
    assign clk_div_100 = (counter <50) ? 0 : 1;
    
endmodule
  • Q) counter는 얼마의 크기를 가져야 하는가?
  • A) n bit 크기를 갖는 Counter는 0 부터 어디까지 카운트할 수 있는가? 0 ~ 2^n - 1까지 카운트가 가능하다.
        ex) 4bit Counter는 0 ~ 15까지 카운트 가능하다.
              10bit Counter는 0 ~ 1023까지 카운트 가능하다.
         따라서 0 ~ 100까지 카운트를 하기 위해서 최소한 7bit counter 가져야 0 ~ 127까지 카운트가 가능해야 
         100까지의 카운트가 가능ㅎ다.

 

 

< Simulation >

  • 시뮬레이션을 통해 주기가 10ns인 Clock Pulse을 100분주하여 새로 생성된 펄스 파형은 주기를 1us를 갖는 것을 확인할 수 있다.

 

 

 

 

 

 

3. 100 분주시켜 새롭게 생성된 파형에 Edge detector를 설치 

  • 위 구현에서는 주기가 10ns인 기본 클럭을 100 분주화하여 주기가 1us인 펄스 파형을 생성했다.
  • 이번에는 새롭게 생성된 주기가 1us인 펄스 파형에 Negative edge detector를 달아 보겠다.
  • 따라서 Negative edge detector는 1us마다 Negative edge가 발생할 때마다 One cycle pulse를 출력으로 내보낼 것이다.

 

< Source , Negative edge detector >

// Negative edge detector
module edge_detector_n (
    input clk, reset_p, 
    input cp,
    output n_edge );
    
    reg flip_flop_current, flip_flop_old;
    
    always @(negedge 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 n_edge = ({flip_flop_current, flip_flop_old} == 2'b01)? 1 : 0;
    
endmodule
 

Verilog RTL 설계(7월 12일 - 6, Edge detector)

flip_flop_current = cp;flip_flop_old = flip_flop_current;1. Verilog에서 동기순차회로를 설계할 때에는 Clock Pulse와 Reset만 Sensitive variable로 사용하고, 나머지 변수에 대해서는 Sensitive variable로 사용하지 않는다.PD

jbhdeve.tistory.com

 

 

 

< Source , Prescaler 100 >

// Prescaler 100
module Prescaler_100_One_Cycle_Pulse (
    input clk, reset_p,
    output clk_div_100,
    output clk_div_100_nedge );
    
    reg [6:0] count;
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) count = 0;
        else begin
            if(count >= 99) count = 0;
            else count = count + 1;
        end
    end
    
    assign clk_div_100 = (count < 50)? 0 : 1;
    
    edge_detector_n negative_edge_detector (clk, reset_p, clk_div_100, clk_div_100_nedge);
    
endmodule
  • CP 값으로 100 분주를 통해 새로 생성된 주기가 1us인 파형을 argument 값으로 넘겨준다.
  • negative edge detector로 clk_div_100_nedge 값을 argument으로 넘겨주면 clk_div_100_nedge는 Negative edge 때마다 One Cycle Pulse를 발생시켜 출력시키게 된다.

 

< Simulation >

 

 

 

 

 

 

4. 100분주한 뒤, 다시 1000분주 시켜 주기가 1ms인 파형을 생성하기

  • 주기가 10ns인 기본 클럭을 100분주화하여 주기가 1us인 펄스 파형을 생성하였고, 이를 Negative edge detector를 통해 Negative edge 때마다 One cycle pulse를 출력했다.
  • 이번에는 이렇게 1us 펄스에서 negative edge 때마다 negative edge detector가 내보내는 One cycle pulse를 감지하여 해당 값이 1일 때마다 1씩 카운트하겠다.
  • Counter는 0 ~ 999까지 Counting할 수 있어야 하기 때문에 Counter의 크기는 최소 10bit 이상을 가져야 하며, 0 ~ 499까지는 Low 레벨을 출력하며, 500 ~ 999까지는 High 레벨을 출력한다.
  • 따라서 100분주된 주기가 1us인 펄스파를 다시 1000분주 하였기 때문에 새로 생성된 파형은 10ns * 100 * 1000 = 1ms 주기를 갖는다.
  • 마지막으로, 100분주하고, 다시 1000분주하여 새롭게 생성된 클럭 펄스는 1ms의 주기를 가지며, 이를 다시 Negative edge detector를 사용하여 1ms 마다 발생하는 Negative edgd에서 One cycle pulse를 발생시키도록 할 것이다.

 

 

< Source , Negative edge detector >

module edge_detector_n_new (
    input clk, enable, reset_p,
    input cp,
    output n_edge );
    
    reg flip_flop_current, flip_flop_old;
    
    always @(negedge clk or posedge reset_p) begin
        if(reset_p) begin 
             flip_flop_current <= 0;
             flip_flop_old <= 0;
        end 
        else if(enable) begin
            flip_flop_current <= cp;
            flip_flop_old <= flip_flop_current;
        end
    end
    
    assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01) ? 1 : 0;
endmodule

 

< Source , Prescaler 1000 >

module Prescaler_1000_CP_10ns_One_Cycle_Pulse(
    input clk, enable, reset_p,
    input clk_div_100,
    output clk_div_1000,
    output clk_div_1000_nedge);
    
    reg [9:0] counter;
    // 100분주를 통해 생성된 주기 1us인 파형의 하강 엣지에서 출력되는 One cycle detector
    wire detect_One_Cycle_Pulse;
    
    // 주기가 1us인 펄스 파의 negative edge 감지.
    edge_detector_n_new negative_edge_detector_0 (clk, enable, reset_p, clk_div_100, detect_One_Cycle_Pulse);
   
    always @(negedge clk or posedge reset_p) begin
        if(reset_p) counter <= 0;
        else if(enable && detect_One_Cycle_Pulse) begin 
               if(counter >= 999) counter = 0;
               else counter = counter + 1;
        end
    end
    
    // 1000분주를 통해 생성된 주기가 1ms인 파형
    assign clk_div_1000 = (counter <= 499) ? 0 : 1;
    
    // 주기가 1ms인 파형의 하강엣지에서 출력되는 One cycle detector
    edge_detector_n_new negative_edge_detector_1 (clk, enable, reset_p, clk_div_1000, clk_div_1000_nedge);
    
endmodule

 

< Analysis Source Code >

  • 변수들의 기능 및 역활은 다음과 같다.
    - clk_div_100은 주기가 10ns인 CP를 100분주하여 주기가 1us인 펄스파형을 의미한다.
    - clk_div_1000은 주기가 1us인 Pulse를 1000분주하여 주기가 1ms인 펄스파형을 의미한다.
    - clk_div_1000_nedge는 clk_div_1000을 Negative edge detector에 넣어 Negative edge 때마다 발생되는 One Cycle Pulse 파형을 의미한다. 
    - detect_One_Cycle_Pulse는 주기가 1us인 Pulse를 Negative edge detector에 넣어 Negative edge 때마다 발생되는 One Cycle Pulse 파형을 의미한다.


  • 위 코드의 알고리즘은 다음과 같다.
    - 1단계) 주기가 10ns인 기본 클럭을 100분주하여 주기가 1us인 펄스 파를 생성한다. (생략)
    - 2단계) Negative edge detector에 CP 값으로 주기가 1us인 펄스 파를 넣어 하강 엣지때마다 One Cycle Pulse을 발생시키도록 한 뒤, One Cycel Pulse를 detect_One_Cycle_Pulse 변수가 받기.
    - 3단계) detect_One_Cycle_Pulse 변수 값이 1일 때마다 Counter가 1씩 증가하기.
    - 4단계) assign clk_div_1000 = (counter <= 499) ? 0 : 1; 명령문을 통해 주기가 1ms인 파형을 출력
    - 5단계) 주기가 1ms인 파형을 Negative edge detector에 CP 값으로 넣어서 하강 엣지때마다 One Cycle Pulse을 발생시키도록 한 뒤, One Cycel Pulse를 clk_div_1000_nedge 변수가 받아서 출력으로 내보내기.

 

 

< Simulation >

  • 1000분주를 통해 생성된 파형은 1ms 마다 하강 엣지가 발생하기 때문에 이를 Negative edge detector가 감지하여 One Cycle Pulse를 1ms마다 출력시키는 것을 확인할 수 있다.