正直日記



2008/03/25

_ 続々・スプライトダブラのスプライトの優先度を考える
続きは明日とか書いておきながら三日も空いてしまったけど気にしない。


(中央部、奥にあるスプライトが貫通して見えている)


(貫通しなくなった)

ポストギャップを設けることで優先度破綻の問題は解消した。が、設けたギャッ
プの分だけ転送量が増えて遅くなるし、表示できるスプライト数も減ってしまう
ため、どうにも芳しくない。

優先度破綻は割り切ってしまった方がいいかもしれないなぁ。

2008/03/22

_ 続・スプライトダブラのスプライトの優先度を考える
というわけでボスの攻撃パターンを作っていたが、例の雑魚キューブを出したら
案の定、奥にあるはずのスプライトが手前まで貫通してしまった。



--

ラスタ分割バッファA・Bの中に、スプライトが優先度順で下記のように格納され
ていると

バッファA:1111122222233…
バッファB:1112222333…
       ↑  ↑

   OAM:11111112122222232323233…
         ↑   ↑↑↑
矢印の部分で優先度が破綻したよ。間に合わなかった。 とにかくそれじゃ困るので……
バッファA:1111122222233…
バッファB:--1112222--33…

   OAM:1-1-111111222222222-2-3333…
ギャップを設けて、揃えたらどうかしら。 でもギャップを設けるためには、分割バッファ内で優先度ごとのスプライト数を 数えておかなくてはならず……。 という所まで考えた。結果は明日!(たぶん)
_ ゲームやり中年
というわけでPencilBulletを遊んでいた。
どことなくアイレム臭がするが、やはり相当難度が高く、4面以降はガッチリと
パターンを組まないと全然先に進めない感じだ。50回ほどコンティニューしたが
未だに5面が越せていない。

画面下方に張り付いて壁の変形を待っているときに、後ろから編隊が飛んでくる
嫌がらせが酷くてオラ、ワクワクしてきたぞ。
_ ソース読み厨房
exceptionのオブジェクトはメッセージドリブンになっていて、スレッド毎に用意
したキューへ衝突などのメッセージを溜めていき、全ての判定が終了した後メッ
セージを投げてるみたい。(自分で把握したみたいに書いてるけど、実は作者の
人に聞いた受け売りです。でもあらかじめ知っていたおかげで、その部分は割と
スラスラ読める。ありがたや)

Game::Update辺りから見ていけばいいのかな。結構階層深いな……えーと、コリ
ジョンテストがグリッド分割で、キューブからバウンディングボックスを、えっ
更にバウンディングボックスで……?
あ、あとでじっくり読む(かも)。
_ ソース読み中毒
exceptionPencilBulletのソースを読んでいるよ。

どちらのソースも「敵の動作や道中をコードで直接記述している」点で共通して
いて、なかなか見応えがある。後者のPencilBulletは機械生成っぽい感じもする
けど、もし手打ちだとしたら結構しんどかったんじゃないかなぁ。

追記:やっぱり機械生成だったみたい
_ tab! tab! tab!
うへぇマジだ。



「ファイルいっぱいあるけど表示すんのかよ?」と聞いてくる前にファイル数を
環境変数PATHから検索するので、PATHの登録が多いとめっちゃ時間かかるな……。

2008/03/12

_ boost::poolを使ってみない
boost::poolでもいいんだけど、Listとメモリを取り合って断片化しているよう
だったので、あらかじめ静的配列を用意すればいいんじゃーんってことで、差し
替えてみた。

template<int N, int M>
class SeitekiHairetsuAllocator {
private:
  struct { int memory[1+(N/4)]; } block[M];
  void* empty[M];
  int used;
public:
  SeitekiHairetsuAllocator() {
    used = 0;
    for (int i = 0; i < M; ++i) empty[i] = &block[i];
  }
  void* malloc() { void* p = empty[used]; used++; return p; }
  void free(void* mem) { used--; empty[used] = mem; }
};

