--- nono/m680x0/m68030core.cpp 2026/04/29 17:04:34 1.1.1.2 +++ nono/m680x0/m68030core.cpp 2026/04/29 17:04:43 1.1.1.3 @@ -25,11 +25,22 @@ static void m68030_flush_interrupt(m68kcpu *cpu); -// request サイクル(を超えるところまで)実行する。 +// 仮想時間 delta [nsec] だけ CPU を実行する。実際には大抵行き過ぎる。 +// 戻り値はフラグ。 +// +// 戻る時に仮想時刻を確定させなくても構わない。スケジューラはこれを呼び出した +// 後に必然的に仮想時刻を取得することになるため、そこで確定させられる。 uint32 -m68030_run(m68kcpu *cpu, uint64 request) +m68030_run(m68kcpu *cpu, uint32 delta) { - uint64 goal_cycle = cpu->total_cycle + request; + // XXX DMAC がデバイスアクセスして時間が進むので + // 今の所ここに来た時点で常に 0 にはならない + //assert(cpu->used_cycle == 0); + + cpu->goal_cycle = cpu->Vtime2Cycle(delta); + if (__predict_false(cpu->goal_cycle == 0)) { + cpu->goal_cycle = 1; + } // メインループ while (1) { @@ -63,23 +74,29 @@ m68030_run(m68kcpu *cpu, uint64 request) return cpu->atomic_reqflag; } + if ((cpu->atomic_reqflag & CPU_REQ_RESET)) { + // リセット例外 + m68030_exception_reset(cpu); + cpu->atomic_reqflag &= ~CPU_REQ_RESET; + } + if ((cpu->atomic_reqflag & CPU_REQ_INTR)) { - // 割り込みチェック - // 必要ならこの中で例外処理を起動する + // 割り込みチェック (必要なら例外処理を起動する) m68030_flush_interrupt(cpu); + cpu->atomic_reqflag &= ~CPU_REQ_INTR; } if ((cpu->atomic_reqflag & CPU_REQ_STOP)) { // STOP 状態は、残りサイクルを消費したことにして戻る cpu->reg.state = CPU_REQ_STOP; - cpu->total_cycle = goal_cycle; + cpu->used_cycle = cpu->goal_cycle; return cpu->atomic_reqflag; } if ((cpu->atomic_reqflag & CPU_REQ_HALT)) { // HALT 状態も、残りサイクルを消費したことにして戻る cpu->reg.state = CPU_REQ_HALT; - cpu->total_cycle = goal_cycle; + cpu->used_cycle = cpu->goal_cycle; return cpu->atomic_reqflag; } @@ -121,11 +138,10 @@ m68030_run(m68kcpu *cpu, uint64 request) goto *jumptable[RegIR >> 6] #define CHECK_AND_JUMP \ - cpu->total_cycle += cpu->cycle_cache; \ - cpu->total_cycle += cpu->cycle_nocache; \ - cpu->cycle_cache = 0; \ + cpu->used_cycle += cpu->cycle_nocache; \ cpu->cycle_nocache = 0; \ - if (cpu->total_cycle >= goal_cycle) return cpu->atomic_reqflag; \ + if (cpu->used_cycle >= cpu->goal_cycle) \ + return cpu->atomic_reqflag; \ if (cpu->atomic_reqflag != 0) goto exit_inner_loop; \ JUMP @@ -152,11 +168,9 @@ m68030_run(m68kcpu *cpu, uint64 request) #include "m68030switch.h" } - cpu->total_cycle += cpu->cycle_cache; - cpu->total_cycle += cpu->cycle_nocache; - cpu->cycle_cache = 0; + cpu->used_cycle += cpu->cycle_nocache; cpu->cycle_nocache = 0; - if (cpu->total_cycle >= goal_cycle) + if (cpu->used_cycle >= cpu->goal_cycle) return cpu->atomic_reqflag; } while (cpu->atomic_reqflag == 0); @@ -177,51 +191,14 @@ m68030_run(m68kcpu *cpu, uint64 request) static void m68030_flush_interrupt(m68kcpu *cpu) { - // 割り込みマスクをレベル(1-7)に変換するテーブル - // b はペンディングになってる割り込みのうち今回処理する最上位の1つ - // を示すビットが立った状態。不正入力がないとすると入力は 0 〜 64。 - static uint8 mask2level[65] = { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0,7,6,0,5,0,0,0, 4,0,0,0,0,0,0,0, // $00 - 3,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // $10 - 2,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // $20 - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // $30 - 1, - }; - int b; - - cpu->intrmtx.lock(); - - b = cpu->intr_pending & cpu->intr_mask; - if (b != 0) { - // 立っている最下位ビットだけを残す - b &= -b; - - // 該当フラグは落としておく - cpu->intr_pending &= ~b; + if (cpu->intr_pending > cpu->reg.intr_level) { + // マスクを超えるレベルの割り込みが起きた // ストップ状態を解除 cpu->atomic_reqflag &= ~CPU_REQ_STOP; cpu->reg.state = 0; - // b をレベルに変換 - int level = mask2level[b]; - int vector = cpu->intr_vector[level]; - - // ロックここまで。例外処理時に intrmtx は外しておくこと - cpu->intrmtx.unlock(); - // 例外処理を起動 - m68030_exception_interrupt(cpu, level, vector); - - // 次の命令境界でも割り込みチェックを行う - // 更に下のレベルの割り込みがペンディングになっている可能性のため - } else { - // ペンディングの割り込みはなくなったので、 - // 次の命令境界では割り込みチェックは不要 - cpu->atomic_reqflag &= ~CPU_REQ_INTR; - - // ロックここまで (atomic なのでその前で解放してもいいけど) - cpu->intrmtx.unlock(); + m68030_exception_interrupt(cpu, cpu->intr_pending); } }