Austin
Austin

Reputation: 7319

Verilog Case Block Concatenation Syntax

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?

Upvotes: 0

Views: 4642

Answers (3)

Unn
Unn

Reputation: 5098

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).

Upvotes: 2

mcleod_ideafix
mcleod_ideafix

Reputation: 11428

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.

Upvotes: 1

Emman
Emman

Reputation: 1234

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}};

Upvotes: 0

Related Questions