2009年08月24日


NP2 for PSPのmain()関数を解析する

今回はNP2 for PSPのプログラム解析を行います。

まずはmain()関数から見てみましょう。
main()関数は、psp/np2.cにあります。

エミュレータソフトウェアはほとんど以下のような構成になっています。

1. 初期化(ハードウェア、ソフトウェア初期化、設定ファイルの読み込み等)
2. メインループ開始
3. キー入力
4. 処理をちょっとだけ実行(CPU命令実行、サウンド再生等)
5. メインループ終了、2.に戻る
6. 終了処理(ハードウェア、ソフトウェア後始末、設定ファイル保存等)


NP2 for PSPも基本は変わりありません。
main()の最初に〜init()とか〜initaialize()とう関数を多数呼び出して初期化を行っています。

以下がメインループですね。

while(taskmng_isavail()) {
(中略)
}


以下の関数でキー入力などを行っています。

taskmng_rol()


以下の関数がエミュレータコアの実行部です。

pccore_exec()


そして、メインループを抜けると、終了処理が走ります。

次にPSP固有の処理について見てみます。

まず特徴的なのは以下の関数です。

int SetupCallbacks(void)
{
int thid;

thid = sceKernelCreateThread("update_thread", CallbackThread,
0x11, 0xFA0, 0, 0);
if (thid >= 0) {
sceKernelStartThread(thid, 0, 0);
}

return thid;
}

スレッドを作成して、実行しています。

スレッドとは、main()から始まる処理から分岐し、平行に動作する、main()の流れとは別の流れのことを言います。スレッドにより処理が平行に動作するように見えますが、実際に処理を行うCPUは一つですので、処理を細かく分けて、main()の流れをちょっと実行しては、別のスレッドの流れをちょっと実行して、ということを繰り返し行っています。

main()の流れ ----+--------------------->
|
別のスレッド +--------------------->

SetupCallbacks()でスレッドを作成し、成功すればそのスレッドを実行します。
実際に起動されるスレッドは、sceKernelCreateThread()の第2引数で指定される関数、つまり以下のCallbackThread()です。

int CallbackThread(void *arg)
{
int cbid;

cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
sceKernelRegisterExitCallback(cbid); //SetExitCallback(cbid);
cbid = sceKernelCreateCallback("Power Callback", power_callback, NULL);
scePowerRegisterCallback(0, cbid);

sceKernelSleepThreadCB(); //KernelPollCallbacks();

return 0;
}

上記CallbackThread()で、二つのcallback関数を登録しています。callback関数登録後、sceKernelSleepThreadCB()を呼び出してこのスレッドはイベント待ちのスリープに入ります。callback関数とは、あらかじめ登録しておき、何かイベントが発生したら、呼び出してもらう関数のことを言います。
CallbackThread()において、sceKernelRegisterExitCallback()でexit_callback()を登録し、scePowerRegisterCallback()でpower_callback()を登録しています。
それぞれ、PSPのホームボタンが押され、終了を選択した場合、電源オフを実行した場合に呼び出されます。
exit_callback()の先では、単に終了処理を実行しますが、パワーオフの場合は、単に終了処理をする場合と、スリープ対応の処理があります。スリープの場合は、一度電源オフのcallbackが実行されてしまったため、再度callback関数を登録して終了し。そのままスリープから再度電源オンを実行されるのを待つようです。

もう一つ、sceKernelWaitSema(), sceKernelSignalSema()を見ておきましょう。
使われているのは、

メインループの直前にsceKernelWaitSema()
メインループの直後にsceKernelSignalSema()
exit_proc()関数の最初、taskmng_exit()の直後にsceKernelWaitSema()
です。

exit_proc()の最初に実行されるtaskmng_exit()でtask_avail = FALSE;を実行しているが、実はこれがメインループを抜ける条件となります。
つまりホームボタン等でゲームを終了する場合に、メインループを完全に抜けてから終了処理を走らせたいため、メインループが抜けてsceKernelSignalSema()が実行されるまでは、exit_proc()は、sceKernelWaitSema()で待たされます。
タグ:NP2 for PSP PSP NP2
posted by ひっそりぃ at 2009/08/24 16:07 | Comment(0) | TrackBack(0) | PSP | このブログの読者になる | 更新情報をチェックする

2009年08月21日


NP2 for PSP Ver0.32のソースをmakeし、PSPで実行する

