Last modified: Sun Jun 14 12:37:34 UTC+0200 2026 © A. Tarpai
ADDITION AND SUBTRACTION WITH THE ADDER
The Adder
[toc]
The 1-bit adder's combinational logic outputs a result- and a carry out bit based on input of two operand- and the carry in bit. The 2-bit output thus is the sum as a binary value, where carry out is the higher order bit: A + B + C = C' Y.
It's a relatively simple digital circuit with a truth table of:
1-bit adder circuit
in in
_|_|_
| A B | A 0 0 0 0 1 1 1 1
| C|_ in B 0 0 1 1 0 0 1 1
out _|C' | C 0 1 0 1 0 1 0 1
|__Y__| _______________________________________
| C' Y 00 01 01 10 01 10 10 11
out
Connecting multiple 1-bit adders sequentially can perform addition of N-bits. This is a 4-bit ripple-carry adder as it was used by the Intel 4004. We are in 1971.
4-bit adder with ripple-carry
bit3 bit3 bit1 bit0
•---------•---------•---------•---------- A[3..0] in
| •-------|-•-------|-•-------|-•-------- B[3..0] in
_|_|_ _|_|_ _|_|_ _|_|_
| A B | | A B | | A B | | A B |
| C|_ | C|_ | C|_ | C|_______CARRY in______
__CARRY out___|C' | \_|C' | \_|C' | \_|C' | |
| |__Y__| |__Y__| |__Y__| |__Y__| |
| | | | | |
| •---------•---------•---------•--------- Y[3..0] out |
| |
| ____ |
|__________________| CF |________________________________________________|
|____|
Carryin and carryout is the same flip-flop, the Carry Flag (CF). It is implemented for multi-digit additions and to signal overflow. It is also the output of that last adder, after adding the msb at the end of the addition–sequence.
This 4-bit adder is used mostly for analysis and for the the examples. But the principle is the same on 8-, 16- or wider bit size.
Addition of binary numbers
Terms: ADDEND + ADDENDUM = SUM (addendum is my term to differentiate between the two)
A 4-bit adder can be used to add binary numbers in the range of 0–15. It signals overflow with the carry bit set to one.
F. ex. adding 5 to 9 the result fits into 4-bits and the carry bit is cleared; while adding 10 to 9 will overflow and the carry bit is set. Columnar addition without intermediate carry:
1 0 0 1 9 1 0 0 1 9
+ 0 1 0 1 5 + 1 0 1 1 10
_______ _______
carry = 0 |1 1 1 0 14 carry = 1 |0 0 1 1 3
__| __|
overflow
Interpreting overflow
Overflow is not an error: the result is somewhat correct as if carry is an extension, the highest order bit of the result does not fit into 4-bits. The overflow gets carried into the carry bit:
1 0 0 1 9
+ 1 0 1 1 10
_______
carry = 1 |0 0 1 1 16 + 3 = 19
__|
Carry can be used to interpret the correct sum, as decimal 19 above by using carry with a value of 24 = 16. See BCD instructions how this was done in the early days.
The above 9 + 10 = 19 also shows as if addition wraps around in the adder:

The adder never overflows
Generally, an N-bit adder with carry has 2 × 2N = 2N+1 output states. It counts from 0 to 2N+1–1.
Considering carry as the Nth bit of the result, the sum is N+1 bits wide, numbers doubled in range. A 4-bit adder produces sum in the 0–31 range:

The A + B + CY sum in a 4-bit adder will be then 5-bits: A + B + CY always fit:

