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