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