Annotation of nono/vm/mpu.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2017 [email protected]
        !             4: //
        !             5: // MPU
        !             6: //
        !             7: 
        !             8: #include <math.h>
        !             9: #include "mpu.h"
        !            10: #include "m68030excep.h"
        !            11: #include "debugger.h"
        !            12: #include "scheduler.h"
        !            13: #include "vm.h"
        !            14: #include "configfile.h"
        !            15: 
        !            16: MPUDevice *gMPU;
        !            17: MPUATC *gMPUATC;
        !            18: MPUBrHist *gMPUBrHist;
        !            19: 
        !            20: // コンストラクタ
        !            21: //
        !            22: // reset_vector にはリセットベクタの番地を指定する。
        !            23: // 本来の MPU の動作は、リセット例外時にメモリの $0, $4 番地 (もっと言えば
        !            24: // FC がプログラム空間の) から SP, PC を読み込むのだが、そのためにメモリ空間
        !            25: // を切り替える処理はリセット時にしか必要ないわりに結構手間である。そしてこの
        !            26: // m68k 恒例のブートストラップ動作はソフトウェア的には一切観測する手段がない。
        !            27: // であれば、リセット例外時にこのアドレスから SP, PC の値を直接読み込んだと
        !            28: // しても動作にはまったく違いは出ない。そしてバス・メモリ空間の実装も簡略化
        !            29: // できる。すごい楽。
        !            30: MPUDevice::MPUDevice(uint32 reset_vector)
        !            31: {
        !            32:        logname = "mpu";
        !            33:        devname = "MPU";
        !            34:        monitor.Init(78, 16);
        !            35: 
        !            36:        cpu = m68030_init(reset_vector);
        !            37: 
        !            38:        // モニタ用の別オブジェクト
        !            39:        gMPUATC = new MPUATC(cpu);
        !            40:        gMPUBrHist = new MPUBrHist(cpu);
        !            41: }
        !            42: 
        !            43: // デストラクタ
        !            44: MPUDevice::~MPUDevice()
        !            45: {
        !            46: }
        !            47: 
        !            48: bool
        !            49: MPUDevice::Init()
        !            50: {
        !            51:        if (gVM->GetType() == VM::TYPE_LUNA) {
        !            52:                // LUNA は 68881 固定
        !            53:                cpu->has_fpu = 1;
        !            54:        } else {
        !            55:                // X68k は設定ファイルで指定
        !            56:                cpu->has_fpu = gConfig->ReadInt("mpu_has_fpu");
        !            57:        }
        !            58:        return true;
        !            59: }
        !            60: 
        !            61: // リセット
        !            62: // (MPU が動くのはこの後 Scheduler::Run() を発行した後)
        !            63: void
        !            64: MPUDevice::ResetHard()
        !            65: {
        !            66:        m68030_exception_reset(cpu);
        !            67: }
        !            68: 
        !            69: // MPU を request で指定されたクロックサイクルだけ実行する。
        !            70: // 今回の実行サイクル数が request を越えた命令境界まで実行するので
        !            71: // 実際には少しはみ出る。
        !            72: // また実行中にデバイスアクセスなどによりスケジューラにイベントが
        !            73: // 追加されるとその次の命令境界で処理を打ち切って戻ってくる。
        !            74: // 戻り値は CPU の outer フラグ。
        !            75: uint32
        !            76: MPUDevice::Run(uint64 request)
        !            77: {
        !            78:        return m68030_run(cpu, request);
        !            79: }
        !            80: 
        !            81: // 割り込み発生を MPU に通知 (オートベクタ)
        !            82: void
        !            83: MPUDevice::Interrupt(int level)
        !            84: {
        !            85:        int vector = M68K_EXCEP_LEVEL_BASE + level;
        !            86:        m68030_interrupt(cpu, level, vector);
        !            87: }
        !            88: 
        !            89: // 割り込み発生を MPU に通知 (ベクタ)
        !            90: void
        !            91: MPUDevice::Interrupt(int level, int vector)
        !            92: {
        !            93:        m68030_interrupt(cpu, level, vector);
        !            94: }
        !            95: 
        !            96: // A-Line 命令エミュレーションのコールバックを指定。
        !            97: void
        !            98: MPUDevice::SetALineCallback(bool (*callback)(m68kcpu *, void*), void *arg)
        !            99: {
        !           100:        cpu->aline_callback = callback;
        !           101:        cpu->aline_arg = arg;
        !           102: }
        !           103: 
        !           104: // F-Line 命令エミュレーションのコールバックを指定。
        !           105: void
        !           106: MPUDevice::SetFLineCallback(bool (*callback)(m68kcpu *, void*), void *arg)
        !           107: {
        !           108:        cpu->fline_callback = callback;
        !           109:        cpu->fline_arg = arg;
        !           110: }
        !           111: 
        !           112: // モニター更新 (レジスタウィンドウ)
        !           113: bool
        !           114: MPUDevice::MonitorUpdate()
        !           115: {
        !           116:        m68kreg reg;
        !           117:        uint32 ppc;
        !           118:        int x;
        !           119:        int y;
        !           120: 
        !           121:        monitor.Clear();
        !           122: 
        !           123:        // ローカルにコピー
        !           124:        // ただし PPC だけ reg 構造体ではなく cpu クラス側にある
        !           125:        reg = cpu->reg;
        !           126:        ppc = cpu->ppc;
        !           127: 
        !           128:        // データレジスタ、アドレスレジスタ
        !           129:        for (int i = 0; i < 4; i++) {
        !           130:                monitor.Print(0, i, "D%d:%08x D%d:%08x  A%d:%08x A%d:%08x",
        !           131:                        i + 0, reg.da[i],
        !           132:                        i + 4, reg.da[i + 4],
        !           133:                        i + 0, reg.da[i + 8],
        !           134:                        i + 4, reg.da[i + 12]);
        !           135:        }
        !           136: 
        !           137:        // 5列目
        !           138:        x = 50;
        !           139:        // SR
        !           140:        monitor.Print(x, 0, "SR:%04x(%c%c%c%c%c)",
        !           141:                (reg.sr_h() | reg.ccr.Get()),
        !           142:                (reg.ccr.IsX()) ? 'X' : '-',
        !           143:                (reg.ccr.IsN()) ? 'N' : '-',
        !           144:                (reg.ccr.IsZ()) ? 'Z' : '-',
        !           145:                (reg.ccr.IsV()) ? 'V' : '-',
        !           146:                (reg.ccr.IsC()) ? 'C' : '-');
        !           147: 
        !           148:        // VBR
        !           149:        monitor.Print(x, 1, "VBR:%08x", reg.vbr);
        !           150: 
        !           151:        // *SP
        !           152:        uint ms = (reg.s ? 2 : 0) | (reg.m ? 1 : 0); // T1 T0 S M
        !           153:        if (ms == 3) {
        !           154:                // Supervisor (Master) mode (A7=MSP, USP/ISP)
        !           155:                monitor.Print(x, 2, TA::Disable, "USP:%08x", reg.usp);
        !           156:                monitor.Print(x, 3, TA::Disable, "ISP:%08x", reg.isp);
        !           157:        } else if (ms == 2) {
        !           158:                // Supervisor (Interrupt) mode (A7=ISP, USP/MSP)
        !           159:                monitor.Print(x, 2, TA::Disable, "USP:%08x", reg.usp);
        !           160:                monitor.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp);
        !           161:        } else {
        !           162:                // User mode (A7=USP, ISP/MSP)
        !           163:                monitor.Print(x, 2, TA::Disable, "ISP:%08x", reg.isp);
        !           164:                monitor.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp);
        !           165:        }
        !           166: 
        !           167:        // 6列目
        !           168:        // PC:  01234567
        !           169:        // SFC:1   DFC:1
        !           170:        // CACR:01234567
        !           171:        // CAAR:01234567
        !           172:        x = 66;
        !           173:        monitor.Print(x, 0, "PC:  %08x", ppc);
        !           174:        monitor.Print(x, 1, "SFC:%d  DFC:%d", reg.sfc, reg.dfc);
        !           175:        monitor.Print(x, 2, "CACR:%08x", reg.cacr);
        !           176:        monitor.Print(x, 3, "CAAR:%08x", reg.caar);
        !           177: 
        !           178:        // XXX どこに置くのがいいか
        !           179:        if (reg.state == 0) {
        !           180:                monitor.Print(25, 4, "State: Running");
        !           181:        } else if (reg.state == CPU_REQ_STOP) {
        !           182:                monitor.Print(25, 4, "State: STOP instruction");
        !           183:        } else if (reg.state == CPU_REQ_HALT) {
        !           184:                monitor.Print(25, 4, "State: Double Bus Fault");
        !           185:        }
        !           186: 
        !           187:        // MMU
        !           188:        x = 0;
        !           189:        y = 4;
        !           190:        monitor.Print(x, y++, "<MMU>");
        !           191:        monitor.Print(x, y,     "SRP:%08x_%08x", reg.srp.h, reg.srp.l);
        !           192:        monitor.Print(x, y + 1, "CRP:%08x_%08x", reg.crp.h, reg.crp.l);
        !           193:        x += 23;
        !           194:        for (int i = 0; i < 2; i++) {
        !           195:                uint32 tt = reg.tt[i];
        !           196:                monitor.Print(x, y + i, "TT%d:%08x(%c%c%c)",
        !           197:                        i, tt,
        !           198:                        (tt & m68030TT::E)   ? 'E' : '-',
        !           199:                        (tt & m68030TT::CI)  ? 'C' : '-',
        !           200:                        (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW)  ? 'R' : 'W'));
        !           201:        }
        !           202:        x += 19;
        !           203:        monitor.Print(x, y, "TC:%08x(%c%c%c)",
        !           204:                reg.tc,
        !           205:                (reg.tc & m68030TC::TC_E)   ? 'E' : '-',
        !           206:                (reg.tc & m68030TC::TC_SRE) ? 'S' : '-',
        !           207:                (reg.tc & m68030TC::TC_FCL) ? 'F' : '-');
        !           208:        monitor.Print(x, y + 1, "MMUSR: %04x(%c%c%c%c%c%c%c N=%d)",
        !           209:                reg.mmusr,
        !           210:                (reg.mmusr & m68030MMUSR::B) ? 'B' : '-',
        !           211:                (reg.mmusr & m68030MMUSR::L) ? 'L' : '-',
        !           212:                (reg.mmusr & m68030MMUSR::S) ? 'S' : '-',
        !           213:                (reg.mmusr & m68030MMUSR::W) ? 'W' : '-',
        !           214:                (reg.mmusr & m68030MMUSR::I) ? 'I' : '-',
        !           215:                (reg.mmusr & m68030MMUSR::M) ? 'M' : '-',
        !           216:                (reg.mmusr & m68030MMUSR::T) ? 'T' : '-',
        !           217:                (reg.mmusr & m68030MMUSR::N));
        !           218: 
        !           219:        // FPU
        !           220:        x = 0;
        !           221:        y = 7;
        !           222:        monitor.Print(x, y++, "<FPU>");
        !           223:        for (int i = 0; i < 8; i++) {
        !           224:                monitor.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)",
        !           225:                        i,
        !           226:                        reg.fpframe.fpf_regs[i * 3 + 0] >> 16,
        !           227:                        reg.fpframe.fpf_regs[i * 3 + 1],
        !           228:                        reg.fpframe.fpf_regs[i * 3 + 2],
        !           229:                        "not yet");
        !           230:        }
        !           231: 
        !           232:        x = 51;
        !           233: 
        !           234:        // FPCR
        !           235:        static const char * const rpstr[] = {
        !           236:                ".EXT",
        !           237:                ".SGL",
        !           238:                ".DBL",
        !           239:                ".???",
        !           240:        };
        !           241:        static const char * const rmstr[] = {
        !           242:                "Near",
        !           243:                "Zero",
        !           244:                "Minus",
        !           245:                "Plus",
        !           246:        };
        !           247:        uint32 fpcr = reg.fpframe.fpf_fpcr;
        !           248:        monitor.Print(x, y++, "FPCR:%04x", fpcr);
        !           249:        monitor.Print(x + 2, y++, "%s %s %s %s %s %s %s %s",
        !           250:                (fpcr & 0x8000) ? "BS" : "--",
        !           251:                (fpcr & 0x4000) ? "SN" : "--",
        !           252:                (fpcr & 0x2000) ? "OP" : "--",
        !           253:                (fpcr & 0x1000) ? "OV" : "--",
        !           254:                (fpcr & 0x0800) ? "UF" : "--",
        !           255:                (fpcr & 0x0400) ? "DZ" : "--",
        !           256:                (fpcr & 0x0200) ? "I2" : "--",
        !           257:                (fpcr & 0x0100) ? "I1" : "--");
        !           258:        monitor.Print(x + 2, y++, "RP=%s RM=%s",
        !           259:                rpstr[(fpcr >> 6) & 3],
        !           260:                rmstr[(fpcr >> 4) & 3]);
        !           261: 
        !           262:        // FPSR
        !           263:        uint32 fpsr = reg.fpframe.fpf_fpsr;
        !           264:        uint32 cc = fpsr >> 24;
        !           265:        monitor.Print(x, y++, "FPSR:%08x", fpsr);
        !           266:        monitor.Print(x + 2, y++, "%c %c %s %s Q=$%02x",
        !           267:                (cc & 0x08) ? 'N' : '-',
        !           268:                (cc & 0x04) ? 'Z' : '-',
        !           269:                (cc & 0x02) ? "Inf" : "---",
        !           270:                (cc & 0x01) ? "NAN" : "---",
        !           271:                (fpsr >> 16) & 0xff);
        !           272:        monitor.Print(x + 2, y++, "%s %s %s %s %s %s %s %s",
        !           273:                (fpsr & 0x8000) ? "BS" : "--",
        !           274:                (fpsr & 0x4000) ? "SN" : "--",
        !           275:                (fpsr & 0x2000) ? "OP" : "--",
        !           276:                (fpsr & 0x1000) ? "OV" : "--",
        !           277:                (fpsr & 0x0800) ? "UF" : "--",
        !           278:                (fpsr & 0x0400) ? "DZ" : "--",
        !           279:                (fpsr & 0x0200) ? "I2" : "--",
        !           280:                (fpsr & 0x0100) ? "I1" : "--");
        !           281:        monitor.Print(x + 2, y++, "%s %s %s %s %s",
        !           282:                (fpsr & 0x80) ? "IOP"  : "---",
        !           283:                (fpsr & 0x40) ? "OVFL" : "----",
        !           284:                (fpsr & 0x20) ? "UNFL" : "----",
        !           285:                (fpsr & 0x10) ? "DZ"   : "--",
        !           286:                (fpsr & 0x08) ? "INEX" : "----");
        !           287: 
        !           288:        // FPIAR
        !           289:        monitor.Print(x, y++, "FPIAR:%08x", reg.fpframe.fpf_fpiar);
        !           290: 
        !           291:        return true;
        !           292: }
        !           293: 
        !           294: // CPU 側からのコールバック。RESET 命令ハンドラ
        !           295: void
        !           296: m68030_reset_inst(m68kcpu *cpu)
        !           297: {
        !           298:        gVM->ResetSoft();
        !           299: }
        !           300: 
        !           301: //
        !           302: // ATC モニタ
        !           303: //
        !           304: MPUATC::MPUATC(m68kcpu *arg)
        !           305: {
        !           306:        cpu = arg;
        !           307: #if !defined(ATC_SINGLE)
        !           308:        monitor.Init(131, m68030ATCTable::LINES + 3);
        !           309: #else
        !           310:        monitor.Init(31, 24);
        !           311: #endif
        !           312: }
        !           313: 
        !           314: bool
        !           315: MPUATC::MonitorUpdate()
        !           316: {
        !           317:        m68030ATCTable *table;
        !           318: #if !defined(ATC_SINGLE)
        !           319:        struct {
        !           320:                int fc;
        !           321:                const char *name;
        !           322:        } fclist[] = {
        !           323:                { 1,    "User/Data" },
        !           324:                { 2,    "User/Program" },
        !           325:                { 5,    "Super/Data" },
        !           326:                { 6,    "Super/Program" },
        !           327:        };
        !           328: 
        !           329:        monitor.Clear();
        !           330: 
        !           331:        // 行数は左端にだけ
        !           332:        for (int i = 0; i < m68030ATCTable::LINES; i++) {
        !           333:                monitor.Print(0, i + 2, "%02d:", i);
        !           334:        }
        !           335: 
        !           336:        for (int t = 0; t < countof(fclist); t++) {
        !           337:                int x = t * 32 + 4;
        !           338:                int fc = fclist[t].fc;
        !           339:                const char *name = fclist[t].name;
        !           340:                double r;
        !           341:                int i;
        !           342: 
        !           343:                table = &cpu->atc.tables[fc];
        !           344:                monitor.Print(x, 0, "FC=%d %s", fc, name);
        !           345:                monitor.Print(x, 1, "LAddr    PAddr   Flag Hit%%  Age");
        !           346:                // 先に統計用の母数を計算
        !           347:                uint64 total = 0;
        !           348:                for (i = 0; i < countof(table->hit); i++) {
        !           349:                        total += table->hit[i];
        !           350:                }
        !           351:                total += table->hit_head;
        !           352: 
        !           353:                // エントリ表示
        !           354:                for (i = 0; i < countof(table->line); i++) {
        !           355:                        m68030ATCLine& a = table->line[i];
        !           356:                        int attr;
        !           357:                        if (a.IsInvalid()) {
        !           358:                                attr = TA::Disable;
        !           359:                        } else if (table->head == &a) {
        !           360:                                attr = TA::Em;
        !           361:                        } else {
        !           362:                                attr = TA::Normal;
        !           363:                        }
        !           364: 
        !           365:                        monitor.Print(x, i + 2, attr, "%08x %08x %c%c%c",
        !           366:                                a.GetLAddr(),
        !           367:                                a.GetPAddr(),
        !           368:                                a.IsBusError() ? 'B' : '-',
        !           369:                                a.IsWProtect() ? 'P' : '-',
        !           370:                                a.IsModified() ? 'M' : '-');
        !           371:                }
        !           372:                // ヘッドのヒット率
        !           373:                monitor.Print(x + 0, i + 2, "head");
        !           374:                r = (double)table->hit_head * 100 / total;
        !           375:                if (!isnan(r)) {
        !           376:                        monitor.Print(x + 5, i + 2, "%4.1f%%", r);
        !           377:                }
        !           378:                // 配列のヒット率とミス率
        !           379:                monitor.Print(x + 17, i + 2, "miss");
        !           380:                for (i = 0; i < countof(table->hit); i++) {
        !           381:                        r = (double)(table->hit[i] * 100) / total;
        !           382:                        if (!isnan(r)) {
        !           383:                                monitor.Print(x + 22, i + 2, "%4.1f%%", r);
        !           384:                        }
        !           385:                }
        !           386:                // カウンタ
        !           387:                // 分かりやすさのため最大値からの差(距離)を表示
        !           388:                for (i = 0; i < countof(table->line); i++) {
        !           389:                        m68030ATCLine& a = table->line[i];
        !           390:                        if (!a.IsInvalid()) {
        !           391:                                monitor.Print(x + 27, i + 2, "%4d", table->head->age - a.age);
        !           392:                        }
        !           393:                }
        !           394:        }
        !           395: #else
        !           396:        m68030ATCLine *a;
        !           397:        int i;
        !           398: 
        !           399:        table = &cpu->atc.tables[0];
        !           400:        monitor.Clear();
        !           401: 
        !           402:        monitor.Print(0, 0, "No. FC    LAddr    PAddr   Flag");
        !           403:        for (a = table->head, i = 0; a; a = a->next, i++) {
        !           404:                monitor.Print(0, i + 1, "%02d:", i);
        !           405:                if (!a->IsInvalid()) {
        !           406:                        char dp;
        !           407:                        switch (a->fc & 3) {
        !           408:                         case 1:        dp = 'D';       break;
        !           409:                         case 2:        dp = 'P';       break;
        !           410:                         default:       dp = '?';       break;
        !           411:                        }
        !           412:                        monitor.Print(4, i + 1, "%d(%c%c):%08x %08x %c%c%c",
        !           413:                                a->fc,
        !           414:                                (a->fc & 4) ? 'S' : 'U',
        !           415:                                dp,
        !           416:                                a->GetLAddr(), a->GetPAddr(),
        !           417:                                a->IsBusError() ? 'B' : '-',
        !           418:                                a->IsWProtect() ? 'W' : '-',
        !           419:                                a->IsModified() ? 'M' : '-');
        !           420:                }
        !           421:        }
        !           422: #endif
        !           423:        return true;
        !           424: }
        !           425: 
        !           426: //
        !           427: // ブランチ履歴モニタ
        !           428: //
        !           429: MPUBrHist::MPUBrHist(m68kcpu *arg)
        !           430: {
        !           431:        cpu = arg;
        !           432:        monitor.Init(70, 16);
        !           433: }
        !           434: 
        !           435: bool
        !           436: MPUBrHist::MonitorUpdate()
        !           437: {
        !           438:        int i;
        !           439:        uint8 t;
        !           440: 
        !           441:        // 0         1         2         3         4         5         6
        !           442:        // 0123456789012345678901234567890123456789012345678901234567890123456789
        !           443:        // 01 $01234567->$01234567 x123456789  16 $01234567->$01234567 x123456789
        !           444: 
        !           445:        monitor.Clear();
        !           446: 
        !           447:        // top は現在の位置。
        !           448:        // brhist[] は古い順に書き込まれるが、表示は新しい順にしたい。
        !           449:        // ブランチ履歴は書き込み最適化のため256エントリあるが、そんなに
        !           450:        // 奥のほうが気になることはないだろう。
        !           451:        t = cpu->brhist_top;
        !           452:        for (i = 0; i < 32; i++) {
        !           453:                m68kbrhist& h = cpu->brhist[t--];
        !           454:                int x = (i / 16) * 36;
        !           455:                int y = i % 16;
        !           456:                if (h.count == 0) {
        !           457:                        continue;
        !           458:                }
        !           459:                monitor.Print(x, y, "%02d:$%08x->$%08x", i,
        !           460:                        h.from, h.to);
        !           461:                if (h.count > 1) {
        !           462:                        monitor.Print(x + 24, y, "x%9u", h.count);
        !           463:                }
        !           464:        }
        !           465:        return true;
        !           466: }

unix.superglobalmegacorp.com

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