--- nono/m88xx0/m88100ops.cpp 2026/04/29 17:04:54 1.1.1.8 +++ nono/m88xx0/m88100ops.cpp 2026/04/29 17:05:47 1.1.1.16 @@ -5,116 +5,91 @@ // #include "m88100acc.h" +#include "bitops.h" #include #include // 命令のフィールド取り出し -#define FLD_D m88100opf_D(opX) -#define FLD_S1 m88100opf_S1(opX) -#define FLD_S2 m88100opf_S2(opX) -#define FLD_CR m88100opf_CR(opX) -#define B5 m88100opf_B5(opX) -#define M5 m88100opf_M5(opX) -#define W5 m88100opf_W5(opX) -#define O5 m88100opf_O5(opX) -#define IMM16 m88100opf_IMM16(opX) -#define VEC9 m88100opf_VEC9(opX) +#define FLD_D m88100opf_D(reg.opX) +#define FLD_S1 m88100opf_S1(reg.opX) +#define FLD_S2 m88100opf_S2(reg.opX) +#define FLD_CR m88100opf_CR(reg.opX) +#define B5 m88100opf_B5(reg.opX) +#define M5 m88100opf_M5(reg.opX) +#define W5 m88100opf_W5(reg.opX) +#define O5 m88100opf_O5(reg.opX) +#define IMM16 m88100opf_IMM16(reg.opX) +#define VEC9 m88100opf_VEC9(reg.opX) +#define IsCO ((reg.opX & 0x100)) +#define IsCI ((reg.opX & 0x200)) // 符号拡張・シフト済みのディスプレースメント // XXX: (負数の右シフト)GCC only -#define D16 (((int32)(int16)opX) << 2) -#define D26 (((int32)(opX << 6) >> 4)) -#define IsCO ((opX >> 8) & 1) -#define IsCI ((opX >> 9) & 1) +#define D16 (((int32)(int16)reg.opX) << 2) +#define D26 (((int32)(reg.opX << 6) >> 4)) // レジスタアクセス -#define rD (r[FLD_D]) -#define rS1 (r[FLD_S1]) -#define rS2 (r[FLD_S2]) +#define rD (reg.r[FLD_D]) +#define rS1 (reg.r[FLD_S1]) +#define rS2 (reg.r[FLD_S2]) // ダブルワードの2ワード目 #define FLD_D2 ((FLD_D + 1) & 0x1f) -#define rD2 (r[FLD_D2]) +#define rD2 (reg.r[FLD_D2]) // FP フィールド -#define FP_T1 m88100opf_FP_T1(opX) -#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; -} +#define FP_T1 m88100opf_FP_T1(reg.opX) +#define FP_T2 m88100opf_FP_T2(reg.opX) +#define FP_TD m88100opf_FP_TD(reg.opX) +// XXX t(サイズ)が原因で Reserved Operand になった時の S1, S2 はどうなる? #define FP_GET(v, t, n) \ do { \ if (t == 0) { \ - v = u2f(r[n]); \ + v = u2f(reg.r[n]); \ } else if (t == 1) { \ - if (n == 31) { \ - FPException(M88K_FPEXCEP_FUNIMP); \ - return; \ - } \ - v = u2d(((uint64)r[n] << 32) | r[n + 1]); \ + uint64 tmp = (uint64)reg.r[n] << 32; \ + if (__predict_true(n != 31)) \ + tmp |= reg.r[n + 1]; \ + v = u2d(tmp); \ } else { \ - FPException(M88K_FPEXCEP_FROP); \ + FPPreciseException(FPECR_FROP); \ return; \ } \ } while (0) +// n==0 は事前に弾いてある。 #define FP_SET(t, n, v) \ do { \ if (t == 0) { \ - r[n] = f2u(v); \ + reg.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; \ + reg.r[n] = tmp >> 32; \ + if (__predict_true(n != 31)) \ + reg.r[n + 1] = (uint32)tmp; \ } else { \ - FPException(M88K_FPEXCEP_FROP); \ + FPPreciseException(FPECR_FROP); \ return; \ } \ } while (0) -// ブランチ命令入り口 -inline void -m88kcpu::EnterBranch(uint32 toaddr) +#define CHECK_FPU do { \ + if (IsFPUEnable() == false) { \ + FPPreciseException(FPECR_FUNIMP); \ + return; \ + } \ +} while (0) + +// ブランチ命令 +void +MPU88xx0Device::DoBranch(uint32 toaddr, bool next_exec) { + // ジャンプ先アドレスの下位2bitはマスクされる + toaddr &= ~3; // ブランチヒストリに登録しつつ、 // ブランチヒストリからブランチ状況を取得 - auto e = brhist.AddEntry(xip | (IsSuper() ? 1 : 0), toaddr, opX); - fip = toaddr; + auto e = brhist.AddEntry(reg.xip | (IsSuper() ? 1 : 0), toaddr, reg.opX); + reg.fip = toaddr; // STOP 検出。 // m88k には STOP 状態 (何もせず割り込みだけ待つ状態。m68k の STOP 命令 @@ -145,14 +120,14 @@ m88kcpu::EnterBranch(uint32 toaddr) // e.count == 2 のときだけ STOP の検証をすれば良い。 // d はブランチ間の命令数 - uint32 d = (xip - toaddr) / sizeof(uint32); + uint32 d = (reg.xip - toaddr) / sizeof(uint32); // 遅延ブランチなら 1 命令余分に実行するはずなので 1 足す - if (opX & (1 << 26)) { + if (next_exec) { d++; } // ブランチ間の命令がすべて NOP なら STOP ということにする。 if (nop_counter == d) { - atomic_reqflag |= CPU_REQ_STOP; + ChangeState(CPU_STATE_STOP); } // OpenBSD 6.6 では @@ -165,37 +140,12 @@ m88kcpu::EnterBranch(uint32 toaddr) } // STOP ではなかったら、あとは放置していい } -} - -// 通常(即時)ブランチ出口 -inline void -m88kcpu::ExitBranch() -{ - // re-fetch branched instruction - fetch(); -} - -// 遅延ブランチ出口 -// 速度を稼ぐため、ビット反転だけでこれを区別しているので、 -// 同じ op 中で複数回呼び出さないこと。 -inline void -m88kcpu::ExitDelayBranch() -{ - opF ^= DELAYSLOT; -} -// ロードストアユニットの usr の処理。 -// 正常なら true を返す (ので呼び出し側は実行継続)、 -// 例外が起きたら処理して false を返すので呼び出し側は即リターンすること。 -inline bool -m88kcpu::ldst_usr(uint32& usr) -{ - usr = (opX & (1 << 8)) ? DM_USR : 0; - if (IsUser() && usr) { - Exception(M88K_EXCEP_PRIV); - return false; + if (next_exec == false) { + // 通常(即時)ブランチ出口 + // re-fetch branched instruction + fetch(); } - return true; } // MEMO: ロードストアでの usr の処理で、CMMU に対して @@ -209,43 +159,39 @@ m88kcpu::ldst_usr(uint32& usr) // ロードストアユニットの scale の処理。addr を返す。 inline uint32 -m88kcpu::ldst_scale(uint32 size) +MPU88xx0Device::ldst_scale(uint32 size) { - if (opX & (1 << 9)) { + if ((reg.opX & (1U << 9)) != 0) { return rS1 + rS2 * size; } else { return rS1 + rS2; } } -// ロードストアユニットの align の処理。 -// 正常なら true を返す (ので呼び出し側は実行継続)、 -// 例外が起きたら処理して false を返すので呼び出し側は即リターンすること。 -inline bool -m88kcpu::ldst_align(uint32 size, uint32& addr) -{ - if (addr & (size - 1)) { - if (IsMXM()) { - addr &= ~(size - 1); - } else { - Exception(M88K_EXCEP_MISALIGNED); - return false; - } - } - return true; -} - -// ロードストアユニットの usr と scale の処理 (呼び出し用マクロ) +// ロードストアユニットの usr と scale の処理。 +// 正常な場合は usr と addr を更新する。 +// 例外の場合は例外を処理してこのマクロが展開してある関数から return する。 #define LDST_USR_SCALE(size) do { \ - if (ldst_usr(usr) == false) \ + usr = (reg.opX & (1U << 8)) ? DM_USR : 0; \ + if (IsUser() && usr) { \ + Exception(EXCPRI_PRIV); \ return; \ + } \ addr = ldst_scale(size); \ } while (0) -// ロードストアユニットの align の処理 (呼び出し用マクロ) +// ロードストアユニットの align の処理。 +// 正常な場合は addr を更新する可能性がある。 +// 例外の場合は例外を処理してこのマクロが展開されてる関数から return する。 #define LDST_ALIGN(size) do { \ - if (ldst_align(size, addr) == false) \ - return; \ + if ((addr & (size - 1)) != 0) { \ + if (IsMXM()) { \ + addr &= ~(size - 1); \ + } else { \ + InternalException(EXCVEC_MISALIGNED); \ + return; \ + } \ + } \ } while (0) // ロードストアユニットのまとめたもの @@ -254,6 +200,18 @@ m88kcpu::ldst_align(uint32 size, uint32& LDST_ALIGN(size); \ } while (0) +// .usr 開始。 +#define ENTER_USR() do { \ + if (__predict_false(usr)) \ + cmmu[1]->SetSuper(false); \ +} while (0) + +// .usr 終了。 +#define LEAVE_USR() do { \ + if (__predict_false(usr)) \ + cmmu[1]->SetSuper(true); \ +} while (0) + // 幅規制付き算術左シフト static inline uint32 ASL(uint32 a, int n) @@ -271,7 +229,7 @@ ASR(uint32 a, int n) { if (n <= 0) return a; - if (n >= 32) + if (n >= 31) return (int32)a < 0 ? -1 : 0; // XXX: 負数の右シフト return (int32)a >> n; @@ -288,20 +246,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) @@ -316,11 +260,11 @@ isovf_sub(uint32 s1, uint32 s2, uint32 r } // bcnd のやつ -static inline int +static inline uint acc_cnd(uint32 r) { - int rv; - if (r & 0x80000000) { + uint rv; + if ((r & 0x80000000) != 0) { if (r == 0x80000000) { rv = 0x8; } else { @@ -342,20 +286,30 @@ acc_bf(int w, int ofs) { uint32 m; if (w == 0) { - m = 0xFFFFFFFFU; + m = 0xffffffffU; } else { - m = ~(0xFFFFFFFFU << w); + m = ~(0xffffffffU << w); } 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 OP_DEF(xmem_bu_imm) { uint32 addr; - uint64 tmp; + busdata data; addr = rS1 + IMM16; LDST_ALIGN(1); @@ -363,21 +317,21 @@ OP_DEF(xmem_bu_imm) AddCycle(4); // Table.7-3 lastaddr = addr; - tmp = cmmu[1].xmem_8(addr, rD & 0xff); - if ((int64)tmp < 0) { - XmemDataException(addr, DM_BU | DM_LOCK); + data = cmmu[1]->xmem_1(addr, rD & 0xff); + if (__predict_false(data.IsBusErr())) { + XmemDataException(addr, DM_BU); return; } if (FLD_D == 0) return; - rD = tmp; + rD = data.Data(); } // 000001_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(xmem_w_imm) { uint32 addr; - uint64 tmp; + busdata data; addr = rS1 + IMM16; LDST_ALIGN(4); @@ -385,21 +339,21 @@ OP_DEF(xmem_w_imm) AddCycle(4); // Table.7-3 lastaddr = addr; - tmp = cmmu[1].xmem_32(addr, rD); - if ((int64)tmp < 0) { - XmemDataException(addr, DM_W | DM_LOCK); + data = cmmu[1]->xmem_4(addr, rD); + if (__predict_false(data.IsBusErr())) { + XmemDataException(addr, DM_W); return; } if (FLD_D == 0) return; - rD = tmp; + rD = data.Data(); } // 000010_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(ld_hu_imm) { uint32 addr; - uint64 data; + busdata data; addr = rS1 + IMM16; LDST_ALIGN(2); @@ -407,21 +361,21 @@ OP_DEF(ld_hu_imm) AddCycle(3); // Table.7-3 lastaddr = addr; - data = cmmu[1].load_16(addr); - if ((int64)data < 0) { + data = cmmu[1]->load_2(addr); + if (__predict_false(data.IsBusErr())) { ReadDataException32(addr, DM_HU); return; } if (FLD_D == 0) return; - rD = data; + rD = data.Data(); } // 000011_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(ld_bu_imm) { uint32 addr; - uint64 data; + busdata data; addr = rS1 + IMM16; LDST_ALIGN(1); @@ -429,21 +383,21 @@ OP_DEF(ld_bu_imm) AddCycle(3); // Table.7-3 lastaddr = addr; - data = cmmu[1].load_8(addr); - if ((int64)data < 0) { + data = cmmu[1]->load_1(addr); + if (__predict_false(data.IsBusErr())) { ReadDataException32(addr, DM_BU); return; } if (FLD_D == 0) return; - rD = data; + rD = data.Data(); } // 000100_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(ld_d_imm) { - uint32 addr; - uint64 data1, data2; + uint32 addr; // ReadDataException64() に渡すのは常に先頭アドレス。 + busdata data; addr = rS1 + IMM16; LDST_ALIGN(8); @@ -451,28 +405,32 @@ OP_DEF(ld_d_imm) AddCycle(4); // Table.7-3 lastaddr = addr; - data1 = cmmu[1].load_32(addr); - if ((int64)data1 < 0) { + + data = cmmu[1]->load_4(addr); + if (__predict_false(data.IsBusErr())) { ReadDataException64(addr, DM_D1); return; } - addr += 4; - data2 = cmmu[1].load_32(addr); - if ((int64)data2 < 0) { + if (__predict_true(FLD_D != 0)) { + rD = data.Data(); + } + + data = cmmu[1]->load_4(addr + 4); + if (__predict_false(data.IsBusErr())) { ReadDataException64(addr, DM_D2); return; } - rD = data1; - rD2 = data2; - r[0] = 0; + if (__predict_true(FLD_D2 != 0)) { + rD2 = data.Data(); + } } // 000101_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(ld_w_imm) { uint32 addr; - uint64 data; + busdata data; addr = rS1 + IMM16; LDST_ALIGN(4); @@ -480,21 +438,21 @@ OP_DEF(ld_w_imm) AddCycle(3); // Table.7-3 lastaddr = addr; - data = cmmu[1].load_32(addr); - if ((int64)data < 0) { + data = cmmu[1]->load_4(addr); + if (__predict_false(data.IsBusErr())) { ReadDataException32(addr, DM_W); return; } if (FLD_D == 0) return; - rD = data; + rD = data.Data(); } // 000110_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(ld_h_imm) { uint32 addr; - uint64 data; + busdata data; addr = rS1 + IMM16; LDST_ALIGN(2); @@ -502,21 +460,21 @@ OP_DEF(ld_h_imm) AddCycle(3); // Table.7-3 lastaddr = addr; - data = cmmu[1].load_16(addr); - if ((int64)data < 0) { + data = cmmu[1]->load_2(addr); + if (__predict_false(data.IsBusErr())) { ReadDataException32(addr, DM_H); return; } if (FLD_D == 0) return; - rD = (uint32)(int32)(int16)data; + rD = (uint32)(int32)(int16)data.Data(); } // 000111_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(ld_b_imm) { uint32 addr; - uint64 data; + busdata data; addr = rS1 + IMM16; LDST_ALIGN(1); @@ -524,21 +482,21 @@ OP_DEF(ld_b_imm) AddCycle(3); // Table.7-3 lastaddr = addr; - data = cmmu[1].load_8(addr); - if ((int64)data < 0) { + data = cmmu[1]->load_1(addr); + if (__predict_false(data.IsBusErr())) { ReadDataException32(addr, DM_B); return; } if (FLD_D == 0) return; - rD = (uint32)(int32)(int8)data; + rD = (uint32)(int32)(int8)data.Data(); } // 001000_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(st_d_imm) { - uint32 addr; - uint64 rv; + uint32 addr; // WriteDataException64() に渡すのは常に先頭アドレス。 + busdata r; addr = rS1 + IMM16; LDST_ALIGN(8); @@ -546,14 +504,15 @@ OP_DEF(st_d_imm) AddCycle(1 + 4); // Table.7-3 lastaddr = addr; - rv = cmmu[1].store_32(addr, rD); - if ((int64)rv < 0) { + + r = cmmu[1]->store_4(addr, rD); + if (__predict_false(r.IsBusErr())) { WriteDataException64(addr, DM_D1); return; } - addr += 4; - rv = cmmu[1].store_32(addr, rD2); - if ((int64)rv < 0) { + + r = cmmu[1]->store_4(addr + 4, rD2); + if (__predict_false(r.IsBusErr())) { WriteDataException64(addr, DM_D2); return; } @@ -563,7 +522,7 @@ OP_DEF(st_d_imm) OP_DEF(st_w_imm) { uint32 addr; - uint64 rv; + busdata r; addr = rS1 + IMM16; LDST_ALIGN(4); @@ -571,8 +530,8 @@ OP_DEF(st_w_imm) AddCycle(3); // Table.7-3 lastaddr = addr; - rv = cmmu[1].store_32(addr, rD); - if ((int64)rv < 0) { + r = cmmu[1]->store_4(addr, rD); + if (__predict_false(r.IsBusErr())) { WriteDataException32(addr, DM_W); return; } @@ -582,7 +541,7 @@ OP_DEF(st_w_imm) OP_DEF(st_h_imm) { uint32 addr; - uint64 rv; + busdata r; addr = rS1 + IMM16; LDST_ALIGN(2); @@ -590,8 +549,8 @@ OP_DEF(st_h_imm) AddCycle(3); // Table.7-3 lastaddr = addr; - rv = cmmu[1].store_16(addr, rD & 0xffff); - if ((int64)rv < 0) { + r = cmmu[1]->store_2(addr, rD & 0xffff); + if (__predict_false(r.IsBusErr())) { WriteDataException32(addr, DM_H); return; } @@ -601,7 +560,7 @@ OP_DEF(st_h_imm) OP_DEF(st_b_imm) { uint32 addr; - uint64 rv; + busdata r; addr = rS1 + IMM16; LDST_ALIGN(1); @@ -609,8 +568,8 @@ OP_DEF(st_b_imm) AddCycle(3); // Table.7-3 lastaddr = addr; - rv = cmmu[1].store_8(addr, rD & 0xff); - if ((int64)rv < 0) { + r = cmmu[1]->store_1(addr, rD & 0xff); + if (__predict_false(r.IsBusErr())) { WriteDataException32(addr, DM_B); return; } @@ -731,15 +690,12 @@ OP_DEF(subu_imm) // 011010_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(divu_imm) { - if (!IsFPUEnable()) { - fpu_unimpl(); - return; - } + CHECK_FPU; AddCycle(38); // Table.7-6 (ただしざっくり) if (IMM16 == 0) { - Exception(M88K_EXCEP_INT_DIV); + InternalException(EXCVEC_INT_DIV); return; } if (FLD_D == 0) @@ -750,10 +706,7 @@ OP_DEF(divu_imm) // 011011_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(mul_imm) { - if (!IsFPUEnable()) { - fpu_unimpl(); - return; - } + CHECK_FPU; AddCycle(4); // Table.7-6 (ただしざっくり) @@ -768,7 +721,7 @@ OP_DEF(add_imm) uint32 imm = IMM16; uint32 res = rS1 + imm; if (isovf_add(rS1, imm, res)) { - Exception(M88K_EXCEP_INT_OVF); + InternalException(EXCVEC_INT_OVF); return; } if (FLD_D == 0) @@ -782,7 +735,7 @@ OP_DEF(sub_imm) uint32 imm = IMM16; uint32 res = rS1 - imm; if (isovf_sub(rS1, imm, res)) { - Exception(M88K_EXCEP_INT_OVF); + InternalException(EXCVEC_INT_OVF); return; } if (FLD_D == 0) @@ -793,15 +746,12 @@ OP_DEF(sub_imm) // 011110_DDDDDSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(div_imm) { - if (!IsFPUEnable()) { - fpu_unimpl(); - return; - } + CHECK_FPU; AddCycle(38); // Table.7-6 (ただしざっくり) if ((int32)rS1 < 0 || IMM16 == 0) { - Exception(M88K_EXCEP_INT_DIV); + InternalException(EXCVEC_INT_DIV); return; } if (FLD_D == 0) @@ -820,19 +770,20 @@ OP_DEF(cmp_imm) // 100000_DDDDDzzzzz_01000n_nnnnnzzzzz OP_DEF(ldcr) { - if (IsUser()) { - Exception(M88K_EXCEP_PRIV); + if (__predict_false(IsUser())) { + Exception(EXCPRI_PRIV); return; } - if (FLD_CR > countof(cr)) { - // 88100 undocumented, - // 88110 compatible - Exception(M88K_EXCEP_UNIMPL_OP); + if (FLD_CR > countof(reg.cr)) { + // 制御レジスタ番号が範囲外の時は + // 88100 では undocumented、 + // 88110 では Unimplemented Opcode 例外。 + Exception(EXCPRI_UNIMPL_OP); return; } if (FLD_D == 0) return; - rD = cr[FLD_CR]; + rD = reg.cr[FLD_CR]; } // 100000_DDDDDzzzzz_01001n_nnnnnzzzzz @@ -840,47 +791,54 @@ OP_DEF(fldcr) { int n = FLD_CR; - if (IsUser()) { - // fcr62, 63 はユーザモードでアクセスできる - // それ以外はスーパバイザ用。 - if (n < 62) { - Exception(M88K_EXCEP_PRIV); - return; - } - } - - if (8 < n && n < 62) { - // 未実装 FCR - // 88100 undocumented, - // 88110 compatible - Exception(M88K_EXCEP_UNIMPL_OP); - 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 - // fcr は 62,63 の配置に細工がしてある if (n >= 62) { n = n - 62 + 9; + } else { + if (__predict_false(IsUser())) { + FPPreciseException(FPECR_FPRV); + return; + } + if (n > 8) { + rD = 0; + return; + } } if (FLD_D == 0) return; - rD = fcr[n]; + + // XXX 内部がバグってなければ読み出す時にマスクする必要はないが、一応 + rD = reg.fcr[n] & reg.fcr_mask[n]; } // 100000_zzzzzSSSSS_10000n_nnnnnsssss OP_DEF(stcr) { - if (IsUser()) { - Exception(M88K_EXCEP_PRIV); + if (__predict_false(IsUser())) { + Exception(EXCPRI_PRIV); return; } - if (FLD_CR > countof(cr)) { - // 88100 undocumented, - // 88110 unimpl_op - Exception(M88K_EXCEP_UNIMPL_OP); + + uint n = FLD_CR; + if (n > countof(reg.cr)) { + // 制御レジスタ番号が範囲外の時は + // 88100 では undocumented、 + // 88110 では Unimplemented Opcode 例外。 + Exception(EXCPRI_UNIMPL_OP); return; } - cr[FLD_CR] = rS1; - if (FLD_CR == 1) { + // PID, SXIP は Read Only。 + if (__predict_true(n != 0 && n != 4)) { + reg.cr[n] = rS1; + } + if (n == 1) { SetPSR(); } } @@ -890,27 +848,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 (__predict_false(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; - } + reg.fcr[n] = rS1 & reg.fcr_mask[n]; - // fcr は 62,63 の配置に細工がしてある - if (n >= 62) { - n = n - 62 + 9; + // FPCR が変更されたら、ホストの丸めモードも更新 + if (n == 10) { + uint32 rm = (reg.fpcr >> 14) & 3; + std::fesetround(rm_to_round[rm]); } - fcr[n] = rS1; } // 100000_DDDDDSSSSS_11000n_nnnnnsssss @@ -918,66 +883,81 @@ OP_DEF(xcr) { uint32 tmp; - if (IsUser()) { - Exception(M88K_EXCEP_PRIV); + if (__predict_false(IsUser())) { + Exception(EXCPRI_PRIV); return; } - if (FLD_CR > countof(cr)) { - // 88100 undocumented, - // 88110 unimpl_op - Exception(M88K_EXCEP_UNIMPL_OP); + + uint n = FLD_CR; + if (n > countof(reg.cr)) { + // 制御レジスタ番号が範囲外の時は + // 88100 では undocumented、 + // 88110 では Unimplemented Opcode 例外。 + Exception(EXCPRI_UNIMPL_OP); return; } tmp = rS1; - rD = cr[FLD_CR]; - cr[FLD_CR] = tmp; - if (FLD_CR == 1) { + rD = reg.cr[n]; + // PID, SXIP は Read Only。 + if (__predict_true(n != 0 && n != 4)) { + reg.cr[n] = tmp; + } + reg.r[0] = 0; + if (n == 1) { SetPSR(); } - r[0] = 0; } // 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 (__predict_false(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 = reg.fcr[n] & reg.fcr_mask[n]; + reg.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; - r[0] = 0; + + exchange: + uint32 tmp = rS1; + rD = reg.fcr[n] & reg.fcr_mask[n]; + reg.fcr[n] = tmp & reg.fcr_mask[n]; + + reg.r[0] = 0; } // 100001_DDDDDSSSSS_00000n_nnnnnsssss OP_DEF(fmul) { - // 暫定 double s1; double s2; + CHECK_FPU; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } @@ -989,25 +969,25 @@ OP_DEF(fmul) // 100001_DDDDD00000_001000_000nnsssss OP_DEF(flt) { - // 暫定 + CHECK_FPU; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } - FP_SET(FP_TD, FLD_D, (double)rS2); + FP_SET(FP_TD, FLD_D, (double)(int32)rS2); } // 100001_DDDDDSSSSS_00101n_nnnnnsssss OP_DEF(fadd) { - // 暫定 double s1; double s2; + CHECK_FPU; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } @@ -1019,12 +999,12 @@ OP_DEF(fadd) // 100001_DDDDDSSSSS_00110n_nnnnnsssss OP_DEF(fsub) { - // 暫定 double s1; double s2; + CHECK_FPU; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } @@ -1036,91 +1016,124 @@ OP_DEF(fsub) // 100001_DDDDDSSSSS_00111n_nnnnnsssss OP_DEF(fcmp) { - // 暫定 double s1; double s2; + CHECK_FPU; 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 || s1 >= s2) res |= 0x0800; // ob + if (0 < s1 && s1 < s2) res |= 0x0400; // in + if (0 <= s1 && s1 <= s2) res |= 0x0200; // ib + if (s1 < 0 || s1 > s2) 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 +MPU88xx0Device::ops_int(int rndmode) +{ + double src; + double res; + int exponent; + CHECK_FPU; 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 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; + int saved_rndmode = std::fegetround(); + + 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 OP_DEF(fdiv) { - // 暫定 double s1; double s2; + CHECK_FPU; if (FLD_D == 0) { - FPException(M88K_FPEXCEP_FUNIMP); + FPPreciseException(FPECR_FUNIMP); return; } @@ -1133,90 +1146,80 @@ OP_DEF(fdiv) OP_DEF(br) { AddCycle(1); // Table.7-5 - EnterBranch(xip + D26); - ExitBranch(); + DoBranch(reg.xip + D26, false); } // 110001_nnnnnnnnnn_nnnnnn_nnnnnnnnnn OP_DEF(br_n) { AddCycle(0); // Table.7-5 - EnterBranch(xip + D26); - ExitDelayBranch(); + DoBranch(reg.xip + D26, true); } // 110010_nnnnnnnnnn_nnnnnn_nnnnnnnnnn OP_DEF(bsr) { AddCycle(1); // Table.7-5 - EnterBranch(xip + D26); - r[1] = nip; - ExitBranch(); + reg.r[1] = reg.nip; + DoBranch(reg.xip + D26, false); } // 110011_nnnnnnnnnn_nnnnnn_nnnnnnnnnn OP_DEF(bsr_n) { AddCycle(0); // Table.7-5 - EnterBranch(xip + D26); - r[1] = nip + 4; - ExitDelayBranch(); + reg.r[1] = reg.nip + 4; + DoBranch(reg.xip + D26, true); } // 110100_nnnnnSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(bb0) { - if ((rS1 & (1 << B5)) == 0) { + if ((rS1 & (1U << B5)) == 0) { AddCycle(1); // Table.7-5 - EnterBranch(xip + D16); - ExitBranch(); + DoBranch(reg.xip + D16, false); } } // 110101_nnnnnSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(bb0_n) { - if ((rS1 & (1 << B5)) == 0) { - EnterBranch(xip + D16); - ExitDelayBranch(); + if ((rS1 & (1U << B5)) == 0) { + DoBranch(reg.xip + D16, true); } } // 110110_nnnnnSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(bb1) { - if ((rS1 & (1 << B5)) != 0) { + if ((rS1 & (1U << B5)) != 0) { AddCycle(1); // Table.7-5 - EnterBranch(xip + D16); - ExitBranch(); + DoBranch(reg.xip + D16, false); } } // 110111_nnnnnSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(bb1_n) { - if ((rS1 & (1 << B5)) != 0) { - EnterBranch(xip + D16); - ExitDelayBranch(); + if ((rS1 & (1U << B5)) != 0) { + DoBranch(reg.xip + D16, true); } } // 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(); + DoBranch(reg.xip + D16, false); } } // 111011_MMMMMSSSSS_nnnnnn_nnnnnnnnnn OP_DEF(bcnd_n) { - if (acc_cnd(rS1) & M5) { - EnterBranch(xip + D16); - ExitDelayBranch(); + if ((acc_cnd(rS1) & M5) != 0) { + DoBranch(reg.xip + D16, true); } } @@ -1240,7 +1243,7 @@ OP_DEF(set_1) OP_DEF(ext_1) { int w, o, left; - uint32 tmp; + uint32 res; if (FLD_D == 0) return; @@ -1249,16 +1252,16 @@ OP_DEF(ext_1) w = 32; o = O5; left = 32 - w - o; - tmp = ASL(rS1, left); - tmp = ASR(tmp, left); - rD = ASR(tmp, o); + res = ASL(rS1, left); + res = ASR(res, left); + rD = ASR(res, o); } // 111100_DDDDDSSSSS_100110_wwwwwooooo OP_DEF(extu_1) { int w, o, left; - uint32 tmp; + uint32 res; if (FLD_D == 0) return; @@ -1267,9 +1270,9 @@ OP_DEF(extu_1) w = 32; o = O5; left = 32 - w - o; - tmp = ASL(rS1, left); - tmp = LSR(tmp, left); - rD = tmp >> o; + res = ASL(rS1, left); + res = LSR(res, left); + rD = res >> o; } // 111100_DDDDDSSSSS_101000_wwwwwooooo @@ -1285,18 +1288,18 @@ OP_DEF(rot_1) { if (FLD_D == 0) return; - rD = ROR(rS1, O5); + rD = ROR32(rS1, O5); } // 111100_bbbbbSSSSS_110100_0vvvvvvvvv OP_DEF(tb0) { if (IsUser() && VEC9 < 128) { - Exception(M88K_EXCEP_PRIV); + Exception(EXCPRI_PRIV); return; } - if ((rS1 & (1 << B5)) == 0) { - ExceptionCore(VEC9, ExceptionKind::TRAP); + if ((rS1 & (1U << B5)) == 0) { + TrapException(VEC9); } } @@ -1304,11 +1307,11 @@ OP_DEF(tb0) OP_DEF(tb1) { if (IsUser() && VEC9 < 128) { - Exception(M88K_EXCEP_PRIV); + Exception(EXCPRI_PRIV); return; } - if ((rS1 & (1 << B5)) != 0) { - ExceptionCore(VEC9, ExceptionKind::TRAP); + if ((rS1 & (1U << B5)) != 0) { + TrapException(VEC9); } else if (pseudo_stop_enable) { // OpenBSD の STOP エミュレーション。 @@ -1329,9 +1332,9 @@ OP_DEF(tb1) if (IsSuper() && VEC9 == 0xff) { const auto& e = brhist.entry[brhist.top]; if (e.count == 3 - && e.to == xip + && e.to == reg.xip && e.from - e.to < 16) { - atomic_reqflag |= CPU_REQ_STOP; + ChangeState(CPU_STATE_STOP); } } } @@ -1341,18 +1344,18 @@ OP_DEF(tb1) OP_DEF(tcnd) { if (IsUser() && VEC9 < 128) { - Exception(M88K_EXCEP_PRIV); + Exception(EXCPRI_PRIV); return; } - if (acc_cnd(rS1) & M5) { - ExceptionCore(VEC9, ExceptionKind::TRAP); + if ((acc_cnd(rS1) & M5) != 0) { + TrapException(VEC9); } } // 111101_DDDDDSSSSS_000000_xU000sssss OP_DEF(xmem_bu) { - uint64 tmp; + busdata data; uint32 addr; uint32 usr; @@ -1363,22 +1366,23 @@ OP_DEF(xmem_bu) lastaddr = addr; // 例外安全のために都度 S/U ビットを制御 - if (__predict_false(usr)) cmmu[1].SetSuper(false); - tmp = cmmu[1].xmem_8(addr, rD & 0xff); - if (__predict_false(usr)) cmmu[1].SetSuper(true); - if ((int64)tmp < 0) { - XmemDataException(addr, DM_BU | DM_LOCK | usr); + ENTER_USR(); + data = cmmu[1]->xmem_1(addr, rD & 0xff); + LEAVE_USR(); + + if (__predict_false(data.IsBusErr())) { + XmemDataException(addr, DM_BU | usr); return; } if (FLD_D == 0) return; - rD = tmp; + rD = data.Data(); } // 111101_DDDDDSSSSS_000001_xU000sssss OP_DEF(xmem_w) { - uint64 tmp; + busdata data; uint32 addr; uint32 usr; @@ -1389,23 +1393,24 @@ OP_DEF(xmem_w) lastaddr = addr; // 例外安全のために都度 S/U ビットを制御 - if (__predict_false(usr)) cmmu[1].SetSuper(false); - tmp = cmmu[1].xmem_32(addr, rD); - if (__predict_false(usr)) cmmu[1].SetSuper(true); - if ((int64)tmp < 0) { - XmemDataException(addr, DM_W | DM_LOCK | usr); + ENTER_USR(); + data = cmmu[1]->xmem_4(addr, rD); + LEAVE_USR(); + + if (__predict_false(data.IsBusErr())) { + XmemDataException(addr, DM_W | usr); return; } if (FLD_D == 0) return; - rD = tmp; + rD = data.Data(); } // 111101_DDDDDSSSSS_000010_xU000sssss OP_DEF(ld_hu) { - uint64 data; + busdata data; uint32 addr; uint32 usr; @@ -1415,24 +1420,24 @@ OP_DEF(ld_hu) lastaddr = addr; - if (__predict_false(usr)) cmmu[1].SetSuper(false); - data = cmmu[1].load_16(addr); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + data = cmmu[1]->load_2(addr); + LEAVE_USR(); - if ((int64)data < 0) { + if (__predict_false(data.IsBusErr())) { ReadDataException32(addr, DM_HU | usr); return; } if (FLD_D == 0) return; - rD = data; + rD = data.Data(); } // 111101_DDDDDSSSSS_000011_xU000sssss OP_DEF(ld_bu) { - uint64 data; uint32 addr; + busdata data; uint32 usr; LDST_USR_SCALE_ALIGN(1); @@ -1441,24 +1446,24 @@ OP_DEF(ld_bu) lastaddr = addr; - if (__predict_false(usr)) cmmu[1].SetSuper(false); - data = cmmu[1].load_8(addr); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + data = cmmu[1]->load_1(addr); + LEAVE_USR(); - if ((int64)data < 0) { + if (__predict_false(data.IsBusErr())) { ReadDataException32(addr, DM_BU | usr); return; } if (FLD_D == 0) return; - rD = data; + rD = data.Data(); } // 111101_DDDDDSSSSS_000100_xU000sssss OP_DEF(ld_d) { - uint64 data1, data2; - uint32 addr; + uint32 addr; // ReadDataException64() に渡すのは常に先頭アドレス。 + busdata data; uint32 usr; LDST_USR_SCALE_ALIGN(8); @@ -1468,34 +1473,36 @@ OP_DEF(ld_d) lastaddr = addr; // 例外安全のために都度 S/U ビットを制御 - if (__predict_false(usr)) cmmu[1].SetSuper(false); - data1 = cmmu[1].load_32(addr); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + data = cmmu[1]->load_4(addr); + LEAVE_USR(); - if ((int64)data1 < 0) { + if (__predict_false(data.IsBusErr())) { ReadDataException64(addr, DM_D1 | usr); return; } - addr += 4; + if (__predict_true(FLD_D != 0)) { + rD = data.Data(); + } - if (__predict_false(usr)) cmmu[1].SetSuper(false); - data2 = cmmu[1].load_32(addr); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + data = cmmu[1]->load_4(addr + 4); + LEAVE_USR(); - if ((int64)data2 < 0) { + if (__predict_false(data.IsBusErr())) { ReadDataException64(addr, DM_D2 | usr); return; } - rD = data1; - rD2 = data2; - r[0] = 0; + if (__predict_true(FLD_D2 != 0)) { + rD2 = data.Data(); + } } // 111101_DDDDDSSSSS_000101_xU000sssss OP_DEF(ld_w) { - uint64 data; uint32 addr; + busdata data; uint32 usr; LDST_USR_SCALE_ALIGN(4); @@ -1504,9 +1511,9 @@ OP_DEF(ld_w) lastaddr = addr; - if (__predict_false(usr)) cmmu[1].SetSuper(false); - data = cmmu[1].load_32(addr); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + data = cmmu[1]->load_4(addr); + LEAVE_USR(); if ((int64)data < 0) { ReadDataException32(addr, DM_W | usr); @@ -1520,8 +1527,8 @@ OP_DEF(ld_w) // 111101_DDDDDSSSSS_000110_xU000sssss OP_DEF(ld_h) { - uint64 data; uint32 addr; + busdata data; uint32 usr; LDST_USR_SCALE_ALIGN(2); @@ -1530,24 +1537,24 @@ OP_DEF(ld_h) lastaddr = addr; - if (__predict_false(usr)) cmmu[1].SetSuper(false); - data = cmmu[1].load_16(addr); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + data = cmmu[1]->load_2(addr); + LEAVE_USR(); - if ((int64)data < 0) { + if (__predict_false(data.IsBusErr())) { ReadDataException32(addr, DM_H | usr); return; } if (FLD_D == 0) return; - rD = (uint32)(int32)(int16)data; + rD = (uint32)(int32)(int16)data.Data(); } // 111101_DDDDDSSSSS_000111_xU000sssss OP_DEF(ld_b) { - uint64 data; uint32 addr; + busdata data; uint32 usr; LDST_USR_SCALE_ALIGN(1); @@ -1556,24 +1563,24 @@ OP_DEF(ld_b) lastaddr = addr; - if (__predict_false(usr)) cmmu[1].SetSuper(false); - data = cmmu[1].load_8(addr); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + data = cmmu[1]->load_1(addr); + LEAVE_USR(); - if ((int64)data < 0) { + if (__predict_false(data.IsBusErr())) { ReadDataException32(addr, DM_B | usr); return; } if (FLD_D == 0) return; - rD = (uint32)(int32)(int8)data; + rD = (uint32)(int32)(int8)data.Data(); } // 111101_DDDDDSSSSS_001000_xU000sssss OP_DEF(st_d) { - uint64 rv; - uint32 addr; + uint32 addr; // WriteDataException64() に渡すのは常に先頭アドレス。 + busdata r; uint32 usr; LDST_USR_SCALE_ALIGN(8); @@ -1582,22 +1589,20 @@ OP_DEF(st_d) lastaddr = addr; - if (__predict_false(usr)) cmmu[1].SetSuper(false); - rv = cmmu[1].store_32(addr, rD); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + r = cmmu[1]->store_4(addr, rD); + LEAVE_USR(); - if ((int64)rv < 0) { + if (__predict_false(r.IsBusErr())) { WriteDataException64(addr, DM_D1 | usr); return; } - addr += 4; + ENTER_USR(); + r = cmmu[1]->store_4(addr + 4, rD2); + LEAVE_USR(); - if (__predict_false(usr)) cmmu[1].SetSuper(false); - rv = cmmu[1].store_32(addr, rD2); - if (__predict_false(usr)) cmmu[1].SetSuper(true); - - if ((int64)rv < 0) { + if (__predict_false(r.IsBusErr())) { WriteDataException64(addr, DM_D2 | usr); return; } @@ -1606,8 +1611,8 @@ OP_DEF(st_d) // 111101_DDDDDSSSSS_001001_xU000sssss OP_DEF(st_w) { - uint64 rv; uint32 addr; + busdata r; uint32 usr; LDST_USR_SCALE_ALIGN(4); @@ -1616,11 +1621,11 @@ OP_DEF(st_w) lastaddr = addr; - if (__predict_false(usr)) cmmu[1].SetSuper(false); - rv = cmmu[1].store_32(addr, rD); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + r = cmmu[1]->store_4(addr, rD); + LEAVE_USR(); - if ((int64)rv < 0) { + if (__predict_false(r.IsBusErr())) { WriteDataException32(addr, DM_W | usr); return; } @@ -1629,8 +1634,8 @@ OP_DEF(st_w) // 111101_DDDDDSSSSS_001010_xU000sssss OP_DEF(st_h) { - uint64 rv; uint32 addr; + busdata r; uint32 usr; LDST_USR_SCALE_ALIGN(2); @@ -1639,11 +1644,11 @@ OP_DEF(st_h) lastaddr = addr; - if (__predict_false(usr)) cmmu[1].SetSuper(false); - rv = cmmu[1].store_16(addr, rD & 0xffff); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + r = cmmu[1]->store_2(addr, rD & 0xffff); + LEAVE_USR(); - if ((int64)rv < 0) { + if (__predict_false(r.IsBusErr())) { WriteDataException32(addr, DM_H | usr); return; } @@ -1652,8 +1657,8 @@ OP_DEF(st_h) // 111101_DDDDDSSSSS_001011_xU000sssss OP_DEF(st_b) { - uint64 rv; uint32 addr; + busdata r; uint32 usr; LDST_USR_SCALE_ALIGN(1); @@ -1662,11 +1667,11 @@ OP_DEF(st_b) lastaddr = addr; - if (__predict_false(usr)) cmmu[1].SetSuper(false); - rv = cmmu[1].store_8(addr, rD & 0xff); - if (__predict_false(usr)) cmmu[1].SetSuper(true); + ENTER_USR(); + r = cmmu[1]->store_1(addr, rD & 0xff); + LEAVE_USR(); - if ((int64)rv < 0) { + if (__predict_false(r.IsBusErr())) { WriteDataException32(addr, DM_B | usr); return; } @@ -1792,8 +1797,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); @@ -1813,15 +1817,12 @@ OP_DEF(subu) // 111101_DDDDDSSSSS_011010_zz000sssss OP_DEF(divu) { - if (!IsFPUEnable()) { - fpu_unimpl(); - return; - } + CHECK_FPU; AddCycle(38); // Table.7-6 (ただしざっくり) if (rS2 == 0) { - Exception(M88K_EXCEP_INT_DIV); + InternalException(EXCVEC_INT_DIV); return; } if (FLD_D == 0) @@ -1832,10 +1833,7 @@ OP_DEF(divu) // 111101_DDDDDSSSSS_011011_zz000sssss OP_DEF(mul) { - if (!IsFPUEnable()) { - fpu_unimpl(); - return; - } + CHECK_FPU; AddCycle(4); // Table.7-6 (ただしざっくり) @@ -1851,15 +1849,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); + InternalException(EXCVEC_INT_OVF); return; } + + // rD, Cy の更新は例外が起きなかった時だけ (p.6-19) + if (IsCO) { + SetCY(res >> 32); + } if (FLD_D == 0) return; rD = res; @@ -1868,8 +1866,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 +1875,15 @@ OP_DEF(sub) } else { res += 1; } - // XXX: オーバーフローが起きたときにキャリーが更新されるかどうか - // ドキュメントされてない気がする - if (IsCO) { - SetCY(res >> 32); - } if (isovf_sub(rS1, rS2, res)) { - Exception(M88K_EXCEP_INT_OVF); + InternalException(EXCVEC_INT_OVF); return; } + + // rD, Cy の更新は例外が起きなかった時だけ (p.6-19) + if (IsCO) { + SetCY(res >> 32); + } if (FLD_D == 0) return; rD = res; @@ -1895,15 +1892,12 @@ OP_DEF(sub) // 111101_DDDDDSSSSS_011110_zz000sssss OP_DEF(div) { - if (!IsFPUEnable()) { - fpu_unimpl(); - return; - } + CHECK_FPU; AddCycle(38); // Table.7-6 (ただしざっくり) if ((int32)rS1 < 0 || (int32)rS2 <= 0) { - Exception(M88K_EXCEP_INT_DIV); + InternalException(EXCVEC_INT_DIV); return; } if (FLD_D == 0) @@ -1939,7 +1933,7 @@ OP_DEF(set_2) OP_DEF(ext_2) { int w, o, left; - uint32 tmp; + uint32 res; if (FLD_D == 0) return; @@ -1948,16 +1942,16 @@ OP_DEF(ext_2) w = 32; o = (rS2 ) & 0x1f; left = 32 - w - o; - tmp = ASL(rS1, left); - tmp = ASR(tmp, left); - rD = ASR(tmp, o); + res = ASL(rS1, left); + res = ASR(res, left); + rD = ASR(res, o); } // 111101_DDDDDSSSSS_100110_00000sssss OP_DEF(extu_2) { int w, o, left; - uint32 tmp; + uint32 res; if (FLD_D == 0) return; @@ -1966,9 +1960,9 @@ OP_DEF(extu_2) w = 32; o = (rS2 ) & 0x1f; left = 32 - w - o; - tmp = ASL(rS1, left); - tmp = LSR(tmp, left); - rD = tmp >> o; + res = ASL(rS1, left); + res = LSR(res, left); + rD = res >> o; } // 111101_DDDDDSSSSS_101000_00000sssss @@ -1987,41 +1981,39 @@ 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 OP_DEF(jmp) { AddCycle(1); // Table.7-5 - EnterBranch(rS2); - ExitBranch(); + DoBranch(rS2, false); } // 111101_zzzzzzzzzz_110001_00000sssss OP_DEF(jmp_n) { AddCycle(0); // Table.7-5 - EnterBranch(rS2); - ExitDelayBranch(); + DoBranch(rS2, true); } // 111101_zzzzzzzzzz_110010_00000sssss OP_DEF(jsr) { AddCycle(1); // Table.7-5 - EnterBranch(rS2); - r[1] = nip; - ExitBranch(); + uint32 toaddr = rS2; + reg.r[1] = reg.nip; + DoBranch(toaddr, false); } // 111101_zzzzzzzzzz_110011_00000sssss OP_DEF(jsr_n) { AddCycle(0); // Table.7-5 - EnterBranch(rS2); - r[1] = nip + 4; - ExitDelayBranch(); + uint32 toaddr = rS2; + reg.r[1] = reg.nip + 4; + DoBranch(toaddr, true); } // 111101_DDDDDzzzzz_111010_00000sssss @@ -2043,7 +2035,6 @@ OP_DEF(ff1) } rD = i; } - } // 111101_DDDDDzzzzz_111011_00000sssss @@ -2070,33 +2061,29 @@ OP_DEF(ff0) // 111101_zzzzzzzzzz_111111_0000000000 OP_DEF(rte) { + if (__predict_false(IsUser())) { + Exception(EXCPRI_PRIV); + return; + } + AddCycle(2); // Table.7-5 - SetPSR(epsr); + SetPSR(reg.epsr); - // LUNA88K の ROM1.2 は sxip, snip, sfip を制御してくる。 - // ROM1.2 の DAE ハンドラは、 - // sxip = INVALID - // snip = 0 (INVALID) - // sfip = original sxip - // で rte してくる。 - // CPU は sxip は評価しない。snip は 0 なので、無効として nop 扱い。 - // (実際はクロックが消費されるかも?) - // sfip が VALID なので、そこから実行を再開する。 - if (snip & SIP_V) { - EnterBranch(snip & SIP_MASK); - ExitBranch(); - fip = sfip & SIP_MASK; - } else { - EnterBranch(sfip & SIP_MASK); - ExitBranch(); + // 本当は有効な SxIP から順次パイプラインを埋めるだけで、 + // こんな条件分けになるわけではないのだが、分岐履歴とかのため。 + + if (__predict_false((reg.sfip & SIP_V) == 0)) { + // どうなる? + putlog(0, "rte: SFIP.V==0 (NOT IMPLEMENTED)"); } - // ディレイスロットにいた命令かどうかをやんわり復元する。 - // 88110 ではこの情報が E?IP に保持されているが - // 88100 にはない。 - if (nip + 4 != fip) { - ExitDelayBranch(); + if ((reg.snip & SIP_V)) { + DoBranch(reg.snip & SIP_MASK, false); + reg.fip = reg.sfip & SIP_MASK; + } else { + // PROM 1.20 の DAE ハンドラが snip の VALID を落として rte を呼ぶ。 + DoBranch(reg.sfip & SIP_MASK, false); } } @@ -2104,7 +2091,7 @@ OP_DEF(rte) OP_DEF(tbnd_1) { if (rS1 > rS2) { - Exception(M88K_EXCEP_BOUNDS); + InternalException(EXCVEC_BOUNDS); } } @@ -2112,21 +2099,32 @@ OP_DEF(tbnd_1) OP_DEF(tbnd_2) { if (rS1 > IMM16) { - Exception(M88K_EXCEP_BOUNDS); + InternalException(EXCVEC_BOUNDS); } } -// 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); }