| @@ -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 | |||||