verilog中forever的运用

verilog使用中总是出现错误Error (10119): Verilog HDL Loop Statement error at test.v(9): loop with non-constant loop condition must terminate within 250 iterations,高手解释下
forever
#10 clk=~clk;
想周期性的输出一定频率的方波

Verilog硬件描述语言有很完整的语法结构和系统,类似高级语言,这些语法结构的应用给我们的设计描述带来很多方便。但是,我们知道,Verilog是描述硬件电路的,它是建立在硬件电路的基础上的。有些语法结构是不能与实际硬件电路对应起来的,也就是说我们在把一个语言描述的程序映射成实际硬件电路中的结构时是不能实现的。下面总结出来的大部分综合工具支持或不支持的verilog语法结构。

一.用verilog建立可综合模型的原则

要保证Verilog HDL赋值语句的可综合性,在建模时应注意以下要点:
(1)不使用initial。
(2)不使用#10。
(3)不使用循环次数不确定的循环语句,如forever、while等。
(4)不使用用户自定义原语(UDP元件)。
(5)尽量使用同步方式设计电路。
(6)除非是关键路径的设计,一般不采用调用门级元件来描述设计的方法,建议采用行为语句来完成设计。
(7)用always过程块描述组合逻辑,应在敏感信号列表中列出所有的输入信号。
(8)所有的内部寄存器都应该能够被复位,在使用FPGA实现设计时,应尽量使用器件的全局复位端作为系统总的复位。

(9)对时序逻辑描述和建模,应尽量使用非阻塞赋值方式。对组合逻辑描述和建模,既可以用阻塞赋值,也可以用非阻塞赋值。但在同一个过程块中,最好不要同时用阻塞赋值和非阻塞赋值。

(10)不能在一个以上的always过程块中对同一个变量赋值。而对同一个赋值对象不能既使用阻塞式赋值,又使用非阻塞式赋值。
(11)如果不打算把变量推导成锁存器,那么必须在if语句或case语句的所有条件分支中都对变量明确地赋值。
(12)避免混合使用上升沿和下降沿触发的触发器。
(13)同一个变量的赋值不能受多个时钟控制,也不能受两种不同的时钟条件(或者不同的时钟沿)控制。
(14)避免在case语句的分支项中使用x值或z值。
温馨提示:内容为网友见解,仅供参考
第1个回答  2021-03-31
先说结论,可以用,但是分时候,不会用的时候别乱用。

你老师说的计数器xx,可能是让你写计数器的时候别用for循环,软硬件编程思维的不同。写一个计数器表示一段延时,软件编程的思维肯定的是用for循环,软件的执行是顺序执行,也就是一直处于这个循环中,直到不满足循环计数条件而跳出循环。

而硬件中的计数器实现直接就是一组D触发器,根据计数器的使能,加上在时钟边沿触发变化,再加上一个清零端(还可以加置位端)。软件和硬件这两个可以说,完全不是一个东西。

always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 3'd0;
else if(cnt_clear)
cnt <= 3'd0;
else if(cnt_en)
cnt <= cnt + 1'd1;
end
如果我想实现软件思维的delay一段时间怎么做,直接用上面的计数器做一个flag

assign flag = cnt == 3'd3;
当cnt == 3‘d3时,我输出一个flag,表示我这段延时的标志。

i的变化不跟时钟走吗?
在Verilog中使用for循环的功能就是,把同一块电路复制多份,完全起不到计数的作用,所以这个i的意思是复制多少份你这段代码实现的电路,和时钟没有任何关系。主要是为了提高编码效率。

这个配图的功能就是把这块电路,复制stages_num份,然后每个clk下,执行的内容操作是相同的。所以能实现在复位时刻,把整个寄存器都赋值为0,然后复位释放执行其他操作。(这个图为题主提供)

题主提供图
什么时候用
可以用,那么什么时候用,代码设计有规律的时候,可以配合generate for,合理使用generate+for循环可以提高编码效率,同样的赋值语句需要赋值多次。这个generate语句里面可以是任何有运算。