namespace {
  SeitekiHairetsuAllocator<TASK_SIZE, 1024> task_pool IN_EWRAM;
}
空き配列の管理にポインタを使っているのが無駄に感じられたり、あと配列を最 後まで使い切ってしまったときの配慮を全くしてなかったり、全然関係ないポイ ンタをfreeされたときどうすんの?とか色々恐ろしいけど、取りあえず動いてい るようなので一人で感動してた。世界が感動で包まれていたよ。
_ タイル消費量を自動で見積もる
自分の目でキャラ化けを確認するしかないと思い込んでいたけど、よく考えたら
スプライト用タイルVRAMの空きが無かったときのための処理は組み込んであるわ
けで、そこに到達した時点でログを出力するようにすれば良かったんだね……。

2008/03/11

_ boost::poolを使ってみる
先日の調整君を改良してみる。
普通にnew/deleteすると、オブジェクト90個を境に処理落ちが始まってた。



boost::poolを使ってみたら、190個までは処理落ちしないようになった。



しかし、速度的に改善してはいるんだけど、operator newともども初めて使うの
で、物凄く不安だ。

static const size_t TASK_SIZE = sizeof(Task) + sizeof(int) * 16;
static boost::pool<boost::default_user_allocator_new_delete>
  task_pool(TASK_SIZE);

static void* 
Task::operator new (size_t const size)
{
  return task_pool.malloc();
}

static void 
Task::operator delete (void *p, size_t size)
{
  memset(p, 0xff, TASK_SIZE);
  task_pool.free(p);
}
こんな簡単な実装で動いちゃっていいの? object_poolではなくpoolを使ってしまうあたりがタスクシステム脳っぽいかも。 ついでにオブジェクトの管理リストにfast_pool_allocatorを使うようにしたら 更に速度が改善した。
  std::list<Task*, boost::fast_pool_allocator<Task*> > tasklist;
各オブジェクトの最大生成数を決めておいて、最初にresize()する方が、よさげ ではあるけど……。 それと、ようやく Right Angle Brackets 問題の深刻さ(としょーもなさ)が分 かったよ。

2008/03/09

_ フラッシュバックと音楽のある生活
食べ終わったあとの食器を洗っているときなど、手は動いても脳は殆ど使わない
ルーチンワークをしているとき、過去にやらかした恥ずかしい出来事を、例えば
「好きになった女の子に告白しようとして、緊張からうっかり変なことを口走っ
てしまう」とか、かなり遡ると「小学校の担任(男)をお母さんと呼んでしまい
からかわれる」とか、そんなどうでもいい恥ずかしげなことがフラッシュバック
しては、きええええええええええええええええええええええ
と叫びたくなってしまう。

このまま食器を洗い続けると、いずれ廃人になってしまう……。そのうち男は、
考えるのをやめた(はずはないっていうかジョぜぇ)

要は脳に刺激が無いのがいけないので、音楽を垂れ流すことにしたら、この問題
はあっさり解消してしまった。音楽携帯が一人の男の危機を救った。


先週のOL進化論に同様のネタがあって、みんな同じなんだなぁと思った次第。
_ テクスチャ消費量を人力で見積もる
けっきょく3/9に間に合わなかった!

道中をまったり作っているのだが、僕は爽快感重視派なので「ここはモリモリと
敵を出して、モリモリ倒せると爽快だよねー」というポイントをモリモリと作り
たくなってしまう。

ある敵のアニメパターン数が6枚だとして、その敵をモリモリと出すと、同時に
6枚分のパターン全てをVRAMに載せておかなきゃならない可能性がある。載らな
かった分はキャラ化けしたあと爆発する。いや爆発はしないけど。

そういうわけで、各キャラごとのアニメパターン数とパターンサイズ、平均滞在
時間を洗い出してメモしておき、その組み合わせを考慮した上で道中を組んでい
る。


しまったほとんど同じ内容の日記を過去に何度か書いてた。
まったく、学習しない人ですね。

2008/03/05

_ 4.3-20080228版 devkitARM を作りなおしてみる(4)
続きです。

