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

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: //
1.1.1.18! root        8: // MPU (MC68030/MC68040)
1.1.1.13  root        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.18! root       14: #include "exttostr.h"
1.1.1.15  root       15: #include "interrupt.h"
1.1.1.16  root       16: #include "m68030cache.h"
1.1.1.18! root       17: #include "m68040mmu.h"
1.1       root       18: #include "mainapp.h"
1.1.1.17  root       19: #include "mainbus.h"
1.1.1.13  root       20: #include "scheduler.h"
1.1.1.15  root       21: #include "syncer.h"
1.1.1.10  root       22: #include "uimessage.h"
1.1.1.15  root       23: #include "vectortable.h"
1.1.1.13  root       24: 
1.1.1.15  root       25: static Syncer *gSyncer;
1.1       root       26: 
1.1.1.18! root       27: // ブートストラップ。設定に応じてインスタンスを生成して返す。
        !            28: // ここではとりあえず 68040 かそれ以外なら 68030 を生成しておき、
        !            29: // Init() でもう一度 (機種情報も含めて) チェックする。
        !            30: // Init() (か Create()) まで進まないとエラー終了出来ないが、
        !            31: // その時点では MainMPU のインスタンスは必要なので。
        !            32: MPU680x0Device *
        !            33: NewMPU680x0Device()
        !            34: {
        !            35:        const ConfigItem& item = gConfig->Find("mpu-type");
        !            36:        std::string mpu_type = item.AsString();
        !            37: 
        !            38:        // 設定に応じて継承側のクラスを作成する。
        !            39:        // この段階では 68040 かそれ以外だけ判断する。
        !            40:        if (mpu_type == "68040") {
        !            41:                return new MPU68040Device();
        !            42:        } else {
        !            43:                return new MPU68030Device();
        !            44:        }
        !            45: }
        !            46: 
        !            47: 
        !            48: //
        !            49: // 68030/040 共通クラス
        !            50: //
        !            51: 
1.1       root       52: // コンストラクタ
1.1.1.8   root       53: MPU680x0Device::MPU680x0Device()
1.1.1.15  root       54:        : inherited()
1.1       root       55: {
1.1.1.18! root       56:        // MPU 種別は継承側で設定する。設定されないままなら Init() でエラー。
        !            57:        mpu_type = m680x0MPUType::NONE;
1.1.1.15  root       58: 
                     59:        // FPU
                     60:        fpu_init();
1.1       root       61: 
1.1.1.17  root       62:        // 例外カウンタ
                     63:        excep_counter.resize(256);
1.1.1.4   root       64: 
1.1.1.13  root       65:        SetTrace(false);
1.1       root       66: }
                     67: 
                     68: // デストラクタ
                     69: MPU680x0Device::~MPU680x0Device()
                     70: {
                     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.18! root       81:        // なる早で、もう一度 MPU 設定を読んで判定。そのついでに FPU も判定。
        !            82:        const ConfigItem& mputype_item = gConfig->Find("mpu-type");
        !            83:        std::string mputype = mputype_item.AsString();
        !            84:        // mpu-type の設定値が不正な場合でも (コンストラクト時点ではまだエラーを
        !            85:        // 報告できない構造なので) 一旦 MPU68030Device インスタンスとしてここに
        !            86:        // 来る。なのでここで改めてチェックしてエラー報告する必要がある。
        !            87:        // mpu_type (メンバ変数) 自体はすでにセットされている。
        !            88:        if (mputype != "68030" && mputype != "68040") {
        !            89:                mputype_item.Err();
        !            90:                return false;
        !            91:        }
        !            92: 
        !            93:        // 機種ごとに MPU/FPU のサポート状況が違う。
        !            94:        // fpu_type はここでセットする。
        !            95:        switch (gMainApp.GetVMType()) {
        !            96:         case VMType::LUNA1:
        !            97:         case VMType::NEWS:
        !            98:                // NEWS は元々 68030 モデルのみ。
        !            99:                // うち NWS-1750 は 68030/68882 固定のようだがここでは 68881 とする。
        !           100:                // LUNA-I は基本的に 68030/68881 モデルのみ。
        !           101:                if (mpu_type != m680x0MPUType::M68030) {
        !           102:                        mputype_item.Err("Only 68030 can be specified for vmtype=%s",
        !           103:                                gMainApp.GetVMTypeStr().c_str());
        !           104:                        return false;
        !           105:                }
        !           106:                fpu_type = m680x0FPUType::M68881;
        !           107:                break;
        !           108: 
        !           109:         case VMType::X68030:
        !           110:         case VMType::VIRT68K:
        !           111:                // 68030/68040 をサポート。mpu_type は継承コンストラクタで設定済み。
        !           112:                if (mpu_type == m680x0MPUType::M68030) {
        !           113:                        // 68030 なら FPU は設定で指定可能。
        !           114:                        const ConfigItem& fputype_item = gConfig->Find("fpu-type");
        !           115:                        std::string fputype = fputype_item.AsString();
        !           116:                        if (fputype == "none" || fputype == "0") {
        !           117:                                fpu_type = m680x0FPUType::M68030_NOFPU;
        !           118:                        } else if (fputype == "68881" || fputype == "1") {
        !           119:                                fpu_type = m680x0FPUType::M68881;
        !           120:                        } else {
        !           121:                                fputype_item.Err();
        !           122:                                return false;
        !           123:                        }
        !           124:                } else {
        !           125:                        // 68040 なら FPU は現状 !LC040 固定。
        !           126:                        fpu_type = m680x0FPUType::M68040;
        !           127:                }
        !           128:                break;
        !           129: 
        !           130:         default:
        !           131:                VMPANIC("vmtype=%s not configured", gMainApp.GetVMTypeStr().c_str());
        !           132:                break;
        !           133:        }
        !           134: 
1.1.1.15  root      135:        debugger = GetDebugger();
                    136:        interruptdev = GetInterruptDevice();
1.1.1.18! root      137:        vectortable = GetVectorTable();
1.1.1.15  root      138:        // static 関数から参照するため。うーん…。
                    139:        gSyncer = syncer;
                    140: 
1.1.1.18! root      141:        // 割り込みイベントコールバック設定。
1.1.1.13  root      142:        //
                    143:        // 外部デバイスが 68030 の IPL0-2 をアサートしてから、68030 がそれを
                    144:        // 認識(確定)するのに 1 ~ 2 クロックかかる。
                    145:        // その後レベルを比較するのは次のアップエッジ。
                    146:        // その後 /IPEND をアサートするのはその次のアップエッジ。
                    147:        // 合わせると、IPL0-2 が変化してから /IPEND がアサートされるまでは
                    148:        // 2 ~ 3 クロックかかる。(Figure 8-4)
1.1.1.18! root      149:        intr_event.func = ToEventCallback(&MPU680x0Device::InterruptCallback);
1.1.1.13  root      150:        intr_event.time = 3 * clock_nsec;
1.1.1.18! root      151:        intr_event.SetName(GetName() + " Interrupt");
        !           152:        scheduler->RegistEvent(intr_event);
1.1.1.5   root      153: 
1.1.1.18! root      154:        // レジスタモニタの行数。
        !           155:        int height = 9;
        !           156:        if (mpu_type == m680x0MPUType::M68030) {
        !           157:                height++;
        !           158:        }
        !           159:        if (HasFPU()) {
        !           160:                height += 12;
        !           161:                if (GetFPUType().Is4060FPU()) {
        !           162:                        height += 3;
1.1       root      163:                }
                    164:        }
1.1.1.18! root      165:        reg_monitor->SetSize(78, height);
1.1.1.17  root      166: 
1.1       root      167:        return true;
                    168: }
                    169: 
