I have almost successfully implemented n-bit adder-subtractor. It works fine, except for one thing.
Carry after an unsigned subtraction doesn't behave, how i expected.
Here is on page 11 the circuit which i have build. In my opinion i have build it the right way. It is a 4-bit adder/subtractor.
So to understand my troubles with the unsigned carry let's calculate 1111 - 1111 in unsigned. Well 15 - 15 is 0, so it should be 0000. What is the unsigned carry?
Input:
a <= "1111";
b <= "1111";
s <= '1';
The only thing s does, is building a 2's complement of b. Let's do it.
b = 1111
1'st complement
b = 0000
2's complement
b = 0001
Now we can perform an addition 1111 + 0001.
1111
0001
=====
10000
And right here is my (thought) problem. The carry (the 5'th bit) is 1. I have calculated 15-15 = 0 with an overflow carry, which i don't understand at all.
On the other hand, i can calculate 1110 - 1111 (14-15) which should be -1, which can't be represented with unsigned numbers. So here i would expect an overflow bit.
b = 1111
2's complement => 0001
1110
0001
=====
01111
So it tells me that 14-15 is 15 (which is not surprising) but the overflow flag is set to 0.
Did i misunderstood the subtraction overflow bit, or is a unsigned_cout xor sub
missing?
My VHDL-Code:
--full adder
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity fad is
port(
a,b,cin : in std_logic;
o, cout: out std_logic);
end fad;
architecture behavior of fad is
begin
o <= a xor b xor cin;
cout <= (a and b)or (cin and (a xor b));
end behavior;
--adder-subtractor
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity add_sub is
generic(N : natural := 4);
port(
a, b : in std_logic_vector(N-1 downto 0);
sub : in std_logic;
o : out std_logic_vector(N-1 downto 0);
scout, ucout : out std_logic);
end add_sub;
architecture behavior of add_sub is
signal carries : std_logic_vector(N downto 0);
signal bXorSub : std_logic_vector(N-1 downto 0);
component fad is
port( a, b, cin : in std_logic;
o, cout : out std_logic
);
end component;
begin
carries(0) <= sub;
subtraction: for i in 0 to N-1 generate
bXorSub(i) <= b(i) xor sub;
end generate subtraction;
RCA: for i in 0 to N-1 generate
fadN: fad port map(
a => a(i),
b => bXorSub(i),
cin => carries(i),
o => o(i),
cout => carries(i+1));
end generate RCA;
ucout <= carries(N);
scout <= carries(N) xor carries(N-1);
end behavior;
Ok, i slept and now evrything is much clearer ;-)
After an unsigned subtraction the carry has to be '1' otherwise there is an overflow, an here is why.
The ripple carry adder consists of more (here 4) full adders. So we are never really subtracting. However in signed addition, we can calculate for exampe 4 + (-1)
.
With unsigned numers i can't represent a negative number. So in fact, i simply can't calculate 4 - 1
. I dont have any subtractor and i can't represent a negatie number.
So how can i perform such an operation. Because it clearly works. 4 - 1 = 3 (0100 - 0001 = 0011).
The only way, to decrease an unsigned number with only an adder, is to overflow it. The fact, that we can't represent all positive numbers is the solution (with 4 bit is the unsigned maximum 15).
For example we calculate 15 - 15 with 4 bit unsigned numbers. 15 - 15 is 0. So what do we add on "1111" to get "0000"? Simply just a "0001", which ist the Two's complement of 15. We rember:
2's complement = invert the number and add 1
"1111" => "0000"
"0000" + "0001" = "0001".
And then we add this number on our 15.
1111
0001
=====
10000
And there, as you can see is the (right) overflow.
So the last carry-bit by an unsigned subtraction has to be set to '1' if the calculation was performed right. Otherwise, if it is '0', the subtracted number should be negative, wich an unsigned number can not represent.