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

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: 
1.1.1.2   root      219:        SetTrace(debugger->IsTrace());
                    220: 
1.1       root      221:        // 3 クロック後から通常サイクル開始? (HD647180.pdf, p23)
                    222:        exec_event.time = 3 * clock_nsec;
                    223:        scheduler->RestartEvent(exec_event);
                    224: }
                    225: 
                    226: // スリープモードに入る。(SLP 命令から呼ばれる)
                    227: void
                    228: MPU64180Device::EnterSleep()
                    229: {
                    230:        // ExecNormal() 内で StartEvent() をしないに分岐するのは無駄が多いので、
                    231:        // ここでは一旦コールバックだけ差し替えて、イベントを停止する。
                    232:        SetExec(ToEventCallback(&MPU64180Device::ExecSleep));
                    233:        exec_event.SetName("XP(HD647180) Sleep");
                    234:        exec_event.time = 0;
                    235: 
                    236:        // 内蔵デバイスのイベントも停止する。
                    237:        scheduler->StopEvent(timer_event);
                    238: }
                    239: 
                    240: // スリープモードから抜ける。
                    241: void
                    242: MPU64180Device::EnterWakeup()
                    243: {
                    244:        // 復帰処理のため一旦 Wakeup へ。
                    245:        SetExec(ToEventCallback(&MPU64180Device::ExecWakeup));
                    246:        exec_event.time = 3 * clock_nsec;
                    247: 
                    248:        scheduler->StartEvent(exec_event);
                    249: }
                    250: 
                    251: // スリープに入る時のイベント
                    252: void
                    253: MPU64180Device::ExecSleep(Event& ev)
                    254: {
                    255:        // 実行イベントを停止する。(StartEvent() を呼ばない)
                    256: }
                    257: 
                    258: // スリープから復帰するイベント
                    259: void
                    260: MPU64180Device::ExecWakeup(Event& ev)
                    261: {
                    262:        // EI なら、割り込み処理から再開。
                    263:        // DI なら、次の命令から再開。
                    264:        if (GetIEF1()) {
                    265:                DoInterrupt();
                    266:        }
                    267: 
                    268:        EnterNormal();
                    269: }
                    270: 
                    271: // MPU トレース状態設定要求メッセージ
                    272: void
                    273: MPU64180Device::TraceMessage(MessageID msgid, uint32 arg)
                    274: {
                    275:        // リセット中は SetTrace しない
                    276:        if (opmode == OpMode::Reset) {
                    277:                return;
                    278:        }
                    279: 
                    280:        // デバッガから MPU のトレース状態を設定してくれと言われた
                    281:        SetTrace((bool)arg);
                    282: }
                    283: 
                    284: // トレース実行
                    285: void
                    286: MPU64180Device::ExecTrace(Event& ev)
                    287: {
                    288:        debugger->ExecXP();
                    289:        (this->*exec_func)(ev);
                    290: }
                    291: 
                    292: // 実行コールバックを設定する。
                    293: void
                    294: MPU64180Device::SetExec(EventCallback_t new_exec)
                    295: {
                    296:        exec_func = new_exec;
                    297: 
                    298:        if (exec_event.func != ToEventCallback(&MPU64180Device::ExecTrace)) {
                    299:                exec_event.func = exec_func;
                    300:        }
                    301: }
                    302: 
                    303: // トレース状態を設定する。
                    304: void
                    305: MPU64180Device::SetTrace(bool enable)
                    306: {
                    307:        EventCallback_t func;
                    308: 
                    309:        if (enable) {
                    310:                func = ToEventCallback(&MPU64180Device::ExecTrace);
                    311:        } else {
                    312:                func = exec_func;
                    313:        }
                    314:        exec_event.func = func;
                    315: }
                    316: 
                    317: // IX/IY 分を考慮したサイクル数
                    318: void
                    319: MPU64180Device::CYCLE_IX(int cycle_hl, int cycle_ix)
                    320: {
                    321:        if (__predict_true(ixiy == USE_HL)) {
                    322:                used_cycle += cycle_hl;
                    323:        } else {
                    324:                used_cycle += cycle_ix;
                    325:        }
                    326: }
                    327: 
                    328: uint32
                    329: MPU64180Device::Fetch8()
                    330: {
                    331:        uint8 data = Read8(reg.pc++);
                    332:        ops.push_back(data);
                    333:        if (__predict_false(reg.pc > 0xffff)) {
                    334:                reg.pc = 0;
                    335:        }
                    336:        return data;
                    337: }
                    338: 
                    339: uint32
                    340: MPU64180Device::Read8(uint32 laddr)
                    341: {
                    342:        uint32 paddr = Translate(laddr);
                    343:        // XXX 内蔵 RAM はノーウェイト
                    344:        CYCLE(memwait);
                    345:        return xpbus->Read8(paddr);
                    346: }
                    347: 
                    348: uint32
                    349: MPU64180Device::Write8(uint32 laddr, uint32 data)
                    350: {
                    351:        uint32 paddr = Translate(laddr);
                    352:        // XXX 内蔵 RAM はノーウェイト
                    353:        CYCLE(memwait);
                    354:        return xpbus->Write8(paddr, data);
                    355: }
                    356: 
                    357: uint32
                    358: MPU64180Device::Peek8(uint32 laddr) const
                    359: {
                    360:        uint32 addr = TranslatePeek(laddr);
                    361:        return xpbus->Peek8(addr);
                    362: }
                    363: 
                    364: uint32
                    365: MPU64180Device::Peek16(uint32 laddr) const
                    366: {
                    367:        uint32 data;
                    368:        data  = Peek8(laddr);
                    369:        data |= Peek8(laddr + 1) << 8;
                    370:        return data;
                    371: }
                    372: 
                    373: // アドレス変換
                    374: uint32
                    375: MPU64180Device::Translate(uint32 laddr) const
                    376: {
                    377:        uint32 paddr;
                    378: 
                    379:        paddr = TranslatePeek(laddr);
                    380:        putlog(3, "Translate: $%04x -> $%05x", laddr, paddr);
                    381:        return paddr;
                    382: }
                    383: 
                    384: // アドレス変換 (デバッガ用)
