llxofaet

仿真时testbench风格导致的竞争现象

0
阅读(2335)

     近期需要用到一段移位寄存器的程序,却在行为仿真时出现问题,代码如下(一个4位移位寄存器):

module sr4(
	input clk ,
	input en ,
	input d ,
	output reg q 
    );
	 
	reg [3:0] q_temp ;
	always @(posedge clk)begin
		if(en)begin
			q_temp[3:0] <= {q_temp[2:0],d} ;
			q <= 0 ;
		end
		else begin
			q_temp <= q_temp ;
			q <= q_temp[3] ;
		end
	end
endmodule

用两种不同的风格写测试文件时,仿真结果却不相同。

testbench(1)的仿真代码:

module sr4_tb;
	reg clk;
	reg en;
	reg d;
	wire q;

	sr4 uut (
		.clk(clk), 
		.en(en), 
		.d(d), 
		.q(q)
	);
	initial begin
		clk = 0 ;
		forever #5 clk = ~clk ;
	end
//在四个时钟周期内,en=1,d一次输入1000
	initial begin
		en = 0 ;
		@(posedge clk)
		#10 en = 1 ;
		   d = 1 ;
		#10 d = 0 ;
		#30 en = 0 ;
	end
endmodule
仿真波形如图:


testbench(1)的仿真波形
      仔细观察发现,使能 en 和输入数据 d 在 15ns 处有效,而移位寄存器第一位立即装载进数据。这不符合逻辑啊,应该延迟一个时钟周期才对啊! 

    于是换了一种代码风格,testbench(2)代码风格如下:

module sr4_tb;
	reg clk;
	reg en;
	reg d;
	wire q;

	sr4 uut (
		.clk(clk), 
		.en(en), 
		.d(d), 
		.q(q)
	);
	initial begin
		clk = 0 ;
		forever #5 clk = ~clk ;
	end
	reg [5:0] en_tb ;
	reg [5:0] d_tb ;
	initial begin
		en_tb = 6'b011110 ;
		d_tb = 6'b010000 ;
   end
//同样四个周期内产生en=1,d一次输入1000	
	always @(posedge clk)begin
		en <= en_tb[5] ;
		d <= d_tb[5] ;
		en_tb[5:0] <= {en_tb[4:0] , 1'b0} ;
		d_tb[5:0] <= {d_tb[4:0] , 1'b0} ;
   end
endmodule
     仿真波形如图:

testbench(2)波形

      按照逻辑来说,移位寄存器的第一次移位进入会在串行输入信号 d 的下一个时钟周期开始。因此testbench(2)的波形才是正确的,那么testbench(1)的错误在哪儿?

       出现了竞争!

       仔细观察,testbench(1)中在 15ns 时,将 clk 和 en , d 的信号值同时改变,而接下来的逻辑中需要在 clk 的上升沿检测 en 和 d 的值,因此出现竞争。

      而在testbench(2)中,en 和 d 的信号变化是由时钟沿来确定的。因此不会有竞争出现。

       那么出现竞争的时候,仿真器的处理逻辑是什么样的呢??

       实际测试结果,ISE 和 Modelsim 的处理逻辑是默认 en 和 d 改变在先,时钟跳变在后,因此 clk 的上升沿采集的是变化之后的 en 和 d ,因此没有延迟一个时钟周期。

    而实际中是什么样子呢??

module test4(
	input clk ,
	input a ,
	output reg b
    );
	always@(posedge clk)begin
		   b <= a ;
	end
endmodule
     实际的信号变化应该为这个样子:

      当输入信号 a 的改变是在 clk 的上升沿触发时,表现为在当 clk 的上升沿检测时,检测到的是 a 改变前的值(因为触发器都有延时,a 在 clk 的上升沿一段延时之后才会改变), b  输出的是改变前  a 的值,在下一个上升沿输出改变后的值,这个时候才会表现为延时一个周期的现象。

        仿真如下:

       因此在设计和测试时,应该避免人为造成的竞争出现。

       测试可用一个简单的状态机实现(或者将输入信号的改变放在always@(posedge clk)块中),本质就是将信号的改变归一到时钟沿之下,这样的仿真才符合实际。