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