例化语句的设计步骤?

例化语句的设计步骤?,第1张

在一个模块中引用另一个模块,对其端口进行相关连接,叫做模块例化。模块例化建立了描述的层次。信号端口可以通过位置或名称关联,端口连接也必须遵循一些规则。

命名端口连接

这种方法将需要例化的模块端口与外部信号按照其名字进行连接,端口顺序随意,可以与引用module的声明端口顺序不一致,只要保证端口名字与外部信号匹配即可。

下面是例化一次1bit全加器的例子:

实例

full_adder1u_adder0(

.Ai(a[0]),

.Bi(b[0]),

.Ci(c==1'b1?1'b0:1'b1),

.So(so_bit0),

.Co(co_temp[0]))

如果某些输出端口并不需要在外部连接,例化时可以悬空不连接,甚至删除。一般来说,input端口在例化时不能删除,否则编译报错,output端口在例化时可以删除。例如:

实例

//output端口Co悬空

full_adder1u_adder0(

.Ai(a[0]),

.Bi(b[0]),

.Ci(c==1'b1?1'b0:1'b1),

.So(so_bit0),

.Co())

//output端口Co删除

full_adder1u_adder0(

.Ai(a[0]),

.Bi(b[0]),

.Ci(c==1'b1?1'b0:1'b1),

.So(so_bit0))

顺序端口连接

这种方法将需要例化的模块端口按照模块声明时端口的顺序与外部信号进行匹配连接,位置要严格保持一致。例如例化一次1bit全加器的代码可以改为:

full_adder1u_adder1(

a[1],b[1],co_temp[0],so_bit1,co_temp[1])

虽然代码从书写上可能会占用相对较少的空间,但代码可读性降低,也不易于调试。有时候在大型的设计中可能会有很多个端口,端口信号的顺序时不时的可能也会有所改动,此时再利用顺序端口连接进行模块例化,显然是不方便的。所以平时,建议采用命名端口方式对模块进行例化。

端口连接规则

输入端口

模块例化时,从模块外部来讲,input端口可以连接wire或reg型变量。这与模块声明是不同的,从模块内部来讲,input端口必须是wire型变量。

输出端口

模块例化时,从模块外部来讲,output端口必须连接wire型变量。这与模块声明是不同的,从模块内部来讲,output端口可以是wire或reg型变量。

输入输出端口

模块例化时,从模块外部来讲,inout端口必须连接wire型变量。这与模块声明是相同的。

悬空端口

模块例化时,如果某些信号不需要与外部信号进行连接交互,我们可以将其悬空,即端口例化处保留空白即可,上述例子中有提及。

output端口正常悬空时,我们甚至可以在例化时将其删除。

input端口正常悬空时,悬空信号的逻辑功能表现为高阻状态(逻辑值为z)。但是,例化时一般不能将悬空的input端口删除,否则编译会报错,例如:

实例

//下述代码编译会报Warning

full_adder4u_adder4(

.a(a),

.b(b),

.c(),

.so(so),

.co(co))

实例

//如果模块full_adder4有input端口c,则下述代码编译是会报Error

full_adder4u_adder4(

.a(a),

.b(b),

.so(so),

.co(co))

一般来说,建议input端口不要做悬空处理,无其他外部连接时赋值其常量,例如:

实例

full_adder4u_adder4(

.a(a),

.b(b),

.c(1'b0),

.so(so),

.co(co))

位宽匹配

当例化端口与连续信号位宽不匹配时,端口会通过无符号数的右对齐或截断方式进行匹配。

假如在模块full_adder4中,端口a和端口b的位宽都为4bit,则下面代码的例化结果会导致:u_adder4.a={2'bzz,a[1:0]},u_adder4.b=b[3:0]。

实例

full_adder4u_adder4(

.a(a[1:0]),//inputa[3:0]

.b(b[5:0]),//inputb[3:0]

.c(1'b0),

.so(so),

.co(co))

端口连续信号类型

连接端口的信号类型可以是,1)标识符,2)位选择,3)部分选择,4)上述类型的合并,5)用于输入端口的表达式。

当然,信号名字可以与端口名字一样,但他们的意义是不一样的,分别代表的是2个模块内的信号。

用generate进行模块例化

当例化多个相同的模块时,一个一个的手动例化会比较繁琐。用generate语句进行多个模块的重复例化,可大大简化程序的编写过程。

重复例化4个1bit全加器组成一个4bit全加器的代码如下:

实例

modulefull_adder4(

input[3:0]a,//adder1

input[3:0]b,//adder2

inputc,//inputcarrybit

output[3:0]so,//addingresult

outputco//outputcarrybit

)

wire[3:0]co_temp

//第一个例化模块一般格式有所差异,需要单独例化

full_adder1u_adder0(

.Ai(a[0]),

.Bi(b[0]),

.Ci(c==1'b1?1'b1:1'b0),

.So(so[0]),

.Co(co_temp[0]))

genvari

generate

for(i=1i<=3i=i+1)begin:adder_gen

full_adder1u_adder(

.Ai(a[i]),

.Bi(b[i]),

.Ci(co_temp[i-1]),//上一个全加器的溢位是下一个的进位

.So(so[i]),

.Co(co_temp[i]))

end

endgenerate

assignco=co_temp[3]

endmodule

testbench如下:

实例

`timescale1ns/1ns

moduletest

reg[3:0]a

reg[3:0]b

//regc

wire[3:0]so

wireco

//简单驱动

initialbegin

a=4'd5

b=4'd2

#10

a=4'd10

b=4'd8

end

full_adder4u_adder4(

.a(a),

.b(b),

.c(1'b0),//端口可以连接常量

.so(so),

.co(co))

initialbegin

foreverbegin

#100

if($time>=1000)$finish

end

end

endmodule//test

仿真结果如下,可知4bit全加器工作正常:

层次访问

每一个例化模块的名字,每个模块的信号变量等,都使用一个特定的标识符进行定义。在整个层次设计中,每个标识符都具有唯一的位置与名字。

Verilog中,通过使用一连串的.符号对各个模块的标识符进行层次分隔连接,就可以在任何地方通过指定完整的层次名对整个设计中的标识符进行访问。

层次访问多见于仿真中。

例如,有以下层次设计,则叶单元、子模块和顶层模块间的信号就可以相互访问。

实例

//u_n1模块中访问u_n3模块信号:

a=top.u_m2.u_n3.c

//u_n1模块中访问top模块信号

if(top.p=='b0)a=1'b1

//top模块中访问u_n4模块信号

assignp=top.u_m2.u_n4.d

前面章节的仿真中,或多或少的也进行过相关的层次访问。例如《过程连续赋值》一节中,在顶层仿真激励test模块中使用了如下语句:

wait(test.u_counter.cnt_temp==4'd4)

模块化的概念并不新鲜,其实很早就接触了模块化思想,知道很多行业都有预制的东西,比如建筑上的标准件,预制板都可以看成模块。机动车上的发动机变速箱和车轮也可以看成是模块化。

因此可以把编程中一些常见功能制作成模板,也就是对象或控件,以方便其他人员使用,这就是模块化程序设计。

结构化程序设计的概念是E.W.Dijkstra在60年代末提出的,其实质是控制编程中的复杂性。结构化程序设计曾被称为软件发展中的第三个里程碑。

扩展资料:

模块的独立性原则表现在模块完成独立的功能,与其他模块的联系应该尽可能得简单,各个模块具有相对的独立性。

模块的规模不能太大,也不能太小。如果模块的功能太强,可读性就会较差,若模块的功能太弱,就会有很多的接口。读者需要通过较多的程序设计来进行经验的积累。

在进行多层次任务分解时,要注意对问题进行抽象化。在分解初期,可以只考虑大的模块,在中期,再逐步进行细化,分解成较小的模块进行设计。

参考资料来源:百度百科-模块化程序设计


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8162918.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-14
下一篇 2023-04-14

发表评论

登录后才能评论

评论列表(0条)

保存