1267 lines
24 KiB
C++
1267 lines
24 KiB
C++
//---------------------------------------------------------------------------
|
|
// NEOPOP : Emulator as in Dreamland
|
|
//
|
|
// Copyright (c) 2001-2002 by neopop_uk
|
|
//---------------------------------------------------------------------------
|
|
|
|
//---------------------------------------------------------------------------
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version. See also the license.txt file for
|
|
// additional informations.
|
|
//---------------------------------------------------------------------------
|
|
|
|
/*
|
|
//---------------------------------------------------------------------------
|
|
//=========================================================================
|
|
|
|
TLCS900h_interpret_src.c
|
|
|
|
//=========================================================================
|
|
//---------------------------------------------------------------------------
|
|
|
|
History of changes:
|
|
===================
|
|
|
|
20 JUL 2002 - neopop_uk
|
|
=======================================
|
|
- Cleaned and tidied up for the source release
|
|
|
|
24 JUL 2002 - neopop_uk
|
|
=======================================
|
|
- Fixed S flag in "RRC (mem)"
|
|
|
|
25 JUL 2002 - neopop_uk
|
|
=======================================
|
|
- Removed unneeded Long mode from EX.
|
|
|
|
28 JUL 2002 - neopop_uk
|
|
=======================================
|
|
- Improved the LDIR/LDDR/CPIR/CPDR instructions so that they
|
|
finish with the correct register settings, even if there is
|
|
a memory error.
|
|
- Converted DIV/DIVS to use the generic function
|
|
|
|
16 AUG 2002 - neopop_uk
|
|
=======================================
|
|
- Replaced 'second & 7' with 'R', clearer, faster - and for some reason
|
|
more accurate... oh well!
|
|
- Fixed V flag emulation of INC/DEC, fixes "Cotton" menus
|
|
|
|
21 AUG 2002 - neopop_uk
|
|
=======================================
|
|
- Fixed "RR (mem)" - It was actually the [REG] version that hadn't been
|
|
changed to use memory accesses!
|
|
|
|
30 AUG 2002 - neopop_uk
|
|
=======================================
|
|
- Fixed "DIV RR,(mem)" in long mode, wrong operand size.
|
|
|
|
04 SEP 2002 - neopop_uk
|
|
=======================================
|
|
- Fixed GCC compatibility.
|
|
|
|
//---------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "../neopop.h"
|
|
#include "TLCS900h_interpret.h"
|
|
#include "TLCS900h_registers.h"
|
|
#include "../mem.h"
|
|
|
|
namespace TLCS900H
|
|
{
|
|
|
|
//=========================================================================
|
|
|
|
//===== PUSH (mem)
|
|
void srcPUSH()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: push8(loadB(mem)); break;
|
|
case 1: push16(loadW(mem)); break;
|
|
}
|
|
cycles = 7;
|
|
}
|
|
|
|
//===== RLD A,(mem)
|
|
void srcRLD()
|
|
{
|
|
uint8 al = REGA & 0xF, m, mh, ml;
|
|
|
|
m = loadB(mem);
|
|
mh = (m & 0xF0) >> 4;
|
|
ml = (m & 0x0F) << 4;
|
|
|
|
REGA = (REGA & 0xF0) | mh;
|
|
storeB(mem, ml | al);
|
|
|
|
SETFLAG_S(REGA & 0x80);
|
|
SETFLAG_Z(REGA == 0);
|
|
SETFLAG_H0
|
|
SETFLAG_N0
|
|
parityB(REGA);
|
|
|
|
cycles = 12;
|
|
}
|
|
|
|
//===== RRD A,(mem)
|
|
void srcRRD()
|
|
{
|
|
uint8 al = (REGA & 0xF) << 4, m, mh, ml;
|
|
|
|
m = loadB(mem);
|
|
mh = (m & 0xF0) >> 4;
|
|
ml = m & 0x0F;
|
|
|
|
REGA = (REGA & 0xF0) | ml;
|
|
storeB(mem, al | mh);
|
|
|
|
SETFLAG_S(REGA & 0x80);
|
|
SETFLAG_Z(REGA == 0);
|
|
SETFLAG_H0
|
|
SETFLAG_N0
|
|
parityB(REGA);
|
|
|
|
cycles = 12;
|
|
}
|
|
|
|
//===== LDI
|
|
void srcLDI()
|
|
{
|
|
uint8 dst = 2/*XDE*/, src = 3/*XHL*/;
|
|
if ((first & 0xF) == 5) { dst = 4/*XIX*/; src = 5/*XIY*/; }
|
|
|
|
switch(size)
|
|
{
|
|
case 0:
|
|
storeB(regL(dst), loadB(regL(src)));
|
|
regL(dst) += 1;
|
|
regL(src) += 1;
|
|
break;
|
|
|
|
case 1:
|
|
storeW(regL(dst), loadW(regL(src)));
|
|
regL(dst) += 2;
|
|
regL(src) += 2;
|
|
break;
|
|
}
|
|
|
|
REGBC --;
|
|
SETFLAG_V(REGBC);
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
cycles = 10;
|
|
}
|
|
|
|
//===== LDIR
|
|
void srcLDIR()
|
|
{
|
|
uint8 dst = 2/*XDE*/, src = 3/*XHL*/;
|
|
if ((first & 0xF) == 5) { dst = 4/*XIX*/; src = 5/*XIY*/; }
|
|
|
|
cycles = 10;
|
|
|
|
do
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: if (debug_abort_memory == FALSE)
|
|
storeB(regL(dst), loadB(regL(src)));
|
|
regL(dst) += 1;
|
|
regL(src) += 1;
|
|
break;
|
|
|
|
case 1: if (debug_abort_memory == FALSE)
|
|
storeW(regL(dst), loadW(regL(src)));
|
|
regL(dst) += 2;
|
|
regL(src) += 2;
|
|
break;
|
|
}
|
|
|
|
REGBC --;
|
|
SETFLAG_V(REGBC);
|
|
|
|
cycles += 14;
|
|
}
|
|
while (FLAG_V);
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
}
|
|
|
|
//===== LDD
|
|
void srcLDD()
|
|
{
|
|
uint8 dst = 2/*XDE*/, src = 3/*XHL*/;
|
|
if ((first & 0xF) == 5) { dst = 4/*XIX*/; src = 5/*XIY*/; }
|
|
|
|
switch(size)
|
|
{
|
|
case 0:
|
|
storeB(regL(dst), loadB(regL(src)));
|
|
regL(dst) -= 1;
|
|
regL(src) -= 1;
|
|
break;
|
|
|
|
case 1:
|
|
storeW(regL(dst), loadW(regL(src)));
|
|
regL(dst) -= 2;
|
|
regL(src) -= 2;
|
|
break;
|
|
}
|
|
|
|
REGBC --;
|
|
SETFLAG_V(REGBC);
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
cycles = 10;
|
|
}
|
|
|
|
//===== LDDR
|
|
void srcLDDR()
|
|
{
|
|
uint8 dst = 2/*XDE*/, src = 3/*XHL*/;
|
|
if ((first & 0xF) == 5) { dst = 4/*XIX*/; src = 5/*XIY*/; }
|
|
|
|
cycles = 10;
|
|
|
|
do
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0:
|
|
if (debug_abort_memory == FALSE)
|
|
storeB(regL(dst), loadB(regL(src)));
|
|
regL(dst) -= 1;
|
|
regL(src) -= 1;
|
|
break;
|
|
|
|
case 1:
|
|
if (debug_abort_memory == FALSE)
|
|
storeW(regL(dst), loadW(regL(src)));
|
|
regL(dst) -= 2;
|
|
regL(src) -= 2;
|
|
break;
|
|
}
|
|
|
|
REGBC --;
|
|
SETFLAG_V(REGBC);
|
|
|
|
cycles += 14;
|
|
}
|
|
while (FLAG_V);
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
}
|
|
|
|
//===== CPI
|
|
void srcCPI()
|
|
{
|
|
uint8 R = first & 7;
|
|
|
|
switch(size)
|
|
{
|
|
case 0: generic_SUB_B(REGA, loadB(regL(R)));
|
|
regL(R) ++; break;
|
|
|
|
case 1: generic_SUB_W(REGWA, loadW(regL(R)));
|
|
regL(R) += 2; break;
|
|
}
|
|
|
|
REGBC --;
|
|
SETFLAG_V(REGBC);
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== CPIR
|
|
void srcCPIR()
|
|
{
|
|
uint8 R = first & 7;
|
|
|
|
cycles = 10;
|
|
|
|
do
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: if (debug_abort_memory == FALSE)
|
|
generic_SUB_B(REGA, loadB(regL(R)));
|
|
regL(R) ++; break;
|
|
|
|
case 1: if (debug_abort_memory == FALSE)
|
|
generic_SUB_W(REGWA, loadW(regL(R)));
|
|
regL(R) += 2; break;
|
|
}
|
|
|
|
REGBC --;
|
|
SETFLAG_V(REGBC);
|
|
|
|
cycles += 14;
|
|
}
|
|
while (FLAG_V && (FLAG_Z == FALSE));
|
|
}
|
|
|
|
//===== CPD
|
|
void srcCPD()
|
|
{
|
|
uint8 R = first & 7;
|
|
|
|
switch(size)
|
|
{
|
|
case 0: generic_SUB_B(REGA, loadB(regL(R)));
|
|
regL(R) --; break;
|
|
|
|
case 1: generic_SUB_W(REGWA, loadW(regL(R)));
|
|
regL(R) -= 2; break;
|
|
}
|
|
|
|
REGBC --;
|
|
SETFLAG_V(REGBC);
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== CPDR
|
|
void srcCPDR()
|
|
{
|
|
uint8 R = first & 7;
|
|
|
|
cycles = 10;
|
|
|
|
do
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: if (debug_abort_memory == FALSE)
|
|
generic_SUB_B(REGA, loadB(regL(R)));
|
|
regL(R) -= 1; break;
|
|
|
|
case 1: if (debug_abort_memory == FALSE)
|
|
generic_SUB_W(REGWA, loadW(regL(R)));
|
|
regL(R) -= 2; break;
|
|
}
|
|
|
|
REGBC --;
|
|
SETFLAG_V(REGBC);
|
|
|
|
cycles += 14;
|
|
}
|
|
while (FLAG_V && (FLAG_Z == FALSE));
|
|
}
|
|
|
|
//===== LD (nn),(mem)
|
|
void srcLD16m()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: storeB(fetch16(), loadB(mem)); break;
|
|
case 1: storeW(fetch16(), loadW(mem)); break;
|
|
}
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== LD R,(mem)
|
|
void srcLD()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: regB(R) = loadB(mem); cycles = 4; break;
|
|
case 1: regW(R) = loadW(mem); cycles = 4; break;
|
|
case 2: regL(R) = loadL(mem); cycles = 6; break;
|
|
}
|
|
}
|
|
|
|
//===== EX (mem),R
|
|
void srcEX()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 temp = regB(R);
|
|
regB(R) = loadB(mem);
|
|
storeB(mem, temp); break; }
|
|
|
|
case 1: { uint16 temp = regW(R);
|
|
regW(R) = loadW(mem);
|
|
storeW(mem, temp); break; }
|
|
}
|
|
|
|
cycles = 6;
|
|
}
|
|
|
|
//===== ADD (mem),#
|
|
void srcADDi()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: storeB(mem, generic_ADD_B(loadB(mem), FETCH8)); cycles = 7;break;
|
|
case 1: storeW(mem, generic_ADD_W(loadW(mem), fetch16())); cycles = 8;break;
|
|
}
|
|
}
|
|
|
|
//===== ADC (mem),#
|
|
void srcADCi()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: storeB(mem, generic_ADC_B(loadB(mem), FETCH8)); cycles = 7;break;
|
|
case 1: storeW(mem, generic_ADC_W(loadW(mem), fetch16())); cycles = 8;break;
|
|
}
|
|
}
|
|
|
|
//===== SUB (mem),#
|
|
void srcSUBi()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: storeB(mem, generic_SUB_B(loadB(mem), FETCH8)); cycles = 7;break;
|
|
case 1: storeW(mem, generic_SUB_W(loadW(mem), fetch16())); cycles = 8;break;
|
|
}
|
|
}
|
|
|
|
//===== SBC (mem),#
|
|
void srcSBCi()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: storeB(mem, generic_SBC_B(loadB(mem), FETCH8)); cycles = 7;break;
|
|
case 1: storeW(mem, generic_SBC_W(loadW(mem), fetch16())); cycles = 8;break;
|
|
}
|
|
}
|
|
|
|
//===== AND (mem),#
|
|
void srcANDi()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = loadB(mem) & FETCH8;
|
|
storeB(mem, result);
|
|
SETFLAG_S(result & 0x80);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
cycles = 7;
|
|
break; }
|
|
|
|
case 1: { uint16 result = loadW(mem) & fetch16();
|
|
storeW(mem, result);
|
|
SETFLAG_S(result & 0x8000);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
cycles = 8;
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H1;
|
|
SETFLAG_N0;
|
|
SETFLAG_C0;
|
|
}
|
|
|
|
//===== OR (mem),#
|
|
void srcORi()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = loadB(mem) | FETCH8;
|
|
storeB(mem, result);
|
|
SETFLAG_S(result & 0x80);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
cycles = 7;
|
|
break; }
|
|
|
|
case 1: { uint16 result = loadW(mem) | fetch16();
|
|
storeW(mem, result);
|
|
SETFLAG_S(result & 0x8000);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
cycles = 8;
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
SETFLAG_C0;
|
|
}
|
|
|
|
//===== XOR (mem),#
|
|
void srcXORi()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = loadB(mem) ^ FETCH8;
|
|
storeB(mem, result);
|
|
SETFLAG_S(result & 0x80);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
cycles = 7;
|
|
break; }
|
|
|
|
case 1: { uint16 result = loadW(mem) ^ fetch16();
|
|
storeW(mem, result);
|
|
SETFLAG_S(result & 0x8000);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
cycles = 8;
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
SETFLAG_C0;
|
|
}
|
|
|
|
//===== CP (mem),#
|
|
void srcCPi()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: generic_SUB_B(loadB(mem), FETCH8); break;
|
|
case 1: generic_SUB_W(loadW(mem), fetch16()); break;
|
|
}
|
|
|
|
cycles = 6;
|
|
}
|
|
|
|
//===== MUL RR,(mem)
|
|
void srcMUL()
|
|
{
|
|
uint8 target = get_RR_Target();
|
|
if (target == 0x80)
|
|
{
|
|
instruction_error("src: MUL bad \'RR\' dst code");
|
|
return;
|
|
}
|
|
|
|
switch(size)
|
|
{
|
|
case 0: rCodeW(target) = (rCodeW(target) & 0xFF) * loadB(mem);
|
|
cycles = 18; break;
|
|
case 1: rCodeL(target) = (rCodeL(target) & 0xFFFF) * loadW(mem);
|
|
cycles = 26; break;
|
|
}
|
|
}
|
|
|
|
//===== MULS RR,(mem)
|
|
void srcMULS()
|
|
{
|
|
uint8 target = get_RR_Target();
|
|
if (target == 0x80)
|
|
{
|
|
instruction_error("src: MUL bad \'RR\' dst code");
|
|
return;
|
|
}
|
|
|
|
switch(size)
|
|
{
|
|
case 0: rCodeW(target) = (int8)(rCodeW(target) & 0xFF) * (int8)loadB(mem);
|
|
cycles = 18; break;
|
|
case 1: rCodeL(target) = (int16)(rCodeL(target) & 0xFFFF) * (int16)loadW(mem);
|
|
cycles = 26; break;
|
|
}
|
|
}
|
|
|
|
//===== DIV RR,(mem)
|
|
void srcDIV()
|
|
{
|
|
uint8 target = get_RR_Target();
|
|
if (target == 0x80)
|
|
{
|
|
instruction_error("src: DIV bad \'RR\' dst code");
|
|
return;
|
|
}
|
|
|
|
switch(size)
|
|
{
|
|
case 0: { rCodeW(target) = generic_DIV_B(rCodeW(target), loadB(mem));
|
|
cycles = 22;
|
|
break; }
|
|
|
|
case 1: { rCodeL(target) = generic_DIV_W(rCodeL(target), loadW(mem));
|
|
cycles = 30;
|
|
break; }
|
|
}
|
|
}
|
|
|
|
//===== DIVS RR,(mem)
|
|
void srcDIVS()
|
|
{
|
|
uint8 target = get_RR_Target();
|
|
if (target == 0x80)
|
|
{
|
|
instruction_error("src: DIVS bad \'RR\' dst code");
|
|
return;
|
|
}
|
|
|
|
switch(size)
|
|
{
|
|
case 0: { rCodeW(target) = generic_DIVS_B(rCodeW(target), loadB(mem));
|
|
cycles = 24;
|
|
break; }
|
|
|
|
case 1: { rCodeL(target) = generic_DIVS_W(rCodeL(target), loadW(mem));
|
|
cycles = 32;
|
|
break; }
|
|
}
|
|
}
|
|
|
|
//===== INC #3,(mem)
|
|
void srcINC()
|
|
{
|
|
uint8 val = R;
|
|
if (val == 0)
|
|
val = 8;
|
|
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 dst = loadB(mem);
|
|
uint32 resultC = dst + val;
|
|
uint8 half = (dst & 0xF) + val;
|
|
uint8 result = (uint8)(resultC & 0xFF);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_H(half > 0xF);
|
|
SETFLAG_S(result & 0x80);
|
|
SETFLAG_N0;
|
|
|
|
if (((int8)dst >= 0) && ((int8)result < 0))
|
|
{SETFLAG_V1} else {SETFLAG_V0}
|
|
|
|
storeB(mem, result);
|
|
break; }
|
|
|
|
case 1: { uint16 dst = loadW(mem);
|
|
uint32 resultC = dst + val;
|
|
uint8 half = (dst & 0xF) + val;
|
|
uint16 result = (uint16)(resultC & 0xFFFF);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_H(half > 0xF);
|
|
SETFLAG_S(result & 0x8000);
|
|
SETFLAG_N0;
|
|
|
|
if (((int16)dst >= 0) && ((int16)result < 0))
|
|
{SETFLAG_V1} else {SETFLAG_V0}
|
|
|
|
storeW(mem, result);
|
|
break; }
|
|
}
|
|
|
|
cycles = 6;
|
|
}
|
|
|
|
//===== DEC #3,(mem)
|
|
void srcDEC()
|
|
{
|
|
uint8 val = R;
|
|
if (val == 0)
|
|
val = 8;
|
|
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 dst = loadB(mem);
|
|
uint32 resultC = dst - val;
|
|
uint8 half = (dst & 0xF) - val;
|
|
uint8 result = (uint8)(resultC & 0xFF);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_H(half > 0xF);
|
|
SETFLAG_S(result & 0x80);
|
|
SETFLAG_N1;
|
|
|
|
if (((int8)dst < 0) && ((int8)result >= 0))
|
|
{SETFLAG_V1} else {SETFLAG_V0}
|
|
|
|
storeB(mem, result);
|
|
break; }
|
|
|
|
case 1: { uint16 dst = loadW(mem);
|
|
uint32 resultC = dst - val;
|
|
uint8 half = (dst & 0xF) - val;
|
|
uint16 result = (uint16)(resultC & 0xFFFF);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_H(half > 0xF);
|
|
SETFLAG_S(result & 0x8000);
|
|
SETFLAG_N1;
|
|
|
|
if (((int16)dst < 0) && ((int16)result >= 0))
|
|
{SETFLAG_V1} else {SETFLAG_V0}
|
|
|
|
storeW(mem, result);
|
|
break; }
|
|
}
|
|
|
|
cycles = 6;
|
|
}
|
|
|
|
//===== RLC (mem)
|
|
void srcRLC()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = loadB(mem);
|
|
SETFLAG_C(result & 0x80);
|
|
result <<= 1;
|
|
if (FLAG_C) result |= 1;
|
|
storeB(mem, result);
|
|
SETFLAG_S(result & 0x80);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
break; }
|
|
|
|
case 1: { uint16 result = loadW(mem);
|
|
SETFLAG_C(result & 0x8000);
|
|
result <<= 1;
|
|
if (FLAG_C) result |= 1;
|
|
storeW(mem, result);
|
|
SETFLAG_S(result & 0x8000);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== RRC (mem)
|
|
void srcRRC()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 data = loadB(mem), result;
|
|
SETFLAG_C(data & 1);
|
|
result = data >> 1;
|
|
if (FLAG_C) result |= 0x80;
|
|
storeB(mem, result);
|
|
SETFLAG_S(result & 0x80);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
break; }
|
|
|
|
case 1: { uint16 data = loadW(mem), result;
|
|
SETFLAG_C(data & 1);
|
|
result = data >> 1;
|
|
if (FLAG_C) result |= 0x8000;
|
|
storeW(mem, result);
|
|
SETFLAG_S(result & 0x8000);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== RL (mem)
|
|
void srcRL()
|
|
{
|
|
bool tempC;
|
|
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = loadB(mem);
|
|
tempC = FLAG_C;
|
|
SETFLAG_C(result & 0x80);
|
|
result <<= 1;
|
|
if (tempC) result |= 1;
|
|
storeB(mem, result);
|
|
SETFLAG_S(result & 0x80);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
break; }
|
|
|
|
case 1: { uint16 result = loadW(mem);
|
|
tempC = FLAG_C;
|
|
SETFLAG_C(result & 0x8000);
|
|
result <<= 1;
|
|
if (tempC) result |= 1;
|
|
storeW(mem, result);
|
|
SETFLAG_S(result & 0x8000);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
break; }
|
|
}
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== RR (mem)
|
|
void srcRR()
|
|
{
|
|
bool tempC;
|
|
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = loadB(mem);
|
|
tempC = FLAG_C;
|
|
SETFLAG_C(result & 1);
|
|
result >>= 1;
|
|
if (tempC) result |= 0x80;
|
|
storeB(mem, result);
|
|
SETFLAG_S(result & 0x80);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
break; }
|
|
|
|
case 1: { uint16 result = loadW(mem);
|
|
tempC = FLAG_C;
|
|
SETFLAG_C(result & 1);
|
|
result >>= 1;
|
|
if (tempC) result |= 0x8000;
|
|
storeW(mem, result);
|
|
SETFLAG_S(result & 0x8000);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
break; }
|
|
}
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== SLA (mem)
|
|
void srcSLA()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result, data = loadB(mem);
|
|
SETFLAG_C(data & 0x80);
|
|
result = ((int8)data << 1);
|
|
SETFLAG_S(result & 0x80);
|
|
storeB(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
break; }
|
|
|
|
case 1: { uint16 result, data = loadW(mem);
|
|
SETFLAG_C(data & 0x8000);
|
|
result = ((int16)data << 1);
|
|
SETFLAG_S(result & 0x8000);
|
|
storeW(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== SRA (mem)
|
|
void srcSRA()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result, data = loadB(mem);
|
|
SETFLAG_C(data & 0x1);
|
|
result = ((int8)data >> 1);
|
|
SETFLAG_S(result & 0x80);
|
|
storeB(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
break; }
|
|
|
|
case 1: { uint16 result, data = loadW(mem);
|
|
SETFLAG_C(data & 0x1);
|
|
result = ((int16)data >> 1);
|
|
SETFLAG_S(result & 0x8000);
|
|
storeW(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== SLL (mem)
|
|
void srcSLL()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result, data = loadB(mem);
|
|
SETFLAG_C(data & 0x80);
|
|
result = (data << 1);
|
|
SETFLAG_S(result & 0x80);
|
|
storeB(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
break; }
|
|
|
|
case 1: { uint16 result, data = loadW(mem);
|
|
SETFLAG_C(data & 0x8000);
|
|
result = (data << 1);
|
|
SETFLAG_S(result & 0x8000);
|
|
storeW(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== SRL (mem)
|
|
void srcSRL()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result, data = loadB(mem);
|
|
SETFLAG_C(data & 0x01);
|
|
result = (data >> 1);
|
|
SETFLAG_S(result & 0x80);
|
|
storeB(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
parityB(result);
|
|
break; }
|
|
|
|
case 1: { uint16 result, data = loadW(mem);
|
|
SETFLAG_C(data & 0x0001);
|
|
result = (data >> 1);
|
|
SETFLAG_S(result & 0x8000);
|
|
storeW(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
parityW(result);
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
|
|
cycles = 8;
|
|
}
|
|
|
|
//===== ADD R,(mem)
|
|
void srcADDRm()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: regB(R) = generic_ADD_B(regB(R), loadB(mem)); cycles = 4;break;
|
|
case 1: regW(R) = generic_ADD_W(regW(R), loadW(mem)); cycles = 4;break;
|
|
case 2: regL(R) = generic_ADD_L(regL(R), loadL(mem)); cycles = 6;break;
|
|
}
|
|
}
|
|
|
|
//===== ADD (mem),R
|
|
void srcADDmR()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: storeB(mem, generic_ADD_B(loadB(mem), regB(R))); cycles = 6;break;
|
|
case 1: storeW(mem, generic_ADD_W(loadW(mem), regW(R))); cycles = 6;break;
|
|
case 2: storeL(mem, generic_ADD_L(loadL(mem), regL(R))); cycles = 10;break;
|
|
}
|
|
}
|
|
|
|
//===== ADC R,(mem)
|
|
void srcADCRm()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: regB(R) = generic_ADC_B(regB(R), loadB(mem)); cycles = 4;break;
|
|
case 1: regW(R) = generic_ADC_W(regW(R), loadW(mem)); cycles = 4;break;
|
|
case 2: regL(R) = generic_ADC_L(regL(R), loadL(mem)); cycles = 6;break;
|
|
}
|
|
}
|
|
|
|
//===== ADC (mem),R
|
|
void srcADCmR()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: storeB(mem, generic_ADC_B(loadB(mem), regB(R))); cycles = 6;break;
|
|
case 1: storeW(mem, generic_ADC_W(loadW(mem), regW(R))); cycles = 6;break;
|
|
case 2: storeL(mem, generic_ADC_L(loadL(mem), regL(R))); cycles = 10;break;
|
|
}
|
|
}
|
|
|
|
//===== SUB R,(mem)
|
|
void srcSUBRm()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: regB(R) = generic_SUB_B(regB(R), loadB(mem)); cycles = 4;break;
|
|
case 1: regW(R) = generic_SUB_W(regW(R), loadW(mem)); cycles = 4;break;
|
|
case 2: regL(R) = generic_SUB_L(regL(R), loadL(mem)); cycles = 6;break;
|
|
}
|
|
}
|
|
|
|
//===== SUB (mem),R
|
|
void srcSUBmR()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: storeB(mem, generic_SUB_B(loadB(mem), regB(R))); cycles = 6;break;
|
|
case 1: storeW(mem, generic_SUB_W(loadW(mem), regW(R))); cycles = 6;break;
|
|
case 2: storeL(mem, generic_SUB_L(loadL(mem), regL(R))); cycles = 10;break;
|
|
}
|
|
}
|
|
|
|
//===== SBC R,(mem)
|
|
void srcSBCRm()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: regB(R) = generic_SBC_B(regB(R), loadB(mem)); cycles = 4;break;
|
|
case 1: regW(R) = generic_SBC_W(regW(R), loadW(mem)); cycles = 4;break;
|
|
case 2: regL(R) = generic_SBC_L(regL(R), loadL(mem)); cycles = 6;break;
|
|
}
|
|
}
|
|
|
|
//===== SBC (mem),R
|
|
void srcSBCmR()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: storeB(mem, generic_SBC_B(loadB(mem), regB(R))); cycles = 6;break;
|
|
case 1: storeW(mem, generic_SBC_W(loadW(mem), regW(R))); cycles = 6;break;
|
|
case 2: storeL(mem, generic_SBC_L(loadL(mem), regL(R))); cycles = 10;break;
|
|
}
|
|
}
|
|
|
|
//===== AND R,(mem)
|
|
void srcANDRm()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = regB(R) & loadB(mem);
|
|
regB(R) = result;
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80);
|
|
parityB(result);
|
|
cycles = 4;
|
|
break; }
|
|
|
|
case 1: { uint16 result = regW(R) & loadW(mem);
|
|
regW(R) = result;
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x8000);
|
|
parityW(result);
|
|
cycles = 4;
|
|
break; }
|
|
|
|
case 2: { uint32 result = regL(R) & loadL(mem);
|
|
regL(R) = result;
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80000000);
|
|
cycles = 6;
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H1;
|
|
SETFLAG_N0;
|
|
SETFLAG_C0;
|
|
}
|
|
|
|
//===== AND (mem),R
|
|
void srcANDmR()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = regB(R) & loadB(mem);
|
|
storeB(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80);
|
|
parityB(result);
|
|
cycles = 6;
|
|
break; }
|
|
|
|
case 1: { uint16 result = regW(R) & loadW(mem);
|
|
storeW(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x8000);
|
|
parityW(result);
|
|
cycles = 6;
|
|
break; }
|
|
|
|
case 2: { uint32 result = regL(R) & loadL(mem);
|
|
storeL(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80000000);
|
|
cycles = 10;
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H1;
|
|
SETFLAG_N0;
|
|
SETFLAG_C0;
|
|
}
|
|
|
|
//===== XOR R,(mem)
|
|
void srcXORRm()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = regB(R) ^ loadB(mem);
|
|
regB(R) = result;
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80);
|
|
parityB(result);
|
|
cycles = 4;
|
|
break; }
|
|
|
|
case 1: { uint16 result = regW(R) ^ loadW(mem);
|
|
regW(R) = result;
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x8000);
|
|
parityW(result);
|
|
cycles = 4;
|
|
break; }
|
|
|
|
case 2: { uint32 result = regL(R) ^ loadL(mem);
|
|
regL(R) = result;
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80000000);
|
|
cycles = 6;
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
SETFLAG_C0;
|
|
}
|
|
|
|
//===== XOR (mem),R
|
|
void srcXORmR()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = regB(R) ^ loadB(mem);
|
|
storeB(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80);
|
|
parityB(result);
|
|
cycles = 6;
|
|
break; }
|
|
|
|
case 1: { uint16 result = regW(R) ^ loadW(mem);
|
|
storeW(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x8000);
|
|
parityW(result);
|
|
cycles = 6;
|
|
break; }
|
|
|
|
case 2: { uint32 result = regL(R) ^ loadL(mem);
|
|
storeL(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80000000);
|
|
cycles = 10;
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
SETFLAG_C0;
|
|
}
|
|
|
|
//===== OR R,(mem)
|
|
void srcORRm()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = regB(R) | loadB(mem);
|
|
regB(R) = result;
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80);
|
|
parityB(result);
|
|
cycles = 4;
|
|
break; }
|
|
|
|
case 1: { uint16 result = regW(R) | loadW(mem);
|
|
regW(R) = result;
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x8000);
|
|
parityW(result);
|
|
cycles = 4;
|
|
break; }
|
|
|
|
case 2: { uint32 result = regL(R) | loadL(mem);
|
|
regL(R) = result;
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80000000);
|
|
cycles = 6;
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
SETFLAG_C0;
|
|
}
|
|
|
|
//===== OR (mem),R
|
|
void srcORmR()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: { uint8 result = regB(R) | loadB(mem);
|
|
storeB(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80);
|
|
parityB(result);
|
|
cycles = 6;
|
|
break; }
|
|
|
|
case 1: { uint16 result = regW(R) | loadW(mem);
|
|
storeW(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x8000);
|
|
parityW(result);
|
|
cycles = 6;
|
|
break; }
|
|
|
|
case 2: { uint32 result = regL(R) | loadL(mem);
|
|
storeL(mem, result);
|
|
SETFLAG_Z(result == 0);
|
|
SETFLAG_S(result & 0x80000000);
|
|
cycles = 10;
|
|
break; }
|
|
}
|
|
|
|
SETFLAG_H0;
|
|
SETFLAG_N0;
|
|
SETFLAG_C0;
|
|
}
|
|
|
|
//===== CP R,(mem)
|
|
void srcCPRm()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: generic_SUB_B(regB(R), loadB(mem)); cycles = 4; break;
|
|
case 1: generic_SUB_W(regW(R), loadW(mem)); cycles = 4; break;
|
|
case 2: generic_SUB_L(regL(R), loadL(mem)); cycles = 6; break;
|
|
}
|
|
}
|
|
|
|
//===== CP (mem),R
|
|
void srcCPmR()
|
|
{
|
|
switch(size)
|
|
{
|
|
case 0: generic_SUB_B(loadB(mem), regB(R)); break;
|
|
case 1: generic_SUB_W(loadW(mem), regW(R)); break;
|
|
case 2: generic_SUB_L(loadL(mem), regL(R)); break;
|
|
}
|
|
|
|
cycles = 6;
|
|
}
|
|
};
|
|
//=============================================================================
|