|
|
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.18! root 103: ev->time = cycle * clock_tsec + 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.18! root 175: last_vector = vec;
1.1.1.15 root 176: excep_counter[vec]++;
1.1.1.17 root 177: if (vec == 450 || vec == 128) {
1.1.1.13 root 178: syscall = reg.r[13];
1.1.1.4 root 179: if (syscall == 0) {
1.1.1.13 root 180: syscall = reg.r[2];
1.1.1.4 root 181: } else if (syscall == 198) {
1.1.1.13 root 182: syscall = reg.r[3];
1.1.1.4 root 183: }
184: syscall &= 0xfff;
185: }
1.1.1.13 root 186: uint32 from = reg.xip | (IsSuper() ? 1 : 0);
1.1.1.16 root 187: uint32 info = 0xfc000000 | (syscall << 12) | vec;
188: exhist.AddEntry(from, 0, info);
189: brhist.AddEntry(from, 0, info);
1.1.1.4 root 190:
1.1.1.13 root 191: if ((reg.psr & PSR_SFRZ)) {
1.1.1.17 root 192: if (pri != EXCPRI_TRAP) {
193: putlog(0, "Exception (primask=$%x) during SFRZ!", primask);
194:
195: // エラー例外でもう一度報告。
196: // BranchHistory に繰り返しと判定されないよう to を変えておく。
197: pri = EXCPRI_ERROR;
198: vec = EXCVEC_ERROR;
1.1.1.18! root 199: last_vector = vec;
1.1.1.17 root 200: info = 0xfc000000 | vec;
201: exhist.AddEntry(from, 1, info);
202: brhist.AddEntry(from, 1, info);
203: } else {
204: putlog(0, "Trap during Exception");
1.1 root 205: }
206: } else {
1.1.1.17 root 207: if (vec == EXCVEC_INTERRUPT) {
208: putlog(2, "Exception (Interrupt)");
209: } else {
1.1.1.13 root 210: putlog(1, "Exception %x x=%x n=%x f=%x",
211: vec, reg.xip, reg.nip, reg.fip);
1.1.1.2 root 212: }
1.1.1.13 root 213: reg.sxip = reg.xip;
214: reg.snip = reg.nip;
215: reg.sfip = reg.fip;
216:
1.1.1.17 root 217: if (pri != EXCPRI_UNIMPL_OP) {
218: reg.sxip |= SIP_V;
219: }
1.1.1.13 root 220: reg.snip |= SIP_V;
221: reg.sfip |= SIP_V;
1.1 root 222:
1.1.1.13 root 223: if (OpIsBusErr(reg.opX)) {
1.1.1.17 root 224: reg.sxip |= SIP_E;
1.1 root 225: }
1.1.1.13 root 226: if (OpIsBusErr(reg.opF)) {
1.1.1.17 root 227: reg.snip |= SIP_E;
1.1 root 228: }
229: }
230:
1.1.1.17 root 231: if ((primask & EXCPRI_DATA)) {
232: // パイプラインが未実装なので、PROM の DAE ハンドラが無限ループに
233: // なるのをごまかすハックは vm/prom.cpp 参照。
1.1.1.2 root 234: } else {
1.1.1.17 root 235: // データアクセス例外でなければ DMT の V ビットはクリア。(Table.6-3)
236: reg.dmt0 &= ~DM_VALID;
237: reg.dmt1 &= ~DM_VALID;
238: reg.dmt2 &= ~DM_VALID;
1.1.1.2 root 239: }
240:
1.1.1.17 root 241: // XXX Figure 6-3 のフローだとトラップ例外の時は EPSR を保存しない
242: // ようだが本当だろうか。本文はトラップ例外の記載が少ない。
1.1.1.13 root 243: reg.epsr = reg.psr;
244: SetPSR(reg.psr | PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ);
1.1 root 245:
1.1.1.13 root 246: reg.fip = reg.vbr + (vec << 3);
1.1 root 247: fetch();
1.1.1.3 root 248: // ここでベクタに飛ぶのだが、ベクタ内の2命令でおそらく必ずもう一度
249: // 分岐してそっちでも履歴が残るので、ここでブランチ履歴を残すのは
250: // ちょっと冗長という気もする。
251:
1.1.1.13 root 252: if (OpIsBusErr(reg.opF)) {
1.1.1.17 root 253: if (pri == EXCPRI_ERROR) {
1.1 root 254: // double bus fault
255: // 実機は無限ループ状態
256: PANIC("Infinite ERROR (double bus fault)");
257: } else {
1.1.1.17 root 258: putlog(0, "Bus error on fetching $%08x (vector $%x)!",
259: reg.vbr + (vec << 3), vec);
260: Exception(EXCPRI_ERROR);
1.1 root 261: }
262: }
263: }
264:
1.1.1.17 root 265: // EXCPRI_* の内部例外発生を予約する。
266: // 例外はこの場で処理するのではなく、命令境界で優先度の高い方から処理される
267: // ので、発生時に出来るのは予約することだけ。
268: void
269: MPU88xx0Device::Exception(uint32 pri)
270: {
271: excep_pending |= pri;
272: }
273:
274: // 外部優先度の例外の発生を予約する。
275: void
276: MPU88xx0Device::OuterException(uint32 pri)
277: {
278: excep_pending |= pri;
279: excep_pending |= EXCPRI_OUTER;
280: }
281:
282: // 内部例外の発生を予約する。
283: // vec は発生させる例外のベクタ番号。
284: void
285: MPU88xx0Device::InternalException(uint32 vec)
286: {
287: excep_vector = vec;
288: Exception(EXCPRI_INTERNAL);
289: }
290:
291: // トラップ例外の発生を予約する。
292: // vec は発生させる例外のベクタ番号。
293: void
294: MPU88xx0Device::TrapException(uint32 vec)
295: {
296: excep_vector = vec;
297: Exception(EXCPRI_TRAP);
298: }
299:
300: // flag から DMT の共通部分を作って返す。
301: uint32
302: MPU88xx0Device::MakeDMT(uint32 flag)
1.1.1.5 root 303: {
1.1.1.13 root 304: uint32 dmt;
305:
306: dmt = DM_VALID;
307: if ((reg.psr & PSR_BO_LE))
308: dmt |= DM_BO;
309: if (IsSuper() && !(flag & DM_USR))
310: dmt |= DM_DAS;
311:
312: return dmt;
1.1.1.5 root 313: }
314:
1.1.1.17 root 315: // データアクセス例外(Read)、ld.[b,h,(w)] 用。
1.1 root 316: void
1.1.1.13 root 317: MPU88xx0Device::ReadDataException32(uint32 addr, uint32 flag)
1.1 root 318: {
319: // ミスアラインドはこの例外より前にチェックされていて、
1.1.1.17 root 320: // ここには (アクセスサイズでの) アラインドしかこない。
321:
322: reg.dmt0 = MakeDMT(flag);
1.1.1.13 root 323: reg.dmt0 |= FLD_D << 7;
324: reg.dmt0 |= flag & DM_SIGNED;
325: reg.dmt0 |= (flag & DM_EN_MASK) >> (addr & 0x03);
1.1.1.17 root 326: reg.dma0 = addr & ~0x3;
1.1.1.13 root 327:
328: reg.dmt1 &= ~DM_VALID;
329: reg.dmt2 &= ~DM_VALID;
1.1.1.17 root 330:
1.1.1.13 root 331: putlog(1, "ReadDAE xip=%x addr=%x", reg.xip, addr);
1.1.1.17 root 332: OuterException(EXCPRI_DATA);
1.1 root 333: }
334:
1.1.1.17 root 335: // データアクセス例外(Read)、ld.d 用。
336: // どちらのワードで例外が起きても first_addr は第1ワードのアドレス。
1.1.1.5 root 337: void
1.1.1.17 root 338: MPU88xx0Device::ReadDataException64(uint32 first_addr, uint32 flag)
1.1.1.5 root 339: {
340: // ミスアラインドはこの例外より前にチェックされていて、
341: // ここにはアラインドしかこない。
1.1.1.13 root 342:
1.1.1.17 root 343: uint32 dmt_2nd;
344: uint32 dma_2nd;
1.1.1.5 root 345:
1.1.1.17 root 346: reg.dmt1 &= ~DM_VALID;
1.1.1.13 root 347: reg.dmt2 &= ~DM_VALID;
1.1.1.5 root 348:
1.1.1.17 root 349: // 先に2ワード目の情報を作っておく。
350: dmt_2nd = MakeDMT(flag);
351: dmt_2nd |= FLD_D2 << 7;
352: dmt_2nd |= DM_EN_MASK; // 32ビット有効
353: dma_2nd = first_addr + 4;
354:
355: uint32 doub1 = (flag & DM_DOUB1);
356: if (doub1) {
357: // 1ワード目がバスエラーなら、DMx0 と DMx1 を使う。
358: reg.dmt0 = MakeDMT(flag);
359: reg.dmt0 |= doub1;
360: reg.dmt0 |= FLD_D << 7;
361: reg.dmt0 |= DM_EN_MASK; // 32ビット有効
362: reg.dma0 = first_addr;
363:
364: reg.dmt1 = dmt_2nd;
365: reg.dma1 = dma_2nd;
366: } else {
367: // 2ワード目がバスエラーなら、DMx0 に2ワード目の情報だけ。
368: reg.dmt0 = dmt_2nd;
369: reg.dma0 = dma_2nd;
1.1.1.5 root 370: }
371:
1.1.1.17 root 372: putlog(1, "ReadDAE64 xip=%x addr=%x", reg.xip, reg.dma0);
373: OuterException(EXCPRI_DATA);
1.1.1.5 root 374: }
375:
1.1.1.17 root 376: // データアクセス例外(Write)、st.[b,h,(w)] 用。
1.1 root 377: void
1.1.1.13 root 378: MPU88xx0Device::WriteDataException32(uint32 addr, uint32 flag)
1.1 root 379: {
380: // ミスアラインドはこの例外より前にチェックされていて、
1.1.1.17 root 381: // ここには (アクセスサイズでの) アラインドしかこない。
382:
383: reg.dmt0 = MakeDMT(flag);
1.1.1.13 root 384: reg.dmt0 |= (flag & DM_EN_MASK) >> (addr & 0x03);
385: reg.dmt0 |= DM_WRITE;
1.1.1.17 root 386: reg.dma0 = addr & ~0x3;
1.1.1.13 root 387: reg.dmd0 = rD;
388:
389: reg.dmt1 &= ~DM_VALID;
390: reg.dmt2 &= ~DM_VALID;
1.1.1.17 root 391:
1.1.1.13 root 392: putlog(1, "WriteDAE xip=%x addr=%x", reg.xip, addr);
1.1.1.17 root 393: OuterException(EXCPRI_DATA);
1.1.1.2 root 394: }
395:
1.1.1.17 root 396: // データアクセス例外(Write)、st.d 用。
397: // どちらのワードで例外が起きても first_addr は第1ワードのアドレス。
1.1.1.5 root 398: void
1.1.1.17 root 399: MPU88xx0Device::WriteDataException64(uint32 first_addr, uint32 flag)
1.1.1.5 root 400: {
401: // ミスアラインドはこの例外より前にチェックされていて、
402: // ここにはアラインドしかこない。
1.1.1.13 root 403:
1.1.1.17 root 404: uint32 dmt_2nd;
405: uint32 dma_2nd;
406: uint32 dmd_2nd;
1.1.1.5 root 407:
1.1.1.17 root 408: reg.dmt1 &= ~DM_VALID;
1.1.1.13 root 409: reg.dmt2 &= ~DM_VALID;
1.1.1.5 root 410:
1.1.1.17 root 411: // 先に2ワード目の情報を作っておく。
412: dmt_2nd = MakeDMT(flag);
413: dmt_2nd |= DM_EN_MASK;
414: dmt_2nd |= DM_WRITE;
415: dma_2nd = first_addr + 4;
416: dmd_2nd = rD2;
417:
418: uint32 doub1 = (flag & DM_DOUB1);
419: if (doub1) {
420: // 1ワード目がバスエラーなら、DMx0 と DMx1 を使う。
421: reg.dmt0 = MakeDMT(flag);
422: reg.dmt0 |= DM_DOUB1; // ダブルワードの第1アクセスのときセット
423: reg.dmt0 |= DM_EN_MASK;
424: reg.dmt0 |= DM_WRITE;
425: reg.dma0 = first_addr;
426: reg.dmd0 = rD;
427:
428: reg.dmt1 = dmt_2nd;
429: reg.dma1 = dma_2nd;
430: reg.dmd1 = dmd_2nd;
431: } else {
432: // 2ワード目がバスエラーなら、DMx0 に2ワード目の情報だけ。
433: reg.dmt0 = dmt_2nd;
434: reg.dma0 = dma_2nd;
435: reg.dmd0 = dmd_2nd;
1.1.1.5 root 436: }
437:
1.1.1.17 root 438: putlog(1, "WriteDAE64 xip=%x addr=%x", reg.xip, reg.dma0);
439: OuterException(EXCPRI_DATA);
1.1.1.5 root 440: }
441:
1.1.1.2 root 442: // データアクセス例外(xmem)
1.1.1.17 root 443: // xmem は .bu と (.w) しかない。
1.1.1.2 root 444: void
1.1.1.13 root 445: MPU88xx0Device::XmemDataException(uint32 addr, uint32 flag)
1.1.1.2 root 446: {
1.1.1.17 root 447: // ミスアラインドはこの例外より前にチェックされていて、
448: // ここには (アクセスサイズでの) アラインドしかこない。
1.1.1.13 root 449:
1.1.1.17 root 450: uint32 dmt_rd;
451: uint32 dmt_wr;
452: uint32 dma;
453: uint32 dmd_wr;
1.1.1.2 root 454:
1.1.1.17 root 455: reg.dmt1 &= ~DM_VALID;
1.1.1.13 root 456: reg.dmt2 &= ~DM_VALID;
1.1.1.2 root 457:
1.1.1.17 root 458: dmt_rd = MakeDMT(flag);
459: dmt_rd |= DM_LOCK;
460: dmt_rd |= FLD_D << 7;
461: dmt_rd |= flag & DM_SIGNED;
462: dmt_rd |= (flag & DM_EN_MASK) >> (addr & 0x03);
463: dma = addr & ~0x3U;
464:
465: dmt_wr = dmt_rd | DM_WRITE;
466: dmd_wr = rD;
467:
1.1.1.13 root 468: if (cmmu[1]->fault_code != m88200::FAULT_CODE_BUSERR
469: || cmmu[1]->acc_read) {
1.1.1.17 root 470: // アドレス変換フォルトまたは read 時点のバスエラー。
471: reg.dmt0 = dmt_rd;
472: reg.dma0 = dma;
473:
474: reg.dmt1 = dmt_wr;
475: reg.dma1 = dma;
476: reg.dmd1 = dmd_wr;
1.1 root 477: } else {
1.1.1.17 root 478: // xmem の write 時点のバスエラー。
479: reg.dmt0 = dmt_wr;
480: reg.dma0 = dma;
481: reg.dmd0 = dmd_wr;
1.1 root 482: }
1.1.1.2 root 483:
1.1.1.13 root 484: putlog(1, "xmemDAE xip=%x addr=%x", reg.xip, addr);
1.1.1.17 root 485: OuterException(EXCPRI_DATA);
1.1 root 486: }
487:
1.1.1.10 root 488: // FPxS レジスタをセット
1.1.1.13 root 489: /*static*/ void
1.1.1.15 root 490: MPU88xx0Device::SetFPxS(uint32 *h, uint32 *l, double src, uint32 ts)
1.1.1.5 root 491: {
1.1.1.10 root 492: // FPHS[12]、FPLS[12] は以下の構造
493: //
494: // 3 2 1 0
495: // 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
496: // +-+---------------------+---------------------------------------+
497: // |S| Exponent(11bit) | High Order 20 bits of Mantissa | FPHSn
498: // +-+---------------------+---------------------------------------+
499: //
500: // +---------------------------------------------------------------+
501: // | Low Order bits of Mantissa, or Integer | FPLSn
502: // +---------------------------------------------------------------+
503: //
504: // ts が 1 (double) の場合は IEEE754 double と同じ。
505: // ts が 0 (single) の場合は float を double にキャスト (拡大変換) した
506: // ものではないことに注意。
507: // S(符号ビット)はそのまま。float の Mantissa (23bit) のうち上位 20bit
508: // を FPHSn に、残り 3bit を FPLSn の上位 3bit に。ここまではいい。
509: // Exponent は float の指数部(8bit、バイアス=127) の値を *そのまま*
510: // 符号拡張(?)する。
511: // (float)1.0 は 1.0 * 2^0 なのでバイアス込みの指数部は 127、
512: // (float)2.0 は 1.0 * 2^1 なのでバイアス込みの指数部は 128。
513: // バイアス込みにした値は符号なし数のはずだが、ここではこれを 11bit に
514: // 符号拡張して FPHSn の Exponent 部に格納するようだ。取り出す際に下位
515: // 8bit しか取り出さなければ害はないし、符号拡張する方がハードウェア的に
516: // 都合がよかったとかだろうか。
517: // 仮に普通に double に変換すると double の指数部バイアスは 1023 なので
518: // バイアス込みの指数部は先程の例だとそれぞれ 1023、1024 になるが
519: // これではないということ。
520:
521: union64 u;
522: u.q = d2u(src);
523: if (ts == 0) {
524: // single
525:
526: uint32 exp;
527: // src は普通の double なのでこの指数部を取り出す
528: uint32 double_biased = (u.h >> 20) & 0x7ff;
1.1.1.17 root 529: if (double_biased == 0) {
530: // Zero
531: exp = 0;
532: } else if (double_biased == 0x7ff) {
1.1.1.10 root 533: // Inf, NAN
534: exp = 0x7ff00000;
535: } else {
536: // double のバイアスを外して float のバイアスを足す
537: int float_biased = (double_biased - 1023) + 127;
538: // この 8bit 値を 11bit に符号拡張して所定の位置へ
539: exp = ((int32)(float_biased << 24)) >> 4;
1.1.1.17 root 540: exp &= ~0x80000000;
1.1.1.10 root 541: }
542:
1.1.1.15 root 543: *h = (u.h & 0x800fffff) | exp;
544: *l = u.l;
1.1.1.10 root 545: } else {
546: // double
1.1.1.15 root 547: *h = u.h;
548: *l = u.l;
1.1.1.10 root 549: }
550: }
551:
1.1.1.13 root 552: // FPxS1 レジスタをセット
553: void
554: MPU88xx0Device::SetFPS1(double src, uint32 t1)
555: {
1.1.1.15 root 556: SetFPxS(®.fphs1, ®.fpls1, src, t1);
1.1.1.13 root 557: }
558:
559: // FPxS2 レジスタをセット
560: void
561: MPU88xx0Device::SetFPS2(double src, uint32 t2)
562: {
1.1.1.15 root 563: SetFPxS(®.fphs2, ®.fpls2, src, t2);
1.1.1.13 root 564: }
565:
566: void
567: MPU88xx0Device::SetFPS1(uint32 src)
568: {
569: reg.fpls1 = src;
570: }
571:
572: void
573: MPU88xx0Device::SetFPS2(uint32 src)
574: {
575: reg.fpls2 = src;
576: }
577:
1.1.1.10 root 578: // FPR[HL] レジスタに double 値をセット
579: // - それ以外のフィールドは保存する XXX ここでクリアしてもいいか?
580: // - XXX Guard, Round, Sticky (, AddOne) はまだない
581: void
1.1.1.13 root 582: MPU88xx0Device::SetFPRx(double src)
1.1.1.10 root 583: {
584: union64 u;
585: uint32 exp;
586:
587: u.q = d2u(src);
588:
589: // Sign は FPRH
1.1.1.13 root 590: reg.fprh &= ~(FPRH_SIGN | FPRH_MANT); // Mantissa もついでにクリア
591: reg.fprh |= u.h & 0x80000000;
1.1.1.10 root 592:
593: // Exp は FPIT。
594: // double は 11bit だが FPIT::RESEXP は 12bit なので 1bit 符号拡張する。
595: // 符号付き数(正確には負数)の右シフトは実装依存だが gcc, clang は
596: // 算術右シフトになる。
597: //
598: // 3 2
599: // 1 0 9 8 7 6 5 4 3 2 1 0 9
600: // +-+---------------------+-
601: // double |S| Exponent(11bit) |
602: // +-+---------------------+-
603: //
604: // +---------------------+-+-
605: // u.h<<1 | Exponent(11bit) |X|
606: // +---------------------+-+-
607: //
608: // +-----------------------+-
609: // exp>>1 | Exponent(12bit) |
610: // +-----------------------+-
611: exp = u.h << 1;
612: exp = (int32)exp >> 1;
1.1.1.13 root 613: reg.fpit &= ~FPIT_RESEXP;
614: reg.fpit |= exp & FPIT_RESEXP;
1.1.1.10 root 615:
616: // Mantissa は FPRH, FPRL
617: // 上位側(FPRH)には最上位(実数桁)の隠しビットを含む。
1.1.1.13 root 618: reg.fprh |= (u.h & 0x000fffff);
619: reg.fprh |= FPRH_1;
620: reg.fprl = u.l;
1.1.1.10 root 621: }
622:
623: // FP Precise 例外。浮動小数点数1つの場合。
624: void
1.1.1.13 root 625: MPU88xx0Device::FPPreciseException(uint32 cause, double s2)
1.1.1.10 root 626: {
1.1.1.13 root 627: SetFPS2(s2, m88100opf_FP_T2(reg.opX));
1.1.1.10 root 628: FPPreciseException(cause);
629: }
630:
631: // FP Precise 例外。浮動小数点数2つの場合。
632: void
1.1.1.13 root 633: MPU88xx0Device::FPPreciseException(uint32 cause, double s1, double s2)
1.1.1.10 root 634: {
1.1.1.13 root 635: SetFPS1(s1, m88100opf_FP_T1(reg.opX));
636: SetFPS2(s2, m88100opf_FP_T2(reg.opX));
1.1.1.10 root 637: FPPreciseException(cause);
638: }
639:
640: // FP Precise 例外。
641: void
1.1.1.13 root 642: MPU88xx0Device::FPPreciseException(uint32 cause)
1.1.1.10 root 643: {
644: assert(cause == FPECR_FIOV ||
645: cause == FPECR_FUNIMP ||
646: cause == FPECR_FPRV ||
647: cause == FPECR_FROP ||
648: cause == FPECR_FDVZ);
649:
1.1.1.13 root 650: reg.fpecr = cause;
1.1.1.10 root 651:
652: // FPPT(FP Precise operation Type Register)
1.1.1.13 root 653: reg.fppt = reg.opX & 0xffe0; // Opcode, T1, T2, TD は opX と同じ位置
654: reg.fppt |= m88100opf_D(reg.opX); // DEST
1.1.1.10 root 655:
1.1.1.17 root 656: InternalException(EXCVEC_SFU1_PRECISE);
1.1.1.10 root 657: }
658:
659: // FP Imprecise 例外。
660: void
1.1.1.13 root 661: MPU88xx0Device::FPImpreciseException(uint32 cause)
1.1.1.10 root 662: {
663: assert(cause == FPECR_FUNF ||
664: cause == FPECR_FOVF ||
665: cause == FPECR_FINX);
666:
1.1.1.13 root 667: reg.fpecr = cause;
1.1.1.10 root 668:
669: // FPIT(FP Imprecise operation Type Register)
1.1.1.13 root 670: reg.fpit &= FPIT_RESEXP;
671: reg.fpit |= reg.opX & FPIT_OPCODE;
672: reg.fpit |= (reg.opX & 0x00000020) << 5; // DESTSIZ
673: reg.fpit |= (reg.fpcr & 0x0000001f) << 5; // EFINV,EFDVZ,EFUNF,EFOVR,EFINX
674: reg.fpit |= m88100opf_D(reg.opX); // DEST
1.1.1.10 root 675:
676: // FPRH(FP Result High Register)
1.1.1.13 root 677: reg.fprh &= ~FPRH_RNDMODE;
678: reg.fprh |= (reg.fpcr & FPCR_RM) << 14;
1.1.1.11 root 679:
1.1.1.17 root 680: OuterException(EXCPRI_SFU_IMPRECISE);
1.1 root 681: }
1.1.1.2 root 682:
683: OP_DEF(illegal)
684: {
1.1.1.17 root 685: // 不当命令例外。
1.1.1.13 root 686: putlog(0, "Illegal instruction %08x", (uint32)reg.opX);
1.1.1.17 root 687: Exception(EXCPRI_UNIMPL_OP);
1.1.1.2 root 688: }
1.1.1.11 root 689:
1.1.1.13 root 690: //
691: // m88100reg の static 変数
692: //
693:
694: // fcr のマスク
695: /*static*/ const uint32 m88100reg::fcr_mask[11] = {
696: M88100::FPECR_MASK,
697: 0xffffffff, // fphs1
698: 0xffffffff, // fpls1
699: 0xffffffff, // fphs2
700: 0xffffffff, // fpls2
701: M88100::FPPT_MASK,
702: M88100::FPRH_MASK,
703: 0xffffffff, // fprl
704: M88100::FPIT_MASK,
705: M88100::FPSR_MASK,
706: M88100::FPCR_MASK,
707: };
708:
709: /*static*/ const char * const m88100reg::sipname[3] = {
710: "sxip", "snip", "sfip",
711: };
712:
713: /*static*/ const char * const m88100reg::dmt_en_str[16] = {
714: "----",
715: "---B",
716: "--B-",
717: "--HH",
718: "-B--",
719: "-1-1", // not used normally
720: "-11-", // not used normally
721: "-111", // not used normally
722: "B---",
723: "1--1", // not used normally
724: "1-1-", // not used normally
725: "1-11", // not used normally
726: "HH--",
727: "11-1", // not used normally
728: "111-", // not used normally
729: "LLLL",
730: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.