6502 Assembly
From Wikibooks, the open-content textbooks collection
Contents |
[edit] Introduction
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, NES Programming or Super NES Programming.
[edit] Memory Addressing Modes
These are the thirteen memory addressing modes for the 6502 processor including some examples.
Accumulator: A
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
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: #
The operand is used directly to perform the computation.
Example
The value $22 is loaded into the Accumulator.
LDA #$22
Absolute: a
A full 16-bit address is specified and the byte at that address is used to perform the computation.
Example
The value $33 at address $D010 is loaded into the X register.
LDX $D010
Zero Page: zp
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 $B3 at address $0002 is loaded into the Y register.
LDY $02
Relative: r
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
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
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
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
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
Absolute Indexed Indirect: (a,x)
The value in X is added to the specified 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 into the program counter, causing the program to jump to a new address. This mode of addressing is only supported by the JMP instruction.
Example
The value $02 in X is added to $0001 for a sum of $0003. The address $E3A5 at addresses $0003 and $0004 is loaded and jumped to.
JMP ($0001,X)
Zero Page Indexed Indirect: (zp,x)
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 is loaded and the value $33 at $D010 is shifted left (yielding $66) and written back to $D010.
ASL ($15,X)
Zero Page Indirect Indexed with Y: (zp),y
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.
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
[edit] Instructions
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.
[edit] Load and Store
Load Accumulator with Memory: LDA
M -> A
Flags: N, Z
| Addressing Mode | Opcode |
| a | AD |
| a,x | BD |
| a,y | B9 |
| # | A9 |
| zp | A5 |
| (zp,x) | A1 |
| zp,x | B5 |
| (zp),y | B1 |
Load Index X with Memory: LDX
M -> X
Flags: N, Z
| Addressing Mode | Opcode |
| a | AE |
| a,y | BE |
| # | A2 |
| zp | A6 |
| zp,y | B6 |
Load Index Y with Memory: LDY
M -> Y
Flags: N, Z
| Addressing Mode | Opcode |
| a | AC |
| a,x | BC |
| # | A0 |
| zp | A4 |
| zp,x | B4 |
Store Accumulator in Memory: STA
A -> M
Flags: none
| Addressing Mode | Opcode |
| a | 8D |
| a,x | 9D |
| a,y | 99 |
| zp | 85 |
| (zp,x) | 81 |
| zp,x | 95 |
| (zp),y | 91 |
Store Index X in Memory: STX
X -> M
Flags: none
| Addressing Mode | Opcode |
| a | 8E |
| zp | 86 |
| zp,y | 96 |
Store Index Y in Memory: STY
Y -> M
Flags: none
| Addressing Mode | Opcode |
| a | 8C |
| zp | 84 |
| zp,x | 94 |
[edit] Arithmetic
Add Memory to Accumulator with Carry: ADC
A + M + C -> A
Flags: N, V, Z, C
| Addressing Mode | Opcode |
| a | 6D |
| a,x | 7D |
| a,y | 79 |
| # | 69 |
| zp | 65 |
| (zp,x) | 61 |
| zp,x | 75 |
| (zp),y | 71 |
Subtract Memory from Accumulator with Borrow: SBC
A - M - ~C -> A
Flags: N, V, Z, C
| Addressing Mode | Opcode |
| a | ED |
| a,x | FD |
| a,y | F9 |
| # | E9 |
| zp | E5 |
| (zp,x) | E1 |
| zp,x | F5 |
| (zp),y | F1 |
[edit] Increment and Decrement
Increment Memory by One: INC
M + 1 -> M
Flags: N, Z
| Addressing Mode | Opcode |
| a | EE |
| a,x | FE |
| zp | E6 |
| zp,x | F6 |
Increment Index X by One: INX
X + 1 -> X
Flags: N, Z
| Addressing Mode | Opcode |
| i | E8 |
Increment Index Y by One: INY
Y + 1 -> Y
Flags: N, Z
| Addressing Mode | Opcode |
| i | C8 |
Decrement Memory by One: DEC
M - 1 -> M
Flags: N, Z
| Addressing Mode | Opcode |
| a | CE |
| a,x | DE |
| zp | C6 |
| zp,x | D6 |
Decrement Index X by One: DEX
X - 1 -> X
Flags: N, Z
| Addressing Mode | Opcode |
| i | CA |
Decrement Index Y by One: DEY
Y - 1 -> Y
Flags: N, Z
| Addressing Mode | Opcode |
| i | 88 |
[edit] Shift and Rotate
Arithmetic Shift Left One Bit: ASL
C <- 7 6 5 4 3 2 1 0 <- 0
Flags: N, Z, C
| Addressing Mode | Opcode |
| a | 0E |
| a,x | 1E |
| A | 0A |
| zp | 06 |
| zp,x | 16 |
Logical Shift Right One Bit: LSR
0 -> 7 6 5 4 3 2 1 0 -> C
Flags: N, Z, C
| Addressing Mode | Opcode |
| a | 4E |
| a,x | 5E |
| A | 4A |
| zp | 46 |
| zp,x | 56 |
Rotate Left One Bit: ROL
C <- 7 6 5 4 3 2 1 0 <- C
Flags: N, Z, C
| Addressing Mode | Opcode |
| a | 2E |
| a,x | 3E |
| A | 2A |
| zp | 26 |
| zp,x | 36 |
Rotate Right One Bit: ROR
C -> 7 6 5 4 3 2 1 0 -> C
Flags: N, Z, C
| Addressing Mode | Opcode |
| a | 6E |
| a,x | 7E |
| A | 6A |
| zp | 66 |
| zp,x | 76 |
[edit] Logic
AND Memory with Accumulator: AND
A & M -> A
Flags: N, Z
| Addressing Mode | Opcode |
| a | 2D |
| a,x | 3D |
| a,y | 39 |
| # | 29 |
| zp | 25 |
| (zp,x) | 21 |
| zp,x | 35 |
| (zp),y | 31 |
OR Memory with Accumulator: ORA
A | M -> A
Flags: N, Z
| Addressing Mode | Opcode |
| a | 0D |
| a,x | 1D |
| a,y | 19 |
| # | 09 |
| zp | 05 |
| (zp,x) | 01 |
| zp,x | 15 |
| (zp),y | 11 |
Exclusive-OR Memory with Accumulator: EOR
A ^ M -> A
Flags: N, Z
| Addressing Mode | Opcode |
| a | 4D |
| a,x | 5D |
| a,y | 59 |
| # | 49 |
| zp | 45 |
| (zp,x) | 41 |
| zp,x | 55 |
| (zp),y | 51 |
[edit] Compare and Test Bit
For all Compare instructions:
| Condition | N | Z | C |
| Register < Memory | 1 | 0 | 0 |
| Register = Memory | 0 | 1 | 1 |
| Register > Memory | 0 | 0 | 1 |
Compare Memory and Accumulator: CMP
A - M
Flags: N, Z, C
| Addressing Mode | Opcode |
| a | CD |
| a,x | DD |
| a,y | D9 |
| # | C9 |
| zp | C5 |
| (zp,x) | C1 |
| zp,x | D5 |
| (zp),y | D1 |
Compare Memory and Index X: CPX
X - M
Flags: N, Z, C
| Addressing Mode | Opcode |
| a | EC |
| # | E0 |
| zp | E4 |
Compare Memory with Index Y: CPY
Y - M
Flags: N, Z, C
| Addressing Mode | Opcode |
| a | CC |
| # | C0 |
| zp | C4 |
Test Bits in Memory with Accumulator: BIT
A & M
Flags: N = M7, V = M6, Z
| Addressing Mode | Opcode |
| a | 2C |
| # | 89 |
| zp | 24 |
[edit] Branch
Branch on Carry Clear: BCC
Branch if C = 0
Flags: none
| Addressing Mode | Opcode |
| r | 90 |
Branch on Carry Set: BCS
Branch if C = 1
Flags: none
| Addressing Mode | Opcode |
| r | B0 |
Branch on Result Zero: BEQ
Branch if Z = 1
Flags: none
| Addressing Mode | Opcode |
| r | F0 |
Branch on Result Minus: BMI
Branch if N = 1
Flags: none
| Addressing Mode | Opcode |
| r | 30 |
Branch on Result not Zero: BNE
Branch if Z = 0
Flags: none
| Addressing Mode | Opcode |
| r | D0 |
Branch on Result Plus: BPL
Branch if N = 0
Flags: none
| Addressing Mode | Opcode |
| r | 10 |
Branch on Overflow Clear: BVC
Branch if V = 0
Flags: none
| Addressing Mode | Opcode |
| r | 50 |
Branch on Overflow Set: BVS
Branch if V = 1
Flags: none
| Addressing Mode | Opcode |
| r | 70 |
[edit] Transfer
Transfer Accumulator to Index X: TAX
A -> X
Flags: N, Z
| Addressing Mode | Opcode |
| i | AA |
Transfer Index X to Accumulator: TXA
X -> A
Flags: N, Z
| Addressing Mode | Opcode |
| i | 8A |
Transfer Accumulator to Index Y: TAY
A -> Y
Flags: N, Z
| Addressing Mode | Opcode |
| i | A8 |
Transfer Index Y to Accumulator: TYA
Y -> A
Flags: N, Z
| Addressing Mode | Opcode |
| i | 98 |
Transfer Stack Pointer to Index X: TSX
S -> X
Flags: N, Z
| Addressing Mode | Opcode |
| i | BA |
Transfer Index X to Stack Pointer: TXS
X -> S
Flags: N, Z
| Addressing Mode | Opcode |
| i | 9A |
[edit] Stack
Push Accumulator on Stack: PHA
A -> S
Flags: none
| Addressing Mode | Opcode |
| i | 48 |
Pull Accumulator from Stack: PLA
S -> A
Flags: N, Z
| Addressing Mode | Opcode |
| i | 68 |
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 Mode | Opcode |
| i | 08 |
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 Mode | Opcode |
| i | 28 |
[edit] Subroutines and Jump
Jump to New Location: JMP
Jump to new location
Flags: none
| Addressing Mode | Opcode |
| a | 4C |
| (a,x) | 7C |
| (a) | 6C |
Jump to New Location Saving Return Address: JSR
Jump to Subroutine
Flags: none
| Addressing Mode | Opcode |
| a | 20 |
Return from Subroutine: RTS
Return from Subroutine
Flags: none
| Addressing Mode | Opcode |
| i | 60 |
Return from Interrupt: RTI
Return from Interrupt
Flags: all
| Addressing Mode | Opcode |
| i | 40 |
[edit] Set and Clear
Set Carry Flag: SEC
1 -> C
Flags: C = 1
| Addressing Mode | Opcode |
| i | 38 |
Set Decimal Mode: SED
1 -> D
Flags: D = 1
| Addressing Mode | Opcode |
| i | F8 |
Set Interrupt Disable Status: SEI
1 -> I
Flags: I = 1
| Addressing Mode | Opcode |
| i | 78 |
Clear Carry Flag: CLC
0 -> C
Flags: C = 0
| Addressing Mode | Opcode |
| i | 18 |
Clear Decimal Mode: CLD
0 -> D
Flags: D = 0
| Addressing Mode | Opcode |
| i | D8 |
Clear Interrupt Disable Status: CLI
0 -> I
Flags: I = 0
| Addressing Mode | Opcode |
| i | 58 |
Clear Overflow Flag: CLV
0 -> V
Flags: V = 0
| Addressing Mode | Opcode |
| i | B8 |
[edit] Miscellaneous
No Operation: NOP
No Operation
Flags: none
| Addressing Mode | Opcode |
| i | EA |
Break: BRK
Force an Interrupt
Flags: B = 1, I = 1
| Addressing Mode | Opcode |
| i | 00 |
[edit] Further Reading
- Owad, Tom, "Apple I Replica Creation", Syngress, 2005. ISBN 193183640X
- 6502.org the 6502 microprocessor resource