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 时,连接情况同实验一至实验三。
其实在查规范的同时还发现了更稀奇的写法,但是看看就明白了,不做解释。
标签:din,dout,clk,实例,Verilog,数组,bits,连接,mod 来源: https://www.cnblogs.com/nevercode/p/15201279.html