Add Z80 processor and tests.

Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-06-05 22:39:15 +01:00
parent 4c6f44c394
commit 211c75d84d
41 changed files with 4119 additions and 615 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -3,63 +3,66 @@
#include <string>
#include <boost/format.hpp>
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);
};
}

View File

@ -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<PortEventArgs> ReadingPort;
Signal<PortEventArgs> ReadPort;
Signal<PortEventArgs> ReadingPort;
Signal<PortEventArgs> ReadPort;
Signal<PortEventArgs> WritingPort;
Signal<PortEventArgs> WrittenPort;
Signal<PortEventArgs> WritingPort;
Signal<PortEventArgs> 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<uint8_t, 0x100> input;
std::array<uint8_t, 0x100> output;
};
private:
std::array<uint8_t, 0x100> input;
std::array<uint8_t, 0x100> output;
};
}

View File

@ -2,15 +2,17 @@
#include <cstdint>
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;
};
}

View File

@ -3,21 +3,22 @@
#include <array>
#include <cstdint>
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<uint64_t, 0x100> m_instructions;
std::array<uint64_t, 0x10000> m_addresses;
void dumpInstructionProfiles() const;
void dumpAddressProfiles() const;
};
private:
std::array<uint64_t, 0x100> m_instructions;
std::array<uint64_t, 0x10000> m_addresses;
void dumpInstructionProfiles() const;
void dumpAddressProfiles() const;
};
}

View File

@ -1,449 +1,456 @@
#pragma once
#include <cstdint>
#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<Z80> ExecutingInstruction;
Signal<Z80> 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<std::array<register16_t, 3>, 2> m_registers;
int m_registerSet;
enum { BC_IDX, DE_IDX, HL_IDX };
std::array<register16_t, 2> m_accumulatorFlags;
int m_accumulatorFlagsSet;
std::array<std::array<register16_t, 3>, 2> m_registers;
int m_registerSet;
register16_t m_ix;
register16_t m_iy;
std::array<register16_t, 2> 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<bool, 8> m_halfCarryTableAdd = { { false, false, true, false, true, false, true, true } };
std::array<bool, 8> m_halfCarryTableSub = { { false, true, true, true, false, false, false, true } };
int8_t m_displacement;
int fetchExecute() {
M1() = true;
return execute(fetchByteExecute());
}
std::array<bool, 8> m_halfCarryTableAdd = { { false, false, true, false, true, false, true, true } };
std::array<bool, 8> 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));
}
};
void readPort() {
m_memory.placeDATA(m_ports.read(m_memory.ADDRESS().low));
}
};
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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];

View File

@ -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) {

170
Z80/src/Z80.vcxproj Normal file
View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{01974F81-2750-45AF-B845-2C903A54A334}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Z80</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>..\inc;..\..\inc;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>..\inc;..\..\inc;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>..\inc;..\..\inc;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>..\inc;..\..\inc;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\inc\Disassembler.h" />
<ClInclude Include="..\inc\InputOutput.h" />
<ClInclude Include="..\inc\PortEventArgs.h" />
<ClInclude Include="..\inc\Profiler.h" />
<ClInclude Include="..\inc\Z80.h" />
<ClInclude Include="stdafx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Disassembler.cpp" />
<ClCompile Include="InputOutput.cpp" />
<ClCompile Include="Profiler.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="Z80.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\boost.1.64.0.0\build\native\boost.targets" Condition="Exists('..\..\packages\boost.1.64.0.0\build\native\boost.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\boost.1.64.0.0\build\native\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\boost.1.64.0.0\build\native\boost.targets'))" />
</Target>
</Project>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\Disassembler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\InputOutput.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\PortEventArgs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\Profiler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\Z80.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Disassembler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="InputOutput.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Profiler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Z80.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

4
Z80/src/packages.config Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.64.0.0" targetFramework="native" />
</packages>

1
Z80/src/stdafx.cpp Normal file
View File

@ -0,0 +1 @@
#include "stdafx.h"

42
Z80/src/stdafx.h Normal file
View File

@ -0,0 +1,42 @@
#ifdef _MSC_VER
#pragma once
#endif
#include <string>
#include <cstdint>
#include <stdexcept>
#include <functional>
#include <algorithm>
#include <memory>
#include <sstream>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <array>
#include <vector>
#include <bitset>
#include <boost/format.hpp>
//#include <SDL.h>
//#include <SDL_mixer.h>
//
//#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

