|
|
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 "m88100.h"
8: #include "m88100excep.h"
9: #include "debugger.h"
1.1.1.11 root 10: #include "mpu88xx0.h"
1.1 root 11:
12: #define OP_DEF(name) void __CONCAT(m88kcpu::op_,name)()
13: #define OP_FUNC(name) __CONCAT(op_,name)()
14: #include "m88100ops.cpp"
15:
1.1.1.7 root 16: // 文字列を作る前にレベルを評価するためマクロ
17: #define cpulog(lv, fmt...) do { \
18: if (__predict_false(gMPU->loglevel >= (lv))) { \
19: gMPU->putlogn(fmt); \
20: } \
21: } while (0)
22:
1.1.1.11 root 23: // 電源オン
1.1.1.8 root 24: void
25: m88kcpu::PowerOn()
26: {
1.1.1.11 root 27: // サイクルを初期化。
28: used_cycle = 0;
29:
1.1.1.8 root 30: // 履歴は電源オン時だけ初期化。
31: // (LUNA88K は ROM が正常パスで CPU リセットを行ったりするので)
32: exhist.Clear();
33: brhist.Clear();
34:
35: // この後起きるリセット例外で xip を初期化する前に参照することになるので
36: // これだけここでも初期化しておく。
37: xip = 0;
38: }
39:
1.1 root 40: // リセット例外のようなもの?
1.1.1.11 root 41: uint64
1.1.1.5 root 42: m88kcpu::Reset()
1.1 root 43: {
1.1.1.11 root 44: uint64 cycle_start = used_cycle;
45:
1.1.1.8 root 46: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
47: // リセット例外も発生時の XIP を記録する。(LUNA88K の ROM 1.20)
48: exhist.AddEntry(xip | 1, 0, 0xfc000000 | 0);
49: brhist.AddEntry(xip | 1, 0, 0xfc000000 | 0);
50: // デバッガに通知 (例外ブレーク用)
51: debugger_notify_exception(0);
52:
1.1.1.5 root 53: // 内部の割り込み状態をクリア
54: intr_pending = 0;
1.1.1.11 root 55: ChangeState(CPU_STATE_NORMAL);
56:
57: // 実際どこかは分からんけど PSR 設定の前にリセットしておきたい
58: cmmu[0].Reset();
59: cmmu[1].Reset();
1.1.1.4 root 60:
61: // Table 6-8 (p6-47)
1.1 root 62: psr = 0x800003ff;
1.1.1.4 root 63: // XXX ただし SFU1 は未実装なので下げておく
1.1 root 64: psr &= ~PSR_SFD1;
65:
1.1.1.2 root 66: #if defined(TEST_INTERRUPT)
1.1.1.4 root 67: psr &= ~PSR_IND;
68: psr &= ~PSR_SFRZ;
1.1 root 69: #endif
70:
1.1.1.4 root 71: SetPSR();
1.1.1.2 root 72:
1.1.1.8 root 73: fip = 0;
1.1.1.7 root 74:
75: // レジスタのうち明記されてるものをクリア。
76: // 不定と明記されてるものはリセットでは触らないでおく。
77: // scoreboard: cleared
1.1 root 78: nip = 0;
79: xip = 0;
1.1.1.4 root 80: vbr = 0;
81: fpecr = 0;
82: fpcr = 0;
83: fpsr = 0;
1.1.1.7 root 84: // DMTx は bit0(Valid) をクリア。他は不定
85: dmt0 &= ~DM_VALID;
86: dmt1 &= ~DM_VALID;
87: dmt2 &= ~DM_VALID;
1.1.1.4 root 88:
1.1 root 89: fetch();
1.1.1.11 root 90:
1.1.1.12! root 91: // リセット例外はここまで。
! 92: // ここからは最初の命令のプリフェッチ
! 93: Prefetch();
! 94:
1.1.1.11 root 95: return used_cycle - cycle_start;
1.1 root 96: }
97:
1.1.1.12! root 98: // プリフェッチステージ(?)。
! 99: // 命令サイクルは、自然に書けば、
! 100: // (1) パイプラインをシフトし、FIP の指すところをフェッチ。
! 101: // (2) デバッガはここに入れたい。
! 102: // (3) XIP(opX) を解釈、実行。
! 103: // の繰り返しになるが、デバッガは Exec() から戻ったところでスケジューラから
! 104: // 呼び出される構造のため、順序をずらして 1回の Exec() では (3)->(1) を実行
! 105: // してからスケジューラに戻って (2) を実行する、の順にする。
! 106: // そのため、リセット例外では1回プリフェッチを実行しておく必要がある。
! 107: inline void
! 108: m88kcpu::Prefetch()
! 109: {
! 110: // shift pipeline
! 111: opX = opF;
! 112: xip = nip;
! 113:
! 114: // prefetch next inst
! 115: fetch();
! 116: }
! 117:
1.1.1.11 root 118: // 1命令実行する。
119: // 戻り値は消費したサイクル数。
120: int
121: m88kcpu::Exec()
1.1 root 122: {
1.1.1.11 root 123: uint64 cycle_start = used_cycle;
1.1.1.12! root 124: uint32 op12;
1.1.1.5 root 125:
1.1.1.12! root 126: // この時点で実行しようとする命令が opX に入っている
1.1 root 127:
1.1.1.12! root 128: if (OpIsBusErr(opX)) {
! 129: // プリフェッチしていた命令がバスエラー
! 130: Exception(M88K_EXCEP_INST);
! 131: goto exit;
! 132: }
1.1 root 133:
1.1.1.12! root 134: op12 = op32_to_12(opX);
! 135: switch (op12) {
1.1 root 136: #include "m88100switch.inc"
1.1.1.12! root 137: default:
! 138: OP_FUNC(illegal);
! 139: break;
! 140: }
1.1.1.2 root 141:
1.1.1.12! root 142: if (intr_pending && IsIntrEnable()) {
! 143: // 割り込み処理要求が来ていて、
! 144: // 直前の命令が割り込みを禁止していなければ割り込み
! 145: // XXX 実際は違う気がする
! 146: cpulog(4, "INTR take");
! 147: ExceptionCore(M88K_EXCEP_INTERRUPT, ExceptionKind::INTR);
! 148: goto exit;
1.1 root 149: }
150:
1.1.1.12! root 151: used_cycle++;
! 152:
1.1.1.6 root 153: exit:
1.1.1.12! root 154: Prefetch();
! 155:
1.1.1.11 root 156: return used_cycle - cycle_start;
1.1.1.5 root 157: }
158:
1.1.1.11 root 159: // STOP 状態で 1 命令実行する。
160: // 戻り値は消費したサイクル数。
161: int
162: m88kcpu::ExecPseudoStop()
1.1 root 163: {
1.1.1.11 root 164: instruction_in_stop++;
165: if (instruction_in_stop > 4) {
166: ChangeState(CPU_STATE_NORMAL);
167: }
1.1 root 168:
1.1.1.11 root 169: return Exec();
1.1.1.5 root 170: }
171:
1.1.1.11 root 172:
1.1 root 173: // 通常の例外。
1.1.1.2 root 174: // DataAccessException, エラー、割り込み、TRAP からは使わない。
1.1 root 175: // vec はベクタ番号。
176: void
177: m88kcpu::Exception(int vec)
178: {
179: ExceptionCore(vec, ExceptionKind::NORMAL);
180: }
181:
182: // 例外処理コア部分
183: // vec はベクタ番号。
184: void
185: m88kcpu::ExceptionCore(int vec, ExceptionKind cause)
186: {
1.1.1.4 root 187: uint syscall = 0;
188:
1.1.1.3 root 189: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.4 root 190: // OpenBSD システムコールなら番号もついでに記録。
191: // システムコール番号は tb0 発行時点で r13 にセットされている。
192: // ただし 0 番は syscall(2) (間接システムコール) で、実際の番号は r2。
193: // 198番 __syscall(2) だと r2:r3 (なので実質 r3)。
194: if (vec == 450) {
195: syscall = r[13];
196: if (syscall == 0) {
197: syscall = r[2];
198: } else if (syscall == 198) {
199: syscall = r[3];
200: }
201: syscall &= 0xfff;
202: }
1.1.1.5 root 203: uint32 from = xip | (IsSuper() ? 1 : 0);
204: uint32 inst = 0xfc000000 | (syscall << 12) | vec;
205: exhist.AddEntry(from, 0, inst);
206: brhist.AddEntry(from, 0, inst);
1.1.1.3 root 207: // デバッガに通知 (例外ブレーク用)
1.1.1.4 root 208: debugger_notify_exception(vec);
209:
210: // 命令中で起きる例外はとりあえず全部2クロック追加? (Table.7-5)
211: if (cause != ExceptionKind::INTR) {
1.1.1.5 root 212: AddCycle(2);
1.1.1.4 root 213: }
1.1.1.3 root 214:
1.1 root 215: if (psr & PSR_SFRZ) {
216: if (cause != ExceptionKind::TRAP) {
1.1.1.7 root 217: cpulog(2, "SFRZ Error Exception");
1.1 root 218: vec = M88K_EXCEP_ERROR;
219: cause = ExceptionKind::ERROR;
220: }
221: } else {
1.1.1.7 root 222: cpulog(2, "Exception %x", vec);
1.1.1.2 root 223: if (vec != 1) {
1.1.1.7 root 224: cpulog(1, "Exception %x x=%x n=%x f=%x", vec, xip, nip, fip);
1.1.1.2 root 225: }
1.1 root 226: sxip = xip;
227: snip = nip;
1.1.1.7 root 228: sfip = fip;
1.1 root 229:
230: sxip |= SIP_V;
231: snip |= SIP_V;
1.1.1.4 root 232: sfip |= SIP_V;
1.1 root 233:
234: if (OpIsBusErr(opX)) {
235: sxip |= SIP_E; // E bit
236: }
237: if (OpIsBusErr(opF)) {
238: snip |= SIP_E; // E bit
239: }
240:
241: if (vec == M88K_EXCEP_UNIMPL_OP) {
242: sxip &= ~SIP_V;
243: }
244: }
245:
1.1.1.2 root 246: if (cause != ExceptionKind::DATA) {
247: // データアクセス例外以外は、
248: // データパイプラインはフラッシュ状態とする。
249: // ほんとうは違う。かも。
250: dmt0 = 0;
251: } else {
252: // xip: ld/st/xmem
253: // nip: next
254: // fip: fetch
255:
256: // rom1.2 は DAE が起きると、
257:
258: // ROM挙動 CPU の RTE 挙動
259: // sfip = sxip
260: // sxip -> ~V (INVALID) CPU はそもそも sxip を評価しない
261: // snip = 0 (INVALID) CPU はこれを nop 相当に処理する
262: // rte
263:
264: // してくる。そのまま読むと命令を再実行しようとしているように
265: // 読めるが、再実行すると無限ループになってしまう。
266: // DAE の時点で xip が進んでいることを期待して利用している?
267:
268: // openbsd は
269: // xmem の write バスエラーを検知すると命令を再実行するために
270: // fip = nip, nip = xip して rte する。ということは xip = xmem に
271: // なっていることを期待している。
272:
273: // というわけで
274: // ld で DataAccessException のときは、実CPUはすでに次の命令を
275: // 実行している?
276: // もう少し考えると、スコアボードでレジスタの干渉がなければ、
277: // 実行している?
278:
279: // 仕方がないのでハックでごまかす。
280: // rte のほうも参照のこと。
281:
282: if (IsSuper() && xip >= 0x41000000 && xip < 0x42000000) {
283: // 遅延例外機構がないので、ROM 合わせのハック。
284: sxip = snip;
285: }
286: }
287:
1.1 root 288: epsr = psr;
1.1.1.2 root 289: SetPSR(psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ);
1.1 root 290:
291: fip = vbr + (vec << 3);
292: fetch();
1.1.1.3 root 293: // ここでベクタに飛ぶのだが、ベクタ内の2命令でおそらく必ずもう一度
294: // 分岐してそっちでも履歴が残るので、ここでブランチ履歴を残すのは
295: // ちょっと冗長という気もする。
296:
1.1 root 297: if (OpIsBusErr(opF)) {
298: if (cause == ExceptionKind::ERROR) {
299: // double bus fault
300: // 実機は無限ループ状態
301: PANIC("Infinite ERROR (double bus fault)");
302: } else {
303: ExceptionCore(M88K_EXCEP_ERROR, ExceptionKind::ERROR);
304: }
305: }
306: }
307:
1.1.1.10 root 308: inline uint32
1.1.1.5 root 309: m88kcpu::Calcdmt(uint32 flag)
310: {
311: return
312: ((psr & PSR_BO_LE) ? DM_BO : 0)
313: | ((IsSuper() && !(flag & DM_USR)) ? DM_DAS : 0)
314: | DM_VALID;
315: }
316:
1.1 root 317: // データアクセス例外(Read)
1.1.1.5 root 318: // ld.b, ld.h, ld.hu, ld 用
1.1 root 319: void
1.1.1.5 root 320: m88kcpu::ReadDataException32(uint32 addr, uint32 flag)
1.1 root 321: {
322: // ミスアラインドはこの例外より前にチェックされていて、
323: // ここにはアラインドしかこない。
324: dma0 = addr & ~0x3;
1.1.1.5 root 325: dmt0 = Calcdmt(flag)
1.1 root 326: | (FLD_D << 7)
327: | (flag & DM_SIGNED)
328: | ((flag & DM_EN_MASK) >> (addr & 0x03))
1.1.1.5 root 329: ;
330: dmt1 &= ~DM_VALID;
331: dmt2 &= ~DM_VALID;
1.1.1.7 root 332: cpulog(1, "ReadDAE xip=%x addr=%x", xip, addr);
1.1.1.2 root 333: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1 root 334: }
335:
1.1.1.5 root 336: // データアクセス例外(Read)
337: // ld.d 用
338: void
339: m88kcpu::ReadDataException64(uint32 addr, uint32 flag)
340: {
341: // ミスアラインドはこの例外より前にチェックされていて、
342: // ここにはアラインドしかこない。
343: dma0 = addr;
344: dmt0 = Calcdmt(flag)
345: | DM_DOUB1 // ダブルワードの第1アクセスのときセット
346: | (FLD_D << 7)
347: | DM_EN_MASK // 32ビット有効
348: ;
349:
350: dma1 = dma0 + 4;
351: dmt1 = Calcdmt(flag)
352: | (FLD_D2 << 7)
353: | DM_EN_MASK // 32ビット有効
354: ;
355:
356: dmt2 &= ~DM_VALID;
357:
358: if ((flag & DM_DOUB1) == 0) {
359: // .d の2ワード目がバスエラー。第1ワードのアクセスは成功した。
1.1.1.11 root 360: // DMx0 が例外を起こしたアクセスを示す。
361: // Manual 6.7.3
362: dma0 = dma1;
363: dmt0 = dmt1;
364: dmt1 &= ~DM_VALID;
1.1.1.5 root 365: }
366:
1.1.1.7 root 367: cpulog(1, "ReadDAE64 xip=%x addr=%x", xip, addr);
1.1.1.5 root 368: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
369: }
370:
1.1 root 371: // データアクセス例外(Write)
1.1.1.5 root 372: // st.b, st.h, st.hu, st 用
1.1 root 373: void
1.1.1.5 root 374: m88kcpu::WriteDataException32(uint32 addr, uint32 flag)
1.1 root 375: {
376: // ミスアラインドはこの例外より前にチェックされていて、
377: // ここにはアラインドしかこない。
378: dma0 = addr & ~0x3;
1.1.1.5 root 379: dmt0 = Calcdmt(flag)
1.1 root 380: | (FLD_D << 7)
381: | ((flag & DM_EN_MASK) >> (addr & 0x03))
382: | DM_WRITE
1.1.1.5 root 383: ;
384: dmd0 = rD;
1.1 root 385:
1.1.1.5 root 386: dmt1 &= ~DM_VALID;
387: dmt2 &= ~DM_VALID;
1.1.1.7 root 388: cpulog(1, "WriteDAE xip=%x addr=%x", xip, addr);
1.1.1.2 root 389: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
390: }
391:
1.1.1.5 root 392: // データアクセス例外(Write)
393: // st.d 用
394: void
395: m88kcpu::WriteDataException64(uint32 addr, uint32 flag)
396: {
397: // ミスアラインドはこの例外より前にチェックされていて、
398: // ここにはアラインドしかこない。
399: dma0 = addr & ~0x3;
400: dmt0 = Calcdmt(flag)
401: | DM_DOUB1 // ダブルワードの第1アクセスのときセット
402: | (FLD_D << 7)
403: | DM_EN_MASK
404: | DM_WRITE
405: ;
406: dmd0 = rD;
407:
408: dma1 = dma0 + 4;
409: dmt1 = Calcdmt(flag)
410: | (FLD_D2 << 7)
411: | DM_EN_MASK
412: | DM_WRITE
413: ;
414: dmd1 = rD2;
415:
416: dmt2 &= ~DM_VALID;
417:
418: if ((flag & DM_DOUB1) == 0) {
419: // .d の2ワード目がバスエラー。第1ワードのアクセスは成功した。
1.1.1.11 root 420: // DMx0 が例外を起こしたアクセスを示す。
421: // Manual 6.7.3
422: dma0 = dma1;
423: dmt0 = dmt1;
424: dmd0 = dmd1;
425: dmt1 &= ~DM_VALID;
1.1.1.5 root 426: }
427:
1.1.1.7 root 428: cpulog(1, "WriteDAE64 xip=%x addr=%x", xip, addr);
1.1.1.5 root 429: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
430: }
431:
1.1.1.2 root 432: // データアクセス例外(xmem)
1.1.1.5 root 433: // xmem には .d は無い
1.1.1.2 root 434: void
1.1.1.5 root 435: m88kcpu::XmemDataException(uint32 addr, uint32 flag)
1.1.1.2 root 436: {
437: dma0 = addr & ~0x3;
1.1.1.5 root 438: dmt0 = Calcdmt(flag)
439: | DM_LOCK // xmem でセット
1.1.1.2 root 440: | (FLD_D << 7)
441: | (flag & DM_SIGNED)
442: | ((flag & DM_EN_MASK) >> (addr & 0x03))
1.1.1.5 root 443: ;
1.1.1.2 root 444:
1.1.1.5 root 445: dma1 = dma0;
446: dmt1 = Calcdmt(flag)
447: | DM_LOCK // xmem でセット
1.1.1.2 root 448: | (FLD_D << 7)
449: | (flag & DM_SIGNED)
450: | ((flag & DM_EN_MASK) >> (addr & 0x03))
451: | DM_WRITE
1.1.1.5 root 452: ;
453: dmd1 = rD;
1.1.1.2 root 454:
1.1.1.5 root 455: dmt2 &= ~DM_VALID;
1.1.1.2 root 456:
457: // ミスアラインドはこの例外より前にチェックされていて、
458: // ここにはアラインドしかこない。
459: if (cmmu[1].fault_code != m88200::FAULT_CODE_BUSERR
460: || cmmu[1].acc_read) {
461: // アドレス変換フォルトまたは read 時点
462: // nop
1.1 root 463: } else {
1.1.1.2 root 464: // xmem の write 時点
1.1.1.5 root 465: dmt0 &= ~DM_VALID;
1.1 root 466: }
1.1.1.2 root 467:
1.1.1.7 root 468: cpulog(1, "xmemDAE xip=%x addr=%x", xip, addr);
1.1.1.2 root 469: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1 root 470: }
471:
1.1.1.10 root 472: // FPxS レジスタをセット
1.1.1.5 root 473: void
1.1.1.10 root 474: m88kcpu::SetFPxS(uint32& h, uint32& l, double src, uint32 ts)
1.1.1.5 root 475: {
1.1.1.10 root 476: // FPHS[12]、FPLS[12] は以下の構造
477: //
478: // 3 2 1 0
479: // 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
480: // +-+---------------------+---------------------------------------+
481: // |S| Exponent(11bit) | High Order 20 bits of Mantissa | FPHSn
482: // +-+---------------------+---------------------------------------+
483: //
484: // +---------------------------------------------------------------+
485: // | Low Order bits of Mantissa, or Integer | FPLSn
486: // +---------------------------------------------------------------+
487: //
488: // ts が 1 (double) の場合は IEEE754 double と同じ。
489: // ts が 0 (single) の場合は float を double にキャスト (拡大変換) した
490: // ものではないことに注意。
491: // S(符号ビット)はそのまま。float の Mantissa (23bit) のうち上位 20bit
492: // を FPHSn に、残り 3bit を FPLSn の上位 3bit に。ここまではいい。
493: // Exponent は float の指数部(8bit、バイアス=127) の値を *そのまま*
494: // 符号拡張(?)する。
495: // (float)1.0 は 1.0 * 2^0 なのでバイアス込みの指数部は 127、
496: // (float)2.0 は 1.0 * 2^1 なのでバイアス込みの指数部は 128。
497: // バイアス込みにした値は符号なし数のはずだが、ここではこれを 11bit に
498: // 符号拡張して FPHSn の Exponent 部に格納するようだ。取り出す際に下位
499: // 8bit しか取り出さなければ害はないし、符号拡張する方がハードウェア的に
500: // 都合がよかったとかだろうか。
501: // 仮に普通に double に変換すると double の指数部バイアスは 1023 なので
502: // バイアス込みの指数部は先程の例だとそれぞれ 1023、1024 になるが
503: // これではないということ。
504:
505: union64 u;
506: u.q = d2u(src);
507: if (ts == 0) {
508: // single
509:
510: uint32 exp;
511: // src は普通の double なのでこの指数部を取り出す
512: uint32 double_biased = (u.h >> 20) & 0x7ff;
513: if (double_biased == 0x7ff) {
514: // Inf, NAN
515: exp = 0x7ff00000;
516: } else {
517: // double のバイアスを外して float のバイアスを足す
518: int float_biased = (double_biased - 1023) + 127;
519: // この 8bit 値を 11bit に符号拡張して所定の位置へ
520: exp = ((int32)(float_biased << 24)) >> 4;
521: exp &= 0x7ff00000;
522: }
523:
524: h = (u.h & 0x800fffff) | exp;
525: l = u.l;
526: } else {
527: // double
528: h = u.h;
529: l = u.l;
530: }
531: }
532:
533: // FPR[HL] レジスタに double 値をセット
534: // - それ以外のフィールドは保存する XXX ここでクリアしてもいいか?
535: // - XXX Guard, Round, Sticky (, AddOne) はまだない
536: void
537: m88kcpu::SetFPRx(double src)
538: {
539: union64 u;
540: uint32 exp;
541:
542: u.q = d2u(src);
543:
544: // Sign は FPRH
545: fprh &= ~(FPRH_SIGN | FPRH_MANT); // Mantissa もついでにクリア
546: fprh |= u.h & 0x80000000;
547:
548: // Exp は FPIT。
549: // double は 11bit だが FPIT::RESEXP は 12bit なので 1bit 符号拡張する。
550: // 符号付き数(正確には負数)の右シフトは実装依存だが gcc, clang は
551: // 算術右シフトになる。
552: //
553: // 3 2
554: // 1 0 9 8 7 6 5 4 3 2 1 0 9
555: // +-+---------------------+-
556: // double |S| Exponent(11bit) |
557: // +-+---------------------+-
558: //
559: // +---------------------+-+-
560: // u.h<<1 | Exponent(11bit) |X|
561: // +---------------------+-+-
562: //
563: // +-----------------------+-
564: // exp>>1 | Exponent(12bit) |
565: // +-----------------------+-
566: exp = u.h << 1;
567: exp = (int32)exp >> 1;
568: fpit &= ~FPIT_RESEXP;
569: fpit |= exp & FPIT_RESEXP;
570:
571: // Mantissa は FPRH, FPRL
572: // 上位側(FPRH)には最上位(実数桁)の隠しビットを含む。
573: fprh |= (u.h & 0x000fffff);
574: fprh |= FPRH_1;
575: fprl = u.l;
576: }
577:
578: // FP Precise 例外。浮動小数点数1つの場合。
579: void
580: m88kcpu::FPPreciseException(uint32 cause, double s2)
581: {
582: SetFPS2(s2, m88100opf_FP_T2(opX));
583: FPPreciseException(cause);
584: }
585:
586: // FP Precise 例外。浮動小数点数2つの場合。
587: void
588: m88kcpu::FPPreciseException(uint32 cause, double s1, double s2)
589: {
590: SetFPS1(s1, m88100opf_FP_T1(opX));
591: SetFPS2(s2, m88100opf_FP_T2(opX));
592: FPPreciseException(cause);
593: }
594:
595: // FP Precise 例外。
596: void
597: m88kcpu::FPPreciseException(uint32 cause)
598: {
599: assert(cause == FPECR_FIOV ||
600: cause == FPECR_FUNIMP ||
601: cause == FPECR_FPRV ||
602: cause == FPECR_FROP ||
603: cause == FPECR_FDVZ);
604:
605: fpecr = cause;
606:
607: // FPPT(FP Precise operation Type Register)
608: fppt = opX & 0xffe0; // Opcode, T1, T2, TD は opX と同じ位置
609: fppt |= m88100opf_D(opX); // DEST
610:
611: Exception(M88K_EXCEP_SFU1_PRECISE);
612: }
613:
614: // FP Imprecise 例外。
615: void
616: m88kcpu::FPImpreciseException(uint32 cause)
617: {
618: assert(cause == FPECR_FUNF ||
619: cause == FPECR_FOVF ||
620: cause == FPECR_FINX);
621:
622: fpecr = cause;
623:
624: // FPIT(FP Imprecise operation Type Register)
625: fpit &= FPIT_RESEXP;
626: fpit |= opX & FPIT_OPCODE;
627: fpit |= (opX & 0x00000020) << 5; // DESTSIZ
628: fpit |= (fpcr & 0x0000001f) << 5; // EFINV,EFDVZ,EFUNF,EFOVR,EFINX
629: fpit |= m88100opf_D(opX); // DEST
630:
631: // FPRH(FP Result High Register)
632: fprh &= ~FPRH_RNDMODE;
633: fprh |= (fpcr & FPCR_RM) << 14;
1.1.1.5 root 634:
1.1.1.10 root 635: Exception(M88K_EXCEP_SFU1_IMPRECISE);
1.1.1.5 root 636: }
637:
1.1 root 638: void
1.1.1.5 root 639: m88kcpu::Interrupt(int level)
1.1 root 640: {
1.1.1.5 root 641: // level は 0 か 1。
642: intr_pending = level;
1.1.1.11 root 643:
644: if (intr_pending && IsIntrEnable() && (cpu_state == CPU_STATE_STOP)) {
645: // 割り込みを受け付けたら STOP 解除。
646: ChangeState(CPU_STATE_NORMAL);
647: }
1.1 root 648: }
649:
650: void
651: m88kcpu::fpu_unimpl()
652: {
653: printf("%s\n", __func__);
1.1.1.10 root 654: FPPreciseException(FPECR_FUNIMP);
1.1 root 655: }
1.1.1.2 root 656:
657: OP_DEF(illegal)
658: {
659: // 本来は不当命令例外?
1.1.1.7 root 660: cpulog(0, "Illegal instruction %08x", (uint32)opX);
1.1.1.2 root 661: }
1.1.1.11 root 662:
663: void
664: m88kcpu::ChangeState(uint32 new_state)
665: {
666: if (new_state == CPU_STATE_STOP) {
667: instruction_in_stop = 0;
668: }
669:
670: if (cpu_state != new_state) {
671: cpu_state = new_state;
672: // スケジューラに通知
673: dev->NotifyCPUMode(cpu_state);
674: }
675: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.