|
|
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:
20: class InterruptDevice;
1.1.1.13 root 21: class m68030Cache;
1.1.1.14! root 22: struct m68030CacheLine;
1.1 root 23:
1.1.1.14! root 24: class MPU680x0Device : public MainMPUDevice
1.1 root 25: {
1.1.1.14! root 26: using inherited = MainMPUDevice;
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.14! root 72: // バーストアクセスをサポートするか
! 73: void EnableBurstAccess(bool enable) { has_burst_access = enable; }
! 74:
1.1.1.13 root 75: void SetCI() override {
76: bus.ci = true;
77: }
1.1.1.9 root 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++ の例外をスローする。
1.1.1.14! root 85: uint32 fetch_2();
! 86: uint32 fetch_4();
! 87: uint32 read_n(uint32 laddr, uint size) {
! 88: busaddr addr =
! 89: busaddr(laddr) | fc_data | BusAddr::R | busaddr::Size(size);
! 90: return read_data(addr);
! 91: }
! 92: void write_n(uint32 laddr, uint size, uint32 data) {
! 93: busaddr addr =
! 94: busaddr(laddr) | fc_data | BusAddr::W | busaddr::Size(size);
! 95: write_data(addr, data);
! 96: }
! 97: uint32 read_1(uint32 laddr) { return read_n(laddr, 1); }
! 98: uint32 read_2(uint32 laddr) { return read_n(laddr, 2); }
! 99: uint32 read_4(uint32 laddr) { return read_n(laddr, 4); }
! 100: void write_1(uint32 laddr, uint32 data) { write_n(laddr, 1, data); }
! 101: void write_2(uint32 laddr, uint32 data) { write_n(laddr, 2, data); }
! 102: void write_4(uint32 laddr, uint32 data) { write_n(laddr, 4, data); }
1.1.1.11 root 103:
104: // MMU アクセス
1.1.1.13 root 105: busaddr TranslatePeek(busaddr laddr);
1.1.1.14! root 106: // 統計
! 107: void CalcStat();
1.1.1.11 root 108:
109: // レジスタ
110: uint16 GetIR() const { return ir; }
111: uint16 GetIR2() const { return ir2; }
112: // SR を変更する (Human68k から使う)
113: void SetSR(uint16);
114: uint16 GetSR() const { return reg.GetSR(); }
115:
116: uint64 GetSRP() const { return reg.srp.q; }
117: uint32 GetSRPh() const { return reg.srp.h; }
118: uint32 GetSRPl() const { return reg.srp.l; }
119: uint64 GetCRP() const { return reg.crp.q; }
120: uint32 GetCRPh() const { return reg.crp.h; }
121: uint32 GetCRPl() const { return reg.crp.l; }
122: uint64 GetTT(int idx) const { return reg.tt[idx]; }
123: uint32 GetTC() const { return reg.tc; }
124: uint16 GetMMUSR() const { return reg.mmusr; }
125:
1.1 root 126: private:
1.1.1.10 root 127: // リセット例外コールバック
128: void ResetCallback(Event& ev);
129:
130: // 命令実行系コールバック
131: void ExecShort(Event& ev);
132: void ExecFull(Event& ev);
133: void ExecTrace(Event& ev);
1.1.1.5 root 134:
1.1.1.10 root 135: // トレース設定。デバッガから呼び出される。
136: void SetTrace(bool trace_on) override;
1.1.1.9 root 137:
1.1.1.10 root 138: // 割り込みイベントコールバック
139: void InterruptCallback(Event& ev);
140:
1.1.1.11 root 141: // 動作モード変更
142: void ChangeState(uint32 new_state);
1.1.1.8 root 143:
1.1.1.11 root 144: // 次の実行サイクルを Full にする。
145: void MakeNextFull();
1.1.1.8 root 146:
1.1.1.11 root 147: inline void CYCLE(int cc) {
148: used_cycle += cc;
149: }
150: inline void CYCLE2(int cc, int ncc) {
151: used_cycle += cc;
152: cycle_nocache += ncc - cc;
153: }
154:
155: // PC を addr に変更する。
156: // ベクタへのジャンプはここではなく JumpVector()。
157: inline void Jump(uint32 addr) {
158: // 先にブランチ履歴に記録
1.1.1.12 root 159: brhist.AddEntry(ppc | (IsSuper() ? 1 : 0), addr, ir);
1.1.1.11 root 160:
161: if (__predict_false((addr & 1) != 0)) {
1.1.1.12 root 162: ExceptionBuserr(M68K::EXCEP_ADDRERR);
1.1.1.11 root 163: return;
164: }
165: reg.pc = addr;
166: }
167:
168: // -(An) 実行前にレジスタを保存する。
169: // バスエラーからの復帰用。
170: inline void save_reg_pd(int n) {
171: // 該当ビットのフラグを立てる
172: flag_pd |= (1 << n);
173:
174: // 保存
175: save_pd[n] = reg.A[n];
176: }
177:
178: // (An)+ 実行前にレジスタを保存する。
179: // バスエラーからの復帰用。
180: inline void save_reg_pi(int n) {
181: // 該当ビットのフラグを立てる
182: flag_pi |= (1 << n);
183:
184: // 保存
185: save_pi[n] = reg.A[n];
186: }
187:
1.1.1.14! root 188: // -(An) 実行前にレジスタを(まだ保存してなければ)保存する。
! 189: // 1命令で同じレジスタを2回 -(An) する可能性がある命令用。
! 190: inline void save_reg_pd_if(int n) {
! 191: if ((flag_pd & (1 << n)) == 0) {
! 192: save_reg_pd(n);
! 193: }
! 194: }
! 195: // (An)+ 実行前にレジスタを(まだ保存してなければ)保存する。
! 196: // 1命令で同じレジスタを2回 (An)+ する可能性がある命令用。
! 197: inline void save_reg_pi_if(int n) {
! 198: if ((flag_pi & (1 << n)) == 0) {
! 199: save_reg_pi(n);
! 200: }
! 201: }
! 202:
1.1.1.11 root 203: void restore_reg_pi();
204: void restore_reg_pd();
1.1.1.14! root 205: void JumpVector(uint vector, bool from_buserr);
1.1.1.11 root 206:
207: protected:
208: #include "m68030ea.h"
209:
210: private:
211: // 基本アクセスルーチンを使った便利サブルーチン
1.1.1.14! root 212: inline void push_2(uint32 data) {
1.1.1.11 root 213: reg.A[7] -= 2;
1.1.1.14! root 214: write_2(reg.A[7], data);
1.1.1.11 root 215: }
1.1.1.14! root 216: inline void push_4(uint32 data) {
1.1.1.11 root 217: reg.A[7] -= 4;
1.1.1.14! root 218: write_4(reg.A[7], data);
1.1.1.11 root 219: }
1.1.1.14! root 220: inline uint32 pop_2() {
! 221: uint32 data = read_2(reg.A[7]);
1.1.1.11 root 222: reg.A[7] += 2;
223: return data;
224: }
1.1.1.14! root 225: inline uint32 pop_4() {
! 226: uint32 data = read_4(reg.A[7]);
1.1.1.11 root 227: reg.A[7] += 4;
228: return data;
229: }
230:
1.1.1.13 root 231: // バスアクセス
1.1.1.14! root 232: uint32 read_data(busaddr addr);
! 233: busdata read_nocache(busaddr addr);
! 234: busdata read_cache(m68030Cache *cache, busaddr addr);
! 235: busdata read_line(m68030CacheLine *, uint32 tag, uint32 opermask);
! 236: busdata read_single(busdata bd, uint32 readmask, uint32 opermask);
! 237:
! 238: void write_data(busaddr addr, uint32 data);
! 239: busdata write_bus(busaddr addr, uint32 data);
! 240:
! 241: busdata read_phys();
! 242: busdata write_phys(uint32 data);
! 243: bool read_phys_burst(uint32 *dst);
1.1.1.13 root 244:
1.1.1.11 root 245: #define OP_PROTO(name) void __CONCAT(op_,name)()
246: #include "m68030ops.h"
247: #undef OP_PROTO
248:
1.1.1.14! root 249: void ops_divu_32_32(uint r, uint q);
! 250: void ops_divu_64_32(uint r, uint q);
! 251: void ops_divs_32_32(uint r, uint q);
! 252: void ops_divs_64_32(uint r, uint q);
1.1.1.11 root 253: void ops_movec_rc_rn();
254: void ops_movec_rn_rc();
255: void ops_movep();
256: // もともとソース内のテンプレートだった
257: void ops_movem_list_ea(int bytesize);
258: void ops_movem_ea_list(int bytesize);
259: void ops_trapcc(uint cond);
260: inline void ops_bra();
261:
262: // 68030core.cpp
263: void ops_rte();
264: void ops_stop();
265: // vm/mpu680x0.cpp
266: void ops_reset();
267:
268: #include "m68030fpu.h"
269: void fpu_op_start();
270:
1.1.1.13 root 271: // キャッシュ
272: void SetCACR(uint32);
273:
1.1.1.11 root 274: // MMU
275: bool SetSRP(uint32, uint32);
276: bool SetCRP(uint32, uint32);
277: void SetTT(int idx, uint32);
278: bool SetTC(uint32);
279: void SetMMUSR(uint16);
280:
281: bool TranslateRead();
282: bool TranslateWrite();
283:
1.1.1.13 root 284: bool CheckTT();
1.1.1.11 root 285: uint32 get_fc();
286: void mmu_op_illg2();
287: void mmu_op_pflush();
288: void mmu_op_pflush_ea();
289: void mmu_op_pload();
290: void mmu_op_ptest();
291: // MMU 有効状態を更新。(TC と TT の変更で呼ばれる)
292: void mmu_enable_changed();
293:
294: // 例外
1.1.1.14! root 295: void GenerateExframe0(uint vector, uint32 pc, uint16 sr);
! 296: void GenerateExframe2(uint vector, uint16 sr);
! 297: void GenerateExframeB(uint vector, uint16 sr);
1.1.1.11 root 298: int ExceptionReset();
1.1.1.14! root 299: void ExceptionBuserr(uint vector);
1.1.1.13 root 300: uint64 ExceptionInterrupt();
1.1.1.12 root 301: void ExceptionTrap15();
1.1.1.14! root 302: void Exception(uint vector);
! 303: void ExceptionGeneric(uint vector, uint32 inst);
1.1.1.11 root 304:
305: // 二重バスフォールト
306: void DoubleBusFault(const char *where);
307:
308: public:
309: // レジスタ
310: m68kreg reg {};
311:
312: // MMU work
313: m68030TT mmu_tt[2] /*{}*/;
314: m68030TC mmu_tc /*{}*/;
315: m68030ATC atc {this};
316: bool mmu_enable {}; // MMU が有効なら true
317:
318: // バス
319: m68kbus bus {};
1.1.1.13 root 320: // 現在の特権状態でのプログラム空間とデータ空間アクセス用。
321: busaddr fc_inst {}; // こっちは R 含む
322: busaddr fc_data {}; // こっちは R/W 含まない
1.1.1.11 root 323:
324: private:
325: uint16 ir {};
326: uint16 ir2 {};
327: // 現在実行中の命令の先頭アドレス
328: uint32 ppc {};
329:
330: // レジスタ(状態保存用)
331: uint32 save_pd[8] {}; // -(An) を保存
332: uint32 save_pi[8] {}; // (An)+ を保存
333: uint8 flag_pd {}; // -(An) のどのレジスタを保存したか
334: uint8 flag_pi {}; // (An)+ のどのレジスタを保存したか
335:
1.1.1.13 root 336: // キャッシュ
337: std::unique_ptr<m68030Cache> icache /*{}*/;
1.1.1.14! root 338: std::unique_ptr<m68030Cache> dcache /*{}*/;
1.1.1.13 root 339:
1.1.1.11 root 340: // FPU
341: int has_fpu {}; // 0:FPUなし、1:68881、2:68882(?)
342: bool fpu_dirty {};
343: struct fpemu fe {};
344:
345: // CPU の実行状態
346: uint32 cpu_state {};
1.1.1.7 root 347:
1.1.1.10 root 348: // 割り込みペンディング
349: bool intr_pending {};
350:
1.1.1.11 root 351: // 現在の外部割り込みレベル
352: int intr_level {};
353:
354: // 電源オンからの累積消費サイクル
355: uint64 used_cycle {};
356:
1.1.1.13 root 357: // 今回のバスウェイト [nsec]
358: uint64 buswait {};
359:
1.1.1.14! root 360: // 外部バスがバースト転送に対応していれば true
! 361: bool has_burst_access {};
! 362:
1.1.1.11 root 363: int32 cycle_nocache {}; // ノーキャッシュケースの時の追加分
364:
365: // A-Line, F-Line 命令エミュレーションのコールバックとユーザ引数。
366: // ユーザ引数には関与しないので呼び出し側が自由に指定してよい。
367: // コールバック側で処理完了したら true を返す。
368: // デフォルトの処理(すなわちm68k例外)にする場合は false を返す。
369: bool (*aline_callback)(MPU680x0Device *, void *) {};
370: void *aline_arg {};
371: bool (*fline_callback)(MPU680x0Device *, void *) {};
372: void *fline_arg {};
373:
374: // ブランチ履歴 (例外履歴を含む)
375: BranchHistory_m680x0 brhist { OBJ_MPU_BRHIST };
376: // 例外履歴のみ
377: BranchHistory_m680x0 exhist { OBJ_MPU_EXHIST };
378:
379: // 割り込みイベント
380: Event intr_event { this };
381:
1.1.1.10 root 382: // トレースでコールバックを差し替えることができるように
383: // イベントコールバックを変数に入れてある
384: EventCallback_t exec_short {};
385: EventCallback_t exec_full {};
1.1.1.4 root 386:
1.1.1.11 root 387: // レジスタモニター
388: DECLARE_MONITOR_CALLBACK(MonitorUpdateReg);
1.1.1.14! root 389: void MonitorUpdateFPU(TextScreen&, int y, m68kreg&);
1.1.1.11 root 390: Monitor reg_monitor { this };
391:
392: // ATC モニター
393: DECLARE_MONITOR_CALLBACK(MonitorUpdateATC);
394: Monitor atc_monitor { this };
395:
1.1.1.13 root 396: // キャッシュモニター
397: DECLARE_MONITOR_CALLBACK(MonitorUpdateCache);
1.1.1.14! root 398: int MonitorUpdateCache1(TextScreen&, int y, m68030Cache *,
! 399: char (*)(const m68030CacheLine&));
1.1.1.13 root 400: Monitor cache_monitor { this };
401:
1.1.1.11 root 402: InterruptDevice *interruptdev {};
403: VectorTable *vectortable {};
1.1 root 404: };
405:
1.1.1.13 root 406: // これを呼びたい人は mpu を持ってるはず。
407: static inline MPU680x0Device *GetMPU680x0Device(Device *mpu_) {
408: return dynamic_cast<MPU680x0Device*>(mpu_);
1.1.1.11 root 409: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.