(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...)
This commit is contained in:
Fabio Priuli 2013-05-10 15:23:51 +00:00
parent 342b2024f2
commit 78b2889737
4 changed files with 358 additions and 207 deletions

View File

@ -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

View File

@ -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();
};

View File

@ -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 );
}

View File

@ -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 */