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