📄 cps1.c
字号:
/***************************************************************************
vidhrdw.c
Functions to emulate the video hardware of the machine.
Todo:
7 unknown attribute bits on scroll 2/3.
Speed, speed, speed...
OUTPUT PORTS (preliminary)
0x00-0x01 OBJ RAM base (/256)
0x02-0x03 Scroll1 RAM base (/256)
0x04-0x05 Scroll2 RAM base (/256)
0x06-0x07 Scroll3 RAM base (/256)
0x08-0x09 "Other" RAM - Scroll distortion (/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 ????
0x20-0x21 ????
0x22-0x23 unknown but widely used - usually 0x0e
0x24-0x25 ????
0x4e-0x4f ????
0x5e-0x5f ????
Registers move from game to game.. following example strider
0x66-0x67 Video control register (location varies according to game)
0x6a-0x6b Priority mask
0x6c-0x6d Priority mask
0x6e-0x6f Priority mask
0x70-0x71 Control register (usually 0x003f)
Fixed registers
0x80-0x81 ???? Sound output.
0x88-0x89 ???? Port thingy (sound fade???)
Known Bug List
==============
All games
* Palette fades overflow palette.
* Large sprites don't exit smoothly on the left side of the screen (e.g. Car
in Mega Man attract mode)
Magic Sword.
* Distortion effect is mapped wrong.
* Rogue scroll 2 character at end of level 1
* 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.
* Distortion effect missing on player selection screen.
1941
* Brief flicker of scroll 2 when coining up / starting game.
Captain Commando
* Continue screen completely wrong
SF2
* Sprite lag on screens.
* Japanese level still doesn't look 100%
ffight
* end of level 1 stairs: can see the player feet through them, and
if you don't destroy the bin it gets covered by the ones behind it.
* continue screen has garbage character tiled in the background
mtwins
* in the cave (with fire) and underwater, rowscroll is used. This
doesn't seem to have any visible effect, but I think it is supposed
to wave, to suggest hot air and water.
* attract mode screens have garbage character tiled in the background
cawing
* priority: at end of level, the plane is drawn above the text
* in level 2, you have to blow out tunnels in skyscrapers to
fly thru. However, you can see the tunnel before you actually make it.
Doesn't seem to be a priority problem, the gfx are just missing.
* garbage characters inbetween text in attract mode
knights
* garbage characters left on screen during boot and under INSERT COIN.
qad
* in attract mode, "Dragons" is missing from the title screen, only
"Quiz &" is visible.
mercs
* a few wrong scroll 2 tiles (check part 2 of the first attract mode round)
Todo
====
Implement CPS2 QSound system
Unknown issues
==============
There are often some redundant high bits in the scroll layer's attributes.
***************************************************************************/
#include "driver.h"
#include "vidhrdw/generic.h"
#include "drivers/cps1.h"
#include "types.h"
#include "osdepend.h"
#define VERBOSE 1
struct CPS1VIDCFG
{
int layer_control;
int priority0; /* usually 0x00 */
int priority1;
int priority2;
int priority3;
int control_reg; /* Control register? Usually contains 0x3f */
int scrl1_enable_mask;
int scrl2_enable_mask;
int scrl3_enable_mask;
int distort_alt;
};
/* Configuration tables */
/* ideally, the layer enable masks should consist of only one bit, */
/* but in many cases it is unknown which bit is which. */
static struct CPS1VIDCFG cps1_vid_cfg[]=
{
{0x66,0x68,0x6a,0x6c,0x6e,0x70, 0x38,0x38,0x38,0}, /* 00 = Un Squadron */
{0x70,0x6e,0x6c,0x6a,0x68,0x66, 0x20,0x10,0x08,0}, /* 01 = Willow */
{0x6e,0x66,0x70,0x68,0x72,0x6a, 0x02,0x0c,0x0c,1}, /* 02 = Final Fight */
{0x66,0x68,0x6a,0x6c,0x6e,0x70, 0x02,0x0c,0x0c,1}, /* 03 = ffightu */
{0x66,0x68,0x6a,0x6c,0x6e,0x70, 0x02,0x0c,0x0c,0}, /* 04 = Strider */
{0x66,0x68,0x6a,0x6c,0x6e,0x70, 0x02,0x04,0x08,0}, /* 05 = Ghouls */
{0x68,0x66,0x64,0x62,0x60,0x70, 0x20,0x10,0x02,0}, /* 06 = Knights */
{0x62,0x64,0x66,0x68,0x6a,0x6c, 0x20,0x06,0x06,2}, /* 07 = Magic Sword */
{0x42,0x44,0x46,0x48,0x4a,0x4c, 0x04,0x22,0x22,0}, /* 08 = Nemo */
{0x6c,0x6a,0x68,0x66,0x64,0x62, 0x02,0x04,0x08,0}, /* 09 = DWJ */
{0x60,0x6e,0x6c,0x6a,0x68,0x70, 0x30,0x08,0x30,0}, /* 10 = KOD */
{0x4c,0x4a,0x48,0x46,0x44,0x42, 0x10,0x0a,0x0a,0}, /* 11 = Carrier Air Wing */
{0x54,0x52,0x50,0x4e,0x4c,0x4a, 0x08,0x12,0x12,3}, /* 12 = Street Fighter 2 */
{0x62,0x64,0x66,0x68,0x6a,0x6c, 0x20,0x06,0x06,3}, /* 13 = sf2j */
{0x66,0x68,0x6a,0x6c,0x6e,0x70, 0x02,0x0c,0x0c,3}, /* 14 = Street Fighter 2 (Turbo) */
{0xdc,0xda,0xd8,0xd6,0xd4,0xd2, 0x10,0x0a,0x0a,3}, /* 15 = SF2 (Rev E) */
{0x68,0x66,0x64,0x62,0x60,0x70, 0x20,0x04,0x08,2}, /* 16 = 3 Wonders */
{0x6e,0x66,0x70,0x68,0x72,0x6a, 0x02,0x0c,0x0c,1}, /* 17 = Varth */
{0x60,0x6e,0x6c,0x6a,0x68,0x70, 0x20,0x06,0x06,1}, /* 18 = varthj */
{0x68,0x6a,0x6c,0x6e,0x70,0x72, 0x02,0x08,0x20,0}, /* 19 = 1941 */
{0x66,0x68,0x6a,0x6c,0x6e,0x70, 0x02,0x0c,0x0c,0}, /* 20 = Megaman */
{0x52,0x54,0x56,0x58,0x5a,0x5c, 0x38,0x38,0x38,1}, /* 21 = Mega Twins */
{0x6c,0x00,0x00,0x00,0x00,0x62, 0x02,0x04,0x08,0}, /* 22 = Mercs (uses port 74) */
{0x6c,0x00,0x00,0x00,0x00,0x52, 0x16,0x16,0x16,0}, /* 23 = Quiz and Dragons */
{0x60,0x00,0x00,0x00,0x00,0x70, 0x20,0x14,0x14,0}, /* 24 = cworld2j */
{0x66,0x00,0x00,0x00,0x00,0x70, 0x0e,0x0e,0x0e,0}, /* 25 = Pnickies */
{0x66,0x68,0x6a,0x6c,0x6e,0x70, 0x0e,0x0e,0x0e,0}, /* 26 = qadj */
{0x4a,0x4c,0x4e,0x40,0x42,0x44, 0x16,0x16,0x16,0}, /* 27 = Cadillacs & Dinosaurs */
{0x52,0x54,0x56,0x48,0x4a,0x4c, 0x04,0x02,0x20,0}, /* 28 = Punisher */
{0x60,0x6e,0x6c,0x6a,0x68,0x70, 0x20,0x12,0x12,0}, /* 29 = Captain Commando */
{0x66,0x68,0x6a,0x6c,0x6e,0x70, 0x02,0x04,0x08,0}, /* 30 = wof */
{0x56,0x40,0x42,0x68,0x6a,0x6c, 0x1c,0x1c,0x1c,0}, /* 31 = Slam Masters */
{0x6a,0x6c,0x6e,0x70,0x72,0x5c, 0x1c,0x1c,0x1c,0}, /* 32 = Muscle Bomber Duo */
{0x62,0x64,0x66,0x68,0x6a,0x6c, 0x10,0x08,0x04,0}, /* 33 = wofj */
};
INLINE int cps1_port(int offset)
{
return READ_WORD(&cps1_output[offset]);
}
INLINE unsigned char * cps1_base(int offset)
{
int base=cps1_port(offset)*256;
return &cps1_gfxram[base&0x3ffff];
}
int cps1_output_r(int offset)
{
return READ_WORD(&cps1_output[offset]);
}
void cps1_output_w(int offset, int data)
{
int value;
COMBINE_WORD_MEM(&cps1_output[offset],data);
/* protections */
switch (offset)
{
case 0x40:
case 0x42:
if (cps1_game_config->alternative==14 )
{
/* Only apply protection to sf2t (other games use 0x40-0x47)*/
value=cps1_port(0x40);
value*=cps1_port(0x42);
/* Slight variation ... only one word result */
WRITE_WORD(&cps1_output[0x44], value&0xffff);
}
else if (cps1_game_config->alternative==11)
{
/* Carrier Air Wing... unknown protection */
WRITE_WORD(&cps1_output[0x40], 0x0406);
}
break;
case 0x44:
case 0x46:
if (cps1_game_config->alternative==6)
{
/* Only apply protection to knights (other games use 0x40-0x47)*/
value=cps1_port(0x44);
value*=cps1_port(0x46);
WRITE_WORD(&cps1_output[0x40], value>>16);
WRITE_WORD(&cps1_output[0x42], value&0xffff);
}
break;
case 0x4c:
case 0x4e:
if (cps1_game_config->alternative==16 /* 3wonders */
|| cps1_game_config->alternative==18) /* varthj */
{
/* Only apply protection to 3wonders (other games use 0x4c-0x4f)*/
value=cps1_port(0x4c);
value*=cps1_port(0x4e);
WRITE_WORD(&cps1_output[0x48], value>>16);
WRITE_WORD(&cps1_output[0x4a], value&0xffff);
}
break;
case 0x5c:
case 0x5e:
if (cps1_game_config->alternative==10)
{
/* Only apply protection to KOD (other games use 0x58-0x5b)*/
value=cps1_port(0x5c);
value*=cps1_port(0x5e);
WRITE_WORD(&cps1_output[0x58], value>>16);
WRITE_WORD(&cps1_output[0x5a], value&0xffff);
}
break;
}
}
/* Public variables */
unsigned char *cps1_gfxram;
unsigned char *cps1_output;
int cps1_gfxram_size;
int cps1_output_size;
/* Private */
/* Offset of each palette entry */
const int cps1_obj_palette =0;
const int cps1_scroll1_palette=32;
const int cps1_scroll2_palette=32+32;
const int cps1_scroll3_palette=32+32+32;
#define cps1_palette_entries (32*4) /* Number colour schemes in palette */
const int cps1_scroll1_size=0x4000;
const int cps1_scroll2_size=0x4000;
const int cps1_scroll3_size=0x4000;
const int cps1_obj_size =0x4000;
const int cps1_other_size =0x4000;
const int cps1_palette_size=cps1_palette_entries*32; /* Size of palette RAM */
static int cps1_flip_screen; /* Flip screen on / off */
static unsigned char *cps1_scroll1;
static unsigned char *cps1_scroll2;
static unsigned char *cps1_scroll3;
static unsigned char *cps1_obj;
static unsigned char *cps1_palette;
static unsigned char *cps1_other;
static unsigned char *cps1_old_palette;
/* Working variables */
static int cps1_last_sprite_offset; /* Offset of the last sprite */
static int cps1_layer_control; /* Layer control register */
static int cps1_layer_enabled[4]; /* Layer enabled [Y/N] */
int scroll1x, scroll1y, scroll2x, scroll2y, scroll3x, scroll3y;
struct CPS1config *cps1_game_config;
static unsigned char *cps1_scroll2_old;
static struct osd_bitmap *cps1_scroll2_bitmap;
/* 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_SCROLL2_WIDTH 0x40
#define CPS1_SCROLL2_HEIGHT 0x40
/*
CPS1 VIDEO RENDERER
*/
const int cps1_gfx_region=1; /* MAME memory region to draw from */
static dword *cps1_gfx; /* Converted GFX memory */
static int *cps1_char_pen_usage; /* pen usage array */
static int *cps1_tile16_pen_usage; /* pen usage array */
static int *cps1_tile32_pen_usage; /* pen usage array */
static int cps1_max_char; /* Maximum number of 8x8 chars */
static int cps1_max_tile16; /* Maximum number of 16x16 tiles */
static int cps1_max_tile32; /* Maximum number of 32x32 tiles */
int cps1_gfx_start(void)
{
dword dwval;
int size=Machine->memory_region_length[cps1_gfx_region];
unsigned char *data = Machine->memory_region[cps1_gfx_region];
int i,j,nchar,penusage,gfxsize;
gfxsize=size/4;
/* Set up maximum values */
cps1_max_char =(gfxsize/2)/8;
cps1_max_tile16=(gfxsize/4)/8;
cps1_max_tile32=(gfxsize/16)/8;
cps1_gfx=malloc(gfxsize*sizeof(dword));
if (!cps1_gfx)
{
return -1;
}
cps1_char_pen_usage=malloc(cps1_max_char*sizeof(int));
if (!cps1_char_pen_usage)
{
return -1;
}
memset(cps1_char_pen_usage, 0, cps1_max_char*sizeof(int));
cps1_tile16_pen_usage=malloc(cps1_max_tile16*sizeof(int));
if (!cps1_tile16_pen_usage)
return -1;
memset(cps1_tile16_pen_usage, 0, cps1_max_tile16*sizeof(int));
cps1_tile32_pen_usage=malloc(cps1_max_tile32*sizeof(int));
if (!cps1_tile32_pen_usage)
{
return -1;
}
memset(cps1_tile32_pen_usage, 0, cps1_max_tile32*sizeof(int));
#if 0
if (Machine->orientation & ORIENTATION_SWAP_XY)
{
unsigned char *p=data;
for (i=0; i<gfxsize/2; i++)
{
int x;
nchar=i/8; /* 8x8 char number */
dwval=0;
for (x=0; x<8; x++)
{
int y=i%8;
int n,mask;
n=0;
mask=0x80>>y;
p=data+nchar*16+x*2;
if (*(p+size/4)&mask) n|=1;
if (*(p+size/4+1)&mask) n|=2;
if (*(p+size/2+size/4)&mask) n|=4;
if (*(p+size/2+size/4+1)&mask) n|=8;
dwval|=n<<(28-x*4);
penusage=1<<n;
cps1_char_pen_usage[nchar]|=penusage;
cps1_tile16_pen_usage[nchar/2]|=penusage;
cps1_tile32_pen_usage[nchar/8]|=penusage;
}
cps1_gfx[2*i]=dwval;
dwval=0;
for (x=0; x<8; x++)
{
int y=i%8;
int n,mask;
n=0;
mask=0x80>>y;
p=data+nchar*16+x*2;
if (*(p)&mask) n|=1;
if (*(p+1)&mask) n|=2;
if (*(p+size/2)&mask) n|=4;
if (*(p+size/2+1)&mask) n|=8;
dwval|=n<<(28-x*4);
penusage=1<<n;
cps1_char_pen_usage[nchar]|=penusage;
cps1_tile16_pen_usage[nchar/2]|=penusage;
cps1_tile32_pen_usage[nchar/8]|=penusage;
}
cps1_gfx[2*i+1]=dwval;
}
}
else
#endif
{
for (i=0; i<gfxsize/2; i++)
{
nchar=i/8; /* 8x8 char number */
dwval=0;
for (j=0; j<8; j++)
{
int n,mask;
n=0;
mask=0x80>>j;
if (*(data+size/4)&mask) n|=1;
if (*(data+size/4+1)&mask) n|=2;
if (*(data+size/2+size/4)&mask) n|=4;
if (*(data+size/2+size/4+1)&mask) n|=8;
dwval|=n<<(28-j*4);
penusage=1<<n;
cps1_char_pen_usage[nchar]|=penusage;
cps1_tile16_pen_usage[nchar/2]|=penusage;
cps1_tile32_pen_usage[nchar/8]|=penusage;
}
cps1_gfx[2*i]=dwval;
dwval=0;
for (j=0; j<8; j++)
{
int n,mask;
n=0;
mask=0x80>>j;
if (*(data)&mask) n|=1;
if (*(data+1)&mask) n|=2;
if (*(data+size/2)&mask) n|=4;
if (*(data+size/2+1)&mask) n|=8;
dwval|=n<<(28-j*4);
penusage=1<<n;
cps1_char_pen_usage[nchar]|=penusage;
cps1_tile16_pen_usage[nchar/2]|=penusage;
cps1_tile32_pen_usage[nchar/8]|=penusage;
}
cps1_gfx[2*i+1]=dwval;
data+=2;
}
}
return 0;
}
void cps1_gfx_stop(void)
{
if (cps1_gfx)
{
free(cps1_gfx);
}
if (cps1_char_pen_usage)
{
free(cps1_char_pen_usage);
}
if (cps1_tile16_pen_usage)
{
free(cps1_tile16_pen_usage);
}
if (cps1_tile32_pen_usage)
{
free(cps1_tile32_pen_usage);
}
}
INLINE void cps1_draw_gfx(
struct osd_bitmap *dest,
const struct GfxElement *gfx,
unsigned int code,
int color,
int flipx,
int flipy,
int sx,
int sy,
int tpens,
int *pusage,
int size,
int max,
int delta,
int srcdelta)
{
int i, j, ex, ey;
dword dwval,n;
dword *src;
const unsigned short *paldata;
tpens=(~tpens) & 0xffff;
if ( code > max || !(tpens & pusage[code]))
{
/* No pens to draw (object is empty) */
return;
}
if (Machine->orientation & ORIENTATION_SWAP_XY)
{
int temp;
temp=sx;
sx=sy;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -