본문 바로가기

[Harman] 반도체 설계/Quartus

Quartus II project - Uart Rx Segment [2].

`include"../simple_uart_tx/simple_uart_tx.v"

module simple_uart_rx (
    input clk,
    input reset_n,
    input rx,
    output [7:0] rx_data
);
    localparam IDLE = 0;
    localparam START = 1;
    localparam MID = 2;
    localparam D0 = 3;
    localparam D1 = 4;
    localparam D2 = 5;
    localparam D3 = 6;
    localparam D4 = 7;
    localparam D5 = 8;
    localparam D6 = 9;
    localparam D7 = 10;
    localparam STOP = 11;
    localparam STOP_1 = 12;

    reg rx_delay1;
    reg rx_delay2;
    reg [3:0] cst;
    reg [3:0] nst;

    reg [8:0] clk_count;
    reg [7:0] rRxdata;

    // falling edge detection : initiate 'start' or CDC, Metastability
    always @(posedge clk, negedge reset_n) begin
        if(!reset_n) begin
            rx_delay1 <= 1'b0;
            rx_delay2 <= 1'b0;        
        end
        else begin
            rx_delay1 <= rx;
            rx_delay2 <= rx_delay1;
        end
    end

    wire f_edge_det = !rx_delay1 & rx_delay2;

    wire bit_clr_st = f_edge_det & (cst == IDLE);
    wire bit_clr_ha = (clk_count == 216) && (cst == START);
    wire bit_clr = (clk_count == 433);

    //counter
    always @(posedge clk, negedge reset_n) begin
        if(!reset_n)
            clk_count <= 0;
        else if (bit_clr_st)
            clk_count <= 0;
        else if (bit_clr_ha)
            clk_count <= 0; 
        else if (bit_clr)
            clk_count <= 0;
        else 
            clk_count <= clk_count + 1;
    end
    
    //seq
    always @(posedge clk, negedge reset_n) begin
        if(!reset_n) begin
            cst <= IDLE;
        end else 
            cst <= nst;
    end

    //comb
    always @(*) begin
        case (cst)
            IDLE : if (f_edge_det) nst = START;
            START : if (bit_clr_ha) nst = D0;  
            D0 : if (bit_clr) nst = D1;  
            D1 : if (bit_clr) nst = D2;
            D2 : if (bit_clr) nst = D3;
            D3 : if (bit_clr) nst = D4;
            D4 : if (bit_clr) nst = D5;
            D5 : if (bit_clr) nst = D6;
            D6 : if (bit_clr) nst = D7;
            D7 : if (bit_clr) nst = STOP;
            STOP : if (bit_clr) nst = IDLE;            
            default : nst = IDLE; 
        endcase
    end

    //output
    always @(posedge clk, negedge reset_n) begin
        if(!reset_n)
            rRxdata <= 0;
        else begin
            case (cst) 
                D0 : if (bit_clr) rRxdata[0] = rx;  
                D1 : if (bit_clr) rRxdata[1] = rx; 
                D2 : if (bit_clr) rRxdata[2] = rx;
                D3 : if (bit_clr) rRxdata[3] = rx;
                D4 : if (bit_clr) rRxdata[4] = rx;
                D5 : if (bit_clr) rRxdata[5] = rx;
                D6 : if (bit_clr) rRxdata[6] = rx;
                D7 : if (bit_clr) rRxdata[7] = rx;
                //STOP : 

            endcase
        end
    end

    assign rx_data = rRxdata;
    
endmodule
//testbench

`timescale 1 ns / 1 ns

module tb_simple_uart_rx ();
    
    reg clk; // design arbitrary pattern 
    reg reset_n; // design arbitrary pattern 
    wire tx;
    wire [7:0] rx_data;

    simple_uart_tx uSimple_uart_tx_0 (
        .clk(clk),
        .reset_n(reset_n),
        .tx(tx)
    );

    simple_uart_rx uSimple_uart_rx_0 (
        .clk(clk),
        .reset_n(reset_n),
        .rx(tx),
        .rx_data(rx_data)
    );

    // clock gen : design arbitrary pattern
    initial begin
        clk = 1'b0;
        forever #10 clk = ~ clk;
    end

    // always #10 clk = ~ clk;

    // reset_n gen : design arbitrary pattern
    initial begin
        reset_n = 1'b1;
        @(negedge clk);
        @(negedge clk);
        reset_n = 1'b0;
        @(negedge clk);
        @(negedge clk);
        @(negedge clk);
        reset_n = 1'b1;
    end
    
