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