From: Michael McMaster Date: Sun, 19 Dec 2010 11:06:09 +0000 (+1000) Subject: Added tests for ALU. Implemented all 8-buit arithmatic. X-Git-Tag: 1.0.0~8 X-Git-Url: http://git.codesrc.com/gitweb.cgi?a=commitdiff_plain;h=8e425f368335f8dc00d77db292b2957a5562cd96;p=glBoy.git Added tests for ALU. Implemented all 8-buit arithmatic. --- diff --git a/ALU.cc b/ALU.cc new file mode 100644 index 0000000..e69de29 diff --git a/ALU.hh b/ALU.hh new file mode 100755 index 0000000..a59402e --- /dev/null +++ b/ALU.hh @@ -0,0 +1,487 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +r = r2; + + + + +r = n; + + + + +r = m_mem.read8(m_reg.HL); + + + + +r = m_mem.read8(m_reg.IX, d); + + + + +r = m_mem.read8(m_reg.IY, d); + + + + +m_mem.write8(m_reg.HL, r); + + + + +m_mem.write8(m_reg.IX, d, r); + + + + +m_mem.write8(m_reg.IY, d, r); + + + + +m_mem.write8(m_reg.HL, n); + + + + +m_mem.write8(m_reg.IX, d, n); + + + + +m_mem.write8(m_reg.IY, d, n); + + + + +m_reg.A = m_mem.read8(m_reg.BC); + + + + +m_reg.A = m_mem.read8(m_reg.DE); + + + + +m_reg.A = m_mem.read8(N); + + + + +m_mem.write8(m_reg.BC, m_reg.A); + + + + +m_mem.write8(m_reg.DE, m_reg.A); + + + + +m_mem.write8(N, m_reg.A); + + + + +m_reg.F.set(m_reg.I, *this); +m_reg.A = m_reg.I; + + + + +m_reg.F.set(m_reg.R, *this); +m_reg.A = m_reg.R; + + + + +m_reg.I = m_reg.A; + + + + +m_reg.R = m_reg.A; + + + + + + +d = N; + + + + +m_reg.IX = N; + + + + +m_reg.IY = N; + + + + +m_reg.HL = m_mem.read16(N); + + + + +d = m_mem.read16(N); + + + + +m_reg.IX = m_mem.read16(N); + + + + +m_reg.IY = m_mem.read16(N); + + + + +m_mem.write16(N, m_reg.HL); + + + + +m_mem.write16(N, d); + + + + +m_mem.write16(N, m_reg.IX); + + + + +m_mem.write16(N, m_reg.IY); + + + + +m_reg.SP = m_reg.HL; + + + + +m_reg.SP = m_reg.IX; + + + + +m_reg.SP = m_reg.IY; + + + + +m_reg.SP.dec(2); +m_mem.write16(m_reg.SP, q); + + + + +m_reg.SP.dec(2); +m_mem.write16(m_reg.SP, m_reg.IX); + + + + +m_reg.SP.dec(2); +m_mem.write16(m_reg.SP, m_reg.IY); + + + + +q = m_mem.read16(m_reg.SP); +m_reg.SP.inc(2); + + + + +m_reg.IX = m_mem.read16(m_reg.SP); +m_reg.SP.inc(2); + + + + +m_reg.IY = m_mem.read16(m_reg.SP); +m_reg.SP.inc(2);; + + + + + + + + DWORD tmp(m_reg.DE); + m_reg.DE = m_reg.HL; + m_reg.HL = tmp; + + + + + DWORD tmp(m_reg.AF); + m_reg.AF = m_regDash.AF; + m_regDash.AF = tmp; + + + + + DWORD tmpBC(m_reg.BC); + DWORD tmpDE(m_reg.BC); + DWORD tmpHL(m_reg.BC); + m_reg.BC = m_regDash.BC; + m_reg.DE = m_regDash.DE; + m_reg.HL = m_regDash.HL; + m_regDash.BC = tmpBC; + m_regDash.DE = tmpDE; + m_regDash.HL = tmpHL; + + + + + DWORD tmp(m_reg.HL); + m_reg.HL = m_mem.read16(m_reg.SP); + m_mem.write16(m_reg.SP, tmp); + + + + + DWORD tmp(m_reg.IX); + m_reg.IX = m_mem.read16(m_reg.SP); + m_mem.write16(m_reg.SP, tmp); + + + + + DWORD tmp(m_reg.IY); + m_reg.IY = m_mem.read16(m_reg.SP); + m_mem.write16(m_reg.SP, tmp); + + + + + m_mem.write8(m_reg.DE, m_mem.read8(m_reg.HL)); + m_reg.DE.inc(); + m_reg.HL.inc(); + m_reg.BC.dec(); + m_reg.F.setCounter(m_reg.BC); + + + + + do + { + m_mem.write8(m_reg.DE, m_mem.read8(m_reg.HL)); + m_reg.DE.inc(); + m_reg.HL.inc(); + m_reg.BC.dec(); + + clock += 21; // Increment for each loop iteration + interrupt(); // Check for interrupts at each iteration + } while (m_reg.BC.host() != 0); + m_reg.F.setCounter(m_reg.BC); + clock += 16; // Increment again when leaving loop. + + + + + m_mem.write8(m_reg.DE, m_mem.read8(m_reg.HL)); + m_reg.DE.dec(); + m_reg.HL.dec(); + m_reg.BC.dec(); + m_reg.F.setCounter(m_reg.BC); + + + + + do + { + m_mem.write8(m_reg.DE, m_mem.read8(m_reg.HL)); + m_reg.DE.dec(); + m_reg.HL.dec(); + m_reg.BC.dec(); + + clock += 21; // Increment for each loop iteration + interrupt(); // Check for interrupts at each iteration + } while (m_reg.BC.host() != 0); + m_reg.F.setCounter(m_reg.BC); + clock += 16; // Increment again when leaving loop. + + + + + m_reg.BC.dec(); + m_reg.F.setSub(m_reg.A, m_reg.read8(r_reg.HL), m_reg.BC); + m_reg.HL.inc(); + + + + + bool equal; + do + { + m_reg.BC.dec(); + m_reg.F.setSub(m_reg.A, m_reg.read8(r_reg.HL), m_reg.BC); + equal = (m_reg.A == m_reg.read8(r_reg.HL)); + m_reg.HL.inc(); + + clock += 21; // Increment for each loop iteration + interrupt(); // Check for interrupts at each iteration + } while (m_reg.BC.host() != 0 && !equal); + clock += 16; // Increment again when leaving loop. + + + + + + m_reg.BC.dec(); + m_reg.F.setSub(m_reg.A, m_reg.read8(r_reg.HL), m_reg.BC); + m_reg.HL.dec(); + + + + + bool equal; + do + { + m_reg.BC.dec(); + m_reg.F.setSub(m_reg.A, m_reg.read8(r_reg.HL), m_reg.BC); + equal = (m_reg.A == m_reg.read8(r_reg.HL)); + m_reg.HL.dec(); + + clock += 21; // Increment for each loop iteration + interrupt(); // Check for interrupts at each iteration + } while (m_reg.BC.host() != 0 && !equal); + clock += 16; // Increment again when leaving loop. + + + +op8_t doAdd8(op8_t a, op8_t b, Flags& flags, bool carry) +{ + op8_t result(a + b); + + if (carry && flags.C) + { + ++result; + } + + flags.byte = + (result & 0x80) | // S MSB + ((result == 0) ? 0x40 : 0) | // Z + // U5 TODO + ((a ^ b ^ result) & 0x10) | // H + // U3 TODO + + // If a and b have the same sign, and the result + // has a different sign, then we overflowed the + // register. + // Can never overflow if a and b have different signs. (even with + // carry, since 127 + -1 + carry == 127). + // Step 1) Determine whether a and b have the same sign. (a NXOR b) + // Step 2) Determine whether the result has // a different sign. + ((((~(a ^ b)) & (result ^ a)) & 0x80) >> 5) |// P + + // N + (((op16_t(a) + op16_t(b)) & 0x100) >> 8) // C +} + + + + m_reg.A = doAdd8(m_reg.A, r, m_reg.F, false); + + + + + m_reg.A = doAdd8(m_reg.A, n, m_reg.F, false); + + + + + m_reg.A = doAdd8(m_reg.A, m_mem.read8(m_reg.HL), m_reg.F, false); + + + + + m_reg.A = doAdd8(m_reg.A, m_mem.read8(m_reg.IX, d), m_reg.F, false); + + + + + m_reg.A = doAdd8(m_reg.A, m_mem.read8(m_reg.IY, d), m_reg.F, false); + + + + + m_reg.A = doAdc8(m_reg.A, r, m_reg.F, true); + + + diff --git a/DWORD.hh b/DWORD.hh new file mode 100644 index 0000000..0c23bd5 --- /dev/null +++ b/DWORD.hh @@ -0,0 +1,178 @@ +/** + * Emulated representation of the Z80 CPU registers. + * + * The Z80 cpu supports switching between multiple register sets. Each Register + * object only stores the details of a single register set. +* +* 16bit Register Pairs are represented in a Struct to enable simple byte-order +* conversions where required. + * + * Authors: Michael McMaster + * Copyright: Michael McMaster + */ +#pragma once + +#include "mm80.hh" + +namespace mm80 +{ + +class Core; + +/** 8-bit packed representation of the Z80 flags register. + * + * C Carry. LSB of Flag register + * N Add/Subtract + * P (V) Parity/Overflow + * U3 3rd bit of last 8bit op that altered flags + * H Half-Carry (BCD) + * U5 5th bit of last 8bit op that altered flags + * Z Zero Flag + * S Sign Flag. MSB of Flag register + */ +struct Flags +{ + union + { + struct + { + unsigned C:1; /// Carry. LSB of Flag register + unsigned N:1; /// Add/Subtract + unsigned P:1; /// (V) Parity/Overflow + unsigned U3:1; /// 3rd bit of last 8bit op that altered flags + unsigned H:1; /// Half-Carry (BCD) + unsigned U5:1; /// 5th bit of last 8bit op that altered flags + unsigned Z:1; /// Zero Flag + unsigned S:1; /// Sign Flag. MSB of Flag register + }; + reg8_t byte; + }; + + Flags(); + + // Update the flags based on an operands value (eg. for simple assignment) + void set(op8_t operand, const Core& context); + + // Update the flags when changing BC + void setCounter(op16_t BC); + + // Set from A - B + void setSub(op8_t A, op8_t B, reg16_t BC); +}; + +struct DWORD +{ + // Always constructed, and stored, in Z80 byte order. + union + { + reg16_t dword; + struct + { + reg8_t l; + reg8_t h; + }; + }; + + reg16_t z80() const { return dword; } + reg16_t host() const + { +#ifdef HOST_LITTLE_ENDIAN + return dword; +#else + return (reg16_t(h) << 8) | l; +#endif + } + + void inc(u8_t val = 1) const + { +#ifdef HOST_LITTLE_ENDIAN + ++dword; +#else + reg16_t tmp(host() + val); + l = tmp & 0xf; + h = tmp >> 8; +#endif + } + + void dec(u8_t val = 1) const + { +#ifdef HOST_LITTLE_ENDIAN + --dword; +#else + reg16_t tmp(host() - val); + l = tmp & 0xf; + h = tmp >> 8; +#endif + } +}; + +// Create a dword from z80-ordered mem. +static DWORD CreateDWORD(u8_t* in) +{ + DWORD result; + result.l = in[0]; + result.h = in[1]; + return result; +} + +/** Z80 register access. + * + * Registers may be accessed in either 8-bit (eg. A) + * or by their 16-bit pair (eg. AF) + * + */ +struct Registers +{ + Registers(); + +#define Z80_REG_STRUCT(h,l) \ + struct \ + { \ + l; \ + h; \ + }; +#endif + + // Note: The order of these unions/structs is important, as + // offsets are taken into the Register struct + reg8_t[0] begin8; + reg16_t[0] begin16; + + union + { + Z80_REG_STRUCT(reg8_t B, reg8_t C); + DWORD BC; + }; + + union + { + Z80_REG_STRUCT(reg8_t D, reg8_t E); + DWORD DE; + }; + + union + { + Z80_REG_STRUCT(reg8_t H, reg8_t L); + DWORD HL; + }; + + union + { + Z80_REG_STRUCT(reg8_t A, Flags F,); + DWORD AF; + }; + + +#undef Z80_REG_STRUCT + + // Special Purpose + reg8_t I; // Interrupt Vector + reg8_t R; // Memory Refresh + DWORD IX; // Index Register + DWORD IY; // Index Register + DWORD SP; // Stack Pointer + DWORD PC; // Program Counter +}; + +} + diff --git a/Test.cc b/Test.cc new file mode 100644 index 0000000..e69de29