Rockwell 6502 Programmers Reference




Ø_________________    _     _    _______    _______   ________    _______              Ø
 ÆÆÆ             ÆÆÆ  ÆÆÆ   ÆÆÆ  ÆÆ_   ÆÆÆ  ÆÆÆ   ÆÆÆ  ___   ÆÆÆ  ÆÆÆ   ÆÆÆ  Est. 1984
 Æ¥Æ             Æ±Æ  Æ±Æ ÷ Æ±Æ  Æ¥Æ ÷ Æ±Æ  Æ¥Æ ÷ Æ¥Æ  Æ¥Æ ÷ Æ±Æ  Æ¥Æ ÷ ƱÆ
 Æ¥Æ             Æ÷Æ  Æ÷Æ ÷ Æ÷Æ  Æ±Æ ÷ Æ÷Æ  Æ±Æ ÷ Æ±Æ  Æ±Æ ÷ Æ÷Æ  Æ±Æ ÷ Æ÷Æ
 Æ±Æ             ™™™  Æ Æ ÷ Æ Æ  Æ÷Æ ÷ Æ Æ  Æ÷Æ ÷ Æ÷Æ  Æ÷Æ ÷ Æ Æ  Æ÷Æ ÷ ™™™
 Æ±Æ                  Æ Æ   Æ Æ  Æ Æ___Æ™™  Æ Æ ^ Æ Æ  Æ Æ___ÆÆ  Æ Æ
 Æ÷Æ                  ÆÆÆÆÆÆ  Æ Æ™™™Æ__  Æ Æ v Æ Æ  Æ Æ  Æ Æ   Æ Æ ™™ÆÆÆ
 Æ÷Æ                     Æ Æ     Æ÷Æ ÷ Æ Æ  Æ÷Æ ÷ Æ÷Æ  Æ÷Æ  Æ Æ   Æ÷Æ ÷ Æ Æ
 Æ÷Æ                     Æ÷Æ     Æ±Æ ÷ Æ÷Æ  Æ±Æ ÷ Æ±Æ  Æ±Æ  Æ÷Æ   Æ±Æ ÷ Æ÷Æ
 Æ Æ                     Æ±Æ     Æ¥Æ ÷ Æ±Æ  Æ¥Æ ÷ Æ¥Æ  Æ¥Æ  Æ±Æ   Æ¥Æ ÷ ƱÆ
 Æ1Æ                     ÆÆÆ     ÆÆÆ   ÆÆÆ  ÆÆÆ   ÆÆÆ  ÆÆÆ  ÆÆÆ   ÆÆ   ÆÆÆ
 Æ3Æ                    ™™™™™     ™™™™™™™    ™™™™™™™   ™™™   ™™™   ™™™™™™™
 Æ5Æ        _______    _     _    _______   _________   _______    _______    _______
 Æ8Æ       ÆÆ_   ÆÆÆ  ÆÆÆ   ÆÆÆ  ÆÆ_   ÆÆÆ  ÆÆÆÆÆÆÆ  ÆÆ_ ÆÆÆÆÆ  ÆÆÆ Æ ÆÆÆ  ÆÆ_   ÆÆÆ
 Æ Æ       Æ¥Æ ÷ Æ±Æ  Æ±Æ ÷ Æ±Æ  Æ¥Æ ÷ Æ±Æ     Æ¥Æ     Æ¥Æ        Æ¥Æ Æ Æ¥Æ  Æ¥Æ ÷ ƱÆ
 Æ÷Æ       Æ±Æ ÷ Æ÷Æ  Æ÷Æ ÷ Æ÷Æ  Æ±Æ ÷ Æ÷Æ     Æ±Æ     Æ±Æ        Æ±Æ Æ Æ±Æ  Æ±Æ ÷ Æ÷Æ
 Æ÷Æ       Æ÷Æ   ™™™  Æ Æ ÷ Æ Æ  Æ÷Æ   ™™™     Æ÷Æ     Æ÷Æ        Æ÷Æ Æ Æ÷Æ  Æ÷Æ   ™™™
 Æ÷Æ       ÆÆ____    Æ Æ   Æ Æ  ÆÆ____       Æ Æ     Æ Æ__Æ™™   Æ Æ ¥ Æ Æ  ÆÆ____
 Æ±Æ         ™™™™ÆÆ_  ÆÆÆÆÆÆ    ™™™™ÆÆ_     Æ Æ     Æ Æ™™Æ__   Æ Æ ± Æ Æ    ™™™™ÆÆ_
 Æ±Æ       ÆÆÆ   Æ Æ     Æ Æ     ÆÆÆ   Æ Æ     Æ÷Æ     Æ÷Æ        Æ÷Æ ÷ Æ÷Æ  ÆÆÆ   Æ Æ
 Æ¥Æ     _ Æ÷Æ ÷ Æ÷Æ     Æ÷Æ     Æ÷Æ ÷ Æ÷Æ     Æ±Æ     Æ±Æ        Æ±Æ   Æ±Æ  Æ÷Æ ÷ Æ÷Æ
 Æ¥Æ     Æ Æ±Æ ÷ Æ±Æ     Æ±Æ     Æ±Æ ÷ Æ±Æ     Æ¥Æ     Æ¥Æ        Æ¥Æ   Æ¥Æ  Æ±Æ ÷ ƱÆ
 ÆÆÆ     Æ ÆÆÆ   ÆÆ     ÆÆÆ     ÆÆÆ   ÆÆ     ÆÆÆ     ÆÆ ÆÆÆÆÆ  ÆÆÆ   ÆÆÆ  ÆÆÆ   ÆÆ
Ø ™™™™™™™™  ™™™™™™™     ™™™™™     ™™™™™™™      ™™™      ™™™™™™™   ™™™   ™™™   ™™™™™™™  Ø
Çybôrg
 - BRINGING YOU THE FACTS - 
Sÿstem$
Authored by: Bluechip


 


Index



Quick Reference

Instruction set Lookup Table
Detailed Instruction Reference
Instructions by Purpose

Processor Status Word (Flags)
Binary Coded Decimal (BCD)

Addressing Modes
6502 Memory Map

The Stack

Program Flow Control

