0

我为 ALU 编写了这个编码器。该 ALU 使用ctrl信号进行控制,并执行一些工作,例如加、减、和、或……当输出为零时,oZero信号应该处于活动状态。

我在标记的行中有一些错误。我的错误是什么?

module ALU_32 (iA, iB ,iCin ,ctrl, oCarry,oZero, out);    
input [31:0] iA,iB;
output [31:0] out;
input iCin,ctrl;
output oCarry,oZero;
reg [31:0] out;
reg oCarry;
reg oZero;
always@ (ctrl)
    begin 
        case(ctrl)
            4'b0: out<=iA&iB;
            4'b0001: out<=iA|iB;
            4'b0010: {oCarry ,out}<=iA+iB;
            4'b0011: out<=iA~|iB;    //error
            4'b0100: 
            begin 
                if(iA==iB)
                    out<=32'b1;
            end  
            4'b0101: out<=iA-iB;  //error
            4'b0110:    //error
            begin 
                if(iA<iB)
                    out<=32'b1;
                else
                    out<=32'b0;
                end
            4'b0111:   out<=iA*iB;     //error
            4'b1000: out<=iA/iB;        //error

        end
       always@(out)
           begin
               if(out==0)
                   oZero<=1;
               end

      endmodule
4

2 回答 2

1

~|您使用的运算符4'b0011: out<=iA~|iB;被您的 IDE 视为归约运算符,而不是 NOR 运算。要解决这个问题,您可以使用例如以下构造:

out <= ~(iA | iB);

第二个问题是您忘记endcase在构造结束时使用关键字case

检查edaplayground以查看应用于您的代码的这些更改。

于 2015-05-20T14:35:14.080 回答
1

正如邱指出的那样,iA~|iB应该是~(iA|iB)并且您缺少一个endcase. 在此之上:

  1. ctrl需要 4 位宽。IEinput [3:0] ctrl
  2. 组合块需要声明敏感列表中的所有元素或使用自动敏感。用always @(ctrl)模拟器将不会使用查看更改iAiB。而是always @*用于自动灵敏度。您应该始终对组合逻辑使用自动灵敏度,除非您仅限于 IEEE Std 1364 的 1995 版本(您可能不是),在这种情况下您需要always @(ctrl or iA or iB or iCin). 自动灵敏度(@*@(*))于 2001 年被添加到标准中。
  3. 您不应将非阻塞赋值 ( <=) 与组合逻辑一起使用,而应使用阻塞赋值 ( =)。应该使用非阻塞来分配触发器和锁存器。
  4. out并且oCarry在每种情况下都没有分配一个已知值,这将它们推断为锁存器。锁存逻辑设计容易出现时序问题,需要谨慎使用。大多数 FPGA 的锁存器数量有限,有些则有一些。编码风格的改变可以移除推断的锁存器,有两种主要方法可以做到这一点。

    1. 在每个条件下分配输出。确保在 case 语句中声明了默认条件:

      always @* begin
        case(ctrl)
        4'b0000 :
          begin
            out = iA&iB;
            oCarry = 1'b0;
          end
        // conditions assigning both 'out' and 'oCarry'
        default:
          begin
            out = 32'0;
            oCarry = 1'b0;
          end
        endcase
      end
      
    2. 在 case-statement 之前将值分配给默认值。case-statement 将覆盖默认值。

      always @* begin
        // default value
        out = 32'd0;
        oCarry = 1'b0;
        // calculate value, override default
        case(ctrl)
          4'b0000 : out = iA&iB;
          // ...
          4'b0010: {oCarry ,out} = iA+iB;
          // ...
          4'b1000: out = iA/iB;
        endcase
      end
      
  5. oZero也是一个推断锁存器。它只能分配给1,没有到0的路径。您可以:

    • always @* oZero = (out==0);
    • oZero = (out==0);将always块与下面合并endcase
    • assign oZero = (out==0); // Make sure 'oZero' is a wire (not reg)

其他建议(可选)

  1. ANSI 样式标题。在 IEEE Std 1364-2001 中添加并受到所有现代模拟器和合成器的支持。它比 IEEE Std 1364-1995 的非 ANSI 样式更紧凑。

    module ALU_32 (    
      input [31:0] iA, iB,
      input        iCin,
      input [3:0]  ctrl,
      output reg  oCarry, oZero,
      output reg [31:0] out );
    
  2. 您在那里建议了iA*iB和的错误iA/iB。在verilog中,没有错。综合工具可能存在问题,因为 32 位乘 32 位乘法器/除法器往往会占用大量资源。您可能需要在单独的模块中流水线化操作。FPGA 可能有一个预定义的模块,因此请查看数据表。

于 2015-05-20T16:26:45.917 回答