为何Verilog task内的assign a = a/2仅触发一次值变更?
关于Task内Verilog过程连续赋值的两个问题解答
问题1:为何assign a = a/2仅执行一次?
task内部的assign属于过程连续赋值(procedural continuous assignment),和模块顶层的连续赋值逻辑有本质区别。针对你的代码:
- 第一个
assign a = 10'd512会持续驱动a为512,直到被后续的过程连续赋值解除。 - 10ns后执行
assign a = a/2时,按照IEEE 1800-2017 LRM 10.6.1的规定,会先解除之前对a的过程连续赋值,再计算当前表达式的值(此时a为512,计算得256)并赋值给a。
你预期的循环除以2直到0的情况未发生,核心原因是自依赖的过程连续赋值会被仿真器限制避免无限delta循环:当表达式的结果直接赋值给自身时,理论上会触发无限次的delta周期更新(a变→表达式重算→a再变→...),Xcelium这类仿真器会通过仅执行一次更新来终止这种潜在的死循环,因此a最终停留在256。
而当RHS不含LHS时(比如assign a = b),不存在自依赖,只要RHS的操作数变化就会触发表达式重算,所以能正常持续更新。
问题2:为何Task内多个assign无多驱动警告?
模块顶层的assign是静态连续赋值语句,一旦定义就会持续生效:
- 若给
net类型变量赋值,多个assign会造成多驱动冲突,触发警告/错误; - 若给
variable类型变量赋值,LRM明确禁止同一变量存在多个静态连续赋值,同样会触发编译错误。
但task内的assign是动态过程连续赋值,LRM 10.6.1明确规定:对已有过程连续赋值的变量执行新的assign时,会先自动解除旧的赋值,再应用新的赋值,同一时间只有一个过程连续赋值在驱动变量,不存在多驱动冲突,因此编译时不会报警告。
内容的提问来源于stack exchange,提问作者DeFalco
相关产品推荐
相关产品推荐