Interrupts and Interrupt ReQuests (IRQ's)
System Startup sequence (boot-strap)

Bibliography


Please ask questions or report any errors you may find here



 

Instruction set Lookup Table



I-Len T-Cnt
Mnemonic
Address Mode
 
I-Len : Instruction length. The number of bytes of memory required to store the instruction.
T-Cnt : Timing Cycle (T-State) count. The number of clock cycles required to execute the instruction.
Mnemonic : The abbreviated "human readable" identity of the instruction
Address Mode : The memory addressing mode used by the instruction.
 
The opcode for any instruction may be composed by reading the row and column it is in.
By example:
  "ASL" in "Absolute" addressing mode is in row "1-", column "-E"
  Therefore it's opcode (hexadecimal representation) is "1E" (or $1E or 0x1E)
 
Some instructions (or more specifically Addressing Modes) require either one or two bytes of data as a parameter.
Under these circumstances, this data immediately follows the instruction itself.
By Example:
 
  Mnemonic Code       Assembled Code   
   PLA                 $68
   BEQ   $03           $F0 $9F
   JMP   $A5B6         $4C $B6 $A5      


  -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F  
 0- 
1 7
BRK
Implied
2 6
ORA
(Ind,X)
     
2 3
ORA
ZP
2 5
ASL
ZP
 
1 3
PHP
Implied
2 2
ORA
Immed
1 2
ASL
Accum
   
3 4
ORA
ABS
3 6
ASL
ABS
   0- 
 1- 
2 **2
BPL
Relative
2 5+
ORA
(Ind),Y
     
2 4
ORA
ZP,X
2 6
ASL
ZP,X
 
1 2
CLC
Implied
3 4+
ORA
ABS,Y
     
3 4+
ORA
ABS,X
3 7
ASL
ABS,X
   1- 
 2- 
3 6
xxx
mm
2 6
xxx
mm
   
2 3
xxx
mm
2 3
xxx
mm
2 5
xxx
mm
 
1 4
xxx
mm
2 2
xxx
mm
1 2
xxx
mm
 
3 4
xxx
mm
3 4
xxx
mm
3 6
xxx
mm
   2- 
 3- 
2 **2
xxx
mm
2 5+
xxx
mm
     
2 4
xxx
mm
2 6
xxx
mm
 
1 2
xxx
mm
3 4+
xxx
mm
     
3 4+
xxx
mm
3 7
xxx
mm
   3- 
 4- 
x x
xxx
mm
x x
xxx
mm
     
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
   4- 
 5- 
x x
xxx
mm
x x
xxx
mm
     
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
     
x x
xxx
mm
x x
xxx
mm
   5- 
 6- 
x x
xxx
mm
x x
xxx
mm
     
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
   6- 
 7- 
x x
xxx
mm
x x
xxx
mm
     
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
     
x x
xxx
mm
x x
xxx
mm
   7- 
 8-   
x x
xxx
mm
   
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
 
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
   8- 
 9- 
x x
xxx
mm
x x
xxx
mm
   
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
   
x x
xxx
mm
     9- 
 A- 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
   A- 
 B- 
x x
xxx
mm
x x
xxx
mm
   
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
   B- 
 C- 
x x
xxx
mm
x x
xxx
mm
   
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
   C- 
 D- 
x x
xxx
mm
x x
xxx
mm
     
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
     
x x
xxx
mm
x x
xxx
mm
   D- 
 E- 
x x
xxx
mm
x x
xxx
mm
   
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
x x
xxx
mm
   E- 
 F- 
x x
xxx
mm
x x
xxx
mm
     
x x
xxx
mm
x x
xxx
mm
 
x x
xxx
mm
x x
xxx
mm
     
x x
xxx
mm
x x
xxx
mm
   F- 
  -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F  

 

Detailed Instruction Reference


 
ADC

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate ADC #$A5 $69 2 2 Zero Page ADC $A5 $65 2 3 Zero Page,X ADC $A5,X $75 2 4 Absolute ADC $A5B6 $6D 3 4 Absolute,X ADC $A5B6,X $7D 3 4+ Absolute,Y ADC $A5B6,Y $79 3 4+ (Indirect,X) ADC ($A5,X) $61 2 6 (Indirect),Y ADC ($A5),Y $71 2 5+
+  Add 1 (one) T-State if a Page Boundary is crossed

Add Memory to A with Carry
Flags Affected:
N V - b d i Z C
Logic:
  t = A + M + P.C
  P.V = (A.7!=t.7) ? 1:0
  P.N = A.7
  P.Z = (t==0) ? 1:0
  IF (P.D)
    t = bcd(A) + bcd(M) + P.C
    P.C = (t>99) ? 1:0
  ELSE
    P.C = (t>255) ? 1:0
  A = t & 0xFF                
Notes:
There is no add-without-carry instruction!
As the result of ADC depends on the contents of the Carry Flag (P.C)
When performing "single precision" (or "8 bit") arithmetic it is often necessary to ensure that the Carry Flag (P.C) is CLEARed with a CLC command before the ADC is executed ...to ensure that the Carry Flag (P.C) has no bearing on the result.
CLEARing the Carry Flag (P.C) with a CLC command is normally necessary before the first stage of a "multiple precision" (or "more than 8 bit") addition.
The action of ADC is dependant on the setting of Decimal Flag (P.D)
 
AND

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate AND #$A5 $29 2 2 Zero Page AND $A5 $25 2 2 Zero Page,X AND $A5,X $35 2 3 Absolute AND $A5B6 $2D 3 4 Absolute,X AND $A5B6,X $3D 3 4+ Absolute,Y AND $A5B6,Y $39 3 4+ (Indirect,X) AND ($A5,X) $21 2 6 (Indirect),Y AND ($A5),Y $31 2 5+
+  Add 1 (one) T-State if a Page Boundary is crossed

Bitwise-AND A with Memory
Flags Affected:
N v - b d i Z c
Logic:
  A = A & M
  P.N = A.7
  P.Z = (A==0) ? 1:0 
Notes:
 
AND
 0 
 1 
 0 
 0 
 0 
 1 
 0 
 1 
 1 0 1 0 
AND 
 1 1 0 0 
---------
 
 1 0 0 0 
 
 
ASL

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Accumulator ASL A $0A 1 2 Zero Page ASL $A5 $06 2 5 Zero Page,X ASL $A5,X $16 2 6 Absolute ASL $A5B6 $0E 3 6 Absolute,X ASL $A5B6,X $1E 3 7
Arithmetic Shift Left
Flags Affected:
N v - b d i Z C
Logic:
  P.C = B.7
  B = (B << 1) & $FE
  P.N = B.7
  P.Z = (B==0) ? 1:0 
Notes:
 
P.C
<-
b.7
<-
b.6
<-
b.5
<-
b.4
<-
b.3
<-
b.2
<-
b.1
<-
b.0
<-
0
 
 Before:
 P.C = ?   B = 1 1 1 0  1 1 1 0 
 After:
 P.C = 1   B = 1 1 0 1  1 1 0 0 
In my experience, this is NOT an "arithmetic" shift.
An Arithmetic shift normally preserves the Most Significant Bit (MSb) or "Sign bit" of the source value.
ASL does NOT do this on the 6502.
The 6502 places a copy of the sign from the result of a Logical Shift Left into the sigN Flag (P.N)
This instruction would be better named as SLS (logical Shift Left and update Sign)
 
BCC

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Relative BCC $A5 $90 2 2++
++ Add 1 (one) T-State if a the branch occurs and the destination address is on the same Page
Add 2 (two) T-States if a the branch occurs and the destination address is on a different Page
Branch iff P.C is CLEAR
Flags Affected:
n v - b d i z c
Logic:
  if (P.C == 0) GOTO (PC+M) 
Notes:
Carry Flag (P.C) gives full details on this flag, including a comprehensive list of instructions which modify its value.
If a branch condition is false the Program Counter (PC) is not affected and program execution continues at the instruction immediately after the Branch instrucion.
 
BCS

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Relative BCS $A5 $B0 2 2++
++ Add 1 (one) T-State if a the branch occurs and the destination address is on the same Page
Add 2 (two) T-States if a the branch occurs and the destination address is on a different Page
Branch iff P.C is SET
Flags Affected:
n v - b d i z c
Logic:
  if (P.C == 1) GOTO (PC+M) 
Notes:
Carry Flag (P.C) gives full details on this flag, including a comprehensive list of instructions which modify its value.
If a branch condition is false the Program Counter (PC) is not affected and program execution continues at the instruction immediately after the Branch instrucion.
 
BEQ

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Relative BEQ $A5 $F0 2 2++
++ Add 1 (one) T-State if a the branch occurs and the destination address is on the same Page
Add 2 (two) T-States if a the branch occurs and the destination address is on a different Page
Branch iff P.Z is SET
Flags Affected:
n v - b d i z c
Logic:
  if (P.Z == 1) GOTO (PC+M) 
Notes:
Zero Flag (P.Z) gives full details on this flag, including a comprehensive list of instructions which modify its value.
If a branch condition is false the Program Counter (PC) is not affected and program execution continues at the instruction immediately after the Branch instrucion.
 
BIT

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Zero Page BIT $A5 $24 2 3 Absolute BIT $A5B6 $2C 3 4
Test bits in A with M
Flags Affected:
N V - b d i Z c
Logic:
  t = A & M
  P.N = t.7
  P.V = t.6
  P.Z = (t==0) ? 1:0 
Notes:
The BIT instuction does NOT affect ANY register values.
To perform a Branch if a bit-4 is SET:
 
  LDA  0001'0000
  BIT  Mem
  BNE  lbl       
To perform a Branch if a bit-4 is CLEAR:
 
  LDA  0001'0000
  BIT  Mem
  BEQ  lbl       
Care should be taken to ensure that bits 6 & 7 are the most frequently tested.
This way it is not necessary to preload A with the mask.

 IF (   bPeek(Mem)&(1<<7)  ) GOTO lbl  
  BIT  Mem 
BMI lbl
 IF ( !(bPeek(Mem)&(1<<7)) ) GOTO lbl  
  BIT  Mem 
BPL lbl
 IF (   bPeek(Mem)&(1<<6)  ) GOTO lbl  
  BIT  Mem 
BVS lbl
 IF ( !(bPeek(Mem)&(1<<6)) ) GOTO lbl  
  BIT  Mem 
BVC lbl
 
BMI

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Relative BMI $A5 $30 2 2++
++ Add 1 (one) T-State if a the branch occurs and the destination address is on the same Page
Add 2 (two) T-States if a the branch occurs and the destination address is on a different Page
Branch iff P.N is SET
Flags Affected:
n v - b d i z c
Logic:
  if (P.N == 1) GOTO (PC+M) 
Notes:
sigN Flag (P.N) gives full details on this flag, including a comprehensive list of instructions which modify its value.
If a branch condition is false the Program Counter (PC) is not affected and program execution continues at the instruction immediately after the Branch instrucion.
 
BNE

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Relative BNE $A5 $D0 2 2++
++ Add 1 (one) T-State if a the branch occurs and the destination address is on the same Page
Add 2 (two) T-States if a the branch occurs and the destination address is on a different Page
Branch iff P.Z is CLEAR
Flags Affected:
n v - b d i z c
Logic:
  if (P.Z == 0) GOTO (PC+M) 
Notes:
Zero Flag (P.Z) gives full details on this flag, including a comprehensive list of instructions which modify its value.
If a branch condition is false the Program Counter (PC) is not affected and program execution continues at the instruction immediately after the Branch instrucion.
 
BPL

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Relative BPL $A5 $10 2 2++
++ Add 1 (one) T-State if a the branch occurs and the destination address is on the same Page
Add 2 (two) T-States if a the branch occurs and the destination address is on a different Page
Branch iff P.N is CLEAR
Flags Affected:
n v - b d i z c
Logic:
  if (P.N == 0) GOTO (PC+M) 
Notes:
sigN Flag (P.N) gives full details on this flag, including a comprehensive list of instructions which modify its value.
If a branch condition is false the Program Counter (PC) is not affected and program execution continues at the instruction immediately after the Branch instrucion.
 
BRK

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied BRK $00 1 7
Simulate Interrupt ReQuest (IRQ)
Flags Affected:
n v - b d i z c
Logic:
  PC = PC + 1
  bPoke(SP,PC.h)
  SP = SP - 1
  bPoke(SP,PC.l)
  SP = SP - 1
  bPoke(SP, (P|$10) )
  SP = SP - 1
  l = bPeek($FFFE)
  h = bPeek($FFFF)<<8
  PC = h|l             
Notes:
The copy of the Break Flag (P.B) in the CPU is NOT changed (remains CLEAR).
The copy of the Break Flag (P.B) which is placed on the Stack is SET.
This simulates an Interrupt in all but one respect:
The Return Address that is placed on the Stack, is incremented by one.
This means that the byte following a BRK command will NOT be executed upon Return.
In the Interrupts section, there is code to correct the return address error, but the code is bulky.
Another solution is to place a NOP after every BRK ...and then forget about this problem.
 
BVC

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Relative BVC $A5 $50 2 2++
++ Add 1 (one) T-State if a the branch occurs and the destination address is on the same Page
Add 2 (two) T-States if a the branch occurs and the destination address is on a different Page
Branch iff P.V is CLEAR
Flags Affected:
n v - b d i z c
Logic:
  if (P.V == 0) GOTO (PC+M) 
Notes:
oVerflow Flag (P.V) gives full details on this flag, including a comprehensive list of instructions which modify its value.
If a branch condition is false the Program Counter (PC) is not affected and program execution continues at the instruction immediately after the Branch instrucion.
 
BVS

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Relative BVS $A5 $70 2 2++
++ Add 1 (one) T-State if a the branch occurs and the destination address is on the same Page
Add 2 (two) T-States if a the branch occurs and the destination address is on a different Page
Branch iff P.V is SET
Flags Affected:
n v - b d i z c
Logic:
  if (P.V == 1) GOTO (PC+M) 
Notes:
oVerflow Flag (P.V) gives full details on this flag, including a comprehensive list of instructions which modify its value.
If a branch condition is false the Program Counter (PC) is not affected and program execution continues at the instruction immediately after the Branch instrucion.
 
CLC

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied CLC $18 1 2
Clear Carry Flag (P.C)
Flags Affected:
n v - b d i z C
Logic:
  P.C = 0 
Notes:
For more information on P.C see: ADC, SBC and Carry Flag (P.C)
 
CLD

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied CLD $D8 1 2
Clear Decimal Flag (P.D)
Flags Affected:
n v - b D i z x
Logic:
  P.D = 0 
Notes:
When P.D is SET aritmetic instructions will operate as Binary Codec Decimal (BCD)
When P.D is CLEAR aritmetic instructions will operate normally
For more information on P.D see: ADC, SBC and Decimal Flag (P.D)
 
CLI

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied CLI $58 1 2
Clear Interrupt (disable) Flag (P.I)
Flags Affected:
n v - b d I z c
Logic:
  P.I = 0 
Notes:
When P.I is SET signals from the hardware IRQ pin will be IGNORED
When P.I is CLEAR a signal from the hardware IRQ pin will cause program execution to continue from the IRQ vector, which is held little-endian at memory address #FFFE. Full details of this vector can be found in Memroy Map.
For more information on P.I see: Interrupt (disable) Flag (P.I)
 
CLV

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied CLV $B8 1 2
Clear oVerflow Flag (P.V)
Flags Affected:
n V - b d i z c
Logic:
  P.V = 0 
Notes:
There is NO instruction to SET the oVerflow Flag (P.V)
P.V serves TWO purposes!
Arithmetic overflow and bit-6 from a BIT instruction.
For more information on P.V see: oVerflow Flag (P.V)
 
CMP

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate CMP #$A5 $C9 2 2 Zero Page CMP $A5 $C5 2 3 Zero Page,X CMP $A5,X $D5 2 4 Absolute CMP $A5B6 $CD 3 4 Absolute,X CMP $A5B6,X $DD 3 4+ Absolute,Y CMP $A5B6,Y $D9 3 4+ (Indirect,X) CMP ($A5,X) $C1 2 6 (Indirect),Y CMP ($A5),Y $D1 2 5+
+  Add 1 (one) T-State if a Page Boundary is crossed

Compare A with Memory
Flags Affected:
N v - b d i Z C
Logic:
  t = A - M
  P.N = t.7
  P.C = (A>=M) ? 1:0
  P.Z = (t==0) ? 1:0 
Notes:
A compare operation (CMP, CPX or CPY) is almost invariably followed by a Conditional Branch.
 
 
 
P.N
P.C
P.Z
A < M
1*
0
0
A = M
0
1
1
A > M
0*
1
0
  Signed Unsigned
 IF (r <  M)  GOTO lbl  
  CMP  M
BMI lbl
  CMP  M
BCC lbl
 IF (r <= M)  GOTO lbl  
  CMP  M
BMI lbl
BEQ lbl
  CMP  M
BCC lbl
BEQ lbl
 IF (r == M)  GOTO lbl  
         CMP  M
BEQ lbl
 IF (r != M)  GOTO lbl  
         CMP  M
BNE lbl
 IF (r >= M)  GOTO lbl  
  CMP  M
BPL lbl
  CMP  M
BCS lbl
 IF (r >  M)  GOTO lbl  
  CMP  M
BEQ +2
BPL lbl
  CMP  M
BEQ +2
BCS lbl
  * Only valid when comparing signed numbers (in the range -128..127)
"r" is any one of the three primary registers {A, X, Y}
If A the intended register, then the CMP instruction must be used (as shown above).
If X or Y is intended register, then the CPX or CPY instruction must be used (in place of the CMP instructions shown in the table above).
 
CPX

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate CPX #$A5 $E0 2 2 Zero Page CPX $A5 $E4 2 3 Absolute CPX $A5B6 $EC 3 4
Compare X with Memory
Flags Affected:
N v - b d i Z C
Logic:
  t = X - M
  P.N = t.7
  P.C = (X>=M) ? 1:0
  P.Z = (t==0) ? 1:0 
Notes:
See CMP instruction for Flag Table and Conditional Branch coding structures
 
CPY

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate CPY #$A5 $C0 2 2 Zero Page CPY $A5 $C4 2 3 Absolute CPY $A5B6 $CC 3 4
Compare Y with Memory
Flags Affected:
N v - b d i Z C
Logic:
  t = Y - M
  P.N = t.7
  P.C = (Y>=M) ? 1:0
  P.Z = (t==0) ? 1:0 
Notes:
See CMP instruction for Flag Table and Conditional Branch coding structures
 
DEC

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Zero Page DEC $A5 $C6 2 5 Zero Page,X DEC $A5,X $D6 2 6 Absolute DEC $A5B6 $CE 3 6 Absolute,X DEC $A5B6,X $DE 3 7
Decrement Memory by one
Flags Affected:
N v - b d i Z c
Logic:
  M = (M - 1) & $FF
  P.N = M.7
  P.Z = (M==0) ? 1:0 
Notes:
DEC does NOT affect the Carry Flag (P.C) or oVerflow Flag (P.V)
 
DEX

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied DEX $CA 1 2
Decrement X by one
Flags Affected:
N v - b d i Z c
Logic:
  X = X - 1
  P.Z = (X==0) ? 1:0
  P.N = X.7          
Notes:
DEX does NOT affect the Carry Flag (P.C) or oVerflow Flag (P.V)
 
DEY

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied DEY $88 1 2
Decrement Y by one
Flags Affected:
N v - b d i Z c
Logic:
  Y = Y - 1
  P.Z = (Y==0) ? 1:0
  P.N = Y.7          
Notes:
DEY does NOT affect the Carry Flag (P.C) or oVerflow Flag (P.V)
 
EOR

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate EOR #$A5 $49 2 2 Zero Page EOR $A5 $45 2 3 Zero Page,X EOR $A5,X $55 2 4 Absolute EOR $A5B6 $4D 3 4 Absolute,X EOR $A5B6,X $5D 3 4+ Absolute,Y EOR $A5B6,Y $59 3 4+ (Indirect,X) EOR ($A5,X) $41 2 6 (Indirect),Y EOR ($A5),Y $51 2 5+
+  Add 1 (one) T-State if a Page Boundary is crossed

Bitwise-EXclusive-OR A with Memory
Flags Affected:
N v - b d i Z c
Logic:
  A = A ^ M
  P.N = A.7
  P.Z = (A==0) ? 1:0 
Notes:
Known as XOR on most other platforms ...Either way, it is an EXclusive OR ...one or the other, but not both.
 
 
EOR
 0 
 1 
 0 
 0 
 1 
 1 
 1 
 0 
 1 0 1 0 
EOR 
 1 1 0 0 
---------
 
 0 1 1 0 
 
 
INC

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Zero Page INC $A5 $E6 2 5 Zero Page,X INC $A5,X $F6 2 6 Absolute INC $A5B6 $EE 3 6 Absolute,X INC $A5B6,X $FE 3 7
Increment Memory by one
Flags Affected:
N v - b d i Z c
Logic:
  M = (M + 1) & $FF
  P.N = M.7
  P.Z = (M==0) ? 1:0 
Notes:
INC does NOT affect the Carry Flag (P.C) or oVerflow Flag (P.V)
 
INX

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied INX $E8 1 2
Increment X by one
Flags Affected:
N v - b d i Z c
Logic:
  X = X + 1
  P.Z = (X==0) ? 1:0
  P.N = X.7          
Notes:
INX does NOT affect the Carry Flag (P.C) or oVerflow Flag (P.V)
 
INY

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied INY $C8 1 2
Increment Y by one
Flags Affected:
N v - b d i Z c
Logic:
  Y = Y + 1
  P.Z = (Y==0) ? 1:0
  P.N = Y.7          
Notes:
INY does NOT affect the Carry Flag (P.C) or oVerflow Flag (P.V)
 
JMP

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Absolute JMP $A5B6 $4C 3 3 Indirect JMP ($A5B6) $6C 3 5
GOTO Address
Flags Affected:
n v - b d i z c
Logic:
  PC = M 
Notes:
None
 
JSR

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Absolute JSR $A5B6 $20 3 6
Jump to SubRoutine
Flags Affected:
n v - b d i z c
Logic:
  t = PC - 1
  bPoke(SP,t.h)
  SP = SP - 1
  bPoke(SP,t.l)
  SP = SP - 1
  PC = $A5B6    
Notes:
The current Program Counter (PC) minus one (PC-1) is PUSHed onto the Stack, and then set to the specified value.
A Subroutine is normally terminated with an RTS instruction.
 
LDA

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate LDA #$A5 $A9 2 2 Zero Page LDA $A5 $A5 2 3 Zero Page,X LDA $A5,X $B5 2 4 Absolute LDA $A5B6 $AD 3 4 Absolute,X LDA $A5B6,X $BD 3 4+ Absolute,Y LDA $A5B6,Y $B9 3 4+ (Indirect,X) LDA ($A5,X) $A1 2 6 (Indirect),Y LDA ($A5),Y $B1 2 5+
+  Add 1 (one) T-State if a Page Boundary is crossed

Load A with Memory
Flags Affected:
N v - b d i Z c
Logic:
  A = M
  P.N = A.7
  P.Z = (A==0) ? 1:0 
Notes:
None
 
LDX

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate LDX #$A5 $A2 2 2 Zero Page LDX $A5 $A6 2 3 Zero Page,Y LDX $A5,Y $B6 2 4 Absolute LDX $A5B6 $AE 2 4 Absolute,Y LDX $A5B6,Y $BE 2 4+
+  Add 1 (one) T-State if a Page Boundary is crossed

Load X with Memory
Flags Affected:
N v - b d i Z c
Logic:
  X = M
  P.N = X.7
  P.Z = (X==0) ? 1:0
Notes:
None
 
LDY

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate LDY #$A5 $A0 2 2 Zero Page LDY $A5 $A4 2 3 Zero Page,X LDY $A5,X $B4 2 4 Absolute LDY $A5B6 $AC 2 4 Absolute,X LDY $A5B6,X $BC 2 4+
+  Add 1 (one) T-State if a Page Boundary is crossed

Load Y with Memory
Flags Affected:
N v - b d i Z c
Logic:
  Y = M
  P.N = Y.7
  P.Z = (Y==0) ? 1:0
Notes:
None
 
LSR

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Accumulator LSR A $4A 1 2 Zero Page LSR $A5 $46 2 5 Zero Page,X LSR $A5,X $56 2 6 Absolute LSR $A5B6 $4E 3 6 Absolute,X LSR $A5B6,X $5E 3 7
Logical Shift Right
Flags Affected:
N v - b d i Z C
Logic:
  P.N = 0
  P.C = B.0
  B = (B >> 1) & $7F
  P.Z = (B==0) ? 1:0 
Notes:
 
0
->
b.7
->
b.6
->
b.5
->
b.4
->
b.3
->
b.2
->
b.1
->
b.0
->
P.C
 Before:
 B = 1 1 1 0  1 1 1 0   P.C = ? 
 After:
 B = 0 1 1 1  0 1 1 1   P.C = 0 
 
NOP

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied NOP $EA 1 2
No OPeration
Flags Affected:
n v - b d i z c
Logic:
  ~none~ 
Notes:
NOP achieves absolutely nothing.
But when it is finished you are 1 T-State closer to your grave.
NOP can be used to reserve space in a program for future code.
Another frequent use of NOP is to patch out features of an existing program without the need for a full recompile.
...The hackers favourite :)
 
