#pragma once #include #include "IntelProcessor.h" #include "InputOutput.h" #include "Signal.h" namespace EightBit { class Z80 : public IntelProcessor { public: enum StatusBits { SF = Bit7, ZF = Bit6, YF = Bit5, HC = Bit4, XF = Bit3, PF = Bit2, VF = Bit2, NF = Bit1, CF = Bit0, }; Z80(Memory& memory, InputOutput& ports); Signal ExecutingInstruction; void di(); void ei(); 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); int execute(uint8_t opcode); int step(); bool getM1() const { return m1; } // Mutable access to processor!! register16_t& AF() { return m_accumulatorFlags[m_accumulatorFlagsSet]; } uint8_t& A() { return AF().high; } uint8_t& F() { return AF().low; } register16_t& BC() { return m_registers[m_registerSet][BC_IDX]; } uint8_t& B() { return BC().high; } uint8_t& C() { return BC().low; } register16_t& DE() { return m_registers[m_registerSet][DE_IDX]; } uint8_t& D() { return DE().high; } uint8_t& E() { return DE().low; } register16_t& HL() { return m_registers[m_registerSet][HL_IDX]; } uint8_t& H() { return HL().high; } uint8_t& L() { return HL().low; } 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; } uint8_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(); virtual void initialise(); protected: InputOutput& m_ports; enum { BC_IDX, DE_IDX, HL_IDX }; std::array, 2> m_registers; int m_registerSet; std::array m_accumulatorFlags; int m_accumulatorFlagsSet; register16_t m_ix; register16_t m_iy; uint8_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; int fetchExecute() { M1() = true; return execute(fetchByte()); } void incrementRefresh() { auto incremented = ((REFRESH() & Mask7) + 1) & Mask7; REFRESH() = (REFRESH() & Bit7) | incremented; } void clearFlag(int flag) { F() &= ~flag; } void setFlag(int flag) { F() |= flag; } void setFlag(int flag, int condition) { setFlag(flag, condition != 0); } void setFlag(int flag, uint32_t condition) { setFlag(flag, condition != 0); } void setFlag(int flag, bool condition) { condition ? setFlag(flag) : clearFlag(flag); } void clearFlag(int flag, int condition) { clearFlag(flag, condition != 0); } void clearFlag(int flag, uint32_t condition) { clearFlag(flag, condition != 0); } void clearFlag(int flag, bool condition) { condition ? clearFlag(flag) : setFlag(flag); } uint8_t& DISPLACED() { if (!(m_prefixDD || m_prefixFD)) throw std::logic_error("Unprefixed indexed displacement requested"); m_memory.ADDRESS().word = MEMPTR().word = (m_prefixDD ? IX() : IY()).word + m_displacement; return m_memory.reference(); } uint8_t& R(int r) { switch (r) { case 0: return B(); case 1: return C(); case 2: return D(); case 3: return E(); case 4: return ALT_HL().high; case 5: return ALT_HL().low; case 6: if (m_prefixDD || m_prefixFD) { m_displacement = fetchByte(); return DISPLACED(); } m_memory.ADDRESS() = HL(); return m_memory.reference(); case 7: return A(); } throw std::logic_error("Unhandled registry mechanism"); } uint8_t& R2(int r) { 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: m_memory.ADDRESS() = HL(); return m_memory.reference(); case 7: return A(); } throw std::logic_error("Unhandled registry mechanism"); } register16_t& RP(int rp) { switch (rp) { case 3: return sp; case HL_IDX: return ALT_HL(); default: return m_registers[m_registerSet][rp]; } } register16_t& ALT_HL() { if (m_prefixDD) return IX(); else if (m_prefixFD) return IY(); return HL(); } register16_t& RP2(int rp) { switch (rp) { case 3: return AF(); case HL_IDX: return ALT_HL(); default: return m_registers[m_registerSet][rp]; } } void addViaMemptr(register16_t& hl, register16_t operand) { MEMPTR().word = hl.word + 1; add(hl, operand); } void sbcViaMemptr(register16_t& hl, register16_t operand) { MEMPTR().word = hl.word + 1; sbc(hl, operand); } void adcViaMemptr(register16_t& hl, register16_t operand) { MEMPTR().word = hl.word + 1; adc(hl, operand); } void adjustHalfCarryAdd(uint8_t before, uint8_t value, int calculation) { setFlag(HC, calculateHalfCarryAdd(before, value, calculation)); } void adjustHalfCarrySub(uint8_t before, uint8_t value, int calculation) { setFlag(HC, calculateHalfCarrySub(before, value, calculation)); } void adjustOverflowAdd(uint8_t before, uint8_t value, uint8_t calculation) { adjustOverflowAdd(before & SF, value & SF, calculation & SF); } void adjustOverflowAdd(int beforeNegative, int valueNegative, int afterNegative) { auto overflow = (beforeNegative == valueNegative) && (beforeNegative != afterNegative); setFlag(VF, overflow); } void adjustOverflowSub(uint8_t before, uint8_t value, uint8_t calculation) { adjustOverflowSub(before & SF, value & SF, calculation & SF); } void adjustOverflowSub(int beforeNegative, int valueNegative, int afterNegative) { auto overflow = (beforeNegative != valueNegative) && (beforeNegative != afterNegative); setFlag(VF, overflow); } void executeCB(int x, int y, int z, int p, int q); void executeED(int x, int y, int z, int p, int q); void executeOther(int x, int y, int z, int p, int q); void adjustSign(uint8_t value); void adjustZero(uint8_t value); void adjustParity(uint8_t value); void adjustSZ(uint8_t value); void adjustSZP(uint8_t value); void adjustXY(uint8_t value); void adjustSZPXY(uint8_t value); void adjustSZXY(uint8_t value); void postIncrement(uint8_t value); void postDecrement(uint8_t value); void retn(); void reti(); bool jrConditionalFlag(int flag); bool returnConditionalFlag(int flag); bool jumpConditionalFlag(int flag); bool callConditionalFlag(int flag); void sbc(register16_t& operand, register16_t value); void adc(register16_t& operand, register16_t value); void add(register16_t& operand, register16_t value); void add(uint8_t& operand, uint8_t value, int carry = 0); void adc(uint8_t& operand, uint8_t value); void sub(uint8_t& operand, uint8_t value, int carry = 0); void sbc(uint8_t& operand, uint8_t value); void andr(uint8_t& operand, uint8_t value); void xorr(uint8_t& operand, uint8_t value); void orr(uint8_t& operand, uint8_t value); void compare(uint8_t value); void rlca(); void rrca(); void rla(); void rra(); void rlc(uint8_t& operand); void rrc(uint8_t& operand); void rl(uint8_t& operand); void rr(uint8_t& operand); void sla(uint8_t& operand); void sra(uint8_t& operand); void sll(uint8_t& operand); void srl(uint8_t& operand); void bit(int n, uint8_t& operand); void res(int n, uint8_t& operand); void set(int nit, uint8_t& operand); void daa(); void scf(); void ccf(); void cpl(); void xhtl(register16_t& operand); void xhtl(); void blockCompare(); void cpi(); bool cpir(); void cpd(); bool cpdr(); void blockLoad(register16_t source, register16_t destination); void ldi(); bool ldir(); void ldd(); bool lddr(); void ini(); bool inir(); void ind(); bool indr(); void blockOut(); void outi(); bool otir(); void outd(); bool otdr(); void neg(); void rrd(); void rld(); void writePort() { m_ports.write(m_memory.ADDRESS().low, m_memory.DATA()); } void readPort() { m_memory.placeDATA(m_ports.read(m_memory.ADDRESS().low)); } }; }