I'm trying to learn digital design this summer and currently going through this excercise of creating a 32-bit ALU based on this schematic:
Im using the +
operator to create an adder, but I need to grab the carry out for use in my carry flag. Should I just hard code an adder instead of using the +
operator? I pretty much hard coded the equation for the carry out of a full adder in my else statement provided below. I'm pretty new to this, and any of type help would be appreciated. I'm also not sure if my code is well designed/structured. Any tips would be awesome!!
module alu(input logic [31:0] a, b,
input logic [1:0] alu_operation,
output logic [31:0] out,
output logic [3:0] alu_flag);
logic [31:0] sum, b_out;
assign b_out = alu_operation[0] ? ~b : b; // if 0 bit of op = 1, then we invert b to subtract, otherwise we keep b and add.
assign sum = a + b_out + alu_operation[0];
always @ (alu_operation, a, b)
case (alu_operation)
2'b00: out <= sum; // ADD
2'b01: out <= sum; // SUBTRACT
2'b10: out <= a & b; // AND
2'b11: out <= a | b; // OR
endcase
wire logic negative, zero, carry, overflow;
assign negative = alu_flag[3];
assign zero = alu_flag[2];
assign carry = alu_flag[1];
assign overflow = alu_flag[0];
always @ (out, a, b)
begin
if (out[31] == 1)
alu_flag[3] <= 1; // Negative
if (out == 0)
alu_flag[2] <= 1; // Zero
if ( ~alu_operation[1] & ((a & b) | (alu_operation[0] & (a ^ b)))) // Carry = AB + Cin(A xor B)
alu_flag[1] <= 1; // Cin = alu_operation[0]
if ((sum[31] & a[31]) & (~alu_operation[1]) & (b[31] ^~ a[31] ^~ alu_operation[0]))
alu_flag[0] <= 1; // Overflow
end
endmodule
1 Answer 1
The layout of your code is good, and you chose meaningful names for your signals. There are some improvements you can make, however.
The following signals are essentially unused:
wire logic negative, zero, carry, overflow;
You do make assignments to them, but you never use them otherwise. If you synthesize your code, they will be optimized away. Therefore, you can simply delete them and their assignments.
Good coding practices recommend that you should use blocking assignments (=
) for combinational logic. Since you do not have any sequential logic, you should not use nonblocking assignments (<=
) in your always
blocks.
Your always
blocks have incomplete sensitivity lists. This will lead to simulation mismatches before and after synthesis. You should use the implicit sensitivity list syntax:
always @*
Your second always
block will infer latches because you do not make assignments to the signals under all conditions. One way to avoid latches is to use an else
clause for each if
statement.
Here is the new code, taking all of the above into account. I also made some minor changes regarding indentation and begin/end
usage:
module alu (
input logic [31:0] a, b,
input logic [1:0] alu_operation,
output logic [31:0] out,
output logic [3:0] alu_flag
);
logic [31:0] sum, b_out;
assign b_out = alu_operation[0] ? ~b : b; // if 0 bit of op = 1, then we invert b to subtract, otherwise we keep b and add.
assign sum = a + b_out + alu_operation[0];
always @* begin
case (alu_operation)
2'b00: out = sum; // ADD
2'b01: out = sum; // SUBTRACT
2'b10: out = a & b; // AND
2'b11: out = a | b; // OR
endcase
end
always @* begin
if (out[31]) begin
alu_flag[3] = 1; // Negative
end else begin
alu_flag[3] = 0;
end
if (out == 0) begin
alu_flag[2] = 1; // Zero
end else begin
alu_flag[2] = 0;
end
// Carry = AB + Cin(A xor B)
if ( ~alu_operation[1] & ((a & b) | (alu_operation[0] & (a ^ b)))) begin
alu_flag[1] = 1;
end else begin
alu_flag[1] = 0;
end
if ((sum[31] & a[31]) & (~alu_operation[1]) & (b[31] ^~ a[31] ^~ alu_operation[0])) begin
alu_flag[0] = 1; // Overflow
end else begin
alu_flag[0] = 0;
end
end
endmodule
Regarding your question about the +
operator, I think you should keep it because it is good to code at a high level of abstraction. Synthesis tools will optimize your code. If your synthesized design does not meet your goals (timing, power, area, etc.), then you can revisit the implementation.
-
\$\begingroup\$ Thank you for the great answer, helped me a bunch. I also had another question, why do you create a begin/end block for each if block? What is the advantage to that as opposed to encapsulating it all under one begin/end block? \$\endgroup\$theonetrue2– theonetrue22021年06月15日 23:09:07 +00:00Commented Jun 15, 2021 at 23:09
-
\$\begingroup\$ @theonetrue2: You're welcome. All the if conditions are different from each other, which means you need different begin/end. In this case, since you only have one statement for each if, you don't really need begin/end, but it is a coding style that I recommend using. \$\endgroup\$toolic– toolic2021年06月16日 10:18:43 +00:00Commented Jun 16, 2021 at 10:18