Sent: Wednesday, August 12, 2009 4:27 PM
To: submit@mamedev.org
Subject: twin16 update
Hello,

Attached is an update for the Konami twin16 driver, see diff for details.
Functional changes:
- improved sprite status register, this fixed the rogue sprites problem in devilw
- added fround coin counters
- lowered k007232 volume
- added savestate support
- added shadows
- fixed devilw and gradius2 sprite lag
- added text layer x/y flipping
- reverted gradius2 sprite-background priority hack, this fixes severe priority problems in 
devilw, but reintroduces bugs on gradius2 level 7 and ending

affected mametesters bugs:
fixed: 02267, 00191, 02553
partial, due to revert: 02523 (intro is ok again, but old priority bugs are reintroduced), 
02268 (ok in-game, small priority problem in prologue)

Greets,
hap
This commit is contained in:
Aaron Giles 2009-08-13 05:17:16 +00:00
parent 5fae7c5093
commit 55480e3ce9
6 changed files with 428 additions and 358 deletions

View File

@ -204,7 +204,7 @@ void timer_device_adjust_periodic(const device_config *timer, attotime start_del
/* ----- anonymous timer management ----- */
/* allocate a one-shot timer, which calls the callback after the given duration */
void _timer_set_internal(running_machine *machine, attotime druation, void *ptr, INT32 param, timer_fired_func callback, const char *file, int line, const char *func);
void _timer_set_internal(running_machine *machine, attotime duration, void *ptr, INT32 param, timer_fired_func callback, const char *file, int line, const char *func);
/* allocate a pulse timer, which repeatedly calls the callback using the given period */
void _timer_pulse_internal(running_machine *machine, attotime period, void *ptr, INT32 param, timer_fired_func callback, const char *file, int line, const char *func);

View File

@ -439,7 +439,7 @@ static void init_buffered_spriteram(running_machine *machine)
/* register for saving it */
state_save_register_global_pointer(machine, buffered_spriteram, spriteram_size);
/* do the same for the secon back buffer, if present */
/* do the same for the second back buffer, if present */
if (spriteram_2_size)
{
/* allocate memory */

View File

@ -8,47 +8,38 @@ SOUND : YM2151 007232 uPD7759C
OSC. : 3.579545MHz 18432.00KHz
Main processors are a pair of 68000 CPUs
Sounds are generated by a Z80, a Yamaha 2151 and 3012, a Konami custom IC and a UPD7759C
Sounds are generated by a Z80, a Yamaha 2151 and 3012, a Konami custom IC and a uPD7759C
Dark Adventure / Devil World / Majuu no Ohkoku
Vulcan Venture / Gradius II
Cuebrick
MIA (Japan)
Final Round / Hard Puncher (Japan)
Known Issues:
- some rogue sprites in Devil World
- sprite-background priority is guessed
Dark Adventure / Devil World / Majuu no Ohkoku
Vulcan Venture / Gradius II
Cuebrick
MIA (Japan)
Final Round / Hard Puncher (Japan)
68000 Memory Map for Konami Twin System
CPUA CPUB
0x000000..0x03ffff ROM 0x000000..0x03ffff
0x040000..0x043fff communication RAM 0x040000..0x043fff (shared)
0x060000..0x063fff work RAM 0x060000..0x063fff
0x080000..0x080fff palette
0x080000..0x09ffff ROM (extra tile data)
0x0a0000..0x0a0001 IRQ control 0x0a0000..0x0a0001
0x0a0008..0x0a0009 sound command
0x0a0010..0xa00011 watchdog
0x0c0000..0x0c0001 screenflip
0x0c0002..0x0c000f scroll registers
CPUA CPUB
0x000000..0x03ffff ROM 0x000000..0x03ffff
0x040000..0x043fff communication RAM 0x040000..0x043fff (shared)
0x060000..0x063fff work RAM 0x060000..0x063fff
0x080000..0x080fff palette
0x080000..0x09ffff ROM (extra tile data)
0x0a0000..0x0a0001 IRQ control 0x0a0000..0x0a0001
0x0a0008..0x0a0009 sound command
0x0a0010..0xa00011 watchdog
0x0c0000..0x0c0001 screenflip
0x0c0002..0x0c000f scroll registers
0x100000..0x103fff FIXRAM (text layer)
0x120000..0x123fff VIDRAM (tilemaps) 0x480000..0x483fff (shared)
0x140000..0x143fff OBJRAM (sprites) 0x400000..0x403fff (shared)
ZIP RAM (tiles) 0x500000..0x53ffff
gfx ROM (banked) 0x600000..0x77ffff
sprite gfx RAM 0x780000..0x79ffff
*/
0x100000..0x103fff FIXRAM (text layer)
0x120000..0x123fff VIDRAM (tilemaps) 0x480000..0x483fff (shared)
0x140000..0x143fff OBJRAM (sprites) 0x400000..0x403fff (shared)
ZIP RAM (tiles) 0x500000..0x53ffff
gfx ROM (banked) 0x600000..0x77ffff
sprite gfx RAM 0x780000..0x79ffff
/*
Konami Twin16 Hardware
TODO:
- mia reset crash
Known Issues:
- repeated uPD7759C samples in fround, disconnecting reset helps but doesn't fix it
- see video/twin16.c for graphics related issues
*/
@ -65,18 +56,17 @@ UINT16 twin16_custom_video;
UINT16 *twin16_gfx_rom;
UINT16 *twin16_sprite_gfx_ram;
UINT16 *twin16_tile_gfx_ram;
UINT16 *twin16_videoram2; /* text layer */
UINT16 *twin16_text_ram;
static UINT16 twin16_CPUA_register, twin16_CPUB_register;
#define CPUA_IRQ_ENABLE (twin16_CPUA_register & 0x20)
#define CPUB_IRQ_ENABLE (twin16_CPUB_register & 0x02)
static UINT8 twin16_soundlatch;
static UINT16 twin16_sound_command;
static int cuebrckj_nvram_bank;
static UINT16 cuebrckj_nvram[0x400*0x20]; // 32k paged in a 1k window
static int cuebrickj_nvram_bank;
static UINT16 cuebrickj_nvram[0x400*0x20]; // 32k paged in a 1k window
int twin16_spriteram_process_enable( void )
@ -108,7 +98,7 @@ static READ16_HANDLER( extra_rom_r )
static READ16_HANDLER( twin16_gfx_rom1_r )
{
return twin16_gfx_rom[offset];
return twin16_gfx_rom[offset + ((twin16_CPUB_register&0x04)?0x40000:0)];
}
static READ16_HANDLER( twin16_gfx_rom2_r )
@ -122,29 +112,16 @@ static WRITE16_HANDLER( sound_command_w )
soundlatch_w( space, 0, twin16_sound_command&0xff );
}
static READ16_HANDLER( twin16_sprite_status_r )
{
/*
return value indicates whether the spriteram16-processing circuitry
is busy.
for now, we'll just alternate the value every time it is read
*/
static int k;
k = 1-k;
return k;
}
static WRITE16_HANDLER( twin16_CPUA_register_w )
{
/*
7 6 5 4 3 2 1 0
? sprite protection disable
X IRQ5 enable (CPUA)
X 0->1 trigger IRQ6 on CPUB
X 0->1 trigger IRQ on sound CPU
x x x coin counters
*/
7 6 5 4 3 2 1 0
X sprite processing disable
X IRQ5 enable (CPUA)
X 0->1 trigger IRQ6 on CPUB
X 0->1 trigger IRQ on sound CPU
x x x coin counters
*/
UINT16 old = twin16_CPUA_register;
COMBINE_DATA(&twin16_CPUA_register);
if (twin16_CPUA_register != old)
@ -153,7 +130,7 @@ static WRITE16_HANDLER( twin16_CPUA_register_w )
cputag_set_input_line_and_vector(space->machine, "audiocpu", 0, HOLD_LINE, 0xff);
if ((old & 0x40) && (twin16_CPUA_register & 0x40) == 0)
twin16_spriteram_process();
twin16_spriteram_process(space->machine);
if ((old & 0x10) == 0 && (twin16_CPUA_register & 0x10))
cputag_set_input_line(space->machine, "sub", M68K_IRQ_6, HOLD_LINE);
@ -167,30 +144,36 @@ static WRITE16_HANDLER( twin16_CPUA_register_w )
static WRITE16_HANDLER( twin16_CPUB_register_w )
{
/*
7 6 5 4 3 2 1 0
X gfx bank select
X IRQ5 enable
X 0->1 trigger IRQ6 on CPUA
*/
7 6 5 4 3 2 1 0
X gfx bank select
X IRQ5 enable
X 0->1 trigger IRQ6 on CPUA
*/
UINT16 old = twin16_CPUB_register;
COMBINE_DATA(&twin16_CPUB_register);
if( twin16_CPUB_register!=old )
{
if ((old & 0x01) == 0 && (twin16_CPUB_register & 0x01))
{
cputag_set_input_line(space->machine, "maincpu", M68K_IRQ_6, HOLD_LINE);
}
}
}
static WRITE16_HANDLER( fround_CPU_register_w )
{
/*
7 6 5 4 3 2 1 0
X 0->1 trigger IRQ on sound CPU
x x coin counters
*/
UINT16 old = twin16_CPUA_register;
COMBINE_DATA(&twin16_CPUA_register);
if (twin16_CPUA_register != old)
{
if ((old & 0x08) == 0 && (twin16_CPUA_register & 0x08))
cputag_set_input_line_and_vector(space->machine, "audiocpu", 0, HOLD_LINE, 0xff); // trigger IRQ on sound CPU
cputag_set_input_line_and_vector(space->machine, "audiocpu", 0, HOLD_LINE, 0xff);
coin_counter_w(0, twin16_CPUA_register & 0x01);
coin_counter_w(1, twin16_CPUA_register & 0x02);
}
}
@ -205,20 +188,19 @@ static READ16_HANDLER( twin16_input_r )
case 0x08: return input_port_read(space->machine, "DSW2");
case 0x09: return input_port_read(space->machine, "DSW1");
case 0x0c: return input_port_read(space->machine, "DSW3");
default: break;
}
return 0;
}
static READ8_HANDLER( twin16_sres_r )
static READ8_DEVICE_HANDLER( twin16_upd_busy_r )
{
return twin16_soundlatch;
return upd7759_busy_r(device);
}
static WRITE8_HANDLER( twin16_sres_w )
static WRITE8_DEVICE_HANDLER( twin16_upd_reset_w )
{
/* bit 1 resets the UPD7795C sound chip */
upd7759_reset_w(devtag_get_device(space->machine, "upd"), data & 0x02);
twin16_soundlatch = data;
upd7759_reset_w(device, data & 2);
}
static WRITE8_DEVICE_HANDLER( twin16_upd_start_w )
@ -226,24 +208,19 @@ static WRITE8_DEVICE_HANDLER( twin16_upd_start_w )
upd7759_start_w(device, data & 1);
}
static READ8_DEVICE_HANDLER( twin16_upd_busy_r )
static READ16_HANDLER( cuebrickj_nvram_r )
{
return upd7759_busy_r(device) ? 1 : 0;
return cuebrickj_nvram[offset + (cuebrickj_nvram_bank * 0x400 / 2)];
}
static READ16_HANDLER( cuebrckj_nvram_r )
static WRITE16_HANDLER( cuebrickj_nvram_w )
{
return cuebrckj_nvram[offset + (cuebrckj_nvram_bank * 0x400 / 2)];
COMBINE_DATA(&cuebrickj_nvram[offset + (cuebrickj_nvram_bank * 0x400 / 2)]);
}
static WRITE16_HANDLER( cuebrckj_nvram_w )
static WRITE16_HANDLER( cuebrickj_nvram_bank_w )
{
COMBINE_DATA(&cuebrckj_nvram[offset + (cuebrckj_nvram_bank * 0x400 / 2)]);
}
static WRITE16_HANDLER( cuebrckj_nvram_bank_w )
{
cuebrckj_nvram_bank = (data >> 8);
cuebrickj_nvram_bank = (data >> 8);
}
/* Memory Maps */
@ -251,19 +228,19 @@ static WRITE16_HANDLER( cuebrckj_nvram_bank_w )
static ADDRESS_MAP_START( sound_map, ADDRESS_SPACE_PROGRAM, 8 )
AM_RANGE(0x0000, 0x7fff) AM_ROM
AM_RANGE(0x8000, 0x8fff) AM_RAM
AM_RANGE(0x9000, 0x9000) AM_READWRITE(twin16_sres_r, twin16_sres_w)
AM_RANGE(0x9000, 0x9000) AM_DEVWRITE("upd", twin16_upd_reset_w)
AM_RANGE(0xa000, 0xa000) AM_READ(soundlatch_r)
AM_RANGE(0xb000, 0xb00d) AM_DEVREADWRITE("konami", k007232_r, k007232_w)
AM_RANGE(0xc000, 0xc001) AM_DEVREADWRITE("ym", ym2151_r, ym2151_w)
AM_RANGE(0xd000, 0xd000) AM_DEVWRITE("upd", upd7759_port_w)
AM_RANGE(0xe000, 0xe000) AM_DEVWRITE("upd", twin16_upd_start_w)
AM_RANGE(0xf000, 0xf000) AM_DEVREAD("upd", twin16_upd_busy_r) AM_WRITENOP // ??? write ???
AM_RANGE(0xf000, 0xf000) AM_DEVREAD("upd", twin16_upd_busy_r) // miaj writes 0 to it
ADDRESS_MAP_END
static ADDRESS_MAP_START( main_map, ADDRESS_SPACE_PROGRAM, 16 )
AM_RANGE(0x000000, 0x03ffff) AM_ROM
AM_RANGE(0x040000, 0x043fff) AM_READWRITE(COMRAM_r, COMRAM_w)
AM_RANGE(0x044000, 0x04ffff) AM_RAM // miaj
// AM_RANGE(0x044000, 0x04ffff) AM_NOP // miaj
AM_RANGE(0x060000, 0x063fff) AM_RAM
AM_RANGE(0x080000, 0x080fff) AM_RAM_WRITE(twin16_paletteram_word_w) AM_BASE(&paletteram16)
AM_RANGE(0x081000, 0x081fff) AM_WRITENOP
@ -271,12 +248,12 @@ static ADDRESS_MAP_START( main_map, ADDRESS_SPACE_PROGRAM, 16 )
AM_RANGE(0x0a0000, 0x0a0001) AM_WRITE(twin16_CPUA_register_w)
AM_RANGE(0x0a0008, 0x0a0009) AM_WRITE(sound_command_w)
AM_RANGE(0x0a0010, 0x0a0011) AM_WRITE(watchdog_reset16_w)
AM_RANGE(0x0b0000, 0x0b03ff) AM_READWRITE(cuebrckj_nvram_r, cuebrckj_nvram_w)
AM_RANGE(0x0b0400, 0x0b0401) AM_WRITE(cuebrckj_nvram_bank_w)
AM_RANGE(0x0b0000, 0x0b03ff) AM_READWRITE(cuebrickj_nvram_r, cuebrickj_nvram_w)
AM_RANGE(0x0b0400, 0x0b0401) AM_WRITE(cuebrickj_nvram_bank_w)
AM_RANGE(0x0c0000, 0x0c000f) AM_WRITE(twin16_video_register_w)
AM_RANGE(0x0c000e, 0x0c000f) AM_READ(twin16_sprite_status_r)
AM_RANGE(0x100000, 0x103fff) AM_RAM_WRITE(twin16_videoram2_w) AM_BASE(&twin16_videoram2)
AM_RANGE(0x104000, 0x105fff) AM_RAM // miaj
AM_RANGE(0x100000, 0x103fff) AM_RAM_WRITE(twin16_text_ram_w) AM_BASE(&twin16_text_ram)
// AM_RANGE(0x104000, 0x105fff) AM_NOP // miaj
AM_RANGE(0x120000, 0x123fff) AM_RAM AM_BASE(&videoram16)
AM_RANGE(0x140000, 0x143fff) AM_RAM AM_SHARE(1) AM_BASE(&spriteram16) AM_SIZE(&spriteram_size)
ADDRESS_MAP_END
@ -284,7 +261,7 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START( sub_map, ADDRESS_SPACE_PROGRAM, 16 )
AM_RANGE(0x000000, 0x03ffff) AM_ROM
AM_RANGE(0x040000, 0x043fff) AM_READWRITE(COMRAM_r, COMRAM_w)
AM_RANGE(0x044000, 0x04ffff) AM_RAM // miaj
// AM_RANGE(0x044000, 0x04ffff) AM_NOP // miaj
AM_RANGE(0x060000, 0x063fff) AM_RAM
AM_RANGE(0x080000, 0x09ffff) AM_READ(extra_rom_r)
AM_RANGE(0x0a0000, 0x0a0001) AM_WRITE(twin16_CPUB_register_w)
@ -308,7 +285,7 @@ static ADDRESS_MAP_START( fround_map, ADDRESS_SPACE_PROGRAM, 16 )
AM_RANGE(0x0c0000, 0x0c000f) AM_WRITE(twin16_video_register_w)
AM_RANGE(0x0c000e, 0x0c000f) AM_READ(twin16_sprite_status_r)
AM_RANGE(0x0e0000, 0x0e0001) AM_WRITE(fround_gfx_bank_w)
AM_RANGE(0x100000, 0x103fff) AM_RAM_WRITE(twin16_videoram2_w) AM_BASE(&twin16_videoram2)
AM_RANGE(0x100000, 0x103fff) AM_RAM_WRITE(twin16_text_ram_w) AM_BASE(&twin16_text_ram)
AM_RANGE(0x120000, 0x123fff) AM_RAM AM_BASE(&videoram16)
AM_RANGE(0x140000, 0x143fff) AM_RAM AM_BASE(&spriteram16) AM_SIZE(&spriteram_size)
AM_RANGE(0x500000, 0x6fffff) AM_READ(twin16_gfx_rom1_r)
@ -328,7 +305,7 @@ static INPUT_PORTS_START( devilw )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("P1") /* 0xa0003 */
KONAMI8_B123_UNK(1) // button1 = start/powerup, button2 = attack, button3 = jump
KONAMI8_B123_UNK(1) // button1 = start/powerup, button2 = attack, button3 = jump
PORT_START("P2") /* 0xa0005 */
KONAMI8_B123_UNK(2)
@ -378,7 +355,7 @@ static INPUT_PORTS_START( darkadv )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SERVICE2 )
PORT_START("P1") /* 0xa0003 */
KONAMI8_B123(1) // button1 = start/jump, button2 = attack, button3 = dynamite
KONAMI8_B123(1) // button1 = start/jump, button2 = attack, button3 = dynamite
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SERVICE3 )
PORT_START("P2") /* 0xa0005 */
@ -438,14 +415,14 @@ static INPUT_PORTS_START( vulcan )
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 ) // advance through tests
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 ) // advance through tests
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE1 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("P1") /* 0xa0003 */
KONAMI8_B123_UNK(1) // button1 = powerup, button2 = shoot, button3 = missile
KONAMI8_B123_UNK(1) // button1 = powerup, button2 = shoot, button3 = missile
PORT_START("P2") /* 0xa0005 */
KONAMI8_B123_UNK(2)
@ -509,14 +486,14 @@ static INPUT_PORTS_START( fround )
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 ) // advance through tests
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 ) // advance through tests
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE1 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("P1") /* 0xa0003 */
KONAMI8_B123_UNK(1) // button1 = face punch, button2 = body punch, button3 = defend
KONAMI8_B123_UNK(1) // button1 = face punch, button2 = body punch, button3 = defend
PORT_START("P2") /* 0xa0005 */
KONAMI8_B123_UNK(2)
@ -559,14 +536,14 @@ static INPUT_PORTS_START( miaj )
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 ) // advance through tests
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 ) // advance through tests
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE1 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("P1") /* 0xa0003 */
KONAMI8_B123_UNK(1) // button1 = knife, button2 = weapon, button3 = choice
KONAMI8_B123_UNK(1) // button1 = knife, button2 = weapon, button3 = choice
PORT_START("P2") /* 0xa0005 */
KONAMI8_B123_UNK(2)
@ -611,19 +588,19 @@ static INPUT_PORTS_START( miaj )
PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
INPUT_PORTS_END
static INPUT_PORTS_START( cuebrckj )
static INPUT_PORTS_START( cuebrickj )
PORT_START("SYSTEM") /* 0xa0001 */
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 ) // advance through tests
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 ) // advance through tests
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE1 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("P1") /* 0xa0003 */
KONAMI8_B123_UNK(1) // button1 = move, button2 = warp, button3 = stop
KONAMI8_B123_UNK(1) // button1 = move, button2 = warp, button3 = stop
PORT_START("P2") /* 0xa0005 */
KONAMI8_B123_UNK(2)
@ -718,6 +695,25 @@ static INTERRUPT_GEN( CPUB_interrupt )
/* Machine Drivers */
static MACHINE_RESET( twin16 )
{
;
}
static MACHINE_START( twin16 )
{
twin16_CPUA_register=0;
twin16_CPUB_register=0;
/* register for savestates */
state_save_register_global(machine, twin16_CPUA_register);
state_save_register_global(machine, twin16_CPUB_register);
state_save_register_global(machine, twin16_sound_command);
state_save_register_global(machine, cuebrickj_nvram_bank);
state_save_register_global_array(machine, cuebrickj_nvram);
}
static MACHINE_DRIVER_START( twin16 )
// basic machine hardware
MDRV_CPU_ADD("maincpu", M68000, XTAL_18_432MHz/2)
@ -732,13 +728,16 @@ static MACHINE_DRIVER_START( twin16 )
MDRV_CPU_PROGRAM_MAP(sound_map)
MDRV_QUANTUM_TIME(HZ(6000))
MDRV_MACHINE_START(twin16)
MDRV_MACHINE_RESET(twin16)
// video hardware
MDRV_VIDEO_ATTRIBUTES(VIDEO_BUFFERS_SPRITERAM)
MDRV_VIDEO_ATTRIBUTES(VIDEO_HAS_SHADOWS | VIDEO_BUFFERS_SPRITERAM)
MDRV_SCREEN_ADD("screen", RASTER)
MDRV_SCREEN_REFRESH_RATE(((double)XTAL_18_432MHz / 2) / (576 * 264))
MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */)
MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2062)) // 32 lines
MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
MDRV_SCREEN_SIZE(40*8, 32*8)
MDRV_SCREEN_VISIBLE_AREA(0, 40*8-1, 2*8, 30*8-1)
@ -759,10 +758,10 @@ static MACHINE_DRIVER_START( twin16 )
MDRV_SOUND_ADD("konami", K007232, 3579545)
MDRV_SOUND_CONFIG(k007232_config)
MDRV_SOUND_ROUTE(0, "lspeaker", 0.20)
MDRV_SOUND_ROUTE(0, "rspeaker", 0.20)
MDRV_SOUND_ROUTE(1, "lspeaker", 0.20)
MDRV_SOUND_ROUTE(1, "rspeaker", 0.20)
MDRV_SOUND_ROUTE(0, "lspeaker", 0.12) // estimated with gradius2 OST
MDRV_SOUND_ROUTE(0, "rspeaker", 0.12)
MDRV_SOUND_ROUTE(1, "lspeaker", 0.12)
MDRV_SOUND_ROUTE(1, "rspeaker", 0.12)
MDRV_SOUND_ADD("upd", UPD7759, UPD7759_STANDARD_CLOCK)
MDRV_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.20)
@ -771,7 +770,7 @@ MACHINE_DRIVER_END
static MACHINE_DRIVER_START( devilw )
MDRV_IMPORT_FROM(twin16)
MDRV_QUANTUM_TIME(HZ(60000))
MDRV_QUANTUM_TIME(HZ(60000)) // watchdog reset otherwise
MACHINE_DRIVER_END
static MACHINE_DRIVER_START( fround )
@ -784,9 +783,12 @@ static MACHINE_DRIVER_START( fround )
MDRV_CPU_PROGRAM_MAP(sound_map)
MDRV_QUANTUM_TIME(HZ(6000))
MDRV_MACHINE_START(twin16)
MDRV_MACHINE_RESET(twin16)
/* video hardware */
MDRV_VIDEO_ATTRIBUTES(VIDEO_BUFFERS_SPRITERAM)
MDRV_VIDEO_ATTRIBUTES(VIDEO_HAS_SHADOWS | VIDEO_BUFFERS_SPRITERAM)
MDRV_SCREEN_ADD("screen", RASTER)
MDRV_SCREEN_REFRESH_RATE(60)
@ -798,7 +800,7 @@ static MACHINE_DRIVER_START( fround )
MDRV_GFXDECODE(twin16)
MDRV_PALETTE_LENGTH(0x400)
MDRV_VIDEO_START(fround)
MDRV_VIDEO_START(twin16)
MDRV_VIDEO_UPDATE(twin16)
MDRV_VIDEO_EOF(twin16)
@ -811,33 +813,26 @@ static MACHINE_DRIVER_START( fround )
MDRV_SOUND_ADD("konami", K007232, 3579545)
MDRV_SOUND_CONFIG(k007232_config)
MDRV_SOUND_ROUTE(0, "lspeaker", 0.20)
MDRV_SOUND_ROUTE(0, "rspeaker", 0.20)
MDRV_SOUND_ROUTE(1, "lspeaker", 0.20)
MDRV_SOUND_ROUTE(1, "rspeaker", 0.20)
MDRV_SOUND_ROUTE(0, "lspeaker", 0.12)
MDRV_SOUND_ROUTE(0, "rspeaker", 0.12)
MDRV_SOUND_ROUTE(1, "lspeaker", 0.12)
MDRV_SOUND_ROUTE(1, "rspeaker", 0.12)
MDRV_SOUND_ADD("upd", UPD7759, UPD7759_STANDARD_CLOCK)
MDRV_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.20)
MDRV_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.20)
MACHINE_DRIVER_END
static MACHINE_DRIVER_START( hpuncher )
MDRV_IMPORT_FROM(twin16)
MDRV_VIDEO_START(fround)
MACHINE_DRIVER_END
static MACHINE_DRIVER_START( miaj )
MDRV_IMPORT_FROM(twin16)
MDRV_SCREEN_MODIFY("screen")
MDRV_SCREEN_VISIBLE_AREA(1*8, 39*8-1, 2*8, 30*8-1)
MDRV_VIDEO_START(fround)
MACHINE_DRIVER_END
static MACHINE_DRIVER_START( cuebrckj )
static MACHINE_DRIVER_START( cuebrickj )
MDRV_IMPORT_FROM(twin16)
MDRV_SCREEN_MODIFY("screen")
MDRV_SCREEN_VISIBLE_AREA(1*8, 39*8-1, 2*8, 30*8-1)
MDRV_VIDEO_START(fround)
MDRV_NVRAM_HANDLER(generic_0fill)
MACHINE_DRIVER_END
@ -1201,7 +1196,7 @@ ROM_START( miaj )
ROM_REGION( 0x20000, "upd", ROMREGION_ERASE00 ) // samples
ROM_END
ROM_START( cuebrckj )
ROM_START( cuebrickj )
ROM_REGION( 0x40000, "maincpu", 0 ) // 68000 code (CPU A)
ROM_LOAD16_BYTE( "903_e05.6n", 0x00000, 0x10000, CRC(8b556220) SHA1(dbe24133e74018c4fe9332519394cbb882c4ed5a) )
ROM_LOAD16_BYTE( "903_e04.4n", 0x00001, 0x10000, CRC(bf9c7927) SHA1(3a594b8846f7e6074ca54f8cd5fe2ba3b64ba740) )
@ -1239,19 +1234,18 @@ ROM_END
static void gfx_untangle( running_machine *machine )
{
// sprite, tile data
int i;
UINT16 *temp = alloc_array_or_die(UINT16, 0x200000/2);
twin16_gfx_rom = (UINT16 *)memory_region(machine, "gfx2");
memcpy( temp, twin16_gfx_rom, 0x200000 );
twin16_gfx_rom = (UINT16 *)memory_region(machine, "gfx2");
memcpy( temp, twin16_gfx_rom, 0x200000 );
for( i=0; i<0x080000; i++ )
{
twin16_gfx_rom[i*2+0] = temp[i+0x080000];
twin16_gfx_rom[i*2+1] = temp[i];
}
free( temp );
for( i=0; i<0x080000; i++ )
{
twin16_gfx_rom[i*2+0] = temp[i+0x080000];
twin16_gfx_rom[i*2+1] = temp[i];
}
free( temp );
}
static DRIVER_INIT( twin16 )
@ -1266,33 +1260,26 @@ static DRIVER_INIT( fround )
twin16_custom_video = 1;
}
static DRIVER_INIT( hpuncher )
static DRIVER_INIT( cuebrickj )
{
gfx_untangle(machine);
twin16_custom_video = 2;
}
static DRIVER_INIT( cuebrckj )
{
gfx_untangle(machine);
twin16_custom_video = 2;
generic_nvram = (UINT8 *)cuebrckj_nvram;
generic_nvram = (UINT8 *)cuebrickj_nvram;
generic_nvram_size = 0x400*0x20;
}
/* Game Drivers */
GAME( 1987, devilw, 0, devilw, devilw, twin16, ROT0, "Konami", "Devil World", 0 )
GAME( 1987, majuu, devilw, devilw, devilw, twin16, ROT0, "Konami", "Majuu no Ohkoku", 0 )
GAME( 1987, darkadv, devilw, devilw, darkadv, twin16, ROT0, "Konami", "Dark Adventure", 0 )
GAME( 1988, vulcan, 0, twin16, vulcan, twin16, ROT0, "Konami", "Vulcan Venture", 0 )
GAME( 1988, gradius2, vulcan, twin16, gradius2, twin16, ROT0, "Konami", "Gradius II - GOFER no Yabou (Japan New Ver.)", 0 )
GAME( 1988, gradius2a,vulcan, twin16, vulcan, twin16, ROT0, "Konami", "Gradius II - GOFER no Yabou (Japan Old Ver.)", 0 )
GAME( 1988, gradius2b,vulcan, twin16, vulcan, twin16, ROT0, "Konami", "Gradius II - GOFER no Yabou (Japan Older Ver.)", 0 )
GAME( 1987, devilw, 0, devilw, devilw, twin16, ROT0, "Konami", "Devil World", GAME_SUPPORTS_SAVE )
GAME( 1987, majuu, devilw, devilw, devilw, twin16, ROT0, "Konami", "Majuu no Ohkoku", GAME_SUPPORTS_SAVE )
GAME( 1987, darkadv, devilw, devilw, darkadv, twin16, ROT0, "Konami", "Dark Adventure", GAME_SUPPORTS_SAVE )
GAME( 1988, vulcan, 0, twin16, vulcan, twin16, ROT0, "Konami", "Vulcan Venture", GAME_SUPPORTS_SAVE )
GAME( 1988, gradius2, vulcan, twin16, gradius2, twin16, ROT0, "Konami", "Gradius II - GOFER no Yabou (Japan New Ver.)", GAME_SUPPORTS_SAVE )
GAME( 1988, gradius2a,vulcan, twin16, vulcan, twin16, ROT0, "Konami", "Gradius II - GOFER no Yabou (Japan Old Ver.)", GAME_SUPPORTS_SAVE )
GAME( 1988, gradius2b,vulcan, twin16, vulcan, twin16, ROT0, "Konami", "Gradius II - GOFER no Yabou (Japan Older Ver.)", GAME_SUPPORTS_SAVE )
GAME( 1988, fround, 0, fround, fround, fround, ROT0, "Konami", "The Final Round (version M)", 0 )
GAME( 1988, froundl, fround, fround, fround, fround, ROT0, "Konami", "The Final Round (version L)", 0 )
GAME( 1988, hpuncher, fround, hpuncher, fround, hpuncher, ROT0, "Konami", "Hard Puncher (Japan)", 0 )
GAME( 1989, miaj, mia, miaj, miaj, hpuncher, ROT0, "Konami", "M.I.A. - Missing in Action (Japan)", 0 )
GAME( 1989, cuebrckj, cuebrick, cuebrckj, cuebrckj, cuebrckj, ROT0, "Konami", "Cue Brick (Japan)", 0 )
GAME( 1988, fround, 0, fround, fround, fround, ROT0, "Konami", "The Final Round (version M)", GAME_SUPPORTS_SAVE )
GAME( 1988, froundl, fround, fround, fround, fround, ROT0, "Konami", "The Final Round (version L)", GAME_SUPPORTS_SAVE )
GAME( 1988, hpuncher, fround, twin16, fround, twin16, ROT0, "Konami", "Hard Puncher (Japan)", GAME_SUPPORTS_SAVE )
GAME( 1989, miaj, mia, miaj, miaj, twin16, ROT0, "Konami", "M.I.A. - Missing in Action (Japan)", GAME_SUPPORTS_SAVE )
GAME( 1989, cuebrickj,cuebrick, cuebrickj, cuebrickj,cuebrickj,ROT0, "Konami", "Cue Brick (Japan)", GAME_SUPPORTS_SAVE )

