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