1

I am trying to create a 4-bit ripple carry adder using 4 full adders each comprised of two half-adders. This is the code for my half-adder:

module HA (input a, b,
    output reg cout,
    output reg sum);

    reg [1:0] temp;

    always @ (a or b) begin
        temp = a + b;
        #2 cout = temp[1];
        #1 sum = temp[0];
    end
endmodule

I have written a test bench for the half adder and it works as expected. This is the code for my full adder:

module FA(input a, b, cin,
    output cout, sum);
    wire c1, c2;
    wire s; 
    HA h0 (.a(a), .b(b), .cout(c1), .sum(s));
    HA h1 (.a(s), .b(cin), .cout(c2), .sum(sum));
    or o1 (cout, c1, c2);
endmodule

The full adder also has a test bench that shows it works as expected.

Now this is the code for my ripple adder:

module PAdder(input [3:0] a,
        input [3:0] b,
        input cin,
        output [3:0] sum,
        output cout);

wire [2:0] c;
FA f0 (a[0], b[0], cin, c[0], sum[0]);
FA f1 (a[1], b[1], c[0], c[1], sum[1]);
FA f2 (a[2], b[2], c[1], c[2], sum[2]);
FA f3 (a[3], b[3], c[2], cout, sum[3]);

endmodule

But when I run a testbench on this one, I get queer results! This is the waveform of trying to add 0 and 0 with cin=0:

Waveform

I found that the second half adder of the second full adder (f1/h1) is the first half adder malfunctioning. I included its signals in the waveform and this is the result:

Waveform1

Note how at time 5ns, both the a and b input of h1 are non-X (both are 0) but still its output, or the temp register inside it, remain X-valued. Why does the always block of the HA not run to update temp to be 0 + 0 which is [0, 0]?

I tried recompiling and redoing the waveforms, but I kept getting the same results.

Here is the testbench:

module PAddertb;
    reg [3:0] a;
    reg [3:0] b;
    reg cin;
    wire [3:0] sum;
    wire cout;
    integer i;

    PAdder p0(a, b, cin, sum, cout);
    
    initial begin
        
        $monitor("a=%d(%0b) b=%d(%0b) cin=%0b cout=%0b sum=%d(%0b)", a, a, b, b, cin, cout, sum, sum);
        for (i = 0; i < 1; i = i + 1) begin
            {a, b, cin} = i;
            #20;
        end
    end
endmodule
toolic
  • 57,801
  • 17
  • 75
  • 117
Amir Kooshky
  • 49
  • 1
  • 6

2 Answers2

1

Your problem is you put procedural delays inside the always block of your HA, and it misses updates to a and b while the block is suspended.

Write it as

module HA (input a, b,
    output cout,
    output sum);

    reg [1:0] temp;

    always @ (*) begin
        temp = a + b;
    end
    assign #2 cout = temp[1];
    assign #1 sum = temp[0];
endmodule

You can also use non-blocking assignments

module HA (input a, b,
    output reg cout,
    output reg sum);

    reg [1:0] temp;

    always @ (a or b) begin
        temp = a + b;
        cout <= #2 temp[1];
        sum  <= #1 temp[0];
    end
endmodule

Note that putting delay in any RTL code is highly unusual. Synthesis tools will ignore them, and if there is any functionality that depends on delays, your synthesised code will not work.

dave_59
  • 39,096
  • 3
  • 24
  • 63
0

The HA module uses an odd coding style. The combinational always block is assigning and reading from the same signal (temp), and there are delays. That yields unpredictable results on different simulators.

This works as expected:

module HA (
    input a, b,
    output cout,
    output sum
);
    wire [1:0] temp = a + b;
    assign #2 cout = temp[1];
    assign #1 sum  = temp[0];
endmodule
toolic
  • 57,801
  • 17
  • 75
  • 117