ORA

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate ORA #$A5 $09 2 2 Zero Page ORA $A5 $05 2 2 Zero Page,X ORA $A5,X $15 2 3 Absolute ORA $A5B6 $0D 3 4 Absolute,X ORA $A5B6,X $1D 3 4+ Absolute,Y ORA $A5B6,Y $19 3 4+ (Indirect,X) ORA ($A5,X) $01 2 6 (Indirect),Y ORA ($A5),Y $11 2 5+
+  Add 1 (one) T-State if a Page Boundary is crossed

Bitwise-OR A with Memory
Flags Affected:
N v - b d i Z c
Logic:
  A = A | M
  P.N = A.7
  P.Z = (A==0) ? 1:0 
Notes:
 
OR 
 0 
 1 
 0 
 0 
 1 
 1 
 1 
 1 
 1 0 1 0 
OR 
 1 1 0 0 
---------
 
 1 1 1 0 
 
 
PHA

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied PHA $48 1 3
PusH A onto Stack
Flags Affected:
n v - b d i z c
Logic:
  bPoke(SP,A)
  SP = SP - 1 
Notes:
You would be wise to take a little time to look at the notes for JSR and RTS and work out why the following code will crash your program:
 
         JSR   Subr
         ...
         ...
 Subr:   PHA
         RTS           
 
PHP

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied PHP $08 1 3
PusH P onto Stack
Flags Affected:
n v - b d i z c
Logic:
  bPoke(SP,P)
  SP = SP - 1 
Notes:
A copy of the current Processor Status Word (Flags) is PUSHed onto the Stack.
This can be useful if you wish to preserve the current Flags state while a Subroutine is called.
This system is utilised automatically by the processor during an Interrupt Subroutine.
You may later copy the Flags back to P with the PLP instruction.
You would be wise to take a little time to look at the notes for JSR and RTS and work out why the following code will crash your program:
 
         JSR   Subr
         ...
         ...
 Subr:   PHP
         RTS           
 
PLA

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied PLA $68 1 4
PulL from Stack to A
Flags Affected:
N v - b d i Z c
Logic:
  SP = SP + 1
  A = bPeek(SP)
  P.N = A.7
  P.Z = (A==0) ? 1:0 
Notes:
You would be wise to take a little time to look at the notes for JSR and RTS and work out why the following code will crash your program:
 
         JSR   Subr
         ...
         ...
 Subr:   PLA
         RTS           
 
PLP

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied PLP $28 1 4
PulL from Stack to P
Flags Affected:
N V - B D I Z C
Logic:
  SP = SP + 1
  P = bPeek(SP)  