View File

@ -2,7 +2,7 @@
extern UINT16 twin16_custom_video;
extern UINT16 *twin16_gfx_rom;
extern UINT16 *twin16_videoram2;
extern UINT16 *twin16_text_ram;
extern UINT16 *twin16_sprite_gfx_ram;
extern UINT16 *twin16_tile_gfx_ram;
int twin16_spriteram_process_enable( void );
@ -10,14 +10,14 @@ int twin16_spriteram_process_enable( void );
/*----------- defined in video/twin16.c -----------*/
WRITE16_HANDLER( twin16_videoram2_w );
WRITE16_HANDLER( twin16_text_ram_w );
WRITE16_HANDLER( twin16_paletteram_word_w );
WRITE16_HANDLER( fround_gfx_bank_w );
WRITE16_HANDLER( twin16_video_register_w );
READ16_HANDLER( twin16_sprite_status_r );
VIDEO_START( twin16 );
VIDEO_START( fround );
VIDEO_UPDATE( twin16 );
VIDEO_EOF( twin16 );
void twin16_spriteram_process( void );
void twin16_spriteram_process( running_machine* );

View File

@ -5312,7 +5312,7 @@ BOMULEUL CHAJARA SEGA ST-V 1997/04/11
DRIVER( gradius2 ) /* GX785 (c) 1988 (Japan) */
DRIVER( gradius2a ) /* GX785 (c) 1988 (Japan) */
DRIVER( gradius2b ) /* GX785 (c) 1988 (Japan) */
DRIVER( cuebrckj ) /* GX903 (c) 1989 */
DRIVER( cuebrickj ) /* GX903 (c) 1989 (Japan) */
DRIVER( fround ) /* GX870 (c) 1988 */
DRIVER( froundl ) /* GX870 (c) 1988 */
DRIVER( hpuncher ) /* GX870 (c) 1988 (Japan) */

