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

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"
1.1.1.7   root       12: #include "scheduler.h"
1.1       root       13: 
                     14: #define OP_DEF(name)   void __CONCAT(m88kcpu::op_,name)()
                     15: #define OP_FUNC(name)  __CONCAT(op_,name)()
                     16: #include "m88100ops.cpp"
                     17: 
1.1.1.7   root       18: // 文字列を作る前にレベルを評価するためマクロ
                     19: #define cpulog(lv, fmt...)     do {    \
                     20:        if (__predict_false(gMPU->loglevel >= (lv))) {  \
                     21:                gMPU->putlogn(fmt);     \
                     22:        }       \
                     23: } while (0)
                     24: 
1.1.1.8   root       25: void
                     26: m88kcpu::PowerOn()
                     27: {
                     28:        // 履歴は電源オン時だけ初期化。
                     29:        // (LUNA88K は ROM が正常パスで CPU リセットを行ったりするので)
                     30:        exhist.Clear();
                     31:        brhist.Clear();
                     32: 
                     33:        // この後起きるリセット例外で xip を初期化する前に参照することになるので
                     34:        // これだけここでも初期化しておく。
                     35:        xip = 0;
                     36: }
                     37: 
1.1       root       38: // リセット例外のようなもの?
                     39: void
1.1.1.5   root       40: m88kcpu::Reset()
1.1       root       41: {
1.1.1.8   root       42:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
                     43:        // リセット例外も発生時の XIP を記録する。(LUNA88K の ROM 1.20)
                     44:        exhist.AddEntry(xip | 1, 0, 0xfc000000 | 0);
                     45:        brhist.AddEntry(xip | 1, 0, 0xfc000000 | 0);
                     46:        // デバッガに通知 (例外ブレーク用)
                     47:        debugger_notify_exception(0);
                     48: 
1.1.1.5   root       49:        // 内部の割り込み状態をクリア
                     50:        intr_pending = 0;
1.1.1.7   root       51:        atomic_reqflag &= ~(CPU_REQ_RESET | CPU_REQ_INTR | CPU_REQ_STOP);
1.1.1.4   root       52: 
                     53:        // Table 6-8 (p6-47)
1.1       root       54:        psr = 0x800003ff;
1.1.1.4   root       55:        // XXX ただし SFU1 は未実装なので下げておく
1.1       root       56:        psr &= ~PSR_SFD1;
                     57: 
1.1.1.2   root       58: #if defined(TEST_INTERRUPT)
1.1.1.4   root       59:        psr &= ~PSR_IND;
                     60:        psr &= ~PSR_SFRZ;
1.1       root       61: #endif
                     62: 
1.1.1.4   root       63:        SetPSR();
1.1.1.2   root       64: 
1.1.1.8   root       65:        fip = 0;
1.1.1.7   root       66: 
                     67:        // レジスタのうち明記されてるものをクリア。
                     68:        // 不定と明記されてるものはリセットでは触らないでおく。
                     69:        // scoreboard: cleared
1.1       root       70:        nip = 0;
                     71:        xip = 0;
1.1.1.4   root       72:        vbr = 0;
                     73:        fpecr = 0;
                     74:        fpcr = 0;
                     75:        fpsr = 0;
1.1.1.7   root       76:        // DMTx は bit0(Valid) をクリア。他は不定
                     77:        dmt0 &= ~DM_VALID;
                     78:        dmt1 &= ~DM_VALID;
                     79:        dmt2 &= ~DM_VALID;
1.1.1.4   root       80: 
                     81:        cmmu[0].Reset();
                     82:        cmmu[1].Reset();
                     83: 
1.1       root       84:        fetch();
                     85: }
                     86: 
