6502 Assembly

From Wikibooks, open books for an open world
Jump to navigation Jump to search

This book is a guide to the 6502 Assembly language. This book will teach the different memory addressing modes and instructions of the 8-bit 6502 processor.

You might want to learn 6502 assembly language programming if you want to do Atari 8 Bit Programming, Commodore 64 Programming, Acorn 8 Bit Programming, Apple II Programming, NES Programming or Super NES Programming.

Memory Addressing Modes[edit]

These are the thirteen memory addressing modes for the 6502 processor including some examples.

Accumulator: A[edit]

The Accumulator is implied as the operand, so no address needs to be specified.

Example

Using the ASL (Arithmetic Shift Left) instruction with no operands, the Accumulator is always the value being shifted left.

ASL

Implied: i[edit]

The operand is implied, so it does not need to be specified.

Example

The operands being implied here are X, the source of the transfer, and A, the destination of the transfer.

TXA

Immediate: #[edit]

The operand is used directly to perform the computation.

Example

The value $22 is loaded into the Accumulator.

LDA #$22

Absolute: a[edit]

A full 16-bit address is specified and the byte at that address is used to perform the computation.

Example

The value at address $D010 is loaded into the X register.

LDX $D010

Zero Page: zp[edit]

A single byte specifies an address in the first page of memory ($00xx), also known as the zero page, and the byte at that address is used to perform the computation.

Example

The value at address $0002 is loaded into the Y register.

LDY $02

Relative: r[edit]

The offset specified is added to the current address stored in the Program Counter (PC). Offsets can range from -128 to +127.

Example

The offset $2D is added to the address in the Program Counter (say $C100). The destination of the branch (if taken) will be $C12D.

BPL $2D

Absolute Indexed with X: a,x[edit]

The value in X is added to the specified address for a sum address. The value at the sum address is used to perform the computation.

Example

The value $02 in X is added to $C001 for a sum of $C003. The value $5A at address $C003 is used to perform the add with carry (ADC) operation.

ADC $C001,X

Absolute Indexed with Y: a,y[edit]

The value in Y is added to the specified address for a sum address. The value at the sum address is used to perform the computation.

Example

The value $03 in Y is added to $F001 for a sum of $F004. The value $EF at address $F004 is incremented (INC) and $F0 is written back to $F004.

INC $F001,Y

Zero Page Indexed with X: zp,x[edit]

The value in X is added to the specified zero page address for a sum address. The value at the sum address is used to perform the computation.

Example

The value $02 in X is added to $01 for a sum of $03. The value $A5 at address $0003 is loaded into the Accumulator.

LDA $01,X

Zero Page Indexed with Y: zp,y[edit]

The value in Y is added to the specified zero page address for a sum address. The value at the sum address is used to perform the computation.

Example

The value $03 in Y is added to $01 for a sum of $04. The value $E3 at address $0004 is loaded into the Accumulator.

LDA $01,Y

Zero Page Indexed Indirect: (zp,x)[edit]

The value in X is added to the specified zero page address for a sum address. The little-endian address stored at the two-byte pair of sum address (LSB) and sum address plus one (MSB) is loaded and the value at that address is used to perform the computation.

Example

The value $02 in X is added to $15 for a sum of $17. The address $D010 at addresses $0017 and $0018 will be where the value $0F in the accumulator is stored.

STA ($15,X)

Zero Page Indirect Indexed with Y: (zp),y[edit]

The value in Y is added to the address at the little-endian address stored at the two-byte pair of the specified address (LSB) and the specified address plus one (MSB). The value at the sum address is used to perform the computation. Indeed addressing mode actually repeats exactly the accumulator register's digits.

Example

The value $03 in Y is added to the address $C235 at addresses $002A and $002B for a sum of $C238. The value $2F at $C238 is shifted right (yielding $17) and written back to $C238.

LSR ($2A),Y

Instructions[edit]

These are the instructions for the 6502 processor including an ASCII visual, a list of affected flags, and a table of opcodes for acceptable addressing modes.

Load and Store[edit]

Load Accumulator with Memory: LDA

M -> A

Flags: N, Z

Addressing ModeOpcode
aAD
a,xBD
a,yB9
#A9
zpA5
(zp,x)A1
zp,xB5
(zp),yB1

Load Index X with Memory: LDX

M -> X

Flags: N, Z

Addressing ModeOpcode
aAE
a,yBE
#A2
zpA6
zp,yB6

Load Index Y with Memory: LDY

