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

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: 
1.1.1.17! root        7: // 例外処理について。
        !             8: // 例外のうち、リセット(優先度1)、命令アクセス(2)、未実装命令(3)、特権違反(4)
        !             9: // とその他の命令内部発生例外(5、トラップやゼロ除算など) は、この命令に
        !            10: // 直接起因しているため precise 例外に分類される。
        !            11: // 一方、割り込み(優先度6)、FPU imprecise(7)、データアクセス(8) は imprecise
        !            12: // 例外に分類される。
        !            13: //
        !            14: // データアクセス例外について。
        !            15: // Figure 6-3 参照。例外 (例えば割り込み例外) 起動時にデータユニットが稼働中
        !            16: // ならデータアクセスの完了を待つ。データアクセスが失敗(fault)すればその状態
        !            17: // でシャドウレジスタをフリーズするので、割り込みの受け付けとデータアクセス
        !            18: // 例外が同じ命令内で起きると、その命令直後の境界での例外はベクタは割り込み
        !            19: // 例外 (1番)だが DMTx が VALID という混合状態になる。
        !            20: // 実際 OpenBSD のカーネルはこの状態を認識してわざわざ処理している。
        !            21: //
        !            22: // 実機は、上記の内部例外を起こす整数ユニットとデータユニットが並行して
        !            23: // 動けるため、割り込み以外の例外でもデータアクセス例外が同時に起きるかも
        !            24: // 知れないが、ここでは考えない。
        !            25: // また割り込みと FPU imprecise も同時に起きる可能性はあるが未調査。
        !            26: // FPU imprecise とデータアクセスについても未調査。
        !            27: 
1.1       root       28: #include "m88100.h"
                     29: #include "debugger.h"
1.1.1.17! root       30: #include "event.h"
1.1.1.11  root       31: #include "mpu88xx0.h"
1.1.1.13  root       32: #include "scheduler.h"
1.1       root       33: 
1.1.1.13  root       34: #define OP_DEF(name)   void __CONCAT(MPU88xx0Device::op_,name)()
1.1       root       35: #define OP_FUNC(name)  __CONCAT(op_,name)()
                     36: #include "m88100ops.cpp"
                     37: 
1.1.1.12  root       38: // プリフェッチステージ(?)。
                     39: // 命令サイクルは、自然に書けば、
                     40: // (1) パイプラインをシフトし、FIP の指すところをフェッチ。
                     41: // (2) デバッガはここに入れたい。
                     42: // (3) XIP(opX) を解釈、実行。
                     43: // の繰り返しになるが、デバッガは Exec() から戻ったところでスケジューラから
                     44: // 呼び出される構造のため、順序をずらして 1回の Exec() では (3)->(1) を実行
                     45: // してからスケジューラに戻って (2) を実行する、の順にする。
                     46: // そのため、リセット例外では1回プリフェッチを実行しておく必要がある。
1.1.1.13  root       47: void
                     48: MPU88xx0Device::Prefetch()
1.1.1.12  root       49: {
                     50:        // shift pipeline
1.1.1.13  root       51:        reg.opX = reg.opF;
                     52:        reg.xip = reg.nip;
1.1.1.12  root       53: 
                     54:        // prefetch next inst
                     55:        fetch();
                     56: }
                     57: 
1.1.1.13  root       58: // 1命令実行のコールバック。
                     59: void
1.1.1.17! root       60: MPU88xx0Device::ExecNormal(Event *ev)
1.1       root       61: {
1.1.1.11  root       62:        uint64 cycle_start = used_cycle;
1.1.1.12  root       63:        uint32 op12;
1.1.1.5   root       64: 
1.1.1.14  root       65:        buswait = 0;
                     66: 
1.1.1.12  root       67:        // この時点で実行しようとする命令が opX に入っている
1.1       root       68: 
1.1.1.17! root       69:        if (__predict_false(OpIsBusErr(reg.opX))) {
1.1.1.12  root       70:                // プリフェッチしていた命令がバスエラー
1.1.1.17! root       71:                Exception(EXCPRI_INST);
        !            72:        } else {
        !            73:                op12 = op32_to_12(reg.opX);
        !            74:                switch (op12) {
1.1       root       75: #include "m88100switch.inc"
1.1.1.17! root       76:                 default:
        !            77:                        OP_FUNC(illegal);
        !            78:                        break;
        !            79:                }
1.1.1.12  root       80:        }
1.1.1.2   root       81: 
1.1.1.17! root       82:        // 例外発生か。
        !            83:        if (__predict_false(excep_pending != 0)) {
        !            84:                if (__predict_false(resetting)) {
1.1.1.15  root       85:                        // 命令実行の先でリセットが起きたら以降を全部キャンセルして帰る。
1.1.1.17! root       86:                        // システムコントローラのリセットポートアクセスで起きる。
1.1.1.15  root       87:                        return;
                     88:                }
1.1.1.17! root       89: 
        !            90:                // 内部(precise)例外のうち優先度の最も高いのを一つ実行。
        !            91:                // x & (-x) で立ってる最下位ビットだけにする。
        !            92:                uint32 pri = excep_pending & (-excep_pending);
        !            93: 
        !            94:                excep_pending &= ~pri;
        !            95:                ExceptionCore(pri);
1.1       root       96:        }
                     97: 
1.1.1.12  root       98:        used_cycle++;
                     99: 
                    100:        Prefetch();
                    101: 
1.1.1.13  root      102:        int cycle = used_cycle - cycle_start;
1.1.1.17! root      103:        ev->time = cycle * clock_nsec + buswait;
1.1.1.13  root      104:        scheduler->StartEvent(ev);
1.1.1.5   root      105: }
                    106: 
