Annotation of nono/vm/mpu680x0.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: 
1.1.1.13! root        7: //
        !             8: // MPU (MC68030)
        !             9: //
1.1       root       10: 
                     11: #include "mpu680x0.h"
                     12: #include "config.h"
1.1.1.13! root       13: #include "debugger.h"
        !            14: #include "debugger_private.h"
1.1.1.10  root       15: #include "m68030bus.h"
1.1.1.2   root       16: #include "m68030excep.h"
1.1       root       17: #include "mainapp.h"
1.1.1.13! root       18: #include "scheduler.h"
        !            19: #include "sync.h"
1.1.1.10  root       20: #include "uimessage.h"
1.1       root       21: #include "vm.h"
1.1.1.13! root       22: #include <cmath>
        !            23: 
        !            24: static void mpu680x0_reset_inst(void *);
        !            25: static void mpu680x0_halt(void *);
1.1       root       26: 
                     27: // コンストラクタ
1.1.1.8   root       28: MPU680x0Device::MPU680x0Device()
1.1.1.9   root       29:        : inherited("MPU(68030)")
1.1       root       30: {
1.1.1.13! root       31:        cpu = m68030_init(this);
1.1       root       32: 
1.1.1.13! root       33:        // 割り込みイベントコールバック設定
        !            34:        intr_event.func = ToEventCallback(&MPU680x0Device::InterruptCallback);
        !            35:        intr_event.Regist("MPU Interrupt");
1.1.1.4   root       36: 
1.1.1.9   root       37:        // レジスタモニター
1.1.1.13! root       38:        reg_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateReg);
1.1.1.9   root       39:        reg_monitor.SetSize(79, 16);
                     40:        reg_monitor.Regist(ID_MONITOR_MPUREG);
                     41: 
                     42:        // ATC モニター
1.1.1.13! root       43:        atc_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateATC);
1.1.1.9   root       44: #if !defined(ATC_SINGLE)
                     45:        atc_monitor.SetSize(131, m68030ATCTable::LINES + 3);
                     46: #else
                     47:        atc_monitor.SetSize(31, 24);
                     48: #endif
                     49:        atc_monitor.Regist(ID_MONITOR_MPUATC);
1.1.1.13! root       50: 
        !            51:        SetTrace(false);
1.1       root       52: }
                     53: 
                     54: // デストラクタ
                     55: MPU680x0Device::~MPU680x0Device()
                     56: {
                     57: }
                     58: 
                     59: bool
                     60: MPU680x0Device::Init()
                     61: {
1.1.1.5   root       62:        // 親クラス
                     63:        if (inherited::Init() == false) {
                     64:                return false;
                     65:        }
1.1.1.13! root       66: 
        !            67:        // 割り込み時のディレイ。
        !            68:        //
        !            69:        // 外部デバイスが 68030 の IPL0-2 をアサートしてから、68030 がそれを
        !            70:        // 認識(確定)するのに 1 ~ 2 クロックかかる。
        !            71:        // その後レベルを比較するのは次のアップエッジ。
        !            72:        // その後 /IPEND をアサートするのはその次のアップエッジ。
        !            73:        // 合わせると、IPL0-2 が変化してから /IPEND がアサートされるまでは
        !            74:        // 2 ~ 3 クロックかかる。(Figure 8-4)
        !            75:        intr_event.time = 3 * clock_nsec;
1.1.1.5   root       76: 
1.1       root       77:        // FPU (6888x)
1.1.1.2   root       78:        if (gMainApp.GetVMType() == VMTYPE_LUNA1) {
1.1       root       79:                // LUNA は 68881 固定 (設定は見ない)
                     80:                cpu->has_fpu = 1;
                     81:        } else {
                     82:                // X68k は設定による
1.1.1.2   root       83:                const ConfigItem& item = gConfig->Find("mpu-has-fpu");
1.1       root       84:                cpu->has_fpu = item.AsInt();
                     85:                if (cpu->has_fpu < 0 || cpu->has_fpu > 2) {
                     86:                        item.Err();
                     87:                        return false;
                     88:                }
                     89:        }
                     90: 
1.1.1.13! root       91:        cpu->resetop_callback = mpu680x0_reset_inst;
        !            92:        cpu->resetop_arg = NULL;
        !            93:        cpu->halt_callback = mpu680x0_halt;
        !            94:        cpu->halt_arg = this;
1.1.1.10  root       95: 
1.1       root       96:        return true;
                     97: }
                     98: 
