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

unix.superglobalmegacorp.com

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