Verilog学习之简化代码设计


前言

今天我们做的是第八道题——使用 generate……for 语句简化代码,在这道题里我们需要注意或者说是学会的是如何使用 generate 循环生成语句,接下来就让我们看如何解这道题。简化代码


一、题目描述

在某个module中包含了很多相似的连续赋值语句,请使用generata…for语句编写代码,替代该语句,要求不能改变原module的功能。
原代码如下:
module template_module(
input [7:0] data_in,
output [7:0] data_out
);
assign data_out [0] = data_in [7];
assign data_out [1] = data_in [6];
assign data_out [2] = data_in [5];
assign data_out [3] = data_in [4];
assign data_out [4] = data_in [3];
assign data_out [5] = data_in [2];
assign data_out [6] = data_in [1];
assign data_out [7] = data_in [0];

endmodule

输入描述:
data_in:8bit位宽的无符号数

输出描述:
data_out:8bit位宽的无符号数

二、实现思路

1.生成块与生成语句

生成语句可以动态地生成Verilog代码。这一声明语句方便了参数化模块的生成。当对矢量中的多个位进行重复操作时,或者当进行多个模块的实例引用的重复操作时,或者在根据参数的定义来确定程序中是否应该包括某段Verilog代码的时候,使用生成块语句能够大大地简化程序的编写过程。

生成块语句能够控制变量的声明、任务或者函数的调用,还能对实例引用进行全面的控制。编写代码时必须在模块中说明生成的实例范围,关键字generate-endgenerate用来指定该范围。

生成实例可以使以下的一个或者多种类型:
(1)模块
(2)用户的定义原语
(3)门级原语
(4)连续赋值语句
(5)initial和always块

生成的声明和生成的实例能够在设计中被有条件地调用(实例引用)。在设计中可以多次调用(实例引用)生成的实例和生成的变量声明。生成的实例唯一的标识名,因此可以用层次命名的规则引用。为了支持结构化的元件与过程块语句的相互连接,Verilog语言允许在生成的范围内声明下列数据类型:
(1)net(线网)、寄存器(reg)
(2)integer(整型数)、real(实型数)、time(时间型)、realtime(实数时间型)
(3)event(事件)

生成的数据类型具有唯一的标识名,可以被层次引用。此外,究竟是使用按照次序或者参数名赋值的参数重新定义,还是defparam声明的参数重新定义,都可以在生成范围中定义。(注意:生成范围中定义的defparam语句能够重新定义的参数必须是在同一个生成范围内,或者是在生成范围的层次化实例当中。)

任务和函数也允许出现在生成范围中,但是能不能出现在循环生成当中。生成任务和函数具有唯一的标识符名称,可以被层次引用。

不允许出现在生成范围之内的模块项声明包括:

(1)参数、局部参数;
(2)输入、输出和输入/输出声明;
(3)指定块

生成块实例的连接方法与常规模块实例相同。

(摘自夏宇闻老师的Verilog数字系统设计教程,自我感觉阐述的比较经典)

在我看来的话,生成块(生成语句)其实就是为了把一些我们代码中重复的部分(多条类似的语句,像本题一样)用简短的几行代码来代替,因为块语句本身的作用就是把多条语句合并在一起。

2.生成语句的分类

1)循环生成语句

循环生成语句其实就是 generate……for 语句,它的主要目的是简化我们的代码书写,利用循环生成语句我们可以将之前需要写很多条比较相似的语句才能实现的功能用很简短的循环生成语句来代替。基本语法如下:

genvar i;//声明一个临时循环变量
generate
	for (i=0; i<N ; i=i+1)
		begin: bit//循环段的名字

		end
endgenerate

关于以上语法有四点注意:
1、循环生成中for语句使用的变量必须用 genvar 关键字定义,genvar 关键字可以写在 generate 语句外面,也可以写在generate语句里面,只要先于for语句声明即可;
2、循环段必须有名字,这是一个强制规定
3、for 语句中的内容必须加 begin-end ,即使只有一条语句也不能省略,这也是一个强制规定,而且给循环段起名字也离不开 begin 关键字;
4、循环段中的语句可以是实例化语句也可以是连续赋值语句。

2)条件生成语句

在夏宇闻老师的书中把 generate……if 语句和 generate……case 语句分开讨论,但在这儿的话我把它们一起对比阐述。它们的目的都是为了左右编译器的行为,类似于C语言中的条件选择宏定义,根据一些初始参数来决定载入哪部分代码来进行编译。下面分别阐述它们的语法以及注意事项。
generate-if语句

generate
	if (<condition>) begin: <label_1>
		<code>;
	end else if (<condition>) begin: <label_2>
		<code>;
	end else begin: <label_3>
		<code>;
	end
endgenerate

关于该语法有三点注意:
1、< condition >必须是常量比较,例如一些参数,这样编译器才可以在编译前确定需要使用的代码;
2、与for语句不同的是,if 语句的内容中,begin-end 只有在 < code > 有多条语句时才是必须的;
3、每一个条件分支的名称是可选的,这点不像循环生成语句那么严格。

generate-case语句

generate
		case (<constant_expression>)
			<value>: begin: <label_1>
				<code>
				end
			<value>: begin: <label_2>
				<code>
				end
			……
			default: begin: <label_N>
				<code>
				end
      	endcase
endgenerate

关于该语法也有三点注意,和generate-if类似:
1、< constant_expression >必须是常量比较,例如一些参数,这样编译器才可以在编译前确定需要使用的代码;
2、同样,与for语句不同的是,case语句的内容中,begin-end 只有在< code >有多条语句时才是必须的;
3、每一个条件分支的名称是可选的,这点不像循环生成语句那么严格。

三、代码展示

`timescale 1ns/1ns
module gen_for_module( 
    input [7:0] data_in,
    output [7:0] data_out
);
//声明一个临时循环变量
//该变量只用于生成快的循环变量
//Verilog仿真时改变量在设计中并不存在
genvar i;
//单循环
generate
    for(i=0;i<8;i=i+1)
    begin : bit
        assign data_out[i] = data_in[7-i];
    end
endgenerate
endmodule

总结

以上就是我在做这道题时的思路,以及代码的编写,如果还有更多更好的解法,欢迎读到这篇文章的朋友们在评论区告诉我,共同进步嘛。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个默默无闻的小程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值