返回首页

6502 指令速查手册

6502 常用指令速查手册

适用于 NES (FC) 开发,配合 ca65 汇编器使用

6502 共 56 条指令,本文收录开发中最常用的 ~40 条,按功能分类


目录

  1. 寄存器与命名规律
  2. 数据传送指令
  3. 算术运算指令
  4. 逻辑运算指令
  5. 比较与分支指令
  6. 移位指令
  7. 跳转与子程序
  8. 栈操作指令
  9. 标志位操作指令
  10. 寻址方式速查
  11. 常见组合模式

1. 寄存器与命名规律

寄存器总览

6502 只有 6 个寄存器——正是这种极简设计让 NES 的 CPU 高效而强大:

寄存器 全称 位数 作用
A Accumulator 累加器 8 唯一的通用运算寄存器,数据中转站
X Index 变址寄存器 8 循环计数、数组下标
Y Index 变址寄存器 8 第二个变址寄存器,配合间接寻址
S Stack Pointer 栈指针 8 指向硬件栈顶($0100-$01FF)
PC Program Counter 程序计数器 16 下一条指令的地址
P Processor Status 状态寄存器 8 标志位集合(N V - B D I Z C)

累加器 A —— 数据中转站

一切算术/逻辑运算只能在 A 中进行;内存之间不能直接传送数据,必须经过 A:

1
2
3
4
lda $10         ; 内存 → A (取变量)
clc
adc #$05 ; A = A + 5 (在A中运算)
sta $20 ; A → 内存 (存回)

变址寄存器 X / Y —— 计数器与下标

两个独立的 8 位寄存器,三大用途:

1
2
3
4
5
6
7
8
9
10
11
12
; 用途1: 循环计数
ldx #$00 ; X = 0
loop:
inx ; X + 1
cpx #$10 ; 到 16 了吗?
bne loop

; 用途2: 数组下标 (变址寻址)
lda ARRAY,x ; A = ARRAY[X] ← X 就是数组下标

; 用途3: Y 配合间接寻址, 访问任意地址
lda (ptr),y ; A = [指针ptr + Y] 处的值

X/Y 功能基本相同。惯例:X 做数组下标,Y 配合 (zp),Y 寻址。

栈指针 S —— 硬件栈管理员

  • 6502 硬件栈固定在内存 $0100-$01FF(256 字节)
  • S 保存栈顶位置的低字节(高字节恒为 $01)
  • 栈向下增长:压栈 S 减 1,出栈 S 加 1
  • JSR/RTS/PHA/PLA/中断自动操作栈,无需手动管理
  • 开机必须初始化:
1
2
ldx #$FF
txs ; S = $FF → 栈顶 = $01FF (从最高处开始)

程序计数器 PC —— 执行位置跟踪器

  • 16 位寄存器,永远指向”下一条要执行的指令”
  • 顺序执行时自动递增(按指令长度)
  • 所有跳转的本质都是修改 PC:
操作 对 PC 的影响
顺序执行 自动 + 指令长度
JMP $C000 PC ← $C000
JSR / RTS 返回地址入栈 / 出栈
BNE loop 条件成立时 PC ← loop

状态寄存器 P —— 标志位集合

P 的每一位是独立的标志,运算指令自动设置它们,分支指令根据它们决定跳转:

位 标志 名称 置 1 的条件
7 N Negative 负数 结果最高位为 1(负数)
6 V oVerflow 溢出 有符号运算溢出
5 — (未用) 恒为 1
4 B Break BRK 软中断指令
3 D Decimal 十进制 BCD 模式(NES 不用,开机 CLD 清 0)
2 I Interrupt 中断禁止 IRQ 禁用(SEI 置 1 / CLI 清 0)
1 Z Zero 零 结果为 0
0 C Carry 进位 加法进位 / 减法无借位 / 移位移出

条件分支的硬件基础——CMP 比较后看 Z 和 C 标志:

