3.4 UART串口仿真实例
下面将对串口的RTL设计进行仿真测试。在前面的例子中,可以看出仿真的行为主要在testbench文件中定义。下面我们将为串口收发模块rxtx.v写一个testbench文件。如下所示:
- `timescale 1 ns/1 ns
- module tb;
- reg clk = 1'b0;
- always clk = #20 ~clk;
- reg rst = 1'b1;
- initial #40 rst = 1'b0;
- reg RxD = 1'b1;
- reg tx_vld = 1'b0;
- reg [7:0] tx_data = 8'h0;
- wire rx_vld ;
- wire [7:0] rx_data ;
- wire TxD;
- wire txrdy;
- rxtx u_rxtx (
- .clk ( clk ),
- .rst ( rst ),
- .rx ( RxD ),
- .tx_vld ( tx_vld ),
- .tx_data ( tx_data ),
- .rx_vld ( rx_vld ),
- .rx_data ( rx_data ),
- .tx ( TxD ),
- .txrdy ( txrdy )
- );
在这里,我们采用同样的方式例化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秒)。
- task rx_send;
- input [7:0] b;
- integer i;
- begin
- RxD = 1'b0;
- for (i=0;i<8;ii=i+1)
- #104167 RxD = b[i];
- #104167 RxD = ^b;
- #104167 RxD = 1'b1;
- #104167 RxD = 1'b1;
- end
- endtask
在这里,外面定义的reg类型RxD可以通过task内部直接调用,于是我们通过这个rx_send的task,可以把一个字节通过RxD串行发送出去。
另外一个task是采用同样的方式给tx_vld和tx_data赋值。触发rxtx模块发送数据。在最开始,它必须等待txrdy为高电平。然后为tx_vld赋值一个周期的高电平。
- task tx_byte;
- input [7:0] b;
- begin
- while (~txrdy)
- @(posedge clk);
- @(posedge clk);
- #3 tx_vld = 1'b1;
- tx_data = b;
- @(posedge clk);
- #3 tx_vld = 1'b0;
- tx_data = 8'b0;
- end
- endtask
前面这两个task是用来给rxtx产生激励的。那么还需要对rxtx的输出进行检测。对于rx_vld和rx_data的检测如下:
- always @ (posedge clk )
- if (rx_vld)
- $display("--A byte: %2h received...",rx_data);
- else;
我们希望一旦rx_vld为高电平,即把接收的字节数据打印出来。接下来,检测TxD,确认它是否发送的是tx_data。我们通过TxD的下降沿触发检测流程。一旦探测到TxD的下降沿,即延时到半个周期,检测起始0 bit是否有效。然后,对TxD传送的数据和奇偶校验位进行保存。在检测完结束1 bit后,对检测结果进行打印。
- integer i;
- reg [7:0] rec_byte;
- reg oddeven;
- always @ (negedge TxD) begin
- #52080 if (TxD!=1'b0) $display("--Start bit error.");
- for (i=0;i<8;ii=i+1)
- #104167 rec_byte[i] = TxD;
- #104167 oddeven = TxD;
- #104167 if (TxD!=1'b1) $display("--End bit error.");
- #52080 $display("--A byte : %2h transmitted...",rec_byte);
- if (oddeven!=^rec_byte) $display("--Odd even error.");
- end
好了,如果我们再加上调用这两个task的initial语句,则会显示出检测结果。
- initial begin
- #100 tb.rx_send(8'h5a);
- tb.tx_byte(8'ha5);
- #2000000 $stop;
- end
- 在Transcript窗口中,显示检测结果如下:
- # --A byte: 5a received...
- # --A byte: a5 transmitted...
回书目 上一节 下一节 |
联系客服