verilog HDL

更新时间:2024-07-02 15:12:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

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);

output Q0,Q1,Q2; input clk,D; reg Q0,Q1,Q2;

always @(posedge clk) begin Q1<=Q0; Q2<=Q1; Q0<=D; end

E ndmodule

【例3-20】 非阻塞赋值方式描述的移位寄存器2。 module non_block2(Q0,Q1,Q2,D,clk); output Q0,Q1,Q2; input clk,D; reg Q0,Q1,Q2;

always @(posedge clk) begin

Q0<=D; //3条赋值语句的顺序与例3-19完全颠倒 Q2<=Q1; Q1<=Q0; end endmodule

例3-16~例3-20的程序说明: (1) 5个例题的设计目标均是实现3位移位寄存器,但从综合结果可以看出例3-17和例3-18没有实现设计目标。

(2) Q2=Q1; 这种赋值方式称为阻塞赋值,Q2的值在赋值语句执行完成后立刻就改变,而且随后的语句必须在赋值语句执行完成后才能继续执行。所以当例3-18中的三条语句Q0=D; Q1=Q0; Q2=Q1; 执行完后,Q0、Q1、Q2的值都变化为D的值,也就是说,D的值同时赋给了Q0、Q1、Q2,参照其综合结果能更清晰地看到这一点。例3-16和例3-17可通过同样的分析得出与综合结果一致的结论。

(3) Q2<=Q1; 这种赋值方式称为非阻塞赋值,Q2的值在赋值语句执行完后并不会立刻就改变,而是等到整个always语句块结束后才完成赋值操作。所以当例3-20中的三条语句Q0<=D; Q2<=Q1;Q1<=Q0;执行完后,Q0、Q1、Q2的值并没有立刻更新,而是保持了原来的值,直到always语句块结束后才同时进行赋值,因此Q0的值变为了D的值,Q2的值变为了原来Q1的值,Q1的值变为了原来Q0的值(而不是刚刚更新的Q0的值D),参照其综

合结果能更清晰地看到这一点。例3-19可通过同样的分析得出与综合结果一致的结论。 (4) 例3-16~例3-18采用的是阻塞赋值方式,可以看出阻塞赋值语句在always块语句中的位置对其结果有影响;例3-19和例3-20采用的是非阻塞赋值方式,可以看出非阻塞赋值语句在always块语句中的位置对其结果没有影响。因此,在使用赋值语句时要注意两者的区别与联系。

【例3-22】 使用always语句描述具有同步复位和同步置位功能的D触发器。 module my_dff(q, clk, set, clr, d); input clk, d, set, clr; output q; reg q;

always @(posedge clk) begin if(set)

q<=1; else if (!clr) q<=0; else q<=d; end endmodule

程序说明:

(1) 本程序使用了第3种if语句形式:if?else if?else的条件语句,在时钟上升沿时刻,首先判断置位信号set是否有效,若有效则将D触发器输出置1,否则判断复位信号clr是否有效,若有效则将D触发器输出置0,否则将数据d赋予D触发器输出。 (2) if(set)等同于if(set==1),else if (!clr)等同于if(clr!=1),Verilog HDL允许采用这样的表达式简写方式。

(3) always @(posedge clk)语句表示只有在clk上升沿时才开始执行always语句块,否则不执行。所以,D触发器置位和复位为同步置位和同步复位。

1. 加法器

例4-3实现了N位加法器。

【例4-3】 参数型N位加法器。 module add_N( X, Y, sum, co); parameter N=8; input [N-1: 0] X, Y; output [N-1: 0] sum; output co;

assign { co, sum } = X + Y;

endmodule 程序说明:

(1) 程序中,X和Y分别为加数和被加数,sum和co分别为本位和及进位。

(2) 本例使用数据流建模实现,在综合时会自动映射为Quartus Ⅱ自带的加法器宏功能模块。

【例4-12】 一位D触发器。 实现方式一:

module my_dff(clk, d, q); input clk; input d;

output reg q;

always @(posedge clk) q <= d; endmodule

实现方式二:调用Quartus Ⅱ软件中的dff模块实现D触发器。 module my_dff(clk, d, q); input clk; input d; output q;

dff my_dff(d, clk, , , q); endmodule

2. 寄存器

