diff --git a/Core/gb.c b/Core/gb.c index 2d5fff4..0049590 100755 --- a/Core/gb.c +++ b/Core/gb.c @@ -503,6 +503,35 @@ void GB_set_rumble_callback(GB_gameboy_t *gb, GB_rumble_callback_t callback) gb->rumble_callback = callback; } +void GB_set_serial_transfer_start_callback(GB_gameboy_t *gb, GB_serial_transfer_start_callback_t callback) +{ + gb->serial_transfer_start_callback = callback; +} + +void GB_set_serial_transfer_end_callback(GB_gameboy_t *gb, GB_serial_transfer_end_callback_t callback) +{ + gb->serial_transfer_end_callback = callback; +} + +uint8_t GB_serial_get_data(GB_gameboy_t *gb) +{ + if (gb->io_registers[GB_IO_SC] & 1) { + /* Internal Clock */ + GB_log(gb, "Serial read request while using internal clock. \n"); + return 0xFF; + } + return gb->io_registers[GB_IO_SB]; +} +void GB_serial_set_data(GB_gameboy_t *gb, uint8_t data) +{ + if (gb->io_registers[GB_IO_SC] & 1) { + /* Internal Clock */ + GB_log(gb, "Serial write request while using internal clock. \n"); + return; + } + gb->io_registers[GB_IO_SB] = data; +} + void GB_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate) { if (gb->audio_buffer) { diff --git a/Core/gb.h b/Core/gb.h index 9b1a64a..63ea824 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -162,6 +162,9 @@ typedef void (*GB_infrared_callback_t)(GB_gameboy_t *gb, bool on, long cycles_si typedef uint8_t (*GB_camera_get_pixel_callback_t)(GB_gameboy_t *gb, uint8_t x, uint8_t y); typedef void (*GB_camera_update_request_callback_t)(GB_gameboy_t *gb); typedef void (*GB_rumble_callback_t)(GB_gameboy_t *gb, bool rumble_on); +typedef void (*GB_serial_transfer_start_callback_t)(GB_gameboy_t *gb, uint8_t byte_to_send); +typedef uint8_t (*GB_serial_transfer_end_callback_t)(GB_gameboy_t *gb); + typedef struct { enum { @@ -418,7 +421,8 @@ typedef struct GB_gameboy_s { GB_camera_get_pixel_callback_t camera_get_pixel_callback; GB_camera_update_request_callback_t camera_update_request_callback; GB_rumble_callback_t rumble_callback; - + GB_serial_transfer_start_callback_t serial_transfer_start_callback; + GB_serial_transfer_end_callback_t serial_transfer_end_callback; /* IR */ long cycles_since_ir_change; long cycles_since_input_ir_change; @@ -497,4 +501,13 @@ void GB_set_infrared_callback(GB_gameboy_t *gb, GB_infrared_callback_t callback) void GB_set_infrared_input(GB_gameboy_t *gb, bool state); void GB_queue_infrared_input(GB_gameboy_t *gb, bool state, long cycles_after_previous_change); void GB_set_rumble_callback(GB_gameboy_t *gb, GB_rumble_callback_t callback); + +/* These APIs are used when using internal clock */ +void GB_set_serial_transfer_start_callback(GB_gameboy_t *gb, GB_serial_transfer_start_callback_t callback); +void GB_set_serial_transfer_end_callback(GB_gameboy_t *gb, GB_serial_transfer_end_callback_t callback); + +/* These APIs are used when using external clock */ +uint8_t GB_serial_get_data(GB_gameboy_t *gb); +void GB_serial_set_data(GB_gameboy_t *gb, uint8_t data); + #endif /* GB_h */ diff --git a/Core/memory.c b/Core/memory.c index 0ea1330..ecc9e54 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -576,6 +576,9 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) gb->io_registers[GB_IO_SC] = value | (~0x83); if ((value & 0x80) && (value & 0x1) ) { gb->serial_cycles = gb->cgb_mode && (value & 2)? 128 : 4096; + if (gb->serial_transfer_start_callback) { + gb->serial_transfer_start_callback(gb, gb->io_registers[GB_IO_SB]); + } } else { gb->serial_cycles = 0; diff --git a/Core/timing.c b/Core/timing.c index 0e6a2a2..c1f8ebc 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -45,7 +45,14 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) if (gb->serial_cycles <= cycles) { gb->serial_cycles = 0; gb->io_registers[GB_IO_SC] &= ~0x80; - gb->io_registers[GB_IO_SB] = 0xFF; + /* TODO: Does SB "update" bit by bit? */ + if (gb->serial_transfer_end_callback) { + gb->io_registers[GB_IO_SB] = gb->serial_transfer_end_callback(gb); + } + else { + gb->io_registers[GB_IO_SB] = 0xFF; + } + gb->io_registers[GB_IO_IF] |= 8; } else {