View File

@ -5,17 +5,21 @@
TODO:
- convert background to tilemap
- clean up sprite drawing
- sprite-background priorities
- sprite lag in devilw
- sprite Y axis lag in vulcan
- add shadow sprites (alpha blending) to sprites in at least devilw
- clean up sprite system
- bad sprites in devilw, eg. odd colours for the mud/lava monster in the 1st level,
or wrong sprite-sprite priority sometimes -- check real arcade first
- unsure about some sprite preprocessor attributes (see twin16_spriteram_process)
*/
#include "driver.h"
#include "includes/twin16.h"
static UINT16 twin16_sprite_buffer[0x800];
static TIMER_CALLBACK( twin16_sprite_tick );
static emu_timer *twin16_sprite_timer;
static int twin16_sprite_busy;
static int need_process_spriteram;
static UINT16 gfx_bank;
static UINT16 scrollx[3], scrolly[3];
@ -23,19 +27,31 @@ static UINT16 video_register;
enum
{
TWIN16_SCREEN_FLIPY = 0x01, /* ? breaks devils world text layer */
TWIN16_SCREEN_FLIPX = 0x02, /* confirmed: Hard Puncher Intro */
TWIN16_UNKNOWN1 = 0x04, /* ?Hard Puncher uses this */
TWIN16_PLANE_ORDER = 0x08, /* confirmed: Devil Worlds */
TWIN16_TILE_FLIPY = 0x20 /* confirmed? Vulcan Venture */
TWIN16_SCREEN_FLIPY = 0x01,
TWIN16_SCREEN_FLIPX = 0x02, // confirmed: Hard Puncher Intro
TWIN16_UNKNOWN1 = 0x04, // ? Hard Puncher uses this
TWIN16_PLANE_ORDER = 0x08, // confirmed: Devil Worlds
TWIN16_TILE_FLIPX = 0x10, // unused?
TWIN16_TILE_FLIPY = 0x20 // confirmed? Vulcan Venture
};
static tilemap *fg_tilemap;
WRITE16_HANDLER( twin16_videoram2_w )
enum
{
COMBINE_DATA(&twin16_videoram2[offset]);
tilemap_mark_tile_dirty(fg_tilemap, offset);
// user-defined priorities
TWIN16_BG_LAYER1 = 0x01,
TWIN16_SPRITE_PRI_L1 = 0x02,
TWIN16_BG_LAYER2 = 0x04,
TWIN16_SPRITE_PRI_L2 = 0x08,
TWIN16_SPRITE_OCCUPIED = 0x10, // sprite on screen pixel
TWIN16_SPRITE_CAST_SHADOW = 0x20
};
static tilemap *text_tilemap;
WRITE16_HANDLER( twin16_text_ram_w )
{
COMBINE_DATA(&twin16_text_ram[offset]);
tilemap_mark_tile_dirty(text_tilemap, offset);
}
WRITE16_HANDLER( twin16_paletteram_word_w )
@ -60,12 +76,8 @@ WRITE16_HANDLER( twin16_video_register_w )
COMBINE_DATA( &video_register );
flip_screen_x_set(space->machine, video_register & TWIN16_SCREEN_FLIPX);
if (twin16_custom_video)
flip_screen_y_set(space->machine, video_register & TWIN16_SCREEN_FLIPY);
else
flip_screen_y_set(space->machine, ~video_register & TWIN16_SCREEN_FLIPY);
flip_screen_y_set(space->machine, video_register & TWIN16_SCREEN_FLIPY);
break;
case 1: COMBINE_DATA( &scrollx[0] ); break;
@ -81,76 +93,124 @@ WRITE16_HANDLER( twin16_video_register_w )
}
}
/* slow slow slow, but it's ok for now */
static void draw_sprite( running_machine *machine, bitmap_t *bitmap,const UINT16 *pen_data, int pal_base, int xpos, int ypos, int width, int height, int flipx, int flipy, int pri )
/*
* Sprite Format
* ----------------------------------
* preprocessor (not much data to test with):
* Word | Bit(s) | Use
* -----+-fedcba9876543210-+----------------
* 0 | x--------------- | enable
* 0 | -xxxxxxx-------- | ?
* 0 | --------xxxxxxxx | sprite-sprite priority
* -----+------------------+
* 1 | xxxxxxxxxxxxxxxx | ?
* -----+------------------+
* 2 | xxxxxx---------- | ?
* 2 | ------x--------- | yflip (devilw)
* 2 | -------x-------- | xflip
* 2 | --------xx------ | height
* 2 | ----------xx---- | width
* 2 | ------------xxxx | color
* -----+------------------+
* 3 | -xxxxxxxxxxxxxxx | code
* -----+------------------+
* 4 | -------xxxxxxxxx | xpos high, other bits probably no effect
* 5 | xxxxxxxx-------- | xpos low, other bits probably no effect
* 6 | -------xxxxxxxxx | xpos high, other bits probably no effect
* 7 | xxxxxxxx-------- | ypos low, other bits probably no effect
*
* ----------------------------------
* normal/after preprocessing:
* Word | Bit(s) | Use
* -----+-fedcba9876543210-+----------------
* 0 | -xxxxxxxxxxxxxxx | code
* -----+------------------+
* 1 | -------xxxxxxxxx | ypos
* -----+------------------+
* 2 | -------xxxxxxxxx | xpos
* -----+------------------+
* 3 | x--------------- | enable
* 3 | -x-------------- | priority ?
* 3 | -----x---------- | no shadow ?
* 3 | ------x--------- | yflip ?
* 3 | -------x-------- | xflip
* 3 | --------xx------ | height
* 3 | ----------xx---- | width
* 3 | ------------xxxx | color
*/
READ16_HANDLER( twin16_sprite_status_r )
{
int x,y,pval;
if( xpos>=320 ) xpos -= 65536;
if( ypos>=256 ) ypos -= 65536;
if (pri) pval=2; else pval=8;
for( y=0; y<height; y++ )
{
int sy = (flipy)?(ypos+height-1-y):(ypos+y);
if( sy>=16 && sy<256-16 )
{
UINT16 *dest = BITMAP_ADDR16(bitmap, sy, 0);
UINT8 *pdest = BITMAP_ADDR8(machine->priority_bitmap, sy, 0);
for( x=0; x<width; x++ )
{
int sx = (flipx)?(xpos+width-1-x):(xpos+x);
if( sx>=0 && sx<320 )
{
UINT16 pen = pen_data[x/4];
switch( x%4 )
{
case 0: pen = pen>>12; break;
case 1: pen = (pen>>8)&0xf; break;
case 2: pen = (pen>>4)&0xf; break;
case 3: pen = pen&0xf; break;
}
if( pen )
{
if(pdest[sx]<pval)
{
dest[sx] = pal_base + pen;
}
pdest[sx]|=0x10;
}
}
}
}
pen_data += width/4;
}
// bit 0: busy, other bits: dunno
return twin16_sprite_busy;
}
void twin16_spriteram_process( void )
static TIMER_CALLBACK( twin16_sprite_tick )
{
twin16_sprite_busy = 0;
}
static int twin16_set_sprite_timer( running_machine *machine )
{
if (twin16_sprite_busy) return 1;
// sprite system busy, maybe a dma? time is guessed, assume 4 scanlines
twin16_sprite_busy = 1;
timer_adjust_oneshot(twin16_sprite_timer, attotime_make(0,(((screen_config *)(machine->primary_screen)->inline_config)->refresh) / video_screen_get_height(machine->primary_screen) * 4), 0);
return 0;
}
void twin16_spriteram_process( running_machine *machine )
{
UINT16 dx = scrollx[0];
UINT16 dy = scrolly[0];
const UINT16 *source = &spriteram16[0x0000];
const UINT16 *finish = &spriteram16[0x1800];
memset( &spriteram16[0x1800], 0, 0x800 );
twin16_set_sprite_timer(machine);
memset(&spriteram16[0x1800],0xff,0x800*sizeof(UINT16));
while( source<finish )
{
UINT16 priority = source[0];
if( priority & 0x8000 )
{
UINT16 *dest = &spriteram16[0x1800 + 4*(priority&0xff)];
INT32 xpos = (0x10000*source[4])|source[5];
INT32 ypos = (0x10000*source[6])|source[7];
UINT16 attributes = source[2]&0x03ff; /* scale,size,color */
if( priority & 0x0200 ) attributes |= 0x4000;
/* Todo: priority & 0x0100 is also used */
attributes |= 0x8000;
UINT16 *dest = &spriteram16[0x1800|(priority&0xff)<<2];
UINT32 xpos = (0x10000*source[4])|source[5];
UINT32 ypos = (0x10000*source[6])|source[7];
/* notes on uncertain attributes:
shadows: pen $F only (like other Konami hw), used in devilw, fround,
miaj? (shadows are solid in tmnt hw version),
gradius2? (ship exhaust)
sprite-background priority: in devilw, most sprites look best at high priority,
in gradius2, most sprites look best at low priority. exceptions:
- devilw prologue: sprites behind crowd (maybe more, haven't completed the game)
- gradius2 intro showing earlier games: sprites above layers
currently using (priority&0x200), broken:
- devilw prologue: sprites should be behind crowd
- gradius2 level 7: bosses should be behind portal (ok except brain boss and mouth boss)
- gradius2 ending: sun should be behind planet
does TWIN16_PLANE_ORDER affect it?
more?
devilw monster dens exploding monochrome, players fading to white in prologue, and trees in
the 1st level shrinking with a solid green color look odd, maybe alpha blended?
fround, hpuncher, miaj, cuebrickj, don't use the preprocessor. all sprites are expected
to be high priority, and shadows are enabled
*/
UINT16 attributes = 0x8000| // enabled
(source[2]&0x03ff)| // scale,size,color
(source[2]&0x4000)>>4| // no-shadow? (gradius2 level 7 boss sets this bit and appears to expect pen $F to be solid)
(priority&0x200)<<5; // sprite-background priority?
dest[0] = source[3]; /* gfx data */
dest[1] = ((xpos>>8) - dx)&0xffff;
dest[2] = ((ypos>>8) - dy)&0xffff;
@ -161,34 +221,8 @@ void twin16_spriteram_process( void )
need_process_spriteram = 0;
}
/*
* Sprite Format
* ----------------------------------
*
* Word | Bit(s) | Use
* -----+-fedcba9876543210-+----------------
* 0 | --xxxxxxxxxxxxxx | code
* -----+------------------+
* 1 | -------xxxxxxxxx | ypos
* -----+------------------+
* 2 | -------xxxxxxxxx | xpos
* -----+------------------+
* 3 | x--------------- | enble
* 3 | -x-------------- | priority?
* 3 | ------x--------- | yflip?
* 3 | -------x-------- | xflip
* 3 | --------xx------ | height
* 3 | ----------xx---- | width
* 3 | ------------xxxx | color
shadow bit?
*/
static void draw_sprites( running_machine *machine, bitmap_t *bitmap )
{
int count = 0;
const UINT16 *source = 0x1800+buffered_spriteram16 + 0x800 - 4;
const UINT16 *finish = 0x1800+buffered_spriteram16;
@ -201,60 +235,50 @@ static void draw_sprites( running_machine *machine, bitmap_t *bitmap )
{
int xpos = source[1];
int ypos = source[2];
int x,y;
int pal_base = ((attributes&0xf)+0x10)*16;
int height = 16<<((attributes>>6)&0x3);
int width = 16<<((attributes>>4)&0x3);
const UINT16 *pen_data = 0;
int flipy = attributes&0x0200;
int flipx = attributes&0x0100;
if( twin16_custom_video == 1 )
{
int priority = (attributes&0x4000)?TWIN16_SPRITE_PRI_L1:TWIN16_SPRITE_PRI_L2;
if( twin16_custom_video ) {
/* fround board */
pen_data = twin16_gfx_rom + 0x80000;
}
else
{
switch( (code>>12)&0x3 )
{ /* bank select */
{
/* bank select */
case 0:
pen_data = twin16_gfx_rom;
break;
pen_data = twin16_gfx_rom;
break;
case 1:
pen_data = twin16_gfx_rom + 0x40000;
break;
pen_data = twin16_gfx_rom + 0x40000;
break;
case 2:
pen_data = twin16_gfx_rom + 0x80000;
if( code&0x4000 ) pen_data += 0x40000;
break;
pen_data = twin16_gfx_rom + 0x80000;
if( code&0x4000 ) pen_data += 0x40000;
break;
case 3:
pen_data = twin16_sprite_gfx_ram;
break;
pen_data = twin16_sprite_gfx_ram;
break;
}
code &= 0xfff;
}
/* some code masking */
if(height == 64 && width == 64)
{
code &= ~8; // fixes bad sprites in vulcan ending sequence
}
else if(height == 32 && width == 32)
{
code &= ~3; // fixes bad sprites in devilw
}
else if(height == 32 && width == 16)
{
code &= ~1; // fixes bad sprites in devilw
}
else if(height == 16 && width == 32)
{
code &= ~1; // fixes bad sprites in devilw
}
if ((height&width) == 64) code &= ~8; // gradius2 ending sequence 64*64
else if ((height&width) == 32) code &= ~3; // devilw 32*32
else if ((height|width) == 48) code &= ~1; // devilw 32*16 / 16*32
pen_data += code*0x40;
if( video_register&TWIN16_SCREEN_FLIPY )
@ -269,15 +293,56 @@ static void draw_sprites( running_machine *machine, bitmap_t *bitmap )
xpos = 320-xpos-width;
flipx = !flipx;
}
//if( sprite_which==count || !input_code_pressed( KEYCODE_B ) )
draw_sprite( machine, bitmap, pen_data, pal_base, xpos, ypos, width, height, flipx, flipy, (attributes&0x4000) );
if( xpos>=320 ) xpos -= 65536;
if( ypos>=256 ) ypos -= 65536;
/* slow slow slow, but it's ok for now */
for( y=0; y<height; y++, pen_data += width/4 )
{
int sy = (flipy)?(ypos+height-1-y):(ypos+y);
if( sy>=16 && sy<256-16 )
{
UINT16 *dest = BITMAP_ADDR16(bitmap, sy, 0);
UINT8 *pdest = BITMAP_ADDR8(machine->priority_bitmap, sy, 0);
for( x=0; x<width; x++ )
{
int sx = (flipx)?(xpos+width-1-x):(xpos+x);
if( sx>=0 && sx<320 )
{
UINT16 pen = pen_data[x>>2]>>((~x&3)<<2)&0xf;
if( pen )
{
int shadow = (pen==0xf) & ((attributes&0x400)==0);
if (pdest[sx]<priority) {
if (shadow) {
dest[sx] = machine->shadow_table[dest[sx]];
pdest[sx]|=TWIN16_SPRITE_CAST_SHADOW;
}
else {
dest[sx] = pal_base + pen;
}
}
else if (!shadow && pdest[sx]&TWIN16_SPRITE_CAST_SHADOW && (pdest[sx]&0xf)<priority) {
// shadow cast onto sprite below, evident in devilw lava level
dest[sx] = machine->shadow_table[pal_base + pen];
pdest[sx]^=TWIN16_SPRITE_CAST_SHADOW;
}
pdest[sx]|=TWIN16_SPRITE_OCCUPIED;
}
}
}
}
}
}
count++;
}
}
static void draw_layer( running_machine *machine, bitmap_t *bitmap, int opaque )
{
const UINT16 *gfx_base;
@ -285,34 +350,31 @@ static void draw_layer( running_machine *machine, bitmap_t *bitmap, int opaque )
int i, xxor, yxor;
int bank_table[4];
int dx, dy, palette;
int tile_flipx = 0; // video_register&TWIN16_TILE_FLIPX;
int tile_flipx = video_register&TWIN16_TILE_FLIPX;
int tile_flipy = video_register&TWIN16_TILE_FLIPY;
if( ((video_register&TWIN16_PLANE_ORDER)?1:0) != opaque )
{
if( ((video_register&TWIN16_PLANE_ORDER)?1:0) != opaque ) {
source += 0x1000;
dx = scrollx[2];
dy = scrolly[2];
palette = 1;
}
else
{
else {
source += 0x0000;
dx = scrollx[1];
dy = scrolly[1];
palette = 0;
}
if( twin16_custom_video == 1 )
{
if( twin16_custom_video ) {
/* fround board */
gfx_base = twin16_gfx_rom;
bank_table[3] = (gfx_bank>>(4*3))&0xf;
bank_table[2] = (gfx_bank>>(4*2))&0xf;
bank_table[1] = (gfx_bank>>(4*1))&0xf;
bank_table[0] = (gfx_bank>>(4*0))&0xf;
}
else
{
else {
gfx_base = twin16_tile_gfx_ram;
bank_table[0] = 0;
bank_table[1] = 1;
@ -358,11 +420,11 @@ static void draw_layer( running_machine *machine, bitmap_t *bitmap, int opaque )
if (x1 <= x2 && y1 <= y2)
{
int code = source[i];
/*
xxx------------- color
---xx----------- tile bank
-----xxxxxxxxxxx tile number
*/
/* fedcba9876543210
xxx------------- color
---xx----------- tile bank
-----xxxxxxxxxxx tile number
*/
const UINT16 *gfx_data = gfx_base + (code&0x7ff)*16 + bank_table[(code>>11)&0x3]*0x8000;
int color = (code>>13);
int pal_base = 16*(0x20+color+8*palette);
@ -381,7 +443,7 @@ static void draw_layer( running_machine *machine, bitmap_t *bitmap, int opaque )
int effx = (x - xpos) ^ xxor;
UINT16 data = gfxptr[effx / 4];
dest[x] = pal_base + ((data >> 4*(~effx & 3)) & 0x0f);
pdest[x] |= 1;
pdest[x] |= TWIN16_BG_LAYER1;
}
}
}
@ -401,7 +463,7 @@ static void draw_layer( running_machine *machine, bitmap_t *bitmap, int opaque )
if (pen)
{
dest[x] = pal_base + pen;
pdest[x] |= 4;
pdest[x] |= TWIN16_BG_LAYER2;
}
}
}
@ -410,59 +472,80 @@ static void draw_layer( running_machine *machine, bitmap_t *bitmap, int opaque )
}
}
static TILE_GET_INFO( get_fg_tile_info )
static TILE_GET_INFO( get_text_tile_info )
{
const UINT16 *source = twin16_videoram2;
const UINT16 *source = twin16_text_ram;
int attr = source[tile_index];
/* fedcba9876543210
-x-------------- yflip
--x------------- xflip
---xxxx--------- color
-------xxxxxxxxx tile number
*/
int code = attr & 0x1ff;
int color = (attr >> 9) & 0x0f;
SET_TILE_INFO(0, code, color, 0);
int flags=0;
if (attr&0x2000) flags|=TILE_FLIPX;
if (attr&0x4000) flags|=TILE_FLIPY;
SET_TILE_INFO(0, code, color, flags);
}
VIDEO_START( twin16 )
{
fg_tilemap = tilemap_create(machine, get_fg_tile_info, tilemap_scan_rows_flip_y, 8, 8, 64, 32);
tilemap_set_transparent_pen(fg_tilemap, 0);
}
VIDEO_START( fround )
{
fg_tilemap = tilemap_create(machine, get_fg_tile_info, tilemap_scan_rows, 8, 8, 64, 32);
tilemap_set_transparent_pen(fg_tilemap, 0);
text_tilemap = tilemap_create(machine, get_text_tile_info, tilemap_scan_rows, 8, 8, 64, 32);
tilemap_set_transparent_pen(text_tilemap, 0);
memset(twin16_sprite_buffer,0xff,0x800*sizeof(UINT16));
twin16_sprite_busy = 0;
twin16_sprite_timer = timer_alloc(machine, twin16_sprite_tick, NULL);
timer_adjust_oneshot(twin16_sprite_timer, attotime_never, 0);
/* register for savestates */
state_save_register_global_array(machine, twin16_sprite_buffer);
state_save_register_global_array(machine, scrollx);
state_save_register_global_array(machine, scrolly);
state_save_register_global(machine, need_process_spriteram);
state_save_register_global(machine, gfx_bank);
state_save_register_global(machine, video_register);
state_save_register_global(machine, twin16_sprite_busy);
}
VIDEO_UPDATE( twin16 )
{
int text_flip=0;
if (video_register&TWIN16_SCREEN_FLIPX) text_flip|=TILEMAP_FLIPX;
if (video_register&TWIN16_SCREEN_FLIPY) text_flip|=TILEMAP_FLIPY;
bitmap_fill(screen->machine->priority_bitmap,cliprect,0);
draw_layer( screen->machine, bitmap, 1 );
if (twin16_custom_video)
{
draw_layer( screen->machine, bitmap, 0 );
draw_sprites( screen->machine, bitmap );
}
else // devilw, vulcan - different priorities order? there should be an enable bit somewhere...
{
draw_sprites( screen->machine, bitmap );
draw_layer( screen->machine, bitmap, 0 );
}
tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
draw_layer( screen->machine, bitmap, 0 );
draw_sprites( screen->machine, bitmap );
if (text_flip) tilemap_set_flip(text_tilemap, text_flip);
tilemap_draw(bitmap, cliprect, text_tilemap, 0, 0);
return 0;
}
VIDEO_EOF( twin16 )
{
const address_space *space = cputag_get_address_space(machine, "maincpu", ADDRESS_SPACE_PROGRAM);
if( twin16_spriteram_process_enable() && need_process_spriteram )
twin16_spriteram_process();
need_process_spriteram = 1;
buffer_spriteram16_w(space,0,0,0xffff);
twin16_set_sprite_timer(machine);
if (twin16_spriteram_process_enable()) {
if (need_process_spriteram) twin16_spriteram_process(machine);
need_process_spriteram = 1;
/* if the sprite preprocessor is used, sprite ram is copied to an external buffer first,
as evidenced by 1-frame sprite lag in gradius2 and devilw otherwise, though there's probably
more to it than that */
memcpy(&buffered_spriteram16[0x1800],twin16_sprite_buffer,0x800*sizeof(UINT16));
memcpy(twin16_sprite_buffer,&spriteram16[0x1800],0x800*sizeof(UINT16));
}
else {
const address_space *space = cputag_get_address_space(machine, "maincpu", ADDRESS_SPACE_PROGRAM);
buffer_spriteram16_w(space,0,0,0xffff);
}
}