endmodule
// tcl file

vlib work
vlog simple_uart_tx.v simple_uart_rx.v tb_simple_uart_rx.v
vsim work.tb_simple_uart_rx
view wave

add wave -radix unsigned /clk
add wave -radix unsigned /reset_n
add wave -radix unsigned /rx
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/rx
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/rx_delay1
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/rx_delay2
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/f_edge_det
//add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/clk_count
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/bit_clr_st
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/bit_clr_ha
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/cst
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/nst

run 300 us

 

Simulation waveform ASCII 'X', 01011000.

 

상태 변화(STOP, 11 → IDLE, 0) 이후에도 rx_data 값 유지.

 

simple_uart_tx module 의 ASCII 'X' 가 simple_uart_rx module 내부로 instantiation. Simulation 을 통해 [7:0] rx_data (0101 1000) 를 확인했고, DE1-SoC Board 에 연결하여 7-segment 동작을 확인한다. 

//instantiation, 7segment

    seven_segment_cntrl uSeven_segment_cntrl_hex1 (
        .inp(rRxdata[7:4]),
        .seg_a(seg_a),
        .seg_b(seg_b),
        .seg_c(seg_c),
        .seg_d(seg_d),
        .seg_e(seg_e),
        .seg_f(seg_f),
        .seg_g(seg_g)
    );
	
    seven_segment_cntrl uSeven_segment_cntrl_hex0 (
        .inp(rRxdata[3:0]),
        .seg_a(seg_h),
        .seg_b(seg_i),
        .seg_c(seg_j),
        .seg_d(seg_k),
        .seg_e(seg_l),
        .seg_f(seg_m),
        .seg_g(seg_n)
    );

 

simple_uart_tx module 에서 지정한 ASCII 'X' 가 아닌, 임의의 입력에 대한 7segment 출력을 확인하고자 한다.

//`include"../simple_uart_tx/simple_uart_tx.v"
`include"../lab3_2/seven_segment_cntrl.v"


module simple_uart_rx (
    input clk,
    input reset_n,
    input rx,
    //output [7:0] rx_data
	 
    output seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g, 
    output seg_h, seg_i, seg_j, seg_k, seg_l, seg_m, seg_n 
);
    localparam IDLE = 0;
    localparam START = 1;
    localparam MID = 2;
    localparam D0 = 3;
    localparam D1 = 4;
    localparam D2 = 5;
    localparam D3 = 6;
    localparam D4 = 7;
    localparam D5 = 8;
    localparam D6 = 9;
    localparam D7 = 10;
    localparam STOP = 11;
    localparam STOP_1 = 12;

    reg rx_delay1;
    reg rx_delay2;
    reg [3:0] cst = 0;
    reg [3:0] nst;

    reg [8:0] clk_count = 0;
    reg [7:0] rRxdata;

    // falling edge detection : initiate 'start' or CDC, Metastability
    always @(posedge clk, negedge reset_n) begin
        if(!reset_n) begin
            rx_delay1 <= 1'b0;
            rx_delay2 <= 1'b0;        
        end
        else begin
            rx_delay1 <= rx;
            rx_delay2 <= rx_delay1;
        end
    end

    wire f_edge_det = !rx_delay1 & rx_delay2;

    wire bit_clr_st = f_edge_det & (cst == IDLE);
    wire bit_clr_ha = (clk_count == 216) && (cst == START);
    wire bit_clr = (clk_count == 433);

    //counter
    always @(posedge clk, negedge reset_n) begin
        if(!reset_n)
            clk_count <= 0;
        else if (bit_clr_st)
            clk_count <= 0;
        else if (bit_clr_ha)
            clk_count <= 0; 
        else if (bit_clr)
            clk_count <= 0;
        else 
            clk_count <= clk_count + 1;
    end
    
    //seq
    always @(posedge clk, negedge reset_n) begin
        if(!reset_n) begin
            cst <= IDLE;
        end else 
            cst <= nst;
    end

    //comb
    always @(*) begin
        case (cst)
            IDLE : if (f_edge_det) nst = START;
            START : if (bit_clr_ha) nst = D0;
            D0 	: if (bit_clr) nst = D1;
            D1 	: if (bit_clr) nst = D2;
            D2 	: if (bit_clr) nst = D3;
            D3 	: if (bit_clr) nst = D4;
            D4 	: if (bit_clr) nst = D5;
            D5 	: if (bit_clr) nst = D6;
            D6 	: if (bit_clr) nst = D7;
            D7 	: if (bit_clr) nst = STOP;
            STOP : if (bit_clr) nst = IDLE;
            default : nst = IDLE; 
        endcase
    end

    always @(posedge clk, negedge reset_n) begin
        if(!reset_n)
            rRxdata <= 0;
        else begin
            case (cst) 
                D0 : if (bit_clr) rRxdata[0] <= rx;  
                D1 : if (bit_clr) rRxdata[1] <= rx; 
                D2 : if (bit_clr) rRxdata[2] <= rx;
                D3 : if (bit_clr) rRxdata[3] <= rx;
                D4 : if (bit_clr) rRxdata[4] <= rx;
                D5 : if (bit_clr) rRxdata[5] <= rx;
                D6 : if (bit_clr) rRxdata[6] <= rx;
                D7 : if (bit_clr) rRxdata[7] <= rx;
            endcase
        end
    end

    //assign rx_data = rRxdata;
     
    seven_segment_cntrl uSeven_segment_cntrl_hex1 (
        .inp(rRxdata[7:4]),
        .seg_a(seg_a),
        .seg_b(seg_b),
        .seg_c(seg_c),
        .seg_d(seg_d),
        .seg_e(seg_e),
        .seg_f(seg_f),
        .seg_g(seg_g)
    );
	
    seven_segment_cntrl uSeven_segment_cntrl_hex0 (
        .inp(rRxdata[3:0]),
        .seg_a(seg_h),
        .seg_b(seg_i),
        .seg_c(seg_j),
        .seg_d(seg_k),
        .seg_e(seg_l),
        .seg_f(seg_m),
        .seg_g(seg_n)
    );
	
endmodule

 

일단 보드 연결하기 전에 simulation 맛보기 Test-bench.

`timescale 1 ns / 1 ns

