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

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.18! root      103:        ev->time = cycle * clock_tsec + 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.18! root      175:        last_vector = vec;
1.1.1.15  root      176:        excep_counter[vec]++;
1.1.1.17  root      177:        if (vec == 450 || vec == 128) {
1.1.1.13  root      178:                syscall = reg.r[13];
1.1.1.4   root      179:                if (syscall == 0) {
1.1.1.13  root      180:                        syscall = reg.r[2];
1.1.1.4   root      181:                } else if (syscall == 198) {
1.1.1.13  root      182:                        syscall = reg.r[3];
1.1.1.4   root      183:                }
                    184:                syscall &= 0xfff;
                    185:        }
1.1.1.13  root      186:        uint32 from = reg.xip | (IsSuper() ? 1 : 0);
1.1.1.16  root      187:        uint32 info = 0xfc000000 | (syscall << 12) | vec;
                    188:        exhist.AddEntry(from, 0, info);
                    189:        brhist.AddEntry(from, 0, info);
1.1.1.4   root      190: 
1.1.1.13  root      191:        if ((reg.psr & PSR_SFRZ)) {
1.1.1.17  root      192:                if (pri != EXCPRI_TRAP) {
                    193:                        putlog(0, "Exception (primask=$%x) during SFRZ!", primask);
                    194: 
                    195:                        // エラー例外でもう一度報告。
                    196:                        // BranchHistory に繰り返しと判定されないよう to を変えておく。
                    197:                        pri = EXCPRI_ERROR;
                    198:                        vec = EXCVEC_ERROR;
1.1.1.18! root      199:                        last_vector = vec;
1.1.1.17  root      200:                        info = 0xfc000000 | vec;
                    201:                        exhist.AddEntry(from, 1, info);
                    202:                        brhist.AddEntry(from, 1, info);
                    203:                } else {
                    204:                        putlog(0, "Trap during Exception");
1.1       root      205:                }
                    206:        } else {
1.1.1.17  root      207:                if (vec == EXCVEC_INTERRUPT) {
                    208:                        putlog(2, "Exception (Interrupt)");
                    209:                } else {
1.1.1.13  root      210:                        putlog(1, "Exception %x x=%x n=%x f=%x",
                    211:                                vec, reg.xip, reg.nip, reg.fip);
1.1.1.2   root      212:                }
1.1.1.13  root      213:                reg.sxip = reg.xip;
                    214:                reg.snip = reg.nip;
                    215:                reg.sfip = reg.fip;
                    216: 
1.1.1.17  root      217:                if (pri != EXCPRI_UNIMPL_OP) {
                    218:                        reg.sxip |= SIP_V;
                    219:                }
1.1.1.13  root      220:                reg.snip |= SIP_V;
                    221:                reg.sfip |= SIP_V;
1.1       root      222: 
1.1.1.13  root      223:                if (OpIsBusErr(reg.opX)) {
1.1.1.17  root      224:                        reg.sxip |= SIP_E;
1.1       root      225:                }
1.1.1.13  root      226:                if (OpIsBusErr(reg.opF)) {
1.1.1.17  root      227:                        reg.snip |= SIP_E;
1.1       root      228:                }
                    229:        }
                    230: 
1.1.1.17  root      231:        if ((primask & EXCPRI_DATA)) {
                    232:                // パイプラインが未実装なので、PROM の DAE ハンドラが無限ループに
                    233:                // なるのをごまかすハックは vm/prom.cpp 参照。
1.1.1.2   root      234:        } else {
1.1.1.17  root      235:                // データアクセス例外でなければ DMT の V ビットはクリア。(Table.6-3)
                    236:                reg.dmt0 &= ~DM_VALID;
                    237:                reg.dmt1 &= ~DM_VALID;
                    238:                reg.dmt2 &= ~DM_VALID;
1.1.1.2   root      239:        }
                    240: 
1.1.1.17  root      241:        // XXX Figure 6-3 のフローだとトラップ例外の時は EPSR を保存しない
                    242:        // ようだが本当だろうか。本文はトラップ例外の記載が少ない。
1.1.1.13  root      243:        reg.epsr = reg.psr;
                    244:        SetPSR(reg.psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ);
1.1       root      245: 
1.1.1.13  root      246:        reg.fip = reg.vbr + (vec << 3);
1.1       root      247:        fetch();
1.1.1.3   root      248:        // ここでベクタに飛ぶのだが、ベクタ内の2命令でおそらく必ずもう一度
                    249:        // 分岐してそっちでも履歴が残るので、ここでブランチ履歴を残すのは
                    250:        // ちょっと冗長という気もする。
                    251: 
1.1.1.13  root      252:        if (OpIsBusErr(reg.opF)) {
1.1.1.17  root      253:                if (pri == EXCPRI_ERROR) {
1.1       root      254:                        // double bus fault
                    255:                        // 実機は無限ループ状態
                    256:                        PANIC("Infinite ERROR (double bus fault)");
                    257:                } else {
1.1.1.17  root      258:                        putlog(0, "Bus error on fetching $%08x (vector $%x)!",
                    259:                                reg.vbr + (vec << 3), vec);
                    260:                        Exception(EXCPRI_ERROR);
1.1       root      261:                }
                    262:        }
                    263: }
                    264: 
1.1.1.17  root      265: // EXCPRI_* の内部例外発生を予約する。
                    266: // 例外はこの場で処理するのではなく、命令境界で優先度の高い方から処理される
                    267: // ので、発生時に出来るのは予約することだけ。
                    268: void
                    269: MPU88xx0Device::Exception(uint32 pri)
                    270: {
                    271:        excep_pending |= pri;
                    272: }
                    273: 
                    274: // 外部優先度の例外の発生を予約する。
                    275: void
                    276: MPU88xx0Device::OuterException(uint32 pri)
                    277: {
                    278:        excep_pending |= pri;
                    279:        excep_pending |= EXCPRI_OUTER;
                    280: }
                    281: 
                    282: // 内部例外の発生を予約する。
                    283: // vec は発生させる例外のベクタ番号。
                    284: void
                    285: MPU88xx0Device::InternalException(uint32 vec)
                    286: {
                    287:        excep_vector = vec;
                    288:        Exception(EXCPRI_INTERNAL);
                    289: }
                    290: 
                    291: // トラップ例外の発生を予約する。
                    292: // vec は発生させる例外のベクタ番号。
                    293: void
                    294: MPU88xx0Device::TrapException(uint32 vec)
                    295: {
                    296:        excep_vector = vec;
                    297:        Exception(EXCPRI_TRAP);
                    298: }
                    299: 
                    300: // flag から DMT の共通部分を作って返す。
                    301: uint32
                    302: MPU88xx0Device::MakeDMT(uint32 flag)
1.1.1.5   root      303: {
1.1.1.13  root      304:        uint32 dmt;
                    305: 
                    306:        dmt = DM_VALID;
                    307:        if ((reg.psr & PSR_BO_LE))
                    308:                dmt |= DM_BO;
                    309:        if (IsSuper() && !(flag & DM_USR))
                    310:                dmt |= DM_DAS;
                    311: 
                    312:        return dmt;
1.1.1.5   root      313: }
                    314: 
1.1.1.17  root      315: // データアクセス例外(Read)、ld.[b,h,(w)] 用。
1.1       root      316: void
1.1.1.13  root      317: MPU88xx0Device::ReadDataException32(uint32 addr, uint32 flag)
1.1       root      318: {
                    319:        // ミスアラインドはこの例外より前にチェックされていて、
1.1.1.17  root      320:        // ここには (アクセスサイズでの) アラインドしかこない。
                    321: 
                    322:        reg.dmt0  = MakeDMT(flag);
1.1.1.13  root      323:        reg.dmt0 |= FLD_D << 7;
                    324:        reg.dmt0 |= flag & DM_SIGNED;
                    325:        reg.dmt0 |= (flag & DM_EN_MASK) >> (addr & 0x03);
1.1.1.17  root      326:        reg.dma0 = addr & ~0x3;
1.1.1.13  root      327: 
                    328:        reg.dmt1 &= ~DM_VALID;
                    329:        reg.dmt2 &= ~DM_VALID;
1.1.1.17  root      330: 
1.1.1.13  root      331:        putlog(1, "ReadDAE xip=%x addr=%x", reg.xip, addr);
1.1.1.17  root      332:        OuterException(EXCPRI_DATA);
1.1       root      333: }
                    334: 
