Verilog HDL 语言
2.2 层 次 建 模
【例2-3】 实现一个1位全加器。
1位全加器的Verilog HDL实现代码如下: /*以下为全加器顶层模块*/
module f_adder(ain,bin,cin,cout,sum); output cout,sum; input ain,bin,cin;
wire ain,bin,cin,cout,sum; wire d,e,f;
h_adder u0(ain,bin,d,e); h_adder u1(e,cin,f,sum); or2a u2(d,f,cout); endmodule
/*以下为半加器模块*/ module h_adder(a,b,co,so); output co,so; input a,b;
wire a,b,co,so,bbar; and and2(co,a,b); not not1(bbar,b);
xnor xnor2(so,a,bbar); endmodule
/*以下为或门模块*/ module or2a(a,b,c); output c; input a,b; wire a,b,c; assign c=a | b; endmodule 程序说明:
(1) 语句assign c=a | b; 中,“|”是按位或运算符,其功能是将a与b按位或的结果赋给信号c。
(2) 语句wire a,b,c; 中,wire是线网数据类型,表示a、b、c是线网,是硬件单元之间的连接。
(3) 一个Verilog HDL模块内部的实现方式有多种。本例中,在或门模块内部使用了数据流语句assign;在半加器模块内部调用了基本逻辑门原语;在全加器模块内部调用了半加器模块和或门模块。
(4) 在全加器模块中有两处调用了半加器:h_adder u0(ain,bin,d,e);和h_adder u1(e,cin,f,sum);。每次调用均给出一个唯一的实例名,而且调用时端口列表名称不同。在Verilog HDL设计中,在模块调用的时候,可以按顺序将模块定义的端口与外部环境中的信号连接起来,这种方法称为“按顺序连接”。h_adder u0(ain,bin,d,e);调用将ain、bin、d、e分别与模块定义中的端口a、b、co、so连接;h_adder u1(e,cin,f,sum);调用将e、cin、f、sum
分别与模块定义中的端口a、b、co、so连接。 【例2-4】 二选一数据选择器示例。 module mux21a(a,b,s,y); input wire a,b,s; output reg y; always @(a,b,s) if(s==1) y=b; else y=a;
endmodule 程序说明:
(1) 在模块中,输入端口只能为wire类型,输出端口可以为wire类型,也可以为reg类型。通常情况下,如果输出端口在always语句中使用,则必须声明为reg类型。
(2) if(s==1) y=b; else y=a;为条件语句结构,表达的意思是当s为1时y=b,否则y=a。条件语句只能用在always语句中。 【例2-7】 设计参数型N位加法器。
module add_N( X, Y, sum, co); parameter N=4; input [N-1: 0] X, Y; output [N-1: 0] sum; output co;
assign { co, sum } = X + Y; endmodule
//16位加法器只需要调用参数型N位加法器即可 module add_16(X, Y, s, c); input [15 : 0] X, Y; output [15 : 0] s; output c;
add_N #(16) add16(X, Y, s, c); endmodule
//8位加法器只需要调用参数型N位加法器即可 module add_8(X, Y, s, c); input [7 : 0] X, Y; output [7 : 0] s; output c;
add_N add8(X, Y, s, c); defparam add8.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_N add8(X, Y, s, c); defparam add8.N=8;。
通过使用参数,用户可以更加灵活地对模块进行说明。用户不但可以根据参数来定义模块,还可以方便地通过参数值重定义来改变模块的行为。
3.3 数据流级建模
连续赋值语句:以关键词assign开始的语句为连续赋值语句,连续赋值语句是Verilog数据流建模的基本语句,用于对线网进行赋值。 【例3-10】 使用数据流建模,实现一位半加器。
module adder_half(ain,bin,sum,co); input ain,bin; output sum,co;
assign {co,sum}= ain+bin; endmodule 程序说明: (1) assign {co,sum}= ain+bin; 是一条连续赋值语句,它将ain和bin的和存放在{co,sum}中。该语句中,“{ }”为位拼接符,其功能是将co和sum拼接成一个两位的数。
(2) 连续赋值语句的左边必须是一个标量或向量线网,或者是标量或向量线网的拼接,而不能是任何形式的寄存器。例如下面的形式是非法的:
reg sum;
assign {co,sum}= ain+bin; //非法,sum不能为寄存器类型 【例3-9】 表示时序逻辑的UDP举例:D触发器。
primitive d_edge_ff (q, clk, data); output q;
input clk, data; reg q;
table // clk dat state next (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语言不同,Verilog HDL的各个always进程是并发执行的,而不是顺序执行的。
过程赋值语句:Verilog HDL包括两种类型的过程赋值语句:阻塞赋值语句和非阻塞赋值语句。
【例3-15】 使用always语句描述D触发器。 module mydff(q, clk, d); input clk, d;
output q; reg q;
always @(posedge clk) q<=d; endmodule 程序说明:
(1) 本程序的功能是在时钟上升沿时刻,将数据d赋予触发器输出q,其功能同D触发器一样。
(2) always语句由于其不断重复执行的特性,只有和一定的时序控制结合在一起才有用。always @(posedge clk)语句表示只有在clk上升沿时才开始执行always语句块,否则不执行。这种时序控制是always语句最常用的。
(3) always 的时序控制除沿触发时序控制外,还可以是电平触发的,也可以是单个信号或多个信号,中间需要用关键字or 或“,”连接,如:
always @(posedge clock or posedge reset) //由两个沿触发的always块 begin ? end
always @( a or b or c ) //由多个电平触发的always块 begin ? end
沿触发的always块常用来描述时序逻辑,如果符合可综合风格要求,则可用综合工具将其自动转换为表示时序逻辑的寄存器组和门级逻辑;而电平触发的always块常用来描述一般组合逻辑和带锁存器的组合逻辑,如果符合可综合风格要求,则可转换为表示组合逻辑的门级逻辑或带锁存器的组合逻辑。一个模块中可以有多个always块,它们都是并行运行的。从综合结果来看,本例实现了一个上升沿触发的D触发器。 【例3-16】 阻塞赋值方式描述的移位寄存器1。 module block1(Q0,Q1,Q2,D,clk); output Q0,Q1,Q2; input clk,D; reg Q0,Q1,Q2;
always @(posedge clk) begin
Q2=Q1; //注意赋值语句的顺序 Q1=Q0; Q0=D; end endmodule
综合结果如图3-13所示。
【例3-17】 阻塞赋值方式描述的移位寄存器2。 module block2(Q0,Q1,Q2,D,clk); output Q0,Q1,Q2; input clk,D; reg Q0,Q1,Q2;
always @(posedge clk) begin
Q1=Q0; //该句与下句的顺序与例3-16颠倒 Q2=Q1; Q0=D; end endmodule
综合结果如图3-14所示。
【例3-18】 阻塞赋值方式描述的移位寄存器3。 module block3(Q0,Q1,Q2,D,clk); output Q0,Q1,Q2; input clk,D; reg Q0,Q1,Q2;
always @(posedge clk) begin
Q0=D; //3条赋值语句的顺序与例3-16完全颠倒 Q1=Q0; Q2=Q1; end endmodule
综合结果如图3-15所示。
【例3-19】 非阻塞赋值方式描述的移位寄存器1。 module non_block1(Q0,Q1,Q2,D,clk);
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库verilog HDL在线全文阅读。
相关推荐: