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