Verilog结构语句和函数、任务语句

目录

结构说明语句

initial说明语句

always说明语句

task和function说明语句 

task说明语句

function说明语句

关于使用任务和函数的小结


结构说明语句

Verilog语言中的任何过程模块都从属于以下4种结构的说明语句:

initial说明语句

一个模块种可以有多个initial块,它们都是并行运行的,initial块常用于测试文件和虚拟模块的编写,用来产生仿真测试信号和设置信号记录等仿真环境。

initial语句只执行一次,而always语句则不断地重复活动着,直到仿真过程结束。

initial语句的格式如下:

initial
    begin
        语句1;
        语句2;
        ...
        语句n;
    end    

always说明语句

always@(敏感事件列表)用于描述时序逻辑

敏感事件上升沿posedge,下降沿negedge,或电平敏感事件列表中可以包含多个敏感事件,但不可以同时包括电平敏感事件和边沿敏感事件,也不可以同时包括同一个信号的上升沿和下降沿,这两个事件可以合并为一个电平敏感事件。

always语句在仿真过程中是不断活动着的。但always语句后面跟着的过程块是否执行,则要看它的触发条件是否满足,如满足则运行一次,如不断满足,则不断地循环执行。其声明格式如下:

  always <时序控制> <语句>,always语句由于其不断活动的特性,只有和一定的时序控制结合在一起才有用,如果一个always语句没有时序控制,则这个always语句将会使仿真器产生死锁。

always的时间控制可以是沿触发也可以是电平触发的,可以单个信号也可以多个信号,中间需要使用关键字or连接。

沿触发的always块常常描述时序行为,如有限状态机。如果符合可综合风格要求,则可通过综合工具自动地将其转换为表示寄存器组和门级组合逻辑的结构,而该结构应具有时序要求,而电平触发的always语句块常常用来描述组合逻辑的行为,如果符合可综合风格结构,综合工具自动转换为组合逻辑的门级结构或带锁存器的组合逻辑。

  • always块的OR事件控制

关键词or连接多个事件名或者信号名组成的列表称为敏感列表,关键词or被用来表示这种关系,或者使用(,)来代替or。如果组合逻辑的敏感列表包括很多信号,可以使用@(*)或者@ *来表示后面语句块中所有输入变量的变化是敏感的。

  • 电平时序控制

Verilog同时也允许使用另外一种形式表示的电平敏感时序控制(即后面的语句和语句块需要等待某个条件为真才能执行),Verilog用关键字wait来表示等待电平敏感的条件为真。

always 
    wait(count_enable)  #20 count = count+1;

上面的例子中,仿真器连续监视count_enable信号的值,若值为0,则不执行后面的语句,仿真会停顿下来,若其值为1,则在20个时间单位之后执行后面的语句,如果一直为1,那么count每隔20个时间单位加1. 

凡是always块内输出,都要定义为reg型的。由这一点也可以看出,定义reg型的对应的电路结构不一定是寄存器。

task和function说明语句 

task和function说明语句的不同点

任务和函数是不同的,主要的不同主要有以下4点:

  1. 函数只能和主模块共用同一个仿真时间单位,而任务可以自定义自己的仿真时间单位。
  2. 函数不能启动任务,而任务可以启动其他任务和函数。
  3. 函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量。
  4. 函数返回一个值,而任务不返回值。

网上说:task和function综合出来的电路都是组合电路。

函数的目的是通过返回一个值来响应输入信号的值。任务却能支持多种目的,能计算多个结果值,这些结果值只能通过被调用的任务的输出或总线端送出。Verilog使用函数时是把它当作表达式中的操作符,这个操作的结果值就是这个函数的返回值。

假定任务或者函数名为switch_bytes

switch_bytes(old_byte,new_byte) //任务调用
new_byte = switch_bytes(old_byte) //函数调用

task说明语句

1、任务的定义 定义任务的语法如下:

task <任务名>;
    <端口及数据类型声明语句>
    <语句1>
    <语句2>
    ...
    ...
    <语句n>
endtask

 2、任务的调用及变量的传递 启动任务并传递输入、输出变量的声明语句的语法如下:

任务的调用:

                <任务名>(端口1,端口2,端口3,....,端口n)

  • module里可以含有task,但task里不可含有module;
  • task极少用在可综合的设计中.因为task不支持always@xxxxxx,所以不能象c的函数那样用.当然,task用在testbench很方便;【这块有点不懂,是彻底不支持always还是不支持常用always实现的时序逻辑呢?】
  • task module之间的区别:主要的区别在于module可以实现很复杂的功能,里面可以包括时序和组合等各种设计要素;然而task却不可以,task里面不可以有always这样的语句,亦即task即使实现某种逻辑功能,也只能实现组合逻辑功能(如果写成module就不局限于此)。还有task可以自己调用自己,并且这样也有可能是可综合的;而module是不可以自己例化自己的,这是不合法的,更不要说可否综合。

function说明语句

函数的目的是返回一个用于表达式的值

1、定义函数的语法

function <返回值的类型或范围> (函数名);
    <端口说明语句>
    <变量类型说明语句>
    begin
    <语句>
    ...
    end
endfunction

返回值的类型或范围是一项可选项,如默认则返回为一位寄存器类型数据。 

2、从函数返回的值:函数的定义蕴含声明了与函数同名的,函数内部的寄存器。如在函数的声明语句中,默认为一位寄存器型

3、函数的调用:函数的调用是通过将函数作为表达式中的操作数来实现的。其调用格式如下:

<函数名> (<表达式1>,...,<表达式>)

4、函数的使用规则:与任务相比函数的使用有较多的约束,下面给出的是函数的使用规则:

  • 函数的定义不能包含有任何的时间控制语句(即任何用# @或wait来标识的语句)
  • 函数不能启动任务
  • 定义函数时至少要有一个输入变量
  • 在函数的定义中必须有一条赋值语句给函数中的一个内部变量赋以函数的结果值,该内部变量具有和函数名相同的名字。

自动递归函数

若在函数声明中使用了关键字automatic,那么该函数将成为自动的或可递归的,即仿真器为每一次函数调用动态地分配新的地址空间,每一个函数调用对各自的地址空间进行操作,因此,自动函数的局部变量不能通过层次名进行访问,而自动函数本身可以通过层次名来访问。

常量函数

常量函数实际上是一个带有某些限制的常规Verilog函数,这种函数能够用来引用复杂的值,因而可以用来代替常量。

关于使用任务和函数的小结

  1. 任务和函数都是用来对设计中多处使用的公共代码进行定义,使用任务或函数可以将模块分割成许多个可独立管理的子单元,增强了模块的可读性和可维护性。
  2. 任务可以具有任意个输入、输入/输出,输出变量,在任务中可以使用延迟时间和时序控制结构,在任务中可以调用其他的任务和函数。
  3. 可重入任务使用关键字automatic进行定义,它的每一次调用都对不同的地址空间进行 操作
  4. 函数只能有一个返回值,并且至少有一个输入变量,在函数中不能使用延迟,事件、和时序控制结构,但可以调用其他函数不能调用任务。
  5. 当声明函数时,Verilog仿真器都会隐含的声明一个同名的寄存器变量,函数的返回值通过这个寄存器传递回调用处。
  6. 递归函数使用关键字automatic进行定义,递归函数的每一次调用都拥有不同的地址空间。
  7. 任务和函数都包含在设计层次中,都可以通过层次名进行调用。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值