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

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

unix.superglobalmegacorp.com

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