スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。


Ten little endian boys Part 2 (フォンノイマン・ボトルネックを回避したい)

前回の記事の続きです。

前回はリトルエンディアンマシンでビッグエンディアンマシンをエミュレートする際のフォンノイマン・ボトルネックの話で終わってしまったわけですが、X68000エミュレータであるkeropiがこれをどのように回避しようと頑張っているのか、今回は実際にソースを追っていきたいと思います。

まずはひっそりぃがxkeropiのソースを読んでいて、最初に「なんぞこれ?」と思った箇所です。x11/winx68k.cpp内のWinX68k_LoadROMs()という関数内ですが、X68000のBIOSデータiplrom.datの内容をメモリIPL[]に読み込んだ直後の以下の処理です。

        for (i = 0; i < 0x40000; i += 2) {
tmp = IPL[i];
IPL[i] = IPL[i + 1];
IPL[i + 1] = tmp;
}

おもむろにメモリIPL[]の内容を並べ替えています。
これは例えば「AA BB CC DD EE FF」というメモリ内容を「BB AA DD CC FF EE」といった内容に並べ替える処理を行っています。
はじめはビッグエンディアンのBIOS情報をファイルiplrom.dat上ではリトルエンディアンで記録していたので、元に戻しているのかと思いましたが、ソースを読み進むうちに、どうやら違うことに気が付きました。

実際にMC68000の命令をメモリからフェッチして、フェッチした命令の処理に分岐させる以下の箇所になります。x11/68kem.asm内の_M68KRUN:です。

_M68KRUN:
pushad
mov esi,[R_PC]
mov edx,[R_CCR]
mov ebp,dword [_OP_ROM]
(途中省略)
movzx ecx,word [esi+ebp]
jmp [OPCODETABLE+ecx*4]

いきなり80386アセンブリで申し訳ないですが、ひっそりぃもZ80のアセンブリしか知らないので、ノリで読んでいきましょう。
まずR_PCにはMC68000のPC(プログラムカウンタ)が格納されています。_OP_ROMにはたとえばPCがメインメモリ内のアドレスを指している場合にはメインメモリ構造体MEM[]の先頭アドレスが、PCがBIOS内のアドレスを指している場合には先ほどiplrom.datの内容を格納した、IPL[]の先頭アドレスが入っているようです。

要するに現在プログラムカウンタがBIOSのメモリ内にある場合には、C言語風に書くと以下のようになるでしょうか。

ecx = IPL[PC];

そして最後のjmp(ジャンプ)命令で、OPCODETABLEに格納された、実行したい関数のポインタ先に分岐しています。ecxレジスタが4倍されているのは、関数のポインタが4バイト長だからです。

と、さらっと書きましたが、元々「リトルエンディアン・マシンでビッグエンディアン・マシンをエミュレートしている」という前提を忘れてはいけません。例えば0x1234というビッグエンディアン・マシンのopcodeがあった場合、それはメモリ上では、0x12, 0x34の順で並んでいます。これをリトルエンディアン・マシンが

movzx ecx,word [esi+ebp]

のように普通にワード読み出ししてしまった場合、ecxレジスタには0x3412という値が格納されてしまうのです。ですから、読みだした0x3412は上位バイトと下位バイトを入れ替えて0x1234に戻す、という処理が本来は必要なはずです。が、それをしていない。

お気づきになりましたでしょうか。keropiではメモリの内容をあらかじめ故意に並べ替えておくことで、リトルエンディアン・マシンがビッグエンディアン・マシンをエミュレートする際のフォンノイマン・ボトルネックをなるべく減らそうとしているのです。
メモリ内容が「AABBCCDDEEFF」と本来なるところは、「BBAADDCCFFEE」とあらかじめ並べ替えておけば、読みだす時には並べ替える必要がなくなるわけです。

もちろんメモリの並びを故意に変えるわけですから、常にそれを意識しなければなりません。メモリにワード単位で書き込むときには、常に上位バイトと下位バイトを入れ替えて書き込まなければなりません。
バイトアクセスする時も注意が必要です。アドレス0x100000の1バイトの内容を読み書きしたい場合は、0x100001のアドレスの内容を読み書きしなければなりません。

長くなりましたが、X68000のMPUであるMC68000は命令フェッチをワード(2バイト)単位で行うので、このワード単位(2バイト単位)の読み込み処理をなるべく最小のステップで行う、という観点でチューニングをしていることになります。その分ワード単位の書き込み、バイト単位の読み、書きについては逆に性能劣化します。それを差し引いてもエミュレータの処理全体でみた場合、今回のチューニングが有効なのでしょう。

ひっそりぃはまだkeropiの68000コアとPSP用CPS2の68000コアしか眺めていませんが、どちらも今回のチューニングを行っています。もしかしたらリトルエンディアン・マシン用の68000コアではメジャーなチューニング法なのかもしれません。


Comment

コメントの投稿


管理者にだけ表示を許可する

Trackback

http://hissorii.blog45.fc2.com/tb.php/215-bf3ce50b

«  | HOME |  »

プロフィール

ひっそりぃ

Author:ひっそりぃ
Twitter:@hissorii_com
GitHub:hissorii


月別アーカイブ


最新記事


カテゴリ



最新コメント


最新トラックバック




RSSリンクの表示


Amazon


QRコード

QRコード

Amazon


ブログランキング

ブログランキング【くつろぐ】
にほんブログ村 ゲームブログ×PlayNCBlogへ

メールフォーム

名前:
メール:
件名:
本文:


カウンタ


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。