module tb_ALU;
reg i;
reg [31:0] SrcA, SrcB;
reg [3:0] af;
wire [31:0] Alures;
wire Zero, Neg, ovfalu;
ALU uut (
.i(i), .SrcA(SrcA), .SrcB(SrcB),
.af(af), .Alures(Alures),
.Zero(Zero), .Neg(Neg), .ovfalu(ovfalu)
);
initial begin
$monitor("af=%b, SrcA=%d, SrcB=%d => Alures=%d, Zero=%b, Neg=%b,
ovfalu=%b", af, SrcA, SrcB, Alures, Zero, Neg, ovfalu);
// ADD
i = 0; af = 4'b0000; SrcA = 32'd10; SrcB = 32'd20; #10;
// SUB (with zero result)
af = 4'b0001; SrcA = 32'd15; SrcB = 32'd15; #10;
// SLT
af = 4'b0101; SrcA = -1; SrcB = 1; #10;
// Overflow test
af = 4'b0000; SrcA = 32'h7FFFFFFF; SrcB = 32'd1; #10;
// Finish
$stop;
end
endmodule
module ALU (
input wire i,
input wire [31:0] SrcA, SrcB,
input wire [3:0] af,
output reg [31:0] Alures,
output wire Zero,
output wire Neg,
output reg ovfalu
);
always @(*) begin
ovfalu = 0;
case (af)
4'b0000: {ovfalu, Alures} = {1'b0, SrcA + SrcB}; // ADD
4'b0001: {ovfalu, Alures} = {1'b0, SrcA - SrcB}; // SUB
4'b0010: Alures = SrcA & SrcB; // AND
4'b0011: Alures = SrcA | SrcB; // OR
4'b0100: Alures = SrcA ^ SrcB; // XOR
4'b0101: Alures = ($signed(SrcA) < $signed(SrcB)) ? 32'd1 : 32'd0; // SLT
4'b0110: Alures = SrcB << SrcA[4:0]; // SLL
4'b0111: Alures = SrcB >> SrcA[4:0]; // SRL
4'b1000: Alures = ~(SrcA | SrcB); // NOR
4'b1001: Alures = {SrcB[15:0], 16'b0}; // LUI
default: Alures = 32'd0;
endcase
// Overflow for signed add/sub
if (af == 4'b0000)
ovfalu = (~SrcA[31] & ~SrcB[31] & Alures[31]) | (SrcA[31] & SrcB[31] &
~Alures[31]);
else if (af == 4'b0001)
ovfalu = (~SrcA[31] & SrcB[31] & Alures[31]) | (SrcA[31] & ~SrcB[31] &
~Alures[31]);
end
assign Zero = (Alures == 32'd0);
assign Neg = (Alures == 32'd0) && (af == 4'b0000 || af == 4'b0001); // Only for
signed ops
endmodule