---
# System prepended metadata

title: 軟硬體協同設計HW6

---

# 軟硬體協同設計HW6
### ●　作業標題：7-Seg Display controlled by UART
### ●　班級姓名座號：國立高雄大學電機系大四 B1095117 黃致衡
### ●　授課老師：林宏益教授

---
## 一、作業內容：
###
撰寫具有 UART 通訊協定中能進行 RX 功能的模組。

## 二、實作步驟：

### 1. 撰寫除頻器的 RTL code (clk_div.v)
```
module clk_div
    (
        input clk,
        input rst_n,
        output reg clkout
    );

    parameter BAUDRATE = 9600;
    parameter DIV_NUMBER = 125000000 / BAUDRATE;

    reg [13:0] num = 0;

    always@(posedge clk or negedge rst_n) 
    begin
        if(!rst_n)
            begin
                num <= 0;
                clkout <= 0;
            end
        else
            if(num == DIV_NUMBER-1)
                begin
                    num <= 0;
                    clkout <= 1;
                end
            else
                begin
                    num <= num+1;
                    clkout <= 0;
                end
    end
endmodule
```
### 2. 再撰寫除頻器的 Testbench (clk_div_tb.v)
```
`timescale 1ns / 1ps

module clk_div_tb;

    reg tb_clk, tb_rst_n;
    wire clkout;

    parameter clk_duration = 8;

    initial
    begin
        $dumpfile("test.vcd");
        $dumpvars;
    end


    initial
    begin
        tb_clk = 1'b1;
        tb_rst_n = 1'b0;
        #20 tb_rst_n = 1'b1;
        #20 tb_rst_n = 1'b0;
        #5_000_000  $finish;
    end

    always #(clk_duration/2) tb_clk = ~tb_clk;


    clk_div u_clk_div(.clk(tb_clk), .rst_n(tb_rst_n), .clkout(clkout));

endmodule
```

※模擬結果圖
![divsion](https://hackmd.io/_uploads/ryiLPnBIa.png)
> 由此可知 DIVISION_NUMBER 大約需設定為 13020，其公式為：
>  Clock signal / BAUDRATE。

### 3. 撰寫 UART 中 RX 模組的 RTL code (clk_div.v)
```
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date:    22:27:09 12/04/2019 
// Design Name: 
// Module Name:    uart_rx 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//
module uart_rx
    (
        input clk,
        input rst_n,
        input rx,
        output reg [9:0] data_out
    );


// State Machine Defination
    parameter IDLE = 2'b01;
    parameter SAMP = 2'b10;
    
// UART Configure Defination
    parameter START_BIT = 1;
    parameter DATA_BIT  = 8;
    parameter STOP_BIT  = 1;
    parameter PARI_BIT  = 0;
    parameter RECV_BIT  = START_BIT + DATA_BIT + STOP_BIT + PARI_BIT;
    
// Negedge Detection Filter
    reg [3:0] data_in;
    always @ (posedge clk or negedge rst_n)
        if (!rst_n) 
        begin
            data_in[0] <= 1'b0;
            data_in[1] <= 1'b0;
            data_in[2] <= 1'b0;
            data_in[3] <= 1'b0;
        end
        else 
        begin
            data_in[0] <= rx;
            data_in[1] <= data_in[0];
            data_in[2] <= data_in[1];
            data_in[3] <= data_in[2];
        end
 
    wire rx_neg = data_in[3] & data_in[2] & (~data_in[1]) & (~data_in[0]);

    reg [1:0] current_state, next_state;

// Current State To Next State
    always @ (posedge clk or negedge rst_n)
    if(!rst_n)
        current_state <= IDLE;
    else
        current_state <= next_state;
 
// State
    reg sample_finish;
    always @(current_state or sample_finish or rx_neg)
    begin
        next_state = 2'bx;
        case(current_state)
            IDLE :
                begin
                    if (rx_neg) next_state = SAMP;
                    else        next_state = IDLE;
                end
            SAMP : 
                begin
                    if (sample_finish) next_state = IDLE;
                    else               next_state = SAMP;
                end
            default : next_state = IDLE;
        endcase
    end

    reg [3:0] recv_cnt;
    reg sample_en;
    reg [RECV_BIT - 1 : 0] data_temp;

    always @ (posedge clk or negedge rst_n)
    if (!rst_n)
        begin
            data_out  <= 10'bx;
            data_temp <= 10'bx;
            sample_finish <= 1'b0;
            sample_en <= 1'b0;
            recv_cnt <= 4'b0;
        end
    else
        begin
            case (next_state)
                IDLE: 
                    begin
                        //data_out  <= 10'bx;
                        data_temp <= 10'bx;
                        sample_finish <= 1'b0;
                        sample_en <= 1'b0;
                        recv_cnt <= 4'b0;
                    end
                SAMP: 
                    begin
                        if (recv_cnt == RECV_BIT) 
                        begin
                            data_out  <= data_temp;
                            data_temp <= 10'bx;
                            sample_finish <= 1'b1;
                            sample_en <= 1'b0;
                            recv_cnt  <= 4'b0;
                        end

                        else 
                        begin
                            sample_en <= 1'b1;
                            
                            if (clk) 
                                begin
                                    data_out <= data_out;
                                    data_temp[recv_cnt] <= rx;
                                    sample_finish <= 1'b0;
                                    recv_cnt <= recv_cnt + 1'b1;
                                end
                            else 
                                begin
                                    data_out <= data_out;
                                    data_temp <= data_temp;
                                    sample_finish <= sample_finish;
                                    recv_cnt <= recv_cnt;
                                end
                        end
                    end
                default:
                    begin
                        data_out        <= 10'bx;
                        sample_finish   <= 1'b0;
                        sample_en       <= 1'b0;
                    end
            endcase
        end


