|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2020 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // +------ 030(without FPU) ! 8: // | +-- 030(+6888x) ! 9: // | | 040 LC040 ! 10: // S o o 4 : FSAVE/FRESTORE (有効なEA) ! 11: // F F F : FSAVE/FRESTORE (無効なEA) ! 12: // F o o 4 : 040 でも実装してある命令 (有効なEA) ! 13: // F F F : 040 でも実装してある命令 (無効なEA) ! 14: // F o 2 4 : 6888x 命令 (有効なEA) ! 15: // F F F? : 6888x 命令 (無効なEA) ! 16: // F F F F : 無効な命令ビットパターン ! 17: // ! 18: // (厳密に言えばFPU命令ではないが) ! 19: // S S F? F? : cpSAVE/cpRESTORE (有効なEA) ! 20: // F F F? F? : cpSAVE/cpRESTORE (無効なEA) ! 21: // … XEiJ の flineprivilege.x によると、無効な EA のパターンは ! 22: // 68030 では F ライン例外になる。 ! 23: // 040 ではコプロセッサプロトコル自体が廃止されているので ! 24: // ここはいずれも F ライン例外になるだろうか。 ! 25: // ! 26: // o: 有効な命令処理 ! 27: // F: F ライン例外 (Format$0) ! 28: // 2: 浮動小数点未実装例外(Format$2) ! 29: // 4: 浮動小数点未実装例外(Format$4) ! 30: // S: 特権違反例外 ! 31: ! 32: // 68040: ! 33: // Int .S .D .X .P ! 34: // ノーマル数 o o o o x ! 35: // Zero o o o o x ! 36: // Inf - o o o x ! 37: // NAN - o o o x ! 38: // 非正規化数 - x x x x ! 39: // アンノーマル数 - - - x x ! 40: // ! 41: // o: ハードウェアサポート ! 42: // x: ソフトウェアサポート ! 43: ! 44: #include "mpu680x0.h" ! 45: #include "m680x0disasm.h" ! 46: #include "textscreen.h" ! 47: ! 48: #define SIZE_L (0) ! 49: #define SIZE_S (1) ! 50: #define SIZE_X (2) ! 51: #define SIZE_P (3) ! 52: #define SIZE_W (4) ! 53: #define SIZE_D (5) ! 54: #define SIZE_B (6) ! 55: ! 56: // val が単精度で非正規化数なら true を返す。 ! 57: static inline bool ! 58: is_denormal_s(uint32 val) ! 59: { ! 60: uint32 e = (val >> 23) & 0xff; ! 61: uint32 m = val & 0x7f'ffff; ! 62: if (e == 0 && m != 0) { ! 63: return true; ! 64: } ! 65: return false; ! 66: } ! 67: ! 68: // data[0..1] が倍精度で非正規化数なら true を返す。 ! 69: static inline bool ! 70: is_denormal_d(const uint32 *data) ! 71: { ! 72: uint32 e = (data[0] >> 20) & 0x7ff; ! 73: uint64 m = ((uint64)(data[0] & 0x000f'ffff) << 32) | data[1]; ! 74: if (e == 0 && m != 0) { ! 75: return true; ! 76: } ! 77: return false; ! 78: } ! 79: ! 80: // data[0..2] が拡張精度で非正規化数なら true を返す。 ! 81: static inline bool ! 82: is_denormal_x(const uint32 *data) ! 83: { ! 84: uint32 e = (data[0] >> 16) & 0x7fff; ! 85: uint32 i = (data[1] >> 31) & 1; ! 86: uint64 m = (((uint64)(data[1] & 0x7fff'ffff)) << 32) | data[2]; ! 87: if (e == 0 && i == 0 && m != 0) { ! 88: return true; ! 89: } ! 90: return false; ! 91: } ! 92: ! 93: // data[0..2] が拡張精度でアンノーマル数なら true を返す。 ! 94: static inline bool ! 95: is_unnormal_x(const uint32 *data) ! 96: { ! 97: uint32 e = (data[0] >> 16) & 0x7fff; ! 98: uint32 i = (data[1] >> 31) & 1; ! 99: uint64 m = (((uint64)(data[1] & 0x7fff'ffff)) << 32) | data[2]; ! 100: if (e != 0 && e != 0x7fff && i == 0 && m != 0) { ! 101: return true; ! 102: } ! 103: // XXX Unnormal zero はハード処理かソフト処理か分からない。 ! 104: if (e != 0 && e != 0x7fff && i == 0 && m == 0) { ! 105: return true; ! 106: } ! 107: return false; ! 108: } ! 109: ! 110: // リセット用のレジスタ初期値 ! 111: /*static*/ struct fpframe ! 112: MPU680x0Device::initial_fpframe; ! 113: ! 114: // 初期化 ! 115: void ! 116: MPU680x0Device::fpu_init() ! 117: { ! 118: int i; ! 119: uint32_t *p; ! 120: ! 121: // XXX cpu の初期化のところと見直してマージするとか ! 122: memset(&fe, 0, sizeof(fe)); ! 123: memset(®.fpframe, 0, sizeof(reg.fpframe)); ! 124: fe.fe_fpframe = ®.fpframe; ! 125: ! 126: // FRESTORE によるリセット用に FP レジスタの初期値を用意しておく。 ! 127: // FPn は NAN に。FPSR, FPCR, FPIAR はゼロクリアされる。 ! 128: memset(&initial_fpframe, 0, sizeof(initial_fpframe)); ! 129: p = initial_fpframe.fpf_regs; ! 130: for (i = 0; i < 8; i++) { ! 131: *p++ = 0x7fff0000; ! 132: *p++ = 0xffffffff; ! 133: *p++ = 0xffffffff; ! 134: } ! 135: } ! 136: ! 137: // FPU をリセットする。 ! 138: // MPU リセット時(true)と、NULL フレームのリストア時(false)に呼ばれる。 ! 139: void ! 140: MPU680x0Device::ResetFPU(bool hard) ! 141: { ! 142: // 高速化のため、あらかじめ用意しておいたイメージをコピーする ! 143: memcpy(®.fpframe, &initial_fpframe, sizeof(initial_fpframe)); ! 144: ! 145: fpu_state = FPU_STATE_NULL; ! 146: ! 147: if (__predict_false(hard)) { ! 148: // この内部情報は NULL フレームのリストア (頻繁に起きる) のたびに ! 149: // モニタから消えるよりは、直近の1つが見え続けていてほしい。 ! 150: // ただしハードリセット前の状態は引き継がない。 ! 151: memset(&fpu40, 0, sizeof(fpu40)); ! 152: fpu40.reg1b = 0xffff; ! 153: fpu40.stag = FPU40::TAG_NONE; ! 154: fpu40.dtag = FPU40::TAG_NONE; ! 155: } ! 156: fpu40.enable = false; ! 157: } ! 158: ! 159: // FPU からの呼び出し用。 ! 160: // ! 161: // (An)+, -(An) は、サイズが増えているのとクロックが増加している(2->6)。 ! 162: // それ以外のアドレッシングモードでもクロック数は微妙に違うのだが、 ! 163: // 大きくは違わないのでそっちは本体の cea と同じということにする。 ! 164: // ! 165: // このルーチンは Dn、An、#imm には対応していないので(自明)、呼び出し側で ! 166: // 事前に弾くこと。いずれも消費クロック数は 0 なので問題ない。 ! 167: // またそれ以外のすべてのアドレッシングモードで反応するため、命令ごとに ! 168: // 対応していないアドレッシングモードは事前に弾くこと。 ! 169: inline uint32 ! 170: MPU680x0Device::cea_fpu(int bytes) ! 171: { ! 172: int n; ! 173: ! 174: switch (eamode(ir)) { ! 175: case 0: // Dn ! 176: case 1: // An ! 177: break; ! 178: case 2: // (An) ! 179: return cea_anin(eanum(ir)); ! 180: case 3: // (An)+ ! 181: CYCLE(6); ! 182: n = eanum(ir); ! 183: save_reg_pi(n); ! 184: if (bytes == 1) { ! 185: return internal_ea_anpi_1(n); ! 186: } else { ! 187: // _anpi_{2,4} のマクロは用意されてるけど、これと同じなので ! 188: reg.A[n] += bytes; ! 189: return reg.A[n] - bytes; ! 190: } ! 191: break; ! 192: case 4: // -(An) ! 193: CYCLE(6); ! 194: n = eanum(ir); ! 195: save_reg_pd(n); ! 196: if (bytes == 1) { ! 197: return internal_ea_anpd_1(n); ! 198: } else { ! 199: // _anpd_{2,4} のマクロは用意されてるけど、これと同じなので ! 200: reg.A[n] -= bytes; ! 201: return reg.A[n]; ! 202: } ! 203: break; ! 204: case 5: // d16(An) ! 205: return cea_andi(eanum(ir)); ! 206: case 6: // (An,IX) ! 207: return cea_anix(eanum(ir)); ! 208: case 7: ! 209: switch (eanum(ir)) { ! 210: case 0: // Abs.W ! 211: return cea_absw(); ! 212: case 1: // Abs.L ! 213: return cea_absl(); ! 214: case 2: // d16(PC) ! 215: return cea_pcdi(); ! 216: case 3: // (PC,IX) ! 217: return cea_pcix(); ! 218: case 4: // #imm ! 219: break; ! 220: default: ! 221: break; ! 222: } ! 223: break; ! 224: } ! 225: // 不当命令 ! 226: throw M68K::EXCEP_ILLEGAL; ! 227: } ! 228: ! 229: // メモリから 64ビット値を読み込む ! 230: void ! 231: MPU680x0Device::read_8(uint32 addr, uint32 *data) ! 232: { ! 233: data[0] = read_4(addr); ! 234: data[1] = read_4(addr + 4); ! 235: } ! 236: ! 237: // メモリから 96ビット値を読み込む ! 238: void ! 239: MPU680x0Device::read_12(uint32 addr, uint32 *data) ! 240: { ! 241: data[0] = read_4(addr); ! 242: data[1] = read_4(addr + 4); ! 243: data[2] = read_4(addr + 8); ! 244: } ! 245: ! 246: // 64ビット値をメモリに書き込む ! 247: void ! 248: MPU680x0Device::write_8(uint32 addr, const uint32 *data) ! 249: { ! 250: write_4(addr, data[0]); ! 251: write_4(addr + 4, data[1]); ! 252: } ! 253: ! 254: // 96ビット値をメモリに書き込む ! 255: void ! 256: MPU680x0Device::write_12(uint32 addr, const uint32 *data) ! 257: { ! 258: write_4(addr, data[0]); ! 259: write_4(addr + 4, data[1]); ! 260: write_4(addr + 8, data[2]); ! 261: } ! 262: ! 263: // ソースを data[] に読み込む。 ! 264: // 不当命令パターンなら false を返す。 ! 265: // size_id は SIZE_*。 ! 266: bool ! 267: MPU680x0Device::readSRC(int size_id, uint32 *data) ! 268: { ! 269: uint mr = ir & 0x3f; ! 270: ! 271: // 68881 本(p6-13) にはクロック数はこう書いてあるので ! 272: // Inst | src=FPn | memory source or dst operand format ! 273: // | | Int Sgl Dbl Ext Pakced ! 274: // ---- +---------- +------ ------- ------- ------- ------- ! 275: // FABS | 35 | 62 54 60 58 872 ! 276: // (差分) +27 +19 +25 +23 +837 ! 277: // FADD | 51 | 80 72 78 76 888 ! 278: // (差分) +29 +21 +27 +25 +837 ! 279: // ! 280: // FABS.X FPn,FPm は 35 としてこれは fgen() 内で加算。 ! 281: // FABS.L <ea>,FPm は 62 クロックなので、ここでは差分の 27 を加算。 ! 282: // FABS.L Dn,FPm の場合 src がレジスタなので 62 から 5 引く。 ! 283: // FABS.P <ea>,FPm は 872 クロックなので、ここでは差分の 837 を加算。 ! 284: // ! 285: // XXX 多くの命令が FABS と同じだけの差分だが、 ! 286: // FADD などいくつかは .P 以外に +2 クロックの追加があるようだ。 ! 287: // どうしたもんか。 ! 288: ! 289: if (mr < 8) { // Dn ! 290: switch (size_id) { ! 291: case SIZE_B: ! 292: data[0] = (int32)(int8)reg.D[mr]; ! 293: break; ! 294: case SIZE_W: ! 295: data[0] = (int32)(int16)reg.D[mr]; ! 296: break; ! 297: case SIZE_L: ! 298: case SIZE_S: ! 299: data[0] = reg.D[mr]; ! 300: break; ! 301: default: ! 302: return false; ! 303: } ! 304: // XXX EA はどうなる? ! 305: ! 306: // ソースが Dn の場合は 5クロック減 ! 307: CYCLE(-5); ! 308: } else if (mr == 0x3c) { // #imm ! 309: switch (size_id) { ! 310: case SIZE_B: ! 311: data[0] = fetch_2() & 0xff; ! 312: break; ! 313: case SIZE_W: ! 314: data[0] = fetch_2(); ! 315: break; ! 316: case SIZE_L: ! 317: case SIZE_S: ! 318: data[0] = fetch_4(); ! 319: break; ! 320: case SIZE_D: ! 321: data[0] = fetch_4(); ! 322: data[1] = fetch_4(); ! 323: break; ! 324: case SIZE_X: ! 325: case SIZE_P: ! 326: data[0] = fetch_4(); ! 327: data[1] = fetch_4(); ! 328: data[2] = fetch_4(); ! 329: break; ! 330: default: ! 331: return false; ! 332: } ! 333: // XXX EA はどうなる? ! 334: } else { ! 335: // それ以外は EA を求めてからメモリから読み込む ! 336: uint32 ea; ! 337: switch (size_id) { ! 338: case SIZE_B: ! 339: ea = cea_fpu(1); ! 340: data[0] = (int32)(int8)read_1(ea); ! 341: break; ! 342: case SIZE_W: ! 343: ea = cea_fpu(2); ! 344: data[0] = (int32)(int16)read_2(ea); ! 345: break; ! 346: case SIZE_L: ! 347: case SIZE_S: ! 348: ea = cea_fpu(4); ! 349: data[0] = read_4(ea); ! 350: break; ! 351: case SIZE_D: ! 352: ea = cea_fpu(8); ! 353: read_8(ea, data); ! 354: break; ! 355: case SIZE_X: ! 356: case SIZE_P: ! 357: ea = cea_fpu(12); ! 358: read_12(ea, data); ! 359: break; ! 360: default: ! 361: return false; ! 362: } ! 363: fpu40.ea = ea; ! 364: } ! 365: ! 366: return true; ! 367: } ! 368: ! 369: // FPU 不当命令 (1ワード目で確定) ! 370: void ! 371: MPU680x0Device::fpu_op_illg() ! 372: { ! 373: putlog(1, "FPU illegal instruction %04X", ir); ! 374: Exception(M68K::EXCEP_FLINE); ! 375: } ! 376: ! 377: // FPU 不当命令 (2ワード目で確定) ! 378: void ! 379: MPU680x0Device::fpu_op_illg2() ! 380: { ! 381: putlog(1, "FPU illegal instruction %04X %04X", ir, ir2); ! 382: Exception(M68K::EXCEP_FLINE); ! 383: } ! 384: ! 385: // R/M=0 (レジスタ-レジスタ演算)、opclass=%000 ! 386: void ! 387: MPU680x0Device::fpu_op_fgen_reg() ! 388: { ! 389: uint srcnum = (ir2 >> 10) & 7; ! 390: ! 391: fgen(&RegFP(srcnum), SIZE_X); ! 392: } ! 393: ! 394: // R/M=1 (メモリ-レジスタ演算)、opclass=%010 ! 395: void ! 396: MPU680x0Device::fpu_op_fgen_mem() ! 397: { ! 398: uint size_id = (ir2 >> 10) & 7; ! 399: uint32 data[3]; ! 400: ! 401: // source specifier はオペランドサイズ ! 402: if (size_id == 7) { ! 403: // こんなところに FMOVECR ! 404: fpu_op_fmovecr(); ! 405: return; ! 406: } ! 407: ! 408: // 第1ワードの EA がソース EA ! 409: if (!readSRC(size_id, data)) { ! 410: fpu_op_illg2(); ! 411: return; ! 412: } ! 413: ! 414: fgen(data, size_id); ! 415: } ! 416: ! 417: // 一般算術演算。 ! 418: // srcdata, srcsize_id がソースの生データとサイズ識別子。 ! 419: // デスティネーション(FPn) は ir2 から求まる。 ! 420: void ! 421: MPU680x0Device::fgen(const uint32 *srcdata, uint srcsize_id) ! 422: { ! 423: uint opmode = ir2 & 0x3f; ! 424: uint dstnum = (ir2 >> 7) & 7; ! 425: bool discard_result = false; ! 426: struct fpn *res = NULL; // shutup gcc ! 427: ! 428: // 機種別の前処理。 ! 429: if (GetFPUType().Is4060FPU()) { ! 430: // 未実装命令と未実装データ型の検出など。 ! 431: if (fgen040pre(opmode, dstnum, srcdata, srcsize_id) == false) { ! 432: return; ! 433: } ! 434: } else { ! 435: // fe_f1, fe_f2 にロードするだけ。 ! 436: fgen881pre(dstnum, srcdata, srcsize_id); ! 437: } ! 438: ! 439: switch (opmode) { ! 440: case 0x00: // FMOVE ! 441: fmove: ! 442: CYCLE(33); ! 443: res = &fe.fe_f2; ! 444: fpu_round_prec(&fe, res); ! 445: break; ! 446: case 0x01: // FINT ! 447: CYCLE(55); ! 448: res = fpu_int(&fe); ! 449: break; ! 450: case 0x02: // FSINH ! 451: CYCLE(687); ! 452: res = fpu_sinh(&fe); ! 453: fpu_round_prec(&fe, res); ! 454: break; ! 455: case 0x03: // FINTRZ ! 456: CYCLE(55); ! 457: res = fpu_intrz(&fe); ! 458: break; ! 459: case 0x04: // FSQRT ! 460: fsqrt: ! 461: CYCLE(107); ! 462: res = fpu_sqrt(&fe); ! 463: fpu_round_prec(&fe, res); ! 464: break; ! 465: case 0x06: // FLOGNP1 ! 466: CYCLE(571); ! 467: res = fpu_lognp1(&fe); ! 468: fpu_round_prec(&fe, res); ! 469: break; ! 470: case 0x08: // FETOXM1 ! 471: CYCLE(545); ! 472: res = fpu_etoxm1(&fe); ! 473: fpu_round_prec(&fe, res); ! 474: break; ! 475: case 0x09: // FTANH ! 476: CYCLE(661); ! 477: res = fpu_tanh(&fe); ! 478: fpu_round_prec(&fe, res); ! 479: break; ! 480: case 0x0a: // FATAN ! 481: CYCLE(403); ! 482: res = fpu_atan(&fe); ! 483: fpu_round_prec(&fe, res); ! 484: break; ! 485: case 0x0c: // FASIN ! 486: CYCLE(581); ! 487: res = fpu_asin(&fe); ! 488: fpu_round_prec(&fe, res); ! 489: break; ! 490: case 0x0d: // FATANH ! 491: CYCLE(693); ! 492: res = fpu_atanh(&fe); ! 493: fpu_round_prec(&fe, res); ! 494: break; ! 495: case 0x0e: // FSIN ! 496: CYCLE(391); ! 497: res = fpu_sin(&fe); ! 498: fpu_round_prec(&fe, res); ! 499: break; ! 500: case 0x0f: // FTAN ! 501: CYCLE(473); ! 502: res = fpu_tan(&fe); ! 503: fpu_round_prec(&fe, res); ! 504: break; ! 505: case 0x10: // FETOX ! 506: CYCLE(497); ! 507: res = fpu_etox(&fe); ! 508: fpu_round_prec(&fe, res); ! 509: break; ! 510: case 0x11: // FTWOTOX ! 511: CYCLE(567); ! 512: res = fpu_twotox(&fe); ! 513: fpu_round_prec(&fe, res); ! 514: break; ! 515: case 0x12: // FTENTOX ! 516: CYCLE(567); ! 517: res = fpu_tentox(&fe); ! 518: fpu_round_prec(&fe, res); ! 519: break; ! 520: case 0x14: // FLOGN ! 521: CYCLE(525); ! 522: res = fpu_logn(&fe); ! 523: fpu_round_prec(&fe, res); ! 524: break; ! 525: case 0x15: // FLOG10 ! 526: CYCLE(581); ! 527: res = fpu_log10(&fe); ! 528: fpu_round_prec(&fe, res); ! 529: break; ! 530: case 0x16: // FLOG2 ! 531: CYCLE(581); ! 532: res = fpu_log2(&fe); ! 533: fpu_round_prec(&fe, res); ! 534: break; ! 535: case 0x18: // FABS ! 536: fabs: ! 537: CYCLE(35); ! 538: fe.fe_f2.fp_sign = 0; ! 539: res = &fe.fe_f2; ! 540: fpu_round_prec(&fe, res); ! 541: break; ! 542: case 0x19: // FCOSH ! 543: CYCLE(607); ! 544: res = fpu_cosh(&fe); ! 545: fpu_round_prec(&fe, res); ! 546: break; ! 547: case 0x1a: // FNEG ! 548: fneg: ! 549: CYCLE(35); ! 550: res = &fe.fe_f2; ! 551: if (!ISNAN(res)) { ! 552: res->fp_sign = !res->fp_sign; ! 553: fpu_round_prec(&fe, res); ! 554: } ! 555: break; ! 556: case 0x1c: // FACOS ! 557: CYCLE(625); ! 558: res = fpu_acos(&fe); ! 559: fpu_round_prec(&fe, res); ! 560: break; ! 561: case 0x1d: // FCOS ! 562: CYCLE(391); ! 563: res = fpu_cos(&fe); ! 564: fpu_round_prec(&fe, res); ! 565: break; ! 566: case 0x1e: // FGETEXP ! 567: CYCLE(45); ! 568: res = fpu_getexp(&fe); ! 569: fpu_round_prec(&fe, res); ! 570: break; ! 571: case 0x1f: // FGETMAN ! 572: CYCLE(31); ! 573: res = fpu_getman(&fe); ! 574: fpu_round_prec(&fe, res); ! 575: break; ! 576: case 0x20: // FDIV ! 577: fdiv: ! 578: CYCLE(103); ! 579: res = fpu_div(&fe); ! 580: fpu_round_prec(&fe, res); ! 581: break; ! 582: case 0x21: // FMOD ! 583: CYCLE(67); ! 584: res = fpu_mod(&fe); ! 585: fpu_round_prec(&fe, res); ! 586: break; ! 587: case 0x22: // FADD ! 588: fadd: ! 589: CYCLE(51); ! 590: res = fpu_add(&fe); ! 591: fpu_round_prec(&fe, res); ! 592: break; ! 593: case 0x23: // FMUL ! 594: fmul: ! 595: CYCLE(71); ! 596: res = fpu_mul(&fe); ! 597: fpu_round_prec(&fe, res); ! 598: break; ! 599: case 0x24: // FSGLDIV ! 600: CYCLE(69); ! 601: res = fpu_sgldiv(&fe); ! 602: break; ! 603: case 0x25: // FREM ! 604: CYCLE(67); ! 605: res = fpu_rem(&fe); ! 606: fpu_round_prec(&fe, res); ! 607: break; ! 608: case 0x26: // FSCALE ! 609: // こいつだけ形式が違う。 ! 610: // 結果は dst に直接格納済み、FPSR も演算済み。 ! 611: CYCLE(41); ! 612: fpu_emul_fscale(&fe, ir2); ! 613: return; ! 614: case 0x27: // FSGLMUL ! 615: CYCLE(59); ! 616: res = fpu_sglmul(&fe); ! 617: break; ! 618: case 0x28: // FSUB ! 619: fsub: ! 620: CYCLE(51); ! 621: res = fpu_sub(&fe); ! 622: fpu_round_prec(&fe, res); ! 623: break; ! 624: case 0x30: ! 625: case 0x31: ! 626: case 0x32: ! 627: case 0x33: ! 628: case 0x34: ! 629: case 0x35: ! 630: case 0x36: ! 631: case 0x37: // FSINCOS ! 632: CYCLE(451); ! 633: res = fpu_sincos(&fe, opmode & 7); ! 634: fpu_round_prec(&fe, res); ! 635: break; ! 636: case 0x38: // FCMP ! 637: CYCLE(33); ! 638: res = fpu_cmp(&fe); ! 639: discard_result = 1; ! 640: break; ! 641: case 0x3a: // FTST ! 642: CYCLE(33); ! 643: res = &fe.fe_f2; ! 644: discard_result = 1; ! 645: break; ! 646: ! 647: #define ONLY_40 do { \ ! 648: if (GetFPUType().Is40FPU() == false) { \ ! 649: goto illegal; \ ! 650: } \ ! 651: } while (0) ! 652: // fe の精度だけ変える。 ! 653: // fe_fpcr は RegFPCR (レジスタ) のほうには伝搬しないし、 ! 654: // 次の命令の冒頭でまた RegFPCR から上書きされるので、 ! 655: // 書き換えっぱなしでよい。 ! 656: #define ROUND_FS do { \ ! 657: fe.fe_fpcr &= ~FPCR_PREC; \ ! 658: fe.fe_fpcr |= FPCR_SNGL; \ ! 659: } while (0) ! 660: #define ROUND_FD do { \ ! 661: fe.fe_fpcr &= ~FPCR_PREC; \ ! 662: fe.fe_fpcr |= FPCR_DBL; \ ! 663: } while (0) ! 664: ! 665: case 0x40: ONLY_40; ROUND_FS; goto fmove; // FSMOVE ! 666: case 0x44: ONLY_40; ROUND_FD; goto fmove; // FDMOVE ! 667: case 0x41: ONLY_40; ROUND_FS; goto fsqrt; // FSSQRT ! 668: case 0x45: ONLY_40; ROUND_FD; goto fsqrt; // FDSQRT ! 669: case 0x58: ONLY_40; ROUND_FS; goto fabs; // FSABS ! 670: case 0x5c: ONLY_40; ROUND_FD; goto fabs; // FDABS ! 671: case 0x5a: ONLY_40; ROUND_FS; goto fneg; // FSNEG ! 672: case 0x5e: ONLY_40; ROUND_FD; goto fneg; // FDNEG ! 673: case 0x60: ONLY_40; ROUND_FS; goto fdiv; // FSDIV ! 674: case 0x64: ONLY_40; ROUND_FD; goto fdiv; // FDDIV ! 675: case 0x62: ONLY_40; ROUND_FS; goto fadd; // FSADD ! 676: case 0x66: ONLY_40; ROUND_FD; goto fadd; // FDADD ! 677: case 0x63: ONLY_40; ROUND_FS; goto fmul; // FSMUL ! 678: case 0x67: ONLY_40; ROUND_FD; goto fmul; // FDMUL ! 679: case 0x68: ONLY_40; ROUND_FS; goto fsub; // FSSUB ! 680: case 0x6c: ONLY_40; ROUND_FD; goto fsub; // FDSUB ! 681: ! 682: illegal: ! 683: default: ! 684: // 不当命令 ! 685: fpu_op_illg2(); ! 686: return; ! 687: } ! 688: ! 689: assert(res); ! 690: if (!discard_result) { ! 691: fpu_implode(&fe, res, FTYPE_EXT, &RegFP(dstnum)); ! 692: } ! 693: fpu_upd_fpsr(&fe, res); ! 694: fpu_upd_excp(&fe); ! 695: } ! 696: ! 697: // fgen() の 68881 での前処理。 ! 698: // src, dst を fe_f2, fe_f1 にそれぞれロードするだけ。 ! 699: void ! 700: MPU680x0Device::fgen881pre(uint dstnum, const uint32 *srcdata, uint srcsize_id) ! 701: { ! 702: switch (srcsize_id) { ! 703: case SIZE_B: ! 704: case SIZE_W: ! 705: case SIZE_L: ! 706: CYCLE(+27); ! 707: fpu_explode(&fe, &fe.fe_f2, FTYPE_LNG, srcdata); ! 708: break; ! 709: case SIZE_S: ! 710: CYCLE(+19); ! 711: fpu_explode(&fe, &fe.fe_f2, FTYPE_SNG, srcdata); ! 712: break; ! 713: case SIZE_D: ! 714: CYCLE(+25); ! 715: fpu_explode(&fe, &fe.fe_f2, FTYPE_DBL, srcdata); ! 716: break; ! 717: case SIZE_X: ! 718: CYCLE(+23); ! 719: fpu_explode(&fe, &fe.fe_f2, FTYPE_EXT, srcdata); ! 720: break; ! 721: case SIZE_P: ! 722: CYCLE(+837); ! 723: fpu_explode(&fe, &fe.fe_f2, FTYPE_BCD, srcdata); ! 724: break; ! 725: default: ! 726: __unreachable(); ! 727: } ! 728: fpu_explode(&fe, &fe.fe_f1, FTYPE_EXT, &RegFP(dstnum)); ! 729: } ! 730: ! 731: // fgen() の 68040 での前処理。 ! 732: // 未実装命令のチェックと該当すればその例外処理、 ! 733: // 未実装データ型のチェックと該当すればその例外処理を行う。 ! 734: // 例外処理を行った場合は false を返す。 ! 735: bool ! 736: MPU680x0Device::fgen040pre(uint opmode, uint dstnum, ! 737: const uint32 *srcdata, uint srcsize_id) ! 738: { ! 739: // 未実装命令か調べる。 ! 740: bool unimpl = false; ! 741: switch (opmode) { ! 742: case 0x01: // FINT ! 743: case 0x02: // FSINH ! 744: case 0x03: // FINTRZ ! 745: case 0x06: // FLOGNP1 ! 746: case 0x08: // FETOXM1 ! 747: case 0x09: // FTANH ! 748: case 0x0a: // FATAN ! 749: case 0x0c: // FASIN ! 750: case 0x0d: // FATANH ! 751: case 0x0e: // FSIN ! 752: case 0x0f: // FTAN ! 753: case 0x10: // FETOX ! 754: case 0x11: // FTWOTOX ! 755: case 0x12: // FTENTOX ! 756: case 0x14: // FLOGN ! 757: case 0x15: // FLOG10 ! 758: case 0x16: // FLOG2 ! 759: case 0x19: // FCOSH ! 760: case 0x1c: // FACOS ! 761: case 0x1d: // FCOS ! 762: case 0x1e: // FGETEXP ! 763: case 0x1f: // FGETMAN ! 764: case 0x21: // FMOD ! 765: case 0x25: // FREM ! 766: case 0x26: // FSCALE ! 767: case 0x30: // FSINCOS ! 768: case 0x31: // FSINCOS ! 769: case 0x32: // FSINCOS ! 770: case 0x33: // FSINCOS ! 771: case 0x34: // FSINCOS ! 772: case 0x35: // FSINCOS ! 773: case 0x36: // FSINCOS ! 774: case 0x37: // FSINCOS ! 775: unimpl = true; ! 776: break; ! 777: default: ! 778: break; ! 779: } ! 780: ! 781: // ソースがサポートしている型なら拡張精度に変換して fe_f2 にセットし、 ! 782: // stag は NONE のままか NORMAL or ZERO をセット。 ! 783: // 未サポート型なら所定の etemp を作成して stag は DENORMAL か UNNORMAL。 ! 784: // ! 785: // Int .S/.D .X .P ! 786: // Normal fe_f2,NORM fe_f2,NONE fe_f2,NONE etemp,UNNO ! 787: // Zero fe_f2,ZERO fe_f2,NONE fe_f2,NONE etemp,UNNO ! 788: // Inf - fe_f2,NONE fe_f2,NONE etemp,UNNO ! 789: // NAN - fe_f2,NONE fe_f2,NONE etemp,UNNO ! 790: // Denorm - etemp,DENO etemp,UNNO etemp,UNNO ! 791: // Unnorm - - etemp,UNNO etemp,UNNO ! 792: ! 793: int32 stag = FPU40::TAG_NONE; ! 794: switch (srcsize_id) { ! 795: case SIZE_B: ! 796: case SIZE_W: ! 797: case SIZE_L: ! 798: CYCLE(+27); ! 799: if (srcdata[0] == 0) { ! 800: stag = FPU40::TAG_ZERO; ! 801: } else { ! 802: stag = FPU40::TAG_NORMAL; ! 803: } ! 804: fpu_explode(&fe, &fe.fe_f2, FTYPE_LNG, srcdata); ! 805: break; ! 806: case SIZE_S: ! 807: CYCLE(+19); ! 808: if (is_denormal_s(srcdata[0])) { ! 809: // 68040UM.pdf, p9-24. Figure 9-9 (a) ! 810: uint32 s = srcdata[0] & 0x8000'0000; ! 811: uint32 m = srcdata[0] & 0x007f'ffff; ! 812: fpu40.etemp[0] = s; ! 813: fpu40.etemp[1] = m << 8; ! 814: fpu40.etemp[2] = 0; ! 815: stag = FPU40::TAG_DENORMAL_S; ! 816: break; ! 817: } ! 818: fpu_explode(&fe, &fe.fe_f2, FTYPE_SNG, srcdata); ! 819: break; ! 820: case SIZE_D: ! 821: CYCLE(+25); ! 822: if (is_denormal_d(srcdata)) { ! 823: // 68040UM.pdf, p9-24. Figure 9-9 (b) ! 824: uint32 s = srcdata[0] & 0x8000'0000; ! 825: uint64 m = ((uint64)(srcdata[0] & 0x000f'ffff) << 32) | srcdata[1]; ! 826: m <<= 11; ! 827: fpu40.etemp[0] = s; ! 828: fpu40.etemp[1] = m >> 32; ! 829: fpu40.etemp[2] = m & 0xffffffff; ! 830: stag = FPU40::TAG_DENORMAL_D; ! 831: break; ! 832: } ! 833: fpu_explode(&fe, &fe.fe_f2, FTYPE_DBL, srcdata); ! 834: break; ! 835: case SIZE_X: ! 836: CYCLE(+23); ! 837: if (is_denormal_x(srcdata)) { ! 838: memcpy(fpu40.etemp, srcdata, 12); ! 839: stag = FPU40::TAG_DENORMAL_X; ! 840: break; ! 841: } else if (is_unnormal_x(srcdata)) { ! 842: memcpy(fpu40.etemp, srcdata, 12); ! 843: stag = FPU40::TAG_UNNORMAL_X; ! 844: break; ! 845: } ! 846: fpu_explode(&fe, &fe.fe_f2, FTYPE_EXT, srcdata); ! 847: break; ! 848: case SIZE_P: ! 849: // 上位32ビットを FPTM[31-00] に、 ! 850: // 下位64ビットを ETM[31-00] に置く。(68040UM.pdf, pp.9-42〜43) ! 851: fpu40.fptemp[2] = srcdata[0]; ! 852: fpu40.etemp[1] = srcdata[1]; ! 853: fpu40.etemp[2] = srcdata[2]; ! 854: // Packed の時 stag は undefined と書いてある。 ! 855: // ここではこの後の例外判定用および表示用として使う。 ! 856: stag = FPU40::TAG_PACKED; ! 857: break; ! 858: default: ! 859: __unreachable(); ! 860: } ! 861: ! 862: // デスティネーション(レジスタ) が未サポートデータ型になるのは ! 863: // 非正規化数の時だけのはず。 ! 864: int32 dtag = FPU40::TAG_NONE; ! 865: if (is_denormal_x(&RegFP(dstnum))) { ! 866: dtag = FPU40::TAG_DENORMAL_X; ! 867: } ! 868: fpu_explode(&fe, &fe.fe_f1, FTYPE_EXT, &RegFP(dstnum)); ! 869: if (dtag == FPU40::TAG_NONE) { ! 870: dtag = fpu_gettag(&fe.fe_f1); ! 871: } ! 872: ! 873: // 例外を起こす必要があるか。 ! 874: if (unimpl || ! 875: stag >= FPU40::TAG_UNNORMAL || ! 876: dtag >= FPU40::TAG_UNNORMAL) ! 877: { ! 878: // stag がまだならここで fpn から決まる。 ! 879: if (stag == FPU40::TAG_NONE) { ! 880: stag = fpu_gettag(&fe.fe_f2); ! 881: } ! 882: // stag が UNNORMAL, DENORMAL なら etemp はセット済み。 ! 883: if (stag < FPU40::TAG_UNNORMAL) { ! 884: fpu_implode(&fe, &fe.fe_f2, FTYPE_EXT, fpu40.etemp); ! 885: } ! 886: // Packed なら E1 を立てる、 ! 887: // また FPTEMP にはソースを展開済みなので dst を書き込まない。 ! 888: // XXX 68040UM.pdf p.9-44 Table 9-16 Unimplemented Instruction には ! 889: // E1 は always 1 とあるが、p.9-42 の E1 の説明のほうが正しそう。 ! 890: if (srcsize_id == SIZE_P) { ! 891: fpu40.eflag = FPU40::E1; ! 892: } else { ! 893: fpu40.eflag = 0; ! 894: memcpy(&fpu40.fptemp, &RegFP(dstnum), 12); ! 895: } ! 896: fpu40.stag = stag; ! 897: fpu40.dtag = dtag; ! 898: if (unimpl) { ! 899: ExceptionFP(M68K::EXCEP_FP_UNIMPL); ! 900: } else { ! 901: ExceptionFP(M68K::EXCEP_FP_UNSUPP); ! 902: } ! 903: return false; ! 904: } ! 905: ! 906: // ハードウェア処理可能。 ! 907: ! 908: // 68040 では条件命令以外 (たぶん実質クラス0命令) を実行すると ! 909: // NULL -> IDLE 状態になる。68040UM.pdf, p9-39 ! 910: fpu_state = FPU_STATE_IDLE; ! 911: ! 912: return true; ! 913: } ! 914: ! 915: // FMOVECR ! 916: void ! 917: MPU680x0Device::fpu_op_fmovecr() ! 918: { ! 919: if (GetFPUType().Is4060FPU()) { ! 920: ExceptionFP(M68K::EXCEP_FP_UNIMPL); ! 921: return; ! 922: } ! 923: ! 924: CYCLE(29); ! 925: ! 926: uint offset = (ir2 & 0x7f); ! 927: uint dstnum = (ir2 >> 7) & 7; ! 928: ! 929: fpu_const(&fe.fe_f3, offset); ! 930: fpu_implode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(dstnum)); ! 931: fpu_upd_fpsr(&fe, &fe.fe_f3); ! 932: fpu_upd_excp(&fe); ! 933: } ! 934: ! 935: // FMOVE FPn,<ea> ! 936: void ! 937: MPU680x0Device::fpu_op_fmove_to_mem() ! 938: { ! 939: // サイズごとに分岐 ! 940: uint size = (ir2 >> 10) & 7; ! 941: switch (size) { ! 942: case SIZE_B: ! 943: fpu_op_fmove_b_mem(); ! 944: break; ! 945: case SIZE_W: ! 946: fpu_op_fmove_w_mem(); ! 947: break; ! 948: case SIZE_L: ! 949: fpu_op_fmove_l_mem(); ! 950: break; ! 951: case SIZE_S: ! 952: fpu_op_fmove_s_mem(); ! 953: break; ! 954: case SIZE_D: ! 955: fpu_op_fmove_d_mem(); ! 956: break; ! 957: case SIZE_X: ! 958: fpu_op_fmove_x_mem(); ! 959: break; ! 960: case SIZE_P: ! 961: case 7: ! 962: fpu_op_fmove_p_mem(); ! 963: break; ! 964: } ! 965: } ! 966: ! 967: // FMOVE.B FPn,<ea> ! 968: // cf. 68000PRM.pdf p378 (5-76) ! 969: void ! 970: MPU680x0Device::fpu_op_fmove_b_mem() ! 971: { ! 972: uint mr = ir & 0x3f; ! 973: uint srcnum = (ir2 >> 7) & 7; ! 974: uint32 ea; ! 975: uint32 data; ! 976: ! 977: fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum)); ! 978: fpu_implode(&fe, &fe.fe_f3, FTYPE_LNG, &data); ! 979: // 入力値は long か、long で表現できなければ 0x80000000 が返ってくるが、 ! 980: // ここはバイトへの変換なので表現できなければ 0x80 にする。 ! 981: if ((int32)data < INT8_MIN || (int32)data > INT8_MAX) { ! 982: data = 0x80; ! 983: RegFPSR |= FPSR_OPERR | FPSR_AIOP; ! 984: } ! 985: ! 986: if (mr < 8) { // Dn ! 987: CYCLE(100-2); ! 988: reg.D[mr] &= 0xffffff00; ! 989: reg.D[mr] |= (uint8)data; ! 990: } else { ! 991: CYCLE(100); ! 992: ea = cea_fpu(1); ! 993: write_1(ea, (uint8)data); ! 994: } ! 995: } ! 996: ! 997: // FMOVE.W FPn,<ea> ! 998: // cf. 68000PRM.pdf p378 (5-76) ! 999: void ! 1000: MPU680x0Device::fpu_op_fmove_w_mem() ! 1001: { ! 1002: uint mr = ir & 0x3f; ! 1003: uint srcnum = (ir2 >> 7) & 7; ! 1004: uint32 ea; ! 1005: uint32 data; ! 1006: ! 1007: fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum)); ! 1008: fpu_implode(&fe, &fe.fe_f3, FTYPE_LNG, &data); ! 1009: // 入力値は long か、long で表現できなければ 0x80000000 が返ってくるが、 ! 1010: // ここはワードへの変換なので表現できなければ 0x8000 にする。 ! 1011: if ((int32)data < INT16_MIN || (int32)data > INT16_MAX) { ! 1012: data = 0x8000; ! 1013: RegFPSR |= FPSR_OPERR | FPSR_AIOP; ! 1014: } ! 1015: ! 1016: if (mr < 8) { // Dn ! 1017: CYCLE(100-2); ! 1018: reg.D[mr] &= 0xffff0000; ! 1019: reg.D[mr] |= (uint16)data; ! 1020: } else { ! 1021: CYCLE(100); ! 1022: ea = cea_fpu(2); ! 1023: write_2(ea, (uint16)data); ! 1024: } ! 1025: } ! 1026: ! 1027: // FMOVE.L FPn,<ea> ! 1028: // cf. 68000PRM.pdf p378 (5-76) ! 1029: void ! 1030: MPU680x0Device::fpu_op_fmove_l_mem() ! 1031: { ! 1032: uint mr = ir & 0x3f; ! 1033: uint srcnum = (ir2 >> 7) & 7; ! 1034: uint32 ea; ! 1035: uint32 data; ! 1036: ! 1037: fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum)); ! 1038: fpu_implode(&fe, &fe.fe_f3, FTYPE_LNG, &data); ! 1039: // XXX オーバーフローチェック ! 1040: ! 1041: if (mr < 8) { // Dn ! 1042: CYCLE(100-2); ! 1043: reg.D[mr] = data; ! 1044: } else { ! 1045: CYCLE(100); ! 1046: ea = cea_fpu(4); ! 1047: write_4(ea, data); ! 1048: } ! 1049: } ! 1050: ! 1051: // FMOVE.S FPn,<ea> ! 1052: // cf. 68000PRM.pdf p378 (5-76) ! 1053: void ! 1054: MPU680x0Device::fpu_op_fmove_s_mem() ! 1055: { ! 1056: uint mr = ir & 0x3f; ! 1057: uint srcnum = (ir2 >> 7) & 7; ! 1058: uint32 ea; ! 1059: uint32 data; ! 1060: ! 1061: fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum)); ! 1062: fpu_implode(&fe, &fe.fe_f3, FTYPE_SNG, &data); ! 1063: ! 1064: // 変換時に検出した UNFL, OVFL だけ外部レジスタにコピー。 ! 1065: fe.fe_fpframe->fpf_fpsr &= ~(FPSR_UNFL | FPSR_OVFL); ! 1066: fe.fe_fpframe->fpf_fpsr |= fe.fe_fpsr & (FPSR_UNFL | FPSR_OVFL); ! 1067: // アクルードバイトは更新。 ! 1068: fpu_upd_excp(&fe); ! 1069: ! 1070: if (mr < 8) { // Dn ! 1071: CYCLE(80-2); ! 1072: reg.D[mr] = data; ! 1073: } else { ! 1074: CYCLE(80); ! 1075: ea = cea_fpu(4); ! 1076: write_4(ea, data); ! 1077: } ! 1078: } ! 1079: ! 1080: // FMOVE.D FPn,<ea> ! 1081: // cf. 68000PRM.pdf p378 (5-76) ! 1082: void ! 1083: MPU680x0Device::fpu_op_fmove_d_mem() ! 1084: { ! 1085: CYCLE(86); ! 1086: ! 1087: uint srcnum = (ir2 >> 7) & 7; ! 1088: uint32 ea; ! 1089: uint32 data[2]; ! 1090: ! 1091: fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum)); ! 1092: fpu_implode(&fe, &fe.fe_f3, FTYPE_DBL, data); ! 1093: ! 1094: // 変換時に検出した UNFL, OVFL だけ外部レジスタにコピー。 ! 1095: fe.fe_fpframe->fpf_fpsr &= ~(FPSR_UNFL | FPSR_OVFL); ! 1096: fe.fe_fpframe->fpf_fpsr |= fe.fe_fpsr & (FPSR_UNFL | FPSR_OVFL); ! 1097: // アクルードバイトは更新。 ! 1098: fpu_upd_excp(&fe); ! 1099: ! 1100: ea = cea_fpu(8); ! 1101: write_8(ea, data); ! 1102: } ! 1103: ! 1104: // FMOVE.X FPn,<ea> ! 1105: // cf. 68000PRM.pdf p378 (5-76) ! 1106: void ! 1107: MPU680x0Device::fpu_op_fmove_x_mem() ! 1108: { ! 1109: CYCLE(72); ! 1110: ! 1111: uint srcnum = (ir2 >> 7) & 7; ! 1112: uint32 ea; ! 1113: uint32 data[3]; ! 1114: ! 1115: fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum)); ! 1116: fpu_implode(&fe, &fe.fe_f3, FTYPE_EXT, data); ! 1117: ! 1118: // 変換時に検出した UNFL, OVFL だけ外部レジスタにコピー。 ! 1119: fe.fe_fpframe->fpf_fpsr &= ~(FPSR_UNFL | FPSR_OVFL); ! 1120: fe.fe_fpframe->fpf_fpsr |= fe.fe_fpsr & (FPSR_UNFL | FPSR_OVFL); ! 1121: // アクルードバイトは更新。 ! 1122: fpu_upd_excp(&fe); ! 1123: ! 1124: ea = cea_fpu(12); ! 1125: write_12(ea, data); ! 1126: } ! 1127: ! 1128: // FMOVE.P FPn,<ea> ! 1129: // cf. 68000PRM.pdf p378 (5-76) ! 1130: void ! 1131: MPU680x0Device::fpu_op_fmove_p_mem() ! 1132: { ! 1133: uint srcnum = (ir2 >> 7) & 7; ! 1134: uint32 ea; ! 1135: uint32 data[3]; ! 1136: uint32 k; ! 1137: ! 1138: if (GetFPUType().Is4060FPU()) { ! 1139: ExceptionFP(M68K::EXCEP_FP_UNIMPL); ! 1140: return; ! 1141: } ! 1142: ! 1143: if ((ir2 & 0x1000)) { ! 1144: // dynamic k-factor ! 1145: CYCLE(1996+14); ! 1146: k = reg.D[(ir2 >> 4) & 7]; ! 1147: } else { ! 1148: // static k-factor ! 1149: CYCLE(1996); ! 1150: k = ir2; ! 1151: } ! 1152: // k は7ビット符号付き数 ! 1153: k &= 0x7f; ! 1154: if ((k & 0x40)) { ! 1155: k = (int32)(int8)(k | 0x80); ! 1156: } ! 1157: ! 1158: fpu_explode(&fe, &fe.fe_f3, FTYPE_EXT, &RegFP(srcnum)); ! 1159: fpu_ftop(&fe, &fe.fe_f3, data, k); ! 1160: ! 1161: ea = cea_fpu(12); ! 1162: write_12(ea, data); ! 1163: } ! 1164: ! 1165: // FMOVEM.L <ea>,<ctllist> ! 1166: // 1111 ccc 000 mmmrrr | 10D RRR 0000 000000 ! 1167: // D=0: <ea> to FPctl ! 1168: // RRR: register list ! 1169: void ! 1170: MPU680x0Device::fpu_op_fmovem_ea2ctl() ! 1171: { ! 1172: uint mr = ir & 0x3f; ! 1173: uint reglist = (ir2 >> 10) & 7; ! 1174: int count; ! 1175: uint32 ea; ! 1176: uint32 src[3]; ! 1177: int i; ! 1178: ! 1179: // cache case worst case ! 1180: // FMOVE Rn,FPc 28 31 ! 1181: // FMOVE <ea>,FPc 33 36 ! 1182: // FMOVE #imm,FPc 30 31 ! 1183: // FMOVEM <ea>,FPcs 27+6n 30+6n ! 1184: // FMOVEM #imm,FPcs 25+6n 29+6n ! 1185: // ! 1186: // FMOVE #imm と FMOVEM #imm (n==1) は cache case が 1クロックだけ違う ! 1187: // ようだけどもう無視する。 ! 1188: ! 1189: // 転送するレジスタ数。 ! 1190: // nofpc の場合は現在の 68881 の実装では FPIAR が選択される。 ! 1191: if (reglist == 0) ! 1192: reglist = 1; ! 1193: count = __builtin_popcount(reglist); ! 1194: ! 1195: if (mr < 8) { // Dn ! 1196: CYCLE2(28, 31); ! 1197: // 対データレジスタは転送数 1 のみ有効 ! 1198: if (count > 1) { ! 1199: fpu_op_illg2(); ! 1200: return; ! 1201: } ! 1202: src[0] = reg.R[mr]; ! 1203: ! 1204: } else if (mr < 16) { // An ! 1205: CYCLE2(28, 31); ! 1206: // 対アドレスレジスタは FPIAR のみ有効 ! 1207: if (reglist != 1) { ! 1208: fpu_op_illg2(); ! 1209: return; ! 1210: } ! 1211: src[0] = reg.R[mr]; ! 1212: ! 1213: } else if (mr < 0x3c) { // 対メモリ ! 1214: CYCLE2(28, 30); ! 1215: CYCLE(count * 6); ! 1216: ! 1217: // EA を取得。 ! 1218: // -(An) の時も先にレジスタ数分一気に減算して、そこからプラス方向に ! 1219: // 読み込んでいくので、ロジックは全部同じになる。 ! 1220: // (68000PRM.pdf p393) ! 1221: ea = cea_fpu(count * 4); ! 1222: for (i = 0; i < count; i++) { ! 1223: src[i] = read_4(ea); ! 1224: ea += 4; ! 1225: } ! 1226: ! 1227: } else if (mr == 0x3c) { // #imm ! 1228: CYCLE2(25, 29); ! 1229: CYCLE(count * 6); ! 1230: ! 1231: for (i = 0; i < count; i++) { ! 1232: src[i] = fetch_4(); ! 1233: } ! 1234: ! 1235: } else { ! 1236: fpu_op_illg2(); ! 1237: return; ! 1238: } ! 1239: ! 1240: // 該当レジスタへ読み込み ! 1241: i = 0; ! 1242: if ((reglist & 4)) { ! 1243: RegFPCR = src[i++] & M68K::FPCR_MASK; ! 1244: } ! 1245: if ((reglist & 2)) { ! 1246: RegFPSR = src[i++] & M68K::FPSR_MASK; ! 1247: } ! 1248: if ((reglist & 1)) { ! 1249: RegFPIAR = src[i++]; ! 1250: } ! 1251: } ! 1252: ! 1253: // FMOVEM.L <ctllist>,<ea> ! 1254: // 1111 ccc 000 mmmrrr | 10D RRR 0000 000000 ! 1255: // D=1: FPctl to <ea> ! 1256: // RRR: register list ! 1257: void ! 1258: MPU680x0Device::fpu_op_fmovem_ctl2ea() ! 1259: { ! 1260: uint mr = ir & 0x3f; ! 1261: uint reglist = (ir2 >> 10) & 7; ! 1262: int count; ! 1263: uint32 ea; ! 1264: ! 1265: // cache case worst case ! 1266: // FMOVE FPc,Rn 31 34 ! 1267: // FMOVE FPc,<ea> 33 36 ! 1268: // FMOVEM FPcs,<ea> 27+6n 30+6n ! 1269: ! 1270: // 転送するレジスタ数。 ! 1271: // nofpc の場合は現在の 68881 の実装では FPIAR が選択される。 ! 1272: if (reglist == 0) ! 1273: reglist = 1; ! 1274: count = __builtin_popcount(reglist); ! 1275: ! 1276: if (mr < 8) { // Dn ! 1277: CYCLE2(31, 34); ! 1278: // 対データレジスタは転送数は 1 のみ有効 ! 1279: if (count > 1) { ! 1280: fpu_op_illg2(); ! 1281: return; ! 1282: } ! 1283: ! 1284: if ((reglist & 4)) { ! 1285: reg.R[mr] = RegFPCR; ! 1286: } ! 1287: if ((reglist & 2)) { ! 1288: reg.R[mr] = RegFPSR; ! 1289: } ! 1290: if ((reglist & 1)) { ! 1291: reg.R[mr] = RegFPIAR; ! 1292: } ! 1293: return; ! 1294: } ! 1295: if (mr < 16) { // An ! 1296: CYCLE2(31, 34); ! 1297: // 対アドレスレジスタは FPIAR のみ有効 ! 1298: if (reglist != 1) { ! 1299: fpu_op_illg2(); ! 1300: return; ! 1301: } ! 1302: reg.R[mr] = RegFPIAR; ! 1303: return; ! 1304: } ! 1305: if (mr >= 0x3a) { // #imm, d16(PC), (PC,IX) ! 1306: fpu_op_illg2(); ! 1307: return; ! 1308: } ! 1309: ! 1310: // それ以外、対メモリの場合。 ! 1311: CYCLE2(27, 30); ! 1312: CYCLE(count * 6); ! 1313: ! 1314: // EA を取得して... ! 1315: ea = cea_fpu(count * 4); ! 1316: // 該当レジスタをメモリへ書き出し ! 1317: if ((reglist & 4)) { ! 1318: write_4(ea, RegFPCR); ! 1319: ea += 4; ! 1320: } ! 1321: if ((reglist & 2)) { ! 1322: write_4(ea, RegFPSR); ! 1323: ea += 4; ! 1324: } ! 1325: if ((reglist & 1)) { ! 1326: write_4(ea, RegFPIAR); ! 1327: ea += 4; ! 1328: } ! 1329: } ! 1330: ! 1331: // FMOVEM.X <ea>,<reglist> ! 1332: // FMOVEM.X <ea>,Dn ! 1333: // 1111 ccc 000 mmmrrr | 11D MM000 RRRRRRRR ! 1334: // D=0: <ea> to FPn ! 1335: void ! 1336: MPU680x0Device::fpu_op_fmovem_ea2reg() ! 1337: { ! 1338: uint mr = ir & 0x3f; ! 1339: bool predec = !(ir2 & 0x1000); ! 1340: bool dynamic = (ir2 & 0x0800); ! 1341: uint8 reglist = ir2 & 0xff; ! 1342: int i; ! 1343: uint32 ea; ! 1344: ! 1345: // cache worst ! 1346: // FMOVEM.X <ea>,<list> 35+23n 38+23n ! 1347: // FMOVEM.X <ea>,Dn 49+23n 52+23n ! 1348: ! 1349: // 不当パターンを弾く ! 1350: switch (mr) { ! 1351: case 000 ... 007: // Dn ! 1352: case 010 ... 017: // An ! 1353: case 040 ... 047: // -(An) ! 1354: case 074: // #imm ! 1355: case 075 ... 077: ! 1356: fpu_op_illg2(); ! 1357: return; ! 1358: } ! 1359: ! 1360: // ダイナミックモードなら reglist の %0nnn0000 にレジスタ番号が ! 1361: // 入っているので、この Dn の下位8ビットを取り出す。レジスタ番号以外の ! 1362: // ビットは無視、Dn の上位ビットも無視。 ! 1363: // ついでにここでベースサイクル数を加算。 ! 1364: if (dynamic) { ! 1365: reglist = reg.D[(reglist >> 4) & 7]; ! 1366: CYCLE2(49, 52); ! 1367: } else { ! 1368: CYCLE2(35, 38); ! 1369: } ! 1370: ! 1371: // EA は最初に一度取得しておいて... ! 1372: int count = __builtin_popcount(reglist); ! 1373: ea = cea_fpu(12 * count); ! 1374: ! 1375: if (predec) { ! 1376: // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。 ! 1377: for (i = 7; reglist; reglist <<=1, i--) { ! 1378: if ((int8)reglist < 0) { ! 1379: read_12(ea, &RegFP(i)); ! 1380: ea += 12; ! 1381: } ! 1382: } ! 1383: } else { ! 1384: // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。 ! 1385: for (i = 0; reglist; reglist <<= 1, i++) { ! 1386: if ((int8)reglist < 0) { ! 1387: read_12(ea, &RegFP(i)); ! 1388: ea += 12; ! 1389: } ! 1390: } ! 1391: } ! 1392: CYCLE(23 * count); ! 1393: } ! 1394: ! 1395: // FMOVEM.X <reglist>,<ea> ! 1396: // FMOVEM.X Dn,<ea> ! 1397: // 1111 ccc 000 mmmrrr | 11D MM000 RRRRRRRR ! 1398: // D=1: FPn to <ea> ! 1399: void ! 1400: MPU680x0Device::fpu_op_fmovem_reg2ea() ! 1401: { ! 1402: uint mr = ir & 0x3f; ! 1403: bool anpd = false; // 第1ワード EA が -(An) か ! 1404: bool predec = !(ir2 & 0x1000); // 第2ワードの mode が predec か ! 1405: bool dynamic = (ir2 & 0x0800); ! 1406: uint8 reglist = ir2 & 0xff; ! 1407: int i; ! 1408: uint32 ea; ! 1409: ! 1410: // cache worst ! 1411: // FMOVEM.X <list>,<ea> 37+25n 40+25n ! 1412: // FMOVEM.X Dn,<ea> 51+25n 54+25n ! 1413: ! 1414: // 不当パターンを弾く ! 1415: // ついでに -(An) だけ覚えておく ! 1416: switch (mr) { ! 1417: case 000 ... 007: // Dn ! 1418: case 010 ... 017: // An ! 1419: case 030 ... 037: // (An)+ ! 1420: case 072: // d16(PC) ! 1421: case 073: // d8(PC,IX) ! 1422: case 074: // #imm ! 1423: case 075 ... 077: ! 1424: fpu_op_illg2(); ! 1425: return; ! 1426: case 040 ... 047: // -(An) ! 1427: anpd = true; ! 1428: break; ! 1429: } ! 1430: ! 1431: // ダイナミックモードなら reglist の %0nnn0000 にレジスタ番号が ! 1432: // 入っているので、この Dn の下位8ビットを取り出す。レジスタ番号以外の ! 1433: // ビットは無視、Dn の上位ビットも無視。 ! 1434: // ついでにここでベースクロックを記録 ! 1435: if (dynamic) { ! 1436: reglist = reg.D[(reglist >> 4) & 7]; ! 1437: CYCLE2(51, 54); ! 1438: } else { ! 1439: CYCLE2(37, 40); ! 1440: } ! 1441: ! 1442: int count = __builtin_popcount(reglist); ! 1443: ! 1444: // -(An) の時だけ EA を別処理。 ! 1445: // 現状の cea_fpu() は -(An) の時、巻き戻し用のレジスタを保存し ! 1446: // デクリメントしたアドレスを返すまでを一度に行う便利関数だが、 ! 1447: // FMOVEM fpn,-(An) は最初に巻き戻し用レジスタを保存し (これは命令先頭 ! 1448: // に戻るためなので最初の1回だけ)、その後レジスタ1つずつ 12バイトを ! 1449: // プリデクリメントしながら格納していく必要がある (この順に実行しないと ! 1450: // バスエラーの原因箇所が異なってしまう)。 ! 1451: // そのため cea_fpu() がそのまま使えないので、ここだけ独自対応する。 ! 1452: // cea_fpu() は1命令中で EA の取得が1回である前提のあくまで便利関数 ! 1453: // なので、例外的である FMOVEM は仕方がない。 ! 1454: if (anpd) { ! 1455: CYCLE(6); ! 1456: uint n = eanum(ir); ! 1457: save_reg_pd(n); ! 1458: ! 1459: if (predec) { ! 1460: // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。 ! 1461: for (i = 7; reglist; reglist <<= 1, i--) { ! 1462: if ((int8)reglist < 0) { ! 1463: reg.A[n] -= 12; ! 1464: write_12(reg.A[n], &RegFP(i)); ! 1465: } ! 1466: } ! 1467: } else { ! 1468: // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。 ! 1469: for (i = 0; reglist; reglist <<= 1, i++) { ! 1470: if ((int8)reglist < 0) { ! 1471: reg.A[n] -= 12; ! 1472: write_12(reg.A[n], &RegFP(i)); ! 1473: } ! 1474: } ! 1475: } ! 1476: } else { ! 1477: // -(An) 以外は EA を最初に一度計算しておく方法が使える ! 1478: ea = cea_fpu(12 * count); ! 1479: ! 1480: if (predec) { ! 1481: // predec ならビット7から FP7..FP0 で、bit7 側から順に転送。 ! 1482: for (i = 7; reglist; reglist <<= 1, i--) { ! 1483: if ((int8)reglist < 0) { ! 1484: write_12(ea, &RegFP(i)); ! 1485: ea += 12; ! 1486: } ! 1487: } ! 1488: } else { ! 1489: // ctrl/postinc ならビット7から FP0..FP7 で、bit7 側から順に転送。 ! 1490: for (i = 0; reglist; reglist <<= 1, i++) { ! 1491: if ((int8)reglist < 0) { ! 1492: write_12(ea, &RegFP(i)); ! 1493: ea += 12; ! 1494: } ! 1495: } ! 1496: } ! 1497: } ! 1498: CYCLE(25 * count); ! 1499: } ! 1500: ! 1501: // FScc.B <ea> ! 1502: // 1111 ccc 001 mmmrrr | 0000 000 000 CCCCCC ! 1503: void ! 1504: MPU680x0Device::fpu_op_fscc() ! 1505: { ! 1506: uint mr = ir & 0x3f; ! 1507: uint mm = eamode(ir); ! 1508: uint rr = eanum(ir); ! 1509: uint cond = ir2 & 0x3f; ! 1510: uint32 data; ! 1511: uint32 ea; ! 1512: ! 1513: // cache worst ! 1514: // FScc.B Dn 18 21 ! 1515: // FScc.B (An)+/-(An) 22 25 ; condition is true ! 1516: // FScc.B (An)+/-(An) 21 24 ; condition is false ! 1517: // FScc.B <ea> 20 23 ! 1518: ! 1519: if (cond > 0x1f) { ! 1520: fpu_op_illg2(); ! 1521: return; ! 1522: } ! 1523: ! 1524: data = (test_cc(&fe, cond) == -1) ? 0xff : 0x00; ! 1525: ! 1526: switch (mm) { ! 1527: case 0: // Dn ! 1528: CYCLE2(18, 21); ! 1529: reg.D[rr] &= 0xffffff00; ! 1530: reg.D[rr] |= data; ! 1531: return; ! 1532: ! 1533: case 3: // (An)+ ! 1534: case 4: // -(An) ! 1535: // ここだけ他のメモリ系 EA とはクロックが違うし、 ! 1536: // 条件の成立可否でも違う。 ! 1537: if (data == 0x00) { ! 1538: CYCLE2(21, 24); ! 1539: } else { ! 1540: CYCLE2(22, 25); ! 1541: } ! 1542: break; ! 1543: case 7: ! 1544: if (mr == 0x38 || mr == 0x39) { // Abs.W, Abs.L ! 1545: } else { ! 1546: fpu_op_illg2(); ! 1547: return; ! 1548: } ! 1549: FALLTHROUGH; ! 1550: default: ! 1551: CYCLE2(20, 23); ! 1552: break; ! 1553: } ! 1554: ! 1555: ea = cea_fpu(1); ! 1556: write_1(ea, data); ! 1557: } ! 1558: ! 1559: // FDBcc Dn,<label> ! 1560: // 1111 ccc 001 001rrr | 0000 000 000 CCCCCC | <16bit disp> ! 1561: void ! 1562: MPU680x0Device::fpu_op_fdbcc() ! 1563: { ! 1564: uint rr = ir & 7; ! 1565: uint cond = ir2 & 0x3f; ! 1566: ! 1567: if (cond > 0x1f) { ! 1568: fpu_op_illg2(); ! 1569: return; ! 1570: } ! 1571: ! 1572: if (test_cc(&fe, cond) == -1) { ! 1573: // 真なら何もしない。disp を読み飛ばして次へ ! 1574: CYCLE2(20, 24); ! 1575: fetch_2(); ! 1576: } else { ! 1577: // 偽の場合 ! 1578: uint16 data = reg.D[rr] - 1; ! 1579: reg.D[rr] = (reg.D[rr] & 0xffff0000) | data; ! 1580: ! 1581: if (data == 0xffff) { ! 1582: // ループ終了。disp を読み飛ばす ! 1583: CYCLE2(24, 32); ! 1584: fetch_2(); ! 1585: } else { ! 1586: // 計算に使う PC はディスプレースメントのあるアドレス。 ! 1587: CYCLE2(20, 26); ! 1588: uint32 origin = reg.pc; ! 1589: int32 disp = (int32)(int16)fetch_2(); ! 1590: Jump(origin + disp); ! 1591: } ! 1592: } ! 1593: } ! 1594: ! 1595: // FTRAPcc.W #<data> ! 1596: void ! 1597: MPU680x0Device::fpu_op_ftrapcc_w() ! 1598: { ! 1599: uint cond = ir2 & 0x3f; ! 1600: ! 1601: if (cond > 0x1f) { ! 1602: fpu_op_illg2(); ! 1603: return; ! 1604: } ! 1605: ! 1606: // 即値はいずれにしても読み捨てる必要がある。 ! 1607: fetch_2(); ! 1608: ! 1609: if (test_cc(&fe, cond) == -1) { ! 1610: CYCLE2(41, 45); ! 1611: Exception(M68K::EXCEP_TRAPV); ! 1612: } else { ! 1613: CYCLE2(20, 23); ! 1614: } ! 1615: } ! 1616: ! 1617: // FTRAPcc.L #<data> ! 1618: void ! 1619: MPU680x0Device::fpu_op_ftrapcc_l() ! 1620: { ! 1621: uint cond = ir2 & 0x3f; ! 1622: ! 1623: if (cond > 0x1f) { ! 1624: fpu_op_illg2(); ! 1625: return; ! 1626: } ! 1627: ! 1628: // 即値はいずれにしても読み捨てる必要がある。 ! 1629: fetch_4(); ! 1630: ! 1631: if (test_cc(&fe, cond) == -1) { ! 1632: CYCLE2(43, 52); ! 1633: Exception(M68K::EXCEP_TRAPV); ! 1634: } else { ! 1635: CYCLE2(22, 27); ! 1636: } ! 1637: } ! 1638: ! 1639: // FTRAPcc ! 1640: void ! 1641: MPU680x0Device::fpu_op_ftrapcc() ! 1642: { ! 1643: uint cond = ir2 & 0x3f; ! 1644: ! 1645: if (cond > 0x1f) { ! 1646: fpu_op_illg2(); ! 1647: return; ! 1648: } ! 1649: ! 1650: // 即値なし。 ! 1651: ! 1652: if (test_cc(&fe, cond) == -1) { ! 1653: CYCLE2(39, 47); ! 1654: Exception(M68K::EXCEP_TRAPV); ! 1655: } else { ! 1656: CYCLE2(18, 22); ! 1657: } ! 1658: } ! 1659: ! 1660: // FBcc.W <label> ! 1661: // 1111 ccc 01S CCCCCC | <16bit disp> ! 1662: // S=0: 16bit disp ! 1663: // ! 1664: // FNOP ! 1665: // 1111 ccc 010 000000 | 0000 0000 0000 0000 ! 1666: void ! 1667: MPU680x0Device::fpu_op_fbcc_w() ! 1668: { ! 1669: uint cond = ir & 0x3f; ! 1670: ! 1671: // TODO: Illegal condition の戻り値を処理すること。他の test_cc() も同様。 ! 1672: if (test_cc(&fe, cond) == -1) { ! 1673: CYCLE2(20, 23); ! 1674: uint32 origin = reg.pc; ! 1675: int32 disp = (int32)(int16)fetch_2(); ! 1676: Jump(origin + disp); ! 1677: } else { ! 1678: // disp を読み飛ばす ! 1679: CYCLE2(18, 19); ! 1680: fetch_2(); ! 1681: } ! 1682: } ! 1683: ! 1684: // FBcc.L <label> ! 1685: // 1111 ccc 01S CCCCCC | <32bit disp> ! 1686: // S=1: 32bit disp ! 1687: void ! 1688: MPU680x0Device::fpu_op_fbcc_l() ! 1689: { ! 1690: uint cond = ir & 0x3f; ! 1691: ! 1692: if (test_cc(&fe, cond) == -1) { ! 1693: CYCLE2(20, 23); ! 1694: uint32 origin = reg.pc; ! 1695: int32 disp = (int32)fetch_4(); ! 1696: Jump(origin + disp); ! 1697: } else { ! 1698: // disp を読み飛ばす ! 1699: CYCLE2(18, 21); ! 1700: fetch_4(); ! 1701: } ! 1702: } ! 1703: ! 1704: // FSAVE の NULL フレーム (全機種共通で4バイト) ! 1705: /*static*/ const uint32 ! 1706: MPU680x0Device::fsave_frame_null[] = { ! 1707: 0, ! 1708: }; ! 1709: ! 1710: // FSAVE のアイドルフレーム (68881) ! 1711: /*static*/ const uint32 ! 1712: MPU680x0Device::fsave_frame_idle_68881[] = { ! 1713: 0x1f180000, ! 1714: 0x0000ffff, ! 1715: 0, ! 1716: 0, ! 1717: 0, ! 1718: 0, ! 1719: 0x70000000, ! 1720: }; ! 1721: ! 1722: // FSAVE のアイドルフレーム (68040) ! 1723: /*static*/ const uint32 ! 1724: MPU680x0Device::fsave_frame_idle_68040[] = { ! 1725: 0x41000000, ! 1726: }; ! 1727: ! 1728: // FSAVE ! 1729: // スーパーバイザモードは判定済み ! 1730: void ! 1731: MPU680x0Device::fpu_op_fsave() ! 1732: { ! 1733: uint32 ea; ! 1734: std::array<uint32, 13> frame_noimpl; ! 1735: const uint32 *frame; ! 1736: int framelen; ! 1737: ! 1738: // フレームを選択。 ! 1739: switch (fpu_state) { ! 1740: case FPU_STATE_NULL: ! 1741: // NULL フレーム ! 1742: CYCLE2(16, 18); ! 1743: frame = fsave_frame_null; ! 1744: framelen = countof(fsave_frame_null); ! 1745: break; ! 1746: case FPU_STATE_IDLE: ! 1747: case FPU_STATE_BUSY: // 実装してないけどとりあえず。 ! 1748: // IDLE フレーム ! 1749: CYCLE2(52, 54); // XXX これは最小値らしいけど ! 1750: if (fpu_type.Is4060FPU()) { ! 1751: frame = fsave_frame_idle_68040; ! 1752: framelen = countof(fsave_frame_idle_68040); ! 1753: } else { ! 1754: frame = fsave_frame_idle_68881; ! 1755: framelen = countof(fsave_frame_idle_68881); ! 1756: } ! 1757: break; ! 1758: case FPU_STATE_NOIMPL: ! 1759: // 68040 で浮動小数点未実装命令を実行した。 ! 1760: fpu_op_fsave_frame_noimpl(frame_noimpl); ! 1761: frame = frame_noimpl.data(); ! 1762: framelen = frame_noimpl.size(); ! 1763: break; ! 1764: default: ! 1765: PANIC("fpu_state=%u corrupted", fpu_state); ! 1766: } ! 1767: ! 1768: switch (ir & 077) { ! 1769: case 020 ... 027: // (An) ! 1770: case 040 ... 047: // -(An) ! 1771: case 050 ... 057: // d16(An) ! 1772: case 060 ... 067: // d8(An,IX) ! 1773: case 070 ... 071: // Abs.[WL] ! 1774: ea = cea_fpu(framelen * 4); ! 1775: break; ! 1776: default: ! 1777: fpu_op_illg(); ! 1778: return; ! 1779: } ! 1780: ! 1781: // -(An) もそれ以外もどちらも、まず先頭フレームを書き出す。 ! 1782: // この時点で ea は先頭フレームの位置を指している。 ! 1783: write_4(ea, frame[0]); ! 1784: ! 1785: // -(An) もそれ以外もどちらも、 ! 1786: // 残りはプリデクリメントのように高位側から順に書き出す。 ! 1787: ea += framelen * 4; ! 1788: for (int i = framelen - 1; i > 0; i--) { ! 1789: ea -= 4; ! 1790: write_4(ea, frame[i]); ! 1791: } ! 1792: } ! 1793: ! 1794: // FRESTORE ! 1795: // スーパーバイザモードは判定済み ! 1796: void ! 1797: MPU680x0Device::fpu_op_frestore() ! 1798: { ! 1799: uint mm = eamode(ir); ! 1800: uint rr = eanum(ir); ! 1801: uint32 ea; ! 1802: uint32 fmtword; ! 1803: uint32 ver_len; ! 1804: uint32 len; ! 1805: bool postinc; ! 1806: ! 1807: postinc = false; ! 1808: // EA は独自体系なのでここでべたに書く ! 1809: switch (mm) { ! 1810: case 2: // (An) ! 1811: ea = cea_anin(rr); ! 1812: break; ! 1813: case 3: // (An)+ ! 1814: ea = cea_anin(rr); ! 1815: postinc = true; ! 1816: break; ! 1817: case 5: // d16(An) ! 1818: ea = cea_andi(rr); ! 1819: break; ! 1820: case 6: // (An,IX) ! 1821: ea = cea_anix(rr); ! 1822: break; ! 1823: case 7: ! 1824: switch (rr) { ! 1825: case 0: // Abs.W ! 1826: ea = cea_absw(); ! 1827: break; ! 1828: case 1: // Abs.L ! 1829: ea = cea_absl(); ! 1830: break; ! 1831: case 2: // d16(PC) ! 1832: ea = cea_pcdi(); ! 1833: break; ! 1834: case 3: // (PC,IX) ! 1835: ea = cea_pcix(); ! 1836: break; ! 1837: default: ! 1838: fpu_op_illg(); ! 1839: return; ! 1840: } ! 1841: break; ! 1842: default: ! 1843: fpu_op_illg(); ! 1844: return; ! 1845: } ! 1846: ! 1847: // 先頭の1ロングワードを読んでみる。 ! 1848: // これがフォーマットワード $VVLL'xxxx で、VV がバージョン(8bit)、 ! 1849: // LL が(自身を含まないこれ以降の) バイト数 (8bit) を示している。 ! 1850: // 68881 本では下位ワードは Reserved($0000) となっているが、 ! 1851: // 68040 本では Reserved のみで値の言及はない。 ! 1852: // ! 1853: // 68881: ! 1854: // NULL $0000'0000 ! 1855: // IDLE $1f18'0000 (以降 6 ロングワード) ! 1856: // BUSY $1fb4'0000 (以降 45 ロングワード) (*) ! 1857: // ! 1858: // 68040: ! 1859: // NULL $0000'xxxx ! 1860: // IDLE $4100'xxxx ! 1861: // BUSY $4160'xxxx (以降 24 ロングワード) (*) ! 1862: // UNIMP $4130'xxxx (以降 12 ロングワード) ! 1863: // ! 1864: // *: BUSY フレームは現状の FSAVE が出力しないので来ないはず。 ! 1865: ! 1866: fmtword = read_4(ea); ! 1867: ea += 4; ! 1868: ! 1869: ver_len = fmtword >> 16; ! 1870: len = ver_len & 0xff; ! 1871: ! 1872: if (GetFPUType().Is4060FPU()) { ! 1873: if (ver_len == 0) { ! 1874: // NULL フレーム。 ! 1875: ! 1876: // NULL フレームのリストアは FPU の状態をリセットする。 ! 1877: CYCLE2(21, 22); ! 1878: ResetFPU(false); ! 1879: } else if (ver_len == 0x4100) { ! 1880: // IDLE フレーム。 ! 1881: ! 1882: // 現状何も実装していないので、状態を戻して読み捨てるだけ。 ! 1883: CYCLE2(57, 58); ! 1884: fpu_state = FPU_STATE_IDLE; ! 1885: } else if (ver_len == 0x4130) { ! 1886: // 浮動小数点未実装命令フレーム。 ! 1887: // どうなる? ! 1888: putlog(0, "FRESTORE: Unsupported UNIMP frame"); ! 1889: } else if (ver_len == 0x4160) { ! 1890: // BUSY フレーム。 ! 1891: putlog(0, "FRESTORE: Unsupported BUSY frame"); ! 1892: if (0) { ! 1893: putlog(0, "[+00] %08x", fmtword); ! 1894: for (int offset = 4; offset < len; offset += 4) { ! 1895: uint32 m = read_4(ea + offset); ! 1896: putlog(0, "[+%02x] %08x", offset, m); ! 1897: } ! 1898: } ! 1899: } else { ! 1900: Exception(M68K::EXCEP_FORMAT); ! 1901: goto done; ! 1902: } ! 1903: } else /* 68881 */ { ! 1904: if (ver_len == 0) { ! 1905: // NULL フレーム。 ! 1906: ! 1907: // NULL フレームのリストアは FPU の状態をリセットする。 ! 1908: CYCLE2(21, 22); ! 1909: ResetFPU(false); ! 1910: } else if (ver_len == 0x1f18) { ! 1911: // IDLE フレーム。 ! 1912: ! 1913: // 現状何も実装していないので、状態を戻して読み捨てるだけ。 ! 1914: CYCLE2(57, 58); ! 1915: fpu_state = FPU_STATE_IDLE; ! 1916: } else { ! 1917: if (ver_len == 0x1fb4) { ! 1918: putlog(0, "FRESTORE: Unsupported BUSY frame"); ! 1919: } ! 1920: Exception(M68K::EXCEP_FORMAT); ! 1921: goto done; ! 1922: } ! 1923: } ! 1924: ! 1925: // とにかく残りを全部読み捨てる。 ! 1926: len /= 4; ! 1927: for (int i = 0; i < len; i++) { ! 1928: read_4(ea); ! 1929: ea += 4; ! 1930: } ! 1931: ! 1932: done: ! 1933: // (An)+ なら更新。 ! 1934: // フォーマットワードを読んだところでエラーが起きたら +4 だけ更新される? ! 1935: if (postinc) { ! 1936: reg.A[rr] = ea; ! 1937: } ! 1938: } ! 1939: ! 1940: // 現在の fpu40 の状態から ! 1941: // 68040 の浮動小数点未実装命令フレームを作成して frame に書き出す。 ! 1942: void ! 1943: MPU680x0Device::fpu_op_fsave_frame_noimpl(std::array<uint32, 13>& frame) ! 1944: { ! 1945: uint32 cmd1; ! 1946: uint32 reg3b; ! 1947: uint32 data6; ! 1948: ! 1949: // CMDREG1B 形式の Ry+CMD1 から CMDREG3B 形式の Ry+CMD3 を作る。 ! 1950: cmd1 = fpu40.reg1b & 0x3ff; ! 1951: reg3b = (cmd1 & 0x3c3) | ((cmd1 >> 1) & 0x1c) | ((cmd1 << 3) & 0x20); ! 1952: ! 1953: data6 = fpu40.eflag; ! 1954: if (fpu40.post) { ! 1955: data6 |= 0x0010'0000; ! 1956: } ! 1957: ! 1958: frame[0] = 0x41300000; ! 1959: frame[1] = reg3b << 16; ! 1960: frame[2] = 0; ! 1961: frame[3] = (uint32)fpu40.stag << 29; ! 1962: frame[4] = fpu40.reg1b << 16; ! 1963: frame[5] = (uint32)fpu40.dtag << 29; ! 1964: frame[6] = data6; ! 1965: memcpy(&frame[7], fpu40.fptemp, 12); ! 1966: memcpy(&frame[10], fpu40.etemp, 12); ! 1967: ! 1968: // モニタ表示用。 ! 1969: fpu40.enable = false; ! 1970: } ! 1971: ! 1972: // 浮動小数点系の例外。 ! 1973: // fpu40 の stag, dtag, etemp, fptemp, eflag を必要に応じてセットしてから ! 1974: // 呼ぶこと。 ! 1975: void ! 1976: MPU680x0Device::ExceptionFP(uint vector) ! 1977: { ! 1978: fpu_state = FPU_STATE_NOIMPL; ! 1979: ! 1980: // CMDREG1B は実質 2ワード目のことのようだ。 ! 1981: // FMOVECR のケースはドキュメントに見当たらないが、FPSP を読む限り ! 1982: // CMDREG1B はここでも FMOVECR の第2ワードそのままのようだ。 ! 1983: // FSQRT 用のハックで cmd(offset) の $04 を $05 に書き換えるが、FPSP の ! 1984: // FMOVECR はどちらも 0.0 を返すので、書き換えてしまっても問題ないはず? ! 1985: uint32 reg1b = ir2; ! 1986: if ((reg1b & 0x3f) == 0x04) { ! 1987: // FSQRT だけマッピングが違う。 ! 1988: reg1b++; ! 1989: } ! 1990: fpu40.reg1b = reg1b; ! 1991: fpu40.post = false; ! 1992: fpu40.enable = true; ! 1993: ! 1994: // この例外を起こした命令のアドレスは FPIAR に置く。 ! 1995: reg.fpframe.fpf_fpiar = ppc; ! 1996: ! 1997: // EXCEP_FP_UNIMPL (未実装命令例外) はベクタが F ラインと同じで、 ! 1998: // フレームフォーマットが違うので、定数値に細工がしてある。 ! 1999: const uint32 inst = BranchHistory_m680x0::Exception | (vector & 0xff); ! 2000: ExceptionGeneric(vector, inst); ! 2001: } ! 2002: ! 2003: // CMDREG1B からコマンド名を返す。 ! 2004: // FSQRT 命令の第2ワードの cmd 部分は $04 だが CMDREG1B では $05 になる。 ! 2005: /*static*/ std::string ! 2006: MPU68040Device::GetReg1BName(uint32 opclass, uint32 sz, uint32 cmd) ! 2007: { ! 2008: std::string name; ! 2009: ! 2010: if (opclass != 0 && opclass != 2) { ! 2011: return ""; ! 2012: } ! 2013: ! 2014: if (sz == 7) { ! 2015: return "fmovecr"; ! 2016: } ! 2017: ! 2018: if (__predict_false(0x30 <= cmd && cmd < 0x38)) { ! 2019: name = "fsincos"; ! 2020: name += '0' + (cmd - 0x30); ! 2021: return name; ! 2022: } ! 2023: ! 2024: if (__predict_false(cmd == 0x04)) { ! 2025: // 来ないはずだけど一応。 ! 2026: return "fsqrt(4)"; ! 2027: } ! 2028: ! 2029: if (__predict_false(cmd == 0x05)) { ! 2030: cmd = 0x04; ! 2031: } ! 2032: name = m680x0disasm::make_fpgen(cmd); ! 2033: return name; ! 2034: } ! 2035: ! 2036: /*static*/ std::string ! 2037: MPU68040Device::GetFPUTagName(int32 tag) ! 2038: { ! 2039: const char * const tagnames[] = { ! 2040: "(Normal)", ! 2041: "(Zero)", ! 2042: "(Inf)", ! 2043: "(NAN)", ! 2044: "(Unnormal)", ! 2045: "(Denormal)", ! 2046: }; ! 2047: ! 2048: if (__predict_true(tag < countof(tagnames))) { ! 2049: return tagnames[tag]; ! 2050: } ! 2051: if (tag == FPU40::TAG_DENORMAL_S) { ! 2052: return "(Denormal.S)"; ! 2053: } ! 2054: if (tag == FPU40::TAG_DENORMAL_D) { ! 2055: return "(Denormal.D)"; ! 2056: } ! 2057: if (tag == FPU40::TAG_DENORMAL_X) { ! 2058: return "(Denormal.X)"; ! 2059: } ! 2060: if (tag == FPU40::TAG_UNNORMAL_X) { ! 2061: return "(Unnormal.X)"; ! 2062: } ! 2063: if (tag == FPU40::TAG_NONE) { ! 2064: return "(NONE)"; ! 2065: } ! 2066: return ""; ! 2067: } ! 2068: ! 2069: // モニター更新 (040 内部情報) ! 2070: void ! 2071: MPU68040Device::MonitorUpdateFPU40(TextScreen& screen, int y, const FPU40& tmp) ! 2072: { ! 2073: // CMDREG1B:$xxxx OPCLASS=0 Rs=7 Rd=7 cmd=00(FTWOTOX) Flags: E3 E1 T ! 2074: // ETEMP :$01234567_01234567_01234567 STAG:1(Unnormal) ! 2075: // FPTEMP: ! 2076: ! 2077: TA attr = tmp.enable ? TA::Normal : TA::Disable; ! 2078: ! 2079: uint32 reg1b = tmp.reg1b; ! 2080: uint32 opclass = reg1b >> 13; ! 2081: uint32 rx = (reg1b >> 10) & 7; ! 2082: uint32 ry = (reg1b >> 7) & 7; ! 2083: uint32 cmd = reg1b & 0x7f; ! 2084: ! 2085: std::string cmdname = GetReg1BName(opclass, rx, cmd); ! 2086: if (__predict_true(cmdname.empty() == false)) { ! 2087: cmdname = '(' + cmdname + ')'; ! 2088: } ! 2089: ! 2090: std::string stagname = GetFPUTagName(tmp.stag); ! 2091: std::string dtagname = GetFPUTagName(tmp.dtag); ! 2092: ! 2093: screen.Print(0, y, attr, ! 2094: "CMDREG1B:%04x OPCLASS=%u Rs=%u Rd=%u CMD=$%02x%s", ! 2095: reg1b, opclass, rx, ry, cmd, cmdname.c_str()); ! 2096: screen.Puts(56, y, attr, "Flags:"); ! 2097: screen.Puts(62, y, attr, (tmp.eflag & FPU40::E1) ? "E1" : "--"); ! 2098: screen.Puts(65, y, attr, (tmp.eflag & FPU40::E3) ? "E3" : "--"); ! 2099: screen.Puts(68, y, attr, (tmp.post) ? "T" : "-"); ! 2100: y++; ! 2101: screen.Print(0, y, attr, "ETEMP: %08x_%08x_%08x STAG:%d%s", ! 2102: tmp.etemp[0], tmp.etemp[1], tmp.etemp[2], ! 2103: (__predict_true(tmp.stag >= 0) ? (tmp.stag & 7) : tmp.stag), ! 2104: stagname.c_str()); ! 2105: screen.Print(56, y, attr, "EA:%08x", tmp.ea); ! 2106: y++; ! 2107: screen.Print(0, y++, attr, "FPTEMP:%08x_%08x_%08x DTAG:%d%s", ! 2108: tmp.fptemp[0], tmp.fptemp[1], tmp.fptemp[2], ! 2109: (__predict_true(tmp.dtag >= 0) ? (tmp.dtag & 7) : tmp.dtag), ! 2110: dtagname.c_str()); ! 2111: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.