SV 过程块

过程块

scope

  在SV中,哪些语句应该放在硬件世界,哪些语句应该属于软件世界。将软件变量定义与硬件例化所在的空间称之为域。

  硬件域:例化硬件的空间

  • module ... endmodule
  • interface ... endinterface

  软件域:定义软件变量的空间

  • program ... endprogram
  • class ...  endclass

语句块

  用来将多个语句组织在一起,使得他们在语法上如同一个语句。

  顺序块:语句置于关键字begin和end之间,块中的语句以顺序方式执行。

  并行块:关键字fork和join/join_any/join_none之间的是并行块语句,块中的语句并行执行。

命名块

  给每个块定义的标识名称,将块名加在begin或fork后面;

  可以定义块内局部变量

  允许定义的块被其他语句调用,如disable语句;

always

  用来描述硬件时序电路和组合电路的正确打开方式,因此只能在 module 或者 interface 中使用;

  用法: always @(敏感信号列表)

initial

  只执行一次;

  initial 和 always一样,无法被延迟执行,在仿真一开始都会同时执行;

  initial 和 always之间在执行顺序上没有顺序可言;

  initial 不可综合,用于测试;

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

  使用 begin ... end 包裹;

function

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

  可以返回数值或者不返回数值(void);如果返回,使用关键字return;

  默认的数据类型是logic,例如  input [7:0] addr;

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

  只有数据变量可以在形式参数列表中被 ref 修饰,线网类型不能;

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

  支持默认值;

function int double_f0(int a);
  return 2*a;
endfunction

function void double_f1(input int a, output int b);
  b = 2*a;
endfunction

function void double_f2(inout int a);
  a = 2*a;
endfunction

function automatic void double_f3(ref int a);
  a = 2*a;
endfunction

initial begin: 
  int v1, v2;
  
  v1 = 10;
  v2 = double_f0(v1);
  $display("v1 = %0d, double function result is %0d", v1, v2);

  v1 = 10;
  double_f1(v1, v2);
  $display("v1 = %0d, double function result is %0d", v1, v2);

  v1 = 10;
  $display("v1 is %0d before calling double_f2(v1)", v1);
  double_f2(v1);
  $display("v1 is %0d (result) after calling double_f2(v1)", v1);

  v1 = 10;
  $display("v1 is %0d before calling double_f3(v1)", v1);
  double_f3(v1);
  $display("v1 is %0d (result) after calling double_f3(v1)", v1);
end

task

  task无法通过return返回结果,只能通过output,inout 或ref的参数返回;

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

  task 中可以调用 task 和 function, 而 function 只能调用function;

task double_t1(input int a, output int b);
  b = 2*a;
endtask

task double_t2(inout int a);
  a = 2*a;
endtask

task automatic double_t3(ref int a);
  a = 2*a;
endtask

task double_t2_delay(inout int a);
  a = 2*a;
  #10ns;
endtask

task automatic double_t3_delay(ref int a);
  a = 2*a;
  #10ns;
endtask

initial begin: 
  int v1, v2;
  
  v1 = 10;
  double_t1(v1, v2);
  $display("v1 = %0d, double task result is %0d", v1, v2);

  v1 = 10;
  $display("v1 is %0d before calling double_t2(v1)", v1);
  double_t2(v1);
  $display("v1 is %0d (result) after calling double_t2(v1)", v1);

  v1 = 10;
  $display("v1 is %0d before calling double_t3(v1)", v1);
  double_t3(v1);
  $display("v1 is %0d (result) after calling double_t3(v1)", v1);
end

inout vs  ref

initial begin: inout_vs_ref
  int v1, v2;
  v1 = 10;
  $display("v1 is %0d before calling double_t2_delay(v1)", v1);
  fork
    double_t2_delay(v1);
    begin #5ns; $display("@%0t v1 = %0d in task call double_t2_delay(v1)", $time, v1); end
  join
  $display("v1 is %0d (result) after calling double_t2_delay(v1)", v1);

  v1 = 10;
  $display("v1 is %0d before calling double_t3_delay(v1)", v1);
  fork
    double_t3_delay(v1);
    begin #5ns; $display("@%0t v1 = %0d in task call double_t3_delay(v1)", $time, v1); end
  join
  $display("v1 is %0d (result) after calling double_t3_delay(v1)", v1);
end

变量生命周期

动态: automatic

  如果数据变量被声明为automatic,那么进入该进程或方法后,automatic变量会被创建,离开进程或方法后被销毁。

静态:static

  全局变量伴随程序执行开始到结束,module中的变量默认情况下全部为全局变量。

  static变量在仿真开始时会被创建,在进程或方法执行过程中,可以被多个进程和方法共享。

static vs automatic

  对于automatic方法,其内部变量默认也是automatic,伴随automatic方法的声明周期建立和销毁。

  对于static方法,其内部的所有变量默认为static类型。

  无论是automatic或者static方法,可以对其内部定义的变量做单个声明。使其类型被显式声明为automatic或static。

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

module tb1;

    function automatic int auto_cnt(input a);
        int cnt =0;
        cnt +=a;
        return cnt;
    endfunction

    function static int static_cnt(input a);
        int cnt=0;
        cnt += a;
        return cnt;
    endfunction

    function int def_cnt(input a);
        int cnt=0;
        cnt += a;
           return cnt;
    endfunction

    function int def_cnt_a(input a);
        automatic int cnt=0;
        cnt += a;
        return cnt;
    endfunction

    initial begin
        $display("@1  auto_cnt=%0d",   auto_cnt(1));
        $display("@2  auto_cnt=%0d",   auto_cnt(1));
        $display("@1  static_cnt=%0d", static_cnt(1));
        $display("@2  static_cnt=%0d", static_cnt(1));
        $display("@1  def_cnt=%0d",    def_cnt(1));
        $display("@2  def_cnt=%0d",    def_cnt(1));
        $display("@1  def_cnt_a=%0d",  def_cnt_a(1));
        $display("@2  def_cnt_a=%0d",  def_cnt_a(1));
    end
endmodule

/*
result
@1  auto_cnt=1
@2  auto_cnt=1
@1  static_cnt=1
@2  static_cnt=2
@1  def_cnt=1
@2  def_cnt=2
@1  def_cnt_a=1
@2  def_cnt_a=1
*/

 

 

 

 


 

posted @ 2021-04-02 15:07  徘徊的游鱼  阅读(423)  评论(0编辑  收藏  举报