Closed GodGnilda closed 4 years ago
@GodGnilda さん このたびは機能追加のご要望をいただき、誠にありがとうございます。
SNESAPUCallbackProc (effect = CBE_S700FCH) の戻り値では時間が経過しない。
「時間が経過しない」とのことでございますが、こちらはタイマーや t64Cnt が進まないとの解釈でよろしいでしょうか。 戻り値の下位 8bit を 0x02 に変更することで、命令を実行せずに時間を進めることは可能でございますが、この方法は使用できない、もしくは想定されている動作と異なっておりますでしょうか。
→ SetSPCDbg (SetSPCDbg= SPC_TRACE | SPC_RETURN) では clkLeft が 0 にならないので、SeekAPU (time = 64000) を実行し 0.5 秒経過後に SPC_RETURN すると 次の SeekAPU (time = 64000) が SeekAPU (time = 96000) になってしまう。
「0.5秒経過後」は EmuAPU を 0.5 秒分実行との解釈でよろしいでしょうか。 SetSPCDbg で SPC_TRACE | SPC_RETURN を設定後、SeekAPU(time = 64000) → EmuAPU(length = 0.5sec) → SeekAPU(time = 64000) を行いましたところ、想定通り 2.5 秒後(最初の Seek + EmuAPU + 2回目の Seek)となり、事象を再現することができませんでした。 お手数をおかけして恐れ入りますが、再現手順をお知らせいただけますでしょうか。
どうぞ、よろしくお願いいたします。
@dgrfactory 様
前回は誤解を招く表現などで間違った情報をお伝えしてしまい、申し訳ございません。
SNESAPUCallbackProc (effect = CBE_S700FCH) の戻り値では時間が経過しない。
改良版 snesapu.dll の SeekAPU (fast = 0) と SNESAPUCallbackProc (effect = CBE_S700FCH) を利用してステップイン機能を実現しようとしていた頃のことですが、当時は下位 8bit を 0x01 に変更することでその命令の時間だけタイマーが進まないと勘違いしてはまったことがありました。
下位 8bit を 0x02 に変更し他場合は命令を実行せずにタイマーを進めることができますが、 NOP の時間ではなく本来実行した場合に必要なサイクル数程度 [*
1] の時間が経過することを 66c065a にて確認いたしました。本来実行しないはずの命令の分まで時間が経過しますので、ステップイン機能を実現することは私にはできなそうです。
[*
1] SPC ファイルを読み込み後に 下位 8bit を 0x02 に変更するだけのコールバック関数で連続で停止させると、CPU サイクル数が奇数の命令で 24 APU サイクル分早く t64Cnt がカウントアップしているのを確認いたしました。
→ SetSPCDbg (SetSPCDbg= SPC_TRACE | SPC_RETURN) では clkLeft が 0 にならないので...
SetSPCDbg= ではなく opts = かつ pTrace に nullptr 以外を指定した状態ですね。大変失礼いたしました。
SetSPCDbg はネットで検索をしても不明な状態でしたので、SPC700.asm で仕様を確認いたしました。
SPC700.asm の [pDebug] が nullptr ではない状態で [opts] に SPC_TRACE と SPC_RETURN がセットされていますと Opcode Fetcher (SPC700.asm ラベル SPCTrace ~) で tracing routine 呼出し後に SPCTimers にジャンプしますので、SetSPCDbg(pTrace = tracing routine, opts = SPC_TRACE | SPC_RETURN) 設定後に SeekAPU や EmuAPU を実行しても命令を実行せず時間も進めない事が可能であることを 66c065a にて再度確認いたしました。
ステップイン機能を実現するために tracing routine で 1 命令実行後(2 回目の呼び出し時)に SetSPCDbg (pTrace = tracing routine, opts = SPC_TRACE | SPC_RETURN) を実行し、SeekAPU を 1 命令で中断させ、CPU の命令サイクル数を意識することなく必要最小限の APU サイクル数で確実に停止させることはできるようになりましたが、SetSPCDbg (pTrace = tracing routine, opts = SPC_TRACE) で SPC_RETURN を無効にした状態でステップインではなく普通に SeekAPU [*
2] を実行しますと、[clkLeft] が中断された残りの時間すべてを加算した時間の分の値になっていますので、[*
2] で設定された値より長い時間が経過してしまいます。
背景の詳細は以上です。
現在の仕様ですと、SetSPCDbg 以外で確実に次の命令に必要な APU サイクル数を 0 にする方法を思いつきませんでした。ただ今の仕様のままですと次の命令を実行するまでの待ち時間(サイクル数)を確認する方法がなさそうですので、[clkLeft] を 0 にすることができれば他の方がステップイン機能等を実現させようとした場合や内部チェックでエミュレーションを中断させたときの正しい時間を確認することが楽になるのではないかと思いまして、機能追加をお願いいたしました。
長文失礼しました。
@GodGnilda さん 詳細な情報をいただき、誠にありがとうございます。 また、動作検証等でたいへんお手数をおかけしましたこと、申し訳ありませんでした。
本件につきまして、下記の通り認識をいたしました。 内容について齟齬がございましたら、遠慮なくご指摘をお願いいたします。
■最終目的
■現状の問題点
■ご要望
上記認識に間違いがない前提として、回答申し上げます。
まず SetSPCDbg の動作についてですが、恥ずかしながら私自身使用したことがない機能であることと、ご存じの通りはっきりとした仕様記載のドキュメントが見当たらなく、 原作者の意図や互換性考慮を含めますと、こちらの動作は変更しないままとし、SNESAPUCallbackProc 側の動作を変更することが最善と思われますため、以下の対応を行いました。
上記動作仕様の変更により、ステップイン実行は、以下のプロセスで実現可能と思います。
処理としては少し複雑となってしまい恐縮ですが、上記方法にて実現可能であるかどうか、ご検討いただきたく存じます。 もし、まだ想定と異なる動作となっております場合は、お気軽にお問い合わせください。
本修正を含む SNESAPU.DLL は、以下よりダウンロード可能です。 snesapu-v2.18.2.7141.zip
どうぞ、よろしくお願いいたします。
@dgrfactory 様
早速に、ご返信恐れ入ります。
こちらこそ簡潔にお伝えできず、たいへんお手数をおかけしまして申し訳ありませんでした。
処理としては少し複雑となってしまい恐縮ですが
以前はそのように処理していましたので、まったく問題ございません。
リビジョン 983d93e , 4d26323 の SeekAPU にて動作を確認いたしましたが、1 命令実行で time に設定した値が増える状態でした。
更にソースを確認いたしましたところ、私のお願いがおかしいため想定通りの動作と異なる状態になっていると判断いたしました。
clkLeft
ではなく clkTotal
を 0 にすることで想定通りの動作になりそうです。
大変恐縮ですがコールバック関数 (effect = CBE_S700FCH) で FCH_HALT を返却した場合の動作を、以下のように変更をお願いできないでしょうか。
( ↓ B は不要でした。申し訳ありません)
A = clkExec - clkLeft // A : 実際に処理した実行時間
B = clkLeft < 0 ? clkLeft : 0; // B : clkLeft < 0 → 命令サイクルぴったりで終了したことにするには (- clkLeft) 足りない
clkTotal = A - B; // SPCTimers で 0 になるはず
Jmp SPCTimers // t64kHz を更新する必要があるので SPCTimers へジャンプ
お手を煩わせて申し訳ございません。どうぞ、よろしくお願いいたします。
@GodGnilda さん 動作検証、および、修正方法のご提示をいただき、誠にありがとうございます。 とても助かります。
FCH_HALT の場合、 clkTotal = clkExec - clkLeft - (clkLeft < 0 ? clkLeft : 0)
を行うよう処理を変更いたしました。
snesapu-v2.18.2.7143.zip
FCH_HALT 状態で、強制終了やフリーズ等しないことは確認いたしました。 ご希望の動作になっておりますか、たいへんお手数をおかけいたしますが、今一度ご確認いただけますでしょうか。
どうぞ、よろしくお願いいたします。
@dgrfactory 様 たびたび恐れ入りますが、SPCFetch でコールバック関数を呼び出す前に clkLeft が正の値であることは保証されるようですので、B は不要ですね。申し訳ありません。
@GodGnilda さん いえいえ、問題ございません。 確かに clkLeft は命令実行後に減算されますので、コールバックの時点では負にならないことを確認いたしました。
計算式上、すぐに影響があるわけではないようですが、念のため修正版を添付いたします。 snesapu-v2.18.2.7143-b2.zip
どうぞ、よろしくお願いいたします。
@dgrfactory 様 最新の修正版で動作を確認いたしました。EmuAPU の画像は len の表示がおかしいですが、修正漏れです。
EmuAPU で 1 命令ずつ実行 (384 APU サイクル)
SeekAPU と コールバック関数 (effect = CBE_S700FCH) で FCH_HALT を返却することで 1 命令ずつ実行 (384 APU サイクル) どちらも 384 APU サイクル経過で t64Cnt が 1 増加することを確認いたしました。
EmuAPU で 1 命令ずつ実行 (360 APU サイクル)
SeekAPU と コールバック関数 (effect = CBE_S700FCH) で FCH_HALT を返却することで 1 命令ずつ実行 (360 APU サイクル) どちらも 360 APU サイクル経過では t64Cnt が増加しないことを確認いたしました。
想定通りの動作です。ご修正いただきありがとうございます。
@GodGnilda さん 早速のご確認、誠にありがとうございます。 想定通りの動作となっていること、承知いたしました。
本件は元々 HALT 状態にしたにも関わらずタイマーが意図せず進んでしまうことから、不具合扱いといたします。 多大なご協力をいただき、ありがとうございます。
本件、いったんクローズいたしますが、追加依頼事項がございましたらリオープンしていただくか、お手数ですが新しい issue を作成していただきますよう、よろしくお願いいたします。
機能追加要望
SetSPCDbg または SNESAPUCallbackProc に SetSPCDbg の SPC_RETURN の機能と更に SPC700.asm の clkLeft を 0 にするフラグが欲しい。
背景
SPC700 のステップ実行やブレークポイントを実装すると、想定外の動作のためどうしても避けることができない不具合が発生してしまうのを回避するため。
SNESAPUCallbackProc (effect = CBE_S700FCH) の戻り値では時間が経過しない。 → SetSPCDbg (SetSPCDbg= SPC_TRACE | SPC_RETURN) では clkLeft が 0 にならないので、SeekAPU (time = 64000) を実行し 0.5 秒経過後に SPC_RETURN すると 次の SeekAPU (time = 64000) が SeekAPU (time = 96000) になってしまう。 → 1 命令ずつ実行で回避可能になるが、DSP エミュレーションが(一部 ?)実行されない ?