【例4-13】 参数型n位寄存器。

(1) 一般寄存器。

module regx(clk, d, q); parameter N=8; input clk;

input[N-1:0] d;

output reg[N-1:0] q; always @(posedge clk) q <= d; endmodule

(2) 同步复位、同步置数、异步使能的寄存器。 module register_N_0(D, Q, data,en,load,reset,clk); parameter N=8;

input en,load,reset,clk; input [N-1: 0] D,data; output reg[N-1: 0] Q; reg[N-1: 0] temp;

always @(posedge clk) //同步复位、同步置数 begin

if(reset) temp<=0;

else if(load) temp<=data; else temp<=D;

end

always @(temp,en) //异步使能 begin

if(en) Q<=temp; else Q <= 'bz; end endmodule

② 同步复位、同步置数要求复位或置数必须在时钟的上升沿发生。

③ 事实上,复位、置数、使能三个信号可以任意选取同步、异步两种方式之一,因此三个信号可以任意组合成8种不同功能的电路,如异步复位、同步置数、异步使能电路等。

(3) 异步复位、同步置数、异步使能的寄存器。 module register_N(D, Q, data,en,load,reset,clk); parameter N=8;

input en,load,reset,clk; input [N-1: 0] D,data; output reg[N-1: 0] Q; reg[N-1: 0] temp;

always @(posedge clk or posedge reset) //异步复位、同步置数 begin

if(reset) temp<=0;

else if(load) temp<=data; else temp<=D; end

always @(temp,en) //异步使能 begin

if(en) Q<=temp; else Q <= 'bz; end endmodule

② 异步复位、同步置数要求只要复位信号为有效电平就复位,而置数必须在时钟的上升沿发生。

3. 移位寄存器

例4-14设计了一个n位移位寄存器,该寄存器具有左移、右移、置数功能。 【例4-14】 参数型n位移位寄存器。

//8位CPU中常用的移位寄存器模块 module shift_N(clk,Ci,mode,D,Q,Co); input clk,Ci; //时钟和移位输入 input[2:0] mode; //移位模式控制字 input[N-1:0] D; //待加载移位的数据 output[N-1:0] Q; //移位数据输出 output reg Co ; //移位输出 reg[N-1:0] temp;

parameter N=8; //8位移位寄存器 always @(posedge clk)

begin case(mode)

3'b000: begin temp <=D; end //加载待移数 3'b001: begin temp[0] <= Ci ; temp[N-1:1] <= temp[N-2:0]; Co<=temp[N-1]; //带进位循环左移 end 3'b010: begin temp[0] <= temp[N-1]; temp[N-1:1] <= temp[N-2:0]; //自循环左移 end

3'b011: begin temp[N-1] <= temp[0]; temp[N-2:0] <= temp[N-1:1]; //自循环右移 end 3'b100: begin temp[N-1] <= Ci ; temp[N-2:0] <= temp[N-1:1]; Co<=temp[0]; //带进位循环右移 end default: temp <= temp ; // 保持 endcase end

assign Q = temp; //移位后输出 endmodule 程序说明:

(1) 移位寄存器可以有多种工作模式,这由移位模式控制字mode来控制。

(2) 仿真波形如图4-14所示。从图中可以看出,第1个时钟上升沿时,mode为3'b000,该模式为加载待置数,因此D的值被装载进Q。第2个时钟上升沿时,mode为3'b001,该模式为带进位循环左移,因此D的值循环左移,同时D的最低位取此时刻Ci的值。从仿真波形图中可以看出,本段代码实现了题目要求的功能。

【例4-16】 十进制加法计数器,带有异步复位和同步时钟使能功能。 module cnt10(clk,rst,en,Q,cout); input clk,rst,en;

output reg[N-1:0] Q; output cout; parameter N=4;

always @(posedge rst, posedge clk) begin

if(rst) //计数器异步复位 Q <= 0; //为了能生成诸如触发器一类的时序逻辑,建议使用非阻塞赋值 else if(en) //计数器同步使能 if(Q==9) Q <= 0; else Q <= Q + 1; end

assign cout= (Q==0)? 1'b1:1'b0; //计数器计满溢出后cout输出1 endmodule

【例2-5】 一个使用多种数据类型的程序片断。 integer M; reg[3:0]A; reg[7:0]B; initial begin