M -> Y

Flags: N, Z

Addressing ModeOpcode
aAC
a,xBC
#A0
zpA4
zp,xB4

Store Accumulator in Memory: STA

A -> M

Flags: none

Addressing ModeOpcode
a8D
a,x9D
a,y99
zp85
(zp,x)81
zp,x95
(zp),y91

Store Index X in Memory: STX

X -> M

Flags: none

Addressing ModeOpcode
a8E
zp86
zp,y96

Store Index Y in Memory: STY

Y -> M

Flags: none

Addressing ModeOpcode
a8C
zp84
zp,x94

Arithmetic[edit]

Add Memory to Accumulator with Carry: ADC

A + M + C -> A

Flags: N, V, Z, C

Addressing ModeOpcode
a6D
a,x7D
a,y79
#69
zp65
(zp,x)61
zp,x75
(zp),y71

Subtract Memory from Accumulator with Borrow: SBC

A - M - ~C -> A

Flags: N, V, Z, C

Addressing ModeOpcode
aED
a,xFD
a,yF9
#E9
zpE5
(zp,x)E1
zp,xF5
(zp),yF1

Increment and Decrement[edit]

Increment Memory by One: INC

M + 1 -> M

Flags: N, Z

Addressing ModeOpcode
aEE
a,xFE
zpE6
zp,xF6

Increment Index X by One: INX

X + 1 -> X

Flags: N, Z

Addressing ModeOpcode
iE8

Increment Index Y by One: INY

Y + 1 -> Y

Flags: N, Z

Addressing ModeOpcode
iC8

Decrement Memory by One: DEC

M - 1 -> M

Flags: N, Z

Addressing ModeOpcode
aCE
a,xDE
zpC6
zp,xD6

Decrement Index X by One: DEX

X - 1 -> X

Flags: N, Z

Addressing ModeOpcode
iCA

Decrement Index Y by One: DEY

Y - 1 -> Y

Flags: N, Z

Addressing ModeOpcode
i88

Shift and Rotate[edit]

Arithmetic Shift Left One Bit: ASL

C <- 7 6 5 4 3 2 1 0 <- 0

Flags: N, Z, C

Addressing ModeOpcode
a0E
a,x1E
A0A
zp06
zp,x16

Logical Shift Right One Bit: LSR

0 -> 7 6 5 4 3 2 1 0 -> C

Flags: N, Z, C

Addressing ModeOpcode
a4E
a,x5E
A4A
zp46
zp,x56

Rotate Left One Bit: ROL

C <- 7 6 5 4 3 2 1 0 <- C

Flags: N, Z, C

Addressing ModeOpcode
a2E
a,x3E
A2A
zp26
zp,x36

Rotate Right One Bit: ROR

C -> 7 6 5 4 3 2 1 0 -> C

Flags: N, Z, C

Addressing ModeOpcode
a6E
a,x7E
A6A
zp66
zp,x76

Logic[edit]

AND Memory with Accumulator: AND

A & M -> A

Flags: N, Z

Addressing ModeOpcode
a2D
a,x3D
a,y39
#29
zp25
(zp,x)21
zp,x35
(zp),y31

OR Memory with Accumulator: ORA

A | M -> A

Flags: N, Z

Addressing ModeOpcode
a0D
a,x1D
a,y19
#09
zp05
(zp,x)01
zp,x15
(zp),y11

Exclusive-OR Memory with Accumulator: EOR

A ^ M -> A

Flags: N, Z

Addressing ModeOpcode
a4D
a,x5D
a,y59
#49
zp45
(zp,x)41
zp,x55
(zp),y51

Compare and Test Bit[edit]

Status Flags
Bit Symbol Name Description
7 N Negative Result was less than zero
6 V Overflow Last result was too large for destination register
5 - Always set
4 B Break 1 if Interrupt request has been triggered by an BRK opcode
3 D Decimal Decimal mode flag (math would be performed in decimal, not hex)
2 I Interrupt Disable Set to 1 to disable interrupts
1 Z Zero Result was zero
0 C Carry Carry/Borrow flag used in math and rotate operations, Result was >= 0

The CPU uses the following status flags. The Negative (N), Zero (Z), and Carry (C) flags are used for conditional (branch) instructions:

For all Compare instructions:

ConditionNZC
Register < Memory100
Register = Memory011
Register > Memory001

Compare Memory and Accumulator: CMP

A - M

Flags: N, Z, C

