mirror of https://github.com/LIJI32/SameBoy.git
parent
f0959d4e70
commit
52ab200544
|
@ -56,7 +56,16 @@ enum model {
|
|||
};
|
||||
|
||||
@interface Document ()
|
||||
@property GBAudioClient *audioClient;
|
||||
@end
|
||||
|
||||
@implementation Document
|
||||
{
|
||||
GB_gameboy_t gb;
|
||||
volatile bool running;
|
||||
volatile bool stopping;
|
||||
NSConditionLock *has_debugger_input;
|
||||
NSMutableArray *debugger_input_queue;
|
||||
|
||||
NSMutableAttributedString *pending_console_output;
|
||||
NSRecursiveLock *console_output_lock;
|
||||
|
@ -66,10 +75,10 @@ enum model {
|
|||
bool fullScreen;
|
||||
bool in_sync_input;
|
||||
HFController *hex_controller;
|
||||
|
||||
|
||||
NSString *lastConsoleInput;
|
||||
HFLineCountingRepresenter *lineRep;
|
||||
|
||||
|
||||
CVImageBufferRef cameraImage;
|
||||
AVCaptureSession *cameraSession;
|
||||
AVCaptureConnection *cameraConnection;
|
||||
|
@ -111,25 +120,6 @@ enum model {
|
|||
void (^ volatile _pendingAtomicBlock)();
|
||||
}
|
||||
|
||||
@property GBAudioClient *audioClient;
|
||||
- (void) vblank;
|
||||
- (void) log: (const char *) log withAttributes: (GB_log_attributes) attributes;
|
||||
- (char *) getDebuggerInput;
|
||||
- (char *) getAsyncDebuggerInput;
|
||||
- (void) cameraRequestUpdate;
|
||||
- (uint8_t) cameraGetPixelAtX:(uint8_t)x andY:(uint8_t)y;
|
||||
- (void) printImage:(uint32_t *)image height:(unsigned) height
|
||||
topMargin:(unsigned) topMargin bottomMargin: (unsigned) bottomMargin
|
||||
exposure:(unsigned) exposure;
|
||||
- (void) gotNewSample:(GB_sample_t *)sample;
|
||||
- (void) rumbleChanged:(double)amp;
|
||||
- (void) loadBootROM:(GB_boot_rom_t)type;
|
||||
- (void)linkCableBitStart:(bool)bit;
|
||||
- (bool)linkCableBitEnd;
|
||||
- (void)infraredStateChanged:(bool)state;
|
||||
|
||||
@end
|
||||
|
||||
static void boot_rom_load(GB_gameboy_t *gb, GB_boot_rom_t type)
|
||||
{
|
||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||
|
@ -139,7 +129,7 @@ static void boot_rom_load(GB_gameboy_t *gb, GB_boot_rom_t type)
|
|||
static void vblank(GB_gameboy_t *gb, GB_vblank_type_t type)
|
||||
{
|
||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||
[self vblank];
|
||||
[self vblankWithType:type];
|
||||
}
|
||||
|
||||
static void consoleLog(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes)
|
||||
|
@ -227,15 +217,6 @@ static void infraredStateChanged(GB_gameboy_t *gb, bool on)
|
|||
}
|
||||
|
||||
|
||||
@implementation Document
|
||||
{
|
||||
GB_gameboy_t gb;
|
||||
volatile bool running;
|
||||
volatile bool stopping;
|
||||
NSConditionLock *has_debugger_input;
|
||||
NSMutableArray *debugger_input_queue;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
|
@ -341,26 +322,29 @@ static void infraredStateChanged(GB_gameboy_t *gb, bool on)
|
|||
self.osdView.usesSGBScale = GB_get_screen_width(&gb) == 256;
|
||||
}
|
||||
|
||||
- (void) vblank
|
||||
- (void) vblankWithType:(GB_vblank_type_t)type
|
||||
{
|
||||
if (_gbsVisualizer) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_gbsVisualizer setNeedsDisplay:true];
|
||||
});
|
||||
}
|
||||
[self.view flip];
|
||||
if (borderModeChanged) {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
size_t previous_width = GB_get_screen_width(&gb);
|
||||
GB_set_border_mode(&gb, (GB_border_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBBorderMode"]);
|
||||
if (GB_get_screen_width(&gb) != previous_width) {
|
||||
[self.view screenSizeChanged];
|
||||
[self updateMinSize];
|
||||
}
|
||||
});
|
||||
borderModeChanged = false;
|
||||
if (type != GB_VBLANK_TYPE_REPEAT) {
|
||||
[self.view flip];
|
||||
if (borderModeChanged) {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
size_t previous_width = GB_get_screen_width(&gb);
|
||||
GB_set_border_mode(&gb, (GB_border_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBBorderMode"]);
|
||||
if (GB_get_screen_width(&gb) != previous_width) {
|
||||
[self.view screenSizeChanged];
|
||||
[self updateMinSize];
|
||||
}
|
||||
});
|
||||
borderModeChanged = false;
|
||||
}
|
||||
GB_set_pixels_output(&gb, self.view.pixels);
|
||||
}
|
||||
GB_set_pixels_output(&gb, self.view.pixels);
|
||||
|
||||
if (self.vramWindow.isVisible) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.view.mouseHidingEnabled = (self.mainWindow.styleMask & NSWindowStyleMaskFullScreen) != 0;
|
||||
|
|
|
@ -107,7 +107,7 @@ typedef struct __attribute__((packed)) {
|
|||
} object_t;
|
||||
|
||||
void GB_display_vblank(GB_gameboy_t *gb, GB_vblank_type_t type)
|
||||
{
|
||||
{
|
||||
gb->vblank_just_occured = true;
|
||||
gb->cycles_since_vblank_callback = 0;
|
||||
gb->lcd_disabled_outside_of_vblank = false;
|
||||
|
@ -123,9 +123,19 @@ void GB_display_vblank(GB_gameboy_t *gb, GB_vblank_type_t type)
|
|||
}
|
||||
}
|
||||
|
||||
if (GB_is_cgb(gb) && type == GB_VBLANK_TYPE_NORMAL_FRAME && gb->frame_repeat_countdown > 0 && gb->frame_skip_state == GB_FRAMESKIP_LCD_TURNED_ON) {
|
||||
GB_handle_rumble(gb);
|
||||
|
||||
if (gb->vblank_callback) {
|
||||
gb->vblank_callback(gb, GB_VBLANK_TYPE_REPEAT);
|
||||
}
|
||||
GB_timing_sync(gb);
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_ppu_stopped = !GB_is_cgb(gb) && gb->stopped && gb->io_registers[GB_IO_LCDC] & 0x80;
|
||||
|
||||
if (!gb->disable_rendering && ((!(gb->io_registers[GB_IO_LCDC] & 0x80) || is_ppu_stopped) || gb->cgb_repeated_a_frame || gb->frame_skip_state == GB_FRAMESKIP_LCD_TURNED_ON)) {
|
||||
if (!gb->disable_rendering && ((!(gb->io_registers[GB_IO_LCDC] & 0x80) || is_ppu_stopped) || gb->frame_skip_state == GB_FRAMESKIP_LCD_TURNED_ON)) {
|
||||
/* LCD is off, set screen to white or black (if LCD is on in stop mode) */
|
||||
if (!GB_is_sgb(gb)) {
|
||||
uint32_t color = 0;
|
||||
|
@ -313,9 +323,9 @@ uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color, bool for_border)
|
|||
new_b = new_b * 15 / 16 + (r + g ) / 32;
|
||||
|
||||
if (agb) {
|
||||
new_r = new_r * (224 - 40) / 255 + 20;
|
||||
new_g = new_g * (220 - 36) / 255 + 18;
|
||||
new_b = new_b * (216 - 32) / 255 + 16;
|
||||
new_r = new_r * (224 - 20) / 255 + 20;
|
||||
new_g = new_g * (220 - 18) / 255 + 18;
|
||||
new_b = new_b * (216 - 16) / 255 + 16;
|
||||
}
|
||||
else {
|
||||
new_r = new_r * (220 - 40) / 255 + 40;
|
||||
|
@ -1398,6 +1408,13 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
|
|||
gb->mode_for_interrupt = 3;
|
||||
}
|
||||
gb->cycles_since_vblank_callback += cycles / 2;
|
||||
|
||||
if (cycles < gb->frame_repeat_countdown) {
|
||||
gb->frame_repeat_countdown -= cycles;
|
||||
}
|
||||
else {
|
||||
gb->frame_repeat_countdown = 0;
|
||||
}
|
||||
|
||||
/* The PPU does not advance while in STOP mode on the DMG */
|
||||
if (gb->stopped && !GB_is_cgb(gb)) {
|
||||
|
@ -1457,7 +1474,6 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
|
|||
GB_SLEEP(gb, display, 1, LCDC_PERIOD - gb->cycles_since_vblank_callback);
|
||||
}
|
||||
GB_display_vblank(gb, GB_VBLANK_TYPE_LCD_OFF);
|
||||
gb->cgb_repeated_a_frame = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1987,14 +2003,14 @@ skip_slow_mode_3:
|
|||
if (gb->frame_skip_state == GB_FRAMESKIP_LCD_TURNED_ON) {
|
||||
if (GB_is_cgb(gb)) {
|
||||
GB_display_vblank(gb, GB_VBLANK_TYPE_NORMAL_FRAME);
|
||||
gb->frame_skip_state = GB_FRAMESKIP_FIRST_FRAME_SKIPPED;
|
||||
gb->frame_skip_state = GB_FRAMESKIP_FIRST_FRAME_RENDERED;
|
||||
}
|
||||
else {
|
||||
if (!GB_is_sgb(gb) || gb->current_lcd_line < LINES) {
|
||||
gb->is_odd_frame ^= true;
|
||||
GB_display_vblank(gb, GB_VBLANK_TYPE_NORMAL_FRAME);
|
||||
}
|
||||
gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED;
|
||||
gb->frame_skip_state = GB_FRAMESKIP_FIRST_FRAME_RENDERED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2002,16 +2018,19 @@ skip_slow_mode_3:
|
|||
gb->is_odd_frame ^= true;
|
||||
GB_display_vblank(gb, GB_VBLANK_TYPE_NORMAL_FRAME);
|
||||
}
|
||||
if (gb->frame_skip_state == GB_FRAMESKIP_FIRST_FRAME_SKIPPED) {
|
||||
gb->cgb_repeated_a_frame = true;
|
||||
gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED;
|
||||
}
|
||||
else {
|
||||
gb->cgb_repeated_a_frame = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 3640 is just a few cycles less than 4 lines, no clue where the
|
||||
AGB constant comes from (These are measured and confirmed) */
|
||||
gb->frame_repeat_countdown = LINES * LINE_LENGTH * 2 + (gb->model > GB_MODEL_CGB_E? 5982 : 3640); // 8MHz units
|
||||
if (gb->display_cycles < gb->frame_repeat_countdown) {
|
||||
gb->frame_repeat_countdown -= gb->display_cycles;
|
||||
}
|
||||
else {
|
||||
gb->frame_repeat_countdown = 0;
|
||||
}
|
||||
|
||||
GB_SLEEP(gb, display, 13, LINE_LENGTH - 5);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ typedef enum {
|
|||
GB_VBLANK_TYPE_NORMAL_FRAME, // An actual Vblank-triggered frame
|
||||
GB_VBLANK_TYPE_LCD_OFF, // An artificial frame pushed while the LCD was off
|
||||
GB_VBLANK_TYPE_ARTIFICIAL, // An artificial frame pushed for some other reason
|
||||
GB_VBLANK_TYPE_REPEAT, // A frame that would not render on actual hardware, but the screen should retain the previous frame
|
||||
} GB_vblank_type_t;
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
|
|
10
Core/gb.c
10
Core/gb.c
|
@ -1183,6 +1183,11 @@ void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output)
|
|||
gb->screen = output;
|
||||
}
|
||||
|
||||
uint32_t *GB_get_pixels_output(GB_gameboy_t *gb)
|
||||
{
|
||||
return gb->screen;
|
||||
}
|
||||
|
||||
void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback)
|
||||
{
|
||||
gb->vblank_callback = callback;
|
||||
|
@ -1220,6 +1225,11 @@ void GB_set_lcd_line_callback(GB_gameboy_t *gb, GB_lcd_line_callback_t callback)
|
|||
gb->lcd_line_callback = callback;
|
||||
}
|
||||
|
||||
void GB_set_lcd_status_callback(GB_gameboy_t *gb, GB_lcd_status_callback_t callback)
|
||||
{
|
||||
gb->lcd_status_callback = callback;
|
||||
}
|
||||
|
||||
const GB_palette_t GB_PALETTE_GREY = {{{0x00, 0x00, 0x00}, {0x55, 0x55, 0x55}, {0xAA, 0xAA, 0xAA}, {0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF}}};
|
||||
const GB_palette_t GB_PALETTE_DMG = {{{0x08, 0x18, 0x10}, {0x39, 0x61, 0x39}, {0x84, 0xA5, 0x63}, {0xC6, 0xDE, 0x8C}, {0xD2, 0xE6, 0xA6}}};
|
||||
const GB_palette_t GB_PALETTE_MGB = {{{0x07, 0x10, 0x0E}, {0x3A, 0x4C, 0x3A}, {0x81, 0x8D, 0x66}, {0xC2, 0xCE, 0x93}, {0xCF, 0xDA, 0xAC}}};
|
||||
|
|
12
Core/gb.h
12
Core/gb.h
|
@ -304,6 +304,7 @@ typedef void (*GB_boot_rom_load_callback_t)(GB_gameboy_t *gb, GB_boot_rom_t type
|
|||
|
||||
typedef void (*GB_execution_callback_t)(GB_gameboy_t *gb, uint16_t address, uint8_t opcode);
|
||||
typedef void (*GB_lcd_line_callback_t)(GB_gameboy_t *gb, uint8_t line);
|
||||
typedef void (*GB_lcd_status_callback_t)(GB_gameboy_t *gb, bool on);
|
||||
|
||||
struct GB_breakpoint_s;
|
||||
struct GB_watchpoint_s;
|
||||
|
@ -600,8 +601,8 @@ struct GB_gameboy_internal_s {
|
|||
GB_FRAMESKIP_LCD_TURNED_ON, // On a DMG, the LCD renders a blank screen during this state,
|
||||
// on a CGB, the previous frame is repeated (which might be
|
||||
// blank if the LCD was off for more than a few cycles)
|
||||
GB_FRAMESKIP_FIRST_FRAME_SKIPPED, // This state is 'skipped' when emulating a DMG
|
||||
GB_FRAMESKIP_SECOND_FRAME_RENDERED,
|
||||
GB_FRAMESKIP_FIRST_FRAME_SKIPPED__DEPRECATED,
|
||||
GB_FRAMESKIP_FIRST_FRAME_RENDERED,
|
||||
} frame_skip_state;
|
||||
bool oam_read_blocked;
|
||||
bool vram_read_blocked;
|
||||
|
@ -650,9 +651,10 @@ struct GB_gameboy_internal_s {
|
|||
bool is_odd_frame;
|
||||
uint16_t last_tile_data_address;
|
||||
uint16_t last_tile_index_address;
|
||||
bool cgb_repeated_a_frame;
|
||||
GB_PADDING(bool, cgb_repeated_a_frame);
|
||||
uint8_t data_for_sel_glitch;
|
||||
bool delayed_glitch_hblank_interrupt;
|
||||
uint32_t frame_repeat_countdown;
|
||||
)
|
||||
|
||||
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
||||
|
@ -732,7 +734,7 @@ struct GB_gameboy_internal_s {
|
|||
GB_workboy_get_time_callback workboy_get_time_callback;
|
||||
GB_execution_callback_t execution_callback;
|
||||
GB_lcd_line_callback_t lcd_line_callback;
|
||||
|
||||
GB_lcd_status_callback_t lcd_status_callback;
|
||||
/*** Debugger ***/
|
||||
volatile bool debug_stopped, debug_disable;
|
||||
bool debug_fin_command, debug_next_command;
|
||||
|
@ -894,6 +896,7 @@ void GB_log(GB_gameboy_t *gb, const char *fmt, ...) __printflike(2, 3);
|
|||
void GB_attributed_log(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, ...) __printflike(3, 4);
|
||||
|
||||
void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output);
|
||||
uint32_t *GB_get_pixels_output(GB_gameboy_t *gb);
|
||||
void GB_set_border_mode(GB_gameboy_t *gb, GB_border_mode_t border_mode);
|
||||
|
||||
void GB_set_infrared_input(GB_gameboy_t *gb, bool state);
|
||||
|
@ -911,6 +914,7 @@ void GB_set_boot_rom_load_callback(GB_gameboy_t *gb, GB_boot_rom_load_callback_t
|
|||
|
||||
void GB_set_execution_callback(GB_gameboy_t *gb, GB_execution_callback_t callback);
|
||||
void GB_set_lcd_line_callback(GB_gameboy_t *gb, GB_lcd_line_callback_t callback);
|
||||
void GB_set_lcd_status_callback(GB_gameboy_t *gb, GB_lcd_status_callback_t callback);
|
||||
|
||||
void GB_set_palette(GB_gameboy_t *gb, const GB_palette_t *palette);
|
||||
const GB_palette_t *GB_get_palette(GB_gameboy_t *gb);
|
||||
|
|
|
@ -1440,6 +1440,9 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||
case GB_IO_LCDC:
|
||||
if ((value & 0x80) && !(gb->io_registers[GB_IO_LCDC] & 0x80)) {
|
||||
// LCD turned on
|
||||
if (gb->lcd_status_callback) {
|
||||
gb->lcd_status_callback(gb, true);
|
||||
}
|
||||
if (!gb->lcd_disabled_outside_of_vblank &&
|
||||
(gb->cycles_since_vblank_callback > 10 * 456 || GB_is_sgb(gb))) {
|
||||
// Trigger a vblank here so we don't exceed LCDC_PERIOD
|
||||
|
@ -1451,15 +1454,18 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||
gb->double_speed_alignment = 0;
|
||||
gb->cycles_for_line = 0;
|
||||
if (GB_is_sgb(gb)) {
|
||||
gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED;
|
||||
gb->frame_skip_state = GB_FRAMESKIP_FIRST_FRAME_RENDERED;
|
||||
}
|
||||
else if (gb->frame_skip_state == GB_FRAMESKIP_SECOND_FRAME_RENDERED) {
|
||||
else {
|
||||
gb->frame_skip_state = GB_FRAMESKIP_LCD_TURNED_ON;
|
||||
}
|
||||
GB_timing_sync(gb);
|
||||
}
|
||||
else if (!(value & 0x80) && (gb->io_registers[GB_IO_LCDC] & 0x80)) {
|
||||
/* Sync after turning off LCD */
|
||||
if (gb->lcd_status_callback) {
|
||||
gb->lcd_status_callback(gb, false);
|
||||
}
|
||||
gb->double_speed_alignment = 0;
|
||||
GB_timing_sync(gb);
|
||||
GB_lcd_off(gb);
|
||||
|
|
20
SDL/main.c
20
SDL/main.c
|
@ -509,15 +509,17 @@ static void vblank(GB_gameboy_t *gb, GB_vblank_type_t type)
|
|||
true);
|
||||
osd_countdown--;
|
||||
}
|
||||
if (configuration.blending_mode) {
|
||||
render_texture(active_pixel_buffer, previous_pixel_buffer);
|
||||
uint32_t *temp = active_pixel_buffer;
|
||||
active_pixel_buffer = previous_pixel_buffer;
|
||||
previous_pixel_buffer = temp;
|
||||
GB_set_pixels_output(gb, active_pixel_buffer);
|
||||
}
|
||||
else {
|
||||
render_texture(active_pixel_buffer, NULL);
|
||||
if (type != GB_VBLANK_TYPE_REPEAT) {
|
||||
if (configuration.blending_mode) {
|
||||
render_texture(active_pixel_buffer, previous_pixel_buffer);
|
||||
uint32_t *temp = active_pixel_buffer;
|
||||
active_pixel_buffer = previous_pixel_buffer;
|
||||
previous_pixel_buffer = temp;
|
||||
GB_set_pixels_output(gb, active_pixel_buffer);
|
||||
}
|
||||
else {
|
||||
render_texture(active_pixel_buffer, NULL);
|
||||
}
|
||||
}
|
||||
do_rewind = rewind_down;
|
||||
handle_events(gb);
|
||||
|
|
|
@ -99,6 +99,8 @@ static bool auto_sgb_enabled[2] = {
|
|||
|
||||
static uint32_t *frame_buf = NULL;
|
||||
static uint32_t *frame_buf_copy = NULL;
|
||||
static uint32_t retained_frame_1[256 * 224];
|
||||
static uint32_t retained_frame_2[256 * 224];
|
||||
static struct retro_log_callback logging;
|
||||
static retro_log_printf_t log_cb;
|
||||
|
||||
|
@ -250,14 +252,42 @@ static void audio_callback(GB_gameboy_t *gb, GB_sample_t *sample)
|
|||
|
||||
static void vblank1(GB_gameboy_t *gb, GB_vblank_type_t type)
|
||||
{
|
||||
if (type == GB_VBLANK_TYPE_REPEAT) {
|
||||
memcpy(GB_get_pixels_output(gb),
|
||||
retained_frame_1,
|
||||
GB_get_screen_width(gb) * GB_get_screen_height(gb) * sizeof(uint32_t));
|
||||
}
|
||||
vblank1_occurred = true;
|
||||
}
|
||||
|
||||
static void vblank2(GB_gameboy_t *gb, GB_vblank_type_t type)
|
||||
{
|
||||
if (type == GB_VBLANK_TYPE_REPEAT) {
|
||||
memcpy(GB_get_pixels_output(gb),
|
||||
retained_frame_2,
|
||||
GB_get_screen_width(gb) * GB_get_screen_height(gb) * sizeof(uint32_t));
|
||||
}
|
||||
vblank2_occurred = true;
|
||||
}
|
||||
|
||||
static void lcd_status_change_1(GB_gameboy_t *gb, bool on)
|
||||
{
|
||||
if (!on) {
|
||||
memcpy(retained_frame_1,
|
||||
GB_get_pixels_output(gb),
|
||||
GB_get_screen_width(gb) * GB_get_screen_height(gb) * sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
static void lcd_status_change_2(GB_gameboy_t *gb, bool on)
|
||||
{
|
||||
if (!on) {
|
||||
memcpy(retained_frame_2,
|
||||
GB_get_pixels_output(gb),
|
||||
GB_get_screen_width(gb) * GB_get_screen_height(gb) * sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
static bool bit_to_send1 = true, bit_to_send2 = true;
|
||||
|
||||
static void serial_start1(GB_gameboy_t *gb, bool bit_received)
|
||||
|
@ -627,8 +657,10 @@ static void init_for_current_model(unsigned id)
|
|||
|
||||
/* todo: attempt to make these more generic */
|
||||
GB_set_vblank_callback(&gameboy[0], (GB_vblank_callback_t) vblank1);
|
||||
GB_set_lcd_status_callback(&gameboy[0], lcd_status_change_1);
|
||||
if (emulated_devices == 2) {
|
||||
GB_set_vblank_callback(&gameboy[1], (GB_vblank_callback_t) vblank2);
|
||||
GB_set_lcd_status_callback(&gameboy[2], lcd_status_change_2);
|
||||
if (link_cable_emulation) {
|
||||
set_link_cable_state(true);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue