Browse Source

Add registers to Z80, plus some skeleton code.

master
Ben Kurtovic 9 years ago
parent
commit
4127f2eb5d
9 changed files with 225 additions and 13 deletions
  1. +0
    -2
      src/config.c
  2. +2
    -0
      src/config.h
  3. +31
    -5
      src/gamegear.c
  4. +9
    -2
      src/gamegear.h
  5. +11
    -1
      src/iomanager.c
  6. +12
    -0
      src/mmu.c
  7. +16
    -0
      src/mmu.h
  8. +122
    -0
      src/z80.c
  9. +22
    -3
      src/z80.h

+ 0
- 2
src/config.c View File

@@ -12,8 +12,6 @@
#include "logging.h"
#include "version.h"

#define ROMS_DIR "roms"

/*
Print command-line help/usage.
*/


+ 2
- 0
src/config.h View File

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


+ 31
- 5
src/gamegear.c View File

@@ -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, ...);
}

+ 9
- 2
src/gamegear.h View File

@@ -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*);

+ 11
- 1
src/iomanager.c View File

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


+ 12
- 0
src/mmu.c View File

@@ -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, ...)
// {
// //
// }

+ 16
- 0
src/mmu.h View File

@@ -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*, ...);

+ 122
- 0
src/z80.c View File

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

+ 22
- 3
src/z80.h View File

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

Loading…
Cancel
Save