参考
いろいろ注意
- arduinoの予定は、未定
結果
プログラム
オンラインコンパイラpaiza
#include <iostream>
using namespace std;
#include <stdio.h>
#include <string.h>
#include "z80.hpp"
// MMU; Memory Management Unit
// z80.hpp では MMU は提供していないので自前で準備する必要があります。
// 以下、64KB RAM と 256 bytes の I/O を持つシンプルな MMU の実装例です。
class MMU {
public:
unsigned char RAM[0x10000];
unsigned char IO[0x100];
MMU() {
memset(&RAM, 0, sizeof(RAM));
memset(&IO, 0, sizeof(IO));
}
};
// メモリアドレス(addr)から1バイト読み込む処理
static unsigned char readByte(void* arg, unsigned short addr) {
return ((MMU*)arg)->RAM[addr];
}
// メモリアドレス(addr) へ 1 byte の値(value)を書き込む処理
static void writeByte(void* arg, unsigned short addr, unsigned char value)
{
((MMU*)arg)->RAM[addr] = value;
}
// I/O ポート (port) からの入力処理
static unsigned char inPort(void* arg, unsigned char port)
{
return ((MMU*)arg)->IO[port];
}
// I/O ポート (port) へ 値(value) を書き込む処理
static void outPort(void* arg, unsigned char port, unsigned char value) {
((MMU*)arg)->IO[port] = value;
}
int main(void){
MMU mmu;
Z80 z80(readByte, writeByte, inPort, outPort, &mmu);
printf("BYE\n");
return 0;
}
z80.hpp
/**
* SUZUKI PLAN - Z80 Emulator
* -----------------------------------------------------------------------------
* The MIT License (MIT)
*
* Copyright (c) 2019 Yoji Suzuki.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* -----------------------------------------------------------------------------
*/
#ifndef INCLUDE_Z80_HPP
#define INCLUDE_Z80_HPP
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(Z80_DISABLE_BREAKPOINT) || !defined(Z80_DISABLE_NESTCHECK)
#include <map>
#include <vector>
#endif
#ifndef Z80_NO_FUNCTIONAL
#include <functional>
#endif
#ifndef Z80_NO_EXCEPTION
#include <stdexcept>
#endif
class Z80
{
public: // Interface data types
struct WaitClocks {
int fetch; // Wait T-cycle (Hz) before fetching instruction (default is 0 = no wait)
int fetchM; // Wait T-cycle (Hz) before fetching multi-bytes instruction (default is 0 = no wait)
int read; // Wait T-cycle (Hz) before to read memory (default is 0 = no wait)
int write; // Wait T-cycle (Hz) before to write memory (default is 0 = no wait)
} wtc;
struct RegisterPair {
unsigned char A;
unsigned char F;
unsigned char B;
unsigned char C;
unsigned char D;
unsigned char E;
unsigned char H;
unsigned char L;
};
struct Register {
struct RegisterPair pair;
struct RegisterPair back;
unsigned short PC;
unsigned short SP;
unsigned short IX;
unsigned short IY;
unsigned short interruptVector; // interrupt vector for IRQ
unsigned short interruptAddrN; // interrupt address for NMI
unsigned short WZ;
unsigned short reserved16;
unsigned char R;
unsigned char I;
unsigned char IFF;
unsigned char interrupt; // NI-- --mm (N: NMI, I: IRQ, mm: mode)
unsigned char consumeClockCounter;
unsigned char execEI;
unsigned char reserved8[2];
} reg;
inline unsigned char flagS() { return 0b10000000; }
inline unsigned char flagZ() { return 0b01000000; }
inline unsigned char flagY() { return 0b00100000; }
inline unsigned char flagH() { return 0b00010000; }
inline unsigned char flagX() { return 0b00001000; }
inline unsigned char flagPV() { return 0b00000100; }
inline unsigned char flagN() { return 0b00000010; }
inline unsigned char flagC() { return 0b00000001; }
inline unsigned char readByte(unsigned short addr, int clock = 4)
{
#ifndef Z80_DISABLE_BREAKPOINT
if (clock && wtc.read) consumeClock(wtc.read);
unsigned char byte = CB.read(CB.arg, addr);
if (clock) consumeClock(clock);
#else
consumeClock(wtc.read);
unsigned char byte = CB.read(CB.arg, addr);
consumeClock(clock);
#endif
return byte;
}
inline void writeByte(unsigned short addr, unsigned char value, int clock = 4)
{
consumeClock(wtc.write);
CB.write(CB.arg, addr, value);
consumeClock(clock);
}
private: // Internal functions & variables
// bit table
const unsigned char bits[8] = {0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00100000, 0b01000000, 0b10000000};
// flag setter
inline void setFlagS() { reg.pair.F |= flagS(); }
inline void setFlagZ() { reg.pair.F |= flagZ(); }
inline void setFlagY() { reg.pair.F |= flagY(); }
inline void setFlagH() { reg.pair.F |= flagH(); }
inline void setFlagX() { reg.pair.F |= flagX(); }
inline void setFlagPV() { reg.pair.F |= flagPV(); }
inline void setFlagN() { reg.pair.F |= flagN(); }
inline void setFlagC() { reg.pair.F |= flagC(); }
inline void resetFlagS() { reg.pair.F &= ~flagS(); }
inline void resetFlagZ() { reg.pair.F &= ~flagZ(); }
inline void resetFlagY() { reg.pair.F &= ~flagY(); }
inline void resetFlagH() { reg.pair.F &= ~flagH(); }
inline void resetFlagX() { reg.pair.F &= ~flagX(); }
inline void resetFlagPV() { reg.pair.F &= ~flagPV(); }
inline void resetFlagN() { reg.pair.F &= ~flagN(); }
inline void resetFlagC() { reg.pair.F &= ~flagC(); }
inline void setFlagS(bool on) { on ? setFlagS() : resetFlagS(); }
inline void setFlagZ(bool on) { on ? setFlagZ() : resetFlagZ(); }
inline void setFlagY(bool on) { on ? setFlagY() : resetFlagY(); }
inline void setFlagH(bool on) { on ? setFlagH() : resetFlagH(); }
inline void setFlagX(bool on) { on ? setFlagX() : resetFlagX(); }
inline void setFlagPV(bool on) { on ? setFlagPV() : resetFlagPV(); }
inline void setFlagN(bool on) { on ? setFlagN() : resetFlagN(); }
inline void setFlagC(bool on) { on ? setFlagC() : resetFlagC(); }
inline void setFlagXY(unsigned char value)
{
setFlagX(value & flagX());
setFlagY(value & flagY());
}
// flag checker
inline bool isFlagS() { return reg.pair.F & flagS(); }
inline bool isFlagZ() { return reg.pair.F & flagZ(); }
inline bool isFlagH() { return reg.pair.F & flagH(); }
inline bool isFlagPV() { return reg.pair.F & flagPV(); }
inline bool isFlagN() { return reg.pair.F & flagN(); }
inline bool isFlagC() { return reg.pair.F & flagC(); }
enum class Condition {
Z = 0x40,
C = 0x01,
PV = 0x04,
S = 0x80,
NZ = 0x4040,
NC = 0x0101,
NPV = 0x0404,
NS = 0x8080,
};
inline bool checkConditionFlag(Condition c)
{
int ic = (int)c;
return (ic & reg.pair.F) ^ ((ic & 0xFF00) >> 8);
}
inline unsigned char IFF1() { return 0b00000001; }
inline unsigned char IFF2() { return 0b00000100; }
inline unsigned char IFF_IRQ() { return 0b00100000; }
inline unsigned char IFF_NMI() { return 0b01000000; }
inline unsigned char IFF_HALT() { return 0b10000000; }
#ifndef Z80_DISABLE_BREAKPOINT
class BreakPoint
{
public:
unsigned short addr;
#ifdef Z80_NO_FUNCTIONAL
void (*callback)(void*);
BreakPoint(unsigned short addr_, void (*callback_)(void*))
#else
std::function<void(void*)> callback;
BreakPoint(unsigned short addr_, const std::function<void(void*)>& callback_)
#endif
{
this->addr = addr_;
this->callback = callback_;
}
};
class BreakOperand
{
public:
int prefixNumber;
unsigned char operandNumber;
#ifdef Z80_NO_FUNCTIONAL
void (*callback)(void*, unsigned char*, int);
BreakOperand(int prefixNumber_, unsigned char operandNumber_, void (*callback_)(void*, unsigned char*, int))
{
this->prefixNumber = prefixNumber_;
this->operandNumber = operandNumber_;
this->callback = callback_;
}
#else
std::function<void(void*, unsigned char*, int)> callback;
BreakOperand(int prefixNumber_, unsigned char operandNumber_, const std::function<void(void*, unsigned char*, int)>& callback_)
{
this->prefixNumber = prefixNumber_;
this->operandNumber = operandNumber_;
this->callback = callback_;
}
#endif
};
#endif
#ifndef Z80_DISABLE_NESTCHECK
class SimpleHandler
{
public:
#ifdef Z80_NO_FUNCTIONAL
void (*callback)(void*);
SimpleHandler(void (*callback_)(void*))
#else
std::function<void(void*)> callback;
SimpleHandler(const std::function<void(void*)>& callback_)
#endif
{
this->callback = callback_;
}
};
inline void invokeReturnHandlers()
{
for (auto handler : this->CB.returnHandlers) {
handler->callback(this->CB.arg);
}
}
inline void invokeCallHandlers()
{
for (auto handler : this->CB.callHandlers) {
handler->callback(this->CB.arg);
}
}
#endif
struct Callback {
#ifdef Z80_NO_FUNCTIONAL
unsigned char (*read)(void*, unsigned short);
void (*write)(void*, unsigned short, unsigned char);
unsigned char (*in)(void*, unsigned short);
void (*out)(void*, unsigned short, unsigned char);
void (*consumeClock)(void*, int);
#else
std::function<unsigned char(void*, unsigned short)> read;
std::function<void(void*, unsigned short, unsigned char)> write;
std::function<unsigned char(void*, unsigned short)> in;
std::function<void(void*, unsigned short, unsigned char)> out;
std::function<void(void*, int)> consumeClock;
#endif
#ifndef Z80_UNSUPPORT_16BIT_PORT
bool returnPortAs16Bits;
#endif
#ifndef Z80_DISABLE_DEBUG
#ifdef Z80_NO_FUNCTIONAL
void (*debugMessage)(void*, const char*);
#else
std::function<void(void*, const char*)> debugMessage;
#endif
bool debugMessageEnabled;
#endif
#ifndef Z80_DISABLE_BREAKPOINT
std::map<int, std::vector<BreakPoint*>*> breakPoints;
std::map<int, std::vector<BreakOperand*>*> breakOperands;
#endif
#ifndef Z80_DISABLE_NESTCHECK
std::vector<SimpleHandler*> returnHandlers;
std::vector<SimpleHandler*> callHandlers;
#endif
bool consumeClockEnabled;
void* arg;
} CB;
bool requestBreakFlag;
#ifndef Z80_DISABLE_BREAKPOINT
inline void checkBreakPoint()
{
auto it = CB.breakPoints.find(reg.PC);
if (it == CB.breakPoints.end()) return;
for (auto bp : *CB.breakPoints[reg.PC]) {
bp->callback(CB.arg);
}
}
inline void readFullOpcode(BreakOperand* operand, unsigned char* opcode, int* opcodeLength)
{
*opcodeLength = 0;
switch (operand->prefixNumber) {
case 0x00:
opcode[0] = operand->operandNumber;
*opcodeLength = opLength1[opcode[0]];
for (int i = 1; i < *opcodeLength; i++) {
opcode[i] = readByte(reg.PC + i - 1, 0); // read without consume clocks
}
break;
case 0xCB:
opcode[0] = 0xCB;
opcode[1] = operand->operandNumber;
*opcodeLength = 2;
break;
case 0xED:
opcode[0] = 0xED;
opcode[1] = operand->operandNumber;
*opcodeLength = opLengthED[opcode[1]];
for (int i = 2; i < *opcodeLength; i++) {
opcode[i] = readByte(reg.PC + i - 2, 0); // read without consume clocks
}
break;
case 0xDD:
opcode[0] = 0xDD;
opcode[1] = operand->operandNumber;
*opcodeLength = opLengthIXY[opcode[1]];
for (int i = 2; i < *opcodeLength; i++) {
opcode[i] = readByte(reg.PC + i - 2, 0); // read without consume clocks
}
break;
case 0xFD:
opcode[0] = 0xFD;
opcode[1] = operand->operandNumber;
*opcodeLength = opLengthIXY[opcode[1]];
for (int i = 2; i < *opcodeLength; i++) {
opcode[i] = readByte(reg.PC + i - 2, 0); // read without consume clocks
}
break;
case 0xDDCB:
opcode[0] = 0xDD;
opcode[1] = 0xCB;
opcode[2] = operand->operandNumber;
opcode[3] = readByte(reg.PC, 0);
*opcodeLength = 4;
break;
case 0xFDCB:
opcode[0] = 0xFD;
opcode[1] = 0xCB;
opcode[2] = operand->operandNumber;
opcode[3] = readByte(reg.PC, 0);
*opcodeLength = 4;
break;
}
}
inline void checkBreakOperand(int operandNumber)
{
if (CB.breakOperands.empty()) return;
auto it = CB.breakOperands.find(operandNumber);
if (it == CB.breakOperands.end()) return;
unsigned char opcode[16];
int opcodeLength = 16;
bool first = true;
for (auto bo : *CB.breakOperands[operandNumber]) {
if (first) {
readFullOpcode(bo, opcode, &opcodeLength);
first = false;
}
bo->callback(CB.arg, opcode, opcodeLength);
}
}
inline void checkBreakOperandCB(unsigned char operandNumber) { checkBreakOperand(0xCB00 | operandNumber); }
inline void checkBreakOperandED(unsigned char operandNumber) { checkBreakOperand(0xED00 | operandNumber); }
inline void checkBreakOperandIX(unsigned char operandNumber) { checkBreakOperand(0xDD00 | operandNumber); }
inline void checkBreakOperandIY(unsigned char operandNumber) { checkBreakOperand(0xFD00 | operandNumber); }
inline void checkBreakOperandIX4(unsigned char operandNumber) { checkBreakOperand(0xDDCB00 | operandNumber); }
inline void checkBreakOperandIY4(unsigned char operandNumber) { checkBreakOperand(0xFDCB00 | operandNumber); }
#endif
#ifndef Z80_DISABLE_DEBUG
inline void log(const char* format, ...)
{
char buf[1024];
va_list args;
va_start(args, format);
vsnprintf(buf, sizeof(buf), format, args);
va_end(args);
CB.debugMessage(CB.arg, buf);
}
#endif
inline unsigned short getAF()
{
return make16BitsFromLE(reg.pair.F, reg.pair.A);
}
inline unsigned short getAF2() { return make16BitsFromLE(reg.back.F, reg.back.A); }
inline unsigned short getBC() { return make16BitsFromLE(reg.pair.C, reg.pair.B); }
inline unsigned short getBC2() { return make16BitsFromLE(reg.back.C, reg.back.B); }
inline unsigned short getDE() { return make16BitsFromLE(reg.pair.E, reg.pair.D); }
inline unsigned short getDE2() { return make16BitsFromLE(reg.back.E, reg.back.D); }
inline unsigned short getHL() { return make16BitsFromLE(reg.pair.L, reg.pair.H); }
inline unsigned short getHL2() { return make16BitsFromLE(reg.back.L, reg.back.H); }
inline void setAF(unsigned short value) { splitTo8BitsPair(value, ®.pair.A, ®.pair.F); }
inline void setAF2(unsigned short value) { splitTo8BitsPair(value, ®.back.A, ®.back.F); }
inline void setBC(unsigned short value) { splitTo8BitsPair(value, ®.pair.B, ®.pair.C); }
inline void setBC2(unsigned short value) { splitTo8BitsPair(value, ®.back.B, ®.back.C); }
inline void setDE(unsigned short value) { splitTo8BitsPair(value, ®.pair.D, ®.pair.E); }
inline void setDE2(unsigned short value) { splitTo8BitsPair(value, ®.back.D, ®.back.E); }
inline void setHL(unsigned short value) { splitTo8BitsPair(value, ®.pair.H, ®.pair.L); }
inline void setHL2(unsigned short value) { splitTo8BitsPair(value, ®.back.H, ®.back.L); }
inline unsigned short getRP(unsigned char rp)
{
switch (rp & 0b11) {
case 0b00: return getBC();
case 0b01: return getDE();
case 0b10: return getHL();
default: return reg.SP;
}
}
inline unsigned short getRPIX(unsigned char rp)
{
switch (rp & 0b11) {
case 0b00: return getBC();
case 0b01: return getDE();
case 0b10: return reg.IX;
default: return reg.SP;
}
}
inline unsigned short getRPIY(unsigned char rp)
{
switch (rp & 0b11) {
case 0b00: return getBC();
case 0b01: return getDE();
case 0b10: return reg.IY;
default: return reg.SP;
}
}
inline void setRP(unsigned char rp, unsigned short value)
{
switch (rp & 0b11) {
case 0b00: setBC(value); break;
case 0b01: setDE(value); break;
case 0b10: setHL(value); break;
default: reg.SP = value;
}
}
inline unsigned char getIXH() { return (reg.IX & 0xFF00) >> 8; }
inline unsigned char getIXL() { return reg.IX & 0x00FF; }
inline unsigned char getIYH() { return (reg.IY & 0xFF00) >> 8; }
inline unsigned char getIYL() { return reg.IY & 0x00FF; }
inline unsigned char getPCH() { return (reg.PC & 0xFF00) >> 8; }
inline unsigned char getPCL() { return reg.PC & 0x00FF; }
inline void setPCH(unsigned char v) { reg.PC = (reg.PC & 0x00FF) + v * 256; }
inline void setPCL(unsigned char v) { reg.PC = (reg.PC & 0xFF00) + v; }
inline void setSPH(unsigned char v) { reg.SP = (reg.SP & 0x00FF) + v * 256; }
inline void setSPL(unsigned char v) { reg.SP = (reg.SP & 0xFF00) + v; }
inline void setIXH(unsigned char v) { reg.IX = (reg.IX & 0x00FF) + v * 256; }
inline void setIXL(unsigned char v) { reg.IX = (reg.IX & 0xFF00) + v; }
inline void setIYH(unsigned char v) { reg.IY = (reg.IY & 0x00FF) + v * 256; }
inline void setIYL(unsigned char v) { reg.IY = (reg.IY & 0xFF00) + v; }
inline bool isEvenNumberBits(unsigned char value)
{
int on = 0;
int off = 0;
value & 0b10000000 ? on++ : off++;
value & 0b01000000 ? on++ : off++;
value & 0b00100000 ? on++ : off++;
value & 0b00010000 ? on++ : off++;
value & 0b00001000 ? on++ : off++;
value & 0b00000100 ? on++ : off++;
value & 0b00000010 ? on++ : off++;
value & 0b00000001 ? on++ : off++;
return (on & 1) == 0;
}
inline void consumeClock(int hz)
{
reg.consumeClockCounter += hz;
#ifndef Z80_CALLBACK_PER_INSTRUCTION
#ifdef Z80_CALLBACK_WITHOUT_CHECK
CB.consumeClock(CB.arg, hz);
#else
if (CB.consumeClockEnabled && hz) CB.consumeClock(CB.arg, hz);
#endif
#endif
}
inline unsigned short getPort16WithB(unsigned char c) { return make16BitsFromLE(c, reg.pair.B); }
inline unsigned short getPort16WithA(unsigned char c) { return make16BitsFromLE(c, reg.pair.A); }
inline unsigned char inPortWithB(unsigned char port, int clock = 4)
{
#ifdef Z80_UNSUPPORT_16BIT_PORT
unsigned char byte = CB.in(CB.arg, port);
#else
unsigned char byte = CB.in(CB.arg, CB.returnPortAs16Bits ? getPort16WithB(port) : port);
#endif
consumeClock(clock);
return byte;
}
inline unsigned char inPortWithA(unsigned char port, int clock = 4)
{
#ifdef Z80_UNSUPPORT_16BIT_PORT
unsigned char byte = CB.in(CB.arg, port);
#else
unsigned char byte = CB.in(CB.arg, CB.returnPortAs16Bits ? getPort16WithA(port) : port);
#endif
consumeClock(clock);
return byte;
}
inline void outPortWithB(unsigned char port, unsigned char value, int clock = 4)
{
#ifdef Z80_UNSUPPORT_16BIT_PORT
CB.out(CB.arg, port, value);
#else
CB.out(CB.arg, CB.returnPortAs16Bits ? getPort16WithB(port) : port, value);
#endif
consumeClock(clock);
}
inline void outPortWithA(unsigned char port, unsigned char value, int clock = 4)
{
#ifdef Z80_UNSUPPORT_16BIT_PORT
CB.out(CB.arg, port, value);
#else
CB.out(CB.arg, CB.returnPortAs16Bits ? getPort16WithA(port) : port, value);
#endif
consumeClock(clock);
}
static inline void NOP(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] NOP", ctx->reg.PC - 1);
#endif
}
static inline void HALT(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] HALT", ctx->reg.PC - 1);
#endif
ctx->reg.IFF |= ctx->IFF_HALT();
}
static inline void DI(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] DI", ctx->reg.PC - 1);
#endif
ctx->reg.IFF &= ~(ctx->IFF1() | ctx->IFF2());
}
static inline void EI(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] EI", ctx->reg.PC - 1);
#endif
ctx->reg.IFF |= ctx->IFF1() | ctx->IFF2();
ctx->reg.execEI = 1;
}
static inline void IM0(Z80* ctx) { ctx->IM(0); }
static inline void IM1(Z80* ctx) { ctx->IM(1); }
static inline void IM2(Z80* ctx) { ctx->IM(2); }
inline void IM(unsigned char interrptMode)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] IM %d", reg.PC - 2, interrptMode);
#endif
reg.interrupt &= 0b11111100;
reg.interrupt |= interrptMode & 0b11;
}
static inline void LD_A_I_(Z80* ctx) { ctx->LD_A_I(); }
inline void LD_A_I()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD A<$%02X>, I<$%02X>", reg.PC - 2, reg.pair.A, reg.I);
#endif
reg.pair.A = reg.I;
setFlagPV(reg.IFF & IFF2());
consumeClock(1);
}
static inline void LD_I_A_(Z80* ctx) { ctx->LD_I_A(); }
inline void LD_I_A()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD I<$%02X>, A<$%02X>", reg.PC - 2, reg.I, reg.pair.A);
#endif
reg.I = reg.pair.A;
consumeClock(1);
}
static inline void LD_A_R_(Z80* ctx) { ctx->LD_A_R(); }
inline void LD_A_R()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD A<$%02X>, R<$%02X>", reg.PC - 2, reg.pair.A, reg.R);
#endif
reg.pair.A = reg.R;
setFlagPV(reg.IFF & IFF1());
consumeClock(1);
}
static inline void LD_R_A_(Z80* ctx) { ctx->LD_R_A(); }
inline void LD_R_A()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD R<$%02X>, A<$%02X>", reg.PC - 2, reg.R, reg.pair.A);
#endif
reg.R = reg.pair.A;
consumeClock(1);
}
static inline void OP_CB(Z80* ctx)
{
unsigned char operandNumber = ctx->fetch(4 + ctx->wtc.fetchM);
#ifndef Z80_DISABLE_BREAKPOINT
ctx->checkBreakOperandCB(operandNumber);
#endif
ctx->opSetCB[operandNumber](ctx);
}
static inline void OP_ED(Z80* ctx)
{
unsigned char operandNumber = ctx->fetch(4 + ctx->wtc.fetchM);
#ifndef Z80_NO_EXCEPTION
if (!ctx->opSetED[operandNumber]) {
char buf[80];
snprintf(buf, sizeof(buf), "detect an unknown operand (ED,%02X)", operandNumber);
throw std::runtime_error(buf);
}
#endif
#ifndef Z80_DISABLE_BREAKPOINT
ctx->checkBreakOperandED(operandNumber);
#endif
ctx->opSetED[operandNumber](ctx);
}
static inline void OP_IX(Z80* ctx)
{
unsigned char operandNumber = ctx->fetch(4 + ctx->wtc.fetchM);
#ifndef Z80_NO_EXCEPTION
if (!ctx->opSetIX[operandNumber]) {
char buf[80];
snprintf(buf, sizeof(buf), "detect an unknown operand (DD,%02X)", operandNumber);
throw std::runtime_error(buf);
}
#endif
#ifndef Z80_DISABLE_BREAKPOINT
ctx->checkBreakOperandIX(operandNumber);
#endif
ctx->opSetIX[operandNumber](ctx);
}
static inline void OP_IY(Z80* ctx)
{
unsigned char operandNumber = ctx->fetch(4 + ctx->wtc.fetchM);
#ifndef Z80_NO_EXCEPTION
if (!ctx->opSetIY[operandNumber]) {
char buf[80];
snprintf(buf, sizeof(buf), "detect an unknown operand (FD,%02X)", operandNumber);
throw std::runtime_error(buf);
}
#endif
#ifndef Z80_DISABLE_BREAKPOINT
ctx->checkBreakOperandIY(operandNumber);
#endif
ctx->opSetIY[operandNumber](ctx);
}
static inline void OP_IX4(Z80* ctx)
{
signed char op3 = (signed char)ctx->fetch(4);
unsigned char op4 = ctx->fetch(4);
#ifndef Z80_DISABLE_BREAKPOINT
ctx->checkBreakOperandIX4(op4);
#endif
ctx->opSetIX4[op4](ctx, op3);
}
static inline void OP_IY4(Z80* ctx)
{
signed char op3 = (signed char)ctx->fetch(4);
unsigned char op4 = ctx->fetch(4);
#ifndef Z80_DISABLE_BREAKPOINT
ctx->checkBreakOperandIY4(op4);
#endif
ctx->opSetIY4[op4](ctx, op3);
}
// Load location (HL) with value n
static inline void LD_HL_N(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
unsigned short hl = ctx->getHL();
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] LD (HL<$%04X>), $%02X", ctx->reg.PC - 2, hl, n);
#endif
ctx->writeByte(hl, n, 3);
}
// Load Acc. wth location (BC)
static inline void LD_A_BC(Z80* ctx)
{
unsigned short addr = ctx->getBC();
unsigned char n = ctx->readByte(addr, 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] LD A, (BC<$%02X%02X>) = $%02X", ctx->reg.PC - 1, ctx->reg.pair.B, ctx->reg.pair.C, n);
#endif
ctx->reg.pair.A = n;
}
// Load Acc. wth location (DE)
static inline void LD_A_DE(Z80* ctx)
{
unsigned short addr = ctx->getDE();
unsigned char n = ctx->readByte(addr, 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] LD A, (DE<$%02X%02X>) = $%02X", ctx->reg.PC - 1, ctx->reg.pair.D, ctx->reg.pair.E, n);
#endif
ctx->reg.pair.A = n;
}
// Load Acc. wth location (nn)
static inline void LD_A_NN(Z80* ctx)
{
unsigned char l = ctx->fetch(3);
unsigned char h = ctx->fetch(3);
unsigned short addr = ctx->make16BitsFromLE(l, h);
unsigned char n = ctx->readByte(addr, 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] LD A, ($%04X) = $%02X", ctx->reg.PC - 3, addr, n);
#endif
ctx->reg.pair.A = n;
}
// Load location (BC) wtih Acc.
static inline void LD_BC_A(Z80* ctx)
{
unsigned short addr = ctx->getBC();
unsigned char n = ctx->reg.pair.A;
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] LD (BC<$%02X%02X>), A<$%02X>", ctx->reg.PC - 1, ctx->reg.pair.B, ctx->reg.pair.C, n);
#endif
ctx->writeByte(addr, n, 3);
}
// Load location (DE) wtih Acc.
static inline void LD_DE_A(Z80* ctx)
{
unsigned short addr = ctx->getDE();
unsigned char n = ctx->reg.pair.A;
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] LD (DE<$%02X%02X>), A<$%02X>", ctx->reg.PC - 1, ctx->reg.pair.D, ctx->reg.pair.E, n);
#endif
ctx->writeByte(addr, n, 3);
}
// Load location (nn) with Acc.
static inline void LD_NN_A(Z80* ctx)
{
unsigned char l = ctx->fetch(3);
unsigned char h = ctx->fetch(3);
unsigned short addr = ctx->make16BitsFromLE(l, h);
unsigned char n = ctx->reg.pair.A;
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] LD ($%04X), A<$%02X>", ctx->reg.PC - 3, addr, n);
#endif
ctx->writeByte(addr, n, 3);
}
// Load HL with location (nn).
static inline void LD_HL_ADDR(Z80* ctx)
{
unsigned char l = ctx->fetch(3);
unsigned char h = ctx->fetch(3);
unsigned short addr = ctx->make16BitsFromLE(l, h);
#ifndef Z80_DISABLE_DEBUG
unsigned short hl = ctx->getHL();
#endif
ctx->reg.pair.L = ctx->readByte(addr, 3);
ctx->reg.pair.H = ctx->readByte(addr + 1, 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] LD HL<$%04X>, ($%04X) = $%04X", ctx->reg.PC - 3, hl, addr, ctx->getHL());
#endif
}
// Load location (nn) with HL.
static inline void LD_ADDR_HL(Z80* ctx)
{
unsigned char l = ctx->fetch(3);
unsigned char h = ctx->fetch(3);
unsigned short addr = ctx->make16BitsFromLE(l, h);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] LD ($%04X), %s", ctx->reg.PC - 3, addr, ctx->registerPairDump(0b10));
#endif
ctx->writeByte(addr, ctx->reg.pair.L, 3);
ctx->writeByte(addr + 1, ctx->reg.pair.H, 3);
}
// Load SP with HL.
static inline void LD_SP_HL(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] LD %s, HL<$%04X>", ctx->reg.PC - 1, ctx->registerPairDump(0b11), ctx->getHL());
#endif
ctx->reg.SP = ctx->getHL();
ctx->consumeClock(2);
}
// Exchange H and L with D and E
static inline void EX_DE_HL(Z80* ctx)
{
unsigned short de = ctx->getDE();
unsigned short hl = ctx->getHL();
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] EX %s, %s", ctx->reg.PC - 1, ctx->registerPairDump(0b01), ctx->registerPairDump(0b10));
#endif
ctx->setDE(hl);
ctx->setHL(de);
}
// Exchange A and F with A' and F'
static inline void EX_AF_AF2(Z80* ctx)
{
unsigned short af = ctx->getAF();
unsigned short af2 = ctx->getAF2();
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] EX AF<$%02X%02X>, AF'<$%02X%02X>", ctx->reg.PC - 1, ctx->reg.pair.A, ctx->reg.pair.F, ctx->reg.back.A, ctx->reg.back.F);
#endif
ctx->setAF(af2);
ctx->setAF2(af);
}
static inline void EX_SP_HL(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
unsigned short sp = ctx->reg.SP;
#endif
unsigned char l = ctx->pop(4);
unsigned char h = ctx->pop(4);
#ifndef Z80_DISABLE_DEBUG
unsigned short hl = ctx->getHL();
if (ctx->isDebug()) ctx->log("[%04X] EX (SP<$%04X>) = $%02X%02X, HL<$%04X>", ctx->reg.PC - 1, sp, h, l, hl);
#endif
ctx->push(ctx->reg.pair.H, 4);
ctx->reg.pair.H = h;
ctx->push(ctx->reg.pair.L, 3);
ctx->reg.pair.L = l;
}
static inline void EXX(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] EXX", ctx->reg.PC - 1);
#endif
unsigned short bc = ctx->getBC();
unsigned short bc2 = ctx->getBC2();
unsigned short de = ctx->getDE();
unsigned short de2 = ctx->getDE2();
unsigned short hl = ctx->getHL();
unsigned short hl2 = ctx->getHL2();
ctx->setBC(bc2);
ctx->setBC2(bc);
ctx->setDE(de2);
ctx->setDE2(de);
ctx->setHL(hl2);
ctx->setHL2(hl);
}
inline void push(unsigned char value, int clocks)
{
reg.SP--;
writeByte(reg.SP, value, clocks);
}
inline unsigned char pop(int clocks)
{
unsigned char value = readByte(reg.SP, clocks);
reg.SP++;
return value;
}
static inline void PUSH_AF(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] PUSH AF<$%02X%02X> <SP:$%04X>", ctx->reg.PC - 1, ctx->reg.pair.A, ctx->reg.pair.F, ctx->reg.SP);
#endif
ctx->push(ctx->reg.pair.A, 4);
ctx->push(ctx->reg.pair.F, 3);
}
static inline void POP_AF(Z80* ctx)
{
ctx->reg.pair.F = ctx->pop(3);
ctx->reg.pair.A = ctx->pop(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] POP AF <SP:$%04X> = $%04X", ctx->reg.PC - 1, ctx->reg.SP - 2, ctx->getAF());
#endif
}
unsigned char* registerPointerTable[8] = {®.pair.B, ®.pair.C, ®.pair.D, ®.pair.E, ®.pair.H, ®.pair.L, ®.pair.F, ®.pair.A};
inline unsigned char* getRegisterPointer(unsigned char r) { return registerPointerTable[r]; }
inline unsigned char getRegister(unsigned char r) { return *registerPointerTable[r]; }
#ifndef Z80_DISABLE_DEBUG
inline char* registerDump(unsigned char r)
{
static char A[16];
static char B[16];
static char C[16];
static char D[16];
static char E[16];
static char H[16];
static char L[16];
static char F[16];
static char unknown[2];
switch (r & 0b111) {
case 0b111: snprintf(A, sizeof(A), "A<$%02X>", reg.pair.A); return A;
case 0b000: snprintf(B, sizeof(B), "B<$%02X>", reg.pair.B); return B;
case 0b001: snprintf(C, sizeof(C), "C<$%02X>", reg.pair.C); return C;
case 0b010: snprintf(D, sizeof(D), "D<$%02X>", reg.pair.D); return D;
case 0b011: snprintf(E, sizeof(E), "E<$%02X>", reg.pair.E); return E;
case 0b100: snprintf(H, sizeof(H), "H<$%02X>", reg.pair.H); return H;
case 0b101: snprintf(L, sizeof(L), "L<$%02X>", reg.pair.L); return L;
case 0b110: snprintf(F, sizeof(F), "F<$%02X>", reg.pair.F); return F;
}
unknown[0] = '?';
unknown[1] = '\0';
return unknown;
}
inline char* conditionDump(Condition c)
{
static char CN[4];
switch (c) {
case Condition::NZ: strcpy(CN, "NZ"); break;
case Condition::Z: strcpy(CN, "Z"); break;
case Condition::NC: strcpy(CN, "NC"); break;
case Condition::C: strcpy(CN, "C"); break;
case Condition::NPV: strcpy(CN, "PO"); break;
case Condition::PV: strcpy(CN, "PE"); break;
case Condition::NS: strcpy(CN, "P"); break;
case Condition::S: strcpy(CN, "M"); break;
}
return CN;
}
inline char* relativeDump(unsigned short pc, signed char e)
{
static char buf[80];
if (e < 0) {
int ee = -e;
ee -= 2;
snprintf(buf, sizeof(buf), "$%04X - %d = $%04X", pc, ee, pc + e + 2);
} else {
snprintf(buf, sizeof(buf), "$%04X + %d = $%04X", pc, e + 2, pc + e + 2);
}
return buf;
}
inline char* registerDump2(unsigned char r)
{
static char A[16];
static char B[16];
static char C[16];
static char D[16];
static char E[16];
static char H[16];
static char L[16];
static char unknown[2] = "?";
switch (r) {
case 0b111: snprintf(A, sizeof(A), "A'<$%02X>", reg.back.A); return A;
case 0b000: snprintf(B, sizeof(B), "B'<$%02X>", reg.back.B); return B;
case 0b001: snprintf(C, sizeof(C), "C'<$%02X>", reg.back.C); return C;
case 0b010: snprintf(D, sizeof(D), "D'<$%02X>", reg.back.D); return D;
case 0b011: snprintf(E, sizeof(E), "E'<$%02X>", reg.back.E); return E;
case 0b100: snprintf(H, sizeof(H), "H'<$%02X>", reg.back.H); return H;
case 0b101: snprintf(L, sizeof(L), "L'<$%02X>", reg.back.L); return L;
default: return unknown;
}
}
inline char* registerPairDump(unsigned char ptn)
{
static char BC[16];
static char DE[16];
static char HL[16];
static char SP[16];
static char unknown[2] = "?";
switch (ptn & 0b11) {
case 0b00: snprintf(BC, sizeof(BC), "BC<$%02X%02X>", reg.pair.B, reg.pair.C); return BC;
case 0b01: snprintf(DE, sizeof(DE), "DE<$%02X%02X>", reg.pair.D, reg.pair.E); return DE;
case 0b10: snprintf(HL, sizeof(HL), "HL<$%02X%02X>", reg.pair.H, reg.pair.L); return HL;
case 0b11: snprintf(SP, sizeof(SP), "SP<$%04X>", reg.SP); return SP;
default: return unknown;
}
}
inline char* registerPairDumpIX(unsigned char ptn)
{
static char BC[16];
static char DE[16];
static char IX[16];
static char SP[16];
static char unknown[2] = "?";
switch (ptn & 0b11) {
case 0b00: snprintf(BC, sizeof(BC), "BC<$%02X%02X>", reg.pair.B, reg.pair.C); return BC;
case 0b01: snprintf(DE, sizeof(DE), "DE<$%02X%02X>", reg.pair.D, reg.pair.E); return DE;
case 0b10: snprintf(IX, sizeof(IX), "IX<$%04X>", reg.IX); return IX;
case 0b11: snprintf(SP, sizeof(SP), "SP<$%04X>", reg.SP); return SP;
default: return unknown;
}
}
inline char* registerPairDumpIY(unsigned char ptn)
{
static char BC[16];
static char DE[16];
static char IY[16];
static char SP[16];
static char unknown[2] = "?";
switch (ptn & 0b11) {
case 0b00: snprintf(BC, sizeof(BC), "BC<$%02X%02X>", reg.pair.B, reg.pair.C); return BC;
case 0b01: snprintf(DE, sizeof(DE), "DE<$%02X%02X>", reg.pair.D, reg.pair.E); return DE;
case 0b10: snprintf(IY, sizeof(IY), "IY<$%04X>", reg.IY); return IY;
case 0b11: snprintf(SP, sizeof(SP), "SP<$%04X>", reg.SP); return SP;
default: return unknown;
}
}
#endif
// Load Reg. r1 with Reg. r2
static inline void LD_B_B(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b000); }
static inline void LD_B_C(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b001); }
static inline void LD_B_D(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b010); }
static inline void LD_B_E(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b011); }
static inline void LD_B_B_2(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b000, 2); }
static inline void LD_B_C_2(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b001, 2); }
static inline void LD_B_D_2(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b010, 2); }
static inline void LD_B_E_2(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b011, 2); }
static inline void LD_B_H(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b100); }
static inline void LD_B_L(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b101); }
static inline void LD_B_A(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b111); }
static inline void LD_C_B(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b000); }
static inline void LD_C_C(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b001); }
static inline void LD_C_D(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b010); }
static inline void LD_C_E(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b011); }
static inline void LD_B_A_2(Z80* ctx) { ctx->LD_R1_R2(0b000, 0b111, 2); }
static inline void LD_C_B_2(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b000, 2); }
static inline void LD_C_C_2(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b001, 2); }
static inline void LD_C_D_2(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b010, 2); }
static inline void LD_C_E_2(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b011, 2); }
static inline void LD_C_H(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b100); }
static inline void LD_C_L(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b101); }
static inline void LD_C_A(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b111); }
static inline void LD_D_B(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b000); }
static inline void LD_D_C(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b001); }
static inline void LD_D_D(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b010); }
static inline void LD_D_E(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b011); }
static inline void LD_C_A_2(Z80* ctx) { ctx->LD_R1_R2(0b001, 0b111, 2); }
static inline void LD_D_B_2(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b000, 2); }
static inline void LD_D_C_2(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b001, 2); }
static inline void LD_D_D_2(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b010, 2); }
static inline void LD_D_E_2(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b011, 2); }
static inline void LD_D_H(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b100); }
static inline void LD_D_L(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b101); }
static inline void LD_D_A(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b111); }
static inline void LD_E_B(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b000); }
static inline void LD_E_C(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b001); }
static inline void LD_E_D(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b010); }
static inline void LD_E_E(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b011); }
static inline void LD_D_A_2(Z80* ctx) { ctx->LD_R1_R2(0b010, 0b111, 2); }
static inline void LD_E_B_2(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b000, 2); }
static inline void LD_E_C_2(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b001, 2); }
static inline void LD_E_D_2(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b010, 2); }
static inline void LD_E_E_2(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b011, 2); }
static inline void LD_E_H(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b100); }
static inline void LD_E_L(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b101); }
static inline void LD_E_A(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b111); }
static inline void LD_E_A_2(Z80* ctx) { ctx->LD_R1_R2(0b011, 0b111, 2); }
static inline void LD_H_B(Z80* ctx) { ctx->LD_R1_R2(0b100, 0b000); }
static inline void LD_H_C(Z80* ctx) { ctx->LD_R1_R2(0b100, 0b001); }
static inline void LD_H_D(Z80* ctx) { ctx->LD_R1_R2(0b100, 0b010); }
static inline void LD_H_E(Z80* ctx) { ctx->LD_R1_R2(0b100, 0b011); }
static inline void LD_H_H(Z80* ctx) { ctx->LD_R1_R2(0b100, 0b100); }
static inline void LD_H_L(Z80* ctx) { ctx->LD_R1_R2(0b100, 0b101); }
static inline void LD_H_A(Z80* ctx) { ctx->LD_R1_R2(0b100, 0b111); }
static inline void LD_L_B(Z80* ctx) { ctx->LD_R1_R2(0b101, 0b000); }
static inline void LD_L_C(Z80* ctx) { ctx->LD_R1_R2(0b101, 0b001); }
static inline void LD_L_D(Z80* ctx) { ctx->LD_R1_R2(0b101, 0b010); }
static inline void LD_L_E(Z80* ctx) { ctx->LD_R1_R2(0b101, 0b011); }
static inline void LD_L_H(Z80* ctx) { ctx->LD_R1_R2(0b101, 0b100); }
static inline void LD_L_L(Z80* ctx) { ctx->LD_R1_R2(0b101, 0b101); }
static inline void LD_L_A(Z80* ctx) { ctx->LD_R1_R2(0b101, 0b111); }
static inline void LD_A_B(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b000); }
static inline void LD_A_C(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b001); }
static inline void LD_A_D(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b010); }
static inline void LD_A_E(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b011); }
static inline void LD_A_B_2(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b000, 2); }
static inline void LD_A_C_2(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b001, 2); }
static inline void LD_A_D_2(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b010, 2); }
static inline void LD_A_E_2(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b011, 2); }
static inline void LD_A_H(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b100); }
static inline void LD_A_L(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b101); }
static inline void LD_A_A(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b111); }
static inline void LD_A_A_2(Z80* ctx) { ctx->LD_R1_R2(0b111, 0b111, 2); }
inline void LD_R1_R2(unsigned char r1, unsigned char r2, int counter = 1)
{
unsigned char* r1p = getRegisterPointer(r1);
unsigned char* r2p = getRegisterPointer(r2);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, %s", reg.PC - counter, registerDump(r1), registerDump(r2));
#endif
if (r1p && r2p) *r1p = *r2p;
}
// Load Reg. r with value n
static inline void LD_A_N(Z80* ctx) { ctx->LD_R_N(0b111); }
static inline void LD_B_N(Z80* ctx) { ctx->LD_R_N(0b000); }
static inline void LD_C_N(Z80* ctx) { ctx->LD_R_N(0b001); }
static inline void LD_D_N(Z80* ctx) { ctx->LD_R_N(0b010); }
static inline void LD_E_N(Z80* ctx) { ctx->LD_R_N(0b011); }
static inline void LD_H_N(Z80* ctx) { ctx->LD_R_N(0b100); }
static inline void LD_L_N(Z80* ctx) { ctx->LD_R_N(0b101); }
static inline void LD_A_N_3(Z80* ctx) { ctx->LD_R_N(0b111, 3); }
static inline void LD_B_N_3(Z80* ctx) { ctx->LD_R_N(0b000, 3); }
static inline void LD_C_N_3(Z80* ctx) { ctx->LD_R_N(0b001, 3); }
static inline void LD_D_N_3(Z80* ctx) { ctx->LD_R_N(0b010, 3); }
static inline void LD_E_N_3(Z80* ctx) { ctx->LD_R_N(0b011, 3); }
inline void LD_R_N(unsigned char r, int pc = 2)
{
unsigned char* rp = getRegisterPointer(r);
unsigned char n = fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, $%02X", reg.PC - pc, registerDump(r), n);
#endif
if (rp) *rp = n;
}
// Load Reg. IX(high) with value n
static inline void LD_IXH_N_(Z80* ctx) { ctx->LD_IXH_N(); }
inline void LD_IXH_N()
{
unsigned char n = fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IXH, $%02X", reg.PC - 3, n);
#endif
setIXH(n);
}
// Load Reg. IX(high) with value Reg.
static inline void LD_IXH_A(Z80* ctx) { ctx->LD_IXH_R(0b111); }
static inline void LD_IXH_B(Z80* ctx) { ctx->LD_IXH_R(0b000); }
static inline void LD_IXH_C(Z80* ctx) { ctx->LD_IXH_R(0b001); }
static inline void LD_IXH_D(Z80* ctx) { ctx->LD_IXH_R(0b010); }
static inline void LD_IXH_E(Z80* ctx) { ctx->LD_IXH_R(0b011); }
inline void LD_IXH_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IXH, %s", reg.PC - 2, registerDump(r));
#endif
setIXH(*rp);
}
// Load Reg. IX(high) with value IX(high)
static inline void LD_IXH_IXH_(Z80* ctx) { ctx->LD_IXH_IXH(); }
inline void LD_IXH_IXH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IXH, IXH<$%02X>", reg.PC - 2, getIXH());
#endif
}
// Load Reg. IX(high) with value IX(low)
static inline void LD_IXH_IXL_(Z80* ctx) { ctx->LD_IXH_IXL(); }
inline void LD_IXH_IXL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IXH, IXL<$%02X>", reg.PC - 2, getIXL());
#endif
setIXH(getIXL());
}
// Load Reg. IX(low) with value n
static inline void LD_IXL_N_(Z80* ctx) { ctx->LD_IXL_N(); }
inline void LD_IXL_N()
{
unsigned char n = fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IXL, $%02X", reg.PC - 3, n);
#endif
setIXL(n);
}
// Load Reg. IX(low) with value Reg.
static inline void LD_IXL_A(Z80* ctx) { ctx->LD_IXL_R(0b111); }
static inline void LD_IXL_B(Z80* ctx) { ctx->LD_IXL_R(0b000); }
static inline void LD_IXL_C(Z80* ctx) { ctx->LD_IXL_R(0b001); }
static inline void LD_IXL_D(Z80* ctx) { ctx->LD_IXL_R(0b010); }
static inline void LD_IXL_E(Z80* ctx) { ctx->LD_IXL_R(0b011); }
inline void LD_IXL_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IXL, %s", reg.PC - 2, registerDump(r));
#endif
setIXL(*rp);
}
// Load Reg. IX(low) with value IX(high)
static inline void LD_IXL_IXH_(Z80* ctx) { ctx->LD_IXL_IXH(); }
inline void LD_IXL_IXH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IXL, IXH<$%02X>", reg.PC - 2, getIXH());
#endif
setIXL(getIXH());
}
// Load Reg. IX(low) with value IX(low)
static inline void LD_IXL_IXL_(Z80* ctx) { ctx->LD_IXL_IXL(); }
inline void LD_IXL_IXL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IXL, IXL<$%02X>", reg.PC - 2, getIXL());
#endif
}
// Load Reg. IY(high) with value n
static inline void LD_IYH_N_(Z80* ctx) { ctx->LD_IYH_N(); }
inline void LD_IYH_N()
{
unsigned char n = fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IYH, $%02X", reg.PC - 3, n);
#endif
setIYH(n);
}
// Load Reg. IY(high) with value Reg.
static inline void LD_IYH_A(Z80* ctx) { ctx->LD_IYH_R(0b111); }
static inline void LD_IYH_B(Z80* ctx) { ctx->LD_IYH_R(0b000); }
static inline void LD_IYH_C(Z80* ctx) { ctx->LD_IYH_R(0b001); }
static inline void LD_IYH_D(Z80* ctx) { ctx->LD_IYH_R(0b010); }
static inline void LD_IYH_E(Z80* ctx) { ctx->LD_IYH_R(0b011); }
inline void LD_IYH_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IYH, %s", reg.PC - 2, registerDump(r));
#endif
setIYH(*rp);
}
// Load Reg. IY(high) with value IY(high)
static inline void LD_IYH_IYH_(Z80* ctx) { ctx->LD_IYH_IYH(); }
inline void LD_IYH_IYH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IYH, IYH<$%02X>", reg.PC - 2, getIYH());
#endif
}
// Load Reg. IY(high) with value IY(low)
static inline void LD_IYH_IYL_(Z80* ctx) { ctx->LD_IYH_IYL(); }
inline void LD_IYH_IYL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IYH, IYL<$%02X>", reg.PC - 2, getIYL());
#endif
setIYH(getIYL());
}
// Load Reg. IY(low) with value n
static inline void LD_IYL_N_(Z80* ctx) { ctx->LD_IYL_N(); }
inline void LD_IYL_N()
{
unsigned char n = fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IYL, $%02X", reg.PC - 3, n);
#endif
setIYL(n);
}
// Load Reg. IY(low) with value Reg.
static inline void LD_IYL_A(Z80* ctx) { ctx->LD_IYL_R(0b111); }
static inline void LD_IYL_B(Z80* ctx) { ctx->LD_IYL_R(0b000); }
static inline void LD_IYL_C(Z80* ctx) { ctx->LD_IYL_R(0b001); }
static inline void LD_IYL_D(Z80* ctx) { ctx->LD_IYL_R(0b010); }
static inline void LD_IYL_E(Z80* ctx) { ctx->LD_IYL_R(0b011); }
inline void LD_IYL_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IYL, %s", reg.PC - 2, registerDump(r));
#endif
setIYL(*rp);
}
// Load Reg. IY(low) with value IY(high)
static inline void LD_IYL_IYH_(Z80* ctx) { ctx->LD_IYL_IYH(); }
inline void LD_IYL_IYH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IYL, IYH<$%02X>", reg.PC - 2, getIYH());
#endif
setIYL(getIYH());
}
// Load Reg. IY(low) with value IY(low)
static inline void LD_IYL_IYL_(Z80* ctx) { ctx->LD_IYL_IYL(); }
inline void LD_IYL_IYL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IYL, IYL<$%02X>", reg.PC - 2, getIYL());
#endif
}
// Load Reg. r with location (HL)
static inline void LD_B_HL(Z80* ctx) { ctx->LD_R_HL(0b000); }
static inline void LD_C_HL(Z80* ctx) { ctx->LD_R_HL(0b001); }
static inline void LD_D_HL(Z80* ctx) { ctx->LD_R_HL(0b010); }
static inline void LD_E_HL(Z80* ctx) { ctx->LD_R_HL(0b011); }
static inline void LD_H_HL(Z80* ctx) { ctx->LD_R_HL(0b100); }
static inline void LD_L_HL(Z80* ctx) { ctx->LD_R_HL(0b101); }
static inline void LD_A_HL(Z80* ctx) { ctx->LD_R_HL(0b111); }
inline void LD_R_HL(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
unsigned char n = readByte(getHL(), 3);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, (%s) = $%02X", reg.PC - 1, registerDump(r), registerPairDump(0b10), n);
#endif
if (rp) *rp = n;
}
// Load Reg. r with location (IX+d)
static inline void LD_A_IX(Z80* ctx) { ctx->LD_R_IX(0b111); }
static inline void LD_B_IX(Z80* ctx) { ctx->LD_R_IX(0b000); }
static inline void LD_C_IX(Z80* ctx) { ctx->LD_R_IX(0b001); }
static inline void LD_D_IX(Z80* ctx) { ctx->LD_R_IX(0b010); }
static inline void LD_E_IX(Z80* ctx) { ctx->LD_R_IX(0b011); }
static inline void LD_H_IX(Z80* ctx) { ctx->LD_R_IX(0b100); }
static inline void LD_L_IX(Z80* ctx) { ctx->LD_R_IX(0b101); }
inline void LD_R_IX(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
signed char d = (signed char)fetch(4);
unsigned char n = readByte((reg.IX + d) & 0xFFFF);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, (IX<$%04X>+$%02X) = $%02X", reg.PC - 3, registerDump(r), reg.IX, d, n);
#endif
if (rp) *rp = n;
consumeClock(3);
}
// Load Reg. r with IXH
static inline void LD_A_IXH(Z80* ctx) { ctx->LD_R_IXH(0b111); }
static inline void LD_B_IXH(Z80* ctx) { ctx->LD_R_IXH(0b000); }
static inline void LD_C_IXH(Z80* ctx) { ctx->LD_R_IXH(0b001); }
static inline void LD_D_IXH(Z80* ctx) { ctx->LD_R_IXH(0b010); }
static inline void LD_E_IXH(Z80* ctx) { ctx->LD_R_IXH(0b011); }
inline void LD_R_IXH(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, IXH<$%02X>", reg.PC - 2, registerDump(r), getIXH());
#endif
if (rp) *rp = getIXH();
}
// Load Reg. r with IXL
static inline void LD_A_IXL(Z80* ctx) { ctx->LD_R_IXL(0b111); }
static inline void LD_B_IXL(Z80* ctx) { ctx->LD_R_IXL(0b000); }
static inline void LD_C_IXL(Z80* ctx) { ctx->LD_R_IXL(0b001); }
static inline void LD_D_IXL(Z80* ctx) { ctx->LD_R_IXL(0b010); }
static inline void LD_E_IXL(Z80* ctx) { ctx->LD_R_IXL(0b011); }
inline void LD_R_IXL(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, IXL<$%02X>", reg.PC - 2, registerDump(r), getIXL());
#endif
if (rp) *rp = getIXL();
}
// Load Reg. r with location (IY+d)
static inline void LD_A_IY(Z80* ctx) { ctx->LD_R_IY(0b111); }
static inline void LD_B_IY(Z80* ctx) { ctx->LD_R_IY(0b000); }
static inline void LD_C_IY(Z80* ctx) { ctx->LD_R_IY(0b001); }
static inline void LD_D_IY(Z80* ctx) { ctx->LD_R_IY(0b010); }
static inline void LD_E_IY(Z80* ctx) { ctx->LD_R_IY(0b011); }
static inline void LD_H_IY(Z80* ctx) { ctx->LD_R_IY(0b100); }
static inline void LD_L_IY(Z80* ctx) { ctx->LD_R_IY(0b101); }
inline void LD_R_IY(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
signed char d = (signed char)fetch(4);
unsigned char n = readByte((reg.IY + d) & 0xFFFF);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, (IY<$%04X>+$%02X) = $%02X", reg.PC - 3, registerDump(r), reg.IY, d, n);
#endif
if (rp) *rp = n;
consumeClock(3);
}
// Load Reg. r with IYH
static inline void LD_A_IYH(Z80* ctx) { ctx->LD_R_IYH(0b111); }
static inline void LD_B_IYH(Z80* ctx) { ctx->LD_R_IYH(0b000); }
static inline void LD_C_IYH(Z80* ctx) { ctx->LD_R_IYH(0b001); }
static inline void LD_D_IYH(Z80* ctx) { ctx->LD_R_IYH(0b010); }
static inline void LD_E_IYH(Z80* ctx) { ctx->LD_R_IYH(0b011); }
inline void LD_R_IYH(unsigned char r)
{
unsigned char iyh = getIYH();
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, IYH<$%02X>", reg.PC - 2, registerDump(r), iyh);
#endif
if (rp) *rp = iyh;
}
// Load Reg. r with IYL
static inline void LD_A_IYL(Z80* ctx) { ctx->LD_R_IYL(0b111); }
static inline void LD_B_IYL(Z80* ctx) { ctx->LD_R_IYL(0b000); }
static inline void LD_C_IYL(Z80* ctx) { ctx->LD_R_IYL(0b001); }
static inline void LD_D_IYL(Z80* ctx) { ctx->LD_R_IYL(0b010); }
static inline void LD_E_IYL(Z80* ctx) { ctx->LD_R_IYL(0b011); }
inline void LD_R_IYL(unsigned char r)
{
unsigned char iyl = getIYL();
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, IYL<$%02X>", reg.PC - 2, registerDump(r), iyl);
#endif
if (rp) *rp = iyl;
}
// Load location (HL) with Reg. r
static inline void LD_HL_B(Z80* ctx) { ctx->LD_HL_R(0b000); }
static inline void LD_HL_C(Z80* ctx) { ctx->LD_HL_R(0b001); }
static inline void LD_HL_D(Z80* ctx) { ctx->LD_HL_R(0b010); }
static inline void LD_HL_E(Z80* ctx) { ctx->LD_HL_R(0b011); }
static inline void LD_HL_H(Z80* ctx) { ctx->LD_HL_R(0b100); }
static inline void LD_HL_L(Z80* ctx) { ctx->LD_HL_R(0b101); }
static inline void LD_HL_A(Z80* ctx) { ctx->LD_HL_R(0b111); }
inline void LD_HL_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
unsigned short addr = getHL();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD (%s), %s", reg.PC - 1, registerPairDump(0b10), registerDump(r));
#endif
writeByte(addr, *rp, 3);
}
// Load location (IX+d) with Reg. r
static inline void LD_IX_A(Z80* ctx) { ctx->LD_IX_R(0b111); }
static inline void LD_IX_B(Z80* ctx) { ctx->LD_IX_R(0b000); }
static inline void LD_IX_C(Z80* ctx) { ctx->LD_IX_R(0b001); }
static inline void LD_IX_D(Z80* ctx) { ctx->LD_IX_R(0b010); }
static inline void LD_IX_E(Z80* ctx) { ctx->LD_IX_R(0b011); }
static inline void LD_IX_H(Z80* ctx) { ctx->LD_IX_R(0b100); }
static inline void LD_IX_L(Z80* ctx) { ctx->LD_IX_R(0b101); }
inline void LD_IX_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IX + d);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD (IX<$%04X>+$%02X), %s", reg.PC - 3, reg.IX, d, registerDump(r));
#endif
if (rp) writeByte(addr, *rp);
consumeClock(3);
}
// Load location (IY+d) with Reg. r
static inline void LD_IY_A(Z80* ctx) { ctx->LD_IY_R(0b111); }
static inline void LD_IY_B(Z80* ctx) { ctx->LD_IY_R(0b000); }
static inline void LD_IY_C(Z80* ctx) { ctx->LD_IY_R(0b001); }
static inline void LD_IY_D(Z80* ctx) { ctx->LD_IY_R(0b010); }
static inline void LD_IY_E(Z80* ctx) { ctx->LD_IY_R(0b011); }
static inline void LD_IY_H(Z80* ctx) { ctx->LD_IY_R(0b100); }
static inline void LD_IY_L(Z80* ctx) { ctx->LD_IY_R(0b101); }
inline void LD_IY_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IY + d);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD (IY<$%04X>+$%02X), %s", reg.PC - 3, reg.IY, d, registerDump(r));
#endif
if (rp) writeByte(addr, *rp);
consumeClock(3);
}
// Load location (IX+d) with value n
static inline void LD_IX_N_(Z80* ctx) { ctx->LD_IX_N(); }
inline void LD_IX_N()
{
signed char d = (signed char)fetch(4);
unsigned char n = fetch(4);
unsigned short addr = (unsigned short)(reg.IX + d);
writeByte(addr, n, 3);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD (IX<$%04X>+$%02X), $%02X", reg.PC - 4, reg.IX, d, n);
#endif
}
// Load location (IY+d) with value n
static inline void LD_IY_N_(Z80* ctx) { ctx->LD_IY_N(); }
inline void LD_IY_N()
{
signed char d = (signed char)fetch(4);
unsigned char n = fetch(4);
unsigned short addr = (unsigned short)(reg.IY + d);
writeByte(addr, n, 3);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD (IY<$%04X>+$%02X), $%02X", reg.PC - 4, reg.IY, d, n);
#endif
}
// Load Reg. pair rp with value nn.
static inline void LD_BC_NN(Z80* ctx) { ctx->LD_RP_NN(0b00); }
static inline void LD_DE_NN(Z80* ctx) { ctx->LD_RP_NN(0b01); }
static inline void LD_HL_NN(Z80* ctx) { ctx->LD_RP_NN(0b10); }
static inline void LD_SP_NN(Z80* ctx) { ctx->LD_RP_NN(0b11); }
inline void LD_RP_NN(unsigned char rp)
{
unsigned char* rH;
unsigned char* rL;
switch (rp) {
case 0b00:
rH = ®.pair.B;
rL = ®.pair.C;
break;
case 0b01:
rH = ®.pair.D;
rL = ®.pair.E;
break;
case 0b10:
rH = ®.pair.H;
rL = ®.pair.L;
break;
case 0b11: {
// SP is not managed in pair structure, so calculate directly
#ifndef Z80_DISABLE_DEBUG
unsigned short sp = reg.SP;
#endif
setSPL(fetch(3));
setSPH(fetch(3));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD SP<$%04X>, $%04X", reg.PC - 3, sp, reg.SP);
#endif
return;
}
default:
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("invalid register pair has specified: $%02X", rp);
#endif
#ifndef Z80_NO_EXCEPTION
throw std::runtime_error("invalid register pair has specified");
#endif
return;
}
#ifndef Z80_DISABLE_DEBUG
const char* dump = isDebug() ? registerPairDump(rp) : "";
#endif
unsigned char nL = fetch(3);
*rL = nL;
unsigned char nH = fetch(3);
*rH = nH;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, $%02X%02X", reg.PC - 3, dump, nH, nL);
#endif
}
static inline void LD_IX_NN_(Z80* ctx) { ctx->LD_IX_NN(); }
inline void LD_IX_NN()
{
setIXL(fetch(3));
setIXH(fetch(3));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IX, $%04X", reg.PC - 4, reg.IX);
#endif
}
static inline void LD_IY_NN_(Z80* ctx) { ctx->LD_IY_NN(); }
inline void LD_IY_NN()
{
setIYL(fetch(3));
setIYH(fetch(3));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IY, $%04X", reg.PC - 4, reg.IY);
#endif
}
// Load Reg. pair rp with location (nn)
static inline void LD_RP_ADDR_BC(Z80* ctx) { ctx->LD_RP_ADDR(0b00); }
static inline void LD_RP_ADDR_DE(Z80* ctx) { ctx->LD_RP_ADDR(0b01); }
static inline void LD_RP_ADDR_HL(Z80* ctx) { ctx->LD_RP_ADDR(0b10); }
static inline void LD_RP_ADDR_SP(Z80* ctx) { ctx->LD_RP_ADDR(0b11); }
inline void LD_RP_ADDR(unsigned char rp)
{
unsigned char l = fetch(3);
unsigned char h = fetch(3);
unsigned short addr = make16BitsFromLE(l, h);
unsigned char* rL;
unsigned char* rH;
switch (rp) {
case 0:
rH = ®.pair.B;
rL = ®.pair.C;
break;
case 1:
rH = ®.pair.D;
rL = ®.pair.E;
break;
case 2:
rH = ®.pair.H;
rL = ®.pair.L;
break;
case 3: {
#ifndef Z80_DISABLE_DEBUG
const char* dump = isDebug() ? registerPairDump(rp) : "";
#endif
setSPL(readByte(addr, 3));
setSPH(readByte(addr + 1, 3));
reg.WZ = addr + 1;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, ($%04X) = $%04X", reg.PC - 4, dump, addr, reg.SP);
#endif
return;
}
default:
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("invalid register pair has specified: $%02X", rp);
#endif
#ifndef Z80_NO_EXCEPTION
throw std::runtime_error("invalid register pair has specified");
#endif
return;
}
#ifndef Z80_DISABLE_DEBUG
const char* dump = isDebug() ? registerPairDump(rp) : "";
#endif
*rL = readByte(addr, 3);
*rH = readByte(addr + 1, 3);
reg.WZ = addr + 1;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, ($%04X) = $%04X", reg.PC - 4, dump, addr, make16BitsFromLE(*rL, *rH));
#endif
}
// Load location (nn) with Reg. pair rp.
static inline void LD_ADDR_RP_BC(Z80* ctx) { ctx->LD_ADDR_RP(0b00); }
static inline void LD_ADDR_RP_DE(Z80* ctx) { ctx->LD_ADDR_RP(0b01); }
static inline void LD_ADDR_RP_HL(Z80* ctx) { ctx->LD_ADDR_RP(0b10); }
static inline void LD_ADDR_RP_SP(Z80* ctx) { ctx->LD_ADDR_RP(0b11); }
inline void LD_ADDR_RP(unsigned char rp)
{
unsigned char l = fetch(3);
unsigned char h = fetch(3);
unsigned short addr = make16BitsFromLE(l, h);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD ($%04X), %s", reg.PC - 4, addr, registerPairDump(rp));
#endif
switch (rp) {
case 0b00:
h = reg.pair.B;
l = reg.pair.C;
break;
case 0b01:
h = reg.pair.D;
l = reg.pair.E;
break;
case 0b10:
h = reg.pair.H;
l = reg.pair.L;
break;
case 0b11:
splitTo8BitsPair(reg.SP, &h, &l);
break;
default:
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("invalid register pair has specified: $%02X", rp);
#endif
#ifndef Z80_NO_EXCEPTION
throw std::runtime_error("invalid register pair has specified");
#endif
return;
}
writeByte(addr, l, 3);
writeByte(addr + 1, h, 3);
reg.WZ = addr + 1;
}
// Load IX with location (nn)
static inline void LD_IX_ADDR_(Z80* ctx) { ctx->LD_IX_ADDR(); }
inline void LD_IX_ADDR()
{
unsigned char l = fetch(3);
unsigned char h = fetch(3);
unsigned short addr = make16BitsFromLE(l, h);
#ifndef Z80_DISABLE_DEBUG
unsigned short ix = reg.IX;
#endif
setIXL(readByte(addr, 3));
setIXH(readByte(addr + 1, 3));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IX<$%04X>, ($%04X) = $%04X", reg.PC - 4, ix, addr, reg.IX);
#endif
}
// Load IY with location (nn)
static inline void LD_IY_ADDR_(Z80* ctx) { ctx->LD_IY_ADDR(); }
inline void LD_IY_ADDR()
{
unsigned char l = fetch(3);
unsigned char h = fetch(3);
unsigned short addr = make16BitsFromLE(l, h);
#ifndef Z80_DISABLE_DEBUG
unsigned short iy = reg.IY;
#endif
setIYL(readByte(addr, 3));
setIYH(readByte(addr + 1, 3));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD IY<$%04X>, ($%04X) = $%04X", reg.PC - 4, iy, addr, reg.IY);
#endif
}
static inline void LD_ADDR_IX_(Z80* ctx) { ctx->LD_ADDR_IX(); }
inline void LD_ADDR_IX()
{
unsigned char l = fetch(3);
unsigned char h = fetch(3);
unsigned short addr = make16BitsFromLE(l, h);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD ($%04X), IX<$%04X>", reg.PC - 4, addr, reg.IX);
#endif
writeByte(addr, getIXL(), 3);
writeByte(addr + 1, getIXH(), 3);
}
static inline void LD_ADDR_IY_(Z80* ctx) { ctx->LD_ADDR_IY(); }
inline void LD_ADDR_IY()
{
unsigned char l = fetch(3);
unsigned char h = fetch(3);
unsigned short addr = make16BitsFromLE(l, h);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD ($%04X), IY<$%04X>", reg.PC - 4, addr, reg.IY);
#endif
writeByte(addr, getIYL(), 3);
writeByte(addr + 1, getIYH(), 3);
}
// Load SP with IX.
static inline void LD_SP_IX_(Z80* ctx) { ctx->LD_SP_IX(); }
inline void LD_SP_IX()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, IX<$%04X>", reg.PC - 2, registerPairDump(0b11), reg.IX);
#endif
reg.SP = reg.IX;
consumeClock(2);
}
// Load SP with IY.
static inline void LD_SP_IY_(Z80* ctx) { ctx->LD_SP_IY(); }
inline void LD_SP_IY()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] LD %s, IY<$%04X>", reg.PC - 2, registerPairDump(0b11), reg.IY);
#endif
reg.SP = reg.IY;
consumeClock(2);
}
// Load location (DE) with Loacation (HL), increment/decrement DE, HL, decrement BC
inline void repeatLD(bool isIncDEHL, bool isRepeat)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) {
if (isIncDEHL) {
if (isDebug()) log("[%04X] %s ... %s, %s, %s", reg.PC - 2, isRepeat ? "LDIR" : "LDI", registerPairDump(0b00), registerPairDump(0b01), registerPairDump(0b10));
} else {
if (isDebug()) log("[%04X] %s ... %s, %s, %s", reg.PC - 2, isRepeat ? "LDDR" : "LDD", registerPairDump(0b00), registerPairDump(0b01), registerPairDump(0b10));
}
}
#endif
unsigned short bc = getBC();
unsigned short de = getDE();
unsigned short hl = getHL();
unsigned char n = readByte(hl);
writeByte(de, n);
if (isIncDEHL) {
de++;
hl++;
} else {
de--;
hl--;
}
bc--;
setBC(bc);
setDE(de);
setHL(hl);
resetFlagH();
setFlagPV(bc != 0);
resetFlagN();
unsigned char an = reg.pair.A + n;
setFlagY(an & 0b00000010);
setFlagX(an & 0b00001000);
if (isRepeat && 0 != bc) {
reg.PC -= 2;
consumeClock(5);
}
}
static inline void LDI(Z80* ctx) { ctx->repeatLD(true, false); }
static inline void LDIR(Z80* ctx) { ctx->repeatLD(true, true); }
static inline void LDD(Z80* ctx) { ctx->repeatLD(false, false); }
static inline void LDDR(Z80* ctx) { ctx->repeatLD(false, true); }
// Exchange stack top with IX
static inline void EX_SP_IX_(Z80* ctx) { ctx->EX_SP_IX(); }
inline void EX_SP_IX()
{
#ifndef Z80_DISABLE_DEBUG
unsigned short sp = reg.SP;
#endif
unsigned char l = pop(4);
unsigned char h = pop(4);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] EX (SP<$%04X>) = $%02X%02X, IX<$%04X>", reg.PC - 2, sp, h, l, reg.IX);
#endif
push(getIXH(), 4);
setIXH(h);
push(getIXL(), 3);
setIXL(l);
}
// Exchange stack top with IY
static inline void EX_SP_IY_(Z80* ctx) { ctx->EX_SP_IY(); }
inline void EX_SP_IY()
{
#ifndef Z80_DISABLE_DEBUG
unsigned short sp = reg.SP;
#endif
unsigned char l = pop(4);
unsigned char h = pop(4);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] EX (SP<$%04X>) = $%02X%02X, IY<$%04X>", reg.PC - 2, sp, h, l, reg.IY);
#endif
push(getIYH(), 4);
setIYH(h);
push(getIYL(), 3);
setIYL(l);
}
// Push Reg. on Stack.
static inline void PUSH_BC(Z80* ctx) { ctx->PUSH_RP(0b00); }
static inline void PUSH_DE(Z80* ctx) { ctx->PUSH_RP(0b01); }
static inline void PUSH_HL(Z80* ctx) { ctx->PUSH_RP(0b10); }
inline void PUSH_RP(unsigned char rp)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] PUSH %s <SP:$%04X>", reg.PC - 1, registerPairDump(rp), reg.SP);
#endif
switch (rp) {
case 0b00:
push(reg.pair.B, 4);
push(reg.pair.C, 3);
break;
case 0b01:
push(reg.pair.D, 4);
push(reg.pair.E, 3);
break;
case 0b10:
push(reg.pair.H, 4);
push(reg.pair.L, 3);
break;
default:
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("invalid register pair has specified: $%02X", rp);
#endif
#ifdef Z80_NO_EXCEPTION
;
#else
throw std::runtime_error("invalid register pair has specified");
#endif
}
}
// Push Reg. on Stack.
static inline void POP_BC(Z80* ctx) { ctx->POP_RP(0b00); }
static inline void POP_DE(Z80* ctx) { ctx->POP_RP(0b01); }
static inline void POP_HL(Z80* ctx) { ctx->POP_RP(0b10); }
inline void POP_RP(unsigned char rp)
{
#ifndef Z80_DISABLE_DEBUG
unsigned short sp = reg.SP;
const char* dump = isDebug() ? registerPairDump(rp) : "";
unsigned short after;
#endif
switch (rp) {
case 0b00:
reg.pair.C = pop(3);
reg.pair.B = pop(3);
#ifndef Z80_DISABLE_DEBUG
after = getBC();
#endif
break;
case 0b01:
reg.pair.E = pop(3);
reg.pair.D = pop(3);
#ifndef Z80_DISABLE_DEBUG
after = getDE();
#endif
break;
case 0b10:
reg.pair.L = pop(3);
reg.pair.H = pop(3);
#ifndef Z80_DISABLE_DEBUG
after = getHL();
#endif
break;
default:
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("invalid register pair has specified: $%02X", rp);
#endif
#ifndef Z80_NO_EXCEPTION
throw std::runtime_error("invalid register pair has specified");
#endif
return;
}
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] POP %s <SP:$%04X> = $%04X", reg.PC - 1, dump, sp, after);
#endif
}
// Push Reg. IX on Stack.
static inline void PUSH_IX_(Z80* ctx) { ctx->PUSH_IX(); }
inline void PUSH_IX()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] PUSH IX<$%04X> <SP:$%04X>", reg.PC - 2, reg.IX, reg.SP);
#endif
push(getIXH(), 4);
push(getIXL(), 3);
}
// Pop Reg. IX from Stack.
static inline void POP_IX_(Z80* ctx) { ctx->POP_IX(); }
inline void POP_IX()
{
#ifndef Z80_DISABLE_DEBUG
unsigned short sp = reg.SP;
#endif
setIXL(pop(3));
setIXH(pop(3));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] POP IX <SP:$%04X> = $%04X", reg.PC - 2, sp, reg.IX);
#endif
}
// Push Reg. IY on Stack.
static inline void PUSH_IY_(Z80* ctx) { ctx->PUSH_IY(); }
inline void PUSH_IY()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] PUSH IY<$%04X> <SP:$%04X>", reg.PC - 2, reg.IY, reg.SP);
#endif
push(getIYH(), 4);
push(getIYL(), 3);
}
// Pop Reg. IY from Stack.
static inline void POP_IY_(Z80* ctx) { ctx->POP_IY(); }
inline void POP_IY()
{
#ifndef Z80_DISABLE_DEBUG
unsigned short sp = reg.SP;
#endif
setIYL(pop(3));
setIYH(pop(3));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] POP IY <SP:$%04X> = $%04X", reg.PC - 2, sp, reg.IY);
#endif
}
inline void setFlagByRotate(unsigned char n, bool carry, bool isA = false)
{
setFlagC(carry);
resetFlagH();
resetFlagN();
setFlagXY(n);
if (!isA) {
setFlagS(n & 0x80);
setFlagZ(0 == n);
setFlagPV(isEvenNumberBits(n));
}
}
inline unsigned char SLL(unsigned char n)
{
unsigned char c = n & 0x80;
n &= 0b01111111;
n <<= 1;
n |= 1; // differ with SLA
setFlagByRotate(n, c);
return n;
}
inline unsigned char SLA(unsigned char n)
{
unsigned char c = (n & 0x80) >> 7;
n &= 0b01111111;
n <<= 1;
setFlagByRotate(n, c);
return n;
}
inline unsigned char SRL(unsigned char n)
{
unsigned char n0 = n & 0x01;
n &= 0b11111110;
n >>= 1;
setFlagByRotate(n, n0);
return n;
}
inline unsigned char SRA(unsigned char n)
{
unsigned char n0 = n & 0x01;
unsigned char n7 = n & 0x80;
n &= 0b11111110;
n >>= 1;
n = n7 ? n | 0x80 : n & 0x7F;
setFlagByRotate(n, n0);
return n;
}
inline unsigned char RLC(unsigned char n, bool isA = false)
{
unsigned char c = (n & 0x80) >> 7;
n &= 0b01111111;
n <<= 1;
n |= c; // differ with RL
setFlagByRotate(n, c, isA);
return n;
}
inline unsigned char RL(unsigned char n, bool isA = false)
{
unsigned char c = (n & 0x80) >> 7;
n &= 0b01111111;
n <<= 1;
n |= isFlagC() ? 1 : 0; // differ with RLC
setFlagByRotate(n, c, isA);
return n;
}
inline unsigned char RRC(unsigned char n, bool isA = false)
{
unsigned char c = (n & 1) << 7;
n &= 0b11111110;
n >>= 1;
n |= c; // differ with RR
setFlagByRotate(n, c, isA);
return n;
}
inline unsigned char RR(unsigned char n, bool isA = false)
{
unsigned char c = (n & 1) << 7;
n &= 0b11111110;
n >>= 1;
n |= isFlagC() ? 0x80 : 0; // differ with RR
setFlagByRotate(n, c, isA);
return n;
}
static inline void RLCA(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] RLCA <A:$%02X, C:%s>", ctx->reg.PC - 1, ctx->reg.pair.A, ctx->isFlagC() ? "ON" : "OFF");
#endif
ctx->reg.pair.A = ctx->RLC(ctx->reg.pair.A, true);
}
static inline void RRCA(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] RRCA <A:$%02X, C:%s>", ctx->reg.PC - 1, ctx->reg.pair.A, ctx->isFlagC() ? "ON" : "OFF");
#endif
ctx->reg.pair.A = ctx->RRC(ctx->reg.pair.A, true);
}
static inline void RLA(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] RLA <A:$%02X, C:%s>", ctx->reg.PC - 1, ctx->reg.pair.A, ctx->isFlagC() ? "ON" : "OFF");
#endif
ctx->reg.pair.A = ctx->RL(ctx->reg.pair.A, true);
}
static inline void RRA(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] RRA <A:$%02X, C:%s>", ctx->reg.PC - 1, ctx->reg.pair.A, ctx->isFlagC() ? "ON" : "OFF");
#endif
ctx->reg.pair.A = ctx->RR(ctx->reg.pair.A, true);
}
// Rotate register Left Circular
static inline void RLC_B(Z80* ctx) { ctx->RLC_R(0b000); }
static inline void RLC_C(Z80* ctx) { ctx->RLC_R(0b001); }
static inline void RLC_D(Z80* ctx) { ctx->RLC_R(0b010); }
static inline void RLC_E(Z80* ctx) { ctx->RLC_R(0b011); }
static inline void RLC_H(Z80* ctx) { ctx->RLC_R(0b100); }
static inline void RLC_L(Z80* ctx) { ctx->RLC_R(0b101); }
static inline void RLC_A(Z80* ctx) { ctx->RLC_R(0b111); }
inline void RLC_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RLC %s", reg.PC - 2, registerDump(r));
#endif
*rp = RLC(*rp);
}
// Rotate Left register
static inline void RL_B(Z80* ctx) { ctx->RL_R(0b000); }
static inline void RL_C(Z80* ctx) { ctx->RL_R(0b001); }
static inline void RL_D(Z80* ctx) { ctx->RL_R(0b010); }
static inline void RL_E(Z80* ctx) { ctx->RL_R(0b011); }
static inline void RL_H(Z80* ctx) { ctx->RL_R(0b100); }
static inline void RL_L(Z80* ctx) { ctx->RL_R(0b101); }
static inline void RL_A(Z80* ctx) { ctx->RL_R(0b111); }
inline void RL_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RL %s <C:%s>", reg.PC - 2, registerDump(r), isFlagC() ? "ON" : "OFF");
#endif
*rp = RL(*rp);
}
// Shift operand register left Arithmetic
static inline void SLA_B(Z80* ctx) { ctx->SLA_R(0b000); }
static inline void SLA_C(Z80* ctx) { ctx->SLA_R(0b001); }
static inline void SLA_D(Z80* ctx) { ctx->SLA_R(0b010); }
static inline void SLA_E(Z80* ctx) { ctx->SLA_R(0b011); }
static inline void SLA_H(Z80* ctx) { ctx->SLA_R(0b100); }
static inline void SLA_L(Z80* ctx) { ctx->SLA_R(0b101); }
static inline void SLA_A(Z80* ctx) { ctx->SLA_R(0b111); }
inline void SLA_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SLA %s", reg.PC - 2, registerDump(r));
#endif
*rp = SLA(*rp);
}
// Rotate register Right Circular
static inline void RRC_B(Z80* ctx) { ctx->RRC_R(0b000); }
static inline void RRC_C(Z80* ctx) { ctx->RRC_R(0b001); }
static inline void RRC_D(Z80* ctx) { ctx->RRC_R(0b010); }
static inline void RRC_E(Z80* ctx) { ctx->RRC_R(0b011); }
static inline void RRC_H(Z80* ctx) { ctx->RRC_R(0b100); }
static inline void RRC_L(Z80* ctx) { ctx->RRC_R(0b101); }
static inline void RRC_A(Z80* ctx) { ctx->RRC_R(0b111); }
inline void RRC_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RRC %s", reg.PC - 2, registerDump(r));
#endif
*rp = RRC(*rp);
}
// Rotate Right register
static inline void RR_B(Z80* ctx) { ctx->RR_R(0b000); }
static inline void RR_C(Z80* ctx) { ctx->RR_R(0b001); }
static inline void RR_D(Z80* ctx) { ctx->RR_R(0b010); }
static inline void RR_E(Z80* ctx) { ctx->RR_R(0b011); }
static inline void RR_H(Z80* ctx) { ctx->RR_R(0b100); }
static inline void RR_L(Z80* ctx) { ctx->RR_R(0b101); }
static inline void RR_A(Z80* ctx) { ctx->RR_R(0b111); }
inline void RR_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RR %s <C:%s>", reg.PC - 2, registerDump(r), isFlagC() ? "ON" : "OFF");
#endif
*rp = RR(*rp);
}
// Shift operand register Right Arithmetic
static inline void SRA_B(Z80* ctx) { ctx->SRA_R(0b000); }
static inline void SRA_C(Z80* ctx) { ctx->SRA_R(0b001); }
static inline void SRA_D(Z80* ctx) { ctx->SRA_R(0b010); }
static inline void SRA_E(Z80* ctx) { ctx->SRA_R(0b011); }
static inline void SRA_H(Z80* ctx) { ctx->SRA_R(0b100); }
static inline void SRA_L(Z80* ctx) { ctx->SRA_R(0b101); }
static inline void SRA_A(Z80* ctx) { ctx->SRA_R(0b111); }
inline void SRA_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SRA %s", reg.PC - 2, registerDump(r));
#endif
*rp = SRA(*rp);
}
// Shift operand register Right Logical
static inline void SRL_B(Z80* ctx) { ctx->SRL_R(0b000); }
static inline void SRL_C(Z80* ctx) { ctx->SRL_R(0b001); }
static inline void SRL_D(Z80* ctx) { ctx->SRL_R(0b010); }
static inline void SRL_E(Z80* ctx) { ctx->SRL_R(0b011); }
static inline void SRL_H(Z80* ctx) { ctx->SRL_R(0b100); }
static inline void SRL_L(Z80* ctx) { ctx->SRL_R(0b101); }
static inline void SRL_A(Z80* ctx) { ctx->SRL_R(0b111); }
inline void SRL_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SRL %s", reg.PC - 2, registerDump(r));
#endif
*rp = SRL(*rp);
}
// Shift operand register Left Logical
static inline void SLL_B(Z80* ctx) { ctx->SLL_R(0b000); }
static inline void SLL_C(Z80* ctx) { ctx->SLL_R(0b001); }
static inline void SLL_D(Z80* ctx) { ctx->SLL_R(0b010); }
static inline void SLL_E(Z80* ctx) { ctx->SLL_R(0b011); }
static inline void SLL_H(Z80* ctx) { ctx->SLL_R(0b100); }
static inline void SLL_L(Z80* ctx) { ctx->SLL_R(0b101); }
static inline void SLL_A(Z80* ctx) { ctx->SLL_R(0b111); }
inline void SLL_R(unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SLL %s", reg.PC - 2, registerDump(r));
#endif
*rp = SLL(*rp);
}
// Rotate memory (HL) Left Circular
static inline void RLC_HL_(Z80* ctx) { ctx->RLC_HL(); }
inline void RLC_HL()
{
unsigned short addr = getHL();
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RLC (HL<$%04X>) = $%02X", reg.PC - 2, addr, n);
#endif
writeByte(addr, RLC(n), 3);
}
// Rotate Left memory
static inline void RL_HL_(Z80* ctx) { ctx->RL_HL(); }
inline void RL_HL()
{
unsigned short addr = getHL();
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RL (HL<$%04X>) = $%02X <C:%s>", reg.PC - 2, addr, n, isFlagC() ? "ON" : "OFF");
#endif
writeByte(addr, RL(n), 3);
}
// Shift operand location (HL) left Arithmetic
static inline void SLA_HL_(Z80* ctx) { ctx->SLA_HL(); }
inline void SLA_HL()
{
unsigned short addr = getHL();
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SLA (HL<$%04X>) = $%02X", reg.PC - 2, addr, n);
#endif
writeByte(addr, SLA(n), 3);
}
// Rotate memory (HL) Right Circular
static inline void RRC_HL_(Z80* ctx) { ctx->RRC_HL(); }
inline void RRC_HL()
{
unsigned short addr = getHL();
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RRC (HL<$%04X>) = $%02X", reg.PC - 2, addr, n);
#endif
writeByte(addr, RRC(n), 3);
}
// Rotate Right memory
static inline void RR_HL_(Z80* ctx) { ctx->RR_HL(); }
inline void RR_HL()
{
unsigned short addr = getHL();
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RR (HL<$%04X>) = $%02X <C:%s>", reg.PC - 2, addr, n, isFlagC() ? "ON" : "OFF");
#endif
writeByte(addr, RR(n), 3);
}
// Shift operand location (HL) Right Arithmetic
static inline void SRA_HL_(Z80* ctx) { ctx->SRA_HL(); }
inline void SRA_HL()
{
unsigned short addr = getHL();
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SRA (HL<$%04X>) = $%02X", reg.PC - 2, addr, n);
#endif
writeByte(addr, SRA(n), 3);
}
// Shift operand location (HL) Right Logical
static inline void SRL_HL_(Z80* ctx) { ctx->SRL_HL(); }
inline void SRL_HL()
{
unsigned short addr = getHL();
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SRL (HL<$%04X>) = $%02X", reg.PC - 2, addr, n);
#endif
writeByte(addr, SRL(n), 3);
}
// Shift operand location (HL) Left Logical
static inline void SLL_HL_(Z80* ctx) { ctx->SLL_HL(); }
inline void SLL_HL()
{
unsigned short addr = getHL();
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SLL (HL<$%04X>) = $%02X", reg.PC - 2, addr, n);
#endif
writeByte(addr, SLL(n), 3);
}
// Rotate memory (IX+d) Left Circular
static inline void RLC_IX_(Z80* ctx, signed char d) { ctx->RLC_IX(d); }
inline void RLC_IX(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RLC (IX+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = RLC(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Rotate memory (IX+d) Left Circular with load to Reg A/B/C/D/E/H/L/F
static inline void RLC_IX_with_LD_B(Z80* ctx, signed char d) { ctx->RLC_IX_with_LD(d, 0b000); }
static inline void RLC_IX_with_LD_C(Z80* ctx, signed char d) { ctx->RLC_IX_with_LD(d, 0b001); }
static inline void RLC_IX_with_LD_D(Z80* ctx, signed char d) { ctx->RLC_IX_with_LD(d, 0b010); }
static inline void RLC_IX_with_LD_E(Z80* ctx, signed char d) { ctx->RLC_IX_with_LD(d, 0b011); }
static inline void RLC_IX_with_LD_H(Z80* ctx, signed char d) { ctx->RLC_IX_with_LD(d, 0b100); }
static inline void RLC_IX_with_LD_L(Z80* ctx, signed char d) { ctx->RLC_IX_with_LD(d, 0b101); }
static inline void RLC_IX_with_LD_A(Z80* ctx, signed char d) { ctx->RLC_IX_with_LD(d, 0b111); }
inline void RLC_IX_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
RLC_IX(d, rp, buf);
#else
RLC_IX(d, rp);
#endif
}
// Rotate memory (IY+d) Left Circular with load to Reg A/B/C/D/E/H/L/F
static inline void RLC_IY_with_LD_B(Z80* ctx, signed char d) { ctx->RLC_IY_with_LD(d, 0b000); }
static inline void RLC_IY_with_LD_C(Z80* ctx, signed char d) { ctx->RLC_IY_with_LD(d, 0b001); }
static inline void RLC_IY_with_LD_D(Z80* ctx, signed char d) { ctx->RLC_IY_with_LD(d, 0b010); }
static inline void RLC_IY_with_LD_E(Z80* ctx, signed char d) { ctx->RLC_IY_with_LD(d, 0b011); }
static inline void RLC_IY_with_LD_H(Z80* ctx, signed char d) { ctx->RLC_IY_with_LD(d, 0b100); }
static inline void RLC_IY_with_LD_L(Z80* ctx, signed char d) { ctx->RLC_IY_with_LD(d, 0b101); }
static inline void RLC_IY_with_LD_A(Z80* ctx, signed char d) { ctx->RLC_IY_with_LD(d, 0b111); }
inline void RLC_IY_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
RLC_IY(d, rp, buf);
#else
RLC_IY(d, rp);
#endif
}
// Rotate memory (IX+d) Right Circular
static inline void RRC_IX_(Z80* ctx, signed char d) { ctx->RRC_IX(d); }
inline void RRC_IX(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RRC (IX+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = RRC(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Rotate memory (IX+d) Right Circular with load to Reg A/B/C/D/E/H/L/F
static inline void RRC_IX_with_LD_B(Z80* ctx, signed char d) { ctx->RRC_IX_with_LD(d, 0b000); }
static inline void RRC_IX_with_LD_C(Z80* ctx, signed char d) { ctx->RRC_IX_with_LD(d, 0b001); }
static inline void RRC_IX_with_LD_D(Z80* ctx, signed char d) { ctx->RRC_IX_with_LD(d, 0b010); }
static inline void RRC_IX_with_LD_E(Z80* ctx, signed char d) { ctx->RRC_IX_with_LD(d, 0b011); }
static inline void RRC_IX_with_LD_H(Z80* ctx, signed char d) { ctx->RRC_IX_with_LD(d, 0b100); }
static inline void RRC_IX_with_LD_L(Z80* ctx, signed char d) { ctx->RRC_IX_with_LD(d, 0b101); }
static inline void RRC_IX_with_LD_A(Z80* ctx, signed char d) { ctx->RRC_IX_with_LD(d, 0b111); }
inline void RRC_IX_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
RRC_IX(d, rp, buf);
#else
RRC_IX(d, rp);
#endif
}
// Rotate memory (IY+d) Right Circular with load to Reg A/B/C/D/E/H/L/F
static inline void RRC_IY_with_LD_B(Z80* ctx, signed char d) { ctx->RRC_IY_with_LD(d, 0b000); }
static inline void RRC_IY_with_LD_C(Z80* ctx, signed char d) { ctx->RRC_IY_with_LD(d, 0b001); }
static inline void RRC_IY_with_LD_D(Z80* ctx, signed char d) { ctx->RRC_IY_with_LD(d, 0b010); }
static inline void RRC_IY_with_LD_E(Z80* ctx, signed char d) { ctx->RRC_IY_with_LD(d, 0b011); }
static inline void RRC_IY_with_LD_H(Z80* ctx, signed char d) { ctx->RRC_IY_with_LD(d, 0b100); }
static inline void RRC_IY_with_LD_L(Z80* ctx, signed char d) { ctx->RRC_IY_with_LD(d, 0b101); }
static inline void RRC_IY_with_LD_A(Z80* ctx, signed char d) { ctx->RRC_IY_with_LD(d, 0b111); }
inline void RRC_IY_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
RRC_IY(d, rp, buf);
#else
RRC_IY(d, rp);
#endif
}
// Rotate Left memory
static inline void RL_IX_(Z80* ctx, signed char d) { ctx->RL_IX(d); }
inline void RL_IX(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RL (IX+d<$%04X>) = $%02X <C:%s>%s", reg.PC - 4, addr, n, isFlagC() ? "ON" : "OFF", extraLog ? extraLog : "");
#endif
unsigned char result = RL(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Rotate Left memory with load Reg.
static inline void RL_IX_with_LD_B(Z80* ctx, signed char d) { ctx->RL_IX_with_LD(d, 0b000); }
static inline void RL_IX_with_LD_C(Z80* ctx, signed char d) { ctx->RL_IX_with_LD(d, 0b001); }
static inline void RL_IX_with_LD_D(Z80* ctx, signed char d) { ctx->RL_IX_with_LD(d, 0b010); }
static inline void RL_IX_with_LD_E(Z80* ctx, signed char d) { ctx->RL_IX_with_LD(d, 0b011); }
static inline void RL_IX_with_LD_H(Z80* ctx, signed char d) { ctx->RL_IX_with_LD(d, 0b100); }
static inline void RL_IX_with_LD_L(Z80* ctx, signed char d) { ctx->RL_IX_with_LD(d, 0b101); }
static inline void RL_IX_with_LD_A(Z80* ctx, signed char d) { ctx->RL_IX_with_LD(d, 0b111); }
inline void RL_IX_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
RL_IX(d, rp, buf);
#else
RL_IX(d, rp);
#endif
}
// Rotate Left memory with load Reg.
static inline void RL_IY_with_LD_B(Z80* ctx, signed char d) { ctx->RL_IY_with_LD(d, 0b000); }
static inline void RL_IY_with_LD_C(Z80* ctx, signed char d) { ctx->RL_IY_with_LD(d, 0b001); }
static inline void RL_IY_with_LD_D(Z80* ctx, signed char d) { ctx->RL_IY_with_LD(d, 0b010); }
static inline void RL_IY_with_LD_E(Z80* ctx, signed char d) { ctx->RL_IY_with_LD(d, 0b011); }
static inline void RL_IY_with_LD_H(Z80* ctx, signed char d) { ctx->RL_IY_with_LD(d, 0b100); }
static inline void RL_IY_with_LD_L(Z80* ctx, signed char d) { ctx->RL_IY_with_LD(d, 0b101); }
static inline void RL_IY_with_LD_A(Z80* ctx, signed char d) { ctx->RL_IY_with_LD(d, 0b111); }
inline void RL_IY_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
RL_IY(d, rp, buf);
#else
RL_IY(d, rp);
#endif
}
// Rotate Right memory
static inline void RR_IX_(Z80* ctx, signed char d) { ctx->RR_IX(d); }
inline void RR_IX(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RR (IX+d<$%04X>) = $%02X <C:%s>%s", reg.PC - 4, addr, n, isFlagC() ? "ON" : "OFF", extraLog ? extraLog : "");
#endif
unsigned char result = RR(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Rotate Right memory with load Reg.
static inline void RR_IX_with_LD_B(Z80* ctx, signed char d) { ctx->RR_IX_with_LD(d, 0b000); }
static inline void RR_IX_with_LD_C(Z80* ctx, signed char d) { ctx->RR_IX_with_LD(d, 0b001); }
static inline void RR_IX_with_LD_D(Z80* ctx, signed char d) { ctx->RR_IX_with_LD(d, 0b010); }
static inline void RR_IX_with_LD_E(Z80* ctx, signed char d) { ctx->RR_IX_with_LD(d, 0b011); }
static inline void RR_IX_with_LD_H(Z80* ctx, signed char d) { ctx->RR_IX_with_LD(d, 0b100); }
static inline void RR_IX_with_LD_L(Z80* ctx, signed char d) { ctx->RR_IX_with_LD(d, 0b101); }
static inline void RR_IX_with_LD_A(Z80* ctx, signed char d) { ctx->RR_IX_with_LD(d, 0b111); }
inline void RR_IX_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
RR_IX(d, rp, buf);
#else
RR_IX(d, rp);
#endif
}
// Rotate Right memory with load Reg.
static inline void RR_IY_with_LD_B(Z80* ctx, signed char d) { ctx->RR_IY_with_LD(d, 0b000); }
static inline void RR_IY_with_LD_C(Z80* ctx, signed char d) { ctx->RR_IY_with_LD(d, 0b001); }
static inline void RR_IY_with_LD_D(Z80* ctx, signed char d) { ctx->RR_IY_with_LD(d, 0b010); }
static inline void RR_IY_with_LD_E(Z80* ctx, signed char d) { ctx->RR_IY_with_LD(d, 0b011); }
static inline void RR_IY_with_LD_H(Z80* ctx, signed char d) { ctx->RR_IY_with_LD(d, 0b100); }
static inline void RR_IY_with_LD_L(Z80* ctx, signed char d) { ctx->RR_IY_with_LD(d, 0b101); }
static inline void RR_IY_with_LD_A(Z80* ctx, signed char d) { ctx->RR_IY_with_LD(d, 0b111); }
inline void RR_IY_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
RR_IY(d, rp, buf);
#else
RR_IY(d, rp);
#endif
}
// Shift operand location (IX+d) left Arithmetic
static inline void SLA_IX_(Z80* ctx, signed char d) { ctx->SLA_IX(d); }
inline void SLA_IX(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SLA (IX+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = SLA(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Shift operand location (IX+d) left Arithmetic with load Reg.
static inline void SLA_IX_with_LD_B(Z80* ctx, signed char d) { ctx->SLA_IX_with_LD(d, 0b000); }
static inline void SLA_IX_with_LD_C(Z80* ctx, signed char d) { ctx->SLA_IX_with_LD(d, 0b001); }
static inline void SLA_IX_with_LD_D(Z80* ctx, signed char d) { ctx->SLA_IX_with_LD(d, 0b010); }
static inline void SLA_IX_with_LD_E(Z80* ctx, signed char d) { ctx->SLA_IX_with_LD(d, 0b011); }
static inline void SLA_IX_with_LD_H(Z80* ctx, signed char d) { ctx->SLA_IX_with_LD(d, 0b100); }
static inline void SLA_IX_with_LD_L(Z80* ctx, signed char d) { ctx->SLA_IX_with_LD(d, 0b101); }
static inline void SLA_IX_with_LD_A(Z80* ctx, signed char d) { ctx->SLA_IX_with_LD(d, 0b111); }
inline void SLA_IX_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
SLA_IX(d, rp, buf);
#else
SLA_IX(d, rp);
#endif
}
// Shift operand location (IY+d) left Arithmetic with load Reg.
static inline void SLA_IY_with_LD_B(Z80* ctx, signed char d) { ctx->SLA_IY_with_LD(d, 0b000); }
static inline void SLA_IY_with_LD_C(Z80* ctx, signed char d) { ctx->SLA_IY_with_LD(d, 0b001); }
static inline void SLA_IY_with_LD_D(Z80* ctx, signed char d) { ctx->SLA_IY_with_LD(d, 0b010); }
static inline void SLA_IY_with_LD_E(Z80* ctx, signed char d) { ctx->SLA_IY_with_LD(d, 0b011); }
static inline void SLA_IY_with_LD_H(Z80* ctx, signed char d) { ctx->SLA_IY_with_LD(d, 0b100); }
static inline void SLA_IY_with_LD_L(Z80* ctx, signed char d) { ctx->SLA_IY_with_LD(d, 0b101); }
static inline void SLA_IY_with_LD_A(Z80* ctx, signed char d) { ctx->SLA_IY_with_LD(d, 0b111); }
inline void SLA_IY_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
SLA_IY(d, rp, buf);
#else
SLA_IY(d, rp);
#endif
}
// Shift operand location (IX+d) Right Arithmetic
static inline void SRA_IX_(Z80* ctx, signed char d) { ctx->SRA_IX(d); }
inline void SRA_IX(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SRA (IX+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = SRA(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Shift operand location (IX+d) right Arithmetic with load Reg.
static inline void SRA_IX_with_LD_B(Z80* ctx, signed char d) { ctx->SRA_IX_with_LD(d, 0b000); }
static inline void SRA_IX_with_LD_C(Z80* ctx, signed char d) { ctx->SRA_IX_with_LD(d, 0b001); }
static inline void SRA_IX_with_LD_D(Z80* ctx, signed char d) { ctx->SRA_IX_with_LD(d, 0b010); }
static inline void SRA_IX_with_LD_E(Z80* ctx, signed char d) { ctx->SRA_IX_with_LD(d, 0b011); }
static inline void SRA_IX_with_LD_H(Z80* ctx, signed char d) { ctx->SRA_IX_with_LD(d, 0b100); }
static inline void SRA_IX_with_LD_L(Z80* ctx, signed char d) { ctx->SRA_IX_with_LD(d, 0b101); }
static inline void SRA_IX_with_LD_A(Z80* ctx, signed char d) { ctx->SRA_IX_with_LD(d, 0b111); }
inline void SRA_IX_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
SRA_IX(d, rp, buf);
#else
SRA_IX(d, rp);
#endif
}
// Shift operand location (IY+d) right Arithmetic with load Reg.
static inline void SRA_IY_with_LD_B(Z80* ctx, signed char d) { ctx->SRA_IY_with_LD(d, 0b000); }
static inline void SRA_IY_with_LD_C(Z80* ctx, signed char d) { ctx->SRA_IY_with_LD(d, 0b001); }
static inline void SRA_IY_with_LD_D(Z80* ctx, signed char d) { ctx->SRA_IY_with_LD(d, 0b010); }
static inline void SRA_IY_with_LD_E(Z80* ctx, signed char d) { ctx->SRA_IY_with_LD(d, 0b011); }
static inline void SRA_IY_with_LD_H(Z80* ctx, signed char d) { ctx->SRA_IY_with_LD(d, 0b100); }
static inline void SRA_IY_with_LD_L(Z80* ctx, signed char d) { ctx->SRA_IY_with_LD(d, 0b101); }
static inline void SRA_IY_with_LD_A(Z80* ctx, signed char d) { ctx->SRA_IY_with_LD(d, 0b111); }
inline void SRA_IY_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
SRA_IY(d, rp, buf);
#else
SRA_IY(d, rp);
#endif
}
// Shift operand location (IX+d) Right Logical
static inline void SRL_IX_(Z80* ctx, signed char d) { ctx->SRL_IX(d); }
inline void SRL_IX(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SRL (IX+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = SRL(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Shift operand location (IX+d) Right Logical with load Reg.
static inline void SRL_IX_with_LD_B(Z80* ctx, signed char d) { ctx->SRL_IX_with_LD(d, 0b000); }
static inline void SRL_IX_with_LD_C(Z80* ctx, signed char d) { ctx->SRL_IX_with_LD(d, 0b001); }
static inline void SRL_IX_with_LD_D(Z80* ctx, signed char d) { ctx->SRL_IX_with_LD(d, 0b010); }
static inline void SRL_IX_with_LD_E(Z80* ctx, signed char d) { ctx->SRL_IX_with_LD(d, 0b011); }
static inline void SRL_IX_with_LD_H(Z80* ctx, signed char d) { ctx->SRL_IX_with_LD(d, 0b100); }
static inline void SRL_IX_with_LD_L(Z80* ctx, signed char d) { ctx->SRL_IX_with_LD(d, 0b101); }
static inline void SRL_IX_with_LD_A(Z80* ctx, signed char d) { ctx->SRL_IX_with_LD(d, 0b111); }
inline void SRL_IX_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
SRL_IX(d, rp, buf);
#else
SRL_IX(d, rp);
#endif
}
// Shift operand location (IY+d) Right Logical with load Reg.
static inline void SRL_IY_with_LD_B(Z80* ctx, signed char d) { ctx->SRL_IY_with_LD(d, 0b000); }
static inline void SRL_IY_with_LD_C(Z80* ctx, signed char d) { ctx->SRL_IY_with_LD(d, 0b001); }
static inline void SRL_IY_with_LD_D(Z80* ctx, signed char d) { ctx->SRL_IY_with_LD(d, 0b010); }
static inline void SRL_IY_with_LD_E(Z80* ctx, signed char d) { ctx->SRL_IY_with_LD(d, 0b011); }
static inline void SRL_IY_with_LD_H(Z80* ctx, signed char d) { ctx->SRL_IY_with_LD(d, 0b100); }
static inline void SRL_IY_with_LD_L(Z80* ctx, signed char d) { ctx->SRL_IY_with_LD(d, 0b101); }
static inline void SRL_IY_with_LD_A(Z80* ctx, signed char d) { ctx->SRL_IY_with_LD(d, 0b111); }
inline void SRL_IY_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
SRL_IY(d, rp, buf);
#else
SRL_IY(d, rp);
#endif
}
// Shift operand location (IX+d) Left Logical
// NOTE: this function is only for SLL_IX_with_LD
static inline void SLL_IX_(Z80* ctx, signed char d) { ctx->SLL_IX(d); }
inline void SLL_IX(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SLL (IX+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = SLL(n);
writeByte(addr, result, 3);
if (rp) *rp = result;
}
// Shift operand location (IX+d) Left Logical with load Reg.
static inline void SLL_IX_with_LD_B(Z80* ctx, signed char d) { ctx->SLL_IX_with_LD(d, 0b000); }
static inline void SLL_IX_with_LD_C(Z80* ctx, signed char d) { ctx->SLL_IX_with_LD(d, 0b001); }
static inline void SLL_IX_with_LD_D(Z80* ctx, signed char d) { ctx->SLL_IX_with_LD(d, 0b010); }
static inline void SLL_IX_with_LD_E(Z80* ctx, signed char d) { ctx->SLL_IX_with_LD(d, 0b011); }
static inline void SLL_IX_with_LD_H(Z80* ctx, signed char d) { ctx->SLL_IX_with_LD(d, 0b100); }
static inline void SLL_IX_with_LD_L(Z80* ctx, signed char d) { ctx->SLL_IX_with_LD(d, 0b101); }
static inline void SLL_IX_with_LD_A(Z80* ctx, signed char d) { ctx->SLL_IX_with_LD(d, 0b111); }
inline void SLL_IX_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
SLL_IX(d, rp, buf);
#else
SLL_IX(d, rp);
#endif
}
// Shift operand location (IY+d) Left Logical
// NOTE: this function is only for SLL_IY_with_LD
static inline void SLL_IY_(Z80* ctx, signed char d) { ctx->SLL_IY(d); }
inline void SLL_IY(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SLL (IY+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = SLL(n);
writeByte(addr, result, 3);
if (rp) *rp = result;
}
// Shift operand location (IY+d) Left Logical with load Reg.
static inline void SLL_IY_with_LD_B(Z80* ctx, signed char d) { ctx->SLL_IY_with_LD(d, 0b000); }
static inline void SLL_IY_with_LD_C(Z80* ctx, signed char d) { ctx->SLL_IY_with_LD(d, 0b001); }
static inline void SLL_IY_with_LD_D(Z80* ctx, signed char d) { ctx->SLL_IY_with_LD(d, 0b010); }
static inline void SLL_IY_with_LD_E(Z80* ctx, signed char d) { ctx->SLL_IY_with_LD(d, 0b011); }
static inline void SLL_IY_with_LD_H(Z80* ctx, signed char d) { ctx->SLL_IY_with_LD(d, 0b100); }
static inline void SLL_IY_with_LD_L(Z80* ctx, signed char d) { ctx->SLL_IY_with_LD(d, 0b101); }
static inline void SLL_IY_with_LD_A(Z80* ctx, signed char d) { ctx->SLL_IY_with_LD(d, 0b111); }
inline void SLL_IY_with_LD(signed char d, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
SLL_IY(d, rp, buf);
#else
SLL_IY(d, rp);
#endif
}
// Rotate memory (IY+d) Left Circular
static inline void RLC_IY_(Z80* ctx, signed char d) { ctx->RLC_IY(d); }
inline void RLC_IY(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RLC (IY+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = RLC(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Rotate memory (IY+d) Right Circular
static inline void RRC_IY_(Z80* ctx, signed char d) { ctx->RRC_IY(d); }
inline void RRC_IY(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RRC (IY+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = RRC(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Rotate Left memory
static inline void RL_IY_(Z80* ctx, signed char d) { ctx->RL_IY(d); }
inline void RL_IY(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RL (IY+d<$%04X>) = $%02X <C:%s>%s", reg.PC - 4, addr, n, isFlagC() ? "ON" : "OFF", extraLog ? extraLog : "");
#endif
unsigned char result = RL(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Shift operand location (IY+d) left Arithmetic
static inline void SLA_IY_(Z80* ctx, signed char d) { ctx->SLA_IY(d); }
inline void SLA_IY(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SLA (IY+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = SLA(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Rotate Right memory
static inline void RR_IY_(Z80* ctx, signed char d) { ctx->RR_IY(d); }
inline void RR_IY(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RR (IY+d<$%04X>) = $%02X <C:%s>%s", reg.PC - 4, addr, n, isFlagC() ? "ON" : "OFF", extraLog ? extraLog : "");
#endif
unsigned char result = RR(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Shift operand location (IY+d) Right Arithmetic
static inline void SRA_IY_(Z80* ctx, signed char d) { ctx->SRA_IY(d); }
inline void SRA_IY(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SRA (IY+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = SRA(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
// Shift operand location (IY+d) Right Logical
static inline void SRL_IY_(Z80* ctx, signed char d) { ctx->SRL_IY(d); }
inline void SRL_IY(signed char d, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SRL (IY+d<$%04X>) = $%02X%s", reg.PC - 4, addr, n, extraLog ? extraLog : "");
#endif
unsigned char result = SRL(n);
if (rp) *rp = result;
writeByte(addr, result, 3);
}
inline void addition8(int addition, int carry) { arithmetic8(false, addition, carry, true, true); }
inline void subtract8(int subtract, int carry, bool setCarry = true, bool setResult = true) { arithmetic8(true, subtract, carry, setCarry, setResult); }
inline void arithmetic8(bool negative, int addition, int carry, bool setCarry, bool setResult)
{
int before = reg.pair.A;
int result = before + (negative ? -addition - carry : addition + carry);
int carryX = before ^ addition ^ result;
unsigned char finalResult = result & 0xFF;
setFlagZ(0 == finalResult);
setFlagN(negative);
setFlagS(0x80 & finalResult);
setFlagH(carryX & 0x10);
setFlagPV(((carryX << 1) ^ carryX) & 0x100);
if (setCarry) setFlagC(carryX & 0x100);
if (setResult) {
reg.pair.A = finalResult;
setFlagXY(reg.pair.A);
} else {
setFlagXY(addition);
}
}
inline void setFlagByIncrement(unsigned char before)
{
unsigned char finalResult = before + 1;
resetFlagN();
setFlagZ(0 == finalResult);
setFlagS(0x80 & finalResult);
setFlagH((finalResult & 0x0F) == 0x00);
setFlagPV(finalResult == 0x80);
setFlagXY(finalResult);
}
inline void setFlagByDecrement(unsigned char before)
{
unsigned char finalResult = before - 1;
setFlagN();
setFlagZ(0 == finalResult);
setFlagS(0x80 & finalResult);
setFlagH((finalResult & 0x0F) == 0x0F);
setFlagPV(finalResult == 0x7F);
setFlagXY(finalResult);
}
// Add Reg. r to Acc.
static inline void ADD_B(Z80* ctx) { ctx->ADD_R(0b000); }
static inline void ADD_C(Z80* ctx) { ctx->ADD_R(0b001); }
static inline void ADD_D(Z80* ctx) { ctx->ADD_R(0b010); }
static inline void ADD_E(Z80* ctx) { ctx->ADD_R(0b011); }
static inline void ADD_H(Z80* ctx) { ctx->ADD_R(0b100); }
static inline void ADD_L(Z80* ctx) { ctx->ADD_R(0b101); }
static inline void ADD_A(Z80* ctx) { ctx->ADD_R(0b111); }
static inline void ADD_B_2(Z80* ctx) { ctx->ADD_R(0b000, 2); }
static inline void ADD_C_2(Z80* ctx) { ctx->ADD_R(0b001, 2); }
static inline void ADD_D_2(Z80* ctx) { ctx->ADD_R(0b010, 2); }
static inline void ADD_E_2(Z80* ctx) { ctx->ADD_R(0b011, 2); }
static inline void ADD_A_2(Z80* ctx) { ctx->ADD_R(0b111, 2); }
inline void ADD_R(unsigned char r, int pc = 1)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADD %s, %s", reg.PC - pc, registerDump(0b111), registerDump(r));
#endif
unsigned char* rp = getRegisterPointer(r);
addition8(*rp, 0);
}
// Add IXH to Acc.
static inline void ADD_IXH_(Z80* ctx) { ctx->ADD_IXH(); }
inline void ADD_IXH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADD %s, IXH<$%02X>", reg.PC - 2, registerDump(0b111), getIXH());
#endif
addition8(getIXH(), 0);
}
// Add IXL to Acc.
static inline void ADD_IXL_(Z80* ctx) { ctx->ADD_IXL(); }
inline void ADD_IXL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADD %s, IXL<$%02X>", reg.PC - 2, registerDump(0b111), getIXL());
#endif
addition8(getIXL(), 0);
}
// Add IYH to Acc.
static inline void ADD_IYH_(Z80* ctx) { ctx->ADD_IYH(); }
inline void ADD_IYH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADD %s, IYH<$%02X>", reg.PC - 2, registerDump(0b111), getIYH());
#endif
addition8(getIYH(), 0);
}
// Add IYL to Acc.
static inline void ADD_IYL_(Z80* ctx) { ctx->ADD_IYL(); }
inline void ADD_IYL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADD %s, IYL<$%02X>", reg.PC - 2, registerDump(0b111), getIYL());
#endif
addition8(getIYL(), 0);
}
// Add value n to Acc.
static inline void ADD_N(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] ADD %s, $%02X", ctx->reg.PC - 2, ctx->registerDump(0b111), n);
#endif
ctx->addition8(n, 0);
}
// Add location (HL) to Acc.
static inline void ADD_HL(Z80* ctx)
{
unsigned short addr = ctx->getHL();
unsigned char n = ctx->readByte(addr, 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] ADD %s, (%s) = $%02X", ctx->reg.PC - 1, ctx->registerDump(0b111), ctx->registerPairDump(0b10), n);
#endif
ctx->addition8(n, 0);
}
// Add location (IX+d) to Acc.
static inline void ADD_IX_(Z80* ctx) { ctx->ADD_IX(); }
inline void ADD_IX()
{
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADD %s, (IX+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), addr, n);
#endif
addition8(n, 0);
consumeClock(3);
}
// Add location (IY+d) to Acc.
static inline void ADD_IY_(Z80* ctx) { ctx->ADD_IY(); }
inline void ADD_IY()
{
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADD %s, (IY+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), addr, n);
#endif
addition8(n, 0);
consumeClock(3);
}
// Add Resister with carry
static inline void ADC_B(Z80* ctx) { ctx->ADC_R(0b000); }
static inline void ADC_C(Z80* ctx) { ctx->ADC_R(0b001); }
static inline void ADC_D(Z80* ctx) { ctx->ADC_R(0b010); }
static inline void ADC_E(Z80* ctx) { ctx->ADC_R(0b011); }
static inline void ADC_H(Z80* ctx) { ctx->ADC_R(0b100); }
static inline void ADC_L(Z80* ctx) { ctx->ADC_R(0b101); }
static inline void ADC_A(Z80* ctx) { ctx->ADC_R(0b111); }
static inline void ADC_B_2(Z80* ctx) { ctx->ADC_R(0b000, 2); }
static inline void ADC_C_2(Z80* ctx) { ctx->ADC_R(0b001, 2); }
static inline void ADC_D_2(Z80* ctx) { ctx->ADC_R(0b010, 2); }
static inline void ADC_E_2(Z80* ctx) { ctx->ADC_R(0b011, 2); }
static inline void ADC_A_2(Z80* ctx) { ctx->ADC_R(0b111, 2); }
inline void ADC_R(unsigned char r, int pc = 1)
{
unsigned char* rp = getRegisterPointer(r);
unsigned char c = isFlagC() ? 1 : 0;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADC %s, %s <C:%s>", reg.PC - pc, registerDump(0b111), registerDump(r), c ? "ON" : "OFF");
#endif
addition8(*rp, c);
}
// Add IXH to Acc.
static inline void ADC_IXH_(Z80* ctx) { ctx->ADC_IXH(); }
inline void ADC_IXH()
{
unsigned char c = isFlagC() ? 1 : 0;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADC %s, IXH<$%02X> <C:%s>", reg.PC - 2, registerDump(0b111), getIXH(), c ? "ON" : "OFF");
#endif
addition8(getIXH(), c);
}
// Add IXL to Acc.
static inline void ADC_IXL_(Z80* ctx) { ctx->ADC_IXL(); }
inline void ADC_IXL()
{
unsigned char c = isFlagC() ? 1 : 0;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADC %s, IXL<$%02X> <C:%s>", reg.PC - 2, registerDump(0b111), getIXL(), c ? "ON" : "OFF");
#endif
addition8(getIXL(), c);
}
// Add IYH to Acc.
static inline void ADC_IYH_(Z80* ctx) { ctx->ADC_IYH(); }
inline void ADC_IYH()
{
unsigned char c = isFlagC() ? 1 : 0;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADC %s, IYH<$%02X> <C:%s>", reg.PC - 2, registerDump(0b111), getIYH(), c ? "ON" : "OFF");
#endif
addition8(getIYH(), c);
}
// Add IYL to Acc.
static inline void ADC_IYL_(Z80* ctx) { ctx->ADC_IYL(); }
inline void ADC_IYL()
{
unsigned char c = isFlagC() ? 1 : 0;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADC %s, IYL<$%02X> <C:%s>", reg.PC - 2, registerDump(0b111), getIYL(), c ? "ON" : "OFF");
#endif
addition8(getIYL(), c);
}
// Add immediate with carry
static inline void ADC_N(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
unsigned char c = ctx->isFlagC() ? 1 : 0;
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] ADC %s, $%02X <C:%s>", ctx->reg.PC - 2, ctx->registerDump(0b111), n, c ? "ON" : "OFF");
#endif
ctx->addition8(n, c);
}
// Add memory with carry
static inline void ADC_HL(Z80* ctx)
{
unsigned short addr = ctx->getHL();
unsigned char n = ctx->readByte(addr, 3);
unsigned char c = ctx->isFlagC() ? 1 : 0;
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] ADC %s, (%s) = $%02X <C:%s>", ctx->reg.PC - 1, ctx->registerDump(0b111), ctx->registerPairDump(0b10), n, c ? "ON" : "OFF");
#endif
ctx->addition8(n, c);
}
// Add memory with carry
static inline void ADC_IX_(Z80* ctx) { ctx->ADC_IX(); }
inline void ADC_IX()
{
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
unsigned char c = isFlagC() ? 1 : 0;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADC %s, (IX+d<$%04X>) = $%02X <C:%s>", reg.PC - 3, registerDump(0b111), addr, n, c ? "ON" : "OFF");
#endif
addition8(n, c);
consumeClock(3);
}
// Add memory with carry
static inline void ADC_IY_(Z80* ctx) { ctx->ADC_IY(); }
inline void ADC_IY()
{
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
unsigned char c = isFlagC() ? 1 : 0;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADC %s, (IY+d<$%04X>) = $%02X <C:%s>", reg.PC - 3, registerDump(0b111), addr, n, c ? "ON" : "OFF");
#endif
addition8(n, c);
consumeClock(3);
}
// Increment Register
static inline void INC_B(Z80* ctx) { ctx->INC_R(0b000); }
static inline void INC_C(Z80* ctx) { ctx->INC_R(0b001); }
static inline void INC_D(Z80* ctx) { ctx->INC_R(0b010); }
static inline void INC_E(Z80* ctx) { ctx->INC_R(0b011); }
static inline void INC_H(Z80* ctx) { ctx->INC_R(0b100); }
static inline void INC_L(Z80* ctx) { ctx->INC_R(0b101); }
static inline void INC_A(Z80* ctx) { ctx->INC_R(0b111); }
static inline void INC_B_2(Z80* ctx) { ctx->INC_R(0b000, 2); }
static inline void INC_C_2(Z80* ctx) { ctx->INC_R(0b001, 2); }
static inline void INC_D_2(Z80* ctx) { ctx->INC_R(0b010, 2); }
static inline void INC_E_2(Z80* ctx) { ctx->INC_R(0b011, 2); }
static inline void INC_A_2(Z80* ctx) { ctx->INC_R(0b111, 2); }
inline void INC_R(unsigned char r, int pc = 1)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] INC %s", reg.PC - pc, registerDump(r));
#endif
setFlagByIncrement(*rp);
(*rp)++;
}
// Increment location (HL)
static inline void INC_HL(Z80* ctx)
{
unsigned short addr = ctx->getHL();
unsigned char n = ctx->readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] INC (%s) = $%02X", ctx->reg.PC - 1, ctx->registerPairDump(0b10), n);
#endif
ctx->setFlagByIncrement(n);
ctx->writeByte(addr, n + 1, 3);
}
// Increment location (IX+d)
static inline void INC_IX_(Z80* ctx) { ctx->INC_IX(); }
inline void INC_IX()
{
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] INC (IX+d<$%04X>) = $%02X", reg.PC - 3, addr, n);
#endif
setFlagByIncrement(n);
writeByte(addr, n + 1);
consumeClock(3);
}
// Increment register high 8 bits of IX
static inline void INC_IXH_(Z80* ctx) { ctx->INC_IXH(); }
inline void INC_IXH()
{
unsigned char ixh = getIXH();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] INC IXH<$%02X>", reg.PC - 2, ixh);
#endif
setFlagByIncrement(ixh++);
setIXH(ixh);
}
// Increment register low 8 bits of IX
static inline void INC_IXL_(Z80* ctx) { ctx->INC_IXL(); }
inline void INC_IXL()
{
unsigned char ixl = getIXL();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] INC IXL<$%02X>", reg.PC - 2, ixl);
#endif
setFlagByIncrement(ixl++);
setIXL(ixl);
}
// Increment location (IY+d)
static inline void INC_IY_(Z80* ctx) { ctx->INC_IY(); }
inline void INC_IY()
{
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] INC (IY+d<$%04X>) = $%02X", reg.PC - 3, addr, n);
#endif
setFlagByIncrement(n);
writeByte(addr, n + 1);
consumeClock(3);
}
// Increment register high 8 bits of IY
static inline void INC_IYH_(Z80* ctx) { ctx->INC_IYH(); }
inline void INC_IYH()
{
unsigned char iyh = getIYH();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] INC IYH<$%02X>", reg.PC - 2, iyh);
#endif
setFlagByIncrement(iyh++);
setIYH(iyh);
}
// Increment register low 8 bits of IY
static inline void INC_IYL_(Z80* ctx) { ctx->INC_IYL(); }
inline void INC_IYL()
{
unsigned char iyl = getIYL();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] INC IYL<$%02X>", reg.PC - 2, iyl);
#endif
setFlagByIncrement(iyl++);
setIYL(iyl);
}
// Subtract Register
static inline void SUB_B(Z80* ctx) { ctx->SUB_R(0b000); }
static inline void SUB_C(Z80* ctx) { ctx->SUB_R(0b001); }
static inline void SUB_D(Z80* ctx) { ctx->SUB_R(0b010); }
static inline void SUB_E(Z80* ctx) { ctx->SUB_R(0b011); }
static inline void SUB_H(Z80* ctx) { ctx->SUB_R(0b100); }
static inline void SUB_L(Z80* ctx) { ctx->SUB_R(0b101); }
static inline void SUB_A(Z80* ctx) { ctx->SUB_R(0b111); }
static inline void SUB_B_2(Z80* ctx) { ctx->SUB_R(0b000, 2); }
static inline void SUB_C_2(Z80* ctx) { ctx->SUB_R(0b001, 2); }
static inline void SUB_D_2(Z80* ctx) { ctx->SUB_R(0b010, 2); }
static inline void SUB_E_2(Z80* ctx) { ctx->SUB_R(0b011, 2); }
static inline void SUB_A_2(Z80* ctx) { ctx->SUB_R(0b111, 2); }
inline void SUB_R(unsigned char r, int pc = 1)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SUB %s, %s", reg.PC - pc, registerDump(0b111), registerDump(r));
#endif
unsigned char* rp = getRegisterPointer(r);
subtract8(*rp, 0);
}
// Subtract IXH to Acc.
static inline void SUB_IXH_(Z80* ctx) { ctx->SUB_IXH(); }
inline void SUB_IXH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SUB %s, IXH<$%02X>", reg.PC - 2, registerDump(0b111), getIXH());
#endif
subtract8(getIXH(), 0);
}
// Subtract IXL to Acc.
static inline void SUB_IXL_(Z80* ctx) { ctx->SUB_IXL(); }
inline void SUB_IXL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SUB %s, IXL<$%02X>", reg.PC - 2, registerDump(0b111), getIXL());
#endif
subtract8(getIXL(), 0);
}
// Subtract IYH to Acc.
static inline void SUB_IYH_(Z80* ctx) { ctx->SUB_IYH(); }
inline void SUB_IYH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SUB %s, IYH<$%02X>", reg.PC - 2, registerDump(0b111), getIYH());
#endif
subtract8(getIYH(), 0);
}
// Subtract IYL to Acc.
static inline void SUB_IYL_(Z80* ctx) { ctx->SUB_IYL(); }
inline void SUB_IYL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SUB %s, IYL<$%02X>", reg.PC - 2, registerDump(0b111), getIYL());
#endif
subtract8(getIYL(), 0);
}
// Subtract immediate
static inline void SUB_N(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] SUB %s, $%02X", ctx->reg.PC - 2, ctx->registerDump(0b111), n);
#endif
ctx->subtract8(n, 0);
}
// Subtract memory
static inline void SUB_HL(Z80* ctx)
{
unsigned short addr = ctx->getHL();
unsigned char n = ctx->readByte(addr, 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] SUB %s, (%s) = $%02X", ctx->reg.PC - 1, ctx->registerDump(0b111), ctx->registerPairDump(0b10), n);
#endif
ctx->subtract8(n, 0);
}
// Subtract memory
static inline void SUB_IX_(Z80* ctx) { ctx->SUB_IX(); }
inline void SUB_IX()
{
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SUB %s, (IX+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), addr, n);
#endif
subtract8(n, 0);
consumeClock(3);
}
// Subtract memory
static inline void SUB_IY_(Z80* ctx) { ctx->SUB_IY(); }
inline void SUB_IY()
{
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SUB %s, (IY+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), addr, n);
#endif
subtract8(n, 0);
consumeClock(3);
}
// Subtract Resister with carry
static inline void SBC_B(Z80* ctx) { ctx->SBC_R(0b000); }
static inline void SBC_C(Z80* ctx) { ctx->SBC_R(0b001); }
static inline void SBC_D(Z80* ctx) { ctx->SBC_R(0b010); }
static inline void SBC_E(Z80* ctx) { ctx->SBC_R(0b011); }
static inline void SBC_H(Z80* ctx) { ctx->SBC_R(0b100); }
static inline void SBC_L(Z80* ctx) { ctx->SBC_R(0b101); }
static inline void SBC_A(Z80* ctx) { ctx->SBC_R(0b111); }
static inline void SBC_B_2(Z80* ctx) { ctx->SBC_R(0b000, 2); }
static inline void SBC_C_2(Z80* ctx) { ctx->SBC_R(0b001, 2); }
static inline void SBC_D_2(Z80* ctx) { ctx->SBC_R(0b010, 2); }
static inline void SBC_E_2(Z80* ctx) { ctx->SBC_R(0b011, 2); }
static inline void SBC_A_2(Z80* ctx) { ctx->SBC_R(0b111, 2); }
inline void SBC_R(unsigned char r, int pc = 1)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SBC %s, %s <C:%s>", reg.PC - pc, registerDump(0b111), registerDump(r), isFlagC() ? "ON" : "OFF");
#endif
subtract8(getRegister(r), isFlagC() ? 1 : 0);
}
// Subtract IXH to Acc. with carry
static inline void SBC_IXH_(Z80* ctx) { ctx->SBC_IXH(); }
inline void SBC_IXH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SBC %s, IXH<$%02X> <C:%s>", reg.PC - 2, registerDump(0b111), getIXH(), isFlagC() ? "ON" : "OFF");
#endif
subtract8(getIXH(), isFlagC() ? 1 : 0);
}
// Subtract IXL to Acc. with carry
static inline void SBC_IXL_(Z80* ctx) { ctx->SBC_IXL(); }
inline void SBC_IXL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SBC %s, IXL<$%02X> <C:%s>", reg.PC - 2, registerDump(0b111), getIXL(), isFlagC() ? "ON" : "OFF");
#endif
subtract8(getIXL(), isFlagC() ? 1 : 0);
}
// Subtract IYH to Acc. with carry
static inline void SBC_IYH_(Z80* ctx) { ctx->SBC_IYH(); }
inline void SBC_IYH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SBC %s, IYH<$%02X> <C:%s>", reg.PC - 2, registerDump(0b111), getIYH(), isFlagC() ? "ON" : "OFF");
#endif
subtract8(getIYH(), isFlagC() ? 1 : 0);
}
// Subtract IYL to Acc. with carry
static inline void SBC_IYL_(Z80* ctx) { ctx->SBC_IYL(); }
inline void SBC_IYL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SBC %s, IYL<$%02X> <C:%s>", reg.PC - 2, registerDump(0b111), getIYL(), isFlagC() ? "ON" : "OFF");
#endif
subtract8(getIYL(), isFlagC() ? 1 : 0);
}
// Subtract immediate with carry
static inline void SBC_N(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] SBC %s, $%02X <C:%s>", ctx->reg.PC - 2, ctx->registerDump(0b111), n, ctx->isFlagC() ? "ON" : "OFF");
#endif
ctx->subtract8(n, ctx->isFlagC() ? 1 : 0);
}
// Subtract memory with carry
static inline void SBC_HL(Z80* ctx)
{
unsigned char n = ctx->readByte(ctx->getHL(), 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] SBC %s, (%s) = $%02X <C:%s>", ctx->reg.PC - 1, ctx->registerDump(0b111), ctx->registerPairDump(0b10), n, ctx->isFlagC() ? "ON" : "OFF");
#endif
ctx->subtract8(n, ctx->isFlagC() ? 1 : 0);
}
// Subtract memory with carry
static inline void SBC_IX_(Z80* ctx) { ctx->SBC_IX(); }
inline void SBC_IX()
{
signed char d = (signed char)fetch(4);
unsigned char n = readByte((unsigned short)(reg.IX + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SBC %s, (IX+d<$%04X>) = $%02X <C:%s>", reg.PC - 3, registerDump(0b111), (unsigned short)(reg.IX + d), n, isFlagC() ? "ON" : "OFF");
#endif
subtract8(n, isFlagC() ? 1 : 0);
consumeClock(3);
}
// Subtract memory with carry
static inline void SBC_IY_(Z80* ctx) { ctx->SBC_IY(); }
inline void SBC_IY()
{
signed char d = (signed char)fetch(4);
unsigned char n = readByte((unsigned short)(reg.IY + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SBC %s, (IY+d<$%04X>) = $%02X <C:%s>", reg.PC - 3, registerDump(0b111), (unsigned short)(reg.IY + d), n, isFlagC() ? "ON" : "OFF");
#endif
subtract8(n, isFlagC() ? 1 : 0);
consumeClock(3);
}
// Decrement Register
static inline void DEC_B(Z80* ctx) { ctx->DEC_R(0b000); }
static inline void DEC_C(Z80* ctx) { ctx->DEC_R(0b001); }
static inline void DEC_D(Z80* ctx) { ctx->DEC_R(0b010); }
static inline void DEC_E(Z80* ctx) { ctx->DEC_R(0b011); }
static inline void DEC_H(Z80* ctx) { ctx->DEC_R(0b100); }
static inline void DEC_L(Z80* ctx) { ctx->DEC_R(0b101); }
static inline void DEC_A(Z80* ctx) { ctx->DEC_R(0b111); }
static inline void DEC_B_2(Z80* ctx) { ctx->DEC_R(0b000, 2); }
static inline void DEC_C_2(Z80* ctx) { ctx->DEC_R(0b001, 2); }
static inline void DEC_D_2(Z80* ctx) { ctx->DEC_R(0b010, 2); }
static inline void DEC_E_2(Z80* ctx) { ctx->DEC_R(0b011, 2); }
static inline void DEC_A_2(Z80* ctx) { ctx->DEC_R(0b111, 2); }
inline void DEC_R(unsigned char r, int pc = 1)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DEC %s", reg.PC - pc, registerDump(r));
#endif
setFlagByDecrement(*rp);
(*rp)--;
}
// Decrement location (HL)
static inline void DEC_HL(Z80* ctx)
{
unsigned short addr = ctx->getHL();
unsigned char n = ctx->readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] DEC (%s) = $%02X", ctx->reg.PC - 1, ctx->registerPairDump(0b10), n);
#endif
ctx->setFlagByDecrement(n);
ctx->writeByte(addr, n - 1, 3);
}
// Decrement location (IX+d)
static inline void DEC_IX_(Z80* ctx) { ctx->DEC_IX(); }
inline void DEC_IX()
{
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DEC (IX+d<$%04X>) = $%02X", reg.PC - 3, addr, n);
#endif
setFlagByDecrement(n);
writeByte(addr, n - 1);
consumeClock(3);
}
// Decrement high 8 bits of IX
static inline void DEC_IXH_(Z80* ctx) { ctx->DEC_IXH(); }
inline void DEC_IXH()
{
unsigned char ixh = getIXH();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DEC IXH<$%02X>", reg.PC - 2, ixh);
#endif
setFlagByDecrement(ixh--);
setIXH(ixh);
}
// Decrement low 8 bits of IX
static inline void DEC_IXL_(Z80* ctx) { ctx->DEC_IXL(); }
inline void DEC_IXL()
{
unsigned char ixl = getIXL();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DEC IXL<$%02X>", reg.PC - 2, ixl);
#endif
setFlagByDecrement(ixl--);
setIXL(ixl);
}
// Decrement location (IY+d)
static inline void DEC_IY_(Z80* ctx) { ctx->DEC_IY(); }
inline void DEC_IY()
{
signed char d = (signed char)fetch(4);
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DEC (IY+d<$%04X>) = $%02X", reg.PC - 3, addr, n);
#endif
setFlagByDecrement(n);
writeByte(addr, n - 1);
consumeClock(3);
}
// Decrement high 8 bits of IY
static inline void DEC_IYH_(Z80* ctx) { ctx->DEC_IYH(); }
inline void DEC_IYH()
{
unsigned char iyh = getIYH();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DEC IYH<$%02X>", reg.PC - 2, iyh);
#endif
setFlagByDecrement(iyh--);
setIYH(iyh);
}
// Decrement low 8 bits of IY
static inline void DEC_IYL_(Z80* ctx) { ctx->DEC_IYL(); }
inline void DEC_IYL()
{
unsigned char iyl = getIYL();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DEC IYL<$%02X>", reg.PC - 2, iyl);
#endif
setFlagByDecrement(iyl--);
setIYL(iyl);
}
inline void setFlagByAdd16(unsigned short before, unsigned short addition)
{
int result = before + addition;
int carrybits = before ^ addition ^ result;
resetFlagN();
setFlagXY((result & 0xFF00) >> 8);
setFlagC((carrybits & 0x10000) != 0);
setFlagH((carrybits & 0x1000) != 0);
}
inline void setFlagByAdc16(unsigned short before, unsigned short addition)
{
int result = before + addition;
int carrybits = before ^ addition ^ result;
unsigned short finalResult = (unsigned short)(result);
// same as ADD
resetFlagN();
setFlagXY((finalResult & 0xFF00) >> 8);
setFlagC((carrybits & 0x10000) != 0);
setFlagH((carrybits & 0x1000) != 0);
// only ADC
setFlagS(finalResult & 0x8000);
setFlagZ(0 == finalResult);
setFlagPV((((carrybits << 1) ^ carrybits) & 0x10000) != 0);
}
// Add register pair to H and L
static inline void ADD_HL_BC(Z80* ctx) { ctx->ADD_HL_RP(0b00); }
static inline void ADD_HL_DE(Z80* ctx) { ctx->ADD_HL_RP(0b01); }
static inline void ADD_HL_HL(Z80* ctx) { ctx->ADD_HL_RP(0b10); }
static inline void ADD_HL_SP(Z80* ctx) { ctx->ADD_HL_RP(0b11); }
inline void ADD_HL_RP(unsigned char rp)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADD %s, %s", reg.PC - 1, registerPairDump(0b10), registerPairDump(rp));
#endif
unsigned short hl = getHL();
unsigned short nn = getRP(rp);
reg.WZ = nn + 1;
setFlagByAdd16(hl, nn);
setHL(hl + nn);
consumeClock(7);
}
// Add with carry register pair to HL
static inline void ADC_HL_BC(Z80* ctx) { ctx->ADC_HL_RP(0b00); }
static inline void ADC_HL_DE(Z80* ctx) { ctx->ADC_HL_RP(0b01); }
static inline void ADC_HL_HL(Z80* ctx) { ctx->ADC_HL_RP(0b10); }
static inline void ADC_HL_SP(Z80* ctx) { ctx->ADC_HL_RP(0b11); }
inline void ADC_HL_RP(unsigned char rp)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADC %s, %s <C:%s>", reg.PC - 2, registerPairDump(0b10), registerPairDump(rp), isFlagC() ? "ON" : "OFF");
#endif
unsigned short hl = getHL();
unsigned short nn = getRP(rp);
unsigned char c = isFlagC() ? 1 : 0;
reg.WZ = hl + 1;
setFlagByAdc16(hl, c + nn);
setHL(hl + c + nn);
consumeClock(7);
}
// Add register pair to IX
static inline void ADD_IX_BC(Z80* ctx) { ctx->ADD_IX_RP(0b00); }
static inline void ADD_IX_DE(Z80* ctx) { ctx->ADD_IX_RP(0b01); }
static inline void ADD_IX_IX(Z80* ctx) { ctx->ADD_IX_RP(0b10); }
static inline void ADD_IX_SP(Z80* ctx) { ctx->ADD_IX_RP(0b11); }
inline void ADD_IX_RP(unsigned char rp)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADD IX<$%04X>, %s", reg.PC - 2, reg.IX, registerPairDumpIX(rp));
#endif
unsigned short nn = getRPIX(rp);
setFlagByAdd16(reg.IX, nn);
reg.IX += nn;
consumeClock(7);
}
// Add register pair to IY
static inline void ADD_IY_BC(Z80* ctx) { ctx->ADD_IY_RP(0b00); }
static inline void ADD_IY_DE(Z80* ctx) { ctx->ADD_IY_RP(0b01); }
static inline void ADD_IY_IY(Z80* ctx) { ctx->ADD_IY_RP(0b10); }
static inline void ADD_IY_SP(Z80* ctx) { ctx->ADD_IY_RP(0b11); }
inline void ADD_IY_RP(unsigned char rp)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] ADD IY<$%04X>, %s", reg.PC - 2, reg.IY, registerPairDumpIY(rp));
#endif
unsigned short nn = getRPIY(rp);
setFlagByAdd16(reg.IY, nn);
reg.IY += nn;
consumeClock(7);
}
// Increment register pair
static inline void INC_RP_BC(Z80* ctx) { ctx->INC_RP(0b00); }
static inline void INC_RP_DE(Z80* ctx) { ctx->INC_RP(0b01); }
static inline void INC_RP_HL(Z80* ctx) { ctx->INC_RP(0b10); }
static inline void INC_RP_SP(Z80* ctx) { ctx->INC_RP(0b11); }
inline void INC_RP(unsigned char rp)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] INC %s", reg.PC - 1, registerPairDump(rp));
#endif
setRP(rp, getRP(rp) + 1);
consumeClock(2);
}
// Increment IX
static inline void INC_IX_reg_(Z80* ctx) { ctx->INC_IX_reg(); }
inline void INC_IX_reg()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] INC IX<$%04X>", reg.PC - 2, reg.IX);
#endif
reg.IX++;
consumeClock(2);
}
// Increment IY
static inline void INC_IY_reg_(Z80* ctx) { ctx->INC_IY_reg(); }
inline void INC_IY_reg()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] INC IY<$%04X>", reg.PC - 2, reg.IY);
#endif
reg.IY++;
consumeClock(2);
}
// Decrement register pair
static inline void DEC_RP_BC(Z80* ctx) { ctx->DEC_RP(0b00); }
static inline void DEC_RP_DE(Z80* ctx) { ctx->DEC_RP(0b01); }
static inline void DEC_RP_HL(Z80* ctx) { ctx->DEC_RP(0b10); }
static inline void DEC_RP_SP(Z80* ctx) { ctx->DEC_RP(0b11); }
inline void DEC_RP(unsigned char rp)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DEC %s", reg.PC - 1, registerPairDump(rp));
#endif
setRP(rp, getRP(rp) - 1);
consumeClock(2);
}
// Decrement IX
static inline void DEC_IX_reg_(Z80* ctx) { ctx->DEC_IX_reg(); }
inline void DEC_IX_reg()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DEC IX<$%04X>", reg.PC - 2, reg.IX);
#endif
reg.IX--;
consumeClock(2);
}
// Decrement IY
static inline void DEC_IY_reg_(Z80* ctx) { ctx->DEC_IY_reg(); }
inline void DEC_IY_reg()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DEC IY<$%04X>", reg.PC - 2, reg.IY);
#endif
reg.IY--;
consumeClock(2);
}
inline void setFlagBySbc16(unsigned short before, unsigned short subtract)
{
int result = before - subtract;
int carrybits = before ^ subtract ^ result;
unsigned short finalResult = (unsigned short)result;
setFlagN();
setFlagXY((finalResult & 0xFF00) >> 8);
setFlagC((carrybits & 0x10000) != 0);
setFlagH((carrybits & 0x1000) != 0);
setFlagS(finalResult & 0x8000);
setFlagZ(0 == finalResult);
setFlagPV((((carrybits << 1) ^ carrybits) & 0x10000) != 0);
}
// Subtract register pair from HL with carry
static inline void SBC_HL_BC(Z80* ctx) { ctx->SBC_HL_RP(0b00); }
static inline void SBC_HL_DE(Z80* ctx) { ctx->SBC_HL_RP(0b01); }
static inline void SBC_HL_HL(Z80* ctx) { ctx->SBC_HL_RP(0b10); }
static inline void SBC_HL_SP(Z80* ctx) { ctx->SBC_HL_RP(0b11); }
inline void SBC_HL_RP(unsigned char rp)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SBC %s, %s <C:%s>", reg.PC - 2, registerPairDump(0b10), registerPairDump(rp), isFlagC() ? "ON" : "OFF");
#endif
unsigned short hl = getHL();
unsigned short nn = getRP(rp);
unsigned char c = isFlagC() ? 1 : 0;
reg.WZ = hl + 1;
setFlagBySbc16(hl, c + nn);
setHL(hl - c - nn);
consumeClock(7);
}
inline void setFlagByLogical()
{
setFlagS(reg.pair.A & 0x80);
setFlagZ(reg.pair.A == 0);
setFlagXY(reg.pair.A);
setFlagPV(isEvenNumberBits(reg.pair.A));
resetFlagN();
resetFlagC();
}
inline void and8(unsigned char n)
{
reg.pair.A &= n;
setFlagByLogical();
setFlagH();
}
inline void or8(unsigned char n)
{
reg.pair.A |= n;
setFlagByLogical();
resetFlagH();
}
inline void xor8(unsigned char n)
{
reg.pair.A ^= n;
setFlagByLogical();
resetFlagH();
}
// AND Register
static inline void AND_B(Z80* ctx) { ctx->AND_R(0b000); }
static inline void AND_C(Z80* ctx) { ctx->AND_R(0b001); }
static inline void AND_D(Z80* ctx) { ctx->AND_R(0b010); }
static inline void AND_E(Z80* ctx) { ctx->AND_R(0b011); }
static inline void AND_H(Z80* ctx) { ctx->AND_R(0b100); }
static inline void AND_L(Z80* ctx) { ctx->AND_R(0b101); }
static inline void AND_A(Z80* ctx) { ctx->AND_R(0b111); }
static inline void AND_B_2(Z80* ctx) { ctx->AND_R(0b000, 2); }
static inline void AND_C_2(Z80* ctx) { ctx->AND_R(0b001, 2); }
static inline void AND_D_2(Z80* ctx) { ctx->AND_R(0b010, 2); }
static inline void AND_E_2(Z80* ctx) { ctx->AND_R(0b011, 2); }
static inline void AND_A_2(Z80* ctx) { ctx->AND_R(0b111, 2); }
inline void AND_R(unsigned char r, int pc = 1)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] AND %s, %s", reg.PC - pc, registerDump(0b111), registerDump(r));
#endif
and8(getRegister(r));
}
// AND with register IXH
static inline void AND_IXH_(Z80* ctx) { ctx->AND_IXH(); }
inline void AND_IXH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] AND %s, IXH<$%02X>", reg.PC - 2, registerDump(0b111), getIXH());
#endif
and8(getIXH());
}
// AND with register IXL
static inline void AND_IXL_(Z80* ctx) { ctx->AND_IXL(); }
inline void AND_IXL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] AND %s, IXL<$%02X>", reg.PC - 2, registerDump(0b111), getIXL());
#endif
and8(getIXL());
}
// AND with register IYH
static inline void AND_IYH_(Z80* ctx) { ctx->AND_IYH(); }
inline void AND_IYH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] AND %s, IYH<$%02X>", reg.PC - 2, registerDump(0b111), getIYH());
#endif
and8(getIYH());
}
// AND with register IYL
static inline void AND_IYL_(Z80* ctx) { ctx->AND_IYL(); }
inline void AND_IYL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] AND %s, IYL<$%02X>", reg.PC - 2, registerDump(0b111), getIYL());
#endif
and8(getIYL());
}
// AND immediate
static inline void AND_N(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] AND %s, $%02X", ctx->reg.PC - 2, ctx->registerDump(0b111), n);
#endif
ctx->and8(n);
}
// AND Memory
static inline void AND_HL(Z80* ctx)
{
unsigned short addr = ctx->getHL();
unsigned char n = ctx->readByte(addr, 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] AND %s, (%s) = $%02X", ctx->reg.PC - 1, ctx->registerDump(0b111), ctx->registerPairDump(0b10), n);
#endif
ctx->and8(n);
}
// AND Memory
static inline void AND_IX_(Z80* ctx) { ctx->AND_IX(); }
inline void AND_IX()
{
signed char d = (signed char)fetch(4);
unsigned char n = readByte((unsigned short)(reg.IX + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] AND %s, (IX+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), (unsigned short)(reg.IX + d), reg.pair.A & n);
#endif
and8(n);
consumeClock(3);
}
// AND Memory
static inline void AND_IY_(Z80* ctx) { ctx->AND_IY(); }
inline void AND_IY()
{
signed char d = (signed char)fetch(4);
unsigned char n = readByte((unsigned short)(reg.IY + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] AND %s, (IY+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), (unsigned short)(reg.IY + d), reg.pair.A & n);
#endif
and8(n);
consumeClock(3);
}
// OR Register
static inline void OR_B(Z80* ctx) { ctx->OR_R(0b000); }
static inline void OR_C(Z80* ctx) { ctx->OR_R(0b001); }
static inline void OR_D(Z80* ctx) { ctx->OR_R(0b010); }
static inline void OR_E(Z80* ctx) { ctx->OR_R(0b011); }
static inline void OR_H(Z80* ctx) { ctx->OR_R(0b100); }
static inline void OR_L(Z80* ctx) { ctx->OR_R(0b101); }
static inline void OR_A(Z80* ctx) { ctx->OR_R(0b111); }
static inline void OR_B_2(Z80* ctx) { ctx->OR_R(0b000, 2); }
static inline void OR_C_2(Z80* ctx) { ctx->OR_R(0b001, 2); }
static inline void OR_D_2(Z80* ctx) { ctx->OR_R(0b010, 2); }
static inline void OR_E_2(Z80* ctx) { ctx->OR_R(0b011, 2); }
static inline void OR_A_2(Z80* ctx) { ctx->OR_R(0b111, 2); }
inline void OR_R(unsigned char r, int pc = 1)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] OR %s, %s", reg.PC - pc, registerDump(0b111), registerDump(r));
#endif
or8(getRegister(r));
}
// OR with register IXH
static inline void OR_IXH_(Z80* ctx) { ctx->OR_IXH(); }
inline void OR_IXH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] OR %s, IXH<$%02X>", reg.PC - 2, registerDump(0b111), getIXH());
#endif
or8(getIXH());
}
// OR with register IXL
static inline void OR_IXL_(Z80* ctx) { ctx->OR_IXL(); }
inline void OR_IXL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] OR %s, IXL<$%02X>", reg.PC - 2, registerDump(0b111), getIXL());
#endif
or8(getIXL());
}
// OR with register IYH
static inline void OR_IYH_(Z80* ctx) { ctx->OR_IYH(); }
inline void OR_IYH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] OR %s, IYH<$%02X>", reg.PC - 2, registerDump(0b111), getIYH());
#endif
or8(getIYH());
}
// OR with register IYL
static inline void OR_IYL_(Z80* ctx) { ctx->OR_IYL(); }
inline void OR_IYL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] OR %s, IYL<$%02X>", reg.PC - 2, registerDump(0b111), getIYL());
#endif
or8(getIYL());
}
// OR immediate
static inline void OR_N(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] OR %s, $%02X", ctx->reg.PC - 2, ctx->registerDump(0b111), n);
#endif
ctx->or8(n);
}
// OR Memory
static inline void OR_HL(Z80* ctx)
{
unsigned char n = ctx->readByte(ctx->getHL(), 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] OR %s, (%s) = $%02X", ctx->reg.PC - 1, ctx->registerDump(0b111), ctx->registerPairDump(0b10), ctx->reg.pair.A | n);
#endif
ctx->or8(n);
}
// OR Memory
static inline void OR_IX_(Z80* ctx) { ctx->OR_IX(); }
inline void OR_IX()
{
signed char d = (signed char)fetch(4);
unsigned char n = readByte((unsigned short)(reg.IX + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] OR %s, (IX+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), (unsigned short)(reg.IX + d), reg.pair.A | n);
#endif
or8(n);
consumeClock(3);
}
// OR Memory
static inline void OR_IY_(Z80* ctx) { ctx->OR_IY(); }
inline void OR_IY()
{
signed char d = (signed char)fetch(4);
unsigned char n = readByte((unsigned short)(reg.IY + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] OR %s, (IY+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), (unsigned short)(reg.IY + d), reg.pair.A | n);
#endif
or8(n);
consumeClock(3);
}
// XOR Reigster
static inline void XOR_B(Z80* ctx) { ctx->XOR_R(0b000); }
static inline void XOR_C(Z80* ctx) { ctx->XOR_R(0b001); }
static inline void XOR_D(Z80* ctx) { ctx->XOR_R(0b010); }
static inline void XOR_E(Z80* ctx) { ctx->XOR_R(0b011); }
static inline void XOR_H(Z80* ctx) { ctx->XOR_R(0b100); }
static inline void XOR_L(Z80* ctx) { ctx->XOR_R(0b101); }
static inline void XOR_A(Z80* ctx) { ctx->XOR_R(0b111); }
static inline void XOR_B_2(Z80* ctx) { ctx->XOR_R(0b000, 2); }
static inline void XOR_C_2(Z80* ctx) { ctx->XOR_R(0b001, 2); }
static inline void XOR_D_2(Z80* ctx) { ctx->XOR_R(0b010, 2); }
static inline void XOR_E_2(Z80* ctx) { ctx->XOR_R(0b011, 2); }
static inline void XOR_A_2(Z80* ctx) { ctx->XOR_R(0b111, 2); }
inline void XOR_R(unsigned char r, int pc = 1)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] XOR %s, %s", reg.PC - pc, registerDump(0b111), registerDump(r));
#endif
xor8(getRegister(r));
}
// XOR with register IXH
static inline void XOR_IXH_(Z80* ctx) { ctx->XOR_IXH(); }
inline void XOR_IXH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] XOR %s, IXH<$%02X>", reg.PC - 2, registerDump(0b111), getIXH());
#endif
xor8(getIXH());
}
// XOR with register IXL
static inline void XOR_IXL_(Z80* ctx) { ctx->XOR_IXL(); }
inline void XOR_IXL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] XOR %s, IXL<$%02X>", reg.PC - 2, registerDump(0b111), getIXL());
#endif
xor8(getIXL());
}
// XOR with register IYH
static inline void XOR_IYH_(Z80* ctx) { ctx->XOR_IYH(); }
inline void XOR_IYH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] XOR %s, IYH<$%02X>", reg.PC - 2, registerDump(0b111), getIYH());
#endif
xor8(getIYH());
}
// XOR with register IYL
static inline void XOR_IYL_(Z80* ctx) { ctx->XOR_IYL(); }
inline void XOR_IYL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] XOR %s, IYL<$%02X>", reg.PC - 2, registerDump(0b111), getIYL());
#endif
xor8(getIYL());
}
// XOR immediate
static inline void XOR_N(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] XOR %s, $%02X", ctx->reg.PC - 2, ctx->registerDump(0b111), n);
#endif
ctx->xor8(n);
}
// XOR Memory
static inline void XOR_HL(Z80* ctx)
{
unsigned char n = ctx->readByte(ctx->getHL(), 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] XOR %s, (%s) = $%02X", ctx->reg.PC - 1, ctx->registerDump(0b111), ctx->registerPairDump(0b10), ctx->reg.pair.A ^ n);
#endif
ctx->xor8(n);
}
// XOR Memory
static inline void XOR_IX_(Z80* ctx) { ctx->XOR_IX(); }
inline void XOR_IX()
{
signed char d = (signed char)fetch(4);
unsigned char n = readByte((unsigned short)(reg.IX + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] XOR %s, (IX+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), (unsigned short)(reg.IX + d), reg.pair.A ^ n);
#endif
xor8(n);
consumeClock(3);
}
// XOR Memory
static inline void XOR_IY_(Z80* ctx) { ctx->XOR_IY(); }
inline void XOR_IY()
{
signed char d = (signed char)fetch(4);
unsigned char n = readByte((unsigned short)(reg.IY + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] XOR %s, (IY+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), (unsigned short)(reg.IY + d), reg.pair.A ^ n);
#endif
xor8(n);
consumeClock(3);
}
// Complement acc. (1's Comp.)
static inline void CPL(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] CPL %s", ctx->reg.PC - 1, ctx->registerDump(0b111));
#endif
ctx->reg.pair.A = ~ctx->reg.pair.A;
ctx->setFlagH();
ctx->setFlagN();
ctx->setFlagXY(ctx->reg.pair.A);
}
// Negate Acc. (2's Comp.)
static inline void NEG_(Z80* ctx) { ctx->NEG(); }
inline void NEG()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] NEG %s", reg.PC - 2, registerDump(0b111));
#endif
unsigned char a = reg.pair.A;
reg.pair.A = 0;
subtract8(a, 0);
}
// Complement Carry Flag
static inline void CCF(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] CCF <C:%s -> %s>", ctx->reg.PC - 1, ctx->isFlagC() ? "ON" : "OFF", !ctx->isFlagC() ? "ON" : "OFF");
#endif
ctx->setFlagH(ctx->isFlagC());
ctx->resetFlagN();
ctx->setFlagC(!ctx->isFlagC());
ctx->setFlagXY(ctx->reg.pair.A);
}
// Set Carry Flag
static inline void SCF(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] SCF <C:%s -> ON>", ctx->reg.PC - 1, ctx->isFlagC() ? "ON" : "OFF");
#endif
ctx->resetFlagH();
ctx->resetFlagN();
ctx->setFlagC();
ctx->setFlagXY(ctx->reg.pair.A);
}
// Test BIT b of register r
static inline void BIT_B_0(Z80* ctx) { ctx->BIT_R(0b000, 0); }
static inline void BIT_B_1(Z80* ctx) { ctx->BIT_R(0b000, 1); }
static inline void BIT_B_2(Z80* ctx) { ctx->BIT_R(0b000, 2); }
static inline void BIT_B_3(Z80* ctx) { ctx->BIT_R(0b000, 3); }
static inline void BIT_B_4(Z80* ctx) { ctx->BIT_R(0b000, 4); }
static inline void BIT_B_5(Z80* ctx) { ctx->BIT_R(0b000, 5); }
static inline void BIT_B_6(Z80* ctx) { ctx->BIT_R(0b000, 6); }
static inline void BIT_B_7(Z80* ctx) { ctx->BIT_R(0b000, 7); }
static inline void BIT_C_0(Z80* ctx) { ctx->BIT_R(0b001, 0); }
static inline void BIT_C_1(Z80* ctx) { ctx->BIT_R(0b001, 1); }
static inline void BIT_C_2(Z80* ctx) { ctx->BIT_R(0b001, 2); }
static inline void BIT_C_3(Z80* ctx) { ctx->BIT_R(0b001, 3); }
static inline void BIT_C_4(Z80* ctx) { ctx->BIT_R(0b001, 4); }
static inline void BIT_C_5(Z80* ctx) { ctx->BIT_R(0b001, 5); }
static inline void BIT_C_6(Z80* ctx) { ctx->BIT_R(0b001, 6); }
static inline void BIT_C_7(Z80* ctx) { ctx->BIT_R(0b001, 7); }
static inline void BIT_D_0(Z80* ctx) { ctx->BIT_R(0b010, 0); }
static inline void BIT_D_1(Z80* ctx) { ctx->BIT_R(0b010, 1); }
static inline void BIT_D_2(Z80* ctx) { ctx->BIT_R(0b010, 2); }
static inline void BIT_D_3(Z80* ctx) { ctx->BIT_R(0b010, 3); }
static inline void BIT_D_4(Z80* ctx) { ctx->BIT_R(0b010, 4); }
static inline void BIT_D_5(Z80* ctx) { ctx->BIT_R(0b010, 5); }
static inline void BIT_D_6(Z80* ctx) { ctx->BIT_R(0b010, 6); }
static inline void BIT_D_7(Z80* ctx) { ctx->BIT_R(0b010, 7); }
static inline void BIT_E_0(Z80* ctx) { ctx->BIT_R(0b011, 0); }
static inline void BIT_E_1(Z80* ctx) { ctx->BIT_R(0b011, 1); }
static inline void BIT_E_2(Z80* ctx) { ctx->BIT_R(0b011, 2); }
static inline void BIT_E_3(Z80* ctx) { ctx->BIT_R(0b011, 3); }
static inline void BIT_E_4(Z80* ctx) { ctx->BIT_R(0b011, 4); }
static inline void BIT_E_5(Z80* ctx) { ctx->BIT_R(0b011, 5); }
static inline void BIT_E_6(Z80* ctx) { ctx->BIT_R(0b011, 6); }
static inline void BIT_E_7(Z80* ctx) { ctx->BIT_R(0b011, 7); }
static inline void BIT_H_0(Z80* ctx) { ctx->BIT_R(0b100, 0); }
static inline void BIT_H_1(Z80* ctx) { ctx->BIT_R(0b100, 1); }
static inline void BIT_H_2(Z80* ctx) { ctx->BIT_R(0b100, 2); }
static inline void BIT_H_3(Z80* ctx) { ctx->BIT_R(0b100, 3); }
static inline void BIT_H_4(Z80* ctx) { ctx->BIT_R(0b100, 4); }
static inline void BIT_H_5(Z80* ctx) { ctx->BIT_R(0b100, 5); }
static inline void BIT_H_6(Z80* ctx) { ctx->BIT_R(0b100, 6); }
static inline void BIT_H_7(Z80* ctx) { ctx->BIT_R(0b100, 7); }
static inline void BIT_L_0(Z80* ctx) { ctx->BIT_R(0b101, 0); }
static inline void BIT_L_1(Z80* ctx) { ctx->BIT_R(0b101, 1); }
static inline void BIT_L_2(Z80* ctx) { ctx->BIT_R(0b101, 2); }
static inline void BIT_L_3(Z80* ctx) { ctx->BIT_R(0b101, 3); }
static inline void BIT_L_4(Z80* ctx) { ctx->BIT_R(0b101, 4); }
static inline void BIT_L_5(Z80* ctx) { ctx->BIT_R(0b101, 5); }
static inline void BIT_L_6(Z80* ctx) { ctx->BIT_R(0b101, 6); }
static inline void BIT_L_7(Z80* ctx) { ctx->BIT_R(0b101, 7); }
static inline void BIT_A_0(Z80* ctx) { ctx->BIT_R(0b111, 0); }
static inline void BIT_A_1(Z80* ctx) { ctx->BIT_R(0b111, 1); }
static inline void BIT_A_2(Z80* ctx) { ctx->BIT_R(0b111, 2); }
static inline void BIT_A_3(Z80* ctx) { ctx->BIT_R(0b111, 3); }
static inline void BIT_A_4(Z80* ctx) { ctx->BIT_R(0b111, 4); }
static inline void BIT_A_5(Z80* ctx) { ctx->BIT_R(0b111, 5); }
static inline void BIT_A_6(Z80* ctx) { ctx->BIT_R(0b111, 6); }
static inline void BIT_A_7(Z80* ctx) { ctx->BIT_R(0b111, 7); }
inline void BIT_R(unsigned char r, unsigned char bit)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] BIT %s of bit-%d", reg.PC - 2, registerDump(r), bit);
#endif
unsigned char n = 0;
n = *rp & bits[bit];
setFlagZ(n ? false : true);
setFlagPV(isFlagZ());
setFlagS(!isFlagZ() && 7 == bit);
setFlagH();
resetFlagN();
setFlagXY(*rp);
}
// Test BIT b of location (HL)
static inline void BIT_HL_0(Z80* ctx) { ctx->BIT_HL(0); }
static inline void BIT_HL_1(Z80* ctx) { ctx->BIT_HL(1); }
static inline void BIT_HL_2(Z80* ctx) { ctx->BIT_HL(2); }
static inline void BIT_HL_3(Z80* ctx) { ctx->BIT_HL(3); }
static inline void BIT_HL_4(Z80* ctx) { ctx->BIT_HL(4); }
static inline void BIT_HL_5(Z80* ctx) { ctx->BIT_HL(5); }
static inline void BIT_HL_6(Z80* ctx) { ctx->BIT_HL(6); }
static inline void BIT_HL_7(Z80* ctx) { ctx->BIT_HL(7); }
inline void BIT_HL(unsigned char bit)
{
unsigned char n = readByte(getHL());
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] BIT (%s) = $%02X of bit-%d", reg.PC - 2, registerPairDump(0b10), n, bit);
#endif
n &= bits[bit];
setFlagZ(!n);
setFlagPV(isFlagZ());
setFlagS(!isFlagZ() && 7 == bit);
setFlagH();
resetFlagN();
setFlagXY((reg.WZ & 0xFF00) >> 8);
}
// Test BIT b of location (IX+d)
static inline void BIT_IX_0(Z80* ctx, signed char d) { ctx->BIT_IX(d, 0); }
static inline void BIT_IX_1(Z80* ctx, signed char d) { ctx->BIT_IX(d, 1); }
static inline void BIT_IX_2(Z80* ctx, signed char d) { ctx->BIT_IX(d, 2); }
static inline void BIT_IX_3(Z80* ctx, signed char d) { ctx->BIT_IX(d, 3); }
static inline void BIT_IX_4(Z80* ctx, signed char d) { ctx->BIT_IX(d, 4); }
static inline void BIT_IX_5(Z80* ctx, signed char d) { ctx->BIT_IX(d, 5); }
static inline void BIT_IX_6(Z80* ctx, signed char d) { ctx->BIT_IX(d, 6); }
static inline void BIT_IX_7(Z80* ctx, signed char d) { ctx->BIT_IX(d, 7); }
inline void BIT_IX(signed char d, unsigned char bit)
{
unsigned char n = readByte((unsigned short)(reg.IX + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] BIT (IX+d<$%04X>) = $%02X of bit-%d", reg.PC - 4, (unsigned short)(reg.IX + d), n, bit);
#endif
n &= bits[bit];
setFlagZ(!n);
setFlagPV(isFlagZ());
setFlagS(!isFlagZ() && 7 == bit);
setFlagH();
resetFlagN();
setFlagXY((reg.WZ & 0xFF00) >> 8);
}
// Test BIT b of location (IY+d)
static inline void BIT_IY_0(Z80* ctx, signed char d) { ctx->BIT_IY(d, 0); }
static inline void BIT_IY_1(Z80* ctx, signed char d) { ctx->BIT_IY(d, 1); }
static inline void BIT_IY_2(Z80* ctx, signed char d) { ctx->BIT_IY(d, 2); }
static inline void BIT_IY_3(Z80* ctx, signed char d) { ctx->BIT_IY(d, 3); }
static inline void BIT_IY_4(Z80* ctx, signed char d) { ctx->BIT_IY(d, 4); }
static inline void BIT_IY_5(Z80* ctx, signed char d) { ctx->BIT_IY(d, 5); }
static inline void BIT_IY_6(Z80* ctx, signed char d) { ctx->BIT_IY(d, 6); }
static inline void BIT_IY_7(Z80* ctx, signed char d) { ctx->BIT_IY(d, 7); }
inline void BIT_IY(signed char d, unsigned char bit)
{
unsigned char n = readByte((unsigned short)(reg.IY + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] BIT (IY+d<$%04X>) = $%02X of bit-%d", reg.PC - 4, (unsigned short)(reg.IY + d), n, bit);
#endif
n &= bits[bit];
setFlagZ(!n);
setFlagPV(isFlagZ());
setFlagS(!isFlagZ() && 7 == bit);
setFlagH();
resetFlagN();
setFlagXY((reg.WZ & 0xFF00) >> 8);
}
// SET bit b of register r
static inline void SET_B_0(Z80* ctx) { ctx->SET_R(0b000, 0); }
static inline void SET_B_1(Z80* ctx) { ctx->SET_R(0b000, 1); }
static inline void SET_B_2(Z80* ctx) { ctx->SET_R(0b000, 2); }
static inline void SET_B_3(Z80* ctx) { ctx->SET_R(0b000, 3); }
static inline void SET_B_4(Z80* ctx) { ctx->SET_R(0b000, 4); }
static inline void SET_B_5(Z80* ctx) { ctx->SET_R(0b000, 5); }
static inline void SET_B_6(Z80* ctx) { ctx->SET_R(0b000, 6); }
static inline void SET_B_7(Z80* ctx) { ctx->SET_R(0b000, 7); }
static inline void SET_C_0(Z80* ctx) { ctx->SET_R(0b001, 0); }
static inline void SET_C_1(Z80* ctx) { ctx->SET_R(0b001, 1); }
static inline void SET_C_2(Z80* ctx) { ctx->SET_R(0b001, 2); }
static inline void SET_C_3(Z80* ctx) { ctx->SET_R(0b001, 3); }
static inline void SET_C_4(Z80* ctx) { ctx->SET_R(0b001, 4); }
static inline void SET_C_5(Z80* ctx) { ctx->SET_R(0b001, 5); }
static inline void SET_C_6(Z80* ctx) { ctx->SET_R(0b001, 6); }
static inline void SET_C_7(Z80* ctx) { ctx->SET_R(0b001, 7); }
static inline void SET_D_0(Z80* ctx) { ctx->SET_R(0b010, 0); }
static inline void SET_D_1(Z80* ctx) { ctx->SET_R(0b010, 1); }
static inline void SET_D_2(Z80* ctx) { ctx->SET_R(0b010, 2); }
static inline void SET_D_3(Z80* ctx) { ctx->SET_R(0b010, 3); }
static inline void SET_D_4(Z80* ctx) { ctx->SET_R(0b010, 4); }
static inline void SET_D_5(Z80* ctx) { ctx->SET_R(0b010, 5); }
static inline void SET_D_6(Z80* ctx) { ctx->SET_R(0b010, 6); }
static inline void SET_D_7(Z80* ctx) { ctx->SET_R(0b010, 7); }
static inline void SET_E_0(Z80* ctx) { ctx->SET_R(0b011, 0); }
static inline void SET_E_1(Z80* ctx) { ctx->SET_R(0b011, 1); }
static inline void SET_E_2(Z80* ctx) { ctx->SET_R(0b011, 2); }
static inline void SET_E_3(Z80* ctx) { ctx->SET_R(0b011, 3); }
static inline void SET_E_4(Z80* ctx) { ctx->SET_R(0b011, 4); }
static inline void SET_E_5(Z80* ctx) { ctx->SET_R(0b011, 5); }
static inline void SET_E_6(Z80* ctx) { ctx->SET_R(0b011, 6); }
static inline void SET_E_7(Z80* ctx) { ctx->SET_R(0b011, 7); }
static inline void SET_H_0(Z80* ctx) { ctx->SET_R(0b100, 0); }
static inline void SET_H_1(Z80* ctx) { ctx->SET_R(0b100, 1); }
static inline void SET_H_2(Z80* ctx) { ctx->SET_R(0b100, 2); }
static inline void SET_H_3(Z80* ctx) { ctx->SET_R(0b100, 3); }
static inline void SET_H_4(Z80* ctx) { ctx->SET_R(0b100, 4); }
static inline void SET_H_5(Z80* ctx) { ctx->SET_R(0b100, 5); }
static inline void SET_H_6(Z80* ctx) { ctx->SET_R(0b100, 6); }
static inline void SET_H_7(Z80* ctx) { ctx->SET_R(0b100, 7); }
static inline void SET_L_0(Z80* ctx) { ctx->SET_R(0b101, 0); }
static inline void SET_L_1(Z80* ctx) { ctx->SET_R(0b101, 1); }
static inline void SET_L_2(Z80* ctx) { ctx->SET_R(0b101, 2); }
static inline void SET_L_3(Z80* ctx) { ctx->SET_R(0b101, 3); }
static inline void SET_L_4(Z80* ctx) { ctx->SET_R(0b101, 4); }
static inline void SET_L_5(Z80* ctx) { ctx->SET_R(0b101, 5); }
static inline void SET_L_6(Z80* ctx) { ctx->SET_R(0b101, 6); }
static inline void SET_L_7(Z80* ctx) { ctx->SET_R(0b101, 7); }
static inline void SET_A_0(Z80* ctx) { ctx->SET_R(0b111, 0); }
static inline void SET_A_1(Z80* ctx) { ctx->SET_R(0b111, 1); }
static inline void SET_A_2(Z80* ctx) { ctx->SET_R(0b111, 2); }
static inline void SET_A_3(Z80* ctx) { ctx->SET_R(0b111, 3); }
static inline void SET_A_4(Z80* ctx) { ctx->SET_R(0b111, 4); }
static inline void SET_A_5(Z80* ctx) { ctx->SET_R(0b111, 5); }
static inline void SET_A_6(Z80* ctx) { ctx->SET_R(0b111, 6); }
static inline void SET_A_7(Z80* ctx) { ctx->SET_R(0b111, 7); }
inline void SET_R(unsigned char r, unsigned char bit)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SET %s of bit-%d", reg.PC - 2, registerDump(r), bit);
#endif
*rp |= bits[bit];
}
// SET bit b of location (HL)
static inline void SET_HL_0(Z80* ctx) { ctx->SET_HL(0); }
static inline void SET_HL_1(Z80* ctx) { ctx->SET_HL(1); }
static inline void SET_HL_2(Z80* ctx) { ctx->SET_HL(2); }
static inline void SET_HL_3(Z80* ctx) { ctx->SET_HL(3); }
static inline void SET_HL_4(Z80* ctx) { ctx->SET_HL(4); }
static inline void SET_HL_5(Z80* ctx) { ctx->SET_HL(5); }
static inline void SET_HL_6(Z80* ctx) { ctx->SET_HL(6); }
static inline void SET_HL_7(Z80* ctx) { ctx->SET_HL(7); }
inline void SET_HL(unsigned char bit)
{
unsigned short addr = getHL();
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SET (%s) = $%02X of bit-%d", reg.PC - 2, registerPairDump(0b10), n, bit);
#endif
n |= bits[bit];
writeByte(addr, n, 3);
}
// SET bit b of location (IX+d)
static inline void SET_IX_0(Z80* ctx, signed char d) { ctx->SET_IX(d, 0); }
static inline void SET_IX_1(Z80* ctx, signed char d) { ctx->SET_IX(d, 1); }
static inline void SET_IX_2(Z80* ctx, signed char d) { ctx->SET_IX(d, 2); }
static inline void SET_IX_3(Z80* ctx, signed char d) { ctx->SET_IX(d, 3); }
static inline void SET_IX_4(Z80* ctx, signed char d) { ctx->SET_IX(d, 4); }
static inline void SET_IX_5(Z80* ctx, signed char d) { ctx->SET_IX(d, 5); }
static inline void SET_IX_6(Z80* ctx, signed char d) { ctx->SET_IX(d, 6); }
static inline void SET_IX_7(Z80* ctx, signed char d) { ctx->SET_IX(d, 7); }
inline void SET_IX(signed char d, unsigned char bit, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SET (IX+d<$%04X>) = $%02X of bit-%d%s", reg.PC - 4, addr, n, bit, extraLog ? extraLog : "");
#endif
n |= bits[bit];
if (rp) *rp = n;
writeByte(addr, n, 3);
}
// SET bit b of location (IX+d) with load Reg.
static inline void SET_IX_0_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 0, 0b000); }
static inline void SET_IX_1_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 1, 0b000); }
static inline void SET_IX_2_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 2, 0b000); }
static inline void SET_IX_3_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 3, 0b000); }
static inline void SET_IX_4_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 4, 0b000); }
static inline void SET_IX_5_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 5, 0b000); }
static inline void SET_IX_6_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 6, 0b000); }
static inline void SET_IX_7_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 7, 0b000); }
static inline void SET_IX_0_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 0, 0b001); }
static inline void SET_IX_1_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 1, 0b001); }
static inline void SET_IX_2_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 2, 0b001); }
static inline void SET_IX_3_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 3, 0b001); }
static inline void SET_IX_4_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 4, 0b001); }
static inline void SET_IX_5_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 5, 0b001); }
static inline void SET_IX_6_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 6, 0b001); }
static inline void SET_IX_7_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 7, 0b001); }
static inline void SET_IX_0_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 0, 0b010); }
static inline void SET_IX_1_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 1, 0b010); }
static inline void SET_IX_2_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 2, 0b010); }
static inline void SET_IX_3_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 3, 0b010); }
static inline void SET_IX_4_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 4, 0b010); }
static inline void SET_IX_5_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 5, 0b010); }
static inline void SET_IX_6_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 6, 0b010); }
static inline void SET_IX_7_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 7, 0b010); }
static inline void SET_IX_0_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 0, 0b011); }
static inline void SET_IX_1_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 1, 0b011); }
static inline void SET_IX_2_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 2, 0b011); }
static inline void SET_IX_3_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 3, 0b011); }
static inline void SET_IX_4_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 4, 0b011); }
static inline void SET_IX_5_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 5, 0b011); }
static inline void SET_IX_6_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 6, 0b011); }
static inline void SET_IX_7_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 7, 0b011); }
static inline void SET_IX_0_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 0, 0b100); }
static inline void SET_IX_1_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 1, 0b100); }
static inline void SET_IX_2_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 2, 0b100); }
static inline void SET_IX_3_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 3, 0b100); }
static inline void SET_IX_4_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 4, 0b100); }
static inline void SET_IX_5_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 5, 0b100); }
static inline void SET_IX_6_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 6, 0b100); }
static inline void SET_IX_7_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 7, 0b100); }
static inline void SET_IX_0_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 0, 0b101); }
static inline void SET_IX_1_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 1, 0b101); }
static inline void SET_IX_2_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 2, 0b101); }
static inline void SET_IX_3_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 3, 0b101); }
static inline void SET_IX_4_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 4, 0b101); }
static inline void SET_IX_5_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 5, 0b101); }
static inline void SET_IX_6_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 6, 0b101); }
static inline void SET_IX_7_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 7, 0b101); }
static inline void SET_IX_0_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 0, 0b111); }
static inline void SET_IX_1_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 1, 0b111); }
static inline void SET_IX_2_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 2, 0b111); }
static inline void SET_IX_3_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 3, 0b111); }
static inline void SET_IX_4_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 4, 0b111); }
static inline void SET_IX_5_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 5, 0b111); }
static inline void SET_IX_6_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 6, 0b111); }
static inline void SET_IX_7_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IX_with_LD(d, 7, 0b111); }
inline void SET_IX_with_LD(signed char d, unsigned char bit, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
SET_IX(d, bit, rp, buf);
#else
SET_IX(d, bit, rp);
#endif
}
// SET bit b of location (IY+d)
static inline void SET_IY_0(Z80* ctx, signed char d) { ctx->SET_IY(d, 0); }
static inline void SET_IY_1(Z80* ctx, signed char d) { ctx->SET_IY(d, 1); }
static inline void SET_IY_2(Z80* ctx, signed char d) { ctx->SET_IY(d, 2); }
static inline void SET_IY_3(Z80* ctx, signed char d) { ctx->SET_IY(d, 3); }
static inline void SET_IY_4(Z80* ctx, signed char d) { ctx->SET_IY(d, 4); }
static inline void SET_IY_5(Z80* ctx, signed char d) { ctx->SET_IY(d, 5); }
static inline void SET_IY_6(Z80* ctx, signed char d) { ctx->SET_IY(d, 6); }
static inline void SET_IY_7(Z80* ctx, signed char d) { ctx->SET_IY(d, 7); }
inline void SET_IY(signed char d, unsigned char bit, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] SET (IY+d<$%04X>) = $%02X of bit-%d%s", reg.PC - 4, addr, n, bit, extraLog ? extraLog : "");
#endif
n |= bits[bit];
if (rp) *rp = n;
writeByte(addr, n, 3);
}
// SET bit b of location (IY+d) with load Reg.
static inline void SET_IY_0_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 0, 0b000); }
static inline void SET_IY_1_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 1, 0b000); }
static inline void SET_IY_2_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 2, 0b000); }
static inline void SET_IY_3_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 3, 0b000); }
static inline void SET_IY_4_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 4, 0b000); }
static inline void SET_IY_5_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 5, 0b000); }
static inline void SET_IY_6_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 6, 0b000); }
static inline void SET_IY_7_with_LD_B(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 7, 0b000); }
static inline void SET_IY_0_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 0, 0b001); }
static inline void SET_IY_1_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 1, 0b001); }
static inline void SET_IY_2_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 2, 0b001); }
static inline void SET_IY_3_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 3, 0b001); }
static inline void SET_IY_4_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 4, 0b001); }
static inline void SET_IY_5_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 5, 0b001); }
static inline void SET_IY_6_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 6, 0b001); }
static inline void SET_IY_7_with_LD_C(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 7, 0b001); }
static inline void SET_IY_0_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 0, 0b010); }
static inline void SET_IY_1_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 1, 0b010); }
static inline void SET_IY_2_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 2, 0b010); }
static inline void SET_IY_3_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 3, 0b010); }
static inline void SET_IY_4_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 4, 0b010); }
static inline void SET_IY_5_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 5, 0b010); }
static inline void SET_IY_6_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 6, 0b010); }
static inline void SET_IY_7_with_LD_D(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 7, 0b010); }
static inline void SET_IY_0_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 0, 0b011); }
static inline void SET_IY_1_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 1, 0b011); }
static inline void SET_IY_2_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 2, 0b011); }
static inline void SET_IY_3_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 3, 0b011); }
static inline void SET_IY_4_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 4, 0b011); }
static inline void SET_IY_5_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 5, 0b011); }
static inline void SET_IY_6_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 6, 0b011); }
static inline void SET_IY_7_with_LD_E(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 7, 0b011); }
static inline void SET_IY_0_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 0, 0b100); }
static inline void SET_IY_1_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 1, 0b100); }
static inline void SET_IY_2_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 2, 0b100); }
static inline void SET_IY_3_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 3, 0b100); }
static inline void SET_IY_4_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 4, 0b100); }
static inline void SET_IY_5_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 5, 0b100); }
static inline void SET_IY_6_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 6, 0b100); }
static inline void SET_IY_7_with_LD_H(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 7, 0b100); }
static inline void SET_IY_0_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 0, 0b101); }
static inline void SET_IY_1_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 1, 0b101); }
static inline void SET_IY_2_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 2, 0b101); }
static inline void SET_IY_3_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 3, 0b101); }
static inline void SET_IY_4_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 4, 0b101); }
static inline void SET_IY_5_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 5, 0b101); }
static inline void SET_IY_6_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 6, 0b101); }
static inline void SET_IY_7_with_LD_L(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 7, 0b101); }
static inline void SET_IY_0_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 0, 0b111); }
static inline void SET_IY_1_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 1, 0b111); }
static inline void SET_IY_2_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 2, 0b111); }
static inline void SET_IY_3_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 3, 0b111); }
static inline void SET_IY_4_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 4, 0b111); }
static inline void SET_IY_5_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 5, 0b111); }
static inline void SET_IY_6_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 6, 0b111); }
static inline void SET_IY_7_with_LD_A(Z80* ctx, signed char d) { ctx->SET_IY_with_LD(d, 7, 0b111); }
inline void SET_IY_with_LD(signed char d, unsigned char bit, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
SET_IY(d, bit, rp, buf);
#else
SET_IY(d, bit, rp);
#endif
}
// RESET bit b of register r
static inline void RES_B_0(Z80* ctx) { ctx->RES_R(0b000, 0); }
static inline void RES_B_1(Z80* ctx) { ctx->RES_R(0b000, 1); }
static inline void RES_B_2(Z80* ctx) { ctx->RES_R(0b000, 2); }
static inline void RES_B_3(Z80* ctx) { ctx->RES_R(0b000, 3); }
static inline void RES_B_4(Z80* ctx) { ctx->RES_R(0b000, 4); }
static inline void RES_B_5(Z80* ctx) { ctx->RES_R(0b000, 5); }
static inline void RES_B_6(Z80* ctx) { ctx->RES_R(0b000, 6); }
static inline void RES_B_7(Z80* ctx) { ctx->RES_R(0b000, 7); }
static inline void RES_C_0(Z80* ctx) { ctx->RES_R(0b001, 0); }
static inline void RES_C_1(Z80* ctx) { ctx->RES_R(0b001, 1); }
static inline void RES_C_2(Z80* ctx) { ctx->RES_R(0b001, 2); }
static inline void RES_C_3(Z80* ctx) { ctx->RES_R(0b001, 3); }
static inline void RES_C_4(Z80* ctx) { ctx->RES_R(0b001, 4); }
static inline void RES_C_5(Z80* ctx) { ctx->RES_R(0b001, 5); }
static inline void RES_C_6(Z80* ctx) { ctx->RES_R(0b001, 6); }
static inline void RES_C_7(Z80* ctx) { ctx->RES_R(0b001, 7); }
static inline void RES_D_0(Z80* ctx) { ctx->RES_R(0b010, 0); }
static inline void RES_D_1(Z80* ctx) { ctx->RES_R(0b010, 1); }
static inline void RES_D_2(Z80* ctx) { ctx->RES_R(0b010, 2); }
static inline void RES_D_3(Z80* ctx) { ctx->RES_R(0b010, 3); }
static inline void RES_D_4(Z80* ctx) { ctx->RES_R(0b010, 4); }
static inline void RES_D_5(Z80* ctx) { ctx->RES_R(0b010, 5); }
static inline void RES_D_6(Z80* ctx) { ctx->RES_R(0b010, 6); }
static inline void RES_D_7(Z80* ctx) { ctx->RES_R(0b010, 7); }
static inline void RES_E_0(Z80* ctx) { ctx->RES_R(0b011, 0); }
static inline void RES_E_1(Z80* ctx) { ctx->RES_R(0b011, 1); }
static inline void RES_E_2(Z80* ctx) { ctx->RES_R(0b011, 2); }
static inline void RES_E_3(Z80* ctx) { ctx->RES_R(0b011, 3); }
static inline void RES_E_4(Z80* ctx) { ctx->RES_R(0b011, 4); }
static inline void RES_E_5(Z80* ctx) { ctx->RES_R(0b011, 5); }
static inline void RES_E_6(Z80* ctx) { ctx->RES_R(0b011, 6); }
static inline void RES_E_7(Z80* ctx) { ctx->RES_R(0b011, 7); }
static inline void RES_H_0(Z80* ctx) { ctx->RES_R(0b100, 0); }
static inline void RES_H_1(Z80* ctx) { ctx->RES_R(0b100, 1); }
static inline void RES_H_2(Z80* ctx) { ctx->RES_R(0b100, 2); }
static inline void RES_H_3(Z80* ctx) { ctx->RES_R(0b100, 3); }
static inline void RES_H_4(Z80* ctx) { ctx->RES_R(0b100, 4); }
static inline void RES_H_5(Z80* ctx) { ctx->RES_R(0b100, 5); }
static inline void RES_H_6(Z80* ctx) { ctx->RES_R(0b100, 6); }
static inline void RES_H_7(Z80* ctx) { ctx->RES_R(0b100, 7); }
static inline void RES_L_0(Z80* ctx) { ctx->RES_R(0b101, 0); }
static inline void RES_L_1(Z80* ctx) { ctx->RES_R(0b101, 1); }
static inline void RES_L_2(Z80* ctx) { ctx->RES_R(0b101, 2); }
static inline void RES_L_3(Z80* ctx) { ctx->RES_R(0b101, 3); }
static inline void RES_L_4(Z80* ctx) { ctx->RES_R(0b101, 4); }
static inline void RES_L_5(Z80* ctx) { ctx->RES_R(0b101, 5); }
static inline void RES_L_6(Z80* ctx) { ctx->RES_R(0b101, 6); }
static inline void RES_L_7(Z80* ctx) { ctx->RES_R(0b101, 7); }
static inline void RES_A_0(Z80* ctx) { ctx->RES_R(0b111, 0); }
static inline void RES_A_1(Z80* ctx) { ctx->RES_R(0b111, 1); }
static inline void RES_A_2(Z80* ctx) { ctx->RES_R(0b111, 2); }
static inline void RES_A_3(Z80* ctx) { ctx->RES_R(0b111, 3); }
static inline void RES_A_4(Z80* ctx) { ctx->RES_R(0b111, 4); }
static inline void RES_A_5(Z80* ctx) { ctx->RES_R(0b111, 5); }
static inline void RES_A_6(Z80* ctx) { ctx->RES_R(0b111, 6); }
static inline void RES_A_7(Z80* ctx) { ctx->RES_R(0b111, 7); }
inline void RES_R(unsigned char r, unsigned char bit)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RES %s of bit-%d", reg.PC - 2, registerDump(r), bit);
#endif
switch (bit) {
case 0: *rp &= 0b11111110; break;
case 1: *rp &= 0b11111101; break;
case 2: *rp &= 0b11111011; break;
case 3: *rp &= 0b11110111; break;
case 4: *rp &= 0b11101111; break;
case 5: *rp &= 0b11011111; break;
case 6: *rp &= 0b10111111; break;
case 7: *rp &= 0b01111111; break;
}
}
// RESET bit b of location (HL)
static inline void RES_HL_0(Z80* ctx) { ctx->RES_HL(0); }
static inline void RES_HL_1(Z80* ctx) { ctx->RES_HL(1); }
static inline void RES_HL_2(Z80* ctx) { ctx->RES_HL(2); }
static inline void RES_HL_3(Z80* ctx) { ctx->RES_HL(3); }
static inline void RES_HL_4(Z80* ctx) { ctx->RES_HL(4); }
static inline void RES_HL_5(Z80* ctx) { ctx->RES_HL(5); }
static inline void RES_HL_6(Z80* ctx) { ctx->RES_HL(6); }
static inline void RES_HL_7(Z80* ctx) { ctx->RES_HL(7); }
inline void RES_HL(unsigned char bit)
{
unsigned short addr = getHL();
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RES (%s) = $%02X of bit-%d", reg.PC - 2, registerPairDump(0b10), n, bit);
#endif
switch (bit) {
case 0: n &= 0b11111110; break;
case 1: n &= 0b11111101; break;
case 2: n &= 0b11111011; break;
case 3: n &= 0b11110111; break;
case 4: n &= 0b11101111; break;
case 5: n &= 0b11011111; break;
case 6: n &= 0b10111111; break;
case 7: n &= 0b01111111; break;
}
writeByte(addr, n, 3);
}
// RESET bit b of location (IX+d)
static inline void RES_IX_0(Z80* ctx, signed char d) { ctx->RES_IX(d, 0); }
static inline void RES_IX_1(Z80* ctx, signed char d) { ctx->RES_IX(d, 1); }
static inline void RES_IX_2(Z80* ctx, signed char d) { ctx->RES_IX(d, 2); }
static inline void RES_IX_3(Z80* ctx, signed char d) { ctx->RES_IX(d, 3); }
static inline void RES_IX_4(Z80* ctx, signed char d) { ctx->RES_IX(d, 4); }
static inline void RES_IX_5(Z80* ctx, signed char d) { ctx->RES_IX(d, 5); }
static inline void RES_IX_6(Z80* ctx, signed char d) { ctx->RES_IX(d, 6); }
static inline void RES_IX_7(Z80* ctx, signed char d) { ctx->RES_IX(d, 7); }
inline void RES_IX(signed char d, unsigned char bit, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IX + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RES (IX+d<$%04X>) = $%02X of bit-%d%s", reg.PC - 4, addr, n, bit, extraLog ? extraLog : "");
#endif
switch (bit) {
case 0: n &= 0b11111110; break;
case 1: n &= 0b11111101; break;
case 2: n &= 0b11111011; break;
case 3: n &= 0b11110111; break;
case 4: n &= 0b11101111; break;
case 5: n &= 0b11011111; break;
case 6: n &= 0b10111111; break;
case 7: n &= 0b01111111; break;
}
if (rp) *rp = n;
writeByte(addr, n, 3);
}
// RESET bit b of location (IX+d) with load Reg.
static inline void RES_IX_0_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 0, 0b000); }
static inline void RES_IX_1_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 1, 0b000); }
static inline void RES_IX_2_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 2, 0b000); }
static inline void RES_IX_3_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 3, 0b000); }
static inline void RES_IX_4_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 4, 0b000); }
static inline void RES_IX_5_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 5, 0b000); }
static inline void RES_IX_6_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 6, 0b000); }
static inline void RES_IX_7_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 7, 0b000); }
static inline void RES_IX_0_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 0, 0b001); }
static inline void RES_IX_1_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 1, 0b001); }
static inline void RES_IX_2_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 2, 0b001); }
static inline void RES_IX_3_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 3, 0b001); }
static inline void RES_IX_4_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 4, 0b001); }
static inline void RES_IX_5_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 5, 0b001); }
static inline void RES_IX_6_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 6, 0b001); }
static inline void RES_IX_7_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 7, 0b001); }
static inline void RES_IX_0_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 0, 0b010); }
static inline void RES_IX_1_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 1, 0b010); }
static inline void RES_IX_2_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 2, 0b010); }
static inline void RES_IX_3_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 3, 0b010); }
static inline void RES_IX_4_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 4, 0b010); }
static inline void RES_IX_5_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 5, 0b010); }
static inline void RES_IX_6_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 6, 0b010); }
static inline void RES_IX_7_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 7, 0b010); }
static inline void RES_IX_0_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 0, 0b011); }
static inline void RES_IX_1_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 1, 0b011); }
static inline void RES_IX_2_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 2, 0b011); }
static inline void RES_IX_3_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 3, 0b011); }
static inline void RES_IX_4_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 4, 0b011); }
static inline void RES_IX_5_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 5, 0b011); }
static inline void RES_IX_6_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 6, 0b011); }
static inline void RES_IX_7_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 7, 0b011); }
static inline void RES_IX_0_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 0, 0b100); }
static inline void RES_IX_1_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 1, 0b100); }
static inline void RES_IX_2_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 2, 0b100); }
static inline void RES_IX_3_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 3, 0b100); }
static inline void RES_IX_4_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 4, 0b100); }
static inline void RES_IX_5_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 5, 0b100); }
static inline void RES_IX_6_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 6, 0b100); }
static inline void RES_IX_7_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 7, 0b100); }
static inline void RES_IX_0_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 0, 0b101); }
static inline void RES_IX_1_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 1, 0b101); }
static inline void RES_IX_2_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 2, 0b101); }
static inline void RES_IX_3_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 3, 0b101); }
static inline void RES_IX_4_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 4, 0b101); }
static inline void RES_IX_5_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 5, 0b101); }
static inline void RES_IX_6_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 6, 0b101); }
static inline void RES_IX_7_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 7, 0b101); }
static inline void RES_IX_0_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 0, 0b111); }
static inline void RES_IX_1_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 1, 0b111); }
static inline void RES_IX_2_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 2, 0b111); }
static inline void RES_IX_3_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 3, 0b111); }
static inline void RES_IX_4_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 4, 0b111); }
static inline void RES_IX_5_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 5, 0b111); }
static inline void RES_IX_6_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 6, 0b111); }
static inline void RES_IX_7_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IX_with_LD(d, 7, 0b111); }
inline void RES_IX_with_LD(signed char d, unsigned char bit, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
RES_IX(d, bit, rp, buf);
#else
RES_IX(d, bit, rp);
#endif
}
// RESET bit b of location (IY+d) with load Reg.
static inline void RES_IY_0_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 0, 0b000); }
static inline void RES_IY_1_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 1, 0b000); }
static inline void RES_IY_2_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 2, 0b000); }
static inline void RES_IY_3_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 3, 0b000); }
static inline void RES_IY_4_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 4, 0b000); }
static inline void RES_IY_5_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 5, 0b000); }
static inline void RES_IY_6_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 6, 0b000); }
static inline void RES_IY_7_with_LD_B(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 7, 0b000); }
static inline void RES_IY_0_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 0, 0b001); }
static inline void RES_IY_1_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 1, 0b001); }
static inline void RES_IY_2_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 2, 0b001); }
static inline void RES_IY_3_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 3, 0b001); }
static inline void RES_IY_4_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 4, 0b001); }
static inline void RES_IY_5_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 5, 0b001); }
static inline void RES_IY_6_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 6, 0b001); }
static inline void RES_IY_7_with_LD_C(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 7, 0b001); }
static inline void RES_IY_0_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 0, 0b010); }
static inline void RES_IY_1_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 1, 0b010); }
static inline void RES_IY_2_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 2, 0b010); }
static inline void RES_IY_3_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 3, 0b010); }
static inline void RES_IY_4_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 4, 0b010); }
static inline void RES_IY_5_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 5, 0b010); }
static inline void RES_IY_6_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 6, 0b010); }
static inline void RES_IY_7_with_LD_D(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 7, 0b010); }
static inline void RES_IY_0_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 0, 0b011); }
static inline void RES_IY_1_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 1, 0b011); }
static inline void RES_IY_2_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 2, 0b011); }
static inline void RES_IY_3_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 3, 0b011); }
static inline void RES_IY_4_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 4, 0b011); }
static inline void RES_IY_5_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 5, 0b011); }
static inline void RES_IY_6_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 6, 0b011); }
static inline void RES_IY_7_with_LD_E(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 7, 0b011); }
static inline void RES_IY_0_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 0, 0b100); }
static inline void RES_IY_1_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 1, 0b100); }
static inline void RES_IY_2_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 2, 0b100); }
static inline void RES_IY_3_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 3, 0b100); }
static inline void RES_IY_4_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 4, 0b100); }
static inline void RES_IY_5_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 5, 0b100); }
static inline void RES_IY_6_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 6, 0b100); }
static inline void RES_IY_7_with_LD_H(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 7, 0b100); }
static inline void RES_IY_0_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 0, 0b101); }
static inline void RES_IY_1_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 1, 0b101); }
static inline void RES_IY_2_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 2, 0b101); }
static inline void RES_IY_3_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 3, 0b101); }
static inline void RES_IY_4_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 4, 0b101); }
static inline void RES_IY_5_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 5, 0b101); }
static inline void RES_IY_6_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 6, 0b101); }
static inline void RES_IY_7_with_LD_L(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 7, 0b101); }
static inline void RES_IY_0_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 0, 0b111); }
static inline void RES_IY_1_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 1, 0b111); }
static inline void RES_IY_2_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 2, 0b111); }
static inline void RES_IY_3_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 3, 0b111); }
static inline void RES_IY_4_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 4, 0b111); }
static inline void RES_IY_5_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 5, 0b111); }
static inline void RES_IY_6_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 6, 0b111); }
static inline void RES_IY_7_with_LD_A(Z80* ctx, signed char d) { ctx->RES_IY_with_LD(d, 7, 0b111); }
inline void RES_IY_with_LD(signed char d, unsigned char bit, unsigned char r)
{
unsigned char* rp = getRegisterPointer(r);
#ifndef Z80_DISABLE_DEBUG
char buf[80];
if (isDebug()) {
snprintf(buf, sizeof(buf), " --> %s", registerDump(r));
} else {
buf[0] = '\0';
}
RES_IY(d, bit, rp, buf);
#else
RES_IY(d, bit, rp);
#endif
}
// RESET bit b of location (IY+d)
static inline void RES_IY_0(Z80* ctx, signed char d) { ctx->RES_IY(d, 0); }
static inline void RES_IY_1(Z80* ctx, signed char d) { ctx->RES_IY(d, 1); }
static inline void RES_IY_2(Z80* ctx, signed char d) { ctx->RES_IY(d, 2); }
static inline void RES_IY_3(Z80* ctx, signed char d) { ctx->RES_IY(d, 3); }
static inline void RES_IY_4(Z80* ctx, signed char d) { ctx->RES_IY(d, 4); }
static inline void RES_IY_5(Z80* ctx, signed char d) { ctx->RES_IY(d, 5); }
static inline void RES_IY_6(Z80* ctx, signed char d) { ctx->RES_IY(d, 6); }
static inline void RES_IY_7(Z80* ctx, signed char d) { ctx->RES_IY(d, 7); }
inline void RES_IY(signed char d, unsigned char bit, unsigned char* rp = nullptr, const char* extraLog = nullptr)
{
unsigned short addr = (unsigned short)(reg.IY + d);
unsigned char n = readByte(addr);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RES (IY+d<$%04X>) = $%02X of bit-%d%s", reg.PC - 4, addr, n, bit, extraLog ? extraLog : "");
#endif
switch (bit) {
case 0: n &= 0b11111110; break;
case 1: n &= 0b11111101; break;
case 2: n &= 0b11111011; break;
case 3: n &= 0b11110111; break;
case 4: n &= 0b11101111; break;
case 5: n &= 0b11011111; break;
case 6: n &= 0b10111111; break;
case 7: n &= 0b01111111; break;
}
if (rp) *rp = n;
writeByte(addr, n, 3);
}
// Compare location (HL) and A, increment/decrement HL and decrement BC
inline void repeatCP(bool isIncHL, bool isRepeat)
{
unsigned short hl = getHL();
unsigned short bc = getBC();
unsigned char n = readByte(hl);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) {
if (isIncHL) {
log("[%04X] %s ... %s, %s = $%02X, %s", reg.PC - 2, isRepeat ? "CPIR" : "CPI", registerDump(0b111), registerPairDump(0b10), n, registerPairDump(0b00));
} else {
log("[%04X] %s ... %s, %s = $%02X, %s", reg.PC - 2, isRepeat ? "CPDR" : "CPD", registerDump(0b111), registerPairDump(0b10), n, registerPairDump(0b00));
}
}
#endif
subtract8(n, 0, false, false);
int nn = reg.pair.A;
nn -= n;
nn -= isFlagH() ? 1 : 0;
setFlagY(nn & 0b00000010);
setFlagX(nn & 0b00001000);
setHL((unsigned short)(hl + (isIncHL ? 1 : -1)));
bc--;
setBC(bc);
setFlagPV(0 != bc);
consumeClock(4);
if (isRepeat && !isFlagZ() && 0 != getBC()) {
reg.PC -= 2;
consumeClock(5);
}
reg.WZ += isIncHL ? 1 : -1;
}
static inline void CPI(Z80* ctx) { ctx->repeatCP(true, false); }
static inline void CPIR(Z80* ctx) { ctx->repeatCP(true, true); }
static inline void CPD(Z80* ctx) { ctx->repeatCP(false, false); }
static inline void CPDR(Z80* ctx) { ctx->repeatCP(false, true); }
// Compare Register
static inline void CP_B(Z80* ctx) { ctx->CP_R(0b000); }
static inline void CP_C(Z80* ctx) { ctx->CP_R(0b001); }
static inline void CP_D(Z80* ctx) { ctx->CP_R(0b010); }
static inline void CP_E(Z80* ctx) { ctx->CP_R(0b011); }
static inline void CP_H(Z80* ctx) { ctx->CP_R(0b100); }
static inline void CP_L(Z80* ctx) { ctx->CP_R(0b101); }
static inline void CP_A(Z80* ctx) { ctx->CP_R(0b111); }
static inline void CP_B_2(Z80* ctx) { ctx->CP_R(0b000, 2); }
static inline void CP_C_2(Z80* ctx) { ctx->CP_R(0b001, 2); }
static inline void CP_D_2(Z80* ctx) { ctx->CP_R(0b010, 2); }
static inline void CP_E_2(Z80* ctx) { ctx->CP_R(0b011, 2); }
static inline void CP_A_2(Z80* ctx) { ctx->CP_R(0b111, 2); }
inline void CP_R(unsigned char r, int pc = 1)
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] CP %s, %s", reg.PC - pc, registerDump(0b111), registerDump(r));
#endif
unsigned char* rp = getRegisterPointer(r);
subtract8(*rp, 0, true, false);
}
// Compare Register IXH
static inline void CP_IXH_(Z80* ctx) { ctx->CP_IXH(); }
inline void CP_IXH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] CP %s, IXH<$%02X>", reg.PC - 2, registerDump(0b111), getIXH());
#endif
subtract8(getIXH(), 0, true, false);
}
// Compare Register IXL
static inline void CP_IXL_(Z80* ctx) { ctx->CP_IXL(); }
inline void CP_IXL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] CP %s, IXL<$%02X>", reg.PC - 2, registerDump(0b111), getIXL());
#endif
subtract8(getIXL(), 0, true, false);
}
// Compare Register IYH
static inline void CP_IYH_(Z80* ctx) { ctx->CP_IYH(); }
inline void CP_IYH()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] CP %s, IYH<$%02X>", reg.PC - 2, registerDump(0b111), getIYH());
#endif
subtract8(getIYH(), 0, true, false);
}
// Compare Register IYL
static inline void CP_IYL_(Z80* ctx) { ctx->CP_IYL(); }
inline void CP_IYL()
{
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] CP %s, IYL<$%02X>", reg.PC - 2, registerDump(0b111), getIYL());
#endif
subtract8(getIYL(), 0, true, false);
}
// Compare immediate
static inline void CP_N(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] CP %s, $%02X", ctx->reg.PC - 2, ctx->registerDump(0b111), n);
#endif
ctx->subtract8(n, 0, true, false);
}
// Compare memory
static inline void CP_HL(Z80* ctx)
{
unsigned char n = ctx->readByte(ctx->getHL(), 3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] CP %s, (%s) = $%02X", ctx->reg.PC - 1, ctx->registerDump(0b111), ctx->registerPairDump(0b10), n);
#endif
ctx->subtract8(n, 0, true, false);
}
// Compare memory
static inline void CP_IX_(Z80* ctx) { ctx->CP_IX(); }
inline void CP_IX()
{
signed char d = (signed char)fetch(4);
unsigned char n = readByte((unsigned short)(reg.IX + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] CP %s, (IX+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), (unsigned short)(reg.IX + d), n);
#endif
subtract8(n, 0, true, false);
consumeClock(3);
}
// Compare memory
static inline void CP_IY_(Z80* ctx) { ctx->CP_IY(); }
inline void CP_IY()
{
signed char d = (signed char)fetch(4);
unsigned char n = readByte((unsigned short)(reg.IY + d));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] CP %s, (IY+d<$%04X>) = $%02X", reg.PC - 3, registerDump(0b111), (unsigned short)(reg.IY + d), n);
#endif
subtract8(n, 0, true, false);
consumeClock(3);
}
// Jump
static inline void JP_NN(Z80* ctx)
{
unsigned char l = ctx->fetch(3);
unsigned char h = ctx->fetch(3);
unsigned short addr = ctx->make16BitsFromLE(l, h);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] JP $%04X", ctx->reg.PC - 3, addr);
#endif
ctx->reg.PC = addr;
ctx->reg.WZ = addr;
}
// Conditional Jump
static inline void JP_C0_NN(Z80* ctx) { ctx->JP_C_NN(Condition::NZ); }
static inline void JP_C1_NN(Z80* ctx) { ctx->JP_C_NN(Condition::Z); }
static inline void JP_C2_NN(Z80* ctx) { ctx->JP_C_NN(Condition::NC); }
static inline void JP_C3_NN(Z80* ctx) { ctx->JP_C_NN(Condition::C); }
static inline void JP_C4_NN(Z80* ctx) { ctx->JP_C_NN(Condition::NPV); }
static inline void JP_C5_NN(Z80* ctx) { ctx->JP_C_NN(Condition::PV); }
static inline void JP_C6_NN(Z80* ctx) { ctx->JP_C_NN(Condition::NS); }
static inline void JP_C7_NN(Z80* ctx) { ctx->JP_C_NN(Condition::S); }
inline void JP_C_NN(Condition c)
{
unsigned char l = fetch(3);
unsigned char h = fetch(3);
unsigned short addr = make16BitsFromLE(l, h);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] JP %s, $%04X", reg.PC - 3, conditionDump(c), addr);
#endif
if (checkConditionFlag(c)) reg.PC = addr;
reg.WZ = addr;
}
// Jump Relative to PC+e
static inline void JR_E(Z80* ctx)
{
signed char e = (signed char)ctx->fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] JR %s", ctx->reg.PC - 2, ctx->relativeDump(ctx->reg.PC - 2, e));
#endif
ctx->reg.PC += e;
ctx->consumeClock(5);
}
// Jump Relative to PC+e, if condition
static inline void JR_NZ_E(Z80* ctx) { ctx->JR_CND_E(Condition::NZ); }
static inline void JR_Z_E(Z80* ctx) { ctx->JR_CND_E(Condition::Z); }
static inline void JR_NC_E(Z80* ctx) { ctx->JR_CND_E(Condition::NC); }
static inline void JR_C_E(Z80* ctx) { ctx->JR_CND_E(Condition::C); }
inline void JR_CND_E(Condition cnd)
{
signed char e = (signed char)fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] JR %s, %s <%s>", reg.PC - 2, conditionDump(cnd), relativeDump(reg.PC - 2, e), checkConditionFlag(cnd) ? "YES" : "NO");
#endif
if (checkConditionFlag(cnd)) {
reg.PC += e;
consumeClock(5);
}
}
// Jump to HL
static inline void JP_HL(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] JP %s", ctx->reg.PC - 1, ctx->registerPairDump(0b10));
#endif
ctx->reg.PC = ctx->getHL();
}
// Jump to IX
static inline void JP_IX(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] JP IX<$%04X>", ctx->reg.PC - 2, ctx->reg.IX);
#endif
ctx->reg.PC = ctx->reg.IX;
}
// Jump to IY
static inline void JP_IY(Z80* ctx)
{
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] JP IY<$%04X>", ctx->reg.PC - 2, ctx->reg.IY);
#endif
ctx->reg.PC = ctx->reg.IY;
}
// Decrement B and Jump relative if B=0
static inline void DJNZ_E(Z80* ctx)
{
signed char e = (signed char)ctx->fetch(4);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] DJNZ %s (%s)", ctx->reg.PC - 2, ctx->relativeDump(ctx->reg.PC - 2, e), ctx->registerDump(0b000));
#endif
ctx->reg.pair.B--;
if (ctx->reg.pair.B) {
ctx->reg.PC += e;
ctx->consumeClock(5);
}
}
// Call
static inline void CALL_NN(Z80* ctx)
{
unsigned short addrL = ctx->fetch(4);
unsigned short addrH = ctx->fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] CALL $%04X (%s)", ctx->reg.PC - 3, ctx->make16BitsFromLE(addrL, addrH), ctx->registerPairDump(0b11));
#endif
ctx->push(ctx->getPCH(), 3);
ctx->setPCH(addrH);
ctx->push(ctx->getPCL(), 3);
ctx->setPCL(addrL);
ctx->reg.WZ = ctx->reg.PC;
#ifndef Z80_DISABLE_NESTCHECK
ctx->invokeCallHandlers();
#endif
}
// Return
static inline void RET(Z80* ctx)
{
#ifndef Z80_DISABLE_NESTCHECK
ctx->invokeReturnHandlers();
#endif
#ifndef Z80_DISABLE_DEBUG
unsigned short pc = ctx->reg.PC - 1;
const char* dump = ctx->isDebug() ? ctx->registerPairDump(0b11) : "";
#endif
ctx->setPCL(ctx->pop(3));
ctx->setPCH(ctx->pop(3));
ctx->reg.WZ = ctx->reg.PC;
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] RET to $%04X (%s)", pc, ctx->reg.PC, dump);
#endif
}
// Call with condition
static inline void CALL_C0_NN(Z80* ctx) { ctx->CALL_C_NN(Condition::NZ); }
static inline void CALL_C1_NN(Z80* ctx) { ctx->CALL_C_NN(Condition::Z); }
static inline void CALL_C2_NN(Z80* ctx) { ctx->CALL_C_NN(Condition::NC); }
static inline void CALL_C3_NN(Z80* ctx) { ctx->CALL_C_NN(Condition::C); }
static inline void CALL_C4_NN(Z80* ctx) { ctx->CALL_C_NN(Condition::NPV); }
static inline void CALL_C5_NN(Z80* ctx) { ctx->CALL_C_NN(Condition::PV); }
static inline void CALL_C6_NN(Z80* ctx) { ctx->CALL_C_NN(Condition::NS); }
static inline void CALL_C7_NN(Z80* ctx) { ctx->CALL_C_NN(Condition::S); }
inline void CALL_C_NN(Condition c)
{
bool execute = checkConditionFlag(c);
unsigned char nL = fetch(3);
unsigned char nH = fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] CALL %s, $%04X (%s) <execute:%s>", reg.PC - 3, conditionDump(c), make16BitsFromLE(nL, nH), registerPairDump(0b11), execute ? "YES" : "NO");
#endif
if (execute) {
push(getPCH(), 4);
setPCH(nH);
push(getPCL(), 3);
setPCL(nL);
#ifndef Z80_DISABLE_NESTCHECK
invokeCallHandlers();
#endif
}
reg.WZ = reg.PC;
}
// with condition
static inline void RET_C0(Z80* ctx) { ctx->RET_C(Condition::NZ); }
static inline void RET_C1(Z80* ctx) { ctx->RET_C(Condition::Z); }
static inline void RET_C2(Z80* ctx) { ctx->RET_C(Condition::NC); }
static inline void RET_C3(Z80* ctx) { ctx->RET_C(Condition::C); }
static inline void RET_C4(Z80* ctx) { ctx->RET_C(Condition::NPV); }
static inline void RET_C5(Z80* ctx) { ctx->RET_C(Condition::PV); }
static inline void RET_C6(Z80* ctx) { ctx->RET_C(Condition::NS); }
static inline void RET_C7(Z80* ctx) { ctx->RET_C(Condition::S); }
inline void RET_C(Condition c)
{
if (!checkConditionFlag(c)) {
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RET %s <execute:NO>", reg.PC - 1, conditionDump(c));
#endif
consumeClock(1);
return;
}
#ifndef Z80_DISABLE_NESTCHECK
invokeReturnHandlers();
#endif
#ifndef Z80_DISABLE_DEBUG
unsigned short pc = reg.PC;
unsigned short sp = reg.SP;
#endif
setPCL(pop(4));
setPCH(pop(3));
reg.WZ = reg.PC;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RET %s to $%04X (SP<$%04X>) <execute:YES>", pc - 1, conditionDump(c), reg.PC, sp);
#endif
}
// Return from interrupt
static inline void RETI_(Z80* ctx) { ctx->RETI(); }
inline void RETI()
{
#ifndef Z80_DISABLE_NESTCHECK
invokeReturnHandlers();
#endif
#ifndef Z80_DISABLE_DEBUG
unsigned short pc = reg.PC;
unsigned short sp = reg.SP;
#endif
setPCL(pop(3));
setPCH(pop(3));
reg.WZ = reg.PC;
reg.IFF &= ~IFF_IRQ();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RETI to $%04X (SP<$%04X>)", pc - 2, reg.PC, sp);
#endif
}
// Return from non maskable interrupt
static inline void RETN_(Z80* ctx) { ctx->RETN(); }
inline void RETN()
{
#ifndef Z80_DISABLE_NESTCHECK
invokeReturnHandlers();
#endif
#ifndef Z80_DISABLE_DEBUG
unsigned short pc = reg.PC;
unsigned short sp = reg.SP;
#endif
setPCL(pop(3));
setPCH(pop(3));
reg.WZ = reg.PC;
reg.IFF &= ~IFF_NMI();
if (!((reg.IFF & IFF1()) && (reg.IFF & IFF2()))) {
reg.IFF |= IFF1();
} else {
if (reg.IFF & IFF2()) {
reg.IFF |= IFF1();
} else {
reg.IFF &= ~IFF1();
}
}
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RETN to $%04X (SP<$%04X>)", pc - 2, reg.PC, sp);
#endif
}
// Interrupt
static inline void RST00(Z80* ctx) { ctx->RST(0, true); }
static inline void RST08(Z80* ctx) { ctx->RST(1, true); }
static inline void RST10(Z80* ctx) { ctx->RST(2, true); }
static inline void RST18(Z80* ctx) { ctx->RST(3, true); }
static inline void RST20(Z80* ctx) { ctx->RST(4, true); }
static inline void RST28(Z80* ctx) { ctx->RST(5, true); }
static inline void RST30(Z80* ctx) { ctx->RST(6, true); }
static inline void RST38(Z80* ctx) { ctx->RST(7, true); }
inline void RST(unsigned char t, bool isOperand)
{
unsigned short addr = t * 8;
#ifndef Z80_DISABLE_DEBUG
unsigned short sp = reg.SP;
unsigned short pc = reg.PC;
#endif
push(getPCH(), 4);
setPCH(0);
push(getPCL(), 3);
reg.PC = addr;
reg.WZ = addr;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RST $%04X (SP<$%04X>)", pc - (isOperand ? 1 : 0), addr, sp);
#endif
#ifndef Z80_DISABLE_NESTCHECK
invokeCallHandlers();
#endif
}
// Input a byte form device n to accu.
static inline void IN_A_N(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
unsigned char i = ctx->inPortWithA(n);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] IN %s, ($%02X) = $%02X", ctx->reg.PC - 2, ctx->registerDump(0b111), n, i);
#endif
ctx->reg.pair.A = i;
}
// Input a byte form device (C) to register.
static inline void IN_B_C(Z80* ctx) { ctx->IN_R_C(0b000); }
static inline void IN_C_C(Z80* ctx) { ctx->IN_R_C(0b001); }
static inline void IN_D_C(Z80* ctx) { ctx->IN_R_C(0b010); }
static inline void IN_E_C(Z80* ctx) { ctx->IN_R_C(0b011); }
static inline void IN_H_C(Z80* ctx) { ctx->IN_R_C(0b100); }
static inline void IN_L_C(Z80* ctx) { ctx->IN_R_C(0b101); }
static inline void IN_C(Z80* ctx) { ctx->IN_R_C(0, false); }
static inline void IN_A_C(Z80* ctx) { ctx->IN_R_C(0b111); }
inline void IN_R_C(unsigned char r, bool setRegister = true)
{
unsigned char* rp = setRegister ? getRegisterPointer(r) : nullptr;
unsigned char i = inPortWithB(reg.pair.C);
#ifndef Z80_DISABLE_DEBUG
if (rp) {
if (isDebug()) log("[%04X] IN %s, (%s) = $%02X", reg.PC - 2, registerDump(r), registerDump(0b001), i);
*rp = i;
} else {
if (isDebug()) log("[%04X] IN (%s) = $%02X", reg.PC - 2, registerDump(0b001), i);
}
#else
if (rp) *rp = i;
#endif
setFlagS(i & 0x80);
setFlagZ(i == 0);
resetFlagH();
setFlagPV(isEvenNumberBits(i));
resetFlagN();
setFlagXY(i);
}
inline void decrementB_forRepeatIO()
{
reg.pair.B--;
reg.pair.F = 0;
setFlagC(isFlagC());
setFlagN();
setFlagZ(reg.pair.B == 0);
setFlagXY(reg.pair.B);
setFlagS(reg.pair.B & 0x80);
setFlagH((reg.pair.B & 0x0F) == 0x0F);
setFlagPV(reg.pair.B == 0x7F);
}
// Load location (HL) with input from port (C); or increment/decrement HL and decrement B
inline void repeatIN(bool isIncHL, bool isRepeat)
{
reg.WZ = (unsigned short)(getBC() + (isIncHL ? 1 : -1));
unsigned char i = inPortWithB(reg.pair.C);
decrementB_forRepeatIO();
unsigned short hl = getHL();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) {
if (isIncHL) {
log("[%04X] %s ... (%s) <- p(%s) = $%02X [%s]", reg.PC - 2, isRepeat ? "INIR" : "INI", registerPairDump(0b10), registerDump(0b001), i, registerDump(0b000));
} else {
log("[%04X] %s ... (%s) <- p(%s) = $%02X [%s]", reg.PC - 2, isRepeat ? "INDR" : "IND", registerPairDump(0b10), registerDump(0b001), i, registerDump(0b000));
}
}
#endif
writeByte(hl, i);
hl += isIncHL ? 1 : -1;
setHL(hl);
setFlagZ(reg.pair.B == 0);
setFlagN(i & 0x80); // NOTE: undocumented
setFlagC(0xFF < i + ((reg.pair.C + 1) & 0xFF)); // NOTE: undocumented
setFlagH(isFlagC()); // NOTE: undocumented
setFlagPV((i + (((reg.pair.C + 1) & 0xFF) & 0x07)) ^ reg.pair.B); // NOTE: undocumented
if (isRepeat && 0 != reg.pair.B) {
reg.PC -= 2;
consumeClock(5);
}
}
static inline void INI(Z80* ctx) { ctx->repeatIN(true, false); }
static inline void INIR(Z80* ctx) { ctx->repeatIN(true, true); }
static inline void IND(Z80* ctx) { ctx->repeatIN(false, false); }
static inline void INDR(Z80* ctx) { ctx->repeatIN(false, true); }
// Load Output port (n) with Acc.
static inline void OUT_N_A(Z80* ctx)
{
unsigned char n = ctx->fetch(3);
#ifndef Z80_DISABLE_DEBUG
if (ctx->isDebug()) ctx->log("[%04X] OUT ($%02X), %s", ctx->reg.PC - 2, n, ctx->registerDump(0b111));
#endif
ctx->outPortWithA(n, ctx->reg.pair.A);
}
// Output a byte to device (C) form register.
static inline void OUT_C_B(Z80* ctx) { ctx->OUT_C_R(0b000); }
static inline void OUT_C_C(Z80* ctx) { ctx->OUT_C_R(0b001); }
static inline void OUT_C_D(Z80* ctx) { ctx->OUT_C_R(0b010); }
static inline void OUT_C_E(Z80* ctx) { ctx->OUT_C_R(0b011); }
static inline void OUT_C_H(Z80* ctx) { ctx->OUT_C_R(0b100); }
static inline void OUT_C_L(Z80* ctx) { ctx->OUT_C_R(0b101); }
static inline void OUT_C_0(Z80* ctx) { ctx->OUT_C_R(0, true); }
static inline void OUT_C_A(Z80* ctx) { ctx->OUT_C_R(0b111); }
inline void OUT_C_R(unsigned char r, bool zero = false)
{
if (zero) {
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] OUT (%s), 0", reg.PC - 2, registerDump(0b001));
#endif
outPortWithB(reg.pair.C, 0);
} else {
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] OUT (%s), %s", reg.PC - 2, registerDump(0b001), registerDump(r));
#endif
outPortWithB(reg.pair.C, getRegister(r));
}
}
// Load Output port (C) with location (HL), increment/decrement HL and decrement B
inline void repeatOUT(bool isIncHL, bool isRepeat)
{
unsigned char o = readByte(getHL());
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) {
if (isIncHL) {
log("[%04X] %s ... p(%s) <- (%s) <$%02x> [%s]", reg.PC - 2, isRepeat ? "OUTIR" : "OUTI", registerDump(0b001), registerPairDump(0b10), o, registerDump(0b000));
} else {
log("[%04X] %s ... p(%s) <- (%s) <$%02x> [%s]", reg.PC - 2, isRepeat ? "OUTDR" : "OUTD", registerDump(0b001), registerPairDump(0b10), o, registerDump(0b000));
}
}
#endif
decrementB_forRepeatIO();
outPortWithB(reg.pair.C, o);
reg.WZ = (unsigned short)(getBC() + (isIncHL ? 1 : -1));
setHL((unsigned short)(getHL() + (isIncHL ? 1 : -1)));
setFlagZ(reg.pair.B == 0);
setFlagN(o & 0x80); // NOTE: ACTUAL FLAG CONDITION IS UNKNOWN
setFlagH(reg.pair.L + o > 0xFF); // NOTE: ACTUAL FLAG CONDITION IS UNKNOWN
setFlagC(isFlagH()); // NOTE: ACTUAL FLAG CONDITION IS UNKNOWN
setFlagPV(((reg.pair.H + o) & 0x07) ^ reg.pair.B); // NOTE: ACTUAL FLAG CONDITION IS UNKNOWN
if (isRepeat && 0 != reg.pair.B) {
reg.PC -= 2;
consumeClock(5);
}
}
static inline void OUTI(Z80* ctx) { ctx->repeatOUT(true, false); }
static inline void OUTIR(Z80* ctx) { ctx->repeatOUT(true, true); }
static inline void OUTD(Z80* ctx) { ctx->repeatOUT(false, false); }
static inline void OUTDR(Z80* ctx) { ctx->repeatOUT(false, true); }
// Decimal Adjust Accumulator
static inline void DAA(Z80* ctx) { ctx->daa(); }
inline void daa()
{
int a = reg.pair.A;
bool c = isFlagC();
bool ac = reg.pair.A > 0x99;
int add = (isFlagH() || (a & 0x0F) > 9 ? 0x06 : 0x00) + (c || ac ? 0x60 : 0x00);
a += isFlagN() ? -add : add;
a &= 0xFF;
setFlagS(a & 0x80);
setFlagXY(a);
setFlagZ(0 == a);
setFlagH((a ^ reg.pair.A) & flagH());
setFlagPV(isEvenNumberBits(a));
setFlagC(c | ac);
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] DAA ... A: $%02X -> $%02X", reg.PC - 1, reg.pair.A, a);
#endif
reg.pair.A = a;
}
// Rotate digit Left and right between Acc. and location (HL)
static inline void RLD_(Z80* ctx) { ctx->RLD(); }
inline void RLD()
{
unsigned short hl = getHL();
unsigned char beforeN = readByte(hl);
unsigned char nH = (beforeN & 0b11110000) >> 4;
unsigned char nL = beforeN & 0b00001111;
unsigned char aH = (reg.pair.A & 0b11110000) >> 4;
unsigned char aL = reg.pair.A & 0b00001111;
#ifndef Z80_DISABLE_DEBUG
unsigned char beforeA = reg.pair.A;
#endif
unsigned char afterA = (aH << 4) | nH;
unsigned char afterN = (nL << 4) | aL;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RLD ... A: $%02X -> $%02X, ($%04X): $%02X -> $%02X", reg.PC - 2, beforeA, afterA, hl, beforeN, afterN);
#endif
reg.pair.A = afterA;
writeByte(hl, afterN);
setFlagS(reg.pair.A & 0x80);
setFlagXY(reg.pair.A);
setFlagZ(reg.pair.A == 0);
resetFlagH();
setFlagPV(isEvenNumberBits(reg.pair.A));
resetFlagN();
consumeClock(2);
}
// Rotate digit Right and right between Acc. and location (HL)
static inline void RRD_(Z80* ctx) { ctx->RRD(); }
inline void RRD()
{
unsigned short hl = getHL();
unsigned char beforeN = readByte(hl);
unsigned char nH = (beforeN & 0b11110000) >> 4;
unsigned char nL = beforeN & 0b00001111;
unsigned char aH = (reg.pair.A & 0b11110000) >> 4;
unsigned char aL = reg.pair.A & 0b00001111;
#ifndef Z80_DISABLE_DEBUG
unsigned char beforeA = reg.pair.A;
#endif
unsigned char afterA = (aH << 4) | nL;
unsigned char afterN = (aL << 4) | nH;
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("[%04X] RRD ... A: $%02X -> $%02X, ($%04X): $%02X -> $%02X", reg.PC - 2, beforeA, afterA, hl, beforeN, afterN);
#endif
reg.pair.A = afterA;
writeByte(hl, afterN);
setFlagS(reg.pair.A & 0x80);
setFlagXY(reg.pair.A);
setFlagZ(reg.pair.A == 0);
resetFlagH();
setFlagPV(isEvenNumberBits(reg.pair.A));
resetFlagN();
consumeClock(2);
}
#ifndef Z80_DISABLE_BREAKPOINT
int opLength1[256] = {
1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 00 ~ 0F
2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, // 10 ~ 1F
2, 3, 3, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1, // 20 ~ 2F
2, 3, 3, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1, // 30 ~ 3F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40 ~ 4F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 50 ~ 5F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60 ~ 6F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 70 ~ 7F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 ~ 8F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90 ~ 9F
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0 ~ AF
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0 ~ BF
1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, 2, 3, 3, 2, 1, // C0 ~ CF
1, 1, 3, 2, 3, 1, 2, 1, 1, 1, 3, 2, 3, 0, 2, 1, // D0 ~ DF
1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, 0, 2, 1, // E0 ~ EF
1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, 0, 2, 1 // F0 ~ FF
};
int opLengthED[256] = {
3, 3, 0, 0, 2, 0, 0, 0, 3, 3, 0, 0, 2, 0, 0, 0, // 00 ~ 0F
3, 3, 0, 0, 2, 0, 0, 0, 3, 3, 0, 0, 2, 0, 0, 0, // 10 ~ 1F
3, 3, 0, 0, 2, 0, 0, 0, 3, 3, 0, 0, 2, 0, 0, 0, // 20 ~ 2F
0, 0, 0, 0, 2, 0, 0, 0, 3, 3, 0, 0, 2, 0, 0, 0, // 30 ~ 3F
2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 0, 2, // 40 ~ 4F
2, 2, 2, 4, 0, 0, 2, 2, 2, 2, 2, 4, 2, 0, 2, 2, // 50 ~ 5F
2, 2, 2, 4, 3, 0, 0, 2, 2, 2, 2, 4, 2, 0, 0, 2, // 60 ~ 6F
2, 2, 2, 4, 3, 0, 2, 0, 2, 2, 2, 4, 2, 0, 0, 0, // 70 ~ 7F
0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, // 80 ~ 8F
0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, // 90 ~ 9F
2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, // A0 ~ AF
2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, // B0 ~ BF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C0 ~ CF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D0 ~ DF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E0 ~ EF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F0 ~ FF
};
int opLengthIXY[256] = {
0, 0, 0, 0, 2, 2, 3, 0, 0, 2, 0, 0, 2, 2, 3, 0, // 00 ~ 0F
0, 0, 0, 0, 2, 2, 3, 0, 0, 2, 0, 0, 2, 2, 3, 0, // 10 ~ 1F
0, 4, 4, 2, 2, 2, 3, 0, 0, 2, 4, 2, 2, 2, 3, 0, // 20 ~ 2F
0, 0, 0, 0, 3, 3, 4, 0, 0, 2, 0, 0, 2, 2, 3, 0, // 30 ~ 3F
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 40 ~ 4F
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 50 ~ 5F
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 60 ~ 6F
3, 3, 3, 3, 3, 3, 0, 3, 2, 2, 2, 2, 2, 2, 3, 2, // 70 ~ 7F
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 80 ~ 8F
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 90 ~ 9F
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // A0 ~ AF
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // B0 ~ BF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, // C0 ~ CF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D0 ~ DF
0, 2, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, // E0 ~ EF
0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 // F0 ~ FF
};
#endif
void (*opSet1[256])(Z80* ctx) = {
NOP, LD_BC_NN, LD_BC_A, INC_RP_BC, INC_B, DEC_B, LD_B_N, RLCA, EX_AF_AF2, ADD_HL_BC, LD_A_BC, DEC_RP_BC, INC_C, DEC_C, LD_C_N, RRCA,
DJNZ_E, LD_DE_NN, LD_DE_A, INC_RP_DE, INC_D, DEC_D, LD_D_N, RLA, JR_E, ADD_HL_DE, LD_A_DE, DEC_RP_DE, INC_E, DEC_E, LD_E_N, RRA,
JR_NZ_E, LD_HL_NN, LD_ADDR_HL, INC_RP_HL, INC_H, DEC_H, LD_H_N, DAA, JR_Z_E, ADD_HL_HL, LD_HL_ADDR, DEC_RP_HL, INC_L, DEC_L, LD_L_N, CPL,
JR_NC_E, LD_SP_NN, LD_NN_A, INC_RP_SP, INC_HL, DEC_HL, LD_HL_N, SCF, JR_C_E, ADD_HL_SP, LD_A_NN, DEC_RP_SP, INC_A, DEC_A, LD_A_N, CCF,
LD_B_B, LD_B_C, LD_B_D, LD_B_E, LD_B_H, LD_B_L, LD_B_HL, LD_B_A, LD_C_B, LD_C_C, LD_C_D, LD_C_E, LD_C_H, LD_C_L, LD_C_HL, LD_C_A,
LD_D_B, LD_D_C, LD_D_D, LD_D_E, LD_D_H, LD_D_L, LD_D_HL, LD_D_A, LD_E_B, LD_E_C, LD_E_D, LD_E_E, LD_E_H, LD_E_L, LD_E_HL, LD_E_A,
LD_H_B, LD_H_C, LD_H_D, LD_H_E, LD_H_H, LD_H_L, LD_H_HL, LD_H_A, LD_L_B, LD_L_C, LD_L_D, LD_L_E, LD_L_H, LD_L_L, LD_L_HL, LD_L_A,
LD_HL_B, LD_HL_C, LD_HL_D, LD_HL_E, LD_HL_H, LD_HL_L, HALT, LD_HL_A, LD_A_B, LD_A_C, LD_A_D, LD_A_E, LD_A_H, LD_A_L, LD_A_HL, LD_A_A,
ADD_B, ADD_C, ADD_D, ADD_E, ADD_H, ADD_L, ADD_HL, ADD_A, ADC_B, ADC_C, ADC_D, ADC_E, ADC_H, ADC_L, ADC_HL, ADC_A,
SUB_B, SUB_C, SUB_D, SUB_E, SUB_H, SUB_L, SUB_HL, SUB_A, SBC_B, SBC_C, SBC_D, SBC_E, SBC_H, SBC_L, SBC_HL, SBC_A,
AND_B, AND_C, AND_D, AND_E, AND_H, AND_L, AND_HL, AND_A, XOR_B, XOR_C, XOR_D, XOR_E, XOR_H, XOR_L, XOR_HL, XOR_A,
OR_B, OR_C, OR_D, OR_E, OR_H, OR_L, OR_HL, OR_A, CP_B, CP_C, CP_D, CP_E, CP_H, CP_L, CP_HL, CP_A,
RET_C0, POP_BC, JP_C0_NN, JP_NN, CALL_C0_NN, PUSH_BC, ADD_N, RST00, RET_C1, RET, JP_C1_NN, OP_CB, CALL_C1_NN, CALL_NN, ADC_N, RST08,
RET_C2, POP_DE, JP_C2_NN, OUT_N_A, CALL_C2_NN, PUSH_DE, SUB_N, RST10, RET_C3, EXX, JP_C3_NN, IN_A_N, CALL_C3_NN, OP_IX, SBC_N, RST18,
RET_C4, POP_HL, JP_C4_NN, EX_SP_HL, CALL_C4_NN, PUSH_HL, AND_N, RST20, RET_C5, JP_HL, JP_C5_NN, EX_DE_HL, CALL_C5_NN, OP_ED, XOR_N, RST28,
RET_C6, POP_AF, JP_C6_NN, DI, CALL_C6_NN, PUSH_AF, OR_N, RST30, RET_C7, LD_SP_HL, JP_C7_NN, EI, CALL_C7_NN, OP_IY, CP_N, RST38};
void (*opSetCB[256])(Z80* ctx) = {
RLC_B, RLC_C, RLC_D, RLC_E, RLC_H, RLC_L, RLC_HL_, RLC_A,
RRC_B, RRC_C, RRC_D, RRC_E, RRC_H, RRC_L, RRC_HL_, RRC_A,
RL_B, RL_C, RL_D, RL_E, RL_H, RL_L, RL_HL_, RL_A,
RR_B, RR_C, RR_D, RR_E, RR_H, RR_L, RR_HL_, RR_A,
SLA_B, SLA_C, SLA_D, SLA_E, SLA_H, SLA_L, SLA_HL_, SLA_A,
SRA_B, SRA_C, SRA_D, SRA_E, SRA_H, SRA_L, SRA_HL_, SRA_A,
SLL_B, SLL_C, SLL_D, SLL_E, SLL_H, SLL_L, SLL_HL_, SLL_A,
SRL_B, SRL_C, SRL_D, SRL_E, SRL_H, SRL_L, SRL_HL_, SRL_A,
BIT_B_0, BIT_C_0, BIT_D_0, BIT_E_0, BIT_H_0, BIT_L_0, BIT_HL_0, BIT_A_0,
BIT_B_1, BIT_C_1, BIT_D_1, BIT_E_1, BIT_H_1, BIT_L_1, BIT_HL_1, BIT_A_1,
BIT_B_2, BIT_C_2, BIT_D_2, BIT_E_2, BIT_H_2, BIT_L_2, BIT_HL_2, BIT_A_2,
BIT_B_3, BIT_C_3, BIT_D_3, BIT_E_3, BIT_H_3, BIT_L_3, BIT_HL_3, BIT_A_3,
BIT_B_4, BIT_C_4, BIT_D_4, BIT_E_4, BIT_H_4, BIT_L_4, BIT_HL_4, BIT_A_4,
BIT_B_5, BIT_C_5, BIT_D_5, BIT_E_5, BIT_H_5, BIT_L_5, BIT_HL_5, BIT_A_5,
BIT_B_6, BIT_C_6, BIT_D_6, BIT_E_6, BIT_H_6, BIT_L_6, BIT_HL_6, BIT_A_6,
BIT_B_7, BIT_C_7, BIT_D_7, BIT_E_7, BIT_H_7, BIT_L_7, BIT_HL_7, BIT_A_7,
RES_B_0, RES_C_0, RES_D_0, RES_E_0, RES_H_0, RES_L_0, RES_HL_0, RES_A_0,
RES_B_1, RES_C_1, RES_D_1, RES_E_1, RES_H_1, RES_L_1, RES_HL_1, RES_A_1,
RES_B_2, RES_C_2, RES_D_2, RES_E_2, RES_H_2, RES_L_2, RES_HL_2, RES_A_2,
RES_B_3, RES_C_3, RES_D_3, RES_E_3, RES_H_3, RES_L_3, RES_HL_3, RES_A_3,
RES_B_4, RES_C_4, RES_D_4, RES_E_4, RES_H_4, RES_L_4, RES_HL_4, RES_A_4,
RES_B_5, RES_C_5, RES_D_5, RES_E_5, RES_H_5, RES_L_5, RES_HL_5, RES_A_5,
RES_B_6, RES_C_6, RES_D_6, RES_E_6, RES_H_6, RES_L_6, RES_HL_6, RES_A_6,
RES_B_7, RES_C_7, RES_D_7, RES_E_7, RES_H_7, RES_L_7, RES_HL_7, RES_A_7,
SET_B_0, SET_C_0, SET_D_0, SET_E_0, SET_H_0, SET_L_0, SET_HL_0, SET_A_0,
SET_B_1, SET_C_1, SET_D_1, SET_E_1, SET_H_1, SET_L_1, SET_HL_1, SET_A_1,
SET_B_2, SET_C_2, SET_D_2, SET_E_2, SET_H_2, SET_L_2, SET_HL_2, SET_A_2,
SET_B_3, SET_C_3, SET_D_3, SET_E_3, SET_H_3, SET_L_3, SET_HL_3, SET_A_3,
SET_B_4, SET_C_4, SET_D_4, SET_E_4, SET_H_4, SET_L_4, SET_HL_4, SET_A_4,
SET_B_5, SET_C_5, SET_D_5, SET_E_5, SET_H_5, SET_L_5, SET_HL_5, SET_A_5,
SET_B_6, SET_C_6, SET_D_6, SET_E_6, SET_H_6, SET_L_6, SET_HL_6, SET_A_6,
SET_B_7, SET_C_7, SET_D_7, SET_E_7, SET_H_7, SET_L_7, SET_HL_7, SET_A_7};
void (*opSetED[256])(Z80* ctx) = {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
IN_B_C, OUT_C_B, SBC_HL_BC, LD_ADDR_RP_BC, NEG_, RETN_, IM0, LD_I_A_,
IN_C_C, OUT_C_C, ADC_HL_BC, LD_RP_ADDR_BC, nullptr, RETI_, nullptr, LD_R_A_,
IN_D_C, OUT_C_D, SBC_HL_DE, LD_ADDR_RP_DE, nullptr, nullptr, IM1, LD_A_I_,
IN_E_C, OUT_C_E, ADC_HL_DE, LD_RP_ADDR_DE, nullptr, nullptr, IM2, LD_A_R_,
IN_H_C, OUT_C_H, SBC_HL_HL, LD_ADDR_RP_HL, nullptr, nullptr, nullptr, RRD_,
IN_L_C, OUT_C_L, ADC_HL_HL, LD_RP_ADDR_HL, nullptr, nullptr, nullptr, RLD_,
IN_C, OUT_C_0, SBC_HL_SP, LD_ADDR_RP_SP, nullptr, nullptr, nullptr, nullptr,
IN_A_C, OUT_C_A, ADC_HL_SP, LD_RP_ADDR_SP, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
LDI, CPI, INI, OUTI, nullptr, nullptr, nullptr, nullptr,
LDD, CPD, IND, OUTD, nullptr, nullptr, nullptr, nullptr,
LDIR, CPIR, INIR, OUTIR, nullptr, nullptr, nullptr, nullptr,
LDDR, CPDR, INDR, OUTDR, nullptr, nullptr, nullptr, nullptr};
void (*opSetIX[256])(Z80* ctx) = {
nullptr, nullptr, nullptr, nullptr, INC_B_2, DEC_B_2, LD_B_N_3, nullptr,
nullptr, ADD_IX_BC, nullptr, nullptr, INC_C_2, DEC_C_2, LD_C_N_3, nullptr,
nullptr, nullptr, nullptr, nullptr, INC_D_2, DEC_D_2, LD_D_N_3, nullptr,
nullptr, ADD_IX_DE, nullptr, nullptr, INC_E_2, DEC_E_2, LD_E_N_3, nullptr,
nullptr, LD_IX_NN_, LD_ADDR_IX_, INC_IX_reg_, INC_IXH_, DEC_IXH_, LD_IXH_N_, nullptr,
nullptr, ADD_IX_IX, LD_IX_ADDR_, DEC_IX_reg_, INC_IXL_, DEC_IXL_, LD_IXL_N_, nullptr,
nullptr, nullptr, nullptr, nullptr, INC_IX_, DEC_IX_, LD_IX_N_, nullptr,
nullptr, ADD_IX_SP, nullptr, nullptr, INC_A_2, DEC_A_2, LD_A_N_3, nullptr,
LD_B_B_2, LD_B_C_2, LD_B_D_2, LD_B_E_2, LD_B_IXH, LD_B_IXL, LD_B_IX, LD_B_A_2,
LD_C_B_2, LD_C_C_2, LD_C_D_2, LD_C_E_2, LD_C_IXH, LD_C_IXL, LD_C_IX, LD_C_A_2,
LD_D_B_2, LD_D_C_2, LD_D_D_2, LD_D_E_2, LD_D_IXH, LD_D_IXL, LD_D_IX, LD_D_A_2,
LD_E_B_2, LD_E_C_2, LD_E_D_2, LD_E_E_2, LD_E_IXH, LD_E_IXL, LD_E_IX, LD_E_A_2,
LD_IXH_B, LD_IXH_C, LD_IXH_D, LD_IXH_E, LD_IXH_IXH_, LD_IXH_IXL_, LD_H_IX, LD_IXH_A,
LD_IXL_B, LD_IXL_C, LD_IXL_D, LD_IXL_E, LD_IXL_IXH_, LD_IXL_IXL_, LD_L_IX, LD_IXL_A,
LD_IX_B, LD_IX_C, LD_IX_D, LD_IX_E, LD_IX_H, LD_IX_L, nullptr, LD_IX_A,
LD_A_B_2, LD_A_C_2, LD_A_D_2, LD_A_E_2, LD_A_IXH, LD_A_IXL, LD_A_IX, LD_A_A_2,
ADD_B_2, ADD_C_2, ADD_D_2, ADD_E_2, ADD_IXH_, ADD_IXL_, ADD_IX_, ADD_A_2,
ADC_B_2, ADC_C_2, ADC_D_2, ADC_E_2, ADC_IXH_, ADC_IXL_, ADC_IX_, ADC_A_2,
SUB_B_2, SUB_C_2, SUB_D_2, SUB_E_2, SUB_IXH_, SUB_IXL_, SUB_IX_, SUB_A_2,
SBC_B_2, SBC_C_2, SBC_D_2, SBC_E_2, SBC_IXH_, SBC_IXL_, SBC_IX_, SBC_A_2,
AND_B_2, AND_C_2, AND_D_2, AND_E_2, AND_IXH_, AND_IXL_, AND_IX_, AND_A_2,
XOR_B_2, XOR_C_2, XOR_D_2, XOR_E_2, XOR_IXH_, XOR_IXL_, XOR_IX_, XOR_A_2,
OR_B_2, OR_C_2, OR_D_2, OR_E_2, OR_IXH_, OR_IXL_, OR_IX_, OR_A_2,
CP_B_2, CP_C_2, CP_D_2, CP_E_2, CP_IXH_, CP_IXL_, CP_IX_, CP_A_2,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, OP_IX4, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, POP_IX_, nullptr, EX_SP_IX_, nullptr, PUSH_IX_, nullptr, nullptr,
nullptr, JP_IX, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, LD_SP_IX_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
void (*opSetIY[256])(Z80* ctx) = {
nullptr, nullptr, nullptr, nullptr, INC_B_2, DEC_B_2, LD_B_N_3, nullptr,
nullptr, ADD_IY_BC, nullptr, nullptr, INC_C_2, DEC_C_2, LD_C_N_3, nullptr,
nullptr, nullptr, nullptr, nullptr, INC_D_2, DEC_D_2, LD_D_N_3, nullptr,
nullptr, ADD_IY_DE, nullptr, nullptr, INC_E_2, DEC_E_2, LD_E_N_3, nullptr,
nullptr, LD_IY_NN_, LD_ADDR_IY_, INC_IY_reg_, INC_IYH_, DEC_IYH_, LD_IYH_N_, nullptr,
nullptr, ADD_IY_IY, LD_IY_ADDR_, DEC_IY_reg_, INC_IYL_, DEC_IYL_, LD_IYL_N_, nullptr,
nullptr, nullptr, nullptr, nullptr, INC_IY_, DEC_IY_, LD_IY_N_, nullptr,
nullptr, ADD_IY_SP, nullptr, nullptr, INC_A_2, DEC_A_2, LD_A_N_3, nullptr,
LD_B_B_2, LD_B_C_2, LD_B_D_2, LD_B_E_2, LD_B_IYH, LD_B_IYL, LD_B_IY, LD_B_A_2,
LD_C_B_2, LD_C_C_2, LD_C_D_2, LD_C_E_2, LD_C_IYH, LD_C_IYL, LD_C_IY, LD_C_A_2,
LD_D_B_2, LD_D_C_2, LD_D_D_2, LD_D_E_2, LD_D_IYH, LD_D_IYL, LD_D_IY, LD_D_A_2,
LD_E_B_2, LD_E_C_2, LD_E_D_2, LD_E_E_2, LD_E_IYH, LD_E_IYL, LD_E_IY, LD_E_A_2,
LD_IYH_B, LD_IYH_C, LD_IYH_D, LD_IYH_E, LD_IYH_IYH_, LD_IYH_IYL_, LD_H_IY, LD_IYH_A,
LD_IYL_B, LD_IYL_C, LD_IYL_D, LD_IYL_E, LD_IYL_IYH_, LD_IYL_IYL_, LD_L_IY, LD_IYL_A,
LD_IY_B, LD_IY_C, LD_IY_D, LD_IY_E, LD_IY_H, LD_IY_L, nullptr, LD_IY_A,
LD_A_B_2, LD_A_C_2, LD_A_D_2, LD_A_E_2, LD_A_IYH, LD_A_IYL, LD_A_IY, LD_A_A_2,
ADD_B_2, ADD_C_2, ADD_D_2, ADD_E_2, ADD_IYH_, ADD_IYL_, ADD_IY_, ADD_A_2,
ADC_B_2, ADC_C_2, ADC_D_2, ADC_E_2, ADC_IYH_, ADC_IYL_, ADC_IY_, ADC_A_2,
SUB_B_2, SUB_C_2, SUB_D_2, SUB_E_2, SUB_IYH_, SUB_IYL_, SUB_IY_, SUB_A_2,
SBC_B_2, SBC_C_2, SBC_D_2, SBC_E_2, SBC_IYH_, SBC_IYL_, SBC_IY_, SBC_A_2,
AND_B_2, AND_C_2, AND_D_2, AND_E_2, AND_IYH_, AND_IYL_, AND_IY_, AND_A_2,
XOR_B_2, XOR_C_2, XOR_D_2, XOR_E_2, XOR_IYH_, XOR_IYL_, XOR_IY_, XOR_A_2,
OR_B_2, OR_C_2, OR_D_2, OR_E_2, OR_IYH_, OR_IYL_, OR_IY_, OR_A_2,
CP_B_2, CP_C_2, CP_D_2, CP_E_2, CP_IYH_, CP_IYL_, CP_IY_, CP_A_2,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, OP_IY4, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, POP_IY_, nullptr, EX_SP_IY_, nullptr, PUSH_IY_, nullptr, nullptr,
nullptr, JP_IY, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, LD_SP_IY_, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
void (*opSetIX4[256])(Z80* ctx, signed char d) = {
RLC_IX_with_LD_B, RLC_IX_with_LD_C, RLC_IX_with_LD_D, RLC_IX_with_LD_E, RLC_IX_with_LD_H, RLC_IX_with_LD_L, RLC_IX_, RLC_IX_with_LD_A,
RRC_IX_with_LD_B, RRC_IX_with_LD_C, RRC_IX_with_LD_D, RRC_IX_with_LD_E, RRC_IX_with_LD_H, RRC_IX_with_LD_L, RRC_IX_, RRC_IX_with_LD_A,
RL_IX_with_LD_B, RL_IX_with_LD_C, RL_IX_with_LD_D, RL_IX_with_LD_E, RL_IX_with_LD_H, RL_IX_with_LD_L, RL_IX_, RL_IX_with_LD_A,
RR_IX_with_LD_B, RR_IX_with_LD_C, RR_IX_with_LD_D, RR_IX_with_LD_E, RR_IX_with_LD_H, RR_IX_with_LD_L, RR_IX_, RR_IX_with_LD_A,
SLA_IX_with_LD_B, SLA_IX_with_LD_C, SLA_IX_with_LD_D, SLA_IX_with_LD_E, SLA_IX_with_LD_H, SLA_IX_with_LD_L, SLA_IX_, SLA_IX_with_LD_A,
SRA_IX_with_LD_B, SRA_IX_with_LD_C, SRA_IX_with_LD_D, SRA_IX_with_LD_E, SRA_IX_with_LD_H, SRA_IX_with_LD_L, SRA_IX_, SRA_IX_with_LD_A,
SLL_IX_with_LD_B, SLL_IX_with_LD_C, SLL_IX_with_LD_D, SLL_IX_with_LD_E, SLL_IX_with_LD_H, SLL_IX_with_LD_L, SLL_IX_, SLL_IX_with_LD_A,
SRL_IX_with_LD_B, SRL_IX_with_LD_C, SRL_IX_with_LD_D, SRL_IX_with_LD_E, SRL_IX_with_LD_H, SRL_IX_with_LD_L, SRL_IX_, SRL_IX_with_LD_A,
BIT_IX_0, BIT_IX_0, BIT_IX_0, BIT_IX_0, BIT_IX_0, BIT_IX_0, BIT_IX_0, BIT_IX_0,
BIT_IX_1, BIT_IX_1, BIT_IX_1, BIT_IX_1, BIT_IX_1, BIT_IX_1, BIT_IX_1, BIT_IX_1,
BIT_IX_2, BIT_IX_2, BIT_IX_2, BIT_IX_2, BIT_IX_2, BIT_IX_2, BIT_IX_2, BIT_IX_2,
BIT_IX_3, BIT_IX_3, BIT_IX_3, BIT_IX_3, BIT_IX_3, BIT_IX_3, BIT_IX_3, BIT_IX_3,
BIT_IX_4, BIT_IX_4, BIT_IX_4, BIT_IX_4, BIT_IX_4, BIT_IX_4, BIT_IX_4, BIT_IX_4,
BIT_IX_5, BIT_IX_5, BIT_IX_5, BIT_IX_5, BIT_IX_5, BIT_IX_5, BIT_IX_5, BIT_IX_5,
BIT_IX_6, BIT_IX_6, BIT_IX_6, BIT_IX_6, BIT_IX_6, BIT_IX_6, BIT_IX_6, BIT_IX_6,
BIT_IX_7, BIT_IX_7, BIT_IX_7, BIT_IX_7, BIT_IX_7, BIT_IX_7, BIT_IX_7, BIT_IX_7,
RES_IX_0_with_LD_B, RES_IX_0_with_LD_C, RES_IX_0_with_LD_D, RES_IX_0_with_LD_E, RES_IX_0_with_LD_H, RES_IX_0_with_LD_L, RES_IX_0, RES_IX_0_with_LD_A,
RES_IX_1_with_LD_B, RES_IX_1_with_LD_C, RES_IX_1_with_LD_D, RES_IX_1_with_LD_E, RES_IX_1_with_LD_H, RES_IX_1_with_LD_L, RES_IX_1, RES_IX_1_with_LD_A,
RES_IX_2_with_LD_B, RES_IX_2_with_LD_C, RES_IX_2_with_LD_D, RES_IX_2_with_LD_E, RES_IX_2_with_LD_H, RES_IX_2_with_LD_L, RES_IX_2, RES_IX_2_with_LD_A,
RES_IX_3_with_LD_B, RES_IX_3_with_LD_C, RES_IX_3_with_LD_D, RES_IX_3_with_LD_E, RES_IX_3_with_LD_H, RES_IX_3_with_LD_L, RES_IX_3, RES_IX_3_with_LD_A,
RES_IX_4_with_LD_B, RES_IX_4_with_LD_C, RES_IX_4_with_LD_D, RES_IX_4_with_LD_E, RES_IX_4_with_LD_H, RES_IX_4_with_LD_L, RES_IX_4, RES_IX_4_with_LD_A,
RES_IX_5_with_LD_B, RES_IX_5_with_LD_C, RES_IX_5_with_LD_D, RES_IX_5_with_LD_E, RES_IX_5_with_LD_H, RES_IX_5_with_LD_L, RES_IX_5, RES_IX_5_with_LD_A,
RES_IX_6_with_LD_B, RES_IX_6_with_LD_C, RES_IX_6_with_LD_D, RES_IX_6_with_LD_E, RES_IX_6_with_LD_H, RES_IX_6_with_LD_L, RES_IX_6, RES_IX_6_with_LD_A,
RES_IX_7_with_LD_B, RES_IX_7_with_LD_C, RES_IX_7_with_LD_D, RES_IX_7_with_LD_E, RES_IX_7_with_LD_H, RES_IX_7_with_LD_L, RES_IX_7, RES_IX_7_with_LD_A,
SET_IX_0_with_LD_B, SET_IX_0_with_LD_C, SET_IX_0_with_LD_D, SET_IX_0_with_LD_E, SET_IX_0_with_LD_H, SET_IX_0_with_LD_L, SET_IX_0, SET_IX_0_with_LD_A,
SET_IX_1_with_LD_B, SET_IX_1_with_LD_C, SET_IX_1_with_LD_D, SET_IX_1_with_LD_E, SET_IX_1_with_LD_H, SET_IX_1_with_LD_L, SET_IX_1, SET_IX_1_with_LD_A,
SET_IX_2_with_LD_B, SET_IX_2_with_LD_C, SET_IX_2_with_LD_D, SET_IX_2_with_LD_E, SET_IX_2_with_LD_H, SET_IX_2_with_LD_L, SET_IX_2, SET_IX_2_with_LD_A,
SET_IX_3_with_LD_B, SET_IX_3_with_LD_C, SET_IX_3_with_LD_D, SET_IX_3_with_LD_E, SET_IX_3_with_LD_H, SET_IX_3_with_LD_L, SET_IX_3, SET_IX_3_with_LD_A,
SET_IX_4_with_LD_B, SET_IX_4_with_LD_C, SET_IX_4_with_LD_D, SET_IX_4_with_LD_E, SET_IX_4_with_LD_H, SET_IX_4_with_LD_L, SET_IX_4, SET_IX_4_with_LD_A,
SET_IX_5_with_LD_B, SET_IX_5_with_LD_C, SET_IX_5_with_LD_D, SET_IX_5_with_LD_E, SET_IX_5_with_LD_H, SET_IX_5_with_LD_L, SET_IX_5, SET_IX_5_with_LD_A,
SET_IX_6_with_LD_B, SET_IX_6_with_LD_C, SET_IX_6_with_LD_D, SET_IX_6_with_LD_E, SET_IX_6_with_LD_H, SET_IX_6_with_LD_L, SET_IX_6, SET_IX_6_with_LD_A,
SET_IX_7_with_LD_B, SET_IX_7_with_LD_C, SET_IX_7_with_LD_D, SET_IX_7_with_LD_E, SET_IX_7_with_LD_H, SET_IX_7_with_LD_L, SET_IX_7, SET_IX_7_with_LD_A};
void (*opSetIY4[256])(Z80* ctx, signed char d) = {
RLC_IY_with_LD_B, RLC_IY_with_LD_C, RLC_IY_with_LD_D, RLC_IY_with_LD_E, RLC_IY_with_LD_H, RLC_IY_with_LD_L, RLC_IY_, RLC_IY_with_LD_A,
RRC_IY_with_LD_B, RRC_IY_with_LD_C, RRC_IY_with_LD_D, RRC_IY_with_LD_E, RRC_IY_with_LD_H, RRC_IY_with_LD_L, RRC_IY_, RRC_IY_with_LD_A,
RL_IY_with_LD_B, RL_IY_with_LD_C, RL_IY_with_LD_D, RL_IY_with_LD_E, RL_IY_with_LD_H, RL_IY_with_LD_L, RL_IY_, RL_IY_with_LD_A,
RR_IY_with_LD_B, RR_IY_with_LD_C, RR_IY_with_LD_D, RR_IY_with_LD_E, RR_IY_with_LD_H, RR_IY_with_LD_L, RR_IY_, RR_IY_with_LD_A,
SLA_IY_with_LD_B, SLA_IY_with_LD_C, SLA_IY_with_LD_D, SLA_IY_with_LD_E, SLA_IY_with_LD_H, SLA_IY_with_LD_L, SLA_IY_, SLA_IY_with_LD_A,
SRA_IY_with_LD_B, SRA_IY_with_LD_C, SRA_IY_with_LD_D, SRA_IY_with_LD_E, SRA_IY_with_LD_H, SRA_IY_with_LD_L, SRA_IY_, SRA_IY_with_LD_A,
SLL_IY_with_LD_B, SLL_IY_with_LD_C, SLL_IY_with_LD_D, SLL_IY_with_LD_E, SLL_IY_with_LD_H, SLL_IY_with_LD_L, SLL_IY_, SLL_IY_with_LD_A,
SRL_IY_with_LD_B, SRL_IY_with_LD_C, SRL_IY_with_LD_D, SRL_IY_with_LD_E, SRL_IY_with_LD_H, SRL_IY_with_LD_L, SRL_IY_, SRL_IY_with_LD_A,
BIT_IY_0, BIT_IY_0, BIT_IY_0, BIT_IY_0, BIT_IY_0, BIT_IY_0, BIT_IY_0, BIT_IY_0,
BIT_IY_1, BIT_IY_1, BIT_IY_1, BIT_IY_1, BIT_IY_1, BIT_IY_1, BIT_IY_1, BIT_IY_1,
BIT_IY_2, BIT_IY_2, BIT_IY_2, BIT_IY_2, BIT_IY_2, BIT_IY_2, BIT_IY_2, BIT_IY_2,
BIT_IY_3, BIT_IY_3, BIT_IY_3, BIT_IY_3, BIT_IY_3, BIT_IY_3, BIT_IY_3, BIT_IY_3,
BIT_IY_4, BIT_IY_4, BIT_IY_4, BIT_IY_4, BIT_IY_4, BIT_IY_4, BIT_IY_4, BIT_IY_4,
BIT_IY_5, BIT_IY_5, BIT_IY_5, BIT_IY_5, BIT_IY_5, BIT_IY_5, BIT_IY_5, BIT_IY_5,
BIT_IY_6, BIT_IY_6, BIT_IY_6, BIT_IY_6, BIT_IY_6, BIT_IY_6, BIT_IY_6, BIT_IY_6,
BIT_IY_7, BIT_IY_7, BIT_IY_7, BIT_IY_7, BIT_IY_7, BIT_IY_7, BIT_IY_7, BIT_IY_7,
RES_IY_0_with_LD_B, RES_IY_0_with_LD_C, RES_IY_0_with_LD_D, RES_IY_0_with_LD_E, RES_IY_0_with_LD_H, RES_IY_0_with_LD_L, RES_IY_0, RES_IY_0_with_LD_A,
RES_IY_1_with_LD_B, RES_IY_1_with_LD_C, RES_IY_1_with_LD_D, RES_IY_1_with_LD_E, RES_IY_1_with_LD_H, RES_IY_1_with_LD_L, RES_IY_1, RES_IY_1_with_LD_A,
RES_IY_2_with_LD_B, RES_IY_2_with_LD_C, RES_IY_2_with_LD_D, RES_IY_2_with_LD_E, RES_IY_2_with_LD_H, RES_IY_2_with_LD_L, RES_IY_2, RES_IY_2_with_LD_A,
RES_IY_3_with_LD_B, RES_IY_3_with_LD_C, RES_IY_3_with_LD_D, RES_IY_3_with_LD_E, RES_IY_3_with_LD_H, RES_IY_3_with_LD_L, RES_IY_3, RES_IY_3_with_LD_A,
RES_IY_4_with_LD_B, RES_IY_4_with_LD_C, RES_IY_4_with_LD_D, RES_IY_4_with_LD_E, RES_IY_4_with_LD_H, RES_IY_4_with_LD_L, RES_IY_4, RES_IY_4_with_LD_A,
RES_IY_5_with_LD_B, RES_IY_5_with_LD_C, RES_IY_5_with_LD_D, RES_IY_5_with_LD_E, RES_IY_5_with_LD_H, RES_IY_5_with_LD_L, RES_IY_5, RES_IY_5_with_LD_A,
RES_IY_6_with_LD_B, RES_IY_6_with_LD_C, RES_IY_6_with_LD_D, RES_IY_6_with_LD_E, RES_IY_6_with_LD_H, RES_IY_6_with_LD_L, RES_IY_6, RES_IY_6_with_LD_A,
RES_IY_7_with_LD_B, RES_IY_7_with_LD_C, RES_IY_7_with_LD_D, RES_IY_7_with_LD_E, RES_IY_7_with_LD_H, RES_IY_7_with_LD_L, RES_IY_7, RES_IY_7_with_LD_A,
SET_IY_0_with_LD_B, SET_IY_0_with_LD_C, SET_IY_0_with_LD_D, SET_IY_0_with_LD_E, SET_IY_0_with_LD_H, SET_IY_0_with_LD_L, SET_IY_0, SET_IY_0_with_LD_A,
SET_IY_1_with_LD_B, SET_IY_1_with_LD_C, SET_IY_1_with_LD_D, SET_IY_1_with_LD_E, SET_IY_1_with_LD_H, SET_IY_1_with_LD_L, SET_IY_1, SET_IY_1_with_LD_A,
SET_IY_2_with_LD_B, SET_IY_2_with_LD_C, SET_IY_2_with_LD_D, SET_IY_2_with_LD_E, SET_IY_2_with_LD_H, SET_IY_2_with_LD_L, SET_IY_2, SET_IY_2_with_LD_A,
SET_IY_3_with_LD_B, SET_IY_3_with_LD_C, SET_IY_3_with_LD_D, SET_IY_3_with_LD_E, SET_IY_3_with_LD_H, SET_IY_3_with_LD_L, SET_IY_3, SET_IY_3_with_LD_A,
SET_IY_4_with_LD_B, SET_IY_4_with_LD_C, SET_IY_4_with_LD_D, SET_IY_4_with_LD_E, SET_IY_4_with_LD_H, SET_IY_4_with_LD_L, SET_IY_4, SET_IY_4_with_LD_A,
SET_IY_5_with_LD_B, SET_IY_5_with_LD_C, SET_IY_5_with_LD_D, SET_IY_5_with_LD_E, SET_IY_5_with_LD_H, SET_IY_5_with_LD_L, SET_IY_5, SET_IY_5_with_LD_A,
SET_IY_6_with_LD_B, SET_IY_6_with_LD_C, SET_IY_6_with_LD_D, SET_IY_6_with_LD_E, SET_IY_6_with_LD_H, SET_IY_6_with_LD_L, SET_IY_6, SET_IY_6_with_LD_A,
SET_IY_7_with_LD_B, SET_IY_7_with_LD_C, SET_IY_7_with_LD_D, SET_IY_7_with_LD_E, SET_IY_7_with_LD_H, SET_IY_7_with_LD_L, SET_IY_7, SET_IY_7_with_LD_A};
inline void checkInterrupt()
{
// Interrupt processing is not executed by the instruction immediately after executing EI.
if (reg.execEI) {
return;
}
// check interrupt flag
if (reg.interrupt & 0b10000000) {
// execute NMI
if (reg.IFF & IFF_NMI()) {
return;
}
reg.interrupt &= 0b01111111;
reg.IFF &= ~IFF_HALT();
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("EXECUTE NMI: $%04X", reg.interruptAddrN);
#endif
reg.R = ((reg.R + 1) & 0x7F) | (reg.R & 0x80);
reg.IFF |= IFF_NMI();
reg.IFF &= ~IFF1();
push(getPCH(), 4);
push(getPCL(), 4);
reg.PC = reg.interruptAddrN;
consumeClock(11);
#ifndef Z80_DISABLE_NESTCHECK
invokeCallHandlers();
#endif
} else if (reg.interrupt & 0b01000000) {
// execute IRQ
if (!(reg.IFF & IFF1())) {
return;
}
reg.interrupt &= 0b10111111;
reg.IFF &= ~IFF_HALT();
reg.IFF |= IFF_IRQ();
reg.IFF &= ~(IFF1() | IFF2());
reg.R = ((reg.R + 1) & 0x7F) | (reg.R & 0x80);
switch (reg.interrupt & 0b00000011) {
case 0: // mode 0
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("EXECUTE INT MODE1 (RST TO $%04X)", reg.interruptVector * 8);
#endif
if (reg.interruptVector == 0xCD) {
consumeClock(7);
}
RST(reg.interruptVector, false);
break;
case 1: // mode 1 (13Hz)
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("EXECUTE INT MODE1 (RST TO $0038)");
#endif
consumeClock(1);
RST(7, false);
break;
case 2: { // mode 2
writeByte(reg.SP - 1, getPCH());
writeByte(reg.SP - 2, getPCL());
reg.SP -= 2;
unsigned short addr = make16BitsFromLE(reg.interruptVector, reg.I);
unsigned short pc = make16BitsFromLE(readByte(addr), readByte(addr + 1));
#ifndef Z80_DISABLE_DEBUG
if (isDebug()) log("EXECUTE INT MODE2: ($%04X) = $%04X", addr, pc);
#endif
reg.PC = pc;
consumeClock(3);
#ifndef Z80_DISABLE_NESTCHECK
invokeCallHandlers();
#endif
break;
}
}
}
}
inline void updateRefreshRegister()
{
reg.R = ((reg.R + 1) & 0x7F) | (reg.R & 0x80);
consumeClock(2);
}
public: // API functions
#ifdef Z80_NO_FUNCTIONAL
Z80(unsigned char (*read)(void* arg, unsigned short addr),
void (*write)(void* arg, unsigned short addr, unsigned char value),
unsigned char (*in)(void* arg, unsigned short port),
void (*out)(void* arg, unsigned short port, unsigned char value),
void* arg,
bool returnPortAs16Bits = false)
#else
Z80(std::function<unsigned char(void*, unsigned short)> read,
std::function<void(void*, unsigned short, unsigned char)> write,
std::function<unsigned char(void*, unsigned short)> in,
std::function<void(void*, unsigned short, unsigned char)> out,
void* arg,
bool returnPortAs16Bits = false)
#endif
{
this->CB.arg = arg;
initialize();
setupCallback(read, write, in, out, returnPortAs16Bits);
}
// without setup callbacks
Z80(void* arg)
{
this->CB.arg = arg;
initialize();
}
Z80()
{
initialize();
}
#ifndef Z80_NO_FUNCTIONAL
void setupCallback(std::function<unsigned char(void*, unsigned short)> read,
std::function<void(void*, unsigned short, unsigned char)> write,
std::function<unsigned char(void*, unsigned short)> in,
std::function<void(void*, unsigned short, unsigned char)> out,
void* arg,
bool returnPortAs16Bits = false)
{
CB.arg = arg;
setupCallback(read, write, in, out, returnPortAs16Bits);
}
void setupCallback(std::function<unsigned char(void*, unsigned short)> read,
std::function<void(void*, unsigned short, unsigned char)> write,
std::function<unsigned char(void*, unsigned short)> in,
std::function<void(void*, unsigned short, unsigned char)> out,
bool returnPortAs16Bits = false)
{
setupMemoryCallback(read, write);
setupDeviceCallback(in, out, returnPortAs16Bits);
}
void setupMemoryCallback(std::function<unsigned char(void*, unsigned short)> read,
std::function<void(void*, unsigned short, unsigned char)> write)
{
CB.read = read;
CB.write = write;
}
void setupDeviceCallback(std::function<unsigned char(void*, unsigned short)> in,
std::function<void(void*, unsigned short, unsigned char)> out,
bool returnPortAs16Bits)
{
CB.in = in;
CB.out = out;
#ifndef Z80_UNSUPPORT_16BIT_PORT
CB.returnPortAs16Bits = returnPortAs16Bits;
#endif
}
#else
void setupCallback(unsigned char (*read)(void* arg, unsigned short addr),
void (*write)(void* arg, unsigned short addr, unsigned char value),
unsigned char (*in)(void* arg, unsigned short port),
void (*out)(void* arg, unsigned short port, unsigned char value),
void* arg,
bool returnPortAs16Bits = false)
{
CB.arg = arg;
setupCallback(read, write, in, out, returnPortAs16Bits);
}
void setupCallback(unsigned char (*read)(void* arg, unsigned short addr),
void (*write)(void* arg, unsigned short addr, unsigned char value),
unsigned char (*in)(void* arg, unsigned short port),
void (*out)(void* arg, unsigned short port, unsigned char value),
bool returnPortAs16Bits = false)
{
setupMemoryCallback(read, write);
setupDeviceCallback(in, out, returnPortAs16Bits);
}
void setupMemoryCallback(unsigned char (*read)(void* arg, unsigned short addr),
void (*write)(void* arg, unsigned short addr, unsigned char value))
{
CB.read = read;
CB.write = write;
}
void setupDeviceCallback(unsigned char (*in)(void* arg, unsigned short addr),
void (*out)(void* arg, unsigned short addr, unsigned char value),
bool returnPortAs16Bits)
{
CB.in = in;
CB.out = out;
#ifndef Z80_UNSUPPORT_16BIT_PORT
CB.returnPortAs16Bits = returnPortAs16Bits;
#endif
}
#endif
void initialize()
{
resetConsumeClockCallback();
#ifndef Z80_DISABLE_DEBUG
resetDebugMessage();
#endif
::memset(®, 0, sizeof(reg));
reg.pair.A = 0xff;
reg.pair.F = 0xff;
reg.SP = 0xffff;
memset(&wtc, 0, sizeof(wtc));
}
~Z80()
{
#ifndef Z80_DISABLE_BREAKPOINT
removeAllBreakOperands();
removeAllBreakPoints();
#endif
#ifndef Z80_DISABLE_NESTCHECK
removeAllCallHandlers();
removeAllReturnHandlers();
#endif
}
#ifndef Z80_DISABLE_DEBUG
#ifdef Z80_NO_FUNCTIONAL
void setDebugMessage(void (*debugMessage)(void* arg, const char* msg))
#else
void setDebugMessage(std::function<void(void*, const char*)> debugMessage)
#endif
{
CB.debugMessageEnabled = true;
CB.debugMessage = debugMessage;
}
void resetDebugMessage()
{
CB.debugMessageEnabled = false;
#ifdef Z80_NO_FUNCTIONAL
CB.debugMessage = nullptr;
#endif
}
inline bool isDebug()
{
return CB.debugMessageEnabled;
}
#endif
inline unsigned short make16BitsFromLE(unsigned char low, unsigned char high)
{
unsigned short n = high;
n <<= 8;
n |= low;
return n;
}
inline void splitTo8BitsPair(unsigned short value, unsigned char* high, unsigned char* low)
{
*high = (value & 0xFF00) >> 8;
*low = value & 0xFF;
}
#ifndef Z80_DISABLE_BREAKPOINT
#ifdef Z80_NO_FUNCTIONAL
void addBreakPoint(unsigned short addr, void (*callback)(void*))
#else
void addBreakPoint(unsigned short addr, std::function<void(void*)> callback)
#endif
{
auto it = CB.breakPoints.find(addr);
if (it == CB.breakPoints.end()) {
CB.breakPoints[addr] = new std::vector<BreakPoint*>();
}
CB.breakPoints[addr]->push_back(new BreakPoint(addr, callback));
}
void removeBreakPoint(unsigned short addr)
{
auto it = CB.breakPoints.find(addr);
if (it == CB.breakPoints.end()) return;
for (auto bp : *CB.breakPoints[addr]) delete bp;
delete CB.breakPoints[addr];
CB.breakPoints.erase(it);
}
void removeAllBreakPoints()
{
std::vector<int> keys;
for (auto it = CB.breakPoints.begin(); it != CB.breakPoints.end(); it++) {
keys.push_back(it->first);
}
for (auto key : keys) {
removeBreakPoint(key);
}
}
#ifdef Z80_NO_FUNCTIONAL
void addBreakOperand(int operandNumber, void (*callback)(void*, unsigned char*, int))
#else
void addBreakOperand(int operandNumber, std::function<void(void*, unsigned char*, int)> callback)
#endif
{
addBreakOperand(0, operandNumber, callback);
}
#ifdef Z80_NO_FUNCTIONAL
void addBreakOperand(int prefixNumber, int operandNumber, void (*callback)(void*, unsigned char*, int))
#else
void addBreakOperand(int prefixNumber, int operandNumber, std::function<void(void*, unsigned char*, int)> callback)
#endif
{
auto op = (prefixNumber << 8) | operandNumber;
auto it = CB.breakOperands.find(op);
if (it == CB.breakOperands.end()) {
CB.breakOperands[op] = new std::vector<BreakOperand*>();
}
CB.breakOperands[op]->push_back(new BreakOperand(prefixNumber, operandNumber, callback));
}
#ifdef Z80_NO_FUNCTIONAL
void addBreakOperand(unsigned char prefixNumber1, unsigned char prefixNumber2, unsigned char operandNumber, void (*callback)(void*, unsigned char*, int))
#else
void addBreakOperand(unsigned char prefixNumber1, unsigned char prefixNumber2, unsigned char operandNumber, std::function<void(void*, unsigned char*, int)> callback)
#endif
{
int n = make16BitsFromLE(prefixNumber2, prefixNumber1);
int prefixNumber = n;
n <<= 8;
n |= operandNumber;
addBreakOperand(prefixNumber, n, callback);
}
void removeBreakOperand(int operandNumber)
{
auto it = CB.breakOperands.find(operandNumber);
if (it == CB.breakOperands.end()) return;
for (auto bo : *CB.breakOperands[operandNumber]) delete bo;
delete CB.breakOperands[operandNumber];
CB.breakOperands.erase(it);
}
void removeBreakOperand(unsigned char prefixNumber, unsigned char operandNumber)
{
removeBreakOperand(make16BitsFromLE(operandNumber, prefixNumber));
}
void removeBreakOperand(unsigned char prefixNumber1, unsigned char prefixNumber2, unsigned char operandNumber)
{
int n = make16BitsFromLE(prefixNumber2, prefixNumber1);
n <<= 8;
n |= operandNumber;
removeBreakOperand(n);
}
void removeAllBreakOperands()
{
std::vector<int> keys;
for (auto it = CB.breakOperands.begin(); it != CB.breakOperands.end(); it++) {
keys.push_back(it->first);
}
for (auto key : keys) {
removeBreakOperand(key);
}
}
#endif
#ifndef Z80_DISABLE_NESTCHECK
#ifdef Z80_NO_FUNCTIONAL
void addReturnHandler(void (*callback)(void*))
#else
void addReturnHandler(std::function<void(void*)> callback)
#endif
{
CB.returnHandlers.push_back(new SimpleHandler(callback));
}
void removeAllReturnHandlers()
{
for (auto handler : CB.returnHandlers) delete handler;
CB.returnHandlers.clear();
}
#ifdef Z80_NO_FUNCTIONAL
void addCallHandler(void (*callback)(void*))
#else
void addCallHandler(std::function<void(void*)> callback)
#endif
{
CB.callHandlers.push_back(new SimpleHandler(callback));
}
void removeAllCallHandlers()
{
for (auto handler : CB.callHandlers) delete handler;
CB.callHandlers.clear();
}
#endif
#ifdef Z80_NO_FUNCTIONAL
void setConsumeClockCallback(void (*consumeClock_)(void* arg, int clocks))
#else
void setConsumeClockCallback(std::function<void(void* arg, int clocks)> consumeClock_)
#endif
{
CB.consumeClockEnabled = true;
CB.consumeClock = consumeClock_;
}
void resetConsumeClockCallback()
{
CB.consumeClockEnabled = false;
#ifdef Z80_NO_FUNCTIONAL
CB.consumeClock = nullptr;
#endif
}
void requestBreak()
{
requestBreakFlag = true;
}
void generateIRQ(unsigned char vector)
{
reg.interrupt |= 0b01000000;
reg.interruptVector = vector;
}
void cancelIRQ()
{
reg.interrupt &= 0b10111111;
}
void generateNMI(unsigned short addr)
{
reg.interrupt |= 0b10000000;
reg.interruptAddrN = addr;
}
inline unsigned char fetch(int clocks)
{
unsigned char result = readByte(reg.PC, clocks);
reg.PC++;
return result;
}
inline int execute(int clock)
{
int executed = 0;
requestBreakFlag = false;
reg.consumeClockCounter = 0;
while (0 < clock && !requestBreakFlag) {
// execute NOP while halt
if (reg.IFF & IFF_HALT()) {
reg.execEI = 0;
readByte(reg.PC); // NOTE: read and discard (to be consumed 4Hz)
} else {
if (wtc.fetch) consumeClock(wtc.fetch);
#ifndef Z80_DISABLE_BREAKPOINT
checkBreakPoint();
#endif
reg.execEI = 0;
int operandNumber = fetch(2);
updateRefreshRegister();
#ifndef Z80_DISABLE_BREAKPOINT
checkBreakOperand(operandNumber);
#endif
opSet1[operandNumber](this);
}
executed += reg.consumeClockCounter;
clock -= reg.consumeClockCounter;
#ifdef Z80_CALLBACK_PER_INSTRUCTION
checkInterrupt();
#ifdef Z80_CALLBACK_WITHOUT_CHECK
CB.consumeClock(CB.arg, reg.consumeClockCounter);
#else
if (CB.consumeClockEnabled) CB.consumeClock(CB.arg, reg.consumeClockCounter);
#endif
reg.consumeClockCounter = 0;
#else
reg.consumeClockCounter = 0;
checkInterrupt();
#endif
}
return executed;
}
inline void execute()
{
requestBreakFlag = false;
while (!requestBreakFlag) {
#ifdef Z80_CALLBACK_PER_INSTRUCTION
reg.consumeClockCounter = 0;
#endif
// execute NOP while halt
if (reg.IFF & IFF_HALT()) {
reg.execEI = 0;
readByte(reg.PC); // NOTE: read and discard (to be consumed 4Hz)
} else {
#ifndef Z80_DISABLE_BREAKPOINT
checkBreakPoint();
#endif
reg.execEI = 0;
int operandNumber = fetch(2 + wtc.fetch);
updateRefreshRegister();
#ifndef Z80_DISABLE_BREAKPOINT
checkBreakOperand(operandNumber);
#endif
opSet1[operandNumber](this);
}
checkInterrupt();
#ifdef Z80_CALLBACK_PER_INSTRUCTION
#ifdef Z80_CALLBACK_WITHOUT_CHECK
CB.consumeClock(CB.arg, reg.consumeClockCounter);
#else
if (CB.consumeClockEnabled) CB.consumeClock(CB.arg, reg.consumeClockCounter);
#endif
#endif
}
}
int executeTick4MHz()
{
return execute(4194304 / 60);
}
int executeTick8MHz()
{
return execute(8388608 / 60);
}
#ifndef Z80_DISABLE_DEBUG
void registerDump()
{
if (isDebug()) log("===== REGISTER DUMP : START =====");
if (isDebug()) log("PAIR: %s %s %s %s %s %s %s", registerDump(0b111), registerDump(0b000), registerDump(0b001), registerDump(0b010), registerDump(0b011), registerDump(0b100), registerDump(0b101));
if (isDebug()) log("PAIR: F<$%02X> ... S:%s, Z:%s, H:%s, P/V:%s, N:%s, C:%s",
reg.pair.F,
isFlagS() ? "ON" : "OFF",
isFlagZ() ? "ON" : "OFF",
isFlagH() ? "ON" : "OFF",
isFlagPV() ? "ON" : "OFF",
isFlagN() ? "ON" : "OFF",
isFlagC() ? "ON" : "OFF");
if (isDebug()) log("BACK: %s %s %s %s %s %s %s F'<$%02X>", registerDump2(0b111), registerDump2(0b000), registerDump2(0b001), registerDump2(0b010), registerDump2(0b011), registerDump2(0b100), registerDump2(0b101), reg.back.F);
if (isDebug()) log("PC<$%04X> SP<$%04X> IX<$%04X> IY<$%04X>", reg.PC, reg.SP, reg.IX, reg.IY);
if (isDebug()) log("R<$%02X> I<$%02X> IFF<$%02X>", reg.R, reg.I, reg.IFF);
if (isDebug()) log("isHalt: %s, interrupt: $%02X", reg.IFF & IFF_HALT() ? "YES" : "NO", reg.interrupt);
if (isDebug()) log("===== REGISTER DUMP : END =====");
}
#endif
};
#endif // INCLUDE_Z80_HPP