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

unix.superglobalmegacorp.com

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