关于“case”语法生成的锁存器

时间:2015-06-22 13:29:07

标签: mips verilog 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

正如我在开头所说,如果添加默认值,则不会生成锁存器。 请查看第二个代码,这是一个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给出的结果:

  

警告(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构造并不能推断纯粹的组合逻辑。

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

2 个答案:

答案 0 :(得分:5)

此处干净简便的解决方案是在Carryout块的开头指定默认值always_comb。最后一项任务将获胜,因此任何未向Carryout分配值的分支都将获得默认值。

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

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

在上面的代码Carryout被分配为0,然后如果some_condition为真,则将其重新分配给1.如果some_condition为假,则它只保留“默认”值为0.这一切都发生在同一时间步,因此输出上没有瞬态毛刺。

答案 1 :(得分:1)

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

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

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

重复其他分支。