hyprduel : Cleanups, Add imagetek_i4220_device, Allocate sound output… (#3272)

* hyprduel : Cleanups, Add imagetek_i4220_device, Allocate sound output form real PCB(real PCB only has mono sound output)
imagetek_i4100.cpp : Boost tilemap drawing routines when VIDEO_UPDATE_SCANLINE case of screen video attributes, Add notes

* Minor cleanup, Add notes

* imagetek_i4100 : Fix tilemap drawing at tilemap offset X/Y !=0 case

* hyprduel : Fix mistake

* magerror : Remove MACHINE_NOT_WORKING Flags
This commit is contained in:
cam900 2018-03-01 04:02:02 +09:00 committed by R. Belmont
parent 71d728f348
commit 5a8890c31c
5 changed files with 156 additions and 1191 deletions

View File

@ -2557,8 +2557,6 @@ files {
createMAMEProjects(_target, _subtarget, "metro")
files {
MAME_DIR .. "src/mame/drivers/hyprduel.cpp",
MAME_DIR .. "src/mame/includes/hyprduel.h",
MAME_DIR .. "src/mame/video/hyprduel.cpp",
MAME_DIR .. "src/mame/drivers/metro.cpp",
MAME_DIR .. "src/mame/includes/metro.h",
MAME_DIR .. "src/mame/video/metro.cpp",

View File

@ -66,7 +66,7 @@
#include "emu.h"
#include "imagetek_i4100.h"
#include <algorithm>
//**************************************************************************
// GLOBAL VARIABLES
@ -342,7 +342,7 @@ WRITE16_MEMBER(imagetek_i4100_device::vram_0_w){ COMBINE_DATA(&m_vram_0[offset])
WRITE16_MEMBER(imagetek_i4100_device::vram_1_w){ COMBINE_DATA(&m_vram_1[offset]); }
WRITE16_MEMBER(imagetek_i4100_device::vram_2_w){ COMBINE_DATA(&m_vram_2[offset]); }
/* This game uses almost only the blitter to write to the tilemaps.
/* Some game uses almost only the blitter to write to the tilemaps.
The CPU can only access a "window" of 512x256 pixels in the upper
left corner of the big tilemap */
// TODO: Puzzlet, Sankokushi & Lady Killer contradicts with aformentioned description (more like RMW?)
@ -1053,10 +1053,37 @@ void imagetek_i4100_device::draw_tilemap( screen_device &screen, bitmap_ind16 &b
int windowwidth = width >> 2;
int windowheight = height >> 3;
sx += m_tilemap_scrolldx[layer] * (m_screen_flip ? 1 : -1);
sy += m_tilemap_scrolldy[layer] * (m_screen_flip ? 1 : -1);
int dx = m_tilemap_scrolldx[layer] * (m_screen_flip ? 1 : -1);
int dy = m_tilemap_scrolldy[layer] * (m_screen_flip ? 1 : -1);
for (y = 0; y < scrheight; y++)
sx += dx;
sy += dy;
int min_x, max_x, min_y, max_y;
if (dx != 0)
{
min_x = 0;
max_x = scrwidth-1;
}
else
{
min_x = cliprect.min_x;
max_x = cliprect.max_x;
}
if (dy != 0)
{
min_y = 0;
max_y = scrheight-1;
}
else
{
min_y = cliprect.min_y;
max_y = cliprect.max_y;
}
for (y = min_y; y <= max_y; y++)
{
int scrolly = (sy+y-wy)&(windowheight-1);
int x;
@ -1070,7 +1097,7 @@ void imagetek_i4100_device::draw_tilemap( screen_device &screen, bitmap_ind16 &b
dst = &bitmap.pix16(y);
priority_baseaddr = &priority_bitmap.pix8(y);
for (x = 0; x < scrwidth; x++)
for (x = min_x; x <= max_x; x++)
{
int scrollx = (sx+x-wx)&(windowwidth-1);
int srccol = (wx+scrollx)&(width-1);
@ -1094,7 +1121,7 @@ void imagetek_i4100_device::draw_tilemap( screen_device &screen, bitmap_ind16 &b
dst = &bitmap.pix16(scrheight-y-1);
priority_baseaddr = &priority_bitmap.pix8(scrheight-y-1);
for (x = 0; x < scrwidth; x++)
for (x = min_x; x <= max_x; x++)
{
int scrollx = (sx+x-wx)&(windowwidth-1);
int srccol = (wx+scrollx)&(width-1);

View File

@ -37,16 +37,81 @@ fix comms so it boots, it's a bit of a hack for hyperduel at the moment ;-)
***************************************************************************/
#include "emu.h"
#include "includes/hyprduel.h"
#include "cpu/m68000/m68000.h"
#include "machine/timer.h"
#include "sound/okim6295.h"
#include "sound/ym2151.h"
#include "sound/ym2413.h"
#include "video/imagetek_i4100.h"
#include "screen.h"
#include "speaker.h"
#define RASTER_LINES 262
#define FIRST_VISIBLE_LINE 0
#define LAST_VISIBLE_LINE 223
class hyprduel_state : public driver_device
{
public:
hyprduel_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_irq_enable(*this, "irq_enable")
, m_sharedram(*this, "sharedram%u", 1)
, m_maincpu(*this, "maincpu")
, m_subcpu(*this, "sub")
, m_vdp(*this, "vdp")
{ }
DECLARE_READ16_MEMBER(irq_cause_r);
DECLARE_WRITE16_MEMBER(irq_cause_w);
DECLARE_WRITE16_MEMBER(subcpu_control_w);
DECLARE_READ16_MEMBER(hyprduel_cpusync_trigger1_r);
DECLARE_WRITE16_MEMBER(hyprduel_cpusync_trigger1_w);
DECLARE_READ16_MEMBER(hyprduel_cpusync_trigger2_r);
DECLARE_WRITE16_MEMBER(hyprduel_cpusync_trigger2_w);
DECLARE_DRIVER_INIT(magerror);
DECLARE_DRIVER_INIT(hyprduel);
DECLARE_MACHINE_START(hyprduel);
DECLARE_MACHINE_START(magerror);
TIMER_CALLBACK_MEMBER(vblank_end_callback);
DECLARE_WRITE_LINE_MEMBER(vdp_blit_end_w);
TIMER_DEVICE_CALLBACK_MEMBER(interrupt);
void magerror(machine_config &config);
void hyprduel(machine_config &config);
void i4220_config(machine_config &config);
void hyprduel_map(address_map &map);
void hyprduel_map2(address_map &map);
void magerror_map(address_map &map);
void magerror_map2(address_map &map);
protected:
virtual void machine_reset() override;
private:
/* memory pointers */
required_shared_ptr<uint16_t> m_irq_enable;
required_shared_ptr_array<uint16_t, 3> m_sharedram;
/* misc */
emu_timer *m_vblank_end_timer;
int m_blitter_bit;
int m_requested_int;
int m_subcpu_resetline;
int m_cpu_trigger;
int m_int_num;
/* devices */
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_subcpu;
required_device<imagetek_i4220_device> m_vdp;
void update_irq_state( );
};
/***************************************************************************
Interrupts
***************************************************************************/
@ -139,14 +204,14 @@ READ16_MEMBER(hyprduel_state::hyprduel_cpusync_trigger1_r)
m_cpu_trigger = 0;
}
return m_sharedram1[0x000408 / 2 + offset];
return m_sharedram[0][0x000408 / 2 + offset];
}
WRITE16_MEMBER(hyprduel_state::hyprduel_cpusync_trigger1_w)
{
COMBINE_DATA(&m_sharedram1[0x00040e / 2 + offset]);
COMBINE_DATA(&m_sharedram[0][0x00040e / 2 + offset]);
if (((m_sharedram1[0x00040e / 2] << 16) + m_sharedram1[0x000410 / 2]) != 0x00)
if (((m_sharedram[0][0x00040e / 2] << 16) + m_sharedram[0][0x000410 / 2]) != 0x00)
{
if (!m_cpu_trigger && !m_subcpu_resetline)
{
@ -165,12 +230,12 @@ READ16_MEMBER(hyprduel_state::hyprduel_cpusync_trigger2_r)
m_cpu_trigger = 0;
}
return m_sharedram3[(0xfff34c - 0xfe4000) / 2 + offset];
return m_sharedram[2][(0xfff34c - 0xfe4000) / 2 + offset];
}
WRITE16_MEMBER(hyprduel_state::hyprduel_cpusync_trigger2_w)
{
COMBINE_DATA(&m_sharedram1[0x000408 / 2 + offset]);
COMBINE_DATA(&m_sharedram[0][0x000408 / 2 + offset]);
if (ACCESSING_BITS_8_15)
{
@ -182,260 +247,21 @@ WRITE16_MEMBER(hyprduel_state::hyprduel_cpusync_trigger2_w)
}
}
TIMER_CALLBACK_MEMBER(hyprduel_state::magerror_irq_callback)
{
m_subcpu->set_input_line(1, HOLD_LINE);
}
/***************************************************************************
Banked ROM access
***************************************************************************/
/*
The main CPU has access to the ROMs that hold the graphics through
a banked window of 64k. Those ROMs also usually store the tables for
the virtual tiles set. The tile codes to be written to the tilemap
memory to render the backgrounds are also stored here, in a format
that the blitter can readily use (which is a form of compression)
*/
READ16_MEMBER(hyprduel_state::bankedrom_r)
{
uint8_t *ROM = memregion("gfx1")->base();
size_t len = memregion("gfx1")->bytes();
offset = offset * 2 + 0x10000 * (*m_rombank);
if (offset < len)
return ((ROM[offset + 0] << 8) + ROM[offset + 1]);
else
return 0xffff;
}
/***************************************************************************
Blitter
[ Registers ]
Offset: Value:
0.l Destination Tilemap (1,2,3)
4.l Blitter Data Address (byte offset into the gfx ROMs)
8.l Destination Address << 7 (byte offset into the tilemap)
The Blitter reads a byte and looks at the most significative
bits for the opcode, while the remaining bits define a value
(usually how many bytes to write). The opcode byte may be
followed by a number of other bytes:
76------ Opcode
--543210 N
(at most N+1 bytes follow)
The blitter is designed to write every other byte (e.g. it
writes a byte and skips the next). Hence 2 blits are needed
to fill a tilemap (first even, then odd addresses)
[ Opcodes ]
0 Copy the following N+1 bytes. If the whole byte
is $00: stop and generate an IRQ
1 Fill N+1 bytes with a sequence, starting with
the value in the following byte
2 Fill N+1 bytes with the value in the following
byte
3 Skip N+1 bytes. If the whole byte is $C0:
skip to the next row of the tilemap (+0x200 bytes)
but preserve the column passed at the start of the
blit (destination address % 0x200)
***************************************************************************/
TIMER_CALLBACK_MEMBER(hyprduel_state::blit_done)
WRITE_LINE_MEMBER(hyprduel_state::vdp_blit_end_w)
{
m_requested_int |= 1 << m_blitter_bit;
update_irq_state();
}
inline int hyprduel_state::blt_read( const uint8_t *ROM, const int offs )
{
return ROM[offs];
}
void hyprduel_state::blt_write( address_space &space, const int tmap, const offs_t offs, const uint16_t data, const uint16_t mask )
{
switch( tmap )
{
case 1: vram_0_w(space, offs,data,mask); break;
case 2: vram_1_w(space, offs, data, mask); break;
case 3: vram_2_w(space, offs, data, mask); break;
}
// logerror("%s : Blitter %X] %04X <- %04X & %04X\n", machine().describe_context(), tmap, offs, data, mask);
}
WRITE16_MEMBER(hyprduel_state::blitter_w)
{
COMBINE_DATA(&m_blitter_regs[offset]);
if (offset == 0xc / 2)
{
uint8_t *src = memregion("gfx1")->base();
size_t src_len = memregion("gfx1")->bytes();
uint32_t tmap = (m_blitter_regs[0x00 / 2] << 16) + m_blitter_regs[0x02 / 2];
uint32_t src_offs = (m_blitter_regs[0x04 / 2] << 16) + m_blitter_regs[0x06 / 2];
uint32_t dst_offs = (m_blitter_regs[0x08 / 2] << 16) + m_blitter_regs[0x0a / 2];
int shift = (dst_offs & 0x80) ? 0 : 8;
uint16_t mask = (dst_offs & 0x80) ? 0x00ff : 0xff00;
// logerror("CPU #0 PC %06X : Blitter regs %08X, %08X, %08X\n", m_maincpu->pc(), tmap, src_offs, dst_offs);
dst_offs >>= 7 + 1;
switch (tmap)
{
case 1:
case 2:
case 3:
break;
default:
logerror("CPU #0 PC %06X : Blitter unknown destination: %08X\n", m_maincpu->pc(), tmap);
return;
}
while (1)
{
uint16_t b1, b2, count;
src_offs %= src_len;
b1 = blt_read(src, src_offs);
// logerror("CPU #0 PC %06X : Blitter opcode %02X at %06X\n", m_maincpu->pc(), b1, src_offs);
src_offs++;
count = ((~b1) & 0x3f) + 1;
switch ((b1 & 0xc0) >> 6)
{
case 0:
/* Stop and Generate an IRQ. We can't generate it now
both because it's unlikely that the blitter is so
fast and because some games (e.g. lastfort) need to
complete the blitter irq service routine before doing
another blit. */
if (b1 == 0)
{
m_blit_done_timer->adjust(attotime::from_usec(500));
return;
}
/* Copy */
while (count--)
{
src_offs %= src_len;
b2 = blt_read(src, src_offs) << shift;
src_offs++;
dst_offs &= 0xffff;
blt_write(space, tmap, dst_offs, b2, mask);
dst_offs = ((dst_offs + 1) & (0x100 - 1)) | (dst_offs & (~(0x100 - 1)));
}
break;
case 1:
/* Fill with an increasing value */
src_offs %= src_len;
b2 = blt_read(src, src_offs);
src_offs++;
while (count--)
{
dst_offs &= 0xffff;
blt_write(space, tmap, dst_offs, b2 << shift, mask);
dst_offs = ((dst_offs + 1) & (0x100 - 1)) | (dst_offs & (~(0x100 - 1)));
b2++;
}
break;
case 2:
/* Fill with a fixed value */
src_offs %= src_len;
b2 = blt_read(src, src_offs) << shift;
src_offs++;
while (count--)
{
dst_offs &= 0xffff;
blt_write(space, tmap, dst_offs, b2, mask);
dst_offs = ((dst_offs + 1) & (0x100 - 1)) | (dst_offs & (~(0x100 - 1)));
}
break;
case 3:
/* Skip to the next line ?? */
if (b1 == 0xC0)
{
dst_offs += 0x100;
dst_offs &= ~(0x100 - 1);
dst_offs |= (0x100 - 1) & (m_blitter_regs[0x0a / 2] >> (7 + 1));
}
else
{
dst_offs += count;
}
break;
default:
logerror("CPU #0 PC %06X : Blitter unknown opcode %02X at %06X\n", m_maincpu->pc(), b1, src_offs - 1);
return;
}
}
}
}
/***************************************************************************
Memory Maps
***************************************************************************/
ADDRESS_MAP_START(hyprduel_state::hyprduel_map)
AM_RANGE(0x000000, 0x07ffff) AM_ROM
AM_RANGE(0x400000, 0x41ffff) AM_RAM_WRITE(vram_0_w) AM_SHARE("vram_0") /* Layer 0 */
AM_RANGE(0x420000, 0x43ffff) AM_RAM_WRITE(vram_1_w) AM_SHARE("vram_1") /* Layer 1 */
AM_RANGE(0x440000, 0x45ffff) AM_RAM_WRITE(vram_2_w) AM_SHARE("vram_2") /* Layer 2 */
AM_RANGE(0x460000, 0x46ffff) AM_READ(bankedrom_r) /* Banked ROM */
AM_RANGE(0x470000, 0x473fff) AM_RAM_WRITE(paletteram_w) AM_SHARE("paletteram") /* Palette */
AM_RANGE(0x474000, 0x474fff) AM_RAM AM_SHARE("spriteram") /* Sprites */
AM_RANGE(0x475000, 0x477fff) AM_RAM /* only used memory test */
AM_RANGE(0x478000, 0x4787ff) AM_RAM AM_SHARE("tiletable") /* Tiles Set */
AM_RANGE(0x478840, 0x47884d) AM_WRITE(blitter_w) AM_SHARE("blitter_regs") /* Tiles Blitter */
AM_RANGE(0x478850, 0x478853) AM_RAM AM_SHARE("spriteregs")
AM_RANGE(0x478860, 0x47886b) AM_WRITE(window_w) AM_SHARE("window") /* Tilemap Window */
AM_RANGE(0x478870, 0x47887b) AM_RAM_WRITE(scrollreg_w) AM_SHARE("scroll") /* Scroll Regs */
AM_RANGE(0x47887c, 0x47887d) AM_WRITE(scrollreg_init_w)
AM_RANGE(0x478880, 0x478881) AM_WRITENOP
AM_RANGE(0x478890, 0x478891) AM_WRITENOP
AM_RANGE(0x4788a0, 0x4788a1) AM_WRITENOP
AM_RANGE(0x400000, 0x47ffff) AM_DEVICE("vdp", imagetek_i4220_device, v2_map)
AM_RANGE(0x4788a2, 0x4788a3) AM_READWRITE(irq_cause_r, irq_cause_w) /* IRQ Cause,Acknowledge */
AM_RANGE(0x4788a4, 0x4788a5) AM_RAM AM_SHARE("irq_enable") /* IRQ Enable */
AM_RANGE(0x4788aa, 0x4788ab) AM_RAM AM_SHARE("rombank") /* Rom Bank */
AM_RANGE(0x4788ac, 0x4788ad) AM_RAM AM_SHARE("screenctrl") /* Screen Control */
AM_RANGE(0x479700, 0x479713) AM_RAM AM_SHARE("videoregs") /* Video Registers */
AM_RANGE(0x800000, 0x800001) AM_WRITE(subcpu_control_w)
AM_RANGE(0xc00000, 0xc07fff) AM_RAM AM_SHARE("sharedram1")
AM_RANGE(0xe00000, 0xe00001) AM_READ_PORT("SERVICE") AM_WRITENOP
@ -449,7 +275,7 @@ ADDRESS_MAP_END
ADDRESS_MAP_START(hyprduel_state::hyprduel_map2)
AM_RANGE(0x000000, 0x003fff) AM_RAM AM_SHARE("sharedram1") /* shadow ($c00000 - $c03fff : vector) */
AM_RANGE(0x004000, 0x007fff) AM_READONLY AM_WRITENOP AM_SHARE("sharedram3") /* shadow ($fe4000 - $fe7fff : read only) */
AM_RANGE(0x400000, 0x400003) AM_DEVREADWRITE8("ymsnd", ym2151_device, read, write, 0x00ff )
AM_RANGE(0x400000, 0x400003) AM_DEVREADWRITE8("ymsnd", ym2151_device, read, write, 0x00ff)
AM_RANGE(0x400004, 0x400005) AM_DEVREADWRITE8("oki", okim6295_device, read, write, 0x00ff)
AM_RANGE(0x800000, 0x800001) AM_NOP
AM_RANGE(0xc00000, 0xc07fff) AM_RAM AM_SHARE("sharedram1")
@ -463,27 +289,9 @@ ADDRESS_MAP_END
ADDRESS_MAP_START(hyprduel_state::magerror_map)
AM_RANGE(0x000000, 0x07ffff) AM_ROM
AM_RANGE(0x400000, 0x400001) AM_WRITE(subcpu_control_w)
AM_RANGE(0x800000, 0x81ffff) AM_RAM_WRITE(vram_0_w) AM_SHARE("vram_0") /* Layer 0 */
AM_RANGE(0x820000, 0x83ffff) AM_RAM_WRITE(vram_1_w) AM_SHARE("vram_1") /* Layer 1 */
AM_RANGE(0x840000, 0x85ffff) AM_RAM_WRITE(vram_2_w) AM_SHARE("vram_2") /* Layer 2 */
AM_RANGE(0x860000, 0x86ffff) AM_READ(bankedrom_r) /* Banked ROM */
AM_RANGE(0x870000, 0x873fff) AM_RAM_WRITE(paletteram_w) AM_SHARE("paletteram") /* Palette */
AM_RANGE(0x874000, 0x874fff) AM_RAM AM_SHARE("spriteram") /* Sprites */
AM_RANGE(0x875000, 0x877fff) AM_RAM /* only used memory test */
AM_RANGE(0x878000, 0x8787ff) AM_RAM AM_SHARE("tiletable") /* Tiles Set */
AM_RANGE(0x878840, 0x87884d) AM_WRITE(blitter_w) AM_SHARE("blitter_regs") /* Tiles Blitter */
AM_RANGE(0x878850, 0x878853) AM_RAM AM_SHARE("spriteregs")
AM_RANGE(0x878860, 0x87886b) AM_WRITE(window_w) AM_SHARE("window") /* Tilemap Window */
AM_RANGE(0x878870, 0x87887b) AM_RAM_WRITE(scrollreg_w) AM_SHARE("scroll") /* Scroll Regs */
AM_RANGE(0x87887c, 0x87887d) AM_WRITE(scrollreg_init_w)
AM_RANGE(0x878880, 0x878881) AM_WRITENOP
AM_RANGE(0x878890, 0x878891) AM_WRITENOP
AM_RANGE(0x8788a0, 0x8788a1) AM_WRITENOP
AM_RANGE(0x800000, 0x87ffff) AM_DEVICE("vdp", imagetek_i4220_device, v2_map)
AM_RANGE(0x8788a2, 0x8788a3) AM_READWRITE(irq_cause_r, irq_cause_w) /* IRQ Cause, Acknowledge */
AM_RANGE(0x8788a4, 0x8788a5) AM_RAM AM_SHARE("irq_enable") /* IRQ Enable */
AM_RANGE(0x8788aa, 0x8788ab) AM_RAM AM_SHARE("rombank") /* Rom Bank */
AM_RANGE(0x8788ac, 0x8788ad) AM_RAM AM_SHARE("screenctrl") /* Screen Control */
AM_RANGE(0x879700, 0x879713) AM_RAM AM_SHARE("videoregs") /* Video Registers */
AM_RANGE(0xc00000, 0xc1ffff) AM_RAM AM_SHARE("sharedram1")
AM_RANGE(0xe00000, 0xe00001) AM_READ_PORT("SERVICE") AM_WRITENOP
AM_RANGE(0xe00002, 0xe00003) AM_READ_PORT("DSW")
@ -611,11 +419,28 @@ static const gfx_layout layout_8x8x4 =
};
/* 8x8x8 tiles for later games */
static GFXLAYOUT_RAW( layout_8x8x8h, 8, 8, 8*8, 32*8 )
static GFXLAYOUT_RAW( layout_8x8x8, 8, 8, 8*8, 32*8 )
static GFXDECODE_START( 14220 )
GFXDECODE_ENTRY( "gfx1", 0, layout_8x8x4, 0x0, 0x200 ) // [0] 4 Bit Tiles
GFXDECODE_ENTRY( "gfx1", 0, layout_8x8x8h, 0x0, 0x20 ) // [1] 8 Bit Tiles
/* 16x16x4 tiles for later games */
static const gfx_layout layout_16x16x4 =
{
16,16,
RGN_FRAC(1,1),
4,
{ STEP4(0,1) },
{ 4*1,4*0, 4*3,4*2, 4*5,4*4, 4*7,4*6, 4*9,4*8, 4*11,4*10, 4*13,4*12, 4*15,4*14 },
{ STEP16(0,4*16) },
4*8*8
};
/* 16x16x8 tiles for later games */
static GFXLAYOUT_RAW( layout_16x16x8, 16, 16, 16*8, 32*8 )
static GFXDECODE_START( i4220 )
GFXDECODE_ENTRY( "gfx1", 0, layout_8x8x4, 0x0, 0x100 ) // [0] 4 Bit Tiles
GFXDECODE_ENTRY( "gfx1", 0, layout_8x8x8, 0x0, 0x10 ) // [1] 8 Bit Tiles
GFXDECODE_ENTRY( "gfx1", 0, layout_16x16x4, 0x0, 0x100 ) // [2] 4 Bit Tiles 16x16
GFXDECODE_ENTRY( "gfx1", 0, layout_16x16x8, 0x0, 0x10 ) // [3] 8 Bit Tiles 16x16
GFXDECODE_END
/***************************************************************************
@ -641,15 +466,25 @@ MACHINE_START_MEMBER(hyprduel_state,hyprduel)
save_item(NAME(m_subcpu_resetline));
save_item(NAME(m_cpu_trigger));
m_blit_done_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hyprduel_state::blit_done), this));
m_vblank_end_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hyprduel_state::vblank_end_callback), this));
}
MACHINE_START_MEMBER(hyprduel_state,magerror)
{
MACHINE_START_CALL_MEMBER(hyprduel);
m_magerror_irq_timer->adjust(attotime::zero, 0, attotime::from_hz(968)); /* tempo? */
}
MACHINE_CONFIG_START(hyprduel_state::i4220_config)
MCFG_DEVICE_ADD("vdp", I4220, XTAL(26'666'000))
MCFG_I4100_GFXDECODE("gfxdecode")
MCFG_I4100_BLITTER_END_CALLBACK(WRITELINE(hyprduel_state,vdp_blit_end_w))
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_UPDATE_SCANLINE)
MCFG_SCREEN_REFRESH_RATE(60) // Unknown/Unverified
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
MCFG_SCREEN_SIZE(320, 224)
MCFG_SCREEN_VISIBLE_AREA(0, 320-1, FIRST_VISIBLE_LINE, LAST_VISIBLE_LINE)
MCFG_SCREEN_UPDATE_DEVICE("vdp", imagetek_i4100_device, screen_update)
MCFG_SCREEN_PALETTE(":vdp:palette")
MCFG_GFXDECODE_ADD("gfxdecode", ":vdp:palette", i4220)
MACHINE_CONFIG_END
MACHINE_CONFIG_START(hyprduel_state::hyprduel)
@ -664,31 +499,17 @@ MACHINE_CONFIG_START(hyprduel_state::hyprduel)
MCFG_MACHINE_START_OVERRIDE(hyprduel_state,hyprduel)
/* video hardware */
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_UPDATE_SCANLINE)
MCFG_SCREEN_REFRESH_RATE(60)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
MCFG_SCREEN_SIZE(320, 224)
MCFG_SCREEN_VISIBLE_AREA(0, 320-1, FIRST_VISIBLE_LINE, LAST_VISIBLE_LINE)
MCFG_SCREEN_UPDATE_DRIVER(hyprduel_state, screen_update)
MCFG_SCREEN_PALETTE("palette")
MCFG_GFXDECODE_ADD("gfxdecode", "palette", 14220)
MCFG_PALETTE_ADD("palette", 8192)
MCFG_VIDEO_START_OVERRIDE(hyprduel_state,hyprduel_14220)
i4220_config(config);
/* sound hardware */
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_YM2151_ADD("ymsnd", 4000000)
MCFG_YM2151_IRQ_HANDLER(INPUTLINE("sub", 1))
MCFG_SOUND_ROUTE(0, "lspeaker", 0.80)
MCFG_SOUND_ROUTE(1, "rspeaker", 0.80)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.80)
MCFG_OKIM6295_ADD("oki", 4000000/16/16*132, PIN7_HIGH) // clock frequency & pin 7 not verified
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.57)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.57)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.57)
MACHINE_CONFIG_END
@ -701,34 +522,21 @@ MACHINE_CONFIG_START(hyprduel_state::magerror)
MCFG_CPU_ADD("sub", M68000,20000000/2) /* 10MHz */
MCFG_CPU_PROGRAM_MAP(magerror_map2)
MCFG_CPU_PERIODIC_INT_DRIVER(hyprduel_state, irq1_line_hold, 968) /* tempo? */
MCFG_MACHINE_START_OVERRIDE(hyprduel_state,magerror)
MCFG_MACHINE_START_OVERRIDE(hyprduel_state,hyprduel)
/* video hardware */
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_UPDATE_SCANLINE)
MCFG_SCREEN_REFRESH_RATE(60)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
MCFG_SCREEN_SIZE(320, 224)
MCFG_SCREEN_VISIBLE_AREA(0, 320-1, FIRST_VISIBLE_LINE, LAST_VISIBLE_LINE)
MCFG_SCREEN_UPDATE_DRIVER(hyprduel_state, screen_update)
MCFG_SCREEN_PALETTE("palette")
MCFG_GFXDECODE_ADD("gfxdecode", "palette", 14220)
MCFG_PALETTE_ADD("palette", 8192)
MCFG_VIDEO_START_OVERRIDE(hyprduel_state,magerror_14220)
i4220_config(config);
/* sound hardware */
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("ymsnd", YM2413, 3579545)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
MCFG_OKIM6295_ADD("oki", 4000000/16/16*132, PIN7_HIGH) // clock frequency & pin 7 not verified
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.57)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.57)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.57)
MACHINE_CONFIG_END
/***************************************************************************
@ -795,7 +603,6 @@ DRIVER_INIT_MEMBER(hyprduel_state,hyprduel)
DRIVER_INIT_MEMBER(hyprduel_state,magerror)
{
m_int_num = 0x01;
m_magerror_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hyprduel_state::magerror_irq_callback),this));
}

View File

@ -1,137 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Luca Elia, Hau
#include "machine/timer.h"
#include "screen.h"
#define RASTER_LINES 262
#define FIRST_VISIBLE_LINE 0
#define LAST_VISIBLE_LINE 223
class hyprduel_state : public driver_device
{
public:
hyprduel_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag),
m_vram_0(*this, "vram_0"),
m_vram_1(*this, "vram_1"),
m_vram_2(*this, "vram_2"),
m_paletteram(*this, "paletteram"),
m_spriteram(*this, "spriteram"),
m_spriteregs(*this, "spriteregs"),
m_tiletable(*this, "tiletable"),
m_blitter_regs(*this, "blitter_regs"),
m_window(*this, "window"),
m_scroll(*this, "scroll"),
m_irq_enable(*this, "irq_enable"),
m_rombank(*this, "rombank"),
m_screenctrl(*this, "screenctrl"),
m_videoregs(*this, "videoregs"),
m_sharedram1(*this, "sharedram1"),
m_sharedram3(*this, "sharedram3"),
m_maincpu(*this, "maincpu"),
m_subcpu(*this, "sub"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette") { }
DECLARE_READ16_MEMBER(irq_cause_r);
DECLARE_WRITE16_MEMBER(irq_cause_w);
DECLARE_WRITE16_MEMBER(subcpu_control_w);
DECLARE_READ16_MEMBER(hyprduel_cpusync_trigger1_r);
DECLARE_WRITE16_MEMBER(hyprduel_cpusync_trigger1_w);
DECLARE_READ16_MEMBER(hyprduel_cpusync_trigger2_r);
DECLARE_WRITE16_MEMBER(hyprduel_cpusync_trigger2_w);
DECLARE_READ16_MEMBER(bankedrom_r);
DECLARE_WRITE16_MEMBER(blitter_w);
DECLARE_WRITE16_MEMBER(paletteram_w);
DECLARE_WRITE16_MEMBER(vram_0_w);
DECLARE_WRITE16_MEMBER(vram_1_w);
DECLARE_WRITE16_MEMBER(vram_2_w);
DECLARE_WRITE16_MEMBER(window_w);
DECLARE_WRITE16_MEMBER(scrollreg_w);
DECLARE_WRITE16_MEMBER(scrollreg_init_w);
DECLARE_DRIVER_INIT(magerror);
DECLARE_DRIVER_INIT(hyprduel);
TILE_GET_INFO_MEMBER(get_tile_info_0_8bit);
TILE_GET_INFO_MEMBER(get_tile_info_1_8bit);
TILE_GET_INFO_MEMBER(get_tile_info_2_8bit);
DECLARE_MACHINE_START(hyprduel);
DECLARE_VIDEO_START(hyprduel_14220);
DECLARE_MACHINE_START(magerror);
DECLARE_VIDEO_START(magerror_14220);
DECLARE_VIDEO_START(common_14220);
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
TIMER_CALLBACK_MEMBER(vblank_end_callback);
TIMER_CALLBACK_MEMBER(magerror_irq_callback);
TIMER_CALLBACK_MEMBER(blit_done);
TIMER_DEVICE_CALLBACK_MEMBER(interrupt);
void magerror(machine_config &config);
void hyprduel(machine_config &config);
void hyprduel_map(address_map &map);
void hyprduel_map2(address_map &map);
void magerror_map(address_map &map);
void magerror_map2(address_map &map);
protected:
virtual void machine_reset() override;
private:
/* memory pointers */
required_shared_ptr<uint16_t> m_vram_0;
required_shared_ptr<uint16_t> m_vram_1;
required_shared_ptr<uint16_t> m_vram_2;
required_shared_ptr<uint16_t> m_paletteram;
required_shared_ptr<uint16_t> m_spriteram;
required_shared_ptr<uint16_t> m_spriteregs;
required_shared_ptr<uint16_t> m_tiletable;
required_shared_ptr<uint16_t> m_blitter_regs;
required_shared_ptr<uint16_t> m_window;
required_shared_ptr<uint16_t> m_scroll;
required_shared_ptr<uint16_t> m_irq_enable;
required_shared_ptr<uint16_t> m_rombank;
required_shared_ptr<uint16_t> m_screenctrl;
required_shared_ptr<uint16_t> m_videoregs;
required_shared_ptr<uint16_t> m_sharedram1;
required_shared_ptr<uint16_t> m_sharedram3;
std::unique_ptr<uint16_t[]> m_tiletable_old;
/* video-related */
tilemap_t *m_bg_tilemap[3];
std::unique_ptr<uint8_t[]> m_empty_tiles;
std::unique_ptr<uint8_t[]> m_dirtyindex;
int m_sprite_xoffs;
int m_sprite_yoffs;
std::unique_ptr<uint8_t[]> m_expanded_gfx1;
/* misc */
emu_timer *m_magerror_irq_timer;
emu_timer *m_vblank_end_timer;
emu_timer *m_blit_done_timer;
int m_blitter_bit;
int m_requested_int;
int m_subcpu_resetline;
int m_cpu_trigger;
int m_int_num;
/* devices */
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_subcpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
void postload();
inline void get_tile_info( tile_data &tileinfo, int tile_index, int layer, uint16_t *vram);
inline void get_tile_info_8bit( tile_data &tileinfo, int tile_index, int layer, uint16_t *vram );
inline void get_tile_info_16x16_8bit( tile_data &tileinfo, int tile_index, int layer, uint16_t *vram );
inline void vram_w( offs_t offset, uint16_t data, uint16_t mem_mask, int layer, uint16_t *vram );
void alloc_empty_tiles( );
void expand_gfx1( );
void draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect );
void draw_layers( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri, int layers_ctrl );
void dirty_tiles( int layer, uint16_t *vram );
void update_irq_state( );
inline int blt_read( const uint8_t *ROM, const int offs );
void blt_write( address_space &space, const int tmap, const offs_t offs, const uint16_t data, const uint16_t mask );
};

