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

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

unix.superglobalmegacorp.com

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