1.1.1.13! root       99: // リセット
        !           100: void
        !           101: MPU680x0Device::ResetHard(bool poweron)
1.1.1.8   root      102: {
1.1.1.13! root      103:        if (poweron) {
        !           104:                m68030_power_on(cpu);
        !           105:        }
        !           106: 
        !           107:        // リセット例外を 520 クロック後に起こす。
        !           108:        // 520 は、電源オン時、Vcc が最小動作規定値に達してから最低 520 クロック
        !           109:        // の間アサートしなければならないという値であって、実際これだけかかる
        !           110:        // とかいう値ではない。が、こちら側の都合で、この後実行される RAM の
        !           111:        // ResetHard() がブートページを用意した後で m68030_exception_reset() で
        !           112:        // SP, PC をフェッチするという順序にしないといけないため、リセット例外が
        !           113:        // 起動するまでに時間がかかるというところを都合よく真似ておく。
        !           114: 
        !           115:        exec_event.func = ToEventCallback(&MPU680x0Device::ResetCallback);
        !           116:        exec_event.time = 520 * clock_nsec;
        !           117:        exec_event.SetName("MPU Reset");
        !           118:        gScheduler->RestartEvent(exec_event);
1.1.1.8   root      119: }
                    120: 
1.1.1.13! root      121: // リセット例外コールバック。
        !           122: // MPU リセットから規定時間後に呼ばれる。
1.1.1.8   root      123: void
1.1.1.13! root      124: MPU680x0Device::ResetCallback(Event& ev)
1.1.1.8   root      125: {
1.1.1.13! root      126:        intr_pending = false;
        !           127: 
        !           128:        // リセット例外を実行
        !           129:        int cycle = m68030_exception_reset(cpu);
        !           130: 
        !           131:        // コールバックを ResetCallback から Exec* に差し替える前のここで
        !           132:        // トレース状態を初期化する。
        !           133:        SetTrace(gDebugger->IsTrace());
        !           134: 
        !           135:        // 以降は通常走行。
        !           136:        if (cpu->state == m68kcpu::CPU_STATE_NORMAL) {
        !           137:                exec_event.func = exec_short;
        !           138:                exec_event.time = cycle * clock_nsec;
        !           139:                exec_event.SetName("MPU Execute");
        !           140:                gScheduler->StartEvent(exec_event);
        !           141:        } else {
        !           142:                // リセット例外でダブルバスフォールトならここで停止。
        !           143:        }
1.1.1.8   root      144: }
                    145: 
1.1.1.13! root      146: // 通常の1命令実行のコールバック
        !           147: // 割り込みチェックなどを省いたショート版。
1.1       root      148: void
1.1.1.13! root      149: MPU680x0Device::ExecShort(Event& ev)
1.1       root      150: {
1.1.1.13! root      151:        int cycle = m68030_exec(cpu);
        !           152: 
        !           153:        ev.time = cycle * clock_nsec;
        !           154:        gScheduler->StartEvent(ev);
        !           155: }
        !           156: 
        !           157: // 割り込みチェック、STOP 処理を含んだ完全な実行サイクルのコールバック。
        !           158: // SR の I2:I0 が変わった直後などに呼ばれる。
        !           159: // ここでは割り込みをチェックし、必要なら割り込み処理を起動、
        !           160: // そうでなければ通常の命令実行を行う。
        !           161: void
        !           162: MPU680x0Device::ExecFull(Event& ev)
        !           163: {
        !           164:        if (intr_pending) {
        !           165:                // 割り込み処理を起動。
        !           166: 
        !           167:                intr_pending = false;
        !           168: 
        !           169:                // 前の命令実行後となるここで割り込みを起動
        !           170:                int cycle = m68030_exception_interrupt(cpu);
        !           171: 
        !           172:                ev.time = cycle * clock_nsec;
        !           173:                gScheduler->StartEvent(ev);
        !           174:        } else {
        !           175:                if (cpu->state == m68kcpu::CPU_STATE_NORMAL) {
        !           176:                        // コールバックを通常処理に戻してから...
        !           177:                        exec_event.func = exec_short;
        !           178: 
        !           179:                        // この場で次の命令を実行。
        !           180:                        ExecShort(ev);
        !           181:                } else {
        !           182:                        // STOP ならここで停止。HALT はそもそも来ないはず。
        !           183:                }
        !           184:        }
1.1       root      185: }
                    186: 
