|
|
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.11 root 7: //
8: // MPU (M88xx0)
9: //
1.1 root 10:
11: #pragma once
12:
13: #include "mpu.h"
1.1.1.12! root 14: #include "branchhistory.h"
! 15: #include "event.h"
1.1 root 16: #include "m88100.h"
1.1.1.12! root 17: #include "m88200.h"
! 18: #include <array>
1.1 root 19:
1.1.1.12! root 20: class MPU88xx0Device : public MPUDevice, private M88100
1.1 root 21: {
1.1.1.2 root 22: using inherited = MPUDevice;
1.1.1.12! root 23:
! 24: static const uint32 CPU_STATE_NORMAL = 0;
! 25: static const uint32 CPU_STATE_STOP = 1; // 疑似 STOP 状態
! 26:
! 27: enum ExceptionKind {
! 28: NORMAL,
! 29: DATA,
! 30: ERROR,
! 31: INTR,
! 32: TRAP,
! 33: };
! 34:
1.1 root 35: public:
1.1.1.8 root 36: MPU88xx0Device();
1.1.1.5 root 37: virtual ~MPU88xx0Device() override;
38:
39: bool Init() override;
1.1.1.11 root 40: void ResetHard(bool poweron) override;
1.1 root 41:
1.1.1.12! root 42: // MPU からのアクセスをエミュレートする。
! 43: // アドレスは論理アドレス。
! 44: // 空間は現在のデータ空間。
! 45: // ミスアラインドアクセスも可能。
! 46: // アクセスエラーは -1 を返す。
! 47: uint64 Read8(uint32 addr) override;
! 48: uint64 Read16(uint32 addr) override;
! 49: uint64 Read32(uint32 addr) override;
! 50: uint64 Write8(uint32 addr, uint32 data) override;
! 51: uint64 Write16(uint32 addr, uint32 data) override;
! 52: uint64 Write32(uint32 addr, uint32 data) override;
! 53:
1.1 root 54: // 現在実行中の命令の PC を取得
1.1.1.12! root 55: uint32 GetPPC() const override { return reg.xip; }
1.1 root 56:
1.1.1.11 root 57: // 現在の VBR を取得
1.1.1.12! root 58: uint32 GetVBR() const override { return reg.vbr; }
! 59:
! 60: // スーパーバイザ/ユーザモードなら true
! 61: bool IsSuper() const { return (reg.psr & PSR_SUPER) != 0; }
! 62: bool IsUser() const { return (reg.psr & PSR_SUPER) == 0; }
! 63:
! 64: // 割り込みが許可なら true
! 65: bool IsIntrEnable() const { return (reg.psr & PSR_IND) == 0; }
! 66:
! 67: // CPU の実行状態 (uint32) を返す。
! 68: uint32 GetState() const { return cpu_state; }
1.1.1.11 root 69:
1.1 root 70: // 現在アクセス中の論理アドレス、物理アドレスを取得。
1.1.1.7 root 71: uint32 GetLaddr() const override;
72: uint32 GetPaddr() const override;
1.1 root 73:
1.1.1.4 root 74: // アクセスウェイトを加算
1.1.1.12! root 75: void AddCycle(int32 cycle) override {
! 76: // XXX 本来は今アクセスしてきている(= バスマスターの) CMMU に
! 77: // 対して加算するべき?かもだが、まだその辺の概念がない。
! 78: used_cycle += cycle;
! 79: }
1.1.1.4 root 80:
1.1 root 81: // 割り込み発生を MPU に通知
1.1.1.5 root 82: void Interrupt(int level) override;
1.1 root 83:
1.1.1.10 root 84: // DOS call エミュレーションのコールバックを指定する
1.1.1.12! root 85: void SetFLineCallback(bool (*callback)(MPU88xx0Device *, void *),
! 86: void *arg);
1.1.1.10 root 87:
1.1.1.12! root 88: // op が負数ならバスエラーが起きた
! 89: static bool OpIsBusErr(uint64 op) {
! 90: return (int64)op < 0;
! 91: }
! 92:
! 93: m88100reg reg {};
! 94:
! 95: // 直近のデータアクセスアドレス。
! 96: // XXX メモリブレークポイント用だがもう少しなんとかしたい
! 97: uint64 lastaddr {};
1.1.1.11 root 98:
1.1 root 99: private:
1.1.1.11 root 100: // リセット例外コールバック
101: void ResetCallback(Event& ev);
102:
103: // 命令実行系コールバック
104: void ExecNormal(Event& ev);
105: void ExecTrace(Event& ev);
106:
107: // トレース設定。デバッガから呼び出される。
108: void SetTrace(bool trace_on) override;
109:
1.1.1.12! root 110: uint64 fetch() {
! 111: reg.nip = reg.fip;
! 112: reg.opF = cmmu[0]->load_32(reg.fip);
! 113: reg.fip += 4;
! 114: return reg.opF;
! 115: }
! 116:
! 117: void Prefetch();
! 118:
! 119: // PSR を newpsr に変更する。
! 120: // CY ビットは特別にこの関数を経由しないで変更してよいことにする。
! 121: void SetPSR(uint32 newpsr) {
! 122: reg.psr = newpsr;
! 123: SetPSR();
! 124: }
! 125: // 更新された psr に基づいて、PSR 変更によって必要な処理をする。
! 126: // CY ビットを変更した場合は呼ばなくてよいことにする。
! 127: void SetPSR() {
! 128: // CMMU に S/U 信号を出す
! 129: cmmu[0]->SetSuper(IsSuper());
! 130: cmmu[1]->SetSuper(IsSuper());
! 131: }
! 132:
! 133: // キャリーフラグが立っていれば 1 を返す
! 134: uint32 GetCY() const { return (reg.psr >> 28) & 1; }
! 135:
! 136: // キャリーフラグをセットする。
! 137: // cy のうち最下位ビットのみ参照する (呼び出し側はマスクせず渡してよい)
! 138: void SetCY(uint cy) {
! 139: reg.psr &= ~PSR_C;
! 140: reg.psr |= ((cy & 1) << 28);
! 141: }
! 142:
! 143: // SFU1(FPU)が有効なら true
! 144: bool IsFPUEnable() const { return (reg.psr & PSR_SFD1) == 0; }
! 145:
! 146: // MXM (Misaligned Access Enable) なら true
! 147: bool IsMXM() const { return (reg.psr & PSR_MXM) != 0; }
! 148:
! 149: // FPxS1, FPxS2 レジスタを設定
! 150: static void SetFPxS(uint32& h, uint32& l, double src, uint32 t);
! 151: void SetFPS1(double src, uint32 t1);
! 152: void SetFPS2(double src, uint32 t2);
! 153: void SetFPS1(uint32 src);
! 154: void SetFPS2(uint32 src);
! 155: // FP Result を FPIT, FPRH, FPRL レジスタに設定
! 156: void SetFPRx(double src);
! 157:
! 158: void Exception(int vec);
! 159: void ExceptionCore(int vec, ExceptionKind cause);
! 160: uint32 Calcdmt(uint32 flag);
! 161: void ReadDataException32(uint32 addr, uint32 flag);
! 162: void ReadDataException64(uint32 addr, uint32 flag);
! 163: void WriteDataException32(uint32 addr, uint32 flag);
! 164: void WriteDataException64(uint32 addr, uint32 flag);
! 165: void XmemDataException(uint32 addr, uint32 flag);
! 166: void FPPreciseException(uint32 cause, double s2);
! 167: void FPPreciseException(uint32 cause, double s1, double s2);
! 168: void FPPreciseException(uint32 cause);
! 169: void FPImpreciseException(uint32 cause);
! 170:
! 171: // ブランチ処理用
! 172: void DoBranch(uint32 toaddr, bool next_exec);
! 173: uint32 nop_counter {}; // STOP 検出用の nop 命令カウンタ
! 174:
! 175: // ロードストア命令用の下処理
! 176: bool ldst_usr(uint32& usr);
! 177: uint32 ldst_scale(uint32 size);
! 178: bool ldst_align(uint32 size, uint32& addr);
! 179: // 浮動小数点数命令用の処理
! 180: void ops_int(int mode);
! 181:
! 182: #define OP_PROTO(name) void __CONCAT(op_,name)()
! 183: #include "m88100ops.h"
! 184: OP_PROTO(illegal);
! 185: #undef OP_PROTO
! 186:
! 187: void fpu_unimpl();
! 188:
! 189: // float,double と整数値の相互変換
! 190: static float u2f(uint32 u) {
! 191: float v;
! 192: memcpy(&v, &u, sizeof(v));
! 193: return v;
! 194: }
! 195: static double u2d(uint64 u) {
! 196: double v;
! 197: memcpy(&v, &u, sizeof(v));
! 198: return v;
! 199: }
! 200: static uint32 f2u(float v) {
! 201: uint32 u;
! 202: memcpy(&u, &v, sizeof(u));
! 203: return u;
! 204: }
! 205: static uint64 d2u(double v) {
! 206: uint64 u;
! 207: memcpy(&u, &v, sizeof(u));
! 208: return u;
! 209: }
! 210:
! 211: // [0] 命令バス
! 212: // [1] データバス
! 213: std::array<std::unique_ptr<m88200>, 2> cmmu {};
! 214:
! 215: // ブランチ履歴 (例外履歴を含む)
! 216: BranchHistory_m88xx0 brhist { OBJ_MPU_BRHIST };
! 217: // 例外履歴のみ
! 218: BranchHistory_m88xx0 exhist { OBJ_MPU_EXHIST };
! 219:
! 220: // 今のところサイクルを正確に実装するのは無理なので
! 221: // 適当に全部積み上げてある。
! 222:
! 223: // 電源オンからの累積消費サイクル
! 224: uint64 used_cycle {};
! 225:
! 226: // ペンディング中の割り込みレベル
! 227: int intr_pending {};
! 228:
! 229: // CPU の状態
! 230: void ChangeState(uint32 new_state);
! 231: uint32 cpu_state {};
! 232:
! 233: // 疑似 STOP 状態に入る機能を有効にする場合 true
! 234: bool pseudo_stop_enable {};
! 235:
! 236: // DOS call エミュレーション
! 237: bool (*fline_callback)(MPU88xx0Device *, void *) = NULL;
! 238: void *fline_arg {};
! 239:
1.1.1.9 root 240: // レジスタモニター
241: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
242: Monitor monitor { this };
1.1.1.2 root 243:
1.1.1.11 root 244: // イベントコールバック
245: EventCallback_t exec_normal {};
1.1.1.2 root 246: };
247:
1.1.1.12! root 248: static inline MPU88xx0Device *GetMPU88xx0Device() {
! 249: return Object::GetObject<MPU88xx0Device>(OBJ_MPU);
! 250: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.