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