32 位 ALU 的 Verilog 设计

Verilog Design of a 32-bit ALU

你们能帮我做一个 32 位 ALU 并向我解释一些事情吗? 想做:

0 bitwise AND: out = inA & inB.
1 bitwise OR: out = inA | inB.
2 addition: out = inA + inB.
6 subtraction: out = inA – inB //2's complement
7 Set On Less Than: out = ((inA < inB)?1:0)
12 NOR: out = ~( inA | inB)

目前已完成:

module ALU #(parameter N=32)(ALUOut, Zero, ALUinA, ALUinB, ALUop); 
    output  [N-1:0] ALUOut;
    reg     [N-1:0] ALUOut;
    output  Zero;
    reg     Zero;
    input   [3:0] ALUop;
    input   [N-1:0] ALUinA, ALUinB;

    always @(ALUinA or ALUinB or ALUop)
    begin
        case (ALUop)
           4'b0000: ALUOut  = ALUinA & ALUinB ;   // 0:AND

你的代码很好。只需要一些修改。 ALUOut 必须是 [N:0],因为在加法的情况下你需要一个进位。此外,在减法的情况下必须需要借位。

参考SystemVerilog LRM 1800-2012第11.6节表达式位长,

SystemVerilog uses the bit length of the operands to determine how many bits to use while evaluating an expression.

因此,ALUOut[N-1:0] = ALUinA[N-1:0] + ALUinB[N-1:0]; 严格地 计算 N 的表达式,而 ALUOut = ALUinA + ALUinB; 将 根据 ALUOut 的大小进行评估。在这里,你看不出区别,因为你所有的操作数都是 N 位宽,但是当 ALUOut 增加到 N+1 位(包括进位)时,就会产生差异。

例如,

module top();
  bit [3:0] a,b;
  logic [3:0] sum;
  bit carry;

  assign sum[3:0] = a[3:0] + b[3:0];
// assign {carry,sum}= a + b;
  initial
      $monitor("a = %0d b = %0d carry = %0d sum = %0d",a,b,carry,sum);

  initial
    begin
      a = 5; b = 1;
      #5 ; a = 15; b = 1;
    end
endmodule

应执行到 a = 15 b = 1 carry = 0 sum = 0,同时使用注释的赋值语句执行到 a = 15 b = 1 carry = 1 sum = 0

请参阅 LRM 1800-2012,第 11.6 节以获取更多信息。 此外,this and this 有关 ALU 设计的链接可能很有用。

在 2 的补码中 -B~B+1~ 是位反转)。因此A - B == A + (-B) == A + ~B + 1。但是你做的是 RTL,所以你不需要为减法写 2 的补码,因为它是默认的。 A - BA + ~B + 1 将合成相同的内容。

A[N-1:0] + B[N-1:0] 始终是无符号运算。如果 A 和 B 声明为 input signed [N-1:0] A, BA + B 可以是有符号运算,否则它是无符号运算。

其他说明:

您的 header 有问题。许多模拟器、合成器和其他 Verilog 工具会接受您拥有的东西,但它不符合 IEEE 标准。有两种 header 样式,ANSI 和 non-ANSI。我推荐 ANSI,除非需要遵循 IEEE1364-1995 版本的标准。

ANSI 样式(IEEE Std 1364-2001 及更高版本):

module ALU #(parameter N=32)( 
    output reg [N-1:0] ALUOut,
    output reg Zero,
    input   [N-1:0] ALUinA, ALUinB,
    input   [3:0] ALUop );

Non-ANSI 样式(IEEE Std 1364-1995 及更高版本):

module ALU (ALUOut, Zero, ALUinA, ALUinB, ALUop);
    parameter N=32;
    output  [N-1:0] ALUOut;
    output  Zero;
    input   [3:0] ALUop;
    input   [N-1:0] ALUinA, ALUinB;

    reg     [N-1:0] ALUOut;
    reg     Zero;

always @(ALUinA or ALUinB or ALUop) 语法合法。但是由于IEEE1364-2001组合逻辑重新开始写成always @*always @(*)@*@(*)是同义词,用户偏好)。对于 SystemVerilog (IEEE1800),Verilog (IEEE1364) 的后继者,always_comb 对于组合逻辑推荐优于 always @*,对于 level-sensitive 锁存逻辑推荐 always_latch