在一个模块中引用另一个模块,对其端口进行相关连接,叫做模块例化。模块例化建立了描述的层次。信号端口可以通过位置或名称关联,端口连接也必须遵循一些规则。
命名端口连接
这种方法将需要例化的模块端口与外部信号按照其名字进行连接,端口顺序随意,可以与引用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)
--两位十进制计数器?每位十进制数用4-bit表示,即CQ?CQ在程序中没有输出啊!--原程序修改
library IEEE
use IEEE.STD_LOGIC_1164.ALL
use IEEE.STD_LOGIC_ARITH.ALL
use IEEE.STD_LOGIC_UNSIGNED.ALL
ENTITY CNT10 IS
PORT (CLK,RST,EN : IN STD_LOGIC
CQ: OUT STD_LOGIC_VECTOR(3 DOWNTO 0)
COUT: OUT STD_LOGIC )
END CNT10
ARCHITECTURE behav OF CNT10 IS
BEGIN
PROCESS(CLK, RST, EN) -----EN是同步的,这边不需要列出???????
VARIABLE CQI : STD_LOGIC_VECTOR(3 DOWNTO 0):=(others>'0')
--???初值为0才好。
BEGIN
IF RST = '1' THEN
CQI := (OTHERS =>'0') --计数器异步复位
ELSIF CLK'EVENT AND CLK='1' THEN --检测时钟上升沿
IF EN = '1' THEN--检测是否允许计数(同步使能)
IF CQI <3 THEN -------------<9?有疑问的。
CQI := CQI + 1 --允许计数, 检测是否小于9
ELSE
CQI := (OTHERS =>'0')
END IF --大于9,计数值清零
ELSE
CQI := (OTHERS =>'0')--------??不允许计数就清零?
--- CQ1 := CQ1------上一句注释掉???或者这个else部分去掉。
END IF
END IF
CQ <= CQ1--------????后加的。
-----这部分合到上面EN下面,貌似也可以。?????
IF CQI = 2 THEN --=2?????有疑问的。
COUT <= '1' --计数大于9,输出进位信号
ELSE
COUT <= '0'
END IF
END PROCESS
END behav
-------例化部分程序,信号都没有声明
architecture beh of CNT10_TOP is
--元件声明cnt10
begin
--例化1--个位数
cnt10_inst1 : CNT10
port map(
CLK=>clk,
RST=>rst,
EN=>en,
CQ=>cq_1,
COUT=>cout1------------------AAAA主要是这
)
--例化2--十位数
cnt10_inst2 : CNT10
port map(
CLK=>clk,
RST=>rst,
EN=>cout1,--------------------AAAA主要是这
CQ=>cq_2,
COUT=>cout2
)
end beh
六进制计数器源程序cnt6.vhd:LIBRARY IEEEUSE IEEE.STD_LOGIC_1164.ALLUSE IEEE.STD_LOGIC_UNSIGNED.ALLENTITY CNT6 ISPORT (CLK,CLRN,ENA,LDN:IN STD_LOGICD:IN STD_LOGIC_VECTOR(3 DOWNTO 0)Q:OUT STD_LOGIC...欢迎分享,转载请注明来源:内存溢出
评论列表(0条)