Notes:
The entry on the top of the Stack is placed in the Processor Status Word (Flags).
By definition this instruction can affect any or all Flags to known states.
This instruction is normally only used to
Reverse a PHA instruction
Test for the Break Flag (P.B) during an Interrupt SubRoutine.
You would be wise to take a little time to look at the notes for JSR and RTS and work out why the following code will crash your program:
 
         JSR   Subr
         ...
         ...
 Subr:   PLA
         RTS           
 
ROL

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Accumulator ROL A $2A 1 2 Zero Page ROL $A5 $26 2 5 Zero Page,X ROL $A5,X $36 2 6 Absolute ROL $A5B6 $2E 3 6 Absolute,X ROL $A5B6,X $3E 3 7
ROtate Left
Flags Affected:
N v - b d i Z C
Logic:
  t = B.7
  B = (B << 1) & $FE
  B = B | P.C
  P.C = t
  P.Z = (B==0) ? 1:0
  P.N = B.7          
Notes:
 
,-<-
P.C
<-
b.7
<-
b.6
<-
b.5
<-
b.4
<-
b.3
<-
b.2
<-
b.1
<-
b.0
-<-.
`->-
->
->
->
->
->
->
->
->
->
->
->
->
->
->
->
->
->
->-'
 Before:
 P.C = 1   B = 0 1 1 0  1 1 1 0 
 After:
 P.C = 0   B = 1 1 0 1  1 1 0 1 
 
ROR

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Accumulator ROR A $6A 1 2 Zero Page ROR $A5 $66 2 5 Zero Page,X ROR $A5,X $76 2 6 Absolute ROR $A5B6 $6E 3 6 Absolute,X ROR $A5B6,X $7E 3 7
ROtate Right
Flags Affected:
N v - b d i Z C
Logic:
  t = B.0
  B = (B >> 1) & $7F
  B = B | ((P.C) ? $80:$00)
  P.C = t
  P.Z = (B==0) ? 1:0
  P.N = B.7                 
Notes:
 
,->-
b.7
->
b.6
->
b.5
->
b.4
->
b.3
->
b.2
->
b.1
->
b.0
->
P.C
->-.
`-<-
<-
<-
<-
<-
<-
<-
<-
<-
<-
<-
<-
<-
<-
<-
<-
<-
<-
-<-'
 Before:
 B = 0 1 1 0  1 1 1 0   P.C = 1 
 After:
 B = 1 0 1 1  0 1 1 1   P.C = 0 
 
RTI

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied RTI $40 1 6
ReTurn from Interrupt
Flags Affected:
N V - B D I Z C
Logic:
  SP = SP - 1
  P = bPeek(SP)
  SP = SP - 1
  l = bPeek(SP)
  SP = SP - 1
  h = bPeek(SP)<<8
  PC = h|l         
Notes:
Interrupts are normally triggered externally by hardware devices via the IRQ pin on the 6502 itself.
Note that unlike RTS, RTI does NOT add one to the destination before placing it in the Program Counter (PC)
An Interrupt may be simulated by a BRK instruction
**WARNING** Make sure you read up on BRK before using it - it's weird!
 
RTS

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied RTS $60 1 6
ReTurn from Subroutine
Flags Affected:
n v - b d i z c
Logic:
  SP = SP + 1
  l = bPeek(SP)
  SP = SP + 1
  h = bPeek(SP)<<8
  PC = (h|l) +1    
Notes:
A word (16-bits) is PulLed from the top of the Stack; this value is then incremented by one and placed in the Program Counter (PC).
RTS is normally used to return from a Subroutine called by the JSR instruction.
This way they act as the classic "GOSUB" and "RETURN" statements.
 
SBC

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Immediate SBC #$A5 $E9 2 2 Zero Page SBC $A5 $E5 2 3 Zero Page,X SBC $A5,X $F5 2 4 Absolute SBC $A5B6 $ED 3 4 Absolute,X SBC $A5B6,X $FD 3 4+ Absolute,Y SBC $A5B6,Y $F9 3 4+ (Indirect,X) SBC ($A5,X) $E1 2 6 (Indirect),Y SBC ($A5),Y $F1 2 5+
+  Add 1 (one) T-State if a Page Boundary is crossed

Subtract Memory from A with Borrow
Flags Affected:
N V - b d i Z C
Logic:
  IF (P.D)
    t = bcd(A) - bcd(M) - !P.C
    P.V = (t>99 OR t<0) ? 1:0
  ELSE
    t = A - M - !P.C
    P.V = (t>127 OR t<-128) ? 1:0
  P.C = (t>=0) ? 1:0
  P.N = t.7
  P.Z = (t==0) ? 1:0
  A = t & 0xFF                    
Notes:
There is no subtract-without-carry instruction!
As the result of SBC depends on the contents of the Carry Flag (P.C)
When performing "single precision" (or "8 bit") arithmetic it is often necessary to ensure that the Carry Flag (P.C) is SET with an SEC command before the subtraction is executed.
The upshot of the SEC is to ensure that the Carry Flag (P.C) has no bearing on the result.
SETting the Carry Flag (P.C) with an SEC command is normally necessary before the first stage of a "multiple precision" (or "more than 8 bit") subtraction.
The action of SBC is dependant on the setting of Decimal Flag (P.D)
 
SEC

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied SEC $38 1 2
Set Carry flag (P.C)
Flags Affected:
n v - b d i z C
Logic:
  P.C = 1 
Notes:
For more information on P.C see: ADC, SBC and Carry Flag (P.C)
 
SED

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied CLD $F8 1 2
Set Binary Coded Decimal Flag (P.D)
Flags Affected:
n v - b D i z x
Logic:
  P.D = 1 
Notes:
When P.D is SET aritmetic instructions will operate as Binary Codec Decimal (BCD)
When P.D is CLEAR aritmetic instructions will operate normally
For more information on P.D see: ADC, SBC and Decimal Flag (P.D)
 
SEI

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied SEI $78 1 2
Set Interrupt (disable) Flag (P.I)
Flags Affected:
n v - b d I z c
Logic:
  P.I = 1 
Notes:
When P.I is SET signals from the hardware IRQ pin will be IGNORED
When P.I is CLEAR a signal from the hardware IRQ pin will cause program execution to continue from the IRQ vector, which is held little-endian at memory address #FFFE. Full details of this vector can be found in Memroy Map.
For more information on P.I see: Interrupt (disable) Flag (P.I)
 
STA

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Zero Page STA $A5 $85 2 3 Zero Page,X STA $A5,X $95 2 4 Absolute STA $A5B6 $8D 3 4 Absolute,X STA $A5B6,X $9D 3 5 Absolute,Y STA $A5B6,Y $99 3 5 (Indirect,X) STA ($A5,X) $81 2 6 (Indirect),Y STA ($A5),Y $91 2 6
+  Add 1 (one) T-State if a Page Boundary is crossed

Store A in Memory
Flags Affected:
n v - b d i z c
Logic:
  M = A 
Notes:
None
 
STX

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Zero Page STX $A5 $86 2 3 Zero Page,Y STX $A5,Y $96 2 4 Absolute STX $A5B6 $8E 3 4
+  Add 1 (one) T-State if a Page Boundary is crossed

Store X in Memory
Flags Affected:
n v - b d i z c
Logic:
  M = X  
Notes:
None
 
STY

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Zero Page STY $A5 $84 2 3 Zero Page,X STY $A5,X $94 2 4 Absolute STY $A5B6 $8C 3 4
+  Add 1 (one) T-State if a Page Boundary is crossed

Store Y in Memory
Flags Affected:
n v - b d i z c
Logic:
  M = Y  
Notes:
None
 
TAX

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied TAX $AA 1 2
Transfer A to X
Flags Affected:
N v - b d i Z c
Logic:
  X = A
  P.N = X.7
  P.Z = (X==0) ? 1:0 
Notes:
None
 
TAY

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied TAY $A8 1 2
Transfer A to Y
Flags Affected:
N v - b d i Z c
Logic:
  Y = A
  P.N = Y.7
  P.Z = (Y==0) ? 1:0 
Notes:
None
 
TSX

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied TSX $BA 1 2
Transfer Stack Pointer to X
Flags Affected:
N v - b d i Z c
Logic:
  X = SP
  P.N = X.7
  P.Z = (X==0) ? 1:0 
Notes:
TSX is the only way to retrieve the current position of the Stack Pointer.
The Stack can ONLY exist in Page 1 of memory (addresses $01'00..$01'FF)
 
TXA

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied TXA $8A 1 2
Transfer X to A
Flags Affected:
N v - b d i Z c
Logic:
  A = X
  P.N = A.7
  P.Z = (A==0) ? 1:0 
Notes:
None
 
TXS

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied TXS $9A 1 2
Transfer X to Stack Pointer
Flags Affected:
n v - b d i z c
Logic:
  SP = X 
Notes:
Although many instructions modify the value of the Stack Pointer, TXS is the only way to set it to a specified value.
The Stack can ONLY exist in Page 1 of memory (addresses $01'00..$01'FF)
 
TYA

  Address Mode    Syntax        Opcode  I-Len  T-Cnt  
Implied TYA $98 1 2
Transfer Y to A
Flags Affected:
N v - b d i Z c
Logic:
  A = Y
  P.N = A.7
  P.Z = (A==0) ? 1:0 
Notes:
None


 

6502 Instruction set Quick Reference



 ADC   AND   ASL
 BCC   BCS   BEQ   BIT   BMI   BNE   BPL   BRK   BVC   BVS 
 CLC   CLD   CLI   CLV   CMP   CPX   CPY
 DEC   DEX   DEY
 EOR
 INC   INX   INY
 JMP   JSR
 LDA   LDX   LDY   LSR
 NOP
 ORA
 PHA   PHP   PLA   PLP
 ROL   ROR   RTI   RTS
 SBC   SEC   SED   SEI   STA   STX   STY
 TAX   TAY   TSX   TXA   TXS   TYA

  ADC - Add Memory to A with Carry
  AND - Bitwise-and A with Memory
  ASL - Arithmetic Shift Left
  BCC - Branch iff Carry flag (P.C) is CLEAR
  BCS - Branch iff Carry flag (P.C) is SET
  BEQ - Branch iff Carry flag (P.Z) is SET
  BIT - Test bits in A with M
  BMI - Branch iff sigN flag (P.N) is SET
  BNE - Branch iff Carry flag (P.Z) is CLEAR
  BPL - Branch iff sigN flag (P.N) is CLEAR
  BRK - Simulate IRQ
  BVC - Branch iff oVerflow flag (P.V) is CLEAR
  BVS - Branch iff oVerflow flag (P.V) is SET
  CLC - Clear Carry flag (P.C)
  CLD - Clear Decimal flag (P.D)
  CLI - Clear Interrupt flag (P.I)
  CLV - Clear oVerflow flag (P.V)
  CMP - Compare A with Memory
  CPX - Compare X with Memory
  CPY - Compare Y with Memory
  DEC - Decrement Memory by one
  DEX - Decrement X by one
  DEY - Decrement Y by one
  EOR - Bitwise-exclusive-or A with Memory
  INC - Increment Memory by one
  INX - Increment X by one
  INY - Increment Y by one
  JMP - GOTO Address
  JSR - Jump to SubRoutine
  LDA - Load A with Memory
  LDX - Load X with Memory
  LDY - Load Y with Memory
  LSR - Logical Shift Right
  NOP - No OPeration
  ORA - Bitwise-or A with Memory
  PHA - PusH A onto stack
  PHP - PusH P onto stack
  PLA - PulL A from stack
  PLP - PulL P from stack
  ROL - ROtate Left
  ROR - ROtate Right
  RTI - ReTurn from Interrupt
  RTS - ReTurn from Subroutine
  SBC - Subtract Memory from A with Borrow
  SEC - Set Carry flag (P.C)
  SED - Set Decimal flag (P.D)
  SEI - Set Interrupt flag (P.I)
  STA - Store A in Memory
  STX - Store X in Memory
  STY - Store Y in Memory
  TAX - Transfer A to X
  TAY - Transfer A to Y
  TSX - Transfer Stack Pointer to X
  TXA - Transfer X to A
  TXS - Transfer X to Stack Pointer
  TYA - Transfer Y to A


 

