하만(Harman) 세미콘 반도체 설계 과정/Verilog를 이용한 RTL 시스템 반도체 설계

하만(Harman) 세미콘 아카데미 61일차 - Verilog HDL 설계(UART_TX 설계)

semicon_circuitdesigner 2024. 6. 10. 14:10

[2024.06.10.월] 인천인력개발원 하만 세미콘 아카데미


실습 1: UART_TX 설계 


 

  • 위 그림에 맞게 TX의 Input, Output 설정
    module uart_tx(
        input RST,
        input CLK,
        input [7:0] DIN,
        input START,
        output reg TXD
        );
  • 각 상태를 나타내는 idle, start, tx_send, stop을 local parameter로 선언하여 갑 지정 후 register와 wire 선언
    localparam [1:0]    idle = 2'b00,
                        start = 2'b01,
                        tx_send = 2'b10,
                        stop = 2'b11;
    reg [1:0]   curr_state, next_state;
    reg [3:0]   over_sample_cnt;
    reg [3:0]   bit_cnt;
    wire        over_sample_cnt_done, bit_cnt_done;
    wire        parity;
    reg [7:0]   tx_data_in;
    wire [8:0]   tx_data = {parity, tx_data_in};
    wire        baud_x16_en;
  • 1clk마다 tx_data_in에 DIN을 넣어주고, 상태를 다음 상태로 변경하는 코드 작성
    always @(posedge CLK)
        if(START)
            tx_data_in <=DIN;
    
    //1clk마다 다음 상태로 넘어가는 코드
    always @(posedge CLK) begin
        if(RST) //RST이 1이면 초기 상태로 복귀
            curr_state <= idle;
        else    //RST이 0이면 1CLK마다 next_state로 curr_state 변경
            curr_state <= next_state;
    end
  • fsm 작동 코드 작성
    //fsm 구문
    always @(curr_state, START,  over_sample_cnt_done. vit_cnt_done)
    begin
        case (curr_state)
            idle:   //idle 상태에서 START가 1이 되면 curr_state를 start로 바꾸어 시작, 아니면 idle 유지
                if(START)   
                    next_state = start; 
                else
                    next_state = idle;
            start:  //start 상태에서 over_sample_cnt_done이 1이 되면 tx_send 시작, 아니면 start 유지
                if(over_sample_cnt_done)
                    next_state = tx_send;
                else
                    next_state = start;
            tx_send:    //tx_send 상태에서 over_sample_cnt_done과 bit_cnt_done이 모두 1이 되면 stop, 아니면 tx_send 유지
                if(over_sample_cnt_done&&bit_cnt_done)
                    next_state = stop;
                else
                    next_state = tx_send;
            stop:   //stop 상태에서 over_sample_cnt_done이 1이면 idle로 상태 복귀, 아니면 stop 유지
                if(over_sample_cnt_done)
                    next_state = idle;
                else
                    next_state = stop;
            default: next_state = idle;
        endcase
    end


  • over sample count 생성 코드 작성
    //over_sample_cnt 생성
    always @(posedge CLK)
        if(curr_state == idle)
            over_sample_cnt <= 5'd15;
        else if (baud_x16_en)
        over_sample_cnt <= over_sample_cnt-1;
    
    assign over_sample_cnt_done = (over_sample_cnt == 4'd0) & baud_x16_en;
  • bit count 생성 코드 작성
    //bit_cnt 생성
    always @(posedge CLK)
        if(curr_state != tx_send)   //tx_send 상태가 아니라면
            bit_cnt <= 4'd0;
        else if(over_sample_cnt_done)
            bit_cnt <= bit_cnt+1;
            
    assign bit_cnt_done = over_sample_cnt_done & (bit_cnt == 4'd8);
  • parity 생성 및 TXD(parallel -> serial) 코드 작성
    //partiy 생성
    assign parity = ^tx_data[7:0];
    
    //parallel to serial(TXD)
    always @(curr_state, bit_cnt)
        if(curr_state == idle || curr_state == stop)
            TXD = 1'b1;
        else if(curr_state == start)
            TXD = 1'b0;
        else
            TXD = tx_data[bit_cnt];
  • baud_gen 인스턴스화
    //instantiation uart_baud_gen
    uart_baud_gen baud_gen_i0 ( 
        .RST    (RST),
        .CLK    (CLK),
        .BAUD_X16_EN    (baud_x16_en)
    );

 


실습 2: UART_TX Debug 


 

1. Constraint 파일의 debug.xdc 내용 삭제

2. Uart_tx 모듈의 debug 할 신호를 mark debug

 

3. 포트 설정(constraints - uart_pin.xdc파일 편집)

  • set_property IOSTANDARD LVCMOS33 [get_ports TXD]
  • set_property PACKAGE_PIN K18 [get_ports TXD]

4. Run Synthesis - Open Synthesized Design - Layout Debug로 정의된 신호 확인

 

5. Setup Debug

6. Synthesized Design 종료 및 저장

7. Run Implementation - Generate Bitstream - Teraterm으로 확인

 

uart_top.v 전체 코드
더보기
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/05/24 12:25:55
// Design Name: 
// Module Name: uart_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_top(
    input RST,
    input CLK,
    input RXD,
    output TXD
    );

wire    [7:0]   rx_data;
wire empty, rx_data_rdy;
reg    [7:0] dout;
wire    [7:0] dout_reg;

always @(posedge CLK)
begin
    if(!empty)
        dout <= dout_reg;
end

uart_rx uart_rx_0 (
    .RST        (RST),
    .CLK        (CLK),
    .RXD        (RXD),
    .RX_DATA    (rx_data),
    .RX_DATA_RDY    (rx_data_rdy),
    .FRM_ERR    (FRM_ERR),
    .PARITY_ERR (PAR_ERR)
    );    

my_fifo fifo_0(
    .RST    (RST),
    .CLK    (CLK),
    .DIN    (rx_data),
    .WR_EN  (rx_data_rdy),
    .FULL   (FULL),
    .DOUT   (dout_reg),
    .RD_EN  (~empty),
    .EMPTY  (empty)
    );

//uart_tx instantiation
uart_tx uart_tx_0 (
    .RST    (RST),
    .CLK    (CLK),
    .START  (~empty),
    .DIN    (dout),
    .TXD    (TXD)
    );
 
endmodule
uart_tx.v 전체 코드
더보기
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/06/10 09:42:17
// Design Name: 
// Module Name: uart_tx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_tx(
    input RST,
    input CLK,
    (* mark_debug = "true" *)
    input [7:0] DIN,
    (* mark_debug = "true" *)
    input START,
    (* mark_debug = "true" *)
    output reg TXD
    );

