Skip to content

Latest commit

 

History

History
724 lines (569 loc) · 21.5 KB

6502.md

File metadata and controls

724 lines (569 loc) · 21.5 KB

1. 6502

寄存器

  • Accumulator: A
  • Index Register: X , Y
    • 变址寻址中 存放地址偏移量
    • 也常被当作计数器用
    • 还可以作为 通用寄存器 用于暂存数据
  • Stack Pointer: S , 或 SP
    • 系统堆栈区: 1页 , 0x100~0x1FF
    • 初始值为 $ff, 指向 $01ff, 也即栈底;
      • 当有值入栈, 值存入当前SP位置,同时 SP=SP-1, 即为 $fe, 指向$01fe
      • 当有值出栈, SP=SP+1, 指向栈顶, 然后弹出值
      • SP 总是指向一个 空slot
  • Processor Status: P
    • C : Carry 进位, 加法有进位 置1,减法有进位 置0
    • Z : Zero , 1 表示运算结果为0
    • I : Interrupt , 表明是否允许中断 0允许.
    • D : Decimal Mode 十进制运算标志,为1则后续的加/减法运算都是十进制
    • B : indicates that the break operation has been called
    • d5 is unused
    • V : Overflow , 1 表示有溢出
      • 如果把 数据看成 signed 有符号的, 那么当
        1. Positive + Positive = Negative
        2. Negative + Negative = Positive
      • 这两种情况发生时, 会被处理成溢出
      • P+P=P, N+N=N 是正常情况 没有溢出, P+N 则不会出现溢出
      • so V = (A^R) & ~(A^M)
    • N : Negative Flag, 复制 运算结果的最高位到 N
D7 D6 D5 D4 D3 D2 D1 D0
N V B D I Z C
  • PC (16位)
    • 下一条指令的地址

中断和复位

中断

  • NMI : $FFFA $FFFB
    • 用于和PPU通信
    • 使用 2000~2007 8个寄存器,实现对 VRAM,字符发生器,和PPU 内部色彩发生器的控制。
  • IRQ : $FFFE $FFFF
    • 可为用户使用
    • 信号的发出由 CLI 指令控制

复位

  • $FFFC $FFFD
  • 开机后,系统自动执行 $FFFC $FFFD 指定的地址

CPU 管理的内存分布

  • 16根地址线,最大寻址64k
地址区间 用途
$0000 ~ $07FF 2K VRAM,前2页分别系统0页和系统堆栈区,第3页一般作为卡通定义区(可设置)
$0800 ~ $1FFF 6K 空区,VRAM的镜像
$2000 ~ $3FFF 8K, 与PPU相连的I/O区
$4000 ~ $5FFF 8K, CPU的I/O区
$6000 ~ $7FFF 8K, 空区,根据需要扩充为SRAM区
$8000 ~ $FFFF 32K, PROM

PPU 管理的内存分布

  • 14根地址线,最大寻址16k
地址区间 用途
$0000 ~ $0FFF 4K, 图形库第一区,256个卡通tile
$1000 ~ $1FFF 4K, 图形库第二区,256个背景,字符tile
$2000 ~ $23FF 1K, 背景00页屏幕映射区 960+64 , 64=((960/16)+7)&(~7)
$2400 ~ $27FF 1K, 背景10页屏幕映射区 (right to 00)
$2800 ~ $2BFF 1K, 01页
$2C00 ~ $2FFF 1K, 11页
$3000 ~ $3EFF 4K-256, 空区, 背景页的镜像
$3F00 ~ $3FFF 256B, 16B 背景页配色代码定义区 + 16B 卡通页配色代码定义区 + 剩余空区镜像
  • 因为VRAM 只有2K,所以只能操作2个背景页, 另外两个背景页则是 镜像(水平镜像或垂直镜像)
    • 实际上,还有一种 four screen mirroring, 但需要昂贵的硬件支持

PPU 控制寄存器 $2000 ~ $2007

  • 背景显示窗口位置
  • 卡通/背景使用的字模首地址 $0000 或 $1000
  • 卡通大小控制
  • 背景/卡通显示控制
  • 卡通定义页面的首地址
  • 读取 PPU数据
  • $2004 CPU向 PPU卡通页面属性工作区 写数据?
    • $4014 PRAM -> PPU ?

2. 寻址方式

  • 13种寻址方式,56条基本指令
  • 主要特点
    1. 支持0页寻址: CPU可以直接访问 $00~$FF

    2. 指令格式统一

      • 指令长度 1-3字节
      • 第一个字节是 操作码;
      • 紧跟着是 操作数 或 操作数地址, 占1-2个字节
    3. 外设访问简便

      • 与外设之间交换数据 或 信息采集,采用了 存储器映像方式。
      • 凡事用于 访问存储器的指令 都可以用来访问 外设。
    4. 高效的显示方式

      • 对显示的控制 仅通过8个系统软开关 向PPU发布命令。
    5. 简单的发声控制

1 立即寻址

  • op #$nn
    • i.e. LDA #$7F , A9 7F
  • 立即数 为两位16进制数, 00~FF
  • 立即寻址方式的指令长度 均为 2个字节
  • 11 条指令
    • LDA, LDX, LDY
    • ADC, SBC
    • AND, ORA, EOR
    • CMP, CPX, CPY

2 绝对寻址 Absolute Addressing

  • op $n2n1 , op n1 n2
    • i.e. LDA $8000 , AD 00 80
    • ($8000) -> A
  • 绝对寻址指令都是 3字节长度
  • 23 条指令
    • LDA, LDX, LDY
    • STA, STX, STY
    • JMP, JSR
    • INC, DEC
    • ADC, SBC
    • AND, ORA, EOR
    • BIT
    • ASL, LSR, ROL, ROR
    • CMP, CPX, CPY

3 零页寻址

  • 每256个字节为 1页
  • 实际上,存储器的页号 就是存储器的高位地址码
  • op $nn
    • i.e. LDA $7F , A5 7F
    • ($7F) -> A
  • 零页寻址 为2字节指令
  • 21 条指令,
    • LDA, LDX, LDY
    • STA, STX, STY
    • JMP, JSR
    • INC, DEC
    • ADC, SBC
    • AND, ORA, EOR
    • BIT
    • ASL, LSR, ROL, ROR
    • CMP, CPX, CPY

4 隐含寻址 Implied Addressing

  • 操作数 已被 操作码 隐含
  • 单字节指令
  • 隐含寻址 只能在 A,X,Y,S,P 寄存器中进行,不能对存储器 进行操作
  • 25条
    • PHA, PLA
    • PHP, PLP
    • TAX, TXA, TAY, TYA, TXS, TSX
    • INX, INY, DEX, DEY
    • SEC, CLC, SED, CLD, SEI, CLI, CLV
    • RTI, RTS
    • NOP
    • BRK

5. 累加器寻址 Accumulator Addressing

  • 操作数在 累计器A中的 寻址方式
  • i.e. ROR
  • 单字节指令
  • 累加器寻址 也是一种 隐含寻址
  • 4条
    • ASL , LSR , ROL , ROR

6. 绝对X变址寻址 Absolute X-Index Addressing

  • 操作数 的地址由 绝对地址 加上 X寄存器中的数值构成
  • i.e. ( M + X ) -> A
  • 3字节
  • 15条指令,
    • LDA, LDX, LDY
    • STA, STX, STY
    • JMP, JSR
    • INC, DEC
    • ADC, SBC
    • AND, ORA, EOR
    • BIT
    • ASL, LSR, ROL, ROR
    • CMP, CPX, CPY

7. 绝对Y变址寻址 Absolute Y-Index Addressing

  • i.e. ( M + Y ) -> A
  • 3字节
  • 9 条指令
    • LDA, LDX
    • STA
    • ADC, SBC
    • ORA, AND, EOR
    • CMP

8. 零页变址寻址

  • 两种情况
    • Zero page X-indexed addressing
    • Zero page Y-indexed addressing
  • 2字节指令
  • i.e. ( M0 + X ) -> A
  • 只能产生 0页地址,超过 部分舍弃掉
    • 如 当 X=$D8时, LDA $80, X 得到的有效地址是 $58 ( 0xD8 + 0x80 = 0x158)
  • 零页X变址寻址指令 , 16条
    • 对比 绝对X变址寻址 , 多了 STY
  • 零页Y变址寻址指令 , 2条
    • LDX
    • STX

9. 间接寻址 Indirect Addressing

  • 操作数部分 给出的是 实际操作数 所在地址的 地址地位
  • 有效地址的高位 则是 低位单元的下一个单元
  • 三字节指令
  • 只有 1条指令
    • JMP

10. 相对寻址 Relative Addressing

  • 2字节指令, 只适用于 条件转移指令
  • 操作数 为相对地址偏移D, 它实际上就是 无条件转移指令的 跳转步长
    • D有正负
  • 操作数的实际地址 是以 本指令的下一条指令的地址作为 基地址,再加偏移量D
  • 8条指令
    • BNE, BEQ
    • BCC, BCS
    • BPL, BMI
    • BVC, BVS

11. 先变址 间接寻址

  • 双字节指令, 操作数为 0页地址
  • 先以 变址寄存器X变址,然后再进行 间接寻址
    • 实际上是 0页X变址, 和 间接寻址 两种方式的结合
  • 只能使用 X寄存器
  • 8 条指令
    • LDA
    • STA
    • ADC, SBC
    • ORA, AND, EOR
    • CMP

12. 后变址间接寻址

  • 先在0页 间接寻址,获得16位基地址, 然后用Y 变址寻址, 得到操作数的实际存放地址
    • 实际上是 0页间接寻址 和 绝对Y变址 相结合的一种寻址方式
  • 双字节指令,操作数为 0页地址
  • 变址寄存器只能使用Y寄存器
  • 8条指令
    • LDA, STA
    • ADC, SBC
    • ORA, AND, EOR
    • CMP

3. 指令系统

http://www.llx.com/~nparker/a2/opcodes.html

http://c64os.com/post/6502instructions#RTS

https://www.masswerk.at/6502/6502_instruction_set.html

  • 大多数 明确引用内存位置的指令都具有 aaabbbcc 的形式
    • The aaa and cc bits determine the opcode
    • and the bbb bits determine the addressing mode
  • Instructions with cc = 01 are the most regular, aaa bits detemine the opcode as follows
aaa opcode
000 ORA
001 AND
010 EOR
011 ADC
100 STA
101 LDA
110 CMP
111 SBC
  • And the addressing mode (bbb) bits:
bbb addressing mode
000 (zero page,X)
001 zero page
010 #immediate
011 absolute
100 (zero page),Y
101 zero page,X
110 absolute,Y
111 absolute,X
  • Putting it all together:
· ORA AND EOR ADC STA LDA CMP SBC
(zp,X) 01 21 41 61 81 A1 C1 E1
zp 05 25 45 65 85 A5 C5 E5
# 09 29 49 69 · A9 C9 E9
abs 0D 2D 4D 6D 8D AD CD ED
(zp),Y 11 31 51 71 91 B1 D1 F1
zp,X 15 35 55 75 95 B5 D5 F5
abs,Y 19 39 59 79 99 B9 D9 F9
abs,X 1D 3D 5D 7D 9D BD DD FD
  • cc = 10 instructions are completely different set of opcodes:
aaa opcode
000 ASL
001 ROL
010 LSR
011 ROR
100 STX
101 LDX
110 DEC
111 INC
  • The addressing modes are similar to the 01 case, but not quite the same:
    • Note that bbb = 100 and 110 are missing.
    • Also,
      • with STX and LDX, "zero page,X" addressing becomes "zero page,Y"
        • 仅有的两条 zero page,Y
      • and with LDX, "absolute,X" becomes "absolute,Y".
    • 只有 cc = 10 指令有 累加器寻址( 4条 ) ,到现在已经出现了10种寻址方式
bbb addressing mode
000 #immediate
001 zero page
010 accumulator
011 absolute
101 zero page,X
111 absolute,X
  • These fit together like this:
· ASL ROL LSR ROR STX LDX DEC INC
# A2
zp 06 26 46 66 86 A6 C6 E6
A 0A 2A 4A 6A
abs 0E 2E 4E 6E 8E AE CE EE
zp,X/zp,Y 16 36 56 76 96 B6 D6 F6
abs,X/abs,Y 1E 3E 5E 7E BE DE FE
  • Next, the cc = 00 instructions. Again, the opcodes are different:
