⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 top_tb.v

📁 全面模仿AVR的UART功能
💻 V
📖 第 1 页 / 共 2 页
字号:

    ebiReadDat(UCSRA, rRsl);
    $display("UCSRA = 0x%H", rRsl);
    ebiReadDat(UCSRB, rRsl);
    $display("UCSRB = 0x%H", rRsl);
    ebiReadDat(UCSRC, rRsl);
    $display("UCSRC = 0x%H", rRsl);
    ebiReadDat(UDR, rRsl);
    if (rRsl == rTstDat) begin
        $display("receive data ok!, UDR = 0x%H", rRsl, $time);
    end else begin
        $display("faile to receive data!", $time);
    end
    $display("==============");
    $stop;



    /*  发送0x51, 7bits, 1 stopbit, odd parity   */
    rTstDat = 8'h51;
    rTstCharSize = CSZ_7BITS;
    rTstStopBit = SBS_1BIT;
    rTstParity  = ODD_PARITY;
    $display("Frame format is: CharSize=[%d], StopBit=[%d], ParityMode=[%d]", rTstCharSize, rTstStopBit, rTstParity);

    ebiWriteDat(UCSRC,
        (1 << UPM1) |
        (1 << UPM0) |
        (1 << UCSZ1) |
        (0 << UCSZ0)
    );
    rTstDat = rTstDat &  ((1<<rTstCharSize) - 1);
    $display("start send data: 0x%H", rTstDat, $time);
    txdGenerate(8'h51, rTstCharSize, rTstParity, rTstStopBit);
    if (uart_int) begin
        @(negedge uart_int);                                       //  wait for rxd completed
        $display("Error: failed to receive one frame!");
    end else begin
        $display("Info: success to receive one frame!");
    end

    ebiReadDat(UCSRA, rRsl);
    $display("UCSRA = 0x%H", rRsl);
    ebiReadDat(UCSRB, rRsl);
    $display("UCSRB = 0x%H", rRsl);
    ebiReadDat(UCSRC, rRsl);
    $display("UCSRC = 0x%H", rRsl);
    ebiReadDat(UDR, rRsl);
    if (rRsl == rTstDat) begin
        $display("receive data ok!, UDR = 0x%H", rRsl, $time);
    end else begin
        $display("faile to receive data!", $time);
    end
    $display("==============");
    $stop;



    /*  发送0x51, 8bits, 1 stopbit, no parity   */
    rTstDat = 8'h51;
    rTstCharSize = CSZ_8BITS;
    rTstStopBit = SBS_1BIT;
    rTstParity  = NO_PARITY;
    $display("Frame format is: CharSize=[%d], StopBit=[%d], ParityMode=[%d]", rTstCharSize, rTstStopBit, rTstParity);
    ebiWriteDat(UCSRC,
        (0 << UPM1) |
        (0 << UPM0) |
        (1 << UCSZ1) |
        (1 << UCSZ0)
    );
    rTstDat = rTstDat &  ((1<<rTstCharSize) - 1);
    $display("start send data: 0x%H", rTstDat, $time);
    txdGenerate(8'h51, rTstCharSize, rTstParity, rTstStopBit);
    if (uart_int) begin
        @(negedge uart_int);                                       //  wait for rxd completed
        $display("Error: failed to receive one frame!");
    end else begin
        $display("Info: success to receive one frame!");
    end

    ebiReadDat(UCSRA, rRsl);
    $display("UCSRA = 0x%H", rRsl);
    ebiReadDat(UCSRB, rRsl);
    $display("UCSRB = 0x%H", rRsl);
    ebiReadDat(UCSRC, rRsl);
    $display("UCSRC = 0x%H", rRsl);
    ebiReadDat(UDR, rRsl);
    if (rRsl == rTstDat) begin
        $display("receive data ok!, UDR = 0x%H", rRsl, $time);
    end else begin
        $display("faile to receive data!", $time);
    end
    $display("==============");
    $stop;

    

    /*  发送0x51, 8bits, 1 stopbit, even parity   */
    rTstDat = 8'h51;
    rTstCharSize = CSZ_8BITS;
    rTstStopBit = SBS_1BIT;
    rTstParity  = EVEN_PARITY;
    $display("Frame format is: CharSize=[%d], StopBit=[%d], ParityMode=[%d]", rTstCharSize, rTstStopBit, rTstParity);

    ebiWriteDat(UCSRC,
        (1 << UPM1) |
        (0 << UPM0) |
        (1 << UCSZ1) |
        (1 << UCSZ0)
    );
    rTstDat = rTstDat &  ((1<<rTstCharSize) - 1);
    $display("start send data: 0x%H", rTstDat, $time);
    txdGenerate(8'h51, rTstCharSize, rTstParity, rTstStopBit);
    if (uart_int) begin
        @(negedge uart_int);                                       //  wait for rxd completed
        $display("Error: failed to receive one frame!");
    end else begin
        $display("Info: success to receive one frame!");
    end

    ebiReadDat(UCSRA, rRsl);
    $display("UCSRA = 0x%H", rRsl);
    ebiReadDat(UCSRB, rRsl);
    $display("UCSRB = 0x%H", rRsl);
    ebiReadDat(UCSRC, rRsl);
    $display("UCSRC = 0x%H", rRsl);
    ebiReadDat(UDR, rRsl);
    if (rRsl == rTstDat) begin
        $display("receive data ok!, UDR = 0x%H", rRsl, $time);
    end else begin
        $display("faile to receive data!", $time);
    end
    $display("==============");
    $stop;



    /*  发送0x51, 8bits, 1 stopbit, odd parity   */
    rTstDat = 8'h51;
    rTstCharSize = CSZ_8BITS;
    rTstStopBit = SBS_1BIT;
    rTstParity  = ODD_PARITY;
    $display("Frame format is: CharSize=[%d], StopBit=[%d], ParityMode=[%d]", rTstCharSize, rTstStopBit, rTstParity);

    ebiWriteDat(UCSRC,
        (1 << UPM1) |
        (1 << UPM0) |
        (1 << UCSZ1) |
        (1 << UCSZ0)
    );
    rTstDat = rTstDat &  ((1<<rTstCharSize) - 1);
    $display("start send data: 0x%H", rTstDat, $time);
    txdGenerate(8'h51, rTstCharSize, rTstParity, rTstStopBit);
    if (uart_int) begin
        @(negedge uart_int);                                       //  wait for rxd completed
        $display("Error: failed to receive one frame!");
    end else begin
        $display("Info: success to receive one frame!");
    end

    ebiReadDat(UCSRA, rRsl);
    $display("UCSRA = 0x%H", rRsl);
    ebiReadDat(UCSRB, rRsl);
    $display("UCSRB = 0x%H", rRsl);
    ebiReadDat(UCSRC, rRsl);
    $display("UCSRC = 0x%H", rRsl);
    ebiReadDat(UDR, rRsl);
    if (rRsl == rTstDat) begin
        $display("receive data ok!, UDR = 0x%H", rRsl, $time);
    end else begin
        $display("faile to receive data!", $time);
    end
    $display("==============");
    $stop;
    

    #1000;
    $display("******************** End Of Test **********************");
    $stop;
    $finish;
end

assign  wAD = (rd_n)? rAD : 8'hzz;
top U_uart_tb(
    .clk            (clk),
    .rst_n          (rst_n),

    .ad             (wAD), 
    .addr           (addr), 
    .wr_n           (wr_n), 
    .rd_n           (rd_n), 
    .ale            (ale),
    
    .txd            (txd),
    .rxd            (rxd),
    
    .int_o          (uart_int),

    .uart_clk       (uart_clk)
);


/*
 *  产生系统时钟
 */
always #(CLK / 2) clk <= ~clk;



/*
 *  初始化UART的寄存器
 */
task uartInit;
reg     [7:0]       rTmp;
begin
    ebiReadDat(UVER, rTmp);
    if (rTmp != 100) begin
        $display("the version not equel to 100 but is %d", rTmp);
        $stop;
    end 
    else begin
        $display("the fpga uart verision is %d", rTmp);
    end

    ebiWriteDat(UBRRL, 8'h05);
    ebiWriteDat(UBRRH, 8'h00);
    ebiWriteDat(UCSRC, 
        (8'h01 << UCSZ1) |                                      //  帧数据位为8位
        (8'h01 << UCSZ0) |
        (8'h01 << UPM1)
    );        
    ebiWriteDat(UCSRB, 
        (8'h01 << RXCIE) |
        (8'h01 << RXEN) | 
        (8'h01 << TXEN)
    );          
    
end
endtask


/*
 *  以查询的方式(Poll Style)检查UART总线上是否接收到数据,
 */
task uartGetChar;
reg     [7:0]       rTmp;

begin

    rTmp    = 8'h0;
    while ( (rTmp & (1<<RXC)) == 0 ) begin                      //  等待接收器接收到数据
        #100;
        ebiReadDat(UCSRA, rTmp);
    end

    $display("\n==========Get One Char===========");
    ebiReadDat(UCSRA, rTmp);
    $write("UCSRA = 0x%H", rTmp);
    if (rTmp & (1<<FE)) 
        $write("detect frame error!");
    if (rTmp & (1<<DOR)) 
        $write("detect OverRun Error!");
    if (rTmp & (1<<UPE))
        $write("detect Parity Check Error!");
    $write("\n");
    ebiReadDat(UCSRB, rTmp);
    $display("UCSRB = 0x%H", rTmp);
    ebiReadDat(UCSRC, rTmp);
    $display("UCSRC = 0x%H", rTmp);
    ebiReadDat(UDR, rTmp);
    $display("UDR   = 0x%H", rTmp);
    $display("has get one char: 0x%H at %dns", rTmp, $realtime);
    ebiWriteDat(UCSRA, 1<<TXC);
    $display("clear xmint done flag!");
    ebiReadDat(UCSRA, rTmp);
    $display("UCSRA = 0x%H", rTmp);
    $display("============End Of Get Char===========");
end
endtask


/*
 *  根据设定的地址, 读取EBI的数据, 模拟C51外部总线的时序, 低8位的地址和数据线
 *  复用, 使用ALE外Address Lock Enable
 */
task ebiReadDat;
input   [15:0]  a;
output  [7:0]   return;

reg     [7:0]   return;
begin
    @(negedge clk)
    ale     = 1'b1;
    @(posedge clk)
    rAD     = a[7:0];
    addr    = a[15:8];
    @(negedge clk)
    ale     = 1'b0;
    @(posedge clk)
    rd_n    = #1 1'b0;

    @(posedge clk)
    return  = wAD;
    rd_n    = #1 1'b1;
end
endtask


/*
 *  往EBI(Extenl Bus Interface)写数据, 模拟C51的外部总线的时序, 输入为地址和数
 *  据
 */
task ebiWriteDat;
input   [15:0]      addr_i;
input   [7:0]       data_i;

begin
    @(negedge clk)
    ale     = 1'b1;
    
    @(posedge clk)
    rAD     = addr_i[7:0];
    addr    = addr_i[15:8];
    
    @(negedge clk)
    ale     = 1'b0;

    @(posedge clk)
    rAD     = data_i;
    wr_n    = #1 1'b0;

    @(posedge clk)
    wr_n    = #1 1'b1;

end
endtask


/*
 *  产生TXD的信号, 根据设定的UART帧格式, 产生个UART的发送器序列
 */
initial rBaudRate = 0;
task txdGenerate;
input   [7:0]       data_i;
input   [3:0]       char_size_i;
input   [1:0]       parity;
input               stop_bit;

integer             i;
reg                 rParVal;

begin
    ebiWriteDat(UDR, data_i);                                   //  利用UART的发送器产生, 作比较

    rParVal = 1'b0;
    /*  发生起始位      */
    @(posedge clk)
    rxd     = 1'b0;
    rBaudRate = ~rBaudRate;
    dlyBaud;

    /*  移位产生数据位  */
    for (i=0; i<char_size_i; i = i+1) begin
        rxd     = data_i[i];
        rParVal = rParVal ^ rxd;
        rBaudRate = ~rBaudRate;
        dlyBaud;
    end

    /*  产生奇偶校验位  */
    if (parity == 2'h2) begin
        rxd     = rParVal;
        rBaudRate = ~rBaudRate;
        dlyBaud;
    end
    else if (parity == 2'h3) begin
        rxd     = ~rParVal;
        rBaudRate = ~rBaudRate;
        dlyBaud;
    end

    rxd     = 1'b1;
    rBaudRate = ~rBaudRate;
    dlyBaud;

    if (stop_bit) begin
        rxd = 1'b1;
        rBaudRate = ~rBaudRate;
        dlyBaud;
    end

    rBaudRate = ~rBaudRate;
end
endtask

/*
 *  延时1个波特的时间, 用于产生模拟的UART总线
 */
task dlyBaud;
    #(16 * DIVIDER_FACTOR * CLK);
endtask

endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -