Annotation of nono/vm/mpu680x0.cpp, revision 1.1.1.16

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

unix.superglobalmegacorp.com

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