ひょっとして ld で section overlap する問題と objcopy で ROM イメージが
肥大化する問題の原因は一緒なのでは?と思っていたがどうやら違うようだ、と
思っていたのだが、どうやら、やはり根本の原因は同じようだ。

実は、ld 2.18 で OVERLAY の挙動も変わっていたらしい。


ここからは僕の妄想なので例によって読まなくていいです。

--

NEWS から引用しようと思ったら載ってなかった。まだ undocumented かしら。
ついでなので LMA のところを引用しておこう。

* The default output section LMA has changed for allocatable sections from being equal to VMA, to keeping the difference between LMA and VMA the same as the previous output section in the same region. This is a more useful default when using overlays and other cases where you specify an LMA differing from the VMA for some sections.
今からすれば、最初にこれを読んでおけば良かったんだよね。まぁ読んでいても たぶん何のことか分からなかったと思うけど。 OVERLAY に話を戻すと、リンカスクリプトでは以下のように記述されている。
OVERLAY ALIGN(4) : NOCROSSREFS AT (__iwram_overlay_lma) { .iwram0 { *(.iwram0) . = ALIGN(4);} .iwram1 { *(.iwram1) . = ALIGN(4);} .iwram2 { *(.iwram2) . = ALIGN(4);} .iwram3 { *(.iwram3) . = ALIGN(4);} .iwram4 { *(.iwram4) . = ALIGN(4);} .iwram5 { *(.iwram5) . = ALIGN(4);} .iwram6 { *(.iwram6) . = ALIGN(4);} .iwram7 { *(.iwram7) . = ALIGN(4);} .iwram8 { *(.iwram8) . = ALIGN(4);} .iwram9 { *(.iwram9) . = ALIGN(4);} }>iwram = 0xff __ewram_lma = __load_stop_iwram9;
ld 2.17 までは、リンクすると下記のように、いちいち全てのセクションに対し て __load_stop_HOGE が出力されていた。
08000468 A __load_stop_iwram0 08000468 A __load_stop_iwram1 08000468 A __load_stop_iwram2 08000468 A __load_stop_iwram3 08000468 A __load_stop_iwram4 08000468 A __load_stop_iwram5 08000468 A __load_stop_iwram6 08000468 A __load_stop_iwram7 08000468 A __load_stop_iwram8 08000468 A __load_stop_iwram9
だが、ld 2.18 の吐いた map ファイルを見てみると、これしか出力されてない。
08000454 A __load_stop_iwram0
で、__ewram_lma に __load_stop_iwram9 を代入しようとしているのだが、存在 しないのでとりあえず現在地を代入している。のかしら、ちょっと分からんけど。 存在しない場所を指していたらエラーか、せめてワーニング吐いて欲しいよなぁ。
03000054 A __ewram_lma
とにかく、結果的にこいつが RAM 領域を指すようになったせいで、objcopy が RAM 領域から ROM 領域に至るまでを吐くようになったらしい。__ewram_lma か ら ROM 終端アドレスまでのサイズを計算してみたら、バイナリサイズとピッタ リ合致した。やった!やったよママン! というわけでリンカスクリプトを修正することで ld に起因する問題はおおよそ 解決したよ。俺たちの戦いはこれからだ! (これにて ld 2.18 編は終わります。柏先生の次回作にご期待ください)
_ 4.3-20080228版 devkitARM を作りなおしてみる(3)
ひょっとして ld で section overlap する問題と objcopy で ROM イメージが
肥大化する問題の原因は一緒なのでは?と思っていたがどうやら違うようだ。

先に結論から書いておくと、ld の方は bug-binutils 及び bugzilla に、ほぼ
同じ問題が報告されてた。よーするにリンカスクリプトの解釈が ld 2.18 から
一部変更になった、らしい。

bug-binutils : [Bug ld/5785] New: Spurious "section xxx overlaps section yyy"
bugzilla : Spurious "section xxx overlaps section yyy"


