--- nono/m88xx0/m88100core.cpp 2026/04/29 17:04:34 1.1.1.2 +++ nono/m88xx0/m88100core.cpp 2026/04/29 17:04:40 1.1.1.4 @@ -18,22 +18,27 @@ void m88kcpu::Reset(uint32 reset_vector) { - // TODO: 未完成 + const uint32 Undefined = 0xcccccccc; + + // 履歴を初期化。リセット前の履歴いらんよな? + exhist.Clear(); + brhist.Clear(); + + // Table 6-8 (p6-47) psr = 0x800003ff; - // SFD1 = 0; + // XXX ただし SFU1 は未実装なので下げておく psr &= ~PSR_SFD1; #if defined(TEST_INTERRUPT) -psr &= ~PSR_IND; -psr &= ~PSR_SFRZ; + psr &= ~PSR_IND; + psr &= ~PSR_SFRZ; #endif - SetPSR(psr); - - vbr = 0; + SetPSR(); - cmmu[0].Reset(); - cmmu[1].Reset(); + epsr = Undefined; + // scoreboard: cleared + ssbr = Undefined; // 実際には m88k MPU はリセット直後は 0 番地から実行を開始するので、 // 大抵の場合システムでリセット直後は 0 番地付近に ROM を見せるように @@ -42,6 +47,45 @@ psr &= ~PSR_SFRZ; fip = reset_vector; nip = 0; xip = 0; + sfip = Undefined; + snip = Undefined; + sxip = Undefined; + + vbr = 0; + // DMTx は bit0(Valid) をクリア。他は不定。 + dmt0 &= ~DM_VALID; + dmt1 &= ~DM_VALID; + dmt2 &= ~DM_VALID; + dma0 = Undefined; + dma1 = Undefined; + dma2 = Undefined; + dmd0 = Undefined; + dmd1 = Undefined; + dmd2 = Undefined; + for (int i = 1; i < 32; i++) { + r[i] = Undefined; + } + + fpecr = 0; + for (int i = 1; i < 9; i++) { + fcr[i] = Undefined; + } + fpcr = 0; + fpsr = 0; + + cmmu[0].Reset(); + cmmu[1].Reset(); + + // 履歴を初期化 + exhist.Clear(); + brhist.Clear(); + + // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + // リセット例外発生時の from にはあまり意味がないので 0 にするか。 + exhist.AddEntry(0, 0, 0xfc000000 | 0); + brhist.AddEntry(0, 0, 0xfc000000 | 0); + // デバッガに通知 (例外ブレーク用) + debugger_notify_exception(0); fetch(); } @@ -84,7 +128,7 @@ m88kcpu::Run(uint64 request) atomic_reqflag &= ~CPU_REQ_INTR; is_intr = true; #if defined(TEST_INTERRUPT) - atomic_reqflag |= CPU_REQ_PROMPT; + atomic_reqflag |= CPU_REQ_PROMPT; #endif } @@ -107,6 +151,11 @@ m88kcpu::Run(uint64 request) // プロンプトを抜けたのでここでフラグを落とす atomic_reqflag &= ~CPU_REQ_PROMPT; + + // プロンプトから戻ってきたら一旦スケジューラまで戻る(?)。 + // reset コマンドのようにデバッガからスケジューラに出した + // リクエストを(なるはやで?)回収するため。 + atomic_reqflag |= CPU_REQ_RELEASE; } if ((atomic_reqflag & CPU_REQ_RELEASE)) { @@ -182,6 +231,32 @@ m88kcpu::Exception(int vec) void m88kcpu::ExceptionCore(int vec, ExceptionKind cause) { + uint syscall = 0; + + // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + // OpenBSD システムコールなら番号もついでに記録。 + // システムコール番号は tb0 発行時点で r13 にセットされている。 + // ただし 0 番は syscall(2) (間接システムコール) で、実際の番号は r2。 + // 198番 __syscall(2) だと r2:r3 (なので実質 r3)。 + if (vec == 450) { + syscall = r[13]; + if (syscall == 0) { + syscall = r[2]; + } else if (syscall == 198) { + syscall = r[3]; + } + syscall &= 0xfff; + } + exhist.AddEntry(xip, 0, 0xfc000000 | (syscall << 12) | vec); + brhist.AddEntry(xip, 0, 0xfc000000 | (syscall << 12) | vec); + // デバッガに通知 (例外ブレーク用) + debugger_notify_exception(vec); + + // 命令中で起きる例外はとりあえず全部2クロック追加? (Table.7-5) + if (cause != ExceptionKind::INTR) { + total_cycle += 2; + } + if (psr & PSR_SFRZ) { if (cause != ExceptionKind::TRAP) { gMPU->putlog(2, "SFRZ Error Exception"); @@ -199,8 +274,7 @@ m88kcpu::ExceptionCore(int vec, Exceptio sxip |= SIP_V; snip |= SIP_V; - // XXX:実機と異なり、fip は常にフェッチ前なので V=0 - // ^^^^ コレ自体怪しい。INTERRUPT とか。 + sfip |= SIP_V; if (OpIsBusErr(opX)) { sxip |= SIP_E; // E bit @@ -260,8 +334,11 @@ m88kcpu::ExceptionCore(int vec, Exceptio SetPSR(psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ); fip = vbr + (vec << 3); - brhist.AddEntry(xip, fip); fetch(); + // ここでベクタに飛ぶのだが、ベクタ内の2命令でおそらく必ずもう一度 + // 分岐してそっちでも履歴が残るので、ここでブランチ履歴を残すのは + // ちょっと冗長という気もする。 + if (OpIsBusErr(opF)) { if (cause == ExceptionKind::ERROR) { // double bus fault