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

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: {
                    185:        if (psr & PSR_SFRZ) {
                    186:                if (cause != ExceptionKind::TRAP) {
                    187:                        gMPU->putlog(2, "SFRZ Error Exception");
                    188:                        vec = M88K_EXCEP_ERROR;
                    189:                        cause = ExceptionKind::ERROR;
                    190:                }
                    191:        } else {
                    192:                gMPU->putlog(2, "Exception %x", vec);
1.1.1.2 ! root      193:                if (vec != 1) {
        !           194:                        gMPU->putlog(1, "Exception %x x=%x n=%x f=%x", vec, xip, nip, fip);
        !           195:                }
1.1       root      196:                sxip = xip;
                    197:                snip = nip;
                    198:                sfip = fip; 
                    199: 
                    200:                sxip |= SIP_V;
                    201:                snip |= SIP_V;
                    202:                // XXX:実機と異なり、fip は常にフェッチ前なので V=0
1.1.1.2 ! root      203:                // ^^^^ コレ自体怪しい。INTERRUPT とか。
1.1       root      204: 
                    205:                if (OpIsBusErr(opX)) {
                    206:                        sxip |= SIP_E;  // E bit
                    207:                }
                    208:                if (OpIsBusErr(opF)) {
                    209:                        snip |= SIP_E;  // E bit
                    210:                }
                    211: 
                    212:                if (vec == M88K_EXCEP_UNIMPL_OP) {
                    213:                        sxip &= ~SIP_V;
                    214:                }
                    215:        }
                    216: 
1.1.1.2 ! root      217:        if (cause != ExceptionKind::DATA) {
        !           218:                // データアクセス例外以外は、
        !           219:                // データパイプラインはフラッシュ状態とする。
        !           220:                // ほんとうは違う。かも。
        !           221:                dmt0 = 0;
        !           222:        } else {
        !           223:                // xip: ld/st/xmem
        !           224:                // nip: next
        !           225:                // fip: fetch
        !           226: 
        !           227:                // rom1.2 は DAE が起きると、
        !           228: 
        !           229:                // ROM挙動               CPU の RTE 挙動
        !           230:                // sfip = sxip
        !           231:                // sxip -> ~V (INVALID)  CPU はそもそも sxip を評価しない
        !           232:                // snip = 0 (INVALID)    CPU はこれを nop 相当に処理する
        !           233:                // rte
        !           234: 
        !           235:                // してくる。そのまま読むと命令を再実行しようとしているように
        !           236:                // 読めるが、再実行すると無限ループになってしまう。
        !           237:                // DAE の時点で xip が進んでいることを期待して利用している?
        !           238: 
        !           239:                // openbsd は
        !           240:                // xmem の write バスエラーを検知すると命令を再実行するために
        !           241:                // fip = nip, nip = xip して rte する。ということは xip = xmem に
        !           242:                // なっていることを期待している。
        !           243: 
        !           244:                // というわけで
        !           245:                // ld で DataAccessException のときは、実CPUはすでに次の命令を
        !           246:                // 実行している?
        !           247:                // もう少し考えると、スコアボードでレジスタの干渉がなければ、
        !           248:                // 実行している?
        !           249: 
        !           250:                // 仕方がないのでハックでごまかす。
        !           251:                // rte のほうも参照のこと。
        !           252: 
        !           253:                if (IsSuper() && xip >= 0x41000000 && xip < 0x42000000) {
        !           254:                        // 遅延例外機構がないので、ROM 合わせのハック。
        !           255:                        sxip = snip;
        !           256:                }
        !           257:        }
        !           258: 
1.1       root      259:        epsr = psr;
1.1.1.2 ! root      260:        SetPSR(psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ);
1.1       root      261: 
                    262:        fip = vbr + (vec << 3);
1.1.1.2 ! root      263:        brhist.AddEntry(xip, fip);
1.1       root      264:        fetch();
                    265:        if (OpIsBusErr(opF)) {
                    266:                if (cause == ExceptionKind::ERROR) {
                    267:                        // double bus fault
                    268:                        // 実機は無限ループ状態
                    269:                        PANIC("Infinite ERROR (double bus fault)");
                    270:                } else {
                    271:                        ExceptionCore(M88K_EXCEP_ERROR, ExceptionKind::ERROR);
                    272:                }
                    273:        }
                    274: }
                    275: 
                    276: // データアクセス例外(Read)
                    277: void
                    278: m88kcpu::ReadDataException(uint32 addr, uint32 flag)
                    279: {
                    280:        // ミスアラインドはこの例外より前にチェックされていて、
                    281:        // ここにはアラインドしかこない。
                    282:        dma0 = addr & ~0x3;
                    283:        dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
                    284:             | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
                    285:             | (flag & DM_DOUB1)        // ダブルワードの第1アクセスのときセット
                    286:             | (flag & DM_LOCK)         // xmem でセット
                    287:             | (FLD_D << 7)
                    288:             | (flag & DM_SIGNED)
                    289:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
                    290:             | 0 // DM_WRITE = 0
                    291:             | DM_VALID;
1.1.1.2 ! root      292:        gMPU->putlog(1, "ReadDAE xip=%x addr=%x", xip, addr);
        !           293:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1       root      294: }
                    295: 
                    296: // データアクセス例外(Write)
                    297: void
                    298: m88kcpu::WriteDataException(uint32 addr, uint32 data, uint32 flag)
                    299: {
                    300:        // ミスアラインドはこの例外より前にチェックされていて、
                    301:        // ここにはアラインドしかこない。
                    302:        dma0 = addr & ~0x3;
                    303:        dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
                    304:             | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
                    305:             | (flag & DM_DOUB1)        // ダブルワードの第1アクセスのときセット
                    306:             | (flag & DM_LOCK)         // xmem でセット
                    307:             | (FLD_D << 7)
                    308:             | (flag & DM_SIGNED)
                    309:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
                    310:             | DM_WRITE
                    311:             | DM_VALID;
                    312: 
1.1.1.2 ! root      313:        dmd0 = data;
        !           314:        gMPU->putlog(1, "WriteDAE xip=%x addr=%x", xip, addr);
        !           315:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
        !           316: }
        !           317: 
        !           318: // データアクセス例外(xmem)
        !           319: void
        !           320: m88kcpu::XmemDataException(uint32 addr, uint32 data, uint32 flag)
        !           321: {
        !           322:        dma0 = addr & ~0x3;
        !           323:        dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
        !           324:             | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
        !           325:             | (flag & DM_DOUB1)        // ダブルワードの第1アクセスのときセット
        !           326:             | (flag & DM_LOCK)         // xmem でセット
        !           327:             | (FLD_D << 7)
        !           328:             | (flag & DM_SIGNED)
        !           329:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
        !           330:             | 0 // DM_WRITE = 0
        !           331:             | DM_VALID;
        !           332: 
        !           333:        dma1 = addr & ~0x3;
        !           334:        dmt1 = ((psr & PSR_BO_LE) ? DM_BO : 0)
        !           335:             | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
        !           336:             | (flag & DM_DOUB1)        // ダブルワードの第1アクセスのときセット
        !           337:             | (flag & DM_LOCK)         // xmem でセット
        !           338:             | (FLD_D << 7)
        !           339:             | (flag & DM_SIGNED)
        !           340:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
        !           341:             | DM_WRITE
        !           342:             | DM_VALID;
        !           343: 
        !           344:        dmd1 = data;
        !           345: 
        !           346:        // ミスアラインドはこの例外より前にチェックされていて、
        !           347:        // ここにはアラインドしかこない。
        !           348:        if (cmmu[1].fault_code != m88200::FAULT_CODE_BUSERR
        !           349:         || cmmu[1].acc_read) {
        !           350:                // アドレス変換フォルトまたは read 時点
        !           351:                // nop
1.1       root      352:        } else {
1.1.1.2 ! root      353:                // xmem の write 時点
        !           354:                dma0 = dma1;
        !           355:                dmt0 = dmt1;
        !           356:                dmd0 = dmd1;
        !           357:                dmt1 &= ~DM_VALID;
1.1       root      358:        }
1.1.1.2 ! root      359: 
        !           360:        gMPU->putlog(1, "xmemDAE xip=%x addr=%x", xip, addr);
        !           361:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1       root      362: }
                    363: 
                    364: void
                    365: m88kcpu::Interrupt()
                    366: {
                    367:        atomic_reqflag |= CPU_REQ_INTR;
1.1.1.2 ! root      368: //     gMPU->putlog(1, "INTERRUPT IGNORED");
1.1       root      369:        gMPU->putlog(4, "INTERRUPT ACK (アドレスは不正確)");
                    370: }
                    371: 
                    372: void
                    373: m88kcpu::fpu_unimpl()
                    374: {
                    375:        printf("%s\n", __func__);
                    376: }
1.1.1.2 ! root      377: 
        !           378: OP_DEF(illegal)
        !           379: {
        !           380:        // 本来は不当命令例外?
        !           381:        gMPU->putlog(0, "Illegal instruction %08x", (uint32)opX);
        !           382: }

unix.superglobalmegacorp.com

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