|
|
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.10 root 7: //
8: // MPU (MC68030)
9: //
1.1 root 10:
11: #pragma once
12:
13: #include "mpu.h"
1.1.1.11 root 14: #include "branchhistory.h"
15: #include "event.h"
1.1 root 16: #include "m68030.h"
1.1.1.11 root 17: #include "m68030mmu.h"
18: #include "mainbus.h"
19:
20: class InterruptDevice;
1.1 root 21:
22: class MPU680x0Device : public MPUDevice
23: {
1.1.1.2 root 24: using inherited = MPUDevice;
1.1.1.11 root 25: friend class m68030MMU;
26:
27: // CPU の実行状態
28: static const uint32 CPU_STATE_NORMAL = 0;
29: static const uint32 CPU_STATE_STOP = 1;
30: static const uint32 CPU_STATE_HALT = 2;
31:
1.1 root 32: public:
1.1.1.7 root 33: MPU680x0Device();
1.1.1.5 root 34: virtual ~MPU680x0Device() override;
1.1 root 35:
1.1.1.2 root 36: bool Init() override;
1.1.1.10 root 37: void ResetHard(bool poweron) override;
1.1 root 38:
39: // 現在の PPC を取得
1.1.1.11 root 40: uint32 GetPPC() const override { return ppc; }
1.1 root 41:
1.1.1.10 root 42: // 現在の VBR を取得
1.1.1.11 root 43: uint32 GetVBR() const override { return reg.vbr; }
44:
45: bool IsSuper() const { return reg.s; }
46: bool IsMaster() const { return reg.m; }
47:
48: // CPU の実行状態 (uint32) を返す。
49: uint32 GetState() const { return cpu_state; }
1.1.1.10 root 50:
1.1 root 51: // 現在アクセス中の論理アドレス、物理アドレスを取得。
1.1.1.11 root 52: uint32 GetLaddr() const override { return bus.laddr; }
53: uint32 GetPaddr() const override { return bus.paddr; }
1.1 root 54:
1.1.1.4 root 55: // アクセスウェイトを加算
1.1.1.11 root 56: void AddCycle(int32 cycle) override { used_cycle += cycle; }
1.1 root 57:
1.1.1.5 root 58: // 割り込みレベルが変わったことを MPU に通知
59: void Interrupt(int level) override;
1.1 root 60:
61: // A-Line, F-Line 命令エミュレーションのコールバックを指定する。
62: // (Human68k エミュレーションで使用)
1.1.1.11 root 63: void SetALineCallback(bool (*callback)(MPU680x0Device*, void*), void *arg);
64: void SetFLineCallback(bool (*callback)(MPU680x0Device*, void*), void *arg);
1.1 root 65:
66: // FPU を持っているか
1.1.1.11 root 67: bool HaveFPU() const { return has_fpu; }
1.1 root 68:
1.1.1.9 root 69: // MPU からのアクセスをエミュレートする。
1.1.1.11 root 70: // アドレスは論理アドレスで、空間は現在のデータ空間。
71: // バスエラーなら (uint64)-1 を返す。
1.1.1.9 root 72: uint64 Read8(uint32 addr) override;
73: uint64 Read16(uint32 addr) override;
74: uint64 Read32(uint32 addr) override;
75: uint64 Write8(uint32 addr, uint32 data) override;
76: uint64 Write16(uint32 addr, uint32 data) override;
77: uint64 Write32(uint32 addr, uint32 data) override;
78:
1.1.1.11 root 79: // ホールト
1.1.1.10 root 80: void Halt();
81:
1.1.1.11 root 82: // 基本アクセス。内部から使用する。
83: // アドレスは論理アドレスで、空間は現在の命令/データ空間。
84: // バスエラーなら C++ の例外をスローする。
85: uint32 fetch_8();
86: uint32 fetch_16();
87: uint32 fetch_32();
88: uint32 read_8(uint32 addr);
89: uint32 read_16(uint32 addr);
90: uint32 read_32(uint32 addr);
91: void write_8(uint32 addr, uint32 data);
92: void write_16(uint32 addr, uint32 data);
93: void write_32(uint32 addr, uint32 data);
94:
95: // MMU アクセス
96: uint64 TranslatePeek(uint32 laddr, uint fc, bool do_search);
97:
98: // レジスタ
99: uint16 GetIR() const { return ir; }
100: uint16 GetIR2() const { return ir2; }
101: // SR を変更する (Human68k から使う)
102: void SetSR(uint16);
103: uint16 GetSR() const { return reg.GetSR(); }
104:
105: uint64 GetSRP() const { return reg.srp.q; }
106: uint32 GetSRPh() const { return reg.srp.h; }
107: uint32 GetSRPl() const { return reg.srp.l; }
108: uint64 GetCRP() const { return reg.crp.q; }
109: uint32 GetCRPh() const { return reg.crp.h; }
110: uint32 GetCRPl() const { return reg.crp.l; }
111: uint64 GetTT(int idx) const { return reg.tt[idx]; }
112: uint32 GetTC() const { return reg.tc; }
113: uint16 GetMMUSR() const { return reg.mmusr; }
114:
1.1 root 115: private:
1.1.1.10 root 116: // リセット例外コールバック
117: void ResetCallback(Event& ev);
118:
119: // 命令実行系コールバック
120: void ExecShort(Event& ev);
121: void ExecFull(Event& ev);
122: void ExecTrace(Event& ev);
1.1.1.5 root 123:
1.1.1.10 root 124: // トレース設定。デバッガから呼び出される。
125: void SetTrace(bool trace_on) override;
1.1.1.9 root 126:
1.1.1.10 root 127: // 割り込みイベントコールバック
128: void InterruptCallback(Event& ev);
129:
1.1.1.11 root 130: // 動作モード変更
131: void ChangeState(uint32 new_state);
1.1.1.8 root 132:
1.1.1.11 root 133: // 次の実行サイクルを Full にする。
134: void MakeNextFull();
1.1.1.8 root 135:
1.1.1.11 root 136: inline void CYCLE(int cc) {
137: used_cycle += cc;
138: }
139: inline void CYCLE2(int cc, int ncc) {
140: used_cycle += cc;
141: cycle_nocache += ncc - cc;
142: }
143:
144: // PC を addr に変更する。
145: // ベクタへのジャンプはここではなく JumpVector()。
146: inline void Jump(uint32 addr) {
147: // 先にブランチ履歴に記録
1.1.1.12! root 148: brhist.AddEntry(ppc | (IsSuper() ? 1 : 0), addr, ir);
1.1.1.11 root 149:
150: if (__predict_false((addr & 1) != 0)) {
1.1.1.12! root 151: ExceptionBuserr(M68K::EXCEP_ADDRERR);
1.1.1.11 root 152: return;
153: }
154: reg.pc = addr;
155: }
156:
157: // -(An) 実行前にレジスタを保存する。
158: // バスエラーからの復帰用。
159: inline void save_reg_pd(int n) {
160: // 該当ビットのフラグを立てる
161: flag_pd |= (1 << n);
162:
163: // 保存
164: save_pd[n] = reg.A[n];
165: }
166:
167: // (An)+ 実行前にレジスタを保存する。
168: // バスエラーからの復帰用。
169: inline void save_reg_pi(int n) {
170: // 該当ビットのフラグを立てる
171: flag_pi |= (1 << n);
172:
173: // 保存
174: save_pi[n] = reg.A[n];
175: }
176:
177: void restore_reg_pi();
178: void restore_reg_pd();
179: void JumpVector(int vector);
180:
181: protected:
182: #include "m68030ea.h"
183:
184: private:
185: #include "m68030bus.h"
186: inline uint32 fetch_16_bus();
187: inline uint32 fetch_32_bus();
188: inline uint32 read_8_bus();
189: inline uint32 read_16_bus();
190: inline uint32 read_32_bus();
191: inline void write_8_bus();
192: inline void write_16_bus();
193: inline void write_32_bus();
194: // FC 指定
195: uint32 read_8_fc(uint32 addr);
196: uint32 read_16_fc(uint32 addr);
197: uint32 read_32_fc(uint32 addr);
198: void write_8_fc(uint32 addr, uint32 data);
199: void write_16_fc(uint32 addr, uint32 data);
200: void write_32_fc(uint32 addr, uint32 data);
201:
202: // 基本アクセスルーチンを使った便利サブルーチン
203: inline void push_16(uint32 data) {
204: reg.A[7] -= 2;
205: write_16(reg.A[7], data);
206: }
207: inline void push_32(uint32 data) {
208: reg.A[7] -= 4;
209: write_32(reg.A[7], data);
210: }
211: inline uint32 pop_16() {
212: uint32 data = read_16(reg.A[7]);
213: reg.A[7] += 2;
214: return data;
215: }
216: inline uint32 pop_32() {
217: uint32 data = read_32(reg.A[7]);
218: reg.A[7] += 4;
219: return data;
220: }
221:
222: #define OP_PROTO(name) void __CONCAT(op_,name)()
223: #include "m68030ops.h"
224: #undef OP_PROTO
225:
226: void ops_divu_32_32(int r, int q);
227: void ops_divu_64_32(int r, int q);
228: void ops_divs_32_32(int r, int q);
229: void ops_divs_64_32(int r, int q);
230: void ops_movec_rc_rn();
231: void ops_movec_rn_rc();
232: void ops_movep();
233: // もともとソース内のテンプレートだった
234: void ops_movem_list_ea(int bytesize);
235: void ops_movem_ea_list(int bytesize);
236: void ops_trapcc(uint cond);
237: inline void ops_bra();
238:
239: // 68030core.cpp
240: void ops_rte();
241: void ops_stop();
242: // vm/mpu680x0.cpp
243: void ops_reset();
244:
245: #include "m68030fpu.h"
246: void fpu_op_start();
247:
248: // MMU
249: bool SetSRP(uint32, uint32);
250: bool SetCRP(uint32, uint32);
251: void SetTT(int idx, uint32);
252: bool SetTC(uint32);
253: void SetMMUSR(uint16);
254:
255: bool TranslateFetch();
256: bool TranslateRead();
257: bool TranslateWrite();
258:
259: bool CheckTT() const;
260: uint32 get_fc();
261: void mmu_op_illg2();
262: void mmu_op_pflush();
263: void mmu_op_pflush_ea();
264: void mmu_op_pload();
265: void mmu_op_ptest();
266: // MMU 有効状態を更新。(TC と TT の変更で呼ばれる)
267: void mmu_enable_changed();
268:
269: // 例外
270: void GenerateExframe0(int vector, uint32 pc, uint16 sr);
271: void GenerateExframe2(int vector, uint16 sr);
272: void GenerateExframeB(int vector, uint16 sr);
273: int ExceptionReset();
274: void ExceptionBuserr(int);
275: int ExceptionInterrupt();
1.1.1.12! root 276: void ExceptionTrap15();
1.1.1.11 root 277: void Exception(int);
1.1.1.12! root 278: void ExceptionGeneric(int vector, uint32 inst);
1.1.1.11 root 279:
280: // 二重バスフォールト
281: void DoubleBusFault(const char *where);
282:
283: public:
284: // レジスタ
285: m68kreg reg {};
286:
287: // MMU work
288: m68030TT mmu_tt[2] /*{}*/;
289: uint8 mmu_tt_quick[256] {};
290: m68030TC mmu_tc /*{}*/;
291: m68030ATC atc {this};
292: bool mmu_enable {}; // MMU が有効なら true
293:
294: // バス
295: m68kbus bus {};
296:
297: private:
298: uint16 ir {};
299: uint16 ir2 {};
300: // 現在実行中の命令の先頭アドレス
301: uint32 ppc {};
302:
303: // レジスタ(状態保存用)
304: uint32 save_pd[8] {}; // -(An) を保存
305: uint32 save_pi[8] {}; // (An)+ を保存
306: uint8 flag_pd {}; // -(An) のどのレジスタを保存したか
307: uint8 flag_pi {}; // (An)+ のどのレジスタを保存したか
308:
309: // FPU
310: int has_fpu {}; // 0:FPUなし、1:68881、2:68882(?)
311: bool fpu_dirty {};
312: struct fpemu fe {};
313:
314: // CPU の実行状態
315: uint32 cpu_state {};
1.1.1.7 root 316:
1.1.1.10 root 317: // 割り込みペンディング
318: bool intr_pending {};
319:
1.1.1.11 root 320: // 現在の外部割り込みレベル
321: int intr_level {};
322:
323: // 電源オンからの累積消費サイクル
324: uint64 used_cycle {};
325:
326: int32 cycle_nocache {}; // ノーキャッシュケースの時の追加分
327:
328: // A-Line, F-Line 命令エミュレーションのコールバックとユーザ引数。
329: // ユーザ引数には関与しないので呼び出し側が自由に指定してよい。
330: // コールバック側で処理完了したら true を返す。
331: // デフォルトの処理(すなわちm68k例外)にする場合は false を返す。
332: bool (*aline_callback)(MPU680x0Device *, void *) {};
333: void *aline_arg {};
334: bool (*fline_callback)(MPU680x0Device *, void *) {};
335: void *fline_arg {};
336:
337: // ブランチ履歴 (例外履歴を含む)
338: BranchHistory_m680x0 brhist { OBJ_MPU_BRHIST };
339: // 例外履歴のみ
340: BranchHistory_m680x0 exhist { OBJ_MPU_EXHIST };
341:
342: // 割り込みイベント
343: Event intr_event { this };
344:
1.1.1.10 root 345: // トレースでコールバックを差し替えることができるように
346: // イベントコールバックを変数に入れてある
347: EventCallback_t exec_short {};
348: EventCallback_t exec_full {};
1.1.1.4 root 349:
1.1.1.11 root 350: // レジスタモニター
351: DECLARE_MONITOR_CALLBACK(MonitorUpdateReg);
352: Monitor reg_monitor { this };
353:
354: // ATC モニター
355: DECLARE_MONITOR_CALLBACK(MonitorUpdateATC);
356: Monitor atc_monitor { this };
357:
358: InterruptDevice *interruptdev {};
359: VectorTable *vectortable {};
1.1 root 360: };
361:
1.1.1.11 root 362: static inline MPU680x0Device *GetMPU680x0Device() {
363: return Object::GetObject<MPU680x0Device>(OBJ_MPU);
364: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.