--- nono/m88xx0/m88100ops.cpp 2026/04/29 17:04:46 1.1.1.6 +++ nono/m88xx0/m88100ops.cpp 2026/04/29 17:04:54 1.1.1.8 @@ -41,7 +41,38 @@ #define FP_TD m88100opf_FP_TD(opX) // XXX: 暫定 -#include "fp.h" +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; +} + #define FP_GET(v, t, n) \ do { \ if (t == 0) { \ @@ -109,7 +140,8 @@ m88kcpu::EnterBranch(uint32 toaddr) // 新規ブランチ // 初期化 nop_counter = 0; - } else { + } else if (pseudo_stop_enable) { + // 疑似 STOP 状態有効のときに、 // e.count == 2 のときだけ STOP の検証をすれば良い。 // d はブランチ間の命令数 @@ -122,6 +154,14 @@ m88kcpu::EnterBranch(uint32 toaddr) if (nop_counter == d) { atomic_reqflag |= CPU_REQ_STOP; } + + // OpenBSD 6.6 では + // L1: tb1 #1 r0, #0xff + // ld r13, r21, #0x168 + // bcnd.n eq0, r13, L1 + // or r2, r25, #0x5ea0 + // の命令列が使用されている。 + // これについては tb1 で実装してある。 } // STOP ではなかったら、あとは放置していい } @@ -1269,6 +1309,31 @@ OP_DEF(tb1) } if ((rS1 & (1 << B5)) != 0) { ExceptionCore(VEC9, ExceptionKind::TRAP); + } else if (pseudo_stop_enable) { + + // OpenBSD の STOP エミュレーション。 + // OpenBSD 6.6 では + // L1: tb1 #1 r0, #0xff + // ld r13, r21, #0x168 + // bcnd.n eq0, r13, L1 + // or r2, r25, #0x5ea0 + // の命令列が使用されている。 + // tb1 は volatile 変数をアクセスするための同期命令として + // gcc により出力されている。スーパバイザが volatile を + // 観測するために同じアドレスの tb1 に直接ブランチで 3 回飛び込んで + // きたら、それは割り込みか別プロセッサか I/O による変更を待っている + // はずなので STOP と判断してみる。 + // o. 3回、という数字に確たる理由はない。 + // o. 念の為、16バイト(4命令)後方以内からのブランチに限定しておく。 + + if (IsSuper() && VEC9 == 0xff) { + const auto& e = brhist.entry[brhist.top]; + if (e.count == 3 + && e.to == xip + && e.from - e.to < 16) { + atomic_reqflag |= CPU_REQ_STOP; + } + } } }