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

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

unix.superglobalmegacorp.com

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