ポケモンシリーズなどに存在する時計機能。基板にはRTCと呼ばれるチップとボタン電池が乗っています。GBA本体の電源を落としたりカードリッジを素の状態でおいたままでも、ボタン電池に残量がある限り時を刻み続ける仕組みです。このページはもう少し踏む混んで時計を表示したり、書き込んだりする仕組みを解説します。
まずはGBATEKとチップのデータシートそれぞれ覗いてみましょう。
GBA Cart I/O Port (GPIO) 4bit General Purpose I/O Port (GPIO) - contained in the ROM-chip The I/O registers are mapped to a 6-byte region in the ROM-area at 80000C4h, the 6-byte region should be zero-filled in the ROM-image. In Boktai, the size of the zero-filled region is 0E0h bytes - that probably due to an incorrect definition (the additional bytes do not contain any extra ports, nor mirrors of the ports in the 6-byte region). Observe that ROM-bus writes are limited to 16bit/32bit access (STRB opcodes are ignored; that, only in DS mode?). 80000C4h - I/O Port Data (selectable W or R/W) bit0-3 Data Bits 0..3 (0=Low, 1=High) bit4-15 not used (0) 80000C6h - I/O Port Direction (for above Data Port) (selectable W or R/W) bit0-3 Direction for Data Port Bits 0..3 (0=In, 1=Out) bit4-15 not used (0) 80000C8h - I/O Port Control (selectable W or R/W) bit0 Register 80000C4h..80000C8h Control (0=Write-Only, 1=Read/Write) bit1-15 not used (0) In write-only mode, reads return 00h (or possible other data, if the rom contains non-zero data at that location). Connection Examples GPIO | Boktai | Wario Bit Pin | RTC SOL | GYR RBL -----------+---------+--------- 0 ROM.1 | SCK CLK | RES - 1 ROM.2 | SIO RST | CLK - 2 ROM.21 | CS - | DTA - 3 ROM.22 | - FLG | - MOT -----------+---------+--------- IRQ ROM.43 | IRQ - | - -
適当翻訳しますとGPIOは80000C4hからの6バイト分、0x00を格納されていることがわかります。また、ボクらの太陽の場合は0E0hで書き込まれているという蛇足情報もありますね。表のConnection Examplesを読むと、GPIOピンはカードリッジのPin1,2,21で、RTCチップへの配線はSCK, SIO, CSに接続されている、ということがわかります。raspberry piやArduinoでLEDチカチカしていた方なら肌感覚でなんとなく理解しやすそうです。結局この3本の線がそれぞれ3つのLEDに繋がっておりHIGH(ON), LOW(OFF)して使うだけということになります。ON, OFFには一定のルールを設けて、その仕様に従ってデータを読んだり書いたりしています。
S3511はセイコーインスツルメンツ株式会社が製作したリアルタイムクロックチップです。データシートが日本語で読めるという、なかなかのレアケースですので練習だと思って全体を軽く読んでみてください。docフォルダ内にpdfファイルを用意しました。さて、10ページ目からの動作説明がとても大事です。このビット操作によって情報のやりとりを行います。「1.1 通信データ構成、1.2 コマンド構成、1.3 データ読み出し」項目は絶対に一読してください、でないと先の説明に進めません。それらを理解したことによって得られる知見が次の11ページ目の図です。ステータスレジスタ読み出しの方法は以下の通りになります。
先の初期値をソースコードレベルに落としてみます。まずはdefine定義について。REG_RTC_DATAの下位3ビットがそれぞれCS, SIO, SCKです。たとえば0x3を代入した場合はCS=0, IO=1, SCK=1となりCS=ON, SIO=OFF, SCK=OFF状態となります。REG_RTC_RWは方向、読み込むか書き込むか。REG_RTC_ENABLEは許可フラグです。
#define REG_RTC_DATA *(vu16*)(0x080000C4) // I/O Port Data(ビット配列 例: 0x3 : CS=0, SIO=1, SCK=1) #define REG_RTC_RW *(vu16*)(0x080000C6) // I/O Port Direction #define REG_RTC_ENABLE *(vu16*)(0x080000C8) // I/O Port Control (selectable W or R/W)
先ほどのステータスレジスタを読み出して時計がカードリッジ内に存在するかをチェックをしてみましょう。けっこう混乱するので紙にかいてトレースしていくのが良いと思います。このプログラムを理解すればS3511を好きに扱えます。
EWRAM_CODE void RtcInit(void) { REG_RTC_ENABLE = 0x1; // ステータスレジスタの24時間表示フラグをチェックします // Bit6 0:12時間、1:24時間 RtcOutCmd(0x63); bool isEnable = (RtcIn() & 0x40) ? TRUE : FALSE; } EWRAM_CODE void RtcOutCmd(u32 cmd) { REG_RTC_RW = 0x7; REG_RTC_DATA = 0x1; REG_RTC_DATA = 0x5; s32 i; cmd <<= 1; for(i=7; i>=0; i--) { REG_RTC_DATA = ((cmd >> i) & 0x2) | 0x4; REG_RTC_DATA = ((cmd >> i) & 0x2) | 0x5; } } EWRAM_CODE u32 RtcIn(void) { REG_RTC_RW = 0x5; s32 i; u32 ret = 0; for(i=0; i<8; i++) { REG_RTC_DATA = 0x4; REG_RTC_DATA = 0x5; ret |= ((REG_RTC_DATA & 0x2) >> 1) << i; } return ret; }
ちなみに本番とも呼べる時計の読み込みや書き込みは・・・仕様書をペタペタ張るのも面倒ですしgithubのソースコードを読んで頂ければと思います。なお、このコードはGBA SP+M3 MiniSDで動作確認済みです。エミュレータ(VBA)で試してみたい場合は「Options -> Emulator -> Real Time Clock」をチェックすることを忘れないでください。読み込み(現在時刻表示)のみ可能で、どうも書き込みは実装していないようでエラーになります。