Annotation of nono/vm/mpu88xx0.cpp, revision 1.1.1.19

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.11  root        7: //
                      8: // MPU (M88xx0)
                      9: //
1.1       root       10: 
                     11: #include "mpu88xx0.h"
                     12: #include "config.h"
1.1.1.11  root       13: #include "debugger.h"
1.1.1.19! root       14: #include "event.h"
1.1.1.12  root       15: #include "m88100disasm.h"
1.1.1.11  root       16: #include "scheduler.h"
1.1.1.2   root       17: 
1.1       root       18: // コンストラクタ
1.1.1.7   root       19: MPU88xx0Device::MPU88xx0Device()
1.1.1.13  root       20:        : inherited()
1.1       root       21: {
1.1.1.13  root       22:        SetName("MPU(88100)");
1.1.1.4   root       23: 
1.1.1.13  root       24:        // LUNA-88K では CMMU の ID は次のように割り振ってあるようだ。
1.1.1.2   root       25:        // OpenBSD の sys/arch/luna68k/include/board.h より。
                     26:        //
                     27:        //       Inst Data
                     28:        // CPU#0 ID=7 ID=6
                     29:        // CPU#1 ID=5 ID=4
                     30:        // CPU#2 ID=3 ID=2
                     31:        // CPU#3 ID=1 ID=0
                     32:        //
1.1.1.13  root       33:        // 厳密にはこれは LUNA-88K のハードウェアがどういうコンフィグレーションで
1.1.1.2   root       34:        // m88200 を使うかなので、ここではなくて vm_luna あたりのほうがいいかも
                     35:        // しれんけど、あまり遠いのも面倒なので、とりあえずこの辺に。
                     36:        // あとマルチプロセッサになったらまたその時考える。
1.1.1.13  root       37:        cmmu[0].reset(new m88200(this, 7));
                     38:        cmmu[1].reset(new m88200(this, 6));
1.1.1.2   root       39: 
1.1.1.15  root       40:        // 設定の初期値。
                     41: 
                     42:        // MPU のデフォルトは xxx.usr バグ修正済みのバージョンに設定する。
                     43:        // 所有している実機にあわせ 0xb。OpenBSD の
                     44:        // sys/arch/m88k/m88k/m88100_machdep.c::m88100_apply_patches() 参照。
                     45:        gConfig->SetDefault("m88100-version", 0xb);
                     46: 
                     47:        // CMMU のデフォルトは xmem の writeback バグが修正されているバージョンに
                     48:        // 設定する。所有している実機にあわせ 0x9。
                     49:        // OpenBSD の sys/arch/m88k/m88k/m8820x_machdep.c::m8820x_apr_cmode() 参照。
                     50:        gConfig->SetDefault("m88200-version", 0x9);
                     51: 
                     52:        // 例外カウンタ
                     53:        excep_counter.resize(512);
                     54: 
1.1.1.8   root       55:        // レジスタモニター
1.1.1.16  root       56:        monitor = gMonitorManager->Regist(ID_MONITOR_MPUREG, this);
                     57:        monitor->func = ToMonitorCallback(&MPU88xx0Device::MonitorUpdate);
                     58:        monitor->SetSize(79, 25);
1.1       root       59: }
                     60: 
                     61: // デストラクタ
                     62: MPU88xx0Device::~MPU88xx0Device()
                     63: {
                     64: }
                     65: 
1.1.1.13  root       66: // 初期化
1.1.1.5   root       67: bool
                     68: MPU88xx0Device::Init()
                     69: {
                     70:        if (inherited::Init() == false) {
                     71:                return false;
                     72:        }
                     73: 
1.1.1.12  root       74:        const ConfigItem& item_stop = gConfig->Find("mpu-pseudo-stop");
1.1.1.13  root       75:        pseudo_stop_enable = (bool)item_stop.AsInt();
1.1.1.12  root       76: 
                     77:        const ConfigItem& item_altname = gConfig->Find(".m88k-altname");
                     78:        m88100disasm::use_altname = item_altname.AsInt();
1.1.1.8   root       79: 
1.1.1.15  root       80:        // MPU のバージョン。
                     81:        const ConfigItem& item_88100ver = gConfig->Find("m88100-version");
                     82:        uint ver88100 = item_88100ver.AsInt();
                     83:        reg.pid = (ver88100 << 1) | M88100::PID_MASTER;
                     84: 
                     85:        // CMMU のバージョン。
                     86:        const ConfigItem& item_88200ver = gConfig->Find("m88200-version");
                     87:        uint ver88200 = item_88200ver.AsInt();
                     88:        cmmu[0]->SetVersion(ver88200);
                     89:        cmmu[1]->SetVersion(ver88200);
                     90: 
1.1.1.5   root       91:        return true;
                     92: }
                     93: 
