三、systemverilog过程语句

过程语句

文章目录

  • 过程语句
    • initial
    • always
    • final语句

  • 什么是 域?

在SV中,为了区分硬件设计和软件的世界,我们将定义的软件变量或者例化的硬件所在的空间称之为 “域”。
因此,module/endmodule,interface/endinterface可以被视为硬件世界,program/endprogram和class/endclass可以被视为软件世界。掌握了这一清晰的概念,有助于分析initial和always的使用域。

initial

注:initial从其执行路径的属性来看,它不应该存在于硬件设计代码中,它本身不可综合,对于描述电路没有任何帮助,initial就是为了测试而生的,由于测试需要按照时间顺序的习惯即软件方式来完成,多以initial便可以实现这一要求,initial过程块可以在module、interface、program中使用。

initial语句在仿真一开始就立刻开始执行(0时刻),之后如果遇到延时,则延时之后执行接下来的语句,每个initial语句只执行一次。如下例:

initial  //语句块内含2条或以上语句需要使用begin…end或
   begin
     statement1;//可以是过程赋值语句/分支语句
     statement2; //循环语句,等待语句,顺序执行语句/并行执行语句..   ; 
     statementN;
   end

注意:

  1. 可以有多个(任意多)initial块。多个initial块并行执行,每个块的执行是独立的。
  2. 包含多条语句的initial过程块需要使用begin…end或fork…join块将这些语句封装成语句块块。
  3. 常用于测试模块,虚拟模块的编写,用于产生仿真测试激励信号,信号初始化等仿真环境。
module example_initial;
  reg clk;
  reg a,b;
  initial begin
    clk=1’b0;
    #2 a=1;
    #3 b=1;
    #5 a=1;
    b=1
  end
endmodule

always

always块是Verilog中用来描述组合逻辑以及时序逻辑的语法。
需要补充的是一个设计中可以有多个always块,或者说一定有很多个always块。
这些硬件块都是相互独立同时工作的。每个块之间的连接是决定数据流的原因。为了模拟这种行为,一个always块被做成一个连续的过程(硬件不可能断断续续工作),当敏感列表中的一个信号变化时,它就会被触发并执行一些动作(always块内的语句)。

always是为了描述硬件的行为,多用于设计之中。需要注意的是,它有两种使用方式
1、用于时序逻辑电路描述:敏感信号列表应该出现的是 时钟信号
2、用于组合逻辑电路描述:敏感信号列表没有时钟信号

什么是敏感列表?
敏感列表就是触发always块内部语句的条件。
在下面的代码中,每当信号a或b的值发生变化时,always块中的所有语句都会被执行。

// Execute always block whenever value of "a" or "b" change
always @ (a or b) begin
	[statements]
end

always中的@(event)敏感列表是为了描述硬件信号的触发行为。
所以说,always过程块是用来描述硬件时序电路和组合电路的正确打开方式,因此只可以在module或者interface中使用。

如果没有敏感列表怎么办?
其实,还真的可以没有敏感列表,这是仿真中的用法。我们经常使用没有敏感列表的always来表示不断的触发,用此特性来生成时钟。

always #10 clk = ~clk;

always块内的敏感列表就是为了控制内部语句什么时候触发的。那么可以理解为一种定时,如果没有了敏感列表,则为零延迟,那么就会不断的触发

always  clk = ~clk;

当然,这种没有敏感列表的显示延迟,是不能综合的,只能用于仿真。

  • always_comb, alwasy_ff, always_latch

SystemVerilog对Verilog 的always语句做了扩展,除了always外还有:

  1. always_comb //组合逻辑建模
  2. always_latch //为latch建模
  3. always_ff //为时序逻辑建模
  • always_comb

always_comb用于描述复杂电路,comb是combination组合的意思。该模块中输出是等号的左边,输入是等号的右边。

always_comb内部每条语句都是赋值语句。不能出现电路语句。
always_comb内部描述电路行为。
always_comb有以下性质: 内部覆盖性(如:上例中,a赋值了两遍)
对外原子性(begin…end的内部会影响外面的assign a = b)

assign a = b;
always_comb begin
    b = 1'b1;
    c = a; // 区别于c = b,c = b此处c=1
    b = 1'b0;
end
//对外的结果b=0,a=0,c=0

阻塞赋值

always_comb内部允许if,case等控制语句。

always_comb中的控制语句:case

case语句常用于描述选择器和译码器。case类似于c的switch语句

unique case(独特)

always_comb begin
    b = 1'b0;
    unique case (a[3:0])
        4'd1: begin
            b = 1'b1;
        end
        4'd0: begin
            b = 1'b0;
        end
        default: begin
        	b = 1'b0;
//          b = b;//形成锁存器,该语句不正确
        end
    endcase
end

如果没列举所有情况且没有default,如何?
答:缺少可选择的项,等待,可能形成锁存器

priority case(优先级)
语义上,可以理解为if…else语句

//把常量当case的枚举项,可能出现多项匹配,a[3]和a[2]都可能=1,但是a[3]比a[2]优先级高
always_comb begin
    priority case (1'b1)
        a[3]: begin
            ...
        end
        a[2]: begin
            ...
        end
        default: begin
            ...
        end
    endcase
end

等同于下面的代码

always_comb begin
    if(a[3]) begin
        ...
    end 
    else if(a[2]) begin
        ...
    end 
    else begin  
    	...
    end //...
end

always_comb中的控制语句:if和for
if和for是always_comb中的常用语法。
if和else用于条件判断。

always_comb begin
    if (a[3]) begin
        b = 1'b1;
    end else if (a[2]) begin
        b = 1'b0;
    end else begin
        b = 1'b0;
    end
end

for
for在always_comb中,会被解释为循环展开。
for相关的语句:break,continue

logic [15:0]a;
logic [3:0] b;
//interger i;//此处是全局变量
always_comb begin
    b = '0;
    for (int i = 15; i >= 0; i--) begin//把i放在内部声明,是局部变量
        if (a[i]) begin
            b = i[3:0];
            break;
        end
    end
end

for和if即可表示行为,也可生成电路。

always_comb begin
    for (int i = 0; i < 16; i++) begin
        a[i] = b[i] & (c[i] == d[i] | e[i]); // 编译器不认为i是常数,a[i:i+3]非法
    end
end

for (genvar i = 0; i < 16; i++) begin
    assign a[i] = b[i] & (c[i] == d[i] | e[i]); // 编译器认为i是常数,a[i:i+3]合法
    always_comb begin
        
    end
end

  • always_ff

always_ff用于可综合时序逻辑的建模。

必须带由posedge或者negedge所定义的敏感列表。通常就是@(posedge clk, negedge rst).

在always_ff块中只能使用非阻塞赋值。

final语句

1.final块类似于intial块,它们都定义了一个过程化的语句块,不同的是,final块仅仅在仿真结束前执行。典型情况下,final块用来显示有关仿真的统计信息。
2. 在final块中可以使用的语句同允许在一个函数声明中使用的语句一样。与intial块不同,final块不会作为一个单独的进程执行。
3. 当一个显式或隐式的$finish调用引起仿真结束的时候会执行final块。
4. final块只能在一次仿真中触发一次

finial语句示例如下:

final
   begin
        $display("Number of cyclesexecuted %d",$time/period);
        $display("Final PC = %h",PC);
   end

initial begin
   …
   $finish();
end

你可能感兴趣的:(systemverilog,其他)