4-bit adder sum on 5 bits
Carry in multi-digit additions
§I was doing some readings about the 4004 microprocessor, which was made for BCD-digit calculations. The multi-digit term was used there. §
For multi-digit additions the carry is used in the following way. Carry is initially cleared. First add the low-order 4-bit, then add the next and so on. The carry bit takes care of overflow in each step, i.e. the adder adds one more when carry is set by the previous addition. This is similar to the columnar addition method on paper.
F. ex. adding two 16-bit numbers with a 4-bit adder:
1_ 0_ 1_ 0__ Carry in = 0
2E83 2 \ E \ 8 \ 3
+ A70F + A \ 7 \ 0 \ F
= D592 = 0 D \_1 5 \_0 9 \_1 2
|
Carry out
After these additions carry = 0, meaning no overflow has occurred. The result fits into 16-bit.
Addition semantics
Additions with carry set
A set carry before addition will add one more to the sum. Therefore, e.g. adding 4 and CY=1 or 5 and CY=0 will produce equivalent results. The adder transforms into the same output state and the semantic of both input combinations is "ADD 5". The only difference is intermediate carry bits – which will have significance for signed interpretation only. For (unsigned) additions these results are identical:

§ Addition semantics of the 4-bit adder §
Add 2N semantics and carry-propagation
The most notable is the last addition, all ones with carry. It can occur in multi-digit additions after overflow in the previous addition.
In multi-digit addition the semantics is add 2N. E.g. on 4-bits, although the value 16 is not a valid 4-bit number, its semantics is plus 16, because this is how in a multi-digit addition can be interpreted.
1_ 1_ 1_ 0__ Carry in = 0
2E86 2 \ E \ 8 \ 6
+ A7FE + A \ 7 \ F \ E
= D682 = 0 D \_1 6 \_1 8 \_1 4
| |
Carry out |
8 + F + 1 = 18h
"add 16"
<------------
carry-propagation
For the second digit (8), the addition leaves the same value in the adder and carry is preserved. It is propagated, so the next addition will add one more. Adding all ones with carry serves the purpose of carry-propagation.
Adding all ones with carry = 1 is similar to adding all zero with carry = 0 in that it does not change the state of the adder:

§ The two additions that do not change the state of the adder §
Subtracting with the adder
§ Terms: MINUEND - SUBTRAHEND = DIFFERENCE §
Early ALU-s contained one adder circuitry only – to save component space on chip. The adder can be fully used for subtraction and for building the SUB instruction logic upon. Why is this possible and how exactly working is the rest of this text is about.
Addition as subtraction
It is possible to use the adder for subtraction based on how additions wrap-around within the whole addition range.
If we ignore carry for a while, subtracting 7 from 10 is equivalent to adding the value of 9 to 10 in a 4-bit adder:

