]> localhost Git - glBoy.git/commitdiff
Still nowhere near finished, 2 years later.
authorMichael McMaster <email@michaelmcmaster.name>
Thu, 19 Aug 2010 11:37:13 +0000 (21:37 +1000)
committerMichael McMaster <email@michaelmcmaster.name>
Thu, 19 Aug 2010 11:37:13 +0000 (21:37 +1000)
Core.cc [new file with mode: 0755]
Core.hh [new file with mode: 0755]
Memory.cc [new file with mode: 0644]
Memory.hh [new file with mode: 0644]
README [new file with mode: 0644]
Registers.cc [new file with mode: 0755]
Registers.hh [new file with mode: 0755]
mm80.hh [new file with mode: 0644]

diff --git a/Core.cc b/Core.cc
new file mode 100755 (executable)
index 0000000..32aa87c
--- /dev/null
+++ b/Core.cc
@@ -0,0 +1,83 @@
+/** \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
diff --git a/Core.hh b/Core.hh
new file mode 100755 (executable)
index 0000000..0dbbadb
--- /dev/null
+++ b/Core.hh
@@ -0,0 +1,49 @@
+/** \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
diff --git a/Memory.cc b/Memory.cc
new file mode 100644 (file)
index 0000000..e54bd2d
--- /dev/null
+++ b/Memory.cc
@@ -0,0 +1,66 @@
+/** \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
diff --git a/Memory.hh b/Memory.hh
new file mode 100644 (file)
index 0000000..e54bd2d
--- /dev/null
+++ b/Memory.hh
@@ -0,0 +1,66 @@
+/** \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
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..034c583
--- /dev/null
+++ b/README
@@ -0,0 +1,5 @@
+Third attempt at a Z80 CPU emulator.
+email@michaelmcmaster.name 2008
+
+Language choice: C++
+
diff --git a/Registers.cc b/Registers.cc
new file mode 100755 (executable)
index 0000000..775d2af
--- /dev/null
@@ -0,0 +1,50 @@
+/** \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
diff --git a/Registers.hh b/Registers.hh
new file mode 100755 (executable)
index 0000000..6decfff
--- /dev/null
@@ -0,0 +1,120 @@
+/** \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
diff --git a/mm80.hh b/mm80.hh
new file mode 100644 (file)
index 0000000..0733195
--- /dev/null
+++ b/mm80.hh
@@ -0,0 +1,35 @@
+/** \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