Annotation of nono/m88xx0/m88100core.cpp, revision 1.1.1.4

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 "m88100.h"
                      8: #include "m88100excep.h"
                      9: #include "debugger.h"
                     10: #include "cvprompt.h"
                     11: #include "mpu.h"
                     12: 
                     13: #define OP_DEF(name)   void __CONCAT(m88kcpu::op_,name)()
                     14: #define OP_FUNC(name)  __CONCAT(op_,name)()
                     15: #include "m88100ops.cpp"
                     16: 
                     17: // リセット例外のようなもの?
                     18: void
                     19: m88kcpu::Reset(uint32 reset_vector)
                     20: {
1.1.1.4 ! root       21:        const uint32 Undefined = 0xcccccccc;
        !            22: 
        !            23:        // 履歴を初期化。リセット前の履歴いらんよな?
        !            24:        exhist.Clear();
        !            25:        brhist.Clear();
        !            26: 
        !            27:        // Table 6-8 (p6-47)
1.1       root       28:        psr = 0x800003ff;
1.1.1.4 ! root       29:        // XXX ただし SFU1 は未実装なので下げておく
1.1       root       30:        psr &= ~PSR_SFD1;
                     31: 
1.1.1.2   root       32: #if defined(TEST_INTERRUPT)
1.1.1.4 ! root       33:        psr &= ~PSR_IND;
        !            34:        psr &= ~PSR_SFRZ;
1.1       root       35: #endif
                     36: 
1.1.1.4 ! root       37:        SetPSR();
1.1.1.2   root       38: 
1.1.1.4 ! root       39:        epsr = Undefined;
        !            40:        // scoreboard: cleared
        !            41:        ssbr = Undefined;
1.1.1.2   root       42: 
1.1       root       43:        // 実際には m88k MPU はリセット直後は 0 番地から実行を開始するので、
                     44:        // 大抵の場合システムでリセット直後は 0 番地付近に ROM を見せるように
                     45:        // してあるのだと思うが、ここではその代わりに ROM のアドレスを指定して、
                     46:        // 直接そこから実行を開始することにする。
                     47:        fip = reset_vector;
                     48:        nip = 0;
                     49:        xip = 0;
1.1.1.4 ! root       50:        sfip = Undefined;
        !            51:        snip = Undefined;
        !            52:        sxip = Undefined;
        !            53: 
        !            54:        vbr = 0;
        !            55:        // DMTx は bit0(Valid) をクリア。他は不定。
        !            56:        dmt0 &= ~DM_VALID;
        !            57:        dmt1 &= ~DM_VALID;
        !            58:        dmt2 &= ~DM_VALID;
        !            59:        dma0 = Undefined;
        !            60:        dma1 = Undefined;
        !            61:        dma2 = Undefined;
        !            62:        dmd0 = Undefined;
        !            63:        dmd1 = Undefined;
        !            64:        dmd2 = Undefined;
        !            65:        for (int i = 1; i < 32; i++) {
        !            66:                r[i] = Undefined;
        !            67:        }
        !            68: 
        !            69:        fpecr = 0;
        !            70:        for (int i = 1; i < 9; i++) {
        !            71:                fcr[i] = Undefined;
        !            72:        }
        !            73:        fpcr = 0;
        !            74:        fpsr = 0;
        !            75: 
        !            76:        cmmu[0].Reset();
        !            77:        cmmu[1].Reset();
        !            78: 
        !            79:        // 履歴を初期化
        !            80:        exhist.Clear();
        !            81:        brhist.Clear();
        !            82: 
        !            83:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
        !            84:        // リセット例外発生時の from にはあまり意味がないので 0 にするか。
        !            85:        exhist.AddEntry(0, 0, 0xfc000000 | 0);
        !            86:        brhist.AddEntry(0, 0, 0xfc000000 | 0);
        !            87:        // デバッガに通知 (例外ブレーク用)
        !            88:        debugger_notify_exception(0);
1.1       root       89: 
                     90:        fetch();
                     91: }
                     92: 
                     93: // request サイクル分実行する。
                     94: uint32
                     95: m88kcpu::Run(uint64 request)
                     96: {
                     97:        uint64 goal_cycle = total_cycle + request;
                     98:        bool is_release = false;
                     99:        bool is_intr = false;
                    100: 
1.1.1.2   root      101:        if ((atomic_reqflag & CPU_REQ_STOP)) {
                    102:                if ((atomic_reqflag & CPU_REQ_INTR) == 0) {
                    103:                        // STOP 状態のままで割り込みが無ければ、
                    104:                        // STOP 継続として戻る。
                    105:                        total_cycle = goal_cycle;
                    106:                        return atomic_reqflag;
                    107:                }
                    108:                // 状態が変わったら STOP 解除。
                    109:                atomic_reqflag &= ~CPU_REQ_STOP;
                    110:        }
                    111: 
1.1       root      112:        while (!is_release) {
                    113:                // shift pipeline
                    114:                opX = opF;
                    115:                xip = nip;
                    116: 
                    117:                // prefetch next inst
                    118:                fetch();
                    119: 
                    120:                // この時点で実行しようとする命令が opX に入っている
                    121: 
                    122:                if (atomic_reqflag != 0) {
                    123:                        // 何かが起きた
                    124: 
                    125:                        // 割り込みの認識
                    126:                        // 割り込みの実行は命令実行完了後、次のプリフェッチの前
                    127:                        if ((atomic_reqflag & CPU_REQ_INTR)) {
                    128:                                atomic_reqflag &= ~CPU_REQ_INTR;
                    129:                                is_intr = true;
1.1.1.2   root      130: #if defined(TEST_INTERRUPT)
1.1.1.4 ! root      131:                                atomic_reqflag |= CPU_REQ_PROMPT;
1.1       root      132: #endif
                    133:                        }
                    134: 
                    135:                        if ((atomic_reqflag & CPU_REQ_TRACE)) {
                    136:                                // デバッガプロンプトを出すかどうかを判断する
                    137:                                //inst_count++;
                    138:                                if (debugger_check()) {
                    139:                                        atomic_reqflag |= CPU_REQ_PROMPT;
                    140:                                }
                    141:                        }
                    142: 
                    143:                        if ((atomic_reqflag & CPU_REQ_PROMPT)) {
                    144:                                // デバッガプロンプトのための実行停止
                    145: 
                    146:                                // プロンプト獲得を通知
                    147:                                gCVPrompt->NotifyAcquire();
                    148: 
                    149:                                // プロンプト解放を待機
                    150:                                gCVPrompt->WaitRelease();
                    151: 
                    152:                                // プロンプトを抜けたのでここでフラグを落とす
                    153:                                atomic_reqflag &= ~CPU_REQ_PROMPT;
1.1.1.4 ! root      154: 
        !           155:                                // プロンプトから戻ってきたら一旦スケジューラまで戻る(?)。
        !           156:                                // reset コマンドのようにデバッガからスケジューラに出した
        !           157:                                // リクエストを(なるはやで?)回収するため。
        !           158:                                atomic_reqflag |= CPU_REQ_RELEASE;
1.1       root      159:                        }
                    160: 
                    161:                        if ((atomic_reqflag & CPU_REQ_RELEASE)) {
                    162:                                // 中断リクエスト受信
                    163:                                // この命令を実行し終わったら抜ける
                    164:                                atomic_reqflag &= ~CPU_REQ_RELEASE;
                    165:                                is_release = true;
                    166:                        }
                    167:                }
                    168: 
                    169:                if (OpIsBusErr(opX)) {
                    170:                        // プリフェッチしていた命令がバスエラー
                    171:                        Exception(M88K_EXCEP_INST);
                    172:                        continue;
                    173:                }
                    174: 
                    175:                uint32 op12 = op32_to_12(opX);
                    176: 
                    177:                switch (op12) {
                    178: #include "m88100switch.inc"
                    179:                 default:
1.1.1.2   root      180:                        OP_FUNC(illegal);
                    181:                        break;
1.1       root      182:                }
                    183: 
                    184:                if (is_intr) {
                    185:                        if (!(psr & PSR_IND)) {
1.1.1.2   root      186:                                // XXX: 割り込み信号線はレベル割り込みなのだが
                    187:                                // まだ処理できないのでとりあえずラッチ割り込みにしておく。
                    188:                                is_intr = false;
1.1       root      189:                                gMPU->putlog(4, "INTR take");
                    190:                                ExceptionCore(M88K_EXCEP_INTERRUPT, ExceptionKind::INTR);
                    191:                                continue;
                    192:                        } else {
                    193:                                gMPU->putlog(4, "INTR DISABLE");
                    194:                        }
                    195:                }
                    196: 
                    197:                total_cycle++;
1.1.1.2   root      198: 
                    199:                if ((atomic_reqflag & CPU_REQ_STOP)) {
                    200:                        // STOP 状態は、残りサイクルを消費したことにして戻る
                    201:                        gMPU->putlog(2, "STOP 状態検出");
                    202:                        total_cycle = goal_cycle;
                    203:                        is_release = true;
                    204:                }
                    205: 
1.1       root      206:                if (total_cycle >= goal_cycle)
                    207:                        break;
                    208:        }
                    209: 
                    210:        return atomic_reqflag;
                    211: }
                    212: 
                    213: // この命令後に実行を中断して VM に戻る
                    214: void
                    215: m88kcpu::Release()
                    216: {
                    217:        atomic_reqflag |= CPU_REQ_RELEASE;
                    218: }
                    219: 
                    220: // 通常の例外。
