본문 바로가기

RTL Design/Verilog RTL 설계

Verilog RTL 설계(7월 17일 - 1, FND Shifting)

1. 10sec 주기로 FND Left Shifting 하기

  • 이번에는 10sec 주기마다 왼쪽으로 Shifting하는 코드를 구현하도록 하겠다.
  • 다음과 같이 동작한다.
    - 12번째부터 15번째 Switch를 통해 16진값을 표현한다.
    - 가장 오른쪽 FND를 첫 번째 FND라고 하였을 때, 10sec를 주기로 왼쪽으로 Shifting한다.
    - 4번째 FND에 도달하게 되면 다시 첫 번째 FND으로 돌아와 무한 반복한다.

 

 

 

1.1. 주기가 10sec이기 위해서는 Counter는 얼마의 크기를 가져야 하는가?

  • Basys3의 기본 클럭 주기는 10ns이다. 따라서 10sec 주기를 갖기 위해서는 10nsec을 1000000000 분주를 해야한다.
  • 따라서 Counter는 1000000000분주를 하기 위해서는 1000000000까지 Counting할 수 있어야 한다.
  • Counter가 1000000000까지 Counting하기 위해서는 최소한 30bit 크기를 가져야 한다.
  • 하지만, 이번에  사용된 Counter는 여유롭게 가져 32bit를 갖도록  설계하였다.

 

 

1.2. Left Shifting을 하기 위해서는 어떻게 해야하는가?

  • 유한하게 Shifting하는 것은 Shift 연산자를 통해 수행이 가능하다.
  • 하지만, 무한하게 Left Shifting하기 위해서는 이를 무한적으로 작업할 수 있는 모듈이 필요하며, 이러한 작업 수행할 수 있는 모듈이 바로 Ring Counter 이다.
  • 따라서 Ring Counter내에서 Common anode의 정보를 담고 있는 anode 배열을 Ring Counter를 통해 원하는 FND만 출력하도록 해당 com 값을 0으로 설정하고, 출력을 원치 않는 FND의 com 값을 1로 설정하여 이를 Shifting 시킴으로서 특정 FND만 불이 나오면서 Shift 될 수 있도록 만들 수 있다.

 

 

1.3. 구현

 

< Source , Decoder_7_segment>

  • Decoder 형태로 구현된 7-Segement 정보를 출력으로 내보내는 모듈
  • 즉, 4bit 크기의 16진 값을 받으면 FND로 해당 값을 출력하기 위한 FND 정보를 8bit 크기로 출력한다.
// Get the Information of FND by using 7-Segment.
module decoder_7_segment (
    input [3:0] hex_value,
    output reg [7:0] seg_7 );
   
   always @(hex_value) begin
        case(hex_value)
            0  : seg_7 = 8'b0000_0011;  // 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'b0000_0101;  // 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

 

 

 

< Source , Edge Detector >

  • Positive edge와 Negative edge를 감지할 수 있는 Edge detector 모듈
  • D Flip Flop 2개를 직렬 연결함으로서 구현하였다.
// Edge Detector
module edge_detector_n (
    input clk, reset_p,
    input cp,
    input n_edge, p_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;
    assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10) ? 1 : 0; 
    
endmodule

 

 

 

< Source, Prescaler 1000000>

  • 입력 받은 클럭 펄스 (clock_source)를 1000000분주하여 출력으로 내보내는 모듈
  • 입력 받은 클럭 펄스 (clock_source)는 One cycle Pulse 형태가 아닌 일반적인 펄스파형을 받는다.
  • 1000000 분주화하기 위해서 해당 모듈에서 32bit Counter를 사용하였다.
  • 해당 모듈로 나갈 수 있는 펄스는 2가지이다.
    - clk_div_1000000000 : 주기가 10sec이면서 Duty cycle이 50%인 펄스파
    - clk_div_1000000000_nedge : 주기가 10sec인 One Cycle Pulse
