I'm writing ALU for MIPS.
I used to write it as a sequential logic (or a always block? I don't know why but c
must be a reg
so I guess it's a sequential logic?)
It seems to be combinational logic
always @* begin
case (op)
4'b0000: c = mux_a + mux_b;
4'b0001: c = mux_a - mux_b;
4'b0010: c = mux_b << mux_a[4:0];
4'b0011: c = mux_b >> mux_a[4:0];
4'b0100: c = $signed(mux_b) >>> mux_a[4:0];
4'b0101: c = mux_a & mux_b;
4'b0110: c = mux_a | mux_b;
4'b0111: c = mux_a ^ mux_b;
4'b1000: c = ~(mux_a | mux_b);
4'b1001: c = (mux_a < mux_b) ? 32'b1 : 32'b0; // sltu
4'b1010: c = ($signed(mux_a) < $signed(mux_b)) ? 32'b1 : 32'b0; // slt
4'b1011: c = mux_a + mux_b - 4;
default: c = 0;
endcase
end
And it works well, 4'b0100: c = $signed(mux_b) >>> mux_a[4:0]
can get correct output. However due to some reasons I decided to use a combinational logic conditional expression.
assign c = (op == 4'b0000) ? (mux_a + mux_b) :
(op == 4'b0001) ? (mux_a - mux_b) :
(op == 4'b0010) ? (mux_b << mux_a[4:0]) :
(op == 4'b0011) ? (mux_b >> mux_a[4:0]) :
(op == 4'b0100) ? ($signed(mux_b) >>> mux_a[4:0]) :
(op == 4'b0101) ? (mux_a & mux_b) :
(op == 4'b0110) ? (mux_a | mux_b) :
(op == 4'b0111) ? (mux_a ^ mux_b) :
(op == 4'b1000) ? (~(mux_a | mux_b)) :
(op == 4'b1001) ? ((mux_a < mux_b) ? 32'b1 : 32'b0) :
(op == 4'b1010) ? (($signed(mux_a) < $signed(mux_b)) ? 32'b1 : 32'b0) :
(op == 4'b1011) ? (mux_a + mux_b - 4) :
0;
Which is almost the same except c
is a wire
.
And I run this code and it tells me that, 4294967280 (FFFFFFF0) >>> 8 = 33554431 (1FFFFFF) which is ridiculous.
PC= 388, Fetched 00000000000100011001101000000011.
Decoder done. alu=4294967280.
ALUOP=0100 ALUMASK=10 Calc Result= 33554431
rs= 0 rt=4294967280
aluflag = 0000
Written(0000) 01ffffff to RegAddr:19
But if I use (op == 4'b0100) ? ({ {31{mux_b[32]}}, mux_b} >> mux_a[4:0]) :
instead, I can get correct result.
Can anyone tell me the reason? Following is how these variable defined (use 33 bits for overflow flags)
input [31:0] a;
input [31:0] b;
input [31:0] imm1;
input [31:0] imm0;
input [3:0] op;
input [1:0] mask;
output [31:0] result;
output [3:0] flags;
wire [31:0] _mux_a;
wire [31:0] _mux_b;
wire [32:0] mux_a;
wire [32:0] mux_b;
wire [32:0] c;
assign _mux_a = mask[1] ? imm1 : a;
assign _mux_b = mask[0] ? imm0 : b;
assign mux_a = {_mux_a[31], _mux_a};
assign mux_b = {_mux_b[31], _mux_b};
assign result = c[31:0];
//zf of uf
assign flags = {c[31], result == 0, c[32:31] == 2'b01, c[32:31] == 2'b10};