|
|
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.5 ! root 170: m88kcpu(uint32 reset_vector_);
1.1 root 171: virtual ~m88kcpu();
172:
1.1.1.5 ! root 173: uint32 Run(uint32 delta);
1.1 root 174: void Release();
1.1.1.5 ! root 175: void RequestReset();
! 176:
! 177: // 仮想時刻を返す
! 178: uint64 GetVTime();
1.1 root 179:
1.1.1.5 ! root 180: // 割り込み信号線が変化したことの通知を受ける。
! 181: // level は 0 か 1。
! 182: void Interrupt(int level);
1.1 root 183:
1.1.1.2 root 184: // PID.VERSION を設定する (初期化時に呼ぶ)
185: void SetVersion(uint32 version);
186:
1.1.1.4 root 187: // クラス外部からの xip 取得
188: uint32 GetXIP() const { return xip; }
1.1 root 189:
190: // op が>=0ならバスエラーは起きていない
191: // そのときに DELAYSLOT bit が 0 ならば通常
192: // bit32 が 1 ならば遅延スロット命令
193: // op が負数ならバスエラーが起きた
194: // そのときに DELAYSLOT bit が 1 ならば通常バスエラー
195: // bit32 が 0 ならば遅延スロットでのバスエラー
196: // バスエラーかどうかのチェックのほうが回数が多いため、
197: // バスエラー優先にしたい。
198:
1.1.1.4 root 199: static bool OpIsBusErr(uint64 op) {
1.1 root 200: return (int64)op < 0;
201: }
1.1.1.4 root 202:
203: // op が DelaySlot 実行なら true を返す。デバッガで表示用に使う。
204: static bool OpIsDelay(uint64 op) {
1.1 root 205: return (OpIsBusErr(op) ? ~op : op) & DELAYSLOT;
206: }
207:
1.1.1.4 root 208: // サイクルを加算 (m88200 から使う)
1.1.1.5 ! root 209: // 今は単純に加算しているだけでオーバーラップなどは考慮してない
! 210: void AddCycle(int32 wait) { used_cycle += wait; }
! 211:
! 212: // MPU クロックを設定
! 213: void SetClockSpeed(uint32 clock_khz_) { clock_khz = clock_khz_; }
1.1.1.4 root 214:
215: std::atomic<uint32> atomic_reqflag {}; // リクエストフラグ
216:
217: // [0] 命令バス
218: // [1] データバス
219: m88200 cmmu[2] {};
220:
221: // ブランチ履歴 (例外履歴を含む)
222: BranchHistory_m88xx0 brhist {};
223: // 例外履歴のみ
224: BranchHistory_m88xx0 exhist {};
225:
1.1.1.5 ! root 226: // 32bit 命令コードからディスパッチ用の 12bit に変換。
! 227: static uint32 op32_to_12(uint32 op) {
! 228: return ((op >> 20) & 0x0fc0) | ((op >> 10) & 0x003f);
! 229: }
! 230:
1.1.1.4 root 231: // 例外名を返す
232: static const char *GetExceptionName(int vector);
233:
234: private:
1.1.1.5 ! root 235: void Reset();
! 236:
1.1.1.4 root 237: uint64 fetch() {
238: nip = fip;
239: opF = cmmu[0].load_32(fip);
240: fip += 4;
241: return opF;
242: }
243:
244: // PSR を newpsr に変更する。
1.1.1.2 root 245: // CY ビットは特別にこの関数を経由しないで変更してよいことにする。
246: void SetPSR(uint32 newpsr)
247: {
248: psr = newpsr;
1.1.1.4 root 249: SetPSR();
250: }
251: // 更新された psr に基づいて、PSR 変更によって必要な処理をする。
252: // CY ビットを変更した場合は呼ばなくてよいことにする。
253: void SetPSR()
254: {
1.1.1.2 root 255: // CMMU に S/U 信号を出す
256: cmmu[0].SetSuper(IsSuper());
257: cmmu[1].SetSuper(IsSuper());
1.1.1.5 ! root 258: // 割り込み許可なら割り込みチェック
! 259: if (IsIntrEnable()) {
! 260: atomic_reqflag |= CPU_REQ_INTR;
! 261: }
1.1.1.2 root 262: }
263:
1.1 root 264: void Exception(int vec);
265: void ExceptionCore(int vec, ExceptionKind cause);
1.1.1.5 ! root 266: uint32 Calcdmt(uint32 flag);
! 267: void ReadDataException32(uint32 addr, uint32 flag);
! 268: void ReadDataException64(uint32 addr, uint32 flag);
! 269: void WriteDataException32(uint32 addr, uint32 flag);
! 270: void WriteDataException64(uint32 addr, uint32 flag);
! 271: void XmemDataException(uint32 addr, uint32 flag);
! 272: void FPException(int fpex);
1.1.1.2 root 273:
1.1 root 274: // ブランチ処理用
1.1.1.4 root 275: void EnterBranch(uint32 toaddr);
1.1 root 276: void ExitBranch();
277: void ExitDelayBranch();
1.1.1.2 root 278: uint32 nop_counter {}; // STOP 検出用の nop 命令カウンタ
279:
1.1 root 280: // ロードストア命令用の下処理
1.1.1.2 root 281: bool ldst_usr(uint32& usr);
1.1 root 282: uint32 ldst_scale(uint32 size);
283: bool ldst_align(uint32 size, uint32& addr);
284:
285: #define OP_PROTO(name) void __CONCAT(op_,name)()
286: #include "m88100ops.h"
1.1.1.2 root 287: OP_PROTO(illegal);
1.1 root 288: #undef OP_PROTO
289:
290: void op_unimpl() {
291: printf("unimplemented op XIP=%08x opX=%08x\n", xip, (uint32)opX);
292: }
1.1.1.4 root 293: void fpu_unimpl();
294:
1.1.1.5 ! root 295: // 仮想時刻 [nsec]
! 296: uint64 total_vtime {};
! 297:
! 298: // サイクル数を仮想時間 [nsec] に変換
! 299: uint64 Cycle2Vtime(int32 cycle) const {
! 300: return (int64)cycle * 1000 * 1000 / clock_khz;
1.1.1.4 root 301: }
302:
1.1.1.5 ! root 303: // 仮想時間 [nsec] をサイクル数に変換
! 304: uint32 Vtime2Cycle(uint32 vtime) const {
! 305: return (uint32)((uint64)vtime * clock_khz / (1000 * 1000));
! 306: }
! 307:
! 308: // 仕掛中のサイクルを仮想時刻に反映させる
! 309: void UpdateVTime();
! 310:
! 311: // 今のところサイクルを正確に実装するのは無理なので
! 312: // 適当に全部積み上げてある。
! 313: uint32 used_cycle {}; // 現在のターンでこれまでに消費したサイクル数
! 314: uint32 goal_cycle {}; // 現在のターンで消費すべきサイクル数
! 315: uint32 clock_khz {}; // MPU クロック [kHz]
! 316:
! 317: // ペンディング中の割り込みレベル
! 318: int intr_pending {};
! 319:
! 320: // リセットベクタ
! 321: uint32 reset_vector {};
1.1.1.3 root 322:
323: // 例外名
324: static const char * const exception_names[];
1.1 root 325: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.