一、Verilog语法的基本概念
1.Verilog HDL程序是由模块组成的。每个模块的内容都是位于module 和 endmodule两个语句之间。每个模块完成特定的功能。
2.模块是可以进行层次嵌套的,因此大型的数字电路可以分割成不同的小模块来实现特定的功能。
3.Verilog模块可以分成两种类型,一种是为了让模块最终能生成电路的结构;另一种是为了测试所设计的电流的逻辑功能是否正确。
4.每个模块都要进行端口的定义,并说明输入、输出口,然后对模块的功能进行描述
5.除了endmodule外的语句都需以分号结尾;类似于C语言的注释语句。
6.若每个模块都是可以综合的,则可以通过综合工具将他们的功能描述全部转换为最基本的逻辑单元描述,最后可以用一个上层模块通过实例引用的方式把这些模块都连接起来,把他们组成一个大的复杂的数字逻辑系统。
二、模块的结构、数据类型、变量和基本运算符号
1、Verilog的基本设计单元是模块(block):(1)描述接口;(2)描述逻辑功能
端口定义: module 模块名(口1,口2,口3,口4……);//模块的端口描述的是输入和输出口名
(1)在被引用时,严格按照模块定义的端口顺序连接,可以不用标明原模块定义时规定的端口名:模块名(连接信号1名,连接信号2名,……)
(2)在引用时用“.”符号,标明原模块定义时的端口名:模块名(.端口1名(连接信号1名),.端口2名(连接信号2名),……)
模块内容:模块内容包括I/O说明,内部信号声明和功能定义
I/O说明:
(1)输入口 input[信号位宽-1:0]端口名1;
input[信号位宽-1:0]端口名2;
(2)输出口 output[信号位宽-1:0]端口名1;
output[信号位宽-1:0]端口名2;
(3)输入输出口
inout[信号位宽-1:0]端口名1;
inout[信号位宽-1:0]端口名2;
内部信号说明:
reg[width-1:0]R变量1,R变量2……
wire[width-1:0]W变量1,W变量2……
功能定义:模块中最重要的部分是逻辑功能的定义部分,有3种方法可在模块中产生逻辑
(1)用“assign”语句声明:如:assign a = b & c;
(2)用实例元件:如:and #2 u1(q,a,b);
(3)用“always”块:如:always @(posedge clk or posedge clr)
begin
if(clr) q<=0;
else if(en) q<=d;
end
always 块既可以描述组合逻辑电路,也可以描述时序逻辑电路;过程块内部是顺序执行的;
要点: (1)在Verilog模块中所有的过程块(如initial块、always块)、连续赋值语句、实例引用都是并行执行的;
(2)只有连续赋值语句assign 和实例引用语句可以独立于过程块而存在于模块的功能定义部分;
2、数据类型及常量、变量
Verilog中共有19种数据类型。数据类型是用来表示数字电路硬件中的数据存储和传送元素的。
常量:运行过程中其值不可改变
数字:
(1)整数
1)二进制整数b或B
2)十进制整数d或D
3)十六进制整数h或H
4)八进制整数o或O
数字的表达方式:
1)<位宽><进制><数字>:如 8’b10101100 //八位二进制数
2)<进制><数字>,此时默认位宽,与机器的系统有关,但至少为32位
3)<数字>,此时默认为十进制
(2)x和z值:x代表不确定值;z代表高阻值。
(3)负数:一个数字被定义为负数,只需在位宽前加一个负号,负号必须写在表达式的最前面:如 -8’d5
(4)下划线:可以用来分隔开数的表达提高可读性,但只能用作具体的数字之间:如8’b1001_1101
参数型:用parameter来定义常量,即用parameter声明一个标识符代表一个常量,称为符号常量。常用于定义延迟时间和变量宽度。在模块和实例引用中可以通过参 数传递改变在被引用模块或实例中已定义的参数,使用defparam。
parameter 参数名1 = 表达式,参数名2 = 表达式……
变量:在程序运行过程中可以改变的量
网络数据类型:标识结构实体之间的物理连接,如果没有驱动器连接到网络类型的变量,则该变量就是高阻的,其值为z值
常用的网络数据类型有 wire 和 tri
wire 型数据通常用来表示单个门驱动或连续赋值语句驱动的网络数据类型。Verilog程序块的输入、输出信号类型默认为wire
wire[7:0] b;
tri 型数据则用来表示多驱动器驱动的网络数据类型。
reg 型:寄存器数据类型,是数据存储单元的抽象;常用来表示“always”模块内的指定信号,常代表触发器(只表示被定义的信号将用在“always”块内)。
reg[n-1:0] rega;
memory型:Verilog 通过对reg型变量建立数组来对存储器建模。
reg[n-1:0]存储器名[m:1]; 如reg[7:0] mema[255:0];定义了名为mema的存储器,它含有256个8位的寄存器。对存储器的mema的访问类似于对数组的访问mema[3],下标索引可以使表达式,但需是常量表达式。
3. 运算符及表达式
(1) 算术运算符(+,-,x,/,%)
(2) 赋值运算符(=,<=)
(3) 关系运算符(>,<,>=,<=)
(4) 逻辑运算符(&&,||,!)
(5) 条件运算符(?:)
(6) 位运算符(~,|,^,&,^~)^~ 按位同或(异或非) ^ 按位异或
(7) 移位运算符(<<,>>)
(8) 拼接运算符({})
(9) 其他
三、 运算符、赋值语句和结构说明语句等基本语法要素
1. 逻辑运算符:与&&、或||、非!
2. 关系运算符:大于>,小于<,大于等于>=,小于等于<=
3. 等式运算符:== 等于,!= 不等于,逻辑等式运算符
=== 等于,!=== 不等于,两个操作数必须完全一致,其结果才为1,否则为0,可以对x和z值进行比较
4. 移位运算符:<<左移,>>右移,都用0填充移除的空位
5. 位拼接运算符: {},用这个运算符可以将多个信号的某些位拼接起来进行运算操作,使用方法如:
{信号1的某几位,信号2的某几位,……信号n的某几位},使用中允许嵌套。
6.因为优先级的关系,建议使用括号,显示的指明运算顺序
7.赋值语句:Verilog中有两种赋值方式
(1)非阻塞型赋值方式:如 b <= a;
1)语句块中,上面的语句所赋值不能立即为下面语句所使用
2)块接收后才能完成此次赋值操作,所赋的变量值是上一次赋值得到的
3)在时序逻辑模块中常用
(2)阻塞型赋值方式: 如 b = a;
1)赋值语句执行完后块才结束
2)b值在赋值语句执行后立即改变
3)在时序逻辑中使用,可能会产生意想不到的结果
8. 块语句:将两条或多条语句组合在一起,使其在格式上更像一条语句。
块语句有两种:
(1)begin-end:
其内语句顺序执行,直到最后一条语句执行完程序流程控制才跳出该语句块;
块内的每条语句的执行时间是相对于前一条语句执行结束开始;
块内声明语句可以是参数声明语句、reg型变量声明语句、integer型变量声明语句和real型变量声明语句。
(2)fork-join:
块内语句并行执行,及程序流程控制一进入到该并行块,块内的语句开始同时执行;
块内的每条语句的执行时间是相对于程序流程控制进入到块内的仿真时间;
延迟时间是用来给赋值语句提供时序的;如 #10 r = ’he4;
当按时间时序排序在最后的一条语句执行完,或disable语句执行完,程序控制流结束跳出该块。
块内声明语句可以是参数声明语句、reg型变量声明语句、integer型变量声明语句、real型变量声明语句、time型变量声明语句和事件(event)声明语句
块名:可以给每个块取一个名字,只需将名字加在关键字begin或fork后面即可,这样做的原因有以下几点:
(1)可以在块内定义局部变量,只在该块内使用
(2)可以允许块被其他语句调用,如disable语句
(3)在Verilog语言里,所有的变量都是静态的,有唯一的存储地址,所以进出块不会影响存储在变量中的值。
起始时刻和结束时刻的概念:注意在顺序块和并行块中,每条语句的执行起始时间,及推出块的时间。
四、 条件语句、循环语句、块语句与生成语句
1. 条件语句 if-else(类似于C语言),if判断的表达式值若为0,x,z按照“假”处理,若为1,按照“真”处理
注意if-else 和 begin-end的嵌套使用,若书写不当可能会导致逻辑行为改变
2. 多分支选择语句:case语句(类似于C语言)
(1)case(表达式) <case分支项> endcase
(2)casex(表达式) <case分支项> endcase
(3)casez(表达式) <case分支项> endcase
case分支项的一般格式:
分支表达式 语句;
默认项(default) 语句;
3. 循环语句:Verilog中存在着4种循环语句,用来控制执行语句的执行次数。
(1)forever 语句:连续的执行语句;不能独立写在程序中,必须写在initial块中
格式:1)forever 语句;
或forever begin 多条语句 end
(2)repeat 语句:连续执行一条语句n次
格式:1)repeat 语句;
或repeat begin 多条语句 end
(3)while 语句:执行一条语句直到某个条件不满足
格式:1)while(表达式) 语句;
或while(表达式) begin 多条语句 end
(4)for 语句:类似于C语言
格式:1)for(表达式1,表达式2,表达式3)语句;
4.顺序块和并行块
块语句的作用是将多条语句合并成一组,使他们像一条语句一样。Verilog 的块语句两种类型:顺序块和并行块
(1)顺序块:关键字begin-end 用于将多条语句组成顺序块。
特点:1)顺序块中的语句是一条接一条按顺序执行的
2)如果语句包括延迟或事件控制,那么延迟总是相对于前面那条语句执行完成的仿真时间的
(2)并行块:并行块由关键字fork-join 声明
特点:1)并行块内的数据是并发执行的
2)语句执行的顺序是由各自语句内延迟或事件控制决定的
3)语句中的延迟或事件控制是相对于块语句开始执行的时刻而言的
二者最主要的区别就是,程序控制流程转入块时,并行块中的所有语句是并发执行的,与语句的先后顺序无关
(3)块语句的特点:嵌套块、命名块和命名块的禁用
1)嵌套块:块可以嵌套使用,顺序块和并行块可以混合在一起使用
2)命名块:块可以具有自己的名字,这称命名块
特点:命名块中可以声明局部变量;
命名块时设计层次的一部分,命名块中声明的变量可以通过层次名引用进行访问;
命名块可以被禁用,例如停止其执行;
3)命名块的禁用:disable 语句
5.生成块
生成语句可以动态的生成Verilog代码;生成语句能够控制变量的声明、任务或函数的调用,还能对实例引用进行全面的控制。
关键字 generate - endgenerate
3种创建生成语句的方法: (1)循环生成
(2)条件生成
(3)case生成
小结:
(1)结构化的过程块,即initial块和always块,构成了行为级建模的基础。其他所有的行为语句只能出现在这两种块中。initial块只执行一次,always块一直执行。
(2)Verilog 中控制时序和语句执行顺序的3种方式是:基于延迟的时序控制、基于事件的时序控制、电平敏感的时序控制
(3)基于延迟的时序控制包括3种形式:常规延迟、0延迟、内嵌延迟
(4)基于事件的时序控制包括:常规事件、命名事件、OR事件
(5)Wait 语句用于电平敏感的时序控制
五、结构语句、系统任务、函数语句和显示系统任务
1. 结构说明语句
Verolog 语言中任何过程模块后从属于以下4种结构的说明语句:
(1)initial 说明语句
(2)always 说明语句
(3)task 说明语句
(4)function 说明语句
一个程序模块可以包括多个initial 和 always 过程块,它们在仿真一开始同时立即开始执行,initial块只执行一次,always块一直执行;
task 和function 语句可以将一个很大的程序模块分解为小的任务和函数,简化程序结构,方便理解和调试。
(1)initial 说明语句:initial
begin
语句1;
语句2;
……
end
(2)always 说明语句:always <时序控制> <语句>
由于always块是不断活动的,所以必须含有时序控制来控制其后的语句在什么条件下执行,若无条件执行将使仿真器产生死锁。
always 块的触发方式可以是信号沿触发也可以是电平触发,可以是单个信号触发,也可以是多个信号的组合中间用or 连接或者使用','代替
always @ (posedge areg) //areg 信号的上升沿触发
always @ (posedge clock or posedge reset) //clock 信号上升沿或 reset信号的上升沿触发
always @ (a or b or c) //a、b、c 信号的电平触发
always @ (reset , clock , d) //reset、clock、d 信号的电平触发(另一种电平敏感的时序控制是使用Wait 语句)
若always 块对模块的所有输入变量都是敏感的,那么敏感列表可以简写为@ (*) 或 @ *,如 always @ (*) 或 always @ *
函数与任务的不同点:
1)函数智能与主模块共用同一个仿真时间单位,而任务可以定义自己的仿真时间单位
2)函数不能启动任务,而任务可以启动其他任务和函数
3)函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量
4)函数返回一个值,而任务不返回值
(3)task 说明语句:用来定义任务
任务的定义语法:
task<任务名>;
<端口及数据类型声明语句>
<语句1>
<语句2>
……
<语句n>
endtask
任务调用语法:
<任务名>(端口1,端口2……)
(4)function 说明语句:函数的目的是返回一个用于表达式的值;函数的定语蕴含声明了与函数同名的、函数内部的寄存器
函数的定义语法:
function<返回值的类型或范围>(函数名) //返回值的类型或范围 不声明时默认返回值是1位;声明时返回值需与声明的一致
<端口说明语句>
<变量类型说明语句>
begin
<语句>
……
end
endfunction
函数的调用:<函数名>(<表达式>,……<表达式>)
函数的使用规则:
1)函数的定义不能包含任何时间控制语句,即任何使用#,@或wait来标识的语句
2)函数不能启动任务
3)定义函数至少要输入一个变量
4)在函数的内部必须有一条赋值语句,给函数的一个内部变量赋以函数的结果值,该变量与函数同名
2. 系统任务函数:参见书本
1.Verilog HDL程序是由模块组成的。每个模块的内容都是位于module 和 endmodule两个语句之间。每个模块完成特定的功能。
2.模块是可以进行层次嵌套的,因此大型的数字电路可以分割成不同的小模块来实现特定的功能。
3.Verilog模块可以分成两种类型,一种是为了让模块最终能生成电路的结构;另一种是为了测试所设计的电流的逻辑功能是否正确。
4.每个模块都要进行端口的定义,并说明输入、输出口,然后对模块的功能进行描述
5.除了endmodule外的语句都需以分号结尾;类似于C语言的注释语句。
6.若每个模块都是可以综合的,则可以通过综合工具将他们的功能描述全部转换为最基本的逻辑单元描述,最后可以用一个上层模块通过实例引用的方式把这些模块都连接起来,把他们组成一个大的复杂的数字逻辑系统。
二、模块的结构、数据类型、变量和基本运算符号
1、Verilog的基本设计单元是模块(block):(1)描述接口;(2)描述逻辑功能
端口定义: module 模块名(口1,口2,口3,口4……);//模块的端口描述的是输入和输出口名
(1)在被引用时,严格按照模块定义的端口顺序连接,可以不用标明原模块定义时规定的端口名:模块名(连接信号1名,连接信号2名,……)
(2)在引用时用“.”符号,标明原模块定义时的端口名:模块名(.端口1名(连接信号1名),.端口2名(连接信号2名),……)
模块内容:模块内容包括I/O说明,内部信号声明和功能定义
I/O说明:
(1)输入口 input[信号位宽-1:0]端口名1;
input[信号位宽-1:0]端口名2;
(2)输出口 output[信号位宽-1:0]端口名1;
output[信号位宽-1:0]端口名2;
(3)输入输出口
inout[信号位宽-1:0]端口名1;
inout[信号位宽-1:0]端口名2;
内部信号说明:
reg[width-1:0]R变量1,R变量2……
wire[width-1:0]W变量1,W变量2……
功能定义:模块中最重要的部分是逻辑功能的定义部分,有3种方法可在模块中产生逻辑
(1)用“assign”语句声明:如:assign a = b & c;
(2)用实例元件:如:and #2 u1(q,a,b);
(3)用“always”块:如:always @(posedge clk or posedge clr)
begin
if(clr) q<=0;
else if(en) q<=d;
end
always 块既可以描述组合逻辑电路,也可以描述时序逻辑电路;过程块内部是顺序执行的;
要点: (1)在Verilog模块中所有的过程块(如initial块、always块)、连续赋值语句、实例引用都是并行执行的;
(2)只有连续赋值语句assign 和实例引用语句可以独立于过程块而存在于模块的功能定义部分;
2、数据类型及常量、变量
Verilog中共有19种数据类型。数据类型是用来表示数字电路硬件中的数据存储和传送元素的。
常量:运行过程中其值不可改变
数字:
(1)整数
1)二进制整数b或B
2)十进制整数d或D
3)十六进制整数h或H
4)八进制整数o或O
数字的表达方式:
1)<位宽><进制><数字>:如 8’b10101100 //八位二进制数
2)<进制><数字>,此时默认位宽,与机器的系统有关,但至少为32位
3)<数字>,此时默认为十进制
(2)x和z值:x代表不确定值;z代表高阻值。
(3)负数:一个数字被定义为负数,只需在位宽前加一个负号,负号必须写在表达式的最前面:如 -8’d5
(4)下划线:可以用来分隔开数的表达提高可读性,但只能用作具体的数字之间:如8’b1001_1101
参数型:用parameter来定义常量,即用parameter声明一个标识符代表一个常量,称为符号常量。常用于定义延迟时间和变量宽度。在模块和实例引用中可以通过参 数传递改变在被引用模块或实例中已定义的参数,使用defparam。
parameter 参数名1 = 表达式,参数名2 = 表达式……
变量:在程序运行过程中可以改变的量
网络数据类型:标识结构实体之间的物理连接,如果没有驱动器连接到网络类型的变量,则该变量就是高阻的,其值为z值
常用的网络数据类型有 wire 和 tri
wire 型数据通常用来表示单个门驱动或连续赋值语句驱动的网络数据类型。Verilog程序块的输入、输出信号类型默认为wire
wire[7:0] b;
tri 型数据则用来表示多驱动器驱动的网络数据类型。
reg 型:寄存器数据类型,是数据存储单元的抽象;常用来表示“always”模块内的指定信号,常代表触发器(只表示被定义的信号将用在“always”块内)。
reg[n-1:0] rega;
memory型:Verilog 通过对reg型变量建立数组来对存储器建模。
reg[n-1:0]存储器名[m:1]; 如reg[7:0] mema[255:0];定义了名为mema的存储器,它含有256个8位的寄存器。对存储器的mema的访问类似于对数组的访问mema[3],下标索引可以使表达式,但需是常量表达式。
3. 运算符及表达式
(1) 算术运算符(+,-,x,/,%)
(2) 赋值运算符(=,<=)
(3) 关系运算符(>,<,>=,<=)
(4) 逻辑运算符(&&,||,!)
(5) 条件运算符(?:)
(6) 位运算符(~,|,^,&,^~)^~ 按位同或(异或非) ^ 按位异或
(7) 移位运算符(<<,>>)
(8) 拼接运算符({})
(9) 其他
三、 运算符、赋值语句和结构说明语句等基本语法要素
1. 逻辑运算符:与&&、或||、非!
2. 关系运算符:大于>,小于<,大于等于>=,小于等于<=
3. 等式运算符:== 等于,!= 不等于,逻辑等式运算符
=== 等于,!=== 不等于,两个操作数必须完全一致,其结果才为1,否则为0,可以对x和z值进行比较
4. 移位运算符:<<左移,>>右移,都用0填充移除的空位
5. 位拼接运算符: {},用这个运算符可以将多个信号的某些位拼接起来进行运算操作,使用方法如:
{信号1的某几位,信号2的某几位,……信号n的某几位},使用中允许嵌套。
6.因为优先级的关系,建议使用括号,显示的指明运算顺序
7.赋值语句:Verilog中有两种赋值方式
(1)非阻塞型赋值方式:如 b <= a;
1)语句块中,上面的语句所赋值不能立即为下面语句所使用
2)块接收后才能完成此次赋值操作,所赋的变量值是上一次赋值得到的
3)在时序逻辑模块中常用
(2)阻塞型赋值方式: 如 b = a;
1)赋值语句执行完后块才结束
2)b值在赋值语句执行后立即改变
3)在时序逻辑中使用,可能会产生意想不到的结果
8. 块语句:将两条或多条语句组合在一起,使其在格式上更像一条语句。
块语句有两种:
(1)begin-end:
其内语句顺序执行,直到最后一条语句执行完程序流程控制才跳出该语句块;
块内的每条语句的执行时间是相对于前一条语句执行结束开始;
块内声明语句可以是参数声明语句、reg型变量声明语句、integer型变量声明语句和real型变量声明语句。
(2)fork-join:
块内语句并行执行,及程序流程控制一进入到该并行块,块内的语句开始同时执行;
块内的每条语句的执行时间是相对于程序流程控制进入到块内的仿真时间;
延迟时间是用来给赋值语句提供时序的;如 #10 r = ’he4;
当按时间时序排序在最后的一条语句执行完,或disable语句执行完,程序控制流结束跳出该块。
块内声明语句可以是参数声明语句、reg型变量声明语句、integer型变量声明语句、real型变量声明语句、time型变量声明语句和事件(event)声明语句
块名:可以给每个块取一个名字,只需将名字加在关键字begin或fork后面即可,这样做的原因有以下几点:
(1)可以在块内定义局部变量,只在该块内使用
(2)可以允许块被其他语句调用,如disable语句
(3)在Verilog语言里,所有的变量都是静态的,有唯一的存储地址,所以进出块不会影响存储在变量中的值。
起始时刻和结束时刻的概念:注意在顺序块和并行块中,每条语句的执行起始时间,及推出块的时间。
四、 条件语句、循环语句、块语句与生成语句
1. 条件语句 if-else(类似于C语言),if判断的表达式值若为0,x,z按照“假”处理,若为1,按照“真”处理
注意if-else 和 begin-end的嵌套使用,若书写不当可能会导致逻辑行为改变
2. 多分支选择语句:case语句(类似于C语言)
(1)case(表达式) <case分支项> endcase
(2)casex(表达式) <case分支项> endcase
(3)casez(表达式) <case分支项> endcase
case分支项的一般格式:
分支表达式 语句;
默认项(default) 语句;
3. 循环语句:Verilog中存在着4种循环语句,用来控制执行语句的执行次数。
(1)forever 语句:连续的执行语句;不能独立写在程序中,必须写在initial块中
格式:1)forever 语句;
或forever begin 多条语句 end
(2)repeat 语句:连续执行一条语句n次
格式:1)repeat 语句;
或repeat begin 多条语句 end
(3)while 语句:执行一条语句直到某个条件不满足
格式:1)while(表达式) 语句;
或while(表达式) begin 多条语句 end
(4)for 语句:类似于C语言
格式:1)for(表达式1,表达式2,表达式3)语句;
4.顺序块和并行块
块语句的作用是将多条语句合并成一组,使他们像一条语句一样。Verilog 的块语句两种类型:顺序块和并行块
(1)顺序块:关键字begin-end 用于将多条语句组成顺序块。
特点:1)顺序块中的语句是一条接一条按顺序执行的
2)如果语句包括延迟或事件控制,那么延迟总是相对于前面那条语句执行完成的仿真时间的
(2)并行块:并行块由关键字fork-join 声明
特点:1)并行块内的数据是并发执行的
2)语句执行的顺序是由各自语句内延迟或事件控制决定的
3)语句中的延迟或事件控制是相对于块语句开始执行的时刻而言的
二者最主要的区别就是,程序控制流程转入块时,并行块中的所有语句是并发执行的,与语句的先后顺序无关
(3)块语句的特点:嵌套块、命名块和命名块的禁用
1)嵌套块:块可以嵌套使用,顺序块和并行块可以混合在一起使用
2)命名块:块可以具有自己的名字,这称命名块
特点:命名块中可以声明局部变量;
命名块时设计层次的一部分,命名块中声明的变量可以通过层次名引用进行访问;
命名块可以被禁用,例如停止其执行;
3)命名块的禁用:disable 语句
5.生成块
生成语句可以动态的生成Verilog代码;生成语句能够控制变量的声明、任务或函数的调用,还能对实例引用进行全面的控制。
关键字 generate - endgenerate
3种创建生成语句的方法: (1)循环生成
(2)条件生成
(3)case生成
小结:
(1)结构化的过程块,即initial块和always块,构成了行为级建模的基础。其他所有的行为语句只能出现在这两种块中。initial块只执行一次,always块一直执行。
(2)Verilog 中控制时序和语句执行顺序的3种方式是:基于延迟的时序控制、基于事件的时序控制、电平敏感的时序控制
(3)基于延迟的时序控制包括3种形式:常规延迟、0延迟、内嵌延迟
(4)基于事件的时序控制包括:常规事件、命名事件、OR事件
(5)Wait 语句用于电平敏感的时序控制
五、结构语句、系统任务、函数语句和显示系统任务
1. 结构说明语句
Verolog 语言中任何过程模块后从属于以下4种结构的说明语句:
(1)initial 说明语句
(2)always 说明语句
(3)task 说明语句
(4)function 说明语句
一个程序模块可以包括多个initial 和 always 过程块,它们在仿真一开始同时立即开始执行,initial块只执行一次,always块一直执行;
task 和function 语句可以将一个很大的程序模块分解为小的任务和函数,简化程序结构,方便理解和调试。
(1)initial 说明语句:initial
begin
语句1;
语句2;
……
end
(2)always 说明语句:always <时序控制> <语句>
由于always块是不断活动的,所以必须含有时序控制来控制其后的语句在什么条件下执行,若无条件执行将使仿真器产生死锁。
always 块的触发方式可以是信号沿触发也可以是电平触发,可以是单个信号触发,也可以是多个信号的组合中间用or 连接或者使用','代替
always @ (posedge areg) //areg 信号的上升沿触发
always @ (posedge clock or posedge reset) //clock 信号上升沿或 reset信号的上升沿触发
always @ (a or b or c) //a、b、c 信号的电平触发
always @ (reset , clock , d) //reset、clock、d 信号的电平触发(另一种电平敏感的时序控制是使用Wait 语句)
若always 块对模块的所有输入变量都是敏感的,那么敏感列表可以简写为@ (*) 或 @ *,如 always @ (*) 或 always @ *
函数与任务的不同点:
1)函数智能与主模块共用同一个仿真时间单位,而任务可以定义自己的仿真时间单位
2)函数不能启动任务,而任务可以启动其他任务和函数
3)函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量
4)函数返回一个值,而任务不返回值
(3)task 说明语句:用来定义任务
任务的定义语法:
task<任务名>;
<端口及数据类型声明语句>
<语句1>
<语句2>
……
<语句n>
endtask
任务调用语法:
<任务名>(端口1,端口2……)
(4)function 说明语句:函数的目的是返回一个用于表达式的值;函数的定语蕴含声明了与函数同名的、函数内部的寄存器
函数的定义语法:
function<返回值的类型或范围>(函数名) //返回值的类型或范围 不声明时默认返回值是1位;声明时返回值需与声明的一致
<端口说明语句>
<变量类型说明语句>
begin
<语句>
……
end
endfunction
函数的调用:<函数名>(<表达式>,……<表达式>)
函数的使用规则:
1)函数的定义不能包含任何时间控制语句,即任何使用#,@或wait来标识的语句
2)函数不能启动任务
3)定义函数至少要输入一个变量
4)在函数的内部必须有一条赋值语句,给函数的一个内部变量赋以函数的结果值,该变量与函数同名
2. 系统任务函数:参见书本