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

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

unix.superglobalmegacorp.com

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