1.1.1.17! root      107: // 例外処理。ExecNormal() の下請け。
        !           108: // 例外を発生させるのはこれではなく、この下にある *Exception() のほう。
1.1       root      109: void
1.1.1.17! root      110: MPU88xx0Device::ExceptionCore(uint32 pri)
1.1       root      111: {
1.1.1.17! root      112:        uint32 vec;
1.1.1.4   root      113:        uint syscall = 0;
                    114: 
1.1.1.17! root      115:        // 例外種別(優先度)からベクタ番号に変換。
        !           116:        uint primask = pri;
        !           117:        switch (pri) {
        !           118:         case EXCPRI_ERROR:
        !           119:                vec = EXCVEC_ERROR;
        !           120:                break;
        !           121:         case EXCPRI_INST:
        !           122:                vec = EXCVEC_INST;
        !           123:                break;
        !           124:         case EXCPRI_UNIMPL_OP:
        !           125:                vec = EXCVEC_UNIMPL_OP;
        !           126:                break;
        !           127:         case EXCPRI_PRIV:
        !           128:                vec = EXCVEC_PRIV;
        !           129:                break;
        !           130:         case EXCPRI_INTERNAL:
        !           131:         case EXCPRI_TRAP:
        !           132:                // ベクタは別に指定されている。
        !           133:                vec = excep_vector;
        !           134:                excep_vector = 0;
        !           135:                break;
        !           136: 
        !           137:         case EXCPRI_OUTER:
        !           138:                // 割り込みとデータアクセス例外は同時に処理する。
        !           139:                // OUTER は、割り込み、データアクセス、FPU imprecise の少なくとも
        !           140:                // どれかが立っているという代表値なので、ここで欲しいのは
        !           141:                // excep_pending の残っているビット (複数かも知れない) のほう。
        !           142:                // FPU imprecise は未調査。
        !           143:                primask = excep_pending;
        !           144:                excep_pending = 0;
        !           145: 
        !           146:                pri = primask & (-primask);
        !           147:                switch (pri) {
        !           148:                 case EXCPRI_INTERRUPT:
        !           149:                        vec = EXCVEC_INTERRUPT;
        !           150:                        break;
        !           151:                 case EXCPRI_SFU_IMPRECISE:
        !           152:                        vec = EXCVEC_SFU1_IMPRECISE;
        !           153:                        break;
        !           154:                 case EXCPRI_DATA:
        !           155:                        vec = EXCVEC_DATA;
        !           156:                        break;
        !           157:                 default:
        !           158:                        assert(false);
        !           159:                        break;
        !           160:                }
        !           161:                break;
        !           162: 
        !           163:         default:
        !           164:         case EXCPRI_RESET:     // 先に弾いてるので来ない。
        !           165:                assert(false);
        !           166:                break;
        !           167:        }
        !           168: 
1.1.1.13  root      169:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)。
                    170:        // ベクタ 450 なら OpenBSD システムコール番号もついでに記録。
1.1.1.4   root      171:        // システムコール番号は tb0 発行時点で r13 にセットされている。
                    172:        // ただし 0 番は syscall(2) (間接システムコール) で、実際の番号は r2。
                    173:        // 198番 __syscall(2) だと r2:r3 (なので実質 r3)。
1.1.1.13  root      174:        // 非公式 NetBSD/luna88k はベクタ 128 を使っているようだ。
1.1.1.15  root      175:        excep_counter[vec]++;
1.1.1.17! root      176:        if (vec == 450 || vec == 128) {
1.1.1.13  root      177:                syscall = reg.r[13];
1.1.1.4   root      178:                if (syscall == 0) {
1.1.1.13  root      179:                        syscall = reg.r[2];
1.1.1.4   root      180:                } else if (syscall == 198) {
1.1.1.13  root      181:                        syscall = reg.r[3];
1.1.1.4   root      182:                }
                    183:                syscall &= 0xfff;
                    184:        }
1.1.1.13  root      185:        uint32 from = reg.xip | (IsSuper() ? 1 : 0);
1.1.1.16  root      186:        uint32 info = 0xfc000000 | (syscall << 12) | vec;
                    187:        exhist.AddEntry(from, 0, info);
                    188:        brhist.AddEntry(from, 0, info);
1.1.1.3   root      189:        // デバッガに通知 (例外ブレーク用)
1.1.1.13  root      190:        debugger->NotifyExceptionMain(vec);
1.1.1.4   root      191: 
1.1.1.13  root      192:        if ((reg.psr & PSR_SFRZ)) {
1.1.1.17! root      193:                if (pri != EXCPRI_TRAP) {
        !           194:                        putlog(0, "Exception (primask=$%x) during SFRZ!", primask);
        !           195: 
        !           196:                        // エラー例外でもう一度報告。
        !           197:                        // BranchHistory に繰り返しと判定されないよう to を変えておく。
        !           198:                        pri = EXCPRI_ERROR;
        !           199:                        vec = EXCVEC_ERROR;
        !           200:                        info = 0xfc000000 | vec;
        !           201:                        exhist.AddEntry(from, 1, info);
        !           202:                        brhist.AddEntry(from, 1, info);
        !           203:                        debugger->NotifyExceptionMain(vec);
        !           204:                } else {
        !           205:                        putlog(0, "Trap during Exception");
1.1       root      206:                }
                    207:        } else {
1.1.1.17! root      208:                if (vec == EXCVEC_INTERRUPT) {
        !           209:                        putlog(2, "Exception (Interrupt)");
        !           210:                } else {
1.1.1.13  root      211:                        putlog(1, "Exception %x x=%x n=%x f=%x",
                    212:                                vec, reg.xip, reg.nip, reg.fip);
1.1.1.2   root      213:                }
1.1.1.13  root      214:                reg.sxip = reg.xip;
                    215:                reg.snip = reg.nip;
                    216:                reg.sfip = reg.fip;
                    217: 
1.1.1.17! root      218:                if (pri != EXCPRI_UNIMPL_OP) {
        !           219:                        reg.sxip |= SIP_V;
        !           220:                }
1.1.1.13  root      221:                reg.snip |= SIP_V;
                    222:                reg.sfip |= SIP_V;
1.1       root      223: 
1.1.1.13  root      224:                if (OpIsBusErr(reg.opX)) {
1.1.1.17! root      225:                        reg.sxip |= SIP_E;
1.1       root      226:                }
1.1.1.13  root      227:                if (OpIsBusErr(reg.opF)) {
1.1.1.17! root      228:                        reg.snip |= SIP_E;
1.1       root      229:                }
                    230:        }
                    231: 
1.1.1.17! root      232:        if ((primask & EXCPRI_DATA)) {
        !           233:                // パイプラインが未実装なので、PROM の DAE ハンドラが無限ループに
        !           234:                // なるのをごまかすハックは vm/prom.cpp 参照。
1.1.1.2   root      235:        } else {
1.1.1.17! root      236:                // データアクセス例外でなければ DMT の V ビットはクリア。(Table.6-3)
        !           237:                reg.dmt0 &= ~DM_VALID;
        !           238:                reg.dmt1 &= ~DM_VALID;
        !           239:                reg.dmt2 &= ~DM_VALID;
1.1.1.2   root      240:        }
                    241: 
1.1.1.17! root      242:        // XXX Figure 6-3 のフローだとトラップ例外の時は EPSR を保存しない
        !           243:        // ようだが本当だろうか。本文はトラップ例外の記載が少ない。
1.1.1.13  root      244:        reg.epsr = reg.psr;
                    245:        SetPSR(reg.psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ);
1.1       root      246: 
1.1.1.13  root      247:        reg.fip = reg.vbr + (vec << 3);
1.1       root      248:        fetch();
1.1.1.3   root      249:        // ここでベクタに飛ぶのだが、ベクタ内の2命令でおそらく必ずもう一度
                    250:        // 分岐してそっちでも履歴が残るので、ここでブランチ履歴を残すのは
                    251:        // ちょっと冗長という気もする。
                    252: 
1.1.1.13  root      253:        if (OpIsBusErr(reg.opF)) {
1.1.1.17! root      254:                if (pri == EXCPRI_ERROR) {
1.1       root      255:                        // double bus fault
                    256:                        // 実機は無限ループ状態
                    257:                        PANIC("Infinite ERROR (double bus fault)");
                    258:                } else {
1.1.1.17! root      259:                        putlog(0, "Bus error on fetching $%08x (vector $%x)!",
        !           260:                                reg.vbr + (vec << 3), vec);
        !           261:                        Exception(EXCPRI_ERROR);
1.1       root      262:                }
                    263:        }
                    264: }
                    265: 
1.1.1.17! root      266: // EXCPRI_* の内部例外発生を予約する。
        !           267: // 例外はこの場で処理するのではなく、命令境界で優先度の高い方から処理される
        !           268: // ので、発生時に出来るのは予約することだけ。
        !           269: void
        !           270: MPU88xx0Device::Exception(uint32 pri)
        !           271: {
        !           272:        excep_pending |= pri;
        !           273: }
        !           274: 
        !           275: // 外部優先度の例外の発生を予約する。
        !           276: void
        !           277: MPU88xx0Device::OuterException(uint32 pri)
        !           278: {
        !           279:        excep_pending |= pri;
        !           280:        excep_pending |= EXCPRI_OUTER;
        !           281: }
        !           282: 
        !           283: // 内部例外の発生を予約する。
        !           284: // vec は発生させる例外のベクタ番号。
        !           285: void
        !           286: MPU88xx0Device::InternalException(uint32 vec)
        !           287: {
        !           288:        excep_vector = vec;
        !           289:        Exception(EXCPRI_INTERNAL);
        !           290: }
        !           291: 
        !           292: // トラップ例外の発生を予約する。
        !           293: // vec は発生させる例外のベクタ番号。
        !           294: void
        !           295: MPU88xx0Device::TrapException(uint32 vec)
        !           296: {
        !           297:        excep_vector = vec;
        !           298:        Exception(EXCPRI_TRAP);
        !           299: }
        !           300: 
        !           301: // flag から DMT の共通部分を作って返す。
        !           302: uint32
        !           303: MPU88xx0Device::MakeDMT(uint32 flag)
1.1.1.5   root      304: {
1.1.1.13  root      305:        uint32 dmt;
                    306: 
                    307:        dmt = DM_VALID;
                    308:        if ((reg.psr & PSR_BO_LE))
                    309:                dmt |= DM_BO;
                    310:        if (IsSuper() && !(flag & DM_USR))
                    311:                dmt |= DM_DAS;
                    312: 
                    313:        return dmt;
1.1.1.5   root      314: }
                    315: 
1.1.1.17! root      316: // データアクセス例外(Read)、ld.[b,h,(w)] 用。
1.1       root      317: void
1.1.1.13  root      318: MPU88xx0Device::ReadDataException32(uint32 addr, uint32 flag)
1.1       root      319: {
                    320:        // ミスアラインドはこの例外より前にチェックされていて、
1.1.1.17! root      321:        // ここには (アクセスサイズでの) アラインドしかこない。
        !           322: 
        !           323:        reg.dmt0  = MakeDMT(flag);
1.1.1.13  root      324:        reg.dmt0 |= FLD_D << 7;
                    325:        reg.dmt0 |= flag & DM_SIGNED;
                    326:        reg.dmt0 |= (flag & DM_EN_MASK) >> (addr & 0x03);
1.1.1.17! root      327:        reg.dma0 = addr & ~0x3;
1.1.1.13  root      328: 
                    329:        reg.dmt1 &= ~DM_VALID;
                    330:        reg.dmt2 &= ~DM_VALID;
1.1.1.17! root      331: 
1.1.1.13  root      332:        putlog(1, "ReadDAE xip=%x addr=%x", reg.xip, addr);
1.1.1.17! root      333:        OuterException(EXCPRI_DATA);
1.1       root      334: }
                    335: 
1.1.1.17! root      336: // データアクセス例外(Read)、ld.d 用。
        !           337: // どちらのワードで例外が起きても first_addr は第1ワードのアドレス。
1.1.1.5   root      338: void
1.1.1.17! root      339: MPU88xx0Device::ReadDataException64(uint32 first_addr, uint32 flag)
1.1.1.5   root      340: {
                    341:        // ミスアラインドはこの例外より前にチェックされていて、
                    342:        // ここにはアラインドしかこない。
1.1.1.13  root      343: 
1.1.1.17! root      344:        uint32 dmt_2nd;
        !           345:        uint32 dma_2nd;
1.1.1.5   root      346: 
1.1.1.17! root      347:        reg.dmt1 &= ~DM_VALID;
1.1.1.13  root      348:        reg.dmt2 &= ~DM_VALID;
1.1.1.5   root      349: 
1.1.1.17! root      350:        // 先に2ワード目の情報を作っておく。
        !           351:        dmt_2nd  = MakeDMT(flag);
        !           352:        dmt_2nd |= FLD_D2 << 7;
        !           353:        dmt_2nd |= DM_EN_MASK;          // 32ビット有効
        !           354:        dma_2nd = first_addr + 4;
        !           355: 
        !           356:        uint32 doub1 = (flag & DM_DOUB1);
        !           357:        if (doub1) {
        !           358:                // 1ワード目がバスエラーなら、DMx0 と DMx1 を使う。
        !           359:                reg.dmt0  = MakeDMT(flag);
        !           360:                reg.dmt0 |= doub1;
        !           361:                reg.dmt0 |= FLD_D << 7;
        !           362:                reg.dmt0 |= DM_EN_MASK;         // 32ビット有効
        !           363:                reg.dma0 = first_addr;
        !           364: 
        !           365:                reg.dmt1 = dmt_2nd;
        !           366:                reg.dma1 = dma_2nd;
        !           367:        } else {
        !           368:                // 2ワード目がバスエラーなら、DMx0 に2ワード目の情報だけ。
        !           369:                reg.dmt0 = dmt_2nd;
        !           370:                reg.dma0 = dma_2nd;
1.1.1.5   root      371:        }
                    372: 
1.1.1.17! root      373:        putlog(1, "ReadDAE64 xip=%x addr=%x", reg.xip, reg.dma0);
        !           374:        OuterException(EXCPRI_DATA);
1.1.1.5   root      375: }
                    376: 