Instruction set by Purpose



 ACCUMULATOR                 ARITHMETIC                      STACK
   Arithmetic                  Accumulator                     Setup
   Memory Storage              Index X                         Implied Interaction
   Register Storage            Index Y                         Direct Interaction
   Bitwise Logic               Memory

 INDEX REGISTERS             BITWISE LOGIC                   FLOW CONTROL
   Index X                     Shifts & Rotates                Comparisons
     Arithmetic                Comparisons                     Conditional Branches
     Memory Storage            Processor Status Flags          GOTO & GOSUB
     Register Storage
   Index Y                                                   MISCELLANEOUS
     Arithmetic
     Memory Storage
     Register Storage                                                               

Where an instruction can be classified into more than one group, it is listed multiple times.

ACCUMULATOR
  Arithmetic
    ADC - Add Memory to A with Carry
    SBC - Subtract Memory from A with Borrow
  Memory Storage
    LDA - Load A with Memory
    STA - Store A in Memory
    PHA - PusH A onto stack (push ->)
    PLA - PulL A from stack (pull <-)
  Register Storage
    TXA - Transfer X to A
    TAX - Transfer A to X
    TYA - Transfer Y to A
    TAY - Transfer A to Y
  Bitwise Logic
    AND - Bitwise-and A with Memory
    EOR - Bitwise-exclusive-or A with Memory
    ORA - Bitwise-or A with Memory
    ASL - Arithmetic Shift Left
    LSR - Logical Shift Right
    ROL - ROtate Left
    ROR - ROtate Right


INDEX REGISTERS
  Index X
    Arithmetic
      INX - Increment X by one
      DEX - Decrement X by one
    Memory Storage
      LDX - Load X with Memory
      STX - Store X in Memory
    Register Storage
      TAX - Transfer A to X
      TXA - Transfer X to A
      TSX - Transfer Stack Pointer to X
      TXS - Transfer X to Stack Pointer
  Index Y
    Arithmetic
      INY - Increment Y by one
      DEY - Decrement Y by one
    Memory Storage
      LDY - Load Y with Memory
      STY - Store Y in Memory
    Register Storage
      TAY - Transfer A to Y
      TYA - Transfer Y to A


ARITHMETIC
  Accumulator
    ADC - Add Memory to A with Carry
    SBC - Subtract Memory from A with Borrow
    ASL - Arithmetic Shift Left
    LSR - Logical Shift Right
  Index X
    INX - Increment X by one
    DEX - Decrement X by one
  Index Y
    INY - Increment Y by one
    DEY - Decrement Y by one
  Memory
    DEC - Decrement Memory by one
    INC - Increment Memory by one
    ASL - Arithmetic Shift Left
    LSR - Logical Shift Right


BITWISE LOGIC
  Shifts & Rotates
    ASL - Arithmetic Shift Left
    LSR - Logical Shift Right
    ROL - ROtate Left
    ROR - ROtate Right
  Comparisons
    BIT - Test bits in A with M
  Processor Status Word (Flags) (P.?)
    P.N : sigN Flag (a.k.a. "S" Sign Flag)
      There are no instructions to directly SET or CLEAR P.N
    P.V : oVerflow Flag
      There is no instruction to directly SET P.V
      CLV - Clear oVerflow flag (P.V)
    P.B : Break Flag
      BRK - Simulate IRQ (push ->)
    P.D : binary coded Decimal Flag
      SED - Set Decimal flag (P.D)
      CLD - Clear Decimal flag (P.D)
    P.I : Interrupt (disable) Flag
      SEI - Set Interrupt flag (P.I)
      CLI - Clear Interrupt flag (P.D)
    P.Z : Zero Flag
      There are no instructions to directly affect P.Z
    P.C : Carry Flag
      SEC - Set Carry flag (P.C)
      CLC - Clear Carry flag (P.C)

STACK
  Setup
    TSX - Transfer Stack Pointer to X
    TXS - Transfer X to Stack Pointer
  Implied Interaction
    JSR - Jump to SubRoutine (push ->)
    RTS - ReTurn from Subroutine (pull <-)
    BRK - Simulate IRQ (push ->)
    RTI - ReTurn from Interrupt (pull <-)
  Direct Interaction
    PHA - PusH A onto stack (push ->)
    PHP - PusH P onto stack (push ->)
    PLA - PulL A from stack (pull <-)
    PLP - PulL P from stack (pull <-)

FLOW CONTROL
  Comparisons
    BIT - Test bits in A with M
    CMP - Compare A with Memory
    CPX - Compare X with Memory
    CPY - Compare Y with Memory
  Conditional Branches
    The is no unconditional Branch instruction.
    BCC - Branch iff Carry flag (P.C) is CLEAR
    BCS - Branch iff Carry flag (P.C) is SET
    BEQ - Branch iff Carry flag (P.Z) is SET
    BMI - Branch iff sigN flag (P.N) is SET
    BNE - Branch iff Carry flag (P.Z) is CLEAR
    BPL - Branch iff sigN flag (P.N) is CLEAR
    BVC - Branch iff oVerflow flag (P.V) is CLEAR
    BVS - Branch iff oVerflow flag (P.V) is SET
  GOTO & GOSUB
    JMP - GOTO Address
    JSR - Jump to SubRoutine
    RTS - ReTurn from Subroutine
    BRK - Simulate IRQ (push ->)
    RTI - ReTurn from Interrupt (pull <-)

MISCELLANEOUS
  NOP - No OPeration


 

Processor Status Word (Flags)



Called "F" for Flags on many other machines, the 6502 calls these indicators "P" for Processor Status Word.
And way back in those days a "word" was "8 bits" ...deal with it ;)

Of the eight available bits in the PSW, seven are used:

bit 7  P.N  Negative*
bit 6  P.V  oVerflow
bit 5   -   unused
bit 4  P.B  BRK was executed

bit 3  P.D  enable binary coded Decimal
bit 2  P.I  block IRQ Interrupts
bit 1  P.Z  Zero
bit 0  P.C  Carry
 
Bit no.:  7  6  5  4  3  2  1  0
Flag ID:  N  V  -  B  D  I  Z  C
          |  |     |  |  |  |  |
          |  |     |  |  |  |  +-- Carry
          |  |     |  |  |  +-- Zero
          |  |     |  |  +-- block IRQ Interrupts
          |  |     |  +-- enable binary coded Decimal
          |  |     +-- BRK was executed
          |  |
          |  +-- oVerflow
          +-- Negative*
* The Negative flag is often referred to as P.S the "S"ign flag

  P.N : sigN Flag
  P.V : oVerflow Flag
  P.B : Break Flag
  P.D : Decimal Flag
      Binary Coded Decimal (BCD)
  P.I : Interrupt (disable) Flag
  P.Z : Zero Flag
  P.C : Carry Flag
 
sigN Flag (P.N)

Also known as P.S (Sign flag) in many documents.
The following instructions can affect P.N:
 
ADC, SBC, INC, INX, INY, DEC, DEX, DEY
AND, EOR, ORA, BIT, CMP, CPX, CPY
ASL, LSR, ROL, ROR
LDA, LDX, LDY
TAX, TAY, TSX, TXA, TYA
PLA, PLP, RTI
The following instructions depend on P.N:
 
BMI, BPL
There are NO instructions to directly SET or CLEAR P.N
P.N serves TWO purposes
1)  To signify the sigN of the last mathematical or bitwise operation.
 
The sign is the bit-7 of the result value.
If the last operation was not a signed operation, P.N will still reflect bit-7 of the result, but will NOT be considered as a sign.
2)  As a result store for a BIT instruction:
 
The BIT instruction reads the contents of the specified memory address and copies bit-7 of that value to P.N

 
oVerflow Flag (P.V)

The following instructions can affect P.V:
 
CLV, BIT
ADC, SBC
PLP, RTI
The following instructions depend on P.V:
 
BVC, BVS
There is NO instruction to directly SET P.V
P.V can be CLEARed by the user by means of the CLV instruction
P.V serves TWO purposes
1)  To signify an oVerflow (a sign change) during a mathmatical operation. Caused by an ADC or SBC instruction:
 
If an ADC or SBC instruction generates a result that would require more than 8 bits to hold (that is, any number outside the range -128 to 127) then P.V is SET; else P.V is CLEARed.
This flag may be ignored if the programmer is NOT using signed arithmetic.
2)  As a result store for a BIT instruction:
 
The BIT instruction reads the contents of the specified memory address and copies bit-6 of that value to P.V

 
Break Flag (P.B)

P.B and the BRK instruction seem to me to be one very badly thought out bodge.
If you do not plan to use the BRK instruction I would just ignore it!
P.B is never actually set in the Flags register!
When a BRK instruction occurs the Flags are PUSHed onto the Stack along with a return address*
It is only this copy of the Flags (the one on the Stack) that has P.B set!
 
* 
This return address is actually "Address_of_BRK_instruction+2".
Bearing in mind that the BRK instruction is only ONE byte long...
This means that if you simply issue an RTI,
The byte immediately following the BRK instruction will be ignored.
I have read reasons as to WHY this is the case, but frankly they all stink! ...Just deal with it!
 
For further information, see Interrupts.
 
 
Decimal Flag (P.D)

The following instructions can affect P.D:
 
CLD, SED
PLP, RTI
The following instructions depend on P.D:
 
ADC, SBC
P.D is "unknown" at boot. Therefore the boot code should initialise this flag
P.D can be SET by the user by means of the SED instruction
P.D can be CLEARed by the user by means of the CLD instruction
P.D dictates whether Addition (ADC) and Subtraction (SBC) operate in the classic Binary or the more obscure Binary Coded Decimal (BCD) mode.

 
 
Binary Coded Decimal (BCD)
  BCD is whereby the upper and lower nibbles (4-bits) of a byte (8-bits) are treated as two digits in a decimal number;
The upper nibble contains the number from the 'tens column'; and the lower nibble, the number from the 'units column'
  By Example: 10010011 (or 1001'0011) represents 93 (or 9'3)
Thus restricting the range of values that can be held in a single byte to the positive integers 0 through 99.
  The upshot is that any routine "PrintHex" will effectively become "PrintDecimal" ...Other than that I personally have never worked out why! And as such I do not intend to cover it in any more detail here. My suggestion is perform a CLD during boot up and forget about it!



  Interrupt (disable) Flag (P.I)

The following instructions can affect P.I:
 