1.1.1.2   root      221: // DataAccessException, エラー、割り込み、TRAP からは使わない。
1.1       root      222: // vec はベクタ番号。
                    223: void
                    224: m88kcpu::Exception(int vec)
                    225: {
                    226:        ExceptionCore(vec, ExceptionKind::NORMAL);
                    227: }
                    228: 
                    229: // 例外処理コア部分
                    230: // vec はベクタ番号。
                    231: void
                    232: m88kcpu::ExceptionCore(int vec, ExceptionKind cause)
                    233: {
1.1.1.4 ! root      234:        uint syscall = 0;
        !           235: 
1.1.1.3   root      236:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.4 ! root      237:        // OpenBSD システムコールなら番号もついでに記録。
        !           238:        // システムコール番号は tb0 発行時点で r13 にセットされている。
        !           239:        // ただし 0 番は syscall(2) (間接システムコール) で、実際の番号は r2。
        !           240:        // 198番 __syscall(2) だと r2:r3 (なので実質 r3)。
        !           241:        if (vec == 450) {
        !           242:                syscall = r[13];
        !           243:                if (syscall == 0) {
        !           244:                        syscall = r[2];
        !           245:                } else if (syscall == 198) {
        !           246:                        syscall = r[3];
        !           247:                }
        !           248:                syscall &= 0xfff;
        !           249:        }
        !           250:        exhist.AddEntry(xip, 0, 0xfc000000 | (syscall << 12) | vec);
        !           251:        brhist.AddEntry(xip, 0, 0xfc000000 | (syscall << 12) | vec);
1.1.1.3   root      252:        // デバッガに通知 (例外ブレーク用)
1.1.1.4 ! root      253:        debugger_notify_exception(vec);
        !           254: 
        !           255:        // 命令中で起きる例外はとりあえず全部2クロック追加? (Table.7-5)
        !           256:        if (cause != ExceptionKind::INTR) {
        !           257:                total_cycle += 2;
        !           258:        }
1.1.1.3   root      259: 
1.1       root      260:        if (psr & PSR_SFRZ) {
                    261:                if (cause != ExceptionKind::TRAP) {
                    262:                        gMPU->putlog(2, "SFRZ Error Exception");
                    263:                        vec = M88K_EXCEP_ERROR;
                    264:                        cause = ExceptionKind::ERROR;
                    265:                }
                    266:        } else {
                    267:                gMPU->putlog(2, "Exception %x", vec);
1.1.1.2   root      268:                if (vec != 1) {
                    269:                        gMPU->putlog(1, "Exception %x x=%x n=%x f=%x", vec, xip, nip, fip);
                    270:                }
1.1       root      271:                sxip = xip;
                    272:                snip = nip;
                    273:                sfip = fip; 
                    274: 
                    275:                sxip |= SIP_V;
                    276:                snip |= SIP_V;
1.1.1.4 ! root      277:                sfip |= SIP_V;
1.1       root      278: 
                    279:                if (OpIsBusErr(opX)) {
                    280:                        sxip |= SIP_E;  // E bit
                    281:                }
                    282:                if (OpIsBusErr(opF)) {
                    283:                        snip |= SIP_E;  // E bit
                    284:                }
                    285: 
                    286:                if (vec == M88K_EXCEP_UNIMPL_OP) {
                    287:                        sxip &= ~SIP_V;
                    288:                }
                    289:        }
                    290: 
1.1.1.2   root      291:        if (cause != ExceptionKind::DATA) {
                    292:                // データアクセス例外以外は、
                    293:                // データパイプラインはフラッシュ状態とする。
                    294:                // ほんとうは違う。かも。
                    295:                dmt0 = 0;
                    296:        } else {
                    297:                // xip: ld/st/xmem
                    298:                // nip: next
                    299:                // fip: fetch
                    300: 
                    301:                // rom1.2 は DAE が起きると、
                    302: 
                    303:                // ROM挙動               CPU の RTE 挙動
                    304:                // sfip = sxip
                    305:                // sxip -> ~V (INVALID)  CPU はそもそも sxip を評価しない
                    306:                // snip = 0 (INVALID)    CPU はこれを nop 相当に処理する
                    307:                // rte
                    308: 
                    309:                // してくる。そのまま読むと命令を再実行しようとしているように
                    310:                // 読めるが、再実行すると無限ループになってしまう。
                    311:                // DAE の時点で xip が進んでいることを期待して利用している?
                    312: 
                    313:                // openbsd は
                    314:                // xmem の write バスエラーを検知すると命令を再実行するために
                    315:                // fip = nip, nip = xip して rte する。ということは xip = xmem に
                    316:                // なっていることを期待している。
                    317: 
                    318:                // というわけで
                    319:                // ld で DataAccessException のときは、実CPUはすでに次の命令を
                    320:                // 実行している?
                    321:                // もう少し考えると、スコアボードでレジスタの干渉がなければ、
                    322:                // 実行している?
                    323: 
                    324:                // 仕方がないのでハックでごまかす。
                    325:                // rte のほうも参照のこと。
                    326: 
                    327:                if (IsSuper() && xip >= 0x41000000 && xip < 0x42000000) {
                    328:                        // 遅延例外機構がないので、ROM 合わせのハック。
                    329:                        sxip = snip;
                    330:                }
                    331:        }
                    332: 
1.1       root      333:        epsr = psr;
1.1.1.2   root      334:        SetPSR(psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ);
1.1       root      335: 
                    336:        fip = vbr + (vec << 3);
                    337:        fetch();
1.1.1.3   root      338:        // ここでベクタに飛ぶのだが、ベクタ内の2命令でおそらく必ずもう一度
                    339:        // 分岐してそっちでも履歴が残るので、ここでブランチ履歴を残すのは
                    340:        // ちょっと冗長という気もする。
                    341: 
1.1       root      342:        if (OpIsBusErr(opF)) {
                    343:                if (cause == ExceptionKind::ERROR) {
                    344:                        // double bus fault
                    345:                        // 実機は無限ループ状態
                    346:                        PANIC("Infinite ERROR (double bus fault)");
                    347:                } else {
                    348:                        ExceptionCore(M88K_EXCEP_ERROR, ExceptionKind::ERROR);
                    349:                }
                    350:        }
                    351: }
                    352: 
                    353: // データアクセス例外(Read)
                    354: void
                    355: m88kcpu::ReadDataException(uint32 addr, uint32 flag)
                    356: {
                    357:        // ミスアラインドはこの例外より前にチェックされていて、
                    358:        // ここにはアラインドしかこない。
                    359:        dma0 = addr & ~0x3;
                    360:        dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
                    361:             | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
                    362:             | (flag & DM_DOUB1)        // ダブルワードの第1アクセスのときセット
                    363:             | (flag & DM_LOCK)         // xmem でセット
                    364:             | (FLD_D << 7)
                    365:             | (flag & DM_SIGNED)
                    366:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
                    367:             | 0 // DM_WRITE = 0
                    368:             | DM_VALID;
1.1.1.2   root      369:        gMPU->putlog(1, "ReadDAE xip=%x addr=%x", xip, addr);
                    370:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1       root      371: }
                    372: 
                    373: // データアクセス例外(Write)
                    374: void
                    375: m88kcpu::WriteDataException(uint32 addr, uint32 data, uint32 flag)
                    376: {
                    377:        // ミスアラインドはこの例外より前にチェックされていて、
                    378:        // ここにはアラインドしかこない。
                    379:        dma0 = addr & ~0x3;
                    380:        dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
                    381:             | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
                    382:             | (flag & DM_DOUB1)        // ダブルワードの第1アクセスのときセット
                    383:             | (flag & DM_LOCK)         // xmem でセット
                    384:             | (FLD_D << 7)
                    385:             | (flag & DM_SIGNED)
                    386:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
                    387:             | DM_WRITE
                    388:             | DM_VALID;
                    389: 
1.1.1.2   root      390:        dmd0 = data;
                    391:        gMPU->putlog(1, "WriteDAE xip=%x addr=%x", xip, addr);
                    392:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
                    393: }
                    394: 
                    395: // データアクセス例外(xmem)
                    396: void
                    397: m88kcpu::XmemDataException(uint32 addr, uint32 data, uint32 flag)
                    398: {
                    399:        dma0 = addr & ~0x3;
                    400:        dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
                    401:             | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
                    402:             | (flag & DM_DOUB1)        // ダブルワードの第1アクセスのときセット
                    403:             | (flag & DM_LOCK)         // xmem でセット
                    404:             | (FLD_D << 7)
                    405:             | (flag & DM_SIGNED)
                    406:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
                    407:             | 0 // DM_WRITE = 0
                    408:             | DM_VALID;
                    409: 
                    410:        dma1 = addr & ~0x3;
                    411:        dmt1 = ((psr & PSR_BO_LE) ? DM_BO : 0)
                    412:             | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
                    413:             | (flag & DM_DOUB1)        // ダブルワードの第1アクセスのときセット
                    414:             | (flag & DM_LOCK)         // xmem でセット
                    415:             | (FLD_D << 7)
                    416:             | (flag & DM_SIGNED)
                    417:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
                    418:             | DM_WRITE
                    419:             | DM_VALID;
                    420: 
                    421:        dmd1 = data;
                    422: 
                    423:        // ミスアラインドはこの例外より前にチェックされていて、
                    424:        // ここにはアラインドしかこない。
                    425:        if (cmmu[1].fault_code != m88200::FAULT_CODE_BUSERR
                    426:         || cmmu[1].acc_read) {
                    427:                // アドレス変換フォルトまたは read 時点
                    428:                // nop
1.1       root      429:        } else {
1.1.1.2   root      430:                // xmem の write 時点
                    431:                dma0 = dma1;
                    432:                dmt0 = dmt1;
                    433:                dmd0 = dmd1;
                    434:                dmt1 &= ~DM_VALID;
1.1       root      435:        }
1.1.1.2   root      436: 
                    437:        gMPU->putlog(1, "xmemDAE xip=%x addr=%x", xip, addr);
                    438:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1       root      439: }
                    440: 
                    441: void
                    442: m88kcpu::Interrupt()
                    443: {
                    444:        atomic_reqflag |= CPU_REQ_INTR;
1.1.1.2   root      445: //     gMPU->putlog(1, "INTERRUPT IGNORED");
1.1       root      446:        gMPU->putlog(4, "INTERRUPT ACK (アドレスは不正確)");
                    447: }
                    448: 
                    449: void
                    450: m88kcpu::fpu_unimpl()
                    451: {
                    452:        printf("%s\n", __func__);
                    453: }
1.1.1.2   root      454: 
                    455: OP_DEF(illegal)
                    456: {
                    457:        // 本来は不当命令例外?
                    458:        gMPU->putlog(0, "Illegal instruction %08x", (uint32)opX);
                    459: }

unix.superglobalmegacorp.com

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