1.1.1.17! root      377: // データアクセス例外(Write)、st.[b,h,(w)] 用。
1.1       root      378: void
1.1.1.13  root      379: MPU88xx0Device::WriteDataException32(uint32 addr, uint32 flag)
1.1       root      380: {
                    381:        // ミスアラインドはこの例外より前にチェックされていて、
1.1.1.17! root      382:        // ここには (アクセスサイズでの) アラインドしかこない。
        !           383: 
        !           384:        reg.dmt0  = MakeDMT(flag);
1.1.1.13  root      385:        reg.dmt0 |= (flag & DM_EN_MASK) >> (addr & 0x03);
                    386:        reg.dmt0 |= DM_WRITE;
1.1.1.17! root      387:        reg.dma0 = addr & ~0x3;
1.1.1.13  root      388:        reg.dmd0 = rD;
                    389: 
                    390:        reg.dmt1 &= ~DM_VALID;
                    391:        reg.dmt2 &= ~DM_VALID;
1.1.1.17! root      392: 
1.1.1.13  root      393:        putlog(1, "WriteDAE xip=%x addr=%x", reg.xip, addr);
1.1.1.17! root      394:        OuterException(EXCPRI_DATA);
1.1.1.2   root      395: }
                    396: 
1.1.1.17! root      397: // データアクセス例外(Write)、st.d 用。
        !           398: // どちらのワードで例外が起きても first_addr は第1ワードのアドレス。
1.1.1.5   root      399: void
1.1.1.17! root      400: MPU88xx0Device::WriteDataException64(uint32 first_addr, uint32 flag)
1.1.1.5   root      401: {
                    402:        // ミスアラインドはこの例外より前にチェックされていて、
                    403:        // ここにはアラインドしかこない。
1.1.1.13  root      404: 
1.1.1.17! root      405:        uint32 dmt_2nd;
        !           406:        uint32 dma_2nd;
        !           407:        uint32 dmd_2nd;
1.1.1.5   root      408: 
1.1.1.17! root      409:        reg.dmt1 &= ~DM_VALID;
1.1.1.13  root      410:        reg.dmt2 &= ~DM_VALID;
1.1.1.5   root      411: 
1.1.1.17! root      412:        // 先に2ワード目の情報を作っておく。
        !           413:        dmt_2nd  = MakeDMT(flag);
        !           414:        dmt_2nd |= DM_EN_MASK;
        !           415:        dmt_2nd |= DM_WRITE;
        !           416:        dma_2nd = first_addr + 4;
        !           417:        dmd_2nd = rD2;
        !           418: 
        !           419:        uint32 doub1 = (flag & DM_DOUB1);
        !           420:        if (doub1) {
        !           421:                // 1ワード目がバスエラーなら、DMx0 と DMx1 を使う。
        !           422:                reg.dmt0  = MakeDMT(flag);
        !           423:                reg.dmt0 |= DM_DOUB1;           // ダブルワードの第1アクセスのときセット
        !           424:                reg.dmt0 |= DM_EN_MASK;
        !           425:                reg.dmt0 |= DM_WRITE;
        !           426:                reg.dma0 = first_addr;
        !           427:                reg.dmd0 = rD;
        !           428: 
        !           429:                reg.dmt1 = dmt_2nd;
        !           430:                reg.dma1 = dma_2nd;
        !           431:                reg.dmd1 = dmd_2nd;
        !           432:        } else {
        !           433:                // 2ワード目がバスエラーなら、DMx0 に2ワード目の情報だけ。
        !           434:                reg.dmt0 = dmt_2nd;
        !           435:                reg.dma0 = dma_2nd;
        !           436:                reg.dmd0 = dmd_2nd;
1.1.1.5   root      437:        }
                    438: 
1.1.1.17! root      439:        putlog(1, "WriteDAE64 xip=%x addr=%x", reg.xip, reg.dma0);
        !           440:        OuterException(EXCPRI_DATA);
1.1.1.5   root      441: }
                    442: 
