summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2009-08-13 05:17:16 +0000
committer Aaron Giles <aaron@aarongiles.com>2009-08-13 05:17:16 +0000
commit55480e3ce9867c789fc60c5bde2c7b8a07afc8e5 (patch)
tree632543cdd53982fe23f4cf5c90f07e85cc68a82c
parent5fae7c509335f79b92c9a52836df010c1268281b (diff)
From: hoge hoge [c8cv@hotmail.com]
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
-rw-r--r--src/emu/timer.h2
-rw-r--r--src/emu/video.c2
-rw-r--r--src/mame/drivers/twin16.c311
-rw-r--r--src/mame/includes/twin16.h8
-rw-r--r--src/mame/mamedriv.c2
-rw-r--r--src/mame/video/twin16.c461
6 files changed, 428 insertions, 358 deletions
diff --git a/src/emu/timer.h b/src/emu/timer.h
index b2d26a40589..9c4ef6b4643 100644
--- a/src/emu/timer.h
+++ b/src/emu/timer.h
@@ -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);
diff --git a/src/emu/video.c b/src/emu/video.c
index a2eaf6f8faf..0c82361714a 100644
--- a/src/emu/video.c
+++ b/src/emu/video.c
@@ -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 */
diff --git a/src/mame/drivers/twin16.c b/src/mame/drivers/twin16.c
index 19576be6f28..19e80350990 100644
--- a/src/mame/drivers/twin16.c
+++ b/src/mame/drivers/twin16.c
@@ -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
-
- 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
+ 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
- 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 )
-{
- return upd7759_busy_r(device) ? 1 : 0;
-}
-
-static READ16_HANDLER( cuebrckj_nvram_r )
+static READ16_HANDLER( cuebrickj_nvram_r )
{
- return cuebrckj_nvram[offset + (cuebrckj_nvram_bank * 0x400 / 2)];
+ return cuebrickj_nvram[offset + (cuebrickj_nvram_bank * 0x400 / 2)];
}
-static WRITE16_HANDLER( cuebrckj_nvram_w )
+static WRITE16_HANDLER( cuebrickj_nvram_w )
{
- COMBINE_DATA(&cuebrckj_nvram[offset + (cuebrckj_nvram_bank * 0x400 / 2)]);
+ COMBINE_DATA(&cuebrickj_nvram[offset + (cuebrickj_nvram_bank * 0x400 / 2)]);
}
-static WRITE16_HANDLER( cuebrckj_nvram_bank_w )
+static WRITE16_HANDLER( cuebrickj_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 )
-{
- gfx_untangle(machine);
- twin16_custom_video = 2;
-}
-
-static DRIVER_INIT( cuebrckj )
+static DRIVER_INIT( cuebrickj )
{
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( 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( 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)", 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 )
diff --git a/src/mame/includes/twin16.h b/src/mame/includes/twin16.h
index 654bc77cff6..05f6fc63270 100644
--- a/src/mame/includes/twin16.h
+++ b/src/mame/includes/twin16.h
@@ -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* );
diff --git a/src/mame/mamedriv.c b/src/mame/mamedriv.c
index f221a9306cc..f41e8081160 100644
--- a/src/mame/mamedriv.c
+++ b/src/mame/mamedriv.c
@@ -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) */
diff --git a/src/mame/video/twin16.c b/src/mame/video/twin16.c
index 292e8fc4b50..45032a11b44 100644
--- a/src/mame/video/twin16.c
+++ b/src/mame/video/twin16.c
@@ -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
+};
+
+enum
+{
+ // 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 *fg_tilemap;
+static tilemap *text_tilemap;
-WRITE16_HANDLER( twin16_videoram2_w )
+WRITE16_HANDLER( twin16_text_ram_w )
{
- COMBINE_DATA(&twin16_videoram2[offset]);
- tilemap_mark_tile_dirty(fg_tilemap, offset);
+ 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 )
-{
- int x,y,pval;
- if( xpos>=320 ) xpos -= 65536;
- if( ypos>=256 ) ypos -= 65536;
-
- if (pri) pval=2; else pval=8;
+/*
+ * 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
+ */
- 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);
+READ16_HANDLER( twin16_sprite_status_r )
+{
+ // bit 0: busy, other bits: dunno
+ return twin16_sprite_busy;
+}
- 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;
- }
+static TIMER_CALLBACK( twin16_sprite_tick )
+{
+ twin16_sprite_busy = 0;
+}
- if( pen )
- {
- if(pdest[sx]<pval)
- {
- dest[sx] = pal_base + pen;
- }
- pdest[sx]|=0x10;
- }
- }
- }
- }
- pen_data += width/4;
- }
+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( void )
+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);
+ }
}