--- nono/vm/mpu88xx0.cpp 2026/04/29 17:04:36 1.1.1.2 +++ nono/vm/mpu88xx0.cpp 2026/04/29 17:05:38 1.1.1.17 @@ -4,25 +4,24 @@ // Licensed under nono-license.txt // -// MPU (m88xx0) +// +// MPU (M88xx0) +// #include "mpu88xx0.h" #include "config.h" -#include "sysctlr.h" - -std::unique_ptr gMPU88200ATC[2]; +#include "debugger.h" +#include "m88100disasm.h" +#include "scheduler.h" +#include "syncer.h" // コンストラクタ -MPU88xx0Device::MPU88xx0Device(uint32 addr) +MPU88xx0Device::MPU88xx0Device() + : inherited() { - monitor.Init(79, 18); - - // リセットベクタアドレスは Reset() で指定するので保持しておく - reset_vector = addr; + SetName("MPU(88100)"); - cpu.reset(new m88kcpu()); - - // LUNA88K では CMMU の ID は次のように割り振ってあるようだ。 + // LUNA-88K では CMMU の ID は次のように割り振ってあるようだ。 // OpenBSD の sys/arch/luna68k/include/board.h より。 // // Inst Data @@ -31,16 +30,32 @@ MPU88xx0Device::MPU88xx0Device(uint32 ad // CPU#2 ID=3 ID=2 // CPU#3 ID=1 ID=0 // - // 厳密にはこれは LUNA88K のハードウェアがどういうコンフィグレーションで + // 厳密にはこれは LUNA-88K のハードウェアがどういうコンフィグレーションで // m88200 を使うかなので、ここではなくて vm_luna あたりのほうがいいかも // しれんけど、あまり遠いのも面倒なので、とりあえずこの辺に。 // あとマルチプロセッサになったらまたその時考える。 - cpu->cmmu[0].SetID(7); - cpu->cmmu[1].SetID(6); + cmmu[0].reset(new m88200(this, 7)); + cmmu[1].reset(new m88200(this, 6)); + + // 設定の初期値。 - // モニタ用の別オブジェクト - gMPU88200ATC[0].reset(new MPU88200ATC(&cpu->cmmu[0])); - gMPU88200ATC[1].reset(new MPU88200ATC(&cpu->cmmu[1])); + // MPU のデフォルトは xxx.usr バグ修正済みのバージョンに設定する。 + // 所有している実機にあわせ 0xb。OpenBSD の + // sys/arch/m88k/m88k/m88100_machdep.c::m88100_apply_patches() 参照。 + gConfig->SetDefault("m88100-version", 0xb); + + // CMMU のデフォルトは xmem の writeback バグが修正されているバージョンに + // 設定する。所有している実機にあわせ 0x9。 + // OpenBSD の sys/arch/m88k/m88k/m8820x_machdep.c::m8820x_apr_cmode() 参照。 + gConfig->SetDefault("m88200-version", 0x9); + + // 例外カウンタ + excep_counter.resize(512); + + // レジスタモニター + monitor = gMonitorManager->Regist(ID_MONITOR_MPUREG, this); + monitor->func = ToMonitorCallback(&MPU88xx0Device::MonitorUpdate); + monitor->SetSize(79, 25); } // デストラクタ @@ -48,233 +63,459 @@ MPU88xx0Device::~MPU88xx0Device() { } +// 初期化 +bool +MPU88xx0Device::Init() +{ + if (inherited::Init() == false) { + return false; + } + + debugger = GetDebugger(); + + const ConfigItem& item_stop = gConfig->Find("mpu-pseudo-stop"); + pseudo_stop_enable = (bool)item_stop.AsInt(); + + const ConfigItem& item_altname = gConfig->Find(".m88k-altname"); + m88100disasm::use_altname = item_altname.AsInt(); + + // MPU のバージョン。 + const ConfigItem& item_88100ver = gConfig->Find("m88100-version"); + uint ver88100 = item_88100ver.AsInt(); + reg.pid = (ver88100 << 1) | M88100::PID_MASTER; + + // CMMU のバージョン。 + const ConfigItem& item_88200ver = gConfig->Find("m88200-version"); + uint ver88200 = item_88200ver.AsInt(); + cmmu[0]->SetVersion(ver88200); + cmmu[1]->SetVersion(ver88200); + + return true; +} + // リセット -// (MPU が動くのはこの後 Scheduler::Run() を発行した後) void -MPU88xx0Device::ResetHard() +MPU88xx0Device::ResetHard(bool poweron) +{ + if (poweron) { + // レジスタのうち不定と明記されてるものは、未初期化のまま触ったことが + // 分かりやすいような適当なパターンで埋めておく。ただし最上位も c に + // すると BT45x のレジスタ付近を指してしまうので、それは避けておく。 + const uint32 Undefined = 0x0ccccccc; + for (int i = 1; i < 32; i++) { + reg.r[i] = Undefined; + } + for (int i = 0; i < countof(reg.fcr); i++) { + reg.fcr[i] = Undefined & reg.fcr_mask[i]; + } + + reg.epsr = Undefined; + reg.ssbr = Undefined; + reg.sfip = Undefined; + reg.snip = Undefined; + reg.sxip = Undefined; + // DMTx は bit0(Valid) をクリア。DMAx/DMDx は不定。 + reg.dma0 = Undefined; + reg.dma1 = Undefined; + reg.dma2 = Undefined; + reg.dmd0 = Undefined; + reg.dmd1 = Undefined; + reg.dmd2 = Undefined; + + // アクセスが一度もない時にどのアドレスとも一致しないようにしておく。 + lastaddr = (uint64)-1; + + // サイクルを初期化。 + used_cycle = 0; + + // 履歴は電源オン時だけ初期化。 + // (LUNA-88K は ROM が正常パスで CPU リセットを行ったりするので) + exhist.Clear(); + brhist.Clear(); + + // この後起きるリセット例外で xip を初期化する前に参照することに + // なるので、これだけここでも初期化しておく。 + reg.xip = 0; + } + + // intr_pending は m88100core.cpp の ExecNormal() 中のコメント参照。 + resetting = true; + intr_pending = 1; + + // リセット例外を 8+256 クロック後に起こす。 + // 8+256 は、電源オン時に最低これだけアサートしなければならないという値 + // のはずで、実際これだけかかるとかいう値ではない。が、こちら側の都合で + // この後実行される RAM の ResetHard() がブートページを用意した後で + // cpu->Reset() で xip をフェッチするという順序にしないといけないため、 + // リセット例外が起動するまでに時間がかかるというところを都合よく真似て + // おく。 + + exec_event.func = ToEventCallback(&MPU88xx0Device::ResetCallback); + exec_event.time = (8 + 256) * clock_nsec; + exec_event.SetName(GetName() + " Reset"); + scheduler->RestartEvent(exec_event); +} + +// リセット例外コールバック。 +// MPU リセットから規定時間後に呼ばれる。 +void +MPU88xx0Device::ResetCallback(Event& ev) { - cpu->Reset(reset_vector); + resetting = false; + + // リセット例外を実行 + uint64 cycle_start = used_cycle; + + // 例外履歴に記録 (例外発生はブランチ履歴にも記録) + // リセット例外も発生時の XIP を記録する。(LUNA-88K の PROM 1.20) + exhist.AddEntry(reg.xip | 1, 0, 0xfc000000 | 0); + brhist.AddEntry(reg.xip | 1, 0, 0xfc000000 | 0); + // デバッガに通知 (例外ブレーク用) + debugger->NotifyExceptionMain(0); + + // 内部の割り込み状態をクリア + intr_pending = 0; + ChangeState(CPU_STATE_NORMAL); + + // 実際どこかは分からんけど PSR 設定の前にリセットしておきたい + cmmu[0]->Reset(); + cmmu[1]->Reset(); + + // Table 6-8 (p6-47) + reg.psr = 0x800003ff; + // XXX ただし SFU1 は未実装なので下げておく + reg.psr &= ~PSR_SFD1; + +#if defined(TEST_INTERRUPT) + reg.psr &= ~PSR_IND; + reg.psr &= ~PSR_SFRZ; +#endif + + SetPSR(); + + reg.fip = 0; + + // レジスタのうち明記されてるものをクリア。 + // 不定と明記されてるものはリセットでは触らないでおく。 + // scoreboard: cleared + reg.nip = 0; + reg.xip = 0; + reg.vbr = 0; + reg.fpecr = 0; + reg.fpcr = 0; + reg.fpsr = 0; + // DMTx は bit0(Valid) をクリア。他は不定 + reg.dmt0 &= ~DM_VALID; + reg.dmt1 &= ~DM_VALID; + reg.dmt2 &= ~DM_VALID; + + fetch(); + + // リセット例外はここまで。 + // ここからは最初の命令のプリフェッチ + Prefetch(); + + // コールバックを ResetCallback から Exec* に差し替える前のここで + // トレース状態を初期化する。 + SetTrace(debugger->IsTrace()); + + // 以降は通常走行 + int cycle = used_cycle - cycle_start; + exec_event.func = exec_normal; + exec_event.time = cycle * clock_nsec; + exec_event.SetName(GetName() + " Execute"); + scheduler->StartEvent(exec_event); +} + +// トレース実行のコールバック +void +MPU88xx0Device::ExecTrace(Event& ev) +{ + debugger->ExecMain(); + ExecNormal(ev); +} + +// トレース状態を設定する +void +MPU88xx0Device::SetTrace(bool enable) +{ + if (enable) { + exec_normal = ToEventCallback(&MPU88xx0Device::ExecTrace); + } else { + exec_normal = ToEventCallback(&MPU88xx0Device::ExecNormal); + } + exec_event.func = exec_normal; +} + +void +MPU88xx0Device::ChangeState(uint32 new_state) +{ + // new_state (CPU_STATE_*) と + // RequestCPUMode() の引数 Syncer::SYNCMODE_CPU_* は + // 実は同じ値なのでそのまま渡してよいことにする。 + static_assert(CPU_STATE_NORMAL == Syncer::SYNCMODE_CPU_NORMAL, ""); + static_assert(CPU_STATE_STOP == Syncer::SYNCMODE_CPU_STOP, ""); + + if (cpu_state != new_state) { + cpu_state = new_state; + // スケジューラに通知 + syncer->RequestCPUMode(new_state); + } +} + +// アクセス中の論理アドレスを取得 +uint32 +MPU88xx0Device::GetLaddr() const +{ + m88200 *m = m88200::GetBusMaster(); + assert(m); + return m->GetLaddr(); +} + +// アクセス中の物理アドレスを取得 +uint32 +MPU88xx0Device::GetPaddr() const +{ + m88200 *m = m88200::GetBusMaster(); + assert(m); + return m->GetPaddr(); } // Interrupt void -MPU88xx0Device::Interrupt(Object *src, int level) +MPU88xx0Device::Interrupt(int level) { - // XXX: なぜか 1 レベルずれている? - level++; - if (gSysCtlr->GetIntMask(0) & (1 << level)) { - putlog(1, "Interrupt from %s", src->devname.c_str()); - gSysCtlr->TellIntLevel(0, 1 << level); - cpu->Interrupt(); + // level は 0 か 1。 + intr_pending = level; + + if (intr_pending && IsIntrEnable() && (cpu_state == CPU_STATE_STOP)) { + // 割り込みを受け付けたら STOP 解除。 + ChangeState(CPU_STATE_NORMAL); } } +// DOS call エミュレーションのコールバックを指定 +void +MPU88xx0Device::SetFLineCallback(bool (*callback)(MPU88xx0Device *, void *), + void *arg) +{ + fline_callback = callback; + fline_arg = arg; +} + +#define FA(val, bit) TA::OnOff((val) & M88100::bit) + // モニター更新 -bool -MPU88xx0Device::MonitorUpdate() +void +MPU88xx0Device::MonitorUpdate(Monitor *, TextScreen& screen) { - m88100reg reg; + m88100reg tmp; int x; int y; - monitor.Clear(); + screen.Clear(); // ローカルにコピー - reg = *cpu; + tmp = reg; - // - for (int i = 0; i < countof(reg.r); i++) { - monitor.Print((i / 8) * 14, i % 8, "r%-2d:%08x", i, reg.r[i]); + // 汎用レジスタ + for (uint i = 0; i < countof(reg.r); i++) { + screen.Print((i / 8) * 14, i % 8, "r%-2u:%08x", i, tmp.r[i]); } - // 制御レジスタ - x = 0; - y = 9; - monitor.Print(x, y++, "pid (cr0):%08x(Arch=$%02x Ver=$%02x MC=%s)", - reg.pid, - (reg.pid >> 8) & 0xff, - (reg.pid >> 1) & 0x7f, - (reg.pid & 1) ? "Master" : "Checker"); - monitor.Print(x, y, "psr (cr1):%08x(", reg.psr); - monitor.Puts(x + 19, y, TA::OnOff(reg.psr & m88100reg::PSR_SUPER), "S"); - monitor.Puts(x + 21, y, - ((reg.psr & m88100reg::PSR_BO_LE) ? "BO=LE" : "BO=BE")); - monitor.Puts(x + 27, y, TA::OnOff(reg.psr & m88100reg::PSR_SER), "SER"); - monitor.Puts(x + 31, y, TA::OnOff(reg.psr & m88100reg::PSR_C), "Cy"); - monitor.Puts(x + 34, y, TA::OnOff(reg.psr & m88100reg::PSR_SFD1), "SFD1"); - monitor.Puts(x + 39, y, TA::OnOff(reg.psr & m88100reg::PSR_MXM), "MXM"); - monitor.Puts(x + 43, y, TA::OnOff(reg.psr & m88100reg::PSR_IND), "IND"); - monitor.Puts(x + 47, y, TA::OnOff(reg.psr & m88100reg::PSR_SFRZ), "SFRZ"); - monitor.Puts(x + 51, y, ")"); - y++; - monitor.Print(x, y, "epsr(cr2):%08x(", reg.epsr); - monitor.Puts(x + 19, y, TA::OnOff(reg.epsr & m88100reg::PSR_SUPER), "S"); - monitor.Puts(x + 21, y, - ((reg.epsr& m88100reg::PSR_BO_LE) ? "BO=LE" : "BO=BE")); - monitor.Puts(x + 27, y, TA::OnOff(reg.epsr & m88100reg::PSR_SER), "SER"); - monitor.Puts(x + 31, y, TA::OnOff(reg.epsr & m88100reg::PSR_C), "Cy"); - monitor.Puts(x + 34, y, TA::OnOff(reg.epsr & m88100reg::PSR_SFD1), "SFD1"); - monitor.Puts(x + 39, y, TA::OnOff(reg.epsr & m88100reg::PSR_MXM), "MXM"); - monitor.Puts(x + 43, y, TA::OnOff(reg.epsr & m88100reg::PSR_IND), "IND"); - monitor.Puts(x + 47, y, TA::OnOff(reg.epsr & m88100reg::PSR_SFRZ), "SFRZ"); - monitor.Puts(x + 51, y, ")"); - - // 制御レジスタ(左中; *IP) - x = 0; - y = 12; - monitor.Print(x, y + 0, "xip:%08x opX:%08x(%c%c)", - reg.xip, (uint32)reg.opX, - cpu->OpIsBusErr(reg.opX) ? 'B' : '-', - cpu->OpIsDelay(reg.opX) ? 'D' : '-'); - monitor.Print(x, y + 1, "nip:%08x opF:%08x(%c%c)", - reg.nip, (uint32)reg.opF, - cpu->OpIsBusErr(reg.opF) ? 'B' : '-', - cpu->OpIsDelay(reg.opF) ? 'D' : '-'); - monitor.Print(x, y + 2, "fip:%08x", reg.fip); - - // 制御レジスタ (S*IP) - x = 32; + // 制御レジスタ (上段右) + x = 57; + y = 0; + for (int i = 0; i < 4; i++) { + int rn = 17 + i; + screen.Print(x, y++, "sr%u(cr%u):%08x", i, rn, tmp.cr[rn]); + } + screen.Print(x, y++, "ssbr(cr3):%08x", tmp.ssbr); for (int i = 0; i < 3; i++) { - monitor.Print(x, y + i, "%s(cr%d):%08x:%c%c", + screen.Print(x, y++, "%s(cr%u):%08x:%c%c", m88100reg::sipname[i], 4 + i, - (reg.cr[4 + i] & m88100reg::SIP_MASK), - (reg.cr[4 + i] & m88100reg::SIP_V) ? 'V' : '-', - (reg.cr[4 + i] & m88100reg::SIP_E) ? 'E' : '-'); + (tmp.cr[4 + i] & M88100::SIP_MASK), + (tmp.cr[4 + i] & M88100::SIP_V) ? 'V' : '-', + (tmp.cr[4 + i] & M88100::SIP_E) ? 'E' : '-'); } + screen.Print(x, y++, "vbr (cr7):%08x", tmp.vbr); - // 制御レジスタ(右中) - x = 55; + // 制御レジスタ(中段上; *IP) + x = 0; y = 9; - monitor.Print(x, y++, "ssbr(cr3):%08x", reg.ssbr); - monitor.Print(x, y++, "vbr (cr7):%08x", reg.vbr); - for (int i = 0; i < 4; i++) { - int rn = 17 + i; - monitor.Print(x, y + i, "sr%d(cr%d):%08x", i, rn, reg.cr[rn]); - } + screen.Print(x, y++, "xip:%08x (op:%08x:%c)", + tmp.xip, (uint32)tmp.opX, OpIsBusErr(tmp.opX) ? 'B' : '-'); + screen.Print(x, y++, "nip:%08x (op:%08x:%c)", + tmp.nip, (uint32)tmp.opF, OpIsBusErr(tmp.opF) ? 'B' : '-'); + screen.Print(x, y++, "fip:%08x", tmp.fip); - // MMU レジスタ(下段) - x = 0; - y = 15; - for (int i = 0; i <= 2; i++) { - int dt = 8 + i * 3; - int dd = 9 + i * 3; - int da = 10 + i * 3; - - monitor.Print(0, y, "dmt%d(cr%-2d):%04x", - i, dt, (reg.cr[dt] & 0xffff)); - monitor.Puts(15, y, "(b,s,d,l,rx, s,en ,w,v)"); - monitor.Puts(16, y, (reg.cr[dt] & m88100reg::DM_BO) ? "B" : "-"); - monitor.Puts(18, y, (reg.cr[dt] & m88100reg::DM_DAS) ? "S" : "U"); - monitor.Puts(20, y, (reg.cr[dt] & m88100reg::DM_DOUB1) ? "D" : "-"); - monitor.Puts(22, y, (reg.cr[dt] & m88100reg::DM_LOCK) ? "L" : "-"); - // カンマが自然に見えるようにここだけカンマも含めて前詰めで出力 - monitor.Print(25, y, "%d,", - (reg.cr[dt] & m88100reg::DM_DREG_MASK) >> 7); - monitor.Puts(28, y, (reg.cr[dt] & m88100reg::DM_SIGNED) ? "S" : "-"); - uint32 en = (reg.cr[dt] & m88100reg::DM_EN_MASK) >> 2; - monitor.Puts(30, y, m88100reg::dmt_en_str[en]); - monitor.Puts(35, y, (reg.cr[dt] & m88100reg::DM_WRITE) ? "W" : "-"); - monitor.Puts(37, y, (reg.cr[dt] & m88100reg::DM_VALID) ? "V" : "-"); + // 制御レジスタ 中段上; pid,*psr) + x = 30; + y = 9; + screen.Print(x, y++, "pid(cr0):%08x(Arch=$%02x Ver=$%02x MC=%s)", + tmp.pid, + (tmp.pid >> 8) & 0xff, + (tmp.pid >> 1) & 0x7f, + (tmp.pid & 1) ? "Master" : "Checker"); + screen.Print(x, y, "psr(cr1):%08x(", tmp.psr); + x--; + screen.Puts(x + 19, y, FA(tmp.psr, PSR_SUPER), "S"); + screen.Puts(x + 21, y, ((tmp.psr & M88100::PSR_BO_LE) ? "LE" : "BE")); + screen.Puts(x + 24, y, FA(tmp.psr, PSR_SER), "SER"); + screen.Puts(x + 28, y, FA(tmp.psr, PSR_C), "Cy"); + screen.Puts(x + 31, y, FA(tmp.psr, PSR_SFD1), "SFD1"); + screen.Puts(x + 36, y, FA(tmp.psr, PSR_MXM), "MXM"); + screen.Puts(x + 40, y, FA(tmp.psr, PSR_IND), "IND"); + screen.Puts(x + 44, y, FA(tmp.psr, PSR_SFRZ), "SFRZ"); + screen.Puts(x + 48, y, ")"); + y++; + screen.Print(x, y, "epsr(cr2):%08x(", tmp.epsr); + screen.Puts(x + 19, y, FA(tmp.epsr, PSR_SUPER), "S"); + screen.Puts(x + 21, y, ((tmp.epsr& M88100::PSR_BO_LE) ? "LE" : "BE")); + screen.Puts(x + 24, y, FA(tmp.epsr, PSR_SER), "SER"); + screen.Puts(x + 28, y, FA(tmp.epsr, PSR_C), "Cy"); + screen.Puts(x + 31, y, FA(tmp.epsr, PSR_SFD1), "SFD1"); + screen.Puts(x + 36, y, FA(tmp.epsr, PSR_MXM), "MXM"); + screen.Puts(x + 40, y, FA(tmp.epsr, PSR_IND), "IND"); + screen.Puts(x + 44, y, FA(tmp.epsr, PSR_SFRZ), "SFRZ"); + screen.Puts(x + 48, y, ")"); - monitor.Print(40, y, "dmd%d(cr%-2d):%08x", i, dd, reg.cr[dd]); - monitor.Print(60, y, "dma%d(cr%2d):%08x", i, da, reg.cr[da]); + // MMU レジスタ(中段下) + y = 12; + for (uint i = 0; i <= 2; i++) { + uint dt = 8 + i * 3; + uint dd = 9 + i * 3; + uint da = 10 + i * 3; + + // DMT は "cr8 " があるので左揃え + screen.Print(0, y, "dmt%u(cr%-2u):%04x", + i, dt, (tmp.cr[dt] & 0xffff)); + screen.Puts(15, y, "(b,s,d,l,rx, s,en ,w,v)"); + screen.Puts(16, y, (tmp.cr[dt] & M88100::DM_BO) ? "B" : "-"); + screen.Puts(18, y, (tmp.cr[dt] & M88100::DM_DAS) ? "S" : "U"); + screen.Puts(20, y, (tmp.cr[dt] & M88100::DM_DOUB1) ? "D" : "-"); + screen.Puts(22, y, (tmp.cr[dt] & M88100::DM_LOCK) ? "L" : "-"); + // カンマが自然に見えるようにここだけカンマも含めて前詰めで出力 + screen.Print(25, y, "%u,", + (tmp.cr[dt] & M88100::DM_DREG_MASK) >> 7); + screen.Puts(28, y, (tmp.cr[dt] & M88100::DM_SIGNED) ? "S" : "-"); + uint32 en = (tmp.cr[dt] & M88100::DM_EN_MASK) >> 2; + screen.Puts(30, y, m88100reg::dmt_en_str[en]); + screen.Puts(35, y, (tmp.cr[dt] & M88100::DM_WRITE) ? "W" : "-"); + screen.Puts(37, y, (tmp.cr[dt] & M88100::DM_VALID) ? "V" : "-"); + + // DMD は "cr9 " があるので左揃え + screen.Print(40, y, "dmd%u(cr%-2u):%08x", i, dd, tmp.cr[dd]); + screen.Print(60, y, "dma%u(cr%2u):%08x", i, da, tmp.cr[da]); y++; } + y++; - return true; -} - -// -// {B,P}ATC モニタ -// - -// コンストラクタ -MPU88200ATC::MPU88200ATC(m88200 *cmmu_) -{ - cmmu = cmmu_; - - monitor.Init(65, 38); -} + // FPU レジスタ (下段) + screen.Print(0, y, "fpecr(fcr0):%08x(", tmp.fpecr); + x = 21; + screen.Puts(x + 0, y, FA(tmp.fpecr, FPECR_FIOV), "FIOV"); + screen.Puts(x + 5, y, FA(tmp.fpecr, FPECR_FUNIMP), "FUNIMP"); + screen.Puts(x + 12, y, FA(tmp.fpecr, FPECR_FPRV), "FPRV"); + screen.Puts(x + 17, y, FA(tmp.fpecr, FPECR_FROP), "FROP"); + screen.Puts(x + 22, y, FA(tmp.fpecr, FPECR_FDVZ), "FDVZ"); + screen.Puts(x + 27, y, FA(tmp.fpecr, FPECR_FUNF), "FUNF"); + screen.Puts(x + 32, y, FA(tmp.fpecr, FPECR_FOVF), "FOVF"); + screen.Puts(x + 37, y, FA(tmp.fpecr, FPECR_FINX), "FINX"); + screen.Puts(x + 41, y, ")"); + y++; -bool -MPU88200ATC::MonitorUpdate() -{ - int x; - int y; + screen.Print(0, y++, + "fppt(fcr5): %08x(OpCode=%%%c%c%c%c%c T1=%u T2=%u TD=%u Dest=r%u)", + tmp.fppt, + ((tmp.fppt >> 15) & 1) + '0', + ((tmp.fppt >> 14) & 1) + '0', + ((tmp.fppt >> 13) & 1) + '0', + ((tmp.fppt >> 12) & 1) + '0', + ((tmp.fppt >> 11) & 1) + '0', + ((tmp.fppt >> 9) & 3), + ((tmp.fppt >> 7) & 3), + ((tmp.fppt >> 5) & 3), + (tmp.fppt & M88100::FPPT_DEST)); + + screen.Print(0, y++, "fphs1(fcr1)/fpls1(fcr2): %08x'%08x", + tmp.fphs1, tmp.fpls1); + screen.Print(0, y++, "fphs2(fcr3)/fpls2(fcr4): %08x'%08x", + tmp.fphs2, tmp.fpls2); + + screen.Print(0, y, "fprh(fcr6) /fprl(fcr7): %08x'%08x(", + tmp.fprh, tmp.fprl); + x = 43; + screen.Puts(x + 0, y, FA(tmp.fprh, FPRH_ADDONE), "ADDONE"); + screen.Print(x + 7, y, "RM=%s)", rmstr[(tmp.fprh >> 29) & 3]); + y++; - monitor.Clear(); + x = 21; + screen.Print(0, y, "fpit(fcr8): %08x(OpCode=%%%c%c%c%c%c TD=%u", + tmp.fpit, + ((tmp.fpit >> 15) & 1) + '0', + ((tmp.fpit >> 14) & 1) + '0', + ((tmp.fpit >> 13) & 1) + '0', + ((tmp.fpit >> 12) & 1) + '0', + ((tmp.fpit >> 11) & 1) + '0', + ((tmp.fpit >> 10) & 1)); + screen.Puts(x + 19, y, FA(tmp.fpit, FPIT_EFINV), "EINV"); + screen.Puts(x + 24, y, FA(tmp.fpit, FPIT_EFDVZ), "EDVZ"); + screen.Puts(x + 29, y, FA(tmp.fpit, FPIT_EFUNF), "EUNF"); + screen.Puts(x + 34, y, FA(tmp.fpit, FPIT_EFOVF), "EOVF"); + screen.Puts(x + 39, y, FA(tmp.fpit, FPIT_EFINX), "EINX"); + screen.Print(x + 44, y, "Dest=r%u)", tmp.fpit & M88100::FPIT_DEST); + y++; - monitor.Print(0, 0, "SAPR %05x'000 TE=%d %c%c%c", - (cmmu->sapr.addr >> 12) & 0xfffff, - cmmu->sapr.enable ? 1 : 0, - (cmmu->sapr.stat & m88200::APR_WT) ? 'T' : '-', - (cmmu->sapr.stat & m88200::APR_G) ? 'G' : '-', - (cmmu->sapr.stat & m88200::APR_CI) ? 'C' : '-'); - - monitor.Print(34, 0, "UAPR %05x'000 TE=%d %c%c%c", - (cmmu->uapr.addr >> 12) & 0xfffff, - cmmu->uapr.enable ? 1 : 0, - (cmmu->uapr.stat & m88200::APR_WT) ? 'T' : '-', - (cmmu->uapr.stat & m88200::APR_G) ? 'G' : '-', - (cmmu->uapr.stat & m88200::APR_CI) ? 'C' : '-'); - - monitor.Puts(0, 1, ""); - monitor.Puts(0, 2, "No. LBA PBA Stat"); - monitor.Puts(34, 2, "No. LBA PBA Stat"); - x = 0; - y = 3; - for (int i = 0; i < 10; i++) { - m88200BATC& b = cmmu->batc[i]; - - if (i == cmmu->batc.size() / 2) { - x = 34; - y = 3; - } - if (i < 8) { - monitor.Print(x, y, " %d:", i); + uint32 sign = (tmp.fprh & M88100::FPRH_SIGN); + uint32 exp = (int32)tmp.fpit >> 20; + uint32 mant_h = (tmp.fprh & 0x000fffff); + uint32 mant_l = tmp.fprl; + screen.Print(12, y, "result: %c%1x.%05x'%08x'grs e%+d", + (sign ? '-' : '+'), + ((tmp.fprh >> 20) & 1), + mant_h, + mant_l, + exp - 0x3ff); + screen.Puts(38, y, FA(tmp.fprh, FPRH_GUARD), "G"); + screen.Puts(39, y, FA(tmp.fprh, FPRH_ROUND), "R"); + screen.Puts(40, y, FA(tmp.fprh, FPRH_STICKY), "S"); + screen.Print(48, y, "($%03x)", exp & 0x7ff); + // Inf と NAN はこの形式だけからでは分かりづらいので別途追加で表示。 + // exp は符号拡張しているので指数部 $7ff は exp == -1。 + if (exp == 0xffffffff) { + x = 55; + if ((mant_h | mant_l) == 0) { + if (sign == 0) { + screen.Puts(x, y, "= +Inf"); + } else { + screen.Puts(x, y, "= -Inf"); + } } else { - monitor.Print(x, y, "(%d)", i); + if (sign == 0) { + screen.Puts(x, y, "= +NAN"); + } else { + screen.Puts(x, y, "= -NAN"); + } } - if ((b.lba & 1) == 0) { - monitor.Print(x + 4, y, "%c:%04x'0000 %04x'0000 %c%c%c%c", - (b.lba & m88200::BATC_S) ? 'S' : 'U', - b.lba >> 16, b.pba >> 16, - (b.stat & m88200::DESC_WT) ? 'T' : '-', - (b.stat & m88200::DESC_G) ? 'G' : '-', - (b.stat & m88200::DESC_CI) ? 'C' : '-', - (b.stat & m88200::DESC_WP) ? 'P' : '-'); - } - y++; } + y++; - monitor.Puts(0, 8, ""); - monitor.Puts(0, 9, "No. LPA PFA Stat"); - monitor.Puts(34, 9, "No. LPA PFA Stat"); - - x = 0; - y = 10; - for (int i = 0; i < cmmu->patc.size(); i++) { - m88200PATC& p = cmmu->patc[i]; - - if (i == cmmu->patc.size() / 2) { - x = 34; - y = 10; - } - - monitor.Print(x, y, "%2d:", i); - if ((p.lpa & 1) == 0) { - monitor.Print(x + 4, y, "%c:%05x'000 %05x'000 %c%c%c%c%c", - (p.lpa & m88200::PATC_S) ? 'S' : 'U', - p.lpa >> 12, p.pfa >> 12, - (p.stat & m88200::DESC_WT) ? 'T' : '-', - (p.stat & m88200::DESC_G) ? 'G' : '-', - (p.stat & m88200::DESC_CI) ? 'C' : '-', - (p.stat & m88200::DESC_WP) ? 'P' : '-', - p.m ? 'M' : '-'); - } - - y++; - } + screen.Print(0, y, "fpsr(fcr62):%08x(", tmp.fpsr); + x = 21; + screen.Puts(x + 0, y, FA(tmp.fpsr, FPSR_AFINV), "AFINV"); + screen.Puts(x + 6, y, FA(tmp.fpsr, FPSR_AFDVZ), "AFDVZ"); + screen.Puts(x + 12, y, FA(tmp.fpsr, FPSR_AFUNF), "AFUNF"); + screen.Puts(x + 18, y, FA(tmp.fpsr, FPSR_AFOVF), "AFOVF"); + screen.Puts(x + 24, y, FA(tmp.fpsr, FPSR_AFINX), "AFINX"); + screen.Puts(x + 29, y, ")"); + y++; - return true; + screen.Print(0, y, "fpcr(fcr63):%08x(", tmp.fpcr); + screen.Puts(x + 0, y, FA(tmp.fpcr, FPCR_EFINV), "EFINV"); + screen.Puts(x + 6, y, FA(tmp.fpcr, FPCR_EFDVZ), "EFDVZ"); + screen.Puts(x + 12, y, FA(tmp.fpcr, FPCR_EFUNF), "EFUNF"); + screen.Puts(x + 18, y, FA(tmp.fpcr, FPCR_EFOVF), "EFOVF"); + screen.Puts(x + 24, y, FA(tmp.fpcr, FPCR_EFINX), "EFINX"); + screen.Print(x + 30, y, "RM=%s)", rmstr[(tmp.fpcr >> 14) & 3]); }