|
|
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 "m68030fpu.h"
1.1.1.3 ! root 10: #include "debugger.h"
1.1 root 11:
12: static void m68030_change_intr(m68kcpu *, int);
13: static void m68030_set_intr(m68kcpu *, int);
14: static void m68030_double_bus_fault(m68kcpu *, const char *);
15:
16: // CPU コアの領域を確保して初期化
17: // reset_vector はリセット例外時に 0 番地に見せる(通常ROMの)アドレス。
18: m68kcpu *
19: m68030_init(uint32 reset_vector)
20: {
21: m68kcpu *cpu;
22:
23: cpu = new m68kcpu();
24: fpu_init(cpu);
25:
26: for (int i = 0; i < 16; i++) {
27: RegR(i) = 0xcccccccc;
28: }
29: // XXX ただし X68030 IPLROM には A6 を初期化せずに書き込んでいるバグが
30: // あるため、A6 を概ね RAM のあるあたりに指定しておく…。
31: RegA(6) = 0x000ccccc;
32:
33: // 手抜きのためリセットベクタを知っている
34: cpu->reset_vector = reset_vector;
35:
36: return cpu;
37: }
38:
39: // 二重バスフォールト
40: static void
41: m68030_double_bus_fault(m68kcpu *cpu, const char *where)
42: {
1.1.1.2 root 43: cpu->atomic_reqflag |= CPU_REQ_RELEASE | CPU_REQ_HALT;
44:
45: // コールバックがあれば呼び出す
46: if (cpu->halt_callback) {
47: cpu->halt_callback(cpu->halt_arg);
48: }
1.1 root 49: }
50:
51: // リセット例外を発生させる。
52: // 各レジスタを所定の状態にして、リセットベクタを読み込む。
53: // リセットベクタが読み込めなければ HALT 状態に移行。
54: void
55: m68030_exception_reset(m68kcpu *cpu)
56: {
1.1.1.3 ! root 57: // 例外履歴ちょっとどうするかは置いておく
! 58:
1.1 root 59: // 1. T0, T1 クリア
60: // 2. S をセット、M をクリア
61: // 3. 割り込みレベルを 7
62:
63: // ここは set_sr を使わずに設定する。
64: cpu->reg.s = true;
65: cpu->reg.m = false;
66: cpu->bus.SetFC2(cpu->reg.s);
67: // ここは割り込みレベル変化のチェックは不要でセットだけでいい。
68: m68030_set_intr(cpu, 7);
69:
70: // 4. VBR をクリア
71: RegVBR = 0;
72: // 5. キャッシュ
73: RegCACR = 0; // XXX
74: // 6. キャッシュエントリクリア
75: // 7. TC:E、TTn:E をクリア
76: cpu->SetTC(cpu->GetTC() & ~m68030TC::TC_E);
77: cpu->SetTT(0, cpu->GetTT(0) & ~m68030TT::E);
78: cpu->SetTT(1, cpu->GetTT(1) & ~m68030TT::E);
79: // 8. リセットベクタ生成
80:
81: // 9. SP をロード
82: // 10. PC をロード
83:
84: // 手抜き。
85: // XXX 本当は ROM を 0番地に見せかけてから 0番地からロードするのだが
86: // ぶっちゃけそれを外部から観測する手段もないのでなー。
87: // XXX FC を気にしないといけない
88: // XXX 読めなければ二重バスフォールト
89: // 本当はアドレスエラーもチェックするのだが、起きないので省略。
90: try {
91: RegA(7) = m68030_read_32(cpu, cpu->reset_vector);
92: RegPC = m68030_read_32(cpu, cpu->reset_vector + 4);
93: } catch (int) {
94: m68030_double_bus_fault(cpu, "reset exception");
95: }
96: }
97:
98: // MPU 外部からの割り込み受付。
99: // オートベクタの場合は vector にオートベクタの例外ベクタを指定のこと。
100: void
101: m68030_interrupt(m68kcpu *cpu, int level, int vector)
102: {
103: std::unique_lock<std::mutex> lock(cpu->intrmtx);
104:
105: // この割り込みレベルがすでにペンディングなら何もしない
106: if ((int8)(cpu->intr_pending << level) < 0) {
107: return;
108: }
109:
110: // 割り込みを受理
111: cpu->intr_pending |= (0x80U >> level);
112: cpu->intr_vector[level] = vector;
113: cpu->atomic_reqflag |= CPU_REQ_INTR;
114: }
115:
116: // 割り込みレベルの設定のみを行う。
117: // 割り込みチェックは行わない。
118: static void
119: m68030_set_intr(m68kcpu *cpu, int level)
120: {
121: cpu->reg.intr_level = level;
122: cpu->intr_mask = 0x7f >> level;
123: }
124:
125: // 割り込みのチェックとレベルの変更。
126: // ステータスレジスタの割り込みレベルを変更し、必要な割り込みチェックを行う。
127: static void
128: m68030_change_intr(m68kcpu *cpu, int level)
129: {
130: int oldlevel = cpu->reg.intr_level;
131:
132: if (oldlevel < 7 && level == 7) {
133: // レベル 7 に引き上げられたら割り込み確認
134: cpu->atomic_reqflag |= CPU_REQ_INTR;
135: } else if (oldlevel == 7 && level < 7) {
136: // レベル 7 から引き下げられたら割り込み確認
137: cpu->atomic_reqflag |= CPU_REQ_INTR;
138: } else if (oldlevel != level) {
139: // それ以外でレベルが変わったら割り込み確認?
140: cpu->atomic_reqflag |= CPU_REQ_INTR;
141: }
142: m68030_set_intr(cpu, level);
143: }
144:
145: // SR (と CCR) に data を代入する。
146: // リセット例外時には呼ばれないのであっちで必要に応じて似た処理をする必要が
147: // ある。XXX なんとかしたほうがいい
148: void
149: m68030_set_sr(m68kcpu *cpu, uint16 data)
150: {
151: bool oldS = cpu->reg.s;
152: bool oldM = cpu->reg.m;
153:
154: // 現在の SP を保存
155: if (oldS == false) {
156: RegUSP = RegA(7);
157: } else if (oldM == false) {
158: RegISP = RegA(7);
159: } else {
160: RegMSP = RegA(7);
161: }
162:
163: CCR.Set(data);
164: cpu->reg.s = ((data & M68K_SR_S) != 0);
165: cpu->reg.m = ((data & M68K_SR_M) != 0);
166: m68030_change_intr(cpu, (data >> 8) & 7);
167:
168: // 新しい SP を用意
169: if (cpu->reg.s == false) {
170: RegA(7) = RegUSP;
171: } else if (cpu->reg.m == false) {
172: RegA(7) = RegISP;
173: } else {
174: RegA(7) = RegMSP;
175: }
176:
177: // バスの FC2 を変更
178: cpu->bus.SetFC2(cpu->reg.s);
179:
180: // XXX 他に何か状態変えないといけないことあったっけか。
181: }
182:
183: // 命令中に (An)+ で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
184: // flag_pi は bit7..0 が save_pi[7..0] の A7..A0 に対応している。
185: void
186: m68030_restore_reg_pi(m68kcpu *cpu)
187: {
188: for (int i = 7; cpu->flag_pi; i--) {
189: if ((int8)cpu->flag_pi < 0) {
190: RegA(i) = cpu->save_pi[i];
191: }
192: cpu->flag_pi <<= 1;
193: }
194: }
195:
196: // 命令中に -(An) で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
197: // flag_pd は bit7..0 が save_pd[7..0] の A7..A0 に対応している。
198: void
199: m68030_restore_reg_pd(m68kcpu *cpu)
200: {
201: for (int i = 7; cpu->flag_pd; i--) {
202: if ((int8)cpu->flag_pd < 0) {
203: RegA(i) = cpu->save_pd[i];
204: }
205: cpu->flag_pd <<= 1;
206: }
207: }
208:
209: // 例外処理について。
210: //
211: // 0. リセット例外
212: // リセット例外は外部から m68030_exception_reset() を呼び出す。
213: //
214: // 1. バスエラー例外
1.1.1.3 ! root 215: // MMU による論理アドレスでのバスエラーは (m68030_mmu_translate_*() が
! 216: // false を返した後) m68030bus.cpp ルーチンが (C++の) 例外をスローする。
! 217: // 物理アドレス空間アクセス後のバスエラーは (VM側の read*()/write*() が
! 218: // (int64)-1 を返した後) m68030bus.cpp ルーチンが (C++) の例外をスローする。
! 219: // どちらのケースも m68030core.cpp のメインループで catch し、その catch
! 220: // ブロック内で m68030_exception() を呼び出す。
1.1 root 221: //
222: // 2. アドレスエラー例外
223: // アドレスエラーは m68030_jump() 内でのみ発生するはずで、その場で
1.1.1.3 ! root 224: // m68030_exception() を呼んで処理する。
1.1 root 225: //
226: // 3. 命令中で起きる例外
227: // 命令途中で起きる(確定的な)例外は m68030_exception() を呼び出す。
228: // これに該当するのは
229: // o 特権違反
230: // o A系列/F系列命令
231: // o TRAP* 系命令、CHK/CHK2 命令
232: // o トレース例外 (未実装)
233: // o ゼロ除算?
234: // o MMU 構成例外
235: // o 不当命令 (*)
236: // である。
237: // ただし、不当命令についてはどこで不当命令と判定されるかによって
238: // フローが複数存在することに注意。
239: // o 1ワード目が不当命令
240: // -> 命令がそれぞれ m68030_exception() で処理。
241: // o 1ワード目の EA が不当命令
1.1.1.3 ! root 242: // -> (C++の)例外をスローして catch 内で m68030_exception() を実行。
1.1 root 243: // o 2ワード目が不当命令
244: // -> 命令がそれぞれ m68030_exception() で処理。
245: //
246: // 4. 割り込み例外
1.1.1.3 ! root 247: // 外部デバイスは m68030_interrpt() を呼び出すことで MPU に割り込みを要求
! 248: // する。その結果 MPU は直後の命令境界で割り込みをチェックし、
! 249: // m68030_exception_interrupt() を呼び出す。
! 250: //
1.1 root 251:
252: // vector にジャンプする。vector はベクタ番号(アドレスではない)。
253: static inline void
254: m68030_jump_vector(m68kcpu *cpu, int vector)
255: {
1.1.1.3 ! root 256: uint32 vecaddr;
1.1 root 257: uint32 newpc;
258:
1.1.1.3 ! root 259: vecaddr = RegVBR + vector * 4;
! 260: RegPC = vecaddr;
1.1 root 261: newpc = m68030_fetch_32(cpu);
1.1.1.3 ! root 262: // VBR 込みのジャンプ先が確定したところで今度はブランチ履歴に記録。
! 263: // この時のブランチ元はベクタアドレス
! 264: // (RegPC は fetch によって進んでしまうので先に保存)
! 265: cpu->brhist.AddEntry(vecaddr, newpc, 0x8000);
! 266:
! 267: CHECK_ADDRESS_ERROR(newpc);
! 268: RegPC = newpc;
1.1.1.2 root 269:
270: // 実際はここでパイプライン充填のために3ワードフェッチするので、
271: // ベクタテーブルはフェッチ出来たけどそのジャンプ先がバスエラーに
272: // なるケースはここでバスエラーが出なければいけないが、まだ
273: // キャッシュを実装していないので、ここで1ワードフェッチしてみて
274: // PC を戻すあほっぽい方法を取る。
275: m68030_fetch_16(cpu);
276: RegPC -= 2;
1.1 root 277: }
278:
279: // 例外スタックフレーム $0 を生成する。
280: // vector はベクタ番号。
281: // pc はスタックに積むプログラムカウンタの値 (例外によって、この命令位置か
282: // 次の命令位置かが異なる)。
283: // sr は例外発生時の SR。
284: static inline void
285: m68030_generate_exframe_0(m68kcpu *cpu, int vector, uint32 pc, uint16 sr)
286: {
287: // 例外スタックフレーム $0
288: // SP+$00.W STATUS REGISTER
289: // +$02.L PROGRAM COUNTER ; 例外ごとに異なる
290: // +$06.W %0000 | VECTOR
291:
292: m68030_push_16(cpu, (0 << 12) | (vector * 4));
293: m68030_push_32(cpu, pc);
294: m68030_push_16(cpu, sr);
295: }
296:
297: // 例外スタックフレーム $2 を生成する。
298: // vector はベクタ番号。
299: // スタックに積む PC は常に次の命令。
300: static inline void
301: m68030_generate_exframe_2(m68kcpu *cpu, int vector, uint16 sr)
302: {
303: // 例外スタックフレーム $2
304: // SP+$00.W STATUS REGISTER
305: // +$02.L PROGRAM COUNTER ; 次の命令位置
306: // +$06.W %0010 | VECTOR
307: // +$08.L INSTRUCTION ADDRESS ; 例外を起こした命令のアドレス
308:
309: m68030_push_32(cpu, RegPPC); // 例外を起こした命令のアドレス
310: m68030_push_16(cpu, (2 << 12) | (vector * 4));
311: m68030_push_32(cpu, RegPC); // 次の命令位置
312: m68030_push_16(cpu, sr);
313: }
314:
315: // 例外スタックフレーム $B を生成する。
316: static inline void
317: m68030_generate_exframe_b(m68kcpu *cpu, int vector, uint16 sr)
318: {
319: uint16 ssw;
320: uint32 fault_addr;
321: uint32 stageBaddr;
322:
323: stageBaddr = RegPC + 2;
324: // この後のスタック操作で bus が変化する前に保存
325: fault_addr = cpu->bus.laddr;
326: // DF ビットを立てておくと RTE した後この命令を再実行。
327: ssw = cpu->bus.ssw | SSW_DF;
328:
329: // 例外スタックフレーム $B
330: // SP+$00.W STATUS REGISTER
331: // +$02.L PROGRAM COUNTER
332: // +$06.W %1011 | VECTOR
333: // +$08.W (internal register)
334: // +$0a.W SPECIAL STATUS REGISTER ; SSW
335: // +$0c.W INSTRUCTION PIPE STAGE C
336: // +$0e.W INSTRUCTION PIPE STAGE B
337: // +$10.L DATA CYCLE FAULT ADDRESS
338: // +$14.W*2 (internal register)
339: // +$18.L DATA OUTPUT BUFFER
340: // +$1c.W*4 (internal register, 4 words)
341: // +$24.L STAGE B ADDRESS
342: // +$28.W*2 (internal register, 2 words)
343: // +$2c.L DATA INPUT BUFFER
344: // +$30.W*3 (internal register, 3 words)
345: // +$36.W VERSION# | internal information
346: // +$38.W*18 (internal register, 18 words)
347: // +$5a
348: // こっちから上に向かって PUSH
349:
350: // internal registers, 18 words
351: // 内部レジスタ18ワードのうち、ここでは17ワード分を save_pd[8] (16ワード)、
352: // flag_pd (1ワード) として使うことにする。
353: // -(An) でバスエラーが起きると An は減算された状態になるが、DF ビットが
354: // 立っていて再実行する時には現行構造では命令先頭から再実行せざるをえず、
355: // そうするともう一度プリデクリメントが動いてしまう。そのため、RTE の時点
356: // で DF=1 ならプリデクリメント発生前の An に戻すという処理をする。
357: // RTE 時点で DF=0 なら命令を再実行しないため An も巻き戻してはならず、
358: // そのためプリデクリメント分の巻き戻しは RTE 時点まで行えない。
1.1.1.2 root 359: // 一方、ポストインクリメントのケースはこの少し下の
360: // m68030_exception_buserr() 内のコメント参照。
1.1 root 361: for (int i = 7; i >= 0; i--) {
362: m68030_push_32(cpu, cpu->save_pd[i]);
363: }
364: m68030_push_16(cpu, cpu->flag_pd);
365: RegA(7) -= 2;
366:
367: RegA(7) -= 2; // VERSION#
368: RegA(7) -= 6;
369: m68030_push_32(cpu, 0); // DATA INPUT BUFFER
370: RegA(7) -= 4;
371: m68030_push_32(cpu, stageBaddr); // STAGE B ADDRESS
372: RegA(7) -= 8;
373: m68030_push_32(cpu, 0); // DATA OUTPUT BUFFER
374: RegA(7) -= 4;
375: m68030_push_32(cpu, fault_addr); // DATA CYCLE FAULT ADDRESS
376: m68030_push_16(cpu, 0); // INSTRUCTION PIPE STAGE B
377: m68030_push_16(cpu, 0); // INSTRUCTION PIPE STAGE C
378: m68030_push_16(cpu, ssw);
379: RegA(7) -= 2;
380: m68030_push_16(cpu, 0xb000 | (vector << 2));
381: // 本当は現在の PC だが、再実行のため PPC を積む。
382: m68030_push_32(cpu, RegPPC); // PC
383: m68030_push_16(cpu, sr); // 例外入り口で保存した SR
384: }
385:
386: // 例外処理 (リセット・割り込み以外) を行う。
387: // vector はベクタ番号。
388: void
389: m68030_exception(m68kcpu *cpu, int vector)
390: {
1.1.1.2 root 391: // バスエラー・アドレスエラーは別で処理。
392: if (vector <= M68K_EXCEP_ADDRERR) {
393: m68030_exception_buserr(cpu, vector);
394: return;
395: }
396:
1.1.1.3 ! root 397: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
! 398: cpu->exhist.AddEntry(RegPPC, 0, 0x8000 | vector);
! 399: cpu->brhist.AddEntry(RegPPC, 0, 0x8000 | vector);
! 400: // デバッガに通知 (例外ブレーク用)
! 401: debugger_notifyexception(vector);
! 402:
1.1 root 403: // 状態を保存
404: uint16 sr = RegSR;
405:
406: // S を立てて T1,T0 を落とす
407: m68030_set_sr(cpu, (RegSR | M68K_SR_S) & ~M68K_SR_T);
408:
1.1.1.2 root 409: try {
410: switch (vector) {
411: case M68K_EXCEP_ILLEGAL: // 不当命令
412: case M68K_EXCEP_PRIV: // 特権違反例外
413: case M68K_EXCEP_ALINE: // Aライン命令例外
414: case M68K_EXCEP_FLINE: // Fライン命令例外
415: // スタックに積む PC はこの命令のアドレス
416: m68030_generate_exframe_0(cpu, vector, RegPPC, sr);
417: break;
418:
419: case M68K_EXCEP_TRAP0 // TRAP#0
420: ... M68K_EXCEP_TRAP15: // TRAP#15
421: // スタックに積む PC は次の命令
422: m68030_generate_exframe_0(cpu, vector, RegPC, sr);
423: break;
424:
425: case M68K_EXCEP_ZERODIV: // ゼロ除算
426: case M68K_EXCEP_CHK: // CHK
427: case M68K_EXCEP_TRAPV: // TRAPV
428: case M68K_EXCEP_MMU_CONFIG: // MMU 構成例外
429: m68030_generate_exframe_2(cpu, vector, sr);
430: break;
431:
432: default:
433: PANIC("$%08x exception vector %d ?", RegPPC, vector);
434: break;
1.1 root 435: }
436:
1.1.1.2 root 437: // ベクタにジャンプ
438: m68030_jump_vector(cpu, vector);
439: } catch (int vector2) {
440: assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector=%d", vector);
1.1 root 441:
1.1.1.2 root 442: // バスエラー処理へ
443: m68030_exception_buserr(cpu, vector2);
1.1 root 444: }
1.1.1.2 root 445: }
446:
447: // バスエラー・アドレスエラー例外処理を行う。
448: // 他の例外とは違いが多いので分けた。
449: void
450: m68030_exception_buserr(m68kcpu *cpu, int vector)
451: {
452: assertmsg((vector == M68K_EXCEP_BUSERR || vector == M68K_EXCEP_ADDRERR),
453: "vector=%d", vector);
454:
1.1.1.3 ! root 455: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
! 456: cpu->exhist.AddEntry(RegPPC, 0, 0x8000 | vector);
! 457: cpu->brhist.AddEntry(RegPPC, 0, 0x8000 | vector);
! 458: // デバッガに通知 (例外ブレーク用)
! 459: debugger_notifyexception(vector);
! 460:
1.1.1.2 root 461: // 状態を保存
462: uint16 sr = RegSR;
1.1 root 463:
1.1.1.2 root 464: // ここで (An)+ で変化したレジスタを命令実行前の状態に巻き戻す。
465: // EA 処理の時点で先にインクリメントしているのだが、バスエラーが
466: // 起きたということは実際にはポストインクリメントは発生しないので、
467: // ここで無条件に巻き戻してよい。SR を書き換えると A7 が切り替わって
468: // しまうので、この巻き戻しは SR を書き換える前のここで行うこと。
469: // 一方、プリデクリメントのケースはこの少し上の exframe_b の中の
470: // コメント参照。
471: m68030_restore_reg_pi(cpu);
472:
473: // S を立てて T1,T0 を落とす
474: m68030_set_sr(cpu, (RegSR | M68K_SR_S) & ~M68K_SR_T);
475:
476: try {
477: // フレームを作成。
478: // 実際はショート($A)、ロング($B)の2種類あって、本来ならショートが
479: // 使えればショートを使うのだが、ここでは全部ロングを使う。
480: m68030_generate_exframe_b(cpu, vector, sr);
481: // ベクタにジャンプ
482: m68030_jump_vector(cpu, vector);
483: } catch (int vector2) {
484: // ここに来るのはバスエラーだけのはず
485: assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector=%d", vector);
486:
487: // バスエラー・アドレスエラー処理中のバスエラーは
488: // ダブルバスフォールト。
489: m68030_double_bus_fault(cpu, "bus/address error handling");
490: }
1.1 root 491: }
492:
493: // 割り込み例外処理を行う。
494: // intrmtx なしで呼び出すこと。
495: // 割り込みチェックは m68030core.cpp::m68030_flush_interrupt() で判定している。
496: void
497: m68030_exception_interrupt(m68kcpu *cpu, int level, int vector)
498: {
1.1.1.3 ! root 499: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
! 500: cpu->exhist.AddEntry(RegPPC, 0, 0x8000 | (level << 8) | vector);
! 501: cpu->brhist.AddEntry(RegPPC, 0, 0x8000 | (level << 8) | vector);
! 502: // デバッガに通知 (例外ブレーク用)
! 503: debugger_notifyexception(vector);
1.1 root 504:
505: // 状態を保存
506: uint16 sr = RegSR;
507:
508: // S を立てて T1,T0 を落とす
509: m68030_set_sr(cpu, (RegSR | M68K_SR_S) & ~M68K_SR_T);
510: // 割り込みレベルを変更
511: m68030_change_intr(cpu, level);
512:
1.1.1.2 root 513: try {
514: // 例外スタックフレーム $0 を生成。
515: // スタックに積む PC は次の命令位置。
516: // M ビットは未実装なのでスローアウェイとか無視
517: m68030_generate_exframe_0(cpu, vector, RegPC, sr);
1.1 root 518:
1.1.1.2 root 519: // ベクタにジャンプ
520: m68030_jump_vector(cpu, vector);
521: } catch (int vector2) {
522: assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector=%d", vector);
523:
524: // バスエラー処理へ
525: m68030_exception_buserr(cpu, vector2);
526: }
1.1 root 527: }
528:
529: // RTE 命令。
530: // 例外処理の近くに置いておくほうが便利なので。
531: void
532: m68030_rte(m68kcpu *cpu)
533: {
534: uint32 pc;
535: uint16 sr;
536: uint16 frame;
537:
1.1.1.2 root 538: try {
539: sr = m68030_pop_16(cpu);
540: pc = m68030_pop_32(cpu);
541: frame = m68030_pop_16(cpu);
542: switch (frame >> 12) {
543: case 0:
544: CYCLE2(18, 20);
545: m68030_set_sr(cpu, sr);
546: m68030_jump(cpu, pc);
547: break;
548:
549: case 2:
550: CYCLE2(18, 20);
551: // +08.L INSTRUCTION ADDRESS を読み捨てる
552: RegA(7) += 4;
553: m68030_set_sr(cpu, sr);
554: m68030_jump(cpu, pc);
555: break;
556:
557: case 0x0b:
558: {
559: uint32 stage_b;
560: uint16 ssw;
561:
562: CYCLE(76);
563: RegA(7) += 2; // $08.W
564: ssw = m68030_pop_16(cpu); // $0a.W SSW
565: RegA(7) += 4 * 6; // $0c.L*6
566: stage_b = m68030_pop_32(cpu); // $24.L Stage B
567: RegA(7) += 2 * 9; // $28.W*9
568: // $3a..$58 ここが save_pd の取り出し
569: cpu->flag_pd = m68030_pop_16(cpu);
570: for (int i = 0; i < 8; i++) {
571: cpu->save_pd[i] = m68030_pop_32(cpu);
572: }
573: // A7 レジスタをリストアするかもしれない前に Super/User を
574: // 復帰しておかないといけない
575: m68030_set_sr(cpu, sr);
576:
577: // DFビットセットなら命令を再実行するため、-(An) で変化
578: // したレジスタを巻き戻す。
579: // DFビットクリアなら例外要因の命令はハンドラで処理された
580: // とみなして、次の命令に進む。
581: if ((ssw & SSW_DF)) {
582: m68030_restore_reg_pd(cpu);
583: } else {
584: pc = stage_b - 2;
585: }
586: m68030_jump(cpu, pc);
587: break;
588: }
589:
590: default:
591: PANIC("RTE frame=$%x not supported", frame >> 12);
592: break;
1.1 root 593: }
1.1.1.2 root 594: } catch (int vector2) {
595: assertmsg(vector2 == M68K_EXCEP_BUSERR, "vector2=%d", vector2);
1.1 root 596:
1.1.1.2 root 597: // RTE 処理中のバスエラーはダブルバスフォールト。
598: m68030_double_bus_fault(cpu, "bus/address error handling");
1.1 root 599: }
600: }
601:
602: static const char * const exception_name_table[] = {
1.1.1.3 ! root 603: // 0123456789012345678 <- 例外履歴欄の横幅
1.1 root 604: /* 0 */ "Reset",
605: /* 1 */ NULL,
606: /* 2 */ "Bus Error",
607: /* 3 */ "Address Error",
608: /* 4 */ "Illegal Instruction",
1.1.1.3 ! root 609: /* 5 */ "Zero Divide",
! 610: /* 6 */ "CHK/CHK2 Insn",
! 611: /* 7 */ "TRAPV, *TRAPcc Insn",
! 612: /* 8 */ "PriviledgeViolation",
1.1 root 613: /* 9 */ "Trace",
1.1.1.3 ! root 614: /* 10 */ "Line 1010 emulator",
! 615: /* 11 */ "Line 1111 emulator",
1.1 root 616: /* 12 */ NULL,
1.1.1.3 ! root 617: /* 13 */ "CoproProtoViolation",
! 618: /* 14 */ "Format Error",
! 619: /* 15 */ "Uninitialized Intr",
! 620: /* 16 */ NULL, NULL, NULL, NULL,
! 621: /* 20 */ NULL, NULL, NULL, NULL,
1.1 root 622: /* 24 */ "Spurious Interrupt",
623: /* 25 */ "Level 1 Interrupt",
624: /* 26 */ "Level 2 Interrupt",
625: /* 27 */ "Level 3 Interrupt",
626: /* 28 */ "Level 4 Interrupt",
627: /* 29 */ "Level 5 Interrupt",
628: /* 30 */ "Level 6 Interrupt",
629: /* 31 */ "Level 7 Interrupt",
630: /* 32 */ "Trap #0",
631: /* 33 */ "Trap #1",
632: /* 34 */ "Trap #2",
633: /* 35 */ "Trap #3",
634: /* 36 */ "Trap #4",
635: /* 37 */ "Trap #5",
636: /* 38 */ "Trap #6",
637: /* 39 */ "Trap #7",
638: /* 40 */ "Trap #8",
639: /* 41 */ "Trap #9",
640: /* 42 */ "Trap #10",
641: /* 43 */ "Trap #11",
642: /* 44 */ "Trap #12",
643: /* 45 */ "Trap #13",
644: /* 46 */ "Trap #14",
645: /* 47 */ "Trap #15",
1.1.1.3 ! root 646: // 0123456789012345678
1.1 root 647: /* 48 */ "FPCP Branch",
1.1.1.3 ! root 648: /* 49 */ "FPCP InexcactResult",
! 649: /* 50 */ "FPCP Divide by Zero",
1.1 root 650: /* 51 */ "FPCP UnderFlow",
1.1.1.3 ! root 651: /* 52 */ "FPCP Operand Error",
1.1 root 652: /* 53 */ "FPCP OverFlow",
1.1.1.3 ! root 653: /* 54 */ "FPCP Signaling NAN",
1.1 root 654: /* 55 */ NULL,
1.1.1.3 ! root 655: /* 56 */ "MMU Config Error",
1.1 root 656: /* 57 */ NULL,
657: /* 58 */ NULL,
658: /* 59 */ NULL,
659: /* 60 */ NULL,
660: /* 61 */ NULL,
661: /* 62 */ NULL,
662: /* 63 */ NULL,
1.1.1.3 ! root 663: // 0123456789012345678
! 664: /* $40 */ "MFP Alarm",
! 665: /* $41 */ "MFP EXPON",
! 666: /* $42 */ "MFP POWSW",
! 667: /* $43 */ "MFP FM IRQ",
! 668: /* $44 */ "MFP Timer-D",
! 669: /* $45 */ "MFP Timer-C",
! 670: /* $46 */ "MFP V-Disp",
! 671: /* $47 */ "MFP GPIP5",
! 672: /* $48 */ "MFP Timer-B",
! 673: /* $49 */ "MFP TX Error",
! 674: /* $4a */ "MFP TX Empty",
! 675: /* $4b */ "MFP RX Error",
! 676: /* $4c */ "MFP RX Full",
! 677: /* $4d */ "MFP Timer-A",
! 678: /* $4e */ "MFP CRTC IRQ",
! 679: /* $4f */ "MFP H-Sync",
! 680: /* $50 */ "SCC#B TX Empty",
! 681: /* $51 */ "SCC#B TX Empty",
! 682: /* $52 */ "SCC#B",
! 683: /* $53 */ "SCC#B",
! 684: /* $54 */ "SCC#B",
! 685: /* $55 */ "SCC#B",
! 686: /* $56 */ "SCC#B",
! 687: /* $57 */ "SCC#B",
! 688: /* $58 */ "SCC#A TX Empty",
! 689: /* $59 */ "SCC#A TX Empty",
! 690: /* $5a */ "SCC#A",
! 691: /* $5b */ "SCC#A",
! 692: /* $5c */ "SCC#A",
! 693: /* $5d */ "SCC#A",
! 694: /* $5e */ "SCC#A",
! 695: /* $5f */ "SCC#A",
! 696:
! 697: // 0123456789012345678
! 698: /* $60 */ "I/O FDC Intr",
! 699: /* $61 */ "I/O FDD Intr",
! 700: /* $62 */ "I/O HDC Intr",
! 701: /* $63 */ "I/O PRN Intr",
! 702: /* $64 */ "DMAC#0 Complete",
! 703: /* $65 */ "DMAC#0 Error",
! 704: /* $66 */ "DMAC#1 Complete",
! 705: /* $67 */ "DMAC#1 Error",
! 706: /* $68 */ "DMAC#2 Complete",
! 707: /* $69 */ "DMAC#2 Error",
! 708: /* $6a */ "DMAC#3 Complete",
! 709: /* $6b */ "DMAC#3 Error",
! 710: /* $6c */ "SPC Interrupt",
! 711: /* $6d */ NULL,
! 712: /* $6e */ NULL,
! 713: /* $6f */ NULL,
! 714:
! 715: /* $70 */ NULL, NULL, NULL, NULL,
! 716: /* $74 */ NULL, NULL, NULL, NULL,
! 717: /* $78 */ NULL, NULL, NULL, NULL,
! 718: /* $7c */ NULL, NULL, NULL, NULL,
! 719: /* $80 */ NULL, NULL, NULL, NULL, // MIDI
! 720: /* $84 */ NULL, NULL, NULL, NULL, // MIDI
! 721: /* $88 */ NULL, NULL, NULL, NULL, // MIDI
! 722: /* $8c */ NULL, NULL, NULL, NULL, // MIDI
! 723: /* $90 */ NULL, NULL, NULL, NULL,
! 724: /* $94 */ NULL, NULL, NULL, NULL,
! 725: /* $98 */ NULL, NULL, NULL, NULL,
! 726: /* $9c */ NULL, NULL, NULL, NULL,
! 727: /* $a0 */ NULL, NULL, NULL, NULL, // MIDI
! 728: /* $a4 */ NULL, NULL, NULL, NULL, // MIDI
! 729: /* $a8 */ NULL, NULL, NULL, NULL, // MIDI
! 730: /* $ac */ NULL, NULL, NULL, NULL, // MIDI
! 731: /* $b0 */ NULL, NULL, NULL, NULL, // RS-232C
! 732: /* $b4 */ NULL, NULL, NULL, NULL, // RS-232C
! 733: /* $b8 */ NULL, NULL, NULL, NULL, // RS-232C
! 734: /* $bc */ NULL, NULL, NULL, NULL, // RS-232C
! 735: /* $c0 */ NULL, NULL, NULL, NULL, // RS-232C
! 736: /* $c4 */ NULL, NULL, NULL, NULL, // RS-232C
! 737: /* $c8 */ NULL, NULL, NULL, NULL, // RS-232C
! 738: /* $cc */ NULL, NULL, NULL, NULL, // RS-232C
! 739: /* $d0 */ NULL, NULL, NULL, NULL,
! 740: /* $d4 */ NULL, NULL, NULL, NULL,
! 741: /* $d8 */ NULL, NULL, NULL, NULL,
! 742: /* $dc */ NULL, NULL, NULL, NULL,
! 743: /* $e0 */ NULL, NULL, NULL, NULL,
! 744: /* $e4 */ NULL, NULL, NULL, NULL,
! 745: /* $e8 */ NULL, NULL, NULL, NULL,
! 746: /* $ec */ NULL, NULL, NULL, NULL,
! 747:
! 748: // 0123456789012345678
! 749: /* $f0 */ "PSX16x50 Interrupt",
! 750: /* $f1 */ NULL,
! 751: /* $f2 */ NULL,
! 752: /* $f3 */ NULL,
! 753: /* $f4 */ NULL,
! 754: /* $f5 */ NULL,
! 755: /* $f6 */ "ExSPC Interrupt",
! 756: /* $f7 */ NULL, // TS-6BSI
! 757: /* $f8 */ "Nereid#1 Interrupt",
! 758: /* $f9 */ "Neptune-X Interrupt",
! 759: /* $fa */ "Nereid#1 USB",
! 760: /* $fb */ "Nereid#0 USB",
! 761: /* $fc */ NULL,
! 762: /* $fd */ NULL,
! 763: /* $fe */ NULL,
! 764: /* $ff */ NULL,
1.1 root 765: };
766:
767: // ベクタ番号から表示名を返す
768: const char *
769: m68030_get_exception_name(int vector)
770: {
771: const char *name = NULL;
772: if (vector < countof(exception_name_table)) {
773: name = exception_name_table[vector];
774: }
775: if (name == NULL) {
776: name = "(reserved?)";
777: }
778: return name;
779: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.