Verilog实例数组
编写 Verilog 代码多年,至今才无意中发现了一种奇怪的语法,估计见过的这种的写法的人,在 FPGA 开发者中不会超过 20% 吧。
直接来看代码吧。先定义了一个简单的模块,名为 mod。
module mod(
input clk,
input din,
output reg [1:0] dout
);
always @(posedge clk)
dout <= {din, ~din};
endmodule
下面是对 mod 模块进行例化。注意例化名后面的东西。
module top(
input clk,
input [3:0] din,
output [7:0] dout
);
mod u_mod[3:0] ( // 例化名后面跟了一个位宽定义。
.clk (clk ), // I
.din (din[3:0] ), // I 连接的位宽是单个 mod 所需要的4倍
.dout (dout[7:0] ) // O 连接的位宽是单个 mod 所需要的4倍
);
endmodule
虽然以前从来没有见过这种写法,但从代码上大概可以推断出这种写法应该和 generate ... for ...
的作用是一样的,但是写法上要简洁得多。
实验一
使用 Vivado 对代码进行综合后,得到的原理图如下。从图上可以看到 mod 模块的确是被例化了 4 次。顶层的 4 bits 的 din 分别连接到了 4 个 u_mod,4 个 din 的索引和 u_mod 的索引相同,din[0] 连接到了 u_mod[0],din[3] 连接到了 u_mod[3]。4 个模块的 dout 输出后合并成了 8 bits,其中 u_mod[0] 的 2 bits 输出连接到了 dout[1:0], u_mod[3] 的 2 bits 输出连接到了 dout[7:6]。
实验二
为了进一步研究连接的顺序,又做了如下实验。模块例化时的位宽由原来的 [3:0] 改为 [0:3]。
mod u_mod[0:3] ( // 位宽定义进行反转。
.clk (clk ), // I
.din (din[3:0] ), // I 连接的位宽是单个 mod 所需要的4倍
.dout (dout[7:0] ) // O 连接的位宽是单个 mod 所需要的4倍
);
再次综合后,得到的原理图如下。4 个 u_mod 和顶层的连接关系完全反了过来,din[0] 连接到了 u_mod[3],din[3] 连接到了 u_mod[0]。输出也是同样的情况, u_mod[0] 的 2 bits 输出连接到了 dout[7:6], u_mod[3] 的 2 bits 输出连接到了 dout[1:0]。
经过上面 2 个实验,大概可以得出结论:模块例化的顺序总是从右到左的,连接顶层线序也是从右到左的。
实验三
为了进一步论证,做了第三个实验。把模块例化的位宽还原,把顶层的端口定义的位宽进行反转,再看一下会有什么效果。
module top(
input clk,
input [0:3] din,
output [0:7] dout
);
mod u_mod[3:0] (
.clk (clk ), // I
.din (din[0:3] ), // I
.dout (dout[0:7] ) // O
);
endmodule
din[0] 连接到了 u_mod[3],din[3] 连接到了 u_mod[0],和预期的一样。u_mod[0] 的 2 bits 输出连接到了 dout[6:7], u_mod[3] 的 2 bits 输出连接到了 dout[0:1],仔细看会发现,每个 u_mod 输出的 2 bits 和顶层的 dout 的 2 bits 是反过来连接的,u_mod[0].dout[0] 连接到了 dout[7],u_mod[0].dout[1] 连接到了 dout[6],这就是和上一个实验不同的地方。这个实验结果和上面做出的结论也是相符合的。
实验四
上面的实验中,顶层接口的输入输出位宽都是 mod 输入输出位宽的 4 倍,4 个 u_mod 连线独立,不会有干扰。但如果把顶层的位宽减小,会有什么后果呢?于是又做了第四个实验。mod 仍然例化 4 次,但是顶层 dout 位宽和 mod 的 dout 位宽相同,也就是说 4 个 u_mod 要共享顶层的 dout 端口,这样会出错吗?
module top(
input clk,
input [3:0] din,
output [1:0] dout
);
mod u_mod[3:0] (
.clk (clk ), // I
.din (din[3:0] ), // I
.dout (dout[1:0] ) // O
);
endmodule
经过 Vivado 的综合,并没有报错,并且生成了如下的原理图。但是报出了 multiple drivers 的告警。从原理图上可以看出,4 个 u_mod 的输出全部连到了一起,造成了多驱动的错误。当进一步在 Vivado 中执行 Implementation 时,直接报错,无法正常布线。(此处无报错,并不是此种连接方式有问题,而是和 mod 的输出相关,如果 mod 的输出在某些条件下输出高阻时,Implementation 是可以过的。只是输出会用到三太门。)
查询规范
针对这种以数组的方式批量例化模块的代码编写方法,我特意查询了 IEEE Std 1364-2005。在里面找到到如下两段话,此种语法称作实例数组。
In order to specify an array of instances, the instance name shall be followed by the range specification. The range shall be specified by two constant expressions, left-hand index ( lhi ) and right-hand index ( rhi ), separated by a colon and enclosed within a pair of square brackets. A [lhi:rhi] range specification shall represent an array of abs(lhi-rhi)+1 instances. Neither of the two constant expressions are required to be zero, and lhi is not required to be larger than rhi . If both constant expressions are equal, only one instance shall be generated.
当需要定义实例数组时,实例名称后面应跟有范围规范。范围由两个常量表达式指定,左侧索引 ( lhi ) 和右侧索引 ( rhi ),用冒号分隔并用一对方括号括起来。[lhi:rhi]
范围表示一次性例化 abs(lhi - rhi) + 1
个实例。两个常量表达式都不要求为零,并且 lhi
不一定需要比 rhi
大。如果两个常量表达式相等,则只会生成一个实例。
- The bit length of each port expression in the declared instance-array shall be compared with the bit length of each single-instance port or terminal in the instantiated module or primitive.
- For each port or terminal where the bit length of the instance-array port expression is the same as the bit length of the single-instance port, the instance-array port expression shall be connected to each single-instance port.
- If bit lengths are different, each instance shall get a part-select of the port expression as specified in the range, starting with the right-hand index.
- Too many or too few bits to connect to all the instances shall be considered an error.
- 声明的实例数组时,需要对中每个端口表达式的位宽和单个模块的端口位宽进行比较。
- 当端口表达式的位宽和单个模块的端口位宽相同时,同一端口表达式连接到每个单实例端口。
- 如果位宽不同,则从端口表达式的右侧索引开始,每个实例都会获取的端口表达式的一部分,获取宽度和单个模块的端口宽度相同。
- 当连接到所有实例的位太多或太少都会视为错误。
上述翻译可能不好理解,简单归纳一下就是,与每个端口相连的信号的位宽只能和端口本身的位宽相同,或者为端口位宽的 N 倍(N为实例数组的长度,即一次性例化模块的个数),其他宽度都是违法的。还是上面的例子,我们一次性例化了 4 个模块,即 N = 4。模块的 dout 本身位宽为 2 bits,所以能够连接到实例数组 dout 的信号位宽只能是 2 bits 或者 8 bits。当为 2 bits 时,连接情况如同实验四,当为 8 bits 时,连接情况同实验一至实验三。
其实在查规范的同时还发现了更稀奇的写法,但是看看就明白了,不做解释。
nand #2 t_nand[0:7] ( ... );
nand #2 x_nand[0:3] ( ... ), y_nand[4:7] ( ... );
总结
这种实例数组的写法相对与 generate ... for ...
在代码上看更简洁,且不容易出错,即便是出错,编译器也会检查出来。但是对于不熟悉此语法的同学来说,可能会不好理解。
Verilog实例数组的更多相关文章
- Java-Runoob-高级教程-实例-数组:16. Java 实例 - 数组并集
ylbtech-Java-Runoob-高级教程-实例-数组:16. Java 实例 - 数组并集 1.返回顶部 1. Java 实例 - 数组并集 Java 实例 以下实例演示了如何使用 unio ...
- ylbtech-Java-Runoob-高级教程-实例-数组:15. Java 实例 – 判断数组是否相等
ylbtech-Java-Runoob-高级教程-实例-数组:15. Java 实例 – 判断数组是否相等 1.返回顶部 1. Java 实例 - 判断数组是否相等 Java 实例 以下实例演示了如 ...
- Java-Runoob-高级教程-实例-数组:14. Java 实例 – 在数组中查找指定元素
ylbtech-Java-Runoob-高级教程-实例-数组:14. Java 实例 – 在数组中查找指定元素 1.返回顶部 1. Java 实例 - 在数组中查找指定元素 Java 实例 以下实例 ...
- Java-Runoob-高级教程-实例-数组:13. Java 实例 – 数组交集
ylbtech-Java-Runoob-高级教程-实例-数组:13. Java 实例 – 数组交集 1.返回顶部 1. Java 实例 - 数组交集 Java 实例 以下实例演示了如何使用 reta ...
- Java-Runoob-高级教程-实例-数组:12. Java 实例 – 数组差集
ylbtech-Java-Runoob-高级教程-实例-数组:12. Java 实例 – 数组差集 1.返回顶部 1. Java 实例 - 数组差集 Java 实例 以下实例演示了如何使用 remo ...
- Java-Runoob-高级教程-实例-数组:11. Java 实例 – 删除数组元素
ylbtech-Java-Runoob-高级教程-实例-数组:11. Java 实例 – 删除数组元素 1.返回顶部 1. Java 实例 - 删除数组元素 Java 实例 以下实例演示了如何使用 ...
- Java-Runoob-高级教程-实例-数组:10. Java 实例 – 查找数组中的重复元素-un
ylbtech-Java-Runoob-高级教程-实例-数组:10. Java 实例 – 查找数组中的重复元素 1.返回顶部 1. Java 实例 - 查找数组中的重复元素 Java 实例 以下实例 ...
- -Java-Runoob-高级教程-实例-数组:09. Java 实例 – 数组扩容
ylbtech-Java-Runoob-高级教程-实例-数组:09. Java 实例 – 数组扩容 1.返回顶部 1. Java 实例 - 数组扩容 Java 实例 以下实例演示了如何在数组初始化后 ...
- Java-Runoob-高级教程-实例-数组:08. Java 实例 – 数组填充
ylbtech-Java-Runoob-高级教程-实例-数组:08. Java 实例 – 数组填充 1.返回顶部 1. Java 实例 - 数组填充 Java 实例 以下实例我们通过 Java Ut ...
随机推荐
- Spring RestTemplate 之中文乱码
由于RestTemplate的默认构造方法初始化的StringHttpMessageConverter的默认字符集是ISO-8859-1,所以导致RestTemplate请求的响应内容会出现中文乱码. ...
- 龙芯 loongnix20 rc2 初体验
2021-07-24 v0.0.1 版权声明:原创文章,未经博主允许不得转载 3A5000 昨天发布啦,历史上的昨天是中共一大的第一天. 3A5000 的团购还没开始(大概还是3999左右整机的样子) ...
- 让Angular自定义组件支持form表单验证
Angular提供了一套非常强大的表单验证库(vue和react都需要第三方库的支持),可以非常方便简单实现web应用程序中的表单验证功能.但是如何让我们自定义的组件也支持验证呢? 我遇到一个需求是封 ...
- 解析ArrayList的底层实现(上)
private static final long serialVersionUID = 8683452581122892189L;//唯一序列号ID private static final int ...
- jboss未授权访问
测试 poc地址 https://github.com/joaomatosf/jexboss
- DS1515+
DS1515+ 2021年05月02日 0 2.4k aahk DS1515+ 2021年05月02日 这篇文章用于记录.改进.提高.分享我在使用群晖DS1515+网络存储服务器过程中的具体操作. ...
- 一文彻底搞清 Gradle 依赖【转】
来源:曾是放牛娃 www.jianshu.com/p/59fd653a54d2 转自:https://mp.weixin.qq.com/s?__biz=MzA3MDMyMjkzNg==&mid ...
- 看完就会的Spring Cloud Gateway
在前面几节,我给大家介绍了当一个系统拆分成微服务后,会产生的问题与解决方案:服务如何发现与管理(Nacos注册中心实战),服务与服务如何通信(Ribbon, Feign实战) 今天我们就来聊一聊另一个 ...
- Windows协议 LDAP篇 - 域用户和计算机用户
域用户 查询域用户 通过SAMR协议查询(net user就是通过这种协议查询的),samr也不是一种专门的协议,是一个RPC接口 在impacket里有个脚本samrdump.py,就是专门调用这个 ...
- 大龄程序员的出路在哪里?八年老Android的一点心得
这篇文章,给大家聊聊Android工程师的职业发展规划的一些思考,同时也给不少20多岁.30多岁,但是对自己的职业未来很迷茫的同学一些建议. 笔者希望通过此文,帮大家梳理一下程序员的职业发展方向,让大 ...