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