正直日記



2009/01/30

_ マルチタスク機構を作って良かった、とちょっと思った話
調子に乗ってあれこれコード生成してみたが、CPU が thumb モードのままうっか
り ARM コードに飛ばしてしまい未定義命令例外が発生してしまい BIOS に飛んで
しまい〜なわけだが、それでも他のタスクは普通に動いていたのでちょっと感動
してしまった。メモリダンプを画面に出力するタスクを走らせておけば実機上で
ある程度のデバッグが出来るかもしれないなー。
_ ミキサーのループアンロール
「その場で ARM コード生成」という超絶テクを習得したおいらは PCM ミキサー
のループアンロールにこのテクを応用できるんじゃないかと思ったが、ソースを
見直してみたら既にその必要が無い程度(コード生成する分で帳消しになる程度)
には最適化されていたのだった。がっくし。

2009/01/23

_ GBA で複数モジュールを動的ロードする (3) : ライブラリの共有
ふとコードサイズが気になって readelf してみたら、libc や libstdc++ から
リンクされるコードが結構でかい。libc くらいは共有させたい気がする。そこ
で、noMMU な環境でライブラリを共有する機構について調べてた。

とりあえずここら辺かな。

Shared Libraries without an MMU
MMU なしプロセッサ用Linuxの 共有ライブラリ機構

ライブラリは GOT (Global Offset Table)経由で参照して、その GOT は DATA セ
クションに配置しておいて、その DATA セクションを参照するのはベースレジス
タ経由で、そのベースレジスタはローダがセットする……って感じかしら。

理屈は分かるけど、どこからどう実装したものやら……。R_ARM_GOT32 を使うの
かしら?

> どうでもいいけど、MMU はエムエムユーだから冠詞は an になるのか……。  (2009/01/24 21:54:30)

2009/01/20

_ GBA で複数モジュールを動的ロードする (2)
uClinux では FLAT というバイナリフォーマットを使っていて、
その bFLT 形式は elf2flt で ELF からコンバートして生成するらしい。
つまり bFLT ローダだけ作ればいいということか。

2009/01/19

_ GBA で複数モジュールを動的ロードする (1)
いくらなんでも bf じゃ辛いでしょやっぱ最低でも C じゃないと……と言われ
てしまったので TCC のソースを見てる。が、作るべきなのはコンパイラじゃな
くてリンカ&ローダのような気がしてきた。MMU が無いので完全リロケータブル
を目指さなくちゃいけないのではと思うに至ったわけだ。BREW で静的変数が使え
ない(使えなかった)という話を以前よく耳にしたけど、多分根本は一緒なのだ
ろう。

uClinux/ARM の MMU-less サポートが参考になりそうな気がして覗いてみたが、
どこから見ればいいのか見当が付かない。ちょっと山が高すぎたかも。

それと、いい加減 arm-elf を脱却して arm-eabi に乗り換えないと……。

2009/01/18

_ GBA にプリエンプティブ☆マルチタスクを実装する(3)
セマフォを実装するためにはクリティカルセクションが必要で、要するに割り込
みかプリエンプションを止めなければならないのか。逆に言うと、止めちゃって
も良いということか。

タイマ割り込みハンドラでは(タスクの寝ている時間を調べるために)割り込み
回数カウンタをインクリしているので、割り込みを止めるよりは、フラグ立てて
コンテキスト☆スイッチだけ禁止する方向でもいいような気がする。VBLANK 割り
込みハンドラ内では割り込みを止めたいので、二段階のロック機構を設けてみる。
これでスプライトダブラが安心して回せるようになった。しっかし、いちいちク
リティカルセクションに入っていたら CPU 資源を食ってかなわんなぁ。スプライ
トダブラといいつつ、その実スプライトシングラと言えるくらいしか数が出せて
いない。

ちなみに ARM7TDMI の TRM によると、セマフォの実装には SWP か SWPB を使え
ということらしい。フラグを中身確認せずに立てるだけなら STR でもいいような
気がする。マルチプロセサなら話は変わるんだろうけど、今のところターゲット
はシングルプロセサだし。まぁ SWP を使わない理由は無いので使っておくか。

--

モジュールの動的実行とかやってみたかったので b****f*** コンパイラを作って
みる。[,.]の4命令に対してリロケーションテーブルを作り、モジュールロード時
に置き換える。ここまではいいとして、入力待ちでビジーループするのはアホら
しいので、スリープ状態に突入して入力があったときだけアクティブになるよう
な機構が欲しいかもしれない。となると、次はシグナルの実装ということになる
のかな。

