├── .vscode └── settings.json ├── README.md ├── arm7tdmi ├── alignment.md ├── arm │ ├── alu.md │ ├── branch.md │ ├── coprocessor.md │ ├── instruction.md │ ├── loadstore.md │ ├── loadstore2.md │ ├── loadstore3.md │ ├── multiply.md │ ├── psr.md │ └── swap.md ├── cond.md ├── cycle.md ├── exception.md ├── register.md └── thumb │ ├── addressing.md │ ├── branch.md │ ├── instruction.md │ ├── loadstore.md │ ├── loadstore2.md │ └── register.md ├── bios ├── arithmetic.md ├── bios.md ├── decompression.md ├── halt.md ├── memcpy.md ├── reset.md └── rotation_scaling.md ├── cartridge ├── addon │ ├── carde.md │ ├── classic.md │ ├── gpio.md │ ├── rtc.md │ ├── rumble.md │ └── solar.md ├── backup │ ├── README.md │ ├── eeprom.md │ ├── flash.md │ └── sram.md ├── header.md ├── prefetch.md └── rom.md ├── cheat ├── README.md ├── arv3.md ├── cb.md ├── par.md └── vba.md ├── communication ├── infrared.md ├── sio │ ├── README.md │ ├── general.md │ ├── joybus.md │ ├── multiplayer.md │ ├── normal.md │ └── uart.md └── wireless.md ├── dma.md ├── images ├── affine_matrix.png ├── alphablend.png ├── bitmap.png ├── blackfade.png ├── boktai.jpeg ├── breakpoint-hit.png ├── breakpoints.png ├── connect.png ├── cycle-accuracy-comparison.svg ├── debugger-targets.png ├── debugger.png ├── decode │ ├── arm_bit_pattern.png │ ├── arm_bit_pattern_1.png │ ├── arm_bit_pattern_2.png │ ├── arm_bit_pattern_3.png │ ├── thumb_bit_pattern.png │ └── thumb_bit_pattern_1.png ├── e_reader.jpeg ├── full-debugger.png ├── gbm_wire_less.jpeg ├── gc_gba_link_cable.jpeg ├── gdb-prompt.png ├── gdb-server.png ├── gdb_packet_format.png ├── ghidra_gba_0.webp ├── ghidra_gba_1.webp ├── ghidra_gba_2.webp ├── modules.png ├── mosaic.png ├── multiplay.png ├── nes_classic.jpeg ├── objects.png ├── open-with-debugger.png ├── purple.webp ├── regions.png ├── rom-1.png ├── rom-2.png ├── screen_size.png ├── scroll.jpg ├── str-ns.svg ├── str-pns.svg ├── strings-password-characters.png ├── threads.png ├── whitefade.png ├── window_0.png ├── window_1.webp ├── window_2.webp └── wire_less.jpeg ├── interrupt.md ├── io.md ├── keypad.md ├── memory.md ├── others ├── emudev │ ├── cycle-counting-prefetch.md │ └── decode.md ├── homebrew │ ├── devkit.md │ ├── hq_mixer.md │ ├── mgba_with_gdb.md │ ├── mgba_with_ghidra_debug.md │ └── tinygo_tutorial.md └── ret │ ├── agbasm.md │ ├── ghidra-debugger.md │ └── interwork.md ├── sound.md ├── spec.md ├── system.md ├── timer.md ├── unpredictable.md ├── video ├── bg │ ├── control.md │ ├── mode │ │ ├── README.md │ │ ├── bitmap.md │ │ └── tile │ │ │ ├── README.md │ │ │ ├── bgmap.md │ │ │ └── tiledata.md │ ├── scalerot.md │ └── scroll.md ├── blend.md ├── dispcnt.md ├── greenswp.md ├── interrupt.md ├── mosaic.md ├── oam.md ├── palette.md ├── scanline.md ├── sprite.md └── window.md └── waitstate.md /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "prettier.printWidth": 5000, 3 | "prettier.tabWidth": 1, 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gba-docs-ja 2 | 3 | 4 | 5 | GameBoyAdvanceについて、技術的な詳細を日本語でまとめたものです。 6 | 7 | 突然消えたり非公開にする可能性もあるので心配な方はクローンしておくことをお勧めします。 8 | 9 | > [!WARNING] 10 | > このレポジトリは大半が執筆途中です。なので現在、ドキュメントとしての信頼性は皆無です。 11 | > また、コミット履歴は気まぐれで破壊されることがあります。 12 | 13 | ## コンテンツ一覧 14 | 15 | ### GBA 16 | 17 | - [仕様](spec.md) 18 | - [メモリマップ](memory.md) 19 | - [IOレジスタ](io.md) 20 | - [DMA転送](dma.md) 21 | - [割り込み](interrupt.md) 22 | - [システム制御](system.md) 23 | - [POSTFLG](system.md) 24 | - [HALTCNT](system.md) 25 | - [MEMCNT](system.md) 26 | - [タイマー(TMnCNT)](timer.md) 27 | - [サウンド](sound.md) 28 | - [キー入力](keypad.md) 29 | - [特殊な挙動](unpredictable.md) 30 | 31 | ### カートリッジ 32 | 33 | - [カートリッジヘッダ](cartridge/header.md) 34 | - [カートリッジROM](cartridge/rom.md) 35 | - [バックアップメディア](cartridge/backup/README.md) 36 | - [SRAM/FRAM](cartridge/backup/sram.md) 37 | - [EEPROM](cartridge/backup/eeprom.md) 38 | - [FLASH](cartridge/backup/flash.md) 39 | - [DACS](cartridge/backup/README.md) 40 | - [カートリッジのプリフェッチ](cartridge/prefetch.md) 41 | - 周辺機器・その他 42 | - [GPIO](cartridge/addon/gpio.md) 43 | - [RTC(時計機能)](cartridge/addon/rtc.md) 44 | - [太陽センサー](cartridge/addon/solar.md) 45 | - [振動パック](cartridge/addon/rumble.md) 46 | - [カードeリーダー](cartridge/addon/carde.md) 47 | - [ファミコンミニシリーズ](cartridge/addon/classic.md) 48 | 49 | ### CPU 50 | 51 | - [レジスタ](arm7tdmi/register.md) 52 | - [ARM命令一覧](arm7tdmi/instruction.md) 53 | - [ALU](arm7tdmi/arm/alu.md) 54 | - [分岐命令](arm7tdmi/arm/branch.md) 55 | - [乗算](arm7tdmi/arm/multiply.md) 56 | - [ロード/ストア](arm7tdmi/arm/loadstore.md) 57 | - [ロード/ストア その2](arm7tdmi/arm/loadstore2.md) 58 | - [ロード/ストア その3](arm7tdmi/arm/loadstore3.md) 59 | - [プロセッサ状態](arm7tdmi/arm/psr.md) 60 | - [スワップ命令](arm7tdmi/arm/swap.md) 61 | - [コプロセッサ命令](arm7tdmi/arm/coprocessor.md) 62 | - [THUMB命令一覧](arm7tdmi/thumb/instruction.md) 63 | - [レジスタ操作](arm7tdmi/thumb/register.md) 64 | - [ロード/ストア](arm7tdmi/thumb/loadstore.md) 65 | - [ロード/ストア(スタック)](arm7tdmi/thumb/loadstore2.md) 66 | - [アドレッシング](arm7tdmi/thumb/addressing.md) 67 | - [分岐命令](arm7tdmi/thumb/branch.md) 68 | - [サイクル](arm7tdmi/cycle.md) 69 | - [Waitstate](arm7tdmi/cycle.md) 70 | - [条件](arm7tdmi/cond.md) 71 | - [例外](arm7tdmi/exception.md) 72 | - [アラインメント](arm7tdmi/alignment.md) 73 | 74 | ### グラフィック 75 | 76 | - 背景(BG) 77 | - [制御レジスタ(BGnCNT)](video/bg/control.md) 78 | - [BGモード](video/bg/mode/) 79 | - [タイルモード(Mode0-2)](video/bg/mode/tile/README.md) 80 | - [タイルデータ](video/bg/mode/tile/tiledata.md) 81 | - [BGマップ](video/bg/mode/tile/bgmap.md) 82 | - [ビットマップモード(Mode3-5)](video/bg/mode/bitmap.md) 83 | - [スクロール(BGnOFS)](video/bg/scroll.md) 84 | - [伸縮回転](video/bg/scalerot.md) 85 | - [BGnX](video/bg/scalerot.md) 86 | - [BGnPA](video/bg/scalerot.md) 87 | - [ウィンドウ](video/window.md) 88 | - [モザイク](video/mosaic.md) 89 | - [ブレンド](video/blend.md) 90 | - [割り込み](video/interrupt.md) 91 | - [DISPSTAT](video/interrupt.md) 92 | - [VCOUNT](video/interrupt.md) 93 | - [スプライト](video/sprite.md) 94 | - [OAM](video/oam.md) 95 | - [パレット](video/palette.md) 96 | - [描画サイクル](video/scanline.md) 97 | 98 | ### BIOS 99 | 100 | - [命令一覧](bios/bios.md) 101 | - [算術](bios/arithmetic.md) 102 | - [伸縮回転](bios/rotation_scaling.md) 103 | - [メモリコピー](bios/memcpy.md) 104 | - [Halt](bios/halt.md) 105 | - [リセット](bios/reset.md) 106 | - [解凍](bios/decompression.md) 107 | 108 | ### 通信機能 109 | 110 | - [シリアル通信](communication/sio/README.md) 111 | - [通常モード](communication/sio/normal.md) 112 | - [マルチプレイモード](communication/sio/multiplayer.md) 113 | - [UARTモード](communication/sio/uart.md) 114 | - [JOYバスモード](communication/sio/joybus.md) 115 | - [汎用モード](communication/sio/general.md) 116 | - [ワイヤレスアダプタ](communication/wireless.md) 117 | - [赤外線通信](communication/infrared.md) 118 | 119 | ### その他 120 | 121 | この辺は、自分のメモ書きの側面も強いです。 122 | 123 | - [devkitProのインストール](others/homebrew/devkit.md) 124 | - [HQミキサー](others/homebrew/hq_mixer.md) 125 | - [mGBAをgdbでデバッグする方法](others/homebrew/mgba_with_gdb.md) 126 | - [GBA命令のデコード](others/emudev/decode.md) 127 | - [GBAのサイクルカウントとプリフェッチについて](others/emudev/cycle-counting-prefetch.md) 128 | - [Ghidraを用いたGBAROMのデバッグ](others/ret/ghidra-debugger.md) 129 | 130 | ## 関連するレポジトリ 131 | 132 | - [gb-docs-ja](https://github.com/akatsuki105/gb-docs-ja): GameBoyについて 133 | - [nds-docs-ja](https://github.com/akatsuki105/nds-docs-ja): Nintendo DSについて 134 | - [snes-docs-ja](https://github.com/akatsuki105/snes-docs-ja): スーパーファミコンについて 135 | 136 | ## 参考記事 137 | 138 | - [GBATEK](https://web.archive.org/web/20210108175702/https://problemkaputt.de/gbatek.htm) 139 | - [GBA develop Wiki](http://akkera102.sakura.ne.jp/gbadev/) 140 | - [情報システム設計演習-携帯型ゲームプログラミング-](http://jaco.ec.t.kanazawa-u.ac.jp/edu/GBA/) 141 | - [ultimate-tutorial-2](https://tutorial.feuniverse.us/) 142 | - [ARM7TDMI](https://ngmansion.github.io/hokanko/ARM7TDMI/) 143 | - [ARM のスタックについて](http://masahir0y.blogspot.com/2012/11/arm.html) 144 | - [Assembler for the GBA](https://github.com/Touched/asm-tutorial/blob/master/doc.md) 145 | - [Tonc v1.4.2](https://www.coranac.com/tonc/text/toc.htm) 146 | - [hkpr.info](https://hkpr.info/ds/wiki/index.php) 147 | - [mGBA](https://mgba.io/) 148 | - [NanoBoyAdvance](https://github.com/fleroviux/NanoBoyAdvance) 149 | - [VisualBoyAdvance-m](https://github.com/visualboyadvance-m/visualboyadvance-m) 150 | - [loveemu labo](https://loveemu.hatenablog.com/) 151 | -------------------------------------------------------------------------------- /arm7tdmi/alignment.md: -------------------------------------------------------------------------------- 1 | # メモリのアラインメント 2 | 3 | CPUは、アラインメントされていないアドレスへのアクセスをサポートしていません。実際にアクセスした場合、2回に分けてデータにアクセスしなければならないため、かえって遅くなります 4 | 5 | コードやデータをメモリに読み書きする際には、ワードやハーフワードは、32bitのワードは4の倍数、16bitのハーフワードは2の倍数というように、アラインメントされたメモリアドレスに配置する必要があります。 6 | 7 | ## Mis-aligned STR,STRH,STM,LDM,LDRD,STRD,PUSH,POP (forced align) 8 | 9 | STR,STRH,STM,LDM,LDRD,STRD,PUSH,POPの場合、アライメントのずれた下位ビットは無視され、メモリアクセスは強制的にアラインメントされた(切り捨てられた)メモリアドレスになります。 10 | 11 | LDRD/STRDの場合、アドレスを8の倍数に揃える必要があるかどうかは明確に定義されていません。NDSでは4の倍数で問題ないようです。64bitデータバスを持つ他のCPUでは8の倍数のアラインメントが必要な場合もあります。 12 | 13 | ## Mis-aligned LDR,SWP (rotated read) 14 | 15 | LDR,SWPでアラインメントされていないアドレスに対してメモリアクセスした場合、まず、`addr AND (NOT 3)`と強制的にアラインメントされたアドレスからデータを読み取り、その後で、`ROR (addr AND 3)*8`によってデータを回転させます。 16 | 17 | この仕組みは、LDRBとLDRHで不要なbitをクリアするために、内部的に利用されています。 18 | 19 | SWPは、LDRとSTRを組み合わせたような動作をします。つまり、読み出しは結果を回転させますが、書き込みは書き込む値を回転させません。 20 | 21 | ## Mis-aligned LDRH,LDRSH 22 | 23 | ARM9(ARMv5) on NDS9 の場合、 24 | 25 | ``` 26 | LDRH Rd,[odd] --> LDRH Rd,[odd-1] 27 | LDRSH Rd,[odd] --> LDRSH Rd,[odd-1] 28 | ``` 29 | 30 | と強制的にアラインメントされます。 31 | 32 | ARM7(ARMv4) on NDS7/GBA の場合、 33 | 34 | ``` 35 | LDRH Rd,[odd] --> LDRH Rd,[odd-1] ROR 8 ; read to bit0-7 and bit24-31 36 | LDRSH Rd,[odd] --> LDRSB Rd,[odd] ; sign-expand BYTE value 37 | ``` 38 | 39 | ## Mis-aligned PC/R15 (branch opcodes, or MOV/ALU/LDR with Rd=R15) 40 | 41 | ARMコードの場合、ターゲットアドレスの下位ビットは通常0でなければならず、そうでない場合は下位2ビットをクリアすることでR15を強制的にアラインメントします。 42 | 43 | THUMBコードの場合、ターゲットアドレスの下位1ビットがセットされ、そのビットがTHUMBビットとして解釈され(または解釈されない)、下位1ビットをクリアすることでR15が強制的にアラインされます。 44 | 45 | つまり、R15は常に強制的にアラインメントされるので、アラインメントされていない分岐命令は、R15または`[R15+disp]`をオペランドとして使用する後続のオペコードに影響を与えません。 46 | -------------------------------------------------------------------------------- /arm7tdmi/arm/alu.md: -------------------------------------------------------------------------------- 1 | # ALU 2 | 3 | ## 📜 命令のフォーマット 4 | 5 | ### I=0 6 | 7 | このとき、2個目のオペランドにはレジスタを指定します 8 | 9 | bit | 内容 10 | ---- | ---- 11 | 31-28 | 条件 12 | 27-26 | ALU命令では必ず0 13 | 25 | 0 (I - 2個目のオペランドにレジスタ) 14 | 24-21 | オペコード(後述) (0x0-0xf) 15 | 20 | S - Set Condition Codes (0=No, 1=Yes) (Must be 1 for opcode 8-B) 16 | 19-16 | Rn - 第一オペランドのレジスタ番号 (R0..R15) MOV/MVNのときは必ず0になる 17 | 15-12 | Rd - 演算結果を格納するレジスタ番号 (R0..R15) CMP/CMN/TST/TEQ{P}のときは必ず0(または15)になる 18 | 11-7 | 後述 19 | 6-5 | シフトの種類 (0=LSL, 1=LSR, 2=ASR, 3=ROR) 20 | 4 | R - シフト量を示すのにレジスタを使うか即値を使うか (0=即値, 1=レジスタ) 21 | 3-0 | Rm - 2個目のオペランドとなるレジスタの番号 22 | 23 | 11-7bitは 24 | 25 | - Rが0のとき: シフト量を表す即値(1-31, 0は後述) 26 | - Rが1のとき: bit11-8はシフト量が入っているレジスタ、 bit7は必ず0になります 27 | 28 | **アセンブリの例** 29 | 30 | ```asm 31 | シフト量がレジスタ: 32 | and r1, r2, r3, lsl r4 ; r1 = r2 & (r3 << r4) 33 | 34 | シフト量が即値: 35 | and r1, r2, r3, lsl #2 ; r1 = r2 & (r3 << 0x2) 36 | ``` 37 | 38 | ### I=1 39 | 40 | このとき、2個目のオペランドには即値を指定する 41 | 42 | bit | 内容 43 | ---- | ---- 44 | 31-28 | 条件 45 | 27-26 | ALU命令では必ず0 46 | 25 | 1 (I - 2個目のオペランドに即値) 47 | 24-21 | オペコード(後述) (0x0-0xf) 48 | 20 | S - Set Condition Codes (0=No, 1=Yes) (Must be 1 for opcode 8-B) 49 | 19-16 | Rn - 第一オペランドのレジスタ番号 (R0..R15) MOV/MVNのときは必ず0になる 50 | 15-12 | Rd - 演算結果を格納するレジスタ番号 (R0..R15) CMP/CMN/TST/TEQ{P}のときは必ず0(または15)になる 51 | 11-8 | Is - nnをRORシフトする量(0-30) 52 | 7-0 | nn - 2個目のオペランドとなる8bitの即値 53 | 54 | **アセンブリの例** 55 | 56 | ```asm 57 | バイナリが 03 13 02 E2 のとき: 58 | and r1, r2, #0xc000000 ; r1 = r2 & ROR(r3, 3) 59 | ``` 60 | 61 | ### オペコード(24-21bit) 62 | 63 | 値 | フォーマット | 処理内容 64 | ---- | ---- | ---- 65 | 0x00 | AND{cond}{S} Rd,Rn,Op2 | Rd = Rn AND Op2 66 | 0x01 | EOR{cond}{S} Rd,Rn,Op2 | Rd = Rn XOR Op2 67 | 0x02 | SUB{cond}{S} Rd,Rn,Op2 | Rd = Rn-Op2 68 | 0x03 | RSB{cond}{S} Rd,Rn,Op2 | Rd = Op2-Rn 69 | 0x04 | ADD{cond}{S} Rd,Rn,Op2 | Rd = Rn+Op2 70 | 0x05 | ADC{cond}{S} Rd,Rn,Op2 | Rd = Rn+Op2+Cy 71 | 0x06 | SBC{cond}{S} Rd,Rn,Op2 | Rd = Rn-Op2+Cy-1 72 | 0x07 | RSC{cond}{S} Rd,Rn,Op2 | Rd = Op2-Rn+Cy-1 73 | 0x08 | TST{cond}{P} Rn,Op2 | Void = Rn AND Op2 74 | 0x09 | TEQ{cond}{P} Rn,Op2 | Void = Rn XOR Op2 75 | 0x0a | CMP{cond}{P} Rn,Op2 | Void = Rn-Op2 76 | 0x0b | CMN{cond}{P} Rn,Op2 | Void = Rn+Op2 77 | 0x0c | ORR{cond}{S} Rd,Rn,Op2 | Rd = Rn OR Op2 78 | 0x0d | MOV{cond}{S} Rd,Op2 | Rd = Op2 79 | 0x0e | BIC{cond}{S} Rd,Rn,Op2 | Rd = Rn AND NOT Op2 80 | 0x0f | MVN{cond}{S} Rd,Op2 | Rd = NOT Op2 81 | 82 | ## 🔴 2個目のオペランド(Op2) 83 | 84 | 25bitや11-0bitを見るとわかるように2個目のオペランドは基本的に、レジスタ値、シフトされたレジスタ値、またはシフトされた即値 となります。 85 | 86 | また、レジスタ値のシフト量は、レジスタ値の場合と即値の場合があります。 87 | 88 | - レジスタ値: Op2は`Rm`と表記されます、アセンブラでは`Rm,LSL#0`と表されます。 89 | - シフトされたレジスタ値: `Rm,SSS#Is` または `Rm,SSS Rs`と表されます (SSS=LSL/LSR/ASR/ROR) 90 | - 即値: `#000NN000h`のように表します。(このとき `#0NNh,ROR#0ssh`), for example: "#000NN000h", assembler should automatically convert into "#0NNh,ROR#0ssh" as far as possible (ie. as far as a section of not more than 8bits of the immediate is non-zero). 91 | 92 | ## 🔴 シフト量が0のとき 93 | 94 | 2個目のオペランドがレジスタで、シフト量を即値で表す場合、シフト量が0のときは特殊な処理になります。 95 | 96 | ``` 97 | LSL#0: シフトは行われません。 つまり、Op2=Rmとなりキャリーの値は不変です。 98 | LSR#0: LSR#32として解釈されます。つまり、Op2が0になったとき、キャリーはRmの31bitが入ります。 99 | ASR#0: ASR#32として解釈されます。つまり、Op2とキャリーはRmの31bitが入ります。 100 | ROR#0: ROR#1 と同様に RRX#1 (RCR) と解釈されますが、Op2の31bitは古いキャリーの値になります。 101 | ``` 102 | 103 | ## Using R15 (PC) 104 | 105 | R15をターゲットレジスタ(Rd)として使用する場合は、以下のCPSRの説明と実行時間の説明に注意してください。 106 | 107 | R15をオペランド(Rm or Rn)として使う場合、R15の値は次のようになります。 108 | 109 | ``` 110 | I=0,R=1 のとき: 111 | R15 => PC+12 112 | 113 | それ以外のとき: 114 | R15 => PC+8 115 | ``` 116 | 117 | ## 🚩 フラグの変更 118 | 119 | ### S=1, Rd≠R15, 論理命令 のとき: 120 | 121 | 該当するのは、AND,EOR,TST,TEQ,ORR,MOV,BIC,MVN 122 | 123 | - V = 不変 124 | - C = シフト処理の場合のみ、キャリー (LSL#0 や Rs=0x00 の場合は不変) 125 | - Z = 演算結果がゼロ 126 | - N = 演算結果がマイナス(bit31が1) 127 | 128 | ### S=1, Rd≠R15, 算術命令 のとき: 129 | 130 | 該当するのは、SUB,RSB,ADD,ADC,SBC,RSC,CMP,CMN 131 | 132 | - V = 演算結果がオーバーフローしたか 133 | - C = 演算結果のキャリー 134 | - Z = 演算結果がゼロ 135 | - N = 演算結果がマイナス(bit31が1) 136 | 137 | ### S=1, with unused Rd bits=1111b, オペコードが CMPP/CMNP/TSTP/TEQP のとき: 138 | 139 | - In user mode only N,Z,C,V bits of R15 can be changed. 140 | - In other modes additionally I,F,M1,M0 can be changed. 141 | - The PC bits in R15 are left unchanged in all modes. 142 | 143 | ### S=1, Rd=R15 のとき: 144 | 145 | ユーザーモード以外からユーザーモードに復帰する用途などで用いる 146 | 147 | - CPSR = `SPSR_${current_mode}` 148 | - PC = 処理結果 149 | 150 | 例: 151 | 152 | ``` 153 | MOVS PC,R14 ; SWIからの復帰 (PC=R14_svc, CPSR=SPSR_svc) 154 | ``` 155 | 156 | ### S=0 のとき 157 | 158 | フラグは全部不変 159 | 160 | ## 🔎 補足 161 | 162 | **実行時間** 163 | 164 | 実行時間: (1+p)S+rI+pN 165 | 166 | - r: 1 (`I==0 && R==1` つまりシフト量にレジスタの値を使う場合) or 0(それ以外) 167 | - p: 1 (`Rd==R15`) or 0(それ以外) 168 | 169 | **NOP** 170 | 171 | ARMステートでは`MOV R0, R0`を`NOP`命令として扱う 172 | 173 | -------------------------------------------------------------------------------- /arm7tdmi/arm/branch.md: -------------------------------------------------------------------------------- 1 | # 分岐命令 2 | 3 | B, BL, BX, SWIが該当します。 4 | 5 | ## 分岐命令(B, BL) 6 | 7 | Bはサブルーチンへのジャンプをおこないます。 8 | 9 | BLはサブルーチンの`コール`つまりリターンアドレスをR14に退避してサブルーチンへジャンプします。 10 | 11 | ビット | 内容 12 | ---- | ---- 13 | 31-28 | 条件 14 | 27-25 | 必ず0b101 15 | 24 | オペコード(後述) 16 | 23-0 | nn - 符号付きオフセット(1ごとにつき4バイト) 17 | 18 | オペコードは 19 | 20 | ``` 21 | 0: B{cond} label ; PC=PC+8+nn*4 22 | 1: BL{cond} label ; PC=PC+8+nn*4, LR=PC+4 23 | ``` 24 | 25 | フラグ: 不変 26 | 27 | 実行時間: 2S + 1N 28 | 29 | ## 特殊な分岐命令(BX) 30 | 31 | ビット | 内容 32 | ---- | ---- 33 | 31-28 | 条件 34 | 27-8 | 0b0001_0010_1111_1111_1111 35 | 7-4 | 0b0001 (`BX{cond} Rn`) 36 | 3-0 | Rn - オペランドのレジスタ番号 37 | 38 | ``` 39 | BX{cond} Rn ; PC=Rn, T=Rn.0 40 | ``` 41 | 42 | Rnのbit0を1にするとTHUMBモードにスイッチし、ジャンプ先は`Rn-1`になります。 43 | 44 | `BX R15` は `BX $+8` と同じことになります。 45 | 46 | フラグ: 不変 47 | 48 | 実行時間: 2S + 1N 49 | 50 | ## ソフトウェア割り込み命令(SWI) 51 | 52 | SWIはOSの機能を呼び出してARMステートのSVCモードに入るための命令です。 (SWI = SoftWare Interrupt) 53 | 54 | ビット | 内容 55 | ---- | ---- 56 | 31-28 | 条件 57 | 27-24 | 0b1111 `SWI{cond} nn` 58 | 23-0 | nn - コメントフィールドでプロセッサには無視されます 59 | 60 | 実行時間: 2S+1N 61 | 62 | 例外ハンドラは`[R14_svc - 4]`に退避されたSWI命令の下位24bitのコメントフィールドを自由に使うことが可能です。 63 | 64 | もしTHUMBステートでSWI命令を使った場合は、SWIハンドラは`SPSR_svc`のTを見て、SWI命令がTHUMBステートから使われたことを理解し、`[R14_svc - 2]`の指す16bitのSWI命令のうち、下位8bitをコメントフィールドとして利用します。 65 | 66 | SWIからリターンするときは`MOVS PC,R14`を実行してPCとCPSRを復帰します。(`PC=R14_svc と CPSR=SPSR_svc`) 67 | 68 | SWIがネストするときにはSWIする前に`SPSR_svc`と`R14_svc`をスタックに退避したり、(IRQハンドラがSWIを使う場合は)IRQを有効にする必要があります。 69 | 70 | SWI実行時の処理 71 | 72 | ``` 73 | R14_svc=PC+4 ; 復帰先のアドレスを退避 74 | SPSR_svc=CPSR ; CPSRを退避 75 | CPSR=${changed} ; ARMステートのSVCモードに入りIRQを無効にする 76 | PC=VVVV0008h ; SWI のベクタにジャンプする 77 | ``` 78 | 79 | ## 未定義命令例外(UND) 80 | 81 | ビット | 内容 82 | ---- | ---- 83 | 31-28 | 条件 84 | 27-25 | 0b011 85 | 24-5 | 未使用(将来使用予定) 86 | 4 | 0b1 87 | 3-0 | 未使用(将来使用予定) 88 | 89 | アセンブラでは対応するニーモニックは存在しません。 90 | 91 | - `cond011xxxxxxxxxxxxxxxxxxxx1xxxx` - 将来使用予定 92 | - `cond01111111xxxxxxxxxxxx1111xxxx` - ユーザーが自由に使えます 93 | 94 | 実行時間: 2S+1I+1N. 95 | -------------------------------------------------------------------------------- /arm7tdmi/arm/coprocessor.md: -------------------------------------------------------------------------------- 1 | # コプロセッサ命令 2 | 3 | MRC/MCR, LDC/STC, CDP, MCRR/MRRC が該当します 4 | 5 | ## Coprocessor Register Transfers (MRC, MCR) (with ARM Register read/write) 6 | 7 | MRC命令は、コプロセッサレジスタからプロセッサレジスタに読み込みを行います。 8 | 9 | MCR命令は、プロセッサレジスタからコプロセッサレジスタに書き込みを行います。 10 | 11 | ビット | 内容 12 | ---- | ---- 13 | 31-28 | 条件 (オペコードがMRC2/MCR2のときは 0b1111) 14 | 27-24 | 必ず 0b1110 15 | 23-21 | cpopc - Coprocessor operation code (0-7) 16 | 20 | オペコード(後述) 17 | 19-16 | Cn - Coprocessor source/dest. Register (C0-C15) 18 | 15-12 | Rd - 読み書き対象のARMレジスタ (R0-R15) 19 | 11-8 | Pn - 対象のコプロセッサ (P0-P15, 例: cp15 -> 15) 20 | 7-5 | cp - Coprocessor information (0-7) 21 | 4 | Reserved, must be one (1) (otherwise CDP opcode) 22 | 3-0 | Cm - Coprocessor operand Register (C0-C15) 23 | 24 | ### オペコード(20bit) 25 | 26 | 値 | フォーマット | 処理内容 27 | ---- | ---- | ---- 28 | 0b0 | `MCR{cond} Pn,,Rd,Cn,Cm{,}` | move from ARM to CoPro 29 | 0b0 | `MCR2 Pn,,Rd,Cn,Cm{,}` | move from ARM to CoPro 30 | 0b1 | `MRC{cond} Pn,,Rd,Cn,Cm{,}` | move from CoPro to ARM 31 | 0b1 | `MRC2 Pn,,Rd,Cn,Cm{,}` | move from CoPro to ARM 32 | 33 | MCR/MRCはARMv2以降、MCR2/MRC2はARMv5以降でサポートされています。 34 | 35 | A22i syntax allows to use MOV with Rd specified as first (dest), or last (source) operand. 36 | 37 | Native MCR/MRC syntax uses Rd as middle operand, \ can be ommited if \ is zero. 38 | 39 | MCRでRdにR15を指定した場合: コプロセッサには、`PC+12`が書き込まれます。 40 | 41 | MRCでRdにR15を指定した場合: Bit 31-28 of data are copied to Bit 31-28 of CPSR (ie. N,Z,C,V flags), other data bits are ignored, CPSR Bit 27-0 are not affected, R15 (PC) is not affected. 42 | 43 | 実行時間: 44 | 45 | - MCR: 1S+bI+1C 46 | - MRC: 1S+(b+1)I+1C 47 | 48 | Return: For MRC only: Either R0-R14 modified, or flags affected (see above). 49 | 50 | For details refer to original ARM docs. The opcodes are irrelevant for GBA/NDS7 because no coprocessor exists (except for a dummy CP14 unit). However, NDS9 includes a working CP15 unit. And, 3DS ARM11 uses CP10/CP11 as VFP floating point unit. 51 | 52 | ## Coprocessor Data Transfers (LDC, STC) (with Memory read/write) 53 | 54 | TODO 55 | 56 | ## Coprocessor Data Operations (CDP) (without Memory or ARM Register operand) 57 | 58 | TODO 59 | 60 | ## Coprocessor Double-Register Transfer (MCRR, MRRC) - ARMv5TE and up only 61 | 62 | TODO 63 | 64 | 65 | -------------------------------------------------------------------------------- /arm7tdmi/arm/instruction.md: -------------------------------------------------------------------------------- 1 | # ARMモードの命令一覧 2 | 3 | CPSRのフラグの更新は全ての{S}命令で省略可能です 4 | 5 | サイクルのS, Nなどについては[サイクル](./cycle.md)を参照してください。 6 | 7 | ## 論理演算 8 | 9 | 命令 | サイクル | フラグ | 処理内容 10 | ---- | ---- | ---- | ---- 11 | MOV{cond}{S} Rd,Op2 | 1S+x+y | NZc- | Rd = Op2 12 | MVN{cond}{S} Rd,Op2 | 1S+x+y | NZc- | Rd = NOT Op2 13 | ORR{cond}{S} Rd,Rn,Op2 | 1S+x+y | NZc- | Rd = Rn OR Op2 14 | EOR{cond}{S} Rd,Rn,Op2 | 1S+x+y | NZc- | Rd = Rn XOR Op2 15 | AND{cond}{S} Rd,Rn,Op2 | 1S+x+y | NZc- | Rd = Rn AND Op2 16 | BIC{cond}{S} Rd,Rn,Op2 | 1S+x+y | NZc- | Rd = Rn AND NOT Op2 17 | TST{cond}{P} Rn,Op2 | 1S+x | NZc- | Void = Rn AND Op2 18 | TEQ{cond}{P} Rn,Op2 | 1S+x | NZc- | Void = Rn XOR Op2 19 | 20 | - Op2がレジスタによってシフトされる場合、`x=1I`となります。 21 | - `Rd=R15`の場合、`y=1S+1N`となります。 22 | 23 | キャリーフラグはOp2のシフト量が1以上のときに更新されます。 24 | 25 | ## 算術演算 26 | 27 | 命令 | サイクル | フラグ | 処理内容 28 | ---- | ---- | ---- | ---- 29 | ADD{cond}{S} Rd,Rn,Op2 | 1S+x+y | NZCV | Rd = Rn+Op2 30 | ADC{cond}{S} Rd,Rn,Op2 | 1S+x+y | NZCV | Rd = Rn+Op2+Cy 31 | SUB{cond}{S} Rd,Rn,Op2 | 1S+x+y | NZCV | Rd = Rn-Op2 32 | SBC{cond}{S} Rd,Rn,Op2 | 1S+x+y | NZCV | Rd = Rn-Op2+Cy-1 33 | RSB{cond}{S} Rd,Rn,Op2 | 1S+x+y | NZCV | Rd = Op2-Rn 34 | RSC{cond}{S} Rd,Rn,Op2 | 1S+x+y | NZCV | Rd = Op2-Rn+Cy-1 35 | CMP{cond}{P} Rn,Op2 | 1S+x | NZCV | Void = Rn-Op2 36 | CMN{cond}{P} Rn,Op2 | 1S+x | NZCV | Void = Rn+Op2 37 | 38 | - Op2がレジスタによってシフトされる場合、`x=1I`となります。 39 | - `Rd=R15`の場合、`y=1S+1N`となります。 40 | 41 | ## 乗算 42 | 43 | 命令 | サイクル | フラグ | 処理内容 44 | ---- | ---- | ---- | ---- 45 | MUL{cond}{S} Rd,Rm,Rs | 1S+mI | NZx- | Rd = Rm×Rs 46 | MLA{cond}{S} Rd,Rm,Rs,Rn | 1S+mI+1I | NZx- | Rd = Rm×Rs+Rn 47 | UMULL{cond}{S} RdLo,RdHi,Rm,Rs | 1S+mI+1I | NZx- | RdHiLo = Rm×Rs 48 | UMLAL{cond}{S} RdLo,RdHi,Rm,Rs | 1S+mI+2I | NZx- | RdHiLo = Rm×Rs+RdHiLo 49 | SMULL{cond}{S} RdLo,RdHi,Rm,Rs | 1S+mI+1I | NZx- | RdHiLo = Rm×Rs 50 | SMLAL{cond}{S} RdLo,RdHi,Rm,Rs | 1S+mI+2I | NZx- | RdHiLo = Rm×Rs+RdHiLo 51 | 52 | ## ロード/ストア 53 | 54 | 命令 | サイクル | フラグ | 処理内容 55 | ---- | ---- | ---- | ---- 56 | LDR{cond}{B}{T} Rd,\${Addr} | 1S+1N+1I+y | ---- | Rd=\[Rn+/-${offset}\] 57 | LDR{cond}H Rd,${Addr} | 1S+1N+1I+y | ---- | Load Unsigned halfword 58 | LDR{cond}SB Rd,${Addr} | 1S+1N+1I+y | ---- | Load Signed byte 59 | LDR{cond}SH Rd,${Addr} | 1S+1N+1I+y | ---- | Load Signed halfword 60 | LDM{cond}{amod} Rn{!},${Rlist}{^} | nS+1N+1I+y | ---- | Load Multiple 61 | STR{cond}{B}{T} Rd,\${Addr} | 2N | ---- | \[Rn+/-${offset}]=Rd 62 | STR{cond}H Rd,${Addr} | 2N | ---- | Store halfword 63 | STM{cond}{amod} Rn{!},${Rlist}{^} | (n-1)S+2N | ---- | Store Multiple 64 | SWP{cond}{B} Rd,Rm,\[Rn] | 1S+2N+1I | ---- | Rd=\[Rn], \[Rn]=Rm 65 | 66 | LDR/LDMでは、`Rd=R15` または `R15 in Rlist` のとき、`y=1S+1N` となります。 67 | 68 | ## ジャンプ、コール、CPSRモード、その他 69 | 70 | 命令 | サイクル | フラグ | 処理内容 71 | ---- | ---- | ---- | ---- 72 | B{cond} label | 2S+1N | ---- | PC=$+8+/-32M 73 | BL{cond} label | 2S+1N | ---- | PC=\$+8+/-32M, LR=$+4 74 | BX{cond} Rn | 2S+1N | ---- | PC=Rn, T=Rn.0 (THUMB/ARM) 75 | MRS{cond} Rd,Psr | 1S | ---- | Rd=Psr 76 | MSR{cond} Psr{_field},Op | 1S | (psr) | Psr\[field]=Op 77 | SWI{cond} Imm24bit | 2S+1N | ---- | PC=8, ARM Svc mode, LR=$+4 78 | The Undefined Instruction | 2S+1I+1N | ---- | PC=4, ARM Und mode, LR=$+4 79 | cond=false | 1S | ---- | Any opcode with condition=false 80 | NOP | 1S | ---- | R0=R0 81 | -------------------------------------------------------------------------------- /arm7tdmi/arm/loadstore.md: -------------------------------------------------------------------------------- 1 | # ロード/ストア命令 2 | 3 | LDR, STR が該当します 4 | 5 | LDRH, LDRSB, LDRSH, STRH は [その2](./loadstore2.md)で解説しています。 6 | 7 | LDM, STM は [その3](./loadstore3.md)で解説しています。 8 | 9 | ## 📜 命令のフォーマット 10 | 11 | ### LDR 12 | 13 | `Rd=[Rn + offset]` or `Rd=[Rn - offset]` 14 | 15 | メモリから1byte読み込む時は、Rdの上位24bitは0埋めされます。 16 | 17 | #### I=0 18 | 19 | I(Immediate)というフラグ名ですが、**I=0のときにオフセットに即値**を用いることに注意 20 | 21 | bit | 内容 22 | ---- | ---- 23 | 31-28 | 条件 24 | 27-26 | 0b01 25 | 25 | 0 (I - オフセットは即値) 26 | 24 | P - Post/Pre (後述 0=post 1=pre) 27 | 23 | U - マイナス(-offset) か プラス(+offset) か (0=マイナス, 1=プラス) 28 | 22 | B - ロードの単位(0=32bit, 1=8bit) 29 | 21 | [後述](#-bit21について) 30 | 20 | 1 (オペコード `LDR{cond}{B}{T} Rd, ${Addr}`) 31 | 19-16 | Rn - ベースレジスタ (R0..R15) (このとき R15はPC+8) 32 | 15-12 | Rd - ターゲットレジスタ (R0..R15) (このとき R15はPC+12) 33 | 11-0 | 符号無し12bitのオフセット (0-4095) 34 | 35 | #### I=1 36 | 37 | I(Immediate)というフラグ名ですが、**I=1のときにオフセットにレジスタ**を用いることに注意 38 | 39 | bit | 内容 40 | ---- | ---- 41 | 31-28 | 条件 42 | 27-26 | 0b01 43 | 25 | 1 (I - オフセットはレジスタ) 44 | 24 | P - Post/Pre (後述 0=post 1=pre) 45 | 23 | U - マイナス(-offset) か プラス(+offset) か (0=マイナス, 1=プラス) 46 | 22 | B - ロードの単位(0=32bit, 1=8bit) 47 | 21 | [後述](#-bit21について) 48 | 20 | 1 (オペコード `LDR{cond}{B}{T} Rd, ${Addr}`) 49 | 19-16 | Rn - ベースレジスタ (R0..R15) (このとき R15はPC+8) 50 | 15-12 | Rd - ターゲットレジスタ (R0..R15) (このとき R15はPC+12) 51 | 11-7 | Is - シフト量 (1-31, 0=ALUと同じ) 52 | 6-5 | シフトの種類 (0=LSL, 1=LSR, 2=ASR, 3=ROR) 53 | 4 | 0b0 54 | 3-0 | Rm - オフセットを格納したレジスタ (R0..R14) 55 | 56 | ### STR 57 | 58 | `[Rn + offset]=Rd` または `[Rn - offset]=Rd` 59 | 60 | メモリに32bit書き込みをする場合、対象のメモリアドレスはword単位のアラインメントをしておく必要があります。 61 | 62 | #### I=0 63 | 64 | bit | 内容 65 | ---- | ---- 66 | 31-28 | 条件 67 | 27-26 | 0b01 68 | 25 | 0 (I - オフセットは即値) 69 | 24 | P - Post/Pre (後述 0=post 1=pre) 70 | 23 | U - マイナス(-offset) か プラス(+offset) か (0=マイナス, 1=プラス) 71 | 22 | B - ストアの単位(0=32bit, 1=8bit) 72 | 21 | [後述](#-bit21について) 73 | 20 | 0 (オペコード `STR{cond}{B}{T} Rd, ${Addr}`) 74 | 19-16 | Rn - ベースレジスタ (R0..R15) (このとき R15はPC+8) 75 | 15-12 | Rd - ターゲットレジスタ (R0..R15) (このとき R15はPC+12) 76 | 11-0 | 符号無し12bitのオフセット (0-4095) 77 | 78 | #### I=1 79 | 80 | bit | 内容 81 | ---- | ---- 82 | 31-28 | 条件 83 | 27-26 | 0b01 84 | 25 | 1 (I - オフセットはレジスタ) 85 | 24 | P - Post/Pre (後述 0=post 1=pre) 86 | 23 | U - マイナス(-offset) か プラス(+offset) か (0=マイナス, 1=プラス) 87 | 22 | B - ストアの単位(0=32bit, 1=8bit) 88 | 21 | [後述](#-bit21について) 89 | 20 | 0 (オペコード `STR{cond}{B}{T} Rd, ${Addr}`) 90 | 19-16 | Rn - ベースレジスタ (R0..R15) (このとき R15はPC+8) 91 | 15-12 | Rd - ターゲットレジスタ (R0..R15) (このとき R15はPC+12) 92 | 11-7 | Is - シフト量 (1-31, 0=ALUと同じ) 93 | 6-5 | シフトの種類 (0=LSL, 1=LSR, 2=ASR, 3=ROR) 94 | 4 | 0b0 95 | 3-0 | Rm - オフセットを格納したレジスタ (R0..R14) 96 | 97 | ## 🔴 Post/Preについて 98 | 99 | - Post: add offset after transfer 100 | - Pre: before trans. 101 | 102 | ## 🔴 bit21について 103 | 104 | bit21は P(bit24)の値によって意味が変わってきます。 105 | 106 | ### P=0(Post)のとき 107 | 108 | bit21はメモリ管理の仕方を表すフラグ(T)となります。 109 | 110 | - 0: Normal 111 | - 1: Force non-privileged access 112 | 113 | ### P=1(Pre)のとき 114 | 115 | bit21はライトバックの有無を表すフラグ(W)となります。 116 | 117 | - 0: ライトバックしない 118 | - 1: Rnにアドレスをライトバックする 119 | 120 | ## 🛠 アセンブリ 121 | 122 | アセンブリでロード/ストア命令を表す表記について説明します。 123 | 124 | ### Preアドレッシング(P=0) 125 | 126 | ``` 127 | [Rn] ; offset = 0 128 | [Rn, <#{+/-}expression>]{!} ; offset = 即値 129 | [Rn, {+/-}Rm{,} ]{!} ; offset = Isだけシフトされたレジスタ 130 | ``` 131 | 132 | ### Postアドレッシング(P=1) 133 | 134 | ``` 135 | [Rn], <#{+/-}expression> ;offset = immediate 136 | [Rn], {+/-}Rm{,} ;offset = register shifted by immediate 137 | ``` 138 | 139 | ### その他 140 | 141 | ``` 142 | immediate shift such like LSL#4, ROR#2, etc. (see ALU opcodes). 143 | {!} exclamation mark ("!") indicates write-back (Rn will be updated). 144 | ``` 145 | 146 | ## 🔎 補足 147 | 148 | シフト量が0のときは特殊な挙動となります。詳しくは[ALU](./alu.md)を参照 149 | 150 | フラグ: 151 | 152 | - 不変(v4) 153 | - v5では `LDR PC, $op`を実行した時に Tフラグに $opのbit0が格納されます 154 | 155 | 実行時間: 156 | 157 | - LDR: 1S+1N+1I 158 | - STR: 2N 159 | 160 | ## PLD 161 | 162 | PLD = Prepare Cache for Load 163 | 164 | PLD must use following settings cond=1111b, P=1, B=1, W=0, L=1, Rd=1111b, the address may not use post-indexing, and may not use writeback, the opcode is encoded identical as `LDRNVB R15,
`. 165 | 166 | PLDは、特定のメモリアドレスが間もなくアクセスされることをメモリシステムに知らせ、メモリシステムはこのヒントを利用してキャッシングやパイプライニングの準備をすることができます。それ以外は、PLDはプログラムロジックに何の影響も与えず、NOPと同じ動作をします。 167 | 168 | PLDはARMv5TE以降でのみサポートされており、ARMv5やARMv5TExPではサポートされていません。 169 | -------------------------------------------------------------------------------- /arm7tdmi/arm/loadstore2.md: -------------------------------------------------------------------------------- 1 | # ロード/ストア命令 その2 2 | 3 | ロード/ストア命令のうち、LDRH, LDRSB, LDRSH, STRHについて解説します 4 | 5 | LDRとSTRは転送単位がWord(32bit)かByte(8bit)でしたが、こちらは 6 | 7 | ``` 8 | LDRH = LDR + Halfword 9 | LDRSB = LDR + Signed Byte 10 | LDRSH = LDR + Signed Halfword 11 | STRH = STR + Halfword 12 | ``` 13 | 14 | のとおり転送単位や符号が異なります 15 | 16 | ## 📜 命令のフォーマット 17 | 18 | ### I=0 19 | 20 | bit | 内容 21 | ---- | ---- 22 | 31-28 | 条件 23 | 27-25 | 0b000 24 | 24 | P - Post/Pre (後述 0=post 1=pre) 25 | 23 | U - マイナス(-offset) か プラス(+offset) か (0=マイナス, 1=プラス) 26 | 22 | 0b0 (I - オフセットはレジスタ) 27 | 21 | [後述](#-bit21について) 28 | 20 | L - 読み出しか書き出しか (0=書き出し, 1=読み出し) 29 | 19-16 | Rn - ベースレジスタ (R0..R15) (このとき R15はPC+8) 30 | 15-12 | Rd - ターゲットレジスタ (R0..R15) (このとき R15はPC+12) 31 | 11-8 | 0b0000 32 | 7 | 0b1 33 | 6-5 | [オペコード](#-オペコード) 34 | 4 | 0b1 35 | 3-0 | Rm - オフセットを格納したレジスタ (R0..R14) 36 | 37 | ### I=1 38 | 39 | bit | 内容 40 | ---- | ---- 41 | 31-28 | 条件 42 | 27-25 | 0b000 43 | 24 | P - Post/Pre (後述 0=post 1=pre) 44 | 23 | U - マイナス(-offset) か プラス(+offset) か (0=マイナス, 1=プラス) 45 | 22 | 0b1 (I - オフセットは即値) 46 | 21 | [後述](#-bit21について) 47 | 20 | L - 読み出しか書き出しか (0=書き出し, 1=読み出し) 48 | 19-16 | Rn - ベースレジスタ (R0..R15) (このとき R15はPC+8) 49 | 15-12 | Rd - ターゲットレジスタ (R0..R15) (このとき R15はPC+12) 50 | 11-8 | オフセット(上位4bit) 51 | 7 | 0b1 52 | 6-5 | [オペコード](#-オペコード) 53 | 4 | 0b1 54 | 3-0 | オフセット(下位4bit) 55 | 56 | ## 🔴 オペコード 57 | 58 | L(bit20)は 59 | 60 | - 0: メモリへのストア 61 | - 1: メモリからのロード 62 | 63 | 値 | L | フォーマット | 処理内容 | 備考 64 | ---- | ---- | ---- | ---- | ---- 65 | 0 | 0 | -- | 未使用 | -- 66 | 1 | 0 | STR{cond}H Rd, ${Addr} | \[a\]=Rd | ハーフワードの格納 67 | 2 | 0 | LDR{cond}D Rd, ${Addr} | R(d)=\[a\], R(d+1)=\[a+4\] | ダブルワードの読み込み 68 | 3 | 0 | STR{cond}D Rd, ${Addr} | \[a\]=R(d), \[a+4\]=R(d+1) | ダブルワードの格納 69 | 0 | 1 | -- | 未使用 | -- 70 | 1 | 1 | LDR{cond}H Rd, ${Addr} | Rd=\[a\] | ハーフワードの読み込み 71 | 2 | 1 | LDR{cond}SB Rd, ${Addr} | -- | 符号付きバイトの読み込み 72 | 3 | 1 | LDR{cond}SH Rd, ${Addr} | Rd=\[a\] | 符号付きハーフワードの読み込み 73 | 74 | 32bitに満たないロードの場合、レジスタの上位部分は0埋めされます。 75 | 76 | ## 🔴 bit21について 77 | 78 | bit21は P(bit24)の値によって意味が変わってきます。 79 | 80 | ### P=0(Post)のとき 81 | 82 | bit21は使われず、必ず0となります。 83 | 84 | ### P=1(Pre)のとき 85 | 86 | bit21はライトバックの有無を表すフラグ(W)となります。 87 | 88 | - 0: ライトバックしない 89 | - 1: Rnにアドレスをライトバックする 90 | 91 | ## 🔎 補足 92 | 93 | フラグ: 不変 94 | 95 | 実行時間: 96 | 97 | - LDR系: 1S+1N+1I 98 | - LDR系でRdがPC: 2S+2N+1I 99 | - STRH: 2N 100 | 101 | -------------------------------------------------------------------------------- /arm7tdmi/arm/loadstore3.md: -------------------------------------------------------------------------------- 1 | # ロード/ストア命令 その3 2 | 3 | ロード/ストア命令のうち、スタックに関連する命令であるLDM, STMについて解説します 4 | 5 | まずARMのスタックについて説明します。 6 | 7 | ## スタックのポリシー 8 | 9 | まずは一般論から説明します。 10 | 11 | Stack Pointer の指している先にデータがあるかないかで以下のように分かれます 12 | 13 | - Full Stack: Stack Pointer は最後に使用された位置を指している 14 | - Empty Stack: Stack Pointer は未使用な最初の位置を指している 15 | 16 | また、アドレスが小さくなる方に成長するか、アドレスが大きくなる方に成長するかで以下のように分かれます。 17 | 18 | - 下降スタック: メモリアドレスの降順に増加 19 | - 上昇スタック: メモリアドレスの昇順に増加 20 | 21 | だから、スタックのポリシー的には 2×2=4 通りが可能ということになります。 22 | 23 | ## ARMのスタックとそれに関する命令 24 | 25 | ARMではスタックを表現するのに **Full&下降スタック** を使うようです。 26 | 27 | `LDM`, `STM`命令はスタックのポリシーを考慮してさまざまな表記があります。 28 | 29 | まず表記法として、非スタックアドレッシングとスタックアドレッシングがあります。 30 | 31 | 非スタックアドレッシングは 32 | 33 | - LDMDA (Decrement After) 34 | - LDMIA (Increment After) 35 | - LDMDB (Decrement Before) 36 | - LDMIB (Increment Before) 37 | - STMDA (Decrement After) 38 | - STMIA (Increment After) 39 | - STMDB (Decrement Before) 40 | - STMIB (Increment Before) 41 | 42 | という表記になります。 43 | 44 | 上で述べたようにARMでは Fullスタック、下降スタックを採用するというので、 pushするときにはSTMDB命令を使用し、 popするときにはLDMIA命令を使用しないといけません。 45 | 46 | これらのことを毎回考えるのは面倒なので、スタックアドレッシングの表記も用意されています。 47 | 48 | - LDMFA (Full Ascending) 49 | - LDMFD (Full Desending) 50 | - LDMEA (Empty Ascending) 51 | - LDMFD (Empty Descending) 52 | - STMFA (Full Ascending) 53 | - STMFD (Full Desending) 54 | - STMEA (Empty Ascending) 55 | - STMFD (Empty Descending) 56 | 57 | 非スタックアドレッシングとスタックアドレッシングの関係は次のようになります。 58 | 59 | ``` 60 | Non-stack | Stack adressing 61 | LDMDA = LDMFA 62 | LDMIA = LDMFD (= pop) 63 | LDMDB = LDMEA 64 | LDMIB = LDMED 65 | STMDA = STMED 66 | STMIA = STMEA 67 | STMDB = STMFD (= push) 68 | STMIB = STMFA 69 | ``` 70 | 71 | ## フォーマット 72 | 73 | bit | 内容 74 | ---- | ---- 75 | 31-28 | 条件 76 | 27-25 | 0b100 77 | 24 | P - Post/Pre (後述 0=post 1=pre) 78 | 23 | U - Up/Down Bit (0=down; subtract offset from base, 1=up; add to base) 79 | 22 | S - PSR & force user bit (0=No, 1=load PSR or force user mode) 80 | 21 | W - Write-back bit (0=no write-back, 1=write address into base) 81 | 20 | L - オペコード 82 | 19-16 | Rn - ベースレジスタ (R0-R14) 83 | 15-0 | Rlist - レジスタのリスト 84 | 85 | ### オペコード(bit20) 86 | 87 | - `{amod}`については後述 88 | - `{!}`: Write-Back (W) 89 | - `{^}`: PSR/User Mode (S) 90 | 91 | ``` 92 | 0: STM{cond}{amod} Rn{!},{^} ; Store (Push) 93 | 1: LDM{cond}{amod} Rn{!},{^} ; Load (Pop) 94 | ``` 95 | 96 | フラグ: 不変 97 | 98 | 実行時間(n=転送する合計ワード数): 99 | 100 | - LDM: nS+1N+1I 101 | - LDM PC: (n+1)S+2N+1I 102 | - STM: (n-1)S+2N 103 | 104 | ## アドレッシング {amod} 105 | 106 | PとUのbitの組み合わせで、IB,IA,DB,DAといったアドレッシングを指定します。 107 | 108 | Suffix | expl | P | U 109 | -- | -- | -- | -- 110 | IB | increment before | 1 | 1 111 | IA | increment after | 0 | 1 112 | DB | decrement before | 1 | 0 113 | DA | decrement after | 0 | 0 114 | 115 | 例: 116 | 117 | ``` 118 | LDMIA r13!, {r4-r7, r9, r15} 119 | STMDB r13!, {r4-r7, r9, r14} 120 | ``` 121 | 122 | ### アセンブリ 123 | 124 | 上で述べたように、`LDM`, `STM`命令にはaliasがあるものが存在します。これらはアセンブリの記述に使用可能で同じものとして扱われます。 125 | 126 | 例えば `STMDB r13!, {r4-r7, r9, r14}` という命令は 127 | 128 | - `STMFD r13!, {r4-r7, r9, r14}` 129 | - `push {r4-r7, r9, r14}` 130 | 131 | と書けます。 132 | 133 | ## 順番 134 | 135 | Rlistのレジスタはレジスタ番号が低いものが、 136 | 137 | - 低いアドレスからロードを行う 138 | - 低いアドレスにストアされる 139 | 140 | 順番で処理されます。 141 | 142 | **例** 143 | 144 | ``` 145 | STMDB r13!, {r4-r7, r9, r14} 146 | -> STMDBするたびにストア先のアドレスが小さくなっていくので r14 -> r9 -> r7 -> ... -> r4 の順番 147 | STMIA r13!, {r4-r7, r9, r14} 148 | -> STMIAするたびにストア先のアドレスが大きくなっていくので r4 -> r5 -> ... -> r14 の順番 149 | LDMIB r13!, {r4-r7, r9, r15} 150 | -> LDMIBするたびに読み出し元のアドレスが大きくなっていくので r4 -> r5 -> ... -> r15 の順番 151 | LDMDA r13!, {r4-r7, r9, r15} 152 | -> LDMDAするたびに読み出し元のアドレスが小さくなっていくので r15 -> r9 -> ... -> r4 の順番 153 | ``` 154 | 155 | ## When S Bit is set (S=1) 156 | 157 | ### LDMでRlistにR15が含まれるとき 158 | 159 | モードが変化します。 160 | 161 | R15のロード時に、自動的に`CPSR=SPSR_${current_mode}`が行われます。 162 | 163 | ### それ以外のとき (User bank transfer) 164 | 165 | RlistはユーザーバンクレジスタのR0~R15を指します。(R14_svcなどの現在のモードに関連するレジスタではありません) 166 | 167 | Base write-back should not be used for User bank transfer. 168 | 169 | **注意(LDMのときのみ)** 170 | 171 | LDMの次の命令がバンクされたレジスタ(例:R14_svc)から読み出す場合、CPUは代わりにR14を読み出す可能性があり、必要に応じてダミーのNOPを挿入します。 172 | 173 | -------------------------------------------------------------------------------- /arm7tdmi/arm/multiply.md: -------------------------------------------------------------------------------- 1 | # 乗算 2 | 3 | MUL, 4 | 5 | ## 命令のフォーマット 6 | 7 | ### ワード単位 8 | 9 | bit | 内容 10 | ---- | ---- 11 | 31-28 | 条件 12 | 27-25 | 0b000 13 | 24-21 | オペコード 14 | 20 | S - Set Condition Codes (0=No, 1=Yes) (Must be 0 for Halfword & UMAAL) 15 | 19-16 | Rd or RdHi - 演算結果を格納するレジスタ 16 | 15-12 | Rn or RdLo - 演算レジスタ (使わないときは0b000) 17 | 11-8 | Rs - オペランドレジスタ 18 | 7-4 | 0b1001 19 | 3-0 | Rm - オペランドレジスタ 20 | 21 | ### ハーフワード単位 22 | 23 | bit | 内容 24 | ---- | ---- 25 | 31-28 | 条件 26 | 27-25 | 0b000 27 | 24-21 | オペコード 28 | 20 | 0b0 29 | 19-16 | Rd or RdHi - 演算結果を格納するレジスタ 30 | 15-12 | Rn or RdLo - 演算レジスタ (使わないときは0b000) 31 | 11-8 | Rs - オペランドレジスタ 32 | 7 | 0b1 33 | 6 | y - Rsの下位16bitと上位16bitのどちらを使うか(0=下位, 1=上位) 34 | 5 | x - Rmの下位16bitと上位16bitのどちらを使うか(0=下位, 1=上位) 35 | 4 | 0b0 36 | 3-0 | Rm - オペランドレジスタ 37 | 38 | ### オペコード(24-21bit) 39 | 40 | 値 | フォーマット | 処理内容 | 備考 41 | ---- | ---- | ---- | ---- 42 | 0b0000 | MUL{cond}{S} Rd,Rm,Rs | Rd=Rm*Rs | 符号関係なし 43 | 0b0001 | MLA{cond}{S} Rd,Rm,Rs,Rn | Rd=Rm*Rs+Rn | 符号関係なし 44 | 0b0010 | UMAAL{cond} RdLo,RdHi,Rm Rs | RdHiLo=Rm*Rs+RdHi+RdLo | 未サポート 45 | 0b0100 | UMULL{cond}{S} RdLo,RdHi,Rm,Rs | RdHiLo=Rm*Rs | unsigned 46 | 0b0101 | UMLAL{cond}{S} RdLo,RdHi,Rm,Rs | RdHiLo=Rm*Rs+RdHiLo | unsigned 47 | 0b0110 | SMULL{cond}{S} RdLo,RdHi,Rm,Rs | RdHiLo=Rm*Rs | 48 | 0b0111 | SMLAL{cond}{S} RdLo,RdHi,Rm,Rs | RdHiLo=Rm*Rs+RdHiLo | 49 | 0b1000 | SMLAxy{cond} Rd,Rm,Rs,Rn | Rd=HalfRm*HalfRs+Rn | 50 | 0b1001 | SMLAWy{cond} Rd,Rm,Rs,Rn | Rd=(Rm*HalfRs)/10000h+Rn | 51 | 0b1001 | SMULWy{cond} Rd,Rm,Rs | Rd=(Rm*HalfRs)/10000h | 52 | 0b1010 | SMLALxy{cond} RdLo,RdHi,Rm,Rs | RdHiLo=RdHiLo+HalfRm*HalfRs | 53 | 0b1011 | SMULxy{cond} Rd,Rm,Rs | Rd=HalfRm*HalfRs | 54 | 55 | ## 各命令について 56 | 57 | ### MUL, MLA 58 | 59 | MULとMLAには制約があり、RdとRmは同じレジスタであり、Rd,Rn,Rs,RmのどれもR15を指していてはいけません。 60 | 61 | 注:内部では64ビットで計算され、その結果の下位32ビットのみがRdに格納されるため、符号/ゼロ拡張は不要であり、MULとMLAは符号付きと符号なしの両方の計算に使用できます。 62 | 63 | 実行時間: 64 | 65 | - MUL: 1S+mI 66 | - MLA: 1S+(m+1)I 67 | 68 | 一方、'm' は、Rsが指すレジスタの値によって決まります。 69 | 70 | Rsレジスタの 71 | 72 | - 31-8bitが全て1: m=1 73 | - 31-16bitが全て1: m=2 74 | - 31-24bitが全て1: m=3 75 | - それ以外: m=4 76 | 77 | フラグ(S=1): 78 | 79 | - N: 計算結果が負 80 | - Z: 計算結果が0 81 | - C: クリア(ARMv4) or 不変(ARMv5以降) 82 | - V: 不変 83 | 84 | ### UMULL, UMLAL, SMULL, SMLAL 85 | 86 | - MULL = `Multiply Long` 87 | - MLAL = `Multiply-Accumulate Long` 88 | 89 | 頭が`U`のときは符号なし、`S`のときは符号ありです。 90 | 91 | RdHi, RdLo, Rmはすべて異なるレジスタである必要があり、R15を指すことはできないことに注意してください。 92 | 93 | 実行時間: 94 | 95 | - MULL: 1S+(m+1)I 96 | - MLAL: 1S+(m+2)I 97 | 98 | 'm' は、Rsが指すレジスタの値によって決まります。 99 | 100 | Rsレジスタの 101 | 102 | - 31-8bitが全て1: m=1 103 | - 31-16bitが全て1: m=2 104 | - 31-24bitが全て1: m=3 105 | - それ以外: m=4 106 | 107 | フラグ(S=1): 108 | 109 | - N: 計算結果が負 110 | - Z: 計算結果が0 111 | - C: クリア(ARMv4) or 不変(ARMv5以降) 112 | - V: 不変 113 | 114 | ### SMLAxy, SMLAWy, SMLALxy, SMULxy, SMULWy 115 | 116 | **GBAではサポートされていません**(ARMv5TE(DS)以降からサポート) 117 | 118 | これらは全て、符号付きのハーフワード単位の乗算命令です。 119 | 120 | Qフラグは32bitのSMLAxy/SMLAWy加算オーバーフローでセットされますが、QADD同様、結果は切り捨てられません。 121 | 122 | Qフラグは64bitのSMLALxy加算オーバーフローでは変更されません。 123 | 124 | SMULxy/SMULWy ではオーバーフローしないので,Qフラグは不変です。 125 | 126 | NZCVフラグはハーフワード乗算のとき不変です。 127 | 128 | 実行時間: 129 | 130 | - SMULxy,SMLAxy,SMULWx,SMLAWx: 1S+Interlock 131 | - SMLALxy: 1S+1I+Interlock 132 | 133 | ### UMAAL 134 | 135 | **GBA・NDSではサポートされていません**(ARMv6以降からサポート) 136 | -------------------------------------------------------------------------------- /arm7tdmi/arm/psr.md: -------------------------------------------------------------------------------- 1 | # PSR Transfer 2 | 3 | MRS, MSRが該当します。 4 | 5 | ## 命令のフォーマット 6 | 7 | ### MRS 8 | 9 | bit | 内容 10 | ---- | ---- 11 | 31-28 | 条件 12 | 27-26 | 0b00 13 | 25 | 0b0 14 | 24-23 | 0b10 15 | 22 | Psr - Source/Destination PSR(0=CPSR, 1=SPSR_${mode}) 16 | 21 | オペコード(0b0) 17 | 20 | 0b0 (otherwise TST,TEQ,CMP,CMN) 18 | 19-16 | 0b1111 (otherwise SWP) 19 | 15-12 | Rd - 命令の結果を格納するレジスタ(R0-R14) 20 | 11-0 | 0b0000_0000_0000 21 | 22 | ### MSR 23 | 24 | #### I=0 つまり MSR Psr, Rmのとき 25 | 26 | bit | 内容 27 | ---- | ---- 28 | 31-28 | 条件 29 | 27-26 | 0b00 30 | 25 | I - (第2オペランド 0=レジスタ, 1=即値) 31 | 24-23 | 0b10 32 | 22 | Psr - Source/Destination PSR(0=CPSR, 1=SPSR_${mode}) 33 | 21 | オペコード(0b1) 34 | 20 | 0b0 (otherwise TST,TEQ,CMP,CMN) 35 | 19 | f write to flags field Bit 31-24 (aka _flg) 36 | 18 | s write to status field Bit 23-16 (reserved, don't change) 37 | 17 | x write to extension field Bit 15-8 (reserved, don't change) 38 | 16 | c write to control field Bit 7-0 (aka _ctl) 39 | 15-12 | Rd - 命令の結果を格納するレジスタ(R0-R14) 40 | 11-4 | 0b0000_0000 (otherwise BX) 41 | 3-0 | Rm - ソースレジスタ(R0-R14) 42 | 43 | #### I=1 つまり MSR Psr, Immのとき 44 | 45 | bit | 内容 46 | ---- | ---- 47 | 31-28 | 条件 48 | 27-26 | 0b00 49 | 25 | 0b1 - I=1で第2オペランドが即値 50 | 24-23 | 0b10 51 | 22 | Psr - Source/Destination PSR(0=CPSR, 1=SPSR_${mode}) 52 | 21 | オペコード(0b1) 53 | 20 | 0b0 (otherwise TST,TEQ,CMP,CMN) 54 | 19 | f write to flags field Bit 31-24 (aka _flg) 55 | 18 | s write to status field Bit 23-16 (reserved, don't change) 56 | 17 | x write to extension field Bit 15-8 (reserved, don't change) 57 | 16 | c write to control field Bit 7-0 (aka _ctl) 58 | 15-12 | Rd - 命令の結果を格納するレジスタ(R0-R14) 59 | 11-8 | ImmをRORシフトする量 (シフト量は1ごとに2増える つまり0b1111で30) 60 | 7-0 | Imm - 符号なし8bitの即値 61 | 62 | Immについての注意: ソースコードでは、オペランドとして32ビットのイミディエイトを指定する必要があります。 その後、アセンブラはそれをシフトされた8ビットの値に変換しなければなりません。 63 | 64 | ## オペコード 65 | 66 | - 0b0: `MRS{cond} Rd,Psr ; Rd = Psr` 67 | - 0b1: `MSR{cond} Psr{_field},Op ; Psr[field] = Op` 68 | 69 | ## 説明 70 | 71 | - フィールドマスクビット(bit19-16)は対象のPsrのどのbitが書き込み可能かを示すビットで、これらのビットのうち1つ以上をセットする必要があります。例えば、CPSR_fsxc(別名CPSR、CPSR_all)にした場合はすべてのビットのロックを解除します(以下のユーザモードの制限を参照してください)。 72 | - 非特権モード(ユーザモード)では、CPSRの条件コードビットのみ変更可能で、制御ビットは変更できません。 73 | - ユーザモードおよびシステムモードでは、SPSR は存在しません。 74 | - Tビットは変更できません。ARM/THUMBステートの切り替えは BX命令を使用してください。 75 | - CPSRの未使用ビットは将来のために予約されており、決して変更してはいけません(フラグフィールドの未使用ビットを除く)。 76 | 77 | 実行時間: 1S 78 | -------------------------------------------------------------------------------- /arm7tdmi/arm/swap.md: -------------------------------------------------------------------------------- 1 | # スワップ命令 2 | 3 | SWP, SWPBが該当します。 4 | 5 | ``` 6 | SWP{cond}{B} Rd,Rm,[Rn] ; Rd=[Rn], [Rn]=Rm 7 | ``` 8 | 9 | RdにRnが指すメモリの内容を格納した後で、RmをRnが指すメモリに格納します。 10 | 11 | ビット | 内容 12 | ---- | ---- 13 | 31-28 | 条件 14 | 27-23 | 必ず 0b00010 15 | 22 | B - スワップするデータの単位(0=32bit, 1=8bit) 16 | 21-20 | 必ず 0b00 17 | 19-16 | Rn (R0..R14) 18 | 15-12 | Rd (R0..R14) 19 | 11-4 | 必ず 0b0000_1001 20 | 3-0 | Rm (R0..R14) 21 | 22 | SWP/SWPB はARMv2a以降でサポートされていますが、ARMv6で非推奨になり、ARMv7ではサポートしてもしなくてもどちらでもよくなり、ついにはARMv8で廃止されました。 23 | 24 | RmとRnが同じレジスタを指すことも可能で、問題なく動作します。 25 | 26 | SWP命令ではR15をRn,Rd,Rmとして指定することはできません。 27 | 28 | Bが1、つまりバイト単位のスワップの場合、Rdの31-8bitは0になります。 29 | 30 | 実行時間: 1S+2N+1I 31 | -------------------------------------------------------------------------------- /arm7tdmi/cond.md: -------------------------------------------------------------------------------- 1 | # CPUフラグと条件フィールド 2 | 3 | ## 条件フィールド(cond) 4 | 5 | オペコードの末尾に`{cond}`をつけるとCPSRレジスタのC,N,Z,Vフラグに基づいて実行されるかされないかが変わってきます。 6 | 7 | 例えば、`BEQ`は `Branch if Equal` の略でZフラグが立っているときに分岐し、`MOVMI`は `Move if Singed` の略でNフラグが立っている時に実行されます。 8 | 9 | ARMステートのとき、`{cond}`はすべてのオペコードで使うことができます。 THUMBステートでは`{cond}`は分岐命令でのみ使用できます。 10 | 11 | コード | ニーモニック | フラグ | 内容 12 | ---- | ---- | ---- | ---- 13 | 0 | EQ | Z=1 | 等価、0 14 | 1 | NE | Z=0 | 値が異なる、非0 15 | 2 | CS/HS | C=1 | unsigned higher or same (carry set) 16 | 3 | CC/LO | C=0 | unsigned lower (carry cleared) 17 | 4 | MI | N=1 | 前の処理結果が負 18 | 5 | PL | N=0 | 前の処理結果が0以上 19 | 6 | VS | V=1 | signed overflow (V set) 20 | 7 | VC | V=0 | signed no overflow (V cleared) 21 | 8 | HI | C=1 and Z=0 | unsigned higher 22 | 9 | LS | C=0 or Z=1 | unsigned lower or same 23 | A | GE | N=V | signed greater or equal 24 | B | LT | N≠V | signed less than 25 | C | GT | Z=0 and N=V | signed greater than 26 | D | LE | Z=1 or N≠V | signed less or equal 27 | E | AL | - | always (the "AL" suffix can be omitted) 28 | F | NV | - | never (ARMv1,v2 only) (Reserved ARMv3 and up) 29 | 30 | 実行時間 31 | 32 | - 条件が満たされた時: それぞれのオペコードの実行時間 33 | - 条件が満たされなかった時: 1S 34 | 35 | ## CPSR 36 | 37 | bit | 内容 38 | ---- | ---- 39 | 0-4 | M0-M4 - モード(後述) 40 | 5 | T - THUMBフラグ (0=ARM, 1=THUMB) 41 | 6 | F - FIQ無効フラグ (1=FIQ無効) 42 | 7 | I - IRQ無効フラグ (1=IRQ無効) 43 | 8-26 | 予約 44 | 27 | Q - Stickyフラグ (GBAでは未使用) 45 | 28 | V - Overflowフラグ (1=Overflow) 46 | 29 | C - Carryフラグ (1=Carry/No Borrow) 47 | 30 | Z - Zeroフラグ (1=Zero) 48 | 31 | N - Signフラグ (1=Signed) 49 | 50 | ### Bit28-31(NZCV) 51 | 52 | これらのビットは、論理命令または算術命令の結果を反映します。 53 | 54 | ARMステートでは、ある命令がフラグを修正するかどうかは任意であることが多く、例えば、条件フラグを修正しないSUB命令を実行することも可能です。 55 | 56 | ARMステートでは、`MOVEQ(if Z=1, MOV)`のように、フラグの設定次第で全ての命令を条件付きで実行することができます。THUMBステートでは、分岐命令(ジャンプ)のみ条件付きで実行できます。 57 | 58 | ### Bit27(Q) 59 | 60 | >**Warning** ARMv5TE/ARMv5TExP 以降のみ有効(GBAはサポートしていません) 61 | 62 | QADD、QSUB、QDADD、QDSUB、SMLAxy、SMLAWy でのみ使用されます。 63 | 64 | これらのオペコードは、オーバーフローが発生した場合にQフラグをセットしますが、それ以外は変更しない。 65 | 66 | QフラグはMSR/MRSオペコードによってのみテスト/リセットできます。 67 | 68 | ### Bit0-7 制御ビット 69 | 70 | これらのbitは例外が起きた時に変わる可能性があります。特権モード(非ユーザモード)では手動で変更することができます。 71 | 72 | IとFはIRQとFIQ割り込みをそれぞれ無効にするのに使用します。 73 | 74 | TはCPUのステートを表し、決して手動で変えてはいけません。ステートを変えたい時はBX命令を使うようにしてください。 75 | 76 | M4-M0は現在の動作モードを表します。 77 | 78 | bit | モード | 備考 79 | ---- | ---- | ---- 80 | 0b0xx00 | Old User | 26bit Backward Compatibility modes 81 | 0b0xx01 | Old FIQ | supported only on ARMv3, except ARMv3G, and on some non-T variants of ARMv4 82 | 0b0xx10 | Old IRQ | supported only on ARMv3, except ARMv3G, and on some non-T variants of ARMv4 83 | 0b0xx11 | Old Supervisor | 84 | 0b10000 | User | これだけ特権モードではない 85 | 0b10001 | FIQ | 86 | 0b10010 | IRQ | 87 | 0b10011 | Supervisor (SWI) | 88 | 0b10111 | Abort | 89 | 0b11011 | Undefined | 90 | 0b11111 | System | 特権"ユーザ"モード 91 | 92 | M0-M4を上記の値以外にすることはできません。 93 | 94 | ## SPSR (SPSR_${mode}) 95 | 96 | `Saved Program Status Registers`の略 97 | 98 | 上記のCPSRに加えて5つのSPSRが存在します: `SPSR_fiq, SPSR_svc, SPSR_abt, SPSR_irq, SPSR_und` 99 | 100 | CPUが例外を起こすと、現在のステータスレジスタ(CPSR)が対応するSPSRレジスタにコピーされます。 101 | 102 | 各モードには1つのSPSRしかないので、同じモード内でネストした例外は、例外ハンドラがSPSRの内容をスタックに退避している場合にのみ許可されることに注意してください。 103 | 104 | 例えば、IRQ例外の場合。IRQモードが入力され、CPSRがSPSR_irqにコピーされます。割り込みハンドラがネストしたIRQを有効にしたい場合は、その前にまずSPSR_irqをプッシュしなければなりません。 105 | -------------------------------------------------------------------------------- /arm7tdmi/cycle.md: -------------------------------------------------------------------------------- 1 | # サイクル 2 | 3 | - n = 転送するワード(32bit)の数 4 | - m = 乗算命令のオペランドの最上位バイトに依存 5 | 6 | 命令 | サイクル | 備考 7 | -- | -- | -- 8 | ALU | 1S | +1S+1N if R15 loaded, +1I if SHIFT(Rs) 9 | MSR,MRS | 1S | -- 10 | LDR | 1S+1N+1I | +1S+1N if R15 loaded 11 | STR | 2N | -- 12 | LDM | nS+1N+1I | +1S+1N if R15 loaded 13 | STM | (n-1)S+2N | -- 14 | SWP | 1S+2N+1I | -- 15 | BL (THUMB) | 3S+1N | -- 16 | B,BL | 2S+1N | -- 17 | SWI,trap | 2S+1N | -- 18 | MUL | 1S+ml | -- 19 | MLA | 1S+(m+1)I | -- 20 | MULL | 1S+(m+1)I | -- 21 | MLAL | 1S+(m+2)I | -- 22 | {cond} false | 1S | -- 23 | 24 | ## N - ノンシーケンシャルサイクル 25 | 26 | 前のサイクルで使用されたアドレスと連続していないアドレスへのアクセスを要求した場合にかかる時間です。 27 | 28 | GBAではこのアクセスのことをファーストアクセスといいます。 29 | 30 | 1Nの実行時間は 31 | 32 | - 通常: 1(クロックサイクル) 33 | - カートリッジ: 1 + WaitStateN 34 | 35 | です。 36 | 37 | ## S - シーケンシャルサイクル 38 | 39 | 前のサイクルで使用されたアドレスの直後に位置するアドレスへのアクセスを要求した場合にかかる時間です。 40 | 41 | GBAではこのアクセスのことをセカンドアクセスといいます。 42 | 43 | 1Sの実行時間は 44 | 45 | - 通常: 1(クロックサイクル) 46 | - カートリッジ: 1 + WaitStateS 47 | 48 | です。 49 | 50 | ## I - 内部サイクル 51 | 52 | 単純にCPUのクロックサイクルのことです。 53 | 54 | つまり、1Iの実行時間は 1(クロックサイクル)です。 55 | 56 | 57 | -------------------------------------------------------------------------------- /arm7tdmi/exception.md: -------------------------------------------------------------------------------- 1 | # 例外 2 | 3 | 次のテーブルはメモリ上にある例外ベクタです。例外が生じた時、CPUはARMモードになりPCがそれぞれのアドレスによってロードされます。 4 | 5 | アドレス | 優先度 | 例外 | エントリモード | 割り込みフラグ 6 | ---- | ---- | ---- | ---- | ---- 7 | BASE + 0x00 | 1 | リセット | _svc | I=1, F=1 8 | BASE + 0x04 | 7 | 未定義命令 | _und | I=1, F=不変 9 | BASE + 0x08 | 6 | ソフトウェア割り込み(SWI) | _svc | I=1, F=不変 10 | BASE + 0x0c | 5 | プリフェッチアボート | _abt | I=1, F=不変 11 | BASE + 0x10 | 2 | データアボート | _abt | I=1, F=不変 12 | BASE + 0x14 | ?? | Address Exceeds 26bit | _svc | I=1, F=不変 13 | BASE + 0x18 | 4 | 割り込み(IRQ) | _irq | I=1, F=不変 14 | BASE + 0x1c | 4 | 高速割り込み(FIQ) | _irq | I=1, F=1 15 | 16 | BASEは`0x0000_0000`か`0xffff_0000`のどちらかです。 17 | 18 | 優先度は1~7まであり、1が最高つまり最優先です。 19 | 20 | 上記の各アドレスにはARMオペコード1つ分のスペースしかないので、通常は各ベクタにBranchオペコードを入れておいて、実際に例外処理を行うハンドラのアドレスにリダイレクトするのが普通です。 21 | 22 | ## 例外発生時にCPUが行う処理 23 | 24 | - `R14_${new mode} = $+nn`: 古いPC、つまりリターンアドレスを保存します。 25 | - `SPSR_${new mode} = CPSR`: 古いPSRを保存します。 26 | - `CPSRのT,Mを更新`: T=0にしてARMモードにし、M4-0を新しいモードに更新 27 | - `CPSRのIを更新`: I=1にして割り込みを無効にします。 28 | - `CPSRのFを更新`: F=1にして高速割り込みを無効にします。リセットとFIQによる例外時にのみ行われます 29 | - `PC=割りこみベクタのアドレス` 30 | 31 | 上記の`$+nn`は例外の種類によって異なります。基本的に、ARMモードでは`nn`はパイプラインによってもたらされるものです。 32 | 33 | THUMBモードもハーフワードでアラインメントされている可能性があるという点では違いますが、同じARM形式でアドレスを保存することに注意してください。 34 | 35 | ## 例外からリターンするときに 36 | 37 | 例外ハンドラによって変更された可能性のある汎用レジスタ(R0-R14)を元に戻します。 38 | 39 | 以下のそれぞれの説明に記載されているように、リターン命令を使用して、PCとCPSRの両方をリストアします。 これはCPUのモード(THUMBまたはARM)とFIQ/IRQ無効化フラグの状態も含まれます。 40 | 41 | 上述したように(例外発生時の処理を参照)、リターンアドレスは常にARM形式で保存されるので、例外ハンドラは、例外がARMモードの内部で生じたか、THUMBモードの内部で生じたかに関わらず、同じリターン命令を使用することができます。 42 | 43 | ## FIQ (高速割り込み) 44 | 45 | この割り込みはnFIQ入力のLOWレベルで発生します。これは、タイミングが重要な割り込みを優先して、できるだけ早く処理することを目的としています。 46 | 47 | FIQモードでは、他のモードと違いR13とR14バンクレジスタ(R13_fiq,R14_fiq)に加えて、5つの余分なバンクレジスタ(R8_fiq-R12_fiq)が利用可能です。おかげで例外ハンドラは、メインプログラムのR8-R12レジスタを変更することなく(スタックに保存することなく)、これらのレジスタに自由にアクセスすることができます。 48 | 49 | 特権(非ユーザ)モードでは、CPSRのFビットをセットすることによって、FIQは手動で無効にすることもできます。 50 | 51 | ## IRQ(割り込み) 52 | 53 | この割り込みはnIRQ入力のLOWレベルで発生します。FIQと違ってFIQモード用のR8-R12レジスタは用意されていません。 54 | 55 | IRQはFIQより優先度が低く、FIQ割り込み中はIRQ割り込みは無効化されています。 56 | 57 | 特権(非ユーザ)モードでは、CPSRのIビットを設定することによって、IRQは手動で無効にすることもできます。 58 | 59 | IRQモードから復帰する際には次の命令を実行します。 60 | 61 | ```asm 62 | subs pc,lr,4 ; PC=R14_irq-4 して CPSR=SPSR_irq 63 | ``` 64 | 65 | ## ソフトウェア割り込み 66 | 67 | ソフトウェア割り込み命令(`SWI`)によって生成されます。例外ハンドラではBIOSの機能を 68 | 69 | スーパバイザ(オペレーティングシステム)機能を要求することを推奨します。SWI命令には、オペコードのコメントフィールド部分にパラメータが含まれている場合もあります。 70 | 71 | メインプログラムがTHUMBとARMの両方の状態の内側からSWIを発行する場合、例外ハンドラはARMの24bitのコメントフィールドとTHUMBの8bitのコメントフィールドを分離する必要があります(必要に応じてSPSR_svcのTビットを調べてもとのCPUモードを判断してください)。 72 | 73 | ただし、リトルエンディアンモードでは、24bitのARMコメントフィールドのうち、最も重要な8bitのみを使用することができます(GBAなどではそう行われています)。 74 | 75 | SVCモードから復帰するには次の命令を実行します。 76 | 77 | `MOVS PC,R14 ;both PC=R14_svc, and CPSR=SPSR_svc` 78 | 79 | 注意: SWI命令はTHUMBモードで生じたとしても、常にARMモードで実行されます。 80 | 81 | ## 未定義命令割り込み 82 | 83 | この例外は、CPU が処理できない命令に遭遇したときに発生します。 84 | 85 | ほとんどの場合、プログラムがロックアップしたことを示し、エラーメッセージを表示すべきであることを示しています。 86 | 87 | しかし、これはカスタム関数をエミュレートするためにも使用されるかもしれません。例えば、追加の 'SWI' 命令としてするなどです。(これは R14_und と SPSR_und を使用しますが、R14_svc と SPSR_svc を保存することなく、SVCモードの内部から未定義命令ハンドラを実行することができます) 88 | 89 | UNDモードから復帰するには次の命令を実行します。 90 | 91 | `MOVS PC,R14 ; both PC=R14_und, and CPSR=SPSR_und` 92 | 93 | ## アボート 94 | 95 | アボート(ページフォールト)は大抵は仮想メモリでサポートされていますが、それ以外にもエラーメッセージを表示するためにも使われることがあります。 96 | 97 | この場合はアボートには次の2つのパターンがあります。 98 | 99 | - プリフェッチアボート(命令のプリフェッチ中に生じる) 100 | - データアボート(データアクセス中に生じる) 101 | 102 | 仮想メモリシステムのアボートハンドラは、フォールトアドレスを決定します。プリフェッチアボートの場合は`R14_abt - 4`です。データアボートでは、メモリ内のアドレスを決定するために、`R14_abt - 8`のTHUMB命令またはARM命令を分解する必要があります。 103 | 104 | 復帰時にハンドラは次の命令を実行することで(アボートを起こした場所に)復帰します。 105 | 106 | ``` 107 | prefetch abort: SUBS PC,R14,#4 ; PC = R14_abt - 4, and CPSR = SPSR_abt 108 | data abort: SUBS PC,R14,#8 ; PC = R14_abt - 8, and CPSR = SPSR_abt 109 | ``` 110 | 111 | ## Address Exceeds 26bit 112 | 113 | この例外は、26bitのアドレススキームを持つ古いARM CPU(または26bitの下位互換モード)でのみ発生します。 114 | 115 | ## リセット 116 | 117 | 強制的に次のことをおこないます 118 | 119 | ``` 120 | PC = BASE 121 | CPSR.T = 0 ; ARMステート 122 | CPSR.F = 1 ; FIQ無効 123 | CPSR.I = 1 ; IRQ無効 124 | CPSR.M[4-0] = 0b10011 ; SVCモード 125 | ``` 126 | -------------------------------------------------------------------------------- /arm7tdmi/register.md: -------------------------------------------------------------------------------- 1 | # レジスタ 2 | 3 | ## 概要 4 | 5 | 次のテーブルはARM7TDMIの各モードで利用可能なレジスタの一覧です。 6 | 7 | 全部で37個の32bitレジスタがあり、そのうち31個は汎用レジスタ(Rxx)で6個はステータスレジスタです(xPSR)。 8 | 9 | いくつかのレジスタはバンク方式であることに注意してください。例をあげると、それぞれのモードはそれぞれ独自のR14レジスタを持っています。 10 | 11 | もちろん、バンク方式でないレジスタもあります。例えばR0はどのモードも共有しています。 12 | 13 | System | User FIQ | Supervisor | Abort | IRQ | Undefined 14 | ---- | ---- | ---- | ---- | ---- | ---- 15 | R0 | R0 | R0 | R0 | R0 | R0 16 | R1 | R1 | R1 | R1 | R1 | R1 17 | R2 | R2 | R2 | R2 | R2 | R2 18 | R3 | R3 | R3 | R3 | R3 | R3 19 | R4 | R4 | R4 | R4 | R4 | R4 20 | R5 | R5 | R5 | R5 | R5 | R5 21 | R6 | R6 | R6 | R6 | R6 | R6 22 | R7 | R7 | R7 | R7 | R7 | R7 23 | R8 | R8_fiq | R8 | R8 | R8 | R8 24 | R9 | R9_fiq | R9 | R9 | R9 | R9 25 | R10 | R10_fiq | R10 | R10 | R10 | R10 26 | R11 | R11_fiq | R11 | R11 | R11 | R11 27 | R12 | R12_fiq | R12 | R12 | R12 | R12 28 | R13 | R13_fiq | R13_svc | R13_abt | R13_irq | R13_und 29 | R14 | R14_fiq | R14_svc | R14_abt | R14_irq | R14_und 30 | R15 | R15 | R15 | R15 | R15 | R15 31 | CPSR | CPSR | CPSR | CPSR | CPSR | CPSR 32 | -- | SPSR_fiq | SPSR_svc | SPSR_abt | SPSR_irq | SPSR_und 33 | 34 | ## R0-R12 (汎用レジスタ) 35 | 36 | これらの13個のレジスタは、さまざまな目的に使用可能です。 37 | 38 | 基本的には、それぞれのレジスタの機能や性能は同じで、演算用の「高速アキュムレータ」やメモリアドレス指定用の「ポインタレジスタ」のような特殊な用途に限定されたレジスタはありません。 39 | 40 | ただし、THUMBモードではR0~R7(Loレジスタ)のみ自由にアクセスでき、R8~R12(Hiレジスタ)は一部の命令でしかアクセスできません。 41 | 42 | ## R13 (SP) 43 | 44 | このレジスタはTHUMBモードではスタックポインタ(SP)として使用されます。 45 | 46 | ARMモードでは、R13ではなく他のレジスタをスタックポインタとして使用したり、R13を汎用レジスタとして使用したりすることができます。 47 | 48 | 上のテーブルからわかるように、各モードには個別のR13レジスタがあり、(SPとして使用されている場合は)各モードの例外ハンドラは独自のスタックを使用することができます。 49 | 50 | ## R14 (LR) 51 | 52 | このレジスタはリンクレジスタ(LR)として使用されます。リンク付き分岐命令(BL)でサブルーチンを呼び出すと、そのリターン先のアドレス(PCの古い値)がこのレジスタに保存されます。 53 | 54 | サブルーチンをネストして呼び出す場合、LRレジスタは各モードに1つしかないので、リターンアドレスを手動でプッシュする必要があります。 55 | 56 | また、例外が呼ばれた場合も同様で、PCは新しいモードのLRに保存されます。 57 | 58 | ARMモードでは、上記のLRレジスタとしての使用が不要であれば、R14を汎用レジスタとして使用することも可能になっています。 59 | 60 | ## R15 (PC) 61 | 62 | R15は常にプログラムカウンタ(PC)として利用されます。 63 | 64 | R15から読み出しを行ったとき、パイプライン処理のため基本的に`$+nn`の値が返されることに注意してください。(つまり今実行している命令のアドレス(`$`)よりR15のほうが進んでいます) 65 | 66 | `$+nn`の`nn`はARMモードかTHUMBモードかによって変わります。 67 | 68 | ## CPSR と SPSR 69 | 70 | PSRは `Program Status Registers`の略です。 CPSRは `Current PSR`, SPSRは `Saved PSR` の略です。 71 | 72 | CPSRは現在のフラグやCPUの制御ビットが格納されています。 73 | 74 | 例外が起こると、古いCPSRが例外のモードに応じたSPSRに退避されます。(PCがLRに退避されるのに似ています。) 75 | 76 | 各Bitの内容やSPSRについての詳細は[こちら](cond.md#cpsr)を参照してください。 77 | -------------------------------------------------------------------------------- /arm7tdmi/thumb/addressing.md: -------------------------------------------------------------------------------- 1 | # アドレッシング 2 | 3 | ## THUMB.12: PC/SPからの相対アドレス取得 4 | 5 | PCやSPからnnだけ離れたアドレスを取得する命令です。 6 | 7 | bit | 内容 8 | ---- | ---- 9 | 15-12 | 0b1010 10 | 11 | オペコード 11 | 10-8 | Rd - ターゲットレジスタ (R0..R7) 12 | 7-0 | nn - 符号無しオフセット (0-1020で1ごとに4刻み つまり0-4080) 13 | 14 | オペコード(bit11): 15 | 16 | ``` 17 | 0: ADD Rd,PC,#nn ; Rd = (($+4) AND NOT 2) + nn 18 | 1: ADD Rd,SP,#nn ; Rd = SP + nn 19 | ``` 20 | 21 | フラグ: 不変 22 | 23 | 実行時間: 1S 24 | 25 | ## THUMB.13: SP操作 26 | 27 | SPをnnだけ動かす命令です。 28 | 29 | bit | 内容 30 | ---- | ---- 31 | 15-8 | 0b10110000 32 | 7 | オペコード 33 | 6-0 | nn - 符号無しオフセット (0-508で1ごとに4) 34 | 35 | オペコード(bit7): 36 | 37 | ``` 38 | 0: ADD SP,#nn ; SP = SP + nn 39 | 1: ADD SP,#-nn ; SP = SP - nn 40 | ``` 41 | 42 | フラグ: 不変 43 | 44 | 実行時間: 1S 45 | -------------------------------------------------------------------------------- /arm7tdmi/thumb/branch.md: -------------------------------------------------------------------------------- 1 | # 分岐命令 2 | 3 | ## THUMB.16: 条件付き分岐 4 | 5 | ビット | 内容 6 | -- | -- 7 | 15-12 | 0b1101 8 | 11-8 | オペコード 9 | 7-0 | 符号付きオフセット(2バイトごと) 10 | 11 | オペコード(bit11-8): 12 | 13 | ``` 14 | 0: BEQ label ; Z=1 EQual 15 | 1: BNE label ; Z=0 NotEqual 16 | 2: BCS label ; C=1 CarrySet 17 | 3: BCC label ; C=0 CarryClear 18 | 4: BMI label ; N=1 MInus 19 | 5: BPL label ; N=0 PLus 20 | 6: BVS label ; V=1 VSet 21 | 7: BVC label ; V=1 VClear 22 | 8: BHI label ; C=1 && Z=0 23 | 9: BLS label ; C=0 || Z=1 24 | a: BGE label ; N=V GreaterEqual 25 | b: BLT label ; N=V LessThan 26 | c: BGT label ; N=V GreaterThan 27 | d: BLE label ; N=V LessEqual 28 | e: 未使用 29 | f: SWIのために予約 30 | ``` 31 | 32 | フラグ: 不変 33 | 34 | 実行時間: 35 | 36 | - true: 2S+1N 37 | - false: 1S 38 | 39 | ## THUMB.17: ソフトウェア割り込み \& ブレーク 40 | 41 | SWIはOSの機能を呼び出す際に使用されます。 42 | 43 | BKPTはプリフェッチアボートによってアボートモードに入るのに使います。デバッグのための命令です。 44 | 45 | ビット | 内容 46 | -- | -- 47 | 15-8 | オペコード - 0b1101_1111(SWI nn) or 0b1011_1110(BKPT nn) 48 | 7-0 | nn - コメントフィールド 49 | 50 | SWIのコメントフィールドは例外ハンドラの処理を分岐させるのに使用します。例外ハンドラは`[R14_svc-2]`に格納されたSWI命令をパースすることによってこのコメントフィールドを得ます。 51 | 52 | もしARMモードでSWIを使用する可能性があるなら、SWIハンドラはSPSR_svcのTビットをみて、ARMモードで起きたSWIかを判定して、そうだとしたら`[R14_svc-4]`の24-32bitからパースを行う必要があります。 53 | 54 | SWIからの復帰には `MOVS PC,R14`を使用しますが、この命令はPCとCPSRの両方をリストア(つまりPC=R14_svc、CPSR=SPSR_svc)し、(THUMBモードから呼び出された場合は)THUMBモードへの復帰もおこないます。 55 | 56 | ネストしたSWIを呼び出す場合は、SWIを呼び出す前またはIRQを有効にする前に現在の`SPSR_svc`と`R14_svc`をスタックに退避して呼び出す必要があります。 57 | 58 | 実行時間: 2S+1N 59 | 60 | ## THUMB.18: 無条件分岐 61 | 62 | `B label`のこと 63 | 64 | ビット | 内容 65 | -- | -- 66 | 15-11 | 0b11100 67 | 10-0 | ジャンプ先(PCからの相対オフセット、2バイトごと) 68 | 69 | フラグ: 不変 70 | 71 | 実行時間: 2S+1N 72 | 73 | ## THUMB.19: サブルーチンコール 74 | 75 | この命令はリターン先がR14になっているサブルーチンのコール(or ジャンプ)に利用されます。 76 | 77 | THUMBモードの命令は16bitですが、この命令は32bit長です。[1](#exception) [2](#bl) 78 | 79 | **1つ目(0-15)** 80 | 81 | LR = PC+4+(nn SHL 12) 82 | 83 | ビット | 内容 84 | -- | -- 85 | 15-11 | 0b11110 86 | 10-0 | nn - ターゲットアドレスの上位11bit 87 | 88 | **2つ目(16-31)** 89 | 90 | PC = LR + (nn SHL 1), and LR = PC+2 OR 1 (and BLX: T=0) 91 | 92 | ビット | 内容 93 | -- | -- 94 | 15-11 | オペコード - 0b11111(BL label) or 0b11101(BLX label) 95 | 10-0 | nn - ターゲットアドレスの下位11bit 96 | 97 | この命令では `PC±0x40_0000`の範囲に飛ぶことが可能です。 98 | 99 | フラグ: 不変 100 | 101 | 実行時間: 3S+1N (1つ目: 1S, 2つ目: 2S+1N) 102 | 103 | 1: 1つ目のオペコードと2つ目のオペコードの間に例外が起きるかどうかは未定義です。 104 | 2: `BL LR+imm`として2つ目のオペコードだけを使うことも可能です。 105 | 106 | ## BX 107 | 108 | [THUMB.5: Hi register operations/branch exchange](./register.md#thumb5-hi-register-operationsbranch-exchange)を参照 109 | -------------------------------------------------------------------------------- /arm7tdmi/thumb/instruction.md: -------------------------------------------------------------------------------- 1 | # THUMBモードの命令一覧 2 | 3 | THUMBモードはARMモードと違って基本的に汎用レジスタをR0-R7までしか利用できません。 4 | 5 | サイクルのS, Nなどについては[サイクル](../cycle.md)を参照してください。 6 | 7 | ## 論理演算 8 | 9 | 命令 | サイクル | フラグ | フォーマット | 処理内容 10 | ---- | ---- | ---- | ---- | ---- 11 | MOV Rd,Imm8bit | 1S | NZ-- | 3 | Rd=nn 12 | MOV Rd,Rs | 1S | NZ00 | 2 | Rd=Rs+0 13 | MOV R0..14,R8..15 | 1S | ---- | 5 | Rd=Rs 14 | MOV R8..14,R0..15 | 1S | ---- | 5 | Rd=Rs 15 | MOV R15,R0..15 | 2S+1N | ---- | 5 | PC=Rs 16 | MVN Rd,Rs | 1S | NZ-- | 4 | Rd=NOT Rs 17 | AND Rd,Rs | 1S | NZ-- | 4 | Rd=Rd AND Rs 18 | TST Rd,Rs | 1S | NZ-- | 4 | Void=Rd AND Rs 19 | BIC Rd,Rs | 1S | NZ-- | 4 | Rd=Rd AND NOT Rs 20 | ORR Rd,Rs | 1S | NZ-- | 4 | Rd=Rd OR Rs 21 | EOR Rd,Rs | 1S | NZ-- | 4 | Rd=Rd XOR Rs 22 | LSL Rd,Rs,Imm5bit | 1S | NZc- | 1 | Rd=Rs SHL nn 23 | LSL Rd,Rs | 1S+1I | NZc- | 4 | Rd=Rd SHL (Rs AND 0FFh) 24 | LSR Rd,Rs,Imm5bit | 1S | NZc- | 1 | Rd=Rs SHR nn 25 | LSR Rd,Rs | 1S+1I | NZc- | 4 | Rd=Rd SHR (Rs AND 0FFh) 26 | ASR Rd,Rs,Imm5bit | 1S | NZc- | 1 | Rd=Rs SAR nn 27 | ASR Rd,Rs | 1S+1I | NZc- | 4 | Rd=Rd SAR (Rs AND 0FFh) 28 | ROR Rd,Rs | 1S+1I | NZc- | 4 | Rd=Rd ROR (Rs AND 0FFh) 29 | NOP | 1S | ---- | 5 | R8=R8 30 | 31 | ## 算術演算+乗算 32 | 33 | 命令 | サイクル | フラグ | フォーマット | 処理内容 34 | ---- | ---- | ---- | ---- | ---- 35 | ADD Rd,Rs,Imm3bit | 1S | NZCV | 2 | Rd=Rs+nn 36 | ADD Rd,Imm8bit | 1S | NZCV | 3 | Rd=Rd+nn 37 | ADD Rd,Rs,Rn | 1S | NZCV | 2 | Rd=Rs+Rn 38 | ADD R0..14,R8..15 | 1S | ---- | 5 | Rd=Rd+Rs 39 | ADD R8..14,R0..15 | 1S | ---- | 5 | Rd=Rd+Rs 40 | ADD R15,R0..15 | 2S+1N | ---- | 5 | PC=Rd+Rs 41 | ADD Rd,PC,Imm8bit*4 | 1S | ---- | 12 | Rd=(($+4) AND NOT 2)+nn 42 | ADD Rd,SP,Imm8bit*4 | 1S | ---- | 12 | Rd=SP+nn 43 | ADD SP,Imm7bit*4 | 1S | ---- | 13 | SP=SP+nn 44 | ADD SP,-Imm7bit*4 | 1S | ---- | 13 | SP=SP-nn 45 | ADC Rd,Rs | 1S | NZCV | 4 | Rd=Rd+Rs+Cy 46 | SUB Rd,Rs,Imm3Bit | 1S | NZCV | 2 | Rd=Rs-nn 47 | SUB Rd,Imm8bit | 1S | NZCV | 3 | Rd=Rd-nn 48 | SUB Rd,Rs,Rn | 1S | NZCV | 2 | Rd=Rs-Rn 49 | SBC Rd,Rs | 1S | NZCV | 4 | Rd=Rd-Rs-NOT Cy 50 | NEG Rd,Rs | 1S | NZCV | 4 | Rd=0-Rs 51 | CMP Rd,Imm8bit | 1S | NZCV | 3 | Void=Rd-nn 52 | CMP Rd,Rs | 1S | NZCV | 4 | Void=Rd-Rs 53 | CMP R0-15,R8-15 | 1S | NZCV | 5 | Void=Rd-Rs 54 | CMP R8-15,R0-15 | 1S | NZCV | 5 | Void=Rd-Rs 55 | CMN Rd,Rs | 1S | NZCV | 4 | Void=Rd+Rs 56 | MUL Rd,Rs | 1S+mI | NZx- | 4 | Rd=Rd*Rs 57 | 58 | ## ロード/ストア 59 | 60 | 命令 | サイクル | フラグ | フォーマット | 処理内容 61 | ---- | ---- | ---- | ---- | ---- 62 | LDR Rd,\[Rb,5bit*4\] | 1S+1N+1I | ---- | 9 | Rd = WORD\[Rb+nn\] 63 | LDR Rd,\[PC,8bit*4\] | 1S+1N+1I | ---- | 6 | Rd = WORD\[PC+nn\] 64 | LDR Rd,\[SP,8bit*4\] | 1S+1N+1I | ---- | 11 | Rd = WORD\[SP+nn\] 65 | LDR Rd,\[Rb,Ro\] | 1S+1N+1I | ---- | 7 | Rd = WORD\[Rb+Ro\] 66 | LDRB Rd,\[Rb,5bit*1\] | 1S+1N+1I | ---- | 9 | Rd = BYTE\[Rb+nn\] 67 | LDRB Rd,\[Rb,Ro\] | 1S+1N+1I | ---- | 7 | Rd = BYTE\[Rb+Ro\] 68 | LDRH Rd,\[Rb,5bit*2\] | 1S+1N+1I | ---- | 10 | Rd = HALFWORD\[Rb+nn\] 69 | LDRH Rd,\[Rb,Ro\] | 1S+1N+1I | ---- | 8 | Rd = HALFWORD\[Rb+Ro\] 70 | LDSB Rd,\[Rb,Ro\] | 1S+1N+1I | ---- | 8 | Rd = SIGNED_BYTE\[Rb+Ro\] 71 | LDSH Rd,\[Rb,Ro\] | 1S+1N+1I | ---- | 8 | Rd = SIGNED_HALFWORD\[Rb+Ro\] 72 | STR Rd,\[Rb,5bit*4\] | 2N | ---- | 9 | WORD\[Rb+nn\] = Rd 73 | STR Rd,\[SP,8bit*4\] | 2N | ---- | 11 | WORD\[SP+nn\] = Rd 74 | STR Rd,\[Rb,Ro\] | 2N | ---- | 7 | WORD\[Rb+Ro\] = Rd 75 | STRB Rd,\[Rb,5bit*1\] | 2N | ---- | 9 | BYTE\[Rb+nn\] = Rd 76 | STRB Rd,\[Rb,Ro\] | 2N | ---- | 7 | BYTE\[Rb+Ro\] = Rd 77 | STRH Rd,\[Rb,5bit*2\] | 2N | ---- | 10 | HALFWORD\[Rb+nn\] = Rd 78 | STRH Rd,\[Rb,Ro\] | 2N | ---- | 8 | HALFWORD\[Rb+Ro\]=Rd 79 | PUSH {Rlist}{LR} | (n-1)S+2N | ---- | 14 | 80 | POP {Rlist}{PC} | | ---- | 14 | (ARM9: with mode switch) 81 | STMIA Rb!,{Rlist} | (n-1)S+2N | ---- | 15 | 82 | LDMIA Rb!,{Rlist} | nS+1N+1I | ---- | 15 | 83 | 84 | ## ジャンプ、コール 85 | 86 | 命令 | サイクル | フラグ | フォーマット | 処理内容($=PC) 87 | ---- | ---- | ---- | ---- | ---- 88 | B disp | 2S+1N | ---- | 18 | PC=$+/-2048 89 | BL disp | 3S+1N | ---- | 19 | PC=\$+/-4M, LR=\$+5 90 | B{cond=true} disp | 2S+1N | ---- | 16 | PC=$+/-0..256 91 | B{cond=false} disp | 1S | ---- | 16 | N/A 92 | BX R0..15 | 2S+1N | ---- | 5 | PC=Rs, ARM/THUMB (Rs bit0) 93 | SWI Imm8bit | 2S+1N | ---- | 17 | PC=8, ARM SVC mode, LR=$+2 94 | POP {Rlist,}PC | (n+1)S+2N+1I | ---- | 14 | 95 | MOV R15,R0..15 | 2S+1N | ---- | 5 | PC=Rs 96 | ADD R15,R0..15 | 2S+1N | ---- | 5 | PC=Rd+Rs 97 | 98 | BL命令は全体で32bit長であることに注意してください。 99 | -------------------------------------------------------------------------------- /arm7tdmi/thumb/loadstore.md: -------------------------------------------------------------------------------- 1 | # ロード/ストア命令 2 | 3 | ## THUMB.6: load PC-relative 4 | 5 | PCからの相対アドレスで指定したメモリから32bitデータをロード/ストアする命令です。リテラルプールからのデータ読み込みで頻繁に利用します。 6 | 7 | ``` 8 | LDR Rd,[PC,#nn] 9 | ``` 10 | 11 | bit | 内容 12 | ---- | ---- 13 | 15-11 | 0b01001 14 | 10-8 | Rd - 読み取った値を格納するレジスタ (R0..R7) 15 | 7-0 | nn - 符号無しオフセット (1増えるとオフセットが4増加。つまりnnの範囲は 0..1020) 16 | 17 | PCは`($+4) AND NOT 2` として扱われます。(`$`: この命令のあるアドレス) 18 | 19 | フラグ: 不変 20 | 21 | 実行時間: 1S+1N+1I 22 | 23 | ## THUMB.7: load/store with register offset 24 | 25 | RbレジスタとRoレジスタに入っているオフセットで指定したメモリから32bitデータ(または8bitデータ)をロード/ストアする命令です。 26 | 27 | bit | 内容 28 | ---- | ---- 29 | 15-12 | 0b0101 30 | 11-10 | オペコード 31 | 9 | 0b0 32 | 8-6 | Ro - オフセットレジスタ (R0..R7) 33 | 5-3 | Rb - ベースレジスタ (R0..R7) 34 | 2-0 | Rd - ターゲットレジスタ (R0..R7) 35 | 36 | フラグ: 不変 37 | 38 | 実行時間: 39 | 40 | - LDR: 1S+1N+1I 41 | - STR: 2N 42 | 43 | オペコード(bit11-10): 44 | 45 | ``` 46 | 0: STR Rd,[Rb,Ro] ; 32bit格納 WORD[Rb+Ro] = Rd 47 | 1: STRB Rd,[Rb,Ro] ; 8bit格納 BYTE[Rb+Ro] = Rd 48 | 2: LDR Rd,[Rb,Ro] ; 32bitロード Rd = WORD[Rb+Ro] 49 | 3: LDRB Rd,[Rb,Ro] ; 8bitロード Rd = BYTE[Rb+Ro] 50 | ``` 51 | 52 | ## THUMB.8: load/store sign-extended byte/halfword 53 | 54 | bit | 内容 55 | ---- | ---- 56 | 15-12 | 0b0101 57 | 11-10 | オペコード 58 | 9 | 0b1 59 | 8-6 | Ro - オフセットレジスタ (R0..R7) 60 | 5-3 | Rb - ベースレジスタ (R0..R7) 61 | 2-0 | Rd - ターゲットレジスタ (R0..R7) 62 | 63 | フラグ: 不変 64 | 65 | 実行時間: 66 | 67 | - LDR: 1S+1N+1I 68 | - STR: 2N 69 | 70 | オペコード(bit11-10): 71 | 72 | ``` 73 | 0: STRH Rd,[Rb,Ro] ; 16bit格納 HALFWORD[Rb+Ro] = Rd 74 | 1: LDSB Rd,[Rb,Ro] ; 符号付き8bitをロード Rd = BYTE[Rb+Ro] 75 | 2: LDRH Rd,[Rb,Ro] ; 16bitをロード Rd = HALFWORD[Rb+Ro] 76 | 3: LDSH Rd,[Rb,Ro] ; 符号付き16bitをロード Rd = HALFWORD[Rb+Ro] 77 | ``` 78 | 79 | ## THUMB.9: load/store with immediate offset 80 | 81 | Rbレジスタと即値オフセットで指定したメモリから32bitデータ(または8bitデータ)をロード/ストアする命令です。 82 | 83 | bit | 内容 84 | ---- | ---- 85 | 15-13 | 0b011 86 | 12-11 | オペコード 87 | 10-6 | nn - 符号無しオフセット (0-31 for BYTE, 0-124 for WORD) 88 | 5-3 | Rb - ベースレジスタ (R0..R7) 89 | 2-0 | Rd - ターゲットレジスタ (R0..R7) 90 | 91 | オペコード(bit12-11): 92 | 93 | ``` 94 | 0: STR Rd,[Rb,#nn] ; store 32bit data WORD[Rb+nn] = Rd 95 | 1: LDR Rd,[Rb,#nn] ; load 32bit data Rd = WORD[Rb+nn] 96 | 2: STRB Rd,[Rb,#nn] ; store 8bit data BYTE[Rb+nn] = Rd 97 | 3: LDRB Rd,[Rb,#nn] ; load 8bit data Rd = BYTE[Rb+nn] 98 | ``` 99 | 100 | フラグ: 不変 101 | 102 | 実行時間: 103 | 104 | - LDR: 1S+1N+1I 105 | - STR: 2N 106 | 107 | ## THUMB.10: load/store halfword 108 | 109 | Rbレジスタと即値オフセットで指定したメモリから16bitデータをロード/ストアする命令です。 110 | 111 | bit | 内容 112 | ---- | ---- 113 | 15-12 | 0b1000 114 | 11 | オペコード 115 | 10-6 | nn - 符号無しオフセット (0-62、2刻み) 116 | 5-3 | Rb - ベースレジスタ (R0..R7) 117 | 2-0 | Rd - ターゲットレジスタ (R0..R7) 118 | 119 | オペコード(bit11): 120 | 121 | ``` 122 | 0: STRH Rd,[Rb,#nn] ; store 16bit data HALFWORD[Rb+nn] = Rd 123 | 1: LDRH Rd,[Rb,#nn] ; load 16bit data Rd = HALFWORD[Rb+nn] 124 | ``` 125 | 126 | フラグ: 不変 127 | 128 | 実行時間: 129 | 130 | - LDR: 1S+1N+1I 131 | - STR: 2N 132 | 133 | ## THUMB.11: load/store SP-relative 134 | 135 | SPからの相対アドレスで指定したメモリから32bitデータをロード/ストアする命令です。 136 | 137 | bit | 内容 138 | ---- | ---- 139 | 15-12 | 0b1001 140 | 11 | オペコード 141 | 10-8 | Rd - ターゲットレジスタ (R0..R7) 142 | 7-0 | nn - 符号無しオフセット (0-1020, 4刻み) 143 | 144 | オペコード(bit11): 145 | 146 | ``` 147 | 0: STR Rd,[SP,#nn] ; store 32bit data WORD[SP+nn] = Rd 148 | 1: LDR Rd,[SP,#nn] ; load 32bit data Rd = WORD[SP+nn] 149 | ``` 150 | 151 | フラグ: 不変 152 | 153 | 実行時間: 154 | 155 | - LDR: 1S+1N+1I 156 | - STR: 2N 157 | -------------------------------------------------------------------------------- /arm7tdmi/thumb/loadstore2.md: -------------------------------------------------------------------------------- 1 | # ロード/ストア命令 その2 2 | 3 | ## THUMB.14: push/pop registers 4 | 5 | bit | 内容 6 | ---- | ---- 7 | 15-12 | 0b1011 8 | 11 | オペコード 9 | 10-9 | 0b10 10 | 8 | PC/LR Bit (0: No, 1: `PUSH LR (R14)`, or `POP PC (R15)`) 11 | 7-0 | Rlist - レジスタのリスト (R7..R0) 12 | 13 | オペコード(bit11): 14 | 15 | ``` 16 | 0: PUSH {Rlist}{LR} ; store in memory, decrements SP (R13) 17 | 1: POP {Rlist}{PC} ; load from memory, increments SP (R13) 18 | ``` 19 | 20 | 例: 21 | 22 | ``` 23 | PUSH {R0-R3} ; push R0,R1,R2,R3 24 | PUSH {R0,R2,LR} ; push R0,R2,LR 25 | POP {R4,R7} ; pop R4,R7 26 | POP {R2-R4,PC} ; pop R2,R3,R4,PC 27 | ``` 28 | 29 | ### サブルーチン 30 | 31 | サブルーチンを呼び出す際には、LRレジスタにリターンアドレスを格納する必要があります。 32 | 33 | ネストして呼び出す場合は`PUSH {LR}`をしてLRレジスタの値をまずスタックに退避する必要があります。逆にサブルーチンから戻る時は`POP {PC}`をしてください。 34 | 35 | POP {PC} ignores the least significant bit of the return address (processor remains in thumb state even if bit0 was cleared), when intending to return with optional mode switch, use a POP/BX combination (eg. POP {R3} / BX R3). 36 | ARM9: POP {PC} copies the LSB to thumb bit (switches to ARM if bit0=0). 37 | 38 | フラグ: 不変 39 | 40 | 実行時間: 41 | 42 | - PUSH: (n-1)S+2N 43 | - POP: nS+1N+1I 44 | - POP PC: (n+1)S+2N+1I 45 | 46 | ## THUMB.15: multiple load/store 47 | 48 | bit | 内容 49 | ---- | ---- 50 | 15-12 | 0b1100 51 | 11 | オペコード 52 | 10-8 | Rb - ベースレジスタ (R0-R7) 53 | 7-0 | Rlist - レジスタのリスト (R7..R0) 54 | 55 | オペコード(bit11): 56 | 57 | ``` 58 | 0: STMIA Rb!,{Rlist} ; store in memory, increments Rb 59 | 1: LDMIA Rb!,{Rlist} ; load from memory, increments Rb 60 | ``` 61 | 62 | 例: 63 | 64 | ``` 65 | STMIA R7!,{R0-R2} ; [R7]=R0, [R7+4]=R1, [R7+8]=R2 66 | LDMIA R0!,{R1,R5} ; R1=[R0], R5=[R0+4] 67 | ``` 68 | 69 | フラグ: 不変 70 | 71 | 実行時間: 72 | 73 | - LDM: nS+1N+1I 74 | - STM: (n-1)S+2N 75 | 76 | ## 順番 77 | 78 | [ARMモードの場合](../arm/loadstore3.md#順番)と同じです。 79 | -------------------------------------------------------------------------------- /arm7tdmi/thumb/register.md: -------------------------------------------------------------------------------- 1 | # レジスタ操作 2 | 3 | 算術、分岐命令など 4 | 5 | ## THUMB.1: ビットシフト 6 | 7 | bit | 内容 8 | ---- | ---- 9 | 13-15 | 0b000 10 | 11-12 | オペコード 11 | 6-10 | オフセット (0-31) 12 | 3-5 | Rs - ソースレジスタ (R0..R7) 13 | 0-2 | Rd - ターゲットレジスタ (R0..R7) 14 | 15 | オペコード(bit11-12): 16 | 17 | ``` 18 | 0: LSL{S} Rd,Rs,#Offset ; 左シフト Rd = Rs << nn 19 | 1: LSR{S} Rd,Rs,#Offset ; 論理右シフト Rd = Rs >> nn 20 | 2: ASR{S} Rd,Rs,#Offset ; 算術右シフト Rd = Rs >> nn 21 | 3: 未使用 22 | ``` 23 | 24 | - 論理右シフト: 右に溢れたbitは捨てられ、左に空いたbitは0埋めされる 25 | - 算術右シフト: 右に溢れたbitは捨てられ、左に空いたbitは元の符号(0 or 1)で埋められる 26 | 27 | ARMモードと同様、シフト量0のときは特殊な処理になります。 28 | 29 | - LSL#0: シフトは行われません。キャリーの値は不変です。 30 | - LSR/ASR#0 は LSR/ASR#32 として解釈されます。 31 | - ソースコードで LSR/ASR#0 を指定しようとすると、自動的に LSL#0 としてリダイレクトされます。同様に LSR/ASR#32 は LSR/ASR#0 としてリダイレクトされます。 32 | 33 | フラグ: NZC (LSL#0のときはCは不変) 34 | 35 | 実行時間: 1S 36 | 37 | ## THUMB.2: 加算/減算 38 | 39 | bit | 内容 40 | ---- | ---- 41 | 11-15 | 0b00011 42 | 9-10 | オペコード 43 | 6-8 | 足し引きする値(0..7 オペコードによってRnかnnかどうか変わる) 44 | 3-5 | Rs - ソースレジスタ (R0..R7) 45 | 0-2 | Rd - ターゲットレジスタ (R0..R7) 46 | 47 | オペコード(bit9-10): 48 | 49 | ``` 50 | 0: ADD{S} Rd,Rs,Rn ; Rd=Rs+Rn 51 | 1: SUB{S} Rd,Rs,Rn ; Rd=Rs-Rn 52 | 2: ADD{S} Rd,Rs,#nn ; Rd=Rs+nn 53 | 3: SUB{S} Rd,Rs,#nn ; Rd=Rs-nn 54 | ``` 55 | 56 | フラグ: NZCV (LSL#0のときはCは不変) 57 | 58 | 実行時間: 1S 59 | 60 | ## THUMB.3: 即値の演算 61 | 62 | bit | 内容 63 | ---- | ---- 64 | 13-15 | 0b001 65 | 11-12 | オペコード 66 | 8-10 | Rd - ターゲットレジスタ (R0..R7) 67 | 0-7 | nn - 符号無しオフセット (0-255) 68 | 69 | オペコード(bit11-12): 70 | 71 | ``` 72 | 0: MOV{S} Rd,#nn ; Rd = #nn 73 | 1: CMP{S} Rd,#nn ; Void = Rd - #nn 74 | 2: ADD{S} Rd,#nn ; Rd = Rd + #nn 75 | 3: SUB{S} Rd,#nn ; Rd = Rd - #nn 76 | ``` 77 | 78 | フラグ: 79 | 80 | - NZ: MOV 81 | - NZCV: それ以外 82 | 83 | 実行時間: 1S 84 | 85 | ## THUMB.4: 算術演算 86 | 87 | bit | 内容 88 | ---- | ---- 89 | 10-15 | 010000 90 | 6-9 | オペコード 91 | 3-5 | Rs - ソースレジスタ (R0..R7) 92 | 0-2 | Rd - ターゲットレジスタ (R0..R7) 93 | 94 | オペコード(bit6-9): 95 | 96 | 値 | 命令 | 処理内容 | 式 97 | ---- | ---- | ---- | ---- 98 | 0 | AND{S} Rd,Rs | AND | Rd = Rd AND Rs 99 | 1 | EOR{S} Rd,Rs | XOR | Rd = Rd XOR Rs 100 | 2 | LSL{S} Rd,Rs | 論理左シフト | Rd = Rd << (Rs AND 0FFh) 101 | 3 | LSR{S} Rd,Rs | 論理右シフト | Rd = Rd >> (Rs AND 0FFh) 102 | 4 | ASR{S} Rd,Rs | 算術右シフト | Rd = Rd SAR (Rs AND 0FFh) 103 | 5 | ADC{S} Rd,Rs | 足し算(+キャリー) | Rd = Rd + Rs + Carry 104 | 6 | SBC{S} Rd,Rs | 引き算(+キャリー) | Rd = Rd - Rs - NOT Carry 105 | 7 | ROR{S} Rd,Rs | ROR | Rd = Rd ROR (Rs AND 0FFh) 106 | 8 | TST Rd,Rs | bitチェック | Void = Rd AND Rs 107 | 9 | NEG{S} Rd,Rs | 反転 | Rd = 0 - Rs 108 | A | CMP Rd,Rs | 比較 | Void = Rd - Rs 109 | B | CMN Rd,Rs | 比較(反転) | Void = Rd + Rs 110 | C | ORR{S} Rd,Rs | OR | Rd = Rd OR Rs 111 | D | MUL{S} Rd,Rs | 乗算 | Rd = Rd * Rs 112 | E | BIC{S} Rd,Rs | bitクリア | Rd = Rd AND NOT Rs 113 | F | MVN{S} Rd,Rs | 否定 | Rd = NOT Rs 114 | 115 | フラグ: 116 | 117 | - NZCV: ADC,SBC,NEG,CMP,CMN 118 | - NZC: LSL,LSR,ASR,ROR (シフト量が0のときはCは不変) 119 | - NZC: MUL (Cは必ずクリア) 120 | - NZ: AND,EOR,TST,ORR,BIC,MVN 121 | 122 | 実行時間: 123 | 124 | - AND,EOR,ADC,SBC,TST,NEG,CMP,CMN,ORR,BIC,MVN: 1S 125 | - LSL,LSR,ASR,ROR: 1S+1I 126 | - MUL: 1S+mI (m=1..4; 入力Rd値の最上位bitに依存) 127 | 128 | ## THUMB.5: R8-15レジスタ操作/BX命令 129 | 130 | THUMBモードで通常操作できないR8-R15を操作する命令です。 131 | 132 | bit | 内容 133 | ---- | ---- 134 | 10-15 | 0b010001 135 | 8-9 | オペコード 136 | 7 | MSBd - ターゲットレジスタのMSB 137 | 6 | MSBs - ソースレジスタのMSB 138 | 3-5 | Rs - ソースレジスタ (MSBsと合わせて R0..R15) 139 | 0-2 | Rd - ターゲットレジスタ (MSBdと合わせて R0..R15) 140 | 141 | オペコード(bit8-9): 142 | 143 | ``` 144 | 0: ADD Rd,Rs ; add Rd = Rd+Rs 145 | 1: CMP Rd,Rs ; compare Void = Rd-Rs ; CPSR affected 146 | 2: MOV Rd,Rs ; move Rd = Rs 147 | 2: NOP ; nop R8 = R8 148 | 3: BX Rs ; jump PC = Rs 149 | ``` 150 | 151 | ADD, CMP, MOVの場合、MSBsかMSBdのどちらかがセットされている、つまりソースレジスタかターゲットレジスタのどちらか(または両方)がR8-R15の必要があります。 152 | 153 | R15がオペランドのとき、R15に入っているのは`($+4)`であることに注意してください。 154 | 155 | ### BX 156 | 157 | BXにはいくつか注意点があります 158 | 159 | まずMSBdは必ずクリアされている必要があります。Rdは使用されません。 160 | 161 | またRsレジスタに格納されている値(つまりジャンプ先)のbit0が0の場合、ARMモードに切り替わり、(アラインメントのため)Rsのbit1はクリアされます。そのため`BX R15`は必ずワードでアラインメントされたアドレスで行う必要があり、ジャンプ先は上述の通り`PC+4`となります。 162 | 163 | ### その他 164 | 165 | THUMBモードにおいて`MOV R8,R8`は`NOP`として扱われます。 166 | 167 | フラグ: 168 | 169 | - NZCV: CMP 170 | - 不変: それ以外 171 | 172 | 実行時間: 173 | 174 | - ADD,MOV,CMP: 1S 175 | - ADD(`Rd=R15`), MOV(`Rd=R15`), BX: 2S+1N 176 | 177 | -------------------------------------------------------------------------------- /bios/arithmetic.md: -------------------------------------------------------------------------------- 1 | # 算術処理 2 | 3 | Div, DivArm, Sqrt, ArcTan, ArcTan2 4 | 5 | ## Div: swi 0x06(GBA) & swi 0x09(NDS) 6 | 7 | ``` 8 | (r0, r1, r3) = r0/r1 9 | ``` 10 | 11 | ``` 12 | 引数: 13 | r0: 分子 14 | r1: 分母 15 | 16 | 戻り値: 17 | r0: 商 18 | r1: 余り 19 | r3: 商の絶対値 20 | ``` 21 | 22 | 例: 23 | 24 | (r0, r1) = (-1234, 10) のとき 25 | 26 | (r0, r1, r3) = (-123, -4, +123) 27 | 28 | 0で割った時は無限ループに陥ります。 29 | 30 | ## DivArm: swi 0x07(GBA) 31 | 32 | ``` 33 | (r0, r1, r3) = r1/r0 34 | ``` 35 | 36 | 引数の分母分子が逆以外はDivと同じです。 37 | 38 | ARMライブラリとの互換を保つための関数でDivより3クロックだけ遅いです。 39 | 40 | ## Sqrt: swi 0x08(GBA) & swi 0x0d(NDS) 41 | 42 | ``` 43 | r0: uint16 = sqrt(r0: uint32) 44 | ``` 45 | 46 | 返り値は整数になります。例えばsqrt(2)は1になります。 47 | 48 | ## ArcTan: swi 0x09(GBA) 49 | 50 | ArcTanを計算します。 51 | 52 | ``` 53 | 引数: 54 | r0 Tan, 16bit (15bit: 符号部分, 14bit: 整数部分, 13-0bit: 小数部分) 55 | 56 | 戻り値: 57 | r0 = 0xc000-0x4000 (= `-PI/2 [!NOTE] 10 | > SWIをARMステートから呼び出す場合、THUMBステートでは`swi nn`でしたが、ARMステートでは`swi nn*0x10000`とする必要があります。 11 | 12 | ## BIOS関数の一覧 13 | 14 | ### 標準機能 15 | 16 | nn | 関数 17 | -- | -- 18 | 0x00 | SoftReset 19 | 0x01 | RegisterRamReset 20 | 0x02 | Halt 21 | 0x03 | Stop/Sleep 22 | 0x04 | IntrWait 23 | 0x05 | VBlankIntrWait 24 | 0x06 | Div 25 | 0x07 | DivArm 26 | 0x08 | Sqrt 27 | 0x09 | ArcTan 28 | 0x0a | ArcTan2 29 | 0x0b | CpuSet 30 | 0x0c | CpuFastSet 31 | 0x0d | GetBiosChecksum 32 | 0x0e | BgAffineSet 33 | 0x0f | ObjAffineSet 34 | 35 | ### 解凍 36 | 37 | nn | 関数 38 | -- | -- 39 | 0x10 | BitUnPack 40 | 0x11 | LZ77UnCompReadNormalWrite8bit 41 | 0x12 | LZ77UnCompReadNormalWrite16bit 42 | 0x13 | HuffUnCompReadNormal 43 | 0x14 | RLUnCompReadNormalWrite8bit 44 | 0x15 | RLUnCompReadNormalWrite16bit 45 | 0x16 | Diff8bitUnFilterWrite8bit 46 | 0x17 | Diff8bitUnFilterWrite16bit 47 | 0x18 | Diff16bitUnFilter 48 | 49 | ### サウンド・その他 50 | 51 | nn | 関数 52 | -- | -- 53 | 0x19 | SoundBias 54 | 0x1a | SoundDriverInit 55 | 0x1b | SoundDriverMode 56 | 0x1c | SoundDriverMain 57 | 0x1d | SoundDriverVSync 58 | 0x1e | SoundChannelClear 59 | 0x1f | MidiKey2Freq 60 | 0x20 | SoundWhatever0 61 | 0x21 | SoundWhatever1 62 | 0x22 | SoundWhatever2 63 | 0x23 | SoundWhatever3 64 | 0x24 | SoundWhatever4 65 | 0x25 | MultiBoot 66 | 0x26 | HardReset 67 | 0x27 | CustomHalt 68 | 0x28 | SoundDriverVSyncOff 69 | 0x29 | SoundDriverVSyncOn 70 | 0x2a | SoundGetJumpList 71 | 72 | ### GBAとNDSのBIOSのシステムコール関数の違い 73 | 74 | NDSではBIOSに以下の変更が加えられました。 75 | 76 | - SoftResetで使うアドレスが異なる 77 | - Halt, Stop/Sleep, Div, Sqrtを呼び出すためのSWIの番号が異なる 78 | - NDS9ではHaltを使うと、r0の内容が破壊される 79 | - NDS9ではIntrWaitにバグがある 80 | - CpuFastSet allows 4-byte blocks (nice), but... 81 | - CpuFastSet works very SLOW because of a programming bug (uncool) 82 | - 解凍を行う関数でコールバックを利用するようになった 83 | - SoundBiasにdelayを指定するための引数が追加された 84 | 85 | さらにNDSでは、GBAのBIOSにあったいくつかの関数が削除され、新しい関数がいくつか追加されました。 86 | -------------------------------------------------------------------------------- /bios/halt.md: -------------------------------------------------------------------------------- 1 | # Halt 2 | 3 | ## Halt: swi 0x02(GBA) & swi 0x06(NDS) 4 | 5 | 割り込みリクエストが発生するまでCPUを停止します。CPUは低消費電力モード(Halt状態)に切り替わり、その他の回路(ビデオ、サウンド、タイマー、シリアル、キーパッド、システムクロック)は動作し続けます。 6 | 7 | Halt状態は,有効な割り込みが要求されると終了します。つまり,`IE & IF`が0でない場合です。その条件が成立しないとGBAはHaltし続けます。 8 | 9 | ただし,CPUのCPSRレジスタのIRQ無効化ビットとIMEレジスタの状態は関係なく,どちらかが割り込みを無効にしていてもHaltは終了します。 10 | 11 | GBAおよびNDS7/DSi7では、`0x4000301`の`HALTCNT`に書き込むことでHalt状態に入ります。 12 | 13 | NDS9/DSi9では、システム制御コプロセッサへの書き込み(mov p15,0,c7,c0,4,r0 opcode)でHalt状態に入りますが、このopcodeはIME=0の場合にハングアップします。 14 | 15 | ``` 16 | 引数、返り値: なし 17 | ``` 18 | 19 | GBA/NDS7/DSi7ではレジスタは全て不変、NDS9/DSi9のみR0が変更されます 20 | 21 | ## IntrWait: swi 0x04 22 | 23 | DSi7/DSi9、ではバグがある模様? 24 | 25 | 引数で指定した割り込みが起きるまでHaltし続けます。 26 | 27 | このシステムコール関数は強制的に、IMEを1にセットします。 28 | 29 | 複数の割り込みを同時に使用する場合、この関数はHalt関数を繰り返し呼び出すよりもオーバーヘッドが少なくなります。 30 | 31 | ``` 32 | 引数: 33 | r0 34 | 0: 古いフラグでセットされていた場合、すぐにリターンする 35 | 1: 古いフラグは無視して新たにフラグがセットされるまで待つ 36 | r1: 対象の割り込みフラグ(IE/IFと同じフォーマット) 37 | r2: 追加のフラグ(DSi7のみ) 38 | ``` 39 | 40 | Caution: When using IntrWait or VBlankIntrWait, the user interrupt handler MUST update the BIOS Interrupt Flags value in RAM; when acknowleding processed interrupt(s) by writing a value to the IF register, the same value should be also ORed to the BIOS Interrupt Flags value, at following memory location: 41 | 42 | ``` 43 | Host GBA (16bit) NDS7 (32bit) NDS9 (32bit) DSi7-IF2 (32bit) 44 | Address [3007FF8h] [380FFF8h] [DTCM+3FF8h] [380FFC0h] 45 | ``` 46 | 47 | NDS9: BUG: No Discard (r0=0) doesn't work. The function always waits for at least one IRQ to occur (no matter which, including IRQs that are not selected in r1), even if the desired flag was already set. NB. the same bug is also found in the GBA/NDS7 functions, but it's compensated by a second bug, ie. the GBA/NDS7 functions are working okay because their "bug doesn't work". 48 | Return: No return value, the selected flag(s) are automatically reset in BIOS Interrupt Flags value in RAM upon return. 49 | 50 | DSi9: BUG: The function tries to enter Halt state via Port 4000301h (which would be okay on ARM7, but it's probably ignored on ARM9, which should normally use CP15 to enter Halt state; if Port 4000301h is really ignored, then the function will "successfully" wait for interrupts, but without actually entering any kind of low power mode). 51 | 52 | DSi7: BUG: The function tries to wait for IF and IF2 interrupts, but it does accidently ignore the old IF interrupts, and works only with new IF2 ones. 53 | 54 | ## VBlankIntrWait: swi 0x05 55 | 56 | 次のVBlank割り込みが起きるまでHaltし続けます。 57 | 58 | 内部では`r0=1`, `r1=1`, `r2=0(DSi7 only)`をして`IntrWait`を実行しているだけなので、詳細は`IntrWait`を参照してください。 59 | 60 | ``` 61 | 引数、返り値: なし 62 | ``` 63 | 64 | ## Stop: swi 0x03(GBA) 65 | 66 | GBAを超低電力モード(Stop状態)に移行します。CPU、システムクロック、サウンド、ビデオ、DMAやタイマーなども停止します。 67 | 68 | Stop state can be terminated by the following interrupts only (as far as enabled in IE register): Joypad, Game Pak, or General-Purpose-SIO. 69 | 70 | Stop状態は、次の割り込みが起きた時に終了します。Joypad, Game Pak, General-Purpose-SIO 71 | 72 | システムクロックも停止しているので、IFフラグがセットされないことに注意してください。 73 | 74 | Stop状態に入る前に: 75 | 76 | Stop状態に入る前に画面表示を無効にしましょう。そうしないとStop状態に入った時に画面はフリーズし、電力を消費し続けます。 77 | 78 | サウンドも無効にしておくのが望ましいです。当然ですが、外部のハードウェアも無効にできるならそうした方が望ましいです。 79 | 80 | ``` 81 | 引数、返り値: なし 82 | ``` 83 | 84 | ## Sleep: swi 0x07(NDS) 85 | 86 | No info, probably similar as GBA SWI 03h (Stop). 87 | 88 | Sleep is implemented for ARM7 only, not for ARM9. 89 | 90 | But maybe the ARM7 function does stop **both** ARM7 and ARM9 (?) 91 | -------------------------------------------------------------------------------- /bios/memcpy.md: -------------------------------------------------------------------------------- 1 | # メモリのコピー 2 | 3 | CPUFastSet, CPUSet 4 | 5 | ## CPUFastSet: swi 0x0c 6 | 7 | 32**バイト**単位でのメモリコピー・メモリ埋めをおこないます。 8 | 9 | メモリコピーは `LDMIA/STMIA [Rb]!,r2-r9` を繰り返し行うことでコピーをします。 10 | 11 | メモリ埋めは `STMIA [Rb]!,r2-r9`を繰り返した後でLDRを1回します。 12 | 13 | 処理サイズはワード単位によって指定されています。つまり処理サイズのバイト数を4で割った値です。 14 | 15 | GBAの場合、処理サイズは8ワード単位、つまりバイト数が32の倍数であることが望ましいです。そうでない場合は強制的に処理サイズを切り上げします。 16 | 17 | ``` 18 | 引数: 19 | r0: ソースアドレス 20 | r1: ターゲットアドレス 21 | r2: サイズ/モード 22 | Bit0-20: 処理サイズ(ワード単位) 23 | Bit24: モード(0=Copy, 1=アドレスr0に格納された値でFill) 24 | 25 | 戻り値: なし 26 | ``` 27 | 28 | ## CPUSet: swi 0x0b 29 | 30 | 2または4バイト単位でのメモリコピー・メモリ埋めをおこないます。 31 | 32 | メモリコピーは`LDMIA/STMIA [Rb]!,r3` または `LDRH/STRH r3,[r0,r5]` を繰り返すことで行われています。 33 | 34 | メモリ埋めは`STMIA [Rb]!,r3` か `STRH r3,[r0,r5]` を繰り返した後に `LDMIA` か `LDRH` を行うことでメモリ埋めをおこないます。 35 | 36 | 処理サイズのバイト長は4バイト(32bitモード)か2バイト(16bitモード)の倍数である必要があります。 37 | 38 | r2の処理サイズは32bitモードならワード単位、16bitモードならハーフワード単位であることに注意してください。 39 | 40 | ``` 41 | 引数: 42 | r0: ソースアドレス 43 | r1: ターゲットアドレス 44 | r2: サイズ/モード/処理単位 45 | Bit0-20: 処理サイズ(ワード/ハーフワード単位) 46 | Bit24: モード(0=Copy, 1=アドレスr0に格納された値でFill) 47 | Bit26: 処理単位(0=16bit, 1=32bit) 48 | 49 | 戻り値: なし 50 | ``` 51 | 52 | ## 注意 53 | 54 | CPUFastSetもCPUSetもコピー元、コピー先のどちらかがBIOS領域に到達すると特に通知せずに終了します。 55 | -------------------------------------------------------------------------------- /bios/reset.md: -------------------------------------------------------------------------------- 1 | # リセット 2 | 3 | SoftReset, RegisterRamReset, HardReset 4 | 5 | ## SoftReset: swi 0x00 6 | 7 | スタック、BIOSのIRQベクタやフラグなどRAM領域を200バイトクリアし、システムスタック、SVCスタック、IRQスタックのポインタを初期化します。最後に、R0-R12, LR_svc, SPSR_svc, LR_irq, SPSR_irqを0クリアしてシステムモードに切り替わります。 8 | 9 | NDS9のスタックレジスタSPはハードコードされていることに注意してください。NDS9では`SoftReset`はさらに、キャッシュとライトバッファをクリアし、CP15コントロールレジスタを`0x12078`に設定します。 10 | 11 | Host | sp_svc | sp_irq | sp_sys | zerofilled area | return address 12 | -- | -- | -- | -- | -- | -- 13 | GBA | 0x3007FE0 | 0x3007FA0 | 0x3007F00 | [0x3007E00..0x3007FFF] | Flag[0x3007FFA] 14 | NDS7 | 0x380FFDC | 0x380FFB0 | 0x380FF00 | [0x380FE00..0x380FFFF] | Addr[0x27FFE34] 15 | NDS9 | 0x0803FC0 | 0x0803FA0 | 0x0803EC0 | [DTCM+0x3E00..0x3FFF] | Addr[0x27FFE24] 16 | 17 | (NDSのみ)リセット処理はSWIを実行したCPUでのみ行われることに注意してください。 18 | 19 | ``` 20 | 引数、返り値: なし 21 | ``` 22 | 23 | `SoftReset`からリターンするときは呼び出した関数には戻らず、上記のリターンアドレスをR14にロードし、`BX R14`オペコードでそのアドレスにジャンプします。 24 | 25 | ## RegisterRamReset: swi 0x01 26 | 27 | ResetFlagsで指定されたI/OレジスタやRAMをリセットします。ただし、`0x3007E00-0x3007FFF`のCPU内蔵RAM領域はクリアされません。 28 | 29 | ``` 30 | 引数: r0(ResetFlags) 31 | Bit Expl. 32 | 0 Clear 256K on-board WRAM ; -don't use when returning to WRAM 33 | 1 Clear 32K on-chip WRAM ; -excluding last 200h bytes 34 | 2 Clear Palette 35 | 3 Clear VRAM 36 | 4 Clear OAM ; -zerofilled! does NOT disable OBJs! 37 | 5 Reset SIO registers ; -switches to general purpose mode! 38 | 6 Reset Sound registers 39 | 7 Reset all other registers (except SIO, Sound) 40 | 41 | 返り値: なし 42 | ``` 43 | 44 | R0のBit5をクリアしてもSIODATA32のLSBが常にクリアされてしまうバグがあります。 45 | 46 | `DISPCNT=0x0080`にすると、常に強制的に画面を白に切り替える機能があります(R0の入力に関わらず、画面が白になります)。 47 | 48 | ## HardReset: swi 0x26(GBA, Undocumented) 49 | 50 | この機能は、GBAを再起動します(時間のかかるnintendoの起動画面を無視するための機能も含まれていますが、この機能は特に役に立たず、煩わしいものとなっています)。 51 | 52 | ``` 53 | 引数、返り値: なし 54 | ``` 55 | 56 | 実行時間: 2秒 57 | 58 | -------------------------------------------------------------------------------- /bios/rotation_scaling.md: -------------------------------------------------------------------------------- 1 | # 伸縮回転 2 | 3 | BgAffineSet, ObjAffineSet 4 | 5 | ## BgAffineSet: swi 0x0e(GBA) 6 | 7 | BGの伸縮回転パラメータを計算するのに使用します。 8 | 9 | ``` 10 | 引数: 11 | r0: ソースデータへのポインタ 12 | s32 変換前のデータのX座標 (8bitの小数部分あり) 13 | s32 変換前のデータのY座標 (8bitの小数部分あり) 14 | s16 変換後のデータの中心X座標 15 | s16 変換後のデータの中心Y座標 16 | s16 X方向の伸縮率 (8bitの小数部分あり) 17 | s16 Y方向の伸縮率 (8bitの小数部分あり) 18 | u16 回転角度 (8bitの小数部分あり) (0x0~0xffff) 19 | r1: ターゲットデータへのポインタ 20 | s16 Difference in X coordinate along same line 21 | s16 Difference in X coordinate along next line 22 | s16 Difference in Y coordinate along same line 23 | s16 Difference in Y coordinate along next line 24 | s32 X座標の開始点 25 | s32 Y座標の開始点 26 | r2: 計算数(ソースデータおよびターゲットデータは配列になっていてその要素数) 27 | 28 | 返り値: なし 29 | ``` 30 | 31 | ## ObjAffineSet: swi 0x0f(GBA) 32 | 33 | OBJのアフィン変換のパラメータを拡大縮小率と回転角度から計算してセットする機能です。 34 | 35 | アフィン変換のパラメータはSrc(r0)が示すパラメータから計算されます。 36 | 37 | 4つのアフィン変換のパラメータ(pa, pb, pc, pd)は、Dst(r1)が示すアドレスから、Offsetバイト(r3)ごとに設定されます。 38 | 39 | Offsetの値が2であれば、パラメータは連続して保存(`0x0`, `0x2`, `0x4`, `0x6`, ...)され、値が8の場合、OAMの構造と一致します。(`0x0`, `0x8`, `0x10`, `0x18`, ...) 40 | 41 | Srcのポインタが配列になっている場合は、Num(r2)を指定することにより、その数だけ連続して計算を行います。 42 | 43 | ``` 44 | 引数: 45 | r0: ソースデータへのポインタ 46 | s16 X方向の伸縮率 (8bitの小数部分あり) 47 | s16 Y方向の伸縮率 (8bitの小数部分あり) 48 | u16 回転角度 (8bitの小数部分あり) (0x0~0xffff) 49 | r1: ターゲットデータへのポインタ 50 | s16 Difference in X coordinate along same line 51 | s16 Difference in X coordinate along next line 52 | s16 Difference in Y coordinate along same line 53 | s16 Difference in Y coordinate along next line 54 | r2: 計算数(ソースデータおよびターゲットデータは配列になっていてその要素数) 55 | r3: Offset 56 | 57 | 返り値: なし 58 | ``` 59 | 60 | ## 補足 61 | 62 | Bg-、ObjAffineSetともに、回転角度は0x0~0xffff(0~360度)で指定できますが、GBAのBIOSは上位8bitのみを参照し、下位8bitには端数が含まれている可能性がありますが、BIOSでは無視しています。 63 | -------------------------------------------------------------------------------- /cartridge/addon/carde.md: -------------------------------------------------------------------------------- 1 | # カードe 2 | 3 | e-reader 4 | 5 | ## 概要 6 | 7 | カードeは、大きなGBAカートリッジに、ドットコードを読み取るハードウェアを内蔵したものです。海外ではe-Readerと呼ばれています。 8 | 9 | ドットコードとは、厚紙のカードの端に印刷された白黒のピクセルの小さな帯のことです。このカードをe-Readerのスロットに通すことで、まるで磁気カードリーダーのような感覚で読み取ることができるのです。 10 | 11 | ドットコード上のバイナリデータには、GBAのネイティブコード(ARM/THUMB)、またはソフトウェアでエミュレートされた8ビットのZ80やファミコン(6502)のコードで、小さなゲームが格納されています。 12 | 13 | **ハードウェア(カードe)のスペック** 14 | 15 | ハードウェアは、通常の8MBのROMと128KBのFLASHチップ、2つの通信ポート、カスタムPGAチップ(PGA=Pin Grid Array)、カメラモジュール(光源として使用される2つの赤色LED付き)、LED電圧を生成するためのいくつかのアナログ部品などで構成されています。 16 | 17 | カメラは402x302ピクセル、7ビットのモノクロ色深度に対応していますが、PGAは1ビットの色深度でスキャンラインあたり最大320ピクセルにクリップします。 18 | 19 | **通信ポート** 20 | 21 | カードeの2つの通信ポートは、単に相互に接続されているだけで、他のカードeとは接続されていません。このポートは初代GBAでのみ使用されています。見た目はカードeの大型カートリッジがGBAの通信ポートを覆う形になります。 22 | 23 | ニンテンドーDS(またはGBA-Micro)にカードeを挿入しようとすると、カードeのリンクプラグがDSのケースに当たってしまうため、ハードウェアを少し改造しないと動作しませんでした。GBASPやDS Liteではそのような問題はありません。 24 | 25 | **リビジョン/バージョン** 26 | 27 | カードeには3つの種類があります。 28 | 29 | - カードe(日本) 30 | - カードeプラス(日本) 31 | - e-Reader(日本以外) 32 | 33 | の3つです。 34 | 35 | カードeは64KBのフラッシュのみで、通信ポートはなく、Z80コードのみをサポートし、NES/GBAコードはサポートしないと言われています。 36 | 37 | カードeプラスとe-Readerは、違う種類のカードeのカードを拒否することと、日本ではタイトル文字列がASCIIではないことを除けば、ほとんど同じであるはずです。 38 | 39 | **エミュレーション** 40 | 41 | 任天堂のプログラマーは、パックマンのようなゲームを4MB以下に収めることはできませんでした。そのため、これらのゲームを動かすために彼らが取った解決策はメモリを増やすことでした。 42 | 43 | つまり、カードe本体には8MBのBIOS ROMを搭載し、その中にはユーザーインターフェースと、20年前の8bit NESやGame&Watchのタイトルを動かすためのソフトウェアのエミュレーションが含まれており、数枚のドットコードに収まるようになっています。 44 | 45 | ## I/Oポート 46 | 47 | TODO 48 | 49 | ## ドットコードフォーマット 50 | 51 | TODO 52 | 53 | ## データフォーマット 54 | 55 | TODO 56 | 57 | ## プログラムコード 58 | 59 | TODO 60 | 61 | ## API 62 | 63 | TODO 64 | 65 | ## VPK解凍 66 | 67 | TODO 68 | 69 | ## エラー訂正 70 | 71 | TODO 72 | 73 | ## ファイルフォーマット 74 | 75 | **.BMP Files (homebrew 300 DPI strips)** 76 | 77 | アドレスバーやシンクマーク(「ドットコード」の章を参照)を含むドットコードストリップ全体の画像を、マイクロソフト社のビットマップ形式で収録しています。 78 | 79 | Contains a picture of the whole dotcode strip with address bars and sync marks (see Dotcode chapter) in Microsoft's Bitmap format. The image is conventionally surrounded by a blank 2-pixel border, resulting in a size of 989x44 pixels for long strips. The file should should have 1bit color depth. The pixels per meter entry should match the desired printing resolution, either 300 DPI or 360 DPI. But, resolution of printer hardware is typically specified in inch rather than in meters, so an exact match isn't supported by Microsoft. Most homebrew .BMP files contain nonsense resolutions like 200 DPI, or 300 dots per meter (ca. 8 DPI). 80 | 81 | **.JPG Files (scanned 1200 DPI strips)** 82 | 83 | Same as BMP, but should contain a dotcode scanned at 1200 DPI, with correct orientation (the card-edge side at the bottom of the image), and containing only the dotcode (not the whole card), so the JPG size should be about 3450x155 pixels for long strips. 84 | No$gba currently doesn't work with progressive JPGs. Scans with white background can be saved as monochrome JPG. Scans with red/yellow background should contain a correct RED layer (due to the red LED light source) (the brightness of the green/blue layers can be set to zero for better compression). 85 | 86 | **.RAW Files** 87 | 88 | TODO 89 | 90 | -------------------------------------------------------------------------------- /cartridge/addon/classic.md: -------------------------------------------------------------------------------- 1 | # ファミコンミニシリーズ 2 | 3 | nes-classic 4 | 5 | GBAのソフトには、ファミコンのゲームをGBA用に移植/エミュレートした[ファミコンミニシリーズ](https://www.nintendo.co.jp/n08/fmk/index.html)というシリーズのゲームがあります。 6 | 7 | これらのゲームはオリジナルのGBA本体やカートリッジを使用していない場合は、次のような、互換性の問題を引き起こす可能性のある、一般的ではないことをしているゲームです。 8 | 9 | - CPU pipeline (selfmodifying code that shall NOT affect prefetched opcodes) 10 | - STMDA write to I/O ports (writes in INCREASING order, not DECREASING order) 11 | - SRAM検知 (オリジナルのゲームではEEPROMを使っており、SRAMが使われていた場合拒絶(?)します) 12 | - ROMのミラー (instead of the usual increasing numbers in unused ROM area) 13 | - RAMのミラー (例: EWRAM`0x0200_0000`にアクセスする代わりに`0x02F0_0000`にアクセス) 14 | 15 | ファミコンミニシリーズかどうかは`0x0800_00AC`の値がASCIIコードの`F`(`0x66`)かをチェックすることで判別できます。 16 | -------------------------------------------------------------------------------- /cartridge/addon/gpio.md: -------------------------------------------------------------------------------- 1 | # GPIO 2 | 3 | ROMチップの中には4bitのGPIOが入っています。 4 | 5 | [ボクらの太陽](https://ja.wikipedia.org/wiki/%E3%83%9C%E3%82%AF%E3%82%89%E3%81%AE%E5%A4%AA%E9%99%BD)ではRTCと太陽センサーにGPIOを使っています。 6 | 7 | [まわるメイドインワリオ](https://www.nintendo.co.jp/n08/rzwj/index.html)では振動パックとジャイロセンサーにGPIOを使っています。 8 | 9 | 他のゲームでも、上記以外のセンサーやSRAMバンクの切り替えなど、他の目的で使用されるかもしれません。 10 | 11 | GPIOのI/Oレジスタは(`0x04xx_xxxx`ではなく)ROMエリアの`0x0800_00C4`にある6バイトの領域にマッピングされており、この6バイトの領域はROMイメージではゼロ埋めされているはずです。ボクらの太陽では、このゼロ埋め領域のサイズは0E0hバイトとなっていますが、これは定義が間違っているためです。 12 | 13 | この領域には追加のポートはありません。ミラー領域になっている場所もありません。 14 | 15 | また、ROMバスへの書き込みは16bit/32bitのアクセスに限定されています。 16 | 17 | ## 0x0800_00C4 - I/Oポートデータ (W または R/W) 18 | 19 | パーミッションは後述の[制御レジスタ](#0x0800_00c8---ioポート制御レジスタ-w-または-rw)で 書き込みのみ と、読み書き可能 のどちらかから選択可能です。 20 | 21 | bit | 内容 22 | -- | -- 23 | 0 | データビット0 24 | 1 | データビット1 25 | 2 | データビット2 26 | 3 | データビット3 27 | 4-15 | 不使用(常に0) 28 | 29 | ## 0x0800_00C6 - I/Oポートディレクション (W または R/W) 30 | 31 | bit | 内容 32 | -- | -- 33 | 0 | ポートディレクション0(0=In, 1=Out) 34 | 1 | ポートディレクション1 35 | 2 | ポートディレクション2 36 | 3 | ポートディレクション3 37 | 4-15 | 不使用(常に0) 38 | 39 | ## 0x0800_00C8 - I/Oポート制御レジスタ (W または R/W) 40 | 41 | 上のI/Oポートデータ、I/Oポートディレクション(、そしてこのレジスタ自身)のパーミッションを制御します。 42 | 43 | bit | 内容 44 | -- | -- 45 | 0 | パーミッション(0=書き込みのみ, 1=読み書き可能) 46 | 1-15 | 不使用(常に0) 47 | 48 | ## 接続の例 49 | 50 | ``` 51 | GPIO | Boktai | Wario 52 | Bit Pin | RTC SOL | GYR RBL 53 | -----------+---------+--------- 54 | 0 ROM.1 | SCK CLK | RES - 55 | 1 ROM.2 | SIO RST | CLK - 56 | 2 ROM.21 | CS - | DTA - 57 | 3 ROM.22 | - FLG | - MOT 58 | -----------+---------+--------- 59 | IRQ ROM.43 | IRQ - | - - 60 | ``` 61 | 62 | Aside from the I/O Port, the ROM-chip also includes an inverter which is used for inverting the RTC /IRQ signal, and some sort of an (unused) address decoder output which appears to be equal or related to A23 signal. That is, reacting on ROM A23, or SRAM D7, which share the same pin on GBA slot. 63 | 64 | -------------------------------------------------------------------------------- /cartridge/addon/rtc.md: -------------------------------------------------------------------------------- 1 | # RTC(Real-Time Clock) 2 | 3 | RTCは、ポケモンシリーズやボクらの太陽シリーズで使用されています。 4 | 5 | ## 概要 6 | 7 | GBAのRTCには、ボクらの太陽の場合、S3511という、3線式のシリアルバスをもった8ピンのRTCが使われています。 8 | 9 | このRTCチップはほとんど[NDSで使われているもの](https://github.com/akatsuki105/nds-docs-ja/blob/main/system/rtc.md)と同じように使用されます。 10 | 11 | このRTCチップは4bit幅のIOポート(GPIO)を通じてアクセスします。RTCで使うのは3bitだけです。 12 | 13 | ## NDSのRTCレジスタとの比較 14 | 15 | ``` 16 | NDS_________GBA_________GBA/Params___ 17 | stat2 control (1-byte) 18 | datetime datetime (7-byte) 19 | time time (3-byte) 20 | stat1 force reset (0-byte) 21 | clkadjust force irq (0-byte) 22 | alarm1/int1 always FFh (boktai contains code for writing 1-byte to it) 23 | alarm2 always FFh (unused) 24 | free always FFh (unused) 25 | ``` 26 | 27 | ## 制御レジスタ 28 | 29 | bit | R/W | 内容 30 | -- | -- | -- 31 | 0 | - | 不使用 32 | 1 | R/W | IRQ duty/hold related? 33 | 2 | - | 不使用 34 | 3 | R/W | Per Minute IRQ (30s duty) (0=Disable, 1=Enable) 35 | 4 | - | 不使用 36 | 5 | R/W | 用途不明 37 | 6 | R/W | 12/24-hour Mode (0=12h, 1=24h) (usually 1) 38 | 7 | R | Power-Off (auto cleared on read) (0=Normal, 1=Failure) 39 | 40 | このレジスタは、`Battery-Shortcut`の後では`$82(0b1000_0010)`に、`Force-Reset`の後では`$00`がセットされます。 41 | 42 | 不使用のビットは常に0のように見えますが、読み取り可能(R)か書き込み可能(W)のどちらかであるようです。 43 | 44 | ## Dateレジスタ 45 | 46 | NDSのそれと全く同じです。 47 | 48 | ``` 49 | Year Register 50 | 0-7 R/W Year (BCD 00h..99h = 2000..2099) 51 | Month Register 52 | 0-4 R/W Month (BCD 01h..12h = January..December) 53 | 5-7 - Not used (always zero) 54 | Day Register 55 | 0-5 R/W Day (BCD 01h..28h,29h,30h,31h, range depending on month/year) 56 | 6-7 - Not used (always zero) 57 | Day of Week Register (septenary counter) 58 | 0-2 R/W Day of Week (00h..06h, custom assignment, usually 0=Monday?) 59 | 3-7 - Not used (always zero) 60 | ``` 61 | 62 | ## Timeレジスタ 63 | 64 | AM/PMフラグのビットの位置が違うことを除けばNDSのそれと同じです。 65 | 66 | - NDSのAM/PMフラグ: hour.bit6 67 | - GBAのAM/PMフラグ: hour.bit7 68 | 69 | ``` 70 | Hour Register 71 | 0-5 R/W Hour (BCD 00h..23h in 24h mode, or 00h..11h in 12h mode) 72 | 6 - Not used (always zero) 73 | 7 * AM/PM (0=AM before noon, 1=PM after noon) 74 | * 24h mode: AM/PM flag is read only (PM=1 if hour = 12h..23h) 75 | * 12h mode: AM/PM flag is read/write-able 76 | * 12h mode: Observe that 12 o'clock is defined as 00h (not 12h) 77 | Minute Register 78 | 0-6 R/W Minute (BCD 00h..59h) 79 | 7 - Not used (always zero) 80 | Second Register 81 | 0-6 R/W Minute (BCD 00h..59h) 82 | 7 - Not used (always zero) 83 | ``` 84 | 85 | ## Force Reset/Irq Registers 86 | 87 | Used to reset all RTC registers (all used registers become 00h, except 88 | day/month which become 01h), or to drag the IRQ output LOW for a short moment. 89 | These registers are strobed by ANY access to them, ie. by both writing to, as 90 | well as reading from these registers. 91 | 92 | ## Pin-Outs / IRQ Signal 93 | 94 | パッケージのピン配置はNDSと同じですが、チップがDSのそれよりも若干大きくなっています。 95 | 96 | For whatever reason, the RTC's /IRQ output is passed through an inverter 97 | (contained in the ROM-chip), the inverted signal is then passed to the /IRQ pin 98 | on the cartridge slot. So, IRQ's will be triggered on the "wrong" edge - 99 | possible somehow in relation with detecting cartridge-removal IRQs? 100 | -------------------------------------------------------------------------------- /cartridge/addon/rumble.md: -------------------------------------------------------------------------------- 1 | # 振動パック 2 | 3 | 振動パックはGBAを振動させるための周辺機器です。 4 | 5 | 振動パックを備えたカートリッジは、一般的には「振動カートリッジ」と呼ばれています。 6 | 7 | ライセンスソフトで振動カートリッジなのは 8 | 9 | - [スクリューブレイカー 轟振どりるれろ](https://www.nintendo.co.jp/n08/v49j/index.html) 10 | - [まわるメイドインワリオ](https://www.nintendo.co.jp/n08/rzwj/index.html) 11 | 12 | が該当します。 13 | 14 | GBAの振動カートリッジには小型モーターが搭載されており、スイッチを入れたとき/入れているときに振動を発生させます。DSの振動カートリッジでは、GBAと違ってスイッチのオン・オフを繰り返すことで振動を発生させているようです。 15 | 16 | まわるメイドインワリオでは、[GPIO](gpio.md)のbit3(データ、ディレクション)を振動機能の制御に利用して、他のbitはジャイロセンサーに利用しているようです。 17 | 18 | Note: GPIO3 is connected to an external pulldown resistor (so the HighZ level gets dragged to Low=Off when direction is set to Input). 19 | 20 | スクリューブレイカー 轟振どりるれろ での詳細は不明です。 21 | 22 | ## DSの振動パック 23 | 24 | また、NDSにはGBAスロットに接続する振動パックがあり、(マルチブートゲームのようなGBAスロットを必要としないゲームなら)GBAのゲームにも使用することができます。 25 | 26 | 詳細は[こちら](https://problemkaputt.de/gbatek.htm#dscartrumblepak)を参照 27 | 28 | ## ゲームキューブの振動パック 29 | 30 | また、ゲームボーイプレイヤーで動作するGBAゲームは、ゲームキューブコントローラーの振動機能を利用しています。 31 | 32 | 詳細は[こちら](https://problemkaputt.de/gbatek.htm#gbagameboyplayer)を参照 33 | -------------------------------------------------------------------------------- /cartridge/addon/solar.md: -------------------------------------------------------------------------------- 1 | # 太陽センサー 2 | 3 | 文字通り、太陽の光を検知するためのセンサーです。[ボクらの太陽(ボクタイ)](https://ja.wikipedia.org/wiki/%E3%83%9C%E3%82%AF%E3%82%89%E3%81%AE%E5%A4%AA%E9%99%BD)では、カートリッジに太陽光が当たると吸血鬼を倒すことができます。 4 | 5 | 太陽センサーとしてフォトダイオードを使用しています。 6 | 7 | カートリッジは透明なケースに入っていて、通常のカートよりも少し長いので、センサーはカートリッジスロットから出ています。 8 | 9 | ![](../../images/boktai.jpeg "https://hinoasuno.hatenablog.com/ より引用") 10 | 11 | 説明書によると、このセンサーは太陽光でのみ動作するとのことですが、実際にはどんな強い光源でも動作します。例えば、100ワットの電球を1〜2cmの距離に置いた場合でも動作します。 12 | 13 | センサーへのアクセスは、ROMチップに内蔵された4bitのI/Oポート(3bitのみ使用)を介して行われます。詳細は[GPIO](gpio.md)を参照してください。 14 | 15 | ## A/D変換 16 | 17 | ``` 18 | Note: 筆者(Akatsuki)が電子回路に詳しくないため、間違った記述があるかもしれません。 19 | ``` 20 | 21 | このカートリッジは、独自の[Digital Ramp ADC](https://www.allaboutcircuits.com/textbook/digital/chpt-13/digital-ramp-adc/)を使用しています。 22 | 23 | これは、コンデンサの充電時間を測定するよりも優れており、本物のADCチップよりも安価です。 24 | 25 | 74LV4040の12bitのバイナリカウンタが内蔵されており、I/Oポートを介してCPUからクロックが送られてきます。 26 | 27 | このうち下位8bitのみが使用され、抵抗ラダー型のDACに渡され、直線的に増加する電圧が生成されます。 28 | 29 | この電圧はTLV272の電圧コンパレータに渡され、カウンタの電圧がセンサの電圧よりも大きくなるとI/Oポートに信号が送られます。 30 | 31 | ## サンプルコード 32 | 33 | ```asm 34 | strh 0001h,[80000c8h] ;-enable R/W mode 35 | strh 0007h,[80000c6h] ;-init I/O direction 36 | strh 0002h,[80000c4h] ;-reset counter to zero (high=reset) (I/O bit0) 37 | strh 0000h,[80000c4h] ;-clear reset (low=normal) 38 | mov r0,0 ;-initial level 39 | @@lop: 40 | strh 0001h,[80000c4h] ;-clock high ;\increase counter (I/O bit1) 41 | strh 0000h,[80000c4h] ;-clock low ;/ 42 | ldrh r1,[80000c4h] ;-read port (I/O bit3) 43 | tst r1,08h ;\ 44 | addeq r0,1 ; loop until voltage match (exit with r0=00h..FFh), 45 | tsteq r0,100h ; or until failure/timeout (exit with r0=100h) 46 | beq @@lop ;/ 47 | ``` 48 | 49 | 使用するクロックレートによって結果が異なります。 50 | 51 | 上記のサンプルコードを使う場合、IRQやDMAによって処理を中断されないようにするか、超低速のクロックレート(例:ボクタイでは666Hz)を使用して、小さなIRQ/DMAの遅れが全体のタイミングにほとんど影響しないようにする必要があります。 52 | 53 | 上記のサンプルコードを実行すれば、太陽センサーから読み取った値が次のように得られます。 54 | 55 | 値 | 内容 56 | -- | -- 57 | 0xE8 | 完全に真っ暗(LED光や、雨の日の日光レベル) 58 | 0xDx | 100W電球で灯した部屋くらいの明るさの日光 59 | 0x5x | ボクタイで太陽ゲージがMAXになるくらいの日光 60 | 0x00 | 原爆の光レベルの日光 61 | 62 | 正確な値はカートリッジごとに変わる可能性があるため、自作のカートリッジに太陽センサーを導入したい場合は、暗さの補正機能を搭載して、遊んでもらう際にはユーザーがセンサーをしばらく覆うように促すことをお勧めします。 63 | 64 | ボクタイの場合は、タイトル画面で左/右を押して入れるオプションメニューでこの補正を行います。 65 | 66 | また、自動補正を使えば、理論的には、これまでにゲーム内で見た最も暗いレベルを記憶することができます。 67 | 68 | -------------------------------------------------------------------------------- /cartridge/backup/README.md: -------------------------------------------------------------------------------- 1 | # バックアップメディア 2 | 3 | セーブ機能のことです。 4 | 5 | ## バックアップID文字列 6 | 7 | バックアップメディアの種類を検出するためのIDです。 8 | 9 | GBAはROMヘッダにバックアップタイプのエントリを入れていません。しかしバックアップタイプはROM内にある後述のID文字列から検出できます。 10 | 11 | 任天堂のツールでは、これらの文字列を(ライブラリ・ヘッダの一部として)自動的に挿入しています。 12 | 13 | **ID文字列** 14 | 15 | ID文字列を配置するアドレスは4バイトアラインメントされている必要があります。また文字列の長さは4バイトの倍数でなければなりません。(余った分はゼロでパディングされます) 16 | 17 | ID文字列 | 内容 18 | -- | -- 19 | `EEPROM_Vnnn` | EEPROM 512B or 8KB 20 | `SRAM_Vnnn` | SRAM 32KB or FRAM 32KB 21 | `FLASH_Vnnn` or `FLASH512_Vnnn` | FLASH 64KB (後者は新しめのゲーム) 22 | `FLASH1M_Vnnn` | FLASH 128KB 23 | 24 | 任天堂のツールでID文字列を挿入する場合、`nnn`は3桁のライブラリバージョン番号です。サードパーティツールで挿入する場合は、数字を入れずに`nnn`のままにしておくとよいでしょう。 25 | 26 | ## 🔋 SRAM/FRAM 27 | 28 | > [!NOTE] 29 | > FRAM は `Ferroelectric RAM` の略で、FLASHとは別物です。 30 | 31 | [こちら](./sram.md)を参照してください。 32 | 33 | ## ⚡️ EEPROM 34 | 35 | [こちら](./eeprom.md)を参照してください。 36 | 37 | ## 📸 FLASH 38 | 39 | [こちら](./flash.md)を参照してください。 40 | 41 | ## 🧰 DACS 42 | 43 | ``` 44 | 1Mbit DACS: 128 KB 45 | セーブ機能の寿命: 100,000 writes. 46 | 8Mbit DACS: 1024 KB 47 | セーブ機能の寿命: 100,000 writes. 48 | ``` 49 | 50 | DACS (Debugging And Communication System) is used in Nintendo's hardware debugger only, DACS is NOT used in normal game cartridges. 51 | 52 | Parts of DACS memory is used to store the debugging exception handlers (entry point/size defined in cartridge header), the remaining memory could be used to store game positions or other data. The address space is the upper end of the 32MB ROM area, the memory can be read directly by the CPU, including for ability to execute program code in this area. 53 | -------------------------------------------------------------------------------- /cartridge/backup/eeprom.md: -------------------------------------------------------------------------------- 1 | # ⚡️ EEPROM 2 | 3 | ``` 4 | EEPROM 512B 5 | チップ名: 9853 6 | セーブ機能の寿命: アドレスあたり100,000回の読み書き 7 | 例: スーパーマリオアドバンス 8 | EEPROM 8KB 9 | チップ名: 9854 10 | セーブ機能の寿命: アドレスあたり100,000回の読み書き 11 | 例: ボクらの太陽 12 | ``` 13 | 14 | ## アクセス 15 | 16 | EEPROM はデータバスのbit0と、カートリッジROMアドレスバスの上位1bit(32MBの大容量ROMの場合は上位17bit)に接続されており、チップとの通信はシリアルで行われます。 17 | 18 | EEPROMは`0xDFFFF00..0xDFFFFFF`(WS2)にマッピングされます。(`WAITCNT=0xX3XXh`の場合)アクセスには8サイクルが必要です。 19 | 20 | EEPROMのデータは、64bit(8バイト)単位で読み書きできます。 21 | 22 | 書き込みを行うと、それまでの64bitのデータは自動的に消去されます。 23 | 24 | アドレッシングについて、512BのEEPROMでは、`0x0..3F`のアドレス範囲、6bitのバス幅となります。8KBのEEPROMでは、`0x0..3FF`のアドレス範囲,14bitのバス幅となります。(アドレスの下位10bitのみ使用し、上位4bitは0とします) 25 | 26 | ## コマンド 27 | 28 | **読み込み対象のアドレス設定** 29 | 30 | 次のようなビットストリームをメモリ上に用意し、DMAを使ってEEPROMに転送します。 31 | 32 | ``` 33 | 11XXXXXX0 34 | 0b11: 読み込みリクエストを示す2bit 35 | 0bXXXXXX: 設定する6bitのEEPROMのアドレス (8KBのEEPROMでは14bit) 36 | 0b0: 終端bit 37 | ``` 38 | 39 | **データの読み込み** 40 | 41 | DMAを使ってEEPROM(`0xDFFFF00..0xDFFFFFF`)から68bitのビットストリームを読み出し、受信したデータを以下のようにデコードします。 42 | 43 | ``` 44 | 4 bits - 無視 45 | 64 bits - 読み出したデータ 46 | ``` 47 | 48 | **データの書き込み** 49 | 50 | 次のようなビットストリームをメモリ上に用意し、DMAを使ってEEPROMに転送します。 51 | 52 | 古いデータが消去され、新しいデータが書き込まれるまで、約108368クロックサイクル(約6.5ms)かかります。 53 | 54 | ``` 55 | 10XXXXXXDD...DDD0 56 | 0b10: 書き込みリクエストを示す2bit 57 | 0bXXXXXX: 書き込み先を示す6bitのEEPROMのアドレス (8KBのEEPROMでは14bit) 58 | 0bDD...DDD: 書き込む64bitデータ 59 | 0b0: 終端bit 60 | ``` 61 | 62 | DMA終了後、通常の`LDRH [DFFFF00h]`により、戻ってきたデータのビット0が "1"(Ready)になるまで、チップからの読み出しを続けます。 63 | 64 | 誤動作時にプログラムがロックしないように、10ms以上経ってもチップが応答しない場合はタイムアウトを発生させてください。 65 | 66 | ## DMAによるアクセス 67 | 68 | ビットストリームのEEPROMに対する読み書きは、DMA3を介して行う必要があります。 転送中に`/CS=LOW`と`A23=HIGH`を維持しないため、LDRH/STRHによる手動転送は動作しません。 69 | 70 | DMAを使用するためには、メモリ上のバッファを使用する必要があります。そのバッファは、通常、スタック上に一時的に割り当てられ、2バイトあたり1bitを使用します。つまりbit0のみが使用され、bit1-15は無視されます。 71 | 72 | バッファはDMA3を使用してEEPROMへ(or から)全体として転送する必要があります(DMA0-2は外部メモリにアクセスできません)。転送モードは16bitで、ソースとデスティネーションの両方のアドレスをインクリメントします。(例:DMA3CNT=`0x80000000+length`) 73 | 74 | 優先度の高いDMAチャンネルは、転送中は無効にしてください(例:H/V-BlankやSound FIFO DMA)。また、DMAレジスタに干渉する可能性のある割り込みは、当然ながら無効にしてください。 75 | 76 | **注意** 77 | 78 | 自動検出の仕組みがないため、ハードコードされたバス幅を使用しなければならないようです。 79 | -------------------------------------------------------------------------------- /cartridge/backup/flash.md: -------------------------------------------------------------------------------- 1 | # 📸 FLASH 2 | 3 | ``` 4 | 512Kb Flash ROM: 64 KB 5 | セーブ機能の寿命: セクタあたり10,000回の書き込み 6 | 例: ソニックアドバンス 7 | 1Mb Flash ROM: 128 KB 8 | セーブ機能の寿命: セクタあたりの書き込み回数上限があるはずだが、具体的な回数は不明 9 | 例: ポケットモンスターエメラルド 10 | ``` 11 | 12 | ## チップの種類 13 | 14 | 任天堂は市販のゲームカートリッジに様々な種類のFLASHチップを搭載しています。エミュレータ開発者はすべてのチップタイプを検出し、サポートする必要があります。 15 | 16 | Atmel製チップの場合、ソフトウェアで4KBセクタをシミュレートすることが推奨されますが、任天堂は後期のゲームではAtmelチップを使用していないと言われています。 17 | 18 | ``` 19 | ID Name Size Sectors AverageTimings Timeouts/ms Waits(w,r) 20 | D4BFh SST 64K 16x4K 20us?,?,? 10, 40, 200 3,2 21 | 1CC2h Macronix 64K 16x4K ?,?,? 10,2000,2000 8,3 22 | 1B32h Panasonic 64K 16x4K ?,?,? 10, 500, 500 4,2 23 | 3D1Fh Atmel 64K 512x128 ?,?,? ...40.., 40 8,8 24 | 1362h Sanyo 128K ? ?,?,? ? ? ? ? 25 | 09C2h Macronix 128K ? ?,?,? ? ? ? ? 26 | ``` 27 | 28 | IDの MSBはデバイスの種類、LSBは製造元を表しています。 29 | 30 | FLASHチップの種類(および存在)を検出するためには後述のチップの検出コマンドを行います。 31 | 32 | ## アクセス 33 | 34 | FLASHメモリは,`0xE000000..E00FFFF`の SRAMエリアに配置されており、(`WAITCNT.0-1 = 3`の場合)アクセスには8サイクルを要します。 35 | 36 | 特定のデバイスタイプが検出された場合、書き込み・消去には、短い待機時間ですみ、生の読み取りにはさらに小さい待機時間で済むことがあります。 37 | 38 | データバスは8bitに制限されています。よって`LDRB/STRB`オペコードでしかアクセスできません。 39 | 40 | また、FLASHメモリからの読み出しは、WRAMで実行されたコードのみが行うことができます。(ROMで実行されたコードは不可。) 書き込みについては、そのような制限はありません。 41 | 42 | ## Verify 43 | 44 | 書き込み・消去の完了を知らせる信号が出ていても、変更されたメモリ領域の内容をソフトウェアで読み込んで確認(Verify)することが推奨されています。 45 | 46 | 実際には、任天堂のソフトウェアの場合は、書き込み・消去でエラーが発生した場合に最大3回まで動作を繰り返すのが一般的です。[1](#sst) 47 | 48 | 1: SST製チップのみ、消去コマンドを最大80回繰り返し、リトライが不要な場合はさらに1回、それ以外の場合はさらに6回消去コマンドを繰り返します。 49 | 50 | ## コマンド 51 | 52 | ### チップの検出 53 | 54 | ``` 55 | [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=90h (enter ID mode) 56 | dev=[E000001h], man=[E000000h] (get device & manufacturer) 57 | [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=F0h (terminate ID mode) 58 | ``` 59 | 60 | IDは `dev << 8 | man` で得られます。 61 | 62 | ### (複数バイト単位の)データの読み出し 63 | 64 | ``` 65 | dat=[E00xxxxh] (read byte from address xxxx) 66 | ``` 67 | 68 | ### データの消去 69 | 70 | ``` 71 | [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=80h (erase command) 72 | [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=10h (erase entire chip) 73 | wait until [E000000h]=FFh (or timeout) 74 | ``` 75 | 76 | チップ内の全メモリを消去し、消去されたメモリは`0xFF`で埋められます。 77 | 78 | ### 4KBセクタ単位のデータ消去 (Atmel以外) 79 | 80 | ``` 81 | [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=80h (erase command) 82 | [E005555h]=AAh, [E002AAAh]=55h, [E00n000h]=30h (erase sector n) 83 | wait until [E00n000h]=FFh (or timeout) 84 | ``` 85 | 86 | `E00n000h...E00nFFFh`のメモリを消去し、消去されたメモリは0xFFで埋められます。 87 | 88 | ### 128Bセクタ単位の消去と書き込み (Atmelのみ) 89 | 90 | ``` 91 | old=IME, IME=0 (disable interrupts) 92 | [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=A0h (erase/write sector command) 93 | [E00xxxxh+00h..7Fh]=dat[00h..7Fh] (write 128 bytes) 94 | IME=old (restore old IME state) 95 | wait until [E00xxxxh+7Fh]=dat[7Fh] (or timeout) 96 | ``` 97 | 98 | コマンドフェーズ・ライトフェーズでは、割り込み(およびDMA)を無効にする必要があります。ターゲットアドレスは、0x80の倍数でなければなりません。 99 | 100 | ### 1バイトの書き込み (Atmel以外) 101 | 102 | ``` 103 | [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=A0h (write byte command) 104 | [E00xxxxh]=dat (write byte to address xxxx) 105 | wait until [E00xxxxh]=dat (or timeout) 106 | ``` 107 | 108 | 対象となるメモリアドレスは、事前に消去されている必要があります。 109 | 110 | **Terminate Command after Timeout (only Macronix devices, ID=1CC2h)** 111 | 112 | ``` 113 | [E005555h]=F0h (force end of write/erase command) 114 | ``` 115 | 116 | Macronixチップのみ、"wait until"期間中にタイムアウトが発生した場合に使用します。 117 | 118 | ### バンクの切り替え (64KBより大きいチップのみ) 119 | 120 | ``` 121 | [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=B0h (select bank command) 122 | [E000000h]=bnk (write bank number 0..1) 123 | ``` 124 | 125 | 読み出し/書き込み/消去 操作の対象の64Kバンク番号を指定します。カートリッジのFLASH/SRAMのアドレスバスが16bit幅に制限されているため必要です。 126 | -------------------------------------------------------------------------------- /cartridge/backup/sram.md: -------------------------------------------------------------------------------- 1 | # 🔋 SRAM/FRAM 2 | 3 | > [!NOTE] 4 | > FRAM は `Ferroelectric RAM` の略で、FLASHとは別物です。 5 | 6 | ``` 7 | SRAM: 32KB 8 | セーブ機能の寿命: バッテリー依存 9 | 例: ロックマンゼロ2 10 | FRAM: 32KB 11 | セーブ機能の寿命: 10,000,000,000回の読み書き 12 | 例: まわるメイドインワリオ 13 | ``` 14 | 15 | SRAM(`Static RAM`)は電池によって通電し続けることでメモリの内容を保存し続けています。 16 | 17 | FRAM(`Ferroelectric RAM`)は新しめのカートリッジに搭載されていてデータを保持するための電池を必要としません。しかもソフトウェア側では、(EEPROM/FLASHと違って)SRAMと同じようにアクセスできます。 18 | 19 | ## アクセス 20 | 21 | SRAM/FRAM は `0xE000000..E007FFF` にマッピングされ、(`WAITCNT.0-1 = 3`の場合)アクセスには8サイクルを要します。バス幅は8bitで固定で、`LDRB/LDRSB/STRB`によってのみアクセス可能です。 22 | 23 | また、SRAM/FRAMからの読み出しは、WRAMで実行されたコードのみが行うことができます。(ROMで実行されたコードは不可。) 書き込みについては、そのような制限はありません。 24 | 25 | ## 保護機能 26 | 27 | SRAM/FRAMカートリッジには基本的にライトプロテクト機能が搭載されていません。 28 | 29 | そのため、GBAの電源を入れたままカートリッジを抜き差しすると、クラッシュしたプログラムによって不正にSRAM/FRAMに書き込みが行われてセーブデータが失われることがあるようです。 30 | 31 | ソフトウェアでは、以下のように設定することで対策することが推奨されます。 32 | 33 | ``` 34 | カートリッジを抜いた時にトリガーされる可能性が高いGamepak割り込みを有効にして、GamepakIRQ割り込みハンドラではGBAを無限ループでハングアップするようにします。 35 | 36 | 当たり前ですが、ROMカートリッジが取り外されたときに備えて、割り込みハンドラはROMではなく、WRAMに配置する必要があります。 37 | ハンドラはGamepakIRQを最優先で処理するようにします。割り込みが禁止されている期間はできるだけ短くし、必要に応じてネストした割り込みを許可してください。 38 | ``` 39 | 40 | 41 | -------------------------------------------------------------------------------- /cartridge/header.md: -------------------------------------------------------------------------------- 1 | # [カートリッジヘッダ](https://mgba-emu.github.io/gbatek/#gbacartridgeheader) 2 | 3 | ROMの先頭192バイト、つまり`0x800_0000..800_00BF`はカートリッジヘッダです。 4 | 5 | マルチブート時に、スレーブGBAではこのカートリッジヘッダの内容が`0x2000000..20000BF`にもロードされます。(マルチブート専用のカートリッジヘッダエントリも`0x20000C0`以降にロードされます) 6 | 7 | オフセット | サイズ(バイト) | 内容 8 | ---- | ---- | ---- 9 | 0x00 | 4 | ROMエントリポイント (32bitのARM分岐命令, 例: `B rom_start`) 10 | 0x04 | 156 | Nintendo Logo(圧縮されたbitmap) 11 | 0xA0 | 12 | ゲームタイトル (大文字ASCII) 12 | 0xAC | 4 | ゲームコード (大文字ASCII) 13 | 0xB0 | 2 | メーカーコード (大文字ASCII) 14 | 0xB2 | 1 | 0x96 15 | 0xB3 | 1 | 0x00 16 | 0xB4 | 1 | デバイスタイプ (基本的に0x00) 17 | 0xB5 | 7 | 予約領域(0) 18 | 0xBC | 1 | ソフトウェアバージョン (基本的に0x00) 19 | 0xBD | 1 | ヘッダのチェックサム 20 | 0xBE | 2 | 予約領域(0) 21 | 22 | **マルチブート時** 23 | 24 | オフセット | サイズ(バイト) | 内容 25 | ---- | ---- | ---- 26 | 0xC0 | 4 | RAMエントリポイント 27 | 0xC4 | 1 | ブートモード 28 | 0xC5 | 1 | SlaveID 29 | 0xC6 | 26 | 未使用 30 | 0xE0 | 4 | JOYBUSエントリーポイント 31 | 32 | エントリポイントではCPUはシステムモードで実行されます。 33 | 34 | ## 0x00 - エントリーポイント 35 | 36 | カートリッジの実際のスタートアドレスにリダイレクトする32bit ARMオペコード用の領域で、通常は `B ${start}`命令が入ります。 37 | 38 | 注意: このエントリはMultibootスレーブGBAでは無視されます(実際には、このエントリは上書きされ、以下で説明するように別のMultibootエントリポイントにリダイレクトされます)。 39 | 40 | ## 0x04-0x9f - 任天堂のロゴ 41 | 42 | 起動時に表示される任天堂のロゴを圧縮したデータが含まれています。このデータが欠損していたりするとカートリッジは動作しません。 43 | 44 | 圧縮データのコピーはBIOSに保存されており、GBAは2つのデータを比較し、BIOSのデータがカートリッジ(またはマルチブートヘッダ)と一致しない場合は動作を停止します。 45 | 46 | ## 0x9c - デバッグ有効フラグ(bit2, 7) 47 | 48 | これは、上記の[任天堂ロゴ](#0x04-0x9f---任天堂のロゴ)のメモリ領域の一部であり、一般的には`0x21`(`0b0010_0001`)に設定する必要がありますが、bit2とbit7には他の値を設定することができます。 49 | 50 | 両方のbitがセットされる(つまり`0xa5`)と、BIOSのFIQ/未定義命令ハンドラのロックが解除され、ハンドラはこれらの例外をカートリッジROMのユーザー定義ハンドラに転送します。 51 | 52 | このとき、エントリーポイントは`0x0800_00B4`(後述)に定義されています。 53 | 54 | その他のbitの組み合わせは、現在のところ特別な機能を持っていないようです。 55 | 56 | ## 0x9e - カートリッジのキーナンバーの上位2bit(bit0, 1) 57 | 58 | ここもまた、上記の[任天堂ロゴ](#0x04-0x9f---任天堂のロゴ)のメモリ領域の一部であり、一般的には`0xf8`(`0b1111_1000`)に設定する必要がありますが、bit0-1には他の値を設定することができます。 59 | 60 | 起動時に、BIOSはあらかじめ定義されたアドレスストリームからいくつかのダミーリードを行います。これらのリードは一見無意味に見えますが、市販のカートリッジ内部のリードプロテクトを解除するためのものである可能性があります。 61 | 62 | 16個の事前定義されたアドレスストリームは、4bitのキーナンバーによって選択され、上位2bitは`0x0800_009E`のbit0-1から得られ、下位2bitはヘッダーバイト`0x9D..0xB7`のチェックサムから得られます。(XORして40hで割ったもの) 63 | 64 | ## 0xa0 - ゲームタイトル 65 | 66 | ゲームタイトルがASCIIフォーマットで格納されています。 67 | 68 | 最大12文字、全て大文字で`00`が終端文字を表しています。 69 | 70 | ## 0xac - ゲームコード 71 | 72 | ゲームカセットの`AGB-UTTD`に対応するゲームコードが格納されています。 73 | 74 | - U: ユニークコード 75 | - TT: ショートタイトル 76 | - D: ROMの発売地域・言語 77 | 78 | 例: ロックマンエグゼ6 電脳獣ファルザー(JPN): AGB-BR6J 79 | 80 | **U: ユニークコード** 81 | 82 | ユニークコードは次のようになっています。 83 | 84 | ユニークコード(U) | 内容 85 | -- | -- 86 | A | 通常のゲーム (2001~2003) 87 | B | 通常のゲーム (2003~) 88 | C | 通常のゲーム (未使用) 89 | F | NESシリーズ 90 | K | 『ヨッシーの万有引力』 & 『コロコロパズル ハッピィパネッチュ!』 91 | P | e-リーダー 92 | R | 『まわるメイド イン ワリオ』 93 | U | 『ボクらの太陽』 & 『続・ボクらの太陽』 94 | V | 『スクリューブレイカー 轟振どりるれろ』 95 | 96 | **TT: ショートタイトル** 97 | 98 | ショートタイトル(TT)は、基本的には、文字通りタイトルを省略したものが入ります。例えば`Pac Man`のショートタイトルは`PM`です。 99 | 100 | 省略したものが別のゲームでTTとして既に使われているゲームには適当な2文字をTTにしている場合もあるようです。 101 | 102 | **D: ROMの発売地域・言語** 103 | 104 | D | 地域(言語) 105 | -- | -- 106 | J | 日本 107 | F | フランス 108 | S | スペイン 109 | E | アメリカ(英語) 110 | D | ドイツ 111 | I | イタリア 112 | P | ヨーロッパ,その他 113 | 114 | ## 0xb0-0xb1 - メーカーコード 115 | 116 | TODO 117 | 118 | Code | Maker 119 | -- | -- 120 | 121 | 122 | ## 0xbd - ヘッダのチェックサム 123 | 124 | ヘッダのチェックサムで、これが正しくない場合カートリッジは起動しません。 125 | 126 | 次のように計算します。 127 | 128 | ```go 129 | chk := byte(0) 130 | for i := 0xA0; i <= 0xBC; i++ { 131 | chk = chk - [i] 132 | chk = (chk - 0x19) & 0xff 133 | } 134 | ``` 135 | 136 | ## マルチブート時 137 | 138 | 以下は、マルチブートされるソフトウェアのみ必要です。 139 | 140 | マルチブートでは、上記192バイトをヘッダブロックとして`0x2000000..0x20000BF`に転送し、実際のプログラム/データブロックの先頭(`0x20000C0..`)にいくつかの追加ヘッダ情報を配置する必要があります。 141 | 142 | この拡張ヘッダは、正しく設定する必要のあるマルチブートエントリポイントと、ブート処理によって上書きされる2つの予約バイトで構成されています。 143 | 144 | ### 0xc0 - エントリポイント(ノーマル/マルチプレイモード用) 145 | 146 | この項目は、スレーブGBAがノーマルモードまたはマルチプレイモードで起動した場合のみ使用されます。 147 | 148 | ここには通常、ARM32bitの`B `命令が格納されており、実際のブート処理へとジャンプします。 149 | 150 | ### 0xc4 - ブートモード 151 | 152 | スレーブGBAのダウンロード処理では、この部分をマルチブート転送モードに対応した値で上書きします。 153 | 154 | ``` 155 | Value Expl. 156 | 01h Joybus mode 157 | 02h Normal mode 158 | 03h Multiplay mode 159 | ``` 160 | 161 | カートリッジでは、基本的にこのバイトは`DCB 00h`で`0x00`にしておきます。 162 | 163 | マルチブートで転送するプログラムには、この位置や以下のIDバイトの位置に重要なプログラムコードやデータが含まれていないことを確認してください。 164 | 165 | ### 0xc5 - スレーブID 166 | 167 | スレーブGBAがノーマルモードまたはマルチプレイモードで起動された場合、このバイトはそのスレーブGBAのスレーブIDで上書きされます(ノーマルモードでは常に`0x01`になります)。 168 | 169 | ``` 170 | Value Expl. 171 | 01h Slave #1 172 | 02h Slave #2 173 | 03h Slave #3 174 | ``` 175 | 176 | カートリッジでは、基本的にこのバイトは`DCB 00h`で`0x00`にしておきます。 177 | 178 | Joybusモードで起動した場合、この値は変更されず、マスターGBAから転送された値のままです。 179 | 180 | ### 0xc6..0xdf - 不使用 181 | 182 | 見たところ使われていません。 183 | 184 | ### 0xe0 - エントリポイント(Joybusモード用) 185 | 186 | GBAがJoybus転送モードを使ってブートされた場合、エントリポイントは`20000C0h`ではなくこのアドレスに位置します。 187 | 188 | ブート処理をこのアドレスに直接置くか、ここに`B `オペコードを格納して実際のブート処理にリダイレクトします。 189 | 190 | また、Joybusモードをサポートするつもりがない場合(おそらくほとんど使われないでしょう)は、このエントリを無視してください。 191 | -------------------------------------------------------------------------------- /cartridge/prefetch.md: -------------------------------------------------------------------------------- 1 | # カートリッジのプリフェッチ 2 | 3 | カートリッジのプリフェッチは`WAITCNT.14`で有効にすることができます。 4 | 5 | プリフェッチが有効になっている場合、GBAはCPUがバスを使用していない間、カートリッジROMからオペコードを読み出そうとします。 6 | 7 | CPUが既にバッファにプリフェッチされているデータを要求した場合、メモリアクセスの際のウェイトステートは`0`になり1サイクルでアクセスできます。 8 | 9 | プリフェッチバッファには、最大8つの16bit値が格納できます。 10 | 11 | > [!NOTE] 12 | > プリフェッチはカートリッジのオペコードに対してのみ有効です。RAMやBIOSに配置されたオペコードに対してはプリフェッチは行われません。 13 | 14 | ## 有効な場面 15 | 16 | プリフェッチは次のようなオペコードで発生します。 17 | 18 | ``` 19 | 1. 実行時にIサイクルが発生し、かつ R15を変更しない 命令 20 | shift/rotate register-by-register 21 | load opcodes (ldr,ldm,pop,swp) 22 | multiply opcodes 23 | 2. カートリッジ以外への ロードストア命令 24 | ldr,str,ldm,stm,etc. 25 | ``` 26 | 27 | ## プリフェッチ無効バグ 28 | 29 | プリフェッチが無効になっている場合、プリフェッチ無効バグが発生します。 30 | 31 | "カートリッジROM内の命令の内、内部サイクル(Iサイクル)が発生し、R15を変更しない命令"(上記の"1"の命令たち) のコードフェッチ時間が 1S から 1N になってしまいます。 32 | 33 | -------------------------------------------------------------------------------- /cartridge/rom.md: -------------------------------------------------------------------------------- 1 | # カートリッジROM 2 | 3 | ## ROM Size 4 | 5 | 基本的に8MBや16MBが主流です。 6 | 7 | FZeroとスーパーマリオアドバンスは4MBです。 8 | 9 | ## ROM Waitstates 10 | 11 | GBAは起動時にカートリッジのWaitStateを`N=4, S=2`に設定し[プリフェッチ](./prefetch.md)は無効にします。これらの設定は[WAITCNT](../system.md#0x0400_0204---waitcnt---waitstate制御レジスタ-rw)を介して変更可能です。 12 | 13 | 例えば、FZeroとスーパーマリオアドバンスはWaitStateを`N=3, S=1`にしプリフェッチを有効にしています。 14 | 15 | プリフェッチ機能を有効にしてWaitStateを短く設定すると、ROMから多くのデータとオペコードを高速に読み取ることができますが、消費電力が増加することに注意してください。 16 | 17 | ## ROMチップ 18 | 19 | 24bitのアドレスがカートリッジのバスを通過するため、カートリッジには、ファーストアクセス時に下位16bitのアドレスをラッチし、セカンドアクセス時にこれらのビットをインクリメントする回路が必要となります。 20 | 21 | 任天堂はこの回路をROMチップに直接組み込んでいるようです。 22 | 23 | また、カートリッジは16bit幅のデータバス、または2つの8bitのデータをwaitstateの間に1つの16bitデータに変換する回路のどちらかを持っていなければなりません。 24 | -------------------------------------------------------------------------------- /cheat/README.md: -------------------------------------------------------------------------------- 1 | # 改造コード 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
フォーマット対応機種
PAR 14 | 日本: プロアクションリプレイ
15 | 米: GameShark v1/v2
16 | ヨーロッパ: AR GBX v1/v2 17 |
ARv3 22 | 米: GameShark v3
23 | ヨーロッパ: AR GBX v3 24 |
CBX-TA, CodeBreaker
VBAVisualBoyAdvance
36 | 37 | ## 参考記事 38 | 39 | - [The Secrets of Professional GameShark(tm) Hacking](https://macrox.gshi.org/The%20Hacking%20Text.htm) 40 | - [GBAPAR解析部屋](https://web.archive.org/web/20070220093153/http://www5.airnet.ne.jp/kajapon/gbapar.html) 41 | -------------------------------------------------------------------------------- /cheat/arv3.md: -------------------------------------------------------------------------------- 1 | # ARv3 2 | 3 | TODO -------------------------------------------------------------------------------- /cheat/cb.md: -------------------------------------------------------------------------------- 1 | # CodeBreaker 2 | 3 | ## フォーマット 4 | 5 | 6 | 7 | 8 | 9 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 48 | 49 | 50 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 112 | 113 | 114 | 115 | 116 |
Master Code #1 10 |  
11 | xxxx is the CRC value (the "Game ID" converted to hex)
12 | address = ((d << 0x16) + 0x08000100)
13 |

14 | Flags ("yyyy"):
15 | 0008 - CRC Exists (CRC is used to autodetect the inserted game)
16 | 0002 - Disable Interupts 17 |  
  18 |
22 | 0000xxxx yyyy 23 | 1aaaaaaa 0007 24 |
単純書き込み(8bit) 30 |  
31 | RAMアドレスaaaaaaaに8bit値yyを連続的に書き込みつづけます。 32 |  
  33 |
3aaaaaaa 00yy
Slide Code 42 |  
43 | 2行で1つの改造コードです。 44 | アドレスaaaaaaaを始点として、16bit値yyyyxxxxxxxx回、書き込みます。
45 | 書き込みのたびにアドレスがiiiiだけインクリメントされます。
46 | この改造コードは、通常、特定の値でメモリを埋めるために使用されます。 47 |  
 
51 | 4aaaaaaa yyyy 52 | xxxxxxxx iiii 53 |
16-Bit Logical AND 59 |  
60 | Performs the AND function on the address provided with the value provided.
61 | I'm not going to explain what AND does, so if you'd like to know I suggest you see the instruction manual for a graphing calculator.
62 | This is another advanced code type you'll probably never need to use. 63 |  
 
6aaaaaaa yyyy
条件比較 72 |  
73 | アドレスaaaaaaaのデータと、16bit値yyyyに対して、条件(c)に合致する場合のみ次の行の改造コードを実行します。 74 |
75 | c: 7: =、A: ≠、B: >、C: <、 D: and (yyyyが右辺) 76 |  
  77 |
7aaaaaaa yyyy
単純書き込み(16bit) 86 |  
87 | RAMアドレスaaaaaaaに16bit値yyyyを連続的に書き込みつづけます。 88 |  
  89 |
8aaaaaaa yyyy
Change Encryption Seeds
(When 1st Code Only!)
 
Works like the DEADFACE on GSA. Changes the encryption seeds used for the rest of the codes.  
 
9yyyyyyy yyyy
キー入力判定書き込み 106 |  
107 | yyyyと16bitのキー入力値に対して条件(c)を満たすときに、次の行の改造コードを実行します。
108 | 16bitのキー入力値、KEYINPUTと同じbit配置ですがキーが押されているときに1になります。
109 | c: 1: ≠, 2: = 110 |  
 
D00000c0 yyyy
117 | -------------------------------------------------------------------------------- /cheat/vba.md: -------------------------------------------------------------------------------- 1 | # VisualBoyAdvance 2 | 3 | TODO 4 | -------------------------------------------------------------------------------- /communication/infrared.md: -------------------------------------------------------------------------------- 1 | # [赤外線通信](https://mgba-emu.github.io/gbatek/#infrared-communication-adapters) 2 | 3 | 初期のGBAのプロトタイプには、IR信号を送受信するためのIRポートが内蔵されていました。このポートを使って、他のGBAや旧CGBモデル、テレビのリモコンなどと通信することができたのです。 4 | 5 | しかし、任天堂は外付けの赤外線アダプタ(シリアル通信ポートに接続し、汎用モードでアクセスする)を提供することを検討しているようです。 6 | 7 | また、ゲームのカートリッジにIRポートを内蔵することも理論的には可能です(昔のハドソンのゲームにはありました)。 8 | 9 | よって、以降の内容は**プロトタイプ版での内容**になります。 10 | 11 | ## 4000136h - IR - Infrared Register (R/W) 12 | 13 | ``` 14 | Bit Expl. 15 | 0 Transmission Data (0=LED Off, 1=LED On) 16 | 1 READ Enable (0=Disable, 1=Enable) 17 | 2 Reception Data (0=None, 1=Signal received) (Read only) 18 | 3 AMP Operation (0=Off, 1=On) 19 | 4 IRQ Enable Flag (0=Disable, 1=Enable) 20 | 5-15 Not used 21 | ``` 22 | 23 | When IRQ is enabled, an interrupt is requested if the incoming signal was 0.119us Off (2 cycles), followed by 0.536us On (9 cycles) - minimum timing periods each. 24 | 25 | ## Transmission Notes 26 | 27 | When transmitting an IR signal, note that it'd be not a good idea to keep the LED turned On for a very long period (such like sending a 1 second synchronization pulse). The recipient's circuit would treat such a long signal as "normal IR pollution which is in the air" after a while, and thus ignore the signal. 28 | 29 | ## Reception Notes 30 | 31 | 32 | Received data is internally latched. Latched data may be read out by setting both READ and AMP bits. 33 | 34 | Note: Provided that you don't want to receive your own IR signal, be sure to set Bit 0 to zero before attempting to receive data. 35 | 36 | ## Power-consumption 37 | 38 | After using the IR port, be sure to reset the register to zero in order to reduce battery power consumption. -------------------------------------------------------------------------------- /communication/sio/README.md: -------------------------------------------------------------------------------- 1 | # [シリアル通信](https://mgba-emu.github.io/gbatek/#gbacommunicationports) 2 | 3 | > シリアルポートとは、情報を(パラレルポートとは異なり)1度に1ビットずつ送受信するシリアル通信物理インタフェースである。 4 | 5 | GBAのシリアルポートは、様々な通信モードを持っており、状況に応じて適した通信モードを使用することができます。 6 | 7 | 注:ニンテンドーDSにはシリアルポートは搭載されていません。 8 | 9 | ## 各モードについて 10 | 11 | - [通常モード](normal.md): 2台のGBA間でデータを交換することができます。または、マスターGBAから複数のスレーブGBAに一方通行でデータを転送することができます。 12 | - [マルチプレイモード](multiplayer.md): 最大4台のGBA間でデータをやり取りします。 13 | - [UARTモード](uart.md): UARTモードは、RS232インターフェースのように動作します。 14 | - [JOYバスモード](joybus.md): 任天堂の標準的なプロトコルであるJOYバスプロトコルを使用した転送です。 15 | - [汎用モード](general.md): シリアルポートを双方向の4ビットパラレルポートとして誤使用(?)して転送を行います。 16 | 17 | ## レジスタ 18 | 19 | 通信ポートの制御レジスタは、モードによって使い方が変わってきます。 20 | 21 | ここでは概要について説明します。 22 | 23 | ### 転送モード選択 24 | 25 | `RCNT.14-15`, `SIOCNT.12-13`を適切な値に設定することで、転送モードを選択できます 26 | 27 | モード | R.15 | R.14 | S.13 | S.12 28 | -- | -- | -- | -- | -- 29 | 通常 8bit | 0 | x | 0 | 0 30 | 通常 32bit | 0 | x | 0 | 1 31 | マルチプレイ | 0 | x | 1 | 0 32 | UART | 0 | x | 1 | 1 33 | 汎用 | 1 | 0 | x | x 34 | JOYバス | 1 | 1 | x | x 35 | 36 | ### SIOCNT 37 | 38 | ``` 39 | Bit 0 1 2 3 4 5 6 7 8 9 10 11 40 | Normal Master Rate SI/In SO/Out - - - Start - - - - 41 | Multi Baud Baud SI/In SD/In ID# Err Start - - - - 42 | UART Baud Baud CTS Parity S R Err Bits FIFO Parity Send Recv 43 | ``` 44 | -------------------------------------------------------------------------------- /communication/sio/general.md: -------------------------------------------------------------------------------- 1 | # [汎用モード](https://mgba-emu.github.io/gbatek/#siogeneralpurposemode) 2 | 3 | このモードでは,SIOは4ビットの双方向パラレルポートとして「誤使用」され,SI,SO,SC,SDの各端子が直接制御され,それぞれが入力信号(内部プルアップ付き)または出力信号として個別に宣言されます。 4 | 5 | ## レジスタ 6 | 7 | ### 4000134h - RCNT - モード選択レジスタ (R/W) 8 | 9 | `SIOCNT.12-13`と合わせて、転送モードを設定するのに利用します。 10 | 11 | 他のモードと違って、bit0-8, bit14-15が利用されます。 12 | 13 | ビット | 内容 14 | ---- | ---- 15 | 0 | SCデータビット (0=Low, 1=High) 16 | 1 | SDデータビット (0=Low, 1=High) 17 | 2 | SIデータビット (0=Low, 1=High) 18 | 3 | SOデータビット (0=Low, 1=High) 19 | 4 | SC入出力フラグ (0=Input, 1=Output) 20 | 5 | SD入出力フラグ (0=Input, 1=Output) 21 | 6 | SI入出力フラグ (0=Input, 1=Output) 22 | 7 | SO入出力フラグ (0=Input, 1=Output) 23 | 8 | SI割り込み有効化フラグ (0=無効, 1=有効) 24 | 9-13 | 不使用 (常に0,読み取り専用) 25 | 14 | 0 26 | 15 | 1 27 | 28 | SI should be always used as Input to avoid problems with other hardware which does not expect data to be output there. 29 | 30 | ### 4000128h - SIOCNT - SIO制御レジスタ 31 | 32 | 汎用モードではこのレジスタは使われません。 33 | 34 | That is, the separate bits of SIOCNT still exist and are read- and/or write-able in the same manner as for Normal, Multiplay, or UART mode (depending on SIOCNT Bit 12,13), but are having no effect on data being output to the link port. 35 | 36 | -------------------------------------------------------------------------------- /communication/sio/joybus.md: -------------------------------------------------------------------------------- 1 | # [JOYバスモード](https://mgba-emu.github.io/gbatek/#siojoybusmode) 2 | 3 | 4 | 5 | この通信モードは、任天堂の標準化されたプロトコルであるJOYバスプロトコルを使った通信モードです。 6 | 7 | JOYバスプロトコルについての詳細は[こちら](https://n64brew.dev/wiki/Joybus_Protocol)を参照してください。 8 | 9 | この通信モードでは、GBAは常にスレーブとして動作します。 10 | 11 | In this mode, SI and SO pins are data lines (apparently synchronized by Start/Stop bits?). 12 | 13 | SC and SD are set to low (including during active transfer?) 14 | 15 | The transfer rate is unknown? 16 | 17 | ## レジスタ 18 | 19 | ### 4000134h - RCNT (R) - モード選択レジスタ 20 | 21 | `SIOCNT.12-13`と合わせて、転送モードを設定するのに利用します。 22 | 23 | 使われているのはbit14-15だけです。 24 | 25 | ビット | 内容 26 | ---- | ---- 27 | 0-3 | 未定義 (current SC,SD,SI,SO state, as for General Purpose mode) 28 | 4-8 | 不使用 (常に0が望ましいが1を書き込むこともできる) 29 | 9-13 | 不使用 (常に0,読み取り専用) 30 | 14 | 1 31 | 15 | 1 32 | 33 | ### 4000128h - SIOCNT - SIO制御レジスタ 34 | 35 | JOYバスモードではこのレジスタは使われません。 36 | 37 | ### 4000140h - JOYCNT - JOYバス制御レジスタ (R/W) 38 | 39 | ビット | 内容 40 | ---- | ---- 41 | 0 | Device Reset Flag (Command FFh) (Read/Acknowledge) 42 | 1 | Receive Complete Flag (Command 14h or 15h?) (Read/Acknowledge) 43 | 2 | Send Complete Flag (Command 15h or 14h?) (Read/Acknowledge) 44 | 3-5 | 不使用 45 | 6 | IRQ when receiving a Device Reset Command (0=Disable, 1=Enable) 46 | 7-31 | 不使用 47 | 48 | Bit 0-2 are working much like the bits in the IF register: Write a "1" bit to reset (acknowledge) the respective bit. 49 | 50 | ### 4000150h - JOY_RECV_L - Receive Data Register low (R/W) 51 | ### 4000152h - JOY_RECV_H - Receive Data Register high (R/W) 52 | 53 | 受信したデータがここに入ります。 54 | 55 | ### 4000154h - JOY_TRANS_L - Send Data Register low (R/W) 56 | ### 4000156h - JOY_TRANS_H - Send Data Register high (R/W) 57 | 58 | 送信するデータをここに格納します。 59 | 60 | ### 4000158h - JOYSTAT - Receive Status Register (R/W) 61 | 62 | ビット | 内容 63 | ---- | ---- 64 | 0 | 不使用 65 | 1 | 受信ステータスフラグ (0=Remote GBA is/was receiving) (Read Only?) 66 | 2 | 不使用 67 | 3 | 送信ステータスフラグ (1=Remote GBA is/was sending) (Read Only?) 68 | 4-5 | General Purpose Flag (Not assigned, may be used for whatever purpose) 69 | 6-31 | 不使用 70 | 71 | JOY_TRANSに書き込みを行うとbit1は自動的にセットされます。 72 | 73 | JOY_RECVから読み取りを行うとbit3は自動的にクリアされます。 74 | 75 | ## コマンド 76 | 77 | 以下は、GBAが受け取ることのできる4つのコマンドです。 78 | 79 | なお、GBA(スレーブ)は自らコマンドを送信することはできず、できるのは受信データを読み取ることと、マスターユニットが読み取ることができる(またはできない)「返信」データを返すことだけです。 80 | 81 | ### Command FFh - Device Reset 82 | 83 | ``` 84 | Receive FFh (Command) 85 | Send 00h (GBA Type number LSB (or MSB?)) 86 | Send 04h (GBA Type number MSB (or LSB?)) 87 | Send XXh (lower 8bits of SIOSTAT register) 88 | ``` 89 | 90 | ### Command 00h - Type/Status Data Request 91 | 92 | ``` 93 | Receive 00h (Command) 94 | Send 00h (GBA Type number LSB (or MSB?)) 95 | Send 04h (GBA Type number MSB (or LSB?)) 96 | Send XXh (lower 8bits of SIOSTAT register) 97 | ``` 98 | 99 | ### Command 15h - GBA Data Write (to GBA) 100 | 101 | ``` 102 | Receive 15h (Command) 103 | Receive XXh (Lower 8bits of JOY_RECV_L) 104 | Receive XXh (Upper 8bits of JOY_RECV_L) 105 | Receive XXh (Lower 8bits of JOY_RECV_H) 106 | Receive XXh (Upper 8bits of JOY_RECV_H) 107 | Send XXh (lower 8bits of SIOSTAT register) 108 | ``` 109 | 110 | ### Command 14h - GBA Data Read (from GBA) 111 | 112 | ``` 113 | Receive 14h (Command) 114 | Send XXh (Lower 8bits of JOY_TRANS_L) 115 | Send XXh (Upper 8bits of JOY_TRANS_L) 116 | Send XXh (Lower 8bits of JOY_TRANS_H) 117 | Send XXh (Upper 8bits of JOY_TRANS_H) 118 | Send XXh (lower 8bits of SIOSTAT register) 119 | ``` 120 | 121 | -------------------------------------------------------------------------------- /communication/sio/multiplayer.md: -------------------------------------------------------------------------------- 1 | # [マルチプレイモード](https://mgba-emu.github.io/gbatek/#siomultiplayermode) 2 | 3 | マルチプレイモードでは4ユニット間の通信が可能になっています。 4 | 5 | multiplay 6 | 7 | ## レジスタ 8 | 9 | ### 4000134h - RCNT (R) - モード選択レジスタ 10 | 11 | `SIOCNT.12-13`と合わせて、転送モードを設定するのに利用します。 12 | 13 | 使われているのはbit15だけです。 14 | 15 | ビット | 内容 16 | ---- | ---- 17 | 0-3 | 未定義 (current SC,SD,SI,SO state, as for General Purpose mode) 18 | 4-8 | 不使用 (常に0が望ましいが1を書き込むこともできる) 19 | 9-13 | 不使用 (常に0,読み取り専用) 20 | 14 | 不使用 (常に0が望ましいが1を書き込むこともできる) 21 | 15 | 0 (モードをノーマル/マルチプレイ/UARTにしたい場合) 22 | 23 | ``` 24 | Note: 未定義の仕様ですが、任天堂製のゲームではbit0をマルチプレイモードでSCの現在の状態を表すのに使っているようです。 25 | ``` 26 | 27 | ### 4000128h - SIOCNT - SIO制御レジスタ (R/W) 28 | 29 | ビット | 内容 30 | ---- | ---- 31 | 0-1 | ボーレート (0-3: 9600,38400,57600,115200 bps) 32 | 2 | SI-Terminal (0=Parent, 1=Child) (Read Only) 33 | 3 | SD-Terminal (0=Bad connection, 1=All GBAs Ready) (Read Only) 34 | 4-5 | マルチプレイID (0=マスター, 1-3=1~3番目のスレーブ) (Read Only) 35 | 6 | エラーフラグ (0=正常, 1=エラー) (Read Only) 36 | 7 | Start/Busy Bit (0=Inactive, 1=Start/Busy) (スレーブ側のみ Read Only) 37 | 8-11 | 不使用 (読み書き可能、0にしたままにすることを推奨) 38 | 12 | 0 (マルチプレイモードにするため必須) 39 | 13 | 1 (マルチプレイモードにするため必須) 40 | 14 | IRQ有効化フラグ (0=無効, 1=完了時に転送リクエスト) 41 | 15 | 不使用 (読み取り専用で常に0) 42 | 43 | 最初の転送が完了するまで、マルチプレイIDビットの値は未定義です。 44 | 45 | ### 400012Ah - SIOMLT_SEND - Data Send Register (R/W) 46 | 47 | 他のGBAに送信したい16bitの送信データを入れます。 48 | 49 | ### 4000120h - SIOMULTI0 - SIO Multi-Player Data 0 (Parent) (R/W) 50 | ### 4000122h - SIOMULTI1 - SIO Multi-Player Data 1 (1st child) (R/W) 51 | ### 4000124h - SIOMULTI2 - SIO Multi-Player Data 2 (2nd child) (R/W) 52 | ### 4000126h - SIOMULTI3 - SIO Multi-Player Data 3 (3rd child) (R/W) 53 | 54 | これらのレジスタは、転送開始時に自動的に`0xFFFF`にリセットされます。 55 | 56 | 転送後、これらのレジスタには、すべてのリモートGBAからの16bitの受信データ(接続されていないGBAがあった場合は0xFFFF)と、ローカルの送信データである`SIOMLT_SEND`データが含まれます。つまり、転送後、接続されているすべてのGBAの`SIOMULTI0-3`レジスタには同じ値が入ります。 57 | 58 | 例: 59 | 60 | GBA | マルチプレイID | SIOMLT_SEND | SIOMULTI0 | SIOMULTI1 | SIOMULTI2 | SIOMULTI3 61 | -- | -- | -- | -- | -- | -- | -- 62 | 1台目 | 3 | 0xff45 | 0xff10 | 0xffa2 | 0xffd5 | 0xff45 63 | 2台目 | 1 | 0xffa2 | 0xff10 | 0xffa2 | 0xffd5 | 0xff45 64 | 3台目 | 0 | 0xff10 | 0xff10 | 0xffa2 | 0xffd5 | 0xff45 65 | 4台目 | 2 | 0xffd5 | 0xff10 | 0xffa2 | 0xffd5 | 0xff45 66 | 67 | ## 初期化処理 68 | 69 | 1. RCNTのbit14-15とSIOCNTのbit12-13を設定してマルチプレイモードにする 70 | 2. SIOCNTのbit3を見て全部のGBAがマルチプレイモードになっていることを確認する 71 | 3. SIOCNTのbit2を見てどのGBAがマスターになっているかを確認する 72 | 73 | ## 推奨される転送手順 74 | 75 | 1. 転送したいデータを`SIODATA_SEND`に書き込む 76 | 2. マスター側がスタートビットをセットする 77 | 3. 全ユニットは転送完了後、`SIOMULTI0-3`で受信したデータを処理する 78 | 4. 最初の転送が成功した後、`SIOCNT`のマルチプレイIDビットが有効となる 79 | 5. 送りたいデータがまだ存在する場合はこの手順を1から繰り返す 80 | 81 | マスターユニットは、スレーブユニットがすでに古いデータを処理しているか、新しいデータを供給しているかに関係なくデータを送信します。そのため、マスターユニットは各転送の間に遅延処理を行なったり、エラーチェックを行う必要があるかもしれません。 82 | 83 | また、スレーブユニットは一時的に他の通信モードに移行することで、マスターユニットに準備不足を知らせることができます(マルチプレイモードのように非アクティブ時にSDに1をセットすることはありません)。 84 | 85 | ## 転送プロトコル 86 | 87 | スレーブN = マルチプレイIDがNのスレーブユニット 88 | 89 | ``` 90 | 転送前 91 | - マスター側のSIを常に0になるようにする 92 | - 全GBAがマルチプレイモードでSDが1であることを確認する 93 | - マスター側が転送を開始すると、SC=LOW となり、スレーブ側のBusyビットがセットされる 94 | Step A 95 | - マスターユニットのIDビットが0にセットされる 96 | - マスターユニットはStartビット(0)、16bitデータ、Stopビット(1)をSDを通して送信する 97 | - このデータは、すべてのGBAの SIOMULTI0 に書き込まれる(マスター含む) 98 | - マスターは、SOからスレーブ1のSIにSO(0)を転送する 99 | - 次のスレーブが一定時間経過してもデータを出力しない場合、転送を終了する。 100 | Step B 101 | - スレーブ1のIDビットが1にセットされる 102 | - スレーブ1はStartビット(0)、16bitデータ、Stopビット(1)をSDを通して送信する 103 | - このデータは、すべてのGBAの SIOMULTI1 に書き込まれる(スレーブ1含む) 104 | - スレーブ1は、SOからスレーブ2のSIにSO(0)を転送する 105 | - 次のスレーブが一定時間経過してもデータを出力しない場合、転送を終了する。 106 | Step C 107 | - スレーブ2のIDビットが2にセットされる 108 | - スレーブ2はStartビット(0)、16bitデータ、Stopビット(1)をSDを通して送信する 109 | - このデータは、すべてのGBAの SIOMULTI2 に書き込まれる(スレーブ2含む) 110 | - スレーブ2は、SOからスレーブ3のSIにSO(0)を転送する 111 | - 次のスレーブが一定時間経過してもデータを出力しない場合、転送を終了する。 112 | Step D 113 | - スレーブ3のIDビットが3にセットされる 114 | - スレーブ3はStartビット(0)、16bitデータ、Stopビット(1)をSDを通して送信する 115 | - このデータは、すべてのGBAの SIOMULTI3 に書き込まれる(スレーブ2含む) 116 | - 転送終了 117 | 転送終了後 118 | - マスターはSCを1にセット、全ユニットはSOを1にセット 119 | - 全てのGBAのStart/Busyビットは自動的にクリアされる 120 | - 全てのGBAで割り込みが要求される(IRQビットが有効な場合) 121 | ``` 122 | 123 | ## エラーフラグ 124 | 125 | `SC=LOW`で転送を通知しても、スレーブが`SI=LOW`を受信しなかった場合に、このビットがセットされます。(4台以上のGBAを接続した場合や、前のスレーブ側が接続されていない場合に発生することがあります。)また、StopbitがHIGHでなかった場合にもこのビットはセットされます。 126 | 127 | 転送がアクティブなときはエラービットが不定になる場合があるので、エラービットからの読み取りは転送完了後にすべきです。プログラマがこのビットに対して書き込むことはできません。一部または全部のGBAでエラーが発生した場合でも、通常通り転送を継続し、完了します。 128 | 129 | ビットは転送ごとに自動的にリセット/初期化されるのか、それとも手動でリセットする必要があるのかは不明です。 130 | 131 | ## 転送時間 132 | 133 | 転送時間は、選択されたボーレートによって異なります。 134 | 135 | また、接続されたGBAの数に依存します。GBAの数が増えると、転送するBit量(各GBAの16bitデータとスタート/ストップビット)、各GBAのデータ間の遅延、および最終タイムアウト(4GBA未満の場合)が変化するからです。 136 | 137 | GBAの数 | 転送Bit量 | 遅延 | 最終タイムアウト 138 | -- | -- | -- | -- 139 | 1 | 18 | None | Yes 140 | 2 | 36 | 1 | Yes 141 | 3 | 54 | 2 | Yes 142 | 4 | 72 | 3 | None 143 | 144 | 上記は、各転送の開始と処理に費やされなければならない追加のCPU時間をカウントしていません。 145 | 146 | ## 高速な単方向転送 147 | 148 | マルチプレイケーブルは、マルチプレイモード以外に、マスターユニットからすべてのスレーブユニットへの高速な一方通行のデータ転送を行うノーマルモードでも使用できます。 149 | 150 | 詳細は[ノーマルモード](normal.md)をみてください。 151 | -------------------------------------------------------------------------------- /communication/sio/normal.md: -------------------------------------------------------------------------------- 1 | # [通常モード](https://mgba-emu.github.io/gbatek/#sionormalmode) 2 | 3 | このモードは、2台のユニット間の通信に使用します。 4 | 5 | 転送速度は、256Kbps と 2Mbps が選択できますが、高速の2Mbpsは、GBAのリンクポートに直接接続される、つまりGBAと拡張ハードウェアの間にケーブルを介さないような特殊な拡張ハードウェアにのみ使用されます。 6 | 7 | 通常の場合は、安定した結果が得られる256Kbpsの転送速度を使用してください。 8 | 9 | 転送サイズは8bitと32bitがあり、8bitモードはDMG/CGBゲームボーイと同じですが、「GBAのカートリッジをGBAに装着した場合」と「DMG/CGBのカートリッジをDMG/CGB/GBAに装着した場合」では電圧が異なり、DMG/CGBのゲームとGBAのゲームは通信できません。 10 | 11 | ## レジスタ 12 | 13 | ### 4000134h - RCNT (R) - モード選択レジスタ 14 | 15 | `SIOCNT.12-13`と合わせて、転送モードを設定するのに利用します。 16 | 17 | 使われているのはbit15だけです。 18 | 19 | ビット | 内容 20 | ---- | ---- 21 | 0-3 | 未定義 (current SC,SD,SI,SO state, as for General Purpose mode) 22 | 4-8 | 不使用 (常に0が望ましいが1を書き込むこともできる) 23 | 9-13 | 不使用 (常に0,読み取り専用) 24 | 14 | 不使用 (常に0が望ましいが1を書き込むこともできる) 25 | 15 | 0 (モードをノーマル/マルチプレイ/UARTにしたい場合) 26 | 27 | ### 4000128h - SIOCNT - SIO制御レジスタ (R/W) 28 | 29 | ビット | 内容 30 | ---- | ---- 31 | 0 | シフトクロック (0=外部クロック, 1=内部クロック) 32 | 1 | 内部シフトクロックの転送レート (0=256KHz, 1=2MHz) 33 | 2 | SI (Serial Input) (0=Low, 1=High/None) --- (Read Only) 34 | 3 | SO during inactivity (0=Low, 1=High) (applied ONLY when Bit7=0) 35 | 4-6 | 不使用 (常に0,読み取り専用) 36 | 7 | スタートビット (0=Inactive/Ready, 1=Start/Active) 37 | 8-11 | 不使用 (常に0が望ましいが1を書き込むこともできる) 38 | 12 | 転送サイズ (0=8bit, 1=32bit) 39 | 13 | 0 (通常モードでは必ず0) 40 | 14 | IRQビット(0=無効, 1=転送完了時にIRQをリクエスト) 41 | 15 | 不使用 (常に0,読み取り専用) 42 | 43 | スタートビット(bit7)は、転送が完了すると自動的にリセットされます。 44 | 45 | IRQビット(bit14)がセットされている場合、8bitまたは32bitすべての転送が完了すると、その時点でIRQが生成されます。 46 | 47 | ### 400012Ah - SIODATA8 - 通信データレジスタ8 (R/W) 48 | 49 | 転送サイズが8bitで、転送モードが通常モードのときのためのレジスタです。 50 | 51 | 8bitのデータが格納されています。(下位8bitのみ使用) 52 | 53 | 送信データは、転送を開始する前にこのレジスタに書き込む必要があります。 54 | 55 | 転送中、MSBからシフトアウトされたビットが送信され、同時にこのレジスタに受信したビットがシフトインされます。 56 | 57 | 転送が完了すると,このレジスタには受信した8bitの値が格納されます。 58 | 59 | ``` 60 | o7 o6 o5 o4 o3 o2 o1 o0 61 | o6 o5 o4 o3 o2 o1 o0 i7 62 | o5 o4 o3 o2 o1 o0 i7 i6 63 | o4 o3 o2 o1 o0 i7 i6 i5 64 | o3 o2 o1 o0 i7 i6 i5 i4 65 | o2 o1 o0 i7 i6 i5 i4 i3 66 | o1 o0 i7 i6 i5 i4 i3 i2 67 | o0 i7 i6 i5 i4 i3 i2 i1 68 | i7 i6 i5 i4 i3 i2 i1 i0 69 | ``` 70 | 71 | ### 4000120h - SIODATA32_L - 通信データレジスタ32の下位16bit (R/W) 72 | ### 4000122h - SIODATA32_H - 通信データレジスタ32の上位16bit (R/W) 73 | 74 | 内容は大きさが32bitレジスタになった以外、SIODATA8と同じです。転送サイズが32bit用のときに使われます。 75 | 76 | SIODATA32に書き込み始める前に、**必ず**SIOCNTとRCNTを32bitの通常転送モードに設定する必要があります。 77 | 78 | ## 初期化処理 79 | 80 | 1. まず、RCNTレジスタを初期化します。 81 | 82 | 2. 次に、スタートビット(SIOCNT.7)をクリアした状態で、SIOCNTのモード/クロックビットを設定します。 83 | 84 | ``` 85 | マスターの場合:内部クロック(SIOCNT.0=1)を選択し、転送レート(SIOCNT.1)として256KHzを指定します。 86 | スレーブの場合:外部クロック(SIOCNT.0=0)を選択します。ローカルの転送レート(SIOCNT.1)の選択結果は無視され、転送レートはリモートのGBA(またはカスタム転送レートを供給する他のコンピュータ)から供給されます。 87 | ``` 88 | 89 | 3. 最後に、モード/クロックビットを変更せずに、SIOCNTのスタートビットをセットします。 90 | 91 | ## スレーブ側(外部クロック側)が通信を行う際におすすめの手順 92 | 93 | 1. マスター側に送る予定のデータを初期化 94 | 2. スタートビットとSOをクリア 95 | 2. スタートビットとSOをセット 96 | 3. SOをクリアしてマスター側に転送準備ができたことを知らせる 97 | 4. IRQが起きる、またはスタートビットが0になるのを待つ 98 | 5. 受信したデータを処理する 99 | 6. 送りたいデータがまだ存在する場合はこの手順を1から繰り返す 100 | 101 | ## マスター側(内部クロック側)が通信を行う際におすすめの手順 102 | 103 | 1. スレーブ側に送る予定のデータを初期化 104 | 2. SI(SIOCNTのbit2)が0になる、つまりスレーブ側の準備が整うのを待つ(タイムアウトを設けることを推奨) 105 | 3. スタートビットをセット 106 | 4. IRQが起きる、またはスタートビットが0になるのを待つ 107 | 5. 受信したデータを処理する 108 | 6. 送りたいデータがまだ存在する場合はこの手順を1から繰り返す 109 | 110 | ## 通信ケーブルの転送プロトコル 111 | 112 | 転送がアクティブで無い場合には、シフトクロック(SC)はHighになります。送信(SO)と受信(SI)のデータ線は、上述のように手動で制御することができます。 113 | 114 | マスターが`SC=LOW`を送ると、マスターとスレーブはそれぞれ次に送り出すデータビットをSOに出力しなければなりません。 115 | 116 | マスターが`SC=HIGH`を送ると、各マスターとスレーブはSIから相手のデータビットを読み出す必要があります。これを8ビットまたは32ビットごとに繰り返し、完了するとSCは再びHighになります。 117 | 118 | ## 転送速度 119 | 120 | SCは転送速度として、256KHz または 2MHz のどちらかを選択でき、1秒間に最大で32KB(256Kbit)または128KB(2Mbit)のデータを転送できます。ただし、8bitまたは32bitの転送データをソフトウェアで個別に処理する必要があるため、実際の転送速度はデータ単位の処理にかかる時間分だけ低下します。 121 | 122 | GBA同士の通信など、ほとんどの場合は256KHzでないと安定した結果が得られません。2MHzは、特殊な拡張ハードウェア(配線が非常に短いもの)のみを想定しています。 123 | 124 | ## マルチプレイケーブルを用いたノーマルモードでの単方向転送 125 | 126 | マルチプレイケーブルでノーマルモードを使用する場合、通常のように最初のGBAと2番目のGBAの間でデータが交換されません。 127 | 128 | その代わりに、リレーのようにGBA間をデータが移動していきます。 129 | 130 | The first GBA receives zero, because master SI is shortcut to GND 131 | 132 | この挙動は、マスターGBAから他のすべてのGBAへの一方向の高速データ転送に使用できます。例えばGBAが3つ繋がっている場合は次のようにデータが転送されます。 133 | 134 | ``` 135 | Step Sender 1st Recipient 2nd Recipient 136 | Transfer 1: DATA #0 --> UNDEF --> UNDEF --> 137 | Transfer 2: DATA #1 --> DATA #0 --> UNDEF --> 138 | Transfer 3: DATA #2 --> DATA #1 --> DATA #0 --> 139 | Transfer 4: DATA #3 --> DATA #2 --> DATA #1 --> 140 | ``` 141 | 142 | 受信者は自分のデータを送信しようとしてはいけません。次の転送時に前に受信したデータを次の受信者に転送してください。受信したデータをデータレジスタに変更せずに残しておくだけです 143 | 144 | 遅延転送のため、2番目の受信者は最初の受信データ(上の例では`Transfer 1のUNDEF`)を無視する必要があります。 145 | 146 | 最後の転送の後、送信者は1つ(または複数)のダミーデータユニットを送信し、最後のデータ(上の例では`Transfer 3のDATA #3`)が2番目(またはそれ以降)の受信者に転送されるようにしなければなりません。 147 | -------------------------------------------------------------------------------- /communication/sio/uart.md: -------------------------------------------------------------------------------- 1 | # [UARTモード](https://mgba-emu.github.io/gbatek/#siouartmode) 2 | 3 | ``` 4 | Note: 筆者(Akatsuki)がハードウェアに詳しくないため、間違った記述があるかもしれません。 5 | ``` 6 | 7 | UART = Universal Asynchronous Receiver/Transmitter(汎用非同期送受信機) 8 | 9 | このモードでは、RS232シリアルポートのような挙動をします。ただし電圧は明確になっていません。+/-12Vより0/3Vだろうと言われています。 10 | 11 | SIとSOはクロスケーブルなデータ回線です。 12 | 13 | SC and SD signalize Clear to Send (with crossed wires also, which requires special cable when linking between two GBAs ?) 14 | 15 | ## レジスタ 16 | 17 | ### 4000134h - RCNT (R) - モード選択レジスタ 18 | 19 | `SIOCNT.12-13`と合わせて、転送モードを設定するのに利用します。 20 | 21 | 使われているのはbit15だけです。 22 | 23 | ビット | 内容 24 | ---- | ---- 25 | 0-3 | 未定義 (current SC,SD,SI,SO state, as for General Purpose mode) 26 | 4-8 | 不使用 (常に0が望ましいが1を書き込むこともできる) 27 | 9-13 | 不使用 (常に0,読み取り専用) 28 | 14 | 不使用 (常に0が望ましいが1を書き込むこともできる) 29 | 15 | 0 (モードをノーマル/マルチプレイ/UARTにしたい場合) 30 | 31 | ### 4000128h - SCCNT_L - SIO制御レジスタ (R/W) 32 | 33 | ビット | 内容 34 | ---- | ---- 35 | 0-1 | Baud Rate (0-3: 9600,38400,57600,115200 bps) 36 | 2 | CTS Flag (0=Send always/blindly, 1=Send only when SC=LOW) 37 | 3 | Parity Control (0=Even, 1=Odd) 38 | 4 | Send Data Flag (0=Not Full, 1=Full) (Read Only) 39 | 5 | Receive Data Flag (0=Not Empty, 1=Empty) (Read Only) 40 | 6 | Error Flag (0=No Error, 1=Error) (Read Only) 41 | 7 | Data Length (0=7bits, 1=8bits) 42 | 8 | FIFO Enable Flag (0=Disable, 1=Enable) 43 | 9 | Parity Enable Flag (0=Disable, 1=Enable) 44 | 10 | Send Enable Flag (0=Disable, 1=Enable) 45 | 11 | Receive Enable Flag (0=Disable, 1=Enable) 46 | 12 | Must be "1" for UART mode 47 | 13 | Must be "1" for UART mode 48 | 14 | IRQ Enable (0=Disable, 1=IRQ when any Bit 4/5/6 become set) 49 | 15 | Not used (Read only, always 0) 50 | 51 | ### 400012Ah - SIODATA8 - usage in UART Mode (R/W) 52 | 53 | Addresses the send/receive shift register, or (when FIFO is used) the send/receive FIFO. 54 | 55 | In either case only the lower 8bit of SIODATA8 are used, the upper 8bit are not used. 56 | 57 | The send/receive FIFO may store up to four 8bit data units each. 58 | 59 | For example, while 1 unit is still transferred from the send shift register, it is possible to deposit another 4 units in the send FIFO, which are then automatically moved to the send shift register one after each other. 60 | 61 | ## Send/Receive Enable, CTS Feedback 62 | 63 | The receiver outputs SD=LOW (which is input as SC=LOW at the remote side) when it is ready to receive data (that is, when Receive Enable is set, and the Receive shift register (or receive FIFO) isn't full. 64 | 65 | When CTS flag is set to always/blindly, then the sender transmits data immediately when Send Enable is set, otherwise data is transmitted only when Send Enable is set and SC is LOW. 66 | 67 | ## Error Flag 68 | 69 | The error flag is set when a bad stop bit has been received (stop bit must be 0), when a parity error has occurred (if enabled), or when new data has been completely received while the receive data register (or receive FIFO) is already full. 70 | 71 | The error flag is automatically reset when reading from SIOCNT register. 72 | 73 | ## Init & Initback 74 | 75 | The content of the FIFO is reset when FIFO is disabled in UART mode, thus, when entering UART mode initially set FIFO=disabled. 76 | 77 | The Send/Receive enable bits must be reset before switching from UART mode into another SIO mode! 78 | -------------------------------------------------------------------------------- /dma.md: -------------------------------------------------------------------------------- 1 | # DMA転送 2 | 3 | ダイレクトメモリアクセス(DMA)は、CPUを介さずにデータを高速に転送する方法です。データのコピー(転送)だけでなく、メモリ埋め(Fill)にも使用できます。 4 | 5 | DMAを有効にすると、転送時にはCPUが一時停止して、DMAコントローラが必要な転送を行い、転送が終わるとCPUが動作を再開します。 6 | 7 | GBAには4つのDMAチャンネルがあり、優先度は `DMA0 > DMA1 > DMA2 > DMA3` となっています。優先度の低いDMAチャンネルは、優先度の高いチャンネルがアクティブな時は一時停止します。 8 | 9 | DMA転送がアクティブなときはCPUは一時停止しますが、`Sound/Blanking DMA転送`が一時停止している間はCPUは動作しています。 10 | 11 | ## それぞれのチャンネルの個性 12 | 13 | ``` 14 | DMA0: (優先度が最も高いため) HBlank期間内のデータ転送(HBlank DMA)など、時間にシビアな転送をしたいときに向いている 15 | DMA1, 2: サウンド再生時のFIFOにデータを転送するとき。内部メモリ・外部メモリから内部メモリへの転送が可能。 16 | DMA3: (後述のDADの指定可能範囲が広いため)唯一、Game Pak ROM/FlashROMに書き込みをするができる(SRAMは除く) 17 | ``` 18 | 19 | 加えて、全部のDMAチャンネルは**汎用的なデータ転送用途**にも使うことができます。(DMA3がよく使われる印象です) 20 | 21 | ## DMAnSAD - ソースレジスタ (W) 22 | 23 | DMA転送で転送するデータが始まるアドレスを指定します。 24 | 25 | ``` 26 | 0x0400_00B0: DMA0SAD - DMA0ソースレジスタ (内部メモリのみ) 27 | 0x0400_00BC: DMA1SAD - DMA1ソースレジスタ 28 | 0x0400_00C8: DMA2SAD - DMA2ソースレジスタ 29 | 0x0400_00D4: DMA3SAD - DMA3ソースレジスタ 30 | ``` 31 | 32 | DMA0の場合は`0x07FF_FFFF`(内部メモリのみ)まで、DMA1,DMA2,DMA3の場合は`0x0FFF_FFFF`まで指定することが可能です。 33 | 34 | ## DMAnDAD - ターゲットレジスタ (W) 35 | 36 | DMA転送でデータ転送先のアドレスを指定します。 37 | 38 | ``` 39 | 0x0400_00B4: DMA0DAD - DMA0ターゲットレジスタ (内部メモリのみ) 40 | 0x0400_00C0: DMA1DAD - DMA1ターゲットレジスタ (内部メモリのみ) 41 | 0x0400_00CC: DMA2DAD - DMA2ターゲットレジスタ (内部メモリのみ) 42 | 0x0400_00D8: DMA3DAD - DMA3ターゲットレジスタ 43 | ``` 44 | 45 | DMA0, DMA1, DMA2の場合は`0x07FF_FFFF`まで、DMA3の場合は`0x0FFF_FFFF`まで指定することが可能です。 46 | 47 | ## DMAnCNT - 制御レジスタ (R/W) 48 | 49 | ``` 50 | 0x0400_00B8: DMA0CNT 51 | 0x0400_00C4: DMA1CNT 52 | 0x0400_00D0: DMA2CNT 53 | 0x0400_00DC: DMA3CNT 54 | ``` 55 | 56 | `DMAnCNT.0-15`は `DMAnCNT_L`、`DMAnCNT.16-31`は `DMAnCNT_H` と呼ぶ場合もあります。 57 | 58 | ``` 59 | Bit Dir Expl. 60 | 0-15 W 転送サイズ(bit26で指定するワードの数) 61 | DMA0,1,2 は bit0-13 のみが使用(つまりbit14-15は無視される) 62 | 0にすると 0x4000ワード (DMA3は 0x10000ワード) 63 | 16-20 - 未使用 64 | 21-22 R/W ターゲットアドレス制御; (0: +1, 1: -1, 2: ±0, 3: +1/Reload) 65 | 23-24 R/W ソースアドレス制御; (0: +1, 1: -1, 2: ±0, 3: 指定禁止(指定した場合は、+1?)) 66 | 25 R/W DMAリピート 67 | 0b0: 転送終了後、DMA有効フラグ(bit31)をクリア 68 | 0b1: 転送終了後もDMA有効フラグはセットされたままで、転送開始タイミング(例:HBlank)になるたびに転送が再開 (毎回ワードカウントレジスタで指定された分のデータを転送しゲーム側で停止するまで永遠に繰り返す) 69 | 26 R/W ワードサイズ(0=16bit, 1=32bit) 70 | 27 R/W Game Pak DRQ(DMA3のみ); 0=Normal, 1=DRQ from Game Pak, DMA3 71 | 28-29 R/W モード (0: 即座に, 1: VBlankDMA(VBlank開始時), 2: HBlankDMA(HBlank開始時), 3: チャンネル固有) 72 | CH0: 使用禁止 73 | CH1,2: サウンドFIFO 74 | CH3: ビデオキャプチャ 75 | 30 R/W 転送終了時にIRQを発生させるかどうか 76 | 31 R/W このDMAチャンネルが有効かどうか 77 | 転送が完了、つまり転送サイズ分の転送を完了すると自動的にクリア(bit25が0なら) 78 | このbitを手動でクリアすることで転送を停止させることも可能 79 | ``` 80 | 81 | DMA有効フラグ(bit15)を0から1に変更した後、DMA関連レジスタにアクセスする前に2クロックサイクル待つ必要があります。 82 | 83 | モード2(HBlankDMA)でOAM(`0x0700_0000`)やOBJ VRAM(`0x0601_0000`)にアクセスする場合は、`DISPCNT.5`("H-Blank Interval Free")をセットする必要があります。 84 | 85 | ## ソースレジスタ、ターゲットレジスタ、ワードカウントレジスタ 86 | 87 | ソースレジスタ、ターゲットレジスタ、ワードカウントレジスタは初期開始アドレスと初期長を保持しています。ハードウェアは転送中または転送後にこれらのレジスタの内容を変更することは**ありません**。 88 | 89 | 実際の転送は、**プログラムからは触れない**、内部ポインタと内部カウンタレジスタを使用して行われます。初期値は次の2つの場合に内部レジスタにコピーされます 90 | 91 | - `DMAnCNT.31`を0から1に変更したとき: SAD, DAD, CNT_L がリロードされます。 92 | - DMAリピート時: CNT_Lがリロードされます。DADは`Increment/Reload`のときにリロードされます。 93 | 94 | ## サウンドDMA (DMA1/DMA2のみ) 95 | 96 | サウンド再生用のFIFOへのDMA転送のことをサウンドDMAと呼びます。 97 | 98 | サウンドDMAを行う場合は上述のリピートビットをONにし、転送先アドレスを `FIFO_A`(`0x0400_00A0`) または `FIFO_B`(`0x0400_00A4`) に設定する必要があります。 99 | 100 | サウンドコントローラからのDMA要求により、32bitを4回(合計16バイト)転送します。 このとき、ワードカウントレジスタとDMA転送タイプビット(`CNT_H.10`)は**無視されます**。サウンドDMAでは転送先アドレスはインクリメントされません。 101 | 102 | DMA0のような、サウンドDMAより優先度の高いDMAチャンネルの動作中は、サウンドDMAが一時停止されることに注意してください。例えば、サウンドのサンプルレートが64kHzの場合、16バイトのサウンドDMAデータが 0.25ms(4kHz)ごとに要求されます。よって0.25ms経過するまでに次の16バイトをサウンドDMAでFIFOに転送する必要があります。 103 | つまり、サウンドDMAより優先度の高いDMA転送は、0.25ms以内に終わるのが望ましいです。とはいえ、HBlankの時間は16.212usに制限されているため、DMA0をHBlank時のデータ転送として使う限り問題にはなりません。 104 | 105 | ## Game Pak DMA 106 | 107 | DMA3 のみが Game Pak ROM または Flash ROM との間のデータ転送に使用されます。(データバスが8bit単位に制限されているため、SRAMにはアクセスできません。) 108 | 109 | 通常モードでは、ワードカウントが0になるまでDMAがリクエストされます。 110 | 111 | `DMAnCNT.27`(Game Pack DRQビット)をセットする場合、カートリッジには`/DREQ`信号を出力する外部回路が必要です。 112 | 113 | `/DREQ`と`/IREQ`は同じピンを使用しているので、DRQモードを使用している間はカートリッジから`/IREQ`を供給できません。 114 | 115 | ## ビデオキャプチャーモード(DMA3のみ) 116 | 117 | > [!TIP] 118 | > 商用ゲームで、この機能を使っているゲームは今のところ確認されていません。 119 | 120 | メモリ(または外部のハードウェア/カメラ)から VRAM にビットマップをコピーするためのモードです。 121 | 122 | この転送モードを使用する場合は、リピートビット(`DMAnCNT.25`)をセットし、ワードカウントレジスタ(`DMAnCNT.0-15`)にスキャンラインあたりのデータ単位数を書き込みます。 123 | 124 | キャプチャは HBlankDMA と同様に動作しますが、`VCOUNT=2` で転送が開始され、スキャンラインごとに繰り返され、`VCOUNT=162` で停止します。 125 | 126 | ## 転送時間 127 | 128 | 最初のデータ単位をのぞいて、すべてのデータ単位はシーケンシャルな読み書きによって転送されます。 129 | 130 | n個のデータ単位があるとき、DMA転送全体に要する時間は、`2N + 2(n-1)S + xI` です。 131 | 132 | このうち、`1N + (n-1)S`がReadサイクル、残りの`1N + (n-1)S`がWriteサイクルとなります。実際のサイクル数は転送元エリアと転送先エリアのウェイトステートとバス幅に依存します。 133 | 134 | さらに、毎回のDMA転送ごとに、 `2I`(通常) か `4I`(転送元と転送先がGamePakメモリのとき)がかかるので、(基本的に)`x` は `2n` か `4n`です。 135 | 136 | 137 | -------------------------------------------------------------------------------- /images/affine_matrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/affine_matrix.png -------------------------------------------------------------------------------- /images/alphablend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/alphablend.png -------------------------------------------------------------------------------- /images/bitmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/bitmap.png -------------------------------------------------------------------------------- /images/blackfade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/blackfade.png -------------------------------------------------------------------------------- /images/boktai.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/boktai.jpeg -------------------------------------------------------------------------------- /images/breakpoint-hit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/breakpoint-hit.png -------------------------------------------------------------------------------- /images/breakpoints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/breakpoints.png -------------------------------------------------------------------------------- /images/connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/connect.png -------------------------------------------------------------------------------- /images/debugger-targets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/debugger-targets.png -------------------------------------------------------------------------------- /images/debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/debugger.png -------------------------------------------------------------------------------- /images/decode/arm_bit_pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/decode/arm_bit_pattern.png -------------------------------------------------------------------------------- /images/decode/arm_bit_pattern_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/decode/arm_bit_pattern_1.png -------------------------------------------------------------------------------- /images/decode/arm_bit_pattern_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/decode/arm_bit_pattern_2.png -------------------------------------------------------------------------------- /images/decode/arm_bit_pattern_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/decode/arm_bit_pattern_3.png -------------------------------------------------------------------------------- /images/decode/thumb_bit_pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/decode/thumb_bit_pattern.png -------------------------------------------------------------------------------- /images/decode/thumb_bit_pattern_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/decode/thumb_bit_pattern_1.png -------------------------------------------------------------------------------- /images/e_reader.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/e_reader.jpeg -------------------------------------------------------------------------------- /images/full-debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/full-debugger.png -------------------------------------------------------------------------------- /images/gbm_wire_less.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/gbm_wire_less.jpeg -------------------------------------------------------------------------------- /images/gc_gba_link_cable.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/gc_gba_link_cable.jpeg -------------------------------------------------------------------------------- /images/gdb-prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/gdb-prompt.png -------------------------------------------------------------------------------- /images/gdb-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/gdb-server.png -------------------------------------------------------------------------------- /images/gdb_packet_format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/gdb_packet_format.png -------------------------------------------------------------------------------- /images/ghidra_gba_0.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/ghidra_gba_0.webp -------------------------------------------------------------------------------- /images/ghidra_gba_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/ghidra_gba_1.webp -------------------------------------------------------------------------------- /images/ghidra_gba_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/ghidra_gba_2.webp -------------------------------------------------------------------------------- /images/modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/modules.png -------------------------------------------------------------------------------- /images/mosaic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/mosaic.png -------------------------------------------------------------------------------- /images/multiplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/multiplay.png -------------------------------------------------------------------------------- /images/nes_classic.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/nes_classic.jpeg -------------------------------------------------------------------------------- /images/objects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/objects.png -------------------------------------------------------------------------------- /images/open-with-debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/open-with-debugger.png -------------------------------------------------------------------------------- /images/purple.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/purple.webp -------------------------------------------------------------------------------- /images/regions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/regions.png -------------------------------------------------------------------------------- /images/rom-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/rom-1.png -------------------------------------------------------------------------------- /images/rom-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/rom-2.png -------------------------------------------------------------------------------- /images/screen_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/screen_size.png -------------------------------------------------------------------------------- /images/scroll.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/scroll.jpg -------------------------------------------------------------------------------- /images/strings-password-characters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/strings-password-characters.png -------------------------------------------------------------------------------- /images/threads.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/threads.png -------------------------------------------------------------------------------- /images/whitefade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/whitefade.png -------------------------------------------------------------------------------- /images/window_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/window_0.png -------------------------------------------------------------------------------- /images/window_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/window_1.webp -------------------------------------------------------------------------------- /images/window_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/window_2.webp -------------------------------------------------------------------------------- /images/wire_less.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/gba-docs-ja/f252c4241d51f23f48ffe82cb2a52deaaf38c69f/images/wire_less.jpeg -------------------------------------------------------------------------------- /interrupt.md: -------------------------------------------------------------------------------- 1 | # 割り込み 2 | 3 | ## 0x0400_0208 - IME - 割り込み有効フラグ (R/W) 4 | 5 | 割り込み機能を使用するか使用しないかを設定します。 0か1を指定するだけです。 6 | 7 | 設定が済んだ後、1にして割り込みを発生させます。 8 | 9 | ``` 10 | Bit Expl. 11 | 0 割り込み有効フラグ (0=全ての割り込み無効, 1=有効) 12 | 1-31 不使用 13 | ``` 14 | 15 | ## 0x0400_0200 - IE - IRQ許可フラグ (R/W) 16 | 17 | 許可する割り込みの種類を管理するフラグです。 対応するビットが0の場合、IRQは無視されます。 18 | 19 | 例えば、VBlank割り込みを受け付けるためには 20 | 21 | ```cpp 22 | IME = 1; 23 | IE = 0bxxxx_xxxx_xxxx_xxx1; 24 | ``` 25 | 26 | ``` 27 | Bit Expl. 28 | 0 LCD V-Blank 29 | 1 LCD H-Blank 30 | 2 LCD V-Counter Match 31 | 3 Timer0オーバーフロー 32 | 4 Timer1オーバーフロー 33 | 5 Timer2オーバーフロー 34 | 6 Timer3オーバーフロー 35 | 7 シリアル通信 36 | 8 DMA0(の転送完了) 37 | 9 DMA1 38 | 10 DMA2 39 | 11 DMA3 40 | 12 キー入力 41 | 13 Game Pak (external IRQ source, ゲーム中にカートリッジが抜かれると発生する模様) 42 | 14-15 不使用 43 | ``` 44 | 45 | である必要があります。 46 | 47 | ## 0x0400_0202 - IF - IRQ発生フラグ (R/W) 48 | 49 | 発生した割り込みリクエストに対応するフラグが立てられます。 50 | 51 | Bit と 割り込みソース の対応は `IE` と同じです。 52 | 53 | プログラム側は対応するビットに`0b1`を書き込むことで、割り込みを手動でアクノリッジする必要があり、ビットはクリアされます。 54 | 55 | IMEをクリアしたりIEのフラグをクリアしているサイクルでは割り込みが起きることに注意してください。 56 | IEのフラグをクリアする場合は、割り込みチェックのミスマッチが発生しないようにIMEを事前にクリアしておくことをお勧めします。 57 | 58 | ## BIOS割り込み 59 | 60 | 割り込みが実行されると、CPUはIRQモードに切り替わり、割り込みベクタ`0x0000_0018`が呼び出されます。このアドレスはBIOS内にあるので、BIOSは常に次のコードを実行してからユーザハンドラに制御を転送します。 61 | 62 | ```asm 63 | 00000018 b 128h ; IRQベクタ(BIOSハンドラにジャンプ) 64 | 00000128 stmfd r13!,r0-r3,r12,r14 ; レジスタをSP_irqに退避 65 | 0000012C mov r0,4000000h ; ptr+4 to 03FFFFFC (mirror of 03007FFC) 66 | 00000130 add r14,r15,0h ; retadr for USER handler $+8=138h 67 | 00000134 ldr r15,[r0,-4h] ; jump to [03FFFFFC] USER handler 68 | 00000138 ldmfd r13!,r0-r3,r12,r14 ; SP_irqに退避したレジスタを復帰 69 | 0000013C subs r15,r14,4h ; IRQからリターン (PC=LR-4, CPSR=SPSR) 70 | ``` 71 | 72 | 上のコードにあるように、ユーザー定義割り込みハンドラのアドレスは`0x0300_7FFC`に格納されています。 73 | 74 | デフォルトでは、WRAMの`0x0300_7F00..0300_7F9F`は割り込みスタックとして予約されています。 75 | 76 | ## 0x0300_7Fxx(ミラー: 0x03FF_FFxx) 77 | 78 | 次は、デフォルトで`0x0300_7Fxx`がどのように使われるかを示したものです。 79 | 80 | アドレス | サイズ | 内容 81 | ---- | ---- | ---- 82 | 0x0300_7F00 | 160 | スタック領域(SP_irq) (6 words/time) 83 | 0x0300_7FA0 | 64 | スタック領域(SP_svc) (4 words/time) 84 | 0x0300_7FE0 | 16 | Allocated Area 85 | 0x0300_7FF0 | 4 | サウンドバッファのアドレス 86 | 0x0300_7FF4 | 4 | Allocated Area 87 | 0x0300_7FF8 | 2 | Interrupt Check Flag (for IntrWait/VBlankIntrWait functions) 88 | 0x0300_7FFC | 4 | ユーザー定義IRQハンドラ(ARMモード)のアドレス 89 | 90 | `0x0300_7F00`より前のメモリは、ユーザスタックとユーザデータのための空きメモリです。3つのスタックポインタは、それぞれの領域の先頭で初期化されます。 91 | 92 | ```cpp 93 | SP_svc = 0x03007FE0; 94 | SP_irq = 0x03007FA0; 95 | SP_usr = 0x03007F00; 96 | ``` 97 | 98 | ユーザーはこれらのアドレスを再定義してスタックを他の場所に移動することができますが、のシステムデータ用のアドレス(`7FE0-7FFF`)だけは固定されています。 99 | 100 | ## 高速割り込み(FIQ) 101 | 102 | GBA(のCPU)は、IRQとFIQの2つの割り込みソースを提供しています。 103 | 104 | **GBAではIRQのみを使用します。** 105 | 106 | 通常のGBAでは、ハードウェアでFIQを生成する方法はありません。[1](#fiq) 107 | 108 | ただし、ソフトウェア側でCPSRに書き込みを行いFIQモードに切り替えることで、レジスタ`R8-R12_fiq`をソフトウェアで使用することができます。[2](#doom) 109 | 110 | しかし、このようなゲームはハードウェアデバッガ(デバッグ目的でFIQを使用していると報告されている)がうまく動作しない可能性があることに注意してください。 111 | 112 | 1. FIQ信号はVDD35にショートカットされており常にHighになっています。 113 | 114 | 2. ここ最近でGBAに移植されたゲームがそのようなことをしています。 https://youtu.be/R43k-p9XdIk 115 | -------------------------------------------------------------------------------- /keypad.md: -------------------------------------------------------------------------------- 1 | # キー入力 2 | 3 | ## 0x0400_0130 - KEYINPUT - キー入力レジスタ (R) 4 | 5 | ボタンの入力はIOレジスタの`0x0400_0130、0x0400_0131`の値で判定します。 6 | 7 | 下位のビットから順番に、Aボタン、Bボタン、セレクトボタン、スタートボタン、 8 | 十字キーの→、←、↑、↓、最後はRボタン、Lボタンとなっています。 9 | 10 | ビット | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 11 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- 12 | ボタン | | | | | | | L | R | ↓ | ↑ | ← | → | Start | Select | B | A 13 | 14 | ビットが立っている時は押されていない状態、ビットが立っていない時は押されている状態です。 15 | 16 | どの程度の強さで押されているか、といった判定はできません。 17 | 18 | 通常、このレジスタの読み出しは1フレームに1回だけにして、現在の状態をメモリに保存することをお勧めします。 19 | 20 | ## 0x0400_0132h - KEYCNT - キー割り込み制御レジスタ (R/W) 21 | 22 | キー割り込み機能は、非常に低消費電力のSTOPモードを終了させるためのもので、通常のユーザ入力を処理するのには適していません。 23 | 24 | ビット | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 25 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- 26 | ボタン | IRQ条件 | IRQ有効 | | | | | L | R | ↓ | ↑ | ← | → | Start | Select | B | A 27 | 28 | A,B,Select,Start,... はbitが0ならその入力は無視する、1なら無視しない 29 | 30 | IRQ条件は 31 | 32 | - 0: bitが1の入力の**どれか**が押されたらIRQ (logical OR) 33 | - 1: bitが1の入力**すべて**が押されているときにIRQ (logical AND) 34 | 35 | ゲームボーイ互換モードでは、LボタンとRボタンを使って、通常の160x144ピクセルと240x144ピクセルの間で画面サイズを切り替えます。 36 | 37 | GBASPにはさらに、バックライトのオンオフを切り替えるための*ボタンがあります(別のハードウェアロジックで制御され、ソフトウェアで現在のバックライトの状態を検出したり変更したりする方法はありません)。 38 | -------------------------------------------------------------------------------- /memory.md: -------------------------------------------------------------------------------- 1 | # メモリマップ 2 | 3 | ## メモリマップ 4 | 5 | **内部メモリ** 6 | 7 | 空いている領域は未使用領域です。 8 | 9 | アドレス | サイズ | バス幅 | 名称 | 用途 10 | ---- | ---- | ---- | ---- | ---- 11 | 00000000-00003FFF | 16KB | 32bit | BIOS | 起動プログラムなどを実装したROM 12 | 02000000-0203FFFF | 256KB | 16bit | WRAM(オンボード) | プログラムを入れる外部メモリ EWRAMとも 13 | 03000000-03007FFF | 32KB | 32bit | WRAM(チップ) | ARM内蔵の高速メモリ IWRAMとも 14 | 04000000-040003FE | 1KB | 32bit | IOレジスタ | IO機能を制御するレジスタ 15 | 16 | **内部メモリ(画面描画用)** 17 | 18 | 空いている領域は未使用領域です。 19 | 20 | アドレス | サイズ | バス幅 | 名称 | 用途 21 | ---- | ---- | ---- | ---- | ---- 22 | 05000000-050003FF | 1KB | 16bit | パレット | 256色分色を記憶可能 23 | 06000000-06017FFF | 96KB | 16bit | VRAM | LCD に表示するデータを入れる 24 | 07000000-070003FF | 1KB | 32bit | OAM | オブジェクトと背景を重ねる機能 25 | 26 | **外部メモリ (Game Pak)** 27 | 28 | Game Pak = カートリッジのことです。 29 | 30 | アドレス | サイズ | バス幅 | 名称 | 備考 31 | ---- | ---- | ---- | ---- | ---- 32 | 08000000-09FFFFFF | 32MB | 16bit | カートリッジROM/FlashROM | WaitState 0 33 | 0A000000-0BFFFFFF | 32MB | 16bit | カートリッジROM/FlashROM | WaitState 1 34 | 0C000000-0DFFFFFF | 32MB | 16bit | カートリッジROM/FlashROM | WaitState 2 35 | 0E000000-0E00FFFF | 64KB | 8bit | SRAM | -- 36 | 0E010000-0FFFFFFF | -- | -- | 未使用 | -- 37 | 38 | `0A000000-0BFFFFFF`と`0C000000-0DFFFFFF`は`08000000-09FFFFFF`で、アクセスに必要な待機時間(WaitState)が違います。基本的に`08000000-09FFFFFF`(WaitState 0)のみが使用されます。 39 | 40 | `0x1000_0000-FFFF_FFFF`は使用できません。 41 | 42 | ## WRAMについて 43 | 44 | デフォルトでは、WRAMの`0x0300_7F00-0x0300_7FFF`の256バイトは、割り込みベクタ、割り込みスタック、BIOSコールスタック用に予約されています。 45 | 46 | 残りのWRAMは、`0x0300_7F00`から配置されているユーザースタックを含めてどのような用途にも自由に使用できます。 47 | 48 | ## アクセス 49 | 50 | バス幅とCPUが一度に読み書き可能なbit数、アクセスに要するサイクルの一覧です。 51 | 52 | メモリ領域 | バス幅 | Read幅 | Write幅 | サイクル(8/16/32bit) 53 | ---- | ---- | ---- | ---- | ---- 54 | BIOS | 32 | 8/16/32 | - | 1/1/1 55 | EWRAM | 16 | 8/16/32 | 8/16/32 | 3/3/6[1](#note_1) 56 | IWRAM | 32 | 8/16/32 | 8/16/32 | 1/1/1 57 | IOレジスタ | 32 | 8/16/32 | 8/16/32 | 1/1/1 58 | パレット | 16 | 8/16/32 | 16/32 | 1/1/2[2](#note_2) 59 | VRAM | 16 | 8/16/32 | 16/32 | 1/1/2[2](#note_2) 60 | OAM | 32 | 8/16/32 | 16/32 | 1/1/1[2](#note_2) 61 | GamePak ROM | 16 | 8/16/32 | - | 5/5/8[1](#note_1),[3](#note_3) 62 | GamePak Flash | 16 | 8/16/32 | 16/32 | 5/5/8[1](#note_1),[3](#note_3) 63 | GamePak SRAM | 8 | 8 | 8 | 5 [1](#note_1) 64 | 65 | これ以外にも16bitごとまたは32bitごとのDMA転送がSRAMをのぞいた全てのメモリに可能です。 66 | 67 | 1: サイクルはwaitstateの設定によって変わってきます 68 | 2: GBAが同時にビデオメモリにアクセスする場合はプラス1サイクルされます 69 | 3: シーケンシャルアクセスとノンシーケンシャルアクセスのタイミングを分けます。 70 | 71 | ## VRAM、OAM、パレット 72 | 73 | VRAM、パレットは、**HBlank中またはVBlank中のみアクセス可能**です。 DISPCNTレジスタのFBlankビット(DISPCNT.7)で表示が無効化されているときはそれ以外のタイミングでもアクセスできます。 74 | 75 | OAMはさらにアクセス条件が厳しいです。 [DISPCNT](video/control.md#0x0400_0000---dispcnt---lcd%E5%88%B6%E5%BE%A1%E3%83%AC%E3%82%B8%E3%82%B9%E3%82%BF-rw)のbit5が1の場合にのみ、HBlank中のアクセスが許可されます。 76 | 77 | ## ROM(GamePak ROM, カートリッジROM)とSRAM 78 | 79 | CPUとDMA3のみがROMにアクセスできます。 80 | 81 | SRAMにはCPUしかアクセスできず一度に8bitごとしかアクセスできません。 SRAMは電池形式とフラッシュメモリ形式があります。 82 | 83 | ROMのバス幅は16bitに制限されているため、ROMの内部からARM命令(32bit)を実行すると、あまり良いパフォーマンスが得られません。よってTHUMB命令(16bit)を使うことをお勧めします。 84 | 85 | ただし、どうしてもARM命令を使いたい時はROMから内部のWRAMにコードをコピーすることで、パフォーマンスを落とさず実行が可能です。 86 | 87 | ## データフォーマット 88 | 89 | GBAでは常にデータはリトルエンディアン形式です。 90 | 91 | ## メモリのミラー 92 | 93 | ``` 94 | BIOS, IO: ミラー無し(`MEMCNT` のみ例外) 95 | EWRAM: 0x40000 ごとに 0x02000000..02FFFFFF の範囲に渡ってミラー 96 | IWRAM: 0x8000 ごとに 0x03000000..03FFFFFF の範囲に渡ってミラー 97 | Palette: 0x400 ごとに 0x05000000..05FFFFFF の範囲に渡ってミラー 98 | VRAM: 0x06010000..06017FFF が 0x06018000..0601FFFF にミラー、そして0x20000ごとに 0x06000000..06FFFFFFF の範囲に渡ってミラー 99 | OAM: 0x400 ごとに 0x07000000..07FFFFFF の範囲に渡ってミラー 100 | SRAM: 0x10000 ごとに 0x0E000000..0FFFFFFF の範囲に渡ってミラー 101 | ``` 102 | 103 | ## BIOS領域からの読み込み(0x0000_0000..0000_3FFF) 104 | 105 | [特殊な挙動](./unpredictable.md#bios領域からの読み込み0x0000_00000000_3fff)を参照 106 | 107 | ## 不使用メモリ領域からの読み込み (0x0000_4000..01FF_FFFF, 0x1000_0000..FFFF_FFFF) 108 | 109 | [特殊な挙動](./unpredictable.md#不使用メモリ領域からの読み込み-0x0000_400001ff_ffff-0x1000_0000ffff_ffff)を参照 110 | -------------------------------------------------------------------------------- /others/emudev/decode.md: -------------------------------------------------------------------------------- 1 | # デコード 2 | 3 |
  4 | Note:
  5 | 
  6 | この記事は
  7 | 
  8 | - Decoding the ARM instruction set
  9 | - Decoding the THUMB instruction set
 10 | 
 11 | を翻訳したもので、主にGBAエミュレータ開発者向けです。
 12 | 
13 | 14 | ## ARMモード 15 | 16 | まず、ARM命令のバイナリオペコードフォーマットを見てみましょう。 17 | 18 | ![arm_bit_pattern](/images/decode/arm_bit_pattern.png) 19 | 20 | しかし、この参考文献は完全に正確なものではなく、最初の命令をデコードするために必要な重要な情報を見逃しているので、これから説明します。 21 | 22 | まず最初に、THUMB命令セットをデコードするとき、私たちは単純に命令の上位8ビットを使用していたので、命令を明確にデコードすることができました。 23 | 24 | 例えば、ビット27~20を使って、どの命令なのかを判断しようとすると、ビット27~20をすべてアンセット(0)にする命令が複数種類あるため、曖昧になってしまいます。 25 | 26 | そこで、上位8ビット(ビット27-20)とベース4ビット(ビット7-4)を端と端で足し合わせることにします。この原理をもう少しわかりやすく説明するための絵があります。 27 | 28 | ![arm_bit_pattern_1](/images/decode/arm_bit_pattern_1.png) 29 | 30 | C/C++では、この値を実際に取得するには、ビット単位での微調整が必要です。例えば、以下のようになります。 31 | 32 | ```cpp 33 | u32 instruction = fetch(); 34 | u16 _12Bits = (((instruction >> 16) & 0xFF0) | ((instruction >> 4) & 0x0F)); 35 | ``` 36 | 37 | これで、命令をデコードするのに使う12ビットの数字ができました。では、最初から考えてみましょう。 38 | 39 | この12ビットの数字が0、つまりすべてのビットがアンセットされていたらどうなるでしょうか。 40 | 41 | オペコードフォーマットを見ると、これを可能にする命令フォーマットは1つだけで、1枚目の写真の一番上の`Data Processing/PSR`命令であることがわかります。 42 | 43 | さて、この命令がどのようなタイプの命令であるかはすでにわかっていますが、どのような命令であるかを正確に知るためには、さらに情報が必要です。 44 | 45 | `Data Processing/PSR`命令では、`Operand2`というフィールドがあります。 46 | 47 | このフィールドは、上記のバイナリオペコードフォーマットには示されていないフォーマットを持っており、以下に`Operand2`フィールドの仕様を示します。 48 | 49 | ![arm_bit_pattern_2](/images/decode/arm_bit_pattern_2.png) 50 | 51 | 今回の状況では、すべてのビットは0なので、当然`immediate`ビット(bit25)がセットされていないので、シフトされたレジスタを使用していることになります。 52 | 53 | バレルシフトについては今のところ説明しませんが、これはこの記事の範囲を超えています。ここでは、より正式な言い方として、マニュアルから直接引用します。 54 | 55 | > 第2オペランドがシフトレジスタと指定されている場合、バレルシフタの動作は命令の`shift`フィールドによって制御されます。 56 | 57 | `shift`フィールドは次のようになっています。 58 | 59 | ![arm_bit_pattern_3](/images/decode/arm_bit_pattern_3.png) 60 | 61 | これは非常に複雑なことだと思いますが、マニュアルを読んでいただくのが一番です。 62 | 63 | とにかく、私についてきてください。この命令について、これまでに集めた情報を確認してみましょう。12ビットすべてが0であると仮定すると...。 64 | 65 | 1. `Data Processing`命令です。 66 | 2. シフトされたレジスタのバレルシフト演算を使用します。 67 | 3. bit24-21からAND命令です。 68 | 4. bit4は0なので、シフトしたレジスタを即値でシフトするシフト操作であることがわかり、直前の図の左側のフォーマットを使用しています。 69 | 5. bit6-5は0なので、シフト内容は`LSL`です。 70 | 71 | よって 72 | 73 | `AND Rd, Rn, Rm, LSL #imm5` 74 | 75 | となります! 76 | 77 | ## THUMBモード 78 | 79 | まず、THUMB命令のバイナリオペコードフォーマットを見てみましょう。 80 | 81 | ![thumb_bit_pattern](/images/decode/thumb_bit_pattern.png) 82 | 83 | 各命令は2バイト(ハーフワード)で構成されており、各命令には、CPUがデコードする独自のフォーマットがあります。 84 | 85 | ご覧のように、フォーマット1(`Move shifted register`)のようないくつかの命令フォーマットには、これが特定の命令であることを示すオペコードフィールドがあります。`Move shifted register`の場合には、12-11bitに2ビットのオペコードフィールドがあります。 86 | 87 | さて、私が命令をデコードする方法は、命令の上位8ビットを取り、その値をチェックすることです。 88 | 89 | 例えば、上位8ビットの値が「0〜7」であれば、その命令が`LSL Rd, Rs, Offset`とわかります。なぜでしょうか? 90 | 91 | これは、上位8ビットが「0〜7」になっている間は、`Move shifted register`のオペコードフィールドが0になり、この形式の他のビットはすべて正しいからです。 92 | 93 | ![thumb_bit_pattern_1](/images/decode/thumb_bit_pattern_1.png) 94 | 95 | 上の図では上位8bitは`00000101`となっています。 96 | 97 | 命令フォーマットを確認すると、`Move shifted register`フォーマットでは、上位8bitがこの値になる場合がありえます。 98 | 99 | `Move shifted register`フォーマットでは、先の8bit値の下位3bitが、`Offset5`フィールドの上位3bit(bit8,9,10)であり、このフィールドは任意の値がありうるからです。 100 | 101 | また、任意の値をとりうるということは、次の8つのバイナリはすべて`LSL Rd, Rs, Offset5`となります。 102 | 103 | ``` 104 | 00000000 (0) 105 | 00000001 (1) 106 | 00000010 (2) 107 | 108 | 00000011 (3) 109 | 00000100 (4) 110 | 00000101 (5) 111 | 00000110 (6) 112 | 00000111 (7) 113 | ``` 114 | 115 | 次に、仮に8という値が出た場合、オペコードフィールドが1つ増えたことになるので、命令は`LSR Rd, Rs, Offset5`となります。 116 | 117 | 残りの命令セットのデコードも、この論理パターンに従うだけです。 118 | 119 | ここでは、最初の数個の命令をどのようにデコードするか、コード例を紹介します 120 | 121 | 条件分岐を使う場合は、 122 | 123 | ```cpp 124 | u16 instruction = fetch(); 125 | 126 | switch (instruction >> 8) 127 | { 128 | case 0: 129 | case 1: 130 | case 2: 131 | case 3: 132 | case 4: 133 | case 5: 134 | case 6: 135 | case 7: 136 | { 137 | // LSL Rd, Rs, Offset5 138 | } break; 139 | case 8: 140 | case 9: 141 | case 0xA: 142 | case 0xB: 143 | case 0xC: 144 | case 0xD: 145 | case 0xE: 146 | case 0xF: 147 | { 148 | // LSR Rd, Rs, Offset5 149 | } break; 150 | } 151 | ``` 152 | 153 | 関数ポインタの配列を使う場合は、 154 | 155 | ```cpp 156 | 157 | void (*CPU_Thumb_Instruction[0x100]) (u16 instruction) = 158 | { 159 | Thumb_LSL_Rd_Rs_Offset, // 00h 160 | Thumb_LSL_Rd_Rs_Offset, // 01h 161 | Thumb_LSL_Rd_Rs_Offset, // 02h 162 | Thumb_LSL_Rd_Rs_Offset, // 03h 163 | Thumb_LSL_Rd_Rs_Offset, // 04h 164 | Thumb_LSL_Rd_Rs_Offset, // 05h 165 | Thumb_LSL_Rd_Rs_Offset, // 06h 166 | Thumb_LSL_Rd_Rs_Offset, // 07h 167 | /*-------------------*/ 168 | Thumb_LSR_Rd_Rs_Offset, // 08h 169 | Thumb_LSR_Rd_Rs_Offset, // 09h 170 | Thumb_LSR_Rd_Rs_Offset, // 0Ah 171 | Thumb_LSR_Rd_Rs_Offset, // 0Bh 172 | Thumb_LSR_Rd_Rs_Offset, // 0Ch 173 | Thumb_LSR_Rd_Rs_Offset, // 0Dh 174 | Thumb_LSR_Rd_Rs_Offset, // 0Eh 175 | Thumb_LSR_Rd_Rs_Offset, // 0Fh 176 | }; 177 | ``` 178 | 179 | -------------------------------------------------------------------------------- /others/homebrew/devkit.md: -------------------------------------------------------------------------------- 1 | # devkitProのインストール手順(MacOS) 2 | 3 | 1. [ここ](https://github.com/devkitPro/pacman/releases/tag/v1.0.2)から[`devkitpro-pacman-installer.pkg`](https://github.com/devkitPro/pacman/releases/download/v1.0.2/devkitpro-pacman-installer.pkg)をダウンロード 4 | 2. ダウンロードした`devkitpro-pacman-installer.pkg`をfinder上で右クリックして『開く』を押してインストール 5 | 3. 再起動 6 | 4. `sudo (dkp-)pacman -S gba-dev` 7 | 8 | -------------------------------------------------------------------------------- /others/homebrew/mgba_with_gdb.md: -------------------------------------------------------------------------------- 1 | # mgbaをgdbでデバッグする方法 2 | 3 | [Debugging With mGBA](https://simianzombie.com/posts/2018/11/12/debugging-with-mgba)を翻訳したものです。 4 | 5 | 1. ROMをmGBAで開く 6 | 2. mGBAのデバッグサーバーUIを開く(MacOSの場合は、`open Tools -> Start GDB server`) 7 | 3. オプションを指定して、`Start` 8 | 4. ターミナルを開いて、`/opt/devkitpro/devkitARM/bin/arm-none-eabi-gdb`と叩き、GDBを実行する 9 | 5. GDBのシェル内で、`target remote localhost:2345`を実行(3のオプションによって`localhost:2345`を調整してください) 10 | 6. GDBのシェル内で、`file `を叩く(確認時には`y`) 11 | 12 | ## GDBのコマンドについて 13 | 14 | ### `target remote dev` 15 | 16 | ターゲットとは、 ユーザ・プログラムが持つ実行環境を指します。 多くの場合、 GDBはユーザ・プログラムと同一のホスト環境上で実行されます。 この場合には、 fileコマンドやcoreコマンドを実行すると、 その副作用としてデバッグ・ターゲットが指定されます。 17 | 18 | 例えば、 物理的に離れた位置にあるホスト・マシン上でGDBを実行したい場合や、 シリアル・ポート経由でスタンドアロン・システムを制御したい場合、 または、 TCP/IP接続を利用してリアルタイム・システムを制御したい場合などのように、 より多くの柔軟性が必要とされる場合、 targetコマンドを使うことによって、 GDBに設定されたターゲットの種類の中から1つを指定することができます。 19 | 20 | **`target remote dev`** 21 | 22 | GDB固有のプロトコルによる、 リモートのシリアル・ターゲットです。 引数`dev`によって、 接続を確立するために使用するシリアル装置 (例えば、 `/dev/ttya`) を指定します。 リモート・デバッグを参照してください。 `target remote`は、 `load`コマンドもサポートするようになりました。 これは、 スタブをターゲット・システム上に持っていく方法が別にあり、 かつ、 ダウンロードが実行されたときに破壊されないようなメモリ域にそれを置くことができる場合にのみ役に立ちます。 23 | 24 | ### `file filename` 25 | 26 | `filename`で指定されるプログラムをデバッグ対象にします。 27 | 28 | そのプログラムは、 **シンボル情報とメモリ内容を獲得するために読み込まれます。** また、 ユーザが`run`コマンドを使用したときに実行されます。 29 | 30 | ユーザがディレクトリを指定せず、 そのファイルがGDBの作業ディレクトリに見つからない場合、 シェルが実行すべきファイルを探すときと同様、 GDBは、 ファイルを探すべきディレクトリのリストとして環境変数PATHの値を使用します。 31 | 32 | `path`コマンドによって、 GDB、 ユーザ・プログラムの両方について、 この変数の値を変更することができます。 ファイルをメモリにマップすることのできるシステムでは、 補助的なファイル`filename.syms`に、 ファイル`filename`のシンボル・テーブル情報が格納されることがあります。 33 | 34 | このような場合、 GDBは、 `filename.syms`というファイルからシンボル・テーブルをメモリ上にマップすることで、 起動に要する時間を短くします。 詳細については、 (以下に説明するfileコマンド、 `symbol-file`コマンド、 `add-symbol-file`コマンドを実行する際にコマンドライン上で使用可能な) ファイル・オプションの`-mapped`、 `-readnow`の説明を参照してください。 35 | 36 | ## 参考記事 37 | 38 | - https://www.asahi-net.or.jp/~wg5k-ickw/html/online/gdb-4.18 39 | 40 | -------------------------------------------------------------------------------- /others/homebrew/mgba_with_ghidra_debug.md: -------------------------------------------------------------------------------- 1 | # mGBAを GDB+Ghidra でデバッグする方法 2 | 3 | ## 動作環境 4 | 5 | ``` 6 | System: M1 Mac 7 | mGBA: v0.9.3 8 | Ghidra: v10.1 (with Java v11.0.2) 9 | GDB: arm-none-eabi-gdb v9.2 10 | ``` 11 | 12 | ## 手順 13 | 14 | 1. mGBAを開いて`0.0.0.0:2345`(任意)でGDBリモートサーバーを立てる 15 | 16 | ![](../../images/ghidra_gba_2.webp) 17 | 18 | 2. Ghidraで対象のプロジェクトを`Open with > Debugger`で開く 19 | 3. `Debugger Targets`で次のようにする 20 | 21 | ![](../../images/ghidra_gba_0.webp) 22 | 23 | 4. シェルでGDB(`Debugger Targets`で指定したのと同じパス)を開いて、`new-ui mi2 xxxx`を入力する これでGDBをGhidraから操れるようになる 24 | 25 | ![](../../images/ghidra_gba_1.webp) 26 | 27 | 5. Ghidra上のGDBインタプリタで次のバッチファイルを実行して、GDB+GhidraをmGBAに接続させる 28 | 29 | ```txt 30 | define info proc mappings 31 | echo 0x0 0xFFFFFFFF 0x100000000 0x0 mem \n 32 | end 33 | target remote :2345 34 | ``` 35 | 36 | ```gdb 37 | source FILEPATH.txt 38 | ``` 39 | -------------------------------------------------------------------------------- /others/ret/interwork.md: -------------------------------------------------------------------------------- 1 | # interwork 2 | 3 | GBAのソフトを解析していると次のようにして関数からリターンしている場合が多いです。 4 | 5 | ``` 6 | pop { r1 } 7 | bx r1 8 | ``` 9 | 10 | ですが、 11 | 12 | ``` 13 | pop { pc } 14 | ``` 15 | 16 | と書く方が素直に思えます。 17 | 18 | 以後、前者の書き方を `popbx`, 後者の書き方を `poppc` と呼ぶことにします。 19 | 20 | 実行速度も、 21 | 22 | ``` 23 | ; 合計: 3S+2N+1 24 | pop { r1 } ; 1S+1N+1 25 | bx r1 ; 2S+1N 26 | ``` 27 | 28 | ``` 29 | pop { pc } ; 2S+2N+1 30 | ``` 31 | 32 | なので、実行時間は `1S` だけ`poppc`のほうが速いです。 33 | 34 | スタックの使い方によっては、もっと差が出る場合もあります。 35 | 36 | 例えば、 37 | 38 | ``` 39 | ; 合計: 4S+3N+2 40 | pop { r4 } ; 1S+1N+1 41 | pop { r1 } ; 1S+1N+1 42 | bx r1 ; 2S+1N 43 | ``` 44 | 45 | ``` 46 | pop { r4, pc } ; 3S+2N+1 47 | ``` 48 | 49 | の場合、実行時間は `1S+1N+1` だけ`poppc`のほうが速くなります。 50 | 51 | 一般的なROMでは `(N, S) = (4, 2)` なので、最初の例では 2サイクル、2番目の例では、 7サイクル の差がつくことになります。 52 | 53 | ## `popbx` と `poppc` の違い 54 | 55 | 両方とも、スタックからアドレスを取り出してそこにジャンプする処理ですが、GBAの場合は挙動が異なります。 56 | 57 | `popbx`では、ジャンプ先のアドレスを偶数にすることでジャンプ先で`ARM`モードに、奇数にすることでジャンプ先で`THUMB`モードにスイッチします。 58 | 59 | `poppc`の場合は、ジャンプしても`ARM/THUMB`モードが切り替わることはありません。 60 | 61 | つまり、`poppc`で正常にリターンできるのは、呼び出し元とサブルーチンのCPUモードが同じ場合です。そのため、呼び出し元とサブルーチンのCPUモードが同じであることを保証できない場合は、`popbx`でリターンする必要があります。 62 | 63 | `popbx`のような、`ARM/THUMB`モードのスイッチをケアするプログラムは `interwork` と呼ばれています。 64 | 65 | ## agbcc 66 | 67 | `agbcc` は NintendoがC言語で書かれたソースコードをGBA ROM向けにビルドするときに使っていたコンパイラです。`GCC 2.95.1`が元になっています。[1](#agbcc) 68 | 69 | `agbcc`(というか元になったGCC ARM)では、コンパイルの際に、`-mthumb-interwork`オプションを指定することで、リターン時のコードとして、`poppc`ではなく、`popbx`を使ったプログラムを吐き出すようになります。 70 | 71 | ## 使い所 72 | 73 | 冒頭でも述べましたが、`interwork`しない(`poppc`)ほうが、実行速度も速く、プログラムのサイズも小さくなります。 74 | 75 | そのため、呼び出し元とサブルーチンのCPUモードが同じであることを保証できる場合は、`interwork`しない方が望ましいです。 76 | 77 | 実際のところ、(筆者の観測範囲で)多くのゲームは、とりあえず`-mthumb-interwork`オプションを指定して`interwork`したプログラムを吐き出させていました。 78 | 79 | ただし、最適化に力を入れているゲーム(例: 黄金の太陽 失われし時代)ではなるべく`poppc`でリターンするようにしていたようです。[2](#gstla) 80 | 81 | ## 注釈 82 | 83 | 1: 他にも`GCC 2.95.0`を元にした初期版(`old agbcc`と呼ばれる) や `GCC 2.95.3`を元にした後期版(`modern agbcc`,`new agbcc`と呼ばれる)がある模様 84 | 85 | 2: https://discord.com/channels/768759024270704641/833314924766953482/931632076992684093 86 | 87 | -------------------------------------------------------------------------------- /spec.md: -------------------------------------------------------------------------------- 1 | # 仕様 2 | 3 | ## 概要 4 | 5 | - CPU: 32bit CPU, クロックは16.78MHz 6 | - RAM: 288KB 7 | - グラフィック: 240x160pxで最大256色 8 | - サウンド: 6チャンネル, 16bit音源 9 | 10 | ## 本体 11 | 12 | - 発売日: 2001/3/21 13 | - 定価: 9800円(税別) 14 | - 大きさ(幅x奥行きx高さ): 144×82×24.5mm 15 | - 重量: 約140g 16 | 17 | ## CPU 18 | 19 | モード | 概要 20 | ---- | ---- 21 | ARMモード | ARM7TDMI 32bit RISC CPU, 16.78MHz, 32bit opcodes 22 | THUMBモード | ARM7TDMI 32bit RISC CPU, 16.78MHz, 16bit opcodes 23 | CGBモード | GBZ80 8bit CPU, 4.2MHz or 8.4MHz 24 | DMGモード | GBZ80 8bit CPU, 4.2MHz 25 | 26 | ## 内部メモリ 27 | 28 | 名称 | 容量 | 備考 29 | ---- | ---- | ---- 30 | BIOS ROM | 16KB | 31 | Work RAM | 288KB | チップ上の32KBは高速で、オンボードの256KBは低速 32 | VRAM | 96KB | 33 | OAM | 1KB | 128 OBJs 3x16bit, 32 OBJ-Rotation/Scalings 4x16bit 34 | Palette RAM | 1KB | BG:256色, OBJ:256色 35 | 36 | ## 画面表示 37 | 38 | 名称 | 概要 39 | ---- | ---- 40 | Display | 240x160px (2.9インチ TFT液晶) 41 | BG layers | 4つの背景レイヤ 42 | BG types | タイルモードとビットマップモード 43 | BG colors | 256色 or 16色/16パレット or 32768色 44 | OBJ colors | 256色 or 16色/16パレット 45 | OBJ size | 12種類 (ピクセル単位で 8x8 から 64x64まで) 46 | OBJs/Screen | max. 128 OBJs of any size (up to 64x64 dots each) 47 | OBJs/Line | max. 128 OBJs of 8x8 dots size (under best circumstances) 48 | Priorities | OBJ/OBJ: 0-127, OBJ/BG: 0-3, BG/BG: 0-3 49 | Effects | 画面に適用できるエフェクト。伸縮回転, ブレンド, モザイク, ウィンドウ 50 | Backlight | GBASPのみ搭載 51 | 52 | ## サウンド 53 | 54 | 名称 | 概要 55 | ---- | ---- 56 | アナログ | CGB互換のための4チャンネル (3x square wave, 1x noise) 57 | デジタル | DMAサウンドチャンネルが2つ 58 | 出力 | スピーカー(モノラル) または ヘッドホン端子(ステレオ) 59 | 60 | ## 操作 61 | 62 | 上下左右4つの方向キーと、A,B,Start,Select,L,Rの6つのボタン 63 | 64 | ## 通信機能 65 | 66 | Serial Port Various transfer modes, 4-Player Link, Single Game Pak play 67 | 68 | ## 外部メモリ 69 | 70 | - GBA Game Pak max. 32MB ROM or flash ROM + max 64K SRAM 71 | - CGB Game Pak max. 32KB ROM + 8KB SRAM (more memory requires banking) 72 | 73 | ## サイズ (mm) 74 | 75 | - GBA: 145x81x25 76 | - GBASP: 82x82x24 (閉), 155x82x24 (開) 77 | 78 | ## 電源 79 | 80 | - Battery GBA GBA: 2x1.5V DC (AA), Life-time approx. 15 hours 81 | - Battery SP GBA SP: Built-in rechargeable Lithium ion battery, 3.7V 600mAh 82 | - External GBA: 3.3V DC 350mA - GBA SP: 5.2V DC 320mA 83 | -------------------------------------------------------------------------------- /system.md: -------------------------------------------------------------------------------- 1 | # システム制御 2 | 3 | ## 0x0400_0300 - POSTFLG(Undocumented) - Post Boot / Debug Control (R/W) 4 | 5 | 最初のリセット後、BIOSはこのレジスタを0x01に初期化しリセットベクタ(0x000000)をさらに実行します。 6 | 7 | このときレジスタがまだ0x01に設定されていることを感知すると、デバッグベクタ(0x0000_001c)に制御を渡します。 8 | 9 | bit | 内容 10 | ----- | ----- 11 | 0 | Undocumented. First Boot Flag (0=First, 1=Further) 12 | 1-7 | Undocumented. Not used. 13 | 14 | 通常、デバッグハンドラは、カートリッジヘッダでデバッグフラグを検出しない限り制御を受け付けませんが、その場合は、(任天堂ロゴとブート遅延を省略することで) 簡略化されたブート処理へとリダイレクトします 15 | 16 | しかし、このレジスタを自動的にリセットせずにGBAを外部からリセットすることは可能なのかどうかはわかりません。 17 | 18 | ## 0x0400_0301 - HALTCNT(Undocumented) - 省電力モード制御レジスタ (W) 19 | 20 | このレジスタに書き込みを行うことでGBAは省電力モードに移行します。 21 | 22 | Haltモードでは、`IE & IF = 0`の限りCPUが停止し続けます。 これはCPUが割り込みを待つ間に電力消費を抑えるために使われます。 23 | 24 | 省電力モードは、サウンドや画面を含めたほとんどのハードウェアが停止します。 25 | 26 | bit | 内容 27 | ----- | ----- 28 | 0-6 | 未使用 29 | 7 | 省電力モード (0=Halt, 1=Stop) 30 | 31 | **基本的に、このレジスタに直接書き込むよりも BIOS関数 SWI2(Halt) または SWI3(Stop) を使用することが一般的に推奨されます。** 32 | 33 | ## 0x0400_0410 - Undocumented - 用途不明(1byte) (W) 34 | 35 | BIOSはこのアドレスに0xFFを書き込みますが目的は不明です。 36 | 37 | おそらくBIOSのバグでしょう。 38 | 39 | ## 0x0400_0800 - MEMCNT(Undocumented) - 内部メモリ制御レジスタ (R/W) 40 | 41 | ハードウェアによって`0x0D00_0020`で初期化されます。 42 | 43 | 他のIOレジスタと違って、このレジスタはIOレジスタ用のメモリ領域にミラーされます。(ここから`0x0001_0000`刻み。 つまり0x0400_0800, 0x0401_0800, 0x0402_0800, ..., 0x04FF_0800) 44 | 45 | ``` 46 | Bit Dir Expl. 47 | 0 R/W WRAM無効化フラグ (0=Normal, 1=IWRAM,EWRAMの両方無効化) 48 | 1-3 R/W 用途不明 49 | 4 W? 用途不明 (常に0) 50 | 5 R/W EWRAM有効化フラグ (0=無効, 1=有効) (無効化するとIWRAMのミラー) 51 | 6-23 W? 用途不明 (常に0) 52 | 24-27 R/W EWRAMウェイトステート (0-14 = 15..1 Waitstates, 15=Lockup) 53 | 28-31 R/W 用途不明 54 | ``` 55 | 56 | EWRAMウェイトステート(`MEMCNT.24-27`) は デフォルトで`13`(`0x0D`)が入っていてウェイトステートが`2`になるようになっています。つまり 8/16/32bitアクセスに要するクロックサイクルは 3/3/6 となります。 57 | 58 | ### EWRAMのオーバークロック 59 | 60 | EWRAMウェイトステート(`MEMCNT.24-27`) を `14`(`0x0E`) にするとウェイトステートは`1`になり、8/16/32bitアクセスに要するクロックサイクルが 2/2/4 となります。 61 | 62 | EWRAMのオーバークロックはGBAとGBASPでは可能ですがゲームボーイミクロでは不可能です。 63 | 64 | ``` 65 | (おそらく)ゲームボーイミクロのEWRAMはGBAやGBASPのものよりもアクセス速度が遅い、つまりメモリ操作を完了するまでにかかる時間が長いため、EWRAMのウェイトステートを減らしてしまうとまだメモリ操作が完了していないということでしょう。 66 | 実際にEWRAMのオーバークロックが可能かをチェックする際は、オーバークロック後にEWRAMに書き込んだデータを読み出してみて、書き込んだデータと読み出したデータが一致するかどうかを確認するという手法がよく使われます。 67 | ``` 68 | -------------------------------------------------------------------------------- /timer.md: -------------------------------------------------------------------------------- 1 | # ⏰ タイマー 2 | 3 | GBAはタイマーを4つ持っています。タイマーは 16.78MHz のクロックで動作し、それぞれのタイマーは 16bit のカウンタを持っています。 4 | 5 | Timer0 と Timer1 はPCM音源のサンプルレートのために使われます。 6 | 7 | ## 制御レジスタ - TMnCNT (R/W) 8 | 9 | ``` 10 | 0x0400_0100 - TM0CNT 11 | 0x0400_0104 - TM1CNT 12 | 0x0400_0108 - TM2CNT 13 | 0x0400_010C - TM3CNT 14 | ``` 15 | 16 | `TMnCNT.0-15`は `TMnCNT_L`、`TMnCNT.16-31`は `TMnCNT_H` と呼ぶ場合もあります。 17 | 18 | ``` 19 | Bit 20 | 0-15 タイマーカウンタ or リロード値 21 | R: 現在のカウンタの値を読み取る 22 | W: リロード値を設定(ただし現在のカウンタの値には直接影響しない) 23 | 16-17 カウント周期 (0=1クロックごとに, 1=64, 2=256, 3=1024) 24 | 18 カスケード機能 (0=Off, 1=On) 25 | 19-21 不使用 26 | 22 カウンタのオーバーフロー時にIRQを発生させるか (0=無効, 1=有効) 27 | 23 タイマーON/OFF (0=OFF, 1=ON) 28 | 24-31 不使用 29 | ``` 30 | 31 | カスケード機能は下位のタイマーがオーバーフローしたときに、上位のタイマーの値がインクリメントされるという機能です。例えば、`TM2CNT.18`をセットしてTimer2のカスケード機能を有効にすると、Timer1がオーバーフローしたときにTimer2のカウンタがインクリメントされます。カスケード機能を使うとそのタイマー自身(この例ではTimer2)は周期(bit0-1で設定)によってインクリメント**されない**ようになっています。Timer0は最も下位のタイマーなので、カスケード機能はTimer0には使用できません。 32 | 33 | リロード値(`TMnCNT.0-15`)は 34 | 35 | - タイマーオーバーフロー時 36 | - タイマーがONになったとき(`TMnCNT.23`が`0`から`1`になったとき) 37 | 38 | にカウンタにセットされる値です。 39 | -------------------------------------------------------------------------------- /unpredictable.md: -------------------------------------------------------------------------------- 1 | # 特殊な挙動 2 | 3 | [GBA Unpredictable Things](https://problemkaputt.de/gbatek.htm#gbaunpredictablethings)より 4 | 5 | ## BIOS領域からの読み込み(0x0000_0000..0000_3FFF) 6 | 7 | BIOSは読み出し処理に対して保護されています。 8 | 9 | GBAは、プログラムカウンタがBIOSエリア内にある場合に限り、オペコードやデータを読み出すことができます。 10 | 11 | プログラムカウンタがBIOSエリアにない場合に読み出しを行うと、正常にフェッチされた最新のBIOSオペコードが返ってきます。 12 | 13 | 例えば、 14 | 15 | - 電源ON直後やソフトリセット直後は`[00DCh+8]`のオペコード 16 | - IRQハンドラの処理中は`[0134h+8]`のオペコード 17 | - IRQ終了後は`[013Ch+8]`のオペコード 18 | - SWIの処理中は`[0188h+8]`のオペコード 19 | 20 | が帰ってきます。 21 | 22 | ## 不使用メモリ領域からの読み込み (0x0000_4000..01FF_FFFF, 0x1000_0000..FFFF_FFFF) 23 | 24 | Accessing unused memory at 00004000h-01FFFFFFh, and 10000000h-FFFFFFFFh (and 02000000h-03FFFFFFh when RAM is disabled via Port 4000800h) returns the recently pre-fetched opcode. 25 | 26 | For ARM code this is simply: 27 | 28 | ``` 29 | WORD = [$+8] 30 | ``` 31 | 32 | For THUMB code the result consists of two 16bit fragments and depends on the address area and alignment where the opcode was stored. 33 | 34 | For THUMB code in Main RAM, Palette Memory, VRAM, and Cartridge ROM this is: 35 | 36 | ``` 37 | LSW = [$+4], MSW = [$+4] 38 | ``` 39 | 40 | For THUMB code in BIOS or OAM (and in 32K-WRAM on Original-NDS (in GBA mode)): 41 | 42 | ``` 43 | LSW = [$+4], MSW = [$+6] ; for opcodes at 4-byte aligned locations 44 | LSW = [$+2], MSW = [$+4] ; for opcodes at non-4-byte aligned locations 45 | ``` 46 | 47 | For THUMB code in 32K-WRAM on GBA, GBA SP, GBA Micro, NDS-Lite (but not NDS): 48 | 49 | ``` 50 | LSW = [$+4], MSW = OldHI ; for opcodes at 4-byte aligned locations 51 | LSW = OldLO, MSW = [$+4] ; for opcodes at non-4-byte aligned locations 52 | ``` 53 | 54 | Whereas OldLO/OldHI are usually: 55 | 56 | ``` 57 | OldLO=[$+2], OldHI=[$+2] 58 | ``` 59 | 60 | Unless the previous opcode's prefetch was overwritten; that can happen if the previous opcode was itself an LDR opcode, ie. if it was itself reading data: 61 | 62 | ``` 63 | OldLO=LSW(data), OldHI=MSW(data) 64 | ``` 65 | 66 | Theoretically, this might also change if a DMA transfer occurs. 67 | 68 | Note: Additionally, as usually, the 32bit data value will be rotated if the data address wasn't 4-byte aligned, and the upper bits of the 32bit value will be masked in case of LDRB/LDRH reads. 69 | 70 | Note: The opcode prefetch is caused by the prefetch pipeline in the CPU itself, not by the external gamepak prefetch, ie. it works for code in ROM and RAM as well. 71 | 72 | ## 8bitデータをビデオメモリに書き込んだときの挙動 73 | 74 | Video Memory (BG, OBJ, OAM, Palette) can be written to in 16bit and 32bit units only. Attempts to write 8bit data (by STRB opcode) won't work: 75 | 76 | Writes to OBJ (6010000h-6017FFFh) (or 6014000h-6017FFFh in Bitmap mode) and to OAM (7000000h-70003FFh) are ignored, the memory content remains unchanged. 77 | 78 | Writes to BG (6000000h-600FFFFh) (or 6000000h-6013FFFh in Bitmap mode) and to Palette (5000000h-50003FFh) are writing the new 8bit value to BOTH upper and lower 8bits of the addressed halfword, ie. "[addr AND NOT 1]=data*101h". 79 | 80 | ## Using Invalid Tile Numbers 81 | 82 | In Text mode, large tile numbers (combined with a non-zero character base setting in BGnCNT register) may exceed the available 64K of BG VRAM. 83 | 84 | On GBA and GBA SP, such invalid tiles are displayed as if the character data is filled by the 16bit BG Map entry value (ie. as vertically striped tiles). Above applies only if there is only one BG layer enabled, with two or more layers, things are getting much more complicated: tile-data is then somehow derived from the other layers, depending on their priority order and scrolling offsets. 85 | 86 | On NDS (in GBA mode), such invalid tiles are displayed as if the character data is zero-filled (ie. as invisible/transparent tiles). 87 | 88 | ## SRAM領域への16/32bitのアクセス 89 | 90 | **Read** 91 | 92 | アドレスから8bitの値を取得しますが、その値には `0x0101`(LDRH),`0x01010101`(LDR) が掛け算されています。 93 | 94 | **Write** 95 | 96 | 対象のアドレスに対してのみ(つまり1バイト分)書き込みを行います。 97 | 98 | 書き込みたい値を`val`(16 or 32bit)、対象のアドレスを4で割った余りを`x`とすると`val ROR (x*8)`が対象のアドレスに書き込まれます。 99 | 100 | -------------------------------------------------------------------------------- /video/bg/control.md: -------------------------------------------------------------------------------- 1 | # BG制御レジスタ 2 | 3 | BGモードによっては、タイルやマップの使い方を指定するため、BG制御レジスタを設定します。 4 | 5 | 背景はBG0~BG3の4枚があり、それぞれに対応するBG制御レジスタがあります。 6 | 7 | ``` 8 | 0x0400_0008 - BG0CNT - BG0制御レジスタ (R/W) (BGモード 0,1 のみ) 9 | 0x0400_000a - BG1CNT - BG1制御レジスタ (R/W) (BGモード 0,1 のみ) 10 | 0x0400_000c - BG2CNT - BG2制御レジスタ (R/W) (BGモード 0,1,2 のみ) 11 | 0x0400_000e - BG3CNT - BG3制御レジスタ (R/W) (BGモード 0,2 のみ) 12 | ``` 13 | 14 | ``` 15 | Bit 0-1 BG優先度(0~3, 0=最高) 16 | 優先度が同じBGが複数ある場合はBG0 -> BG3の順に優先(つまりBG0が最優先) 17 | Bit 2-3 タイルデータ(16KB単位)を置くブロック 18 | 0: 0x0600_0000 19 | 1: 0x0600_4000 20 | 2: 0x0600_8000 21 | 3: 0x0600_C000 22 | Bit 4-5 未使用(0b00) 23 | Bit 6 モザイク (0=無効, 1=有効) 24 | Bit 7 カラーモード 25 | 0: 16/16(16色のパレットが16個) 26 | 1: 256/1(256色のパレットが1個) 27 | Bit 8-12 マップデータ(2KB単位)を置くブロック (0-31) 28 | n: 0x0600_0000 + (0x800)*n 29 | Bit 13 画面オーバーフロー時の挙動 (BG2,3のみ) 30 | 0: Transparent 31 | 1: Wraparound 32 | Bit 14-15 画面サイズ 33 | 通常時: 34 | 0: 256×256 px 35 | 1: 512x256 px 36 | 2: 256x512 px 37 | 3: 512x512 px 38 | 伸縮回転モード時: 39 | 0: 128x128 px 40 | 1: 256x256 px 41 | 2: 512x512 px 42 | 3: 1024x1024 px 43 | ``` 44 | 45 | タイルモードでは、VRAMをタイルデータ(16KB単位)とマップデータ(2KB単位)で共有しますので、各データサイズを計算して、アドレスがが互いに重ならないように注意する必要があります。 46 | 47 | たとえばタイルブロック番号2、マップ番号16のようにしてはいけません。 48 | -------------------------------------------------------------------------------- /video/bg/mode/README.md: -------------------------------------------------------------------------------- 1 | # BGモード 2 | 3 | 背景(BG)に関して、GBAは6つのモードが存在しています。 4 | 5 | 各モードは Mode0, Mode1, ... Mode5 と呼ばれ、モードごとに 6 | 7 | - 利用できる背景レイヤの枚数と色数 8 | - レンダリングの特性 9 | 10 | が異なります。 11 | 12 | モードの切り替えは[DISPCNT](../../control.md)で設定します。 13 | 14 | さらに Mode0-2 はタイル単位の描画を行うのでタイルモード(テキストモード)、Mode3-5はビットマップに基づいた描画を行うのでビットマップモードと呼ばれます。 15 | 16 | ## Mode0,1,2 17 | 18 | [タイルモード](./tile/README.md)を参照してください。 19 | 20 | ## Mode3,4,5 21 | 22 | [ビットマップモード](./bitmap.md)を参照してください。 23 | -------------------------------------------------------------------------------- /video/bg/mode/bitmap.md: -------------------------------------------------------------------------------- 1 | # Mode3,4,5 2 | 3 | Mode3-5はビットマップに基づいた描画を行うのでビットマップモードと呼ばれています。 4 | 5 | タイルモード(Mode0-2)と違って、BGレイヤという概念はありません。 6 | 7 | この形式はVRAMに値を書き込むと、それがそのまま画面に反映されます。 8 | 9 | ビットマップ形式ではVRAMのうち80KBを背景描画に使うので、OBJタイルデータの格納に使えるのは残りの16KBだけになります。 10 | 11 |
12 | ビットマップモードを利用しているゲーム 13 | 14 | ``` 15 | ビットマップモードは低速なので、GBAのほとんどのゲームはタイルモードを使用しています。 16 | ほとんどの場合、ビットマップモードが使われるのは、1枚の画像を表示する用途や3Dゲームのような動的な画面を必要とするゲーム(V-Rally3など)です。 17 | 18 | 参考: https://www.coranac.com/tonc/text/bitmaps.htm 19 | ``` 20 |
21 | 22 | ## Mode3 23 | 24 | ``` 25 | 0x0600_0000..0601_3FFF: 80KBのフレームバッファ0 (使えるのは75KB) 26 | 0x0601_4000..0601_7FFF: 16KBでOBJタイルデータを格納 27 | ``` 28 | 29 | フレームバッファ0に書き込んだ2バイトの色データ(RGB555)がそのまま画面の対応するピクセルに出力されます。RGB555を自由に指定できるので、最大同時発色数は32768色です。 30 | 31 | 最初の480バイトは最初の行(1行=240pxなので480バイト)で、次の480バイトは次の行です。以後も同様です。 32 | 33 | 画面全体を描画するのに必要なメモリ領域は76800バイト(=75KB: `0x0600_0000..0601_2bff`)で、あらかじめ用意された80KBのフレームバッファのほとんどを使用します。 34 | 35 | ```go 36 | type RGB555 uint16 // 0b0BBBBBGGGGGRRRRR 37 | 38 | // 240 * 160 * 2 = 76800 bytes = 75KB 39 | var FrameBuffer0 [160][240]RGB555 = { 40 | { /* y=0 */ }, 41 | { /* y=1 */ }, 42 | ... 43 | { /* y=159 */ }, 44 | } 45 | ``` 46 | 47 | ## Mode4 48 | 49 | ``` 50 | 0x0600_0000..0600_9FFF: 37.5KBのフレームバッファ0 51 | 0x0600_A000..0601_3FFF: 37.5KBのフレームバッファ1 52 | 0x0601_4000..0601_7FFF: 16KBでOBJタイルデータを格納 53 | ``` 54 | 55 | Mode3と違って、256色のBGパレットの色番号(1バイト、0..255)で対応するピクセルの色を指定します。 56 | 57 | 1ピクセルあたりのバイト数が1バイトで済みますが、最大同時発色数は256色です。 58 | 59 | 色番号0は透明色として扱われ、OBJをビットマップの後ろに表示することも可能です。 60 | 61 | 最初の240バイトが1行目、次の240バイトが2行目となっており以後も同様です。 62 | 63 | このモードでは画面全体をカバーするのに必要なフレームバッファが37.5KBだけで済み、VRAM全体で2つのフレームバッファを使用することができます。 64 | 65 | 画面にどちらのフレームバッファを表示するかは、[DISPCNT.4](../../control.md)で指定します。 66 | 67 | ## Mode5 68 | 69 | ``` 70 | 0x0600_0000..0600_9FFF: 40KBのフレームバッファ0 71 | 0x0600_A000..0601_3FFF: 40KBのフレームバッファ1 72 | 0x0601_4000..0601_7FFF: 16KBでOBJタイルデータを格納 73 | ``` 74 | 75 | Mode3同様、直接RGB555をフレームバッファに書き込むことで画面を描画します。 76 | 77 | Mode3と違って、Mode5のフレームバッファは `160x128px`分しかないですが、2つのフレームバッファを使うことができます。 78 | 79 | GBAの解像度は `240x160px`なので`160x128px`のフレームバッファの内容はハードウェアによって自動的に`240x160px`に拡大されて画面に表示されます。 80 | -------------------------------------------------------------------------------- /video/bg/mode/tile/README.md: -------------------------------------------------------------------------------- 1 | # Mode0,1,2 2 | 3 | Mode0-2 は8x8タイル単位の描画を行うのでタイルモード(テキストモード)と呼ばれています。 4 | 5 | ## タイルモード(Mode0-2)の共通の仕様 6 | 7 | ``` 8 | 0x0600_0000..0600_FFFF: 64KBでBGマップとBGタイルデータで共有 9 | 0x0601_0000..0601_7FFF: 32KBでOBJタイルデータが格納 10 | ``` 11 | 12 | VRAMのメモリ空間のうち、64KBを[BGタイルデータ](tiledata.md)と[BGマップ](bgmap.md)で共有します。それぞれのリソースがどのアドレスを使うかは`BGnCNT`レジスタで設定します。 13 | 14 | ## Mode0 15 | 16 | BG0-3 の4枚のBGレイヤが使えます。各BGレイヤの性能は同じです。 17 | 18 | ``` 19 | BG0-3: 20 | Color: 4bpp or 8bpp 21 | Size: 32x32 or 32x64 or 64x32 or 64x64 タイル 22 | Scalerot: 不可能 23 | Tile: 1024種類まで 24 | ``` 25 | 26 | ## Mode1 27 | 28 | BG0-2 の3枚のBGレイヤが使えます。 29 | 30 | ``` 31 | BG0-1: 32 | Color: 4bpp or 8bpp 33 | Size: 32x32 or 32x64 or 64x32 or 64x64 タイル 34 | Scalerot: 不可能 35 | Tile: 1024種類まで 36 | BG2: 37 | Color: 8bpp 38 | Size: 16x16 ~ 128x128 39 | Scalerot: 可能 40 | Tile: 256種類まで 41 | ``` 42 | 43 | ## Mode2 44 | 45 | BG2-3 の2枚のBGレイヤが使えます。 46 | 47 | ``` 48 | BG2-3: 49 | Color: 8bpp 50 | Size: 16x16 ~ 128x128 51 | Scalerot: 可能 52 | Tile: 256種類まで 53 | ``` 54 | -------------------------------------------------------------------------------- /video/bg/mode/tile/bgmap.md: -------------------------------------------------------------------------------- 1 | # BGマップ 2 | 3 | GBAは96KBのVRAMを`0x0600_0000-0x0601_7fff`に持っています。VRAMの使い方は[DISPCNT](../../../control.md)で設定するBGモードによって異なります。 4 | 5 | BGマップは、8x8のタイルデータを画面上にどのように配置していくかを表すデータです。背景マップや、タイルマップとも呼ばれます。 6 | 7 | タイルモード(Mode0-2)でのみ利用します。 8 | 9 | BGマップは、BGレイヤが伸縮回転するかしないかで内容が異なります。 10 | 11 | ## テキストモード(伸縮回転無し) 12 | 13 | 各エントリ(1タイルの配置を担当)あたり2バイトです。 14 | 15 | Specifies the tile number and attributes. Note that BG tile numbers are always specified in steps of 1 (unlike OBJ tile numbers which are using steps of two in 256 color/1 palette mode). 16 | 17 | bit | 内容 18 | ---- | ---- 19 | 0-9 | タイル番号 (0-1023) (a bit less in 256 color mode, because there'd be otherwise no room for the bg map) 20 | 10 | X反転 (0=しない, 1=反転) 21 | 11 | Y反転 (0=しない, 1=反転) 22 | 12-15 | パレット番号 (0-15) (256色/1パレットのときは使用しない) 23 | 24 | BGマップは、32タイル×32タイル(256px×256px)が1単位で、大きさは 32×32×2 = 2KBとなります。これはマップブロックの大きさと一致します。 25 | 26 | もちろんBGのサイズによっては複数のBGマップが必要になることもあります。 例えば512px×512pxのBGが必要な場合はBGマップが4つ必要になります。 この場合BGマップが配置されるマップブロックは連続している必要があります。 27 | 28 | ## 伸縮回転モード 29 | 30 | 各エントリ(1タイルの配置を担当)あたり1バイトです。 31 | 32 | 伸縮回転モードでは256タイルのみが利用可能で、XY方向の反転属性はなく色深度も256色/1パレットのみ利用可能です。 33 | 34 | bit | 内容 35 | ---- | ---- 36 | 0-7 | タイル番号 (0-255) 37 | 38 | BGマップの大きさとVRAMのどこに配置されるかは、BG0-3それぞれ別々の値を取ることが可能です。 39 | 40 | BGマップのサイズの設定はBG制御レジスタのbit14-15でおこないます。 41 | 42 | VRAMの配置場所の設定はBG制御レジスタのbit8-12でおこないます。 43 | -------------------------------------------------------------------------------- /video/bg/mode/tile/tiledata.md: -------------------------------------------------------------------------------- 1 | # タイルデータ 2 | 3 | **キャラクタデータ** や BGタイルデータ とも呼ばれます。 タイルモードにおける描画単位です。 4 | 5 | 各タイルは `8×8px` です。 6 | 7 | 色深度(色を表すのに利用するbit数)は 4bit か 8bit のどちらかを[BGnCNT](../../control.md)で選択できます。 8 | 9 | ### 4bit (16色/16パレット) 10 | 11 | 1pxあたり4bit(0.5バイト)なので `1タイル = 64px = 64×0.5 = 32バイト`です。 12 | 13 | 最初の4バイトはタイルの最上段の行のためのものです。その次の4バイトは次の行となり、以後同様です。 14 | 15 | 各バイトは2つのドットを表し、下位4ビットが**左ドット**の色、上位4ビットが**右ドット**の色を定義します。 16 | 17 | ### 8bit (256色/1パレット) 18 | 19 | `1タイル = 64バイト`です。 20 | 21 | 4bitと同様に最初の8バイトが最初の行に対応し、その後の行も同様です。 22 | 23 | 各バイトは、各ドットのパレットエントリを選択します。 24 | -------------------------------------------------------------------------------- /video/bg/scalerot.md: -------------------------------------------------------------------------------- 1 | # BG伸縮回転 2 | 3 | 英語では、`Scale and Rotation` なので略して `scalerot` と呼ばれることも多いです。また数学的にはアフィン変換とも呼ばれます。 4 | 5 | ## オフセットレジスタ 6 | 7 | 伸縮回転とビットマップモードでは、BGスクロールレジスタとして、(テキストモードの)`BGnOFS`の代わりにこちらが使用されます。 8 | 9 | BGスクロールレジスタに入っている値は、伸縮回転とビットマップモードでは無視されます。 10 | 11 | ``` 12 | 0x0400_0028/0x0400_002c - BG2X/BG2Y - BG2 X/YオフセットX(0-27bit) (W) 13 | 0x0400_0038/0x0400_003c - BG3X/BG3Y - BG3 X/YオフセットX(0-27bit) (W) 14 | ``` 15 | ``` 16 | Bit Expl. 17 | 0-7 小数部分 (8 bits) 18 | 8-26 整数部分 (19 bits) 19 | 27 符号 (1 bit) 20 | 28-31 不使用 21 | ``` 22 | 23 | 例えば、0x12を設定したい時は、分数部分は0x00、整数部分は0x12にしたいのでレジスタには `0x12 << 8` を格納することになります。 24 | 25 | 符号付きの32bit値を上記のレジスタに書き込むことができますが、このとき最上位bitは無視され、値は28bitに切り捨てられます。 26 | 27 | ### 内部レジスタについて 28 | 29 | 上記の基準点(`BGnX/Y`)は、VBlankの間に自動的に内部レジスタにコピーされ、最初の走査線の原点を指定します。内部レジスタは、各スキャンラインの後にdmxとdmy(PBとPD)によってインクリメントされます。 30 | 31 | VBlank期間外に`BGnX/Y`を変更すると即座に内部レジスタにコピーされます。 32 | 33 | ### 実際のオフセット 34 | 35 | `BGnX/BGnY`は、格納した値がそのまま画面上のBGのオフセットになるのでなく、後述の伸縮回転パラメータに影響されます。 36 | 37 | BGが1/10に縮小される場合は、`BGnX/BGnY`にセットした値の1/10だけ画面上で移動することになります。 38 | 39 | また、BGが回転している場合は、回転したあとのBGの上下左右を基準に画像が移動します。 40 | 41 | `BGnX/BGnY`に格納する値の計算式は以下のようになります。 42 | 43 | ```c 44 | bgx = x1 - α*cos(θ-β)*hzoom 45 | bgy = y1 - α*(-sin(θ-β))*vzoom 46 | ``` 47 | 48 | 変数 | 内容 49 | -- | -- 50 | bgx, bgy | BGオフセットレジスタ 51 | x1, y1 | BG面での回転の中心座標(x1,y1) 52 | hzoom, vzoom | 横・縦の拡大率 53 | θ | 回転の角度 54 | α | (0,0)から(x1,y1)までの長さ α = sqrt(x1\*x1 + y1\*y1) 55 | β | (0,0)から(x1,y1)までの角度 β = atan2(y1,x1) 56 | 57 | ## 伸縮回転パラメータ 58 | 59 | ``` 60 | 0x0400_0020 - BG2PA - BG2伸縮回転パラメータA (W) 61 | 0x0400_0022 - BG2PB - BG2伸縮回転パラメータB (W) 62 | 0x0400_0024 - BG2PC - BG2伸縮回転パラメータC (W) 63 | 0x0400_0026 - BG2PD - BG2伸縮回転パラメータD (W) 64 | 65 | 0x0400_0030 - BG3PA - BG3伸縮回転パラメータA (W) 66 | 0x0400_0032 - BG3PB - BG3伸縮回転パラメータB (W) 67 | 0x0400_0034 - BG3PC - BG3伸縮回転パラメータC (W) 68 | 0x0400_0036 - BG3PD - BG3伸縮回転パラメータD (W) 69 | ``` 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
bit1514-87-0
内容符号整数部分 (7 bits)分数部分 (8 bits)
89 | 90 | 伸縮回転パラメータの4つの数値(PA,PB,PC,PD)を組み合わせることで、伸縮や回転などさまざまな効果を出すことができます。 91 | 92 | GBAでのアフィン変換は以下の行列を座標に対してかけることで行われます。 93 | 94 | ``` 95 | [PA, PB] [cos(θ)/Sx, -sin(θ)/Sx] 96 | [PC, PD] = [sin(θ)/Sy, cos(θ)/Sy] 97 | ``` 98 | 99 | - `θ`: 回転角度 100 | - `Sx, Sy`: 拡大倍率 101 | 102 | 拡大倍率が逆数をとることに注意してください。 103 | 104 | ### 行列の例 105 | 106 | 画像を2倍の大きさに拡大する場合は、 107 | 108 | ``` 109 | [1/2 * 256, 0] 110 | [0, 1/2 * 256] 111 | ``` 112 | 113 | 画像をX方向に2倍、Y方向にはそのままの大きさにする場合は、 114 | 115 | ``` 116 | [1/2 * 256, 0] 117 | [0, 1 * 256] 118 | ``` 119 | 120 | 画像を60度回転させる場合は、 121 | 122 | ``` 123 | [cos(π/3), -sin(π/3)] 124 | [sin(π/3), cos(π/3)] 125 | 126 | ↓ 127 | 128 | [0.9921875 * 256, -0.8660254 * 256] 129 | [0.8660254 * 256, 0.9921875 * 256] 130 | ``` 131 | 132 | となります。 133 | 134 | 画像をX方向に2倍、Y方向にはそのままの大きさにして、60度回転させるのを同時にやりたい場合には 135 | 136 | ``` 137 | [1/2, 0] [0.9921875, -0.8660254] [256, 0] 138 | [0, 1] * [0.8660254, 0.9921875] * [0, 256] 139 | 140 | ↓ 141 | 142 | [1/2 * 0.9921875 * 256, 1/2 * (-0.8660254) * 256] 143 | [ 0.8660254 * 256, 0.9921875 * 256] 144 | 145 | ↓ 146 | 147 | [127, 110.8512] 148 | [221.7025, 254] 149 | ``` 150 | 151 | となります。 152 | 153 | ### はみでた場合 154 | 155 | 変換の結果、画像がBGの外にはみ出てしまう場合の挙動はBGモードによってことなります。 156 | 157 | BGモードが1,2のときは、[BG2CNT,BG3CNT](control.md)のbit13で、無視するかwrap(1周)するか指定することができます。 158 | 159 | BGモードが3,4,5のときははみでた部分は無視されます。 160 | 161 | -------------------------------------------------------------------------------- /video/bg/scroll.md: -------------------------------------------------------------------------------- 1 | # 背景スクロール 2 | 3 | ## オフセットレジスタ 4 | 5 | ### 0x0400_0010 - BG0HOFS - BG0 Xオフセット & 0x0400_0012 - BG0VOFS - BG0 Yオフセット (W) 6 | 7 | - BG0HOFS = BG0 の X方向(Horizontal) のオフセット(OFS) 8 | - BG0VOFS = BG0 の Y方向(Vertical) のオフセット(OFS) 9 | 10 | bit | 内容 11 | ---- | ---- 12 | 0-8 | オフセット(0-511) 13 | 9-15 | 未使用 14 | 15 | BG0背景レイヤーの左上のピクセルの座標を指定します。 16 | 17 | ![offset](../../images/scroll.jpg) 18 | 19 | ### 0x0400_0014 - BG1HOFS - BG1 Xオフセット & 0x0400_0016 - BG1VOFS - BG1 Yオフセット (W) 20 | 21 | BG1背景レイヤーの左上のピクセルの座標を指定します。 22 | 23 | ### 0x0400_0018 - BG2HOFS - BG2 Xオフセット & 0x0400_001a - BG2VOFS - BG2 Yオフセット (W) 24 | 25 | BG2背景レイヤーの左上のピクセルの座標を指定します。 26 | 27 | ### 0x0400001c - BG3HOFS - BG3 Xオフセット && 0x0400001e - BG3VOFS - BG3 Yオフセット (W) 28 | 29 | BG3背景レイヤーの左上のピクセルの座標を指定します。 30 | 31 | ## 補足 32 | 33 | 上記のBGオフセットレジスタは、テキストモードでのみ、つまりBGモード0の全レイヤ(BG0-3)とBGモード1の最初の2つのレイヤ(BG0-1)に使用されます。 34 | 35 | 伸縮回転とビットマップモードでは、上記のレジスタは無視されます。その代わりに、[BG の伸縮回転用のオフセットレジスタ](scalerot.md#オフセットレジスタ)を変更することで、画面をスクロールさせることができます。 36 | 37 | -------------------------------------------------------------------------------- /video/blend.md: -------------------------------------------------------------------------------- 1 | # ブレンド 2 | 3 | ブレンドはBGやスプライトから2つのグループを選択し、一定の割合で色を混ぜて表示するアルファブレンドと、白か黒を一定の割合で混ぜて表示するフェードがあります 4 | 5 | ## 例 6 | 7 | **アルファブレンド** 8 | 9 | ロックマンゼロのオープニングムービーでゴーレムのレーザー(緑)とレジスタンスのオイル(赤)部分の重なりにアルファブレンドが使用されています。 10 | 11 | 12 | 13 | **白フェード** 14 | 15 | ロックマンエグゼ2の起動時、真っ白な画面からカプコンロゴが徐々にフェードインしてくる際に白フェードが使用されています。 16 | 17 | 18 | 19 | **黒フェード** 20 | 21 | ロックマンエグゼ2のカプコンロゴ表示後、カプコンロゴが徐々にフェードアウトする際に黒フェードが使用されています。 22 | 23 | 24 | 25 | ## 0x0400_0050 - BLDCNT - ブレンド制御レジスタ (R/W) 26 | 27 | bit | 内容 28 | ---- | ---- 29 | 0 | BG0を1stターゲットに 30 | 1 | BG1を1stターゲットに 31 | 2 | BG2を1stターゲットに 32 | 3 | BG3を1stターゲットに 33 | 4 | OBJを1stターゲットに (Top-most OBJ pixel) 34 | 5 | BD(Backdrop)を1stターゲットに 35 | 6-7 | 特殊効果の種類 (後述) 36 | 8 | BG0を2ndターゲットに 37 | 9 | BG1を2ndターゲットに 38 | 10 | BG2を2ndターゲットに 39 | 11 | BG3を2ndターゲットに 40 | 12 | OBJを2ndターゲットに (Top-most OBJ pixel) 41 | 13 | BD(Backdrop)を2ndターゲットに 42 | 14-15 | 未使用 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
Addr7-6543210
0x0400_0050特殊効果BD/1stOBJ/1stBG3/1stBG2/1stBG1/1stBG0/1st
0x0400_0051不使用(0)BD/2ndOBJ/2ndBG3/2ndBG2/2ndBG1/2ndBG0/2nd
80 | 81 | 第1ターゲットと第2ターゲットに、どのBGやスプライトを割り当てるかの設定です。両方のグループに同じものを割り当てることもできます。 82 | 83 | BG0-BG3はその番号のBG、OBJはスプライトすべて、BDは背景(詳細は不明)です。 84 | 85 | フェードモードのときは第1ターゲットに設定したものだけが対象になります。 86 | 87 | スプライトはスプライト同士の色の混ぜ合わせは行われないようです。 88 | 89 | すべてのレイヤーが第1ターゲットと第2ターゲットの両方を選択することも可能で、 その場合は最上位の画素が第1ターゲットとなり、 次の下位の画素が第2ターゲットとなります。 90 | 91 | ### 特殊効果(bit6-7) 92 | 93 | - 0: 特殊効果なし 94 | - 1: 2つのグループの色を混ぜ合わせるアルファブレンド 95 | - 2: 白フェード。グループと白色を一定の割合で混ぜます 96 | - 3: 黒フェード。グループと黒色を一定の割合で混ぜます 97 | 98 | ## 0x0400_0052 - BLDALPHA - アルファブレンド (R/W) 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 |
bit1514131211109876543210
内容不使用EVB不使用EVA
132 | 133 | ``` 134 | EVA: 第1ターゲット色割合 (0..16 = 0/16..16/16, 17..31=16/16) 135 | EVB: 第2ターゲット色割合 (0..16 = 0/16..16/16, 17..31=16/16) 136 | ``` 137 | 138 | 各ピクセルのRGBは次のように計算されます。 139 | 140 | ``` 141 | R = min(31, R1*EVA + R2*EVB) 142 | G = min(31, G1*EVA + G2*EVB) 143 | B = min(31, B1*EVA + B2*EVB) 144 | ``` 145 | 146 | ## 0x0400_0054 - BLDY - フェード (W) 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 |
bit31-54-0
内容不使用EVY
164 | 165 | ``` 166 | EVY: フェード率 (0..16 = 0/16..16/16, 17..31=16/16) 167 | ``` 168 | 169 | 各ピクセルのRGBは次のように計算されます。 170 | 171 | **白フェード** 172 | 173 | BLDCNTのbit6-7が2(白フェード)のときは次のようになります。 174 | 175 | ``` 176 | R = R1 + (31-R1)*EVY 177 | G = G1 + (31-G1)*EVY 178 | B = B1 + (31-B1)*EVY 179 | ``` 180 | 181 | どれも255に近づいているので明るくなり白に近づいています。 182 | 183 | **黒フェード** 184 | 185 | BLDCNTのbit6-7が3(黒フェード)のときは次のようになります。 186 | 187 | ``` 188 | R = R1 - (R1)*EVY 189 | G = G1 - (G1)*EVY 190 | B = B1 - (B1)*EVY 191 | ``` 192 | 193 | ## 半透明のOBJ 194 | 195 | OAMで半透明と定義されているOBJは、常に第1ターゲットとして選択され、常にアルファブレンドが適用されます。これはBLDCNT.4とBLDCNT.6-7に関係なく適用されます。 196 | 197 | BLDCNTレジスタは、OBJ(または 他のBG/BDレイヤー)に対してフェードを行うために使用することもできます。 198 | 199 | しかし、半透明のOBJピクセルが第2ターゲットのピクセルと重なっている場合、半透明なOBJに対するアルファブレンドが優先され、(第1ターゲットも第2ターゲットも)フェードは行われません。 200 | 201 | ## 補足 202 | 203 | アルファブレンドは、OBJ-to-BGやBG-to-OBJには使用できますが、OBJ-to-OBJには使用できません。 204 | -------------------------------------------------------------------------------- /video/dispcnt.md: -------------------------------------------------------------------------------- 1 | # 0x0400_0000 - DISPCNT - LCD制御レジスタ (R/W) 2 | 3 | bit | 内容 4 | ---- | ---- 5 | 0-2 | BGモード (0-5=Mode0-5, 6-7=無効) 6 | 3 | CGBモード (0=GBA, 1=CGB, BIOSオペコードで設定されます) 7 | 4 | フレーム選択 (0-1=Frame0-1) (BGモードが4,5のときのみ) 8 | 5 | HBlank中にOAMにアクセス可能か (1=可能) 9 | 6 | [OBJマッピングモード](sprite.md#objのマッピングモード) (0=2次元, 1=1次元) 10 | 7 | FBlank (1=有効 その間はVRAM,Palette,OAMに高速アクセス可能) 11 | 8 | BG0有効フラグ (1=On) 12 | 9 | BG1有効フラグ (1=On) 13 | 10 | BG2有効フラグ (1=On) 14 | 11 | BG3有効フラグ (1=On) 15 | 12 | OBJ有効フラグ (1=On) 16 | 13 | WIN0有効フラグ (1=On) 17 | 14 | WIN1有効フラグ (1=On) 18 | 15 | OBJWIN有効フラグ (1=On) 19 | 20 | 次のテーブルはBGモード0~5がどのような機能を持っているか表したものです。 21 | 22 | モード | 伸縮回転 | レイヤ | 画面サイズ | タイル | 色 | 属性 23 | ---- | ---- | ---- | ---- | ---- | ---- | ---- 24 | 0 | No | 0123 | 256x256..512x515 | 1024 | 16/16..256/1 | SFMABP 25 | 1 | Mixed | 012- | -- | -- | -- | -- 26 | 2 | Yes | --23 | 128x128..1024x1024 | 256 | 256/1 | S-MABP 27 | 3 | Yes | --2- | 240x160 | 1 | 32768 | --MABP 28 | 4 | Yes | --2- | 240x160 | 2 | 256/1 | --MABP 29 | 5 | Yes | --2- | 160x128 | 2 | 32768 | --MABP 30 | 31 | ``` 32 | 属性: 33 | S: Scrolling 34 | F: Flip 35 | M: Mosaic 36 | A: AlphaBlending 37 | B: Brightness 38 | P: Priority 39 | ``` 40 | 41 | BGモード0-2はタイルモード用です。BGモード3-5はビットマップモード用です。 42 | 43 | BGモード1は、BG0,BG1はBGモード0と同じ, BG2はBGモード2と同じ機能です。 44 | 45 | ビットマップモードでは 1つまたは2つのフレーム(バッファ)が存在します。2つのフレームが存在する場合は、どちらか1つを表示することができ、もう片方は背景に再描画することができます。 46 | 47 | ## FBlank(DISPCNT.7) 48 | 49 | FBlank(強制白塗り, Forced Blank)を有効にすると画面が真っ白になり、この間は、HBlank、VBlank以外でもVRAM、パレット、OAMにアクセスすることが可能になります。 50 | 51 | DISPCNT.5を有効にするとHBlank中にOAMにアクセス可能になりますが、[1行あたりに描画可能なスプライトの数](sprite.md#1行に同時に表示可能なスプライトの数)が減ることになります。 52 | 53 | ## (BG/OBJ)有効フラグ 54 | 55 | デフォルトではBG0-3有効フラグとOBJ有効フラグ(bit8-12)がBGとOBJの有効無効化に使われます。 56 | 57 | bit13-14を通してWindow0/1を有効にすると、特殊効果が適用され、BGとOBJは[ウィンドウ](window.md)の影響を受けます。 58 | 59 | ## フレーム選択 60 | 61 | BGモード4-5(ビットマップモード)では、2つのフレームのうちどちらか一方が表示され(bit4で選択)、バックグラウンドでもう一方のフレームを更新することができます。 62 | 63 | BGモード3では、利用できるフレームは1つのみです。 64 | 65 | BGモード0-2(タイルモード) では、BGマップ や BGキャラクタデータ のベースアドレスを変更することで、同様の効果を得ることができます。 66 | 67 | -------------------------------------------------------------------------------- /video/greenswp.md: -------------------------------------------------------------------------------- 1 | # 0x0400_0002 - GREENSWP - グリーンスワップ (R/W) 2 | 3 | > [!WARNING] 4 | > 信頼性低 5 | 6 | Normally, red green blue intensities for a group of two pixels is output as BGRbgr (uppercase for left pixel at even xloc, lowercase for right pixel at odd xloc). 7 | 8 | When the Green Swap bit is set, each pixel group is output as BgRbGr (ie. green intensity of each two pixels exchanged). 9 | 10 | bit | 内容 11 | ---- | ---- 12 | 0 | グリーンスワップ (0=Normal, 1=Swap) 13 | 1 | 未使用 14 | 15 | この機能は、最終的に生成される画像(つまり別々のBGとOBJレイヤを混合した後)に適用されるようです。 16 | 17 | 最終的には、他のディスプレイタイプ(他のピンアウトを持つ)のために意図されています。 18 | 19 | 通常のGBAハードウェアでは、面白い汚れの効果を生み出しているだけです。 20 | 21 | NDSのDISPCNTレジスタは32ビット(0x0400_0000...0x0400_0003)なので、NDSモードではグリーンスワップは存在しませんが、GBAモードではNDSはグリーンスワップをサポートしています。 22 | 23 | -------------------------------------------------------------------------------- /video/interrupt.md: -------------------------------------------------------------------------------- 1 | # 割り込みとステータス 2 | 3 | ## 0x0400_0004 - DISPSTAT - LCDステータス (R/W) 4 | 5 | 表示ステータスと割り込み制御に関するレジスタです。 6 | 7 | HBlankは、VBlank中の画面外のスキャンラインを含め、スキャンラインごとに1回発生します。 8 | 9 | bit | RW | 内容 10 | ---- | ---- | ---- 11 | 0 | R | V-Blankフラグ (1=VBlank) 12 | 1 | R | H-Blankフラグ (1=HBlank) 13 | 2 | R | V-Counterフラグ (1=Match) (set in selected line) 14 | 3 | RW | V-Blank割り込み有効フラグ (1=有効) 15 | 4 | RW | H-Blank割り込み有効フラグ (1=有効) 16 | 5 | RW | V-Counter割り込み有効フラグ (1=有効) 17 | 6 | R | 0, 不使用 18 | 7 | R | 0, 不使用 19 | 8-15 | RW | V-Count設定 (LYC) (0..227) 20 | 21 | VBlankフラグはVBlank期間であることを表すフラグで後述のスキャンラインが160~226のときにセットされます。227ではクリアされます。 22 | 23 | HBlankフラグはHBlank期間であることを表すフラグで、毎スキャンライン、フラグがトグルされます。 24 | 25 | V-Count設定(bit8-15)の値はゲームボーイのLYCとほぼ同じで、その値がVCOUNTレジスタの内容と同じであれば、V-Counterフラグがセットされ(bit2)、(bit5で有効になっていれば)割り込みがリクエストされます。 26 | 27 | 描画時間はわずか960サイクル(240×4)ですが、H-Blank期間は"0"で合計1006サイクルです。 28 | 29 | ## 0x0400_0006 - VCOUNT - スキャンライン (R) 30 | 31 | ゲームボーイのLYレジスタとほぼ同じで現在描画されているスキャンライン(画面の行)を示し、この値が(画面にない)160~227の範囲にあるときはVBlank期間であることを示しています。 32 | 33 | bit | RW | 内容 34 | ---- | ---- | ---- 35 | 0-7 | R | 現在のスキャンライン (LY) (0..227) 36 | 8 | R | 0, 不使用 37 | 9-15 | R | 0, 不使用 38 | 39 | -------------------------------------------------------------------------------- /video/mosaic.md: -------------------------------------------------------------------------------- 1 | # モザイク 2 | 3 | モザイク機能は、使用することを選択したBGやスプライト1個づつに対して、画像を `(縦 x 横)` の一定サイズで区切り、その部分を左上の色で塗りつぶすというものです。(色を混ぜるわけではありません) 4 | 5 | モザイク効果(`6x6`)を適用すると、`6x6`の範囲はすべて`(0, 0)`の色になるので、左から右のようになります。 6 | 7 | ![before](../images/bitmap.png)   ![after](../images/mosaic.png) 8 | 9 | ## モザイクの有効化 10 | 11 | モザイク機能は[BG制御レジスタ](./control.md)によって BG0-3 に対して個別に ON/OFF ができます。 12 | 13 | また[OAMのアトリビュート](./sprite.md#objアトリビュート0-rw)をいじることで OBJ0-127 に対しても個別で ON/OFF できます。 14 | 15 | ## 0x0400_004c - MOSAIC - モザイクサイズ (W) 16 | 17 | またこのMOSAICレジスタをすべて0に設定することでモザイク機能そのものを無効にすることができます。 18 | 19 | bit | 内容 20 | ---- | ---- 21 | 0-3 | BGモザイクサイズX - 1 22 | 4-7 | BGモザイクサイズY - 1 23 | 8-11 | OBJモザイクサイズX - 1 24 | 12-15 | OBJモザイクサイズY - 1 25 | 16-31 | 不使用 26 | 27 | 例: 先程の例のように6×6単位でモザイクを当てたい時は、BGモザイクサイズX、BGモザイクサイズYにそれぞれ5をセットすることで実現できます。 28 | 29 | 通常、モザイクピクセル(上の例なら6×6の左上のピクエル)は左上のピクセルの色となります。 30 | 31 | 場合によっては、領域の中央にあるピクセルの色を使った方が良いかもしれません。 これは背景をスクロールすることで得られるかもしれません。 32 | -------------------------------------------------------------------------------- /video/oam.md: -------------------------------------------------------------------------------- 1 | # OAM - スプライト属性メモリ 2 | 3 | OAMは`0x0700_0000-0700_03ff`にあります。 サイズは1KBです。 4 | 5 | このメモリ領域には、128個のOBJのそれぞれの位置、サイズ、色深度などの[スプライト](sprite.md)の使用に必要な属性(アトリビュート)が格納されています。さらに、32個のOBJに対する伸縮回転パラメータが格納されています。 6 | 7 | OAMは`OBJ0`から`OBJ127`まで分けられています。各エントリは2バイトのプロパティが3つあるので6バイトですが、間にOBJの伸縮回転パラメータ(`ParamN`)が格納されています。**これらはOAMのOBJとは結びついていません。** 8 | 9 | ``` 10 | Offset | Memory 11 | ------------------ 12 | 0 +--------+ 13 | | OBJ0 | 14 | 6 | ------ | 15 | | Param0 | 16 | 8 | ------ | 17 | | OBJ1 | 18 | 14 | ------ | 19 | | Param1 | 20 | 16 | ------ | 21 | | OBJ2 | 22 | 22 | ------ | 23 | | ... | 24 | | ... | 25 | | ... | 26 | 1024 +--------+ 27 | ``` 28 | 29 | ## ⌚️ OBJアトリビュート(`OBJn`) 30 | 31 | ### OBJアトリビュート0 (R/W) 32 | 33 | bit | 内容 34 | ---- | ---- 35 | 0-7 | Y座標 (0-255) 36 | 8 | 伸縮回転フラグ(0=無効, 1=有効) 37 | 9 | サイズ2倍フラグ(伸縮回転フラグが1のとき, 1=2倍) or OBJ非表示フラグ(伸縮回転フラグが0のとき, 1=非表示) 38 | 10-11 | OBJモード (0=通常, 1=半透明, 2=OBJウィンドウ, 3=指定不可) 39 | 12 | OBJモザイク (0=無効, 1=有効) 40 | 13 | カラーパレット (0=16色/16パレット, 1=256色/1パレット) 41 | 14-15 | OBJ Shape (0=正方形, 1=横長, 2=縦長, 3=指定不可) 42 | 43 | 注意: 大きいOBJ(Y方向のサイズがサイズ2倍フラグによって128px)が Y>128 に存在するとき Y>-128として扱われます。 つまりOBJは画面の上の方に表示され、下の方には表示されません。 44 | 45 | ### OBJアトリビュート1 (R/W) 46 | 47 | **伸縮回転が有効(Attr0のbit8が1)** 48 | 49 | bit | 内容 50 | ---- | ---- 51 | 0-8 | X座標 (0-511) 52 | 9-13 | 伸縮回転パラメータ番号 (0-31) 53 | 14-15 | OBJサイズ (0-3, Attr0のOBJ Shapeに依存) 54 | 55 | **伸縮回転が無効(Attr0のbit8が0)** 56 | 57 | bit | 内容 58 | ---- | ---- 59 | 0-8 | X座標 (0-511) 60 | 9-11 | 使用しない 61 | 12 | X反転 62 | 13 | Y反転 63 | 14-15 | OBJサイズ (0-3, Attr0のOBJ Shapeに依存) 64 | 65 | **OBJサイズ(bit14-15)** 66 | 67 | OBJサイズ | 正方形 | 横長 | 縦長 68 | -- | -- | -- | -- 69 | 0 | 8x8 | 16x8 | 8x16 70 | 1 | 16x16 | 32x8 | 8x32 71 | 2 | 32x32 | 32x16 | 16x32 72 | 3 | 64x64 | 64x32 | 32x64 73 | 74 | ### OBJアトリビュート2 (R/W) 75 | 76 | bit | 内容 77 | ---- | ---- 78 | 0-9 | タイル番号 (0-1023) 79 | 10-11 | 対BG優先度 (0-3; 0=Highest) 80 | 12-15 | パレット番号 (0-15) (256色/1パレットのときは使用しない) 81 | 82 | ### OBJモード 83 | 84 | OBJモード(Attr0のbit10-11)は 85 | 86 | - 通常(0) 87 | - 半透明(1) 88 | - OBJウィンドウ(2) 89 | 90 | のどれかになります。 91 | 92 | 半透明モードのとき、OBJはBLDCNTレジスタの値に関係なくアルファブレンドの第1ターゲットとして使われます。詳しくは[ブレンド](./blend.md)を参照してください。 93 | 94 | OBJウィンドウモードのときは、OBJは表示されず、代わりに透明でないピクセルはOBJウィンドウのマスクとして使用されます。詳しくは[LCD制御レジスタ](./control.md)と[WINOUT](./window.md)を見てください。 95 | 96 | ### OBJのタイル番号 97 | 98 | Attr2のbit0-9で指定するタイル番号は通常0-1023まで指定可能ですが、場合によっては制限が加わる時があります。 99 | 100 | - 256色/1パレットのとき: 偶数のタイル番号のみを使用することができ、タイル番号の下位ビットは0にする必要があります。 2次元マッピングモード(後述)では、このビットは完全に無視されます。 101 | - BGモード3-5のときつまりビットマップモードのとき: タイル番号は512から1023までしか指定できません。これはOBJの下位16KBがフレームバッファとして使われているからです。0-511を指定したときは無視され非表示になります。 102 | 103 | ### 対BG優先度 104 | 105 | Attr2の対BG優先度が[BG制御レジスタ](./bg_control.md)のbit0-1で指定するBGレイヤの優先度と同じ場合、OBJのほうが優先され、そのBGレイヤの上に表示されます。 106 | 107 | OBJ同士の優先度と混同しないように注意してください。 108 | 109 | 例として、OBJ0の対BG優先度=1 で OBJ1の対BG優先度=0 の場合を考えてみましょう 110 | 111 | [1行に同時に表示可能なスプライトの数](#1行に同時に表示可能なスプライトの数)のところでも述べたようにOBJ同士ではOBJ0が最も優先度が高いです。 112 | 113 | なのでOBJ同士が重なった時は OBJ0 > OBJ1 ですが、対BG優先度を見ると BG0 > OBJ0、OBJ1 > BG0となり奇妙なことになってしまいます。 114 | 115 | ## 💠 伸縮回転パラメータ(`ParamN`) 116 | 117 | 上で述べたようにOAMの各エントリの間には空白の領域がありました。 これらの 128×16bit はOBJの伸縮回転パラメータを格納するのに使われます。 118 | 119 | ### PA,PB,PC,PD (R/W) 120 | 121 | 4つの16bitパラメータ(PA,PB,PC,PD)で各OBJの伸縮回転に関するプロパティを定義しています。 122 | 123 | ``` 124 | -1st Group: PA=07000006, PB=0700000E, PC=07000016, PD=0700001E 125 | -2nd Group: PA=07000026, PB=0700002E, PC=07000036, PD=0700003E 126 | -... 127 | ``` 128 | 129 | のように配置されています。 130 | 131 | 伸縮回転パラメータ用のメモリ領域は全部で 128×16bitであり、1つのOBJにつき4×16bitなので全部で 32個のOBJ の伸縮回転パラメータを持つことができます。 132 | 133 | 伸縮回転を使用する各OBJは、上記の32のパラメータグループの中から任意のものを選択することができます。 134 | 135 | これは[アトリビュート1](#objアトリビュート1-rw)のbit9-13でOBJと紐づけられます。 136 | 137 | 個別のPA,PB,PC,PD値の意味は[BGの場合](bg_scalerot.md#伸縮回転パラメータ)と同じです。 138 | 139 | ### 基準点 140 | 141 | OBJの伸縮回転時の基準点はOBJの座標に等しくなります。 142 | 143 | またOBJを回転させる際はOBJの真ん中を軸として回転させることになります。例えば 8×32の場合、`(4, 16)`が軸になって回転します。 144 | 145 | ### サイズ2倍フラグ (アトリビュート0のbit9) 146 | 147 | これは伸縮回転が有効なOBJに対するフラグです。 148 | 149 | - フラグが0: スプライトを回転させて、(回転していない場合の)通常サイズの長方形の領域の内側に表示します。回転されたスプライトの端がその領域の外に出てしまうと、その端は見えなくなってしまいます。 150 | - フラグが1: スプライトを回転させた後,(回転していない場合の)2倍のサイズのの矩形領域の内側に表示します.これにより,回転したスプライトの端が通常のサイズの範囲外に出てしまっても,スプライトの端が見えるようになります。 151 | 152 | ただし、例えば8x32ピクセルのスプライトを90度回転させた場合、サイズ2倍の領域は16×64と32に満たないので、スプライトの一部が切り取られてしまいます。 153 | -------------------------------------------------------------------------------- /video/palette.md: -------------------------------------------------------------------------------- 1 | # 🎨 パレット 2 | 3 | メモリ空間`0x05000000..050003FF`はパレット用のメモリ空間です。サイズは1KB(1024バイト)です。 4 | 5 | BGパレットとOBJパレットはそれぞれ独立したメモリ領域を持っています。 6 | 7 | ``` 8 | 0x0500_0000..0500_01ff: BGパレット (512バイト, 256色) 9 | 0x0500_0200..0500_03ff: OBJパレット (512バイト, 256色) 10 | ``` 11 | 12 | BGとOBJのパレットは、それぞれ16色×16枚のパレットとしても使えますし、256色の単一パレットとして使うこともできます。 13 | 14 | OBJの一部が16色モードとしてパレットを使用している間、他のOBJは256色モードとしてパレットを使用することがあることに注意してください。 これはOBJに限らずBG0-BG3レイヤについても同様です。 15 | 16 | ### 透明色 17 | 18 | すべてのBG/OBJパレットの色0は透明色として扱います。 19 | 20 | よってカタログスペック上では 16(256)色のパレットですが、実際に使えるのは 15(255)色だけです。 21 | 22 | ### 背景色 23 | 24 | BGパレット0の色0は背景色(Backdrop)として扱います。 25 | 26 | 背景色は画面上で(非透明色の)BGかOBJが描画されなかったピクセルに表示されます。 27 | 28 | ### 色の定義 29 | 30 | 1色を表すのに2バイト使用します。RGBで32段階で、Bit15は不使用です。 31 | 32 | 前述のようにパレットのメモリ領域は512バイトなので 256色 or 16色/16パレット を表現可能です。 33 | 34 | また32768色を使用可能なBGモード(3, 5)でも色の表現は同じです。 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
bit1514131211109876543210
color--Blue(0..31)Green(0..31)Red(0..31)
68 | 69 | **注意** 70 | 71 | 基本的に、各色の強度は0..31の32段階ありますが、**0..14にした場合全て真っ黒**になってしまいます。なので実際に色を表す場合は15..31の間で表していくことになります。 72 | 73 | 色の強度が上がるにつれて画面は明るくなっていきます。 74 | -------------------------------------------------------------------------------- /video/scanline.md: -------------------------------------------------------------------------------- 1 | # 描画サイクル 2 | 3 | GBAの画面描画は上から順に1行ずつやっていきます。 4 | 5 | HBlank、VBlankも含めた画面の概略図は次のようになっています。 6 | 7 | screensize 8 | 9 | ## 列の描画 10 | 11 | 現在描画中の行を左から右に1列(1ピクセル)ずつ描画していきます。 12 | 13 | 1ピクセル(=dot)描画するのにCPU時間で4サイクルかかります。 14 | 15 | ``` 16 | Visible 240px, 57.221 us, 960サイクル 17 | HBlank 68px, 16.212 us, 272サイクル 18 | Total 308px, 73.433 us, 1232サイクル 19 | ``` 20 | 21 | VRAMとPaletteにはHBlank中のみアクセス可能です。OAMはHBlank中に加えて、DISPCNTのbit5がセットされているときのみアクセス可能です。 22 | 23 | ## 行の描画 24 | 25 | 1行を描画し終えたら次の行の描画に写ります。行の描画は上から下へと行われます。 26 | 27 | ``` 28 | Visible (*) 160行, 11.749 ms, 197120サイクル 29 | VBlank 68行, 4.994 ms, 83776サイクル 30 | Total 228行, 16.743 ms, 280896サイクル 31 | ``` 32 | 33 | VBlank中はVRAM,OAM,Palette全てにアクセス可能です。 34 | 35 | VBlank中(160\~228行)は、240\~308pxのHBlank期間に入ってもHBlank割り込みは発生しません。 36 | 37 | > [!NOTE] 38 | > 縦画面のサイズは160px(160行)ですが、上の8pxは実際には見えません。 39 | > これらの行は、光源に向けてGBAを持っているときに影に覆われています。これらの行は事実上黒です。そして、重要な情報を表示するために使用するべきではありません。 40 | 41 | ## システムクロック 42 | 43 | CPUのクロックは 16.78MHz(16×1024×1024Hz) なので、1サイクルあたり59.59ns秒です。 44 | 45 | ## インターフェイス 46 | 47 | The LCD display is using some sort of interlace in which even scanlines are dimmed in each second frame, and odd scanlines are dimmed in each other frame (it does always render ALL lines in ALL frames, but half of them are dimmed). 48 | 49 | The effect can be seen when displaying some horizontal lines in each second frame, and hiding them in each other frame: the hardware will randomly show the lines in dimmed or non-dimmed form (depending on whether the test was started in an even or odd frame). 50 | Unknown if it's possible to determine the even/off frame state by software (or possibly to reset the hardware to this or that state by software). 51 | 52 | Note: The NDS is applying some sort of frameskip to GBA games, about every 3 seconds there will by a missing (or maybe: inserted) frame, ie. a GBA game that is updating the display in sync with GBA interlace will get offsync on NDS consoles. 53 | -------------------------------------------------------------------------------- /video/sprite.md: -------------------------------------------------------------------------------- 1 | # スプライト(OBJ) 2 | 3 | スプライトとは8x8~64x64サイズの画像を最大128個まで表示し、シューティングゲームでいう自機や弾、RPGでいう主人公キャラなどに使います。 4 | 5 | ## 🖍 概要 6 | 7 | 1画面あたり最大128個のOBJ(大きさは64×64ドットまで任意)を表示することができます。 8 | 9 | 8×8ドットの小さなサイズなら1行に最大128個のOBJを表示することができます。 10 | 11 | ### 1行に同時に表示可能なスプライトの数 12 | 13 | 1行あたり、OBJをレンダリングするのに使えるCPUサイクルの合計は 14 | 15 | [LCD制御レジスタ](./control.md)のbit5("H-Blank Interval Free" bit)が 16 | 17 | - 0のとき: 1210 (=304×4-6) 18 | - 1のとき: 954 (=240×4-6) 19 | 20 | となります。 21 | 22 | またOBJのレンダリングに必要なサイクルは、OBJのX方向のピクセルサイズをnとすると次のようになります 23 | 24 | サイクル | OBJ Type | OBJ Type Screen Pixel Range 25 | -- | -- | -- 26 | n*1 cycles | Normal OBJs | 8..64 pixels 27 | 10+n*2 cycles | Rotation/Scaling OBJs | 8..64 pixels (area clipped) 28 | 10+n*2 cycles | Rotation/Scaling OBJs | 16..128 pixels (double size) 29 | 30 | プログラマはこれらの情報を用いて、OBJのレンダリングが間に合うように1行に表示するOBJを調整する必要があります。 31 | 32 | 1行あたりの最大OBJ数は、表示されているOBJよりも優先度の高い非表示(画面外)OBJの影響も受けます。 33 | 34 | これを避けるには、表示したいOBJをなるべくOAMの前方に持ってきてください。 35 | 36 | OBJ0が最も優先度が高く、OBJ127が最も優先度が低くなっています。 37 | 38 | プログラムがOBJをOAMの固定位置にあることを前提としているなどの理由でそれができない場合、少なくとも、伸縮回転を無効にして、表示されていないOBJのサイズを8x8に設定することで余計な負荷を減らすことができます。 39 | 40 | ### VRAM - スプライトのタイルデータ 41 | 42 | OBJは8×8のタイル単位で構成されています。 43 | 44 | ただしOBJのタイルデータは背景のタイルデータとは別のメモリ領域に格納されています。BGモード0-2では `0x0601_0000-0601_7fff`(32KB) に、BGモード3-5では `0x0601_4000-0601_7fff`(16KB)に格納されています。 45 | 46 | このOBJタイルデータ用のメモリ領域に、何枚のタイルを格納できるかは、メモリ領域のサイズ(16KB or 32KB)だけでなく、OBJの色深度にも依存しており、最小で256タイル、最大で1024タイル格納できます。 47 | 48 | ### OAM - スプライト属性メモリ 49 | 50 | OAMは`0x0700_0000-0700_03ff`にあります。 サイズは1KBです。詳細は[OAM](oam.md)を参照してください。 51 | 52 | ## 🗺 OBJのマッピングモード 53 | 54 | OBJタイルは8×8pxを1単位としており、より大きなOBJは複数の8×8タイルを組み合わせることによって表示することができます。 55 | 56 | 各OBJのX方向とY方向のサイズは、個別にOAMで定義することができ、8,16,32,64ピクセルから選択可能です。よって組み合わせによって正方形だったり長方形のOBJを設定可能です。 57 | 58 | 複数の8×8タイルを含むOBJを表示する場合、[LCD制御レジスタ](./control.md)のbit6で指定することで、以下の2つのマッピングモードのいずれかを使用することができます。いずれの場合も、左上のタイルのタイル番号をOAMメモリに指定しなければなりません。 59 | 60 | ### 2次元マッピングモード 61 | 62 | このマッピングモードでは、1024個のOBJタイルが32x32の行列(256色モードでは16x32の行列)として配置されていることを前提としています。 63 | 64 | つまり、この行列の上段には0x00..1f、次の列には0x20..3fのタイルが含まれています。 65 | 66 | ```sh 67 | # 16色/16パレット 68 | 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1a, 1b, 1c, 1d, 1e, 1f 69 | 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 3a, 3b, 3c, 3d, 3e, 3f 70 | ... 71 | 72 | # 256色/1パレット 73 | 00, 02, 04, 06, 08, 0a, 0c, 0e, 10, 12, 14, 16, 18, 1a, 1c, 1e, 74 | 20, 22, 24, 26, 28, 2a, 2c, 2e, 30, 32, 34, 36, 38, 3a, 3c, 3e, 75 | ... 76 | ``` 77 | 78 | 例えば、16x16ピクセルのOBJを表示する場合、タイル番号が0x04に設定されている場合、OBJの上段のタイルは0x04と0x05、次の行は0x24と0x25となります。(256色モードの場合は 0x04と0x06、0x24と0x26) 79 | 80 | ### 1次元マッピングモード 81 | 82 | このモードでは1024個のOBJタイルが長さ0x3ffの配列として配置されていることを前提としています。 83 | 84 | 1次元という名前のとおり、16x16ピクセルのOBJを表示する場合、タイル番号が0x04に設定されている場合、OBJの上段のタイルは0x04と0x05、次の行は0x06と0x07となります。(256色モードの場合は 0x04と0x06、0x08と0x0a) 85 | -------------------------------------------------------------------------------- /video/window.md: -------------------------------------------------------------------------------- 1 | # ウィンドウ 2 | 3 | ウィンドウ機能は、画面の一定の領域を指定し、その内部と外部で各BGレイヤやスプライトなどを表示するか表示しないかを指定する機能です。 4 | 5 | ウィンドウには、Window0, Window1, OBJWindowの3種類があります。 6 | 7 | ## 例 8 | 9 | ロックマンエグゼ6の次のライブラリの画面ではウィンドウが使われています。 10 | 11 | 12 | 13 | BG2レイヤがウィンドウとして使われています。 14 | 15 | 16 | 17 | 18 | 19 | ## ウィンドウの有効化 20 | 21 | [ディスプレイ制御](control.md)で紹介したDISPCNTの13-15bit は Window0, Window1, OBJ Windowを有効化するために使用されます。 22 | 23 | DISPCNTのbit8-12は BG0-3,OBJレイヤのマスタイネーブルビットとして使用され、DISPCNTと後述のWININ/WINOUT の 有効ビットの両方がセットされている場合にのみレイヤーが表示されます。 24 | 25 | ## ウィンドウの座標の設定 26 | 27 | ### ウィンドウのX座標 28 | 29 | ``` 30 | 0x0400_0040 - WIN0H - Window0のX座標 (W) 31 | 0x0400_0042 - WIN1H - Window1のX座標 (W) 32 | ``` 33 | 34 | bit | 内容 35 | ---- | ---- 36 | 0-7 | X2, ウィンドウの右端のX座標+1 37 | 8-15 | X1, ウィンドウの左端のX座標 38 | 39 | X2が不正な値(X2>240 または X1>X2)のときは X2=240として扱われます。 40 | 41 | ### ウィンドウのY座標 42 | 43 | ``` 44 | 0x0400_0044 - WIN0V - Window0のY座標 (W) 45 | 0x0400_0046 - WIN1V - Window1のY座標 (W) 46 | ``` 47 | 48 | bit | 内容 49 | ---- | ---- 50 | 0-7 | Y2, ウィンドウの下端のY座標+1 51 | 8-15 | Y1, ウィンドウの上端のY座標 52 | 53 | Y2が不正な値(Y2>160 または Y1>Y2)のときは Y2=160として扱われます。 54 | 55 | ## ウィンドウの挙動制御 56 | 57 | ### 0x0400_0048 - WININ - 内側制御レジスタ (R/W) 58 | 59 | bit | 内容 60 | ---- | ---- 61 | 0-3 | Window0 BG0-BG3表示フラグ (0=非表示, 1=表示) 62 | 4 | Window0 OBJ表示フラグ (0=非表示, 1=表示) 63 | 5 | Window0 Color Special Effect (0=Disable, 1=Enable) 64 | 6-7 | 不使用 65 | 8-11 | Window1 BG0-BG3表示フラグ (0=非表示, 1=表示) 66 | 12 | Window1 OBJ表示フラグ (0=非表示, 1=表示) 67 | 13 | Window1 Color Special Effect (0=Disable, 1=Enable) 68 | 14-15 | 不使用 69 | 70 | ### 0x0400_004a - WINOUT - 外側・OBJウィンドウ内側制御レジスタ (R/W) 71 | 72 | bit | 内容 73 | ---- | ---- 74 | 0-3 | Outside BG0-BG3表示フラグ (0=非表示, 1=表示) 75 | 4 | Outside OBJ表示フラグ (0=非表示, 1=表示) 76 | 5 | Outside Color Special Effect (0=Disable, 1=Enable) 77 | 6-7 | 不使用 78 | 8-11 | OBJ Window BG0-BG3表示フラグ (0=非表示, 1=表示) 79 | 12 | OBJ Window OBJ表示フラグ (0=非表示, 1=表示) 80 | 13 | OBJ Window Color Special Effect (0=Disable, 1=Enable) 81 | 14-15 | 不使用 82 | 83 | ## OBJウィンドウ(`OBJWIN`) 84 | 85 | OBJウィンドウの寸法は、OBJ Mode属性がOBJウィンドウになっているOBJによって指定されます。そのようなOBJの透明でないドットはOBJウィンドウ領域としてマークされます。OBJ自体は表示されません。 86 | 87 | これらのOBJの色、パレット、表示優先度は無視されます。OBJウィンドウ領域を定義する際には、DISPCNTのbit12とbit15の両方を設定する必要があります。 88 | 89 | ## ウィンドウの優先度 90 | 91 | 複数のウィンドウが有効になっていて、これらのウィンドウが重なっている場合、優先度は `WIN0 > WIN1 > OBJWIN`の順です。 92 | 93 | ウィンドウの優先度が`0`の場合、任意のウィンドウ領域の内側にないすべてのドットにウィンドウの外側エフェクトが使用されます。 94 | -------------------------------------------------------------------------------- /waitstate.md: -------------------------------------------------------------------------------- 1 | # ウェイトステート 2 | 3 | ## ウェイトステート 4 | 5 | メモリのアクセスにはウェイトステートがない方が望ましいです。 つまり、`1N`と`1S`はそれぞれ1クロックサイクルに等しくなるべきです。 6 | 7 | しかし、時間のかかるカートリッジへのアクセスやデータバス幅が小さいメモリ領域に対しての(32bit)アクセスは、1クロックサイクルでは完了しません。 8 | 9 | そのため、CPUはアクセス時間を考慮して、自発的に待機する必要があります。この待機時間のことをウェイトステートと呼びます。 10 | 11 | どれくらいのウェイトステートが必要かは、アクセス対象のバスクロックによるため、GBAでは`WAITCNT`というレジスタでウェイトステートを設定することが可能です。 12 | 13 | ## 0x0400_0204 - WAITCNT - ウェイトステート制御レジスタ (R/W) 14 | 15 | カートリッジのROMは `0x0800_0000`, `0x0A00_0000`, `0x0C00_0000` の3つのアドレス領域にミラーリングされており、これらの領域にCPUがアクセスするのに要する時間を WaitState0, WaitState1, WaitState2 と呼びます。 16 | 17 | それぞれの領域に異なるウェイトステートを割り当てることができます。 18 | 19 | ``` 20 | Bit Expl. 21 | 0-1 SRAMウェイトステート (0..3 = 4,3,2,8 cycles) 22 | 2-3 N0 - WaitState0 ノンシーケンシャルアクセス (0..3 = 4,3,2,8 cycles) 23 | 4 S0 - WaitState0 シーケンシャルアクセス (0..1 = 2,1 cycles) 24 | 5-6 N1 - WaitState1 ノンシーケンシャルアクセス (0..3 = 4,3,2,8 cycles) 25 | 7 S1 - WaitState1 シーケンシャルアクセス (0..1 = 4,1 cycles) 26 | 8-9 N2 - WaitState2 ノンシーケンシャルアクセス (0..3 = 4,3,2,8 cycles) 27 | 10 S2 - WaitState2 シーケンシャルアクセス (0..1 = 8,1 cycles) 28 | 11-12 PHI Terminal Output (0..3 = Disable, 4.19MHz, 8.38MHz, 16.78MHz) 29 | 13 不使用 30 | 14 カートリッジのプリフェッチが有効かどうか (0=無効, 1=有効) 31 | 15 Game Pak Type Flag (Read Only) (0=GBA, 1=CGB) (IN35 signal) 32 | 16-31 不使用 33 | ``` 34 | 35 | `WAITCNT`は起動時には`0x0000_0000`です。 36 | 37 | そしてその後、現在製造されているカートリッジでは `WAITCNT=0x0000_4317=0b0000_0000_0000_0000_0100_0011_0001_0111` となります。これは 38 | 39 | ``` 40 | SRAM: 8サイクル 41 | N0, N1, N2: 3, 4, 8サイクル 42 | S0, S1, S2: 1, 4, 8サイクル 43 | ``` 44 | 45 | となります。 実際のカートリッジのアクセスにはこれに1サイクル加えたものがアクセスに要するサイクルになります。(SRAMはそのまま8サイクル) 46 | 47 | また、カートリッジのデータバスは16bitなので、32bitアクセスは2回の16bitアクセスに分割されて行われます。 最初の16bitがノンシーケンシャルであっても、2回目の16bitは常にシーケンシャルです 48 | 49 | 注意: GBAはカートリッジROMの各128Kブロックの先頭にアクセスする際には強制的にノンシーケンシャルアクセスします。 またPHI端子出力(Gamepak BusのPHIピン)は無効にしてください。 50 | --------------------------------------------------------------------------------