| 1 |
#include "driver.h" |
| 2 |
#include <ctype.h> |
| 3 |
#include <stdarg.h> |
| 4 |
#include "ui_text.h" /* LBO 042400 */ |
| 5 |
#include "mamedbg.h" |
| 6 |
#include "artwork.h" |
| 7 |
#include "state.h" |
| 8 |
#include "vidhrdw/generic.h" |
| 9 |
#include "palette.h" |
| 10 |
#include "harddisk.h" |
| 11 |
#ifdef MAME32JP |
| 12 |
#include "tilemap.h" |
| 13 |
#if !defined(CPSMAME) && !defined(NEOMAME) && !defined(TINY_COMPILE) |
| 14 |
#include "patch/neopatch.h" |
| 15 |
#define WIN32_LEAN_AND_MEAN |
| 16 |
#include <windows.h> |
| 17 |
BOOL Use60HzVsync(void); |
| 18 |
#endif |
| 19 |
#endif |
| 20 |
|
| 21 |
#define TEST_CLIPPING 0 |
| 22 |
|
| 23 |
|
| 24 |
static struct RunningMachine active_machine; |
| 25 |
struct RunningMachine *Machine = &active_machine; |
| 26 |
static const struct GameDriver *gamedrv; |
| 27 |
static struct InternalMachineDriver internal_drv; |
| 28 |
static struct mame_bitmap *real_scrbitmap; |
| 29 |
|
| 30 |
/* Variables to hold the status of various game options */ |
| 31 |
struct GameOptions options; |
| 32 |
|
| 33 |
void *record; /* for -record */ |
| 34 |
void *playback; /* for -playback */ |
| 35 |
int mame_debug; /* !0 when -debug option is specified */ |
| 36 |
|
| 37 |
int bailing; /* set to 1 if the startup is aborted to prevent multiple error messages */ |
| 38 |
|
| 39 |
static int settingsloaded; |
| 40 |
|
| 41 |
#ifndef MAME32JP |
| 42 |
static int leds_status; |
| 43 |
#else |
| 44 |
int inp_use = 0; |
| 45 |
#endif |
| 46 |
static int bitmap_dirty; |
| 47 |
|
| 48 |
static int last_partial_scanline; |
| 49 |
int partial_update_count; |
| 50 |
|
| 51 |
|
| 52 |
|
| 53 |
static void *mame_hard_disk_open(const char *filename, const char *mode); |
| 54 |
static void mame_hard_disk_close(void *file); |
| 55 |
static UINT32 mame_hard_disk_read(void *file, UINT64 offset, UINT32 count, void *buffer); |
| 56 |
static UINT32 mame_hard_disk_write(void *file, UINT64 offset, UINT32 count, const void *buffer); |
| 57 |
|
| 58 |
static struct hard_disk_interface mame_hard_disk_interface = |
| 59 |
{ |
| 60 |
mame_hard_disk_open, |
| 61 |
mame_hard_disk_close, |
| 62 |
mame_hard_disk_read, |
| 63 |
mame_hard_disk_write |
| 64 |
}; |
| 65 |
|
| 66 |
|
| 67 |
|
| 68 |
int init_machine(void); |
| 69 |
void shutdown_machine(void); |
| 70 |
int run_machine(void); |
| 71 |
|
| 72 |
|
| 73 |
#ifdef MAME_DEBUG |
| 74 |
|
| 75 |
INLINE int my_stricmp( const char *dst, const char *src) |
| 76 |
{ |
| 77 |
while (*src && *dst) |
| 78 |
{ |
| 79 |
if( tolower(*src) != tolower(*dst) ) return *dst - *src; |
| 80 |
src++; |
| 81 |
dst++; |
| 82 |
} |
| 83 |
return *dst - *src; |
| 84 |
} |
| 85 |
|
| 86 |
static int validitychecks(void) |
| 87 |
{ |
| 88 |
int i,j,cpu; |
| 89 |
UINT8 a,b; |
| 90 |
int error = 0; |
| 91 |
|
| 92 |
|
| 93 |
a = 0xff; |
| 94 |
b = a + 1; |
| 95 |
if (b > a) { printf("UINT8 must be 8 bits\n"); error = 1; } |
| 96 |
|
| 97 |
if (sizeof(INT8) != 1) { printf("INT8 must be 8 bits\n"); error = 1; } |
| 98 |
if (sizeof(UINT8) != 1) { printf("UINT8 must be 8 bits\n"); error = 1; } |
| 99 |
if (sizeof(INT16) != 2) { printf("INT16 must be 16 bits\n"); error = 1; } |
| 100 |
if (sizeof(UINT16) != 2) { printf("UINT16 must be 16 bits\n"); error = 1; } |
| 101 |
if (sizeof(INT32) != 4) { printf("INT32 must be 32 bits\n"); error = 1; } |
| 102 |
if (sizeof(UINT32) != 4) { printf("UINT32 must be 32 bits\n"); error = 1; } |
| 103 |
if (sizeof(INT64) != 8) { printf("INT64 must be 64 bits\n"); error = 1; } |
| 104 |
if (sizeof(UINT64) != 8) { printf("UINT64 must be 64 bits\n"); error = 1; } |
| 105 |
|
| 106 |
for (i = 0;drivers[i];i++) |
| 107 |
{ |
| 108 |
struct InternalMachineDriver drv; |
| 109 |
const struct RomModule *romp; |
| 110 |
const struct InputPortTiny *inp; |
| 111 |
|
| 112 |
expand_machine_driver(drivers[i]->drv, &drv); |
| 113 |
|
| 114 |
if (drivers[i]->clone_of == drivers[i]) |
| 115 |
{ |
| 116 |
printf("%s: %s is set as a clone of itself\n",drivers[i]->source_file,drivers[i]->name); |
| 117 |
error = 1; |
| 118 |
} |
| 119 |
|
| 120 |
if (drivers[i]->clone_of && drivers[i]->clone_of->clone_of) |
| 121 |
{ |
| 122 |
if ((drivers[i]->clone_of->clone_of->flags & NOT_A_DRIVER) == 0) |
| 123 |
{ |
| 124 |
printf("%s: %s is a clone of a clone\n",drivers[i]->source_file,drivers[i]->name); |
| 125 |
error = 1; |
| 126 |
} |
| 127 |
} |
| 128 |
|
| 129 |
#if 0 |
| 130 |
// if (drivers[i]->drv->color_table_len == drivers[i]->drv->total_colors && |
| 131 |
if (drivers[i]->drv->color_table_len && drivers[i]->drv->total_colors && |
| 132 |
drivers[i]->drv->vh_init_palette == 0) |
| 133 |
{ |
| 134 |
printf("%s: %s could use color_table_len = 0\n",drivers[i]->source_file,drivers[i]->name); |
| 135 |
error = 1; |
| 136 |
} |
| 137 |
#endif |
| 138 |
|
| 139 |
for (j = i+1;drivers[j];j++) |
| 140 |
{ |
| 141 |
if (!strcmp(drivers[i]->name,drivers[j]->name)) |
| 142 |
{ |
| 143 |
printf("%s: %s is a duplicate name (%s, %s)\n",drivers[i]->source_file,drivers[i]->name,drivers[i]->source_file,drivers[j]->source_file); |
| 144 |
error = 1; |
| 145 |
} |
| 146 |
if (!strcmp(drivers[i]->description,drivers[j]->description)) |
| 147 |
{ |
| 148 |
printf("%s: %s is a duplicate description (%s, %s)\n",drivers[i]->description,drivers[i]->source_file,drivers[i]->name,drivers[j]->name); |
| 149 |
error = 1; |
| 150 |
} |
| 151 |
if (drivers[i]->rom && drivers[i]->rom == drivers[j]->rom |
| 152 |
&& (drivers[i]->flags & NOT_A_DRIVER) == 0 |
| 153 |
&& (drivers[j]->flags & NOT_A_DRIVER) == 0) |
| 154 |
{ |
| 155 |
printf("%s: %s and %s use the same ROM set\n",drivers[i]->source_file,drivers[i]->name,drivers[j]->name); |
| 156 |
error = 1; |
| 157 |
} |
| 158 |
} |
| 159 |
|
| 160 |
romp = drivers[i]->rom; |
| 161 |
|
| 162 |
if (romp) |
| 163 |
{ |
| 164 |
int region_type_used[REGION_MAX]; |
| 165 |
int region_length[REGION_MAX]; |
| 166 |
const char *last_name = 0; |
| 167 |
int count = -1; |
| 168 |
|
| 169 |
for (j = 0;j < REGION_MAX;j++) |
| 170 |
{ |
| 171 |
region_type_used[j] = 0; |
| 172 |
region_length[j] = 0; |
| 173 |
} |
| 174 |
|
| 175 |
while (!ROMENTRY_ISEND(romp)) |
| 176 |
{ |
| 177 |
const char *c; |
| 178 |
|
| 179 |
if (ROMENTRY_ISREGION(romp)) |
| 180 |
{ |
| 181 |
int type = ROMREGION_GETTYPE(romp); |
| 182 |
|
| 183 |
count++; |
| 184 |
if (type && (type >= REGION_MAX || type <= REGION_INVALID)) |
| 185 |
{ |
| 186 |
printf("%s: %s has invalid ROM_REGION type %x\n",drivers[i]->source_file,drivers[i]->name,type); |
| 187 |
error = 1; |
| 188 |
} |
| 189 |
|
| 190 |
region_type_used[type]++; |
| 191 |
region_length[type] = region_length[count] = ROMREGION_GETLENGTH(romp); |
| 192 |
} |
| 193 |
if (ROMENTRY_ISFILE(romp)) |
| 194 |
{ |
| 195 |
int pre,post; |
| 196 |
|
| 197 |
last_name = c = ROM_GETNAME(romp); |
| 198 |
while (*c) |
| 199 |
{ |
| 200 |
if (tolower(*c) != *c) |
| 201 |
{ |
| 202 |
printf("%s: %s has upper case ROM name %s\n",drivers[i]->source_file,drivers[i]->name,ROM_GETNAME(romp)); |
| 203 |
error = 1; |
| 204 |
} |
| 205 |
c++; |
| 206 |
} |
| 207 |
|
| 208 |
c = ROM_GETNAME(romp); |
| 209 |
pre = 0; |
| 210 |
post = 0; |
| 211 |
while (*c && *c != '.') |
| 212 |
{ |
| 213 |
pre++; |
| 214 |
c++; |
| 215 |
} |
| 216 |
while (*c) |
| 217 |
{ |
| 218 |
post++; |
| 219 |
c++; |
| 220 |
} |
| 221 |
if (pre > 8 || post > 4) |
| 222 |
{ |
| 223 |
printf("%s: %s has >8.3 ROM name %s\n",drivers[i]->source_file,drivers[i]->name,ROM_GETNAME(romp)); |
| 224 |
error = 1; |
| 225 |
} |
| 226 |
} |
| 227 |
if (!ROMENTRY_ISREGIONEND(romp)) /* ROM_LOAD_XXX() */ |
| 228 |
{ |
| 229 |
if (ROM_GETOFFSET(romp) + ROM_GETLENGTH(romp) > region_length[count]) |
| 230 |
{ |
| 231 |
printf("%s: %s has ROM %s extending past the defined memory region\n",drivers[i]->source_file,drivers[i]->name,last_name); |
| 232 |
error = 1; |
| 233 |
} |
| 234 |
} |
| 235 |
romp++; |
| 236 |
} |
| 237 |
|
| 238 |
for (j = 1;j < REGION_MAX;j++) |
| 239 |
{ |
| 240 |
if (region_type_used[j] > 1) |
| 241 |
{ |
| 242 |
printf("%s: %s has duplicated ROM_REGION type %x\n",drivers[i]->source_file,drivers[i]->name,j); |
| 243 |
error = 1; |
| 244 |
} |
| 245 |
} |
| 246 |
|
| 247 |
|
| 248 |
for (cpu = 0;cpu < MAX_CPU;cpu++) |
| 249 |
{ |
| 250 |
if (drv.cpu[cpu].cpu_type) |
| 251 |
{ |
| 252 |
int alignunit,databus_width; |
| 253 |
|
| 254 |
|
| 255 |
alignunit = cputype_align_unit(drv.cpu[cpu].cpu_type & ~CPU_FLAGS_MASK); |
| 256 |
databus_width = cputype_databus_width(drv.cpu[cpu].cpu_type & ~CPU_FLAGS_MASK); |
| 257 |
|
| 258 |
if (drv.cpu[cpu].memory_read) |
| 259 |
{ |
| 260 |
const struct Memory_ReadAddress *mra = drv.cpu[cpu].memory_read; |
| 261 |
|
| 262 |
if (!IS_MEMPORT_MARKER(mra) || (mra->end & MEMPORT_DIRECTION_MASK) != MEMPORT_DIRECTION_READ) |
| 263 |
{ |
| 264 |
printf("%s: %s wrong MEMPORT_READ_START\n",drivers[i]->source_file,drivers[i]->name); |
| 265 |
error = 1; |
| 266 |
} |
| 267 |
|
| 268 |
switch (databus_width) |
| 269 |
{ |
| 270 |
case 8: |
| 271 |
if ((mra->end & MEMPORT_WIDTH_MASK) != MEMPORT_WIDTH_8) |
| 272 |
{ |
| 273 |
printf("%s: %s cpu #%d uses wrong data width memory handlers! (width = %d, memory = %08x)\n",drivers[i]->source_file,drivers[i]->name,cpu,databus_width,mra->end); |
| 274 |
error = 1; |
| 275 |
} |
| 276 |
break; |
| 277 |
case 16: |
| 278 |
if ((mra->end & MEMPORT_WIDTH_MASK) != MEMPORT_WIDTH_16) |
| 279 |
{ |
| 280 |
printf("%s: %s cpu #%d uses wrong data width memory handlers! (width = %d, memory = %08x)\n",drivers[i]->source_file,drivers[i]->name,cpu,databus_width,mra->end); |
| 281 |
error = 1; |
| 282 |
} |
| 283 |
break; |
| 284 |
case 32: |
| 285 |
if ((mra->end & MEMPORT_WIDTH_MASK) != MEMPORT_WIDTH_32) |
| 286 |
{ |
| 287 |
printf("%s: %s cpu #%d uses wrong data width memory handlers! (width = %d, memory = %08x)\n",drivers[i]->source_file,drivers[i]->name,cpu,databus_width,mra->end); |
| 288 |
error = 1; |
| 289 |
} |
| 290 |
break; |
| 291 |
} |
| 292 |
|
| 293 |
while (!IS_MEMPORT_END(mra)) |
| 294 |
{ |
| 295 |
if (!IS_MEMPORT_MARKER(mra)) |
| 296 |
{ |
| 297 |
if (mra->end < mra->start) |
| 298 |
{ |
| 299 |
printf("%s: %s wrong memory read handler start = %08x > end = %08x\n",drivers[i]->source_file,drivers[i]->name,mra->start,mra->end); |
| 300 |
error = 1; |
| 301 |
} |
| 302 |
if ((mra->start & (alignunit-1)) != 0 || (mra->end & (alignunit-1)) != (alignunit-1)) |
| 303 |
{ |
| 304 |
printf("%s: %s wrong memory read handler start = %08x, end = %08x ALIGN = %d\n",drivers[i]->source_file,drivers[i]->name,mra->start,mra->end,alignunit); |
| 305 |
error = 1; |
| 306 |
} |
| 307 |
} |
| 308 |
mra++; |
| 309 |
} |
| 310 |
} |
| 311 |
if (drv.cpu[cpu].memory_write) |
| 312 |
{ |
| 313 |
const struct Memory_WriteAddress *mwa = drv.cpu[cpu].memory_write; |
| 314 |
|
| 315 |
if (mwa->start != MEMPORT_MARKER || |
| 316 |
(mwa->end & MEMPORT_DIRECTION_MASK) != MEMPORT_DIRECTION_WRITE) |
| 317 |
{ |
| 318 |
printf("%s: %s wrong MEMPORT_WRITE_START\n",drivers[i]->source_file,drivers[i]->name); |
| 319 |
error = 1; |
| 320 |
} |
| 321 |
|
| 322 |
switch (databus_width) |
| 323 |
{ |
| 324 |
case 8: |
| 325 |
if ((mwa->end & MEMPORT_WIDTH_MASK) != MEMPORT_WIDTH_8) |
| 326 |
{ |
| 327 |
printf("%s: %s cpu #%d uses wrong data width memory handlers! (width = %d, memory = %08x)\n",drivers[i]->source_file,drivers[i]->name,cpu,databus_width,mwa->end); |
| 328 |
error = 1; |
| 329 |
} |
| 330 |
break; |
| 331 |
case 16: |
| 332 |
if ((mwa->end & MEMPORT_WIDTH_MASK) != MEMPORT_WIDTH_16) |
| 333 |
{ |
| 334 |
printf("%s: %s cpu #%d uses wrong data width memory handlers! (width = %d, memory = %08x)\n",drivers[i]->source_file,drivers[i]->name,cpu,databus_width,mwa->end); |
| 335 |
error = 1; |
| 336 |
} |
| 337 |
break; |
| 338 |
case 32: |
| 339 |
if ((mwa->end & MEMPORT_WIDTH_MASK) != MEMPORT_WIDTH_32) |
| 340 |
{ |
| 341 |
printf("%s: %s cpu #%d uses wrong data width memory handlers! (width = %d, memory = %08x)\n",drivers[i]->source_file,drivers[i]->name,cpu,databus_width,mwa->end); |
| 342 |
error = 1; |
| 343 |
} |
| 344 |
break; |
| 345 |
} |
| 346 |
|
| 347 |
while (!IS_MEMPORT_END(mwa)) |
| 348 |
{ |
| 349 |
if (!IS_MEMPORT_MARKER(mwa)) |
| 350 |
{ |
| 351 |
if (mwa->end < mwa->start) |
| 352 |
{ |
| 353 |
printf("%s: %s wrong memory write handler start = %08x > end = %08x\n",drivers[i]->source_file,drivers[i]->name,mwa->start,mwa->end); |
| 354 |
error = 1; |
| 355 |
} |
| 356 |
if ((mwa->start & (alignunit-1)) != 0 || (mwa->end & (alignunit-1)) != (alignunit-1)) |
| 357 |
{ |
| 358 |
printf("%s: %s wrong memory write handler start = %08x, end = %08x ALIGN = %d\n",drivers[i]->source_file,drivers[i]->name,mwa->start,mwa->end,alignunit); |
| 359 |
error = 1; |
| 360 |
} |
| 361 |
} |
| 362 |
mwa++; |
| 363 |
} |
| 364 |
} |
| 365 |
} |
| 366 |
} |
| 367 |
|
| 368 |
|
| 369 |
if (drv.gfxdecodeinfo) |
| 370 |
{ |
| 371 |
for (j = 0;j < MAX_GFX_ELEMENTS && drv.gfxdecodeinfo[j].memory_region != -1;j++) |
| 372 |
{ |
| 373 |
int len,avail,k,start; |
| 374 |
int type = drv.gfxdecodeinfo[j].memory_region; |
| 375 |
|
| 376 |
|
| 377 |
/* |
| 378 |
if (type && (type >= REGION_MAX || type <= REGION_INVALID)) |
| 379 |
{ |
| 380 |
printf("%s: %s has invalid memory region for gfx[%d]\n",drivers[i]->source_file,drivers[i]->name,j); |
| 381 |
error = 1; |
| 382 |
} |
| 383 |
*/ |
| 384 |
|
| 385 |
if (!IS_FRAC(drv.gfxdecodeinfo[j].gfxlayout->total)) |
| 386 |
{ |
| 387 |
start = 0; |
| 388 |
for (k = 0;k < MAX_GFX_PLANES;k++) |
| 389 |
{ |
| 390 |
if (drv.gfxdecodeinfo[j].gfxlayout->planeoffset[k] > start) |
| 391 |
start = drv.gfxdecodeinfo[j].gfxlayout->planeoffset[k]; |
| 392 |
} |
| 393 |
start &= ~(drv.gfxdecodeinfo[j].gfxlayout->charincrement-1); |
| 394 |
len = drv.gfxdecodeinfo[j].gfxlayout->total * |
| 395 |
drv.gfxdecodeinfo[j].gfxlayout->charincrement; |
| 396 |
avail = region_length[type] |
| 397 |
- (drv.gfxdecodeinfo[j].start & ~(drv.gfxdecodeinfo[j].gfxlayout->charincrement/8-1)); |
| 398 |
if ((start + len) / 8 > avail) |
| 399 |
{ |
| 400 |
printf("%s: %s has gfx[%d] extending past allocated memory\n",drivers[i]->source_file,drivers[i]->name,j); |
| 401 |
error = 1; |
| 402 |
} |
| 403 |
} |
| 404 |
} |
| 405 |
} |
| 406 |
} |
| 407 |
|
| 408 |
|
| 409 |
inp = drivers[i]->input_ports; |
| 410 |
|
| 411 |
if (inp) |
| 412 |
{ |
| 413 |
while (inp->type != IPT_END) |
| 414 |
{ |
| 415 |
if (inp->name && inp->name != IP_NAME_DEFAULT) |
| 416 |
{ |
| 417 |
j = 0; |
| 418 |
|
| 419 |
for (j = 0;j < STR_TOTAL;j++) |
| 420 |
{ |
| 421 |
if (inp->name == ipdn_defaultstrings[j]) break; |
| 422 |
else if (!my_stricmp(inp->name,ipdn_defaultstrings[j])) |
| 423 |
{ |
| 424 |
printf("%s: %s must use DEF_STR( %s )\n",drivers[i]->source_file,drivers[i]->name,inp->name); |
| 425 |
error = 1; |
| 426 |
} |
| 427 |
} |
| 428 |
|
| 429 |
if (inp->name == DEF_STR( On ) && (inp+1)->name == DEF_STR( Off )) |
| 430 |
{ |
| 431 |
printf("%s: %s has inverted Off/On dipswitch order\n",drivers[i]->source_file,drivers[i]->name); |
| 432 |
error = 1; |
| 433 |
} |
| 434 |
|
| 435 |
if (inp->name == DEF_STR( Yes ) && (inp+1)->name == DEF_STR( No )) |
| 436 |
{ |
| 437 |
printf("%s: %s has inverted No/Yes dipswitch order\n",drivers[i]->source_file,drivers[i]->name); |
| 438 |
error = 1; |
| 439 |
} |
| 440 |
|
| 441 |
if (!my_stricmp(inp->name,"table")) |
| 442 |
{ |
| 443 |
printf("%s: %s must use DEF_STR( Cocktail ), not %s\n",drivers[i]->source_file,drivers[i]->name,inp->name); |
| 444 |
error = 1; |
| 445 |
} |
| 446 |
|
| 447 |
if (inp->name == DEF_STR( Cabinet ) && (inp+1)->name == DEF_STR( Upright ) |
| 448 |
&& inp->default_value != (inp+1)->default_value) |
| 449 |
{ |
| 450 |
printf("%s: %s Cabinet must default to Upright\n",drivers[i]->source_file,drivers[i]->name); |
| 451 |
error = 1; |
| 452 |
} |
| 453 |
|
| 454 |
if (inp->name == DEF_STR( Cocktail ) && (inp+1)->name == DEF_STR( Upright )) |
| 455 |
{ |
| 456 |
printf("%s: %s has inverted Upright/Cocktail dipswitch order\n",drivers[i]->source_file,drivers[i]->name); |
| 457 |
error = 1; |
| 458 |
} |
| 459 |
|
| 460 |
if (inp->name >= DEF_STR( 9C_1C ) && inp->name <= DEF_STR( Free_Play ) |
| 461 |
&& (inp+1)->name >= DEF_STR( 9C_1C ) && (inp+1)->name <= DEF_STR( Free_Play ) |
| 462 |
&& inp->name >= (inp+1)->name) |
| 463 |
{ |
| 464 |
printf("%s: %s has unsorted coinage %s > %s\n",drivers[i]->source_file,drivers[i]->name,inp->name,(inp+1)->name); |
| 465 |
error = 1; |
| 466 |
} |
| 467 |
|
| 468 |
if (inp->name == DEF_STR( Flip_Screen ) && (inp+1)->name != DEF_STR( Off )) |
| 469 |
{ |
| 470 |
printf("%s: %s has wrong Flip Screen option %s\n",drivers[i]->source_file,drivers[i]->name,(inp+1)->name); |
| 471 |
error = 1; |
| 472 |
} |
| 473 |
|
| 474 |
if (inp->name == DEF_STR( Demo_Sounds ) && (inp+2)->name == DEF_STR( On ) |
| 475 |
&& inp->default_value != (inp+2)->default_value) |
| 476 |
{ |
| 477 |
printf("%s: %s Demo Sounds must default to On\n",drivers[i]->source_file,drivers[i]->name); |
| 478 |
error = 1; |
| 479 |
} |
| 480 |
|
| 481 |
} |
| 482 |
|
| 483 |
inp++; |
| 484 |
} |
| 485 |
} |
| 486 |
} |
| 487 |
|
| 488 |
return error; |
| 489 |
} |
| 490 |
#endif |
| 491 |
|
| 492 |
|
| 493 |
|
| 494 |
|
| 495 |
int run_game(int game) |
| 496 |
{ |
| 497 |
int err; |
| 498 |
|
| 499 |
begin_resource_tracking(); |
| 500 |
|
| 501 |
#ifdef MAME_DEBUG |
| 502 |
/* validity checks */ |
| 503 |
if (validitychecks()) return 1; |
| 504 |
#endif |
| 505 |
|
| 506 |
#ifdef MAME32JP |
| 507 |
set_tilefunc(); |
| 508 |
{ |
| 509 |
extern int resampling; |
| 510 |
resampling = 0; |
| 511 |
} |
| 512 |
#endif |
| 513 |
|
| 514 |
/* copy some settings into easier-to-handle variables */ |
| 515 |
record = options.record; |
| 516 |
playback = options.playback; |
| 517 |
mame_debug = options.mame_debug; |
| 518 |
|
| 519 |
Machine->gamedrv = gamedrv = drivers[game]; |
| 520 |
expand_machine_driver(gamedrv->drv, &internal_drv); |
| 521 |
Machine->drv = &internal_drv; |
| 522 |
|
| 523 |
/* copy configuration */ |
| 524 |
if (Machine->drv->video_attributes & VIDEO_RGB_DIRECT) |
| 525 |
{ |
| 526 |
if (Machine->drv->video_attributes & VIDEO_NEEDS_6BITS_PER_GUN) |
| 527 |
Machine->color_depth = 32; |
| 528 |
else |
| 529 |
Machine->color_depth = 15; |
| 530 |
} |
| 531 |
else |
| 532 |
Machine->color_depth = 16; |
| 533 |
|
| 534 |
switch (options.color_depth) |
| 535 |
{ |
| 536 |
case 16: |
| 537 |
/* comply to -depth 16 only if we don't need a direct RGB mode */ |
| 538 |
if (!(Machine->drv->video_attributes & VIDEO_RGB_DIRECT)) |
| 539 |
Machine->color_depth = options.color_depth; |
| 540 |
break; |
| 541 |
|
| 542 |
case 15: |
| 543 |
case 32: |
| 544 |
/* comply to -depth 15/32 only if we need a direct RGB mode */ |
| 545 |
if (Machine->drv->video_attributes & VIDEO_RGB_DIRECT) |
| 546 |
Machine->color_depth = options.color_depth; |
| 547 |
break; |
| 548 |
} |
| 549 |
|
| 550 |
|
| 551 |
if (Machine->color_depth == 15 || Machine->color_depth == 32) |
| 552 |
{ |
| 553 |
if (!(Machine->drv->video_attributes & VIDEO_RGB_DIRECT)) |
| 554 |
Machine->color_depth = 16; |
| 555 |
else |
| 556 |
{ |
| 557 |
alpha_active = 1; |
| 558 |
alpha_init(); |
| 559 |
} |
| 560 |
} |
| 561 |
else |
| 562 |
alpha_active = 0; |
| 563 |
|
| 564 |
if (options.vector_width == 0) options.vector_width = 640; |
| 565 |
if (options.vector_height == 0) options.vector_height = 480; |
| 566 |
|
| 567 |
Machine->sample_rate = options.samplerate; |
| 568 |
|
| 569 |
/* get orientation right */ |
| 570 |
Machine->orientation = gamedrv->flags & ORIENTATION_MASK; |
| 571 |
Machine->ui_orientation = ROT0; |
| 572 |
if (options.norotate) |
| 573 |
Machine->orientation = ROT0; |
| 574 |
if (options.ror) |
| 575 |
{ |
| 576 |
/* if only one of the components is inverted, switch them */ |
| 577 |
if ((Machine->orientation & ROT180) == ORIENTATION_FLIP_X || |
| 578 |
(Machine->orientation & ROT180) == ORIENTATION_FLIP_Y) |
| 579 |
Machine->orientation ^= ROT180; |
| 580 |
|
| 581 |
Machine->orientation ^= ROT90; |
| 582 |
|
| 583 |
/* if only one of the components is inverted, switch them */ |
| 584 |
if ((Machine->ui_orientation & ROT180) == ORIENTATION_FLIP_X || |
| 585 |
(Machine->ui_orientation & ROT180) == ORIENTATION_FLIP_Y) |
| 586 |
Machine->ui_orientation ^= ROT180; |
| 587 |
|
| 588 |
Machine->ui_orientation ^= ROT90; |
| 589 |
} |
| 590 |
if (options.rol) |
| 591 |
{ |
| 592 |
/* if only one of the components is inverted, switch them */ |
| 593 |
if ((Machine->orientation & ROT180) == ORIENTATION_FLIP_X || |
| 594 |
(Machine->orientation & ROT180) == ORIENTATION_FLIP_Y) |
| 595 |
Machine->orientation ^= ROT180; |
| 596 |
|
| 597 |
Machine->orientation ^= ROT270; |
| 598 |
|
| 599 |
/* if only one of the components is inverted, switch them */ |
| 600 |
if ((Machine->ui_orientation & ROT180) == ORIENTATION_FLIP_X || |
| 601 |
(Machine->ui_orientation & ROT180) == ORIENTATION_FLIP_Y) |
| 602 |
Machine->ui_orientation ^= ROT180; |
| 603 |
|
| 604 |
Machine->ui_orientation ^= ROT270; |
| 605 |
} |
| 606 |
if (options.flipx) |
| 607 |
{ |
| 608 |
Machine->orientation ^= ORIENTATION_FLIP_X; |
| 609 |
Machine->ui_orientation ^= ORIENTATION_FLIP_X; |
| 610 |
} |
| 611 |
if (options.flipy) |
| 612 |
{ |
| 613 |
Machine->orientation ^= ORIENTATION_FLIP_Y; |
| 614 |
Machine->ui_orientation ^= ORIENTATION_FLIP_Y; |
| 615 |
} |
| 616 |
|
| 617 |
/* Do the work*/ |
| 618 |
err = 1; |
| 619 |
bailing = 0; |
| 620 |
|
| 621 |
#ifdef MESS |
| 622 |
if (get_filenames()) |
| 623 |
return err; |
| 624 |
#endif |
| 625 |
|
| 626 |
if (options.savegame) |
| 627 |
cpu_loadsave_schedule(LOADSAVE_LOAD, options.savegame); |
| 628 |
else |
| 629 |
cpu_loadsave_reset(); |
| 630 |
|
| 631 |
if (osd_init() == 0) |
| 632 |
{ |
| 633 |
begin_resource_tracking(); |
| 634 |
if (init_machine() == 0) |
| 635 |
{ |
| 636 |
if (run_machine() == 0) |
| 637 |
err = 0; |
| 638 |
else if (!bailing) |
| 639 |
{ |
| 640 |
bailing = 1; |
| 641 |
printf("Unable to start machine emulation\n"); |
| 642 |
} |
| 643 |
|
| 644 |
shutdown_machine(); |
| 645 |
} |
| 646 |
else if (!bailing) |
| 647 |
{ |
| 648 |
bailing = 1; |
| 649 |
printf("Unable to initialize machine emulation\n"); |
| 650 |
} |
| 651 |
|
| 652 |
end_resource_tracking(); |
| 653 |
osd_exit(); |
| 654 |
} |
| 655 |
else if (!bailing) |
| 656 |
{ |
| 657 |
bailing = 1; |
| 658 |
printf ("Unable to initialize system\n"); |
| 659 |
} |
| 660 |
|
| 661 |
end_resource_tracking(); |
| 662 |
return err; |
| 663 |
} |
| 664 |
|
| 665 |
|
| 666 |
|
| 667 |
/*************************************************************************** |
| 668 |
|
| 669 |
Initialize the emulated machine (load the roms, initialize the various |
| 670 |
subsystems...). Returns 0 if successful. |
| 671 |
|
| 672 |
***************************************************************************/ |
| 673 |
int init_machine(void) |
| 674 |
{ |
| 675 |
#ifndef JAPANESE |
| 676 |
/* LBO 042400 start */ |
| 677 |
if (uistring_init (options.language_file) != 0) |
| 678 |
{ |
| 679 |
logerror("uisting_init failed\n"); |
| 680 |
goto out; |
| 681 |
} |
| 682 |
/* LBO 042400 end */ |
| 683 |
#endif |
| 684 |
|
| 685 |
if (code_init() != 0) |
| 686 |
{ |
| 687 |
logerror("code_init failed\n"); |
| 688 |
goto out; |
| 689 |
} |
| 690 |
|
| 691 |
memset(&Machine->memory_region, 0, sizeof(Machine->memory_region)); |
| 692 |
|
| 693 |
if (gamedrv->input_ports) |
| 694 |
{ |
| 695 |
Machine->input_ports = input_port_allocate(gamedrv->input_ports); |
| 696 |
if (!Machine->input_ports) |
| 697 |
{ |
| 698 |
logerror("could not allocate Machine->input_ports\n"); |
| 699 |
goto out_code; |
| 700 |
} |
| 701 |
Machine->input_ports_default = input_port_allocate(gamedrv->input_ports); |
| 702 |
if (!Machine->input_ports_default) |
| 703 |
{ |
| 704 |
logerror("could not allocate Machine->input_ports_default\n"); |
| 705 |
input_port_free(Machine->input_ports); |
| 706 |
Machine->input_ports = 0; |
| 707 |
goto out_code; |
| 708 |
} |
| 709 |
} |
| 710 |
|
| 711 |
#ifdef MESS |
| 712 |
if (!gamedrv->rom) |
| 713 |
{ |
| 714 |
logerror("Going to load_next tag\n"); |
| 715 |
goto load_next; |
| 716 |
} |
| 717 |
#endif |
| 718 |
|
| 719 |
if (readroms() != 0) |
| 720 |
{ |
| 721 |
logerror("readroms failed\n"); |
| 722 |
goto out_free; |
| 723 |
} |
| 724 |
|
| 725 |
#ifdef MAME32JP |
| 726 |
#if !defined(CPSMAME) && !defined(NEOMAME) && !defined(TINY_COMPILE) |
| 727 |
if(!Use60HzVsync()) { |
| 728 |
if (strcmp(Machine->gamedrv->name, "kof99p") == 0) |
| 729 |
neogeo_kof99p_patch(); |
| 730 |
else if (strcmp(Machine->gamedrv->name, "garoup") == 0) |
| 731 |
neogeo_garoup_patch(); |
| 732 |
else if (strcmp(Machine->gamedrv->name, "fightfev") == 0) |
| 733 |
neogeo_fightfev_patch(); |
| 734 |
} |
| 735 |
#endif |
| 736 |
#endif |
| 737 |
|
| 738 |
#ifdef MESS |
| 739 |
load_next: |
| 740 |
if (init_devices(gamedrv)) |
| 741 |
{ |
| 742 |
logerror("init_devices failed\n"); |
| 743 |
goto out_free; |
| 744 |
} |
| 745 |
#endif |
| 746 |
|
| 747 |
/* Mish: Multi-session safety - set spriteram size to zero before memory map is set up */ |
| 748 |
spriteram_size=spriteram_2_size=0; |
| 749 |
|
| 750 |
/* first init the timers; some CPUs have built-in timers and will need */ |
| 751 |
/* to allocate them up front */ |
| 752 |
timer_init(); |
| 753 |
cpu_init_refresh_timer(); |
| 754 |
|
| 755 |
/* first of all initialize the memory handlers, which could be used by the */ |
| 756 |
/* other initialization routines */ |
| 757 |
cpu_init(); |
| 758 |
|
| 759 |
/* init the hard drives */ |
| 760 |
hard_disk_set_interface(&mame_hard_disk_interface); |
| 761 |
|
| 762 |
/* load input ports settings (keys, dip switches, and so on) */ |
| 763 |
settingsloaded = load_input_port_settings(); |
| 764 |
|
| 765 |
if( !memory_init() ) |
| 766 |
{ |
| 767 |
logerror("memory_init failed\n"); |
| 768 |
goto out_free; |
| 769 |
} |
| 770 |
|
| 771 |
if (gamedrv->driver_init) (*gamedrv->driver_init)(); |
| 772 |
|
| 773 |
return 0; |
| 774 |
|
| 775 |
out_free: |
| 776 |
input_port_free(Machine->input_ports); |
| 777 |
Machine->input_ports = 0; |
| 778 |
input_port_free(Machine->input_ports_default); |
| 779 |
Machine->input_ports_default = 0; |
| 780 |
out_code: |
| 781 |
code_close(); |
| 782 |
out: |
| 783 |
return 1; |
| 784 |
} |
| 785 |
|
| 786 |
|
| 787 |
void shutdown_machine(void) |
| 788 |
{ |
| 789 |
int i; |
| 790 |
|
| 791 |
#ifdef MESS |
| 792 |
exit_devices(); |
| 793 |
#endif |
| 794 |
|
| 795 |
/* ASG 971007 free memory element map */ |
| 796 |
memory_shutdown(); |
| 797 |
|
| 798 |
/* free the memory allocated for ROM and RAM */ |
| 799 |
for (i = 0;i < MAX_MEMORY_REGIONS;i++) |
| 800 |
free_memory_region(i); |
| 801 |
|
| 802 |
/* close all hard drives */ |
| 803 |
hard_disk_close_all(); |
| 804 |
|
| 805 |
/* reset the CPU system */ |
| 806 |
cpu_exit(); |
| 807 |
|
| 808 |
/* free the memory allocated for input ports definition */ |
| 809 |
input_port_free(Machine->input_ports); |
| 810 |
Machine->input_ports = 0; |
| 811 |
input_port_free(Machine->input_ports_default); |
| 812 |
Machine->input_ports_default = 0; |
| 813 |
|
| 814 |
code_close(); |
| 815 |
|
| 816 |
#ifndef JAPANESE |
| 817 |
uistring_shutdown (); /* LBO 042400 */ |
| 818 |
#endif |
| 819 |
state_save_reset(); |
| 820 |
} |
| 821 |
|
| 822 |
|
| 823 |
|
| 824 |
static void vh_close(void) |
| 825 |
{ |
| 826 |
int i; |
| 827 |
|
| 828 |
|
| 829 |
for (i = 0;i < MAX_GFX_ELEMENTS;i++) |
| 830 |
{ |
| 831 |
freegfx(Machine->gfx[i]); |
| 832 |
Machine->gfx[i] = 0; |
| 833 |
} |
| 834 |
#ifdef JAPANESE |
| 835 |
uifont_freefont(); |
| 836 |
#else |
| 837 |
freegfx(Machine->uifont); |
| 838 |
Machine->uifont = NULL; |
| 839 |
#endif |
| 840 |
if (Machine->debugger_font) |
| 841 |
{ |
| 842 |
freegfx(Machine->debugger_font); |
| 843 |
Machine->debugger_font = NULL; |
| 844 |
} |
| 845 |
osd_close_display(); |
| 846 |
if (Machine->scrbitmap) |
| 847 |
{ |
| 848 |
bitmap_free(Machine->scrbitmap); |
| 849 |
Machine->scrbitmap = NULL; |
| 850 |
} |
| 851 |
if (Machine->debug_bitmap) |
| 852 |
{ |
| 853 |
bitmap_free(Machine->debug_bitmap); |
| 854 |
Machine->debug_bitmap = NULL; |
| 855 |
} |
| 856 |
|
| 857 |
palette_stop(); |
| 858 |
} |
| 859 |
|
| 860 |
|
| 861 |
|
| 862 |
/* Scale the vector games to a given resolution */ |
| 863 |
static void scale_vectorgames(int gfx_width,int gfx_height,int *width,int *height) |
| 864 |
{ |
| 865 |
double x_scale, y_scale, scale; |
| 866 |
|
| 867 |
if (Machine->orientation & ORIENTATION_SWAP_XY) |
| 868 |
{ |
| 869 |
x_scale=(double)gfx_width/(double)(*height); |
| 870 |
y_scale=(double)gfx_height/(double)(*width); |
| 871 |
} |
| 872 |
else |
| 873 |
{ |
| 874 |
x_scale=(double)gfx_width/(double)(*width); |
| 875 |
y_scale=(double)gfx_height/(double)(*height); |
| 876 |
} |
| 877 |
if (x_scale<y_scale) |
| 878 |
scale=x_scale; |
| 879 |
else |
| 880 |
scale=y_scale; |
| 881 |
*width=(int)((double)*width*scale); |
| 882 |
*height=(int)((double)*height*scale); |
| 883 |
|
| 884 |
/* Padding to an dword value */ |
| 885 |
*width-=*width % 4; |
| 886 |
*height-=*height % 4; |
| 887 |
} |
| 888 |
|
| 889 |
|
| 890 |
static int vh_open(void) |
| 891 |
{ |
| 892 |
int i; |
| 893 |
int bmwidth,bmheight,viswidth,visheight,attr; |
| 894 |
|
| 895 |
|
| 896 |
for (i = 0;i < MAX_GFX_ELEMENTS;i++) Machine->gfx[i] = 0; |
| 897 |
Machine->uifont = NULL; |
| 898 |
Machine->debugger_font = NULL; |
| 899 |
|
| 900 |
if (palette_start() != 0) |
| 901 |
{ |
| 902 |
vh_close(); |
| 903 |
return 1; |
| 904 |
} |
| 905 |
|
| 906 |
|
| 907 |
/* convert the gfx ROMs into character sets. This is done BEFORE calling the driver's */ |
| 908 |
/* convert_color_prom() routine (in palette_init()) because it might need to check the */ |
| 909 |
/* Machine->gfx[] data */ |
| 910 |
if (Machine->drv->gfxdecodeinfo) |
| 911 |
{ |
| 912 |
for (i = 0;i < MAX_GFX_ELEMENTS && Machine->drv->gfxdecodeinfo[i].memory_region != -1;i++) |
| 913 |
{ |
| 914 |
int reglen = 8*memory_region_length(Machine->drv->gfxdecodeinfo[i].memory_region); |
| 915 |
struct GfxLayout glcopy; |
| 916 |
int j; |
| 917 |
|
| 918 |
|
| 919 |
memcpy(&glcopy,Machine->drv->gfxdecodeinfo[i].gfxlayout,sizeof(glcopy)); |
| 920 |
|
| 921 |
if (IS_FRAC(glcopy.total)) |
| 922 |
glcopy.total = reglen / glcopy.charincrement * FRAC_NUM(glcopy.total) / FRAC_DEN(glcopy.total); |
| 923 |
for (j = 0;j < MAX_GFX_PLANES;j++) |
| 924 |
{ |
| 925 |
if (IS_FRAC(glcopy.planeoffset[j])) |
| 926 |
{ |
| 927 |
glcopy.planeoffset[j] = FRAC_OFFSET(glcopy.planeoffset[j]) + |
| 928 |
reglen * FRAC_NUM(glcopy.planeoffset[j]) / FRAC_DEN(glcopy.planeoffset[j]); |
| 929 |
} |
| 930 |
} |
| 931 |
for (j = 0;j < MAX_GFX_SIZE;j++) |
| 932 |
{ |
| 933 |
if (IS_FRAC(glcopy.xoffset[j])) |
| 934 |
{ |
| 935 |
glcopy.xoffset[j] = FRAC_OFFSET(glcopy.xoffset[j]) + |
| 936 |
reglen * FRAC_NUM(glcopy.xoffset[j]) / FRAC_DEN(glcopy.xoffset[j]); |
| 937 |
} |
| 938 |
if (IS_FRAC(glcopy.yoffset[j])) |
| 939 |
{ |
| 940 |
glcopy.yoffset[j] = FRAC_OFFSET(glcopy.yoffset[j]) + |
| 941 |
reglen * FRAC_NUM(glcopy.yoffset[j]) / FRAC_DEN(glcopy.yoffset[j]); |
| 942 |
} |
| 943 |
} |
| 944 |
|
| 945 |
/* some games increment on partial tile boundaries; to handle this without reading */ |
| 946 |
/* past the end of the region, we may need to truncate the count */ |
| 947 |
/* an example is the games in metro.c */ |
| 948 |
if (glcopy.planeoffset[0] == GFX_RAW) |
| 949 |
{ |
| 950 |
int region = Machine->drv->gfxdecodeinfo[i].memory_region; |
| 951 |
UINT8 *base = memory_region(region) + Machine->drv->gfxdecodeinfo[i].start; |
| 952 |
UINT8 *end = memory_region(region) + memory_region_length(region); |
| 953 |
while (glcopy.total > 0) |
| 954 |
{ |
| 955 |
UINT8 *elementbase = base + (glcopy.total - 1) * glcopy.charincrement / 8; |
| 956 |
UINT8 *lastpixelbase = elementbase + glcopy.height * glcopy.yoffset[0] / 8 - 1; |
| 957 |
if (lastpixelbase < end) |
| 958 |
break; |
| 959 |
glcopy.total--; |
| 960 |
} |
| 961 |
} |
| 962 |
|
| 963 |
|
| 964 |
if ((Machine->gfx[i] = decodegfx(memory_region(Machine->drv->gfxdecodeinfo[i].memory_region) |
| 965 |
+ Machine->drv->gfxdecodeinfo[i].start, |
| 966 |
&glcopy)) == 0) |
| 967 |
{ |
| 968 |
vh_close(); |
| 969 |
|
| 970 |
bailing = 1; |
| 971 |
printf("Out of memory decoding gfx\n"); |
| 972 |
|
| 973 |
return 1; |
| 974 |
} |
| 975 |
if (Machine->remapped_colortable) |
| 976 |
Machine->gfx[i]->colortable = &Machine->remapped_colortable[Machine->drv->gfxdecodeinfo[i].color_codes_start]; |
| 977 |
Machine->gfx[i]->total_colors = Machine->drv->gfxdecodeinfo[i].total_color_codes; |
| 978 |
} |
| 979 |
} |
| 980 |
|
| 981 |
|
| 982 |
bmwidth = Machine->drv->screen_width; |
| 983 |
bmheight = Machine->drv->screen_height; |
| 984 |
|
| 985 |
if (Machine->drv->video_attributes & VIDEO_TYPE_VECTOR) |
| 986 |
scale_vectorgames(options.vector_width,options.vector_height,&bmwidth,&bmheight); |
| 987 |
|
| 988 |
if (!(Machine->drv->video_attributes & VIDEO_TYPE_VECTOR)) |
| 989 |
{ |
| 990 |
viswidth = Machine->drv->default_visible_area.max_x - Machine->drv->default_visible_area.min_x + 1; |
| 991 |
visheight = Machine->drv->default_visible_area.max_y - Machine->drv->default_visible_area.min_y + 1; |
| 992 |
} |
| 993 |
else |
| 994 |
{ |
| 995 |
viswidth = bmwidth; |
| 996 |
visheight = bmheight; |
| 997 |
} |
| 998 |
|
| 999 |
if (Machine->orientation & ORIENTATION_SWAP_XY) |
| 1000 |
{ |
| 1001 |
int temp; |
| 1002 |
temp = viswidth; viswidth = visheight; visheight = temp; |
| 1003 |
} |
| 1004 |
|
| 1005 |
/* take out the hicolor flag if it's not being used */ |
| 1006 |
attr = Machine->drv->video_attributes; |
| 1007 |
if (Machine->color_depth != 15 && Machine->color_depth != 32) |
| 1008 |
attr &= ~VIDEO_RGB_DIRECT; |
| 1009 |
|
| 1010 |
/* create the display bitmap, and allocate the palette */ |
| 1011 |
if (osd_create_display(viswidth,visheight,Machine->color_depth, |
| 1012 |
Machine->drv->frames_per_second,attr,Machine->orientation)) |
| 1013 |
{ |
| 1014 |
vh_close(); |
| 1015 |
return 1; |
| 1016 |
} |
| 1017 |
|
| 1018 |
Machine->scrbitmap = bitmap_alloc_depth(bmwidth,bmheight,Machine->color_depth); |
| 1019 |
if (!Machine->scrbitmap) |
| 1020 |
{ |
| 1021 |
vh_close(); |
| 1022 |
return 1; |
| 1023 |
} |
| 1024 |
|
| 1025 |
switch_ui_orientation(NULL); |
| 1026 |
if (mame_debug) |
| 1027 |
{ |
| 1028 |
Machine->debug_bitmap = bitmap_alloc_depth(options.debug_width,options.debug_height,Machine->color_depth); |
| 1029 |
if (!Machine->debug_bitmap) |
| 1030 |
{ |
| 1031 |
vh_close(); |
| 1032 |
return 1; |
| 1033 |
} |
| 1034 |
} |
| 1035 |
switch_true_orientation(NULL); |
| 1036 |
|
| 1037 |
set_visible_area( |
| 1038 |
Machine->drv->default_visible_area.min_x, |
| 1039 |
Machine->drv->default_visible_area.max_x, |
| 1040 |
Machine->drv->default_visible_area.min_y, |
| 1041 |
Machine->drv->default_visible_area.max_y); |
| 1042 |
|
| 1043 |
/* create spriteram buffers if necessary */ |
| 1044 |
if (Machine->drv->video_attributes & VIDEO_BUFFERS_SPRITERAM) |
| 1045 |
{ |
| 1046 |
if (spriteram_size) |
| 1047 |
{ |
| 1048 |
buffered_spriteram = auto_malloc(spriteram_size); |
| 1049 |
if (!buffered_spriteram) |
| 1050 |
{ |
| 1051 |
vh_close(); |
| 1052 |
return 1; |
| 1053 |
} |
| 1054 |
|
| 1055 |
state_save_register_UINT8("generic_video", 0, "buffered_spriteram", buffered_spriteram, spriteram_size); |
| 1056 |
|
| 1057 |
if (spriteram_2_size) |
| 1058 |
{ |
| 1059 |
buffered_spriteram_2 = auto_malloc(spriteram_2_size); |
| 1060 |
if (!buffered_spriteram_2) |
| 1061 |
{ |
| 1062 |
vh_close(); |
| 1063 |
return 1; |
| 1064 |
} |
| 1065 |
|
| 1066 |
state_save_register_UINT8("generic_video", 0, "buffered_spriteram_2", buffered_spriteram_2, spriteram_2_size); |
| 1067 |
} |
| 1068 |
|
| 1069 |
buffered_spriteram16 = (data16_t *)buffered_spriteram; |
| 1070 |
buffered_spriteram32 = (data32_t *)buffered_spriteram; |
| 1071 |
buffered_spriteram16_2 = (data16_t *)buffered_spriteram_2; |
| 1072 |
buffered_spriteram32_2 = (data32_t *)buffered_spriteram_2; |
| 1073 |
} |
| 1074 |
else |
| 1075 |
{ |
| 1076 |
logerror("vh_open(): Video buffers spriteram but spriteram_size is 0\n"); |
| 1077 |
} |
| 1078 |
} |
| 1079 |
|
| 1080 |
/* build our private user interface font */ |
| 1081 |
/* This must be done AFTER osd_create_display() so the function knows the */ |
| 1082 |
/* resolution we are running at and can pick a different font depending on it. */ |
| 1083 |
/* It must be done BEFORE palette_init() because that will also initialize */ |
| 1084 |
/* (through osd_allocate_colors()) the uifont colortable. */ |
| 1085 |
#ifdef JAPANESE |
| 1086 |
if (uifont_buildfont() == 0) |
| 1087 |
#else |
| 1088 |
if (NULL == (Machine->uifont = builduifont())) |
| 1089 |
#endif |
| 1090 |
{ |
| 1091 |
vh_close(); |
| 1092 |
return 1; |
| 1093 |
} |
| 1094 |
#ifdef MAME_DEBUG |
| 1095 |
if (mame_debug) |
| 1096 |
{ |
| 1097 |
if (NULL == (Machine->debugger_font = build_debugger_font())) |
| 1098 |
{ |
| 1099 |
vh_close(); |
| 1100 |
return 1; |
| 1101 |
} |
| 1102 |
} |
| 1103 |
#endif |
| 1104 |
|
| 1105 |
/* initialize the palette - must be done after osd_create_display() */ |
| 1106 |
if (palette_init()) |
| 1107 |
{ |
| 1108 |
vh_close(); |
| 1109 |
return 1; |
| 1110 |
} |
| 1111 |
|
| 1112 |
pdrawgfx_shadow_lowpri = 0; |
| 1113 |
|
| 1114 |
#ifndef MAME32JP |
| 1115 |
leds_status = 0; |
| 1116 |
#endif |
| 1117 |
|
| 1118 |
return 0; |
| 1119 |
} |
| 1120 |
|
| 1121 |
|
| 1122 |
|
| 1123 |
/*************************************************************************** |
| 1124 |
|
| 1125 |
This function takes care of refreshing the screen, processing user input, |
| 1126 |
and throttling the emulation speed to obtain the required frames per second. |
| 1127 |
|
| 1128 |
***************************************************************************/ |
| 1129 |
|
| 1130 |
void force_partial_update(int scanline) |
| 1131 |
{ |
| 1132 |
struct rectangle clip = Machine->visible_area; |
| 1133 |
|
| 1134 |
/* if skipping this frame, bail */ |
| 1135 |
if (osd_skip_this_frame()) |
| 1136 |
return; |
| 1137 |
|
| 1138 |
/* skip if less than the lowest so far */ |
| 1139 |
if (scanline < last_partial_scanline) |
| 1140 |
return; |
| 1141 |
|
| 1142 |
/* if there's a dirty bitmap and we didn't do any partial updates yet, handle it now */ |
| 1143 |
if (bitmap_dirty && last_partial_scanline == 0) |
| 1144 |
{ |
| 1145 |
fillbitmap(Machine->scrbitmap, get_black_pen(), NULL); |
| 1146 |
osd_mark_dirty(Machine->uixmin, Machine->uiymin, Machine->uixmin+Machine->uiwidth-1, Machine->uiymin+Machine->uiheight-1); |
| 1147 |
bitmap_dirty = 0; |
| 1148 |
} |
| 1149 |
|
| 1150 |
/* set the start/end scanlines */ |
| 1151 |
if (last_partial_scanline > clip.min_y) |
| 1152 |
clip.min_y = last_partial_scanline; |
| 1153 |
if (scanline < clip.max_y) |
| 1154 |
clip.max_y = scanline; |
| 1155 |
|
| 1156 |
/* render if necessary */ |
| 1157 |
if (clip.min_y <= clip.max_y) |
| 1158 |
{ |
| 1159 |
profiler_mark(PROFILER_VIDEO); |
| 1160 |
(*Machine->drv->video_update)(Machine->scrbitmap, &clip); |
| 1161 |
partial_update_count++; |
| 1162 |
profiler_mark(PROFILER_END); |
| 1163 |
} |
| 1164 |
|
| 1165 |
/* remember where we left off */ |
| 1166 |
last_partial_scanline = scanline + 1; |
| 1167 |
} |
| 1168 |
|
| 1169 |
|
| 1170 |
void reset_partial_updates(void) |
| 1171 |
{ |
| 1172 |
last_partial_scanline = 0; |
| 1173 |
partial_update_count = 0; |
| 1174 |
} |
| 1175 |
|
| 1176 |
|
| 1177 |
|
| 1178 |
/************************************* |
| 1179 |
* |
| 1180 |
* Called by cpuexec either at the |
| 1181 |
* start or end of VBLANK |
| 1182 |
* |
| 1183 |
*************************************/ |
| 1184 |
|
| 1185 |
int updatescreen(void) |
| 1186 |
{ |
| 1187 |
/* update sound */ |
| 1188 |
sound_update(); |
| 1189 |
#ifdef MAME32JP |
| 1190 |
osd_log_wave(); |
| 1191 |
#endif |
| 1192 |
|
| 1193 |
/* if we're not skipping this frame, draw the screen */ |
| 1194 |
if (osd_skip_this_frame() == 0) |
| 1195 |
{ |
| 1196 |
profiler_mark(PROFILER_VIDEO); |
| 1197 |
draw_screen(); |
| 1198 |
profiler_mark(PROFILER_END); |
| 1199 |
} |
| 1200 |
|
| 1201 |
/* the user interface must be called between vh_update() and osd_update_video_and_audio(), */ |
| 1202 |
/* to allow it to overlay things on the game display. We must call it even */ |
| 1203 |
/* if the frame is skipped, to keep a consistent timing. */ |
| 1204 |
if (handle_user_interface(real_scrbitmap)) |
| 1205 |
/* quit if the user asked to */ |
| 1206 |
return 1; |
| 1207 |
|
| 1208 |
/* blit to the screen */ |
| 1209 |
update_video_and_audio(); |
| 1210 |
|
| 1211 |
/* call the end-of-frame callback */ |
| 1212 |
if (Machine->drv->video_eof) |
| 1213 |
(*Machine->drv->video_eof)(); |
| 1214 |
|
| 1215 |
return 0; |
| 1216 |
} |
| 1217 |
|
| 1218 |
|
| 1219 |
/*************************************************************************** |
| 1220 |
|
| 1221 |
Draw screen with overlays and backdrops |
| 1222 |
|
| 1223 |
***************************************************************************/ |
| 1224 |
|
| 1225 |
void draw_screen(void) |
| 1226 |
{ |
| 1227 |
/* finish updating the screen */ |
| 1228 |
force_partial_update(Machine->visible_area.max_y); |
| 1229 |
|
| 1230 |
/* blend with artwork */ |
| 1231 |
if (artwork_backdrop || artwork_overlay) |
| 1232 |
artwork_draw(artwork_real_scrbitmap, Machine->scrbitmap, bitmap_dirty); |
| 1233 |
} |
| 1234 |
|
| 1235 |
void schedule_full_refresh(void) |
| 1236 |
{ |
| 1237 |
bitmap_dirty = 1; |
| 1238 |
} |
| 1239 |
|
| 1240 |
|
| 1241 |
/*************************************************************************** |
| 1242 |
|
| 1243 |
Calls OSD layer handling overlays and backdrops |
| 1244 |
|
| 1245 |
***************************************************************************/ |
| 1246 |
void update_video_and_audio(void) |
| 1247 |
{ |
| 1248 |
#ifdef MAME_DEBUG |
| 1249 |
debug_trace_delay = 0; |
| 1250 |
#endif |
| 1251 |
#ifdef MAME32JP |
| 1252 |
osd_update_video_and_audio(real_scrbitmap,Machine->debug_bitmap); |
| 1253 |
#else |
| 1254 |
osd_update_video_and_audio(real_scrbitmap,Machine->debug_bitmap,leds_status); |
| 1255 |
#endif |
| 1256 |
} |
| 1257 |
|
| 1258 |
|
| 1259 |
/*************************************************************************** |
| 1260 |
|
| 1261 |
Run the emulation. Start the various subsystems and the CPU emulation. |
| 1262 |
Returns non zero in case of error. |
| 1263 |
|
| 1264 |
***************************************************************************/ |
| 1265 |
int run_machine(void) |
| 1266 |
{ |
| 1267 |
int res = 1; |
| 1268 |
|
| 1269 |
/* start the video hardware */ |
| 1270 |
if (vh_open() == 0) |
| 1271 |
{ |
| 1272 |
tilemap_init(); |
| 1273 |
if (Machine->drv->video_start == 0 || (*Machine->drv->video_start)() == 0) /* start the video hardware */ |
| 1274 |
{ |
| 1275 |
if (sound_start() == 0) /* start the audio hardware */ |
| 1276 |
{ |
| 1277 |
int region; |
| 1278 |
|
| 1279 |
if (artwork_overlay || artwork_backdrop) |
| 1280 |
real_scrbitmap = artwork_real_scrbitmap; |
| 1281 |
else |
| 1282 |
real_scrbitmap = Machine->scrbitmap; |
| 1283 |
|
| 1284 |
/* free memory regions allocated with REGIONFLAG_DISPOSE (typically gfx roms) */ |
| 1285 |
for (region = 0; region < MAX_MEMORY_REGIONS; region++) |
| 1286 |
{ |
| 1287 |
if (Machine->memory_region[region].flags & ROMREGION_DISPOSE) |
| 1288 |
{ |
| 1289 |
int i; |
| 1290 |
|
| 1291 |
/* invalidate contents to avoid subtle bugs */ |
| 1292 |
for (i = 0;i < memory_region_length(region);i++) |
| 1293 |
memory_region(region)[i] = rand(); |
| 1294 |
free(Machine->memory_region[region].base); |
| 1295 |
Machine->memory_region[region].base = 0; |
| 1296 |
} |
| 1297 |
} |
| 1298 |
|
| 1299 |
if (settingsloaded == 0) |
| 1300 |
{ |
| 1301 |
/* if there is no saved config, it must be first time we run this game, */ |
| 1302 |
/* so show the disclaimer. */ |
| 1303 |
if (showcopyright(real_scrbitmap)) goto userquit; |
| 1304 |
} |
| 1305 |
|
| 1306 |
if (showgamewarnings(real_scrbitmap) == 0) /* show info about incorrect behaviour (wrong colors etc.) */ |
| 1307 |
{ |
| 1308 |
init_user_interface(); |
| 1309 |
|
| 1310 |
/* disable cheat if no roms */ |
| 1311 |
if (!gamedrv->rom) options.cheat = 0; |
| 1312 |
|
| 1313 |
if (options.cheat) InitCheat(); |
| 1314 |
|
| 1315 |
if (Machine->drv->nvram_handler) |
| 1316 |
{ |
| 1317 |
void *f; |
| 1318 |
|
| 1319 |
f = osd_fopen(Machine->gamedrv->name,0,OSD_FILETYPE_NVRAM,0); |
| 1320 |
(*Machine->drv->nvram_handler)(f,0); |
| 1321 |
if (f) osd_fclose(f); |
| 1322 |
} |
| 1323 |
#ifdef MAME32JP |
| 1324 |
if((inp_use & 0x80000000)) { |
| 1325 |
if(options.record) { |
| 1326 |
(*Machine->drv->nvram_handler)(options.record,1); |
| 1327 |
} else if(options.playback) { |
| 1328 |
(*Machine->drv->nvram_handler)(options.playback,0); |
| 1329 |
} |
| 1330 |
} |
| 1331 |
#endif |
| 1332 |
cpu_run(); /* run the emulation! */ |
| 1333 |
|
| 1334 |
if (Machine->drv->nvram_handler) |
| 1335 |
{ |
| 1336 |
void *f; |
| 1337 |
|
| 1338 |
if ((f = osd_fopen(Machine->gamedrv->name,0,OSD_FILETYPE_NVRAM,1)) != 0) |
| 1339 |
{ |
| 1340 |
(*Machine->drv->nvram_handler)(f,1); |
| 1341 |
osd_fclose(f); |
| 1342 |
} |
| 1343 |
} |
| 1344 |
|
| 1345 |
#ifdef MAME32JP |
| 1346 |
if(inp_use) { |
| 1347 |
extern void SetUse60HzVsync(int); |
| 1348 |
SetUse60HzVsync(inp_use >> 3); |
| 1349 |
inp_use = 0; |
| 1350 |
} |
| 1351 |
#endif |
| 1352 |
if (options.cheat) StopCheat(); |
| 1353 |
|
| 1354 |
/* save input ports settings */ |
| 1355 |
save_input_port_settings(); |
| 1356 |
} |
| 1357 |
|
| 1358 |
userquit: |
| 1359 |
/* the following MUST be done after hiscore_save() otherwise */ |
| 1360 |
/* some 68000 games will not work */ |
| 1361 |
sound_stop(); |
| 1362 |
if (Machine->drv->video_stop) (*Machine->drv->video_stop)(); |
| 1363 |
artwork_kill(); |
| 1364 |
|
| 1365 |
res = 0; |
| 1366 |
} |
| 1367 |
else if (!bailing) |
| 1368 |
{ |
| 1369 |
bailing = 1; |
| 1370 |
printf("Unable to start audio emulation\n"); |
| 1371 |
} |
| 1372 |
} |
| 1373 |
else if (!bailing) |
| 1374 |
{ |
| 1375 |
bailing = 1; |
| 1376 |
printf("Unable to start video emulation\n"); |
| 1377 |
} |
| 1378 |
|
| 1379 |
tilemap_close(); |
| 1380 |
vh_close(); |
| 1381 |
} |
| 1382 |
else if (!bailing) |
| 1383 |
{ |
| 1384 |
bailing = 1; |
| 1385 |
printf("Unable to start video emulation\n"); |
| 1386 |
} |
| 1387 |
|
| 1388 |
return res; |
| 1389 |
} |
| 1390 |
|
| 1391 |
|
| 1392 |
|
| 1393 |
int mame_highscore_enabled(void) |
| 1394 |
{ |
| 1395 |
/* disable high score when record/playback is on */ |
| 1396 |
if (record != 0 || playback != 0) return 0; |
| 1397 |
|
| 1398 |
/* disable high score when cheats are used */ |
| 1399 |
if (he_did_cheat != 0) return 0; |
| 1400 |
|
| 1401 |
#ifdef MAME_NET |
| 1402 |
/* disable high score when playing network game */ |
| 1403 |
/* (this forces all networked machines to start from the same state!) */ |
| 1404 |
if (net_active()) return 0; |
| 1405 |
#endif /* MAME_NET */ |
| 1406 |
|
| 1407 |
return 1; |
| 1408 |
} |
| 1409 |
|
| 1410 |
|
| 1411 |
#ifndef MAME32JP |
| 1412 |
void set_led_status(int num,int on) |
| 1413 |
{ |
| 1414 |
if (on) leds_status |= (1 << num); |
| 1415 |
else leds_status &= ~(1 << num); |
| 1416 |
} |
| 1417 |
#endif |
| 1418 |
|
| 1419 |
|
| 1420 |
|
| 1421 |
/************************************* |
| 1422 |
* |
| 1423 |
* Expand a machine driver |
| 1424 |
* |
| 1425 |
*************************************/ |
| 1426 |
|
| 1427 |
void expand_machine_driver(void (*constructor)(struct InternalMachineDriver *), struct InternalMachineDriver *output) |
| 1428 |
{ |
| 1429 |
memset(output, 0, sizeof(*output)); |
| 1430 |
|
| 1431 |
/* if this is tagged in the new format, parse it */ |
| 1432 |
(*constructor)(output); |
| 1433 |
} |
| 1434 |
|
| 1435 |
|
| 1436 |
|
| 1437 |
/************************************* |
| 1438 |
* |
| 1439 |
* Helper functions for building up |
| 1440 |
* InternalMachineDrivers |
| 1441 |
* |
| 1442 |
*************************************/ |
| 1443 |
|
| 1444 |
struct MachineCPU *machine_add_cpu(struct InternalMachineDriver *machine, const char *tag, int type, int cpuclock) |
| 1445 |
{ |
| 1446 |
int cpunum; |
| 1447 |
|
| 1448 |
for (cpunum = 0; cpunum < MAX_CPU; cpunum++) |
| 1449 |
if (machine->cpu[cpunum].cpu_type == 0) |
| 1450 |
{ |
| 1451 |
machine->cpu[cpunum].tag = tag; |
| 1452 |
machine->cpu[cpunum].cpu_type = type; |
| 1453 |
machine->cpu[cpunum].cpu_clock = cpuclock; |
| 1454 |
return &machine->cpu[cpunum]; |
| 1455 |
} |
| 1456 |
|
| 1457 |
logerror("Out of CPU's!\n"); |
| 1458 |
return NULL; |
| 1459 |
} |
| 1460 |
|
| 1461 |
|
| 1462 |
struct MachineCPU *machine_find_cpu(struct InternalMachineDriver *machine, const char *tag) |
| 1463 |
{ |
| 1464 |
int cpunum; |
| 1465 |
|
| 1466 |
for (cpunum = 0; cpunum < MAX_CPU; cpunum++) |
| 1467 |
if (machine->cpu[cpunum].tag && strcmp(machine->cpu[cpunum].tag, tag) == 0) |
| 1468 |
return &machine->cpu[cpunum]; |
| 1469 |
|
| 1470 |
logerror("Can't find CPU '%s'!\n", tag); |
| 1471 |
return NULL; |
| 1472 |
} |
| 1473 |
|
| 1474 |
|
| 1475 |
void machine_remove_cpu(struct InternalMachineDriver *machine, const char *tag) |
| 1476 |
{ |
| 1477 |
int cpunum; |
| 1478 |
|
| 1479 |
for (cpunum = 0; cpunum < MAX_CPU; cpunum++) |
| 1480 |
if (machine->cpu[cpunum].tag == tag) |
| 1481 |
{ |
| 1482 |
memmove(&machine->cpu[cpunum], &machine->cpu[cpunum + 1], sizeof(machine->cpu[0]) * (MAX_CPU - cpunum - 1)); |
| 1483 |
memset(&machine->cpu[MAX_CPU - 1], 0, sizeof(machine->cpu[0])); |
| 1484 |
return; |
| 1485 |
} |
| 1486 |
|
| 1487 |
logerror("Can't find CPU '%s'!\n", tag); |
| 1488 |
} |
| 1489 |
|
| 1490 |
|
| 1491 |
struct MachineSound *machine_add_sound(struct InternalMachineDriver *machine, const char *tag, int type, void *sndintf) |
| 1492 |
{ |
| 1493 |
int soundnum; |
| 1494 |
|
| 1495 |
for (soundnum = 0; soundnum < MAX_SOUND; soundnum++) |
| 1496 |
if (machine->sound[soundnum].sound_type == 0) |
| 1497 |
{ |
| 1498 |
machine->sound[soundnum].tag = tag; |
| 1499 |
machine->sound[soundnum].sound_type = type; |
| 1500 |
machine->sound[soundnum].sound_interface = sndintf; |
| 1501 |
return &machine->sound[soundnum]; |
| 1502 |
} |
| 1503 |
|
| 1504 |
logerror("Out of sounds!\n"); |
| 1505 |
return NULL; |
| 1506 |
|
| 1507 |
} |
| 1508 |
|
| 1509 |
|
| 1510 |
struct MachineSound *machine_find_sound(struct InternalMachineDriver *machine, const char *tag) |
| 1511 |
{ |
| 1512 |
int soundnum; |
| 1513 |
|
| 1514 |
for (soundnum = 0; soundnum < MAX_SOUND; soundnum++) |
| 1515 |
if (machine->sound[soundnum].tag && strcmp(machine->sound[soundnum].tag, tag) == 0) |
| 1516 |
return &machine->sound[soundnum]; |
| 1517 |
|
| 1518 |
logerror("Can't find sound '%s'!\n", tag); |
| 1519 |
return NULL; |
| 1520 |
} |
| 1521 |
|
| 1522 |
|
| 1523 |
void machine_remove_sound(struct InternalMachineDriver *machine, const char *tag) |
| 1524 |
{ |
| 1525 |
int soundnum; |
| 1526 |
|
| 1527 |
for (soundnum = 0; soundnum < MAX_SOUND; soundnum++) |
| 1528 |
if (machine->sound[soundnum].tag == tag) |
| 1529 |
{ |
| 1530 |
memmove(&machine->sound[soundnum], &machine->sound[soundnum + 1], sizeof(machine->sound[0]) * (MAX_SOUND - soundnum - 1)); |
| 1531 |
memset(&machine->sound[MAX_SOUND - 1], 0, sizeof(machine->sound[0])); |
| 1532 |
return; |
| 1533 |
} |
| 1534 |
|
| 1535 |
logerror("Can't find sound '%s'!\n", tag); |
| 1536 |
} |
| 1537 |
|
| 1538 |
|
| 1539 |
void *mame_hard_disk_open(const char *filename, const char *mode) |
| 1540 |
{ |
| 1541 |
/* look for read-only drives first in the ROM path */ |
| 1542 |
if (mode[0] == 'r' && !strchr(mode, '+')) |
| 1543 |
{ |
| 1544 |
void *file = osd_fopen(Machine->gamedrv->name, filename, OSD_FILETYPE_IMAGE_R, 0); |
| 1545 |
if (file) |
| 1546 |
return file; |
| 1547 |
} |
| 1548 |
|
| 1549 |
/* look for read/write drives in the diff area */ |
| 1550 |
return osd_fopen(NULL, filename, OSD_FILETYPE_IMAGE_DIFF, 1); |
| 1551 |
} |
| 1552 |
|
| 1553 |
|
| 1554 |
void mame_hard_disk_close(void *file) |
| 1555 |
{ |
| 1556 |
osd_fclose(file); |
| 1557 |
} |
| 1558 |
|
| 1559 |
|
| 1560 |
UINT32 mame_hard_disk_read(void *file, UINT64 offset, UINT32 count, void *buffer) |
| 1561 |
{ |
| 1562 |
osd_fseek(file, offset, SEEK_SET); |
| 1563 |
return osd_fread(file, buffer, count); |
| 1564 |
} |
| 1565 |
|
| 1566 |
|
| 1567 |
UINT32 mame_hard_disk_write(void *file, UINT64 offset, UINT32 count, const void *buffer) |
| 1568 |
{ |
| 1569 |
osd_fseek(file, offset, SEEK_SET); |
| 1570 |
return osd_fwrite(file, buffer, count); |
| 1571 |
} |
| 1572 |
|