CLI, SEI
BRK, RTI, PLP
The following instructions depend on P.I:
~None~
P.I can be CLEARed by the user by means of the CLI instruction
P.I can be SET by the user by means of the SEI instruction
When P.I is SET, Interrupt ReQuest signals (IRQs) to the IRQ pin (classically pin-4) are IGNORED
When P.I is CLEAR, signals to the IRQ pin are acknowledged.
  Full details can be found under Interrupts and Interrupt ReQuests (IRQ's)
When the processor is switched on or reset, P.I is SET.
Thus Interrupts are disabled on startup.
The intention here is to give the boot code an opportunity to initialise all external hardware without Interruption from that hardware.

 
Zero Flag (P.Z)

The following instructions affect P.Z:
 
ADC, SBC, INC, INX, INY, DEC, DEX, DEY
AND, EOR, ORA, BIT, CMP, CPX, CPY
ASL, LSR, ROL, ROR
LDA, LDX, LDY
PLA, PLP, RTI
TAX, TAY, TSX, TXA, TYA
The following instructions depend on P.Z:
 
BEQ, BNE
There are no instructions to directly SET or CLEAR P.Z
P.Z is SET when a zero value is placed in a register
P.Z is CLEARed when a non-zero value is placed in a register

 
Carry Flag (P.C)

The following instructions affect P.C:
 
CLC, SEC
ADC, SBC
CMP, CPX, CPY
ASL, LSR, ROL, ROR
PLP, RTI
The following instructions depend on P.C:
 
BCC, BCS
ADC, SBC
ROL, ROR
P.C is "unknown" at boot. Therefore the boot code should initialise this flag
P.C can be SET by the user by means of the SEC instruction
P.C can be CLEARed by the user by means of the CLC instruction
P.C can be considered to be the 9th bit of an arithmetic operation.


 

Addressing Modes



Name
-
Abbreviation
Absolute
-
"Abs"
Absolute Indexed
-
"Abs,X" & "Abs,Y"
Accumulator
-
"A"
Immediate
-
"Immed"
Implied
-
"Implied"
Indexed Indirect
-
"(Ind,X)"
Indirect
-
"Indirect"
Indirect Indexed
-
"(Ind),Y"
Relative
-
"Relative"
Zero-Page
-
"ZP"
Zero-Page Indexed
-
"ZP,X" & "ZP,Y"


 
"Implied" : Implied Addressing

This mode is whereby no address or value is specified by the programmer. Some of these instructions perform no memory access at all:
 
 
  Example:   TXA                                    
 
  Logic:     A = X                                  

Others require memory addresses, but these are either known or calculated by the CPU at run time.
 
 
  Example:   PHA                                    
 
  Logic:     bPoke(SP,A)
             SP = SP - 1                            

 
 
  Example:   BRK                                    
 
  Logic:     bPoke(SP,A)
             SP = SP - 1
             bPoke(SP,P)
             SP = SP - 1
             PC = (bPeek($FFFF)<<8) | bPeek($FFFE)  

Implied Addressing is available for the following instructions:
  CLC, CLD, CLI, CLV, DEX, DEY, INX, INY, NOP, PHA, PHP, PLA, PLP, RTI, RTS, SEC, CLD, SEI, TAX, TAY, TSX, TXA, TXS, TYA


 
"A" : Accumulator Addressing

There are a number of "atomic read/modify/write" instructions which can address EITHER Memory OR the Accumulator (A)
In this case one cannot 'infer' A (as above), it MUST be stated.
 
 
  Example:   DEC  A                                 
 
  Logic:     A = A - 1                              

Accumulator Addressing is available for the following instructions:
  ASL, LSR, ROL, ROR


 
"Immed" : Immediate Addressing

A better name for this mode might be Immediate Value as no "addressing" actually takes place.
 
 
  Example:   LDA  #$A5                              
 
  Logic:     A = $A5                                

Immediate Addressing is available for the following instructions:
  ADC, AND, CMP, CPX, XPY, EOR, LDA, LDX, LDY, ORA, SBC


 
"Relative" : Relative Addressing

This mode is used exclusively by the Branch instructions. For further information see Conditional Branches
 
Immediate Addressing is available for the following instructions:
  BCC, BCS, BEQ, BMI, BNE, BPL, BVC, BCS


 
"Abs" : Absolute Addressing

Read a value from a 16-bit address
Remember without special external hardware for paging, the 6502 only has a maximum of 64K of address space available - so 16-bits is enough to address ANY byte of memory.
 
 
  Example:   LDA  $A5B6                             
 
  Logic:     A = bPeek($A5B6)                       

Absolute Addressing is available for the following instructions:
  ADC, AND, ASL, BIT, CMP, CPX, CPY, DEC, EOR, INC, JMP, JSR, LDA, LDX, LDY, LSR, ORA, ROL, ROR, SBC, STA, STX, STY


 
"ZP" : Zero-Page Addressing

Much like Absolute Addressing, but can only address the first 256 (0..255) bytes of memory.
The benefit is a saving of 1 T-State :)
 
 
  Example:   LDA  $A5                               
 
  Logic:     A = bPeek($A5)                         

Zero-Page Addressing is available for the following instructions:
  ADC, AND, ASL, BIT, CMP, CPX, CPY, DEC, EOR, INC, LDA, LDX, LDY, LSR, ORA, ROL, ROR, SBC, STA, STX, STY


 
"Abs,X" & "Abs,Y" : Absolute Indexed Addressing

In Absolute Addressing the destination address is fixed by the programmer (or assembler) at assembly time.
By using the hard-coded address as a base, and X or Y as an Index, a more dynamic addressing system can be implemented.
If the result of Base+Index is greater than $FFFF, wrapping will occur.
 
 
  Example:   LDA  $A5B6,X                           
 
  Logic:     A = bPeek( ($A5B6+X) & $FFFF )         


 
  Example:   LDA  $A5B6,Y                           
 
  Logic:     A = bPeek( ($A5B6+Y) & $FFFF )         

Absolute Indexed Addressing with X is available for the following instructions:
ADC, AND, ASL, CMP, DEC, EOR, INC, LDA, LDY, LSR, ORA, ROL, ROR, SBC, STA
Absolute Indexed Addressing with Y is available for the following instructions:
ADC, AND, CMP, EOR, LDA, LDX, ORA, SBC, STA


 
"ZP,X" & "ZP,Y" : Zero-Page Indexed Addressing

In Zero-Page Addressing the destination address is fixed by the programmer (or assembler) at assembly time.
By using the hard-coded address as a base, and X or Y as an Index, a more dynamic addressing system can be implemented.
With Zero-Page, only the first 256 (0..255) bytes of memory may be addressed. So if the result of Base+Index is greater than $FF, wrapping will occur.
The benefit is a saving of 1 T-State :)
 
 
 
  Example:   LDA  $A5,X                             
 
  Logic:     A = bPeek( ($A5+X) & $FF )             


 
  Example:   LDX  $A5,Y                             
 
  Logic:     X = bPeek( ($A5+Y) & $FF )             
 
Zero-Page Indexed Addressing with X is available for the following instructions:
  ADC, AND, ASL, CMP, DEC, EOR, INC, LDA, LDY, LSR, ORA, ROL, ROR, SBC, STA, STY
 
Zero-Page Indexed Addressing with Y is available for the following instructions:
  LDX, STX


 
"Indirect" : Indirect Addressing

With this instruction, the 8-but address (location) supplied by the programmer is considered to be a Zero-Page address, that is, an address in the first 256 (0..255) bytes of memory.
The content of this Zero-Page address must contain the low 8-bits of a memory address
The following byte (the contents of address+1) must contain the upper 8-bits of a memory address
Once this memory address has been read from the Zero-Page location (specified by the programmer), this calculated memory address is then examined, and it's contents are returned.
Although tricky to explain, the concept is actually quite simple. The upshot is that you do not need to hard-code all address value, this system allows addresses to be calculated at run time.
 
 
 
  Example:   LDA  $A5                               
 
  Logic:     l = bPeek( $A5 )
             h = bPeek( ($A5+1) & $FF )<<8
             m = h | l
             A = bPeek(m)                           
 
Indirect Addressing is available for the following instructions:
  JMP


 
"(Ind,X)" : Indexed Indirect Addressing

This addressing mode is only available with X.
Much like Indirect Addressing, but the contents of the index register is added to the Zero-Page address (location)
If Base_Location+Index is greater than $FF, wrapping will occur.
 
 
 
  Example:   LDA  ($A5,X)                           
 
  Logic:     l = bPeek( ($A5+X) & $FF )
             h = bPeek( ($A5+X+1) & $FF ) <<8
             m = h | l
             A = bPeek(m)                           
 
Indexed Indirect Addressing is available for the following instructions:
  ADC, AND, CMP, EOR, LDA, ORA, SBC, STA


 
"(Ind),Y" : Indirect Indexed Addressing

This addressing mode is only available with Y.
Much like Indexed Addressing, but the contents of the index register is added to the Base_Location after it is read from Zero-Page memory.
If Base_Location+Index is greater than $FFFF, wrapping will occur.
 
 
 
  Example:   LDA  ($A5),Y                          
 
  Logic:     l = bPeek( $A5 )
             h = bPeek( ($A5+1) & $FF )<<8
             m = ( (h|l)+Y ) & $FFFF
             A = bPeek(m)                           
 
Indirect Indexed Addressing is available for the following instructions:
  ADC, AND, CMP, EOR, LDA, ORA, SBC, STA



 

6502 Memory Map



The 6502 memory map is not strict, architecture may use different compositions.
The following is the structure proposed by Rockwell and implemented by many, if not most, implementations of the architecture.


 0000-00FF  - RAM for Zero-Page & Indirect-Memory Addressing
 0100-01FF  - RAM for Stack Space & Absolute Addressing
 0200-3FFF  - RAM for programmer use
 4000-7FFF  - Memory mapped I/O
 8000-FFF9  - ROM for programmer useage
 FFFA       - Vector address for NMI (low byte)
 FFFB       - Vector address for NMI (high byte)
 FFFC       - Vector address for RESET (low byte)
 FFFD       - Vector address for RESET (high byte)
 FFFE       - Vector address for IRQ & BRK (low byte)
 FFFF       - Vector address for IRQ & BRK  (high byte)     


 

The Stack



Assembler newcomers might like to read What is The Stack?

Given that you know what a Stack is ...this is probably the information you are after:

The Stack Pointer is standardly abbreviated to "SP" or "S" depending on many factors, not least of all the author of the document you are reading.
  
For the duration of this section of the document, the Processor Status Word (or "Flags") will be referred to as PSW
The following instructions affect the Stack: BRK, JSR, PHA, PHP, PLA, PLP, RTI, RTS, TXS
  
TXS is used by the programmer to initialise the Stack Pointer. An example of this can be found in the System Startup code.
The Stack can only live in Page 1 of memory; That is, addresses in the range $01'00...$01'FF
Therefore SP is only an 8-bit value
This means that the Stack will wrap around within Page 1 if care is not taken.
  
PHA PusHes a single byte onto the Stack;
This byte will contain a copy of the value currently in register A
  
PHP PusHes a single byte onto the Stack;
This byte will contain a copy of the value currently in the PSW
  
PLA PulLs (or "POPs") a single byte from the stack;
This value retrieved will be stored in A
  
PLP PulLs (or "POPs") a single byte from the stack;
This value retrieved will be stored in the PSW
  
The easiest way to set the Flags to a "known value" is:
 
  LDA   $A5      ; A = "known value" ...$A5, in this case
  PHA            ; Place a copy of the value in A onto the Stack
  PLP            ; Retrieve the top value on the Stack into the PSW  
  
JSR and RTS are the 6502 equivalents of GOSUB and RETURN;
A comprehensive explanation of their use of the Stack is under GOSUB and RETURN
  
