Mips 关于由“生成的闩锁”;案例;语法

Mips 关于由“生成的闩锁”;案例;语法,mips,verilog,system-verilog,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: {

我理解在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   
模块ALU(
输出逻辑[31:0]结果,
输出逻辑零、溢出、负、执行、,
输入逻辑[5:0]ALOUP_i,
输入逻辑[31:0]ALU_A_i,ALU_B_i,
输入逻辑[4:0]SHMT
);
逻辑[31:0]加法器;
总是用梳子
开始
卡塞兹(阿卢普ú一)
/*添加{u trap*/0,1:{Carryout,Result}={ALU_A_i[31],ALU_A_i}+{ALU_B_i[31],ALU_B_i};
/*添加\u notrap*/
/*子标签*/2,3:
/*Sub_notrap*/开始
加法器b=ALU_b_i^{32{1'b1};
{Carryout,Result}={ALU_A_i[31],ALU_A_i}+{adder_b[31],adder_b}+1;
终止
/*SLL*/8: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;
/*和*/14:Result=ALU_A_i&&ALU_B_i;
/*或*/15:Result=ALU_A_i | ALU_B_i;
/*XOR*/16:Result=ALU_A_i^^ ALU_B_i;
违约:
开始
结果=0;
结转率=0;
加法器_b=0;
终止
尾声
终止
端模
上述代码将生成锁存,以下是Quartus II给出的结果:

警告(10240):Verilog HDL始终在ALU.sv(16)处构造警告: 推断变量“carrout”的锁存(es),该变量保持其先前的 通过always构造的一个或多个路径中的值

警告(10240):Verilog HDL始终在ALU.sv(16)处构造警告: 推断变量“adder_b”的锁存器,该变量保持其先前的 通过always构造的一个或多个路径中的值

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


我确实在案件的结尾添加了一个默认值,有人能解释发生了什么吗?非常感谢。

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

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

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

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

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

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

Result=ALU_B_i这里简单明了的解决方案是在
始终梳
块的开头指定一个默认值
执行
。最后一次分配将获胜,因此任何未将值分配给执行的分支将获得默认值

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

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

在上面的代码中,
carrout
被指定为0,然后如果
some_条件
为真,它将被重新指定为1。如果
some_condition
为false,则只保留“default”值0。这一切都发生在同一个时间步中,因此输出上没有瞬时故障。

这里简单明了的解决方案是在
始终梳
块的开头指定一个默认值
执行
。最后一次分配将获胜,因此任何未将值分配给执行的分支将获得默认值

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

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

在上面的代码中,
carrout
被指定为0,然后如果
some_条件
为真,它将被重新指定为1。如果
some_condition
为false,则只保留“default”值0。这一切都发生在同一个时间步中,因此输出上没有瞬时故障。

您所说的“最后一次分配将获胜”是什么意思?在我的回答中添加了更多的内容以澄清。我还应该指出,我意识到我编写的代码是一种荒谬的方式,它执行
assigncarrout=some_条件
和只是为了说明这个概念。因此,根据我们在一开始时的默认值,我们是否仍然需要在case语句的末尾添加一个“default”呢?不,您可以删除默认case,而不获取闩锁。您所说的“last assignment will win”是什么意思?在我的回答中添加了更多的内容来澄清。我还应该指出,我意识到我编写的代码是一种荒谬的方式,它执行
assigncarrout=some_条件和只是为了说明这个概念。因此,使用我们在最开始时的默认值,我们是否仍然需要在case语句的末尾使用“default”呢?不,您可以删除默认的case,而不获取推断的闩锁。如果我在always_comb的最开始添加默认值,那么就不会生成闩锁。这也是在所有不同分支中不完全分配的解决方案吗?是的-在通过
始终\u comb
的每个路径中,每个信号都被分配一个值。如果我在always_comb的最开始添加默认值,则不会生成锁存。这也是一个解决方案吗