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