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