16-bit ALU: try to change operation code, but results still remain the same

62 Views Asked by At

I am trying to write a 16-bit ALU. I have compiled everything successfully, but when the operation code alu_code changes, the result C stays the same (the first operation result). Here's my code for ALU:

module ALU (
    input [15:0] A, B,
    input [4:0] alu_code,
    output reg [15:0] C,
    output reg overflow
);

wire [1:0] over;
wire signed [15:0] As, Bs, Bs2s;
wire signed [15:0] C_add, C_sub;
wire [15:0] C_addu, C_subu;
wire [15:0] B2s;
wire overflow_temp;

assign B2s = ~B + 1;
assign As = A;
assign Bs = B;
assign Bs2s = ~Bs + 1;

CLA add(.A(As), .B(Bs), .Sum(C_add), .overflow(overflow_temp));
CLA addu(.A(A), .B(B), .Sum(C_addu), .overflow(overflow_temp));
CLA sub(.A(As), .B(Bs2s), .Sum(C_sub), .overflow(overflow_temp));
CLA subu(.A(A), .B(B2s), .Sum(C_subu), .overflow(overflow_temp));

always @(alu_code or A or B) begin
    case(alu_code)
    00000 : C = C_add;
    00001 : C = C_addu;
    00010 : C = C_sub;
    00011 : C = C_subu;
    endcase
end

assign over = {overflow_temp, C[15]};

always @(*) begin
if (over == 2'b01) overflow = 1;
else overflow = 0;
end
endmodule

module CLA (
    input [15:0] A, B,
    output [15:0] Sum,
    output overflow
);

wire c1, c2, c3;

CLA4bit CLA1 (.A(A[3:0]), .B(B[3:0]), .Cin(1'b0), .Sum(Sum[3:0]), .Cout(c1));
CLA4bit CLA2 (.A(A[7:4]), .B(B[7:4]), .Cin(c1), .Sum(Sum[7:4]), .Cout(c2));
CLA4bit CLA3(.A(A[11:8]), .B(B[11:8]), .Cin(c2), .Sum(Sum[11:8]), .Cout(c3));
CLA4bit CLA4(.A(A[15:12]), .B(B[15:12]), .Cin(c3), .Sum(Sum[15:12]), .Cout(overflow));

endmodule


module CLA4bit(
    input [3:0] A, B,
    input Cin,
    output [3:0] Sum,
    output Cout
);

wire [3:0] P, G, C;

assign P = A ^ B;
assign G = A & B;

assign C[0] = Cin;
assign C[1] = G[0] | (P[0] & C[0]);
assign C[2] = G[1] | (P[1] & G[0]) | P[1] & P[0] & C[0];
assign C[3] = G[2] | (P[2] & G[1]) | P[2] & P[1] & G[0] | P[2] & P[1] & P[0] & C[0];
assign Cout = G[3] | (P[3] & G[2]) | P[3] & P[2] & G[1] | P[3] & P[2] & P[1] & G[0] | P[3] & P[2] & P[1] & P[0] & C[0];

assign Sum = P ^ C;

endmodule 

Here is the testbench:

module tbALU();

reg [15:0] A, B;
reg [4:0] alu_code;
wire [15:0] C;
wire overflow;

ALU uut(A, B, alu_code, C, overflow);

initial begin
A = 8'hAA; B = 8'hAA;
#50; alu_code = 0;
#50; alu_code = 1;
#50; alu_code = 2;
#50; alu_code = 3;
end
endmodule 

The waveform of C is just like what I said; it never changes corresponding to change of operation.

1

There are 1 best solutions below

0
Greg On

A couple of issues:

  • @(alu_code or A or B) should be @* as C depends on C_add,C_addu,C_sub,C_subu and not directly A or B. By using A and B in the sensitivity list, you create a race condition between the always block that assigns C and the CLA modules. @* (or synonymous @(*)) is automatic sensitivity, and you should use always @* for just about all combinational blocks. Specify the sensitivity list for combinational logic is should only be used for coding in the old IEEE1364-1995 style or obscure non-synthesizable bus-functional-models. Better than always @* would be to use SystemVerilog's always_comb
  • There are multiple drivers on overflow_temp. If there are conflicting values being driven, the result will be x. There should be only one driver per output. You can OR, MUX, or perform other logic to the output with other logic outside of the connection.
  • The case statement has 00010 and 00011 which is treated as ten and eleven respectively. You need to prefix the radix to have it treated as binary.

The code should be modified to include:

// ...
wire [1:0] overflow_temp;
// ...

CLA add(.A(As), .B(Bs), .Sum(C_add), .overflow(overflow_temp[0]));
CLA addu(.A(A), .B(B), .Sum(C_addu), .overflow(overflow_temp[1]));
CLA sub(.A(As), .B(Bs2s), .Sum(C_sub), .overflow(overflow_temp[2]));
CLA subu(.A(A), .B(B2s), .Sum(C_subu), .overflow(overflow_temp[3]));

always @* begin
    case(alu_code)
    5'b00000 : C = C_add;
    5'b00001 : C = C_addu;
    5'b00010 : C = C_sub;
    5'b00011 : C = C_subu;
    endcase
end

assign over = {overflow_temp[alu_code], C[15]};

// ...

There might be other issues with the code. This feedback should be enough to get in in the correct direction.