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