NES红白机学习笔记

计划

  1. 模拟6502、总线和内存RAM,CPU能够从内存读写数据和获取指令
  2. 参考CPU的数据手册,能够对指令进行解析
  3. 解析卡带Cartidge的文件格式
  4. 实现Mapper功能
  5. 构建PPU模块,能够调用SFML输出画面
  6. 增加按键控制功能

CPU-6502

2A03简介

2A03是Ricoh(理光集团)基于6502制造的NMOS处理器。

小端字节处理器。

CPU内存分布

下图展示处理器如何使用总线访问内存。内存分为三个区域:卡带中的ROM、处理器RAM、I/O寄存器。8位控制总线负责通知组件请求是读还是写。8位数据总线用于读写字节。16位地址总线用于选择目标组件。请注意,ROM是只读的,需要通过MMC访问,以便切换bank。I/O寄存器用于和系统其他组件通信,比如PPU和控制器。

image-20230917160740959

16位地址总线可以访问64KB内存地址$0000-$FFFF。具体的分布见下图。RAM区域$0000-$2000,I/O寄存器区域$2000-$4020,扩展ROM区域$4020-$6000,SRAM区域$6000-$8000,程序ROM区域$8000-$10000

零页是指地址范围$0000-$00FF,在特定模式下允许更快的执行。内存地址$0000-$00FF会被镜像三次到$0800-$2000。比如,任何写到$0000的数据也会写到$0800$1000$1800

位置$2000-$2007每8字节会被镜像到$2008-$3FFF,剩余的寄存器都遵循这个镜像。

SRAM(WRAM)是存储内存,这个地址用于访问记忆游戏Cartridges卡带中的RAM。

$8000开始的地址是分配给Cartridges卡带的PRG-ROM。游戏只有一个16KB数据区(bank)的,会被加载到$8000$C000。游戏有两个16KB数据区的,将一个加载到$8000,另一个加载到$C000。游戏拥有超过两个16KB数据区的,使用内存映射器决定哪个数据区加载到内存。内存映射器会监视特定地址(或地址范围)的内存写入,当地址被写入时,它会执行数据区切换。详见附录D。

image-20230917165157967

寄存器

Program Counter (PC)

16位寄存器;

Stack Pointer (SP)

8位寄存器;固定偏移$0100;位置$0100-$01FF;自顶向下增长;不会检测越界;

Accumulator (A)

8位寄存器;从内存取值;

Index Register X (X)

8位寄存器;从内存取值;地址偏移值;读写SP寄存器;

Index Register Y (Y)

8位寄存器;从内存取值;地址偏移值;

Processor Status (P)

image-20230917211324567
  • Carry Flag (C) 上个指令结果越界标记;指令SEC/CLC,设置为1/0;
  • Zero Flag (Z) 上个指令结果为零标记;
  • Interrupt Disable (I) 中断禁用标记;指令SEI/CLI,设置为1/0;
  • Decimal Mode (D) BCD十进制模式,会被忽略;指令SED/CLD,设置为1/0;
  • Break Command (B) 指明BRK指令,会引发IRQ;
  • Overflow Flag (V) 溢出标记;
  • Negative Flag (N) 符号位;0为正,1为负;

中断

NES有三种类型的中断:NMI、IRQ、复位,中断向量表存储在$FFFA-$FFFF

发生中断时,需要进行如下步骤:

  1. 识别中断;
  2. 完成当前指令执行;
  3. PC和P寄存器压栈;
  4. 设置中断禁用位;
  5. 读取中断向量表处理函数赋值给PC;
  6. 执行处理函数;
  7. 执行RTI指令,恢复P和PC寄存器;
  8. 继续执行程序;

中断或可屏蔽中断,是由某些内存映射器生成的。

IRQ可以由软件使用BRK指令触发。当发生IRQ时,系统跳到$FFFE$FFFF所指地址。

NMI(不可屏蔽中断)是当V-Blank出现在每个帧的末尾时,PPU产生的中断类型。它不受中断禁用寄存器影响,所以它发生时,程序总是被中断。当PPU控制寄存器1($2000)被清空时,会阻止NMI的触发。当发生NMI时,系统跳到$FFFA$FFFB所指地址。

复位中断在系统第一次启动和用户按下复位按钮时触发。当发生复位时,系统跳到$FFFC$FFFD所指地址。

中断优先级为复位、NMI和IRQ。NES有7个周期的中断延时,即它会花费7个CPU周期来开始执行中断处理。

寻址模式

在6502上总共有13种不同的寻址模式。详见附录E。

指令

6502有56条不同的指令,尽管有些指令有多种,使用不同的寻址模式,使得在可能得256个操作码中总计151个有效。指令可以是1、2或3字节长,根据它们的寻址模式。第一个字节为操作码,其他字节为操作数。指令可以分为几个功能组:

  • 加载/存储操作
  • 寄存器传输操作
  • 栈操作
  • 逻辑操作
  • 算术操作
  • 递增/递减
  • 移位
  • 跳转/调用
  • 分支
  • 状态寄存器操作
  • 系统函数

PPU-2C02

内存分布

image-20230923162104444

图案表

英文名PatternTable,卡带CHR-ROM映射到此处,也可能是RAM。游戏中使用的一个图案被称为Tile,背景或精灵都是由若干个Tile组成。

image-20230924191909278

每个Tile大小为8x8像素,游戏屏幕大小为256x240像素,由32x30个Tile组成。

一个图案表占用大小4KB,总共有两个占用8KB。对于许多游戏拥有超过两个图案表,需要使用Mapper来控制映射。

简单计算:

一个PatternTable大小4KB,由256个Tile组成。每个Tile大小为4KB/256=16B。一个Tile大小8x8=64像素,每个像素占用16B/64=2bit。

参考

《Nintendo Entertainment System Documentation Version 1.0.pdf》

《任天堂产品系统文件.chm》

“玩”明白计算机底层系列-计组-红白机模拟器 - 知乎 (zhihu.com)

NES专题_金小庭的博客-CSDN博客