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