1.1.1.5   root       87: // 仮想時間 delta [nsec] だけ CPU を実行する。実際には大抵行き過ぎる。
1.1.1.7   root       88: // 戻り値は CPU 状態 (Scheduler::SCHED_CPU_*)。
1.1       root       89: uint32
1.1.1.5   root       90: m88kcpu::Run(uint32 delta)
1.1       root       91: {
                     92:        bool is_release = false;
                     93:        bool is_intr = false;
                     94: 
1.1.1.5   root       95:        assert(used_cycle == 0);
                     96: 
                     97:        goal_cycle = Vtime2Cycle(delta);
                     98:        if (__predict_false(goal_cycle == 0)) {
                     99:                goal_cycle = 1;
                    100:        }
                    101: 
1.1.1.2   root      102:        if ((atomic_reqflag & CPU_REQ_STOP)) {
1.1.1.5   root      103:                if ((atomic_reqflag & (CPU_REQ_INTR | CPU_REQ_PROMPT | CPU_REQ_RESET))) {
                    104:                        // 割り込み、デバッガ、リセットが来たら STOP 解除。
                    105:                        atomic_reqflag &= ~CPU_REQ_STOP;
                    106:                } else {
1.1.1.2   root      107:                        // STOP 継続として戻る。
1.1.1.5   root      108:                        used_cycle = goal_cycle;
1.1.1.6   root      109:                        goto exit;
1.1.1.2   root      110:                }
                    111:        }
                    112: 
1.1       root      113:        while (!is_release) {
                    114:                // shift pipeline
                    115:                opX = opF;
                    116:                xip = nip;
                    117: 
                    118:                // prefetch next inst
                    119:                fetch();
                    120: 
                    121:                // この時点で実行しようとする命令が opX に入っている
                    122: 
                    123:                if (atomic_reqflag != 0) {
                    124:                        // 何かが起きた
                    125: 
1.1.1.5   root      126:                        if ((atomic_reqflag & CPU_REQ_RESET)) {
                    127:                                // リセット例外。
                    128:                                Reset();
                    129:                                // XIP がリセットベクタを指すためにはもう一回フェッチが必要
                    130:                                // なので、ここは continue が必要。
                    131:                                continue;
                    132:                        }
                    133: 
1.1       root      134:                        // 割り込みの認識
                    135:                        // 割り込みの実行は命令実行完了後、次のプリフェッチの前
                    136:                        if ((atomic_reqflag & CPU_REQ_INTR)) {
                    137:                                atomic_reqflag &= ~CPU_REQ_INTR;
1.1.1.5   root      138:                                if (intr_pending && IsIntrEnable()) {
                    139:                                        // この命令のあとに割り込み処理
                    140:                                        is_intr = true;
                    141:                                }
1.1.1.2   root      142: #if defined(TEST_INTERRUPT)
1.1.1.4   root      143:                                atomic_reqflag |= CPU_REQ_PROMPT;
1.1       root      144: #endif
                    145:                        }
                    146: 
                    147:                        if ((atomic_reqflag & CPU_REQ_TRACE)) {
                    148:                                // デバッガプロンプトを出すかどうかを判断する
                    149:                                //inst_count++;
                    150:                                if (debugger_check()) {
                    151:                                        atomic_reqflag |= CPU_REQ_PROMPT;
                    152:                                }
                    153:                        }
                    154: 
                    155:                        if ((atomic_reqflag & CPU_REQ_PROMPT)) {
                    156:                                // デバッガプロンプトのための実行停止
                    157: 
                    158:                                // プロンプト獲得を通知
                    159:                                gCVPrompt->NotifyAcquire();
                    160: 
                    161:                                // プロンプト解放を待機
                    162:                                gCVPrompt->WaitRelease();
                    163: 
                    164:                                // プロンプトを抜けたのでここでフラグを落とす
                    165:                                atomic_reqflag &= ~CPU_REQ_PROMPT;
1.1.1.4   root      166: 
                    167:                                // プロンプトから戻ってきたら一旦スケジューラまで戻る(?)。
                    168:                                // reset コマンドのようにデバッガからスケジューラに出した
                    169:                                // リクエストを(なるはやで?)回収するため。
                    170:                                atomic_reqflag |= CPU_REQ_RELEASE;
1.1       root      171:                        }
                    172: 
                    173:                        if ((atomic_reqflag & CPU_REQ_RELEASE)) {
                    174:                                // 中断リクエスト受信
                    175:                                // この命令を実行し終わったら抜ける
                    176:                                atomic_reqflag &= ~CPU_REQ_RELEASE;
                    177:                                is_release = true;
                    178:                        }
                    179:                }
                    180: 
                    181:                if (OpIsBusErr(opX)) {
                    182:                        // プリフェッチしていた命令がバスエラー
                    183:                        Exception(M88K_EXCEP_INST);
                    184:                        continue;
                    185:                }
                    186: 
                    187:                uint32 op12 = op32_to_12(opX);
                    188: 
                    189:                switch (op12) {
                    190: #include "m88100switch.inc"
                    191:                 default:
1.1.1.2   root      192:                        OP_FUNC(illegal);
                    193:                        break;
1.1       root      194:                }
                    195: 
1.1.1.5   root      196:                if (is_intr && IsIntrEnable()) {
1.1.1.10! root      197:                        // 割り込み処理要求が来ていて、
        !           198:                        // 直前の命令が割り込みを禁止していなければ割り込み
1.1.1.5   root      199:                        // XXX 実際は違う気がする
                    200:                        is_intr = false;
1.1.1.7   root      201:                        cpulog(4, "INTR take");
1.1.1.5   root      202:                        ExceptionCore(M88K_EXCEP_INTERRUPT, ExceptionKind::INTR);
                    203:                        continue;
1.1       root      204:                }
                    205: 
1.1.1.5   root      206:                used_cycle++;
1.1.1.2   root      207: 
                    208:                if ((atomic_reqflag & CPU_REQ_STOP)) {
                    209:                        // STOP 状態は、残りサイクルを消費したことにして戻る
1.1.1.7   root      210:                        cpulog(2, "STOP 状態検出");
1.1.1.6   root      211:                        if (used_cycle < goal_cycle) {
                    212:                                used_cycle = goal_cycle;
                    213:                        }
1.1.1.2   root      214:                }
                    215: 
1.1.1.9   root      216:                // XXX 命令の実行でリリースするのに、いったんループを回って
                    217:                // からではタイミングが遅すぎる
                    218:                if ((atomic_reqflag & CPU_REQ_RELEASE)) {
                    219:                        // 中断リクエスト受信
                    220:                        // この命令を実行し終わったら抜ける
                    221:                        atomic_reqflag &= ~CPU_REQ_RELEASE;
                    222:                        is_release = true;
                    223:                }
                    224: 
1.1.1.5   root      225:                if (used_cycle >= goal_cycle)
1.1       root      226:                        break;
                    227:        }
                    228: 
1.1.1.6   root      229:  exit:
1.1.1.5   root      230:        total_vtime += Cycle2Vtime(used_cycle);
                    231:        used_cycle = 0;
                    232: 
1.1.1.7   root      233:        // HALT 状態がないので NORMAL か STOP かだけでいい
                    234:        return (atomic_reqflag & CPU_REQ_STOP)
                    235:                ? Scheduler::SCHED_CPU_STOP
                    236:                : Scheduler::SCHED_CPU_NORMAL;
1.1.1.5   root      237: }
                    238: 
1.1       root      239: // この命令後に実行を中断して VM に戻る
                    240: void
                    241: m88kcpu::Release()
                    242: {
                    243:        atomic_reqflag |= CPU_REQ_RELEASE;
                    244: }
                    245: 
1.1.1.5   root      246: // リセット例外を発行する
                    247: void
                    248: m88kcpu::RequestReset()
                    249: {
                    250:        atomic_reqflag |= CPU_REQ_RESET;
                    251: }
                    252: 
1.1       root      253: // 通常の例外。
1.1.1.2   root      254: // DataAccessException, エラー、割り込み、TRAP からは使わない。
1.1       root      255: // vec はベクタ番号。
                    256: void
                    257: m88kcpu::Exception(int vec)
                    258: {
                    259:        ExceptionCore(vec, ExceptionKind::NORMAL);
                    260: }
                    261: 
                    262: // 例外処理コア部分
                    263: // vec はベクタ番号。
                    264: void
                    265: m88kcpu::ExceptionCore(int vec, ExceptionKind cause)
                    266: {
1.1.1.4   root      267:        uint syscall = 0;
                    268: 
1.1.1.3   root      269:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.4   root      270:        // OpenBSD システムコールなら番号もついでに記録。
                    271:        // システムコール番号は tb0 発行時点で r13 にセットされている。
                    272:        // ただし 0 番は syscall(2) (間接システムコール) で、実際の番号は r2。
                    273:        // 198番 __syscall(2) だと r2:r3 (なので実質 r3)。
                    274:        if (vec == 450) {
                    275:                syscall = r[13];
                    276:                if (syscall == 0) {
                    277:                        syscall = r[2];
                    278:                } else if (syscall == 198) {
                    279:                        syscall = r[3];
                    280:                }
                    281:                syscall &= 0xfff;
                    282:        }
1.1.1.5   root      283:        uint32 from = xip | (IsSuper() ? 1 : 0);
                    284:        uint32 inst = 0xfc000000 | (syscall << 12) | vec;
                    285:        exhist.AddEntry(from, 0, inst);
                    286:        brhist.AddEntry(from, 0, inst);
1.1.1.3   root      287:        // デバッガに通知 (例外ブレーク用)
1.1.1.4   root      288:        debugger_notify_exception(vec);
                    289: 
                    290:        // 命令中で起きる例外はとりあえず全部2クロック追加? (Table.7-5)
                    291:        if (cause != ExceptionKind::INTR) {
1.1.1.5   root      292:                AddCycle(2);
1.1.1.4   root      293:        }
1.1.1.3   root      294: 
1.1       root      295:        if (psr & PSR_SFRZ) {
                    296:                if (cause != ExceptionKind::TRAP) {
1.1.1.7   root      297:                        cpulog(2, "SFRZ Error Exception");
1.1       root      298:                        vec = M88K_EXCEP_ERROR;
                    299:                        cause = ExceptionKind::ERROR;
                    300:                }
                    301:        } else {
1.1.1.7   root      302:                cpulog(2, "Exception %x", vec);
1.1.1.2   root      303:                if (vec != 1) {
1.1.1.7   root      304:                        cpulog(1, "Exception %x x=%x n=%x f=%x", vec, xip, nip, fip);
1.1.1.2   root      305:                }
1.1       root      306:                sxip = xip;
                    307:                snip = nip;
1.1.1.7   root      308:                sfip = fip;
1.1       root      309: 
                    310:                sxip |= SIP_V;
                    311:                snip |= SIP_V;
1.1.1.4   root      312:                sfip |= SIP_V;
1.1       root      313: 
                    314:                if (OpIsBusErr(opX)) {
                    315:                        sxip |= SIP_E;  // E bit
                    316:                }
                    317:                if (OpIsBusErr(opF)) {
                    318:                        snip |= SIP_E;  // E bit
                    319:                }
                    320: 
                    321:                if (vec == M88K_EXCEP_UNIMPL_OP) {
                    322:                        sxip &= ~SIP_V;
                    323:                }
                    324:        }
                    325: 
1.1.1.2   root      326:        if (cause != ExceptionKind::DATA) {
                    327:                // データアクセス例外以外は、
                    328:                // データパイプラインはフラッシュ状態とする。
                    329:                // ほんとうは違う。かも。
                    330:                dmt0 = 0;
                    331:        } else {
                    332:                // xip: ld/st/xmem
                    333:                // nip: next
                    334:                // fip: fetch
                    335: 
                    336:                // rom1.2 は DAE が起きると、
                    337: 
                    338:                // ROM挙動               CPU の RTE 挙動
                    339:                // sfip = sxip
                    340:                // sxip -> ~V (INVALID)  CPU はそもそも sxip を評価しない
                    341:                // snip = 0 (INVALID)    CPU はこれを nop 相当に処理する
                    342:                // rte
                    343: 
                    344:                // してくる。そのまま読むと命令を再実行しようとしているように
                    345:                // 読めるが、再実行すると無限ループになってしまう。
                    346:                // DAE の時点で xip が進んでいることを期待して利用している?
                    347: 
                    348:                // openbsd は
                    349:                // xmem の write バスエラーを検知すると命令を再実行するために
                    350:                // fip = nip, nip = xip して rte する。ということは xip = xmem に
                    351:                // なっていることを期待している。
                    352: 
                    353:                // というわけで
                    354:                // ld で DataAccessException のときは、実CPUはすでに次の命令を
                    355:                // 実行している?
                    356:                // もう少し考えると、スコアボードでレジスタの干渉がなければ、
                    357:                // 実行している?
                    358: 
                    359:                // 仕方がないのでハックでごまかす。
                    360:                // rte のほうも参照のこと。
                    361: 
                    362:                if (IsSuper() && xip >= 0x41000000 && xip < 0x42000000) {
                    363:                        // 遅延例外機構がないので、ROM 合わせのハック。
                    364:                        sxip = snip;
                    365:                }
                    366:        }
                    367: 
1.1       root      368:        epsr = psr;
1.1.1.2   root      369:        SetPSR(psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ);
1.1       root      370: 
                    371:        fip = vbr + (vec << 3);
                    372:        fetch();
1.1.1.3   root      373:        // ここでベクタに飛ぶのだが、ベクタ内の2命令でおそらく必ずもう一度
                    374:        // 分岐してそっちでも履歴が残るので、ここでブランチ履歴を残すのは
                    375:        // ちょっと冗長という気もする。
                    376: 
1.1       root      377:        if (OpIsBusErr(opF)) {
                    378:                if (cause == ExceptionKind::ERROR) {
                    379:                        // double bus fault
                    380:                        // 実機は無限ループ状態
                    381:                        PANIC("Infinite ERROR (double bus fault)");
                    382:                } else {
                    383:                        ExceptionCore(M88K_EXCEP_ERROR, ExceptionKind::ERROR);
                    384:                }
                    385:        }
                    386: }
                    387: 