NP2 for PSPの最新版ソースについては、まだNP2 for PSP作者のsakahiさんより返事がありませんので、とりあえず一つ前のVer0.32のソースをUbuntu 9.04でmakeし、PSPでの実行確認をしておきます。

まずは、NP2 for PSPの公式サイト から、NP2 for PSP Ver0.32ソース をダウンロードします。

ダウンロードしたファイルを作業ディレクトリ(ここでは~/tmp)で展開します。

hissorii@ubuntu:~/tmp$ unzip np2_081as_psp_v0.32.zip

psp用のMakefileがあるディレクトリまで降りて、makeしてみる。

hissorii@ubuntu:~/tmp$ cd np2_081as_psp_v0.32/np2/psp/
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ make -f Makefile.psp
make: *** `../obj/psp/strres.o' に必要なターゲット `../common/strres.c' を make するルールがありません. 中止.
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$

うーん、Linuxだとファイルの大文字小文字を区別するので、Makefileに小文字でディレクトリ名やファイル名が書かれていて、実際のファイル名が大文字だったりすると、よろしくないです。
とりあえず「Linux入門はじめますた」のこのエントリ に書いた方法であらゆるディレクトリとファイル名を小文字に変換しました。
さらに、make時に-f指定しなくても済むようにMakefile.pspをMakefileとmvして、makeを再実行。

hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ make
(中略)
Assembler messages:
FATAL: can't create ../obj/psp/strres.o: No such file or directory
make: *** [../obj/psp/strres.o] エラー 1
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$

む、エラーですね。../obj/pspディレクトリがない。掘ってmake。

hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ mkdir -p ../obj/psp
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ make
(中略)
ERROR: Could not open the file. (NP2_logo01.png)
make: *** [EBOOT.PBP] エラー 255
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$

NP2log01.pngがみつからない。一括で小文字に変換したので、当然そうなりますね。
今回はファイル名を修正し、再make。

hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ mv np21_logo01.png NP21_logo01.png
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ mv np2_logo01.png NP2_logo01.png
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ make
psp-strip NP2.elf -o NP2_strip.elf
pack-pbp EBOOT.PBP PARAM.SFO NP2_logo01.png \
NULL NULL NULL \
NULL NP2_strip.elf NULL
[0] 408 bytes | PARAM.SFO
[1] 12406 bytes | NP2_logo01.png
[2] 0 bytes | NULL
[3] 0 bytes | NULL
[4] 0 bytes | NULL
[5] 0 bytes | NULL
[6] 543520 bytes | NP2_strip.elf
[7] 0 bytes | NULL
rm -f NP2_strip.elf
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$

できあがりました。EBOOT.PBPがPSPに転送して実行するファイルになります。しかしタイムスタンプを見ると、ほぼ4年経過しています。

hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ ls -lt | head
合計 1520
-rw-r--r-- 1 hissorii hissorii 556374 2009-08-21 15:29 EBOOT.PBP
-rw-r--r-- 1 hissorii hissorii 408 2009-08-21 15:24 PARAM.SFO
-rwxr-xr-x 1 hissorii hissorii 678390 2009-08-21 15:24 NP2.elf
drwxr-xr-x 2 hissorii hissorii 4096 2009-08-21 15:19 psp
-rw-r--r-- 1 hissorii hissorii 7489 2005-09-23 00:30 Makefile
-rw-r--r-- 1 hissorii hissorii 3983 2005-09-22 23:56 psp_readme.txt
-rw-r--r-- 1 hissorii hissorii 8732 2005-09-22 23:36 np2.c
-rw-r--r-- 1 hissorii hissorii 18848 2005-09-20 09:09 taskmng.c
-rw-r--r-- 1 hissorii hissorii 7367 2005-09-20 08:53 dosio.c
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$

PSPをUSB経由でUbuntuにつなげ、EBOOT.PBPをコピーし、PSPをumount。

hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ mkdir /media/disk/PSP/GAME/np2
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ cp EBOOT.PBP /media/disk/PSP/GAME/np2/
hissorii@ubuntu:~/tmp/np2_081as_psp_v0.32/np2/psp$ umount /media/disk

フォントファイルやDiskイメージを入れていませんが、NP2 for PSPが起動するまで確認できました。

さて、次はどうするかな。
タグ:NP2 PSP NP2 for PSP
posted by ひっそりぃ at 2009/08/21 15:51 | Comment(0) | TrackBack(0) | PSP | このブログの読者になる | 更新情報をチェックする
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。