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

这是对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;
end
always@(posedge clk)

end
always@(posedge clk)
begin:read
if(rd)
rom_data=memory[rom_addr];
end
endmodule    
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;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值