1.1.1.17  root      335: // データアクセス例外(Read)、ld.d 用。
                    336: // どちらのワードで例外が起きても first_addr は第1ワードのアドレス。
1.1.1.5   root      337: void
1.1.1.17  root      338: MPU88xx0Device::ReadDataException64(uint32 first_addr, uint32 flag)
1.1.1.5   root      339: {
                    340:        // ミスアラインドはこの例外より前にチェックされていて、
                    341:        // ここにはアラインドしかこない。
1.1.1.13  root      342: 
1.1.1.17  root      343:        uint32 dmt_2nd;
                    344:        uint32 dma_2nd;
1.1.1.5   root      345: 
1.1.1.17  root      346:        reg.dmt1 &= ~DM_VALID;
1.1.1.13  root      347:        reg.dmt2 &= ~DM_VALID;
1.1.1.5   root      348: 
1.1.1.17  root      349:        // 先に2ワード目の情報を作っておく。
                    350:        dmt_2nd  = MakeDMT(flag);
                    351:        dmt_2nd |= FLD_D2 << 7;
                    352:        dmt_2nd |= DM_EN_MASK;          // 32ビット有効
                    353:        dma_2nd = first_addr + 4;
                    354: 
                    355:        uint32 doub1 = (flag & DM_DOUB1);
                    356:        if (doub1) {
                    357:                // 1ワード目がバスエラーなら、DMx0 と DMx1 を使う。
                    358:                reg.dmt0  = MakeDMT(flag);
                    359:                reg.dmt0 |= doub1;
                    360:                reg.dmt0 |= FLD_D << 7;
                    361:                reg.dmt0 |= DM_EN_MASK;         // 32ビット有効
                    362:                reg.dma0 = first_addr;
                    363: 
                    364:                reg.dmt1 = dmt_2nd;
                    365:                reg.dma1 = dma_2nd;
                    366:        } else {
                    367:                // 2ワード目がバスエラーなら、DMx0 に2ワード目の情報だけ。
                    368:                reg.dmt0 = dmt_2nd;
                    369:                reg.dma0 = dma_2nd;
1.1.1.5   root      370:        }
                    371: 
1.1.1.17  root      372:        putlog(1, "ReadDAE64 xip=%x addr=%x", reg.xip, reg.dma0);
                    373:        OuterException(EXCPRI_DATA);
1.1.1.5   root      374: }
                    375: 
1.1.1.17  root      376: // データアクセス例外(Write)、st.[b,h,(w)] 用。
1.1       root      377: void
1.1.1.13  root      378: MPU88xx0Device::WriteDataException32(uint32 addr, uint32 flag)
1.1       root      379: {
                    380:        // ミスアラインドはこの例外より前にチェックされていて、
1.1.1.17  root      381:        // ここには (アクセスサイズでの) アラインドしかこない。
                    382: 
                    383:        reg.dmt0  = MakeDMT(flag);
1.1.1.13  root      384:        reg.dmt0 |= (flag & DM_EN_MASK) >> (addr & 0x03);
                    385:        reg.dmt0 |= DM_WRITE;
1.1.1.17  root      386:        reg.dma0 = addr & ~0x3;
1.1.1.13  root      387:        reg.dmd0 = rD;
                    388: 
                    389:        reg.dmt1 &= ~DM_VALID;
                    390:        reg.dmt2 &= ~DM_VALID;
1.1.1.17  root      391: 
1.1.1.13  root      392:        putlog(1, "WriteDAE xip=%x addr=%x", reg.xip, addr);
1.1.1.17  root      393:        OuterException(EXCPRI_DATA);
1.1.1.2   root      394: }
                    395: 
1.1.1.17  root      396: // データアクセス例外(Write)、st.d 用。
                    397: // どちらのワードで例外が起きても first_addr は第1ワードのアドレス。