generate
genvar i;
for(i = 0;i < 16;i = i + 1)
begin: neg_data
assign neg_data_out[i*DATA_WIDTH +:DATA_WIDTH] =
-data_in[i*DATA_WIDTH +:DATA_WIDTH]
end
endgenerate
同一个模块需要实例化多次也可以,比如这里有一个运算需要调用16个乘法器,如果把乘法器IP模块实例化16份,那岂不是要写很长的代码,所以用generate+for可以极大的提高编码效率。
第2个回答  2010-11-06
begin
clk = 0;
forever #10 clk = !clk;
end

这样可以产生一个周期信号

这是Modelsim给的例test bench中给的方案(tcount.v),在modelsim中可以正常运行。
在quartus中仿真count.v(原module),把tcount.v在test bench中调用,仿真时可以正常通过。但如果单独仿真tcount.v,会报和你一样的错误。
这个错误按字面意思是“与非恒定循环条件循环必须终止在250次迭代”,具体原因我也不知道
第3个回答  2021-03-31
先说结论,可以用,但是分时候,不会用的时候别乱用。

你老师说的计数器xx,可能是让你写计数器的时候别用for循环,软硬件编程思维的不同。写一个计数器表示一段延时,软件编程的思维肯定的是用for循环,软件的执行是顺序执行,也就是一直处于这个循环中,直到不满足循环计数条件而跳出循环。

而硬件中的计数器实现直接就是一组D触发器,根据计数器的使能,加上在时钟边沿触发变化,再加上一个清零端(还可以加置位端)。软件和硬件这两个可以说,完全不是一个东西。

always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 3'd0;
else if(cnt_clear)
cnt <= 3'd0;
else if(cnt_en)
cnt <= cnt + 1'd1;
end
如果我想实现软件思维的delay一段时间怎么做,直接用上面的计数器做一个flag

assign flag = cnt == 3'd3;
当cnt == 3‘d3时,我输出一个flag,表示我这段延时的标志。

i的变化不跟时钟走吗?
在Verilog中使用for循环的功能就是,把同一块电路复制多份,完全起不到计数的作用,所以这个i的意思是复制多少份你这段代码实现的电路,和时钟没有任何关系。主要是为了提高编码效率。

这个配图的功能就是把这块电路,复制stages_num份,然后每个clk下,执行的内容操作是相同的。所以能实现在复位时刻,把整个寄存器都赋值为0,然后复位释放执行其他操作。(这个图为题主提供)

题主提供图
什么时候用
可以用,那么什么时候用,代码设计有规律的时候,可以配合generate for,合理使用generate+for循环可以提高编码效率,同样的赋值语句需要赋值多次。这个generate语句里面可以是任何有运算。

generate
genvar i;
for(i = 0;i < 16;i = i + 1)
begin: neg_data
assign neg_data_out[i*DATA_WIDTH +:DATA_WIDTH] =
-data_in[i*DATA_WIDTH +:DATA_WIDTH]
end
endgenerate
同一个模块需要实例化多次也可以,比如这里有一个运算需要调用16个乘法器,如果把乘法器IP模块实例化16份,那岂不是要写很长的代码,所以用generate+for可以极大的提高编码效率。

generate
genvar i;
for(i = 0;i < 16;i = i + 1)
begin: mult_12x12
DW02_mult #(
.A_WIDTH(12),
.B_WIDTH(12)
) u_DW02_mult0(
.A(mult_a[i*12 +:12]),
.B(mult_b[i*12 +:12]),
.TC(1’b0),
.PRODUCT(product[i*24 +:24])
);
end
endgenerate
当然这样写debug会有一些困扰,不容易找到信号对应位宽数据。不过Verdi会显示每一个generate块,选中对应的块,加进去的波形就会是对应的bit信号。
第4个回答  推荐于2017-10-09
如果想输出周期为20个时间单位的方波,格式如下:
forever
begin
#0 clk=0;
#10 clk=1;
#10 clk=0;
end
或者
always #10 clk=~clk
希望我的回答能解决您的问题!本回答被提问者采纳
相似回答