--- nono/m680x0/m680x0core.cpp 2026/04/29 17:05:40 1.1.1.3 +++ nono/m680x0/m680x0core.cpp 2026/04/29 17:05:57 1.1.1.5 @@ -7,6 +7,7 @@ #include "mpu680x0.h" #include "bitops.h" #include "debugger.h" +#include "event.h" #include "interrupt.h" #include "mainbus.h" #include "scheduler.h" @@ -20,7 +21,7 @@ // 1命令実行する。 // 割り込みチェックなどを省いたショート版。 void -MPU680x0Device::ExecShort(Event& ev) +MPU680x0Device::ExecShort(Event *ev) { uint64 cycle_start = used_cycle; @@ -70,7 +71,7 @@ MPU680x0Device::ExecShort(Event& ev) // 外部割り込みの起動は VM 側で処理している。 int cycle = used_cycle - cycle_start; - ev.time = cycle * clock_nsec + buswait; + ev->time = cycle * clock_tsec + buswait; scheduler->StartEvent(ev); } @@ -266,7 +267,6 @@ inline void MPU680x0Device::GenerateExframe7(uint vector, uint16 sr) { uint16 ssw; - uint32 fault_addr; uint32 pc; uint32 ea = 0; uint16 wb1s = 0; @@ -306,7 +306,7 @@ MPU680x0Device::GenerateExframe7(uint ve // +$30.L PUSH DATA LW1 (PD1) // +$34.L PUSH DATA LW2 (PD2) // +$38.L PUSH DATA LW3 (PD3) - // +$40 + // +$3c // こっちから上に向かって PUSH // SSW @@ -316,12 +316,11 @@ MPU680x0Device::GenerateExframe7(uint ve // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ // この後のスタック操作で bus が変化する前に保存。 - fault_addr = bus.laddr.Addr(); + const busaddr fault = bus.laddr; - ssw = bus.laddr.GetFC(); // TM - ssw |= (bus.size & 3) << 5; - bool is_write = bus.IsWrite(); - if (is_write == false) { + ssw = fault.GetFC(); // TM(=FC) + ssw |= (fault.GetSize() & 3) << 5; // Size の下位2ビット + if (fault.IsRead()) { ssw |= M68040::SSW_RW; } if (bus.atcfault) { @@ -345,13 +344,13 @@ MPU680x0Device::GenerateExframe7(uint ve push_4(wb2a); // WB2A push_4(0); // WB3D push_4(0); // WB3A - push_4(fault_addr); + push_4(fault.Addr()); push_2(wb1s); // WB1S push_2(wb2s); // WB2S push_2(0); // WB3S push_2(ssw); push_4(ea); - push_2(0x7000 | vector); + push_2(0x7000 | (vector << 2)); push_4(pc); push_2(sr); } @@ -361,15 +360,22 @@ inline void MPU680x0Device::GenerateExframeB(uint vector, uint16 sr) { uint16 ssw; - uint32 fault_addr; uint32 stageBaddr; stageBaddr = reg.pc + 2; + // この後のスタック操作で bus が変化する前に保存 - fault_addr = bus.laddr.Addr(); + const busaddr fault = bus.laddr; + + // SSW + // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + // |FC |FB |RC |RB | X | X | X |DF |RM |RW | SIZE | X | FC | + // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - // DF は常に立てる必要がある?? - ssw = bus.laddr.GetSSW() | M68030::SSW_SIZE(bus.size) | M68030::SSW_DF; + ssw = (fault.Get() >> 33) & 0x47; // R/W+FC + ssw |= (fault.GetSize() & 3) << 4; // Size の下位2ビット + ssw |= M68030::SSW_DF; // DF は常に立てる必要がある?? if (mmu_enable && (ssw & M68K::FC_DATA) != 0) { // 命令アクセスなら RB をセット。 ssw |= M68030::SSW_RB; @@ -421,7 +427,7 @@ MPU680x0Device::GenerateExframeB(uint ve reg.A[7] -= 8; push_4(0); // DATA OUTPUT BUFFER reg.A[7] -= 4; - push_4(fault_addr); // DATA CYCLE FAULT ADDRESS + push_4(fault.Addr()); // DATA CYCLE FAULT ADDRESS push_2(0); // INSTRUCTION PIPE STAGE B push_2(0); // INSTRUCTION PIPE STAGE C push_2(ssw); @@ -490,8 +496,7 @@ MPU680x0Device::ExceptionReset() constexpr uint32 info = BranchHistory_m680x0::InfoException(vector); exhist.AddEntry(reg.pc | 1, 0, info); brhist.AddEntry(reg.pc | 1, 0, info); - // デバッガに通知 (例外ブレーク用)。こっちのベクタは 0 のままでよい。 - debugger->NotifyExceptionMain(vector); + last_vector = vector; // RESET 信号線をネゲートしてから SP の読み込み開始まで 4クロック // (Section 7.8, Figure 7-64) @@ -560,7 +565,8 @@ MPU680x0Device::ExceptionReset() // ただし以下の例外はここではなくそれぞれ固有のを呼ぶこと。 // o リセット例外は ExceptionReset() // o 割り込み例外は ExceptionInterrupt() -// o TRAP#15 例外は ExceptionTrap15() +// o TRAP#0 例外は ExceptionTrap0() .. NetBSD システムコール用 +// o TRAP#15 例外は ExceptionTrap15() .. IOCS コール用 // o バスエラー・アドレスエラーは ExceptionBuserr() void MPU680x0Device::Exception(uint vector) @@ -569,6 +575,44 @@ MPU680x0Device::Exception(uint vector) ExceptionGeneric(vector, info); } +// TRAP #0 の例外処理を行う。 +// 処理自体は汎用の Exception() とまったく同じだが、 +// NetBSD システムコールの時に分岐履歴の内容を変えるため入口を分けてある。 +void +MPU680x0Device::ExceptionTrap0() +{ + // 今発生した TRAP #0 が NetBSD/m68k システムコールっぽいか調べる。 + // + // NetBSD/m68k 方面をやってる時は TRAP #0 はシステムコールを表示して + // ほしい。一方 Human68k などでは TRAP #0 は別用途なので、システムコール + // かのように表示されるのは紛らわしいので、 + // 出来れば今呼ばれたこれが NetBSD/m68k システムコールなのか、そうでない + // TRAP #0 なのかは区別したい。 + // + // NetBSD/m68k カーネルが実行中かどうかは厳密には分からないが、これが + // 呼ばれた時点で、 + // 1) MMU がオン。 + // 2) カーネルのエントリポイントの最初の命令が move.w #$2700,sr 命令。 + // を満たせば NetBSD/m68k システムコールと判定することにする。 + // カーネルエントリポイントは機種ごとに固有で、不変ではないものの + // ブートローダ側にも影響があるためおそらくそう簡単には変わらないだろう。 + // だめならまた考える。 + + const uint vector = M68K::EXCEP_TRAP0; + uint32 info; + if (__predict_true(mmu_enable)) { + // カーネルエントリポイントの最初の命令はどれも move.w #$2700,sr。 + if (mainbus->Peek4(netbsd_entrypoint) == 0x46fc2700) { + // NetBSD/m68k カーネルっぽい。 + info = BranchHistory_m680x0::InfoNetBSDSyscall(reg.D[0] & 0xffff); + ExceptionGeneric(vector, info); + return; + } + } + // その他の TRAP#0 っぽい + Exception(vector); +} + // TRAP #15 の例外処理を行う。 // 処理自体は汎用の Exception() とまったく同じだが、 // IOCS コールの時に分岐履歴の内容を変えるため入口を分けてある。 @@ -596,11 +640,12 @@ MPU680x0Device::ExceptionTrap15() if (mainbus->Peek1(0xcb6) == 0x02 && mainbus->Peek1(0xcb7) == 0x03) { // IOCS コールっぽい info = BranchHistory_m680x0::InfoIOCSCall(reg.D[0] & 0xff); - } else { - // TRAP#15 っぽい - info = BranchHistory_m680x0::InfoException(vector); + ExceptionGeneric(vector, info); + return; } - ExceptionGeneric(vector, info); + + // その他の TRAP#15 っぽい + Exception(vector); } // F ライン例外処理を行う。 @@ -639,12 +684,11 @@ MPU680x0Device::ExceptionGeneric(uint ex uint vector = ext_vector & 0xff; // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + last_vector = vector; excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); exhist.AddEntry(from, 0, info); brhist.AddEntry(from, 0, info); - // デバッガに通知 (例外ブレーク用) - debugger->NotifyExceptionMain(vector); // 状態を保存 uint16 sr = GetSR(); @@ -706,13 +750,12 @@ MPU680x0Device::ExceptionBuserr(uint vec "vector=%u", vector); // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + last_vector = vector; excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); uint32 info = BranchHistory_m680x0::InfoException(vector); exhist.AddEntry(from, 0, info); brhist.AddEntry(from, 0, info); - // デバッガに通知 (例外ブレーク用) - debugger->NotifyExceptionMain(vector); // 現状 68030 のバスエラーに short/long の区別はないので全部 long 相当。 CYCLE3(busfault); @@ -801,13 +844,12 @@ MPU680x0Device::ExceptionInterrupt() } // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + last_vector = vector; excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); uint32 info = BranchHistory_m680x0::InfoException(vector); exhist.AddEntry(from, 0, info); brhist.AddEntry(from, 0, info); - // デバッガに通知 (例外ブレーク用) - debugger->NotifyExceptionMain(vector); // 状態を保存 uint16 oldsr = GetSR(); @@ -833,7 +875,7 @@ MPU680x0Device::ExceptionInterrupt() ExceptionBuserr(vector2); } - return (used_cycle - cycle_start) * clock_nsec + bd.GetWait(); + return (used_cycle - cycle_start) * clock_tsec + bd.GetWait(); } // LC040 の未実装浮動小数点命令例外。 @@ -843,13 +885,12 @@ MPU680x0Device::ExceptionFPLC(uint32 ea) const uint vector = M68K::EXCEP_FLINE; // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + last_vector = vector; excep_counter[vector]++; uint32 from = ppc | (IsSuper() ? 1 : 0); constexpr uint32 info = BranchHistory_m680x0::InfoException(vector); exhist.AddEntry(from, 0, info); brhist.AddEntry(from, 0, info); - // デバッガに通知 (例外ブレーク用) - debugger->NotifyExceptionMain(vector); // 状態を保存 uint16 sr = GetSR();