--- nono/m88xx0/m88100ops.cpp 2026/04/29 17:05:01 1.1.1.10 +++ nono/m88xx0/m88100ops.cpp 2026/04/29 17:05:07 1.1.1.12 @@ -5,6 +5,7 @@ // #include "m88100acc.h" +#include "bitops.h" #include #include @@ -40,51 +41,15 @@ #define FP_T2 m88100opf_FP_T2(opX) #define FP_TD m88100opf_FP_TD(opX) -// XXX: 暫定 -static float -u2f(uint32 u) -{ - float v; - memcpy(&v, &u, 4); - return v; -} - -static double -u2d(uint64 u) -{ - double v; - memcpy(&v, &u, 8); - return v; -} - -static uint32 -f2u(float v) -{ - uint32 u; - memcpy(&u, &v, 4); - return u; -} - -static uint64 -d2u(double v) -{ - uint64 u; - memcpy(&u, &v, 8); - return u; -} - +// XXX t(サイズ)が原因で Reserved Operand になった時の S1, S2 はどうなる? #define FP_GET(v, t, n) \ do { \ if (t == 0) { \ v = u2f(r[n]); \ } else if (t == 1) { \ - if (n == 31) { \ - FPException(M88K_FPEXCEP_FUNIMP); \ - return; \ - } \ - v = u2d(((uint64)r[n] << 32) | r[n + 1]); \ + v = u2d(((uint64)r[n] << 32) | r[(n + 1) & 31]); \ } else { \ - FPException(M88K_FPEXCEP_FROP); \ + FPPreciseException(FPECR_FROP); \ return; \ } \ } while (0) @@ -94,15 +59,12 @@ do { \ if (t == 0) { \ r[n] = f2u(v); \ } else if (t == 1) { \ - if (n == 31) { \ - FPException(M88K_FPEXCEP_FUNIMP); \ - return; \ - } \ uint64 tmp = d2u(v); \ r[n] = tmp >> 32; \ - r[n + 1] = (uint32)tmp; \ + if (__predict_true(n != 31)) \ + r[n + 1] = (uint32)tmp; \ } else { \ - FPException(M88K_FPEXCEP_FROP); \ + FPPreciseException(FPECR_FROP); \ return; \ } \ } while (0) @@ -154,7 +116,7 @@ m88kcpu::EnterBranch(uint32 toaddr) } // ブランチ間の命令がすべて NOP なら STOP ということにする。 if (nop_counter == d) { - atomic_reqflag |= CPU_REQ_STOP; + ChangeState(CPU_STATE_STOP); } // OpenBSD 6.6 では @@ -290,20 +252,6 @@ LSR(uint32 a, int n) return a >> n; } - -// 右ローテート -static inline uint32 -ROR(uint32 a, int n) -{ - // TODO: 各種コンパイラごとにビルトインがあったりなかったりするらしい - n &= 31; - if (n == 0) { - return a; - } else { - return (a >> n) | (a << (32 - n)); - } -} - // add でのオーバーフロー条件 static inline bool isovf_add(uint32 s1, uint32 s2, uint32 res) @@ -351,6 +299,16 @@ acc_bf(int w, int ofs) return m << ofs; } +// m88100 FPCR の RndMode (0..3) から の丸めモード値への変換。 +// 大抵ここに渡す前に 3 で AND しているはずなので範囲外は考慮しない。 +static int rm_to_round[4] = { + FE_TONEAREST, + FE_TOWARDZERO, + FE_DOWNWARD, + FE_UPWARD, +}; + + // ここから命令定義 // 000000_DDDDDSSSSS_nnnnnn_nnnnnnnnnn @@ -827,8 +785,9 @@ OP_DEF(ldcr) return; } if (FLD_CR > countof(cr)) { - // 88100 undocumented, - // 88110 compatible + // 制御レジスタ番号が範囲外の時は + // 88100 では undocumented、 + // 88110 では Unimplemented Opcode 例外。 Exception(M88K_EXCEP_UNIMPL_OP); return; } @@ -842,30 +801,31 @@ OP_DEF(fldcr) { int n = FLD_CR; - if (IsUser()) { - // fcr62, 63 はユーザモードでアクセスできる - // それ以外はスーパバイザ用。 - if (n < 62) { - Exception(M88K_EXCEP_PRIV); - return; - } - } + // 88100 88110(Only for reference) + // Super User Super User + // ----- ----- ----- ----- + // FCR0 read FPRV read FPRV + // FCR1..8 read FPRV FUNIMP FPRV + // FCR9..61 read0 FPRV FUNIMP FPRV + // FCR62,63 read read read read - if (8 < n && n < 62) { - // 未実装 FCR - // 88100 undocumented, - // 88110 compatible - Exception(M88K_EXCEP_UNIMPL_OP); - return; - } - - // fcr は 62,63 の配置に細工がしてある if (n >= 62) { n = n - 62 + 9; + } else { + if (IsUser()) { + FPPreciseException(FPECR_FPRV); + return; + } + if (n > 8) { + rD = 0; + return; + } } if (FLD_D == 0) return; - rD = fcr[n]; + + // XXX 内部がバグってなければ読み出す時にマスクする必要はないが、一応 + rD = fcr[n] & fcr_mask[n]; } // 100000_zzzzzSSSSS_10000n_nnnnnsssss @@ -876,8 +836,9 @@ OP_DEF(stcr) return; } if (FLD_CR > countof(cr)) { - // 88100 undocumented, - // 88110 unimpl_op + // 制御レジスタ番号が範囲外の時は + // 88100 では undocumented、 + // 88110 では Unimplemented Opcode 例外。 Exception(M88K_EXCEP_UNIMPL_OP); return; } @@ -892,27 +853,34 @@ OP_DEF(fstcr) { int n = FLD_CR; - if (IsUser()) { - // fcr62, 63 はユーザモードでアクセスできる - // それ以外はスーパバイザ用。 - if (n < 62) { - Exception(M88K_EXCEP_PRIV); + // 88100 88110(Only for reference) + // Super User Super User + // ----- ----- ----- ----- + // FCR0 write FPRV write FPRV + // FCR1..8 noop FPRV FUNIMP FPRV + // FCR9..61 noop FPRV FUNIMP FPRV + // FCR62,63 write write write write + + if (n >= 62) { + n = n - 62 + 9; + } else { + if (IsUser()) { + FPPreciseException(FPECR_FPRV); + return; + } + // FCR1..8(読み込み専用レジスタ)、9..61(未実装レジスタ) ともに noop + if (n > 0) { return; } } - if (8 < n && n < 62) { - // 未実装 FCR - // 88100 null op - // 88110 fpu-unimpl - return; - } + fcr[n] = rS1 & fcr_mask[n]; - // fcr は 62,63 の配置に細工がしてある - if (n >= 62) { - n = n - 62 + 9; + // FPCR が変更されたら、ホストの丸めモードも更新 + if (n == 10) { + uint32 rm = (fpcr >> 14) & 3; + std::fesetround(rm_to_round[rm]); } - fcr[n] = rS1; } // 100000_DDDDDSSSSS_11000n_nnnnnsssss @@ -925,8 +893,9 @@ OP_DEF(xcr) return; } if (FLD_CR > countof(cr)) { - // 88100 undocumented, - // 88110 unimpl_op + // 制御レジスタ番号が範囲外の時は + // 88100 では undocumented、 + // 88110 では Unimplemented Opcode 例外。 Exception(M88K_EXCEP_UNIMPL_OP); return; } @@ -942,32 +911,41 @@ OP_DEF(xcr) // 100000_DDDDDSSSSS_11001n_nnnnnsssss OP_DEF(fxcr) { - uint32 tmp; - int n = FLD_CR; + uint n = FLD_CR; - if (IsUser()) { - // fcr62, 63 はユーザモードでアクセスできる - // それ以外はスーパバイザ用。 - if (n < 62) { - Exception(M88K_EXCEP_PRIV); - return; - } - } + // 88100 88110(Only for reference) + // Super User Super User + // ----- ----- ----- ----- + // FCR0 xchg FPRV xchg FPRV + // FCR1..8 read FPRV FUNIMP FPRV + // FCR9..61 read0 FPRV FUNIMP FPRV + // FCR62,63 xchg xchg xchg xchg - if (8 < n && n < 62) { - // 未実装 FCR - // 88100 null op - // 88110 fpu-unimpl + if (IsUser() && n < 62) { + FPPreciseException(FPECR_FPRV); return; } - // fcr は 62,63 の配置に細工がしてある - if (n >= 62) { + if (n == 0) { + goto exchange; + } else if (__predict_false(n < 9)) { + // FCR1..8 は読み込み専用レジスタなので、読み出す側のみ + rD = fcr[n] & fcr_mask[n]; + r[0] = 0; + return; + } else if (__predict_false(n < 62)) { + // FCR9..61 は未実装レジスタなので、0 が読み出せるのみ + rD = 0; + return; + } else { n = n - 62 + 9; } - tmp = rS1; - rD = fcr[n]; - fcr[n] = tmp; + + exchange: + uint32 tmp = rS1; + rD = fcr[n] & fcr_mask[n]; + fcr[n] = tmp & fcr_mask[n]; + r[0] = 0; } @@ -979,7 +957,7 @@ OP_DEF(fmul) double s2; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } @@ -993,7 +971,7 @@ OP_DEF(flt) { // 暫定 if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } @@ -1009,7 +987,7 @@ OP_DEF(fadd) double s2; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } @@ -1026,7 +1004,7 @@ OP_DEF(fsub) double s2; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } @@ -1038,80 +1016,111 @@ OP_DEF(fsub) // 100001_DDDDDSSSSS_00111n_nnnnnsssss OP_DEF(fcmp) { - // 暫定 double s1; double s2; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } FP_GET(s1, FP_T1, FLD_S1); FP_GET(s2, FP_T2, FLD_S2); - rD = acc_fcmp(s1, s2); + + // XXX テストが出来てないので Inf と非正規化数は未対応 + // 非正規化数もここのはず + if (std::isnan(s1) || std::isnan(s2) || + std::isinf(s1) || std::isinf(s2) ) + { + FPPreciseException(FPECR_FROP, s1, s2); + return; + } + + // + // 31 .. 12 11 10 9 8 7 6 5 4 3 2 1 0 + // +---- ---+----+----+----+----+----+----+----+----+----+----+----+----+ + // | 0 | ob | in | ib | ou | ge | lt | le | gt | ne | eq | cp | nc | + // +---- ---+----+----+----+----+----+----+----+----+----+----+----+----+ + + uint32 res = 0; + if (s2 >= 0) { + if (s1 <= 0 || s2 <= s1) res |= 0x0800; // ob + if (0 < s1 && s1 < s2) res |= 0x0400; // in + if (0 <= s1 && s1 <= s2) res |= 0x0200; // ib + if (s1 < 0 || s2 < s1) res |= 0x0100; // ou + } + if (s1 >= s2) res |= 0x0080; // ge + if (s1 < s2) res |= 0x0040; // lt + if (s1 <= s2) res |= 0x0020; // le + if (s1 > s2) res |= 0x0010; // gt + if (s1 != s2) res |= 0x0008; // ne + if (s1 == s2) res |= 0x0004; // eq + // cp; if and only if the two operands are comparable + if (!std::isnan(s1) && !std::isnan(s2)) { + res |= 0x0002; + } + // nc; if, and only if, the two operands are not comparable + if (std::isnan(s1) || std::isnan(s2)) { + res |= 0x0001; + } + + rD = res; } -// 100001_DDDDD00000_010010_0nn00sssss -OP_DEF(int) -{ - // 暫定 - double s2; +// int, nint, trnc 命令の共通部 +void +m88kcpu::ops_int(int rndmode) +{ + double src; + double res; + int exponent; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } - FP_GET(s2, FP_T2, FLD_S2); + if (FP_T2 == 0) { + float f; + FP_GET(f, FP_T2, FLD_S2); + src = f; + } else { + FP_GET(src, FP_T2, FLD_S2); + } + + int saved_rndmode = std::fegetround(); - int mode = (fpcr >> 14) & 3; - switch (mode) { - case 0: - std::fesetround(FE_TONEAREST); - rD = (uint32)(int32)std::nearbyint(s2); - break; - case 1: - rD = (uint32)(int32)std::trunc(s2); - break; - case 2: - rD = (uint32)(int32)std::floor(s2); - break; - case 3: - rD = (uint32)(int32)std::ceil(s2); - break; + std::fesetround(rndmode); + res = std::nearbyint(src); + std::fesetround(saved_rndmode); + + exponent = 0; + std::frexp(res, &exponent); + if (std::isinf(res) || std::isnan(res) || exponent >= 30) { + // 整数で表現出来ない(かも知れない)ので例外 + FPPreciseException(FPECR_FIOV, src); + return; } + rD = (uint32)(int32)res; +} + +// 100001_DDDDD00000_010010_0nn00sssss +OP_DEF(int) +{ + // 現在のモードのまま (ちょっと無駄だけど…) + ops_int(std::fegetround()); } // 100001_DDDDD00000_010100_0nn00sssss OP_DEF(nint) { - // 暫定 - double s2; - - if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); - return; - } - - FP_GET(s2, FP_T2, FLD_S2); - std::fesetround(FE_TONEAREST); - rD = (uint32)(int32)std::nearbyint(s2); + ops_int(FE_TONEAREST); } // 100001_DDDDD00000_010110_0nn00sssss OP_DEF(trnc) { - // 暫定 - double s2; - - if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); - return; - } - - FP_GET(s2, FP_T2, FLD_S2); - rD = (uint32)(int32)std::trunc(s2); + ops_int(FE_TOWARDZERO); } // 100001_DDDDDSSSSS_01110n_nnnnnsssss @@ -1122,7 +1131,7 @@ OP_DEF(fdiv) double s2; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } @@ -1287,7 +1296,7 @@ OP_DEF(rot_1) { if (FLD_D == 0) return; - rD = ROR(rS1, O5); + rD = ROR32(rS1, O5); } // 111100_bbbbbSSSSS_110100_0vvvvvvvvv @@ -1333,7 +1342,7 @@ OP_DEF(tb1) if (e.count == 3 && e.to == xip && e.from - e.to < 16) { - atomic_reqflag |= CPU_REQ_STOP; + ChangeState(CPU_STATE_STOP); } } } @@ -1987,7 +1996,7 @@ OP_DEF(rot_2) if (FLD_D == 0) return; int o = (rS2 ) & 0x1f; - rD = ROR(rS1, o); + rD = ROR32(rS1, o); } // 111101_zzzzzzzzzz_110000_00000sssss