--- nono/m88xx0/m88100ops.cpp 2026/04/29 17:04:54 1.1.1.8 +++ nono/m88xx0/m88100ops.cpp 2026/04/29 17:04:57 1.1.1.9 @@ -111,6 +111,8 @@ do { \ inline void m88kcpu::EnterBranch(uint32 toaddr) { + // ジャンプ先アドレスの下位2bitはマスクされる + toaddr &= ~3; // ブランチヒストリに登録しつつ、 // ブランチヒストリからブランチ状況を取得 auto e = brhist.AddEntry(xip | (IsSuper() ? 1 : 0), toaddr, opX); @@ -147,7 +149,7 @@ m88kcpu::EnterBranch(uint32 toaddr) // d はブランチ間の命令数 uint32 d = (xip - toaddr) / sizeof(uint32); // 遅延ブランチなら 1 命令余分に実行するはずなので 1 足す - if (opX & (1 << 26)) { + if ((opX & (1 << 26)) != 0) { d++; } // ブランチ間の命令がすべて NOP なら STOP ということにする。 @@ -211,7 +213,7 @@ m88kcpu::ldst_usr(uint32& usr) inline uint32 m88kcpu::ldst_scale(uint32 size) { - if (opX & (1 << 9)) { + if ((opX & (1 << 9)) != 0) { return rS1 + rS2 * size; } else { return rS1 + rS2; @@ -224,7 +226,7 @@ m88kcpu::ldst_scale(uint32 size) inline bool m88kcpu::ldst_align(uint32 size, uint32& addr) { - if (addr & (size - 1)) { + if ((addr & (size - 1)) != 0) { if (IsMXM()) { addr &= ~(size - 1); } else { @@ -320,7 +322,7 @@ static inline int acc_cnd(uint32 r) { int rv; - if (r & 0x80000000) { + if ((r & 0x80000000) != 0) { if (r == 0x80000000) { rv = 0x8; } else { @@ -1204,7 +1206,7 @@ OP_DEF(bb1_n) // 111010_MMMMMSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(bcnd) { - if (acc_cnd(rS1) & M5) { + if ((acc_cnd(rS1) & M5) != 0) { AddCycle(1); // Table.7-5 EnterBranch(xip + D16); ExitBranch(); @@ -1214,7 +1216,7 @@ OP_DEF(bcnd) // 111011_MMMMMSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(bcnd_n) { - if (acc_cnd(rS1) & M5) { + if ((acc_cnd(rS1) & M5) != 0) { EnterBranch(xip + D16); ExitDelayBranch(); } @@ -1344,7 +1346,7 @@ OP_DEF(tcnd) Exception(M88K_EXCEP_PRIV); return; } - if (acc_cnd(rS1) & M5) { + if ((acc_cnd(rS1) & M5) != 0) { ExceptionCore(VEC9, ExceptionKind::TRAP); } } @@ -1792,8 +1794,7 @@ OP_DEF(addu) // 111101_DDDDDSSSSS_011001_nn000sssss OP_DEF(subu) { - // sub 命令では CY ビットは Z80 とかと逆で、0 ならボロー発生。 - // 88100 のマニュアルには書いてない。88110 のマニュアルにある。 + // sub* 命令の CY ビットはボローが発生*していない*時セット。 // 1 の補数をとって足す。 uint64 res = (uint64)rS1 + (~rS2); @@ -1851,15 +1852,15 @@ OP_DEF(add) if (IsCI) { res += GetCY(); } - // XXX: オーバーフローが起きたときにキャリーが更新されるかどうか - // ドキュメントされてない気がする - if (IsCO) { - SetCY(res >> 32); - } if (isovf_add(rS1, rS2, res)) { Exception(M88K_EXCEP_INT_OVF); return; } + + // rD, Cy の更新は例外が起きなかった時だけ (p.6-19) + if (IsCO) { + SetCY(res >> 32); + } if (FLD_D == 0) return; rD = res; @@ -1868,8 +1869,7 @@ OP_DEF(add) // 111101_DDDDDSSSSS_011101_nn000sssss OP_DEF(sub) { - // sub 命令では CY ビットは Z80 とかと逆で、0 ならボロー発生。 - // 88100 のマニュアルには書いてない。88110 のマニュアルにある。 + // sub* 命令の CY ビットはボローが発生*していない*時セット。 // 1 の補数をとって足す。 uint64 res = (uint64)rS1 + (~rS2); @@ -1878,15 +1878,15 @@ OP_DEF(sub) } else { res += 1; } - // XXX: オーバーフローが起きたときにキャリーが更新されるかどうか - // ドキュメントされてない気がする - if (IsCO) { - SetCY(res >> 32); - } if (isovf_sub(rS1, rS2, res)) { Exception(M88K_EXCEP_INT_OVF); return; } + + // rD, Cy の更新は例外が起きなかった時だけ (p.6-19) + if (IsCO) { + SetCY(res >> 32); + } if (FLD_D == 0) return; rD = res; @@ -2083,7 +2083,7 @@ OP_DEF(rte) // CPU は sxip は評価しない。snip は 0 なので、無効として nop 扱い。 // (実際はクロックが消費されるかも?) // sfip が VALID なので、そこから実行を再開する。 - if (snip & SIP_V) { + if ((snip & SIP_V)) { EnterBranch(snip & SIP_MASK); ExitBranch(); fip = sfip & SIP_MASK; @@ -2116,17 +2116,28 @@ OP_DEF(tbnd_2) } } -// 111111_zzzzzzzzzz_000011_zzzzzzzzzz -OP_DEF(getc) +// 111111_DDDDDSSSSS_000001_nnnnnnnnnn +OP_DEF(doscall) { - printf("getc inst\n"); - int c = getchar(); - r[2] = c; -} + // Human68k の DOS call エミュレーションのような何か。 + // 独自ニーモニックでは doscall rD, rS1, #nn と表記することにする。 + // + // Human68k の DOS コール #nn 番を実行し、戻り値を rD に書き込む。 + // 戻り値のない DOS コールでは rD に 0 を指定すること。 + // 引数は rS1 以降に一つずつ置く。m68k でのワードやバイト値の場合は + // 下位詰めするだけで上位ビットのクリア等は不要。 + // 処理するこちら側が必要なビット幅だけを取り出すこと。 + // + // また、ここでのコンソールは VM 内のコンソールではなくホストの標準入出力。 + // + // コールバックがセットされていて特権状態の時のみ発動する。 + // それ以外では現物同様不当命令扱い。 -// 111111_zzzzzzzzzz_000100_zzzzzzzzzz -OP_DEF(putc) -{ - // r3 を表示 - putchar(r[3]); + if (fline_callback && IsSuper()) { + if (fline_callback(this, fline_arg)) { + return; + } + } + + OP_FUNC(illegal); }