Good evening all! I am facing an unexpected behaviour of the timing analysis of my bypass (or skip) carry adder. In particular, the implementation of the adder looks correct to me, the Modelsim simulation yields correct functional results with all the input combination, but the timing analysis doesn't sound correct. In particular, i am working with Quartus Prime Lite (Cyclone IV hardware platform) and the timing analyzer which specifies the maximum clock frequency appropriate for the correct functioning of the circuit. Basically, if imposing an arbitrary clock to the circuit of 1 GHz, the maximum frequency from the timing analyzer results about 180 MHz, while the same analysis on a Ripple Carry Adder yields a maximum frequency of about 200 MHz. How can the CBA perform worse than the RCA in terms of delay? What am i missing? The two adders basically differ only for the skip logic and the multiplexer used in the CBA (the full adders are identical, i only bring out the propagate signal for the CBA cell).
The overall circuit (first code below) is a 16 bit signed adder, with clocked input and output register, implemented with a 16 bit RCA or a 16 bit (four 4-bit cells) CBA.
I am pasting the code of the two circuits below:
Overall Adder with input and output registers:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_Std.all;
-- This circuit implements a 16 bit adder with different solutions.
-- In particular, ripple carry adder, carry select adder and carry bypass adder
-- are compared.
entity Adder16Bit is
port (
-- Input ports
A : in signed(15 downto 0);
B : in signed(15 downto 0);
Resetn : in std_logic;
Clk : in std_logic;
-- Output ports
S : out signed(15 downto 0);
Overflow : out std_logic
);
end Adder16Bit;
Architecture Behavior of Adder16Bit is
signal Sint : signed(15 downto 0);
signal A_reg: signed(15 downto 0);
signal B_reg: signed(15 downto 0);
signal S_reg: signed(15 downto 0);
signal Overflow_int: std_logic;
-- Ripple Carry Adder
component RippleCarryAdderNBit is
GENERIC ( N : integer:= 16);
port (
-- Input ports
A : in signed((N-1) downto 0);
B : in signed((N-1) downto 0);
Cin : in std_logic;
-- Output ports
S : out signed((N-1) downto 0);
Overflow : out std_logic
);
end component;
-- Carry Bypass Adder
COMPONENT CarryBypassAdder16Bit is
port (
-- Input ports
A : in signed(15 downto 0);
B : in signed(15 downto 0);
Cin: in std_logic;
-- Output ports
S : out signed(15 downto 0);
Overflow : out std_logic
);
end COMPONENT;
-- Synchronization register
component regn
GENERIC ( N : integer:=4);
PORT (R : IN SIGNED(N-1 DOWNTO 0);
Clock, Resetn : IN STD_LOGIC;
Q : OUT SIGNED(N-1 DOWNTO 0));
END component;
-- D type FF
component flipflop IS
PORT (D, Clock, Resetn : IN STD_LOGIC;
Q : OUT STD_LOGIC);
END component;
begin
-- Instance of FF
FF1:flipflop port map(Overflow_int,Clk,Resetn,Overflow);
-- Instances of register
Reg1:regn generic map(16)
port map(A,Clk,Resetn,A_reg);
Reg2:regn generic map(16)
port map(B,Clk,Resetn,B_reg);
Reg3:regn generic map(16)
port map(Sint,Clk,Resetn,S);
-- Instances of Adders
--RcaInst: RippleCarryAdderNBit PORT MAP(A_reg,B_reg,'0',Sint,Overflow_int); -- Ripple Carry Adder
CbaInst: CarryBypassAdder16Bit PORT MAP(A_reg,B_reg,'0',Sint,Overflow_int); -- Carry Bypass Adder
end Behavior;
Ripple Carry Adder
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_Std.all;
-- Ripple carry adder subcircuit
entity RippleCarryAdderNBit is
GENERIC ( N : integer:= 16);
port (
-- Input ports
A : in signed((N-1) downto 0);
B : in signed((N-1) downto 0);
Cin : in std_logic;
-- Output ports
S : out signed((N-1) downto 0);
Overflow : out std_logic
);
end RippleCarryAdderNBit;
Architecture Behavior of RippleCarryAdderNBit is
signal Cint : std_logic_vector((N-1) downto 0);
signal Sint : std_logic_vector((N-1) downto 0);
-- Full adder
component FA
port (
-- Input ports
a : in std_logic;
b : in std_logic;
cin : in std_logic;
-- Output ports
s : out std_logic;
cout : out std_logic
);
end component;
begin
-- Overflow detection
Overflow <= (Cint(N-1) XOR Cint(N-2));
-- Instances of Adders using generate
GENERATE_ADDER : FOR i IN 0 to (N-1) GENERATE
-- At first stage, usually no carry in
FirstStage : IF (i = 0) GENERATE
AddInst0 : FA PORT MAP(std_logic(A(i)),std_logic(B(i)),Cin,Sint(i),Cint(i));
END GENERATE FirstStage;
-- Other stages take carry in from previous one
OtherStages : IF (i > 0) GENERATE
AddInstI : FA PORT MAP(std_logic(A(i)),std_logic(B(i)),Cint(i-1),Sint(i),Cint(i));
END GENERATE OtherStages;
END GENERATE GENERATE_ADDER;
-- Cast output sum
S <= signed(Sint);
end Behavior;
Carry Bypass Adder (4-bit sub cell first, complete adder with 4 cells instance below)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_Std.all;
-- This circuit implements a single 4-bit cell
-- for a carry bypass adder
entity CBACell is
port (
-- Input ports
A : in signed(3 downto 0);
B : in signed(3 downto 0);
Cin: in std_logic;
-- Output ports
C : out std_logic;
S : buffer signed(3 downto 0);
Cinternal: out std_logic_vector(3 downto 0)
);
end CBACell;
Architecture Behavior of CBACell is
signal Cint : std_logic_vector(3 downto 0);
signal Propagate : std_logic_vector(3 downto 0);
signal CarryP: std_logic;
-- Full adder
component FA_prop
port (
-- Input ports
a : in std_logic;
b : in std_logic;
cin : in std_logic;
-- Output ports
s : out std_logic;
cout : out std_logic;
p : buffer std_logic
);
end component;
begin
-- Instances of Adders
FA0:FA_prop port map(std_logic(A(0)),std_logic(B(0)),Cin,S(0),Cint(0),Propagate(0));
FA1:FA_prop port map(std_logic(A(1)),std_logic(B(1)),Cint(0),S(1),Cint(1),Propagate(1));
FA2:FA_prop port map(std_logic(A(2)),std_logic(B(2)),Cint(1),S(2),Cint(2),Propagate(2));
FA3:FA_prop port map(std_logic(A(3)),std_logic(B(3)),Cint(2),S(3),Cint(3),Propagate(3));
-- Logic condition for carry propagation
CarryP <= (Propagate(0) AND Propagate(1)) AND (Propagate(2) AND Propagate(3));
C <= (CarryP AND Cin) OR Cint(3);
Cinternal <= Cint;
end Behavior;
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_Std.all;
-- carry bypass adder subcircuit
entity CarryBypassAdder16Bit is
port (
-- Input ports
A : in signed(15 downto 0);
B : in signed(15 downto 0);
cin : in std_logic;
-- Output ports
S : out signed(15 downto 0);
Overflow : out std_logic
);
end CarryBypassAdder16Bit;
Architecture Behavior of CarryBypassAdder16Bit is
-- Declare the single carry bypass adder cell (4 bits)
component CBACell
port (
-- Input ports
A : in signed(3 downto 0);
B : in signed(3 downto 0);
Cin: in std_logic;
-- Output ports
C : out std_logic;
S : buffer signed(3 downto 0);
Cinternal : out std_logic_vector(3 downto 0)
);
end component;
signal CarryIntern: std_logic_vector(3 downto 0);
signal CarryOutSingleBlock: std_logic_vector(3 downto 0);
-- Full adder
component FA
port (
-- Input ports
a : in std_logic;
b : in std_logic;
cin : in std_logic;
-- Output ports
s : out std_logic;
cout : out std_logic
);
end component;
-- regular ripple carry adder for last block
component RippleCarryAdderNBit is
GENERIC ( N : integer:= 16);
port (
-- Input ports
A : in signed((N-1) downto 0);
B : in signed((N-1) downto 0);
Cin : in std_logic;
-- Output ports
S : out signed((N-1) downto 0);
Overflow : out std_logic
);
end component;
begin
-- Instantiate four cells to implement the full 16 bit adder
Cell1:CBACell port map(A(3 downto 0),B(3 downto 0),cin,CarryIntern(0),S(3 downto 0));
Cell2:CBACell port map(A(7 downto 4),B(7 downto 4),CarryIntern(0),CarryIntern(1),S(7 downto 4));
Cell3:CBACell port map(A(11 downto 8),B(11 downto 8),CarryIntern(1),CarryIntern(2),S(11 downto 8));
Cell4:CBACell port map(A(15 downto 12),B(15 downto 12),CarryIntern(2),CarryIntern(3),S(15 downto 12),CarryOutSingleBlock);
--cell4:RippleCarryAdderNBit generic map(4) port map(A(15 downto 12),B(15 downto 12),CarryIntern(2),S(15 downto 12),CarryIntern(3));
Overflow <= CarryOutSingleBlock(3) XOR CarryOutSingleBlock(2);
end Behavior;
Full Adder code:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_Std.all;
-- This circuit implements the full adder,
-- which takes the carry from previous stages,
-- sums two bits and outputs the carry of the new sum
entity FA_prop is
port (
-- Input ports
a : in std_logic;
b : in std_logic;
cin : in std_logic;
-- Output ports
s : out std_logic;
cout : out std_logic;
p : buffer std_logic
);
end FA_prop;
Architecture Behavior of FA_prop is
signal c1,s1,c2,s2 : std_logic;
component MUX_2_TO_1 is
port
(
-- Input ports
Input1 : in STD_LOGIC;
Input2 : in STD_LOGIC;
Sel : in STD_LOGIC;
-- Output ports
Output : out STD_LOGIC
);
end component;
begin
p <= (a XOR b);
s <= p XOR cin;
MuxInst: MUX_2_TO_1 PORT MAP(b,Cin,p,cout);
end Behavior;
Thanks in advance for any suggestion!
EDIT:
Attaching a screenshot of the carry bypass adder as implemented in the RTL viewer (what i want) and the post-mapping implementation (what the compiler does):

