1披坏、系統(tǒng)簡介
任天堂主機由6502處理器和一個特制的圖形處理器組成。CPU是6502脚乡,而不是傳言中的65C02(CMOS)替劈。PPU的顯存是和CPU的內(nèi)存是分離的寄雀,可以通過對特殊端口的讀/寫來操作≡上祝卡帶可能包含的內(nèi)容有位于處理器地址FFFF的ROM盒犹,和位于PPU地址
1FFF的 VROM。由于NES只有2K的RAM眨业,因此變量的可用的變量空間只有從
07FF共8個頁面急膀。在開機之后RAM和VRAM中的內(nèi)容是0,但是注意:復(fù)位并不改變其中的內(nèi)容龄捡。在更小的卡帶卓嫂,比如只有16KB的ROM,它占有
FFFF聘殖,而
BFFF的空間是不用的晨雳。那些大于32KB的卡帶行瑞,它被特殊的電路分頁到一定的地址空間。一些卡帶在
7FFF有SRAM餐禁,那是電池存儲的位置血久。卡帶VROM被用來做圖案表(例如 Tile 表, 角色發(fā)生器等等)帮非。通常的數(shù)量是8KB氧吐,包含兩個圖案表。大于8KB 的VROM被特殊的電路分頁到一定的地址空間喜鼓。內(nèi)部的VRAM在 PPU 內(nèi)存里定位于
3FFF,它用來存儲命名表(例如屏幕緩沖)衔肢。雖然PPU 支持4個命名表庄岖,但只能支持兩個的存放空間。另外的兩個是開始兩個的鏡像角骤。NES共有154條指令隅忿。
在本文本里,你將遇到如下形式的符號:“Dn" (5 位邦尊,3 位背桐,等等)。位是按從最低位(0 位)到最高位(7 位)蝉揍。所有的十六進制都在前面加上一個美圓符號(2002,$4026,等等)是在6502處理器匯編里常用的符號,二進制前面加上一個百分號%链峭。
2、縮寫表
NES | 任天堂娛樂系統(tǒng) |
---|---|
Famicom | 任天堂家用計算機又沾,即FC |
FDS | 任天堂磁碟機系統(tǒng) |
CPU | 中央處理器弊仪,NES使用一個定制的6502(NMOS)芯片,有些型號為6527 |
PPU | 圖像處理器杖刷,用來處理背景励饵,精靈和其他圖像特性,通常為6538 |
APU | 聲音處理器滑燃,集合在CPU內(nèi)部役听,包含4個模擬通道和1個數(shù)字通道 |
MMC | ROM和VROM的擴容控制,用來控制訪問超過6502限制的64K地址表窘,同樣典予,也可以擴容VROM |
VRAM | 圖像RAM,PPU專用乐严,2K字節(jié) |
VROM | 圖像ROM熙参,儲存圖像數(shù)據(jù)的地方,可以由MMC切換到VRAM里 |
ROM | 程序ROM麦备,實際程序儲存的地方孽椰,擴容部分可以通過MMC切換到PRG-RAM里 |
RAM | 程序RAM昭娩,和ROM同義,不同的是它是RAM |
SPR-RAM | 精靈RAM黍匾,RAM中的256字節(jié)栏渺,專用于儲存精靈,它不屬于VRAM或ROM |
SRAM | 電池RAM锐涯,卡帶上用來保存游戲記錄的EPROM-電擦寫ROM |
DMC | 三角波調(diào)制通道磕诊,APU用來處理數(shù)字聲音的,也寫作PCM通道 |
EX-RAM | 擴展VRAM纹腌,用在MMC5里霎终,可以擴展VRAM容量 |
3、中央處理器
NES定制的6502內(nèi)部特別加上了聲音處理單元升薯。NTSC制式的NES使用1.7897725MHz主頻莱褒,PAL制式使用1.773447MHz主頻。
CPU內(nèi)存映像:
開始地址 | 用途 | 結(jié)束地址 |
---|---|---|
$0000 | 2K字節(jié)RAM涎劈,做4次鏡象(即 |
$1FFF |
$2000 | 寄存器 | $2007 |
$2008 | 寄存器( |
$3FFF |
$4000 | 寄存器 | $401F |
$4020 | 擴展ROM | $5FFF |
$6000 | 卡帶的SRAM(需要有電池支持) | $7FFF |
$8000 | 卡帶的下層ROM | $BFFF |
$C000 | 卡帶的上層ROM | $FFFF |
中斷:
6502有3個中斷IRQ/BRK、NMI和RESET蛛枚,每個中斷都有一個16位的向量谅海,即指針,用來存放該中斷發(fā)生時中斷服務(wù)函數(shù)的地址蹦浦。中斷發(fā)生時CPU都會把狀態(tài)標志和返回地址壓棧扭吁,然后調(diào)用中斷服務(wù)程序。
IRQ/BRK中斷由一下兩種情況產(chǎn)生:一是軟件通過BRK指令產(chǎn)生盲镶,一是硬件通過IRQ引腳產(chǎn)生智末。
RESET在開機的時候觸發(fā),這是ROM被裝入徒河,6502跳到RESET向量指向的地址沒有寄存器被修改系馆,沒有內(nèi)存被清空,這些都只在開機是發(fā)生顽照。
NMI指不可屏蔽中斷由蘑,它在VBlank即屏幕刷新時發(fā)生,持續(xù)時間根據(jù)系統(tǒng)(NTSC/PAL)不同而不同代兵。NTSC是每秒60次尼酿,而PAL是每秒50 次。6502的中斷延時是7個時鐘周期植影,也就是說裳擎,進入和離開中斷都需要7個時鐘周期。它產(chǎn)生于PPU的每一幀結(jié)束思币,NMI中斷可以由$2000的第7位的1/0控制允許/禁止鹿响。
大部分中斷應(yīng)該使用RTI指令返回羡微,但是有些游戲不用,例如《最終幻想1》惶我。它用一個很奇怪的方式:手工修改堆棧指針妈倔,然后執(zhí)行RTS指令。這種方法在技術(shù)上是可行的绸贡,但是應(yīng)該盡量避免盯蝴。
以上中斷在ROM內(nèi)有以下對應(yīng)的地址:
中斷地址 | 中斷 | 優(yōu)先權(quán) |
---|---|---|
$FFFA | NMI | 中 |
$FFFC | RESET | 高 |
$FFFE | IRQ/BRK | 低 |
特別說明:
NES的6502不支持10進制。雖然CLD和SED指令都正常工作听怕,但是ADC和SBC都不使用CPU狀態(tài)標志的“D”位捧挺。由于復(fù)位后“D”位的狀態(tài)是不確定的,所以游戲通常在程序開始時使用一個CLD指令尿瞭。
聲音寄存器映射到CPU內(nèi)部闽烙,所有波形發(fā)生的工作都在CPU內(nèi)部完成。
注意那兩個分開的16K ROM段筷厘,它們可能是連續(xù)的鸣峭,但是它們根據(jù)卡帶的大小扮演不同的角色宏所。有的卡帶只有一個16K ROM酥艳,那么它就同時被裝入$8000和$COOO。
所有游戲都將它們自己裝入$8000爬骤,使用32K RAM充石,但是它們都能夠通過內(nèi)存映射把多于一個16K ROM裝入$8000。VROM也是同樣的道理霞玄。
當BRK中斷發(fā)生的時候骤铃,CPU把狀態(tài)標志壓入堆棧,同時設(shè)置“B”標志坷剧。而IRQ中斷發(fā)生時惰爬,CPU把狀態(tài)標志壓入堆棧,同時清除“B”標志惫企。這是因為6502使用同一個向量來處理兩種中斷撕瞧,用“B”標志來區(qū)分它們。你可以用以下程序來區(qū)別兩種中斷:
C134: PLA ; 拷貝CPU狀態(tài)標志到A
C135: PHA ; 把狀態(tài)標志還回給堆棧
C136: AND #$10 ; 檢查“B”標志
C138: BNE is_BRK_opcode; 如果設(shè)置了狞尔,就是軟件中斷(BRK)
在NMI里指向BRK會導(dǎo)致已經(jīng)被壓棧的“B”標志被設(shè)置丛版。
6502的$6C指令(間接絕對跳轉(zhuǎn))有一個BUG,當?shù)臀蛔止?jié)是$FF時CPU將不能正確計算有效地址偏序。例如:
C100: 4F
C1FF: 00
C200: 23
..
D000: 6C FF C1 - JMP ($C1FF)
本來它是應(yīng)該跳到$2300的页畦,但是在計算高位字節(jié)的時候,在頁面邊界處地址是不能再增加的研儒,所以實際將跳轉(zhuǎn)到$4F00豫缨。
需要注意的是独令,頁面越界不會在變址間接尋址模式發(fā)生。由于0頁面的限制州胳,由于0頁面的限制记焊,所有變址間接尋址的讀寫都應(yīng)該在計算有效地址之后和#$FF進行邏輯與操作。例如:
C000: LDX #3 ; 從 $0002+$0003 讀變址地址栓撞,
C002: LDA ($FF,X) ; 不是 $0102+$0103.
4遍膜、圖形處理器
PPU時序:
- | NTSC制式 | PAL制式 |
---|---|---|
基頻(Base clock) | 21477270.0Hz | 21281364.0Hz |
CPU主頻(Cpu clock) | 1789772.5Hz | 1773447.0Hz |
總掃描線數(shù)(Total scanlines) | 262 | 312 |
掃描線總周期(Scanline total cycles) | 1364(15.75KHz) | 1362(15.625KHz) |
水平掃描周期(H-Draw cycles) | 1024 | 1024 |
水平空白周期(H-Blank cycles) | 340 | 338 |
結(jié)束周期(End cycles) | 4 | 2 |
幀周期(Frame cycles) | 1364*262 | 1362*312 |
幀IRQ周期(FrameIRQ cycles) | 29830 | 35469 |
幀率(Frame rate) | 60(59.94Hz) | 50Hz |
幀時間(Frame period) | 1000.0/60.0(ms) | 1000.0/50.0(ms) |
鏡像是指通過硬件映射特殊的內(nèi)存地址或范圍的一個過程。
PPU內(nèi)存映像:
開始地址 | 用途 | 結(jié)束地址 |
---|---|---|
$0000 | 圖案表0(256x2x8瓤湘,可能是VROM) | $0FFF |
$1000 | 圖案表1(256x2x8瓢颅,可能是VROM) | $1FFF |
$2000 | 命名表0(32x30塊)(鏡像,見命名表鏡像) | $23BF |
$23C0 | 屬性表0(鏡像弛说,見命名表鏡像) | $23FF |
$2400 | 命名表1(32x30塊)(鏡像挽懦,見命名表鏡像) | $27BF |
$27C0 | 屬性表1(鏡像,見命名表鏡像) | $27FF |
$2800 | 命名表2(32x30塊)(鏡像木人,見命名表鏡像) | $2BBF |
$2BC0 | 屬性表2(鏡像信柿,見命名表鏡像) | $2BFF |
$2C00 | 命名表3(32x30塊)(鏡像,見命名表鏡像) | $2FBF |
$2FC0 | 屬性表3(鏡像醒第,見命名表鏡像) | $2FFF |
$3000 |
|
$3EFF |
$3F00 | 背景調(diào)色板#1 | $3F0F |
$3F10 | 精靈調(diào)色板#1 | $3F1F |
$3F20 | 鏡像渔嚷,(見調(diào)色板鏡像) | $3FFF |
$4000 |
|
$7FFF |
命名表:
NES 的圖像通過Tile矩陣來顯示,這個網(wǎng)格就叫命名表稠曼。一個命名表和字符模式下的屏幕緩沖比較相象形病,它包含字符的代碼,也就是30列的32Byte長度霞幅。每個Tile有8x8個象素漠吻,每個命名表有32x30個Tile,也就是256x240象素司恳。PPU支持4個命名表途乃,他們在$2000,$2400,$2800,$2C00。在NTSC制式下扔傅,上面和下面的8象素通常不顯示出來耍共,只有256x224象素;在PAL制式下铅鲤,屏幕有256x240象素划提。
需要說的是,雖然PPU支持4個命名表邢享,任天堂主機只支持2個命名表鹏往。另外兩個被做了鏡像。命名表保存了Tile的編號,而Tile存在圖案表里伊履。計算命名表里Tile號對應(yīng)的實際地址的公式是:
(Tile號×16)+由$2000端口指定的圖案表地址
命名表鏡像:
NES只有2048字節(jié)($800)的VRAM給命名表使用韩容,但是如前表所示,NES有能力尋址到4個命名表唐瀑。缺省情況下群凶,NES卡帶都帶有水平和垂直鏡像,允許你改變命名表指向PPU的VRAM位置哄辣。這種方式同時影響兩個命名表请梢,你不能單獨改變其中的一個。每個卡帶都控制著PPU地址線的A10 和A11力穗。它可能將他們設(shè)置成以下4種可能的方式的1種毅弧。下面這個圖表有助于理解NES里的各種鏡像,指向PPU VRAM中命名表的12位地址相當于“$2xxxx”:
名字 | 命名 表#0 | 命名 表#1 | 命名 表#2 | 命名 表#3 | 說明 | 地址線A11 | 地址線A10 |
---|---|---|---|---|---|---|---|
水平 | $000 | $000 | $400 | $400 | 1 | 0 | |
垂直 | $000 | $800 | $000 | $800 | 0 | 1 | |
4屏幕鏡像 | $000 | $400 | $800 | $C00 | 卡帶里有2K VRAM当窗,4個命名表物理上獨立的 | 1 | 1 |
單屏幕 | $X00 | $X00 | $X00 | $X00 | 所有的命名表指相同的VRAM區(qū)域,X=0够坐、4、8崖面、C | 0 | 0 |
VROM鏡像 | Mapper 68#游戲映射VROM到PPU VRAM的命名表元咙,這使得命名表是基于VROM的,你不能寫它但卻可以通過mapper自己來控制是否使用這種特性 |