summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/deco16ic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/video/deco16ic.c')
-rw-r--r--src/mame/video/deco16ic.c1050
1 files changed, 1050 insertions, 0 deletions
diff --git a/src/mame/video/deco16ic.c b/src/mame/video/deco16ic.c
new file mode 100644
index 00000000000..c896399ee14
--- /dev/null
+++ b/src/mame/video/deco16ic.c
@@ -0,0 +1,1050 @@
+/********************************************************************************
+
+ Data East video emulation & information by Bryan McPhail, mish@tendril.co.uk (c) 2000-2005 Bryan McPhail
+ Please send me any additions to the table below.
+
+
+ Game Mask Rom CPU Sprites Playfields IO/Protection Other
+ ==============================================================================================
+ Vapor Trail/Kuhga MAA 59 MXC-06 55, 55
+ Crude Buster/Two Crude MAB 59 52 55, 55
+ Dark Seal/Gate Of Doom MAC 59 52 55, 55
+ Edward Randy MAD 59 52 55, 55 60
+ Super Burger Time MAE 59 52 55
+ Mutant Fighter/Death Brade MAF 59 52 55, 56 66
+ Caveman Ninja/Joe & Mac MAG 59 52 55, 55 104
+ Robocop 2 MAH 59 52 55, 55 75
+ Desert Assault/Thunderzone MAJ 59,59 52,52 55, 55
+ China Town MAK 59 52 55
+ Rogha/Wolf Fang MAM 59 52,52,71,71 55, 56 104 113
+ Captain America MAN 101 52,71 56, 56 75
+ Tumblepop MAP 59 52 56
+ Dragon Gun MAR 101 ? 74, 74 146 113,186,187
+ Wizard Fire/Dark Seal 2 MAS 59 52,52,71,71 74, 74 104 113
+ Funky Jet MAT 59 52 74 146
+ Nitro Ball MAV 59 52,52,71,71 56, 74 146 113
+ Diet GoGo MAY 102 52,71 141 104 113
+ Pocket Gal DX MAZ 102 52,71 56 104 153
+ Boogie Wings MBD 102 52,52,71,71 141, 141 104 113,99,200
+1 Double Wings MBE 102 52 141 104
+ Fighter's History MBF 101 52,153 56,74 [Scratched] 200, 153, 170
+ Heavy Smash MBG 156 52 141 153*3
+ Night Slashers MBH 156 52,52,52,153,153,153 74, 141 104 99,200
+ Locked N Loaded MBM 101 ? 74,74 146 113,186,187
+ Joe & Mac Return MBN 156 52 141 223,223
+2 Charlie Ninja MBR 156 52 141 223,223
+ World Cup Volleyball 95 MBX 156 52 141 ?
+ Backfire! MBZ 156 52,52,153,153 141,141 ? 223
+2* Ganbare Gonta MCB 156 52 141 223,223
+ Chain Reaction/Magical Drop MCC 156 52 141 223,223
+ Dunk Dream 95 MCE 156 [MLC] [MLC]
+2 Osman/Cannon Dancer MCF 156 52 141 223,223
+ Avengers In Galactic Storm MCG SH2 [MLC] [MLC]
+ Stadium Hero 96 MCM 156 [MLC] [MLC] 146
+
+ Sotsugyo Shousho 59 52 74 146?
+ Lemmings --- 59 52,52,71,71 None 75
+ Tattoo Assassins --- 101 52,52,71,71 141, 141? ? 99, ?
+
+Note 1: Mitchell game on DECO PCB board number DEC-22V0 (S-NK-3220)
+Note 2: Mitchell games on DECO PCB board number MT5601-0
+Note *: Ganbare! Gonta!! 2 / Lady Killer Part 2 - Party Time
+
+ Custom chip 59 = 68000 cpu
+ Custom chip 101 = Arm6 cpu
+ Custom chip 113 = Alpha blending
+ Custom chip 99 = 'Ace' chip (Special alpha blending?)
+ Custom chip 156 = Encrypted ARM cpu
+ Custom chip 102 = Encrypted 68000 cpu
+
+ Custom chip 55 provides two playfields of 4bpp tiles, with optional
+ rowscroll and column scroll. Some games use two of these to give
+ 4 playfields. Palette banking, tile banking and priority are outside
+ the scope of this chip, and usually differ between games. Some games
+ combine the 4bpp output of each playfield to give an effective 8bpp
+ display.
+
+ Custom chip 56 is the same as 55 but with on-chip decryption, so
+ encrypted roms can be used.
+
+ Custom chip 74 is the same as 56 but with different decryption tables.
+
+ Custom chip 141 is same as 56, but can output up to 8BPP per layer.
+
+ Custom chip 55/56/74/141 control register layout:
+
+ Word 0:
+ Mask 0x0080: Flip screen
+ Mask 0x007f: ? Possibly a bit to set transparent pen 0 on/off
+ Word 2:
+ Mask 0xffff: Playfield 2 X scroll
+ Word 4:
+ Mask 0xffff: Playfield 2 Y scroll
+ Word 6:
+ Mask 0xffff: Playfield 1 X scroll
+ Word 8:
+ Mask 0xffff: Playfield 1 Y scroll
+ Word 0xa:
+ Mask 0x8000: Playfield 1 enable
+ Mask 0x7800: Playfield 1 rowscroll style
+ Mask 0x0700: Playfield 1 colscroll style
+
+ Mask 0x0080: Playfield 2 enable
+ Mask 0x0078: Playfield 2 rowscroll style
+ Mask 0x0007: Playfield 2 colscroll style
+ Word 0xc:
+ Mask 0x8000: Playfield 1 is 8*8 tiles else 16*16
+ Mask 0x4000: Playfield 1 rowscroll enabled
+ Mask 0x2000: Playfield 1 colscroll enabled
+ Mask 0x1800: Seemingly unused
+ Mask 0x0400: Use alternate palette bank (unimplemented/unused by any game)
+ Mask 0x0200: Y flip tiles with top bit of palette code set (palette becomes 3 bits for this tile)
+ Mask 0x0100: X flip tiles with top bit of palette code set (palette becomes 3 bits for this tile)
+
+ Mask 0x0080: Playfield 2 is 8*8 tiles else 16*16
+ Mask 0x0040: Playfield 2 rowscroll enabled
+ Mask 0x0020: Playfield 2 colscroll enabled
+ Mask 0x0018: Seemingly unused
+ Mask 0x0004: Use alternate palette bank (unimplemented/unused by any game)
+ Mask 0x0002: Y flip tiles with top bit of palette code set (palette becomes 3 bits for this tile)
+ Mask 0x0001: X flip tiles with top bit of palette code set (palette becomes 3 bits for this tile)
+
+ Word 0xe:
+ Mask 0xff00: Playfield 1 gfx rom banking (Usually different hookup per game)
+ Mask 0x00ff: Playfield 2 gfx rom banking
+
+Colscroll style:
+ 0 8 pixel columns across bitmap
+ 1 16 pixel columns across bitmap
+ 2 32
+ 3 64
+ 4 128
+ 5 256
+ 6 512
+ 7 1024 (Effectively 0 as 1024 is the width of the bitmap)
+
+Rowscroll style:
+ 0 512 rows down bitmap in 16x16 tile mode, 256 rows in 8x8 mode
+ 1 256 rows in 16x16, 128 in 8x8
+ 2 128 / 64
+ 3 64 / 32
+ 4 32 / 16
+ 5 16 / 8
+ 6 8 / 4
+ 7 4 / 2
+ 8 2 / 1
+ 9-15 Untested on hardware, no known games set this anyway. Assumed invalid (no rowscroll)
+
+ Column and rowscroll can both be applied at once.
+
+***************************************************************************/
+
+#include "driver.h"
+#include "deco16ic.h"
+#include "ui.h"
+
+UINT16 *deco16_pf1_data,*deco16_pf2_data;
+UINT16 *deco16_pf3_data,*deco16_pf4_data;
+UINT16 *deco16_pf1_rowscroll,*deco16_pf2_rowscroll;
+UINT16 *deco16_pf3_rowscroll,*deco16_pf4_rowscroll;
+
+static const UINT16 *pf1_rowscroll_ptr, *pf2_rowscroll_ptr;
+static const UINT16 *pf3_rowscroll_ptr, *pf4_rowscroll_ptr;
+
+UINT16 *deco16_pf12_control,*deco16_pf34_control;
+UINT16 deco16_priority;
+
+UINT16 *deco16_raster_display_list;
+int deco16_raster_display_position;
+
+static int use_custom_pf1, use_custom_pf2, use_custom_pf3, use_custom_pf4;
+
+static tilemap *pf1_tilemap_16x16,*pf2_tilemap_16x16,*pf3_tilemap_16x16,*pf4_tilemap_16x16;
+static tilemap *pf1_tilemap_8x8,*pf2_tilemap_8x8;
+
+static mame_bitmap *sprite_priority_bitmap;
+
+static UINT8 *dirty_palette;
+static int deco16_pf1_bank,deco16_pf2_bank,deco16_pf3_bank,deco16_pf4_bank;
+static int deco16_pf12_16x16_gfx_bank,deco16_pf34_16x16_gfx_bank,deco16_pf12_8x8_gfx_bank;
+static int deco16_pf1_colourmask,deco16_pf2_colourmask,deco16_pf3_colourmask,deco16_pf4_colourmask;
+int deco16_pf1_colour_bank,deco16_pf2_colour_bank,deco16_pf3_colour_bank,deco16_pf4_colour_bank;
+static int deco16_pf1_trans_mask,deco16_pf2_trans_mask,deco16_pf3_trans_mask,deco16_pf4_trans_mask;
+static int (*deco16_bank_callback_1)(const int bank);
+static int (*deco16_bank_callback_2)(const int bank);
+static int (*deco16_bank_callback_3)(const int bank);
+static int (*deco16_bank_callback_4)(const int bank);
+static void custom_tilemap_draw(mame_bitmap *bitmap,tilemap *tilemap0_8x8,tilemap *tilemap0_16x16,
+ tilemap *tilemap1_8x8,tilemap *tilemap1_16x16, const UINT16 *rowscroll_ptr,const UINT16 scrollx,
+ const UINT16 scrolly,const UINT16 control0, const UINT16 control1,int combine_mask,int combine_shift,int trans_mask,int flags,UINT32 priority);
+
+/******************************************************************************/
+
+/* Later games have double buffered paletteram - the real palette ram is
+only updated on a DMA call */
+
+WRITE16_HANDLER( deco16_nonbuffered_palette_w )
+{
+ int r,g,b;
+
+ COMBINE_DATA(&paletteram16[offset]);
+ if (offset&1) offset--;
+
+ b = (paletteram16[offset] >> 0) & 0xff;
+ g = (paletteram16[offset+1] >> 8) & 0xff;
+ r = (paletteram16[offset+1] >> 0) & 0xff;
+
+ palette_set_color(Machine,offset/2,MAKE_RGB(r,g,b));
+}
+
+WRITE16_HANDLER( deco16_buffered_palette_w )
+{
+ COMBINE_DATA(&paletteram16[offset]);
+ dirty_palette[offset/2]=1;
+}
+
+WRITE16_HANDLER( deco16_palette_dma_w )
+{
+ const int m=Machine->drv->total_colors;
+ int r,g,b,i;
+
+ for (i=0; i<m; i++) {
+ if (dirty_palette[i]) {
+ dirty_palette[i]=0;
+
+ b = (paletteram16[i*2] >> 0) & 0xff;
+ g = (paletteram16[i*2+1] >> 8) & 0xff;
+ r = (paletteram16[i*2+1] >> 0) & 0xff;
+
+ palette_set_color(Machine,i,MAKE_RGB(r,g,b));
+ }
+ }
+}
+
+/*****************************************************************************************/
+
+/* */
+READ16_HANDLER( deco16_71_r )
+{
+ return 0xffff;
+}
+
+WRITE16_HANDLER( deco16_priority_w )
+{
+ deco16_priority=data;
+}
+
+/*****************************************************************************************/
+
+static TILEMAP_MAPPER( deco16_scan_rows )
+{
+ /* logical (col,row) -> memory offset */
+ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 5) + ((row & 0x20) << 6);
+}
+
+static TILE_GET_INFO( get_pf4_tile_info )
+{
+ UINT16 tile=deco16_pf4_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf34_control[6]>>8)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf34_control[6]>>8)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf34_16x16_gfx_bank,
+ (tile&0xfff)|deco16_pf4_bank,
+ (colour&deco16_pf4_colourmask)+deco16_pf4_colour_bank,
+ flags);
+}
+
+static TILE_GET_INFO( get_pf3_tile_info )
+{
+ UINT16 tile=deco16_pf3_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf34_control[6]>>0)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf34_control[6]>>0)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf34_16x16_gfx_bank,
+ (tile&0xfff)|deco16_pf3_bank,
+ (colour&deco16_pf3_colourmask)+deco16_pf3_colour_bank,
+ flags);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info )
+{
+ UINT16 tile=deco16_pf2_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf12_control[6]>>8)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf12_control[6]>>8)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf12_16x16_gfx_bank,
+ (tile&0xfff)|deco16_pf2_bank,
+ (colour&deco16_pf2_colourmask)+deco16_pf2_colour_bank,
+ flags);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info )
+{
+ UINT16 tile=deco16_pf1_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf12_control[6]>>0)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf12_control[6]>>0)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf12_16x16_gfx_bank,
+ (tile&0xfff)|deco16_pf1_bank,
+ (colour&deco16_pf1_colourmask)+deco16_pf1_colour_bank,
+ flags);
+}
+
+static TILE_GET_INFO( get_pf2_tile_info_b )
+{
+ UINT16 tile=deco16_pf2_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf12_control[6]>>8)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf12_control[6]>>8)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf12_8x8_gfx_bank,
+ (tile&0xfff)|deco16_pf2_bank,
+ (colour&deco16_pf2_colourmask)+deco16_pf2_colour_bank,
+ flags);
+}
+
+static TILE_GET_INFO( get_pf1_tile_info_b )
+{
+ UINT16 tile=deco16_pf1_data[tile_index];
+ UINT8 colour=(tile>>12)&0xf;
+ UINT8 flags=0;
+
+ if (tile&0x8000) {
+ if ((deco16_pf12_control[6]>>0)&0x01) {
+ flags|=TILE_FLIPX;
+ colour&=0x7;
+ }
+ if ((deco16_pf12_control[6]>>0)&0x02) {
+ flags|=TILE_FLIPY;
+ colour&=0x7;
+ }
+ }
+
+ SET_TILE_INFO(
+ deco16_pf12_8x8_gfx_bank,
+ (tile&0xfff)|deco16_pf1_bank,
+ (colour&deco16_pf1_colourmask)+deco16_pf1_colour_bank,
+ flags);
+}
+
+/******************************************************************************/
+
+/* Each game can have banking set up differently depending on how the roms are
+connected, and what rom slots are used */
+
+void deco16_set_tilemap_bank_callback(int tmap, int (*callback)(const int bank))
+{
+ switch (tmap) {
+ case 0: deco16_bank_callback_1=callback; break;
+ case 1: deco16_bank_callback_2=callback; break;
+ case 2: deco16_bank_callback_3=callback; break;
+ case 3: deco16_bank_callback_4=callback; break;
+ }
+}
+
+/* Each game can have colours set up differently depending on how the playfield
+generator is connected to paletteram */
+
+void deco16_set_tilemap_colour_base(int tmap, int base)
+{
+ switch (tmap) {
+ case 0: deco16_pf1_colour_bank=base; break;
+ case 1: deco16_pf2_colour_bank=base; break;
+ case 2: deco16_pf3_colour_bank=base; break;
+ case 3: deco16_pf4_colour_bank=base; break;
+ }
+}
+
+void deco16_set_tilemap_colour_mask(int tmap, int mask)
+{
+ switch (tmap) {
+ case 0: deco16_pf1_colourmask=mask; break;
+ case 1: deco16_pf2_colourmask=mask; break;
+ case 2: deco16_pf3_colourmask=mask; break;
+ case 3: deco16_pf4_colourmask=mask; break;
+ }
+}
+
+void deco16_set_tilemap_transparency_mask(int tmap, int mask)
+{
+ switch (tmap) {
+ case 0: deco16_pf1_trans_mask=mask; break;
+ case 1: deco16_pf2_trans_mask=mask; break;
+ case 2: deco16_pf3_trans_mask=mask; break;
+ case 3: deco16_pf4_trans_mask=mask; break;
+ }
+}
+
+void deco16_pf12_set_gfxbank(int small, int big)
+{
+ static int last_small=-1, last_big=-1;
+
+ if (last_small!=small) {
+ if (pf1_tilemap_8x8)
+ tilemap_mark_all_tiles_dirty(pf1_tilemap_8x8);
+ if (pf2_tilemap_8x8)
+ tilemap_mark_all_tiles_dirty(pf2_tilemap_8x8);
+ last_small=small;
+ }
+ deco16_pf12_8x8_gfx_bank=small;
+
+ if (last_big!=big) {
+ if (pf1_tilemap_16x16)
+ tilemap_mark_all_tiles_dirty(pf1_tilemap_16x16);
+ if (pf2_tilemap_16x16)
+ tilemap_mark_all_tiles_dirty(pf2_tilemap_16x16);
+ last_big=big;
+ }
+ deco16_pf12_16x16_gfx_bank=big;
+
+}
+
+void deco16_pf34_set_gfxbank(int small, int big)
+{
+ static int last_big=-1;
+
+ if (last_big!=big) {
+ if (pf3_tilemap_16x16)
+ tilemap_mark_all_tiles_dirty(pf3_tilemap_16x16);
+ if (pf4_tilemap_16x16)
+ tilemap_mark_all_tiles_dirty(pf4_tilemap_16x16);
+ last_big=big;
+ }
+ deco16_pf34_16x16_gfx_bank=big;
+}
+
+tilemap *deco16_get_tilemap(int pf, int size)
+{
+ switch (pf) {
+ case 0: if (size) return pf1_tilemap_8x8; return pf1_tilemap_16x16;
+ case 1: if (size) return pf2_tilemap_8x8; return pf2_tilemap_16x16;
+ case 2: if (size) return 0; return pf3_tilemap_16x16;
+ case 3: if (size) return 0; return pf4_tilemap_16x16;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+WRITE16_HANDLER( deco16_pf1_data_w )
+{
+ COMBINE_DATA(&deco16_pf1_data[offset]);
+ tilemap_mark_tile_dirty(pf1_tilemap_8x8,offset);
+ if (offset<0x800)
+ tilemap_mark_tile_dirty(pf1_tilemap_16x16,offset);
+}
+
+WRITE16_HANDLER( deco16_pf2_data_w )
+{
+ COMBINE_DATA(&deco16_pf2_data[offset]);
+ tilemap_mark_tile_dirty(pf2_tilemap_8x8,offset);
+ if (offset<0x800)
+ tilemap_mark_tile_dirty(pf2_tilemap_16x16,offset);
+}
+
+WRITE16_HANDLER( deco16_pf3_data_w )
+{
+ COMBINE_DATA(&deco16_pf3_data[offset]);
+ tilemap_mark_tile_dirty(pf3_tilemap_16x16,offset);
+}
+
+WRITE16_HANDLER( deco16_pf4_data_w )
+{
+ COMBINE_DATA(&deco16_pf4_data[offset]);
+ tilemap_mark_tile_dirty(pf4_tilemap_16x16,offset);
+}
+
+/*****************************************************************************************/
+
+static void deco16_video_init(int pf12_only, int split, int full_width)
+{
+ sprite_priority_bitmap = auto_bitmap_alloc( Machine->screen[0].width, Machine->screen[0].height, BITMAP_FORMAT_INDEXED8 );
+
+ pf1_tilemap_16x16 = tilemap_create(get_pf1_tile_info, deco16_scan_rows, TILEMAP_TYPE_PEN,16,16,64,32);
+ pf1_tilemap_8x8 = tilemap_create(get_pf1_tile_info_b, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32);
+
+ if (split)
+ pf2_tilemap_16x16 = tilemap_create(get_pf2_tile_info, deco16_scan_rows, TILEMAP_TYPE_PEN,16,16,full_width ? 64 : 32,32);
+ else
+ pf2_tilemap_16x16 = tilemap_create(get_pf2_tile_info, deco16_scan_rows, TILEMAP_TYPE_PEN,16,16,full_width ? 64 : 32,32);
+ pf2_tilemap_8x8 = tilemap_create(get_pf2_tile_info_b, tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,full_width ? 64 : 32,32);
+
+ dirty_palette = auto_malloc(4096);
+ deco16_raster_display_list=auto_malloc(20 * 256);
+
+ if (!pf12_only)
+ {
+ pf4_tilemap_16x16 = tilemap_create(get_pf4_tile_info, deco16_scan_rows, TILEMAP_TYPE_PEN,16,16,full_width ? 64 : 32,32);
+ pf3_tilemap_16x16 = tilemap_create(get_pf3_tile_info, deco16_scan_rows, TILEMAP_TYPE_PEN,16,16,full_width ? 64 : 32,32);
+ }
+ else
+ {
+ pf3_tilemap_16x16=0;
+ pf4_tilemap_16x16=0;
+ }
+
+ tilemap_set_transparent_pen(pf1_tilemap_8x8,0);
+ tilemap_set_transparent_pen(pf2_tilemap_8x8,0);
+ tilemap_set_transparent_pen(pf1_tilemap_16x16,0);
+ tilemap_set_transparent_pen(pf2_tilemap_16x16,0);
+ if (split) /* Caveman Ninja only */
+ tilemap_set_transmask(pf2_tilemap_16x16,0,0x00ff,0xff01);
+
+ if (!pf12_only)
+ {
+ tilemap_set_transparent_pen(pf3_tilemap_16x16,0);
+ tilemap_set_transparent_pen(pf4_tilemap_16x16,0);
+ }
+
+
+ deco16_bank_callback_1=0;
+ deco16_bank_callback_2=0;
+ deco16_bank_callback_3=0;
+ deco16_bank_callback_4=0;
+
+ deco16_pf1_trans_mask=0xf;
+ deco16_pf2_trans_mask=0xf;
+ deco16_pf3_trans_mask=0xf;
+ deco16_pf4_trans_mask=0xf;
+
+ deco16_pf1_colourmask=deco16_pf2_colourmask=0xf;
+ deco16_pf3_colourmask=deco16_pf4_colourmask=0xf;
+ deco16_pf1_bank=deco16_pf2_bank=deco16_pf3_bank=deco16_pf4_bank=0;
+ deco16_pf4_colour_bank=deco16_pf2_colour_bank=16;
+ deco16_pf3_colour_bank=deco16_pf1_colour_bank=0;
+
+ deco16_pf12_8x8_gfx_bank=0;
+ deco16_pf12_16x16_gfx_bank=1;
+ deco16_pf34_16x16_gfx_bank=2;
+
+ deco16_raster_display_position=0;
+}
+
+void deco16_1_video_init(void) /* 1 times playfield generator chip */
+{
+ deco16_video_init(1, 0, 1);
+}
+
+void deco16_2_video_init(int split) /* 2 times playfield generator chips */
+{
+ deco16_video_init(0, split, 1);
+}
+
+void deco16_2_video_init_half_width(void) /* 2 times playfield generator chips */
+{
+ deco16_video_init(0, 0, 0);
+}
+
+void deco_allocate_sprite_bitmap(void)
+{
+ /* Allow sprite bitmap to be used by Deco32 games as well */
+ sprite_priority_bitmap = auto_bitmap_alloc( Machine->screen[0].width, Machine->screen[0].height, BITMAP_FORMAT_INDEXED8 );
+}
+
+/*****************************************************************************************/
+
+static int deco16_pf_update(
+ tilemap *tilemap_8x8,
+ tilemap *tilemap_16x16,
+ const UINT16 *rowscroll_ptr,
+ const UINT16 scrollx,
+ const UINT16 scrolly,
+ const UINT16 control0,
+ const UINT16 control1)
+{
+ int rows, cols, offs, use_custom=0;
+
+ /* Toggle between 8x8 and 16x16 modes (and master enable bit) */
+ if (control1&0x80) {
+ if (!tilemap_8x8) popmessage("Deco16: Playfield switched into 8x8 mode but no tilemap defined");
+
+ if (tilemap_8x8) tilemap_set_enable(tilemap_8x8,control0&0x80);
+ if (tilemap_16x16) tilemap_set_enable(tilemap_16x16,0);
+ } else {
+ if (!tilemap_16x16) popmessage("Deco16: Playfield switched into 16x16 mode but no tilemap defined");
+
+ if (tilemap_8x8) tilemap_set_enable(tilemap_8x8,0);
+ if (tilemap_16x16) tilemap_set_enable(tilemap_16x16,control0&0x80);
+ }
+
+ /* Rowscroll enable */
+ if (rowscroll_ptr && (control1&0x60)==0x40) {
+
+ /* Several different rowscroll styles */
+ switch ((control0>>3)&0xf) {
+ case 0: rows=512; break;/* Every line of 512 height bitmap */
+ case 1: rows=256; break;
+ case 2: rows=128; break;
+ case 3: rows=64; break;
+ case 4: rows=32; break;
+ case 5: rows=16; break;
+ case 6: rows=8; break;
+ case 7: rows=4; break;
+ case 8: rows=2; break;
+ default: rows=1; break;
+ }
+
+ if (tilemap_16x16) {
+ tilemap_set_scroll_cols(tilemap_16x16,1);
+ tilemap_set_scroll_rows(tilemap_16x16,rows);
+ tilemap_set_scrolly(tilemap_16x16,0,scrolly);
+
+ for (offs = 0;offs < rows;offs++)
+ tilemap_set_scrollx( tilemap_16x16, offs, scrollx + rowscroll_ptr[offs] );
+ }
+
+ if (tilemap_8x8) {
+ tilemap_set_scroll_cols(tilemap_8x8,1);
+ tilemap_set_scroll_rows(tilemap_8x8,rows/2);
+ tilemap_set_scrolly(tilemap_8x8,0,scrolly);
+
+ for (offs = 0;offs < rows/2;offs++)
+ tilemap_set_scrollx( tilemap_8x8, offs, scrollx + rowscroll_ptr[offs] );
+ }
+ }
+ else if (rowscroll_ptr && (control1&0x60)==0x20) { /* Column scroll */
+
+ /* Column scroll ranges from 8 pixel columns to 512 pixel columns */
+ int mask=(0x40 >> (control0&7))-1;
+ if (mask==-1) mask=0;
+ cols=(8<<(control0&7))&0x3ff;
+ if (!cols) cols=1024;
+ cols=1024 / cols;
+
+ if (tilemap_16x16) {
+ tilemap_set_scroll_cols(tilemap_16x16,cols);
+ tilemap_set_scroll_rows(tilemap_16x16,1);
+ tilemap_set_scrollx(tilemap_16x16,0,scrollx );
+
+ for (offs=0 ; offs < cols;offs++)
+ tilemap_set_scrolly( tilemap_16x16, offs, scrolly + rowscroll_ptr[(offs&mask)+0x200] );
+ }
+
+ if (tilemap_8x8) {
+ cols = cols / 2; /* Adjust because 8x8 tilemap is half the width of 16x16 */
+
+ tilemap_set_scroll_cols(tilemap_8x8,cols);
+ tilemap_set_scroll_rows(tilemap_8x8,1);
+ tilemap_set_scrollx(tilemap_8x8,0,scrollx );
+
+ for (offs=0 ; offs < cols;offs++)
+ tilemap_set_scrolly( tilemap_8x8,offs, scrolly + rowscroll_ptr[(offs&mask)+0x200] );
+ }
+ }
+ else if (control1&0x60) {
+ /* Simultaneous row & column scroll requested - use custom renderer */
+ use_custom=1;
+
+ if (tilemap_16x16) {
+ tilemap_set_scroll_rows(tilemap_16x16,1);
+ tilemap_set_scroll_cols(tilemap_16x16,1);
+ tilemap_set_scrollx( tilemap_16x16,0, scrollx );
+ tilemap_set_scrolly( tilemap_16x16,0, scrolly );
+ }
+
+ if (tilemap_8x8) {
+ tilemap_set_scroll_rows(tilemap_8x8,1);
+ tilemap_set_scroll_cols(tilemap_8x8,1);
+ tilemap_set_scrollx( tilemap_8x8,0, scrollx );
+ tilemap_set_scrolly( tilemap_8x8,0, scrolly );
+
+ }
+
+ } else {
+ if (tilemap_16x16) {
+ tilemap_set_scroll_rows(tilemap_16x16,1);
+ tilemap_set_scroll_cols(tilemap_16x16,1);
+ tilemap_set_scrollx( tilemap_16x16,0, scrollx );
+ tilemap_set_scrolly( tilemap_16x16,0, scrolly );
+ }
+
+ if (tilemap_8x8) {
+ tilemap_set_scroll_rows(tilemap_8x8,1);
+ tilemap_set_scroll_cols(tilemap_8x8,1);
+ tilemap_set_scrollx( tilemap_8x8,0, scrollx );
+ tilemap_set_scrolly( tilemap_8x8,0, scrolly );
+ }
+ }
+
+ return use_custom;
+}
+
+void deco16_pf12_update(const UINT16 *rowscroll_1_ptr, const UINT16 *rowscroll_2_ptr)
+{
+ int bank1, bank2;
+
+ /* Update scrolling and tilemap enable */
+ pf1_rowscroll_ptr=rowscroll_1_ptr;
+ pf2_rowscroll_ptr=rowscroll_2_ptr;
+ use_custom_pf2=deco16_pf_update(pf2_tilemap_8x8,pf2_tilemap_16x16,rowscroll_2_ptr,deco16_pf12_control[3], deco16_pf12_control[4], deco16_pf12_control[5]>>8, deco16_pf12_control[6]>>8);
+ use_custom_pf1=deco16_pf_update(pf1_tilemap_8x8,pf1_tilemap_16x16,rowscroll_1_ptr,deco16_pf12_control[1], deco16_pf12_control[2], deco16_pf12_control[5]&0xff, deco16_pf12_control[6]&0xff);
+
+ /* Update banking and global flip state */
+ if (deco16_bank_callback_1) {
+ bank1=deco16_bank_callback_1(deco16_pf12_control[7]&0xff);
+ if (bank1!=deco16_pf1_bank) {
+ if (pf1_tilemap_8x8) tilemap_mark_all_tiles_dirty(pf1_tilemap_8x8);
+ if (pf1_tilemap_16x16) tilemap_mark_all_tiles_dirty(pf1_tilemap_16x16);
+ }
+
+ deco16_pf1_bank=bank1;
+ }
+
+ if (deco16_bank_callback_2) {
+ bank2=deco16_bank_callback_2(deco16_pf12_control[7]>>8);
+ if (bank2!=deco16_pf2_bank) {
+ if (pf2_tilemap_8x8) tilemap_mark_all_tiles_dirty(pf2_tilemap_8x8);
+ if (pf2_tilemap_16x16) tilemap_mark_all_tiles_dirty(pf2_tilemap_16x16);
+ }
+
+ deco16_pf2_bank=bank2;
+ }
+}
+
+void deco16_pf34_update(const UINT16 *rowscroll_1_ptr, const UINT16 *rowscroll_2_ptr)
+{
+ int bank1, bank2;
+
+ /* Update scrolling and tilemap enable */
+ pf3_rowscroll_ptr=rowscroll_1_ptr;
+ pf4_rowscroll_ptr=rowscroll_2_ptr;
+ use_custom_pf4=deco16_pf_update(0,pf4_tilemap_16x16,rowscroll_2_ptr,deco16_pf34_control[3], deco16_pf34_control[4], deco16_pf34_control[5]>>8, deco16_pf34_control[6]>>8);
+ use_custom_pf3=deco16_pf_update(0,pf3_tilemap_16x16,rowscroll_1_ptr,deco16_pf34_control[1], deco16_pf34_control[2], deco16_pf34_control[5]&0xff, deco16_pf34_control[6]&0xff);
+
+
+ /* Update banking and global flip state */
+ if (deco16_bank_callback_3) {
+ bank1=deco16_bank_callback_3(deco16_pf34_control[7]&0xff);
+ if (bank1!=deco16_pf3_bank) {
+ //if (pf3_tilemap_8x8) tilemap_mark_all_tiles_dirty(pf3_tilemap_8x8);
+ if (pf3_tilemap_16x16) tilemap_mark_all_tiles_dirty(pf3_tilemap_16x16);
+ }
+
+ deco16_pf3_bank=bank1;
+ }
+
+ if (deco16_bank_callback_4) {
+ bank2=deco16_bank_callback_4(deco16_pf34_control[7]>>8);
+ if (bank2!=deco16_pf4_bank) {
+ //if (pf4_tilemap_8x8) tilemap_mark_all_tiles_dirty(pf4_tilemap_8x8);
+ if (pf4_tilemap_16x16) tilemap_mark_all_tiles_dirty(pf4_tilemap_16x16);
+ }
+
+ deco16_pf4_bank=bank2;
+ }
+}
+
+/*****************************************************************************************/
+
+void deco16_print_debug_info(mame_bitmap *bitmap)
+{
+ char buf[64*5];
+
+ if (input_code_pressed(KEYCODE_O))
+ return;
+
+ if (deco16_pf12_control) {
+ sprintf(buf,"%04X %04X %04X %04X\n",deco16_pf12_control[0],deco16_pf12_control[1],deco16_pf12_control[2],deco16_pf12_control[3]);
+ sprintf(&buf[strlen(buf)],"%04X %04X %04X %04X\n",deco16_pf12_control[4],deco16_pf12_control[5],deco16_pf12_control[6],deco16_pf12_control[7]);
+ }
+ else
+ sprintf(buf, "\n\n");
+
+ if (deco16_pf34_control) {
+ sprintf(&buf[strlen(buf)],"%04X %04X %04X %04X\n",deco16_pf34_control[0],deco16_pf34_control[1],deco16_pf34_control[2],deco16_pf34_control[3]);
+ sprintf(&buf[strlen(buf)],"%04X %04X %04X %04X\n",deco16_pf34_control[4],deco16_pf34_control[5],deco16_pf34_control[6],deco16_pf34_control[7]);
+ }
+ else
+ sprintf(&buf[strlen(buf)], "\n\n");
+
+ sprintf(&buf[strlen(buf)],"%04X",deco16_priority);
+
+ ui_draw_text(buf,60,40);
+}
+
+/*****************************************************************************************/
+
+void deco16_clear_sprite_priority_bitmap(void)
+{
+ if (sprite_priority_bitmap)
+ fillbitmap(sprite_priority_bitmap,0,NULL);
+}
+
+/* A special pdrawgfx z-buffered sprite renderer that is needed to properly draw multiple sprite sources with alpha */
+void deco16_pdrawgfx(mame_bitmap *dest,const gfx_element *gfx,
+ UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy,
+ const rectangle *clip,int transparency,int transparent_color,UINT32 pri_mask,UINT32 sprite_mask,UINT8 write_pri)
+{
+ int ox,oy,cx,cy;
+ int x_index,y_index,x,y;
+
+ const pen_t *pal = &Machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)];
+ int source_base = (code % gfx->total_elements) * gfx->height;
+
+ /* check bounds */
+ ox = sx;
+ oy = sy;
+
+ if (sx>319 || sy>247 || sx<-15 || sy<-7)
+ return;
+
+ if (sy<0) sy=0;
+ if (sx<0) sx=0;
+ if (sx>319) cx=319;
+ else cx=ox+16;
+
+ cy=(sy-oy);
+
+ if (flipy) y_index=15-cy; else y_index=cy;
+
+ for( y=0; y<16-cy; y++ )
+ {
+ UINT8 *source = gfx->gfxdata + ((source_base+y_index) * gfx->line_modulo);
+ UINT32 *destb = BITMAP_ADDR32(dest, sy, 0);
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, sy, 0);
+ UINT8 *spri = BITMAP_ADDR8(sprite_priority_bitmap, sy, 0);
+
+ if (sy >= 0 && sy < 248)
+ {
+ if (flipx) { source+=15-(sx-ox); x_index=-1; } else { x_index=1; source+=(sx-ox); }
+
+ for (x=sx; x<cx; x++)
+ {
+ int c = *source;
+ if( c != transparent_color && x >= 0 && x < 320 )
+ {
+ if (pri_mask>pri[x] && sprite_mask>spri[x]) {
+ if (transparency == TRANSPARENCY_ALPHA)
+ destb[x] = alpha_blend32(destb[x], pal[c]);
+ else
+ destb[x] = pal[c];
+ if (write_pri)
+ pri[x] |= pri_mask;
+ }
+ spri[x]|=sprite_mask;
+ }
+ source+=x_index;
+ }
+ }
+
+ sy++;
+ if (sy>247)
+ return;
+ if (flipy) y_index--; else y_index++;
+ }
+}
+
+/*****************************************************************************************/
+
+void deco16_tilemap_1_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, UINT32 priority)
+{
+ if (use_custom_pf1)
+ {
+ custom_tilemap_draw(bitmap,pf1_tilemap_8x8,pf1_tilemap_16x16,0,0,pf1_rowscroll_ptr,deco16_pf12_control[1], deco16_pf12_control[2], deco16_pf12_control[5]&0xff, deco16_pf12_control[6]&0xff, 0, 0, deco16_pf1_trans_mask, flags, priority);
+ }
+ else
+ {
+ if (pf1_tilemap_8x8) tilemap_draw(bitmap,cliprect,pf1_tilemap_8x8,flags,priority);
+ if (pf1_tilemap_16x16) tilemap_draw(bitmap,cliprect,pf1_tilemap_16x16,flags,priority);
+ }
+}
+
+void deco16_tilemap_2_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, UINT32 priority)
+{
+ if (use_custom_pf2)
+ {
+ custom_tilemap_draw(bitmap,pf2_tilemap_8x8,pf2_tilemap_16x16,0,0,pf2_rowscroll_ptr,deco16_pf12_control[3], deco16_pf12_control[4], deco16_pf12_control[5]>>8, deco16_pf12_control[6]>>8, 0, 0, deco16_pf2_trans_mask, flags, priority);
+ }
+ else
+ {
+ if (pf2_tilemap_8x8) tilemap_draw(bitmap,cliprect,pf2_tilemap_8x8,flags,priority);
+ if (pf2_tilemap_16x16) tilemap_draw(bitmap,cliprect,pf2_tilemap_16x16,flags,priority);
+ }
+}
+
+void deco16_tilemap_3_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, UINT32 priority)
+{
+ if (use_custom_pf3) custom_tilemap_draw(bitmap,0,pf3_tilemap_16x16,0,0,pf3_rowscroll_ptr,deco16_pf34_control[1], deco16_pf34_control[2], deco16_pf34_control[5]&0xff, deco16_pf34_control[6]&0xff, 0, 0, deco16_pf3_trans_mask, flags, priority);
+ else if (pf3_tilemap_16x16) tilemap_draw(bitmap,cliprect,pf3_tilemap_16x16,flags,priority);
+}
+
+void deco16_tilemap_4_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, UINT32 priority)
+{
+ if (use_custom_pf4) custom_tilemap_draw(bitmap,0,pf4_tilemap_16x16,0,0,pf4_rowscroll_ptr,deco16_pf34_control[3], deco16_pf34_control[4], deco16_pf34_control[5]>>8, deco16_pf34_control[6]>>8, 0, 0, deco16_pf4_trans_mask, flags, priority);
+ else if (pf4_tilemap_16x16) tilemap_draw(bitmap,cliprect,pf4_tilemap_16x16,flags,priority);
+}
+
+/*****************************************************************************************/
+
+// Combines the output of two 4BPP tilemaps into an 8BPP tilemap
+void deco16_tilemap_34_combine_draw(mame_bitmap *bitmap, const rectangle *cliprect, int flags, UINT32 priority)
+{
+ custom_tilemap_draw(bitmap,0,pf3_tilemap_16x16,0,pf4_tilemap_16x16,pf3_rowscroll_ptr,deco16_pf34_control[1], deco16_pf34_control[2], deco16_pf34_control[5]&0xff, deco16_pf34_control[6]&0xff, 0xf, 4, 0xff, flags, priority);
+}
+
+/*****************************************************************************************/
+
+/*
+ Consider this the 'reference rasterizer' for the 56/74/141 tilemap chips - it implements
+ simultaneous row & column scroll which the Mame tilemap core cannot do. It also
+ implements combining the 4BPP output of two tilemaps into 8BPP output. This function
+ is automatically called when the tilemap is in a state the cannot be properly rendered
+ by the Mame core.
+*/
+
+static void custom_tilemap_draw(
+ mame_bitmap *bitmap,
+ tilemap *tilemap0_8x8,
+ tilemap *tilemap0_16x16,
+ tilemap *tilemap1_8x8,
+ tilemap *tilemap1_16x16,
+ const UINT16 *rowscroll_ptr,
+ const UINT16 scrollx,
+ const UINT16 scrolly,
+ const UINT16 control0,
+ const UINT16 control1,
+ int combine_mask,
+ int combine_shift,
+ int trans_mask,
+ int flags,
+ UINT32 priority)
+{
+ tilemap *tilemap0 = (control1&0x80) ? tilemap0_8x8 : tilemap0_16x16;
+ tilemap *tilemap1 = (control1&0x80) ? tilemap1_8x8 : tilemap1_16x16;
+ const mame_bitmap *src_bitmap0 = tilemap0 ? tilemap_get_pixmap(tilemap0) : NULL;
+ const mame_bitmap *src_bitmap1 = tilemap1 ? tilemap_get_pixmap(tilemap1) : NULL;
+ int width_mask, height_mask, x, y, p;
+ int column_offset, src_x=0, src_y=0;
+ int row_type=1 << ((control0>>3)&0xf);
+ int col_type=8 << (control0&7);
+
+ if (!src_bitmap0)
+ return;
+
+ // Playfield disable
+ if (!(control0&0x80))
+ return;
+
+ width_mask=src_bitmap0->width - 1;
+ height_mask=src_bitmap0->height - 1;
+ src_y=scrolly + 8;
+
+ for (y=8; y<248; y++) {
+ if (rowscroll_ptr && (control1&0x40))
+ src_x=scrollx + rowscroll_ptr[src_y / row_type];
+ else
+ src_x=scrollx;
+
+ src_x &= width_mask;
+
+ if (bitmap->bpp == 16)
+ {
+ for (x=0; x<320; x++) {
+ if (rowscroll_ptr && (control1&0x20))
+ column_offset=rowscroll_ptr[0x200 + ((src_x&0x1ff) / col_type)];
+ else
+ column_offset=0;
+
+ p=*BITMAP_ADDR16(src_bitmap0, (src_y + column_offset)&height_mask, src_x);
+ if (src_bitmap1)
+ p|=(*BITMAP_ADDR16(src_bitmap1, (src_y + column_offset)&height_mask, src_x)&combine_mask)<<combine_shift;
+
+ src_x=(src_x+1)&width_mask;
+ if ((flags&TILEMAP_DRAW_OPAQUE) || (p&trans_mask))
+ {
+ *BITMAP_ADDR16(bitmap, y, x) = Machine->pens[p];
+ if (priority_bitmap)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ pri[x]|=priority;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* boogwing */
+ for (x=0; x<320; x++) {
+ if (rowscroll_ptr && (control1&0x20))
+ column_offset=rowscroll_ptr[0x200 + ((src_x&0x1ff) / col_type)];
+ else
+ column_offset=0;
+
+ p=*BITMAP_ADDR16(src_bitmap0, (src_y + column_offset)&height_mask, src_x);
+ if (src_bitmap1)
+ p|=(*BITMAP_ADDR16(src_bitmap1, (src_y + column_offset)&height_mask, src_x)&combine_mask)<<combine_shift;
+
+ src_x=(src_x+1)&width_mask;
+ if ((flags&TILEMAP_DRAW_OPAQUE) || (p&trans_mask))
+ {
+ *BITMAP_ADDR32(bitmap, y, x) = Machine->pens[p];
+ if (priority_bitmap)
+ {
+ UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0);
+ pri[x]|=priority;
+ }
+ }
+ }
+ }
+ src_y=(src_y+1)&height_mask;
+ }
+}