@@ -12,8 +12,6 @@ | |||
#include "logging.h" | |||
#include "version.h" | |||
#define ROMS_DIR "roms" | |||
/* | |||
Print command-line help/usage. | |||
*/ | |||
@@ -5,6 +5,8 @@ | |||
#include <stdbool.h> | |||
#define ROMS_DIR "roms" | |||
#define CONFIG_OK 0 | |||
#define CONFIG_EXIT_SUCCESS 1 | |||
#define CONFIG_EXIT_FAILURE 2 | |||
@@ -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, ...); | |||
} |
@@ -5,13 +5,19 @@ | |||
#include <stdbool.h> | |||
#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*); |
@@ -1,6 +1,8 @@ | |||
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
Released under the terms of the MIT License. See LICENSE for details. */ | |||
#include <unistd.h> | |||
#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); | |||
@@ -0,0 +1,12 @@ | |||
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
Released under the terms of the MIT License. See LICENSE for details. */ | |||
#include "z80.h" | |||
/* | |||
Initialize a MMU object. | |||
*/ | |||
// void mmu_init(MMU *mmu, ...) | |||
// { | |||
// // | |||
// } |
@@ -0,0 +1,16 @@ | |||
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
Released under the terms of the MIT License. See LICENSE for details. */ | |||
#pragma once | |||
// #include <> | |||
/* Structs */ | |||
typedef struct { | |||
// | |||
} MMU; | |||
/* Functions */ | |||
// void mmu_init(MMU*, ...); |
@@ -1,4 +1,126 @@ | |||
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
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 |
@@ -3,11 +3,30 @@ | |||
#pragma once | |||
/* Clock speed in Hz was taken from the official Sega GG documentation */ | |||
#define CLOCK_SPEED 3579545 | |||
#include <stdbool.h> | |||
#include <stdint.h> | |||
/* 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 |