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