GBA開發C語言內功補習(轉)

post0發表於2007-08-12
GBA開發C語言內功補習(轉)[@more@]

  自從學習開發GBA後,便對其開發的容易性,效率為之吸引.

  想必大家也是如此.

  因為GBA開發多數是使用C語言的,

  這裡寫一點基本的C語言的使用技巧.

  希望能增加大家的內功.

  

  1 對記憶體裡的暫存器進行操作.

  

  任何一個GBA開發庫的GBA標頭檔案都包含了很多由#define定義的符號.

  如 #define VRAM 0x06000000 // VRAM

  

  這裡的VRAM是一個宏符號,後面的0x06000000是一個立即數

  說明VRAM所代替的是0x06000000.

  和變數不同的是,變數會佔記憶體,而宏定義是不佔記憶體的.因為宏只對編譯器負責.

  

  由於GBA是使用了統一編地址.所有邏輯功能部件都是直接連線CPU片匯流排

  所以,GBA要對其他部件操作的時候,就如同操作記憶體一樣容易.

  

  下面講一下如何直接對記憶體進行操作.

  就拿VRAM來說,如果想對這個地址寫入一個 8 位無符號數的話,可以如下操作.

  

  *(u8*)VRAM = 0xff; // u8 是 unsigned char

  

  也可以這樣寫

  

  *(u8*)0x06000000 = 0xff

  

  這樣的操作在C語言中是合法的.相當與把一個指標直接指定地址後型別轉換成U8然後對內容操作.

  

  其結果是 06000000h 的位置為 0xff

  

  如果你想寫入一個u16的數的話,可以這樣寫

  

  *(u16*)VRAM=0xaaff 或 *(u16*)0x06000000

  

  其結果是 06000000h 為 0xff

  06000001h 為 0xaa

  

  以高位存放高地址,低位存放低地址的(大數端)原則存放資料.

  

  當然,地址是固定的,如何使用就要看實際情況了.

  

  上面這樣的操作是GBA裡最普遍的.由於98%的C語言的書上都沒有提到這類用法,

  所以在某種程度上,成了新手學習的絆腳石.

  

  2 利用結構型直接對位進行定義名稱.

  

  結構型是C語言裡極重要和普遍的定義資料的手段.

  但是恰恰許多人對結構型瞭解不是很深入.

  

  結構型的基本定義方式為

  

  struct

  {

  u8 a,

  u8 b;

  u8 c;

  u8 *d;

  }mystr;

  

  如此便定義好了一個結構,其中包括a,b,c三個U8型別的成員.和一個指標d

  這個結構的大小是 3 * 8 + 16 = 40 bit. = 5 byte

  

  因為一個指標的大小等於字長,GBA裡多數情況下是用THUMB模式開發程式.故為16位.

  

  然後到我們今天的重點.

  

  舉個例子,定義一個15bit顏色結構RGB ,其包含 R,G, B.是一共是16位.

  格式為 a bbbbb ggggg rrrrr 最高位無用.

  

  許多人會定義成

  

  typedef struct {

  U8 R,G,B;

  }RGB;

  

  這個結構佔3位元組,使用的時候用邏輯運算,壓成一個16位的點的資料.

  

  其實此操作太麻煩.

  先進的定義方式是:

  

  typedef struct {

  u16 r : 5 ;

  u16 g : 5 ;

  u16 b : 5 ;

  u16 dummy : 1 ;

  }RGB;

  

  此結構大小為 16bit 符合RGB的規則.

  

  關鍵在於在成員變數的後面加上 冒號 和 定義的位數.就完成了直接給位進行定義名稱.

  其中 嚴格按照從低位到高位的原則,先定義這為低位.後面定義的會接在前面一個後面的位定義.

  由於RGB定義完了,使用了15位,有最高位空閒,.所以定義個1位的DUMMY,防止浪費.

  

  使用的時候和一般的結構型一樣使用.不過如果數值超出範圍的話,超出的部分無效.

  

  如果這樣定義

  

  typedef struct

  {

  u8 a:5 ;

  u8 b;

  u8 c:4;

  }ABC

  

  那麼這個結構仍然為3BYTE. 因為成員b沒有說明是跟在a後面定義,而是另外重新定義一個成員.故

  無法連在a後.

  也就是說 a 的高3位就浪費了.

  

  3 例項

  

  就拿GBA裡一個十分重要的暫存器DISPCNT來說

  位於0x4000000 大小為16bit

  標頭檔案裡定義為

  

  #define DISPCNT 0x4000000

  

  具體內容為

  

  F E D C B A 9 8 7 6 5 4 3 2 1 0

  W V U S L K J I F D B A C M M M

  0-2 (M) = BG模式 0 ~ 5

  3 (C) = Game Boy Color 模式

  4 (A) = BG反轉

  5 (B) = hblnk

  6 (D) = 1D 方式還是2D方式

  7 (F) = MODE4中使用.用於檢測是哪個FRAME有效.

  8 (I) = BG0. 允許顯示

  9 (J) = BG1. 允許顯示

  A (K) = BG2. 允許顯示

  B (L) = BG3. 允許顯示

  C (S) = OAM 允許顯示

  E (V) = Window允許

  F (W) = Sprite Windows允許

  

  按照上面說的,可以如此定義結構.

  

  typedef struct DispCnt{

  u16 BgMode:3; // BG Mode Select

  u16 CgbMode:1; // CGB Mode Select

  u16 Bmp_FrameNo:1; // Bitmap Mode Display Frame Select

  u16 Obj_H_Off:1; // OBJ Processing in H Blank OFF

  u16 ObjCharMapType:1; // OBJ Character Data Mapping Type

  u16 Lcdc_Off:1; // LCDC OFF

  u16 Bg0_On:1; // BG 0 ON

  u16 Bg1_On:1; // BG 1 ON

  u16 Bg2_On:1; // BG 2 ON

  u16 Bg3_On:1; // BG 3 ON

  u16 Obj_On:1; // OBJ ON

  u16 Win0_On:1; // Window 0 ON

  u16 Win1_On:1; // Window 1 ON

  u16 ObjWin_On:1; // OBJ Window ON

  } DispCnt;

  

  對其進行操作:

  

  ((DispCnt*) DISPCNT)->成員變數.

  

  把DISPCNT的地址轉換成DispCnt型別然後指標化,把這個指標操作其內部的成員.

  

  這樣夠方便了把.不用理會那些麻煩的標誌,和邏輯操作.

  直接賦值就可以了.

  

  (此種方法在99%的C語言書裡也沒提到過. ……..心寒)

  

  由於GBA裡類似的暫存器實在太多,請切記,上述方法使用不要過度.

  否則一大堆指標,會佔太多的記憶體.使可用的記憶體減少,造成資源短缺.

  請一定要注意.

  

  寫完後,有點累了.希望能幫助大家進入GBA的開發圈子,提高自己的C語言內功

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-951702/,如需轉載,請註明出處,否則將追究法律責任。

相關文章