ここからは僕の考察がうだうだと、くどくどと書いてあるだけなので、読まなく
ていいです。

--

まず ld の方。
__attribute__ ((section (".iwram"), long_call))
この .iwram セクションは、ROM にコードの実体をおいて(LMA)、RAM にはロード する領域を設ける(VMA)ために、リンカスクリプトでその旨が記述してある。
MEMORY { rom : ORIGIN = 0x08000000, LENGTH = 32M iwram : ORIGIN = 0x03000000, LENGTH = 32K ewram : ORIGIN = 0x02000000, LENGTH = 256K } ... .iwram __iwram_start : AT (__iwram_lma) { /* foo */ } >iwram = 0xff __data_lma = __iwram_lma + SIZEOF(.iwram) ; .bss ALIGN(4) : { /* bar */ } >iwram __bss_end__ = __bss_end ; .data ALIGN(4) : AT (__data_lma) { /* buzz */ } >iwram = 0xff
bugzilla に投稿されているものとほぼ一緒な形態やね。 現象の理由も説明されているんだけど、ちょっと、いやかなり英語に自信が無い。 .iwram で指定した LMA を .bss が引き継ぐようになったため、おかしなことに なってるらしい?
.bss 0x03004794 0xf88 load address 0x08103ce4 .data 0x0300571c 0x89c load address 0x08103ce4
map 出力を見ると確かに、.bss を ROM 領域からロードしようとしてるんだよなー。 で、.data で指定している LMA が __data_lma なのだが、これが .iwram の終わ りを指しているため、同様に .iwram の終わりから LMA が継続している .bss と バッティングするってことかいな。 .bss の締めを AT> iwram に変更することで、エラー無しにリンク出来るように なった。 -- 次に objcopy の方。 ROM イメージが巨大( 83,936,992 bytes )になるのは、本来 ROM 領域に配置され るべき、なんらかのデータの実体が RAM 領域に配置されているため、RAM から ROM までの空間を吐いてしまっているっぽい。 RAM 0x0300:0000 〜 ROM 0x0800:0000 で 80 メガ( 83,886,080 bytes )になる。 int main() { return 0; } みたいなソースでも巨大なイメージになるので、他に リンクしているオブジェクト( gba_crt0.o crti.o crtbegin.o libsysbase.a )か、 リンカスクリプトに問題がありそう。 んで、リンカスクリプトの問題は先ほど解決したばかりなので、となると問題は オブジェクトにあるのか。あったらいいなぁって感じで、まだ調査してないです。 っていうか調査の仕方が分からないです。困る。

2008/03/02

_ 死んで覚える敵出現パターン
「パワーアップ中は敵との接触判定が無くなる」というフィーチャーを設けたら
絶対に「ここに着く前までにパワーアップしておかないと確実に半ダメ」みたい
なポイントを作りたくなると思うんだけど、そうしないのは、さすが親切設計と
いうか、勿体無いというか。
_ 4.3-20080228版 devkitARM を作りなおしてみる(2)
新たに ld 2.18.0 をコンパイルしてみたが、同じエラーが発生してリンクに失
敗するようだ。

ついでに cvs の devkitARM r22 (binutils 2.18.50 & gcc 4.2.3 & newlib 1.15.0)
もビルドしてみたがやはり同様だった。

いろいろ試してみたが、プロトタイプ宣言時に
__attribute__ ((section (".iwram"), long_call))
と指定して関数を IWRAM に配置すると、 bss 領域と data 領域が overlap する らしい。逆に言うと、セクションをまたがなければリンク出来るようだ。 これって組み込みの人には致命的なんじゃないの? 何か間違えてるのかな……。 あ、 -Wl,--no-check-sections で overlap チェックを無視して無理矢理リンク 出来るみたいだ。ろくなことにならなそうだけど……。 -- リンクが完了したあと
arm-eabi-objcopy -v -O binary hoge.elf hoge.gba
で ROM イメージを作るのだが、出来たイメージが巨大なファイルになってしまう。
hoge.gba 80.0 MB (83,936,992 bytes)
中を覗いても 0 で埋められているし、なんつーか、壊れてるなぁ……。 ROM イメージの生成はひとまず諦めるとして、エミュレータに elf ファイルを 食わせてみたら一応動いた。しかし点数やらなんやら表示系がおかしな値を示し ている。 BCD なのに何故 B とか表示されるんだろう? と思ったらハングアップした。駄目だコリャ、toolchain の新調は様子見だな。

