|
|
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:
277: // MPU からのアクセスをエミュレート
278: uint64
279: MPU88xx0Device::Read8(uint32 addr)
280: {
1.1.1.13! root 281: return cmmu[1]->load_8(addr);
1.1.1.9 root 282: }
283:
284: uint64
285: MPU88xx0Device::Read16(uint32 addr)
286: {
287: if ((addr & 1) == 0) {
1.1.1.13! root 288: return cmmu[1]->load_16(addr);
1.1.1.9 root 289: } else {
290: uint64 h, l;
291: h = Read8(addr);
292: if ((int64)h < 0) {
293: return h;
294: }
295: l = Read8(addr + 1);
296: if ((int64)l < 0) {
297: return l;
298: }
299: return (h << 8) | l;
300: }
301: }
302:
303: uint64
304: MPU88xx0Device::Read32(uint32 addr)
305: {
306: if ((addr & 3) == 0) {
1.1.1.13! root 307: return cmmu[1]->load_32(addr);
1.1.1.9 root 308: } else if ((addr & 1) == 0) {
309: uint64 h, l;
310: h = Read16(addr);
311: if ((int64)h < 0) {
312: return h;
313: }
314: l = Read16(addr + 2);
315: if ((int64)l < 0) {
316: return l;
317: }
318: return (h << 16) | l;
319: } else {
320: uint64 h, m, l;
321: h = Read8(addr);
322: if ((int64)h < 0) {
323: return h;
324: }
325: m = Read16(addr + 1);
326: if ((int64)m < 0) {
327: return m;
328: }
329: l = Read8(addr + 3);
330: if ((int64)l < 0) {
331: return l;
332: }
333: return (h << 24) | (m << 8) | l;
334: }
335: }
336:
337: uint64
338: MPU88xx0Device::Write8(uint32 addr, uint32 data)
339: {
1.1.1.13! root 340: return cmmu[1]->store_8(addr, data & 0xff);
1.1.1.9 root 341: }
342:
343: uint64
344: MPU88xx0Device::Write16(uint32 addr, uint32 data)
345: {
346: if ((addr & 1) == 0) {
1.1.1.13! root 347: return cmmu[1]->store_16(addr, data & 0xffff);
1.1.1.9 root 348: } else {
349: uint64 r;
350: r = Write8(addr, data >> 8);
351: if ((int64)r < 0) {
352: return r;
353: }
354: return Write8(addr + 1, data);
355: }
356: }
357:
358: uint64
359: MPU88xx0Device::Write32(uint32 addr, uint32 data)
360: {
361: if ((addr & 3) == 0) {
1.1.1.13! root 362: return cmmu[1]->store_32(addr, data);
1.1.1.9 root 363: } else if ((addr & 1) == 0) {
364: uint64 r;
365: r = Write16(addr, data >> 16);
366: if ((int64)r < 0) {
367: return r;
368: }
369: return Write16(addr + 2, data);
370: } else {
371: uint64 r;
372: r = Write8(addr, data >> 24);
373: if ((int64)r < 0) {
374: return r;
375: }
376: r = Write16(addr + 1, data >> 8);
377: if ((int64)r < 0) {
378: return r;
379: }
380: return Write8(addr + 3, data);
381: }
382: }
383:
1.1.1.13! root 384: #define FA(val, bit) TA::OnOff((val) & M88100::bit)
1.1.1.10 root 385:
1.1 root 386: // モニター更新
1.1.1.3 root 387: void
1.1.1.8 root 388: MPU88xx0Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 389: {
1.1.1.13! root 390: m88100reg tmp;
1.1 root 391: int x;
392: int y;
393:
1.1.1.8 root 394: screen.Clear();
1.1 root 395:
396: // ローカルにコピー
1.1.1.13! root 397: tmp = reg;
1.1 root 398:
399: //
400: for (int i = 0; i < countof(reg.r); i++) {
1.1.1.13! root 401: screen.Print((i / 8) * 14, i % 8, "r%-2d:%08x", i, tmp.r[i]);
1.1 root 402: }
403:
404: // 制御レジスタ
405: x = 0;
406: y = 9;
1.1.1.8 root 407: screen.Print(x, y++, "pid (cr0):%08x(Arch=$%02x Ver=$%02x MC=%s)",
1.1.1.13! root 408: tmp.pid,
! 409: (tmp.pid >> 8) & 0xff,
! 410: (tmp.pid >> 1) & 0x7f,
! 411: (tmp.pid & 1) ? "Master" : "Checker");
! 412: screen.Print(x, y, "psr (cr1):%08x(", tmp.psr);
! 413: screen.Puts(x + 19, y, FA(tmp.psr, PSR_SUPER), "S");
1.1.1.8 root 414: screen.Puts(x + 21, y,
1.1.1.13! root 415: ((tmp.psr & M88100::PSR_BO_LE) ? "BO=LE" : "BO=BE"));
! 416: screen.Puts(x + 27, y, FA(tmp.psr, PSR_SER), "SER");
! 417: screen.Puts(x + 31, y, FA(tmp.psr, PSR_C), "Cy");
! 418: screen.Puts(x + 34, y, FA(tmp.psr, PSR_SFD1), "SFD1");
! 419: screen.Puts(x + 39, y, FA(tmp.psr, PSR_MXM), "MXM");
! 420: screen.Puts(x + 43, y, FA(tmp.psr, PSR_IND), "IND");
! 421: screen.Puts(x + 47, y, FA(tmp.psr, PSR_SFRZ), "SFRZ");
1.1.1.8 root 422: screen.Puts(x + 51, y, ")");
1.1.1.2 root 423: y++;
1.1.1.13! root 424: screen.Print(x, y, "epsr(cr2):%08x(", tmp.epsr);
! 425: screen.Puts(x + 19, y, FA(tmp.epsr, PSR_SUPER), "S");
1.1.1.8 root 426: screen.Puts(x + 21, y,
1.1.1.13! root 427: ((tmp.epsr& M88100::PSR_BO_LE) ? "BO=LE" : "BO=BE"));
! 428: screen.Puts(x + 27, y, FA(tmp.epsr, PSR_SER), "SER");
! 429: screen.Puts(x + 31, y, FA(tmp.epsr, PSR_C), "Cy");
! 430: screen.Puts(x + 34, y, FA(tmp.epsr, PSR_SFD1), "SFD1");
! 431: screen.Puts(x + 39, y, FA(tmp.epsr, PSR_MXM), "MXM");
! 432: screen.Puts(x + 43, y, FA(tmp.epsr, PSR_IND), "IND");
! 433: screen.Puts(x + 47, y, FA(tmp.epsr, PSR_SFRZ), "SFRZ");
1.1.1.8 root 434: screen.Puts(x + 51, y, ")");
1.1 root 435:
1.1.1.2 root 436: // 制御レジスタ(左中; *IP)
1.1 root 437: x = 0;
438: y = 12;
1.1.1.13! root 439: screen.Print(x, y + 0, "xip:%08x opX:%08x(%c)",
! 440: tmp.xip, (uint32)tmp.opX,
! 441: OpIsBusErr(tmp.opX) ? 'B' : '-');
! 442: screen.Print(x, y + 1, "nip:%08x opF:%08x(%c)",
! 443: tmp.nip, (uint32)tmp.opF,
! 444: OpIsBusErr(tmp.opF) ? 'B' : '-');
! 445: screen.Print(x, y + 2, "fip:%08x", tmp.fip);
1.1 root 446:
447: // 制御レジスタ (S*IP)
448: x = 32;
449: for (int i = 0; i < 3; i++) {
1.1.1.8 root 450: screen.Print(x, y + i, "%s(cr%d):%08x:%c%c",
1.1 root 451: m88100reg::sipname[i], 4 + i,
1.1.1.13! root 452: (tmp.cr[4 + i] & M88100::SIP_MASK),
! 453: (tmp.cr[4 + i] & M88100::SIP_V) ? 'V' : '-',
! 454: (tmp.cr[4 + i] & M88100::SIP_E) ? 'E' : '-');
1.1 root 455: }
456:
1.1.1.2 root 457: // 制御レジスタ(右中)
1.1 root 458: x = 55;
459: y = 9;
460: for (int i = 0; i < 4; i++) {
461: int rn = 17 + i;
1.1.1.13! root 462: screen.Print(x, y++, "sr%d(cr%d):%08x", i, rn, tmp.cr[rn]);
1.1 root 463: }
1.1.1.13! root 464: screen.Print(x, y++, "ssbr(cr3):%08x", tmp.ssbr);
! 465: screen.Print(x, y++, "vbr (cr7):%08x", tmp.vbr);
1.1 root 466:
1.1.1.10 root 467: // MMU レジスタ(次段)
1.1.1.2 root 468: y = 15;
469: for (int i = 0; i <= 2; i++) {
470: int dt = 8 + i * 3;
471: int dd = 9 + i * 3;
472: int da = 10 + i * 3;
473:
1.1.1.8 root 474: screen.Print(0, y, "dmt%d(cr%-2d):%04x",
1.1.1.13! root 475: i, dt, (tmp.cr[dt] & 0xffff));
1.1.1.8 root 476: screen.Puts(15, y, "(b,s,d,l,rx, s,en ,w,v)");
1.1.1.13! root 477: screen.Puts(16, y, (tmp.cr[dt] & M88100::DM_BO) ? "B" : "-");
! 478: screen.Puts(18, y, (tmp.cr[dt] & M88100::DM_DAS) ? "S" : "U");
! 479: screen.Puts(20, y, (tmp.cr[dt] & M88100::DM_DOUB1) ? "D" : "-");
! 480: screen.Puts(22, y, (tmp.cr[dt] & M88100::DM_LOCK) ? "L" : "-");
1.1.1.2 root 481: // カンマが自然に見えるようにここだけカンマも含めて前詰めで出力
1.1.1.8 root 482: screen.Print(25, y, "%d,",
1.1.1.13! root 483: (tmp.cr[dt] & M88100::DM_DREG_MASK) >> 7);
! 484: screen.Puts(28, y, (tmp.cr[dt] & M88100::DM_SIGNED) ? "S" : "-");
! 485: uint32 en = (tmp.cr[dt] & M88100::DM_EN_MASK) >> 2;
1.1.1.8 root 486: screen.Puts(30, y, m88100reg::dmt_en_str[en]);
1.1.1.13! root 487: screen.Puts(35, y, (tmp.cr[dt] & M88100::DM_WRITE) ? "W" : "-");
! 488: screen.Puts(37, y, (tmp.cr[dt] & M88100::DM_VALID) ? "V" : "-");
1.1.1.2 root 489:
1.1.1.13! root 490: screen.Print(40, y, "dmd%d(cr%-2d):%08x", i, dd, tmp.cr[dd]);
! 491: screen.Print(60, y, "dma%d(cr%2d):%08x", i, da, tmp.cr[da]);
1.1.1.2 root 492: y++;
493: }
1.1.1.10 root 494: y++;
495:
496: // FPU レジスタ (下段)
1.1.1.13! root 497: screen.Print(0, y, "fpecr(fcr0):%08x(", tmp.fpecr);
1.1.1.10 root 498: x = 21;
1.1.1.13! root 499: screen.Puts(x + 0, y, FA(tmp.fpecr, FPECR_FIOV), "FIOV");
! 500: screen.Puts(x + 5, y, FA(tmp.fpecr, FPECR_FUNIMP), "FUNIMP");
! 501: screen.Puts(x + 12, y, FA(tmp.fpecr, FPECR_FPRV), "FPRV");
! 502: screen.Puts(x + 17, y, FA(tmp.fpecr, FPECR_FROP), "FROP");
! 503: screen.Puts(x + 22, y, FA(tmp.fpecr, FPECR_FDVZ), "FDVZ");
! 504: screen.Puts(x + 27, y, FA(tmp.fpecr, FPECR_FUNF), "FUNF");
! 505: screen.Puts(x + 32, y, FA(tmp.fpecr, FPECR_FOVF), "FOVF");
! 506: screen.Puts(x + 37, y, FA(tmp.fpecr, FPECR_FINX), "FINX");
1.1.1.10 root 507: screen.Puts(x + 41, y, ")");
508: y++;
509:
510: screen.Print(0, y++,
511: "fppt(fcr5): %08x(OpCode=%%%c%c%c%c%c T1=%d T2=%d TD=%d Dest=r%d)",
1.1.1.13! root 512: tmp.fppt,
! 513: ((tmp.fppt >> 15) & 1) + '0',
! 514: ((tmp.fppt >> 14) & 1) + '0',
! 515: ((tmp.fppt >> 13) & 1) + '0',
! 516: ((tmp.fppt >> 12) & 1) + '0',
! 517: ((tmp.fppt >> 11) & 1) + '0',
! 518: ((tmp.fppt >> 9) & 3),
! 519: ((tmp.fppt >> 7) & 3),
! 520: ((tmp.fppt >> 5) & 3),
! 521: (tmp.fppt & M88100::FPPT_DEST));
1.1.1.10 root 522:
523: screen.Print(0, y++, "fphs1(fcr1)/fpls1(fcr2): %08x'%08x",
1.1.1.13! root 524: tmp.fphs1, tmp.fpls1);
1.1.1.10 root 525: screen.Print(0, y++, "fphs2(fcr3)/fpls2(fcr4): %08x'%08x",
1.1.1.13! root 526: tmp.fphs2, tmp.fpls2);
1.1.1.10 root 527:
528: screen.Print(0, y, "fprh(fcr6) /fprl(fcr7): %08x'%08x(",
1.1.1.13! root 529: tmp.fprh, tmp.fprl);
1.1.1.10 root 530: x = 43;
1.1.1.13! root 531: screen.Puts(x + 0, y, FA(tmp.fprh, FPRH_ADDONE), "ADDONE");
! 532: screen.Print(x + 7, y, "RM=%s)", rmstr[(tmp.fprh >> 29) & 3]);
1.1.1.10 root 533: y++;
534:
535: x = 21;
536: screen.Print(0, y, "fpit(fcr8): %08x(OpCode=%%%c%c%c%c%c TD=%d",
1.1.1.13! root 537: tmp.fpit,
! 538: ((tmp.fpit >> 15) & 1) + '0',
! 539: ((tmp.fpit >> 14) & 1) + '0',
! 540: ((tmp.fpit >> 13) & 1) + '0',
! 541: ((tmp.fpit >> 12) & 1) + '0',
! 542: ((tmp.fpit >> 11) & 1) + '0',
! 543: ((tmp.fpit >> 10) & 1));
! 544: screen.Puts(x + 19, y, FA(tmp.fpit, FPIT_EFINV), "EINV");
! 545: screen.Puts(x + 24, y, FA(tmp.fpit, FPIT_EFDVZ), "EDVZ");
! 546: screen.Puts(x + 29, y, FA(tmp.fpit, FPIT_EFUNF), "EUNF");
! 547: screen.Puts(x + 34, y, FA(tmp.fpit, FPIT_EFOVF), "EOVF");
! 548: screen.Puts(x + 39, y, FA(tmp.fpit, FPIT_EFINX), "EINX");
! 549: screen.Print(x + 44, y, "Dest=r%d)", tmp.fpit & M88100::FPIT_DEST);
1.1.1.10 root 550: y++;
551:
1.1.1.13! root 552: uint32 sign = (tmp.fprh & M88100::FPRH_SIGN);
! 553: uint32 exp = (int32)tmp.fpit >> 20;
! 554: uint32 mant_h = (tmp.fprh & 0x000fffff);
! 555: uint32 mant_l = tmp.fprl;
1.1.1.10 root 556: screen.Print(12, y, "result: %c%1x.%05x'%08x'grs e%+d",
557: (sign ? '-' : '+'),
1.1.1.13! root 558: ((tmp.fprh >> 20) & 1),
1.1.1.10 root 559: mant_h,
560: mant_l,
561: exp - 0x3ff);
1.1.1.13! root 562: screen.Puts(38, y, FA(tmp.fprh, FPRH_GUARD), "G");
! 563: screen.Puts(39, y, FA(tmp.fprh, FPRH_ROUND), "R");
! 564: screen.Puts(40, y, FA(tmp.fprh, FPRH_STICKY), "S");
1.1.1.10 root 565: screen.Print(48, y, "($%03x)", exp & 0x7ff);
566: // Inf と NAN はこの形式だけからでは分かりづらいので別途追加で表示。
567: // exp は符号拡張しているので指数部 $7ff は exp == -1。
568: if (exp == 0xffffffff) {
569: x = 55;
570: if ((mant_h | mant_l) == 0) {
571: if (sign == 0) {
572: screen.Puts(x, y, "= +Inf");
573: } else {
574: screen.Puts(x, y, "= -Inf");
575: }
576: } else {
577: if (sign == 0) {
578: screen.Puts(x, y, "= +NAN");
579: } else {
580: screen.Puts(x, y, "= -NAN");
581: }
582: }
583: }
584: y++;
585:
1.1.1.13! root 586: screen.Print(0, y, "fpsr(fcr62):%08x(", tmp.fpsr);
1.1.1.10 root 587: x = 21;
1.1.1.13! root 588: screen.Puts(x + 0, y, FA(tmp.fpsr, FPSR_AFINV), "AFINV");
! 589: screen.Puts(x + 6, y, FA(tmp.fpsr, FPSR_AFDVZ), "AFDVZ");
! 590: screen.Puts(x + 12, y, FA(tmp.fpsr, FPSR_AFUNF), "AFUNF");
! 591: screen.Puts(x + 18, y, FA(tmp.fpsr, FPSR_AFOVF), "AFOVF");
! 592: screen.Puts(x + 24, y, FA(tmp.fpsr, FPSR_AFINX), "AFINX");
1.1.1.10 root 593: screen.Puts(x + 29, y, ")");
594: y++;
595:
1.1.1.13! root 596: screen.Print(0, y, "fpcr(fcr63):%08x(", tmp.fpcr);
! 597: screen.Puts(x + 0, y, FA(tmp.fpcr, FPCR_EFINV), "EFINV");
! 598: screen.Puts(x + 6, y, FA(tmp.fpcr, FPCR_EFDVZ), "EFDVZ");
! 599: screen.Puts(x + 12, y, FA(tmp.fpcr, FPCR_EFUNF), "EFUNF");
! 600: screen.Puts(x + 18, y, FA(tmp.fpcr, FPCR_EFOVF), "EFOVF");
! 601: screen.Puts(x + 24, y, FA(tmp.fpcr, FPCR_EFINX), "EFINX");
! 602: screen.Print(x + 30, y, "RM=%s)", rmstr[(tmp.fpcr >> 14) & 3]);
1.1 root 603: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.