// Prescaler 1000000
module clk_div_1000000000 (
    input clk, reset_p,
    input clock_source, 
    output clk_div_1000000000,
    output clk_div_1000000000_nedge);
 
    // Detect of negative edge of clock_source.
    wire clk_time_nedge;
    edge_detector_n(.clk(clk), .reset_p(reset_p), .cp(clock_source), .n_edge(clk_time_nedge));
    
    // 17bit Counter 
    reg [31:0] counter;
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) counter = 0;
        else begin
            if(counter >= 999999999) counter = 0;
            else counter = counter + 1;
        end
    end 
    
    assign clk_div_1000000000 = (counter < 500000000)? 0 : 1;
    
    edge_detector_n(.clk(clk), .reset_p(reset_p), .cp(clk_div_1000000000), .n_edge(clk_div_1000000000_nedge));
endmodule

 

 

 

< Source , Ring Counter로 구현한 FND의 common anode 제어 모듈 >

  • 해당 모듈은 Shifting 연산을 무한적으로 반복하기 위해 Ring Counter를 사용했다.
  • wire형인 clk_10s 변수는 주기가 10s인 One Cycle Pulse이다.
  • com 변수 값을 10sec을 주기마다 left shifting을 받기 위해서는 주기를 10sec마다 알려주는 신호가 필요하는데, 해당 역활을 수행하는 신호가 바로 clk_10s 이다.
    - One Cycle Pulse인 clk_10s는 주기가 10sec를 가지며, 10ns 동안만 활성화되고, 나머지 시간은 다 비활성화 상태를 갖는 신호이다. 
  • 그래서 com 변수의 Shifting 작업은 clk_10s 신호에 맞춰 수행되게 된다.
    • decoder_7_segment 모듈을 통해 Switch로 부터 얻은 데이터를 FND로 출력하게 된다.
module left_shift_10s (
    input clk, reset_p,
    input [15:0] switch,
    output reg [3:0] com,
    output [7:0] seg_7
);
    wire clk_10s;
    
    clk_div_1000000000 u_clk_div(
        .clk(clk),
        .reset_p(reset_p),
        .clk_div_1000000000_nedge(clk_10ms)
    );
        
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) com <= 4'b1110;
        else if(clk_10s) begin
            if(com == 4'b0111) com <= 4'b1110;
            else com <= {com[2:0], 1'b1};
        end
    end

    
    decoder_7_segment decoder(
        .hex_value(switch[15:12]),
        .seg_7(seg_7)
    );
endmodule

 

 

 

< Source, 전체 코드 >

// Ring Counter for FND
module left_shift_10s (
    input clk, reset_p,
    input [15:0] switch,
    output reg [3:0] com,
    output [7:0] seg_7
);
    wire clk_10s;
    
    clk_div_1000000000 u_clk_div(
        .clk(clk),
        .reset_p(reset_p),
        .clk_div_1000000000_nedge(clk_10ms)
    );
        
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) com <= 4'b1110;
        else if(clk_10ms) begin
            if(com == 4'b0111) com <= 4'b1110;
            else com <= {com[2:0], 1'b1};
        end
    end

    
    decoder_7_segment decoder(
        .hex_value(switch[15:12]),
        .seg_7(seg_7)
    );
endmodule

// Prescaler 1000000
module clk_div_1000000000 (
    input clk, reset_p,
    input clock_source, 
    output clk_div_1000000000,
    output clk_div_1000000000_nedge);
 
    // Detect of negative edge of clock_source.
    wire clk_time_nedge;
    edge_detector_n(.clk(clk), .reset_p(reset_p), .cp(clock_source), .n_edge(clk_time_nedge));
    
    // 17bit Counter 
    reg [32:0] counter;
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) counter = 0;
        else begin
            if(counter >= 999999999) counter = 0;
            else counter = counter + 1;
        end
    end 
    
    assign clk_div_1000000000 = (counter < 500000000)? 0 : 1;
    
    edge_detector_n(.clk(clk), .reset_p(reset_p), .cp(clk_div_1000000000), .n_edge(clk_div_1000000000_nedge));
endmodule

// Edge Detector
module edge_detector_n (
    input clk, reset_p,
    input cp,
    input n_edge, p_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;
    assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10) ? 1 : 0; 
    
endmodule

// Get the Information of FND by using 7-Segment.
module decoder_7_segment (
    input [3:0] hex_value,
    output reg [7:0] seg_7 );
   
   always @(hex_value) begin
        case(hex_value)
            0  : seg_7 = 8'b0000_0011;  // 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'b0000_0101;  // 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

 

 

 

 

 

1.4. 구현 영상