aaa opcode
001 BIT
010 JMP
011 JMP (indirect)
100 STY
101 LDY
110 CPY
111 CPX
  • The addressing modes are the same as the 10 case, except that accumulator mode (010) is missing.
    • 这里出现一条 唯一的间接寻址指令 JMP indirect, 到现在已经出现了11种寻址方式
    • JMP indirect 跨页寻址有bug,会意外复位
bbb addressing mode
000 #immediate
001 zero page
011 absolute
101 zero page,X
111 absolute,X
  • And here's how they fit together:
· BIT JMP JMP indirect STY LDY CPY CPX
# A0 C0 E0
zp 24 84 A4 C4 E4
abs 2C 4C 6C 8C AC CC EC
zp,X 94 B4
abs,X BC
  • so this is the reason why accumulator mode is missing :

    • if accumulator mode (bbb = 010) were available,
    • "LDY A" would be A8, which falls in the slot occupied by TAY,
    • but the pattern breaks down elsewhere--TYA is 98, rather than 88,
    • which we would expect it to be if it corresponded to the nonexistant "STY A".
  • No instructions have the form aaabbb11.

  • The conditional branch instructions all have the form xxy10000.

    • The flag indicated by xx is compared with y (flag) , and the branch is taken if they are equal.
    • note: cc==00 instruction has no bbb=100 mode, so it can be used for conditional branch
xx flag
00 negative
01 overflow
10 carry
11 zero
  • This gives the following branches:
    • 8条相对寻址指令
