WindowsPhone-GameBoy模拟器开发四--Gameboy显示系统分析
這次說(shuō)一下GB的顯示系統(tǒng),先從一幅Gb的內(nèi)存分布圖說(shuō)起,請(qǐng)看圖:
圖中紅色框框起來(lái)的部分就是這篇文章關(guān)注的部分,這一部分的內(nèi)存地址從8000-9Fff,共8KB,這一部分是從來(lái)存儲(chǔ)背景和游戲“精靈”的數(shù)據(jù)的。通常我們認(rèn)為Gb只能顯示黑、白兩種顏色,但其實(shí),Gb還能顯示明、暗灰度,總共是4種顏色。這樣,顯示出來(lái)的每個(gè)像素點(diǎn)需要占用兩個(gè)bit的空間。對(duì)于Gb的顯示系統(tǒng)來(lái)說(shuō),屏幕會(huì)緩存256*256大小的圖片,其中160*144大小的某個(gè)區(qū)域會(huì)顯示在液晶屏上,我們算一下,要緩存的圖片的大小為256*256*2=16KB。但是我們的顯存只有從8000-9Fff的8KB,顯然是放不下的。所以Gameboy使用了某種機(jī)制,使不夠16KB的顯存也能夠顯示出16KB大小的內(nèi)容,這種機(jī)制就是再顯存中一部分用來(lái)存放圖片數(shù)據(jù),一部分用來(lái)存放映射數(shù)據(jù)。圖片被劃分為每個(gè)8*8大小的塊(tile),每個(gè)塊有一個(gè)編號(hào),而在映射數(shù)據(jù)的部分存的只是每個(gè)塊的編號(hào),這樣子,每個(gè)塊就有可能會(huì)被重復(fù)使用,從而達(dá)到在不足16KB顯存的情況下顯示16KB數(shù)據(jù)的目的。這就解釋了為什么在上一篇文中,我直接把任天堂的logo數(shù)據(jù)加載成圖片,顯示出來(lái)的東西確怎么看都不像是一個(gè)logo,其實(shí)加載進(jìn)來(lái)的數(shù)據(jù)只是一個(gè)映射數(shù)據(jù),而不是真正的圖片數(shù)據(jù)。
好,我們繼續(xù)。知道了gameboy的顯示機(jī)制之后再重新看一下顯存中的數(shù)據(jù)分布情況,請(qǐng)看下表:
| 區(qū)域 | 作用 |
| 8000-87FF | 圖塊集1: 圖塊編號(hào)0-127 |
| 8800-8FFF | 圖塊集1: 圖塊編號(hào)128-255 |
| 9000-97FF | 圖塊集0: 圖塊編號(hào)0-127 |
| 9800-9BFF | 圖塊集0的映射區(qū)域 |
| 9C00-9FFF | 圖塊集1的映射區(qū)域 |
圖塊集1可以用來(lái)顯示背景、窗口和精靈,圖塊集0用來(lái)顯示背景和窗口。這里的窗口指的就是160*144大小的在液晶屏上顯示的區(qū)域。
精靈
Gameboy可以控制40個(gè)精靈的顯示,每個(gè)精靈的大小為8*8或者8*16的圖片塊,同時(shí),受硬件能力限制,每個(gè)掃描線(scan line,對(duì)這個(gè)概念理解得不是很好,希望有人能幫助解釋一下)只能顯示10個(gè)精靈。每個(gè)精靈的圖片數(shù)據(jù)存放在8000-8Fff的區(qū)域中,就是上面說(shuō)的圖塊集1所在的區(qū)域。而精靈自身的屬性數(shù)據(jù)(x和y坐標(biāo)等數(shù)據(jù))則存放在專(zhuān)門(mén)的精靈屬性表中(Sprite Attribute Table),也叫對(duì)象屬性內(nèi)存OAM(Object Attribute Memory),該區(qū)域位于內(nèi)存FE00-FE9F中,OAM被劃分成40個(gè)4字節(jié)的塊,每個(gè)塊代表一個(gè)精靈。
對(duì)于精靈對(duì)象,x坐標(biāo)越小則它的顯示優(yōu)先級(jí)越高,對(duì)于擁有同樣x坐標(biāo)的精靈對(duì)象,則通過(guò)它在OAM中的順序來(lái)區(qū)分顯示優(yōu)先級(jí)(FE00的最高,FE04的次之,然后依次往下)。
由于最多只能有10個(gè)精靈在同一行上顯示,所以,在一行有超過(guò)10個(gè)精靈的時(shí)候,顯示優(yōu)先級(jí)低的將會(huì)被隱藏。為了避免不使用的精靈影響正常精靈的顯示,應(yīng)該把這些精靈的位置設(shè)為y=0 or y>=144+16或者x=0 or x>=160+8.
下面說(shuō)一下OAM中每個(gè)精靈屬性數(shù)據(jù)的含義:
Byte0: y坐標(biāo)值
Byte1: x坐標(biāo)值
Byte2: 精靈的圖塊編號(hào),對(duì)于8*16模式大小的精靈,LSB(最低有效位?)被忽略
Byte3:標(biāo)志位:
| ? | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| 值0 | 顯示在背景和窗口的頂端 | ? | ? | 從OBJ0PAL取色 | ? | ? | ? | ? |
| 值1 | 如果背景和窗口關(guān)的顏色為1,2,3則隱藏 | 垂直跳動(dòng) | 水平跳動(dòng) | 從OBJ1PAL取色 | ? | ? | ? | ? |
顏色表:
| 值 | 模擬的顏色 |
| 0 | [255, 255, 255] |
| 1 | [192, 192, 192] |
| 2 | [96, 96, 96] |
| 3 | [0, 0, 0] |
好了,再了解完gameboy的顯示機(jī)制之后接下來(lái)就要看一下在程序上是怎么來(lái)完成從內(nèi)存到液晶屏上的顯示過(guò)程了:
下表列出并說(shuō)明了顯示中用到的一些特殊的寄存器,特殊是因?yàn)檫@些寄存器是對(duì)內(nèi)存中特定地址的稱(chēng)呼,而不是在Cpu中的寄存器:
FF40 - LCDC – 液晶屏控制器 (R/W)
| Bit 7 – 是否開(kāi)啟液晶屏顯示 (0=Off, 1=On) Bit 6 – 窗口圖塊映射范圍選擇 (0=9800-9BFF, 1=9C00-9FFF) Bit 5 – 是否開(kāi)啟窗口顯示 (0=Off, 1=On) Bit 4 – 背景和窗口圖塊數(shù)據(jù)范圍選擇 (0=8800-97FF, 1=8000-8FFF) Bit 3 – 背景圖塊映射范圍選擇 (0=9800-9BFF, 1=9C00-9FFF) Bit 2 – 精靈尺寸選擇 (0=8x8, 1=8x16) Bit 1 – 是否允許顯示精靈 (0=Off, 1=On) Bit 0 – (對(duì)于黑白的GB和SGB)背景顯示開(kāi)關(guān) (0=Off, 1=On) 對(duì)于CGB在CGB模式下,0=背景和窗口會(huì)失去他們的優(yōu)先級(jí),精靈們還是會(huì)顯示在背景和窗口的頂端。 對(duì)于CGB在非CGB模式下,0=背景和窗口變白,只有精靈任能繼續(xù)顯示 |
注:對(duì)于Bit7停止LCD操作只能在v-blank中斷中進(jìn)行,否則會(huì)毀壞硬件(我們做模擬器開(kāi)發(fā)的就不需要擔(dān)心這個(gè)了J)
FF41 - STAT - LCDC Status (R/W)
| Bit 6 - LYC=LY Coincidence 中斷 (1=Enable) (Read/Write) Bit 5 - 模式 2 OAM 中斷 (1=Enable) (Read/Write) Bit 4 - 模式 1 V-Blank 中斷 (1=Enable) (Read/Write) Bit 3 - 模式 0 H-Blank 中斷 (1=Enable) (Read/Write) Bit 2 - Coincidence Flag (0:LYC<>LY, 1:LYC=LY) (Read Only) Bit 1-0 - 模式標(biāo)志 (模式 0-3) (Read Only) 0: 處于H-Blank中斷中,Cpu能訪問(wèn)8000-9FFF和FE00-FE9F 1: 處于V-Blank中斷中,Cpu訪問(wèn)同上 2: 正在搜索OAM-RAM,Cpu不能訪問(wèn)8000-9FFF和FE00-FE9F 3: 正在傳輸數(shù)據(jù)到 LCD 驅(qū)動(dòng),Cpu不能訪問(wèn)8000-9FFF和FE00-FE9F。CGB模式下,不能訪問(wèn)調(diào)色板數(shù)據(jù)FF69,FF6B. |
以下是一些典型的數(shù)值切換的過(guò)程中各個(gè)模式的值:
Mode 2 2_____2_____2_____2_____2_____2___________________2____
Mode 3 _33____33____33____33____33____33__________________3___
Mode 0 ___000___000___000___000___000___000________________000
Mode 1 ____________________________________11111111111111_____
模式標(biāo)志每個(gè)周期的切換順序?yàn)?,2,3,一個(gè)周期的時(shí)間大約為109uS,0大約停留48.6uS,2大約19uS,3大約41uS,這由vblank中斷沒(méi)16.6ms觸發(fā)一次,模式標(biāo)志被設(shè)為1的持續(xù)時(shí)間大約為1.08ms.
用時(shí)鐘周期表示的話模式0大概201-207個(gè)周期,模式2大概77-83個(gè)周期,模式3大約169-175個(gè)周期,一個(gè)完整的模式切換大約456個(gè)周期,vblank持續(xù)4560個(gè)周期,一個(gè)完整的屏幕刷新大約每70224個(gè)周期發(fā)生一次
FF42 - SCY – 滾動(dòng)Y坐標(biāo) (R/W)
FF43 - SCX – 滾動(dòng)X坐標(biāo) (R/W)
制定256*256的背景中,哪一點(diǎn)作為液晶屏幕的左上角原點(diǎn)。兩坐標(biāo)的范圍為0—255.
the video controller automatically wraps back to the upper (left) position in BG map when drawing exceeds the lower (right) border of the BG map area.
FF44 - LY – LCDC的Y坐標(biāo) (R)
LY指示當(dāng)前那一條水平線上的顯示數(shù)據(jù)被傳送給LCD驅(qū)動(dòng),LY的值可能為0—153,當(dāng)值為144—153之間時(shí),GB處于vblank中斷之中,當(dāng)寫(xiě)入值時(shí),會(huì)重置計(jì)數(shù)器
FF45 - LYC - LY 比較 (R/W)
GB不停地比較Lyc和Ly寄存器的值,當(dāng)兩個(gè)值完全一樣時(shí)STAT寄存器的Coincidence Flag位會(huì)被設(shè)為1,然后如果開(kāi)啟了STAT中斷的話,會(huì)請(qǐng)求該中斷
FF4A - WY – 窗口Y坐標(biāo) (R/W)
FF4B - WX – 窗口X坐標(biāo) (R/W)
指定左上角的窗口位置,當(dāng)Wx=0—166,Wy=0—143時(shí),窗口可見(jiàn)
下面通過(guò)一張圖來(lái)說(shuō)明Scy,SCX和Wy,Wx之間的關(guān)系:
FF47 - BGP – 背景調(diào)色板數(shù)據(jù) (R/W) – 非CGB模式,即黑白模式
該寄存器用來(lái)給背景和窗口的圖塊的顏色編號(hào)賦上灰度值
| Bit 7-6 -Color Number 3 Bit 5-4 - Color Number 2 Bit 3-2 - Color Number 1 Bit 1-0 - Color Number 0 |
顏色值參考上面的顏色值表
FF48 - OBP0PAL – 0號(hào)對(duì)象調(diào)色板數(shù)據(jù)(R/W) -非CGB模式,即黑白模式
FF49 - OBP1PAL - 1號(hào)對(duì)象調(diào)色板數(shù)據(jù)(R/W) -非CGB模式,即黑白模式
這兩個(gè)寄存器分別給0號(hào)和1號(hào)精靈調(diào)色板賦上灰度值,每個(gè)位代表的意思和BGP寄存器一樣,但最低的兩位是不使用的,因?yàn)?0代表精靈是透明的
好,寄存器的介紹暫告一段落,現(xiàn)在來(lái)計(jì)算一下。不管是使用圖塊0還是圖塊1,GB的映射空間的大小都是3FFF=1024,然后GB的背景是256*256,同時(shí)背景是由8*8的圖塊拼起來(lái)的,所以總共需要32*32個(gè)圖塊。而32*32正好等于1024,由此可知通過(guò)解析圖塊映射區(qū)內(nèi)的所有圖塊的編號(hào)就能夠得到要顯示的背景的像素?cái)?shù)據(jù)了。
由今天的分析可知每個(gè)圖塊的大小是8*8個(gè)像素,占用的空間是8*8*2個(gè)bit,共16個(gè)字節(jié)。下面通過(guò)一副圖來(lái)說(shuō)明:
由上圖,其實(shí)每個(gè)像素點(diǎn)的信息表示的是一個(gè)索引值,用來(lái)索引在調(diào)試版的顏色,調(diào)色板才是用來(lái)實(shí)際存放顏色信息的地方。
好了,今天的筆記的就到這吧,本來(lái)想先完成模擬Cpu部分的指令的代碼再來(lái)學(xué)習(xí)顯示的,不過(guò)在寫(xiě)代碼的時(shí)候發(fā)現(xiàn),如果沒(méi)有顯示的話都不知道實(shí)際模擬的對(duì)不對(duì),所以就只能先學(xué)習(xí)顯示部分的知識(shí)然后再去寫(xiě)代碼了,有了輸出差不多就可以判斷自己的代碼是不是正確了。
下一回將會(huì)對(duì)今天的知識(shí)用代碼來(lái)進(jìn)行實(shí)現(xiàn),就是模擬gameboy的顯示系統(tǒng)了,希望不要太難,呼,老天保佑。
轉(zhuǎn)載于:https://www.cnblogs.com/li0803/p/3283727.html
總結(jié)
以上是生活随笔為你收集整理的WindowsPhone-GameBoy模拟器开发四--Gameboy显示系统分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 美股周四:热门中概股普跌,阿里跌逾5%
- 下一篇: 盒马启动上市计划:预计6-12个月内完成