1.1.1.5   root      398: void
1.1.1.17  root      399: MPU88xx0Device::WriteDataException64(uint32 first_addr, uint32 flag)
1.1.1.5   root      400: {
                    401:        // ミスアラインドはこの例外より前にチェックされていて、
                    402:        // ここにはアラインドしかこない。
1.1.1.13  root      403: 
1.1.1.17  root      404:        uint32 dmt_2nd;
                    405:        uint32 dma_2nd;
                    406:        uint32 dmd_2nd;
1.1.1.5   root      407: 
1.1.1.17  root      408:        reg.dmt1 &= ~DM_VALID;
1.1.1.13  root      409:        reg.dmt2 &= ~DM_VALID;
1.1.1.5   root      410: 
1.1.1.17  root      411:        // 先に2ワード目の情報を作っておく。
                    412:        dmt_2nd  = MakeDMT(flag);
                    413:        dmt_2nd |= DM_EN_MASK;
                    414:        dmt_2nd |= DM_WRITE;
                    415:        dma_2nd = first_addr + 4;
                    416:        dmd_2nd = rD2;
                    417: 
                    418:        uint32 doub1 = (flag & DM_DOUB1);
                    419:        if (doub1) {
                    420:                // 1ワード目がバスエラーなら、DMx0 と DMx1 を使う。
                    421:                reg.dmt0  = MakeDMT(flag);
                    422:                reg.dmt0 |= DM_DOUB1;           // ダブルワードの第1アクセスのときセット
                    423:                reg.dmt0 |= DM_EN_MASK;
                    424:                reg.dmt0 |= DM_WRITE;
                    425:                reg.dma0 = first_addr;
                    426:                reg.dmd0 = rD;
                    427: 
                    428:                reg.dmt1 = dmt_2nd;
                    429:                reg.dma1 = dma_2nd;
                    430:                reg.dmd1 = dmd_2nd;
                    431:        } else {
                    432:                // 2ワード目がバスエラーなら、DMx0 に2ワード目の情報だけ。
                    433:                reg.dmt0 = dmt_2nd;
                    434:                reg.dma0 = dma_2nd;
                    435:                reg.dmd0 = dmd_2nd;
1.1.1.5   root      436:        }
                    437: 
1.1.1.17  root      438:        putlog(1, "WriteDAE64 xip=%x addr=%x", reg.xip, reg.dma0);
                    439:        OuterException(EXCPRI_DATA);
1.1.1.5   root      440: }
                    441: 
1.1.1.2   root      442: // データアクセス例外(xmem)
1.1.1.17  root      443: // xmem は .bu と (.w) しかない。
1.1.1.2   root      444: void
1.1.1.13  root      445: MPU88xx0Device::XmemDataException(uint32 addr, uint32 flag)
1.1.1.2   root      446: {
1.1.1.17  root      447:        // ミスアラインドはこの例外より前にチェックされていて、
                    448:        // ここには (アクセスサイズでの) アラインドしかこない。
1.1.1.13  root      449: 
1.1.1.17  root      450:        uint32 dmt_rd;
                    451:        uint32 dmt_wr;
                    452:        uint32 dma;
                    453:        uint32 dmd_wr;
1.1.1.2   root      454: 
1.1.1.17  root      455:        reg.dmt1 &= ~DM_VALID;
1.1.1.13  root      456:        reg.dmt2 &= ~DM_VALID;
1.1.1.2   root      457: 
1.1.1.17  root      458:        dmt_rd  = MakeDMT(flag);
                    459:        dmt_rd |= DM_LOCK;
                    460:        dmt_rd |= FLD_D << 7;
                    461:        dmt_rd |= flag & DM_SIGNED;
                    462:        dmt_rd |= (flag & DM_EN_MASK) >> (addr & 0x03);
                    463:        dma = addr & ~0x3U;
                    464: 
                    465:        dmt_wr = dmt_rd | DM_WRITE;
                    466:        dmd_wr = rD;
                    467: 
1.1.1.13  root      468:        if (cmmu[1]->fault_code != m88200::FAULT_CODE_BUSERR
                    469:         || cmmu[1]->acc_read) {
1.1.1.17  root      470:                // アドレス変換フォルトまたは read 時点のバスエラー。
                    471:                reg.dmt0 = dmt_rd;
                    472:                reg.dma0 = dma;
                    473: 
                    474:                reg.dmt1 = dmt_wr;
                    475:                reg.dma1 = dma;
                    476:                reg.dmd1 = dmd_wr;
1.1       root      477:        } else {
1.1.1.17  root      478:                // xmem の write 時点のバスエラー。
                    479:                reg.dmt0 = dmt_wr;
                    480:                reg.dma0 = dma;
                    481:                reg.dmd0 = dmd_wr;
1.1       root      482:        }
1.1.1.2   root      483: 
1.1.1.13  root      484:        putlog(1, "xmemDAE xip=%x addr=%x", reg.xip, addr);
1.1.1.17  root      485:        OuterException(EXCPRI_DATA);
1.1       root      486: }
                    487: 
