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