|
|
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: //
1.1.1.18 root 8: // MPU (MC68030/MC68040)
1.1.1.13 root 9: //
1.1 root 10:
1.1.1.19 root 11: // MPU/FPU 種別について:
12: //
13: // 構造上やむをえないが MPU が 68030 なら FPU は fpu-type で指定し、
14: // MPU が 68040/68LC040 なら mpu-type で MPU/FPU を指定する。
15: //
16: // mpu-type fpu-type
17: // -------- --------
18: // 68030 none : 68030、FPU なし
19: // 68030 68881 : 68030 + 68881
20: // 68LC040 - : 68040 (FPU なし)
21: // 68040 - : 68040 (FPU あり)
22:
1.1 root 23: #include "mpu680x0.h"
24: #include "config.h"
1.1.1.13 root 25: #include "debugger.h"
1.1.1.21 root 26: #include "event.h"
1.1.1.18 root 27: #include "exttostr.h"
1.1.1.15 root 28: #include "interrupt.h"
1.1.1.16 root 29: #include "m68030cache.h"
1.1.1.18 root 30: #include "m68040mmu.h"
1.1 root 31: #include "mainapp.h"
1.1.1.17 root 32: #include "mainbus.h"
1.1.1.13 root 33: #include "scheduler.h"
1.1.1.10 root 34: #include "uimessage.h"
1.1.1.15 root 35: #include "vectortable.h"
1.1.1.13 root 36:
1.1.1.18 root 37: // ブートストラップ。設定に応じてインスタンスを生成して返す。
38: // ここではとりあえず 68040 かそれ以外なら 68030 を生成しておき、
39: // Init() でもう一度 (機種情報も含めて) チェックする。
40: // Init() (か Create()) まで進まないとエラー終了出来ないが、
41: // その時点では MainMPU のインスタンスは必要なので。
42: MPU680x0Device *
43: NewMPU680x0Device()
44: {
45: const ConfigItem& item = gConfig->Find("mpu-type");
46: std::string mpu_type = item.AsString();
47:
48: // 設定に応じて継承側のクラスを作成する。
1.1.1.19 root 49: // この段階では知らないものは一旦 68030 にしておく。
50: if (mpu_type == "68040" || strcasecmp(mpu_type.c_str(), "68LC040") == 0) {
1.1.1.18 root 51: return new MPU68040Device();
52: } else {
53: return new MPU68030Device();
54: }
55: }
56:
57:
58: //
59: // 68030/040 共通クラス
60: //
61:
1.1 root 62: // コンストラクタ
1.1.1.8 root 63: MPU680x0Device::MPU680x0Device()
1.1.1.15 root 64: : inherited()
1.1 root 65: {
1.1.1.18 root 66: // MPU 種別は継承側で設定する。設定されないままなら Init() でエラー。
67: mpu_type = m680x0MPUType::NONE;
1.1.1.15 root 68:
69: // FPU
70: fpu_init();
1.1 root 71:
1.1.1.17 root 72: // 例外カウンタ
73: excep_counter.resize(256);
1.1 root 74: }
75:
76: // デストラクタ
77: MPU680x0Device::~MPU680x0Device()
78: {
79: }
80:
1.1.1.15 root 81: // 初期化
1.1 root 82: bool
83: MPU680x0Device::Init()
84: {
1.1.1.5 root 85: if (inherited::Init() == false) {
86: return false;
87: }
1.1.1.13 root 88:
1.1.1.18 root 89: // なる早で、もう一度 MPU 設定を読んで判定。そのついでに FPU も判定。
1.1.1.19 root 90: // "mpu-type" の設定値が不正な場合でも (コンストラクト時点ではまだエラーを
1.1.1.18 root 91: // 報告できない構造なので) 一旦 MPU68030Device インスタンスとしてここに
92: // 来る。なのでここで改めてチェックしてエラー報告する必要がある。
93: // mpu_type (メンバ変数) 自体はすでにセットされている。
1.1.1.19 root 94: const ConfigItem& mputype_item = gConfig->Find("mpu-type");
95: std::string mputype = mputype_item.AsString();
96: if (mputype == "68030") {
97: // FPU はこのすぐ次で機種ごとに選ぶ。
98: } else if (mputype == "68040") {
99: fpu_type = m680x0FPUType::M68040;
100: } else if (strcasecmp(mputype.c_str(), "68LC040") == 0) {
101: fpu_type = m680x0FPUType::M68LC040;
102: // 名前も再設定?
103: mpu_name = "MC68LC040";
104: SetName("MPU(68LC040)");
105: } else {
1.1.1.18 root 106: mputype_item.Err();
107: return false;
108: }
109:
110: // 機種ごとに MPU/FPU のサポート状況が違う。
1.1.1.19 root 111: // 68030 なら fpu_type はここでセットする。
1.1.1.18 root 112: switch (gMainApp.GetVMType()) {
113: case VMType::LUNA1:
114: case VMType::NEWS:
115: // NEWS は元々 68030 モデルのみ。
116: // うち NWS-1750 は 68030/68882 固定のようだがここでは 68881 とする。
117: // LUNA-I は基本的に 68030/68881 モデルのみ。
118: if (mpu_type != m680x0MPUType::M68030) {
119: mputype_item.Err("Only 68030 can be specified for vmtype=%s",
120: gMainApp.GetVMTypeStr().c_str());
121: return false;
122: }
123: fpu_type = m680x0FPUType::M68881;
124: break;
125:
126: case VMType::X68030:
127: case VMType::VIRT68K:
128: // 68030/68040 をサポート。mpu_type は継承コンストラクタで設定済み。
129: if (mpu_type == m680x0MPUType::M68030) {
130: // 68030 なら FPU は設定で指定可能。
131: const ConfigItem& fputype_item = gConfig->Find("fpu-type");
132: std::string fputype = fputype_item.AsString();
133: if (fputype == "none" || fputype == "0") {
134: fpu_type = m680x0FPUType::M68030_NOFPU;
135: } else if (fputype == "68881" || fputype == "1") {
136: fpu_type = m680x0FPUType::M68881;
137: } else {
138: fputype_item.Err();
139: return false;
140: }
141: } else {
1.1.1.19 root 142: // 68040 なら FPU はすぐ上で設定済み。
1.1.1.18 root 143: }
144: break;
145:
146: default:
147: VMPANIC("vmtype=%s not configured", gMainApp.GetVMTypeStr().c_str());
148: break;
149: }
150:
1.1.1.22! root 151: // 機種ごとの NetBSD カーネルエントリポイント。
! 152: // 履歴で TRAP #0 がシステムコールかどうかの判定に使う。
! 153: switch (gMainApp.GetVMType()) {
! 154: case VMType::LUNA1:
! 155: netbsd_entrypoint = 0xc000;
! 156: break;
! 157: case VMType::X68030:
! 158: netbsd_entrypoint = 0x0022;
! 159: break;
! 160: case VMType::NEWS:
! 161: netbsd_entrypoint = 0x0000;
! 162: break;
! 163: case VMType::VIRT68K:
! 164: netbsd_entrypoint = 0x2000;
! 165: break;
! 166: default:
! 167: __unreachable();
! 168: }
! 169:
1.1.1.15 root 170: interruptdev = GetInterruptDevice();
1.1.1.18 root 171: vectortable = GetVectorTable();
1.1.1.15 root 172:
1.1.1.18 root 173: // 割り込みイベントコールバック設定。
1.1.1.13 root 174: //
175: // 外部デバイスが 68030 の IPL0-2 をアサートしてから、68030 がそれを
176: // 認識(確定)するのに 1 ~ 2 クロックかかる。
177: // その後レベルを比較するのは次のアップエッジ。
178: // その後 /IPEND をアサートするのはその次のアップエッジ。
179: // 合わせると、IPL0-2 が変化してから /IPEND がアサートされるまでは
180: // 2 ~ 3 クロックかかる。(Figure 8-4)
1.1.1.21 root 181: auto evman = GetEventManager();
182: intr_event = evman->Regist(this,
183: ToEventCallback(&MPU680x0Device::InterruptCallback),
184: GetName() + " Interrupt");
1.1.1.22! root 185: intr_event->time = 3 * clock_tsec;
1.1.1.5 root 186:
1.1.1.18 root 187: // レジスタモニタの行数。
188: int height = 9;
189: if (mpu_type == m680x0MPUType::M68030) {
190: height++;
191: }
192: if (HasFPU()) {
193: height += 12;
194: if (GetFPUType().Is4060FPU()) {
195: height += 3;
1.1 root 196: }
197: }
1.1.1.18 root 198: reg_monitor->SetSize(78, height);
1.1.1.17 root 199:
1.1 root 200: return true;
201: }
202:
1.1.1.13 root 203: // リセット
204: void
205: MPU680x0Device::ResetHard(bool poweron)
1.1.1.8 root 206: {
1.1.1.13 root 207: if (poweron) {
1.1.1.15 root 208: // サイクルを初期化。
209: used_cycle = 0;
210:
211: // 履歴を初期化。電源(再)投入時のみ行う。
212: exhist.Clear();
213: brhist.Clear();
214:
215: for (int i = 0; i < 16; i++) {
216: reg.R[i] = 0xcccccccc;
217: }
218: // XXX ただし X68030 IPLROM には A6 を初期化せずに書き込んでいるバグが
219: // あるため、A6 を概ね RAM のあるあたりに指定しておく…。
220: reg.A[6] = 0x000ccccc;
221:
222: // この後起きるリセット例外で PC を初期化する前に参照することになるので
223: // これだけここでも初期化しておく。
224: reg.pc = 0;
1.1.1.13 root 225: }
1.1.1.14 root 226: resetting = true;
1.1.1.13 root 227:
228: // リセット例外を 520 クロック後に起こす。
229: // 520 は、電源オン時、Vcc が最小動作規定値に達してから最低 520 クロック
230: // の間アサートしなければならないという値であって、実際これだけかかる
231: // とかいう値ではない。が、こちら側の都合で、この後実行される RAM の
1.1.1.15 root 232: // ResetHard() がブートページを用意した後で ExceptionReset() で
1.1.1.13 root 233: // SP, PC をフェッチするという順序にしないといけないため、リセット例外が
234: // 起動するまでに時間がかかるというところを都合よく真似ておく。
235:
1.1.1.22! root 236: exec_event->SetCallback(&MPU680x0Device::ResetCallback);
! 237: exec_event->time = 520 * clock_tsec;
1.1.1.21 root 238: exec_event->SetName(GetName() + " Reset");
1.1.1.15 root 239: scheduler->RestartEvent(exec_event);
1.1.1.8 root 240: }
241:
1.1.1.13 root 242: // リセット例外コールバック。
243: // MPU リセットから規定時間後に呼ばれる。
1.1.1.8 root 244: void
1.1.1.21 root 245: MPU680x0Device::ResetCallback(Event *ev)
1.1.1.8 root 246: {
1.1.1.14 root 247: resetting = false;
1.1.1.13 root 248: intr_pending = false;
249:
250: // リセット例外を実行
1.1.1.15 root 251: int cycle = ExceptionReset();
1.1.1.13 root 252:
253: // コールバックを ResetCallback から Exec* に差し替える前のここで
254: // トレース状態を初期化する。
1.1.1.15 root 255: SetTrace(debugger->IsTrace());
1.1.1.13 root 256:
257: // 以降は通常走行。
1.1.1.15 root 258: if (cpu_state == CPU_STATE_NORMAL) {
1.1.1.22! root 259: exec_event->SetCallback(exec_short);
! 260: exec_event->time = cycle * clock_tsec;
1.1.1.21 root 261: exec_event->SetName(GetName() + " Execute");
1.1.1.15 root 262: scheduler->RestartEvent(exec_event);
1.1.1.13 root 263: } else {
264: // リセット例外でダブルバスフォールトならここで停止。
265: }
1.1.1.8 root 266: }
267:
1.1.1.15 root 268: // 割り込みチェック、STOP/HALT 処理を含んだ完全な実行サイクルのコールバック。
1.1.1.13 root 269: // SR の I2:I0 が変わった直後などに呼ばれる。
270: // ここでは割り込みをチェックし、必要なら割り込み処理を起動、
271: // そうでなければ通常の命令実行を行う。
272: void
1.1.1.21 root 273: MPU680x0Device::ExecFull(Event *ev)
1.1.1.13 root 274: {
1.1.1.15 root 275: if (cpu_state == CPU_STATE_HALT) {
276: // HALT なら停止。
277: return;
278: }
279:
280: // マスクよりも割り込みレベルのほうが高ければ割り込み処理。
281: // この時点で intr_pending が true の可能性もあることに留意。
282: // 割り込みレベルは変化してないので Level 7 の特別処理は不要
283: // (割り込みレベルの変化はここではなく InterruptCallback() で処理)。
284: if (intr_level > reg.intr_mask) {
285: intr_pending = true;
286: }
1.1.1.14 root 287:
1.1.1.13 root 288: if (intr_pending) {
289: // 割り込み処理を起動。
290:
291: intr_pending = false;
292:
293: // 前の命令実行後となるここで割り込みを起動
1.1.1.21 root 294: ev->time = ExceptionInterrupt();
1.1.1.15 root 295: scheduler->StartEvent(ev);
1.1.1.13 root 296: } else {
1.1.1.15 root 297: if (cpu_state == CPU_STATE_NORMAL) {
1.1.1.13 root 298: // コールバックを通常処理に戻してから...
1.1.1.22! root 299: exec_event->SetCallback(exec_short);
1.1.1.13 root 300:
301: // この場で次の命令を実行。
302: ExecShort(ev);
303: } else {
1.1.1.15 root 304: // STOP ならここで停止。
1.1.1.13 root 305: }
306: }
1.1 root 307: }
308:
1.1.1.13 root 309: // トレース実行
310: void
1.1.1.21 root 311: MPU680x0Device::ExecTrace(Event *ev)
1.1 root 312: {
1.1.1.15 root 313: debugger->ExecMain();
1.1.1.13 root 314: ExecFull(ev);
1.1 root 315: }
316:
1.1.1.13 root 317: // トレース状態を設定する
318: void
319: MPU680x0Device::SetTrace(bool enable)
1.1 root 320: {
1.1.1.13 root 321: if (enable) {
322: exec_short = ToEventCallback(&MPU680x0Device::ExecTrace);
323: exec_full = ToEventCallback(&MPU680x0Device::ExecTrace);
324: } else {
325: exec_short = ToEventCallback(&MPU680x0Device::ExecShort);
326: exec_full = ToEventCallback(&MPU680x0Device::ExecFull);
327: }
1.1.1.22! root 328: exec_event->SetCallback(exec_full);
1.1.1.13 root 329:
330: // STOP 命令中にオンにするには、停止しているイベントを起こす。
331: // STOP 命令中にオフにする場合は、何もしなくていい。
1.1.1.21 root 332: if (enable && exec_event->IsRunning() == false) {
1.1.1.15 root 333: scheduler->StartEvent(exec_event);
1.1.1.13 root 334: }
1.1 root 335: }
336:
1.1.1.5 root 337: // 割り込みレベルが変わったことを MPU に通知。
1.1 root 338: void
1.1.1.5 root 339: MPU680x0Device::Interrupt(int level)
1.1 root 340: {
1.1.1.5 root 341: assertmsg(0 <= level && level <= 7, "level=%d", level);
342:
1.1.1.21 root 343: intr_event->code = level;
344: if (intr_event->IsRunning() == false) {
1.1.1.15 root 345: scheduler->StartEvent(intr_event);
1.1.1.5 root 346: }
1.1.1.13 root 347: }
348:
349: // 外部割り込みイベントコールバック。
350: // ev.code 0-7 は新しい割り込みレベル。
1.1.1.15 root 351: //
352: // 割り込みは本来命令境界ごとにチェックするが、実際に割り込みが起きうるのは
353: // 1) 割り込み信号線が変化した時
354: // 2) 割り込みマスクを変更した時
355: // しかないはずなので、この時だけ命令境界でチェックする。
356: // ここはその 1) のほう。その2のほうは core.cpp:SetSR() 参照。
357: //
358: // 外部割り込みが来たので、レベル比較などをして、必要なら次の命令境界で
359: // 割り込みチェックを行うようにするところ。
1.1.1.13 root 360: void
1.1.1.21 root 361: MPU680x0Device::InterruptCallback(Event *ev)
1.1.1.13 root 362: {
1.1.1.21 root 363: uint level = ev->code;
1.1.1.17 root 364: uint mask = reg.intr_mask;
1.1.1.15 root 365:
366: // 信号線が 2 クロック期間安定していること云々は省略
1.1.1.13 root 367:
1.1.1.16 root 368: // 割り込みを起こすかどうかに関わらずここで更新。
369: intr_level = level;
370:
371: // ホールトならここまで。
1.1.1.15 root 372: if (cpu_state == CPU_STATE_HALT) {
373: return;
374: }
375:
376: // 割り込み例外を起動するのは
377: // o レベルがマスクより高い
378: // o マスクに関係なく、レベルが下位から 7 に変化した場合
379: // (ここは変化した時だけ呼ばれるのと 7 より上はないので
380: // level==7 なら必ず「下位から 7 に変化」のはず)
381: if (level > mask || level == 7) {
1.1.1.13 root 382: // 通知した結果割り込みが受け付けられたので、
383: // この命令終了時のコールバックを割り込み処理起動に差し替える。
384: MakeNextFull();
385: intr_pending = true;
386:
387: // STOP 状態だったらここでイベントを開始する
1.1.1.15 root 388: if (cpu_state == CPU_STATE_STOP) {
1.1.1.13 root 389: // STOP から抜ける時間?
1.1.1.22! root 390: exec_event->time = 1 * clock_tsec;
1.1.1.15 root 391: scheduler->StartEvent(exec_event);
1.1.1.13 root 392: }
393: }
394: }
395:
396: // 次の命令境界は Full にする。
397: void
398: MPU680x0Device::MakeNextFull()
399: {
1.1.1.22! root 400: exec_event->SetCallback(exec_full);
1.1.1.13 root 401: }
402:
1.1 root 403: // A-Line 命令エミュレーションのコールバックを指定。
404: void
1.1.1.15 root 405: MPU680x0Device::SetALineCallback(bool (*callback)(MPU680x0Device *, void*),
406: void *arg)
1.1 root 407: {
1.1.1.15 root 408: aline_callback = callback;
409: aline_arg = arg;
1.1 root 410: }
411:
412: // F-Line 命令エミュレーションのコールバックを指定。
413: void
1.1.1.15 root 414: MPU680x0Device::SetFLineCallback(bool (*callback)(MPU680x0Device *, void*),
415: void *arg)
1.1 root 416: {
1.1.1.15 root 417: fline_callback = callback;
418: fline_arg = arg;
1.1 root 419: }
420:
1.1.1.15 root 421: // RESET 命令
422: void
423: MPU680x0Device::ops_reset()
1.1.1.10 root 424: {
1.1.1.16 root 425: mainbus->ResetByMPU();
1.1.1.13 root 426: }
427:
428: // ホールト状態
429: void
430: MPU680x0Device::Halt()
431: {
1.1.1.15 root 432: ChangeState(CPU_STATE_HALT);
433:
434: // この命令完了後に停止するため exec を差し替える。
435: MakeNextFull();
1.1.1.13 root 436:
437: // UI に通知 (メッセージボックス表示とか)
1.1.1.21 root 438: gMainApp.GetUIMessage()->Post(UIMessage::HALT);
1.1.1.10 root 439: }
440:
1.1.1.18 root 441: // モニター更新の下請け (レジスタ共通部分)
1.1.1.3 root 442: void
1.1.1.22! root 443: MPU680x0Device::MonitorScreenRegCommon(TextScreen& screen,
1.1.1.18 root 444: m68kreg& tmp, uint32 tmp_ppc, uint32 tmp_state)
1.1 root 445: {
446: int x;
447:
448: // データレジスタ、アドレスレジスタ
449: for (int i = 0; i < 4; i++) {
1.1.1.17 root 450: screen.Print(0, i, "D%u:%08x D%u:%08x A%u:%08x A%u:%08x",
1.1.1.15 root 451: i + 0, tmp.R[i],
452: i + 4, tmp.R[i + 4],
453: i + 0, tmp.R[i + 8],
454: i + 4, tmp.R[i + 12]);
1.1 root 455: }
456:
457: // 5列目
458: x = 50;
459: // SR
1.1.1.9 root 460: screen.Print(x, 0, "SR:%04x(%c%c%c%c%c)",
1.1.1.15 root 461: tmp.GetSR(),
462: (tmp.ccr.IsX()) ? 'X' : '-',
463: (tmp.ccr.IsN()) ? 'N' : '-',
464: (tmp.ccr.IsZ()) ? 'Z' : '-',
465: (tmp.ccr.IsV()) ? 'V' : '-',
466: (tmp.ccr.IsC()) ? 'C' : '-');
1.1 root 467:
468: // *SP
1.1.1.15 root 469: uint ms = (tmp.s ? 2 : 0) | (tmp.m ? 1 : 0); // T1 T0 S M
1.1 root 470: if (ms == 3) {
471: // Supervisor (Master) mode (A7=MSP, USP/ISP)
1.1.1.16 root 472: screen.Print(x, 1, TA::Disable, "USP:%08x", tmp.usp);
473: screen.Print(x, 2, TA::Disable, "ISP:%08x", tmp.isp);
1.1 root 474: } else if (ms == 2) {
475: // Supervisor (Interrupt) mode (A7=ISP, USP/MSP)
1.1.1.16 root 476: screen.Print(x, 1, TA::Disable, "USP:%08x", tmp.usp);
477: screen.Print(x, 2, TA::Disable, "MSP:%08x", tmp.msp);
1.1 root 478: } else {
479: // User mode (A7=USP, ISP/MSP)
1.1.1.16 root 480: screen.Print(x, 1, TA::Disable, "ISP:%08x", tmp.isp);
481: screen.Print(x, 2, TA::Disable, "MSP:%08x", tmp.msp);
1.1 root 482: }
483:
484: // 6列目
1.1.1.16 root 485: // PC: 01234567
486: // SFC:1 DFC:1
487: // VBR:01234567
1.1 root 488: x = 66;
1.1.1.16 root 489: screen.Print(x, 0, "PC: %08x", tmp_ppc);
1.1.1.17 root 490: screen.Print(x, 1, "SFC:%u DFC:%u", tmp.GetSFC(), tmp.GetDFC());
1.1.1.16 root 491: screen.Print(x, 2, "VBR:%08x", tmp.vbr);
1.1 root 492:
1.1.1.15 root 493: switch (tmp_state) {
494: case CPU_STATE_NORMAL:
1.1.1.16 root 495: screen.Puts(50, 3, "State: Running");
1.1.1.13 root 496: break;
1.1.1.15 root 497: case CPU_STATE_STOP:
1.1.1.16 root 498: screen.Puts(50, 3, "State: STOP instruction");
1.1.1.13 root 499: break;
1.1.1.15 root 500: case CPU_STATE_HALT:
1.1.1.16 root 501: screen.Puts(50, 3, TA::On, "State: Double Bus Fault");
1.1.1.13 root 502: break;
503: default:
1.1.1.17 root 504: screen.Print(50, 3, TA::On, "corrupted cpu_state=%u", tmp_state);
1.1.1.15 root 505: break;
1.1 root 506: }
1.1.1.18 root 507: }
1.1 root 508:
1.1.1.18 root 509: // モニタ更新の下請け (FPU)
510: int
1.1.1.22! root 511: MPU680x0Device::MonitorScreenFPU(TextScreen& screen, int y, m68kreg& tmp)
1.1.1.18 root 512: {
513: int x;
514:
515: /*
516: 0123456789012345678901234567890123456789012345678901234567890123456789012345
517: FP0:7fff_ffffffff_ffffffff = NAN
518: FPCR: 0000 BS SN OP OV UF DZ I2 I1 Prec=.X Mode=Minus
519: FPSR: 00000000 N Z INF NAN Q=$xx BS SN OP OV UF DZ I2 I1 AV AO AU AD AI
520: FPIAR:00000000
521: */
522:
523: x = 0;
524: screen.Puts(x, y++, "<FPU>");
525: for (int i = 0; i < 8; i++) {
526: screen.Print(x, y++, "FP%u:%04x_%08x_%08x = %s",
527: i,
528: tmp.fpframe.fpf_regs[i * 3 + 0] >> 16,
529: tmp.fpframe.fpf_regs[i * 3 + 1],
530: tmp.fpframe.fpf_regs[i * 3 + 2],
531: ExtToStr(&tmp.fpframe.fpf_regs[i * 3]).c_str());
532: }
533:
534: // FPCR
535: uint32 fpcr = tmp.fpframe.fpf_fpcr;
536: screen.Puts(0, y, "FPCR:");
537: screen.Print(10, y, "%04x", fpcr);
538: x = 34;
539: screen.Puts(x + 0, y, TA::OnOff(fpcr & 0x8000), "BS");
540: screen.Puts(x + 3, y, TA::OnOff(fpcr & 0x4000), "SN");
541: screen.Puts(x + 6, y, TA::OnOff(fpcr & 0x2000), "OE");
542: screen.Puts(x + 9, y, TA::OnOff(fpcr & 0x1000), "OF");
543: screen.Puts(x + 12, y, TA::OnOff(fpcr & 0x0800), "UF");
544: screen.Puts(x + 15, y, TA::OnOff(fpcr & 0x0400), "DZ");
545: screen.Puts(x + 18, y, TA::OnOff(fpcr & 0x0200), "X2");
546: screen.Puts(x + 21, y, TA::OnOff(fpcr & 0x0100), "X1");
547: screen.Print(x + 25, y, "RP=.%c RM=%s",
548: "XSD?"[(fpcr >> 6) & 3],
549: rmstr[(fpcr >> 4) & 3]);
550: y++;
551:
552: // FPSR
553: uint32 fpsr = tmp.fpframe.fpf_fpsr;
554: uint32 cc = fpsr >> 24;
555: screen.Print(0, y, "FPSR: %08x", fpsr);
556: x = 15;
557: screen.Puts(x + 0, y, TA::OnOff(cc & 0x08), "N");
558: screen.Puts(x + 2, y, TA::OnOff(cc & 0x04), "Z");
559: screen.Puts(x + 4, y, TA::OnOff(cc & 0x02), "Inf");
560: screen.Puts(x + 8, y, TA::OnOff(cc & 0x01), "NAN");
561: screen.Print(x + 12, y, "Q=$%02x", (fpsr >> 16) & 0xff);
562: x = 34;
563: screen.Puts(x + 0, y, TA::OnOff(fpsr & 0x8000), "BS");
564: screen.Puts(x + 3, y, TA::OnOff(fpsr & 0x4000), "SN");
565: screen.Puts(x + 6, y, TA::OnOff(fpsr & 0x2000), "OE");
566: screen.Puts(x + 9, y, TA::OnOff(fpsr & 0x1000), "OF");
567: screen.Puts(x + 12, y, TA::OnOff(fpsr & 0x0800), "UF");
568: screen.Puts(x + 15, y, TA::OnOff(fpsr & 0x0400), "DZ");
569: screen.Puts(x + 18, y, TA::OnOff(fpsr & 0x0200), "X2");
570: screen.Puts(x + 21, y, TA::OnOff(fpsr & 0x0100), "X1");
571: screen.Puts(x + 25, y, TA::OnOff(fpsr & 0x80), "AV");
572: screen.Puts(x + 28, y, TA::OnOff(fpsr & 0x40), "AO");
573: screen.Puts(x + 31, y, TA::OnOff(fpsr & 0x20), "AU");
574: screen.Puts(x + 34, y, TA::OnOff(fpsr & 0x10), "AZ");
575: screen.Puts(x + 37, y, TA::OnOff(fpsr & 0x08), "AX");
576: y++;
577:
578: // FPIAR
579: screen.Print(0, y++, "FPIAR:%08x", tmp.fpframe.fpf_fpiar);
580:
581: return y;
582: }
583:
584:
585: //
586: // 68030
587: //
588:
589: // コンストラクタ
590: MPU68030Device::MPU68030Device()
591: : inherited()
592: {
593: mpu_type = m680x0MPUType::M68030;
594: mpu_name = "MC68030";
595: SetName("MPU(68030)");
596:
597: // MMU.xRP.DT == 0 になってはいけない(MMU 構成例外)。
598: SetSRP(0x00000001, 0);
599: SetCRP(0x00000001, 0);
600:
601: // キャッシュ
602: icache.reset(new m68030Cache());
603: dcache.reset(new m68030Cache());
604:
605: // レジスタモニター (サイズは Init で確定する)
606: reg_monitor = gMonitorManager->Regist(ID_MONITOR_MPUREG, this);
1.1.1.22! root 607: reg_monitor->SetCallback(&MPU68030Device::MonitorScreenReg);
1.1.1.18 root 608:
609: // ATC モニター
610: atc_monitor = gMonitorManager->Regist(ID_MONITOR_MPUATC, this);
1.1.1.22! root 611: atc_monitor->SetCallback(&MPU68030Device::MonitorScreenATC);
! 612: #if defined(M68030_CUSTOM_ATC)
1.1.1.18 root 613: atc_monitor->SetSize(114, m68030ATCTable::LINES + 6);
1.1.1.22! root 614: #else
! 615: atc_monitor->SetSize(45, m68030ATCTable::LINES + 2);
! 616: #endif
1.1.1.18 root 617:
618: // キャッシュモニター
619: cache_monitor = gMonitorManager->Regist(ID_MONITOR_MPUCACHE, this);
1.1.1.22! root 620: cache_monitor->SetCallback(&MPU68030Device::MonitorScreenCache);
1.1.1.18 root 621: cache_monitor->SetSize(48, 20 * 2 + 1);
622: }
623:
624: // デストラクタ
625: MPU68030Device::~MPU68030Device()
626: {
627: }
628:
629: void
630: MPU68030Device::SetLogLevel(int loglevel_)
631: {
632: inherited::SetLogLevel(loglevel_);
633:
634: atc.SetLogLevel(loglevel_);
635: }
636:
1.1.1.22! root 637: void
! 638: MPU68030Device::ResetHard(bool poweron)
! 639: {
! 640: inherited::ResetHard(poweron);
! 641:
! 642: if (poweron) {
! 643: // 電源(再)投入で統計情報もクリア。
! 644: atc.ResetStat();
! 645: }
! 646: }
! 647:
! 648: static int __unused
1.1.1.18 root 649: sort_atc(const void *a, const void *b)
650: {
651: const uint32 *ua = (const uint32 *)a;
652: const uint32 *ub = (const uint32 *)b;
653: return *ub - *ua;
654: }
655:
656: // モニター更新 (レジスタ)
657: void
1.1.1.22! root 658: MPU68030Device::MonitorScreenReg(Monitor *, TextScreen& screen)
1.1.1.18 root 659: {
660: m68kreg tmp;
661: uint32 tmp_ppc;
662: uint32 tmp_state;
663: int y;
664:
665: screen.Clear();
666:
667: // ローカルにコピーする。
668: // ただし一部は reg ではなく cpu クラス本体にある。
669: tmp = reg;
670: tmp_ppc = ppc;
671: tmp_state = cpu_state;
672:
673: // 共通部分。
1.1.1.22! root 674: MonitorScreenRegCommon(screen, tmp, tmp_ppc, tmp_state);
1.1.1.18 root 675:
676: // Cache/MMU 部分。
1.1.1.16 root 677: y = 4;
1.1.1.22! root 678: y = MonitorScreenMMU(screen, y, tmp);
1.1.1.18 root 679:
680: // FPU はある時だけ表示。
681: if (HasFPU()) {
1.1.1.22! root 682: MonitorScreenFPU(screen, y, tmp);
1.1.1.18 root 683: }
684: }
685:
686: // モニター更新の下請け (Cache/MMU 部分)
687: int
1.1.1.22! root 688: MPU68030Device::MonitorScreenMMU(TextScreen& screen, int y, m68kreg& tmp)
1.1.1.18 root 689: {
690: int x;
691:
692: // Cache
1.1.1.16 root 693: screen.Puts(0, y++, "<Cache>");
694: screen.Print(0, y, "CACR:%08x(", tmp.cacr);
1.1.1.18 root 695: screen.Puts(14, y, TA::OnOff(tmp.cacr & M68030::CACR_WA), "WA");
696: screen.Puts(17, y, TA::OnOff(tmp.cacr & M68030::CACR_DBE), "DBE");
1.1.1.17 root 697: screen.Puts(21, y, "- -");
1.1.1.18 root 698: screen.Puts(25, y, TA::OnOff(tmp.cacr & M68030::CACR_FD), "FD");
699: screen.Puts(28, y, TA::OnOff(tmp.cacr & M68030::CACR_ED), "ED");
1.1.1.17 root 700: screen.Puts(31, y, "000");
1.1.1.18 root 701: screen.Puts(35, y, TA::OnOff(tmp.cacr & M68030::CACR_IBE), "IBE");
1.1.1.17 root 702: screen.Puts(39, y, "- -");
1.1.1.18 root 703: screen.Puts(43, y, TA::OnOff(tmp.cacr & M68030::CACR_FI), "FI");
704: screen.Puts(46, y, TA::OnOff(tmp.cacr & M68030::CACR_EI), "EI");
1.1.1.17 root 705: screen.Putc(48, y, ')');
1.1.1.16 root 706: screen.Print(50, y, "CAAR:%08x", tmp.caar);
707: y++;
708:
1.1 root 709: // MMU
710: x = 0;
1.1.1.9 root 711: screen.Puts(x, y++, "<MMU>");
1.1.1.15 root 712: screen.Print(x, y, "SRP:%08x_%08x", tmp.srp.h, tmp.srp.l);
713: screen.Print(x, y + 1, "CRP:%08x_%08x", tmp.crp.h, tmp.crp.l);
1.1.1.16 root 714: x += 25;
1.1 root 715: for (int i = 0; i < 2; i++) {
1.1.1.15 root 716: uint32 tt = tmp.tt[i];
1.1.1.16 root 717: screen.Print(x, y + i,
1.1.1.17 root 718: "TT%u:%08x(%c%c%c Addr=$%02x Mask=$%02x FC=%u FCMask=%u)",
1.1 root 719: i, tt,
720: (tt & m68030TT::E) ? 'E' : '-',
721: (tt & m68030TT::CI) ? 'C' : '-',
1.1.1.16 root 722: (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW) ? 'R' : 'W'),
723: (tt >> 24),
724: (tt >> 16) & 0xff,
725: (tt >> 4) & 0x07,
726: (tt ) & 0x07);
727: }
728: y += 2;
729: screen.Print(0, y,
730: "TC:%08x(%c%c%c IS=$%x TIA-D=%x:%x:%x:%x PS=$%x)",
1.1.1.15 root 731: tmp.tc,
732: (tmp.tc & m68030TC::TC_E) ? 'E' : '-',
733: (tmp.tc & m68030TC::TC_SRE) ? 'S' : '-',
1.1.1.16 root 734: (tmp.tc & m68030TC::TC_FCL) ? 'F' : '-',
735: (tmp.tc >> 16) & 0xf,
736: (tmp.tc >> 12) & 0xf,
737: (tmp.tc >> 8) & 0xf,
738: (tmp.tc >> 4) & 0xf,
739: (tmp.tc ) & 0xf,
740: (tmp.tc >> 20) & 0xf);
741: x = 49;
742: screen.Print(x, y, "MMUSR:%04x(", tmp.mmusr);
743: x += 11;
1.1.1.15 root 744: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::B) | 'B');
745: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::L) | 'L');
746: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::S) | 'S');
747: screen.Putc(x++, y, '-');
748: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::W) | 'W');
749: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::I) | 'I');
750: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::M) | 'M');
751: screen.Puts(x, y, "- -");
752: x += 3;
753: screen.Putc(x++, y, TA::OnOff(tmp.mmusr & m68030MMUSR::T) | 'T');
1.1.1.17 root 754: screen.Print(x, y, "---N=%u)", tmp.mmusr & m68030MMUSR::N);
1.1.1.16 root 755: y++;
1.1 root 756:
1.1.1.18 root 757: return y;
1.1.1.17 root 758: }
759:
1.1.1.18 root 760: // モニター更新 (68030 ATC)
1.1.1.3 root 761: void
1.1.1.22! root 762: MPU68030Device::MonitorScreenATC(Monitor *, TextScreen& screen)
1.1 root 763: {
1.1.1.22! root 764: TA e_attr = mmu_tc.e ? TA::Normal : TA::Disable;
1.1.1.17 root 765:
766: screen.Clear();
767:
1.1.1.22! root 768: #if defined(M68030_CUSTOM_ATC)
! 769: m68030ATCTable_Custom *table;
! 770:
1.1 root 771: struct {
772: int fc;
773: const char *name;
774: } fclist[] = {
775: { 1, "User/Data" },
776: { 2, "User/Program" },
777: { 5, "Super/Data" },
778: { 6, "Super/Program" },
779: };
780:
1.1.1.17 root 781: for (uint t = 0; t < countof(fclist); t++) {
782: int x = t * 29;
1.1 root 783: int fc = fclist[t].fc;
784: const char *name = fclist[t].name;
785:
1.1.1.22! root 786: table = atc.GetTable(fc);
1.1.1.17 root 787: screen.Print(x, 0, "FC=%u %s", fc, name);
788: screen.Puts(x, 1, "No. LAddr PAddr Flag");
789:
790: std::array<uint32, m68030ATCTable::LINES * 2> sbuf;
791: for (uint i = 0; i < m68030ATCTable::LINES; i++) {
792: sbuf[i * 2 + 0] = table->line[i].age;
793: sbuf[i * 2 + 1] = i;
1.1 root 794: }
1.1.1.17 root 795: qsort(&sbuf[0], m68030ATCTable::LINES, sizeof(uint32) * 2, sort_atc);
1.1 root 796:
797: // エントリ表示
1.1.1.17 root 798: for (uint i = 0; i < m68030ATCTable::LINES; i++) {
799: int idx = sbuf[i * 2 + 1];
800: m68030ATCLine& a = table->line[idx];
1.1.1.22! root 801: TA v_attr;
1.1 root 802: if (a.IsInvalid()) {
1.1.1.22! root 803: v_attr = TA::Disable;
1.1 root 804: } else {
1.1.1.22! root 805: v_attr = TA::Normal;
1.1 root 806: }
807:
1.1.1.22! root 808: screen.Print(x, i + 2, e_attr, "[%02x]", idx);
! 809: screen.Print(x + 5, i + 2, v_attr, "%08x %08x %c%c%c%c",
1.1 root 810: a.GetLAddr(),
811: a.GetPAddr(),
812: a.IsBusError() ? 'B' : '-',
1.1.1.16 root 813: a.IsCInhibit() ? 'C' : '-',
1.1 root 814: a.IsWProtect() ? 'P' : '-',
815: a.IsModified() ? 'M' : '-');
816: }
1.1.1.17 root 817:
818: // ヒット率とミス率。
819: uint64 total = 0;
820: uint64 tthit = 0;
821: uint64 miss = 0;
822: bool tt_once_hit;
823:
824: {
1.1.1.22! root 825: std::lock_guard<std::mutex> lock(table->hist_mtx);
! 826: for (int i = 0; i < table->hist.Length(); i++) {
! 827: const auto& s = table->hist.Peek(i);
1.1.1.17 root 828: total += s.total;
829: tthit += s.tthit;
830: miss += s.miss;
1.1 root 831: }
1.1.1.22! root 832: tt_once_hit = table->hist_tt_once_hit;
1.1 root 833: }
1.1.1.17 root 834:
835: int y = m68030ATCTable::LINES + 2;
1.1.1.22! root 836: screen.Puts(x + 1, y, e_attr, "TT Match");
1.1.1.17 root 837: if (tt_once_hit) {
1.1.1.22! root 838: screen.Print(x + 10, y, e_attr, "%5.1f%%",
! 839: (double)(tthit * 100) / total);
1.1.1.17 root 840: } else {
1.1.1.22! root 841: screen.Puts(x + 12, y, e_attr, "0");
1.1 root 842: }
1.1.1.17 root 843: y++;
1.1.1.16 root 844:
1.1.1.22! root 845: screen.Puts(x + 1, y, e_attr, "ATC Match");
1.1.1.17 root 846: if (total == 0) {
1.1.1.22! root 847: screen.Puts(x + 12, y, e_attr, "0");
1.1.1.17 root 848: } else {
1.1.1.22! root 849: screen.Print(x + 10, y, e_attr, "%5.1f%%",
1.1.1.17 root 850: (double)((total - miss - tthit) * 100) / total);
851: }
852: y++;
1.1 root 853:
1.1.1.22! root 854: screen.Puts(x + 1, y, e_attr, "ATC Miss");
1.1.1.17 root 855: if (miss == 0) {
1.1.1.22! root 856: screen.Puts(x + 12, y, e_attr, "0");
1.1.1.17 root 857: } else {
1.1.1.22! root 858: screen.Print(x + 10, y, e_attr, "%5.1f%%",
! 859: (double)(miss * 100) / total);
1.1.1.17 root 860: }
861: y++;
862: }
1.1 root 863:
1.1.1.17 root 864: screen.Print(0, m68030ATCTable::LINES + 5,
865: "Note: The real 68030 ATC is single FC-mixed 22-entries. "
866: "This ATC with FC-separated %u-entries is by nono.",
867: m68030ATCTable::LINES);
1.1.1.22! root 868: #else
! 869: // 00 [00] SD(5).01234'567 01234'567 ----
! 870: screen.Puts(0, 0, "No Idx FC LAddr PAddr Flag Hit%");
! 871: uint y = 1;
! 872: auto table = atc.GetTable();
! 873: for (uint pri = 0; pri < m68030ATCTable::LINES; pri++) {
! 874: uint idx = table->GetIdx(pri);
! 875: const m68030ATCLine *a = &table->line[idx];
! 876: TA attr;
! 877: if (a->IsInvalid()) {
! 878: attr = TA::Disable;
! 879: } else {
! 880: attr = TA::Normal;
! 881: }
! 882: uint fc = a->GetFC();
! 883: screen.Print(0, y, e_attr, "%2d [%02d]", pri, idx);
! 884: screen.Print(8, y++, attr,
! 885: "%u(%s).%06x'00 %06x'00 %c%c%c%c",
! 886: fc, FCstr(fc),
! 887: (a->GetLAddr() >> 8),
! 888: (a->GetPAddr() >> 8),
! 889: (a->IsBusError() ? 'B' : '-'),
! 890: (a->IsCInhibit() ? 'C' : '-'),
! 891: (a->IsWProtect() ? 'P' : '-'),
! 892: (a->IsModified() ? 'M' : '-'));
! 893: }
! 894:
! 895: // ATC ヒット/ミス率。
! 896: m68030ATCStat tmp = table->stat;
! 897: std::array<float, m68030ATCTable::LINES> hitrate {};
! 898: float missrate = 0;
! 899: // total はヒットとミスの合計。
! 900: uint64 total = tmp.miss;
! 901: for (auto v : tmp.hit) {
! 902: total += v;
! 903: }
! 904: if (total != 0) {
! 905: for (uint i = 0; i < hitrate.size(); i++) {
! 906: hitrate[i] = (float)tmp.hit[i] / total * 100;
! 907: }
! 908: missrate = (float)tmp.miss / total * 100;
! 909: }
! 910: y = 1;
! 911: for (auto r : hitrate) {
! 912: screen.Print(38, y++, e_attr, "%6.2f%%", r);
! 913: }
! 914: screen.Print(31, y, e_attr, "ATCMiss%6.2f%%", missrate);
! 915: #endif
1.1.1.17 root 916: }
917:
918: // 統計情報を更新 (Syncer から呼ばれる)
919: void
1.1.1.18 root 920: MPU68030Device::CalcStat()
1.1.1.17 root 921: {
922: // ATC のヒット率。
1.1.1.22! root 923: atc.CalcStat();
1.1.1.17 root 924:
925: // キャッシュのヒット率。
926: icache->CalcStat();
927: dcache->CalcStat();
928: }
929:
930: static char
931: icache_fc2str(const m68030CacheLine& l)
932: {
933: return l.IsSuper() ? 'S' : 'U';
934: }
935:
936: static char
937: dcache_fc2str(const m68030CacheLine& l)
938: {
939: return "0U234S67"[l.GetFC()];
1.1 root 940: }
1.1.1.16 root 941:
1.1.1.18 root 942: // モニタ更新 (68030 キャッシュ)
1.1.1.16 root 943: void
1.1.1.22! root 944: MPU68030Device::MonitorScreenCache(Monitor *, TextScreen& screen)
1.1.1.16 root 945: {
946: int y;
1.1.1.17 root 947:
1.1.1.16 root 948: screen.Clear();
949:
1.1.1.17 root 950: // <Instruction Cache>
1.1.1.16 root 951: // 01234567890123456789012345678901234567890123456789
952: // Tag Address Data
953: // S.012345'00: 00000000 00000000 -------- 00000000
954:
1.1.1.17 root 955: y = 0;
956: screen.Puts(0, y++, "<Instruction Cache>");
1.1.1.22! root 957: y = MonitorScreenCache1(screen, y, icache.get(), icache_fc2str);
1.1.1.17 root 958:
959: y++;
960: screen.Puts(0, y++, "<Data Cache>");
1.1.1.22! root 961: MonitorScreenCache1(screen, y, dcache.get(), dcache_fc2str);
1.1.1.17 root 962: }
963:
1.1.1.18 root 964: // モニタ更新 (68030 キャッシュ片方の下請け)
1.1.1.17 root 965: int
1.1.1.22! root 966: MPU68030Device::MonitorScreenCache1(TextScreen& screen, int y,
1.1.1.17 root 967: m68030Cache *cache, char (*fc2str)(const m68030CacheLine&))
968: {
969: screen.Puts(0, y, "Tag Address Data[0]");
970: screen.Puts(13 + 1 * 9, y, "[1]");
971: screen.Puts(13 + 2 * 9, y, "[2]");
972: screen.Puts(13 + 3 * 9, y, "[3]");
973: y++;
1.1.1.16 root 974:
1.1.1.17 root 975: TA attr = cache->enable ? TA::Normal : TA::Disable;
976: for (int idx = 0; idx < cache->line.size(); idx++) {
977: auto& l = cache->line[idx];
978: screen.Print(0, y, attr, "%c.%06x'%x0:",
979: fc2str(l), (l.TagAddr() >> 8), idx);
1.1.1.16 root 980:
981: for (int i = 0; i < 4; i++) {
982: if (l.valid[i]) {
1.1.1.17 root 983: screen.Print(13 + 9 * i, y, attr, "%08x", l.data[i]);
1.1.1.16 root 984: } else {
1.1.1.17 root 985: screen.Puts(13 + 9 * i, y, TA::Disable, "--------");
1.1.1.16 root 986: }
987: }
988: y++;
989: }
990:
1.1.1.17 root 991: // 統計。
992: float hit = 0.0;
993: {
1.1.1.21 root 994: std::lock_guard<std::mutex> lock(cache->hist_mtx);
1.1.1.17 root 995: int len = cache->hist.Length();
996: if (len != 0) {
997: for (int i = 0; i < cache->hist.Length(); i++) {
998: const auto& s = cache->hist.Peek(i);
999: hit += s.hit;
1000: }
1001: hit /= len;
1002: }
1003: }
1004:
1.1.1.16 root 1005: y++;
1.1.1.17 root 1006: screen.Print(1, y++, attr, "Cache Read Hit %5.1f%%", hit);
1007:
1008: return y;
1.1.1.16 root 1009: }
1.1.1.18 root 1010:
1.1.1.22! root 1011: /*static*/ const char
! 1012: MPU68030Device::fcstr[] =
! 1013: "--\0\0" // 0
! 1014: "UD\0\0" // 1
! 1015: "UP\0\0" // 2
! 1016: "--\0\0" // 3
! 1017: "--\0\0" // 4
! 1018: "SD\0\0" // 5
! 1019: "SP\0\0" // 6
! 1020: "--"; // 7
! 1021:
1.1.1.18 root 1022:
1023: //
1024: // 68040
1025: //
1026:
1027: // コンストラクタ
1028: MPU68040Device::MPU68040Device()
1029: : inherited()
1030: {
1031: mpu_type = m680x0MPUType::M68040;
1032: mpu_name = "MC68040";
1033: SetName("MPU(68040)");
1034:
1.1.1.20 root 1035: cycle_table = cycle_table_040;
1036:
1.1.1.18 root 1037: mmu_itt[0].reset(new m68040TT("ITT0", ®.itt[0]));
1038: mmu_itt[1].reset(new m68040TT("ITT1", ®.itt[1]));
1039: mmu_dtt[0].reset(new m68040TT("DTT0", ®.dtt[0]));
1040: mmu_dtt[1].reset(new m68040TT("DTT1", ®.dtt[1]));
1041: mmu_tc.reset(new m68040TC());
1042: atc_inst.reset(new m68040ATC());
1043: atc_data.reset(new m68040ATC());
1044:
1045: // レジスタモニター (サイズは Init で確定する)
1046: reg_monitor = gMonitorManager->Regist(ID_MONITOR_MPUREG, this);
1.1.1.22! root 1047: reg_monitor->SetCallback(&MPU68040Device::MonitorScreenReg);
1.1.1.18 root 1048:
1049: // ATC モニター (Inst/Data)
1050: atc_monitor = gMonitorManager->Regist(ID_MONITOR_MPUATC, this);
1.1.1.22! root 1051: atc_monitor->SetCallback(&MPU68040Device::MonitorScreenATC);
1.1.1.20 root 1052: atc_monitor->SetSize(125, 34);
1.1.1.18 root 1053: }
1054:
1055: // デストラクタ
1056: MPU68040Device::~MPU68040Device()
1057: {
1058: }
1059:
1060: // モニター更新 (レジスタ)
1061: void
1.1.1.22! root 1062: MPU68040Device::MonitorScreenReg(Monitor *, TextScreen& screen)
1.1.1.18 root 1063: {
1064: m68kreg tmp;
1065: uint32 tmp_ppc;
1066: uint32 tmp_state;
1067: FPU40 tmp_fpu40;
1068: int y;
1069:
1070: screen.Clear();
1071:
1072: // ローカルにコピーする。
1073: // ただし一部は reg ではなく cpu クラス本体にある。
1074: tmp = reg;
1075: tmp_ppc = ppc;
1076: tmp_state = cpu_state;
1077: tmp_fpu40 = fpu40;
1078:
1079: // 共通部分。
1.1.1.22! root 1080: MonitorScreenRegCommon(screen, tmp, tmp_ppc, tmp_state);
1.1.1.18 root 1081:
1082: // Cache/MMU 部分。
1083: y = 4;
1.1.1.22! root 1084: y = MonitorScreenMMU(screen, y, tmp);
1.1.1.18 root 1085:
1086: // FPU はある時だけ表示。
1087: if (HasFPU()) {
1.1.1.22! root 1088: y = MonitorScreenFPU(screen, y, tmp);
! 1089: MonitorScreenFPU40(screen, y, tmp_fpu40);
1.1.1.18 root 1090: }
1091: }
1092:
1093: // モニター更新の下請け (Cache/MMU 部分)
1094: int
1.1.1.22! root 1095: MPU68040Device::MonitorScreenMMU(TextScreen& screen, int y, m68kreg& tmp)
1.1.1.18 root 1096: {
1097: int x;
1098:
1099: screen.Puts(0, y++, "<MMU/Cache>");
1100: screen.Print(0, y, "SRP:%08x TC:%04x( )", tmp.srp40, tmp.tc40);
1101: screen.Putc(24, y, TA::OnOff(tmp.tc40 & m68040TC::E) | 'E');
1102: screen.Putc(26, y, TA::OnOff(tmp.tc40 & m68040TC::P) | 'P');
1103: y++;
1104: screen.Print(0, y++, "URP:%08x", tmp.urp40);
1105: screen.Print(0, y, "MMUSR:%05x'%03x",
1106: (tmp.mmusr40 >> 12),
1107: (tmp.mmusr40 & 0xfff));
1108: x = 16;
1109: screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::B) | 'B');
1110: screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::G) | 'G');
1111: screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::U1)| 'U');
1112: screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::U0)| 'U');
1113: screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::S) | 'S');
1114: x++;
1115: screen.Print(x, y, "CM%u", (tmp.mmusr40 & m68040MMUSR::CM) >> 5);
1116: x += 4;
1117: screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::M) | 'M');
1118: screen.Putc(x++, y, '-');
1119: screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::W) | 'W');
1120: screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::T) | 'T');
1121: screen.Putc(x++, y, TA::OnOff(tmp.mmusr40 & m68040MMUSR::R) | 'R');
1122: y++;
1123:
1124: screen.Print(0, y, "CACR:%08x(", tmp.cacr);
1125: screen.Puts(14, y, TA::OnOff(tmp.cacr & M68040::CACR_DE), "DE");
1126: screen.Puts(17, y, TA::OnOff(tmp.cacr & M68040::CACR_IE), "IE");
1127: screen.Putc(19, y, ')');
1128: y++;
1129:
1130: y -= 4;
1131: x = 33;
1.1.1.22! root 1132: MonitorScreenTT(screen, x, y++, "ITT0", tmp.itt[0]);
! 1133: MonitorScreenTT(screen, x, y++, "ITT1", tmp.itt[1]);
! 1134: MonitorScreenTT(screen, x, y++, "DTT0", tmp.dtt[0]);
! 1135: MonitorScreenTT(screen, x, y++, "DTT1", tmp.dtt[1]);
1.1.1.18 root 1136:
1137: return y;
1138: }
1139:
1140: // *TTn 1つ分の下請け。
1141: void
1.1.1.22! root 1142: MPU68040Device::MonitorScreenTT(TextScreen& screen, int x, int y,
1.1.1.18 root 1143: const char *name, uint32 tt)
1144: {
1145: bool e = (tt & m68040TT::E);
1146:
1147: screen.Print(x, y, "%s:%08x(", name, tt);
1148: x += 14;
1149: screen.Putc(x++, y, TA::OnOff(e) | 'E');
1150: x++;
1151: screen.Print(x, y, (e ? TA::Normal : TA::Disable),
1152: "Base=$%02x Mask=$%02x", (tt >> 24), (tt >> 16) & 0xff);
1153:
1154: x += 18;
1155: if (e) {
1156: screen.Putc(x++, y, TA::OnOff(tt & m68040TT::S_IGN) | 'S');
1157: screen.Putc(x++, y, TA::OnOff(tt & m68040TT::S_FC2) | 'S');
1158: screen.Putc(x++, y, TA::OnOff(tt & m68040TT::U1) | 'U');
1159: screen.Putc(x++, y, TA::OnOff(tt & m68040TT::U0) | 'U');
1160: x++;
1161: screen.Print(x, y, "CM%u", (tt & m68040TT::CM) >> 5);
1162: x += 4;
1163: screen.Putc(x++, y, TA::OnOff(tt & m68040TT::W) | 'W');
1164: } else {
1165: screen.Puts(x, y, TA::Disable, "---- --- -");
1166: x += 10;
1167: }
1168: screen.Putc(x, y, ')');
1169: }
1170:
1171: void
1172: MPU68040Device::CalcStat()
1173: {
1174: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.