summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/v60/op7a.inc
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/v60/op7a.inc')
-rw-r--r--src/devices/cpu/v60/op7a.inc1212
1 files changed, 1212 insertions, 0 deletions
diff --git a/src/devices/cpu/v60/op7a.inc b/src/devices/cpu/v60/op7a.inc
new file mode 100644
index 00000000000..67a7b0fb82c
--- /dev/null
+++ b/src/devices/cpu/v60/op7a.inc
@@ -0,0 +1,1212 @@
+// license:BSD-3-Clause
+// copyright-holders:Farfetch'd, R. Belmont
+/*
+ * CMPC: What happens to _S flag if the strings are identical?
+ * I suppose that it will be cleared. And is it set or cleared
+ * when the first one is a substring of the second? I suppose
+ * cleared (since _S should be (src > dst))
+ * MOVC: Why MOVCS does not exist in downward version?
+ * SHCHDB / SHCHDH: R27 is filled with the offset from the start or from the end?
+ *
+ * Strange stuff:
+ * SCHC opcodes does *not* modify _Z flag as stated in V60 manual:
+ * they do the opposite (set if not found, reset if found)
+ */
+
+#define F7AEND() \
+ return m_amlength1 + m_amlength2 + 4;
+
+#define F7BEND() \
+ return m_amlength1 + m_amlength2 + 3;
+
+#define F7CEND() \
+ return m_amlength1 + m_amlength2 + 3;
+
+#define F7BCREATEBITMASK(x) \
+ x = ((1 << (x)) - 1)
+
+#define F7CCREATEBITMASK(x) \
+ x = ((1 << (x)) - 1)
+
+void v60_device::F7aDecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2)
+{
+ UINT8 appb;
+ // Decode first operand
+ m_moddim = dim1;
+ m_modm = m_subop & 0x40;
+ m_modadd = PC + 2;
+ m_amlength1 = (this->*DecodeOp1)();
+ m_flag1 = m_amflag;
+ m_op1 = m_amout;
+
+ // Decode length
+ appb = OpRead8(PC + 2 + m_amlength1);
+ if (appb & 0x80)
+ m_lenop1 = m_reg[appb & 0x1F];
+ else
+ m_lenop1 = appb;
+
+ // Decode second operand
+ m_moddim = dim2;
+ m_modm = m_subop & 0x20;
+ m_modadd = PC + 3 + m_amlength1;
+ m_amlength2 = (this->*DecodeOp2)();
+ m_flag2 = m_amflag;
+ m_op2 = m_amout;
+
+ // Decode length
+ appb = OpRead8(PC + 3 + m_amlength1 + m_amlength2);
+ if (appb & 0x80)
+ m_lenop2 = m_reg[appb & 0x1F];
+ else
+ m_lenop2 = appb;
+}
+
+void v60_device::F7bDecodeFirstOperand(am_func DecodeOp1, UINT8 dim1)
+{
+ UINT8 appb;
+ // Decode first operand
+ m_moddim = dim1;
+ m_modm = m_subop & 0x40;
+ m_modadd = PC + 2;
+ m_amlength1 = (this->*DecodeOp1)();
+ m_flag1 = m_amflag;
+ m_op1 = m_amout;
+
+ // Decode ext
+ appb = OpRead8(PC + 2 + m_amlength1);
+ if (appb & 0x80)
+ m_lenop1 = m_reg[appb & 0x1F];
+ else
+ m_lenop1 = appb;
+}
+
+
+void v60_device::F7bWriteSecondOperand(UINT8 dim2)
+{
+ m_moddim = dim2;
+ m_modm = m_subop & 0x20;
+ m_modadd = PC + 3 + m_amlength1;
+ m_amlength2 = WriteAM();
+}
+
+
+void v60_device::F7bDecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2)
+{
+ // Decode first operand
+ F7bDecodeFirstOperand(DecodeOp1, dim1);
+ m_bamoffset1 = m_bamoffset;
+
+ // Decode second operand
+ m_moddim = dim2;
+ m_modm = m_subop & 0x20;
+ m_modadd = PC + 3 + m_amlength1;
+ m_amlength2 = (this->*DecodeOp2)();
+ m_flag2 = m_amflag;
+ m_op2 = m_amout;
+ m_bamoffset2 = m_bamoffset;
+}
+
+void v60_device::F7cDecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2)
+{
+ UINT8 appb;
+ // Decode first operand
+ m_moddim = dim1;
+ m_modm = m_subop & 0x40;
+ m_modadd = PC + 2;
+ m_amlength1 = (this->*DecodeOp1)();
+ m_flag1 = m_amflag;
+ m_op1 = m_amout;
+
+ // Decode second operand
+ m_moddim = dim2;
+ m_modm = m_subop & 0x20;
+ m_modadd = PC + 2 + m_amlength1;
+ m_amlength2 = (this->*DecodeOp2)();
+ m_flag2 = m_amflag;
+ m_op2 = m_amout;
+
+ // Decode ext
+ appb = OpRead8(PC + 2 + m_amlength1 + m_amlength2);
+ if (appb & 0x80)
+ m_lenop1 = m_reg[appb & 0x1F];
+ else
+ m_lenop1 = appb;
+}
+
+#define F7CLOADOP1BYTE(appb) \
+ if (m_flag1) \
+ appb = (UINT8)(m_reg[m_op1]&0xFF); \
+ else \
+ appb = m_program->read_byte(m_op1);
+
+#define F7CLOADOP2BYTE(appb) \
+ if (m_flag2) \
+ appb = (UINT8)(m_reg[m_op2]&0xFF); \
+ else \
+ appb = m_program->read_byte(m_op2);
+
+
+#define F7CSTOREOP2BYTE() \
+ if (m_flag2) \
+ SETREG8(m_reg[m_op2], appb); \
+ else \
+ m_program->write_byte(m_op2, appb);
+
+#define F7CSTOREOP2HALF() \
+ if (m_flag2) \
+ SETREG16(m_reg[m_op2], apph); \
+ else \
+ m_program->write_word_unaligned(m_op2, apph);
+
+UINT32 v60_device::opCMPSTRB(UINT8 bFill, UINT8 bStop)
+{
+ UINT32 i, dest;
+ UINT8 c1, c2;
+
+ F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0);
+
+ // Filling
+ if (bFill)
+ {
+ if (m_lenop1 < m_lenop2)
+ {
+ for (i = m_lenop1; i < m_lenop2; i++)
+ m_program->write_byte(m_op1 + i,(UINT8)R26);
+ }
+ else if (m_lenop2 < m_lenop1)
+ {
+ for (i = m_lenop2; i < m_lenop1; i++)
+ m_program->write_byte(m_op2 + i,(UINT8)R26);
+ }
+ }
+
+ dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
+
+ _Z = 0;
+ _S = 0;
+ if (bStop) _CY = 1;
+
+ for (i = 0; i < dest; i++)
+ {
+ c1 = m_program->read_byte(m_op1 + i);
+ c2 = m_program->read_byte(m_op2 + i);
+
+ if (c1 > c2)
+ {
+ _S = 1; break;
+ }
+ else if (c2 > c1)
+ {
+ _S = 0; break;
+ }
+
+ if (bStop)
+ if (c1 == (UINT8)R26 || c2 == (UINT8)R26)
+ {
+ _CY = 0;
+ break;
+ }
+ }
+
+ R28 = m_lenop1 + i;
+ R27 = m_lenop2 + i;
+
+ if (i == dest)
+ {
+ if (m_lenop1 > m_lenop2)
+ _S = 1;
+ else if (m_lenop2 > m_lenop1)
+ _S = 0;
+ else
+ _Z = 1;
+ }
+
+ F7AEND();
+}
+
+UINT32 v60_device::opCMPSTRH(UINT8 bFill, UINT8 bStop)
+{
+ UINT32 i, dest;
+ UINT16 c1, c2;
+
+ F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0);
+
+ // Filling
+ if (bFill)
+ {
+ if (m_lenop1 < m_lenop2)
+ {
+ for (i = m_lenop1; i < m_lenop2; i++)
+ m_program->write_word_unaligned(m_op1 + i * 2,(UINT16)R26);
+ }
+ else if (m_lenop2 < m_lenop1)
+ {
+ for (i = m_lenop2; i < m_lenop1; i++)
+ m_program->write_word_unaligned(m_op2 + i * 2,(UINT16)R26);
+ }
+ }
+
+ dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
+
+ _Z = 0;
+ _S = 0;
+ if (bStop) _CY = 1;
+
+ for (i = 0; i < dest; i++)
+ {
+ c1 = m_program->read_word_unaligned(m_op1 + i * 2);
+ c2 = m_program->read_word_unaligned(m_op2 + i * 2);
+
+ if (c1 > c2)
+ {
+ _S = 1; break;
+ }
+ else if (c2 > c1)
+ {
+ _S = 0; break;
+ }
+
+ if (bStop)
+ if (c1 == (UINT16)R26 || c2 == (UINT16)R26)
+ {
+ _CY = 0;
+ break;
+ }
+ }
+
+ R28 = m_lenop1 + i * 2;
+ R27 = m_lenop2 + i * 2;
+
+ if (i == dest)
+ {
+ if (m_lenop1 > m_lenop2)
+ _S = 1;
+ else if (m_lenop2 > m_lenop1)
+ _S = 0;
+ else
+ _Z = 1;
+ }
+
+ F7AEND();
+}
+
+
+
+UINT32 v60_device::opMOVSTRUB(UINT8 bFill, UINT8 bStop) /* TRUSTED (0, 0) (1, 0) */
+{
+ UINT32 i, dest;
+ UINT8 c1;
+
+// if (bStop)
+// {
+// int a = 1;
+// }
+
+ F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0);
+
+ dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
+
+ for (i = 0; i < dest; i++)
+ {
+ m_program->write_byte(m_op2 + i,(c1 = m_program->read_byte(m_op1 + i)));
+
+ if (bStop && c1 == (UINT8)R26)
+ break;
+ }
+
+ R28 = m_op1 + i;
+ R27 = m_op2 + i;
+
+ if (bFill && m_lenop1 < m_lenop2)
+ {
+ for (;i < m_lenop2; i++)
+ m_program->write_byte(m_op2 + i,(UINT8)R26);
+
+ R27 = m_op2 + i;
+ }
+
+
+ F7AEND();
+}
+
+UINT32 v60_device::opMOVSTRDB(UINT8 bFill, UINT8 bStop)
+{
+ UINT32 i, dest;
+ UINT8 c1;
+
+ F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0);
+
+ dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
+
+ for (i = 0; i < dest; i++)
+ {
+ m_program->write_byte(m_op2 + (dest - i - 1),(c1 = m_program->read_byte(m_op1 + (dest - i - 1))));
+
+ if (bStop && c1 == (UINT8)R26)
+ break;
+ }
+
+ R28 = m_op1 + (m_lenop1 - i - 1);
+ R27 = m_op2 + (m_lenop2 - i - 1);
+
+ if (bFill && m_lenop1 < m_lenop2)
+ {
+ for (;i < m_lenop2; i++)
+ m_program->write_byte(m_op2 + dest + (m_lenop2 - i - 1),(UINT8)R26);
+
+ R27 = m_op2 + (m_lenop2 - i - 1);
+ }
+
+
+ F7AEND();
+}
+
+
+UINT32 v60_device::opMOVSTRUH(UINT8 bFill, UINT8 bStop) /* TRUSTED (0, 0) (1, 0) */
+{
+ UINT32 i, dest;
+ UINT16 c1;
+
+// if (bStop)
+// { int a = 1; }
+
+ F7aDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAMAddress, 1);
+
+ dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
+
+ for (i = 0; i < dest; i++)
+ {
+ m_program->write_word_unaligned(m_op2 + i * 2,(c1 = m_program->read_word_unaligned(m_op1 + i * 2)));
+
+ if (bStop && c1 == (UINT16)R26)
+ break;
+ }
+
+ R28 = m_op1 + i * 2;
+ R27 = m_op2 + i * 2;
+
+ if (bFill && m_lenop1 < m_lenop2)
+ {
+ for (;i < m_lenop2; i++)
+ m_program->write_word_unaligned(m_op2 + i * 2,(UINT16)R26);
+
+ R27 = m_op2 + i * 2;
+ }
+
+ F7AEND();
+}
+
+UINT32 v60_device::opMOVSTRDH(UINT8 bFill, UINT8 bStop)
+{
+ UINT32 i, dest;
+ UINT16 c1;
+
+// if (bFill | bStop)
+// { int a = 1; }
+
+ F7aDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAMAddress, 1);
+
+// if (m_lenop1 != m_lenop2)
+// { int a = 1; }
+
+ dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
+
+ for (i = 0; i < dest; i++)
+ {
+ m_program->write_word_unaligned(m_op2 + (dest - i - 1) * 2,(c1 = m_program->read_word_unaligned(m_op1 + (dest - i - 1) * 2)));
+
+ if (bStop && c1 == (UINT16)R26)
+ break;
+ }
+
+ R28 = m_op1 + (m_lenop1 - i - 1) * 2;
+ R27 = m_op2 + (m_lenop2 - i - 1) * 2;
+
+ if (bFill && m_lenop1 < m_lenop2)
+ {
+ for (;i < m_lenop2; i++)
+ m_program->write_word_unaligned(m_op2 + (m_lenop2 - i - 1) * 2,(UINT16)R26);
+
+ R27 = m_op2 + (m_lenop2 - i - 1) * 2;
+ }
+
+ F7AEND();
+}
+
+UINT32 v60_device::opSEARCHUB(UINT8 bSearch)
+{
+ UINT8 appb;
+ UINT32 i;
+
+ F7bDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAM, 0);
+
+ for (i = 0; i < m_lenop1; i++)
+ {
+ appb = (m_program->read_byte(m_op1 + i) == (UINT8)m_op2);
+ if ((bSearch && appb) || (!bSearch && !appb))
+ break;
+ }
+
+ R28 = m_op1 + i;
+ R27 = i;
+
+ // This is the opposite as stated in V60 manual...
+ if (i != m_lenop1)
+ _Z = 0;
+ else
+ _Z = 1;
+
+ F7BEND();
+}
+
+UINT32 v60_device::opSEARCHUH(UINT8 bSearch)
+{
+ UINT8 appb;
+ UINT32 i;
+
+ F7bDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAM, 1);
+
+ for (i = 0; i < m_lenop1; i++)
+ {
+ appb = (m_program->read_word_unaligned(m_op1 + i * 2) == (UINT16)m_op2);
+ if ((bSearch && appb) || (!bSearch && !appb))
+ break;
+ }
+
+ R28 = m_op1 + i * 2;
+ R27 = i;
+
+ if (i != m_lenop1)
+ _Z = 0;
+ else
+ _Z = 1;
+
+ F7BEND();
+}
+
+UINT32 v60_device::opSEARCHDB(UINT8 bSearch)
+{
+ UINT8 appb;
+ INT32 i;
+
+ F7bDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAM, 0);
+
+ for (i = m_lenop1; i >= 0; i--)
+ {
+ appb = (m_program->read_byte(m_op1 + i) == (UINT8)m_op2);
+ if ((bSearch && appb) || (!bSearch && !appb))
+ break;
+ }
+
+ R28 = m_op1 + i;
+ R27 = i;
+
+ // This is the opposite as stated in V60 manual...
+ if ((UINT32)i != m_lenop1)
+ _Z = 0;
+ else
+ _Z = 1;
+
+ F7BEND();
+}
+
+UINT32 v60_device::opSEARCHDH(UINT8 bSearch)
+{
+ UINT8 appb;
+ INT32 i;
+
+ F7bDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAM, 1);
+
+ for (i = m_lenop1 - 1; i >= 0; i--)
+ {
+ appb = (m_program->read_word_unaligned(m_op1 + i * 2) == (UINT16)m_op2);
+ if ((bSearch && appb) || (!bSearch && !appb))
+ break;
+ }
+
+ R28 = m_op1 + i * 2;
+ R27 = i;
+
+ if ((UINT32)i != m_lenop1)
+ _Z = 0;
+ else
+ _Z = 1;
+
+ F7BEND();
+}
+
+
+UINT32 v60_device::opSCHCUB() { return opSEARCHUB(1); }
+UINT32 v60_device::opSCHCUH() { return opSEARCHUH(1); }
+UINT32 v60_device::opSCHCDB() { return opSEARCHDB(1); }
+UINT32 v60_device::opSCHCDH() { return opSEARCHDH(1); }
+UINT32 v60_device::opSKPCUB() { return opSEARCHUB(0); }
+UINT32 v60_device::opSKPCUH() { return opSEARCHUH(0); }
+UINT32 v60_device::opSKPCDB() { return opSEARCHDB(0); }
+UINT32 v60_device::opSKPCDH() { return opSEARCHDH(0); }
+
+UINT32 v60_device::opCMPCB() { return opCMPSTRB(0, 0); }
+UINT32 v60_device::opCMPCH() { return opCMPSTRH(0, 0); }
+UINT32 v60_device::opCMPCFB() { return opCMPSTRB(1, 0); }
+UINT32 v60_device::opCMPCFH() { return opCMPSTRH(1, 0); }
+UINT32 v60_device::opCMPCSB() { return opCMPSTRB(0, 1); }
+UINT32 v60_device::opCMPCSH() { return opCMPSTRH(0, 1); }
+
+UINT32 v60_device::opMOVCUB() { return opMOVSTRUB(0, 0); }
+UINT32 v60_device::opMOVCUH() { return opMOVSTRUH(0, 0); }
+UINT32 v60_device::opMOVCFUB() { return opMOVSTRUB(1, 0); }
+UINT32 v60_device::opMOVCFUH() { return opMOVSTRUH(1, 0); }
+UINT32 v60_device::opMOVCSUB() { return opMOVSTRUB(0, 1); }
+UINT32 v60_device::opMOVCSUH() { return opMOVSTRUH(0, 1); }
+
+UINT32 v60_device::opMOVCDB() { return opMOVSTRDB(0, 0); }
+UINT32 v60_device::opMOVCDH() { return opMOVSTRDH(0, 0); }
+UINT32 v60_device::opMOVCFDB() { return opMOVSTRDB(1, 0); }
+UINT32 v60_device::opMOVCFDH() { return opMOVSTRDH(1, 0); }
+
+UINT32 v60_device::opEXTBFZ() /* TRUSTED */
+{
+ F7bDecodeFirstOperand(&v60_device::BitReadAM, 11);
+
+ F7BCREATEBITMASK(m_lenop1);
+
+ m_modwritevalw = (m_op1 >> m_bamoffset) & m_lenop1;
+
+ F7bWriteSecondOperand(2);
+
+ F7BEND();
+}
+
+UINT32 v60_device::opEXTBFS() /* TRUSTED */
+{
+ F7bDecodeFirstOperand(&v60_device::BitReadAM, 11);
+
+ F7BCREATEBITMASK(m_lenop1);
+
+ m_modwritevalw = (m_op1 >> m_bamoffset) & m_lenop1;
+ if (m_modwritevalw & ((m_lenop1 + 1) >> 1))
+ m_modwritevalw |= ~m_lenop1;
+
+ F7bWriteSecondOperand(2);
+
+ F7BEND();
+}
+
+UINT32 v60_device::opEXTBFL()
+{
+ UINT32 appw;
+
+ F7bDecodeFirstOperand(&v60_device::BitReadAM, 11);
+
+ appw = m_lenop1;
+ F7BCREATEBITMASK(m_lenop1);
+
+ m_modwritevalw = (m_op1 >> m_bamoffset) & m_lenop1;
+ m_modwritevalw <<= 32 - appw;
+
+ F7bWriteSecondOperand(2);
+
+ F7BEND();
+}
+
+UINT32 v60_device::opSCHBS(UINT32 bSearch1)
+{
+ UINT32 i, data;
+ UINT32 offset;
+
+ F7bDecodeFirstOperand(&v60_device::BitReadAMAddress, 10);
+
+ // Read first UINT8
+ m_op1 += m_bamoffset / 8;
+ data = m_program->read_byte(m_op1);
+ offset = m_bamoffset & 7;
+
+ // Scan bitstring
+ for (i = 0; i < m_lenop1; i++)
+ {
+ // Update the work register
+ R28 = m_op1;
+
+ // There is a 0 / 1 at current offset?
+ if ((bSearch1 && (data&(1 << offset))) ||
+ (!bSearch1 && !(data&(1 << offset))))
+ break;
+
+ // Next bit please
+ offset++;
+ if (offset == 8)
+ {
+ // Next UINT8 please
+ offset = 0;
+ m_op1++;
+ data = m_program->read_byte(m_op1);
+ }
+ }
+
+ // Set zero if bit not found
+ _Z = (i == m_lenop1);
+
+ // Write to destination the final offset
+ m_modwritevalw = i;
+ F7bWriteSecondOperand(2);
+
+ F7BEND();
+}
+
+UINT32 v60_device::opSCH0BSU() { return opSCHBS(0); }
+UINT32 v60_device::opSCH1BSU() { return opSCHBS(1); }
+
+UINT32 v60_device::opINSBFR()
+{
+ UINT32 appw;
+ F7cDecodeOperands(&v60_device::ReadAM, 2,&v60_device::BitReadAMAddress, 11);
+
+ F7CCREATEBITMASK(m_lenop1);
+
+ m_op2 += m_bamoffset / 8;
+ appw = m_program->read_dword_unaligned(m_op2);
+ m_bamoffset &= 7;
+
+ appw &= ~(m_lenop1 << m_bamoffset);
+ appw |= (m_lenop1 & m_op1) << m_bamoffset;
+
+ m_program->write_dword_unaligned(m_op2, appw);
+
+ F7CEND();
+}
+
+UINT32 v60_device::opINSBFL()
+{
+ UINT32 appw;
+ F7cDecodeOperands(&v60_device::ReadAM, 2,&v60_device::BitReadAMAddress, 11);
+
+ m_op1 >>= (32 - m_lenop1);
+
+ F7CCREATEBITMASK(m_lenop1);
+
+ m_op2 += m_bamoffset / 8;
+ appw = m_program->read_dword_unaligned(m_op2);
+ m_bamoffset &= 7;
+
+ appw &= ~(m_lenop1 << m_bamoffset);
+ appw |= (m_lenop1 & m_op1) << m_bamoffset;
+
+ m_program->write_dword_unaligned(m_op2, appw);
+
+ F7CEND();
+}
+
+UINT32 v60_device::opMOVBSD()
+{
+ UINT32 i;
+ UINT8 srcdata, dstdata;
+
+ F7bDecodeOperands(&v60_device::BitReadAMAddress, 10, &v60_device::BitReadAMAddress, 10);
+
+// if (m_lenop1 != 1)
+// { int a = 1; }
+
+ m_bamoffset1 += m_lenop1 - 1;
+ m_bamoffset2 += m_lenop1 - 1;
+
+ m_op1 += m_bamoffset1 / 8;
+ m_op2 += m_bamoffset2 / 8;
+
+ m_bamoffset1 &= 7;
+ m_bamoffset2 &= 7;
+
+ srcdata = m_program->read_byte(m_op1);
+ dstdata = m_program->read_byte(m_op2);
+
+ for (i = 0; i < m_lenop1; i++)
+ {
+ // Update work registers
+ R28 = m_op1;
+ R27 = m_op2;
+
+ dstdata &= ~(1 << m_bamoffset2);
+ dstdata |= ((srcdata >> m_bamoffset1) & 1) << m_bamoffset2;
+
+ if (m_bamoffset1 == 0)
+ {
+ m_bamoffset1 = 8;
+ m_op1--;
+ srcdata = m_program->read_byte(m_op1);
+ }
+ if (m_bamoffset2 == 0)
+ {
+ m_program->write_byte(m_op2, dstdata);
+ m_bamoffset2 = 8;
+ m_op2--;
+ dstdata = m_program->read_byte(m_op2);
+ }
+
+ m_bamoffset1--;
+ m_bamoffset2--;
+ }
+
+ // Flush of the final data
+ if (m_bamoffset2 != 7)
+ m_program->write_byte(m_op2, dstdata);
+
+ F7BEND();
+}
+
+UINT32 v60_device::opMOVBSU()
+{
+ UINT32 i;
+ UINT8 srcdata, dstdata;
+
+ F7bDecodeOperands(&v60_device::BitReadAMAddress, 10, &v60_device::BitReadAMAddress, 10);
+
+ m_op1 += m_bamoffset1 / 8;
+ m_op2 += m_bamoffset2 / 8;
+
+ m_bamoffset1 &= 7;
+ m_bamoffset2 &= 7;
+
+ srcdata = m_program->read_byte(m_op1);
+ dstdata = m_program->read_byte(m_op2);
+
+ for (i = 0; i < m_lenop1; i++)
+ {
+ // Update work registers
+ R28 = m_op1;
+ R27 = m_op2;
+
+ dstdata &= ~(1 << m_bamoffset2);
+ dstdata |= ((srcdata >> m_bamoffset1) & 1) << m_bamoffset2;
+
+ m_bamoffset1++;
+ m_bamoffset2++;
+ if (m_bamoffset1 == 8)
+ {
+ m_bamoffset1 = 0;
+ m_op1++;
+ srcdata = m_program->read_byte(m_op1);
+ }
+ if (m_bamoffset2 == 8)
+ {
+ m_program->write_byte(m_op2, dstdata);
+ m_bamoffset2 = 0;
+ m_op2++;
+ dstdata = m_program->read_byte(m_op2);
+ }
+ }
+
+ // Flush of the final data
+ if (m_bamoffset2 != 0)
+ m_program->write_byte(m_op2, dstdata);
+
+ F7BEND();
+}
+
+// RADM 0x20f4b8 holds the time left
+
+UINT32 v60_device::opADDDC()
+{
+ UINT8 appb;
+ UINT8 src, dst;
+
+ F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 0);
+
+ if (m_lenop1 != 0)
+ {
+ logerror("ADDDC %x (pat: %x)\n", m_op1, m_lenop1);
+ }
+
+ F7CLOADOP2BYTE(appb);
+
+ src = (UINT8)(m_op1 >> 4) * 10 + (UINT8)(m_op1 & 0xF);
+ dst = (appb >> 4) * 10 + (appb & 0xF);
+
+ appb = src + dst + (_CY?1:0);
+
+ if (appb >= 100)
+ {
+ appb -= 100;
+ _CY = 1;
+ }
+ else
+ _CY = 0;
+
+ // compute z flag:
+ // cleared if result non-zero or carry generated
+ // unchanged otherwise
+ if (appb != 0 || _CY)
+ _Z = 0;
+
+ appb = ((appb / 10) << 4) | (appb % 10);
+
+ F7CSTOREOP2BYTE();
+ F7CEND();
+}
+
+UINT32 v60_device::opSUBDC()
+{
+ INT8 appb;
+ UINT32 src, dst;
+
+ F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 0);
+
+ if (m_lenop1 != 0)
+ {
+ logerror("SUBDC %x (pat: %x)\n", m_op1, m_lenop1);
+ }
+
+ F7CLOADOP2BYTE(appb);
+
+ src = (UINT32)(m_op1 >> 4) * 10 + (UINT32)(m_op1 & 0xF);
+ dst = ((appb & 0xF0) >> 4) * 10 + (appb & 0xF);
+
+ // Note that this APPB must be SIGNED!
+ appb = (INT32)dst - (INT32)src - (_CY?1:0);
+
+ if (appb < 0)
+ {
+ appb += 100;
+ _CY = 1;
+ }
+ else
+ _CY = 0;
+
+ // compute z flag:
+ // cleared if result non-zero or carry generated
+ // unchanged otherwise
+ if (appb != 0 || _CY)
+ _Z = 0;
+
+ appb = ((appb / 10) << 4) | (appb % 10);
+
+ F7CSTOREOP2BYTE();
+ F7CEND();
+}
+
+UINT32 v60_device::opSUBRDC()
+{
+ INT8 appb;
+ UINT32 src, dst;
+
+ F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 0);
+
+ if (m_lenop1 != 0)
+ {
+ logerror("SUBRDC %x (pat: %x)\n", m_op1, m_lenop1);
+ }
+
+ F7CLOADOP2BYTE(appb);
+
+ src = (UINT32)(m_op1 >> 4) * 10 + (UINT32)(m_op1 & 0xF);
+ dst = ((appb & 0xF0) >> 4) * 10 + (appb & 0xF);
+
+ // Note that this APPB must be SIGNED!
+ appb = (INT32)src - (INT32)dst - (_CY?1:0);
+
+ if (appb < 0)
+ {
+ appb += 100;
+ _CY = 1;
+ }
+ else
+ _CY = 0;
+
+ // compute z flag:
+ // cleared if result non-zero or carry generated
+ // unchanged otherwise
+ if (appb != 0 || _CY)
+ _Z = 0;
+
+ appb = ((appb / 10) << 4) | (appb % 10);
+
+ F7CSTOREOP2BYTE();
+ F7CEND();
+}
+
+UINT32 v60_device::opCVTDPZ()
+{
+ UINT16 apph;
+
+ F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 1);
+
+ apph = (UINT16)(((m_op1 >> 4) & 0xF) | ((m_op1 & 0xF) << 8));
+ apph |= (m_lenop1);
+ apph |= (m_lenop1 << 8);
+
+ // Z flag is unchanged if src is zero, cleared otherwise
+ if (m_op1 != 0) _Z = 0;
+
+ F7CSTOREOP2HALF();
+ F7CEND();
+}
+
+UINT32 v60_device::opCVTDZP()
+{
+ UINT8 appb;
+ F7cDecodeOperands(&v60_device::ReadAM, 1, &v60_device::ReadAMAddress, 0);
+
+ if ((m_op1 & 0xF0) != (m_lenop1 & 0xF0) || ((m_op1 >> 8) & 0xF0) != (m_lenop1 & 0xF0))
+ {
+ // Decimal exception
+ logerror("CVTD.ZP Decimal exception #1!\n");
+ }
+
+ if ((m_op1 & 0xF) > 9 || ((m_op1 >> 8) & 0xF) > 9)
+ {
+ // Decimal exception
+ logerror("CVTD.ZP Decimal exception #2!\n");
+ }
+
+ appb = (UINT8)(((m_op1 >> 8) & 0xF) | ((m_op1 & 0xF) << 4));
+ if (appb != 0) _Z = 0;
+
+ F7CSTOREOP2BYTE();
+ F7CEND();
+}
+
+UINT32 v60_device::op58UNHANDLED()
+{
+ fatalerror("Unhandled 58 opcode at PC: /%06x\n", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+UINT32 v60_device::op5AUNHANDLED()
+{
+ fatalerror("Unhandled 5A opcode at PC: /%06x\n", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+UINT32 v60_device::op5BUNHANDLED()
+{
+ fatalerror("Unhandled 5B opcode at PC: /%06x\n", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+UINT32 v60_device::op5DUNHANDLED()
+{
+ fatalerror("Unhandled 5D opcode at PC: /%06x\n", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+UINT32 v60_device::op59UNHANDLED()
+{
+ fatalerror("Unhandled 59 opcode at PC: /%06x\n", PC);
+ return 0; /* never reached, fatalerror won't return */
+}
+
+const v60_device::am_func v60_device::s_Op59Table[32] =
+{
+ &v60_device::opADDDC,
+ &v60_device::opSUBDC,
+ &v60_device::opSUBRDC,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::opCVTDPZ,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::opCVTDZP,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED,
+ &v60_device::op59UNHANDLED
+};
+
+
+const v60_device::am_func v60_device::s_Op5BTable[32] =
+{
+ &v60_device::opSCH0BSU,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::opSCH1BSU,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::opMOVBSU,
+ &v60_device::opMOVBSD,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED,
+ &v60_device::op5BUNHANDLED
+};
+
+
+const v60_device::am_func v60_device::s_Op5DTable[32] =
+{
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::opEXTBFS,
+ &v60_device::opEXTBFZ,
+ &v60_device::opEXTBFL,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::opINSBFR,
+ &v60_device::opINSBFL,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED,
+ &v60_device::op5DUNHANDLED
+};
+
+const v60_device::am_func v60_device::s_Op58Table[32] =
+{
+ &v60_device::opCMPCB,
+ &v60_device::opCMPCFB,
+ &v60_device::opCMPCSB,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::opMOVCUB,
+ &v60_device::opMOVCDB,
+ &v60_device::opMOVCFUB,
+ &v60_device::opMOVCFDB,
+ &v60_device::opMOVCSUB,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::opSCHCUB,
+ &v60_device::opSCHCDB,
+ &v60_device::opSKPCUB,
+ &v60_device::opSKPCDB,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED,
+ &v60_device::op58UNHANDLED
+};
+
+const v60_device::am_func v60_device::s_Op5ATable[32] =
+{
+ &v60_device::opCMPCH,
+ &v60_device::opCMPCFH,
+ &v60_device::opCMPCSH,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::opMOVCUH,
+ &v60_device::opMOVCDH,
+ &v60_device::opMOVCFUH,
+ &v60_device::opMOVCFDH,
+ &v60_device::opMOVCSUH,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::opSCHCUH,
+ &v60_device::opSCHCDH,
+ &v60_device::opSKPCUH,
+ &v60_device::opSKPCDH,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED,
+ &v60_device::op5AUNHANDLED
+};
+
+UINT32 v60_device::op58()
+{
+ m_subop = OpRead8(PC + 1);
+
+ return (this->*s_Op58Table[m_subop & 0x1F])();
+}
+
+UINT32 v60_device::op5A()
+{
+ m_subop = OpRead8(PC + 1);
+
+ return (this->*s_Op5ATable[m_subop & 0x1F])();
+}
+
+UINT32 v60_device::op5B()
+{
+ m_subop = OpRead8(PC + 1);
+
+ return (this->*s_Op5BTable[m_subop & 0x1F])();
+}
+
+UINT32 v60_device::op5D()
+{
+ m_subop = OpRead8(PC + 1);
+
+ return (this->*s_Op5DTable[m_subop & 0x1F])();
+}
+
+UINT32 v60_device::op59()
+{
+ m_subop = OpRead8(PC + 1);
+
+ return (this->*s_Op59Table[m_subop & 0x1F])();
+}