2009/01/14

_ 口の中にプッチン☆プリンを実装する(3)
去年自アンで知った「ダイレクト・プッチン」を今になって実践してみたところ、
口の中全体に柔らかい甘味が押し寄せたと思った次の瞬間、ほのかな甘みだけを
残し、消えて無くなってしまった。もう過去の自分には戻れないだろう。とてつ
もない体験をしてしまった。
_ GBA にプリエンプティブ☆マルチタスクを実装する(2)
タイマ割り込みでコンテキスト☆スイッチする機構を作ったものの、main() 関数
の処理を奪いっぱなしのまま回していたので、このままでは同期処理が出来ない
ことに気づいた。自分自身をタスクとして割り当てないといけないのではないか?

同期と関連して。タスクが終了する時のことを全く考えていなかった。コンテキ
ストを拡張して、関数を抜けるときにポップされる分のスタックをあらかじめ積
んでおき、リンクレジスタから終了処理へと飛ぶように細工する。終了処理から
はもう return できないので、空ループでもさせておく。保存された main() の
コンテキストを探して戻るようにするべきだろうか?

色々と謎が深まるばかりである。つーか、聞きかじりからの想像で作るのはやっ
ぱ無理があるから、そろそろ何かを参考にするにゃん。

名無しさん > コンテキスト〜をスタックじゃなくて連結リストに置く。割り込みが掛かったら入れ替えて、インデックスを次のタスクに進める。タスク終了でリストから切り離す。こんな感じではどうでしょう?  (2009/01/16 00:36:55)
>
アルゴリズムの方のスタックの話でしょうか?
タスクの処理順はstd::queue<taskid_t>に突っ込んでます。
なので仰っている方法とほとんど同じ実装だと思いますよー。
# ちなみにコンテキスト保存領域とタスク用のスタック領域は、ヒープ領域からnewで取ってmap<taskid_t, tcb_t*>に突っ込んでいます。

タスクが終了した後、次の割り込みが掛かるまでの空ループ時間が無駄だなぁと思ったので、どうしようかと思ったのです。
強制的に次のタスクにジャンプさせようかと思ったけど、飛ばす準備に入っている間に割り込みが掛かったらイヤン。
 (2009/01/16 07:17:41)
名無しさん >
試しに書き始めましたが、普通に垂直同期待ち後に積んだ分を処理、
で足りてしまうので、プリエンプティブ〜が必要な状況無しで迷走中。
偶に(?)話が出てくるSTGゲームに載せるのだと思っているのですけど...
#勘違いでしたらごめんなさい

>GBA で複数モジュールを
拙作エミュでは、オーバーレイとジャンプアドレス書き換えでそれっぽくしました。
リロケータブルではないので話題からズレてますが、楽な手段でアリですよね?
 (2009/01/24 04:40:36)
>
普通に(GBAで)ゲームを作るならプリエンプティブマルチタスクなんて要らない気がします。垂直同期待ちで充分。
プリエンプティブマルチタスクを実装したのは、単に技術的な興味からやりました。

ところで僕は逆に、オーバーレイの使いどころが思いつかなかったりしますね。
ゲームだと1フレ内に何度も置き換えるわけにはいかないし、しかしIWRAMに置くからには速度が要求されるんだろうし、
となるとシーン切り替え時に関数を置き換えるのだろうと思うけど、シーン切り替えで置き換えられるクリティカル処理ってそんなに無いような……。
 (2009/01/24 21:50:07)
名無しさん >
0x03000000:core
0x03001000:[MMC][VRC][...]共有領域1 ここは初期化時にロード。
0x03002000:[sub1][sub2][...]共有領域2
フレームの頭で分岐フラグは決定していて、(n * 240ライン)回の分岐判定があったので
垂直同期待ちの空き時間に先に[sub(n)]を入れ替えておく、な感じです。
loop:240回   →     loop:240回
ldr r0, flag        bl sub1 or sub2
adr lr, 1f         処理
cmp r0, #0x00       bl sub3 or sub4
beq sub1          処理
b  sub2          b loop
1:処理
ldr r0, flag
adr lr, 1f
cmp r0, #0xFF
beq sub3
b  sub4
1:処理
b  loop
メモリに余裕が無かったので、可能な限り空けておく方針でした。
#EWRAMに置いても全く問題無いのは内緒(^^;
 (2009/01/26 00:45:58)