1.1.1.13  root      170: // リセット
                    171: void
                    172: MPU680x0Device::ResetHard(bool poweron)
1.1.1.8   root      173: {
1.1.1.13  root      174:        if (poweron) {
1.1.1.15  root      175:                // サイクルを初期化。
                    176:                used_cycle = 0;
                    177: 
                    178:                // 履歴を初期化。電源(再)投入時のみ行う。
                    179:                exhist.Clear();
                    180:                brhist.Clear();
                    181: 
                    182:                for (int i = 0; i < 16; i++) {
                    183:                        reg.R[i] = 0xcccccccc;
                    184:                }
                    185:                // XXX ただし X68030 IPLROM には A6 を初期化せずに書き込んでいるバグが
                    186:                // あるため、A6 を概ね RAM のあるあたりに指定しておく…。
                    187:                reg.A[6] = 0x000ccccc;
                    188: 
                    189:                // この後起きるリセット例外で PC を初期化する前に参照することになるので
                    190:                // これだけここでも初期化しておく。
                    191:                reg.pc = 0;
1.1.1.13  root      192:        }
1.1.1.14  root      193:        resetting = true;
1.1.1.13  root      194: 
                    195:        // リセット例外を 520 クロック後に起こす。
                    196:        // 520 は、電源オン時、Vcc が最小動作規定値に達してから最低 520 クロック
                    197:        // の間アサートしなければならないという値であって、実際これだけかかる
                    198:        // とかいう値ではない。が、こちら側の都合で、この後実行される RAM の
1.1.1.15  root      199:        // ResetHard() がブートページを用意した後で ExceptionReset() で
1.1.1.13  root      200:        // SP, PC をフェッチするという順序にしないといけないため、リセット例外が
                    201:        // 起動するまでに時間がかかるというところを都合よく真似ておく。
                    202: 
                    203:        exec_event.func = ToEventCallback(&MPU680x0Device::ResetCallback);
                    204:        exec_event.time = 520 * clock_nsec;
1.1.1.15  root      205:        exec_event.SetName(GetName() + " Reset");
                    206:        scheduler->RestartEvent(exec_event);
1.1.1.8   root      207: }
                    208: 
1.1.1.13  root      209: // リセット例外コールバック。
                    210: // MPU リセットから規定時間後に呼ばれる。
1.1.1.8   root      211: void
1.1.1.13  root      212: MPU680x0Device::ResetCallback(Event& ev)
1.1.1.8   root      213: {
1.1.1.14  root      214:        resetting = false;
1.1.1.13  root      215:        intr_pending = false;
                    216: 
                    217:        // リセット例外を実行
1.1.1.15  root      218:        int cycle = ExceptionReset();
1.1.1.13  root      219: 
                    220:        // コールバックを ResetCallback から Exec* に差し替える前のここで
                    221:        // トレース状態を初期化する。
1.1.1.15  root      222:        SetTrace(debugger->IsTrace());
1.1.1.13  root      223: 
                    224:        // 以降は通常走行。
1.1.1.15  root      225:        if (cpu_state == CPU_STATE_NORMAL) {
1.1.1.13  root      226:                exec_event.func = exec_short;
                    227:                exec_event.time = cycle * clock_nsec;
1.1.1.15  root      228:                exec_event.SetName(GetName() + " Execute");
                    229:                scheduler->RestartEvent(exec_event);
1.1.1.13  root      230:        } else {
                    231:                // リセット例外でダブルバスフォールトならここで停止。
                    232:        }
1.1.1.8   root      233: }
                    234: 
1.1.1.15  root      235: // 割り込みチェック、STOP/HALT 処理を含んだ完全な実行サイクルのコールバック。
1.1.1.13  root      236: // SR の I2:I0 が変わった直後などに呼ばれる。
                    237: // ここでは割り込みをチェックし、必要なら割り込み処理を起動、
                    238: // そうでなければ通常の命令実行を行う。
                    239: void
                    240: MPU680x0Device::ExecFull(Event& ev)
                    241: {
1.1.1.15  root      242:        if (cpu_state == CPU_STATE_HALT) {
                    243:                // HALT なら停止。
                    244:                return;
                    245:        }
                    246: 
                    247:        // マスクよりも割り込みレベルのほうが高ければ割り込み処理。
                    248:        // この時点で intr_pending が true の可能性もあることに留意。
                    249:        // 割り込みレベルは変化してないので Level 7 の特別処理は不要
                    250:        // (割り込みレベルの変化はここではなく InterruptCallback() で処理)。
                    251:        if (intr_level > reg.intr_mask) {
                    252:                intr_pending = true;
                    253:        }
1.1.1.14  root      254: 
1.1.1.13  root      255:        if (intr_pending) {
                    256:                // 割り込み処理を起動。
                    257: 
                    258:                intr_pending = false;
                    259: 
                    260:                // 前の命令実行後となるここで割り込みを起動
1.1.1.16  root      261:                ev.time = ExceptionInterrupt();
1.1.1.15  root      262:                scheduler->StartEvent(ev);
1.1.1.13  root      263:        } else {
1.1.1.15  root      264:                if (cpu_state == CPU_STATE_NORMAL) {
1.1.1.13  root      265:                        // コールバックを通常処理に戻してから...
                    266:                        exec_event.func = exec_short;
                    267: 
                    268:                        // この場で次の命令を実行。
                    269:                        ExecShort(ev);
                    270:                } else {
1.1.1.15  root      271:                        // STOP ならここで停止。
1.1.1.13  root      272:                }
                    273:        }
1.1       root      274: }
                    275: 
1.1.1.13  root      276: // トレース実行
                    277: void
                    278: MPU680x0Device::ExecTrace(Event& ev)
1.1       root      279: {
1.1.1.15  root      280:        debugger->ExecMain();
1.1.1.13  root      281:        ExecFull(ev);
1.1       root      282: }
                    283: 
1.1.1.13  root      284: // トレース状態を設定する
                    285: void
                    286: MPU680x0Device::SetTrace(bool enable)
1.1       root      287: {
1.1.1.13  root      288:        if (enable) {
                    289:                exec_short = ToEventCallback(&MPU680x0Device::ExecTrace);
                    290:                exec_full  = ToEventCallback(&MPU680x0Device::ExecTrace);
                    291:        } else {
                    292:                exec_short = ToEventCallback(&MPU680x0Device::ExecShort);
                    293:                exec_full  = ToEventCallback(&MPU680x0Device::ExecFull);
                    294:        }
                    295:        exec_event.func = exec_full;
                    296: 
                    297:        // STOP 命令中にオンにするには、停止しているイベントを起こす。
                    298:        // STOP 命令中にオフにする場合は、何もしなくていい。
                    299:        if (enable && exec_event.IsRunning() == false) {
1.1.1.15  root      300:                scheduler->StartEvent(exec_event);
1.1.1.13  root      301:        }
1.1       root      302: }
                    303: 
