|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2018 [email protected] ! 4: // ! 5: ! 6: #include "header.h" ! 7: #include "m68030core.h" ! 8: #include "m68030bus.h" ! 9: #include "m68030excep.h" ! 10: #include "m68030ea.h" ! 11: #include "m68030fpu.h" ! 12: ! 13: static void fgen(m68kcpu *); ! 14: static void fpu_op_fmovecr(m68kcpu *); ! 15: ! 16: // リセット用のレジスタ初期値 ! 17: struct fpframe initial_fpframe; ! 18: ! 19: // 初期化 ! 20: void ! 21: fpu_init(m68kcpu *cpu) ! 22: { ! 23: int i; ! 24: uint32_t *p; ! 25: ! 26: // XXX cpu の初期化のところと見直してマージするとか ! 27: memset(&cpu->fe, 0, sizeof(cpu->fe)); ! 28: memset(&cpu->reg.fpframe, 0, sizeof(cpu->reg.fpframe)); ! 29: cpu->fe.fe_fpframe = &cpu->reg.fpframe; ! 30: ! 31: // FRESTORE によるリセット用に FP レジスタの初期値を用意しておく ! 32: memset(&initial_fpframe, 0, sizeof(initial_fpframe)); ! 33: p = initial_fpframe.fpf_regs; ! 34: for (i = 0; i < 8; i++) { ! 35: *p++ = 0x7fff0000; ! 36: *p++ = 0xffffffff; ! 37: *p++ = 0xffffffff; ! 38: } ! 39: } ! 40: ! 41: // FPU をリセットする。 ! 42: // MPU リセット時と、NULL フレームのリストア時に呼ばれる。 ! 43: void ! 44: fpu_reset(m68kcpu *cpu) ! 45: { ! 46: // 高速化のため、あらかじめ用意しておいたイメージをコピーする ! 47: memcpy(&cpu->reg.fpframe, &initial_fpframe, sizeof(initial_fpframe)); ! 48: ! 49: cpu->fpu_dirty = false; ! 50: } ! 51: ! 52: // FPU からの呼び出し用。 ! 53: // ! 54: // (An)+, -(An) は、サイズが増えているのとクロックが増加している(2->6)。 ! 55: // それ以外のアドレッシングモードでもクロック数は微妙に違うのだが、 ! 56: // 大きくは違わないのでそっちは本体の cea と同じということにする。 ! 57: // ! 58: // このルーチンは Dn、An、#imm には対応していないので(自明)、呼び出し側で ! 59: // 事前に弾くこと。いずれも消費クロック数は 0 なので問題ない。 ! 60: // またそれ以外のすべてのアドレッシングモードで反応するため、命令ごとに ! 61: // 対応していないアドレッシングモードは事前に弾くこと。 ! 62: static inline uint32 ! 63: cea_fpu(m68kcpu *cpu, int bytes) ! 64: { ! 65: int n; ! 66: ! 67: switch (eamode(RegIR)) { ! 68: case 0: // Dn ! 69: case 1: // An ! 70: break; ! 71: case 2: // (An) ! 72: return cea_anin(cpu, eanum(RegIR)); ! 73: case 3: // (An)+ ! 74: CYCLE(6); ! 75: n = eanum(RegIR); ! 76: m68030_save_reg_pi(cpu, n); ! 77: if (bytes == 1) { ! 78: return internal_ea_anpi_8(cpu, n); ! 79: } else { ! 80: // _anpi_{16,32} のマクロは用意されてるけど、これと同じなので ! 81: RegA(n) += bytes; ! 82: return RegA(n) - bytes; ! 83: } ! 84: break; ! 85: case 4: // -(An) ! 86: CYCLE(6); ! 87: n = eanum(RegIR); ! 88: m68030_save_reg_pd(cpu, n); ! 89: if (bytes == 1) { ! 90: return internal_ea_anpd_8(cpu, n); ! 91: } else { ! 92: // _anpd_{16,32} のマクロは用意されてるけど、これと同じなので ! 93: RegA(n) -= bytes; ! 94: return RegA(n); ! 95: } ! 96: break; ! 97: case 5: // d16(An) ! 98: return cea_andi(cpu, eanum(RegIR)); ! 99: case 6: // (An,IX) ! 100: return cea_anix(cpu, eanum(RegIR)); ! 101: case 7: ! 102: switch (eanum(RegIR)) { ! 103: case 0: // Abs.W ! 104: return cea_absw(cpu); ! 105: case 1: // Abs.L ! 106: return cea_absl(cpu); ! 107: case 2: // d16(PC) ! 108: return cea_pcdi(cpu); ! 109: case 3: // (PC,IX) ! 110: return cea_pcix(cpu); ! 111: case 4: // #imm ! 112: break; ! 113: default: ! 114: break; ! 115: } ! 116: break; ! 117: } ! 118: // 不当命令 ! 119: throw M68K_EXCEP_ILLEGAL; ! 120: } ! 121: ! 122: // メモリから 64ビット値を読み込む ! 123: void ! 124: m68030_read_64(m68kcpu *cpu, uint32 addr, uint32 *data) ! 125: { ! 126: data[0] = m68030_read_32(cpu, addr); ! 127: data[1] = m68030_read_32(cpu, addr + 4); ! 128: } ! 129: ! 130: // メモリから 96ビット値を読み込む ! 131: void ! 132: m68030_read_96(m68kcpu *cpu, uint32 addr, uint32 *data) ! 133: { ! 134: data[0] = m68030_read_32(cpu, addr); ! 135: data[1] = m68030_read_32(cpu, addr + 4); ! 136: data[2] = m68030_read_32(cpu, addr + 8); ! 137: } ! 138: ! 139: // 64ビット値(.D)をメモリに書き込む ! 140: void ! 141: m68030_write_64(m68kcpu *cpu, int32 addr, const uint32 *data) ! 142: { ! 143: m68030_write_32(cpu, addr, data[0]); ! 144: m68030_write_32(cpu, addr + 4, data[1]); ! 145: } ! 146: ! 147: // 96ビット値(.D)をメモリに書き込む ! 148: void ! 149: m68030_write_96(m68kcpu *cpu, int32 addr, const uint32 *data) ! 150: { ! 151: m68030_write_32(cpu, addr, data[0]); ! 152: m68030_write_32(cpu, addr + 4, data[1]); ! 153: m68030_write_32(cpu, addr + 8, data[2]); ! 154: } ! 155: ! 156: // ソースを読み込みます。 ! 157: // 不当命令パターンなら false を返します。 ! 158: // size_id は SIZE_* です。 ! 159: static bool ! 160: readSRC(m68kcpu *cpu, int size_id, struct fpn *fpn) ! 161: { ! 162: struct fpemu *fe = &cpu->fe; ! 163: uint mr = RegIR & 0x3f; ! 164: uint32 ea; ! 165: uint32 data[3]; ! 166: ! 167: // 68881 本(p6-13) にはクロック数はこう書いてあるので ! 168: // Inst | src=FPn | memory source or dst operand format ! 169: // | | Int Sgl Dbl Ext Pakced ! 170: // ---- +---------- +------ ------- ------- ------- ------- ! 171: // FABS | 35 | 62 54 60 58 872 ! 172: // (差分) +27 +19 +25 +23 +837 ! 173: // FADD | 51 | 80 72 78 76 888 ! 174: // (差分) +29 +21 +27 +25 +837 ! 175: // ! 176: // FABS.X FPn,FPm は 35 としてこれは fgen() 内で加算。 ! 177: // FABS.L <ea>,FPm は 62 クロックなので、ここでは差分の 27 を加算。 ! 178: // FABS.L Dn,FPm の場合 src がレジスタなので 62 から 5 引く。 ! 179: // FABS.P <ea>,FPm は 872 クロックなので、ここでは差分の 837 を加算。 ! 180: // ! 181: // XXX 多くの命令が FABS と同じだけの差分だが、 ! 182: // FADD などいくつかは .P 以外に +2 クロックの追加があるようだ。 ! 183: // どうしたもんか。 ! 184: ! 185: if (mr < 8) { // Dn ! 186: switch (size_id) { ! 187: case SIZE_B: ! 188: data[0] = (int32)(int8)RegD(mr); ! 189: break; ! 190: case SIZE_W: ! 191: data[0] = (int32)(int16)RegD(mr); ! 192: break; ! 193: case SIZE_L: ! 194: case SIZE_S: ! 195: data[0] = RegD(mr); ! 196: break; ! 197: default: ! 198: return false; ! 199: } ! 200: // ソースが Dn の場合は 5クロック減 ! 201: CYCLE(-5); ! 202: } else if (mr == 0x3c) { // #imm ! 203: switch (size_id) { ! 204: case SIZE_B: ! 205: data[0] = m68030_fetch_16(cpu) & 0xff; ! 206: break; ! 207: case SIZE_W: ! 208: data[0] = m68030_fetch_16(cpu); ! 209: break; ! 210: case SIZE_L: ! 211: case SIZE_S: ! 212: data[0] = m68030_fetch_32(cpu); ! 213: break; ! 214: case SIZE_D: ! 215: data[0] = m68030_fetch_32(cpu); ! 216: data[1] = m68030_fetch_32(cpu); ! 217: break; ! 218: case SIZE_X: ! 219: case SIZE_P: ! 220: data[0] = m68030_fetch_32(cpu); ! 221: data[1] = m68030_fetch_32(cpu); ! 222: data[2] = m68030_fetch_32(cpu); ! 223: break; ! 224: default: ! 225: return false; ! 226: } ! 227: } else { ! 228: // それ以外は EA を求めてからメモリから読み込む ! 229: switch (size_id) { ! 230: case SIZE_B: ! 231: ea = cea_fpu(cpu, 1); ! 232: data[0] = (int32)(int8)m68030_read_8(cpu, ea); ! 233: break; ! 234: case SIZE_W: ! 235: ea = cea_fpu(cpu, 2); ! 236: data[0] = (int32)(int16)m68030_read_16(cpu, ea); ! 237: break; ! 238: case SIZE_L: ! 239: case SIZE_S: ! 240: ea = cea_fpu(cpu, 4); ! 241: data[0] = m68030_read_32(cpu, ea); ! 242: break; ! 243: case SIZE_D: ! 244: ea = cea_fpu(cpu, 8); ! 245: m68030_read_64(cpu, ea, data); ! 246: break; ! 247: case SIZE_X: ! 248: case SIZE_P: ! 249: ea = cea_fpu(cpu, 12); ! 250: m68030_read_96(cpu, ea, data); ! 251: break; ! 252: default: ! 253: return false; ! 254: } ! 255: } ! 256: ! 257: // 型別に fpn に変換 ! 258: switch (size_id) { ! 259: case SIZE_B: ! 260: case SIZE_W: ! 261: case SIZE_L: ! 262: CYCLE(+27); ! 263: fpu_explode(fe, fpn, FTYPE_LNG, data); ! 264: break; ! 265: case SIZE_S: ! 266: CYCLE(+19); ! 267: fpu_explode(fe, fpn, FTYPE_SNG, data); ! 268: break; ! 269: case SIZE_D: ! 270: CYCLE(+25); ! 271: fpu_explode(fe, fpn, FTYPE_DBL, data); ! 272: break; ! 273: case SIZE_X: ! 274: CYCLE(+23); ! 275: fpu_explode(fe, fpn, FTYPE_EXT, data); ! 276: break; ! 277: case SIZE_P: ! 278: CYCLE(+837); ! 279: fpu_explode(fe, fpn, FTYPE_BCD, data); ! 280: break; ! 281: } ! 282: ! 283: return true; ! 284: } ! 285: ! 286: // FPU 不当命令 (1ワード目で確定) ! 287: void ! 288: fpu_op_illg(m68kcpu *cpu) ! 289: { ! 290: cpulog(1, "FPU 不当命令 %04X", RegIR); ! 291: m68030_exception(cpu, M68K_EXCEP_FLINE); ! 292: } ! 293: ! 294: // FPU 不当命令 (2ワード目で確定) ! 295: void ! 296: fpu_op_illg2(m68kcpu *cpu) ! 297: { ! 298: cpulog(1, "FPU 不当命令 %04X %04X", RegIR, RegIR2); ! 299: m68030_exception(cpu, M68K_EXCEP_FLINE); ! 300: } ! 301: ! 302: // R/M=0 (レジスタ-レジスタ演算) ! 303: void ! 304: fpu_op_fgen_reg(m68kcpu *cpu) ! 305: { ! 306: struct fpemu *fe = &cpu->fe; ! 307: uint srcnum = (RegIR2 >> 10) & 7; ! 308: uint dstnum = (RegIR2 >> 7) & 7; ! 309: ! 310: fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &RegFP(srcnum * 3)); ! 311: fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &RegFP(dstnum * 3)); ! 312: fgen(cpu); ! 313: } ! 314: ! 315: // R/M=1 (メモリ-レジスタ演算) ! 316: void ! 317: fpu_op_fgen_mem(m68kcpu *cpu) ! 318: { ! 319: struct fpemu *fe = &cpu->fe; ! 320: uint size_id = (RegIR2 >> 10) & 7; ! 321: uint dstnum = (RegIR2 >> 7) & 7; ! 322: ! 323: // source specifier はオペランドサイズ ! 324: if (size_id == 7) { ! 325: // こんなところに FMOVECR ! 326: fpu_op_fmovecr(cpu); ! 327: return; ! 328: } ! 329: ! 330: // 第1ワードの EA がソース EA ! 331: if (!readSRC(cpu, size_id, &fe->fe_f2)) { ! 332: fpu_op_illg2(cpu); ! 333: return; ! 334: } ! 335: fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &RegFP(dstnum * 3)); ! 336: fgen(cpu); ! 337: } ! 338: ! 339: // 一般算術演算 ! 340: static void ! 341: fgen(m68kcpu *cpu) ! 342: { ! 343: struct fpemu *fe = &cpu->fe; ! 344: uint opmode = RegIR2 & 0x3f; ! 345: uint dstnum = (RegIR2 >> 7) & 7; ! 346: bool discard_result = false; ! 347: struct fpn *res = NULL; // shutup gcc ! 348: ! 349: switch (opmode) { ! 350: case 0x00: // FMOVE ! 351: CYCLE(33); ! 352: res = &fe->fe_f2; ! 353: fpu_round_prec(fe, res); ! 354: break; ! 355: case 0x01: // FINT ! 356: CYCLE(55); ! 357: res = fpu_int(fe); ! 358: break; ! 359: case 0x02: // FSINH ! 360: CYCLE(687); ! 361: res = fpu_sinh(fe); ! 362: fpu_round_prec(fe, res); ! 363: break; ! 364: case 0x03: // FINTRZ ! 365: CYCLE(55); ! 366: res = fpu_intrz(fe); ! 367: break; ! 368: case 0x04: // FSQRT ! 369: CYCLE(107); ! 370: res = fpu_sqrt(fe); ! 371: fpu_round_prec(fe, res); ! 372: break; ! 373: case 0x06: // FLOGNP1 ! 374: CYCLE(571); ! 375: res = fpu_lognp1(fe); ! 376: fpu_round_prec(fe, res); ! 377: break; ! 378: case 0x08: // FETOXM1 ! 379: CYCLE(545); ! 380: res = fpu_etoxm1(fe); ! 381: fpu_round_prec(fe, res); ! 382: break; ! 383: case 0x09: // FTANH ! 384: CYCLE(661); ! 385: res = fpu_tanh(fe); ! 386: fpu_round_prec(fe, res); ! 387: break; ! 388: case 0x0a: // FATAN ! 389: CYCLE(403); ! 390: res = fpu_atan(fe); ! 391: fpu_round_prec(fe, res); ! 392: break; ! 393: case 0x0c: // FASIN ! 394: CYCLE(581); ! 395: res = fpu_asin(fe); ! 396: fpu_round_prec(fe, res); ! 397: break; ! 398: case 0x0d: // FATANH ! 399: CYCLE(693); ! 400: res = fpu_atanh(fe); ! 401: fpu_round_prec(fe, res); ! 402: break; ! 403: case 0x0e: // FSIN ! 404: CYCLE(391); ! 405: res = fpu_sin(fe); ! 406: fpu_round_prec(fe, res); ! 407: break; ! 408: case 0x0f: // FTAN ! 409: CYCLE(473); ! 410: res = fpu_tan(fe); ! 411: fpu_round_prec(fe, res); ! 412: break; ! 413: case 0x10: // FETOX ! 414: CYCLE(497); ! 415: res = fpu_etox(fe); ! 416: fpu_round_prec(fe, res); ! 417: break; ! 418: case 0x11: // FTWOTOX ! 419: CYCLE(567); ! 420: res = fpu_twotox(fe); ! 421: fpu_round_prec(fe, res); ! 422: break; ! 423: case 0x12: // FTENTOX ! 424: CYCLE(567); ! 425: res = fpu_tentox(fe); ! 426: fpu_round_prec(fe, res); ! 427: break; ! 428: case 0x14: // FLOGN ! 429: CYCLE(525); ! 430: res = fpu_logn(fe); ! 431: fpu_round_prec(fe, res); ! 432: break; ! 433: case 0x15: // FLOG10 ! 434: CYCLE(581); ! 435: res = fpu_log10(fe); ! 436: fpu_round_prec(fe, res); ! 437: break; ! 438: case 0x16: // FLOG2 ! 439: CYCLE(581); ! 440: res = fpu_log2(fe); ! 441: fpu_round_prec(fe, res); ! 442: break; ! 443: case 0x18: // FABS ! 444: CYCLE(35); ! 445: fe->fe_f2.fp_sign = 0; ! 446: res = &fe->fe_f2; ! 447: fpu_round_prec(fe, res); ! 448: break; ! 449: case 0x19: // FCOSH ! 450: CYCLE(607); ! 451: res = fpu_cosh(fe); ! 452: fpu_round_prec(fe, res); ! 453: break; ! 454: case 0x1a: // FNEG ! 455: CYCLE(35); ! 456: res = &fe->fe_f2; ! 457: if (!ISNAN(res)) { ! 458: res->fp_sign = !res->fp_sign; ! 459: fpu_round_prec(fe, res); ! 460: } ! 461: break; ! 462: case 0x1c: // FACOS ! 463: CYCLE(625); ! 464: res = fpu_acos(fe); ! 465: fpu_round_prec(fe, res); ! 466: break; ! 467: case 0x1d: // FCOS ! 468: CYCLE(391); ! 469: res = fpu_cos(fe); ! 470: fpu_round_prec(fe, res); ! 471: break; ! 472: case 0x1e: // FGETEXP ! 473: CYCLE(45); ! 474: res = fpu_getexp(fe); ! 475: fpu_round_prec(fe, res); ! 476: break; ! 477: case 0x1f: // FGETMAN ! 478: CYCLE(31); ! 479: res = fpu_getman(fe); ! 480: fpu_round_prec(fe, res); ! 481: break; ! 482: case 0x20: // FDIV ! 483: CYCLE(103); ! 484: res = fpu_div(fe); ! 485: fpu_round_prec(fe, res); ! 486: break; ! 487: case 0x21: // FMOD ! 488: CYCLE(67); ! 489: res = fpu_mod(fe); ! 490: fpu_round_prec(fe, res); ! 491: break; ! 492: case 0x22: // FADD ! 493: CYCLE(51); ! 494: res = fpu_add(fe); ! 495: fpu_round_prec(fe, res); ! 496: break; ! 497: case 0x23: // FMUL ! 498: CYCLE(71); ! 499: res = fpu_mul(fe); ! 500: fpu_round_prec(fe, res); ! 501: break; ! 502: case 0x24: // FSGLDIV ! 503: CYCLE(69); ! 504: res = fpu_sgldiv(fe); ! 505: break; ! 506: case 0x25: // FREM ! 507: CYCLE(67); ! 508: res = fpu_rem(fe); ! 509: fpu_round_prec(fe, res); ! 510: break; ! 511: case 0x26: // FSCALE ! 512: // こいつだけ形式が違う。 ! 513: // 結果は dst に直接格納済み、FPSR も演算済み。 ! 514: CYCLE(41); ! 515: fpu_emul_fscale(fe, RegIR2); ! 516: return; ! 517: case 0x27: // FSGLMUL ! 518: CYCLE(59); ! 519: res = fpu_sglmul(fe); ! 520: break; ! 521: case 0x28: // FSUB ! 522: CYCLE(51); ! 523: res = fpu_sub(fe); ! 524: fpu_round_prec(fe, res); ! 525: break; ! 526: case 0x30: ! 527: case 0x31: ! 528: case 0x32: ! 529: case 0x33: ! 530: case 0x34: ! 531: case 0x35: ! 532: case 0x36: ! 533: case 0x37: // FSINCOS ! 534: CYCLE(451); ! 535: res = fpu_sincos(fe, opmode & 7); ! 536: fpu_round_prec(fe, res); ! 537: break; ! 538: case 0x38: // FCMP ! 539: CYCLE(33); ! 540: res = fpu_cmp(fe); ! 541: discard_result = 1; ! 542: break; ! 543: case 0x3a: // FTST ! 544: CYCLE(33); ! 545: res = &fe->fe_f2; ! 546: discard_result = 1; ! 547: break; ! 548: ! 549: default: ! 550: // 不当命令 ! 551: fpu_op_illg2(cpu); ! 552: return; ! 553: } ! 554: ! 555: assert(res); ! 556: if (!discard_result) { ! 557: fpu_implode(fe, res, FTYPE_EXT, &RegFP(dstnum * 3)); ! 558: } ! 559: fpu_upd_fpsr(fe, res); ! 560: fpu_upd_excp(fe); ! 561: } ! 562: ! 563: // FMOVECR ! 564: void ! 565: fpu_op_fmovecr(m68kcpu *cpu) ! 566: { ! 567: CYCLE(29); ! 568: ! 569: struct fpemu *fe = &cpu->fe; ! 570: uint offset = (RegIR2 & 0x7f); ! 571: uint dstnum = (RegIR2 >> 7) & 7; ! 572: ! 573: fpu_const(&fe->fe_f3, offset); ! 574: fpu_implode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(dstnum * 3)); ! 575: fpu_upd_fpsr(fe, &fe->fe_f3); ! 576: fpu_upd_excp(fe); ! 577: } ! 578: ! 579: // FMOVE.B FPn,<ea> ! 580: // cf. 68000PRM.pdf p378 (5-76) ! 581: void ! 582: fpu_op_fmove_b_mem(m68kcpu *cpu) ! 583: { ! 584: struct fpemu *fe = &cpu->fe; ! 585: uint mr = RegIR & 0x3f; ! 586: uint srcnum = (RegIR2 >> 7) & 7; ! 587: uint32 ea; ! 588: uint32 data; ! 589: ! 590: fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3)); ! 591: fpu_implode(fe, &fe->fe_f3, FTYPE_LNG, &data); ! 592: if ((int32)data < INT8_MIN || (int32)data > INT8_MAX) { ! 593: RegFPSR |= FPSR_OPERR | FPSR_AIOP; ! 594: } ! 595: ! 596: if (mr < 8) { // Dn ! 597: CYCLE(100-2); ! 598: RegD(mr) &= 0xffffff00; ! 599: RegD(mr) |= (uint8)data; ! 600: } else { ! 601: CYCLE(100); ! 602: ea = cea_fpu(cpu, 1); ! 603: m68030_write_8(cpu, ea, (uint8)data); ! 604: } ! 605: } ! 606: ! 607: // FMOVE.W FPn,<ea> ! 608: // cf. 68000PRM.pdf p378 (5-76) ! 609: void ! 610: fpu_op_fmove_w_mem(m68kcpu *cpu) ! 611: { ! 612: struct fpemu *fe = &cpu->fe; ! 613: uint mr = RegIR & 0x3f; ! 614: uint srcnum = (RegIR2 >> 7) & 7; ! 615: uint32 ea; ! 616: uint32 data; ! 617: ! 618: fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3)); ! 619: fpu_implode(fe, &fe->fe_f3, FTYPE_LNG, &data); ! 620: if ((int32)data < INT16_MIN || (int32)data > INT16_MAX) { ! 621: RegFPSR |= FPSR_OPERR | FPSR_AIOP; ! 622: } ! 623: ! 624: if (mr < 8) { // Dn ! 625: CYCLE(100-2); ! 626: RegD(mr) &= 0xffff0000; ! 627: RegD(mr) |= (uint16)data; ! 628: } else { ! 629: CYCLE(100); ! 630: ea = cea_fpu(cpu, 2); ! 631: m68030_write_16(cpu, ea, (uint16)data); ! 632: } ! 633: } ! 634: ! 635: // FMOVE.L FPn,<ea> ! 636: // cf. 68000PRM.pdf p378 (5-76) ! 637: void ! 638: fpu_op_fmove_l_mem(m68kcpu *cpu) ! 639: { ! 640: struct fpemu *fe = &cpu->fe; ! 641: uint mr = RegIR & 0x3f; ! 642: uint srcnum = (RegIR2 >> 7) & 7; ! 643: uint32 ea; ! 644: uint32 data; ! 645: ! 646: fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3)); ! 647: fpu_implode(fe, &fe->fe_f3, FTYPE_LNG, &data); ! 648: // XXX オーバーフローチェック ! 649: ! 650: if (mr < 8) { // Dn ! 651: CYCLE(100-2); ! 652: RegD(mr) = data; ! 653: } else { ! 654: CYCLE(100); ! 655: ea = cea_fpu(cpu, 4); ! 656: m68030_write_32(cpu, ea, data); ! 657: } ! 658: } ! 659: ! 660: // FMOVE.S FPn,<ea> ! 661: // cf. 68000PRM.pdf p378 (5-76) ! 662: void ! 663: fpu_op_fmove_s_mem(m68kcpu *cpu) ! 664: { ! 665: struct fpemu *fe = &cpu->fe; ! 666: uint mr = RegIR & 0x3f; ! 667: uint srcnum = (RegIR2 >> 7) & 7; ! 668: uint32 ea; ! 669: uint32 data; ! 670: ! 671: fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3)); ! 672: fpu_implode(fe, &fe->fe_f3, FTYPE_SNG, &data); ! 673: ! 674: if (mr < 8) { // Dn ! 675: CYCLE(80-2); ! 676: RegD(mr) = data; ! 677: } else { ! 678: CYCLE(80); ! 679: ea = cea_fpu(cpu, 4); ! 680: m68030_write_32(cpu, ea, data); ! 681: } ! 682: } ! 683: ! 684: // FMOVE.D FPn,<ea> ! 685: // cf. 68000PRM.pdf p378 (5-76) ! 686: void ! 687: fpu_op_fmove_d_mem(m68kcpu *cpu) ! 688: { ! 689: CYCLE(86); ! 690: ! 691: struct fpemu *fe = &cpu->fe; ! 692: uint srcnum = (RegIR2 >> 7) & 7; ! 693: uint32 ea; ! 694: uint32 data[2]; ! 695: ! 696: fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3)); ! 697: fpu_implode(fe, &fe->fe_f3, FTYPE_DBL, data); ! 698: ! 699: ea = cea_fpu(cpu, 8); ! 700: m68030_write_64(cpu, ea, data); ! 701: } ! 702: ! 703: // FMOVE.X FPn,<ea> ! 704: // cf. 68000PRM.pdf p378 (5-76) ! 705: void ! 706: fpu_op_fmove_x_mem(m68kcpu *cpu) ! 707: { ! 708: CYCLE(72); ! 709: ! 710: uint srcnum = (RegIR2 >> 7) & 7; ! 711: uint32 ea; ! 712: ! 713: ea = cea_fpu(cpu, 12); ! 714: m68030_write_96(cpu, ea, &RegFP(srcnum * 3)); ! 715: } ! 716: ! 717: // FMOVE.P FPn,<ea> ! 718: // cf. 68000PRM.pdf p378 (5-76) ! 719: void ! 720: fpu_op_fmove_p_mem(m68kcpu *cpu) ! 721: { ! 722: struct fpemu *fe = &cpu->fe; ! 723: uint srcnum = (RegIR2 >> 7) & 7; ! 724: uint32 ea; ! 725: uint32 data[3]; ! 726: uint32 k; ! 727: ! 728: if ((RegIR2 & 0x1000)) { ! 729: // dynamic k-factor ! 730: CYCLE(1996+14); ! 731: k = RegD((RegIR2 >> 4) & 7); ! 732: } else { ! 733: // static k-factor ! 734: CYCLE(1996); ! 735: k = RegIR2; ! 736: } ! 737: // k は7ビット符号付き数 ! 738: k &= 0x7f; ! 739: if ((k & 0x40)) { ! 740: k = (int32)(int8)(k | 0x80); ! 741: } ! 742: ! 743: fpu_explode(fe, &fe->fe_f3, FTYPE_EXT, &RegFP(srcnum * 3)); ! 744: fpu_ftop(fe, &fe->fe_f3, data, k); ! 745: ! 746: ea = cea_fpu(cpu, 12); ! 747: m68030_write_96(cpu, ea, data); ! 748: } ! 749: ! 750: // FMOVEM.L <ea>,<ctllist> ! 751: // 1111 ccc 000 mmmrrr | 10D RRR 0000 000000 ! 752: // D=0: <ea> to FPctl ! 753: // RRR: register list ! 754: void ! 755: fpu_op_fmovem_ea2ctl(m68kcpu *cpu) ! 756: { ! 757: uint mr = RegIR & 0x3f; ! 758: uint reglist = (RegIR2 >> 10) & 7; ! 759: int count; ! 760: uint32 ea; ! 761: uint32 src[3]; ! 762: int i; ! 763: ! 764: // cache case worst case ! 765: // FMOVE Rn,FPc 28 31 ! 766: // FMOVE <ea>,FPc 33 36 ! 767: // FMOVE #imm,FPc 30 31 ! 768: // FMOVEM <ea>,FPcs 27+6n 30+6n ! 769: // FMOVEM #imm,FPcs 25+6n 29+6n ! 770: // ! 771: // FMOVE #imm と FMOVEM #imm (n==1) は cache case が 1クロックだけ違う ! 772: // ようだけどもう無視する。 ! 773: ! 774: // 転送するレジスタ数 ! 775: // ただし nofpc は FPIAR とみなされるようだ。see exp/fmovem.php ! 776: if (reglist == 0) ! 777: reglist = 1; ! 778: count = __builtin_popcount(reglist); ! 779: ! 780: if (mr < 8) { // Dn ! 781: CYCLE2(28, 31); ! 782: // 対データレジスタは転送数 1 のみ有効 ! 783: if (count > 1) { ! 784: fpu_op_illg2(cpu); ! 785: return; ! 786: } ! 787: src[0] = RegR(mr); ! 788: ! 789: } else if (mr < 16) { // An ! 790: CYCLE2(28, 31); ! 791: // 対アドレスレジスタは FPIAR のみ有効 ! 792: if (reglist != 1) { ! 793: fpu_op_illg2(cpu); ! 794: return; ! 795: } ! 796: src[0] = RegR(mr); ! 797: ! 798: } else if (mr < 0x3c) { // 対メモリ ! 799: CYCLE2(28, 30); ! 800: CYCLE(count * 6); ! 801: ! 802: // EA を取得。 ! 803: // -(An) の時も先にレジスタ数分一気に減算して、そこからプラス方向に ! 804: // 読み込んでいくので、ロジックは全部同じになる。 ! 805: // (68000PRM.pdf p393) ! 806: ea = cea_fpu(cpu, count * 4); ! 807: for (i = 0; i < count; i++) { ! 808: src[i] = m68030_read_32(cpu, ea); ! 809: ea += 4; ! 810: } ! 811: ! 812: } else if (mr == 0x3c) { // #imm ! 813: CYCLE2(25, 29); ! 814: CYCLE(count * 6); ! 815: ! 816: for (i = 0; i < count; i++) { ! 817: src[i] = m68030_fetch_32(cpu); ! 818: } ! 819: ! 820: } else { ! 821: fpu_op_illg2(cpu); ! 822: return; ! 823: } ! 824: ! 825: // 該当レジスタへ読み込み ! 826: i = 0; ! 827: if ((reglist & 4)) { ! 828: RegFPCR = src[i++] & M68K_FPCR_MASK; ! 829: } ! 830: if ((reglist & 2)) { ! 831: RegFPSR = src[i++] & M68K_FPSR_MASK; ! 832: } ! 833: if ((reglist & 1)) { ! 834: RegFPIAR = src[i++]; ! 835: } ! 836: } ! 837: ! 838: // FMOVEM.L <ctllist>,<ea> ! 839: // 1111 ccc 000 mmmrrr | 10D RRR 0000 000000 ! 840: // D=1: FPctl to <ea> ! 841: // RRR: register list ! 842: void ! 843: fpu_op_fmovem_ctl2ea(m68kcpu *cpu) ! 844: { ! 845: uint mr = RegIR & 0x3f; ! 846: uint reglist = (RegIR2 >> 10) & 7; ! 847: int count; ! 848: uint32 ea; ! 849: ! 850: // cache case worst case ! 851: // FMOVE FPc,Rn 31 34 ! 852: // FMOVE FPc,<ea> 33 36 ! 853: // FMOVEM FPcs,<ea> 27+6n 30+6n ! 854: ! 855: // 転送するレジスタ数 ! 856: // ただし nofpc は FPIAR とみなされるようだ。see exp/fmovem.php ! 857: if (reglist == 0) ! 858: reglist = 1; ! 859: count = __builtin_popcount(reglist); ! 860: ! 861: if (mr < 8) { // Dn ! 862: CYCLE2(31, 34); ! 863: // 対データレジスタは転送数は 1 のみ有効 ! 864: if (count > 1) { ! 865: fpu_op_illg2(cpu); ! 866: return; ! 867: } ! 868: ! 869: if ((reglist & 4)) { ! 870: RegR(mr) = RegFPCR; ! 871: } ! 872: if ((reglist & 2)) { ! 873: RegR(mr) = RegFPSR; ! 874: } ! 875: if ((reglist & 1)) { ! 876: RegR(mr) = RegFPIAR; ! 877: } ! 878: return; ! 879: } ! 880: if (mr < 16) { // An ! 881: CYCLE2(31, 34); ! 882: // 対アドレスレジスタは FPIAR のみ有効 ! 883: if (reglist != 1) { ! 884: fpu_op_illg2(cpu); ! 885: return; ! 886: } ! 887: RegR(mr) = RegFPIAR; ! 888: return; ! 889: } ! 890: if (mr >= 0x3a) { // #imm, d16(PC), (PC,IX) ! 891: fpu_op_illg2(cpu); ! 892: return; ! 893: } ! 894: ! 895: // それ以外、対メモリの場合。 ! 896: CYCLE2(27, 30); ! 897: CYCLE(count * 6); ! 898: ! 899: // EA を取得して... ! 900: ea = cea_fpu(cpu, count * 4); ! 901: // 該当レジスタをメモリへ書き出し ! 902: if ((reglist & 4)) { ! 903: m68030_write_32(cpu, ea, RegFPCR); ! 904: ea += 4; ! 905: } ! 906: if ((reglist & 2)) { ! 907: m68030_write_32(cpu, ea, RegFPSR); ! 908: ea += 4; ! 909: } ! 910: if ((reglist & 1)) { ! 911: m68030_write_32(cpu, ea, RegFPIAR); ! 912: ea += 4; ! 913: } ! 914: } ! 915: ! 916: // FMOVEM.X <ea>,<reglist> ! 917: // FMOVEM.X <ea>,Dn ! 918: // 1111 ccc 000 mmmrrr | 11D MM000 RRRRRRRR ! 919: // D=0: <ea> to FPn ! 920: void ! 921: fpu_op_fmovem_ea2reg(m68kcpu *cpu) ! 922: { ! 923: uint mr = RegIR & 0x3f; ! 924: bool predec = !(RegIR2 & 0x1000); ! 925: bool dynamic = (RegIR2 & 0x0800); ! 926: uint8 reglist = RegIR2 & 0xff; ! 927: int i; ! 928: uint32 ea; ! 929: ! 930: // cache worst ! 931: // FMOVEM.X <ea>,<list> 35+23n 38+23n ! 932: // FMOVEM.X <ea>,Dn 49+23n 52+23n ! 933: ! 934: // 不当パターンを弾く ! 935: switch (mr) { ! 936: case 0x00 ... 0x07: // Dn ! 937: case 0x08 ... 0x0f: // An ! 938: case 0x20 ... 0x27: // -(An) ! 939: case 0x3c: // #imm ! 940: case 0x3d ... 0x3f: ! 941: fpu_op_illg2(cpu); ! 942: return; ! 943: } ! 944: ! 945: // ダイナミックモードなら reglist の %0nnn0000 にレジスタ番号が ! 946: // 入っているので、この Dn の下位8ビットを取り出す。レジスタ番号以外の ! 947: // ビットは無視、Dn の上位ビットも無視。 ! 948: // ついでにここでベースクロックを記録 ! 949: if (dynamic) { ! 950: reglist = RegD((reglist >> 4) & 7); ! 951: CYCLE2(49, 52); ! 952: } else { ! 953: CYCLE2(35, 38); ! 954: } ! 955: ! 956: // EA は最初に一度取得しておいて... ! 957: int count = __builtin_popcount(reglist); ! 958: ea = cea_fpu(cpu, 12 * count); ! 959: ! 960: if (predec) { ! 961: // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。 ! 962: for (i = 7; reglist; reglist <<=1, i--) { ! 963: if ((int8)reglist < 0) { ! 964: m68030_read_96(cpu, ea, &RegFP(i * 3)); ! 965: ea += 12; ! 966: } ! 967: } ! 968: } else { ! 969: // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。 ! 970: for (i = 0; reglist; reglist <<= 1, i++) { ! 971: if ((int8)reglist < 0) { ! 972: m68030_read_96(cpu, ea, &RegFP(i * 3)); ! 973: ea += 12; ! 974: } ! 975: } ! 976: } ! 977: CYCLE(23 * count); ! 978: } ! 979: ! 980: // FMOVEM.X <reglist>,<ea> ! 981: // FMOVEM.X Dn,<ea> ! 982: // 1111 ccc 000 mmmrrr | 11D MM000 RRRRRRRR ! 983: // D=1: FPn to <ea> ! 984: void ! 985: fpu_op_fmovem_reg2ea(m68kcpu *cpu) ! 986: { ! 987: uint mr = RegIR & 0x3f; ! 988: bool anpd = false; // 第1ワード EA が -(An) か ! 989: bool predec = !(RegIR2 & 0x1000); // 第2ワードの mode が predec か ! 990: bool dynamic = (RegIR2 & 0x0800); ! 991: uint8 reglist = RegIR2 & 0xff; ! 992: int i; ! 993: uint32 ea; ! 994: ! 995: // cache worst ! 996: // FMOVEM.X <list>,<ea> 37+25n 40+25n ! 997: // FMOVEM.X Dn,<ea> 51+25n 54+25n ! 998: ! 999: // 不当パターンを弾く ! 1000: // ついでに -(An) だけ覚えておく ! 1001: switch (mr) { ! 1002: case 0x00 ... 0x07: // Dn ! 1003: case 0x08 ... 0x0f: // An ! 1004: case 0x18 ... 0x1f: // (An)+ ! 1005: case 0x3a: // d16(PC) ! 1006: case 0x3b: // (PC,IX) ! 1007: case 0x3c: // #imm ! 1008: case 0x3d ... 0x3f: ! 1009: fpu_op_illg2(cpu); ! 1010: return; ! 1011: case 0x20 ... 0x27: // -(An) ! 1012: anpd = true; ! 1013: break; ! 1014: } ! 1015: ! 1016: // ダイナミックモードなら reglist の %0nnn0000 にレジスタ番号が ! 1017: // 入っているので、この Dn の下位8ビットを取り出す。レジスタ番号以外の ! 1018: // ビットは無視、Dn の上位ビットも無視。 ! 1019: // ついでにここでベースクロックを記録 ! 1020: if (dynamic) { ! 1021: reglist = RegD((reglist >> 4) & 7); ! 1022: CYCLE2(51, 54); ! 1023: } else { ! 1024: CYCLE2(37, 40); ! 1025: } ! 1026: ! 1027: int count = __builtin_popcount(reglist); ! 1028: ! 1029: // -(An) の時だけ EA を別処理。 ! 1030: // 現状の cea_fpu() は -(An) の時、巻き戻し用のレジスタを保存し ! 1031: // デクリメントしたアドレスを返すまでを一度に行う便利関数だが、 ! 1032: // FMOVEM fpn,-(An) は最初に巻き戻し用レジスタを保存し (これは命令先頭 ! 1033: // に戻るためなので最初の1回だけ)、その後レジスタ1つずつ 12バイトを ! 1034: // プリデクリメントしながら格納していく必要がある (この順に実行しないと ! 1035: // バスエラーの原因箇所が異なってしまう)。 ! 1036: // そのため cea_fpu() がそのまま使えないので、ここだけ独自対応する。 ! 1037: // cea_fpu() は1命令中で EA の取得が1回である前提のあくまで便利関数 ! 1038: // なので、例外的である FMOVEM は仕方がない。 ! 1039: if (anpd) { ! 1040: CYCLE(6); ! 1041: uint n = eanum(RegIR); ! 1042: m68030_save_reg_pd(cpu, n); ! 1043: ! 1044: if (predec) { ! 1045: // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。 ! 1046: for (i = 7; reglist; reglist <<= 1, i--) { ! 1047: if ((int8)reglist < 0) { ! 1048: RegA(n) -= 12; ! 1049: m68030_write_96(cpu, RegA(n), &RegFP(i * 3)); ! 1050: } ! 1051: } ! 1052: } else { ! 1053: // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。 ! 1054: for (i = 0; reglist; reglist <<= 1, i++) { ! 1055: if ((int8)reglist < 0) { ! 1056: RegA(n) -= 12; ! 1057: m68030_write_96(cpu, RegA(n), &RegFP(i * 3)); ! 1058: } ! 1059: } ! 1060: } ! 1061: } else { ! 1062: // -(An) 以外は EA を最初に一度計算しておく方法が使える ! 1063: ea = cea_fpu(cpu, 12 * count); ! 1064: ! 1065: if (predec) { ! 1066: // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。 ! 1067: for (i = 7; reglist; reglist <<= 1, i--) { ! 1068: if ((int8)reglist < 0) { ! 1069: m68030_write_96(cpu, ea, &RegFP(i * 3)); ! 1070: ea += 12; ! 1071: } ! 1072: } ! 1073: } else { ! 1074: // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。 ! 1075: for (i = 0; reglist; reglist <<= 1, i++) { ! 1076: if ((int8)reglist < 0) { ! 1077: m68030_write_96(cpu, ea, &RegFP(i * 3)); ! 1078: ea += 12; ! 1079: } ! 1080: } ! 1081: } ! 1082: } ! 1083: CYCLE(25 * count); ! 1084: } ! 1085: ! 1086: // FScc.B <ea> ! 1087: // 1111 ccc 001 mmmrrr | 0000 000 000 CCCCCC ! 1088: void ! 1089: fpu_op_fscc(m68kcpu *cpu) ! 1090: { ! 1091: struct fpemu *fe = &cpu->fe; ! 1092: uint mr = RegIR & 0x3f; ! 1093: uint mm = eamode(RegIR); ! 1094: uint rr = eanum(RegIR); ! 1095: uint cond = RegIR2 & 0x3f; ! 1096: int data; ! 1097: uint32 ea; ! 1098: ! 1099: // cache worst ! 1100: // FScc.B Dn 18 21 ! 1101: // FScc.B (An)+/-(An) 22 25 ; condition is true ! 1102: // FScc.B (An)+/-(An) 21 24 ; condition is false ! 1103: // FScc.B <ea> 20 23 ! 1104: ! 1105: if (cond > 0x1f) { ! 1106: fpu_op_illg2(cpu); ! 1107: return; ! 1108: } ! 1109: ! 1110: data = (test_cc(fe, cond) == -1) ? 0xff : 0x00; ! 1111: ! 1112: switch (mm) { ! 1113: case 0: // Dn ! 1114: CYCLE2(18, 21); ! 1115: RegD(rr) &= 0xffffff00; ! 1116: RegD(rr) |= data; ! 1117: return; ! 1118: ! 1119: case 3: // (An)+ ! 1120: case 4: // -(An) ! 1121: // ここだけ他のメモリ系 EA とはクロックが違うし、 ! 1122: // 条件の成立可否でも違う。 ! 1123: if (data == 0x00) { ! 1124: CYCLE2(21, 24); ! 1125: } else { ! 1126: CYCLE2(22, 25); ! 1127: } ! 1128: break; ! 1129: case 7: ! 1130: if (mr == 0x38 || mr == 0x39) { // Abs.W, Abs.L ! 1131: } else { ! 1132: fpu_op_illg2(cpu); ! 1133: return; ! 1134: } ! 1135: FALLTHROUGH; ! 1136: default: ! 1137: CYCLE2(20, 23); ! 1138: break; ! 1139: } ! 1140: ! 1141: ea = cea_fpu(cpu, 1); ! 1142: m68030_write_8(cpu, ea, data); ! 1143: } ! 1144: ! 1145: // FDBcc Dn,<label> ! 1146: // 1111 ccc 001 001rrr | 0000 000 000 CCCCCC | <16bit disp> ! 1147: void ! 1148: fpu_op_fdbcc(m68kcpu *cpu) ! 1149: { ! 1150: struct fpemu *fe = &cpu->fe; ! 1151: uint rr = RegIR & 7; ! 1152: uint cond = RegIR2 & 0x3f; ! 1153: ! 1154: if (cond > 0x1f) { ! 1155: fpu_op_illg2(cpu); ! 1156: return; ! 1157: } ! 1158: ! 1159: if (test_cc(fe, cond) == -1) { ! 1160: // 真なら何もしない。disp を読み飛ばして次へ ! 1161: CYCLE2(20, 24); ! 1162: m68030_fetch_16(cpu); ! 1163: } else { ! 1164: // 偽の場合 ! 1165: uint16 data = RegD(rr) - 1; ! 1166: RegD(rr) = (RegD(rr) & 0xffff0000) | data; ! 1167: ! 1168: if (data == 0xffff) { ! 1169: // ループ終了。disp を読み飛ばす ! 1170: CYCLE2(24, 32); ! 1171: m68030_fetch_16(cpu); ! 1172: } else { ! 1173: // 計算に使う PC は FDBcc 命令+2 のところらしい ! 1174: CYCLE2(20, 26); ! 1175: uint32 pc = RegPPC + 2; ! 1176: int32 disp = (int32)(int16)m68030_fetch_16(cpu); ! 1177: m68030_jump(cpu, pc + disp); ! 1178: } ! 1179: } ! 1180: } ! 1181: ! 1182: // FTRAPcc.W #<data> ! 1183: void ! 1184: fpu_op_ftrapcc_w(m68kcpu *cpu) ! 1185: { ! 1186: struct fpemu *fe = &cpu->fe; ! 1187: uint cond = RegIR2 & 0x3f; ! 1188: ! 1189: if (cond > 0x1f) { ! 1190: fpu_op_illg2(cpu); ! 1191: return; ! 1192: } ! 1193: ! 1194: if (test_cc(fe, cond) == -1) { ! 1195: // TODO: 例外発生 ! 1196: CYCLE2(41, 45); ! 1197: PANIC("unimpl ftrapcc_w at %08X", RegPPC); ! 1198: } else { ! 1199: // 即値は読み捨て ! 1200: CYCLE2(20, 23); ! 1201: m68030_fetch_16(cpu); ! 1202: } ! 1203: } ! 1204: ! 1205: // FTRAPcc.L #<data> ! 1206: void ! 1207: fpu_op_ftrapcc_l(m68kcpu *cpu) ! 1208: { ! 1209: struct fpemu *fe = &cpu->fe; ! 1210: uint cond = RegIR2 & 0x3f; ! 1211: ! 1212: if (cond > 0x1f) { ! 1213: fpu_op_illg2(cpu); ! 1214: return; ! 1215: } ! 1216: ! 1217: if (test_cc(fe, cond) == -1) { ! 1218: // TODO: 例外発生 ! 1219: CYCLE2(43, 52); ! 1220: PANIC("unimpl ftrapcc_l at %08X", RegPPC); ! 1221: } else { ! 1222: // 即値は読み捨て ! 1223: CYCLE2(22, 27); ! 1224: m68030_fetch_32(cpu); ! 1225: } ! 1226: } ! 1227: ! 1228: // FTRAPcc ! 1229: void ! 1230: fpu_op_ftrapcc(m68kcpu *cpu) ! 1231: { ! 1232: struct fpemu *fe = &cpu->fe; ! 1233: uint cond = RegIR2 & 0x3f; ! 1234: ! 1235: if (cond > 0x1f) { ! 1236: fpu_op_illg2(cpu); ! 1237: return; ! 1238: } ! 1239: ! 1240: if (test_cc(fe, cond) == -1) { ! 1241: // TODO: 例外発生 ! 1242: CYCLE2(39, 47); ! 1243: PANIC("unimpl ftrapcc_l at %08X", RegPPC); ! 1244: } else { ! 1245: // 即値はないので、何もしない ! 1246: CYCLE2(18, 22); ! 1247: } ! 1248: } ! 1249: ! 1250: // FBcc.W <label> ! 1251: // 1111 ccc 01S CCCCCC | <16bit disp> ! 1252: // S=0: 16bit disp ! 1253: // ! 1254: // FNOP ! 1255: // 1111 ccc 010 000000 | 0000 0000 0000 0000 ! 1256: void ! 1257: fpu_op_fbcc_w(m68kcpu *cpu) ! 1258: { ! 1259: struct fpemu *fe = &cpu->fe; ! 1260: uint cond = RegIR & 0x3f; ! 1261: ! 1262: if (test_cc(fe, cond) == -1) { ! 1263: CYCLE2(20, 23); ! 1264: uint32 pc = RegPC; ! 1265: int32 disp = (int32)(int16)m68030_fetch_16(cpu); ! 1266: m68030_jump(cpu, pc + disp); ! 1267: } else { ! 1268: // disp を読み飛ばす ! 1269: CYCLE2(18, 19); ! 1270: m68030_fetch_16(cpu); ! 1271: } ! 1272: } ! 1273: ! 1274: // FBcc.L <label> ! 1275: // 1111 ccc 01S CCCCCC | <32bit disp> ! 1276: // S=1: 32bit disp ! 1277: void ! 1278: fpu_op_fbcc_l(m68kcpu *cpu) ! 1279: { ! 1280: struct fpemu *fe = &cpu->fe; ! 1281: uint cond = RegIR & 0x3f; ! 1282: ! 1283: if (test_cc(fe, cond) == -1) { ! 1284: CYCLE2(20, 23); ! 1285: uint32 pc = RegPC; ! 1286: int32 disp = (int32)m68030_fetch_32(cpu); ! 1287: m68030_jump(cpu, pc + disp); ! 1288: } else { ! 1289: // disp を読み飛ばす ! 1290: CYCLE2(18, 21); ! 1291: m68030_fetch_32(cpu); ! 1292: } ! 1293: } ! 1294: ! 1295: // FSAVE の NULL フレーム (全機種共通で4バイト) ! 1296: static const uint32 fsave_frame_null[] = { ! 1297: 0, ! 1298: }; ! 1299: ! 1300: // FSAVE のアイドルフレーム (68881 は 0x1c = 28 バイト、 7ロングワード) ! 1301: static const uint32 fsave_frame_idle[] = { ! 1302: 0x1f180000, ! 1303: 0, ! 1304: 0, ! 1305: 0, ! 1306: 0, ! 1307: 0, ! 1308: 0x70000000, ! 1309: }; ! 1310: ! 1311: // FSAVE ! 1312: // スーパーバイザモードは判定済み ! 1313: void ! 1314: fpu_op_fsave(m68kcpu *cpu) ! 1315: { ! 1316: uint mm = eamode(RegIR); ! 1317: uint rr = eanum(RegIR); ! 1318: uint32 ea; ! 1319: const uint32 *frame; ! 1320: int framelen; ! 1321: ! 1322: // XXX EA が -(An) の時 An が逐次減算て書いてあるソースきぼんぬ ! 1323: ! 1324: // フレームを選択 ! 1325: if (cpu->fpu_dirty == false) { ! 1326: // NULL フレーム ! 1327: CYCLE2(16, 18); ! 1328: frame = fsave_frame_null; ! 1329: framelen = countof(fsave_frame_null); ! 1330: } else { ! 1331: // IDLE フレーム ! 1332: CYCLE2(52, 54); // XXX これは最小値らしいけど ! 1333: frame = fsave_frame_idle; ! 1334: framelen = countof(fsave_frame_idle); ! 1335: } ! 1336: ! 1337: // EA は独自体系なのでここでべたに書く ! 1338: switch (mm) { ! 1339: case 2: // (An) ! 1340: ea = cea_anin(cpu, rr); ! 1341: break; ! 1342: case 4: // -(An) ! 1343: // これだけ処理が違うので、ここでやる ! 1344: m68030_save_reg_pd(cpu, rr); ! 1345: for (int i = framelen; i >= 0; i--) { ! 1346: RegA(rr) -= 4; ! 1347: m68030_write_32(cpu, RegA(rr), frame[i]); ! 1348: } ! 1349: return; ! 1350: ! 1351: case 5: // d16(An) ! 1352: ea = cea_andi(cpu, rr); ! 1353: break; ! 1354: case 6: // (An,IX) ! 1355: ea = cea_anix(cpu, rr); ! 1356: break; ! 1357: case 7: ! 1358: switch (rr) { ! 1359: case 0: // Abs.W ! 1360: ea = cea_absw(cpu); ! 1361: break; ! 1362: case 1: // Abs.L ! 1363: ea = cea_absl(cpu); ! 1364: break; ! 1365: default: ! 1366: fpu_op_illg(cpu); ! 1367: return; ! 1368: } ! 1369: break; ! 1370: default: ! 1371: fpu_op_illg(cpu); ! 1372: return; ! 1373: } ! 1374: ! 1375: // -(An) 以外の EA の場合 ! 1376: for (int i = 0; i < framelen; i++) { ! 1377: m68030_write_32(cpu, ea, frame[i]); ! 1378: ea += 4; ! 1379: } ! 1380: } ! 1381: ! 1382: // FRESTORE ! 1383: // スーパーバイザモードは判定済み ! 1384: void ! 1385: fpu_op_frestore(m68kcpu *cpu) ! 1386: { ! 1387: uint mm = eamode(RegIR); ! 1388: uint rr = eanum(RegIR); ! 1389: uint32 ea; ! 1390: uint32 data; ! 1391: bool postinc; ! 1392: ! 1393: postinc = false; ! 1394: // EA は独自体系なのでここでべたに書く ! 1395: switch (mm) { ! 1396: case 2: // (An) ! 1397: ea = cea_anin(cpu, rr); ! 1398: break; ! 1399: case 3: // (An)+ ! 1400: ea = cea_anin(cpu, rr); ! 1401: postinc = true; ! 1402: break; ! 1403: case 5: // d16(An) ! 1404: ea = cea_andi(cpu, rr); ! 1405: break; ! 1406: case 6: // (An,IX) ! 1407: ea = cea_anix(cpu, rr); ! 1408: break; ! 1409: case 7: ! 1410: switch (rr) { ! 1411: case 0: // Abs.W ! 1412: ea = cea_absw(cpu); ! 1413: break; ! 1414: case 1: // Abs.L ! 1415: ea = cea_absl(cpu); ! 1416: break; ! 1417: case 2: // d16(PC) ! 1418: ea = cea_pcdi(cpu); ! 1419: break; ! 1420: case 3: // (PC,IX) ! 1421: ea = cea_pcix(cpu); ! 1422: break; ! 1423: default: ! 1424: fpu_op_illg(cpu); ! 1425: return; ! 1426: } ! 1427: break; ! 1428: default: ! 1429: fpu_op_illg(cpu); ! 1430: return; ! 1431: } ! 1432: ! 1433: // 1ロングワード読んでみる ! 1434: data = m68030_read_32(cpu, ea); ! 1435: ea += 4; ! 1436: ! 1437: if (data == 0) { ! 1438: // NULL フレームなら、これ以上フレームはない。 ! 1439: CYCLE2(21, 22); ! 1440: ! 1441: // NULL フレームのリストアは FPU の状態をリセットする ! 1442: fpu_reset(cpu); ! 1443: } else { ! 1444: // それ以外のフレームは先頭ロングワードから長さを取得。 ! 1445: // 先頭1ロングワードは $VVLL0000 で VV がバージョン(8bit)、 ! 1446: // LL が(自身を含まないこれ以降の)バイト数 (8bit) を示している。 ! 1447: // 現在の実装ではセーブ/リストアは何も実装していないので、 ! 1448: // 全部読み捨てる。 ! 1449: ! 1450: // 実際にはフレーム種別によってサイクル数は変わるけど、ここでは ! 1451: // FSAVE は NULL フレーム以外には IDLE フレームしか吐かないので ! 1452: // IDLE フレームのサイクルだけでいい。 ! 1453: CYCLE2(57, 58); ! 1454: ! 1455: int len = (data >> 16) & 0xff; ! 1456: len /= 4; ! 1457: for (int i = 0; i < len; i++) { ! 1458: m68030_read_32(cpu, ea); ! 1459: ea += 4; ! 1460: } ! 1461: ! 1462: cpu->fpu_dirty = true; ! 1463: } ! 1464: ! 1465: // (An)+ なら書き戻し ! 1466: if (postinc) { ! 1467: RegA(rr) = ea; ! 1468: } ! 1469: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.