BRK simulates an interrupt, but behaves most perculiarly.
BRK places THREE bytes on the stack.
 
The first byte on is the MSB of the (Return_Address_plus_one)
The second byte on is the LSB of the (Return_Address_plus_one)
The third byte on is a copy of the current PSW, with P.B SET
It should be noted that P.B is not SET in the PSW
The effects and uses of BRK are also discussed at the following locations:
  BRK - Simulate an Interrupt ReQuest (IRQ)
  Break Flag (P.B)
  Interrupts - How can I simulate an Interrupt?
  
RTI is used to terminate an Interrupt or to return from a BRK instruction. RTI removes THREE bytes from the Stack
  The first byte on the Stack is retrieved and place in P
  The next byte on the Stack is retrieved and place in the LSB of the Program Counter (PC)
  The next byte on the Stack is retrieved and place in the MSB of the Program Counter (PC)


 
    The Stack - What Is It?    


I once sat through a one hour lecture where a professor of computer science completely failed to explain The Stack. WHAT IS THE PROBLEM?

The Stack is a very very simple idea. It's a "pile of stuff" and due to the laws of physics you can only add or remove stuff to or from the top.
Okay, it does NOT build from the ground-up, but from the ceiling-down - if that is too confusing, stand on your hands while you read that again :)

If you want something in the middle ...you take all the stuff off the top; remove the thing you want; and put all the other stuff back.
In reality, you could build some scaffolding and carefully remove something from the middle. And yes, you can metaphorically do the same thing in assembler ...WHEN you know how it's done.

So, before you try to get clever ...read this:

Imagine a cardboard box that can hold 8-bits of information.
Now Imagine a STACK of these boxes.
Next to this STACK, is a guard to stands watch over it.
His main guard duty is to POINT to the space where the next box will go.
Due to the nature of physics, this gap will always be just above the the top-most box!
If anyone PUSHes another box onto the STACK, it will be added to the STACK at precisely where the guard is POINTing. After this has happened the guard will automatically move his finger and POINT at the new space.
If anyone PULLs (or POPs) a box from the stack; that is, should anyone as the guard for the top box. He will move his finger to point at the last box, and then pass it to you.
The result is that as he passes you the box, his finger is left POINTing at the newly formed space.
This creates a "last-in, first-out" system - because you can only ever access the TOP of the stack.
...oh yeah, one more thing...
This system was designed by an Australian; As we all know, the laws of physics invert when you are on the bottom of the globe.
So the stack actually builds from the ceiling down - deal with it!
 
Realise that there is a limited amount of room an the STACK.
If the STACK is full and you attempt to PUSH another box STACK a "Stack Overflow" condition will occur.
On many modern system architecture you will receive a warning when this occurs.
This is NOT true of the 6502 STACK POINTer
So it is the concern of the programmer to be careful that this does not occur.
 
There are a couple of more subtle things that are for the advanced programmer.
When a box is removed, a ghost of it remains.
This ghost is a perfect copy of the last box which occupied that space.
But be warned, a light breeze that passes that area of the warehouse will destroy the ghost, so do NOT depend on the presence of this ghost too heavily.
 
In actual fact you do not retrieve the value on the TOP of the stack, but actually the value which is indicated by the STACK POINTER
For a bribe, (the currency is T-states in this world), the guard will point anywhere you want him to, including (but not restricted to) the middle of the stack.
Bear in mind that during this process, the stack will NOT be guarded. BE WARNED it may not be there when you get back!
This is a very dodgy process and considered to be very bad coding etiquette, but a is also a damn fine way to confuse hackers and has found many other weird and wonderful uses in it's life.
...what this security guard will do for a small bribe is certainly perverted, but great fun to watch :)
 
Question: What colour uniform was the guard wearing?



 

Program Flow Control



The Program Counter (PC) is a 16-bit register and is therefore capable of addressing ANY byte in the 64K or 65536 bytes (0..65535) memory space.
It always holds the address of the next instruction to be exeucted.

Program flow control is effected by changing the value in PC.

First, a brief note should made here about the way instructions execute.
The "Fetch-Execute cycle" is what drives a processor
The processor fetches an instruction and then executes it.
The Program Counter is incremented AFTER the Fetch phase and BEFORE the Execute phase.
Therefore... during Execution of an instruction, the Program Counter is pointing at the NEXT instruction to be executed; NOT this one!
This is particularly important when considering the destination of a Branch instructions.
And makes perfect sense when considered in relation to the JSR and RTS instructions.

Interrupts also modify the flow of execution.
But as they are not normally under programmer control, they are covered in detail in their own section: Interrupts and Interrupt ReQuests (IRQ's)


 
Conditional Branching

The following Conditional Branch instructions are available:
 
BCC - Branch iff Carry flag (P.C) is CLEAR
BCS - Branch iff Carry flag (P.C) is SET
BEQ - Branch iff Carry flag (P.Z) is SET
BMI - Branch iff sigN flag (P.N) is SET
BNE - Branch iff Carry flag (P.Z) is CLEAR
BPL - Branch iff sigN flag (P.N) is CLEAR
BVC - Branch iff oVerflow flag (P.V) is CLEAR
BVS - Branch iff oVerflow flag (P.V) is SET
 
It should be noted that there is NO unconditional branch! ...but one can be simlated by setting a Processor Status Word Flag to a known state and then Branching on that condition flag.
The operand to a Branch instruction is a single byte offset (8 bits, giving a range of -128 to 127) which specifies the new Program Counter (PC) address realtive to it's current position. Hence the name Relative Addressing
All branch commands are two bytes long - one byte for the Branch instruction; another for the relative offset.
 
 So
  BR  +0  
will have no effect on program flow.
 and
  BR  -2  
will cause an infinite loop ...a nice place to sit and wait for an Interrupts?
 
The advantage of Relative Addressing is that it geneates fully relocatable code; That is, the program will execute normally no matter where it is loaded into memory.
The down-side Relative Addressing is that compromises must be made if you wish to change PC by more than {-128 to +127}.

Two solutions are available to long branches:
1) Use a "complimented branch and jump pair"
  Consider this example where "label" is 'out of range'
   

         ...
         BCC      label    ; Branch to "label" is P.C is Clear
         [blah]
         ...
         ...
 label:  [foobar]                                                                      
  This code can be replaced with
   
         ...
         BCS    $$       ; Branch to "$$" is P.C is Set
         JMP    label    ; Jump to "label"
 $$:     [blah]
         ...
         ...
 label:  [foobar]                                                                      
  The advantage of this method is that the memory overhead is only 3 bytes
  And although it may cause several passes for an assembler, the process can be automated simply and still produce readable code.
  The disadvantage is that the code will no longer be relocatable.
 
2) "skip" or "leap-frog" through the code.
 
This process involves placing branches at intermediate points throughout the code.
This process will ensure that the resultant program is still relocatable, but at the cost of bulky and long winded code which can become unreadable quite quickly.
One should also consider the fact that there is no BRA (BRanch Always) instruction in 6502.
Although, there is no reason that a smart assembler could not handle the process for you.
To solve the same problem as set in resolution 1 above:
 
         ...
         BCC    $1       ; Branch to "$1" is P.C is Clear
         [blah]
         ...
         ...
         ...
         PHP             ; Preseve PSW/Flag status
         CLV             ; Clear P.?, where "?" is an flag other than that being used
         BVC    $$       ; Branch to "$$" is P.? is Clear
 $1:     BCC    label    ; Branch to "label" is P.C is Clear
 $$:     PLP             ; Restore PSW/Flag status
         ...
         ...
         ...
 label:  [foobar]                                                                      
This "skipping" or "leap-frogging" process can be repeated as many time as is necessary to traverse the distance involved.
The process outlined here is appropriate for a semi-intelligent assembler. It could be optimised by careful choice of flag and placing of skip points.
All-in-all it is a horrible clumsy method that should not be used unless the need is dire - It is memory hungry, ugly, uses Stack space, and results in unreadble code.

The following table shows how to assemble standard C comparisons to their 6502 equivalents.
It should be noted that two of the conditions require TWO Branch instructions to resolve, whereas the other four only require ONE.
 
 
  Signed Unsigned
 IF (r <  M)  GOTO lbl  
  CMP  M
BMI lbl
  CMP  M
BCC lbl
 IF (r <= M)  GOTO lbl  
  CMP  M
BMI lbl
BEQ lbl
  CMP  M
BCC lbl
BEQ lbl
 IF (r == M)  GOTO lbl  
         CMP  M
BEQ lbl
 IF (r != M)  GOTO lbl  
         CMP  M
BNE lbl
 IF (r >= M)  GOTO lbl  
  CMP  M
BPL lbl
  CMP  M
BCS lbl
 IF (r >  M)  GOTO lbl  
  CMP  M
BEQ +2
BPL lbl
  CMP  M
BEQ +2
BCS lbl
 
 IF (   bPeek(Mem)&(1<<7)  ) GOTO lbl  
  BIT  Mem 
BMI lbl
 IF ( !(bPeek(Mem)&(1<<7)) ) GOTO lbl  
  BIT  Mem 
BPL lbl
 IF (   bPeek(Mem)&(1<<6)  ) GOTO lbl  
  BIT  Mem 
BVS lbl
 IF ( !(bPeek(Mem)&(1<<6)) ) GOTO lbl  
  BIT  Mem 
BVC lbl
 
"r" is any one of the three primary registers {A, X, Y}
If A the intended register, then the CMP instruction must be used (as shown above).
If X or Y is intended register, then the CPX or CPY instruction must be used (in place of the CMP instructions shown in the table above).


 
GOTO, GOSUB and RETURN


JMP - a.k.a GOTO

 
The simplest way to change the execution flow of the processor is with the JMP instruction.
This will immediately and unconditionally modify the Program Counter. And effectively behaves just like the classic GOTO command in most higher level languages.
JMP has TWO addressing modes, Absolute and Indirect.
 
Absolute Addressing:
 
This is whereby the two bytes that follow the JMP instruction are the value which will be placed in PC.
And therefore, also the address of the next instruction that will be executed.
 
 
  Example:   JMP  $A5B6                           
 
  Logic:     PC = $A5B6                           
 
Indirect Addressing:
 
This mode allows the Destination address to be held anywhere in memory.
The two bytes that follow the JMP instruction are a pointer to where the Destination address is stored.
The 6502 is "little-endian", this means that:
The byte immeditely after the JMP instruction is the "Bottom" or "Low" 8-bits of the address
And the second byte that follows the JMP instruction is the "Top" or "Hight" 8-bits of the address
 
 
  Example:   JMP  ($A5B6)                         
 
  Logic:     l = bPeek($A5B6)
             h = bPeek( ($A5B6+1) & $FFFF ) <<8
             PC = h | l                           
 

 JSR & RTS - GOSUB & RETURN

 
JSR is normally used to call SubRoutines;
That is, small pieces of code which are used repetetively by the main code.
A typical example might be "print".
JSR behaves exactly like JMP in Absolute Addressing Mode with one excpetion...
Before PC is changed, a copy of PC is placed on the Stack for safe keeping.
When the Subroutine is finished, it simply issues an RTS and the return address is retrieved from the Stack and placed back into PC.
The net result is that execution will then continue from exactly where it left off.
 
  Example:   JSR  $A5B5                           
 
  Logic:     t = PC - 1
             bPoke(SP,t.h)
             SP = SP - 1
             bPoke(SP,t.l)
             SP = SP - 1
             PC = $A5B6                           
 
 
  Example:   RTS                                  
 
  Logic:     SP = SP + 1
             l = bPeek(SP)
             SP = SP + 1
             h = bPeek(SP)<<8
             PC = (h|l) +1                        
 
