--- nono/m88xx0/m88100core.cpp 2026/04/29 17:04:57 1.1.1.9 +++ nono/m88xx0/m88100core.cpp 2026/04/29 17:05:05 1.1.1.10 @@ -194,7 +194,8 @@ m88kcpu::Run(uint32 delta) } if (is_intr && IsIntrEnable()) { - // 割り込み処理要求が来ていて、直前の命令が割り込みを禁止していなければ割り込み + // 割り込み処理要求が来ていて、 + // 直前の命令が割り込みを禁止していなければ割り込み // XXX 実際は違う気がする is_intr = false; cpulog(4, "INTR take"); @@ -384,8 +385,7 @@ m88kcpu::ExceptionCore(int vec, Exceptio } } -inline -uint32 +inline uint32 m88kcpu::Calcdmt(uint32 flag) { return @@ -540,17 +540,170 @@ m88kcpu::XmemDataException(uint32 addr, ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA); } -// FP 例外 -// fpex: FP例外コード M88K_FPEXCEP +// FPxS レジスタをセット void -m88kcpu::FPException(int fpex) +m88kcpu::SetFPxS(uint32& h, uint32& l, double src, uint32 ts) { - // FDVZ 以上の例外が PRECISE。 - // 未満の FUNF, FOVF, FINX は IMPRECISE。 - int vec = (fpex >= M88K_FPEXCEP_FDVZ) ? M88K_EXCEP_SFU1_PRECISE : M88K_EXCEP_SFU1_IMPRECISE; - fpecr = fpex; + // FPHS[12]、FPLS[12] は以下の構造 + // + // 3 2 1 0 + // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + // +-+---------------------+---------------------------------------+ + // |S| Exponent(11bit) | High Order 20 bits of Mantissa | FPHSn + // +-+---------------------+---------------------------------------+ + // + // +---------------------------------------------------------------+ + // | Low Order bits of Mantissa, or Integer | FPLSn + // +---------------------------------------------------------------+ + // + // ts が 1 (double) の場合は IEEE754 double と同じ。 + // ts が 0 (single) の場合は float を double にキャスト (拡大変換) した + // ものではないことに注意。 + // S(符号ビット)はそのまま。float の Mantissa (23bit) のうち上位 20bit + // を FPHSn に、残り 3bit を FPLSn の上位 3bit に。ここまではいい。 + // Exponent は float の指数部(8bit、バイアス=127) の値を *そのまま* + // 符号拡張(?)する。 + // (float)1.0 は 1.0 * 2^0 なのでバイアス込みの指数部は 127、 + // (float)2.0 は 1.0 * 2^1 なのでバイアス込みの指数部は 128。 + // バイアス込みにした値は符号なし数のはずだが、ここではこれを 11bit に + // 符号拡張して FPHSn の Exponent 部に格納するようだ。取り出す際に下位 + // 8bit しか取り出さなければ害はないし、符号拡張する方がハードウェア的に + // 都合がよかったとかだろうか。 + // 仮に普通に double に変換すると double の指数部バイアスは 1023 なので + // バイアス込みの指数部は先程の例だとそれぞれ 1023、1024 になるが + // これではないということ。 + + union64 u; + u.q = d2u(src); + if (ts == 0) { + // single + + uint32 exp; + // src は普通の double なのでこの指数部を取り出す + uint32 double_biased = (u.h >> 20) & 0x7ff; + if (double_biased == 0x7ff) { + // Inf, NAN + exp = 0x7ff00000; + } else { + // double のバイアスを外して float のバイアスを足す + int float_biased = (double_biased - 1023) + 127; + // この 8bit 値を 11bit に符号拡張して所定の位置へ + exp = ((int32)(float_biased << 24)) >> 4; + exp &= 0x7ff00000; + } + + h = (u.h & 0x800fffff) | exp; + l = u.l; + } else { + // double + h = u.h; + l = u.l; + } +} + +// FPR[HL] レジスタに double 値をセット +// - それ以外のフィールドは保存する XXX ここでクリアしてもいいか? +// - XXX Guard, Round, Sticky (, AddOne) はまだない +void +m88kcpu::SetFPRx(double src) +{ + union64 u; + uint32 exp; + + u.q = d2u(src); + + // Sign は FPRH + fprh &= ~(FPRH_SIGN | FPRH_MANT); // Mantissa もついでにクリア + fprh |= u.h & 0x80000000; + + // Exp は FPIT。 + // double は 11bit だが FPIT::RESEXP は 12bit なので 1bit 符号拡張する。 + // 符号付き数(正確には負数)の右シフトは実装依存だが gcc, clang は + // 算術右シフトになる。 + // + // 3 2 + // 1 0 9 8 7 6 5 4 3 2 1 0 9 + // +-+---------------------+- + // double |S| Exponent(11bit) | + // +-+---------------------+- + // + // +---------------------+-+- + // u.h<<1 | Exponent(11bit) |X| + // +---------------------+-+- + // + // +-----------------------+- + // exp>>1 | Exponent(12bit) | + // +-----------------------+- + exp = u.h << 1; + exp = (int32)exp >> 1; + fpit &= ~FPIT_RESEXP; + fpit |= exp & FPIT_RESEXP; + + // Mantissa は FPRH, FPRL + // 上位側(FPRH)には最上位(実数桁)の隠しビットを含む。 + fprh |= (u.h & 0x000fffff); + fprh |= FPRH_1; + fprl = u.l; +} + +// FP Precise 例外。浮動小数点数1つの場合。 +void +m88kcpu::FPPreciseException(uint32 cause, double s2) +{ + SetFPS2(s2, m88100opf_FP_T2(opX)); + FPPreciseException(cause); +} + +// FP Precise 例外。浮動小数点数2つの場合。 +void +m88kcpu::FPPreciseException(uint32 cause, double s1, double s2) +{ + SetFPS1(s1, m88100opf_FP_T1(opX)); + SetFPS2(s2, m88100opf_FP_T2(opX)); + FPPreciseException(cause); +} + +// FP Precise 例外。 +void +m88kcpu::FPPreciseException(uint32 cause) +{ + assert(cause == FPECR_FIOV || + cause == FPECR_FUNIMP || + cause == FPECR_FPRV || + cause == FPECR_FROP || + cause == FPECR_FDVZ); + + fpecr = cause; + + // FPPT(FP Precise operation Type Register) + fppt = opX & 0xffe0; // Opcode, T1, T2, TD は opX と同じ位置 + fppt |= m88100opf_D(opX); // DEST + + Exception(M88K_EXCEP_SFU1_PRECISE); +} + +// FP Imprecise 例外。 +void +m88kcpu::FPImpreciseException(uint32 cause) +{ + assert(cause == FPECR_FUNF || + cause == FPECR_FOVF || + cause == FPECR_FINX); + + fpecr = cause; + + // FPIT(FP Imprecise operation Type Register) + fpit &= FPIT_RESEXP; + fpit |= opX & FPIT_OPCODE; + fpit |= (opX & 0x00000020) << 5; // DESTSIZ + fpit |= (fpcr & 0x0000001f) << 5; // EFINV,EFDVZ,EFUNF,EFOVR,EFINX + fpit |= m88100opf_D(opX); // DEST + + // FPRH(FP Result High Register) + fprh &= ~FPRH_RNDMODE; + fprh |= (fpcr & FPCR_RM) << 14; - Exception(vec); + Exception(M88K_EXCEP_SFU1_IMPRECISE); } void @@ -565,7 +718,7 @@ void m88kcpu::fpu_unimpl() { printf("%s\n", __func__); - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); } OP_DEF(illegal)