1.1.1.11  root       94: // リセット
                     95: void
                     96: MPU88xx0Device::ResetHard(bool poweron)
1.1.1.7   root       97: {
1.1.1.11  root       98:        if (poweron) {
1.1.1.13  root       99:                // レジスタのうち不定と明記されてるものは、未初期化のまま触ったことが
                    100:                // 分かりやすいような適当なパターンで埋めておく。ただし最上位も c に
                    101:                // すると BT45x のレジスタ付近を指してしまうので、それは避けておく。
                    102:                const uint32 Undefined = 0x0ccccccc;
                    103:                for (int i = 1; i < 32; i++) {
                    104:                        reg.r[i] = Undefined;
                    105:                }
                    106:                for (int i = 0; i < countof(reg.fcr); i++) {
                    107:                        reg.fcr[i] = Undefined & reg.fcr_mask[i];
                    108:                }
                    109: 
                    110:                reg.epsr = Undefined;
                    111:                reg.ssbr = Undefined;
                    112:                reg.sfip = Undefined;
                    113:                reg.snip = Undefined;
                    114:                reg.sxip = Undefined;
                    115:                // DMTx は bit0(Valid) をクリア。DMAx/DMDx は不定。
                    116:                reg.dma0 = Undefined;
                    117:                reg.dma1 = Undefined;
                    118:                reg.dma2 = Undefined;
                    119:                reg.dmd0 = Undefined;
                    120:                reg.dmd1 = Undefined;
                    121:                reg.dmd2 = Undefined;
                    122: 
                    123:                // アクセスが一度もない時にどのアドレスとも一致しないようにしておく。
                    124:                lastaddr = (uint64)-1;
                    125: 
                    126:                // サイクルを初期化。
                    127:                used_cycle = 0;
                    128: 
                    129:                // 履歴は電源オン時だけ初期化。
                    130:                // (LUNA-88K は ROM が正常パスで CPU リセットを行ったりするので)
                    131:                exhist.Clear();
                    132:                brhist.Clear();
                    133: 
                    134:                // この後起きるリセット例外で xip を初期化する前に参照することに
                    135:                // なるので、これだけここでも初期化しておく。
                    136:                reg.xip = 0;
1.1.1.11  root      137:        }
1.1.1.15  root      138: 
1.1.1.12  root      139:        resetting = true;
1.1.1.19! root      140:        Exception(EXCPRI_RESET);
1.1.1.11  root      141: 
                    142:        // リセット例外を 8+256 クロック後に起こす。
                    143:        // 8+256 は、電源オン時に最低これだけアサートしなければならないという値
                    144:        // のはずで、実際これだけかかるとかいう値ではない。が、こちら側の都合で
                    145:        // この後実行される RAM の ResetHard() がブートページを用意した後で
                    146:        // cpu->Reset() で xip をフェッチするという順序にしないといけないため、
                    147:        // リセット例外が起動するまでに時間がかかるというところを都合よく真似て
                    148:        // おく。
                    149: 
1.1.1.19! root      150:        exec_event->func = ToEventCallback(&MPU88xx0Device::ResetCallback);
        !           151:        exec_event->time = (8 + 256) * clock_nsec;
        !           152:        exec_event->SetName(GetName() + " Reset");
1.1.1.13  root      153:        scheduler->RestartEvent(exec_event);
1.1.1.7   root      154: }
                    155: 
1.1.1.11  root      156: // リセット例外コールバック。
                    157: // MPU リセットから規定時間後に呼ばれる。
