#8 メガドラDAC実装してみた。
メガドラDAC実装したよ「実験版DGEN」のA09とA10で聞き比べてみて。(別館の一番下にある)。 (2006-02/08) ■管理人がギャースカ言ってるメガドラのDAC特性を実装してみた。(別館にあります) 1.中音が強調されて聞きずらい。 これはPSPのスピーカーの周波数特性ですから、なんともなりませんね。 デジタルフィルター等実装する気はない。ただし、もしかしたら、SCEのライブラリで、 なんとかなる可能性はある。(PSPのスペックが判ってないだけで、 既にフィルター入ってるかもしれないじゃん) 2.時々変なノイズがはいる。 これは、エミュの速度がとろいから、データーを取りこぼすのが原因です。 現在、音バッファが、基本的に一フレーム分しかない。(実装の都合で2フレーム分とって、 ぎったんばっこんやってる。) PSPで聞くと、多少聞きづらい所(中音の強調)はあるけど、リニア特性に比べたら遥かにましでしょ?
■今日はメモリの話。 っていうか’-lc’の話。 過去の日記を読むと、CDに焼いてバックアップ取りました。だの、進めたんだけど、コンパイルエラー ないから、PSPに転送して実行したら起動できなくて、ソースを数時間戻した。だのあきらめただの。 ゴミに捨てた。だの。 そんな記述が、煩雑に出てくる筈。
全ては’-lc’のせい。(c)ルパン V.S. クローン(のマモーの音声で読む)
とにかく理屈上は正しい筈、なのに動かない。エラーも出ない。全て’-lc’のせい。 すわっ!エンバグかっ。 管理人、人間だし、人間は間違える生き物だし、間違えた場合に殆どは気がつくけど、 100%完全に気がつくとは限らない。 つまり、間違えるのがあたりまえ。 これは、人間の特性なんだから、どうこう言っても始まらない。
そおいう特性がある。と認識して、対抗手段を講じれば良い筈。
管理人が用意した、対抗手段は数知れずあるが。 基本的には、
「あき、らぁめがぁ~かんぢぃん」(c)プップクプー(のつぼ作りの人の音声で読む)
なんてね。(あながち冗談でない所が恐ろしい) それならば、「あきらめられる様にする為の仕組み」を作れば良い。
CDに焼く。HDDやPCが壊れてもOK. WEBにUP。WEBのサーバーが壊れなければOK.
なんてこった。別館は単なる外部ハードディスクじゃん。 ミラーリングしてるから、えーとRAID0+1かな。(嘘つけ) まあいいや、所詮2~3時間ずつしか作業しないし。 動かなくなっても、まあ2~3時間ぐらいいっかって言って全部破棄して元に戻してた。
もう、そんな苦労とは、おさらばだ!(c)管理人(心の声で読む)
’-lc’外したら、何処弄っても、そんな事(コンパイルOKで起動しない)はおきなくなった。 ’-lc’のばかーーーーーー。
あーーすっきり。 ってな訳で、今迄ちょっと弄るとすぐ動かなくなる。メモリ関係をいじって見た。 っていうかまともにソース(読めないが)読んだ。「src¥cpp¥mem.cpp」 古い。古臭い。あと、訳わからん。(aoo3はjoypad1、aoo5はjoypad2) 5年前の基準と比べても、古臭いソースだ。実験の匂いしかしない。
■5年前の基準データ(MAMEのソースより) /* Gen I/O */ #1は 方向と B、Cボタン(マークⅢ互換の為) #2は(方向と)スタートとAボタン(確か方向も読めたと思う。自信がないが) /* cgfm info $A10001 Version BIOSが見る(リージョンビット) $A10003 Port A data ←aoo3 1P用ボタンや方向のデータ8BIT分(切り替えて#1、#2どちらか読む) $A10005 Port B data ←aoo5 2P用 $A10007 Port C data $A10009 Port A control 1P用、ボタンデータ(#1と#2)を切り替える。 $A1000B Port B control 2P用 $A1000D Port C control 以下は通信ポート $A1000F Port A TxData いらん $A10011 Port A RxData いらん $A10013 Port A serial control いらん $A10015 Port B TxData いらん $A10017 Port B RxData いらん $A10019 Port B serial control いらん $A1001B Port C TxData いらん $A1001D Port C RxData いらん $A1001F Port C serial control いらん */ リージョンビット詳細。(本体を空けると、このポートに直結しているジャンパピンがあった。(D6、D7) 全シリーズ共通。D0~D3はおそらくVDPのチップ番号。D5はメガCDを繋ぐと0になる。 D4はおそらく未使用(Unused/Resurved)ではなくて、VDPが正常なら0。) /* Charles MacDonald ( http://cgfm2.emuviews.com/ ) D7 : Console is 1= Export (USA, Europe, etc.) 0= Domestic (Japan) D6 : Video type is 1= PAL, 0= NTSC D5 : Sega CD unit is 1= not present, 0= connected. D4 : Unused (always returns zero) D3 : Bit 3 of version number D2 : Bit 2 of version number D1 : Bit 1 of version number D0 : Bit 0 of version number */
とにかくLONGはゲシっと削除。(ちゃんとWORDとBYTE作ってあればいらん) (例えば、WRITE) void md::misc_writelong(unsigned a,unsigned d) { misc_writeword(a ,(d>>16) ); misc_writeword(a+2,d&0xffff); } あーすっきり。(680x0プログラマなら、LONGだけ特別な仕組みなぞ、ありえない事に気が付く。 BYTEとWORDは多少違いがある。(実は殆どないが))
懸念だったZ80のミラーリングもサポート。(注:2000年代のメガドラエミュでは常識) (0x0000-0x1fff)と(0x2000-0x3fff)は同じ。(ミラーリング) void md::z80_write(unsigned int a,unsigned char v) Z80はBYTEのみだぉ。 { if( a < 0x4000 ){ z80ram[(a&0x1fff)] = v; } else if( a < 0x4004 ){ myfm_write((a&3),v,1); } else if( a == 0x6000 ){ write_z80_bank(v); } else if( a == 0x7f11 ){ mysn_write(v); } else if( a >= 0x8000 ) { <ここから先はバンク切り替え> 以下略
そんで、Z80(のメモリ)ちやんと作ったから、68000から気兼ねなく呼ぶ。 void md::misc_writebyte(unsigned a,unsigned d) { if( a > 0x00dfffff ){ ram[(a^1)&0xffff] = d ; return ; } ○書き込みだからRAM優先 else if ( a < 0xa00000 ) //MAX_ROM_SIZE) ○ROMに書くのはないんだけど。 { このエリアの書き込みは、 save_update = 1 ; ←SRAM更新したつ SRAMの事を意味している。 rom[(a^1)] = d ; return ; } else if( a < 0x00a08000 ) /*shered Z80*/ { z80_write((a&0x7fff),d); ←あるもんは、使おう。 } else { 以下略
ちなみにWORD(つまりshort)は、 void md::misc_writeword(unsigned a,unsigned d) { 中略 // else pass onto writebyte misc_writebyte(a ,(d>>8)); misc_writebyte(a+1,d&0xff); }
READも似たようなもん。まだ訳わからんの「パッド関係と」「調停関連」残ってるけど、 結構すっきりしてきた。(まだまだ) それにしてもここまでピーーーーだとは、知らんかった。 すべては’-lc’のおかげ。 感謝感謝なむー。(2006-02/08、14:00)
メモリ乗せ変えたんで、「BF03チェック」やってみた。 ずっと前(MUSASI2.0A/GCC4.0.0)
| OFF | 79~80fps | 
| 補間付5512kHz | 72~73fps | 
| 補間付11025kHz | 70fps | 
| 22050kHz | 65~66fps | 
| 44100kHz | 60~61fps | 
| OFF | 80fps |  = | 
| 補間付5512kHz | 73fps |  = | 
| 補間付11025kHz | 70fps |  = | 
| 22050kHz | 64~65fps |  -1 | 
| 44100kHz | 54fps |  -6~-7 | 
何故44100だけ重いんだろ。DACのテーブル分はまあ吸収できたかも。 っていうかBFじゃあDAC使ってないし。違う方法のチェックもしとけば良かったかも。
今日(MUSASI2.XX/GCC4.0.0)「A12」
| OFF | 83fps |  +3~4 | 
| 5512kHz | 75~76fps |  +2~3 | 
| 11025kHz | 73fps |  +3 | 
| 22050kHz | 68~69fps |  +3 | 
| 44100kHz | 60fps |  0~-1 | 
線形補間とって、インテル変換工夫しただけ。
■インテル変換工夫した。 #if 000 #define GET_WORD( src ) ((*((unsigned short*)src) << 8) | (*((unsigned short*)src) >> 8)) #else /* PSPではこっちの方が軽いじぇ。 */ static inline int GET_WORD(unsigned char *src) { return (src[0] << 8) | src[1]; } #endif どおも、PCのRISCと違って、PSPのRISCはシフトが苦手らしい。 PCのRISCはシフトが異常に速いから、ああいうソースになってる。 がPSPのシフトはそこまで速くない。多分ね。 その分、PCのRISCでは、既に非実用的になってきている。「char」がPSPでは使えるっぽい。 (場合による)PCだと、charで書いてある所をintに直すだけで、速度がアップするの常識なんだけど。 PSPでその技は使えない。逆にcharで足りるんだけど(フラグとか)PCの場合charよりint(32bit)の 方が速いからっていって、intにしてある場合が(PCのソースは)ある。 これをcharに変更して試してみるのも、いいかもしれない。(場合による) align関係(の速度)はどおいう事になってるのか現段階では判らない。
上記のマクロは何をしてるのか動作を補足しとく。 上のタイプはショートでフェチ、が2回。ショートのシフト2回。OR1回。 下のタイプはキャラでフェチ、が2回。ショートのシフト1回。OR1回。アドレスインクリメント1回。
現実に下の方が速くなってるんだから、普通に考えれば、 キャラのフェチ、が早いか、ショートのシフトがとろいかだろ。 或いは、キャラで内部レジスタ(もしくはキャッシュ)を消費しない可能性もあるが。
でも、現実的に考えてシフトがとろいと考えるのが一番ありそうな想定だと思うんだか、如何がかな?
■線形補間とった。 switch(F2612_ddd){ case 3: *((unsigned short*)bufR++) = rt; *((unsigned short*)bufR++) = lt; *((unsigned short*)bufR++) = rt; *((unsigned short*)bufR++) = lt; *((unsigned short*)bufR++) = rt; *((unsigned short*)bufR++) = lt; *((unsigned short*)bufR++) = rt; *((unsigned short*)bufR++) = lt; /*no break;*/ case 2: *((unsigned short*)bufR++) = rt; *((unsigned short*)bufR++) = lt; *((unsigned short*)bufR++) = rt; *((unsigned short*)bufR++) = lt; /*no break;*/ case 1: *((unsigned short*)bufR++) = rt; *((unsigned short*)bufR++) = lt; /*no break;*/ case 0: *((unsigned short*)bufR++) = rt; *((unsigned short*)bufR++) = lt; /*no break;*/ }
なんか知らんが、悪さしてたみたい。(ルーチンが)あるだけで駄目なんだよ、きっと。 (先読みキャッシュもしくはalign)
駄目だな、ついオタクなネタにはしって。一般人にはついてけないかも。 この辺とか(パフォーマンスとか)考えられる様になったのは、すべて’-lc’を取っ払ったおかげなんだよ。 不要なルーチンがしがし削除してんのに、ガンガン速度が低下する状態では、何もできませんって。 あと、CPPのクラスライブラリをひとつのOBJに閉じ込めた事も大きい。これやんないと、リンカを疑いだして、 訳、判んない事になるのは明白。これも大きいなぁ。 現状サウンドが重い事がはっきりしているので、これをなんとかすればなんとかなるかも。
「A12」は、現状FSKIP1で5512kHzかOFFなら60fpsぐらいの表示になって、秒間30コマ書くゲームもある。 (どうせPSPの液晶は中間色の反応速度がない。明暗差がある場合は速い) でも、音悪すぎ。うるさいから下にタオルなど詰めで誤魔化すか、11025にして、少しとろいのは我慢するか。 どっちかだな。もちっと速くしないとSFCならともかくメガドラは実用的には遊べんなぁ。 いずれにせよ、遊ぶだけなら他のエミュで。まだ現実的ではないです。
PC(DOS/V)のRISCでは多少効果のあった手法。ループ前にアドレス加算を試してみた。 が、逆にPSPでは遅くなった。逆効果だ。68000で言えばプリ/ポスト.インクリメント.アドレッシングの ような物がPSPのRISC(R4000)にもあるに違いない。 (これがあるCPUでは逆効果になってあたりまえの実験) こんなソース。
{ int R_Output_3; int R_Count_3; int R_Period_3; R_Output_3 = sn_Output[3]; R_Count_3 = sn_Count[3]; R_Period_3 = sn_Period[3]; do { int nextevent; if (R_Count_3 < left76) nextevent = R_Count_3; else nextevent = left76; if (R_Output_3) vol76[3] += R_Count_3; R_Count_3 -= nextevent; if (R_Count_3 <= 0) { if (sn_RNG & 1) sn_RNG ^= sn_NoiseFB; sn_RNG >>= 1; R_Output_3 = sn_RNG & 1; R_Count_3 += R_Period_3; if (R_Output_3) vol76[3] += R_Period_3; } if (R_Output_3) vol76[3] -= R_Count_3; left76 -= nextevent; } while (left76 > 0); sn_Output[3]= R_Output_3; sn_Count[3] = R_Count_3; /* not need it restore the sn_Period[3] */ }
これは86RISCでは、効果があるが、680x0やSHシリーズやR4000では、逆効果の模様。 PC(DOS/V)の場合。sn_Output[0]とsn_Output[3]は、(最適化しても)アドレス加算が入る為。違う。 上記RISCチップでは、3のような小さい数は、命令自体に吸収され、変わらない。 逆にロード/ストアの無駄分やメモリやレジスタを多く消費してパフォーマンスは落ちる。 PSPでは、上記のようなコーディングは、無意味で無駄。
=
-6~-7
+3~4