打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
3.4 UART串口仿真实例

3.4   UART串口仿真实例

下面将对串口的RTL设计进行仿真测试。在前面的例子中,可以看出仿真的行为主要在testbench文件中定义。下面我们将为串口收发模块rxtx.v写一个testbench文件。如下所示:

  1. `timescale 1 ns/1 ns  
  2. module tb;  
  3.  
  4. reg clk = 1'b0;  
  5. always clk = #20 ~clk;  
  6.  
  7. reg rst = 1'b1;  
  8. initial #40 rst = 1'b0;  
  9.  
  10. reg RxD = 1'b1;  
  11. reg tx_vld = 1'b0;  
  12. reg [7:0] tx_data = 8'h0;  
  13.  
  14. wire  rx_vld ;  
  15. wire [7:0] rx_data ;  
  16. wire TxD;  
  17. wire txrdy;  
  18.  
  19.  rxtx u_rxtx (  
  20.                       .clk         (         clk             ),  
  21.                       .rst         (         rst             ),  
  22.                       .rx          (         RxD             ),  
  23.                       .tx_vld      (         tx_vld          ),  
  24.                       .tx_data     (         tx_data         ),  
  25.               
  26.                       .rx_vld      (         rx_vld          ),  
  27.                       .rx_data     (         rx_data         ),  
  28.                       .tx          (         TxD             ),  
  29.                       .txrdy       (         txrdy           )  
  30.                       ); 

在这里,我们采用同样的方式例化rxtx。将rxtx的3个输入信号RxD、tx_vld、tx_data定义为reg类型,并赋给初值。而对输出rx_vld、rx_data、TxD、txrdy采用wire类型,表示把输出信号引出来,共testbench使用。

接下来,定义一个task以传送串行数据给RxD。task是在Verilog描述testbench经常用到的一种手段。它和function不同,它不需要返回数据。通过定义一个输入input [7:0] b; 可以让调用这个task时,赋给一个变量到b。然后RxD在发送串行数据时,采用b作为发送字节。这个task按照串口的格式把字节b送给RxD。它的周期是:104 167 ns(1/9600秒)。

  1. task rx_send;  
  2. input [7:0] b;  
  3. integer i;  
  4. begin  
  5.     RxD = 1'b0;  
  6.      for (i=0;i<8;ii=i+1)  
  7.         #104167 RxD = b[i];  
  8.      #104167 RxD = ^b;  
  9.     #104167 RxD = 1'b1;  
  10.     #104167 RxD = 1'b1;   
  11. end  
  12. endtask 

在这里,外面定义的reg类型RxD可以通过task内部直接调用,于是我们通过这个rx_send的task,可以把一个字节通过RxD串行发送出去。

另外一个task是采用同样的方式给tx_vld和tx_data赋值。触发rxtx模块发送数据。在最开始,它必须等待txrdy为高电平。然后为tx_vld赋值一个周期的高电平。

  1. task tx_byte;  
  2. input [7:0] b;  
  3. begin  
  4.     while (~txrdy)  
  5.         @(posedge clk);  
  6.      @(posedge clk);  
  7.      #3 tx_vld = 1'b1;  
  8.         tx_data = b;  
  9.      @(posedge clk);  
  10.      #3 tx_vld = 1'b0;  
  11.         tx_data = 8'b0;  
  12. end  
  13. endtask  

前面这两个task是用来给rxtx产生激励的。那么还需要对rxtx的输出进行检测。对于rx_vld和rx_data的检测如下:

  1. always @ (posedge clk )  
  2. if (rx_vld)  
  3.     $display("--A byte: %2h received...",rx_data);  
  4. else; 

我们希望一旦rx_vld为高电平,即把接收的字节数据打印出来。接下来,检测TxD,确认它是否发送的是tx_data。我们通过TxD的下降沿触发检测流程。一旦探测到TxD的下降沿,即延时到半个周期,检测起始0 bit是否有效。然后,对TxD传送的数据和奇偶校验位进行保存。在检测完结束1 bit后,对检测结果进行打印。

  1. integer i;  
  2. reg [7:0] rec_byte;  
  3. reg  oddeven;  
  4. always @ (negedge TxD) begin  
  5.     #52080 if (TxD!=1'b0) $display("--Start bit error.");  
  6.     for (i=0;i<8;ii=i+1)  
  7.         #104167 rec_byte[i] = TxD;  
  8.     #104167 oddeven = TxD;  
  9.     #104167 if (TxD!=1'b1) $display("--End bit error.");      
  10.     #52080 $display("--A byte : %2h transmitted...",rec_byte);  
  11.             if (oddeven!=^rec_byte) $display("--Odd even error.");  
  12. end 

好了,如果我们再加上调用这两个task的initial语句,则会显示出检测结果。

  1. initial begin  
  2. #100 tb.rx_send(8'h5a);  
  3.      tb.tx_byte(8'ha5);  
  4. #2000000 $stop;  
  5. end   
  6. 在Transcript窗口中,显示检测结果如下:  
  7. # --A byte: 5a received...  
  8. # --A byte: a5 transmitted... 

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
FPGA串口实现(带FIFO)
【接口时序】3、UART串口收发的原理与Verilog实现
基于verilog 的很基础的RS232串口收发代码
自协商SGMII_SerDers篇
MII接口全家福
UART串口收发控制器设计详解
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服