1.1.1.10! root      388: inline uint32
1.1.1.5   root      389: m88kcpu::Calcdmt(uint32 flag)
                    390: {
                    391:        return
                    392:                   ((psr & PSR_BO_LE) ? DM_BO : 0)
                    393:             | ((IsSuper() && !(flag & DM_USR)) ? DM_DAS : 0)
                    394:             | DM_VALID;
                    395: }
                    396: 
1.1       root      397: // データアクセス例外(Read)
1.1.1.5   root      398: // ld.b, ld.h, ld.hu, ld 用
1.1       root      399: void
1.1.1.5   root      400: m88kcpu::ReadDataException32(uint32 addr, uint32 flag)
1.1       root      401: {
                    402:        // ミスアラインドはこの例外より前にチェックされていて、
                    403:        // ここにはアラインドしかこない。
                    404:        dma0 = addr & ~0x3;
1.1.1.5   root      405:        dmt0 = Calcdmt(flag)
1.1       root      406:             | (FLD_D << 7)
                    407:             | (flag & DM_SIGNED)
                    408:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
1.1.1.5   root      409:        ;
                    410:        dmt1 &= ~DM_VALID;
                    411:        dmt2 &= ~DM_VALID;
1.1.1.7   root      412:        cpulog(1, "ReadDAE xip=%x addr=%x", xip, addr);
1.1.1.2   root      413:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1       root      414: }
                    415: 
