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

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2022 nono project
        !             4: // Licensed under nono-license.txt
        !             5: //
        !             6: 
        !             7: //
        !             8: // MPU (HD647180)
        !             9: //
        !            10: 
        !            11: #include "mpu64180.h"
        !            12: #include "debugger.h"
        !            13: #include "hd647180.h"
        !            14: #include "pio.h"
        !            15: #include "scheduler.h"
        !            16: #include "xpbus.h"
        !            17: 
        !            18: // コンストラクタ
        !            19: MPU64180Device::MPU64180Device()
        !            20:        : inherited(OBJ_MPUXP)
        !            21: {
        !            22:        ClearAlias();
        !            23:        AddAlias("XP");
        !            24:        AddAlias("HD647180");
        !            25: 
        !            26:        // 6.144MHz = 162.7604… [nsec]
        !            27:        clock_nsec = 163;
        !            28: 
        !            29:        // 命令実行イベント。func, time は都度設定する。
        !            30:        exec_event.Regist("XP(HD647180) Execute");
        !            31: 
        !            32:        // タイマーイベント。time は都度設定する。
        !            33:        timer_event.func = ToEventCallback(&MPU64180Device::TimerCallback);
        !            34:        timer_event.Regist("XP(HD647180) Timer");
        !            35: 
        !            36:        // レジスタモニター
        !            37:        reg_monitor.func = ToMonitorCallback(&MPU64180Device::MonitorUpdateReg);
        !            38:        reg_monitor.SetSize(38, 6);
        !            39:        reg_monitor.Regist(ID_MONITOR_XPREG);
        !            40: 
        !            41:        // I/O モニター
        !            42:        io_monitor.func = ToMonitorCallback(&MPU64180Device::MonitorUpdateIO);
        !            43:        io_monitor.SetSize(55, 20);
        !            44:        io_monitor.Regist(ID_MONITOR_XPIO);
        !            45: 
        !            46:        // 割り込みモニター
        !            47:        intr_monitor.func = ToMonitorCallback(&MPU64180Device::MonitorUpdateIntr);
        !            48:        intr_monitor.SetSize(64, 18);
        !            49:        intr_monitor.Regist(ID_MONITOR_XPINTR);
        !            50: }
        !            51: 
        !            52: // デストラクタ
        !            53: MPU64180Device::~MPU64180Device()
        !            54: {
        !            55: }
        !            56: 
        !            57: // ログ表示を差し替える。
        !            58: // こっちでは XP の PC を表示したい。
        !            59: void
        !            60: MPU64180Device::putlogn(const char *fmt, ...) const
        !            61: {
        !            62:        char buf[1024];
        !            63:        va_list ap;
        !            64:        uint64 vt;
        !            65:        int len;
        !            66: 
        !            67:        vt = scheduler->GetVirtTime();
        !            68:        len = snprintf(buf, sizeof(buf), "%4d.%03d'%03d'%03d %04x %s ",
        !            69:                (int)(vt / 1000 / 1000 / 1000),
        !            70:                (int)((vt / 1000 / 1000) % 1000),
        !            71:                (int)((vt / 1000) % 1000),
        !            72:                (int)(vt % 1000),
        !            73:                GetPPC(),
        !            74:                GetName().c_str());
        !            75: 
        !            76:        va_start(ap, fmt);
        !            77:        vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
        !            78:        va_end(ap);
        !            79: 
        !            80:        WriteLog(buf);
        !            81: }
        !            82: 
        !            83: // 初期化
        !            84: bool
        !            85: MPU64180Device::Init()
        !            86: {
        !            87:        if (inherited::Init() == false) {
        !            88:                return false;
        !            89:        }
        !            90: 
        !            91:        debugger = GetDebugger();
        !            92:        pio0 = GetPIO0Device();
        !            93:        xpbus = GetXPbusDevice();
        !            94: 
        !            95:        scheduler->ConnectMessage(MessageID::MPU_TRACE_XP, this,
        !            96:                ToMessageCallback(&MPU64180Device::TraceMessage));
        !            97: 
        !            98:        return true;
        !            99: }
        !           100: 
        !           101: // こっちは本体リセットと電源オン
        !           102: void
        !           103: MPU64180Device::ResetHard(bool poweron)
        !           104: {
        !           105:        if (poweron) {
        !           106:                used_cycle = 0;
        !           107: 
        !           108:                // 履歴は電源オン時だけ初期化。
        !           109:                exhist.Clear();
        !           110:                brhist.Clear();
        !           111:        }
        !           112: 
        !           113:        // リセット信号でさすがにリセットされるよな?
        !           114:        Reset();
        !           115: }
        !           116: 
        !           117: // RESET 信号を変化させる。
        !           118: // new_reset が true ならアサート、false ならネゲート。
        !           119: void
        !           120: MPU64180Device::ChangeRESET(bool new_reset)
        !           121: {
        !           122:        if (new_reset) {
        !           123:                AssertRESET();
        !           124:        } else {
        !           125:                NegateRESET();
        !           126:        }
        !           127: }
        !           128: 
        !           129: // RESET 信号をアサートする。
        !           130: void
        !           131: MPU64180Device::AssertRESET()
        !           132: {
        !           133:        if (opmode != OpMode::Reset) {
        !           134:                Reset();
        !           135:        }
        !           136: }
        !           137: 
        !           138: // RESET 信号をネゲートする。
        !           139: void
        !           140: MPU64180Device::NegateRESET()
        !           141: {
        !           142:        if (opmode == OpMode::Reset) {
        !           143:                // リセット解除がタイマーの開始時刻
        !           144:                timer_epoch = scheduler->GetVirtTime();
        !           145: 
        !           146:                EnterNormal();
        !           147:        }
        !           148: }
        !           149: 
        !           150: // プロセッサをリセット
        !           151: // (どうすべ)
        !           152: void
        !           153: MPU64180Device::Reset()
        !           154: {
        !           155:        putlog(1, "RESET");
        !           156:        opmode = OpMode::Reset;
        !           157: 
        !           158:        // 命令実行サイクルを停止
        !           159:        exec_event.SetName("XP(HD647180) Reset");
        !           160:        scheduler->StopEvent(exec_event);
        !           161: 
        !           162:        // 汎用レジスタの値は不定。目印として $cc で埋めておく。
        !           163:        memset((void *)&reg, 0xcc, sizeof(reg));
        !           164:        reg.f.Set(0xcc);
        !           165:        reg.ex.f.Set(0xcc);
        !           166: 
        !           167:        ppc = 0;
        !           168:        reg.pc = 0;
        !           169:        reg.sp = 0;
        !           170:        reg_i = 0;
        !           171:        reg_r = 0;
        !           172:        ief1 = false;
        !           173:        ief2 = false;
        !           174:        int0mode = 0;
        !           175: 
        !           176:        for (int i = 0; i < timer.size(); i++) {
        !           177:                timer[i].reload = 0xffff;
        !           178:                timer[i].count = 0xffff;
        !           179:                timer[i].running = false;
        !           180:                timer[i].intr_enable = false;
        !           181:                timer[i].tif = 0;
        !           182:                // 一時レジスタの初期値は定義されてないがとりあえず
        !           183:                timer[i].tmpcount = 0xffff;
        !           184:        }
        !           185:        MakeActiveTimer();
        !           186:        timer_toc = 0;
        !           187:        scheduler->StopEvent(timer_event);
        !           188: 
        !           189:        memwait = 3;
        !           190:        iowait = 4;
        !           191:        dcntl = 0;
        !           192:        itc_trap = false;
        !           193:        itc_ufo  = false;
        !           194:        itc_ite0 = true;        // ITE0 は初期値 1
        !           195:        itc_ite1 = false;
        !           196:        itc_ite2 = false;
        !           197:        rcr = 0xfc;
        !           198:        commbase = 0;
        !           199:        bankbase = 0;
        !           200:        commarea = 0xf000;
        !           201:        bankarea = 0x0000;
        !           202:        io_address = 0x00;
        !           203: 
        !           204:        memset(&int_counter, 0, sizeof(int_counter));
        !           205: 
        !           206:        xpbus->SetRMCR(0xf0);
        !           207: }
        !           208: 
        !           209: // ノーマルモードに入る。
        !           210: void
        !           211: MPU64180Device::EnterNormal()
        !           212: {
        !           213:        putlog(1, "Normal mode");
        !           214:        opmode = OpMode::Normal;
        !           215: 
        !           216:        SetExec(ToEventCallback(&MPU64180Device::ExecNormal));
        !           217:        exec_event.SetName("XP(HD647180) Execute");
        !           218: 
        !           219:        // 3 クロック後から通常サイクル開始? (HD647180.pdf, p23)
        !           220:        exec_event.time = 3 * clock_nsec;
        !           221:        scheduler->RestartEvent(exec_event);
        !           222: }
        !           223: 
        !           224: // スリープモードに入る。(SLP 命令から呼ばれる)
        !           225: void
        !           226: MPU64180Device::EnterSleep()
        !           227: {
        !           228:        // ExecNormal() 内で StartEvent() をしないに分岐するのは無駄が多いので、
        !           229:        // ここでは一旦コールバックだけ差し替えて、イベントを停止する。
        !           230:        SetExec(ToEventCallback(&MPU64180Device::ExecSleep));
        !           231:        exec_event.SetName("XP(HD647180) Sleep");
        !           232:        exec_event.time = 0;
        !           233: 
        !           234:        // 内蔵デバイスのイベントも停止する。
        !           235:        scheduler->StopEvent(timer_event);
        !           236: }
        !           237: 
        !           238: // スリープモードから抜ける。
        !           239: void
        !           240: MPU64180Device::EnterWakeup()
        !           241: {
        !           242:        // 復帰処理のため一旦 Wakeup へ。
        !           243:        SetExec(ToEventCallback(&MPU64180Device::ExecWakeup));
        !           244:        exec_event.time = 3 * clock_nsec;
        !           245: 
        !           246:        scheduler->StartEvent(exec_event);
        !           247: }
        !           248: 
        !           249: // スリープに入る時のイベント
        !           250: void
        !           251: MPU64180Device::ExecSleep(Event& ev)
        !           252: {
        !           253:        // 実行イベントを停止する。(StartEvent() を呼ばない)
        !           254: }
        !           255: 
        !           256: // スリープから復帰するイベント
        !           257: void
        !           258: MPU64180Device::ExecWakeup(Event& ev)
        !           259: {
        !           260:        // EI なら、割り込み処理から再開。
        !           261:        // DI なら、次の命令から再開。
        !           262:        if (GetIEF1()) {
        !           263:                DoInterrupt();
        !           264:        }
        !           265: 
        !           266:        EnterNormal();
        !           267: }
        !           268: 
        !           269: // MPU トレース状態設定要求メッセージ
        !           270: void
        !           271: MPU64180Device::TraceMessage(MessageID msgid, uint32 arg)
        !           272: {
        !           273:        // リセット中は SetTrace しない
        !           274:        if (opmode == OpMode::Reset) {
        !           275:                return;
        !           276:        }
        !           277: 
        !           278:        // デバッガから MPU のトレース状態を設定してくれと言われた
        !           279:        SetTrace((bool)arg);
        !           280: }
        !           281: 
        !           282: // トレース実行
        !           283: void
        !           284: MPU64180Device::ExecTrace(Event& ev)
        !           285: {
        !           286:        debugger->ExecXP();
        !           287:        (this->*exec_func)(ev);
        !           288: }
        !           289: 
        !           290: // 実行コールバックを設定する。
        !           291: void
        !           292: MPU64180Device::SetExec(EventCallback_t new_exec)
        !           293: {
        !           294:        exec_func = new_exec;
        !           295: 
        !           296:        if (exec_event.func != ToEventCallback(&MPU64180Device::ExecTrace)) {
        !           297:                exec_event.func = exec_func;
        !           298:        }
        !           299: }
        !           300: 
        !           301: // トレース状態を設定する。
        !           302: void
        !           303: MPU64180Device::SetTrace(bool enable)
        !           304: {
        !           305:        EventCallback_t func;
        !           306: 
        !           307:        if (enable) {
        !           308:                func = ToEventCallback(&MPU64180Device::ExecTrace);
        !           309:        } else {
        !           310:                func = exec_func;
        !           311:        }
        !           312:        exec_event.func = func;
        !           313: }
        !           314: 
        !           315: // IX/IY 分を考慮したサイクル数
        !           316: void
        !           317: MPU64180Device::CYCLE_IX(int cycle_hl, int cycle_ix)
        !           318: {
        !           319:        if (__predict_true(ixiy == USE_HL)) {
        !           320:                used_cycle += cycle_hl;
        !           321:        } else {
        !           322:                used_cycle += cycle_ix;
        !           323:        }
        !           324: }
        !           325: 
        !           326: uint32
        !           327: MPU64180Device::Fetch8()
        !           328: {
        !           329:        uint8 data = Read8(reg.pc++);
        !           330:        ops.push_back(data);
        !           331:        if (__predict_false(reg.pc > 0xffff)) {
        !           332:                reg.pc = 0;
        !           333:        }
        !           334:        return data;
        !           335: }
        !           336: 
        !           337: uint32
        !           338: MPU64180Device::Read8(uint32 laddr)
        !           339: {
        !           340:        uint32 paddr = Translate(laddr);
        !           341:        // XXX 内蔵 RAM はノーウェイト
        !           342:        CYCLE(memwait);
        !           343:        return xpbus->Read8(paddr);
        !           344: }
        !           345: 
        !           346: uint32
        !           347: MPU64180Device::Write8(uint32 laddr, uint32 data)
        !           348: {
        !           349:        uint32 paddr = Translate(laddr);
        !           350:        // XXX 内蔵 RAM はノーウェイト
        !           351:        CYCLE(memwait);
        !           352:        return xpbus->Write8(paddr, data);
        !           353: }
        !           354: 
        !           355: uint32
        !           356: MPU64180Device::Peek8(uint32 laddr) const
        !           357: {
        !           358:        uint32 addr = TranslatePeek(laddr);
        !           359:        return xpbus->Peek8(addr);
        !           360: }
        !           361: 
        !           362: uint32
        !           363: MPU64180Device::Peek16(uint32 laddr) const
        !           364: {
        !           365:        uint32 data;
        !           366:        data  = Peek8(laddr);
        !           367:        data |= Peek8(laddr + 1) << 8;
        !           368:        return data;
        !           369: }
        !           370: 
        !           371: // アドレス変換
        !           372: uint32
        !           373: MPU64180Device::Translate(uint32 laddr) const
        !           374: {
        !           375:        uint32 paddr;
        !           376: 
        !           377:        paddr = TranslatePeek(laddr);
        !           378:        putlog(3, "Translate: $%04x -> $%05x", laddr, paddr);
        !           379:        return paddr;
        !           380: }
        !           381: 
        !           382: // アドレス変換 (デバッガ用)
        !           383: uint64
        !           384: MPU64180Device::TranslatePeek(uint32 laddr) const
        !           385: {
        !           386:        uint32 paddr;
        !           387: 
        !           388:        // 論理アドレスから物理アドレスへの変換
        !           389:        if (laddr >= commarea) {
        !           390:                // Common Area 1
        !           391:                paddr = commbase + laddr;
        !           392:        } else if (laddr >= bankarea) {
        !           393:                // Bank Area
        !           394:                paddr = bankbase + laddr;
        !           395:        } else {
        !           396:                // Common Area 0
        !           397:                paddr = laddr;
        !           398:        }
        !           399: 
        !           400:        return paddr;
        !           401: }
        !           402: 
        !           403: // MSXDOS エミュレーションのコールバックを指定
        !           404: void
        !           405: MPU64180Device::SetSYSCALLCallback(void (*callback)(void *), void *arg)
        !           406: {
        !           407:        syscall_callback = callback;
        !           408:        syscall_arg = arg;
        !           409: }
        !           410: 
        !           411: void
        !           412: MPU64180Device::MonitorUpdateReg(Monitor *, TextScreen& screen)
        !           413: {
        !           414:        screen.Clear();
        !           415: 
        !           416:        // 0         1         2         3
        !           417:        // 012345678901234567890123456789012345678
        !           418:        // AF:00 00 (------)  PC:8000   AF':00 00
        !           419:        // BC:00 00           SP:8000   BC':00 00
        !           420:        // DE:00 00  IX:0000   I:00     DE':00 00
        !           421:        // HL:00 00  IY:0000   R:00     HL':00 00
        !           422:        //
        !           423:        // Operation Mode: Normal
        !           424: 
        !           425:        hd64180reg tmp = reg;
        !           426: 
        !           427:        screen.Print(0, 0, "AF:%02x %02x", tmp.a, tmp.f.Get());
        !           428:        screen.Print(0, 1, "BC:%02x %02x", tmp.b, tmp.c);
        !           429:        screen.Print(0, 2, "DE:%02x %02x", tmp.d, tmp.e);
        !           430:        screen.Print(0, 3, "HL:%02x %02x", tmp.h, tmp.l);
        !           431: 
        !           432:        screen.Print(9, 0, "(%c%c%c%c%c%c)",
        !           433:                tmp.f.IsS() ? 'S' : '-',
        !           434:                tmp.f.IsZ() ? 'Z' : '-',
        !           435:                tmp.f.IsH() ? 'H' : '-',
        !           436:                tmp.f.IsV() ? 'V' : (tmp.f.IsP() ? 'P' : '-'),
        !           437:                tmp.f.IsN() ? 'N' : '-',
        !           438:                tmp.f.IsC() ? 'C' : '-');
        !           439:        screen.Print(10, 2, "IX:%04x", tmp.ix);
        !           440:        screen.Print(10, 3, "IY:%04x", tmp.iy);
        !           441: 
        !           442:        screen.Print(19, 0, "PC:%04x", tmp.pc);
        !           443:        screen.Print(19, 1, "SP:%04x", tmp.sp);
        !           444:        screen.Print(20, 2, "I:%02x", reg_i);
        !           445:        screen.Print(20, 3, "R:%02x", GetR());
        !           446: 
        !           447:        screen.Print(29, 0, "AF':%02x %02x", tmp.ex.a, tmp.ex.f.Get());
        !           448:        screen.Print(29, 1, "BC':%02x %02x", tmp.ex.b, tmp.ex.c);
        !           449:        screen.Print(29, 2, "DE':%02x %02x", tmp.ex.d, tmp.ex.e);
        !           450:        screen.Print(29, 3, "HL':%02x %02x", tmp.ex.h, tmp.ex.l);
        !           451: 
        !           452:        screen.Puts(0, 5, "Operation Mode:");
        !           453:        screen.Puts(16, 5, (opmode == OpMode::Reset) ? TA::On : TA::Normal,
        !           454:                opmode_names[(int)opmode]);
        !           455: }
        !           456: 
        !           457: /*static*/ const char * const
        !           458: MPU64180Device::opmode_names[] = {
        !           459:        "Reset",
        !           460:        "Normal",
        !           461:        "Halt",
        !           462:        "Sleep",
        !           463: };
        !           464: 
        !           465: void
        !           466: MPU64180Device::MonitorUpdateIO(Monitor *, TextScreen& screen)
        !           467: {
        !           468:        int y;
        !           469:        uint32 val;
        !           470: 
        !           471:        screen.Clear();
        !           472: 
        !           473: /*
        !           474: 0         1         2         3         4         5         6         7
        !           475: 01234567890123456789012345678901234567890123456789012345678901234567890123456789
        !           476: <MMU>
        !           477: 38H CBR  = $20: Common Base Addr = $20000
        !           478: 39H BBR  = $00:   Bank Base Addr = $00000
        !           479: 3AH CBAR = $83: Common Area = $8000
        !           480:                   Bank Area = $3000
        !           481: 51H RMCR = $00: RAM Address = $00000
        !           482: */
        !           483:        y = 0;
        !           484:        screen.Puts(0, y++, "<DMA and wait>");
        !           485:        val = PeekDCNTL();
        !           486:        screen.Print(0, y, "32H DCNTL= $%02x:", val);
        !           487:        screen.Print(16, y, "MemWait=%d", memwait);
        !           488:        screen.Print(26, y, "IOWait=%d", iowait);
        !           489:        y++;
        !           490: 
        !           491:        screen.Puts(0, y++, "<Interrupt Control>");
        !           492:        screen.Print(0, y++, "33H IL   = $%02x", intvec_low);
        !           493: 
        !           494:        val = PeekITC();
        !           495:        screen.Print(0, y, "34H ITC  = $%02x:", val);
        !           496:        static const char * const itc_str[] = {
        !           497:                "TRAP", "UFO", "----", "----", "----", "ITE2", "ITE1", "ITE0"
        !           498:        };
        !           499:        for (int i = 0; i < 8; i++) {
        !           500:                screen.Puts(16 + 5 * i, y,
        !           501:                        TA::OnOff(val & (1U << (7 - i))), itc_str[i]);
        !           502:        }
        !           503:        y++;
        !           504:        val = PeekRCR();
        !           505:        screen.Print(0, y, "36H RCR  = $%02x:", val);
        !           506:        static const char * const rcr_str[] = {
        !           507:                "REFE", "REFW", "----", "----", "----", "----"
        !           508:        };
        !           509:        for (int i = 0; i < countof(rcr_str); i++) {
        !           510:                screen.Puts(16 + 5 * i, y,
        !           511:                        TA::OnOff(val & (1U << (7 - i))), rcr_str[i]);
        !           512:        }
        !           513:        screen.Print(46, y, "RefCyc=%d", (1 << (val & 3)) * 10);
        !           514:        y++;
        !           515: 
        !           516:        y++;
        !           517:        screen.Puts(0, y++, "<Timer>");
        !           518:        val = PeekTCR();
        !           519:        screen.Print(0, y, "10H TCR  = $%02x:", val);
        !           520:        static const char * const tcr_str[] = {
        !           521:                "TIF1", "TIF0", "TIE1", "TIE0", "", "", "TDE1", "TDE0"
        !           522:        };
        !           523:        for (int i = 0; i < 8; i++) {
        !           524:                screen.Puts(16 + 5 * i, y,
        !           525:                        TA::OnOff(val & (1U << (7 - i))), tcr_str[i]);
        !           526:        }
        !           527:        screen.Print(16 + 5 * 4, y, "TOC=$%d", timer_toc);
        !           528:        y++;
        !           529:        for (int ch = 0; ch < timer.size(); ch++) {
        !           530:                auto& t = timer[ch];
        !           531:                uint64 reload_nsec = t.reload * clock_nsec * 20;
        !           532:                screen.Print(4, y++, "Timer%d: Count=$%04x Reload=$%04x(%6u.%03u usec)",
        !           533:                        ch, t.count, t.reload,
        !           534:                        (uint)(reload_nsec / 1000),
        !           535:                        (uint)(reload_nsec % 1000));
        !           536:        }
        !           537:        screen.Print(0, y++, "18H FRC  = $%02x", PeekFRC());
        !           538: 
        !           539:        y++;
        !           540:        screen.Puts(0, y++, "<Memory Control>");
        !           541:        screen.Print(0, y++, "38H CBR  = $%02x: Common Base Addr = $%05x",
        !           542:                PeekCBR(), commbase);
        !           543:        screen.Print(0, y++, "39H BBR  = $%02x:   Bank Base Addr = $%05x",
        !           544:                PeekBBR(), bankbase);
        !           545:        screen.Print(0, y++, "3AH CBAR = $%02x: Common Area = $%04x",
        !           546:                PeekCBAR(), commarea);
        !           547:        screen.Print(18, y++, "Bank Area = $%04x", bankarea);
        !           548: 
        !           549:        screen.Print(0, y++, "3FH ICR  = $%02x: I/O Address = $%02x",
        !           550:                PeekICR(), io_address);
        !           551:        screen.Print(0, y++, "51H RMCR = $%02x: RAM Address = $%05x",
        !           552:                PeekRMCR(), xpbus->GetXPRAMAddr());
        !           553: }
        !           554: 
        !           555: void
        !           556: MPU64180Device::MonitorUpdateIntr(Monitor *, TextScreen& screen)
        !           557: {
        !           558:        static const struct {
        !           559:                uint offset;
        !           560:                const char *flagname;
        !           561:        } table[] = {
        !           562:                { 0x00, "" },   // TRAP
        !           563:                { 0x66, "" },   // NMI
        !           564:                { 0,    "ITC:ITE0" },   // INT0
        !           565:                { 0x00, "ITC:ITE1" },   // INT1
        !           566:                { 0x02, "ITC:ITE2" },   // INT2
        !           567:                { 0x12, "" },   // Input Capture
        !           568:                { 0x14, "" },   // Output Compare
        !           569:                { 0x16, "" },   // Timer Overflow
        !           570:                { 0x04, "TCR:TIE0" },   // Timer0
        !           571:                { 0x06, "TCR:TIE1" },   // Timer1
        !           572:                { 0x08, "" },   // DMA0
        !           573:                { 0x0a, "" },   // DMA1
        !           574:                { 0x0c, "" },   // CSIO
        !           575:                { 0x0e, "" },   // ASCI0
        !           576:                { 0x10, "" },   // ASCI1
        !           577:        };
        !           578:        struct {
        !           579:                bool enable;    // この割り込みが有効か
        !           580:                uint32 vecaddr; // ベクタが格納されているアドレス
        !           581:                uint16 handler; // ハンドラのアドレス
        !           582:        } data[countof(table)];
        !           583:        int x, y;
        !           584: 
        !           585:        // 割り込み有効制御ビットは各地に散らばってるのでここで集める。
        !           586:        uint32 itc = PeekITC();
        !           587:        uint32 tcr = PeekTCR();
        !           588:        data[HD647180::IntmapINT0].enable       = (itc & 0x01);
        !           589:        data[HD647180::IntmapINT1].enable       = (itc & 0x02);
        !           590:        data[HD647180::IntmapINT2].enable       = (itc & 0x04);
        !           591:        data[HD647180::IntmapTimer0].enable     = (tcr & 0x10);
        !           592:        data[HD647180::IntmapTimer1].enable     = (tcr & 0x20);
        !           593: 
        !           594:        // ベクタを集める。
        !           595:        // INT1 (Pri=3) 以降が I + IL + ベクタ方式。
        !           596:        // 0(TRAP), 1(NMI), 2(INT0) は個別処理。
        !           597:        uint32 intvec = (reg_i << 8) + intvec_low;
        !           598:        for (int i = 3; i < countof(data); i++) {
        !           599:                data[i].vecaddr = intvec + table[i].offset;
        !           600:                data[i].handler = Peek16(data[i].vecaddr);
        !           601:        }
        !           602: 
        !           603:        screen.Clear();
        !           604: 
        !           605:        screen.Puts(0, 0, "Mask:");
        !           606:        screen.Puts(6,  0, TA::OnOff(GetIEF1()), "IEF1");
        !           607:        screen.Putc(11, 0, '(');
        !           608:        screen.Puts(12, 0, TA::OnOff(GetIEF2()), "IEF2");
        !           609:        screen.Putc(16, 0, ')');
        !           610:        screen.Print(26, 0, "INT0 Mode: %d", int0mode);
        !           611: 
        !           612:        // 0         1         2         3         4         5         6
        !           613:        // 0123456789012345678901234567890123456789012345678901234567890123
        !           614:        // Pri Name         Enable   Vec                              Count
        !           615:        // 00  InputCapture ITC:ITE0 0000H(0000H)01234567890123456789012345
        !           616: 
        !           617:        y = 2; //          012345678901234567890123456789012345
        !           618:        screen.Puts(0, y, "Pri Name         Enable   Vector");
        !           619:        screen.Puts(59, y, "Count");
        !           620:        y++;
        !           621: 
        !           622:        // TRAP, NMI だけ別処理
        !           623:        screen.Puts(3, y, InterruptName[0]);
        !           624:        screen.Puts(3, y + 1, TA::Disable, "NMI (NotConn)");
        !           625: 
        !           626:        // INT0 以降はレベルトリガー & マスク可能なので現在の状態を表示
        !           627:        for (int i = 2; i < 15; i++) {
        !           628:                screen.Puts(3, y + i, TA::OnOff(intmap & (1U << (31 - i))),
        !           629:                        InterruptName[i]);
        !           630:                screen.Puts(17, y + i, TA::OnOff(data[i].enable), table[i].flagname);
        !           631:        }
        !           632: 
        !           633:        // ベクタ
        !           634:        x = 26;
        !           635:        screen.Puts(x, y + 0, "0000H");
        !           636:        screen.Puts(x, y + 1, "0066H");
        !           637:        if (int0mode == 1) {
        !           638:                screen.Puts(x, y + 2, "0038H");
        !           639:        } else {
        !           640:                // Mode0 はデータバスから命令自体を読み込む方式。
        !           641:                // Mode1 はデータバスからベクタの下位アドレスを読み込む方式。
        !           642:                // どちらもサポートしていない。
        !           643:                screen.Print(x, y + 2, "(IM%d)", int0mode);
        !           644:        }
        !           645:        for (int i = 3; i < 15; i++) {
        !           646:                screen.Print(x, y + i, "%04XH(%04XH)",
        !           647:                        data[i].handler, data[i].vecaddr);
        !           648:        }
        !           649: 
        !           650:        // カウンタ
        !           651:        x = 38;
        !           652:        for (int i = 0; i < 15; i++) {
        !           653:                screen.Print(0, y + i, "%2d", i);
        !           654:                screen.Print(x, y + i, "%26s", format_number(int_counter[i]).c_str());
        !           655:        }
        !           656: }
        !           657: 
        !           658: /*static*/ std::vector<const char *>
        !           659: MPU64180Device::InterruptName = {
        !           660:        "TRAP",
        !           661:        "NMI",
        !           662:        "INT0(PIO1)",
        !           663:        "INT1",
        !           664:        "INT2",
        !           665:        "InputCapture",
        !           666:        "OutputCompare",
        !           667:        "TimerOverflow",
        !           668:        "Timer 0",
        !           669:        "Timer 1",
        !           670:        "DMA 0",
        !           671:        "DMA 1",
        !           672:        "CSIO",
        !           673:        "ASCI 0",
        !           674:        "ASCI 1",
        !           675: };

unix.superglobalmegacorp.com

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