// license:BSD-3-Clause // copyright-holders:David Haywood /************************************************************************************************************* Toshiba TLCS-870 Series MCUs (reg) prefix ops (e8 to ef subtable) (reg) implies one of the follow registers (8-bit mode operations) E8 A E9 W EA C EB B EC E ED D EE L EF H (16-bit mode operations) E8 WA E9 BC EA DE EB HL EC WA ED BC EE DE EF HL (RETN operation - special) E8 RETN E9-EF invalid *************************************************************************************************************/ #include "emu.h" #include "tlcs870.h" #include "tlcs870d.h" #include "debugger.h" // Main dispatch handlers for these void tlcs870_device::do_regprefixtype_opcode(const uint8_t opbyte0) { // register prefix: g/gg uint8_t opbyte1 = READ8(); switch (opbyte1) { case 0x01: do_SWAP_g(opbyte0, opbyte1); break; case 0x02: do_MUL_gg(opbyte0, opbyte1); break; case 0x03: do_DIV_gg_C(opbyte0, opbyte1); break; case 0x04: do_RETN(opbyte0, opbyte1); break; case 0x06: do_POP_gg(opbyte0, opbyte1); break; case 0x07: do_PUSH_gg(opbyte0, opbyte1); break; case 0x0a: do_DAA_g(opbyte0, opbyte1); break; case 0x0b: do_DAS_g(opbyte0, opbyte1); break; case 0x10: case 0x11: case 0x12: case 0x13: do_XCH_rr_gg(opbyte0, opbyte1); break; case 0x14: case 0x15: case 0x16: case 0x17: do_LD_rr_gg(opbyte0, opbyte1); break; case 0x1c: do_SHLC_g(opbyte0, opbyte1); break; case 0x1d: do_SHRC_g(opbyte0, opbyte1); break; case 0x1e: do_ROLC_g(opbyte0, opbyte1); break; case 0x1f: do_RORC_g(opbyte0, opbyte1); break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: do_ALUOP_WA_gg(opbyte0, opbyte1); break; case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: do_ALUOP_gg_mn(opbyte0, opbyte1); break; case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: do_SET_gbit(opbyte0, opbyte1); break; case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: do_CLR_gbit(opbyte0, opbyte1); break; case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: do_LD_r_g(opbyte0, opbyte1); break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: do_ALUOP_A_g(opbyte0, opbyte1); break; case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: do_ALUOP_g_A(opbyte0, opbyte1); break; case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: do_ALUOP_g_n(opbyte0, opbyte1); break; case 0x82: case 0x83: do_SET_inppbit(opbyte0, opbyte1); break; case 0x8a: case 0x8b: do_CLR_inppbit(opbyte0, opbyte1); break; case 0x92: case 0x93: do_CPL_inpp_indirectbit(opbyte0, opbyte1); break; case 0x9a: case 0x9b: do_LD_inpp_indirectbit_CF(opbyte0, opbyte1); break; case 0x9e: case 0x9f: do_LD_CF_inpp_indirectbit(opbyte0, opbyte1); break; case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: do_XCH_r_g(opbyte0, opbyte1); break; case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: do_CPL_gbit(opbyte0, opbyte1); break; case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: do_LD_gbit_CF(opbyte0, opbyte1); break; case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: do_XOR_CF_gbit(opbyte0, opbyte1); break; case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: do_LD_CF_gbit(opbyte0, opbyte1); break; case 0xfa: do_LD_SP_gg(opbyte0, opbyte1); break; case 0xfb: do_LD_gg_SP(opbyte0, opbyte1); break; case 0xfc: do_CALL_gg(opbyte0, opbyte1); break; case 0xfe: do_JP_gg(opbyte0, opbyte1); break; default: do_regprefixtype_oprand_illegal(opbyte0, opbyte1); break; } } // Actual handlers /**********************************************************************************************************************/ // (Special) /**********************************************************************************************************************/ void tlcs870_device::do_regprefixtype_oprand_illegal(const uint8_t opbyte0, const uint8_t opbyte1) { m_cycles = 1; logerror("illegal reg prefix opcode %02x %02x\n", opbyte0, opbyte1); } void tlcs870_device::do_RETN(const uint8_t opbyte0, const uint8_t opbyte1) { // with E8 only if (opbyte0 == 0xe8) { /* Return from non-maskable interrupt service (how does this differ from RETI?) OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles RETN 1110 1000 0000 0100 * * * * 7 */ m_cycles = 7; m_sp.d += 3; m_addr = RM16(m_sp.d - 2); set_PSW(RM8(m_sp.d - 1)); } else { do_regprefixtype_oprand_illegal(opbyte0, opbyte1); } } /**********************************************************************************************************************/ // (8-bit) /**********************************************************************************************************************/ void tlcs870_device::do_SWAP_g(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles SWAP g 1110 1ggg 0000 0001 1 - - - 4 */ m_cycles = 4; const uint8_t reg = opbyte0 & 0x7; handle_swap(reg); } void tlcs870_device::do_DAA_g(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles DAS g 1110 1ggg 0000 1010 C Z C H 3 */ m_cycles = 3; uint8_t val = get_reg8(opbyte0 & 0x7); val = handle_DAA(val); set_reg8(opbyte0 & 0x7, val); } void tlcs870_device::do_DAS_g(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles DAS g 1110 1ggg 0000 1011 C Z C H 3 */ m_cycles = 3; uint8_t val = get_reg8(opbyte0 & 0x7); val = handle_DAS(val); set_reg8(opbyte0 & 0x7, val); } void tlcs870_device::do_SHLC_g(const uint8_t opbyte0, const uint8_t opbyte1) { /* Logical Shift Left with Carry Flag OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles SHLC g 1110 1ggg 0001 1100 C Z * - 2 */ m_cycles = 2; uint8_t val = get_reg8(opbyte0 & 0x7); val = handle_SHLC(val); set_reg8(opbyte0 & 0x7, val); } void tlcs870_device::do_SHRC_g(const uint8_t opbyte0, const uint8_t opbyte1) { /* Logical Shift Right with Carry Flag OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles SHRC g 1110 1ggg 0001 1101 C Z * - 2 */ m_cycles = 2; uint8_t val = get_reg8(opbyte0 & 0x7); val = handle_SHRC(val); set_reg8(opbyte0 & 0x7, val); } void tlcs870_device::do_ROLC_g(const uint8_t opbyte0, const uint8_t opbyte1) { /* Rotate Left through Carry flag OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles ROLC g 1110 1ggg 0001 1110 C Z * - 2 */ m_cycles = 2; uint8_t val = get_reg8(opbyte0 & 0x7); val = handle_ROLC(val); set_reg8(opbyte0 & 0x7, val); } void tlcs870_device::do_RORC_g(const uint8_t opbyte0, const uint8_t opbyte1) { /* Rotate Right through Carry flag OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles RORC g 1110 1ggg 0001 1111 C Z * - 2 */ m_cycles = 2; uint8_t val = get_reg8(opbyte0 & 0x7); val = handle_RORC(val); set_reg8(opbyte0 & 0x7, val); } void tlcs870_device::do_LD_r_g(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles LD r, g 1110 1ggg 0101 1rrr 1 Z - - 2 */ m_cycles = 2; const uint8_t val = get_reg8(opbyte0 & 0x7); set_reg8(opbyte1 & 0x7, val); set_JF(); if (val == 0x00) set_ZF(); else clear_ZF(); } void tlcs870_device::do_XCH_r_g(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles XCG r, g 1110 1ggg 1010 1rrr 1 Z - - 3 */ m_cycles = 3; const uint8_t val = get_reg8(opbyte0 & 0x7); const uint8_t r = get_reg8(opbyte1 & 0x7); set_reg8(opbyte1 & 0x7, val); set_reg8(opbyte0 & 0x7, r); set_JF(); if (val == 0x00) set_ZF(); else clear_ZF(); } /**********************************************************************************************************************/ // (ALU handlers) /**********************************************************************************************************************/ void tlcs870_device::do_ALUOP_A_g(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles ADDC A, g 1110 1ggg 0110 0000 C Z C H 2 ADD A, g 1110 1ggg 0110 0001 C Z C H 2 SUBB A, g 1110 1ggg 0110 0010 C Z C H 2 SUB A, g 1110 1ggg 0110 0011 C Z C H 2 AND A, g 1110 1ggg 0110 0100 Z Z - - 2 XOR A, g 1110 1ggg 0110 0101 Z Z - - 2 OR A, g 1110 1ggg 0110 0110 Z Z - - 2 CMP A, g 1110 1ggg 0110 0111 Z Z C H 2 */ m_cycles = 2; const int aluop = (opbyte1 & 0x7); const uint8_t result = do_alu_8bit(aluop, get_reg8(REG_A), get_reg8(opbyte0 & 0x7)); if (aluop != 0x07) // CMP doesn't write back { set_reg8(REG_A, result); } } void tlcs870_device::do_ALUOP_g_A(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles ADDC g, A 1110 1ggg 0110 1000 C Z C H 3 ADD g, A 1110 1ggg 0110 1001 C Z C H 3 SUBB g, A 1110 1ggg 0110 1010 C Z C H 3 SUB g, A 1110 1ggg 0110 1011 C Z C H 3 AND g, A 1110 1ggg 0110 1100 Z Z - - 3 XOR g, A 1110 1ggg 0110 1101 Z Z - - 3 OR g, A 1110 1ggg 0110 1110 Z Z - - 3 CMP g, A 1110 1ggg 0110 1111 Z Z C H 3 */ m_cycles = 3; const int aluop = (opbyte1 & 0x7); const uint8_t result = do_alu_8bit(aluop, get_reg8(opbyte0 & 0x7), get_reg8(REG_A)); if (aluop != 0x07) // CMP doesn't write back { set_reg8(opbyte0 & 0x7, result); } } void tlcs870_device::do_ALUOP_g_n(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles ADDC g, n 1110 1ggg 0111 0000 nnnn nnnn C Z C H 3 ADD g, n 1110 1ggg 0111 0001 nnnn nnnn C Z C H 3 SUBB g, n 1110 1ggg 0111 0010 nnnn nnnn C Z C H 3 SUB g, n 1110 1ggg 0111 0011 nnnn nnnn C Z C H 3 AND g, n 1110 1ggg 0111 0100 nnnn nnnn Z Z - - 3 XOR g, n 1110 1ggg 0111 0101 nnnn nnnn Z Z - - 3 OR g, n 1110 1ggg 0111 0110 nnnn nnnn Z Z - - 3 CMP g, n 1110 1ggg 0111 0111 nnnn nnnn Z Z C H 3 */ m_cycles = 3; const int aluop = (opbyte1 & 0x7); const uint8_t n = READ8(); const uint8_t result = do_alu_8bit(aluop, get_reg8(opbyte0 & 0x7), n); if (aluop != 0x07) // CMP doesn't write back { set_reg8(opbyte0 & 0x7, result); } } /**********************************************************************************************************************/ // (16-bit ALU handlers) /**********************************************************************************************************************/ void tlcs870_device::do_ALUOP_WA_gg(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles ADDC WA, gg 1110 10gg 0011 0000 C Z C U 4 ADD WA, gg 1110 10gg 0011 0001 C Z C U 4 SUBB WA, gg 1110 10gg 0011 0010 C Z C U 4 SUB WA, gg 1110 10gg 0011 0011 C Z C U 4 AND WA, gg 1110 10gg 0011 0100 Z Z - - 4 XOR WA, gg 1110 10gg 0011 0101 Z Z - - 4 OR WA, gg 1110 10gg 0011 0110 Z Z - - 4 CMP WA, gg 1110 10gg 0011 0111 Z Z C U 4 */ m_cycles = 4; const int aluop = (opbyte1 & 0x7); const uint16_t result = do_alu_16bit(aluop, get_reg16(REG_WA), get_reg16(opbyte0 & 0x3)); if (aluop != 0x07) // CMP doesn't write back { set_reg16(REG_WA, result); } } void tlcs870_device::do_ALUOP_gg_mn(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles ADDC gg, mn 1110 10gg 0011 1000 nnnn nnnn mmmm mmmm C Z C U 4 ADD gg, mn 1110 10gg 0011 1001 nnnn nnnn mmmm mmmm C Z C U 4 SUBB gg, mn 1110 10gg 0011 1010 nnnn nnnn mmmm mmmm C Z C U 4 SUB gg, mn 1110 10gg 0011 1011 nnnn nnnn mmmm mmmm C Z C U 4 AND gg, mn 1110 10gg 0011 1100 nnnn nnnn mmmm mmmm Z Z - - 4 XOR gg, mn 1110 10gg 0011 1101 nnnn nnnn mmmm mmmm Z Z - - 4 OR gg, mn 1110 10gg 0011 1110 nnnn nnnn mmmm mmmm Z Z - - 4 CMP gg, mn 1110 10gg 0011 1111 nnnn nnnn mmmm mmmm Z Z C U 4 */ m_cycles = 4; const int aluop = (opbyte1 & 0x7); const uint16_t mn = READ16(); const uint16_t result = do_alu_16bit(aluop, get_reg16(opbyte0 & 0x3), mn); if (aluop != 0x07) // CMP doesn't write back { set_reg16(opbyte0 & 0x3, result); } } /**********************************************************************************************************************/ // bit accesses /**********************************************************************************************************************/ // ops using (pp).g void tlcs870_device::do_SET_inppbit(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles SET (DE).g 1110 1ggg 1000 0010 Z * - - 5 SET (HL).g 1110 1ggg 1000 0011 Z * - - 5 */ m_cycles = 5; const uint8_t bitpos = get_reg8(opbyte0 & 7) & 0x7; const uint8_t bitused = 1 << bitpos; const uint16_t addr = get_reg16((opbyte1 & 1) + 2); // DE or HL uint8_t val = RM8(addr); if (val & bitused) // Zero flag gets set based on original value of bit? { clear_ZF(); clear_JF(); // 'Z' (so copy Z flag?) } else { set_ZF(); set_JF(); // 'Z' } val |= bitused; WM8(addr, val); } void tlcs870_device::do_CLR_inppbit(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles CLR (DE).g 1110 1ggg 1000 1010 Z * - - 5 CLR (HL).g 1110 1ggg 1000 1011 Z * - - 5 */ m_cycles = 5; const uint8_t bitpos = get_reg8(opbyte0 & 7) & 0x7; const uint8_t bitused = 1 << bitpos; const uint16_t addr = get_reg16((opbyte1 & 1) + 2); // DE or HL m_read_input_port = 0; // reads output latch, not actual ports if accessing memory mapped ports uint8_t val = RM8(addr); if (val & bitused) // Zero flag gets set based on original value of bit? { clear_ZF(); clear_JF(); // 'Z' (so copy Z flag?) } else { set_ZF(); set_JF(); // 'Z' } val &= ~bitused; WM8(addr, val); } void tlcs870_device::do_CPL_inpp_indirectbit(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles CPL (DE).g 1110 1ggg 1001 0010 Z * - - 5 CPL (HL).g 1110 1ggg 1001 0011 Z * - - 5 */ m_cycles = 5; const uint8_t bitpos = get_reg8(opbyte0 & 7) & 0x7; const uint8_t bitused = 1 << bitpos; const uint16_t addr = get_reg16((opbyte1 & 1) + 2); // DE or HL m_read_input_port = 0; // reads output latch, not actual ports if accessing memory mapped ports uint8_t val = RM8(addr); uint8_t bit = val & bitused; if (bit) // if the bit is set, clear the zero/jump flags and unset the bit { clear_ZF(); clear_JF(); val &= ~bitused; } else // if the bit isn't set, set the zero/jump flags and set the bit { set_ZF(); set_JF(); val |= bitused; } WM8(addr, val); } void tlcs870_device::do_LD_inpp_indirectbit_CF(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles LD (DE).g, CF 1110 1ggg 1001 1010 1 - - - 5 LD (HL).g, CF 1110 1ggg 1001 1011 1 - - - 5 */ m_cycles = 5; const uint8_t bitpos = get_reg8(opbyte0 & 7) & 0x7; const uint8_t bitused = 1 << bitpos; const uint16_t addr = get_reg16((opbyte1 & 1) + 2); // DE or HL uint8_t val = RM8(addr); if (is_CF()) // if carry flag is set, set the bit in val { val |= bitused; } else // if carry flag isn't set, clear the bit in val { val &= ~bitused; } // for this optype of operation ( LD *.b, CF ) the Jump Flag always ends up being 1 set_JF(); WM8(addr, val); } void tlcs870_device::do_LD_CF_inpp_indirectbit(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles LD CF, (DE).g 1110 1ggg 1001 1110 ~C - * - 4 LD CF, (HL).g 1110 1ggg 1001 1111 ~C - * - 4 aka aka TEST (pp).g */ m_cycles = 4; const uint8_t bitpos = get_reg8(opbyte0 & 7) & 0x7; const uint8_t bitused = 1 << bitpos; const uint16_t addr = get_reg16((opbyte1 & 1) + 2); // DE or HL const uint8_t val = RM8(addr); const uint8_t bit = val & bitused; bit ? set_CF() : clear_CF(); // for this optype of operation ( LD CF, *.b ) the Jump Flag always ends up the inverse of the Carry Flag bit ? clear_JF() : set_JF(); } // ops using g.b void tlcs870_device::do_SET_gbit(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles SET g.b 1110 1ggg 0100 0bbb Z * - - 3 */ m_cycles = 3; uint8_t val = get_reg8(opbyte0 & 0x7); const uint8_t bitpos = opbyte1 & 0x7; const int bitused = (1 << bitpos); if (val & bitused) // Zero flag gets set based on original value of bit? { clear_ZF(); clear_JF(); // 'Z' (so copy Z flag?) } else { set_ZF(); set_JF(); // 'Z' } val |= bitused; set_reg8(opbyte0 & 0x7, val); } void tlcs870_device::do_CLR_gbit(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles CLR g.b 1110 1ggg 0100 1bbb Z * - - 3 */ m_cycles = 3; uint8_t val = get_reg8(opbyte0 & 0x7); const uint8_t bitpos = opbyte1 & 0x7; const int bitused = (1 << bitpos); if (val & bitused) // Zero flag gets set based on original value of bit? { clear_ZF(); clear_JF(); // 'Z' (so copy Z flag?) } else { set_ZF(); set_JF(); // 'Z' } val &= ~bitused; set_reg8(opbyte0 & 0x7, val); } void tlcs870_device::do_CPL_gbit(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles CPL g.b 1110 1ggg 1100 0bbb Z * - - 3 */ m_cycles = 3; uint8_t val = get_reg8(opbyte0 & 0x7); const uint8_t bitpos = opbyte1 & 0x7; const int bitused = (1 << bitpos); uint8_t bit = val & bitused; if (bit) // if the bit is set, clear the zero/jump flags and unset the bit { clear_ZF(); clear_JF(); val &= ~bitused; } else // if the bit isn't set, set the zero/jump flags and set the bit { set_ZF(); set_JF(); val |= bitused; } set_reg8(opbyte0 & 0x7, val); } void tlcs870_device::do_LD_gbit_CF(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles LD g.b, CF 1110 1ggg 1100 1bbb 1 - - - 2 */ m_cycles = 2; uint8_t val = get_reg8(opbyte0 & 0x7); const uint8_t bitpos = opbyte1 & 0x7; const int bitused = (1 << bitpos); if (is_CF()) // if carry flag is set, set the bit in val { val |= bitused; } else // if carry flag isn't set, clear the bit in val { val &= ~bitused; } // for this optype of operation ( LD *.b, CF ) the Jump Flag always ends up being 1 set_JF(); set_reg8(opbyte0 & 0x7, val); } void tlcs870_device::do_XOR_CF_gbit(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles XOR CF, g.b 1110 1ggg 1101 0bbb ~C - * - 2 */ m_cycles = 2; const uint8_t bitpos = opbyte1 & 0x7; const uint8_t bitused = 1 << bitpos; const uint8_t g = get_reg8(opbyte0 & 0x7); const uint8_t bit = g & bitused; if (is_CF()) { if (bit) { clear_CF(); } else { set_CF(); } } else { if (bit) { set_CF(); } else { clear_CF(); } } // JF ends up being whatever the new value of CF is if (is_CF()) set_JF(); else clear_JF(); } void tlcs870_device::do_LD_CF_gbit(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles LD CF, g.b 1110 1ggg 1101 1bbb ~C - * - 2 aka TEST g.b */ m_cycles = 2; const uint8_t bitpos = opbyte1 & 0x7; const uint8_t bitused = 1 << bitpos; const uint8_t g = get_reg8(opbyte0 & 0x7); const uint8_t bit = g & bitused; bit ? set_CF() : clear_CF(); // for this optype of operation ( LD CF, *.b ) the Jump Flag always ends up the inverse of the Carry Flag bit ? clear_JF() : set_JF(); } /**********************************************************************************************************************/ // 16-bit /**********************************************************************************************************************/ void tlcs870_device::do_MUL_gg(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles MUL W, A not listed (redundant encoding?) ? ? ? ? ? MUL B, C 1110 1010 0000 0010 Z Z - - 8 MUL D, E 1110 1010 0000 0010 Z Z - - 8 MUL H, L 1110 1011 0000 0010 Z Z - - 8 aka MUL ggH, ggL (odd syntax, basically MUL gg) */ m_cycles = 8; const uint8_t reg = opbyte0 & 0x3; // opbyte0 & 4 = invalid? handle_mul(reg); // flag changes in handler } void tlcs870_device::do_DIV_gg_C(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles DIV WA, C not listed (redundant encoding?) ? ? ? ? ? DIV BC, C not listed (illegal?) ? ? ? ? ? DIV DE, C 1110 1010 0000 0011 Z Z C - 8 DIV HL, C 1110 1011 0000 0011 Z Z C - 8 */ m_cycles = 8; const uint8_t reg = opbyte0 & 0x3; // opbyte0 & 4 = invalid? handle_div(reg); // flag changes in handler } void tlcs870_device::do_POP_gg(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles POP gg 1110 10gg 0000 0110 - - - - 5 */ m_cycles = 5; m_sp.d += 2; const uint16_t val = RM16(m_sp.d - 1); set_reg16(opbyte0 & 3, val); // no flag changes } void tlcs870_device::do_PUSH_gg(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles PUSH gg 1110 10gg 0000 0111 - - - - 4 */ m_cycles = 4; const uint16_t val = get_reg16(opbyte0 & 3); WM16(m_sp.d - 1, val); m_sp.d -= 2; // no flag changes } void tlcs870_device::do_LD_SP_gg(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles LD SP, gg 1110 10gg 1111 1010 1 - - - 3 */ m_cycles = 3; m_sp.d = get_reg16(opbyte0 & 0x3); set_JF(); // no other flag changes for this type of LD } void tlcs870_device::do_LD_gg_SP(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles LD gg, SP 1110 10gg 1111 1011 1 - - - 3 */ m_cycles = 3; set_reg16(opbyte0 & 0x3, m_sp.d); set_JF(); // no other flag changes for this type of LD } void tlcs870_device::do_LD_rr_gg(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles LD rr, gg 1110 10gg 0001 00rr 1 - - - 2 */ m_cycles = 2; const uint16_t gg = get_reg16(opbyte0 & 0x3); set_reg16(opbyte1 & 0x3, gg); set_JF(); // no other flag changes for this type of LD } void tlcs870_device::do_XCH_rr_gg(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles XCH rr, gg 1110 10gg 0001 01rr 1 - - - 3 */ m_cycles = 3; const uint16_t gg = get_reg16(opbyte0 & 0x3); const uint16_t rr = get_reg16(opbyte1 & 0x3); set_reg16(opbyte1 & 0x3, gg); set_reg16(opbyte0 & 0x3, rr); set_JF(); } void tlcs870_device::do_CALL_gg(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles CALL gg 1110 10gg 1111 1100 - - - - 6 */ m_cycles = 6; const uint16_t val = get_reg16(opbyte0 & 3); WM16(m_sp.d - 1, m_addr); m_sp.d -= 2; m_addr = val; // no flag changes on call } void tlcs870_device::do_JP_gg(const uint8_t opbyte0, const uint8_t opbyte1) { /* OP (opbyte0) (immval0) (opbyte1) (immval1) (immval2) JF ZF CF HF cycles JP gg 1110 10gg 1111 1110 1 - - - 3 */ m_cycles = 3; const uint16_t val = get_reg16(opbyte0 & 3); m_addr = val; set_JF(); }