0

I can't seem to figure out what the proper syntax is to do {c_out, result} = {a + b + c_in} within a case block. The c_out doesn't work in my test bench, if I add 32'hffffffff + 1'b1 I get c_out = 0, result = 32'b0. What's the correct way to do this?

module verification_alu(
input c_in
input [W-1:0] a, b,
input [2:0] operation,
output reg [W-1:0] result
output reg c_out
);
parameter W = 32;

always@*
begin
    case(operation)
        0: result = a;
        1: result = ~a;
        2: {c_out, result} = {a + b + c_in};
        3: {c_out, result} = {a - b + c_in};
        4: result = a | b;
        5: result = a & b;
        default: {c_out, result} = {W-2'b0}; // will this line fill with zeros properly?
    endcase
end
endmodule

Also, side question, what should be the proper output of 32'b0 - 1'b1? Should I be getting 32'hffffffff?

3 Answers 3

2

The reason the addition and subtraction operations are not working is because you are wrapping the calculation in the concatenation operator ({}). Verilog determines the bit size of an operation partially based on the operands in an expression as well as by the context of that expression. In your case, the expression a + b + c_in is being evaluated as W-bits because the maximum length of any of the variables in that expression is W (ie, a and b are that length and because Verilog will first evaluate this addition (or two additions) before moving on to evaluating the {} operator wrapping it). By removing this unneeded step, you should get the proper (W+1)-bit evaluation of a + b + c_in; so the line would be: 3: {c_out, result} = a - b + c_in;. For more on this, see IEEE1800-2012, section 11.6.

To answer two of your other questions:

No, the expression {W-2'b0} will not zero fill but will instead result in the value W as you are telling the simulator to subtract 2'b0 from W. You are thinking of {(W-2){1'b0}}, or specially for zero filling '0 (because its so common, you can also use '1, 'x, or 'z for filling 1, don't care or high-Z respectively). (Note {c_out, result} has width W+1, not W-2 though)

Finally, 32'b0 - 1'b1 will most likely yield 32'hffffffff, but it is subject to the rules above on sizing (and sign extension rules as well).

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you! I have just one more question, If I'm doing a bit-slice ALU structurally and I subtract 32'hffffffff - 1'b1 I get 32'hfffffffe, but I also get a carry_out of 1. Should I do something to flip this carry_out back to 0? I did a verification alu module behaviorally with an error_flag and the flag gets tripped on subtraction because of the carry_out.
@Austin This depends on how you want the carry flag to behave for subtraction. If you think how subtraction typically works, it uses the two's compliment of 1, ie 32'hffffffff for 32-bit numbers, and adds that to the first operand, thus an overflow is generated (and desired to get the correct 32-bit result). Unless you want the carry flag to act like a borrow flag, in which case the logic will be a bit different (I want to say its just ~c_out but Im not sure if thats true. Also, take note of how the other did the parameter declaration.
FYI, there is one more issue with the code. c_out is an inferred latch because it is not assigned an value when operation is 0, 1, 4, or 5. To resolve, either assign c_out in each condition or assign it a default constant value before the case-statement.
@Greg youre correct, I was very focused on the primary issue so I forgot to check for other mistakes; like that one and the parameter declaration. Thanks for pointing it out!
1

A revised description:

module verification_alu #(parameter W=32) (
  input wire c_in,
  input wire [W-1:0] a,
  input wire [W-1:0] b,
  input wire [2:0] operation,
  output reg [W-1:0] result,
  output reg c_out
);

  always @* begin
    case(operation)
      0: result = a;
      1: result = ~a;
      2: {c_out, result} = a + b + c_in;
      3: {c_out, result} = a - b + c_in;
      4: result = a | b;
      5: result = a & b;
      default: {c_out, result} = 0; // will this line fill with zeros properly?
    endcase
  end
endmodule

The point is to assure that at least one of the operands have the same size as the result you want, so I prepend a 0 bit to both a and b.

I have verified this to work even for sizes far beyond the size of an ordinary integer:

module tb;
  reg c_in;
  reg [127:0] a;
  reg [127:0] b;
  reg [2:0] op;
  wire [127:0] res;
  wire c_out;

  verification_alu #(.W(128)) uut (c_in, a, b, op, res, c_out);

  initial begin
    c_in = 0;
    a = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
    b = 128'h00000000000000000000000000000001;
    op = 3'd2;    
    #100;
    $display ("RES = %H  C_OUT = %d\n", res, c_out);

    #100;
    c_in = 0;
    a = 128'h00000000000000000000000000000000;
    b = 128'h00000000000000000000000000000001;
    op = 3;    
    #100;
    $display ("RES = %H  C_OUT = %d\n", res, c_out);

    #100;
    op = 7;    
    #100;
    $display ("RES = %H  C_OUT = %d\n", res, c_out);

    $finish;
    end
endmodule

Chronologic VCS simulator copyright 1991-2014
Contains Synopsys proprietary information.
Compiler version J-2014.12-SP1-1; Runtime version J-2014.12-SP1-1;  Oct 11 17:47 2015
RES = 00000000000000000000000000000000  C_OUT = 1

RES = ffffffffffffffffffffffffffffffff  C_OUT = 1

RES = 00000000000000000000000000000000  C_OUT = 0

$finish called from file "testbench.sv", line 35.
$finish at simulation time                  500

You can edit and/or run the testbench along with the revised module at http://www.edaplayground.com/x/CJV

EDIT: ouch! I didn't realized the OP had used the concatenation operator { } for embracing the three operands. Yes! your code is way much simpler. I'll edit the code in my answer.

2 Comments

Note that this might work for W <= sizeof(int) but not for the reasons you think, see my answer for an explanation on Verilog sizing rules.
But now that I think about it, you'll run into a strange offset error, as W-2'b0 evaluates to W which will then by concatenated with c_in, which is very much not what you want.
0

First of all as per your code the parameter definitions in the input ports will not be accessible by compiler and will throw syntax error, you have to mention the parameter definitions before your i/o declarations since it is been accessed in i/o declarations, verilog comes with a syntax as to avoid this

module module_name #(parameter W =value)

{} is a concatenation operator used with "," eg: a=1bit b= 1bit c=2bit so we can give c={a,b}; so the correct syntax is as simple as

2: {c_out, result} = a + b + c_in;
3: {c_out, result} = a - b + c_in;

to fill it with zeros a mix of parameter with curly braces will help in resolving (the inner curly brace will act as replication operator)

default: {c_out, result} = {(W-2){1'b0}};

1 Comment

I put #(.W(W)) in a top module I just listed the parameter in this one, but thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.