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