|
|
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 *)®, 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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.