1.1.1.2   root      443: // データアクセス例外(xmem)
1.1.1.17! root      444: // xmem は .bu と (.w) しかない。
1.1.1.2   root      445: void
1.1.1.13  root      446: MPU88xx0Device::XmemDataException(uint32 addr, uint32 flag)
1.1.1.2   root      447: {
1.1.1.17! root      448:        // ミスアラインドはこの例外より前にチェックされていて、
        !           449:        // ここには (アクセスサイズでの) アラインドしかこない。
1.1.1.13  root      450: 
1.1.1.17! root      451:        uint32 dmt_rd;
        !           452:        uint32 dmt_wr;
        !           453:        uint32 dma;
        !           454:        uint32 dmd_wr;
1.1.1.2   root      455: 
1.1.1.17! root      456:        reg.dmt1 &= ~DM_VALID;
1.1.1.13  root      457:        reg.dmt2 &= ~DM_VALID;
1.1.1.2   root      458: 
1.1.1.17! root      459:        dmt_rd  = MakeDMT(flag);
        !           460:        dmt_rd |= DM_LOCK;
        !           461:        dmt_rd |= FLD_D << 7;
        !           462:        dmt_rd |= flag & DM_SIGNED;
        !           463:        dmt_rd |= (flag & DM_EN_MASK) >> (addr & 0x03);
        !           464:        dma = addr & ~0x3U;
        !           465: 
        !           466:        dmt_wr = dmt_rd | DM_WRITE;
        !           467:        dmd_wr = rD;
        !           468: 
1.1.1.13  root      469:        if (cmmu[1]->fault_code != m88200::FAULT_CODE_BUSERR
                    470:         || cmmu[1]->acc_read) {
1.1.1.17! root      471:                // アドレス変換フォルトまたは read 時点のバスエラー。
        !           472:                reg.dmt0 = dmt_rd;
        !           473:                reg.dma0 = dma;
        !           474: 
        !           475:                reg.dmt1 = dmt_wr;
        !           476:                reg.dma1 = dma;
        !           477:                reg.dmd1 = dmd_wr;
1.1       root      478:        } else {
1.1.1.17! root      479:                // xmem の write 時点のバスエラー。
        !           480:                reg.dmt0 = dmt_wr;
        !           481:                reg.dma0 = dma;
        !           482:                reg.dmd0 = dmd_wr;
1.1       root      483:        }
1.1.1.2   root      484: 
1.1.1.13  root      485:        putlog(1, "xmemDAE xip=%x addr=%x", reg.xip, addr);
1.1.1.17! root      486:        OuterException(EXCPRI_DATA);
1.1       root      487: }
                    488: 
1.1.1.10  root      489: // FPxS レジスタをセット
1.1.1.13  root      490: /*static*/ void
1.1.1.15  root      491: MPU88xx0Device::SetFPxS(uint32 *h, uint32 *l, double src, uint32 ts)
1.1.1.5   root      492: {
1.1.1.10  root      493:        // FPHS[12]、FPLS[12] は以下の構造
                    494:        //
                    495:        //    3                   2                   1                   0
                    496:        //  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
                    497:        // +-+---------------------+---------------------------------------+
                    498:        // |S|   Exponent(11bit)   |     High Order 20 bits of Mantissa    | FPHSn
                    499:        // +-+---------------------+---------------------------------------+
                    500:        //
                    501:        // +---------------------------------------------------------------+
                    502:        // |           Low Order bits of Mantissa, or Integer              | FPLSn
                    503:        // +---------------------------------------------------------------+
                    504:        //
                    505:        // ts が 1 (double) の場合は IEEE754 double と同じ。
                    506:        // ts が 0 (single) の場合は float を double にキャスト (拡大変換) した
                    507:        // ものではないことに注意。
                    508:        // S(符号ビット)はそのまま。float の Mantissa (23bit) のうち上位 20bit
                    509:        // を FPHSn に、残り 3bit を FPLSn の上位 3bit に。ここまではいい。
                    510:        // Exponent は float の指数部(8bit、バイアス=127) の値を *そのまま*
                    511:        // 符号拡張(?)する。
                    512:        // (float)1.0 は 1.0 * 2^0 なのでバイアス込みの指数部は 127、
                    513:        // (float)2.0 は 1.0 * 2^1 なのでバイアス込みの指数部は 128。
                    514:        // バイアス込みにした値は符号なし数のはずだが、ここではこれを 11bit に
                    515:        // 符号拡張して FPHSn の Exponent 部に格納するようだ。取り出す際に下位
                    516:        // 8bit しか取り出さなければ害はないし、符号拡張する方がハードウェア的に
                    517:        // 都合がよかったとかだろうか。
                    518:        // 仮に普通に double に変換すると double の指数部バイアスは 1023 なので
                    519:        // バイアス込みの指数部は先程の例だとそれぞれ 1023、1024 になるが
                    520:        // これではないということ。
                    521: 
                    522:        union64 u;
                    523:        u.q = d2u(src);
                    524:        if (ts == 0) {
                    525:                // single
                    526: 
                    527:                uint32 exp;
                    528:                // src は普通の double なのでこの指数部を取り出す
                    529:                uint32 double_biased = (u.h >> 20) & 0x7ff;
1.1.1.17! root      530:                if (double_biased == 0) {
        !           531:                        // Zero
        !           532:                        exp = 0;
        !           533:                } else if (double_biased == 0x7ff) {
1.1.1.10  root      534:                        // Inf, NAN
                    535:                        exp = 0x7ff00000;
                    536:                } else {
                    537:                        // double のバイアスを外して float のバイアスを足す
                    538:                        int float_biased = (double_biased - 1023) + 127;
                    539:                        // この 8bit 値を 11bit に符号拡張して所定の位置へ
                    540:                        exp = ((int32)(float_biased << 24)) >> 4;
1.1.1.17! root      541:                        exp &= ~0x80000000;
1.1.1.10  root      542:                }
                    543: 
1.1.1.15  root      544:                *h = (u.h & 0x800fffff) | exp;
                    545:                *l = u.l;
1.1.1.10  root      546:        } else {
                    547:                // double
1.1.1.15  root      548:                *h = u.h;
                    549:                *l = u.l;
1.1.1.10  root      550:        }
                    551: }
                    552: 