module simple_uart_rx_tb ();

   reg clk;
   reg reset_n;
   reg rx;
   
   wire seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g;
   wire seg_h, seg_i, seg_j, seg_k, seg_l, seg_m, seg_n;
   
   simple_uart_rx uSimple_uart_rx (
      .clk(clk),
      .reset_n(reset_n),
      .rx(rx),
      .seg_a(seg_a), 
      .seg_b(seg_b), 
      .seg_c(seg_c), 
      .seg_d(seg_d), 
      .seg_e(seg_e), 
      .seg_f(seg_f), 
      .seg_g(seg_g),
      .seg_h(seg_h), 
      .seg_i(seg_i), 
      .seg_j(seg_j), 
      .seg_k(seg_k), 
      .seg_l(seg_l), 
      .seg_m(seg_m), 
      .seg_n(seg_n)
   );
   
   initial begin
      clk = 1'b1;
      forever #10 clk = ~ clk;
   end
   
   initial begin
      reset_n = 1'b1;
   end
   
   initial begin 
      rx = 1'b1;
      #20000 rx = 1'b0;
      #4340 rx = 1'b0;
      
      #8680 rx = 1'b0;
      #8680 rx = 1'b0;
      #8680 rx = 1'b0;
      #8680 rx = 1'b1;
      #8680 rx = 1'b1;
      #8680 rx = 1'b0;
      #8680 rx = 1'b1;
      #8680 rx = 1'b0;//ASCII 'X'
      
      #8680 rx = 1'b1;
      #8680 rx = 1'b1;//STOP
      
      #8680 rx = 1'b1;
      #8680 rx = 1'b0;
      #4340 rx = 1'b0;
      
      #8680 rx = 1'b1;
      #8680 rx = 1'b0;
      #8680 rx = 1'b0;
      #8680 rx = 1'b0;
      #8680 rx = 1'b0;
      #8680 rx = 1'b0;
      #8680 rx = 1'b1;
      #8680 rx = 1'b0;//ASCII 'A'
      
      #8680 rx = 1'b1;
      #8680 rx = 1'b1;//STOP
      
   end
endmodule

 

ASCII code 출력 확인.

X, 0101 1000
A, 0100 0001

 

7segment 출력 확인.

ASCII code 'X'

rx_data[0] 을 시작으로  rx_data[3] 까지 채워지면 hex0 값(seg_h ~ seg_n) 출력. 이후에 rx_data[7] 까지 모두 채워지면  hex1 값(seg_a ~ seg_g) 까지도 출력.

 

ASCII code 'A'

 

Board 연결 : Pin Planner, Programmer. (DE1-SoC spec 참고)

 

띠요옹? 이상한 값이 나와버렸다.

초기 상태(AA), A, Z, C

 

