--- nono/vm/mpu88xx0.cpp 2026/04/29 17:04:36 1.1.1.2 +++ nono/vm/mpu88xx0.cpp 2026/04/29 17:05:06 1.1.1.10 @@ -10,16 +10,10 @@ #include "config.h" #include "sysctlr.h" -std::unique_ptr gMPU88200ATC[2]; - // コンストラクタ -MPU88xx0Device::MPU88xx0Device(uint32 addr) +MPU88xx0Device::MPU88xx0Device() + : inherited("MPU(88xx0)") { - monitor.Init(79, 18); - - // リセットベクタアドレスは Reset() で指定するので保持しておく - reset_vector = addr; - cpu.reset(new m88kcpu()); // LUNA88K では CMMU の ID は次のように割り振ってあるようだ。 @@ -38,9 +32,10 @@ MPU88xx0Device::MPU88xx0Device(uint32 ad cpu->cmmu[0].SetID(7); cpu->cmmu[1].SetID(6); - // モニタ用の別オブジェクト - gMPU88200ATC[0].reset(new MPU88200ATC(&cpu->cmmu[0])); - gMPU88200ATC[1].reset(new MPU88200ATC(&cpu->cmmu[1])); + // レジスタモニター + monitor.func = (MonitorCallback_t)&MPU88xx0Device::MonitorUpdate; + monitor.SetSize(79, 28); + monitor.Regist(ID_MONITOR_MPUREG); } // デストラクタ @@ -48,94 +43,253 @@ MPU88xx0Device::~MPU88xx0Device() { } -// リセット -// (MPU が動くのはこの後 Scheduler::Run() を発行した後) +bool +MPU88xx0Device::Init() +{ + // 親クラス + if (inherited::Init() == false) { + return false; + } + // MPU クロックは親 Init() で読み込んで、ここで cpu にセットする + cpu->SetClockSpeed(clock_khz); + + const ConfigItem& item = gConfig->Find("mpu-pseudo-stop"); + cpu->pseudo_stop_enable = (bool)item.AsInt(); + + return true; +} + +bool +MPU88xx0Device::PowerOn() +{ + cpu->PowerOn(); + return true; +} + void MPU88xx0Device::ResetHard() { - cpu->Reset(reset_vector); + cpu->RequestReset(); +} + +// アクセス中の論理アドレスを取得 +uint32 +MPU88xx0Device::GetLaddr() const +{ + m88200 *cmmu = m88200::GetBusMaster(); + assert(cmmu); + return cmmu->GetLaddr(); +} + +// アクセス中の物理アドレスを取得 +uint32 +MPU88xx0Device::GetPaddr() const +{ + m88200 *cmmu = m88200::GetBusMaster(); + assert(cmmu); + return cmmu->GetPaddr(); +} + +// アクセスウェイトを加算 +void +MPU88xx0Device::AddCycle(int32 cycle) +{ + // 今アクセスしてきている(= バスマスターの) CMMU に対して加算する + m88200 *cmmu = m88200::GetBusMaster(); + assert(cmmu); + cmmu->AddCycle(cycle); } // Interrupt void -MPU88xx0Device::Interrupt(Object *src, int level) +MPU88xx0Device::Interrupt(int level) +{ + cpu->Interrupt(level); +} + +// DOS call エミュレーションのコールバックを指定 +void +MPU88xx0Device::SetFLineCallback(bool (*callback)(m88kcpu *, void *), void *arg) +{ + cpu->SetFLineCallback(callback, arg); +} + +// MPU からのアクセスをエミュレート +uint64 +MPU88xx0Device::Read8(uint32 addr) +{ + return cpu->cmmu[1].load_8(addr); +} + +uint64 +MPU88xx0Device::Read16(uint32 addr) { - // 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(); + if ((addr & 1) == 0) { + return cpu->cmmu[1].load_16(addr); + } else { + uint64 h, l; + h = Read8(addr); + if ((int64)h < 0) { + return h; + } + l = Read8(addr + 1); + if ((int64)l < 0) { + return l; + } + return (h << 8) | l; + } +} + +uint64 +MPU88xx0Device::Read32(uint32 addr) +{ + if ((addr & 3) == 0) { + return cpu->cmmu[1].load_32(addr); + } else if ((addr & 1) == 0) { + uint64 h, l; + h = Read16(addr); + if ((int64)h < 0) { + return h; + } + l = Read16(addr + 2); + if ((int64)l < 0) { + return l; + } + return (h << 16) | l; + } else { + uint64 h, m, l; + h = Read8(addr); + if ((int64)h < 0) { + return h; + } + m = Read16(addr + 1); + if ((int64)m < 0) { + return m; + } + l = Read8(addr + 3); + if ((int64)l < 0) { + return l; + } + return (h << 24) | (m << 8) | l; } } +uint64 +MPU88xx0Device::Write8(uint32 addr, uint32 data) +{ + return cpu->cmmu[1].store_8(addr, data & 0xff); +} + +uint64 +MPU88xx0Device::Write16(uint32 addr, uint32 data) +{ + if ((addr & 1) == 0) { + return cpu->cmmu[1].store_16(addr, data & 0xffff); + } else { + uint64 r; + r = Write8(addr, data >> 8); + if ((int64)r < 0) { + return r; + } + return Write8(addr + 1, data); + } +} + +uint64 +MPU88xx0Device::Write32(uint32 addr, uint32 data) +{ + if ((addr & 3) == 0) { + return cpu->cmmu[1].store_32(addr, data); + } else if ((addr & 1) == 0) { + uint64 r; + r = Write16(addr, data >> 16); + if ((int64)r < 0) { + return r; + } + return Write16(addr + 2, data); + } else { + uint64 r; + r = Write8(addr, data >> 24); + if ((int64)r < 0) { + return r; + } + r = Write16(addr + 1, data >> 8); + if ((int64)r < 0) { + return r; + } + return Write8(addr + 3, data); + } +} + +#define FA(val, bit) TA::OnOff((val) & m88100reg::bit) + // モニター更新 -bool -MPU88xx0Device::MonitorUpdate() +void +MPU88xx0Device::MonitorUpdate(Monitor *, TextScreen& screen) { m88100reg reg; int x; int y; - monitor.Clear(); + screen.Clear(); // ローカルにコピー reg = *cpu; // for (int i = 0; i < countof(reg.r); i++) { - monitor.Print((i / 8) * 14, i % 8, "r%-2d:%08x", i, reg.r[i]); + screen.Print((i / 8) * 14, i % 8, "r%-2d:%08x", i, reg.r[i]); } // 制御レジスタ x = 0; y = 9; - monitor.Print(x, y++, "pid (cr0):%08x(Arch=$%02x Ver=$%02x MC=%s)", + screen.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, + screen.Print(x, y, "psr (cr1):%08x(", reg.psr); + screen.Puts(x + 19, y, FA(reg.psr, PSR_SUPER), "S"); + screen.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, ")"); + screen.Puts(x + 27, y, FA(reg.psr, PSR_SER), "SER"); + screen.Puts(x + 31, y, FA(reg.psr, PSR_C), "Cy"); + screen.Puts(x + 34, y, FA(reg.psr, PSR_SFD1), "SFD1"); + screen.Puts(x + 39, y, FA(reg.psr, PSR_MXM), "MXM"); + screen.Puts(x + 43, y, FA(reg.psr, PSR_IND), "IND"); + screen.Puts(x + 47, y, FA(reg.psr, PSR_SFRZ), "SFRZ"); + screen.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, + screen.Print(x, y, "epsr(cr2):%08x(", reg.epsr); + screen.Puts(x + 19, y, FA(reg.epsr, PSR_SUPER), "S"); + screen.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, ")"); + screen.Puts(x + 27, y, FA(reg.epsr, PSR_SER), "SER"); + screen.Puts(x + 31, y, FA(reg.epsr, PSR_C), "Cy"); + screen.Puts(x + 34, y, FA(reg.epsr, PSR_SFD1), "SFD1"); + screen.Puts(x + 39, y, FA(reg.epsr, PSR_MXM), "MXM"); + screen.Puts(x + 43, y, FA(reg.epsr, PSR_IND), "IND"); + screen.Puts(x + 47, y, FA(reg.epsr, PSR_SFRZ), "SFRZ"); + screen.Puts(x + 51, y, ")"); // 制御レジスタ(左中; *IP) x = 0; y = 12; - monitor.Print(x, y + 0, "xip:%08x opX:%08x(%c%c)", + screen.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)", + screen.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); + screen.Print(x, y + 2, "fip:%08x", reg.fip); // 制御レジスタ (S*IP) x = 32; for (int i = 0; i < 3; i++) { - monitor.Print(x, y + i, "%s(cr%d):%08x:%c%c", + screen.Print(x, y + i, "%s(cr%d):%08x:%c%c", m88100reg::sipname[i], 4 + i, (reg.cr[4 + i] & m88100reg::SIP_MASK), (reg.cr[4 + i] & m88100reg::SIP_V) ? 'V' : '-', @@ -145,136 +299,147 @@ MPU88xx0Device::MonitorUpdate() // 制御レジスタ(右中) x = 55; 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++, "sr%d(cr%d):%08x", i, rn, reg.cr[rn]); } + screen.Print(x, y++, "ssbr(cr3):%08x", reg.ssbr); + screen.Print(x, y++, "vbr (cr7):%08x", reg.vbr); - // MMU レジスタ(下段) - x = 0; + // MMU レジスタ(次段) 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", + screen.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" : "-"); + screen.Puts(15, y, "(b,s,d,l,rx, s,en ,w,v)"); + screen.Puts(16, y, (reg.cr[dt] & m88100reg::DM_BO) ? "B" : "-"); + screen.Puts(18, y, (reg.cr[dt] & m88100reg::DM_DAS) ? "S" : "U"); + screen.Puts(20, y, (reg.cr[dt] & m88100reg::DM_DOUB1) ? "D" : "-"); + screen.Puts(22, y, (reg.cr[dt] & m88100reg::DM_LOCK) ? "L" : "-"); // カンマが自然に見えるようにここだけカンマも含めて前詰めで出力 - monitor.Print(25, y, "%d,", + screen.Print(25, y, "%d,", (reg.cr[dt] & m88100reg::DM_DREG_MASK) >> 7); - monitor.Puts(28, y, (reg.cr[dt] & m88100reg::DM_SIGNED) ? "S" : "-"); + screen.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" : "-"); + screen.Puts(30, y, m88100reg::dmt_en_str[en]); + screen.Puts(35, y, (reg.cr[dt] & m88100reg::DM_WRITE) ? "W" : "-"); + screen.Puts(37, y, (reg.cr[dt] & m88100reg::DM_VALID) ? "V" : "-"); - 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]); + screen.Print(40, y, "dmd%d(cr%-2d):%08x", i, dd, reg.cr[dd]); + screen.Print(60, y, "dma%d(cr%2d):%08x", i, da, reg.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(", reg.fpecr); + x = 21; + screen.Puts(x + 0, y, FA(reg.fpecr, FPECR_FIOV), "FIOV"); + screen.Puts(x + 5, y, FA(reg.fpecr, FPECR_FUNIMP), "FUNIMP"); + screen.Puts(x + 12, y, FA(reg.fpecr, FPECR_FPRV), "FPRV"); + screen.Puts(x + 17, y, FA(reg.fpecr, FPECR_FROP), "FROP"); + screen.Puts(x + 22, y, FA(reg.fpecr, FPECR_FDVZ), "FDVZ"); + screen.Puts(x + 27, y, FA(reg.fpecr, FPECR_FUNF), "FUNF"); + screen.Puts(x + 32, y, FA(reg.fpecr, FPECR_FOVF), "FOVF"); + screen.Puts(x + 37, y, FA(reg.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=%d T2=%d TD=%d Dest=r%d)", + reg.fppt, + ((reg.fppt >> 15) & 1) + '0', + ((reg.fppt >> 14) & 1) + '0', + ((reg.fppt >> 13) & 1) + '0', + ((reg.fppt >> 12) & 1) + '0', + ((reg.fppt >> 11) & 1) + '0', + ((reg.fppt >> 9) & 3), + ((reg.fppt >> 7) & 3), + ((reg.fppt >> 5) & 3), + (reg.fppt & m88100reg::FPPT_DEST)); + + screen.Print(0, y++, "fphs1(fcr1)/fpls1(fcr2): %08x'%08x", + reg.fphs1, reg.fpls1); + screen.Print(0, y++, "fphs2(fcr3)/fpls2(fcr4): %08x'%08x", + reg.fphs2, reg.fpls2); + + screen.Print(0, y, "fprh(fcr6) /fprl(fcr7): %08x'%08x(", + reg.fprh, reg.fprl); + x = 43; + screen.Puts(x + 0, y, FA(reg.fprh, FPRH_ADDONE), "ADDONE"); + screen.Print(x + 7, y, "RM=%s)", rmstr[(reg.fprh >> 29) & 3]); + y++; - monitor.Clear(); + x = 21; + screen.Print(0, y, "fpit(fcr8): %08x(OpCode=%%%c%c%c%c%c TD=%d", + reg.fpit, + ((reg.fpit >> 15) & 1) + '0', + ((reg.fpit >> 14) & 1) + '0', + ((reg.fpit >> 13) & 1) + '0', + ((reg.fpit >> 12) & 1) + '0', + ((reg.fpit >> 11) & 1) + '0', + ((reg.fpit >> 10) & 1)); + screen.Puts(x + 19, y, FA(reg.fpit, FPIT_EFINV), "EINV"); + screen.Puts(x + 24, y, FA(reg.fpit, FPIT_EFDVZ), "EDVZ"); + screen.Puts(x + 29, y, FA(reg.fpit, FPIT_EFUNF), "EUNF"); + screen.Puts(x + 34, y, FA(reg.fpit, FPIT_EFOVF), "EOVF"); + screen.Puts(x + 39, y, FA(reg.fpit, FPIT_EFINX), "EINX"); + screen.Print(x + 44, y, "Dest=r%d)", reg.fpit & m88100reg::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 = (reg.fprh & m88100reg::FPRH_SIGN); + uint32 exp = (int32)reg.fpit >> 20; + uint32 mant_h = (reg.fprh & 0x000fffff); + uint32 mant_l = reg.fprl; + screen.Print(12, y, "result: %c%1x.%05x'%08x'grs e%+d", + (sign ? '-' : '+'), + ((reg.fprh >> 20) & 1), + mant_h, + mant_l, + exp - 0x3ff); + screen.Puts(38, y, FA(reg.fprh, FPRH_GUARD), "G"); + screen.Puts(39, y, FA(reg.fprh, FPRH_ROUND), "R"); + screen.Puts(40, y, FA(reg.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(", reg.fpsr); + x = 21; + screen.Puts(x + 0, y, FA(reg.fpsr, FPSR_AFINV), "AFINV"); + screen.Puts(x + 6, y, FA(reg.fpsr, FPSR_AFDVZ), "AFDVZ"); + screen.Puts(x + 12, y, FA(reg.fpsr, FPSR_AFUNF), "AFUNF"); + screen.Puts(x + 18, y, FA(reg.fpsr, FPSR_AFOVF), "AFOVF"); + screen.Puts(x + 24, y, FA(reg.fpsr, FPSR_AFINX), "AFINX"); + screen.Puts(x + 29, y, ")"); + y++; - return true; + screen.Print(0, y, "fpcr(fcr63):%08x(", reg.fpcr); + screen.Puts(x + 0, y, FA(reg.fpcr, FPCR_EFINV), "EFINV"); + screen.Puts(x + 6, y, FA(reg.fpcr, FPCR_EFDVZ), "EFDVZ"); + screen.Puts(x + 12, y, FA(reg.fpcr, FPCR_EFUNF), "EFUNF"); + screen.Puts(x + 18, y, FA(reg.fpcr, FPCR_EFOVF), "EFOVF"); + screen.Puts(x + 24, y, FA(reg.fpcr, FPCR_EFINX), "EFINX"); + screen.Print(x + 30, y, "RM=%s)", rmstr[(reg.fpcr >> 14) & 3]); }