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

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

unix.superglobalmegacorp.com

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