// Sample Counter Signal Generator
    parameter BAUD_MAX   = 50;
    reg [5:0] baud_cnt;

    always @ (posedge clk or negedge rst_n)
    if (!rst_n) 
    begin
        baud_cnt <= 6'd0;
    end

    else 
    begin
        if (sample_en) 
            begin
                if (baud_cnt == BAUD_MAX - 1) baud_cnt <= 6'd0;
                else baud_cnt <= baud_cnt + 1'b1;
            end
        else baud_cnt <= 6'd0;
    end



// Sample Clock Signal Generator
    parameter BAUD_CNT_H = (BAUD_MAX / 2);
    wire baud_clk = (baud_cnt == BAUD_CNT_H) ? (1'b1) : (1'b0);


endmodule
```
### 4. 再撰寫 UART 中 RX 模組的 Testbench (uart_tb.v)
```
`timescale 1ns / 1ps
 
 
// Company: 
// Engineer:
//
// Create Date:   14:03:06 12/05/2019
// Design Name:   uart_rx
// Module Name:   D:/Xlinx_ISE_Projects/testbench/uart_rx_tb.v
// Project Name:  test
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: uart_rx
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
module uart_tb;

    // Inputs
    reg CLK;
    reg RST_N;
    reg RX;
 
    // Outputs
    wire [9:0] DATA_OUT;

    integer i;

    initial
    begin
        $dumpfile("tt.vcd");
        $dumpvars(0,uart_tb);
        $dumpvars;
        //$fsdbDumpfile("test.fsdb");
        //$fsdbDumpvars;
    end

    initial
    begin
        for(i=0 ; i<=700000 ; i=i+1)
        begin
            i = i+1;
            $display("At time %t, RST_N=%b | RX=%b | data_i=%b", $realtime/1000, RST_N, RX, DATA_OUT);
            #200;
        end
    end
    
    always #1 CLK = ~CLK;

    initial
    begin
        // Initialize Inputs
        CLK = 0;
        RST_N = 0;
        RX = 1;

        // Wait 100 ns for global reset to finish
        #100;

        // Add stimulus here
        RST_N = 1;

        #100;
        // Generate Start bit
        #200 RX = 1'b0;
        // 8 data bits
        #200 RX = 1'b1;
        #200 RX = 1'b0;
        #200 RX = 1'b1;
        #200 RX = 1'b0;
        #200 RX = 1'b0;
        #200 RX = 1'b0;
        #200 RX = 1'b0;
        #200 RX = 1'b0;
        // Generate Stop bit
        #200 RX = 1'b1;

        #600;
        // Generate Start bit
        #200 RX = 1'b0;
        // 8 data bits
        #200 RX = 1'b1;
        #200 RX = 1'b1;
        #200 RX = 1'b1;
        #200 RX = 1'b0;
        #200 RX = 1'b0;
        #200 RX = 1'b1;
        #200 RX = 1'b1;
        #200 RX = 1'b1;
        // Generate Stop bit
        #200 RX = 1'b1;
        #20000 $finish;
	end
    

    // Instantiate the Unit Under Test (UUT)
    uart_rx U_uart_rx
    (
        .clk(CLK),
        .rst_n(RST_N),
        .rx(RX),
        .data_out(DATA_OUT)
    );

endmodule
```

※模擬結果圖
![datawatch](https://hackmd.io/_uploads/B1bXi3SU6.png)
![datawatch2](https://hackmd.io/_uploads/BkFXjhSI6.png)
> 由此可見在 testbench 中產生了兩組 data_out 的值，LSB 的 0 代表通知 RX 為 start bit，而 MSB 的 1 代表通知 RX 為 end bit。

>中間夾住的 8bits 則為需要傳送的訊號內容，由右至左判讀。


