今天给大侠带来Verilog HDL 语法学习笔记,话不多说,上货。
关于详细的VHDL语法以及Verilog HDL语法可参见往期文章。
一周掌握 FPGA VHDL Day 7 暨汇总篇
一周掌握FPGA Verilog HDL语法 汇总篇
Verilog HDL 语法学习笔记
一、Verilog HDL 简介
1.1 Verilog HDL 的历史
Verilog HDL 语 言 最 初 是 作为 Gateway Design Automation 公 司 ( Gateway DesignAutomation 公司后来被著名的 Cadence Design Systems 公司收购)模拟器产品开发的硬件建模语言。
开始 Verilog HDL 只是一种专用语言,随着 Gateway Design Automation 公司模拟、仿真器产品的广泛使用,Verilog HDL 便于使用、实用的语言逐渐为众多设计者所接受。1995年 Verilog HDL 正式成为 IEEE 标准,称为 IEEE Std 1364-1995。
1.2 Verilog HDL 的特点
Verilog HDL 语言不仅定义了语法,而且对每个语法结构都定义了清晰的模拟、仿真语义。使用这种语言编写的模型可以方便地使用 Verilog 仿真器进行验证。Verilog HDL 从 C 语言中继承了多种操作符和结构。Verilog HDL 提供了扩展的建模能力和扩展模块。Verilog HDL 语言的核心子集非常易于学习和使用,这对大多数建模应用来说已经足够。
Verilog HDL 之所以成为和 VHDL 并驾齐驱的硬件描述语言,是因为它具有如下特点:
• 基本逻辑门和开关级基本结构模型都内置在语言中;
• 可采用多种方式对设计建模,这些方式包括行为描述方式、数据流方式、结构化方式;
• Verilog HDL 中有线网(Wire)数据类型和寄存器(Reg)数据类型两类数据类型,线网类型表示构件间的物理连线,而寄存器类型表示抽象的数据存储元件;
• 能够描述层次设计,可使用模块实例结构描述任何层次;
• 设计的规模可以是任意的,语言不对设计的规模大小施加任何限制;
• Verilog HDL 不再是某些公司的专有语言而是 IEEE 标准;
• Verilog HDL 语言的描述能力能够通过使用编程语言接口(Programme LanguageInterface,简称 PLI)机制进一步扩展,PLI 允许外部函数访问 Verilog 模块内信息、允许设计者与模拟器交互的例程集合;
• 设计能够在多个层次上加以描述,从开关级、门级、寄存器传送级(RT L)到算法级,包括进程和队列级;
• Verilog HDL 能够监控模拟验证的执行,即模拟验证执行过程中设计的值能够被监控和显示,这些值也能够用于与期望值比较,在不匹配的情况下打印报告消息。
二、Verilog HDL 程序基本结构
模块是 Verilog 的基本描述单位,描述某个设计的功能或结构及其与其他模块通信的外部端口。一个模块的基本语法如下:
module module_name//模块名称
(port_list);//输入输出信号列表
//说明
reg //寄存器
wire//线网
parameter//参数
input//输入信号
output//输出信号
inout//输入输出信号
function//函数
task//任务
. . .//语句
Initial statement
Always statement
Module instantiation//
Gate instantiation//
UDP instantiation//
Continuous assignment//
endmodule
说明部分用于定义不同的项,例如模块描述中使用的寄存器和参数、语句定义设计的功能和结构。说明部分和语句可以放置在模块中的任何地方,但是变量、寄存器、线网和参数等的说明部分必须在使用前出现。为了使模块描述清晰和具有良好的可读性, 最好将所有的说明部分放在语句前。
图 1 所示的是一个半加器。
图 1 半加器
这个半加器用 Verilog HDL 实现,代码如下:
module HalfAdder(A,B,Sum,Carry) ;
input A,B;
output Sum, Carry;
assign #2 Sum = A ^ B;
assign #5 Carry = A & B;
endmodule
模块的名字是 HalfAdder。模块有 4 个端口:两个输入端口 A 和 B,两个输出端口 Sum 和Carry。由于没有定义端口的位数,所有端口大小都为 1 位;同时由于没有各端口的数据类型说明,这 4 个端口都是线网数据类型。模块包含两条描述半加器数据流行为的连续赋值语句。从这种意义上讲,这些语句在模块中出现的顺序无关紧要,因为这些语句是并发的。每条语句的执行顺序依赖于发生在变量 A 和 B 上的事件。
三、Verilog HDL 语言的数据类型和运算符
本篇介绍 Verilog HDL 语言的基本要素,包括标识符、注释、数值、编译程序指令、系统任务和系统函数、两种主要的数据类型。
3.1 标识符
Verilog HDL 中的标识符可以是任意一组字母、数字、$符号和_(下划线)符号的组合,但标识符的第一个字符必须是字母或者下划线。另外,标识符是区分大小写的。以下是标识符的几个例子:
Piero
PIERO / /与 Piero 不同。
_a1_b2
c00_68
ABC$
3.2 数据类型
Verilog HDL 有两大类数据类型:
• 线网类型,表示 Verilog HDL 结构化元件间的物理连线,它的值由驱动元件的值决定,例如连续赋值或门的输出,线网的缺省值为 z(高阻态);
• 寄存器类型,表示一个抽象的数据存储单元,它只能在 always 语句和 initial 语句中被赋值,并且它的值被保存下来,缺省值为 x(未知状态)。
1)线网类型
线网数据类型包含下述不同种类的线网子类型:wire、tri、wor、trior、wand、triand、trireg、tri1、tri0、supply0、supply1。简单的线网类型说明语法为:
net_kind [msb:lsb] net1, net2, . . . , netN;
net_kind 是上述线网类型的一种。msb 和 lsb 是用于定义线网范围的常量表达式,范围定义是可选的;如果没有定义范围,缺省的线网类型为 1 位。下面是一个线网类型说明实例。
wire Rdy, Start; //2 个 1 位的连线。
wand [2:0] Addr; //Addr 是 3 位线与。
2)寄存器类型
有 5 种不同的寄存器类型:reg、integer、time、real 和 realtime。寄存器数据类型 reg是最常见的数据类型。reg 类型使用保留字 reg 加以说明,形式如下:
reg [msb: lsb] reg1, reg2, . . . regN;
msb 和 lsb 定义了范围,并且均为常数值表达式。范围定义是可选的,如果没有定义范围,缺省值为 1 位寄存器。例如:
reg [3:0] Sat; //Sat 为 4 位寄存器。
reg Cnt; //1 位寄存器。
reg [1:32] Kisp, Pisp, Lisp;
3.3 模块端口
模块端口是指模块与外界交流信息的接口,包括 3 种:
• in:模块通过这个接口从外界环境读取数据,是不可写的;
• out:模块通过这个接口向外界环境输出数据,是不可读的;
• inout:模块可以通过这个接口从外界环境读取并输出数据,数据可以双向流通。
3.4 值集合
Verilog HDL 有下列 4 种基本的值:
• 0:逻辑 0 或“假”;
• 1:逻辑 1 或“真”;
• x:未知;
• z:高阻。
这 4 种值的解释都内置于语言中。如一个为 z 的值总是意味着高阻抗,一个为 0 的值通常是指逻辑 0。在门的输入或一个表达式中的为“z”的值通常解释成“x”。此外,x 值和 z 值都是不分大小写的。也就是说,值 0x1z 与值 0X1Z 相同。Verilog HDL 中的常量是由以上这四类基本值组成的。
Verilog HDL 中有 3 类常量:整型、实数型和字符串型。下划线符号(_)可以随意用在整数或实数中,它们就数量本身没有意义。它们能用来提高易读性;惟一的限制是下划线符号不能用作为首字符。
1)整型数
整型数可以按如下两种方式书写:简单的十进制数格式和基数格式。
简单的十进制形式的整数定义为带有一个可选的“+”(一元)或“-”(一元)操作符的数字序列。下面是这种简易十进制形式整数的例子:
32;// 十进制数 32
-15;// 十进制数-15
基数格式的格式为:
[size ] 'base value
size 定义以位计的常量的位长,base 为 o 或 O(表示八进制)、b 或 B(表示二进制)、d或 D(表示十进制)、h 或 H(表示十六进制),value 是基于 base 的值的数字序列。值 x 和 z以及十六进制中的 a 到 f 不区分大小写。下面是一些具体实例:
5'O37;// 5 位八进制数
4'D2;//4 位十进制数
4'B1x_01;// 4 位二进制数
7'Hx ;//7 位 x(扩展的 x),即 xxxxxxx
4'hZ;// 4 位 z(扩展的 z) , 即 zzzz
4'd-4;//非法,数值不能为负
8'h 2 A;//在位长和字符之间,以及基数和数值之间允许出现空格
3' b001;//非法: `和基数 b 之间不允许出现空格
(2+3)'b10;// 非法:位长不能够为表达式
2)实数
实数可以用下列两种形式定义:
• 十进制计数法,例如 2.0、5.678、1、1572.12;
• 科学计数法,例如 23_5.1e2(其值为 23510.0,忽略下划线)、3.6E2(360.0)。
3)字符串
字符串是双引号内的字符序列。字符串不能分成多行书写,例如:
"INTERNAL ERROR"
" REACHED->HERE "
用 8 位 ASCII 值表示的字符可看作是无符号整数。因此字符串是 8 位 ASCII 值的序列。为存储字符串“INTERNAL ERROR”,变量需要 8 * 1 4 位。
reg [1 : 8*14] Message;
. . .
Message = "INTERNAL ERROR"
反斜线(\)用于对确定的特殊字符转义。
\n 换行符
\t 制表符
\\ 字符\本身
\" 字符"
\206 八进制数 2 0 6 对应的字符
3.5 表达式
表达式是 Verilog HDL 语言中进行逻辑运算和表达最基本的元素。表达式由操作符和操作数按照一定的规则组合而成,下面进行详细介绍。
1)操作数
操作数的类型包括:常量、参数、线网、寄存器、存储器单元和函数调用等。
常量的使用规则在3.4 中进行说明,下面是一些实例:
256,7 //非定长的十进制数
4'b10_11, 8'h0A // 定长的整型常量
'b1, 'hFBA // 非定长的整数常量
90.00006 // 实数型常量
"BOND" // 串常量;每个字符作为 8 位 ASCII 值存储
表达式中的整数值可被解释为有符号数或无符号数。参数类似于常量,并且使用参数声明进行说明。下面是参数说明实例:
parameterLOAD = 4'd12, STORE = 4'd10;
LOAD 和 STORE 为参数的例子,值分别被声明为 12 和 10。
线网在表达式中可以分别按照标量和向量两种方式使用,下面是线网说明实例:
wire [0:3] Prt; //Prt 为 4 位向量线网
wire Bdq; //Bbq 是标量线网
线网中的值被解释为无符号数。例如在连续赋值语句中:
assign Prt = -3;
Prt 被赋于位向量 1101,实际上为十进制的 13,例如在下面的连续赋值中:
assign Prt = 4'HA;
Prt 被赋于位向量 1010,即为十进制的 10。
寄存器也是可以按照标量和向量两种方式使用。寄存器变量使用寄存器声明进行说明,例如:
integer TemA, TemB;
reg [1:5] State;
time Que [ 1:5 ] ;
整型寄存器中的值被解释为有符号的二进制补码数,而 reg 寄存器或时间寄存器中的值被解释为无符号数,实数和实数时间类型寄存器中的值被解释为有符号浮点数。例如下面的寄存器代码:
TemA = -10; //TemA 值为位向量 10110,是 10 的二进制补码
TemA = 'b1011; //TemA 值为十进制数 11
State = -10; //State 值为位向量 10110,即十进制数 22
State = 'b1011; // State 值为位向量 01011,是十进制值 11
在 Verilog HDL 语言中,对于向量形式的线网和寄存器,都可以采用部分选择的方式使用向量中需要的部分。在部分选择中,向量的连续序列被选择,形式如下:
net_or_reg_vector [msb_const_expr:1sb_const_expr]//部分选择的语法形式
State [1:4] //寄存器部分选择
Prt [1:3] // 线网部分选择
存储器单元的定义形式如下:
memory [word_address] //定义形式
reg [1:8] Ack, Dram [ 0 : 6 3 ] ;//例子
. . .
Ack = Dram [60]; //存储器的第 6 0 个单元
不允许对存储器变量值部分选择或位选择。例如:
Dram [60] [2] //使用错误
Dram [60] [2:4]//使用错误
在存储器中读取一个位或部分选择一个字的方法如下:将存储器单元赋值给寄存器变量,然后对该寄存器变量采用部分选择或位选择操作。
2)操作符
Verilog HDL语言中的操作符包括:
• 算术操作符 +(加法)、-(减法)、×(乘法)、÷(除法)和%(取模)。
• 关系操作符 >(大于)、<(小于)、≥(大于等于)和≤(小于等于),计算结果为真(1)或者假(0)。
• 相等操作符 ==(逻辑相等)、!=(逻辑不相等)、===(逻辑全等)和!==(非全等)。
• 逻辑操作符 &&(逻辑与)、||(逻辑或)、!(逻辑非)。
• 按位操作符 ~(一元非)、&(二元与)、|(二元或)、^(二元异或)和~^(二元异或非)。
• 移位操作符 <<(左移)、>>(右移)。
• 条件操作符 条件操作符根据条件表达式的值选择表达式。
四、Verilog HDL 语言的描述语句
Verilog HDL 语言的描述语句有结构化建模方式、数据流建模方式和行为建模方式 3 种。
4.1 结构化建模方式
Verilog HDL 中可以使用内置基本门来进行硬件描述。Verilog HDL 中提供下列内置基本门:
• 多输入门 and(与门)、nand(与非门)、or(或门)、nor(或非门)、xor(异或门)。
• 多输出门 buf(缓冲门)、not(取反)。
• 三态门 bufif0、bufif1、notif0、notif1。
• 上拉、下拉电阻 pullup(上拉电阻)、pulldown(下拉电阻)。
• MOS 开关 cmos、nmos、pmos、rcmos、rnmos、rpmos。
• 双向开关 tran、tranif0、tranif1、rtran、rtranif0、rtranif1。
门级逻辑设计描述中可使用具体的门实例语句。下面是简单的门实例语句的格式:
gate_type[instance_name] (term1, term2, . . . ,termN ) ;
其中 instance_name 是可选的,gate_type 为前面列出的某种门类型。各 term 用于表示与门的输入/输出端口相连的线网或寄存器。同一门类型的多个实例能够在一个结构形式中定义。语法如下:
gate_type
[instance_name1] (term11, term12, . . .,term1N ) ,
[instance_name2] (term21, term22, . . .,term2N ) ,
. . .
[instance_nameM] (termM1, termM2, . . .,termMN)
下面是一个用结构化建模方式实现的多路选择电路的例子,如图 2 所示。
图 2 多路选择电路
多路选择电路如果用结构化建模方式实现,代码如下:
module MUX4x1 (Z , D0 , D1 , D2 , D3 , S0 , S1) ;
input D0 , D1 , D2 , D3 , S0 , S1;
output Z;
and (T0 , D0 , S01 , S11) ,
(T1 , D1 , S01, S1) ,
(T2 , D2 , S0 , S11) ,
(T3 , D3 , S0 , S1) ,
not (S01, S0) ,
(S11 , S1) ;
or (Z , T0 , T1 , T2 , T3) ;
endmodule
4.2 数据流建模方式
Verilog HDL 中的数据流建模方式一般用连续赋值语句来实现。Verilog HDL 中有两种形式的赋值方式:连续赋值和过程赋值。其中过程赋值用于顺序行为建模,而组合逻辑电路的行为最好使用连续赋值语句建模。
连续赋值语句将值赋给线网(连续赋值不能为寄存器赋值),它的格式如下:
assign LHS_target = RHS_expression;//定义格式
//例子
wire [3:0] Z, Preset, Clear; //线网说明
assign Z = Preset & Clear; //连续赋值语句
连续赋值的目标为 Z,表达式右端为“Preset & Clear”,连续赋值语句中的关键词为assign。只要在右端表达式的操作数上有事件(事件为值的变化)发生时,连续赋值语句即被计算,如果结果值有变化,新结果就赋给左边的线网。在上面的例子中,如果 Preset 或 Clear变化,就计算右边的整个表达式。如果结果变化,那么结果即赋值到线网 Z。
如图 3 所示的是主从触发器。
图 3 主从触发器
主从触发器用连续赋值语句实现的代码如下:
module MSDFF_DF (D, C, Q, Qbar) ;
input D, C;
output Q, Qbar;
wire NotC, NotD, NotY, Y, D1, D2, Ybar, Y1, Y2 ;
assign NotD = ~ D;
assign NotC = ~ C;
assign NotY = ~ Y;
assign D1 = ~ (D & C) ;
assign D2 = ~ (C & NotD) ;
assign Y = ~ (D1 & Ybar ) ;
assign Ybar = ~ (Y & D2) ;
assign Y1 = ~ (Y & NotC ) ;
assign Y2 = ~ (NotY & NotC) ;
assign Q = ~ (Qbar & Y1) ;
assign Qbar = ~ (Y2 & Q) ;
endmodule
4.3 行为建模方式
行为建模方式是用过程赋值语句来实现的。下面对行为建模方式的各个部分进行详细介绍。
1)过程结构
Verilog HDL 中的主要行为通过两种语句来控制进行:
• initial 语句;
• always 语句。
initial 语句在模拟开始时执行,即在 0 时刻开始执行。initial 语句只执行一次,它的语法如下:
initial
[timing_control] procedural_statement
这里的时序控制可以是延时控制,即等待一个确定的时间;或事件控制,即等待确定的事件发生或某一特定的条件为真。initial 语句的各个进程语句仅执行一次。initial 语句根据进程语句中出现的时间控制在以后的某个时间完成执行。下面是一个 initial 语句实例:
parameter SIZE = 1024;
reg [7:0] RAM [ 0:SIZE- 1 ] ;
reg RibReg;
initial
begin: SEQ_BLK_A
integer Index;
RibReg = 0;
for (Index = 0; Index < SIZE; Index = Index + 1)
RAM[Index] = 0;
End
与 initial 语句相反,always 语句可重复执行。与 initial 语句类似,always 语句语法如下:
always
[timing_control]procedural_statement
下面是一个 always 语句的实例。
reg [0:5] InstrReg;
reg [3:0] Accum;
wire ExecuteCycle;
always@ (EcecuteCycle) //发生在某个时钟沿
begin
case(InstrReg[ 0 : 1 ] )//多路条件分支
2'b00: Store (Accum, InstrReg[2:5]) ;//存储
2'b11: Load (Accum, InstrReg[2:5]) ;//读取
2'b01: Jump (InstrReg[ 2 : 5 ] ) ;//跳转
2'b10: ;
endcase
end
2)时序控制
Verilog HDL 中进行时序控制分别通过下面两种方式进行:
• 延时控制;
• 事件控制。
延时控制的语法如下:
#delay procedural_statement
延时控制定义为执行过程中首次遇到该语句与该语句的执行的时间间隔。延时控制表示在语句执行前的“等待时延”。下面是一个延时控制的例子:
initial
begin
#3 Wave = 'b0111;//3 个时间单位后执行
#6 Wave = 'b1100; //6 个时间单位后执行
#7 Wave = 'b0000; //7 个时间单位后执行
end
事件控制有两种方式:边沿触发事件控制和电平敏感事件控制。边沿触发事件是指指定信号的边沿发生跳变时发生指定的行为,下面是边沿触发事件控制的语法和实例:
@ event procedural_statement
//实例
time RiseEdge, OnDelay;
initial
begin
//等待,直到在时钟上发生正边沿:
@ (posedge ClockA) ;
RiseEdge = $time;
//等待,直到在时钟上发生负边沿:
@ (negedge ClockA) ;
OnDelay = $time - RiseEdge;
$display ("The on-period of clock is %t.", Delay) ;
end
在电平敏感事件控制中,进程语句或进程中的过程语句一直延迟到条件变为真后才执行。下面是电平敏感事件控制的语法和实例:
wait (Condition)
procedural_statement
//实例
wait (Sum > 22) //直到 Sum 大于 22 时发生
Sum = 0;
wait (DataReady) //直到 DataReady 为高时发生
Data = Bus;
wait (Preset) ; //直到 Preset 为高时才能执行后面的语句
3)语句块
Verilog HDL 在执行语句时分为顺序和并行两种方式。在顺序语句块中,语句按给定次序顺序执行;在并行语句块中,语句并行执行。
顺序语句块的语法和实例如下:
begin
[:block_id{declarations} ]
procedural_statement(s)
end
//实例
//产生波形
begin
#2 Stream = 1;
#5 Stream = 0;
#3 Stream = 1;
#4 Stream = 0;
#2 Stream = 1;
#5 Stream = 0;
end
并行语句块的语法和实例如下:
fork
[:block_id{declarations} ]
procedural_statement(s) ;
join
//实例
//生成波形,生成的波形和前面使用顺序语句块的例子一样
fork
#2 Stream = 1;
#7 Stream = 0;
#10 Stream = 1;
#14 Stream = 0;
#16 Stream = 1;
#21 Stream = 0;
join
4)过程性赋值
过程性赋值是在 initial 语句或 always 语句内的赋值,它只能对寄存器数据类型的变量赋值。过程性赋值如下两类:
• 阻塞性过程赋值:赋值在其后所有语句执行前执行,即在下一语句执行前该赋值语句完成执行;
• 非阻塞性过程赋值:对目标的赋值是非阻塞的(因为时延),但可预定在将来某个时间发生。
阻塞性过程赋值用操作符“=”完成,例如下面的实例:
always @ (A or B or Cin)
begin: CARRY_OUT
reg T1,T2 , T3;
T1 = A & B;
T2 = B & Ci n;
T3 = A & Ci n;
Cout = T1|T2|T3;
end
T1 赋值首先发生,计算 T1;接着执行第二条语句,T2 被赋值;然后执行第三条语句, T3被赋值,依此类推直到最后。
非阻塞性过程赋值用操作符“<=”完成,例如下面的实例:
initial
begin
Clr <= #5 1;
Clr <= #4 0;
Clr <= #10 0;
End
第一条语句的执行使 Clr 在第 5 个时间单位被赋于值 1;第二条语句的执行使 Clr 第 4 个时间单位被赋值为 0(从 0 时刻开始的第 4 个时间单位);最终第 3 条语句的执行使 Clr 在第10 个时间单位被赋值为 0(从 0 时刻开始的第 1 0 个时间单位)。这 3 条语句都是在 0 时刻执行的。
5)流程控制语句
流程控制语句包括:
• if 语句;
• case 语句;
• 循环语句。
if 语句的语法如下:
if(condition_1)
procedural_statement_1
{else if(condition_2)
procedural_statement_2}
{else
procedural_statement_3}
如果对 condition_1 求值的结果为一个非零值,那么 procedural_statement_1 被执行,如果 condition_1 的值为 0、x 或 z,那么 procedural_statement_1 不执行。如果存在一个 else分支,那么这个分支被执行。
下面是一个 if 语句的例子:
if(Sum < 60)
begin
Grade = C;
Total_C = Total_c + 1;
end
else if(Sum < 75)
begin
Grade = B;
Total_B = Total_B + 1;
end
else
begin
Grade = A;
Total_A = Total_A + 1;
End
case 语句是一个多路条件分支形式,其语法如下:
case(case_expr)
case_item_expr{ ,case_item_expr} :procedural_statement
. . .
. . .
[default:procedural_statement]
endcase
case 语句首先对条件表达式 case_expr 求值,然后依次对各分支项求值并进行比较,第一个与条件表达式值相匹配的分支中的语句被执行。可以在 1 个分支中定义多个分支项,这些值不需要互斥。缺省分支覆盖所有没有被分支表达式覆盖的其他分支。
下面是 case 语句的一个实例:
always @ (A or B or OpCode)
case (OpCode)
ADD_INSTR: Z = A + B;
SUB_INSTR: Z = A -B;
MULT_INSTR: Z = A * B;
DIV_INSTR: Z = A / B;
endcase
endmodule
Verilog HDL 中提供 4 种循环语句:forever 循环,repeat 循环,while 循环和 for 循环。
forever 循环语句连续执行过程语句。因此为跳出这样的循环,中止语句可以与过程语句共同使用。同时,在过程语句中必须使用某种形式的时序控制,否则 forever 循环将在 0 延时后永远循环下去。forever 循环语句语法和实例如下:
forever
procedural_statement
//实例
initial
begin
Clock = 0;
# 5 forever
#10 Clock = ~Clock;
end
这一实例产生时钟波形:时钟首先初始化为 0,并一直保持到第 5 个时间单位;此后每隔10 个时间单位,时钟反相一次。
repeat 循环语句执行指定循环次数,如果循环计数表达式的值不确定,即为 x 或 z 时,那么循环次数按 0 处理。下面是 repeat 循环语句语法和实例如下:
repeat(loop_count)
procedural _ statement
//实例
repeat(Count)
@ (posedge Clk) Sum = Sum + 1;//在时钟上升沿时每次加一
while 循环执行过程赋值语句直到指定的条件为假。如果表达式在开始时为假,那么过程语句便永远不会执行。如果条件表达式为 x 或 z,它也同样按 0(假)处理。
下面时 while 循环的语法和实例:
while(condition)
procedural_statement
//实例,一直执行直到 BY 小于等于 0
while (BY > 0 )
begin
Acc = Acc << 1;
By = By - 1;
End
for 循环照指定的次数重复执行过程赋值语句。下面是 for 循环的语法和实例:
for(initial_assignment ; condition ; step_assignment)
procedural_statement
//实例中,MAX_RANGE 为循环计次的上限,每次循环加一
for (K=0 ; K < MAX_RANGE ; K = K + 1)
begin
if(Abus[K] == 0)
Abus[K] = 1;
else if(Abus[k] == 1)
Abus[K] = 0;
else
$display( "Abus[K] is an x or a z");
end
end
关于详细的VHDL语法以及Verilog HDL语法可参见往期文章。
一周掌握 FPGA VHDL Day 7 暨汇总篇
一周掌握FPGA Verilog HDL语法 汇总篇
END
后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。
大侠们,江湖偌大,继续闯荡,愿一切安好,有缘再见!
往期推荐
基于FPGA的以太网控制器(MAC)设计(下)
基于FPGA的CAN总线控制器的设计(下)
FPGA之通信算法工程师面试题3
基于FPGA的单目内窥镜定位系统设计(下)