1.1.1.13! root      187: // トレース実行
        !           188: void
        !           189: MPU680x0Device::ExecTrace(Event& ev)
1.1       root      190: {
1.1.1.13! root      191:        gDebugger->Exec();
        !           192:        ExecFull(ev);
1.1       root      193: }
                    194: 
1.1.1.13! root      195: // トレース状態を設定する
        !           196: void
        !           197: MPU680x0Device::SetTrace(bool enable)
1.1       root      198: {
1.1.1.13! root      199:        if (enable) {
        !           200:                exec_short = ToEventCallback(&MPU680x0Device::ExecTrace);
        !           201:                exec_full  = ToEventCallback(&MPU680x0Device::ExecTrace);
        !           202:        } else {
        !           203:                exec_short = ToEventCallback(&MPU680x0Device::ExecShort);
        !           204:                exec_full  = ToEventCallback(&MPU680x0Device::ExecFull);
        !           205:        }
        !           206:        exec_event.func = exec_full;
        !           207: 
        !           208:        // STOP 命令中にオンにするには、停止しているイベントを起こす。
        !           209:        // STOP 命令中にオフにする場合は、何もしなくていい。
        !           210:        if (enable && exec_event.IsRunning() == false) {
        !           211:                gScheduler->StartEvent(exec_event);
        !           212:        }
1.1       root      213: }
                    214: 
1.1.1.5   root      215: // 割り込みレベルが変わったことを MPU に通知。
1.1       root      216: void
1.1.1.5   root      217: MPU680x0Device::Interrupt(int level)
1.1       root      218: {
1.1.1.5   root      219:        assertmsg(0 <= level && level <= 7, "level=%d", level);
                    220: 
1.1.1.13! root      221:        intr_event.code = level;
        !           222:        if (intr_event.IsRunning() == false) {
        !           223:                gScheduler->StartEvent(intr_event);
1.1.1.5   root      224:        }
1.1.1.13! root      225: }
        !           226: 
        !           227: // 外部割り込みイベントコールバック。
        !           228: // 割り込みレベルが変わったことをコアに通知する。
        !           229: // ev.code 0-7 は新しい割り込みレベル。
        !           230: void
        !           231: MPU680x0Device::InterruptCallback(Event& ev)
        !           232: {
        !           233:        int level = ev.code;
        !           234: 
        !           235:        if (m68030_interrupt(cpu, level)) {
        !           236:                // 通知した結果割り込みが受け付けられたので、
        !           237:                // この命令終了時のコールバックを割り込み処理起動に差し替える。
        !           238:                MakeNextFull();
        !           239:                intr_pending = true;
        !           240: 
        !           241:                // STOP 状態だったらここでイベントを開始する
        !           242:                if (cpu->state == m68kcpu::CPU_STATE_STOP) {
        !           243:                        // STOP から抜ける時間?
        !           244:                        exec_event.time = 1 * clock_nsec;
        !           245:                        gScheduler->StartEvent(exec_event);
        !           246:                }
        !           247:        }
        !           248: }
        !           249: 
        !           250: // 次の命令境界で割り込みチェックを行う。
        !           251: // (割り込みマスクを変更する命令の実行で呼ばれる)
        !           252: void
        !           253: MPU680x0Device::CheckIntr()
        !           254: {
        !           255:        MakeNextFull();
        !           256:        intr_pending |= m68030_check_interrupt(cpu);
        !           257: }
        !           258: 
        !           259: // 次の命令境界は Full にする。
        !           260: void
        !           261: MPU680x0Device::MakeNextFull()
        !           262: {
        !           263:        exec_event.func = exec_full;
        !           264: }
        !           265: 
        !           266: // コアからの動作変更通知
        !           267: /*static*/ void
        !           268: MPU680x0Device::NotifyCPUMode(uint32 new_mode)
        !           269: {
        !           270:        // new_mode (m68kcpu::CPU_STATE_*) と
        !           271:        // RequestCPUMode() の引数 Sync::SCHED_CPU_* は
        !           272:        // 実は同じ値なのでそのまま渡してよいことにする。
        !           273:        static_assert(m68kcpu::CPU_STATE_NORMAL == Sync::SCHED_CPU_NORMAL, "");
        !           274:        static_assert(m68kcpu::CPU_STATE_STOP   == Sync::SCHED_CPU_STOP,   "");
        !           275:        static_assert(m68kcpu::CPU_STATE_HALT   == Sync::SCHED_CPU_HALT,   "");
        !           276: 
        !           277:        // 通知 (同期のため)
        !           278:        gSync->RequestCPUMode(new_mode);
1.1       root      279: }
                    280: 
                    281: // A-Line 命令エミュレーションのコールバックを指定。
                    282: void
                    283: MPU680x0Device::SetALineCallback(bool (*callback)(m68kcpu *, void*), void *arg)
                    284: {
                    285:        cpu->aline_callback = callback;
                    286:        cpu->aline_arg = arg;
                    287: }
                    288: 
                    289: // F-Line 命令エミュレーションのコールバックを指定。
                    290: void
                    291: MPU680x0Device::SetFLineCallback(bool (*callback)(m68kcpu *, void*), void *arg)
                    292: {
                    293:        cpu->fline_callback = callback;
                    294:        cpu->fline_arg = arg;
                    295: }
                    296: 
