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