NES 硬件組成
NES 有以下硬件
CPU
想必它的作用不用介紹了。它的型號(hào)是 2A03,8bit审残,工作頻率 1.7897725 MHz梭域。它有 16bit 地址總線斑举,所以它的尋址范圍為 0x0000 - 0xFFFF搅轿,即 64KB。CPU 支持三種中斷:RESET(復(fù)位)富玷,NMI(不可屏蔽中斷)璧坟,IRQ(可屏蔽中斷)APU(Audio Processing Unit)
APU 集成在了 2A03 里面,用于聲音的產(chǎn)生和輸出赎懦,所以它沒有專門的芯片雀鹃。它有 5 個(gè)通道,可以產(chǎn)生方波励两,三角波黎茎,噪聲,PCM(你問為什么 4 種波形占了 5 個(gè)通道当悔?因?yàn)橛?2 個(gè)通道可以用于產(chǎn)生方波)傅瞻。-
PPU(Picture Processing Unit)
PPU 型號(hào)為 2C02,用于產(chǎn)生圖像盲憎。NES 中圖像分兩種- Background(背景)
顧名思義嗅骄,用于背景的顯示,比如游戲的天空饼疙,草地溺森,建筑 - Sprite(精靈)
用于前景的顯示,例如游戲里的人物窑眯,子彈等
最終上述兩種圖像組合后屏积,輸出到屏幕
- Background(背景)
-
Cartridge(卡帶)/ Mapper
這是我們最熟悉的硬件了,就是這個(gè):
image.png
卡帶中包含了 NES 程序和圖像的信息磅甩,所以不同游戲就會(huì)生產(chǎn)不同的卡帶肾请,CPU 和 PPU 都能直接訪問卡帶讀取內(nèi)容,至于讀取的時(shí)候返回什么樣的數(shù)據(jù)更胖,這就是 Mapper 需要做的事情铛铁。有的 Mapper 擴(kuò)大了程序的容量,有的 Mapper 植入了額外的芯片提升音頻等等却妨。饵逐。。 -
RAM(內(nèi)存)
NES 主機(jī)中一共有 2 個(gè) 2KB RAM彪标,一個(gè)給 CPU 用倍权,另一個(gè)給 PPU 用
NES 卡帶中可能不帶任何 RAM,也可能帶 8KB 的額外用于 CPU 的 RAM(也就是我們常見的帶了紐扣電池的卡帶),甚至還有的卡帶還帶了 2KB 的額外用于 PPU 用的 VRAM- 主機(jī)中 2KB RAM
用于游戲運(yùn)行數(shù)據(jù)存儲(chǔ) - 主機(jī)中 2KB VRAM(Video RAM)
看名字就知道它干嘛了薄声,該 RAM 用于顯示數(shù)據(jù)的存儲(chǔ)当船,CPU 將要顯示的數(shù)據(jù)寫入 VRAM,然后 PPU 會(huì)讀取這里面的數(shù)據(jù)解碼后輸出到屏幕 - 卡帶上 8KB RAM
用于游戲額外的數(shù)據(jù)存儲(chǔ)默辨,最重要的是它能夠保存游戲存檔德频。這也說明了為什么我們拔了卡帶上的電池后存檔就沒了 - 卡帶上 2KB VRAM
PPU 工作在 4-Screen 的時(shí)候才會(huì)用到,現(xiàn)在不需要了解它
- 主機(jī)中 2KB RAM
NES 總線
這里有一張?jiān)韴D:
圖中左上為 CPU缩幸,左下為 PPU壹置,右上為卡槽
能夠觀察到圖中有兩條粗的藍(lán)色的線,一個(gè)在上方表谊,一個(gè)在下方
- 上方的藍(lán)線
這是 CPU 的地址總線钞护,它有 16bit,尋址范圍 0x0000 - 0xFFFF - 下方的藍(lán)線
這是 PPU 的地址總線爆办,它有 14bit难咕,尋址范圍 0x0000 - 0x3FFF
總結(jié)下來,我們知道了 NES 有 CPU 和 PPU 兩類總線距辆,他們分別有自己的尋址空間余佃。由于卡帶上既有圖像數(shù)據(jù)又有程序數(shù)據(jù),所以卡帶同時(shí)接入了兩根總線
NES 內(nèi)存映射
了解了 NES 有兩條總線之后挑格,我們需要關(guān)注 NES 的內(nèi)存映射咙冗,也就是總線上哪些地址對(duì)應(yīng)了哪些數(shù)據(jù)
1. CPU 內(nèi)存映射
-
0x0000 - 0x0800 ( RAM )
這是主機(jī)中 2KB RAM 的數(shù)據(jù),分成了 3 塊-
0x0000 - 0x00FF ( Zero page )
前 256 字節(jié)劃分為 Zero page漂彤,這塊內(nèi)存相比其他區(qū)域不同點(diǎn)在于能讓 CPU 以更快的速度訪問雾消,所以需要頻繁讀寫的數(shù)據(jù)會(huì)優(yōu)先放入此區(qū)域 -
0x0100 - 0x01FF ( Stack )
這一塊區(qū)域用于棧數(shù)據(jù)的存儲(chǔ),SP(棧指針) 從 0x1FF 處向下增長(zhǎng) -
0x0200 - 0x07FF ( 剩余 RAM )
這是 2KB 被 Zero page 和 Sack 瓜分后剩余的區(qū)域
-
0x0000 - 0x00FF ( Zero page )
0x0800 - 0x2000 ( Mirrors )
你可能會(huì)感覺到奇怪這個(gè) Mirror 到底是干什么的挫望。實(shí)際上它是 0x0000 - 0x07FF 數(shù)據(jù)的鏡像立润,總共重復(fù) 3 次
例如:0x0001, 0x0801, 0x1001, 0x1801 都指向了同樣的數(shù)據(jù),用程序來解釋的話媳板,就是:
address &= 0x07FF
對(duì)應(yīng)到硬件上的話桑腮,就是 bit11 - 13 的線不接
至于為什么任天堂要這樣設(shè)計(jì)?我猜可能是考慮到成本原因蛉幸,2KB RAM 夠用了破讨,不需要更大的 RAM,但是地址空間得用完啊奕纫,所以才有了 Mirror 效果0x2000 - 0x401F ( IO Registers )
這里包含了部分外設(shè)的數(shù)據(jù)提陶,包括 PPU,APU匹层,輸入設(shè)備的寄存器隙笆。比如 CPU 如果想讀寫 VRAM 的數(shù)據(jù),就得靠 PPU 寄存器作為中介0x4020 - 0x5FFF ( Expansion ROM )
Nesdev 的論壇上有篇解釋這塊區(qū)域的帖子,簡(jiǎn)單來講撑柔,該區(qū)域用于一些 Mapper 擴(kuò)展用瘸爽,大部分情況用不到0x6000 - 0x7FFF ( SRAM )
這就是之前說過的帶電池的 RAM 了,該區(qū)域位于卡帶上0x8000 - 0xFFFF ( Program ROM )
這里對(duì)應(yīng)了程序的數(shù)據(jù)铅忿,一般 CPU 就在這塊區(qū)域中執(zhí)行指令剪决,該區(qū)域位于卡帶上
2. PPU 內(nèi)存映射
這個(gè)圖簡(jiǎn)單看看就好了,后面介紹 PPU 的時(shí)候再詳細(xì)看看
0x0000 - 0x1FFF ( Pattern Tables )
這里存放了 8KB 的圖像數(shù)據(jù)辆沦,該區(qū)域位于卡帶上昼捍,由 Mapper 管理著识虚。它的作用是用來 PPU 渲染圖像的時(shí)候作為參考肢扯。有的游戲里面這塊區(qū)域是 RAM,由 CPU 寫入圖像數(shù)據(jù)0x2000 - 0x2FFF ( Name Tables )
這里一共 4KB 數(shù)據(jù)担锤,其中 2KB 為主機(jī) VRAM蔚晨,另外 2KB 根據(jù)游戲配置為前 2KB 的 Mirror 或者卡帶上的 VRAM。這里面存放著 Pattern Table 的偏移量肛循,以此控制屏幕顯示的內(nèi)容铭腕,具體在后面的 PPU 章節(jié)討論0x3000 - 0x3EFF ( Mirrors )
同 CPU 的 Mirror 一樣0x3F00 - 0x3F1F ( Palettes )
這里是 NES 調(diào)色板數(shù)據(jù),用于控制圖像上每個(gè)像素的顏色多糠,具體在后面的 PPU 章節(jié)討論0x3F20 - 0x3FFF ( Mirrors )
同 CPU 的 Mirror 一樣
NES 游戲運(yùn)行大致流程
了解了各個(gè)硬件作用和內(nèi)存映射后累舷,下面可以來探討 NES 游戲運(yùn)行時(shí)的流程了,其實(shí)只是很簡(jiǎn)單的循環(huán):
首先系統(tǒng)上電或者 RESET 按鈕按下后夹孔,會(huì)觸發(fā) RESET 中斷被盈,CPU 從 0xFFFA 和 0xFFFB 存儲(chǔ)的地址處(2byte)開始取指令運(yùn)行(具體在 CPU 章節(jié)討論),之后 CPU 會(huì)一直運(yùn)行 0x8000 - 0xFFF9 區(qū)間的指令搭伤。在每一幀渲染之前只怎,CPU 會(huì)讀取輸入設(shè)備,然后通過 PPU 寄存器往 PPU 總線上的 VRAM 寫數(shù)據(jù)怜俐,同時(shí)往 APU 寫數(shù)據(jù)身堡,最終反饋到了屏幕和聲音上