modelsim中用非阻塞赋值仿真遇到的问题

来源:互联网 发布:淘宝商品链接怎么复制 编辑:程序博客网 时间:2024/04/30 00:58

这是对rom初始化并读取的源码

module rom_nxm(rom_data,rom_addr,clk,rd,load);    parameter M=8,N=4;    input clk,rd;    input load;    input [N-1:0] rom_addr;    output reg [M-1:0] rom_data;    reg[M-1:0]memory[0:2**N-1];    always@(posedge load)    begin:init    integer i;    for(i=0;i<(2**N);i=i+1)    memory[i]=i+1;endalways@(posedge clk)endalways@(posedge clk)begin:readif(rd)rom_data=memory[rom_addr];endendmodule    
testbench为
`timescale 1ns/100ps module rom_nxm_tb  ; parameter M  = 8 ;parameter N  = 4 ;   reg    load   ;
  reg  [N-1:0]  rom_addr   ;   reg    rd   ;   reg    clk   ;   wire  [M-1:0]  rom_data   ;   rom_nxm    #( M , N  )   DUT  (        .load (load ) ,      .rom_addr (rom_addr ) ,      .rd (rd ) ,      .clk (clk ) ,      .rom_data (rom_data ) );       initial      begin      clk=0;      load=0;      rd=0;  end  initial  begin   #10 load=1;  #10 rd=1;  rom_addr=0;    end  always #10 clk=~clk;   always@(posedge clk)  begin      $display("addr:%d,data:%d",rom_addr,rom_data);  if(rom_addr==15)   rom_addr=0;//rom_addr<=0  else  rom_addr= rom_addr+1;//rom_addr<= rom_addr+1     end  initial  #35 $strobe($time,"addr:%d,data:%d",rom_addr,rom_data);  endmodule

阻塞赋值的仿真结果:

addr: x,data:  x

# addr: 0,data:  x

#                   35addr: 1,data:  2

# addr: 1,data:  2

# addr: 2,data:  3

# addr: 3,data:  4

非阻塞赋值的结果:

 

addr: x,data:  x

# addr: 0,data:  x

#                   35addr: 1,data:  1

# addr: 1,data:  1

# addr: 2,data:  2

# addr: 3,data:  3

 

modelsim的testbench中对always@(posedge)模块的阻塞赋值是在posedge clk之前delta时间进行赋值,而非阻塞赋值是在posedge clk之后delta时间进行赋值,且一般寄存器的采样在时钟前delta时间,而赋值在时钟后delta时间

若为阻塞赋值,在第二个上升沿的时侯,addr在posedge clk前的delta时间进行赋值变为0001,然后memory采样的是posedge clk之前delta时间的值即0001(虽然显示为0000,),则addr显示为0001的时候,memory显示的是memory【0001】。这时addr与memory对应。

但若用非阻塞赋值的话,在第二个上升沿的时侯,addr的显示与阻塞赋值是一样的,但差别是非阻塞赋值是在posedge clk之后delta时间进行赋值,则memory采样仍是在clk之前,就变成memory【0000】。这时,从图上看,仿佛addr与memory不对应。

但是在testbench中将阻塞赋值用非阻塞赋值替代是有好处的,尤其是你的verilig源文件中有非阻塞赋值(存在寄存器或触发器)的情况,这样才能在时序图中体现非阻塞赋值的功能(因非阻塞的本质是读取触发前的状态,而testbench中的非阻塞赋值起到了延时的作用,不要死板的认为是在下一个时钟触发时才赋值),但你要将testbench中的非阻塞赋值当做阻塞赋值对待,深刻理解modelsim是仿真,可参考:

http://xilinx.eetop.cn/viewthread-282059

有高手说:

写tb时注意信号的生成不要在pos clk的同时用阻塞赋值(当你的模块是pos clk时)。这就是多事件同时发生:如果都是非阻塞赋值就不存在问题。但阻塞赋值时,不同仿真器的处理顺序不一样,会导致结果差异。可用3种方式:1:neg clk 和阻塞赋值;2:pos clk和非阻塞赋值;3:pos clk +单位延时 + 阻塞赋值。

 若用testbench中用阻塞赋值,

加载测试向量时,避免在时钟的上下沿变化

为了模拟真实器件的行为,加载测试向量时,避免在时钟的上下沿变化,而是在时钟的上升沿延时一个时间单位后,加载的测试向量发生变化。如:

assign #5 c="a"^b

……

@(posedge clk) #(0.1*`cycle) A=1;

 

原创粉丝点击