--- nono/vm/mpu680x0.cpp 2026/04/29 17:04:36 1.1.1.2 +++ nono/vm/mpu680x0.cpp 2026/04/29 17:04:45 1.1.1.5 @@ -27,10 +27,13 @@ std::unique_ptr gMPUATC; // できる。すごい楽。 MPU680x0Device::MPU680x0Device(uint32 reset_vector) { - monitor.Init(79, 16); + monitor_size = nnSize(79, 16); cpu = m68030_init(reset_vector); + // イベントコールバック設定 + event.func = (DeviceCallback_t)&MPU680x0Device::Callback; + // モニタ用の別オブジェクト gMPUATC.reset(new MPUATC(cpu)); } @@ -43,6 +46,15 @@ MPU680x0Device::~MPU680x0Device() bool MPU680x0Device::Init() { + // 親クラス + if (inherited::Init() == false) { + return false; + } + // MPU クロックは親 Init() で読み込んで、ここで cpu にセットする + cpu->clock_khz = clock_khz; + // 割り込み時のディレイ + intdelay = cpu->Cycle2Vtime(4); + // FPU (6888x) if (gMainApp.GetVMType() == VMTYPE_LUNA1) { // LUNA は 68881 固定 (設定は見ない) @@ -60,39 +72,61 @@ MPU680x0Device::Init() return true; } -// リセット -// (MPU が動くのはこの後 Scheduler::Run() を発行した後) +// イベントコールバック +// ev.code は +// 0x80000000: リセット例外 +// 0x0 〜 0x7: 新しい割り込みレベルを通知 (0-7) void -MPU680x0Device::ResetHard() +MPU680x0Device::Callback(Event& ev) { - m68030_exception_reset(cpu); + if (__predict_false((int32)ev.code < 0)) { + // リセット例外 + m68030_request_reset_exception(cpu); + } else { + // コードが 0-7 なら新しい割り込みレベルの通知 + int level = ev.code; + m68030_interrupt(cpu, level); + } } -// MPU を request で指定されたクロックサイクルだけ実行する。 -// 今回の実行サイクル数が request を越えた命令境界まで実行するので -// 実際には少しはみ出る。 -// また実行中にデバイスアクセスなどによりスケジューラにイベントが -// 追加されるとその次の命令境界で処理を打ち切って戻ってくる。 -// 戻り値は CPU の outer フラグ。 +// MPU を vtime [nsec] 分実行する。 +// 戻り値は outer フラグ。 uint32 -MPU680x0Device::Run(uint64 request) +MPU680x0Device::Run(uint32 vtime) { - return m68030_run(cpu, request); + return m68030_run(cpu, vtime); } -// 割り込み発生を MPU に通知 (オートベクタ) -void -MPU680x0Device::Interrupt(Object *src, int level) +// 現在の仮想時刻 [nsec] を取得する +uint64 +MPU680x0Device::GetVirtTime() { - int vector = M68K_EXCEP_LEVEL_BASE + level; - m68030_interrupt(cpu, level, vector); + return m68030_get_vtime(cpu); } -// 割り込み発生を MPU に通知 (ベクタ) +// 割り込みレベルが変わったことを MPU に通知。 void -MPU680x0Device::Interrupt(Object *src, int level, int vector) +MPU680x0Device::Interrupt(int level) { - m68030_interrupt(cpu, level, vector); + assertmsg(0 <= level && level <= 7, "level=%d", level); + + // 外部デバイスが 68030 の IPL0-2 をアサートしてから、68030 がそれを + // 認識(確定)するのに 2クロックかかる。ここでレベルを比較して割り込みを + // 上げる場合は /IPEND をアサートする。 + // そこからさらに2クロック後以降の命令境界で割り込みを受け付ける(?) + // らしい? + // この 4クロック待つところはイベントスケジューラがある VM 側で担当する。 + // 本来、レベル比較はここから2クロック後に行われるはずだが、ちょっと省略。 + // 今はコア側でペンディング処理をしているのでこっち側は起きたことを全部 + // 通知する。 + // 割り込みレベルが 0 に下がる時にはこのディレイは不要のはず。 + if (level != 0) { + event.time = intdelay; + } else { + event.time = 0; + } + event.code = level; + event.Start(); } // A-Line 命令エミュレーションのコールバックを指定。 @@ -120,8 +154,8 @@ MPU680x0Device::SetHaltCallback(void (*c } // モニター更新 (レジスタウィンドウ) -bool -MPU680x0Device::MonitorUpdate() +void +MPU680x0Device::MonitorUpdate(TextScreen& monitor) { m68kreg reg; uint32 ppc; @@ -297,8 +331,6 @@ MPU680x0Device::MonitorUpdate() // FPIAR monitor.Print(x, y++, "FPIAR:%08x", reg.fpframe.fpf_fpiar); - - return true; } // CPU 側からのコールバック。RESET 命令ハンドラ @@ -315,14 +347,14 @@ MPUATC::MPUATC(m68kcpu *cpu_) { cpu = cpu_; #if !defined(ATC_SINGLE) - monitor.Init(131, m68030ATCTable::LINES + 3); + monitor_size = nnSize(131, m68030ATCTable::LINES + 3); #else - monitor.Init(31, 24); + monitor_size = nnSize(31, 24); #endif } -bool -MPUATC::MonitorUpdate() +void +MPUATC::MonitorUpdate(TextScreen& monitor) { m68030ATCTable *table; #if !defined(ATC_SINGLE) @@ -430,5 +462,4 @@ MPUATC::MonitorUpdate() } } #endif - return true; }