--- /dev/null
+/** \r
+ * Emulated Z80 CPU.\r
+ *\r
+ * Incrementing elapsed cycles is performed separately from emulating the opcodes.\r
+ * to simplify the emulation. Cycle info could be embedded in the switch statement?\r
+ * eg. case X: doFoo; cycles += 7\r
+ *\r
+ * Authors: Michael McMaster <email@michaelmcmaster.name>\r
+ * Copyright: Michael McMaster <email@michaelmcmaster.name>\r
+ */ \r
+#include "bits/Z80.hh"\r
+#include "Core.hh"\r
+\r
+using namespace Z80;\r
+\r
+Z80::Core(std::auto_ptr<Memory> mem) :\r
+ m_iff1(0),\r
+ m_iff2(0),\r
+ m_mem(mem),\r
+{\r
+}\r
+\r
+ public void run(CycleCount maxCycles)\r
+ {\r
+ CycleCount elapsedCycles = 0;\r
+\r
+ while (elapsedCycles < maxCycles)\r
+ {\r
+ op8_t opcode = op8();\r
+ switch (opcode)\r
+ {\r
+ }\r
+ }\r
+ }\r
+\r
+op8_t Core::op8()\r
+{\r
+ return m_mem.read8(m_reg.PC++);\r
+}\r
+\r
+op16_t Core::op16()\r
+{\r
+ op16_t operand = m_mem.read16(m_reg.PC);\r
+ m_reg.PC += 2;\r
+ return operand;\r
+}\r
+\r
+void Core::reg8(op8_t opcode, u8_t value)\r
+{\r
+ // 00RRR000\r
+ reg8(opcode >> 3) = value;\r
+}\r
+\r
+reg8_t& Core::reg8(op8_t opcode) const\r
+{\r
+ // 00000RRR\r
+ switch (opcode & 0b00000111)\r
+ {\r
+ case 0: return m_reg.B;\r
+ case 1: return m_reg.C;\r
+ case 2: return m_reg.D;\r
+ case 3: return m_reg.E;\r
+ case 4: return m_reg.H;\r
+ case 5: return m_reg.L;\r
+ case 6: assert(0); FIXME\r
+ case 7: return m_reg.A;\r
+ }\r
+}\r
+ \r
+reg16_t& Core::dd(op8_t opcode) const\r
+{\r
+ // 00dd0000\r
+ u8_t offset = (opcode & 0b00110000) >> 4;\r
+ return (offset == 3) ? m_reg.SP : *(m_reg.begin16 + offset);\r
+}\r
+\r
+reg16_t& Core::qq(op8_t opcode) const\r
+{\r
+ // 00qq0000\r
+ u8_t offset = (opcode & 0b00110000) >> 4;\r
+ return *(m_reg.begin16 + offset);\r
+}\r
+\r
--- /dev/null
+/** \r
+ * Emulated Z80 CPU.\r
+ *\r
+ * Incrementing elapsed cycles is performed separately from emulating the opcodes.\r
+ * to simplify the emulation. Cycle info could be embedded in the switch statement?\r
+ * eg. case X: doFoo; cycles += 7\r
+ *\r
+ * Authors: Michael McMaster <email@michaelmcmaster.name>\r
+ * Copyright: Michael McMaster <email@michaelmcmaster.name>\r
+ */ \r
+#pragma once\r
+\r
+#include "bits/Z80.hh"\r
+#include "Clock.hh"\r
+\r
+#include <memory>\r
+\r
+namespace Z80\r
+{\r
+\r
+class Core\r
+{\r
+public:\r
+ Core(std::auto_ptr<Memory> mem);\r
+\r
+ cycle_t run(cycle_t maxCycles);\r
+\r
+ bit getIFF2() const { return m_iff2; }\r
+\r
+private:\r
+ op8_t op8();\r
+ op16_t op16();\r
+\r
+ void reg8(op8_t opcode, u8_t value);\r
+ reg8_t& reg8(op8_t opcode) const;\r
+\r
+ reg16_t& dd(op8_t opcode) const;\r
+ reg16_t& qq(op8_t opcode) const;\r
+\r
+ // The Z80 can switch between register sets.\r
+ Registers m_reg;\r
+ Registers m_regDash;\r
+\r
+ // Interrupt enablement\r
+ bit m_iff1;\r
+ bit m_iff2;\r
+\r
+ std::auto_ptr<Memory> m_mem;\r
+};\r
--- /dev/null
+/** \r
+ * Flat memory-model emulation.\r
+ *\r
+ * Authors: Michael McMaster <email@michaelmcmaster.name>\r
+ * Copyright: Michael McMaster <email@michaelmcmaster.name>\r
+ */\r
+\r
+#include "bits/Z80.hh"\r
+#include "ByteOrder.hh"\r
+#include "Memory.hh"\r
+\r
+#include <cstring>\r
+\r
+using namespace Z80;\r
+\r
+Memory::Memory(address_t initialSize)\r
+{\r
+ m_mem.resize(initialSize);\r
+}\r
+\r
+u8_t Memory::read8(address_t address)\r
+{\r
+ return m_mem[address];\r
+}\r
+\r
+u8_t Memory::read8(address_t address, offset_t offset)\r
+{\r
+ return m_mem[address + offset];\r
+}\r
+\r
+void Memory::write8(address_t address, u8_t value)\r
+{\r
+ m_mem[address] = value;\r
+}\r
+\r
+void Memory::write8(address_t address, offset_t offset, u8_t value)\r
+{\r
+ m_mem[address + offset] = value;\r
+}\r
+\r
+u16_t Memory::read16(address_t address)\r
+{\r
+ return Z80ToHost(&m_mem[address]);\r
+}\r
+\r
+u16_t Memory::read16(address_t address, offset_t offset)\r
+{\r
+ return Z80ToHost(&m_mem[address + offset]);\r
+}\r
+\r
+void Memory::write16(address_t address, u16_t value)\r
+{\r
+ hostToZ80(value, &m_mem[address]);\r
+}\r
+\r
+void Memory::write16(address_t address, offset_t offset, u16_t value)\r
+{\r
+ hostToZ80(value, &m_mem[address + offset]);\r
+}\r
+\r
+\r
+void Memory::copy(address_t src, address_t dst, address_t count)\r
+{\r
+ memcpy(&m_mem[dst], &m_mem[src], count);\r
+}\r
+\r
--- /dev/null
+/** \r
+ * Flat memory-model emulation.\r
+ *\r
+ * Authors: Michael McMaster <email@michaelmcmaster.name>\r
+ * Copyright: Michael McMaster <email@michaelmcmaster.name>\r
+ */\r
+\r
+#include "bits/Z80.hh"\r
+#include "ByteOrder.hh"\r
+#include "Memory.hh"\r
+\r
+#include <cstring>\r
+\r
+using namespace Z80;\r
+\r
+Memory::Memory(address_t initialSize)\r
+{\r
+ m_mem.resize(initialSize);\r
+}\r
+\r
+u8_t Memory::read8(address_t address)\r
+{\r
+ return m_mem[address];\r
+}\r
+\r
+u8_t Memory::read8(address_t address, offset_t offset)\r
+{\r
+ return m_mem[address + offset];\r
+}\r
+\r
+void Memory::write8(address_t address, u8_t value)\r
+{\r
+ m_mem[address] = value;\r
+}\r
+\r
+void Memory::write8(address_t address, offset_t offset, u8_t value)\r
+{\r
+ m_mem[address + offset] = value;\r
+}\r
+\r
+u16_t Memory::read16(address_t address)\r
+{\r
+ return Z80ToHost(&m_mem[address]);\r
+}\r
+\r
+u16_t Memory::read16(address_t address, offset_t offset)\r
+{\r
+ return Z80ToHost(&m_mem[address + offset]);\r
+}\r
+\r
+void Memory::write16(address_t address, u16_t value)\r
+{\r
+ hostToZ80(value, &m_mem[address]);\r
+}\r
+\r
+void Memory::write16(address_t address, offset_t offset, u16_t value)\r
+{\r
+ hostToZ80(value, &m_mem[address + offset]);\r
+}\r
+\r
+\r
+void Memory::copy(address_t src, address_t dst, address_t count)\r
+{\r
+ memcpy(&m_mem[dst], &m_mem[src], count);\r
+}\r
+\r
--- /dev/null
+Third attempt at a Z80 CPU emulator.
+email@michaelmcmaster.name 2008
+
+Language choice: C++
+
--- /dev/null
+/** \r
+ * Authors: Michael McMaster <email@michaelmcmaster.name>\r
+ * Copyright: Michael McMaster <email@michaelmcmaster.name>\r
+ */ \r
+#include "bits/Z80.hh"\r
+#include "Registers.hh"\r
+\r
+#include "Core.hh"\r
+\r
+using namespace Z80;\r
+\r
+Flags::Flags() :\r
+ C(0),\r
+ N(0),\r
+ P(0),\r
+ U3(0),\r
+ H(0),\r
+ U5(0),\r
+ Z(0),\r
+ S(0)\r
+{\r
+ // do nothing\r
+}\r
+\r
+op8_t Flags::operator()(op8_t operand, const Core& context)\r
+{\r
+ S = operand < 0 ? 1 : 0;\r
+ Z = operand == 0 ? 1 : 0;\r
+ U5 = operand & 0b00010000 >> 4;\r
+ H = 0;\r
+ U3 = operand & 0b00000100 >> 2;\r
+ P = context.getIFF2();\r
+ N = 0;\r
+ // C is not affected\r
+ return operand;\r
+}\r
+\r
+Registers::Registers() :\r
+ AF(0),\r
+ BC(0),\r
+ DE(0),\r
+ HL(0),\r
+ I(0),\r
+ R(0),\r
+ IX(0),\r
+ IY(0),\r
+ SP(0),\r
+ PC(0)\r
+{\r
+}\r
--- /dev/null
+/** \r
+ * Emulated representation of the Z80 CPU registers.\r
+ *\r
+ * The Z80 register emulation allows efficient access to both the 8-bit ,\r
+ * registers an the 16-bit register pairs. This is achieved by modifying the \r
+ * structure layout according to the endianess of the host.\r
+ *\r
+ * The Z80 cpu supports switching between multiple register sets. Each Register\r
+ * object only stores the details of a single register set. \r
+ *\r
+ * Authors: Michael McMaster <email@michaelmcmaster.name>\r
+ * Copyright: Michael McMaster <email@michaelmcmaster.name>\r
+ */ \r
+#pragma once\r
+\r
+#include "bits/Z80.hh"\r
+\r
+namespace Z80\r
+{\r
+\r
+class Core;\r
+\r
+/** 8-bit packed representation of the Z80 flags register.\r
+ *\r
+ * C Carry. LSB of Flag register\r
+ * N Add/Subtract\r
+ * P (V) Parity/Overflow\r
+ * U3 3rd bit of last 8bit op that altered flags\r
+ * H Half-Carry (BCD)\r
+ * U5 5th bit of last 8bit op that altered flags\r
+ * Z Zero Flag\r
+ * S Sign Flag. MSB of Flag register\r
+ */\r
+struct Flags\r
+{\r
+ unsigned C:1; /// Carry. LSB of Flag register\r
+ unsigned N:1; /// Add/Subtract\r
+ unsigned P:1; /// (V) Parity/Overflow\r
+ unsigned U3:1; /// 3rd bit of last 8bit op that altered flags\r
+ unsigned H:1; /// Half-Carry (BCD)\r
+ unsigned U5:1; /// 5th bit of last 8bit op that altered flags\r
+ unsigned Z:1; /// Zero Flag\r
+ unsigned S:1; /// Sign Flag. MSB of Flag register\r
+\r
+ Flags();\r
+\r
+ // Update the flags based on an operands value (eg. for simple assignment)\r
+ op8_t operator()(op8_t operand, const Core& context);\r
+};\r
+\r
+/** Z80 register access.\r
+ *\r
+ * Registers may be accessed in either 8-bit (eg. A) \r
+ * or by their 16-bit pair (eg. AF)\r
+ *\r
+ */\r
+struct Registers\r
+{\r
+ Registers();\r
+\r
+ // Storage Order allows for 16 bit pairs to be accessed naturally.\r
+ // ie. AF, BC, DE, HL\r
+ // eg. AF = 0x1234, A will == 0x12.\r
+#ifdef HOST_LITTLE_ENDIAN\r
+#define Z80_REG_STRUCT(h,l) \\r
+ struct \\r
+ { \\r
+ l; \\r
+ h; \\r
+ };\r
+#else\r
+#define Z80_REG_STRUCT(h,l) \\r
+ struct \\r
+ { \\r
+ h; \\r
+ l; \\r
+ };\r
+#endif\r
+\r
+ // Note: The order of these unions/structs is important, as\r
+ // offsets are taken into the Register struct\r
+ reg8_t[0] begin8;\r
+ reg16_t[0] begin16;\r
+\r
+ union\r
+ {\r
+ Z80_REG_STRUCT(reg8_t B, reg8_t C);\r
+ reg16_t BC;\r
+ };\r
+\r
+ union\r
+ {\r
+ Z80_REG_STRUCT(reg8_t D, reg8_t E);\r
+ reg16_t DE;\r
+ };\r
+\r
+ union\r
+ {\r
+ Z80_REG_STRUCT(reg8_t H, reg8_t L);\r
+ reg16_t HL;\r
+ };\r
+\r
+ union\r
+ {\r
+ Z80_REG_STRUCT(reg8_t A, Flags F,);\r
+ reg16_t AF;\r
+ };\r
+\r
+\r
+#undef Z80_REG_STRUCT\r
+\r
+ // Special Purpose\r
+ reg8_t I; // Interrupt Vector\r
+ reg8_t R; // Memory Refresh\r
+ reg16_t IX; // Index Register\r
+ reg16_t IY; // Index Register\r
+ reg16_t SP; // Stack Pointer\r
+ reg16_t PC; // Program Counter\r
+};\r
+\r
--- /dev/null
+/** \r
+ * Z80 CPU emulator\r
+ *\r
+ * Authors: Michael McMaster <email@michaelmcmaster.name>\r
+ * Copyright: Michael McMaster <email@michaelmcmaster.name>\r
+ *\r
+ * Description goes here\r
+ */ \r
+#pragma once\r
+\r
+#include <cstdint>\r
+\r
+namespace Z80\r
+{\r
+ typedef uint8_t u8_t;\r
+ typedef uint16_t u16_t;\r
+\r
+ typedef uint8_t op8_t;\r
+ typedef uint8_t op16_t;\r
+\r
+ typedef uint8_t reg8_t;\r
+ typedef uint16_t reg16_t;\r
+\r
+ typedef uint16_t address_t;\r
+ typedef int16_t offset_t;\r
+\r
+ typedef bool bit;\r
+\r
+ typedef uint64_t cycle_t;\r
+\r
+ #if !(defined(HOST_LITTLE_ENDIAN) || defined(HOST_BIG_ENDIAN))\r
+ #warn Assuming little-endian\r
+ #define HOST_LITTLE_ENDIAN\r
+ #endif\r
+}\r