1.1.1.5   root      304: // 割り込みレベルが変わったことを MPU に通知。
1.1       root      305: void
1.1.1.5   root      306: MPU680x0Device::Interrupt(int level)
1.1       root      307: {
1.1.1.5   root      308:        assertmsg(0 <= level && level <= 7, "level=%d", level);
                    309: 
1.1.1.13  root      310:        intr_event.code = level;
                    311:        if (intr_event.IsRunning() == false) {
1.1.1.15  root      312:                scheduler->StartEvent(intr_event);
1.1.1.5   root      313:        }
1.1.1.13  root      314: }
                    315: 
                    316: // 外部割り込みイベントコールバック。
                    317: // ev.code 0-7 は新しい割り込みレベル。
1.1.1.15  root      318: //
                    319: // 割り込みは本来命令境界ごとにチェックするが、実際に割り込みが起きうるのは
                    320: // 1) 割り込み信号線が変化した時
                    321: // 2) 割り込みマスクを変更した時
                    322: // しかないはずなので、この時だけ命令境界でチェックする。
                    323: // ここはその 1) のほう。その2のほうは core.cpp:SetSR() 参照。
                    324: //
                    325: // 外部割り込みが来たので、レベル比較などをして、必要なら次の命令境界で
                    326: // 割り込みチェックを行うようにするところ。
1.1.1.13  root      327: void
                    328: MPU680x0Device::InterruptCallback(Event& ev)
                    329: {
1.1.1.17  root      330:        uint level = ev.code;
                    331:        uint mask = reg.intr_mask;
1.1.1.15  root      332: 
                    333:        // 信号線が 2 クロック期間安定していること云々は省略
1.1.1.13  root      334: 
1.1.1.16  root      335:        // 割り込みを起こすかどうかに関わらずここで更新。
                    336:        intr_level = level;
                    337: 
                    338:        // ホールトならここまで。
1.1.1.15  root      339:        if (cpu_state == CPU_STATE_HALT) {
                    340:                return;
                    341:        }
                    342: 
                    343:        // 割り込み例外を起動するのは
                    344:        // o レベルがマスクより高い
                    345:        // o マスクに関係なく、レベルが下位から 7 に変化した場合
                    346:        //   (ここは変化した時だけ呼ばれるのと 7 より上はないので
                    347:        //   level==7 なら必ず「下位から 7 に変化」のはず)
                    348:        if (level > mask || level == 7) {
1.1.1.13  root      349:                // 通知した結果割り込みが受け付けられたので、
                    350:                // この命令終了時のコールバックを割り込み処理起動に差し替える。
                    351:                MakeNextFull();
                    352:                intr_pending = true;
                    353: 
                    354:                // STOP 状態だったらここでイベントを開始する
1.1.1.15  root      355:                if (cpu_state == CPU_STATE_STOP) {
1.1.1.13  root      356:                        // STOP から抜ける時間?
                    357:                        exec_event.time = 1 * clock_nsec;
1.1.1.15  root      358:                        scheduler->StartEvent(exec_event);
1.1.1.13  root      359:                }
                    360:        }
                    361: }
                    362: 
                    363: // 次の命令境界は Full にする。
                    364: void
                    365: MPU680x0Device::MakeNextFull()
                    366: {
                    367:        exec_event.func = exec_full;
                    368: }
                    369: 
1.1.1.15  root      370: void
                    371: MPU680x0Device::ChangeState(uint32 new_state)
1.1.1.13  root      372: {
1.1.1.15  root      373:        // new_mode (CPU_STATE_*) と
                    374:        // RequestCPUMode() の引数 Syncer::SCHED_CPU_* は
1.1.1.13  root      375:        // 実は同じ値なのでそのまま渡してよいことにする。
1.1.1.15  root      376:        static_assert(CPU_STATE_NORMAL == Syncer::SCHED_CPU_NORMAL, "");
                    377:        static_assert(CPU_STATE_STOP   == Syncer::SCHED_CPU_STOP,   "");
                    378:        static_assert(CPU_STATE_HALT   == Syncer::SCHED_CPU_HALT,   "");
                    379: 
                    380:        if (cpu_state != new_state) {
                    381:                cpu_state = new_state;
                    382:                // スケジューラに通知
                    383:                syncer->RequestCPUMode(cpu_state);
                    384:        }
1.1       root      385: }
                    386: 
                    387: // A-Line 命令エミュレーションのコールバックを指定。
                    388: void
1.1.1.15  root      389: MPU680x0Device::SetALineCallback(bool (*callback)(MPU680x0Device *, void*),
                    390:        void *arg)
1.1       root      391: {
1.1.1.15  root      392:        aline_callback = callback;
                    393:        aline_arg = arg;
1.1       root      394: }
                    395: 
                    396: // F-Line 命令エミュレーションのコールバックを指定。
                    397: void
1.1.1.15  root      398: MPU680x0Device::SetFLineCallback(bool (*callback)(MPU680x0Device *, void*),
                    399:        void *arg)
1.1       root      400: {
1.1.1.15  root      401:        fline_callback = callback;
                    402:        fline_arg = arg;
1.1       root      403: }
                    404: 
1.1.1.15  root      405: // RESET 命令
                    406: void
                    407: MPU680x0Device::ops_reset()
1.1.1.10  root      408: {
1.1.1.16  root      409:        auto mainbus = GetMainbusDevice();
                    410:        mainbus->ResetByMPU();
1.1.1.13  root      411: }
                    412: 
                    413: // ホールト状態
                    414: void
                    415: MPU680x0Device::Halt()
                    416: {
1.1.1.15  root      417:        ChangeState(CPU_STATE_HALT);
                    418: 
                    419:        // この命令完了後に停止するため exec を差し替える。
                    420:        MakeNextFull();
1.1.1.13  root      421: 
                    422:        // UI に通知 (メッセージボックス表示とか)
1.1.1.10  root      423:        UIMessage::Post(UIMessage::HALT);
                    424: }
                    425: 
1.1.1.18! root      426: // モニター更新の下請け (レジスタ共通部分)
1.1.1.3   root      427: void
1.1.1.18! root      428: MPU680x0Device::MonitorUpdateRegCommon(TextScreen& screen,
        !           429:        m68kreg& tmp, uint32 tmp_ppc, uint32 tmp_state)
