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

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

unix.superglobalmegacorp.com

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