View File

@ -1,730 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Luca Elia, Hau
/* based on driver from video/metro.c by Luca Elia */
/* modified by Hau */
/***************************************************************************
-= Metro Games =-
driver by Luca Elia (l.elia@tin.it)
Note: if MAME_DEBUG is defined, pressing Z with:
Q Shows Layer 0
W Shows Layer 1
E Shows Layer 2
A Shows Sprites
Keys can be used together!
[ 3 Scrolling Layers ]
There is memory for a huge layer, but the actual tilemap
is a smaller window (of fixed size) carved from anywhere
inside that layer.
Tile Size: 8 x 8 x 4
(later games can switch to 8 x 8 x 8, 16 x 16 x 4/8 at run time)
Big Layer Size: 2048 x 2048 (8x8 tiles) or 4096 x 4096 (16x16 tiles)
Tilemap Window Size: 512 x 256 (8x8 tiles) or 1024 x 512 (16x16 tiles)
The tile codes in memory do not map directly to tiles. They
are indexes into a table (with 0x200 entries) that defines
a virtual set of tiles for the 3 layers. Each entry in that
table adds 16 tiles to the set of available tiles, and decides
their color code.
Tile code with their msbit set are different as they mean:
draw a tile filled with a single color (0-1ff)
[ 512 Zooming Sprites ]
The sprites are NOT tile based: the "tile" size can vary from
8 to 64 (independently for width and height) with an 8 pixel
granularity. The "tile" address is a multiple of 8x8 pixels.
Each sprite can be shrinked to ~1/4 or enlarged to ~32x following
an exponential curve of sizes (with one zoom value for both width
and height)
***************************************************************************/
#include "emu.h"
#include "includes/hyprduel.h"
/***************************************************************************
Palette GGGGGRRRRRBBBBBx
***************************************************************************/
WRITE16_MEMBER(hyprduel_state::paletteram_w)
{
data = COMBINE_DATA(&m_paletteram[offset]);
m_palette->set_pen_color(offset, pal5bit(data >> 6), pal5bit(data >> 11), pal5bit(data >> 1));
}
/***************************************************************************
Tilemaps: Tiles Set & Window
Each entry in the Tiles Set RAM uses 2 words to specify a starting
tile code and a color code. This adds 16 consecutive tiles with
that color code to the set of available tiles.
Offset: Bits: Value:
0.w fedc ---- ---- ----
---- ba98 7654 ---- Color Code
---- ---- ---- 3210 Code High Bits
2.w Code Low Bits
***************************************************************************/
/***************************************************************************
Tilemaps: Rendering
***************************************************************************/
/* A 2048 x 2048 virtual tilemap */
#define BIG_NX (0x100)
#define BIG_NY (0x100)
/* A smaller 512 x 256 window defines the actual tilemap */
#define WIN_NX (0x40)
#define WIN_NY (0x20)
//#define WIN_NX (0x40+1)
//#define WIN_NY (0x20+1)
/* 8x8x4 tiles only */
inline void hyprduel_state::get_tile_info( tile_data &tileinfo, int tile_index, int layer, uint16_t *vram)
{
uint16_t code;
int table_index;
uint32_t tile;
/* The actual tile index depends on the window */
tile_index = ((tile_index / WIN_NX + m_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX +
((tile_index % WIN_NX + m_window[layer * 2 + 1] / 8) % BIG_NX);
/* Fetch the code */
code = vram[tile_index];
/* Use it as an index into the tiles set table */
table_index = ((code & 0x1ff0) >> 4 ) * 2;
tile = (m_tiletable[table_index + 0] << 16) + m_tiletable[table_index + 1];
if (code & 0x8000) /* Special: draw a tile of a single color (i.e. not from the gfx ROMs) */
{
int _code = code & 0x000f;
tileinfo.pen_data = m_empty_tiles.get() + _code * 16 * 16;
tileinfo.palette_base = ((code & 0x0ff0)) + 0x1000;
tileinfo.flags = 0;
tileinfo.group = 0;
}
else
{
tileinfo.group = 0;
SET_TILE_INFO_MEMBER(0,
(tile & 0xfffff) + (code & 0xf),
(((tile & 0x0ff00000) >> 20)) + 0x100,
TILE_FLIPXY((code & 0x6000) >> 13));
}
}
/* 8x8x4 or 8x8x8 tiles. It's the tile's color that decides: if its low 4
bits are high ($f,$1f,$2f etc) the tile is 8bpp, otherwise it's 4bpp */
inline void hyprduel_state::get_tile_info_8bit( tile_data &tileinfo, int tile_index, int layer, uint16_t *vram )
{
uint16_t code;
int table_index;
uint32_t tile;
/* The actual tile index depends on the window */
tile_index = ((tile_index / WIN_NX + m_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX +
((tile_index % WIN_NX + m_window[layer * 2 + 1] / 8) % BIG_NX);
/* Fetch the code */
code = vram[tile_index];
/* Use it as an index into the tiles set table */
table_index = ((code & 0x1ff0) >> 4) * 2;
tile = (m_tiletable[table_index + 0] << 16) + m_tiletable[table_index + 1];
if (code & 0x8000) /* Special: draw a tile of a single color (i.e. not from the gfx ROMs) */
{
int _code = code & 0x000f;
tileinfo.pen_data = m_empty_tiles.get() + _code * 16 * 16;
tileinfo.palette_base = ((code & 0x0ff0)) + 0x1000;
tileinfo.flags = 0;
tileinfo.group = 0;
}
else if ((tile & 0x00f00000) == 0x00f00000) /* draw tile as 8bpp */
{
tileinfo.group = 1;
SET_TILE_INFO_MEMBER(1,
(tile & 0xfffff) + 2*(code & 0xf),
((tile & 0x0f000000) >> 24) + 0x10,
TILE_FLIPXY((code & 0x6000) >> 13));
}
else
{
tileinfo.group = 0;
SET_TILE_INFO_MEMBER(0,
(tile & 0xfffff) + (code & 0xf),
(((tile & 0x0ff00000) >> 20)) + 0x100,
TILE_FLIPXY((code & 0x6000) >> 13));
}
}
/* 16x16x4 or 16x16x8 tiles. It's the tile's color that decides: if its low 4
bits are high ($f,$1f,$2f etc) the tile is 8bpp, otherwise it's 4bpp */
inline void hyprduel_state::get_tile_info_16x16_8bit( tile_data &tileinfo, int tile_index, int layer, uint16_t *vram )
{
uint16_t code;
int table_index;
uint32_t tile;
/* The actual tile index depends on the window */
tile_index = ((tile_index / WIN_NX + m_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX +
((tile_index % WIN_NX + m_window[layer * 2 + 1] / 8) % BIG_NX);
/* Fetch the code */
code = vram[tile_index];
/* Use it as an index into the tiles set table */
table_index = ((code & 0x1ff0) >> 4) * 2;
tile = (m_tiletable[table_index + 0] << 16) + m_tiletable[table_index + 1];
if (code & 0x8000) /* Special: draw a tile of a single color (i.e. not from the gfx ROMs) */
{
int _code = code & 0x000f;
tileinfo.pen_data = m_empty_tiles.get() + _code * 16 * 16;
tileinfo.palette_base = ((code & 0x0ff0)) + 0x1000;
tileinfo.flags = 0;
tileinfo.group = 0;
}
else if ((tile & 0x00f00000) == 0x00f00000) /* draw tile as 8bpp */
{
tileinfo.group = 1;
SET_TILE_INFO_MEMBER(3,
(tile & 0xfffff) + 8*(code & 0xf),
((tile & 0x0f000000) >> 24) + 0x10,
TILE_FLIPXY((code & 0x6000) >> 13));
}
else
{
tileinfo.group = 0;
SET_TILE_INFO_MEMBER(2,
(tile & 0xfffff) + 4*(code & 0xf),
(((tile & 0x0ff00000) >> 20)) + 0x100,
TILE_FLIPXY((code & 0x6000) >> 13));
}
}
inline void hyprduel_state::vram_w( offs_t offset, uint16_t data, uint16_t mem_mask, int layer, uint16_t *vram )
{
COMBINE_DATA(&vram[offset]);
{
/* Account for the window */
int col = (offset % BIG_NX) - ((m_window[layer * 2 + 1] / 8) % BIG_NX);
int row = (offset / BIG_NX) - ((m_window[layer * 2 + 0] / 8) % BIG_NY);
if (col < -(BIG_NX-WIN_NX))
col += (BIG_NX-WIN_NX) + WIN_NX;
if (row < -(BIG_NY-WIN_NY))
row += (BIG_NY-WIN_NY) + WIN_NY;
if ((col >= 0) && (col < WIN_NX) && (row >= 0) && (row < WIN_NY))
m_bg_tilemap[layer]->mark_tile_dirty(row * WIN_NX + col);
}
}
TILE_GET_INFO_MEMBER(hyprduel_state::get_tile_info_0_8bit)
{
get_tile_info_8bit(tileinfo, tile_index, 0, m_vram_0);
}
TILE_GET_INFO_MEMBER(hyprduel_state::get_tile_info_1_8bit)
{
get_tile_info_8bit(tileinfo, tile_index, 1, m_vram_1);
}
TILE_GET_INFO_MEMBER(hyprduel_state::get_tile_info_2_8bit)
{
get_tile_info_8bit(tileinfo, tile_index, 2, m_vram_2);
}
WRITE16_MEMBER(hyprduel_state::vram_0_w)
{
vram_w(offset, data, mem_mask, 0, m_vram_0);
}
WRITE16_MEMBER(hyprduel_state::vram_1_w)
{
vram_w(offset, data, mem_mask, 1, m_vram_1);
}
WRITE16_MEMBER(hyprduel_state::vram_2_w)
{
vram_w(offset, data, mem_mask, 2, m_vram_2);
}
/* Dirty the relevant tilemap when its window changes */
WRITE16_MEMBER(hyprduel_state::window_w)
{
uint16_t olddata = m_window[offset];
uint16_t newdata = COMBINE_DATA(&m_window[offset]);
if (newdata != olddata)
{
offset /= 2;
m_bg_tilemap[offset]->mark_all_dirty();
}
}
/***************************************************************************
Video Init Routines
***************************************************************************/
/*
Sprites are not tile based, so we decode their graphics at runtime.
*/
void hyprduel_state::alloc_empty_tiles( )
{
int code,i;
m_empty_tiles = std::make_unique<uint8_t[]>(16*16*16);
save_pointer(NAME(m_empty_tiles.get()), 16*16*16);
for (code = 0; code < 0x10; code++)
for (i = 0; i < 16 * 16; i++)
m_empty_tiles[16 * 16 * code + i] = code;
}
void hyprduel_state::postload()
{
int i;
for (i = 0; i < 3; i++)
{
uint16_t wx = m_window[i * 2 + 1];
uint16_t wy = m_window[i * 2 + 0];
m_bg_tilemap[i]->set_scrollx(0, m_scroll[i * 2 + 1] - wx - (wx & 7));
m_bg_tilemap[i]->set_scrolly(0, m_scroll[i * 2 + 0] - wy - (wy & 7));
m_bg_tilemap[i]->mark_all_dirty();
}
}
void hyprduel_state::expand_gfx1()
{
uint8_t *base_gfx = memregion("gfx1")->base();
uint32_t length = 2 * memregion("gfx1")->bytes();
m_expanded_gfx1 = std::make_unique<uint8_t[]>(length);
for (int i = 0; i < length; i += 2)
{
uint8_t src = base_gfx[i / 2];
m_expanded_gfx1[i+0] = src & 15;
m_expanded_gfx1[i+1] = src >> 4;
}
}
VIDEO_START_MEMBER(hyprduel_state,common_14220)
{
expand_gfx1();
alloc_empty_tiles();
m_tiletable_old = std::make_unique<uint16_t[]>(m_tiletable.bytes() / 2);
m_dirtyindex = std::make_unique<uint8_t[]>(m_tiletable.bytes() / 4);
save_pointer(NAME(m_tiletable_old.get()), m_tiletable.bytes() / 2);
save_pointer(NAME(m_dirtyindex.get()), m_tiletable.bytes() / 4);
m_bg_tilemap[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(hyprduel_state::get_tile_info_0_8bit),this), TILEMAP_SCAN_ROWS, 8, 8, WIN_NX, WIN_NY);
m_bg_tilemap[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(hyprduel_state::get_tile_info_1_8bit),this), TILEMAP_SCAN_ROWS, 8, 8, WIN_NX, WIN_NY);
m_bg_tilemap[2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(hyprduel_state::get_tile_info_2_8bit),this), TILEMAP_SCAN_ROWS, 8, 8, WIN_NX, WIN_NY);
m_bg_tilemap[0]->map_pen_to_layer(0, 15, TILEMAP_PIXEL_TRANSPARENT);
m_bg_tilemap[0]->map_pen_to_layer(1, 255, TILEMAP_PIXEL_TRANSPARENT);
m_bg_tilemap[1]->map_pen_to_layer(0, 15, TILEMAP_PIXEL_TRANSPARENT);
m_bg_tilemap[1]->map_pen_to_layer(1, 255, TILEMAP_PIXEL_TRANSPARENT);
m_bg_tilemap[2]->map_pen_to_layer(0, 15, TILEMAP_PIXEL_TRANSPARENT);
m_bg_tilemap[2]->map_pen_to_layer(1, 255, TILEMAP_PIXEL_TRANSPARENT);
m_bg_tilemap[0]->set_scrolldx(0, 0);
m_bg_tilemap[1]->set_scrolldx(0, 0);
m_bg_tilemap[2]->set_scrolldx(0, 0);
/* Set up save state */
save_item(NAME(m_sprite_xoffs));
save_item(NAME(m_sprite_yoffs));
machine().save().register_postload(save_prepost_delegate(FUNC(hyprduel_state::postload), this));
}
VIDEO_START_MEMBER(hyprduel_state,hyprduel_14220)
{
VIDEO_START_CALL_MEMBER(common_14220);
}
VIDEO_START_MEMBER(hyprduel_state,magerror_14220)
{
VIDEO_START_CALL_MEMBER(common_14220);
}
/***************************************************************************
Video Registers
Offset: Bits: Value:
0.w Number Of Sprites To Draw
2.w f--- ---- ---- ---- Disabled Sprites Layer Priority
-edc ---- ---- ----
---- ba-- ---- ---- Sprites Masked Layer
---- --98 ---- ---- Sprites Priority
---- ---- 765- ----
---- ---- ---4 3210 Sprites Masked Number
4.w Sprites Y Offset
6.w Sprites X Offset
8.w Sprites Color Codes Start
-
10.w fedc ba98 76-- ----
---- ---- --54 ---- Layer 2 Priority (3 backmost, 0 frontmost)
---- ---- ---- 32-- Layer 1 Priority
---- ---- ---- --10 Layer 0 Priority
12.w Backround Color
***************************************************************************/
/***************************************************************************
Sprites Drawing
Offset: Bits: Value:
0.w fedc b--- ---- ---- Priority (0 = Max)
---- -a98 7654 3210 X
2.w fedc ba-- ---- ---- Zoom (Both X & Y)
---- --98 7654 3210 Y
4.w f--- ---- ---- ---- Flip X
-e-- ---- ---- ---- Flip Y
--dc b--- ---- ---- Size X *
---- -a98 ---- ---- Size Y *
---- ---- 7654 ---- Color
---- ---- ---- 3210 Code High Bits **
6.w Code Low Bits **
* 8 pixel increments
** 8x8 pixel increments
***************************************************************************/
/* Draw sprites */
void hyprduel_state::draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect )
{
uint8_t *base_gfx4 = m_expanded_gfx1.get();
uint8_t *base_gfx8 = memregion("gfx1")->base();
uint32_t gfx_size = memregion("gfx1")->bytes();
int max_x = (m_spriteregs[1]+1) * 2;
int max_y = (m_spriteregs[0]+1) * 2;
int max_sprites = m_spriteram.bytes() / 8;
int sprites = m_videoregs[0x00 / 2] % max_sprites;
int color_start = ((m_videoregs[0x08 / 2] & 0xf) << 4) + 0x100;
int i, j, pri;
static const int primask[4] = { 0x0000, 0xff00, 0xff00|0xf0f0, 0xff00|0xf0f0|0xcccc };
uint16_t *src;
int inc;
if (sprites == 0)
return;
for (i = 0; i < 0x20; i++)
{
if (!(m_videoregs[0x02 / 2] & 0x8000))
{
src = m_spriteram + (sprites - 1) * (8 / 2);
inc = -(8 / 2);
} else {
src = m_spriteram;
inc = (8 / 2);
}
for (j = 0; j < sprites; j++)
{
int x, y, attr, code, color, flipx, flipy, zoom, curr_pri, width, height;
/* Exponential zoom table extracted from daitoride */
static const int zoomtable[0x40] =
{
0xAAC,0x800,0x668,0x554,0x494,0x400,0x390,0x334,
0x2E8,0x2AC,0x278,0x248,0x224,0x200,0x1E0,0x1C8,
0x1B0,0x198,0x188,0x174,0x164,0x154,0x148,0x13C,
0x130,0x124,0x11C,0x110,0x108,0x100,0x0F8,0x0F0,
0x0EC,0x0E4,0x0DC,0x0D8,0x0D4,0x0CC,0x0C8,0x0C4,
0x0C0,0x0BC,0x0B8,0x0B4,0x0B0,0x0AC,0x0A8,0x0A4,
0x0A0,0x09C,0x098,0x094,0x090,0x08C,0x088,0x080,
0x078,0x070,0x068,0x060,0x058,0x050,0x048,0x040
};
x = src[0];
curr_pri = (x & 0xf800) >> 11;
if ((curr_pri == 0x1f) || (curr_pri != i))
{
src += inc;
continue;
}
pri = (m_videoregs[0x02 / 2] & 0x0300) >> 8;
if (!(m_videoregs[0x02 / 2] & 0x8000))
{
if (curr_pri > (m_videoregs[0x02 / 2] & 0x1f))
pri = (m_videoregs[0x02 / 2] & 0x0c00) >> 10;
}
y = src[1];
attr = src[2];
code = src[3];
flipx = attr & 0x8000;
flipy = attr & 0x4000;
color = (attr & 0xf0) >> 4;
zoom = zoomtable[(y & 0xfc00) >> 10] << (16 - 8);
x = (x & 0x07ff) - m_sprite_xoffs;
y = (y & 0x03ff) - m_sprite_yoffs;
width = (((attr >> 11) & 0x7) + 1) * 8;
height = (((attr >> 8) & 0x7) + 1) * 8;
uint32_t gfxstart = (8 * 8 * 4 / 8) * (((attr & 0x000f) << 16) + code);
if (flip_screen())
{
flipx = !flipx; x = max_x - x - width;
flipy = !flipy; y = max_y - y - height;
}
if (color == 0xf) /* 8bpp */
{
/* Bounds checking */
if ((gfxstart + width * height - 1) >= gfx_size)
continue;
gfx_element gfx(m_palette, base_gfx8 + gfxstart, width, height, width, m_palette->entries(), 0, 256);
gfx.prio_zoom_transpen(bitmap,cliprect,
0,
color_start >> 4,
flipx, flipy,
x, y,
zoom, zoom,
screen.priority(),primask[pri], 255);
}
else
{
/* Bounds checking */
if ((gfxstart + width / 2 * height - 1) >= gfx_size)
continue;
gfx_element gfx(m_palette, base_gfx4 + 2 * gfxstart, width, height, width, m_palette->entries(), 0, 16);
gfx.prio_zoom_transpen(bitmap,cliprect,
0,
color + color_start,
flipx, flipy,
x, y,
zoom, zoom,
screen.priority(),primask[pri], 15);
}
#if 0
{ /* Display priority + zoom on each sprite */
char buf[80];
sprintf(buf, "%02X %02X",((src[ 0 ] & 0xf800) >> 11)^0x1f,((src[ 1 ] & 0xfc00) >> 10) );
ui_draw_text(buf, x, y);
}
#endif
src += inc;
}
}
}
/***************************************************************************
Screen Drawing
***************************************************************************/
WRITE16_MEMBER(hyprduel_state::scrollreg_w)
{
uint16_t window = m_window[offset];
COMBINE_DATA(&m_scroll[offset]);
if (offset & 0x01)
m_bg_tilemap[offset / 2]->set_scrollx(0, m_scroll[offset] - window - (window & 7));
else
m_bg_tilemap[offset / 2]->set_scrolly(0, m_scroll[offset] - window - (window & 7));
}
WRITE16_MEMBER(hyprduel_state::scrollreg_init_w)
{
int i;
for (i = 0; i < 3; i++)
{
uint16_t wx = m_window[i * 2 + 1];
uint16_t wy = m_window[i * 2 + 0];
m_scroll[i * 2 + 1] = data;
m_scroll[i * 2 + 0] = data;
m_bg_tilemap[i]->set_scrollx(0, data - wx - (wx & 7));
m_bg_tilemap[i]->set_scrolly(0, data - wy - (wy & 7));
}
}
void hyprduel_state::draw_layers( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri, int layers_ctrl )
{
uint16_t layers_pri = m_videoregs[0x10/2];
int layer;
/* Draw all the layers with priority == pri */
for (layer = 2; layer >= 0; layer--) // tilemap[2] below?
{
if ( pri == ((layers_pri >> (layer*2)) & 3) )
{
if (layers_ctrl & (1 << layer)) // for debug
m_bg_tilemap[layer]->draw(screen, bitmap, cliprect, 0, 1 << (3 - pri));
}
}
}
/* Dirty tilemaps when the tiles set changes */
void hyprduel_state::dirty_tiles( int layer, uint16_t *vram )
{
int col, row;
for (row = 0; row < WIN_NY; row++)
{
for (col = 0; col < WIN_NX; col++)
{
int offset = (col + m_window[layer * 2 + 1] / 8) % BIG_NX + ((row + m_window[layer * 2 + 0] / 8) % BIG_NY) * BIG_NX;
uint16_t code = vram[offset];
if (!(code & 0x8000) && m_dirtyindex[(code & 0x1ff0) >> 4])
m_bg_tilemap[layer]->mark_tile_dirty(row * WIN_NX + col);
}
}
}
uint32_t hyprduel_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int i, pri, layers_ctrl = -1;
uint16_t screenctrl = *m_screenctrl;
{
int dirty = 0;
memset(m_dirtyindex.get(), 0, m_tiletable.bytes() / 4);
for (i = 0; i < m_tiletable.bytes() / 4; i++)
{
uint32_t tile_new = (m_tiletable[2 * i + 0] << 16 ) + m_tiletable[2 * i + 1];
uint32_t tile_old = (m_tiletable_old[2 * i + 0] << 16 ) + m_tiletable_old[2 * i + 1];
if ((tile_new ^ tile_old) & 0x0fffffff)
{
m_dirtyindex[i] = 1;
dirty = 1;
}
}
memcpy(m_tiletable_old.get(), m_tiletable, m_tiletable.bytes());
if (dirty)
{
dirty_tiles(0, m_vram_0);
dirty_tiles(1, m_vram_1);
dirty_tiles(2, m_vram_2);
}
}
m_sprite_xoffs = m_videoregs[0x06 / 2] - (m_spriteregs[1]+1);
m_sprite_yoffs = m_videoregs[0x04 / 2] - (m_spriteregs[0]+1);
/* The background color is selected by a register */
screen.priority().fill(0, cliprect);
bitmap.fill((m_videoregs[0x12 / 2] & 0x0fff) + 0x1000, cliprect);
/* Screen Control Register:
f--- ---- ---- ---- ?
-edc b--- ---- ----
---- -a98 ---- ---- ? Leds
---- ---- 7--- ---- 16x16 Tiles (Layer 2)
---- ---- -6-- ---- 16x16 Tiles (Layer 1)
---- ---- --5- ---- 16x16 Tiles (Layer 0)
---- ---- ---4 32--
---- ---- ---- --1- ? Blank Screen
---- ---- ---- ---0 Flip Screen */
if (screenctrl & 2)
return 0;
flip_screen_set(screenctrl & 1);
#if 0
if (machine().input().code_pressed(KEYCODE_Z))
{ int msk = 0;
if (machine().input().code_pressed(KEYCODE_Q)) msk |= 0x01;
if (machine().input().code_pressed(KEYCODE_W)) msk |= 0x02;
if (machine().input().code_pressed(KEYCODE_E)) msk |= 0x04;
if (machine().input().code_pressed(KEYCODE_A)) msk |= 0x08;
if (msk != 0)
{
bitmap.fill(0, cliprect);
layers_ctrl &= msk;
}
popmessage("%x-%x-%x:%04x %04x %04x",
m_videoregs[0x10/2]&3,(m_videoregs[0x10/2] & 0xc) >> 2, (m_videoregs[0x10/2] & 0x30) >> 4,
m_videoregs[0x02/2], m_videoregs[0x08/2],
*m_screenctrl);
}
#endif
for (pri = 3; pri >= 0; pri--)
draw_layers(screen, bitmap, cliprect, pri, layers_ctrl);
if (layers_ctrl & 0x08)
draw_sprites(screen, bitmap, cliprect);
return 0;
}