Mass name and type changes. Save states are now compatible between 32- and 64-bit systems. Maybe.
This commit is contained in:
parent
32a1ad87b7
commit
70bd90740a
@ -17,7 +17,7 @@
|
||||
|
||||
@property GBAudioClient *audioClient;
|
||||
- (void) vblank;
|
||||
- (void) log: (const char *) log withAttributes: (gb_log_attributes) attributes;
|
||||
- (void) log: (const char *) log withAttributes: (GB_log_attributes) attributes;
|
||||
- (const char *) getDebuggerInput;
|
||||
@end
|
||||
|
||||
@ -27,7 +27,7 @@ static void vblank(GB_gameboy_t *gb)
|
||||
[self vblank];
|
||||
}
|
||||
|
||||
static void consoleLog(GB_gameboy_t *gb, const char *string, gb_log_attributes attributes)
|
||||
static void consoleLog(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes)
|
||||
{
|
||||
Document *self = (__bridge Document *)(gb->user_data);
|
||||
[self log:string withAttributes: attributes];
|
||||
@ -39,7 +39,7 @@ static char *consoleInput(GB_gameboy_t *gb)
|
||||
return strdup([self getDebuggerInput]);
|
||||
}
|
||||
|
||||
static uint32_t rgbEncode(GB_gameboy_t *gb, unsigned char r, unsigned char g, unsigned char b)
|
||||
static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return (r << 0) | (g << 8) | (b << 16);
|
||||
}
|
||||
@ -71,47 +71,47 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, unsigned char r, unsigned char g, un
|
||||
|
||||
- (void) initDMG
|
||||
{
|
||||
gb_init(&gb);
|
||||
gb_load_bios(&gb, [[[NSBundle mainBundle] pathForResource:@"dmg_boot" ofType:@"bin"] UTF8String]);
|
||||
gb_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
gb_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
||||
gb_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
|
||||
gb_set_rgb_encode_callback(&gb, rgbEncode);
|
||||
GB_init(&gb);
|
||||
GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:@"dmg_boot" ofType:@"bin"] UTF8String]);
|
||||
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
GB_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
||||
GB_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
|
||||
GB_set_rgb_encode_callback(&gb, rgbEncode);
|
||||
gb.user_data = (__bridge void *)(self);
|
||||
}
|
||||
|
||||
- (void) initCGB
|
||||
{
|
||||
gb_init_cgb(&gb);
|
||||
gb_load_bios(&gb, [[[NSBundle mainBundle] pathForResource:@"cgb_boot" ofType:@"bin"] UTF8String]);
|
||||
gb_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
gb_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
||||
gb_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
|
||||
gb_set_rgb_encode_callback(&gb, rgbEncode);
|
||||
GB_init_cgb(&gb);
|
||||
GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:@"cgb_boot" ofType:@"bin"] UTF8String]);
|
||||
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
GB_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
||||
GB_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
|
||||
GB_set_rgb_encode_callback(&gb, rgbEncode);
|
||||
gb.user_data = (__bridge void *)(self);
|
||||
}
|
||||
|
||||
- (void) vblank
|
||||
{
|
||||
[self.view flip];
|
||||
gb_set_pixels_output(&gb, self.view.pixels);
|
||||
GB_set_pixels_output(&gb, self.view.pixels);
|
||||
}
|
||||
|
||||
- (void) run
|
||||
{
|
||||
running = true;
|
||||
gb_set_pixels_output(&gb, self.view.pixels);
|
||||
GB_set_pixels_output(&gb, self.view.pixels);
|
||||
self.view.gb = &gb;
|
||||
gb_set_sample_rate(&gb, 96000);
|
||||
GB_set_sample_rate(&gb, 96000);
|
||||
self.audioClient = [[GBAudioClient alloc] initWithRendererBlock:^(UInt32 sampleRate, UInt32 nFrames, GB_sample_t *buffer) {
|
||||
apu_copy_buffer(&gb, buffer, nFrames);
|
||||
GB_apu_copy_buffer(&gb, buffer, nFrames);
|
||||
} andSampleRate:96000];
|
||||
[self.audioClient start];
|
||||
while (running) {
|
||||
gb_run(&gb);
|
||||
GB_run(&gb);
|
||||
}
|
||||
[self.audioClient stop];
|
||||
gb_save_battery(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
|
||||
GB_save_battery(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
|
||||
stopping = false;
|
||||
}
|
||||
|
||||
@ -137,7 +137,7 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, unsigned char r, unsigned char g, un
|
||||
{
|
||||
bool was_cgb = gb.is_cgb;
|
||||
[self stop];
|
||||
gb_free(&gb);
|
||||
GB_free(&gb);
|
||||
is_inited = false;
|
||||
if (([sender tag] == 0 && was_cgb) || [sender tag] == 2) {
|
||||
[self initCGB];
|
||||
@ -165,7 +165,7 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, unsigned char r, unsigned char g, un
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
gb_free(&gb);
|
||||
GB_free(&gb);
|
||||
}
|
||||
|
||||
- (void)windowControllerDidLoadNib:(NSWindowController *)aController {
|
||||
@ -198,8 +198,8 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, unsigned char r, unsigned char g, un
|
||||
if (is_inited++) {
|
||||
return YES;
|
||||
}
|
||||
gb_load_rom(&gb, [fileName UTF8String]);
|
||||
gb_load_battery(&gb, [[[fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
|
||||
GB_load_rom(&gb, [fileName UTF8String]);
|
||||
GB_load_battery(&gb, [[[fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -283,7 +283,7 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, unsigned char r, unsigned char g, un
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (void) log: (const char *) string withAttributes: (gb_log_attributes) attributes
|
||||
- (void) log: (const char *) string withAttributes: (GB_log_attributes) attributes
|
||||
{
|
||||
if (pendingLogLines > 128) {
|
||||
/* The ROM causes so many errors in such a short time, and we can't handle it. */
|
||||
@ -367,7 +367,7 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, unsigned char r, unsigned char g, un
|
||||
if (!gb.debug_stopped) {
|
||||
[self stop];
|
||||
}
|
||||
gb_save_state(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:[NSString stringWithFormat:@"s%ld", (long)[sender tag] ]] UTF8String]);
|
||||
GB_save_state(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:[NSString stringWithFormat:@"s%ld", (long)[sender tag] ]] UTF8String]);
|
||||
if (was_running) {
|
||||
[self start];
|
||||
}
|
||||
@ -379,7 +379,7 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, unsigned char r, unsigned char g, un
|
||||
if (!gb.debug_stopped) {
|
||||
[self stop];
|
||||
}
|
||||
gb_load_state(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:[NSString stringWithFormat:@"s%ld", (long)[sender tag] ]] UTF8String]);
|
||||
GB_load_state(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:[NSString stringWithFormat:@"s%ld", (long)[sender tag] ]] UTF8String]);
|
||||
if (was_running) {
|
||||
[self start];
|
||||
}
|
||||
|
36
Core/apu.c
36
Core/apu.c
@ -27,7 +27,7 @@ static int16_t generate_square(double phase, int16_t amplitude, double duty)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int16_t generate_wave(double phase, int16_t amplitude, signed char *wave, unsigned char shift)
|
||||
static int16_t generate_wave(double phase, int16_t amplitude, int8_t *wave, uint8_t shift)
|
||||
{
|
||||
phase = fmod(phase, 2 * M_PI);
|
||||
return ((wave[(int)(phase / (2 * M_PI) * 32)]) >> shift) * (int)amplitude / 0xF;
|
||||
@ -60,7 +60,7 @@ static int16_t step_lfsr(uint16_t lfsr, bool uses_7_bit)
|
||||
/* General Todo: The APU emulation seems to fail many accuracy tests. It might require a rewrite with
|
||||
these tests in mind. */
|
||||
|
||||
void apu_render(GB_gameboy_t *gb, unsigned long sample_rate, unsigned long n_samples, GB_sample_t *samples)
|
||||
void GB_apu_render(GB_gameboy_t *gb, unsigned int sample_rate, unsigned int n_samples, GB_sample_t *samples)
|
||||
{
|
||||
for (; n_samples--; samples++) {
|
||||
samples->left = samples->right = 0;
|
||||
@ -112,7 +112,7 @@ void apu_render(GB_gameboy_t *gb, unsigned long sample_rate, unsigned long n_sam
|
||||
samples->left *= gb->apu.left_volume;
|
||||
samples->right *= gb->apu.right_volume;
|
||||
|
||||
for (unsigned char i = 0; i < 4; i++) {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
/* Phase */
|
||||
gb->apu.wave_channels[i].phase += 2 * M_PI * gb->apu.wave_channels[i].frequency / sample_rate;
|
||||
while (gb->apu.wave_channels[i].phase >= 2 * M_PI) {
|
||||
@ -137,7 +137,7 @@ void apu_render(GB_gameboy_t *gb, unsigned long sample_rate, unsigned long n_sam
|
||||
gb->apu.envelope_step_timer += 1.0 / sample_rate;
|
||||
if (gb->apu.envelope_step_timer >= 1.0 / 64) {
|
||||
gb->apu.envelope_step_timer -= 1.0 / 64;
|
||||
for (unsigned char i = 0; i < 4; i++) {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (gb->apu.wave_channels[i].envelope_steps && !--gb->apu.wave_channels[i].cur_envelope_steps) {
|
||||
gb->apu.wave_channels[i].amplitude = min(max(gb->apu.wave_channels[i].amplitude + gb->apu.wave_channels[i].envelope_direction * CH_STEP, 0), MAX_CH_AMP);
|
||||
gb->apu.wave_channels[i].cur_envelope_steps = gb->apu.wave_channels[i].envelope_steps;
|
||||
@ -151,7 +151,7 @@ void apu_render(GB_gameboy_t *gb, unsigned long sample_rate, unsigned long n_sam
|
||||
if (gb->apu.wave_channels[0].sweep_steps && !--gb->apu.wave_channels[0].cur_sweep_steps) {
|
||||
|
||||
// Convert back to GB format
|
||||
unsigned short temp = (unsigned short) (2048 - 131072 / gb->apu.wave_channels[0].frequency);
|
||||
uint16_t temp = (uint16_t) (2048 - 131072 / gb->apu.wave_channels[0].frequency);
|
||||
|
||||
// Apply sweep
|
||||
temp = temp + gb->apu.wave_channels[0].sweep_direction *
|
||||
@ -169,19 +169,19 @@ void apu_render(GB_gameboy_t *gb, unsigned long sample_rate, unsigned long n_sam
|
||||
}
|
||||
}
|
||||
|
||||
void apu_run(GB_gameboy_t *gb)
|
||||
void GB_apu_run(GB_gameboy_t *gb)
|
||||
{
|
||||
static bool should_log_overflow = true;
|
||||
while (gb->audio_copy_in_progress);
|
||||
double ticks_per_sample = (double) CPU_FREQUENCY / gb->sample_rate;
|
||||
while (gb->apu_cycles > ticks_per_sample) {
|
||||
GB_sample_t sample = {0, };
|
||||
apu_render(gb, gb->sample_rate, 1, &sample);
|
||||
GB_apu_render(gb, gb->sample_rate, 1, &sample);
|
||||
gb->apu_cycles -= ticks_per_sample;
|
||||
if (gb->audio_position == gb->buffer_size) {
|
||||
/*
|
||||
if (should_log_overflow && !gb->turbo) {
|
||||
gb_log(gb, "Audio overflow\n");
|
||||
GB_log(gb, "Audio overflow\n");
|
||||
should_log_overflow = false;
|
||||
}
|
||||
*/
|
||||
@ -193,7 +193,7 @@ void apu_run(GB_gameboy_t *gb)
|
||||
}
|
||||
}
|
||||
|
||||
void apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, unsigned int count)
|
||||
void GB_apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, unsigned int count)
|
||||
{
|
||||
gb->audio_copy_in_progress = true;
|
||||
|
||||
@ -204,7 +204,7 @@ void apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, unsigned int count)
|
||||
}
|
||||
|
||||
if (count > gb->audio_position) {
|
||||
// gb_log(gb, "Audio underflow: %d\n", count - gb->audio_position);
|
||||
// GB_log(gb, "Audio underflow: %d\n", count - gb->audio_position);
|
||||
memset(dest + gb->audio_position, 0, (count - gb->audio_position) * sizeof(*gb->audio_buffer));
|
||||
count = gb->audio_position;
|
||||
}
|
||||
@ -215,7 +215,7 @@ void apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, unsigned int count)
|
||||
gb->audio_copy_in_progress = false;
|
||||
}
|
||||
|
||||
void apu_init(GB_gameboy_t *gb)
|
||||
void GB_apu_init(GB_gameboy_t *gb)
|
||||
{
|
||||
memset(&gb->apu, 0, sizeof(gb->apu));
|
||||
gb->apu.wave_channels[0].duty = gb->apu.wave_channels[1].duty = 0.5;
|
||||
@ -227,12 +227,12 @@ void apu_init(GB_gameboy_t *gb)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char apu_read(GB_gameboy_t *gb, unsigned char reg)
|
||||
uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg)
|
||||
{
|
||||
/* Todo: what happens when reading from the wave from while it's playing? */
|
||||
|
||||
if (reg == GB_IO_NR52) {
|
||||
unsigned char value = 0;
|
||||
uint8_t value = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
value >>= 1;
|
||||
if (gb->apu.wave_channels[i].is_playing) {
|
||||
@ -260,17 +260,17 @@ unsigned char apu_read(GB_gameboy_t *gb, unsigned char reg)
|
||||
};
|
||||
|
||||
if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END && gb->apu.wave_channels[2].is_playing) {
|
||||
return (unsigned char)((gb->display_cycles * 22695477 * reg) >> 8); // Semi-random but deterministic
|
||||
return (uint8_t)((gb->display_cycles * 22695477 * reg) >> 8); // Semi-random but deterministic
|
||||
}
|
||||
|
||||
return gb->io_registers[reg] | read_mask[reg - GB_IO_NR10];
|
||||
}
|
||||
|
||||
void apu_write(GB_gameboy_t *gb, unsigned char reg, unsigned char value)
|
||||
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
|
||||
{
|
||||
static const double duties[] = {0.125, 0.25, 0.5, 0.75};
|
||||
static uint16_t NRX3_X4_temp[3] = {0};
|
||||
unsigned char channel = 0;
|
||||
uint8_t channel = 0;
|
||||
|
||||
if (!gb->apu.global_enable && reg != GB_IO_NR52) {
|
||||
return;
|
||||
@ -376,7 +376,7 @@ void apu_write(GB_gameboy_t *gb, unsigned char reg, unsigned char value)
|
||||
{
|
||||
double r = value & 0x7;
|
||||
if (r == 0) r = 0.5;
|
||||
unsigned char s = value >> 4;
|
||||
uint8_t s = value >> 4;
|
||||
gb->apu.wave_channels[3].frequency = 524288.0 / r / (1 << (s + 1));
|
||||
gb->apu.lfsr_7_bit = value & 0x8;
|
||||
break;
|
||||
@ -406,7 +406,7 @@ void apu_write(GB_gameboy_t *gb, unsigned char reg, unsigned char value)
|
||||
case GB_IO_NR52:
|
||||
|
||||
if ((value & 0x80) && !gb->apu.global_enable) {
|
||||
apu_init(gb);
|
||||
GB_apu_init(gb);
|
||||
gb->apu.global_enable = true;
|
||||
}
|
||||
else if (!(value & 0x80) && gb->apu.global_enable) {
|
||||
|
39
Core/apu.h
39
Core/apu.h
@ -7,6 +7,7 @@
|
||||
#define MAX_CH_AMP 0x1E00
|
||||
#define CH_STEP (0x1E00/0xF)
|
||||
|
||||
#include "save_struct.h"
|
||||
|
||||
struct GB_gameboy_s;
|
||||
typedef struct GB_gameboy_s GB_gameboy_t;
|
||||
@ -20,30 +21,30 @@ typedef struct
|
||||
/* Not all used on all channels */
|
||||
typedef struct
|
||||
{
|
||||
double phase;
|
||||
double frequency;
|
||||
GB_aligned_double phase;
|
||||
GB_aligned_double frequency;
|
||||
GB_aligned_double duty;
|
||||
GB_aligned_double sound_length; /* In seconds */
|
||||
int16_t amplitude;
|
||||
int16_t start_amplitude;
|
||||
double duty;
|
||||
double sound_length; /* In seconds */
|
||||
bool stop_on_length;
|
||||
unsigned char envelope_steps;
|
||||
unsigned char cur_envelope_steps;
|
||||
uint8_t envelope_steps;
|
||||
uint8_t cur_envelope_steps;
|
||||
signed int envelope_direction;
|
||||
unsigned char sweep_steps;
|
||||
unsigned char cur_sweep_steps;
|
||||
uint8_t sweep_steps;
|
||||
uint8_t cur_sweep_steps;
|
||||
signed int sweep_direction;
|
||||
unsigned char sweep_shift;
|
||||
uint8_t sweep_shift;
|
||||
bool is_playing;
|
||||
} GB_apu_channel_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GB_apu_channel_t wave_channels[4];
|
||||
double envelope_step_timer; /* In seconds */
|
||||
double sweep_step_timer; /* In seconds */
|
||||
signed char wave_form[32];
|
||||
unsigned char wave_shift;
|
||||
GB_aligned_double envelope_step_timer; /* In seconds */
|
||||
GB_aligned_double sweep_step_timer; /* In seconds */
|
||||
int8_t wave_form[32];
|
||||
uint8_t wave_shift;
|
||||
bool wave_enable;
|
||||
uint16_t lfsr;
|
||||
bool lfsr_7_bit;
|
||||
@ -54,11 +55,11 @@ typedef struct
|
||||
bool global_enable;
|
||||
} GB_apu_t;
|
||||
|
||||
void apu_render(GB_gameboy_t *gb, unsigned long sample_rate, unsigned long n_samples, GB_sample_t *samples);
|
||||
void apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, unsigned int count);
|
||||
void apu_write(GB_gameboy_t *gb, unsigned char reg, unsigned char value);
|
||||
unsigned char apu_read(GB_gameboy_t *gb, unsigned char reg);
|
||||
void apu_init(GB_gameboy_t *gb);
|
||||
void apu_run(GB_gameboy_t *gb);
|
||||
void GB_apu_render(GB_gameboy_t *gb, unsigned int sample_rate, unsigned int n_samples, GB_sample_t *samples);
|
||||
void GB_apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, unsigned int count);
|
||||
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value);
|
||||
uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg);
|
||||
void GB_apu_init(GB_gameboy_t *gb);
|
||||
void GB_apu_run(GB_gameboy_t *gb);
|
||||
|
||||
#endif /* apu_h */
|
||||
|
196
Core/debugger.c
196
Core/debugger.c
@ -15,17 +15,17 @@ typedef struct {
|
||||
LVALUE_REG_L,
|
||||
} kind;
|
||||
union {
|
||||
unsigned short *register_address;
|
||||
unsigned short memory_address;
|
||||
uint16_t *register_address;
|
||||
uint16_t memory_address;
|
||||
};
|
||||
} lvalue_t;
|
||||
|
||||
static unsigned short read_lvalue(GB_gameboy_t *gb, lvalue_t lvalue)
|
||||
static uint16_t read_lvalue(GB_gameboy_t *gb, lvalue_t lvalue)
|
||||
{
|
||||
/* Not used until we add support for operators like += */
|
||||
switch (lvalue.kind) {
|
||||
case LVALUE_MEMORY:
|
||||
return read_memory(gb, lvalue.memory_address);
|
||||
return GB_read_memory(gb, lvalue.memory_address);
|
||||
|
||||
case LVALUE_REG16:
|
||||
return *lvalue.register_address;
|
||||
@ -38,11 +38,11 @@ static unsigned short read_lvalue(GB_gameboy_t *gb, lvalue_t lvalue)
|
||||
}
|
||||
}
|
||||
|
||||
static void write_lvalue(GB_gameboy_t *gb, lvalue_t lvalue, unsigned short value)
|
||||
static void write_lvalue(GB_gameboy_t *gb, lvalue_t lvalue, uint16_t value)
|
||||
{
|
||||
switch (lvalue.kind) {
|
||||
case LVALUE_MEMORY:
|
||||
write_memory(gb, lvalue.memory_address, value);
|
||||
GB_write_memory(gb, lvalue.memory_address, value);
|
||||
return;
|
||||
|
||||
case LVALUE_REG16:
|
||||
@ -61,27 +61,27 @@ static void write_lvalue(GB_gameboy_t *gb, lvalue_t lvalue, unsigned short value
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned short add(unsigned short a, unsigned short b) {return a + b;};
|
||||
static unsigned short sub(unsigned short a, unsigned short b) {return a - b;};
|
||||
static unsigned short mul(unsigned short a, unsigned short b) {return a * b;};
|
||||
static unsigned short _div(unsigned short a, unsigned short b) {
|
||||
static uint16_t add(uint16_t a, uint16_t b) {return a + b;};
|
||||
static uint16_t sub(uint16_t a, uint16_t b) {return a - b;};
|
||||
static uint16_t mul(uint16_t a, uint16_t b) {return a * b;};
|
||||
static uint16_t _div(uint16_t a, uint16_t b) {
|
||||
if (b == 0) {
|
||||
return 0;
|
||||
}
|
||||
return a / b;
|
||||
};
|
||||
static unsigned short mod(unsigned short a, unsigned short b) {
|
||||
static uint16_t mod(uint16_t a, uint16_t b) {
|
||||
if (b == 0) {
|
||||
return 0;
|
||||
}
|
||||
return a % b;
|
||||
};
|
||||
static unsigned short and(unsigned short a, unsigned short b) {return a & b;};
|
||||
static unsigned short or(unsigned short a, unsigned short b) {return a | b;};
|
||||
static unsigned short xor(unsigned short a, unsigned short b) {return a ^ b;};
|
||||
static unsigned short shleft(unsigned short a, unsigned short b) {return a << b;};
|
||||
static unsigned short shright(unsigned short a, unsigned short b) {return a >> b;};
|
||||
static unsigned short assign(GB_gameboy_t *gb, lvalue_t a, unsigned short b)
|
||||
static uint16_t and(uint16_t a, uint16_t b) {return a & b;};
|
||||
static uint16_t or(uint16_t a, uint16_t b) {return a | b;};
|
||||
static uint16_t xor(uint16_t a, uint16_t b) {return a ^ b;};
|
||||
static uint16_t shleft(uint16_t a, uint16_t b) {return a << b;};
|
||||
static uint16_t shright(uint16_t a, uint16_t b) {return a >> b;};
|
||||
static uint16_t assign(GB_gameboy_t *gb, lvalue_t a, uint16_t b)
|
||||
{
|
||||
write_lvalue(gb, a, b);
|
||||
return read_lvalue(gb, a);
|
||||
@ -90,8 +90,8 @@ static unsigned short assign(GB_gameboy_t *gb, lvalue_t a, unsigned short b)
|
||||
static struct {
|
||||
const char *string;
|
||||
char priority;
|
||||
unsigned short (*operator)(unsigned short, unsigned short);
|
||||
unsigned short (*lvalue_operator)(GB_gameboy_t *, lvalue_t, unsigned short);
|
||||
uint16_t (*operator)(uint16_t, uint16_t);
|
||||
uint16_t (*lvalue_operator)(GB_gameboy_t *, lvalue_t, uint16_t);
|
||||
} operators[] =
|
||||
{
|
||||
// Yes. This is not C-like. But it makes much more sense.
|
||||
@ -109,7 +109,7 @@ static struct {
|
||||
{"=", 2, NULL, assign},
|
||||
};
|
||||
|
||||
unsigned short debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned int length, bool *error);
|
||||
uint16_t debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned int length, bool *error);
|
||||
|
||||
static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string, unsigned int length, bool *error)
|
||||
{
|
||||
@ -124,7 +124,7 @@ static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string, u
|
||||
}
|
||||
if (length == 0)
|
||||
{
|
||||
gb_log(gb, "Expected expression.\n");
|
||||
GB_log(gb, "Expected expression.\n");
|
||||
*error = true;
|
||||
return (lvalue_t){0,};
|
||||
}
|
||||
@ -183,17 +183,17 @@ static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string, u
|
||||
case 'p': if (string[2] == 'c') return (lvalue_t){LVALUE_REG16, .register_address = &gb->pc};
|
||||
}
|
||||
}
|
||||
gb_log(gb, "Unknown register: %.*s\n", length, string);
|
||||
GB_log(gb, "Unknown register: %.*s\n", length, string);
|
||||
*error = true;
|
||||
return (lvalue_t){0,};
|
||||
}
|
||||
|
||||
gb_log(gb, "Expression is not an lvalue: %.*s\n", length, string);
|
||||
GB_log(gb, "Expression is not an lvalue: %.*s\n", length, string);
|
||||
*error = true;
|
||||
return (lvalue_t){0,};
|
||||
}
|
||||
|
||||
unsigned short debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned int length, bool *error)
|
||||
uint16_t debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned int length, bool *error)
|
||||
{
|
||||
*error = false;
|
||||
// Strip whitespace
|
||||
@ -206,7 +206,7 @@ unsigned short debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned
|
||||
}
|
||||
if (length == 0)
|
||||
{
|
||||
gb_log(gb, "Expected expression.\n");
|
||||
GB_log(gb, "Expected expression.\n");
|
||||
*error = true;
|
||||
return -1;
|
||||
}
|
||||
@ -236,7 +236,7 @@ unsigned short debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned
|
||||
}
|
||||
if (string[i] == ']') depth--;
|
||||
}
|
||||
if (depth == 0) return read_memory(gb, debugger_evaluate(gb, string + 1, length - 2, error));
|
||||
if (depth == 0) return GB_read_memory(gb, debugger_evaluate(gb, string + 1, length - 2, error));
|
||||
}
|
||||
// Search for lowest priority operator
|
||||
signed int depth = 0;
|
||||
@ -262,14 +262,14 @@ unsigned short debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned
|
||||
}
|
||||
if (operator_index != -1) {
|
||||
unsigned int right_start = (unsigned int)(operator_pos + strlen(operators[operator_index].string));
|
||||
unsigned short right = debugger_evaluate(gb, string + right_start, length - right_start, error);
|
||||
uint16_t right = debugger_evaluate(gb, string + right_start, length - right_start, error);
|
||||
if (*error) return -1;
|
||||
if (operators[operator_index].lvalue_operator) {
|
||||
lvalue_t left = debugger_evaluate_lvalue(gb, string, operator_pos, error);
|
||||
if (*error) return -1;
|
||||
return operators[operator_index].lvalue_operator(gb, left, right);
|
||||
}
|
||||
unsigned short left = debugger_evaluate(gb, string, operator_pos, error);
|
||||
uint16_t left = debugger_evaluate(gb, string, operator_pos, error);
|
||||
if (*error) return -1;
|
||||
return operators[operator_index].operator(left, right);
|
||||
}
|
||||
@ -300,15 +300,15 @@ unsigned short debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned
|
||||
case 'p': if (string[2] == 'c') return gb->pc;
|
||||
}
|
||||
}
|
||||
gb_log(gb, "Unknown register: %.*s\n", length, string);
|
||||
GB_log(gb, "Unknown register: %.*s\n", length, string);
|
||||
*error = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *end;
|
||||
unsigned short literal = (unsigned short) (strtol(string, &end, 16));
|
||||
uint16_t literal = (uint16_t) (strtol(string, &end, 16));
|
||||
if (end != string + length) {
|
||||
gb_log(gb, "Failed to parse: %.*s\n", length, string);
|
||||
GB_log(gb, "Failed to parse: %.*s\n", length, string);
|
||||
*error = true;
|
||||
return -1;
|
||||
}
|
||||
@ -319,7 +319,7 @@ typedef bool debugger_command_imp_t(GB_gameboy_t *gb, char *arguments);
|
||||
|
||||
typedef struct {
|
||||
const char *command;
|
||||
unsigned char min_length;
|
||||
uint8_t min_length;
|
||||
debugger_command_imp_t *implementation;
|
||||
const char *help_string; // Null if should not appear in help
|
||||
} debugger_command_t;
|
||||
@ -335,7 +335,7 @@ static const char *lstrip(const char *str)
|
||||
static bool cont(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments))) {
|
||||
gb_log(gb, "Usage: continue\n");
|
||||
GB_log(gb, "Usage: continue\n");
|
||||
return true;
|
||||
}
|
||||
gb->debug_stopped = false;
|
||||
@ -345,7 +345,7 @@ static bool cont(GB_gameboy_t *gb, char *arguments)
|
||||
static bool next(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments))) {
|
||||
gb_log(gb, "Usage: next\n");
|
||||
GB_log(gb, "Usage: next\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -358,7 +358,7 @@ static bool next(GB_gameboy_t *gb, char *arguments)
|
||||
static bool step(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments))) {
|
||||
gb_log(gb, "Usage: step\n");
|
||||
GB_log(gb, "Usage: step\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -368,7 +368,7 @@ static bool step(GB_gameboy_t *gb, char *arguments)
|
||||
static bool finish(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments))) {
|
||||
gb_log(gb, "Usage: finish\n");
|
||||
GB_log(gb, "Usage: finish\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -381,7 +381,7 @@ static bool finish(GB_gameboy_t *gb, char *arguments)
|
||||
static bool stack_leak_detection(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments))) {
|
||||
gb_log(gb, "Usage: sld\n");
|
||||
GB_log(gb, "Usage: sld\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -394,23 +394,23 @@ static bool stack_leak_detection(GB_gameboy_t *gb, char *arguments)
|
||||
static bool registers(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments))) {
|
||||
gb_log(gb, "Usage: registers\n");
|
||||
GB_log(gb, "Usage: registers\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
gb_log(gb, "AF = %04x\n", gb->registers[GB_REGISTER_AF]);
|
||||
gb_log(gb, "BC = %04x\n", gb->registers[GB_REGISTER_BC]);
|
||||
gb_log(gb, "DE = %04x\n", gb->registers[GB_REGISTER_DE]);
|
||||
gb_log(gb, "HL = %04x\n", gb->registers[GB_REGISTER_HL]);
|
||||
gb_log(gb, "SP = %04x\n", gb->registers[GB_REGISTER_SP]);
|
||||
gb_log(gb, "PC = %04x\n", gb->pc);
|
||||
gb_log(gb, "TIMA = %d/%lu\n", gb->io_registers[GB_IO_TIMA], gb->tima_cycles);
|
||||
gb_log(gb, "Display Controller: LY = %d/%lu\n", gb->io_registers[GB_IO_LY], gb->display_cycles % 456);
|
||||
GB_log(gb, "AF = %04x\n", gb->registers[GB_REGISTER_AF]);
|
||||
GB_log(gb, "BC = %04x\n", gb->registers[GB_REGISTER_BC]);
|
||||
GB_log(gb, "DE = %04x\n", gb->registers[GB_REGISTER_DE]);
|
||||
GB_log(gb, "HL = %04x\n", gb->registers[GB_REGISTER_HL]);
|
||||
GB_log(gb, "SP = %04x\n", gb->registers[GB_REGISTER_SP]);
|
||||
GB_log(gb, "PC = %04x\n", gb->pc);
|
||||
GB_log(gb, "TIMA = %d/%u\n", gb->io_registers[GB_IO_TIMA], gb->tima_cycles);
|
||||
GB_log(gb, "Display Controller: LY = %d/%u\n", gb->io_registers[GB_IO_LY], gb->display_cycles % 456);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Find the index of the closest breakpoint equal or greater to addr */
|
||||
static unsigned short find_breakpoint(GB_gameboy_t *gb, unsigned short addr)
|
||||
static uint16_t find_breakpoint(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (!gb->breakpoints) {
|
||||
return 0;
|
||||
@ -418,7 +418,7 @@ static unsigned short find_breakpoint(GB_gameboy_t *gb, unsigned short addr)
|
||||
int min = 0;
|
||||
int max = gb->n_breakpoints;
|
||||
while (min < max) {
|
||||
unsigned short pivot = (min + max) / 2;
|
||||
uint16_t pivot = (min + max) / 2;
|
||||
if (gb->breakpoints[pivot] == addr) return pivot;
|
||||
if (gb->breakpoints[pivot] > addr) {
|
||||
max = pivot - 1;
|
||||
@ -427,24 +427,24 @@ static unsigned short find_breakpoint(GB_gameboy_t *gb, unsigned short addr)
|
||||
min = pivot + 1;
|
||||
}
|
||||
}
|
||||
return (unsigned short) min;
|
||||
return (uint16_t) min;
|
||||
}
|
||||
|
||||
static bool breakpoint(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments)) == 0) {
|
||||
gb_log(gb, "Usage: breakpoint <expression>\n");
|
||||
GB_log(gb, "Usage: breakpoint <expression>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool error;
|
||||
unsigned short result = debugger_evaluate(gb, arguments, (unsigned int)strlen(arguments), &error);
|
||||
uint16_t result = debugger_evaluate(gb, arguments, (unsigned int)strlen(arguments), &error);
|
||||
|
||||
if (error) return true;
|
||||
|
||||
unsigned short index = find_breakpoint(gb, result);
|
||||
uint16_t index = find_breakpoint(gb, result);
|
||||
if (index < gb->n_breakpoints && gb->breakpoints[index] == result) {
|
||||
gb_log(gb, "Breakpoint already set at %04x\n", result);
|
||||
GB_log(gb, "Breakpoint already set at %04x\n", result);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -453,14 +453,14 @@ static bool breakpoint(GB_gameboy_t *gb, char *arguments)
|
||||
gb->breakpoints[index] = result;
|
||||
gb->n_breakpoints++;
|
||||
|
||||
gb_log(gb, "Breakpoint set at %04x\n", result);
|
||||
GB_log(gb, "Breakpoint set at %04x\n", result);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool delete(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments)) == 0) {
|
||||
gb_log(gb, "Delete all breakpoints? ");
|
||||
GB_log(gb, "Delete all breakpoints? ");
|
||||
char *answer = gb->input_callback(gb);
|
||||
if (answer[0] == 'Y' || answer[0] == 'y') {
|
||||
free(gb->breakpoints);
|
||||
@ -471,13 +471,13 @@ static bool delete(GB_gameboy_t *gb, char *arguments)
|
||||
}
|
||||
|
||||
bool error;
|
||||
unsigned short result = debugger_evaluate(gb, arguments, (unsigned int)strlen(arguments), &error);
|
||||
uint16_t result = debugger_evaluate(gb, arguments, (unsigned int)strlen(arguments), &error);
|
||||
|
||||
if (error) return true;
|
||||
|
||||
unsigned short index = find_breakpoint(gb, result);
|
||||
uint16_t index = find_breakpoint(gb, result);
|
||||
if (index >= gb->n_breakpoints || gb->breakpoints[index] != result) {
|
||||
gb_log(gb, "No breakpoint set at %04x\n", result);
|
||||
GB_log(gb, "No breakpoint set at %04x\n", result);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -485,33 +485,33 @@ static bool delete(GB_gameboy_t *gb, char *arguments)
|
||||
gb->n_breakpoints--;
|
||||
gb->breakpoints = realloc(gb->breakpoints, gb->n_breakpoints * sizeof(gb->breakpoints[0]));
|
||||
|
||||
gb_log(gb, "Breakpoint removed from %04x\n", result);
|
||||
GB_log(gb, "Breakpoint removed from %04x\n", result);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool list(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments))) {
|
||||
gb_log(gb, "Usage: list\n");
|
||||
GB_log(gb, "Usage: list\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (gb->n_breakpoints == 0) {
|
||||
gb_log(gb, "No breakpoints set.\n");
|
||||
GB_log(gb, "No breakpoints set.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
gb_log(gb, "%d breakpoint(s) set:\n", gb->n_breakpoints);
|
||||
for (unsigned short i = 0; i < gb->n_breakpoints; i++) {
|
||||
gb_log(gb, " %d. %04x\n", i + 1, gb->breakpoints[i]);
|
||||
GB_log(gb, "%d breakpoint(s) set:\n", gb->n_breakpoints);
|
||||
for (uint16_t i = 0; i < gb->n_breakpoints; i++) {
|
||||
GB_log(gb, " %d. %04x\n", i + 1, gb->breakpoints[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool should_break(GB_gameboy_t *gb, unsigned short addr)
|
||||
static bool should_break(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
unsigned short index = find_breakpoint(gb, addr);
|
||||
uint16_t index = find_breakpoint(gb, addr);
|
||||
if (index < gb->n_breakpoints && gb->breakpoints[index] == addr) {
|
||||
return true;
|
||||
}
|
||||
@ -521,14 +521,14 @@ static bool should_break(GB_gameboy_t *gb, unsigned short addr)
|
||||
static bool print(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments)) == 0) {
|
||||
gb_log(gb, "Usage: print <expression>\n");
|
||||
GB_log(gb, "Usage: print <expression>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool error;
|
||||
unsigned short result = debugger_evaluate(gb, arguments, (unsigned int)strlen(arguments), &error);
|
||||
uint16_t result = debugger_evaluate(gb, arguments, (unsigned int)strlen(arguments), &error);
|
||||
if (!error) {
|
||||
gb_log(gb, "=%04x\n", result);
|
||||
GB_log(gb, "=%04x\n", result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -536,18 +536,18 @@ static bool print(GB_gameboy_t *gb, char *arguments)
|
||||
static bool examine(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments)) == 0) {
|
||||
gb_log(gb, "Usage: examine <expression>\n");
|
||||
GB_log(gb, "Usage: examine <expression>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool error;
|
||||
unsigned short addr = debugger_evaluate(gb, arguments, (unsigned int)strlen(arguments), &error);
|
||||
uint16_t addr = debugger_evaluate(gb, arguments, (unsigned int)strlen(arguments), &error);
|
||||
if (!error) {
|
||||
gb_log(gb, "%4x: ", addr);
|
||||
GB_log(gb, "%4x: ", addr);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
gb_log(gb, "%02x ", read_memory(gb, addr + i));
|
||||
GB_log(gb, "%02x ", GB_read_memory(gb, addr + i));
|
||||
}
|
||||
gb_log(gb, "\n");
|
||||
GB_log(gb, "\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -555,41 +555,41 @@ static bool examine(GB_gameboy_t *gb, char *arguments)
|
||||
static bool mbc(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments))) {
|
||||
gb_log(gb, "Usage: mbc\n");
|
||||
GB_log(gb, "Usage: mbc\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
const GB_cartridge_t *cartridge = gb->cartridge_type;
|
||||
|
||||
if (cartridge->has_ram) {
|
||||
gb_log(gb, "Cartrdige includes%s RAM: %zx\n", cartridge->has_battery? " battery-backed": "", gb->mbc_ram_size);
|
||||
GB_log(gb, "Cartrdige includes%s RAM: %x\n", cartridge->has_battery? " battery-backed": "", gb->mbc_ram_size);
|
||||
}
|
||||
else {
|
||||
gb_log(gb, "No cartridge RAM\n");
|
||||
GB_log(gb, "No cartridge RAM\n");
|
||||
}
|
||||
|
||||
if (cartridge->mbc_type) {
|
||||
gb_log(gb, "MBC%d\n", cartridge->mbc_type);
|
||||
gb_log(gb, "Current mapped ROM bank: %x\n", gb->mbc_rom_bank);
|
||||
GB_log(gb, "MBC%d\n", cartridge->mbc_type);
|
||||
GB_log(gb, "Current mapped ROM bank: %x\n", gb->mbc_rom_bank);
|
||||
if (cartridge->has_ram) {
|
||||
gb_log(gb, "Current mapped RAM bank: %x\n", gb->mbc_ram_bank);
|
||||
gb_log(gb, "RAM is curently %s\n", gb->mbc_ram_enable? "enabled" : "disabled");
|
||||
GB_log(gb, "Current mapped RAM bank: %x\n", gb->mbc_ram_bank);
|
||||
GB_log(gb, "RAM is curently %s\n", gb->mbc_ram_enable? "enabled" : "disabled");
|
||||
}
|
||||
if (cartridge->mbc_type == MBC1) {
|
||||
gb_log(gb, "MBC1 banking mode is %s\n", gb->mbc_ram_banking? "RAM" : "ROM");
|
||||
GB_log(gb, "MBC1 banking mode is %s\n", gb->mbc_ram_banking? "RAM" : "ROM");
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
gb_log(gb, "No MBC\n");
|
||||
GB_log(gb, "No MBC\n");
|
||||
}
|
||||
|
||||
if (cartridge->has_rumble) {
|
||||
gb_log(gb, "Cart contains a rumble pak\n");
|
||||
GB_log(gb, "Cart contains a rumble pak\n");
|
||||
}
|
||||
|
||||
if (cartridge->has_rtc) {
|
||||
gb_log(gb, "Cart contains a real time clock\n");
|
||||
GB_log(gb, "Cart contains a real time clock\n");
|
||||
}
|
||||
|
||||
|
||||
@ -622,8 +622,8 @@ static bool help(GB_gameboy_t *gb, char *arguments)
|
||||
const debugger_command_t *command = commands;
|
||||
for (size_t i = sizeof(commands) / sizeof(*command); i--; command++) {
|
||||
if (command->help_string) {
|
||||
gb_attributed_log(gb, GB_LOG_BOLD, "%s", command->command);
|
||||
gb_log(gb, ": %s\n", command->help_string);
|
||||
GB_attributed_log(gb, GB_LOG_BOLD, "%s", command->command);
|
||||
GB_log(gb, ": %s\n", command->help_string);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -643,13 +643,13 @@ static const debugger_command_t *find_command(const char *string)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void debugger_call_hook(GB_gameboy_t *gb)
|
||||
void GB_debugger_call_hook(GB_gameboy_t *gb)
|
||||
{
|
||||
/* Called just after the CPU calls a function/enters an interrupt/etc... */
|
||||
|
||||
if (gb->stack_leak_detection) {
|
||||
if (gb->debug_call_depth >= sizeof(gb->sp_for_call_depth) / sizeof(gb->sp_for_call_depth[0])) {
|
||||
gb_log(gb, "Potential stack overflow detected (Functions nest too much). \n");
|
||||
GB_log(gb, "Potential stack overflow detected (Functions nest too much). \n");
|
||||
gb->debug_stopped = true;
|
||||
}
|
||||
else {
|
||||
@ -661,7 +661,7 @@ void debugger_call_hook(GB_gameboy_t *gb)
|
||||
gb->debug_call_depth++;
|
||||
}
|
||||
|
||||
void debugger_ret_hook(GB_gameboy_t *gb)
|
||||
void GB_debugger_ret_hook(GB_gameboy_t *gb)
|
||||
{
|
||||
/* Called just before the CPU runs ret/reti */
|
||||
|
||||
@ -669,13 +669,13 @@ void debugger_ret_hook(GB_gameboy_t *gb)
|
||||
|
||||
if (gb->stack_leak_detection) {
|
||||
if (gb->debug_call_depth < 0) {
|
||||
gb_log(gb, "Function finished without a stack leak.\n");
|
||||
GB_log(gb, "Function finished without a stack leak.\n");
|
||||
gb->debug_stopped = true;
|
||||
}
|
||||
else {
|
||||
if (gb->registers[GB_REGISTER_SP] != gb->sp_for_call_depth[gb->debug_call_depth]) {
|
||||
gb_log(gb, "Stack leak detected for function %04x!\n", gb->addr_for_call_depth[gb->debug_call_depth]);
|
||||
gb_log(gb, "SP is %04x, should be %04x.\n", gb->registers[GB_REGISTER_SP],
|
||||
GB_log(gb, "Stack leak detected for function %04x!\n", gb->addr_for_call_depth[gb->debug_call_depth]);
|
||||
GB_log(gb, "SP is %04x, should be %04x.\n", gb->registers[GB_REGISTER_SP],
|
||||
gb->sp_for_call_depth[gb->debug_call_depth]);
|
||||
gb->debug_stopped = true;
|
||||
}
|
||||
@ -683,7 +683,7 @@ void debugger_ret_hook(GB_gameboy_t *gb)
|
||||
}
|
||||
}
|
||||
|
||||
void debugger_run(GB_gameboy_t *gb)
|
||||
void GB_debugger_run(GB_gameboy_t *gb)
|
||||
{
|
||||
char *input = NULL;
|
||||
if (gb->debug_next_command && gb->debug_call_depth <= 0) {
|
||||
@ -693,7 +693,7 @@ void debugger_run(GB_gameboy_t *gb)
|
||||
gb->debug_stopped = true;
|
||||
}
|
||||
if (gb->debug_stopped) {
|
||||
cpu_disassemble(gb, gb->pc, 5);
|
||||
GB_cpu_disassemble(gb, gb->pc, 5);
|
||||
}
|
||||
next_command:
|
||||
if (input) {
|
||||
@ -701,8 +701,8 @@ next_command:
|
||||
}
|
||||
if (!gb->debug_stopped && should_break(gb, gb->pc)) {
|
||||
gb->debug_stopped = true;
|
||||
gb_log(gb, "Breakpoint: PC = %04x\n", gb->pc);
|
||||
cpu_disassemble(gb, gb->pc, 5);
|
||||
GB_log(gb, "Breakpoint: PC = %04x\n", gb->pc);
|
||||
GB_cpu_disassemble(gb, gb->pc, 5);
|
||||
}
|
||||
if (gb->debug_stopped) {
|
||||
gb->debug_next_command = false;
|
||||
@ -731,7 +731,7 @@ next_command:
|
||||
}
|
||||
}
|
||||
else {
|
||||
gb_log(gb, "%s: no such command.\n", command_string);
|
||||
GB_log(gb, "%s: no such command.\n", command_string);
|
||||
goto next_command;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
#define debugger_h
|
||||
#include "gb.h"
|
||||
|
||||
void debugger_run(GB_gameboy_t *gb);
|
||||
void debugger_call_hook(GB_gameboy_t *gb);
|
||||
void debugger_ret_hook(GB_gameboy_t *gb);
|
||||
void GB_debugger_run(GB_gameboy_t *gb);
|
||||
void GB_debugger_call_hook(GB_gameboy_t *gb);
|
||||
void GB_debugger_ret_hook(GB_gameboy_t *gb);
|
||||
|
||||
#endif /* debugger_h */
|
||||
|
@ -9,14 +9,14 @@
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
unsigned char y;
|
||||
unsigned char x;
|
||||
unsigned char tile;
|
||||
unsigned char flags;
|
||||
uint8_t y;
|
||||
uint8_t x;
|
||||
uint8_t tile;
|
||||
uint8_t flags;
|
||||
} GB_sprite_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
static uint32_t get_pixel(GB_gameboy_t *gb, unsigned char x, unsigned char y)
|
||||
static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
|
||||
{
|
||||
/*
|
||||
Bit 7 - LCD Display Enable (0=Off, 1=On)
|
||||
@ -28,17 +28,17 @@ static uint32_t get_pixel(GB_gameboy_t *gb, unsigned char x, unsigned char y)
|
||||
Bit 1 - OBJ (Sprite) Display Enable (0=Off, 1=On)
|
||||
Bit 0 - BG Display (for CGB see below) (0=Off, 1=On)
|
||||
*/
|
||||
unsigned short map = 0x1800;
|
||||
unsigned char tile = 0;
|
||||
unsigned char attributes = 0;
|
||||
unsigned char sprite_palette = 0;
|
||||
unsigned short tile_address = 0;
|
||||
unsigned char background_pixel = 0, sprite_pixel = 0;
|
||||
uint16_t map = 0x1800;
|
||||
uint8_t tile = 0;
|
||||
uint8_t attributes = 0;
|
||||
uint8_t sprite_palette = 0;
|
||||
uint16_t tile_address = 0;
|
||||
uint8_t background_pixel = 0, sprite_pixel = 0;
|
||||
GB_sprite_t *sprite = (GB_sprite_t *) &gb->oam;
|
||||
unsigned char sprites_in_line = 0;
|
||||
uint8_t sprites_in_line = 0;
|
||||
bool lcd_8_16_mode = (gb->io_registers[GB_IO_LCDC] & 4) != 0;
|
||||
bool sprites_enabled = (gb->io_registers[GB_IO_LCDC] & 2) != 0;
|
||||
unsigned char lowest_sprite_x = 0xFF;
|
||||
uint8_t lowest_sprite_x = 0xFF;
|
||||
bool use_obp1 = false, priority = false;
|
||||
bool in_window = false;
|
||||
if (gb->effective_window_enabled && (gb->io_registers[GB_IO_LCDC] & 0x20)) { /* Window Enabled */
|
||||
@ -49,13 +49,13 @@ static uint32_t get_pixel(GB_gameboy_t *gb, unsigned char x, unsigned char y)
|
||||
|
||||
if (sprites_enabled) {
|
||||
// Loop all sprites
|
||||
for (unsigned char i = 40; i--; sprite++) {
|
||||
for (uint8_t i = 40; i--; sprite++) {
|
||||
int sprite_y = sprite->y - 16;
|
||||
int sprite_x = sprite->x - 8;
|
||||
// Is sprite in our line?
|
||||
if (sprite_y <= y && sprite_y + (lcd_8_16_mode? 16:8) > y) {
|
||||
unsigned char tile_x, tile_y, current_sprite_pixel;
|
||||
unsigned short line_address;
|
||||
uint8_t tile_x, tile_y, current_sprite_pixel;
|
||||
uint16_t line_address;
|
||||
// Limit to 10 sprites in one scan line.
|
||||
if (++sprites_in_line == 11) break;
|
||||
// Does not overlap our pixel.
|
||||
@ -129,7 +129,7 @@ static uint32_t get_pixel(GB_gameboy_t *gb, unsigned char x, unsigned char y)
|
||||
tile_address = tile * 0x10;
|
||||
}
|
||||
else {
|
||||
tile_address = (signed char) tile * 0x10 + 0x1000;
|
||||
tile_address = (int8_t) tile * 0x10 + 0x1000;
|
||||
}
|
||||
if (attributes & 0x8) {
|
||||
tile_address += 0x2000;
|
||||
@ -171,7 +171,7 @@ void display_vblank(GB_gameboy_t *gb)
|
||||
if (gb->turbo) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
signed long nanoseconds = (now.tv_usec) * 1000 + now.tv_sec * 1000000000L;
|
||||
int64_t nanoseconds = (now.tv_usec) * 1000 + now.tv_sec * 1000000000L;
|
||||
if (nanoseconds <= gb->last_vblank + FRAME_LENGTH) {
|
||||
return;
|
||||
}
|
||||
@ -209,7 +209,7 @@ void display_vblank(GB_gameboy_t *gb)
|
||||
struct timespec sleep = {0,};
|
||||
gettimeofday(&now, NULL);
|
||||
signed long nanoseconds = (now.tv_usec) * 1000 + now.tv_sec * 1000000000L;
|
||||
if (labs(nanoseconds - gb->last_vblank) < FRAME_LENGTH ) {
|
||||
if (labs((signed long)(nanoseconds - gb->last_vblank)) < FRAME_LENGTH ) {
|
||||
sleep.tv_nsec = (FRAME_LENGTH + gb->last_vblank - nanoseconds);
|
||||
nanosleep(&sleep, NULL);
|
||||
|
||||
@ -221,21 +221,21 @@ void display_vblank(GB_gameboy_t *gb)
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned char scale_channel(unsigned char x)
|
||||
static inline uint8_t scale_channel(uint8_t x)
|
||||
{
|
||||
x &= 0x1f;
|
||||
return (x << 3) | (x >> 2);
|
||||
}
|
||||
|
||||
void palette_changed(GB_gameboy_t *gb, bool background_palette, unsigned char index)
|
||||
void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index)
|
||||
{
|
||||
unsigned char *palette_data = background_palette? gb->background_palletes_data : gb->sprite_palletes_data;
|
||||
unsigned short color = palette_data[index & ~1] | (palette_data[index | 1] << 8);
|
||||
uint8_t *palette_data = background_palette? gb->background_palletes_data : gb->sprite_palletes_data;
|
||||
uint16_t color = palette_data[index & ~1] | (palette_data[index | 1] << 8);
|
||||
|
||||
// No need to &, scale channel does that.
|
||||
unsigned char r = scale_channel(color);
|
||||
unsigned char g = scale_channel(color >> 5);
|
||||
unsigned char b = scale_channel(color >> 10);
|
||||
uint8_t r = scale_channel(color);
|
||||
uint8_t g = scale_channel(color >> 5);
|
||||
uint8_t b = scale_channel(color >> 10);
|
||||
assert (gb->rgb_encode_callback);
|
||||
(background_palette? gb->background_palletes_rgb : gb->sprite_palletes_rgb)[index / 2] = gb->rgb_encode_callback(gb, r, g, b);
|
||||
}
|
||||
@ -257,7 +257,7 @@ void palette_changed(GB_gameboy_t *gb, bool background_palette, unsigned char in
|
||||
#define MODE1_LENGTH 204
|
||||
#define LINE_LENGTH (MODE2_LENGTH + MODE3_LENGTH + MODE1_LENGTH) // = 456
|
||||
|
||||
void display_run(GB_gameboy_t *gb)
|
||||
void GB_display_run(GB_gameboy_t *gb)
|
||||
{
|
||||
/*
|
||||
Display controller bug: For some reason, the OAM STAT interrupt is called, as expected, for LY = 0..143.
|
||||
@ -271,10 +271,10 @@ void display_run(GB_gameboy_t *gb)
|
||||
http://board.byuu.org/phpbb3/viewtopic.php?p=25527#p25531
|
||||
*/
|
||||
|
||||
unsigned char previous_stat_interrupt_line = gb->stat_interrupt_line;
|
||||
uint8_t previous_stat_interrupt_line = gb->stat_interrupt_line;
|
||||
gb->stat_interrupt_line = false;
|
||||
|
||||
unsigned char last_mode = gb->io_registers[GB_IO_STAT] & 3;
|
||||
uint8_t last_mode = gb->io_registers[GB_IO_STAT] & 3;
|
||||
gb->io_registers[GB_IO_STAT] &= ~3;
|
||||
|
||||
if (gb->display_cycles >= LCDC_PERIOD) {
|
||||
@ -360,7 +360,7 @@ void display_run(GB_gameboy_t *gb)
|
||||
|
||||
/* Render. This chunk is outside the Mode 3 if, because otherwise we might not render some pixels, since this
|
||||
function only runs between atomic CPU changes, and not every clock. */
|
||||
signed short current_lcdc_x = ((gb->display_cycles % LINE_LENGTH - MODE2_LENGTH) & ~7) - (gb->effective_scx & 0x7);
|
||||
int16_t current_lcdc_x = ((gb->display_cycles % LINE_LENGTH - MODE2_LENGTH) & ~7) - (gb->effective_scx & 0x7);
|
||||
for (;gb->previous_lcdc_x < current_lcdc_x; gb->previous_lcdc_x++) {
|
||||
if (gb->previous_lcdc_x >= 160) {
|
||||
continue;
|
||||
|
@ -2,6 +2,6 @@
|
||||
#define display_h
|
||||
|
||||
#include "gb.h"
|
||||
void display_run(GB_gameboy_t *gb);
|
||||
void palette_changed(GB_gameboy_t *gb, bool background_palette, unsigned char index);
|
||||
void GB_display_run(GB_gameboy_t *gb);
|
||||
void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index);
|
||||
#endif /* display_h */
|
||||
|
60
Core/gb.c
60
Core/gb.c
@ -59,7 +59,7 @@ static const GB_cartridge_t cart_defs[256] = {
|
||||
{ NO_MBC, true , true , false, false}, // FFh HuC1+RAM+BATTERY
|
||||
};
|
||||
|
||||
void gb_attributed_logv(GB_gameboy_t *gb, gb_log_attributes attributes, const char *fmt, va_list args)
|
||||
void GB_attributed_logv(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, va_list args)
|
||||
{
|
||||
char *string = NULL;
|
||||
vasprintf(&string, fmt, args);
|
||||
@ -75,19 +75,19 @@ void gb_attributed_logv(GB_gameboy_t *gb, gb_log_attributes attributes, const ch
|
||||
free(string);
|
||||
}
|
||||
|
||||
void gb_attributed_log(GB_gameboy_t *gb, gb_log_attributes attributes, const char *fmt, ...)
|
||||
void GB_attributed_log(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
gb_attributed_logv(gb, attributes, fmt, args);
|
||||
GB_attributed_logv(gb, attributes, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void gb_log(GB_gameboy_t *gb,const char *fmt, ...)
|
||||
void GB_log(GB_gameboy_t *gb,const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
gb_attributed_logv(gb, 0, fmt, args);
|
||||
GB_attributed_logv(gb, 0, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ static char *default_input_callback(GB_gameboy_t *gb)
|
||||
return expression;
|
||||
}
|
||||
|
||||
void gb_init(GB_gameboy_t *gb)
|
||||
void GB_init(GB_gameboy_t *gb)
|
||||
{
|
||||
memset(gb, 0, sizeof(*gb));
|
||||
gb->magic = (uintptr_t)'SAME';
|
||||
@ -136,7 +136,7 @@ void gb_init(GB_gameboy_t *gb)
|
||||
gb->io_registers[GB_IO_JOYP] = 0xF;
|
||||
}
|
||||
|
||||
void gb_init_cgb(GB_gameboy_t *gb)
|
||||
void GB_init_cgb(GB_gameboy_t *gb)
|
||||
{
|
||||
memset(gb, 0, sizeof(*gb));
|
||||
gb->magic = (uintptr_t)'SAME';
|
||||
@ -160,7 +160,7 @@ void gb_init_cgb(GB_gameboy_t *gb)
|
||||
gb->io_registers[GB_IO_JOYP] = 0xF;
|
||||
}
|
||||
|
||||
void gb_free(GB_gameboy_t *gb)
|
||||
void GB_free(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->ram) {
|
||||
free(gb->ram);
|
||||
@ -182,16 +182,16 @@ void gb_free(GB_gameboy_t *gb)
|
||||
}
|
||||
}
|
||||
|
||||
int gb_load_bios(GB_gameboy_t *gb, const char *path)
|
||||
int GB_load_boot_rom(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "r");
|
||||
if (!f) return errno;
|
||||
fread(gb->bios, sizeof(gb->bios), 1, f);
|
||||
fread(gb->boot_rom, sizeof(gb->boot_rom), 1, f);
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gb_load_rom(GB_gameboy_t *gb, const char *path)
|
||||
int GB_load_rom(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "r");
|
||||
if (!f) return errno;
|
||||
@ -228,7 +228,7 @@ static bool dump_section(FILE *f, const void *src, uint32_t size)
|
||||
#define DUMP_SECTION(gb, f, section) dump_section(f, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section))
|
||||
|
||||
/* Todo: we need a sane and protable save state format. */
|
||||
int gb_save_state(GB_gameboy_t *gb, const char *path)
|
||||
int GB_save_state(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "w");
|
||||
if (!f) {
|
||||
@ -290,7 +290,7 @@ static bool read_section(FILE *f, void *dest, uint32_t size)
|
||||
|
||||
#define READ_SECTION(gb, f, section) read_section(f, GB_GET_SECTION(gb, section), GB_SECTION_SIZE(section))
|
||||
|
||||
int gb_load_state(GB_gameboy_t *gb, const char *path)
|
||||
int GB_load_state(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
GB_gameboy_t save;
|
||||
|
||||
@ -313,31 +313,31 @@ int gb_load_state(GB_gameboy_t *gb, const char *path)
|
||||
if (!READ_SECTION(&save, f, video )) goto error;
|
||||
|
||||
if (gb->magic != save.magic) {
|
||||
gb_log(gb, "File is not a save state, or is from an incompatible operating system.\n");
|
||||
GB_log(gb, "File is not a save state, or is from an incompatible operating system.\n");
|
||||
errno = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (gb->version != save.version) {
|
||||
gb_log(gb, "Save state is for a different version of SameBoy.\n");
|
||||
GB_log(gb, "Save state is for a different version of SameBoy.\n");
|
||||
errno = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (gb->mbc_ram_size != save.mbc_ram_size) {
|
||||
gb_log(gb, "Save state has non-matching MBC RAM size.\n");
|
||||
GB_log(gb, "Save state has non-matching MBC RAM size.\n");
|
||||
errno = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (gb->ram_size != save.ram_size) {
|
||||
gb_log(gb, "Save state has non-matching RAM size. Try changing emulated model.\n");
|
||||
GB_log(gb, "Save state has non-matching RAM size. Try changing emulated model.\n");
|
||||
errno = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (gb->vram_size != save.vram_size) {
|
||||
gb_log(gb, "Save state has non-matching VRAM size. Try changing emulated model.\n");
|
||||
GB_log(gb, "Save state has non-matching VRAM size. Try changing emulated model.\n");
|
||||
errno = -1;
|
||||
goto error;
|
||||
}
|
||||
@ -364,7 +364,7 @@ error:
|
||||
return errno;
|
||||
}
|
||||
|
||||
int gb_save_battery(GB_gameboy_t *gb, const char *path)
|
||||
int GB_save_battery(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
if (!gb->cartridge_type->has_battery) return 0; // Nothing to save.
|
||||
if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */
|
||||
@ -395,7 +395,7 @@ int gb_save_battery(GB_gameboy_t *gb, const char *path)
|
||||
}
|
||||
|
||||
/* Loading will silently stop if the format is incomplete */
|
||||
void gb_load_battery(GB_gameboy_t *gb, const char *path)
|
||||
void GB_load_battery(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "r");
|
||||
if (!f) {
|
||||
@ -433,39 +433,39 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void gb_run(GB_gameboy_t *gb)
|
||||
void GB_run(GB_gameboy_t *gb)
|
||||
{
|
||||
update_joyp(gb);
|
||||
debugger_run(gb);
|
||||
cpu_run(gb);
|
||||
GB_update_joyp(gb);
|
||||
GB_debugger_run(gb);
|
||||
GB_cpu_run(gb);
|
||||
}
|
||||
|
||||
void gb_set_pixels_output(GB_gameboy_t *gb, uint32_t *output)
|
||||
void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output)
|
||||
{
|
||||
gb->screen = output;
|
||||
}
|
||||
|
||||
void gb_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback)
|
||||
void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback)
|
||||
{
|
||||
gb->vblank_callback = callback;
|
||||
}
|
||||
|
||||
void gb_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback)
|
||||
void GB_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback)
|
||||
{
|
||||
gb->log_callback = callback;
|
||||
}
|
||||
|
||||
void gb_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback)
|
||||
void GB_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback)
|
||||
{
|
||||
gb->input_callback = callback;
|
||||
}
|
||||
|
||||
void gb_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback)
|
||||
void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback)
|
||||
{
|
||||
gb->rgb_encode_callback = callback;
|
||||
}
|
||||
|
||||
void gb_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate)
|
||||
void GB_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate)
|
||||
{
|
||||
if (gb->audio_buffer) {
|
||||
free(gb->audio_buffer);
|
||||
|
159
Core/gb.h
159
Core/gb.h
@ -1,5 +1,5 @@
|
||||
#ifndef gb_h
|
||||
#define gb_h
|
||||
#ifndef GB_h
|
||||
#define GB_h
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@ -8,7 +8,7 @@
|
||||
#include "save_struct.h"
|
||||
|
||||
|
||||
#define GB_STRUCT_VERSION 8
|
||||
#define GB_STRUCT_VERSION 9
|
||||
|
||||
enum {
|
||||
GB_REGISTER_AF,
|
||||
@ -146,14 +146,14 @@ typedef enum {
|
||||
GB_LOG_DASHED_UNDERLINE = 2,
|
||||
GB_LOG_UNDERLINE = 4,
|
||||
GB_LOG_UNDERLINE_MASK = GB_LOG_DASHED_UNDERLINE | GB_LOG_UNDERLINE
|
||||
} gb_log_attributes;
|
||||
} GB_log_attributes;
|
||||
|
||||
struct GB_gameboy_s;
|
||||
typedef struct GB_gameboy_s GB_gameboy_t;
|
||||
typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb);
|
||||
typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, gb_log_attributes attributes);
|
||||
typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes);
|
||||
typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb);
|
||||
typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, unsigned char r, unsigned char g, unsigned char b);
|
||||
typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
@ -172,21 +172,32 @@ typedef struct {
|
||||
|
||||
/* When state saving, each section is dumped independently of other sections.
|
||||
This allows adding data to the end of the section without worrying about future compatibility.
|
||||
Some other changes might be "safe" as well. */
|
||||
Some other changes might be "safe" as well.
|
||||
This struct is not packed, but dumped sections exclusively use types that have the same alignment in both 32 and 64
|
||||
bit platforms. */
|
||||
|
||||
/* We make sure bool is 1 for cross-platform save state compatibility. */
|
||||
/* Todo: We might want to typedef our own bool if this prevents SameBoy from working on specific platforms. */
|
||||
_Static_assert(sizeof(bool) == 1, "sizeof(bool) != 1");
|
||||
|
||||
typedef struct GB_gameboy_s {
|
||||
GB_SECTION(header,
|
||||
uintptr_t magic; // States are currently platform dependent
|
||||
int version; // and version dependent
|
||||
/* The magic makes sure a state file is:
|
||||
- Indeed a SameBoy state file.
|
||||
- Has the same endianess has the current platform. */
|
||||
uint32_t magic;
|
||||
/* The version field makes sure we don't load save state files with a completely different structure.
|
||||
This happens when struct fields are removed/resized in an backward incompatible manner. */
|
||||
uint32_t version;
|
||||
);
|
||||
|
||||
GB_SECTION(core_state,
|
||||
/* Registers */
|
||||
unsigned short pc;
|
||||
unsigned short registers[GB_REGISTERS_16_BIT];
|
||||
uint16_t pc;
|
||||
uint16_t registers[GB_REGISTERS_16_BIT];
|
||||
bool ime;
|
||||
unsigned char interrupt_enable;
|
||||
unsigned char cgb_ram_bank;
|
||||
uint8_t interrupt_enable;
|
||||
uint8_t cgb_ram_bank;
|
||||
|
||||
/* CPU and General Hardware Flags*/
|
||||
bool cgb_mode;
|
||||
@ -194,23 +205,23 @@ typedef struct GB_gameboy_s {
|
||||
bool cgb_double_speed;
|
||||
bool halted;
|
||||
bool stopped;
|
||||
bool bios_finished;
|
||||
bool boot_rom_finished;
|
||||
);
|
||||
|
||||
/* HDMA */
|
||||
GB_SECTION(hdma,
|
||||
bool hdma_on;
|
||||
bool hdma_on_hblank;
|
||||
unsigned char hdma_steps_left;
|
||||
unsigned short hdma_cycles;
|
||||
unsigned short hdma_current_src, hdma_current_dest;
|
||||
uint8_t hdma_steps_left;
|
||||
uint16_t hdma_cycles;
|
||||
uint16_t hdma_current_src, hdma_current_dest;
|
||||
);
|
||||
|
||||
/* MBC */
|
||||
GB_SECTION(mbc,
|
||||
unsigned short mbc_rom_bank;
|
||||
unsigned char mbc_ram_bank;
|
||||
size_t mbc_ram_size;
|
||||
uint16_t mbc_rom_bank;
|
||||
uint8_t mbc_ram_bank;
|
||||
uint32_t mbc_ram_size;
|
||||
bool mbc_ram_enable;
|
||||
bool mbc_ram_banking;
|
||||
);
|
||||
@ -218,18 +229,18 @@ typedef struct GB_gameboy_s {
|
||||
|
||||
/* HRAM and HW Registers */
|
||||
GB_SECTION(hram,
|
||||
unsigned char hram[0xFFFF - 0xFF80];
|
||||
unsigned char io_registers[0x80];
|
||||
uint8_t hram[0xFFFF - 0xFF80];
|
||||
uint8_t io_registers[0x80];
|
||||
);
|
||||
|
||||
/* Timing */
|
||||
GB_SECTION(timing,
|
||||
signed long last_vblank;
|
||||
unsigned long display_cycles;
|
||||
unsigned long div_cycles;
|
||||
unsigned long tima_cycles;
|
||||
unsigned long dma_cycles;
|
||||
double apu_cycles;
|
||||
int64_t last_vblank;
|
||||
uint32_t display_cycles;
|
||||
uint32_t div_cycles;
|
||||
uint32_t tima_cycles;
|
||||
uint32_t dma_cycles;
|
||||
GB_aligned_double apu_cycles;
|
||||
);
|
||||
|
||||
/* APU */
|
||||
@ -241,47 +252,45 @@ typedef struct GB_gameboy_s {
|
||||
GB_SECTION(rtc,
|
||||
union {
|
||||
struct {
|
||||
unsigned char rtc_seconds;
|
||||
unsigned char rtc_minutes;
|
||||
unsigned char rtc_hours;
|
||||
unsigned char rtc_days;
|
||||
unsigned char rtc_high;
|
||||
uint8_t rtc_seconds;
|
||||
uint8_t rtc_minutes;
|
||||
uint8_t rtc_hours;
|
||||
uint8_t rtc_days;
|
||||
uint8_t rtc_high;
|
||||
};
|
||||
unsigned char rtc_data[5];
|
||||
uint8_t rtc_data[5];
|
||||
};
|
||||
time_t last_rtc_second;
|
||||
);
|
||||
|
||||
/* Video Display */
|
||||
GB_SECTION(video,
|
||||
unsigned long vram_size; // Different between CGB and DMG
|
||||
unsigned char cgb_vram_bank;
|
||||
unsigned char oam[0xA0];
|
||||
unsigned char background_palletes_data[0x40];
|
||||
unsigned char sprite_palletes_data[0x40];
|
||||
uint32_t vram_size; // Different between CGB and DMG
|
||||
uint8_t cgb_vram_bank;
|
||||
uint8_t oam[0xA0];
|
||||
uint8_t background_palletes_data[0x40];
|
||||
uint8_t sprite_palletes_data[0x40];
|
||||
uint32_t background_palletes_rgb[0x20];
|
||||
uint32_t sprite_palletes_rgb[0x20];
|
||||
GB_PADDING(bool, ly144_bug_oam);
|
||||
GB_PADDING(bool, ly144_bug_hblank);
|
||||
signed short previous_lcdc_x;
|
||||
unsigned char padding;
|
||||
int16_t previous_lcdc_x;
|
||||
uint8_t padding;
|
||||
bool effective_window_enabled;
|
||||
unsigned char effective_window_y;
|
||||
uint8_t effective_window_y;
|
||||
bool stat_interrupt_line;
|
||||
unsigned char effective_scx;
|
||||
uint8_t effective_scx;
|
||||
);
|
||||
|
||||
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
||||
|
||||
/* ROM */
|
||||
unsigned char *rom;
|
||||
size_t rom_size;
|
||||
uint8_t *rom;
|
||||
uint32_t rom_size;
|
||||
const GB_cartridge_t *cartridge_type;
|
||||
|
||||
/* Various RAMs */
|
||||
unsigned char *ram;
|
||||
unsigned char *vram;
|
||||
unsigned char *mbc_ram;
|
||||
uint8_t *ram;
|
||||
uint8_t *vram;
|
||||
uint8_t *mbc_ram;
|
||||
|
||||
/* I/O */
|
||||
uint32_t *screen;
|
||||
@ -305,17 +314,17 @@ typedef struct GB_gameboy_s {
|
||||
/* Debugger */
|
||||
int debug_call_depth;
|
||||
bool debug_fin_command, debug_next_command;
|
||||
unsigned short n_breakpoints;
|
||||
unsigned short *breakpoints;
|
||||
uint16_t n_breakpoints;
|
||||
uint16_t *breakpoints;
|
||||
bool stack_leak_detection;
|
||||
unsigned short sp_for_call_depth[0x200]; /* Should be much more than enough */
|
||||
unsigned short addr_for_call_depth[0x200];
|
||||
uint16_t sp_for_call_depth[0x200]; /* Should be much more than enough */
|
||||
uint16_t addr_for_call_depth[0x200];
|
||||
bool debug_stopped;
|
||||
|
||||
/* Misc */
|
||||
bool turbo;
|
||||
unsigned long ram_size; // Different between CGB and DMG
|
||||
unsigned char bios[0x900];
|
||||
uint32_t ram_size; // Different between CGB and DMG
|
||||
uint8_t boot_rom[0x900];
|
||||
|
||||
} GB_gameboy_t;
|
||||
|
||||
@ -325,23 +334,23 @@ typedef struct GB_gameboy_s {
|
||||
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
||||
#endif
|
||||
|
||||
void gb_init(GB_gameboy_t *gb);
|
||||
void gb_init_cgb(GB_gameboy_t *gb);
|
||||
void gb_free(GB_gameboy_t *gb);
|
||||
int gb_load_bios(GB_gameboy_t *gb, const char *path);
|
||||
int gb_load_rom(GB_gameboy_t *gb, const char *path);
|
||||
int gb_save_battery(GB_gameboy_t *gb, const char *path);
|
||||
void gb_load_battery(GB_gameboy_t *gb, const char *path);
|
||||
int gb_save_state(GB_gameboy_t *gb, const char *path);
|
||||
int gb_load_state(GB_gameboy_t *gb, const char *path);
|
||||
void gb_run(GB_gameboy_t *gb);
|
||||
void gb_set_pixels_output(GB_gameboy_t *gb, uint32_t *output);
|
||||
void gb_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback);
|
||||
void gb_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback);
|
||||
void gb_log(GB_gameboy_t *gb, const char *fmt, ...) __printflike(2, 3);
|
||||
void gb_attributed_log(GB_gameboy_t *gb, gb_log_attributes attributes, const char *fmt, ...) __printflike(3, 4);
|
||||
void gb_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback);
|
||||
void gb_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate);
|
||||
void gb_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback);
|
||||
void GB_init(GB_gameboy_t *gb);
|
||||
void GB_init_cgb(GB_gameboy_t *gb);
|
||||
void GB_free(GB_gameboy_t *gb);
|
||||
int GB_load_boot_rom(GB_gameboy_t *gb, const char *path);
|
||||
int GB_load_rom(GB_gameboy_t *gb, const char *path);
|
||||
int GB_save_battery(GB_gameboy_t *gb, const char *path);
|
||||
void GB_load_battery(GB_gameboy_t *gb, const char *path);
|
||||
int GB_save_state(GB_gameboy_t *gb, const char *path);
|
||||
int GB_load_state(GB_gameboy_t *gb, const char *path);
|
||||
void GB_run(GB_gameboy_t *gb);
|
||||
void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output);
|
||||
void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback);
|
||||
void GB_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback);
|
||||
void GB_log(GB_gameboy_t *gb, const char *fmt, ...) __printflike(2, 3);
|
||||
void GB_attributed_log(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, ...) __printflike(3, 4);
|
||||
void GB_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback);
|
||||
void GB_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate);
|
||||
void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback);
|
||||
|
||||
#endif /* gb_h */
|
||||
#endif /* GB_h */
|
||||
|
@ -2,10 +2,10 @@
|
||||
#include "gb.h"
|
||||
#include "joypad.h"
|
||||
|
||||
void update_joyp(GB_gameboy_t *gb)
|
||||
void GB_update_joyp(GB_gameboy_t *gb)
|
||||
{
|
||||
unsigned char key_selection = 0;
|
||||
unsigned char previous_state = 0;
|
||||
uint8_t key_selection = 0;
|
||||
uint8_t previous_state = 0;
|
||||
|
||||
/* Todo: add delay to key selection */
|
||||
previous_state = gb->io_registers[GB_IO_JOYP] & 0xF;
|
||||
@ -19,21 +19,21 @@ void update_joyp(GB_gameboy_t *gb)
|
||||
|
||||
case 2:
|
||||
/* Direction keys */
|
||||
for (unsigned char i = 0; i < 4; i++) {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i]) << i;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Other keys */
|
||||
for (unsigned char i = 0; i < 4; i++) {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i + 4]) << i;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
/* Todo: verifiy this is correct */
|
||||
for (unsigned char i = 0; i < 4; i++) {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i]) << i;
|
||||
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i + 4]) << i;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define joypad_h
|
||||
#include "gb.h"
|
||||
|
||||
void update_joyp(GB_gameboy_t *gb);
|
||||
void update_keys_status(GB_gameboy_t *gb);
|
||||
void GB_update_joyp(GB_gameboy_t *gb);
|
||||
void GB_update_keys_status(GB_gameboy_t *gb);
|
||||
|
||||
#endif /* joypad_h */
|
||||
|
@ -5,17 +5,17 @@
|
||||
#include "display.h"
|
||||
#include "memory.h"
|
||||
|
||||
typedef unsigned char GB_read_function_t(GB_gameboy_t *gb, unsigned short addr);
|
||||
typedef void GB_write_function_t(GB_gameboy_t *gb, unsigned short addr, unsigned char value);
|
||||
typedef uint8_t GB_read_function_t(GB_gameboy_t *gb, uint16_t addr);
|
||||
typedef void GB_write_function_t(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
|
||||
static unsigned char read_rom(GB_gameboy_t *gb, unsigned short addr)
|
||||
static uint8_t read_rom(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (addr < 0x100 && !gb->bios_finished) {
|
||||
return gb->bios[addr];
|
||||
if (addr < 0x100 && !gb->boot_rom_finished) {
|
||||
return gb->boot_rom[addr];
|
||||
}
|
||||
|
||||
if (addr >= 0x200 && addr < 0x900 && gb->is_cgb && !gb->bios_finished) {
|
||||
return gb->bios[addr];
|
||||
if (addr >= 0x200 && addr < 0x900 && gb->is_cgb && !gb->boot_rom_finished) {
|
||||
return gb->boot_rom[addr];
|
||||
}
|
||||
|
||||
if (!gb->rom_size) {
|
||||
@ -24,7 +24,7 @@ static unsigned char read_rom(GB_gameboy_t *gb, unsigned short addr)
|
||||
return gb->rom[addr];
|
||||
}
|
||||
|
||||
static unsigned char read_mbc_rom(GB_gameboy_t *gb, unsigned short addr)
|
||||
static uint8_t read_mbc_rom(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (gb->mbc_rom_bank >= gb->rom_size / 0x4000) {
|
||||
return 0xFF;
|
||||
@ -32,15 +32,15 @@ static unsigned char read_mbc_rom(GB_gameboy_t *gb, unsigned short addr)
|
||||
return gb->rom[(addr & 0x3FFF) + gb->mbc_rom_bank * 0x4000];
|
||||
}
|
||||
|
||||
static unsigned char read_vram(GB_gameboy_t *gb, unsigned short addr)
|
||||
static uint8_t read_vram(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if ((gb->io_registers[GB_IO_STAT] & 0x3) == 3) {
|
||||
return 0xFF;
|
||||
}
|
||||
return gb->vram[(addr & 0x1FFF) + (unsigned short) gb->cgb_vram_bank * 0x2000];
|
||||
return gb->vram[(addr & 0x1FFF) + (uint16_t) gb->cgb_vram_bank * 0x2000];
|
||||
}
|
||||
|
||||
static unsigned char read_mbc_ram(GB_gameboy_t *gb, unsigned short addr)
|
||||
static uint8_t read_mbc_ram(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
||||
/* RTC read */
|
||||
@ -50,27 +50,27 @@ static unsigned char read_mbc_ram(GB_gameboy_t *gb, unsigned short addr)
|
||||
unsigned int ram_index = (addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000;
|
||||
if (!gb->mbc_ram_enable)
|
||||
{
|
||||
gb_log(gb, "Read from %02x:%04x (%06x) (Disabled MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
GB_log(gb, "Read from %02x:%04x (%06x) (Disabled MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
return 0xFF;
|
||||
}
|
||||
if (ram_index >= gb->mbc_ram_size) {
|
||||
gb_log(gb, "Read from %02x:%04x (%06x) (Unmapped MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
GB_log(gb, "Read from %02x:%04x (%06x) (Unmapped MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
return 0xFF;
|
||||
}
|
||||
return gb->mbc_ram[(addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000];
|
||||
}
|
||||
|
||||
static unsigned char read_ram(GB_gameboy_t *gb, unsigned short addr)
|
||||
static uint8_t read_ram(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
return gb->ram[addr & 0x0FFF];
|
||||
}
|
||||
|
||||
static unsigned char read_banked_ram(GB_gameboy_t *gb, unsigned short addr)
|
||||
static uint8_t read_banked_ram(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
return gb->ram[(addr & 0x0FFF) + gb->cgb_ram_bank * 0x1000];
|
||||
}
|
||||
|
||||
static unsigned char read_high_memory(GB_gameboy_t *gb, unsigned short addr)
|
||||
static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
|
||||
if (addr < 0xFE00) {
|
||||
@ -150,7 +150,7 @@ static unsigned char read_high_memory(GB_gameboy_t *gb, unsigned short addr)
|
||||
if (!gb->is_cgb) {
|
||||
return 0xFF;
|
||||
}
|
||||
unsigned char index_reg = (addr & 0xFF) - 1;
|
||||
uint8_t index_reg = (addr & 0xFF) - 1;
|
||||
return ((addr & 0xFF) == GB_IO_BGPD?
|
||||
gb->background_palletes_data :
|
||||
gb->sprite_palletes_data)[gb->io_registers[index_reg] & 0x3F];
|
||||
@ -165,7 +165,7 @@ static unsigned char read_high_memory(GB_gameboy_t *gb, unsigned short addr)
|
||||
|
||||
default:
|
||||
if ((addr & 0xFF) >= GB_IO_NR10 && (addr & 0xFF) <= GB_IO_WAV_END) {
|
||||
return apu_read(gb, addr & 0xFF);
|
||||
return GB_apu_read(gb, addr & 0xFF);
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
@ -192,7 +192,7 @@ static GB_read_function_t * const read_map[] =
|
||||
read_high_memory, read_high_memory, /* EXXX FXXX */
|
||||
};
|
||||
|
||||
unsigned char read_memory(GB_gameboy_t *gb, unsigned short addr)
|
||||
uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (addr < 0xFF00 && gb->dma_cycles) {
|
||||
/* Todo: can we access IO registers during DMA? */
|
||||
@ -201,7 +201,7 @@ unsigned char read_memory(GB_gameboy_t *gb, unsigned short addr)
|
||||
return read_map[addr >> 12](gb, addr);
|
||||
}
|
||||
|
||||
static void write_mbc(GB_gameboy_t *gb, unsigned short addr, unsigned char value)
|
||||
static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
if (gb->cartridge_type->mbc_type == NO_MBC) return;
|
||||
switch (addr >> 12) {
|
||||
@ -223,7 +223,7 @@ static void write_mbc(GB_gameboy_t *gb, unsigned short addr, unsigned char value
|
||||
case 3:
|
||||
if (gb->cartridge_type->mbc_type != MBC5) goto bank_low;
|
||||
if (value > 1) {
|
||||
gb_log(gb, "Bank overflow: [%x] <- %d\n", addr, value);
|
||||
GB_log(gb, "Bank overflow: [%x] <- %d\n", addr, value);
|
||||
}
|
||||
gb->mbc_rom_bank = (gb->mbc_rom_bank & 0xFF) | value << 8;
|
||||
break;
|
||||
@ -274,16 +274,16 @@ static void write_mbc(GB_gameboy_t *gb, unsigned short addr, unsigned char value
|
||||
}
|
||||
}
|
||||
|
||||
static void write_vram(GB_gameboy_t *gb, unsigned short addr, unsigned char value)
|
||||
static void write_vram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
if ((gb->io_registers[GB_IO_STAT] & 0x3) == 3) {
|
||||
//gb_log(gb, "Wrote %02x to %04x (VRAM) during mode 3\n", value, addr);
|
||||
//GB_log(gb, "Wrote %02x to %04x (VRAM) during mode 3\n", value, addr);
|
||||
return;
|
||||
}
|
||||
gb->vram[(addr & 0x1FFF) + (unsigned short) gb->cgb_vram_bank * 0x2000] = value;
|
||||
gb->vram[(addr & 0x1FFF) + (uint16_t) gb->cgb_vram_bank * 0x2000] = value;
|
||||
}
|
||||
|
||||
static void write_mbc_ram(GB_gameboy_t *gb, unsigned short addr, unsigned char value)
|
||||
static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
if (gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
||||
/* RTC write*/
|
||||
@ -294,30 +294,30 @@ static void write_mbc_ram(GB_gameboy_t *gb, unsigned short addr, unsigned char v
|
||||
unsigned int ram_index = (addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000;
|
||||
if (!gb->mbc_ram_enable)
|
||||
{
|
||||
gb_log(gb, "Write to %02x:%04x (%06x) (Disabled MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
GB_log(gb, "Write to %02x:%04x (%06x) (Disabled MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
return;
|
||||
}
|
||||
if (ram_index >= gb->mbc_ram_size) {
|
||||
gb_log(gb, "Write to %02x:%04x (%06x) (Unmapped MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
GB_log(gb, "Write to %02x:%04x (%06x) (Unmapped MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
return;
|
||||
}
|
||||
gb->mbc_ram[(addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000] = value;
|
||||
}
|
||||
|
||||
static void write_ram(GB_gameboy_t *gb, unsigned short addr, unsigned char value)
|
||||
static void write_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
gb->ram[addr & 0x0FFF] = value;
|
||||
}
|
||||
|
||||
static void write_banked_ram(GB_gameboy_t *gb, unsigned short addr, unsigned char value)
|
||||
static void write_banked_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
gb->ram[(addr & 0x0FFF) + gb->cgb_ram_bank * 0x1000] = value;
|
||||
}
|
||||
|
||||
static void write_high_memory(GB_gameboy_t *gb, unsigned short addr, unsigned char value)
|
||||
static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
if (addr < 0xFE00) {
|
||||
gb_log(gb, "Wrote %02x to %04x (RAM Mirror)\n", value, addr);
|
||||
GB_log(gb, "Wrote %02x to %04x (RAM Mirror)\n", value, addr);
|
||||
gb->ram[addr & 0x0FFF] = value;
|
||||
return;
|
||||
}
|
||||
@ -331,7 +331,7 @@ static void write_high_memory(GB_gameboy_t *gb, unsigned short addr, unsigned ch
|
||||
}
|
||||
|
||||
if (addr < 0xFF00) {
|
||||
gb_log(gb, "Wrote %02x to %04x (Unused)\n", value, addr);
|
||||
GB_log(gb, "Wrote %02x to %04x (Unused)\n", value, addr);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -386,19 +386,19 @@ static void write_high_memory(GB_gameboy_t *gb, unsigned short addr, unsigned ch
|
||||
return;
|
||||
|
||||
case GB_IO_BIOS:
|
||||
gb->bios_finished = true;
|
||||
gb->boot_rom_finished = true;
|
||||
return;
|
||||
|
||||
case GB_IO_DMG_EMULATION:
|
||||
if (gb->is_cgb && !gb->bios_finished) {
|
||||
if (gb->is_cgb && !gb->boot_rom_finished) {
|
||||
gb->cgb_mode = value != 4; /* The real "contents" of this register aren't quite known yet. */
|
||||
}
|
||||
return;
|
||||
|
||||
case GB_IO_DMA:
|
||||
if (value <= 0xF1) { /* According to Pan Docs */
|
||||
for (unsigned char i = 0xA0; i--;) {
|
||||
gb->oam[i] = read_memory(gb, (value << 8) + i);
|
||||
for (uint8_t i = 0xA0; i--;) {
|
||||
gb->oam[i] = GB_read_memory(gb, (value << 8) + i);
|
||||
}
|
||||
}
|
||||
/* else { what? } */
|
||||
@ -433,11 +433,11 @@ static void write_high_memory(GB_gameboy_t *gb, unsigned short addr, unsigned ch
|
||||
if (!gb->is_cgb) {
|
||||
return;
|
||||
}
|
||||
unsigned char index_reg = (addr & 0xFF) - 1;
|
||||
uint8_t index_reg = (addr & 0xFF) - 1;
|
||||
((addr & 0xFF) == GB_IO_BGPD?
|
||||
gb->background_palletes_data :
|
||||
gb->sprite_palletes_data)[gb->io_registers[index_reg] & 0x3F] = value;
|
||||
palette_changed(gb, (addr & 0xFF) == GB_IO_BGPD, gb->io_registers[index_reg] & 0x3F);
|
||||
GB_palette_changed(gb, (addr & 0xFF) == GB_IO_BGPD, gb->io_registers[index_reg] & 0x3F);
|
||||
if (gb->io_registers[index_reg] & 0x80) {
|
||||
gb->io_registers[index_reg]++;
|
||||
gb->io_registers[index_reg] |= 0x80;
|
||||
@ -477,11 +477,11 @@ static void write_high_memory(GB_gameboy_t *gb, unsigned short addr, unsigned ch
|
||||
|
||||
default:
|
||||
if ((addr & 0xFF) >= GB_IO_NR10 && (addr & 0xFF) <= GB_IO_WAV_END) {
|
||||
apu_write(gb, addr & 0xFF, value);
|
||||
GB_apu_write(gb, addr & 0xFF, value);
|
||||
return;
|
||||
}
|
||||
if (gb->io_registers[addr & 0xFF] != 0x37) {
|
||||
gb_log(gb, "Wrote %02x to %04x (HW Register)\n", value, addr);
|
||||
GB_log(gb, "Wrote %02x to %04x (HW Register)\n", value, addr);
|
||||
}
|
||||
gb->io_registers[addr & 0xFF] = 0x37;
|
||||
return;
|
||||
@ -510,7 +510,7 @@ static GB_write_function_t * const write_map[] =
|
||||
write_high_memory, write_high_memory, /* EXXX FXXX */
|
||||
};
|
||||
|
||||
void write_memory(GB_gameboy_t *gb, unsigned short addr, unsigned char value)
|
||||
void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
if (addr < 0xFF00 && gb->dma_cycles) {
|
||||
/* Todo: can we access IO registers during DMA? */
|
||||
@ -519,18 +519,18 @@ void write_memory(GB_gameboy_t *gb, unsigned short addr, unsigned char value)
|
||||
write_map[addr >> 12](gb, addr, value);
|
||||
}
|
||||
|
||||
void hdma_run(GB_gameboy_t *gb)
|
||||
void GB_hdma_run(GB_gameboy_t *gb)
|
||||
{
|
||||
if (!gb->hdma_on) return;
|
||||
while (gb->hdma_cycles >= 8) {
|
||||
gb->hdma_cycles -= 8;
|
||||
// The CGB bios uses the dest in "absolute" space, while some games use it relative to VRAM.
|
||||
// The CGB boot rom uses the dest in "absolute" space, while some games use it relative to VRAM.
|
||||
// This "normalizes" the dest to the CGB address space.
|
||||
gb->hdma_current_dest &= 0x1fff;
|
||||
gb->hdma_current_dest |= 0x8000;
|
||||
if ((gb->hdma_current_src < 0x8000 || (gb->hdma_current_src >= 0xa000 && gb->hdma_current_src < 0xe000))) {
|
||||
for (unsigned char i = 0; i < 0x10; i++) {
|
||||
write_memory(gb, gb->hdma_current_dest + i, read_memory(gb, gb->hdma_current_src + i));
|
||||
for (uint8_t i = 0; i < 0x10; i++) {
|
||||
GB_write_memory(gb, gb->hdma_current_dest + i, GB_read_memory(gb, gb->hdma_current_src + i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2,8 +2,8 @@
|
||||
#define memory_h
|
||||
#include "gb.h"
|
||||
|
||||
unsigned char read_memory(GB_gameboy_t *gb, unsigned short addr);
|
||||
void write_memory(GB_gameboy_t *gb, unsigned short addr, unsigned char value);
|
||||
void hdma_run(GB_gameboy_t *gb);
|
||||
uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr);
|
||||
void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
void GB_hdma_run(GB_gameboy_t *gb);
|
||||
|
||||
#endif /* memory_h */
|
||||
|
@ -4,9 +4,11 @@
|
||||
|
||||
#define GB_PADDING(type, old_usage) type old_usage##__do_not_use
|
||||
|
||||
#define GB_SECTION(name, ...) __attribute__ ((aligned (sizeof(void*)))) struct {} name##_section_start; __VA_ARGS__; struct {} name##_section_end
|
||||
#define GB_SECTION(name, ...) __attribute__ ((aligned (8))) struct {} name##_section_start; __VA_ARGS__; struct {} name##_section_end
|
||||
#define GB_SECTION_OFFSET(name) (offsetof(GB_gameboy_t, name##_section_start))
|
||||
#define GB_SECTION_SIZE(name) (offsetof(GB_gameboy_t, name##_section_end) - offsetof(GB_gameboy_t, name##_section_start))
|
||||
#define GB_GET_SECTION(gb, name) ((void*)&((gb)->name##_section_start))
|
||||
|
||||
#define GB_aligned_double __attribute__ ((aligned (8))) double
|
||||
|
||||
#endif /* save_struct_h */
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "memory.h"
|
||||
#include "display.h"
|
||||
|
||||
void advance_cycles(GB_gameboy_t *gb, unsigned char cycles)
|
||||
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
|
||||
{
|
||||
// Affected by speed boost
|
||||
if (gb->dma_cycles > cycles){
|
||||
@ -24,16 +24,16 @@ void advance_cycles(GB_gameboy_t *gb, unsigned char cycles)
|
||||
gb->hdma_cycles += cycles;
|
||||
gb->display_cycles += cycles;
|
||||
gb->apu_cycles += cycles;
|
||||
hdma_run(gb);
|
||||
timers_run(gb);
|
||||
apu_run(gb);
|
||||
display_run(gb);
|
||||
GB_hdma_run(gb);
|
||||
GB_timers_run(gb);
|
||||
GB_apu_run(gb);
|
||||
GB_display_run(gb);
|
||||
}
|
||||
|
||||
void timers_run(GB_gameboy_t *gb)
|
||||
void GB_timers_run(GB_gameboy_t *gb)
|
||||
{
|
||||
/* Standard Timers */
|
||||
static const unsigned long GB_TAC_RATIOS[] = {1024, 16, 64, 256};
|
||||
static const unsigned int GB_TAC_RATIOS[] = {1024, 16, 64, 256};
|
||||
|
||||
if (gb->div_cycles >= DIV_CYCLES) {
|
||||
gb->div_cycles -= DIV_CYCLES;
|
||||
|
@ -2,6 +2,6 @@
|
||||
#define timing_h
|
||||
#include "gb.h"
|
||||
|
||||
void advance_cycles(GB_gameboy_t *gb, unsigned char cycles);
|
||||
void timers_run(GB_gameboy_t *gb);
|
||||
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles);
|
||||
void GB_timers_run(GB_gameboy_t *gb);
|
||||
#endif /* timing_h */
|
||||
|
668
Core/z80_cpu.c
668
Core/z80_cpu.c
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
#ifndef z80_cpu_h
|
||||
#define z80_cpu_h
|
||||
#include "gb.h"
|
||||
void cpu_disassemble(GB_gameboy_t *gb, unsigned short pc, unsigned short count);
|
||||
void cpu_run(GB_gameboy_t *gb);
|
||||
void GB_cpu_disassemble(GB_gameboy_t *gb, uint16_t pc, uint16_t count);
|
||||
void GB_cpu_run(GB_gameboy_t *gb);
|
||||
|
||||
#endif /* z80_cpu_h */
|
||||
|
@ -5,161 +5,161 @@
|
||||
#include "gb.h"
|
||||
|
||||
|
||||
typedef void GB_opcode_t(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc);
|
||||
typedef void GB_opcode_t(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc);
|
||||
|
||||
static void ill(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ill(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, ".BYTE %02x\n", opcode);
|
||||
GB_log(gb, ".BYTE %02x\n", opcode);
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void nop(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void nop(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "NOP\n");
|
||||
GB_log(gb, "NOP\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void stop(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void stop(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "STOP\n");
|
||||
GB_log(gb, "STOP\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static char *register_names[] = {"af", "bc", "de", "hl", "sp"};
|
||||
|
||||
static void ld_rr_d16(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_rr_d16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
unsigned short value;
|
||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
value = read_memory(gb, (*pc)++);
|
||||
value |= read_memory(gb, (*pc)++) << 8;
|
||||
gb_log(gb, "LD %s, %04x\n", register_names[register_id], value);
|
||||
uint8_t register_id;
|
||||
uint16_t value;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
value = GB_read_memory(gb, (*pc)++);
|
||||
value |= GB_read_memory(gb, (*pc)++) << 8;
|
||||
GB_log(gb, "LD %s, %04x\n", register_names[register_id], value);
|
||||
}
|
||||
|
||||
static void ld_drr_a(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_drr_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
gb_log(gb, "LD [%s], a\n", register_names[register_id]);
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "LD [%s], a\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void inc_rr(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void inc_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
gb_log(gb, "INC %s\n", register_names[register_id]);
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "INC %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void inc_hr(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void inc_hr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
||||
gb_log(gb, "INC %c\n", register_names[register_id][0]);
|
||||
GB_log(gb, "INC %c\n", register_names[register_id][0]);
|
||||
|
||||
}
|
||||
static void dec_hr(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void dec_hr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
||||
gb_log(gb, "DEC %c\n", register_names[register_id][0]);
|
||||
GB_log(gb, "DEC %c\n", register_names[register_id][0]);
|
||||
}
|
||||
|
||||
static void ld_hr_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_hr_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
||||
gb_log(gb, "LD %c, %02x\n", register_names[register_id][0], read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "LD %c, %02x\n", register_names[register_id][0], GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void rlca(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void rlca(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "RLCA\n");
|
||||
GB_log(gb, "RLCA\n");
|
||||
}
|
||||
|
||||
static void rla(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void rla(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "RLA\n");
|
||||
GB_log(gb, "RLA\n");
|
||||
}
|
||||
|
||||
static void ld_da16_sp(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc){
|
||||
unsigned short addr;
|
||||
static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc){
|
||||
uint16_t addr;
|
||||
(*pc)++;
|
||||
addr = read_memory(gb, (*pc)++);
|
||||
addr |= read_memory(gb, (*pc)++) << 8;
|
||||
gb_log(gb, "LD [%04x], sp\n", addr);
|
||||
addr = GB_read_memory(gb, (*pc)++);
|
||||
addr |= GB_read_memory(gb, (*pc)++) << 8;
|
||||
GB_log(gb, "LD [%04x], sp\n", addr);
|
||||
}
|
||||
|
||||
static void add_hl_rr(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void add_hl_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
uint8_t register_id;
|
||||
(*pc)++;
|
||||
register_id = (opcode >> 4) + 1;
|
||||
gb_log(gb, "ADD hl, %s\n", register_names[register_id]);
|
||||
GB_log(gb, "ADD hl, %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void ld_a_drr(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_a_drr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
gb_log(gb, "LD a, [%s]\n", register_names[register_id]);
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "LD a, [%s]\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void dec_rr(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void dec_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
gb_log(gb, "DEC %s\n", register_names[register_id]);
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
GB_log(gb, "DEC %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void inc_lr(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void inc_lr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
|
||||
gb_log(gb, "INC %c\n", register_names[register_id][1]);
|
||||
GB_log(gb, "INC %c\n", register_names[register_id][1]);
|
||||
}
|
||||
static void dec_lr(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void dec_lr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
|
||||
gb_log(gb, "DEC %c\n", register_names[register_id][1]);
|
||||
GB_log(gb, "DEC %c\n", register_names[register_id][1]);
|
||||
}
|
||||
|
||||
static void ld_lr_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_lr_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
uint8_t register_id;
|
||||
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||
|
||||
gb_log(gb, "LD %c, %02x\n", register_names[register_id][1], read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "LD %c, %02x\n", register_names[register_id][1], GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void rrca(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void rrca(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "RRCA\n");
|
||||
GB_log(gb, "RRCA\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void rra(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void rra(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "RRA\n");
|
||||
GB_log(gb, "RRA\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void jr_r8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void jr_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_attributed_log(gb, GB_LOG_UNDERLINE, "JR %04x\n", *pc + (signed char) read_memory(gb, (*pc)) + 1);
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "JR %04x\n", *pc + (int8_t) GB_read_memory(gb, (*pc)) + 1);
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static const char *condition_code(unsigned char opcode)
|
||||
static const char *condition_code(uint8_t opcode)
|
||||
{
|
||||
switch ((opcode >> 3) & 0x3) {
|
||||
case 0:
|
||||
@ -175,83 +175,83 @@ static const char *condition_code(unsigned char opcode)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void jr_cc_r8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, %04x\n", condition_code(opcode), *pc + (signed char)read_memory(gb, (*pc)) + 1);
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, %04x\n", condition_code(opcode), *pc + (int8_t)GB_read_memory(gb, (*pc)) + 1);
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void daa(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void daa(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "DAA\n");
|
||||
GB_log(gb, "DAA\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void cpl(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void cpl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "CPL\n");
|
||||
GB_log(gb, "CPL\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void scf(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void scf(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "SCF\n");
|
||||
GB_log(gb, "SCF\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ccf(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ccf(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "CCF\n");
|
||||
GB_log(gb, "CCF\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_dhli_a(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_dhli_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "LD [hli], a\n");
|
||||
GB_log(gb, "LD [hli], a\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_dhld_a(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_dhld_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "LD [hld], a\n");
|
||||
GB_log(gb, "LD [hld], a\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_a_dhli(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_a_dhli(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "LD a, [hli]\n");
|
||||
GB_log(gb, "LD a, [hli]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_a_dhld(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_a_dhld(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "LD a, [hld]\n");
|
||||
GB_log(gb, "LD a, [hld]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void inc_dhl(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void inc_dhl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "INC [hl]\n");
|
||||
GB_log(gb, "INC [hl]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void dec_dhl(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void dec_dhl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
gb_log(gb, "DEC [hl]\n");
|
||||
GB_log(gb, "DEC [hl]\n");
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void ld_dhl_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "LD [hl], %02x\n", read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "LD [hl], %02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static const char *get_src_name(unsigned char opcode)
|
||||
static const char *get_src_name(uint8_t opcode)
|
||||
{
|
||||
unsigned char src_register_id;
|
||||
unsigned char src_low;
|
||||
uint8_t src_register_id;
|
||||
uint8_t src_low;
|
||||
src_register_id = ((opcode >> 1) + 1) & 3;
|
||||
src_low = !(opcode & 1);
|
||||
if (src_register_id == GB_REGISTER_AF && src_low) {
|
||||
@ -265,10 +265,10 @@ static const char *get_src_name(unsigned char opcode)
|
||||
return high_register_names[src_register_id];
|
||||
}
|
||||
|
||||
static const char *get_dst_name(unsigned char opcode)
|
||||
static const char *get_dst_name(uint8_t opcode)
|
||||
{
|
||||
unsigned char dst_register_id;
|
||||
unsigned char dst_low;
|
||||
uint8_t dst_register_id;
|
||||
uint8_t dst_low;
|
||||
dst_register_id = ((opcode >> 4) + 1) & 3;
|
||||
dst_low = opcode & 8;
|
||||
if (dst_register_id == GB_REGISTER_AF && dst_low) {
|
||||
@ -282,326 +282,326 @@ static const char *get_dst_name(unsigned char opcode)
|
||||
return high_register_names[dst_register_id];
|
||||
}
|
||||
|
||||
static void ld_r_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_r_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "LD %s, %s\n", get_dst_name(opcode), get_src_name(opcode));
|
||||
GB_log(gb, "LD %s, %s\n", get_dst_name(opcode), get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void add_a_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void add_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "ADD %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "ADD %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void adc_a_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void adc_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "ADC %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "ADC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sub_a_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void sub_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "SUB %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "SUB %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sbc_a_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void sbc_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "SBC %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "SBC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void and_a_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void and_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "AND %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "AND %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void xor_a_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void xor_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "XOR %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "XOR %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void or_a_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void or_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "OR %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "OR %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void cp_a_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void cp_a_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "CP %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "CP %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void halt(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void halt(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "HALT\n");
|
||||
GB_log(gb, "HALT\n");
|
||||
}
|
||||
|
||||
static void ret_cc(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ret_cc(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "RET %s\n", condition_code(opcode));
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "RET %s\n", condition_code(opcode));
|
||||
}
|
||||
|
||||
static void pop_rr(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void pop_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
register_id = ((read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
||||
gb_log(gb, "POP %s\n", register_names[register_id]);
|
||||
uint8_t register_id;
|
||||
register_id = ((GB_read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
||||
GB_log(gb, "POP %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void jp_cc_a16(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, %04x\n", condition_code(opcode), read_memory(gb, *pc) | (read_memory(gb, *pc + 1) << 8));
|
||||
GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, %04x\n", condition_code(opcode), GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8));
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void jp_a16(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void jp_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "JP %04x\n", read_memory(gb, *pc) | (read_memory(gb, *pc + 1) << 8));
|
||||
GB_log(gb, "JP %04x\n", GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8));
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void call_cc_a16(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "CALL %s, %04x\n", condition_code(opcode), read_memory(gb, *pc) | (read_memory(gb, *pc + 1) << 8));
|
||||
GB_log(gb, "CALL %s, %04x\n", condition_code(opcode), GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8));
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void push_rr(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void push_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char register_id;
|
||||
register_id = ((read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
||||
gb_log(gb, "PUSH %s\n", register_names[register_id]);
|
||||
uint8_t register_id;
|
||||
register_id = ((GB_read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
||||
GB_log(gb, "PUSH %s\n", register_names[register_id]);
|
||||
}
|
||||
|
||||
static void add_a_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void add_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "ADD %02x\n", read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "ADD %02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void adc_a_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void adc_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "ADC %02x\n", read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "ADC %02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void sub_a_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void sub_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "SUB %02x\n", read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "SUB %02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void sbc_a_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void sbc_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "LBC %02x\n", read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "LBC %02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void and_a_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void and_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "AND %02x\n", read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "AND %02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void xor_a_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void xor_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "XOR %02x\n", read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "XOR %02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void or_a_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void or_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "OR %02x\n", read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "OR %02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void cp_a_d8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "CP %02x\n", read_memory(gb, (*pc)++));
|
||||
GB_log(gb, "CP %02x\n", GB_read_memory(gb, (*pc)++));
|
||||
}
|
||||
|
||||
static void rst(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void rst(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "RST %02x\n", opcode ^ 0xC7);
|
||||
GB_log(gb, "RST %02x\n", opcode ^ 0xC7);
|
||||
|
||||
}
|
||||
|
||||
static void ret(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ret(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_attributed_log(gb, GB_LOG_UNDERLINE, "RET\n");
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "RET\n");
|
||||
}
|
||||
|
||||
static void reti(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void reti(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_attributed_log(gb, GB_LOG_UNDERLINE, "RETI\n");
|
||||
GB_attributed_log(gb, GB_LOG_UNDERLINE, "RETI\n");
|
||||
}
|
||||
|
||||
static void call_a16(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void call_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "CALL %04x\n", read_memory(gb, *pc) | (read_memory(gb, *pc + 1) << 8));
|
||||
GB_log(gb, "CALL %04x\n", GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8));
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void ld_da8_a(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
unsigned char temp = read_memory(gb, (*pc)++);
|
||||
gb_log(gb, "LDH [%02x], a\n", temp);
|
||||
uint8_t temp = GB_read_memory(gb, (*pc)++);
|
||||
GB_log(gb, "LDH [%02x], a\n", temp);
|
||||
}
|
||||
|
||||
static void ld_a_da8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_a_da8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
unsigned char temp = read_memory(gb, (*pc)++);
|
||||
gb_log(gb, "LDH a, [%02x]\n", temp);
|
||||
uint8_t temp = GB_read_memory(gb, (*pc)++);
|
||||
GB_log(gb, "LDH a, [%02x]\n", temp);
|
||||
}
|
||||
|
||||
static void ld_dc_a(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_dc_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "LDH [c], a\n");
|
||||
GB_log(gb, "LDH [c], a\n");
|
||||
}
|
||||
|
||||
static void ld_a_dc(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_a_dc(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "LDH a, [c]\n");
|
||||
GB_log(gb, "LDH a, [c]\n");
|
||||
}
|
||||
|
||||
static void add_sp_r8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void add_sp_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
signed char temp = read_memory(gb, (*pc)++);
|
||||
gb_log(gb, "ADD SP, %s%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp);
|
||||
int8_t temp = GB_read_memory(gb, (*pc)++);
|
||||
GB_log(gb, "ADD SP, %s%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp);
|
||||
}
|
||||
|
||||
static void jp_hl(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void jp_hl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "JP hl\n");
|
||||
GB_log(gb, "JP hl\n");
|
||||
}
|
||||
|
||||
static void ld_da16_a(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "LD [%04x], a\n", read_memory(gb, *pc) | (read_memory(gb, *pc + 1) << 8));
|
||||
GB_log(gb, "LD [%04x], a\n", GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8));
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void ld_a_da16(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "LD a, [%04x]\n", read_memory(gb, *pc) | (read_memory(gb, *pc + 1) << 8));
|
||||
GB_log(gb, "LD a, [%04x]\n", GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8));
|
||||
(*pc) += 2;
|
||||
}
|
||||
|
||||
static void di(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void di(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "DI\n");
|
||||
GB_log(gb, "DI\n");
|
||||
}
|
||||
|
||||
static void ei(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ei(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "EI\n");
|
||||
GB_log(gb, "EI\n");
|
||||
}
|
||||
|
||||
static void ld_hl_sp_r8(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_hl_sp_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
signed char temp = read_memory(gb, (*pc)++);
|
||||
gb_log(gb, "LD hl, sp, %s%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp);
|
||||
int8_t temp = GB_read_memory(gb, (*pc)++);
|
||||
GB_log(gb, "LD hl, sp, %s%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp);
|
||||
}
|
||||
|
||||
static void ld_sp_hl(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void ld_sp_hl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "LD sp, hl\n");
|
||||
GB_log(gb, "LD sp, hl\n");
|
||||
}
|
||||
|
||||
static void rlc_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void rlc_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "RLC %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "RLC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void rrc_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void rrc_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "RRC %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "RRC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void rl_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void rl_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "RL %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "RL %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void rr_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void rr_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "RR %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "RR %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sla_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void sla_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "SLA %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "SLA %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void sra_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void sra_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "SRA %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "SRA %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void srl_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void srl_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "SRL %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "SRL %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void swap_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void swap_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
(*pc)++;
|
||||
gb_log(gb, "RLC %s\n", get_src_name(opcode));
|
||||
GB_log(gb, "RLC %s\n", get_src_name(opcode));
|
||||
}
|
||||
|
||||
static void bit_r(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void bit_r(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
unsigned char bit;
|
||||
uint8_t bit;
|
||||
(*pc)++;
|
||||
bit = ((opcode >> 3) & 7);
|
||||
if ((opcode & 0xC0) == 0x40) { /* Bit */
|
||||
gb_log(gb, "BIT %s, %d\n", get_src_name(opcode), bit);
|
||||
GB_log(gb, "BIT %s, %d\n", get_src_name(opcode), bit);
|
||||
}
|
||||
else if ((opcode & 0xC0) == 0x80) { /* res */
|
||||
gb_log(gb, "RES %s, %d\n", get_src_name(opcode), bit);
|
||||
GB_log(gb, "RES %s, %d\n", get_src_name(opcode), bit);
|
||||
}
|
||||
else if ((opcode & 0xC0) == 0xC0) { /* set */
|
||||
gb_log(gb, "SET %s, %d\n", get_src_name(opcode), bit);
|
||||
GB_log(gb, "SET %s, %d\n", get_src_name(opcode), bit);
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_prefix(GB_gameboy_t *gb, unsigned char opcode, unsigned short *pc)
|
||||
static void cb_prefix(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc)
|
||||
{
|
||||
opcode = read_memory(gb, ++*pc);
|
||||
opcode = GB_read_memory(gb, ++*pc);
|
||||
switch (opcode >> 3) {
|
||||
case 0:
|
||||
rlc_r(gb, opcode, pc);
|
||||
@ -670,11 +670,11 @@ static GB_opcode_t *opcodes[256] = {
|
||||
ld_hl_sp_r8,ld_sp_hl, ld_a_da16, ei, ill, ill, cp_a_d8, rst,
|
||||
};
|
||||
|
||||
void cpu_disassemble(GB_gameboy_t *gb, unsigned short pc, unsigned short count)
|
||||
void GB_cpu_disassemble(GB_gameboy_t *gb, uint16_t pc, uint16_t count)
|
||||
{
|
||||
while (count--) {
|
||||
gb_log(gb, "%s%04x: ", pc == gb->pc? "-> ": " ", pc);
|
||||
unsigned char opcode = read_memory(gb, pc);
|
||||
GB_log(gb, "%s%04x: ", pc == gb->pc? "-> ": " ", pc);
|
||||
uint8_t opcode = GB_read_memory(gb, pc);
|
||||
opcodes[opcode](gb, opcode, &pc);
|
||||
}
|
||||
}
|
||||
|
34
SDL/main.c
34
SDL/main.c
@ -9,7 +9,7 @@
|
||||
|
||||
static bool running = false;
|
||||
|
||||
void update_keys_status(GB_gameboy_t *gb)
|
||||
void GB_update_keys_status(GB_gameboy_t *gb)
|
||||
{
|
||||
static bool ctrl = false;
|
||||
SDL_Event event;
|
||||
@ -74,9 +74,9 @@ void vblank(GB_gameboy_t *gb)
|
||||
{
|
||||
SDL_Surface *screen = gb->user_data;
|
||||
SDL_Flip(screen);
|
||||
update_keys_status(gb);
|
||||
GB_update_keys_status(gb);
|
||||
|
||||
gb_set_pixels_output(gb, screen->pixels);
|
||||
GB_set_pixels_output(gb, screen->pixels);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
@ -123,7 +123,7 @@ static char *executable_relative_path(const char *filename)
|
||||
}
|
||||
|
||||
static SDL_Surface *screen = NULL;
|
||||
static uint32_t rgb_encode(GB_gameboy_t *gb, unsigned char r, unsigned char g, unsigned char b)
|
||||
static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return SDL_MapRGB(screen->format, r, g, b);
|
||||
}
|
||||
@ -138,7 +138,7 @@ static void debugger_interrupt(int ignore)
|
||||
|
||||
static void audio_callback(void *gb, Uint8 *stream, int len)
|
||||
{
|
||||
apu_copy_buffer(gb, (GB_sample_t *) stream, len / sizeof(GB_sample_t));
|
||||
GB_apu_copy_buffer(gb, (GB_sample_t *) stream, len / sizeof(GB_sample_t));
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
@ -169,21 +169,21 @@ usage:
|
||||
|
||||
|
||||
if (dmg) {
|
||||
gb_init(&gb);
|
||||
if (gb_load_bios(&gb, executable_relative_path("dmg_boot.bin"))) {
|
||||
GB_init(&gb);
|
||||
if (GB_load_boot_rom(&gb, executable_relative_path("dmg_boot.bin"))) {
|
||||
perror("Failed to load boot ROM");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gb_init_cgb(&gb);
|
||||
if (gb_load_bios(&gb, executable_relative_path("cgb_boot.bin"))) {
|
||||
GB_init_cgb(&gb);
|
||||
if (GB_load_boot_rom(&gb, executable_relative_path("cgb_boot.bin"))) {
|
||||
perror("Failed to load boot ROM");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (gb_load_rom(&gb, argv[argc - 1])) {
|
||||
if (GB_load_rom(&gb, argv[argc - 1])) {
|
||||
perror("Failed to load ROM");
|
||||
exit(1);
|
||||
}
|
||||
@ -198,10 +198,10 @@ usage:
|
||||
#endif
|
||||
/* Configure Screen */
|
||||
SDL_LockSurface(screen);
|
||||
gb_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
gb.user_data = screen;
|
||||
gb_set_pixels_output(&gb, screen->pixels);
|
||||
gb_set_rgb_encode_callback(&gb, rgb_encode);
|
||||
GB_set_pixels_output(&gb, screen->pixels);
|
||||
GB_set_rgb_encode_callback(&gb, rgb_encode);
|
||||
|
||||
/* Configure battery */
|
||||
size_t path_length = strlen(argv[argc - 1]);
|
||||
@ -220,7 +220,7 @@ usage:
|
||||
/* Add .sav */
|
||||
strcat(battery_save_path, ".sav");
|
||||
|
||||
gb_load_battery(&gb, battery_save_path);
|
||||
GB_load_battery(&gb, battery_save_path);
|
||||
|
||||
/* Configure Audio */
|
||||
SDL_AudioSpec want, have;
|
||||
@ -232,7 +232,7 @@ usage:
|
||||
want.callback = audio_callback;
|
||||
want.userdata = &gb;
|
||||
SDL_OpenAudio(&want, &have);
|
||||
gb_set_sample_rate(&gb, 96000);
|
||||
GB_set_sample_rate(&gb, 96000);
|
||||
|
||||
/* Start Audio */
|
||||
SDL_PauseAudio(0);
|
||||
@ -240,11 +240,11 @@ usage:
|
||||
/* Run emulation */
|
||||
running = true;
|
||||
while (running) {
|
||||
gb_run(&gb);
|
||||
GB_run(&gb);
|
||||
}
|
||||
SDL_CloseAudio();
|
||||
|
||||
gb_save_battery(&gb, battery_save_path);
|
||||
GB_save_battery(&gb, battery_save_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user