Verilog:generate、for、always 语句用法与电路结构对比

本文通过实例代码对比了Verilog中generate-for、for-always、generate_for_always等不同循环结构在时序逻辑和组合逻辑中的应用,探讨了它们在模块复用和代码生成上的差异。所有示例在首个有效时钟沿后均能正确设置目标值,而对于组合逻辑,信号在仿真开始时即有值并随输入变化。结论指出,在循环/条件/分支中调用模块需使用generate-for,循环变量需为genvar类型,其他情况可按需求选择合适语法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


最近写Verilog时,对于generate-for 和 for循环相关不是很清楚,所以写了一些代码对比一下不同写法的结果,记录一下,如有错误请多多指正,不喜轻喷。

1、always-for

代码:

reg	[data_width-1:0]	in1_reg	[0:depth-1];
	integer i;
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
		begin
			for(i=0;i<depth;i=i+1)
				in1_reg[i] <= 0;
		end
		else
		begin
			for(i=0;i<depth;i=i+1)
				in1_reg[i] <= in1+i;
		end
	end

仿真结果说明:in1_reg 在第一个有效时钟沿后,数据均变为目标值

ANALYSIS得到的结构图
in1

综合后的电路图:
in1_syn

2、 for-always

代码:

//integer j;							// Error:j is not a genvar;j is not a constant
	genvar j;
	reg [data_width-1:0]	in2_reg	[0:depth-1];
	for(j=0;j<depth;j=j+1)
	begin:in2_loop
		always@(posedge clk or negedge rst_n)
		begin
			if(!rst_n)
				in2_reg[j] <= 0;
			else
				in2_reg[j] <= in2+j;
		end
	end

仿真结果说明:in2_reg 在第一个有效时钟沿后,数据均变为目标值
ANALYSIS得到的结构图
in2

综合后的电路图:
in2_syn

3、generate_for_always

代码:

reg [data_width-1:0]	in3_reg	[0:depth-1];
	genvar k;
	generate
		for(k=0;k<depth;k=k+1)
		begin:generate_case
			always@(posedge clk or negedge rst_n)
			begin
				if(!rst_n)
					in3_reg[k] <= 0;
				else
					in3_reg[k] <= in3+k;
			end
		end
	endgenerate

仿真结果说明:in3_reg 在第一个有效时钟沿后,数据均变为目标值

ANALYSIS得到的结构图
in3

综合后的电路图:
in3_syn

3.1、generate-always-for

代码:

reg [data_width-1:0]	in31_reg	[0:depth-1];
	//genvar k1;		// Error:procedural assignment to a non-register k1 is not permitted, left-hand side should be reg/integer/time/genvar 
	integer k1;
	generate
		always@(posedge clk or negedge rst_n)
		begin
			if(!rst_n)
			begin
				for(k1=0;k1<depth;k1=k1+1)
				begin:for_rst
					in31_reg[k1] <= 0;
				end
			end
			else
			begin
				for(k1=0;k1<depth;k1=k1+1)
				begin:generate_always_for
					in31_reg[k1] <= in31+k1;
				end
			end
				
		end
	endgenerate

仿真结果说明:in31_reg 在第一个有效时钟沿后,数据均变为目标值

ANALYSIS得到的结构图
in31

综合后的电路图:
in31_syn

4、for-assign

代码:

wire[data_width-1:0]	in4_wire	[0:depth-1];
	//integer n;			// Error: n is not a genvar;n is not a constant
	genvar n;
	for(n=0;n<depth;n=n+1)
	begin:for_assign
		assign in4_wire[n] = in4+n;
	end

仿真结果说明:wire型,仿真开始即有值,随输入信号变化而变化

ANALYSIS得到的结构图
in4

综合后的电路图:
in4_syn

5、generate-for-assign

代码:

wire[data_width-1:0]	in5_wire	[0:depth-1];
	genvar m;
	generate
		for(m=0;m<depth;m=m+1)
		begin:generate_for_assign
			assign in5_wire[m] = in5+m;
		end
	endgenerate

仿真结果说明:wire型,仿真开始即有值,随输入信号变化而变化

ANALYSIS得到的结构图
in5

综合后的电路图:
in5_syn

6、always@(*)-for

代码:

reg [data_width-1:0]	in6_reg	[0:depth-1];
	always@(*)
	begin
		for(i=0;i<depth;i=i+1)
			in6_reg[i] = in6+i;
	end

仿真结果说明:wire型,仿真开始即有值,随输入信号变化而变化

ANALYSIS得到的结构图
in6

综合后的电路图:
在这里插入图片描述

7、for-always@(*)

可以用 for-assign 替换

8、generate_for_always@(*)

可以用generate-assign 替换

仿真结果

sim

可以看到,时序信号in1_reg,in2_reg,in3_reg,in31_reg 都在第一个有效时钟边沿后变为目标值;组合逻辑信号in4_wire, in5_wire, in6_reg 在电路开始仿真时即被赋值进行运算,输入数据变化后随之发生变化

2、根据电路结构,generate-for 和 for 循环对于always 和 assig 语句的作用相同,但书写方法不同
generate-for / for循环在alway块外面时,循环变量要定义为 genvar 型
for 循环在always 块内时,循环遍历要定义为 integer 类型

3、结论:
若要在循环/条件/分支语句中调用模块,须使用 generate-for语句,注意要用genvar 定义循环变量,并在for循环的 begin: 后跟上 循环名称;
其他情况可根据自身情况而定

generate-for和for循环使用说明可见 Verilog:generate-for 语句(用法,及与for语句区别)
文中的代码等可见https://download.csdn.net/download/weixin_44544687/13117406

### VerilogGenerate For 和 Normal For 的区别 #### 使用场景差异 Generate 构造主要用于模块实例化和参数化的条件编译或循环展开,而普通的 `for` 循环则用于一般的算法实现或者数据处理逻辑。Generate 结构中的代码会在 **综合阶段** 展开并生成多个独立的硬件结构[^1]。 #### 综合能力差异 普通 `for` 循环通常不会被综合工具识别为可综合的硬件描述语言的一部分,除非它是在组合逻辑中使用,并且其迭代次数可以静态确定。然而,在 RTL 级别的设计中,如果需要动态控制某些行为,则可能需要用到普通的 `for` 循环来完成复杂的计算任务[^3]。 #### 句法上的不同之处 以下是两者语法形式的区别: - **Generate For** ```verilog genvar i; // 定义genvar类型的变量i generate for (i = 0; i < N; i = i + 1) begin : inst_loop your_module instance_name ( .port1(wire[i]), ... ); end endgenerate ``` - **Normal For** ```verilog integer j; always @(*) begin for(j = 0; j < M; j = j + 1) begin if(condition[j]) result <= value[j]; end end ``` 在上述例子中可以看出,`genvar` 是专门用来定义供 `generate` 块使用的索引变量;而在常规过程中我们一般会采用 `integer` 类型作为计数器变量类型声明[^2]。 #### 示例对比分析 假设我们需要创建一组寄存器链路传输信号延迟模型时: - 如果利用 `generate-for`, 我们可以直接通过一次编写模板来自动生成多级寄存器连接关系; - 而如果是单纯依靠程序流内的 `normal-for`, 则更多时候是用来表达瞬态变化过程而非物理实体映射。 因此总结来说就是:当涉及到实际电路元件数量增加以及相应互连关系建立的时候应该优先考虑运用 `generate-for`; 对于那些只需要简单数值运算而不涉及额外资源消耗的操作而言, 就完全可以借助标准流程控制语句即 `normal-for`.
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值