1.1.1.10  root      488: // FPxS レジスタをセット
1.1.1.13  root      489: /*static*/ void
1.1.1.15  root      490: MPU88xx0Device::SetFPxS(uint32 *h, uint32 *l, double src, uint32 ts)
1.1.1.5   root      491: {
1.1.1.10  root      492:        // FPHS[12]、FPLS[12] は以下の構造
                    493:        //
                    494:        //    3                   2                   1                   0
                    495:        //  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
                    496:        // +-+---------------------+---------------------------------------+
                    497:        // |S|   Exponent(11bit)   |     High Order 20 bits of Mantissa    | FPHSn
                    498:        // +-+---------------------+---------------------------------------+
                    499:        //
                    500:        // +---------------------------------------------------------------+
                    501:        // |           Low Order bits of Mantissa, or Integer              | FPLSn
                    502:        // +---------------------------------------------------------------+
                    503:        //
                    504:        // ts が 1 (double) の場合は IEEE754 double と同じ。
                    505:        // ts が 0 (single) の場合は float を double にキャスト (拡大変換) した
                    506:        // ものではないことに注意。
                    507:        // S(符号ビット)はそのまま。float の Mantissa (23bit) のうち上位 20bit
                    508:        // を FPHSn に、残り 3bit を FPLSn の上位 3bit に。ここまではいい。
                    509:        // Exponent は float の指数部(8bit、バイアス=127) の値を *そのまま*
                    510:        // 符号拡張(?)する。
                    511:        // (float)1.0 は 1.0 * 2^0 なのでバイアス込みの指数部は 127、
                    512:        // (float)2.0 は 1.0 * 2^1 なのでバイアス込みの指数部は 128。
                    513:        // バイアス込みにした値は符号なし数のはずだが、ここではこれを 11bit に
                    514:        // 符号拡張して FPHSn の Exponent 部に格納するようだ。取り出す際に下位
                    515:        // 8bit しか取り出さなければ害はないし、符号拡張する方がハードウェア的に
                    516:        // 都合がよかったとかだろうか。
                    517:        // 仮に普通に double に変換すると double の指数部バイアスは 1023 なので
                    518:        // バイアス込みの指数部は先程の例だとそれぞれ 1023、1024 になるが
                    519:        // これではないということ。
                    520: 
                    521:        union64 u;
                    522:        u.q = d2u(src);
                    523:        if (ts == 0) {
                    524:                // single
                    525: 
                    526:                uint32 exp;
                    527:                // src は普通の double なのでこの指数部を取り出す
                    528:                uint32 double_biased = (u.h >> 20) & 0x7ff;
1.1.1.17  root      529:                if (double_biased == 0) {
                    530:                        // Zero
                    531:                        exp = 0;
                    532:                } else if (double_biased == 0x7ff) {
1.1.1.10  root      533:                        // Inf, NAN
                    534:                        exp = 0x7ff00000;
                    535:                } else {
                    536:                        // double のバイアスを外して float のバイアスを足す
                    537:                        int float_biased = (double_biased - 1023) + 127;
                    538:                        // この 8bit 値を 11bit に符号拡張して所定の位置へ
                    539:                        exp = ((int32)(float_biased << 24)) >> 4;
1.1.1.17  root      540:                        exp &= ~0x80000000;
1.1.1.10  root      541:                }
                    542: 
1.1.1.15  root      543:                *h = (u.h & 0x800fffff) | exp;
                    544:                *l = u.l;
1.1.1.10  root      545:        } else {
                    546:                // double
1.1.1.15  root      547:                *h = u.h;
                    548:                *l = u.l;
1.1.1.10  root      549:        }
                    550: }
                    551: 
