Can you help me guys do a 32-bit ALU and explain me some things? Wanna do:
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)
Done this so far:
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
Your code is good. Just some modifications required. ALUOut
must be [N:0]
, since you'll require a carry bit in case of addition. Also, borrow bit must be required in case of subtraction.
Referring to SystemVerilog LRM 1800-2012 Section 11.6 Expression bit lengths ,
SystemVerilog uses the bit length of the operands to determine how many bits to use while evaluating an expression.
So, ALUOut[N-1:0] = ALUinA[N-1:0] + ALUinB[N-1:0];
will strictly evaluate an expression of N
, while ALUOut = ALUinA + ALUinB;
will evaluate depending on size of ALUOut
. Here, you can not see the difference, since all youe operands are N
bits wide, but when ALUOut
is increased to N+1
bits(including carry), then it can create a difference.
For example,
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
shall execute to a = 15 b = 1 carry = 0 sum = 0
while, using the commented assign statement executes to a = 15 b = 1 carry = 1 sum = 0
Refer to LRM 1800-2012 , Section 11.6 for further information. Also, this and this links regarding ALU design can be useful.
In 2's complement -B
is ~B+1
( ~
is bit invert). Therefor A - B == A + (-B) == A + ~B + 1
. But your doing RTL, so you don't need to write the 2's complement for subtraction as it is default. A - B
and A + ~B + 1
will synthesize the same.
A[N-1:0] + B[N-1:0]
is always an unsigned operation. A + B
can be a signed operation if A and B are declared as input signed [N-1:0] A, B
, otherwise it is an unsigned operation.
Other notes:
There is an issue with your header. Many simulators, synthesizers, and other Verilog tools will accept what you have, but it is not complaint with the IEEE standard. There are two header styles, ANSI and non-ANSI. I recommend ANSI unless required to follow the IEEE1364-1995 version of the standard.
ANSI style (IEEE Std 1364-2001 and above):
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 style (IEEE Std 1364-1995 and above):
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)
is syntax legal. However since IEEE1364-2001 combinational logic is recommenced to be written as always @*
or always @(*)
( @*
and @(*)
are synonymous, user preference). With SystemVerilog (IEEE1800), the successor of Verilog (IEEE1364), always_comb
is recommend over always @*
for combinational logic, and always_latch
for level-sensitive latching logic.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.