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