1.1       root      430: {
                    431:        int x;
                    432: 
                    433:        // データレジスタ、アドレスレジスタ
                    434:        for (int i = 0; i < 4; i++) {
1.1.1.17  root      435:                screen.Print(0, i, "D%u:%08x D%u:%08x  A%u:%08x A%u:%08x",
1.1.1.15  root      436:                        i + 0, tmp.R[i],
                    437:                        i + 4, tmp.R[i + 4],
                    438:                        i + 0, tmp.R[i + 8],
                    439:                        i + 4, tmp.R[i + 12]);
1.1       root      440:        }
                    441: 
                    442:        // 5列目
                    443:        x = 50;
                    444:        // SR
1.1.1.9   root      445:        screen.Print(x, 0, "SR:%04x(%c%c%c%c%c)",
1.1.1.15  root      446:                tmp.GetSR(),
                    447:                (tmp.ccr.IsX()) ? 'X' : '-',
                    448:                (tmp.ccr.IsN()) ? 'N' : '-',
                    449:                (tmp.ccr.IsZ()) ? 'Z' : '-',
                    450:                (tmp.ccr.IsV()) ? 'V' : '-',
                    451:                (tmp.ccr.IsC()) ? 'C' : '-');
1.1       root      452: 
                    453:        // *SP
1.1.1.15  root      454:        uint ms = (tmp.s ? 2 : 0) | (tmp.m ? 1 : 0); // T1 T0 S M
1.1       root      455:        if (ms == 3) {
                    456:                // Supervisor (Master) mode (A7=MSP, USP/ISP)
1.1.1.16  root      457:                screen.Print(x, 1, TA::Disable, "USP:%08x", tmp.usp);
                    458:                screen.Print(x, 2, TA::Disable, "ISP:%08x", tmp.isp);
1.1       root      459:        } else if (ms == 2) {
                    460:                // Supervisor (Interrupt) mode (A7=ISP, USP/MSP)
1.1.1.16  root      461:                screen.Print(x, 1, TA::Disable, "USP:%08x", tmp.usp);
                    462:                screen.Print(x, 2, TA::Disable, "MSP:%08x", tmp.msp);
1.1       root      463:        } else {
                    464:                // User mode (A7=USP, ISP/MSP)
1.1.1.16  root      465:                screen.Print(x, 1, TA::Disable, "ISP:%08x", tmp.isp);
                    466:                screen.Print(x, 2, TA::Disable, "MSP:%08x", tmp.msp);
1.1       root      467:        }
                    468: 
                    469:        // 6列目
1.1.1.16  root      470:        // PC: 01234567
                    471:        // SFC:1  DFC:1
                    472:        // VBR:01234567
1.1       root      473:        x = 66;
1.1.1.16  root      474:        screen.Print(x, 0, "PC: %08x", tmp_ppc);
1.1.1.17  root      475:        screen.Print(x, 1, "SFC:%u  DFC:%u", tmp.GetSFC(), tmp.GetDFC());
1.1.1.16  root      476:        screen.Print(x, 2, "VBR:%08x", tmp.vbr);
1.1       root      477: 
1.1.1.15  root      478:        switch (tmp_state) {
                    479:         case CPU_STATE_NORMAL:
1.1.1.16  root      480:                screen.Puts(50, 3, "State: Running");
1.1.1.13  root      481:                break;
1.1.1.15  root      482:         case CPU_STATE_STOP:
1.1.1.16  root      483:                screen.Puts(50, 3, "State: STOP instruction");
1.1.1.13  root      484:                break;
1.1.1.15  root      485:         case CPU_STATE_HALT:
1.1.1.16  root      486:                screen.Puts(50, 3, TA::On, "State: Double Bus Fault");
1.1.1.13  root      487:                break;
                    488:         default:
1.1.1.17  root      489:                screen.Print(50, 3, TA::On, "corrupted cpu_state=%u", tmp_state);
1.1.1.15  root      490:                break;
1.1       root      491:        }
1.1.1.18! root      492: }
1.1       root      493: 
1.1.1.18! root      494: // モニタ更新の下請け (FPU)
        !           495: int
        !           496: MPU680x0Device::MonitorUpdateFPU(TextScreen& screen, int y, m68kreg& tmp)
        !           497: {
        !           498:        int x;
        !           499: 
        !           500: /*
        !           501: 0123456789012345678901234567890123456789012345678901234567890123456789012345
        !           502: FP0:7fff_ffffffff_ffffffff = NAN
        !           503: FPCR:     0000                    BS SN OP OV UF DZ I2 I1  Prec=.X Mode=Minus
        !           504: FPSR: 00000000 N Z INF NAN Q=$xx  BS SN OP OV UF DZ I2 I1  AV AO AU AD AI
        !           505: FPIAR:00000000
        !           506: */
        !           507: 
        !           508:        x = 0;
        !           509:        screen.Puts(x, y++, "<FPU>");
        !           510:        for (int i = 0; i < 8; i++) {
        !           511:                screen.Print(x, y++, "FP%u:%04x_%08x_%08x = %s",
        !           512:                        i,
        !           513:                        tmp.fpframe.fpf_regs[i * 3 + 0] >> 16,
        !           514:                        tmp.fpframe.fpf_regs[i * 3 + 1],
        !           515:                        tmp.fpframe.fpf_regs[i * 3 + 2],
        !           516:                        ExtToStr(&tmp.fpframe.fpf_regs[i * 3]).c_str());
        !           517:        }
        !           518: 
        !           519:        // FPCR
        !           520:        uint32 fpcr = tmp.fpframe.fpf_fpcr;
        !           521:        screen.Puts(0, y, "FPCR:");
        !           522:        screen.Print(10, y, "%04x", fpcr);
        !           523:        x = 34;
        !           524:        screen.Puts(x +  0, y, TA::OnOff(fpcr & 0x8000), "BS");
        !           525:        screen.Puts(x +  3, y, TA::OnOff(fpcr & 0x4000), "SN");
        !           526:        screen.Puts(x +  6, y, TA::OnOff(fpcr & 0x2000), "OE");
        !           527:        screen.Puts(x +  9, y, TA::OnOff(fpcr & 0x1000), "OF");
        !           528:        screen.Puts(x + 12, y, TA::OnOff(fpcr & 0x0800), "UF");
        !           529:        screen.Puts(x + 15, y, TA::OnOff(fpcr & 0x0400), "DZ");
        !           530:        screen.Puts(x + 18, y, TA::OnOff(fpcr & 0x0200), "X2");
        !           531:        screen.Puts(x + 21, y, TA::OnOff(fpcr & 0x0100), "X1");
        !           532:        screen.Print(x + 25, y, "RP=.%c RM=%s",
        !           533:                "XSD?"[(fpcr >> 6) & 3],
        !           534:                rmstr[(fpcr >> 4) & 3]);
        !           535:        y++;
        !           536: 
        !           537:        // FPSR
        !           538:        uint32 fpsr = tmp.fpframe.fpf_fpsr;
        !           539:        uint32 cc = fpsr >> 24;
        !           540:        screen.Print(0, y, "FPSR: %08x", fpsr);
        !           541:        x = 15;
        !           542:        screen.Puts(x +  0, y, TA::OnOff(cc & 0x08), "N");
        !           543:        screen.Puts(x +  2, y, TA::OnOff(cc & 0x04), "Z");
        !           544:        screen.Puts(x +  4, y, TA::OnOff(cc & 0x02), "Inf");
        !           545:        screen.Puts(x +  8, y, TA::OnOff(cc & 0x01), "NAN");
        !           546:        screen.Print(x + 12, y, "Q=$%02x", (fpsr >> 16) & 0xff);
        !           547:        x = 34;
        !           548:        screen.Puts(x +  0, y, TA::OnOff(fpsr & 0x8000), "BS");
        !           549:        screen.Puts(x +  3, y, TA::OnOff(fpsr & 0x4000), "SN");
        !           550:        screen.Puts(x +  6, y, TA::OnOff(fpsr & 0x2000), "OE");
        !           551:        screen.Puts(x +  9, y, TA::OnOff(fpsr & 0x1000), "OF");
        !           552:        screen.Puts(x + 12, y, TA::OnOff(fpsr & 0x0800), "UF");
        !           553:        screen.Puts(x + 15, y, TA::OnOff(fpsr & 0x0400), "DZ");
        !           554:        screen.Puts(x + 18, y, TA::OnOff(fpsr & 0x0200), "X2");
        !           555:        screen.Puts(x + 21, y, TA::OnOff(fpsr & 0x0100), "X1");
        !           556:        screen.Puts(x + 25, y, TA::OnOff(fpsr & 0x80), "AV");
        !           557:        screen.Puts(x + 28, y, TA::OnOff(fpsr & 0x40), "AO");
        !           558:        screen.Puts(x + 31, y, TA::OnOff(fpsr & 0x20), "AU");
        !           559:        screen.Puts(x + 34, y, TA::OnOff(fpsr & 0x10), "AZ");
        !           560:        screen.Puts(x + 37, y, TA::OnOff(fpsr & 0x08), "AX");
        !           561:        y++;
        !           562: 
        !           563:        // FPIAR
        !           564:        screen.Print(0, y++, "FPIAR:%08x", tmp.fpframe.fpf_fpiar);
        !           565: 
        !           566:        return y;
        !           567: }
        !           568: 
        !           569: 
        !           570: //
        !           571: // 68030
        !           572: //
        !           573: 
        !           574: // コンストラクタ
        !           575: MPU68030Device::MPU68030Device()
        !           576:        : inherited()
        !           577: {
        !           578:        mpu_type = m680x0MPUType::M68030;
        !           579:        mpu_name = "MC68030";
        !           580:        SetName("MPU(68030)");
        !           581: 
        !           582:        // MMU.xRP.DT == 0 になってはいけない(MMU 構成例外)。
        !           583:        SetSRP(0x00000001, 0);
        !           584:        SetCRP(0x00000001, 0);
        !           585: 
        !           586:        // キャッシュ
        !           587:        icache.reset(new m68030Cache());
        !           588:        dcache.reset(new m68030Cache());
        !           589: 
        !           590:        // レジスタモニター (サイズは Init で確定する)
        !           591:        reg_monitor = gMonitorManager->Regist(ID_MONITOR_MPUREG, this);
        !           592:        reg_monitor->func = ToMonitorCallback(&MPU68030Device::MonitorUpdateReg);
        !           593: 
        !           594:        // ATC モニター
        !           595:        atc_monitor = gMonitorManager->Regist(ID_MONITOR_MPUATC, this);
        !           596:        atc_monitor->func = ToMonitorCallback(&MPU68030Device::MonitorUpdateATC);
        !           597:        atc_monitor->SetSize(114, m68030ATCTable::LINES + 6);
        !           598: 
        !           599:        // キャッシュモニター
        !           600:        cache_monitor = gMonitorManager->Regist(ID_MONITOR_MPUCACHE, this);
        !           601:        cache_monitor->func =
        !           602:                ToMonitorCallback(&MPU68030Device::MonitorUpdateCache);
        !           603:        cache_monitor->SetSize(48, 20 * 2 + 1);
        !           604: }
        !           605: 
        !           606: // デストラクタ
        !           607: MPU68030Device::~MPU68030Device()
        !           608: {
        !           609: }
        !           610: 
        !           611: void
        !           612: MPU68030Device::SetLogLevel(int loglevel_)
        !           613: {
        !           614:        inherited::SetLogLevel(loglevel_);
        !           615: 
        !           616:        atc.SetLogLevel(loglevel_);
        !           617: }
        !           618: 
        !           619: static int
        !           620: sort_atc(const void *a, const void *b)
        !           621: {
        !           622:        const uint32 *ua = (const uint32 *)a;
        !           623:        const uint32 *ub = (const uint32 *)b;
        !           624:        return *ub - *ua;
        !           625: }
        !           626: 
        !           627: // モニター更新 (レジスタ)
        !           628: void
        !           629: MPU68030Device::MonitorUpdateReg(Monitor *, TextScreen& screen)
        !           630: {
        !           631:        m68kreg tmp;
        !           632:        uint32 tmp_ppc;
        !           633:        uint32 tmp_state;
        !           634:        int y;
        !           635: 
        !           636:        screen.Clear();
        !           637: 
        !           638:        // ローカルにコピーする。
        !           639:        // ただし一部は reg ではなく cpu クラス本体にある。
        !           640:        tmp = reg;
        !           641:        tmp_ppc = ppc;
        !           642:        tmp_state = cpu_state;
        !           643: 
        !           644:        // 共通部分。
        !           645:        MonitorUpdateRegCommon(screen, tmp, tmp_ppc, tmp_state);
        !           646: 
        !           647:        // Cache/MMU 部分。
1.1.1.16  root      648:        y = 4;
1.1.1.18! root      649:        y = MonitorUpdateMMU(screen, y, tmp);
        !           650: 
        !           651:        // FPU はある時だけ表示。
        !           652:        if (HasFPU()) {
        !           653:                MonitorUpdateFPU(screen, y, tmp);
        !           654:        }
        !           655: }
        !           656: 
        !           657: // モニター更新の下請け (Cache/MMU 部分)
        !           658: int
        !           659: MPU68030Device::MonitorUpdateMMU(TextScreen& screen, int y, m68kreg& tmp)
        !           660: {
        !           661:        int x;
        !           662: 
        !           663:        // Cache
1.1.1.16  root      664:        screen.Puts(0, y++, "<Cache>");
                    665:        screen.Print(0, y,  "CACR:%08x(", tmp.cacr);
1.1.1.18! root      666:        screen.Puts(14, y, TA::OnOff(tmp.cacr & M68030::CACR_WA),  "WA");
        !           667:        screen.Puts(17, y, TA::OnOff(tmp.cacr & M68030::CACR_DBE), "DBE");
1.1.1.17  root      668:        screen.Puts(21, y, "- -");
1.1.1.18! root      669:        screen.Puts(25, y, TA::OnOff(tmp.cacr & M68030::CACR_FD),  "FD");
        !           670:        screen.Puts(28, y, TA::OnOff(tmp.cacr & M68030::CACR_ED),  "ED");
1.1.1.17  root      671:        screen.Puts(31, y, "000");
1.1.1.18! root      672:        screen.Puts(35, y, TA::OnOff(tmp.cacr & M68030::CACR_IBE), "IBE");
1.1.1.17  root      673:        screen.Puts(39, y, "- -");
1.1.1.18! root      674:        screen.Puts(43, y, TA::OnOff(tmp.cacr & M68030::CACR_FI),  "FI");
        !           675:        screen.Puts(46, y, TA::OnOff(tmp.cacr & M68030::CACR_EI),  "EI");
1.1.1.17  root      676:        screen.Putc(48, y, ')');
1.1.1.16  root      677:        screen.Print(50, y, "CAAR:%08x", tmp.caar);
                    678:        y++;
                    679: 
1.1       root      680:        // MMU
                    681:        x = 0;
1.1.1.9   root      682:        screen.Puts(x, y++, "<MMU>");
1.1.1.15  root      683:        screen.Print(x, y,     "SRP:%08x_%08x", tmp.srp.h, tmp.srp.l);
                    684:        screen.Print(x, y + 1, "CRP:%08x_%08x", tmp.crp.h, tmp.crp.l);
1.1.1.16  root      685:        x += 25;
1.1       root      686:        for (int i = 0; i < 2; i++) {
1.1.1.15  root      687:                uint32 tt = tmp.tt[i];
1.1.1.16  root      688:                screen.Print(x, y + i,
1.1.1.17  root      689:                        "TT%u:%08x(%c%c%c Addr=$%02x Mask=$%02x FC=%u FCMask=%u)",
1.1       root      690:                        i, tt,
                    691:                        (tt & m68030TT::E)   ? 'E' : '-',
                    692:                        (tt & m68030TT::CI)  ? 'C' : '-',
1.1.1.16  root      693:                        (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW)  ? 'R' : 'W'),
                    694:                        (tt >> 24),
                    695:                        (tt >> 16) & 0xff,
                    696:                        (tt >>  4) & 0x07,
                    697:                        (tt      ) & 0x07);
                    698:        }
                    699:        y += 2;
                    700:        screen.Print(0, y,
                    701:                "TC:%08x(%c%c%c IS=$%x TIA-D=%x:%x:%x:%x PS=$%x)",
1.1.1.15  root      702:                tmp.tc,
                    703:                (tmp.tc & m68030TC::TC_E)   ? 'E' : '-',
                    704:                (tmp.tc & m68030TC::TC_SRE) ? 'S' : '-',
1.1.1.16  root      705:                (tmp.tc & m68030TC::TC_FCL) ? 'F' : '-',
                    706:                (tmp.tc >> 16) & 0xf,
                    707:                (tmp.tc >> 12) & 0xf,
                    708:                (tmp.tc >>  8) & 0xf,
                    709:                (tmp.tc >>  4) & 0xf,
                    710:                (tmp.tc      ) & 0xf,
                    711:                (tmp.tc >> 20) & 0xf);
                    712:        x = 49;
                    713:        screen.Print(x, y, "MMUSR:%04x(", tmp.mmusr);
                    714:        x += 11;
1.1.1.15  root      715:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::B) | 'B');
                    716:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::L) | 'L');
                    717:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::S) | 'S');
                    718:        screen.Putc(x++, y, '-');
                    719:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::W) | 'W');
                    720:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::I) | 'I');
                    721:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::M) | 'M');
                    722:        screen.Puts(x, y, "- -");
                    723:        x += 3;
                    724:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::T) | 'T');
1.1.1.17  root      725:        screen.Print(x, y, "---N=%u)", tmp.mmusr & m68030MMUSR::N);
1.1.1.16  root      726:        y++;
1.1       root      727: 
1.1.1.18! root      728:        return y;
1.1.1.17  root      729: }
                    730: 
1.1.1.18! root      731: // モニター更新 (68030 ATC)
1.1.1.3   root      732: void
1.1.1.18! root      733: MPU68030Device::MonitorUpdateATC(Monitor *, TextScreen& screen)
1.1       root      734: {
                    735:        m68030ATCTable *table;
1.1.1.17  root      736: 
                    737:        screen.Clear();
                    738: 
1.1       root      739:        struct {
                    740:                int fc;
                    741:                const char *name;
                    742:        } fclist[] = {
                    743:                { 1,    "User/Data" },
                    744:                { 2,    "User/Program" },
                    745:                { 5,    "Super/Data" },
                    746:                { 6,    "Super/Program" },
                    747:        };
                    748: 
1.1.1.17  root      749:        for (uint t = 0; t < countof(fclist); t++) {
                    750:                int x = t * 29;
1.1       root      751:                int fc = fclist[t].fc;
                    752:                const char *name = fclist[t].name;
                    753: 
1.1.1.17  root      754:                table = atc.fctables[fc];
                    755:                screen.Print(x, 0, "FC=%u %s", fc, name);
                    756:                screen.Puts(x, 1, "No.  LAddr    PAddr    Flag");
                    757: 
                    758:                std::array<uint32, m68030ATCTable::LINES * 2> sbuf;
                    759:                for (uint i = 0; i < m68030ATCTable::LINES; i++) {
                    760:                        sbuf[i * 2 + 0] = table->line[i].age;
                    761:                        sbuf[i * 2 + 1] = i;
1.1       root      762:                }
1.1.1.17  root      763:                qsort(&sbuf[0], m68030ATCTable::LINES, sizeof(uint32) * 2, sort_atc);
1.1       root      764: 
                    765:                // エントリ表示
1.1.1.17  root      766:                for (uint i = 0; i < m68030ATCTable::LINES; i++) {
                    767:                        int idx = sbuf[i * 2 + 1];
                    768:                        m68030ATCLine& a = table->line[idx];
1.1.1.2   root      769:                        TA attr;
1.1       root      770:                        if (a.IsInvalid()) {
                    771:                                attr = TA::Disable;
                    772:                        } else {
                    773:                                attr = TA::Normal;
                    774:                        }
                    775: 
1.1.1.17  root      776:                        screen.Print(x, i + 2, attr, "[%02x] %08x %08x %c%c%c%c",
                    777:                                idx,
1.1       root      778:                                a.GetLAddr(),
                    779:                                a.GetPAddr(),
                    780:                                a.IsBusError() ? 'B' : '-',
1.1.1.16  root      781:                                a.IsCInhibit() ? 'C' : '-',
1.1       root      782:                                a.IsWProtect() ? 'P' : '-',
                    783:                                a.IsModified() ? 'M' : '-');
                    784:                }
1.1.1.17  root      785: 
                    786:                // ヒット率とミス率。
                    787:                uint64 total = 0;
                    788:                uint64 tthit = 0;
                    789:                uint64 miss = 0;
                    790:                bool tt_once_hit;
                    791: 
                    792:                {
                    793:                        std::unique_lock<std::mutex> lock(table->atchist_mtx);
                    794:                        for (int i = 0; i < table->atchist.Length(); i++) {
                    795:                                const auto& s = table->atchist.Peek(i);
                    796:                                total += s.total;
                    797:                                tthit += s.tthit;
                    798:                                miss  += s.miss;
1.1       root      799:                        }
1.1.1.17  root      800:                        tt_once_hit = table->atchist_tt_once_hit;
1.1       root      801:                }
1.1.1.17  root      802: 
                    803:                int y = m68030ATCTable::LINES + 2;
                    804:                screen.Puts(x + 1, y, "TT Match");
                    805:                if (tt_once_hit) {
                    806:                        screen.Print(x + 10, y, "%5.1f%%", (double)(tthit * 100) / total);
                    807:                } else {
                    808:                        screen.Puts(x + 12, y, "0");
1.1       root      809:                }
1.1.1.17  root      810:                y++;
1.1.1.16  root      811: 
1.1.1.17  root      812:                screen.Puts(x + 1, y, "ATC Match");
                    813:                if (total == 0) {
                    814:                        screen.Puts(x + 12, y, "0");
                    815:                } else {
                    816:                        screen.Print(x + 10, y, "%5.1f%%",
                    817:                                (double)((total - miss - tthit) * 100) / total);
                    818:                }
                    819:                y++;
1.1       root      820: 
1.1.1.17  root      821:                screen.Puts(x + 1, y, "ATC Miss");
                    822:                if (miss == 0) {
                    823:                        screen.Puts(x + 12, y, "0");
                    824:                } else {
                    825:                        screen.Print(x + 10, y, "%5.1f%%", (double)(miss * 100) / total);
                    826:                }
                    827:                y++;
                    828:        }
1.1       root      829: 
1.1.1.17  root      830:        screen.Print(0, m68030ATCTable::LINES + 5,
                    831:                "Note: The real 68030 ATC is single FC-mixed 22-entries. "
                    832:                "This ATC with FC-separated %u-entries is by nono.",
                    833:                m68030ATCTable::LINES);
                    834: }
                    835: 
                    836: // 統計情報を更新 (Syncer から呼ばれる)
                    837: void