1.1.1.13  root      552: // FPxS1 レジスタをセット
                    553: void
                    554: MPU88xx0Device::SetFPS1(double src, uint32 t1)
                    555: {
1.1.1.15  root      556:        SetFPxS(&reg.fphs1, &reg.fpls1, src, t1);
1.1.1.13  root      557: }
                    558: 
                    559: // FPxS2 レジスタをセット
                    560: void
                    561: MPU88xx0Device::SetFPS2(double src, uint32 t2)
                    562: {
1.1.1.15  root      563:        SetFPxS(&reg.fphs2, &reg.fpls2, src, t2);
1.1.1.13  root      564: }
                    565: 
                    566: void
                    567: MPU88xx0Device::SetFPS1(uint32 src)
                    568: {
                    569:        reg.fpls1 = src;
                    570: }
                    571: 
                    572: void
                    573: MPU88xx0Device::SetFPS2(uint32 src)
                    574: {
                    575:        reg.fpls2 = src;
                    576: }
                    577: 
1.1.1.10  root      578: // FPR[HL] レジスタに double 値をセット
                    579: // - それ以外のフィールドは保存する XXX ここでクリアしてもいいか?
                    580: // - XXX Guard, Round, Sticky (, AddOne) はまだない
                    581: void
1.1.1.13  root      582: MPU88xx0Device::SetFPRx(double src)
1.1.1.10  root      583: {
                    584:        union64 u;
                    585:        uint32 exp;
                    586: 
                    587:        u.q = d2u(src);
                    588: 
                    589:        // Sign は FPRH
1.1.1.13  root      590:        reg.fprh &= ~(FPRH_SIGN | FPRH_MANT);   // Mantissa もついでにクリア
                    591:        reg.fprh |= u.h & 0x80000000;
1.1.1.10  root      592: 
                    593:        // Exp  は FPIT。
                    594:        // double は 11bit だが FPIT::RESEXP は 12bit なので 1bit 符号拡張する。
                    595:        // 符号付き数(正確には負数)の右シフトは実装依存だが gcc, clang は
                    596:        // 算術右シフトになる。
                    597:        //
                    598:        //           3                   2
                    599:        //         1 0 9 8 7 6 5 4 3 2 1 0 9
                    600:        //        +-+---------------------+-
                    601:        // double |S|   Exponent(11bit)   |
                    602:        //        +-+---------------------+-
                    603:        //
                    604:        //        +---------------------+-+-
                    605:        // u.h<<1 |  Exponent(11bit)    |X|
                    606:        //        +---------------------+-+-
                    607:        //
                    608:        //        +-----------------------+-
                    609:        // exp>>1 |   Exponent(12bit)     |
                    610:        //        +-----------------------+-
                    611:        exp = u.h << 1;
                    612:        exp = (int32)exp >> 1;
1.1.1.13  root      613:        reg.fpit &= ~FPIT_RESEXP;
                    614:        reg.fpit |= exp & FPIT_RESEXP;
1.1.1.10  root      615: 
                    616:        // Mantissa は FPRH, FPRL
                    617:        // 上位側(FPRH)には最上位(実数桁)の隠しビットを含む。
1.1.1.13  root      618:        reg.fprh |= (u.h & 0x000fffff);
                    619:        reg.fprh |= FPRH_1;
                    620:        reg.fprl = u.l;
1.1.1.10  root      621: }
                    622: 
                    623: // FP Precise 例外。浮動小数点数1つの場合。
                    624: void
1.1.1.13  root      625: MPU88xx0Device::FPPreciseException(uint32 cause, double s2)
1.1.1.10  root      626: {
1.1.1.13  root      627:        SetFPS2(s2, m88100opf_FP_T2(reg.opX));
1.1.1.10  root      628:        FPPreciseException(cause);
                    629: }
                    630: 
                    631: // FP Precise 例外。浮動小数点数2つの場合。
                    632: void
1.1.1.13  root      633: MPU88xx0Device::FPPreciseException(uint32 cause, double s1, double s2)
1.1.1.10  root      634: {
1.1.1.13  root      635:        SetFPS1(s1, m88100opf_FP_T1(reg.opX));
                    636:        SetFPS2(s2, m88100opf_FP_T2(reg.opX));
1.1.1.10  root      637:        FPPreciseException(cause);
                    638: }
                    639: 
                    640: // FP Precise 例外。
                    641: void
