|
|
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.11 root 7: //
8: // MPU (M88xx0)
9: //
1.1 root 10:
11: #include "mpu88xx0.h"
12: #include "config.h"
1.1.1.11 root 13: #include "debugger.h"
1.1.1.19! root 14: #include "event.h"
1.1.1.12 root 15: #include "m88100disasm.h"
1.1.1.11 root 16: #include "scheduler.h"
1.1.1.2 root 17:
1.1 root 18: // コンストラクタ
1.1.1.7 root 19: MPU88xx0Device::MPU88xx0Device()
1.1.1.13 root 20: : inherited()
1.1 root 21: {
1.1.1.13 root 22: SetName("MPU(88100)");
1.1.1.4 root 23:
1.1.1.13 root 24: // LUNA-88K では CMMU の ID は次のように割り振ってあるようだ。
1.1.1.2 root 25: // OpenBSD の sys/arch/luna68k/include/board.h より。
26: //
27: // Inst Data
28: // CPU#0 ID=7 ID=6
29: // CPU#1 ID=5 ID=4
30: // CPU#2 ID=3 ID=2
31: // CPU#3 ID=1 ID=0
32: //
1.1.1.13 root 33: // 厳密にはこれは LUNA-88K のハードウェアがどういうコンフィグレーションで
1.1.1.2 root 34: // m88200 を使うかなので、ここではなくて vm_luna あたりのほうがいいかも
35: // しれんけど、あまり遠いのも面倒なので、とりあえずこの辺に。
36: // あとマルチプロセッサになったらまたその時考える。
1.1.1.13 root 37: cmmu[0].reset(new m88200(this, 7));
38: cmmu[1].reset(new m88200(this, 6));
1.1.1.2 root 39:
1.1.1.15 root 40: // 設定の初期値。
41:
42: // MPU のデフォルトは xxx.usr バグ修正済みのバージョンに設定する。
43: // 所有している実機にあわせ 0xb。OpenBSD の
44: // sys/arch/m88k/m88k/m88100_machdep.c::m88100_apply_patches() 参照。
45: gConfig->SetDefault("m88100-version", 0xb);
46:
47: // CMMU のデフォルトは xmem の writeback バグが修正されているバージョンに
48: // 設定する。所有している実機にあわせ 0x9。
49: // OpenBSD の sys/arch/m88k/m88k/m8820x_machdep.c::m8820x_apr_cmode() 参照。
50: gConfig->SetDefault("m88200-version", 0x9);
51:
52: // 例外カウンタ
53: excep_counter.resize(512);
54:
1.1.1.8 root 55: // レジスタモニター
1.1.1.16 root 56: monitor = gMonitorManager->Regist(ID_MONITOR_MPUREG, this);
57: monitor->func = ToMonitorCallback(&MPU88xx0Device::MonitorUpdate);
58: monitor->SetSize(79, 25);
1.1 root 59: }
60:
61: // デストラクタ
62: MPU88xx0Device::~MPU88xx0Device()
63: {
64: }
65:
1.1.1.13 root 66: // 初期化
1.1.1.5 root 67: bool
68: MPU88xx0Device::Init()
69: {
70: if (inherited::Init() == false) {
71: return false;
72: }
73:
1.1.1.12 root 74: const ConfigItem& item_stop = gConfig->Find("mpu-pseudo-stop");
1.1.1.13 root 75: pseudo_stop_enable = (bool)item_stop.AsInt();
1.1.1.12 root 76:
77: const ConfigItem& item_altname = gConfig->Find(".m88k-altname");
78: m88100disasm::use_altname = item_altname.AsInt();
1.1.1.8 root 79:
1.1.1.15 root 80: // MPU のバージョン。
81: const ConfigItem& item_88100ver = gConfig->Find("m88100-version");
82: uint ver88100 = item_88100ver.AsInt();
83: reg.pid = (ver88100 << 1) | M88100::PID_MASTER;
84:
85: // CMMU のバージョン。
86: const ConfigItem& item_88200ver = gConfig->Find("m88200-version");
87: uint ver88200 = item_88200ver.AsInt();
88: cmmu[0]->SetVersion(ver88200);
89: cmmu[1]->SetVersion(ver88200);
90:
1.1.1.5 root 91: return true;
92: }
93:
1.1.1.11 root 94: // リセット
95: void
96: MPU88xx0Device::ResetHard(bool poweron)
1.1.1.7 root 97: {
1.1.1.11 root 98: if (poweron) {
1.1.1.13 root 99: // レジスタのうち不定と明記されてるものは、未初期化のまま触ったことが
100: // 分かりやすいような適当なパターンで埋めておく。ただし最上位も c に
101: // すると BT45x のレジスタ付近を指してしまうので、それは避けておく。
102: const uint32 Undefined = 0x0ccccccc;
103: for (int i = 1; i < 32; i++) {
104: reg.r[i] = Undefined;
105: }
106: for (int i = 0; i < countof(reg.fcr); i++) {
107: reg.fcr[i] = Undefined & reg.fcr_mask[i];
108: }
109:
110: reg.epsr = Undefined;
111: reg.ssbr = Undefined;
112: reg.sfip = Undefined;
113: reg.snip = Undefined;
114: reg.sxip = Undefined;
115: // DMTx は bit0(Valid) をクリア。DMAx/DMDx は不定。
116: reg.dma0 = Undefined;
117: reg.dma1 = Undefined;
118: reg.dma2 = Undefined;
119: reg.dmd0 = Undefined;
120: reg.dmd1 = Undefined;
121: reg.dmd2 = Undefined;
122:
123: // アクセスが一度もない時にどのアドレスとも一致しないようにしておく。
124: lastaddr = (uint64)-1;
125:
126: // サイクルを初期化。
127: used_cycle = 0;
128:
129: // 履歴は電源オン時だけ初期化。
130: // (LUNA-88K は ROM が正常パスで CPU リセットを行ったりするので)
131: exhist.Clear();
132: brhist.Clear();
133:
134: // この後起きるリセット例外で xip を初期化する前に参照することに
135: // なるので、これだけここでも初期化しておく。
136: reg.xip = 0;
1.1.1.11 root 137: }
1.1.1.15 root 138:
1.1.1.12 root 139: resetting = true;
1.1.1.19! root 140: Exception(EXCPRI_RESET);
1.1.1.11 root 141:
142: // リセット例外を 8+256 クロック後に起こす。
143: // 8+256 は、電源オン時に最低これだけアサートしなければならないという値
144: // のはずで、実際これだけかかるとかいう値ではない。が、こちら側の都合で
145: // この後実行される RAM の ResetHard() がブートページを用意した後で
146: // cpu->Reset() で xip をフェッチするという順序にしないといけないため、
147: // リセット例外が起動するまでに時間がかかるというところを都合よく真似て
148: // おく。
149:
1.1.1.19! root 150: exec_event->func = ToEventCallback(&MPU88xx0Device::ResetCallback);
! 151: exec_event->time = (8 + 256) * clock_nsec;
! 152: exec_event->SetName(GetName() + " Reset");
1.1.1.13 root 153: scheduler->RestartEvent(exec_event);
1.1.1.7 root 154: }
155:
1.1.1.11 root 156: // リセット例外コールバック。
157: // MPU リセットから規定時間後に呼ばれる。
1.1 root 158: void
1.1.1.19! root 159: MPU88xx0Device::ResetCallback(Event *ev)
1.1 root 160: {
1.1.1.11 root 161: // リセット例外を実行
1.1.1.13 root 162: uint64 cycle_start = used_cycle;
163:
164: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
165: // リセット例外も発生時の XIP を記録する。(LUNA-88K の PROM 1.20)
166: exhist.AddEntry(reg.xip | 1, 0, 0xfc000000 | 0);
167: brhist.AddEntry(reg.xip | 1, 0, 0xfc000000 | 0);
168: // デバッガに通知 (例外ブレーク用)
169: debugger->NotifyExceptionMain(0);
170:
1.1.1.19! root 171: // 内部の例外状態をクリア
! 172: resetting = false;
! 173: excep_pending = 0;
1.1.1.13 root 174: ChangeState(CPU_STATE_NORMAL);
175:
176: // 実際どこかは分からんけど PSR 設定の前にリセットしておきたい
177: cmmu[0]->Reset();
178: cmmu[1]->Reset();
179:
180: // Table 6-8 (p6-47)
181: reg.psr = 0x800003ff;
182: // XXX ただし SFU1 は未実装なので下げておく
183: reg.psr &= ~PSR_SFD1;
184:
185: #if defined(TEST_INTERRUPT)
186: reg.psr &= ~PSR_IND;
187: reg.psr &= ~PSR_SFRZ;
188: #endif
189:
190: SetPSR();
191:
192: reg.fip = 0;
193:
194: // レジスタのうち明記されてるものをクリア。
195: // 不定と明記されてるものはリセットでは触らないでおく。
196: // scoreboard: cleared
197: reg.nip = 0;
198: reg.xip = 0;
199: reg.vbr = 0;
200: reg.fpecr = 0;
201: reg.fpcr = 0;
202: reg.fpsr = 0;
203: // DMTx は bit0(Valid) をクリア。他は不定
204: reg.dmt0 &= ~DM_VALID;
205: reg.dmt1 &= ~DM_VALID;
206: reg.dmt2 &= ~DM_VALID;
207:
208: fetch();
209:
210: // リセット例外はここまで。
211: // ここからは最初の命令のプリフェッチ
212: Prefetch();
1.1.1.11 root 213:
214: // コールバックを ResetCallback から Exec* に差し替える前のここで
215: // トレース状態を初期化する。
1.1.1.13 root 216: SetTrace(debugger->IsTrace());
1.1.1.11 root 217:
218: // 以降は通常走行
1.1.1.13 root 219: int cycle = used_cycle - cycle_start;
1.1.1.19! root 220: exec_event->func = exec_normal;
! 221: exec_event->time = cycle * clock_nsec;
! 222: exec_event->SetName(GetName() + " Execute");
1.1.1.13 root 223: scheduler->StartEvent(exec_event);
1.1.1.11 root 224: }
225:
226: // トレース実行のコールバック
227: void
1.1.1.19! root 228: MPU88xx0Device::ExecTrace(Event *ev)
1.1.1.11 root 229: {
1.1.1.13 root 230: debugger->ExecMain();
1.1.1.11 root 231: ExecNormal(ev);
232: }
233:
234: // トレース状態を設定する
235: void
236: MPU88xx0Device::SetTrace(bool enable)
237: {
238: if (enable) {
239: exec_normal = ToEventCallback(&MPU88xx0Device::ExecTrace);
240: } else {
241: exec_normal = ToEventCallback(&MPU88xx0Device::ExecNormal);
242: }
1.1.1.19! root 243: exec_event->func = exec_normal;
1.1.1.11 root 244: }
245:
1.1.1.6 root 246: // アクセス中の論理アドレスを取得
247: uint32
248: MPU88xx0Device::GetLaddr() const
249: {
1.1.1.13 root 250: m88200 *m = m88200::GetBusMaster();
251: assert(m);
252: return m->GetLaddr();
1.1.1.6 root 253: }
254:
255: // アクセス中の物理アドレスを取得
256: uint32
257: MPU88xx0Device::GetPaddr() const
258: {
1.1.1.13 root 259: m88200 *m = m88200::GetBusMaster();
260: assert(m);
261: return m->GetPaddr();
1.1.1.4 root 262: }
263:
1.1.1.2 root 264: // Interrupt
265: void
1.1.1.5 root 266: MPU88xx0Device::Interrupt(int level)
1.1.1.2 root 267: {
1.1.1.13 root 268: // level は 0 か 1。
1.1.1.19! root 269: intr_asserted = level;
1.1.1.13 root 270:
1.1.1.19! root 271: if (intr_asserted && IsIntrEnable()) {
! 272: OuterException(EXCPRI_INTERRUPT);
! 273:
! 274: if (cpu_state == CPU_STATE_STOP) {
! 275: // 割り込みを受け付けたら STOP 解除。
! 276: ChangeState(CPU_STATE_NORMAL);
! 277: }
! 278: } else {
! 279: excep_pending &= ~EXCPRI_INTERRUPT;
! 280: // INTERRUPT を下げたことで全員いなくなれば OUTER を下げる。
! 281: if ((excep_pending & EXCPRI_OUTER_MASK) == 0) {
! 282: excep_pending &= ~EXCPRI_OUTER;
! 283: }
1.1.1.13 root 284: }
1.1.1.2 root 285: }
286:
1.1.1.19! root 287: void
! 288: MPU88xx0Device::SetPSR()
! 289: {
! 290: if (intr_asserted && IsIntrEnable()) {
! 291: OuterException(EXCPRI_INTERRUPT);
! 292: } else {
! 293: excep_pending &= ~EXCPRI_INTERRUPT;
! 294: // INTERRUPT を下げたことで全員いなくなれば OUTER を下げる。
! 295: if ((excep_pending & EXCPRI_OUTER_MASK) == 0) {
! 296: excep_pending &= ~EXCPRI_OUTER;
! 297: }
! 298: }
! 299:
! 300: // CMMU に S/U 信号を出す
! 301: cmmu[0]->SetSuper(IsSuper());
! 302: cmmu[1]->SetSuper(IsSuper());
! 303: }
! 304:
1.1.1.9 root 305: // DOS call エミュレーションのコールバックを指定
306: void
1.1.1.13 root 307: MPU88xx0Device::SetFLineCallback(bool (*callback)(MPU88xx0Device *, void *),
308: void *arg)
1.1.1.9 root 309: {
1.1.1.13 root 310: fline_callback = callback;
311: fline_arg = arg;
1.1.1.9 root 312: }
313:
1.1.1.13 root 314: #define FA(val, bit) TA::OnOff((val) & M88100::bit)
1.1.1.10 root 315:
1.1 root 316: // モニター更新
1.1.1.3 root 317: void
1.1.1.8 root 318: MPU88xx0Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 319: {
1.1.1.13 root 320: m88100reg tmp;
1.1 root 321: int x;
322: int y;
323:
1.1.1.8 root 324: screen.Clear();
1.1 root 325:
326: // ローカルにコピー
1.1.1.13 root 327: tmp = reg;
1.1 root 328:
1.1.1.15 root 329: // 汎用レジスタ
330: for (uint i = 0; i < countof(reg.r); i++) {
331: screen.Print((i / 8) * 14, i % 8, "r%-2u:%08x", i, tmp.r[i]);
332: }
333:
334: // 制御レジスタ (上段右)
335: x = 57;
336: y = 0;
337: for (int i = 0; i < 4; i++) {
338: int rn = 17 + i;
339: screen.Print(x, y++, "sr%u(cr%u):%08x", i, rn, tmp.cr[rn]);
1.1 root 340: }
1.1.1.15 root 341: screen.Print(x, y++, "ssbr(cr3):%08x", tmp.ssbr);
342: for (int i = 0; i < 3; i++) {
343: screen.Print(x, y++, "%s(cr%u):%08x:%c%c",
344: m88100reg::sipname[i], 4 + i,
345: (tmp.cr[4 + i] & M88100::SIP_MASK),
346: (tmp.cr[4 + i] & M88100::SIP_V) ? 'V' : '-',
347: (tmp.cr[4 + i] & M88100::SIP_E) ? 'E' : '-');
348: }
349: screen.Print(x, y++, "vbr (cr7):%08x", tmp.vbr);
1.1 root 350:
1.1.1.15 root 351: // 制御レジスタ(中段上; *IP)
1.1 root 352: x = 0;
353: y = 9;
1.1.1.15 root 354: screen.Print(x, y++, "xip:%08x (op:%08x:%c)",
355: tmp.xip, (uint32)tmp.opX, OpIsBusErr(tmp.opX) ? 'B' : '-');
356: screen.Print(x, y++, "nip:%08x (op:%08x:%c)",
357: tmp.nip, (uint32)tmp.opF, OpIsBusErr(tmp.opF) ? 'B' : '-');
358: screen.Print(x, y++, "fip:%08x", tmp.fip);
359:
360: // 制御レジスタ 中段上; pid,*psr)
361: x = 30;
362: y = 9;
363: screen.Print(x, y++, "pid(cr0):%08x(Arch=$%02x Ver=$%02x MC=%s)",
1.1.1.13 root 364: tmp.pid,
365: (tmp.pid >> 8) & 0xff,
366: (tmp.pid >> 1) & 0x7f,
367: (tmp.pid & 1) ? "Master" : "Checker");
1.1.1.15 root 368: screen.Print(x, y, "psr(cr1):%08x(", tmp.psr);
369: x--;
1.1.1.13 root 370: screen.Puts(x + 19, y, FA(tmp.psr, PSR_SUPER), "S");
1.1.1.15 root 371: screen.Puts(x + 21, y, ((tmp.psr & M88100::PSR_BO_LE) ? "LE" : "BE"));
372: screen.Puts(x + 24, y, FA(tmp.psr, PSR_SER), "SER");
373: screen.Puts(x + 28, y, FA(tmp.psr, PSR_C), "Cy");
374: screen.Puts(x + 31, y, FA(tmp.psr, PSR_SFD1), "SFD1");
375: screen.Puts(x + 36, y, FA(tmp.psr, PSR_MXM), "MXM");
376: screen.Puts(x + 40, y, FA(tmp.psr, PSR_IND), "IND");
377: screen.Puts(x + 44, y, FA(tmp.psr, PSR_SFRZ), "SFRZ");
378: screen.Puts(x + 48, y, ")");
1.1.1.2 root 379: y++;
1.1.1.13 root 380: screen.Print(x, y, "epsr(cr2):%08x(", tmp.epsr);
381: screen.Puts(x + 19, y, FA(tmp.epsr, PSR_SUPER), "S");
1.1.1.15 root 382: screen.Puts(x + 21, y, ((tmp.epsr& M88100::PSR_BO_LE) ? "LE" : "BE"));
383: screen.Puts(x + 24, y, FA(tmp.epsr, PSR_SER), "SER");
384: screen.Puts(x + 28, y, FA(tmp.epsr, PSR_C), "Cy");
385: screen.Puts(x + 31, y, FA(tmp.epsr, PSR_SFD1), "SFD1");
386: screen.Puts(x + 36, y, FA(tmp.epsr, PSR_MXM), "MXM");
387: screen.Puts(x + 40, y, FA(tmp.epsr, PSR_IND), "IND");
388: screen.Puts(x + 44, y, FA(tmp.epsr, PSR_SFRZ), "SFRZ");
389: screen.Puts(x + 48, y, ")");
1.1 root 390:
1.1.1.15 root 391: // MMU レジスタ(中段下)
1.1 root 392: y = 12;
1.1.1.15 root 393: for (uint i = 0; i <= 2; i++) {
394: uint dt = 8 + i * 3;
395: uint dd = 9 + i * 3;
396: uint da = 10 + i * 3;
1.1.1.2 root 397:
1.1.1.15 root 398: // DMT は "cr8 " があるので左揃え
399: screen.Print(0, y, "dmt%u(cr%-2u):%04x",
1.1.1.13 root 400: i, dt, (tmp.cr[dt] & 0xffff));
1.1.1.8 root 401: screen.Puts(15, y, "(b,s,d,l,rx, s,en ,w,v)");
1.1.1.13 root 402: screen.Puts(16, y, (tmp.cr[dt] & M88100::DM_BO) ? "B" : "-");
403: screen.Puts(18, y, (tmp.cr[dt] & M88100::DM_DAS) ? "S" : "U");
404: screen.Puts(20, y, (tmp.cr[dt] & M88100::DM_DOUB1) ? "D" : "-");
405: screen.Puts(22, y, (tmp.cr[dt] & M88100::DM_LOCK) ? "L" : "-");
1.1.1.2 root 406: // カンマが自然に見えるようにここだけカンマも含めて前詰めで出力
1.1.1.15 root 407: screen.Print(25, y, "%u,",
1.1.1.13 root 408: (tmp.cr[dt] & M88100::DM_DREG_MASK) >> 7);
409: screen.Puts(28, y, (tmp.cr[dt] & M88100::DM_SIGNED) ? "S" : "-");
410: uint32 en = (tmp.cr[dt] & M88100::DM_EN_MASK) >> 2;
1.1.1.8 root 411: screen.Puts(30, y, m88100reg::dmt_en_str[en]);
1.1.1.13 root 412: screen.Puts(35, y, (tmp.cr[dt] & M88100::DM_WRITE) ? "W" : "-");
413: screen.Puts(37, y, (tmp.cr[dt] & M88100::DM_VALID) ? "V" : "-");
1.1.1.2 root 414:
1.1.1.15 root 415: // DMD は "cr9 " があるので左揃え
416: screen.Print(40, y, "dmd%u(cr%-2u):%08x", i, dd, tmp.cr[dd]);
417: screen.Print(60, y, "dma%u(cr%2u):%08x", i, da, tmp.cr[da]);
1.1.1.2 root 418: y++;
419: }
1.1.1.10 root 420: y++;
421:
422: // FPU レジスタ (下段)
1.1.1.13 root 423: screen.Print(0, y, "fpecr(fcr0):%08x(", tmp.fpecr);
1.1.1.10 root 424: x = 21;
1.1.1.13 root 425: screen.Puts(x + 0, y, FA(tmp.fpecr, FPECR_FIOV), "FIOV");
426: screen.Puts(x + 5, y, FA(tmp.fpecr, FPECR_FUNIMP), "FUNIMP");
427: screen.Puts(x + 12, y, FA(tmp.fpecr, FPECR_FPRV), "FPRV");
428: screen.Puts(x + 17, y, FA(tmp.fpecr, FPECR_FROP), "FROP");
429: screen.Puts(x + 22, y, FA(tmp.fpecr, FPECR_FDVZ), "FDVZ");
430: screen.Puts(x + 27, y, FA(tmp.fpecr, FPECR_FUNF), "FUNF");
431: screen.Puts(x + 32, y, FA(tmp.fpecr, FPECR_FOVF), "FOVF");
432: screen.Puts(x + 37, y, FA(tmp.fpecr, FPECR_FINX), "FINX");
1.1.1.10 root 433: screen.Puts(x + 41, y, ")");
434: y++;
435:
1.1.1.19! root 436: char tsiz[4] = { 's', 'd', '2', '3' };
1.1.1.10 root 437: screen.Print(0, y++,
1.1.1.19! root 438: "fppt(fcr5): %08x(OpCode=%%%c%c%c%c%c T1=%c T2=%c TD=%c Dest=r%u)",
1.1.1.13 root 439: tmp.fppt,
440: ((tmp.fppt >> 15) & 1) + '0',
441: ((tmp.fppt >> 14) & 1) + '0',
442: ((tmp.fppt >> 13) & 1) + '0',
443: ((tmp.fppt >> 12) & 1) + '0',
444: ((tmp.fppt >> 11) & 1) + '0',
1.1.1.19! root 445: tsiz[(tmp.fppt >> 9) & 3],
! 446: tsiz[(tmp.fppt >> 7) & 3],
! 447: tsiz[(tmp.fppt >> 5) & 3],
1.1.1.13 root 448: (tmp.fppt & M88100::FPPT_DEST));
1.1.1.10 root 449:
1.1.1.19! root 450: for (uint i = 0; i < 2; i++) {
! 451: uint32 hs;
! 452: uint32 ls;
! 453: bool isfloat;
! 454: if (i == 0) {
! 455: hs = tmp.fphs1;
! 456: ls = tmp.fpls1;
! 457: isfloat = (tmp.fppt & 0x600) == 0;
! 458: } else {
! 459: hs = tmp.fphs2;
! 460: ls = tmp.fpls2;
! 461: isfloat = (tmp.fppt & 0x180) == 0;
! 462: }
! 463: uint n = i * 2;
! 464: screen.Print(0, y, "fphs%u(fcr%u)/fpls%u(fcr%u): %08x'%08x =",
! 465: (i + 1), (n + 1), (i + 1), (n + 2), hs, ls);
! 466: int32 e = ((int32)(hs << 1)) >> 21;
! 467: screen.Print(45, y, "%c0.%05x'",
! 468: ((hs & 0x80000000) ? '-' : '+'),
! 469: (hs & 0x000f'ffff));
! 470: if (isfloat) {
! 471: screen.Print(45 + 9, y, "%1x", (ls >> 28) & 0xf);
! 472: screen.Print(45 + 10, y, TA::Disable, "%07x", (ls & 0x0fff'ffff));
! 473: screen.Print(45 + 18, y, "e%+d", e);
! 474: } else {
! 475: screen.Print(45 + 9, y, "%08x e%+d", ls, e);
! 476: }
! 477: y++;
! 478: }
1.1.1.10 root 479:
480: screen.Print(0, y, "fprh(fcr6) /fprl(fcr7): %08x'%08x(",
1.1.1.13 root 481: tmp.fprh, tmp.fprl);
1.1.1.10 root 482: x = 43;
1.1.1.13 root 483: screen.Puts(x + 0, y, FA(tmp.fprh, FPRH_ADDONE), "ADDONE");
484: screen.Print(x + 7, y, "RM=%s)", rmstr[(tmp.fprh >> 29) & 3]);
1.1.1.10 root 485: y++;
486:
487: x = 21;
1.1.1.15 root 488: screen.Print(0, y, "fpit(fcr8): %08x(OpCode=%%%c%c%c%c%c TD=%u",
1.1.1.13 root 489: tmp.fpit,
490: ((tmp.fpit >> 15) & 1) + '0',
491: ((tmp.fpit >> 14) & 1) + '0',
492: ((tmp.fpit >> 13) & 1) + '0',
493: ((tmp.fpit >> 12) & 1) + '0',
494: ((tmp.fpit >> 11) & 1) + '0',
495: ((tmp.fpit >> 10) & 1));
496: screen.Puts(x + 19, y, FA(tmp.fpit, FPIT_EFINV), "EINV");
497: screen.Puts(x + 24, y, FA(tmp.fpit, FPIT_EFDVZ), "EDVZ");
498: screen.Puts(x + 29, y, FA(tmp.fpit, FPIT_EFUNF), "EUNF");
499: screen.Puts(x + 34, y, FA(tmp.fpit, FPIT_EFOVF), "EOVF");
500: screen.Puts(x + 39, y, FA(tmp.fpit, FPIT_EFINX), "EINX");
1.1.1.15 root 501: screen.Print(x + 44, y, "Dest=r%u)", tmp.fpit & M88100::FPIT_DEST);
1.1.1.10 root 502: y++;
503:
1.1.1.13 root 504: uint32 sign = (tmp.fprh & M88100::FPRH_SIGN);
505: uint32 exp = (int32)tmp.fpit >> 20;
506: uint32 mant_h = (tmp.fprh & 0x000fffff);
507: uint32 mant_l = tmp.fprl;
1.1.1.10 root 508: screen.Print(12, y, "result: %c%1x.%05x'%08x'grs e%+d",
509: (sign ? '-' : '+'),
1.1.1.13 root 510: ((tmp.fprh >> 20) & 1),
1.1.1.10 root 511: mant_h,
512: mant_l,
513: exp - 0x3ff);
1.1.1.13 root 514: screen.Puts(38, y, FA(tmp.fprh, FPRH_GUARD), "G");
515: screen.Puts(39, y, FA(tmp.fprh, FPRH_ROUND), "R");
516: screen.Puts(40, y, FA(tmp.fprh, FPRH_STICKY), "S");
1.1.1.10 root 517: screen.Print(48, y, "($%03x)", exp & 0x7ff);
518: // Inf と NAN はこの形式だけからでは分かりづらいので別途追加で表示。
519: // exp は符号拡張しているので指数部 $7ff は exp == -1。
520: if (exp == 0xffffffff) {
521: x = 55;
522: if ((mant_h | mant_l) == 0) {
523: if (sign == 0) {
524: screen.Puts(x, y, "= +Inf");
525: } else {
526: screen.Puts(x, y, "= -Inf");
527: }
528: } else {
529: if (sign == 0) {
530: screen.Puts(x, y, "= +NAN");
531: } else {
532: screen.Puts(x, y, "= -NAN");
533: }
534: }
535: }
536: y++;
537:
1.1.1.13 root 538: screen.Print(0, y, "fpsr(fcr62):%08x(", tmp.fpsr);
1.1.1.10 root 539: x = 21;
1.1.1.13 root 540: screen.Puts(x + 0, y, FA(tmp.fpsr, FPSR_AFINV), "AFINV");
541: screen.Puts(x + 6, y, FA(tmp.fpsr, FPSR_AFDVZ), "AFDVZ");
542: screen.Puts(x + 12, y, FA(tmp.fpsr, FPSR_AFUNF), "AFUNF");
543: screen.Puts(x + 18, y, FA(tmp.fpsr, FPSR_AFOVF), "AFOVF");
544: screen.Puts(x + 24, y, FA(tmp.fpsr, FPSR_AFINX), "AFINX");
1.1.1.10 root 545: screen.Puts(x + 29, y, ")");
546: y++;
547:
1.1.1.13 root 548: screen.Print(0, y, "fpcr(fcr63):%08x(", tmp.fpcr);
549: screen.Puts(x + 0, y, FA(tmp.fpcr, FPCR_EFINV), "EFINV");
550: screen.Puts(x + 6, y, FA(tmp.fpcr, FPCR_EFDVZ), "EFDVZ");
551: screen.Puts(x + 12, y, FA(tmp.fpcr, FPCR_EFUNF), "EFUNF");
552: screen.Puts(x + 18, y, FA(tmp.fpcr, FPCR_EFOVF), "EFOVF");
553: screen.Puts(x + 24, y, FA(tmp.fpcr, FPCR_EFINX), "EFINX");
554: screen.Print(x + 30, y, "RM=%s)", rmstr[(tmp.fpcr >> 14) & 3]);
1.1 root 555: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.