第三章 Verilog HDL 基本语法
--------------------------------------------------------------------------------------------------------------------------------------------------
任务可以启动其它的任务,其它任务又可以启动别的任务,可以启动的任务数是没有限制的。不管有多少任务启动,只有当所有的启动任务完成以后,控制才能返回。
1) 任务的定义
定义任务的语法如下: 任务:
task <任务名>;
<端口及数据类型声明语句> <语句1> <语句2> ..... <语句n> endtask
这些声明语句的语法与模块定义中的对应声明语句的语法是一致的。 2) 任务的调用及变量的传递
启动任务并传递输入输出变量的声明语句的语法如下: 任务的调用:
<任务名>(端口1,端口2,...,端口n);
下面的例子说明怎样定义任务和调用任务: 任务定义:
task my_task; input a, b; inout c; output d, e; …
<语句> //执行任务工作相应的语句 …
c = foo1; //赋初始值 d = foo2; //对任务的输出变量赋值t e = foo3; endtask
任务调用:
my_task(v,w,x,y,z);
任务调用变量(v,w,x,y,z)和任务定义的I/O变量(a,b,c,d,e)之间是一一对应的。当任务启动时,由v,w,和x.传入的变量赋给了a,b,和c,而当任务完成后的输出又通过c,d和e赋给了x,y和z。下面是一个具体的例子用来说明怎样在模块的设计中使用任务,使程序容易读懂:
module traffic_lights;
reg clock, red, amber, green;
parameter on=1, off=0, red_tics=350, amber_tics=30,green_tics=200;
//交通灯初始化
initial red=off; initial amber=off; initial green=off; //交通灯控制时序
always begin
red=on; //开红灯
47
第三章 Verilog HDL 基本语法
--------------------------------------------------------------------------------------------------------------------------------------------------
light(red,red_tics); //调用等待任务 green=on; //开绿灯 light(green,green_tics); //等待 amber=on; //开黄灯 light(amber,amber_tics); //等待
end
//定义交通灯开启时间的任务 task light(color,tics); output color; input[31:0] tics; begin
repeat(tics) @(posedge clock);//等待tics个时钟的上升沿 color=off;//关灯 end endtask
//产生时钟脉冲的always块 always begin
#100 clock=0; #100 clock=1; end endmodule
这个例子描述了一个简单的交通灯的时序控制,并且该交通灯有它自己的时钟产生器。
二. function说明语句
函数的目的是返回一个用于表达式的值。
? 定义函数的语法:
function <返回值的类型或范围> (函数名);
<端口说明语句>
<变量类型说明语句>
begin <语句> ........ end
endfunction
请注意<返回值的类型或范围>这一项是可选项,如缺省则返回值为一位寄存器类型数据。下面用例子说明:
function [7:0] getbyte; input [15:0] address; begin
<说明语句> //从地址字中提取低字节的程序
getbyte = result_expression; //把结果赋予函数的返回字节 end
endfunction
? 从函数返回的值
函数的定义蕴含声明了与函数同名的、函数内部的寄存器。如在函数的声明语句中<返回值
的类型或范围>为缺省,则这个寄存器是一位的,否则是与函数定义中<返回值的类型或范围>一致的
48
第三章 Verilog HDL 基本语法
--------------------------------------------------------------------------------------------------------------------------------------------------
寄存器。函数的定义把函数返回值所赋值寄存器的名称初始化为与函数同名的内部变量。下面的例子说明了这个概念:getbyte被赋予的值就是函数的返回值。
? 函数的调用
函数的调用是通过将函数作为表达式中的操作数来实现的。 其调用格式如下:
<函数名> (<表达式><,<表达式>>*)
其中函数名作为确认符。下面的例子中通过对两次调用函数getbyte的结果值进行位拼接运算来生成一个字。
word = control? {getbyte(msbyte),getbyte(lsbyte)} : 0;
? 函数的使用规则
与任务相比较函数的使用有较多的约束,下面给出的是函数的使用规则:
1) 函数的定义不能包含有任何的时间控制语句,即任何用#、@、或wait来标识的语句。 2) 函数不能启动任务。
3) 定义函数时至少要有一个输入参量。
4) 在函数的定义中必须有一条赋值语句给函数中的一个内部变量赋以函数的结果值,该内
部变量具有和函数名相同的名字。
? 举例说明
下面的例子中定义了一个可进行阶乘运算的名为factorial的函数,该函数返回一个32位的寄存器类型的值,该函数可后向调用自身,并且打印出部分结果值。
module tryfact;
//函数的定义------------------------------- function[31:0]factorial; input[3:0]operand; reg[3:0]index; begin
factorial = operand? 1 : 0;
for(index=2;index<=operand;index=index+1) factorial = index * factorial; end
endfunction
//函数的测试------------------------------------- reg[31:0]result; reg[3:0]n; initial begin
result=1;
for(n=2;n<=9;n=n+1) begin
$display(\result = n * factorial(n)/((n*2)+1); end
$display(\end
endmodule//模块结束
前面我们已经介绍了足够的语句类型可以编写一些完整的模块。在下一章里,我们将举许多实际的例子进行介绍。这些例子都给出了完整的模块描述,因此可以对它们进行仿真测试和结果检验。通过学习和练习我们就能逐步掌握利用Verilog HDL设计数字系统的方法和技术。
49
第三章 Verilog HDL 基本语法
--------------------------------------------------------------------------------------------------------------------------------------------------
3.8.系统函数和任务
Verilog HDL语言中共有以下一些系统函数和任务:
$bitstoreal, $rtoi, $display, $setup, $finish, $skew, $hold, $setuphold, $itor, $strobe, $period, $time, $printtimescale,
$timefoemat, $realtime, $width, $real tobits, $write, $recovery,
在Verilog HDL语言中每个系统函数和任务前面都用一个标识符$来加以确认。这些系统函数和任务提供了非常强大的功能。有兴趣的同学可以参阅附录:Verilog语言参考手册。下面对一些常用的系统函数和任务逐一加以介绍。
3.8.1.$display和$write任务 格式:
$display(p1,p2,....pn); $write(p1,p2,....pn);
这两个函数和系统任务的作用是用来输出信息,即将参数p2到pn按参数p1给定的格式输出。参数p1通常称为“格式控制”,参数p2至pn通常称为“输出表列”。这两个任务的作用基本相同。$display自动地在输出后进行换行,$write则不是这样。如果想在一行里输出多个信息,可以使用$write。在$display和$write中,其输出格式控制是用双引号括起来的字符串,它包括两种信息:
? 格式说明,由\和格式字符组成。它的作用是将输出的数据转换成指定的格式输出。
格式说明总是由“%”字符开始的。对于不同类型的数据用不同的格式输出。表一中给出了常用的几种输出格式。
表一 输出格式 说明 %h或%H 以十六进制数的形式输出 %d或%D 以十进制数的形式输出 %o或%O 以八进制数的形式输出 %b或%B 以二进制数的形式输出 %c或%C 以ASCII码字符的形式输出 %v或%V 输出网络型数据信号强度 %m或%M 输出等级层次的名字 %s或%S 以字符串的形式输出 %t或%T 以当前的时间格式输出 %e或%E 以指数的形式输出实型数 %f或%F 以十进制数的形式输出实型数 %g或%G 以指数或十进制数的形式输出实型数 无论何种格式都以较短的结果输出
? 普通字符,即需要原样输出的字符。其中一些特殊的字符可以通过表二中的转换序列来输
出。下面表中的字符形式用于格式字符串参数中,用来显示特殊的字符。
50
第三章 Verilog HDL 基本语法
--------------------------------------------------------------------------------------------------------------------------------------------------
表二: 换码序列 功能 \\n 换行 \\t 横向跳格(即跳到下一个输出区) \\\\ 反斜杠字符\\ \\\双引号字符\\\o 1到3位八进制数代表的字符 %% 百分符号%
在$display和$write的参数列表中,其“输出表列”是需要输出的一些数据,可以是表达式。下面举几个例子说明一下。
[例1]:module disp;
initial begin
$display(\end endmodule
输出结果为
\\% \
从上面的这个例子中可以看到一些特殊字符的输出形式(八进制数123就是字符S)。
[例2]:module disp;
reg[31:0] rval; pulldown(pd); initial begin
rval=101;
$display(\$display(\
$display(\$display(\$display(\
$display(\$display(\end
endmodule
其输出结果为:
rval=00000065 hex 101 decimal
rval=00000000145 octal 00000000000000000000000001100101 binary rval has e ascii character value pd strength value is StX current scope is disp e is ascii value for 101 simulation time is 0
输出数据的显示宽度
51