EightBit/Z80/inc/Z80.h
Adrian.Conlon cae34d61d1 Ensure the Z80 unit tests run successfully to completion.
Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
2017-09-07 01:04:09 +01:00

412 lines
9.0 KiB
C++

#pragma once
#include <cstdint>
#include <cassert>
#include "IntelProcessor.h"
#include "InputOutput.h"
#include "Signal.h"
namespace EightBit {
class Z80 : public IntelProcessor {
public:
struct refresh_t {
bool high : 1;
uint8_t variable : 7;
refresh_t(uint8_t value)
: high((value & Bit7) != 0),
variable(value & Mask7)
{ }
operator uint8_t() const {
return (high << 7) | variable;
}
refresh_t& operator++() {
++variable;
return *this;
}
};
enum StatusBits {
SF = Bit7,
ZF = Bit6,
YF = Bit5,
HC = Bit4,
XF = Bit3,
PF = Bit2,
VF = Bit2,
NF = Bit1,
CF = Bit0,
};
Z80(Bus& bus, InputOutput& ports);
Signal<Z80> ExecutingInstruction;
int interruptMaskable(uint8_t value) { return interrupt(true, value); }
int interruptMaskable() { return interruptMaskable(0); }
int interruptNonMaskable() { return interrupt(false, 0); }
int interrupt(bool maskable, uint8_t value);
virtual int execute(uint8_t opcode);
int step();
virtual register16_t& AF() override {
return m_accumulatorFlags[m_accumulatorFlagsSet];
}
virtual register16_t& BC() override {
return m_registers[m_registerSet][BC_IDX];
}
virtual register16_t& DE() override {
return m_registers[m_registerSet][DE_IDX];
}
virtual register16_t& HL() override {
return m_registers[m_registerSet][HL_IDX];
}
register16_t& IX() { return m_ix; }
uint8_t& IXH() { return IX().high; }
uint8_t& IXL() { return IX().low; }
register16_t& IY() { return m_iy; }
uint8_t& IYH() { return IY().high; }
uint8_t& IYL() { return IY().low; }
refresh_t& REFRESH() { return m_refresh; }
uint8_t& IV() { return iv; }
int& IM() { return m_interruptMode; }
bool& IFF1() { return m_iff1; }
bool& IFF2() { return m_iff2; }
bool& M1() { return m1; }
void exx() {
m_registerSet ^= 1;
}
void exxAF() {
m_accumulatorFlagsSet = !m_accumulatorFlagsSet;
}
virtual void reset() override;
protected:
virtual int fetchExecute() override {
M1() = true;
return IntelProcessor::fetchExecute();
}
private:
InputOutput& m_ports;
enum { BC_IDX, DE_IDX, HL_IDX };
std::array<std::array<register16_t, 3>, 2> m_registers;
int m_registerSet;
std::array<register16_t, 2> m_accumulatorFlags;
int m_accumulatorFlagsSet;
register16_t m_ix;
register16_t m_iy;
refresh_t m_refresh;
uint8_t iv;
int m_interruptMode;
bool m_iff1;
bool m_iff2;
bool m1;
bool m_prefixCB;
bool m_prefixDD;
bool m_prefixED;
bool m_prefixFD;
int8_t m_displacement;
bool m_displaced;
uint16_t displacedAddress() {
assert(m_displaced);
return MEMPTR().word = (m_prefixDD ? IX() : IY()).word + m_displacement;
}
void fetchDisplacement() {
m_displacement = fetchByte();
}
uint8_t R(int r, uint8_t a) {
switch (r) {
case 0:
return B();
case 1:
return C();
case 2:
return D();
case 3:
return E();
case 4:
return HL2().high;
case 5:
return HL2().low;
case 6:
return getByte(m_displaced ? displacedAddress() : HL().word);
case 7:
return a;
default:
__assume(0);
}
throw std::logic_error("Unhandled registry mechanism");
}
void R(int r, uint8_t& a, uint8_t value) {
switch (r) {
case 0:
B() = value;
break;
case 1:
C() = value;
break;
case 2:
D() = value;
break;
case 3:
E() = value;
break;
case 4:
HL2().high = value;
break;
case 5:
HL2().low = value;
break;
case 6:
setByte(m_displaced ? displacedAddress() : HL().word, value);
break;
case 7:
a = value;
break;
default:
__assume(0);
}
}
uint8_t R2(int r, const uint8_t& a) {
switch (r) {
case 0:
return B();
case 1:
return C();
case 2:
return D();
case 3:
return E();
case 4:
return H();
case 5:
return L();
case 6:
return getByte(HL());
case 7:
return a;
default:
__assume(0);
}
throw std::logic_error("Unhandled registry mechanism");
}
void R2(int r, uint8_t& a, uint8_t value) {
switch (r) {
case 0:
B() = value;
break;
case 1:
C() = value;
break;
case 2:
D() = value;
break;
case 3:
E() = value;
break;
case 4:
H() = value;
break;
case 5:
L() = value;
break;
case 6:
setByte(HL(), value);
break;
case 7:
a = value;
break;
default:
__assume(0);
}
}
register16_t& RP(int rp) {
__assume(rp < 4);
__assume(rp >= 0);
switch (rp) {
case 3:
return SP();
case HL_IDX:
return HL2();
default:
return m_registers[m_registerSet][rp];
}
}
register16_t& HL2() {
if (!m_displaced)
return HL();
if (m_prefixDD)
return IX();
// Must be FD prefix
return IY();
}
register16_t& RP2(int rp) {
__assume(rp < 4);
__assume(rp >= 0);
switch (rp) {
case 3:
return AF();
case HL_IDX:
return HL2();
default:
return m_registers[m_registerSet][rp];
}
}
static void adjustHalfCarryAdd(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
setFlag(f, HC, calculateHalfCarryAdd(before, value, calculation));
}
static void adjustHalfCarrySub(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
setFlag(f, HC, calculateHalfCarrySub(before, value, calculation));
}
static void adjustOverflowAdd(uint8_t& f, uint8_t before, uint8_t value, uint8_t calculation) {
adjustOverflowAdd(f, before & SF, value & SF, calculation & SF);
}
static void adjustOverflowAdd(uint8_t& f, int beforeNegative, int valueNegative, int afterNegative) {
auto overflow = (beforeNegative == valueNegative) && (beforeNegative != afterNegative);
setFlag(f, VF, overflow);
}
static void adjustOverflowSub(uint8_t& f, uint8_t before, uint8_t value, uint8_t calculation) {
adjustOverflowSub(f, before & SF, value & SF, calculation & SF);
}
static void adjustOverflowSub(uint8_t& f, int beforeNegative, int valueNegative, int afterNegative) {
auto overflow = (beforeNegative != valueNegative) && (beforeNegative != afterNegative);
setFlag(f, VF, overflow);
}
static void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0);
void executeCB(int x, int y, int z);
void executeED(int x, int y, int z, int p, int q);
void executeOther(int x, int y, int z, int p, int q);
static void increment(uint8_t& f, uint8_t& operand);
static void decrement(uint8_t& f, uint8_t& operand);
void di();
void ei();
void retn();
void reti();
bool jrConditionalFlag(uint8_t& f, int flag);
bool returnConditionalFlag(uint8_t& f, int flag);
bool jumpConditionalFlag(uint8_t& f, int flag);
bool callConditionalFlag(uint8_t& f, int flag);
void sbc(uint8_t& f, register16_t& operand, register16_t value);
void adc(uint8_t& f, register16_t& operand, register16_t value);
void add(uint8_t& f, register16_t& operand, register16_t value);
static void add(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0);
static void adc(uint8_t& f, uint8_t& operand, uint8_t value);
static void sub(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0);
static void sbc(uint8_t& f, uint8_t& operand, uint8_t value);
static void andr(uint8_t& f, uint8_t& operand, uint8_t value);
static void xorr(uint8_t& f, uint8_t& operand, uint8_t value);
static void orr(uint8_t& f, uint8_t& operand, uint8_t value);
static void compare(uint8_t& f, uint8_t check, uint8_t value);
static uint8_t rlc(uint8_t& f, uint8_t operand);
static uint8_t rrc(uint8_t& f, uint8_t operand);
static uint8_t rl(uint8_t& f, uint8_t operand);
static uint8_t rr(uint8_t& f, uint8_t operand);
static uint8_t sla(uint8_t& f, uint8_t operand);
static uint8_t sra(uint8_t& f, uint8_t operand);
static uint8_t sll(uint8_t& f, uint8_t operand);
static uint8_t srl(uint8_t& f, uint8_t operand);
static uint8_t bit(uint8_t& f, int n, uint8_t operand);
static uint8_t res(int n, uint8_t operand);
static uint8_t set(int n, uint8_t operand);
static void daa(uint8_t& a, uint8_t& f);
static void scf(uint8_t a, uint8_t& f);
static void ccf(uint8_t a, uint8_t& f);
static void cpl(uint8_t& a, uint8_t& f);
void xhtl(register16_t& operand);
void blockCompare(uint8_t a, uint8_t& f);
void cpi(uint8_t a, uint8_t& f);
bool cpir(uint8_t a, uint8_t& f);
void cpd(uint8_t a, uint8_t& f);
bool cpdr(uint8_t a, uint8_t& f);
void blockLoad(uint8_t a, uint8_t& f, register16_t source, register16_t destination);
void ldi(uint8_t a, uint8_t& f);
bool ldir(uint8_t a, uint8_t& f);
void ldd(uint8_t a, uint8_t& f);
bool lddr(uint8_t a, uint8_t& f);
void ini(uint8_t& f);
bool inir(uint8_t& f);
void ind(uint8_t& f);
bool indr(uint8_t& f);
void blockOut(uint8_t& f);
void outi(uint8_t& f);
bool otir(uint8_t& f);
void outd(uint8_t& f);
bool otdr(uint8_t& f);
static void neg(uint8_t& a, uint8_t& f);
void rrd(uint8_t& a, uint8_t& f);
void rld(uint8_t& a, uint8_t& f);
void writePort(uint8_t port, uint8_t a);
void writePort();
void readPort(uint8_t port, uint8_t& a);
void readPort();
};
}