Annotation of nono/m680x0/m68030core.cpp, revision 1.1.1.5

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #include "m68030core.h"
                      8: #include "debugger.h"
                      9: #include "cvprompt.h"
                     10: #include "mpu.h"
1.1.1.5 ! root       11: #include "scheduler.h"
1.1       root       12: 
                     13: #define OP_PROTO(name) static inline void __CONCAT(op_,name)(m68kcpu *cpu)
                     14: #define OP_DEF(name)   static inline void __CONCAT(op_,name)(m68kcpu *cpu)
                     15: #define OP_FUNC(name)  __CONCAT(op_,name)(cpu)
                     16: 
                     17: #include "m68030bus.h"
                     18: #include "m68030bus.cpp"
                     19: #include "m68030excep.h"
                     20: #include "m68030ea.h"
                     21: #include "m68030acc.h"
                     22: #include "m68030ops.h"
                     23: #include "m68030mmu.h"
                     24: #include "m68030fpu.h"
                     25: #include "m68030ops.cpp"
                     26: 
                     27: static void m68030_flush_interrupt(m68kcpu *cpu);
                     28: 
1.1.1.3   root       29: // 仮想時間 delta [nsec] だけ CPU を実行する。実際には大抵行き過ぎる。
1.1.1.5 ! root       30: // 戻り値は CPU 状態 (Scheduler::SCHED_CPU_*)。
1.1       root       31: uint32
1.1.1.3   root       32: m68030_run(m68kcpu *cpu, uint32 delta)
1.1       root       33: {
1.1.1.3   root       34:        // XXX DMAC がデバイスアクセスして時間が進むので
                     35:        // 今の所ここに来た時点で常に 0 にはならない
                     36:        //assert(cpu->used_cycle == 0);
                     37: 
                     38:        cpu->goal_cycle = cpu->Vtime2Cycle(delta);
                     39:        if (__predict_false(cpu->goal_cycle == 0)) {
                     40:                cpu->goal_cycle = 1;
                     41:        }
1.1       root       42: 
                     43:        // メインループ
                     44:        while (1) {
                     45:                if (cpu->atomic_reqflag != 0) {
                     46:                        // 何かが起きた
                     47: 
                     48:                        // デバッグ用
                     49:                        if (0) {
                     50:                                static int oldreq = -1;
                     51:                                uint32 _req = cpu->atomic_reqflag;
                     52:                                if ((_req & (CPU_REQ_TRACE | CPU_REQ_PROMPT)) != oldreq) {
                     53:                                        oldreq = _req & (CPU_REQ_TRACE | CPU_REQ_PROMPT);
                     54:                                        printf("reqflag=%c%c\n",
                     55:                                                (_req & CPU_REQ_TRACE)  ? 'T' : '-',
                     56:                                                (_req & CPU_REQ_PROMPT) ? 'P' : '-');
                     57:                                }
                     58:                        }
                     59: 
                     60:                        // XXX 発生頻度を観測すること。
                     61:                        //     そして並び替えるとか、フラグの割り当てを考えるとか。
                     62: 
                     63:                        // このフラグ処理の優先度はたぶん次のような感じになるはず。
                     64:                        // 1. スケジューラ依頼による処理の中断
                     65:                        // 2. 命令途中で起きた例外の処理
                     66:                        // 3. 割り込みチェック
                     67:                        // 4. STOP、HALT 状態の対応
                     68: 
                     69:                        if ((cpu->atomic_reqflag & CPU_REQ_RELEASE)) {
                     70:                                // ここで実行を中断してスケジューラに戻る
                     71:                                cpu->atomic_reqflag &= ~CPU_REQ_RELEASE;
1.1.1.4   root       72:                                goto exit;
1.1       root       73:                        }
                     74: 
1.1.1.3   root       75:                        if ((cpu->atomic_reqflag & CPU_REQ_RESET)) {
                     76:                                // リセット例外
                     77:                                m68030_exception_reset(cpu);
                     78:                                cpu->atomic_reqflag &= ~CPU_REQ_RESET;
                     79:                        }
                     80: 
1.1       root       81:                        if ((cpu->atomic_reqflag & CPU_REQ_INTR)) {
1.1.1.3   root       82:                                // 割り込みチェック (必要なら例外処理を起動する)
1.1       root       83:                                m68030_flush_interrupt(cpu);
1.1.1.3   root       84:                                cpu->atomic_reqflag &= ~CPU_REQ_INTR;
1.1       root       85:                        }
                     86: 
                     87:                        if ((cpu->atomic_reqflag & CPU_REQ_STOP)) {
                     88:                                // STOP 状態は、残りサイクルを消費したことにして戻る
1.1.1.5 ! root       89:                                cpu->reg.state = Scheduler::SCHED_CPU_STOP;
1.1.1.4   root       90:                                if (cpu->used_cycle < cpu->goal_cycle) {
                     91:                                        cpu->used_cycle = cpu->goal_cycle;
                     92:                                }
                     93:                                goto exit;
1.1       root       94:                        }
                     95: 
                     96:                        if ((cpu->atomic_reqflag & CPU_REQ_HALT)) {
1.1.1.2   root       97:                                // HALT 状態も、残りサイクルを消費したことにして戻る
1.1.1.5 ! root       98:                                cpu->reg.state = Scheduler::SCHED_CPU_HALT;
1.1.1.4   root       99:                                if (cpu->used_cycle < cpu->goal_cycle) {
                    100:                                        cpu->used_cycle = cpu->goal_cycle;
                    101:                                }
                    102:                                goto exit;
1.1       root      103:                        }
                    104: 
                    105:                        if ((cpu->atomic_reqflag & CPU_REQ_TRACE)) {
                    106:                                // デバッガプロンプトを出すかどうかを判断する
                    107:                                cpu->inst_count++;
                    108:                                if (debugger_check()) {
                    109:                                        cpu->atomic_reqflag |= CPU_REQ_PROMPT;
                    110:                                }
                    111:                        }
                    112: 
                    113:                        if ((cpu->atomic_reqflag & CPU_REQ_PROMPT)) {
                    114:                                // デバッガプロンプトのための実行停止
                    115: 
                    116:                                // プロンプト獲得を通知
                    117:                                gCVPrompt->NotifyAcquire();
                    118: 
                    119:                                // プロンプト解放を待機
                    120:                                gCVPrompt->WaitRelease();
                    121: 
                    122:                                // プロンプトを抜けたのでここでフラグを落とす
                    123:                                cpu->atomic_reqflag &= ~CPU_REQ_PROMPT;
                    124:                        }
                    125:                }
                    126: 
                    127:                try {
                    128: #define USE_COMPUTED_GOTO
                    129: #if defined(USE_COMPUTED_GOTO)
                    130:                        // computed-goto を使う方法。
                    131:                        // JUMP が1回目の分岐。CHECK_AND_JUMP が命令実行後の分岐。
                    132:                        // outer は命令実行前にチェックしてはいけないので、2つに
                    133:                        // 分かれている。1回目の分岐も goto.h の中で出力してある。
                    134: #define JUMP   \
                    135:                        RegPPC = RegPC; \
                    136:                        cpu->flag_pi = 0; \
                    137:                        cpu->flag_pd = 0; \
                    138:                        RegIR = m68030_fetch_16(cpu);   \
                    139:                        __assume((RegIR >> 6) < 1024);  \
                    140:                        goto *jumptable[RegIR >> 6]
                    141: 
                    142: #define CHECK_AND_JUMP \
1.1.1.3   root      143:                        cpu->used_cycle += cpu->cycle_nocache;  \
1.1       root      144:                        cpu->cycle_nocache = 0; \
1.1.1.3   root      145:                        if (cpu->used_cycle >= cpu->goal_cycle) \
1.1.1.4   root      146:                                goto exit;      \
1.1       root      147:                        if (cpu->atomic_reqflag != 0) goto exit_inner_loop; \
                    148:                        JUMP
                    149: 
                    150: #include "m68030goto.h"
                    151:                        exit_inner_loop:;
                    152: #else
                    153:                        // switch-case を使う方法。
                    154:                        do {
                    155:                                RegPPC = RegPC;
                    156:                                cpu->flag_pi = 0;
                    157:                                cpu->flag_pd = 0;
                    158:                                RegIR = m68030_fetch_16(cpu);
                    159: 
                    160:                                // uint16 を 6ビット右シフトしたら 1024 以上になるはずは
                    161:                                // ないのだが、デフォルトでは gcc/clang どちらも律儀に
                    162:                                // 1024 以上かどうか比較して分岐しようとする。
                    163:                                // gcc は __assume() を入れることでこの比較・分岐を出力
                    164:                                // しないようにすることが出来た(がパフォーマンスの差は
                    165:                                // 見えない程度でしかなかった)。
                    166:                                // clang ではどうやったら効くか不明。
                    167:                                uint16 ir = RegIR >> 6;
                    168:                                __assume(ir < 1024);
                    169:                                switch (ir) {
                    170: #include "m68030switch.h"
                    171:                                }
                    172: 
1.1.1.3   root      173:                                cpu->used_cycle += cpu->cycle_nocache;
1.1       root      174:                                cpu->cycle_nocache = 0;
1.1.1.3   root      175:                                if (cpu->used_cycle >= cpu->goal_cycle)
1.1.1.4   root      176:                                        goto exit;
1.1       root      177: 
                    178:                        } while (cpu->atomic_reqflag == 0);
                    179: #endif
                    180:                } catch (int vector) {
                    181:                        // ここで(C++の)例外スローをキャッチするのは
                    182:                        // - メモリ空間をアクセスした先でのバスエラー例外
                    183:                        // - EA パース中の不当命令例外
                    184:                        // のみ。それ以外の命令途中例外はその場で処理できる。
                    185:                        cpulog(1, "%s", m68030_get_exception_name(vector));
                    186:                        m68030_exception(cpu, vector);
                    187:                }
                    188:        }
                    189:        __unreachable();
1.1.1.4   root      190: 
                    191:  exit:
                    192:        cpu->total_vtime += cpu->Cycle2Vtime(cpu->used_cycle);
                    193:        cpu->used_cycle = 0;
                    194: 
1.1.1.5 ! root      195:        return cpu->reg.state;
1.1       root      196: }
                    197: 
                    198: // ペンディングの割り込みを確認
                    199: static void
                    200: m68030_flush_interrupt(m68kcpu *cpu)
                    201: {
1.1.1.3   root      202:        if (cpu->intr_pending > cpu->reg.intr_level) {
                    203:                // マスクを超えるレベルの割り込みが起きた
1.1       root      204: 
                    205:                // ストップ状態を解除
                    206:                cpu->atomic_reqflag &= ~CPU_REQ_STOP;
1.1.1.5 ! root      207:                cpu->reg.state = Scheduler::SCHED_CPU_NORMAL;
1.1       root      208: 
                    209:                // 例外処理を起動
1.1.1.3   root      210:                m68030_exception_interrupt(cpu, cpu->intr_pending);
1.1       root      211:        }
                    212: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.