>
ああ、ようやっと、どなただか分かりました。(拙作エミュ〜の時点で気づくべきだったかも)
名前が変わる前(VRC6とDPCMに対応した頃かな)のソースを拝見したことあります。確かにapuとmapperをそれぞれOVERLAYで切り分けてますね。
自己書き換えやってるのは気づかなかったけど、そういえばメモリに展開したコードは書き換え可能なんですよね。ちょっと目から鱗かも。
 (2009/01/26 13:56:40)

2009/01/13

_ GBA にプリエンプティブ☆マルチタスクを実装する
そもそもの発端は、読み込みしながらゲームが開始してしまうソフトって何気に
凄くね? スレッドでも使ってるんかね、という話題から、そういや俺スレッド
って使ったことないなーと思ったので使ってみることにしたのだが、GBA の非公
式環境にはスレッドなどというものは用意されていないので(探せば RTOS 的な
実装は出てくるけど、見なかったことにして)原始的なプリエンプティブ・マル
チタスクの再車輪からスタートすることになったわけだ。(動機が長いよ)

まずはガムシャラに実装してみた。

1. 割り込みが掛かる 2. コンテキストを TCB (TaskControlBlock) に保存する 3. スタックポインタを巻き戻す 4. TCB を切り替えてコンテキスト復元
割り込み復帰処理をせずに回すパターン。スタックがどんどん積まれてしまうの で、スタックポインタを直接操作してみた。アセンブラだぜ!という無駄な満足 感は得られたが、タイマ以外の割り込みにも対応したい等の拡張を施すのは大変 そうだ。 そこで、ちょっと考えて実装を変えてみた。
1. 割り込みが掛かる 2. コンテキストを TCB に保存 3. 割り込みがタイマかどうかを調べる   ・タイマ割り込みなら TCB を切り替え、TCB の復帰レジスタを書き換える    (実際には、あらかじめ書き換えておく)   ・他の割り込みなら TCB を切り替えずに処理し、4.に移行する 4. コンテキストを復元 5. 割り込みから復帰
これなら他の割り込みが入っても綺麗に流すことが出来る。素晴らしいね。が、 それぞれのタスクのコンテキストを引き継いで処理するため、スタックサイズが 心もとない。他の割り込み用にスタック領域を設けるなど、もう一工夫必要かも。 RTOS 的もしくは POSIX 的なタスクスケジューラを組んでみたい気もしてきたけ ど、とりあえず寝かせておこうかしら。あと、よく分かってないんだけど、多分 mutex とかも必要になるよなぁ。タスク間通信も必要だ。やること一杯あるな。 それと、BIOS に戻るための復帰アドレスをスマートに得る方法がどうしても思い つかなかった。結局、最初のタイマ割り込みで保存した main() 関数のコンテキ ストからタスクのコンテキストにリンクレジスタをコピーしてしまった。おかげ で以降のタスクでも延々と直前からのコピーが発生している。かなり無駄なので なんとかしたいところ。 -- 前回、企業秘密がどうのと書いてしまったけど、このドメインでそんなことを書 くとあらぬ誤解を生んでしまいそうだと気づいたので弁明しておくと、当サイト は実在する企業とは無関係の、ただの個人日記ブログ兼ネタ帳です。一発ネタ多めで。

2009/01/11

_ 割り込み時にリンクレジスタをひっこ抜く
GBA の例外ベクタは BIOS に割り当てられているので割り込みから SWI まで全
部、一度 BIOS へと飛んでいく仕様になっていて、んでもって割り込みの場合は
その先でリンクレジスタを退避してくれちゃってるもんだから、アレが出来ない。
「アレ」が何かはモロバレなような気もしないではないですが、企業秘密なんで
伏せておきます。

@ VisualBoyAdvance pseudo-BIOS (IRQ Exception) @ @ 0000-0018: b $0000-0240 @ @ 0000-0240: stmfd sp!, {r0-r3,r12,lr} @ 0000-0244: mov r0, #0x04000000 @ 0000-0248: mov lr, pc @ 0000-024c: ldr pc, [r0, -#0x4] @ @ 0000-0250: ldmfd sp!, {r0-r3,r12,lr} @ 0000-0254: subs pc, lr, #0x4
IRQ ハンドラに飛んだ後、BIOS に戻るようリンクレジスタが上書きされちゃって いますなー。(VBA の似非 BIOS コードを貼りましたが、実機も同じ挙動になり ます) なもんで、IRQ ハンドラに飛ぶ前にリンクレジスタをどこかに保存しなおす処理 を間に挟んであげる。
ldr r0, =lr_pool add r1, sp, #20 ldr r2, [r1] str r2, [r0] b IRQ_Handler
ついでに、その他のコンテキストも保存しちゃってもいいかもしれない。
_ STG NEWSとか(9) スパムが凄いよ
風邪引いてダウンしてた都合で気づかなかったんですが、正月明け、具体的には
1月8日からスパムが急増したようですなー。