1
2
3
4
5
lda #$05
cmp #$03 ; 计算 5-3 (只设标志): 结果2 → Z=0, C=1
beq equal ; Z=0 → 不相等, 不跳
bcc less ; C=1 → 5>=3, 不跳
; 两个分支都没跳 → 说明 A > 3

指令命名规律

1
2
3
4
5
6
7
动词缩写 + 寄存器/对象

LD = LoaD 读入 ST = STore 写出
T = Transfer 寄存器传送 AD = ADd 加法
SB = SuBtract 减法 CP = ComPare 比较
IN = INcrement 加1 DE = DEcrement 减1
J = Jump 跳转 R = Return 返回

例:LDA = LoaD Accumulator(装入累加器)


2. 数据传送指令

最常用的指令组,占程序中大部分篇幅。

LDA / LDX / LDY — 读入

指令 全称 作用
LDA LoaD Accumulator 累加器 A ← 数据
LDX LoaD X register 变址寄存器 X ← 数据
LDY LoaD Y register 变址寄存器 Y ← 数据
1
2
3
4
5
lda #$0A        ; A = 10          (立即寻址: 数值本身)
lda $10 ; A = 内存$10的值 (零页寻址)
lda $8000 ; A = 内存$8000的值 (绝对寻址)
ldx #$00 ; X = 0
ldy #$20 ; Y = $20

STA / STX / STY — 写出

指令 全称 作用
STA STore Accumulator 内存 ← 累加器 A
STX STore X register 内存 ← 变址寄存器 X
STY STore Y register 内存 ← 变址寄存器 Y
1
2
3
4
sta $10         ; 内存$10 = A
sta $2007 ; PPU数据口 = A (写VRAM)
stx $00 ; 内存$00 = X
sty $01 ; 内存$01 = Y

注意:LDA/STA 没有”立即寻址的 STA”——立即数只能作为源,不能作为目标

TAX / TXA / TAY / TYA — 寄存器间传送

指令 全称 作用
TAX Transfer A to X X ← A
TXA Transfer X to A A ← X
TAY Transfer A to Y Y ← A
TYA Transfer Y to A A ← Y
1
2
lda #$FF
tax ; X = A = $FF

TSX / TXS — 栈指针传送

指令 全称 作用
TSX Transfer S to X X ← 栈指针 S
TXS Transfer X to S 栈指针 S ← X
1
2
ldx #$FF
txs ; 初始化栈指针 = $FF (栈顶$01FF) ← 开机必做

3. 算术运算指令

所有运算都在累加器 A 中进行。

ADC — 带进位加法

ADC = ADd with Carry

1
2
3
clc             ; 清进位 (加法前必做!)
lda #$05
adc #$03 ; A = 5 + 3 + 0 = 8

SBC — 带借位减法

SBC = SuBtract with Carry

1
2
3
sec             ; 置进位 (减法前必做! 6502的借位是反的)
lda #$05
sbc #$03 ; A = 5 - 3 = 2

易错点:6502 减法前要 SEC(不是 CLC),因为 C=1 表示”无借位”

16 位加减法(进位链接高低字节)

1
2
3
4
5
6
7
8
9
10
11
; 16位加法: $0200:$0201 += 1
inc $0200 ; 低字节+1
bne @done ; 低字节没回绕到0 → 完成
inc $0201 ; 低字节回绕了 → 高字节+1 (进位)
@done:

; 16位加法: AX = AX + $0100
clc
adc #$00 ; 低字节相加
tax ; 暂存低字节
lda $01 ; 取高字节... (示意)

INC / DEC — 内存加1/减1

指令 全称 作用
INC INCrement 内存值 +1
DEC DECrement 内存值 -1
1
2
inc $10         ; 内存$10 += 1 (不需要经过累加器!)
dec $0200 ; 内存$0200 -= 1

INX / INY / DEX / DEY — 寄存器加1/减1

指令 全称 作用
INX INcrement X X += 1
INY INcrement Y Y += 1
DEX DEcrement X X -= 1
DEY DEcrement Y Y -= 1
1
2
3
4
5
6
ldx #$00
loop:
; ...处理...
inx ; X += 1
cpx #$10 ; 到16了吗?
bne loop ; 没到继续