1.1.1.13  root      553: // FPxS1 レジスタをセット
                    554: void
                    555: MPU88xx0Device::SetFPS1(double src, uint32 t1)
                    556: {
1.1.1.15  root      557:        SetFPxS(&reg.fphs1, &reg.fpls1, src, t1);
1.1.1.13  root      558: }
                    559: 
                    560: // FPxS2 レジスタをセット
                    561: void
                    562: MPU88xx0Device::SetFPS2(double src, uint32 t2)
                    563: {
1.1.1.15  root      564:        SetFPxS(&reg.fphs2, &reg.fpls2, src, t2);
1.1.1.13  root      565: }
                    566: 
                    567: void
                    568: MPU88xx0Device::SetFPS1(uint32 src)
                    569: {
                    570:        reg.fpls1 = src;
                    571: }
                    572: 
                    573: void
                    574: MPU88xx0Device::SetFPS2(uint32 src)
                    575: {
                    576:        reg.fpls2 = src;
                    577: }
                    578: 
1.1.1.10  root      579: // FPR[HL] レジスタに double 値をセット
                    580: // - それ以外のフィールドは保存する XXX ここでクリアしてもいいか?
                    581: // - XXX Guard, Round, Sticky (, AddOne) はまだない
                    582: void
1.1.1.13  root      583: MPU88xx0Device::SetFPRx(double src)
1.1.1.10  root      584: {
                    585:        union64 u;
                    586:        uint32 exp;
                    587: 
                    588:        u.q = d2u(src);
                    589: 
                    590:        // Sign は FPRH
1.1.1.13  root      591:        reg.fprh &= ~(FPRH_SIGN | FPRH_MANT);   // Mantissa もついでにクリア
                    592:        reg.fprh |= u.h & 0x80000000;
1.1.1.10  root      593: 
                    594:        // Exp  は FPIT。
                    595:        // double は 11bit だが FPIT::RESEXP は 12bit なので 1bit 符号拡張する。
                    596:        // 符号付き数(正確には負数)の右シフトは実装依存だが gcc, clang は
                    597:        // 算術右シフトになる。
                    598:        //
                    599:        //           3                   2
                    600:        //         1 0 9 8 7 6 5 4 3 2 1 0 9
                    601:        //        +-+---------------------+-
                    602:        // double |S|   Exponent(11bit)   |
                    603:        //        +-+---------------------+-
                    604:        //
                    605:        //        +---------------------+-+-
                    606:        // u.h<<1 |  Exponent(11bit)    |X|
                    607:        //        +---------------------+-+-
                    608:        //
                    609:        //        +-----------------------+-
                    610:        // exp>>1 |   Exponent(12bit)     |
                    611:        //        +-----------------------+-
                    612:        exp = u.h << 1;
                    613:        exp = (int32)exp >> 1;
1.1.1.13  root      614:        reg.fpit &= ~FPIT_RESEXP;
                    615:        reg.fpit |= exp & FPIT_RESEXP;
1.1.1.10  root      616: 
                    617:        // Mantissa は FPRH, FPRL
                    618:        // 上位側(FPRH)には最上位(実数桁)の隠しビットを含む。
1.1.1.13  root      619:        reg.fprh |= (u.h & 0x000fffff);
                    620:        reg.fprh |= FPRH_1;
                    621:        reg.fprl = u.l;
1.1.1.10  root      622: }
                    623: 
                    624: // FP Precise 例外。浮動小数点数1つの場合。
                    625: void
1.1.1.13  root      626: MPU88xx0Device::FPPreciseException(uint32 cause, double s2)
1.1.1.10  root      627: {
1.1.1.13  root      628:        SetFPS2(s2, m88100opf_FP_T2(reg.opX));
1.1.1.10  root      629:        FPPreciseException(cause);
                    630: }
                    631: 
                    632: // FP Precise 例外。浮動小数点数2つの場合。
                    633: void
