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

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

unix.superglobalmegacorp.com

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