BPL BMI BVC BVS BCC BCS BNE BEQ
10 30 50 70 90 B0 D0 F0
  • interrupt and subroutine instructions:
    • (JSR is the only absolute-addressing instruction that doesn't fit the aaabbbcc pattern.)
    • xxx00000, cc = 00 的 立即数寻址 bbb=000 没有使用 000,001,010,011
BRK JSR abs RTI RTS
00 20 40 60

Other single-byte instructions (大部分的隐含寻址指令):

  • xxx01000 , cc = 00 没有 bbb=010 形式
PHP PLP PHA PLA DEY TAY INY INX
08 28 48 68 88 A8 C8 E8
  • xxx11000 , cc = 00 没有 bbb=110 形式
CLC SEC CLI SEI TYA CLV CLD SED
18 38 58 78 98 B8 D8 F8
  • xxx01010 , cc = 10 没有 bbb=010 形式
TXA TXS TAX TSX DEX NOP
8A 9A AA BA CA EA

数据传送类

  1. 立即数/内存单元 数据 送入 寄存器
    • LDA , Load Accumulator
    • LDX , Load index register X
    • LDY , Load index register Y
  2. 寄存器数据 送入 内存单元 (注意:不影响标志寄存器)
    • STY
    • STA
    • STX
  3. 寄存器之间数据传送
    • TAX (AA) , Transfer A to X , A -> X
    • TXA (8A) , X -> A
    • TAY (A8) , A -> Y
    • TYA (98) , Y -> A
    • TXS (9A) , X -> S
    • TSX (BA) , S -> X
  4. 堆栈指令
    • A 内容进出栈 // 隐含寻址开始
      • PHA (48) , PusH Accumulator , A push -> 堆栈
      • PLA (68) , PuLl Accumulator, 堆栈 pop -> A
    • P 内容进出栈
      • PHP (08) , PusH Processor status
      • PLP (28) , PuLl Processor status
  5. 移位指令
    • 算术左移 , Arithmetic Shift Left
      • ASL shifts all bits left one position.
        • 0 is shifted into bit 0 , and the original bit 7 is shifted into the Carry.
      • [C NN]
      • ASL
      • D7 -> C
      • 0 -> D0
      • <=> x * 2
    • 逻辑右移 4E , Logical Shift Right
      • LSR
      • D0 -> C
      • 0 -> D7
      • <=> 无符号数 / 2
    • 循环左移 2E , ROtate Left
      • ROL shifts all bits left one position.
        • The Carry is shifted into bit 0 and the original bit 7 is shifted into the Carry.
      • [ C NN C ]
    • 循环右移动 6E , ROtate Right
      • ROR
      • C -> D7
      • D0 -> C

算术运算类

  1. 带进位加法
    • ADC , ADd with Carry
    • A + M + C -> A
  2. 带进位减法
    • SBC , SuBtract with Carry
    • A - M - C̅ -> A
      • C̅ 是 进位标志的 反码
    • A - M - (1-C) => A+ -M -1+C => A + ~M+1-1 +C => A + ~M + C // something like ADC
  3. 比较指令
    • CMP , 计算 A - XX ,仅改变 标志寄存器 N,Z,C
    • CPX , ComPare with index register X , 计算 X - XX
    • CPY , ComPare with index register Y , 计算 Y - XX
  4. +1 指令
    • INC
    • INX
    • INY
  5. -1 指令
    • DEC
    • DEX
    • DEY
  6. 标志位指令
    • P 进位标志 设置/清除

      • SEC (38) , C = 1
      • CLC (18) , C = 0
    • P 十进制运算标志 设置/清除

      • SED (F8) , D = 1
      • CLD (D8) , D = 0 // 41
      • The Decimal Flag (D) is bit 3 of the Processor Status Register.
        • The NES does not use decimal mode, so the bit is usually set to 0.
        • However, since the opcodes that set and clear the flag are still functional in the NES, you can use this flag to store data.
        • If the NES did support decimal mode, math would be handled differently when the decimal mode flag was set.
          • If an ADC or SBC instruction were executed, the source values would be treated as valid BCD (Binary Coded Decimal,
          • eg. 0x00-0x99 = 0-99) numbers, and the generated result would also be a BCD number.
    • P 溢出标志位 清除

      • CLV (D8) , V = 0

逻辑运算 与 位测试 指令

  1. 逻辑运算指令
    • AND , A & nn -> A
    • ORA , OR with Accumulator , A | nn -> A
    • EOR , Exclusive OR , A ^ nn -> A
  2. 位测试指令
    • BIT
    • M D7 -> N
    • M D6 -> V
    • A & M , Z

程序控制类指令

  1. 无条件转移 ( 不影响标志位 )
    • JMP
    • 跳转到某个地址 继续执行,i.e. 分支语句
  2. 条件转移指令
    • Z标志转移指令
      • BNE 非零转移
      • BEQ 零转移
    • C标志转移指令
      • BCC 无进位转移 , Branch on Carry Clear
      • BCS 有进位转移 , Branch on Carry Set
    • N标志转移指令
      • BPL 非负转移 , Branch on PLus
      • BMI 负转移 , Branch on Minus
    • V标志转移指令
      • BVC 无溢出转移 , Branch on oVerflow Clear
      • BVS 溢出转移, Branch on oVerflow SET // 55
  3. 子程序指令
    • 转子指令 , Jump to SubRoutine ( 不影响标志位 )
      • JSR
      • i.e. function call
      • JSR pushes the address-1 of the next operation on to the stack
        • before transferring program control to the following address.
        • Subroutines are normally terminated by an RTS op code.
    • 返主指令 ,控制子程序返回指令
      • RTS (60) , ReTurn from Subroutine
      • RTS pulls the top two bytes off the stack (low byte first)
        • and transfers program control to that address+1
  4. 中断指令
    • SEI (78) , I = 1
    • CLI (58) , I = 0
      • 当 I=0时,可屏蔽中断允许,6502响应中断后,将转到可屏蔽中断服务子程序执行程序。
      • 记:SEI 告诉NES我正在处理中断,在我处理完之前,不响应其他可屏蔽中断
    • 中断返回指令 RTI (40) , ReTurn from Interrupt
      • 控制中断处理程序返回, 恢复中断处理前的线场。
      • 当 6502响应中断后,将把 断点地址和标志寄存器P的内容压栈保存, 然后转到服务程序执行。
      • 当 中断服务程序执行完毕后,将通过RTI指令返回,从堆栈弹出断点地址和P, 恢复中断前的现场,继续执行主程序
  5. 空操作
    • NOP (EA)
    • 编程中,一般使用 空操作指令 控制延时 // 47

其他 ?

  • BRK
    • BRK causes a non-maskable interrupt and increments the program counter by one. Therefore an RTI will go to the address of the BRK +2 so that BRK may be used to replace a two-byte instruction for debugging and the subsequent RTI will be correct.

undocumented instruction

  • 00,01,10 系列的空指令, 只有4种寻址方式
    1. 001 : zero page
    2. 011 : absolute
    3. 111 : absolute,X
    4. 000 : 只有 00,10 系列指令有
  • 11 系列的空指令, 没有 bbb == 010 的情况