|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #pragma once
8:
9: //
10: // 外部公開用
11: //
12:
1.1.1.3 root 13: #include "branchhistory.h"
1.1 root 14: #include <atomic>
15: #include <mutex>
16: #include <sys/cdefs.h>
17:
18: __BEGIN_DECLS
19: #include "fpu_emulate.h"
20: __END_DECLS
21:
22: class m68kcpu;
23:
24: // 外部ループフラグ
25: // これらのフラグがいずれも立っていない間、CPU 実行は内側のディスパッチ
26: // ループを周り、どれかでも立てばディスパッチループを抜けてフラグを処理
27: // してから再びディスパッチループに戻る。
28: // それぞれ独立しているためビットを立てる際は代入ではなく OR すること。
29: #define CPU_REQ_STOP (0x00000001) // ストップ状態
30: #define CPU_REQ_HALT (0x00000002) // ホールト状態
31: #define CPU_REQ_TRACE (0x00000004) // デバッガ有効
32: #define CPU_REQ_PROMPT (0x00000008) // デバッガプロンプト
33: #define CPU_REQ_RELEASE (0x00000010) // 命令後に CPU 実行中断
34: #define CPU_REQ_INTR (0x00000020) // 命令後に割り込みチェックが必要
35:
36: #define M68K_SR_T (0xc000)
37: #define M68K_SR_S (0x2000)
38: #define M68K_SR_M (0x1000)
39: #define M68K_CCR_X (0x0010)
40: #define M68K_CCR_N (0x0008)
41: #define M68K_CCR_Z (0x0004)
42: #define M68K_CCR_V (0x0002)
43: #define M68K_CCR_C (0x0001)
44:
45: // SSW
46: #define SSW_SIZE(x) (((x) & 0x03) << 4)
47: #define SSW_SIZE_BYTE SSW_SIZE(1)
48: #define SSW_SIZE_WORD SSW_SIZE(2)
49: #define SSW_SIZE_3BYTES SSW_SIZE(3)
50: #define SSW_SIZE_LONG SSW_SIZE(0)
51: #define SSW_SIZE_MASK SSW_SIZE(0x03)
52:
53: #define SSW_FC_MASK (0x0007) // FC_*
54: #define SSW_RW (0x0040) // SSW_BUS_{R,W}
55: #define SSW_RM (0x0080)
56: #define SSW_DF (0x0100) // Data Fault
57: #define SSW_RB (0x1000)
58: #define SSW_RC (0x2000)
59: #define SSW_FB (0x4000)
60: #define SSW_FC (0x8000)
61:
62: #define SSW_BUS_R (0x0040)
63: #define SSW_BUS_W (0x0000)
64:
65: #define FC_DATA (1)
66: #define FC_PROG (2)
67: #define FC_USER (0)
68: #define FC_SUPER (4)
69: #define FC_UD (FC_USER | FC_DATA)
70: #define FC_UP (FC_USER | FC_PROG)
71: #define FC_SD (FC_SUPER | FC_DATA)
72: #define FC_SP (FC_SUPER | FC_PROG)
73:
74: #define M68K_FPCR_MASK (0x0000fff0)
75: #define M68K_FPSR_MASK (0x0ffffff8)
76:
77: #include "m68030ccr.h"
78: #include "m68030mmu.h"
79:
80: // レジスタイメージを保持する構造体。
81: // この構造体はコピーとか比較をするのでポインタとかは置かないこと。
82: struct m68kreg {
83: public:
84: uint32 pc;
85: uint32 da[16];
86:
87: m68030ccr ccr;
88: bool s; // SR の S ビット
89: bool m; // SR の M ビット
90: int intr_level; // SR の割り込みレベル (0-7)
91:
92: // 現在の SP は常に da[15]。現在有効でない残り2つの SP をここに保存。
93: // 例えばユーザ状態なら da[15] が USP、isp/msp は ISP/MSP を示し、
94: // usp の内容は無効。
95: uint32 usp;
96: uint32 isp;
97: uint32 msp;
98:
99: uint32 vbr;
100: uint32 sfc;
101: uint32 dfc;
102:
103: uint32 cacr;
104: uint32 caar;
105:
106: union64 srp;
107: union64 crp;
108: uint32 tt[2];
109: uint32 tc;
110: uint16 mmusr;
111:
112: struct fpframe fpframe;
113:
114: // CPU の実行状態
115: // 0 .. 通常状態
116: // CPU_REQ_STOP .. STOP 状態
117: // CPU_REQ_HALT .. HALT 状態
118: uint32 state;
119:
120: public:
121: // SR の上位8ビット部分のみを返す
122: uint16 sr_h() {
123: return (s ? M68K_SR_S : 0) | (m ? M68K_SR_M : 0) | (intr_level << 8);
124: }
125: };
126:
127: // バス状態
128: struct m68kbus {
129: // 論理アドレスと SSW。
130: // SSW はアクセス前に SSW_BUS_{R,W} と FC[012] をセットすること。
131: DEF_UNION64(, ssw_laddr, ssw, laddr);
132:
133: uint32 paddr; // 対応する物理アドレス
134: // データバス。
135: // 今の所書き込みだけで使う。読み込みデータは戻り値のみ。
136: uint32 data;
137:
138: // SSW のうち現在の FC2 だけ別途覚えておく。
139: // FC2 が変化するのは SR:S による特権モードが変わった時だけなので。
140: uint16 fc2;
141:
142: // バスが Write なら true を返す
143: bool IsWrite() const { return (ssw & SSW_BUS_R) == 0; }
144:
145: // このへんどうするか
146:
147: // FC2 をキャッシュしておく。
148: void SetFC2(bool newfc2) {
149: fc2 = newfc2 ? 4 : 0;
150: }
151: // FC を取得する。
152: // これは MMU ルーチンから呼ばれる。そのためこの時点ではすでに
153: // FC0/1 と FC2 は ssw に合成済みなので、これでよい。
154: uint GetFC() const { return ssw & SSW_FC_MASK; }
155: };
156:
1.1.1.3 root 157: class m68kcpu final {
1.1 root 158: public:
159: m68kcpu() { }
1.1.1.3 root 160: ~m68kcpu() { }
1.1 root 161:
162: public:
163: m68kreg reg {};
164: uint32 ppc = 0; // 現在実行中の命令の先頭アドレス
165: uint16 ir = 0;
166: uint16 ir2 = 0;
167:
168: uint32 save_pd[8] {}; // -(An) を保存
169: uint32 save_pi[8] {}; // (An)+ を保存
170: uint8 flag_pd = 0; // -(An) のどのレジスタを保存したか
171: uint8 flag_pi = 0; // (An)+ のどのレジスタを保存したか
172:
173: // MMU 状態
174: bool mmu_enable = false;
175: // SRP
176: void SetSRP(uint32, uint32);
177: uint64 GetSRP() const { return reg.srp.q; }
178: uint32 GetSRPh() const { return reg.srp.h; }
179: uint32 GetSRPl() const { return reg.srp.l; }
180: // CRP
181: void SetCRP(uint32, uint32);
182: uint64 GetCRP() const { return reg.crp.q; }
183: uint32 GetCRPh() const { return reg.crp.h; }
184: uint32 GetCRPl() const { return reg.crp.l; }
185: // TT
186: void SetTT(int idx, uint32);
187: uint64 GetTT(int idx) const { return reg.tt[idx]; }
188: // TC
189: bool SetTC(uint32);
190: uint32 GetTC() const { return reg.tc; }
191: // MMUSR
192: void SetMMUSR(uint16);
193: uint16 GetMMUSR() const { return reg.mmusr; }
194: // MMU work
195: m68030TT mmu_tt[2];
196: uint8 mmu_tt_quick[256] {};
197: m68030TC mmu_tc;
198: m68030ATC atc {this};
199:
200: private:
201: void mmu_enable_changed();
202:
203: public:
204: int has_fpu = 0; // 0:FPUなし、1:68881、2:68882(?)
205: bool fpu_dirty = false;
206: struct fpemu fe {};
207:
208: std::atomic<uint32> atomic_reqflag {}; // 外部ループ & リクエストフラグ
209:
210: // 割り込みペンディング
211: // intr_vector[1] がレベル1割り込みのペンディング中ベクタ
212: // :
213: // intr_vector[7] がレベル7割り込みのペンディング中ベクタ
214: //
215: // [0] を intr_pending (割り込みペンディング) として使う。
216: // ペンディングになっているレベルのビットを立てる。
217: //
218: // bit 7 6 5 4 3 2 1 0
219: // Level 0 1 2 3 4 5 6 7
220: //
221: // intrmtx 取ってからアクセスすること。
222: uint8 intr_vector[8] {};
223: #define intr_pending intr_vector[0]
224:
225: // 割り込みマスク
226: // 現在の割り込みレベルで割り込みを受け付けるレベルのビットを立てる
227: // I=0 だと割り込みレベル 1..7 を受け付けるので %01111111
228: // I=5 だと割り込みレベル 6,7 を受け付けるので %00000011
229: // I=6 だと割り込みレベル 7 を受け付けるので %00000001
230: // ただし I=7 はこれを使わず別処理する
231: // bit 7 6 5 4 3 2 1 0
232: // Level 0 1 2 3 4 5 6 7
233: //
234: // intrmtx 取ってからアクセスすること。
235: uint8 intr_mask = 0;
236:
237: // 割り込み要求は別スレッドから呼ばれる場合もあるので
238: // (自スレッドから呼び出した関数の向こうから呼ばれる場合もあることに注意)
239: // それらの変数はこれで保護する。
240: // 最終的には atomic_reqflag に CPU_REQ_INTR を立てることでメインループ
241: // に通知する (この通知そのものは atomic なので特に保護しなくてもよい)。
242: std::mutex intrmtx {};
243:
244: uint64 total_cycle = 0; // 積算実行サイクル数
245: int32 cycle_cache = 0; // キャッシュケースの所用サイクル数
246: int32 cycle_nocache = 0; // ノーキャッシュケースの時の *追加分*
247: uint64 inst_count = 0; // 命令実行数
248:
1.1.1.4 ! root 249: // ブランチ履歴 (例外履歴を含む)
! 250: BranchHistory_m680x0 brhist {};
! 251: // 例外履歴のみ
! 252: BranchHistory_m680x0 exhist {};
1.1 root 253:
254: // バス
255: m68kbus bus {};
256:
257: // 手抜きのためリセットベクタ取得アドレスを知っている。
258: // リセット時のためだけにデバイス側に細工を入れるのは実行時の
259: // オーバーヘッドが大きそうなので。
260: uint32 reset_vector = 0;
261:
262: // A-Line, F-Line 命令エミュレーションのコールバックとユーザ引数。
263: // ユーザ引数には関与しないので呼び出し側が自由に指定してよい。
264: // コールバック側で処理完了したら true を返す。
265: // デフォルトの処理(すなわちm68k例外)にする場合は false を返す。
266: bool (*aline_callback)(m68kcpu *, void *) = NULL;
267: void *aline_arg = NULL;
268: bool (*fline_callback)(m68kcpu *, void *) = NULL;
269: void *fline_arg = NULL;
1.1.1.3 root 270:
271: // ダブルバスフォールトのコールバックとユーザ引数。
272: void (*halt_callback)(void *) = NULL;
273: void *halt_arg = NULL;
1.1 root 274: };
275:
276: #define RegD(n) (cpu->reg.da[(n)])
277: #define RegA(n) (cpu->reg.da[(n) + 8])
278: #define RegR(n) (cpu->reg.da[(n)])
279: #define RegPC (cpu->reg.pc)
280: #define RegPPC (cpu->ppc)
281: #define RegIR (cpu->ir)
282: #define RegIR2 (cpu->ir2)
283: #define RegSR (cpu->reg.sr_h() | cpu->reg.ccr.Get())
284: #define RegVBR (cpu->reg.vbr)
285: #define RegUSP (cpu->reg.usp)
286: #define RegISP (cpu->reg.isp)
287: #define RegMSP (cpu->reg.msp)
288: #define RegSFC (cpu->reg.sfc)
289: #define RegDFC (cpu->reg.dfc)
290: #define RegCACR (cpu->reg.cacr)
291: #define RegCAAR (cpu->reg.caar)
292:
293: #define RegFP(n) (cpu->reg.fpframe.fpf_regs[n])
294: #define RegFPCR (cpu->reg.fpframe.fpf_fpcr)
295: #define RegFPSR (cpu->reg.fpframe.fpf_fpsr)
296: #define RegFPIAR (cpu->reg.fpframe.fpf_fpiar)
297:
298: #define RegIRX ((RegIR >> 9) & 7)
299: #define RegIRY (RegIR & 7)
300: #define RegDX RegD(RegIRX)
301: #define RegAX RegA(RegIRX)
302: #define RegDY RegD(RegIRY)
303: #define RegAY RegA(RegIRY)
304:
305: // 外部公開ルーチン
306: extern m68kcpu *m68030_init(uint32 reset_vector);
307: extern uint32 m68030_run(m68kcpu *cpu, uint64 request);
308: extern void m68030_exception_reset(m68kcpu *cpu);
309: extern void m68030_interrupt(m68kcpu *cpu, int level, int vector);
310:
311: // 外部で定義されるコールバック
312: extern void m68030_reset_inst(m68kcpu *cpu);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.