例によって、アクセスログから POST メソッドのみを抽出してみた画像ですが、
こんなのが旧年中は1日 100 件近くあったんですが、今年からは 400 件に増や
したんだそうですが、まぁ幸いぼくわ天才うぇぶぷろぐらまーなので全部弾いて
いますがね。

どうやら referer の頭が http://:// となる新種のスパマーが現れたようです。
こんな分かりやすい特徴を残してどうするの。あと、User-Agent が全て同一な
のはどーにかならんのかと、他人事ながら思ったりします。ぼくが天才うぇぶぷ
ろぐらまーというよりは、むしろスパマーが(中略)ということのようですね。
残念。ぼくは天才じゃなかった。

2009/01/06

_ ゲーム機のノンインタレをレコで録って60fps化する
何故は分からないけど、ゲーム機のムービーを PC で云々したい場合、今までは
キャプチャするか……という発想しか出てこなかった。しかし、レコがあるなら
それで録って焼いた DVD を PC に読み込ませればよいという話だわ。PC でのキャ
プチャより安定して録れるし、いいかもしれない。

とりあえず作業手順を残しておこうかしら。

DVD-RW からコピーした .vob ファイルを DGIndex で読み込んで、d2v で保存す
る。avisynth で適当な .avs ファイルに
MPEG2Source("source.d2v") DGBob(order=1,thresh=0)
とか書いて bob (60fps化)し、 aviutl や VirtualDub で読み込んでエンコード するだけ。PC で見るだけなら crop した後 resize してもいいかもしれない。 youtube にアップする場合は bob より blend の方が良いのだけど、ノンインタ レースのソースだと少し残念なことになる。まぁ 60fps 化したものをアップし て(youtube 側の再エンコード・fps 調整によって)点滅半透明がものすごく残 念なことになるよりはマシなのかもしれない。 まぁそんなこんなで録った動画がコレ。アップしたのは昨年だけども。 Galaxy Force Neo Classic 16:9 (1/2) Galaxy Force Neo Classic 16:9 (2/2) ううん、眠い画質だなぁ。 折角なので1面だけ、HD画質でもアップしてみた。 http://www.youtube.com/watch?v=GRxGvzbZcas&fmt=22 元のゲームの解像度がせいぜいワイド・プログレなのに HD にして意味あるの? と思われるかもしれないが、意味など無い!と言わざるを得ない。

2009/01/05

_ Wonderflって現時点で最もオンラインベーマガに近い環境なのでは
http://d.hatena.ne.jp/ABA/20090105#p1

少ない行数に収めるためにコンパクト化云々してたり、割と好き勝手にforkされ
ている様子を見ていると、そんな気がしてくる。

2009/01/01

_ 月末から年末にかけて
大掃除をしていたら PS2 メモリカードを読み書きする装置を発掘してしまい、こ
れを使って何か面白いことが出来ないかと調べていたら、タイムリーなことに純
正 HDD 付き BB ユニットが某中古ハード取扱店にて 1,500 円で売られているの
を入手してしまい、仕方無いので mips-toolchain などを用意してみたら、あれ
よこれよと言う間に homebrew 環境が整ってしまった。

PS2 はかなりクセがあって面白そうなのでいずれ手をつけたいとは思うんだけど、
自分のスキルを考えると、まぁたいしたことは出来ないだろうなぁ。マニュアル
目当てに PS2 Linux が欲しいような気もする。
_ そうか。もう年末なんだな。(・ω・)
(;´ω`)=3

最新
2010 | 01 04
2009 | 01 02 03 04 05 06 07 09 10 11 12
2008 | 01 02 03 04 05 06 07 08 09 10 11 12
2007 | 02 03 04 05 06 07 08 10 11 12
2006 | 01 02 03 04 05 06 07 08 09 10 11 12
2005 | 01 02 03 04 05 06 07 08 09 10 11 12