1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
| 结构建模 verilog HDL中的结构建模风格,结构建模风格用以下3种 Gate实例引用语句 UDP实例引用语句 or and xor module 实例应用语句 模块 在Verilog HDL种,一个模块定义了一个基本单元,格式 module module_name(port_list); Declarations_and_Statements endmodule 端口列表(port_list)列出了该模块与外部模块进行通信的端口。 端口 模块的端口可以被声明为输入、输出、双向端口。端口的默认类型为线网类型(即wire类型),也可以明确地把端口声明为线网类型。在声明端口后,可在模块内将输出端口再次声明为reg变量类型。无论是在线网声明还是变量声明中,线网 变量必须与端口声明中指定的位宽一致。 端口声明还可以直接放在端口列表中而不放在模块内部,这样的端口声明风格称为模块端口声明风格 模块端口列表风格(端口声明放在模块内部)。 模块端口声明风格 module ( input wire[3:0] prog_ctr, output wire[1:0]instr_reg, inout wire [15:0]next_addr );
endmodule 端口在端口列表中被声明,那么就不能在模块内部重新声明。端口还可以被进一步限定为寄存器类型(reg)端口 、有符号类型(signed)端口。 module remap_ctrl( input[31:0]rpc_addr, input signed[31:0]rpc_rdata, output reg remap,ready, output reg signed [31:0]rpc_wdata ); endmodule 所有端口都是用逗号隔开,共用同一个声明的多个端口 参数端口 除了可以在模块内部声明参数外,还可以用端口列表的风格来声明参数。 module module_name #(parameter param1 = value1,param2 = value2,..., parameter param3 = value3) (port_list); ... endmodule 在参数声明中可以选择 指定参数的位宽以及符号。 module sspm #(parameter SIZE = 6,WIDTH = 8, parameter [WIDTH-1:0]HOLD_VALUE = 56, parameter DUMP_FILE = "dump.rpt") (input chip_select,read_write, output [WIDTH-1:0]data); ... endmodule 若每一个实例引用语句中的参数都一样,换言之,参数值不是由实例引用语句来指定的,则参数应该被声明为局部参数。 否则参数既可以在模块内部声明,也可以在参数端口中声明。 模块实例引用: 按照位置排列的连接 按照名称的连接 连接类型:标识符(变量 线网)、位选择、部分选择、上述类型的拼接、表达式(只适用于输入端口) 未连接的端口 实例引用语句中,若端口表达式的位置为空白,就将该端口指定为未连接的端口。 例子 df u0df(.q(qs), .qb(), .cock(ck), .qd() ); df u1df(qs, ,ck,,); 模块未连接输入端的值被设置为z。模块未连接的输出端只是表示该输出端口没有被使用。 不同的端口位宽 在端口和端口表达式之间存在着一种隐含的连续赋值的关系。 因此当端口和端口表达式的位宽不一致时,会进行端口匹配,采用的位宽匹配规则与连续赋值时使用的规则相同。 module child(psa,ppy); input [5:0]psa; output [2:0]ppy; ... endmodule module top; wire [1:2] bdl; wire [2:6] mpr; child u6child( .psa(bdl), .ppy(mpr) ); endmodule 模块child的实例引用语句中,存在两个隐含的连续赋值。 psa是输入端口,所以从端口表达式往端口进行赋值 assign psa = bdl; ppy是输出端口,所以从端口往端口表达式进行赋值 assign mpr = ppy; bdl[2]->psa[0],bdl[1]->psa[1]。psa[5] psa[4] psa[3] psa[2] 未连接,因此值为z mpr[6]<-ppy[0],mpr[5]<-ppy[1],mpr[4]<-ppy[2] 模块参数值 一个模块在另一个模块的内部被实例引用时,较高层次的模块能够改变较低层次模块参数的参数值。用以下两种途径可以改变模块实例的参数: 1.使用定义参数语句(defparam语句)修改参数值 2.在模块实例引用中修改参数值 1.定义参数语句 定义参数语句的格式如下: defparam hier_path1 = value1, hier_path2 = value2,...; 在较低层次模块中的参数层次路径明可以使用如下这样一条语句清晰地矛以设置(层次路径名), module top (tpa,tpd,tps,tpc); input tpa,tpd; output tps,tpc; defparam u5ha.XOR_DELAY = 5, u5ha.AND_DELAY = 2; half_adder u5ha(tpa,tpb,tps,tpc); endmodule module top2(tp2p,tp2q,tp2cin,tp2sum.tp2cont); input tp2p,tp2q,tp2cin; output tp2sum,tp2cout; defparam u8fa.u1ha.XOR_DELAY = 2, u8fa.u1ha.AND_DELAY = 3, u8fa.OR_DELAY = 3; full_adder u8fa(tp2p,tp2q,tp2cin,tp2sum,tp2cout); endmodule 模块实例引用中修改参数值 模块实例的本身就能指定新的参数值,模块实例引用语句可采用以下两种风格来指定实例中的参数值: (1)按照位置来赋对应的参数值(位置关联):第1个值对应于模块中声明的第1个参数,第2个值对应于模块中声明的第2个参数,依此类推 (2)按照名称来赋对应的参数值(名称关联):参数的名称和值都被明确地标出。因此参数地顺序并不重要,从而可以按照任意顺序来传递参数。更重要的是,不是所有的参数值都必须明确的标出 下面功能一样 module top3(tp3a,tp3d,tp3s,tp3c); input tp3a,tp3d; output tp3s,tp3c; half_adder #(5,2) u4ha(tp3a,tp3d,tp3s,tp3c); half_adder #(.AND_DELAY(5),.XOR_DELAY(2)) u12ha(tp3a,tp3d,tp3s,tp3c); endmodule module top4(tp4p,tp4q,tp4cin,tp4sum.tp4cont); input tp4p,tp4q,tp4cin; output tp4sum,tp4cont; defparam u22fa.u1ha.XOR_DELAY = 2, u22fa.u1ha.AND_DELAY = 3; full_adder #(3) u22fa(tp4p,tp4q,tp4cin,tp4sum.tp4cont); endmodule 按照位置来赋参数值时,模块实例引用语句中的参数值顺序必须于与参数在被引用的底层模块中被声明的顺序一致。在模块top3中的半加器实例u4ha中,AND_DELAY 设置5 ,XOR_DELAY 设置 2。 模块top3 和top4 的解释说明了用带参数值的模块实例引用语句只能将参数值向下传递一个层次(例如 OR_DELAY),但是用参数定义语句能够修改任意层次的参数值。 注意:在带参数值的模块实例引用语句中,指定参数值位置的标记符与门级实例引用语句中定义延时的位置标记符相似。 外部端口 模块定义中,端口列表举出了模块外部可见的端口 module scram_a(arb,ctrl,mem_blk,byte); input [0:3] arb; input ctrl; input [8:0]mem_blk; output [0:3]byte; ... endmodule arb、ctrl、mem_blk、byte 为这个模块的端口。这些端口同时也是外部端口,即在实例引用中,当采用按照名称 在模块定义的端口列表中,这两种风格可以混合使用,换言之,在模块定义中允许只有部分端口拥有外部端口名称。 如果模块端口是按位置对应关系进行连接的,则模块实例应用语句中不能使用外部端口名称。(端口名称不能与模块实例名相同) 内部端口名称不经可以是标识符,也可以是下面类型的表达式之一: 位选择;部分选择 位选择、部分选择和标识符的拼接项。 下面举例说明: module scram_c( arb[0:2],ctrl, {mem_blk[0],mem_blk[1]},byte[3] ); input [0:3] arb; input ctrl; input [8:0]mem_blk; output [0:3]byte; ... endmodule 在scram_c模块的定义中,端口列表中包括部分选择(arb[0:2])、标识符(ctrl)、拼接项({mem_blk[0],mem_blk[1]})和位选择(byte[3])。在外部端口是位选择、部分选择、拼接项的情况下,不能隐式地指定外部端口的名称。因为若这样定义模块端口的话,在模块实例引用语句中,模块端口必须按位置对应关系才能进行互连, 示例 scram_c u_scram_c( cab[4:6],ram_ctl,mmy[1:0],tcb ); 这个实例引用语句中,端口按照位置对应关系来进行互连;因此,cab[4:6]连接到arb[0:2],ram_ctl连接到ctrl,mmy[1]连接到mem_blk[0],mmy[0]连接到mem_blk[1],tcb连接到byte[3]。arb[3] mem_blk[8:2]没有连接到任何信号,因此这些输入信号将被赋予默认值Z 当内部端口信号与外部连接所需要的表示信号的位宽不完全一致时,若想要使用按名称对应关系连接,(内部端口并不所有信号需要与外部连接时,但是又要按名称对应关系连接,采用方式)则必须为模块内部的端口明确地指定外部端口名称。 如下 module scram_d( .data(arb[0:2]), .control(ctrl), .mem_word(mem_blk[0],mem_blk[1]), .addr(byte[3]) ); input [0:3]arb; input ctrl; input[0:8]mem_blk; output [0:3]byte; ... endmodule 在模块scram_d的实例引用语句中,端口既能够按位置对应关系,也能够按名称对应关系连接,但是不能混合使用。 按名称对应关系连接的实例引用语句。 scram_d u_scram_d( .data(cab[4:6]),.control(ram_ctrl), .mem_word(mmy[1:0]),.addr(tcb) ); 模块也可以只有外部端口而没有相应的内部端口。例如: module scram_e( .data ,.control(ctrl), .mem_word({mem_blk[0],mem_blk[1]}),.addr() ); input ctrl; input [8:0]mem_blk; ... endmodule 模块scram_e有两个外部端口data、addr 没有与模块内部的任何信号相连。 一个内部端口是否能与多个外部端口相连? Verilog HDL 允许一个内部端口与多个外部端口相连。例: module fan_out( .a(ctrl_in),.b(cond_out),.c(cond_out) ); input ctrl_in; output cond_out; assign cond_out = ctrl_in; endmodule 内部端口cond_out与两个外部端口b和c相连。因此在b和c上都将出现cond_out的值。 module ssp_ctrl( .wdata({write_bus[15:12],write_bus[3:0]}) ); input [15:0]write_bus; endmodule module top_ssp_ctrl; reg [7:0] ssp_select; ssp_ctrl u_ssp_ctrl(.wdata(ssp_select)); endmodule 上面描述模块ssp_ctrl的外部端口名称是wdata,而模块top_ssp_ctrl有选择性地把ssp_select的8个位依次连接到write_bus[15:12] 和 write_bus[3:0] 上。
|