|
|
1.1 root 1: //
2: // nono
1.1.1.2 ! root 3: // Copyright (C) 2020 nono project
! 4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #include "m68030core.h"
8: #include "m68030bus.h"
9: #include "m68030ccr.h"
10: #include "m68030acc.h"
11:
12: // インライン展開するにはでかいし使用頻度も少ない人たちはこっち。
13: // インライン展開できそうな人たちは m68030acc.h のほうへ。
14:
15:
16: // ビットフィールド命令
17:
18: // コンストラクタ
19: // 呼び出し側でここまでに RegIR2 へのフェッチはしておくこと。
1.1.1.2 ! root 20: acc_bf::acc_bf(m68kcpu *cpu_)
1.1 root 21: {
1.1.1.2 ! root 22: cpu = cpu_;
1.1 root 23:
24: // F E D C B A 9 8 7 6 5 4 3 2 1 0
25: // 0 0 0 0 DO <-- offset --> DW <-- width --->
26:
27: offset = (RegIR2 >> 6) & 0x1f;
28: if ((RegIR2 & 0x0800)) {
29: offset = (int32)RegD(offset & 7);
30: local_offset = offset & 0x1f;
31: } else {
32: local_offset = offset;
33: }
34:
35: width = RegIR2;
36: if ((RegIR2 & 0x0020)) {
37: width = RegD(width & 7);
38: }
39: // モジュロ 32 を取り、0 なら 32 を表す
40: width = ((width - 1) & 31) + 1;
41: // mask は32ビットの上位から width ビット 1 が並んだもの
42: mask = 0xffffffff << (32 - width);
43: }
44:
45: // データレジスタから値を読み込む。n はデータレジスタの番号。
46: void
47: acc_bf::LoadReg(uint n)
48: {
49: data = RegD(n);
50: data = ROL32(data, local_offset);
51: data &= mask;
52: }
53:
54: // メモリから値を読み込む。
55: void
56: acc_bf::LoadMem(uint32 addr)
57: {
58: // EA の計算
59: ea = addr + offset / 8;
60: local_offset = offset % 8;
61: if (local_offset < 0) {
62: local_offset += 8;
63: ea--;
64: }
65:
66: // アクセスするバイト数
67: bytes = (local_offset + width + 7) / 8;
68:
69: // 40ビットバッファに読み込む
70: // m68030_read_NN() はミスアラインドでもアクセスできる
71: switch (bytes) {
72: case 1:
73: buf = ((uint64)m68030_read_8(cpu, ea)) << 32;
74: break;
75: case 2:
76: buf = ((uint64)m68030_read_16(cpu, ea)) << 24;
77: break;
78: case 3:
79: if ((ea & 1) == 0) {
80: // 偶数アドレスから3バイト
81: buf = ((uint64)m68030_read_16(cpu, ea)) << 24;
82: buf |= ((uint64)m68030_read_8(cpu, ea + 2)) << 16;
83: } else {
84: // 奇数アドレスから3バイト
85: buf = ((uint64)m68030_read_8(cpu, ea)) << 32;
86: buf |= (uint64)m68030_read_16(cpu, ea + 1) << 16;
87: }
88: break;
89: case 4:
90: buf = ((uint64)m68030_read_32(cpu, ea)) << 8;
91: break;
92: case 5:
93: if ((ea & 1) == 0) {
94: // 偶数アドレスから5バイト
95: buf = ((uint64)m68030_read_32(cpu, ea)) << 8;
96: buf |= ((uint64)m68030_read_8(cpu, ea + 4));
97: } else {
98: // 奇数アドレスから5バイト
99: buf = ((uint64)m68030_read_8(cpu, ea)) << 32;
100: buf |= ((uint64)m68030_read_32(cpu, ea + 1));
101: }
102: break;
103: default:
104: __unreachable();
105: }
106:
107: // 32ビット左詰めにする
108: data = (buf >> (8 - local_offset)) & mask;
109: }
110:
111: // データレジスタに値を書き出す。
112: void
113: acc_bf::StoreReg(uint n)
114: {
115: uint32 m = ROR32(mask, local_offset);
116: uint32 d = ROR32(data, local_offset);
117:
118: RegD(n) = (RegD(n) & ~m) | (d & m);
119: }
120:
121: // メモリに値を書き出す
122: void
123: acc_bf::StoreMem()
124: {
125: // 32ビット左詰めデータを 40ビットバッファにマージ
126: uint64 m = (uint64)mask << (8 - local_offset);
127: uint64 d = (uint64)data << (8 - local_offset);
128: buf = (buf & ~m) | (d & m);
129:
130: // 40ビットバッファを書き戻す
131: // m68030_write_NN() はミスアラインドでもアクセスできる
132: switch (bytes) {
133: case 1:
134: m68030_write_8(cpu, ea, buf >> 32);
135: break;
136: case 2:
137: m68030_write_16(cpu, ea, buf >> 24);
138: break;
139: case 3:
140: if ((ea & 1) == 0) {
141: // 偶数アドレスから3バイト
142: m68030_write_16(cpu, ea, buf >> 24);
143: m68030_write_8(cpu, ea + 2, buf >> 16);
144: } else {
145: // 奇数アドレスから3バイト
146: m68030_write_8(cpu, ea, buf >> 32);
147: m68030_write_16(cpu, ea + 1, buf >> 16);
148: }
149: break;
150: case 4:
151: m68030_write_32(cpu, ea, buf >> 8);
152: break;
153: case 5:
154: if ((ea & 1) == 0) {
155: // 偶数アドレスから5バイト
156: m68030_write_32(cpu, ea, buf >> 8);
157: m68030_write_8(cpu, ea + 4, buf);
158: } else {
159: // 奇数アドレスから5バイト
160: m68030_write_8(cpu, ea, buf >> 32);
161: m68030_write_32(cpu, ea + 1, buf);
162: }
163: break;
164: default:
165: __unreachable();
166: }
167: }
168:
169: void
170: acc_chk2cmp2_32(m68kcpu *cpu, uint32 compare, uint32 lower, uint32 upper)
171: {
172: // 実機の実行結果をじっと睨んだ結果、このロジックで
173: // cmp2 は実行していると考えられる。
174: // オペランド順はフラグに影響する。
175: // なぜ 68k のデザイナが順序を入れ替えたのかは不明。
176: // なんかの都合があったんだろうな...
177:
178: // この cmp は通常の if で代替できるけど、
179: // あえて MPU 内部の動作をエミュレート。
180: acc_cmp_32(cpu, lower, upper);
181:
182: if (RegCondCS) {
183: acc_cmp_32(cpu, compare, upper);
184: if (RegCondEQ) {
185: // break
186: } else if (RegCondCS) {
187: acc_cmp_32(cpu, lower, compare);
188: } else {
189: acc_cmp_32(cpu, compare, lower);
190: }
191: } else {
192: acc_cmp_32(cpu, lower, compare);
193: if (RegCondEQ) {
194: // break
195: } else if (RegCondCS) {
196: // break
197: } else {
198: acc_cmp_32(cpu, compare, upper);
199: }
200: }
201: }
202:
203: // dst(u32) / src(u16) を計算して、NZVC フラグをセットする。
204: // src の上位ビットはクリアしておくこと。
205: // true なら rem(16) と quo(16) が有効で、
206: // rem, quo の上位ビットはクリアされている。
207: // false なら結果を書き戻さずに終了する。
208: bool
209: acc_divu_32_16(m68kcpu *cpu, uint32 src, uint32 dst, uint32 *quo, uint32 *rem)
210: {
211: if (src == 0) {
212: // ゼロ除算の場合、
213: // X は変化しない
214: // C は常にクリア
215: // N,Z,V は未定義
216: CCR.c = 0;
217: m68030_exception(cpu, M68K_EXCEP_ZERODIV);
218: return false;
219: }
220: *quo = dst / src;
221: *rem = dst % src;
222: if (*quo > 0xffff) {
223: // オーバーフローの場合、
224: // X は変化しない
225: // N,Z は未定義
226: // V はセット
227: // C は常にクリア
228: CCR.v = m68030ccr::V_BIT;
229: CCR.c = 0;
230: return false;
231: }
232: // 正常の場合、
233: // X は変化しない
234: // V, C はクリア
235: // N, Z は quo の結果。
236: *rem &= 0xffff;
237: acc_move_16(cpu, *quo);
238: return true;
239: }
240:
241: // dst(u32) / src(u32) を計算して、NZVC フラグをセットする。
242: // true なら rem(32), quo(32) が有効、
243: // false なら結果を書き戻さずに終了する。
244: bool
245: acc_divu_32_32(m68kcpu *cpu, uint32 src, uint32 dst, uint32 *quo, uint32 *rem)
246: {
247: if (src == 0) {
248: // ゼロ除算の場合、
249: // X は変化しない
250: // C は常にクリア
251: // N,Z,V は未定義
252: CCR.c = 0;
253: m68030_exception(cpu, M68K_EXCEP_ZERODIV);
254: return false;
255: }
256: *quo = dst / src;
257: *rem = dst % src;
258: // このケースでオーバーフローは起きないはず
259:
260: // 正常の場合、
261: // X は変化しない
262: // V, C はクリア
263: // N, Z は quo の結果。
264: acc_move_32(cpu, *quo);
265: return true;
266: }
267:
268: // dst(u64) / src(u32) を計算して、NZVC フラグをセットする。
269: // true なら rem(32), quo(32) が有効、
270: // false なら結果を書き戻さずに終了する。
271: bool
272: acc_divu_64_32(m68kcpu *cpu, uint32 src, uint64 dst, uint32 *quo, uint32 *rem)
273: {
274: if (src == 0) {
275: // ゼロ除算の場合、
276: // X は変化しない
277: // C は常にクリア
278: // N,Z,V は未定義
279: CCR.c = 0;
280: m68030_exception(cpu, M68K_EXCEP_ZERODIV);
281: return false;
282: }
283: uint64 q64 = dst / src;
284: *rem = dst % src;
285: if (q64 > 0xffffffffUL) {
286: // オーバーフローの場合、
287: // X は変化しない
288: // N,Z は未定義
289: // V はセット
290: // C は常にクリア
291: CCR.v = m68030ccr::V_BIT;
292: CCR.c = 0;
293: return false;
294: }
295:
296: *quo = q64;
297:
298: // 正常の場合、
299: // X は変化しない
300: // V, C はクリア
301: // N, Z は quo の結果。
302: acc_move_32(cpu, *quo);
303: return true;
304: }
305:
306: // dst(s32) / src(s16) を計算して、NZVC フラグをセットする。
307: // src の上位ビットはクリアしておくこと。
308: // true なら rem(16) と quo(16) が有効で、
309: // rem, quo の上位ビットはクリアされている。
310: // false なら結果を書き戻さずに終了する。
311: bool
312: acc_divs_32_16(m68kcpu *cpu, uint32 src, uint32 dst, uint32 *quo, uint32 *rem)
313: {
314: if (src == 0) {
315: // ゼロ除算の場合、
316: // X は変化しない
317: // C は常にクリア
318: // N,Z,V は未定義
319: CCR.c = 0;
320: m68030_exception(cpu, M68K_EXCEP_ZERODIV);
321: return false;
322: }
323:
324: // ホストでオーバーフローが起きるのはこのケースのみ
325: if (dst == 0x80000000 && src == 0xffff) {
326: // オーバーフローの場合、
327: // X は変化しない
328: // N,Z は未定義
329: // V はセット
330: // C は常にクリア
331: CCR.v = m68030ccr::V_BIT;
332: CCR.c = 0;
333: return false;
334: }
335:
336: int32 squo = (int32)dst / (int32)(int16)src;
337: int32 srem = (int32)dst % (int32)(int16)src;
338: if ((int16)squo != squo) {
339: // オーバーフローの場合
340: CCR.v = m68030ccr::V_BIT;
341: CCR.c = 0;
342: return false;
343: }
344: // 正常の場合、
345: // X は変化しない
346: // V, C はクリア
347: // N, Z は quo の結果。
348: *quo = (uint32)squo & 0xffff;
349: *rem = (uint32)srem & 0xffff;
350: acc_move_16(cpu, *quo);
351: return true;
352: }
353:
354: // dst(s32) / src(s32) を計算して、NZVC フラグをセットする。
355: // true なら rem(32), quo(32) が有効、
356: // false なら結果を書き戻さずに終了する。
357: bool
358: acc_divs_32_32(m68kcpu *cpu, uint32 src, uint32 dst, uint32 *quo, uint32 *rem)
359: {
360: if (src == 0) {
361: // ゼロ除算の場合、
362: // X は変化しない
363: // C は常にクリア
364: // N,Z,V は未定義
365: CCR.c = 0;
366: m68030_exception(cpu, M68K_EXCEP_ZERODIV);
367: return false;
368: }
369:
370: // ホストでオーバーフローが起きるのはこのケースのみ
371: if (dst == INT32_MIN && src == -1) {
372: // オーバーフローの場合、
373: // X は変化しない
374: // N,Z は未定義
375: // V はセット
376: // C は常にクリア
377: CCR.v = m68030ccr::V_BIT;
378: CCR.c = 0;
379: return false;
380: }
381:
382: *quo = (int32)dst / (int32)src;
383: *rem = (int32)dst % (int32)src;
384: // ここでオーバーフローは起きない
385:
386: // 正常の場合、
387: // X は変化しない
388: // V, C はクリア
389: // N, Z は quo の結果。
390: acc_move_32(cpu, *quo);
391: return true;
392: }
393:
394: // dst(s64) / src(s32) を計算して、NZVC フラグをセットする。
395: // true なら rem(32), quo(32) が有効、
396: // false なら結果を書き戻さずに終了する。
397: bool
398: acc_divs_64_32(m68kcpu *cpu, uint32 src, uint64 dst, uint32 *quo, uint32 *rem)
399: {
400: if (src == 0) {
401: // ゼロ除算の場合、
402: // X は変化しない
403: // C は常にクリア
404: // N,Z,V は未定義
405: CCR.c = 0;
406: m68030_exception(cpu, M68K_EXCEP_ZERODIV);
407: return false;
408: }
409:
410: // ホストでオーバーフローが起きるのはこのケースのみ
411: if (dst == INT64_MIN && src == -1) {
412: // オーバーフローの場合、
413: // X は変化しない
414: // N,Z は未定義
415: // V はセット
416: // C は常にクリア
417: CCR.v = m68030ccr::V_BIT;
418: CCR.c = 0;
419: return false;
420: }
421:
422: int64 sq64 = (int64)dst / (int32)src;
423: *rem = (int64)dst % (int32)src;
424: if ((int32)sq64 != sq64) {
425: // オーバーフロー
426: CCR.v = m68030ccr::V_BIT;
427: CCR.c = 0;
428: return false;
429: }
430:
431: // 正常の場合、
432: // X は変化しない
433: // V, C はクリア
434: // N, Z は quo の結果。
435: *quo = (uint32)sq64;
436: acc_move_32(cpu, *quo);
437: return true;
438: }
439:
440: // src_10 + dst_10 + X を計算し、XNZVC フラグをセットして結果を返す。
441: // src, dst の上位ビットはクリアしておくこと。
442: // 戻り値の上位ビットはクリアされている。
443: uint32
444: acc_abcd_8(m68kcpu *cpu, uint32 src, uint32 dst)
445: {
446: uint32 res;
447: uint32 tmp;
448: uint32 adj;
449: uint32 low;
450: uint32 c;
451:
452: adj = 0;
453: c = 0;
454:
455: // X フラグは LSB なので直接足してよい
456: tmp = src + dst + (CCR.x & m68030ccr::X_BIT);
457:
458: low = (src & 0x0f) + (dst & 0x0f) + (CCR.x & m68030ccr::X_BIT);
459: if (low > 0x09) {
460: adj = 0x06;
461: }
462:
463: if (tmp > 0x99) {
464: adj += 0x60;
465: c = m68030ccr::C_BIT;
466: }
467:
468: res = tmp + adj;
469: c |= res >> 8;
470: CCR.x = CCR.c = c;
471:
472: res &= 0xff;
473: CCR.z |= res;
474:
475: // V フラグは不定だが 68030 では常にクリア
476: CCR.v = 0;
477: // N フラグは不定だが 68030 実機合わせ
478: CCR.n = res << 24;
479:
480: return res;
481: }
482:
483: // src_10 - dst_10 - X を計算し、XNZVC フラグをセットして結果を返す。
484: // src, dst の上位ビットはクリアしておくこと。
485: // 戻り値の上位ビットはクリアされている。
486: uint32
487: acc_sbcd_8(m68kcpu *cpu, uint32 src, uint32 dst)
488: {
489: uint32 res;
490: int32 tmp;
491: int32 adj;
492: int32 low;
493: uint32 c;
494:
495: adj = 0;
496: c = 0;
497:
498: // X フラグは LSB なので直接引いてよい
499: tmp = dst - src - (CCR.x & m68030ccr::X_BIT);
500:
501: low = (dst & 0x0f) - (src & 0x0f) - (CCR.x & m68030ccr::X_BIT);
502: if (low < 0) {
503: adj = 0x06;
504: }
505:
506: if (tmp < 0) {
507: adj += 0x60;
508: c = m68030ccr::C_BIT;
509: }
510:
511: res = tmp - adj;
512: c |= res >> 8;
513: CCR.x = CCR.c = c;
514:
515: res &= 0xff;
516: CCR.z |= res;
517:
518: // V フラグは不定だが 68030 では常にクリア
519: CCR.v = 0;
520: // N フラグは不定だが 68030 実機合わせ
521: CCR.n = res << 24;
522:
523: return res;
524: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.