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

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

unix.superglobalmegacorp.com

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