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;
|
@property GBAudioClient *audioClient;
|
||||||
- (void) vblank;
|
- (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;
|
- (const char *) getDebuggerInput;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ static void vblank(GB_gameboy_t *gb)
|
|||||||
[self vblank];
|
[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);
|
Document *self = (__bridge Document *)(gb->user_data);
|
||||||
[self log:string withAttributes: attributes];
|
[self log:string withAttributes: attributes];
|
||||||
@ -39,7 +39,7 @@ static char *consoleInput(GB_gameboy_t *gb)
|
|||||||
return strdup([self getDebuggerInput]);
|
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);
|
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
|
- (void) initDMG
|
||||||
{
|
{
|
||||||
gb_init(&gb);
|
GB_init(&gb);
|
||||||
gb_load_bios(&gb, [[[NSBundle mainBundle] pathForResource:@"dmg_boot" ofType:@"bin"] UTF8String]);
|
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_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||||
gb_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
GB_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
||||||
gb_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
|
GB_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
|
||||||
gb_set_rgb_encode_callback(&gb, rgbEncode);
|
GB_set_rgb_encode_callback(&gb, rgbEncode);
|
||||||
gb.user_data = (__bridge void *)(self);
|
gb.user_data = (__bridge void *)(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) initCGB
|
- (void) initCGB
|
||||||
{
|
{
|
||||||
gb_init_cgb(&gb);
|
GB_init_cgb(&gb);
|
||||||
gb_load_bios(&gb, [[[NSBundle mainBundle] pathForResource:@"cgb_boot" ofType:@"bin"] UTF8String]);
|
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_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||||
gb_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
GB_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
||||||
gb_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
|
GB_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
|
||||||
gb_set_rgb_encode_callback(&gb, rgbEncode);
|
GB_set_rgb_encode_callback(&gb, rgbEncode);
|
||||||
gb.user_data = (__bridge void *)(self);
|
gb.user_data = (__bridge void *)(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) vblank
|
- (void) vblank
|
||||||
{
|
{
|
||||||
[self.view flip];
|
[self.view flip];
|
||||||
gb_set_pixels_output(&gb, self.view.pixels);
|
GB_set_pixels_output(&gb, self.view.pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) run
|
- (void) run
|
||||||
{
|
{
|
||||||
running = true;
|
running = true;
|
||||||
gb_set_pixels_output(&gb, self.view.pixels);
|
GB_set_pixels_output(&gb, self.view.pixels);
|
||||||
self.view.gb = &gb;
|
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) {
|
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];
|
} andSampleRate:96000];
|
||||||
[self.audioClient start];
|
[self.audioClient start];
|
||||||
while (running) {
|
while (running) {
|
||||||
gb_run(&gb);
|
GB_run(&gb);
|
||||||
}
|
}
|
||||||
[self.audioClient stop];
|
[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;
|
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;
|
bool was_cgb = gb.is_cgb;
|
||||||
[self stop];
|
[self stop];
|
||||||
gb_free(&gb);
|
GB_free(&gb);
|
||||||
is_inited = false;
|
is_inited = false;
|
||||||
if (([sender tag] == 0 && was_cgb) || [sender tag] == 2) {
|
if (([sender tag] == 0 && was_cgb) || [sender tag] == 2) {
|
||||||
[self initCGB];
|
[self initCGB];
|
||||||
@ -165,7 +165,7 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, unsigned char r, unsigned char g, un
|
|||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
gb_free(&gb);
|
GB_free(&gb);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)windowControllerDidLoadNib:(NSWindowController *)aController {
|
- (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++) {
|
if (is_inited++) {
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
gb_load_rom(&gb, [fileName UTF8String]);
|
GB_load_rom(&gb, [fileName UTF8String]);
|
||||||
gb_load_battery(&gb, [[[fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
|
GB_load_battery(&gb, [[[fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +283,7 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, unsigned char r, unsigned char g, un
|
|||||||
return rect;
|
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) {
|
if (pendingLogLines > 128) {
|
||||||
/* The ROM causes so many errors in such a short time, and we can't handle it. */
|
/* 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) {
|
if (!gb.debug_stopped) {
|
||||||
[self stop];
|
[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) {
|
if (was_running) {
|
||||||
[self start];
|
[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) {
|
if (!gb.debug_stopped) {
|
||||||
[self stop];
|
[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) {
|
if (was_running) {
|
||||||
[self start];
|
[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;
|
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);
|
phase = fmod(phase, 2 * M_PI);
|
||||||
return ((wave[(int)(phase / (2 * M_PI) * 32)]) >> shift) * (int)amplitude / 0xF;
|
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
|
/* General Todo: The APU emulation seems to fail many accuracy tests. It might require a rewrite with
|
||||||
these tests in mind. */
|
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++) {
|
for (; n_samples--; samples++) {
|
||||||
samples->left = samples->right = 0;
|
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->left *= gb->apu.left_volume;
|
||||||
samples->right *= gb->apu.right_volume;
|
samples->right *= gb->apu.right_volume;
|
||||||
|
|
||||||
for (unsigned char i = 0; i < 4; i++) {
|
for (uint8_t i = 0; i < 4; i++) {
|
||||||
/* Phase */
|
/* Phase */
|
||||||
gb->apu.wave_channels[i].phase += 2 * M_PI * gb->apu.wave_channels[i].frequency / sample_rate;
|
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) {
|
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;
|
gb->apu.envelope_step_timer += 1.0 / sample_rate;
|
||||||
if (gb->apu.envelope_step_timer >= 1.0 / 64) {
|
if (gb->apu.envelope_step_timer >= 1.0 / 64) {
|
||||||
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) {
|
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].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;
|
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) {
|
if (gb->apu.wave_channels[0].sweep_steps && !--gb->apu.wave_channels[0].cur_sweep_steps) {
|
||||||
|
|
||||||
// Convert back to GB format
|
// 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
|
// Apply sweep
|
||||||
temp = temp + gb->apu.wave_channels[0].sweep_direction *
|
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;
|
static bool should_log_overflow = true;
|
||||||
while (gb->audio_copy_in_progress);
|
while (gb->audio_copy_in_progress);
|
||||||
double ticks_per_sample = (double) CPU_FREQUENCY / gb->sample_rate;
|
double ticks_per_sample = (double) CPU_FREQUENCY / gb->sample_rate;
|
||||||
while (gb->apu_cycles > ticks_per_sample) {
|
while (gb->apu_cycles > ticks_per_sample) {
|
||||||
GB_sample_t sample = {0, };
|
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;
|
gb->apu_cycles -= ticks_per_sample;
|
||||||
if (gb->audio_position == gb->buffer_size) {
|
if (gb->audio_position == gb->buffer_size) {
|
||||||
/*
|
/*
|
||||||
if (should_log_overflow && !gb->turbo) {
|
if (should_log_overflow && !gb->turbo) {
|
||||||
gb_log(gb, "Audio overflow\n");
|
GB_log(gb, "Audio overflow\n");
|
||||||
should_log_overflow = false;
|
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;
|
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) {
|
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));
|
memset(dest + gb->audio_position, 0, (count - gb->audio_position) * sizeof(*gb->audio_buffer));
|
||||||
count = gb->audio_position;
|
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;
|
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));
|
memset(&gb->apu, 0, sizeof(gb->apu));
|
||||||
gb->apu.wave_channels[0].duty = gb->apu.wave_channels[1].duty = 0.5;
|
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? */
|
/* Todo: what happens when reading from the wave from while it's playing? */
|
||||||
|
|
||||||
if (reg == GB_IO_NR52) {
|
if (reg == GB_IO_NR52) {
|
||||||
unsigned char value = 0;
|
uint8_t value = 0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
value >>= 1;
|
value >>= 1;
|
||||||
if (gb->apu.wave_channels[i].is_playing) {
|
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) {
|
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];
|
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 const double duties[] = {0.125, 0.25, 0.5, 0.75};
|
||||||
static uint16_t NRX3_X4_temp[3] = {0};
|
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) {
|
if (!gb->apu.global_enable && reg != GB_IO_NR52) {
|
||||||
return;
|
return;
|
||||||
@ -376,7 +376,7 @@ void apu_write(GB_gameboy_t *gb, unsigned char reg, unsigned char value)
|
|||||||
{
|
{
|
||||||
double r = value & 0x7;
|
double r = value & 0x7;
|
||||||
if (r == 0) r = 0.5;
|
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.wave_channels[3].frequency = 524288.0 / r / (1 << (s + 1));
|
||||||
gb->apu.lfsr_7_bit = value & 0x8;
|
gb->apu.lfsr_7_bit = value & 0x8;
|
||||||
break;
|
break;
|
||||||
@ -406,7 +406,7 @@ void apu_write(GB_gameboy_t *gb, unsigned char reg, unsigned char value)
|
|||||||
case GB_IO_NR52:
|
case GB_IO_NR52:
|
||||||
|
|
||||||
if ((value & 0x80) && !gb->apu.global_enable) {
|
if ((value & 0x80) && !gb->apu.global_enable) {
|
||||||
apu_init(gb);
|
GB_apu_init(gb);
|
||||||
gb->apu.global_enable = true;
|
gb->apu.global_enable = true;
|
||||||
}
|
}
|
||||||
else if (!(value & 0x80) && gb->apu.global_enable) {
|
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 MAX_CH_AMP 0x1E00
|
||||||
#define CH_STEP (0x1E00/0xF)
|
#define CH_STEP (0x1E00/0xF)
|
||||||
|
|
||||||
|
#include "save_struct.h"
|
||||||
|
|
||||||
struct GB_gameboy_s;
|
struct GB_gameboy_s;
|
||||||
typedef struct GB_gameboy_s GB_gameboy_t;
|
typedef struct GB_gameboy_s GB_gameboy_t;
|
||||||
@ -20,30 +21,30 @@ typedef struct
|
|||||||
/* Not all used on all channels */
|
/* Not all used on all channels */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
double phase;
|
GB_aligned_double phase;
|
||||||
double frequency;
|
GB_aligned_double frequency;
|
||||||
|
GB_aligned_double duty;
|
||||||
|
GB_aligned_double sound_length; /* In seconds */
|
||||||
int16_t amplitude;
|
int16_t amplitude;
|
||||||
int16_t start_amplitude;
|
int16_t start_amplitude;
|
||||||
double duty;
|
|
||||||
double sound_length; /* In seconds */
|
|
||||||
bool stop_on_length;
|
bool stop_on_length;
|
||||||
unsigned char envelope_steps;
|
uint8_t envelope_steps;
|
||||||
unsigned char cur_envelope_steps;
|
uint8_t cur_envelope_steps;
|
||||||
signed int envelope_direction;
|
signed int envelope_direction;
|
||||||
unsigned char sweep_steps;
|
uint8_t sweep_steps;
|
||||||
unsigned char cur_sweep_steps;
|
uint8_t cur_sweep_steps;
|
||||||
signed int sweep_direction;
|
signed int sweep_direction;
|
||||||
unsigned char sweep_shift;
|
uint8_t sweep_shift;
|
||||||
bool is_playing;
|
bool is_playing;
|
||||||
} GB_apu_channel_t;
|
} GB_apu_channel_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
GB_apu_channel_t wave_channels[4];
|
GB_apu_channel_t wave_channels[4];
|
||||||
double envelope_step_timer; /* In seconds */
|
GB_aligned_double envelope_step_timer; /* In seconds */
|
||||||
double sweep_step_timer; /* In seconds */
|
GB_aligned_double sweep_step_timer; /* In seconds */
|
||||||
signed char wave_form[32];
|
int8_t wave_form[32];
|
||||||
unsigned char wave_shift;
|
uint8_t wave_shift;
|
||||||
bool wave_enable;
|
bool wave_enable;
|
||||||
uint16_t lfsr;
|
uint16_t lfsr;
|
||||||
bool lfsr_7_bit;
|
bool lfsr_7_bit;
|
||||||
@ -54,11 +55,11 @@ typedef struct
|
|||||||
bool global_enable;
|
bool global_enable;
|
||||||
} GB_apu_t;
|
} GB_apu_t;
|
||||||
|
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
unsigned char apu_read(GB_gameboy_t *gb, unsigned char reg);
|
uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg);
|
||||||
void apu_init(GB_gameboy_t *gb);
|
void GB_apu_init(GB_gameboy_t *gb);
|
||||||
void apu_run(GB_gameboy_t *gb);
|
void GB_apu_run(GB_gameboy_t *gb);
|
||||||
|
|
||||||
#endif /* apu_h */
|
#endif /* apu_h */
|
||||||
|
196
Core/debugger.c
196
Core/debugger.c
@ -15,17 +15,17 @@ typedef struct {
|
|||||||
LVALUE_REG_L,
|
LVALUE_REG_L,
|
||||||
} kind;
|
} kind;
|
||||||
union {
|
union {
|
||||||
unsigned short *register_address;
|
uint16_t *register_address;
|
||||||
unsigned short memory_address;
|
uint16_t memory_address;
|
||||||
};
|
};
|
||||||
} lvalue_t;
|
} 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 += */
|
/* Not used until we add support for operators like += */
|
||||||
switch (lvalue.kind) {
|
switch (lvalue.kind) {
|
||||||
case LVALUE_MEMORY:
|
case LVALUE_MEMORY:
|
||||||
return read_memory(gb, lvalue.memory_address);
|
return GB_read_memory(gb, lvalue.memory_address);
|
||||||
|
|
||||||
case LVALUE_REG16:
|
case LVALUE_REG16:
|
||||||
return *lvalue.register_address;
|
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) {
|
switch (lvalue.kind) {
|
||||||
case LVALUE_MEMORY:
|
case LVALUE_MEMORY:
|
||||||
write_memory(gb, lvalue.memory_address, value);
|
GB_write_memory(gb, lvalue.memory_address, value);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case LVALUE_REG16:
|
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 uint16_t add(uint16_t a, uint16_t b) {return a + b;};
|
||||||
static unsigned short sub(unsigned short a, unsigned short b) {return a - b;};
|
static uint16_t sub(uint16_t a, uint16_t b) {return a - b;};
|
||||||
static unsigned short mul(unsigned short a, unsigned short b) {return a * b;};
|
static uint16_t mul(uint16_t a, uint16_t b) {return a * b;};
|
||||||
static unsigned short _div(unsigned short a, unsigned short b) {
|
static uint16_t _div(uint16_t a, uint16_t b) {
|
||||||
if (b == 0) {
|
if (b == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return a / b;
|
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) {
|
if (b == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return a % b;
|
return a % b;
|
||||||
};
|
};
|
||||||
static unsigned short and(unsigned short a, unsigned short b) {return a & b;};
|
static uint16_t and(uint16_t a, uint16_t b) {return a & b;};
|
||||||
static unsigned short or(unsigned short a, unsigned short b) {return a | b;};
|
static uint16_t or(uint16_t a, uint16_t b) {return a | b;};
|
||||||
static unsigned short xor(unsigned short a, unsigned short b) {return a ^ b;};
|
static uint16_t xor(uint16_t a, uint16_t b) {return a ^ b;};
|
||||||
static unsigned short shleft(unsigned short a, unsigned short b) {return a << b;};
|
static uint16_t shleft(uint16_t a, uint16_t b) {return a << b;};
|
||||||
static unsigned short shright(unsigned short a, unsigned short b) {return a >> b;};
|
static uint16_t shright(uint16_t a, uint16_t b) {return a >> b;};
|
||||||
static unsigned short assign(GB_gameboy_t *gb, lvalue_t a, unsigned short b)
|
static uint16_t assign(GB_gameboy_t *gb, lvalue_t a, uint16_t b)
|
||||||
{
|
{
|
||||||
write_lvalue(gb, a, b);
|
write_lvalue(gb, a, b);
|
||||||
return read_lvalue(gb, a);
|
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 {
|
static struct {
|
||||||
const char *string;
|
const char *string;
|
||||||
char priority;
|
char priority;
|
||||||
unsigned short (*operator)(unsigned short, unsigned short);
|
uint16_t (*operator)(uint16_t, uint16_t);
|
||||||
unsigned short (*lvalue_operator)(GB_gameboy_t *, lvalue_t, unsigned short);
|
uint16_t (*lvalue_operator)(GB_gameboy_t *, lvalue_t, uint16_t);
|
||||||
} operators[] =
|
} operators[] =
|
||||||
{
|
{
|
||||||
// Yes. This is not C-like. But it makes much more sense.
|
// Yes. This is not C-like. But it makes much more sense.
|
||||||
@ -109,7 +109,7 @@ static struct {
|
|||||||
{"=", 2, NULL, assign},
|
{"=", 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)
|
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)
|
if (length == 0)
|
||||||
{
|
{
|
||||||
gb_log(gb, "Expected expression.\n");
|
GB_log(gb, "Expected expression.\n");
|
||||||
*error = true;
|
*error = true;
|
||||||
return (lvalue_t){0,};
|
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};
|
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;
|
*error = true;
|
||||||
return (lvalue_t){0,};
|
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;
|
*error = true;
|
||||||
return (lvalue_t){0,};
|
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;
|
*error = false;
|
||||||
// Strip whitespace
|
// Strip whitespace
|
||||||
@ -206,7 +206,7 @@ unsigned short debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned
|
|||||||
}
|
}
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
{
|
{
|
||||||
gb_log(gb, "Expected expression.\n");
|
GB_log(gb, "Expected expression.\n");
|
||||||
*error = true;
|
*error = true;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ unsigned short debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned
|
|||||||
}
|
}
|
||||||
if (string[i] == ']') depth--;
|
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
|
// Search for lowest priority operator
|
||||||
signed int depth = 0;
|
signed int depth = 0;
|
||||||
@ -262,14 +262,14 @@ unsigned short debugger_evaluate(GB_gameboy_t *gb, const char *string, unsigned
|
|||||||
}
|
}
|
||||||
if (operator_index != -1) {
|
if (operator_index != -1) {
|
||||||
unsigned int right_start = (unsigned int)(operator_pos + strlen(operators[operator_index].string));
|
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 (*error) return -1;
|
||||||
if (operators[operator_index].lvalue_operator) {
|
if (operators[operator_index].lvalue_operator) {
|
||||||
lvalue_t left = debugger_evaluate_lvalue(gb, string, operator_pos, error);
|
lvalue_t left = debugger_evaluate_lvalue(gb, string, operator_pos, error);
|
||||||
if (*error) return -1;
|
if (*error) return -1;
|
||||||
return operators[operator_index].lvalue_operator(gb, left, right);
|
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;
|
if (*error) return -1;
|
||||||
return operators[operator_index].operator(left, right);
|
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;
|
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;
|
*error = true;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *end;
|
char *end;
|
||||||
unsigned short literal = (unsigned short) (strtol(string, &end, 16));
|
uint16_t literal = (uint16_t) (strtol(string, &end, 16));
|
||||||
if (end != string + length) {
|
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;
|
*error = true;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -319,7 +319,7 @@ typedef bool debugger_command_imp_t(GB_gameboy_t *gb, char *arguments);
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *command;
|
const char *command;
|
||||||
unsigned char min_length;
|
uint8_t min_length;
|
||||||
debugger_command_imp_t *implementation;
|
debugger_command_imp_t *implementation;
|
||||||
const char *help_string; // Null if should not appear in help
|
const char *help_string; // Null if should not appear in help
|
||||||
} debugger_command_t;
|
} debugger_command_t;
|
||||||
@ -335,7 +335,7 @@ static const char *lstrip(const char *str)
|
|||||||
static bool cont(GB_gameboy_t *gb, char *arguments)
|
static bool cont(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments))) {
|
if (strlen(lstrip(arguments))) {
|
||||||
gb_log(gb, "Usage: continue\n");
|
GB_log(gb, "Usage: continue\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
gb->debug_stopped = false;
|
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)
|
static bool next(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments))) {
|
if (strlen(lstrip(arguments))) {
|
||||||
gb_log(gb, "Usage: next\n");
|
GB_log(gb, "Usage: next\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,7 +358,7 @@ static bool next(GB_gameboy_t *gb, char *arguments)
|
|||||||
static bool step(GB_gameboy_t *gb, char *arguments)
|
static bool step(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments))) {
|
if (strlen(lstrip(arguments))) {
|
||||||
gb_log(gb, "Usage: step\n");
|
GB_log(gb, "Usage: step\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,7 +368,7 @@ static bool step(GB_gameboy_t *gb, char *arguments)
|
|||||||
static bool finish(GB_gameboy_t *gb, char *arguments)
|
static bool finish(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments))) {
|
if (strlen(lstrip(arguments))) {
|
||||||
gb_log(gb, "Usage: finish\n");
|
GB_log(gb, "Usage: finish\n");
|
||||||
return true;
|
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)
|
static bool stack_leak_detection(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments))) {
|
if (strlen(lstrip(arguments))) {
|
||||||
gb_log(gb, "Usage: sld\n");
|
GB_log(gb, "Usage: sld\n");
|
||||||
return true;
|
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)
|
static bool registers(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments))) {
|
if (strlen(lstrip(arguments))) {
|
||||||
gb_log(gb, "Usage: registers\n");
|
GB_log(gb, "Usage: registers\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_log(gb, "AF = %04x\n", gb->registers[GB_REGISTER_AF]);
|
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, "BC = %04x\n", gb->registers[GB_REGISTER_BC]);
|
||||||
gb_log(gb, "DE = %04x\n", gb->registers[GB_REGISTER_DE]);
|
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, "HL = %04x\n", gb->registers[GB_REGISTER_HL]);
|
||||||
gb_log(gb, "SP = %04x\n", gb->registers[GB_REGISTER_SP]);
|
GB_log(gb, "SP = %04x\n", gb->registers[GB_REGISTER_SP]);
|
||||||
gb_log(gb, "PC = %04x\n", gb->pc);
|
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, "TIMA = %d/%u\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, "Display Controller: LY = %d/%u\n", gb->io_registers[GB_IO_LY], gb->display_cycles % 456);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the index of the closest breakpoint equal or greater to addr */
|
/* 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) {
|
if (!gb->breakpoints) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -418,7 +418,7 @@ static unsigned short find_breakpoint(GB_gameboy_t *gb, unsigned short addr)
|
|||||||
int min = 0;
|
int min = 0;
|
||||||
int max = gb->n_breakpoints;
|
int max = gb->n_breakpoints;
|
||||||
while (min < max) {
|
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) return pivot;
|
||||||
if (gb->breakpoints[pivot] > addr) {
|
if (gb->breakpoints[pivot] > addr) {
|
||||||
max = pivot - 1;
|
max = pivot - 1;
|
||||||
@ -427,24 +427,24 @@ static unsigned short find_breakpoint(GB_gameboy_t *gb, unsigned short addr)
|
|||||||
min = pivot + 1;
|
min = pivot + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (unsigned short) min;
|
return (uint16_t) min;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool breakpoint(GB_gameboy_t *gb, char *arguments)
|
static bool breakpoint(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments)) == 0) {
|
if (strlen(lstrip(arguments)) == 0) {
|
||||||
gb_log(gb, "Usage: breakpoint <expression>\n");
|
GB_log(gb, "Usage: breakpoint <expression>\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool error;
|
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;
|
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) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,14 +453,14 @@ static bool breakpoint(GB_gameboy_t *gb, char *arguments)
|
|||||||
gb->breakpoints[index] = result;
|
gb->breakpoints[index] = result;
|
||||||
gb->n_breakpoints++;
|
gb->n_breakpoints++;
|
||||||
|
|
||||||
gb_log(gb, "Breakpoint set at %04x\n", result);
|
GB_log(gb, "Breakpoint set at %04x\n", result);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool delete(GB_gameboy_t *gb, char *arguments)
|
static bool delete(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments)) == 0) {
|
if (strlen(lstrip(arguments)) == 0) {
|
||||||
gb_log(gb, "Delete all breakpoints? ");
|
GB_log(gb, "Delete all breakpoints? ");
|
||||||
char *answer = gb->input_callback(gb);
|
char *answer = gb->input_callback(gb);
|
||||||
if (answer[0] == 'Y' || answer[0] == 'y') {
|
if (answer[0] == 'Y' || answer[0] == 'y') {
|
||||||
free(gb->breakpoints);
|
free(gb->breakpoints);
|
||||||
@ -471,13 +471,13 @@ static bool delete(GB_gameboy_t *gb, char *arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool error;
|
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;
|
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) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,33 +485,33 @@ static bool delete(GB_gameboy_t *gb, char *arguments)
|
|||||||
gb->n_breakpoints--;
|
gb->n_breakpoints--;
|
||||||
gb->breakpoints = realloc(gb->breakpoints, gb->n_breakpoints * sizeof(gb->breakpoints[0]));
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool list(GB_gameboy_t *gb, char *arguments)
|
static bool list(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments))) {
|
if (strlen(lstrip(arguments))) {
|
||||||
gb_log(gb, "Usage: list\n");
|
GB_log(gb, "Usage: list\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb->n_breakpoints == 0) {
|
if (gb->n_breakpoints == 0) {
|
||||||
gb_log(gb, "No breakpoints set.\n");
|
GB_log(gb, "No breakpoints set.\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_log(gb, "%d breakpoint(s) set:\n", gb->n_breakpoints);
|
GB_log(gb, "%d breakpoint(s) set:\n", gb->n_breakpoints);
|
||||||
for (unsigned short i = 0; i < gb->n_breakpoints; i++) {
|
for (uint16_t i = 0; i < gb->n_breakpoints; i++) {
|
||||||
gb_log(gb, " %d. %04x\n", i + 1, gb->breakpoints[i]);
|
GB_log(gb, " %d. %04x\n", i + 1, gb->breakpoints[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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) {
|
if (index < gb->n_breakpoints && gb->breakpoints[index] == addr) {
|
||||||
return true;
|
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)
|
static bool print(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments)) == 0) {
|
if (strlen(lstrip(arguments)) == 0) {
|
||||||
gb_log(gb, "Usage: print <expression>\n");
|
GB_log(gb, "Usage: print <expression>\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool error;
|
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) {
|
if (!error) {
|
||||||
gb_log(gb, "=%04x\n", result);
|
GB_log(gb, "=%04x\n", result);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -536,18 +536,18 @@ static bool print(GB_gameboy_t *gb, char *arguments)
|
|||||||
static bool examine(GB_gameboy_t *gb, char *arguments)
|
static bool examine(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments)) == 0) {
|
if (strlen(lstrip(arguments)) == 0) {
|
||||||
gb_log(gb, "Usage: examine <expression>\n");
|
GB_log(gb, "Usage: examine <expression>\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool error;
|
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) {
|
if (!error) {
|
||||||
gb_log(gb, "%4x: ", addr);
|
GB_log(gb, "%4x: ", addr);
|
||||||
for (int i = 0; i < 16; i++) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@ -555,41 +555,41 @@ static bool examine(GB_gameboy_t *gb, char *arguments)
|
|||||||
static bool mbc(GB_gameboy_t *gb, char *arguments)
|
static bool mbc(GB_gameboy_t *gb, char *arguments)
|
||||||
{
|
{
|
||||||
if (strlen(lstrip(arguments))) {
|
if (strlen(lstrip(arguments))) {
|
||||||
gb_log(gb, "Usage: mbc\n");
|
GB_log(gb, "Usage: mbc\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GB_cartridge_t *cartridge = gb->cartridge_type;
|
const GB_cartridge_t *cartridge = gb->cartridge_type;
|
||||||
|
|
||||||
if (cartridge->has_ram) {
|
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 {
|
else {
|
||||||
gb_log(gb, "No cartridge RAM\n");
|
GB_log(gb, "No cartridge RAM\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cartridge->mbc_type) {
|
if (cartridge->mbc_type) {
|
||||||
gb_log(gb, "MBC%d\n", 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, "Current mapped ROM bank: %x\n", gb->mbc_rom_bank);
|
||||||
if (cartridge->has_ram) {
|
if (cartridge->has_ram) {
|
||||||
gb_log(gb, "Current mapped RAM bank: %x\n", gb->mbc_ram_bank);
|
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, "RAM is curently %s\n", gb->mbc_ram_enable? "enabled" : "disabled");
|
||||||
}
|
}
|
||||||
if (cartridge->mbc_type == MBC1) {
|
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 {
|
else {
|
||||||
gb_log(gb, "No MBC\n");
|
GB_log(gb, "No MBC\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cartridge->has_rumble) {
|
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) {
|
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;
|
const debugger_command_t *command = commands;
|
||||||
for (size_t i = sizeof(commands) / sizeof(*command); i--; command++) {
|
for (size_t i = sizeof(commands) / sizeof(*command); i--; command++) {
|
||||||
if (command->help_string) {
|
if (command->help_string) {
|
||||||
gb_attributed_log(gb, GB_LOG_BOLD, "%s", command->command);
|
GB_attributed_log(gb, GB_LOG_BOLD, "%s", command->command);
|
||||||
gb_log(gb, ": %s\n", command->help_string);
|
GB_log(gb, ": %s\n", command->help_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -643,13 +643,13 @@ static const debugger_command_t *find_command(const char *string)
|
|||||||
return NULL;
|
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... */
|
/* Called just after the CPU calls a function/enters an interrupt/etc... */
|
||||||
|
|
||||||
if (gb->stack_leak_detection) {
|
if (gb->stack_leak_detection) {
|
||||||
if (gb->debug_call_depth >= sizeof(gb->sp_for_call_depth) / sizeof(gb->sp_for_call_depth[0])) {
|
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;
|
gb->debug_stopped = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -661,7 +661,7 @@ void debugger_call_hook(GB_gameboy_t *gb)
|
|||||||
gb->debug_call_depth++;
|
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 */
|
/* 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->stack_leak_detection) {
|
||||||
if (gb->debug_call_depth < 0) {
|
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;
|
gb->debug_stopped = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (gb->registers[GB_REGISTER_SP] != gb->sp_for_call_depth[gb->debug_call_depth]) {
|
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, "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, "SP is %04x, should be %04x.\n", gb->registers[GB_REGISTER_SP],
|
||||||
gb->sp_for_call_depth[gb->debug_call_depth]);
|
gb->sp_for_call_depth[gb->debug_call_depth]);
|
||||||
gb->debug_stopped = true;
|
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;
|
char *input = NULL;
|
||||||
if (gb->debug_next_command && gb->debug_call_depth <= 0) {
|
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;
|
gb->debug_stopped = true;
|
||||||
}
|
}
|
||||||
if (gb->debug_stopped) {
|
if (gb->debug_stopped) {
|
||||||
cpu_disassemble(gb, gb->pc, 5);
|
GB_cpu_disassemble(gb, gb->pc, 5);
|
||||||
}
|
}
|
||||||
next_command:
|
next_command:
|
||||||
if (input) {
|
if (input) {
|
||||||
@ -701,8 +701,8 @@ next_command:
|
|||||||
}
|
}
|
||||||
if (!gb->debug_stopped && should_break(gb, gb->pc)) {
|
if (!gb->debug_stopped && should_break(gb, gb->pc)) {
|
||||||
gb->debug_stopped = true;
|
gb->debug_stopped = true;
|
||||||
gb_log(gb, "Breakpoint: PC = %04x\n", gb->pc);
|
GB_log(gb, "Breakpoint: PC = %04x\n", gb->pc);
|
||||||
cpu_disassemble(gb, gb->pc, 5);
|
GB_cpu_disassemble(gb, gb->pc, 5);
|
||||||
}
|
}
|
||||||
if (gb->debug_stopped) {
|
if (gb->debug_stopped) {
|
||||||
gb->debug_next_command = false;
|
gb->debug_next_command = false;
|
||||||
@ -731,7 +731,7 @@ next_command:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gb_log(gb, "%s: no such command.\n", command_string);
|
GB_log(gb, "%s: no such command.\n", command_string);
|
||||||
goto next_command;
|
goto next_command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
#define debugger_h
|
#define debugger_h
|
||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
|
|
||||||
void debugger_run(GB_gameboy_t *gb);
|
void GB_debugger_run(GB_gameboy_t *gb);
|
||||||
void debugger_call_hook(GB_gameboy_t *gb);
|
void GB_debugger_call_hook(GB_gameboy_t *gb);
|
||||||
void debugger_ret_hook(GB_gameboy_t *gb);
|
void GB_debugger_ret_hook(GB_gameboy_t *gb);
|
||||||
|
|
||||||
#endif /* debugger_h */
|
#endif /* debugger_h */
|
||||||
|
@ -9,14 +9,14 @@
|
|||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char y;
|
uint8_t y;
|
||||||
unsigned char x;
|
uint8_t x;
|
||||||
unsigned char tile;
|
uint8_t tile;
|
||||||
unsigned char flags;
|
uint8_t flags;
|
||||||
} GB_sprite_t;
|
} GB_sprite_t;
|
||||||
#pragma pack(pop)
|
#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)
|
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 1 - OBJ (Sprite) Display Enable (0=Off, 1=On)
|
||||||
Bit 0 - BG Display (for CGB see below) (0=Off, 1=On)
|
Bit 0 - BG Display (for CGB see below) (0=Off, 1=On)
|
||||||
*/
|
*/
|
||||||
unsigned short map = 0x1800;
|
uint16_t map = 0x1800;
|
||||||
unsigned char tile = 0;
|
uint8_t tile = 0;
|
||||||
unsigned char attributes = 0;
|
uint8_t attributes = 0;
|
||||||
unsigned char sprite_palette = 0;
|
uint8_t sprite_palette = 0;
|
||||||
unsigned short tile_address = 0;
|
uint16_t tile_address = 0;
|
||||||
unsigned char background_pixel = 0, sprite_pixel = 0;
|
uint8_t background_pixel = 0, sprite_pixel = 0;
|
||||||
GB_sprite_t *sprite = (GB_sprite_t *) &gb->oam;
|
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 lcd_8_16_mode = (gb->io_registers[GB_IO_LCDC] & 4) != 0;
|
||||||
bool sprites_enabled = (gb->io_registers[GB_IO_LCDC] & 2) != 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 use_obp1 = false, priority = false;
|
||||||
bool in_window = false;
|
bool in_window = false;
|
||||||
if (gb->effective_window_enabled && (gb->io_registers[GB_IO_LCDC] & 0x20)) { /* Window Enabled */
|
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) {
|
if (sprites_enabled) {
|
||||||
// Loop all sprites
|
// 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_y = sprite->y - 16;
|
||||||
int sprite_x = sprite->x - 8;
|
int sprite_x = sprite->x - 8;
|
||||||
// Is sprite in our line?
|
// Is sprite in our line?
|
||||||
if (sprite_y <= y && sprite_y + (lcd_8_16_mode? 16:8) > y) {
|
if (sprite_y <= y && sprite_y + (lcd_8_16_mode? 16:8) > y) {
|
||||||
unsigned char tile_x, tile_y, current_sprite_pixel;
|
uint8_t tile_x, tile_y, current_sprite_pixel;
|
||||||
unsigned short line_address;
|
uint16_t line_address;
|
||||||
// Limit to 10 sprites in one scan line.
|
// Limit to 10 sprites in one scan line.
|
||||||
if (++sprites_in_line == 11) break;
|
if (++sprites_in_line == 11) break;
|
||||||
// Does not overlap our pixel.
|
// 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;
|
tile_address = tile * 0x10;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tile_address = (signed char) tile * 0x10 + 0x1000;
|
tile_address = (int8_t) tile * 0x10 + 0x1000;
|
||||||
}
|
}
|
||||||
if (attributes & 0x8) {
|
if (attributes & 0x8) {
|
||||||
tile_address += 0x2000;
|
tile_address += 0x2000;
|
||||||
@ -171,7 +171,7 @@ void display_vblank(GB_gameboy_t *gb)
|
|||||||
if (gb->turbo) {
|
if (gb->turbo) {
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
gettimeofday(&now, NULL);
|
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) {
|
if (nanoseconds <= gb->last_vblank + FRAME_LENGTH) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -209,7 +209,7 @@ void display_vblank(GB_gameboy_t *gb)
|
|||||||
struct timespec sleep = {0,};
|
struct timespec sleep = {0,};
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
signed long nanoseconds = (now.tv_usec) * 1000 + now.tv_sec * 1000000000L;
|
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);
|
sleep.tv_nsec = (FRAME_LENGTH + gb->last_vblank - nanoseconds);
|
||||||
nanosleep(&sleep, NULL);
|
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;
|
x &= 0x1f;
|
||||||
return (x << 3) | (x >> 2);
|
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;
|
uint8_t *palette_data = background_palette? gb->background_palletes_data : gb->sprite_palletes_data;
|
||||||
unsigned short color = palette_data[index & ~1] | (palette_data[index | 1] << 8);
|
uint16_t color = palette_data[index & ~1] | (palette_data[index | 1] << 8);
|
||||||
|
|
||||||
// No need to &, scale channel does that.
|
// No need to &, scale channel does that.
|
||||||
unsigned char r = scale_channel(color);
|
uint8_t r = scale_channel(color);
|
||||||
unsigned char g = scale_channel(color >> 5);
|
uint8_t g = scale_channel(color >> 5);
|
||||||
unsigned char b = scale_channel(color >> 10);
|
uint8_t b = scale_channel(color >> 10);
|
||||||
assert (gb->rgb_encode_callback);
|
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);
|
(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 MODE1_LENGTH 204
|
||||||
#define LINE_LENGTH (MODE2_LENGTH + MODE3_LENGTH + MODE1_LENGTH) // = 456
|
#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.
|
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
|
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;
|
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;
|
gb->io_registers[GB_IO_STAT] &= ~3;
|
||||||
|
|
||||||
if (gb->display_cycles >= LCDC_PERIOD) {
|
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
|
/* 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. */
|
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++) {
|
for (;gb->previous_lcdc_x < current_lcdc_x; gb->previous_lcdc_x++) {
|
||||||
if (gb->previous_lcdc_x >= 160) {
|
if (gb->previous_lcdc_x >= 160) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
#define display_h
|
#define display_h
|
||||||
|
|
||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
void display_run(GB_gameboy_t *gb);
|
void GB_display_run(GB_gameboy_t *gb);
|
||||||
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);
|
||||||
#endif /* display_h */
|
#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
|
{ 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;
|
char *string = NULL;
|
||||||
vasprintf(&string, fmt, args);
|
vasprintf(&string, fmt, args);
|
||||||
@ -75,19 +75,19 @@ void gb_attributed_logv(GB_gameboy_t *gb, gb_log_attributes attributes, const ch
|
|||||||
free(string);
|
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_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
gb_attributed_logv(gb, attributes, fmt, args);
|
GB_attributed_logv(gb, attributes, fmt, args);
|
||||||
va_end(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_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
gb_attributed_logv(gb, 0, fmt, args);
|
GB_attributed_logv(gb, 0, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ static char *default_input_callback(GB_gameboy_t *gb)
|
|||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gb_init(GB_gameboy_t *gb)
|
void GB_init(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
memset(gb, 0, sizeof(*gb));
|
memset(gb, 0, sizeof(*gb));
|
||||||
gb->magic = (uintptr_t)'SAME';
|
gb->magic = (uintptr_t)'SAME';
|
||||||
@ -136,7 +136,7 @@ void gb_init(GB_gameboy_t *gb)
|
|||||||
gb->io_registers[GB_IO_JOYP] = 0xF;
|
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));
|
memset(gb, 0, sizeof(*gb));
|
||||||
gb->magic = (uintptr_t)'SAME';
|
gb->magic = (uintptr_t)'SAME';
|
||||||
@ -160,7 +160,7 @@ void gb_init_cgb(GB_gameboy_t *gb)
|
|||||||
gb->io_registers[GB_IO_JOYP] = 0xF;
|
gb->io_registers[GB_IO_JOYP] = 0xF;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gb_free(GB_gameboy_t *gb)
|
void GB_free(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
if (gb->ram) {
|
if (gb->ram) {
|
||||||
free(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");
|
FILE *f = fopen(path, "r");
|
||||||
if (!f) return errno;
|
if (!f) return errno;
|
||||||
fread(gb->bios, sizeof(gb->bios), 1, f);
|
fread(gb->boot_rom, sizeof(gb->boot_rom), 1, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 0;
|
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");
|
FILE *f = fopen(path, "r");
|
||||||
if (!f) return errno;
|
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))
|
#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. */
|
/* 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");
|
FILE *f = fopen(path, "w");
|
||||||
if (!f) {
|
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))
|
#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;
|
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 (!READ_SECTION(&save, f, video )) goto error;
|
||||||
|
|
||||||
if (gb->magic != save.magic) {
|
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;
|
errno = -1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb->version != save.version) {
|
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;
|
errno = -1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb->mbc_ram_size != save.mbc_ram_size) {
|
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;
|
errno = -1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb->ram_size != save.ram_size) {
|
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;
|
errno = -1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb->vram_size != save.vram_size) {
|
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;
|
errno = -1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -364,7 +364,7 @@ error:
|
|||||||
return errno;
|
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->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 */
|
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 */
|
/* 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");
|
FILE *f = fopen(path, "r");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
@ -433,39 +433,39 @@ exit:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gb_run(GB_gameboy_t *gb)
|
void GB_run(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
update_joyp(gb);
|
GB_update_joyp(gb);
|
||||||
debugger_run(gb);
|
GB_debugger_run(gb);
|
||||||
cpu_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;
|
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;
|
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;
|
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;
|
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;
|
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) {
|
if (gb->audio_buffer) {
|
||||||
free(gb->audio_buffer);
|
free(gb->audio_buffer);
|
||||||
|
159
Core/gb.h
159
Core/gb.h
@ -1,5 +1,5 @@
|
|||||||
#ifndef gb_h
|
#ifndef GB_h
|
||||||
#define gb_h
|
#define GB_h
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -8,7 +8,7 @@
|
|||||||
#include "save_struct.h"
|
#include "save_struct.h"
|
||||||
|
|
||||||
|
|
||||||
#define GB_STRUCT_VERSION 8
|
#define GB_STRUCT_VERSION 9
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GB_REGISTER_AF,
|
GB_REGISTER_AF,
|
||||||
@ -146,14 +146,14 @@ typedef enum {
|
|||||||
GB_LOG_DASHED_UNDERLINE = 2,
|
GB_LOG_DASHED_UNDERLINE = 2,
|
||||||
GB_LOG_UNDERLINE = 4,
|
GB_LOG_UNDERLINE = 4,
|
||||||
GB_LOG_UNDERLINE_MASK = GB_LOG_DASHED_UNDERLINE | GB_LOG_UNDERLINE
|
GB_LOG_UNDERLINE_MASK = GB_LOG_DASHED_UNDERLINE | GB_LOG_UNDERLINE
|
||||||
} gb_log_attributes;
|
} GB_log_attributes;
|
||||||
|
|
||||||
struct GB_gameboy_s;
|
struct GB_gameboy_s;
|
||||||
typedef struct GB_gameboy_s GB_gameboy_t;
|
typedef struct GB_gameboy_s GB_gameboy_t;
|
||||||
typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb);
|
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 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 {
|
typedef struct {
|
||||||
enum {
|
enum {
|
||||||
@ -172,21 +172,32 @@ typedef struct {
|
|||||||
|
|
||||||
/* When state saving, each section is dumped independently of other sections.
|
/* 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.
|
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 {
|
typedef struct GB_gameboy_s {
|
||||||
GB_SECTION(header,
|
GB_SECTION(header,
|
||||||
uintptr_t magic; // States are currently platform dependent
|
/* The magic makes sure a state file is:
|
||||||
int version; // and version dependent
|
- 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,
|
GB_SECTION(core_state,
|
||||||
/* Registers */
|
/* Registers */
|
||||||
unsigned short pc;
|
uint16_t pc;
|
||||||
unsigned short registers[GB_REGISTERS_16_BIT];
|
uint16_t registers[GB_REGISTERS_16_BIT];
|
||||||
bool ime;
|
bool ime;
|
||||||
unsigned char interrupt_enable;
|
uint8_t interrupt_enable;
|
||||||
unsigned char cgb_ram_bank;
|
uint8_t cgb_ram_bank;
|
||||||
|
|
||||||
/* CPU and General Hardware Flags*/
|
/* CPU and General Hardware Flags*/
|
||||||
bool cgb_mode;
|
bool cgb_mode;
|
||||||
@ -194,23 +205,23 @@ typedef struct GB_gameboy_s {
|
|||||||
bool cgb_double_speed;
|
bool cgb_double_speed;
|
||||||
bool halted;
|
bool halted;
|
||||||
bool stopped;
|
bool stopped;
|
||||||
bool bios_finished;
|
bool boot_rom_finished;
|
||||||
);
|
);
|
||||||
|
|
||||||
/* HDMA */
|
/* HDMA */
|
||||||
GB_SECTION(hdma,
|
GB_SECTION(hdma,
|
||||||
bool hdma_on;
|
bool hdma_on;
|
||||||
bool hdma_on_hblank;
|
bool hdma_on_hblank;
|
||||||
unsigned char hdma_steps_left;
|
uint8_t hdma_steps_left;
|
||||||
unsigned short hdma_cycles;
|
uint16_t hdma_cycles;
|
||||||
unsigned short hdma_current_src, hdma_current_dest;
|
uint16_t hdma_current_src, hdma_current_dest;
|
||||||
);
|
);
|
||||||
|
|
||||||
/* MBC */
|
/* MBC */
|
||||||
GB_SECTION(mbc,
|
GB_SECTION(mbc,
|
||||||
unsigned short mbc_rom_bank;
|
uint16_t mbc_rom_bank;
|
||||||
unsigned char mbc_ram_bank;
|
uint8_t mbc_ram_bank;
|
||||||
size_t mbc_ram_size;
|
uint32_t mbc_ram_size;
|
||||||
bool mbc_ram_enable;
|
bool mbc_ram_enable;
|
||||||
bool mbc_ram_banking;
|
bool mbc_ram_banking;
|
||||||
);
|
);
|
||||||
@ -218,18 +229,18 @@ typedef struct GB_gameboy_s {
|
|||||||
|
|
||||||
/* HRAM and HW Registers */
|
/* HRAM and HW Registers */
|
||||||
GB_SECTION(hram,
|
GB_SECTION(hram,
|
||||||
unsigned char hram[0xFFFF - 0xFF80];
|
uint8_t hram[0xFFFF - 0xFF80];
|
||||||
unsigned char io_registers[0x80];
|
uint8_t io_registers[0x80];
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Timing */
|
/* Timing */
|
||||||
GB_SECTION(timing,
|
GB_SECTION(timing,
|
||||||
signed long last_vblank;
|
int64_t last_vblank;
|
||||||
unsigned long display_cycles;
|
uint32_t display_cycles;
|
||||||
unsigned long div_cycles;
|
uint32_t div_cycles;
|
||||||
unsigned long tima_cycles;
|
uint32_t tima_cycles;
|
||||||
unsigned long dma_cycles;
|
uint32_t dma_cycles;
|
||||||
double apu_cycles;
|
GB_aligned_double apu_cycles;
|
||||||
);
|
);
|
||||||
|
|
||||||
/* APU */
|
/* APU */
|
||||||
@ -241,47 +252,45 @@ typedef struct GB_gameboy_s {
|
|||||||
GB_SECTION(rtc,
|
GB_SECTION(rtc,
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
unsigned char rtc_seconds;
|
uint8_t rtc_seconds;
|
||||||
unsigned char rtc_minutes;
|
uint8_t rtc_minutes;
|
||||||
unsigned char rtc_hours;
|
uint8_t rtc_hours;
|
||||||
unsigned char rtc_days;
|
uint8_t rtc_days;
|
||||||
unsigned char rtc_high;
|
uint8_t rtc_high;
|
||||||
};
|
};
|
||||||
unsigned char rtc_data[5];
|
uint8_t rtc_data[5];
|
||||||
};
|
};
|
||||||
time_t last_rtc_second;
|
time_t last_rtc_second;
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Video Display */
|
/* Video Display */
|
||||||
GB_SECTION(video,
|
GB_SECTION(video,
|
||||||
unsigned long vram_size; // Different between CGB and DMG
|
uint32_t vram_size; // Different between CGB and DMG
|
||||||
unsigned char cgb_vram_bank;
|
uint8_t cgb_vram_bank;
|
||||||
unsigned char oam[0xA0];
|
uint8_t oam[0xA0];
|
||||||
unsigned char background_palletes_data[0x40];
|
uint8_t background_palletes_data[0x40];
|
||||||
unsigned char sprite_palletes_data[0x40];
|
uint8_t sprite_palletes_data[0x40];
|
||||||
uint32_t background_palletes_rgb[0x20];
|
uint32_t background_palletes_rgb[0x20];
|
||||||
uint32_t sprite_palletes_rgb[0x20];
|
uint32_t sprite_palletes_rgb[0x20];
|
||||||
GB_PADDING(bool, ly144_bug_oam);
|
int16_t previous_lcdc_x;
|
||||||
GB_PADDING(bool, ly144_bug_hblank);
|
uint8_t padding;
|
||||||
signed short previous_lcdc_x;
|
|
||||||
unsigned char padding;
|
|
||||||
bool effective_window_enabled;
|
bool effective_window_enabled;
|
||||||
unsigned char effective_window_y;
|
uint8_t effective_window_y;
|
||||||
bool stat_interrupt_line;
|
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 */
|
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
||||||
|
|
||||||
/* ROM */
|
/* ROM */
|
||||||
unsigned char *rom;
|
uint8_t *rom;
|
||||||
size_t rom_size;
|
uint32_t rom_size;
|
||||||
const GB_cartridge_t *cartridge_type;
|
const GB_cartridge_t *cartridge_type;
|
||||||
|
|
||||||
/* Various RAMs */
|
/* Various RAMs */
|
||||||
unsigned char *ram;
|
uint8_t *ram;
|
||||||
unsigned char *vram;
|
uint8_t *vram;
|
||||||
unsigned char *mbc_ram;
|
uint8_t *mbc_ram;
|
||||||
|
|
||||||
/* I/O */
|
/* I/O */
|
||||||
uint32_t *screen;
|
uint32_t *screen;
|
||||||
@ -305,17 +314,17 @@ typedef struct GB_gameboy_s {
|
|||||||
/* Debugger */
|
/* Debugger */
|
||||||
int debug_call_depth;
|
int debug_call_depth;
|
||||||
bool debug_fin_command, debug_next_command;
|
bool debug_fin_command, debug_next_command;
|
||||||
unsigned short n_breakpoints;
|
uint16_t n_breakpoints;
|
||||||
unsigned short *breakpoints;
|
uint16_t *breakpoints;
|
||||||
bool stack_leak_detection;
|
bool stack_leak_detection;
|
||||||
unsigned short sp_for_call_depth[0x200]; /* Should be much more than enough */
|
uint16_t sp_for_call_depth[0x200]; /* Should be much more than enough */
|
||||||
unsigned short addr_for_call_depth[0x200];
|
uint16_t addr_for_call_depth[0x200];
|
||||||
bool debug_stopped;
|
bool debug_stopped;
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
bool turbo;
|
bool turbo;
|
||||||
unsigned long ram_size; // Different between CGB and DMG
|
uint32_t ram_size; // Different between CGB and DMG
|
||||||
unsigned char bios[0x900];
|
uint8_t boot_rom[0x900];
|
||||||
|
|
||||||
} GB_gameboy_t;
|
} GB_gameboy_t;
|
||||||
|
|
||||||
@ -325,23 +334,23 @@ typedef struct GB_gameboy_s {
|
|||||||
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void gb_init(GB_gameboy_t *gb);
|
void GB_init(GB_gameboy_t *gb);
|
||||||
void gb_init_cgb(GB_gameboy_t *gb);
|
void GB_init_cgb(GB_gameboy_t *gb);
|
||||||
void gb_free(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_boot_rom(GB_gameboy_t *gb, const char *path);
|
||||||
int gb_load_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);
|
int GB_save_battery(GB_gameboy_t *gb, const char *path);
|
||||||
void gb_load_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_save_state(GB_gameboy_t *gb, const char *path);
|
||||||
int gb_load_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_run(GB_gameboy_t *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);
|
||||||
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);
|
||||||
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);
|
||||||
void gb_log(GB_gameboy_t *gb, const char *fmt, ...) __printflike(2, 3);
|
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_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_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_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_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 "gb.h"
|
||||||
#include "joypad.h"
|
#include "joypad.h"
|
||||||
|
|
||||||
void update_joyp(GB_gameboy_t *gb)
|
void GB_update_joyp(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
unsigned char key_selection = 0;
|
uint8_t key_selection = 0;
|
||||||
unsigned char previous_state = 0;
|
uint8_t previous_state = 0;
|
||||||
|
|
||||||
/* Todo: add delay to key selection */
|
/* Todo: add delay to key selection */
|
||||||
previous_state = gb->io_registers[GB_IO_JOYP] & 0xF;
|
previous_state = gb->io_registers[GB_IO_JOYP] & 0xF;
|
||||||
@ -19,21 +19,21 @@ void update_joyp(GB_gameboy_t *gb)
|
|||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
/* Direction keys */
|
/* 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;
|
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i]) << i;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
/* Other keys */
|
/* 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;
|
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i + 4]) << i;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
/* Todo: verifiy this is correct */
|
/* 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]) << i;
|
||||||
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i + 4]) << i;
|
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i + 4]) << i;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#define joypad_h
|
#define joypad_h
|
||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
|
|
||||||
void update_joyp(GB_gameboy_t *gb);
|
void GB_update_joyp(GB_gameboy_t *gb);
|
||||||
void update_keys_status(GB_gameboy_t *gb);
|
void GB_update_keys_status(GB_gameboy_t *gb);
|
||||||
|
|
||||||
#endif /* joypad_h */
|
#endif /* joypad_h */
|
||||||
|
@ -5,17 +5,17 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
typedef unsigned char GB_read_function_t(GB_gameboy_t *gb, unsigned short addr);
|
typedef uint8_t GB_read_function_t(GB_gameboy_t *gb, uint16_t addr);
|
||||||
typedef void GB_write_function_t(GB_gameboy_t *gb, unsigned short addr, unsigned char value);
|
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) {
|
if (addr < 0x100 && !gb->boot_rom_finished) {
|
||||||
return gb->bios[addr];
|
return gb->boot_rom[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr >= 0x200 && addr < 0x900 && gb->is_cgb && !gb->bios_finished) {
|
if (addr >= 0x200 && addr < 0x900 && gb->is_cgb && !gb->boot_rom_finished) {
|
||||||
return gb->bios[addr];
|
return gb->boot_rom[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gb->rom_size) {
|
if (!gb->rom_size) {
|
||||||
@ -24,7 +24,7 @@ static unsigned char read_rom(GB_gameboy_t *gb, unsigned short addr)
|
|||||||
return gb->rom[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) {
|
if (gb->mbc_rom_bank >= gb->rom_size / 0x4000) {
|
||||||
return 0xFF;
|
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];
|
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) {
|
if ((gb->io_registers[GB_IO_STAT] & 0x3) == 3) {
|
||||||
return 0xFF;
|
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) {
|
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
||||||
/* RTC read */
|
/* 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;
|
unsigned int ram_index = (addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000;
|
||||||
if (!gb->mbc_ram_enable)
|
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;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
if (ram_index >= gb->mbc_ram_size) {
|
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 0xFF;
|
||||||
}
|
}
|
||||||
return gb->mbc_ram[(addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000];
|
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];
|
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];
|
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) {
|
if (addr < 0xFE00) {
|
||||||
@ -150,7 +150,7 @@ static unsigned char read_high_memory(GB_gameboy_t *gb, unsigned short addr)
|
|||||||
if (!gb->is_cgb) {
|
if (!gb->is_cgb) {
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
unsigned char index_reg = (addr & 0xFF) - 1;
|
uint8_t index_reg = (addr & 0xFF) - 1;
|
||||||
return ((addr & 0xFF) == GB_IO_BGPD?
|
return ((addr & 0xFF) == GB_IO_BGPD?
|
||||||
gb->background_palletes_data :
|
gb->background_palletes_data :
|
||||||
gb->sprite_palletes_data)[gb->io_registers[index_reg] & 0x3F];
|
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:
|
default:
|
||||||
if ((addr & 0xFF) >= GB_IO_NR10 && (addr & 0xFF) <= GB_IO_WAV_END) {
|
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;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
@ -192,7 +192,7 @@ static GB_read_function_t * const read_map[] =
|
|||||||
read_high_memory, read_high_memory, /* EXXX FXXX */
|
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) {
|
if (addr < 0xFF00 && gb->dma_cycles) {
|
||||||
/* Todo: can we access IO registers during DMA? */
|
/* 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);
|
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;
|
if (gb->cartridge_type->mbc_type == NO_MBC) return;
|
||||||
switch (addr >> 12) {
|
switch (addr >> 12) {
|
||||||
@ -223,7 +223,7 @@ static void write_mbc(GB_gameboy_t *gb, unsigned short addr, unsigned char value
|
|||||||
case 3:
|
case 3:
|
||||||
if (gb->cartridge_type->mbc_type != MBC5) goto bank_low;
|
if (gb->cartridge_type->mbc_type != MBC5) goto bank_low;
|
||||||
if (value > 1) {
|
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;
|
gb->mbc_rom_bank = (gb->mbc_rom_bank & 0xFF) | value << 8;
|
||||||
break;
|
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) {
|
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;
|
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) {
|
if (gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
||||||
/* RTC write*/
|
/* 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;
|
unsigned int ram_index = (addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000;
|
||||||
if (!gb->mbc_ram_enable)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (ram_index >= gb->mbc_ram_size) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
gb->mbc_ram[(addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000] = value;
|
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;
|
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;
|
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) {
|
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;
|
gb->ram[addr & 0x0FFF] = value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -331,7 +331,7 @@ static void write_high_memory(GB_gameboy_t *gb, unsigned short addr, unsigned ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (addr < 0xFF00) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,19 +386,19 @@ static void write_high_memory(GB_gameboy_t *gb, unsigned short addr, unsigned ch
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case GB_IO_BIOS:
|
case GB_IO_BIOS:
|
||||||
gb->bios_finished = true;
|
gb->boot_rom_finished = true;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case GB_IO_DMG_EMULATION:
|
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. */
|
gb->cgb_mode = value != 4; /* The real "contents" of this register aren't quite known yet. */
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case GB_IO_DMA:
|
case GB_IO_DMA:
|
||||||
if (value <= 0xF1) { /* According to Pan Docs */
|
if (value <= 0xF1) { /* According to Pan Docs */
|
||||||
for (unsigned char i = 0xA0; i--;) {
|
for (uint8_t i = 0xA0; i--;) {
|
||||||
gb->oam[i] = read_memory(gb, (value << 8) + i);
|
gb->oam[i] = GB_read_memory(gb, (value << 8) + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* else { what? } */
|
/* else { what? } */
|
||||||
@ -433,11 +433,11 @@ static void write_high_memory(GB_gameboy_t *gb, unsigned short addr, unsigned ch
|
|||||||
if (!gb->is_cgb) {
|
if (!gb->is_cgb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unsigned char index_reg = (addr & 0xFF) - 1;
|
uint8_t index_reg = (addr & 0xFF) - 1;
|
||||||
((addr & 0xFF) == GB_IO_BGPD?
|
((addr & 0xFF) == GB_IO_BGPD?
|
||||||
gb->background_palletes_data :
|
gb->background_palletes_data :
|
||||||
gb->sprite_palletes_data)[gb->io_registers[index_reg] & 0x3F] = value;
|
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) {
|
if (gb->io_registers[index_reg] & 0x80) {
|
||||||
gb->io_registers[index_reg]++;
|
gb->io_registers[index_reg]++;
|
||||||
gb->io_registers[index_reg] |= 0x80;
|
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:
|
default:
|
||||||
if ((addr & 0xFF) >= GB_IO_NR10 && (addr & 0xFF) <= GB_IO_WAV_END) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (gb->io_registers[addr & 0xFF] != 0x37) {
|
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;
|
gb->io_registers[addr & 0xFF] = 0x37;
|
||||||
return;
|
return;
|
||||||
@ -510,7 +510,7 @@ static GB_write_function_t * const write_map[] =
|
|||||||
write_high_memory, write_high_memory, /* EXXX FXXX */
|
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) {
|
if (addr < 0xFF00 && gb->dma_cycles) {
|
||||||
/* Todo: can we access IO registers during DMA? */
|
/* 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);
|
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;
|
if (!gb->hdma_on) return;
|
||||||
while (gb->hdma_cycles >= 8) {
|
while (gb->hdma_cycles >= 8) {
|
||||||
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.
|
// This "normalizes" the dest to the CGB address space.
|
||||||
gb->hdma_current_dest &= 0x1fff;
|
gb->hdma_current_dest &= 0x1fff;
|
||||||
gb->hdma_current_dest |= 0x8000;
|
gb->hdma_current_dest |= 0x8000;
|
||||||
if ((gb->hdma_current_src < 0x8000 || (gb->hdma_current_src >= 0xa000 && gb->hdma_current_src < 0xe000))) {
|
if ((gb->hdma_current_src < 0x8000 || (gb->hdma_current_src >= 0xa000 && gb->hdma_current_src < 0xe000))) {
|
||||||
for (unsigned char i = 0; i < 0x10; i++) {
|
for (uint8_t i = 0; i < 0x10; i++) {
|
||||||
write_memory(gb, gb->hdma_current_dest + i, read_memory(gb, gb->hdma_current_src + i));
|
GB_write_memory(gb, gb->hdma_current_dest + i, GB_read_memory(gb, gb->hdma_current_src + i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
#define memory_h
|
#define memory_h
|
||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
|
|
||||||
unsigned char read_memory(GB_gameboy_t *gb, unsigned short addr);
|
uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr);
|
||||||
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);
|
||||||
void hdma_run(GB_gameboy_t *gb);
|
void GB_hdma_run(GB_gameboy_t *gb);
|
||||||
|
|
||||||
#endif /* memory_h */
|
#endif /* memory_h */
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
#define GB_PADDING(type, old_usage) type old_usage##__do_not_use
|
#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_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_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_GET_SECTION(gb, name) ((void*)&((gb)->name##_section_start))
|
||||||
|
|
||||||
|
#define GB_aligned_double __attribute__ ((aligned (8))) double
|
||||||
|
|
||||||
#endif /* save_struct_h */
|
#endif /* save_struct_h */
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "display.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
|
// Affected by speed boost
|
||||||
if (gb->dma_cycles > cycles){
|
if (gb->dma_cycles > cycles){
|
||||||
@ -24,16 +24,16 @@ void advance_cycles(GB_gameboy_t *gb, unsigned char cycles)
|
|||||||
gb->hdma_cycles += cycles;
|
gb->hdma_cycles += cycles;
|
||||||
gb->display_cycles += cycles;
|
gb->display_cycles += cycles;
|
||||||
gb->apu_cycles += cycles;
|
gb->apu_cycles += cycles;
|
||||||
hdma_run(gb);
|
GB_hdma_run(gb);
|
||||||
timers_run(gb);
|
GB_timers_run(gb);
|
||||||
apu_run(gb);
|
GB_apu_run(gb);
|
||||||
display_run(gb);
|
GB_display_run(gb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void timers_run(GB_gameboy_t *gb)
|
void GB_timers_run(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
/* Standard Timers */
|
/* 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) {
|
if (gb->div_cycles >= DIV_CYCLES) {
|
||||||
gb->div_cycles -= DIV_CYCLES;
|
gb->div_cycles -= DIV_CYCLES;
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
#define timing_h
|
#define timing_h
|
||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
|
|
||||||
void advance_cycles(GB_gameboy_t *gb, unsigned char cycles);
|
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles);
|
||||||
void timers_run(GB_gameboy_t *gb);
|
void GB_timers_run(GB_gameboy_t *gb);
|
||||||
#endif /* timing_h */
|
#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
|
#ifndef z80_cpu_h
|
||||||
#define z80_cpu_h
|
#define z80_cpu_h
|
||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
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);
|
||||||
void cpu_run(GB_gameboy_t *gb);
|
void GB_cpu_run(GB_gameboy_t *gb);
|
||||||
|
|
||||||
#endif /* z80_cpu_h */
|
#endif /* z80_cpu_h */
|
||||||
|
@ -5,161 +5,161 @@
|
|||||||
#include "gb.h"
|
#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)++;
|
(*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)++;
|
(*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)++;
|
(*pc)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *register_names[] = {"af", "bc", "de", "hl", "sp"};
|
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;
|
uint8_t register_id;
|
||||||
unsigned short value;
|
uint16_t value;
|
||||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||||
value = read_memory(gb, (*pc)++);
|
value = GB_read_memory(gb, (*pc)++);
|
||||||
value |= read_memory(gb, (*pc)++) << 8;
|
value |= GB_read_memory(gb, (*pc)++) << 8;
|
||||||
gb_log(gb, "LD %s, %04x\n", register_names[register_id], value);
|
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;
|
uint8_t register_id;
|
||||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||||
gb_log(gb, "LD [%s], a\n", register_names[register_id]);
|
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;
|
uint8_t register_id;
|
||||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||||
gb_log(gb, "INC %s\n", register_names[register_id]);
|
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)++;
|
(*pc)++;
|
||||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
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)++;
|
(*pc)++;
|
||||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
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)++;
|
(*pc)++;
|
||||||
register_id = ((opcode >> 4) + 1) & 0x03;
|
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)++;
|
(*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)++;
|
(*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){
|
static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc){
|
||||||
unsigned short addr;
|
uint16_t addr;
|
||||||
(*pc)++;
|
(*pc)++;
|
||||||
addr = read_memory(gb, (*pc)++);
|
addr = GB_read_memory(gb, (*pc)++);
|
||||||
addr |= read_memory(gb, (*pc)++) << 8;
|
addr |= GB_read_memory(gb, (*pc)++) << 8;
|
||||||
gb_log(gb, "LD [%04x], sp\n", addr);
|
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)++;
|
(*pc)++;
|
||||||
register_id = (opcode >> 4) + 1;
|
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;
|
uint8_t register_id;
|
||||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||||
gb_log(gb, "LD a, [%s]\n", register_names[register_id]);
|
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;
|
uint8_t register_id;
|
||||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1;
|
||||||
gb_log(gb, "DEC %s\n", register_names[register_id]);
|
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;
|
uint8_t register_id;
|
||||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
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;
|
uint8_t register_id;
|
||||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
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;
|
uint8_t register_id;
|
||||||
register_id = (read_memory(gb, (*pc)++) >> 4) + 1;
|
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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*pc)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *condition_code(unsigned char opcode)
|
static const char *condition_code(uint8_t opcode)
|
||||||
{
|
{
|
||||||
switch ((opcode >> 3) & 0x3) {
|
switch ((opcode >> 3) & 0x3) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -175,83 +175,83 @@ static const char *condition_code(unsigned char opcode)
|
|||||||
return NULL;
|
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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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;
|
uint8_t src_register_id;
|
||||||
unsigned char src_low;
|
uint8_t src_low;
|
||||||
src_register_id = ((opcode >> 1) + 1) & 3;
|
src_register_id = ((opcode >> 1) + 1) & 3;
|
||||||
src_low = !(opcode & 1);
|
src_low = !(opcode & 1);
|
||||||
if (src_register_id == GB_REGISTER_AF && src_low) {
|
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];
|
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;
|
uint8_t dst_register_id;
|
||||||
unsigned char dst_low;
|
uint8_t dst_low;
|
||||||
dst_register_id = ((opcode >> 4) + 1) & 3;
|
dst_register_id = ((opcode >> 4) + 1) & 3;
|
||||||
dst_low = opcode & 8;
|
dst_low = opcode & 8;
|
||||||
if (dst_register_id == GB_REGISTER_AF && dst_low) {
|
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];
|
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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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;
|
uint8_t register_id;
|
||||||
register_id = ((read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
register_id = ((GB_read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
||||||
gb_log(gb, "POP %s\n", register_names[register_id]);
|
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)++;
|
(*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;
|
(*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)++;
|
(*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;
|
(*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)++;
|
(*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;
|
(*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;
|
uint8_t register_id;
|
||||||
register_id = ((read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
register_id = ((GB_read_memory(gb, (*pc)++) >> 4) + 1) & 3;
|
||||||
gb_log(gb, "PUSH %s\n", register_names[register_id]);
|
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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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;
|
(*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)++;
|
(*pc)++;
|
||||||
unsigned char temp = read_memory(gb, (*pc)++);
|
uint8_t temp = GB_read_memory(gb, (*pc)++);
|
||||||
gb_log(gb, "LDH [%02x], a\n", temp);
|
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)++;
|
(*pc)++;
|
||||||
unsigned char temp = read_memory(gb, (*pc)++);
|
uint8_t temp = GB_read_memory(gb, (*pc)++);
|
||||||
gb_log(gb, "LDH a, [%02x]\n", temp);
|
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)++;
|
(*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)++;
|
(*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)++;
|
(*pc)++;
|
||||||
signed char temp = read_memory(gb, (*pc)++);
|
int8_t temp = GB_read_memory(gb, (*pc)++);
|
||||||
gb_log(gb, "ADD SP, %s%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp);
|
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)++;
|
(*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)++;
|
(*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;
|
(*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)++;
|
(*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;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*pc)++;
|
||||||
signed char temp = read_memory(gb, (*pc)++);
|
int8_t temp = GB_read_memory(gb, (*pc)++);
|
||||||
gb_log(gb, "LD hl, sp, %s%02x\n", temp < 0? "-" : "", temp < 0? -temp : temp);
|
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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*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)++;
|
(*pc)++;
|
||||||
bit = ((opcode >> 3) & 7);
|
bit = ((opcode >> 3) & 7);
|
||||||
if ((opcode & 0xC0) == 0x40) { /* Bit */
|
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 */
|
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 */
|
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) {
|
switch (opcode >> 3) {
|
||||||
case 0:
|
case 0:
|
||||||
rlc_r(gb, opcode, pc);
|
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,
|
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--) {
|
while (count--) {
|
||||||
gb_log(gb, "%s%04x: ", pc == gb->pc? "-> ": " ", pc);
|
GB_log(gb, "%s%04x: ", pc == gb->pc? "-> ": " ", pc);
|
||||||
unsigned char opcode = read_memory(gb, pc);
|
uint8_t opcode = GB_read_memory(gb, pc);
|
||||||
opcodes[opcode](gb, opcode, &pc);
|
opcodes[opcode](gb, opcode, &pc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
SDL/main.c
34
SDL/main.c
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
static bool running = false;
|
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;
|
static bool ctrl = false;
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
@ -74,9 +74,9 @@ void vblank(GB_gameboy_t *gb)
|
|||||||
{
|
{
|
||||||
SDL_Surface *screen = gb->user_data;
|
SDL_Surface *screen = gb->user_data;
|
||||||
SDL_Flip(screen);
|
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__
|
#ifdef __APPLE__
|
||||||
@ -123,7 +123,7 @@ static char *executable_relative_path(const char *filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static SDL_Surface *screen = NULL;
|
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);
|
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)
|
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__
|
#ifdef __APPLE__
|
||||||
@ -169,21 +169,21 @@ usage:
|
|||||||
|
|
||||||
|
|
||||||
if (dmg) {
|
if (dmg) {
|
||||||
gb_init(&gb);
|
GB_init(&gb);
|
||||||
if (gb_load_bios(&gb, executable_relative_path("dmg_boot.bin"))) {
|
if (GB_load_boot_rom(&gb, executable_relative_path("dmg_boot.bin"))) {
|
||||||
perror("Failed to load boot ROM");
|
perror("Failed to load boot ROM");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gb_init_cgb(&gb);
|
GB_init_cgb(&gb);
|
||||||
if (gb_load_bios(&gb, executable_relative_path("cgb_boot.bin"))) {
|
if (GB_load_boot_rom(&gb, executable_relative_path("cgb_boot.bin"))) {
|
||||||
perror("Failed to load boot ROM");
|
perror("Failed to load boot ROM");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb_load_rom(&gb, argv[argc - 1])) {
|
if (GB_load_rom(&gb, argv[argc - 1])) {
|
||||||
perror("Failed to load ROM");
|
perror("Failed to load ROM");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -198,10 +198,10 @@ usage:
|
|||||||
#endif
|
#endif
|
||||||
/* Configure Screen */
|
/* Configure Screen */
|
||||||
SDL_LockSurface(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.user_data = screen;
|
||||||
gb_set_pixels_output(&gb, screen->pixels);
|
GB_set_pixels_output(&gb, screen->pixels);
|
||||||
gb_set_rgb_encode_callback(&gb, rgb_encode);
|
GB_set_rgb_encode_callback(&gb, rgb_encode);
|
||||||
|
|
||||||
/* Configure battery */
|
/* Configure battery */
|
||||||
size_t path_length = strlen(argv[argc - 1]);
|
size_t path_length = strlen(argv[argc - 1]);
|
||||||
@ -220,7 +220,7 @@ usage:
|
|||||||
/* Add .sav */
|
/* Add .sav */
|
||||||
strcat(battery_save_path, ".sav");
|
strcat(battery_save_path, ".sav");
|
||||||
|
|
||||||
gb_load_battery(&gb, battery_save_path);
|
GB_load_battery(&gb, battery_save_path);
|
||||||
|
|
||||||
/* Configure Audio */
|
/* Configure Audio */
|
||||||
SDL_AudioSpec want, have;
|
SDL_AudioSpec want, have;
|
||||||
@ -232,7 +232,7 @@ usage:
|
|||||||
want.callback = audio_callback;
|
want.callback = audio_callback;
|
||||||
want.userdata = &gb;
|
want.userdata = &gb;
|
||||||
SDL_OpenAudio(&want, &have);
|
SDL_OpenAudio(&want, &have);
|
||||||
gb_set_sample_rate(&gb, 96000);
|
GB_set_sample_rate(&gb, 96000);
|
||||||
|
|
||||||
/* Start Audio */
|
/* Start Audio */
|
||||||
SDL_PauseAudio(0);
|
SDL_PauseAudio(0);
|
||||||
@ -240,11 +240,11 @@ usage:
|
|||||||
/* Run emulation */
|
/* Run emulation */
|
||||||
running = true;
|
running = true;
|
||||||
while (running) {
|
while (running) {
|
||||||
gb_run(&gb);
|
GB_run(&gb);
|
||||||
}
|
}
|
||||||
SDL_CloseAudio();
|
SDL_CloseAudio();
|
||||||
|
|
||||||
gb_save_battery(&gb, battery_save_path);
|
GB_save_battery(&gb, battery_save_path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user