1.1.1.13! root      297: // RESET 命令の CPU からのコールバック関数
        !           298: static void
        !           299: mpu680x0_reset_inst(void *arg)
1.1.1.10  root      300: {
1.1.1.13! root      301:        gVM->ResetByMPU();
        !           302: }
        !           303: 
        !           304: // ホールト時の CPU からのコールバック関数
        !           305: static void
        !           306: mpu680x0_halt(void *arg)
        !           307: {
        !           308:        ((MPU680x0Device *)arg)->Halt();
        !           309: }
        !           310: 
        !           311: // ホールト状態
        !           312: void
        !           313: MPU680x0Device::Halt()
        !           314: {
        !           315:        // 動作停止
        !           316:        gScheduler->StopEvent(exec_event);
        !           317: 
        !           318:        // UI に通知 (メッセージボックス表示とか)
1.1.1.10  root      319:        UIMessage::Post(UIMessage::HALT);
                    320: }
                    321: 
                    322: // MPU からのアクセスをエミュレート
                    323: uint64
                    324: MPU680x0Device::Read8(uint32 addr)
                    325: {
                    326:        try {
                    327:                return m68030_read_8(cpu, addr);
                    328:        } catch (...) {
                    329:                return (uint64)-1;
                    330:        }
                    331: }
                    332: 
                    333: uint64
                    334: MPU680x0Device::Read16(uint32 addr)
                    335: {
                    336:        try {
                    337:                return m68030_read_16(cpu, addr);
                    338:        } catch (...) {
                    339:                return (uint64)-1;
                    340:        }
                    341: }
                    342: 
                    343: uint64
                    344: MPU680x0Device::Read32(uint32 addr)
1.1.1.2   root      345: {
1.1.1.10  root      346:        try {
                    347:                return m68030_read_32(cpu, addr);
                    348:        } catch (...) {
                    349:                return (uint64)-1;
                    350:        }
                    351: }
                    352: 
                    353: uint64
                    354: MPU680x0Device::Write8(uint32 addr, uint32 data)
                    355: {
                    356:        try {
                    357:                m68030_write_8(cpu, addr, data);
                    358:                return 0;
                    359:        } catch (...) {
                    360:                return (uint64)-1;
                    361:        }
                    362: }
                    363: 
                    364: uint64
                    365: MPU680x0Device::Write16(uint32 addr, uint32 data)
                    366: {
                    367:        try {
                    368:                m68030_write_16(cpu, addr, data);
                    369:                return 0;
                    370:        } catch (...) {
                    371:                return (uint64)-1;
                    372:        }
                    373: }
                    374: 
                    375: uint64
                    376: MPU680x0Device::Write32(uint32 addr, uint32 data)
                    377: {
                    378:        try {
                    379:                m68030_write_32(cpu, addr, data);
                    380:                return 0;
                    381:        } catch (...) {
                    382:                return (uint64)-1;
                    383:        }
1.1.1.2   root      384: }
                    385: 
