65c02 Assembly

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

This is an edit of the 6502 Assembly book, with the addition of the new instructions/modes on the 65c02.

Syntax
Syntax will vary between assemblers - this book will use the following syntax throughout:

Introduction
The 65C02 CPU has an 8-bit data bus, and a 16-bit address bus. All registers are 8-bit except for the 16-bit Program Counter (PC) register. Therefore the CPU is considered to be 8-bit.

That the address bus is 16-bit means that the CPU can access 2^16 individual bytes of memory, from address $0000 to address $FFFF, which is 65536 bytes (64KB).

Communication with peripheral units (e.g. video, audio, disk and controllers for a game system) is often performed with memory-mapped I/O.

The memory is divided into "pages", each of 256 bytes (within the range of an 8-bit offset). Page n is the n 'th page in the memory, with a starting address of 256*n, and end address of (256*(n+1))-1. E.g. the "zero page" starts at address 0, and ends at address 255. See memory layout below for more details.

Slightly less than half of the 65c02 CPUs opcodes deal with memory stored in the Zero Page. Memory stored in the zero page often takes less time to process.

Memory layout
16-bit values are stored in memory in little-endian, so the least significant byte is stored before the most significant. E.g. if address  contains   and address   contains , reading a two-byte value from   will result in.

Signed integers are in two's complement and can represent values from -128 to +127. Bit 7 is set if the integer is negative.

The 6502's program counter is 16 bits wide, so up to 2^16 (65536) bytes of memory are addressable. Certain regions of memory are reserved for particular purposes:

Memory Addressing Modes
Each instruction uses one of thirteen memory addressing modes, which determines the operand of the instruction. An example is provided for each.

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 at address  is loaded into the X register.

LDX $D010

Zero Page: zp
A single byte specifies an address in the first page of memory, also known as the zero page, and the byte at that address is used to perform the computation.

 Example 

The value at address  is loaded into the Y register.

LDY $02

Stack: s
Essentially the same as Implied (i). The difference is that these instructions perform stack operations; pushing or pulling operands from the stack.

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  is added to the address in the Program Counter (say  ). The destination of the branch (if taken) will be.

BPL $2D

Absolute Indirect: (a)
The little-endian two-byte value stored at the specified address is used to perform the computation. Only used by the  instruction.

 Example 

The addresses  and   are read, returning   and   respectively. The address  is then jumped to.

JMP ($A001)

Absolute Indirect Indexed with X: (a,x)
The value in  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 and the value at that address is used to perform the computation. Only used by the  instruction.

 Example 

The value  in   is added to   for a sum of. The address  at addresses   and   are read. The address  is then jumped to.

JMP ($E015,X)

Absolute Indexed with X: a,x
The value in  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  in   is added to   for a sum of. The value  at address   is used to perform the add with carry ( ) operation.

ADC $C001,X

Absolute Indexed with Y: a,y
The value in  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  in   is added to   for a sum of. The value  at address   is incremented ( ) and   is written back to.

INC $F001,Y

Zero Page Indexed with X: zp,x
The value in  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  in   is added to   for a sum of. The value  at address   is loaded into the Accumulator.

LDA $01,X

Zero Page Indexed with Y: zp,y
The value in  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  in   is added to   for a sum of. The value  at address   is loaded into the Accumulator.

LDA $01,Y

Zero Page Indexed Indirect: (zp,x)
The value in  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  in   is added to   for a sum of. The address  at addresses   and   will be where the value   in the Accumulator is stored.

STA ($15,X)

Zero Page Indirect: (zp)
The little-endian address stored at the two-byte pair of zero page address (LSB) and zero page address plus one (MSB) is loaded and the value at that address is used to perform the computation.

 Example 

The address  at addresses   and   will be where the value   in the Accumulator is stored.

STA ($15)

Zero Page Indirect Indexed with Y: (zp),y
The value in  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  in   is added to the address   at addresses   and   for a sum of. The Accumulator is then exclusive ORed with the value  at.

EOR ($2A),Y

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.

Compare and Test Bit
The Negative (N), Zero (Z), and Carry (C) status flags are used for conditional (branch) instructions.

All Compare instructions affect flags in the same way:

 Test Bits in Memory with Accumulator:  

A & M

Flags: N = M7, V = M6, Z

Branch
Unlike the other branch instructions, BBR and BBS have two operands. The M operand, used for the Set or Reset comparison, is always the zp addressing mode. The branch address operand is the r addressing mode, and has the same meaning as the other branch instructions.

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

Subroutines and Jump
 Jump to New Location:  

Jump to new location by changing the value of the program counter.

Flags: none

 Jump to New Location Saving Return Address:  

Jumps to a subroutine

The address before the next instruction (PC - 1) is pushed onto the stack: first the upper byte followed by the lower byte. As the stack grows backwards, the return address is therefore stored as a little-endian number in memory. PC is set to the target address.

Flags: none

 Return from Subroutine:  

Return from a subroutine to the point where it called with.

The return address is popped from the stack (low byte first, then high byte). The return address is incremented and stored in PC.

Flags: none

 Return from Interrupt:  

Return from an interrupt.

SR is popped from the stack. PC is popped from the stack.

Flags: all

Miscellaneous
 Break:  

Force an Interrupt.

This is a two-byte instruction, where the second byte is ignored by the processor. The 2nd byte can be used as argument to the interrupt service routine.

Flags: B = 1, I = 1

 No Operation:  

No Operation

Flags: none

 Wait for Interrupt:  

Wait for Interrupt

Flags: none

 Stop mode:  

Stop mode

Flags: none

Opcode map
List of all the OpCodes present. An opcode is an "operation code", the first byte in an instruction. This byte decides which operation is being performed. Multiple assembler mnemonics (eg. ADC, BIT, JMP et.c.) correspond to several different opcodes. There is one opcode per addressing mode used. For example, the menmonic ASL have multiple opcodes, one for each addressing mode supported by the CPU.

Opcodes marked with an asterisk (*) are opcodes that did not exist for the 6502 CPU.

Blank entries are supposed to behave identical the NOP instruction (EA).