4. 逻辑运算指令

按位运算,结果放回累加器。

指令 全称 作用 示例
AND logical AND 按位与 and #$80 取最高位
ORA OR Accumulator 按位或 ora #$01 置最低位
EOR Exclusive OR 按位异或 eor #$FF 全部位取反
1
2
3
4
5
6
7
lda $2002       ; 读PPU状态
and #$80 ; 只保留bit7 (VBlank标志) → A = 0或$80
beq not_vblank ; 结果为0 → 不在VBlank

lda #$0F
ora #$30 ; A = $3F (置位bit4,5)
eor #$FF ; A = $C0 (取反)

BIT — 位测试

BIT = 位测试,测试内存与累加器的公共位,不改变 A。

1
2
3
lda #$80
bit $2002 ; 测试PPU状态的bit7
bpl wait ; N标志 = bit7 → 为0说明不在VBlank

5. 比较与分支指令

CMP / CPX / CPY — 比较

指令 全称 作用
CMP CMPare A A 与操作数比较
CPX ComPare X X 与操作数比较
CPY ComPare Y Y 与操作数比较

比较即做减法(A - 操作数)但不保存结果,只设置标志位:

1
2
3
4
5
lda $10
cmp #$0A ; A 与 10 比较
; A = 10 → Z=1 (相等)
; A < 10 → C=0 (借位)
; A >= 10 → C=1

分支指令(相对跳转,范围 ±127 字节)

指令 全称 跳转条件
BEQ Branch if Equal Z=1(相等/为零)
BNE Branch if Not Equal Z=0(不等/非零)
BCS Branch if Carry Set C=1(≥/无借位)
BCC Branch if Carry Clear C=0(</有借位)
BMI Branch if Minus N=1(负数)
BPL Branch if Plus N=0(正数/零)
BVS Branch if oVerflow Set V=1(溢出)
BVC Branch if oVerflow Clear V=0(无溢出)

