From 78b2889737c4cee7cb5dda6bb8d0df82d69673c3 Mon Sep 17 00:00:00 2001 From: Fabio Priuli Date: Fri, 10 May 2013 15:23:51 +0000 Subject: [PATCH] (MESS) gameboy/gbcolor: simplified video code by reducing the number of memory pointers used, and added support for save state registration. [Fabio Priuli] I haven't added the support_save flag yet because I'd like to receive some feedback from users (I have only tested 2 dozen of games, without issues, but there are thousands...) --- src/mess/drivers/gb.c | 1 + src/mess/includes/gb.h | 39 ++--- src/mess/machine/gb.c | 207 ++++++++++++++++----------- src/mess/video/gb.c | 318 +++++++++++++++++++++++++++-------------- 4 files changed, 358 insertions(+), 207 deletions(-) diff --git a/src/mess/drivers/gb.c b/src/mess/drivers/gb.c index 22eb3c6e957..f24bd6c2afd 100644 --- a/src/mess/drivers/gb.c +++ b/src/mess/drivers/gb.c @@ -736,6 +736,7 @@ static MACHINE_CONFIG_DERIVED( gbpocket, gameboy ) MCFG_LR35902_HALT_BUG MCFG_LR35902_RESET_VALUES(mgb_cpu_regs) + MCFG_MACHINE_START_OVERRIDE(gb_state, gbpocket) MCFG_MACHINE_RESET_OVERRIDE(gb_state, gbpocket) MCFG_PALETTE_INIT_OVERRIDE(gb_state,gbp) MACHINE_CONFIG_END diff --git a/src/mess/includes/gb.h b/src/mess/includes/gb.h index 3656e23bea6..4d21e9f596a 100644 --- a/src/mess/includes/gb.h +++ b/src/mess/includes/gb.h @@ -92,16 +92,16 @@ struct gb_lcd_t { emu_timer *lcd_timer; int gbc_mode; - memory_region *gb_vram; /* Pointer to VRAM */ - memory_region *gb_oam; /* Pointer to OAM memory */ - UINT8 *gb_vram_ptr; - UINT8 *gb_chrgen; /* Character generator */ - UINT8 *gb_bgdtab; /* Background character table */ - UINT8 *gb_wndtab; /* Window character table */ + UINT8 *gb_vram; // Pointer to VRAM + UINT8 *gb_oam; // Pointer to OAM memory UINT8 gb_tile_no_mod; - UINT8 *gbc_chrgen; /* CGB Character generator */ - UINT8 *gbc_bgdtab; /* CGB Background character table */ - UINT8 *gbc_wndtab; /* CGB Window character table */ + UINT32 gb_chrgen_offs; // GB Character generator + UINT32 gb_bgdtab_offs; // GB Background character table + UINT32 gb_wndtab_offs; // GB Window character table + UINT32 gbc_chrgen_offs; // CGB Character generator + UINT32 gbc_bgdtab_offs; // CGB Background character table + UINT32 gbc_wndtab_offs; // CGB Window character table + int gb_vram_bank; }; @@ -138,7 +138,7 @@ public: UINT8 m_reloading; /* Serial I/O related */ - UINT32 m_SIOCount; /* Serial I/O counter */ + UINT32 m_sio_count; /* Serial I/O counter */ emu_timer *m_gb_serial_timer; /* SGB variables */ @@ -154,13 +154,13 @@ public: UINT32 m_sgb_atf; /* CGB variables */ - UINT8 *m_GBC_RAMMap[8]; /* (CGB) Addresses of internal RAM banks */ - UINT8 m_GBC_RAMBank; /* (CGB) Current CGB RAM bank */ + UINT8 *m_gbc_rammap[8]; /* (CGB) Addresses of internal RAM banks */ + UINT8 m_gbc_rambank; /* (CGB) Current CGB RAM bank */ gb_lcd_t m_lcd; void (gb_state::*update_scanline) (); - bool m_bios_disable; + int m_bios_disable; bitmap_ind16 m_bitmap; DECLARE_WRITE8_MEMBER(gb_io_w); @@ -185,13 +185,12 @@ public: DECLARE_MACHINE_START(sgb); DECLARE_MACHINE_RESET(sgb); DECLARE_PALETTE_INIT(sgb); + DECLARE_MACHINE_START(gbpocket); DECLARE_MACHINE_RESET(gbpocket); DECLARE_PALETTE_INIT(gbp); DECLARE_MACHINE_START(gbc); DECLARE_MACHINE_RESET(gbc); DECLARE_PALETTE_INIT(gbc); - DECLARE_MACHINE_START(gb_video); - DECLARE_MACHINE_START(gbc_video); INTERRUPT_GEN_MEMBER(gb_scanline_interrupt); TIMER_CALLBACK_MEMBER(gb_serial_timer_proc); TIMER_CALLBACK_MEMBER(gb_video_init_vbl); @@ -228,11 +227,19 @@ protected: void sgb_update_scanline(); void cgb_update_sprites(); void cgb_update_scanline(); - void gb_video_reset( int mode ); + void gb_video_reset(int mode); + void gb_video_start(int mode); void gbc_hdma(UINT16 length); void gb_increment_scanline(); void gb_lcd_switch_on(); inline void gb_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color); + + void save_gb_base(); + void save_gb_video(); + void save_gbc_only(); + void save_sgb_only(); + void gb_videoptr_restore(); + void gbc_videoptr_restore(); }; diff --git a/src/mess/machine/gb.c b/src/mess/machine/gb.c index 0ac1b62689e..e2e14e37050 100644 --- a/src/mess/machine/gb.c +++ b/src/mess/machine/gb.c @@ -87,28 +87,6 @@ TODO: #include "audio/gb.h" #include "includes/gb.h" -/* Memory bank controller types */ -enum { - MBC_NONE=0, /* 32KB ROM - No memory bank controller */ - MBC_MBC1, /* ~2MB ROM, 8KB RAM -or- 512KB ROM, 32KB RAM */ - MBC_MBC2, /* 256KB ROM, 32KB RAM */ - MBC_MMM01, /* ?? ROM, ?? RAM */ - MBC_MBC3, /* 2MB ROM, 32KB RAM, RTC */ - MBC_MBC4, /* ?? ROM, ?? RAM */ - MBC_MBC5, /* 8MB ROM, 128KB RAM (32KB w/ Rumble) */ - MBC_TAMA5, /* ?? ROM ?? RAM - What is this? */ - MBC_HUC1, /* ?? ROM, ?? RAM - Hudson Soft Controller */ - MBC_HUC3, /* ?? ROM, ?? RAM - Hudson Soft Controller */ - MBC_MBC6, /* ?? ROM, 32KB SRAM */ - MBC_MBC7, /* ?? ROM, ?? RAM */ - MBC_WISDOM, /* ?? ROM, ?? RAM - Wisdom tree controller */ - MBC_MBC1_KOR, /* 1MB ROM, ?? RAM - Korean MBC1 variant */ - MBC_YONGYONG, /* ?? ROM, ?? RAM - Appears in Sonic 3D Blast 5 pirate */ - MBC_LASAMA, /* ?? ROM, ?? RAM - Appears in La Sa Ma */ - MBC_ATVRACIN, - MBC_MEGADUCK, /* MEGADUCK style banking */ - MBC_UNKNOWN, /* Unknown mapper */ -}; /* RAM layout defines */ #define CGB_START_VRAM_BANKS 0x0000 @@ -134,6 +112,51 @@ enum { /* #define V_BANK*/ /* Display bank switching debug information */ #endif +//------------------------- +// handle save state +//------------------------- + +void gb_state::save_gb_base() +{ + save_item(NAME(m_gb_io)); + save_item(NAME(m_divcount)); + save_item(NAME(m_shift)); + save_item(NAME(m_shift_cycles)); + save_item(NAME(m_triggering_irq)); + save_item(NAME(m_reloading)); + save_item(NAME(m_sio_count)); + save_item(NAME(m_bios_disable)); +} + +void gb_state::save_gbc_only() +{ + save_item(NAME(m_gbc_rambank)); +} + +void gb_state::save_sgb_only() +{ + save_item(NAME(m_sgb_pal_data)); + save_item(NAME(m_sgb_pal)); + save_item(NAME(m_sgb_tile_map)); + save_item(NAME(m_sgb_window_mask)); + save_item(NAME(m_sgb_pal_data)); + save_item(NAME(m_sgb_atf_data)); + save_item(NAME(m_sgb_packets)); + save_item(NAME(m_sgb_bitcount)); + save_item(NAME(m_sgb_bytecount)); + save_item(NAME(m_sgb_start)); + save_item(NAME(m_sgb_rest)); + save_item(NAME(m_sgb_controller_no)); + save_item(NAME(m_sgb_controller_mode)); + save_item(NAME(m_sgb_data)); + save_item(NAME(m_sgb_atf)); + + save_pointer(NAME(m_sgb_tile_data), 0x2000); + for (int i = 0; i < 20; i++) + save_item(NAME(m_sgb_pal_map[i])); +} + + void gb_state::gb_init_regs() { /* Initialize the registers */ @@ -163,7 +186,18 @@ MACHINE_START_MEMBER(gb_state,gb) m_gb_serial_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_serial_timer_proc),this)); m_gb_serial_timer->enable( 0 ); - MACHINE_START_CALL_MEMBER( gb_video ); + save_gb_base(); + gb_video_start(GB_VIDEO_DMG); +} + +MACHINE_START_MEMBER(gb_state,gbpocket) +{ + /* Allocate the serial timer, and disable it */ + m_gb_serial_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_serial_timer_proc),this)); + m_gb_serial_timer->enable( 0 ); + + save_gb_base(); + gb_video_start(GB_VIDEO_MGB); } MACHINE_START_MEMBER(gb_state,gbc) @@ -172,52 +206,38 @@ MACHINE_START_MEMBER(gb_state,gbc) m_gb_serial_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_serial_timer_proc),this)); m_gb_serial_timer->enable( 0 ); - MACHINE_START_CALL_MEMBER( gbc_video ); -} + for (int i = 0; i < 8; i++) + m_gbc_rammap[i] = m_ram->pointer() + CGB_START_RAM_BANKS + i * 0x1000; -MACHINE_RESET_MEMBER(gb_state,gb) -{ - gb_init(); - - gb_video_reset(GB_VIDEO_DMG); - - /* Enable BIOS rom */ - m_bios_disable = FALSE; - - m_divcount = 0x0004; + save_gb_base(); + save_gbc_only(); + gb_video_start(GB_VIDEO_CGB); } MACHINE_START_MEMBER(gb_state,sgb) { m_sgb_packets = -1; - m_sgb_tile_data = auto_alloc_array_clear(machine(), UINT8, 0x2000 ); + m_sgb_tile_data = auto_alloc_array_clear(machine(), UINT8, 0x2000); /* Allocate the serial timer, and disable it */ m_gb_serial_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_serial_timer_proc),this)); m_gb_serial_timer->enable( 0 ); - MACHINE_START_CALL_MEMBER( gb_video ); + save_gb_base(); + save_sgb_only(); + gb_video_start(GB_VIDEO_SGB); } -MACHINE_RESET_MEMBER(gb_state,sgb) +MACHINE_RESET_MEMBER(gb_state,gb) { gb_init(); - - gb_video_reset(GB_VIDEO_SGB); - - gb_init_regs(); - - + + gb_video_reset(GB_VIDEO_DMG); + /* Enable BIOS rom */ - m_bios_disable = FALSE; - - memset(m_sgb_tile_data, 0, 0x2000); - - m_sgb_window_mask = 0; - memset(m_sgb_pal_map, 0, sizeof(m_sgb_pal_map)); - memset(m_sgb_atf_data, 0, sizeof(m_sgb_atf_data)); - + m_bios_disable = 0; + m_divcount = 0x0004; } @@ -229,7 +249,7 @@ MACHINE_RESET_MEMBER(gb_state,gbpocket) gb_init_regs(); - m_bios_disable = TRUE; + m_bios_disable = 0; /* Initialize the Sound registers */ gb_sound_w(m_custom, generic_space(), 0x16,0x80); @@ -241,8 +261,6 @@ MACHINE_RESET_MEMBER(gb_state,gbpocket) MACHINE_RESET_MEMBER(gb_state,gbc) { - int ii; - gb_init(); gb_video_reset( GB_VIDEO_CGB ); @@ -250,16 +268,34 @@ MACHINE_RESET_MEMBER(gb_state,gbc) gb_init_regs(); /* Enable BIOS rom */ - m_bios_disable = FALSE; + m_bios_disable = 0; - /* Allocate memory for internal ram */ - for (ii = 0; ii < 8; ii++) - { - m_GBC_RAMMap[ii] = m_ram->pointer() + CGB_START_RAM_BANKS + ii * 0x1000; - memset(m_GBC_RAMMap[ii], 0, 0x1000); - } + for (int i = 0; i < 8; i++) + memset(m_gbc_rammap[i], 0, 0x1000); } +MACHINE_RESET_MEMBER(gb_state,sgb) +{ + gb_init(); + + gb_video_reset(GB_VIDEO_SGB); + + gb_init_regs(); + + + /* Enable BIOS rom */ + m_bios_disable = 0; + + memset(m_sgb_tile_data, 0, 0x2000); + + m_sgb_window_mask = 0; + memset(m_sgb_pal_map, 0, sizeof(m_sgb_pal_map)); + memset(m_sgb_atf_data, 0, sizeof(m_sgb_atf_data)); + + m_divcount = 0x0004; +} + + WRITE8_MEMBER(gb_state::gb_io_w) { static const UINT8 timer_shifts[4] = {10, 4, 6, 8}; @@ -281,11 +317,11 @@ WRITE8_MEMBER(gb_state::gb_io_w) case 0x00: case 0x01: case 0x80: /* enabled & external clock */ - m_SIOCount = 0; + m_sio_count = 0; break; case 0x81: /* enabled & internal clock */ SIODATA = 0xFF; - m_SIOCount = 8; + m_sio_count = 8; m_gb_serial_timer->adjust(m_maincpu->cycles_to_attotime(512), 0, m_maincpu->cycles_to_attotime(512)); m_gb_serial_timer->enable( 1 ); break; @@ -339,7 +375,7 @@ WRITE8_MEMBER(gb_state::gb_io2_w) if (offset == 0x10) { /* disable BIOS ROM */ - m_bios_disable = TRUE; + m_bios_disable = 1; //printf("here again?\n"); } else @@ -731,7 +767,7 @@ WRITE8_MEMBER(gb_state::sgb_io_w) for( I = 0; I < 2048; I++ ) { - col = ( m_lcd.gb_vram_ptr[ 0x0800 + (I*2) + 1 ] << 8 ) | m_lcd.gb_vram_ptr[ 0x0800 + (I*2) ]; + col = (m_lcd.gb_vram[0x0800 + (I*2) + 1] << 8) | m_lcd.gb_vram[0x0800 + (I*2)]; m_sgb_pal_data[I] = col; } } @@ -761,10 +797,10 @@ WRITE8_MEMBER(gb_state::sgb_io_w) /* Not Implemented */ break; case 0x13: /* CHR_TRN */ - if( sgb_data[1] & 0x1 ) - memcpy( m_sgb_tile_data + 4096, m_lcd.gb_vram_ptr + 0x0800, 4096 ); + if (sgb_data[1] & 0x1) + memcpy(m_sgb_tile_data + 4096, m_lcd.gb_vram + 0x0800, 4096); else - memcpy( m_sgb_tile_data, m_lcd.gb_vram_ptr + 0x0800, 4096 ); + memcpy(m_sgb_tile_data, m_lcd.gb_vram + 0x0800, 4096); break; case 0x14: /* PCT_TRN */ { @@ -772,26 +808,26 @@ WRITE8_MEMBER(gb_state::sgb_io_w) UINT16 col; if (m_cartslot && m_cartslot->get_sgb_hack()) { - memcpy( m_sgb_tile_map, m_lcd.gb_vram_ptr + 0x1000, 2048 ); + memcpy(m_sgb_tile_map, m_lcd.gb_vram + 0x1000, 2048); for( I = 0; I < 64; I++ ) { - col = ( m_lcd.gb_vram_ptr[ 0x0800 + (I*2) + 1 ] << 8 ) | m_lcd.gb_vram_ptr[ 0x0800 + (I*2) ]; + col = (m_lcd.gb_vram[0x0800 + (I*2) + 1 ] << 8) | m_lcd.gb_vram[0x0800 + (I*2)]; m_sgb_pal[SGB_BORDER_PAL_OFFSET + I] = col; } } else /* Do things normally */ { - memcpy( m_sgb_tile_map, m_lcd.gb_vram_ptr + 0x0800, 2048 ); + memcpy(m_sgb_tile_map, m_lcd.gb_vram + 0x0800, 2048); for( I = 0; I < 64; I++ ) { - col = ( m_lcd.gb_vram_ptr[ 0x1000 + (I*2) + 1 ] << 8 ) | m_lcd.gb_vram_ptr[ 0x1000 + (I*2) ]; + col = (m_lcd.gb_vram[0x1000 + (I*2) + 1] << 8) | m_lcd.gb_vram[0x1000 + (I*2)]; m_sgb_pal[SGB_BORDER_PAL_OFFSET + I] = col; } } } break; case 0x15: /* ATTR_TRN */ - memcpy( m_sgb_atf_data, m_lcd.gb_vram_ptr + 0x0800, 4050 ); + memcpy( m_sgb_atf_data, m_lcd.gb_vram + 0x0800, 4050 ); break; case 0x16: /* ATTR_SET */ { @@ -923,9 +959,9 @@ TIMER_CALLBACK_MEMBER(gb_state::gb_serial_timer_proc) /* Shift in a received bit */ SIODATA = (SIODATA << 1) | 0x01; /* Decrement number of handled bits */ - m_SIOCount--; + m_sio_count--; /* If all bits done, stop timer and trigger interrupt */ - if ( ! m_SIOCount ) + if ( ! m_sio_count ) { SIOCONT &= 0x7F; m_gb_serial_timer->enable( 0 ); @@ -994,15 +1030,15 @@ WRITE8_MEMBER(gb_state::gbc_io2_w) m_maincpu->set_speed(data); return; case 0x10: /* BFF - Bios disable */ - m_bios_disable = TRUE; + m_bios_disable = 1; return; case 0x16: /* RP - Infrared port */ break; case 0x30: /* SVBK - RAM bank select */ - m_GBC_RAMBank = data & 0x7; - if (!m_GBC_RAMBank) - m_GBC_RAMBank = 1; - m_rambank->set_base(m_GBC_RAMMap[m_GBC_RAMBank]); + m_gbc_rambank = data & 0x7; + if (!m_gbc_rambank) + m_gbc_rambank = 1; + m_rambank->set_base(m_gbc_rammap[m_gbc_rambank]); break; default: break; @@ -1019,7 +1055,7 @@ READ8_MEMBER(gb_state::gbc_io2_r) case 0x16: /* RP - Infrared port */ break; case 0x30: /* SVBK - RAM bank select */ - return m_GBC_RAMBank; + return m_gbc_rambank; default: break; } @@ -1037,8 +1073,9 @@ MACHINE_START_MEMBER(megaduck_state,megaduck) /* Allocate the serial timer, and disable it */ m_gb_serial_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_serial_timer_proc),this)); m_gb_serial_timer->enable( 0 ); - - MACHINE_START_CALL_MEMBER( gb_video ); + + save_gb_base(); + gb_video_start(GB_VIDEO_DMG); } MACHINE_RESET_MEMBER(megaduck_state,megaduck) @@ -1046,7 +1083,7 @@ MACHINE_RESET_MEMBER(megaduck_state,megaduck) /* We may have to add some more stuff here, if not then it can be merged back into gb */ gb_init(); - m_bios_disable = TRUE; + m_bios_disable = 1; gb_video_reset( GB_VIDEO_DMG ); } diff --git a/src/mess/video/gb.c b/src/mess/video/gb.c index d8b6e83d3c1..8f50a2ab262 100644 --- a/src/mess/video/gb.c +++ b/src/mess/video/gb.c @@ -154,7 +154,7 @@ inline void gb_state::gb_plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 c void gb_state::gb_select_sprites() { int i, /*yindex,*/ line, height; - UINT8 *oam = m_lcd.gb_oam->base() + 39 * 4; + UINT8 *oam = m_lcd.gb_oam + 39 * 4; m_lcd.sprCount = 0; @@ -211,8 +211,8 @@ void gb_state::gb_update_sprites() yindex = m_lcd.current_line; line = m_lcd.current_line + 16; - oam = m_lcd.gb_oam->base() + 39 * 4; - vram = m_lcd.gb_vram->base(); + oam = m_lcd.gb_oam + 39 * 4; + vram = m_lcd.gb_vram; for (i = 39; i >= 0; i--) { /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */ @@ -304,8 +304,8 @@ void gb_state::gb_update_scanline() if ( m_lcd.layer[0].enabled ) { m_lcd.layer[0].bgline = ( SCROLLY + m_lcd.current_line ) & 0xFF; - m_lcd.layer[0].bg_map = m_lcd.gb_bgdtab; - m_lcd.layer[0].bg_tiles = m_lcd.gb_chrgen; + m_lcd.layer[0].bg_map = m_lcd.gb_vram + m_lcd.gb_bgdtab_offs; + m_lcd.layer[0].bg_tiles = m_lcd.gb_vram + m_lcd.gb_chrgen_offs; m_lcd.layer[0].xindex = SCROLLX >> 3; m_lcd.layer[0].xshift = SCROLLX & 7; m_lcd.layer[0].xstart = 0; @@ -321,8 +321,8 @@ void gb_state::gb_update_scanline() xpos = 0; m_lcd.layer[1].bgline = m_lcd.window_lines_drawn; - m_lcd.layer[1].bg_map = m_lcd.gb_wndtab; - m_lcd.layer[1].bg_tiles = m_lcd.gb_chrgen; + m_lcd.layer[1].bg_map = m_lcd.gb_vram + m_lcd.gb_wndtab_offs; + m_lcd.layer[1].bg_tiles = m_lcd.gb_vram + m_lcd.gb_chrgen_offs; m_lcd.layer[1].xindex = 0; m_lcd.layer[1].xshift = 0; m_lcd.layer[1].xstart = xpos; @@ -448,8 +448,8 @@ void gb_state::sgb_update_sprites() yindex = m_lcd.current_line + SGB_YOFFSET; line = m_lcd.current_line + 16; - oam = m_lcd.gb_oam->base() + 39 * 4; - vram = m_lcd.gb_vram->base(); + oam = m_lcd.gb_oam + 39 * 4; + vram = m_lcd.gb_vram; for (i = 39; i >= 0; i--) { /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */ @@ -617,8 +617,8 @@ void gb_state::sgb_update_scanline() if ( m_lcd.layer[0].enabled ) { m_lcd.layer[0].bgline = ( SCROLLY + m_lcd.current_line ) & 0xFF; - m_lcd.layer[0].bg_map = m_lcd.gb_bgdtab; - m_lcd.layer[0].bg_tiles = m_lcd.gb_chrgen; + m_lcd.layer[0].bg_map = m_lcd.gb_vram + m_lcd.gb_bgdtab_offs; + m_lcd.layer[0].bg_tiles = m_lcd.gb_vram + m_lcd.gb_chrgen_offs; m_lcd.layer[0].xindex = SCROLLX >> 3; m_lcd.layer[0].xshift = SCROLLX & 7; m_lcd.layer[0].xstart = 0; @@ -635,8 +635,8 @@ void gb_state::sgb_update_scanline() xpos = 0; m_lcd.layer[1].bgline = m_lcd.window_lines_drawn; - m_lcd.layer[1].bg_map = m_lcd.gb_wndtab; - m_lcd.layer[1].bg_tiles = m_lcd.gb_chrgen; + m_lcd.layer[1].bg_map = m_lcd.gb_vram + m_lcd.gb_wndtab_offs; + m_lcd.layer[1].bg_tiles = m_lcd.gb_vram + m_lcd.gb_chrgen_offs; m_lcd.layer[1].xindex = 0; m_lcd.layer[1].xshift = 0; m_lcd.layer[1].xstart = xpos; @@ -791,7 +791,7 @@ void gb_state::cgb_update_sprites() yindex = m_lcd.current_line; line = m_lcd.current_line + 16; - oam = m_lcd.gb_oam->base() + 39 * 4; + oam = m_lcd.gb_oam + 39 * 4; for (i = 39; i >= 0; i--) { /* if sprite is on current line && x-coordinate && x-coordinate is < 168 */ @@ -809,11 +809,11 @@ void gb_state::cgb_update_sprites() xindex = oam[1] - 8; if (oam[3] & 0x40) /* flip y ? */ { - data = *((UINT16 *) &m_lcd.gb_vram->base()[ ((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2]); + data = *((UINT16 *) &m_lcd.gb_vram[((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (height - 1 - line + oam[0]) * 2]); } else { - data = *((UINT16 *) &m_lcd.gb_vram->base()[ ((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (line - oam[0]) * 2]); + data = *((UINT16 *) &m_lcd.gb_vram[((oam[3] & 0x8)<<10) + (oam[2] & tilemask) * 16 + (line - oam[0]) * 2]); } #ifndef LSB_FIRST data = (data << 8) | (data >> 8); @@ -908,8 +908,8 @@ void gb_state::cgb_update_scanline() if ( m_lcd.layer[0].enabled ) { m_lcd.layer[0].bgline = ( SCROLLY + m_lcd.current_line ) & 0xFF; - m_lcd.layer[0].bg_map = m_lcd.gb_bgdtab; - m_lcd.layer[0].gbc_map = m_lcd.gbc_bgdtab; + m_lcd.layer[0].bg_map = m_lcd.gb_vram + m_lcd.gb_bgdtab_offs; + m_lcd.layer[0].gbc_map = m_lcd.gb_vram + m_lcd.gbc_bgdtab_offs; m_lcd.layer[0].xindex = SCROLLX >> 3; m_lcd.layer[0].xshift = SCROLLX & 7; m_lcd.layer[0].xstart = 0; @@ -926,8 +926,8 @@ void gb_state::cgb_update_scanline() xpos = 0; m_lcd.layer[1].bgline = m_lcd.window_lines_drawn; - m_lcd.layer[1].bg_map = m_lcd.gb_wndtab; - m_lcd.layer[1].gbc_map = m_lcd.gbc_wndtab; + m_lcd.layer[1].bg_map = m_lcd.gb_vram + m_lcd.gb_wndtab_offs; + m_lcd.layer[1].gbc_map = m_lcd.gb_vram + m_lcd.gbc_wndtab_offs; m_lcd.layer[1].xindex = 0; m_lcd.layer[1].xshift = 0; m_lcd.layer[1].xstart = xpos; @@ -959,7 +959,7 @@ void gb_state::cgb_update_scanline() } map = m_lcd.layer[l].bg_map + ( ( m_lcd.layer[l].bgline << 2 ) & 0x3E0 ); gbcmap = m_lcd.layer[l].gbc_map + ( ( m_lcd.layer[l].bgline << 2 ) & 0x3E0 ); - tiles = ( gbcmap[ m_lcd.layer[l].xindex ] & 0x08 ) ? m_lcd.gbc_chrgen : m_lcd.gb_chrgen; + tiles = (gbcmap[m_lcd.layer[l].xindex] & 0x08) ? (m_lcd.gb_vram + m_lcd.gbc_chrgen_offs) : (m_lcd.gb_vram + m_lcd.gb_chrgen_offs); /* Check for vertical flip */ if ( gbcmap[ m_lcd.layer[l].xindex ] & 0x40 ) @@ -1024,7 +1024,7 @@ void gb_state::cgb_update_scanline() m_lcd.layer[l].xindex = ( m_lcd.layer[l].xindex + 1 ) & 31; m_lcd.layer[l].xshift = 0; - tiles = ( gbcmap[ m_lcd.layer[l].xindex ] & 0x08 ) ? m_lcd.gbc_chrgen : m_lcd.gb_chrgen; + tiles = (gbcmap[m_lcd.layer[l].xindex] & 0x08) ? (m_lcd.gb_vram + m_lcd.gbc_chrgen_offs) : (m_lcd.gb_vram + m_lcd.gb_chrgen_offs); /* Check for vertical flip */ if ( gbcmap[ m_lcd.layer[l].xindex ] & 0x40 ) @@ -1183,18 +1183,129 @@ TIMER_CALLBACK_MEMBER(gb_state::gb_video_init_vbl) m_maincpu->set_input_line(VBL_INT, ASSERT_LINE ); } -MACHINE_START_MEMBER(gb_state,gb_video) +void gb_state::gb_videoptr_restore() { - m_lcd.lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_lcd_timer_proc),this)); - machine().primary_screen->register_screen_bitmap(m_bitmap); + m_lcd.layer[0].bg_map = m_lcd.gb_vram + m_lcd.gb_bgdtab_offs; + m_lcd.layer[0].bg_tiles = m_lcd.gb_vram + m_lcd.gb_chrgen_offs; + m_lcd.layer[1].bg_map = m_lcd.gb_vram + m_lcd.gb_wndtab_offs; + m_lcd.layer[1].bg_tiles = m_lcd.gb_vram + m_lcd.gb_chrgen_offs; } -MACHINE_START_MEMBER(gb_state,gbc_video) +void gb_state::gbc_videoptr_restore() { - m_lcd.lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gbc_lcd_timer_proc),this)); - machine().primary_screen->register_screen_bitmap(m_bitmap); + m_lcd.layer[0].bg_map = m_lcd.gb_vram + m_lcd.gb_bgdtab_offs; + m_lcd.layer[0].gbc_map = m_lcd.gb_vram + m_lcd.gbc_bgdtab_offs; + m_lcd.layer[1].bg_map = m_lcd.gb_vram + m_lcd.gb_wndtab_offs; + m_lcd.layer[1].gbc_map = m_lcd.gb_vram + m_lcd.gbc_wndtab_offs; } +void gb_state::save_gb_video() +{ + save_item(NAME(m_lcd.window_lines_drawn)); + save_item(NAME(m_lcd.gb_vid_regs)); + save_item(NAME(m_lcd.bg_zbuf)); + + save_item(NAME(m_lcd.cgb_bpal)); + save_item(NAME(m_lcd.cgb_spal)); + + save_item(NAME(m_lcd.gb_bpal)); + save_item(NAME(m_lcd.gb_spal0)); + save_item(NAME(m_lcd.gb_spal1)); + + save_item(NAME(m_lcd.current_line)); + save_item(NAME(m_lcd.cmp_line)); + save_item(NAME(m_lcd.sprCount)); + save_item(NAME(m_lcd.sprite)); + save_item(NAME(m_lcd.previous_line)); + save_item(NAME(m_lcd.start_x)); + save_item(NAME(m_lcd.end_x)); + save_item(NAME(m_lcd.mode)); + save_item(NAME(m_lcd.state)); + save_item(NAME(m_lcd.lcd_irq_line)); + save_item(NAME(m_lcd.triggering_line_irq)); + save_item(NAME(m_lcd.line_irq)); + save_item(NAME(m_lcd.triggering_mode_irq)); + save_item(NAME(m_lcd.mode_irq)); + save_item(NAME(m_lcd.delayed_line_irq)); + save_item(NAME(m_lcd.sprite_cycles)); + save_item(NAME(m_lcd.scrollx_adjust)); + save_item(NAME(m_lcd.oam_locked)); + save_item(NAME(m_lcd.vram_locked)); + save_item(NAME(m_lcd.pal_locked)); + save_item(NAME(m_lcd.hdma_enabled)); + save_item(NAME(m_lcd.hdma_possible)); + save_item(NAME(m_lcd.gbc_mode)); + save_item(NAME(m_lcd.gb_tile_no_mod)); + save_item(NAME(m_lcd.gb_vram_bank)); + + save_item(NAME(m_lcd.gb_chrgen_offs)); + save_item(NAME(m_lcd.gb_bgdtab_offs)); + save_item(NAME(m_lcd.gb_wndtab_offs)); + save_item(NAME(m_lcd.gbc_chrgen_offs)); + save_item(NAME(m_lcd.gbc_bgdtab_offs)); + save_item(NAME(m_lcd.gbc_wndtab_offs)); + + save_item(NAME(m_lcd.layer[0].enabled)); + save_item(NAME(m_lcd.layer[0].xindex)); + save_item(NAME(m_lcd.layer[0].xshift)); + save_item(NAME(m_lcd.layer[0].xstart)); + save_item(NAME(m_lcd.layer[0].xend)); + save_item(NAME(m_lcd.layer[0].bgline)); + save_item(NAME(m_lcd.layer[1].enabled)); + save_item(NAME(m_lcd.layer[1].xindex)); + save_item(NAME(m_lcd.layer[1].xshift)); + save_item(NAME(m_lcd.layer[1].xstart)); + save_item(NAME(m_lcd.layer[1].xend)); + save_item(NAME(m_lcd.layer[1].bgline)); +} + +void gb_state::gb_video_start( int mode ) +{ + int vram_size = (mode == GB_VIDEO_CGB) ? 0x4000 : 0x2000; + + machine().primary_screen->register_screen_bitmap(m_bitmap); + m_lcd.gb_vram = auto_alloc_array_clear(machine(), UINT8, vram_size); + m_lcd.gb_oam = auto_alloc_array_clear(machine(), UINT8, 0x100); + + save_pointer(NAME(m_lcd.gb_vram), vram_size); + save_pointer(NAME(m_lcd.gb_oam), 0x100); + save_gb_video(); + + if (mode == GB_VIDEO_CGB) + { + m_lcd.lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gbc_lcd_timer_proc),this)); + machine().save().register_postload(save_prepost_delegate(FUNC(gb_state::gbc_videoptr_restore), this)); + } + else + { + m_lcd.lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gb_state::gb_lcd_timer_proc),this)); + machine().save().register_postload(save_prepost_delegate(FUNC(gb_state::gb_videoptr_restore), this)); + } + + switch (mode) + { + case GB_VIDEO_DMG: + memcpy(m_lcd.gb_oam, dmg_oam_fingerprint, 0x100); + break; + case GB_VIDEO_MGB: + /* Initialize part of VRAM. This code must be deleted when we have added the bios dump */ + for (int i = 1; i < 0x0d; i++) + { + m_lcd.gb_vram[0x1903 + i] = i; + m_lcd.gb_vram[0x1923 + i] = i + 0x0C; + } + m_lcd.gb_vram[0x1910] = 0x19; + memcpy(m_lcd.gb_oam, mgb_oam_fingerprint, 0x100); + break; + case GB_VIDEO_SGB: + break; + case GB_VIDEO_CGB: + memcpy(m_lcd.gb_oam, cgb_oam_fingerprint, 0x100); + break; + } +} + + UINT32 gb_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); @@ -1203,34 +1314,50 @@ UINT32 gb_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, cons void gb_state::gb_video_reset( int mode ) { - int i; - int vram_size = 0x2000; address_space &space = m_maincpu->space(AS_PROGRAM); - emu_timer *old_timer = m_lcd.lcd_timer; - memset( &m_lcd, 0, sizeof(m_lcd) ); - m_lcd.lcd_timer = old_timer; + m_lcd.window_lines_drawn = 0; + + m_lcd.current_line = 0; + m_lcd.cmp_line = 0; + m_lcd.sprCount = 0; + m_lcd.previous_line = 0; + m_lcd.start_x = 0; + m_lcd.end_x = 0; + m_lcd.mode = 0; + m_lcd.state = 0; + m_lcd.lcd_irq_line = 0; + m_lcd.triggering_line_irq = 0; + m_lcd.line_irq = 0; + m_lcd.triggering_mode_irq = 0; + m_lcd.mode_irq = 0; + m_lcd.delayed_line_irq = 0; + m_lcd.sprite_cycles = 0; + m_lcd.scrollx_adjust = 0; + m_lcd.oam_locked = 0; + m_lcd.vram_locked = 0; + m_lcd.pal_locked = 0; + m_lcd.gbc_mode = 0; + m_lcd.gb_tile_no_mod = 0; + m_lcd.gb_vram_bank = 0; + + m_lcd.gb_chrgen_offs = 0; + m_lcd.gb_bgdtab_offs = 0x1c00; + m_lcd.gb_wndtab_offs = 0x1c00; + + memset(&m_lcd.gb_vid_regs, 0, sizeof(m_lcd.gb_vid_regs)); + memset(&m_lcd.bg_zbuf, 0, sizeof(m_lcd.bg_zbuf)); + memset(&m_lcd.cgb_bpal, 0, sizeof(m_lcd.cgb_bpal)); + memset(&m_lcd.cgb_spal, 0, sizeof(m_lcd.cgb_spal)); + memset(&m_lcd.sprite, 0, sizeof(m_lcd.sprite)); + memset(&m_lcd.layer[0], 0, sizeof(m_lcd.layer[0])); + memset(&m_lcd.layer[1], 0, sizeof(m_lcd.layer[1])); - if (mode == GB_VIDEO_CGB) vram_size = 0x4000; + // specific reg initialization + m_lcd.gb_vid_regs[0x06] = 0xff; - /* free regions if already allocated */ - if (memregion("gfx1")->base()) machine().memory().region_free(":gfx1"); - if (memregion("gfx2")->base()) machine().memory().region_free(":gfx2"); - - m_lcd.gb_vram = machine().memory().region_alloc(":gfx1", vram_size, 1, ENDIANNESS_LITTLE ); - m_lcd.gb_oam = machine().memory().region_alloc(":gfx2", 0x100, 1, ENDIANNESS_LITTLE ); - memset( m_lcd.gb_vram->base(), 0, vram_size ); - - m_lcd.gb_vram_ptr = m_lcd.gb_vram->base(); - m_lcd.gb_chrgen = m_lcd.gb_vram->base(); - m_lcd.gb_bgdtab = m_lcd.gb_vram->base() + 0x1C00; - m_lcd.gb_wndtab = m_lcd.gb_vram->base() + 0x1C00; - - m_lcd.gb_vid_regs[0x06] = 0xFF; - for( i = 0x0c; i < _NR_GB_VID_REGS; i++ ) - { - m_lcd.gb_vid_regs[i] = 0xFF; - } + for (int i = 0x0c; i < _NR_GB_VID_REGS; i++) + m_lcd.gb_vid_regs[i] = 0xff; LCDSTAT = 0x80; LCDCONT = 0x00; /* Video hardware is turned off at boot time */ @@ -1239,11 +1366,9 @@ void gb_state::gb_video_reset( int mode ) SPR0PAL = SPR1PAL = 0xFF; WNDPOSX = WNDPOSY = 0x00; - /* Initialize palette arrays */ - for( i = 0; i < 4; i++ ) - { + // Initialize palette arrays + for (int i = 0; i < 4; i++) m_lcd.gb_bpal[i] = m_lcd.gb_spal0[i] = m_lcd.gb_spal1[i] = i; - } switch( mode ) { @@ -1252,55 +1377,38 @@ void gb_state::gb_video_reset( int mode ) /* set the scanline update function */ update_scanline = &gb_state::gb_update_scanline; - - memcpy( m_lcd.gb_oam->base(), dmg_oam_fingerprint, 0x100 ); - break; + case GB_VIDEO_MGB: /* set the scanline update function */ update_scanline = &gb_state::gb_update_scanline; - /* Initialize part of VRAM. This code must be deleted when we have added the bios dump */ - for( i = 1; i < 0x0D; i++ ) - { - m_lcd.gb_vram->base()[ 0x1903 + i ] = i; - m_lcd.gb_vram->base()[ 0x1923 + i ] = i + 0x0C; - } - m_lcd.gb_vram->base()[ 0x1910 ] = 0x19; - - - memcpy( m_lcd.gb_oam->base(), mgb_oam_fingerprint, 0x100 ); - /* Make sure the VBlank interrupt is set when the first instruction gets executed */ machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(1), timer_expired_delegate(FUNC(gb_state::gb_video_init_vbl),this)); /* Initialize some video registers */ - gb_video_w( space, 0x0, 0x91 ); /* LCDCONT */ - gb_video_w( space, 0x7, 0xFC ); /* BGRDPAL */ - gb_video_w( space, 0x8, 0xFC ); /* SPR0PAL */ - gb_video_w( space, 0x9, 0xFC ); /* SPR1PAL */ + gb_video_w(space, 0x0, 0x91); /* LCDCONT */ + gb_video_w(space, 0x7, 0xFC); /* BGRDPAL */ + gb_video_w(space, 0x8, 0xFC); /* SPR0PAL */ + gb_video_w(space, 0x9, 0xFC); /* SPR1PAL */ CURLINE = m_lcd.current_line = 0; LCDSTAT = ( LCDSTAT & 0xF8 ) | 0x05; m_lcd.mode = 1; m_lcd.lcd_timer->adjust(m_maincpu->cycles_to_attotime(60), GB_LCD_STATE_LY00_M0); - break; + case GB_VIDEO_SGB: /* set the scanline update function */ update_scanline = &gb_state::sgb_update_scanline; - break; case GB_VIDEO_CGB: /* set the scanline update function */ update_scanline = &gb_state::cgb_update_scanline; - memcpy( m_lcd.gb_oam->base(), cgb_oam_fingerprint, 0x100 ); - - m_lcd.gb_chrgen = m_lcd.gb_vram->base(); - m_lcd.gbc_chrgen = m_lcd.gb_vram->base() + 0x2000; - m_lcd.gb_bgdtab = m_lcd.gb_wndtab = m_lcd.gb_vram->base() + 0x1C00; - m_lcd.gbc_bgdtab = m_lcd.gbc_wndtab = m_lcd.gb_vram->base() + 0x3C00; + m_lcd.gbc_chrgen_offs = 0x2000; + m_lcd.gbc_bgdtab_offs = 0x3c00; + m_lcd.gbc_wndtab_offs = 0x3c00; /* HDMA disabled */ m_lcd.hdma_enabled = 0; @@ -1958,30 +2066,28 @@ READ8_MEMBER(gb_state::gb_video_r) READ8_MEMBER(gb_state::gb_vram_r) { - return ( m_lcd.vram_locked == LOCKED ) ? 0xFF : m_lcd.gb_vram_ptr[offset]; + return (m_lcd.vram_locked == LOCKED) ? 0xff : m_lcd.gb_vram[offset + (m_lcd.gb_vram_bank * 0x2000)]; } WRITE8_MEMBER(gb_state::gb_vram_w) { - if ( m_lcd.vram_locked == LOCKED ) - { + if (m_lcd.vram_locked == LOCKED) return; - } - m_lcd.gb_vram_ptr[offset] = data; + + m_lcd.gb_vram[offset + (m_lcd.gb_vram_bank * 0x2000)] = data; } READ8_MEMBER(gb_state::gb_oam_r) { - return ( m_lcd.oam_locked == LOCKED ) ? 0xFF : m_lcd.gb_oam->base()[offset]; + return (m_lcd.oam_locked == LOCKED) ? 0xff : m_lcd.gb_oam[offset]; } WRITE8_MEMBER(gb_state::gb_oam_w) { - if ( m_lcd.oam_locked == LOCKED || offset >= 0xa0 ) - { + if (m_lcd.oam_locked == LOCKED || offset >= 0xa0) return; - } - m_lcd.gb_oam->base()[offset] = data; + + m_lcd.gb_oam[offset] = data; } WRITE8_MEMBER(gb_state::gb_video_w) @@ -1989,12 +2095,12 @@ WRITE8_MEMBER(gb_state::gb_video_w) switch (offset) { case 0x00: /* LCDC - LCD Control */ - m_lcd.gb_chrgen = m_lcd.gb_vram->base() + ((data & 0x10) ? 0x0000 : 0x0800); + m_lcd.gb_chrgen_offs = (data & 0x10) ? 0x0000 : 0x0800; m_lcd.gb_tile_no_mod = (data & 0x10) ? 0x00 : 0x80; - m_lcd.gb_bgdtab = m_lcd.gb_vram->base() + ((data & 0x08) ? 0x1C00 : 0x1800 ); - m_lcd.gb_wndtab = m_lcd.gb_vram->base() + ((data & 0x40) ? 0x1C00 : 0x1800 ); + m_lcd.gb_bgdtab_offs = (data & 0x08) ? 0x1c00 : 0x1800; + m_lcd.gb_wndtab_offs = (data & 0x40) ? 0x1c00 : 0x1800; /* if LCD controller is switched off, set STAT and LY to 00 */ - if ( ! ( data & 0x80 ) ) + if (!(data & 0x80)) { LCDSTAT &= ~0x03; CURLINE = 0; @@ -2002,7 +2108,7 @@ WRITE8_MEMBER(gb_state::gb_video_w) m_lcd.vram_locked = UNLOCKED; } /* If LCD is being switched on */ - if ( !( LCDCONT & 0x80 ) && ( data & 0x80 ) ) + if (!(LCDCONT & 0x80) && (data & 0x80)) { gb_lcd_switch_on(); } @@ -2077,7 +2183,7 @@ WRITE8_MEMBER(gb_state::gb_video_w) break; case 0x06: /* DMA - DMA Transfer and Start Address */ { - UINT8 *P = m_lcd.gb_oam->base(); + UINT8 *P = m_lcd.gb_oam; offset = (UINT16) data << 8; for (data = 0; data < 0xA0; data++) *P++ = space.read_byte(offset++); @@ -2113,7 +2219,7 @@ WRITE8_MEMBER(gb_state::gb_video_w) default: /* Unknown register, no change */ return; } - m_lcd.gb_vid_regs[ offset ] = data; + m_lcd.gb_vid_regs[offset] = data; } READ8_MEMBER(gb_state::gbc_video_r) @@ -2141,13 +2247,13 @@ WRITE8_MEMBER(gb_state::gbc_video_w) switch( offset ) { case 0x00: /* LCDC - LCD Control */ - m_lcd.gb_chrgen = m_lcd.gb_vram->base() + ((data & 0x10) ? 0x0000 : 0x0800); - m_lcd.gbc_chrgen = m_lcd.gb_vram->base() + ((data & 0x10) ? 0x2000 : 0x2800); + m_lcd.gb_chrgen_offs = (data & 0x10) ? 0x0000 : 0x0800; + m_lcd.gbc_chrgen_offs = (data & 0x10) ? 0x2000 : 0x2800; m_lcd.gb_tile_no_mod = (data & 0x10) ? 0x00 : 0x80; - m_lcd.gb_bgdtab = m_lcd.gb_vram->base() + ((data & 0x08) ? 0x1C00 : 0x1800); - m_lcd.gbc_bgdtab = m_lcd.gb_vram->base() + ((data & 0x08) ? 0x3C00 : 0x3800); - m_lcd.gb_wndtab = m_lcd.gb_vram->base() + ((data & 0x40) ? 0x1C00 : 0x1800); - m_lcd.gbc_wndtab = m_lcd.gb_vram->base() + ((data & 0x40) ? 0x3C00 : 0x3800); + m_lcd.gb_bgdtab_offs = (data & 0x08) ? 0x1c00 : 0x1800; + m_lcd.gbc_bgdtab_offs = (data & 0x08) ? 0x3c00 : 0x3800; + m_lcd.gb_wndtab_offs = (data & 0x40) ? 0x1c00 : 0x1800; + m_lcd.gbc_wndtab_offs = (data & 0x40) ? 0x3c00 : 0x3800; /* if LCD controller is switched off, set STAT to 00 */ if ( ! ( data & 0x80 ) ) { @@ -2234,7 +2340,7 @@ WRITE8_MEMBER(gb_state::gbc_video_w) logerror( "Write to undocumented register: %X = %X\n", offset, data ); break; case 0x0F: /* VBK - VRAM bank select */ - m_lcd.gb_vram_ptr = m_lcd.gb_vram->base() + ( data & 0x01 ) * 0x2000; + m_lcd.gb_vram_bank = data & 0x01; data |= 0xFE; break; case 0x11: /* HDMA1 - HBL General DMA - Source High */