2008/03/01

_ 4.3-20080228版 devkitARM を作りなおしてみる
早速、手元のプロジェクトでも再ビルドしてみるかと思ったら、リンクする段に
なって libsysbase が無いとか _sbrk がみつからないとかもーなんなのです!

_sbrk ってことは、どうやら newlib を configure する時点でしくじっていた
らしいな……と、libc の objdump を見ながら思うのだった。確かに、無い。

今更気づいたけど、buildscripts-20060724を再利用するよりも、CVSから持ってき
たスクリプトを再利用した方がよかったらしい。内容を眺めてみたら、libsysbase
を作るよう newlib の libgloss/configure にパッチを当てているみたいだ。

--

というわけで再ビルドしたら、今度はちゃんと libsysbase も作られているし、
その中に_sbrk が含まれているようだ。よかったよかっ……

h:/gcc/devkitARM/bin/../lib/gcc/arm-eabi/4.3.0/../../../../arm-eabi/bin/ld.exe: section .data [08103ce4 -> 0810457f] overlaps .bss [08103ce4 -> 08104c6b] collect2: ld returned 1 exit status
あれっ。困るなー。mapが出力されているので見る。
.bss 0x03004794 0xf88 load address 0x08103ce4 .data 0x0300571c 0x89c load address 0x08103ce4
なぜ .bss に load address がついてるんだー?そして何故、同アドレスですか? どうも ld 2.18.50 がおかしい気がする。本家 devkitARM の ld 2.17 とバイナ リを差し替えてみた。エラー無しでリンク完了。map 出力。
.bss 0x03004794 0xf88 .data 0x0300571c 0x89c load address 0x08103ce4
これが正しい姿なのだよ。しかし困ったな。
_ 4.3-20080228版 devkitARM を作ってみた
というわけで……

http://d.hatena.ne.jp/toge/20080229#1204238423

こちらをarm-eabiで確認したかったんだ。
比較対象が古いけど気にしない!

arm-elf-gcc -O3 -marm -S : gcc version 3.4.3
_Z3fooi: mov ip, sp stmfd sp!, {r4, fp, ip, lr, pc} subs r4, r0, #0 sub fp, ip, #4 sub r0, r4, #1 mov r3, #1 ble .L1 bl _Z3fooi mul r3, r4, r0 .L1: mov r0, r3 ldmfd sp, {r4, fp, sp, pc} main: mov ip, sp stmfd sp!, {r4, fp, ip, lr, pc} mov r4, #10 sub fp, ip, #4 sub r0, r4, #1 bl _Z3fooi mul r1, r0, r4 ldr r0, .L8 bl printf mov r0, #0 ldmfd sp, {r4, fp, sp, pc}
arm-eabi-gcc -O3 -marm -S : gcc version 4.3.0 20080228 (prerelease) (GCC)
main: .fnstart .LFB915: str lr, [sp, #-4]! .save {lr} .LCFI1: mov r1, #3620864 .pad #4 sub sp, sp, #4 .LCFI2: add r1, r1, #7936 ldr r0, .L7 bl printf mov r0, #0 add sp, sp, #4 ldr lr, [sp], #4 bx lr
いやー良かった良かった。ちゃんと畳み込まれてる。 定数が二つに分解されてるのがARMらしいね。  3620864 + 7936 = 3628800 ARMv4のイミディエイトは符号無し8ビット即値を4bit量ローテートなので、こう。  #3620864 = (221 << 14)  #7936 = (124 << 6) つか定数の分解って今まではあまりされてなかった気がする。何気に嬉しいかも。

最新
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