M=-1; //M为32位整数,采用补码形式存放,补码形式为32个1 A=M; //A为4位无符号数,截取M的低4位赋给A:1111 B=A; //B为8位无符号数,将A零扩展后送给B:00001111 B=A+14; //B为29:11101

A=A+14; //A+14为29,截取低4位送给A:1101 end

【例2-6】 存储器建模。 module rom(clk,rst,rd,data,addr); input clk,rst,rd; //rd为读使能信号

input[2:0] addr; //建立的存储器有8个地址空间 output reg[7:0] data; //数据是8位的

reg[7:0] memory[0:7]; //8× 8位数据的存储器 always @(posedge clk,posedge rst) if(rst) begin: init //该顺序块用于初始化ROM值 memory[0] = 8'b0000_0001; memory[1] = 8'b0000_0010; memory[2] = 8'b0000_0100; memory[3] = 8'b0000_1000; memory[4] = 8'b0001_0000; memory[5] = 8'b0010_0000; memory[6] = 8'b0100_0000; memory[7] = 8'b1000_0000; end else

begin: read //该顺序块用于读取ROM值 if(rd) data=memory[addr]; end endmodule

【例3-8】 表示组合逻辑的UDP举例:一位全加器。 全加器进位实现部分:

primitive U_ADD_C(CO, A, B, CI); output CO; input A, B, CI;

table // A B CI : CO 1 1 ? : 1; 1 ? 1 : 1; ? 1 1 : 1;

0 0 ? : 0; 0 ? 0 : 0; ? 0 0 : 0; endtable endprimitive

全加器求和实现部分:

primitive U_ADD_S(S, A, B,CI); output S;

input A, B, CI;

table // A B CI : S

0 0 0 : 0; 0 0 1 : 1; 0 1 0 : 1; 0 1 1 : 0; 1 0 0 : 1; 1 0 1 : 0; 1 1 0 : 0; 1 1 1 : 1; endtable endprimitive

调用上述两个UDP的全加器模块: module U_ADD(SUM,CO,a, b,ci); input a, b,ci; output SUM,CO;

U_ADD_S U1(SUM, a, b,ci); U_ADD_C U2(CO,a, b,ci); endmodule

3.2 结构化形式建模

在Verilog HDL中可使用如下方式描述结构: (1) 开关级原语(在晶体管级)——开关级建模。 (2) 内置门原语(在门级)——门级建模。 (3) 用户定义的原语。

(4) 模块实例(创建层次结构)。 3.2.1 门级建模

简单的逻辑电路可以使用逻辑门来设计实现。

基本的逻辑门分为两类:与/或门类、缓冲/非门类。 1. 与/或门类

与/或门类包括与门(and)、或门(or)、与非门(nand)、或非门(nor)、异或门(xor)、同或门(xnor)。与/或门类都具有一个标量输出端和多个标量输入端,门的端口列表中的第一个端口必定是输出端口,其他均为输入端口。当任意一个输入端口的值发生变化时,输出端的值立即重新计算。

3.3 数据流级建模

在电路规模较小的情况下,由于包含的门数比较少,因此使用门级建模进行设计不仅直观,而且方便。但是,如果电路的功能比较复杂,则通常该电路包含的逻辑门的个数会很多,这时使用门级建模不仅繁琐而且很容易出错。在这种情况下,如果从更高抽象层次入手,将设计重点放在功能实现上,则不仅能避免繁琐的细节,还可以大大提高设计的效率。

本节介绍更高抽象层次的建模方法:数据流建模。 3.3.1 连续赋值语句

以关键词assign开始的语句为连续赋值语句,连续赋值语句是Verilog数据流建模的基本语句,用于对线网进行赋值。

【例3-10】 使用数据流建模,实现一位半加器。 解题指引:半加器实现的是不带进位的两个数的相加,若半加器的输入为ain和bin,输出为sum和co,其中sum为和,co为进位,则半加器的真值表如表3-3所示。

Verilog HDL实现代码如下:

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不能为寄存器类型 对连续赋值语句的进一步说明:

(1) 连续赋值语句的基本元素是表达式、运算符和操作数。其功能是计算右侧表达式的值,然后赋给左边变量。表达式由运算符和操作数构成,根据运算符界定的功能对操作数进行运算后得出结果。数据流的强大建模能力体现在多种运算符类型上。下一节我们将详细介绍运算符类型。

