# GameBoy Advance Emulator :::danger github連結 : [rGBA](https://github.com/kd992102/rGBA) 目前問題 1.CPSR狀態暫存器(暫時OK) 2.0x4000301 HALTCNT (CPU停擺,其他元件繼續) 3.Timer/DMA/Sound模擬 ::: ## 編譯教學 ::: success 環境:Windows 10/11 編譯器:MinGW-w64-i686-toolchain 編譯環境安裝 1.下載[msys2](https://www.msys2.org/) 2.安裝msys2後,打開 3.輸入指令 __pacman -S mingw-w64-i686-toolchain__ 4.選擇 mingw-w64-i686-gcc後安裝 4.輸入指令 __pacman -S mingw-w64-i686-make__ 後安裝 5.到[SDL2 github](https://github.com/libsdl-org/SDL/releases/tag/release-2.30.0)下載mingw用的library 6.解壓縮後將 __i686-w64-mingw32\include__ 資料夾中的SDL2資料夾整個複製到 __C:\msys64\mingw32\include__ 7.將 __i686-w64-mingw32\lib__ 資料夾中 __.a,.la__ 的檔案複製到 __C:\msys64\mingw32\lib__ 8.將 __i686-w64-mingw32\bin__ 中 __SDL.dll__ 複製到rGBA專案目錄底下(和main.c同一個目錄) 9.在cmd中 __執行compile.bat__ ,即可執行 ::: --- ## [1.CPU : ARM7TDMI](https://hackmd.io/@Ray0536011/rJ1OoojZC) --- ## 2.PPU : 圖形處理單元 > 所謂的PPU(Pixel Processing Unit),簡單講就是負責在畫紙(LCD螢幕)上繪圖的畫筆(硬體元件),因為CPU本身須負責計算各種資料以及記憶體位置變化,所以繪圖這種較為複雜的動作就需要另一個具備同樣強大運算功能的硬體元件來負責,而不同元件同時運作會碰到的問題就是能不能同步。 ### Video System(繪圖系統) - 記憶體中與繪圖相關的記憶體區段可分為 - Palette(調色盤) : 儲存著所有需要上色的顏色 - 0x5000000 - VRAM(影像記憶體) : 儲存著所有會被畫在螢幕上的資料(Pixel) - 0x6000000 - OAM(物件記憶體) : 儲存著Sprite這種小型物件的屬性 - 0x7000000 - Video Mode(繪圖模式): - | Mode | Type | Resolution | Backgrounds | Colors | | ---- | ---- | ---------- | ----------- | ------ | | 0 | Tile | 240 x 160 | 4 | 8-bpp (indexed) | | 1 | Tile | 240 x 160 | 3 | 8-bpp (indexed) | | 2 | Tile | 240 x 160 | 2 | 8-bpp (indexed) | | 3 | Bitmap | 240 x 160 | 1 | 16-bpp (direct) | | 4 | Bitmap | 240 x 160 | 2 | 8-bpp (indexed) | | 5 | Bitmap | 160 x 128 | 2 | 16-bpp (direct) | - __BG Mode 0-2 (Tile/Map 基礎模式)__: - 0x6000000-0x600FFFF (64KBytes),由Map和Tile共用,並由BGXCNT暫存器控制。 - Map以2K(800h)大小為一單元,Tile以16K(4000h)大小為一單元 - 0x6010000-0x6017FFF (32KBytes),OBJ Tiles使用 - BG Mode 0,1 (Tile/Map 基礎模式) - Tile有兩種色深(Color Depth),4bit(16 color mode,占20h大小)和8bit(256 color mode,占40h大小) - 最小Map為32x32 Tiles,最大為64x64 Tiles - 每個map上限為1024個Tiles - BG Mode 1,2 (Tile/Map 基礎旋轉/縮放模式) - Tile只有一種8bit色深 - 最小Map為16x16 Tiles,最大為128x128 Tiles - 每個map上限為256個Tiles - __BG Mode 3 (Bitmap靜態影像基礎模式)__: - 0x6000000-0x6013FFF (80KBytes Frame 0 緩衝區,實際只使用75KBytes) - 0x6014000-0x6017FFF (16KBytes),OBJ Tiles使用 - __BG Mode 4,5 (Bitmap基礎模式)__: - 0x6000000-0x6009FFF (40KBytes Frame 0 緩衝區),Mode 4 實際只使用37.5KBytes - 0x600A000-0x6013FFF (40KBytes Frame 1 緩衝區),Mode 4 實際只使用37.5KBytes - 0x6014000-0x6017FFF (16KBytes),OBJ Tiles使用 - BG Screen Data (BG Map): - Text BG Screen (每個entry 2 bytes、64 pixels) - BG共有4個,BG0、BG1、BG2、BG3 - 每個BG由多個8x8的Tiles組成,包含32x32個entries,(32x32)x(8x8)x2bytes = 800h - 每個entry都存著欲顯示的Tiles號碼、顏色、水平、垂直等設定 - 4個BG有多種組合,可組成256x256、512x256、256x512、512x512 pixels四種畫面 - Rotation/Scaling BG Screen (每個entry 1 byte) - 固定使用256 Tiles,並使用256 color mode - 只儲存Tile號碼 - BG Map維度由BG大小決定(由BGXCNT暫存器決定) - 0->16x16 - 1->32x32 - 2->64x64 - 3->128x128 - BG Bitmap Data - 指定BG2, 支援旋轉/縮放 - BG Mode 3 (240x160 pixels, 32768 colors) - 不使用調色盤,自帶顏色資訊,可使用32768(32 R x 32 G x 32 B)種顏色 - 每480 bytes為一條橫向直線單位 - 佔用空間極大,只可同時載入1個畫面,建議使用於靜態影像 - BG Mode 4 (240x160 pixels, 256 colors) - 使用調色盤,256 color mode - 每240 bytes為一條橫向直線單位 - 可一次載入2個畫面 - BG Mode 5 (160x128 pixels, 32768 colors) - Mode3 畫面閹割版 - 每480 bytes為一條橫向直線單位 - 可一次載入2個畫面 - OBJ (Sprite,為小型圖案物件) - Sprite的Tile儲存於0x6010000,Sprite的屬性(Attribute)儲存於0x7000000 - GBA每個畫面可顯示的Sprite上限為128個 - Rotation/Scaling (旋轉/縮放) - 在OAM資料結構中有四個參數Pa、Pb、Pc、Pd - 使用二維矩陣計算,並使用定點數運算(fixed-point system)來表示浮點數 - 例:Pa = 80, 換算成浮點數為80/256 = 0.31 - 這時就要提到GBA一個特性,就是沒有所謂的浮點運算器(FPU),因此採用一種格式叫定點數(fixed-point number)來取代浮點數運算,優點是運算快,耗電量低,缺點則是無法精確表達出正確的數值,但對於GBA這種低像素的遊戲機來說是很夠用了。 - ![rot_scal](https://hackmd.io/_uploads/HymrDHWKa.png) - 繪圖所耗費之週期 | Type | Length | Cycles | | ---- | ------ | ------ | | Pixel | 1 | 4 | | HDraw | 240 | 960 | | HBlank | 68 | 272 | | Scanline | 308 | 1232 | | VDraw | 160*308 | 197120 | | VBlank | 68*308 | 83776 | | Refresh | 228*308 | 280896 | ## 3.Timers : 計時器 - 計時器對遊戲機來說其實並不是很重要的功能,因為玩遊戲並不一定要看時間,所以特別設計一個計時相關的零件並不符合成本 - 現有零件中與時間直接有關的是時脈(clock),但時脈太快了,要用時脈模擬出秒為單位時間太浪費空間了 - 因此退而求其次,使用垂直繪圖的刷新頻率來當作單位,我們都知道頻率是週期的倒數,而週期的單位就與我們熟知的時間相同 - 以GBA來說,1個CPU週期就是59.6微秒,並提供以下四種時間作為單位,1、64、256、1024 clock - 從REG_TMxD讀到的值是 __現在__ 的時間計數值,但寫入REG_TMxD的數值是當暫存器溢位或中斷發生時的值(initial value) - 假設n為初始值,c為現在計數值 ``` 假設REG_TM2D= 0xc000;//n為0xc000 需先設n值,再啟用暫存器 當暫存器啟用時,c=n 而當溢位或中斷發生時,會再將n寫入暫存器中 ``` - Cascade計時器是指用多個計時器疊加而成的計時器 - 利用第一個計時器累加後溢位來觸發下一個計時器,以此來達成指定時間單位的計時方式 ## 4.Direct Memory Access : 直接記憶體存取 ## 5.Sound : 聲音 - 硬體上使用兩個8位元 __數位-類比轉換器__ - 播放的採樣資料,必須以8位元有號數的方式儲存 - 播放前,資料須備載入硬體位址0x40000A0(名為REG_FIFO_A的I/O暫存器) - FIFO為First-In-First-Out(先進先出,概念為水管) - 回放的頻率由Timer0和Timer1兩個暫存器以溢位的方式控制 - 讓兩個不同頻道可獨自以不同頻率播放 - 可在兩個不同模式下運作,DMA模式(較有效率)和中斷模式 ## Reference - [ARM7TDMI microprocessors Datasheet](https://www.dwedit.org/files/ARM7TDMI.pdf) - [mGBA cycle-counting-prefetch](https://mgba.io/2015/06/27/cycle-counting-prefetch/) - [THE POLYGONS OF ANOTHER WORLD: GAME BOY ADVANCE](https://fabiensanglard.net/another_world_polygons_GBA/) - [Tonc GBA](https://www.coranac.com/tonc/text/)