In other words, certain additions can be interpreted as subtraction. By adding the value of 9 to the minuend in this case, the adder performed apparent subtraction i.e. computed the difference between two binary numbers.
There are two different state change possibilities for "ADD 9" in the adder, to move from 10 to 3:
- add 9 and carry = 0 (subtract by two's complement)
- add 8 and carry = 1 (subtract by one's complement)
Two's complement One's complement
of 7 is 9 of 7 is 8
Subtraction Perform addition Perform addition
0 CY 1 CY
1010 = 10 1 0 1 0 10 1 0 1 0 10
- 0111 = 7 + 1 0 0 1 9 + 1 0 0 0 8
_______ _______ _______
0011 = 3 1 |0 0 1 1 3 1 |0 0 1 1 3
___| ___|
Carry set Carry set
The results are indeed identical.
The first method will lead us to storage and representation of signed numbers. Mathematically, subtracting 7 is equivalent to adding −7. In this sense 9 can represent −7 as a stored signed number (on 4-bits). Signed two's complement arithmetic is another chapter.
The second method will lead us to the subtraction algorithm and how the SUB instruction can be implemented in hardware using the adder.
About one's complement
One's complement – or simply complement – is a logical operation, inversion of each bits and can be implemented cheap by inverters (NOT-gates). For example, the one's complement value of 3 is 12 on 4-bits:
Implementing one's complement: logical NOT instruction
+-----+-----+-----+-----+
| 0 | 0 | 1 | 1 | 3
+-----+-----+-----+-----+
| | | |
NOT NOT NOT NOT
| | | |
+-----+-----+-----+-----+
| 1 | 1 | 0 | 0 | 12
+-----+-----+-----+-----+
0011 0011 0011
AND 1100 XOR 1100 + 1100
_________ _________ _________
= 0000 = 1111 = 1111
One's complement pairs have the following properties:
- pairs binary complements each other to all zero (by AND) and to all one-s (by XOR) using other logical instructions
- adding one's complement to the original number results in all one-s. On N-bits, one's complement arithmetically complements the original number to 2N-1 by addition. This property will be used for the subtraction algorithm.
About two's complement
In the example above, 9 is the two's complement value of 7 (on 4 bits). Each binary number has a matching two's complement value.
The following is always true for two's complement pairs:
- addition of any number and its two's complement results in all zero bits in the adder (ignore carry)
- for two values the two's complement equals to itself: 0 and 8 (i.e. half, or 2N-1 on N-bits). But the above rule still holds.
We can see the symmetry for these two values:

To compute the two's complement value of a binary number the following rules are applied:
- invert each bit of the number (producing the so-called one's complement)
- add one to the result, ignoring any carry out of the high order bit position
The operation is reversible. E.g. 7 → 9 → 7. Two's complement values are arranged in unique pairs:

Note that "add one and complement" does NOT WORK. E.g. 4:
0100 = 4 0100 = 4
1011 = 11 complement 0101 = 5 add one
1100 = 12 add one 1010 = 10 complement
correct WRONG!
Subtracting by two's complement
To subtract an arbitrary number B from A using two's complement is a two-step process. First the two's complement of B has to be computed, then this value added to A. The detailed steps using the adder are the following:
complement B carry = 0 add 1 to B carry = 0 add B to A
Since even the Intel 4004 in 1971 had the SUB instruction, this is hypothetical, but good to remember that every addition is also a subtraction by interpretation – and vica versa.
E.g. adding FFh in a byte adder leaves the result one less to the original value.
Two's complement is not suitable to implement a subtraction algorithm, mainly because of how subtracting zero is represented. It can be used to subtract constants, but the most important use is to interpret results after subtraction as it is a form of negation.
Subtracting by complement
One problem is that two's complementing is an arithmetic operation and involves the adder (add one). The solution is, since the two's complement value will be used in a subsequent addition, a set carry bit can be used to add one.
complement B carry = 1 add B to A
Thus, subtraction becomes a sequence of bit inversion and addition:
- set carry
- add complement of B to A
It is not even simpler, but there is a very important property difference in how zero is subtracted by these two methods.
One's complement is real complement, the sum of each pair is a constant value. If we include carry as well, it's a perfect arithmetic complement to zero by addition:

Two's complement does not differentiate between zero and two's complement zero:

Interpreting underflow
When using the adder for subtraction we quickly slip into uncharted territory: negative numbers.
What happens when the subtrahend is bigger that the minuend? Let's perform subtraction of 3 - 14 in our 4-bit adder via the complement and set carry method:
3 - 14 = -11 1 = carry set
0011 = 3
+ 0001 = 1 (complement of 14)
= 0 0101 = 5
|
Carry cleared
Mathematically the result is negative and equals to −11. We got 5 in the adder. Carry = 0 means an underflow has occurred. We must interpret this in code and act, accordingly, e.g. print out the result with a negative sign "−" before the number.
But what is number 5? It is actually the two's complement value of 11:
5 = 0101
invert bits
10 = 1010
add one
11 = 1011
This means that our 4-bit adder can subtract numbers in the range of 0–15. It needs a little bit of work. Interpreting the Carry bit after these additions correctly, the program can deal with negative results in the full range of −15 – 15:

Generally, for an N-bit adder this interpretation range is ± 2N-1.
This interpretation is the origin of signed two's complement representation: below zero comes −1, then −2 etc.

Opposite carry meaning
When an addition is interpreted as subtraction, carry operates the opposite way to signal overflow – more precisely underflow. To get a smaller result, carry = 1 is supposed to be set and it means no underflow has occurred. The carry bit has a different meaning, and it is opposite from addition (the adder operation unchanged!):
- When Carry = 0 → underflow has occurred. The result must be interpreted as negative −1 to −2N-1 by two's complementing
- When Carry = 1 → no underflow after subtraction. The result is positive 0 to 2N-1
Multi-digit subtraction in the adder
A multi-digit subtraction with the adder is performed the following way: set carry before adding the first complement, add the next complement etc. The carry bit takes care of underflow in each step, i.e. the adder adds one less, when CY left cleared by the previous addition – thus apparently subtract one more from the next digit. At the end interpret carry the opposite way: a cleared carry flag means underflow.
Example: a 16-bit subtraction to compute 8436 - 2584 = 5852 decimal (20F4h - A18h = 16DCh) with an adder, showing both 4- and 8-bit versions. Complement of 0A18h is F5E7h.
16-bit sub 16-bit ADDER 2 × 8-bit ADDER 4 × 4-bit ADDER
1__ 1_ 1__ 0_ 1_ 0_ 1__ Carry in
20F4 20F4 20 \ F4 2 \ 0 \ F \ 4
- 0A18 + F5E7 + F5 \ E7 + F \ 5 \ E \ 7
= 16DC 1 16DC 1 16 \_1 DC 1 1 \_0 6 \_1 D \_0 C
| | |
Carry out Carry out Carry out
After these additions carry is set – meaning no underflow occurred and the result is a correct positive value.
Another interesting observation is that it does not matter what granularity the subtraction is computed. 4-, 8- or 16 bits, the results are identical. A 4-bit adder's carry out is just an intermediate carry for the 8-bit adder etc. What matters is the last carry (and that the first carry was set).
Subtraction semantics
Subtractions with carry cleared
It can be seen in multi-digit subtraction, that a cleared carry before addition interpreted as subtraction will add one less to the result, thus the adder apparently subtracts one more.
Adding one less will subtract one more

The semantic of additions interpreted as subtractions is similar to additions. E.g. add 4 with CY=1 is equivalent to adding 5 with CY=0 in the adder and both will have the "SUB 11" semantics. The only difference is intermediate carry bits – which will have significance for signed interpretation only. As for unsigned subtractions these results are identical.
This table shows all possible additions on 4-bit, interpreted as subtraction. These are the subtraction semantics of these additions:

The most notable is how subtract zero is performed by the complement method (add all one's with carry). The other peculiar subtraction is 16 (or 2N in an N-bit adder generally).
Subtract zero by Negative Zero
When subtracting zero with the complement rule, the corresponding addition is all one's with carry. Let's call this value negative zero to distinguish it from the all zero addition.
Addition of negative zero will leave the same result in the adder and will certainly set CY. Thus, signaling no underflow has occurred after subtraction:

Adding the two's complement of 0 = 0 will not set CY.
Subtract 2N semantics
The interpretation is similar to the add 2N case. It can occur in multi-digit subtraction after underflow in the previous subtraction, when the complement of the subtrahend is zero (subtract 15 or 2N-1 with underflow).
In a 4-bit adder, therefore, the semantic is subtract 15 + 1 = 16. As an example, the multi-digit subtraction of 4A3h - 2FEh = 1A5h. Complement of 2FEh is D01h. For the middle digit the adder performs an addition of 0 with carry = 0:
"-16" semantics in 4A3 + D01 + 1 = 1 1A5
1 0_ 0_ 1__ Carry in = 1
4 A 3 4 \ A \ 3
+ D 0 1 + D \ 0 \ 1
_________ = 1 1 \_0 A \_0 5
1 1 A 5 |
Carry out |
No underflow A + 0 + 0 = A
"sub 16"
<------------
borrow-propagation
Borrow-propagation
All zero in addition interpreted as subtraction serves the purpose of borrow-propagation: borrow is preserved without changing the adder state, so the next digit addition will subtract one more.
Binary subtraction
The concept of BORROW
The term borrow comes from manual subtraction, somewhat similar to carry but it means one minus during the columnar method. For a subsequent operation the meaning of carry is add one more – the meaning of borrow is subtract one more.
An example decimal subtraction with pen and paper (without going into negatives now):
carry borrow
+1 <-- -1 -->
5 4 5 4
+ 3 8 - 3 8
_____________ _____________
9 2 1 6
54 + 38 = 92 54 - 38 = 16
- We cannot subtract 8 from 4, so we borrow one and subtract form 14 instead. That is 6. Write it down.
- Next subtract 3 from one less than 5 (or -1 + 5 - 3). That equals 1. Write it down. Done.
We started with no borrow for the first one, but that borrowed. The second subtracted with borrow, but did not borrow. We can start to see a subtract algorithm with the borrow bit, BW ← SUB ← BW:
- subtract with borrow i.e. one more or not (1 or 0)
- produce borrow i.e underflow or not (1 or 0).
A theoretical "SUBBER" circuit
We could – but no-one does – construct a separate binary subber circuit. The subber would subtract the subtrahend (B) with a borrow-bit (BW) from the minuend (A) – and outputs the result and a borrow-bit: A - B - BW = BW' Y.
B
____|____ Y = A - B - BW
| A |
| |
BW ___| SUBBER |__ BW
out |____ ____| in
|
Y
Based on the BORROW concept, a set BW-bit before subtraction would make the subber subtract one more. After subtraction, an underflow sets the BW bit – so the next subtraction subtracts one more.
To start with the 1-bit "SUBBER" combinational logic, the idea is if a 1-bit adder adds to a 0 or 1 bit, a corresponding "subber" would subtract from 0 or 1:
>Subtract 0 from 1 should produce a one bit (1-0=1), Subtract 1 from 1 should produce a zero bit (1-1=0) etc. But subtract 1 from 0 should produce a one bit (0-1=1) and set the bit signaling underflow. The output is 11, this will be the −1 interpretation. Consequently, subtract 1 and borrow from 0 results in 10. That is −2.
add with carry
----------------->
10 11 | 00 01 | 10 11
<-----------------
-2 -1
subtract with borrow
As if a subber's 2-bit output (result bit and BW bit) counts in the opposite direction from the adder:

We can compile a 1-bit subber's truth table:
1-bit subber's truth table:
A 0 0 0 0 1 1 1 1
- B 0 0 1 1 0 0 1 1
- BW 0 1 0 1 0 1 0 1
_______ ________________________________
BW' Y 00 11 11 10 01 00 00 11
Interpretation:
0 0 0 0 1 1 1 1
-0 -1 -1 -2 -0 -1 -1 -2
= 0 -1 -1 -2 1 0 0 -1
An N-bit subber with ripple-borrow would be very similar to the adder, only the combinational logic function is different.
Subber vs. adder comparison
Lets perform a 3-digit subtraction 1187 - 766 = 421 using a 4-bit adder- and subber and compare the operation. This is hex 4A3h - 2FEh.
For the subber:
- clear borrow
- subtract the first lsb digit
- subtract next digit.. etc.
For the adder:
- set carry
- add complement of the first lsb digit
- add next complement.. etc.
With an 4-bit subber
2 F E
_____|________|________|_____
4 A 3 | 4 A 3 |
- 2 F E | 1 __ 1 __ 0 __ |
- 0 0 _|__ 0 1 \_ 1 A \_ 1 5 \_|_ 0 (borrow)
______________ |_____|________|________|_____|
= 0 1 A 5 | | |
1 A 5
With an 4-bit adder
D 0 1
_____|________|________|_____
4 A 3 | 4 A 3 |
+ D 0 1 | 0 __ 0 __ 1 __ |
+ 1 1 _|__ 1 1 \_ 0 A \_ 0 5 \_|_ 1 (carry)
______________ |_____|________|________|_____|
= 1 1 A 5 | | |
1 A 5
The results are identical, 1A5h = 421:
- with the subber, borrow = 0, i.e. the result is positive 1A5h
- with the adder, carry = 1, i.e. the result is positive 1A5h
Interestingly, not only is the output carry bit opposite at the end of the addition sequence, but each intermediate carry bit is also opposite from the subber.
Now when we look at and analyze e.g. the first lsb operation isolated:
_
E E
____|____ ____|____
| 3 | | 3 |
| 0 _ | _ | 1 _ | _
1 _|_ 1 5 \_|_ 0 0 _|_ 0 5 \_|_ 0
|____|____| |____|____|
| |
5 5
subber adder
It seems like subber operation can be substituted by the adder operation by feeding inverted operands and inverting output carry. The output result in this way will be identical.
But we need proof..
Adder equations: proving subtraction in the adder
This is an attempt to prove that a theoretical subber, which subtracts binary values with borrow and generates a borrow bit can be fully emulated with the adder by adding negated operands and addition.
For an N-bit adder let M = 2N.
The N-bit subber equation for difference is:
D = a − b − c
and the adder equation for sum is:
S = a + b + c
where a and b are non-negative integers (a < M, b < M), c is the overflow/underflow bit (carry/borrow), zero or one. We consider carry as bit-extension of the result, thus max(S) = 2N+1-1 or max(S) < 2M.
The N-bit binary adder performs apparent subtraction by adding the complement of its operands (denoted by overline),
where
b = M−1 − b, and
c = 1 − c
then
S = a + b + c = a + M−1 − b + 1 − c = a − b − c + M = D + M
S = D + M means the result sum is M greater than the difference.
This is exactly the congruence modulo relationship between D and S (S = k M + D). The value left in the adder is D difference.
For output carry, it is cleared when S < M:
a + b + c < M
a + M-1 – b + 1 – c < M
a - b - c < 0
D < 0
i.e. carry is cleared, when the Δ difference is negative. Consequently, carry is set when D >= 0. Here we have proven carryout is opposite borrowout.
These two circuits therefore are interchangeable:
_
B B
____|____ ____|____
| A | | A |
| | __ | | __
BW ___| SUBBER |__ BW CY ___| ADDER |__ CY
out |____ ____| in out |____ ____| in
| |
Y Y
Interpreting adder-subtraction
If S = D + M then D = S − M, i.e. the mathematical difference is M less, than the sum in the adder. Based on D = S − M there are three types of relationships between the difference D and sum S in the adder:
Math Δ Value difference in adder negative D<0 S<M zero D=0 S=M positive D>0 S>M
Illustrating this relationship between D and S on 4-bits, considering CY as the 5th bit of the addition:

This also proves how unsigned comparison will work correctly with this method in hardware. CMP is subtraction, testing the result
- for zero (or ZF=1, S=M) means equality
- for larger/smaller the carry bit (CF) will differentiate between the two.
When the Δ difference is negative, S < M. But what is S, the value in the adder? The positive number in the adder is −D = −(S−M) = M − S, which is the two's complement definition (no need for modulo: 0 < S < M).
Adder subtraction examples on 4 bits
In any case, to subtract b+c from a, the addition is a + (M - b - c).
Difference is positive
For 10 − 7 = 3, the Δ difference is positive. The addition is 10 + 7 + 0 = 10 + 8 + 1 = 19 and carry set:

Difference is negative
For 3 − 7 = −4, the Δ difference is negative. The addition is 3 + 7 + 0 = 3 + 8 + 1 = 12 and carry cleared: two's complement of 12 = 4. Or -D = M - S = 16 - 12 = 4. The result should be interpreted as −4:

Implementing the SUB instruction
A desired SUB instruction would subtract binary numbers with a borrow bit – and signal underflow with the same borrow bit set to one in case of underflow (which represents negative results). As if there was a separate subber circuit along with a borrow-flag in the CPU.
The program could simply use e.g. "SUB 7", clear/set- and interpret the borrow bit. The CPU, when it encounters opcode SUB and the value of 7 in the instruction stream, would operate similar to the ADD instruction.
We know by now, that
- the adder can apparently subtract: set carry and add complement,
- a cleared carry followed by add complement will apparently subtract one more,
- subtracting in this way leaves carry cleared on underflow, otherwise it is set.
i.e. there is no need for a separate subber circuit, the already existing adder circuit can implement the SUB instruction in hardware. This is also firmly supported by the Adder equations.
SUB instruction in hardware
Building the SUB instruction logic on top of already present ADD instruction involves only additional bit-inversions (NOT gates). In early processors therefore, fewer circuits were required to perform subtraction. The ADD instruction with carry is the adder operation itself:
SUB instruction in hardware
+-----------------------------------------------------+
|SUB |
| +---------------------------+ |
| | ADD | |
| _____ | ___________ | _____ |
CY <--|--| NOT |<--| CY <--| |<-- CY |<--| NOT |--|<-- CY
(BORROW) | |_____| | | | | |_____| | (BORROW)
| | | ADDER | | _____ |
| | | |<-- OP |<--| NOT |--|<-- OP
| | |___________| | |_____| |
| | | |
| +---------------------------+ |
| |
+-----------------------------------------------------+
This SUB logic:
- uses the same carry flag (CF) for borrow
- interprets a set carry bit for a set borrowin (to subtract one more)
- complements the operand
- making the addition
- sets carry in case of underflow as borrowout
Redefinition of the carry bit to borrow exists purely for the convenience. By redefining the carry bit, SUB becomes similar how ADD is used by the programmer:
- start with clearing carry
- SUB, SUB, ...
- a set carry means an underflow has occurred
Fun fact: the Intel 4004 SUB
The Intel 4004 SUB logic did not complement carry after the operation. It subtracted with borrow but did not produce borrow. Therefore, for multi-digit subtractions, a CMC (complement carry) instruction had to be inserted before each subsequent SUB. This was corrected in 8008 and later.
Intel x86 ADD/SUB and ADC/SBB instructions
Already in 1972, the Intel 8008 implemented different ADC/SBB and ADD/SUB instructions with or without carry. The meaning of carry was also proper BORROW after subtraction: "An underflow (borrow) sets the carry flip-flop" – 8008 Data Sheet 1978. That means internally, subtraction instructions automatically complemented the carry bit before and after adding complement of the operand.
Intel x86 ADD/SUB is only a convenient instruction support for the first addition/subtraction, automatically clearing Carry/Borrow before the operation. For multi-digit operations, subsequent instructions should not alter and consider Carry/Borrow by using ADC/SBB.
If there exists an adder circuit with carry bit, it's perfectly possible to subtract with the CPU using carry manipulation-, complement- and ADD instructions. The adder uses carry, so the basic instruction for x86 is ADC: add with carry. The other instructions operate as if the following logic is built on top of ADC:
ADD SUB SBB
+---------+ +---------+ +---------+
| CLC | | STC | | CMC |
| | | NOT B | | NOT B |
+---------+ +---------+ +---------+
| | | | | |
| ADC | | ADC | | ADC |
| | | | | |
+---------+ +---------+ +---------+
| CMC | | CMC |
+---------+ +---------+
ADC = Add With Carry
SBB = Subtract With Borrow
SUB = Subtract
ADD = Add
CLC = Clear Carry Bit
STC = Set Carry Bit
CMC = Complement Carry Bit
As an example, subtracting 1301h − 0503h = 0DFEh using ADC only.
On 16-bit, these are all equivalent: AX = 0DFEh and CF=0 (no borrow)
16-bit subtraction mov ax, 0x1301 mov bx, 0x0503 sub ax, bx mov ax, 0x1301 mov bx, 0x0503 clc -----------+ sbb ax, bx | 16-bit SUB implementation with SBB mov ax, 0x1301 mov bx, 0x0503 stc -----------+ not bx | adc ax, bx | 16-bit SUB implementation with ADC cmc ------------+
8-bit multi-digit subtractions (pretend ALU is 8-bits). These are all equivalent:
mov al, 0x01 mov bl, 0x03 sub al, bl ; AL=FE CF=1 (borrow) mov al, 0x13 mov bl, 0x05 sbb al, bl ; AL=0D CF=0 (no borrow) mov al, 0x01 mov bl, 0x03 stc ------------+ not bl | SUB implementation with ADC adc al, bl | cmc ------------+ AL=FE CF=1 (borrow) mov al, 0x13 mov bl, 0x05 cmc ------------+ not bl | SBB implementation with ADC adc al, bl | cmc ------------+ AL=0D CF=0 (no borrow) 8-bit old-school multi-digit subtraction with ADC (stc.. adc.. adc.. cmc) mov al, 0x01 mov bl, 0x03 stc not bl adc al, bl ; AL=FE CF=0 mov al, 0x13 mov bl, 0x05 not bl adc al, bl cmc ; AL=0D CF=0 (no borrow)