1.1.1.5   root      416: // データアクセス例外(Read)
                    417: // ld.d 用
                    418: void
                    419: m88kcpu::ReadDataException64(uint32 addr, uint32 flag)
                    420: {
                    421:        // ミスアラインドはこの例外より前にチェックされていて、
                    422:        // ここにはアラインドしかこない。
                    423:        dma0 = addr;
                    424:        dmt0 = Calcdmt(flag)
                    425:             | DM_DOUB1                 // ダブルワードの第1アクセスのときセット
                    426:             | (FLD_D << 7)
                    427:             | DM_EN_MASK               // 32ビット有効
                    428:        ;
                    429: 
                    430:        dma1 = dma0 + 4;
                    431:        dmt1 = Calcdmt(flag)
                    432:             | (FLD_D2 << 7)
                    433:             | DM_EN_MASK                       // 32ビット有効
                    434:        ;
                    435: 
                    436:        dmt2 &= ~DM_VALID;
                    437: 
                    438:        if ((flag & DM_DOUB1) == 0) {
                    439:                // .d の2ワード目がバスエラー。第1ワードのアクセスは成功した。
                    440:                dmt0 &= ~DM_VALID;
                    441:        }
                    442: 
1.1.1.7   root      443:        cpulog(1, "ReadDAE64 xip=%x addr=%x", xip, addr);
1.1.1.5   root      444:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
                    445: }
                    446: 
1.1       root      447: // データアクセス例外(Write)
1.1.1.5   root      448: // st.b, st.h, st.hu, st 用
1.1       root      449: void
1.1.1.5   root      450: m88kcpu::WriteDataException32(uint32 addr, uint32 flag)
1.1       root      451: {
                    452:        // ミスアラインドはこの例外より前にチェックされていて、
                    453:        // ここにはアラインドしかこない。
                    454:        dma0 = addr & ~0x3;
1.1.1.5   root      455:        dmt0 = Calcdmt(flag)
1.1       root      456:             | (FLD_D << 7)
                    457:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
                    458:             | DM_WRITE
1.1.1.5   root      459:        ;
                    460:        dmd0 = rD;
1.1       root      461: 
1.1.1.5   root      462:        dmt1 &= ~DM_VALID;
                    463:        dmt2 &= ~DM_VALID;
1.1.1.7   root      464:        cpulog(1, "WriteDAE xip=%x addr=%x", xip, addr);
1.1.1.2   root      465:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
                    466: }
                    467: 
