编写 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实例数组的更多相关文章

  1. Java-Runoob-高级教程-实例-数组:16. Java 实例 - 数组并集

    ylbtech-Java-Runoob-高级教程-实例-数组:16. Java 实例 - 数组并集 1.返回顶部 1. Java 实例 - 数组并集  Java 实例 以下实例演示了如何使用 unio ...

  2. ylbtech-Java-Runoob-高级教程-实例-数组:15. Java 实例 – 判断数组是否相等

    ylbtech-Java-Runoob-高级教程-实例-数组:15. Java 实例 – 判断数组是否相等 1.返回顶部 1. Java 实例 - 判断数组是否相等  Java 实例 以下实例演示了如 ...

  3. Java-Runoob-高级教程-实例-数组:14. Java 实例 – 在数组中查找指定元素

    ylbtech-Java-Runoob-高级教程-实例-数组:14. Java 实例 – 在数组中查找指定元素 1.返回顶部 1. Java 实例 - 在数组中查找指定元素  Java 实例 以下实例 ...

  4. Java-Runoob-高级教程-实例-数组:13. Java 实例 – 数组交集

    ylbtech-Java-Runoob-高级教程-实例-数组:13. Java 实例 – 数组交集 1.返回顶部 1. Java 实例 - 数组交集  Java 实例 以下实例演示了如何使用 reta ...

  5. Java-Runoob-高级教程-实例-数组:12. Java 实例 – 数组差集

    ylbtech-Java-Runoob-高级教程-实例-数组:12. Java 实例 – 数组差集 1.返回顶部 1. Java 实例 - 数组差集  Java 实例 以下实例演示了如何使用 remo ...

  6. Java-Runoob-高级教程-实例-数组:11. Java 实例 – 删除数组元素

    ylbtech-Java-Runoob-高级教程-实例-数组:11. Java 实例 – 删除数组元素 1.返回顶部 1. Java 实例 - 删除数组元素  Java 实例 以下实例演示了如何使用 ...

  7. Java-Runoob-高级教程-实例-数组:10. Java 实例 – 查找数组中的重复元素-un

    ylbtech-Java-Runoob-高级教程-实例-数组:10. Java 实例 – 查找数组中的重复元素 1.返回顶部 1. Java 实例 - 查找数组中的重复元素  Java 实例 以下实例 ...

  8. -Java-Runoob-高级教程-实例-数组:09. Java 实例 – 数组扩容

    ylbtech-Java-Runoob-高级教程-实例-数组:09. Java 实例 – 数组扩容 1.返回顶部 1. Java 实例 - 数组扩容  Java 实例 以下实例演示了如何在数组初始化后 ...

  9. Java-Runoob-高级教程-实例-数组:08. Java 实例 – 数组填充

    ylbtech-Java-Runoob-高级教程-实例-数组:08. Java 实例 – 数组填充 1.返回顶部 1. Java 实例 - 数组填充  Java 实例 以下实例我们通过 Java Ut ...

随机推荐

  1. 程序向informix数据库插入text类型的中文乱码问题

    部署应用的Linux服务器的编码格式为utf-8.但是数据库的编码格式为Gbk.所以导致的乱码.但是其他类型的数据中文并不乱码. 通过图片中修改编码格式,可以解决,导致的后果就是tomcat的日志输出 ...

  2. webpack 安装使用简例

    1. 新建项目文件夹,如 webpack-demo 2. cd 到安装项目根目录,即进入webpack-demo文件夹,命令行工具输入"npm install webpack webpack ...

  3. [考试总结]noip模拟22

    又发现模拟 \(22\) 的总结也咕掉了,现在补上它... 似乎又是gg的一场. 以为自己的部分分数打的很全,然而到后面发现自己的树剖打假了 \(\color{green}{\huge{\text{树 ...

  4. Python脚本:爬取天气数据并发邮件给心爱的Ta

    第一部分:爬取天气数据 # 在函数调用 get_weather(url = 'https://www.tianqi.com/foshan') 的 url中更改城市,foshan为佛山市 1 impor ...

  5. ECMAScript 2020(ES11)新特性简介

    目录 简介 动态imports import.meta export加强 BigInt matchAll() globalThis Promise.allSettled() ??操作符 ?.操作符 总 ...

  6. atom之插件安装及相关

    1. simplified-chinese-menu 汉化软件 2. file-icons 加上文件图标 3. language-vue 加上vue语言支持 4. platformio-ide-ter ...

  7. HttpRunner3源码阅读:7.响应后处理 response.py

    response 上一篇说的client.py来发送请求,这里就来看另一个response.py,该文件主要是完成测试断言方法 可用资料 jmespath[json数据取值处理]: https://g ...

  8. appium自动化测试(5)-一些pyhon操作

    1.套件的问题 将所有的测试用例加进去,会一个个执行,用于用例名字没有规范test开头的时候 def suite(): suite = unittest.TestSuite suite.addTest ...

  9. BUUCTF[强网杯 2019]随便注(堆叠注入)

    记一道堆叠注入的题.也是刷BUU的第一道题. ?inject=1' 报错 ?inject=1'--+ //正常 存在注入的.正常查询字段数,字段数为2.在联合查询的时候给了新提示 ?inject=0' ...

  10. Jetpack Compose 1.0 终于要投入使用了!

    前言 Jetpack Compose 是用于构建原生界面的「新款 Android 工具包」.2021 Google IO 大会上,Google宣布:「Jetpack Compose 1.0 即将面世」 ...