1.1       root      158: void
1.1.1.19! root      159: MPU88xx0Device::ResetCallback(Event *ev)
1.1       root      160: {
1.1.1.11  root      161:        // リセット例外を実行
1.1.1.13  root      162:        uint64 cycle_start = used_cycle;
                    163: 
                    164:        // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
                    165:        // リセット例外も発生時の XIP を記録する。(LUNA-88K の PROM 1.20)
                    166:        exhist.AddEntry(reg.xip | 1, 0, 0xfc000000 | 0);
                    167:        brhist.AddEntry(reg.xip | 1, 0, 0xfc000000 | 0);
                    168:        // デバッガに通知 (例外ブレーク用)
                    169:        debugger->NotifyExceptionMain(0);
                    170: 
1.1.1.19! root      171:        // 内部の例外状態をクリア
        !           172:        resetting = false;
        !           173:        excep_pending = 0;
1.1.1.13  root      174:        ChangeState(CPU_STATE_NORMAL);
                    175: 
                    176:        // 実際どこかは分からんけど PSR 設定の前にリセットしておきたい
                    177:        cmmu[0]->Reset();
                    178:        cmmu[1]->Reset();
                    179: 
                    180:        // Table 6-8 (p6-47)
                    181:        reg.psr = 0x800003ff;
                    182:        // XXX ただし SFU1 は未実装なので下げておく
                    183:        reg.psr &= ~PSR_SFD1;
                    184: 
                    185: #if defined(TEST_INTERRUPT)
                    186:        reg.psr &= ~PSR_IND;
                    187:        reg.psr &= ~PSR_SFRZ;
                    188: #endif
                    189: 
                    190:        SetPSR();
                    191: 
                    192:        reg.fip = 0;
                    193: 
                    194:        // レジスタのうち明記されてるものをクリア。
                    195:        // 不定と明記されてるものはリセットでは触らないでおく。
                    196:        // scoreboard: cleared
                    197:        reg.nip = 0;
                    198:        reg.xip = 0;
                    199:        reg.vbr = 0;
                    200:        reg.fpecr = 0;
                    201:        reg.fpcr = 0;
                    202:        reg.fpsr = 0;
                    203:        // DMTx は bit0(Valid) をクリア。他は不定
                    204:        reg.dmt0 &= ~DM_VALID;
                    205:        reg.dmt1 &= ~DM_VALID;
                    206:        reg.dmt2 &= ~DM_VALID;
                    207: 
                    208:        fetch();
                    209: 
                    210:        // リセット例外はここまで。
                    211:        // ここからは最初の命令のプリフェッチ
                    212:        Prefetch();
1.1.1.11  root      213: 
                    214:        // コールバックを ResetCallback から Exec* に差し替える前のここで
                    215:        // トレース状態を初期化する。
1.1.1.13  root      216:        SetTrace(debugger->IsTrace());
1.1.1.11  root      217: 
                    218:        // 以降は通常走行
1.1.1.13  root      219:        int cycle = used_cycle - cycle_start;
1.1.1.19! root      220:        exec_event->func = exec_normal;
        !           221:        exec_event->time = cycle * clock_nsec;
        !           222:        exec_event->SetName(GetName() + " Execute");
1.1.1.13  root      223:        scheduler->StartEvent(exec_event);
1.1.1.11  root      224: }
                    225: 
                    226: // トレース実行のコールバック
                    227: void
1.1.1.19! root      228: MPU88xx0Device::ExecTrace(Event *ev)
1.1.1.11  root      229: {
1.1.1.13  root      230:        debugger->ExecMain();
1.1.1.11  root      231:        ExecNormal(ev);
                    232: }
                    233: 
                    234: // トレース状態を設定する
                    235: void
                    236: MPU88xx0Device::SetTrace(bool enable)
                    237: {
                    238:        if (enable) {
                    239:                exec_normal = ToEventCallback(&MPU88xx0Device::ExecTrace);
                    240:        } else {
                    241:                exec_normal = ToEventCallback(&MPU88xx0Device::ExecNormal);
                    242:        }
1.1.1.19! root      243:        exec_event->func = exec_normal;
1.1.1.11  root      244: }
                    245: 
