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