verilogHDL.docx
《verilogHDL.docx》由会员分享,可在线阅读,更多相关《verilogHDL.docx(21页珍藏版)》请在冰豆网上搜索。
![verilogHDL.docx](https://file1.bdocx.com/fileroot1/2022-10/28/e5a4afdb-a545-4164-b5ce-00b2ce3e82bb/e5a4afdb-a545-4164-b5ce-00b2ce3e82bb1.gif)
verilogHDL
VerilogHDL语言
2.2层次建模
【例2-3】实现一个1位全加器。
1位全加器的VerilogHDL实现代码如下:
/*以下为全加器顶层模块*/
modulef_adder(ain,bin,cin,cout,sum);
outputcout,sum;
inputain,bin,cin;
wireain,bin,cin,cout,sum;
wired,e,f;
h_adderu0(ain,bin,d,e);
h_adderu1(e,cin,f,sum);
or2au2(d,f,cout);
endmodule
/*以下为半加器模块*/
moduleh_adder(a,b,co,so);
outputco,so;
inputa,b;
wirea,b,co,so,bbar;
andand2(co,a,b);
notnot1(bbar,b);
xnorxnor2(so,a,bbar);
endmodule
/*以下为或门模块*/
moduleor2a(a,b,c);
outputc;
inputa,b;
wirea,b,c;
assignc=a|b;
endmodule
程序说明:
(1)语句assignc=a|b;中,“|”是按位或运算符,其功能是将a与b按位或的结果赋给信号c。
(2)语句wirea,b,c;中,wire是线网数据类型,表示a、b、c是线网,是硬件单元之间的连接。
(3)一个VerilogHDL模块内部的实现方式有多种。
本例中,在或门模块内部使用了数据流语句assign;在半加器模块内部调用了基本逻辑门原语;在全加器模块内部调用了半加器模块和或门模块。
(4)在全加器模块中有两处调用了半加器:
h_adderu0(ain,bin,d,e);和h_adderu1(e,cin,f,sum);。
每次调用均给出一个唯一的实例名,而且调用时端口列表名称不同。
在VerilogHDL设计中,在模块调用的时候,可以按顺序将模块定义的端口与外部环境中的信号连接起来,这种方法称为“按顺序连接”。
h_adderu0(ain,bin,d,e);调用将ain、bin、d、e分别与模块定义中的端口a、b、co、so连接;h_adderu1(e,cin,f,sum);调用将e、cin、f、sum分别与模块定义中的端口a、b、co、so连接。
【例2-4】二选一数据选择器示例。
modulemux21a(a,b,s,y);
inputwirea,b,s;
outputregy;
always@(a,b,s)
if(s==1)y=b;
elsey=a;
endmodule
程序说明:
(1)在模块中,输入端口只能为wire类型,输出端口可以为wire类型,也可以为reg类型。
通常情况下,如果输出端口在always语句中使用,则必须声明为reg类型。
(2) if(s==1)y=b;elsey=a;为条件语句结构,表达的意思是当s为1时y=b,否则y=a。
条件语句只能用在always语句中。
【例2-7】设计参数型N位加法器。
moduleadd_N(X,Y,sum,co);
parameterN=4;
input[N-1:
0]X,Y;
output[N-1:
0]sum;
outputco;
assign{co,sum}=X+Y;
endmodule
//16位加法器只需要调用参数型N位加法器即可
moduleadd_16(X,Y,s,c);
input[15:
0]X,Y;
output[15:
0]s;
outputc;
add_N#(16)add16(X,Y,s,c);
endmodule
//8位加法器只需要调用参数型N位加法器即可
moduleadd_8(X,Y,s,c);
input[7:
0]X,Y;
output[7:
0]s;
outputc;
add_Nadd8(X,Y,s,c);
defparamadd8.N=8;
endmodule
程序说明:
(1)在调用add_N模块时,可用#(16)使参数N的值变为16,从而使模块功能变为16位加法器,具体实现语句为add_N#(16)add16(X,Y,s,c);。
(2)也可以使用defparam来改变参数。
用后缀改变引用模块的参数要用被引用模块的实例名作为参数的前缀,如add8.N=8,从而使被引用模块的功能变为8位加法器。
具体实现语句为:
add_Nadd8(X,Y,s,c);defparamadd8.N=8;。
通过使用参数,用户可以更加灵活地对模块进行说明。
用户不但可以根据参数来定义模块,还可以方便地通过参数值重定义来改变模块的行为。
3.3数据流级建模
连续赋值语句:
以关键词assign开始的语句为连续赋值语句,连续赋值语句是Verilog数据流建模的基本语句,用于对线网进行赋值。
【例3-10】使用数据流建模,实现一位半加器。
moduleadder_half(ain,bin,sum,co);
inputain,bin;
outputsum,co;
assign{co,sum}=ain+bin;
endmodule
程序说明:
(1) assign{co,sum}=ain+bin;是一条连续赋值语句,它将ain和bin的和存放在{co,sum}中。
该语句中,“{}”为位拼接符,其功能是将co和sum拼接成一个两位的数。
(2)连续赋值语句的左边必须是一个标量或向量线网,或者是标量或向量线网的拼接,而不能是任何形式的寄存器。
例如下面的形式是非法的:
regsum;
assign{co,sum}=ain+bin;//非法,sum不能为寄存器类型
【例3-9】表示时序逻辑的UDP举例:
D触发器。
primitived_edge_ff(q,clk,data);
outputq;
inputclk,data;
regq;
table//clkdatstatenext
(01)0:
?
:
0;
(01)1:
?
:
1;
//时钟下降沿
(?
0)?
:
?
:
-;
//时钟稳定时忽略data的变化
?
(?
?
):
?
:
-;
endtable
endprimitive
程序说明:
(1)使用QuartusⅡ软件综合的结果如图3-9所示。
从综合结果可以看出,该设计实现了一个D触发器。
(2)程序中的“?
”表示逻辑值可以为0、1或x。
(3)端口列表中的第一个端口q为输出端口,其余为输入端口。
3.4行 为 级 建 模
结构化过程语句always:
always语句是行为建模的基本语句,每个always语句代表一个独立的执行过程,也称为进程。
与C语言不同,VerilogHDL的各个always进程是并发执行的,而不是顺序执行的。
过程赋值语句:
VerilogHDL包括两种类型的过程赋值语句:
阻塞赋值语句和非阻塞赋值语句。
【例3-15】使用always语句描述D触发器。
modulemydff(q,clk,d);
inputclk,d;
outputq;regq;
always@(posedgeclk)
q<=d;
endmodule
程序说明:
(1)本程序的功能是在时钟上升沿时刻,将数据d赋予触发器输出q,其功能同D触发器一样。
(2) always语句由于其不断重复执行的特性,只有和一定的时序控制结合在一起才有用。
always@(posedgeclk)语句表示只有在clk上升沿时才开始执行always语句块,否则不执行。
这种时序控制是always语句最常用的。
(3) always的时序控制除沿触发时序控制外,还可以是电平触发的,也可以是单个信号或多个信号,中间需要用关键字or或“,”连接,如:
always@(posedgeclockorposedgereset)//由两个沿触发的always块
begin
…
end
always@(aorborc)//由多个电平触发的always块
begin
…
end
沿触发的always块常用来描述时序逻辑,如果符合可综合风格要求,则可用综合工具将其自动转换为表示时序逻辑的寄存器组和门级逻辑;而电平触发的always块常用来描述一般组合逻辑和带锁存器的组合逻辑,如果符合可综合风格要求,则可转换为表示组合逻辑的门级逻辑或带锁存器的组合逻辑。
一个模块中可以有多个always块,它们都是并行运行的。
从综合结果来看,本例实现了一个上升沿触发的D触发器。
【例3-16】阻塞赋值方式描述的移位寄存器1。
moduleblock1(Q0,Q1,Q2,D,clk);
outputQ0,Q1,Q2;
inputclk,D;
regQ0,Q1,Q2;
always@(posedgeclk)
begin
Q2=Q1;//注意赋值语句的顺序
Q1=Q0;
Q0=D;
end
endmodule
综合结果如图3-13所示。
【例3-17】阻塞赋值方式描述的移位寄存器2。
moduleblock2(Q0,Q1,Q2,D,clk);
outputQ0,Q1,Q2;
inputclk,D;
regQ0,Q1,Q2;
always@(posedgeclk)
begin
Q1=Q0;//该句与下句的顺序与例3-16颠倒
Q2=Q1;
Q0=D;
end
endmodule
综合结果如图3-14所示。
【例3-18】阻塞赋值方式描述的移位寄存器3。
moduleblock3(Q0,Q1,Q2,D,clk);
outputQ0,Q1,Q2;
inputclk,D;
regQ0,Q1,Q2;
always@(posedgeclk)
begin
Q0=D;//3条赋值语句的顺序与例3-16完全颠倒
Q1=Q0;
Q2=Q1;
end
endmodule
综合结果如图3-15所示。
【例3-19】非阻塞赋值方式描述的移位寄存器1。
modulenon_block1(Q0,Q1,Q2,D,clk);
outputQ0,Q1,Q2;
inputclk,D;
regQ0,Q1,Q2;
always@(posedgeclk)
begin
Q1<=Q0;
Q2<=Q1;
Q0<=D;
end
Endmodule
【例3-20】非阻塞赋值方式描述的移位寄存器2。
modulenon_block2(Q0,Q1,Q2,D,clk);
outputQ0,Q1,Q2;
inputclk,D;
regQ0,Q1,Q2;
always@(posedgeclk)
begin
Q0<=D;//3条赋值语句的顺序与例3-19完全颠倒
Q2<=Q1;