1.1.1.18! root      838: MPU68030Device::CalcStat()
1.1.1.17  root      839: {
                    840:        // ATC のヒット率。
                    841:        for (auto& table : atc.tables) {
                    842:                // ここはロックなしでやってしまう
                    843:                m68030ATCStat s;
                    844:                s.total = table->atcstat.total;
                    845:                s.tthit = table->atcstat.tthit;
                    846:                s.miss  = table->atcstat.miss;
                    847:                table->atcstat.total = 0;
                    848:                table->atcstat.tthit = 0;
                    849:                table->atcstat.miss  = 0;
                    850: 
                    851:                // こっちはロックする
                    852:                {
                    853:                        std::unique_lock<std::mutex> lock(table->atchist_mtx);
                    854: 
                    855:                        table->atchist.EnqueueForce(s);
                    856:                        if (__predict_false(s.tthit != 0)) {
                    857:                                table->atchist_tt_once_hit = true;
1.1       root      858:                        }
                    859:                }
                    860:        }
1.1.1.17  root      861: 
                    862:        // キャッシュのヒット率。
                    863:        icache->CalcStat();
                    864:        dcache->CalcStat();
                    865: }
                    866: 
                    867: static char
                    868: icache_fc2str(const m68030CacheLine& l)
                    869: {
                    870:        return l.IsSuper() ? 'S' : 'U';
                    871: }
                    872: 
                    873: static char
                    874: dcache_fc2str(const m68030CacheLine& l)
                    875: {
                    876:        return "0U234S67"[l.GetFC()];
1.1       root      877: }
1.1.1.16  root      878: 
1.1.1.18! root      879: // モニタ更新 (68030 キャッシュ)
1.1.1.16  root      880: void
1.1.1.18! root      881: MPU68030Device::MonitorUpdateCache(Monitor *, TextScreen& screen)
1.1.1.16  root      882: {
                    883:        int y;
1.1.1.17  root      884: 
1.1.1.16  root      885:        screen.Clear();
                    886: 
1.1.1.17  root      887:        // <Instruction Cache>
1.1.1.16  root      888:        // 01234567890123456789012345678901234567890123456789
                    889:        // Tag Address  Data
                    890:        // S.012345'00: 00000000 00000000 -------- 00000000
                    891: 
1.1.1.17  root      892:        y = 0;
                    893:        screen.Puts(0, y++, "<Instruction Cache>");
                    894:        y = MonitorUpdateCache1(screen, y, icache.get(), icache_fc2str);
                    895: 
                    896:        y++;
                    897:        screen.Puts(0, y++, "<Data Cache>");
                    898:        MonitorUpdateCache1(screen, y, dcache.get(), dcache_fc2str);
                    899: }
                    900: 
