From 4127f2eb5db1f9ad659461c767fe54a0cbfdebfa Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Wed, 25 Mar 2015 21:43:10 -0400 Subject: [PATCH] Add registers to Z80, plus some skeleton code. --- src/config.c | 2 - src/config.h | 2 + src/gamegear.c | 36 ++++++++++++++--- src/gamegear.h | 11 ++++- src/iomanager.c | 12 +++++- src/mmu.c | 12 ++++++ src/mmu.h | 16 ++++++++ src/z80.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/z80.h | 25 ++++++++++-- 9 files changed, 225 insertions(+), 13 deletions(-) create mode 100644 src/mmu.c create mode 100644 src/mmu.h diff --git a/src/config.c b/src/config.c index fe79b86..fe347ec 100644 --- a/src/config.c +++ b/src/config.c @@ -12,8 +12,6 @@ #include "logging.h" #include "version.h" -#define ROMS_DIR "roms" - /* Print command-line help/usage. */ diff --git a/src/config.h b/src/config.h index fde297b..6899e4a 100644 --- a/src/config.h +++ b/src/config.h @@ -5,6 +5,8 @@ #include +#define ROMS_DIR "roms" + #define CONFIG_OK 0 #define CONFIG_EXIT_SUCCESS 1 #define CONFIG_EXIT_FAILURE 2 diff --git a/src/gamegear.c b/src/gamegear.c index a587015..02ac623 100644 --- a/src/gamegear.c +++ b/src/gamegear.c @@ -17,7 +17,9 @@ GameGear* gamegear_create() if (!gg) OUT_OF_MEMORY() - gg->rom = NULL; + // mmu_init(&gg->mmu, ...); + z80_init(&gg->cpu, CPU_CLOCK_SPEED); + gg->powered = false; return gg; } @@ -34,11 +36,15 @@ void gamegear_destroy(GameGear *gg) /* Load a ROM image into the GameGear object. - Does *not* steal the reference to the ROM object. + Does *not* steal a reference to the ROM object. Calling this function while + the GameGear is powered on has no effect. */ void gamegear_load(GameGear *gg, ROM *rom) { - gg->rom = rom; + if (gg->powered) + return; + + // mmu_hard_map(&gg->mmu, rom->data, ..., ...); } /* @@ -52,9 +58,29 @@ void gamegear_load(GameGear *gg, ROM *rom) */ void gamegear_power(GameGear *gg, bool state) { - if (gg->state == state) + if (gg->powered == state) + return; + + if (state) { + // mmu_power(&gg->mmu); + z80_power(&gg->cpu); + } + gg->powered = state; +} + +/* + Update the simulation of the GameGear. + + This function simulates the number of clock cycles corresponding to the + time since the last call to gamegear_simulate() or gamegear_power() if the + system was just powered on. If the system is powered off, this function + does nothing. +*/ +void gamegear_simulate(GameGear *gg) +{ + if (!gg->powered) return; // TODO - gg->state = state; + // z80_do_cycles(&gg->cpu, ...); } diff --git a/src/gamegear.h b/src/gamegear.h index 3e5be71..2f461ed 100644 --- a/src/gamegear.h +++ b/src/gamegear.h @@ -5,13 +5,19 @@ #include +#include "mmu.h" #include "rom.h" +#include "z80.h" + +/* Clock speed in Hz was taken from the official Sega GG documentation */ +#define CPU_CLOCK_SPEED 3579545 /* Structs */ typedef struct { - ROM *rom; - bool state; + MMU mmu; + Z80 cpu; + bool powered; } GameGear; /* Functions */ @@ -20,3 +26,4 @@ GameGear* gamegear_create(); void gamegear_destroy(GameGear*); void gamegear_load(GameGear*, ROM*); void gamegear_power(GameGear*, bool); +void gamegear_simulate(GameGear*); diff --git a/src/iomanager.c b/src/iomanager.c index 88e68a7..80a9233 100644 --- a/src/iomanager.c +++ b/src/iomanager.c @@ -1,6 +1,8 @@ /* Copyright (C) 2014-2015 Ben Kurtovic Released under the terms of the MIT License. See LICENSE for details. */ +#include + #include "iomanager.h" #include "logging.h" @@ -14,7 +16,15 @@ void iomanager_emulate(GameGear *gg) DEBUG("IOManager powering GameGear") gamegear_power(gg, true); - // TODO +#ifdef DEBUG_MODE + z80_dump_registers(&gg->cpu); +#endif + + // TODO: use SDL events + while (1) { + gamegear_simulate(gg); + usleep(1000 * 1000 / 60); + } DEBUG("IOManager unpowering GameGear") gamegear_power(gg, false); diff --git a/src/mmu.c b/src/mmu.c new file mode 100644 index 0000000..ba78687 --- /dev/null +++ b/src/mmu.c @@ -0,0 +1,12 @@ +/* Copyright (C) 2014-2015 Ben Kurtovic + Released under the terms of the MIT License. See LICENSE for details. */ + +#include "z80.h" + +/* + Initialize a MMU object. +*/ +// void mmu_init(MMU *mmu, ...) +// { +// // +// } diff --git a/src/mmu.h b/src/mmu.h new file mode 100644 index 0000000..ea68c0b --- /dev/null +++ b/src/mmu.h @@ -0,0 +1,16 @@ +/* Copyright (C) 2014-2015 Ben Kurtovic + Released under the terms of the MIT License. See LICENSE for details. */ + +#pragma once + +// #include <> + +/* Structs */ + +typedef struct { + // +} MMU; + +/* Functions */ + +// void mmu_init(MMU*, ...); diff --git a/src/z80.c b/src/z80.c index b837eb0..5949ce8 100644 --- a/src/z80.c +++ b/src/z80.c @@ -1,4 +1,126 @@ /* Copyright (C) 2014-2015 Ben Kurtovic Released under the terms of the MIT License. See LICENSE for details. */ +#include "logging.h" #include "z80.h" + +#define FLAG_CARRY 0 +#define FLAG_SUBTRACT 1 +#define FLAG_PARITY 2 +#define FLAG_OVERFLOW 2 +#define FLAG_HALFCARRY 4 +#define FLAG_ZERO 6 +#define FLAG_SIGN 7 + +/* + Initialize a Z80 object. +*/ +void z80_init(Z80 *z80, uint64_t clock_speed) +{ + z80->clock_speed = clock_speed; +} + +/* + Power on the Z80, setting registers to their default values. +*/ +void z80_power(Z80 *z80) +{ + Z80RegFile *regfile = &z80->regfile; + + regfile->a = regfile->f = 0xFF; + regfile->b = regfile->c = 0xFF; + regfile->d = regfile->e = 0xFF; + regfile->h = regfile->l = 0xFF; + regfile->a_ = regfile->f_ = 0xFF; + regfile->b_ = regfile->c_ = 0xFF; + regfile->d_ = regfile->e_ = 0xFF; + regfile->h_ = regfile->l_ = 0xFF; + + regfile->ix = 0xFFFF; + regfile->iy = 0xFFFF; + regfile->sp = 0xFFFF; + regfile->pc = 0x0000; + + regfile->i = 0xFF; + regfile->r = 0xFF; + + regfile->im_a = regfile->im_b = 0; + regfile->iff1 = regfile->iff2 = 0; +} + +/* + Return whether a particular flag is set in the F register. +*/ +static inline bool get_flag(Z80 *z80, uint8_t flag) +{ + return z80->regfile.f & (1 << flag); +} + +/* + Return whether a particular flag is set in the F' register. +*/ +static inline bool get_shadow_flag(Z80 *z80, uint8_t flag) +{ + return z80->regfile.f_ & (1 << flag); +} + +/* + Return the CPU's current interrupt mode. +*/ +static inline uint8_t get_interrupt_mode(Z80 *z80) +{ + if (!z80->regfile.im_a) + return 0; + if (!z80->regfile.im_b) + return 1; + return 2; +} + +#ifdef DEBUG_MODE +/* + DEBUG FUNCTION: Print out all register values to stdout. +*/ +void z80_dump_registers(Z80 *z80) +{ + Z80RegFile *regfile = &z80->regfile; + DEBUG("Dumping Z80 register values:") + + DEBUG("- AF: 0x%02X%02X (C: %u, N: %u, P/V: %u, H: %u, Z: %u, S: %u)", + regfile->a, regfile->f, + get_flag(z80, FLAG_CARRY), + get_flag(z80, FLAG_SUBTRACT), + get_flag(z80, FLAG_PARITY), + get_flag(z80, FLAG_HALFCARRY), + get_flag(z80, FLAG_ZERO), + get_flag(z80, FLAG_SIGN)) + + DEBUG("- BC: 0x%02X%02X", regfile->b, regfile->c) + DEBUG("- DE: 0x%02X%02X", regfile->d, regfile->e) + DEBUG("- HL: 0x%02X%02X", regfile->h, regfile->l) + + DEBUG("- AF': 0x%02X%02X (C: %u, N: %u, P/V: %u, H: %u, Z: %u, S: %u)", + regfile->a_, regfile->f_, + get_shadow_flag(z80, FLAG_CARRY), + get_shadow_flag(z80, FLAG_SUBTRACT), + get_shadow_flag(z80, FLAG_PARITY), + get_shadow_flag(z80, FLAG_HALFCARRY), + get_shadow_flag(z80, FLAG_ZERO), + get_shadow_flag(z80, FLAG_SIGN)) + + DEBUG("- BC': 0x%02X%02X", regfile->b_, regfile->c_) + DEBUG("- DE': 0x%02X%02X", regfile->d_, regfile->e_) + DEBUG("- HL': 0x%02X%02X", regfile->h_, regfile->l_) + + DEBUG("- IX: 0x%04X", regfile->ix) + DEBUG("- IY: 0x%04X", regfile->iy) + DEBUG("- SP: 0x%04X", regfile->sp) + DEBUG("- PC: 0x%04X", regfile->pc) + + DEBUG("- I: 0x%2X", regfile->i) + DEBUG("- R: 0x%2X", regfile->r) + + DEBUG("- IM: 0b%u%u (mode: %u)", regfile->im_a, regfile->im_b, get_interrupt_mode(z80)) + DEBUG("- IFF1: %u", regfile->iff1) + DEBUG("- IFF2: %u", regfile->iff2) +} +#endif diff --git a/src/z80.h b/src/z80.h index 7ed55a1..b3486db 100644 --- a/src/z80.h +++ b/src/z80.h @@ -3,11 +3,30 @@ #pragma once -/* Clock speed in Hz was taken from the official Sega GG documentation */ -#define CLOCK_SPEED 3579545 +#include +#include /* Structs */ typedef struct { - int pc; + uint8_t a, f, b, c, d, e, h, l; + uint8_t a_, f_, b_, c_, d_, e_, h_, l_; + uint16_t ix, iy, sp, pc; + uint8_t i, r; + bool im_a, im_b; + bool iff1, iff2; +} Z80RegFile; + +typedef struct { + Z80RegFile regfile; + uint64_t clock_speed; } Z80; + +/* Functions */ + +void z80_init(Z80*, uint64_t); +void z80_power(Z80*); + +#ifdef DEBUG_MODE +void z80_dump_registers(Z80*); +#endif