|
|
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: // 先にブランチ履歴に記録
! 148: brhist.AddEntry(ppc | (IsSuper() ? 1 : 0), addr, ir << 16);
! 149:
! 150: if (__predict_false((addr & 1) != 0)) {
! 151: Exception(M68K::EXCEP_ADDRERR);
! 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();
! 276: void Exception(int);
! 277:
! 278: // 二重バスフォールト
! 279: void DoubleBusFault(const char *where);
! 280:
! 281: public:
! 282: // レジスタ
! 283: m68kreg reg {};
! 284:
! 285: // MMU work
! 286: m68030TT mmu_tt[2] /*{}*/;
! 287: uint8 mmu_tt_quick[256] {};
! 288: m68030TC mmu_tc /*{}*/;
! 289: m68030ATC atc {this};
! 290: bool mmu_enable {}; // MMU が有効なら true
! 291:
! 292: // バス
! 293: m68kbus bus {};
! 294:
! 295: private:
! 296: uint16 ir {};
! 297: uint16 ir2 {};
! 298: // 現在実行中の命令の先頭アドレス
! 299: uint32 ppc {};
! 300:
! 301: // レジスタ(状態保存用)
! 302: uint32 save_pd[8] {}; // -(An) を保存
! 303: uint32 save_pi[8] {}; // (An)+ を保存
! 304: uint8 flag_pd {}; // -(An) のどのレジスタを保存したか
! 305: uint8 flag_pi {}; // (An)+ のどのレジスタを保存したか
! 306:
! 307: // FPU
! 308: int has_fpu {}; // 0:FPUなし、1:68881、2:68882(?)
! 309: bool fpu_dirty {};
! 310: struct fpemu fe {};
! 311:
! 312: // CPU の実行状態
! 313: uint32 cpu_state {};
1.1.1.7 root 314:
1.1.1.10 root 315: // 割り込みペンディング
316: bool intr_pending {};
317:
1.1.1.11! root 318: // 現在の外部割り込みレベル
! 319: int intr_level {};
! 320:
! 321: // 電源オンからの累積消費サイクル
! 322: uint64 used_cycle {};
! 323:
! 324: int32 cycle_nocache {}; // ノーキャッシュケースの時の追加分
! 325:
! 326: // A-Line, F-Line 命令エミュレーションのコールバックとユーザ引数。
! 327: // ユーザ引数には関与しないので呼び出し側が自由に指定してよい。
! 328: // コールバック側で処理完了したら true を返す。
! 329: // デフォルトの処理(すなわちm68k例外)にする場合は false を返す。
! 330: bool (*aline_callback)(MPU680x0Device *, void *) {};
! 331: void *aline_arg {};
! 332: bool (*fline_callback)(MPU680x0Device *, void *) {};
! 333: void *fline_arg {};
! 334:
! 335: // ブランチ履歴 (例外履歴を含む)
! 336: BranchHistory_m680x0 brhist { OBJ_MPU_BRHIST };
! 337: // 例外履歴のみ
! 338: BranchHistory_m680x0 exhist { OBJ_MPU_EXHIST };
! 339:
! 340: // 割り込みイベント
! 341: Event intr_event { this };
! 342:
1.1.1.10 root 343: // トレースでコールバックを差し替えることができるように
344: // イベントコールバックを変数に入れてある
345: EventCallback_t exec_short {};
346: EventCallback_t exec_full {};
1.1.1.4 root 347:
1.1.1.11! root 348: // レジスタモニター
! 349: DECLARE_MONITOR_CALLBACK(MonitorUpdateReg);
! 350: Monitor reg_monitor { this };
! 351:
! 352: // ATC モニター
! 353: DECLARE_MONITOR_CALLBACK(MonitorUpdateATC);
! 354: Monitor atc_monitor { this };
! 355:
! 356: InterruptDevice *interruptdev {};
! 357: VectorTable *vectortable {};
1.1 root 358: };
359:
1.1.1.11! root 360: static inline MPU680x0Device *GetMPU680x0Device() {
! 361: return Object::GetObject<MPU680x0Device>(OBJ_MPU);
! 362: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.