1.1.1.3 ! root      385: busaddr
1.1       root      386: MPU64180Device::TranslatePeek(uint32 laddr) const
                    387: {
                    388:        uint32 paddr;
                    389: 
                    390:        // 論理アドレスから物理アドレスへの変換
                    391:        if (laddr >= commarea) {
                    392:                // Common Area 1
                    393:                paddr = commbase + laddr;
                    394:        } else if (laddr >= bankarea) {
                    395:                // Bank Area
                    396:                paddr = bankbase + laddr;
                    397:        } else {
                    398:                // Common Area 0
                    399:                paddr = laddr;
                    400:        }
                    401: 
                    402:        return paddr;
                    403: }
                    404: 
                    405: // MSXDOS エミュレーションのコールバックを指定
                    406: void
                    407: MPU64180Device::SetSYSCALLCallback(void (*callback)(void *), void *arg)
                    408: {
                    409:        syscall_callback = callback;
                    410:        syscall_arg = arg;
                    411: }
                    412: 
                    413: void
                    414: MPU64180Device::MonitorUpdateReg(Monitor *, TextScreen& screen)
                    415: {
                    416:        screen.Clear();
                    417: 
                    418:        // 0         1         2         3
                    419:        // 012345678901234567890123456789012345678
                    420:        // AF:00 00 (------)  PC:8000   AF':00 00
                    421:        // BC:00 00           SP:8000   BC':00 00
                    422:        // DE:00 00  IX:0000   I:00     DE':00 00
                    423:        // HL:00 00  IY:0000   R:00     HL':00 00
                    424:        //
                    425:        // Operation Mode: Normal
                    426: 
                    427:        hd64180reg tmp = reg;
                    428: 
                    429:        screen.Print(0, 0, "AF:%02x %02x", tmp.a, tmp.f.Get());
                    430:        screen.Print(0, 1, "BC:%02x %02x", tmp.b, tmp.c);
                    431:        screen.Print(0, 2, "DE:%02x %02x", tmp.d, tmp.e);
                    432:        screen.Print(0, 3, "HL:%02x %02x", tmp.h, tmp.l);
                    433: 
                    434:        screen.Print(9, 0, "(%c%c%c%c%c%c)",
                    435:                tmp.f.IsS() ? 'S' : '-',
                    436:                tmp.f.IsZ() ? 'Z' : '-',
                    437:                tmp.f.IsH() ? 'H' : '-',
                    438:                tmp.f.IsV() ? 'V' : (tmp.f.IsP() ? 'P' : '-'),
                    439:                tmp.f.IsN() ? 'N' : '-',
                    440:                tmp.f.IsC() ? 'C' : '-');
                    441:        screen.Print(10, 2, "IX:%04x", tmp.ix);
                    442:        screen.Print(10, 3, "IY:%04x", tmp.iy);
                    443: 
                    444:        screen.Print(19, 0, "PC:%04x", tmp.pc);
                    445:        screen.Print(19, 1, "SP:%04x", tmp.sp);
                    446:        screen.Print(20, 2, "I:%02x", reg_i);
                    447:        screen.Print(20, 3, "R:%02x", GetR());
                    448: 
                    449:        screen.Print(29, 0, "AF':%02x %02x", tmp.ex.a, tmp.ex.f.Get());
                    450:        screen.Print(29, 1, "BC':%02x %02x", tmp.ex.b, tmp.ex.c);
                    451:        screen.Print(29, 2, "DE':%02x %02x", tmp.ex.d, tmp.ex.e);
                    452:        screen.Print(29, 3, "HL':%02x %02x", tmp.ex.h, tmp.ex.l);
                    453: 
                    454:        screen.Puts(0, 5, "Operation Mode:");
                    455:        screen.Puts(16, 5, (opmode == OpMode::Reset) ? TA::On : TA::Normal,
                    456:                opmode_names[(int)opmode]);
                    457: }
                    458: 
                    459: /*static*/ const char * const
                    460: MPU64180Device::opmode_names[] = {
                    461:        "Reset",
                    462:        "Normal",
                    463:        "Halt",
                    464:        "Sleep",
                    465: };
                    466: 
                    467: void
                    468: MPU64180Device::MonitorUpdateIO(Monitor *, TextScreen& screen)
                    469: {
                    470:        int y;
                    471:        uint32 val;
                    472: 
                    473:        screen.Clear();
                    474: 
                    475: /*
                    476: 0         1         2         3         4         5         6         7
                    477: 01234567890123456789012345678901234567890123456789012345678901234567890123456789
                    478: <MMU>
                    479: 38H CBR  = $20: Common Base Addr = $20000
                    480: 39H BBR  = $00:   Bank Base Addr = $00000
                    481: 3AH CBAR = $83: Common Area = $8000
                    482:                   Bank Area = $3000
                    483: 51H RMCR = $00: RAM Address = $00000
                    484: */
                    485:        y = 0;
                    486:        screen.Puts(0, y++, "<DMA and wait>");
                    487:        val = PeekDCNTL();
                    488:        screen.Print(0, y, "32H DCNTL= $%02x:", val);
                    489:        screen.Print(16, y, "MemWait=%d", memwait);
                    490:        screen.Print(26, y, "IOWait=%d", iowait);
                    491:        y++;
                    492: 
                    493:        screen.Puts(0, y++, "<Interrupt Control>");
                    494:        screen.Print(0, y++, "33H IL   = $%02x", intvec_low);
                    495: 
                    496:        val = PeekITC();
                    497:        screen.Print(0, y, "34H ITC  = $%02x:", val);
                    498:        static const char * const itc_str[] = {
                    499:                "TRAP", "UFO", "----", "----", "----", "ITE2", "ITE1", "ITE0"
                    500:        };
                    501:        for (int i = 0; i < 8; i++) {
                    502:                screen.Puts(16 + 5 * i, y,
                    503:                        TA::OnOff(val & (1U << (7 - i))), itc_str[i]);
                    504:        }
                    505:        y++;
                    506:        val = PeekRCR();
                    507:        screen.Print(0, y, "36H RCR  = $%02x:", val);
                    508:        static const char * const rcr_str[] = {
                    509:                "REFE", "REFW", "----", "----", "----", "----"
                    510:        };
                    511:        for (int i = 0; i < countof(rcr_str); i++) {
                    512:                screen.Puts(16 + 5 * i, y,
                    513:                        TA::OnOff(val & (1U << (7 - i))), rcr_str[i]);
                    514:        }
                    515:        screen.Print(46, y, "RefCyc=%d", (1 << (val & 3)) * 10);
                    516:        y++;
                    517: 
                    518:        y++;
                    519:        screen.Puts(0, y++, "<Timer>");
                    520:        val = PeekTCR();
                    521:        screen.Print(0, y, "10H TCR  = $%02x:", val);
                    522:        static const char * const tcr_str[] = {
                    523:                "TIF1", "TIF0", "TIE1", "TIE0", "", "", "TDE1", "TDE0"
                    524:        };
                    525:        for (int i = 0; i < 8; i++) {
                    526:                screen.Puts(16 + 5 * i, y,
                    527:                        TA::OnOff(val & (1U << (7 - i))), tcr_str[i]);
                    528:        }
                    529:        screen.Print(16 + 5 * 4, y, "TOC=$%d", timer_toc);
                    530:        y++;
                    531:        for (int ch = 0; ch < timer.size(); ch++) {
                    532:                auto& t = timer[ch];
                    533:                uint64 reload_nsec = t.reload * clock_nsec * 20;
                    534:                screen.Print(4, y++, "Timer%d: Count=$%04x Reload=$%04x(%6u.%03u usec)",
                    535:                        ch, t.count, t.reload,
                    536:                        (uint)(reload_nsec / 1000),
                    537:                        (uint)(reload_nsec % 1000));
                    538:        }
                    539:        screen.Print(0, y++, "18H FRC  = $%02x", PeekFRC());
                    540: 
                    541:        y++;
                    542:        screen.Puts(0, y++, "<Memory Control>");
                    543:        screen.Print(0, y++, "38H CBR  = $%02x: Common Base Addr = $%05x",
                    544:                PeekCBR(), commbase);
                    545:        screen.Print(0, y++, "39H BBR  = $%02x:   Bank Base Addr = $%05x",
                    546:                PeekBBR(), bankbase);
                    547:        screen.Print(0, y++, "3AH CBAR = $%02x: Common Area = $%04x",
                    548:                PeekCBAR(), commarea);
                    549:        screen.Print(18, y++, "Bank Area = $%04x", bankarea);
                    550: 
                    551:        screen.Print(0, y++, "3FH ICR  = $%02x: I/O Address = $%02x",
                    552:                PeekICR(), io_address);
                    553:        screen.Print(0, y++, "51H RMCR = $%02x: RAM Address = $%05x",
                    554:                PeekRMCR(), xpbus->GetXPRAMAddr());
                    555: }
                    556: 
                    557: void
                    558: MPU64180Device::MonitorUpdateIntr(Monitor *, TextScreen& screen)
                    559: {
                    560:        static const struct {
                    561:                uint offset;
                    562:                const char *flagname;
                    563:        } table[] = {
                    564:                { 0x00, "" },   // TRAP
                    565:                { 0x66, "" },   // NMI
                    566:                { 0,    "ITC:ITE0" },   // INT0
                    567:                { 0x00, "ITC:ITE1" },   // INT1
                    568:                { 0x02, "ITC:ITE2" },   // INT2
                    569:                { 0x12, "" },   // Input Capture
                    570:                { 0x14, "" },   // Output Compare
                    571:                { 0x16, "" },   // Timer Overflow
                    572:                { 0x04, "TCR:TIE0" },   // Timer0
                    573:                { 0x06, "TCR:TIE1" },   // Timer1
                    574:                { 0x08, "" },   // DMA0
                    575:                { 0x0a, "" },   // DMA1
                    576:                { 0x0c, "" },   // CSIO
                    577:                { 0x0e, "" },   // ASCI0
                    578:                { 0x10, "" },   // ASCI1
                    579:        };
                    580:        struct {
                    581:                bool enable;    // この割り込みが有効か
                    582:                uint32 vecaddr; // ベクタが格納されているアドレス
                    583:                uint16 handler; // ハンドラのアドレス
                    584:        } data[countof(table)];
                    585:        int x, y;
                    586: 
                    587:        // 割り込み有効制御ビットは各地に散らばってるのでここで集める。
                    588:        uint32 itc = PeekITC();
                    589:        uint32 tcr = PeekTCR();
                    590:        data[HD647180::IntmapINT0].enable       = (itc & 0x01);
                    591:        data[HD647180::IntmapINT1].enable       = (itc & 0x02);
                    592:        data[HD647180::IntmapINT2].enable       = (itc & 0x04);
                    593:        data[HD647180::IntmapTimer0].enable     = (tcr & 0x10);
                    594:        data[HD647180::IntmapTimer1].enable     = (tcr & 0x20);
                    595: 
                    596:        // ベクタを集める。
                    597:        // INT1 (Pri=3) 以降が I + IL + ベクタ方式。
                    598:        // 0(TRAP), 1(NMI), 2(INT0) は個別処理。
                    599:        uint32 intvec = (reg_i << 8) + intvec_low;
                    600:        for (int i = 3; i < countof(data); i++) {
                    601:                data[i].vecaddr = intvec + table[i].offset;
                    602:                data[i].handler = Peek16(data[i].vecaddr);
                    603:        }
                    604: 
                    605:        screen.Clear();
                    606: 
                    607:        screen.Puts(0, 0, "Mask:");
                    608:        screen.Puts(6,  0, TA::OnOff(GetIEF1()), "IEF1");
                    609:        screen.Putc(11, 0, '(');
                    610:        screen.Puts(12, 0, TA::OnOff(GetIEF2()), "IEF2");
                    611:        screen.Putc(16, 0, ')');
                    612:        screen.Print(26, 0, "INT0 Mode: %d", int0mode);
                    613: 
                    614:        // 0         1         2         3         4         5         6
                    615:        // 0123456789012345678901234567890123456789012345678901234567890123
                    616:        // Pri Name         Enable   Vec                              Count
                    617:        // 00  InputCapture ITC:ITE0 0000H(0000H)01234567890123456789012345
                    618: 
                    619:        y = 2; //          012345678901234567890123456789012345
                    620:        screen.Puts(0, y, "Pri Name         Enable   Vector");
                    621:        screen.Puts(59, y, "Count");
                    622:        y++;
                    623: 
                    624:        // TRAP, NMI だけ別処理
                    625:        screen.Puts(3, y, InterruptName[0]);
                    626:        screen.Puts(3, y + 1, TA::Disable, "NMI (NotConn)");
                    627: 
                    628:        // INT0 以降はレベルトリガー & マスク可能なので現在の状態を表示
                    629:        for (int i = 2; i < 15; i++) {
                    630:                screen.Puts(3, y + i, TA::OnOff(intmap & (1U << (31 - i))),
                    631:                        InterruptName[i]);
                    632:                screen.Puts(17, y + i, TA::OnOff(data[i].enable), table[i].flagname);
                    633:        }
                    634: 
                    635:        // ベクタ
                    636:        x = 26;
                    637:        screen.Puts(x, y + 0, "0000H");
                    638:        screen.Puts(x, y + 1, "0066H");
                    639:        if (int0mode == 1) {
                    640:                screen.Puts(x, y + 2, "0038H");
                    641:        } else {
                    642:                // Mode0 はデータバスから命令自体を読み込む方式。
                    643:                // Mode1 はデータバスからベクタの下位アドレスを読み込む方式。
                    644:                // どちらもサポートしていない。
                    645:                screen.Print(x, y + 2, "(IM%d)", int0mode);
                    646:        }
                    647:        for (int i = 3; i < 15; i++) {
                    648:                screen.Print(x, y + i, "%04XH(%04XH)",
                    649:                        data[i].handler, data[i].vecaddr);
                    650:        }
                    651: 
                    652:        // カウンタ
                    653:        x = 38;
                    654:        for (int i = 0; i < 15; i++) {
                    655:                screen.Print(0, y + i, "%2d", i);
                    656:                screen.Print(x, y + i, "%26s", format_number(int_counter[i]).c_str());
                    657:        }
                    658: }
                    659: 
                    660: /*static*/ std::vector<const char *>
                    661: MPU64180Device::InterruptName = {
                    662:        "TRAP",
                    663:        "NMI",
                    664:        "INT0(PIO1)",
                    665:        "INT1",
                    666:        "INT2",
                    667:        "InputCapture",
                    668:        "OutputCompare",
                    669:        "TimerOverflow",
                    670:        "Timer 0",
                    671:        "Timer 1",
                    672:        "DMA 0",
                    673:        "DMA 1",
                    674:        "CSIO",
                    675:        "ASCI 0",
                    676:        "ASCI 1",
                    677: };

unix.superglobalmegacorp.com

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