1.1.1.6   root      246: // アクセス中の論理アドレスを取得
                    247: uint32
                    248: MPU88xx0Device::GetLaddr() const
                    249: {
1.1.1.13  root      250:        m88200 *m = m88200::GetBusMaster();
                    251:        assert(m);
                    252:        return m->GetLaddr();
1.1.1.6   root      253: }
                    254: 
                    255: // アクセス中の物理アドレスを取得
                    256: uint32
                    257: MPU88xx0Device::GetPaddr() const
                    258: {
1.1.1.13  root      259:        m88200 *m = m88200::GetBusMaster();
                    260:        assert(m);
                    261:        return m->GetPaddr();
1.1.1.4   root      262: }
                    263: 
1.1.1.2   root      264: // Interrupt
                    265: void
1.1.1.5   root      266: MPU88xx0Device::Interrupt(int level)
1.1.1.2   root      267: {
1.1.1.13  root      268:        // level は 0 か 1。
1.1.1.19! root      269:        intr_asserted = level;
1.1.1.13  root      270: 
1.1.1.19! root      271:        if (intr_asserted && IsIntrEnable()) {
        !           272:                OuterException(EXCPRI_INTERRUPT);
        !           273: 
        !           274:                if (cpu_state == CPU_STATE_STOP) {
        !           275:                        // 割り込みを受け付けたら STOP 解除。
        !           276:                        ChangeState(CPU_STATE_NORMAL);
        !           277:                }
        !           278:        } else {
        !           279:                excep_pending &= ~EXCPRI_INTERRUPT;
        !           280:                // INTERRUPT を下げたことで全員いなくなれば OUTER を下げる。
        !           281:                if ((excep_pending & EXCPRI_OUTER_MASK) == 0) {
        !           282:                        excep_pending &= ~EXCPRI_OUTER;
        !           283:                }
1.1.1.13  root      284:        }
1.1.1.2   root      285: }
                    286: 
1.1.1.19! root      287: void
        !           288: MPU88xx0Device::SetPSR()
        !           289: {
        !           290:        if (intr_asserted && IsIntrEnable()) {
        !           291:                OuterException(EXCPRI_INTERRUPT);
        !           292:        } else {
        !           293:                excep_pending &= ~EXCPRI_INTERRUPT;
        !           294:                // INTERRUPT を下げたことで全員いなくなれば OUTER を下げる。
        !           295:                if ((excep_pending & EXCPRI_OUTER_MASK) == 0) {
        !           296:                        excep_pending &= ~EXCPRI_OUTER;
        !           297:                }
        !           298:        }
        !           299: 
        !           300:        // CMMU に S/U 信号を出す
        !           301:        cmmu[0]->SetSuper(IsSuper());
        !           302:        cmmu[1]->SetSuper(IsSuper());
        !           303: }
        !           304: 
1.1.1.9   root      305: // DOS call エミュレーションのコールバックを指定
                    306: void
1.1.1.13  root      307: MPU88xx0Device::SetFLineCallback(bool (*callback)(MPU88xx0Device *, void *),
                    308:        void *arg)
1.1.1.9   root      309: {
1.1.1.13  root      310:        fline_callback = callback;
                    311:        fline_arg = arg;
1.1.1.9   root      312: }
                    313: 
