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