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