Verilog | for语句的理解与使用

这篇具有很好参考价值的文章主要介绍了Verilog | for语句的理解与使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

for语句在硬件里的使用并不频繁,一方面是因为for语句循环几次,就是将相同的电路复制几次,因此循环次数越多,占用面积越大, 综合就越慢,for语句的使用就很占用硬件资源,另一方面是因为在设计中往往是采用时序逻辑设计用到for循环的地方不多。

generate for 与 always for用法与区别

generate for

  • 首先需要定义genvar,作为 generate中的循环变量。
  • generate语句中定义的for语句,必须要有begin,为后续增加标签做准备。
  • begin后要有名称,也就是要有标签,因为标签会作为generate循环的实例名称。

可以使用在generate语句中的类型主要有:

  • module(模块)
  • UDP(用户自定义原语,不常用)
  • 门级原语
  • 连续赋值语句
  • initialalways语句

generate的注意事项可参考:https://blog.csdn.net/moon9999/article/details/106969615

  1. 同一个文件中,generate for循环每次的循环变量名称不能重复,否则lint检查会报错,这也意味着generate不是一个完整的命名空间域吧;
generate
    genvar i;
    for(i=0; i<10; i=i+1)begin: RTL1
        ...
    end
endgenerate

generate
    genvar i;
    for(i=0; i<10; i=i+1)begin: RTL2
        ...
    end
endgenerate
  1. generate 后跟begin end可以避免这一报错,但是verilog2005标准中已经明确禁止这种写法(generate begin-end),所以就乖乖的为每一个generate for定义一个genvar变量吧;

  2. genvar定义在generate之外的话,两个generate都使用了这个变量,那么编译/lint/nlint都不会报错,甚至warning都不会报出,但是却可能引起仿真陷入死循环,也是不推荐,就乖乖定义genvar好了;

genvar i;
generate
    for(i=0; i<PORT_NUM; i=i+1)begin:gen_data
        assign data_in[i*DATA_WD +:DATA_WD] = data_arr[i];
    end
endgenerate

generate
    for(i=0; i<PORT_NUM; i=i+1)begin:gen_data_tmp
        assign data_in_tmp[i*DATA_WD +:DATA_WD] = data_arr[i];
    end