(2) 连续赋值语句总是处于激活状态。只要任意一个操作数发生变化,表达式就会被立即重新计算,并且将结果赋给等号左边的线网。

(3) 操作数可以是标量或向量线网,也可以是标量或向量寄存器。

3.4 行 为 级 建 模

Verilog HDL支持从算法的角度,即从电路外部行为的角度对其进行描述,因此行为

级建模是从一个很高的抽象层次来表示电路的。 在这个层次上进行数字系统设计类似于使用C语言编程,而且Verilog HDL行为建模的语法结构和C语言相当类似。Verilog HDL提供了许多行为级建模语法结构,为设计者提供了很大的灵活性。

3.4.1 结构化过程语句always

always语句是行为建模的基本语句,每个always语句代表一个独立的执行过程,也称为进程。与C语言不同,Verilog HDL的各个always进程是并发执行的,而不是顺序执行的。always语句包括的所有行为语句构成了一个always语句块。每个always语句块在满

足一定的条件后即执行其中的第一条语句,然后顺序执行随后的语句,直到最后一条语句执行完后,再次等待always语句块的执行条件,等条件满足后又从第一条语句开始执行,循环往复。因此,always语句通常用于对数字电路中一组反复执行的活动进行建模。

【例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块,它们都是并行运行的。

3.4.2 过程赋值语句

过程赋值语句的更新对象是寄存器、整数等。这些类型的变量在被赋值后,其值将保持不变,直到被其他过程赋值语句赋予新值。

过程赋值语句与数据流建模中的连续赋值语句是不同的。首先,连续赋值语句总是处于活动状态,任意一个操作数的变化都会导致表达式的重新计算以及重新赋值,但过程赋值语句只有在执行到的时候才会起作用。其次,更新对象不同,连续赋值语句的更新对象是线网,而过程赋值语句的更新对象是寄存器、整数等。最后,从形式上看,过程赋值语句不使用assign。

但过程赋值语句与连续赋值语句又有相同之处,即两者可以使用的运算符是完全相同的。连续赋值语句中使用的运算符在过程赋值语句中同样适用,而且含义完全相同。

Verilog HDL包括两种类型的过程赋值语句:阻塞赋值语句和非阻塞赋值语句。 小结:?

门的基本类型包括与门(and)、或门(or)、与非门(nand)、或非门(nor)、异或门(xor)、同或门(xnor)、缓冲器(buf)和非门(not)等。 每种门都有逻辑符号、真值表和对应的Verilog HDL

原语。这些原语的调用方法和模块的调用方法一样,但这些原语是Verilog HDL预定义的(不需要自行编写)。门的任意一个输入发生变化以后,门的输出立即被重新计算。 ? 连续赋值语句是数据流建模的主要语法结构。连续赋值语句总是处于有效状态,即任一操作数的变化都会立即导致对表达式的重新计算。连续赋值语句的左侧必须是线网类型的变量或者拼接。任何逻辑功能都能够使用连续赋值语句来完成。

? 运算符的类型包括算术、关系、逻辑、按位、缩减、条件、移位和位拼接。单目、双目和三目运算符分别具有一个、两个和三个操作数,而拼接运算符可以具有任意多个操作数。

? 由于运算符的优先级被忽视或混淆而造成错误的情况经常发生。为了避免源于运算符优先级的运算错误,在不确定运算符优先级的情况下,建议读者使用小括号将各个表达式分开。另外,使用括号也可以提高程序的可读性,明确表达各运算符间的优先关系。

? 电路的门级描述、数据流描述、行为描述的抽象层次越来越高,但也越来越接近人的思维,方便设计者高效准确地进行系统设计。

? 利用任务和函数可以把一个很大的程序模块分解成许多较小的任务和函数,这样便于理解和调试。Veirlog HDL函数和任务在综合时被理解成具有独立运算功能的电路,每调用一次函数和任务,都相当于改变这部分电路的输入以得到相应的计算结果。学会使用task和function语句可以简化程序的结构,使程序明白易懂,是编写较大型模块的基本功。

本文来源:https://www.bwwdw.com/article/wuz.html

Top