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