📄 mdmx.c
字号:
static voidSubMulAOB(signed24 *a, unsigned8 ts, unsigned8 tt){ *a -= (signed24)ts * (signed24)tt;}static voidSubMulLOB(signed24 *a, unsigned8 ts, unsigned8 tt){ *a = -((signed24)ts * (signed24)tt);}static voidAccSubAOB(signed24 *a, unsigned8 ts, unsigned8 tt){ *a += (signed24)ts - (signed24)tt;}static voidAccSubLOB(signed24 *a, unsigned8 ts, unsigned8 tt){ *a = (signed24)ts - (signed24)tt;}static voidAccAbsDiffOB(signed24 *a, unsigned8 ts, unsigned8 tt){ unsigned8 t = (ts >= tt ? ts - tt : tt - ts); *a += (signed24)t;}/* Dispatch tables for operations that update a CPR. */static const QH_ACC qh_acc[] = { AccAddAQH, AccAddAQH, AccMulAQH, AccMulLQH, SubMulAQH, SubMulLQH, AccSubAQH, AccSubLQH, NULL};static const OB_ACC ob_acc[] = { AccAddAOB, AccAddLOB, AccMulAOB, AccMulLOB, SubMulAOB, SubMulLOB, AccSubAOB, AccSubLOB, AccAbsDiffOB};static voidqh_vector_acc(signed48 a[], unsigned64 v1, unsigned64 v2, QH_ACC acc){ int i; signed16 h1, h2; for (i = 0; i < 4; i++) { h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16; h2 = (signed16)(v2 & 0xFFFF); v2 >>= 16; (*acc)(&a[i], h1, h2); }}static voidqh_map_acc(signed48 a[], unsigned64 v1, signed16 h2, QH_ACC acc){ int i; signed16 h1; for (i = 0; i < 4; i++) { h1 = (signed16)(v1 & 0xFFFF); v1 >>= 16; (*acc)(&a[i], h1, h2); }}static voidob_vector_acc(signed24 a[], unsigned64 v1, unsigned64 v2, OB_ACC acc){ int i; unsigned8 b1, b2; for (i = 0; i < 8; i++) { b1 = v1 & 0xFF; v1 >>= 8; b2 = v2 & 0xFF; v2 >>= 8; (*acc)(&a[i], b1, b2); }}static voidob_map_acc(signed24 a[], unsigned64 v1, unsigned8 b2, OB_ACC acc){ int i; unsigned8 b1; for (i = 0; i < 8; i++) { b1 = v1 & 0xFF; v1 >>= 8; (*acc)(&a[i], b1, b2); }}/* Primary entry for operations that accumulate */voidmdmx_acc_op(sim_cpu *cpu, address_word cia, int op, unsigned64 op1, int vt, MX_fmtsel fmtsel) { unsigned64 op2; switch (MX_FMT (fmtsel)) { case mdmx_qh: switch (MX_VT (fmtsel)) { case sel_elem: op2 = ValueFPR(vt, fmt_mdmx); qh_map_acc(ACC.qh, op1, QH_ELEM(op2, fmtsel), qh_acc[op]); break; case sel_vect: qh_vector_acc(ACC.qh, op1, ValueFPR(vt, fmt_mdmx), qh_acc[op]); break; case sel_imm: qh_map_acc(ACC.qh, op1, vt, qh_acc[op]); break; } break; case mdmx_ob: switch (MX_VT (fmtsel)) { case sel_elem: op2 = ValueFPR(vt, fmt_mdmx); ob_map_acc(ACC.ob, op1, OB_ELEM(op2, fmtsel), ob_acc[op]); break; case sel_vect: ob_vector_acc(ACC.ob, op1, ValueFPR(vt, fmt_mdmx), ob_acc[op]); break; case sel_imm: ob_map_acc(ACC.ob, op1, vt, ob_acc[op]); break; } break; default: Unpredictable (); }}/* Reading and writing accumulator (no conversion). */unsigned64mdmx_rac_op(sim_cpu *cpu, address_word cia, int op, int fmt) { unsigned64 result; unsigned int shift; int i; shift = op; /* L = 00, M = 01, H = 10. */ result = 0; switch (fmt) { case MX_FMT_QH: shift <<= 4; /* 16 bits per element. */ for (i = 3; i >= 0; --i) { result <<= 16; result |= ((ACC.qh[i] >> shift) & 0xFFFF); } break; case MX_FMT_OB: shift <<= 3; /* 8 bits per element. */ for (i = 7; i >= 0; --i) { result <<= 8; result |= ((ACC.ob[i] >> shift) & 0xFF); } break; default: Unpredictable (); } return result;}voidmdmx_wacl(sim_cpu *cpu, address_word cia, int fmt, unsigned64 vs, unsigned64 vt) { int i; switch (fmt) { case MX_FMT_QH: for (i = 0; i < 4; i++) { signed32 s = (signed16)(vs & 0xFFFF); ACC.qh[i] = ((signed48)s << 16) | (vt & 0xFFFF); vs >>= 16; vt >>= 16; } break; case MX_FMT_OB: for (i = 0; i < 8; i++) { signed16 s = (signed8)(vs & 0xFF); ACC.ob[i] = ((signed24)s << 8) | (vt & 0xFF); vs >>= 8; vt >>= 8; } break; default: Unpredictable (); }}voidmdmx_wach(sim_cpu *cpu, address_word cia, int fmt, unsigned64 vs){ int i; switch (fmt) { case MX_FMT_QH: for (i = 0; i < 4; i++) { signed32 s = (signed16)(vs & 0xFFFF); ACC.qh[i] &= ~((signed48)0xFFFF << 32); ACC.qh[i] |= ((signed48)s << 32); vs >>= 16; } break; case MX_FMT_OB: for (i = 0; i < 8; i++) { ACC.ob[i] &= ~((signed24)0xFF << 16); ACC.ob[i] |= ((signed24)(vs & 0xFF) << 16); vs >>= 8; } break; default: Unpredictable (); }}/* Reading and writing accumulator (rounding conversions). Enumerating function guarantees s >= 0 for QH ops. */typedef signed16 (*QH_ROUND)(signed48 a, signed16 s);#define QH_BIT(n) ((unsigned48)1 << (n))#define QH_ONES(n) (((unsigned48)1 << (n))-1)static signed16RNASQH(signed48 a, signed16 s){ signed48 t; signed16 result = 0; if (s > 48) result = 0; else { t = (a >> s); if ((a & QH_BIT(47)) == 0) { if (s > 0 && ((a >> (s-1)) & 1) == 1) t++; if (t > QH_MAX) t = QH_MAX; } else { if (s > 0 && ((a >> (s-1)) & 1) == 1) { if (s > 1 && ((unsigned48)a & QH_ONES(s-1)) != 0) t++; } if (t < QH_MIN) t = QH_MIN; } result = (signed16)t; } return result;}static signed16RNAUQH(signed48 a, signed16 s){ unsigned48 t; signed16 result; if (s > 48) result = 0; else if (s == 48) result = ((unsigned48)a & MASK48) >> 47; else { t = ((unsigned48)a & MASK48) >> s; if (s > 0 && ((a >> (s-1)) & 1) == 1) t++; if (t > 0xFFFF) t = 0xFFFF; result = (signed16)t; } return result;}static signed16RNESQH(signed48 a, signed16 s){ signed48 t; signed16 result = 0; if (s > 47) result = 0; else { t = (a >> s); if (s > 0 && ((a >> (s-1)) & 1) == 1) { if (s == 1 || (a & QH_ONES(s-1)) == 0) t += t & 1; else t += 1; } if ((a & QH_BIT(47)) == 0) { if (t > QH_MAX) t = QH_MAX; } else { if (t < QH_MIN) t = QH_MIN; } result = (signed16)t; } return result;}static signed16RNEUQH(signed48 a, signed16 s){ unsigned48 t; signed16 result; if (s > 48) result = 0; else if (s == 48) result = ((unsigned48)a > QH_BIT(47) ? 1 : 0); else { t = ((unsigned48)a & MASK48) >> s; if (s > 0 && ((a >> (s-1)) & 1) == 1) { if (s > 1 && (a & QH_ONES(s-1)) != 0) t++; else t += t & 1; } if (t > 0xFFFF) t = 0xFFFF; result = (signed16)t; } return result;}static signed16RZSQH(signed48 a, signed16 s){ signed48 t; signed16 result = 0; if (s > 47) result = 0; else { t = (a >> s); if ((a & QH_BIT(47)) == 0) { if (t > QH_MAX) t = QH_MAX; } else { if (t < QH_MIN) t = QH_MIN; } result = (signed16)t; } return result;}static signed16RZUQH(signed48 a, signed16 s){ unsigned48 t; signed16 result = 0; if (s > 48) result = 0; else if (s == 48) result = ((unsigned48)a > QH_BIT(47) ? 1 : 0); else { t = ((unsigned48)a & MASK48) >> s; if (t > 0xFFFF) t = 0xFFFF; result = (signed16)t; } return result;}typedef unsigned8 (*OB_ROUND)(signed24 a, unsigned8 s);#define OB_BIT(n) ((unsigned24)1 << (n))#define OB_ONES(n) (((unsigned24)1 << (n))-1)static unsigned8RNAUOB(signed24 a, unsigned8 s){ unsigned8 result; unsigned24 t; if (s > 24) result = 0; else if (s == 24) result = ((unsigned24)a & MASK24) >> 23; else { t = ((unsigned24)a & MASK24) >> s; if (s > 0 && ((a >> (s-1)) & 1) == 1) t ++; result = OB_CLAMP(t); } return result;}static unsigned8RNEUOB(signed24 a, unsigned8 s){ unsigned8 result; unsigned24 t; if (s > 24) result = 0; else if (s == 24) result = (((unsigned24)a & MASK24) > OB_BIT(23) ? 1 : 0); else { t = ((unsigned24)a & MASK24) >> s; if (s > 0 && ((a >> (s-1)) & 1) == 1) { if (s > 1 && (a & OB_ONES(s-1)) != 0) t++; else t += t & 1; } result = OB_CLAMP(t); } return result;}static unsigned8RZUOB(signed24 a, unsigned8 s){ unsigned8 result; unsigned24 t; if (s >= 24) result = 0; else { t = ((unsigned24)a & MASK24) >> s; result = OB_CLAMP(t); } return result;}static const QH_ROUND qh_round[] = { RNASQH, RNAUQH, RNESQH, RNEUQH, RZSQH, RZUQH};static const OB_ROUND ob_round[] = { NULL, RNAUOB, NULL, RNEUOB, NULL, RZUOB};static unsigned64qh_vector_round(sim_cpu *cpu, address_word cia, unsigned64 v2, QH_ROUND round){ unsigned64 result = 0; int i, s; signed16 h, h2; s = 0; for (i = 0; i < 4; i++) { h2 = (signed16)(v2 & 0xFFFF); if (h2 >= 0) h = (*round)(ACC.qh[i], h2); else { UnpredictableResult (); h = 0xdead; } v2 >>= 16; result |= ((unsigned64)((unsigned16)h) << s); s += 16; } return result;}static unsigned64qh_map_round(sim_cpu *cpu, address_word cia, signed16 h2, QH_ROUND round){ unsigned64 result = 0; int i, s; signed16 h; s = 0; for (i = 0; i < 4; i++) { if (h2 >= 0) h = (*round)(ACC.qh[i], h2); else { UnpredictableResult (); h = 0xdead; } result |= ((unsigned64)((unsigned16)h) << s); s += 16; } return result;}static unsigned64ob_vector_round(sim_cpu *cpu, address_word cia, unsigned64 v2, OB_ROUND round){ unsigned64 result = 0; int i, s; unsigned8 b, b2; s = 0; for (i = 0; i < 8; i++) { b2 = v2 & 0xFF; v2 >>= 8; b = (*round)(ACC.ob[i], b2); result |= ((unsigned64)b << s); s += 8; } return result;}static unsigned64ob_map_round(sim_cpu *cpu, address_word cia, unsigned8 b2, OB_ROUND round){ unsigned64 result = 0; int i, s; unsigned8 b; s = 0; for (i = 0; i < 8; i++) { b = (*round)(ACC.ob[i], b2); result |= ((unsigned64)b << s); s += 8; } return result;}unsigned64mdmx_round_op(sim_cpu *cpu, address_word cia, int rm, int vt, MX_fmtsel fmtsel) { unsigned64 op2; unsigned64 result = 0; switch (MX_FMT (fmtsel)) { case mdmx_qh: switch (MX_VT (fmtsel)) { case sel_elem: op2 = ValueFPR(vt, fmt_mdmx); result = qh_map_round(cpu, cia, QH_ELEM(op2, fmtsel), qh_round[rm]); break; case sel_vect: op2 = ValueFPR(vt, fmt_mdmx); result = qh_vector_round(cpu, cia, op2, qh_round[rm]); break; case sel_imm: result = qh_map_round(cpu, cia, vt, qh_round[rm]); break; } break; case mdmx_ob: switch (MX_VT (fmtsel)) { case sel_elem: op2 = ValueFPR(vt, fmt_mdmx); result = ob_map_round(cpu, cia, OB_ELEM(op2, fmtsel), ob_round[rm]); break; case sel_vect: op2 = ValueFPR(vt, fmt_mdmx); result = ob_vector_round(cpu, cia, op2, ob_round[rm]); break; case sel_imm: result = ob_map_round(cpu, cia, vt, ob_round[rm]); break; } break; default: Unpredictable (); } return result;}/* Shuffle operation. */typedef struct { enum {vs, ss, vt} source; unsigned int index;} sh_map;static const sh_map ob_shuffle[][8] = { /* MDMX 2.0 encodings (3-4, 6-7). */ /* vr5400 encoding (5), otherwise. */ { }, /* RSVD */ {{vt,4}, {vs,4}, {vt,5}, {vs,5}, {vt,6}, {vs,6}, {vt,7}, {vs,7}}, /* RSVD */ {{vt,0}, {vs,0}, {vt,1}, {vs,1}, {vt,2}, {vs,2}, {vt,3}, {vs,3}}, /* RSVD */ {{vs,0}, {ss,0}, {vs,1}, {ss,1}, {vs,2}, {ss,2}, {vs,3}, {ss,3}}, /* upsl */ {{vt,1}, {vt,3}, {vt,5}, {vt,7}, {vs,1}, {vs,3}, {vs,5}, {vs,7}}, /* pach */ {{vt,0}, {vt,2}, {vt,4}, {vt,6}, {vs,0}, {vs,2}, {vs,4}, {vs,6}}, /* pacl */ {{vt,4}, {vs,4}, {vt,5}, {vs,5}, {vt,6}, {vs,6}, {vt,7}, {vs,7}}, /* mixh */ {{vt,0}, {vs,0}, {vt,1}, {vs,1}, {vt,2}, {vs,2}, {vt,3}, {vs,3}} /* mixl */};static const sh_map qh_shuffle[][4] = { {{vt,2}, {vs,2}, {vt,3}, {vs,3}}, /* mixh */ {{vt,0}, {vs,0}, {vt,1}, {vs,1}}, /* mixl */ {{vt,1}, {vt,3}, {vs,1}, {vs,3}}, /* pach */ { }, /* RSVD */ {{vt,1}, {vs,0}, {vt,3}, {vs,2}}, /* bfla */ { }, /* RSVD */ {{vt,2}, {vt,3}, {vs,2}, {vs,3}}, /* repa */ {{vt,0}, {vt,1}, {vs,0}, {vs,1}} /* repb */};unsigned64mdmx_shuffle(sim_cpu *cpu, address_word cia, int shop, unsigned64 op1, unsigned64 op2){ unsigned64 result = 0; int i, s; int op; if ((shop & 0x3) == 0x1) /* QH format. */ { op = shop >> 2; s = 0; for (i = 0; i < 4; i++) { unsigned64 v; switch (qh_shuffle[op][i].source) { case vs: v = op1; break; case vt: v = op2; break; default: Unpredictable (); v = 0; } result |= (((v >> 16*qh_shuffle[op][i].index) & 0xFFFF) << s); s += 16; } } else if ((shop & 0x1) == 0x0) /* OB format. */ { op = shop >> 1; s = 0; for (i = 0; i < 8; i++) { unsigned8 b; unsigned int ishift = 8*ob_shuffle[op][i].index; switch (ob_shuffle[op][i].source) { case vs: b = (op1 >> ishift) & 0xFF; break; case ss: b = ((op1 >> ishift) & 0x80) ? 0xFF : 0; break; case vt: b = (op2 >> ishift) & 0xFF; break; default: Unpredictable (); b = 0; } result |= ((unsigned64)b << s); s += 8; } } else Unpredictable (); return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -