Rewritten Imagetek i4100 / i4220 / i4300 video display processor family, hooked it up to metro.cpp [Angelo Salese]

This commit is contained in:
angelosa 2017-11-21 07:04:52 +01:00
parent c268543e40
commit 56828c2446
6 changed files with 1609 additions and 1665 deletions

View File

@ -1021,3 +1021,15 @@ if (VIDEOS["BT459"]~=null) then
MAME_DIR .. "src/devices/video/bt459.h", MAME_DIR .. "src/devices/video/bt459.h",
} }
end end
--------------------------------------------------
--
--@src/devices/video/imagetek_i4100.h,VIDEOS["I4100"] = true
--------------------------------------------------
if (VIDEOS["I4100"]~=null) then
files {
MAME_DIR .. "src/devices/video/imagetek_i4100.cpp",
MAME_DIR .. "src/devices/video/imagetek_i4100.h",
}
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,229 @@
// license:BSD-3-Clause
// copyright-holders:Luca Elia,David Haywood,Angelo Salese
/***************************************************************************
Imagetek I4100 / I4220 / I4300 device files
***************************************************************************/
#ifndef MAME_VIDEO_I4100_H
#define MAME_VIDEO_I4100_H
#pragma once
#include "screen.h"
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_I4100_ADD(tag) \
MCFG_DEVICE_ADD((tag), I4100, (0))
#define MCFG_I4220_ADD(tag) \
MCFG_DEVICE_ADD((tag), I4220, (0))
#define MCFG_I4300_ADD(tag) \
MCFG_DEVICE_ADD((tag), I4300, (0))
#define MCFG_I4100_GFXDECODE(gfxtag) \
imagetek_i4100_device::static_set_gfxdecode_tag(*device, ("^" gfxtag));
#define MCFG_I4100_BLITTER_END_CALLBACK(_devcb) \
devcb = &imagetek_i4100_device::static_set_blitter_irq_callback(*device, DEVCB_##_devcb);
#define MCFG_I4100_TILEMAP_XOFFSETS(_a, _b, _c) \
imagetek_i4100_device::static_set_tmap_xoffsets(*device, _a, _b, _c);
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> i4100_device
class imagetek_i4100_device : public device_t,
public device_video_interface
{
public:
// construction/destruction
imagetek_i4100_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_ADDRESS_MAP(map, 16);
static void static_set_gfxdecode_tag(device_t &device, const char *tag);
static void static_set_tmap_xoffsets(device_t &device, int x1, int x2, int x3);
template <class Object> static devcb_base &static_set_blitter_irq_callback(device_t &device, Object &&cb) { return downcast<imagetek_i4100_device &>(device).m_blit_irq_cb.set_callback(std::forward<Object>(cb)); }
// I/O operations
DECLARE_READ16_MEMBER( vram_0_r );
DECLARE_READ16_MEMBER( vram_1_r );
DECLARE_READ16_MEMBER( vram_2_r );
DECLARE_WRITE16_MEMBER( vram_0_w );
DECLARE_WRITE16_MEMBER( vram_1_w );
DECLARE_WRITE16_MEMBER( vram_2_w );
DECLARE_READ16_MEMBER( rmw_vram_0_r );
DECLARE_READ16_MEMBER( rmw_vram_1_r );
DECLARE_READ16_MEMBER( rmw_vram_2_r );
DECLARE_WRITE16_MEMBER( rmw_vram_0_w );
DECLARE_WRITE16_MEMBER( rmw_vram_1_w );
DECLARE_WRITE16_MEMBER( rmw_vram_2_w );
DECLARE_READ16_MEMBER( scratchram_r );
DECLARE_WRITE16_MEMBER( scratchram_w );
DECLARE_READ16_MEMBER( spriteram_r );
DECLARE_WRITE16_MEMBER( spriteram_w );
DECLARE_READ16_MEMBER( tiletable_r );
DECLARE_WRITE16_MEMBER( tiletable_w );
DECLARE_READ16_MEMBER( sprite_count_r );
DECLARE_WRITE16_MEMBER( sprite_count_w );
DECLARE_READ16_MEMBER( sprite_priority_r );
DECLARE_WRITE16_MEMBER( sprite_priority_w );
DECLARE_READ16_MEMBER( sprite_xoffset_r );
DECLARE_WRITE16_MEMBER( sprite_xoffset_w );
DECLARE_READ16_MEMBER( sprite_yoffset_r );
DECLARE_WRITE16_MEMBER( sprite_yoffset_w );
DECLARE_READ16_MEMBER( sprite_color_code_r );
DECLARE_WRITE16_MEMBER( sprite_color_code_w );
DECLARE_READ16_MEMBER( layer_priority_r );
DECLARE_WRITE16_MEMBER( layer_priority_w );
DECLARE_READ16_MEMBER( background_color_r );
DECLARE_WRITE16_MEMBER( background_color_w );
DECLARE_READ16_MEMBER( screen_xoffset_r );
DECLARE_WRITE16_MEMBER( screen_xoffset_w );
DECLARE_READ16_MEMBER( screen_yoffset_r );
DECLARE_WRITE16_MEMBER( screen_yoffset_w );
DECLARE_READ16_MEMBER( window_r );
DECLARE_WRITE16_MEMBER( window_w );
DECLARE_READ16_MEMBER( scroll_r );
DECLARE_WRITE16_MEMBER( scroll_w );
DECLARE_READ16_MEMBER( gfxrom_r );
DECLARE_WRITE16_MEMBER( crtc_vert_w );
DECLARE_WRITE16_MEMBER( crtc_horz_w );
DECLARE_WRITE16_MEMBER( crtc_unlock_w );
DECLARE_WRITE16_MEMBER( blitter_w );
DECLARE_WRITE16_MEMBER( screen_ctrl_w );
DECLARE_WRITE16_MEMBER( rombank_w );
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
protected:
imagetek_i4100_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool has_ext_tiles);
// device-level overrides
//virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
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_scratchram;
required_shared_ptr<uint16_t> m_blitter_regs;
required_shared_ptr<uint16_t> m_spriteram;
required_shared_ptr<uint16_t> m_tiletable;
required_shared_ptr<uint16_t> m_window;
required_shared_ptr<uint16_t> m_scroll;
required_device<palette_device> m_palette;
required_device<gfxdecode_device> m_gfxdecode;
required_region_ptr<uint8_t> m_gfxrom;
std::unique_ptr<uint8_t[]> m_expanded_gfx1;
devcb_write_line m_blit_irq_cb;
uint16_t m_rombank;
size_t m_gfxrom_size;
bool m_crtc_unlock;
uint16_t m_sprite_count;
uint16_t m_sprite_priority;
uint16_t m_sprite_xoffset,m_sprite_yoffset;
uint16_t m_sprite_color_code;
uint8_t m_layer_priority[3];
uint16_t m_background_color;
uint16_t m_screen_xoffset,m_screen_yoffset;
bool m_layer_tile_select[3];
bool m_screen_blank;
bool m_screen_flip;
const bool m_support_8bpp, m_support_16x16;
int m_tilemap_scrolldx[3];
void blt_write( address_space &space, const int tmap, const offs_t offs, const uint16_t data, const uint16_t mask );
enum
{
TIMER_BLIT_END = 1
};
emu_timer *m_blit_done_timer;
void draw_layers( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri );
inline uint8_t get_tile_pix( uint16_t code, uint8_t x, uint8_t y, bool big, uint16_t *pix );
void draw_tilemap( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, uint32_t flags, uint32_t pcode,
int sx, int sy, int wx, int wy, bool big, uint16_t *tilemapram, int layer );
void draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect );
void expand_gfx1();
// A 2048 x 2048 virtual tilemap
static constexpr uint32_t BIG_NX = (0x100);
static constexpr uint32_t BIG_NY = (0x100);
// A smaller 512 x 256 window defines the actual tilemap
static constexpr uint32_t WIN_NX = (0x40);
static constexpr uint32_t WIN_NY = (0x20);
bool m_inited_hack;
};
class imagetek_i4220_device : public imagetek_i4100_device
{
public:
// construction/destruction
imagetek_i4220_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_ADDRESS_MAP(v2_map, 16);
// needed by Blazing Tornado / Grand Striker 2 for mixing with PSAC
// (it's unknown how the chip enables external sync)
uint16_t get_background_pen() { return m_background_color; };
protected:
};
class imagetek_i4300_device : public imagetek_i4100_device
{
public:
// construction/destruction
imagetek_i4300_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_ADDRESS_MAP(v3_map, 16);
protected:
};
// device type definition
DECLARE_DEVICE_TYPE(I4100, imagetek_i4100_device)
DECLARE_DEVICE_TYPE(I4220, imagetek_i4220_device)
DECLARE_DEVICE_TYPE(I4300, imagetek_i4300_device)
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
#endif // MAME_VIDEO_I4100_H

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@
#include "sound/ym2151.h" #include "sound/ym2151.h"
#include "sound/es8712.h" #include "sound/es8712.h"
#include "video/k053936.h" #include "video/k053936.h"
#include "video/imagetek_i4100.h"
#include "machine/eepromser.h" #include "machine/eepromser.h"
#include "machine/gen_latch.h" #include "machine/gen_latch.h"
#include "screen.h" #include "screen.h"
@ -20,8 +21,7 @@ public:
enum enum
{ {
TIMER_KARATOUR_IRQ, TIMER_KARATOUR_IRQ,
TIMER_MOUJA_IRQ, TIMER_MOUJA_IRQ
TIMER_METRO_BLIT_DONE
}; };
metro_state(const machine_config &mconfig, device_type type, const char *tag) metro_state(const machine_config &mconfig, device_type type, const char *tag)
@ -31,27 +31,17 @@ public:
m_oki(*this, "oki"), m_oki(*this, "oki"),
m_ymsnd(*this, "ymsnd"), m_ymsnd(*this, "ymsnd"),
m_essnd(*this, "essnd"), m_essnd(*this, "essnd"),
m_vdp(*this, "vdp"),
m_vdp2(*this, "vdp2"),
m_vdp3(*this, "vdp3"),
m_k053936(*this, "k053936") , m_k053936(*this, "k053936") ,
m_eeprom(*this, "eeprom"), m_eeprom(*this, "eeprom"),
m_gfxdecode(*this, "gfxdecode"), m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"), m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_soundlatch(*this, "soundlatch"), m_soundlatch(*this, "soundlatch"),
m_vram_0(*this, "vram_0"),
m_vram_1(*this, "vram_1"),
m_vram_2(*this, "vram_2"),
m_spriteram(*this, "spriteram"),
m_spriteregs(*this, "spriteregs"),
m_tiletable(*this, "tiletable"),
m_blitter_regs(*this, "blitter_regs"),
m_scroll(*this, "scroll"),
m_window(*this, "window"),
m_irq_enable(*this, "irq_enable"), m_irq_enable(*this, "irq_enable"),
m_irq_levels(*this, "irq_levels"), m_irq_levels(*this, "irq_levels"),
m_irq_vectors(*this, "irq_vectors"), m_irq_vectors(*this, "irq_vectors"),
m_rombank(*this, "rombank"),
m_videoregs(*this, "videoregs"),
m_screenctrl(*this, "screenctrl"),
m_input_sel(*this, "input_sel"), m_input_sel(*this, "input_sel"),
m_k053936_ram(*this, "k053936_ram") m_k053936_ram(*this, "k053936_ram")
{ } { }
@ -70,25 +60,13 @@ public:
DECLARE_WRITE8_MEMBER(daitorid_portb_w); DECLARE_WRITE8_MEMBER(daitorid_portb_w);
DECLARE_WRITE16_MEMBER(metro_coin_lockout_1word_w); DECLARE_WRITE16_MEMBER(metro_coin_lockout_1word_w);
DECLARE_WRITE16_MEMBER(metro_coin_lockout_4words_w); DECLARE_WRITE16_MEMBER(metro_coin_lockout_4words_w);
DECLARE_READ16_MEMBER(metro_bankedrom_r);
DECLARE_WRITE16_MEMBER(metro_blitter_w);
DECLARE_READ16_MEMBER(balcube_dsw_r); DECLARE_READ16_MEMBER(balcube_dsw_r);
DECLARE_READ16_MEMBER(karatour_vram_0_r);
DECLARE_READ16_MEMBER(karatour_vram_1_r);
DECLARE_READ16_MEMBER(karatour_vram_2_r);
DECLARE_WRITE16_MEMBER(karatour_vram_0_w);
DECLARE_WRITE16_MEMBER(karatour_vram_1_w);
DECLARE_WRITE16_MEMBER(karatour_vram_2_w);
DECLARE_READ16_MEMBER(gakusai_input_r); DECLARE_READ16_MEMBER(gakusai_input_r);
DECLARE_WRITE16_MEMBER(blzntrnd_sound_w); DECLARE_WRITE16_MEMBER(blzntrnd_sound_w);
DECLARE_WRITE8_MEMBER(blzntrnd_sh_bankswitch_w); DECLARE_WRITE8_MEMBER(blzntrnd_sh_bankswitch_w);
DECLARE_WRITE16_MEMBER(puzzlet_irq_enable_w); DECLARE_WRITE16_MEMBER(puzzlet_irq_enable_w);
DECLARE_WRITE16_MEMBER(puzzlet_portb_w); DECLARE_WRITE16_MEMBER(puzzlet_portb_w);
DECLARE_WRITE16_MEMBER(metro_k053936_w); DECLARE_WRITE16_MEMBER(metro_k053936_w);
DECLARE_WRITE16_MEMBER(metro_vram_0_w);
DECLARE_WRITE16_MEMBER(metro_vram_1_w);
DECLARE_WRITE16_MEMBER(metro_vram_2_w);
DECLARE_WRITE16_MEMBER(metro_window_w);
DECLARE_CUSTOM_INPUT_MEMBER(custom_soundstatus_r); DECLARE_CUSTOM_INPUT_MEMBER(custom_soundstatus_r);
DECLARE_WRITE8_MEMBER(gakusai_oki_bank_hi_w); DECLARE_WRITE8_MEMBER(gakusai_oki_bank_hi_w);
DECLARE_WRITE8_MEMBER(gakusai_oki_bank_lo_w); DECLARE_WRITE8_MEMBER(gakusai_oki_bank_lo_w);
@ -98,8 +76,7 @@ public:
DECLARE_WRITE8_MEMBER(dokyusp_eeprom_bit_w); DECLARE_WRITE8_MEMBER(dokyusp_eeprom_bit_w);
DECLARE_WRITE8_MEMBER(dokyusp_eeprom_reset_w); DECLARE_WRITE8_MEMBER(dokyusp_eeprom_reset_w);
DECLARE_WRITE8_MEMBER(mouja_sound_rombank_w); DECLARE_WRITE8_MEMBER(mouja_sound_rombank_w);
DECLARE_READ16_MEMBER(gakusai_spriteregs_r); DECLARE_WRITE_LINE_MEMBER(vdp_blit_end_w);
DECLARE_WRITE16_MEMBER(gakusai_spriteregs_w);
// vmetal // vmetal
DECLARE_WRITE8_MEMBER(vmetal_control_w); DECLARE_WRITE8_MEMBER(vmetal_control_w);
@ -120,19 +97,13 @@ public:
TILE_GET_INFO_MEMBER(metro_k053936_get_tile_info); TILE_GET_INFO_MEMBER(metro_k053936_get_tile_info);
TILE_GET_INFO_MEMBER(metro_k053936_gstrik2_get_tile_info); TILE_GET_INFO_MEMBER(metro_k053936_gstrik2_get_tile_info);
TILEMAP_MAPPER_MEMBER(tilemap_scan_gstrik2); TILEMAP_MAPPER_MEMBER(tilemap_scan_gstrik2);
DECLARE_VIDEO_START(metro_i4100);
DECLARE_VIDEO_START(metro_i4220);
DECLARE_VIDEO_START(metro_i4220_dx_tmap);
DECLARE_VIDEO_START(metro_i4220_dx_sprite);
DECLARE_VIDEO_START(metro_i4300);
DECLARE_VIDEO_START(blzntrnd); DECLARE_VIDEO_START(blzntrnd);
DECLARE_VIDEO_START(gstrik2); DECLARE_VIDEO_START(gstrik2);
uint32_t screen_update_metro(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); uint32_t screen_update_psac_vdp2_mix(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
INTERRUPT_GEN_MEMBER(metro_vblank_interrupt); INTERRUPT_GEN_MEMBER(metro_vblank_interrupt);
INTERRUPT_GEN_MEMBER(metro_periodic_interrupt); INTERRUPT_GEN_MEMBER(metro_periodic_interrupt);
INTERRUPT_GEN_MEMBER(karatour_interrupt); INTERRUPT_GEN_MEMBER(karatour_interrupt);
INTERRUPT_GEN_MEMBER(puzzlet_interrupt); INTERRUPT_GEN_MEMBER(puzzlet_interrupt);
TIMER_CALLBACK_MEMBER(metro_blit_done);
IRQ_CALLBACK_MEMBER(metro_irq_callback); IRQ_CALLBACK_MEMBER(metro_irq_callback);
DECLARE_READ_LINE_MEMBER(metro_rxd_r); DECLARE_READ_LINE_MEMBER(metro_rxd_r);
@ -147,47 +118,25 @@ private:
optional_device<okim6295_device> m_oki; optional_device<okim6295_device> m_oki;
optional_device<device_t> m_ymsnd; // TODO set correct type optional_device<device_t> m_ymsnd; // TODO set correct type
optional_device<es8712_device> m_essnd; optional_device<es8712_device> m_essnd;
optional_device<imagetek_i4100_device> m_vdp;
optional_device<imagetek_i4220_device> m_vdp2;
optional_device<imagetek_i4300_device> m_vdp3;
optional_device<k053936_device> m_k053936; optional_device<k053936_device> m_k053936;
optional_device<eeprom_serial_93cxx_device> m_eeprom; optional_device<eeprom_serial_93cxx_device> m_eeprom;
required_device<gfxdecode_device> m_gfxdecode; required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen; required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
optional_device<generic_latch_8_device> m_soundlatch; optional_device<generic_latch_8_device> m_soundlatch;
/* memory pointers */ /* memory pointers */
optional_shared_ptr<uint16_t> m_vram_0;
optional_shared_ptr<uint16_t> m_vram_1;
optional_shared_ptr<uint16_t> m_vram_2;
required_shared_ptr<uint16_t> m_spriteram;
required_shared_ptr<uint16_t> m_spriteregs;
optional_shared_ptr<uint16_t> m_tiletable;
optional_shared_ptr<uint16_t> m_blitter_regs;
optional_shared_ptr<uint16_t> m_scroll;
optional_shared_ptr<uint16_t> m_window;
optional_shared_ptr<uint16_t> m_irq_enable; optional_shared_ptr<uint16_t> m_irq_enable;
optional_shared_ptr<uint16_t> m_irq_levels; optional_shared_ptr<uint16_t> m_irq_levels;
optional_shared_ptr<uint16_t> m_irq_vectors; optional_shared_ptr<uint16_t> m_irq_vectors;
optional_shared_ptr<uint16_t> m_rombank;
required_shared_ptr<uint16_t> m_videoregs;
optional_shared_ptr<uint16_t> m_screenctrl;
optional_shared_ptr<uint16_t> m_input_sel; optional_shared_ptr<uint16_t> m_input_sel;
optional_shared_ptr<uint16_t> m_k053936_ram; optional_shared_ptr<uint16_t> m_k053936_ram;
int m_flip_screen;
/* video-related */ /* video-related */
tilemap_t *m_k053936_tilemap; tilemap_t *m_k053936_tilemap;
int m_tilemap_scrolldx[3];
int m_support_8bpp;
int m_support_16x16;
int m_has_zoom;
int m_sprite_xoffs;
int m_sprite_yoffs;
int m_sprite_xoffs_dx;
emu_timer *m_blit_done_timer;
std::unique_ptr<uint8_t[]> m_expanded_gfx1;
/* irq_related */ /* irq_related */
int m_vblank_bit; int m_vblank_bit;
@ -209,16 +158,9 @@ private:
int m_gakusai_oki_bank_hi; int m_gakusai_oki_bank_hi;
void update_irq_state(); void update_irq_state();
inline uint8_t get_tile_pix( uint16_t code, uint8_t x, uint8_t y, int big, uint16_t *pix );
inline void metro_vram_w( offs_t offset, uint16_t data, uint16_t mem_mask, int layer, uint16_t *vram );
void metro_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 );
inline int blt_read( const uint8_t *ROM, const int offs );
void metro_common(); void metro_common();
void draw_tilemap( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, uint32_t flags, uint32_t pcode,
int sx, int sy, int wx, int wy, int big, uint16_t *tilemapram, int layer );
void expand_gfx1();
void blt_write( address_space &space, const int tmap, const offs_t offs, const uint16_t data, const uint16_t mask );
void gakusai_oki_bank_set(); void gakusai_oki_bank_set();
// blazing tornado
bitmap_ind16 m_vdp_bitmap;
}; };

View File

@ -2,54 +2,8 @@
// copyright-holders:Luca Elia, David Haywood // copyright-holders:Luca Elia, David Haywood
/*************************************************************************** /***************************************************************************
-= Metro Games =- (legacy metro.cpp, currently contains Blazing Tornado overrides,
to be moved into its own driver file!)
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-fff)
[ 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)
***************************************************************************/ ***************************************************************************/
@ -95,647 +49,30 @@ TILEMAP_MAPPER_MEMBER(metro_state::tilemap_scan_gstrik2)
return val; return val;
} }
/***************************************************************************
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
* 00-ff, but on later chips supporting it, xf means 256 color tile and palette x
***************************************************************************/
/***************************************************************************
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)
/* This looks up a single pixel in a tile, given the tile code.
The Metro hardware has an indirection table, which is used here.
Returns if to draw the pixel or not, pixel colour is placed in pix */
inline uint8_t metro_state::get_tile_pix( uint16_t code, uint8_t x, uint8_t y, int big, uint16_t *pix )
{
int table_index;
uint32_t tile;
// Use code 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)
{
*pix = code & 0x0fff;
if ((*pix & 0xf) != 0xf)
return 1;
else
return 0;
}
else if (((tile & 0x00f00000) == 0x00f00000) && (m_support_8bpp)) /* draw tile as 8bpp (e.g. balcube bg) */
{
gfx_element *gfx1 = m_gfxdecode->gfx(big?3:1);
uint32_t tile2 = big ? ((tile & 0xfffff) + 8*(code & 0xf)) :
((tile & 0xfffff) + 2*(code & 0xf));
const uint8_t* data;
uint8_t flipxy = (code & 0x6000) >> 13;
if (tile2 < gfx1->elements())
data = gfx1->get_data(tile2);
else
{
*pix = 0;
return 0;
}
switch (flipxy)
{
default:
case 0x0: *pix = data[(y * (big?16:8)) + x]; break;
case 0x1: *pix = data[(((big?15:7)-y) * (big?16:8)) + x]; break;
case 0x2: *pix = data[(y * (big?16:8)) + ((big?15:7)-x)]; break;
case 0x3: *pix = data[(((big?15:7)-y) * (big?16:8)) + ((big?15:7)-x)]; break;
}
*pix |= ((tile & 0x0f000000) >> 24) * 0x100;
if ((*pix & 0xff) != 0xff)
return 1;
else
return 0;
}
else
{
gfx_element *gfx1 = m_gfxdecode->gfx(big?2:0);
uint32_t tile2 = big ? ((tile & 0xfffff) + 4*(code & 0xf)) :
((tile & 0xfffff) + (code & 0xf));
const uint8_t* data;
uint8_t flipxy = (code & 0x6000) >> 13;
if (tile2 < gfx1->elements())
data = gfx1->get_data(tile2);
else
{
*pix = 0;
return 0;
}
switch (flipxy)
{
default:
case 0x0: *pix = data[(y * (big?16:8)) + x]; break;
case 0x1: *pix = data[(((big?15:7)-y) * (big?16:8)) + x]; break;
case 0x2: *pix = data[(y * (big?16:8)) + ((big?15:7)-x)]; break;
case 0x3: *pix = data[(((big?15:7)-y) * (big?16:8)) + ((big?15:7)-x)]; break;
}
*pix |= (((tile & 0x0ff00000) >> 20)) * 0x10;
if ((*pix & 0xf) != 0xf)
return 1;
else
return 0;
}
}
inline void metro_state::metro_vram_w( offs_t offset, uint16_t data, uint16_t mem_mask, int layer, uint16_t *vram )
{
COMBINE_DATA(&vram[offset]);
}
WRITE16_MEMBER(metro_state::metro_vram_0_w){ metro_vram_w(offset, data, mem_mask, 0, m_vram_0); }
WRITE16_MEMBER(metro_state::metro_vram_1_w){ metro_vram_w(offset, data, mem_mask, 1, m_vram_1); }
WRITE16_MEMBER(metro_state::metro_vram_2_w){ metro_vram_w(offset, data, mem_mask, 2, m_vram_2); }
WRITE16_MEMBER(metro_state::metro_window_w)
{
COMBINE_DATA(&m_window[offset]);
}
/***************************************************************************
Video Init Routines
***************************************************************************/
/*
Sprites are not tile based, so we decode their graphics at runtime.
*/
void metro_state::expand_gfx1()
{
uint8_t *base_gfx = memregion("gfx1")->base();
uint32_t length = memregion("gfx1")->bytes() * 2;
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 & 0xf;
m_expanded_gfx1[i + 1] = src >> 4;
}
}
VIDEO_START_MEMBER(metro_state,metro_i4100)
{
expand_gfx1();
m_support_8bpp = 0;
m_support_16x16 = 0;
m_has_zoom = 0;
m_tilemap_scrolldx[0] = 0;
m_tilemap_scrolldx[1] = 0;
m_tilemap_scrolldx[2] = 0;
m_sprite_xoffs_dx = 0;
}
VIDEO_START_MEMBER(metro_state,metro_i4220)
{
VIDEO_START_CALL_MEMBER(metro_i4100);
m_support_8bpp = 1; // balcube
m_support_16x16 = 1; // vmetal
}
VIDEO_START_MEMBER(metro_state,metro_i4220_dx_tmap)
{
VIDEO_START_CALL_MEMBER(metro_i4220);
m_tilemap_scrolldx[0] = -2;
m_tilemap_scrolldx[1] = -2;
m_tilemap_scrolldx[2] = -2;
}
VIDEO_START_MEMBER(metro_state,metro_i4220_dx_sprite)
{
VIDEO_START_CALL_MEMBER(metro_i4220);
m_tilemap_scrolldx[0] = -16;
m_tilemap_scrolldx[1] = -16;
m_tilemap_scrolldx[2] = -16;
m_sprite_xoffs_dx = 0;
}
VIDEO_START_MEMBER(metro_state,metro_i4300)
{
VIDEO_START_CALL_MEMBER(metro_i4220);
// any additional feature?
}
VIDEO_START_MEMBER(metro_state,blzntrnd) VIDEO_START_MEMBER(metro_state,blzntrnd)
{ {
VIDEO_START_CALL_MEMBER(metro_i4220);
m_has_zoom = 1;
m_k053936_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(metro_state::metro_k053936_get_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 256, 512); m_k053936_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(metro_state::metro_k053936_get_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 256, 512);
m_tilemap_scrolldx[0] = 0; m_screen->register_screen_bitmap(m_vdp_bitmap);
m_tilemap_scrolldx[1] = 0;
m_tilemap_scrolldx[2] = 0;
m_sprite_xoffs_dx = 0;
} }
VIDEO_START_MEMBER(metro_state,gstrik2) VIDEO_START_MEMBER(metro_state,gstrik2)
{ {
VIDEO_START_CALL_MEMBER(metro_i4220);
m_has_zoom = 1;
m_k053936_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(metro_state::metro_k053936_gstrik2_get_tile_info),this), tilemap_mapper_delegate(FUNC(metro_state::tilemap_scan_gstrik2),this), 16, 16, 128, 256); m_k053936_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(metro_state::metro_k053936_gstrik2_get_tile_info),this), tilemap_mapper_delegate(FUNC(metro_state::tilemap_scan_gstrik2),this), 16, 16, 128, 256);
m_tilemap_scrolldx[0] = 0; m_screen->register_screen_bitmap(m_vdp_bitmap);
m_tilemap_scrolldx[1] = -8;
m_tilemap_scrolldx[2] = 0;
m_sprite_xoffs_dx = 0;
} }
/*************************************************************************** uint32_t metro_state::screen_update_psac_vdp2_mix(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
Video Registers
Offset: Bits: Value:
0.w Number Of Sprites To Draw
2.w f--- ---- ---- ---- Disable 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
***************************************************************************/
/***************************************************************************
Sprite Registers
Offset: Bits: Value:
0.w Sprite Y center point
2.w Sprite X center point
***************************************************************************/
/***************************************************************************
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
***************************************************************************/
void metro_state::metro_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] & 0x0f) << 4;
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 (m_flip_screen)
{
flipx = !flipx; x = max_x - x - width;
flipy = !flipy; y = max_y - y - height;
}
if (m_support_8bpp && 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
***************************************************************************/
// Copy a 'window' from the large 2048x2048 (or 4096x4096 for 16x16 tiles) tilemap
void metro_state::draw_tilemap( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, uint32_t flags, uint32_t pcode,
int sx, int sy, int wx, int wy, int big, uint16_t *tilemapram, int layer )
{
int y;
bitmap_ind8 &priority_bitmap = m_screen->priority();
int width = big ? 4096 : 2048;
int height = big ? 4096 : 2048;
int scrwidth = bitmap.width();
int scrheight = bitmap.height();
int windowwidth = width >> 2;
int windowheight = height >> 3;
sx += m_tilemap_scrolldx[layer] * (m_flip_screen ? 1 : -1);
for (y = 0; y < scrheight; y++)
{
int scrolly = (sy+y-wy)&(windowheight-1);
int x;
uint16_t *dst;
uint8_t *priority_baseaddr;
int srcline = (wy+scrolly)&(height-1);
int srctilerow = srcline >> (big ? 4 : 3);
if (!m_flip_screen)
{
dst = &bitmap.pix16(y);
priority_baseaddr = &priority_bitmap.pix8(y);
for (x = 0; x < scrwidth; x++)
{
int scrollx = (sx+x-wx)&(windowwidth-1);
int srccol = (wx+scrollx)&(width-1);
int srctilecol = srccol >> (big ? 4 : 3);
int tileoffs = srctilecol + srctilerow * BIG_NX;
uint16_t dat = 0;
uint16_t tile = tilemapram[tileoffs];
uint8_t draw = get_tile_pix(tile, big ? (srccol&0xf) : (srccol&0x7), big ? (srcline&0xf) : (srcline&0x7), big, &dat);
if (draw)
{
dst[x] = dat;
priority_baseaddr[x] = (priority_baseaddr[x] & (pcode >> 8)) | pcode;
}
}
}
else // flipped case
{
dst = &bitmap.pix16(scrheight-y-1);
priority_baseaddr = &priority_bitmap.pix8(scrheight-y-1);
for (x = 0; x < scrwidth; x++)
{
int scrollx = (sx+x-wx)&(windowwidth-1);
int srccol = (wx+scrollx)&(width-1);
int srctilecol = srccol >> (big ? 4 : 3);
int tileoffs = srctilecol + srctilerow * BIG_NX;
uint16_t dat = 0;
uint16_t tile = tilemapram[tileoffs];
uint8_t draw = get_tile_pix(tile, big ? (srccol&0xf) : (srccol&0x7), big ? (srcline&0xf) : (srcline&0x7), big, &dat);
if (draw)
{
dst[scrwidth-x-1] = dat;
priority_baseaddr[scrwidth-x-1] = (priority_baseaddr[scrwidth-x-1] & (pcode >> 8)) | pcode;
}
}
}
}
}
// Draw all the layers that match the given priority
void metro_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--)
{
if (pri == ((layers_pri >> (layer * 2)) & 3))
{
// Scroll and Window values
uint16_t sy = m_scroll[layer * 2 + 0]; uint16_t sx = m_scroll[layer * 2 + 1];
uint16_t wy = m_window[layer * 2 + 0]; uint16_t wx = m_window[layer * 2 + 1];
if (BIT(layers_ctrl, layer)) // for debug
{
uint16_t *tilemapram = nullptr;
switch (layer)
{
case 0: tilemapram = m_vram_0; break;
case 1: tilemapram = m_vram_1; break;
case 2: tilemapram = m_vram_2; break;
}
int big = m_support_16x16 && (*m_screenctrl & (0x0020 << layer));
draw_tilemap(screen, bitmap, cliprect, 0, 1 << (3 - pri), sx, sy, wx, wy, big, tilemapram, layer);
}
}
}
}
uint32_t metro_state::screen_update_metro(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int pri, layers_ctrl = -1;
uint16_t screenctrl = *m_screenctrl;
m_sprite_xoffs = m_videoregs[0x06 / 2] - (m_spriteregs[1]+1) + m_sprite_xoffs_dx;
m_sprite_yoffs = m_videoregs[0x04 / 2] - (m_spriteregs[0]+1);
screen.priority().fill(0, cliprect);
// The background color is selected by a register
bitmap.fill(m_videoregs[0x12/2] & 0x0fff, cliprect);
/* Screen Control Register:
f--- ---- ---- ---- ?
-edc b--- ---- ----
---- -a98 ---- ---- ? Leds (see gakusai attract)
---- ---- 765- ---- 16x16 Tiles (Layer 2-1-0)
---- ---- ---4 32--
---- ---- ---- --1- Blank Screen
---- ---- ---- ---0 Flip Screen */
if (screenctrl & 2)
return 0;
m_flip_screen = screenctrl & 1;
#ifdef MAME_DEBUG
if (machine().input().code_pressed(KEYCODE_Z))
{
int msk = 0;
if (machine().input().code_pressed(KEYCODE_Q)) msk |= 1;
if (machine().input().code_pressed(KEYCODE_W)) msk |= 2;
if (machine().input().code_pressed(KEYCODE_E)) msk |= 4;
if (machine().input().code_pressed(KEYCODE_A)) msk |= 8;
if (msk != 0)
{
bitmap.fill(m_palette->black_pen(), cliprect);
layers_ctrl &= msk;
}
popmessage( "lyr: %x-%x-%x spr: %04x clr: %04x scr: %04x",
(m_videoregs[0x10/2] & 0x30) >> 4, (m_videoregs[0x10/2] & 0xc) >> 2, m_videoregs[0x10/2] & 3,
m_videoregs[0x02/2], m_videoregs[0x12/2],
*m_screenctrl);
}
#endif
if (m_has_zoom)
{ {
/* TODO: bit 5 of reg 7 is off when ROZ is supposed to be disabled /* TODO: bit 5 of reg 7 is off when ROZ is supposed to be disabled
* (Blazing Tornado title screen/character select/ending and Grand Striker 2 title/how to play transition) * (Blazing Tornado title screen/character select/ending and Grand Striker 2 title/how to play transition)
*/ */
bitmap.fill(m_vdp2->get_background_pen(), cliprect);
m_k053936->zoom_draw(screen, bitmap, cliprect, m_k053936_tilemap, 0, 0, 1); m_k053936->zoom_draw(screen, bitmap, cliprect, m_k053936_tilemap, 0, 0, 1);
} m_vdp2->screen_update(screen, m_vdp_bitmap, cliprect);
copybitmap_trans(bitmap, m_vdp_bitmap, 0, 0, 0, 0, cliprect, m_vdp2->get_background_pen());
for (pri = 3; pri >= 0; pri--)
draw_layers(screen, bitmap, cliprect, pri, layers_ctrl);
if (layers_ctrl & 0x08)
metro_draw_sprites(screen, bitmap, cliprect);
return 0; return 0;
} }