)
相关阅读Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482目录前言实例数组范围(range)普通模块实例的端口连接门实例的端口连接实例数组的端口连接前言谈到重复实例化一般都会想到for generate结构但其实有一种更加简单的语法只是使用的人不多它就是实例数组其实在Verilog 1995标准它就已被引入早于generate结构被引入的Verilog 2001标准。首先来看看门的例化和模块的例化时实例数组的BNF范式语法有关BNF范式相关内容可以参考之前的文章。Verilog基础巴科斯范式(BNF)https://blog.csdn.net/weixin_45791458/article/details/132567389?ops_request_misc%257B%2522request%255Fid%2522%253A%2522172381461616800207085955%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257Drequest_id172381461616800207085955biz_id0utm_mediumdistribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-132567389-null-null.nonecaseutm_termBNFspm1018.2226.3001.4450图1 门例化时的实例数组图2 模块例化时的实例数组实例数组范围(range)在许多场合下我们需要重复多个实例。这些实例之间的唯一差异通常只是它们所连接的向量的索引。比如你可能需要四个与门每个与门的输入和输出连接到不同的位上像A[0]、A[1]等此时就可以使用实例数组如图1和图2所示。可选的范围和声明一个数组型变量/线网时的范围很相似由两个常量表达式指定即左侧索引(lhi)和右侧索引(rhi)它们之间用冒号分隔并用方括号括起来如例1所示。// 例1 and and_inst [3: 0] (Y, A, B); // 当对门使用实例数组时, 名字是必须的, 不能省略 test_module test_module_inst [3: 0] (Y, A, B);范围[lhi, rhi]表示有|lhi-rhi|1个实例生成如例2所示。// 例2 and and_inst [3: 0] (Y, A, B); // 生成了四个实例, 名字分别为and_inst[0], and_inst[1], and_inst[2], and_inst[3] test_module test_module_inst [3: 0] (Y, A, B); // 生成了四个实例, 名字分别为test_module_inst[0], test_module_inst[1], test_module_inst[2], test_module_inst[3]左侧索引和右侧索引的相对大小和绝对大小可以随意如例3所示。// 例3 and and_inst [-1: 3] (Y, A, B); // 生成了四个实例, 名字分别为and_inst[-1], and_inst[0], and_inst[1], and_inst[2] test_module test_module_inst [-1: 3] (Y, A, B); // 生成了四个实例, 名字分别为test_module_inst[-1], test_module_inst[0], test_module_inst[1], test_module_inst[2]如果左侧索引和左侧索引相等那么只会生成一个实例如例4所示。// 例4 and and_inst [3: 3] (Y, A, B); // 生成了一个实例, 名字为and_inst[3] test_module test_module_inst [3: 3] (Y, A, B); // 生成了一个实例, 名字为test_module_inst[3]同一个实例标识符只能与一个范围关联以声明实例数组也就是说不能用一个标识符分批实例数组如例5所示。// 例5 and and_inst [3: 0] (Y, A, B); // 生成了四个实例, 名字分别为and_inst[0], and_inst[1], and_inst[2], and_inst[3] and and_inst [5: 4] (Y, A, B); // 错误的 test_module test_module_inst [3: 0] (Y, A, B); // 生成了四个实例, 名字分别为test_module_inst[0], test_module_inst[1], test_module_inst[2], test_module_inst[3] test_module test_module_inst [5: 4] (Y, A, B); // 错误的范围说明是可选的如果没有给出范围说明那么只会创建一个实例且其无需索引普通的实例就是这种情况如例6所示。// 例6 and and_inst (Y, A, B); // 名字可以省略 test_module test_module_inst (Y, A, B);普通模块实例的端口连接在说明实例数组的端口连接前首先复习一下普通模块实例的端口连接如图3所示。图3 普通模块实例的连接规则每个实例的端口可以以命令端口连接或位置端口连接的方式连接到该实例外部的一个端口expression。对于输入端口该端口expression可以是任意的比如一个简单的标量信号、一个矢量信号、一个矢量信号的位选、一个矢量信号的域选、前面各项的加减乘除、前面各项的拼接.....如例7所示。// 例7 module example_module ( input wire [3:0] a, input wire b, input wire c, output wire y ); assign y (a[0] b) | c; endmodule module top_module; wire [3:0] in_vec; wire scalar1, scalar2; wire out; example_module inst3 ( .a({in_vec[2:1], scalar1, scalar2}), .b(in_vec[0] ^ scalar1), .c(in_vec[3] scalar2), .y(out) ); endmodule对于输出端口 该端口expression只能是一个简单的标量线网信号、一个矢量线网信号、一个矢量线网信号的位选、一个矢量线网信号的域选以及前面各项的拼接或者说是一个net_lvalue即能作为一个连续赋值语句(assign)左值的表达式如图4和例8所示。图4 net_lvalue的定义// 例8 module example_module ( input wire [3:0] a, input wire b, input wire c, output wire y_1, y_2, y_3 ); assign y_1 (a[0] b) | c; assign y_2 (a[0] b) | c; assign y_3 (a[0] b) | c; endmodule module top_module; wire [3:0] in_vec; wire scalar1, scalar2; wire out_1, out_2; wire [3:0] out_vec; example_module inst3 ( .a({in_vec[2:1], scalar1, scalar2}), .b(in_vec[0] ^ scalar1), .c(in_vec[3] scalar2), .y_1(out_1out_2), // 错误 .y_2({out_vec[0], out_2}), // 正确但位宽不匹配, 会有警告 .y_3(out_vec[3]) // 正确 ); endmodule当发生连接位宽不匹配时仿真器会产生警告但不会报错因为其实端口连接就相当于使用连续赋值语句(assign)连接外部的端口expression和内部的端口例如上例中的y_2端口相当于assign {out_vec[0], out_2} y_2右侧表达式的位宽为1左侧信号位宽为2因此右侧表达式会被位宽拓展高位补0至2位再进行赋值因此out_vec[0]会被赋值0。有关位宽拓展的相关内容见Verilog基础表达式位宽的确定位宽拓展。门实例的端口连接门实例的端口连接如图5所示。图5 门实例的连接规则对于门实例连接到输出端口的表达式位宽必须是标量这与普通模块实例的端口连接是不同的如例9所示其余的限制与普通模块实例的端口连接相同。// 例9 module gate (output [3:0] Y, input [3:0] A, B); and (Y, A, B); \\ 错误 and (Y[0], A, B); \\ 正确但位宽不匹配 endmodule实例数组的端口连接对于实例数组的端口连接而言首先需要对实例数组中的端口表达式的位宽应该与单个模块实例或门实例中的对应端口的位宽进行比较1、如果实例数组的端口expression的位宽与单个实例的端口的位宽相同那么整个数组的端口expression会连接到每个单个实例的端口如例10所示。// 例10 module and_gate ( input wire [3:0] A, B, output wire [3:0] Y ); assign Y A B; endmodule module and_array ( output [3:0] Y, input [3:0] A, B ); // 实例化4个and_array, 每个都连接到了位宽为4的ABY端口 and_gate and_inst [3:0] ( .A(A), .B(B), .Y(Y) ); endmodule2、如果位宽不同单个实例的端口将从相应的端口expression中根据实例数组大小平均获得域选从右侧索引开始如例11所示。// 例11 module and_gate ( input wire [3:0] A, B, output wire [3:0] Y ); assign Y A B; endmodule module and_array ( output [15:0] Y, input [15:0] A, B ); // 实例化4个and_array, and_inst[0]连接到A[3:0], B[3:0], Y[3:0], and_inst[1]连接到A[7:4], B[7:4], Y[7:4], 以此类推 // 如果声明时使用[0:15], 则and_inst[0]连接到A[12:15], B[12:15], Y[12:15], and_inst[1]连接到A[8:11], B[8:11], Y[8:11], 以此类推 and_gate and_inst [3:0] ( .A(A), .B(B), .Y(Y) ); endmodule3、如果域选结果的位宽与单个实例端口的位宽不匹配将被视为错误这与之前两种实例化不同。这也就代表要么像例10实例数组的端口expression的位宽与单个实例的端口的位宽相同要么像例11实例数组的端口expression的位宽等于单个实例的端口的位宽乘以实例数组大小。最后要说的是在例10和例11中 端口expression都是简单的矢量信号实际上它可以是更加复杂的表达式如例7和例8所示。