Systemverilog always_comb 过程块


前言

 这一篇文章主要比较Verilog always块与Systemverilog 中的always_comb、always_ff、always_latch块的区别。

一、Verilog always与Systemverilog always_comb、always_latch、always_ff对比

 1、Verilog中使用always过程块表示锁存逻辑和组合逻辑的区别:
 always表示锁存逻辑的情况:
 过程块中赋值的变量至少有一个不能被某些输入条件更新。
 always表示组合逻辑的情况:
 所有在过程块中赋值的变量必须随所有可能的输入组合变量而更新。(if else 要完整)  因为Verilog的always过程块是通用的,因此不能强制其他软件工具也采用这些综合原则,比如,仿真工具必须允许always 过程块能够灵活地使用,不必遵循综合编译器的使用方式,因为always过程块的仿真和综合不依照同样的语法规则,所以如果设计者没有遵循严格的、自我约束的建模规则的情况下,自然会发生仿真和综合结果不一致的情况,形式验证工具也可能会要求设计遵循自我约束的建模规则来避免仿真结果和形式验证结果的不一致。
 Systemverilog 新加入了3个特有的过程块,用来减少通用always过程块建模硬件时的不确定性,它们是always_comb、always_ff、always_latch。
 Verilog和Systemverilog 关于锁存器建模的区别
Verilog
always @(a,en)
  if(en) y=a;
Systemverilog
always_comb
 if(en) y=a;

 分析:
 从always_comb这个关键字出发,软件工具就能够明确设计者想要对组合逻辑建模,并且给出一个警告信息,指出在硬件实现该功能块时会产生一个锁存器。
 在上面的例子中,如果想得到组合逻辑,正确的描述应该包括一个else分支,这样输出y就能够在en的条件下更新。

二、零时刻自动求值

1、 always_comb 与 always不同

 always_comb过程块与always过程块的另一个不同之处在于,在所有initial和always过程块启动后,always_comb块会在仿真的零时刻自动触发,不管推断出的敏感表中的信号是否发生了变化,这样的自动求值都会发生。always_comb的这种特殊的语义确保了组合逻辑在零时刻产生与输入相对应的输出结果,特别是在使用缺省值为逻辑0的两态变量建模时,这种零时刻的自由自动求值尤为重要,复位信号很可能不会引起组合逻辑的敏感表中的信号发生变化,而如果没有变化,通用always过程块不会被触发,从而使输出变量也不会变化。
 代码如下:
module controller(output logic read,write,
                  input instr_t instruction,
                  input logic clk,resetN);
enum {WAITE,LOAD,STORE} State,NextState;

always @(posedge clk or negedge resetN)
  if(!resetN)
    State <= WAITE;
  else
   State  <= NextState;
 //always_comb
always @(State) begin
  case (State)
   WAITE: NextState=LOAD;
   LOAD:  NextState=STORE;
   STORE: NextState=WAITE;
   endcase
 end
always @(State,instruction) begin
 read=0;write=0;    //初始值 防止生成锁存器
 if(State==LOAD && instruction ==FETCH)
   read=1;
 else if(State==STORE && instruction == WRITE) 
   write=1;
end
endmodule

由于read=0,write=0,所以即时if没有else的分支,
也不会有锁存器生成。

 这个仿真会有一个微秒的结果,在仿真的零时刻,枚举类型变量默认为枚举类型基类的缺省值。除非显式声明,否则基类为两态int类型,仿真开始时int的初始值为0,这也是枚举值列表中WAITE的值。因此,变量State和NextState的缺省值都为WAITE,在clk的上升沿,状态时序逻辑会将NextState的值赋给State,由于两个变量的值是一样的,所以赋值后State的值实际上并没有变化,而正因为State没有发生变化,也就不会触发always@(State)过程块,导致变量NextState的值不断更新,这样变量State和NextState的值始终相同,导致此模型的仿真结果锁定。
 使用always_comb

module controller(output logic read,write,
                  input instr_t instruction,
                  input logic clk,resetN);
enum {WAITE,LOAD,STORE} State,NextState;

always @(posedge clk or negedge resetN)
  if(!resetN)
    State <= WAITE;
  else
   State  <= NextState;
 //always_comb
always_comb  begin
  case (State)
   WAITE: NextState=LOAD;
   LOAD:  NextState=STORE;
   STORE: NextState=WAITE;
   endcase
 end
always @(State,instruction) begin
 read=0;write=0;    //初始值 防止生成锁存器
 if(State==LOAD && instruction ==FETCH)
   read=1;
 else if(State==STORE && instruction == WRITE) 
   write=1;
end
endmodule

 当所有过程块启动之后,always_comb过程块会在仿真零时刻自动执行一次,也就是说在仿真零时刻,这个例子中的变量NextState会更新为与变量State值相对应的新值。当第一个时钟上升沿来临之后,State的值变为NextState的值,这个值与原来的State值不同的,这种变化会触发always_comb过程块,然后更新NextState值对应新的State的值。

2.always_comb 和 always@*的比较

 与always相比always_comb敏感列表包含函数的读取信号。
always_comb过程块会对data、sel、c、d和e敏感

always @* begin
 a1 = data << 1;
 b1 = decode();
end

//推断出@(data)

always_comb begin
 a2 = data << 1;
 b2 = decode();
end

//推断出@(data,sel,c,d,e)

function decode; //不带输入的函数
 begin
 case(sel)
 2'b01: decode = d| e;
 2'b10: decode = d & e;
default: decode = c;
 endcase
 end
 endfunction

总结

 always与always_comb最大的区别在于,是否是零时刻触发,上面的代码例子很形象地说明由于always不会在零时刻自动触发,所以产生了死锁。
  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值