As can be seen from the Logic above, JSR actually stores PC-1 on the Stack
This means that the address on the Stack is actually:
A)  The byte BEFORE the instruction that follows the JSR
and
B)  The second byte of the JSR address; in this case $A5
(remember... "little-endian" -- the "lowest" or "least significant" byte comes first)
RTS is sensible enough to know this, and corrects the error before making the return.
 
Although it is not normally necessary to know this.
There are occasions when you may wish to Push an address on the Stack and then use the RTS instruction to initiate the jump.
This is very unusual, but if you wish to use this method of Flow Control you must remember to
Push the address of the destination instruction MINUS ONE.
 
 
  Example:   Affect a jump to memory address $A5D8    
 
  Code:      LDA   #$A5
             PHA
             LDA   #$D7
             PHA
             RTS                
If you plan to use this method, you should take time to read the section on The Stack.



 

Interrupts and Interrupt ReQuests (IRQ's)



What is an Interrupt?
An Interrupt is, at it's most primitive level, a signal that comes into the CPU from one of it's pins.
Specifically, the one labelled "/IRQ".
When this pin is "pulled low" (Eg. has 0V applied to it), a signal is sent to the CPU core.
The CPU halts the current program and instead runs a special routine called the Interrupt Service Routine.
 
 
How can I ENable Interrupts?
When the 6502 starts. Interrupts are disabled.
The intention here is to give the boot code an opportunity to initialise all external hardware without interruption (from that hardware.)
 
Interrupts can be enabled by CLEARing the Interrupt (disable) Flag (P.I) with the CLI instruction.
 
 
How can I DISable Interrupts?
Sometimes, when you are executing time critical code, you may wish to ensure that you are not interrupted.
 
The process of disabling Interrupts is known as "Masking" or "Disabling" or "Inhibiting" or "Ignoring".
That is, you don't stop the interrupt from occuring, you just ignore it! ...you "Mask" it.
 
To make the 6502 Mask interrupts you need to SET the Interrupt (disable) Flag (P.I)
This is done with the SEI instruction.
 
 
What happens when an Interrupt occurs?
First you must consider if Interrupts are disabled
If they are (disabled). We do nothing!
 
If Interrupts are enabled (I.e. Interrupt (disable) Flag (P.I) is CLEAR)
The following process occurs:
  The current instruction is allowed to finish.
  The current PC is Pushed onto the Stack.
    (This is the address of the next instruction).
  A copy of the Processor Status Word (Flags) (P.?) is Pushed onto the Stack.
  The Interrupt (disable) Flag (P.I) is SET
    (This ensures that the interrupt does not get interrupted)
  A 16-bit address is read from $FFFE...$FFFF in memory and placed in Program Counter (PC).
 
You must supply a special piece of code called The Interrupt Service Routine which will start at this address (or "Vector")
An Example/Template Interrupt Service Routine is supplied below
 
 
What is a "Non-Maskable Interrupt"?
An NMI is almost identical to an IRQ, but it:
  Uses a different pin on the chip - Namely "/NMI"
  Is triggered by a Level Change (Eg. from 0V-to-5V or vice versa)
  Calls a different Routine - Specified by the 16-bit Vector at $FFFA...$FFFB
  Cannot be Masked, Disabled, Inhibited or Ignored
 
 
How can I disable Non-Maskable Interrupts?
You can't - They're NON-Maskable!
The Interrupt (disable) Flag (P.I) has NO effect on NON-Maskable Interrupts
The purpose of the NMI is to alert the CPU to a critical event.
 
You can, of course, design/modify your hardware such that no signals are ever sent to the /NMI pin. That'll stop it working!
You might instead write an NMI-Handler which does nothing except RTI. Not so much "ignoring it", more akin to saying "yeah, whatever" everytime it tries to interrupt you.
 
In very simple computers, NMI is often left unused.
 
If the NMI wants your attention - whatever it is, is more important that what you're currently doing.
If an NMI happens for a trivial task, lean over and slap your hardware engineer sqaure between the eyes and when he asks why you just did that, say "oh nothing important" ...he'll soon get the message!
My Girlfriend is a non-maskable-interrupt. The telephone isn't!
 
 
What happens when a Non-Maskable Interrupt occurs?
Pretty much the same as a normal Interrupt except the Vector (address of Interrupt Routine) is read from $FFFA...$FFFB
  The current instruction is allowed to finish.
  The current PC is Pushed onto the Stack.
    (This is the address of the next instruction).
  A copy of the Processor Status Word (Flags) (P.?) is Pushed onto the Stack.
  The Interrupt (disable) Flag (P.I) is SET
    (This ensures that the interrupt does not get interrupted)
Also note that the Flag is SET after the Processor Status Word (Flags) (P.?) is Pushed onto the Stack
  A 16-bit address is read from $FFFA...$FFFB in memory and placed in Program Counter (PC).
 
 
When does an Interrupt or Non-Maskable Interrupt finish?
Quite simply: When the CPU finds an RTI - ReTurn from Interrupt instruction.
 
It is important to note that an Interrupt will Push "PC" on the Stack
...Unlike JSR which Pushes "PC-1"
Therefore when the RTI instruction is executed
it does NOT need to perform the error correction that is used by RTS
This is only relevant if you are playing silly buggers with the Stack
...but worth noting, in case you do.
 
RTI does not actually reset the Interrupt (disable) Flag (P.I)
...but it DOES Pull (Pop) the a copy of the Processor Status Word (Flags) (P.?) from the stack as it returns.
Due to the way that the Interrupt occurs;
The action of Pulling (POPing) the Processor Status Word (Flags) (P.?) off the stack
means that the Interrupt (disable) Flag (P.I) is implicitly CLEARed.
The upshot is that under normal conditions RTI will CLEAR the Interrupt (disable) Flag (P.I)
 
 
How can I simulate an Interrupt.
The BRK instruction does precisely this.
In fact, an IRQ triggers the same ciruit in the chip as BRK.
It MUST be noted that when BRK Pushes the return address on the Stack, it actually Pushes "PC+1".
...Nobody seems to know why, but it does, and you have to deal with it!
The Interrupt Service Routine suggested below takes cares of this correction.
Alternatively, you can just put a NOP after each BRK instruction
 
 
How do I write an Interrupt Service Routine?
The following code is an example of an Interrupt Service Routine
This code does not realy tackle the issue of Device I/O.
It is presumed that each device will set bit-7 of a specified memory address to indicate that it requires servicing.
This is NOT always true, you will need to read the respective Device Manual to know precisely how each device works.
 
There is a LOT more to know about Interrupts and Interrupt Service Routines,
but it is not considered "in scope" for this document.
(I've been at this a week and I'm getting bored.)
 
 
 IRQ:    ; Preserve all registers
         PHA                ; Put A on the Stack
         TXA                ; Put X on the Stack
         PHA                ; ...
         TYA                ; Put Y on the Stack
         PHA                ; ...

 ChkBrk: ; Check if Interrupt was caused by a BRK
         TSX                ; Get Stack Pointer to X
         INX                ; =Address where Y is stored
         INX                ; =Address where X is stored
         INX                ; =Address where A is stored
         INX                ; =Address where P is stored
         LDA  $0100,X       ; Get Stack copy of PSW to A
         AND  A,$10         ; Isolate P.B
         BEQ  NotBrk        ; If P.B=0, skip BRK Handling code

 Break:  ; Handle BRK Interrupt
         ...
         ...
         ...

 RetAdr: ; Correct Return Address error
         TSX                ; Get Stack Pointer to X
         INX                ; =Address where Y is stored
         INX                ; =Address where X is stored
         INX                ; =Address where A is stored
         INX                ; =Address where P is stored
         INX                ; =Address where PC.l is stored
         DEC  $0100,X       ; PC.l = PC.l - 1
         BPL  Return        ; If Page Boundary was NOT crossed
         INC  X             ; =Address where PC.h is stored
         DEC  $0100,X       ; PC.h = PC.h - 1
         STC                ; Branch to return code
         BCS  Return        ; ...

 NotBrk: ; Interrupt was caused by hardware IRQ pin
         ; Poll each I/O device to see who caused the Interrupt
         LDA  $Device1      ; Get status of device 1
         BMI  Dev1          ; Check if it is active
         ...
         ...
         LDA  $DeviceN      ; Get status of device N
         BMI  DevN          ; Check if it is active
         ; nothing was acive!?

 Return: ; Restore registers from stack and ReTurn from Interrupt
         PLA                ; Restore Y
         TAY                ; ...
         PLA                ; Restore X
         TAX                ; ...
         PLA                ; Restore A
         RTI                ; ReTurn from Interrupt

 Dev1:   ; Handle Interrupt from Device 1
         SEI**              ; Allow Interrupt to be interrupted
         ...
         ...
         STC                ; Branch to return code
         BCS  Return        ; ...

 ...     ...
         ...
         ...

 DevN:   ; Handle Interrupt from Device N
         SEI**              ; Allow Interrupt to be interrupted
         ...
         ...
         STC                ; Branch to return code
         BCS  Return        ; ...
                                                                       
 ** If a device is a LOW priority device, you may choose to allow that device to interrupted by placing and CLI instruction at the top of it's private handler code.
  If ZERO Device Handlers contain a CLI instruction then you will be coding an "Interrupt Queue".
  If EVERY Device Handlers contain a CLI instruction then you will be coding an "Interrupt Stack".
  If SOME Device Handlers contain a CLI instruction then you will be coding an "Hybrid Interrupt Handler".
 


 

System Startup sequence (boot-strap)



At startup the processor will SET the Interrupt (disable) Flag (P.I) and place the RESET Vector Address in the Program Counter (PC).
...and start executing whatever it finds there.
 
The programmer should now:
 
Initialise the Stack
  Note that the Stack is ALWAYS on page 1 (bytes 256..511 of memory)
Intialise I/O Devices
Enable Interrupts
Set the arithmetic mode
 
By Example:
 
 Reset:  LDX  #$FF      ; SP = $01'FF
         TXS            ; ...
         ...
 Init:   Intitialise I/O
         ...
         CLI            ; Enable Interrupts
         CLD            ; Math Mode = Binary
         ...                                  
 
Each Input/Output (I/O) Device will normally trap reads and writes to block of addresses in the range $4000 to $7FFF.
Therefore, each I/O Device is normally initialised by writing a specific value to a specific memory address.
 
 
By Example:
 
 Init:   LDA  #$80      ; Enable Controller
         STA  $50FF     ; ...
         LDA  #$A3      ; Disable Audio
         STA  $6125     ; ...
         ...                                    



 

Bibliography





"Synertek Programming Manual" DOWNLOAD
Publication Number 6500-50
Written, 1975
Revised, August 1976
Published, May 1978
SynerTek, 3050 Colorado Drive, Santa Clara, Cal. 95051


Mastering Machine Code on Your ZX Spectrum PURCHASE
Toni Baker
October 1983
Publisher: Interface
ISBN: 0907563236


Rockwell 650x : 651x Data Sheet DOWNLOAD
Document Number 29000D39
Order No. D39
Rev B, June 1987


6502 Opcodes VIEW
John Pickens


Compare Instructions VIEW
John Pickens


[Links valid 01/Oct/2003]

 
  Authored by: Bluechip