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