最近瀏覽了github,找到了比較有意思的一些開源項目,也想著使用C++寫一個紅白機的模擬器。說干就干吧,在這里記錄一下相應(yīng)的準備工作。
一些基本概念
首先是一些術(shù)語的含義,如下表所示。
其次,一些需要注意的地方:
- CPU和PPU分別擁有16位(64KB)的地址空間;
- RAM和ROM位于同一個16位地址空間內(nèi),CPU和PPU通過指定地址讀取相應(yīng)數(shù)據(jù),(和計算機中的虛擬內(nèi)存層次存儲結(jié)構(gòu)不太一樣);
- RAM的地址空間為13位(0x0000~0x1FFF, 8KB),但實際上只有11位(0x0000~0x07FF, 2KB)是真實用到的,所以會有CPU地址空間分布中的"RAM鏡像的概念",其實就是把原來13位中的高2位抹去,歸根結(jié)底就是為了省錢,同時把地址空間給覆蓋滿;
- PPU中的鏡像:PPU的地址空間中,任何超過0x4000的地址,也都被抹去高位,使得實際上尋址范圍在0x0000~0x3FFFF,可見,鏡像在NES中是廣泛應(yīng)用的;
CPU地址空間分布
nes的CPU地址空間分布如下表所示,這對于后續(xù)編寫CPU讀取數(shù)據(jù)的函數(shù),是至關(guān)重要的。
| 起始地址 | 字節(jié)大小 | 具體類型 |
|---|---|---|
| 0x0000 | 0x800 | RAM |
| 0x0800 | 0x800 | RAM映像 |
| 0x1000 | 0x800 | RAM映像 |
| 0x1800 | 0x800 | RAM映像 |
| 0x2000 | 0x8 | Register |
| 0x2008 | 0x1FF8 | PPU Register |
| 0x4000 | 0x20 | Register |
| 0x4020 | 0x1FDF | 擴展ROM |
| 0x6000 | 0x2000 | SRAM(用電池供電的額外RAM,卡帶提供) |
| 0x8000 | 0x4000 | PRG-ROM |
| 0xC000 | 0x4000 | PRG-ROM |
PPU的渲染模式
nes圖形種有一個palette的概念,具體是什么不用細講,我們只需要知道,每個像素點需要4bits的信息來告知是哪一個palette即可,用以顯示對應(yīng)的顏色。PPU使用Name Table和Pattern Table以及Attribute Table來指示顏色信息,如圖所示(寫的很亂...估計除了自己,也沒人看得懂了)。簡單來說,游戲的每一幀有個Tile,所謂Tile,就是
個像素點構(gòu)成的一個小方塊。然后,程序通過幾個Table來指定小方塊的顏色(也就是降低精度來節(jié)省空間了)。
Tile有960個,而單個NameTable剛好也是960Bytes構(gòu)成,和Tile一一對應(yīng)。Pattren Tables總共有8KBytes的空間,分為,分別給Background和Sprite使用。4KBytes以16Bytes為單位,劃分為256個單位。而Nametable中的每個Bytes剛好作為Pattern Tables中單位的索引。單位用以指示Palette偏移的低2位,高兩位由Attribute Table指示。后面也懶得寫了。。。如果到這里能讀懂的話,圖也就能看懂了,看圖吧。。。

PPU.jpg
NES文件格式
查閱了相關(guān)的資料,nes文件的文件格式如下,供后面參考。
| 字節(jié)范圍 | 字節(jié)數(shù) | 具體內(nèi)容 |
|---|---|---|
| 0~3 | 4 | 字符串"NES^Z" (^Z表示EOF) |
| 4 | 1 | 16KB ROM的數(shù)目 |
| 5 | 1 | 8KB VROM的數(shù)量 |
| 6 | 1 | D0:1=垂直鏡像,0=水平鏡像,即游戲的板式為橫斑還是豎版(D0表示該字節(jié)的LSB,下面類推) |
| D1:1=有電池記憶,SRAM地址0x6000-0x7FFF | ||
| D2:1=在0x7000-0x71FF有一個512字節(jié)的Trainer | ||
| D3:1=4屏幕VRAM布局 | ||
| D4-D7:ROM Mapper的低4位 | ||
| 7 | 1 | D0-D3:保留,必須是0(準備作為副Mapper號) |
| D4-D7:ROM Mapper的高4位 | ||
| 8~F | 8 | 保留,必須是0 |
| 16~ | 16KB |
ROM段升序排列,若存在trainer,則其512字節(jié)擺在ROM之前 |
| ~EOF | 8KB |
VROM段, 升序排列 |
工作流程
- 讀取nes文件,將對應(yīng)的ROM,VROM等數(shù)據(jù)讀取至內(nèi)存中(可以直接用vector來存儲),以及mapper的建立;
- 實際運行游戲之前,先要進行reset,將CPU和PPU中的寄存器、標志位等部件恢復(fù)至默認值;
未完待續(xù)...