|
|
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:
7: #pragma once
8:
9: #include "header.h"
1.1.1.2 root 10: #include "branchhistory.h"
1.1 root 11: #include "bus.h"
1.1.1.2 root 12: #include "m88200.h"
1.1 root 13: #include <atomic>
14:
15: // 外部リクエストフラグ
16: // XXX m680x0 側にもよく似たものがあってどうしたもんか
1.1.1.2 root 17: #define CPU_REQ_STOP (0x00000001) // ストップ状態
1.1 root 18: #define CPU_REQ_TRACE (0x00000004) // デバッガ有効
19: #define CPU_REQ_PROMPT (0x00000008) // デバッガプロンプト
20: #define CPU_REQ_RELEASE (0x00000010) // 命令後に CPU 実行中断
21: #define CPU_REQ_INTR (0x00000020) // 命令後に割り込みチェック
1.1.1.5 root 22: #define CPU_REQ_RESET (0x00000040) // リセット例外
1.1 root 23:
24: // m88100 レジスタイメージを保持する構造体。
25: // この構造体はコピーや比較をするので、ポインタとかは置かないこと。
26: struct m88100reg
27: {
28: // PID(cr0)
29: static const uint32 PID_REV_MASK = 0x0000ff00; // 0 = MC88100
30: static const uint32 PID_VER_MASK = 0x000000fe;
31: static const uint32 PID_MASTER = 0x00000001;
32: // PSR(cr1)
33: static const uint32 PSR_SUPER = 0x80000000;
34: static const uint32 PSR_BO_LE = 0x40000000; // ByteOrder(Little)
35: static const uint32 PSR_SER = 0x20000000;
36: static const uint32 PSR_C = 0x10000000; // Carry
37: static const uint32 PSR_SFD1 = 0x00000008; // SFU1 Disable
38: static const uint32 PSR_MXM = 0x00000004; // MisalignedAccessEnable
39: static const uint32 PSR_IND = 0x00000002; // Interrupt Disable
40: static const uint32 PSR_SFRZ = 0x00000001; // Shadow Freeze
41:
42: // 例外処理で使用される S*IP
43: static const uint32 SIP_MASK = 0xfffffffcU;
44: static const uint32 SIP_V = 0x00000002;
45: static const uint32 SIP_E = 0x00000001;
46:
47: // DMTn、データ例外
48: static const uint32 DM_BO = 0x00008000;
49: static const uint32 DM_DAS = 0x00004000;
50: static const uint32 DM_DOUB1 = 0x00002000;
51: static const uint32 DM_LOCK = 0x00001000;
52: static const uint32 DM_DREG_MASK = 0x00000f80;
53: static const uint32 DM_SIGNED = 0x00000040;
54: static const uint32 DM_EN3 = 0x00000020;
55: static const uint32 DM_EN2 = 0x00000010;
56: static const uint32 DM_EN1 = 0x00000008;
57: static const uint32 DM_EN0 = 0x00000004;
58: static const uint32 DM_EN_MASK = (DM_EN0 | DM_EN1 | DM_EN2 | DM_EN3);
59: static const uint32 DM_WRITE = 0x00000002;
60: static const uint32 DM_VALID = 0x00000001;
61: // 内部識別フラグ
62: static const uint32 DM_SIZE_B = (1U << 16) | DM_EN3;
63: static const uint32 DM_SIZE_H = (1U << 17) | DM_EN3 | DM_EN2;
64: static const uint32 DM_SIZE_W = (1U << 18) | DM_EN_MASK;
65: static const uint32 DM_USR = (1U << 20);
66: static const uint32 DM_BU = DM_SIZE_B;
67: static const uint32 DM_B = DM_SIZE_B | DM_SIGNED;
68: static const uint32 DM_HU = DM_SIZE_H;
69: static const uint32 DM_H = DM_SIZE_H | DM_SIGNED;
70: static const uint32 DM_W = DM_SIZE_W;
71: static const uint32 DM_D1 = DM_SIZE_W | DM_DOUB1;
72: static const uint32 DM_D2 = DM_SIZE_W;
73:
74: // 頻繁にアクセスしそうな変数はオフセットの若いほうに持ってきておく。
75:
76: // 実行中の命令
77: uint64 opX = 0;
78: // プリフェッチ命令
79: uint64 opF = 0;
80:
81: uint32 xip = 0;
82: uint32 nip = 0;
83: uint32 fip = 0;
84:
85: uint32 r[32] {};
86: union {
87: uint32 cr[21] {};
88: struct {
89: uint32 pid; // cr0
90: uint32 psr; // cr1
91: uint32 epsr; // cr2
92: uint32 ssbr; // cr3
93: uint32 sxip; // cr4
94: uint32 snip; // cr5
95: uint32 sfip; // cr6
96: uint32 vbr; // cr7
97: uint32 dmt0; // cr8
98: uint32 dmd0; // cr9
99: uint32 dma0; // cr10
100: uint32 dmt1; // cr11
101: uint32 dmd1; // cr12
102: uint32 dma1; // cr13
103: uint32 dmt2; // cr14
104: uint32 dmd2; // cr15
105: uint32 dma2; // cr16
106: uint32 sr[4]; // cr17,18,19,20
107: };
108: };
109: union {
110: uint32 fcr[11] {};
111: struct {
112: uint32 fpecr; // fcr0
113: uint32 fphs1; // fcr1
114: uint32 fpls1; // fcr2
115: uint32 fphs2; // fcr3
116: uint32 fpls2; // fcr4
117: uint32 fppt; // fcr5
118: uint32 fprh; // fcr6
119: uint32 fprl; // fcr7
120: uint32 fpit; // fcr8
121: uint32 fpsr; // fcr62 [9]
122: uint32 fpcr; // fcr63 [10]
123: };
124: };
125:
126: // 直近のデータアクセスアドレス
127: uint32 lastaddr;
128:
129: // スーパーバイザ/ユーザモードなら true
130: bool IsSuper() const { return (psr & PSR_SUPER) != 0; }
131: bool IsUser() const { return (psr & PSR_SUPER) == 0; }
132:
1.1.1.5 root 133: // 割り込みが許可なら true
134: bool IsIntrEnable() const { return (psr & PSR_IND) == 0; }
135:
1.1.1.4 root 136: // SFU1(FPU)が有効なら true
137: bool IsFPUEnable() const { return (psr & PSR_SFD1) == 0; }
138:
1.1 root 139: // MXM (Misaligned Access Enable) なら true
140: bool IsMXM() const { return (psr & PSR_MXM) != 0; }
141:
142: // キャリーフラグが立っていれば 1 を返す
143: uint32 GetCY() const { return (psr >> 28) & 1; }
1.1.1.4 root 144:
145: // キャリーフラグをセットする。
146: // cy のうち最下位ビットのみ参照する (呼び出し側はマスクせず渡してよい)
1.1 root 147: void SetCY(uint cy) {
148: psr &= ~PSR_C;
149: psr |= ((cy & 1) << 28);
150: }
151:
152: static const char * const sipname[3];
1.1.1.2 root 153: static const char * const dmt_en_str[16];
1.1 root 154: };
155:
156: class m88kcpu : public m88100reg
157: {
1.1.1.4 root 158: static const uint64 DELAYSLOT = 1ULL << 62;
159:
160: enum ExceptionKind
161: {
162: NORMAL,
163: DATA,
164: ERROR,
165: INTR,
166: TRAP,
167: };
168:
1.1 root 169: public:
1.1.1.8 root 170: m88kcpu();
1.1 root 171: virtual ~m88kcpu();
172:
1.1.1.8 root 173: void PowerOn();
174: void RequestReset();
175:
1.1.1.5 root 176: uint32 Run(uint32 delta);
1.1 root 177: void Release();
1.1.1.5 root 178:
179: // 仮想時刻を返す
1.1.1.6 root 180: uint64 GetVTime() const { return total_vtime + Cycle2Vtime(used_cycle); }
1.1 root 181:
1.1.1.5 root 182: // 割り込み信号線が変化したことの通知を受ける。
183: // level は 0 か 1。
184: void Interrupt(int level);
1.1 root 185:
1.1.1.2 root 186: // PID.VERSION を設定する (初期化時に呼ぶ)
187: void SetVersion(uint32 version);
188:
1.1.1.4 root 189: // クラス外部からの xip 取得
190: uint32 GetXIP() const { return xip; }
1.1 root 191:
192: // op が>=0ならバスエラーは起きていない
193: // そのときに DELAYSLOT bit が 0 ならば通常
194: // bit32 が 1 ならば遅延スロット命令
195: // op が負数ならバスエラーが起きた
196: // そのときに DELAYSLOT bit が 1 ならば通常バスエラー
197: // bit32 が 0 ならば遅延スロットでのバスエラー
198: // バスエラーかどうかのチェックのほうが回数が多いため、
199: // バスエラー優先にしたい。
200:
1.1.1.4 root 201: static bool OpIsBusErr(uint64 op) {
1.1 root 202: return (int64)op < 0;
203: }
1.1.1.4 root 204:
205: // op が DelaySlot 実行なら true を返す。デバッガで表示用に使う。
206: static bool OpIsDelay(uint64 op) {
1.1 root 207: return (OpIsBusErr(op) ? ~op : op) & DELAYSLOT;
208: }
209:
1.1.1.4 root 210: // サイクルを加算 (m88200 から使う)
1.1.1.5 root 211: // 今は単純に加算しているだけでオーバーラップなどは考慮してない
212: void AddCycle(int32 wait) { used_cycle += wait; }
213:
214: // MPU クロックを設定
1.1.1.7 root 215: void SetClockSpeed(uint32 clock_khz_);
1.1.1.4 root 216:
217: std::atomic<uint32> atomic_reqflag {}; // リクエストフラグ
218:
219: // [0] 命令バス
220: // [1] データバス
221: m88200 cmmu[2] {};
222:
223: // ブランチ履歴 (例外履歴を含む)
1.1.1.9 ! root 224: BranchHistory_m88xx0 brhist { BranchHistory::BrHist };
1.1.1.4 root 225: // 例外履歴のみ
1.1.1.9 ! root 226: BranchHistory_m88xx0 exhist { BranchHistory::ExHistOnly };
1.1.1.4 root 227:
1.1.1.5 root 228: // 32bit 命令コードからディスパッチ用の 12bit に変換。
229: static uint32 op32_to_12(uint32 op) {
230: return ((op >> 20) & 0x0fc0) | ((op >> 10) & 0x003f);
231: }
232:
1.1.1.4 root 233: // 例外名を返す
234: static const char *GetExceptionName(int vector);
235:
1.1.1.9 ! root 236: // 疑似 STOP 状態に入る機能を有効にする場合 true
! 237: bool pseudo_stop_enable {};
! 238:
1.1.1.4 root 239: private:
1.1.1.5 root 240: void Reset();
241:
1.1.1.4 root 242: uint64 fetch() {
243: nip = fip;
244: opF = cmmu[0].load_32(fip);
245: fip += 4;
246: return opF;
247: }
248:
249: // PSR を newpsr に変更する。
1.1.1.2 root 250: // CY ビットは特別にこの関数を経由しないで変更してよいことにする。
251: void SetPSR(uint32 newpsr)
252: {
253: psr = newpsr;
1.1.1.4 root 254: SetPSR();
255: }
256: // 更新された psr に基づいて、PSR 変更によって必要な処理をする。
257: // CY ビットを変更した場合は呼ばなくてよいことにする。
258: void SetPSR()
259: {
1.1.1.2 root 260: // CMMU に S/U 信号を出す
261: cmmu[0].SetSuper(IsSuper());
262: cmmu[1].SetSuper(IsSuper());
1.1.1.5 root 263: // 割り込み許可なら割り込みチェック
264: if (IsIntrEnable()) {
265: atomic_reqflag |= CPU_REQ_INTR;
266: }
1.1.1.2 root 267: }
268:
1.1 root 269: void Exception(int vec);
270: void ExceptionCore(int vec, ExceptionKind cause);
1.1.1.5 root 271: uint32 Calcdmt(uint32 flag);
272: void ReadDataException32(uint32 addr, uint32 flag);
273: void ReadDataException64(uint32 addr, uint32 flag);
274: void WriteDataException32(uint32 addr, uint32 flag);
275: void WriteDataException64(uint32 addr, uint32 flag);
276: void XmemDataException(uint32 addr, uint32 flag);
277: void FPException(int fpex);
1.1.1.2 root 278:
1.1 root 279: // ブランチ処理用
1.1.1.4 root 280: void EnterBranch(uint32 toaddr);
1.1 root 281: void ExitBranch();
282: void ExitDelayBranch();
1.1.1.2 root 283: uint32 nop_counter {}; // STOP 検出用の nop 命令カウンタ
284:
1.1 root 285: // ロードストア命令用の下処理
1.1.1.2 root 286: bool ldst_usr(uint32& usr);
1.1 root 287: uint32 ldst_scale(uint32 size);
288: bool ldst_align(uint32 size, uint32& addr);
289:
290: #define OP_PROTO(name) void __CONCAT(op_,name)()
291: #include "m88100ops.h"
1.1.1.2 root 292: OP_PROTO(illegal);
1.1 root 293: #undef OP_PROTO
294:
295: void op_unimpl() {
296: printf("unimplemented op XIP=%08x opX=%08x\n", xip, (uint32)opX);
297: }
1.1.1.4 root 298: void fpu_unimpl();
299:
1.1.1.5 root 300: // 仮想時刻 [nsec]
301: uint64 total_vtime {};
302:
303: // サイクル数を仮想時間 [nsec] に変換
304: uint64 Cycle2Vtime(int32 cycle) const {
1.1.1.7 root 305: return (int64)cycle * c2v;
1.1.1.4 root 306: }
307:
1.1.1.5 root 308: // 仮想時間 [nsec] をサイクル数に変換
309: uint32 Vtime2Cycle(uint32 vtime) const {
1.1.1.7 root 310: return ((uint64)vtime * v2c_factor) >> v2c_shift;
1.1.1.5 root 311: }
312:
313: // 今のところサイクルを正確に実装するのは無理なので
314: // 適当に全部積み上げてある。
315: uint32 used_cycle {}; // 現在のターンでこれまでに消費したサイクル数
316: uint32 goal_cycle {}; // 現在のターンで消費すべきサイクル数
317: uint32 clock_khz {}; // MPU クロック [kHz]
1.1.1.7 root 318: uint32 c2v {}; // サイクル数を nsec に変換する際の係数
319: uint64 v2c_factor {}; // nsec をサイクル数に変換する際の乗算係数
320: uint32 v2c_shift {}; // nsec をサイクル数に変換する際のシフト係数
1.1.1.5 root 321:
322: // ペンディング中の割り込みレベル
323: int intr_pending {};
324:
1.1.1.3 root 325: // 例外名
326: static const char * const exception_names[];
1.1 root 327: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.