summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/megasys1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/video/megasys1.c')
-rw-r--r--src/mame/video/megasys1.c1022
1 files changed, 1022 insertions, 0 deletions
diff --git a/src/mame/video/megasys1.c b/src/mame/video/megasys1.c
new file mode 100644
index 00000000000..d8a4798c7aa
--- /dev/null
+++ b/src/mame/video/megasys1.c
@@ -0,0 +1,1022 @@
+/***************************************************************************
+
+ -= Jaleco Mega System 1 =-
+
+ driver by Luca Elia (l.elia@tin.it)
+
+
+
+********** There are 3 scrolling layers, 1 word per tile:
+
+* Note: MS1-Z has 2 layers only.
+
+ A page is 256x256, approximately the visible screen size. Each layer is
+ made up of 8 pages (8x8 tiles) or 32 pages (16x16 tiles). The number of
+ horizontal pages and the tiles size is selectable, using the layer's
+ control register. I think that when tiles are 16x16 a layer can be made
+ of 16x2, 8x4, 4x8 or 2x16 pages (see below). When tile size is 8x8 we
+ have two examples to guide the choice:
+
+ the copyright screen of p47j (0x12) should be 4x2 (unless it's been hacked :)
+ the ending sequence of 64th street (0x13) should be 2x4.
+
+ I don't see a relation.
+
+
+MS1-A MS1-B MS1-C
+-----------------
+
+ Scrolling layers:
+
+90000 50000 e0000 Scroll 0
+94000 54000 e8000 Scroll 1
+98000 58000 f0000 Scroll 2 * Note: missing on MS1-Z
+
+Tile format: fedc------------ Palette
+ ----ba9876543210 Tile Number
+
+
+
+84000 44000 c2208 Layers Enable * Note: missing on MS1-Z?
+
+ fedc ---- ---- ---- unused
+ ---- ba98 ---- ---- Priority Code
+ ---- ---- 7654 ---- unused
+ ---- ---- ---- 3--- Enable Sprites
+ ---- ---- ---- -210 Enable Layer 210
+
+ (Note that the bottom layer can't be disabled)
+
+
+84200 44200 c2000 Scroll 0 Control
+84208 44208 c2008 Scroll 1 Control
+84008 44008 c2100 Scroll 2 Control * Note: missing on MS1-Z
+
+Offset: 00 Scroll X
+ 02 Scroll Y
+ 04 fedc ba98 765- ---- ? (unused?)
+ ---- ---- ---4 ---- 0<->16x16 Tiles 1<->8x8 Tiles
+ ---- ---- ---- 32-- ? (used, by p47!)
+ ---- ---- ---- --10 N: Layer H pages = 16 / (2^N)
+
+
+
+84300 44300 c2308 Screen Control
+
+ fed- ---- ---- ---- ? (unused?)
+ ---c ---- ---- ---- ? (on, troughout peekaboo)
+ ---- ba9- ---- ---- ? (unused?)
+ ---- ---8 ---- ---- Portrait F/F (?FullFill?)
+ ---- ---- 765- ---- ? (unused?)
+ ---- ---- ---4 ---- Reset Sound CPU (1->0 Transition)
+ ---- ---- ---- 321- ? (unused?)
+ ---- ---- ---- ---0 Flip Screen
+
+
+
+********** There are 256*4 colors (256*3 for MS1-Z):
+
+Colors MS1-A/C MS1-Z
+
+000-0ff Scroll 0 Scroll 0
+100-1ff Scroll 1 Sprites
+200-2ff Scroll 2 Scroll 1
+300-3ff Sprites -
+
+88000 48000 f8000 Palette
+
+ fedc--------3--- Red
+ ----ba98-----2-- Blue
+ --------7654--1- Green
+ ---------------0 ? (used, not RGB! [not changed in fades])
+
+
+********** There are 256 sprites (128 for MS1-Z):
+
+&RAM[8000] Sprite Data (16 bytes/entry. 128? entries)
+
+Offset: 0-6 ? (used, but as normal RAM, I think)
+ 08 fed- ---- ---- ---- ?
+ ---c ---- ---- ---- mosaic sol. (?)
+ ---- ba98 ---- ---- mosaic (?)
+ ---- ---- 7--- ---- y flip
+ ---- ---- -6-- ---- x flip
+ ---- ---- --45 ---- ?
+ ---- ---- ---- 3210 color code (* bit 3 = priority *)
+ 0A H position
+ 0C V position
+ 0E fedc ---- ---- ---- ? (used by p47j, 0-8!)
+ ---- ba98 7654 3210 Number
+
+
+
+Object RAM tells the hw how to use Sprite Data (missing on MS1-Z).
+This makes it possible to group multiple small sprite, up to 256,
+into one big virtual sprite (up to a whole screen):
+
+8e000 4e000 d2000 Object RAM (8 bytes/entry. 256*4 entries)
+
+Offset: 00 Index into Sprite Data RAM
+ 02 H Displacement
+ 04 V Displacement
+ 06 Number Displacement
+
+Only one of these four 256 entries is used to see if the sprite is to be
+displayed, according to this latter's flipx/y state:
+
+Object RAM entries: Used by sprites with:
+
+000-0ff No Flip
+100-1ff Flip X
+200-2ff Flip Y
+300-3ff Flip X & Y
+
+
+
+
+No? No? c2108 Sprite Bank
+
+ fedc ba98 7654 321- ? (unused?)
+ ---- ---- ---- ---0 Sprite Bank
+
+
+
+84100 44100 c2200 Sprite Control
+
+ fedc ba9- ---- ---- ? (unused?)
+ ---- ---8 ---- ---- Enable Sprite Splitting In 2 Groups:
+ Some Sprite Appear Over, Some Below The Layers
+ ---- ---- 765- ---- ? (unused?)
+ ---- ---- ---4 ---- Enable Effect (?)
+ ---- ---- ---- 3210 Effect Number (?)
+
+I think bit 4 enables some sort of color cycling for sprites having priority
+bit set. See code of p7j at 6488, affecting the rotating sprites before the
+Jaleco logo is shown: values 11-1f, then 0. I fear the Effect Number is an
+offset to be applied over the pens used by those sprites. As for bit 8, it's
+not used during game, but it is turned on when sprite/foreground priority is
+tested, along with Effect Number being 1, so ...
+
+
+********** Priorities (ouch!)
+
+[ Sprite / Sprite order ]
+
+ [MS1-A,B,C] From first in Object RAM (frontmost) to last.
+ [MS1-Z] From last in Sprite RAM (frontmost) to first.
+
+[ Layer / Layer & Sprite / Layer order ]
+
+Controlled by:
+
+ * bits 7-4 (16 values) of the Layer Control register
+ * bit 4 of the Sprite Control register
+
+ Layer Control Sprite Control
+MS1-Z -
+MS1-A 84000 84100
+MS1-B 44000 44100
+MS1-C c2208 c2200
+
+When bit 4 of the Sprite Contol register is set, sprites with color
+code 0-7 and sprites with color 8-f form two groups. Each group can
+appear over or below some layers.
+
+The 16 values in the Layer Control register determine the order of
+the layers, and of the groups of sprites.
+
+There is a PROM that translates the values in the register to the
+actual code sent to the hardware.
+
+
+***************************************************************************/
+
+#include "driver.h"
+#include "megasys1.h"
+
+/* Variables defined here, that have to be shared: */
+tilemap *megasys1_tmap[3];
+
+UINT16 *megasys1_scrollram[3];
+UINT16 *megasys1_objectram, *megasys1_vregs, *megasys1_ram;
+
+int megasys1_scrollx[3], megasys1_scrolly[3];
+int megasys1_active_layers;
+int megasys1_bits_per_color_code;
+
+static int megasys1_scroll_flag[3];
+static int megasys1_sprite_bank;
+static int megasys1_screen_flag, megasys1_sprite_flag;
+static int megasys1_8x8_scroll_factor[3], megasys1_16x16_scroll_factor[3];
+
+static tilemap *megasys1_tilemap[3][2][4];
+
+/* Variables defined in driver: */
+static int hardware_type_z;
+
+static void create_tilemaps(void);
+
+
+
+#ifdef MAME_DEBUG
+
+#define SHOW_WRITE_ERROR(_format_,_offset_,_data_)\
+{ \
+ popmessage(_format_,_offset_,_data_);\
+ logerror("CPU #0 PC %06X : Warning, ",activecpu_get_pc()); \
+ logerror(_format_,_offset_,_data_);\
+ logerror("\n");\
+}
+
+#else
+
+#define SHOW_WRITE_ERROR(_format_,_offset_,_data_)\
+{\
+ logerror("CPU #0 PC %06X : Warning, ",activecpu_get_pc()); \
+ logerror(_format_,_offset_,_data_); \
+ logerror("\n");\
+}
+
+#endif
+
+
+
+VIDEO_START( megasys1 )
+{
+ int i;
+
+ spriteram16 = &megasys1_ram[0x8000/2];
+
+ create_tilemaps();
+ megasys1_tmap[0] = megasys1_tilemap[0][0][0];
+ megasys1_tmap[1] = megasys1_tilemap[1][0][0];
+ megasys1_tmap[2] = megasys1_tilemap[2][0][0];
+
+ megasys1_active_layers = megasys1_sprite_bank = megasys1_screen_flag = megasys1_sprite_flag = 0;
+
+ for (i = 0; i < 3; i ++)
+ {
+ megasys1_scroll_flag[i] = megasys1_scrollx[i] = megasys1_scrolly[i] = 0;
+ }
+
+ megasys1_bits_per_color_code = 4;
+
+/*
+ The tile code of a specific layer is multiplied for a constant
+ depending on the tile mode (8x8 or 16x16)
+
+ The most reasonable arrangement seems a 1:1 mapping (meaning we
+ must multiply by 4 the tile code in 16x16 mode, since we decode
+ the graphics like 8x8)
+
+ However, this is probably a game specific thing, as Soldam uses
+ layer 1 in both modes, and even with 8x8 tiles the tile code must
+ be multiplied by 4!
+
+ AFAIK, the other games use a layer in one mode only (always 8x8 or
+ 16x16) so it could be that the multiplication factor is constant
+ for each layer and hardwired to 1x or 4x for both tile sizes
+*/
+
+ megasys1_8x8_scroll_factor[0] = 1; megasys1_16x16_scroll_factor[0] = 4;
+ megasys1_8x8_scroll_factor[1] = 1; megasys1_16x16_scroll_factor[1] = 4;
+ megasys1_8x8_scroll_factor[2] = 1; megasys1_16x16_scroll_factor[2] = 4;
+
+ if (strcmp(machine->gamedrv->name, "soldamj") == 0)
+ {
+ megasys1_8x8_scroll_factor[1] = 4; megasys1_16x16_scroll_factor[1] = 4;
+ }
+
+ hardware_type_z = 0;
+ if (strcmp(machine->gamedrv->name, "lomakai") == 0 ||
+ strcmp(machine->gamedrv->name, "makaiden") == 0)
+ hardware_type_z = 1;
+}
+
+/***************************************************************************
+
+ Layers declarations:
+
+ * Read and write handlers for the layer
+ * Callbacks for the TileMap code
+
+***************************************************************************/
+
+#define TILES_PER_PAGE_X (0x20)
+#define TILES_PER_PAGE_Y (0x20)
+#define TILES_PER_PAGE (TILES_PER_PAGE_X * TILES_PER_PAGE_Y)
+
+INLINE void scrollram_w(int which, offs_t offset, UINT16 data, UINT16 mem_mask)
+{
+ COMBINE_DATA(&megasys1_scrollram[which][offset]);
+ if (offset < 0x40000/2 && megasys1_tmap[which])
+ {
+ if (megasys1_scroll_flag[which] & 0x10) /* tiles are 8x8 */
+ {
+ tilemap_mark_tile_dirty(megasys1_tmap[which], offset );
+ }
+ else
+ {
+ tilemap_mark_tile_dirty(megasys1_tmap[which], offset*4 + 0);
+ tilemap_mark_tile_dirty(megasys1_tmap[which], offset*4 + 1);
+ tilemap_mark_tile_dirty(megasys1_tmap[which], offset*4 + 2);
+ tilemap_mark_tile_dirty(megasys1_tmap[which], offset*4 + 3);
+ }
+ }
+}
+
+WRITE16_HANDLER( megasys1_scrollram_0_w ) { scrollram_w(0, offset, data, mem_mask); }
+WRITE16_HANDLER( megasys1_scrollram_1_w ) { scrollram_w(1, offset, data, mem_mask); }
+WRITE16_HANDLER( megasys1_scrollram_2_w ) { scrollram_w(2, offset, data, mem_mask); }
+
+
+
+
+/***************************************************************************
+
+ Video registers access
+
+***************************************************************************/
+
+
+/* Tilemap Size (PagesX x PagesY)
+
+ Reg. Value 16 8 <- Tile Size
+
+ 0 16 x 2 8 x 1
+ 1 8 x 4 4 x 2
+ 2 4 x 8 4 x 2
+ 3 2 x 16 2 x 4
+*/
+
+static TILEMAP_MAPPER( megasys1_scan_8x8 )
+{
+ return (col * TILES_PER_PAGE_Y) +
+ (row / TILES_PER_PAGE_Y) * TILES_PER_PAGE * (num_cols / TILES_PER_PAGE_X) +
+ (row % TILES_PER_PAGE_Y);
+}
+
+static TILEMAP_MAPPER( megasys1_scan_16x16 )
+{
+ return ( ((col / 2) * (TILES_PER_PAGE_Y / 2)) +
+ ((row / 2) / (TILES_PER_PAGE_Y / 2)) * (TILES_PER_PAGE / 4) * (num_cols / TILES_PER_PAGE_X) +
+ ((row / 2) % (TILES_PER_PAGE_Y / 2)) )*4 + (row&1) + (col&1)*2;
+}
+
+static TILE_GET_INFO( megasys1_get_scroll_tile_info_8x8 )
+{
+ int tmap = (FPTR)param;
+ UINT16 code = megasys1_scrollram[tmap][tile_index];
+ SET_TILE_INFO(tmap, (code & 0xfff) * megasys1_8x8_scroll_factor[tmap], code >> (16 - megasys1_bits_per_color_code), 0);
+}
+
+static TILE_GET_INFO( megasys1_get_scroll_tile_info_16x16 )
+{
+ int tmap = (FPTR)param;
+ UINT16 code = megasys1_scrollram[tmap][tile_index/4];
+ SET_TILE_INFO(tmap, (code & 0xfff) * megasys1_16x16_scroll_factor[tmap] + (tile_index & 3), code >> (16 - megasys1_bits_per_color_code), 0);
+}
+
+static void create_tilemaps(void)
+{
+ int layer, i;
+
+ for (layer = 0; layer < 3; layer++)
+ {
+ /* 16x16 tilemaps */
+ megasys1_tilemap[layer][0][0] = tilemap_create(megasys1_get_scroll_tile_info_16x16, megasys1_scan_16x16,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 16, TILES_PER_PAGE_Y * 2);
+ megasys1_tilemap[layer][0][1] = tilemap_create(megasys1_get_scroll_tile_info_16x16, megasys1_scan_16x16,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 8, TILES_PER_PAGE_Y * 4);
+ megasys1_tilemap[layer][0][2] = tilemap_create(megasys1_get_scroll_tile_info_16x16, megasys1_scan_16x16,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 4, TILES_PER_PAGE_Y * 8);
+ megasys1_tilemap[layer][0][3] = tilemap_create(megasys1_get_scroll_tile_info_16x16, megasys1_scan_16x16,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 2, TILES_PER_PAGE_Y * 16);
+
+ /* 8x8 tilemaps */
+ megasys1_tilemap[layer][1][0] = tilemap_create(megasys1_get_scroll_tile_info_8x8, megasys1_scan_8x8,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 8, TILES_PER_PAGE_Y * 1);
+ megasys1_tilemap[layer][1][1] = tilemap_create(megasys1_get_scroll_tile_info_8x8, megasys1_scan_8x8,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 4, TILES_PER_PAGE_Y * 2);
+ megasys1_tilemap[layer][1][2] = tilemap_create(megasys1_get_scroll_tile_info_8x8, megasys1_scan_8x8,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 4, TILES_PER_PAGE_Y * 2);
+ megasys1_tilemap[layer][1][3] = tilemap_create(megasys1_get_scroll_tile_info_8x8, megasys1_scan_8x8,
+ TILEMAP_TYPE_PEN, 8,8, TILES_PER_PAGE_X * 2, TILES_PER_PAGE_Y * 4);
+
+ /* set user data and transparency */
+ for (i = 0; i < 8; i++)
+ {
+ tilemap_set_user_data(megasys1_tilemap[layer][i/4][i%4], (void *)(FPTR)layer);
+ tilemap_set_transparent_pen(megasys1_tilemap[layer][i/4][i%4], 15);
+ }
+ }
+}
+
+void megasys1_set_vreg_flag(int which, int data)
+{
+ if (megasys1_scroll_flag[which] != data)
+ {
+ megasys1_scroll_flag[which] = data;
+ megasys1_tmap[which] = megasys1_tilemap[which][(data >> 4) & 1][data & 3];
+ tilemap_mark_all_tiles_dirty(megasys1_tmap[which]);
+ }
+}
+
+
+
+/* Used by MS1-A/Z, B */
+WRITE16_HANDLER( megasys1_vregs_A_w )
+{
+ UINT16 new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ switch (offset)
+ {
+ case 0x000/2 : megasys1_active_layers = new_data; break;
+
+ case 0x008/2+0 : megasys1_scrollx[2] = new_data; break;
+ case 0x008/2+1 : megasys1_scrolly[2] = new_data; break;
+ case 0x008/2+2 : megasys1_set_vreg_flag(2, new_data); break;
+
+ case 0x200/2+0 : megasys1_scrollx[0] = new_data; break;
+ case 0x200/2+1 : megasys1_scrolly[0] = new_data; break;
+ case 0x200/2+2 : megasys1_set_vreg_flag(0, new_data); break;
+
+ case 0x208/2+0 : megasys1_scrollx[1] = new_data; break;
+ case 0x208/2+1 : megasys1_scrolly[1] = new_data; break;
+ case 0x208/2+2 : megasys1_set_vreg_flag(1, new_data); break;
+
+ case 0x100/2 : megasys1_sprite_flag = new_data; break;
+
+ case 0x300/2 : megasys1_screen_flag = new_data;
+ if (new_data & 0x10)
+ cpunum_set_input_line(1, INPUT_LINE_RESET, ASSERT_LINE);
+ else
+ cpunum_set_input_line(1, INPUT_LINE_RESET, CLEAR_LINE);
+ break;
+
+ case 0x308/2 : soundlatch_word_w(0,new_data,0);
+ cpunum_set_input_line(1,4,HOLD_LINE);
+ break;
+
+ default : SHOW_WRITE_ERROR("vreg %04X <- %04X",offset*2,data);
+ }
+
+}
+
+
+
+
+/* Used by MS1-C only */
+READ16_HANDLER( megasys1_vregs_C_r )
+{
+ switch (offset)
+ {
+ case 0x8000/2: return soundlatch2_word_r(0,0);
+ default: return megasys1_vregs[offset];
+ }
+}
+
+WRITE16_HANDLER( megasys1_vregs_C_w )
+{
+ UINT16 new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ switch (offset)
+ {
+ case 0x2000/2+0 : megasys1_scrollx[0] = new_data; break;
+ case 0x2000/2+1 : megasys1_scrolly[0] = new_data; break;
+ case 0x2000/2+2 : megasys1_set_vreg_flag(0, new_data); break;
+
+ case 0x2008/2+0 : megasys1_scrollx[1] = new_data; break;
+ case 0x2008/2+1 : megasys1_scrolly[1] = new_data; break;
+ case 0x2008/2+2 : megasys1_set_vreg_flag(1, new_data); break;
+
+ case 0x2100/2+0 : megasys1_scrollx[2] = new_data; break;
+ case 0x2100/2+1 : megasys1_scrolly[2] = new_data; break;
+ case 0x2100/2+2 : megasys1_set_vreg_flag(2, new_data); break;
+
+ case 0x2108/2 : megasys1_sprite_bank = new_data; break;
+ case 0x2200/2 : megasys1_sprite_flag = new_data; break;
+ case 0x2208/2 : megasys1_active_layers = new_data; break;
+
+ case 0x2308/2 : megasys1_screen_flag = new_data;
+ if (new_data & 0x10)
+ cpunum_set_input_line(1, INPUT_LINE_RESET, ASSERT_LINE);
+ else
+ cpunum_set_input_line(1, INPUT_LINE_RESET, CLEAR_LINE);
+ break;
+
+ case 0x8000/2 : /* Cybattler reads sound latch on irq 2 */
+ soundlatch_word_w(0,new_data,0);
+ cpunum_set_input_line(1,2,HOLD_LINE);
+ break;
+
+ default: SHOW_WRITE_ERROR("vreg %04X <- %04X",offset*2,data);
+ }
+}
+
+
+
+/* Used by MS1-D only */
+WRITE16_HANDLER( megasys1_vregs_D_w )
+{
+ UINT16 new_data = COMBINE_DATA(&megasys1_vregs[offset]);
+
+ switch (offset)
+ {
+ case 0x2000/2+0 : megasys1_scrollx[0] = new_data; break;
+ case 0x2000/2+1 : megasys1_scrolly[0] = new_data; break;
+ case 0x2000/2+2 : megasys1_set_vreg_flag(0, new_data); break;
+
+ case 0x2008/2+0 : megasys1_scrollx[1] = new_data; break;
+ case 0x2008/2+1 : megasys1_scrolly[1] = new_data; break;
+ case 0x2008/2+2 : megasys1_set_vreg_flag(1, new_data); break;
+
+// case 0x2100/2+0 : megasys1_scrollx[2] = new_data; break;
+// case 0x2100/2+1 : megasys1_scrolly[2] = new_data; break;
+// case 0x2100/2+2 : megasys1_set_vreg_flag(2, new_data); break;
+
+ case 0x2108/2 : megasys1_sprite_bank = new_data; break;
+ case 0x2200/2 : megasys1_sprite_flag = new_data; break;
+ case 0x2208/2 : megasys1_active_layers = new_data; break;
+ case 0x2308/2 : megasys1_screen_flag = new_data; break;
+
+ default: SHOW_WRITE_ERROR("vreg %04X <- %04X",offset*2,data);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Sprites Drawing
+
+***************************************************************************/
+
+
+/* Draw sprites in the given bitmap.
+
+ Sprite Data:
+
+ Offset Data
+
+ 00-07 ?
+ 08 fed- ---- ---- ---- ?
+ ---c ---- ---- ---- mosaic sol. (?)
+ ---- ba98 ---- ---- mosaic (?)
+ ---- ---- 7--- ---- y flip
+ ---- ---- -6-- ---- x flip
+ ---- ---- --45 ---- ?
+ ---- ---- ---- 3210 color code (bit 3 = priority)
+ 0A X position
+ 0C Y position
+ 0E Code */
+
+static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
+{
+ int color,code,sx,sy,flipx,flipy,attr,sprite,offs,color_mask;
+
+/* objram: 0x100*4 entries spritedata: 0x80 entries */
+
+ /* sprite order is from first in Sprite Data RAM (frontmost) to last */
+
+ if (hardware_type_z == 0) /* standard sprite hardware */
+ {
+ color_mask = (megasys1_sprite_flag & 0x100) ? 0x07 : 0x0f;
+
+ for (offs = (0x800-8)/2;offs >= 0;offs -= 8/2)
+ {
+ for (sprite = 0; sprite < 4 ; sprite ++)
+ {
+ UINT16 *objectdata = &megasys1_objectram[offs + (0x800/2) * sprite];
+ UINT16 *spritedata = &spriteram16[ (objectdata[ 0 ] & 0x7f) * 0x10/2];
+
+ attr = spritedata[ 8/2 ];
+ if (((attr & 0xc0)>>6) != sprite) continue; // flipping
+
+ /* apply the position displacements */
+ sx = ( spritedata[0x0A/2] + objectdata[0x02/2] ) % 512;
+ sy = ( spritedata[0x0C/2] + objectdata[0x04/2] ) % 512;
+
+ if (sx > 256-1) sx -= 512;
+ if (sy > 256-1) sy -= 512;
+
+ flipx = attr & 0x40;
+ flipy = attr & 0x80;
+
+ if (megasys1_screen_flag & 1)
+ {
+ flipx = !flipx; flipy = !flipy;
+ sx = 240-sx; sy = 240-sy;
+ }
+
+ /* sprite code is displaced as well */
+ code = spritedata[0x0E/2] + objectdata[0x06/2];
+ color = (attr & color_mask);
+
+ pdrawgfx(bitmap,machine->gfx[3],
+ (code & 0xfff ) + ((megasys1_sprite_bank & 1) << 12),
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN,15,
+ (attr & 0x08) ? 0x0c : 0x0a);
+ } /* sprite */
+ } /* offs */
+ } /* non Z hw */
+ else
+ {
+
+ /* MS1-Z just draws Sprite Data, and in reverse order */
+
+ for (sprite = 0x80-1;sprite >= 0;sprite--)
+ {
+ UINT16 *spritedata = &spriteram16[ sprite * 0x10/2];
+
+ attr = spritedata[ 8/2 ];
+
+ sx = spritedata[0x0A/2] % 512;
+ sy = spritedata[0x0C/2] % 512;
+
+ if (sx > 256-1) sx -= 512;
+ if (sy > 256-1) sy -= 512;
+
+ code = spritedata[0x0E/2];
+ color = (attr & 0x0F);
+
+ flipx = attr & 0x40;
+ flipy = attr & 0x80;
+
+ if (megasys1_screen_flag & 1)
+ {
+ flipx = !flipx; flipy = !flipy;
+ sx = 240-sx; sy = 240-sy;
+ }
+
+ pdrawgfx(bitmap,machine->gfx[2],
+ code,
+ color,
+ flipx, flipy,
+ sx, sy,
+ cliprect,
+ TRANSPARENCY_PEN,15,
+ (attr & 0x08) ? 0x0c : 0x0a);
+ } /* sprite */
+ } /* Z hw */
+
+}
+
+
+
+
+/***************************************************************************
+ Convert the Priority Prom
+***************************************************************************/
+
+struct priority
+{
+ const char *driver;
+ int priorities[16];
+};
+
+static int megasys1_layers_order[16];
+
+/*
+ Layers order encoded as an int like: 0x01234, where
+
+ 0: Scroll 0
+ 1: Scroll 1
+ 2: Scroll 2
+ 3: Sprites with color 0-7
+ (*every sprite*, if sprite splitting is not active)
+ 4: Sprites with color 8-f
+ f: empty placeholder (we can't use 0!)
+
+ and the bottom layer is on the left (e.g. 0).
+
+ The special value 0xfffff means that the order is either unknown
+ or no simple stack of layers can account for the values in the prom.
+ (the default value, 0x04132, will be used in those cases)
+
+*/
+
+static const struct priority priorities[] =
+{
+ { "64street",
+ { 0x04132,0x03142,0x14032,0x04132,0xfffff,0x04132,0xfffff,0xfffff,
+ 0xfffff,0xfffff,0xfffff,0xfffff,0xfffff,0xfffff,0xfffff,0xfffff }
+ },
+ { "chimerab",
+ { 0x14032,0x04132,0x14032,0x04132,0xfffff,0xfffff,0xfffff,0xfffff,
+ 0xfffff,0xfffff,0x01324,0xfffff,0xfffff,0xfffff,0xfffff,0xfffff }
+ },
+ { 0 } // end of list: use the prom's data
+};
+
+
+/*
+ Convert the 512 bytes in the Priority Prom into 16 ints, encoding
+ the layers order for 16 selectable priority schemes.
+
+ INPUT (to the video chip):
+
+ 4 pixels: 3 layers(012) + 1 sprite (3)
+ (there are low and high priority sprites which
+ are split when the "split sprites" bit is set)
+
+ addr = ( (low pri sprite & split sprites ) << 0 ) +
+ ( (pixel 0 is enabled and opaque ) << 1 ) +
+ ( (pixel 1 is enabled and opaque ) << 2 ) +
+ ( (pixel 2 is enabled and opaque ) << 3 ) +
+ ( (pixel 3 is enabled and opaque ) << 4 ) +
+ ( (layers_enable bits 11-8 ) << 5 )
+
+ OUTPUT (to video):
+ 1 pixel, the one from layer: PROM[addr] (layer can be 0-3)
+
+ This scheme can generate a wealth of funky priority schemes
+ while we can account for just a simple stack of transparent
+ layers like: 01324. That is: bottom layer is 0, then 1, then
+ sprites (low priority sprites if sprite splitting is active,
+ every sprite if not) then layer 2 and high priority sprites
+ (only if sprite splitting is active).
+
+ Hence, during the conversion process we make sure each of the
+ 16 priority scheme in the prom is a "simple" one like the above
+ and log a warning otherwise. The feasibility criterion is such:
+
+ the opaque pens of the top layer must be above any other layer.
+ The transparent pens of the top layer must be either totally
+ opaque or totally transparent with respects to the other layers:
+ when the bit relative to the top layer is not set, the top layer's
+ code must be either always absent (transparent case) or always
+ present (opaque case) in the prom.
+
+ NOTE: This can't account for orders starting like: 030..
+ as found in peekaboo's prom. That's where sprites go below
+ the bottom layer's opaque pens, but above its transparent
+ pens.
+*/
+
+PALETTE_INIT( megasys1 )
+{
+ int pri_code, offset, i, order;
+
+ /* First check if we have an hand-crafted priority scheme
+ available (this should happen only if no good dump
+ of the prom is known) */
+
+ i = 0;
+ while ( priorities[i].driver &&
+ strcmp(priorities[i].driver, machine->gamedrv->name) != 0 &&
+ strcmp(priorities[i].driver, machine->gamedrv->parent) != 0)
+ i++;
+
+ if (priorities[i].driver)
+ {
+ memcpy (megasys1_layers_order, priorities[i].priorities, 16 * sizeof(int));
+
+ logerror("WARNING: using an hand-crafted priorities scheme\n");
+
+ return;
+ }
+
+ /* Otherwise, perform the conversion from the prom itself */
+
+ for (pri_code = 0; pri_code < 0x10 ; pri_code++) // 16 priority codes
+ {
+ int layers_order[2]; // 2 layers orders (split sprites on/off)
+
+ for (offset = 0; offset < 2; offset ++)
+ {
+ int enable_mask = 0xf; // start with every layer enabled
+
+ layers_order[offset] = 0xfffff;
+
+ do
+ {
+ int top = color_prom[pri_code * 0x20 + offset + enable_mask * 2] & 3; // this must be the top layer
+ int top_mask = 1 << top;
+
+ int result = 0; // result of the feasibility check for this layer
+
+ for (i = 0; i < 0x10 ; i++) // every combination of opaque and transparent pens
+ {
+ int opacity = i & enable_mask; // only consider active layers
+ int layer = color_prom[pri_code * 0x20 + offset + opacity * 2];
+
+ if (opacity)
+ {
+ if (opacity & top_mask)
+ {
+ if (layer != top ) result |= 1; // error: opaque pens aren't always opaque!
+ }
+ else
+ {
+ if (layer == top) result |= 2; // transparent pen is opaque
+ else result |= 4; // transparent pen is transparent
+ }
+ }
+ }
+
+ /* note: 3210 means that layer 0 is the bottom layer
+ (the order is reversed in the hand-crafted data) */
+
+ layers_order[offset] = ( (layers_order[offset] << 4) | top ) & 0xfffff;
+ enable_mask &= ~top_mask;
+
+ if (result & 1)
+ {
+ logerror("WARNING, pri $%X split %d - layer %d's opaque pens not totally opaque\n",pri_code,offset,top);
+
+ layers_order[offset] = 0xfffff;
+ break;
+ }
+
+ if ((result & 6) == 6)
+ {
+ logerror("WARNING, pri $%X split %d - layer %d's transparent pens aren't always transparent nor always opaque\n",pri_code,offset,top);
+
+ layers_order[offset] = 0xfffff;
+ break;
+ }
+
+ if (result == 2) enable_mask = 0; // totally opaque top layer
+
+ } while (enable_mask);
+
+ } // offset
+
+ /* merge the two layers orders */
+
+ order = 0xfffff;
+
+ for (i = 5; i > 0 ; ) // 5 layers to write
+ {
+ int layer;
+ int layer0 = layers_order[0] & 0x0f;
+ int layer1 = layers_order[1] & 0x0f;
+
+ if (layer0 != 3) // 0,1,2 or f
+ {
+ if (layer1 == 3)
+ {
+ layer = 4;
+ layers_order[0] <<= 4; // layer1 won't change next loop
+ }
+ else
+ {
+ layer = layer0;
+ if (layer0 != layer1)
+ {
+ logerror("WARNING, pri $%X - 'sprite splitting' does not simply split sprites\n",pri_code);
+
+ order = 0xfffff;
+ break;
+ }
+
+ }
+ }
+ else // layer0 = 3;
+ {
+ if (layer1 == 3)
+ {
+ layer = 0x43; // 4 must always be present
+ order <<= 4;
+ i --; // 2 layers written at once
+ }
+ else
+ {
+ layer = 3;
+ layers_order[1] <<= 4; // layer1 won't change next loop
+ }
+ }
+
+ /* reverse the order now */
+ order = (order << 4 ) | layer;
+
+ i --; // layer written
+
+ layers_order[0] >>= 4;
+ layers_order[1] >>= 4;
+
+ } // merging
+
+ megasys1_layers_order[pri_code] = order & 0xfffff; // at last!
+
+ } // pri_code
+
+
+
+#if 0
+ /* log the priority schemes */
+ for (i = 0; i < 16; i++)
+ logerror("PROM %X] %05x\n", i, megasys1_layers_order[i]);
+#endif
+
+
+}
+
+
+
+
+
+/***************************************************************************
+ Draw the game screen in the given mame_bitmap.
+***************************************************************************/
+
+
+VIDEO_UPDATE( megasys1 )
+{
+ int i,flag,pri,primask;
+ int active_layers;
+
+ if (hardware_type_z)
+ {
+ /* no layer 2 and fixed layers order? */
+ active_layers = 0x000b;
+ pri = 0x0314f;
+ }
+ else
+ {
+ int reallyactive = 0;
+
+ /* get layers order */
+ pri = megasys1_layers_order[(megasys1_active_layers & 0x0f0f) >> 8];
+
+#ifdef MAME_DEBUG
+ if (pri == 0xfffff)
+ {
+ popmessage("Pri: %04X - Flag: %04X", megasys1_active_layers, megasys1_sprite_flag);
+ }
+#endif
+
+ if (pri == 0xfffff) pri = 0x04132;
+
+ /* see what layers are really active (layers 4 & f will do no harm) */
+ for (i = 0;i < 5;i++)
+ reallyactive |= 1 << ((pri >> (4*i)) & 0x0f);
+
+ active_layers = megasys1_active_layers & reallyactive;
+ active_layers |= 1 << ((pri & 0xf0000) >> 16); // bottom layer can't be disabled
+ }
+
+ tilemap_set_flip( ALL_TILEMAPS, (megasys1_screen_flag & 1) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0 );
+
+ for (i = 0;i < 3;i++)
+ {
+ if (megasys1_tmap[i])
+ {
+ tilemap_set_enable(megasys1_tmap[i],active_layers & (1 << i));
+
+ tilemap_set_scrollx(megasys1_tmap[i],0,megasys1_scrollx[i]);
+ tilemap_set_scrolly(megasys1_tmap[i],0,megasys1_scrolly[i]);
+ }
+ }
+
+ fillbitmap(priority_bitmap,0,cliprect);
+
+ flag = TILEMAP_DRAW_OPAQUE;
+ primask = 0;
+
+ for (i = 0;i < 5;i++)
+ {
+ int layer = (pri & 0xf0000) >> 16;
+ pri <<= 4;
+
+ switch (layer)
+ {
+ case 0:
+ case 1:
+ case 2:
+ if ( (megasys1_tmap[layer]) && (active_layers & (1 << layer) ) )
+ {
+ tilemap_draw(bitmap,cliprect,megasys1_tmap[layer],flag,primask);
+ flag = 0;
+ }
+ break;
+ case 3:
+ case 4:
+ if (flag != 0)
+ {
+ flag = 0;
+ fillbitmap(bitmap,machine->pens[0],cliprect);
+ }
+
+ if (megasys1_sprite_flag & 0x100) /* sprites are split */
+ {
+ /* following tilemaps will obscure this sprites layer */
+ primask |= 1 << (layer-3);
+ }
+ else
+ /* following tilemaps will obscure all sprites */
+ if (layer == 3) primask |= 3;
+
+ break;
+ }
+ }
+
+ if (active_layers & 0x08)
+ draw_sprites(machine,bitmap,cliprect);
+ return 0;
+}