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

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

unix.superglobalmegacorp.com

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