// 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_t dim1, am_func DecodeOp2, uint8_t dim2) { uint8_t 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_t dim1) { uint8_t 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_t 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_t dim1, am_func DecodeOp2, uint8_t 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_t dim1, am_func DecodeOp2, uint8_t dim2) { uint8_t 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_t)(m_reg[m_op1]&0xFF); \ else \ appb = m_program->read_byte(m_op1); #define F7CLOADOP2BYTE(appb) \ if (m_flag2) \ appb = (uint8_t)(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_t v60_device::opCMPSTRB(uint8_t bFill, uint8_t bStop) { uint32_t i, dest; uint8_t 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_t)R26); } else if (m_lenop2 < m_lenop1) { for (i = m_lenop2; i < m_lenop1; i++) m_program->write_byte(m_op2 + i,(uint8_t)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_t)R26 || c2 == (uint8_t)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_t v60_device::opCMPSTRH(uint8_t bFill, uint8_t bStop) { uint32_t i, dest; uint16_t 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_t)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_t)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_t)R26 || c2 == (uint16_t)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_t v60_device::opMOVSTRUB(uint8_t bFill, uint8_t bStop) /* TRUSTED (0, 0) (1, 0) */ { uint32_t i, dest; uint8_t 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_t)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_t)R26); R27 = m_op2 + i; } F7AEND(); } uint32_t v60_device::opMOVSTRDB(uint8_t bFill, uint8_t bStop) { uint32_t i, dest; uint8_t 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_t)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_t)R26); R27 = m_op2 + (m_lenop2 - i - 1); } F7AEND(); } uint32_t v60_device::opMOVSTRUH(uint8_t bFill, uint8_t bStop) /* TRUSTED (0, 0) (1, 0) */ { uint32_t i, dest; uint16_t 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_t)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_t)R26); R27 = m_op2 + i * 2; } F7AEND(); } uint32_t v60_device::opMOVSTRDH(uint8_t bFill, uint8_t bStop) { uint32_t i, dest; uint16_t 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_t)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_t)R26); R27 = m_op2 + (m_lenop2 - i - 1) * 2; } F7AEND(); } uint32_t v60_device::opSEARCHUB(uint8_t bSearch) { uint8_t appb; uint32_t 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_t)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_t v60_device::opSEARCHUH(uint8_t bSearch) { uint8_t appb; uint32_t 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_t)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_t v60_device::opSEARCHDB(uint8_t bSearch) { uint8_t appb; int32_t 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_t)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_t)i != m_lenop1) _Z = 0; else _Z = 1; F7BEND(); } uint32_t v60_device::opSEARCHDH(uint8_t bSearch) { uint8_t appb; int32_t 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_t)m_op2); if ((bSearch && appb) || (!bSearch && !appb)) break; } R28 = m_op1 + i * 2; R27 = i; if ((uint32_t)i != m_lenop1) _Z = 0; else _Z = 1; F7BEND(); } uint32_t v60_device::opSCHCUB() { return opSEARCHUB(1); } uint32_t v60_device::opSCHCUH() { return opSEARCHUH(1); } uint32_t v60_device::opSCHCDB() { return opSEARCHDB(1); } uint32_t v60_device::opSCHCDH() { return opSEARCHDH(1); } uint32_t v60_device::opSKPCUB() { return opSEARCHUB(0); } uint32_t v60_device::opSKPCUH() { return opSEARCHUH(0); } uint32_t v60_device::opSKPCDB() { return opSEARCHDB(0); } uint32_t v60_device::opSKPCDH() { return opSEARCHDH(0); } uint32_t v60_device::opCMPCB() { return opCMPSTRB(0, 0); } uint32_t v60_device::opCMPCH() { return opCMPSTRH(0, 0); } uint32_t v60_device::opCMPCFB() { return opCMPSTRB(1, 0); } uint32_t v60_device::opCMPCFH() { return opCMPSTRH(1, 0); } uint32_t v60_device::opCMPCSB() { return opCMPSTRB(0, 1); } uint32_t v60_device::opCMPCSH() { return opCMPSTRH(0, 1); } uint32_t v60_device::opMOVCUB() { return opMOVSTRUB(0, 0); } uint32_t v60_device::opMOVCUH() { return opMOVSTRUH(0, 0); } uint32_t v60_device::opMOVCFUB() { return opMOVSTRUB(1, 0); } uint32_t v60_device::opMOVCFUH() { return opMOVSTRUH(1, 0); } uint32_t v60_device::opMOVCSUB() { return opMOVSTRUB(0, 1); } uint32_t v60_device::opMOVCSUH() { return opMOVSTRUH(0, 1); } uint32_t v60_device::opMOVCDB() { return opMOVSTRDB(0, 0); } uint32_t v60_device::opMOVCDH() { return opMOVSTRDH(0, 0); } uint32_t v60_device::opMOVCFDB() { return opMOVSTRDB(1, 0); } uint32_t v60_device::opMOVCFDH() { return opMOVSTRDH(1, 0); } uint32_t v60_device::opEXTBFZ() /* TRUSTED */ { F7bDecodeFirstOperand(&v60_device::BitReadAM, 11); F7BCREATEBITMASK(m_lenop1); m_modwritevalw = (m_op1 >> m_bamoffset) & m_lenop1; F7bWriteSecondOperand(2); F7BEND(); } uint32_t 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_t v60_device::opEXTBFL() { uint32_t 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_t v60_device::opSCHBS(uint32_t bSearch1) { uint32_t i, data; uint32_t offset; F7bDecodeFirstOperand(&v60_device::BitReadAMAddress, 10); // Read first uint8_t 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_t 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_t v60_device::opSCH0BSU() { return opSCHBS(0); } uint32_t v60_device::opSCH1BSU() { return opSCHBS(1); } uint32_t v60_device::opINSBFR() { uint32_t 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_t v60_device::opINSBFL() { uint32_t 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_t v60_device::opMOVBSD() { uint32_t i; uint8_t 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_t v60_device::opMOVBSU() { uint32_t i; uint8_t 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_t v60_device::opADDDC() { uint8_t appb; uint8_t 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_t)(m_op1 >> 4) * 10 + (uint8_t)(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_t v60_device::opSUBDC() { int8_t appb; uint32_t 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_t)(m_op1 >> 4) * 10 + (uint32_t)(m_op1 & 0xF); dst = ((appb & 0xF0) >> 4) * 10 + (appb & 0xF); // Note that this APPB must be SIGNED! appb = (int32_t)dst - (int32_t)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_t v60_device::opSUBRDC() { int8_t appb; uint32_t 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_t)(m_op1 >> 4) * 10 + (uint32_t)(m_op1 & 0xF); dst = ((appb & 0xF0) >> 4) * 10 + (appb & 0xF); // Note that this APPB must be SIGNED! appb = (int32_t)src - (int32_t)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_t v60_device::opCVTDPZ() { uint16_t apph; F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 1); apph = (uint16_t)(((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_t v60_device::opCVTDZP() { uint8_t 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_t)(((m_op1 >> 8) & 0xF) | ((m_op1 & 0xF) << 4)); if (appb != 0) _Z = 0; F7CSTOREOP2BYTE(); F7CEND(); } uint32_t v60_device::op58UNHANDLED() { fatalerror("Unhandled 58 opcode at PC: /%06x\n", PC); return 0; /* never reached, fatalerror won't return */ } uint32_t v60_device::op5AUNHANDLED() { fatalerror("Unhandled 5A opcode at PC: /%06x\n", PC); return 0; /* never reached, fatalerror won't return */ } uint32_t v60_device::op5BUNHANDLED() { fatalerror("Unhandled 5B opcode at PC: /%06x\n", PC); return 0; /* never reached, fatalerror won't return */ } uint32_t v60_device::op5DUNHANDLED() { fatalerror("Unhandled 5D opcode at PC: /%06x\n", PC); return 0; /* never reached, fatalerror won't return */ } uint32_t 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_t v60_device::op58() { m_subop = OpRead8(PC + 1); return (this->*s_Op58Table[m_subop & 0x1F])(); } uint32_t v60_device::op5A() { m_subop = OpRead8(PC + 1); return (this->*s_Op5ATable[m_subop & 0x1F])(); } uint32_t v60_device::op5B() { m_subop = OpRead8(PC + 1); return (this->*s_Op5BTable[m_subop & 0x1F])(); } uint32_t v60_device::op5D() { m_subop = OpRead8(PC + 1); return (this->*s_Op5DTable[m_subop & 0x1F])(); } uint32_t v60_device::op59() { m_subop = OpRead8(PC + 1); return (this->*s_Op59Table[m_subop & 0x1F])(); }