84
Z80/test/Board.cpp Normal file
View File

@ -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';
}

37
Z80/test/Board.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <string>
#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();
};

View File

@ -0,0 +1,8 @@
#include "stdafx.h"
#include "Configuration.h"
Configuration::Configuration()
: m_debugMode(false),
m_profileMode(false),
m_romDirectory("roms") {
}

42
Z80/test/Configuration.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
#include <string>
#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;
};

21
Z80/test/Game.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "stdafx.h"
#include "Game.h"
#include <algorithm>
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();
}
}

22
Z80/test/Game.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
//#include <stdexcept>
//#include <string>
//#include <memory>
//#include <map>
#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;
};

4
Z80/test/packages.config Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.64.0.0" targetFramework="native" />
</packages>

BIN
Z80/test/roms/CPUTEST.COM Normal file

Binary file not shown.

805
Z80/test/roms/TEST.ASM Normal file
View File

@ -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=F0H<AND>55H=50H,C=0,P=1,S=0,Z=0
CPI 050H
JZ ORII ;TEST "ANI"
CALL CPUER
ORII: ORI 03AH ;A=50H<OR>3AH=7AH,C=0,P=0,S=0,Z=0
CPI 07AH
JZ XRII ;TEST "ORI"
CALL CPUER
XRII: XRI 00FH ;A=7AH<XOR>0FH=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

BIN
Z80/test/roms/TEST.COM Normal file

Binary file not shown.

BIN
Z80/test/roms/prelim.com Normal file

Binary file not shown.

343
Z80/test/roms/prelim.z80 Normal file
View File

@ -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

BIN
Z80/test/roms/zexall.com Normal file

Binary file not shown.

BIN
Z80/test/roms/zexdoc.com Normal file

Binary file not shown.

1546
Z80/test/roms/zexdoc.z80 Normal file

File diff suppressed because it is too large Load Diff

1
Z80/test/stdafx.cpp Normal file
View File

@ -0,0 +1 @@
#include "stdafx.h"

24
Z80/test/stdafx.h Normal file
View File

@ -0,0 +1,24 @@
#ifdef _MSC_VER
#pragma once
#endif
#include <string>
#include <cstdint>
#include <stdexcept>
#include <algorithm>
#include <memory>
#include <iostream>
#include <array>
#include <vector>
#include <map>
//#include <SDL.h>
//#include <SDL_mixer.h>
//
//#ifdef _MSC_VER
//#pragma comment(lib, "SDL2.lib")
//#pragma comment(lib, "SDL2main.lib")
//#pragma comment(lib, "SDL2_mixer.lib")
//#endif

19
Z80/test/test.cpp Normal file
View File

@ -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;
}

185
Z80/test/test_Z80.vcxproj Normal file
View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{F8EE7116-0D75-4C82-BA9E-409F69F5D47C}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>test_Z80</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>..\inc;..\..\inc;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>..\inc;..\..\inc;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>..\inc;..\..\inc;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>..\inc;..\..\inc;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link />
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link />
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Board.h" />
<ClInclude Include="Configuration.h" />
<ClInclude Include="Game.h" />
<ClInclude Include="stdafx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Board.cpp" />
<ClCompile Include="Configuration.cpp" />
<ClCompile Include="Game.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="test.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\EightBit.vcxproj">
<Project>{a9c24bd9-0cb4-4c84-b09b-46b815f9da47}</Project>
</ProjectReference>
<ProjectReference Include="..\src\Z80.vcxproj">
<Project>{01974f81-2750-45af-b845-2c903a54a334}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\boost.1.64.0.0\build\native\boost.targets" Condition="Exists('..\..\packages\boost.1.64.0.0\build\native\boost.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\boost.1.64.0.0\build\native\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\boost.1.64.0.0\build\native\boost.targets'))" />
</Target>
</Project>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Board.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Configuration.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Game.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Board.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Configuration.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Game.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="test.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View File

@ -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);

View File

@ -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;
}
};
}

View File

@ -7,18 +7,20 @@
#include <algorithm>
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) {

View File

@ -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;
}