From C64-Wiki
Jump to: navigation, search

SBC (short for "SuBtract with Carry") is the mnemonic for a machine language instruction which subtracts the byte held at the specified memory address, from the one currently held in the accumulator, leaving the result in the accumulator: The state of the carry flag before the subtraction takes place, is taken as an incoming "borrow" flag in the computation. After the subtraction, the carry flag will indicate where a new "borrow" was "left over". Contrary to many other CPUs, the architecture of the 65xx family (of which the 6510 in the Commodore 64 is a member) does not have separate instructions for subtraction with or without taking the carry flag as the incoming "borrow" flag. Therefore the programmer must make sure that carry is set prior to a subtraction for which there is no incoming borrow to consider – this is usually accomplished with the SEC instruction, for example:

LDA Num1    Read the first byte value from Num1
SEC         No incoming borrow; make sure carry is set
SBC Num2    Perform the subtraction
STA Result  Store result in Result

This example takes the byte stored in a memory address labelled Num2, and subtracts it from the contents of a memory address labelled Num1, and stores the resulting difference in a third place with the label Result.

In a few special cases (such as immediately following a BCC), the carry is always set in any situation where the CPU reaches the SBC instruction; this allows for leaving out the SEC, saving 1 byte and 2 machine cycles execution time.

The inclusion of the incoming borrow provides a simple means to subtract binary integers of arbitrary length, "spread" across two or more bytes: Subtract the least significant byte pair first with the carry flag set, then do the subtraction for increasingly significant bytes without modifying the carry prior to each; this will let the outgoing borrow from one subtraction "travel" from one byte to the next. The following example assumes that Num1 and Num2 mark the first of two series of bytes, of increasing significance, each holding a "dozens-of-bits" integer, and stores the resulting difference as a series of byte in the same order, beginning at label Result:

LDA Num1     Subtract least
SEC          significant pair
SBC Num2     with the carry
STA Result   set (= no borrow)

LDA Num1+1   Subtract next
SBC Num2+1   pair without
STA Result+1 changing carry

LDA Num1+2   and the next
SBC Num2+2   pair...
STA Result+2

... etc.

SBC handles both signed and unsigned integers: Both examples above will yield correct results for any pair of integer where both the integers and the resulting difference are within the limits imposed by the number of bits involved: The single-byte addition example works for unsigned integers in the range 0–255/$0–FF as well as signed integers in the −128–+127/$−80–+7F range. For 16-bit (2 bytes) unsigned integers, the limits are 0–65535/$0–FFFF; for signed 16-bit quantities, it's −32768–+32767/$−8000–+7FFF, etc.

Addressing modes[edit]

Opcode Addressing
in bytes
Number of
Dec Hex
233 E9 Immediate SBC #nn 2 2
237 ED Absolute SBC nnnn 3 4
253 FD Absolute,X SBC nnnn,X 3 4*
249 F9 Absolute,Y SBC nnnn,Y 3 4*
229 E5 Zeropage SBC nn 2 3
245 F5 Zeropage,X SBC nn,X 2 4
225 E1 Indexed-indirect SBC (nn,X) 2 6
241 F1 Indirect-indexed SBC (nn),Y 2 5*

SBC supports eight different addressing modes, as shown in the table at right. In the assembler formats listed, nn represents a single-byte (8-bit) figure, and nnnn is a two-byte (16-bit) address.
With some addressing forms (marked with an asterisk, *, in the "Number of cycles" column) the execution time for SBC depends on the circumstances: In cases where the indexing requires the CPU to "reach across" a page boundary from the base address, the execution time is 1 cycle longer than listed here.

CPU flags[edit]

SBC affects 4 of the CPU's status flags:

  • The negative status flag is set if the result is negative, i.e. has it's most significant bit set.
  • The overflow status flag is set if the operation results in an overflow.
  • The zero flag is set if the result is zero, or cleared if it is non-zero.
  • The carry flag is set or cleared depending on the result.