使用C++实现FC红白机模拟器 Cartridge 与 Mapper(原理篇)
1. 认识nes文件
我们既然是模拟,就不可能使用实体的卡带硬件。那我们如何获取游戏文件呢?好在已经有人为我们准备好了(心怀感恩)。
.nes文件是NES(FC)的rom文件,关于它的来龙去脉这里就不做详细介绍了(我也不知道)。.nes有1.0和2.0之分,简单起见 这里只考虑1.0。
NES文件由 Header、Trainer、PRG ROM、CHR ROM 4个部分组成。
- Header 大小:16字节,用于ROM文件的校验,记录PRG和CHR大小等作用。
- Trainer,这个区域很多时候并不存在,也基本不影响运行。因此我们忽略此部分。
- PRG ROM 是程序的可执行部分,也就是程序的“代码部分”。将来CPU就是读取这个区域的内容,再执行。PRG ROM由若干个16KB的“块”组成,块的数量在Header中记录。通常至少有1个PRG ROM。
- CHR ROM 是ROM的图像数据,将来PPU会读取这部分的内容,并拼合成最终可显示的图像数据。这部分同样是由若干块组成,只是块的大小为8KB。块的数量在Header中记录。数量可能为0。
rom文件具体分布:
2. Mapper与内存映射
2.1 内存映射
在弄清楚什么是mapper之前,我们先来看看什么是内存映射。FC的CPU是8BIT处理器,但是地址总线却是16BIT的,这就意味着CPU的寻址范围是0x0000~0xFFFF,也就是最大能寻址64KB。尽管64KB已经非常小了,但是在那个年代,即便是64KB的内存也十分昂贵。FC内实际可自由使用的内存仅为2KB,而多余的地址空间就分别映射到了不同的外设上面。(有单片机经验或者操作系统底层开发经验的朋友应该很熟悉这种做法)。
FC内部的两个重要部件CPU和PPU都有自己独立的地址总线,因此CPU和PPU分别有不同的内存映射方案。
地址范围 | 大小 | 所映射的设备 |
---|---|---|
0x0000-0x07FF | 2 KB | 内置的2KB内存 |
0x0800-0x1FFF | 6 KB | 0x0000-0x07FF的镜像 |
0x2000-0x2007 | 8 byte | PPU寄存器 |
0x2008-0x3FFF | 0x2000-0x2007的镜像 | |
0x4000-0x4017 | APU和I/O寄存器 | |
0x4018-0x401F | 暂时忽略 | |
0x4020-0x5FFF | 暂时忽略 | |
0x6000-0x7FFF | 8 KB | PRG RAM |
0x8000-0xBFFF | 16KB | 带空间前16KB PRG ROM |
0xC000-0xFFFF | 16KB | 带空间后16KB PRG ROM |
从上图可以看到0x8000~0xFFFF的地址空间被映射到了PRG ROM,因此CPU读取0x8000~0xFFFF的时候实际上访问的就是rom中的PRG ROM内容。这块空间总计32KB,而当ROM中只有1个PRG ROM时,大小仅为16KB。这个时候0xC000~0xFFFF的地址空间就是0x8000-0xBFFF的镜像。
Pattern Tables | 0x0000-0x0FFF | Pattern Table 0 |
0x1000-0x1FFF | Pattern Table 1 | |
Name Tables | 0x2000-0x23BF | Name Table 0 |
0x23C0-0x23FF | Attribute Table 0 | |
0x2400-0x27BF | Name Table 1 | |
0x27C0-0x27FF | Attribute Table 1 | |
0x2800-0x2BBF | Name Table 2 | |
0x2BC0-0x2BFF | Attribute Table 2 | |
0x2C00-0x2FBF | Name Table 3 | |
0x2FC0-0x2FFF | Attribute Table 3 | |
Palettes | 0x3F00-0x3F0F | Image Palette |
0x3F10-0x3F1F | Sprite Palette | |
0x0000 - 0x3FFF的镜像 | 0x0000 - 0x3FFF的镜像 |
PPU的内存映射主要分为图样表(Pattern Tables)、命名表(Name Tables)和调色板(Palettes)。其中 图样表分为两个小区块,每个4KB,总共8K。实际上就是ROM中CHR ROM的内容。
总结下来,CPU的地址空间0x8000~0xFFFF因映射到了PRG ROM ,而PPU的地址空间0x0000-0x1FFF则映射到了CHR ROM。因此我们在稍后的实现代码中,需要预留出相关接口。
您也许会疑惑为什么内存映射表还有那么多部分没有讲到?这个不用担心,我们再讲到CPU和PPU章节的时候,会更为详细的介绍。而我们现在不需要关心这些。
2.2 那什么是Mapper?
我们通过前面的小节已经了解到了什么是地址映射,但是我们也知道,映射到PRG ROM的地址空间大小只有32KB,映射到CHR ROM的则更小,仅为8KB。很多游戏想要实现比较复杂多样的显示效果这远远不够。那怎么办呢?厂商在开发卡带的会把PRG ROM和CHR ROM分成不同大小的空间区块(BANK)。
例如:
某块游戏以16KB区块为大小划分PRG ROM,一共10个。那就是160KB的程序空间! 但是地址空间只有32KB啊?Mapper的作用就出现了。他可以控制地址空间到底映射到那个BANK,然后程序可以通过读写特定的地址切换。比如我默认将第0和1 BANK映射到0x8000-0xFFFF。运行过程中再切换为第5、6 BANK映射到0x8000-0xFFFF。这样就能在有限的地址空间内实现了存储空间的扩容。而且这部分由游戏卡带实现,因此成本不必计算在游戏机本体内。
不过官方(nes1.0)支持256种不同的Mapper,不同的Mapper映射方法和区块划分都不同,有的还支持中断甚至额外的”声卡“。我们一开始就实现这些太复杂了。因此我们只实现基本的Mapper功能用来测试。后面Mapper进阶我们再实现更高级的功能。
(未完待续)
小贴士:
因为本章较长,因此分了“原理”和“实现”两部分。实现部分在下次更新哦~
使用C++实现FC红白机模拟器 Cartridge 与 Mapper(原理篇)相关推荐
- 使用C++实现FC红白机模拟器 Cartridge 与 Mapper(实现篇)
(继上篇:原理篇,下:实现篇) 2. Cartridge 与 Mapper的实现 首先我们在QT中创建两个类,Cartridge 与 Mapper类: Cartridge 类负责加载和解析ROM,因为 ...
- fc安卓模拟器_安利一款手机上的红白机模拟器
戳上面的蓝字关注我哦! 使用平台:安卓 软件简介: NES.emu是一款任天堂红白机(NES.FC)模拟器,软件支持横竖屏.自动保存游戏进度.按键自定义等功能,还可以自行编辑作弊文件,小编为大家带来的 ...
- 撸一个VS Code插件——红白机模拟器 支持手柄 支持保存
分享我自己写的VS Code红白机模拟器 前言 我曾经利用 jense 这个库封装了一个vue组件的nes模拟器:nes-vue: Vue 3 的NES(FC)模拟器组件 (gitee.com),最近 ...
- 小霸王其乐无穷~FC红白机游戏600合集(支持mac 12.x系统)
FC游戏是任天堂红白机一FC(Family Computer),代表作品主要有<魂斗罗系列>.<93超级魂>.<沙罗曼蛇系列>.<超级玛丽>.<赤 ...
- 计算机丢失fc64,FC红白机64合1
软件简介 Soft Introduction FC红白机64合1 64in1.nes 01Islander冒险岛1 02Grading沙罗曼蛇1 03Star Soldier星际战士 04Goonie ...
- 【转】FC(红白机)游戏nes文件的汉化技术
FC大字体汉化方法 作者:madcell 一.前言: 本文以FC上第一个发售的游戏<大金刚>为例,介绍如何对标题画面进行大字体汉化. 阅读本文,必须具备一定的的条件,否则看了也是不知所云. ...
- ADI Blackfin DSP处理器-BF533的开发详解70:NES 红白机模拟器(含源码)
硬件准备 ADSP-EDU-BF533:BF533开发板 AD-HP530ICE:ADI DSP仿真器 软件准备 Visual DSP++软件 硬件链接 代码实现功能 代码实现了 NES 游戏模拟器在 ...
- nes 红白机模拟器 第6篇 声音支持
InfoNES 源码中并没有包含 linux 的声音支持. 但提供 wince 和 win 的工程,文件,通过分析,win 的 DirectSound 发声,在使用 linux ALSA 实现. 先使 ...
- linux终端玩fc游戏,在UBuntu下玩FC和街机模拟器
我不是太爱玩游戏,所以Linux下我并没有特别关心游戏的问题.不过有一天,突然觉得想起以前在Windows下玩过的VirtualNES FC(红白机)模拟器和Nebula街机模拟器了.也许是怀旧的缘故 ...
最新文章
- 2019 数据竞赛年鉴联合发布!250页竞赛方案合集
- android网络请求流程图,Android OKHttp系列1-流程总结
- Maximum Element In A Stack 数据结构
- 环境复制_PostgreSQL热备之流复制环境搭建以及常见问题处理
- http 长连接 短连接
- ocx控件 postmessage消息会消失_实战经验:如何检测CMFCTabCtrl控件标签页切换事件...
- Spring AOP中declare-parents为特定的类增加新的功能
- BZOJ1925 [Sdoi2010]地精部落 【dp】
- 中国双氢青蒿素市场趋势报告、技术动态创新及市场预测
- 面向对象编程已死,OOP 永存!
- AutoMapper,对象映射的简单使用
- 误删libcrypto.so.1.0.0
- Intel HD Graphics
- 计算机无法使用64位itunes,电脑itunes读iphone不了的解决方法
- matlab模拟化学反应,Matlab环境下化学反应动力学的MonteCarlo模拟
- sql—labs通关
- 王者转区显示服务器列表错误,王者荣耀转区功能-王者转区服务-王者转移号-王者转服...
- ITK入门教程(11)点集之创建一个点集
- 简单解决高分屏模糊问题
- 有了它,你的照片能“屏蔽”人脸识别算法
热门文章
- 重装战姬服务器维护,重装战姬2020年10月1日更新维护公告_重装战姬2020年10月1日更新了什么_玩游戏网...
- java牛奶订购系统,Java IO系统
- 微信支付的软件架构究竟有多牛逼...
- 学习笔记-应用光学 第一章 几何光学的基本定律
- SpringBoot 自动装配原理解析
- MQTT-Eclipse paho mqtt重连机制
- 光学瞄准镜测距之数学原理
- Matlab中sim函数的用法
- win10系统没有切换用户功能怎么办
- 数据建模 Database Modeling:概念 (Conceptual) vs 逻辑 (Logical) vs 物理数据 (Physical) 模型