ボタンを押すたびにカウントアップする実装です。
といっても大したことはなく、CPUにボタン押下時の割り込み処理が存在するので、そのときに実行する関数を指定しているだけです。
私は今までOSが存在しない低レイヤーのプログラミングをしたことがなく、「割り込み」の機能がOSレイヤーで実装されていると思いこんでいた(もしかしたらOSレイヤーでも実装されているのかもしれませんが)ので、CPUの機能として実装されていることがちょっと意外でした。
- 作者: Igor Zhirkov,吉川邦夫
- 出版社/メーカー: 翔泳社
- 発売日: 2018/01/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る
『低レベルプログラミング』から引用すると、フォン・ノイマン・アーキテクチャから現代のCPU(書籍ではIntel 64が例ですが)いくつかの拡張があるようです。
このうち「割り込み」によって、対話的なプログラミングできるようになったそうです。このうちゲームボーイでは「プロテクションリング」「仮想メモリ」のような、プログラムの機構は無さそうですね。また、以前海外の記事で「GBのアーキテクチャがGBA以前は"register-oriented strategy"向けに設計されていて、関数でスタックを利用するC言語では遅い場合がある」というような話を読んだことあるのですが、それはハードウェアスタックが存在しないことを指しているのかもしれません。
ただ、割り込みの実装自体はできたものの、ライフゲームの実装をするためにはいくつか困った点があります。
割り込み処理中に joypad()
でボタンの情報を取得できない
もともと、以下のようにグローバル変数( joypad_state
)を書き換え、ボタンの処理によって分岐しようとしていました。
int main(void) { disable_interrupts(); add_JOY(onjoy); enable_interrupts(); set_interrupts(JOY_IFLAG); while (1) { switch (joypad_state) { // 分岐 } } } void onjoy(void) { joypad_state = joypad(); }
ただ、公式ドキュメントにもある通り、 add_JOY
の処理中には、ボタンの状態を受け取れません( joypad
関数が動作しません)でした。これは少し工夫する必要があります。
Interrupts in GBDK are handled using the functions disable_interrupts(), enable_interrupts(), set_interrupts(UBYTE ier) and the interrupt service routine (ISR) linkers add_VBL, add_TIM, add_LCD, add_SIO and add_JOY which add interrupt handlers for the vertical blank, timer, LCD, serial and joypad interrupts respectively.
set_interrupts
をした場合に画面の表示がズレてしまう
#include <gb/gb.h> #include <gb/drawing.h> void onjoy(void); int main(void) { disable_interrupts(); add_JOY(onjoy); enable_interrupts(); // set_interrupts(JOY_IFLAG); // <- ここをコメントアウトしたりする line(16, 4, 16, 140); }
コメントアウトした場合はこうなのですが、
コメントアウトを外し、 set_interrupts
を行うとこうなります。
こういう場合のデバッグ方法が分からずに困っています。コンパイル後のアセンブリを見ていくしかないと思うんですが、どういう観点で見れば良いのか分かりません。