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