编了一个串口接收的小程序,死活不工作。万般无奈之下,求助仿真。不学不知道,一学发现,原来很好学。尤其是前仿真,简单好用。把那个不听话的小程序在仿真里一遛,不禁暗暗叫好。先看源程序
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
`timescale 1ns / 1ps
module rxd(clk,rx,rx_reg);
input clk;
input rx;
output reg[7:0]rx_reg; //显示收到的数据
reg clk_bps,rx_1,rx_2,flag_rx;
reg [3:0]num_rx = 4'b0;
reg [12:0]cnt = 13'b0;
//parameter reference="13"'b1000_0010_0011; //2083*9600=<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />20M
parameter reference="13"'b0000_0000_0001; //testbench
always @ (posedge clk)
if(cnt == reference) cnt <= 13'b0;
else cnt <= cnt+13'b1;
//晶振跑得快,波特率时钟跑得慢,咱不必亦步亦趋,可以跑会歇会
always @ (posedge clk)
if(cnt == reference) clk_bps <= 1'b1;
else clk_bps <= 1'b0;
//该跑就跑,不跑咱就歇着
always @ (posedge clk )
begin rx_1 <= rx;
rx_2 <= rx_1;
end
always @ (posedge clk )
if (rx_1 == 0 && rx_2 == 1)
flag_rx <= 1;
//该喂孩子了
always @ (posedge clk_bps)
if (flag_rx == 1)
begin
case (num_rx)
4'd0: rx_reg[0] <= rx;
4'd1: rx_reg[1] <= rx;
4'd2: rx_reg[2] <= rx;
4'd3: rx_reg[3] <= rx;
4'd4: rx_reg[4] <= rx;
4'd5: rx_reg[5] <= rx;
4'd6: rx_reg[6] <= rx;
4'd7: rx_reg[7] <= rx; //每个都得喂
endcase
if(num_rx < 7)
num_rx <= num_rx+4'b1; //为了防止偏心,特设移位机制
end
endmodule
仿真结果如下:
咱给的是01H,可数据明显不对。点开各位,发现把起始位也弄到数据里去了。赋值应该慢一拍。最后一个always语句应该改为:
always @ (posedge clk_bps)
if (flag_rx == 1)
begin
case (num_rx)
4'd1: rx_reg[0] <= rx;
4'd2: rx_reg[1] <= rx;
4'd3: rx_reg[2] <= rx;
4'd4: rx_reg[3] <= rx;
4'd5: rx_reg[4] <= rx;
4'd6: rx_reg[5] <= rx;
4'd7: rx_reg[6] <= rx;
4'd8: rx_reg[7] <= rx;
endcase
if(num_rx < 8)
num_rx <= num_rx+4'b1;
end
这下仿真结果变成这样了——
可以看出其它各位都对,只有最高位不对,而且变化2次。再看看源程序,发现num_rx到8就不再累加,导致最高位先正确赋值,然后又被停止位赋了一次。把上面的always语句中的if语句改成
if(num_rx < 9)
num_rx <= num_rx+4'b1;
再仿真
一切正常。前仿真操作简单,但借助它可以看到程序运行的细节,因此仍不失为一件利器。也正因为简单,大家就更要早点学会它。
另外,观察仿真波形可以看出,verilog中变量如果不初始化,其值为x。
用户1584993 2010-6-3 15:04
用户1122702 2010-6-3 09:29