diff options
Diffstat (limited to 'src/mame/video/cps1.c')
-rw-r--r-- | src/mame/video/cps1.c | 1955 |
1 files changed, 1955 insertions, 0 deletions
diff --git a/src/mame/video/cps1.c b/src/mame/video/cps1.c new file mode 100644 index 00000000000..1ee5e333d8d --- /dev/null +++ b/src/mame/video/cps1.c @@ -0,0 +1,1955 @@ +/*************************************************************************** + +These are some of the CPS-B chip numbers: + +NAME CPS-B # C-board PAL's B-board PAL's +Forgotten Worlds / Lost Worlds CPS-B-01 DL-0411-10001 None LWCH1 & LW10 +Ghouls 'n Ghosts CPS-B-01 DL-0411-10001 None DM620, LW10 +Strider CPS-B-01 DL-0411-10001 None ST24N1 & LW10 or ST22B +Dynasty Wars CPS-B-02 DL-0411-10002 ? ? +Willow CPS-B-03 DL-0411-10003 None WL24B & LW10 +UN Squadron / Area 88 CPS-B-11 DL-0411-10004 None AR24B & LW10 +Street Fighter II (ETC Rev G) CPS-B-11 DL-0411-10004 None STF29 & IOB1 +Final Fight (World / Japan) CPS-B-04 DL-0411-10005 None S224B & LW10 +Final Fight (US) CPS-B-04* DL-0411-10001 None S224B & LW10 + *actually CPS-B-01, the original number was scratched out and "04" stamped over it +Varth CPS-B-04 DL-0411-10005 None VA24B & LW10 +1941 CPS-B-05 DL-0411-10006 ? YI24B & ? +Street Fighter II (US Rev D) CPS-B-05 DL-0411-10006 C632 STF29 & IOB1 +Mercs (US) CPS-B-12 DL-0411-10007 C628 0224B & IOB1 +Street Fighter II (Japan Rev C) CPS-B-12 DL-0411-10007 C632 STF29 & IOB1 +Magic Sword (US) CPS-B-13 DL-0411-10008 None MS24B & IOB1 +Street Fighter II (Japan) CPS-B-13 DL-0411-10008 C632 STF29 & IOB1 +Chiki Chiki Boys / Mega Twins CPS-B-14 DL-0411-10009 ? ? +Street Fighter II (US Rev I) CPS-B-14 DL-0411-10009 C632 STF29 & IOB1 +Nemo CPS-B-15 DL-0411-10010 ? NM24B & ? +Carrier Air Wing CPS-B-16 DL-0411-10011 None CA24B & IOB1 +Street Fighter II CPS-B-17 DL-0411-10012 C632 STF29 & IOB1 +Three Wonders* CPS-B-21 DL-0921-10014 IOC1 & C632 RT24B & IOB1 +King of Dragons* CPS-B-21 DL-0921-10014 IOC1 & C632 KD29B & IOB1 +Captain Commando* (US) CPS-B-21 DL-0921-10014 IOC1 & C632 CC63B, CCPRG & IOB1 +Knights of the Round* CPS-B-21 DL-0921-10014 IOC1 & C632 KR63B, BPRG1 & IOB1 +Street Fighter II' Champion Edition CPS-B-21 DL-0921-10014 IOC1 & C632 S9263B, BPRG1 & IOB1 +Capcom World 2* CPS-B-21 DL-0921-10014 IOC1 Q522B & IOB1 +Quiz and Dragons* CPS-B-21 DL-0921-10014 IOC1 QD22B & IOB1 +Warriors of Fate* CPS-B-21 DL-0921-10014 IOC1 TK263B, BPRG1 & IOB1 +Street Fighter II Turbo Hyper Fighting CPS-B-21 DL-0921-10014 IOC1 & C632 S9263B, BPRG1 & IOB1 +Cadillacs and Dinosaurs* CPS-B-21 DL-0921-10014 IOC1 CD63B, BPRG1 & IOB1 +Punisher* CPS-B-21 DL-0921-10014 IOC1 PS63B, BPRG1 & IOB1 +Saturday Night Slam Masters* CPS-B-21 DL-0921-10014 IOC1 MB63B, BPRG1 & IOB1 +Muscle Bomber Duo* CPS-B-21 DL-0921-10014 ? ? +Pnickies CPS-B-21? DL-0921-10014? ? ? +Pang 3 CPS-B-21 DL-0921-10014 IOC1 & C632 CP1B1F, CP1B8K & CP1B9KA +Megaman the Power Battle CPS-B-21 DL-0921-10014 IOC1 & C632 RCM63B, BPRG1 & IOB1 + +Street Fighter Zero changer system (Japan) CPS-B-21 DL-0921-10014 ? ? + +*denotes Suicide Battery + +You can set the suicide CPS-B-21 chips to their default layer register and priority bit values +if you pull pins 45 and 46 high (floating the pins seems to work, too). The default is the same +values as Street Fighter 2 CE/Turbo. + + + +OUTPUT PORTS +0x00-0x01 OBJ RAM base (/256) +0x02-0x03 Scroll1 (8x8) RAM base (/256) +0x04-0x05 Scroll2 (16x16) RAM base (/256) +0x06-0x07 Scroll3 (32x32) RAM base (/256) +0x08-0x09 rowscroll RAM base (/256) +0x0a-0x0b Palette base (/256) +0x0c-0x0d Scroll 1 X +0x0e-0x0f Scroll 1 Y +0x10-0x11 Scroll 2 X +0x12-0x13 Scroll 2 Y +0x14-0x15 Scroll 3 X +0x16-0x17 Scroll 3 Y +0x18-0x19 Starfield 1 X +0x1a-0x1b Starfield 1 Y +0x1c-0x1d Starfield 2 X +0x1e-0x1f Starfield 2 Y +0x20-0x21 start offset for the rowscroll matrix +0x22-0x23 unknown but widely used - usually 0x0e. bit 0 enables rowscroll + on layer 2. bit 15 is flip screen. + + +Some registers move from game to game.. following example strider +0x66-0x67 Layer control register + bits 14-15 seem to be unused + ghouls sets bits 15 in service mode when you press button 2 in + the input test + bits 6-13 (4 groups of 2 bits) select layer draw order + bits 1-5 enable the three tilemap layers and the two starfield + layers (the bit order changes from game to game). + Only Forgotten Worlds and Strider use the starfield. + bit 0 could be rowscroll related. It is set by captain commando, + varth, mtwins, mssword, cawing while rowscroll is active. However + kodj and sf2 do NOT set this bit while they are using rowscroll. + Games known to use row scrolling: + SF2 + Mega Twins (underwater, cave) + Carrier Air Wing (hazy background at beginning of mission 8, put 07 at ff8501 to jump there) + Magic Sword (fire on floor 3; screen distort after continue) + Varth (title screen) + Captain Commando (end game sequence) +0x68-0x69 Priority mask \ Tiles in the layer just below sprites can have +0x6a-0x6b Priority mask | four priority levels, each one associated with one +0x6c-0x6d Priority mask | of these masks. The masks indicate pens in the tile +0x6e-0x6f Priority mask / that have priority over sprites. +0x70-0x71 Control register (usually 0x003f). The details of how this register + works are unknown, but it definitely affects the palette; experiments + on the real board show that values different from 0x3f in the low 6 + bits cause wrong colors. The other bits seem to be unused. + There is one CPS2 game (Slammasters II) setting this to 0x2f: the + purpose is unknown. + The only other places where this register seems to be set to a value + different from 0x3f is during startup tests. Examples: + ghouls 0x02 + strider 0x02 + unsquad 0x0f + kod 0x0f + mtwins 0x0f + +Fixed registers +0x80-0x81 Sound command +0x88-0x89 Sound fade + +Known Bug List +============== +CPS2: +* CPS2 can do raster effects, certainly used by ssf2 (Cammy, DeeJay, T.Hawk levels), + msh (lava level, early in attract mode) and maybe others (xmcotaj, vsavj). + IRQ4 is some sort of scanline interrupt used for that purpose. + +* Its unknown what CPS2_OBJ_BASE register (0x400000) does but it is not a object base + register. All games use 0x7000 even if 0x7080 is used at this register (checked on + real HW). Maybe it sets the object bank used when cps2_objram_bank is set. + +* Sprites are currently lagged by one frame to keep sync with backgrounds. This causes + sprites to stay on screen one frame longer (visable in VSAV attract mode). + +Marvel Vs. Capcom +* Sometimes currupt gfx are displayed on the 32x32 layer as the screen flashes at the + start of super combo moves. The problem seems to be due to tiles being fetched before + the first 32x32 tile offset and results in data coming from 16x16 or 8x8 tiles instead. + +CPS1: +SF2 +* Missing chain in the foreground in Ken's level, and sign in Cun Li's level. + Those graphics are in the backmost layer. + +UN Squadron +* DOT TEST in service mode shows garbage chars + +Magic Sword. +* during attract mode, characters are shown with a black background. There is +a background, but the layers are disabled. I think this IS the correct +behaviour. + +King of Dragons (World). +* Distortion effect missing on character description screen during attract +mode. The game rapidly toggles on and off the layer enable bit. Again, I +think this IS the correct behaviour. The Japanese version does the +distortion as expected. + +3wonders +* one bad tile at the end of level 1 +* writes to output ports 42, 44, 46. + +qad +* layer enable mask incomplete + +wof +* In round 8, when the player goes over a bridge, there is a problem with +some sprites. When an enemy falls to the floor near the edge of the bridge, +parts of it become visible under the bridge. + + +Unknown issues +============== + +There are often some redundant high bits in the scroll layer's attributes. +I think that these are spare bits that the game uses for to store additional +information, not used by the hardware. +The games seem to use them to mark platforms, kill zones and no-go areas. + +***************************************************************************/ + +#include "driver.h" +#include "cps1.h" + +#define VERBOSE 0 + +#define CPS1_DUMP_VIDEO 0 + +/******************************************************************** + + Configuration table: + +********************************************************************/ + +/* Game specific data */ +struct CPS1config +{ + const char *name; /* game driver name */ + + /* Some games interrogate a couple of registers on bootup. */ + /* These are CPS1 board B self test checks. They wander from game to */ + /* game. */ + int cpsb_addr; /* CPS board B test register address */ + int cpsb_value; /* CPS board B test register expected value */ + + /* some games use as a protection check the ability to do 16-bit multiplies */ + /* with a 32-bit result, by writing the factors to two ports and reading the */ + /* result from two other ports. */ + /* It looks like this feature was introduced with 3wonders (CPSB ID = 08xx) */ + int mult_factor1; + int mult_factor2; + int mult_result_lo; + int mult_result_hi; + + int layer_control; + int priority[4]; + int control_reg; /* Control register? seems to be always 0x3f */ + + /* ideally, the layer enable masks should consist of only one bit, */ + /* but in many cases it is unknown which bit is which. */ + int layer_enable_mask[5]; + + int bank_scroll1; + int bank_scroll2; + int bank_scroll3; + + /* Some characters aren't visible */ + const int start_scroll2; + const int end_scroll2; + const int start_scroll3; + const int end_scroll3; + + int kludge; /* Ghouls n Ghosts sprite kludge */ +}; + +struct CPS1config *cps1_game_config; + +/* CPSB ID multiply protection ctrl priority masks unknwn layer enable masks */ +#define CPS_B_01 0x00,0x0000, 0,0,0,0, /* n/a */ 0x66,{0x68,0x6a,0x6c,0x6e},0x70, {0x02,0x04,0x08,0x30,0x30} +#define CPS_B_02 0x60,0x0002, 0,0,0,0, /* n/a */ 0x6c,{0x6a,0x68,0x66,0x64},0x62, {0x02,0x04,0x08,0x00,0x00} +#define CPS_B_03 0x00,0x0000, 0,0,0,0, /* n/a */ 0x70,{0x6e,0x6c,0x6a,0x68},0x66, {0x20,0x10,0x08,0x00,0x00} +#define CPS_B_04 0x60,0x0004, 0,0,0,0, /* n/a */ 0x6e,{0x66,0x70,0x68,0x72},0x6a, {0x02,0x0c,0x0c,0x00,0x00} +#define CPS_B_05 0x60,0x0005, 0,0,0,0, /* n/a */ 0x68,{0x6a,0x6c,0x6e,0x70},0x72, {0x02,0x08,0x20,0x14,0x14} +#define CPS_B_11 0x72,0x0401, 0,0,0,0, /* n/a */ 0x66,{0x68,0x6a,0x6c,0x6e},0x70, {0x08,0x10,0x20,0x00,0x00} +#define CPS_B_12 0x60,0x0402, 0,0,0,0, /* n/a */ 0x6c,{0x6a,0x68,0x66,0x64},0x62, {0x02,0x04,0x08,0x00,0x00} +#define CPS_B_13 0x6e,0x0403, 0,0,0,0, /* n/a */ 0x62,{0x64,0x66,0x68,0x6a},0x6c, {0x20,0x02,0x04,0x00,0x00} +#define CPS_B_14 0x5e,0x0404, 0,0,0,0, /* n/a */ 0x52,{0x54,0x56,0x58,0x5a},0x5c, {0x08,0x20,0x10,0x00,0x00} +#define CPS_B_15 0x4e,0x0405, 0,0,0,0, /* n/a */ 0x42,{0x44,0x46,0x48,0x4a},0x4c, {0x04,0x02,0x20,0x00,0x00} +#define CPS_B_16 0x40,0x0406, 0,0,0,0, /* n/a */ 0x4c,{0x4a,0x48,0x46,0x44},0x42, {0x10,0x0a,0x0a,0x00,0x00} +#define CPS_B_17 0x48,0x0407, 0,0,0,0, /* n/a */ 0x54,{0x52,0x50,0x4e,0x4c},0x4a, {0x08,0x10,0x02,0x00,0x00} +#define CPS_B_18 0xd0,0x0408, 0,0,0,0, /* n/a */ 0xdc,{0xda,0xd8,0xd6,0xd4},0xd2, {0x10,0x08,0x02,0x00,0x00} +#define NOBATTRY 0x00,0x0000, 0x40,0x42,0x44,0x46, 0x66,{0x68,0x6a,0x6c,0x6e},0x70, {0x02,0x04,0x08,0x30,0x30} // pang3 sets layer enable to 0x26 on startup +#define BATTRY_1 0x72,0x0800, 0x4e,0x4c,0x4a,0x48, 0x68,{0x66,0x64,0x62,0x60},0x70, {0x20,0x04,0x08,0x12,0x12} +#define BATTRY_2 0x00,0x0000, 0x5e,0x5c,0x5a,0x58, 0x60,{0x6e,0x6c,0x6a,0x68},0x70, {0x30,0x08,0x30,0x00,0x00} +#define BATTRY_3 0x00,0x0000, 0x46,0x44,0x42,0x40, 0x60,{0x6e,0x6c,0x6a,0x68},0x70, {0x20,0x12,0x12,0x00,0x00} +#define BATTRY_4 0x00,0x0000, 0x46,0x44,0x42,0x40, 0x68,{0x66,0x64,0x62,0x60},0x70, {0x20,0x10,0x02,0x00,0x00} +#define BATTRY_5 0x00,0x0000, 0x4e,0x4c,0x4a,0x48, 0x60,{0x6e,0x6c,0x6a,0x68},0x70, {0x20,0x06,0x06,0x00,0x00} +#define BATTRY_6 0x00,0x0000, 0x00,0x00,0x00,0x00, 0x60,{0x6e,0x6c,0x6a,0x68},0x70, {0x20,0x14,0x14,0x00,0x00} +#define BATTRY_7 0x00,0x0000, 0x00,0x00,0x00,0x00, 0x6c,{0x00,0x00,0x00,0x00},0x52, {0x14,0x02,0x14,0x00,0x00} +#define QSOUND_1 0x00,0x0000, 0x00,0x00,0x00,0x00, 0x62,{0x64,0x66,0x68,0x6a},0x6c, {0x10,0x08,0x04,0x00,0x00} +#define QSOUND_2 0x00,0x0000, 0x00,0x00,0x00,0x00, 0x4a,{0x4c,0x4e,0x40,0x42},0x44, {0x16,0x16,0x16,0x00,0x00} +#define QSOUND_3 0x4e,0x0c00, 0x00,0x00,0x00,0x00, 0x52,{0x54,0x56,0x48,0x4a},0x4c, {0x04,0x02,0x20,0x00,0x00} +#define QSOUND_4 0x6e,0x0c01, 0x00,0x00,0x00,0x00, 0x56,{0x40,0x42,0x68,0x6a},0x6c, {0x04,0x08,0x10,0x00,0x00} +#define QSOUND_5 0x5e,0x0c02, 0x00,0x00,0x00,0x00, 0x6a,{0x6c,0x6e,0x70,0x72},0x5c, {0x04,0x08,0x10,0x00,0x00} +#define HACK_B_1 0x00,0x0000, 0x00,0x00,0x00,0x00, 0x54,{0x52,0x50,0x4e,0x4c},0x5c, {0xff,0xff,0xff,0x00,0x00} + + +static struct CPS1config cps1_config_table[]= +{ + /* name CPSB banks tile limits kludge */ + {"forgottn",CPS_B_01, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 7 }, + {"lostwrld",CPS_B_01, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 7 }, + {"ghouls", CPS_B_01, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 1 }, + {"ghoulsu", CPS_B_01, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 1 }, + {"daimakai",CPS_B_01, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 1 }, + {"strider", CPS_B_01, 1,0,1, 0x0000,0xffff,0x0000,0xffff }, + {"stridrua",CPS_B_01, 1,0,1, 0x0000,0xffff,0x0000,0xffff }, + {"striderj",CPS_B_01, 1,0,1, 0x0000,0xffff,0x0000,0xffff }, + {"stridrja",CPS_B_01, 1,0,1, 0x0000,0xffff,0x0000,0xffff }, + {"dynwar", CPS_B_02, 0,1,1, 0x0000,0xffff,0x0000,0xffff }, + {"dynwarj", CPS_B_02, 0,1,1, 0x0000,0xffff,0x0000,0xffff }, + {"willow", CPS_B_03, 0,1,0, 0x0000,0xffff,0x0000,0xffff }, + {"willowj", CPS_B_03, 0,1,0, 0x0000,0xffff,0x0000,0xffff }, + {"willowje",CPS_B_03, 0,1,0, 0x0000,0xffff,0x0000,0xffff }, + {"ffight", CPS_B_04, 0,0,0, 0x0001,0xffff,0x0001,0xffff }, + {"ffightu", CPS_B_04, 0,0,0, 0x0001,0xffff,0x0001,0xffff }, + {"ffightua",CPS_B_01, 0,0,0, 0x0001,0xffff,0x0001,0xffff }, + {"ffightub",CPS_B_05, 0,0,0, 0x0001,0xffff,0x0001,0xffff }, // I think + {"ffightj", CPS_B_04, 0,0,0, 0x0001,0xffff,0x0001,0xffff }, + {"ffightj1",CPS_B_02, 0,0,0, 0x0001,0xffff,0x0001,0xffff }, + {"1941", CPS_B_05, 0,0,0, 0x0000,0xffff,0x0400,0x07ff }, + {"1941j", CPS_B_05, 0,0,0, 0x0000,0xffff,0x0400,0x07ff }, + {"unsquad", CPS_B_11, 0,0,0, 0x0000,0xffff,0x0001,0xffff }, /* CPSB ID not checked, but it's the same as sf2eg */ + {"area88", CPS_B_11, 0,0,0, 0x0000,0xffff,0x0001,0xffff }, /* CPSB ID not checked, but it's the same as sf2eg */ + {"mercs", CPS_B_12, 0,0,0, 0x0600,0x5bff,0x0700,0x17ff, 4 }, /* (uses port 74) */ + {"mercsu", CPS_B_12, 0,0,0, 0x0600,0x5bff,0x0700,0x17ff, 4 }, /* (uses port 74) */ + {"mercsua", CPS_B_12, 0,0,0, 0x0600,0x5bff,0x0700,0x17ff, 4 }, /* (uses port 74) */ + {"mercsj", CPS_B_12, 0,0,0, 0x0600,0x5bff,0x0700,0x17ff, 4 }, /* (uses port 74) */ + {"msword", CPS_B_13, 0,0,0, 0x2800,0x37ff,0x0000,0xffff, 3 }, /* CPSB ID not checked, but it's the same as sf2j */ + {"mswordr1",CPS_B_13, 0,0,0, 0x2800,0x37ff,0x0000,0xffff, 3 }, /* CPSB ID not checked, but it's the same as sf2j */ + {"mswordu", CPS_B_13, 0,0,0, 0x2800,0x37ff,0x0000,0xffff, 3 }, /* CPSB ID not checked, but it's the same as sf2j */ + {"mswordj", CPS_B_13, 0,0,0, 0x2800,0x37ff,0x0000,0xffff, 3 }, /* CPSB ID not checked, but it's the same as sf2j */ + {"mtwins", CPS_B_14, 0,0,0, 0x0000,0x3fff,0x0e00,0xffff }, + {"chikij", CPS_B_14, 0,0,0, 0x0000,0x3fff,0x0e00,0xffff }, + {"nemo", CPS_B_15, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"nemoj", CPS_B_15, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"cawing", CPS_B_16, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"cawingr1",CPS_B_16, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"cawingu", CPS_B_16, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"cawingj", CPS_B_16, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"sf2", CPS_B_11, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2eb", CPS_B_17, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2ua", CPS_B_17, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2ub", CPS_B_17, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2ud", CPS_B_05, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2ue", CPS_B_18, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2uf", CPS_B_15, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2ui", CPS_B_14, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2uk", CPS_B_17, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, // check CPS_B + {"sf2j", CPS_B_13, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2ja", CPS_B_17, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2jc", CPS_B_12, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + /* from here onwards the CPS-B board has suicide battery and multiply protection */ + {"3wonders",BATTRY_1, 0,1,0, 0x0000,0xffff,0x0000,0xffff, 2 }, + {"3wonderu",BATTRY_1, 0,1,0, 0x0000,0xffff,0x0000,0xffff, 2 }, + {"wonder3", BATTRY_1, 0,1,0, 0x0000,0xffff,0x0000,0xffff, 2 }, + {"kod", BATTRY_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"kodu", BATTRY_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"kodj", BATTRY_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"kodb", BATTRY_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* bootleg, doesn't use multiply protection */ + {"captcomm",BATTRY_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"captcomu",BATTRY_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"captcomj",BATTRY_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"knights", BATTRY_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 3 }, + {"knightsu",BATTRY_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 3 }, + {"knightsj",BATTRY_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 3 }, + {"sf2ce", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2ceua", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2ceub", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2ceuc", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2cej", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2rb", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2rb2", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2red", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2v004", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2accp2",NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2m1", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2m2", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2m3", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2m4", HACK_B_1, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 }, + {"sf2m5", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 }, + {"sf2m6", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 }, + {"sf2m7", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 }, + {"sf2yyc", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 }, + {"sf2koryu",NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff, 10 }, + {"varth", CPS_B_04, 0,0,0, 0x0000,0xffff,0x0c00,0x0fff }, /* CPSB test has been patched out (60=0008) */ + {"varthr1", CPS_B_04, 0,0,0, 0x0000,0xffff,0x0c00,0x0fff }, /* CPSB test has been patched out (60=0008) */ + {"varthu", CPS_B_04, 0,0,0, 0x0000,0xffff,0x0c00,0x0fff }, /* CPSB test has been patched out (60=0008) */ + {"varthj", BATTRY_5, 0,0,0, 0x0000,0xffff,0x0c00,0x0fff }, /* CPSB test has been patched out (72=0001) */ + {"cworld2j",BATTRY_6, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* The 0x76 priority values are incorrect values */ + {"wof", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* bootleg? */ + {"wofa", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* bootleg? */ + {"wofu", QSOUND_1, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"wofj", QSOUND_1, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"dino", QSOUND_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* layer enable never used */ + {"dinou", QSOUND_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* layer enable never used */ + {"dinoj", QSOUND_2, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* layer enable never used */ + {"punisher",QSOUND_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"punishru",QSOUND_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"punishrj",QSOUND_3, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"slammast",QSOUND_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"slammasu",QSOUND_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"mbomberj",QSOUND_4, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"mbombrd", QSOUND_5, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"mbombrdj",QSOUND_5, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"sf2hf", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2t", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"sf2tj", NOBATTRY, 2,2,2, 0x0000,0xffff,0x0000,0xffff }, + {"qad", BATTRY_7, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, /* TODO: layer enable */ + {"qadj", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"qtono2", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"megaman", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"rockmanj",NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"pnickj", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + {"pang3", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 5 }, /* EEPROM port is among the CPS registers */ + {"pang3j", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff, 5 }, /* EEPROM port is among the CPS registers */ + #ifdef MESS + {"sfzch", NOBATTRY, 0,0,0, 0x0000,0xffff,0x0000,0xffff }, + #endif + + /* CPS2 games */ + {"cps2", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2u", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2a", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2ar1", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2j", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2jr1", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2jr2", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2tb", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2tbr1",NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2tbj", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff }, + {"ssf2t", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 }, + {"ssf2tu", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 }, + {"ssf2tur1",NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 }, + {"ssf2ta", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 }, + {"ssf2xj", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 }, + {"xmcota", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 }, + {"xmcotau", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 }, + {"xmcotah", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 }, + {"xmcotaj", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 }, + {"xmcotaj1",NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 }, + {"xmcotajr",NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 }, + {"xmcotaa", NOBATTRY, 4,4,4, 0x0000,0xffff,0x0000,0xffff, 8 }, + {"hsf2", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 }, + {"hsf2j", NOBATTRY, 4,4,0, 0x0000,0xffff,0x0000,0xffff, 9 }, + {0} /* End of table */ +}; + +static int cps_version; +int cps1_scanline1; +int cps1_scanline2; +int cps1_scancalls; + +#ifdef UNUSED_FUNCTION +void cps_setversion(int v) +{ + cps_version=v; +} +#endif + + +static MACHINE_RESET( cps ) +{ + const char *gamename = machine->gamedrv->name; + struct CPS1config *pCFG=&cps1_config_table[0]; + + while(pCFG->name) + { + if (strcmp(pCFG->name, gamename) == 0) + { + break; + } + pCFG++; + } + cps1_game_config=pCFG; + + if (!cps1_game_config->name) + { + gamename="cps2"; + pCFG=&cps1_config_table[0]; + while(pCFG->name) + { + if (strcmp(pCFG->name, gamename) == 0) + { + break; + } + pCFG++; + } + cps1_game_config=pCFG; + } + + if (strcmp(gamename, "sf2rb" )==0) + { + /* Patch out protection check */ + UINT16 *rom = (UINT16 *)memory_region(REGION_CPU1); + rom[0xe5464/2] = 0x6012; + } + if (strcmp(gamename, "sf2rb2" )==0) + { + /* Patch out protection check */ + UINT16 *rom = (UINT16 *)memory_region(REGION_CPU1); + rom[0xe5332/2] = 0x6014; + } + +#if 0 + if (strcmp(gamename, "sf2accp2" )==0) + { + /* Patch out a odd branch which would be incorrectly interpreted + by the cpu core as a 32-bit branch. This branch would make the + game crash (address error, since it would branch to an odd address) + if location 180ca6 (outside ROM space) isn't 0. Protection check? */ + UINT16 *rom = (UINT16 *)memory_region(REGION_CPU1); + rom[0x11756/2] = 0x4e71; + } + else if (strcmp(gamename, "ghouls" )==0) + { + /* Patch out self-test... it takes forever */ + UINT16 *rom = (UINT16 *)memory_region(REGION_CPU1); + rom[0x61964/2] = 0x4ef9; + rom[0x61966/2] = 0x0000; + rom[0x61968/2] = 0x0400; + } +#endif +} + + +int cps1_port(int offset) +{ + return cps1_output[offset/2]; +} + +INLINE UINT16 *cps1_base(int offset,int boundary) +{ + int base=cps1_port(offset)*256; + /* + The scroll RAM must start on a 0x4000 boundary. + Some games do not do this. + For example: + Captain commando - continue screen will not display + Muscle bomber games - will animate garbage during gameplay + Mask out the irrelevant bits. + */ + base &= ~(boundary-1); + return &cps1_gfxram[(base&0x3ffff)/2]; +} + + + +READ16_HANDLER( cps1_output_r ) +{ +#if VERBOSE +if (offset >= 0x18/2) logerror("PC %06x: read output port %02x\n",activecpu_get_pc(),offset*2); +#endif + + /* Some games interrogate a couple of registers on bootup. */ + /* These are CPS1 board B self test checks. They wander from game to */ + /* game. */ + if (offset && offset == cps1_game_config->cpsb_addr/2) + return cps1_game_config->cpsb_value; + + /* some games use as a protection check the ability to do 16-bit multiplies */ + /* with a 32-bit result, by writing the factors to two ports and reading the */ + /* result from two other ports. */ + if (offset && offset == cps1_game_config->mult_result_lo/2) + return (cps1_output[cps1_game_config->mult_factor1/2] * + cps1_output[cps1_game_config->mult_factor2/2]) & 0xffff; + if (offset && offset == cps1_game_config->mult_result_hi/2) + return (cps1_output[cps1_game_config->mult_factor1/2] * + cps1_output[cps1_game_config->mult_factor2/2]) >> 16; + + /* Pang 3 EEPROM interface */ + if (cps1_game_config->kludge == 5 && offset == 0x7a/2) + return cps1_eeprom_port_r(0,mem_mask); + + return cps1_output[offset]; +} + +WRITE16_HANDLER( cps1_output_w ) +{ + /* Pang 3 EEPROM interface */ + if (cps1_game_config->kludge == 5 && offset == 0x7a/2) + { + cps1_eeprom_port_w(0,data,mem_mask); + return; + } + + data = COMBINE_DATA(&cps1_output[offset]); + + /* To mark scanlines for raster effects */ + if(offset == 0x52/2) + { + cps1_scanline2 = (data & 0x1ff); + } + if(offset == 0x50/2) + { + cps1_scanline1 = (data & 0x1ff); + } + + +#ifdef MAME_DEBUG +if (cps1_game_config->control_reg && offset == cps1_game_config->control_reg/2 && data != 0x3f) + logerror("control_reg = %04x",data); +#endif +#if VERBOSE +if (offset > 0x22/2 && + offset != cps1_game_config->layer_control/2 && + offset != cps1_game_config->priority[0]/2 && + offset != cps1_game_config->priority[1]/2 && + offset != cps1_game_config->priority[2]/2 && + offset != cps1_game_config->priority[3]/2 && + offset != cps1_game_config->control_reg/2) + logerror("PC %06x: write %02x to output port %02x\n",activecpu_get_pc(),data,offset*2); + +#ifdef MAME_DEBUG +if (offset == 0x22/2 && (data & ~0x8001) != 0x0e) + logerror("port 22 = %04x",data); +if (cps1_game_config->priority[0] && offset == cps1_game_config->priority[0]/2 && data != 0x00) + popmessage("priority0 %04x",data); +#endif +#endif +} + + + +/* Public variables */ +UINT16 *cps1_gfxram; +UINT16 *cps1_output; + +size_t cps1_gfxram_size; +size_t cps1_output_size; + +/* Offset of each palette entry */ +static int palette_basecolor[6]; +#define cps1_palette_entries (32*8) /* Number colour schemes in palette */ + +const int cps1_scroll_size =0x4000; /* scroll1, scroll2, scroll3 */ +const int cps1_obj_size =0x0800; +const int cps1_other_size =0x0800; +const int cps1_palette_align=0x0800; /* can't be larger than this, breaks ringdest & batcirc otherwise */ +const int cps1_palette_size=cps1_palette_entries*32; /* Size of palette RAM */ + +static UINT16 *cps1_scroll1; +static UINT16 *cps1_scroll2; +static UINT16 *cps1_scroll3; +static UINT16 *cps1_obj; +static UINT16 *cps1_buffered_obj; +static UINT16 *cps1_palette; +UINT16 *cps1_other; +static UINT16 *cps1_old_palette; + +/* Working variables */ +static int cps1_last_sprite_offset; /* Offset of the last sprite */ +static int cps1_stars_enabled[2]; /* Layer enabled [Y/N] */ + +tilemap *cps1_bg_tilemap[3]; + + +int cps1_scroll1x, cps1_scroll1y; +int cps1_scroll2x, cps1_scroll2y; +int cps1_scroll3x, cps1_scroll3y; +static int stars1x, stars1y, stars2x, stars2y; + + +/* Output ports */ +#define CPS1_OBJ_BASE 0x00 /* Base address of objects */ +#define CPS1_SCROLL1_BASE 0x02 /* Base address of scroll 1 */ +#define CPS1_SCROLL2_BASE 0x04 /* Base address of scroll 2 */ +#define CPS1_SCROLL3_BASE 0x06 /* Base address of scroll 3 */ +#define CPS1_OTHER_BASE 0x08 /* Base address of other video */ +#define CPS1_PALETTE_BASE 0x0a /* Base address of palette */ +#define CPS1_SCROLL1_SCROLLX 0x0c /* Scroll 1 X */ +#define CPS1_SCROLL1_SCROLLY 0x0e /* Scroll 1 Y */ +#define CPS1_SCROLL2_SCROLLX 0x10 /* Scroll 2 X */ +#define CPS1_SCROLL2_SCROLLY 0x12 /* Scroll 2 Y */ +#define CPS1_SCROLL3_SCROLLX 0x14 /* Scroll 3 X */ +#define CPS1_SCROLL3_SCROLLY 0x16 /* Scroll 3 Y */ +#define CPS1_STARS1_SCROLLX 0x18 /* Stars 1 X */ +#define CPS1_STARS1_SCROLLY 0x1a /* Stars 1 Y */ +#define CPS1_STARS2_SCROLLX 0x1c /* Stars 2 X */ +#define CPS1_STARS2_SCROLLY 0x1e /* Stars 2 Y */ + +#define CPS1_ROWSCROLL_OFFS 0x20 /* base of row scroll offsets in other RAM */ + +#define CPS1_SCROLL2_WIDTH 0x40 +#define CPS1_SCROLL2_HEIGHT 0x40 + + +/* +CPS1 VIDEO RENDERER + +*/ +/* first 0x4000 of gfx ROM are used, but 0x0000-0x1fff is == 0x2000-0x3fff */ +static const int stars_rom_size = 0x2000; + +/* PSL: CPS2 support */ +const int cps2_obj_size =0x2000; +UINT16 *cps2_objram1,*cps2_objram2; +UINT16 *cps2_output; + +size_t cps2_output_size; +static UINT16 *cps2_buffered_obj; +static int pri_ctrl; /* Sprite layer priorities */ +static int cps2_objram_bank; +static int cps2_last_sprite_offset; /* Offset of the last sprite */ + +#define CPS2_OBJ_BASE 0x00 /* Unknown (not base address of objects). Could be bass address of bank used when object swap bit set? */ +#define CPS2_OBJ_UK1 0x02 /* Unknown (nearly always 0x807d, or 0x808e when screen flipped) */ +#define CPS2_OBJ_PRI 0x04 /* Layers priorities */ +#define CPS2_OBJ_UK2 0x06 /* Unknown (usually 0x0000, 0x1101 in ssf2, 0x0001 in 19XX) */ +#define CPS2_OBJ_XOFFS 0x08 /* X offset (usually 0x0040) */ +#define CPS2_OBJ_YOFFS 0x0a /* Y offset (always 0x0010) */ + +INLINE int cps2_port(int offset) +{ + return cps2_output[offset/2]; +} + + + + +static void cps1_gfx_decode(void) +{ + int size=memory_region_length(REGION_GFX1); + int i,j,gfxsize; + UINT8 *cps1_gfx = memory_region(REGION_GFX1); + + + gfxsize=size/4; + + for (i = 0;i < gfxsize;i++) + { + UINT32 src = cps1_gfx[4*i] + (cps1_gfx[4*i+1]<<8) + (cps1_gfx[4*i+2]<<16) + (cps1_gfx[4*i+3]<<24); + UINT32 dwval = 0; + + for (j = 0;j < 8;j++) + { + int n = 0; + UINT32 mask = (0x80808080 >> j) & src; + + if (mask & 0x000000ff) n |= 1; + if (mask & 0x0000ff00) n |= 2; + if (mask & 0x00ff0000) n |= 4; + if (mask & 0xff000000) n |= 8; + + dwval |= n << (j * 4); + } + cps1_gfx[4*i ] = dwval>>0; + cps1_gfx[4*i+1] = dwval>>8; + cps1_gfx[4*i+2] = dwval>>16; + cps1_gfx[4*i+3] = dwval>>24; + } +} + +static void unshuffle(UINT64 *buf,int len) +{ + int i; + UINT64 t; + + if (len == 2) return; + + assert(len % 4 == 0); /* must not happen */ + + len /= 2; + + unshuffle(buf,len); + unshuffle(buf + len,len); + + for (i = 0;i < len/2;i++) + { + t = buf[len/2 + i]; + buf[len/2 + i] = buf[len + i]; + buf[len + i] = t; + } +} + +static void cps2_gfx_decode(void) +{ + const int banksize=0x200000; + int size=memory_region_length(REGION_GFX1); + int i; + + for (i = 0;i < size;i += banksize) + unshuffle((UINT64 *)(memory_region(REGION_GFX1) + i),banksize/8); + + cps1_gfx_decode(); +} + + +DRIVER_INIT( cps1 ) +{ + cps1_gfx_decode(); +} + + + +DRIVER_INIT( cps2_video ) +{ + cps2_gfx_decode(); + + cps1_scanline1 = 262; + cps1_scanline2 = 262; + cps1_scancalls = 0; +} + + +#if CPS1_DUMP_VIDEO +static void cps1_dump_video(void) +{ + FILE *fp; + fp=fopen("SCROLL1.DMP", "w+b"); + if (fp) + { + fwrite(cps1_scroll1, cps1_scroll_size, 1, fp); + fclose(fp); + } + fp=fopen("SCROLL2.DMP", "w+b"); + if (fp) + { + fwrite(cps1_scroll2, cps1_scroll_size, 1, fp); + fclose(fp); + } + fp=fopen("SCROLL3.DMP", "w+b"); + if (fp) + { + fwrite(cps1_scroll3, cps1_scroll_size, 1, fp); + fclose(fp); + } + + fp=fopen("OBJ.DMP", "w+b"); + if (fp) + { + fwrite(cps1_obj, cps1_obj_size, 1, fp); + fclose(fp); + } + if (cps_version == 2) + { + /* PSL: CPS2 support */ + fp=fopen("OBJCPS2.DMP", "w+b"); + if (fp) + { + fwrite(cps2_objram1, cps2_obj_size, 1, fp); + fwrite(cps2_objram2, cps2_obj_size, 1, fp); + fclose(fp); + } + fp=fopen("CPS2OUTP.DMP", "w+b"); + if (fp) + { + fwrite(cps2_output, cps2_output_size, 1, fp); + fclose(fp); + } + + } + + + fp=fopen("OTHER.DMP", "w+b"); + if (fp) + { + fwrite(cps1_other, cps1_other_size, 1, fp); + fclose(fp); + } + + fp=fopen("PALETTE.DMP", "w+b"); + if (fp) + { + fwrite(cps1_palette, cps1_palette_size, 1, fp); + fclose(fp); + } + + fp=fopen("OUTPUT.DMP", "w+b"); + if (fp) + { + fwrite(cps1_output, cps1_output_size, 1, fp); + fclose(fp); + } + fp=fopen("VIDEO.DMP", "w+b"); + if (fp) + { + fwrite(cps1_gfxram, cps1_gfxram_size, 1, fp); + fclose(fp); + } + +} +#endif + + +void cps1_get_video_base(void ) +{ + int layercontrol, scroll1xoff, scroll2xoff, scroll3xoff; + + /* Re-calculate the VIDEO RAM base */ + if (cps1_scroll1 != cps1_base(CPS1_SCROLL1_BASE,cps1_scroll_size)) + { + cps1_scroll1 = cps1_base(CPS1_SCROLL1_BASE,cps1_scroll_size); + tilemap_mark_all_tiles_dirty(cps1_bg_tilemap[0]); + } + if (cps1_scroll2 != cps1_base(CPS1_SCROLL2_BASE,cps1_scroll_size)) + { + cps1_scroll2 = cps1_base(CPS1_SCROLL2_BASE,cps1_scroll_size); + tilemap_mark_all_tiles_dirty(cps1_bg_tilemap[1]); + } + if (cps1_scroll3 != cps1_base(CPS1_SCROLL3_BASE,cps1_scroll_size)) + { + cps1_scroll3 = cps1_base(CPS1_SCROLL3_BASE,cps1_scroll_size); + tilemap_mark_all_tiles_dirty(cps1_bg_tilemap[2]); + } + + /* Some of the sf2 hacks use only sprite port 0x9100 and the scroll layers are offset */ + if (cps1_game_config->kludge == 10) + { + cps1_output[CPS1_OBJ_BASE/2] = 0x9100; + cps1_obj=cps1_base(CPS1_OBJ_BASE, cps1_obj_size); + scroll1xoff = -0x0c; + scroll2xoff = -0x0e; + scroll3xoff = -0x10; + } + else + { + cps1_obj=cps1_base(CPS1_OBJ_BASE, cps1_obj_size); + scroll1xoff = 0; + scroll2xoff = 0; + scroll3xoff = 0; + } + cps1_palette=cps1_base(CPS1_PALETTE_BASE,cps1_palette_align); + cps1_other=cps1_base(CPS1_OTHER_BASE,cps1_other_size); + + /* Get scroll values */ + cps1_scroll1x=cps1_port(CPS1_SCROLL1_SCROLLX) + scroll1xoff; + cps1_scroll1y=cps1_port(CPS1_SCROLL1_SCROLLY); + cps1_scroll2x=cps1_port(CPS1_SCROLL2_SCROLLX) + scroll2xoff; + cps1_scroll2y=cps1_port(CPS1_SCROLL2_SCROLLY); + cps1_scroll3x=cps1_port(CPS1_SCROLL3_SCROLLX) + scroll3xoff; + cps1_scroll3y=cps1_port(CPS1_SCROLL3_SCROLLY); + stars1x =cps1_port(CPS1_STARS1_SCROLLX); + stars1y =cps1_port(CPS1_STARS1_SCROLLY); + stars2x =cps1_port(CPS1_STARS2_SCROLLX); + stars2y =cps1_port(CPS1_STARS2_SCROLLY); + + /* Get layer enable bits */ + layercontrol=cps1_port(cps1_game_config->layer_control); + tilemap_set_enable(cps1_bg_tilemap[0],layercontrol & cps1_game_config->layer_enable_mask[0]); + tilemap_set_enable(cps1_bg_tilemap[1],layercontrol & cps1_game_config->layer_enable_mask[1]); + tilemap_set_enable(cps1_bg_tilemap[2],layercontrol & cps1_game_config->layer_enable_mask[2]); + cps1_stars_enabled[0] = layercontrol & cps1_game_config->layer_enable_mask[3]; + cps1_stars_enabled[1] = layercontrol & cps1_game_config->layer_enable_mask[4]; + + +#ifdef MAME_DEBUG +{ + int enablemask; + +#if 0 +if (input_code_pressed(KEYCODE_Z)) +{ + if (input_code_pressed(KEYCODE_Q)) cps1_layer_enabled[3]=0; + if (input_code_pressed(KEYCODE_W)) cps1_layer_enabled[2]=0; + if (input_code_pressed(KEYCODE_E)) cps1_layer_enabled[1]=0; + if (input_code_pressed(KEYCODE_R)) cps1_layer_enabled[0]=0; + if (input_code_pressed(KEYCODE_T)) + { + popmessage("%d %d %d %d layer %02x", + (layercontrol>>0x06)&03, + (layercontrol>>0x08)&03, + (layercontrol>>0x0a)&03, + (layercontrol>>0x0c)&03, + layercontrol&0xc03f + ); + } + +} +#endif + + enablemask = 0; + if (cps1_game_config->layer_enable_mask[0] == cps1_game_config->layer_enable_mask[1]) + enablemask = cps1_game_config->layer_enable_mask[0]; + if (cps1_game_config->layer_enable_mask[0] == cps1_game_config->layer_enable_mask[2]) + enablemask = cps1_game_config->layer_enable_mask[0]; + if (cps1_game_config->layer_enable_mask[1] == cps1_game_config->layer_enable_mask[2]) + enablemask = cps1_game_config->layer_enable_mask[1]; + if (enablemask) + { + if (((layercontrol & enablemask) && (layercontrol & enablemask) != enablemask)) + popmessage("layer %02x",layercontrol&0xc03f); + } +} +#endif + +{ + int enablemask; + enablemask = cps1_game_config->layer_enable_mask[0] | cps1_game_config->layer_enable_mask[1] + | cps1_game_config->layer_enable_mask[2] + | cps1_game_config->layer_enable_mask[3] | cps1_game_config->layer_enable_mask[4]; + if (((layercontrol & ~enablemask) & 0xc03e) != 0) + popmessage("layer %02x contact MAMEDEV",layercontrol&0xc03f); +} + +} + + +WRITE16_HANDLER( cps1_gfxram_w ) +{ + int page = (offset >> 7) & 0x3c0; + COMBINE_DATA(&cps1_gfxram[offset]); + + if (page == (cps1_port(CPS1_SCROLL1_BASE) & 0x3c0)) + tilemap_mark_tile_dirty(cps1_bg_tilemap[0],offset/2 & 0x0fff); + if (page == (cps1_port(CPS1_SCROLL2_BASE) & 0x3c0)) + tilemap_mark_tile_dirty(cps1_bg_tilemap[1],offset/2 & 0x0fff); + if (page == (cps1_port(CPS1_SCROLL3_BASE) & 0x3c0)) + tilemap_mark_tile_dirty(cps1_bg_tilemap[2],offset/2 & 0x0fff); +} + + + +/*************************************************************************** + + Start the video hardware emulation. + +***************************************************************************/ + +static TILEMAP_MAPPER( tilemap0_scan ) +{ + /* logical (col,row) -> memory offset */ + return (row & 0x1f) + ((col & 0x3f) << 5) + ((row & 0x20) << 6); +} + +static TILEMAP_MAPPER( tilemap1_scan ) +{ + /* logical (col,row) -> memory offset */ + return (row & 0x0f) + ((col & 0x3f) << 4) + ((row & 0x30) << 6); +} + +static TILEMAP_MAPPER( tilemap2_scan ) +{ + /* logical (col,row) -> memory offset */ + return (row & 0x07) + ((col & 0x3f) << 3) + ((row & 0x38) << 6); +} + +static UINT8 empty_tile[32*32/2]; + +static TILE_GET_INFO( get_tile0_info ) +{ + int base = cps1_game_config->bank_scroll1 * 0x08000; + int code = cps1_scroll1[2*tile_index]; + int attr = cps1_scroll1[2*tile_index+1]; + int gfxset; + + /* allows us to reproduce a problem seen with a ffight board where USA and Japanese + roms have been mixed to be reproduced (ffightua) -- it looks like each column + should alternate between the left and right side of the 16x16 tiles */ + if (tile_index&0x20) gfxset = 1; + else gfxset = 0; + + /* knights & msword */ + if (cps1_game_config->kludge == 3) + if (code == 0xf020) { gfxset = 4; code = 0; } // use a blank tile (see startup text..) + + /* 0x0020 appears to never be drawn for CPS1 games (it is drawn for CPS2 games though, see gigawing '0' in score for example) */ + if (cps_version == 1 && code == 0x0020) { gfxset = 4; code = 0; } + + SET_TILE_INFO( + gfxset, + code + base, + (attr & 0x1f) + palette_basecolor[1], + TILE_FLIPYX((attr & 0x60) >> 5)); + tileinfo->group = (attr & 0x0180) >> 7; +} + +static TILE_GET_INFO( get_tile1_info ) +{ + int base = cps1_game_config->bank_scroll2 * 0x04000; + const int startcode = cps1_game_config->start_scroll2; + const int endcode = cps1_game_config->end_scroll2; + int code = cps1_scroll2[2*tile_index]; + int attr = cps1_scroll2[2*tile_index+1]; + + SET_TILE_INFO( + 2, + code + base, + (attr & 0x1f) + palette_basecolor[2], + TILE_FLIPYX((attr & 0x60) >> 5)); + tileinfo->group = (attr & 0x0180) >> 7; + + if (code < startcode || code > endcode + /* + MERCS has an gap in the scroll 2 layout + (bad tiles at start of level 2)*/ + || (cps1_game_config->kludge == 4 && (code >= 0x1e00 && code < 0x5400)) + ) + { + tileinfo->pen_data = empty_tile; + } +} + +static TILE_GET_INFO( get_tile2_info ) +{ + int base = cps1_game_config->bank_scroll3 * 0x1000; + const int startcode = cps1_game_config->start_scroll3; + const int endcode = cps1_game_config->end_scroll3; + int code = cps1_scroll3[2*tile_index]; + int attr = cps1_scroll3[2*tile_index+1]; + + if (cps1_game_config->kludge == 2 && code < 0x0e00) + { + code += 0x1000; + } + if (cps1_game_config->kludge == 8 && code >= 0x5800) + { + code -= 0x4000; + } + if (cps1_game_config->kludge == 9 && code < 0x5600) + { + code += 0x4000; + } + + SET_TILE_INFO( + 3, + code + base, + (attr & 0x1f) + palette_basecolor[3], + TILE_FLIPYX((attr & 0x60) >> 5)); + tileinfo->group = (attr & 0x0180) >> 7; + + if (code < startcode || code > endcode) + { + tileinfo->pen_data = empty_tile; + } +} + + + +static void cps1_update_transmasks(void) +{ + int i; + + for (i = 0;i < 4;i++) + { + int mask; + + /* Get transparency registers */ + if (cps1_game_config->priority[i]) + mask = cps1_port(cps1_game_config->priority[i]) ^ 0xffff; + else mask = 0xffff; /* completely transparent if priority masks not defined (mercs, qad) */ + + tilemap_set_transmask(cps1_bg_tilemap[0],i,mask,0x8000); + tilemap_set_transmask(cps1_bg_tilemap[1],i,mask,0x8000); + tilemap_set_transmask(cps1_bg_tilemap[2],i,mask,0x8000); + } +} + +static void cps1_create_empty_8x8_tile(running_machine *machine) +{ + /* for the 8x8 layer we can't use GFX_RAW so we need to create an empty tile + so that the 'don't draw tile' kludges work */ + static const gfx_layout empty_layout8x8 = + { + 8,8, + 1, + 4, + { 0, 1, 2, 3 }, + { 1*4, 0*4, 3*4, 2*4, 5*4, 4*4, 7*4, 6*4 }, + { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64 }, + 64*8 + }; + + machine->gfx[4] = allocgfx(&empty_layout8x8); + decodechar(machine->gfx[4], 0, (UINT8 *)empty_tile, &empty_layout8x8); + machine->gfx[4]->total_colors = 0x100; + +} + +static VIDEO_START( cps ) +{ + int i; + + machine_reset_cps(machine); + + cps1_bg_tilemap[0] = tilemap_create(get_tile0_info,tilemap0_scan,TILEMAP_TYPE_PEN, 8, 8,64,64); + cps1_bg_tilemap[1] = tilemap_create(get_tile1_info,tilemap1_scan,TILEMAP_TYPE_PEN,16,16,64,64); + cps1_bg_tilemap[2] = tilemap_create(get_tile2_info,tilemap2_scan,TILEMAP_TYPE_PEN,32,32,64,64); + + /* front masks will change at runtime to handle sprite occluding */ + cps1_update_transmasks(); + memset(empty_tile,0xff,sizeof(empty_tile)); + + cps1_create_empty_8x8_tile(machine); + + cps1_old_palette=auto_malloc(cps1_palette_size); + memset(cps1_old_palette, 0x00, cps1_palette_size); + for (i = 0;i < cps1_palette_entries*16;i++) + { + palette_set_color(machine,i,MAKE_RGB(0,0,0)); + } + + cps1_buffered_obj = auto_malloc (cps1_obj_size); + memset(cps1_buffered_obj, 0x00, cps1_obj_size); + + if (cps_version==2) { + cps2_buffered_obj = auto_malloc (cps2_obj_size); + memset(cps2_buffered_obj, 0x00, cps2_obj_size); + } + + memset(cps1_gfxram, 0, cps1_gfxram_size); /* Clear GFX RAM */ + memset(cps1_output, 0, cps1_output_size); /* Clear output ports */ + + if (cps_version == 2) + { + memset(cps2_objram1, 0, cps2_obj_size); + memset(cps2_objram2, 0, cps2_obj_size); + } + + /* Put in some defaults */ + cps1_output[CPS1_OBJ_BASE/2] = 0x9200; + cps1_output[CPS1_SCROLL1_BASE/2] = 0x9000; + cps1_output[CPS1_SCROLL2_BASE/2] = 0x9040; + cps1_output[CPS1_SCROLL3_BASE/2] = 0x9080; + cps1_output[CPS1_OTHER_BASE/2] = 0x9100; + cps1_output[CPS1_PALETTE_BASE/2] = 0x90c0; + + assert_always(cps1_game_config, "cps1_game_config hasn't been set up yet"); + + /* Set up old base */ + cps1_get_video_base(); /* Calculate base pointers */ + cps1_get_video_base(); /* Calculate old base pointers */ + + /* set palette banks */ + palette_basecolor[0] = 0*32; /* obj */ + palette_basecolor[1] = 1*32; /* scroll1 */ + palette_basecolor[2] = 2*32; /* scroll2 */ + palette_basecolor[3] = 3*32; /* scroll3 */ + palette_basecolor[4] = 4*32; /* stars1 */ + palette_basecolor[5] = 5*32; /* stars2 */ +} + +VIDEO_START( cps1 ) +{ + cps_version=1; + video_start_cps(machine); +} + +VIDEO_START( cps2 ) +{ + if (cps_version != 99) + { + cps_version=2; + } + video_start_cps(machine); +} + +/*************************************************************************** + + Build palette from palette RAM + + 12 bit RGB with a 4 bit brightness value. + +***************************************************************************/ + +void cps1_build_palette(running_machine *machine) +{ + int offset; + + for (offset = 0; offset < cps1_palette_entries*16; offset++) + { + int palette = cps1_palette[offset]; + + if (palette != cps1_old_palette[offset]) + { + int red, green, blue, bright; + + bright = 0x10 + (palette>>12); + + red = ((palette>>8)&0x0f) * bright * 0x11 / 0x1f; + green = ((palette>>4)&0x0f) * bright * 0x11 / 0x1f; + blue = ((palette>>0)&0x0f) * bright * 0x11 / 0x1f; + + palette_set_color (machine, offset, MAKE_RGB(red, green, blue)); + cps1_old_palette[offset] = palette; + } + } +} + + + +/*************************************************************************** + + Sprites + ======= + + Sprites are represented by a number of 8 byte values + + xx xx yy yy nn nn aa aa + + where xxxx = x position + yyyy = y position + nnnn = tile number + aaaa = attribute word + 0x0001 colour + 0x0002 colour + 0x0004 colour + 0x0008 colour + 0x0010 colour + 0x0020 X Flip + 0x0040 Y Flip + 0x0080 X & Y offset toggle (used in Marvel vs. Capcom.) + 0x0100 X block size (in sprites) + 0x0200 X block size + 0x0400 X block size + 0x0800 X block size + 0x1000 Y block size (in sprites) + 0x2000 Y block size + 0x4000 Y block size + 0x8000 Y block size + + The end of the table (may) be marked by an attribute value of 0xff00. + +***************************************************************************/ + +static void cps1_find_last_sprite(void) /* Find the offset of last sprite */ +{ + int offset=0; + /* Locate the end of table marker */ + while (offset < cps1_obj_size/2) + { + int colour=cps1_buffered_obj[offset+3]; + if ((colour & 0xff00) == 0xff00) + { + /* Marker found. This is the last sprite. */ + cps1_last_sprite_offset=offset-4; + return; + } + offset+=4; + } + /* Sprites must use full sprite RAM */ + cps1_last_sprite_offset=cps1_obj_size/2-4; +} + + +static void cps1_render_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) +{ +#define DRAWSPRITE(CODE,COLOR,FLIPX,FLIPY,SX,SY) \ +{ \ + if (flip_screen) \ + pdrawgfx(bitmap,machine->gfx[2], \ + CODE, \ + COLOR, \ + !(FLIPX),!(FLIPY), \ + 511-16-(SX),255-16-(SY), \ + cliprect,TRANSPARENCY_PEN,15,0x02); \ + else \ + pdrawgfx(bitmap,machine->gfx[2], \ + CODE, \ + COLOR, \ + FLIPX,FLIPY, \ + SX,SY, \ + cliprect,TRANSPARENCY_PEN,15,0x02); \ +} + + + int i, baseadd; + UINT16 *base=cps1_buffered_obj; + + /* some sf2 hacks draw the sprites in reverse order */ + if (cps1_game_config->kludge == 10) + { + base += cps1_last_sprite_offset; + baseadd = -4; + } + else + { + baseadd = 4; + } + + for (i=cps1_last_sprite_offset; i>=0; i-=4) + { + int x=*(base+0); + int y=*(base+1); + int code =*(base+2); + int colour=*(base+3); + int col=colour&0x1f; + +// x-=0x20; +// y+=0x20; + + if (cps1_game_config->kludge == 7) + { + code += 0x4000; + } + if (cps1_game_config->kludge == 1 && code >= 0x01000) + { + code += 0x4000; + } + if (cps1_game_config->kludge == 2 && code >= 0x02a00) + { + code += 0x4000; + } + + if (code < machine->gfx[1]->total_elements) + { + if (colour & 0xff00 ) + { + /* handle blocked sprites */ + int nx=(colour & 0x0f00) >> 8; + int ny=(colour & 0xf000) >> 12; + int nxs,nys,sx,sy; + nx++; + ny++; + + if (colour & 0x40) + { + /* Y flip */ + if (colour &0x20) + { + for (nys=0; nys<ny; nys++) + { + for (nxs=0; nxs<nx; nxs++) + { + sx = (x+nxs*16) & 0x1ff; + sy = (y+nys*16) & 0x1ff; + + DRAWSPRITE( + code+(nx-1)-nxs+0x10*(ny-1-nys), + (col&0x1f) + palette_basecolor[0], + 1,1, + sx,sy); + } + } + } + else + { + for (nys=0; nys<ny; nys++) + { + for (nxs=0; nxs<nx; nxs++) + { + sx = (x+nxs*16) & 0x1ff; + sy = (y+nys*16) & 0x1ff; + + DRAWSPRITE( + code+nxs+0x10*(ny-1-nys), + (col&0x1f) + palette_basecolor[0], + 0,1, + sx,sy); + } + } + } + } + else + { + if (colour &0x20) + { + for (nys=0; nys<ny; nys++) + { + for (nxs=0; nxs<nx; nxs++) + { + sx = (x+nxs*16) & 0x1ff; + sy = (y+nys*16) & 0x1ff; + + DRAWSPRITE( + code+(nx-1)-nxs+0x10*nys, + (col&0x1f) + palette_basecolor[0], + 1,0, + sx,sy); + } + } + } + else + { + for (nys=0; nys<ny; nys++) + { + for (nxs=0; nxs<nx; nxs++) + { + sx = (x+nxs*16) & 0x1ff; + sy = (y+nys*16) & 0x1ff; + + DRAWSPRITE( + code+nxs+0x10*nys, + (col&0x1f) + palette_basecolor[0], + 0,0, + sx,sy); + } + } + } + } + } + else + { + /* Simple case... 1 sprite */ + DRAWSPRITE( + code, + (col&0x1f) + palette_basecolor[0], + colour&0x20,colour&0x40, + x & 0x1ff,y & 0x1ff); + } + } + base += baseadd; + } +#undef DRAWSPRITE +} + + + + +WRITE16_HANDLER( cps2_objram_bank_w ) +{ + if (ACCESSING_LSB) + { + cps2_objram_bank = data & 1; + } +} + +READ16_HANDLER( cps2_objram1_r ) +{ + if (cps2_objram_bank & 1) + return cps2_objram2[offset]; + else + return cps2_objram1[offset]; +} + +READ16_HANDLER( cps2_objram2_r ) +{ + if (cps2_objram_bank & 1) + return cps2_objram1[offset]; + else + return cps2_objram2[offset]; +} + +WRITE16_HANDLER( cps2_objram1_w ) +{ + if (cps2_objram_bank & 1) + COMBINE_DATA(&cps2_objram2[offset]); + else + COMBINE_DATA(&cps2_objram1[offset]); +} + +WRITE16_HANDLER( cps2_objram2_w ) +{ + if (cps2_objram_bank & 1) + COMBINE_DATA(&cps2_objram1[offset]); + else + COMBINE_DATA(&cps2_objram2[offset]); +} + +static UINT16 *cps2_objbase(void) +{ + int baseptr; + baseptr = 0x7000; + + if (cps2_objram_bank & 1) baseptr ^= 0x0080; + +//popmessage("%04x %d",cps2_port(CPS2_OBJ_BASE),cps2_objram_bank&1); + + if (baseptr == 0x7000) + return cps2_objram1; + else //if (baseptr == 0x7080) + return cps2_objram2; +} + + +static void cps2_find_last_sprite(void) /* Find the offset of last sprite */ +{ + int offset=0; + UINT16 *base=cps2_buffered_obj; + + /* Locate the end of table marker */ + while (offset < cps2_obj_size/2) + { + if (base[offset+1]>=0x8000 + || base[offset+3]>=0xff00) + { + /* Marker found. This is the last sprite. */ + cps2_last_sprite_offset=offset-4; + return; + } + + offset+=4; + } + /* Sprites must use full sprite RAM */ + cps2_last_sprite_offset=cps2_obj_size/2-4; +#undef DRAWSPRITE +} + +static void cps2_render_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect,int *primasks) +{ +#define DRAWSPRITE(CODE,COLOR,FLIPX,FLIPY,SX,SY) \ +{ \ + if (flip_screen) \ + pdrawgfx(bitmap,machine->gfx[2], \ + CODE, \ + COLOR, \ + !(FLIPX),!(FLIPY), \ + 511-16-(SX),255-16-(SY), \ + cliprect,TRANSPARENCY_PEN,15,primasks[priority]); \ + else \ + pdrawgfx(bitmap,machine->gfx[2], \ + CODE, \ + COLOR, \ + FLIPX,FLIPY, \ + SX,SY, \ + cliprect,TRANSPARENCY_PEN,15,primasks[priority]); \ +} + + int i; + UINT16 *base=cps2_buffered_obj; + int xoffs = 64-cps2_port(CPS2_OBJ_XOFFS); + int yoffs = 16-cps2_port(CPS2_OBJ_YOFFS); + +#ifdef MAME_DEBUG + if (input_code_pressed(KEYCODE_Z) && input_code_pressed(KEYCODE_R)) + { + return; + } +#endif + + for (i=cps2_last_sprite_offset; i>=0; i-=4) + { + int x=base[i+0]; + int y=base[i+1]; + int priority=(x>>13)&0x07; + int code = base[i+2]+((y & 0x6000) <<3); + int colour= base[i+3]; + int col=colour&0x1f; + + if(colour & 0x80) + { + x += cps2_port(CPS2_OBJ_XOFFS); /* fix the offset of some games */ + y += cps2_port(CPS2_OBJ_YOFFS); /* like Marvel vs. Capcom ending credits */ + } + + if (colour & 0xff00 ) + { + /* handle blocked sprites */ + int nx=(colour & 0x0f00) >> 8; + int ny=(colour & 0xf000) >> 12; + int nxs,nys,sx,sy; + nx++; + ny++; + + if (colour & 0x40) + { + /* Y flip */ + if (colour &0x20) + { + for (nys=0; nys<ny; nys++) + { + for (nxs=0; nxs<nx; nxs++) + { + sx = (x+nxs*16+xoffs) & 0x3ff; + sy = (y+nys*16+yoffs) & 0x3ff; + DRAWSPRITE( + code+(nx-1)-nxs+0x10*(ny-1-nys), + (col&0x1f) + palette_basecolor[0], + 1,1, + sx,sy); + } + } + } + else + { + for (nys=0; nys<ny; nys++) + { + for (nxs=0; nxs<nx; nxs++) + { + sx = (x+nxs*16+xoffs) & 0x3ff; + sy = (y+nys*16+yoffs) & 0x3ff; + + DRAWSPRITE( + code+nxs+0x10*(ny-1-nys), + (col&0x1f) + palette_basecolor[0], + 0,1, + sx,sy); + } + } + } + } + else + { + if (colour &0x20) + { + for (nys=0; nys<ny; nys++) + { + for (nxs=0; nxs<nx; nxs++) + { + sx = (x+nxs*16+xoffs) & 0x3ff; + sy = (y+nys*16+yoffs) & 0x3ff; + + DRAWSPRITE( + code+(nx-1)-nxs+0x10*nys, + (col&0x1f) + palette_basecolor[0], + 1,0, + sx,sy); + } + } + } + else + { + for (nys=0; nys<ny; nys++) + { + for (nxs=0; nxs<nx; nxs++) + { + sx = (x+nxs*16+xoffs) & 0x3ff; + sy = (y+nys*16+yoffs) & 0x3ff; + + DRAWSPRITE( +// code+nxs+0x10*nys, + (code & ~0xf) + ((code + nxs) & 0xf) + 0x10*nys, // pgear fix + (col&0x1f) + palette_basecolor[0], + 0,0, + sx,sy); + } + } + } + } + } + else + { + /* Simple case... 1 sprite */ + DRAWSPRITE( + code, + (col&0x1f) + palette_basecolor[0], + colour&0x20,colour&0x40, + (x+xoffs) & 0x3ff,(y+yoffs) & 0x3ff); + } + } +} + + + + +static void cps1_render_stars(running_machine *machine,mame_bitmap *bitmap,const rectangle *cliprect) +{ + int offs; + UINT8 *stars_rom = memory_region(REGION_GFX2); + + if (!stars_rom && (cps1_stars_enabled[0] || cps1_stars_enabled[1])) + { +#ifdef MAME_DEBUG + popmessage("stars enabled but no stars ROM"); +#endif + return; + } + + if (cps1_stars_enabled[0]) + { + for (offs = 0;offs < stars_rom_size/2;offs++) + { + int col = stars_rom[8*offs+4]; + if (col != 0x0f) + { + int sx = (offs / 256) * 32; + int sy = (offs % 256); + sx = (sx - stars2x + (col & 0x1f)) & 0x1ff; + sy = (sy - stars2y) & 0xff; + if (flip_screen) + { + sx = 511 - sx; + sy = 255 - sy; + } + + col = ((col & 0xe0) >> 1) + (cpu_getcurrentframe()/16 & 0x0f); + + if (sx >= cliprect->min_x && sx <= cliprect->max_x && + sy >= cliprect->min_y && sy <= cliprect->max_y) + *BITMAP_ADDR16(bitmap, sy, sx) = machine->pens[0xa00+col]; + } + } + } + + if (cps1_stars_enabled[1]) + { + for (offs = 0;offs < stars_rom_size/2;offs++) + { + int col = stars_rom[8*offs]; + if (col != 0x0f) + { + int sx = (offs / 256) * 32; + int sy = (offs % 256); + sx = (sx - stars1x + (col & 0x1f)) & 0x1ff; + sy = (sy - stars1y) & 0xff; + if (flip_screen) + { + sx = 511 - sx; + sy = 255 - sy; + } + + col = ((col & 0xe0) >> 1) + (cpu_getcurrentframe()/16 & 0x0f); + + if (sx >= cliprect->min_x && sx <= cliprect->max_x && + sy >= cliprect->min_y && sy <= cliprect->max_y) + *BITMAP_ADDR16(bitmap, sy, sx) = machine->pens[0x800+col]; + } + } + } +} + + +static void cps1_render_layer(running_machine *machine,mame_bitmap *bitmap,const rectangle *cliprect,int layer,int primask) +{ + switch (layer) + { + case 0: + cps1_render_sprites(machine,bitmap,cliprect); + break; + case 1: + case 2: + case 3: + tilemap_draw(bitmap,cliprect,cps1_bg_tilemap[layer-1],TILEMAP_DRAW_LAYER1,primask); + break; + } +} + +static void cps1_render_high_layer(mame_bitmap *bitmap, const rectangle *cliprect, int layer) +{ + switch (layer) + { + case 0: + /* there are no high priority sprites */ + break; + case 1: + case 2: + case 3: + tilemap_draw(NULL,cliprect,cps1_bg_tilemap[layer-1],TILEMAP_DRAW_LAYER0,1); + break; + } +} + + +/*************************************************************************** + + Refresh screen + +***************************************************************************/ + +VIDEO_UPDATE( cps1 ) +{ + int layercontrol,l0,l1,l2,l3; + int videocontrol=cps1_port(0x22); + + + flip_screen_set(videocontrol & 0x8000); + + layercontrol = cps1_output[cps1_game_config->layer_control/2]; + + /* Get video memory base registers */ + cps1_get_video_base(); + + /* Find the offset of the last sprite in the sprite table */ + cps1_find_last_sprite(); + if (cps_version == 2) + { + cps2_find_last_sprite(); + } + /* Build palette */ + cps1_build_palette(machine); + + cps1_update_transmasks(); + + tilemap_set_scrollx(cps1_bg_tilemap[0],0,cps1_scroll1x); + tilemap_set_scrolly(cps1_bg_tilemap[0],0,cps1_scroll1y); + if (videocontrol & 0x01) /* linescroll enable */ + { + int scrly=-cps1_scroll2y; + int i; + int otheroffs; + + tilemap_set_scroll_rows(cps1_bg_tilemap[1],1024); + + otheroffs = cps1_port(CPS1_ROWSCROLL_OFFS); + + for (i = 0;i < 256;i++) + tilemap_set_scrollx(cps1_bg_tilemap[1],(i - scrly) & 0x3ff,cps1_scroll2x + cps1_other[(i + otheroffs) & 0x3ff]); + } + else + { + tilemap_set_scroll_rows(cps1_bg_tilemap[1],1); + tilemap_set_scrollx(cps1_bg_tilemap[1],0,cps1_scroll2x); + } + tilemap_set_scrolly(cps1_bg_tilemap[1],0,cps1_scroll2y); + tilemap_set_scrollx(cps1_bg_tilemap[2],0,cps1_scroll3x); + tilemap_set_scrolly(cps1_bg_tilemap[2],0,cps1_scroll3y); + + + /* Blank screen */ + fillbitmap(bitmap,machine->pens[4095],cliprect); + + cps1_render_stars(machine,bitmap,cliprect); + + /* Draw layers (0 = sprites, 1-3 = tilemaps) */ + l0 = (layercontrol >> 0x06) & 03; + l1 = (layercontrol >> 0x08) & 03; + l2 = (layercontrol >> 0x0a) & 03; + l3 = (layercontrol >> 0x0c) & 03; + fillbitmap(priority_bitmap,0,cliprect); + + if (cps_version == 1) + { + cps1_render_layer(machine,bitmap,cliprect,l0,0); + if (l1 == 0) cps1_render_high_layer(bitmap,cliprect,l0); /* prepare mask for sprites */ + cps1_render_layer(machine,bitmap,cliprect,l1,0); + if (l2 == 0) cps1_render_high_layer(bitmap,cliprect,l1); /* prepare mask for sprites */ + cps1_render_layer(machine,bitmap,cliprect,l2,0); + if (l3 == 0) cps1_render_high_layer(bitmap,cliprect,l2); /* prepare mask for sprites */ + cps1_render_layer(machine,bitmap,cliprect,l3,0); + } + else + { + int l0pri,l1pri,l2pri,l3pri; + int primasks[8],i; + l0pri = (pri_ctrl >> 4*l0) & 0x0f; + l1pri = (pri_ctrl >> 4*l1) & 0x0f; + l2pri = (pri_ctrl >> 4*l2) & 0x0f; + l3pri = (pri_ctrl >> 4*l3) & 0x0f; + +#if 0 +if ( (cps2_port(CPS2_OBJ_BASE) != 0x7080 && cps2_port(CPS2_OBJ_BASE) != 0x7000) || + cps2_port(CPS2_OBJ_UK1) != 0x807d || + (cps2_port(CPS2_OBJ_UK2) != 0x0000 && cps2_port(CPS2_OBJ_UK2) != 0x1101 && cps2_port(CPS2_OBJ_UK2) != 0x0001) || + popmessage("base %04x uk1 %04x uk2 %04x", + cps2_port(CPS2_OBJ_BASE), + cps2_port(CPS2_OBJ_UK1), + cps2_port(CPS2_OBJ_UK2)); + +if (0 && input_code_pressed(KEYCODE_Z)) + popmessage("order: %d (%d) %d (%d) %d (%d) %d (%d)",l0,l0pri,l1,l1pri,l2,l2pri,l3,l3pri); +#endif + + /* take out the CPS1 sprites layer */ + if (l0 == 0) { l0 = l1; l1 = 0; l0pri = l1pri; } + if (l1 == 0) { l1 = l2; l2 = 0; l1pri = l2pri; } + if (l2 == 0) { l2 = l3; l3 = 0; l2pri = l3pri; } + + { + int mask0 = 0xaa; + int mask1 = 0xcc; + if(l0pri>l1pri) mask0 &= ~0x88; + if(l0pri>l2pri) mask0 &= ~0xa0; + if(l1pri>l2pri) mask1 &= ~0xc0; + + primasks[0] = 0xff; + for (i = 1;i < 8;i++) + { + if (i <= l0pri && i <= l1pri && i <= l2pri) + { + primasks[i] = 0xfe; + continue; + } + primasks[i] = 0; + if (i <= l0pri) primasks[i] |= mask0; + if (i <= l1pri) primasks[i] |= mask1; + if (i <= l2pri) primasks[i] |= 0xf0; + } + } + + cps1_render_layer(machine,bitmap,cliprect,l0,1); + cps1_render_layer(machine,bitmap,cliprect,l1,2); + cps1_render_layer(machine,bitmap,cliprect,l2,4); + cps2_render_sprites(machine,bitmap,cliprect,primasks); + } + +#if CPS1_DUMP_VIDEO + if (input_code_pressed(KEYCODE_F)) + { + cps1_dump_video(); + } +#endif + return 0; +} + +VIDEO_EOF( cps1 ) +{ + /* Get video memory base registers */ + cps1_get_video_base(); + + if (cps_version == 1) + { + /* CPS1 sprites have to be delayed one frame */ + memcpy(cps1_buffered_obj, cps1_obj, cps1_obj_size); + } +} + +void cps2_set_sprite_priorities(void) +{ + pri_ctrl = cps2_port(CPS2_OBJ_PRI); +} + +void cps2_objram_latch(void) +{ + cps2_set_sprite_priorities(); + memcpy(cps2_buffered_obj, cps2_objbase(), cps2_obj_size); +} + |