此次說一下GB的顯示系統,先從一幅Gb的內存分佈圖提及,請看圖:緩存
圖中紅色框框起來的部分就是這篇文章關注的部分,這一部分的內存地址從8000-9Fff,共8KB,這一部分是歷來存儲背景和遊戲「精靈」的數據的。一般咱們認爲Gb只能顯示黑、白兩種顏色,但其實,Gb還能顯示明、暗灰度,總共是4種顏色。這樣,顯示出來的每一個像素點須要佔用兩個bit的空間。對於Gb的顯示系統來講,屏幕會緩存256*256大小的圖片,其中160*144大小的某個區域會顯示在液晶屏上,咱們算一下,要緩存的圖片的大小爲256*256*2=16KB。可是咱們的顯存只有從8000-9Fff的8KB,顯然是放不下的。因此Gameboy使用了某種機制,使不夠16KB的顯存也可以顯示出16KB大小的內容,這種機制就是再顯存中一部分用來存放圖片數據,一部分用來存放映射數據。圖片被劃分爲每一個8*8大小的塊(tile),每一個塊有一個編號,而在映射數據的部分存的只是每一個塊的編號,這樣子,每一個塊就有可能會被重複使用,從而達到在不足16KB顯存的狀況下顯示16KB數據的目的。這就解釋了爲何在上一篇文中,我直接把任天堂的logo數據加載成圖片,顯示出來的東西確怎麼看都不像是一個logo,其實加載進來的數據只是一個映射數據,而不是真正的圖片數據。ide
好,咱們繼續。知道了gameboy的顯示機制以後再從新看一下顯存中的數據分佈狀況,請看下錶:學習
區域spa |
做用3d |
8000-87FF調試 |
圖塊集1: 圖塊編號0-127對象 |
8800-8FFFblog |
圖塊集1: 圖塊編號128-255 |
9000-97FF遊戲 |
圖塊集0: 圖塊編號0-127 |
9800-9BFF |
圖塊集0的映射區域 |
9C00-9FFF |
圖塊集1的映射區域 |
圖塊集1能夠用來顯示背景、窗口和精靈,圖塊集0用來顯示背景和窗口。這裏的窗口指的就是160*144大小的在液晶屏上顯示的區域。
精靈
Gameboy能夠控制40個精靈的顯示,每一個精靈的大小爲8*8或者8*16的圖片塊,同時,受硬件能力限制,每一個掃描線(scan line,對這個概念理解得不是很好,但願有人能幫助解釋一下)只能顯示10個精靈。每一個精靈的圖片數據存放在8000-8Fff的區域中,就是上面說的圖塊集1所在的區域。而精靈自身的屬性數據(x和y座標等數據)則存放在專門的精靈屬性表中(Sprite Attribute Table),也叫對象屬性內存OAM(Object Attribute Memory),該區域位於內存FE00-FE9F中,OAM被劃分紅40個4字節的塊,每一個塊表明一個精靈。
對於精靈對象,x座標越小則它的顯示優先級越高,對於擁有一樣x座標的精靈對象,則經過它在OAM中的順序來區分顯示優先級(FE00的最高,FE04的次之,而後依次往下)。
因爲最多隻能有10個精靈在同一行上顯示,因此,在一行有超過10個精靈的時候,顯示優先級低的將會被隱藏。爲了不不使用的精靈影響正常精靈的顯示,應該把這些精靈的位置設爲y=0 or y>=144+16或者x=0 or x>=160+8.
下面說一下OAM中每一個精靈屬性數據的含義:
Byte0: y座標值
Byte1: x座標值
Byte2: 精靈的圖塊編號,對於8*16模式大小的精靈,LSB(最低有效位?)被忽略
Byte3:標誌位:
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
值0 |
顯示在背景和窗口的頂端 |
從OBJ0PAL取色 |
||||||
值1 |
若是背景和窗口關的顏色爲1,2,3則隱藏 |
垂直跳動 |
水平跳動 |
從OBJ1PAL取色 |
顏色表:
值 |
模擬的顏色 |
0 |
[255, 255, 255] |
1 |
[192, 192, 192] |
2 |
[96, 96, 96] |
3 |
[0, 0, 0] |
好了,再瞭解完gameboy的顯示機制以後接下來就要看一下在程序上是怎麼來完成從內存到液晶屏上的顯示過程了:
下表列出並說明了顯示中用到的一些特殊的寄存器,特殊是由於這些寄存器是對內存中特定地址的稱呼,而不是在Cpu中的寄存器:
FF40 - LCDC – 液晶屏控制器 (R/W)
Bit 7 – 是否開啓液晶屏顯示 (0=Off, 1=On) Bit 6 – 窗口圖塊映射範圍選擇 (0=9800-9BFF, 1=9C00-9FFF) Bit 5 – 是否開啓窗口顯示 (0=Off, 1=On) Bit 4 – 背景和窗口圖塊數據範圍選擇 (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 – (對於黑白的GB和SGB)背景顯示開關 (0=Off, 1=On) 對於CGB在CGB模式下,0=背景和窗口會失去他們的優先級,精靈們仍是會顯示在背景和窗口的頂端。 對於CGB在非CGB模式下,0=背景和窗口變白,只有精靈任能繼續顯示 |
注:對於Bit7中止LCD操做只能在v-blank中斷中進行,不然會毀壞硬件(咱們作模擬器開發的就不須要擔憂這個了J)
FF41 - STAT - LCDC Status (R/W)
如下是一些典型的數值切換的過程當中各個模式的值:
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_____
模式標誌每一個週期的切換順序爲0,2,3,一個週期的時間大約爲109uS,0大約停留48.6uS,2大約19uS,3大約41uS,這由vblank中斷沒16.6ms觸發一次,模式標誌被設爲1的持續時間大約爲1.08ms.
用時鐘週期表示的話模式0大概201-207個週期,模式2大概77-83個週期,模式3大約169-175個週期,一個完整的模式切換大約456個週期,vblank持續4560個週期,一個完整的屏幕刷新大約每70224個週期發生一次
FF42 - SCY – 滾動Y座標 (R/W)
FF43 - SCX – 滾動X座標 (R/W)
制定256*256的背景中,哪一點做爲液晶屏幕的左上角原點。兩座標的範圍爲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座標 (R)
LY指示當前那一條水平線上的顯示數據被傳送給LCD驅動,LY的值可能爲0—153,當值爲144—153之間時,GB處於vblank中斷之中,當寫入值時,會重置計數器
FF45 - LYC - LY 比較 (R/W)
GB不停地比較Lyc和Ly寄存器的值,當兩個值徹底同樣時STAT寄存器的Coincidence Flag位會被設爲1,而後若是開啓了STAT中斷的話,會請求該中斷
FF4A - WY – 窗口Y座標 (R/W)
FF4B - WX – 窗口X座標 (R/W)
指定左上角的窗口位置,當Wx=0—166,Wy=0—143時,窗口可見
下面經過一張圖來講明Scy,SCX和Wy,Wx之間的關係:
FF47 - BGP – 背景調色板數據 (R/W) – 非CGB模式,即黑白模式
該寄存器用來給背景和窗口的圖塊的顏色編號賦上灰度值
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號對象調色板數據(R/W) -非CGB模式,即黑白模式
FF49 - OBP1PAL - 1號對象調色板數據(R/W) -非CGB模式,即黑白模式
這兩個寄存器分別給0號和1號精靈調色板賦上灰度值,每一個位表明的意思和BGP寄存器同樣,但最低的兩位是不使用的,由於00表明精靈是透明的
好,寄存器的介紹暫告一段落,如今來計算一下。不論是使用圖塊0仍是圖塊1,GB的映射空間的大小都是3FFF=1024,而後GB的背景是256*256,同時背景是由8*8的圖塊拼起來的,因此總共須要32*32個圖塊。而32*32正好等於1024,由此可知經過解析圖塊映射區內的全部圖塊的編號就可以獲得要顯示的背景的像素數據了。
由今天的分析可知每一個圖塊的大小是8*8個像素,佔用的空間是8*8*2個bit,共16個字節。下面經過一副圖來講明:
由上圖,其實每一個像素點的信息表示的是一個索引值,用來索引在調試版的顏色,調色板纔是用來實際存放顏色信息的地方。
好了,今天的筆記的就到這吧,原本想先完成模擬Cpu部分的指令的代碼再來學習顯示的,不過在寫代碼的時候發現,若是沒有顯示的話都不知道實際模擬的對不對,因此就只能先學習顯示部分的知識而後再去寫代碼了,有了輸出差很少就能夠判斷本身的代碼是否是正確了。
下一回將會對今天的知識用代碼來進行實現,就是模擬gameboy的顯示系統了,但願不要太難,呼,老天保佑。