|
|
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.14 root 20: class MPU88xx0Device : public MainMPUDevice, private M88100
1.1 root 21: {
1.1.1.14 root 22: using inherited = MainMPUDevice;
1.1.1.13 root 23: friend class Luna88kPROMEmuDevice;
1.1.1.12 root 24:
25: static const uint32 CPU_STATE_NORMAL = 0;
26: static const uint32 CPU_STATE_STOP = 1; // 疑似 STOP 状態
27:
28: enum ExceptionKind {
29: NORMAL,
30: DATA,
31: ERROR,
32: INTR,
33: TRAP,
34: };
35:
1.1 root 36: public:
1.1.1.8 root 37: MPU88xx0Device();
1.1.1.13 root 38: ~MPU88xx0Device() override;
1.1.1.5 root 39:
40: bool Init() override;
1.1.1.11 root 41: void ResetHard(bool poweron) override;
1.1 root 42:
1.1.1.13 root 43: // キャッシュ禁止通知 (LUNA-88K では使っていない?)
44: void SetCI() override { }
1.1.1.12 root 45:
1.1 root 46: // 現在実行中の命令の PC を取得
1.1.1.12 root 47: uint32 GetPPC() const override { return reg.xip; }
1.1 root 48:
1.1.1.11 root 49: // 現在の VBR を取得
1.1.1.12 root 50: uint32 GetVBR() const override { return reg.vbr; }
51:
1.1.1.13 root 52: // MPU 名を取得
53: const char *GetMPUName() const override { return "MC88100"; }
54:
1.1.1.12 root 55: // スーパーバイザ/ユーザモードなら true
56: bool IsSuper() const { return (reg.psr & PSR_SUPER) != 0; }
57: bool IsUser() const { return (reg.psr & PSR_SUPER) == 0; }
58:
59: // 割り込みが許可なら true
60: bool IsIntrEnable() const { return (reg.psr & PSR_IND) == 0; }
61:
62: // CPU の実行状態 (uint32) を返す。
63: uint32 GetState() const { return cpu_state; }
1.1.1.11 root 64:
1.1 root 65: // 現在アクセス中の論理アドレス、物理アドレスを取得。
1.1.1.7 root 66: uint32 GetLaddr() const override;
67: uint32 GetPaddr() const override;
1.1 root 68:
1.1.1.13 root 69: // アクセスウェイト [clock] を加算。m88200 が呼ぶ。
70: void AddCycle(int32 cycle) {
1.1.1.12 root 71: // XXX 本来は今アクセスしてきている(= バスマスターの) CMMU に
72: // 対して加算するべき?かもだが、まだその辺の概念がない。
73: used_cycle += cycle;
74: }
1.1.1.4 root 75:
1.1.1.13 root 76: // アクセスウェイト [nsec] を加算。m88200 が呼ぶ。
77: void AddWait(uint32 nsec) {
78: buswait += nsec;
79: }
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;
1.1.1.14 root 112: reg.opF = cmmu[0]->load_4(reg.fip);
1.1.1.12 root 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 レジスタを設定
1.1.1.14 root 150: static void SetFPxS(uint32 *h, uint32 *l, double src, uint32 t);
1.1.1.12 root 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: uint32 ldst_scale(uint32 size);
1.1.1.14 root 177:
1.1.1.12 root 178: // 浮動小数点数命令用の処理
179: void ops_int(int mode);
180:
181: #define OP_PROTO(name) void __CONCAT(op_,name)()
182: #include "m88100ops.h"
183: OP_PROTO(illegal);
184: #undef OP_PROTO
185:
186: void fpu_unimpl();
187:
188: // float,double と整数値の相互変換
189: static float u2f(uint32 u) {
190: float v;
191: memcpy(&v, &u, sizeof(v));
192: return v;
193: }
194: static double u2d(uint64 u) {
195: double v;
196: memcpy(&v, &u, sizeof(v));
197: return v;
198: }
199: static uint32 f2u(float v) {
200: uint32 u;
201: memcpy(&u, &v, sizeof(u));
202: return u;
203: }
204: static uint64 d2u(double v) {
205: uint64 u;
206: memcpy(&u, &v, sizeof(u));
207: return u;
208: }
209:
210: // [0] 命令バス
211: // [1] データバス
212: std::array<std::unique_ptr<m88200>, 2> cmmu {};
213:
214: // ブランチ履歴 (例外履歴を含む)
215: BranchHistory_m88xx0 brhist { OBJ_MPU_BRHIST };
216: // 例外履歴のみ
217: BranchHistory_m88xx0 exhist { OBJ_MPU_EXHIST };
218:
219: // 今のところサイクルを正確に実装するのは無理なので
220: // 適当に全部積み上げてある。
221:
222: // 電源オンからの累積消費サイクル
223: uint64 used_cycle {};
224:
1.1.1.13 root 225: // 今回のバスウェイト [nsec]
226: uint64 buswait {};
227:
1.1.1.12 root 228: // ペンディング中の割り込みレベル
229: int intr_pending {};
230:
231: // CPU の状態
232: void ChangeState(uint32 new_state);
233: uint32 cpu_state {};
234:
235: // 疑似 STOP 状態に入る機能を有効にする場合 true
236: bool pseudo_stop_enable {};
237:
238: // DOS call エミュレーション
239: bool (*fline_callback)(MPU88xx0Device *, void *) = NULL;
240: void *fline_arg {};
241:
1.1.1.9 root 242: // レジスタモニター
243: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
1.1.1.15! root 244: Monitor *monitor {};
1.1.1.2 root 245:
1.1.1.11 root 246: // イベントコールバック
247: EventCallback_t exec_normal {};
1.1.1.2 root 248: };
249:
1.1.1.13 root 250: // これを呼びたい人は mpu を持ってるはず。
251: static inline MPU88xx0Device *GetMPU88xx0Device(Device *mpu_) {
252: return dynamic_cast<MPU88xx0Device*>(mpu_);
1.1.1.12 root 253: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.