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

Shu*_*ang 1 verilog mips system-verilog

我理解在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
Run Code Online (Sandbox Code Playgroud)

正如我在开头所说,如果添加默认值,则不会生成锁存器.请查看第二个代码,这是一个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   
Run Code Online (Sandbox Code Playgroud)

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

警告(10240):Verilog HDL总是在ALU.sv(16)构造警告:推断变量"Carryout"的锁存器,它通过always结构在一个或多个路径中保存其先前的值

警告(10240):Verilog HDL总是在ALU.sv(16)构造警告:推断变量"adder_b"的锁存器,它通过always结构在一个或多个路径中保存其先前的值

错误(10166):ALU.sv(16)处的SystemVerilog RTL编码错误:always_comb构造不推断纯粹的组合逻辑.

我在案例的最后添加了一个默认值,有人可以解释一下发生了什么吗?非常感谢.

ngu*_*rie 5

这里干净简单的解决方案是Carryoutalways_comb块的开头分配一个默认值.最后一次分配将获胜,因此任何未分配值的分支都Carryout将获得默认值.

下一个如何获胜的简单示例如下所示:

always_comb begin
   Carryout = 1'b0;
   if(some_condition) begin
      Carryout = 1'b1;
   end
end
Run Code Online (Sandbox Code Playgroud)

在上面的代码Carryout被赋值为0,然后if some_condition为true,它被重新赋值为1.如果some_condition为false,则它只保持"默认"值0.这一切都发生在同一时间步,所以没有瞬态输出上的故障.