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