SBC

From C64-Wiki
Jump to navigationJump to 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.

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]

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]

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]

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.

Links[edit]