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