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