@@ -12,8 +12,6 @@ | |||||
#include "logging.h" | #include "logging.h" | ||||
#include "version.h" | #include "version.h" | ||||
#define ROMS_DIR "roms" | |||||
/* | /* | ||||
Print command-line help/usage. | Print command-line help/usage. | ||||
*/ | */ | ||||
@@ -5,6 +5,8 @@ | |||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#define ROMS_DIR "roms" | |||||
#define CONFIG_OK 0 | #define CONFIG_OK 0 | ||||
#define CONFIG_EXIT_SUCCESS 1 | #define CONFIG_EXIT_SUCCESS 1 | ||||
#define CONFIG_EXIT_FAILURE 2 | #define CONFIG_EXIT_FAILURE 2 | ||||
@@ -17,7 +17,9 @@ GameGear* gamegear_create() | |||||
if (!gg) | if (!gg) | ||||
OUT_OF_MEMORY() | OUT_OF_MEMORY() | ||||
gg->rom = NULL; | |||||
// mmu_init(&gg->mmu, ...); | |||||
z80_init(&gg->cpu, CPU_CLOCK_SPEED); | |||||
gg->powered = false; | |||||
return gg; | return gg; | ||||
} | } | ||||
@@ -34,11 +36,15 @@ void gamegear_destroy(GameGear *gg) | |||||
/* | /* | ||||
Load a ROM image into the GameGear object. | 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) | 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) | 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; | return; | ||||
// TODO | // TODO | ||||
gg->state = state; | |||||
// z80_do_cycles(&gg->cpu, ...); | |||||
} | } |
@@ -5,13 +5,19 @@ | |||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include "mmu.h" | |||||
#include "rom.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 */ | /* Structs */ | ||||
typedef struct { | typedef struct { | ||||
ROM *rom; | |||||
bool state; | |||||
MMU mmu; | |||||
Z80 cpu; | |||||
bool powered; | |||||
} GameGear; | } GameGear; | ||||
/* Functions */ | /* Functions */ | ||||
@@ -20,3 +26,4 @@ GameGear* gamegear_create(); | |||||
void gamegear_destroy(GameGear*); | void gamegear_destroy(GameGear*); | ||||
void gamegear_load(GameGear*, ROM*); | void gamegear_load(GameGear*, ROM*); | ||||
void gamegear_power(GameGear*, bool); | void gamegear_power(GameGear*, bool); | ||||
void gamegear_simulate(GameGear*); |
@@ -1,6 +1,8 @@ | |||||
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | ||||
Released under the terms of the MIT License. See LICENSE for details. */ | Released under the terms of the MIT License. See LICENSE for details. */ | ||||
#include <unistd.h> | |||||
#include "iomanager.h" | #include "iomanager.h" | ||||
#include "logging.h" | #include "logging.h" | ||||
@@ -14,7 +16,15 @@ void iomanager_emulate(GameGear *gg) | |||||
DEBUG("IOManager powering GameGear") | DEBUG("IOManager powering GameGear") | ||||
gamegear_power(gg, true); | 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") | DEBUG("IOManager unpowering GameGear") | ||||
gamegear_power(gg, false); | 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> | /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | ||||
Released under the terms of the MIT License. See LICENSE for details. */ | Released under the terms of the MIT License. See LICENSE for details. */ | ||||
#include "logging.h" | |||||
#include "z80.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 | #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 */ | /* Structs */ | ||||
typedef struct { | 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; | } Z80; | ||||
/* Functions */ | |||||
void z80_init(Z80*, uint64_t); | |||||
void z80_power(Z80*); | |||||
#ifdef DEBUG_MODE | |||||
void z80_dump_registers(Z80*); | |||||
#endif |