mirror of
https://github.com/holub/mame
synced 2025-04-19 07:00:31 +03:00
950 lines
28 KiB
C++
950 lines
28 KiB
C++
// 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();
|
|
}
|