I'm doing an exercise in which I need to calculate the maximum delay of a 1-bit full adder. In a full adder, the slowest path is the carry_out. Here is how I have designed it:
Let's suppose all gates have a delay of 50ps. Then the slowest path would be the one that goes from c_in to c_out through those two AND gates. Thus, 4 * 50 = 200ps should be the maximum delay.
However, I have implemented this circuit in Verilog, and I find that it is not that slow. Here is the implementation and the test bench:
Full adder
`timescale 10ps/1ps
module full_adder(
input wire a,
input wire b,
input wire cin,
output wire o,
output wire cout
);
//
// cout
//
wire ncin, net0, net1, net2, net3;
not #(5) n0(ncin, cin);
and #(5) a0(net0, ncin, b);
and #(5) a1(net1, a, net0);
or #(5) o0(net2, a, b);
and #(5) a2(net3, net2, cin);
or #(5) o1(cout, net3, net1);
//
// o
//
wire net4;
xor #(5) x0(net4, a, b);
xor #(5) x1(o, net4, cin);
endmodule
Test bench
`timescale 10ps/1ps
`define WAIT_DELAY 16
module full_adder_tb;
reg a = 0;
reg b = 0;
reg cin = 0;
wire o;
wire cout;
full_adder fa(a, b, cin, o, cout);
initial begin
$dumpfile("full_adder_tb.vcd");
$dumpvars(1, full_adder_tb);
cin <= 0; a <= 0; b <= 0; #`WAIT_DELAY;
$display("%d;%d", o, cout);
cin <= 0; a <= 0; b <= 1; #`WAIT_DELAY;
$display("%d;%d", o, cout);
cin <= 0; a <= 1; b <= 0; #`WAIT_DELAY;
$display("%d;%d", o, cout);
cin <= 0; a <= 1; b <= 1; #`WAIT_DELAY;
$display("%d;%d", o, cout);
cin <= 1; a <= 0; b <= 0; #`WAIT_DELAY;
$display("%d;%d", o, cout);
cin <= 1; a <= 0; b <= 1; #`WAIT_DELAY;
$display("%d;%d", o, cout);
cin <= 1; a <= 1; b <= 0; #`WAIT_DELAY;
$display("%d;%d", o, cout);
cin <= 1; a <= 1; b <= 1; #`WAIT_DELAY;
$display("%d;%d", o, cout);
$finish;
end
endmodule
After the test runs, I double check that the output values match the expected with a Python script. I was expecting WAIT_DELAY
to be required to be 20 (200ps) for the test to pass; however, 16 (160ps) is enough.
My test hits the error when the inputs {cin, a, b} transit from {0, 0, 1} to {0, 1, 0}.
My understanding is that this happens because the actual worst case is not the sum of the gates mentioned above, because depending on what was the previous state, and what is the current one, the gates might need less time to get stabilized because some signals will be 'don't care'.
For instance, if {cin, a} = {1, 1}, cout will be always 1 even if {b} starts oscillating every 1ps, because the last or gate will be like 1 + X = 1
(where X
is an invalid state).
In other words, it might happen that the actual critical path is not the one made of 4 gates, because there is no combination of inputs that make all of those gate's outputs to change.
Questions
- Am I right in the above reasoning?
- If so, is this valid out of the simulator, in real life, or can the
X
input of the above example's or gate 'pertubate' its output? - I imagine it will be better to use the worst case in terms of the sum of all the critical path's gate's delays because it is easier, safer and less error prone. Is this correct?