summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/t11/t11ops.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/t11/t11ops.hxx')
-rw-r--r--src/devices/cpu/t11/t11ops.hxx245
1 files changed, 239 insertions, 6 deletions
diff --git a/src/devices/cpu/t11/t11ops.hxx b/src/devices/cpu/t11/t11ops.hxx
index 90c0a4121f3..1aeaace16dd 100644
--- a/src/devices/cpu/t11/t11ops.hxx
+++ b/src/devices/cpu/t11/t11ops.hxx
@@ -33,6 +33,7 @@
/* extracts the source/destination register index from the opcode into 'sreg' or 'dreg' */
#define GET_SREG sreg = (op >> 6) & 7
#define GET_DREG dreg = op & 7
+#define EIS_SWAP op = ((op & 7) << 6) | ((op >> 6) & 7)
/* for a byte-sized source operand: extracts 'sreg', computes 'ea', and loads the value into 'source' */
#define GET_SB_RG GET_SREG; source = REGB(sreg)
@@ -144,6 +145,11 @@
#define SETW_NZV SETW_N; SETW_Z; SETW_V
#define SETW_NZVC SETW_N; SETW_Z; SETW_V; SETW_C
+/* SIMH */
+#define GET_ZERO(v) ((v) == 0)
+#define GET_SIGN_W(v) (((v) >> 15) & 1)
+#define GET_SIGN_B(v) (((v) >> 7) & 1)
+
/* operations */
/* ADC: dst += C */
#define ADC_R(d) int dreg, source, dest, result; source = GET_C; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_DREG(result)
@@ -187,9 +193,9 @@
#define BR(c) if (c) { PC += 2 * (signed char)(op & 0xff); }
/* CLR: dst = 0 */
#define CLR_R(d) int dreg; PUT_DW_##d(0); CLR_NZVC; SET_Z
-#define CLR_M(d) int dreg, ea; PUT_DWT_##d(0); CLR_NZVC; SET_Z
+#define CLR_M(d) int dreg, ea; if (c_insn_set & (IS_T11|IS_VM1)) { PUT_DWT_##d(0); } else { PUT_DW_##d(0); } CLR_NZVC; SET_Z
#define CLRB_R(d) int dreg; PUT_DB_##d(0); CLR_NZVC; SET_Z
-#define CLRB_M(d) int dreg, ea; PUT_DBT_##d(0); CLR_NZVC; SET_Z
+#define CLRB_M(d) int dreg, ea; if (c_insn_set & (IS_T11|IS_VM1|IS_VM2)) { PUT_DBT_##d(0); } else { PUT_DB_##d(0); } CLR_NZVC; SET_Z
/* CMP: flags = src - dst */
#define CMP_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = source - dest; SETW_NZVC;
#define CMP_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = source - dest; SETW_NZVC;
@@ -216,13 +222,13 @@
#define JSR(d) int sreg, dreg, ea; GET_SREG; GET_DREG; MAKE_EAW_##d(dreg); PUSH(REGW(sreg)); REGW(sreg) = PC; PC = ea
/* MFPS: dst = flags */
#define MFPS_R(d) int dreg, result; result = PSW; CLR_NZV; SETB_NZ; PUT_DW_##d((signed char)result)
-#define MFPS_M(d) int dreg, result, ea; result = PSW; CLR_NZV; SETB_NZ; PUT_DB_##d(result)
+#define MFPS_M(d) int dreg, result, ea; result = PSW; CLR_NZV; SETB_NZ; if (c_insn_set & (IS_VM1|IS_VM2)) { PUT_DBT_##d(result); } else { PUT_DB_##d(result); }
/* MOV: dst = src */
#define MOV_R(s,d) int sreg, dreg, source, result; GET_SW_##s; CLR_NZV; result = source; SETW_NZ; PUT_DW_##d(result)
-#define MOV_M(s,d) int sreg, dreg, source, result, ea; GET_SW_##s; CLR_NZV; result = source; SETW_NZ; if (c_insn_set & IS_VM1) { PUT_DW_##d(result); } else { PUT_DWT_##d(result); }
+#define MOV_M(s,d) int sreg, dreg, source, result, ea; GET_SW_##s; CLR_NZV; result = source; SETW_NZ; if (c_insn_set & IS_T11) { PUT_DWT_##d(result); } else { PUT_DW_##d(result); }
#define MOVB_R(s,d) int sreg, dreg, source, result; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; PUT_DW_##d((signed char)result)
#define MOVB_X(s,d) int sreg, dreg, source, result, ea; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; PUT_DW_##d((signed char)result)
-#define MOVB_M(s,d) int sreg, dreg, source, result, ea; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; if (c_insn_set & IS_VM1) { PUT_DB_##d(result); } else { PUT_DBT_##d(result); }
+#define MOVB_M(s,d) int sreg, dreg, source, result, ea; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; if (c_insn_set & (IS_T11|IS_VM2)) { PUT_DBT_##d(result); } else { PUT_DB_##d(result); }
/* MTPS: flags = src */
#define MTPS_R(d) int dreg, dest; GET_DB_##d; PSW = (PSW & ~0xef) | (dest & 0xef); m_check_irqs = true
#define MTPS_M(d) int dreg, dest, ea; GET_DB_##d; PSW = (PSW & ~0xef) | (dest & 0xef); m_check_irqs = true
@@ -258,7 +264,7 @@
#define SWAB_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = ((dest >> 8) & 0xff) + (dest << 8); SETB_NZ; PUT_DW_EA(result)
/* SXT: dst = sign-extend dst */
#define SXT_R(d) int dreg, result; CLR_ZV; if (GET_N) result = -1; else { result = 0; SET_Z; } PUT_DW_##d(result)
-#define SXT_M(d) int dreg, result, ea; CLR_ZV; if (GET_N) result = -1; else { result = 0; SET_Z; } PUT_DWT_##d(result)
+#define SXT_M(d) int dreg, result, ea; CLR_ZV; if (GET_N) result = -1; else { result = 0; SET_Z; } if (c_insn_set & (IS_T11|IS_VM1)) { PUT_DWT_##d(result); } else { PUT_DW_##d(result); }
/* TST: dst = ~dst */
#define TST_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = dest; SETW_NZ;
#define TST_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = dest; SETW_NZ;
@@ -271,6 +277,191 @@
/* test if insn is supported by the CPU */
#define CHECK_IS(d) do { if (!(c_insn_set & (d))) { illegal(op); return; } } while (false)
+/* Extended Instruction Set -- SIMH impl */
+
+int t11_device::_mul(int src, int src2, int *psw) {
+ int dst;
+ int N, Z, V, C;
+
+ if (GET_SIGN_W (src2))
+ src2 = src2 | ~077777;
+ if (GET_SIGN_W (src))
+ src = src | ~077777;
+ dst = src * src2;
+ N = (dst < 0);
+ Z = GET_ZERO (dst);
+ V = 0;
+ C = ((dst > 077777) || (dst < -0100000));
+ *psw = (*psw & ~15) | ((N&1) << 3) | ((Z&1) << 2) | ((V&1) << 1) | (C&1);
+
+ return dst;
+}
+
+#define MUL_M(s) \
+int sreg, dreg, source, dest, result, ea = 0, _psw = PSW; \
+EIS_SWAP; GET_SW_##s; GET_DW_RG; \
+result = _mul(dest, source, &_psw); PSW = (PSW & ~15) | (_psw & 15); \
+PUT_DW_DREG(result >> 16); REGW(dreg|1) = result
+
+#define MUL_R(s) \
+int sreg, dreg, source, dest, result, _psw = PSW; \
+EIS_SWAP; GET_SW_##s; GET_DW_RG; \
+result = _mul(dest, source, &_psw); PSW = (PSW & ~15) | (_psw & 15); \
+PUT_DW_DREG(result >> 16); REGW(dreg|1) = result
+
+int t11_device::_div(int source, int source1, int src2, int *remainder, int *psw) {
+ int src, dst = 0;
+ int N, Z, V, C;
+
+ src = (((uint32_t) source) << 16) | source1;
+ if (src2 == 0) {
+ N = 0; /* J11,11/70 compat */
+ Z = V = C = 1; /* N = 0, Z = 1 */
+ if (c_insn_set & IS_VM2) Z = 0;
+ } else if ((((uint32_t)src) == 020000000000) && (src2 == 0177777)) {
+ V = 1; /* J11,11/70 compat */
+ N = Z = C = 0; /* N = Z = 0 */
+ } else {
+ if (GET_SIGN_W (src2))
+ src2 = src2 | ~077777;
+ if (GET_SIGN_W (source))
+ src = src | ~017777777777;
+ dst = src / src2;
+ N = (dst < 0); /* N set on 32b result */
+ if ((dst > 077777) || (dst < -0100000)) {
+ V = 1; /* J11,11/70 compat */
+ Z = C = 0; /* Z = C = 0 */
+ if (c_insn_set & IS_VM2) N = 0;
+ } else {
+ Z = GET_ZERO (dst);
+ V = C = 0;
+ }
+ *remainder = (src - (src2 * dst)) & 0177777;
+ }
+ *psw = (*psw & ~15) | ((N&1) << 3) | ((Z&1) << 2) | ((V&1) << 1) | (C&1);
+ return dst;
+}
+
+#define DIV_M(s) \
+int sreg, dreg, source, dest, result, remainder = 0, ea = 0, _psw = PSW; \
+EIS_SWAP; GET_SW_##s; GET_DW_RG; \
+result = _div(dest, REGD(dreg|1), source, &remainder, &_psw); PSW = (PSW & ~15) | (_psw & 15); \
+if (!(PSW & VFLAG)) { REGW((dreg|1)) = remainder; PUT_DW_DREG(result); }
+
+#define DIV_R(s) \
+int sreg, dreg, source, dest, result, remainder = 0, _psw = PSW; \
+EIS_SWAP; GET_SW_##s; GET_DW_RG; \
+result = _div(dest, REGD(dreg|1), source, &remainder, &_psw); PSW = (PSW & ~15) | (_psw & 15); \
+if (!(PSW & VFLAG)) { REGW((dreg|1)) = remainder; PUT_DW_DREG(result); }
+
+int t11_device::_ash(int source, int dest, int *psw) {
+ int src, src2, dst, sign, i;
+ int N, Z, V, C;
+
+ N = BIT(*psw, 3);
+ Z = BIT(*psw, 2);
+ V = BIT(*psw, 1);
+ C = BIT(*psw, 0);
+
+ src2 = dest & 077;
+ sign = GET_SIGN_W (source);
+ src = sign? source | ~077777: source;
+ if (src2 == 0) { /* [0] */
+ dst = src;
+ V = C = 0;
+ }
+ else if (src2 <= 15) { /* [1,15] */
+ dst = src << src2;
+ i = (src >> (16 - src2)) & 0177777;
+ V = (i != ((dst & 0100000)? 0177777: 0));
+ C = (i & 1);
+ }
+ else if (src2 <= 31) { /* [16,31] */
+ dst = 0;
+ V = (src != 0);
+ C = (src << (src2 - 16)) & 1;
+ }
+ else if (src2 == 32) { /* [32] = -32 */
+ dst = -sign;
+ V = 0;
+ C = sign;
+ }
+ else { /* [33,63] = -31,-1 */
+ dst = (src >> (64 - src2)) | (-sign << (src2 - 32));
+ V = 0;
+ C = ((src >> (63 - src2)) & 1);
+ }
+ N = GET_SIGN_W (dst);
+ Z = GET_ZERO (dst);
+ *psw = (*psw & ~15) | ((N&1) << 3) | ((Z&1) << 2) | ((V&1) << 1) | (C&1);
+ return dst & 0177777;
+}
+
+#define ASH_M(s) \
+int sreg, dreg, source, dest, result, _psw = PSW, ea = 0; \
+EIS_SWAP; GET_SW_##s; GET_DW_RG; \
+result = _ash(dest, source, &_psw); PSW = (PSW & ~15) | (_psw & 15); \
+PUT_DW_DREG(result)
+
+#define ASH_R(s) \
+int sreg, dreg, source, dest, result, _psw = PSW; \
+EIS_SWAP; GET_SW_##s; GET_DW_RG; \
+result = _ash(dest, source, &_psw); PSW = (PSW & ~15) | (_psw & 15); \
+PUT_DW_DREG(result)
+
+int t11_device::_ashc(int source, int source1, int dest, int *psw) {
+ int src, src2, dst, sign, i;
+ int N, Z, V, C;
+
+ N = BIT(*psw, 3);
+ Z = BIT(*psw, 2);
+ V = BIT(*psw, 1);
+ C = BIT(*psw, 0);
+
+ src2 = dest & 077;
+ sign = GET_SIGN_W (source);
+
+ src = (((uint32_t) source) << 16) | source1;
+ if (src2 == 0) { /* [0] */
+ dst = src;
+ V = C = 0;
+ }
+ else if (src2 <= 31) { /* [1,31] */
+ dst = ((uint32_t) src) << src2;
+ i = (src >> (32 - src2)) | (-sign << src2);
+ V = (i != ((dst & 020000000000)? -1: 0));
+ C = (i & 1);
+ }
+ else if (src2 == 32) { /* [32] = -32 */
+ dst = -sign;
+ V = 0;
+ C = sign;
+ }
+ else { /* [33,63] = -31,-1 */
+ dst = (src >> (64 - src2)) | (-sign << (src2 - 32));
+ V = 0;
+ C = ((src >> (63 - src2)) & 1);
+ }
+ i = (dst >> 16) & 0177777;
+ N = GET_SIGN_W (i);
+ Z = GET_ZERO (dst | i);
+ *psw = (*psw & ~15) | ((N&1) << 3) | ((Z&1) << 2) | ((V&1) << 1) | (C&1);
+ return dst;
+}
+
+#define ASHC_M(s) \
+int sreg, dreg, source, dest, result, ea = 0, _psw = PSW; \
+EIS_SWAP; GET_SW_##s; GET_DW_RG; \
+result = _ashc(dest, REGD(dreg|1), source, &_psw); PSW = (PSW & ~15) | (_psw & 15); \
+PUT_DW_DREG(result >> 16); REGW(dreg|1) = result
+
+#define ASHC_R(s) \
+int sreg, dreg, source, dest, result, _psw = PSW; \
+EIS_SWAP; GET_SW_##s; GET_DW_RG; \
+result = _ashc(dest, REGD(dreg|1), source, &_psw); PSW = (PSW & ~15) | (_psw & 15); \
+PUT_DW_DREG(result >> 16); REGW(dreg|1) = result
+
+
void t11_device::trap_to(uint16_t vector)
{
PUSH(PSW);
@@ -329,6 +520,12 @@ void t11_device::halt(uint16_t op)
m_mcir = MCIR_HALT;
m_vsel = VM1_HALT;
}
+ else if (c_insn_set & IS_VM2)
+ {
+ m_mcir = MCIR_HALT;
+ m_vsel = VM2_HALT;
+ m_check_irqs = true;
+ }
else
{
PUSH(PSW);
@@ -927,6 +1124,42 @@ void t11_device::xor_ded(uint16_t op) { CHECK_IS(IS_LEIS); m_icount -= 30;
void t11_device::xor_ix(uint16_t op) { CHECK_IS(IS_LEIS); m_icount -= 30; { XOR_M(IX); } }
void t11_device::xor_ixd(uint16_t op) { CHECK_IS(IS_LEIS); m_icount -= 36; { XOR_M(IXD); } }
+void t11_device::ash_rg(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 12; { ASH_R(RG); } } // XXX icount is fake
+void t11_device::ash_rgd(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 21; { ASH_M(RGD); } }
+void t11_device::ash_in(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 21; { ASH_M(IN); } }
+void t11_device::ash_ind(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 27; { ASH_M(IND); } }
+void t11_device::ash_de(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 24; { ASH_M(DE); } }
+void t11_device::ash_ded(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 30; { ASH_M(DED); } }
+void t11_device::ash_ix(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 30; { ASH_M(IX); } }
+void t11_device::ash_ixd(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 36; { ASH_M(IXD); } }
+
+void t11_device::ashc_rg(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 12; { ASHC_R(RG); } } // XXX icount is fake
+void t11_device::ashc_rgd(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 21; { ASHC_M(RGD); } }
+void t11_device::ashc_in(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 21; { ASHC_M(IN); } }
+void t11_device::ashc_ind(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 27; { ASHC_M(IND); } }
+void t11_device::ashc_de(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 24; { ASHC_M(DE); } }
+void t11_device::ashc_ded(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 30; { ASHC_M(DED); } }
+void t11_device::ashc_ix(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 30; { ASHC_M(IX); } }
+void t11_device::ashc_ixd(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 36; { ASHC_M(IXD); } }
+
+void t11_device::mul_rg(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 12; { MUL_R(RG); } } // XXX icount is fake
+void t11_device::mul_rgd(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 21; { MUL_M(RGD); } }
+void t11_device::mul_in(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 21; { MUL_M(IN); } }
+void t11_device::mul_ind(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 27; { MUL_M(IND); } }
+void t11_device::mul_de(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 24; { MUL_M(DE); } }
+void t11_device::mul_ded(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 30; { MUL_M(DED); } }
+void t11_device::mul_ix(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 30; { MUL_M(IX); } }
+void t11_device::mul_ixd(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 36; { MUL_M(IXD); } }
+
+void t11_device::div_rg(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 12; { DIV_R(RG); } } // XXX icount is fake
+void t11_device::div_rgd(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 21; { DIV_M(RGD); } }
+void t11_device::div_in(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 21; { DIV_M(IN); } }
+void t11_device::div_ind(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 27; { DIV_M(IND); } }
+void t11_device::div_de(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 24; { DIV_M(DE); } }
+void t11_device::div_ded(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 30; { DIV_M(DED); } }
+void t11_device::div_ix(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 30; { DIV_M(IX); } }
+void t11_device::div_ixd(uint16_t op) { CHECK_IS(IS_EIS); m_icount -= 36; { DIV_M(IXD); } }
+
void t11_device::sob(uint16_t op)
{
int sreg, source;