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