|
|
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:
1.1.1.8 root 7: #include "mpu680x0.h"
8: #include "debugger.h"
9: #include "interrupt.h"
10: #include "scheduler.h"
1.1.1.6 root 11: #include "vectortable.h"
1.1 root 12:
1.1.1.8 root 13: #define OP_FUNC(name) __CONCAT(op_,name)()
1.1 root 14:
1.1.1.6 root 15: // 1命令実行する。
1.1.1.8 root 16: // 割り込みチェックなどを省いたショート版。
1.1.1.6 root 17: // 戻り値は消費したサイクル数。
1.1.1.8 root 18: void
19: MPU680x0Device::ExecShort(Event& ev)
1.1 root 20: {
1.1.1.8 root 21: uint64 cycle_start = used_cycle;
1.1 root 22:
1.1.1.6 root 23: try {
24: // 1命令版では switch-case を使うしかない。
1.1.1.8 root 25: ppc = reg.pc;
26: flag_pi = 0;
27: flag_pd = 0;
28: ir = fetch_16();
1.1.1.6 root 29:
30: // uint16 を 6ビット右シフトしたら 1024 以上になるはずは
31: // ないのだが、デフォルトでは gcc/clang どちらも律儀に
32: // 1024 以上かどうか比較して分岐しようとする。
33: // gcc は __assume() を入れることでこの比較・分岐を出力
34: // しないようにすることが出来た(がパフォーマンスの差は
35: // 見えない程度でしかなかった)。
36: // clang ではどうやったら効くか不明。
1.1.1.8 root 37: uint16 ir6 = ir >> 6;
38: __assume(ir6 < 1024);
39: switch (ir6) {
1.1 root 40: #include "m68030switch.h"
41: }
1.1.1.4 root 42:
1.1.1.8 root 43: used_cycle += cycle_nocache;
44: cycle_nocache = 0;
1.1.1.6 root 45: } catch (int vector) {
46: // ここで(C++の)例外スローをキャッチするのは
47: // - メモリ空間をアクセスした先でのバスエラー例外
48: // - EA パース中の不当命令例外
49: // のみ。それ以外の命令途中例外はその場で処理できる。
1.1.1.8 root 50: if (__predict_false(loglevel >= 2)) {
51: const char *name = vectortable->GetExceptionName(vector);
1.1.1.7 root 52: if (__predict_true(name)) {
1.1.1.8 root 53: putlogn("%s", name);
1.1.1.7 root 54: } else {
1.1.1.8 root 55: putlogn("vector 0x%x", vector);
1.1.1.7 root 56: }
57: }
1.1.1.9 ! root 58: if (vector == M68K::EXCEP_BUSERR) {
! 59: ExceptionBuserr(vector);
! 60: } else {
! 61: Exception(vector);
! 62: }
1.1.1.6 root 63: }
1.1 root 64:
1.1.1.6 root 65: // 外部割り込みの起動は VM 側で処理している。
1.1 root 66:
1.1.1.8 root 67: int cycle = used_cycle - cycle_start;
68: ev.time = cycle * clock_nsec;
69: scheduler->StartEvent(ev);
70: }
71:
72: // 二重バスフォールト
73: void
74: MPU680x0Device::DoubleBusFault(const char *where)
75: {
76: // where をログに出す?
77:
78: // ホールト状態へ移行
79: Halt();
80: }
81:
82: // SR (と CCR) をセットする。
83: // リセット例外以外から使う (リセット例外はやや異なるため)。
84: //
85: // 割り込みマスクが変わる場合は、ここで次の命令実行コールバックを差し替える。
86: void
87: MPU680x0Device::SetSR(uint16 data)
88: {
89: bool oldS = reg.s;
90: bool oldM = reg.m;
91:
92: // 現在の SP を保存
93: if (oldS == false) {
94: reg.usp = reg.A[7];
95: } else if (oldM == false) {
96: reg.isp = reg.A[7];
97: } else {
98: reg.msp = reg.A[7];
99: }
100:
101: reg.ccr.Set(data);
102: reg.s = ((data & M68K::SR_S) != 0);
103: reg.m = ((data & M68K::SR_M) != 0);
104:
105: // 割り込みマスクレジスタを更新して..
106: uint new_mask = (data >> 8) & 7;
107: if (reg.intr_mask != new_mask) {
108: reg.intr_mask = new_mask;
109:
110: // 次の命令境界で割り込みをチェックさせる
111: MakeNextFull();
112: }
113:
114: // 新しい SP を用意
115: if (reg.s == false) {
116: reg.A[7] = reg.usp;
117: } else if (reg.m == false) {
118: reg.A[7] = reg.isp;
119: } else {
120: reg.A[7] = reg.msp;
121: }
122:
123: // バスの FC2 を変更
124: bus.SetFC2(reg.s);
125:
126: // XXX 他に何か状態変えないといけないことあったっけか。
127: }
128:
129: // 命令中に (An)+ で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
130: // flag_pi は bit7..0 が save_pi[7..0] の A7..A0 に対応している。
131: void
132: MPU680x0Device::restore_reg_pi()
133: {
134: for (int i = 7; flag_pi; i--) {
135: if ((int8)flag_pi < 0) {
136: reg.A[i] = save_pi[i];
137: }
138: flag_pi <<= 1;
139: }
140: }
141:
142: // 命令中に -(An) で変化したアドレスレジスタを命令実行前の状態に巻き戻す。
143: // flag_pd は bit7..0 が save_pd[7..0] の A7..A0 に対応している。
144: void
145: MPU680x0Device::restore_reg_pd()
146: {
147: for (int i = 7; flag_pd; i--) {
148: if ((int8)flag_pd < 0) {
149: reg.A[i] = save_pd[i];
150: }
151: flag_pd <<= 1;
152: }
153: }
154:
155: // vector にジャンプする。vector はベクタ番号(アドレスではない)。
156: void
157: MPU680x0Device::JumpVector(int vector)
158: {
159: uint32 vecaddr;
160: uint32 newpc;
161:
162: vecaddr = reg.vbr + vector * 4;
163: reg.pc = vecaddr;
164: newpc = fetch_32();
165: // VBR 込みのジャンプ先が確定したところで今度はブランチ履歴に記録。
166: // この時のブランチ元はベクタアドレス
167: // (reg.pc は fetch によって進んでしまうので先に保存)
1.1.1.9 ! root 168: uint32 inst = BranchHistory_m680x0::VectorJump;
! 169: brhist.AddEntry(vecaddr | (IsSuper() ? 1 : 0), newpc, inst);
1.1.1.8 root 170:
171: // 奇数番地ならアドレスエラー
172: if (__predict_false((newpc & 1) != 0)) {
1.1.1.9 ! root 173: ExceptionBuserr(M68K::EXCEP_ADDRERR);
1.1.1.8 root 174: return;
175: }
176: reg.pc = newpc;
177:
178: // 実際はここでパイプライン充填のために3ワードフェッチするので、
179: // ベクタテーブルはフェッチ出来たけどそのジャンプ先がバスエラーに
180: // なるケースはここでバスエラーが出なければいけないが、まだ
181: // キャッシュを実装していないので、ここで1ワードフェッチしてみて
182: // PC を戻すあほっぽい方法を取る。
183: fetch_16();
184: reg.pc -= 2;
185: }
186:
187: // 例外スタックフレーム $0 を生成する。
188: // vector はベクタ番号。
189: // pc はスタックに積むプログラムカウンタの値 (例外によって、この命令位置か
190: // 次の命令位置かが異なる)。
191: // sr は例外発生時の SR。
192: inline void
193: MPU680x0Device::GenerateExframe0(int vector, uint32 pc, uint16 sr)
194: {
195: // 例外スタックフレーム $0
196: // SP+$00.W STATUS REGISTER
197: // +$02.L PROGRAM COUNTER ; 例外ごとに異なる
198: // +$06.W %0000 | VECTOR
199:
200: push_16((0 << 12) | (vector * 4));
201: push_32(pc);
202: push_16(sr);
203: }
204:
205: // 例外スタックフレーム $2 を生成する。
206: // vector はベクタ番号。
207: // スタックに積む PC は常に次の命令。
208: inline void
209: MPU680x0Device::GenerateExframe2(int vector, uint16 sr)
210: {
211: // 例外スタックフレーム $2
212: // SP+$00.W STATUS REGISTER
213: // +$02.L PROGRAM COUNTER ; 次の命令位置
214: // +$06.W %0010 | VECTOR
215: // +$08.L INSTRUCTION ADDRESS ; 例外を起こした命令のアドレス
216:
217: push_32(ppc); // 例外を起こした命令のアドレス
218: push_16((2 << 12) | (vector * 4));
219: push_32(reg.pc); // 次の命令位置
220: push_16(sr);
221: }
222:
223: // 例外スタックフレーム $B を生成する。
224: inline void
225: MPU680x0Device::GenerateExframeB(int vector, uint16 sr)
226: {
227: uint16 ssw;
228: uint32 fault_addr;
229: uint32 stageBaddr;
230:
231: stageBaddr = reg.pc + 2;
232: // この後のスタック操作で bus が変化する前に保存
233: fault_addr = bus.laddr;
234: // DF ビットを立てておくと RTE した後この命令を再実行。
235: ssw = bus.ssw | M68K::SSW_DF;
236:
237: // 例外スタックフレーム $B
238: // SP+$00.W STATUS REGISTER
239: // +$02.L PROGRAM COUNTER
240: // +$06.W %1011 | VECTOR
241: // +$08.W (internal register)
242: // +$0a.W SPECIAL STATUS REGISTER ; SSW
243: // +$0c.W INSTRUCTION PIPE STAGE C
244: // +$0e.W INSTRUCTION PIPE STAGE B
245: // +$10.L DATA CYCLE FAULT ADDRESS
246: // +$14.W*2 (internal register)
247: // +$18.L DATA OUTPUT BUFFER
248: // +$1c.W*4 (internal register, 4 words)
249: // +$24.L STAGE B ADDRESS
250: // +$28.W*2 (internal register, 2 words)
251: // +$2c.L DATA INPUT BUFFER
252: // +$30.W*3 (internal register, 3 words)
253: // +$36.W VERSION# | internal information
254: // +$38.W*18 (internal register, 18 words)
255: // +$5a
256: // こっちから上に向かって PUSH
257:
258: // internal registers, 18 words
259: // 内部レジスタ18ワードのうち、ここでは17ワード分を save_pd[8] (16ワード)、
260: // flag_pd (1ワード) として使うことにする。
261: // -(An) でバスエラーが起きると An は減算された状態になるが、DF ビットが
262: // 立っていて再実行する時には現行構造では命令先頭から再実行せざるをえず、
263: // そうするともう一度プリデクリメントが動いてしまう。そのため、RTE の時点
264: // で DF=1 ならプリデクリメント発生前の An に戻すという処理をする。
265: // RTE 時点で DF=0 なら命令を再実行しないため An も巻き戻してはならず、
266: // そのためプリデクリメント分の巻き戻しは RTE 時点まで行えない。
267: // 一方、ポストインクリメントのケースはこの少し下の
268: // ExceptionBuserr() 内のコメント参照。
269: for (int i = 7; i >= 0; i--) {
270: push_32(save_pd[i]);
271: }
272: push_16(flag_pd);
273: reg.A[7] -= 2;
274:
275: reg.A[7] -= 2; // VERSION#
276: reg.A[7] -= 6;
277: push_32(0); // DATA INPUT BUFFER
278: reg.A[7] -= 4;
279: push_32(stageBaddr); // STAGE B ADDRESS
280: reg.A[7] -= 8;
281: push_32(0); // DATA OUTPUT BUFFER
282: reg.A[7] -= 4;
283: push_32(fault_addr); // DATA CYCLE FAULT ADDRESS
284: push_16(0); // INSTRUCTION PIPE STAGE B
285: push_16(0); // INSTRUCTION PIPE STAGE C
286: push_16(ssw);
287: reg.A[7] -= 2;
288: push_16(0xb000 | (vector << 2));
289: // 本当は現在の PC だが、再実行のため PPC を積む。
290: push_32(ppc); // PC
291: push_16(sr); // 例外入り口で保存した SR
292: }
293:
294: // 例外処理について。
295: //
296: // 0. リセット例外
297: // リセット例外は外部から ExceptionReset() を呼び出す。
298: //
299: // 1. バスエラー例外
300: // MMU による論理アドレスでのバスエラーは (Translate*() が false を返した後)
301: // m68030bus.cpp ルーチンが (C++の) 例外をスローする。
302: // 物理アドレス空間アクセス後のバスエラーは (VM側の read*()/write*() が
303: // (int64)-1 を返した後) m68030bus.cpp ルーチンが (C++) の例外をスローする。
304: // どちらのケースも m68030core.cpp のメインループで catch し、その catch
1.1.1.9 ! root 305: // ブロック内で ExceptionBuserr() を呼び出す。
1.1.1.8 root 306: //
307: // 2. アドレスエラー例外
308: // アドレスエラーは Jump() 内でのみ発生するはずで、その場で
1.1.1.9 ! root 309: // ExceptionBuserr() を呼んで処理する。
1.1.1.8 root 310: //
311: // 3. 命令中で起きる例外
312: // 命令途中で起きる(確定的な)例外は Exception() を呼び出す。
313: // これに該当するのは
314: // o 特権違反
315: // o A系列/F系列命令
316: // o TRAP* 系命令、CHK/CHK2 命令
317: // o トレース例外 (未実装)
318: // o ゼロ除算?
319: // o MMU 構成例外
320: // o 不当命令 (*)
321: // である。
322: // ただし、不当命令についてはどこで不当命令と判定されるかによって
323: // フローが複数存在することに注意。
324: // o 1ワード目が不当命令
325: // -> 命令がそれぞれ Exception() で処理。
326: // o 1ワード目の EA が不当命令
327: // -> (C++の)例外をスローして catch 内で Exception() を実行。
328: // o 2ワード目が不当命令
329: // -> 命令がそれぞれ Exception() で処理。
330: //
331: // 4. 割り込み例外
332: // 別コメント(下のほう)参照。
333: //
334:
335: // リセット例外処理。
336: // 各レジスタを所定の状態にして、リセットベクタを読み込む。
337: // リセットベクタが読み込めなければ HALT 状態に移行。
338: // 戻り値は消費したサイクル数。
339: int
340: MPU680x0Device::ExceptionReset()
341: {
342: uint64 cycle_start = used_cycle;
343:
344: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
345: // m68k では今の所リセット例外発生時の PC にはあまり意味がないけど、
346: // m88k と動作を揃えておく。
347: const uint vector = 0;
1.1.1.9 ! root 348: exhist.AddEntry(reg.pc | 1, 0, BranchHistory_m680x0::Exception | 0);
! 349: brhist.AddEntry(reg.pc | 1, 0, BranchHistory_m680x0::Exception | 0);
1.1.1.8 root 350: // デバッガに通知 (例外ブレーク用)。こっちのベクタは 0 のままでよい。
351: debugger->NotifyExceptionMain(vector);
352:
353: // RESET 信号線をネゲートしてから SP の読み込み開始まで 4クロック
354: // (Section 7.8, Figure 7-64)
355: used_cycle += 4;
356:
357: // STOP 状態とホールト状態を解除。
358: ChangeState(CPU_STATE_NORMAL);
359:
360: // 1. T0, T1 クリア
361: // 2. S をセット、M をクリア
362: // 3. 割り込みレベルを 7
363:
364: // ここは SetSR を使わずに設定する。
365: reg.s = true;
366: reg.m = false;
367: bus.SetFC2(reg.s);
368: // ここは割り込みレベル変化のチェックは不要でセットだけでいい。
369: reg.intr_mask = 7;
370:
371: // 4. VBR をクリア
372: reg.vbr = 0;
373: // 5. キャッシュ
374: reg.cacr = 0; // XXX
375: // 6. キャッシュエントリクリア
376: // 7. TC:E、TTn:E をクリア
377: SetTC(GetTC() & ~m68030TC::TC_E);
378: SetTT(0, GetTT(0) & ~m68030TT::E);
379: SetTT(1, GetTT(1) & ~m68030TT::E);
380: // 8. リセットベクタ生成
381:
382: // 9. SP をロード
383: // 10. PC をロード
384: try {
385: reg.pc = 0;
386: reg.A[7] = fetch_32();
387: uint32 pc = fetch_32();
388: // 大丈夫のはずだけど fetch_32() が reg.pc を書き換えるので一応
389: reg.pc = pc;
390: // リセットベクタは常に 0, 4 番地から取得したことになっている
1.1.1.9 ! root 391: uint32 inst = BranchHistory_m680x0::VectorJump;
! 392: brhist.AddEntry(0x00000004 | 1, reg.pc, inst);
1.1.1.8 root 393: } catch (int) {
394: DoubleBusFault("reset exception");
395: }
396:
397: // SP のアドレスエラーはリセット例外ではチェックしないようだ。
398: // PC のアドレスエラーは本来ならここにあるはずの3ワードのプリフェッチで
399: // 行われるのだが、それがないので、とりあえずここで。
400: if ((reg.pc & 1) != 0) {
401: DoubleBusFault("reset exception");
402: }
403:
404: return used_cycle - cycle_start;
405: }
406:
1.1.1.9 ! root 407: // 汎用の例外処理を行う。vector はベクタ番号。
! 408: // ただし以下の例外はここではなくそれぞれ固有のを呼ぶこと。
! 409: // o リセット例外は ExceptionReset()
! 410: // o 割り込み例外は ExceptionInterrupt()
! 411: // o TRAP#15 例外は ExceptionTrap15()
! 412: // o バスエラー・アドレスエラーは ExceptionBuserr()
1.1.1.8 root 413: void
414: MPU680x0Device::Exception(int vector)
415: {
1.1.1.9 ! root 416: uint32 inst = BranchHistory_m680x0::Exception | vector;
! 417: ExceptionGeneric(vector, inst);
! 418: }
! 419:
! 420: // TRAP #15 の例外処理を行う。
! 421: // 処理自体は汎用の Exception() とまったく同じだが、
! 422: // IOCS コールの時には分岐履歴の出力が変わるため入口を分けてある。
! 423: void
! 424: MPU680x0Device::ExceptionTrap15()
! 425: {
! 426: // 今発生した TRAP #15 が IOCS コールっぽいかどうか調べる。
! 427: //
! 428: // Human68k 方面をやってる時は TRAP #15 は IOCS コールで表示してほしい。
! 429: // 一方、NetBSD のカーネル内では TRAP #15 は IOCS コールではない別用途
! 430: // なので IOCS コールかのように表示されるのは紛らわしい。さらに言えば
! 431: // NetBSD でもブートローダの時点はまだ IOCS コールを使うので、出来れば
! 432: // 今呼ばれたこれが IOCS コールなのか、そうでない TRAP #15 なのかは
! 433: // 区別したい。
! 434: //
! 435: // IOCS コールかどうかは厳密には分からないが、これが呼ばれた時点で
! 436: // ワークエリアの $cbc == 0x03、$cbe == 0xff であれば IOCS コールと
! 437: // 判定することにする。
! 438: // $cbc は MPU 種別で 3:68030。
! 439: // $cbe は MMU 有無で 0xff:有り。
! 440: // 今の所 68030/MMU有り しかサポートしていないので。
! 441: // だめならまた考える。
! 442:
! 443: const int vector = M68K::EXCEP_TRAP15;
! 444: uint32 inst;
! 445: if (mainbus->Peek8(0xcbc) == 0x03 && mainbus->Peek8(0xcbe) == 0xff) {
! 446: // IOCS コールっぽい
! 447: inst = BranchHistory_m680x0::IOCSCall | (reg.D[0] & 0xff);
! 448: } else {
! 449: // TRAP#15 っぽい
! 450: inst = BranchHistory_m680x0::Exception | vector;
1.1.1.8 root 451: }
1.1.1.9 ! root 452: ExceptionGeneric(vector, inst);
! 453: }
1.1.1.8 root 454:
1.1.1.9 ! root 455: // 汎用の例外処理本体。
! 456: void
! 457: MPU680x0Device::ExceptionGeneric(int vector, uint32 inst)
! 458: {
1.1.1.8 root 459: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
460: uint32 from = ppc | (IsSuper() ? 1 : 0);
1.1.1.9 ! root 461: exhist.AddEntry(from, 0, inst);
! 462: brhist.AddEntry(from, 0, inst);
1.1.1.8 root 463: // デバッガに通知 (例外ブレーク用)
464: debugger->NotifyExceptionMain(vector);
465:
466: // 状態を保存
467: uint16 sr = GetSR();
468:
469: // S を立てて T1,T0 を落とす
470: SetSR((GetSR() | M68K::SR_S) & ~M68K::SR_T);
471:
472: try {
473: switch (vector) {
474: case M68K::EXCEP_ILLEGAL: // 不当命令
475: case M68K::EXCEP_PRIV: // 特権違反例外
476: case M68K::EXCEP_ALINE: // Aライン命令例外
477: case M68K::EXCEP_FLINE: // Fライン命令例外
478: // スタックに積む PC はこの命令のアドレス
479: GenerateExframe0(vector, ppc, sr);
480: break;
481:
482: case M68K::EXCEP_TRAP0 // TRAP#0
483: ... M68K::EXCEP_TRAP15: // TRAP#15
484: // スタックに積む PC は次の命令
485: GenerateExframe0(vector, reg.pc, sr);
486: break;
487:
488: case M68K::EXCEP_ZERODIV: // ゼロ除算
489: case M68K::EXCEP_CHK: // CHK
490: case M68K::EXCEP_TRAPV: // TRAPV
491: case M68K::EXCEP_MMU_CONFIG: // MMU 構成例外
492: GenerateExframe2(vector, sr);
493: break;
494:
495: default:
496: PANIC("$%08x exception vector %d ?", ppc, vector);
497: break;
498: }
499:
500: // ベクタにジャンプ
501: JumpVector(vector);
502: } catch (int vector2) {
503: assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector);
504:
505: // バスエラー処理へ
506: ExceptionBuserr(vector2);
507: }
508: }
509:
510: // バスエラー・アドレスエラー例外処理を行う。
511: // 他の例外とは違いが多いので分けた。
512: void
513: MPU680x0Device::ExceptionBuserr(int vector)
514: {
515: assertmsg((vector == M68K::EXCEP_BUSERR || vector == M68K::EXCEP_ADDRERR),
516: "vector=%d", vector);
517:
518: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
519: uint32 from = ppc | (IsSuper() ? 1 : 0);
1.1.1.9 ! root 520: uint32 inst = BranchHistory_m680x0::Exception | vector;
! 521: exhist.AddEntry(from, 0, inst);
! 522: brhist.AddEntry(from, 0, inst);
1.1.1.8 root 523: // デバッガに通知 (例外ブレーク用)
524: debugger->NotifyExceptionMain(vector);
525:
526: // 状態を保存
527: uint16 sr = GetSR();
528:
529: // ここで (An)+ で変化したレジスタを命令実行前の状態に巻き戻す。
530: // EA 処理の時点で先にインクリメントしているのだが、バスエラーが
531: // 起きたということは実際にはポストインクリメントは発生しないので、
532: // ここで無条件に巻き戻してよい。SR を書き換えると A7 が切り替わって
533: // しまうので、この巻き戻しは SR を書き換える前のここで行うこと。
534: // 一方、プリデクリメントのケースはこの少し上の ExframeB の中の
535: // コメント参照。
536: restore_reg_pi();
537:
538: // S を立てて T1,T0 を落とす
539: SetSR((GetSR() | M68K::SR_S) & ~M68K::SR_T);
540:
541: try {
542: // フレームを作成。
543: // 実際はショート($A)、ロング($B)の2種類あって、本来ならショートが
544: // 使えればショートを使うのだが、ここでは全部ロングを使う。
545: GenerateExframeB(vector, sr);
546: // ベクタにジャンプ
547: JumpVector(vector);
548: } catch (int vector2) {
549: // ここに来るのはバスエラーだけのはず
550: assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector);
551:
552: // バスエラー・アドレスエラー処理中のバスエラーは
553: // ダブルバスフォールト。
554: DoubleBusFault("bus/address error handling");
555: }
556: }
557:
558: // 割り込み例外処理を行う。
559: // 割り込みの受け付けとレベルのチェック等の後、次命令境界で呼ばれるやつ。
560: int
561: MPU680x0Device::ExceptionInterrupt()
562: {
563: int cycle_start = used_cycle;
564: int level = intr_level;
565:
566: // ユーザーズマニュアル(日本語) p.399 図8-5 の中ほど
567: // 「/IPEND をネゲート、割り込みアクノリッジサイクルを実行」
568: // 以降に相当。
569:
570: // STOP なら解除
571: ChangeState(CPU_STATE_NORMAL);
572:
573: // 割り込みアクノリッジサイクルを実行
574: int vector = interruptdev->InterruptAcknowledge(level);
575: if (vector == -1) {
576: vector = 24 + level;
577: }
578:
579: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
580: uint32 from = ppc | (IsSuper() ? 1 : 0);
1.1.1.9 ! root 581: uint32 inst = BranchHistory_m680x0::Exception | vector;
1.1.1.8 root 582: exhist.AddEntry(from, 0, inst);
583: brhist.AddEntry(from, 0, inst);
584: // デバッガに通知 (例外ブレーク用)
585: debugger->NotifyExceptionMain(vector);
586:
587: // 状態を保存
588: uint16 oldsr = GetSR();
589:
590: // S を立てて T1,T0 を落とす。割り込みレベルも変更。
591: uint16 newsr = GetSR() & ~(M68K::SR_T | M68K::SR_IMASK);
592: newsr |= M68K::SR_S;
593: newsr |= level << 8;
594: SetSR(newsr);
595:
596: try {
597: // 例外スタックフレーム $0 を生成。
598: // スタックに積む PC は次の命令位置。
599: // M ビットは未実装なのでスローアウェイとか無視
600: GenerateExframe0(vector, reg.pc, oldsr);
601:
602: // ベクタにジャンプ
603: JumpVector(vector);
604: } catch (int vector2) {
605: assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector=%d", vector);
606:
607: // バスエラー処理へ
608: ExceptionBuserr(vector2);
609: }
610:
611: return used_cycle - cycle_start;
612: }
613:
614: // RTE 命令。
615: // 例外処理の近くに置いておくほうが便利なので。
616: void
617: MPU680x0Device::ops_rte()
618: {
619: uint32 pc;
620: uint16 sr;
621: uint16 frame;
622:
623: try {
624: sr = pop_16();
625: pc = pop_32();
626: frame = pop_16();
627: switch (frame >> 12) {
628: case 0:
629: CYCLE2(18, 20);
630: SetSR(sr);
631: Jump(pc);
632: break;
633:
634: case 2:
635: CYCLE2(18, 20);
636: // +08.L INSTRUCTION ADDRESS を読み捨てる
637: reg.A[7] += 4;
638: SetSR(sr);
639: Jump(pc);
640: break;
641:
642: case 0x0b:
643: {
644: uint32 stage_b;
645: uint16 ssw;
646:
647: CYCLE(76);
648: reg.A[7] += 2; // $08.W
649: ssw = pop_16(); // $0a.W SSW
650: reg.A[7] += 4 * 6; // $0c.L*6
651: stage_b = pop_32(); // $24.L Stage B
652: reg.A[7] += 2 * 9; // $28.W*9
653: // $3a..$58 ここが save_pd の取り出し
654: flag_pd = pop_16();
655: for (int i = 0; i < 8; i++) {
656: save_pd[i] = pop_32();
657: }
658: // A7 レジスタをリストアするかもしれない前に Super/User を
659: // 復帰しておかないといけない
660: SetSR(sr);
661:
662: // DFビットセットなら命令を再実行するため、-(An) で変化
663: // したレジスタを巻き戻す。
664: // DFビットクリアなら例外要因の命令はハンドラで処理された
665: // とみなして、次の命令に進む。
666: if ((ssw & M68K::SSW_DF)) {
667: restore_reg_pd();
668: } else {
669: pc = stage_b - 2;
670: }
671: Jump(pc);
672: break;
673: }
674:
675: default:
676: PANIC("RTE frame=$%x not supported", frame >> 12);
677: break;
678: }
679: } catch (int vector2) {
680: assertmsg(vector2 == M68K::EXCEP_BUSERR, "vector2=%d", vector2);
681:
682: // RTE 処理中のバスエラーはダブルバスフォールト。
683: DoubleBusFault("bus/address error handling");
684: }
685: }
686:
687: // STOP 命令。
688: void
689: MPU680x0Device::ops_stop()
690: {
691: uint32 data = fetch_16();
692: SetSR(data);
693: ChangeState(CPU_STATE_STOP);
694:
695: MakeNextFull();
1.1 root 696: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.