1.1       root      386: // モニター更新 (レジスタウィンドウ)
1.1.1.3   root      387: void
1.1.1.9   root      388: MPU680x0Device::MonitorUpdateReg(Monitor *, TextScreen& screen)
1.1       root      389: {
                    390:        m68kreg reg;
                    391:        uint32 ppc;
1.1.1.13! root      392:        uint32 state;
1.1       root      393:        int x;
                    394:        int y;
                    395: 
1.1.1.9   root      396:        screen.Clear();
1.1       root      397: 
                    398:        // ローカルにコピー
1.1.1.13! root      399:        // ただし一部は reg ではなく cpu クラス本体にある
1.1       root      400:        reg = cpu->reg;
                    401:        ppc = cpu->ppc;
1.1.1.13! root      402:        state = cpu->state;
1.1       root      403: 
                    404:        // データレジスタ、アドレスレジスタ
                    405:        for (int i = 0; i < 4; i++) {
1.1.1.9   root      406:                screen.Print(0, i, "D%d:%08x D%d:%08x  A%d:%08x A%d:%08x",
1.1       root      407:                        i + 0, reg.da[i],
                    408:                        i + 4, reg.da[i + 4],
                    409:                        i + 0, reg.da[i + 8],
                    410:                        i + 4, reg.da[i + 12]);
                    411:        }
                    412: 
                    413:        // 5列目
                    414:        x = 50;
                    415:        // SR
1.1.1.9   root      416:        screen.Print(x, 0, "SR:%04x(%c%c%c%c%c)",
1.1       root      417:                (reg.sr_h() | reg.ccr.Get()),
                    418:                (reg.ccr.IsX()) ? 'X' : '-',
                    419:                (reg.ccr.IsN()) ? 'N' : '-',
                    420:                (reg.ccr.IsZ()) ? 'Z' : '-',
                    421:                (reg.ccr.IsV()) ? 'V' : '-',
                    422:                (reg.ccr.IsC()) ? 'C' : '-');
                    423: 
                    424:        // VBR
1.1.1.9   root      425:        screen.Print(x, 1, "VBR:%08x", reg.vbr);
1.1       root      426: 
                    427:        // *SP
                    428:        uint ms = (reg.s ? 2 : 0) | (reg.m ? 1 : 0); // T1 T0 S M
                    429:        if (ms == 3) {
                    430:                // Supervisor (Master) mode (A7=MSP, USP/ISP)
1.1.1.9   root      431:                screen.Print(x, 2, TA::Disable, "USP:%08x", reg.usp);
                    432:                screen.Print(x, 3, TA::Disable, "ISP:%08x", reg.isp);
1.1       root      433:        } else if (ms == 2) {
                    434:                // Supervisor (Interrupt) mode (A7=ISP, USP/MSP)
1.1.1.9   root      435:                screen.Print(x, 2, TA::Disable, "USP:%08x", reg.usp);
                    436:                screen.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp);
1.1       root      437:        } else {
                    438:                // User mode (A7=USP, ISP/MSP)
1.1.1.9   root      439:                screen.Print(x, 2, TA::Disable, "ISP:%08x", reg.isp);
                    440:                screen.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp);
1.1       root      441:        }
                    442: 
                    443:        // 6列目
                    444:        // PC:  01234567
                    445:        // SFC:1   DFC:1
                    446:        // CACR:01234567
                    447:        // CAAR:01234567
                    448:        x = 66;
1.1.1.9   root      449:        screen.Print(x, 0, "PC:  %08x", ppc);
                    450:        screen.Print(x, 1, "SFC:%d  DFC:%d", reg.sfc, reg.dfc);
                    451:        screen.Print(x, 2, "CACR:%08x", reg.cacr);
                    452:        screen.Print(x, 3, "CAAR:%08x", reg.caar);
1.1       root      453: 
                    454:        // XXX どこに置くのがいいか
