参考
いろいろ注意
- 過去ログを見よ!!!
- end -> @ (not ctrl + z)
- NOP -> NOP_t
mem[0] = 0xAF; // xor a
mem[1] = 0x3C; // inc a
mem[2] = 0x32; mem[3] = 0x32; mem[4] = 0x00; // ld(0x0032) a
mem[5] = 0x76; // halt
AF 3C 32 32 00
結果
=================================
=================================
*[a]ddress input/outupt start address
[i]nput input dump (stop ctrl + z)
[l]ist output dump
*[n]ew reset ram clear
[r]eset run execution (no ram clear) 256step
*[s]ave save eeprom
*[g]et load eeprom
[b]ye exit system
=>i
!!input
input text
AF 3C 32 32 00
[AF 3C 32 32 00]num=5
=================================
=================================
*[a]ddress input/outupt start address
[i]nput input dump (stop ctrl + z)
[l]ist output dump
*[n]ew reset ram clear
[r]eset run execution (no ram clear) 256step
*[s]ave save eeprom
*[g]et load eeprom
[b]ye exit system
=>l
!!list
input binary
add +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0000 AF 3C 32 32 00 00 00 00 00 00 00 00 00 00 00 00
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=================================
=================================
*[a]ddress input/outupt start address
[i]nput input dump (stop ctrl + z)
[l]ist output dump
*[n]ew reset ram clear
[r]eset run execution (no ram clear) 256step
*[s]ave save eeprom
*[g]et load eeprom
[b]ye exit system
=>r
!!run
=================================
=================================
*[a]ddress input/outupt start address
[i]nput input dump (stop ctrl + z)
[l]ist output dump
*[n]ew reset ram clear
[r]eset run execution (no ram clear) 256step
*[s]ave save eeprom
*[g]et load eeprom
[b]ye exit system
=>l
!!list
input binary
add +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0000 AF 3C 32 32 00 00 00 00 00 00 00 00 00 00 00 00
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=================================
=================================
*[a]ddress input/outupt start address
[i]nput input dump (stop ctrl + z)
[l]ist output dump
*[n]ew reset ram clear
[r]eset run execution (no ram clear) 256step
*[s]ave save eeprom
*[g]et load eeprom
[b]ye exit system
=>
プログラム
//Z80_monitor_menu1
//インクルド
#include <Arduino.h>
#include <EEPROM.h>
#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;
}
//定義
char str1[256 + 1] = {0,0,0,0};
//定義 メニュー用
char menu1[] = {"\n"
"=================================\n"
"=================================\n"
"*[a]ddress input/outupt start address\n"
"[i]nput input dump (stop ctrl + z)\n"
"[l]ist output dump\n"
"*[n]ew reset ram clear\n"
"[r]eset run execution (no ram clear) 256step\n"
"*[s]ave save eeprom\n"
"*[g]et load eeprom\n"
"[b]ye exit system\n"
"=>"
};
//char menu1[] = ">"; //debug
//0 1 2 3 4 5 6 7 8 9 A B C D E F
char t[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //00
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, //30
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //50
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //60
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //70
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //80
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //90
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //A0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //B0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //C0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //D0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //E0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 //F0
};
int dump_in(unsigned char *p, unsigned char *d) {
// Your code here!
int i = 0; //カウンター 入力文字
int l = 0; //カウンター 出力バイナリ
int a; //一時領域
int g; //一時領域
while (1) { //無限ループ
//読み飛ばし
//構造化プログラミング先読み
a = p[i]; //読み出し
while ((t[a] == 0) && (a != '0') && (a != 0)) {
i++;
a = p[i]; //読み出し
} //while
if (a == 0) break; //終端文字の時は、ループを抜ける
//-------------------------------------
//16進の間
//構造化プログラミング先読み
a = p[i]; //読み出し
g = 0;
while ( ((t[a] != 0) || (a == '0')) && (a != 0)) {
g = (g << 4) + t[a];
i++;
a = p[i]; //読み出し
} //while
d[l] = g;
l++;
if (a == 0) break; //終端文字の時は、ループを抜ける
} //while 0
return (l);
} //dump_in
void dump_out(unsigned char *dump1, int num) {
// Your code here!
char *b = "0123456789ABCDEF"; //16進の変換テーブル
int k = 0; //アドレスのカウンター
//ヘッターの表示
Serial.println("add +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F");
if (num == 0) return;
for (int i = 0; i < (((num - 1) / 16) + 1); i++) { //行のループ
//アドレスの表示
Serial.print(b[k >> 12 ]); //上位4ビットを表示
Serial.print(b[k >> 8 & 0x0f]); //12ビット目から4ビット
Serial.print(b[k >> 4 & 0x0f]); //8ビット目から4ビット
Serial.print(b[k & 0x0f]); //下位4ビットを表示
Serial.print(' ');
for (int j = 0; j < 16; j++) { //列のループ
//データの表示
int a = dump1[k++];
Serial.print(b[a >> 4 ]); //上位4ビットを表示
Serial.print(b[a & 0x0f]); //下位4ビットを表示
Serial.print(' ');
} //for j
Serial.println(); //改行
} //for i
} //dump_out
//初期化
void setup() {
//シリアルポートの初期化
Serial.begin(9600);
Serial.print(menu1); //メニューの表示
} //setup
MMU mmu;
Z80 z80(readByte, writeByte, inPort, outPort, &mmu);
//メインループ
void loop() {
if (Serial.available() > 0) { // 受信したデータが存在する
char ch1 = Serial.read(); // 受信データを読み込む
Serial.println(ch1); // 受信データを送りかえす
if (ch1 == 'a') { //add
Serial.println("!!add"); //debug
} else if (ch1 == 'i') { //input
Serial.println("!!input"); //debug
Serial.println();
Serial.println("input text"); //debug
int i = 0;
while (1) { //無限ループ
if (Serial.available() > 0) { // 受信したデータが存在する
char ch = Serial.read(); // 受信データを読み込む
//if (ch == 26) { //STOP
if (ch == '@') { //STOP
str1[i] = 0;
break;
}
str1[i++] = ch;
Serial.print(ch); // 受信データを送りかえす
} //endif
} //while
//16進テキストをバイナリーに変換
//unsigned char p[]="01-02-0A";
Serial.println(); //debug
Serial.print('['); //debug
Serial.print(str1); //gebug
Serial.print(']'); //debug
int num = dump_in((unsigned char *)str1,mmu.RAM);
Serial.print("num="); //gebug
Serial.print(num); //gebug
Serial.println(); //debug
} else if (ch1 == 'l') { //list
Serial.println("!!list"); //debug
Serial.println();
Serial.println("input binary"); //debug
dump_out( mmu.RAM ,256);
} else if (ch1 == 'n') { //new
Serial.println("!!new"); //debug
str1[0] = 0; //文字列の初期化(クリアー)
} else if (ch1 == 'r') { //run
Serial.println("!!run"); //debug
// when executing about 1234Hz
int actualExecuteClocks = z80.execute(256);
} else if (ch1 == 's') { //save
Serial.println("!!save"); //debug
int i = 0;
while (str1[i] != 0) {
EEPROM.write(i, str1[i]); //EEPROMへの書き込み
i++;
} //while
EEPROM.write(i, 0); //EEPROMへの書き込み
} else if (ch1 == 'g') { // get
Serial.println("!!load"); //debug
char ch;
int i = 0;
do {
ch = EEPROM.read(i); //EEPROMからの読み込み
//ch = 0; //debug
str1[i] = ch;
i++;
} while (ch != 0); //while
} else if (ch1 == 'b') { //bye
Serial.println("!!bye"); //debug
while (1) {}; //無限ループ
} //endif
Serial.print(menu1); //メニューの表示
} //endif
} //loop
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_t(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_t, 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