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