RTL Viewer 를 확인하면 cst 앞에 Latch 가 발생했다. 

 

Latch 들은 Synthesis Tool 에서 자동으로 생성되며, verilog HDL code 내에 지정되어야 하는 모든 조건들 중 일부가 정의되지 않았기 때문에 발생한다. 

    always @(*) begin
        case (cst)
            IDLE     : if (f_edge_det) nst = START;
            START    : if (bit_clr_ha) nst = D0; 
            D0 	     : if (bit_clr) nst = D1;
            D1 	     : if (bit_clr) nst = D2;
            D2 	     : if (bit_clr) nst = D3;
            D3 	     : if (bit_clr) nst = D4;
            D4 	     : if (bit_clr) nst = D5; 
            D5 	     : if (bit_clr) nst = D6;
            D6 	     : if (bit_clr) nst = D7;
            D7 	     : if (bit_clr) nst = STOP; 
            STOP     : if (bit_clr) nst = IDLE;
            default  : nst = IDLE; 
        endcase
    end

 

위와 같은 IF 문에서 가능한 조건들에 대하여 모두 동작정의가 되어 있지 않으면 nst 에 이전 값을 저장하는 Latch 가 자동으로 합성된다. Latch 는 Clock Edge 기반의 Synchronous 동작이 아닌 level sensitive, Asynchronous 동작이다. 따라서, Timing 관점에서 문제가 발생한다. 

 

 

    always @(*) begin
        case (cst)
            IDLE      : if (f_edge_det) nst = START; else nst = IDLE;
            START     : if (bit_clr_ha) nst = D0;    else nst = START;
            D0 	      : if (bit_clr) nst = D1;       else nst = D0;
            D1 	      : if (bit_clr) nst = D2;       else nst = D1;
            D2 	      : if (bit_clr) nst = D3;       else nst = D2;
            D3 	      : if (bit_clr) nst = D4;       else nst = D3;
            D4 	      : if (bit_clr) nst = D5;       else nst = D4;
            D5 	      : if (bit_clr) nst = D6;       else nst = D5;
            D6 	      : if (bit_clr) nst = D7;       else nst = D6;
            D7 	      : if (bit_clr) nst = STOP;     else nst = D7;
            STOP      : if (bit_clr) nst = IDLE;     else nst = STOP;
            default   : nst = IDLE; 
        endcase
    end

 

뾰로롱~

초기상태, A, Z, X, M, reset
RTL Viewer : cst

RTL Viewer 도 깔끔하게 나왔다.

 

    //Latch generation
    
    always @(*) begin
        if(!reset_n)
            rRxdata = 0;
        else begin
            case (cst) 
                D0 : if (bit_clr) rRxdata[0] = rx;  
                D1 : if (bit_clr) rRxdata[1] = rx; 
                D2 : if (bit_clr) rRxdata[2] = rx;
                D3 : if (bit_clr) rRxdata[3] = rx;
                D4 : if (bit_clr) rRxdata[4] = rx;
                D5 : if (bit_clr) rRxdata[5] = rx;
                D6 : if (bit_clr) rRxdata[6] = rx;
                D7 : if (bit_clr) rRxdata[7] = rx;
            endcase
        end
    end

    always @(posedge clk, negedge reset_n) begin
        if(!reset_n)
            rRxdata <= 0;
        else begin
            case (cst) 
                D0 : if (bit_clr) rRxdata[0] <= rx;  
                D1 : if (bit_clr) rRxdata[1] <= rx; 
                D2 : if (bit_clr) rRxdata[2] <= rx;
                D3 : if (bit_clr) rRxdata[3] <= rx;
                D4 : if (bit_clr) rRxdata[4] <= rx;
                D5 : if (bit_clr) rRxdata[5] <= rx;
                D6 : if (bit_clr) rRxdata[6] <= rx;
                D7 : if (bit_clr) rRxdata[7] <= rx;
            endcase
        end
    end

위와 같이 always @( ) block 내에서 clk 와 같은 동기화 신호를 Sensitivity list 에 포함시키는 경우, 해당 block 내의 register 나 logic circuit 는 클럭 신호에 의해 동작하는 순차 회로(Sequential Circuit)로 간주된다. 따라서, else 문을 사용하지 않아도 latch 를 생성하지 않는다. 이미 클럭에 의해 트리거(Edge-triggered)되는 순간, 순차 논리에서 if 문이 아닌 모든 조건에 대해 해당 상태가 이전 클럭 사이클에서 저장된 상태를 유지하기 때문이다.