Verilog 时延
连续赋值延时语句中的延时,用于控制任意操作数发生变化到语句左端赋予新值之间的时间延时。
连续赋值时延一般可分为普通赋值时延、隐式时延、声明时延。
时延一般是不可综合的,但寄存器的时延也是可以控制的。
以下 3 个例子实现的功能是等效的,分别对应 3 种不同连续赋值时延的写法。
//普通时延,A&B计算结果延时10个时间单位赋值给Z wire Z, A, B ; assign #10 Z = A & B ; //隐式时延,声明一个wire型变量时对其进行包含一定时延的连续赋值。 wire A, B; wire #10 Z = A & B; //声明时延,声明一个wire型变量是指定一个时延。因此对该变量所有的连续赋值都会被推迟到指定的时间。除非门级建模中,一般不推荐使用此类方法建模。 wire A, B; wire #10 Z ; assign Z =A & B
1. 惯性时延
在上述例子中,A 或 B 任意一个变量发生变化,那么在 Z 得到新的值之前,会有 10 个时间单位的时延。如果在这 10 个时间单位内,即在 Z 获取新的值之前,A 或 B 任意一个值又发生了变化,那么计算 Z 的新值时会取 A 或 B 当前的新值。所以称之为惯性时延,即信号脉冲宽度小于时延时,对输出没有影响。
因此仿真时,时延一定要合理设置,防止某些信号不能进行有效的延迟。
对一个有延迟的与门逻辑进行时延仿真。
module time_delay_module( input ai, bi, output so_lose, so_get, so_normal); assign #20 so_lose = ai & bi ; assign #5 so_get = ai & bi ; assign so_normal = ai & bi ; endmodule
testbench 参考如下:
`timescale 1ns/1ns module test ; reg ai, bi ; wire so_lose, so_get, so_normal ; initial begin ai = 0 ; #25 ; ai = 1 ; #35 ; ai = 0 ; //60ns #40 ; ai = 1 ; //100ns #10 ; ai = 0 ; //110ns end initial begin bi = 1 ; #70 ; bi = 0 ; #20 ; bi = 1 ; end time_delay_module u_wire_delay( .ai (ai), .bi (bi), .so_lose (so_lose), .so_get (so_get), .so_normal (so_normal)); initial begin forever begin #100; //$display("---gyc---%d", $time); if ($time >= 1000) begin $finish ; end end end endmodule
仿真结果如下:
信号 so_normal 为正常的与逻辑。
由于所有的时延均大于 5ns,所以信号 so_get 的结果为与操作后再延迟 5ns 的结果。
信号 so_lose 前一段是与操作后再延迟 20ns 的结果。
由于信号 ai 第二个高电平持续时间小于 20ns,so_lose 信号会因惯性时延而漏掉对这个脉冲的延时检测,所以后半段 so_lose 信号仍然为 0。
过程结构语句有 2 种,initial 与 always 语句。它们是行为级建模的 2 种基本语句。一个模块中可以包含多个 initial 和 always 语句,但 2 种语句不能嵌套使用。这些语句在模块间并行执行,与其在模块的前后顺序没有关系。但是 initial 语句或 always 语句内部可以理解为是顺序执行的(非阻塞赋值除外)。