1.1.1.13! root      455:        switch (state) {
        !           456:         case m68kcpu::CPU_STATE_NORMAL:
1.1.1.9   root      457:                screen.Puts(25, 4, "State: Running");
1.1.1.13! root      458:                break;
        !           459:         case m68kcpu::CPU_STATE_STOP:
1.1.1.9   root      460:                screen.Puts(25, 4, "State: STOP instruction");
1.1.1.13! root      461:                break;
        !           462:         case m68kcpu::CPU_STATE_HALT:
1.1.1.9   root      463:                screen.Puts(25, 4, TA::On, "State: Double Bus Fault");
1.1.1.13! root      464:                break;
        !           465:         default:
        !           466:                __unreachable();
1.1       root      467:        }
                    468: 
                    469:        // MMU
                    470:        x = 0;
                    471:        y = 4;
1.1.1.9   root      472:        screen.Puts(x, y++, "<MMU>");
                    473:        screen.Print(x, y,     "SRP:%08x_%08x", reg.srp.h, reg.srp.l);
                    474:        screen.Print(x, y + 1, "CRP:%08x_%08x", reg.crp.h, reg.crp.l);
1.1       root      475:        x += 23;
                    476:        for (int i = 0; i < 2; i++) {
                    477:                uint32 tt = reg.tt[i];
1.1.1.9   root      478:                screen.Print(x, y + i, "TT%d:%08x(%c%c%c)",
1.1       root      479:                        i, tt,
                    480:                        (tt & m68030TT::E)   ? 'E' : '-',
                    481:                        (tt & m68030TT::CI)  ? 'C' : '-',
                    482:                        (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW)  ? 'R' : 'W'));
                    483:        }
                    484:        x += 19;
1.1.1.9   root      485:        screen.Print(x, y, "TC:%08x(%c%c%c)",
1.1       root      486:                reg.tc,
                    487:                (reg.tc & m68030TC::TC_E)   ? 'E' : '-',
                    488:                (reg.tc & m68030TC::TC_SRE) ? 'S' : '-',
                    489:                (reg.tc & m68030TC::TC_FCL) ? 'F' : '-');
1.1.1.9   root      490:        screen.Print(x, y + 1, "MMUSR: %04x(%c%c%c%c%c%c%c N=%d)",
1.1       root      491:                reg.mmusr,
                    492:                (reg.mmusr & m68030MMUSR::B) ? 'B' : '-',
                    493:                (reg.mmusr & m68030MMUSR::L) ? 'L' : '-',
                    494:                (reg.mmusr & m68030MMUSR::S) ? 'S' : '-',
                    495:                (reg.mmusr & m68030MMUSR::W) ? 'W' : '-',
                    496:                (reg.mmusr & m68030MMUSR::I) ? 'I' : '-',
                    497:                (reg.mmusr & m68030MMUSR::M) ? 'M' : '-',
                    498:                (reg.mmusr & m68030MMUSR::T) ? 'T' : '-',
                    499:                (reg.mmusr & m68030MMUSR::N));
                    500: 
                    501:        // FPU
                    502:        x = 0;
                    503:        y = 7;
1.1.1.9   root      504:        screen.Puts(x, y++, "<FPU>");
1.1       root      505:        for (int i = 0; i < 8; i++) {
1.1.1.9   root      506:                screen.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)",
1.1       root      507:                        i,
                    508:                        reg.fpframe.fpf_regs[i * 3 + 0] >> 16,
                    509:                        reg.fpframe.fpf_regs[i * 3 + 1],
                    510:                        reg.fpframe.fpf_regs[i * 3 + 2],
                    511:                        "not yet");
                    512:        }
                    513: 
                    514:        x = 51;
                    515: 
                    516:        // FPCR
                    517:        static const char * const rpstr[] = {
                    518:                ".EXT",
                    519:                ".SGL",
                    520:                ".DBL",
                    521:                ".???",
                    522:        };
                    523:        uint32 fpcr = reg.fpframe.fpf_fpcr;
1.1.1.9   root      524:        screen.Print(x, y++, "FPCR:%04x", fpcr);
1.1.1.11  root      525:        screen.Puts(x +  2, y, TA::OnOff(fpcr & 0x8000), "BS");
                    526:        screen.Puts(x +  5, y, TA::OnOff(fpcr & 0x4000), "SN");
                    527:        screen.Puts(x +  8, y, TA::OnOff(fpcr & 0x2000), "OP");
                    528:        screen.Puts(x + 11, y, TA::OnOff(fpcr & 0x1000), "OV");
                    529:        screen.Puts(x + 14, y, TA::OnOff(fpcr & 0x0800), "UF");
                    530:        screen.Puts(x + 17, y, TA::OnOff(fpcr & 0x0400), "DZ");
                    531:        screen.Puts(x + 20, y, TA::OnOff(fpcr & 0x0200), "I2");
                    532:        screen.Puts(x + 23, y, TA::OnOff(fpcr & 0x0100), "I1");
                    533:        y++;
