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