--- nono/m680x0/m680x0fpu.cpp 2026/04/29 17:05:35 1.1.1.2 +++ nono/m680x0/m680x0fpu.cpp 2026/04/29 17:05:40 1.1.1.3 @@ -43,6 +43,7 @@ #include "mpu680x0.h" #include "m680x0disasm.h" +#include "m680x0cycle.h" #include "textscreen.h" #define SIZE_L (0) @@ -178,7 +179,7 @@ MPU680x0Device::cea_fpu(int bytes) case 2: // (An) return cea_anin(eanum(ir)); case 3: // (An)+ - CYCLE(6); + CYCLE3(cea_fpu_anpi); n = eanum(ir); save_reg_pi(n); if (bytes == 1) { @@ -190,7 +191,7 @@ MPU680x0Device::cea_fpu(int bytes) } break; case 4: // -(An) - CYCLE(6); + CYCLE3(cea_fpu_anpd); n = eanum(ir); save_reg_pd(n); if (bytes == 1) { @@ -390,7 +391,7 @@ MPU680x0Device::fpu_op_fgen_mem() fpu40.ea = 0; // ソースが Dn の場合は 5クロック減 - CYCLE(-5); + CYCLE3(fpu_src_dn); } else if (mr == 074) { // #imm switch (bytes) { case 1: @@ -470,7 +471,7 @@ MPU680x0Device::fgen(const uint32 *srcda switch (opmode) { case 0x00: // FMOVE fmove: - CYCLE(33); + CYCLE3(fmove); res = &fe.fe_f2; fpu_round_prec(&fe, res); break; @@ -489,7 +490,7 @@ MPU680x0Device::fgen(const uint32 *srcda break; case 0x04: // FSQRT fsqrt: - CYCLE(107); + CYCLE3(fsqrt); res = fpu_sqrt(&fe); fpu_round_prec(&fe, res); break; @@ -565,7 +566,7 @@ MPU680x0Device::fgen(const uint32 *srcda break; case 0x18: // FABS fabs: - CYCLE(35); + CYCLE3(fabs); fe.fe_f2.fp_sign = 0; res = &fe.fe_f2; fpu_round_prec(&fe, res); @@ -577,7 +578,7 @@ MPU680x0Device::fgen(const uint32 *srcda break; case 0x1a: // FNEG fneg: - CYCLE(35); + CYCLE3(fneg); res = &fe.fe_f2; if (!ISNAN(res)) { res->fp_sign = !res->fp_sign; @@ -606,7 +607,7 @@ MPU680x0Device::fgen(const uint32 *srcda break; case 0x20: // FDIV fdiv: - CYCLE(103); + CYCLE3(fdiv); res = fpu_div(&fe); fpu_round_prec(&fe, res); break; @@ -617,18 +618,18 @@ MPU680x0Device::fgen(const uint32 *srcda break; case 0x22: // FADD fadd: - CYCLE(51); + CYCLE3(fadd); res = fpu_add(&fe); fpu_round_prec(&fe, res); break; case 0x23: // FMUL fmul: - CYCLE(71); + CYCLE3(fmul); res = fpu_mul(&fe); fpu_round_prec(&fe, res); break; case 0x24: // FSGLDIV - CYCLE(69); + CYCLE3(fsgldiv); res = fpu_sgldiv(&fe); break; case 0x25: // FREM @@ -643,12 +644,12 @@ MPU680x0Device::fgen(const uint32 *srcda fpu_emul_fscale(&fe, ir2); return; case 0x27: // FSGLMUL - CYCLE(59); + CYCLE3(fsglmul); res = fpu_sglmul(&fe); break; case 0x28: // FSUB fsub: - CYCLE(51); + CYCLE3(fsub); res = fpu_sub(&fe); fpu_round_prec(&fe, res); break; @@ -665,12 +666,12 @@ MPU680x0Device::fgen(const uint32 *srcda fpu_round_prec(&fe, res); break; case 0x38: // FCMP - CYCLE(33); + CYCLE3(fcmp); res = fpu_cmp(&fe); discard_result = 1; break; case 0x3a: // FTST - CYCLE(33); + CYCLE3(ftst); res = &fe.fe_f2; discard_result = 1; break; @@ -821,12 +822,14 @@ MPU680x0Device::fgen040pre(uint opmode, // Denorm - etemp,DENO etemp,UNNO etemp,UNNO // Unnorm - - etemp,UNNO etemp,UNNO + // サイクル数は 68040UM.pdf p10-30 の表から適当に逆算。 + int32 stag = FPU40::TAG_NONE; switch (srcsize_id) { case SIZE_B: case SIZE_W: case SIZE_L: - CYCLE(+27); + CYCLE(+0); if (srcdata[0] == 0) { stag = FPU40::TAG_ZERO; } else { @@ -835,7 +838,7 @@ MPU680x0Device::fgen040pre(uint opmode, fpu_explode(&fe, &fe.fe_f2, FTYPE_LNG, srcdata); break; case SIZE_S: - CYCLE(+19); + CYCLE(+0); if (is_denormal_s(srcdata[0])) { // 68040UM.pdf, p9-24. Figure 9-9 (a) uint32 s = srcdata[0] & 0x8000'0000; @@ -849,7 +852,7 @@ MPU680x0Device::fgen040pre(uint opmode, fpu_explode(&fe, &fe.fe_f2, FTYPE_SNG, srcdata); break; case SIZE_D: - CYCLE(+25); + CYCLE(+0); if (is_denormal_d(srcdata)) { // 68040UM.pdf, p9-24. Figure 9-9 (b) uint32 s = srcdata[0] & 0x8000'0000; @@ -864,7 +867,7 @@ MPU680x0Device::fgen040pre(uint opmode, fpu_explode(&fe, &fe.fe_f2, FTYPE_DBL, srcdata); break; case SIZE_X: - CYCLE(+23); + CYCLE(+1); if (is_denormal_x(srcdata)) { memcpy(fpu40.etemp, srcdata, 12); stag = FPU40::TAG_DENORMAL_X; @@ -1029,11 +1032,11 @@ MPU680x0Device::fpu_op_fmove_b_mem() } if (mr < 8) { // Dn - CYCLE(100-2); + CYCLE3(fmove_i_fp_dn); reg.D[mr] &= 0xffffff00; reg.D[mr] |= (uint8)data; } else { - CYCLE(100); + CYCLE3(fmove_i_fp_mem); ea = cea_fpu(1); write_1(ea, (uint8)data); } @@ -1069,11 +1072,11 @@ MPU680x0Device::fpu_op_fmove_w_mem() } if (mr < 8) { // Dn - CYCLE(100-2); + CYCLE3(fmove_i_fp_dn); reg.D[mr] &= 0xffff0000; reg.D[mr] |= (uint16)data; } else { - CYCLE(100); + CYCLE3(fmove_i_fp_mem); ea = cea_fpu(2); write_2(ea, (uint16)data); } @@ -1104,10 +1107,10 @@ MPU680x0Device::fpu_op_fmove_l_mem() // XXX オーバーフローチェック if (mr < 8) { // Dn - CYCLE(100-2); + CYCLE3(fmove_i_fp_dn); reg.D[mr] = data; } else { - CYCLE(100); + CYCLE3(fmove_i_fp_mem); ea = cea_fpu(4); write_4(ea, data); } @@ -1143,10 +1146,10 @@ MPU680x0Device::fpu_op_fmove_s_mem() fpu_upd_excp(&fe); if (mr < 8) { // Dn - CYCLE(80-2); + CYCLE3(fmove_s_fp_dn); reg.D[mr] = data; } else { - CYCLE(80); + CYCLE3(fmove_s_fp_mem); ea = cea_fpu(4); write_4(ea, data); } @@ -1172,7 +1175,7 @@ MPU680x0Device::fpu_op_fmove_d_mem() return; } - CYCLE(86); + CYCLE3(fmove_d_fp_ea); fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum)); fpu_implode(&fe, &fe.fe_f3, FTYPE_DBL, data); @@ -1207,7 +1210,7 @@ MPU680x0Device::fpu_op_fmove_x_mem() return; } - CYCLE(72); + CYCLE3(fmove_x_fp_ea); fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum)); fpu_implode(&fe, &fe.fe_f3, FTYPE_EXT, data); @@ -1292,6 +1295,7 @@ MPU680x0Device::fpu_op_fmovem_ea2ctl() // // FMOVE #imm と FMOVEM #imm (n==1) は cache case が 1クロックだけ違う // ようだけどもう無視する。 + // 040 で複数レジスタのケースの記述が見当たらない。 // 転送するレジスタ数。 // nofpc の場合は現在の 68881 の実装では FPIAR が選択される。 @@ -1300,7 +1304,7 @@ MPU680x0Device::fpu_op_fmovem_ea2ctl() count = __builtin_popcount(reglist); if (mr < 8) { // Dn - CYCLE2(28, 31); + CYCLE3(fmovem_rn_ctl); // 対データレジスタは転送数 1 のみ有効 if (count > 1) { fpu_op_illg2(); @@ -1313,7 +1317,7 @@ MPU680x0Device::fpu_op_fmovem_ea2ctl() src[0] = reg.R[mr]; } else if (mr < 16) { // An - CYCLE2(28, 31); + CYCLE3(fmovem_rn_ctl); // 対アドレスレジスタは FPIAR のみ有効 if (reglist != 1) { fpu_op_illg2(); @@ -1326,7 +1330,7 @@ MPU680x0Device::fpu_op_fmovem_ea2ctl() src[0] = reg.R[mr]; } else if (mr < 0x3c) { // 対メモリ - CYCLE2(28, 30); + CYCLE3(fmovem_mem_ctl); CYCLE(count * 6); // EA を取得。 @@ -1351,7 +1355,7 @@ MPU680x0Device::fpu_op_fmovem_ea2ctl() return; } - CYCLE2(25, 29); + CYCLE3(fmovem_imm_ctl); CYCLE(count * 6); for (i = 0; i < count; i++) { @@ -1392,6 +1396,8 @@ MPU680x0Device::fpu_op_fmovem_ctl2ea() // FMOVE FPc,Rn 31 34 // FMOVE FPc, 33 36 // FMOVEM FPcs, 27+6n 30+6n + // + // 040 で複数レジスタのケースの記述が見当たらない。 // 転送するレジスタ数。 // nofpc の場合は現在の 68881 の実装では FPIAR が選択される。 @@ -1400,7 +1406,7 @@ MPU680x0Device::fpu_op_fmovem_ctl2ea() count = __builtin_popcount(reglist); if (mr < 8) { // Dn - CYCLE2(31, 34); + CYCLE3(fmovem_ctl_rn); // 対データレジスタは転送数は 1 のみ有効 if (count > 1) { fpu_op_illg2(); @@ -1423,7 +1429,7 @@ MPU680x0Device::fpu_op_fmovem_ctl2ea() return; } if (mr < 16) { // An - CYCLE2(31, 34); + CYCLE3(fmovem_ctl_rn); // 対アドレスレジスタは FPIAR のみ有効 if (reglist != 1) { fpu_op_illg2(); @@ -1449,7 +1455,7 @@ MPU680x0Device::fpu_op_fmovem_ctl2ea() return; } - CYCLE2(27, 30); + CYCLE3(fmovem_ctl_mem); CYCLE(count * 6); // 該当レジスタをメモリへ書き出し @@ -1502,9 +1508,9 @@ MPU680x0Device::fpu_op_fmovem_ea2reg() // ついでにここでベースサイクル数を加算。 if (dynamic) { reglist = reg.D[(reglist >> 4) & 7]; - CYCLE2(49, 52); + CYCLE3(fmovem_ea2reg_dyn); } else { - CYCLE2(35, 38); + CYCLE3(fmovem_ea2reg_sta); } // EA は最初に一度取得しておいて... @@ -1533,7 +1539,7 @@ MPU680x0Device::fpu_op_fmovem_ea2reg() } } } - CYCLE(23 * count); + CYCLE3(fmovem_ea2reg_n) * count; // 副作用上等! } // FMOVEM.X , @@ -1578,9 +1584,9 @@ MPU680x0Device::fpu_op_fmovem_reg2ea() // ついでにここでベースクロックを記録 if (dynamic) { reglist = reg.D[(reglist >> 4) & 7]; - CYCLE2(51, 54); + CYCLE3(fmovem_reg2ea_dyn); } else { - CYCLE2(37, 40); + CYCLE3(fmovem_reg2ea_sta); } int count = __builtin_popcount(reglist); @@ -1596,7 +1602,7 @@ MPU680x0Device::fpu_op_fmovem_reg2ea() // cea_fpu() は1命令中で EA の取得が1回である前提のあくまで便利関数 // なので、例外的である FMOVEM は仕方がない。 if (anpd) { - CYCLE(6); + CYCLE3(fmovem_reg2ea_anpd); uint n = eanum(ir); save_reg_pd(n); @@ -1652,7 +1658,7 @@ MPU680x0Device::fpu_op_fmovem_reg2ea() } } } - CYCLE(25 * count); + CYCLE3(fmovem_reg2ea_n) * count; // 副作用上等! } // FScc.B @@ -1689,7 +1695,7 @@ MPU680x0Device::fpu_op_fscc() switch (mm) { case 0: // Dn - CYCLE2(18, 21); + CYCLE3(fscc_dn); reg.D[rr] &= 0xffffff00; reg.D[rr] |= data; return; @@ -1699,9 +1705,9 @@ MPU680x0Device::fpu_op_fscc() // ここだけ他のメモリ系 EA とはクロックが違うし、 // 条件の成立可否でも違う。 if (data == 0x00) { - CYCLE2(21, 24); + CYCLE3(fscc_anp_z); } else { - CYCLE2(22, 25); + CYCLE3(fscc_anp_nz); } break; case 7: @@ -1712,7 +1718,7 @@ MPU680x0Device::fpu_op_fscc() } FALLTHROUGH; default: - CYCLE2(20, 23); + CYCLE3(fscc_mem); break; } @@ -1741,7 +1747,7 @@ MPU680x0Device::fpu_op_fdbcc() if (test_cc(&fe, cond) == -1) { // 真なら何もしない。disp を読み飛ばして次へ - CYCLE2(20, 24); + CYCLE3(fdbcc_true); fetch_2(); } else { // 偽の場合 @@ -1750,11 +1756,11 @@ MPU680x0Device::fpu_op_fdbcc() if (data == 0xffff) { // ループ終了。disp を読み飛ばす - CYCLE2(24, 32); + CYCLE3(fdbcc_done); fetch_2(); } else { // 計算に使う PC はディスプレースメントのあるアドレス。 - CYCLE2(20, 26); + CYCLE3(fdbcc_jump); uint32 origin = reg.pc; int32 disp = (int32)(int16)fetch_2(); Jump(origin + disp); @@ -1783,10 +1789,10 @@ MPU680x0Device::fpu_op_ftrapcc_w() fetch_2(); if (test_cc(&fe, cond) == -1) { - CYCLE2(41, 45); + CYCLE3(ftrapccw_excep); Exception(M68K::EXCEP_TRAPV); } else { - CYCLE2(20, 23); + CYCLE3(ftrapccw_nop); } } @@ -1811,10 +1817,10 @@ MPU680x0Device::fpu_op_ftrapcc_l() fetch_4(); if (test_cc(&fe, cond) == -1) { - CYCLE2(43, 52); + CYCLE3(ftrapccl_excep); Exception(M68K::EXCEP_TRAPV); } else { - CYCLE2(22, 27); + CYCLE3(ftrapccl_nop); } } @@ -1838,10 +1844,10 @@ MPU680x0Device::fpu_op_ftrapcc() // 即値なし。 if (test_cc(&fe, cond) == -1) { - CYCLE2(39, 47); + CYCLE3(ftrapcc_excep); Exception(M68K::EXCEP_TRAPV); } else { - CYCLE2(18, 22); + CYCLE3(ftrapcc_nop); } } @@ -1864,13 +1870,13 @@ MPU680x0Device::fpu_op_fbcc_w() // TODO: Illegal condition の戻り値を処理すること。他の test_cc() も同様。 if (test_cc(&fe, cond) == -1) { - CYCLE2(20, 23); + CYCLE3(fbcc_jump); uint32 origin = reg.pc; int32 disp = (int32)(int16)fetch_2(); Jump(origin + disp); } else { // disp を読み飛ばす - CYCLE2(18, 19); + CYCLE3(fbccw_nop); fetch_2(); } } @@ -1890,13 +1896,13 @@ MPU680x0Device::fpu_op_fbcc_l() uint cond = ir & 0x3f; if (test_cc(&fe, cond) == -1) { - CYCLE2(20, 23); + CYCLE3(fbcc_jump); uint32 origin = reg.pc; int32 disp = (int32)fetch_4(); Jump(origin + disp); } else { // disp を読み飛ばす - CYCLE2(18, 21); + CYCLE3(fbccl_nop); fetch_4(); } } @@ -1939,14 +1945,14 @@ MPU680x0Device::fpu_op_fsave() switch (fpu_state) { case FPU_STATE_NULL: // NULL フレーム - CYCLE2(16, 18); + CYCLE3(fsave_null); frame = fsave_frame_null; framelen = countof(fsave_frame_null); break; case FPU_STATE_IDLE: case FPU_STATE_BUSY: // 実装してないけどとりあえず。 // IDLE フレーム - CYCLE2(52, 54); // XXX これは最小値らしいけど + CYCLE3(fsave_idle); // XXX これは最小値らしいけど if (fpu_type.Is4060FPU()) { frame = fsave_frame_idle_68040; framelen = countof(fsave_frame_idle_68040); @@ -2086,13 +2092,13 @@ MPU680x0Device::fpu_op_frestore() // NULL フレーム。 // NULL フレームのリストアは FPU の状態をリセットする。 - CYCLE2(21, 22); + CYCLE3(frestore_null); ResetFPU(false); } else if (ver_len == 0x4100) { // IDLE フレーム。 // 現状何も実装していないので、状態を戻して読み捨てるだけ。 - CYCLE2(57, 58); + CYCLE3(frestore_idle); fpu_state = FPU_STATE_IDLE; } else if (ver_len == 0x4130) { // 浮動小数点未実装命令フレーム。 @@ -2117,13 +2123,13 @@ MPU680x0Device::fpu_op_frestore() // NULL フレーム。 // NULL フレームのリストアは FPU の状態をリセットする。 - CYCLE2(21, 22); + CYCLE3(frestore_null); ResetFPU(false); } else if (ver_len == 0x1f18) { // IDLE フレーム。 // 現状何も実装していないので、状態を戻して読み捨てるだけ。 - CYCLE2(57, 58); + CYCLE3(frestore_idle); fpu_state = FPU_STATE_IDLE; } else { if (ver_len == 0x1fb4) { @@ -2208,8 +2214,8 @@ MPU680x0Device::ExceptionFP(uint vector) // EXCEP_FP_UNIMPL (未実装命令例外) はベクタが F ラインと同じで、 // フレームフォーマットが違うので、定数値に細工がしてある。 - const uint32 inst = BranchHistory_m680x0::Exception | (vector & 0xff); - ExceptionGeneric(vector, inst); + const uint32 info = BranchHistory_m680x0::InfoException(vector & 0xff); + ExceptionGeneric(vector, info); } // CMDREG1B からコマンド名を返す。