分层事件队列
1 活动事件队列(Active event queue) 是调度大多数Verilog事件的地方,包括:
阻塞赋值 非阻塞赋值的RHS 连续赋值 显示命令($display) 计算原语和实例的输入信号,更改输出信号。
2 非活动事件队列(Inactive event queue) , 用于#0-delayed赋值的调度。
3 非阻塞赋值更改队列(Nonblocking event) ,用于更改非阻塞赋值LHS的调度。
4 监控事件队列 ( Monitor event queue) , 用于$strobe 和 $monitor显示命令的调度。
5 未来事件队列 (Euture event) , 用于保存未来执行的事件
事件队列特性
1 所有active事件的处理称为一个仿真周期
2 事件要根据它的属性添加到对应的事件队列中。不再active的事件会被激活并提升到iacitve中,然后执行并从中移除
3 Verilog调度算法可以选取任意的active事件进行处理
4 使用#0把进程挂起,然后在当前时间把inactive事件在当前时间的下一个仿真周期恢复执行
5 非阻塞赋值在当前事件或未来事件调度
确定性和不确定性
确定性:仿真器要保证下面两个调度顺序:
begin/end 块中的语句应该按照他们在块中顺序执行。
非阻塞赋值的赋值顺序应该和语句执行的顺序保持一致
不确定性
不确定性的来源是:active事件可以任意的顺序从事件队列中取出事件并做处理
// 当posedge clk 发生时,两个always都要被激活,仿真器可以以任意顺序执行,因而导致x的不确定性
always @ (posedge clk) x = y;
always @ (posedge clk) y = z;
//当使用非阻塞赋值,计算RHS和更改LHS分开进行,所以解决了竞争条件
always @ (posedge clk) x <= y;
always @ (posedge clk) y <= z;
// 上面的竞争条件的情况是两个进程对一个变量同时有read和write
// 另一种竞争条件是两个进程对一个变量同时write
always @ (posedge clk) x <= y;
always @ (posedge clk) x <= z;
//不确定性另一种来源:行为块中没有时序控制的语句不用必须在一个事件中执行完
自己触发自己
module osc1(output reg clk);
initial #10 clk = 0;
always @ (clk) #10 clk = ~clk;
endmodule
// 阻塞赋值在计算RHS和更改LHS时不能中断,always 对 clk的变化又敏感时阻塞已经完成,所以不能触发自己
module osc2(output reg clk);
initial #10 clk = 0;
always @ (clk) #10 clk <= ~clk;
endmodule
// 非阻塞赋值当LHS发生更改时,@(Clk)又被触发,所以可以触发自己