星期二, 3月 30, 2010

VRAM & DMA

因為有人問  所以在此就我所知的做簡單解說
如有誤   歡迎給予指教 (畢竟我也只是個中文化路人....)

又因為我只對皇騎系有興趣  所以這邊僅以SFC為例來解說
(GBA上的TOG沒用到debugger  所以不清楚......)

以SFC為例來說
通常會把字庫圖像放到RAM(7E0000~7FFFFF)裡
再用DMA一次丟到VRAM中  然後輸出畫面


ROM --解讀字庫--〉RAM --DMA--〉VRAM  --〉螢幕畫面



VRAM中每個8x8字庫圖像(tile)會對應一個tile編號
依模式不同  VRAM中可用的tile數量
與及每個tile所佔的byte數也不同(通常是8x2或8x4個bytes)
在繪製畫面前  SFC會把用到的tile編號
依畫面顯示順序存在VRAM的另一個地方
VRAM中的字庫tile   大致會以下圖所示方法顯示




















因為VRAM只有64kB  所以一次可以放進去的字不多
加上其他圖標、欄框、背景也要佔tile數量
如果只有平片假名  大概還能全部塞進VRAM
但如果是大量的漢字  通常會把畫面用到的字先存到RAM
再把這些挑出來的字存到VRAM

所以
如果遊戲因為只用到少數平片假名文字
而採用一口氣全部讀到VRAM裡的作法時
就沒辦法透過改字庫pointer等方式來擴增可用字數
因為程式無法一次讀更多字進去
只能用ASM改寫原程式  只挑出要用的字到RAM裡
用DMA把這些字送到VRAM中
並且根據這些字在畫面上該出現的位置
填寫對應的tile編號 

基本上  除了上面黃字的Case
中文化好像不太需要去動VRAM這一塊
DMA倒是比較常用到
傳輸大塊連續資料很快速方便

要修改VRAM中的資料不是很直覺
必須要去存取幾個特定位址  才能更動裡面資料
參考連結1
*參考連結2


舉例(這是國外某文章的範例  借花獻佛一下):
如果要從ROM位置$18000的地方
複製128個8x8大小的4色(2bytes)文字
到VRAM中$0000的位置時
(也就是共複製$800 bytes到VRAM中$0000的位置)
可以用下面這個函式完成

#$表示16進位數字  $表示16進位位址的值
除".w"表示處理資料為2bytes外  其餘皆為1byte 

    ldx.w #$0000    ; 設定VRAM pointer($2116)為#$0000
    stx $2116       
    lda #$01        ; 設定DMA control value($4300) 為 "normal"
    sta $4300
    lda #$18        ; 設定DMA至VRAM($2118)
    sta $4301        ; 參考上面的*連結   
    ldx.w #$8000    ; 設定DMA來源位址($18000)
    stx $4302
    lda #$01       
    sta $4304
    ldx.w #$0800    ; 設定DMA要傳的總Byte數
    stx $4305
    lda #$01        ; 經由channel 0開始DMA傳輸
    sta $420B

這邊要注意的一點是
DMA傳輸有0~7八種channel    各自有對應使用的特定位址
如果是經由channel 1做DMA傳輸  $430X要改為$431X
如果是經由channel 2做DMA傳輸  $430X要改為$432X
以此類推 $420B亦如是

雖然前述例子是ROM --DMA--〉VRAM
但當然也能RAM --DMA--〉VRAM  作法上沒啥改變
我處理OB就是把要顯示的字先從ROM挑好排到RAM中
再用DMA傳到VRAM

DMA也能用在ROM --〉RAM或RAM --〉RAM(單純移動位址)
這時就有一個專門op code處理
不用像傳到VRAM中那麼麻煩