1.1.1.13  root      634: MPU88xx0Device::FPPreciseException(uint32 cause, double s1, double s2)
1.1.1.10  root      635: {
1.1.1.13  root      636:        SetFPS1(s1, m88100opf_FP_T1(reg.opX));
                    637:        SetFPS2(s2, m88100opf_FP_T2(reg.opX));
1.1.1.10  root      638:        FPPreciseException(cause);
                    639: }
                    640: 
                    641: // FP Precise 例外。
                    642: void
1.1.1.13  root      643: MPU88xx0Device::FPPreciseException(uint32 cause)
1.1.1.10  root      644: {
                    645:        assert(cause == FPECR_FIOV   ||
                    646:               cause == FPECR_FUNIMP ||
                    647:               cause == FPECR_FPRV   ||
                    648:               cause == FPECR_FROP   ||
                    649:               cause == FPECR_FDVZ);
                    650: 
1.1.1.13  root      651:        reg.fpecr = cause;
1.1.1.10  root      652: 
                    653:        // FPPT(FP Precise operation Type Register)
1.1.1.13  root      654:        reg.fppt = reg.opX & 0xffe0;            // Opcode, T1, T2, TD は opX と同じ位置
                    655:        reg.fppt |= m88100opf_D(reg.opX);       // DEST
1.1.1.10  root      656: 
1.1.1.17! root      657:        InternalException(EXCVEC_SFU1_PRECISE);
1.1.1.10  root      658: }
                    659: 
                    660: // FP Imprecise 例外。
                    661: void
1.1.1.13  root      662: MPU88xx0Device::FPImpreciseException(uint32 cause)
1.1.1.10  root      663: {
                    664:        assert(cause == FPECR_FUNF ||
                    665:               cause == FPECR_FOVF ||
                    666:               cause == FPECR_FINX);
                    667: 
1.1.1.13  root      668:        reg.fpecr = cause;
1.1.1.10  root      669: 
                    670:        // FPIT(FP Imprecise operation Type Register)
1.1.1.13  root      671:        reg.fpit &= FPIT_RESEXP;
                    672:        reg.fpit |= reg.opX & FPIT_OPCODE;
                    673:        reg.fpit |= (reg.opX & 0x00000020) << 5;        // DESTSIZ
                    674:        reg.fpit |= (reg.fpcr & 0x0000001f) << 5;       // EFINV,EFDVZ,EFUNF,EFOVR,EFINX
                    675:        reg.fpit |= m88100opf_D(reg.opX);                       // DEST
1.1.1.10  root      676: 
                    677:        // FPRH(FP Result High Register)
1.1.1.13  root      678:        reg.fprh &= ~FPRH_RNDMODE;
                    679:        reg.fprh |= (reg.fpcr & FPCR_RM) << 14;
1.1.1.11  root      680: 
1.1.1.17! root      681:        OuterException(EXCPRI_SFU_IMPRECISE);
1.1       root      682: }
1.1.1.2   root      683: 
                    684: OP_DEF(illegal)
                    685: {
1.1.1.17! root      686:        // 不当命令例外。
1.1.1.13  root      687:        putlog(0, "Illegal instruction %08x", (uint32)reg.opX);
1.1.1.17! root      688:        Exception(EXCPRI_UNIMPL_OP);
1.1.1.2   root      689: }
1.1.1.11  root      690: 
1.1.1.13  root      691: //
                    692: // m88100reg の static 変数
                    693: //
                    694: 
                    695: // fcr のマスク
                    696: /*static*/ const uint32 m88100reg::fcr_mask[11] = {
                    697:        M88100::FPECR_MASK,
                    698:        0xffffffff,     // fphs1
                    699:        0xffffffff,     // fpls1
                    700:        0xffffffff,     // fphs2
                    701:        0xffffffff,     // fpls2
                    702:        M88100::FPPT_MASK,
                    703:        M88100::FPRH_MASK,
                    704:        0xffffffff,     // fprl
                    705:        M88100::FPIT_MASK,
                    706:        M88100::FPSR_MASK,
                    707:        M88100::FPCR_MASK,
                    708: };
                    709: 
                    710: /*static*/ const char * const m88100reg::sipname[3] = {
                    711:        "sxip", "snip", "sfip",
                    712: };
                    713: 
                    714: /*static*/ const char * const m88100reg::dmt_en_str[16] = {
                    715:        "----",
                    716:        "---B",
                    717:        "--B-",
                    718:        "--HH",
                    719:        "-B--",
                    720:        "-1-1", // not used normally
                    721:        "-11-", // not used normally
                    722:        "-111", // not used normally
                    723:        "B---",
                    724:        "1--1", // not used normally
                    725:        "1-1-", // not used normally
                    726:        "1-11", // not used normally
                    727:        "HH--",
                    728:        "11-1", // not used normally
                    729:        "111-", // not used normally
                    730:        "LLLL",
                    731: };

unix.superglobalmegacorp.com

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