1.1.1.5   root      468: // データアクセス例外(Write)
                    469: // st.d 用
                    470: void
                    471: m88kcpu::WriteDataException64(uint32 addr, uint32 flag)
                    472: {
                    473:        // ミスアラインドはこの例外より前にチェックされていて、
                    474:        // ここにはアラインドしかこない。
                    475:        dma0 = addr & ~0x3;
                    476:        dmt0 = Calcdmt(flag)
                    477:             | DM_DOUB1         // ダブルワードの第1アクセスのときセット
                    478:             | (FLD_D << 7)
                    479:             | DM_EN_MASK
                    480:             | DM_WRITE
                    481:        ;
                    482:        dmd0 = rD;
                    483: 
                    484:        dma1 = dma0 + 4;
                    485:        dmt1 = Calcdmt(flag)
                    486:             | (FLD_D2 << 7)
                    487:             | DM_EN_MASK
                    488:             | DM_WRITE
                    489:        ;
                    490:        dmd1 = rD2;
                    491: 
                    492:        dmt2 &= ~DM_VALID;
                    493: 
                    494:        if ((flag & DM_DOUB1) == 0) {
                    495:                // .d の2ワード目がバスエラー。第1ワードのアクセスは成功した。
                    496:                dmt0 &= ~DM_VALID;
                    497:        }
                    498: 
1.1.1.7   root      499:        cpulog(1, "WriteDAE64 xip=%x addr=%x", xip, addr);
1.1.1.5   root      500:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
                    501: }
                    502: 
1.1.1.2   root      503: // データアクセス例外(xmem)
1.1.1.5   root      504: // xmem には .d は無い
1.1.1.2   root      505: void
1.1.1.5   root      506: m88kcpu::XmemDataException(uint32 addr, uint32 flag)
1.1.1.2   root      507: {
                    508:        dma0 = addr & ~0x3;
1.1.1.5   root      509:        dmt0 = Calcdmt(flag)
                    510:             | DM_LOCK          // xmem でセット
1.1.1.2   root      511:             | (FLD_D << 7)
                    512:             | (flag & DM_SIGNED)
                    513:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
1.1.1.5   root      514:        ;
1.1.1.2   root      515: 
1.1.1.5   root      516:        dma1 = dma0;
                    517:        dmt1 = Calcdmt(flag)
                    518:             | DM_LOCK          // xmem でセット
1.1.1.2   root      519:             | (FLD_D << 7)
                    520:             | (flag & DM_SIGNED)
                    521:             | ((flag & DM_EN_MASK) >> (addr & 0x03))
                    522:             | DM_WRITE
1.1.1.5   root      523:        ;
                    524:        dmd1 = rD;
1.1.1.2   root      525: 
1.1.1.5   root      526:        dmt2 &= ~DM_VALID;
1.1.1.2   root      527: 
                    528:        // ミスアラインドはこの例外より前にチェックされていて、
                    529:        // ここにはアラインドしかこない。
                    530:        if (cmmu[1].fault_code != m88200::FAULT_CODE_BUSERR
                    531:         || cmmu[1].acc_read) {
                    532:                // アドレス変換フォルトまたは read 時点
                    533:                // nop
1.1       root      534:        } else {
1.1.1.2   root      535:                // xmem の write 時点
1.1.1.5   root      536:                dmt0 &= ~DM_VALID;
1.1       root      537:        }
1.1.1.2   root      538: 
1.1.1.7   root      539:        cpulog(1, "xmemDAE xip=%x addr=%x", xip, addr);
1.1.1.2   root      540:        ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1       root      541: }
                    542: 
