关于 "case" 语法生成的锁存器

About the latches generated by "case" syntax

我理解在systemverilog 中使用case 语法时,我们需要完整描述所有组合或添加默认值以避免闩锁。

这是我的示例代码,没有生成锁存器:

 module test(
input logic[2:0] op,
output logic a,b,c
);

    always_comb
    begin

    case(op)

     0: {a,b,c} = {1'b1,1'b1,1'b0};
     1: {a,b,c} = {1'b1,1'b0,1'b0};
     2: {a,b,c} = {1'b0,1'b1,1'b0};
     default: {a,b,c} = {1'b0,1'b0,1'b0};
     endcase
     end
     endmodule

正如我一开始所说,如果添加默认值,则不会生成闩锁。 请看第二个代码,这是一个ALU设计:

module ALU(
output logic[31:0] Result,
output logic Zero, Overflow, Negative, Carryout,

input logic [5:0]ALUOp_i,
input logic [31:0] ALU_A_i, ALU_B_i,
input logic [4:0] Shamt
);

logic [31:0] adder_b;

always_comb
begin


  casez(ALUOp_i)

 /*Add_trap*/   0,1: {Carryout,Result} = {ALU_A_i[31],ALU_A_i} + {ALU_B_i[31],ALU_B_i};
 /*Add_notrap*/ 
 /*Subtrap*/    2,3: 
 /*Sub_notrap*/    begin
             adder_b = ALU_B_i ^ {32{1'b1}};
             {Carryout,Result} = {ALU_A_i[31],ALU_A_i} + {adder_b[31],adder_b} + 1;
           end

/*SLL*/         8: Result = ALU_B_i << Shamt;
/*SLLV*/        9: Result = ALU_B_i << ALU_A_i;
/*SRA*/         10: Result = ALU_B_i >>> Shamt;
/*SRAV*/        11: Result = ALU_B_i >>> ALU_A_i;
/*SRL*/         12: Result = ALU_B_i >> Shamt;
/*SRLV*/        13: Result = ALU_B_i >> ALU_A_i;
/*AND*/         14: Result = ALU_A_i && ALU_B_i;
/*OR*/          15: Result = ALU_A_i || ALU_B_i;
/*XOR*/         16: Result = ALU_A_i ^^ ALU_B_i;
                default:
          begin
               Result = 0;
               Carryout = 0;
               adder_b = 0;
          end        
  endcase
end
endmodule   

上面的代码会生成锁存器,这里是Quartus II给出的结果:

Warning (10240): Verilog HDL Always Construct warning at ALU.sv(16): inferring latch(es) for variable "Carryout", which holds its previous value in one or more paths through the always construct

Warning (10240): Verilog HDL Always Construct warning at ALU.sv(16): inferring latch(es) for variable "adder_b", which holds its previous value in one or more paths through the always construct

Error (10166): SystemVerilog RTL Coding error at ALU.sv(16): always_comb construct does not infer purely combinational logic.

我确实在案例的最后添加了一个默认值,有人可以解释一下这是怎么回事吗?非常感谢。

虽然您关于通过 case 语句的多个路径(并且需要 default 子句)的说法是正确的,但如果不是每个分支中都存在信号,也会生成锁存器。在这种情况下,Carryoutadder_b 仅出现在某些路径中。因此,您的综合工具假设您希望存储这些值,这会生成一个锁存器。

您需要为 case 的每个分支中的那些信号分配一些值。例如:

/*SLL*/         8: begin
                      Result = ALU_B_i << Shamt;
                      ader_b = 0;
                      Carryout = 0;
                end

对其他分支重复上述步骤。

这里简洁明了的解决方案是在 always_comb 块的开头分配默认值 Carryout。最后一个赋值将获胜,因此任何没有为 Carryout 赋值的分支将获得默认值。

最后一个分配如何获胜的简单示例如下所示:

always_comb begin
   Carryout = 1'b0;
   if(some_condition) begin
      Carryout = 1'b1;
   end
end

在上面的代码中,Carryout 被赋值为 0,然后如果 some_condition 为真,它被重新赋值为 1。如果 some_condition 为假,那么它只是保留 "default" 值为 0。这一切都发生在同一时间步,因此输出上没有瞬态毛刺。