diff --git a/EightBit.sln b/EightBit.sln index 0cc0d71..c1f0b64 100644 --- a/EightBit.sln +++ b/EightBit.sln @@ -9,6 +9,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Intel8080", "Intel8080\src\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_Intel8080", "Intel8080\test\test_Intel8080.vcxproj", "{391D3B95-D9DA-47E5-9F61-70483F6BB396}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Z80", "Z80\src\Z80.vcxproj", "{01974F81-2750-45AF-B845-2C903A54A334}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_Z80", "Z80\test\test_Z80.vcxproj", "{F8EE7116-0D75-4C82-BA9E-409F69F5D47C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -41,6 +45,22 @@ Global {391D3B95-D9DA-47E5-9F61-70483F6BB396}.Release|x64.Build.0 = Release|x64 {391D3B95-D9DA-47E5-9F61-70483F6BB396}.Release|x86.ActiveCfg = Release|Win32 {391D3B95-D9DA-47E5-9F61-70483F6BB396}.Release|x86.Build.0 = Release|Win32 + {01974F81-2750-45AF-B845-2C903A54A334}.Debug|x64.ActiveCfg = Debug|x64 + {01974F81-2750-45AF-B845-2C903A54A334}.Debug|x64.Build.0 = Debug|x64 + {01974F81-2750-45AF-B845-2C903A54A334}.Debug|x86.ActiveCfg = Debug|Win32 + {01974F81-2750-45AF-B845-2C903A54A334}.Debug|x86.Build.0 = Debug|Win32 + {01974F81-2750-45AF-B845-2C903A54A334}.Release|x64.ActiveCfg = Release|x64 + {01974F81-2750-45AF-B845-2C903A54A334}.Release|x64.Build.0 = Release|x64 + {01974F81-2750-45AF-B845-2C903A54A334}.Release|x86.ActiveCfg = Release|Win32 + {01974F81-2750-45AF-B845-2C903A54A334}.Release|x86.Build.0 = Release|Win32 + {F8EE7116-0D75-4C82-BA9E-409F69F5D47C}.Debug|x64.ActiveCfg = Debug|x64 + {F8EE7116-0D75-4C82-BA9E-409F69F5D47C}.Debug|x64.Build.0 = Debug|x64 + {F8EE7116-0D75-4C82-BA9E-409F69F5D47C}.Debug|x86.ActiveCfg = Debug|Win32 + {F8EE7116-0D75-4C82-BA9E-409F69F5D47C}.Debug|x86.Build.0 = Debug|Win32 + {F8EE7116-0D75-4C82-BA9E-409F69F5D47C}.Release|x64.ActiveCfg = Release|x64 + {F8EE7116-0D75-4C82-BA9E-409F69F5D47C}.Release|x64.Build.0 = Release|x64 + {F8EE7116-0D75-4C82-BA9E-409F69F5D47C}.Release|x86.ActiveCfg = Release|Win32 + {F8EE7116-0D75-4C82-BA9E-409F69F5D47C}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index d75da2a..104a0a5 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -158,7 +158,7 @@ namespace EightBit { void jmpConditional(int conditional) { auto destination = fetchWord(); if (conditional) - pc.word = destination; + pc = destination; } void callConditional(int condition) { @@ -325,9 +325,9 @@ namespace EightBit { m_memory.set(HL().word, data); } - void lxi_b() { BC().word = fetchWord(); } - void lxi_d() { DE().word = fetchWord(); } - void lxi_h() { HL().word = fetchWord(); } + void lxi_b() { BC() = fetchWord(); } + void lxi_d() { DE() = fetchWord(); } + void lxi_h() { HL() = fetchWord(); } void stax_b() { m_memory.set(BC().word, A()); } void stax_d() { m_memory.set(DE().word, A()); } @@ -337,21 +337,21 @@ namespace EightBit { void sta() { auto destination = fetchWord(); - m_memory.set(destination, A()); + m_memory.set(destination.word, A()); } void lda() { auto source = fetchWord(); - A() = m_memory.get(source); + A() = m_memory.get(source.word); } void shld() { auto destination = fetchWord(); - setWord(destination, HL()); + m_memory.setWord(destination.word, HL()); } void lhld() { - HL() = getWord(fetchWord()); + HL() = m_memory.getWord(fetchWord().word); } void xchg() { @@ -382,8 +382,8 @@ namespace EightBit { } void xhtl() { - auto tos = getWord(sp.word); - setWord(sp.word, HL()); + auto tos = m_memory.getWord(sp.word); + m_memory.setWord(sp.word, HL()); HL() = tos; } @@ -392,7 +392,7 @@ namespace EightBit { } void lxi_sp() { - sp.word = fetchWord(); + sp = fetchWord(); } void inx_sp() { ++sp.word; } @@ -421,7 +421,7 @@ namespace EightBit { // call void call() { - auto destination = getWord(pc.word); + auto destination = m_memory.getWord(pc.word); callAddress(destination.word); } diff --git a/Intel8080/src/Disassembler.cpp b/Intel8080/src/Disassembler.cpp index d0b3bc2..186c946 100644 --- a/Intel8080/src/Disassembler.cpp +++ b/Intel8080/src/Disassembler.cpp @@ -78,7 +78,7 @@ std::string EightBit::Disassembler::disassemble(Intel8080& cpu) { output << hex(memory.peek(pc.word + 1)); break; case Intel8080::Absolute: - output << hex(cpu.getWord(pc.word + 1).word); + output << hex(memory.peekWord(pc.word + 1)); break; default: break; diff --git a/Z80/inc/Disassembler.h b/Z80/inc/Disassembler.h index a007704..516b165 100644 --- a/Z80/inc/Disassembler.h +++ b/Z80/inc/Disassembler.h @@ -3,63 +3,66 @@ #include #include -class Z80; +namespace EightBit { -class Disassembler { -public: - Disassembler(); + class Z80; - static std::string state(Z80& cpu); - std::string disassemble(const Z80& cpu); + class Disassembler { + public: + Disassembler(); - static std::string flag(uint8_t value, int flag, const std::string& represents); - static std::string flags(uint8_t value); - static std::string hex(uint8_t value); - static std::string hex(uint16_t value); - static std::string binary(uint8_t value); - static std::string decimal(uint8_t value); + static std::string state(Z80& cpu); + std::string disassemble(const Z80& cpu); - static std::string invalid(uint8_t value); + static std::string flag(uint8_t value, int flag, const std::string& represents); + static std::string flags(uint8_t value); + static std::string hex(uint8_t value); + static std::string hex(uint16_t value); + static std::string binary(uint8_t value); + static std::string decimal(uint8_t value); -private: - mutable boost::format m_formatter; - bool m_prefixCB; - bool m_prefixDD; - bool m_prefixED; - bool m_prefixFD; + static std::string invalid(uint8_t value); - void disassemble(std::ostringstream& output, const Z80& cpu, uint16_t pc); + private: + mutable boost::format m_formatter; + bool m_prefixCB; + bool m_prefixDD; + bool m_prefixED; + bool m_prefixFD; - void disassembleCB( - std::ostringstream& output, - const Z80& cpu, - uint16_t pc, - std::string& specification, - int& dumpCount, - int x, int y, int z, - int p, int q); + void disassemble(std::ostringstream& output, const Z80& cpu, uint16_t pc); - void disassembleED( - std::ostringstream& output, - const Z80& cpu, - uint16_t pc, - std::string& specification, - int& dumpCount, - int x, int y, int z, - int p, int q); + void disassembleCB( + std::ostringstream& output, + const Z80& cpu, + uint16_t pc, + std::string& specification, + int& dumpCount, + int x, int y, int z, + int p, int q); - void disassembleOther( - std::ostringstream& output, - const Z80& cpu, - uint16_t pc, - std::string& specification, - int& dumpCount, - int x, int y, int z, - int p, int q); + void disassembleED( + std::ostringstream& output, + const Z80& cpu, + uint16_t pc, + std::string& specification, + int& dumpCount, + int x, int y, int z, + int p, int q); - std::string RP(int rp) const; - std::string RP2(int rp) const; - std::string R(int r) const; - static std::string cc(int flag); - static std::string alu(int which); -}; + void disassembleOther( + std::ostringstream& output, + const Z80& cpu, + uint16_t pc, + std::string& specification, + int& dumpCount, + int x, int y, int z, + int p, int q); + + std::string RP(int rp) const; + std::string RP2(int rp) const; + std::string R(int r) const; + static std::string cc(int flag); + static std::string alu(int which); + }; +} \ No newline at end of file diff --git a/Z80/inc/InputOutput.h b/Z80/inc/InputOutput.h index bfc538f..c51eda6 100644 --- a/Z80/inc/InputOutput.h +++ b/Z80/inc/InputOutput.h @@ -4,33 +4,35 @@ #include "Signal.h" #include "PortEventArgs.h" -class InputOutput { -public: - InputOutput(); +namespace EightBit { + class InputOutput { + public: + InputOutput(); - uint8_t read(uint8_t port) { return readInputPort(port); } - void write(uint8_t port, uint8_t value) { return writeOutputPort(port, value); } + uint8_t read(uint8_t port) { return readInputPort(port); } + void write(uint8_t port, uint8_t value) { return writeOutputPort(port, value); } - uint8_t readInputPort(uint8_t port); - void writeInputPort(uint8_t port, uint8_t value) { input[port] = value; } + uint8_t readInputPort(uint8_t port); + void writeInputPort(uint8_t port, uint8_t value) { input[port] = value; } - uint8_t readOutputPort(uint8_t port) { return output[port]; } - void writeOutputPort(uint8_t port, uint8_t value); + uint8_t readOutputPort(uint8_t port) { return output[port]; } + void writeOutputPort(uint8_t port, uint8_t value); - Signal ReadingPort; - Signal ReadPort; + Signal ReadingPort; + Signal ReadPort; - Signal WritingPort; - Signal WrittenPort; + Signal WritingPort; + Signal WrittenPort; -protected: - void OnReadingPort(uint8_t port); - void OnReadPort(uint8_t port); + protected: + void OnReadingPort(uint8_t port); + void OnReadPort(uint8_t port); - void OnWritingPort(uint8_t port); - void OnWrittenPort(uint8_t port); + void OnWritingPort(uint8_t port); + void OnWrittenPort(uint8_t port); -private: - std::array input; - std::array output; -}; + private: + std::array input; + std::array output; + }; +} \ No newline at end of file diff --git a/Z80/inc/PortEventArgs.h b/Z80/inc/PortEventArgs.h index ea4c49b..3455770 100644 --- a/Z80/inc/PortEventArgs.h +++ b/Z80/inc/PortEventArgs.h @@ -2,15 +2,17 @@ #include -class PortEventArgs { -public: - PortEventArgs(uint8_t port) - : m_port(port) {} +namespace EightBit { + class PortEventArgs { + public: + PortEventArgs(uint8_t port) + : m_port(port) {} - uint8_t getPort() const { - return m_port; - } + uint8_t getPort() const { + return m_port; + } -private: - uint8_t m_port; -}; + private: + uint8_t m_port; + }; +} \ No newline at end of file diff --git a/Z80/inc/Profiler.h b/Z80/inc/Profiler.h index c833b80..90a4986 100644 --- a/Z80/inc/Profiler.h +++ b/Z80/inc/Profiler.h @@ -3,21 +3,22 @@ #include #include -class Profiler { -public: - Profiler(); - ~Profiler(); +namespace EightBit { + class Profiler { + public: + Profiler(); + ~Profiler(); - void addInstruction(uint8_t instruction); - void addAddress(uint16_t address); + void addInstruction(uint8_t instruction); + void addAddress(uint16_t address); - void dump() const; + void dump() const; -private: - std::array m_instructions; - std::array m_addresses; - - void dumpInstructionProfiles() const; - void dumpAddressProfiles() const; -}; + private: + std::array m_instructions; + std::array m_addresses; + void dumpInstructionProfiles() const; + void dumpAddressProfiles() const; + }; +} \ No newline at end of file diff --git a/Z80/inc/Z80.h b/Z80/inc/Z80.h index 8fe63d8..c3d6c2f 100644 --- a/Z80/inc/Z80.h +++ b/Z80/inc/Z80.h @@ -1,449 +1,456 @@ #pragma once +#include + #include "Processor.h" +#include "InputOutput.h" -class Z80 : public Processor { -public: - enum StatusBits { - SF = Bit7, - ZF = Bit6, - YF = Bit5, - HC = Bit4, - XF = Bit3, - PF = Bit2, - VF = Bit2, - NF = Bit1, - CF = Bit0, - }; +namespace EightBit { + class Z80 : public Processor { + 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); + Z80(Memory& memory, InputOutput& ports); - Signal ExecutingInstruction; + Signal ExecutingInstruction; - void disableInterrupts(); - void enableInterrupts(); + void disableInterrupts(); + void enableInterrupts(); - int interruptMaskable(uint8_t value) { return interrupt(true, value); } - int interruptMaskable() { return interruptMaskable(0); } - int interruptNonMaskable() { return interrupt(false, 0); } + 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 interrupt(bool maskable, uint8_t value); - int execute(uint8_t opcode); - int step(); + int execute(uint8_t opcode); + int step(); - bool getM1() const { return m1; } + bool getM1() const { return m1; } - // Mutable access to processor!! + // Mutable access to processor!! - register16_t& AF() { - return m_accumulatorFlags[m_accumulatorFlagsSet]; - } + register16_t& AF() { + return m_accumulatorFlags[m_accumulatorFlagsSet]; + } - uint8_t& A() { return AF().high; } - uint8_t& F() { return AF().low; } + uint8_t& A() { return AF().high; } + uint8_t& F() { return AF().low; } - register16_t& BC() { - return m_registers[m_registerSet][BC_IDX]; - } + register16_t& BC() { + return m_registers[m_registerSet][BC_IDX]; + } - uint8_t& B() { return BC().high; } - uint8_t& C() { return BC().low; } + uint8_t& B() { return BC().high; } + uint8_t& C() { return BC().low; } - register16_t& DE() { - return m_registers[m_registerSet][DE_IDX]; - } + register16_t& DE() { + return m_registers[m_registerSet][DE_IDX]; + } - uint8_t& D() { return DE().high; } - uint8_t& E() { return DE().low; } + uint8_t& D() { return DE().high; } + uint8_t& E() { return DE().low; } - register16_t& HL() { - return m_registers[m_registerSet][HL_IDX]; - } + register16_t& HL() { + return m_registers[m_registerSet][HL_IDX]; + } - uint8_t& H() { return HL().high; } - uint8_t& L() { return HL().low; } + 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& 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; } + 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; } + 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; } - register16_t& MEMPTR() { return m_memptr; } + register16_t& MEMPTR() { return m_memptr; } - bool& M1() { return m1; } + bool& M1() { return m1; } - void exx() { - m_registerSet ^= 1; - } + void exx() { + m_registerSet ^= 1; + } - void exxAF() { - m_accumulatorFlagsSet = !m_accumulatorFlagsSet; - } + void exxAF() { + m_accumulatorFlagsSet = !m_accumulatorFlagsSet; + } - virtual void reset(); - virtual void initialise(); + virtual void reset(); + virtual void initialise(); -private: - enum { BC_IDX, DE_IDX, HL_IDX }; + private: + InputOutput& m_ports; - std::array, 2> m_registers; - int m_registerSet; + enum { BC_IDX, DE_IDX, HL_IDX }; - std::array m_accumulatorFlags; - int m_accumulatorFlagsSet; + std::array, 2> m_registers; + int m_registerSet; - register16_t m_ix; - register16_t m_iy; + std::array m_accumulatorFlags; + int m_accumulatorFlagsSet; - uint8_t m_refresh; - uint8_t iv; - int m_interruptMode; - bool m_iff1; - bool m_iff2; + register16_t m_ix; + register16_t m_iy; - register16_t m_memptr; + uint8_t m_refresh; + uint8_t iv; + int m_interruptMode; + bool m_iff1; + bool m_iff2; - bool m1; + register16_t m_memptr; - bool m_prefixCB; - bool m_prefixDD; - bool m_prefixED; - bool m_prefixFD; + bool m1; - int8_t m_displacement; + bool m_prefixCB; + bool m_prefixDD; + bool m_prefixED; + bool m_prefixFD; - std::array m_halfCarryTableAdd = { { false, false, true, false, true, false, true, true } }; - std::array m_halfCarryTableSub = { { false, true, true, true, false, false, false, true } }; + int8_t m_displacement; - int fetchExecute() { - M1() = true; - return execute(fetchByteExecute()); - } + std::array m_halfCarryTableAdd = { { false, false, true, false, true, false, true, true } }; + std::array m_halfCarryTableSub = { { false, true, true, true, false, false, false, true } }; - uint8_t fetchByteExecute() { - if (!getM1()) - throw std::logic_error("M1 cannot be high"); - return fetchByte(); - } + int fetchExecute() { + M1() = true; + return execute(fetchByteExecute()); + } - uint8_t fetchByteData() { - if (getM1()) - throw std::logic_error("M1 cannot be low"); - return fetchByte(); - } + uint8_t fetchByteExecute() { + if (!getM1()) + throw std::logic_error("M1 cannot be high"); + return fetchByte(); + } - void incrementRefresh() { - auto incremented = ((REFRESH() & Mask7) + 1) & Mask7; - REFRESH() = (REFRESH() & Bit7) | incremented; - } + uint8_t fetchByteData() { + if (getM1()) + throw std::logic_error("M1 cannot be low"); + return fetchByte(); + } - void clearFlag(int flag) { F() &= ~flag; } - void setFlag(int flag) { F() |= flag; } + void incrementRefresh() { + auto incremented = ((REFRESH() & Mask7) + 1) & Mask7; + REFRESH() = (REFRESH() & Bit7) | incremented; + } - 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) { F() &= ~flag; } + void setFlag(int flag) { F() |= 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); } + 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); } - 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(); - } + 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& 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 = fetchByteData(); - return DISPLACED(); + 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 = fetchByteData(); + return DISPLACED(); + } + m_memory.ADDRESS() = HL(); + return m_memory.reference(); + case 7: + return A(); } - m_memory.ADDRESS() = HL(); + 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]; + } + } + + uint8_t getViaMemptr(register16_t address) { + m_memory.ADDRESS() = address; + MEMPTR().word = address.word + 1; 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(); + void setViaMemptr(register16_t address, uint8_t value) { + m_memory.ADDRESS() = address; + m_memory.reference() = value; + ++address.word; + MEMPTR().low = address.low; + MEMPTR().high = value; } - 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 getWordViaMemptr(register16_t address) { + register16_t returned; + m_memory.ADDRESS() = address; + returned.low = m_memory.reference(); + m_memory.ADDRESS().word++; + returned.high = m_memory.reference(); + MEMPTR() = m_memory.ADDRESS(); + return returned; } - } - 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 setWordViaMemptr(register16_t address, register16_t value) { + m_memory.ADDRESS() = address; + m_memory.reference() = value.low; + m_memory.ADDRESS().word++; + m_memory.reference() = value.high; + MEMPTR() = m_memory.ADDRESS(); } - } - uint8_t getViaMemptr(register16_t address) { - m_memory.ADDRESS() = address; - MEMPTR().word = address.word + 1; - return m_memory.reference(); - } + void setPcViaMemptr(register16_t address) { + MEMPTR() = pc = address; + } - void setViaMemptr(register16_t address, uint8_t value) { - m_memory.ADDRESS() = address; - m_memory.reference() = value; - ++address.word; - MEMPTR().low = address.low; - MEMPTR().high = value; - } + void addViaMemptr(register16_t& hl, register16_t operand) { + MEMPTR().word = hl.word + 1; + add(hl, operand); + } - register16_t getWordViaMemptr(register16_t address) { - register16_t returned; - m_memory.ADDRESS() = address; - returned.low = m_memory.reference(); - m_memory.ADDRESS().word++; - returned.high = m_memory.reference(); - MEMPTR() = m_memory.ADDRESS(); - return returned; - } + void sbcViaMemptr(register16_t& hl, register16_t operand) { + MEMPTR().word = hl.word + 1; + sbc(hl, operand); + } - void setWordViaMemptr(register16_t address, register16_t value) { - m_memory.ADDRESS() = address; - m_memory.reference() = value.low; - m_memory.ADDRESS().word++; - m_memory.reference() = value.high; - MEMPTR() = m_memory.ADDRESS(); - } + void adcViaMemptr(register16_t& hl, register16_t operand) { + MEMPTR().word = hl.word + 1; + adc(hl, operand); + } - void setPcViaMemptr(register16_t address) { - MEMPTR() = pc = address; - } + int buildHalfCarryIndex(uint8_t before, uint8_t value, int calculation) { + return ((before & 0x88) >> 1) | ((value & 0x88) >> 2) | ((calculation & 0x88) >> 3); + } - void addViaMemptr(register16_t& hl, register16_t operand) { - MEMPTR().word = hl.word + 1; - add(hl, operand); - } + void adjustHalfCarryAdd(uint8_t before, uint8_t value, int calculation) { + auto index = buildHalfCarryIndex(before, value, calculation); + setFlag(HC, m_halfCarryTableAdd[index & 0x7]); + } - void sbcViaMemptr(register16_t& hl, register16_t operand) { - MEMPTR().word = hl.word + 1; - sbc(hl, operand); - } + void adjustHalfCarrySub(uint8_t before, uint8_t value, int calculation) { + auto index = buildHalfCarryIndex(before, value, calculation); + setFlag(HC, m_halfCarryTableSub[index & 0x7]); + } - void adcViaMemptr(register16_t& hl, register16_t operand) { - MEMPTR().word = hl.word + 1; - adc(hl, operand); - } + void adjustOverflowAdd(uint8_t before, uint8_t value, uint8_t calculation) { + adjustOverflowAdd(before & SF, value & SF, calculation & SF); + } - int buildHalfCarryIndex(uint8_t before, uint8_t value, int calculation) { - return ((before & 0x88) >> 1) | ((value & 0x88) >> 2) | ((calculation & 0x88) >> 3); - } + void adjustOverflowAdd(int beforeNegative, int valueNegative, int afterNegative) { + auto overflow = (beforeNegative == valueNegative) && (beforeNegative != afterNegative); + setFlag(VF, overflow); + } - void adjustHalfCarryAdd(uint8_t before, uint8_t value, int calculation) { - auto index = buildHalfCarryIndex(before, value, calculation); - setFlag(HC, m_halfCarryTableAdd[index & 0x7]); - } + void adjustOverflowSub(uint8_t before, uint8_t value, uint8_t calculation) { + adjustOverflowSub(before & SF, value & SF, calculation & SF); + } - void adjustHalfCarrySub(uint8_t before, uint8_t value, int calculation) { - auto index = buildHalfCarryIndex(before, value, calculation); - setFlag(HC, m_halfCarryTableSub[index & 0x7]); - } + void adjustOverflowSub(int beforeNegative, int valueNegative, int afterNegative) { + auto overflow = (beforeNegative != valueNegative) && (beforeNegative != afterNegative); + setFlag(VF, overflow); + } - void adjustOverflowAdd(uint8_t before, uint8_t value, uint8_t calculation) { - adjustOverflowAdd(before & SF, value & SF, calculation & SF); - } + 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 adjustOverflowAdd(int beforeNegative, int valueNegative, int afterNegative) { - auto overflow = (beforeNegative == valueNegative) && (beforeNegative != afterNegative); - setFlag(VF, overflow); - } + 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 adjustOverflowSub(uint8_t before, uint8_t value, uint8_t calculation) { - adjustOverflowSub(before & SF, value & SF, calculation & SF); - } + void postIncrement(uint8_t value); + void postDecrement(uint8_t value); - void adjustOverflowSub(int beforeNegative, int valueNegative, int afterNegative) { - auto overflow = (beforeNegative != valueNegative) && (beforeNegative != afterNegative); - setFlag(VF, overflow); - } + void restart(uint8_t address); - 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 jrConditional(int conditional); + void jrConditionalFlag(int flag); - 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 ret(); + void retn(); + void reti(); - void postIncrement(uint8_t value); - void postDecrement(uint8_t value); + void returnConditional(int condition); + void returnConditionalFlag(int flag); - void restart(uint8_t address); + void jumpConditional(int condition); + void jumpConditionalFlag(int flag); - void jrConditional(int conditional); - void jrConditionalFlag(int flag); + void call(register16_t address); + void callConditional(register16_t address, int condition); + void callConditionalFlag(register16_t address, int flag); - void ret(); - void retn(); - void reti(); + void sbc(register16_t& operand, register16_t value); + void adc(register16_t& operand, register16_t value); - void returnConditional(int condition); - void returnConditionalFlag(int flag); + void add(register16_t& operand, register16_t value); - void jumpConditional(int condition); - void jumpConditionalFlag(int flag); + 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 call(register16_t address); - void callConditional(register16_t address, int condition); - void callConditionalFlag(register16_t address, int flag); + void rlca(); + void rrca(); + void rla(); + void rra(); - void sbc(register16_t& operand, register16_t value); - void adc(register16_t& operand, register16_t value); + 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 add(register16_t& operand, register16_t value); + void bit(int n, uint8_t& operand); + void res(int n, uint8_t& operand); + void set(int nit, uint8_t& operand); - 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 daa(); - void rlca(); - void rrca(); - void rla(); - void rra(); + void scf(); + void ccf(); + void cpl(); - 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 xhtl(register16_t& operand); + void xhtl(); - void bit(int n, uint8_t& operand); - void res(int n, uint8_t& operand); - void set(int nit, uint8_t& operand); + void blockCompare(); - void daa(); + void cpi(); + void cpir(); - void scf(); - void ccf(); - void cpl(); + void cpd(); + void cpdr(); - void xhtl(register16_t& operand); - void xhtl(); + void blockLoad(register16_t source, register16_t destination); - void blockCompare(); + void ldi(); + void ldir(); - void cpi(); - void cpir(); + void ldd(); + void lddr(); - void cpd(); - void cpdr(); + void ini(); + void inir(); - void blockLoad(register16_t source, register16_t destination); + void ind(); + void indr(); - void ldi(); - void ldir(); + void blockOut(); - void ldd(); - void lddr(); + void outi(); + void otir(); - void ini(); - void inir(); + void outd(); + void otdr(); - void ind(); - void indr(); + void neg(); - void blockOut(); + void rrd(); + void rld(); - void outi(); - void otir(); + void writePort() { + m_ports.write(m_memory.ADDRESS().low, m_memory.DATA()); + } - void outd(); - void 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)); - } -}; \ No newline at end of file + void readPort() { + m_memory.placeDATA(m_ports.read(m_memory.ADDRESS().low)); + } + }; +} \ No newline at end of file diff --git a/Z80/src/Disassembler.cpp b/Z80/src/Disassembler.cpp index 3051918..d4f7517 100644 --- a/Z80/src/Disassembler.cpp +++ b/Z80/src/Disassembler.cpp @@ -8,12 +8,12 @@ #include "Memory.h" #include "Z80.h" -Disassembler::Disassembler() { +EightBit::Disassembler::Disassembler() { // Disable exceptions where too many format arguments are available m_formatter.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit); } -std::string Disassembler::state(Z80& cpu) { +std::string EightBit::Disassembler::state(Z80& cpu) { auto pc = cpu.getProgramCounter(); auto sp = cpu.getStackPointer(); @@ -51,7 +51,7 @@ std::string Disassembler::state(Z80& cpu) { return output.str(); } -std::string Disassembler::RP(int rp) const { +std::string EightBit::Disassembler::RP(int rp) const { switch (rp) { case 0: return "BC"; @@ -69,7 +69,7 @@ std::string Disassembler::RP(int rp) const { throw std::logic_error("Unhandled register pair"); } -std::string Disassembler::RP2(int rp) const { +std::string EightBit::Disassembler::RP2(int rp) const { switch (rp) { case 0: return "BC"; @@ -87,7 +87,7 @@ std::string Disassembler::RP2(int rp) const { throw std::logic_error("Unhandled register pair"); } -std::string Disassembler::R(int r) const { +std::string EightBit::Disassembler::R(int r) const { switch (r) { case 0: return "B"; @@ -125,7 +125,7 @@ std::string Disassembler::R(int r) const { throw std::logic_error("Unhandled register"); } -std::string Disassembler::cc(int flag) { +std::string EightBit::Disassembler::cc(int flag) { switch (flag) { case 0: return "NZ"; @@ -147,7 +147,7 @@ std::string Disassembler::cc(int flag) { throw std::logic_error("Unhandled condition"); } -std::string Disassembler::alu(int which) { +std::string EightBit::Disassembler::alu(int which) { switch (which) { case 0: // ADD A,n return "ADD"; @@ -169,14 +169,14 @@ std::string Disassembler::alu(int which) { throw std::logic_error("Unhandled alu operation"); } -std::string Disassembler::disassemble(const Z80& cpu) { +std::string EightBit::Disassembler::disassemble(const Z80& cpu) { m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false; std::ostringstream output; disassemble(output, cpu, cpu.getProgramCounter().word); return output.str(); } -void Disassembler::disassemble(std::ostringstream& output, const Z80& cpu, uint16_t pc) { +void EightBit::Disassembler::disassemble(std::ostringstream& output, const Z80& cpu, uint16_t pc) { const auto& memory = cpu.getMemory(); auto opcode = memory.peek(pc); @@ -234,7 +234,7 @@ void Disassembler::disassemble(std::ostringstream& output, const Z80& cpu, uint1 } } -void Disassembler::disassembleCB( +void EightBit::Disassembler::disassembleCB( std::ostringstream& output, const Z80& cpu, uint16_t pc, @@ -284,7 +284,7 @@ void Disassembler::disassembleCB( } } -void Disassembler::disassembleED( +void EightBit::Disassembler::disassembleED( std::ostringstream& output, const Z80& cpu, uint16_t pc, @@ -418,7 +418,7 @@ void Disassembler::disassembleED( } } -void Disassembler::disassembleOther( +void EightBit::Disassembler::disassembleOther( std::ostringstream& output, const Z80& cpu, uint16_t pc, @@ -674,13 +674,13 @@ void Disassembler::disassembleOther( } } -std::string Disassembler::flag(uint8_t value, int flag, const std::string& represents) { +std::string EightBit::Disassembler::flag(uint8_t value, int flag, const std::string& represents) { std::ostringstream output; output << (value & flag ? represents : "-"); return output.str(); } -std::string Disassembler::flags(uint8_t value) { +std::string EightBit::Disassembler::flags(uint8_t value) { std::ostringstream output; output << flag(value, Z80::SF, "S") @@ -694,31 +694,31 @@ std::string Disassembler::flags(uint8_t value) { return output.str(); } -std::string Disassembler::hex(uint8_t value) { +std::string EightBit::Disassembler::hex(uint8_t value) { std::ostringstream output; output << std::hex << std::setw(2) << std::setfill('0') << (int)value; return output.str(); } -std::string Disassembler::hex(uint16_t value) { +std::string EightBit::Disassembler::hex(uint16_t value) { std::ostringstream output; output << std::hex << std::setw(4) << std::setfill('0') << (int)value; return output.str(); } -std::string Disassembler::binary(uint8_t value) { +std::string EightBit::Disassembler::binary(uint8_t value) { std::ostringstream output; output << std::bitset<8>(value); return output.str(); } -std::string Disassembler::decimal(uint8_t value) { +std::string EightBit::Disassembler::decimal(uint8_t value) { std::ostringstream output; output << (int)value; return output.str(); } -std::string Disassembler::invalid(uint8_t value) { +std::string EightBit::Disassembler::invalid(uint8_t value) { std::ostringstream output; output << "Invalid instruction: " << hex(value) << "(" << binary(value) << ")"; return output.str(); diff --git a/Z80/src/InputOutput.cpp b/Z80/src/InputOutput.cpp index d7ff558..ab24c0e 100644 --- a/Z80/src/InputOutput.cpp +++ b/Z80/src/InputOutput.cpp @@ -1,38 +1,38 @@ #include "stdafx.h" #include "InputOutput.h" -InputOutput::InputOutput() { +EightBit::InputOutput::InputOutput() { } -uint8_t InputOutput::readInputPort(uint8_t port) { +uint8_t EightBit::InputOutput::readInputPort(uint8_t port) { OnReadingPort(port); auto value = input[port]; OnReadPort(port); return value; } -void InputOutput::writeOutputPort(uint8_t port, uint8_t value) { +void EightBit::InputOutput::writeOutputPort(uint8_t port, uint8_t value) { OnWritingPort(port); output[port] = value; OnWrittenPort(port); } -void InputOutput::OnReadingPort(uint8_t port) { +void EightBit::InputOutput::OnReadingPort(uint8_t port) { PortEventArgs event(port); ReadingPort.fire(event); } -void InputOutput::OnReadPort(uint8_t port) { +void EightBit::InputOutput::OnReadPort(uint8_t port) { PortEventArgs event(port); ReadPort.fire(event); } -void InputOutput::OnWritingPort(uint8_t port) { +void EightBit::InputOutput::OnWritingPort(uint8_t port) { PortEventArgs event(port); WritingPort.fire(event); } -void InputOutput::OnWrittenPort(uint8_t port) { +void EightBit::InputOutput::OnWrittenPort(uint8_t port) { PortEventArgs event(port); WrittenPort.fire(event); } diff --git a/Z80/src/Profiler.cpp b/Z80/src/Profiler.cpp index 628af2b..84491aa 100644 --- a/Z80/src/Profiler.cpp +++ b/Z80/src/Profiler.cpp @@ -2,28 +2,28 @@ #include "Profiler.h" #include "Disassembler.h" -Profiler::Profiler() { +EightBit::Profiler::Profiler() { std::fill(m_instructions.begin(), m_instructions.end(), 0); std::fill(m_addresses.begin(), m_addresses.end(), 0); } -Profiler::~Profiler() { +EightBit::Profiler::~Profiler() { } -void Profiler::addInstruction(uint8_t instruction) { +void EightBit::Profiler::addInstruction(uint8_t instruction) { m_instructions[instruction]++; } -void Profiler::addAddress(uint16_t address) { +void EightBit::Profiler::addAddress(uint16_t address) { m_addresses[address]++; } -void Profiler::dump() const { +void EightBit::Profiler::dump() const { dumpInstructionProfiles(); dumpAddressProfiles(); } -void Profiler::dumpInstructionProfiles() const { +void EightBit::Profiler::dumpInstructionProfiles() const { std::cout << "** instructions" << std::endl; for (int i = 0; i < 0x100; ++i) { auto count = m_instructions[i]; @@ -32,7 +32,7 @@ void Profiler::dumpInstructionProfiles() const { } } -void Profiler::dumpAddressProfiles() const { +void EightBit::Profiler::dumpAddressProfiles() const { std::cout << "** addresses" << std::endl; for (int i = 0; i < 0x10000; ++i) { auto count = m_addresses[i]; diff --git a/Z80/src/Z80.cpp b/Z80/src/Z80.cpp index d9e00f9..e122baa 100644 --- a/Z80/src/Z80.cpp +++ b/Z80/src/Z80.cpp @@ -4,8 +4,9 @@ // based on http://www.z80.info/decoding.htm // Half carry flag help from https://github.com/oubiwann/z80 -Z80::Z80(Memory& memory, InputOutput& ports) -: Processor(memory, ports), +EightBit::Z80::Z80(Memory& memory, InputOutput& ports) +: Processor(memory), + m_ports(ports), m_registerSet(0), m_accumulatorFlagsSet(0), m_refresh(0x7f), @@ -23,12 +24,12 @@ Z80::Z80(Memory& memory, InputOutput& ports) MEMPTR().word = 0; } -void Z80::reset() { +void EightBit::Z80::reset() { Processor::reset(); IFF1() = IFF2() = false; } -void Z80::initialise() { +void EightBit::Z80::initialise() { Processor::initialise(); @@ -64,15 +65,15 @@ void Z80::initialise() { #pragma region Interrupt routines -void Z80::disableInterrupts() { +void EightBit::Z80::disableInterrupts() { IFF1() = IFF2() = false; } -void Z80::enableInterrupts() { +void EightBit::Z80::enableInterrupts() { IFF1() = IFF2() = true; } -int Z80::interrupt(bool maskable, uint8_t value) { +int EightBit::Z80::interrupt(bool maskable, uint8_t value) { cycles = 0; if (!maskable || (maskable && IFF1())) { if (maskable) { @@ -107,53 +108,53 @@ int Z80::interrupt(bool maskable, uint8_t value) { #pragma region Flag manipulation helpers -void Z80::adjustSign(uint8_t value) { +void EightBit::Z80::adjustSign(uint8_t value) { setFlag(SF, value & SF); } -void Z80::adjustZero(uint8_t value) { +void EightBit::Z80::adjustZero(uint8_t value) { clearFlag(ZF, value); } -void Z80::adjustParity(uint8_t value) { +void EightBit::Z80::adjustParity(uint8_t value) { static const uint8_t lookup[0x10] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; auto set = lookup[highNibble(value)] + lookup[lowNibble(value)]; clearFlag(PF, set % 2); } -void Z80::adjustSZ(uint8_t value) { +void EightBit::Z80::adjustSZ(uint8_t value) { adjustSign(value); adjustZero(value); } -void Z80::adjustSZP(uint8_t value) { +void EightBit::Z80::adjustSZP(uint8_t value) { adjustSZ(value); adjustParity(value); } -void Z80::adjustXY(uint8_t value) { +void EightBit::Z80::adjustXY(uint8_t value) { setFlag(XF, value & XF); setFlag(YF, value & YF); } -void Z80::adjustSZPXY(uint8_t value) { +void EightBit::Z80::adjustSZPXY(uint8_t value) { adjustSZP(value); adjustXY(value); } -void Z80::adjustSZXY(uint8_t value) { +void EightBit::Z80::adjustSZXY(uint8_t value) { adjustSZ(value); adjustXY(value); } -void Z80::postIncrement(uint8_t value) { +void EightBit::Z80::postIncrement(uint8_t value) { adjustSZXY(value); clearFlag(NF); setFlag(VF, value == Bit7); clearFlag(HC, lowNibble(value)); } -void Z80::postDecrement(uint8_t value) { +void EightBit::Z80::postDecrement(uint8_t value) { adjustSZXY(value); setFlag(NF); setFlag(VF, value == Mask7); @@ -164,14 +165,14 @@ void Z80::postDecrement(uint8_t value) { #pragma region PC manipulation: call/ret/jp/jr -void Z80::restart(uint8_t address) { +void EightBit::Z80::restart(uint8_t address) { pushWord(pc); register16_t destination; destination.word = address; setPcViaMemptr(destination); } -void Z80::jrConditional(int conditional) { +void EightBit::Z80::jrConditional(int conditional) { auto offset = (int8_t)fetchByteData(); if (conditional) { register16_t destination; @@ -181,7 +182,7 @@ void Z80::jrConditional(int conditional) { } } -void Z80::jrConditionalFlag(int flag) { +void EightBit::Z80::jrConditionalFlag(int flag) { switch (flag) { case 0: // NZ jrConditional(!(F() & ZF)); @@ -210,14 +211,14 @@ void Z80::jrConditionalFlag(int flag) { } } -void Z80::jumpConditional(int conditional) { +void EightBit::Z80::jumpConditional(int conditional) { auto address = fetchWord(); if (conditional) pc = address; MEMPTR() = address; } -void Z80::jumpConditionalFlag(int flag) { +void EightBit::Z80::jumpConditionalFlag(int flag) { switch (flag) { case 0: // NZ jumpConditional(!(F() & ZF)); @@ -246,27 +247,27 @@ void Z80::jumpConditionalFlag(int flag) { } } -void Z80::ret() { +void EightBit::Z80::ret() { setPcViaMemptr(popWord()); } -void Z80::retn() { +void EightBit::Z80::retn() { ret(); IFF1() = IFF2(); } -void Z80::reti() { +void EightBit::Z80::reti() { retn(); } -void Z80::returnConditional(int condition) { +void EightBit::Z80::returnConditional(int condition) { if (condition) { ret(); cycles += 6; } } -void Z80::returnConditionalFlag(int flag) { +void EightBit::Z80::returnConditionalFlag(int flag) { switch (flag) { case 0: // NZ returnConditional(!(F() & ZF)); @@ -295,12 +296,12 @@ void Z80::returnConditionalFlag(int flag) { } } -void Z80::call(register16_t address) { +void EightBit::Z80::call(register16_t address) { pushWord(pc); pc = address; } -void Z80::callConditional(register16_t address, int condition) { +void EightBit::Z80::callConditional(register16_t address, int condition) { if (condition) { call(address); cycles += 7; @@ -308,7 +309,7 @@ void Z80::callConditional(register16_t address, int condition) { MEMPTR() = address; } -void Z80::callConditionalFlag(register16_t address, int flag) { +void EightBit::Z80::callConditionalFlag(register16_t address, int flag) { switch (flag) { case 0: // NZ callConditional(address, !(F() & ZF)); @@ -341,7 +342,7 @@ void Z80::callConditionalFlag(register16_t address, int flag) { #pragma region 16-bit arithmetic -void Z80::sbc(register16_t& operand, register16_t value) { +void EightBit::Z80::sbc(register16_t& operand, register16_t value) { auto before = operand; @@ -362,7 +363,7 @@ void Z80::sbc(register16_t& operand, register16_t value) { adjustXY(operand.high); } -void Z80::adc(register16_t& operand, register16_t value) { +void EightBit::Z80::adc(register16_t& operand, register16_t value) { auto before = operand; @@ -383,7 +384,7 @@ void Z80::adc(register16_t& operand, register16_t value) { adjustXY(operand.high); } -void Z80::add(register16_t& operand, register16_t value) { +void EightBit::Z80::add(register16_t& operand, register16_t value) { auto before = operand; @@ -401,7 +402,7 @@ void Z80::add(register16_t& operand, register16_t value) { #pragma region ALU -void Z80::add(uint8_t& operand, uint8_t value, int carry) { +void EightBit::Z80::add(uint8_t& operand, uint8_t value, int carry) { register16_t result; result.word = operand + value + carry; @@ -416,11 +417,11 @@ void Z80::add(uint8_t& operand, uint8_t value, int carry) { adjustSZXY(operand); } -void Z80::adc(uint8_t& operand, uint8_t value) { +void EightBit::Z80::adc(uint8_t& operand, uint8_t value) { add(operand, value, F() & CF); } -void Z80::sub(uint8_t& operand, uint8_t value, int carry) { +void EightBit::Z80::sub(uint8_t& operand, uint8_t value, int carry) { register16_t result; result.word = operand - value - carry; @@ -435,30 +436,30 @@ void Z80::sub(uint8_t& operand, uint8_t value, int carry) { adjustSZXY(operand); } -void Z80::sbc(uint8_t& operand, uint8_t value) { +void EightBit::Z80::sbc(uint8_t& operand, uint8_t value) { sub(operand, value, F() & CF); } -void Z80::andr(uint8_t& operand, uint8_t value) { +void EightBit::Z80::andr(uint8_t& operand, uint8_t value) { operand &= value; setFlag(HC); clearFlag(CF | NF); adjustSZPXY(operand); } -void Z80::xorr(uint8_t& operand, uint8_t value) { +void EightBit::Z80::xorr(uint8_t& operand, uint8_t value) { operand ^= value; clearFlag(HC | CF | NF); adjustSZPXY(operand); } -void Z80::orr(uint8_t& operand, uint8_t value) { +void EightBit::Z80::orr(uint8_t& operand, uint8_t value) { operand |= value; clearFlag(HC | CF | NF); adjustSZPXY(operand); } -void Z80::compare(uint8_t value) { +void EightBit::Z80::compare(uint8_t value) { auto check = A(); sub(check, value); adjustXY(value); @@ -468,7 +469,7 @@ void Z80::compare(uint8_t value) { #pragma region Shift and rotate -void Z80::rlc(uint8_t& operand) { +void EightBit::Z80::rlc(uint8_t& operand) { auto carry = operand & Bit7; operand <<= 1; setFlag(CF, carry); @@ -477,7 +478,7 @@ void Z80::rlc(uint8_t& operand) { adjustXY(operand); } -void Z80::rrc(uint8_t& operand) { +void EightBit::Z80::rrc(uint8_t& operand) { auto carry = operand & Bit0; operand >>= 1; carry ? operand |= Bit7 : operand &= ~Bit7; @@ -486,7 +487,7 @@ void Z80::rrc(uint8_t& operand) { adjustXY(operand); } -void Z80::rl(uint8_t& operand) { +void EightBit::Z80::rl(uint8_t& operand) { auto oldCarry = F() & CF; auto newCarry = operand & Bit7; operand <<= 1; @@ -496,7 +497,7 @@ void Z80::rl(uint8_t& operand) { adjustXY(operand); } -void Z80::rr(uint8_t& operand) { +void EightBit::Z80::rr(uint8_t& operand) { auto oldCarry = F() & CF; auto newCarry = operand & Bit0; operand >>= 1; @@ -508,7 +509,7 @@ void Z80::rr(uint8_t& operand) { // -void Z80::sla(uint8_t& operand) { +void EightBit::Z80::sla(uint8_t& operand) { auto newCarry = operand & Bit7; operand <<= 1; setFlag(CF, newCarry); @@ -516,7 +517,7 @@ void Z80::sla(uint8_t& operand) { adjustXY(operand); } -void Z80::sra(uint8_t& operand) { +void EightBit::Z80::sra(uint8_t& operand) { auto new7 = operand & Bit7; auto newCarry = operand & Bit0; operand >>= 1; @@ -526,7 +527,7 @@ void Z80::sra(uint8_t& operand) { adjustXY(operand); } -void Z80::sll(uint8_t& operand) { +void EightBit::Z80::sll(uint8_t& operand) { auto newCarry = operand & Bit7; operand <<= 1; operand |= 1; @@ -535,7 +536,7 @@ void Z80::sll(uint8_t& operand) { adjustXY(operand); } -void Z80::srl(uint8_t& operand) { +void EightBit::Z80::srl(uint8_t& operand) { auto newCarry = operand & Bit0; operand >>= 1; operand &= ~Bit7; // clear bit 7 @@ -547,19 +548,19 @@ void Z80::srl(uint8_t& operand) { // -void Z80::rlca() { +void EightBit::Z80::rlca() { rlc(A()); } -void Z80::rrca() { +void EightBit::Z80::rrca() { rrc(A()); } -void Z80::rla() { +void EightBit::Z80::rla() { rl(A()); } -void Z80::rra() { +void EightBit::Z80::rra() { rr(A()); } @@ -567,7 +568,7 @@ void Z80::rra() { #pragma region BIT/SET/RES -void Z80::bit(int n, uint8_t& operand) { +void EightBit::Z80::bit(int n, uint8_t& operand) { auto carry = F() & CF; uint8_t discarded = operand; andr(discarded, 1 << n); @@ -575,12 +576,12 @@ void Z80::bit(int n, uint8_t& operand) { setFlag(CF, carry); } -void Z80::res(int n, uint8_t& operand) { +void EightBit::Z80::res(int n, uint8_t& operand) { auto bit = 1 << n; operand &= ~bit; } -void Z80::set(int n, uint8_t& operand) { +void EightBit::Z80::set(int n, uint8_t& operand) { auto bit = 1 << n; operand |= bit; } @@ -589,7 +590,7 @@ void Z80::set(int n, uint8_t& operand) { #pragma region Miscellaneous instructions -void Z80::neg() { +void EightBit::Z80::neg() { auto original = A(); A() = 0; sub(A(), original); @@ -597,7 +598,7 @@ void Z80::neg() { setFlag(CF, original); } -void Z80::daa() { +void EightBit::Z80::daa() { uint8_t a = A(); @@ -623,19 +624,19 @@ void Z80::daa() { A() = a; } -void Z80::cpl() { +void EightBit::Z80::cpl() { A() = ~A(); adjustXY(A()); setFlag(HC | NF); } -void Z80::scf() { +void EightBit::Z80::scf() { setFlag(CF); adjustXY(A()); clearFlag(HC | NF); } -void Z80::ccf() { +void EightBit::Z80::ccf() { auto carry = F() & CF; setFlag(HC, carry); clearFlag(CF, carry); @@ -643,7 +644,7 @@ void Z80::ccf() { adjustXY(A()); } -void Z80::xhtl(register16_t& operand) { +void EightBit::Z80::xhtl(register16_t& operand) { m_memory.ADDRESS() = sp; MEMPTR().low = m_memory.reference(); m_memory.reference() = operand.low; @@ -654,7 +655,7 @@ void Z80::xhtl(register16_t& operand) { operand.high = MEMPTR().high; } -void Z80::xhtl() { +void EightBit::Z80::xhtl() { if (m_prefixDD) xhtl(IX()); else if (m_prefixFD) @@ -669,7 +670,7 @@ void Z80::xhtl() { #pragma region Block compare instructions -void Z80::blockCompare() { +void EightBit::Z80::blockCompare() { m_memory.ADDRESS() = HL(); @@ -689,19 +690,19 @@ void Z80::blockCompare() { setFlag(XF, result & Bit3); } -void Z80::cpi() { +void EightBit::Z80::cpi() { blockCompare(); HL().word++; MEMPTR().word++; } -void Z80::cpd() { +void EightBit::Z80::cpd() { blockCompare(); HL().word--; MEMPTR().word--; } -void Z80::cpir() { +void EightBit::Z80::cpir() { cpi(); if ((F() & PF) && !(F() & ZF)) { // See CPI cycles += 5; @@ -712,7 +713,7 @@ void Z80::cpir() { } } -void Z80::cpdr() { +void EightBit::Z80::cpdr() { cpd(); if ((F() & PF) && !(F() & ZF)) { // See CPD cycles += 5; @@ -727,7 +728,7 @@ void Z80::cpdr() { #pragma region Block load instructions -void Z80::blockLoad(register16_t source, register16_t destination) { +void EightBit::Z80::blockLoad(register16_t source, register16_t destination) { m_memory.ADDRESS() = source; auto value = m_memory.reference(); m_memory.ADDRESS() = destination; @@ -739,19 +740,19 @@ void Z80::blockLoad(register16_t source, register16_t destination) { setFlag(PF, --BC().word); } -void Z80::ldd() { +void EightBit::Z80::ldd() { blockLoad(HL(), DE()); HL().word--; DE().word--; } -void Z80::ldi() { +void EightBit::Z80::ldi() { blockLoad(HL(), DE()); HL().word++; DE().word++; } -void Z80::ldir() { +void EightBit::Z80::ldir() { ldi(); if (F() & PF) { // See LDI cycles += 5; @@ -760,7 +761,7 @@ void Z80::ldir() { } } -void Z80::lddr() { +void EightBit::Z80::lddr() { ldd(); if (F() & PF) { // See LDR cycles += 5; @@ -773,7 +774,7 @@ void Z80::lddr() { #pragma region Block input instructions -void Z80::ini() { +void EightBit::Z80::ini() { auto bc = BC().word; m_memory.ADDRESS().word = bc; readPort(); @@ -785,7 +786,7 @@ void Z80::ini() { MEMPTR().word = ++bc; } -void Z80::ind() { +void EightBit::Z80::ind() { auto bc = BC().word; m_memory.ADDRESS().word = bc; readPort(); @@ -797,7 +798,7 @@ void Z80::ind() { MEMPTR().word = --bc; } -void Z80::inir() { +void EightBit::Z80::inir() { ini(); if (!(F() & ZF)) { // See INI cycles += 5; @@ -805,7 +806,7 @@ void Z80::inir() { } } -void Z80::indr() { +void EightBit::Z80::indr() { ind(); if (!(F() & ZF)) { // See IND cycles += 5; @@ -817,7 +818,7 @@ void Z80::indr() { #pragma region Block output instructions -void Z80::blockOut() { +void EightBit::Z80::blockOut() { auto value = m_memory.reference(); m_memory.ADDRESS().word = BC().word; writePort(); @@ -827,19 +828,19 @@ void Z80::blockOut() { adjustParity(((value + L()) & 7) ^ B()); } -void Z80::outi() { +void EightBit::Z80::outi() { m_memory.ADDRESS().word = HL().word++; blockOut(); MEMPTR().word = BC().word + 1; } -void Z80::outd() { +void EightBit::Z80::outd() { m_memory.ADDRESS().word = HL().word--; blockOut(); MEMPTR().word = BC().word - 1; } -void Z80::otir() { +void EightBit::Z80::otir() { outi(); if (!(F() & ZF)) { // See OUTI cycles += 5; @@ -847,7 +848,7 @@ void Z80::otir() { } } -void Z80::otdr() { +void EightBit::Z80::otdr() { outd(); if (!(F() & ZF)) { // See OUTD cycles += 5; @@ -861,7 +862,7 @@ void Z80::otdr() { #pragma region Nibble rotation -void Z80::rrd() { +void EightBit::Z80::rrd() { auto accumulator = A(); m_memory.ADDRESS() = HL(); auto memory = m_memory.reference(); @@ -873,7 +874,7 @@ void Z80::rrd() { MEMPTR().word = HL().word + 1; } -void Z80::rld() { +void EightBit::Z80::rld() { auto accumulator = A(); m_memory.ADDRESS() = HL(); auto memory = m_memory.reference(); @@ -887,14 +888,14 @@ void Z80::rld() { #pragma endregion Nibble rotation -int Z80::step() { +int EightBit::Z80::step() { ExecutingInstruction.fire(*this); m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false; cycles = 0; return fetchExecute(); } -int Z80::execute(uint8_t opcode) { +int EightBit::Z80::execute(uint8_t opcode) { if (!getM1()) throw std::logic_error("M1 cannot be high"); @@ -924,7 +925,7 @@ int Z80::execute(uint8_t opcode) { return cycles; } -void Z80::executeCB(int x, int y, int z, int p, int q) { +void EightBit::Z80::executeCB(int x, int y, int z, int p, int q) { switch (x) { case 0: // rot[y] r[z] switch (y) { @@ -1049,7 +1050,7 @@ void Z80::executeCB(int x, int y, int z, int p, int q) { } } -void Z80::executeED(int x, int y, int z, int p, int q) { +void EightBit::Z80::executeED(int x, int y, int z, int p, int q) { switch (x) { case 0: case 3: // Invalid instruction, equivalent to NONI followed by NOP @@ -1246,7 +1247,7 @@ void Z80::executeED(int x, int y, int z, int p, int q) { } } -void Z80::executeOther(int x, int y, int z, int p, int q) { +void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) { switch (x) { case 0: switch (z) { diff --git a/Z80/src/Z80.vcxproj b/Z80/src/Z80.vcxproj new file mode 100644 index 0000000..b9a5881 --- /dev/null +++ b/Z80/src/Z80.vcxproj @@ -0,0 +1,170 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {01974F81-2750-45AF-B845-2C903A54A334} + Win32Proj + Z80 + 8.1 + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + ..\inc;..\..\inc;$(IncludePath) + + + ..\inc;..\..\inc;$(IncludePath) + + + ..\inc;..\..\inc;$(IncludePath) + + + ..\inc;..\..\inc;$(IncludePath) + + + + Level3 + Use + MaxSpeed + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + + + + + Use + Level3 + Disabled + _DEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + true + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/Z80/src/Z80.vcxproj.filters b/Z80/src/Z80.vcxproj.filters new file mode 100644 index 0000000..28b2e88 --- /dev/null +++ b/Z80/src/Z80.vcxproj.filters @@ -0,0 +1,53 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + \ No newline at end of file diff --git a/Z80/src/packages.config b/Z80/src/packages.config new file mode 100644 index 0000000..2f23632 --- /dev/null +++ b/Z80/src/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Z80/src/stdafx.cpp b/Z80/src/stdafx.cpp new file mode 100644 index 0000000..fd4f341 --- /dev/null +++ b/Z80/src/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" diff --git a/Z80/src/stdafx.h b/Z80/src/stdafx.h new file mode 100644 index 0000000..fe79e2d --- /dev/null +++ b/Z80/src/stdafx.h @@ -0,0 +1,42 @@ +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +//#include +//#include +// +//#if SDL_BYTEORDER == SDL_LIL_ENDIAN +//#define HOST_LITTLE_ENDIAN +//#endif +// +//#if SDL_BYTEORDER == SDL_BIG_ENDIAN +//#define HOST_BIG_ENDIAN +//#endif +// +//#define RUN_TESTS +////#define RUN_CPM +////#define RUN_INVADERS +// +//#ifdef _MSC_VER +//#pragma comment(lib, "SDL2.lib") +//#pragma comment(lib, "SDL2main.lib") +//#pragma comment(lib, "SDL2_mixer.lib") +//#endif diff --git a/Z80/test/Board.cpp b/Z80/test/Board.cpp new file mode 100644 index 0000000..589f233 --- /dev/null +++ b/Z80/test/Board.cpp @@ -0,0 +1,84 @@ +#include "stdafx.h" +#include "Board.h" +#include "Disassembler.h" + +Board::Board(const Configuration& configuration) +: m_configuration(configuration), + m_memory(0x3fff), + m_cpu(EightBit::Z80(m_memory, m_ports)) { +} + +void Board::initialise() { + + m_memory.clear(); + auto romDirectory = m_configuration.getRomDirectory(); + + //m_memory.loadRam(romDirectory + "/prelim.com", 0x100); // Bartholomew preliminary + //m_memory.loadRam(romDirectory + "/zexdoc.com", 0x100); // Cringle/Bartholomew + m_memory.loadRam(romDirectory + "/zexall.com", 0x100); // Cringle/Bartholomew + //m_memory.loadRam(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics + //m_memory.loadRam(romDirectory + "/TEST.COM", 0x100); // Microcosm + + m_memory.ADDRESS().word = 5; + m_memory.reference() = 0xc9; // ret + m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Cpm, this, std::placeholders::_1)); + + if (m_configuration.isProfileMode()) { + m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Profile, this, std::placeholders::_1)); + } + + if (m_configuration.isDebugMode()) { + m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Debug, this, std::placeholders::_1)); + } + + m_cpu.initialise(); + m_cpu.setProgramCounter(m_configuration.getStartAddress()); +} + +void Board::Cpu_ExecutingInstruction_Cpm(const EightBit::Z80&) { + auto pc = m_cpu.getProgramCounter(); + switch (pc.word) { + case 0x0: // CP/M warm start + m_cpu.halt(); + m_profiler.dump(); + break; + case 0x5: // BDOS + bdos(); + break; + default: + break; + } +} + +void Board::bdos() { + auto c = m_cpu.C(); + switch (c) { + case 0x2: { + auto character = m_cpu.E(); + std::cout << character; + break; + } + case 0x9: + for (uint16_t i = m_cpu.DE().word; m_memory.peek(i) != '$'; ++i) { + std::cout << m_memory.peek(i); + } + break; + } +} + +void Board::Cpu_ExecutingInstruction_Profile(const EightBit::Z80& cpu) { + + const auto pc = cpu.getProgramCounter(); + + m_profiler.addAddress(pc.word); + m_profiler.addInstruction(m_memory.peek(pc.word)); +} + +void Board::Cpu_ExecutingInstruction_Debug(const EightBit::Z80& cpu) { + + std::cerr + << EightBit::Disassembler::state(m_cpu) + << "\t" + << m_disassembler.disassemble(cpu) + << '\n'; +} diff --git a/Z80/test/Board.h b/Z80/test/Board.h new file mode 100644 index 0000000..0eda262 --- /dev/null +++ b/Z80/test/Board.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include "Memory.h" +#include "InputOutput.h" +#include "Configuration.h" +#include "Profiler.h" +#include "EventArgs.h" +#include "Disassembler.h" +#include "Z80.h" + +class Board { +public: + Board(const Configuration& configuration); + + EightBit::Memory& getMemory() { return m_memory; } + const EightBit::Z80& getCPU() const { return m_cpu; } + EightBit::Z80& getCPUMutable() { return m_cpu; } + + void initialise(); + +private: + const Configuration& m_configuration; + EightBit::Memory m_memory; + EightBit::InputOutput m_ports; + EightBit::Z80 m_cpu; + EightBit::Profiler m_profiler; + EightBit::Disassembler m_disassembler; + + void Cpu_ExecutingInstruction_Cpm(const EightBit::Z80& cpu); + + void Cpu_ExecutingInstruction_Debug(const EightBit::Z80& cpuEvent); + void Cpu_ExecutingInstruction_Profile(const EightBit::Z80& cpuEvent); + + void bdos(); +}; diff --git a/Z80/test/Configuration.cpp b/Z80/test/Configuration.cpp new file mode 100644 index 0000000..77ae143 --- /dev/null +++ b/Z80/test/Configuration.cpp @@ -0,0 +1,8 @@ +#include "stdafx.h" +#include "Configuration.h" + +Configuration::Configuration() +: m_debugMode(false), + m_profileMode(false), + m_romDirectory("roms") { +} diff --git a/Z80/test/Configuration.h b/Z80/test/Configuration.h new file mode 100644 index 0000000..0e6cee8 --- /dev/null +++ b/Z80/test/Configuration.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include "Memory.h" + +class Configuration { +public: + Configuration(); + + bool isDebugMode() const { + return m_debugMode; + } + + void setDebugMode(bool value) { + m_debugMode = value; + } + + bool isProfileMode() const { + return m_profileMode; + } + + void setProfileMode(bool value) { + m_profileMode = value; + } + + std::string getRomDirectory() const { + return m_romDirectory; + } + + EightBit::register16_t getStartAddress() const { + EightBit::register16_t returned; + returned.word = 0x100; + return returned; + } + +private: + bool m_debugMode; + bool m_profileMode; + + std::string m_romDirectory; +}; diff --git a/Z80/test/Game.cpp b/Z80/test/Game.cpp new file mode 100644 index 0000000..ed823c9 --- /dev/null +++ b/Z80/test/Game.cpp @@ -0,0 +1,21 @@ +#include "stdafx.h" +#include "Game.h" + +#include + +Game::Game(const Configuration& configuration) +: m_configuration(configuration), + m_board(configuration) { +} + +void Game::initialise() { + m_board.initialise(); +} + +void Game::runLoop() { + auto& cpu = m_board.getCPUMutable(); + auto cycles = 0; + while (!cpu.isHalted()) { + cycles = cpu.step(); + } +} diff --git a/Z80/test/Game.h b/Z80/test/Game.h new file mode 100644 index 0000000..9e5f682 --- /dev/null +++ b/Z80/test/Game.h @@ -0,0 +1,22 @@ +#pragma once + +//#include +//#include +//#include +//#include + +#include "Board.h" + +class Configuration; + +class Game { +public: + Game(const Configuration& configuration); + + void runLoop(); + void initialise(); + +private: + const Configuration& m_configuration; + mutable Board m_board; +}; diff --git a/Z80/test/packages.config b/Z80/test/packages.config new file mode 100644 index 0000000..2f23632 --- /dev/null +++ b/Z80/test/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Z80/test/roms/CPUTEST.COM b/Z80/test/roms/CPUTEST.COM new file mode 100644 index 0000000..dd535a4 Binary files /dev/null and b/Z80/test/roms/CPUTEST.COM differ diff --git a/Z80/test/roms/TEST.ASM b/Z80/test/roms/TEST.ASM new file mode 100644 index 0000000..4d1fe71 --- /dev/null +++ b/Z80/test/roms/TEST.ASM @@ -0,0 +1,805 @@ +;*********************************************************************** +; MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC VERSION 1.0 (C) 1980 +;*********************************************************************** +; Load into virtual altair with: ALTAIR L=TEST.HEX +; Then press F2 to view screen, and 'G' to execute the test. +; +;DONATED TO THE "SIG/M" CP/M USER'S GROUP BY: +;KELLY SMITH, MICROCOSM ASSOCIATES +;3055 WACO AVENUE +;SIMI VALLEY, CALIFORNIA, 93065 +;(805) 527-9321 (MODEM, CP/M-NET (TM)) +;(805) 527-0518 (VERBAL) +; + CPU 8080 + ORG 00100H + + LXI H, LOLZ + CALL MSG + JMP CPU ;JUMP TO 8080 CPU DIAGNOSTIC +; +LOLZ: DB "MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC VERSION 1.0 (C) 1980", 0dh, 0ah, 24h +; +BDOS EQU 00005H ;BDOS ENTRY TO CP/M +WBOOT: JMP 0 +; +;MESSAGE OUTPUT ROUTINE +; +MSG: MOV A,M ; Get data + CPI '$' ; End? + RZ + CALL PCHAR ; Output + INX H ; Next + JMP MSG ; Do all +; +; +;CHARACTER OUTPUT ROUTINE +; +PCHAR: PUSH PSW + PUSH D + PUSH H + MOV E,A + MVI C,2 + CALL BDOS + POP H + POP D + POP PSW + RET +; +; +; +BYTEO: PUSH PSW + CALL BYTO1 + MOV E,A + CALL PCHAR + POP PSW + CALL BYTO2 + MOV E,A + JMP PCHAR +BYTO1: RRC + RRC + RRC + RRC +BYTO2: ANI 0FH + CPI 0AH + JM BYTO3 + ADI 7 +BYTO3: ADI 30H + RET +; +; +; +;************************************************************ +; MESSAGE TABLE FOR OPERATIONAL CPU TEST +;************************************************************ +; +OKCPU: DB 0DH,0AH + DB "CPU IS OPERATIONAL$" +; +NGCPU: DB 0DH,0AH + DB " CPU HAS FAILED! ERROR EXIT=$" +; +; +; +;************************************************************ +; 8080/8085 CPU TEST/DIAGNOSTIC +;************************************************************ +; +;NOTE: (1) PROGRAM ASSUMES "CALL",AND "LXI SP" INSTRUCTIONS WORK! +; +; (2) INSTRUCTIONS NOT TESTED ARE "HLT","DI","EI", +; AND "RST 0" THRU "RST 7" +; +; +; +;TEST JUMP INSTRUCTIONS AND FLAGS +; +CPU: LXI SP,STACK ;SET THE STACK POINTER + ANI 0 ;INITIALIZE A REG. AND CLEAR ALL FLAGS + JZ J010 ;TEST "JZ" + CALL CPUER +J010: JNC J020 ;TEST "JNC" + CALL CPUER +J020: JPE J030 ;TEST "JPE" + CALL CPUER +J030: JP J040 ;TEST "JP" + CALL CPUER +J040: JNZ J050 ;TEST "JNZ" + JC J050 ;TEST "JC" + JPO J050 ;TEST "JPO" + JM J050 ;TEST "JM" + JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL! +J050: CALL CPUER +J060: ADI 6 ;A=6,C=0,P=1,S=0,Z=0 + JNZ J070 ;TEST "JNZ" + CALL CPUER +J070: JC J080 ;TEST "JC" + JPO J080 ;TEST "JPO" + JP J090 ;TEST "JP" +J080: CALL CPUER +J090: ADI 070H ;A=76H,C=0,P=0,S=0,Z=0 + JPO J100 ;TEST "JPO" + CALL CPUER +J100: JM J110 ;TEST "JM" + JZ J110 ;TEST "JZ" + JNC J120 ;TEST "JNC" +J110: CALL CPUER +J120: ADI 081H ;A=F7H,C=0,P=0,S=1,Z=0 + JM J130 ;TEST "JM" + CALL CPUER +J130: JZ J140 ;TEST "JZ" + JC J140 ;TEST "JC" + JPO J150 ;TEST "JPO" +J140: CALL CPUER +J150: ADI 0FEH ;A=F5H,C=1,P=1,S=1,Z=0 + JC J160 ;TEST "JC" + CALL CPUER +J160: JZ J170 ;TEST "JZ" + JPO J170 ;TEST "JPO" + JM AIMM ;TEST "JM" +J170: CALL CPUER +; +; +; +;TEST ACCUMULATOR IMMEDIATE INSTRUCTIONS +; +AIMM: CPI 0 ;A=F5H,C=0,Z=0 + JC CPIE ;TEST "CPI" FOR RE-SET CARRY + JZ CPIE ;TEST "CPI" FOR RE-SET ZERO + CPI 0F5H ;A=F5H,C=0,Z=1 + JC CPIE ;TEST "CPI" FOR RE-SET CARRY ("ADI") + JNZ CPIE ;TEST "CPI" FOR RE-SET ZERO + CPI 0FFH ;A=F5H,C=1,Z=0 + JZ CPIE ;TEST "CPI" FOR RE-SET ZERO + JC ACII ;TEST "CPI" FOR SET CARRY +CPIE: CALL CPUER +ACII: ACI 00AH ;A=F5H+0AH+CARRY(1)=0,C=1 + ACI 00AH ;A=0+0AH+CARRY(0)=0BH,C=0 + CPI 00BH + JZ SUII ;TEST "ACI" + CALL CPUER +SUII: SUI 00CH ;A=FFH,C=0 + SUI 00FH ;A=F0H,C=1 + CPI 0F0H + JZ SBII ;TEST "SUI" + CALL CPUER +SBII: SBI 0F1H ;A=F0H-0F1H-CARRY(0)=FFH,C=1 + SBI 00EH ;A=FFH-OEH-CARRY(1)=F0H,C=0 + CPI 0F0H + JZ ANII ;TEST "SBI" + CALL CPUER +ANII: ANI 055H ;A=F0H55H=50H,C=0,P=1,S=0,Z=0 + CPI 050H + JZ ORII ;TEST "ANI" + CALL CPUER +ORII: ORI 03AH ;A=50H3AH=7AH,C=0,P=0,S=0,Z=0 + CPI 07AH + JZ XRII ;TEST "ORI" + CALL CPUER +XRII: XRI 00FH ;A=7AH0FH=75H,C=0,P=0,S=0,Z=0 + CPI 075H + JZ C010 ;TEST "XRI" + CALL CPUER +; +; +; +;TEST CALLS AND RETURNS +; +C010: ANI 000H ;A=0,C=0,P=1,S=0,Z=1 + CC CPUER ;TEST "CC" + CPO CPUER ;TEST "CPO" + CM CPUER ;TEST "CM" + CNZ CPUER ;TEST "CNZ" + CPI 000H + JZ C020 ;A=0,C=0,P=0,S=0,Z=1 + CALL CPUER +C020: SUI 077H ;A=89H,C=1,P=0,S=1,Z=0 + CNC CPUER ;TEST "CNC" + CPE CPUER ;TEST "CPE" + CP CPUER ;TEST "CP" + CZ CPUER ;TEST "CZ" + CPI 089H + JZ C030 ;TEST FOR "CALLS" TAKING BRANCH + CALL CPUER +C030: ANI 0FFH ;SET FLAGS BACK! + CPO CPOI ;TEST "CPO" + CPI 0D9H + JZ MOVI ;TEST "CALL" SEQUENCE SUCCESS + CALL CPUER +CPOI: RPE ;TEST "RPE" + ADI 010H ;A=99H,C=0,P=0,S=1,Z=0 + CPE CPEI ;TEST "CPE" + ADI 002H ;A=D9H,C=0,P=0,S=1,Z=0 + RPO ;TEST "RPO" + CALL CPUER +CPEI: RPO ;TEST "RPO" + ADI 020H ;A=B9H,C=0,P=0,S=1,Z=0 + CM CMI ;TEST "CM" + ADI 004H ;A=D7H,C=0,P=1,S=1,Z=0 + RPE ;TEST "RPE" + CALL CPUER +CMI: RP ;TEST "RP" + ADI 080H ;A=39H,C=1,P=1,S=0,Z=0 + CP TCPI ;TEST "CP" + ADI 080H ;A=D3H,C=0,P=0,S=1,Z=0 + RM ;TEST "RM" + CALL CPUER +TCPI: RM ;TEST "RM" + ADI 040H ;A=79H,C=0,P=0,S=0,Z=0 + CNC CNCI ;TEST "CNC" + ADI 040H ;A=53H,C=0,P=1,S=0,Z=0 + RP ;TEST "RP" + CALL CPUER +CNCI: RC ;TEST "RC" + ADI 08FH ;A=08H,C=1,P=0,S=0,Z=0 + CC CCI ;TEST "CC" + SUI 002H ;A=13H,C=0,P=0,S=0,Z=0 + RNC ;TEST "RNC" + CALL CPUER +CCI: RNC ;TEST "RNC" + ADI 0F7H ;A=FFH,C=0,P=1,S=1,Z=0 + CNZ CNZI ;TEST "CNZ" + ADI 0FEH ;A=15H,C=1,P=0,S=0,Z=0 + RC ;TEST "RC" + CALL CPUER +CNZI: RZ ;TEST "RZ" + ADI 001H ;A=00H,C=1,P=1,S=0,Z=1 + CZ CZI ;TEST "CZ" + ADI 0D0H ;A=17H,C=1,P=1,S=0,Z=0 + RNZ ;TEST "RNZ" + CALL CPUER +CZI: RNZ ;TEST "RNZ" + ADI 047H ;A=47H,C=0,P=1,S=0,Z=0 + CPI 047H ;A=47H,C=0,P=1,S=0,Z=1 + RZ ;TEST "RZ" + CALL CPUER +; +; +; +;TEST "MOV","INR",AND "DCR" INSTRUCTIONS +; +MOVI: MVI A,077H + INR A + MOV B,A + INR B + MOV C,B + DCR C + MOV D,C + MOV E,D + MOV H,E + MOV L,H + MOV A,L ;TEST "MOV" A,L,H,E,D,C,B,A + DCR A + MOV C,A + MOV E,C + MOV L,E + MOV B,L + MOV D,B + MOV H,D + MOV A,H ;TEST "MOV" A,H,D,B,L,E,C,A + MOV D,A + INR D + MOV L,D + MOV C,L + INR C + MOV H,C + MOV B,H + DCR B + MOV E,B + MOV A,E ;TEST "MOV" A,E,B,H,C,L,D,A + MOV E,A + INR E + MOV B,E + MOV H,B + INR H + MOV C,H + MOV L,C + MOV D,L + DCR D + MOV A,D ;TEST "MOV" A,D,L,C,H,B,E,A + MOV H,A + DCR H + MOV D,H + MOV B,D + MOV L,B + INR L + MOV E,L + DCR E + MOV C,E + MOV A,C ;TEST "MOV" A,C,E,L,B,D,H,A + MOV L,A + DCR L + MOV H,L + MOV E,H + MOV D,E + MOV C,D + MOV B,C + MOV A,B + CPI 077H + CNZ CPUER ;TEST "MOV" A,B,C,D,E,H,L,A +; +; +; +;TEST ARITHMETIC AND LOGIC INSTRUCTIONS +; + XRA A + MVI B,001H + MVI C,003H + MVI D,007H + MVI E,00FH + MVI H,01FH + MVI L,03FH + ADD B + ADD C + ADD D + ADD E + ADD H + ADD L + ADD A + CPI 0F0H + CNZ CPUER ;TEST "ADD" B,C,D,E,H,L,A + SUB B + SUB C + SUB D + SUB E + SUB H + SUB L + CPI 078H + CNZ CPUER ;TEST "SUB" B,C,D,E,H,L + SUB A + CNZ CPUER ;TEST "SUB" A + MVI A,080H + ADD A + MVI B,001H + MVI C,002H + MVI D,003H + MVI E,004H + MVI H,005H + MVI L,006H + ADC B + MVI B,080H + ADD B + ADD B + ADC C + ADD B + ADD B + ADC D + ADD B + ADD B + ADC E + ADD B + ADD B + ADC H + ADD B + ADD B + ADC L + ADD B + ADD B + ADC A + CPI 037H + CNZ CPUER ;TEST "ADC" B,C,D,E,H,L,A + MVI A,080H + ADD A + MVI B,001H + SBB B + MVI B,0FFH + ADD B + SBB C + ADD B + SBB D + ADD B + SBB E + ADD B + SBB H + ADD B + SBB L + CPI 0E0H + CNZ CPUER ;TEST "SBB" B,C,D,E,H,L + MVI A,080H + ADD A + SBB A + CPI 0FFH + CNZ CPUER ;TEST "SBB" A + MVI A,0FFH + MVI B,0FEH + MVI C,0FCH + MVI D,0EFH + MVI E,07FH + MVI H,0F4H + MVI L,0BFH + ANA A + ANA C + ANA D + ANA E + ANA H + ANA L + ANA A + CPI 024H + CNZ CPUER ;TEST "ANA" B,C,D,E,H,L,A + XRA A + MVI B,001H + MVI C,002H + MVI D,004H + MVI E,008H + MVI H,010H + MVI L,020H + ORA B + ORA C + ORA D + ORA E + ORA H + ORA L + ORA A + CPI 03FH + CNZ CPUER ;TEST "ORA" B,C,D,E,H,L,A + MVI A,000H + MVI H,08FH + MVI L,04FH + XRA B + XRA C + XRA D + XRA E + XRA H + XRA L + CPI 0CFH + CNZ CPUER ;TEST "XRA" B,C,D,E,H,L + XRA A + CNZ CPUER ;TEST "XRA" A + MVI B,044H + MVI C,045H + MVI D,046H + MVI E,047H + MVI H,(TEMP0/0FFH) ;HIGH BYTE OF TEST MEMORY LOCATION + MVI L,(TEMP0&0FFH) ;LOW BYTE OF TEST MEMORY LOCATION + MOV M,B + MVI B,000H + MOV B,M + MVI A,044H + CMP B + CNZ CPUER ;TEST "MOV" M,B AND B,M + MOV M,D + MVI D,000H + MOV D,M + MVI A,046H + CMP D + CNZ CPUER ;TEST "MOV" M,D AND D,M + MOV M,E + MVI E,000H + MOV E,M + MVI A,047H + CMP E + CNZ CPUER ;TEST "MOV" M,E AND E,M + MOV M,H + MVI H,(TEMP0/0FFH) + MVI L,(TEMP0&0FFH) + MOV H,M + MVI A,(TEMP0/0FFH) + CMP H + CNZ CPUER ;TEST "MOV" M,H AND H,M + MOV M,L + MVI H,(TEMP0/0FFH) + MVI L,(TEMP0&0FFH) + MOV L,M + MVI A,(TEMP0&0FFH) + CMP L + CNZ CPUER ;TEST "MOV" M,L AND L,M + MVI H,(TEMP0/0FFH) + MVI L,(TEMP0&0FFH) + MVI A,032H + MOV M,A + CMP M + CNZ CPUER ;TEST "MOV" M,A + ADD M + CPI 064H + CNZ CPUER ;TEST "ADD" M + XRA A + MOV A,M + CPI 032H + CNZ CPUER ;TEST "MOV" A,M + MVI H,(TEMP0/0FFH) + MVI L,(TEMP0&0FFH) + MOV A,M + SUB M + CNZ CPUER ;TEST "SUB" M + MVI A,080H + ADD A + ADC M + CPI 033H + CNZ CPUER ;TEST "ADC" M + MVI A,080H + ADD A + SBB M + CPI 0CDH + CNZ CPUER ;TEST "SBB" M + ANA M + CNZ CPUER ;TEST "ANA" M + MVI A,025H + ORA M + CPI 037H + CNZ CPUER ;TEST "ORA" M + XRA M + CPI 005H + CNZ CPUER ;TEST "XRA" M + MVI M,055H + INR M + DCR M + ADD M + CPI 05AH + CNZ CPUER ;TEST "INR","DCR",AND "MVI" M + LXI B,12FFH + LXI D,12FFH + LXI H,12FFH + INX B + INX D + INX H + MVI A,013H + CMP B + CNZ CPUER ;TEST "LXI" AND "INX" B + CMP D + CNZ CPUER ;TEST "LXI" AND "INX" D + CMP H + CNZ CPUER ;TEST "LXI" AND "INX" H + MVI A,000H + CMP C + CNZ CPUER ;TEST "LXI" AND "INX" B + CMP E + CNZ CPUER ;TEST "LXI" AND "INX" D + CMP L + CNZ CPUER ;TEST "LXI" AND "INX" H + DCX B + DCX D + DCX H + MVI A,012H + CMP B + CNZ CPUER ;TEST "DCX" B + CMP D + CNZ CPUER ;TEST "DCX" D + CMP H + CNZ CPUER ;TEST "DCX" H + MVI A,0FFH + CMP C + CNZ CPUER ;TEST "DCX" B + CMP E + CNZ CPUER ;TEST "DCX" D + CMP L + CNZ CPUER ;TEST "DCX" H + STA TEMP0 + XRA A + LDA TEMP0 + CPI 0FFH + CNZ CPUER ;TEST "LDA" AND "STA" + LHLD TEMPP + SHLD TEMP0 + LDA TEMPP + MOV B,A + LDA TEMP0 + CMP B + CNZ CPUER ;TEST "LHLD" AND "SHLD" + LDA TEMPP+1 + MOV B,A + LDA TEMP0+1 + CMP B + CNZ CPUER ;TEST "LHLD" AND "SHLD" + MVI A,0AAH + STA TEMP0 + MOV B,H + MOV C,L + XRA A + LDAX B + CPI 0AAH + CNZ CPUER ;TEST "LDAX" B + INR A + STAX B + LDA TEMP0 + CPI 0ABH + CNZ CPUER ;TEST "STAX" B + MVI A,077H + STA TEMP0 + LHLD TEMPP + LXI D,00000H + XCHG + XRA A + LDAX D + CPI 077H + CNZ CPUER ;TEST "LDAX" D AND "XCHG" + XRA A + ADD H + ADD L + CNZ CPUER ;TEST "XCHG" + MVI A,0CCH + STAX D + LDA TEMP0 + CPI 0CCH + STAX D + LDA TEMP0 + CPI 0CCH + CNZ CPUER ;TEST "STAX" D + LXI H,07777H + DAD H + MVI A,0EEH + CMP H + CNZ CPUER ;TEST "DAD" H + CMP L + CNZ CPUER ;TEST "DAD" H + LXI H,05555H + LXI B,0FFFFH + DAD B + MVI A,055H + CNC CPUER ;TEST "DAD" B + CMP H + CNZ CPUER ;TEST "DAD" B + MVI A,054H + CMP L + CNZ CPUER ;TEST "DAD" B + LXI H,0AAAAH + LXI D,03333H + DAD D + MVI A,0DDH + CMP H + CNZ CPUER ;TEST "DAD" D + CMP L + CNZ CPUER ;TEST "DAD" B + STC + CNC CPUER ;TEST "STC" + CMC + CC CPUER ;TEST "CMC + MVI A,0AAH + CMA + CPI 055H + CNZ CPUER ;TEST "CMA" + ORA A ;RE-SET AUXILIARY CARRY + DAA + CPI 055H + CNZ CPUER ;TEST "DAA" + MVI A,088H + ADD A + DAA + CPI 076H + CNZ CPUER ;TEST "DAA" + XRA A + MVI A,0AAH + DAA + CNC CPUER ;TEST "DAA" + CPI 010H + CNZ CPUER ;TEST "DAA" + XRA A + MVI A,09AH + DAA + CNC CPUER ;TEST "DAA" + CNZ CPUER ;TEST "DAA" + STC + MVI A,042H + RLC + CC CPUER ;TEST "RLC" FOR RE-SET CARRY + RLC + CNC CPUER ;TEST "RLC" FOR SET CARRY + CPI 009H + CNZ CPUER ;TEST "RLC" FOR ROTATION + RRC + CNC CPUER ;TEST "RRC" FOR SET CARRY + RRC + CPI 042H + CNZ CPUER ;TEST "RRC" FOR ROTATION + RAL + RAL + CNC CPUER ;TEST "RAL" FOR SET CARRY + CPI 008H + CNZ CPUER ;TEST "RAL" FOR ROTATION + RAR + RAR + CC CPUER ;TEST "RAR" FOR RE-SET CARRY + CPI 002H + CNZ CPUER ;TEST "RAR" FOR ROTATION + LXI B,01234H + LXI D,0AAAAH + LXI H,05555H + XRA A + PUSH B + PUSH D + PUSH H + PUSH PSW + LXI B,00000H + LXI D,00000H + LXI H,00000H + MVI A,0C0H + ADI 0F0H + POP PSW + POP H + POP D + POP B + CC CPUER ;TEST "PUSH PSW" AND "POP PSW" + CNZ CPUER ;TEST "PUSH PSW" AND "POP PSW" + CPO CPUER ;TEST "PUSH PSW" AND "POP PSW" + CM CPUER ;TEST "PUSH PSW" AND "POP PSW" + MVI A,012H + CMP B + CNZ CPUER ;TEST "PUSH B" AND "POP B" + MVI A,034H + CMP C + CNZ CPUER ;TEST "PUSH B" AND "POP B" + MVI A,0AAH + CMP D + CNZ CPUER ;TEST "PUSH D" AND "POP D" + CMP E + CNZ CPUER ;TEST "PUSH D" AND "POP D" + MVI A,055H + CMP H + CNZ CPUER ;TEST "PUSH H" AND "POP H" + CMP L + CNZ CPUER ;TEST "PUSH H" AND "POP H" + LXI H,00000H + DAD SP + SHLD SAVSTK ;SAVE THE "OLD" STACK-POINTER! + LXI SP,TEMP4 + DCX SP + DCX SP + INX SP + DCX SP + MVI A,055H + STA TEMP2 + CMA + STA TEMP3 + POP B + CMP B + CNZ CPUER ;TEST "LXI","DAD","INX",AND "DCX" SP + CMA + CMP C + CNZ CPUER ;TEST "LXI","DAD","INX", AND "DCX" SP + LXI H,TEMP4 + SPHL + LXI H,07733H + DCX SP + DCX SP + XTHL + LDA TEMP3 + CPI 077H + CNZ CPUER ;TEST "SPHL" AND "XTHL" + LDA TEMP2 + CPI 033H + CNZ CPUER ;TEST "SPHL" AND "XTHL" + MVI A,055H + CMP L + CNZ CPUER ;TEST "SPHL" AND "XTHL" + CMA + CMP H + CNZ CPUER ;TEST "SPHL" AND "XTHL" + LHLD SAVSTK ;RESTORE THE "OLD" STACK-POINTER + SPHL + LXI H,CPUOK + PCHL ;TEST "PCHL" +; +; +; +CPUER: LXI H,NGCPU ;OUTPUT "CPU HAS FAILED ERROR EXIT=" TO CONSOLE + CALL MSG + XTHL + MOV A,H + CALL BYTEO ;SHOW ERROR EXIT ADDRESS HIGH BYTE + MOV A,L + CALL BYTEO ;SHOW ERROR EXIT ADDRESS LOW BYTE + JMP WBOOT ;EXIT TO CP/M WARM BOOT +; +; +; +CPUOK: LXI H,OKCPU ;OUTPUT "CPU IS OPERATIONAL" TO CONSOLE + CALL MSG + JMP WBOOT ;EXIT TO CP/M WARM BOOT +; +; +; +TEMPP: DW TEMP0 ;POINTER USED TO TEST "LHLD","SHLD", + ; AND "LDAX" INSTRUCTIONS +; +TEMP0: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS +TEMP1: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS +TEMP2 DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS +TEMP3: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS +TEMP4: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS +SAVSTK: DS 2 ;TEMPORARY STACK-POINTER STORAGE LOCATION +; +; +; +STACK EQU TEMPP+256 ;DE-BUG STACK POINTER STORAGE AREA +; + END + diff --git a/Z80/test/roms/TEST.COM b/Z80/test/roms/TEST.COM new file mode 100644 index 0000000..a02ab70 Binary files /dev/null and b/Z80/test/roms/TEST.COM differ diff --git a/Z80/test/roms/prelim.com b/Z80/test/roms/prelim.com new file mode 100644 index 0000000..e5c82b5 Binary files /dev/null and b/Z80/test/roms/prelim.com differ diff --git a/Z80/test/roms/prelim.z80 b/Z80/test/roms/prelim.z80 new file mode 100644 index 0000000..7dc0fd3 --- /dev/null +++ b/Z80/test/roms/prelim.z80 @@ -0,0 +1,343 @@ + .title 'Preliminary Z80 tests' + +; prelim.z80 - Preliminary Z80 tests +; Copyright (C) 1994 Frank D. Cringle +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation; either version 2 +; of the License, or (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, write to the Free Software +; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +; These tests have two goals. To start with, we assume the worst and +; successively test the instructions needed to continue testing. +; Then we try to test all instructions which cannot be handled by +; zexlax - the crc-based instruction exerciser. + +; Initially errors are 'reported' by jumping to 0. This should reboot +; cp/m, so if the program terminates without any output one of the +; early tests failed. Later errors are reported by outputting an +; address via the bdos conout routine. The address can be located in +; a listing of this program. + +; If the program runs to completion it displays a suitable message. + + aseg + org 100h + +start: ld a,1 ; test simple compares and z/nz jumps + cp 2 + jp z,0 + cp 1 + jp nz,0 + jp lab0 + halt ; emergency exit + db 0ffh + +lab0: call lab2 ; does a simple call work? +lab1: jp 0 ; fail + +lab2: pop hl ; check return address + ld a,h + cp high lab1 + jp z,lab3 + jp 0 +lab3: ld a,l + cp low lab1 + jp z,lab4 + jp 0 + +; test presence and uniqueness of all machine registers +; (except ir) +lab4: ld sp,regs1 + pop af + pop bc + pop de + pop hl + ex af,af' + exx + pop af + pop bc + pop de + pop hl + pop ix + pop iy + ld sp,regs2+20 + push iy + push ix + push hl + push de + push bc + push af + ex af,af' + exx + push hl + push de + push bc + push af + +v: set 0 + rept 20 + ld a,(regs2+v/2) +v: set v+2 + cp v + jp nz,0 + endm + +; test access to memory via (hl) + ld hl,hlval + ld a,(hl) + cp 0a5h + jp nz,0 + ld hl,hlval+1 + ld a,(hl) + cp 03ch + jp nz,0 + +; test unconditional return + ld sp,stack + ld hl,reta + push hl + ret + jp 0 + +; test instructions needed for hex output +reta: ld a,255 + and a,15 + cp 15 + jp nz,0 + ld a,05ah + and 15 + cp 00ah + jp nz,0 + rrca + cp 005h + jp nz,0 + rrca + cp 082h + jp nz,0 + rrca + cp 041h + jp nz,0 + rrca + cp 0a0h + jp nz,0 + ld hl,01234h + push hl + pop bc + ld a,b + cp 012h + jp nz,0 + ld a,c + cp 034h + jp nz,0 + +; from now on we can report errors by displaying an address + +; test conditional call, ret, jp, jr +tcond: macro flag,pcond,ncond,rel + ld hl,&flag + push hl + pop af + call &pcond,lab1&pcond + jp error +lab1&pcond: pop hl + ld hl,0d7h xor &flag + push hl + pop af + call &ncond,lab2&pcond + jp error +lab2&pcond: pop hl + ld hl,lab3&pcond + push hl + ld hl,&flag + push hl + pop af + ret &pcond + call error +lab3&pcond: ld hl,lab4&pcond + push hl + ld hl,0d7h xor &flag + push hl + pop af + ret &ncond + call error +lab4&pcond: ld hl,&flag + push hl + pop af + jp &pcond,lab5&pcond + call error +lab5&pcond: ld hl,0d7h xor &flag + push hl + pop af + jp &ncond,lab6&pcond + call error +lab6&pcond: + if &rel + ld hl,&flag + push hl + pop af + jr &pcond,lab7&pcond + call error +lab7&pcond: ld hl,0d7h xor &flag + push hl + pop af + jr &ncond,lab8&pcond + call error +lab8&pcond: + endif + endm + + tcond 1,c,nc,1 + tcond 4,pe,po,0 + tcond 040h,z,nz,1 + tcond 080h,m,p,0 + +; test indirect jumps + ld hl,lab5 + jp (hl) + call error +lab5: ld hl,lab6 + push hl + pop ix + jp (ix) + call error +lab6: ld hl,lab7 + push hl + pop iy + jp (iy) + call error + +; djnz (and (partially) inc a, inc hl) +lab7: ld a,0a5h + ld b,4 +lab8: rrca + djnz lab8 + cp 05ah + call nz,error + ld b,16 +lab9: inc a + djnz lab9 + cp 06ah + call nz,error + ld b,0 + ld hl,0 +lab10: inc hl + djnz lab10 + ld a,h + cp 1 + call nz,error + ld a,l + cp 0 + call nz,error + +; relative addressing +reladr: macro r + ld &r,hlval + ld a,(&r) + cp 0a5h + call nz,error + ld a,(&r+1) + cp 03ch + call nz,error + inc &r + ld a,(&r-1) + cp 0a5h + call nz,error + ld &r,hlval-126 + ld a,(&r+127) + cp 03ch + call nz,error + ld &r,hlval+128 + ld a,(&r-128) + cp 0a5h + call nz,error + endm + + reladr ix + reladr iy + +allok: ld de,okmsg + ld c,9 + call 5 + jp 0 + +okmsg: db 'Preliminary tests complete$' + + +; display address at top of stack and exit +error: pop bc + ld h,high hextab + ld a,b + rrca + rrca + rrca + rrca + and 15 + ld l,a + ld a,(hl) + call conout + ld a,b + and 15 + ld l,a + ld a,(hl) + call conout + ld a,c + rrca + rrca + rrca + rrca + and 15 + ld l,a + ld a,(hl) + call conout + ld a,c + and 15 + ld l,a + ld a,(hl) + call conout + ld a,13 + call conout + ld a,10 + call conout + jp 0 + +conout: push af + push bc + push de + push hl + ld c,2 + ld e,a + call 5 + pop hl + pop de + pop bc + pop af + ret + +v: set 0 +regs1: rept 20 +v: set v+2 + db v + endm + +regs2: ds 20,0 + +hlval: db 0a5h,03ch + +; skip to next page boundary + org (($+255)/256)*256 +hextab: db '0123456789abcdef' + ds 240 +stack: equ $ + + end diff --git a/Z80/test/roms/zexall.com b/Z80/test/roms/zexall.com new file mode 100644 index 0000000..fa0e6ff Binary files /dev/null and b/Z80/test/roms/zexall.com differ diff --git a/Z80/test/roms/zexdoc.com b/Z80/test/roms/zexdoc.com new file mode 100644 index 0000000..5cfd531 Binary files /dev/null and b/Z80/test/roms/zexdoc.com differ diff --git a/Z80/test/roms/zexdoc.z80 b/Z80/test/roms/zexdoc.z80 new file mode 100644 index 0000000..2a56c84 --- /dev/null +++ b/Z80/test/roms/zexdoc.z80 @@ -0,0 +1,1546 @@ + .title 'Z80 instruction set exerciser' + +; zexlax.z80 - Z80 instruction set exerciser +; Copyright (C) 1994 Frank D. Cringle +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation; either version 2 +; of the License, or (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, write to the Free Software +; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + aseg + org 100h + + jp start + +; machine state before test (needs to be at predictably constant address) +msbt: ds 14 +spbt: ds 2 + +; For the purposes of this test program, the machine state consists of: +; a 2 byte memory operand, followed by +; the registers iy,ix,hl,de,bc,af,sp +; for a total of 16 bytes. + +; The program tests instructions (or groups of similar instructions) +; by cycling through a sequence of machine states, executing the test +; instruction for each one and running a 32-bit crc over the resulting +; machine states. At the end of the sequence the crc is compared to +; an expected value that was found empirically on a real Z80. + +; A test case is defined by a descriptor which consists of: +; a flag mask byte, +; the base case, +; the incement vector, +; the shift vector, +; the expected crc, +; a short descriptive message. +; +; The flag mask byte is used to prevent undefined flag bits from +; influencing the results. Documented flags are as per Mostek Z80 +; Technical Manual. +; +; The next three parts of the descriptor are 20 byte vectors +; corresponding to a 4 byte instruction and a 16 byte machine state. +; The first part is the base case, which is the first test case of +; the sequence. This base is then modified according to the next 2 +; vectors. Each 1 bit in the increment vector specifies a bit to be +; cycled in the form of a binary counter. For instance, if the byte +; corresponding to the accumulator is set to 0ffh in the increment +; vector, the test will be repeated for all 256 values of the +; accumulator. Note that 1 bits don't have to be contiguous. The +; number of test cases 'caused' by the increment vector is equal to +; 2^(number of 1 bits). The shift vector is similar, but specifies a +; set of bits in the test case that are to be successively inverted. +; Thus the shift vector 'causes' a number of test cases equal to the +; number of 1 bits in it. + +; The total number of test cases is the product of those caused by the +; counter and shift vectors and can easily become unweildy. Each +; individual test case can take a few milliseconds to execute, due to +; the overhead of test setup and crc calculation, so test design is a +; compromise between coverage and execution time. + +; This program is designed to detect differences between +; implementations and is not ideal for diagnosing the causes of any +; discrepancies. However, provided a reference implementation (or +; real system) is available, a failing test case can be isolated by +; hand using a binary search of the test space. + + +start: ld hl,(6) + ld sp,hl + ld de,msg1 + ld c,9 + call bdos + + ld hl,tests ; first test case +loop: ld a,(hl) ; end of list ? + inc hl + or (hl) + jp z,done + dec hl + call stt + jp loop + +done: ld de,msg2 + ld c,9 + call bdos + jp 0 ; warm boot + +tests: + dw adc16 + dw add16 + dw add16x + dw add16y + dw alu8i + dw alu8r + dw alu8rx + dw alu8x + dw bitx + dw bitz80 + dw cpd1 + dw cpi1 + dw daa + dw inca + dw incb + dw incbc + dw incc + dw incd + dw incde + dw ince + dw inch + dw inchl + dw incix + dw inciy + dw incl + dw incm + dw incsp + dw incx + dw incxh + dw incxl + dw incyh + dw incyl + dw ld161 + dw ld162 + dw ld163 + dw ld164 + dw ld165 + dw ld166 + dw ld167 + dw ld168 + dw ld16im + dw ld16ix + dw ld8bd + dw ld8im + dw ld8imx + dw ld8ix1 + dw ld8ix2 + dw ld8ix3 + dw ld8ixy + dw ld8rr + dw ld8rrx + dw lda + dw ldd1 + dw ldd2 + dw ldi1 + dw ldi2 + dw neg + dw rld + dw rot8080 + dw rotxy + dw rotz80 + dw srz80 + dw srzx + dw st8ix1 + dw st8ix2 + dw st8ix3 + dw stabd + dw 0 + +tstr: macro insn,memop,iy,ix,hl,de,bc,flags,acc,sp + local lab +&lab: db insn + ds &lab+4-$,0 + dw &memop,&iy,&ix,&hl,&de,&bc + db &flags + db &acc + dw &sp + if $-&lab ne 20 + error 'missing parameter' + endif + endm + +tmsg: macro m + local lab +&lab: db m + if $ ge &lab+30 + error 'message too long' + else + ds &lab+30-$,'.' + endif + db '$' + endm + +; hl, (38,912 cycles) +adc16: db 0c7h ; flag mask + tstr <0edh,042h>,0832ch,04f88h,0f22bh,0b339h,07e1fh,01563h,0d3h,089h,0465eh + tstr <0,038h>,0,0,0,0f821h,0,0,0,0,0 ; (1024 cycles) + tstr 0,0,0,0,-1,-1,-1,0d7h,0,-1 ; (38 cycles) + db 0f8h,0b4h,0eah,0a9h ; expected crc + tmsg ' hl,' + +; add hl, (19,456 cycles) +add16: db 0c7h ; flag mask + tstr 9,0c4a5h,0c4c7h,0d226h,0a050h,058eah,08566h,0c6h,0deh,09bc9h + tstr 030h,0,0,0,0f821h,0,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,-1,-1,-1,0d7h,0,-1 ; (38 cycles) + db 089h,0fdh,0b6h,035h ; expected crc + tmsg 'add hl,' + +; add ix, (19,456 cycles) +add16x: db 0c7h ; flag mask + tstr <0ddh,9>,0ddach,0c294h,0635bh,033d3h,06a76h,0fa20h,094h,068h,036f5h + tstr <0,030h>,0,0,0f821h,0,0,0,0,0,0 ; (512 cycles) + tstr 0,0,0,-1,0,-1,-1,0d7h,0,-1 ; (38 cycles) + db 0c1h,033h,079h,00bh ; expected crc + tmsg 'add ix,' + +; add iy, (19,456 cycles) +add16y: db 0c7h ; flag mask + tstr <0fdh,9>,0c7c2h,0f407h,051c1h,03e96h,00bf4h,0510fh,092h,01eh,071eah + tstr <0,030h>,0,0f821h,0,0,0,0,0,0,0 ; (512 cycles) + tstr 0,0,-1,0,0,-1,-1,0d7h,0,-1 ; (38 cycles) + db 0e8h,081h,07bh,09eh ; expected crc + tmsg 'add iy,' + +; aluop a,nn (28,672 cycles) +alu8i: db 0d7h ; flag mask + tstr 0c6h,09140h,07e3ch,07a67h,0df6dh,05b61h,00b29h,010h,066h,085b2h + tstr 038h,0,0,0,0,0,0,0,-1,0 ; (2048 cycles) + tstr <0,-1>,0,0,0,0,0,0,0d7h,0,0 ; (14 cycles) + db 048h,079h,093h,060h ; expected crc + tmsg 'aluop a,nn' + +; aluop a, (753,664 cycles) +alu8r: db 0d7h ; flag mask + tstr 080h,0c53eh,0573ah,04c4dh,msbt,0e309h,0a666h,0d0h,03bh,0adbbh + tstr 03fh,0,0,0,0,0,0,0,-1,0 ; (16,384 cycles) + tstr 0,0ffh,0,0,0,-1,-1,0d7h,0,0 ; (46 cycles) + db 0feh,043h,0b0h,016h ; expected crc + tmsg 'aluop a,' + +; aluop a, (376,832 cycles) +alu8rx: db 0d7h ; flag mask + tstr <0ddh,084h>,0d6f7h,0c76eh,0accfh,02847h,022ddh,0c035h,0c5h,038h,0234bh + tstr <020h,039h>,0,0,0,0,0,0,0,-1,0 ; (8,192 cycles) + tstr 0,0ffh,0,0,0,-1,-1,0d7h,0,0 ; (46 cycles) + db 0a4h,002h,06dh,05ah ; expected crc + tmsg 'aluop a,' + +; aluop a,(+1) (229,376 cycles) +alu8x: db 0d7h ; flag mask + tstr <0ddh,086h,1>,090b7h,msbt-1,msbt-1,032fdh,0406eh,0c1dch,045h,06eh,0e5fah + tstr <020h,038h>,0,1,1,0,0,0,0,-1,0 ; (16,384 cycles) + tstr 0,0ffh,0,0,0,0,0,0d7h,0,0 ; (14 cycles) + db 0e8h,049h,067h,06eh ; expected crc + tmsg 'aluop a,(+1)' + +; bit n,(+1) (2048 cycles) +bitx: db 053h ; flag mask + tstr <0ddh,0cbh,1,046h>,02075h,msbt-1,msbt-1,03cfch,0a79ah,03d74h,051h,027h,0ca14h + tstr <020h,0,0,038h>,0,0,0,0,0,0,053h,0,0 ; (256 cycles) + tstr 0,0ffh,0,0,0,0,0,0,0,0 ; (8 cycles) + db 0a8h,0eeh,008h,067h ; expected crc + tmsg 'bit n,(+1)' + +; bit n, (49,152 cycles) +bitz80: db 053h ; flag mask + tstr <0cbh,040h>,03ef1h,09dfch,07acch,msbt,0be61h,07a86h,050h,024h,01998h + tstr <0,03fh>,0,0,0,0,0,0,053h,0,0 ; (1024 cycles) + tstr 0,0ffh,0,0,0,-1,-1,0,-1,0 ; (48 cycles) + db 07bh,055h,0e6h,0c8h ; expected crc + tmsg 'bit n,' + +; cpd (1) (6144 cycles) +cpd1: db 0d7h ; flag mask + tstr <0edh,0a9h>,0c7b6h,072b4h,018f6h,msbt+17,08dbdh,1,0c0h,030h,094a3h + tstr <0,010h>,0,0,0,0,0,010,0,-1,0 ; (1024 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 0a8h,07eh,06ch,0fah ; expected crc + tmsg 'cpd' + +; cpi (1) (6144 cycles) +cpi1: db 0d7h ; flag mask + tstr <0edh,0a1h>,04d48h,0af4ah,0906bh,msbt,04e71h,1,093h,06ah,0907ch + tstr <0,010h>,0,0,0,0,0,010,0,-1,0 ; (1024 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 006h,0deh,0b3h,056h ; expected crc + tmsg 'cpi' + +; +daa: db 0d7h ; flag mask + tstr 027h,02141h,009fah,01d60h,0a559h,08d5bh,09079h,004h,08eh,0299dh + tstr 018h,0,0,0,0,0,0,0d7h,-1,0 ; (65,536 cycles) + tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) + db 09bh,04bh,0a6h,075h ; expected crc + tmsg '' + +; a (3072 cycles) +inca: db 0d7h ; flag mask + tstr 03ch,04adfh,0d5d8h,0e598h,08a2bh,0a7b0h,0431bh,044h,05ah,0d030h + tstr 001h,0,0,0,0,0,0,0,-1,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 0d1h,088h,015h,0a4h ; expected crc + tmsg ' a' + +; b (3072 cycles) +incb: db 0d7h ; flag mask + tstr 004h,0d623h,0432dh,07a61h,08180h,05a86h,01e85h,086h,058h,09bbbh + tstr 001h,0,0,0,0,0,0ff00h,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 05fh,068h,022h,064h ; expected crc + tmsg ' b' + +; bc (1536 cycles) +incbc: db 0d7h ; flag mask + tstr 003h,0cd97h,044abh,08dc9h,0e3e3h,011cch,0e8a4h,002h,049h,02a4dh + tstr 008h,0,0,0,0,0,0f821h,0,0,0 ; (256 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 0d2h,0aeh,03bh,0ech ; expected crc + tmsg ' bc' + +; c (3072 cycles) +incc: db 0d7h ; flag mask + tstr 00ch,0d789h,00935h,0055bh,09f85h,08b27h,0d208h,095h,005h,00660h + tstr 001h,0,0,0,0,0,0ffh,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 0c2h,084h,055h,04ch ; expected crc + tmsg ' c' + +; d (3072 cycles) +incd: db 0d7h ; flag mask + tstr 014h,0a0eah,05fbah,065fbh,0981ch,038cch,0debch,043h,05ch,003bdh + tstr 001h,0,0,0,0,0ff00h,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 045h,023h,0deh,010h ; expected crc + tmsg ' d' + +; de (1536 cycles) +incde: db 0d7h ; flag mask + tstr 013h,0342eh,0131dh,028c9h,00acah,09967h,03a2eh,092h,0f6h,09d54h + tstr 008h,0,0,0,0,0f821h,0,0,0,0 ; (256 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 0aeh,0c6h,0d4h,02ch ; expected crc + tmsg ' de' + +; e (3072 cycles) +ince: db 0d7h ; flag mask + tstr 01ch,0602fh,04c0dh,02402h,0e2f5h,0a0f4h,0a10ah,013h,032h,05925h + tstr 001h,0,0,0,0,0ffh,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 0e1h,075h,0afh,0cch ; expected crc + tmsg ' e' + +; h (3072 cycles) +inch: db 0d7h ; flag mask + tstr 024h,01506h,0f2ebh,0e8ddh,0262bh,011a6h,0bc1ah,017h,006h,02818h + tstr 001h,0,0,0,0ff00h,0,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 01ch,0edh,084h,07dh ; expected crc + tmsg ' h' + +; hl (1536 cycles) +inchl: db 0d7h ; flag mask + tstr 023h,0c3f4h,007a5h,01b6dh,04f04h,0e2c2h,0822ah,057h,0e0h,0c3e1h + tstr 008h,0,0,0,0f821h,0,0,0,0,0 ; (256 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 0fch,00dh,06dh,04ah ; expected crc + tmsg ' hl' + +; ix (1536 cycles) +incix: db 0d7h ; flag mask + tstr <0ddh,023h>,0bc3ch,00d9bh,0e081h,0adfdh,09a7fh,096e5h,013h,085h,00be2h + tstr <0,8>,0,0,0f821h,0,0,0,0,0,0 ; (256 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 0a5h,04dh,0beh,031h ; expected crc + tmsg ' ix' + +; iy (1536 cycles) +inciy: db 0d7h ; flag mask + tstr <0fdh,023h>,09402h,0637ah,03182h,0c65ah,0b2e9h,0abb4h,016h,0f2h,06d05h + tstr <0,8>,0,0f821h,0,0,0,0,0,0,0 ; (256 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 050h,05dh,051h,0a3h ; expected crc + tmsg ' iy' + +; l (3072 cycles) +incl: db 0d7h ; flag mask + tstr 02ch,08031h,0a520h,04356h,0b409h,0f4c1h,0dfa2h,0d1h,03ch,03ea2h + tstr 001h,0,0,0,0ffh,0,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 056h,0cdh,006h,0f3h ; expected crc + tmsg ' l' + +; (hl) (3072 cycles) +incm: db 0d7h ; flag mask + tstr 034h,0b856h,00c7ch,0e53eh,msbt,0877eh,0da58h,015h,05ch,01f37h + tstr 001h,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 0b8h,03ah,0dch,0efh ; expected crc + tmsg ' (hl)' + +; sp (1536 cycles) +incsp: db 0d7h ; flag mask + tstr 033h,0346fh,0d482h,0d169h,0deb6h,0a494h,0f476h,053h,002h,0855bh + tstr 008h,0,0,0,0,0,0,0,0,0f821h ; (256 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 05dh,0ach,0d5h,027h ; expected crc + tmsg ' sp' + +; (+1) (6144 cycles) +incx: db 0d7h ; flag mask + tstr <0ddh,034h,1>,0fa6eh,msbt-1,msbt-1,02c28h,08894h,05057h,016h,033h,0286fh + tstr <020h,1>,0ffh,0,0,0,0,0,0,0,0 ; (1024 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 020h,058h,014h,070h ; expected crc + tmsg ' (+1)' + +; ixh (3072 cycles) +incxh: db 0d7h ; flag mask + tstr <0ddh,024h>,0b838h,0316ch,0c6d4h,03e01h,08358h,015b4h,081h,0deh,04259h + tstr <0,1>,0,0ff00h,0,0,0,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 06fh,046h,036h,062h ; expected crc + tmsg ' ixh' + +; ixl (3072 cycles) +incxl: db 0d7h ; flag mask + tstr <0ddh,02ch>,04d14h,07460h,076d4h,006e7h,032a2h,0213ch,0d6h,0d7h,099a5h + tstr <0,1>,0,0ffh,0,0,0,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 002h,07bh,0efh,02ch ; expected crc + tmsg ' ixl' + +; iyh (3072 cycles) +incyh: db 0d7h ; flag mask + tstr <0ddh,024h>,02836h,09f6fh,09116h,061b9h,082cbh,0e219h,092h,073h,0a98ch + tstr <0,1>,0ff00h,0,0,0,0,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 02dh,096h,06ch,0f3h ; expected crc + tmsg ' iyh' + +; iyl (3072 cycles) +incyl: db 0d7h ; flag mask + tstr <0ddh,02ch>,0d7c6h,062d5h,0a09eh,07039h,03e7eh,09f12h,090h,0d9h,0220fh + tstr <0,1>,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 0fbh,0cbh,0bah,095h ; expected crc + tmsg ' iyl' + +; ld ,(nnnn) (32 cycles) +ld161: db 0d7h ; flag mask + tstr <0edh,04bh,low msbt,high msbt>,0f9a8h,0f559h,093a4h,0f5edh,06f96h,0d968h,086h,0e6h,04bd8h + tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) + db 04dh,045h,0a9h,0ach ; expected crc + tmsg 'ld ,(nnnn)' + +; ld hl,(nnnn) (16 cycles) +ld162: db 0d7h ; flag mask + tstr <02ah,low msbt,high msbt>,09863h,07830h,02077h,0b1feh,0b9fah,0abb8h,004h,006h,06015h + tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) + tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) + db 05fh,097h,024h,087h ; expected crc + tmsg 'ld hl,(nnnn)' + +; ld sp,(nnnn) (16 cycles) +ld163: db 0d7h ; flag mask + tstr <0edh,07bh,low msbt,high msbt>,08dfch,057d7h,02161h,0ca18h,0c185h,027dah,083h,01eh,0f460h + tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycles) + tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) + db 07ah,0ceh,0a1h,01bh ; expected crc + tmsg 'ld sp,(nnnn)' + +; ld ,(nnnn) (32 cycles) +ld164: db 0d7h ; flag mask + tstr <0ddh,02ah,low msbt,high msbt>,0ded7h,0a6fah,0f780h,0244ch,087deh,0bcc2h,016h,063h,04c96h + tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) + db 085h,08bh,0f1h,06dh ; expected crc + tmsg 'ld ,(nnnn)' + +; ld (nnnn), (64 cycles) +ld165: db 0d7h ; flag mask + tstr <0edh,043h,low msbt,high msbt>,01f98h,0844dh,0e8ach,0c9edh,0c95dh,08f61h,080h,03fh,0c7bfh + tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr 0,0,0,0,0,-1,-1,0,0,0 ; (32 cycles) + db 064h,01eh,087h,015h ; expected crc + tmsg 'ld (nnnn),' + +; ld (nnnn),hl (16 cycles) +ld166: db 0d7h ; flag mask + tstr <022h,low msbt,high msbt>,0d003h,07772h,07f53h,03f72h,064eah,0e180h,010h,02dh,035e9h + tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) + tstr 0,0,0,0,-1,0,0,0,0,0 ; (16 cycles) + db 0a3h,060h,08bh,047h ; expected crc + tmsg 'ld (nnnn),hl' + +; ld (nnnn),sp (16 cycles) +ld167: db 0d7h ; flag mask + tstr <0edh,073h,low msbt,high msbt>,0c0dch,0d1d6h,0ed5ah,0f356h,0afdah,06ca7h,044h,09fh,03f0ah + tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) + tstr 0,0,0,0,0,0,0,0,0,-1 ; (16 cycles) + db 016h,058h,05fh,0d7h ; expected crc + tmsg 'ld (nnnn),sp' + +; ld (nnnn), (64 cycles) +ld168: db 0d7h ; flag mask + tstr <0ddh,022h,low msbt,high msbt>,06cc3h,00d91h,06900h,08ef8h,0e3d6h,0c3f7h,0c6h,0d9h,0c2dfh + tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr 0,0,-1,-1,0,0,0,0,0,0 ; (32 cycles) + db 0bah,010h,02ah,06bh ; expected crc + tmsg 'ld (nnnn),' + +; ld ,nnnn (64 cycles) +ld16im: db 0d7h ; flag mask + tstr 1,05c1ch,02d46h,08eb9h,06078h,074b1h,0b30eh,046h,0d1h,030cch + tstr 030h,0,0,0,0,0,0,0,0,0 ; (4 cycles) + tstr <0,0ffh,0ffh>,0,0,0,0,0,0,0,0,0 ; (16 cycles) + db 0deh,039h,019h,069h ; expected crc + tmsg 'ld ,nnnn' + +; ld ,nnnn (32 cycles) +ld16ix: db 0d7h ; flag mask + tstr <0ddh,021h>,087e8h,02006h,0bd12h,0b69bh,07253h,0a1e5h,051h,013h,0f1bdh + tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr <0,0,0ffh,0ffh>,0,0,0,0,0,0,0,0,0 ; (16 cycles) + db 022h,07dh,0d5h,025h ; expected crc + tmsg 'ld ,nnnn' + +; ld a,<(bc),(de)> (44 cycles) +ld8bd: db 0d7h ; flag mask + tstr 00ah,0b3a8h,01d2ah,07f8eh,042ach,msbt,msbt,0c6h,0b1h,0ef8eh + tstr 010h,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles) + db 0b0h,081h,089h,035h ; expected crc + tmsg 'ld a,<(bc),(de)>' + +; ld ,nn (64 cycles) +ld8im: db 0d7h ; flag mask + tstr 6,0c407h,0f49dh,0d13dh,00339h,0de89h,07455h,053h,0c0h,05509h + tstr 038h,0,0,0,0,0,0,0,0,0 ; (8 cycles) + tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) + db 0f1h,0dah,0b5h,056h ; expected crc + tmsg 'ld ,nn' + +; ld (+1),nn (32 cycles) +ld8imx: db 0d7h ; flag mask + tstr <0ddh,036h,1>,01b45h,msbt-1,msbt-1,0d5c1h,061c7h,0bdc4h,0c0h,085h,0cd16h + tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr <0,0,0,-1>,0,0,0,0,0,0,0,-1,0 ; (16 cycles) + db 026h,0dbh,047h,07eh ; expected crc + tmsg 'ld (+1),nn' + +; ld ,(+1) (512 cycles) +ld8ix1: db 0d7h ; flag mask + tstr <0ddh,046h,1>,0d016h,msbt-1,msbt-1,04260h,07f39h,00404h,097h,04ah,0d085h + tstr <020h,018h>,0,1,1,0,0,0,0,0,0 ; (32 cycles) + tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) + db 0cch,011h,006h,0a8h ; expected crc + tmsg 'ld ,(+1)' + +; ld ,(+1) (256 cycles) +ld8ix2: db 0d7h ; flag mask + tstr <0ddh,066h,1>,084e0h,msbt-1,msbt-1,09c52h,0a799h,049b6h,093h,000h,0eeadh + tstr <020h,008h>,0,1,1,0,0,0,0,0,0 ; (16 cycles) + tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) + db 0fah,02ah,04dh,003h ; expected crc + tmsg 'ld ,(+1)' + +; ld a,(+1) (128 cycles) +ld8ix3: db 0d7h ; flag mask + tstr <0ddh,07eh,1>,0d8b6h,msbt-1,msbt-1,0c612h,0df07h,09cd0h,043h,0a6h,0a0e5h + tstr 020h,0,1,1,0,0,0,0,0,0 ; (8 cycles) + tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) + db 0a5h,0e9h,0ach,064h ; expected crc + tmsg 'ld a,(+1)' + +; ld ,nn (32 cycles) +ld8ixy: db 0d7h ; flag mask + tstr <0ddh,026h>,03c53h,04640h,0e179h,07711h,0c107h,01afah,081h,0adh,05d9bh + tstr <020h,8>,0,0,0,0,0,0,0,0,0 ; (4 cycles) + tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) + db 024h,0e8h,082h,08bh ; expected crc + tmsg 'ld ,nn' + +; ld , (3456 cycles) +ld8rr: db 0d7h ; flag mask + tstr 040h,072a4h,0a024h,061ach,msbt,082c7h,0718fh,097h,08fh,0ef8eh + tstr 03fh,0,0,0,0,0,0,0,0,0 ; (64 cycles) + tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (54 cycles) + db 074h,04bh,001h,018h ; expected crc + tmsg 'ld ,' + +; ld , (6912 cycles) +ld8rrx: db 0d7h ; flag mask + tstr <0ddh,040h>,0bcc5h,msbt,msbt,msbt,02fc2h,098c0h,083h,01fh,03bcdh + tstr <020h,03fh>,0,0,0,0,0,0,0,0,0 ; (128 cycles) + tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (54 cycles) + db 047h,08bh,0a3h,06bh ; expected crc + tmsg 'ld ,' + +; ld a,(nnnn) / ld (nnnn),a (44 cycles) +lda: db 0d7h ; flag mask + tstr <032h,low msbt,high msbt>,0fd68h,0f4ech,044a0h,0b543h,00653h,0cdbah,0d2h,04fh,01fd8h + tstr 008h,0,0,0,0,0,0,0,0,0 ; (2 cycle) + tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles) + db 0c9h,026h,02dh,0e5h ; expected crc + tmsg 'ld a,(nnnn) / ld (nnnn),a' + +; ldd (1) (44 cycles) +ldd1: db 0d7h ; flag mask + tstr <0edh,0a8h>,09852h,068fah,066a1h,msbt+3,msbt+1,1,0c1h,068h,020b7h + tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) + db 094h,0f4h,027h,069h ; expected crc + tmsg 'ldd (1)' + +; ldd (2) (44 cycles) +ldd2: db 0d7h ; flag mask + tstr <0edh,0a8h>,0f12eh,0eb2ah,0d5bah,msbt+3,msbt+1,2,047h,0ffh,0fbe4h + tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) + db 05ah,090h,07eh,0d4h ; expected crc + tmsg 'ldd (2)' + +; ldi (1) (44 cycles) +ldi1: db 0d7h ; flag mask + tstr <0edh,0a0h>,0fe30h,003cdh,06058h,msbt+2,msbt,1,004h,060h,02688h + tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) + db 09ah,0bdh,0f6h,0b5h ; expected crc + tmsg 'ldi (1)' + +; ldi (2) (44 cycles) +ldi2: db 0d7h ; flag mask + tstr <0edh,0a0h>,04aceh,0c26eh,0b188h,msbt+2,msbt,2,014h,02dh,0a39fh + tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) + tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) + db 0ebh,059h,089h,01bh ; expected crc + tmsg 'ldi (2)' + +; neg (16,384 cycles) +neg: db 0d7h ; flag mask + tstr <0edh,044h>,038a2h,05f6bh,0d934h,057e4h,0d2d6h,04642h,043h,05ah,009cch + tstr 0,0,0,0,0,0,0,0d7h,-1,0 ; (16,384 cycles) + tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) + db 06ah,03ch,03bh,0bdh ; expected crc + tmsg 'neg' + +; (7168 cycles) +rld: db 0d7h ; flag mask + tstr <0edh,067h>,091cbh,0c48bh,0fa62h,msbt,0e720h,0b479h,040h,006h,08ae2h + tstr <0,8>,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) + tstr 0,0,0,0,0,0,0,0d7h,-1,0 ; (14 cycles) + db 095h,05bh,0a3h,026h ; expected crc + tmsg '' + +; (6144 cycles) +rot8080: db 0d7h ; flag mask + tstr 7,0cb92h,06d43h,00a90h,0c284h,00c53h,0f50eh,091h,0ebh,040fch + tstr 018h,0,0,0,0,0,0,0,-1,0 ; (1024 cycles) + tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) + db 025h,013h,030h,0aeh ; expected crc + tmsg '' + +; shift/rotate (+1) (416 cycles) +rotxy: db 0d7h ; flag mask + tstr <0ddh,0cbh,1,6>,0ddafh,msbt-1,msbt-1,0ff3ch,0dbf6h,094f4h,082h,080h,061d9h + tstr <020h,0,0,038h>,0,0,0,0,0,0,080h,0,0 ; (32 cycles) + tstr 0,0ffh,0,0,0,0,0,057h,0,0 ; (13 cycles) + db 071h,03ah,0cdh,081h ; expected crc + tmsg 'shf/rot (+1)' + +; shift/rotate (6784 cycles) +rotz80: db 0d7h ; flag mask + tstr 0cbh,0ccebh,05d4ah,0e007h,msbt,01395h,030eeh,043h,078h,03dadh + tstr <0,03fh>,0,0,0,0,0,0,080h,0,0 ; (128 cycles) + tstr 0,0ffh,0,0,0,-1,-1,057h,-1,0 ; (53 cycles) + db 0ebh,060h,04dh,058h ; expected crc + tmsg 'shf/rot ' + +; n, (7936 cycles) +srz80: db 0d7h ; flag mask + tstr <0cbh,080h>,02cd5h,097abh,039ffh,msbt,0d14bh,06ab2h,053h,027h,0b538h + tstr <0,07fh>,0,0,0,0,0,0,0,0,0 ; (128 cycles) + tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (62 cycles) + db 08bh,057h,0f0h,008h ; expected crc + tmsg ' n,' + +; n,(+1) (1792 cycles) +srzx: db 0d7h ; flag mask + tstr <0ddh,0cbh,1,086h>,0fb44h,msbt-1,msbt-1,0ba09h,068beh,032d8h,010h,05eh,0a867h + tstr <020h,0,0,078h>,0,0,0,0,0,0,0,0,0 ; (128 cycles) + tstr 0,0ffh,0,0,0,0,0,0d7h,0,0 ;(14 cycles) + db 0cch,063h,0f9h,08ah ; expected crc + tmsg ' n,(+1)' + +; ld (+1), (1024 cycles) +st8ix1: db 0d7h ; flag mask + tstr <0ddh,070h,1>,0270dh,msbt-1,msbt-1,0b73ah,0887bh,099eeh,086h,070h,0ca07h + tstr <020h,003h>,0,1,1,0,0,0,0,0,0 ; (32 cycles) + tstr 0,0,0,0,0,-1,-1,0,0,0 ; (32 cycles) + db 004h,062h,06ah,0bfh ; expected crc + tmsg 'ld (+1),' + +; ld (+1), (256 cycles) +st8ix2: db 0d7h ; flag mask + tstr <0ddh,074h,1>,0b664h,msbt-1,msbt-1,0e8ach,0b5f5h,0aafeh,012h,010h,09566h + tstr <020h,001h>,0,1,1,0,0,0,0,0,0 ; (16 cycles) + tstr 0,0,0,0,-1,0,0,0,0,0 ; (32 cycles) + db 06ah,01ah,088h,031h ; expected crc + tmsg 'ld (+1),' + +; ld (+1),a (64 cycles) +st8ix3: db 0d7h ; flag mask + tstr <0ddh,077h,1>,067afh,msbt-1,msbt-1,04f13h,00644h,0bcd7h,050h,0ach,05fafh + tstr 020h,0,1,1,0,0,0,0,0,0 ; (8 cycles) + tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) + db 0cch,0beh,05ah,096h ; expected crc + tmsg 'ld (+1),a' + +; ld (),a (96 cycles) +stabd: db 0d7h ; flag mask + tstr 2,00c3bh,0b592h,06cffh,0959eh,msbt,msbt+1,0c1h,021h,0bde7h + tstr 018h,0,0,0,0,0,0,0,0,0 ; (4 cycles) + tstr 0,-1,0,0,0,0,0,0,-1,0 ; (24 cycles) + db 07ah,04ch,011h,04fh ; expected crc + tmsg 'ld (),a' + +; start test pointed to by (hl) +stt: push hl + ld a,(hl) ; get pointer to test + inc hl + ld h,(hl) + ld l,a + ld a,(hl) ; flag mask + ld (flgmsk+1),a + inc hl + push hl + ld de,20 + add hl,de ; point to incmask + ld de,counter + call initmask + pop hl + push hl + ld de,20+20 + add hl,de ; point to scanmask + ld de,shifter + call initmask + ld hl,shifter + ld (hl),1 ; first bit + pop hl + push hl + ld de,iut ; copy initial instruction under test + ld bc,4 + ldir + ld de,msbt ; copy initial machine state + ld bc,16 + ldir + ld de,20+20+4 ; skip incmask, scanmask and expcrc + add hl,de + ex de,hl + ld c,9 + call bdos ; show test name + call initcrc ; initialise crc +; test loop +tlp: ld a,(iut) + cp 076h ; pragmatically avoid halt intructions + jp z,tlp2 + and a,0dfh + cp 0ddh + jp nz,tlp1 + ld a,(iut+1) + cp 076h +tlp1: call nz,test ; execute the test instruction +tlp2: call count ; increment the counter + call nz,shift ; shift the scan bit + pop hl ; pointer to test case + jp z,tlp3 ; done if shift returned NZ + ld de,20+20+20 + add hl,de ; point to expected crc + call cmpcrc + ld de,okmsg + jp z,tlpok + ld de,ermsg1 + ld c,9 + call bdos + call phex8 + ld de,ermsg2 + ld c,9 + call bdos + ld hl,crcval + call phex8 + ld de,crlf +tlpok: ld c,9 + call bdos + pop hl + inc hl + inc hl + ret + +tlp3: push hl + ld a,1 ; initialise count and shift scanners + ld (cntbit),a + ld (shfbit),a + ld hl,counter + ld (cntbyt),hl + ld hl,shifter + ld (shfbyt),hl + + ld b,4 ; bytes in iut field + pop hl ; pointer to test case + push hl + ld de,iut + call setup ; setup iut + ld b,16 ; bytes in machine state + ld de,msbt + call setup ; setup machine state + jp tlp + +; setup a field of the test case +; b = number of bytes +; hl = pointer to base case +; de = destination +setup: call subyte + inc hl + dec b + jp nz,setup + ret + +subyte: push bc + push de + push hl + ld c,(hl) ; get base byte + ld de,20 + add hl,de ; point to incmask + ld a,(hl) + cp 0 + jp z,subshf + ld b,8 ; 8 bits +subclp: rrca + push af + ld a,0 + call c,nxtcbit ; get next counter bit if mask bit was set + xor c ; flip bit if counter bit was set + rrca + ld c,a + pop af + dec b + jp nz,subclp + ld b,8 +subshf: ld de,20 + add hl,de ; point to shift mask + ld a,(hl) + cp 0 + jp z,substr + ld b,8 ; 8 bits +sbshf1: rrca + push af + ld a,0 + call c,nxtsbit ; get next shifter bit if mask bit was set + xor c ; flip bit if shifter bit was set + rrca + ld c,a + pop af + dec b + jp nz,sbshf1 +substr: pop hl + pop de + ld a,c + ld (de),a ; mangled byte to destination + inc de + pop bc + ret + +; get next counter bit in low bit of a +cntbit: ds 1 +cntbyt: ds 2 + +nxtcbit: push bc + push hl + ld hl,(cntbyt) + ld b,(hl) + ld hl,cntbit + ld a,(hl) + ld c,a + rlca + ld (hl),a + cp a,1 + jp nz,ncb1 + ld hl,(cntbyt) + inc hl + ld (cntbyt),hl +ncb1: ld a,b + and c + pop hl + pop bc + ret z + ld a,1 + ret + +; get next shifter bit in low bit of a +shfbit: ds 1 +shfbyt: ds 2 + +nxtsbit: push bc + push hl + ld hl,(shfbyt) + ld b,(hl) + ld hl,shfbit + ld a,(hl) + ld c,a + rlca + ld (hl),a + cp a,1 + jp nz,nsb1 + ld hl,(shfbyt) + inc hl + ld (shfbyt),hl +nsb1: ld a,b + and c + pop hl + pop bc + ret z + ld a,1 + ret + + +; clear memory at hl, bc bytes +clrmem: push af + push bc + push de + push hl + ld (hl),0 + ld d,h + ld e,l + inc de + dec bc + ldir + pop hl + pop de + pop bc + pop af + ret + +; initialise counter or shifter +; de = pointer to work area for counter or shifter +; hl = pointer to mask +initmask: + push de + ex de,hl + ld bc,20+20 + call clrmem ; clear work area + ex de,hl + ld b,20 ; byte counter + ld c,1 ; first bit + ld d,0 ; bit counter +imlp: ld e,(hl) +imlp1: ld a,e + and a,c + jp z,imlp2 + inc d +imlp2: ld a,c + rlca + ld c,a + cp a,1 + jp nz,imlp1 + inc hl + dec b + jp nz,imlp +; got number of 1-bits in mask in reg d + ld a,d + and 0f8h + rrca + rrca + rrca ; divide by 8 (get byte offset) + ld l,a + ld h,0 + ld a,d + and a,7 ; bit offset + inc a + ld b,a + ld a,080h +imlp3: rlca + dec b + jp nz,imlp3 + pop de + add hl,de + ld de,20 + add hl,de + ld (hl),a + ret + +; multi-byte counter +count: push bc + push de + push hl + ld hl,counter ; 20 byte counter starts here + ld de,20 ; somewhere in here is the stop bit + ex de,hl + add hl,de + ex de,hl +cntlp: inc (hl) + ld a,(hl) + cp 0 + jp z,cntlp1 ; overflow to next byte + ld b,a + ld a,(de) + and a,b ; test for terminal value + jp z,cntend + ld (hl),0 ; reset to zero +cntend: pop bc + pop de + pop hl + ret + +cntlp1: inc hl + inc de + jp cntlp + + +; multi-byte shifter +shift: push bc + push de + push hl + ld hl,shifter ; 20 byte shift register starts here + ld de,20 ; somewhere in here is the stop bit + ex de,hl + add hl,de + ex de,hl +shflp: ld a,(hl) + or a + jp z,shflp1 + ld b,a + ld a,(de) + and b + jp nz,shlpe + ld a,b + rlca + cp a,1 + jp nz,shflp2 + ld (hl),0 + inc hl + inc de +shflp2: ld (hl),a + xor a ; set Z +shlpe: pop hl + pop de + pop bc + ret +shflp1: inc hl + inc de + jp shflp + +counter: ds 2*20 +shifter: ds 2*20 + +; test harness +test: push af + push bc + push de + push hl + if 0 + ld de,crlf + ld c,9 + call bdos + ld hl,iut + ld b,4 + call hexstr + ld e,' ' + ld c,2 + call bdos + ld b,16 + ld hl,msbt + call hexstr + endif + di ; disable interrupts + ld (spsav),sp ; save stack pointer + ld sp,msbt+2 ; point to test-case machine state + pop iy ; and load all regs + pop ix + pop hl + pop de + pop bc + pop af + ld sp,(spbt) +iut: ds 4 ; max 4 byte instruction under test + ld (spat),sp ; save stack pointer + ld sp,spat + push af ; save other registers + push bc + push de + push hl + push ix + push iy + ld sp,(spsav) ; restore stack pointer + ei ; enable interrupts + ld hl,(msbt) ; copy memory operand + ld (msat),hl + ld hl,flgsat ; flags after test + ld a,(hl) +flgmsk: and a,0d7h ; mask-out irrelevant bits (self-modified code!) + ld (hl),a + ld b,16 ; total of 16 bytes of state + ld de,msat + ld hl,crcval +tcrc: ld a,(de) + inc de + call updcrc ; accumulate crc of this test case + dec b + jp nz,tcrc + if 0 + ld e,' ' + ld c,2 + call bdos + ld hl,crcval + call phex8 + ld de,crlf + ld c,9 + call bdos + ld hl,msat + ld b,16 + call hexstr + ld de,crlf + ld c,9 + call bdos + endif + pop hl + pop de + pop bc + pop af + ret + +; machine state after test +msat: ds 14 ; memop,iy,ix,hl,de,bc,af +spat: ds 2 ; stack pointer after test +flgsat: equ spat-2 ; flags + +spsav: ds 2 ; saved stack pointer + +; display hex string (pointer in hl, byte count in b) +hexstr: ld a,(hl) + call phex2 + inc hl + dec b + jp nz,hexstr + ret + +; display hex +; display the big-endian 32-bit value pointed to by hl +phex8: push af + push bc + push hl + ld b,4 +ph8lp: ld a,(hl) + call phex2 + inc hl + dec b + jp nz,ph8lp + pop hl + pop bc + pop af + ret + +; display byte in a +phex2: push af + rrca + rrca + rrca + rrca + call phex1 + pop af +; fall through + +; display low nibble in a +phex1: push af + push bc + push de + push hl + and a,0fh + cp a,10 + jp c,ph11 + add a,'a'-'9'-1 +ph11: add a,'0' + ld e,a + ld c,2 + call bdos + pop hl + pop de + pop bc + pop af + ret + +bdos push af + push bc + push de + push hl + call 5 + pop hl + pop de + pop bc + pop af + ret + +msg1: db 'Z80 instruction exerciser',10,13,'$' +msg2: db 'Tests complete$' +okmsg: db ' OK',10,13,'$' +ermsg1: db ' ERROR **** crc expected:$' +ermsg2: db ' found:$' +crlf: db 10,13,'$' + +; compare crc +; hl points to value to compare to crcval +cmpcrc: push bc + push de + push hl + ld de,crcval + ld b,4 +cclp: ld a,(de) + cp a,(hl) + jp nz,cce + inc hl + inc de + dec b + jp nz,cclp +cce: pop hl + pop de + pop bc + ret + +; 32-bit crc routine +; entry: a contains next byte, hl points to crc +; exit: crc updated +updcrc: push af + push bc + push de + push hl + push hl + ld de,3 + add hl,de ; point to low byte of old crc + xor a,(hl) ; xor with new byte + ld l,a + ld h,0 + add hl,hl ; use result as index into table of 4 byte entries + add hl,hl + ex de,hl + ld hl,crctab + add hl,de ; point to selected entry in crctab + ex de,hl + pop hl + ld bc,4 ; c = byte count, b = accumulator +crclp: ld a,(de) + xor a,b + ld b,(hl) + ld (hl),a + inc de + inc hl + dec c + jp nz,crclp + if 0 + ld hl,crcval + call phex8 + ld de,crlf + ld c,9 + call bdos + endif + pop hl + pop de + pop bc + pop af + ret + +initcrc:push af + push bc + push hl + ld hl,crcval + ld a,0ffh + ld b,4 +icrclp: ld (hl),a + inc hl + dec b + jp nz,icrclp + pop hl + pop bc + pop af + ret + +crcval ds 4 + +crctab: db 000h,000h,000h,000h + db 077h,007h,030h,096h + db 0eeh,00eh,061h,02ch + db 099h,009h,051h,0bah + db 007h,06dh,0c4h,019h + db 070h,06ah,0f4h,08fh + db 0e9h,063h,0a5h,035h + db 09eh,064h,095h,0a3h + db 00eh,0dbh,088h,032h + db 079h,0dch,0b8h,0a4h + db 0e0h,0d5h,0e9h,01eh + db 097h,0d2h,0d9h,088h + db 009h,0b6h,04ch,02bh + db 07eh,0b1h,07ch,0bdh + db 0e7h,0b8h,02dh,007h + db 090h,0bfh,01dh,091h + db 01dh,0b7h,010h,064h + db 06ah,0b0h,020h,0f2h + db 0f3h,0b9h,071h,048h + db 084h,0beh,041h,0deh + db 01ah,0dah,0d4h,07dh + db 06dh,0ddh,0e4h,0ebh + db 0f4h,0d4h,0b5h,051h + db 083h,0d3h,085h,0c7h + db 013h,06ch,098h,056h + db 064h,06bh,0a8h,0c0h + db 0fdh,062h,0f9h,07ah + db 08ah,065h,0c9h,0ech + db 014h,001h,05ch,04fh + db 063h,006h,06ch,0d9h + db 0fah,00fh,03dh,063h + db 08dh,008h,00dh,0f5h + db 03bh,06eh,020h,0c8h + db 04ch,069h,010h,05eh + db 0d5h,060h,041h,0e4h + db 0a2h,067h,071h,072h + db 03ch,003h,0e4h,0d1h + db 04bh,004h,0d4h,047h + db 0d2h,00dh,085h,0fdh + db 0a5h,00ah,0b5h,06bh + db 035h,0b5h,0a8h,0fah + db 042h,0b2h,098h,06ch + db 0dbh,0bbh,0c9h,0d6h + db 0ach,0bch,0f9h,040h + db 032h,0d8h,06ch,0e3h + db 045h,0dfh,05ch,075h + db 0dch,0d6h,00dh,0cfh + db 0abh,0d1h,03dh,059h + db 026h,0d9h,030h,0ach + db 051h,0deh,000h,03ah + db 0c8h,0d7h,051h,080h + db 0bfh,0d0h,061h,016h + db 021h,0b4h,0f4h,0b5h + db 056h,0b3h,0c4h,023h + db 0cfh,0bah,095h,099h + db 0b8h,0bdh,0a5h,00fh + db 028h,002h,0b8h,09eh + db 05fh,005h,088h,008h + db 0c6h,00ch,0d9h,0b2h + db 0b1h,00bh,0e9h,024h + db 02fh,06fh,07ch,087h + db 058h,068h,04ch,011h + db 0c1h,061h,01dh,0abh + db 0b6h,066h,02dh,03dh + db 076h,0dch,041h,090h + db 001h,0dbh,071h,006h + db 098h,0d2h,020h,0bch + db 0efh,0d5h,010h,02ah + db 071h,0b1h,085h,089h + db 006h,0b6h,0b5h,01fh + db 09fh,0bfh,0e4h,0a5h + db 0e8h,0b8h,0d4h,033h + db 078h,007h,0c9h,0a2h + db 00fh,000h,0f9h,034h + db 096h,009h,0a8h,08eh + db 0e1h,00eh,098h,018h + db 07fh,06ah,00dh,0bbh + db 008h,06dh,03dh,02dh + db 091h,064h,06ch,097h + db 0e6h,063h,05ch,001h + db 06bh,06bh,051h,0f4h + db 01ch,06ch,061h,062h + db 085h,065h,030h,0d8h + db 0f2h,062h,000h,04eh + db 06ch,006h,095h,0edh + db 01bh,001h,0a5h,07bh + db 082h,008h,0f4h,0c1h + db 0f5h,00fh,0c4h,057h + db 065h,0b0h,0d9h,0c6h + db 012h,0b7h,0e9h,050h + db 08bh,0beh,0b8h,0eah + db 0fch,0b9h,088h,07ch + db 062h,0ddh,01dh,0dfh + db 015h,0dah,02dh,049h + db 08ch,0d3h,07ch,0f3h + db 0fbh,0d4h,04ch,065h + db 04dh,0b2h,061h,058h + db 03ah,0b5h,051h,0ceh + db 0a3h,0bch,000h,074h + db 0d4h,0bbh,030h,0e2h + db 04ah,0dfh,0a5h,041h + db 03dh,0d8h,095h,0d7h + db 0a4h,0d1h,0c4h,06dh + db 0d3h,0d6h,0f4h,0fbh + db 043h,069h,0e9h,06ah + db 034h,06eh,0d9h,0fch + db 0adh,067h,088h,046h + db 0dah,060h,0b8h,0d0h + db 044h,004h,02dh,073h + db 033h,003h,01dh,0e5h + db 0aah,00ah,04ch,05fh + db 0ddh,00dh,07ch,0c9h + db 050h,005h,071h,03ch + db 027h,002h,041h,0aah + db 0beh,00bh,010h,010h + db 0c9h,00ch,020h,086h + db 057h,068h,0b5h,025h + db 020h,06fh,085h,0b3h + db 0b9h,066h,0d4h,009h + db 0ceh,061h,0e4h,09fh + db 05eh,0deh,0f9h,00eh + db 029h,0d9h,0c9h,098h + db 0b0h,0d0h,098h,022h + db 0c7h,0d7h,0a8h,0b4h + db 059h,0b3h,03dh,017h + db 02eh,0b4h,00dh,081h + db 0b7h,0bdh,05ch,03bh + db 0c0h,0bah,06ch,0adh + db 0edh,0b8h,083h,020h + db 09ah,0bfh,0b3h,0b6h + db 003h,0b6h,0e2h,00ch + db 074h,0b1h,0d2h,09ah + db 0eah,0d5h,047h,039h + db 09dh,0d2h,077h,0afh + db 004h,0dbh,026h,015h + db 073h,0dch,016h,083h + db 0e3h,063h,00bh,012h + db 094h,064h,03bh,084h + db 00dh,06dh,06ah,03eh + db 07ah,06ah,05ah,0a8h + db 0e4h,00eh,0cfh,00bh + db 093h,009h,0ffh,09dh + db 00ah,000h,0aeh,027h + db 07dh,007h,09eh,0b1h + db 0f0h,00fh,093h,044h + db 087h,008h,0a3h,0d2h + db 01eh,001h,0f2h,068h + db 069h,006h,0c2h,0feh + db 0f7h,062h,057h,05dh + db 080h,065h,067h,0cbh + db 019h,06ch,036h,071h + db 06eh,06bh,006h,0e7h + db 0feh,0d4h,01bh,076h + db 089h,0d3h,02bh,0e0h + db 010h,0dah,07ah,05ah + db 067h,0ddh,04ah,0cch + db 0f9h,0b9h,0dfh,06fh + db 08eh,0beh,0efh,0f9h + db 017h,0b7h,0beh,043h + db 060h,0b0h,08eh,0d5h + db 0d6h,0d6h,0a3h,0e8h + db 0a1h,0d1h,093h,07eh + db 038h,0d8h,0c2h,0c4h + db 04fh,0dfh,0f2h,052h + db 0d1h,0bbh,067h,0f1h + db 0a6h,0bch,057h,067h + db 03fh,0b5h,006h,0ddh + db 048h,0b2h,036h,04bh + db 0d8h,00dh,02bh,0dah + db 0afh,00ah,01bh,04ch + db 036h,003h,04ah,0f6h + db 041h,004h,07ah,060h + db 0dfh,060h,0efh,0c3h + db 0a8h,067h,0dfh,055h + db 031h,06eh,08eh,0efh + db 046h,069h,0beh,079h + db 0cbh,061h,0b3h,08ch + db 0bch,066h,083h,01ah + db 025h,06fh,0d2h,0a0h + db 052h,068h,0e2h,036h + db 0cch,00ch,077h,095h + db 0bbh,00bh,047h,003h + db 022h,002h,016h,0b9h + db 055h,005h,026h,02fh + db 0c5h,0bah,03bh,0beh + db 0b2h,0bdh,00bh,028h + db 02bh,0b4h,05ah,092h + db 05ch,0b3h,06ah,004h + db 0c2h,0d7h,0ffh,0a7h + db 0b5h,0d0h,0cfh,031h + db 02ch,0d9h,09eh,08bh + db 05bh,0deh,0aeh,01dh + db 09bh,064h,0c2h,0b0h + db 0ech,063h,0f2h,026h + db 075h,06ah,0a3h,09ch + db 002h,06dh,093h,00ah + db 09ch,009h,006h,0a9h + db 0ebh,00eh,036h,03fh + db 072h,007h,067h,085h + db 005h,000h,057h,013h + db 095h,0bfh,04ah,082h + db 0e2h,0b8h,07ah,014h + db 07bh,0b1h,02bh,0aeh + db 00ch,0b6h,01bh,038h + db 092h,0d2h,08eh,09bh + db 0e5h,0d5h,0beh,00dh + db 07ch,0dch,0efh,0b7h + db 00bh,0dbh,0dfh,021h + db 086h,0d3h,0d2h,0d4h + db 0f1h,0d4h,0e2h,042h + db 068h,0ddh,0b3h,0f8h + db 01fh,0dah,083h,06eh + db 081h,0beh,016h,0cdh + db 0f6h,0b9h,026h,05bh + db 06fh,0b0h,077h,0e1h + db 018h,0b7h,047h,077h + db 088h,008h,05ah,0e6h + db 0ffh,00fh,06ah,070h + db 066h,006h,03bh,0cah + db 011h,001h,00bh,05ch + db 08fh,065h,09eh,0ffh + db 0f8h,062h,0aeh,069h + db 061h,06bh,0ffh,0d3h + db 016h,06ch,0cfh,045h + db 0a0h,00ah,0e2h,078h + db 0d7h,00dh,0d2h,0eeh + db 04eh,004h,083h,054h + db 039h,003h,0b3h,0c2h + db 0a7h,067h,026h,061h + db 0d0h,060h,016h,0f7h + db 049h,069h,047h,04dh + db 03eh,06eh,077h,0dbh + db 0aeh,0d1h,06ah,04ah + db 0d9h,0d6h,05ah,0dch + db 040h,0dfh,00bh,066h + db 037h,0d8h,03bh,0f0h + db 0a9h,0bch,0aeh,053h + db 0deh,0bbh,09eh,0c5h + db 047h,0b2h,0cfh,07fh + db 030h,0b5h,0ffh,0e9h + db 0bdh,0bdh,0f2h,01ch + db 0cah,0bah,0c2h,08ah + db 053h,0b3h,093h,030h + db 024h,0b4h,0a3h,0a6h + db 0bah,0d0h,036h,005h + db 0cdh,0d7h,006h,093h + db 054h,0deh,057h,029h + db 023h,0d9h,067h,0bfh + db 0b3h,066h,07ah,02eh + db 0c4h,061h,04ah,0b8h + db 05dh,068h,01bh,002h + db 02ah,06fh,02bh,094h + db 0b4h,00bh,0beh,037h + db 0c3h,00ch,08eh,0a1h + db 05ah,005h,0dfh,01bh + db 02dh,002h,0efh,08dh + diff --git a/Z80/test/stdafx.cpp b/Z80/test/stdafx.cpp new file mode 100644 index 0000000..fd4f341 --- /dev/null +++ b/Z80/test/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" diff --git a/Z80/test/stdafx.h b/Z80/test/stdafx.h new file mode 100644 index 0000000..113a094 --- /dev/null +++ b/Z80/test/stdafx.h @@ -0,0 +1,24 @@ +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +//#include +//#include +// +//#ifdef _MSC_VER +//#pragma comment(lib, "SDL2.lib") +//#pragma comment(lib, "SDL2main.lib") +//#pragma comment(lib, "SDL2_mixer.lib") +//#endif diff --git a/Z80/test/test.cpp b/Z80/test/test.cpp new file mode 100644 index 0000000..4fa905c --- /dev/null +++ b/Z80/test/test.cpp @@ -0,0 +1,19 @@ +#include "stdafx.h" +#include "Game.h" +#include "Configuration.h" + +int main(int, char*[]) { + + Configuration configuration; + +#ifdef _DEBUG + configuration.setDebugMode(true); + configuration.setProfileMode(true); +#endif + + Game game(configuration); + game.initialise(); + game.runLoop(); + + return 0; +} \ No newline at end of file diff --git a/Z80/test/test_Z80.vcxproj b/Z80/test/test_Z80.vcxproj new file mode 100644 index 0000000..137bff5 --- /dev/null +++ b/Z80/test/test_Z80.vcxproj @@ -0,0 +1,185 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {F8EE7116-0D75-4C82-BA9E-409F69F5D47C} + Win32Proj + test_Z80 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + ..\inc;..\..\inc;$(IncludePath) + + + ..\inc;..\..\inc;$(IncludePath) + + + ..\inc;..\..\inc;$(IncludePath) + + + ..\inc;..\..\inc;$(IncludePath) + + + + Level3 + Use + MaxSpeed + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + AnySuitable + Speed + false + AdvancedVectorExtensions + + + true + true + Console + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + + + + Console + + + + + Use + Level3 + Disabled + _DEBUG;_LIB;%(PreprocessorDefinitions) + + + + Console + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + AnySuitable + Speed + false + AdvancedVectorExtensions + + + true + true + Console + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + {a9c24bd9-0cb4-4c84-b09b-46b815f9da47} + + + {01974f81-2750-45af-b845-2c903a54a334} + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/Z80/test/test_Z80.vcxproj.filters b/Z80/test/test_Z80.vcxproj.filters new file mode 100644 index 0000000..1f1b6ad --- /dev/null +++ b/Z80/test/test_Z80.vcxproj.filters @@ -0,0 +1,47 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + \ No newline at end of file diff --git a/inc/Memory.h b/inc/Memory.h index d35b0dc..840b5da 100644 --- a/inc/Memory.h +++ b/inc/Memory.h @@ -30,7 +30,7 @@ namespace EightBit { public: Memory(uint16_t addressMask); - virtual uint16_t& ADDRESS() { return m_address; } + virtual register16_t& ADDRESS() { return m_address; } virtual uint8_t& DATA() { return *m_data; } virtual uint8_t& placeDATA(uint8_t value) { @@ -48,21 +48,21 @@ namespace EightBit { virtual uint16_t peekWord(uint16_t address) const; virtual uint8_t get(uint16_t address) { - ADDRESS() = address; + ADDRESS().word = address; return reference(); } virtual register16_t getWord(uint16_t address); virtual void set(uint16_t address, uint8_t value) { - ADDRESS() = address; + ADDRESS().word = address; reference() = value; } virtual void setWord(uint16_t address, register16_t value); virtual uint8_t& reference() { - uint16_t effective = ADDRESS() & m_addressMask; + uint16_t effective = ADDRESS().word & m_addressMask; return m_locked[effective] ? placeDATA(m_bus[effective]) : referenceDATA(m_bus[effective]); } @@ -76,7 +76,7 @@ namespace EightBit { uint16_t m_addressMask; // Mirror uint8_t m_temporary; // Used to simulate ROM - uint16_t m_address; + register16_t m_address; uint8_t* m_data; int loadMemory(const std::string& path, uint16_t offset); diff --git a/inc/Processor.h b/inc/Processor.h index ae1fcca..0587142 100644 --- a/inc/Processor.h +++ b/inc/Processor.h @@ -47,10 +47,6 @@ namespace EightBit { static uint8_t promoteNibble(uint8_t value) { return value << 4; } static uint8_t demoteNibble(uint8_t value) { return highNibble(value); } - static uint16_t makeWord(uint8_t low, uint8_t high) { - return (high << 8) | low; - } - Processor(Memory& memory); const Memory& getMemory() const { return m_memory; } @@ -68,14 +64,6 @@ namespace EightBit { void reset(); - virtual register16_t getWord(uint16_t address) const { - return m_memory.getWord(address); - } - - virtual void setWord(uint16_t address, register16_t value) { - m_memory.setWord(address, value); - } - protected: Memory& m_memory; @@ -86,17 +74,23 @@ namespace EightBit { bool m_halted; + void push(uint8_t value); void pushWord(register16_t value); + + uint8_t pop(); register16_t popWord(); uint8_t fetchByte() { - return m_memory.get(pc.word++); + m_memory.ADDRESS() = pc; + pc.word++; + return m_memory.reference(); } - uint16_t fetchWord() { - auto value = getWord(pc.word); - pc.word += 2; - return value.word; + register16_t fetchWord() { + register16_t returned; + returned.low = fetchByte(); + returned.high = fetchByte(); + return returned; } }; } \ No newline at end of file diff --git a/src/Memory.cpp b/src/Memory.cpp index 0490f9f..1553cb9 100644 --- a/src/Memory.cpp +++ b/src/Memory.cpp @@ -7,18 +7,20 @@ #include EightBit::Memory::Memory(uint16_t addressMask) -: m_address(0), - m_addressMask(addressMask), - m_data(&(m_bus[m_address])) {} +: m_addressMask(addressMask) { + m_address.word = 0; + m_data = &(m_bus[m_address.word]); +} uint8_t EightBit::Memory::peek(uint16_t address) const { return m_bus[address]; } uint16_t EightBit::Memory::peekWord(uint16_t address) const { - auto low = peek(address); - auto high = peek(address + 1); - return Processor::makeWord(low, high); + register16_t returned; + returned.low = peek(address); + returned.high = peek(address + 1); + return returned.word; } EightBit::register16_t EightBit::Memory::getWord(uint16_t address) { diff --git a/src/Processor.cpp b/src/Processor.cpp index ea14108..d41862a 100644 --- a/src/Processor.cpp +++ b/src/Processor.cpp @@ -5,7 +5,8 @@ EightBit::Processor::Processor(Memory& memory) : m_memory(memory), cycles(0), m_halted(false) { - pc.word = sp.word = 0; + sp.word = 0xffff; + pc.word = 0; } void EightBit::Processor::reset() { @@ -13,17 +14,30 @@ void EightBit::Processor::reset() { } void EightBit::Processor::initialise() { - sp.word = 0; + sp.word = 0xffff; reset(); } +void EightBit::Processor::push(uint8_t value) { + sp.word--; + m_memory.ADDRESS() = sp; + m_memory.reference() = value; +} + void EightBit::Processor::pushWord(register16_t value) { - sp.word -= 2; - setWord(sp.word, value); + push(value.high); + push(value.low); +} + +uint8_t EightBit::Processor::pop() { + m_memory.ADDRESS() = sp; + sp.word++; + return m_memory.reference(); } EightBit::register16_t EightBit::Processor::popWord() { - auto value = getWord(sp.word); - sp.word += 2; - return value; + register16_t returned; + returned.low = pop(); + returned.high = pop(); + return returned; }