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

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

unix.superglobalmegacorp.com

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