比较后的分支组合(最常用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
; if A == 10
cmp #$0A
beq equal

; if A < 10 (无符号)
cmp #$0A
bcc less

; if A >= 10 (无符号)
cmp #$0A
bcs greater_equal

; if A > 10
cmp #$0B
bcs greater

; if 内存$10 != 0
lda $10
bne nonzero

; if X == Y
cpx #$10
beq same

6. 移位指令

对累加器或内存单字节操作。

指令 全称 作用
ASL Arithmetic Shift Left 左移1位,bit0补0,bit7→C
LSR Logical Shift Right 右移1位,bit7补0,bit0→C
ROL ROtate Left 循环左移,C→bit0,bit7→C
ROR ROtate Right 循环右移,C→bit7,bit0→C
1
2
3
4
5
6
lda #$05
asl ; A = $0A (×2)
asl ; A = $14 (×4)

lda #$10
lsr ; A = $08 (÷2)

用途:乘除 2 的幂、逐位检测、乘法算法的核心。


7. 跳转与子程序

指令 全称 作用
JMP JuMP 无条件跳转(绝对地址)
JSR Jump to SubRoutine 调用子程序(返回地址入栈)
RTS ReTurn from Subroutine 子程序返回(地址出栈)
RTI ReTurn from Interrupt 中断返回
1
2
3
4
5
6
7
8
9
main:
jsr init_ppu ; 调用子程序
jsr draw_screen
forever:
jmp forever ; 死循环

init_ppu:
; ...初始化...
rts ; 返回调用处

JSR/RTS 是 6502 的函数调用机制:JSR 把返回地址压入硬件栈,RTS 弹出并跳回。


8. 栈操作指令

6502 硬件栈固定在内存 $0100-$01FF,栈指针 S 从 $FF 递减。

指令 全称 作用
PHA PHush Accumulator A 入栈
PLA PLull Accumulator A 出栈
PHP PHush Processor status 状态寄存器入栈
PLP PLull Processor status 状态寄存器出栈
1
2
3
4
5
; 保存/恢复累加器 (子程序中防止破坏调用者的A)
pha ; 保存A
; ...使用A做别的事...
pla ; 恢复A
rts

注意:6502 栈只能直接操作 A 和标志位,X/Y 不能入栈(需经 TAX→PHA 间接保存)


9. 标志位操作指令

状态寄存器 P 的标志位:Carry、Zero、Interrupt、Decimal、oVerflow、Negative

指令 全称 作用
CLC CLear Carry C=0(加法前)
SEC SEt Carry C=1(减法前)
CLI CLear Interrupt 允许IRQ中断
SEI SEt Interrupt 禁止IRQ中断
CLD CLear Decimal 关闭BCD模式(NES必做)
SED SEt Decimal 开启BCD模式(NES不用)
CLV CLear oVerflow V=0
1
2
3
4
5
; 开机标准初始化
sei ; 禁中断
cld ; 关BCD
ldx #$FF
txs ; 栈指针 = $FF

10. 寻址方式速查

同一指令配合不同寻址方式,是 6502 汇编的核心。

寻址方式 语法示例 含义 速度
立即寻址 lda #$0A 数值 10 本身 快
零页寻址 lda $10 读内存 $0010 最短
零页,X lda $10,x 读内存 $0010+X 快
绝对寻址 lda $8000 读内存 $8000 中
绝对,X lda $8000,x 读内存 $8000+X 慢
绝对,Y lda $8000,y 读内存 $8000+Y 慢
间接索引 lda ($10),y 读”指针$10指向的地址+Y” 慢但灵活
隐含寻址 txs / rts 操作数隐含 最快
相对寻址 bne loop 跳转 ±127 字节内 快
间接寻址 jmp ($1000) 跳到”指针指向的地址” 仅JMP
1
2
3
4
5
6
7
8
9
; 间接索引寻址 —— 遍历数组的利器
lda #<mydata ; 指针低字节
sta $10
lda #>mydata ; 指针高字节
sta $11
ldy #$00
lda ($10),y ; A = mydata[0]
iny
lda ($10),y ; A = mydata[1]

11. 常见组合模式

模式 1:变量赋值(BASIC: A = 10)

1
2
lda #$0A        ; 常量进累加器
sta VAR_A ; 累加器存入变量

模式 2:变量运算(BASIC: A = A + 5)

1
2
3
4
lda VAR_A       ; 取变量
clc ; 清进位
adc #$05 ; +5
sta VAR_A ; 存回

模式 3:循环 256 次

1
2
3
4
5
ldx #$00
loop:
; ...循环体...
inx ; X += 1
bne loop ; X回绕到0前继续 (恰好256次)

模式 4:等待硬件状态(轮询 VBlank)

1
2
3
wait:
bit $2002 ; 读PPU状态
bpl wait ; bit7=0 → 还没到VBlank, 继续

模式 5:数组遍历(零页指针)

1
2
3
4
5
6
7
8
9
10
11
lda #<array
sta $10
lda #>array
sta $11 ; $10:$11 = 数组地址
ldy #$00
loop:
lda ($10),y ; 读 array[Y]
; ...处理...
iny
cpy #$10 ; 处理16个
bne loop

模式 6:16位比较

1
2
3
4
5
6
7
; 比较 $10:$11 与 #$000A
lda $11 ; 先比高字节
cmp #$00
bne done
lda $10 ; 高字节相等 → 比低字节
cmp #$0A
done:

附:完整指令集分类总表

类别 指令
传送 LDA LDX LDY STA STX STY TAX TXA TAY TYA TSX TXS
算术 ADC SBC INC DEC INX INY DEX DEY
逻辑 AND ORA EOR BIT
移位 ASL LSR ROL ROR
比较 CMP CPX CPY
分支 BEQ BNE BCS BCC BMI BPL BVS BVC
跳转 JMP JSR RTS RTI
栈 PHA PLA PHP PLP
标志 CLC SEC CLI SEI CLD SED CLV
其他 NOP BRK

参考:6502 指令集完整参考 · NESdev Wiki