|
|
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: #include "m88100.h"
8: #include "m88100excep.h"
9: #include "debugger.h"
10: #include "cvprompt.h"
11: #include "mpu.h"
12:
13: #define OP_DEF(name) void __CONCAT(m88kcpu::op_,name)()
14: #define OP_FUNC(name) __CONCAT(op_,name)()
15: #include "m88100ops.cpp"
16:
17: // リセット例外のようなもの?
18: void
19: m88kcpu::Reset(uint32 reset_vector)
20: {
21: // TODO: 未完成
22: psr = 0x800003ff;
23: // SFD1 = 0;
24: psr &= ~PSR_SFD1;
25:
1.1.1.2 ! root 26: #if defined(TEST_INTERRUPT)
1.1 root 27: psr &= ~PSR_IND;
28: psr &= ~PSR_SFRZ;
29: #endif
30:
1.1.1.2 ! root 31: SetPSR(psr);
! 32:
1.1 root 33: vbr = 0;
34:
1.1.1.2 ! root 35: cmmu[0].Reset();
! 36: cmmu[1].Reset();
! 37:
1.1 root 38: // 実際には m88k MPU はリセット直後は 0 番地から実行を開始するので、
39: // 大抵の場合システムでリセット直後は 0 番地付近に ROM を見せるように
40: // してあるのだと思うが、ここではその代わりに ROM のアドレスを指定して、
41: // 直接そこから実行を開始することにする。
42: fip = reset_vector;
43: nip = 0;
44: xip = 0;
45:
46: fetch();
47: }
48:
49: // request サイクル分実行する。
50: uint32
51: m88kcpu::Run(uint64 request)
52: {
53: uint64 goal_cycle = total_cycle + request;
54: bool is_release = false;
55: bool is_intr = false;
56:
1.1.1.2 ! root 57: if ((atomic_reqflag & CPU_REQ_STOP)) {
! 58: if ((atomic_reqflag & CPU_REQ_INTR) == 0) {
! 59: // STOP 状態のままで割り込みが無ければ、
! 60: // STOP 継続として戻る。
! 61: total_cycle = goal_cycle;
! 62: return atomic_reqflag;
! 63: }
! 64: // 状態が変わったら STOP 解除。
! 65: atomic_reqflag &= ~CPU_REQ_STOP;
! 66: }
! 67:
1.1 root 68: while (!is_release) {
69: // shift pipeline
70: opX = opF;
71: xip = nip;
72:
73: // prefetch next inst
74: fetch();
75:
76: // この時点で実行しようとする命令が opX に入っている
77:
78: if (atomic_reqflag != 0) {
79: // 何かが起きた
80:
81: // 割り込みの認識
82: // 割り込みの実行は命令実行完了後、次のプリフェッチの前
83: if ((atomic_reqflag & CPU_REQ_INTR)) {
84: atomic_reqflag &= ~CPU_REQ_INTR;
85: is_intr = true;
1.1.1.2 ! root 86: #if defined(TEST_INTERRUPT)
1.1 root 87: atomic_reqflag |= CPU_REQ_PROMPT;
88: #endif
89: }
90:
91: if ((atomic_reqflag & CPU_REQ_TRACE)) {
92: // デバッガプロンプトを出すかどうかを判断する
93: //inst_count++;
94: if (debugger_check()) {
95: atomic_reqflag |= CPU_REQ_PROMPT;
96: }
97: }
98:
99: if ((atomic_reqflag & CPU_REQ_PROMPT)) {
100: // デバッガプロンプトのための実行停止
101:
102: // プロンプト獲得を通知
103: gCVPrompt->NotifyAcquire();
104:
105: // プロンプト解放を待機
106: gCVPrompt->WaitRelease();
107:
108: // プロンプトを抜けたのでここでフラグを落とす
109: atomic_reqflag &= ~CPU_REQ_PROMPT;
110: }
111:
112: if ((atomic_reqflag & CPU_REQ_RELEASE)) {
113: // 中断リクエスト受信
114: // この命令を実行し終わったら抜ける
115: atomic_reqflag &= ~CPU_REQ_RELEASE;
116: is_release = true;
117: }
118: }
119:
120: if (OpIsBusErr(opX)) {
121: // プリフェッチしていた命令がバスエラー
122: Exception(M88K_EXCEP_INST);
123: continue;
124: }
125:
126: uint32 op12 = op32_to_12(opX);
127:
128: switch (op12) {
129: #include "m88100switch.inc"
130: default:
1.1.1.2 ! root 131: OP_FUNC(illegal);
! 132: break;
1.1 root 133: }
134:
135: if (is_intr) {
136: if (!(psr & PSR_IND)) {
1.1.1.2 ! root 137: // XXX: 割り込み信号線はレベル割り込みなのだが
! 138: // まだ処理できないのでとりあえずラッチ割り込みにしておく。
! 139: is_intr = false;
1.1 root 140: gMPU->putlog(4, "INTR take");
141: ExceptionCore(M88K_EXCEP_INTERRUPT, ExceptionKind::INTR);
142: continue;
143: } else {
144: gMPU->putlog(4, "INTR DISABLE");
145: }
146: }
147:
148: total_cycle++;
1.1.1.2 ! root 149:
! 150: if ((atomic_reqflag & CPU_REQ_STOP)) {
! 151: // STOP 状態は、残りサイクルを消費したことにして戻る
! 152: gMPU->putlog(2, "STOP 状態検出");
! 153: total_cycle = goal_cycle;
! 154: is_release = true;
! 155: }
! 156:
1.1 root 157: if (total_cycle >= goal_cycle)
158: break;
159: }
160:
161: return atomic_reqflag;
162: }
163:
164: // この命令後に実行を中断して VM に戻る
165: void
166: m88kcpu::Release()
167: {
168: atomic_reqflag |= CPU_REQ_RELEASE;
169: }
170:
171: // 通常の例外。
1.1.1.2 ! root 172: // DataAccessException, エラー、割り込み、TRAP からは使わない。
1.1 root 173: // vec はベクタ番号。
174: void
175: m88kcpu::Exception(int vec)
176: {
177: ExceptionCore(vec, ExceptionKind::NORMAL);
178: }
179:
180: // 例外処理コア部分
181: // vec はベクタ番号。
182: void
183: m88kcpu::ExceptionCore(int vec, ExceptionKind cause)
184: {
185: if (psr & PSR_SFRZ) {
186: if (cause != ExceptionKind::TRAP) {
187: gMPU->putlog(2, "SFRZ Error Exception");
188: vec = M88K_EXCEP_ERROR;
189: cause = ExceptionKind::ERROR;
190: }
191: } else {
192: gMPU->putlog(2, "Exception %x", vec);
1.1.1.2 ! root 193: if (vec != 1) {
! 194: gMPU->putlog(1, "Exception %x x=%x n=%x f=%x", vec, xip, nip, fip);
! 195: }
1.1 root 196: sxip = xip;
197: snip = nip;
198: sfip = fip;
199:
200: sxip |= SIP_V;
201: snip |= SIP_V;
202: // XXX:実機と異なり、fip は常にフェッチ前なので V=0
1.1.1.2 ! root 203: // ^^^^ コレ自体怪しい。INTERRUPT とか。
1.1 root 204:
205: if (OpIsBusErr(opX)) {
206: sxip |= SIP_E; // E bit
207: }
208: if (OpIsBusErr(opF)) {
209: snip |= SIP_E; // E bit
210: }
211:
212: if (vec == M88K_EXCEP_UNIMPL_OP) {
213: sxip &= ~SIP_V;
214: }
215: }
216:
1.1.1.2 ! root 217: if (cause != ExceptionKind::DATA) {
! 218: // データアクセス例外以外は、
! 219: // データパイプラインはフラッシュ状態とする。
! 220: // ほんとうは違う。かも。
! 221: dmt0 = 0;
! 222: } else {
! 223: // xip: ld/st/xmem
! 224: // nip: next
! 225: // fip: fetch
! 226:
! 227: // rom1.2 は DAE が起きると、
! 228:
! 229: // ROM挙動 CPU の RTE 挙動
! 230: // sfip = sxip
! 231: // sxip -> ~V (INVALID) CPU はそもそも sxip を評価しない
! 232: // snip = 0 (INVALID) CPU はこれを nop 相当に処理する
! 233: // rte
! 234:
! 235: // してくる。そのまま読むと命令を再実行しようとしているように
! 236: // 読めるが、再実行すると無限ループになってしまう。
! 237: // DAE の時点で xip が進んでいることを期待して利用している?
! 238:
! 239: // openbsd は
! 240: // xmem の write バスエラーを検知すると命令を再実行するために
! 241: // fip = nip, nip = xip して rte する。ということは xip = xmem に
! 242: // なっていることを期待している。
! 243:
! 244: // というわけで
! 245: // ld で DataAccessException のときは、実CPUはすでに次の命令を
! 246: // 実行している?
! 247: // もう少し考えると、スコアボードでレジスタの干渉がなければ、
! 248: // 実行している?
! 249:
! 250: // 仕方がないのでハックでごまかす。
! 251: // rte のほうも参照のこと。
! 252:
! 253: if (IsSuper() && xip >= 0x41000000 && xip < 0x42000000) {
! 254: // 遅延例外機構がないので、ROM 合わせのハック。
! 255: sxip = snip;
! 256: }
! 257: }
! 258:
1.1 root 259: epsr = psr;
1.1.1.2 ! root 260: SetPSR(psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ);
1.1 root 261:
262: fip = vbr + (vec << 3);
1.1.1.2 ! root 263: brhist.AddEntry(xip, fip);
1.1 root 264: fetch();
265: if (OpIsBusErr(opF)) {
266: if (cause == ExceptionKind::ERROR) {
267: // double bus fault
268: // 実機は無限ループ状態
269: PANIC("Infinite ERROR (double bus fault)");
270: } else {
271: ExceptionCore(M88K_EXCEP_ERROR, ExceptionKind::ERROR);
272: }
273: }
274: }
275:
276: // データアクセス例外(Read)
277: void
278: m88kcpu::ReadDataException(uint32 addr, uint32 flag)
279: {
280: // ミスアラインドはこの例外より前にチェックされていて、
281: // ここにはアラインドしかこない。
282: dma0 = addr & ~0x3;
283: dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
284: | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
285: | (flag & DM_DOUB1) // ダブルワードの第1アクセスのときセット
286: | (flag & DM_LOCK) // xmem でセット
287: | (FLD_D << 7)
288: | (flag & DM_SIGNED)
289: | ((flag & DM_EN_MASK) >> (addr & 0x03))
290: | 0 // DM_WRITE = 0
291: | DM_VALID;
1.1.1.2 ! root 292: gMPU->putlog(1, "ReadDAE xip=%x addr=%x", xip, addr);
! 293: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1 root 294: }
295:
296: // データアクセス例外(Write)
297: void
298: m88kcpu::WriteDataException(uint32 addr, uint32 data, uint32 flag)
299: {
300: // ミスアラインドはこの例外より前にチェックされていて、
301: // ここにはアラインドしかこない。
302: dma0 = addr & ~0x3;
303: dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
304: | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
305: | (flag & DM_DOUB1) // ダブルワードの第1アクセスのときセット
306: | (flag & DM_LOCK) // xmem でセット
307: | (FLD_D << 7)
308: | (flag & DM_SIGNED)
309: | ((flag & DM_EN_MASK) >> (addr & 0x03))
310: | DM_WRITE
311: | DM_VALID;
312:
1.1.1.2 ! root 313: dmd0 = data;
! 314: gMPU->putlog(1, "WriteDAE xip=%x addr=%x", xip, addr);
! 315: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
! 316: }
! 317:
! 318: // データアクセス例外(xmem)
! 319: void
! 320: m88kcpu::XmemDataException(uint32 addr, uint32 data, uint32 flag)
! 321: {
! 322: dma0 = addr & ~0x3;
! 323: dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
! 324: | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
! 325: | (flag & DM_DOUB1) // ダブルワードの第1アクセスのときセット
! 326: | (flag & DM_LOCK) // xmem でセット
! 327: | (FLD_D << 7)
! 328: | (flag & DM_SIGNED)
! 329: | ((flag & DM_EN_MASK) >> (addr & 0x03))
! 330: | 0 // DM_WRITE = 0
! 331: | DM_VALID;
! 332:
! 333: dma1 = addr & ~0x3;
! 334: dmt1 = ((psr & PSR_BO_LE) ? DM_BO : 0)
! 335: | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
! 336: | (flag & DM_DOUB1) // ダブルワードの第1アクセスのときセット
! 337: | (flag & DM_LOCK) // xmem でセット
! 338: | (FLD_D << 7)
! 339: | (flag & DM_SIGNED)
! 340: | ((flag & DM_EN_MASK) >> (addr & 0x03))
! 341: | DM_WRITE
! 342: | DM_VALID;
! 343:
! 344: dmd1 = data;
! 345:
! 346: // ミスアラインドはこの例外より前にチェックされていて、
! 347: // ここにはアラインドしかこない。
! 348: if (cmmu[1].fault_code != m88200::FAULT_CODE_BUSERR
! 349: || cmmu[1].acc_read) {
! 350: // アドレス変換フォルトまたは read 時点
! 351: // nop
1.1 root 352: } else {
1.1.1.2 ! root 353: // xmem の write 時点
! 354: dma0 = dma1;
! 355: dmt0 = dmt1;
! 356: dmd0 = dmd1;
! 357: dmt1 &= ~DM_VALID;
1.1 root 358: }
1.1.1.2 ! root 359:
! 360: gMPU->putlog(1, "xmemDAE xip=%x addr=%x", xip, addr);
! 361: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1 root 362: }
363:
364: void
365: m88kcpu::Interrupt()
366: {
367: atomic_reqflag |= CPU_REQ_INTR;
1.1.1.2 ! root 368: // gMPU->putlog(1, "INTERRUPT IGNORED");
1.1 root 369: gMPU->putlog(4, "INTERRUPT ACK (アドレスは不正確)");
370: }
371:
372: void
373: m88kcpu::fpu_unimpl()
374: {
375: printf("%s\n", __func__);
376: }
1.1.1.2 ! root 377:
! 378: OP_DEF(illegal)
! 379: {
! 380: // 本来は不当命令例外?
! 381: gMPU->putlog(0, "Illegal instruction %08x", (uint32)opX);
! 382: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.