过程块和方法

        域(scope):为了区分硬件设计、软件世界,将定义的软件变量或者例化的硬件其所在的空间称之为域。module/endmodule,interface/endinterface可以被视为硬件世界,program/endprogram和class/endclass可以被视为软件世界

initial和always

  • always是为了描述硬件行为,而在使用时需要注意哪种使用方式是时序电路(寄存器、锁存器)描述,哪种使用方式是组合电路描述。initial不可综合(为测试而生),always可综合。

  • always中的@(event..)敏感列表是为了模拟硬件信号的触发行为,需正确对标硬件行为和always过程块描述。

  • initial符合软件的执行方式,只执行一次。一般初始化就在软件中(initial)或定义时。

  • initial和always一样,无法被延迟执行,即在仿真一开始它们会同时执行,不同initial和always之间在执行顺序上没有顺序可言

  • initial从执行路径属性来看,不应该存在于硬件设计代码中,它本身不可综合,对于描述电路没有任何帮助

  • initial就是为了测试而生,由于测试需要按照时间顺序的习惯即软件方式来完成,所以initial便可以实现这一要求

  • 所有测试语句都可以放置在initial中,为了便于统一管理测试顺序,建议将有关测试语句都放置在同一个initial过程块中

  • initial过程块可以在module、interface和program中使用

  • 对于过程块的书写,用begin..end将作用域包住,同样适用于控制语句、循环语句等

function

  • 可以在参数列表中指定输入参数(input)、输出函数(output)、输入输出函数(inout)或者引用参数(ref)

  • 可以返回数值或者不返回数值(void)

function int double (input a);  //输入为a,double变量,返回int
   return 2*a;
endfunction

initial begin
     $display("double of %0d is %0d",10,double(10));
end
  • 默认数据类型为logic,如input[7:0] addr

  • 数组可以作为形式参数传递

  • function可以返回或者不返回结果,如果返回即需要用关键词return。如果不返回则应该在声明function时采用void function()

  • 只有数据变量可以在形式参数列表中被声明为ref类型,而线网类型不能被声明为ref类型         //验证里面只能传递变量,不能传递硬件的信号和存储器

  • 在使用ref类型时,有时候为了保护数据对象只被读取不被写入,可以通过const方式来限定ref声明的参数

  • 在声明参数时,可以给入默认数组,例如input[7:0]addr=0,同时在调用时如果省略该参数的传递,那么默认值即会被传递给function

  • function不标明方向,默认为input

typedef structure{
    bit [1:0] cmd;
    bit [7:0] addr;
    bit [31:0] data;
}trans;
function automatic void op_copy(trans t,trans s);  //此时,t和s都默认为input
    t=s;
endfunction
initial begin
    trans s;
    trans t;
    s.cmd='h1;
    s.addr='h10;
    s.data='h100;
    op_copy(t,s);  //调用函数,退出后s得到三个参数为{0,0,0}
    t.cmd='h2;
end

task

  • task无法通过return返回结果,因此只能通过output、inout或ref的参数来返回

  • task内可以置入耗时语句,而function则不能。常见的耗时语句包括@event、wait event、#delay等。 

task mytask1 (output logic [31:0] x,input logic y);
...
endtask 

注意:

  • task可以内置耗时语句

  • 非耗时方法定义时使用function,在内置耗时语句时使用task。可以知道function只能应用于纯粹的数字或者逻辑运算,而task则可能会被应用于需要耗时的信号采样或者驱动场景

  • 如果要调用function,则使用function和task均可对其调用;而如果要调用task,建议使用task调用,因为如果调用的task内置有耗时语句,则外部调用它的方法类型必须为task。 

变量生命周期

  • 在sv中,将数据的生命周期分为动态(automatic)和静态(static)

  • 局部变量的生命周期同其所在的域共存亡,例如function、task中的临时变量,在其方法调用结束后,临时变量的生命也将终结,所以它们是动态生命周期

  • 全局变量即伴随着程序执行开始到结束一直存在,例如module中的变量默认情况下全部为全局变量,用户也可理解为module中的变量由于在模拟硬件信号,所以它们是静态生命周期(硬件从仿真0时刻开始就构建好,固定下来)

  • 如果数据变量被声明为automatic,那么在进入该进程/方法后,automatic变量会被创建,而在离开该进程/方法后,automatic变量会自动销毁。而在static变量在仿真开始时即会被创建,而在进程/方法执行过程中,自身不会被销毁,且可以被多个进程和方法所共享。

module  里默认生命周期为static

class       里默认生命周期为automatic,类里需要静态变量

动态变量每次调用都会赋予新值;静态变量则不会;不标明静态或动态默认为静态变量

  • 对于automatic方法,其内部的所有变量默认也是automatic,即伴随automatic方法的生命周期建立和销毁

  • 对于static方法,其内部的所有变量默认也是static类型

  • 对于automatic或者static方法,用户可以对其内部定义的变量做单个声明,使其类型被显式声明为automatic或者static

  • 对于static变量,用户在声明变量时应该同时对其做初始化 ,而初始化只会伴随它的生命周期发生一次,并不会随着方法调用被多次初始化

  • 在module、program、interface、task和function之外声明的变量拥有静态的生命周期,即存在于整个仿真阶段

  • 在module、interface和program内部声明,且在task、process或者function外部声明的变量也是static变量,且作用域在该块中

  • 在module、program和interface中定义的task、function默认都是static类型

  • 在过程块中(task、function、process)定义的变量均跟随它的作用域,即过程块的类型。如果过程块为static,则它们也默认为static,反之亦然。这些变量也可以由用户显式声明为automatic或者static

  • 为了使得在过程块中声明的变量有统一默认的生命周期,可以在定义module、interface、package或者program时,通过限定词automatic或者static来区分。对于上述程序块默认的生命周期类型为static

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值