Addressing ModeOpcode
aCD
a,xDD
a,yD9
#C9
zpC5
(zp,x)C1
zp,xD5
(zp),yD1

Compare Memory and Index X: CPX

X - M

Flags: N, Z, C

Addressing ModeOpcode
aEC
#E0
zpE4

Compare Memory with Index Y: CPY

Y - M

Flags: N, Z, C

Addressing ModeOpcode
aCC
#C0
zpC4

Test Bits in Memory with Accumulator: BIT

A & M

Flags: N = M7, V = M6, Z

Addressing ModeOpcode
a2C
#89
zp24

Branch[edit]

Branch on Carry Clear: BCC

Branch if C = 0

Flags: none

Addressing ModeOpcode
r90

Branch on Carry Set: BCS

Branch if C = 1

Flags: none

Addressing ModeOpcode
rB0

Branch on Result Zero: BEQ

Branch if Z = 1

Flags: none

Addressing ModeOpcode
rF0

Branch on Result Minus: BMI

Branch if N = 1

Flags: none

Addressing ModeOpcode
r30

Branch on Result not Zero: BNE

Branch if Z = 0

Flags: none

Addressing ModeOpcode
rD0

Branch on Result Plus: BPL

Branch if N = 0

Flags: none

Addressing ModeOpcode
r10

Branch on Overflow Clear: BVC

Branch if V = 0

Flags: none

Addressing ModeOpcode
r50

Branch on Overflow Set: BVS

Branch if V = 1

Flags: none

Addressing ModeOpcode
r70

Transfer[edit]

Transfer Accumulator to Index X: TAX

A -> X

Flags: N, Z

Addressing ModeOpcode
iAA

Transfer Index X to Accumulator: TXA

X -> A

Flags: N, Z

Addressing ModeOpcode
i8A

Transfer Accumulator to Index Y: TAY

A -> Y

Flags: N, Z

Addressing ModeOpcode
iA8

Transfer Index Y to Accumulator: TYA

Y -> A

Flags: N, Z

Addressing ModeOpcode
i98

Transfer Stack Pointer to Index X: TSX

S -> X

Flags: N, Z

Addressing ModeOpcode
iBA

Transfer Index X to Stack Pointer: TXS

X -> S

Flags: none

Addressing ModeOpcode
i9A

Stack[edit]

Push Accumulator on Stack: PHA

A -> S

Flags: none

Addressing ModeOpcode
i48

Pull Accumulator from Stack: PLA

S -> A

Flags: N, Z

Addressing ModeOpcode
i68

Push Processor Status on Stack: PHP

P -> S

The processor status is stored as a single byte with the following flags bits from high to low: NV-BDIZC.

Flags: none

Addressing ModeOpcode
i08

Pull Processor Status from Stack: PLP

S -> P

Setting the processor status from the stack is the only way to clear the B (Break) flag.

Flags: all

Addressing ModeOpcode
i28

Subroutines and Jump[edit]

Jump to New Location: JMP

Jump to new location

Flags: none

Addressing ModeOpcode
a4C
(a)6C

Jump to New Location Saving Return Address: JSR

Jump to Subroutine

Flags: none

Addressing ModeOpcode
a20

Return from Subroutine: RTS

Return from Subroutine

Flags: none

Addressing ModeOpcode
i60

Return from Interrupt: RTI

Return from Interrupt

Flags: all

Addressing ModeOpcode
i40

Set and Clear[edit]

Set Carry Flag: SEC

1 -> C

Flags: C = 1

Addressing ModeOpcode
i38

Set Decimal Mode: SED

1 -> D

Flags: D = 1

Addressing ModeOpcode
iF8

Set Interrupt Disable Status: SEI

1 -> I

Flags: I = 1

Addressing ModeOpcode
i78

Clear Carry Flag: CLC

0 -> C

Flags: C = 0

Addressing ModeOpcode
i18

Clear Decimal Mode: CLD

0 -> D

Flags: D = 0

Addressing ModeOpcode
iD8

Clear Interrupt Disable Status: CLI

0 -> I

Flags: I = 0

Addressing ModeOpcode
i58

Clear Overflow Flag: CLV

0 -> V

Flags: V = 0

Addressing ModeOpcode
iB8

Miscellaneous[edit]

No Operation: NOP

No Operation

Flags: none

Addressing ModeOpcode
iEA

Break: BRK

Force an Interrupt

Flags: B = 1, I = 1

Addressing ModeOpcode
i00

Further reading[edit]