|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.13 root 7: //
8: // MPU (MC68030)
9: //
1.1 root 10:
11: #include "mpu680x0.h"
12: #include "config.h"
1.1.1.13 root 13: #include "debugger.h"
1.1.1.15 root 14: #include "interrupt.h"
1.1.1.16! root 15: #include "m68030cache.h"
1.1 root 16: #include "mainapp.h"
1.1.1.13 root 17: #include "scheduler.h"
1.1.1.15 root 18: #include "syncer.h"
1.1.1.10 root 19: #include "uimessage.h"
1.1.1.15 root 20: #include "vectortable.h"
1.1.1.13 root 21: #include <cmath>
22:
1.1.1.15 root 23: static Syncer *gSyncer;
1.1 root 24:
25: // コンストラクタ
1.1.1.8 root 26: MPU680x0Device::MPU680x0Device()
1.1.1.15 root 27: : inherited()
1.1 root 28: {
1.1.1.15 root 29: SetName("MPU(68030)");
30:
31: // MMU.xRP.DT == 0 になってはいけない(MMU 構成例外)。
32: SetSRP(0x00000001, 0);
33: SetCRP(0x00000001, 0);
34: // FPU
35: fpu_init();
1.1.1.16! root 36: // キャッシュ
! 37: icache.reset(new m68030Cache());
1.1 root 38:
1.1.1.13 root 39: // 割り込みイベントコールバック設定
40: intr_event.func = ToEventCallback(&MPU680x0Device::InterruptCallback);
1.1.1.15 root 41: intr_event.Regist(GetName() + " Interrupt");
1.1.1.4 root 42:
1.1.1.9 root 43: // レジスタモニター
1.1.1.13 root 44: reg_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateReg);
1.1.1.16! root 45: reg_monitor.SetSize(78, 19);
1.1.1.9 root 46: reg_monitor.Regist(ID_MONITOR_MPUREG);
47:
48: // ATC モニター
1.1.1.13 root 49: atc_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateATC);
1.1.1.9 root 50: #if !defined(ATC_SINGLE)
1.1.1.16! root 51: atc_monitor.SetSize(135, m68030ATCTable::LINES + 4);
1.1.1.9 root 52: #else
1.1.1.16! root 53: atc_monitor.SetSize(32, 24);
1.1.1.9 root 54: #endif
55: atc_monitor.Regist(ID_MONITOR_MPUATC);
1.1.1.13 root 56:
1.1.1.16! root 57: // キャッシュモニター
! 58: cache_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateCache);
! 59: cache_monitor.SetSize(48, 20);
! 60: cache_monitor.Regist(ID_MONITOR_MPUCACHE);
! 61:
1.1.1.13 root 62: SetTrace(false);
1.1 root 63: }
64:
65: // デストラクタ
66: MPU680x0Device::~MPU680x0Device()
67: {
68: }
69:
1.1.1.16! root 70: void
! 71: MPU680x0Device::SetLogLevel(int loglevel_)
! 72: {
! 73: inherited::SetLogLevel(loglevel_);
! 74:
! 75: atc.SetLogLevel(loglevel_);
! 76: }
! 77:
1.1.1.15 root 78: // 初期化
1.1 root 79: bool
80: MPU680x0Device::Init()
81: {
1.1.1.5 root 82: if (inherited::Init() == false) {
83: return false;
84: }
1.1.1.13 root 85:
1.1.1.15 root 86: debugger = GetDebugger();
87: interruptdev = GetInterruptDevice();
88: // static 関数から参照するため。うーん…。
89: gSyncer = syncer;
90:
1.1.1.13 root 91: // 割り込み時のディレイ。
92: //
93: // 外部デバイスが 68030 の IPL0-2 をアサートしてから、68030 がそれを
94: // 認識(確定)するのに 1 ~ 2 クロックかかる。
95: // その後レベルを比較するのは次のアップエッジ。
96: // その後 /IPEND をアサートするのはその次のアップエッジ。
97: // 合わせると、IPL0-2 が変化してから /IPEND がアサートされるまでは
98: // 2 ~ 3 クロックかかる。(Figure 8-4)
99: intr_event.time = 3 * clock_nsec;
1.1.1.5 root 100:
1.1 root 101: // FPU (6888x)
1.1.1.15 root 102: if (gMainApp.IsX68030()) {
1.1 root 103: // X68k は設定による
1.1.1.14 root 104: const ConfigItem& item = gConfig->Find("fpu-type");
105: std::string type = item.AsString();
106: if (type == "none" || type == "0") {
1.1.1.15 root 107: has_fpu = 0;
1.1.1.14 root 108: } else if (type == "68881" || type == "1") {
1.1.1.15 root 109: has_fpu = 1;
1.1.1.14 root 110: } else {
1.1 root 111: item.Err();
112: return false;
113: }
1.1.1.15 root 114: } else {
115: // LUNA は 68881 固定 (設定は見ない)
116: has_fpu = 1;
1.1 root 117: }
118:
1.1.1.15 root 119: vectortable = GetVectorTable();
1.1.1.10 root 120:
1.1 root 121: return true;
122: }
123:
1.1.1.13 root 124: // リセット
125: void
126: MPU680x0Device::ResetHard(bool poweron)
1.1.1.8 root 127: {
1.1.1.13 root 128: if (poweron) {
1.1.1.15 root 129: // サイクルを初期化。
130: used_cycle = 0;
131:
132: // 履歴を初期化。電源(再)投入時のみ行う。
133: exhist.Clear();
134: brhist.Clear();
135:
136: for (int i = 0; i < 16; i++) {
137: reg.R[i] = 0xcccccccc;
138: }
139: // XXX ただし X68030 IPLROM には A6 を初期化せずに書き込んでいるバグが
140: // あるため、A6 を概ね RAM のあるあたりに指定しておく…。
141: reg.A[6] = 0x000ccccc;
142:
143: // この後起きるリセット例外で PC を初期化する前に参照することになるので
144: // これだけここでも初期化しておく。
145: reg.pc = 0;
1.1.1.13 root 146: }
1.1.1.14 root 147: resetting = true;
1.1.1.13 root 148:
149: // リセット例外を 520 クロック後に起こす。
150: // 520 は、電源オン時、Vcc が最小動作規定値に達してから最低 520 クロック
151: // の間アサートしなければならないという値であって、実際これだけかかる
152: // とかいう値ではない。が、こちら側の都合で、この後実行される RAM の
1.1.1.15 root 153: // ResetHard() がブートページを用意した後で ExceptionReset() で
1.1.1.13 root 154: // SP, PC をフェッチするという順序にしないといけないため、リセット例外が
155: // 起動するまでに時間がかかるというところを都合よく真似ておく。
156:
157: exec_event.func = ToEventCallback(&MPU680x0Device::ResetCallback);
158: exec_event.time = 520 * clock_nsec;
1.1.1.15 root 159: exec_event.SetName(GetName() + " Reset");
160: scheduler->RestartEvent(exec_event);
1.1.1.8 root 161: }
162:
1.1.1.13 root 163: // リセット例外コールバック。
164: // MPU リセットから規定時間後に呼ばれる。
1.1.1.8 root 165: void
1.1.1.13 root 166: MPU680x0Device::ResetCallback(Event& ev)
1.1.1.8 root 167: {
1.1.1.14 root 168: resetting = false;
1.1.1.13 root 169: intr_pending = false;
170:
171: // リセット例外を実行
1.1.1.15 root 172: int cycle = ExceptionReset();
1.1.1.13 root 173:
174: // コールバックを ResetCallback から Exec* に差し替える前のここで
175: // トレース状態を初期化する。
1.1.1.15 root 176: SetTrace(debugger->IsTrace());
1.1.1.13 root 177:
178: // 以降は通常走行。
1.1.1.15 root 179: if (cpu_state == CPU_STATE_NORMAL) {
1.1.1.13 root 180: exec_event.func = exec_short;
181: exec_event.time = cycle * clock_nsec;
1.1.1.15 root 182: exec_event.SetName(GetName() + " Execute");
183: scheduler->RestartEvent(exec_event);
1.1.1.13 root 184: } else {
185: // リセット例外でダブルバスフォールトならここで停止。
186: }
1.1.1.8 root 187: }
188:
1.1.1.15 root 189: // 割り込みチェック、STOP/HALT 処理を含んだ完全な実行サイクルのコールバック。
1.1.1.13 root 190: // SR の I2:I0 が変わった直後などに呼ばれる。
191: // ここでは割り込みをチェックし、必要なら割り込み処理を起動、
192: // そうでなければ通常の命令実行を行う。
193: void
194: MPU680x0Device::ExecFull(Event& ev)
195: {
1.1.1.15 root 196: if (cpu_state == CPU_STATE_HALT) {
197: // HALT なら停止。
198: return;
199: }
200:
201: // マスクよりも割り込みレベルのほうが高ければ割り込み処理。
202: // この時点で intr_pending が true の可能性もあることに留意。
203: // 割り込みレベルは変化してないので Level 7 の特別処理は不要
204: // (割り込みレベルの変化はここではなく InterruptCallback() で処理)。
205: if (intr_level > reg.intr_mask) {
206: intr_pending = true;
207: }
1.1.1.14 root 208:
1.1.1.13 root 209: if (intr_pending) {
210: // 割り込み処理を起動。
211:
212: intr_pending = false;
213:
214: // 前の命令実行後となるここで割り込みを起動
1.1.1.16! root 215: ev.time = ExceptionInterrupt();
1.1.1.15 root 216: scheduler->StartEvent(ev);
1.1.1.13 root 217: } else {
1.1.1.15 root 218: if (cpu_state == CPU_STATE_NORMAL) {
1.1.1.13 root 219: // コールバックを通常処理に戻してから...
220: exec_event.func = exec_short;
221:
222: // この場で次の命令を実行。
223: ExecShort(ev);
224: } else {
1.1.1.15 root 225: // STOP ならここで停止。
1.1.1.13 root 226: }
227: }
1.1 root 228: }
229:
1.1.1.13 root 230: // トレース実行
231: void
232: MPU680x0Device::ExecTrace(Event& ev)
1.1 root 233: {
1.1.1.15 root 234: debugger->ExecMain();
1.1.1.13 root 235: ExecFull(ev);
1.1 root 236: }
237:
1.1.1.13 root 238: // トレース状態を設定する
239: void
240: MPU680x0Device::SetTrace(bool enable)
1.1 root 241: {
1.1.1.13 root 242: if (enable) {
243: exec_short = ToEventCallback(&MPU680x0Device::ExecTrace);
244: exec_full = ToEventCallback(&MPU680x0Device::ExecTrace);
245: } else {
246: exec_short = ToEventCallback(&MPU680x0Device::ExecShort);
247: exec_full = ToEventCallback(&MPU680x0Device::ExecFull);
248: }
249: exec_event.func = exec_full;
250:
251: // STOP 命令中にオンにするには、停止しているイベントを起こす。
252: // STOP 命令中にオフにする場合は、何もしなくていい。
253: if (enable && exec_event.IsRunning() == false) {
1.1.1.15 root 254: scheduler->StartEvent(exec_event);
1.1.1.13 root 255: }
1.1 root 256: }
257:
1.1.1.5 root 258: // 割り込みレベルが変わったことを MPU に通知。
1.1 root 259: void
1.1.1.5 root 260: MPU680x0Device::Interrupt(int level)
1.1 root 261: {
1.1.1.5 root 262: assertmsg(0 <= level && level <= 7, "level=%d", level);
263:
1.1.1.13 root 264: intr_event.code = level;
265: if (intr_event.IsRunning() == false) {
1.1.1.15 root 266: scheduler->StartEvent(intr_event);
1.1.1.5 root 267: }
1.1.1.13 root 268: }
269:
270: // 外部割り込みイベントコールバック。
271: // ev.code 0-7 は新しい割り込みレベル。
1.1.1.15 root 272: //
273: // 割り込みは本来命令境界ごとにチェックするが、実際に割り込みが起きうるのは
274: // 1) 割り込み信号線が変化した時
275: // 2) 割り込みマスクを変更した時
276: // しかないはずなので、この時だけ命令境界でチェックする。
277: // ここはその 1) のほう。その2のほうは core.cpp:SetSR() 参照。
278: //
279: // 外部割り込みが来たので、レベル比較などをして、必要なら次の命令境界で
280: // 割り込みチェックを行うようにするところ。
1.1.1.13 root 281: void
282: MPU680x0Device::InterruptCallback(Event& ev)
283: {
284: int level = ev.code;
1.1.1.15 root 285: int mask = reg.intr_mask;
286:
287: // 信号線が 2 クロック期間安定していること云々は省略
1.1.1.13 root 288:
1.1.1.16! root 289: // 割り込みを起こすかどうかに関わらずここで更新。
! 290: intr_level = level;
! 291:
! 292: // ホールトならここまで。
1.1.1.15 root 293: if (cpu_state == CPU_STATE_HALT) {
294: return;
295: }
296:
297: // 割り込み例外を起動するのは
298: // o レベルがマスクより高い
299: // o マスクに関係なく、レベルが下位から 7 に変化した場合
300: // (ここは変化した時だけ呼ばれるのと 7 より上はないので
301: // level==7 なら必ず「下位から 7 に変化」のはず)
302: if (level > mask || level == 7) {
1.1.1.13 root 303: // 通知した結果割り込みが受け付けられたので、
304: // この命令終了時のコールバックを割り込み処理起動に差し替える。
305: MakeNextFull();
306: intr_pending = true;
307:
308: // STOP 状態だったらここでイベントを開始する
1.1.1.15 root 309: if (cpu_state == CPU_STATE_STOP) {
1.1.1.13 root 310: // STOP から抜ける時間?
311: exec_event.time = 1 * clock_nsec;
1.1.1.15 root 312: scheduler->StartEvent(exec_event);
1.1.1.13 root 313: }
314: }
315: }
316:
317: // 次の命令境界は Full にする。
318: void
319: MPU680x0Device::MakeNextFull()
320: {
321: exec_event.func = exec_full;
322: }
323:
1.1.1.15 root 324: void
325: MPU680x0Device::ChangeState(uint32 new_state)
1.1.1.13 root 326: {
1.1.1.15 root 327: // new_mode (CPU_STATE_*) と
328: // RequestCPUMode() の引数 Syncer::SCHED_CPU_* は
1.1.1.13 root 329: // 実は同じ値なのでそのまま渡してよいことにする。
1.1.1.15 root 330: static_assert(CPU_STATE_NORMAL == Syncer::SCHED_CPU_NORMAL, "");
331: static_assert(CPU_STATE_STOP == Syncer::SCHED_CPU_STOP, "");
332: static_assert(CPU_STATE_HALT == Syncer::SCHED_CPU_HALT, "");
333:
334: if (cpu_state != new_state) {
335: cpu_state = new_state;
336: // スケジューラに通知
337: syncer->RequestCPUMode(cpu_state);
338: }
1.1 root 339: }
340:
341: // A-Line 命令エミュレーションのコールバックを指定。
342: void
1.1.1.15 root 343: MPU680x0Device::SetALineCallback(bool (*callback)(MPU680x0Device *, void*),
344: void *arg)
1.1 root 345: {
1.1.1.15 root 346: aline_callback = callback;
347: aline_arg = arg;
1.1 root 348: }
349:
350: // F-Line 命令エミュレーションのコールバックを指定。
351: void
1.1.1.15 root 352: MPU680x0Device::SetFLineCallback(bool (*callback)(MPU680x0Device *, void*),
353: void *arg)
1.1 root 354: {
1.1.1.15 root 355: fline_callback = callback;
356: fline_arg = arg;
1.1 root 357: }
358:
1.1.1.15 root 359: // RESET 命令
360: void
361: MPU680x0Device::ops_reset()
1.1.1.10 root 362: {
1.1.1.16! root 363: auto mainbus = GetMainbusDevice();
! 364: mainbus->ResetByMPU();
1.1.1.13 root 365: }
366:
367: // ホールト状態
368: void
369: MPU680x0Device::Halt()
370: {
1.1.1.15 root 371: ChangeState(CPU_STATE_HALT);
372:
373: // この命令完了後に停止するため exec を差し替える。
374: MakeNextFull();
1.1.1.13 root 375:
376: // UI に通知 (メッセージボックス表示とか)
1.1.1.10 root 377: UIMessage::Post(UIMessage::HALT);
378: }
379:
1.1 root 380: // モニター更新 (レジスタウィンドウ)
1.1.1.3 root 381: void
1.1.1.9 root 382: MPU680x0Device::MonitorUpdateReg(Monitor *, TextScreen& screen)
1.1 root 383: {
1.1.1.15 root 384: m68kreg tmp;
385: uint32 tmp_ppc;
386: uint32 tmp_state;
1.1 root 387: int x;
388: int y;
389:
1.1.1.9 root 390: screen.Clear();
1.1 root 391:
392: // ローカルにコピー
1.1.1.13 root 393: // ただし一部は reg ではなく cpu クラス本体にある
1.1.1.15 root 394: tmp = reg;
395: tmp_ppc = ppc;
396: tmp_state = cpu_state;
1.1 root 397:
398: // データレジスタ、アドレスレジスタ
399: for (int i = 0; i < 4; i++) {
1.1.1.9 root 400: screen.Print(0, i, "D%d:%08x D%d:%08x A%d:%08x A%d:%08x",
1.1.1.15 root 401: i + 0, tmp.R[i],
402: i + 4, tmp.R[i + 4],
403: i + 0, tmp.R[i + 8],
404: i + 4, tmp.R[i + 12]);
1.1 root 405: }
406:
407: // 5列目
408: x = 50;
409: // SR
1.1.1.9 root 410: screen.Print(x, 0, "SR:%04x(%c%c%c%c%c)",
1.1.1.15 root 411: tmp.GetSR(),
412: (tmp.ccr.IsX()) ? 'X' : '-',
413: (tmp.ccr.IsN()) ? 'N' : '-',
414: (tmp.ccr.IsZ()) ? 'Z' : '-',
415: (tmp.ccr.IsV()) ? 'V' : '-',
416: (tmp.ccr.IsC()) ? 'C' : '-');
1.1 root 417:
418: // *SP
1.1.1.15 root 419: uint ms = (tmp.s ? 2 : 0) | (tmp.m ? 1 : 0); // T1 T0 S M
1.1 root 420: if (ms == 3) {
421: // Supervisor (Master) mode (A7=MSP, USP/ISP)
1.1.1.16! root 422: screen.Print(x, 1, TA::Disable, "USP:%08x", tmp.usp);
! 423: screen.Print(x, 2, TA::Disable, "ISP:%08x", tmp.isp);
1.1 root 424: } else if (ms == 2) {
425: // Supervisor (Interrupt) mode (A7=ISP, USP/MSP)
1.1.1.16! root 426: screen.Print(x, 1, TA::Disable, "USP:%08x", tmp.usp);
! 427: screen.Print(x, 2, TA::Disable, "MSP:%08x", tmp.msp);
1.1 root 428: } else {
429: // User mode (A7=USP, ISP/MSP)
1.1.1.16! root 430: screen.Print(x, 1, TA::Disable, "ISP:%08x", tmp.isp);
! 431: screen.Print(x, 2, TA::Disable, "MSP:%08x", tmp.msp);
1.1 root 432: }
433:
434: // 6列目
1.1.1.16! root 435: // PC: 01234567
! 436: // SFC:1 DFC:1
! 437: // VBR:01234567
1.1 root 438: x = 66;
1.1.1.16! root 439: screen.Print(x, 0, "PC: %08x", tmp_ppc);
! 440: screen.Print(x, 1, "SFC:%d DFC:%d", tmp.GetSFC(), tmp.GetDFC());
! 441: screen.Print(x, 2, "VBR:%08x", tmp.vbr);
1.1 root 442:
1.1.1.15 root 443: switch (tmp_state) {
444: case CPU_STATE_NORMAL:
1.1.1.16! root 445: screen.Puts(50, 3, "State: Running");
1.1.1.13 root 446: break;
1.1.1.15 root 447: case CPU_STATE_STOP:
1.1.1.16! root 448: screen.Puts(50, 3, "State: STOP instruction");
1.1.1.13 root 449: break;
1.1.1.15 root 450: case CPU_STATE_HALT:
1.1.1.16! root 451: screen.Puts(50, 3, TA::On, "State: Double Bus Fault");
1.1.1.13 root 452: break;
453: default:
1.1.1.16! root 454: screen.Print(50, 3, TA::On, "corrupted cpu_state=%d", tmp_state);
1.1.1.15 root 455: break;
1.1 root 456: }
457:
1.1.1.16! root 458: // Cache
! 459: y = 4;
! 460: screen.Puts(0, y++, "<Cache>");
! 461: screen.Print(0, y, "CACR:%08x(", tmp.cacr);
! 462: screen.Puts(14, y, TA::OnOff(tmp.cacr & M68K::CACR_WA), "WA");
! 463: screen.Puts(17, y, TA::OnOff(tmp.cacr & M68K::CACR_DBE), "DBE");
! 464: screen.Puts(21, y, TA::OnOff(tmp.cacr & M68K::CACR_FD), "FD");
! 465: screen.Puts(24, y, TA::OnOff(tmp.cacr & M68K::CACR_ED), "ED");
! 466: screen.Puts(27, y, TA::OnOff(tmp.cacr & M68K::CACR_IBE), "IBE");
! 467: screen.Puts(31, y, TA::OnOff(tmp.cacr & M68K::CACR_FI), "FI");
! 468: screen.Puts(34, y, TA::OnOff(tmp.cacr & M68K::CACR_EI), "EI");
! 469: screen.Putc(36, y, ')');
! 470: screen.Print(50, y, "CAAR:%08x", tmp.caar);
! 471: y++;
! 472:
1.1 root 473: // MMU
474: x = 0;
1.1.1.9 root 475: screen.Puts(x, y++, "<MMU>");
1.1.1.15 root 476: screen.Print(x, y, "SRP:%08x_%08x", tmp.srp.h, tmp.srp.l);
477: screen.Print(x, y + 1, "CRP:%08x_%08x", tmp.crp.h, tmp.crp.l);
1.1.1.16! root 478: x += 25;
1.1 root 479: for (int i = 0; i < 2; i++) {
1.1.1.15 root 480: uint32 tt = tmp.tt[i];
1.1.1.16! root 481: screen.Print(x, y + i,
! 482: "TT%d:%08x(%c%c%c Addr=$%02x Mask=$%02x FC=%d FCMask=%d)",
1.1 root 483: i, tt,
484: (tt & m68030TT::E) ? 'E' : '-',
485: (tt & m68030TT::CI) ? 'C' : '-',
1.1.1.16! root 486: (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW) ? 'R' : 'W'),
! 487: (tt >> 24),
! 488: (tt >> 16) & 0xff,
! 489: (tt >> 4) & 0x07,
! 490: (tt ) & 0x07);
! 491: }
! 492: y += 2;
! 493: screen.Print(0, y,
! 494: "TC:%08x(%c%c%c IS=$%x TIA-D=%x:%x:%x:%x PS=$%x)",
1.1.1.15 root 495: tmp.tc,
496: (tmp.tc & m68030TC::TC_E) ? 'E' : '-',
497: (tmp.tc & m68030TC::TC_SRE) ? 'S' : '-',
1.1.1.16! root 498: (tmp.tc & m68030TC::TC_FCL) ? 'F' : '-',
! 499: (tmp.tc >> 16) & 0xf,
! 500: (tmp.tc >> 12) & 0xf,
! 501: (tmp.tc >> 8) & 0xf,
! 502: (tmp.tc >> 4) & 0xf,
! 503: (tmp.tc ) & 0xf,
! 504: (tmp.tc >> 20) & 0xf);
! 505: x = 49;
! 506: screen.Print(x, y, "MMUSR:%04x(", tmp.mmusr);
! 507: x += 11;
1.1.1.15 root 508: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::B) | 'B');
509: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::L) | 'L');
510: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::S) | 'S');
511: screen.Putc(x++, y, '-');
512: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::W) | 'W');
513: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::I) | 'I');
514: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::M) | 'M');
515: screen.Puts(x, y, "- -");
516: x += 3;
517: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::T) | 'T');
518: screen.Print(x, y, "---N=%d)", tmp.mmusr & m68030MMUSR::N);
1.1.1.16! root 519: y++;
1.1 root 520:
521: // FPU
522: x = 0;
1.1.1.9 root 523: screen.Puts(x, y++, "<FPU>");
1.1 root 524: for (int i = 0; i < 8; i++) {
1.1.1.9 root 525: screen.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)",
1.1 root 526: i,
1.1.1.15 root 527: tmp.fpframe.fpf_regs[i * 3 + 0] >> 16,
528: tmp.fpframe.fpf_regs[i * 3 + 1],
529: tmp.fpframe.fpf_regs[i * 3 + 2],
1.1 root 530: "not yet");
531: }
532:
533: x = 51;
534:
535: // FPCR
536: static const char * const rpstr[] = {
537: ".EXT",
538: ".SGL",
539: ".DBL",
540: ".???",
541: };
1.1.1.15 root 542: uint32 fpcr = tmp.fpframe.fpf_fpcr;
1.1.1.9 root 543: screen.Print(x, y++, "FPCR:%04x", fpcr);
1.1.1.11 root 544: screen.Puts(x + 2, y, TA::OnOff(fpcr & 0x8000), "BS");
545: screen.Puts(x + 5, y, TA::OnOff(fpcr & 0x4000), "SN");
546: screen.Puts(x + 8, y, TA::OnOff(fpcr & 0x2000), "OP");
547: screen.Puts(x + 11, y, TA::OnOff(fpcr & 0x1000), "OV");
548: screen.Puts(x + 14, y, TA::OnOff(fpcr & 0x0800), "UF");
549: screen.Puts(x + 17, y, TA::OnOff(fpcr & 0x0400), "DZ");
550: screen.Puts(x + 20, y, TA::OnOff(fpcr & 0x0200), "I2");
551: screen.Puts(x + 23, y, TA::OnOff(fpcr & 0x0100), "I1");
552: y++;
1.1.1.9 root 553: screen.Print(x + 2, y++, "RP=%s RM=%s",
1.1 root 554: rpstr[(fpcr >> 6) & 3],
555: rmstr[(fpcr >> 4) & 3]);
556:
557: // FPSR
1.1.1.15 root 558: uint32 fpsr = tmp.fpframe.fpf_fpsr;
1.1 root 559: uint32 cc = fpsr >> 24;
1.1.1.9 root 560: screen.Print(x, y++, "FPSR:%08x", fpsr);
1.1.1.11 root 561: screen.Puts(x + 2, y, TA::OnOff(cc & 0x08), "N");
562: screen.Puts(x + 4, y, TA::OnOff(cc & 0x04), "Z");
563: screen.Puts(x + 6, y, TA::OnOff(cc & 0x02), "Inf");
564: screen.Puts(x + 10, y, TA::OnOff(cc & 0x01), "NAN");
565: screen.Print(x + 14, y, "Q=$%02x", (fpsr >> 16) & 0xff);
566: y++;
567: screen.Puts(x + 2, y, TA::OnOff(fpsr & 0x8000), "BS");
568: screen.Puts(x + 5, y, TA::OnOff(fpsr & 0x4000), "SN");
569: screen.Puts(x + 8, y, TA::OnOff(fpsr & 0x2000), "OP");
570: screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x1000), "OV");
571: screen.Puts(x + 14, y, TA::OnOff(fpsr & 0x0800), "UF");
572: screen.Puts(x + 17, y, TA::OnOff(fpsr & 0x0400), "DZ");
573: screen.Puts(x + 20, y, TA::OnOff(fpsr & 0x0200), "I2");
574: screen.Puts(x + 23, y, TA::OnOff(fpsr & 0x0100), "I1");
575: y++;
576: screen.Puts(x + 2, y, TA::OnOff(fpsr & 0x80), "IOP");
577: screen.Puts(x + 6, y, TA::OnOff(fpsr & 0x80), "OVFL");
578: screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x80), "UNFL");
579: screen.Puts(x + 16, y, TA::OnOff(fpsr & 0x80), "DZ");
580: screen.Puts(x + 19, y, TA::OnOff(fpsr & 0x80), "INEX");
581: y++;
1.1 root 582:
583: // FPIAR
1.1.1.15 root 584: screen.Print(x, y++, "FPIAR:%08x", tmp.fpframe.fpf_fpiar);
1.1 root 585: }
586:
1.1.1.9 root 587: // モニター更新 (ATC)
1.1.1.3 root 588: void
1.1.1.9 root 589: MPU680x0Device::MonitorUpdateATC(Monitor *, TextScreen& screen)
1.1 root 590: {
591: m68030ATCTable *table;
592: #if !defined(ATC_SINGLE)
593: struct {
594: int fc;
595: const char *name;
596: } fclist[] = {
597: { 1, "User/Data" },
598: { 2, "User/Program" },
599: { 5, "Super/Data" },
600: { 6, "Super/Program" },
601: };
602:
1.1.1.9 root 603: screen.Clear();
1.1 root 604:
605: // 行数は左端にだけ
606: for (int i = 0; i < m68030ATCTable::LINES; i++) {
1.1.1.9 root 607: screen.Print(0, i + 2, "%02d:", i);
1.1 root 608: }
609:
610: for (int t = 0; t < countof(fclist); t++) {
1.1.1.16! root 611: int x = t * 33 + 4;
1.1 root 612: int fc = fclist[t].fc;
613: const char *name = fclist[t].name;
614: double r;
615: int i;
616:
1.1.1.15 root 617: table = &atc.tables[fc];
1.1.1.9 root 618: screen.Print(x, 0, "FC=%d %s", fc, name);
1.1.1.16! root 619: screen.Puts(x, 1, "LAddr PAddr Flag Hit% Age");
1.1 root 620: // 先に統計用の母数を計算
621: uint64 total = 0;
622: for (i = 0; i < countof(table->hit); i++) {
623: total += table->hit[i];
624: }
625: total += table->hit_head;
626:
627: // エントリ表示
628: for (i = 0; i < countof(table->line); i++) {
629: m68030ATCLine& a = table->line[i];
1.1.1.2 root 630: TA attr;
1.1 root 631: if (a.IsInvalid()) {
632: attr = TA::Disable;
633: } else if (table->head == &a) {
634: attr = TA::Em;
635: } else {
636: attr = TA::Normal;
637: }
638:
1.1.1.16! root 639: screen.Print(x, i + 2, attr, "%08x %08x %c%c%c%c",
1.1 root 640: a.GetLAddr(),
641: a.GetPAddr(),
642: a.IsBusError() ? 'B' : '-',
1.1.1.16! root 643: a.IsCInhibit() ? 'C' : '-',
1.1 root 644: a.IsWProtect() ? 'P' : '-',
645: a.IsModified() ? 'M' : '-');
646: }
647: // ヘッドのヒット率
1.1.1.9 root 648: screen.Puts(x + 0, i + 2, "head");
1.1 root 649: r = (double)table->hit_head * 100 / total;
1.1.1.13 root 650: if (!std::isnan(r)) {
1.1.1.9 root 651: screen.Print(x + 5, i + 2, "%4.1f%%", r);
1.1 root 652: }
653: // 配列のヒット率とミス率
1.1.1.16! root 654: screen.Puts(x + 18, i + 2, "miss");
1.1 root 655: for (i = 0; i < countof(table->hit); i++) {
656: r = (double)(table->hit[i] * 100) / total;
1.1.1.13 root 657: if (!std::isnan(r)) {
1.1.1.16! root 658: screen.Print(x + 23, i + 2, "%4.1f%%", r);
1.1 root 659: }
660: }
661: // カウンタ
662: // 分かりやすさのため最大値からの差(距離)を表示
663: for (i = 0; i < countof(table->line); i++) {
664: m68030ATCLine& a = table->line[i];
665: if (!a.IsInvalid()) {
1.1.1.16! root 666: screen.Print(x + 28, i + 2, "%4d", table->head->age - a.age);
1.1 root 667: }
668: }
669: }
1.1.1.16! root 670:
! 671: screen.Print(0, 25,
! 672: "Note: Real 68030's ATC is 22 entries, FC-mixed. "
! 673: "This FC-separated one is by nono.");
1.1 root 674: #else
675: m68030ATCLine *a;
676: int i;
677:
1.1.1.15 root 678: table = &atc.tables[0];
1.1.1.9 root 679: screen.Clear();
1.1 root 680:
1.1.1.9 root 681: screen.Puts(0, 0, "No. FC LAddr PAddr Flag");
1.1 root 682: for (a = table->head, i = 0; a; a = a->next, i++) {
1.1.1.9 root 683: screen.Print(0, i + 1, "%02d:", i);
1.1 root 684: if (!a->IsInvalid()) {
685: char dp;
686: switch (a->fc & 3) {
687: case 1: dp = 'D'; break;
688: case 2: dp = 'P'; break;
689: default: dp = '?'; break;
690: }
1.1.1.16! root 691: screen.Print(4, i + 1, "%d(%c%c):%08x %08x %c%c%c%c",
1.1 root 692: a->fc,
693: (a->fc & 4) ? 'S' : 'U',
694: dp,
695: a->GetLAddr(), a->GetPAddr(),
696: a->IsBusError() ? 'B' : '-',
1.1.1.16! root 697: a->IsCInhibit() ? 'C' : '-',
1.1 root 698: a->IsWProtect() ? 'W' : '-',
699: a->IsModified() ? 'M' : '-');
700: }
701: }
702: #endif
703: }
1.1.1.16! root 704:
! 705: // モニタ更新 (キャッシュ)
! 706: void
! 707: MPU680x0Device::MonitorUpdateCache(Monitor *, TextScreen& screen)
! 708: {
! 709: int y;
! 710: screen.Clear();
! 711:
! 712: // <I-Cache>
! 713: // 01234567890123456789012345678901234567890123456789
! 714: // Tag Address Data
! 715: // S.012345'00: 00000000 00000000 -------- 00000000
! 716:
! 717: screen.Print(0, 0, "<I-Cache>");
! 718: screen.Print(0, 1, "Tag Address Data");
! 719:
! 720: y = 2;
! 721: for (int idx = 0; idx < icache->line.size(); idx++) {
! 722: auto& l = icache->line[idx];
! 723: screen.Print(0, y, "%c.%06x'%x0:",
! 724: (l.IsSuper() ? 'S' : 'U'),
! 725: (l.TagAddr() >> 8),
! 726: idx);
! 727:
! 728: for (int i = 0; i < 4; i++) {
! 729: if (l.valid[i]) {
! 730: screen.Print(13 + 9 * i, y, "%08x", l.data[i]);
! 731: } else {
! 732: screen.Print(13 + 9 * i, y, TA::Disable, "--------");
! 733: }
! 734: }
! 735: y++;
! 736: }
! 737:
! 738: y++;
! 739: screen.Print(0, y, "<D-Cache> Not Implemented");
! 740: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.