1.1.1.9   root      534:        screen.Print(x + 2, y++, "RP=%s RM=%s",
1.1       root      535:                rpstr[(fpcr >> 6) & 3],
                    536:                rmstr[(fpcr >> 4) & 3]);
                    537: 
                    538:        // FPSR
                    539:        uint32 fpsr = reg.fpframe.fpf_fpsr;
                    540:        uint32 cc = fpsr >> 24;
1.1.1.9   root      541:        screen.Print(x, y++, "FPSR:%08x", fpsr);
1.1.1.11  root      542:        screen.Puts(x +  2, y, TA::OnOff(cc & 0x08), "N");
                    543:        screen.Puts(x +  4, y, TA::OnOff(cc & 0x04), "Z");
                    544:        screen.Puts(x +  6, y, TA::OnOff(cc & 0x02), "Inf");
                    545:        screen.Puts(x + 10, y, TA::OnOff(cc & 0x01), "NAN");
                    546:        screen.Print(x + 14, y, "Q=$%02x", (fpsr >> 16) & 0xff);
                    547:        y++;
                    548:        screen.Puts(x +  2, y, TA::OnOff(fpsr & 0x8000), "BS");
                    549:        screen.Puts(x +  5, y, TA::OnOff(fpsr & 0x4000), "SN");
                    550:        screen.Puts(x +  8, y, TA::OnOff(fpsr & 0x2000), "OP");
                    551:        screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x1000), "OV");
                    552:        screen.Puts(x + 14, y, TA::OnOff(fpsr & 0x0800), "UF");
                    553:        screen.Puts(x + 17, y, TA::OnOff(fpsr & 0x0400), "DZ");
                    554:        screen.Puts(x + 20, y, TA::OnOff(fpsr & 0x0200), "I2");
                    555:        screen.Puts(x + 23, y, TA::OnOff(fpsr & 0x0100), "I1");
                    556:        y++;
                    557:        screen.Puts(x +  2, y, TA::OnOff(fpsr & 0x80), "IOP");
                    558:        screen.Puts(x +  6, y, TA::OnOff(fpsr & 0x80), "OVFL");
                    559:        screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x80), "UNFL");
                    560:        screen.Puts(x + 16, y, TA::OnOff(fpsr & 0x80), "DZ");
                    561:        screen.Puts(x + 19, y, TA::OnOff(fpsr & 0x80), "INEX");
                    562:        y++;
1.1       root      563: 
                    564:        // FPIAR
1.1.1.9   root      565:        screen.Print(x, y++, "FPIAR:%08x", reg.fpframe.fpf_fpiar);
1.1       root      566: }
                    567: 
