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