endgenerate
  1. genvar定义的变量不要用在always中循环使用,这种场景下乖乖在always里定义integer
    genvar i; // fail
    always @(*)begin: gain_data
        //integer i;  //yes
        vld  = 0;
        data = 0;
        cnt  = 0;				
        for(i=0; i<PORT_NUM; i=i+1)begin
            if(in_vld[i])begin
                vld  = 1'b1;
                cnt  = cnt + {DATA_WD{1'b1}};
                data = in_data[DATA_WD*i +:DATA_WD];
            end
        end
    end

verilog for,Verilog,fpga开发

  1. if-generate(case-generate)的每一个if-else块也建议有一个名字,而不只是always块有名字。尽管在编译和lint检查时不会报错,但是可能会引发后续的formal报错,这是听一位大佬说的,不过说实话,我平时也不加这个名字;

  2. generate中的代码块名字不要与文件中定义的信号名重复;

reg inst_rtl;
genvar j;
generate
	for(i=0; i<3; i=i+1)begin:inst_rtl
		flow_proc U_PROC(clk, rst_n, data_vld, in_data);
	end
endgenerate

verilog for,Verilog,fpga开发

  1. generate for里的参数必须直接调用,例如for(i=0; i<DEPTH; i=i+1),不能够出现运算例如for(i=0; i<DEPTH*5; i=i+1),如果一定需要这样做,那么要将参数提前处理好再拿来用;

  2. generate for中支持data[3i+8 : 3i]的取值方式,但是单纯的for循环不支持,只支持data[3i +: 8]写法;

    这是Verilog2001新加的语法:Verilog-2001向量部分选择

    在Verilog-1995中,可以选择向量的任一位输出,也可以选择向量的连续几位输出,不过此时连续几位的始末数值的index需要是常量。而在Verilog-2001中,可以用变量作为index,进行part select。

          [base_expr +: width_expr] //positive offset
    
          [base_expr -: width_expr] //negative offset  
    

    其中base_expr可以是变量,而width_expr必须是常量。+:表示由base_expr向上增长width_expr位,-:表示由base_expr向上递减width_expr位。

always for

  • always for循环的主要功能用于赋值和延迟两个功能
  • 需要定义integer类型变量。
  • 异步复位时序逻辑always @下面第一行必须是异步复位,不能有for循环,否则综合工具会报错。

区别

  • generate-for 循环适用于物理结构随参数变化的模块,always for 循环适用于物理结构不变的。
  • generate-for 每个循环产生一个实例,由于for 循环在 always 模块内部,只产生一个 always 实例。
  • genvar循环用于产生多套电路,各套电路之间必须独立;integer循环可以用于同一个逻辑的累积赋值,例如累加,但是也可以用于多套独立组合逻辑描述。

generate foralways for 语句用法与电路结构对比可参考:

https://blog.csdn.net/weixin_44544687/article/details/109720389

流水线乘法实现

Verilog代码:

`timescale 1ns / 1ps
//牛客第56题,流水线乘法器
		
module multi_pipe#(
	parameter size = 4
)(
	input 						clk 		,   
	input 						rst_n		,
	input	[size-1:0]			mul_a		,
	input	[size-1:0]			mul_b		,
 
 	output	reg	[size*2-1:0]	mul_out		
);

	parameter N = size*2;
    wire [N-1:0] temp [size-1:0];
    reg	[size*2-1:0]	mul_out1,mul_out2,mul_out3;	
//    genvar定义的变量不要用在always中循环使用
//    genvar i;
//    generate
//        for (i =0;i<size;i=i+1)
//        begin :emnnnn
//            always @(posedge clk or negedge rst_n)
//            begin
//                if(!rst_n ) temp[i] <= 0;
//                else
//                    temp[i] <= mul_b[i]?mul_a<<i:'d0;
//            end
//        end
//    endgenerate
    genvar i;
    generate
        for(i = 0; i < 4; i = i + 1)begin : loop
            assign temp[i] = mul_b[i] ? mul_a << i : 'd0;
        end
    endgenerate
    
//    第一种(正确)
    always @(posedge clk or negedge rst_n)
            begin
                if(!rst_n ) mul_out <= 0;
                else
                    mul_out <= temp[0] + temp[1]+temp[2]+temp[3];
            end
         
//     第二种(错误)   
//     genvar定义的变量不要用在always中循环使用,这种场景下建议在always里定义integer,或更改写法     
    genvar j;//一个 genvar 变量可用于多个 generate 循环,但不建议
    generate
		  for (j =0;j<size;j=j+1)
		  begin :emnnn
			  always @(posedge clk or negedge rst_n)
			  begin
				  if(!rst_n ) mul_out1 <= 0;
				  else
					  mul_out1 <= mul_out1 + temp[j];
			  end
		  end
    endgenerate
    
//    第三种(正确,结果和第一种存在差异)
//    这种写法要使用阻塞赋值
	integer k;
	always @(temp)
	begin
		if(!rst_n ) mul_out2 <= 0;
		else
		 for(k = 0;k<size ;k=k+1)
			mul_out2 = mul_out2 + temp[k];
	end
	
//	第四种,作为对比(错误)
// 使用非阻塞赋值,与上面阻塞赋值进行对比
	integer m;
	always @(temp)            
	begin             	
		if(!rst_n ) mul_out3 <= 0;
		else  
			for (m=0;m<size;m=m+1)
				mul_out3 <= mul_out3 + temp[m];
	end
	  
endmodule

Tb代码:

`timescale 1ns / 1ps

module multi_pipe_tb(

    );
    reg clk;
    reg rst_n;
    reg [3:0] mul_a;
    reg [3:0] mul_b;
    wire [7:0] mul_out;
    parameter size = 4;
    
    initial begin
    clk = 0;
    rst_n = 0;
    mul_a = 0;mul_b = 0;
    #10 rst_n =1;
    #10 mul_a = 4;mul_b =14;
    #500 mul_a = 5;mul_b = 8;
    end
    
    always #5 clk = ~clk;
    
    multi_pipe #(size) multi_pipe(clk,rst_n,mul_a,mul_b,mul_out);
    
endmodule

verilog for,Verilog,fpga开发

mul_out1和mul_out3的结果可以看到结果为temp[3]的值,这是由于always语句中使用非阻塞赋值<=时,是在always结束后才把值赋给左边的寄存器,因此才出现了上面的情况。需要注意的是,mul_out2是将mul_out3的非阻塞赋值改为阻塞赋值可以得到正确结果,但是由于always块是并行的,将mul_out1改为阻塞赋值依旧得到的是错误的结果。文章来源地址https://www.toymoban.com/news/detail-780545.html

到了这里,关于Verilog | for语句的理解与使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FPGA开发] 使用Verilog实现一个简单的计数器

    计数器是数字电路中常见的元件之一,它能够按照一定的规律进行计数。在FPGA开发中,我们可以使用硬件描述语言Verilog来实现一个简单的计数器。本文将为您详细介绍如何使用Verilog编写一个基于FPGA的计数器,并提供相应的源代码。 首先,我们需要定义计数器的功能和规格

    2024年02月03日
    浏览(61)
  • 【FPGA/verilog -入门学习5】verilog中的genrate for 和for 以及数组的用法

    本文参考:verilog generate语法总结-CSDN博客 Verilog数组赋值_笔记大全_设计学院 在Verilog中, generate for 和 for 都是用于循环的结构,但是它们具有不同的应用场合和语义。 for 循环: for 循环主要用于行为描述(behavioral description),通常用于描述算法或数学运算。 for 循环在仿真

    2024年02月03日
    浏览(47)
  • Verilog循环语句(for、while、foever和repeat)

    本文主要介绍verilog常用的循环语句,循环语句的用途,主要是可以多次执行相同的代码或逻辑。 verilog的循环语句主要有:for循环、while循环、foever循环和repeat循环。 注意注意,for循环在正式FPGA设计中部分情况下可综合,其余几个循环语句均不可综合,主要用于testbench。 f

    2024年02月04日
    浏览(49)
  • Vivado开发FPGA使用流程、教程 verilog(建立工程、编译文件到最终烧录的全流程)

    目录 一、概述 二、工程创建 三、添加设计文件并编译 四、线上仿真 五、布局布线 六、生成比特流文件 七、烧录 一、概述 vivado开发FPGA流程分为创建工程、添加设计文件、编译、线上仿真、布局布线(添加约束文件)、生成比特流文件、烧录等步骤,下文将按照这些步骤讲

    2024年02月09日
    浏览(37)
  • 【FPGA Verilog开发实战指南】初识Verilog HDL-基础语法

    就是用代码来描述硬件结构 语言有VHDL与Verilog HDL Verilog HDL 是从C语言来的,学的快 ###例子 也叫保留字,一般是小写 module 表示模块的开始 endmodule 模块的结束 模块名 一般与.v文件的名字一致 输入信号 input 输出信号 output 既做输入也做输出 inout 需要一些变量和参数对输

    2024年02月21日
    浏览(45)
  • FPGA模块使用Verilog调用另一个Verilog模块

    FPGA模块使用Verilog调用另一个Verilog模块 在FPGA设计中,常常需要将一个大的模块分解成多个子模块来实现。而这些子模块通常由Verilog代码编写而成。在设计中,我们需要通过调用这些子模块来实现整体的功能。本文将介绍如何使用Verilog调用另一个Verilog模块。 为了说明这个过

    2024年02月07日
    浏览(47)
  • 基于FPGA的QPSK调制系统verilog开发

    目录 一、理论基础 二、核心程序 三、测试结果         正交相移键控(Quadrature Phase Shift Keying,QPSK)是一种数字调制方式。它分为绝对相移和相对相移两种。由于绝对相移方式存在相位模糊问题,所以在实际中主要采用相对移相方式DQPSK。QPSK是一种四进制相位调制,具有良

    2024年02月01日
    浏览(47)
  • 基于Verilog 语言开发的FPGA密码锁工程

    基于Verilog 语言开发的FPGA密码锁工程。 通过矩阵键盘输入按键值。 输入12修改密码,13清除密码,可以修改原来默认的密码,修改时首先要输入当前密码进行验证,正确后才能更新当前密码,否则修改不成功。 修改结束后按键15,确认修改成功。 也直接使用默认密码作为最终

    2024年02月10日
    浏览(59)
  • 基于FPGA的FSK调制解调系统verilog开发

    目录 1.算法仿真效果 2.verilog核心程序 3.算法涉及理论知识概要 4.完整verilog VIVADO2019.2仿真结果如下:       频移键控是利用载波的频率变化来传递数字信息。数字频率调制是数据通信中使用较 早的一种通信方式,由于这种调制解调方式容易实现,抗噪声和抗衰减性能较强,

    2024年02月05日
    浏览(77)
  • 基于vivado+Verilog FPGA开发 — GT收发器

    代码规范:Verilog 代码规范_verilog代码编写规范-CSDN博客 开发流程:FPGA基础知识----第二章 FPGA 开发流程_fpga 一个项目的整个流程-CSDN博客   源码下载:GitHub - Redamancy785/FPGA-Learning-Record: 项目博客:https://blog.csdn.net/weixin_51460407 零、低速通信接口的缺陷 1、同步通信要求传输数据

    2024年04月17日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包