1.1.1.13  root      642: MPU88xx0Device::FPPreciseException(uint32 cause)
1.1.1.10  root      643: {
                    644:        assert(cause == FPECR_FIOV   ||
                    645:               cause == FPECR_FUNIMP ||
                    646:               cause == FPECR_FPRV   ||
                    647:               cause == FPECR_FROP   ||
                    648:               cause == FPECR_FDVZ);
                    649: 
1.1.1.13  root      650:        reg.fpecr = cause;
1.1.1.10  root      651: 
                    652:        // FPPT(FP Precise operation Type Register)
1.1.1.13  root      653:        reg.fppt = reg.opX & 0xffe0;            // Opcode, T1, T2, TD は opX と同じ位置
                    654:        reg.fppt |= m88100opf_D(reg.opX);       // DEST
1.1.1.10  root      655: 
1.1.1.17  root      656:        InternalException(EXCVEC_SFU1_PRECISE);
1.1.1.10  root      657: }
                    658: 
                    659: // FP Imprecise 例外。
                    660: void
1.1.1.13  root      661: MPU88xx0Device::FPImpreciseException(uint32 cause)
1.1.1.10  root      662: {
                    663:        assert(cause == FPECR_FUNF ||
                    664:               cause == FPECR_FOVF ||
                    665:               cause == FPECR_FINX);
                    666: 
1.1.1.13  root      667:        reg.fpecr = cause;
1.1.1.10  root      668: 
                    669:        // FPIT(FP Imprecise operation Type Register)
1.1.1.13  root      670:        reg.fpit &= FPIT_RESEXP;
                    671:        reg.fpit |= reg.opX & FPIT_OPCODE;
                    672:        reg.fpit |= (reg.opX & 0x00000020) << 5;        // DESTSIZ
                    673:        reg.fpit |= (reg.fpcr & 0x0000001f) << 5;       // EFINV,EFDVZ,EFUNF,EFOVR,EFINX
                    674:        reg.fpit |= m88100opf_D(reg.opX);                       // DEST
1.1.1.10  root      675: 
                    676:        // FPRH(FP Result High Register)
1.1.1.13  root      677:        reg.fprh &= ~FPRH_RNDMODE;
                    678:        reg.fprh |= (reg.fpcr & FPCR_RM) << 14;
1.1.1.11  root      679: 
1.1.1.17  root      680:        OuterException(EXCPRI_SFU_IMPRECISE);
1.1       root      681: }
1.1.1.2   root      682: 
                    683: OP_DEF(illegal)
                    684: {
1.1.1.17  root      685:        // 不当命令例外。
1.1.1.13  root      686:        putlog(0, "Illegal instruction %08x", (uint32)reg.opX);
1.1.1.17  root      687:        Exception(EXCPRI_UNIMPL_OP);
1.1.1.2   root      688: }
1.1.1.11  root      689: 
1.1.1.13  root      690: //
                    691: // m88100reg の static 変数
                    692: //
                    693: 
                    694: // fcr のマスク
                    695: /*static*/ const uint32 m88100reg::fcr_mask[11] = {
                    696:        M88100::FPECR_MASK,
                    697:        0xffffffff,     // fphs1
                    698:        0xffffffff,     // fpls1
                    699:        0xffffffff,     // fphs2
                    700:        0xffffffff,     // fpls2
                    701:        M88100::FPPT_MASK,
                    702:        M88100::FPRH_MASK,
                    703:        0xffffffff,     // fprl
                    704:        M88100::FPIT_MASK,
                    705:        M88100::FPSR_MASK,
                    706:        M88100::FPCR_MASK,
                    707: };
                    708: 
                    709: /*static*/ const char * const m88100reg::sipname[3] = {
                    710:        "sxip", "snip", "sfip",
                    711: };
                    712: 
                    713: /*static*/ const char * const m88100reg::dmt_en_str[16] = {
                    714:        "----",
                    715:        "---B",
                    716:        "--B-",
                    717:        "--HH",
                    718:        "-B--",
                    719:        "-1-1", // not used normally
                    720:        "-11-", // not used normally
                    721:        "-111", // not used normally
                    722:        "B---",
                    723:        "1--1", // not used normally
                    724:        "1-1-", // not used normally
                    725:        "1-11", // not used normally
                    726:        "HH--",
                    727:        "11-1", // not used normally
                    728:        "111-", // not used normally
                    729:        "LLLL",
                    730: };

unix.superglobalmegacorp.com

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