首先引入一个例子:
`timescale 1ns/100ps
module TB; module INV_DFF(Clock, Reset_n, DataIn, DataOut);
reg Ck, Rst_n, Din; input Clock;
wire Dout; input Reset_n;
//Clock generation input DataIn;
initial begin output reg Data_Out
Ck = 0; wire DataInv;
forever #10 Ck = ~Ck; always @(posedge Clock or negedge Reset_n)
end begin if(~Reset_n)
//Reset generation Data_Out <= 1‘b0;
initial begin else Data_Out <= Data_Inv;
Rst_n = 1; end
#5 Rst_n = 0; assign #3 DataInv = ~ DataIn;
#55 Rst = 1; endmodule
end
//Data input generation
initial begin
Din = 0;
#80 Din = 1;
#40 Din = 0;
end
INV_DFF u_INV_DFF( //DUV
.Clock(Ck),
.Reset_n(Rst_n),
.DataIn(Din),
.DataOut(Dout),
);
0仿真时刻:3个initial进程和1个DUV同时执行。同时执行的进程其顺序不是固定的,和所用的仿真器有关,假设此处的同时执行,按代码中的顺序来执行。
执行Clock Generation 中的语句Ck = 0; ~Ck。 执行forever #10 进程挂起。
执行Reset Generation 中的语句Rst_n = 1; #5 进程挂起。
执行Data Input Generation中的语句Din = 0; #80 进程挂起。
执行DUV中的语句~DataIn; #3进程挂起。always @进程挂起。 至此0仿真时刻的语句全部执行完毕,仿真时间轴向前推进。
3仿真时刻:只有一个计算事件 DataInv = #3 ~DataIn;更新DataInv的值。无触发更多计算事件,所以仿真时间轴向前推进。
5仿真时刻:执行Reset Generation 中的语句 Rst_n = 0; #55 进程挂起。
由于Rst_n的更新时间,DUV中的always @进程执行,DataOut值更新。无触发更多计算事件,仿真时间轴向前推进。
10仿真时刻: 执行Clock Gneration 中的计算事件CK。更新事件触发。#10进程挂起。
执行DUV中的always进程,计算事件Data_Out = 0。无触发更多事件,仿真时间轴向前推进。
60仿真时刻: 执行Clock Gneration 中的计算事件CK。更新事件触发。#10进程挂起。
执行Reset Generation 中的语句 Rst_n = 1; 进程结束。
执行DUV中的always进程,计算事件Data_Out = 1(Rst_n的值已经为1)。无触发更多事件,仿真时间轴向前推进。
80仿真时刻: 执行Clock Gneration 中的计算事件CK。更新事件触发。#10进程挂起。
执行Data Input Generation中的语句Din = 1; #40 进程挂起。
执行DUV中的always进程,计算事件Data_Out = Data_Inv。
执行DUV中的语句~DataIn; #3进程挂起。always @进程挂起。 至此0仿真时刻的语句全部执行完毕,仿真时间轴向前推进。
仿真时间:是仿真时间维护的时间值,用来对仿真电路的真实时间进行建模(仿真时间和软件的执行时间没有任何联系),当仿真时间推进到某一个时间点时,该时间点就被称为当前仿真时间,而以后的任何时间都被称为将来仿真时间。
事件:模型中数值的变化,功能仿真是一种事件驱动的仿真,整个仿真过程都是围绕事件来组织的。
更新事件:在被仿真的电路中,线网或寄存器的值在任何进程中的任何改变都被认为是一个更新事件。
计算事件:由于更新事件产生的,进程的计算,计算事件。
计算事件和更新事件之间循环往复的互相触发,推动仿真时间的前进。
进程是Verilog中的独立执行单元,包括:原语(Primitives), 模块(Moules), initial过程块, always过程块, 连续赋值语句(assign), 异步任务(task)。在仿真时,所有的进程都是仿真器按Verilog的语义来顺序执行的,效果是各个进程并行执行的效果,在未执行完当前所有的进程时,仿真时间不会向前推进。
initial begin
Ck = 0; forever Ck = ~Ck;
end
例子会hang在仿真时刻0,因为更新时间一直触发计算事件,计算事件一直触发更新时间。
Verilog中的时序控制:事件语句(@),延时语句(#),等待语句(wait)。
Verilog仿真时的不确定性:在同一个仿真时间内,几个同一调度模块中事件执行顺序的任意性,进程之间语句的任意交织。
Verilog的事件调度:
注意:1,阻塞赋值和非阻塞赋值同处一个优先级,执行顺序随机或随仿真器。2,系统任务处于最低优先级,在该时刻的最后执行。