1.1.1.13  root      314: #define FA(val, bit)   TA::OnOff((val) & M88100::bit)
1.1.1.10  root      315: 
1.1       root      316: // モニター更新
1.1.1.3   root      317: void
1.1.1.8   root      318: MPU88xx0Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      319: {
1.1.1.13  root      320:        m88100reg tmp;
1.1       root      321:        int x;
                    322:        int y;
                    323: 
1.1.1.8   root      324:        screen.Clear();
1.1       root      325: 
                    326:        // ローカルにコピー
1.1.1.13  root      327:        tmp = reg;
1.1       root      328: 
1.1.1.15  root      329:        // 汎用レジスタ
                    330:        for (uint i = 0; i < countof(reg.r); i++) {
                    331:                screen.Print((i / 8) * 14, i % 8, "r%-2u:%08x", i, tmp.r[i]);
                    332:        }
                    333: 
                    334:        // 制御レジスタ (上段右)
                    335:        x = 57;
                    336:        y = 0;
                    337:        for (int i = 0; i < 4; i++) {
                    338:                int rn = 17 + i;
                    339:                screen.Print(x, y++, "sr%u(cr%u):%08x", i, rn, tmp.cr[rn]);
1.1       root      340:        }
1.1.1.15  root      341:        screen.Print(x, y++, "ssbr(cr3):%08x", tmp.ssbr);
                    342:        for (int i = 0; i < 3; i++) {
                    343:                screen.Print(x, y++, "%s(cr%u):%08x:%c%c",
                    344:                        m88100reg::sipname[i], 4 + i,
                    345:                        (tmp.cr[4 + i] & M88100::SIP_MASK),
                    346:                        (tmp.cr[4 + i] & M88100::SIP_V) ? 'V' : '-',
                    347:                        (tmp.cr[4 + i] & M88100::SIP_E) ? 'E' : '-');
                    348:        }
                    349:        screen.Print(x, y++, "vbr (cr7):%08x", tmp.vbr);
1.1       root      350: 
1.1.1.15  root      351:        // 制御レジスタ(中段上; *IP)
1.1       root      352:        x = 0;
                    353:        y = 9;
1.1.1.15  root      354:        screen.Print(x, y++, "xip:%08x (op:%08x:%c)",
                    355:                tmp.xip, (uint32)tmp.opX, OpIsBusErr(tmp.opX) ? 'B' : '-');
                    356:        screen.Print(x, y++, "nip:%08x (op:%08x:%c)",
                    357:                tmp.nip, (uint32)tmp.opF, OpIsBusErr(tmp.opF) ? 'B' : '-');
                    358:        screen.Print(x, y++, "fip:%08x", tmp.fip);
                    359: 
                    360:        // 制御レジスタ 中段上; pid,*psr)
                    361:        x = 30;
                    362:        y = 9;
                    363:        screen.Print(x, y++,  "pid(cr0):%08x(Arch=$%02x Ver=$%02x MC=%s)",
1.1.1.13  root      364:                tmp.pid,
                    365:                (tmp.pid >> 8) & 0xff,
                    366:                (tmp.pid >> 1) & 0x7f,
                    367:                (tmp.pid & 1) ? "Master" : "Checker");
1.1.1.15  root      368:        screen.Print(x, y, "psr(cr1):%08x(", tmp.psr);
                    369:        x--;
1.1.1.13  root      370:        screen.Puts(x + 19, y, FA(tmp.psr,  PSR_SUPER), "S");
1.1.1.15  root      371:        screen.Puts(x + 21, y, ((tmp.psr & M88100::PSR_BO_LE) ? "LE" : "BE"));
                    372:        screen.Puts(x + 24, y, FA(tmp.psr,  PSR_SER),  "SER");
                    373:        screen.Puts(x + 28, y, FA(tmp.psr,  PSR_C),    "Cy");
                    374:        screen.Puts(x + 31, y, FA(tmp.psr,  PSR_SFD1), "SFD1");
                    375:        screen.Puts(x + 36, y, FA(tmp.psr,  PSR_MXM),  "MXM");
                    376:        screen.Puts(x + 40, y, FA(tmp.psr,  PSR_IND),  "IND");
                    377:        screen.Puts(x + 44, y, FA(tmp.psr,  PSR_SFRZ), "SFRZ");
                    378:        screen.Puts(x + 48, y, ")");
1.1.1.2   root      379:        y++;
1.1.1.13  root      380:        screen.Print(x, y, "epsr(cr2):%08x(", tmp.epsr);
                    381:        screen.Puts(x + 19, y, FA(tmp.epsr, PSR_SUPER), "S");
1.1.1.15  root      382:        screen.Puts(x + 21, y, ((tmp.epsr& M88100::PSR_BO_LE) ? "LE" : "BE"));
                    383:        screen.Puts(x + 24, y, FA(tmp.epsr, PSR_SER),  "SER");
                    384:        screen.Puts(x + 28, y, FA(tmp.epsr, PSR_C),    "Cy");
                    385:        screen.Puts(x + 31, y, FA(tmp.epsr, PSR_SFD1), "SFD1");
                    386:        screen.Puts(x + 36, y, FA(tmp.epsr, PSR_MXM),  "MXM");
                    387:        screen.Puts(x + 40, y, FA(tmp.epsr, PSR_IND),  "IND");
                    388:        screen.Puts(x + 44, y, FA(tmp.epsr, PSR_SFRZ), "SFRZ");
                    389:        screen.Puts(x + 48, y, ")");
1.1       root      390: 
1.1.1.15  root      391:        // MMU レジスタ(中段下)
1.1       root      392:        y = 12;
1.1.1.15  root      393:        for (uint i = 0; i <= 2; i++) {
                    394:                uint dt =  8 + i * 3;
                    395:                uint dd =  9 + i * 3;
                    396:                uint da = 10 + i * 3;
1.1.1.2   root      397: 
1.1.1.15  root      398:                // DMT は "cr8 " があるので左揃え
                    399:                screen.Print(0, y, "dmt%u(cr%-2u):%04x",
1.1.1.13  root      400:                        i, dt, (tmp.cr[dt] & 0xffff));
1.1.1.8   root      401:                screen.Puts(15, y, "(b,s,d,l,rx, s,en  ,w,v)");
1.1.1.13  root      402:                screen.Puts(16, y, (tmp.cr[dt] & M88100::DM_BO)     ? "B" : "-");
                    403:                screen.Puts(18, y, (tmp.cr[dt] & M88100::DM_DAS)    ? "S" : "U");
                    404:                screen.Puts(20, y, (tmp.cr[dt] & M88100::DM_DOUB1)  ? "D" : "-");
                    405:                screen.Puts(22, y, (tmp.cr[dt] & M88100::DM_LOCK)   ? "L" : "-");
1.1.1.2   root      406:                // カンマが自然に見えるようにここだけカンマも含めて前詰めで出力
1.1.1.15  root      407:                screen.Print(25, y, "%u,",
1.1.1.13  root      408:                        (tmp.cr[dt] & M88100::DM_DREG_MASK) >> 7);
                    409:                screen.Puts(28, y, (tmp.cr[dt] & M88100::DM_SIGNED) ? "S" : "-");
                    410:                uint32 en = (tmp.cr[dt] & M88100::DM_EN_MASK) >> 2;
1.1.1.8   root      411:                screen.Puts(30, y, m88100reg::dmt_en_str[en]);
1.1.1.13  root      412:                screen.Puts(35, y, (tmp.cr[dt] & M88100::DM_WRITE)  ? "W" : "-");
                    413:                screen.Puts(37, y, (tmp.cr[dt] & M88100::DM_VALID)  ? "V" : "-");
1.1.1.2   root      414: 
1.1.1.15  root      415:                // DMD は "cr9 " があるので左揃え
                    416:                screen.Print(40, y, "dmd%u(cr%-2u):%08x", i, dd, tmp.cr[dd]);
                    417:                screen.Print(60, y, "dma%u(cr%2u):%08x",  i, da, tmp.cr[da]);
1.1.1.2   root      418:                y++;
                    419:        }
1.1.1.10  root      420:        y++;
                    421: 
                    422:        // FPU レジスタ (下段)
1.1.1.13  root      423:        screen.Print(0, y, "fpecr(fcr0):%08x(", tmp.fpecr);
1.1.1.10  root      424:        x = 21;
1.1.1.13  root      425:        screen.Puts(x +  0, y, FA(tmp.fpecr, FPECR_FIOV),       "FIOV");
                    426:        screen.Puts(x +  5, y, FA(tmp.fpecr, FPECR_FUNIMP),     "FUNIMP");
                    427:        screen.Puts(x + 12, y, FA(tmp.fpecr, FPECR_FPRV),       "FPRV");
                    428:        screen.Puts(x + 17, y, FA(tmp.fpecr, FPECR_FROP),       "FROP");
                    429:        screen.Puts(x + 22, y, FA(tmp.fpecr, FPECR_FDVZ),       "FDVZ");
                    430:        screen.Puts(x + 27, y, FA(tmp.fpecr, FPECR_FUNF),       "FUNF");
                    431:        screen.Puts(x + 32, y, FA(tmp.fpecr, FPECR_FOVF),       "FOVF");
                    432:        screen.Puts(x + 37, y, FA(tmp.fpecr, FPECR_FINX),       "FINX");
1.1.1.10  root      433:        screen.Puts(x + 41, y, ")");
                    434:        y++;
                    435: 
1.1.1.19! root      436:        char tsiz[4] = { 's', 'd', '2', '3' };
1.1.1.10  root      437:        screen.Print(0, y++,
1.1.1.19! root      438:                "fppt(fcr5): %08x(OpCode=%%%c%c%c%c%c T1=%c T2=%c TD=%c Dest=r%u)",
1.1.1.13  root      439:                tmp.fppt,
                    440:                ((tmp.fppt >> 15) & 1) + '0',
                    441:                ((tmp.fppt >> 14) & 1) + '0',
                    442:                ((tmp.fppt >> 13) & 1) + '0',
                    443:                ((tmp.fppt >> 12) & 1) + '0',
                    444:                ((tmp.fppt >> 11) & 1) + '0',
1.1.1.19! root      445:                tsiz[(tmp.fppt >> 9) & 3],
        !           446:                tsiz[(tmp.fppt >> 7) & 3],
        !           447:                tsiz[(tmp.fppt >> 5) & 3],
1.1.1.13  root      448:                (tmp.fppt & M88100::FPPT_DEST));
1.1.1.10  root      449: 
1.1.1.19! root      450:        for (uint i = 0; i < 2; i++) {
        !           451:                uint32 hs;
        !           452:                uint32 ls;
        !           453:                bool isfloat;
        !           454:                if (i == 0) {
        !           455:                        hs = tmp.fphs1;
        !           456:                        ls = tmp.fpls1;
        !           457:                        isfloat = (tmp.fppt & 0x600) == 0;
        !           458:                } else {
        !           459:                        hs = tmp.fphs2;
        !           460:                        ls = tmp.fpls2;
        !           461:                        isfloat = (tmp.fppt & 0x180) == 0;
        !           462:                }
        !           463:                uint n = i * 2;
        !           464:                screen.Print(0, y, "fphs%u(fcr%u)/fpls%u(fcr%u): %08x'%08x =",
        !           465:                        (i + 1), (n + 1), (i + 1), (n + 2), hs, ls);
        !           466:                int32 e = ((int32)(hs << 1)) >> 21;
        !           467:                screen.Print(45, y, "%c0.%05x'",
        !           468:                        ((hs & 0x80000000) ? '-' : '+'),
        !           469:                        (hs & 0x000f'ffff));
        !           470:                if (isfloat) {
        !           471:                        screen.Print(45 + 9,  y, "%1x", (ls >> 28) & 0xf);
        !           472:                        screen.Print(45 + 10, y, TA::Disable, "%07x", (ls & 0x0fff'ffff));
        !           473:                        screen.Print(45 + 18, y, "e%+d", e);
        !           474:                } else {
        !           475:                        screen.Print(45 + 9, y, "%08x e%+d", ls, e);
        !           476:                }
        !           477:                y++;
        !           478:        }
1.1.1.10  root      479: 
                    480:        screen.Print(0, y, "fprh(fcr6) /fprl(fcr7):  %08x'%08x(",
1.1.1.13  root      481:                tmp.fprh, tmp.fprl);
1.1.1.10  root      482:        x = 43;
1.1.1.13  root      483:        screen.Puts(x + 0, y, FA(tmp.fprh, FPRH_ADDONE), "ADDONE");
                    484:        screen.Print(x + 7, y, "RM=%s)", rmstr[(tmp.fprh >> 29) & 3]);
1.1.1.10  root      485:        y++;
                    486: 
                    487:        x = 21;
1.1.1.15  root      488:        screen.Print(0, y, "fpit(fcr8): %08x(OpCode=%%%c%c%c%c%c TD=%u",
1.1.1.13  root      489:                tmp.fpit,
                    490:                ((tmp.fpit >> 15) & 1) + '0',
                    491:                ((tmp.fpit >> 14) & 1) + '0',
                    492:                ((tmp.fpit >> 13) & 1) + '0',
                    493:                ((tmp.fpit >> 12) & 1) + '0',
                    494:                ((tmp.fpit >> 11) & 1) + '0',
                    495:                ((tmp.fpit >> 10) & 1));
                    496:        screen.Puts(x + 19, y, FA(tmp.fpit, FPIT_EFINV), "EINV");
                    497:        screen.Puts(x + 24, y, FA(tmp.fpit, FPIT_EFDVZ), "EDVZ");
                    498:        screen.Puts(x + 29, y, FA(tmp.fpit, FPIT_EFUNF), "EUNF");
                    499:        screen.Puts(x + 34, y, FA(tmp.fpit, FPIT_EFOVF), "EOVF");
                    500:        screen.Puts(x + 39, y, FA(tmp.fpit, FPIT_EFINX), "EINX");
1.1.1.15  root      501:        screen.Print(x + 44, y, "Dest=r%u)", tmp.fpit & M88100::FPIT_DEST);
1.1.1.10  root      502:        y++;
                    503: 
1.1.1.13  root      504:        uint32 sign = (tmp.fprh & M88100::FPRH_SIGN);
                    505:        uint32 exp  = (int32)tmp.fpit >> 20;
                    506:        uint32 mant_h = (tmp.fprh & 0x000fffff);
                    507:        uint32 mant_l = tmp.fprl;
1.1.1.10  root      508:        screen.Print(12, y, "result: %c%1x.%05x'%08x'grs e%+d",
                    509:                (sign ? '-' : '+'),
1.1.1.13  root      510:                ((tmp.fprh >> 20) & 1),
1.1.1.10  root      511:                mant_h,
                    512:                mant_l,
                    513:                exp - 0x3ff);
1.1.1.13  root      514:        screen.Puts(38, y, FA(tmp.fprh, FPRH_GUARD),  "G");
                    515:        screen.Puts(39, y, FA(tmp.fprh, FPRH_ROUND),  "R");
                    516:        screen.Puts(40, y, FA(tmp.fprh, FPRH_STICKY), "S");
1.1.1.10  root      517:        screen.Print(48, y, "($%03x)", exp & 0x7ff);
                    518:        // Inf と NAN はこの形式だけからでは分かりづらいので別途追加で表示。
                    519:        // exp は符号拡張しているので指数部 $7ff は exp == -1。
                    520:        if (exp == 0xffffffff) {
                    521:                x = 55;
                    522:                if ((mant_h | mant_l) == 0) {
                    523:                        if (sign == 0) {
                    524:                                screen.Puts(x, y, "= +Inf");
                    525:                        } else {
                    526:                                screen.Puts(x, y, "= -Inf");
                    527:                        }
                    528:                } else {
                    529:                        if (sign == 0) {
                    530:                                screen.Puts(x, y, "= +NAN");
                    531:                        } else {
                    532:                                screen.Puts(x, y, "= -NAN");
                    533:                        }
                    534:                }
                    535:        }
                    536:        y++;
                    537: 
1.1.1.13  root      538:        screen.Print(0, y, "fpsr(fcr62):%08x(", tmp.fpsr);
1.1.1.10  root      539:        x = 21;
1.1.1.13  root      540:        screen.Puts(x +  0, y, FA(tmp.fpsr, FPSR_AFINV), "AFINV");
                    541:        screen.Puts(x +  6, y, FA(tmp.fpsr, FPSR_AFDVZ), "AFDVZ");
                    542:        screen.Puts(x + 12, y, FA(tmp.fpsr, FPSR_AFUNF), "AFUNF");
                    543:        screen.Puts(x + 18, y, FA(tmp.fpsr, FPSR_AFOVF), "AFOVF");
                    544:        screen.Puts(x + 24, y, FA(tmp.fpsr, FPSR_AFINX), "AFINX");
1.1.1.10  root      545:        screen.Puts(x + 29, y, ")");
                    546:        y++;
                    547: 
1.1.1.13  root      548:        screen.Print(0, y, "fpcr(fcr63):%08x(", tmp.fpcr);
                    549:        screen.Puts(x +  0, y, FA(tmp.fpcr, FPCR_EFINV), "EFINV");
                    550:        screen.Puts(x +  6, y, FA(tmp.fpcr, FPCR_EFDVZ), "EFDVZ");
                    551:        screen.Puts(x + 12, y, FA(tmp.fpcr, FPCR_EFUNF), "EFUNF");
                    552:        screen.Puts(x + 18, y, FA(tmp.fpcr, FPCR_EFOVF), "EFOVF");
                    553:        screen.Puts(x + 24, y, FA(tmp.fpcr, FPCR_EFINX), "EFINX");
                    554:        screen.Print(x + 30, y, "RM=%s)", rmstr[(tmp.fpcr >> 14) & 3]);
1.1       root      555: }

unix.superglobalmegacorp.com

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