I want to add A, B and the carry in. This should be done using only one big adder. But when I look at the circuit generated, there is an extra adder for the carry in. How can I solve this problem?

Picture:

Code:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
port(
a, b : in unsigned(3 downto 0);
result : out unsigned(3 downto 0);
clk : in STD_LOGIC;
cin : in integer
);
end entity;
signal a_r, b_r, result_r : unsigned(3 downto 0);
signal cin_r : integer;
begin
process(clk)
begin
if rising_edge(clk) then
a_r <= a;
b_r <= b;
cin_r <= cin;
result_r <= a_r + b_r + to_unsigned(cin_r, 4);
end if;
result <= result_r;
end process;
end behavioral;

• speculation here, so not an answer. Cin is an integer, you may need to extract bit 4 external to your adder process and forward the single bit. But, it looks like it has synthesised what you have asked for, which is two adders, two plus signs in the expression. What width does the function to_unsigned expand up to? If you have a specific FPGA vendor in mind, then they will provide libraries from which you can directly generate full adders. The generic logic you are generating in this step may be synthesised correctly by a vendor's software. – Neil_UK Aug 27 '16 at 16:06
• What does the technology map output look like. RTL is only half the story - even in Verilog you can end up with the same "two adders" in RTL, but there is only one in the technology map. But either way, your signals seem to be all the wrong size as the others have pointed out, – Tom Carpenter Aug 27 '16 at 16:39
• cin, cin_r S.B. std_logic (1 bit), result_r <= a_r + b_r + ("" & cin_r); Converts cin_r to unsigned, length 1. – user8352 Aug 27 '16 at 16:52
• You have removed the problem from your question. The good news is it can be recovered from the edit history. You could show your modifications and results in a separate answer. It might even get up votes. – user8352 Aug 28 '16 at 0:41

Why are cin and cin_r of type integer? You can see in the Altera RTL view that it's trying to synthesize a 32-bit wide signal!

Typically, a VHDL adder would take two unsigned or signed inputs of appropriate width and the cin input of type std_logic or similar one-bit-wide signal. Try changing the two integers into std_logics and seeing if the result_r <= a_r + b_r + ("" & cin_r); (suggested by user8352) can correctly infer an adder with carry-in.

• When changing cin and cin_r to STD_LOGIC I get the following error: Error (10476): VHDL error at adder.vhd(21): type of identifier "cin_r" does not agree with its usage as "natural" type – gilianzz Aug 27 '16 at 19:38
• I don't have any VHDL tools handy, but I changed the form to user8352's comment suggestion. – user2943160 Aug 27 '16 at 23:19

To solve this problem you have to change cin and cin_r to STD_LOGIC. The line

result_r <= a_r + b_r + to_unsigned(cin_r, 4);


becomes

result_r <= a_r + b_r + ("" & cin_r);


The new code is:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
port(
a, b : in unsigned(3 downto 0);
result : out unsigned(3 downto 0);
clk, cin : in STD_LOGIC
);
end entity;
signal a_r, b_r, result_r : unsigned(3 downto 0);
signal cin_r : STD_LOGIC;
begin
process(clk)
begin
if rising_edge(clk) then
a_r <= a;
b_r <= b;
cin_r <= cin;
result_r <= a_r + b_r + ("" & cin_r);
end if;
result <= result_r;
end process;
end behavioral;


All current answers are bad design. a b and c should all be either integers or unsigneds. Correctly defining the ranges will solve the problem.

Either cin and cin_r become

unsigned(0 downto 0)


and a and b stay as they are now or you put

a : natural range 0 to 7
b : natural range 0 to 7
a_r : natural range 0 to 7
b_r : natural range 0 to 7
cin : natural range 0 to 1
cin_r : natural range 0 to 1