1.1.1.18! root      901: // モニタ更新 (68030 キャッシュ片方の下請け)
1.1.1.17  root      902: int
1.1.1.18! root      903: MPU68030Device::MonitorUpdateCache1(TextScreen& screen, int y,
1.1.1.17  root      904:        m68030Cache *cache, char (*fc2str)(const m68030CacheLine&))
                    905: {
                    906:        screen.Puts(0, y, "Tag Address  Data[0]");
                    907:        screen.Puts(13 + 1 * 9, y, "[1]");
                    908:        screen.Puts(13 + 2 * 9, y, "[2]");
                    909:        screen.Puts(13 + 3 * 9, y, "[3]");
                    910:        y++;
1.1.1.16  root      911: 
1.1.1.17  root      912:        TA attr = cache->enable ? TA::Normal : TA::Disable;
                    913:        for (int idx = 0; idx < cache->line.size(); idx++) {
                    914:                auto& l = cache->line[idx];
                    915:                screen.Print(0, y, attr, "%c.%06x'%x0:",
                    916:                        fc2str(l), (l.TagAddr() >> 8), idx);
1.1.1.16  root      917: 
                    918:                for (int i = 0; i < 4; i++) {
                    919:                        if (l.valid[i]) {
1.1.1.17  root      920:                                screen.Print(13 + 9 * i, y, attr, "%08x", l.data[i]);
1.1.1.16  root      921:                        } else {
1.1.1.17  root      922:                                screen.Puts(13 + 9 * i, y, TA::Disable, "--------");
1.1.1.16  root      923:                        }
                    924:                }
                    925:                y++;
                    926:        }
                    927: 
1.1.1.17  root      928:        // 統計。
                    929:        float hit = 0.0;
                    930:        {
                    931:                std::unique_lock<std::mutex> lock(cache->hist_mtx);
                    932:                int len = cache->hist.Length();
                    933:                if (len != 0) {
                    934:                        for (int i = 0; i < cache->hist.Length(); i++) {
                    935:                                const auto& s = cache->hist.Peek(i);
                    936:                                hit += s.hit;
                    937:                        }
                    938:                        hit /= len;
                    939:                }
                    940:        }
                    941: 
1.1.1.16  root      942:        y++;
1.1.1.17  root      943:        screen.Print(1, y++, attr, "Cache Read Hit            %5.1f%%", hit);
                    944: 
                    945:        return y;
1.1.1.16  root      946: }
1.1.1.18! root      947: 
        !           948: 
        !           949: //
        !           950: // 68040
        !           951: //
        !           952: 
        !           953: // コンストラクタ
        !           954: MPU68040Device::MPU68040Device()
        !           955:        : inherited()
        !           956: {
        !           957:        mpu_type = m680x0MPUType::M68040;
        !           958:        mpu_name = "MC68040";
        !           959:        SetName("MPU(68040)");
        !           960: 
        !           961:        mmu_itt[0].reset(new m68040TT("ITT0", &reg.itt[0]));
        !           962:        mmu_itt[1].reset(new m68040TT("ITT1", &reg.itt[1]));
        !           963:        mmu_dtt[0].reset(new m68040TT("DTT0", &reg.dtt[0]));
        !           964:        mmu_dtt[1].reset(new m68040TT("DTT1", &reg.dtt[1]));
        !           965:        mmu_tc.reset(new m68040TC());
        !           966:        atc_inst.reset(new m68040ATC());
        !           967:        atc_data.reset(new m68040ATC());
        !           968: 
        !           969:        // レジスタモニター (サイズは Init で確定する)
        !           970:        reg_monitor = gMonitorManager->Regist(ID_MONITOR_MPUREG, this);
        !           971:        reg_monitor->func = ToMonitorCallback(&MPU68040Device::MonitorUpdateReg);
        !           972: 
        !           973:        // ATC モニター (Inst/Data)
        !           974:        atc_monitor = gMonitorManager->Regist(ID_MONITOR_MPUATC, this);
        !           975:        atc_monitor->func = ToMonitorCallback(&MPU68040Device::MonitorUpdateATC);
        !           976:        atc_monitor->SetSize(121, 34);
        !           977: }
        !           978: 
        !           979: // デストラクタ
        !           980: MPU68040Device::~MPU68040Device()
        !           981: {
        !           982: }
        !           983: 
        !           984: // モニター更新 (レジスタ)
        !           985: void
        !           986: MPU68040Device::MonitorUpdateReg(Monitor *, TextScreen& screen)
        !           987: {
        !           988:        m68kreg tmp;
        !           989:        uint32 tmp_ppc;
        !           990:        uint32 tmp_state;
        !           991:        FPU40 tmp_fpu40;
        !           992:        int y;
        !           993: 
        !           994:        screen.Clear();
        !           995: 
        !           996:        // ローカルにコピーする。
        !           997:        // ただし一部は reg ではなく cpu クラス本体にある。
        !           998:        tmp = reg;
        !           999:        tmp_ppc = ppc;
        !          1000:        tmp_state = cpu_state;
        !          1001:        tmp_fpu40 = fpu40;
        !          1002: 
        !          1003:        // 共通部分。
        !          1004:        MonitorUpdateRegCommon(screen, tmp, tmp_ppc, tmp_state);
        !          1005: 
        !          1006:        // Cache/MMU 部分。
        !          1007:        y = 4;
        !          1008:        y = MonitorUpdateMMU(screen, y, tmp);
        !          1009: 
        !          1010:        // FPU はある時だけ表示。
        !          1011:        if (HasFPU()) {
        !          1012:                y = MonitorUpdateFPU(screen, y, tmp);
        !          1013:                MonitorUpdateFPU40(screen, y, tmp_fpu40);
        !          1014:        }
        !          1015: }
        !          1016: 
        !          1017: // モニター更新の下請け (Cache/MMU 部分)
        !          1018: int
        !          1019: MPU68040Device::MonitorUpdateMMU(TextScreen& screen, int y, m68kreg& tmp)
        !          1020: {
        !          1021:        int x;
        !          1022: 
        !          1023:        screen.Puts(0, y++, "<MMU/Cache>");
        !          1024:        screen.Print(0, y, "SRP:%08x    TC:%04x(   )", tmp.srp40, tmp.tc40);
        !          1025:        screen.Putc(24, y, TA::OnOff(tmp.tc40 & m68040TC::E) | 'E');
        !          1026:        screen.Putc(26, y, TA::OnOff(tmp.tc40 & m68040TC::P) | 'P');
        !          1027:        y++;
        !          1028:        screen.Print(0, y++, "URP:%08x", tmp.urp40);
        !          1029:        screen.Print(0, y, "MMUSR:%05x'%03x",
        !          1030:                (tmp.mmusr40 >> 12),
        !          1031:                (tmp.mmusr40 & 0xfff));
        !          1032:        x = 16;
        !          1033:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::B) | 'B');
        !          1034:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::G) | 'G');
        !          1035:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::U1)| 'U');
        !          1036:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::U0)| 'U');
        !          1037:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::S) | 'S');
        !          1038:        x++;
        !          1039:        screen.Print(x,  y, "CM%u", (tmp.mmusr40 & m68040MMUSR::CM) >> 5);
        !          1040:        x += 4;
        !          1041:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::M) | 'M');
        !          1042:        screen.Putc(x++, y, '-');
        !          1043:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::W) | 'W');
        !          1044:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::T) | 'T');
        !          1045:        screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::R) | 'R');
        !          1046:        y++;
        !          1047: 
        !          1048:        screen.Print(0, y, "CACR:%08x(", tmp.cacr);
        !          1049:        screen.Puts(14, y, TA::OnOff(tmp.cacr & M68040::CACR_DE), "DE");
        !          1050:        screen.Puts(17, y, TA::OnOff(tmp.cacr & M68040::CACR_IE), "IE");
        !          1051:        screen.Putc(19, y, ')');
        !          1052:        y++;
        !          1053: 
        !          1054:        y -= 4;
        !          1055:        x = 33;
        !          1056:        MonitorUpdateTT(screen, x, y++, "ITT0", tmp.itt[0]);
        !          1057:        MonitorUpdateTT(screen, x, y++, "ITT1", tmp.itt[1]);
        !          1058:        MonitorUpdateTT(screen, x, y++, "DTT0", tmp.dtt[0]);
        !          1059:        MonitorUpdateTT(screen, x, y++, "DTT1", tmp.dtt[1]);
        !          1060: 
        !          1061:        return y;
        !          1062: }
        !          1063: 
        !          1064: // *TTn 1つ分の下請け。
        !          1065: void
        !          1066: MPU68040Device::MonitorUpdateTT(TextScreen& screen, int x, int y,
        !          1067:        const char *name, uint32 tt)
        !          1068: {
        !          1069:        bool e = (tt & m68040TT::E);
        !          1070: 
        !          1071:        screen.Print(x, y, "%s:%08x(", name, tt);
        !          1072:        x += 14;
        !          1073:        screen.Putc(x++, y, TA::OnOff(e) | 'E');
        !          1074:        x++;
        !          1075:        screen.Print(x, y, (e ? TA::Normal : TA::Disable),
        !          1076:                "Base=$%02x Mask=$%02x", (tt >> 24), (tt >> 16) & 0xff);
        !          1077: 
        !          1078:        x += 18;
        !          1079:        if (e) {
        !          1080:                screen.Putc(x++, y, TA::OnOff(tt & m68040TT::S_IGN) | 'S');
        !          1081:                screen.Putc(x++, y, TA::OnOff(tt & m68040TT::S_FC2) | 'S');
        !          1082:                screen.Putc(x++, y, TA::OnOff(tt & m68040TT::U1)    | 'U');
        !          1083:                screen.Putc(x++, y, TA::OnOff(tt & m68040TT::U0)    | 'U');
        !          1084:                x++;
        !          1085:                screen.Print(x, y, "CM%u", (tt & m68040TT::CM) >> 5);
        !          1086:                x += 4;
        !          1087:                screen.Putc(x++, y, TA::OnOff(tt & m68040TT::W)     | 'W');
        !          1088:        } else {
        !          1089:                screen.Puts(x, y, TA::Disable, "---- --- -");
        !          1090:                x += 10;
        !          1091:        }
        !          1092:        screen.Putc(x, y, ')');
        !          1093: }
        !          1094: 
        !          1095: void
        !          1096: MPU68040Device::CalcStat()
        !          1097: {
        !          1098: }

unix.superglobalmegacorp.com

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