SBC
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
.
There two operational modes for SBC depending on the decimal flag. If this flag is set the operation uses BCD semantics. In addition the zero flag, negative flag and overflow flag usually set accordingly are remain undefined in this mode.
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 | edit source]
Opcode | Addressing mode |
Assembler format |
Length in bytes |
Number of cycles | |
Dec | Hex | ||||
233 | E9 | Immediate | SBC #nn | 2 | 2 |
235 | EB | 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 8 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.
Opcode $EB is an illegal opcode implementing SBC #nn
CPU flags[edit | edit source]
SBC affects 4 of the CPU's status flags:
- The negative flag is set if the result is negative, i.e. has its most significant bit set (not in decimal mode).
- The overflow flag is set if the operation results in an overflow (not in decimal mode).
- The zero flag is set if the result is zero, or cleared if it is non-zero (not in decimal mode).
- The carry flag is set or cleared depending on the result.
Examples[edit | edit source]
Negate A
Many processors have a native negate instruction, which subtracts the value from zero. Here we must manually calculate the two's complement of A, which involves a one's complement and increment by one:
; A = -A EOR #$FF ; One's complement SEC ADC #$00 ; Increment by adding 1 through the carry flag
As an optimization the SEC could be omitted if the code before provides an already set Carry Flag.