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 - B
和 A + ~B + 1
将合成相同的内容。
A[N-1:0] + B[N-1:0]
始终是无符号运算。如果 A 和 B 声明为 input signed [N-1:0] A, B
,A + 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
。
你们能帮我做一个 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 - B
和 A + ~B + 1
将合成相同的内容。
A[N-1:0] + B[N-1:0]
始终是无符号运算。如果 A 和 B 声明为 input signed [N-1:0] A, B
,A + 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
。