--- nono/m88xx0/m88100core.cpp 2026/04/29 17:05:05 1.1.1.10 +++ nono/m88xx0/m88100core.cpp 2026/04/29 17:05:07 1.1.1.11 @@ -7,9 +7,7 @@ #include "m88100.h" #include "m88100excep.h" #include "debugger.h" -#include "cvprompt.h" -#include "mpu.h" -#include "scheduler.h" +#include "mpu88xx0.h" #define OP_DEF(name) void __CONCAT(m88kcpu::op_,name)() #define OP_FUNC(name) __CONCAT(op_,name)() @@ -22,9 +20,13 @@ } \ } while (0) +// 電源オン void m88kcpu::PowerOn() { + // サイクルを初期化。 + used_cycle = 0; + // 履歴は電源オン時だけ初期化。 // (LUNA88K は ROM が正常パスで CPU リセットを行ったりするので) exhist.Clear(); @@ -36,9 +38,11 @@ m88kcpu::PowerOn() } // リセット例外のようなもの? -void +uint64 m88kcpu::Reset() { + uint64 cycle_start = used_cycle; + // 例外履歴に記録 (例外発生はブランチ履歴にも記録) // リセット例外も発生時の XIP を記録する。(LUNA88K の ROM 1.20) exhist.AddEntry(xip | 1, 0, 0xfc000000 | 0); @@ -48,7 +52,11 @@ m88kcpu::Reset() // 内部の割り込み状態をクリア intr_pending = 0; - atomic_reqflag &= ~(CPU_REQ_RESET | CPU_REQ_INTR | CPU_REQ_STOP); + ChangeState(CPU_STATE_NORMAL); + + // 実際どこかは分からんけど PSR 設定の前にリセットしておきたい + cmmu[0].Reset(); + cmmu[1].Reset(); // Table 6-8 (p6-47) psr = 0x800003ff; @@ -78,39 +86,19 @@ m88kcpu::Reset() dmt1 &= ~DM_VALID; dmt2 &= ~DM_VALID; - cmmu[0].Reset(); - cmmu[1].Reset(); - fetch(); + + return used_cycle - cycle_start; } -// 仮想時間 delta [nsec] だけ CPU を実行する。実際には大抵行き過ぎる。 -// 戻り値は CPU 状態 (Scheduler::SCHED_CPU_*)。 -uint32 -m88kcpu::Run(uint32 delta) +// 1命令実行する。 +// 戻り値は消費したサイクル数。 +int +m88kcpu::Exec() { - bool is_release = false; - bool is_intr = false; - - assert(used_cycle == 0); + uint64 cycle_start = used_cycle; - goal_cycle = Vtime2Cycle(delta); - if (__predict_false(goal_cycle == 0)) { - goal_cycle = 1; - } - - if ((atomic_reqflag & CPU_REQ_STOP)) { - if ((atomic_reqflag & (CPU_REQ_INTR | CPU_REQ_PROMPT | CPU_REQ_RESET))) { - // 割り込み、デバッガ、リセットが来たら STOP 解除。 - atomic_reqflag &= ~CPU_REQ_STOP; - } else { - // STOP 継続として戻る。 - used_cycle = goal_cycle; - goto exit; - } - } - - while (!is_release) { + { // shift pipeline opX = opF; xip = nip; @@ -120,68 +108,10 @@ m88kcpu::Run(uint32 delta) // この時点で実行しようとする命令が opX に入っている - if (atomic_reqflag != 0) { - // 何かが起きた - - if ((atomic_reqflag & CPU_REQ_RESET)) { - // リセット例外。 - Reset(); - // XIP がリセットベクタを指すためにはもう一回フェッチが必要 - // なので、ここは continue が必要。 - continue; - } - - // 割り込みの認識 - // 割り込みの実行は命令実行完了後、次のプリフェッチの前 - if ((atomic_reqflag & CPU_REQ_INTR)) { - atomic_reqflag &= ~CPU_REQ_INTR; - if (intr_pending && IsIntrEnable()) { - // この命令のあとに割り込み処理 - is_intr = true; - } -#if defined(TEST_INTERRUPT) - atomic_reqflag |= CPU_REQ_PROMPT; -#endif - } - - if ((atomic_reqflag & CPU_REQ_TRACE)) { - // デバッガプロンプトを出すかどうかを判断する - //inst_count++; - if (debugger_check()) { - atomic_reqflag |= CPU_REQ_PROMPT; - } - } - - if ((atomic_reqflag & CPU_REQ_PROMPT)) { - // デバッガプロンプトのための実行停止 - - // プロンプト獲得を通知 - gCVPrompt->NotifyAcquire(); - - // プロンプト解放を待機 - gCVPrompt->WaitRelease(); - - // プロンプトを抜けたのでここでフラグを落とす - atomic_reqflag &= ~CPU_REQ_PROMPT; - - // プロンプトから戻ってきたら一旦スケジューラまで戻る(?)。 - // reset コマンドのようにデバッガからスケジューラに出した - // リクエストを(なるはやで?)回収するため。 - atomic_reqflag |= CPU_REQ_RELEASE; - } - - if ((atomic_reqflag & CPU_REQ_RELEASE)) { - // 中断リクエスト受信 - // この命令を実行し終わったら抜ける - atomic_reqflag &= ~CPU_REQ_RELEASE; - is_release = true; - } - } - if (OpIsBusErr(opX)) { // プリフェッチしていた命令がバスエラー Exception(M88K_EXCEP_INST); - continue; + goto exit; } uint32 op12 = op32_to_12(opX); @@ -193,63 +123,37 @@ m88kcpu::Run(uint32 delta) break; } - if (is_intr && IsIntrEnable()) { + if (intr_pending && IsIntrEnable()) { // 割り込み処理要求が来ていて、 // 直前の命令が割り込みを禁止していなければ割り込み // XXX 実際は違う気がする - is_intr = false; cpulog(4, "INTR take"); ExceptionCore(M88K_EXCEP_INTERRUPT, ExceptionKind::INTR); - continue; + goto exit; } used_cycle++; - if ((atomic_reqflag & CPU_REQ_STOP)) { - // STOP 状態は、残りサイクルを消費したことにして戻る - cpulog(2, "STOP 状態検出"); - if (used_cycle < goal_cycle) { - used_cycle = goal_cycle; - } - } - - // XXX 命令の実行でリリースするのに、いったんループを回って - // からではタイミングが遅すぎる - if ((atomic_reqflag & CPU_REQ_RELEASE)) { - // 中断リクエスト受信 - // この命令を実行し終わったら抜ける - atomic_reqflag &= ~CPU_REQ_RELEASE; - is_release = true; - } - - if (used_cycle >= goal_cycle) - break; } exit: - total_vtime += Cycle2Vtime(used_cycle); - used_cycle = 0; - - // HALT 状態がないので NORMAL か STOP かだけでいい - return (atomic_reqflag & CPU_REQ_STOP) - ? Scheduler::SCHED_CPU_STOP - : Scheduler::SCHED_CPU_NORMAL; + return used_cycle - cycle_start; } -// この命令後に実行を中断して VM に戻る -void -m88kcpu::Release() +// STOP 状態で 1 命令実行する。 +// 戻り値は消費したサイクル数。 +int +m88kcpu::ExecPseudoStop() { - atomic_reqflag |= CPU_REQ_RELEASE; -} + instruction_in_stop++; + if (instruction_in_stop > 4) { + ChangeState(CPU_STATE_NORMAL); + } -// リセット例外を発行する -void -m88kcpu::RequestReset() -{ - atomic_reqflag |= CPU_REQ_RESET; + return Exec(); } + // 通常の例外。 // DataAccessException, エラー、割り込み、TRAP からは使わない。 // vec はベクタ番号。 @@ -437,7 +341,11 @@ m88kcpu::ReadDataException64(uint32 addr if ((flag & DM_DOUB1) == 0) { // .d の2ワード目がバスエラー。第1ワードのアクセスは成功した。 - dmt0 &= ~DM_VALID; + // DMx0 が例外を起こしたアクセスを示す。 + // Manual 6.7.3 + dma0 = dma1; + dmt0 = dmt1; + dmt1 &= ~DM_VALID; } cpulog(1, "ReadDAE64 xip=%x addr=%x", xip, addr); @@ -493,7 +401,12 @@ m88kcpu::WriteDataException64(uint32 add if ((flag & DM_DOUB1) == 0) { // .d の2ワード目がバスエラー。第1ワードのアクセスは成功した。 - dmt0 &= ~DM_VALID; + // DMx0 が例外を起こしたアクセスを示す。 + // Manual 6.7.3 + dma0 = dma1; + dmt0 = dmt1; + dmd0 = dmd1; + dmt1 &= ~DM_VALID; } cpulog(1, "WriteDAE64 xip=%x addr=%x", xip, addr); @@ -711,7 +624,11 @@ m88kcpu::Interrupt(int level) { // level は 0 か 1。 intr_pending = level; - atomic_reqflag |= CPU_REQ_INTR; + + if (intr_pending && IsIntrEnable() && (cpu_state == CPU_STATE_STOP)) { + // 割り込みを受け付けたら STOP 解除。 + ChangeState(CPU_STATE_NORMAL); + } } void @@ -726,3 +643,17 @@ OP_DEF(illegal) // 本来は不当命令例外? cpulog(0, "Illegal instruction %08x", (uint32)opX); } + +void +m88kcpu::ChangeState(uint32 new_state) +{ + if (new_state == CPU_STATE_STOP) { + instruction_in_stop = 0; + } + + if (cpu_state != new_state) { + cpu_state = new_state; + // スケジューラに通知 + dev->NotifyCPUMode(cpu_state); + } +}