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