localparam [1:0]    idle = 2'b00,
                    start = 2'b01,
                    tx_send = 2'b10,
                    stop = 2'b11;
(* mark_debug = "true" *)                    
reg [1:0]   curr_state;
reg [1:0]   next_state;
(* mark_debug = "true" *)
reg [3:0]   over_sample_cnt;
(* mark_debug = "true" *)
reg [3:0]   bit_cnt;
(* mark_debug = "true" *)
wire        over_sample_cnt_done, bit_cnt_done;
(* mark_debug = "true" *)
wire        parity;
(* mark_debug = "true" *)
reg [7:0]   tx_data_in;
wire [8:0]   tx_data = {parity, tx_data_in};
wire        baud_x16_en;


always @(posedge CLK)
    if(START)
        tx_data_in <=DIN;

//1clk마다 다음 상태로 넘어가는 코드
always @(posedge CLK) begin
    if(RST) //RST이 1이면 초기 상태로 복귀
        curr_state <= idle;
    else    //RST이 0이면 1CLK마다 next_state로 curr_state 변경
        curr_state <= next_state;
end

//fsm 구문
always @(curr_state, START,  over_sample_cnt_done. vit_cnt_done)
begin
    case (curr_state)
        idle:   //idle 상태에서 START가 1이 되면 curr_state를 start로 바꾸어 시작, 아니면 idle 유지
            if(START)   
                next_state = start; 
            else
                next_state = idle;
        start:  //start 상태에서 over_sample_cnt_done이 1이 되면 tx_send 시작, 아니면 start 유지
            if(over_sample_cnt_done)
                next_state = tx_send;
            else
                next_state = start;
        tx_send:    //tx_send 상태에서 over_sample_cnt_done과 bit_cnt_done이 모두 1이 되면 stop, 아니면 tx_send 유지
            if(over_sample_cnt_done&&bit_cnt_done)
                next_state = stop;
            else
                next_state = tx_send;
        stop:   //stop 상태에서 over_sample_cnt_done이 1이면 idle로 상태 복귀, 아니면 stop 유지
            if(over_sample_cnt_done)
                next_state = idle;
            else
                next_state = stop;
        default: next_state = idle;
    endcase
end

//over_sample_cnt 생성
always @(posedge CLK)
    if(curr_state == idle)
        over_sample_cnt <= 5'd15;
    else if (baud_x16_en)
    over_sample_cnt <= over_sample_cnt-1;

assign over_sample_cnt_done = (over_sample_cnt == 4'd0) & baud_x16_en;

//bit_cnt 생성
always @(posedge CLK)
    if(curr_state != tx_send)   //tx_send 상태가 아니라면
        bit_cnt <= 4'd0;
    else if(over_sample_cnt_done)
        bit_cnt <= bit_cnt+1;
        
assign bit_cnt_done = over_sample_cnt_done & (bit_cnt == 4'd8);        

//partiy 생성
assign parity = ^tx_data[7:0];

//parallel to serial(TXD)
always @(curr_state, bit_cnt)
    if(curr_state == idle || curr_state == stop)
        TXD = 1'b1;
    else if(curr_state == start)
        TXD = 1'b0;
    else
        TXD = tx_data[bit_cnt];
        
//instantiation uart_baud_gen
uart_baud_gen baud_gen_i0 ( 
    .RST    (RST),
    .CLK    (CLK),
    .BAUD_X16_EN    (baud_x16_en)
);
endmodule
uart_pin.xdc
더보기
set_property IOSTANDARD LVCMOS33 [get_ports CLK]
set_property IOSTANDARD LVCMOS33 [get_ports RST]
set_property IOSTANDARD LVCMOS33 [get_ports RXD]
set_property IOSTANDARD LVCMOS33 [get_ports TXD]
set_property IOSTANDARD LVCMOS33 K18 [get_ports TXD]
set_property PACKAGE_PIN H16 [get_ports CLK]
set_property PACKAGE_PIN D19 [get_ports RST]
set_property PACKAGE_PIN J18 [get_ports RXD]
set_property PACKAGE_PIN K18 [get_ports TXD]