|
|
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"
1.1.1.7 root 12: #include "scheduler.h"
1.1 root 13:
14: #define OP_DEF(name) void __CONCAT(m88kcpu::op_,name)()
15: #define OP_FUNC(name) __CONCAT(op_,name)()
16: #include "m88100ops.cpp"
17:
1.1.1.7 root 18: // 文字列を作る前にレベルを評価するためマクロ
19: #define cpulog(lv, fmt...) do { \
20: if (__predict_false(gMPU->loglevel >= (lv))) { \
21: gMPU->putlogn(fmt); \
22: } \
23: } while (0)
24:
1.1.1.8 root 25: void
26: m88kcpu::PowerOn()
27: {
28: // 履歴は電源オン時だけ初期化。
29: // (LUNA88K は ROM が正常パスで CPU リセットを行ったりするので)
30: exhist.Clear();
31: brhist.Clear();
32:
33: // この後起きるリセット例外で xip を初期化する前に参照することになるので
34: // これだけここでも初期化しておく。
35: xip = 0;
36: }
37:
1.1 root 38: // リセット例外のようなもの?
39: void
1.1.1.5 root 40: m88kcpu::Reset()
1.1 root 41: {
1.1.1.8 root 42: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
43: // リセット例外も発生時の XIP を記録する。(LUNA88K の ROM 1.20)
44: exhist.AddEntry(xip | 1, 0, 0xfc000000 | 0);
45: brhist.AddEntry(xip | 1, 0, 0xfc000000 | 0);
46: // デバッガに通知 (例外ブレーク用)
47: debugger_notify_exception(0);
48:
1.1.1.5 root 49: // 内部の割り込み状態をクリア
50: intr_pending = 0;
1.1.1.7 root 51: atomic_reqflag &= ~(CPU_REQ_RESET | CPU_REQ_INTR | CPU_REQ_STOP);
1.1.1.4 root 52:
53: // Table 6-8 (p6-47)
1.1 root 54: psr = 0x800003ff;
1.1.1.4 root 55: // XXX ただし SFU1 は未実装なので下げておく
1.1 root 56: psr &= ~PSR_SFD1;
57:
1.1.1.2 root 58: #if defined(TEST_INTERRUPT)
1.1.1.4 root 59: psr &= ~PSR_IND;
60: psr &= ~PSR_SFRZ;
1.1 root 61: #endif
62:
1.1.1.4 root 63: SetPSR();
1.1.1.2 root 64:
1.1.1.8 root 65: fip = 0;
1.1.1.7 root 66:
67: // レジスタのうち明記されてるものをクリア。
68: // 不定と明記されてるものはリセットでは触らないでおく。
69: // scoreboard: cleared
1.1 root 70: nip = 0;
71: xip = 0;
1.1.1.4 root 72: vbr = 0;
73: fpecr = 0;
74: fpcr = 0;
75: fpsr = 0;
1.1.1.7 root 76: // DMTx は bit0(Valid) をクリア。他は不定
77: dmt0 &= ~DM_VALID;
78: dmt1 &= ~DM_VALID;
79: dmt2 &= ~DM_VALID;
1.1.1.4 root 80:
81: cmmu[0].Reset();
82: cmmu[1].Reset();
83:
1.1 root 84: fetch();
85: }
86:
1.1.1.5 root 87: // 仮想時間 delta [nsec] だけ CPU を実行する。実際には大抵行き過ぎる。
1.1.1.7 root 88: // 戻り値は CPU 状態 (Scheduler::SCHED_CPU_*)。
1.1 root 89: uint32
1.1.1.5 root 90: m88kcpu::Run(uint32 delta)
1.1 root 91: {
92: bool is_release = false;
93: bool is_intr = false;
94:
1.1.1.5 root 95: assert(used_cycle == 0);
96:
97: goal_cycle = Vtime2Cycle(delta);
98: if (__predict_false(goal_cycle == 0)) {
99: goal_cycle = 1;
100: }
101:
1.1.1.2 root 102: if ((atomic_reqflag & CPU_REQ_STOP)) {
1.1.1.5 root 103: if ((atomic_reqflag & (CPU_REQ_INTR | CPU_REQ_PROMPT | CPU_REQ_RESET))) {
104: // 割り込み、デバッガ、リセットが来たら STOP 解除。
105: atomic_reqflag &= ~CPU_REQ_STOP;
106: } else {
1.1.1.2 root 107: // STOP 継続として戻る。
1.1.1.5 root 108: used_cycle = goal_cycle;
1.1.1.6 root 109: goto exit;
1.1.1.2 root 110: }
111: }
112:
1.1 root 113: while (!is_release) {
114: // shift pipeline
115: opX = opF;
116: xip = nip;
117:
118: // prefetch next inst
119: fetch();
120:
121: // この時点で実行しようとする命令が opX に入っている
122:
123: if (atomic_reqflag != 0) {
124: // 何かが起きた
125:
1.1.1.5 root 126: if ((atomic_reqflag & CPU_REQ_RESET)) {
127: // リセット例外。
128: Reset();
129: // XIP がリセットベクタを指すためにはもう一回フェッチが必要
130: // なので、ここは continue が必要。
131: continue;
132: }
133:
1.1 root 134: // 割り込みの認識
135: // 割り込みの実行は命令実行完了後、次のプリフェッチの前
136: if ((atomic_reqflag & CPU_REQ_INTR)) {
137: atomic_reqflag &= ~CPU_REQ_INTR;
1.1.1.5 root 138: if (intr_pending && IsIntrEnable()) {
139: // この命令のあとに割り込み処理
140: is_intr = true;
141: }
1.1.1.2 root 142: #if defined(TEST_INTERRUPT)
1.1.1.4 root 143: atomic_reqflag |= CPU_REQ_PROMPT;
1.1 root 144: #endif
145: }
146:
147: if ((atomic_reqflag & CPU_REQ_TRACE)) {
148: // デバッガプロンプトを出すかどうかを判断する
149: //inst_count++;
150: if (debugger_check()) {
151: atomic_reqflag |= CPU_REQ_PROMPT;
152: }
153: }
154:
155: if ((atomic_reqflag & CPU_REQ_PROMPT)) {
156: // デバッガプロンプトのための実行停止
157:
158: // プロンプト獲得を通知
159: gCVPrompt->NotifyAcquire();
160:
161: // プロンプト解放を待機
162: gCVPrompt->WaitRelease();
163:
164: // プロンプトを抜けたのでここでフラグを落とす
165: atomic_reqflag &= ~CPU_REQ_PROMPT;
1.1.1.4 root 166:
167: // プロンプトから戻ってきたら一旦スケジューラまで戻る(?)。
168: // reset コマンドのようにデバッガからスケジューラに出した
169: // リクエストを(なるはやで?)回収するため。
170: atomic_reqflag |= CPU_REQ_RELEASE;
1.1 root 171: }
172:
173: if ((atomic_reqflag & CPU_REQ_RELEASE)) {
174: // 中断リクエスト受信
175: // この命令を実行し終わったら抜ける
176: atomic_reqflag &= ~CPU_REQ_RELEASE;
177: is_release = true;
178: }
179: }
180:
181: if (OpIsBusErr(opX)) {
182: // プリフェッチしていた命令がバスエラー
183: Exception(M88K_EXCEP_INST);
184: continue;
185: }
186:
187: uint32 op12 = op32_to_12(opX);
188:
189: switch (op12) {
190: #include "m88100switch.inc"
191: default:
1.1.1.2 root 192: OP_FUNC(illegal);
193: break;
1.1 root 194: }
195:
1.1.1.5 root 196: if (is_intr && IsIntrEnable()) {
1.1.1.10! root 197: // 割り込み処理要求が来ていて、
! 198: // 直前の命令が割り込みを禁止していなければ割り込み
1.1.1.5 root 199: // XXX 実際は違う気がする
200: is_intr = false;
1.1.1.7 root 201: cpulog(4, "INTR take");
1.1.1.5 root 202: ExceptionCore(M88K_EXCEP_INTERRUPT, ExceptionKind::INTR);
203: continue;
1.1 root 204: }
205:
1.1.1.5 root 206: used_cycle++;
1.1.1.2 root 207:
208: if ((atomic_reqflag & CPU_REQ_STOP)) {
209: // STOP 状態は、残りサイクルを消費したことにして戻る
1.1.1.7 root 210: cpulog(2, "STOP 状態検出");
1.1.1.6 root 211: if (used_cycle < goal_cycle) {
212: used_cycle = goal_cycle;
213: }
1.1.1.2 root 214: }
215:
1.1.1.9 root 216: // XXX 命令の実行でリリースするのに、いったんループを回って
217: // からではタイミングが遅すぎる
218: if ((atomic_reqflag & CPU_REQ_RELEASE)) {
219: // 中断リクエスト受信
220: // この命令を実行し終わったら抜ける
221: atomic_reqflag &= ~CPU_REQ_RELEASE;
222: is_release = true;
223: }
224:
1.1.1.5 root 225: if (used_cycle >= goal_cycle)
1.1 root 226: break;
227: }
228:
1.1.1.6 root 229: exit:
1.1.1.5 root 230: total_vtime += Cycle2Vtime(used_cycle);
231: used_cycle = 0;
232:
1.1.1.7 root 233: // HALT 状態がないので NORMAL か STOP かだけでいい
234: return (atomic_reqflag & CPU_REQ_STOP)
235: ? Scheduler::SCHED_CPU_STOP
236: : Scheduler::SCHED_CPU_NORMAL;
1.1.1.5 root 237: }
238:
1.1 root 239: // この命令後に実行を中断して VM に戻る
240: void
241: m88kcpu::Release()
242: {
243: atomic_reqflag |= CPU_REQ_RELEASE;
244: }
245:
1.1.1.5 root 246: // リセット例外を発行する
247: void
248: m88kcpu::RequestReset()
249: {
250: atomic_reqflag |= CPU_REQ_RESET;
251: }
252:
1.1 root 253: // 通常の例外。
1.1.1.2 root 254: // DataAccessException, エラー、割り込み、TRAP からは使わない。
1.1 root 255: // vec はベクタ番号。
256: void
257: m88kcpu::Exception(int vec)
258: {
259: ExceptionCore(vec, ExceptionKind::NORMAL);
260: }
261:
262: // 例外処理コア部分
263: // vec はベクタ番号。
264: void
265: m88kcpu::ExceptionCore(int vec, ExceptionKind cause)
266: {
1.1.1.4 root 267: uint syscall = 0;
268:
1.1.1.3 root 269: // 例外履歴に記録 (例外発生はブランチ履歴にも記録)
1.1.1.4 root 270: // OpenBSD システムコールなら番号もついでに記録。
271: // システムコール番号は tb0 発行時点で r13 にセットされている。
272: // ただし 0 番は syscall(2) (間接システムコール) で、実際の番号は r2。
273: // 198番 __syscall(2) だと r2:r3 (なので実質 r3)。
274: if (vec == 450) {
275: syscall = r[13];
276: if (syscall == 0) {
277: syscall = r[2];
278: } else if (syscall == 198) {
279: syscall = r[3];
280: }
281: syscall &= 0xfff;
282: }
1.1.1.5 root 283: uint32 from = xip | (IsSuper() ? 1 : 0);
284: uint32 inst = 0xfc000000 | (syscall << 12) | vec;
285: exhist.AddEntry(from, 0, inst);
286: brhist.AddEntry(from, 0, inst);
1.1.1.3 root 287: // デバッガに通知 (例外ブレーク用)
1.1.1.4 root 288: debugger_notify_exception(vec);
289:
290: // 命令中で起きる例外はとりあえず全部2クロック追加? (Table.7-5)
291: if (cause != ExceptionKind::INTR) {
1.1.1.5 root 292: AddCycle(2);
1.1.1.4 root 293: }
1.1.1.3 root 294:
1.1 root 295: if (psr & PSR_SFRZ) {
296: if (cause != ExceptionKind::TRAP) {
1.1.1.7 root 297: cpulog(2, "SFRZ Error Exception");
1.1 root 298: vec = M88K_EXCEP_ERROR;
299: cause = ExceptionKind::ERROR;
300: }
301: } else {
1.1.1.7 root 302: cpulog(2, "Exception %x", vec);
1.1.1.2 root 303: if (vec != 1) {
1.1.1.7 root 304: cpulog(1, "Exception %x x=%x n=%x f=%x", vec, xip, nip, fip);
1.1.1.2 root 305: }
1.1 root 306: sxip = xip;
307: snip = nip;
1.1.1.7 root 308: sfip = fip;
1.1 root 309:
310: sxip |= SIP_V;
311: snip |= SIP_V;
1.1.1.4 root 312: sfip |= SIP_V;
1.1 root 313:
314: if (OpIsBusErr(opX)) {
315: sxip |= SIP_E; // E bit
316: }
317: if (OpIsBusErr(opF)) {
318: snip |= SIP_E; // E bit
319: }
320:
321: if (vec == M88K_EXCEP_UNIMPL_OP) {
322: sxip &= ~SIP_V;
323: }
324: }
325:
1.1.1.2 root 326: if (cause != ExceptionKind::DATA) {
327: // データアクセス例外以外は、
328: // データパイプラインはフラッシュ状態とする。
329: // ほんとうは違う。かも。
330: dmt0 = 0;
331: } else {
332: // xip: ld/st/xmem
333: // nip: next
334: // fip: fetch
335:
336: // rom1.2 は DAE が起きると、
337:
338: // ROM挙動 CPU の RTE 挙動
339: // sfip = sxip
340: // sxip -> ~V (INVALID) CPU はそもそも sxip を評価しない
341: // snip = 0 (INVALID) CPU はこれを nop 相当に処理する
342: // rte
343:
344: // してくる。そのまま読むと命令を再実行しようとしているように
345: // 読めるが、再実行すると無限ループになってしまう。
346: // DAE の時点で xip が進んでいることを期待して利用している?
347:
348: // openbsd は
349: // xmem の write バスエラーを検知すると命令を再実行するために
350: // fip = nip, nip = xip して rte する。ということは xip = xmem に
351: // なっていることを期待している。
352:
353: // というわけで
354: // ld で DataAccessException のときは、実CPUはすでに次の命令を
355: // 実行している?
356: // もう少し考えると、スコアボードでレジスタの干渉がなければ、
357: // 実行している?
358:
359: // 仕方がないのでハックでごまかす。
360: // rte のほうも参照のこと。
361:
362: if (IsSuper() && xip >= 0x41000000 && xip < 0x42000000) {
363: // 遅延例外機構がないので、ROM 合わせのハック。
364: sxip = snip;
365: }
366: }
367:
1.1 root 368: epsr = psr;
1.1.1.2 root 369: SetPSR(psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ);
1.1 root 370:
371: fip = vbr + (vec << 3);
372: fetch();
1.1.1.3 root 373: // ここでベクタに飛ぶのだが、ベクタ内の2命令でおそらく必ずもう一度
374: // 分岐してそっちでも履歴が残るので、ここでブランチ履歴を残すのは
375: // ちょっと冗長という気もする。
376:
1.1 root 377: if (OpIsBusErr(opF)) {
378: if (cause == ExceptionKind::ERROR) {
379: // double bus fault
380: // 実機は無限ループ状態
381: PANIC("Infinite ERROR (double bus fault)");
382: } else {
383: ExceptionCore(M88K_EXCEP_ERROR, ExceptionKind::ERROR);
384: }
385: }
386: }
387:
1.1.1.10! root 388: inline uint32
1.1.1.5 root 389: m88kcpu::Calcdmt(uint32 flag)
390: {
391: return
392: ((psr & PSR_BO_LE) ? DM_BO : 0)
393: | ((IsSuper() && !(flag & DM_USR)) ? DM_DAS : 0)
394: | DM_VALID;
395: }
396:
1.1 root 397: // データアクセス例外(Read)
1.1.1.5 root 398: // ld.b, ld.h, ld.hu, ld 用
1.1 root 399: void
1.1.1.5 root 400: m88kcpu::ReadDataException32(uint32 addr, uint32 flag)
1.1 root 401: {
402: // ミスアラインドはこの例外より前にチェックされていて、
403: // ここにはアラインドしかこない。
404: dma0 = addr & ~0x3;
1.1.1.5 root 405: dmt0 = Calcdmt(flag)
1.1 root 406: | (FLD_D << 7)
407: | (flag & DM_SIGNED)
408: | ((flag & DM_EN_MASK) >> (addr & 0x03))
1.1.1.5 root 409: ;
410: dmt1 &= ~DM_VALID;
411: dmt2 &= ~DM_VALID;
1.1.1.7 root 412: cpulog(1, "ReadDAE xip=%x addr=%x", xip, addr);
1.1.1.2 root 413: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1 root 414: }
415:
1.1.1.5 root 416: // データアクセス例外(Read)
417: // ld.d 用
418: void
419: m88kcpu::ReadDataException64(uint32 addr, uint32 flag)
420: {
421: // ミスアラインドはこの例外より前にチェックされていて、
422: // ここにはアラインドしかこない。
423: dma0 = addr;
424: dmt0 = Calcdmt(flag)
425: | DM_DOUB1 // ダブルワードの第1アクセスのときセット
426: | (FLD_D << 7)
427: | DM_EN_MASK // 32ビット有効
428: ;
429:
430: dma1 = dma0 + 4;
431: dmt1 = Calcdmt(flag)
432: | (FLD_D2 << 7)
433: | DM_EN_MASK // 32ビット有効
434: ;
435:
436: dmt2 &= ~DM_VALID;
437:
438: if ((flag & DM_DOUB1) == 0) {
439: // .d の2ワード目がバスエラー。第1ワードのアクセスは成功した。
440: dmt0 &= ~DM_VALID;
441: }
442:
1.1.1.7 root 443: cpulog(1, "ReadDAE64 xip=%x addr=%x", xip, addr);
1.1.1.5 root 444: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
445: }
446:
1.1 root 447: // データアクセス例外(Write)
1.1.1.5 root 448: // st.b, st.h, st.hu, st 用
1.1 root 449: void
1.1.1.5 root 450: m88kcpu::WriteDataException32(uint32 addr, uint32 flag)
1.1 root 451: {
452: // ミスアラインドはこの例外より前にチェックされていて、
453: // ここにはアラインドしかこない。
454: dma0 = addr & ~0x3;
1.1.1.5 root 455: dmt0 = Calcdmt(flag)
1.1 root 456: | (FLD_D << 7)
457: | ((flag & DM_EN_MASK) >> (addr & 0x03))
458: | DM_WRITE
1.1.1.5 root 459: ;
460: dmd0 = rD;
1.1 root 461:
1.1.1.5 root 462: dmt1 &= ~DM_VALID;
463: dmt2 &= ~DM_VALID;
1.1.1.7 root 464: cpulog(1, "WriteDAE xip=%x addr=%x", xip, addr);
1.1.1.2 root 465: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
466: }
467:
1.1.1.5 root 468: // データアクセス例外(Write)
469: // st.d 用
470: void
471: m88kcpu::WriteDataException64(uint32 addr, uint32 flag)
472: {
473: // ミスアラインドはこの例外より前にチェックされていて、
474: // ここにはアラインドしかこない。
475: dma0 = addr & ~0x3;
476: dmt0 = Calcdmt(flag)
477: | DM_DOUB1 // ダブルワードの第1アクセスのときセット
478: | (FLD_D << 7)
479: | DM_EN_MASK
480: | DM_WRITE
481: ;
482: dmd0 = rD;
483:
484: dma1 = dma0 + 4;
485: dmt1 = Calcdmt(flag)
486: | (FLD_D2 << 7)
487: | DM_EN_MASK
488: | DM_WRITE
489: ;
490: dmd1 = rD2;
491:
492: dmt2 &= ~DM_VALID;
493:
494: if ((flag & DM_DOUB1) == 0) {
495: // .d の2ワード目がバスエラー。第1ワードのアクセスは成功した。
496: dmt0 &= ~DM_VALID;
497: }
498:
1.1.1.7 root 499: cpulog(1, "WriteDAE64 xip=%x addr=%x", xip, addr);
1.1.1.5 root 500: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
501: }
502:
1.1.1.2 root 503: // データアクセス例外(xmem)
1.1.1.5 root 504: // xmem には .d は無い
1.1.1.2 root 505: void
1.1.1.5 root 506: m88kcpu::XmemDataException(uint32 addr, uint32 flag)
1.1.1.2 root 507: {
508: dma0 = addr & ~0x3;
1.1.1.5 root 509: dmt0 = Calcdmt(flag)
510: | DM_LOCK // xmem でセット
1.1.1.2 root 511: | (FLD_D << 7)
512: | (flag & DM_SIGNED)
513: | ((flag & DM_EN_MASK) >> (addr & 0x03))
1.1.1.5 root 514: ;
1.1.1.2 root 515:
1.1.1.5 root 516: dma1 = dma0;
517: dmt1 = Calcdmt(flag)
518: | DM_LOCK // xmem でセット
1.1.1.2 root 519: | (FLD_D << 7)
520: | (flag & DM_SIGNED)
521: | ((flag & DM_EN_MASK) >> (addr & 0x03))
522: | DM_WRITE
1.1.1.5 root 523: ;
524: dmd1 = rD;
1.1.1.2 root 525:
1.1.1.5 root 526: dmt2 &= ~DM_VALID;
1.1.1.2 root 527:
528: // ミスアラインドはこの例外より前にチェックされていて、
529: // ここにはアラインドしかこない。
530: if (cmmu[1].fault_code != m88200::FAULT_CODE_BUSERR
531: || cmmu[1].acc_read) {
532: // アドレス変換フォルトまたは read 時点
533: // nop
1.1 root 534: } else {
1.1.1.2 root 535: // xmem の write 時点
1.1.1.5 root 536: dmt0 &= ~DM_VALID;
1.1 root 537: }
1.1.1.2 root 538:
1.1.1.7 root 539: cpulog(1, "xmemDAE xip=%x addr=%x", xip, addr);
1.1.1.2 root 540: ExceptionCore(M88K_EXCEP_DATA, ExceptionKind::DATA);
1.1 root 541: }
542:
1.1.1.10! root 543: // FPxS レジスタをセット
1.1.1.5 root 544: void
1.1.1.10! root 545: m88kcpu::SetFPxS(uint32& h, uint32& l, double src, uint32 ts)
1.1.1.5 root 546: {
1.1.1.10! root 547: // FPHS[12]、FPLS[12] は以下の構造
! 548: //
! 549: // 3 2 1 0
! 550: // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
! 551: // +-+---------------------+---------------------------------------+
! 552: // |S| Exponent(11bit) | High Order 20 bits of Mantissa | FPHSn
! 553: // +-+---------------------+---------------------------------------+
! 554: //
! 555: // +---------------------------------------------------------------+
! 556: // | Low Order bits of Mantissa, or Integer | FPLSn
! 557: // +---------------------------------------------------------------+
! 558: //
! 559: // ts が 1 (double) の場合は IEEE754 double と同じ。
! 560: // ts が 0 (single) の場合は float を double にキャスト (拡大変換) した
! 561: // ものではないことに注意。
! 562: // S(符号ビット)はそのまま。float の Mantissa (23bit) のうち上位 20bit
! 563: // を FPHSn に、残り 3bit を FPLSn の上位 3bit に。ここまではいい。
! 564: // Exponent は float の指数部(8bit、バイアス=127) の値を *そのまま*
! 565: // 符号拡張(?)する。
! 566: // (float)1.0 は 1.0 * 2^0 なのでバイアス込みの指数部は 127、
! 567: // (float)2.0 は 1.0 * 2^1 なのでバイアス込みの指数部は 128。
! 568: // バイアス込みにした値は符号なし数のはずだが、ここではこれを 11bit に
! 569: // 符号拡張して FPHSn の Exponent 部に格納するようだ。取り出す際に下位
! 570: // 8bit しか取り出さなければ害はないし、符号拡張する方がハードウェア的に
! 571: // 都合がよかったとかだろうか。
! 572: // 仮に普通に double に変換すると double の指数部バイアスは 1023 なので
! 573: // バイアス込みの指数部は先程の例だとそれぞれ 1023、1024 になるが
! 574: // これではないということ。
! 575:
! 576: union64 u;
! 577: u.q = d2u(src);
! 578: if (ts == 0) {
! 579: // single
! 580:
! 581: uint32 exp;
! 582: // src は普通の double なのでこの指数部を取り出す
! 583: uint32 double_biased = (u.h >> 20) & 0x7ff;
! 584: if (double_biased == 0x7ff) {
! 585: // Inf, NAN
! 586: exp = 0x7ff00000;
! 587: } else {
! 588: // double のバイアスを外して float のバイアスを足す
! 589: int float_biased = (double_biased - 1023) + 127;
! 590: // この 8bit 値を 11bit に符号拡張して所定の位置へ
! 591: exp = ((int32)(float_biased << 24)) >> 4;
! 592: exp &= 0x7ff00000;
! 593: }
! 594:
! 595: h = (u.h & 0x800fffff) | exp;
! 596: l = u.l;
! 597: } else {
! 598: // double
! 599: h = u.h;
! 600: l = u.l;
! 601: }
! 602: }
! 603:
! 604: // FPR[HL] レジスタに double 値をセット
! 605: // - それ以外のフィールドは保存する XXX ここでクリアしてもいいか?
! 606: // - XXX Guard, Round, Sticky (, AddOne) はまだない
! 607: void
! 608: m88kcpu::SetFPRx(double src)
! 609: {
! 610: union64 u;
! 611: uint32 exp;
! 612:
! 613: u.q = d2u(src);
! 614:
! 615: // Sign は FPRH
! 616: fprh &= ~(FPRH_SIGN | FPRH_MANT); // Mantissa もついでにクリア
! 617: fprh |= u.h & 0x80000000;
! 618:
! 619: // Exp は FPIT。
! 620: // double は 11bit だが FPIT::RESEXP は 12bit なので 1bit 符号拡張する。
! 621: // 符号付き数(正確には負数)の右シフトは実装依存だが gcc, clang は
! 622: // 算術右シフトになる。
! 623: //
! 624: // 3 2
! 625: // 1 0 9 8 7 6 5 4 3 2 1 0 9
! 626: // +-+---------------------+-
! 627: // double |S| Exponent(11bit) |
! 628: // +-+---------------------+-
! 629: //
! 630: // +---------------------+-+-
! 631: // u.h<<1 | Exponent(11bit) |X|
! 632: // +---------------------+-+-
! 633: //
! 634: // +-----------------------+-
! 635: // exp>>1 | Exponent(12bit) |
! 636: // +-----------------------+-
! 637: exp = u.h << 1;
! 638: exp = (int32)exp >> 1;
! 639: fpit &= ~FPIT_RESEXP;
! 640: fpit |= exp & FPIT_RESEXP;
! 641:
! 642: // Mantissa は FPRH, FPRL
! 643: // 上位側(FPRH)には最上位(実数桁)の隠しビットを含む。
! 644: fprh |= (u.h & 0x000fffff);
! 645: fprh |= FPRH_1;
! 646: fprl = u.l;
! 647: }
! 648:
! 649: // FP Precise 例外。浮動小数点数1つの場合。
! 650: void
! 651: m88kcpu::FPPreciseException(uint32 cause, double s2)
! 652: {
! 653: SetFPS2(s2, m88100opf_FP_T2(opX));
! 654: FPPreciseException(cause);
! 655: }
! 656:
! 657: // FP Precise 例外。浮動小数点数2つの場合。
! 658: void
! 659: m88kcpu::FPPreciseException(uint32 cause, double s1, double s2)
! 660: {
! 661: SetFPS1(s1, m88100opf_FP_T1(opX));
! 662: SetFPS2(s2, m88100opf_FP_T2(opX));
! 663: FPPreciseException(cause);
! 664: }
! 665:
! 666: // FP Precise 例外。
! 667: void
! 668: m88kcpu::FPPreciseException(uint32 cause)
! 669: {
! 670: assert(cause == FPECR_FIOV ||
! 671: cause == FPECR_FUNIMP ||
! 672: cause == FPECR_FPRV ||
! 673: cause == FPECR_FROP ||
! 674: cause == FPECR_FDVZ);
! 675:
! 676: fpecr = cause;
! 677:
! 678: // FPPT(FP Precise operation Type Register)
! 679: fppt = opX & 0xffe0; // Opcode, T1, T2, TD は opX と同じ位置
! 680: fppt |= m88100opf_D(opX); // DEST
! 681:
! 682: Exception(M88K_EXCEP_SFU1_PRECISE);
! 683: }
! 684:
! 685: // FP Imprecise 例外。
! 686: void
! 687: m88kcpu::FPImpreciseException(uint32 cause)
! 688: {
! 689: assert(cause == FPECR_FUNF ||
! 690: cause == FPECR_FOVF ||
! 691: cause == FPECR_FINX);
! 692:
! 693: fpecr = cause;
! 694:
! 695: // FPIT(FP Imprecise operation Type Register)
! 696: fpit &= FPIT_RESEXP;
! 697: fpit |= opX & FPIT_OPCODE;
! 698: fpit |= (opX & 0x00000020) << 5; // DESTSIZ
! 699: fpit |= (fpcr & 0x0000001f) << 5; // EFINV,EFDVZ,EFUNF,EFOVR,EFINX
! 700: fpit |= m88100opf_D(opX); // DEST
! 701:
! 702: // FPRH(FP Result High Register)
! 703: fprh &= ~FPRH_RNDMODE;
! 704: fprh |= (fpcr & FPCR_RM) << 14;
1.1.1.5 root 705:
1.1.1.10! root 706: Exception(M88K_EXCEP_SFU1_IMPRECISE);
1.1.1.5 root 707: }
708:
1.1 root 709: void
1.1.1.5 root 710: m88kcpu::Interrupt(int level)
1.1 root 711: {
1.1.1.5 root 712: // level は 0 か 1。
713: intr_pending = level;
1.1 root 714: atomic_reqflag |= CPU_REQ_INTR;
715: }
716:
717: void
718: m88kcpu::fpu_unimpl()
719: {
720: printf("%s\n", __func__);
1.1.1.10! root 721: FPPreciseException(FPECR_FUNIMP);
1.1 root 722: }
1.1.1.2 root 723:
724: OP_DEF(illegal)
725: {
726: // 本来は不当命令例外?
1.1.1.7 root 727: cpulog(0, "Illegal instruction %08x", (uint32)opX);
1.1.1.2 root 728: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.