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