1.1.1.9   root      568: // モニター更新 (ATC)
1.1.1.3   root      569: void
1.1.1.9   root      570: MPU680x0Device::MonitorUpdateATC(Monitor *, TextScreen& screen)
1.1       root      571: {
                    572:        m68030ATCTable *table;
                    573: #if !defined(ATC_SINGLE)
                    574:        struct {
                    575:                int fc;
                    576:                const char *name;
                    577:        } fclist[] = {
                    578:                { 1,    "User/Data" },
                    579:                { 2,    "User/Program" },
                    580:                { 5,    "Super/Data" },
                    581:                { 6,    "Super/Program" },
                    582:        };
                    583: 
1.1.1.9   root      584:        screen.Clear();
1.1       root      585: 
                    586:        // 行数は左端にだけ
                    587:        for (int i = 0; i < m68030ATCTable::LINES; i++) {
1.1.1.9   root      588:                screen.Print(0, i + 2, "%02d:", i);
1.1       root      589:        }
                    590: 
                    591:        for (int t = 0; t < countof(fclist); t++) {
                    592:                int x = t * 32 + 4;
                    593:                int fc = fclist[t].fc;
                    594:                const char *name = fclist[t].name;
                    595:                double r;
                    596:                int i;
                    597: 
                    598:                table = &cpu->atc.tables[fc];
1.1.1.9   root      599:                screen.Print(x, 0, "FC=%d %s", fc, name);
                    600:                screen.Puts(x, 1, "LAddr    PAddr   Flag Hit%  Age");
1.1       root      601:                // 先に統計用の母数を計算
                    602:                uint64 total = 0;
                    603:                for (i = 0; i < countof(table->hit); i++) {
                    604:                        total += table->hit[i];
                    605:                }
                    606:                total += table->hit_head;
                    607: 
                    608:                // エントリ表示
                    609:                for (i = 0; i < countof(table->line); i++) {
                    610:                        m68030ATCLine& a = table->line[i];
1.1.1.2   root      611:                        TA attr;
1.1       root      612:                        if (a.IsInvalid()) {
                    613:                                attr = TA::Disable;
                    614:                        } else if (table->head == &a) {
                    615:                                attr = TA::Em;
                    616:                        } else {
                    617:                                attr = TA::Normal;
                    618:                        }
                    619: 
1.1.1.9   root      620:                        screen.Print(x, i + 2, attr, "%08x %08x %c%c%c",
1.1       root      621:                                a.GetLAddr(),
                    622:                                a.GetPAddr(),
                    623:                                a.IsBusError() ? 'B' : '-',
                    624:                                a.IsWProtect() ? 'P' : '-',
                    625:                                a.IsModified() ? 'M' : '-');
                    626:                }
                    627:                // ヘッドのヒット率
1.1.1.9   root      628:                screen.Puts(x + 0, i + 2, "head");
1.1       root      629:                r = (double)table->hit_head * 100 / total;
1.1.1.13! root      630:                if (!std::isnan(r)) {
1.1.1.9   root      631:                        screen.Print(x + 5, i + 2, "%4.1f%%", r);
1.1       root      632:                }
                    633:                // 配列のヒット率とミス率
1.1.1.9   root      634:                screen.Puts(x + 17, i + 2, "miss");
1.1       root      635:                for (i = 0; i < countof(table->hit); i++) {
                    636:                        r = (double)(table->hit[i] * 100) / total;
1.1.1.13! root      637:                        if (!std::isnan(r)) {
1.1.1.9   root      638:                                screen.Print(x + 22, i + 2, "%4.1f%%", r);
1.1       root      639:                        }
                    640:                }
                    641:                // カウンタ
                    642:                // 分かりやすさのため最大値からの差(距離)を表示
                    643:                for (i = 0; i < countof(table->line); i++) {
                    644:                        m68030ATCLine& a = table->line[i];
                    645:                        if (!a.IsInvalid()) {
1.1.1.9   root      646:                                screen.Print(x + 27, i + 2, "%4d", table->head->age - a.age);
1.1       root      647:                        }
                    648:                }
                    649:        }
                    650: #else
                    651:        m68030ATCLine *a;
                    652:        int i;
                    653: 
                    654:        table = &cpu->atc.tables[0];
1.1.1.9   root      655:        screen.Clear();
1.1       root      656: 
1.1.1.9   root      657:        screen.Puts(0, 0, "No. FC    LAddr    PAddr   Flag");
1.1       root      658:        for (a = table->head, i = 0; a; a = a->next, i++) {
1.1.1.9   root      659:                screen.Print(0, i + 1, "%02d:", i);
1.1       root      660:                if (!a->IsInvalid()) {
                    661:                        char dp;
                    662:                        switch (a->fc & 3) {
                    663:                         case 1:        dp = 'D';       break;
                    664:                         case 2:        dp = 'P';       break;
                    665:                         default:       dp = '?';       break;
                    666:                        }
1.1.1.9   root      667:                        screen.Print(4, i + 1, "%d(%c%c):%08x %08x %c%c%c",
1.1       root      668:                                a->fc,
                    669:                                (a->fc & 4) ? 'S' : 'U',
                    670:                                dp,
                    671:                                a->GetLAddr(), a->GetPAddr(),
                    672:                                a->IsBusError() ? 'B' : '-',
                    673:                                a->IsWProtect() ? 'W' : '-',
                    674:                                a->IsModified() ? 'M' : '-');
                    675:                }
                    676:        }
                    677: #endif
                    678: }

unix.superglobalmegacorp.com

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