1.1.1.10! root      543: // FPxS レジスタをセット
1.1.1.5   root      544: void
1.1.1.10! root      545: m88kcpu::SetFPxS(uint32& h, uint32& l, double src, uint32 ts)
1.1.1.5   root      546: {
1.1.1.10! root      547:        // FPHS[12]、FPLS[12] は以下の構造
        !           548:        //
        !           549:        //    3                   2                   1                   0
        !           550:        //  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
        !           551:        // +-+---------------------+---------------------------------------+
        !           552:        // |S|   Exponent(11bit)   |     High Order 20 bits of Mantissa    | FPHSn
        !           553:        // +-+---------------------+---------------------------------------+
        !           554:        //
        !           555:        // +---------------------------------------------------------------+
        !           556:        // |           Low Order bits of Mantissa, or Integer              | FPLSn
        !           557:        // +---------------------------------------------------------------+
        !           558:        //
        !           559:        // ts が 1 (double) の場合は IEEE754 double と同じ。
        !           560:        // ts が 0 (single) の場合は float を double にキャスト (拡大変換) した
        !           561:        // ものではないことに注意。
        !           562:        // S(符号ビット)はそのまま。float の Mantissa (23bit) のうち上位 20bit
        !           563:        // を FPHSn に、残り 3bit を FPLSn の上位 3bit に。ここまではいい。
        !           564:        // Exponent は float の指数部(8bit、バイアス=127) の値を *そのまま*
        !           565:        // 符号拡張(?)する。
        !           566:        // (float)1.0 は 1.0 * 2^0 なのでバイアス込みの指数部は 127、
        !           567:        // (float)2.0 は 1.0 * 2^1 なのでバイアス込みの指数部は 128。
        !           568:        // バイアス込みにした値は符号なし数のはずだが、ここではこれを 11bit に
        !           569:        // 符号拡張して FPHSn の Exponent 部に格納するようだ。取り出す際に下位
        !           570:        // 8bit しか取り出さなければ害はないし、符号拡張する方がハードウェア的に
        !           571:        // 都合がよかったとかだろうか。
        !           572:        // 仮に普通に double に変換すると double の指数部バイアスは 1023 なので
        !           573:        // バイアス込みの指数部は先程の例だとそれぞれ 1023、1024 になるが
        !           574:        // これではないということ。
        !           575: 
        !           576:        union64 u;
        !           577:        u.q = d2u(src);
        !           578:        if (ts == 0) {
        !           579:                // single
        !           580: 
        !           581:                uint32 exp;
        !           582:                // src は普通の double なのでこの指数部を取り出す
        !           583:                uint32 double_biased = (u.h >> 20) & 0x7ff;
        !           584:                if (double_biased == 0x7ff) {
        !           585:                        // Inf, NAN
        !           586:                        exp = 0x7ff00000;
        !           587:                } else {
        !           588:                        // double のバイアスを外して float のバイアスを足す
        !           589:                        int float_biased = (double_biased - 1023) + 127;
        !           590:                        // この 8bit 値を 11bit に符号拡張して所定の位置へ
        !           591:                        exp = ((int32)(float_biased << 24)) >> 4;
        !           592:                        exp &= 0x7ff00000;
        !           593:                }
        !           594: 
        !           595:                h = (u.h & 0x800fffff) | exp;
        !           596:                l = u.l;
        !           597:        } else {
        !           598:                // double
        !           599:                h = u.h;
        !           600:                l = u.l;
        !           601:        }
        !           602: }
        !           603: 
        !           604: // FPR[HL] レジスタに double 値をセット
        !           605: // - それ以外のフィールドは保存する XXX ここでクリアしてもいいか?
        !           606: // - XXX Guard, Round, Sticky (, AddOne) はまだない
        !           607: void
        !           608: m88kcpu::SetFPRx(double src)
        !           609: {
        !           610:        union64 u;
        !           611:        uint32 exp;
        !           612: 
        !           613:        u.q = d2u(src);
        !           614: 
        !           615:        // Sign は FPRH
        !           616:        fprh &= ~(FPRH_SIGN | FPRH_MANT);       // Mantissa もついでにクリア
        !           617:        fprh |= u.h & 0x80000000;
        !           618: 
        !           619:        // Exp  は FPIT。
        !           620:        // double は 11bit だが FPIT::RESEXP は 12bit なので 1bit 符号拡張する。
        !           621:        // 符号付き数(正確には負数)の右シフトは実装依存だが gcc, clang は
        !           622:        // 算術右シフトになる。
        !           623:        //
        !           624:        //           3                   2
        !           625:        //         1 0 9 8 7 6 5 4 3 2 1 0 9
        !           626:        //        +-+---------------------+-
        !           627:        // double |S|   Exponent(11bit)   |
        !           628:        //        +-+---------------------+-
        !           629:        //
        !           630:        //        +---------------------+-+-
        !           631:        // u.h<<1 |  Exponent(11bit)    |X|
        !           632:        //        +---------------------+-+-
        !           633:        //
        !           634:        //        +-----------------------+-
        !           635:        // exp>>1 |   Exponent(12bit)     |
        !           636:        //        +-----------------------+-
        !           637:        exp = u.h << 1;
        !           638:        exp = (int32)exp >> 1;
        !           639:        fpit &= ~FPIT_RESEXP;
        !           640:        fpit |= exp & FPIT_RESEXP;
        !           641: 
        !           642:        // Mantissa は FPRH, FPRL
        !           643:        // 上位側(FPRH)には最上位(実数桁)の隠しビットを含む。
        !           644:        fprh |= (u.h & 0x000fffff);
        !           645:        fprh |= FPRH_1;
        !           646:        fprl = u.l;
        !           647: }
        !           648: 
        !           649: // FP Precise 例外。浮動小数点数1つの場合。
        !           650: void
        !           651: m88kcpu::FPPreciseException(uint32 cause, double s2)
        !           652: {
        !           653:        SetFPS2(s2, m88100opf_FP_T2(opX));
        !           654:        FPPreciseException(cause);
        !           655: }
        !           656: 
        !           657: // FP Precise 例外。浮動小数点数2つの場合。
        !           658: void
        !           659: m88kcpu::FPPreciseException(uint32 cause, double s1, double s2)
        !           660: {
        !           661:        SetFPS1(s1, m88100opf_FP_T1(opX));
        !           662:        SetFPS2(s2, m88100opf_FP_T2(opX));
        !           663:        FPPreciseException(cause);
        !           664: }
        !           665: 
        !           666: // FP Precise 例外。
        !           667: void
        !           668: m88kcpu::FPPreciseException(uint32 cause)
        !           669: {
        !           670:        assert(cause == FPECR_FIOV   ||
        !           671:               cause == FPECR_FUNIMP ||
        !           672:               cause == FPECR_FPRV   ||
        !           673:               cause == FPECR_FROP   ||
        !           674:               cause == FPECR_FDVZ);
        !           675: 
        !           676:        fpecr = cause;
        !           677: 
        !           678:        // FPPT(FP Precise operation Type Register)
        !           679:        fppt = opX & 0xffe0;            // Opcode, T1, T2, TD は opX と同じ位置
        !           680:        fppt |= m88100opf_D(opX);       // DEST
        !           681: 
        !           682:        Exception(M88K_EXCEP_SFU1_PRECISE);
        !           683: }
        !           684: 
        !           685: // FP Imprecise 例外。
        !           686: void
        !           687: m88kcpu::FPImpreciseException(uint32 cause)
        !           688: {
        !           689:        assert(cause == FPECR_FUNF ||
        !           690:               cause == FPECR_FOVF ||
        !           691:               cause == FPECR_FINX);
        !           692: 
        !           693:        fpecr = cause;
        !           694: 
        !           695:        // FPIT(FP Imprecise operation Type Register)
        !           696:        fpit &= FPIT_RESEXP;
        !           697:        fpit |= opX & FPIT_OPCODE;
        !           698:        fpit |= (opX & 0x00000020) << 5;        // DESTSIZ
        !           699:        fpit |= (fpcr & 0x0000001f) << 5;       // EFINV,EFDVZ,EFUNF,EFOVR,EFINX
        !           700:        fpit |= m88100opf_D(opX);                       // DEST
        !           701: 
        !           702:        // FPRH(FP Result High Register)
        !           703:        fprh &= ~FPRH_RNDMODE;
        !           704:        fprh |= (fpcr & FPCR_RM) << 14;
1.1.1.5   root      705: 
1.1.1.10! root      706:        Exception(M88K_EXCEP_SFU1_IMPRECISE);
1.1.1.5   root      707: }
                    708: 
1.1       root      709: void
1.1.1.5   root      710: m88kcpu::Interrupt(int level)
1.1       root      711: {
1.1.1.5   root      712:        // level は 0 か 1。
                    713:        intr_pending = level;
1.1       root      714:        atomic_reqflag |= CPU_REQ_INTR;
                    715: }
                    716: 
                    717: void
                    718: m88kcpu::fpu_unimpl()
                    719: {
                    720:        printf("%s\n", __func__);
1.1.1.10! root      721:        FPPreciseException(FPECR_FUNIMP);
1.1       root      722: }
1.1.1.2   root      723: 
                    724: OP_DEF(illegal)
                    725: {
                    726:        // 本来は不当命令例外?
1.1.1.7   root      727:        cpulog(0, "Illegal instruction %08x", (uint32)opX);
1.1.1.2   root      728: }

unix.superglobalmegacorp.com

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