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

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

unix.superglobalmegacorp.com

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