(MESS) snes.c: major overhaul of cart and add-on handling [Fabio Priuli]

- updated carts to be slot devices
  - simplified loading and bankswitch mechanism
  - removed drivers snessfx and snespsfx: SuperFX/GSU games can now 
    be loaded in snes and snespal
  - removed drivers snesdsp and snespdsp: NEC DSPx games can now 
    be loaded in snes and snespal from softlist
  - removed drivers snesst10 and snesst11: Seta DSP games can now 
    be loaded in snes and snespal from softlist
  - removed driver snesst: when you load Sufami Turbo, two more cart slots 
    (-cart2 and -cart3) become available to load ST carts
  - added preliminary support for games with BS-X slots: when you load 
    one of these, a -cart2 slot becomes available to load a 8MB memory pack
    (only a few of these work at the moment, e.g. Same Game)
  - added support for loading DSPx games with DSP dump appended at the 
    end of the .sfc file
  - added two "legacy" drivers snes_add and snesp_add containing the 
    DSP dumps in the bios, to allow loading of old .sfc dumps missing the DSP
    content (these drivers are of course marked as GAME_UNOFFICIAL)


out of whatsnew: 
- I have removed the DSP1B dump from NSS, because I plan to update NSS
to use slot devices as well and that will cover everything needed by SMK, if we 
ever find its NSS release and dump it
- Also, I will take care of fixing snes entries in messnew before u2, because 
part of this set of changes supersede the log for 21546 (e.g. no more snesnew
or snespnew wip drivers)
This commit is contained in:
Fabio Priuli 2013-03-15 09:13:49 +00:00
parent d0a4f25e58
commit 16d68e7fbb
16 changed files with 1130 additions and 5334 deletions

6
.gitattributes vendored
View File

@ -7493,14 +7493,8 @@ src/mess/machine/smartmed.h svneol=native#text/plain
src/mess/machine/smc92x4.c svneol=native#text/plain
src/mess/machine/smc92x4.h svneol=native#text/plain
src/mess/machine/sms.c svneol=native#text/plain
src/mess/machine/snes7110.c svneol=native#text/plain
src/mess/machine/snescart.c svneol=native#text/plain
src/mess/machine/snescart.h svneol=native#text/plain
src/mess/machine/snescx4.c svneol=native#text/plain
src/mess/machine/snescx4.h svneol=native#text/plain
src/mess/machine/snesobc1.c svneol=native#text/plain
src/mess/machine/snesrtc.c svneol=native#text/plain
src/mess/machine/snessdd1.c svneol=native#text/plain
src/mess/machine/sns_bsx.c svneol=native#text/plain
src/mess/machine/sns_bsx.h svneol=native#text/plain
src/mess/machine/sns_rom.c svneol=native#text/plain

View File

@ -866,17 +866,11 @@ MACHINE_CONFIG_END
#define NSS_BIOS \
ROM_REGION(0x100, "sound_ipl", 0) /* IPL ROM */ \
ROM_LOAD("spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) \
ROM_REGION(0x10000, "addons", ROMREGION_ERASE00) /* add-on chip ROMs (DSP1 will be needed if we dump the NSS version of Super Mario Kart)*/\
ROM_LOAD( "dsp1b.bin", SNES_DSP1B_OFFSET, 0x002800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) ) \
ROM_REGION(0x8000, "bios", 0) /* Bios CPU */ \
ROM_SYSTEM_BIOS( 0, "single", "Nintendo Super System (Single Cart BIOS)" ) \
ROMX_LOAD("nss-ic14.02", 0x00000, 0x8000, CRC(e06cb58f) SHA1(62f507e91a2797919a78d627af53f029c7d81477), ROM_BIOS(1) ) /* bios */ \
ROM_SYSTEM_BIOS( 1, "multi", "Nintendo Super System (Multi Cart BIOS)" ) \
ROMX_LOAD("nss-c.dat" , 0x00000, 0x8000, CRC(a8e202b3) SHA1(b7afcfe4f5cf15df53452dc04be81929ced1efb2), ROM_BIOS(2) ) /* bios */ \
ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF) \
ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF)
ROMX_LOAD("nss-c.dat" , 0x00000, 0x8000, CRC(a8e202b3) SHA1(b7afcfe4f5cf15df53452dc04be81929ced1efb2), ROM_BIOS(2) ) /* bios */
ROM_START( nss )

View File

@ -29,12 +29,6 @@
#define SNES_LAYER_DEBUG 0
#define SNES_DSP1B_OFFSET (0x0000)
#define SNES_DSP1_OFFSET (0x3000)
#define SNES_DSP2_OFFSET (0x6000)
#define SNES_DSP3_OFFSET (0x9000)
#define SNES_DSP4_OFFSET (0xc000)
/* Debug definitions */
#ifdef MAME_DEBUG
/* #define SNES_DBG_GENERAL*/ /* Display general debug info */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,913 +0,0 @@
/***************************************************************************
snescart.c
Machine file to handle cart loading in the Nintendo Super NES emulation.
***************************************************************************/
#include "emu.h"
#include "includes/snes.h"
#include "imagedev/cartslot.h"
#include "snescart.h"
#define SNES_CART_DEBUG 0
/****** Strings for Cart Header Logging ******/
#define UNK "Unknown"
/* Some known type of cart */
static const char *const types[] =
{
"ROM",
"ROM, DSP-1",
"ROM, DSP-2",
"ROM, DSP-3",
"ROM, DSP-4",
"ROM, Super FX / FX2",
"ROM, SA-1",
"ROM, S-DD1",
"ROM, OBC-1",
"ROM, S-RTC",
"ROM, Z80GB (Super Game Boy)",
"ROM, C4",
"ROM, Seta ST-010",
"ROM, Seta ST-011",
"ROM, Seta ST-018",
"ROM, SPC7110",
"ROM, SPC7110, RTC",
UNK, // to add: Satellaview BS-X detection
};
/* Some known countries */
static const char *const countries[] =
{
/* 0*/ "Japan (NTSC)", "USA & Canada (NTSC)", "Europe, Oceania & Asia (PAL)", "Sweden (PAL)",
/* 4*/ "Finland (PAL)", "Denmark (PAL)", "France (PAL)", "Holland (PAL)",
/* 8*/ "Spain (PAL)", "Germany, Austria & Switzerland (PAL)", "Italy (PAL)", "Hong Kong & China (PAL)",
/* c*/ "Indonesia (PAL)", "South Korea (NTSC)", UNK, UNK,
};
/* Some known companies (integrations to the list from Snes9x) */
static const char *const companies[] =
{
/* 0*/ "Invalid", "Nintendo", "Ajinomoto", "Imagineer-Zoom", "Chris Gray Enterprises Inc.", "Zamuse", "Falcom", UNK,
/* 8*/ "Capcom", "HOT-B", "Jaleco", "Coconuts", "Rage Software", "Micronet", "Technos", "Mebio Software",
/*10*/ "SHOUEi System", "Starfish", "Gremlin Graphics", "Electronic Arts", "NCS / Masaya", "COBRA Team", "Human/Field", "KOEI",
/*18*/ "Hudson Soft", "Game Village", "Yanoman", UNK, "Tecmo", UNK, "Open System", "Virgin Games",
/*20*/ "KSS", "Sunsoft", "POW", "Micro World", UNK, UNK, "Enix", "Loriciel/Electro Brain",
/*28*/ "Kemco", "Seta Co.,Ltd.", "Culture Brain", "Irem Japan", "Pal Soft", "Visit Co.,Ltd.", "INTEC Inc.", "System Sacom Corp.",
/*30*/ "Viacom New Media", "Carrozzeria", "Dynamic", "Nintendo", "Magifact", "Hect", UNK, UNK,
/*38*/ "Capcom Europe", "Accolade Europe", UNK, "Arcade Zone", "Empire Software", "Loriciel", "Gremlin Graphics", UNK,
/*40*/ "Seika Corp.", "UBI Soft", UNK, UNK, "LifeFitness Exertainment", UNK, "System 3", "Spectrum Holobyte",
/*48*/ UNK, "Irem", UNK, "Raya Systems/Sculptured Software", "Renovation Products", "Malibu Games/Black Pearl", UNK, "U.S. Gold",
/*50*/ "Absolute Entertainment", "Acclaim", "Activision", "American Sammy", "GameTek", "Hi Tech Expressions", "LJN Toys", UNK,
/*58*/ UNK, UNK, "Mindscape", "Romstar, Inc.", UNK, "Tradewest", UNK, "American Softworks Corp.",
/*60*/ "Titus", "Virgin Interactive Entertainment", "Maxis", "Origin/FCI/Pony Canyon", UNK, UNK, UNK, "Ocean",
/*68*/ UNK, "Electronic Arts", UNK, "Laser Beam", UNK, UNK, "Elite", "Electro Brain",
/*70*/ "Infogrames", "Interplay", "LucasArts", "Parker Brothers", "Konami", "STORM", UNK, UNK,
/*78*/ "THQ Software", "Accolade Inc.", "Triffix Entertainment", UNK, "Microprose", UNK, UNK, "Kemco",
/*80*/ "Misawa", "Teichio", "Namco Ltd.", "Lozc", "Koei", UNK, "Tokuma Shoten Intermedia", "Tsukuda Original",
/*88*/ "DATAM-Polystar", UNK, UNK, "Bullet-Proof Software", "Vic Tokai", UNK, "Character Soft", "I\'\'Max",
/*90*/ "Takara", "CHUN Soft", "Video System Co., Ltd.", "BEC", UNK, "Varie", "Yonezawa / S'Pal Corp.", "Kaneco",
/*98*/ UNK, "Pack in Video", "Nichibutsu", "TECMO", "Imagineer Co.", UNK, UNK, UNK,
/*a0*/ "Telenet", "Hori", UNK, UNK, "Konami", "K.Amusement Leasing Co.", UNK, "Takara",
/*a8*/ UNK, "Technos Jap.", "JVC", UNK, "Toei Animation", "Toho", UNK, "Namco Ltd.",
/*b0*/ "Media Rings Corp.", "ASCII Co. Activison", "Bandai", UNK, "Enix America", UNK, "Halken", UNK,
/*b8*/ UNK, UNK, "Culture Brain", "Sunsoft", "Toshiba EMI", "Sony Imagesoft", UNK, "Sammy",
/*c0*/ "Taito", UNK, "Kemco", "Square", "Tokuma Soft", "Data East", "Tonkin House", UNK,
/*c8*/ "KOEI", UNK, "Konami USA", "NTVIC", UNK, "Meldac", "Pony Canyon", "Sotsu Agency/Sunrise",
/*d0*/ "Disco/Taito", "Sofel", "Quest Corp.", "Sigma", "Ask Kodansha Co., Ltd.", UNK, "Naxat", UNK,
/*d8*/ "Capcom Co., Ltd.", "Banpresto", "Tomy", "Acclaim", UNK, "NCS", "Human Entertainment", "Altron",
/*e0*/ "Jaleco", UNK, "Yutaka", UNK, "T&ESoft", "EPOCH Co.,Ltd.", UNK, "Athena",
/*e8*/ "Asmik", "Natsume", "King Records", "Atlus", "Sony Music Entertainment", UNK, "IGS", UNK,
/*f0*/ UNK, "Motown Software", "Left Field Entertainment", "Beam Software", "Tec Magik", UNK, UNK, UNK,
/*f8*/ UNK, "Cybersoft", UNK, "Psygnosis", UNK, UNK, "Davidson", UNK,
};
/* We use this to convert the company_id in the header to int value to be passed in companies[] */
static int char_to_int_conv( char id )
{
int value;
if (id == '1') value = 0x01;
else if (id == '2') value = 0x02;
else if (id == '3') value = 0x03;
else if (id == '4') value = 0x04;
else if (id == '5') value = 0x05;
else if (id == '6') value = 0x06;
else if (id == '7') value = 0x07;
else if (id == '8') value = 0x08;
else if (id == '9') value = 0x09;
else if (id == 'A') value = 0x0a;
else if (id == 'B') value = 0x0b;
else if (id == 'C') value = 0x0c;
else if (id == 'D') value = 0x0d;
else if (id == 'E') value = 0x0e;
else if (id == 'F') value = 0x0f;
else value = 0x00;
return value;
}
/***************************************************************************
SRAM handling
***************************************************************************/
/* Loads the battery backed RAM into the appropriate memory area */
static void snes_load_sram(running_machine &machine)
{
snes_state *state = machine.driver_data<snes_state>();
device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart"));
image->battery_load(state->m_cart[0].m_nvram, state->m_cart[0].m_nvram_size, 0xff);
}
/* Saves the battery backed RAM from the appropriate memory area */
void snes_machine_stop(running_machine &machine)
{
snes_state *state = machine.driver_data<snes_state>();
/* Save SRAM */
if (state->m_cart[0].m_nvram_size > 0)
{
device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart"));
image->battery_save(state->m_cart[0].m_nvram, state->m_cart[0].m_nvram_size);
}
}
static void sufami_load_sram(running_machine &machine, const char *cart_tag)
{
snes_state *state = machine.driver_data<snes_state>();
int slot_id = 0;
device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device(cart_tag));
if (strcmp(cart_tag, ":slot_a") == 0)
slot_id = 0;
if (strcmp(cart_tag, ":slot_b") == 0)
slot_id = 1;
image->battery_load(state->m_cart[slot_id].m_nvram, state->m_cart[slot_id].m_nvram_size, 0xff);
}
void sufami_machine_stop(running_machine &machine)
{
snes_state *state = machine.driver_data<snes_state>();
if (state->m_cart[0].slot_in_use && state->m_cart[0].m_nvram_size)
{
device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("slot_a"));
image->battery_save(state->m_cart[0].m_nvram, state->m_cart[0].m_nvram_size);
}
if (state->m_cart[1].slot_in_use && state->m_cart[1].m_nvram_size)
{
device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("slot_b"));
image->battery_save(state->m_cart[1].m_nvram, state->m_cart[1].m_nvram_size);
}
}
/***************************************************************************
Cart handling
***************************************************************************/
/* This function assign a 'score' to data immediately after 'offset' to measure how valid they are
as information block (to decide if the image is HiRom, LoRom, ExLoRom or ExHiRom) */
/* Code from bsnes, courtesy of byuu - http://byuu.org/ , based on previous code by Cowering */
static int snes_validate_infoblock( UINT8 *infoblock, UINT32 offset )
{
int score = 0;
UINT16 reset_vector = infoblock[offset + 0x3c] | (infoblock[offset + 0x3d] << 8);
UINT16 checksum = infoblock[offset + 0x1e] | (infoblock[offset + 0x1f] << 8);
UINT16 ichecksum = infoblock[offset + 0x1c] | (infoblock[offset + 0x1d] << 8);
UINT8 reset_opcode = infoblock[(offset & ~0x7fff) | (reset_vector & 0x7fff)]; //first opcode executed upon reset
UINT8 mapper = infoblock[offset + 0x15] & ~0x10; //mask off irrelevant FastROM-capable bit
/* $00:[000-7fff] contains uninitialized RAM and MMIO.
reset vector must point to ROM at $00:[8000-ffff] to be considered valid. */
if (reset_vector < 0x8000)
return 0;
/* some images duplicate the header in multiple locations, and others have completely
invalid header information that cannot be relied upon. The code below will analyze
the first opcode executed at the specified reset vector to determine the probability
that this is the correct header. Score is assigned accordingly. */
/* most likely opcodes */
if (reset_opcode == 0x78 //sei
|| reset_opcode == 0x18 //clc (clc; xce)
|| reset_opcode == 0x38 //sec (sec; xce)
|| reset_opcode == 0x9c //stz $nnnn (stz $4200)
|| reset_opcode == 0x4c //jmp $nnnn
|| reset_opcode == 0x5c //jml $nnnnnn
)
score += 8;
/* plausible opcodes */
if (reset_opcode == 0xc2 //rep #$nn
|| reset_opcode == 0xe2 //sep #$nn
|| reset_opcode == 0xad //lda $nnnn
|| reset_opcode == 0xae //ldx $nnnn
|| reset_opcode == 0xac //ldy $nnnn
|| reset_opcode == 0xaf //lda $nnnnnn
|| reset_opcode == 0xa9 //lda #$nn
|| reset_opcode == 0xa2 //ldx #$nn
|| reset_opcode == 0xa0 //ldy #$nn
|| reset_opcode == 0x20 //jsr $nnnn
|| reset_opcode == 0x22 //jsl $nnnnnn
)
score += 4;
/* implausible opcodes */
if (reset_opcode == 0x40 //rti
|| reset_opcode == 0x60 //rts
|| reset_opcode == 0x6b //rtl
|| reset_opcode == 0xcd //cmp $nnnn
|| reset_opcode == 0xec //cpx $nnnn
|| reset_opcode == 0xcc //cpy $nnnn
)
score -= 4;
/* least likely opcodes */
if (reset_opcode == 0x00 //brk #$nn
|| reset_opcode == 0x02 //cop #$nn
|| reset_opcode == 0xdb //stp
|| reset_opcode == 0x42 //wdm
|| reset_opcode == 0xff //sbc $nnnnnn,x
)
score -= 8;
/* Sometimes, both the header and reset vector's first opcode will match ...
fallback and rely on info validity in these cases to determine more likely header. */
/* a valid checksum is the biggest indicator of a valid header. */
if ((checksum + ichecksum) == 0xffff && (checksum != 0) && (ichecksum != 0))
score += 4;
/* then there are the expected mapper values */
if (offset == 0x007fc0 && mapper == 0x20) // 0x20 is usually LoROM
score += 2;
if (offset == 0x00ffc0 && mapper == 0x21) // 0x21 is usually HiROM
score += 2;
if (offset == 0x007fc0 && mapper == 0x22) // 0x22 is usually ExLoROM
score += 2;
if (offset == 0x40ffc0 && mapper == 0x25) // 0x25 is usually ExHiROM
score += 2;
/* finally, there are valid values in the Company, Region etc. fields */
if (infoblock[offset + 0x1a] == 0x33) // Company field: 0x33 indicates extended header
score += 2;
if (infoblock[offset + 0x16] < 0x08) // ROM Type field
score++;
if (infoblock[offset + 0x17] < 0x10) // ROM Size field
score++;
if (infoblock[offset + 0x18] < 0x08) // SRAM Size field
score++;
if (infoblock[offset + 0x19] < 14) // Region field
score++;
/* do we still have a positive score? */
if (score < 0)
score = 0;
return score;
}
/* Here we add a couple of cart utilities, to avoid duplicating the code in each DEVICE_IMAGE_LOAD */
static UINT32 snes_skip_header( device_image_interface &image, UINT32 snes_rom_size )
{
UINT8 header[512];
UINT32 offset = 512;
/* Check for a header (512 bytes) */
if (image.software_entry() == NULL)
image.fread(header, 512);
else
memcpy(header, image.get_software_region("rom"), 512);
if ((header[8] == 0xaa) && (header[9] == 0xbb) && (header[10] == 0x04))
{
/* Found an SWC identifier */
logerror("Found header (SWC) - Skipped\n");
}
else if ((header[0] | (header[1] << 8)) == (((snes_rom_size - 512) / 1024) / 8))
{
/* Some headers have the rom size at the start, if this matches with the actual rom size, we probably have a header */
logerror("Found header (size) - Skipped\n");
}
else if ((snes_rom_size % 0x8000) == 512)
{
/* As a last check we'll see if there's exactly 512 bytes extra to this image. */
logerror("Found header (extra) - Skipped\n");
}
else
{
/* No header found so go back to the start of the file */
logerror("No header found.\n");
offset = 0;
}
return offset;
}
/* This determines if a cart is in Mode 20, 21, 22 or 25; sets state->m_cart[0].mode and
state->m_cart[0].sram_max accordingly; and returns the offset of the internal header
(needed to detect BSX and ST carts) */
static UINT32 snes_find_hilo_mode( running_machine &machine, UINT8 *buffer, UINT32 len, int cartid )
{
snes_state *state = machine.driver_data<snes_state>();
UINT8 valid_mode20, valid_mode21, valid_mode25;
UINT32 retvalue;
/* Now to determine if this is a lo-ROM, a hi-ROM or an extended lo/hi-ROM */
valid_mode20 = snes_validate_infoblock(buffer, 0x007fc0);
valid_mode21 = snes_validate_infoblock(buffer, 0x00ffc0);
valid_mode25 = (len > 0x40ffc0) ? snes_validate_infoblock(buffer, 0x40ffc0) : 0;
/* Images larger than 32mbits are likely ExHiRom */
if (valid_mode25)
valid_mode25 += 4;
if ((valid_mode20 >= valid_mode21) && (valid_mode20 >= valid_mode25))
{
if (buffer[0x007fd5] == 0x32 || len > 0x401000)
state->m_cart[cartid].mode = SNES_MODE_22; // ExLoRom
else
state->m_cart[cartid].mode = SNES_MODE_20; // LoRom
retvalue = 0x007fc0;
/* a few games require 512k, however we store twice as much to be sure to cover the various mirrors */
state->m_cart[cartid].sram_max = 0x100000;
}
else if (valid_mode21 >= valid_mode25)
{
state->m_cart[cartid].mode = SNES_MODE_21; // HiRom
retvalue = 0x00ffc0;
state->m_cart[cartid].sram_max = 0x20000;
}
else
{
state->m_cart[cartid].mode = SNES_MODE_25; // ExHiRom
retvalue = 0x40ffc0;
state->m_cart[cartid].sram_max = 0x20000;
}
logerror( "\t HiROM/LoROM id: %s (LoROM: %d , HiROM: %d, ExHiROM: %d)\n",
(state->m_cart[cartid].mode == SNES_MODE_20) ? "LoROM" :
(state->m_cart[cartid].mode == SNES_MODE_21) ? "HiROM" :
(state->m_cart[cartid].mode == SNES_MODE_22) ? "ExLoROM" :
(state->m_cart[cartid].mode == SNES_MODE_25) ? "ExHiROM" : "Other (BSX or ST)",
valid_mode20, valid_mode21, valid_mode25);
return retvalue;
}
static int snes_find_addon_chip( running_machine &machine, UINT8 *buffer, UINT32 start_offs )
{
snes_state *state = machine.driver_data<snes_state>();
int supported_type = 1;
int dsp_prg_offset = 0;
/* Info mostly taken from http://snesemu.black-ship.net/misc/-from%20nsrt.edgeemu.com-chipinfo.htm */
switch (buffer[start_offs + 0x16])
{
case 0x00:
case 0x01:
case 0x02:
state->m_has_addon_chip = HAS_NONE;
break;
case 0x03:
if (buffer[start_offs + 0x15] == 0x30)
{
state->m_has_addon_chip = HAS_DSP4;
dsp_prg_offset = SNES_DSP4_OFFSET;
}
else
{
state->m_has_addon_chip = HAS_DSP1;
dsp_prg_offset = SNES_DSP1B_OFFSET;
}
break;
case 0x04:
state->m_has_addon_chip = HAS_DSP1;
dsp_prg_offset = SNES_DSP1B_OFFSET;
break;
case 0x05:
if (buffer[start_offs + 0x15] == 0x20)
{
state->m_has_addon_chip = HAS_DSP2;
dsp_prg_offset = SNES_DSP2_OFFSET;
}
/* DSP-3 is hard to detect. We exploit the fact that the only game has been manufactured by Bandai */
else if ((buffer[start_offs + 0x15] == 0x30) && (buffer[start_offs + 0x1a] == 0xb2))
{
state->m_has_addon_chip = HAS_DSP3;
dsp_prg_offset = SNES_DSP3_OFFSET;
}
else
{
state->m_has_addon_chip = HAS_DSP1;
dsp_prg_offset = SNES_DSP1B_OFFSET;
}
break;
case 0x13: // Mario Chip 1
case 0x14: // GSU-x
case 0x15: // GSU-x
case 0x1a: // GSU-1 (21 MHz at start)
if (buffer[start_offs + 0x15] == 0x20)
state->m_has_addon_chip = HAS_SUPERFX;
break;
case 0x25:
state->m_has_addon_chip = HAS_OBC1;
break;
case 0x32: // needed by a Sample game (according to ZSNES)
case 0x34:
case 0x35:
if (buffer[start_offs + 0x15] == 0x23)
{
state->m_has_addon_chip = HAS_SA1;
supported_type = 0;
mame_printf_error("This is a SA-1 type game, currently unsupported by the driver\n");
}
break;
case 0x43:
case 0x45:
if (buffer[start_offs + 0x15] == 0x32)
{
state->m_has_addon_chip = HAS_SDD1;
}
break;
case 0x55:
if (buffer[start_offs + 0x15] == 0x35)
{
state->m_has_addon_chip = HAS_RTC;
}
break;
case 0xe3:
state->m_has_addon_chip = HAS_Z80GB;
supported_type = 0;
break;
case 0xf3:
state->m_has_addon_chip = HAS_CX4;
break;
case 0xf5:
if (buffer[start_offs + 0x15] == 0x30)
{
state->m_has_addon_chip = HAS_ST018;
supported_type = 0;
}
else if (buffer[start_offs + 0x15] == 0x3a)
{
state->m_has_addon_chip = HAS_SPC7110;
}
break;
case 0xf6:
/* These Seta ST-01X chips have both 0x30 at 0x00ffd5,
they only differ for the 'size' at 0x00ffd7 */
if (buffer[start_offs + 0x17] < 0x0a)
state->m_has_addon_chip = HAS_ST011;
else
state->m_has_addon_chip = HAS_ST010;
break;
case 0xf9:
if (buffer[start_offs + 0x15] == 0x3a)
{
state->m_has_addon_chip = HAS_SPC7110_RTC;
supported_type = 0;
}
break;
default:
state->m_has_addon_chip = HAS_UNK;
supported_type = 0;
break;
}
if ((state->m_has_addon_chip >= HAS_DSP1) && (state->m_has_addon_chip <= HAS_DSP4))
{
UINT8 *dspsrc = (UINT8 *)(*machine.root_device().memregion("addons"));
UINT32 *dspprg = (UINT32 *)(*machine.root_device().memregion("dspprg"));
UINT16 *dspdata = (UINT16 *)(*machine.root_device().memregion("dspdata"));
// copy DSP program
for (int i = 0; i < 0x2000; i+= 4)
{
*dspprg = dspsrc[dsp_prg_offset+0+i]<<24 | dspsrc[dsp_prg_offset+1+i]<<16 | dspsrc[dsp_prg_offset+2+i]<<8;
dspprg++;
}
// copy DSP data
for (int i = 0; i < 0x800; i+= 2)
{
*dspdata++ = dspsrc[dsp_prg_offset+0x2000+i]<<8 | dspsrc[dsp_prg_offset+0x2001+i];
}
}
if ((state->m_has_addon_chip == HAS_ST010) || (state->m_has_addon_chip == HAS_ST011))
{
UINT8 *dspsrc = (UINT8 *)(*machine.root_device().memregion("addons"));
UINT32 *dspprg = (UINT32 *)(*machine.root_device().memregion("dspprg"));
UINT16 *dspdata = (UINT16 *)(*machine.root_device().memregion("dspdata"));
// copy DSP program
for (int i = 0; i < 0x10000; i+= 4)
{
*dspprg = dspsrc[0+i]<<24 | dspsrc[1+i]<<16 | dspsrc[2+i]<<8;
dspprg++;
}
// copy DSP data
for (int i = 0; i < 0x1000; i+= 2)
{
*dspdata++ = dspsrc[0x10000+i]<<8 | dspsrc[0x10001+i];
}
}
return supported_type;
}
static void snes_cart_log_info( running_machine &machine, UINT8* ROM, UINT32 len, int supported )
{
snes_state *state = machine.driver_data<snes_state>();
char title[21], rom_id[4], company_id[2];
int i, company, has_ram = 0, has_sram = 0;
UINT32 hilo_mode = snes_find_hilo_mode(machine, ROM, len, 0);
/* Company */
for (i = 0; i < 2; i++)
company_id[i] = ROM[hilo_mode - 0x10 + i];
company = (char_to_int_conv(company_id[0]) << 4) + char_to_int_conv(company_id[1]);
if (company == 0)
company = ROM[hilo_mode + 0x1a];
/* ROM ID */
for (i = 0; i < 4; i++)
rom_id[i] = ROM[hilo_mode - 0x0e + i];
/* Title */
for (i = 0; i < 21; i++)
title[i] = ROM[hilo_mode + i];
/* RAM */
if (((ROM[hilo_mode + 0x16] & 0xf) == 1) ||
((ROM[hilo_mode + 0x16] & 0xf) == 2) ||
((ROM[hilo_mode + 0x16] & 0xf) == 4) ||
((ROM[hilo_mode + 0x16] & 0xf) == 5))
has_ram = 1;
/* SRAM */
if (((ROM[hilo_mode + 0x16] & 0xf) == 2) ||
((ROM[hilo_mode + 0x16] & 0xf) == 5) ||
((ROM[hilo_mode + 0x16] & 0xf) == 6))
has_sram = 1;
int total_blocks = len / (state->m_cart[0].mode & 0xa5 ? 0x8000 : 0x10000);
logerror( "ROM DETAILS\n" );
logerror( "===========\n\n" );
logerror( "\tTotal blocks: %d (%dmb)\n", total_blocks, total_blocks / (state->m_cart[0].mode & 5 ? 32 : 16) );
logerror( "\tROM bank size: %s \n",
(state->m_cart[0].mode == SNES_MODE_20) ? "LoROM" :
(state->m_cart[0].mode == SNES_MODE_21) ? "HiROM" :
(state->m_cart[0].mode == SNES_MODE_22) ? "ExLoROM" :
(state->m_cart[0].mode == SNES_MODE_25) ? "ExHiROM" : "Other (BSX or ST)" );
logerror( "\tCompany: %s [%.2s]\n", companies[company], company_id );
logerror( "\tROM ID: %.4s\n\n", rom_id );
logerror( "HEADER DETAILS\n" );
logerror( "==============\n\n" );
logerror( "\tName: %.21s\n", title );
logerror( "\tSpeed: %s [%d]\n", ((ROM[hilo_mode + 0x15] & 0xf0)) ? "FastROM" : "SlowROM", (ROM[hilo_mode + 0x15] & 0xf0) >> 4 );
logerror( "\tBank size: %s [%d]\n", (ROM[hilo_mode + 0x15] & 0xf) ? "HiROM" : "LoROM", ROM[hilo_mode + 0x15] & 0xf );
logerror( "\tType: %s", types[state->m_has_addon_chip]);
if (has_ram)
logerror( ", RAM");
if (has_sram)
logerror( ", SRAM");
logerror( " [%d]\n", ROM[hilo_mode + 0x16] );
logerror( "\tSize: %d megabits [%d]\n", 1 << (ROM[hilo_mode + 0x17] - 7), ROM[hilo_mode + 0x17] );
logerror( "\tSRAM: %d kilobits [%d]\n", state->m_cart[0].m_nvram_size * 8, ROM[hilo_mode + 0x18] );
logerror( "\tCountry: %s [%d]\n", countries[ROM[hilo_mode + 0x19]], ROM[hilo_mode + 0x19] );
logerror( "\tLicense: %s [%X]\n", companies[ROM[hilo_mode + 0x1a]], ROM[hilo_mode + 0x1a] );
logerror( "\tVersion: 1.%d\n", ROM[hilo_mode + 0x1b] );
logerror( "\tInv Checksum: %X %X\n", ROM[hilo_mode + 0x1d], ROM[hilo_mode + 0x1c] );
logerror( "\tChecksum: %X %X\n", ROM[hilo_mode + 0x1f], ROM[hilo_mode + 0x1e] );
logerror( "\tNMI Address: %2X%2Xh\n", ROM[hilo_mode + 0x3b], ROM[hilo_mode + 0x3a] );
logerror( "\tStart Address: %2X%2Xh\n\n", ROM[hilo_mode + 0x3d], ROM[hilo_mode + 0x3c] );
logerror( "\tMode: %d\n", state->m_cart[0].mode);
if (!supported)
logerror("WARNING: This cart type \"%s\" is not supported yet!\n", types[state->m_has_addon_chip]);
}
DEVICE_IMAGE_LOAD_MEMBER( snes_state,snes_cart )
{
int supported_type = 1;
int has_bsx_slot = 0, st_bios = 0;
UINT32 offset, int_header_offs;
if (image.software_entry() == NULL)
m_cart[0].m_rom_size = image.length();
else
m_cart[0].m_rom_size = image.get_software_region_length("rom");
// Check for a header (512 bytes), and skip it if found
offset = snes_skip_header(image, m_cart[0].m_rom_size);
m_cart[0].m_rom_size -= offset;
// Allocate rom pointer
m_cart[0].m_rom = auto_alloc_array_clear(machine(), UINT8, m_cart[0].m_rom_size);
if (image.software_entry() == NULL)
{
image.fseek(offset, SEEK_SET);
image.fread(m_cart[0].m_rom, m_cart[0].m_rom_size);
}
else
memcpy(m_cart[0].m_rom, image.get_software_region("rom") + offset, m_cart[0].m_rom_size);
if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", m_cart[0].m_rom_size);
// Setup the bank map to handle mirroring of ROM up to 8MB of accessible memory
rom_map_setup(m_cart[0].m_rom_size);
// Check if the cart is HiROM or LoROM (and set variables accordingly)
int_header_offs = snes_find_hilo_mode(machine(), m_cart[0].m_rom, m_cart[0].m_rom_size, 0);
// Detect BS-X carts:
// 1. Detect BS-X Flash Cart
if ((m_cart[0].m_rom[int_header_offs + 0x13] == 0x00 || m_cart[0].m_rom[int_header_offs + 0x13] == 0xff) &&
m_cart[0].m_rom[int_header_offs + 0x14] == 0x00)
{
UINT8 n15 = m_cart[0].m_rom[int_header_offs + 0x15];
if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc)
{
if (m_cart[0].m_rom[int_header_offs + 0x1a] == 0x33 || m_cart[0].m_rom[int_header_offs + 0x1a] == 0xff)
{
// BS-X Flash Cart
mame_printf_error("This is a game with BS-X slot: MESS does not support these yet, sorry.\n");
m_cart[0].mode = SNES_MODE_BSX;
}
}
}
// 2. Detect presence of BS-X flash cartridge connector
if ((m_cart[0].m_rom[int_header_offs - 14] == 'Z') && (m_cart[0].m_rom[int_header_offs - 11] == 'J'))
{
UINT8 n13 = m_cart[0].m_rom[int_header_offs - 13];
if ((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9'))
{
if (m_cart[0].m_rom[int_header_offs + 0x1a] == 0x33 ||
(m_cart[0].m_rom[int_header_offs - 10] == 0x00 && m_cart[0].m_rom[int_header_offs - 4] == 0x00))
{
has_bsx_slot = 1;
}
}
}
// If there is a BS-X connector, detect if it is the Base Cart or a compatible slotted cart
if (has_bsx_slot)
{
mame_printf_error("This is a game with BS-X slot: MESS does not support these yet, sorry.\n");
if (!memcmp(m_cart[0].m_rom + int_header_offs, "Satellaview BS-X ", 21))
{
//BS-X Base Cart
m_cart[0].mode = SNES_MODE_20; //SNES_MODE_BSX;
}
else
{
m_cart[0].mode = (int_header_offs == 0x007fc0) ? SNES_MODE_20 : SNES_MODE_21; //SNES_MODE_BSLO : SNES_MODE_BSHI;
}
}
/* Then, detect Sufami Turbo carts */
if (!memcmp(m_cart[0].m_rom, "BANDAI SFC-ADX", 14))
{
m_cart[0].mode = SNES_MODE_ST;
if (!memcmp(m_cart[0].m_rom + 16, "SFC-ADX BACKUP", 14))
st_bios = 1;
}
if (st_bios)
mame_printf_error("This is the Sufami Turbo base cart. MESS does not fully support this game in snes/snespal yet, sorry.\nYou might want to try the snesst driver.\n");
else if (m_cart[0].mode == SNES_MODE_ST)
{
mame_printf_error("This is a Sufami Turbo data cart and cannot be loaded for snes/snespal in MESS.\n");
mame_printf_error("Please use snesst driver to load it, instead.\n");
return IMAGE_INIT_FAIL;
}
if (SNES_CART_DEBUG) mame_printf_error("mode %d\n", m_cart[0].mode);
/* Detect special chips */
supported_type = snes_find_addon_chip(machine(), m_cart[0].m_rom, int_header_offs);
/* Find the amount of cart ram */
m_cart[0].m_nvram_size = 0;
if (image.software_entry() == NULL)
{
UINT32 nvram_size;
if ((m_has_addon_chip != HAS_SUPERFX))
nvram_size = m_cart[0].m_rom[int_header_offs + 0x18];
else
nvram_size = (m_cart[0].m_rom[0x007fbd] & 0x07);
if (nvram_size > 0)
{
nvram_size = (1024 << nvram_size);
if (nvram_size > m_cart[0].sram_max)
nvram_size = m_cart[0].sram_max;
m_cart[0].m_nvram_size = nvram_size;
}
// printf("size %x\n", m_cart[0].m_nvram_size);
}
else
{
// if we are loading from softlist, take memory length from the xml
m_cart[0].m_nvram_size = image.get_software_region("nvram") ? image.get_software_region_length("nvram") : 0;
if (m_cart[0].m_nvram_size > 0)
{
if (m_cart[0].m_nvram_size > m_cart[0].sram_max)
fatalerror("Found more memory than max allowed (found: %x, max: %x), check xml file!\n", m_cart[0].m_nvram_size, m_cart[0].sram_max);
}
// TODO: Eventually sram handlers should point to the allocated cart:sram region!
// For now, we only use the region as a placeholder to carry size info...
// printf("size %x\n", m_cart[0].m_nvram_size);
}
if (m_cart[0].m_nvram_size > 0)
m_cart[0].m_nvram = auto_alloc_array_clear(machine(), UINT8, m_cart[0].m_nvram_size);
/* Log snes_cart information */
snes_cart_log_info(machine(), m_cart[0].m_rom, m_cart[0].m_rom_size, supported_type);
/* Load SRAM */
if (m_cart[0].m_nvram_size > 0)
snes_load_sram(machine());
/* All done */
return IMAGE_INIT_PASS;
}
DEVICE_IMAGE_LOAD_MEMBER( snes_state,sufami_cart )
{
int st_bios = 0, slot_id = 0;
UINT32 offset;
if (strcmp(image.device().tag(), ":slot_a") == 0)
slot_id = 0;
if (strcmp(image.device().tag(), ":slot_b") == 0)
slot_id = 1;
if (image.software_entry() == NULL)
m_cart[slot_id].m_rom_size = image.length();
else
m_cart[slot_id].m_rom_size = image.get_software_region_length("rom");
// Check for a header (512 bytes), and skip it if found
offset = snes_skip_header(image, m_cart[slot_id].m_rom_size);
m_cart[slot_id].m_rom_size -= offset;
// Allocate rom pointer
m_cart[slot_id].m_rom = auto_alloc_array_clear(machine(), UINT8, m_cart[slot_id].m_rom_size);
if (image.software_entry() == NULL)
{
image.fseek(offset, SEEK_SET);
image.fread(m_cart[slot_id].m_rom, m_cart[slot_id].m_rom_size);
}
else
memcpy(m_cart[slot_id].m_rom, image.get_software_region("rom") + offset, m_cart[slot_id].m_rom_size);
if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", m_cart[slot_id].m_rom_size);
// Setup the bank map to handle mirroring of ROM
rom_map_setup(m_cart[slot_id].m_rom_size);
// Detect Sufami Turbo carts
if (!memcmp(m_cart[slot_id].m_rom, "BANDAI SFC-ADX", 14))
{
m_cart[slot_id].mode = SNES_MODE_ST;
if (!memcmp(m_cart[slot_id].m_rom + 16, "SFC-ADX BACKUP", 14))
st_bios = 1;
}
else
{
mame_printf_error("This is not a Sufami Turbo data pack.\n");
mame_printf_error("This image cannot be loaded in snesst (Use snes or snespal drivers, instead).\n");
return IMAGE_INIT_FAIL;
}
if (st_bios == 1)
{
mame_printf_error("This is the Sufami Turbo BIOS and not a Sufami Turbo data pack.\n");
mame_printf_error("This image cannot be loaded in snesst.\n");
return IMAGE_INIT_FAIL;
}
m_cart[slot_id].m_nvram_size = 0x20000;
m_cart[slot_id].m_nvram = auto_alloc_array_clear(machine(), UINT8, m_cart[slot_id].m_nvram_size);
sufami_load_sram(machine(), image.device().tag());
m_cart[slot_id].slot_in_use = 1; // acknowledge the cart in this slot
return IMAGE_INIT_PASS;
}
MACHINE_CONFIG_FRAGMENT( snes_cartslot )
MCFG_CARTSLOT_ADD("cart")
MCFG_CARTSLOT_EXTENSION_LIST("sfc,smc,fig,swc,bin")
MCFG_CARTSLOT_NOT_MANDATORY
MCFG_CARTSLOT_INTERFACE("snes_cart")
MCFG_CARTSLOT_LOAD(snes_state,snes_cart)
MCFG_SOFTWARE_LIST_ADD("cart_list","snes")
MCFG_SOFTWARE_LIST_FILTER("cart_list","NTSC")
MACHINE_CONFIG_END
MACHINE_CONFIG_FRAGMENT( snesp_cartslot )
MCFG_CARTSLOT_ADD("cart")
MCFG_CARTSLOT_EXTENSION_LIST("sfc,smc,fig,swc,bin")
MCFG_CARTSLOT_NOT_MANDATORY
MCFG_CARTSLOT_INTERFACE("snes_cart")
MCFG_CARTSLOT_LOAD(snes_state,snes_cart)
MCFG_SOFTWARE_LIST_ADD("cart_list","snes")
MCFG_SOFTWARE_LIST_FILTER("cart_list","PAL")
MACHINE_CONFIG_END
// This (hackily) emulates a SNES unit with a Sufami Turbo Unit cart inserted:
// hence, the user can mount two data cart in the two slots available on the ST Unit
MACHINE_CONFIG_FRAGMENT( sufami_cartslot )
MCFG_CARTSLOT_ADD("slot_a")
MCFG_CARTSLOT_EXTENSION_LIST("st,sfc")
MCFG_CARTSLOT_NOT_MANDATORY
MCFG_CARTSLOT_INTERFACE("sufami_cart")
MCFG_CARTSLOT_LOAD(snes_state,sufami_cart)
MCFG_CARTSLOT_ADD("slot_b")
MCFG_CARTSLOT_EXTENSION_LIST("st,sfc")
MCFG_CARTSLOT_NOT_MANDATORY
MCFG_CARTSLOT_INTERFACE("sufami_cart")
MCFG_CARTSLOT_LOAD(snes_state,sufami_cart)
// MCFG_SOFTWARE_LIST_ADD("cart_list","snes")
MACHINE_CONFIG_END
DRIVER_INIT_MEMBER(snes_state,snes_mess)
{
}
DRIVER_INIT_MEMBER(snes_state,snesst)
{
m_cart[0].slot_in_use = 0;
m_cart[1].slot_in_use = 0;
DRIVER_INIT_CALL(snes_mess);
}
// add-on chip emulators
#include "machine/snesobc1.c"
#include "machine/snescx4.c"
#include "machine/snesrtc.c"
#include "machine/snessdd1.c"
#include "machine/snes7110.c"

View File

@ -1,39 +0,0 @@
/*
snescart.h
*/
#ifndef _SNESCART_H
#define _SNESCART_H
void snes_machine_stop(running_machine &machine);
void sufami_machine_stop(running_machine &machine);
MACHINE_CONFIG_EXTERN( snes_cartslot );
MACHINE_CONFIG_EXTERN( snesp_cartslot );
MACHINE_CONFIG_EXTERN( sufami_cartslot );
// add-on chips IO
void srtc_write(running_machine &machine, UINT16 addr, UINT8 data);
UINT8 srtc_read(address_space &space, UINT16 addr);
void srtc_init(running_machine &machine);
extern DECLARE_READ8_HANDLER(obc1_read);
extern DECLARE_WRITE8_HANDLER(obc1_write);
void obc1_init(running_machine &machine);
UINT8 CX4_read(UINT32 addr);
void CX4_write(running_machine &machine, UINT32 addr, UINT8 data);
UINT8 sdd1_mmio_read(address_space &space, UINT32 addr);
void sdd1_mmio_write(address_space &space, UINT32 addr, UINT8 data);
void sdd1_init(running_machine& machine);
UINT8 sdd1_read(running_machine& machine, UINT32 addr);
UINT8 spc7110_mmio_read(address_space &space, UINT32 addr);
void spc7110_mmio_write(running_machine &machine, UINT32 addr, UINT8 data);
UINT8 spc7110_bank7_read(address_space &space, UINT32 offset);
void spc7110_init(running_machine& machine);
void spc7110rtc_init(running_machine& machine);
UINT8 spc7110_ram_read(UINT32 offset);
void spc7110_ram_write(UINT32 offset, UINT8 data);
#endif /* _SNESCART_H */

View File

@ -11,7 +11,7 @@
***************************************************************************/
#include "emu.h"
#include "snescx4.h"
#include "machine/snescx4.h"
static CX4 cx4;
@ -23,8 +23,8 @@ static void CX4_writew(running_machine &machine, UINT16 addr, UINT16 data);
static void CX4_C4DrawLine(INT32 X1, INT32 Y1, INT16 Z1, INT32 X2, INT32 Y2, INT16 Z2, UINT8 Color);
#include "cx4data.c"
#include "cx4fn.c"
#include "machine/cx4data.c"
#include "machine/cx4fn.c"
static UINT32 CX4_ldr(UINT8 r)
{
@ -113,8 +113,8 @@ static void CX4_transfer_data(running_machine &machine)
}
}
#include "cx4oam.c"
#include "cx4ops.c"
#include "machine/cx4oam.c"
#include "machine/cx4ops.c"
void CX4_write(running_machine &machine, UINT32 addr, UINT8 data)
{

View File

@ -22,3 +22,6 @@ struct CX4
double c4x, c4y, c4z;
double c4x2, c4y2, c4z2;
};
UINT8 CX4_read(UINT32 addr);
void CX4_write(running_machine &machine, UINT32 addr, UINT8 data);

View File

@ -1,119 +0,0 @@
/***************************************************************************
snesobc1.c
File to handle emulation of the SNES "OBC-1" add-on chip.
Original C++ code by byuu.
Byuu's code is released under GNU General Public License
version 2 as published by the Free Software Foundation.
The implementation below is released under the MAME license
for use in MAME, MESS and derivatives by permission of the author.
***************************************************************************/
struct snes_obc1_state
{
int address;
int offset;
int shift;
UINT8 ram[0x2000];
};
static snes_obc1_state obc1_state;
READ8_HANDLER( obc1_read )
{
UINT16 address = offset & 0x1fff;
UINT8 value;
switch (address)
{
case 0x1ff0:
value = obc1_state.ram[obc1_state.offset + (obc1_state.address << 2) + 0];
break;
case 0x1ff1:
value = obc1_state.ram[obc1_state.offset + (obc1_state.address << 2) + 1];
break;
case 0x1ff2:
value = obc1_state.ram[obc1_state.offset + (obc1_state.address << 2) + 2];
break;
case 0x1ff3:
value = obc1_state.ram[obc1_state.offset + (obc1_state.address << 2) + 3];
break;
case 0x1ff4:
value = obc1_state.ram[obc1_state.offset + (obc1_state.address >> 2) + 0x200];
break;
default:
value = obc1_state.ram[address];
break;
}
return value;
}
WRITE8_HANDLER( obc1_write )
{
UINT16 address = offset & 0x1fff;
UINT8 temp;
switch(address)
{
case 0x1ff0:
obc1_state.ram[obc1_state.offset + (obc1_state.address << 2) + 0] = data;
break;
case 0x1ff1:
obc1_state.ram[obc1_state.offset + (obc1_state.address << 2) + 1] = data;
break;
case 0x1ff2:
obc1_state.ram[obc1_state.offset + (obc1_state.address << 2) + 2] = data;
break;
case 0x1ff3:
obc1_state.ram[obc1_state.offset + (obc1_state.address << 2) + 3] = data;
break;
case 0x1ff4:
temp = obc1_state.ram[obc1_state.offset + (obc1_state.address >> 2) + 0x200];
temp = (temp & ~(3 << obc1_state.shift)) | ((data & 0x03) << obc1_state.shift);
obc1_state.ram[obc1_state.offset + (obc1_state.address >> 2) + 0x200] = temp;
break;
case 0x1ff5:
obc1_state.offset = (data & 0x01) ? 0x1800 : 0x1c00;
obc1_state.ram[address & 0x1fff] = data;
break;
case 0x1ff6:
obc1_state.address = data & 0x7f;
obc1_state.shift = (data & 0x03) << 1;
obc1_state.ram[address & 0x1fff] = data;
break;
default:
obc1_state.ram[address & 0x1fff] = data;
break;
}
}
void obc1_init( running_machine &machine )
{
memset(obc1_state.ram, 0x00, sizeof(obc1_state.ram));
obc1_state.offset = (obc1_state.ram[0x1ff5] & 0x01) ? 0x1800 : 0x1c00;
obc1_state.address = (obc1_state.ram[0x1ff6] & 0x7f);
obc1_state.shift = (obc1_state.ram[0x1ff6] & 0x03) << 1;
state_save_register_global(machine, obc1_state.offset);
state_save_register_global(machine, obc1_state.address);
state_save_register_global(machine, obc1_state.shift);
state_save_register_global_array(machine, obc1_state.ram);
}

View File

@ -1,222 +0,0 @@
/***************************************************************************
snesrtc.c
File to handle emulation of the SNES "S-RTC" add-on chip.
Based on C++ implementation by Byuu in BSNES.
Byuu's code is released under GNU General Public License
version 2 as published by the Free Software Foundation.
The implementation below is released under the MAME license
for use in MAME, MESS and derivatives by permission of the
author
***************************************************************************/
enum
{
RTCM_Ready,
RTCM_Command,
RTCM_Read,
RTCM_Write
};
struct snes_rtc_state
{
UINT8 ram[13];
INT32 mode;
INT8 index;
};
static snes_rtc_state rtc_state;
static const UINT8 srtc_months[12] =
{
31, 28, 31,
30, 31, 30,
31, 31, 30,
31, 30, 31
};
static void srtc_update_time( running_machine &machine )
{
system_time curtime, *systime = &curtime;
machine.current_datetime(curtime);
rtc_state.ram[0] = systime->local_time.second % 10;
rtc_state.ram[1] = systime->local_time.second / 10;
rtc_state.ram[2] = systime->local_time.minute % 10;
rtc_state.ram[3] = systime->local_time.minute / 10;
rtc_state.ram[4] = systime->local_time.hour % 10;
rtc_state.ram[5] = systime->local_time.hour / 10;
rtc_state.ram[6] = systime->local_time.mday % 10;
rtc_state.ram[7] = systime->local_time.mday / 10;
rtc_state.ram[8] = systime->local_time.month;
rtc_state.ram[9] = (systime->local_time.year - 1000) % 10;
rtc_state.ram[10] = ((systime->local_time.year - 1000) / 10) % 10;
rtc_state.ram[11] = (systime->local_time.year - 1000) / 100;
rtc_state.ram[12] = systime->local_time.weekday % 7;
}
// Returns day-of-week for specified date
// e.g. 0 = Sunday, 1 = Monday, ... 6 = Saturday
// Usage: weekday(2008, 1, 1) returns the weekday of January 1st, 2008
static UINT8 srtc_weekday( UINT32 year, UINT32 month, UINT32 day )
{
UINT32 y = 1900, m = 1; // Epoch is 1900-01-01
UINT32 sum = 0; // Number of days passed since epoch
year = MAX(1900, year);
month = MAX(1, MIN(12, month));
day = MAX(1, MIN(31, day));
while (y < year)
{
UINT8 leapyear = 0;
if ((y % 4) == 0)
{
leapyear = 1;
if ((y % 100) == 0 && (y % 400) != 0)
{
leapyear = 0;
}
}
sum += leapyear ? 366 : 365;
y++;
}
while (m < month)
{
UINT32 days = srtc_months[m - 1];
if (days == 28)
{
UINT8 leapyear = 0;
if ((y % 4) == 0)
{
leapyear = 1;
if ((y % 100) == 0 && (y % 400) != 0)
{
leapyear = 0;
}
}
days += leapyear ? 1 : 0;
}
sum += days;
m++;
}
sum += day - 1;
return (sum + 1) % 7; // 1900-01-01 was a Monday
}
UINT8 srtc_read( address_space &space, UINT16 addr )
{
addr &= 0xffff;
if (addr == 0x2800)
{
if (rtc_state.mode != RTCM_Read)
{
return 0x00;
}
if (rtc_state.index < 0)
{
srtc_update_time(space.machine());
rtc_state.index++;
return 0x0f;
}
else if (rtc_state.index > 12)
{
rtc_state.index = -1;
return 0x0f;
}
else
{
return rtc_state.ram[rtc_state.index++];
}
}
return snes_open_bus_r(space, 0);
}
void srtc_write( running_machine &machine, UINT16 addr, UINT8 data )
{
addr &= 0xffff;
if (addr == 0x2801)
{
data &= 0x0f; // Only the low four bits are used
if (data == 0x0d)
{
rtc_state.mode = RTCM_Read;
rtc_state.index = -1;
return;
}
if (data == 0x0e)
{
rtc_state.mode = RTCM_Command;
return;
}
if (data == 0x0f)
{
return; // Unknown behaviour
}
if (rtc_state.mode == RTCM_Write)
{
if (rtc_state.index >= 0 && rtc_state.index < 12)
{
rtc_state.ram[rtc_state.index++] = data;
if (rtc_state.index == 12)
{
// Day of week is automatically calculated and written
UINT32 day = rtc_state.ram[6] + rtc_state.ram[7] * 10;
UINT32 month = rtc_state.ram[8];
UINT32 year = rtc_state.ram[9] + rtc_state.ram[10] * 10 + rtc_state.ram[11] * 100;
year += 1000;
rtc_state.ram[rtc_state.index++] = srtc_weekday(year, month, day);
}
}
}
else if (rtc_state.mode == RTCM_Command)
{
if (data == 0)
{
rtc_state.mode = RTCM_Write;
rtc_state.index = 0;
}
else if (data == 4)
{
UINT8 i;
rtc_state.mode = RTCM_Ready;
rtc_state.index = -1;
for(i = 0; i < 13; i++)
{
rtc_state.ram[i] = 0;
}
}
else
{
// Unknown behaviour
rtc_state.mode = RTCM_Ready;
}
}
}
}
void srtc_init( running_machine &machine )
{
rtc_state.mode = RTCM_Read;
rtc_state.index = -1;
srtc_update_time(machine);
state_save_register_global_array(machine, rtc_state.ram);
state_save_register_global(machine, rtc_state.mode);
state_save_register_global(machine, rtc_state.index);
}

View File

@ -1,678 +0,0 @@
/***************************************************************************
snessdd1.c
File to handle emulation of the SNES "S-DD1" add-on chip.
Based on Andreas Naive Public Domain code.
***************************************************************************/
#define SSD1_ADD(addr)\
mmc[(addr >> 20) & 3] + (addr & 0x0fffff)
class SDD1_IM //Input Manager
{
public:
SDD1_IM() {}
UINT32 m_byte_ptr;
UINT8 m_bit_count;
void IM_prepareDecomp(UINT32 in_buf);
UINT8 IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len);
};
void SDD1_IM::IM_prepareDecomp(UINT32 in_buf)
{
m_byte_ptr = in_buf;
m_bit_count = 4;
}
UINT8 SDD1_IM::IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len)
{
UINT8 codeword = ROM[SSD1_ADD(m_byte_ptr)] << m_bit_count;
++m_bit_count;
if (codeword & 0x80)
{
codeword |= ROM[SSD1_ADD((m_byte_ptr + 1))] >> (9 - m_bit_count);
m_bit_count += code_len;
}
if (m_bit_count & 0x08)
{
m_byte_ptr++;
m_bit_count &= 0x07;
}
return codeword;
}
class SDD1_GCD //Golomb-Code Decoder
{
public:
SDD1_GCD(SDD1_IM* associatedIM)
: m_IM(associatedIM) { }
SDD1_IM* m_IM;
void GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind);
};
void SDD1_GCD::GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind)
{
const UINT8 run_count[] =
{
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
};
UINT8 codeword = m_IM->IM_getCodeword(ROM, mmc, code_num);
if (codeword & 0x80)
{
*LPSind = 1;
*MPScount = run_count[codeword >> (code_num ^ 0x07)];
}
else
{
*MPScount = (1 << code_num);
}
}
class SDD1_BG // Bits Generator
{
public:
SDD1_BG(SDD1_GCD* associatedGCD, UINT8 code)
: m_code_num(code),
m_GCD(associatedGCD) { }
UINT8 m_code_num;
UINT8 m_MPScount;
UINT8 m_LPSind;
SDD1_GCD* m_GCD;
void BG_prepareDecomp();
UINT8 BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun);
} ;
void SDD1_BG::BG_prepareDecomp()
{
m_MPScount = 0;
m_LPSind = 0;
}
UINT8 SDD1_BG::BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun)
{
UINT8 bit;
if (!(m_MPScount || m_LPSind))
{
m_GCD->GCD_getRunCount(ROM, mmc, m_code_num, &(m_MPScount), &(m_LPSind));
}
if (m_MPScount)
{
bit = 0;
m_MPScount--;
}
else
{
bit = 1;
m_LPSind = 0;
}
if (m_MPScount || m_LPSind)
{
(*endOfRun) = 0;
}
else
{
(*endOfRun) = 1;
}
return bit;
}
struct SDD1_PEM_state
{
UINT8 code_num;
UINT8 nextIfMPS;
UINT8 nextIfLPS;
};
static const SDD1_PEM_state PEM_evolution_table[33] =
{
{ 0,25,25},
{ 0, 2, 1},
{ 0, 3, 1},
{ 0, 4, 2},
{ 0, 5, 3},
{ 1, 6, 4},
{ 1, 7, 5},
{ 1, 8, 6},
{ 1, 9, 7},
{ 2,10, 8},
{ 2,11, 9},
{ 2,12,10},
{ 2,13,11},
{ 3,14,12},
{ 3,15,13},
{ 3,16,14},
{ 3,17,15},
{ 4,18,16},
{ 4,19,17},
{ 5,20,18},
{ 5,21,19},
{ 6,22,20},
{ 6,23,21},
{ 7,24,22},
{ 7,24,23},
{ 0,26, 1},
{ 1,27, 2},
{ 2,28, 4},
{ 3,29, 8},
{ 4,30,12},
{ 5,31,16},
{ 6,32,18},
{ 7,24,22}
};
struct SDD1_PEM_ContextInfo
{
UINT8 status;
UINT8 MPS;
};
class SDD1_PEM //Probability Estimation Module
{
public:
SDD1_PEM(
SDD1_BG* associatedBG0, SDD1_BG* associatedBG1,
SDD1_BG* associatedBG2, SDD1_BG* associatedBG3,
SDD1_BG* associatedBG4, SDD1_BG* associatedBG5,
SDD1_BG* associatedBG6, SDD1_BG* associatedBG7)
{
m_BG[0] = associatedBG0;
m_BG[1] = associatedBG1;
m_BG[2] = associatedBG2;
m_BG[3] = associatedBG3;
m_BG[4] = associatedBG4;
m_BG[5] = associatedBG5;
m_BG[6] = associatedBG6;
m_BG[7] = associatedBG7;
}
SDD1_PEM_ContextInfo m_contextInfo[32];
SDD1_BG* m_BG[8];
void PEM_prepareDecomp();
UINT8 PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context);
} ;
void SDD1_PEM::PEM_prepareDecomp()
{
for (int i = 0; i < 32; i++)
{
m_contextInfo[i].status = 0;
m_contextInfo[i].MPS = 0;
}
}
UINT8 SDD1_PEM::PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context)
{
UINT8 endOfRun;
UINT8 bit;
SDD1_PEM_ContextInfo *pContInfo = &(m_contextInfo)[context];
UINT8 currStatus = pContInfo->status;
const SDD1_PEM_state* pState = &(PEM_evolution_table[currStatus]);
UINT8 currentMPS = pContInfo->MPS;
bit = m_BG[pState->code_num]->BG_getBit(ROM, mmc, &endOfRun);
if (endOfRun)
{
if (bit)
{
if (!(currStatus & 0xfe))
{
(pContInfo->MPS) ^= 0x01;
}
pContInfo->status = pState->nextIfLPS;
}
else
{
pContInfo->status = pState->nextIfMPS;
}
}
return bit ^ currentMPS;
}
class SDD1_CM
{
public:
SDD1_CM(SDD1_PEM* associatedPEM)
: m_PEM(associatedPEM) { }
UINT8 m_bitplanesInfo;
UINT8 m_contextBitsInfo;
UINT8 m_bit_number;
UINT8 m_currBitplane;
UINT16 m_prevBitplaneBits[8];
SDD1_PEM* m_PEM;
void CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte);
UINT8 CM_getBit(UINT8 *ROM, UINT32 *mmc);
} ;
void SDD1_CM::CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte)
{
INT32 i = 0;
m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0;
m_contextBitsInfo = ROM[SSD1_ADD(first_byte)] & 0x30;
m_bit_number = 0;
for (i = 0; i < 8; i++)
{
m_prevBitplaneBits[i] = 0;
}
switch (m_bitplanesInfo)
{
case 0x00:
m_currBitplane = 1;
break;
case 0x40:
m_currBitplane = 7;
break;
case 0x80:
m_currBitplane = 3;
break;
}
}
UINT8 SDD1_CM::CM_getBit(UINT8 *ROM, UINT32 *mmc)
{
UINT8 currContext;
UINT16 *context_bits;
UINT8 bit = 0;
switch (m_bitplanesInfo)
{
case 0x00:
m_currBitplane ^= 0x01;
break;
case 0x40:
m_currBitplane ^= 0x01;
if (!(m_bit_number & 0x7f))
m_currBitplane = ((m_currBitplane + 2) & 0x07);
break;
case 0x80:
m_currBitplane ^= 0x01;
if (!(m_bit_number & 0x7f))
m_currBitplane ^= 0x02;
break;
case 0xc0:
m_currBitplane = m_bit_number & 0x07;
break;
}
context_bits = &(m_prevBitplaneBits)[m_currBitplane];
currContext = (m_currBitplane & 0x01) << 4;
switch (m_contextBitsInfo)
{
case 0x00:
currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001);
break;
case 0x10:
currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001);
break;
case 0x20:
currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001);
break;
case 0x30:
currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003);
break;
}
bit = m_PEM->PEM_getBit(ROM, mmc, currContext);
*context_bits <<= 1;
*context_bits |= bit;
m_bit_number++;
return bit;
}
class SDD1_OL
{
public:
SDD1_OL(SDD1_CM* associatedCM)
: m_CM(associatedCM) { }
UINT8 m_bitplanesInfo;
UINT16 m_length;
UINT8* m_buffer;
SDD1_CM* m_CM;
void OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf);
void OL_launch(UINT8 *ROM, UINT32 *mmc);
} ;
void SDD1_OL::OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf)
{
m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0;
m_length = out_len;
m_buffer = out_buf;
}
void SDD1_OL::OL_launch(UINT8 *ROM, UINT32 *mmc)
{
UINT8 i;
UINT8 register1 = 0, register2 = 0;
switch (m_bitplanesInfo)
{
case 0x00:
case 0x40:
case 0x80:
i = 1;
do
{ // if length == 0, we output 2^16 bytes
if (!i)
{
*(m_buffer++) = register2;
i = ~i;
}
else
{
for (register1 = register2 = 0, i = 0x80; i; i >>= 1)
{
if (m_CM->CM_getBit(ROM, mmc))
register1 |= i;
if (m_CM->CM_getBit(ROM, mmc))
register2 |= i;
}
*(m_buffer++) = register1;
}
} while (--(m_length));
break;
case 0xc0:
do
{
for (register1 = 0, i = 0x01; i; i <<= 1)
{
if (m_CM->CM_getBit(ROM, mmc))
{
register1 |= i;
}
}
*(m_buffer++) = register1;
} while (--(m_length));
break;
}
}
class SDD1emu
{
public:
SDD1emu(running_machine &machine);
running_machine &machine() const { return m_machine; }
SDD1_IM* m_IM;
SDD1_GCD* m_GCD;
SDD1_BG* m_BG0; SDD1_BG* m_BG1; SDD1_BG* m_BG2; SDD1_BG* m_BG3;
SDD1_BG* m_BG4; SDD1_BG* m_BG5; SDD1_BG* m_BG6; SDD1_BG* m_BG7;
SDD1_PEM* m_PEM;
SDD1_CM* m_CM;
SDD1_OL* m_OL;
void SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf);
private:
running_machine& m_machine;
};
SDD1emu::SDD1emu(running_machine &machine)
: m_machine(machine)
{
m_IM = auto_alloc(machine, SDD1_IM());
m_GCD = auto_alloc(machine, SDD1_GCD(m_IM));
m_BG0 = auto_alloc(machine, SDD1_BG(m_GCD, 0));
m_BG1 = auto_alloc(machine, SDD1_BG(m_GCD, 1));
m_BG2 = auto_alloc(machine, SDD1_BG(m_GCD, 2));
m_BG3 = auto_alloc(machine, SDD1_BG(m_GCD, 3));
m_BG4 = auto_alloc(machine, SDD1_BG(m_GCD, 4));
m_BG5 = auto_alloc(machine, SDD1_BG(m_GCD, 5));
m_BG6 = auto_alloc(machine, SDD1_BG(m_GCD, 6));
m_BG7 = auto_alloc(machine, SDD1_BG(m_GCD, 7));
m_PEM = auto_alloc(machine, SDD1_PEM(m_BG0, m_BG1, m_BG2, m_BG3,
m_BG4, m_BG5, m_BG6, m_BG7));
m_CM = auto_alloc(machine, SDD1_CM(m_PEM));
m_OL = auto_alloc(machine, SDD1_OL(m_CM));
}
void SDD1emu::SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf)
{
m_IM->IM_prepareDecomp(in_buf);
m_BG0->BG_prepareDecomp();
m_BG1->BG_prepareDecomp();
m_BG2->BG_prepareDecomp();
m_BG3->BG_prepareDecomp();
m_BG4->BG_prepareDecomp();
m_BG5->BG_prepareDecomp();
m_BG6->BG_prepareDecomp();
m_BG7->BG_prepareDecomp();
m_PEM->PEM_prepareDecomp();
m_CM->CM_prepareDecomp(ROM, mmc, in_buf);
m_OL->OL_prepareDecomp(ROM, mmc, in_buf, out_len, out_buf);
m_OL->OL_launch(ROM, mmc);
}
struct snes_sdd1_t
{
UINT8 sdd1_enable; // channel bit-mask
UINT8 xfer_enable; // channel bit-mask
UINT32 mmc[4]; // memory map controller ROM indices
struct
{
UINT32 addr; // $43x2-$43x4 -- DMA transfer address
UINT16 size; // $43x5-$43x6 -- DMA transfer size
} dma[8];
SDD1emu* sdd1emu;
struct
{
UINT8 *data; // pointer to decompressed S-DD1 data (65536 bytes)
UINT16 offset; // read index into S-DD1 decompression buffer
UINT32 size; // length of data buffer; reads decrement counter, set ready to false at 0
UINT8 ready; // 1 when data[] is valid; 0 to invoke sdd1emu.decompress()
} buffer;
} ;
static snes_sdd1_t snes_sdd1;
void sdd1_init(running_machine& machine)
{
snes_sdd1.sdd1_enable = 0x00;
snes_sdd1.xfer_enable = 0x00;
snes_sdd1.mmc[0] = 0 << 20;
snes_sdd1.mmc[1] = 1 << 20;
snes_sdd1.mmc[2] = 2 << 20;
snes_sdd1.mmc[3] = 3 << 20;
for (int i = 0; i < 8; i++)
{
snes_sdd1.dma[i].addr = 0;
snes_sdd1.dma[i].size = 0;
}
snes_sdd1.sdd1emu = auto_alloc(machine, SDD1emu(machine));
snes_sdd1.buffer.data = (UINT8*)auto_alloc_array(machine, UINT8, 0x10000);
snes_sdd1.buffer.ready = 0;
}
UINT8 sdd1_mmio_read(address_space &space, UINT32 addr)
{
addr &= 0xffff;
switch(addr)
{
case 0x4804:
return (snes_sdd1.mmc[0] >> 20) & 7;
case 0x4805:
return (snes_sdd1.mmc[1] >> 20) & 7;
case 0x4806:
return (snes_sdd1.mmc[2] >> 20) & 7;
case 0x4807:
return (snes_sdd1.mmc[3] >> 20) & 7;
}
return snes_open_bus_r(space, 0);
}
void sdd1_mmio_write(address_space &space, UINT32 addr, UINT8 data)
{
addr &= 0xffff;
if ((addr & 0x4380) == 0x4300)
{
UINT8 channel = (addr >> 4) & 7;
switch(addr & 15)
{
case 2:
snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0xffff00) + (data << 0);
break;
case 3:
snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0xff00ff) + (data << 8);
break;
case 4:
snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0x00ffff) + (data << 16);
break;
case 5:
snes_sdd1.dma[channel].size = (snes_sdd1.dma[channel].size & 0xff00) + (data << 0);
break;
case 6:
snes_sdd1.dma[channel].size = (snes_sdd1.dma[channel].size & 0x00ff) + (data << 8);
break;
}
return;
}
switch(addr)
{
case 0x4800:
snes_sdd1.sdd1_enable = data;
break;
case 0x4801:
snes_sdd1.xfer_enable = data;
break;
case 0x4804:
snes_sdd1.mmc[0] = (data & 7) << 20;
break;
case 0x4805:
snes_sdd1.mmc[1] = (data & 7) << 20;
break;
case 0x4806:
snes_sdd1.mmc[2] = (data & 7) << 20;
break;
case 0x4807:
snes_sdd1.mmc[3] = (data & 7) << 20;
break;
}
}
UINT8 sdd1_read(running_machine& machine, UINT32 addr)
{
snes_state *state = machine.driver_data<snes_state>();
UINT8 *ROM = state->m_cart[0].m_rom;
if (snes_sdd1.sdd1_enable & snes_sdd1.xfer_enable)
{
// at least one channel has S-DD1 decompression enabled...
for (int i = 0; i < 8; i++)
{
if (snes_sdd1.sdd1_enable & snes_sdd1.xfer_enable & (1 << i))
{
// S-DD1 always uses fixed transfer mode, so address will not change during transfer
if ((addr + 0xc00000) == snes_sdd1.dma[i].addr)
{
UINT8 data;
if (!snes_sdd1.buffer.ready)
{
UINT8 temp;
// first byte read for channel performs full decompression.
// this really should stream byte-by-byte, but it's not necessary since the size is known
snes_sdd1.buffer.offset = 0;
snes_sdd1.buffer.size = snes_sdd1.dma[i].size ? snes_sdd1.dma[i].size : 65536;
// sdd1emu calls this function; it needs to access uncompressed data;
// so temporarily disable decompression mode for decompress() call.
temp = snes_sdd1.sdd1_enable;
snes_sdd1.sdd1_enable = 0;
snes_sdd1.sdd1emu->SDD1emu_decompress(ROM, snes_sdd1.mmc, addr, snes_sdd1.buffer.size, snes_sdd1.buffer.data);
snes_sdd1.sdd1_enable = temp;
snes_sdd1.buffer.ready = 1;
}
// fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer
data = snes_sdd1.buffer.data[(UINT16)snes_sdd1.buffer.offset++];
if (snes_sdd1.buffer.offset >= snes_sdd1.buffer.size)
{
snes_sdd1.buffer.ready = 0;
snes_sdd1.xfer_enable &= ~(1 << i);
}
return data;
} // address matched
} // channel enabled
} // channel loop
} // S-DD1 decompressor enabled
return ROM[snes_sdd1.mmc[(addr >> 20) & 3] + (addr & 0x0fffff)];
}

View File

@ -21,6 +21,12 @@
subslots (e.g. BS-X compatible ones), that need to write to subslot (NV)RAM independently
to accesses to their own (NV)RAM.
In order to support legacy dumps of games with add-on NEC & Seta DSPs, CX4 and Seta ST018,
we use not only m_type to identify the correct slot device to be used (for this DSP1B, DSP2 and
DSP3 are the same), but also a m_addon variable that snes_add driver uses to load CPU dump from
the system BIOS (for this DSP1B, DSP2 and DSP3 are not the same).
***********************************************************************************************************/
@ -169,6 +175,7 @@ base_sns_cart_slot_device::base_sns_cart_slot_device(const machine_config &mconf
device_t(mconfig, type, name, tag, owner, clock),
device_image_interface(mconfig, *this),
device_slot_interface(mconfig, *this),
m_addon(ADDON_NONE),
m_type(SNES_MODE20)
{
}
@ -495,73 +502,78 @@ static int snes_find_addon_chip( UINT8 *buffer, UINT32 start_offs )
case 0x03:
if (buffer[start_offs + 0x15] == 0x30)
return SNES_DSP4;
return ADDON_DSP4;
else
return SNES_DSP;
return ADDON_DSP1;
case 0x04:
return SNES_DSP;
return ADDON_DSP1;
case 0x05:
// DSP2 can be detected by (buffer[start_offs + 0x15] == 0x20)
// DSP3 is harder to detect, and one has to rely on the manufacturer (Bandai)
// by checking (buffer[start_offs + 0x15] == 0x30) && (buffer[start_offs + 0x1a] == 0xb2)
// in other cases is DSP1, but we do treat all these together...
return SNES_DSP;
if (buffer[start_offs + 0x15] == 0x20)
return ADDON_DSP2;
else if ((buffer[start_offs + 0x15] == 0x30) && (buffer[start_offs + 0x1a] == 0xb2))
return ADDON_DSP3;
else
return ADDON_DSP1;
case 0x13: // Mario Chip 1
case 0x14: // GSU-x
case 0x15: // GSU-x
case 0x1a: // GSU-1 (21 MHz at start)
if (buffer[start_offs + 0x15] == 0x20)
return SNES_SFX;
return ADDON_SFX;
break;
case 0x25:
return SNES_OBC1;
return ADDON_OBC1;
case 0x32: // needed by a Sample game (according to ZSNES)
case 0x34:
case 0x35:
if (buffer[start_offs + 0x15] == 0x23)
return SNES_SA1;
return ADDON_SA1;
break;
case 0x43:
case 0x45:
if (buffer[start_offs + 0x15] == 0x32)
return SNES_SDD1;
return ADDON_SDD1;
break;
case 0x55:
if (buffer[start_offs + 0x15] == 0x35)
return SNES_SRTC;
return ADDON_SRTC;
break;
case 0xe3:
return SNES_Z80GB;
return ADDON_Z80GB;
case 0xf3:
return SNES_CX4;
return ADDON_CX4;
case 0xf5:
if (buffer[start_offs + 0x15] == 0x30)
return SNES_ST018;
return ADDON_ST018;
else if (buffer[start_offs + 0x15] == 0x3a)
return SNES_SPC7110;
return ADDON_SPC7110;
break;
case 0xf6:
/* These Seta ST-01X chips have both 0x30 at 0xffd5,
they only differ for the 'size' at 0xffd7 */
if (buffer[start_offs + 0x17] < 0x0a)
return SNES_ST011;
return ADDON_ST011;
else
return SNES_ST010;
return ADDON_ST010;
case 0xf9:
if (buffer[start_offs + 0x15] == 0x3a)
return SNES_SPC7110_RTC;
return ADDON_SPC7110_RTC;
break;
default:
@ -618,7 +630,7 @@ bool base_sns_cart_slot_device::call_load()
// get pcb type
if (software_entry() == NULL)
m_type = get_cart_type(ROM, len);
get_cart_type_addon(ROM, len, m_type, m_addon);
else
{
if ((slot_name = get_feature("slot")) == NULL)
@ -630,7 +642,8 @@ bool base_sns_cart_slot_device::call_load()
m_type = SNES_DSP_2MB;
}
setup_custom_mappers();
if (software_entry() == NULL)
setup_appended_addon();
setup_nvram();
@ -648,7 +661,7 @@ bool base_sns_cart_slot_device::call_load()
auto_free(machine(), temp_nvram);
}
printf("Type %d\n", m_type);
//printf("Type %d\n", m_type);
internal_header_logging(ROM, len);
@ -684,9 +697,91 @@ void base_sns_cart_slot_device::call_unload()
}
void base_sns_cart_slot_device::setup_custom_mappers()
void base_sns_cart_slot_device::setup_appended_addon()
{
// we have to eventually support pirate mappers here
// if we already have an add-on bios or if no addon has been detected, we have nothing to do
if (m_cart->get_addon_bios_size() || m_addon == ADDON_NONE)
return;
// check if the add-on dump is appended to the file
// if this is the case, copy it in m_bios and refresh
// the rom_bank_map with correct game rom size
switch (m_addon)
{
case ADDON_DSP1:
case ADDON_DSP1B:
case ADDON_DSP2:
case ADDON_DSP3:
case ADDON_DSP4:
// check for add-on dump
if ((m_cart->get_rom_size() & 0x7fff) == 0x2800)
{
logerror("Found NEC DSP dump at the bottom of the ROM.\n");
m_cart->addon_bios_alloc(machine(), 0x2800);
memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2800), 0x2800);
m_cart->rom_map_setup(m_cart->get_rom_size() - 0x2800);
}
// check for byuu's compressed version (swapped order of bytes and stripped fixed 0x00 bytes)
if ((m_cart->get_rom_size() & 0x7fff) == 0x2000)
{
logerror("Found NEC DSP dump (byuu's version) at the bottom of the ROM.\n");
m_cart->addon_bios_alloc(machine(), 0x2800);
for (int i = 0; i < 0x800; i++)
{
memcpy(m_cart->get_addon_bios_base() + i * 4 + 2, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2000) + i * 3 + 0, 1);
memcpy(m_cart->get_addon_bios_base() + i * 4 + 1, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2000) + i * 3 + 1, 1);
memcpy(m_cart->get_addon_bios_base() + i * 4 + 0, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2000) + i * 3 + 2, 1);
memset(m_cart->get_addon_bios_base() + i * 4 + 3, 0xff, 1);
}
memcpy(m_cart->get_addon_bios_base() + 0x2000, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x1800), 0x800);
m_cart->rom_map_setup(m_cart->get_rom_size() - 0x2000);
}
break;
case ADDON_ST010:
case ADDON_ST011:
// check for add-on dump
if ((m_cart->get_rom_size() & 0x3ffff) == 0x11000)
{
logerror("Found Seta DSP dump at the bottom of the ROM.\n");
m_cart->addon_bios_alloc(machine(), 0x11000);
memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x11000), 0x11000);
m_cart->rom_map_setup(m_cart->get_rom_size() - 0x11000);
}
// check for byuu's compressed version (swapped order of bytes and stripped fixed 0x00 bytes)
if ((m_cart->get_rom_size() & 0xffff) == 0xd000)
{
logerror("Found Seta DSP dump (byuu's version) at the bottom of the ROM.\n");
m_cart->addon_bios_alloc(machine(), 0x11000);
for (int i = 0; i < 0x4000; i++)
{
memcpy(m_cart->get_addon_bios_base() + i * 4 + 2, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xd000) + i * 3 + 0, 1);
memcpy(m_cart->get_addon_bios_base() + i * 4 + 1, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xd000) + i * 3 + 1, 1);
memcpy(m_cart->get_addon_bios_base() + i * 4 + 0, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xd000) + i * 3 + 2, 1);
memset(m_cart->get_addon_bios_base() + i * 4 + 3, 0xff, 1);
}
memcpy(m_cart->get_addon_bios_base() + 0x10000, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xc000), 0x1000);
m_cart->rom_map_setup(m_cart->get_rom_size() - 0xd000);
}
break;
case ADDON_CX4:
if ((m_cart->get_rom_size() & 0x7fff) == 0x0c00)
{
logerror("Found CX4 dump at the bottom of the ROM.\n");
m_cart->addon_bios_alloc(machine(), 0x0c00);
memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x0c00), 0x0c00);
m_cart->rom_map_setup(m_cart->get_rom_size() - 0x0c00);
}
break;
case ADDON_ST018:
if ((m_cart->get_rom_size() & 0x3ffff) == 0x28000)
{
logerror("Found ST018 dump at the bottom of the ROM.\n");
m_cart->addon_bios_alloc(machine(), 0x28000);
memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x28000), 0x28000);
m_cart->rom_map_setup(m_cart->get_rom_size() - 0x28000);
}
break;
}
}
void base_sns_cart_slot_device::setup_nvram()
@ -738,10 +833,8 @@ bool base_sns_cart_slot_device::call_softlist_load(char *swlist, char *swname, r
return TRUE;
}
int base_sns_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len)
void base_sns_cart_slot_device::get_cart_type_addon(UINT8 *ROM, UINT32 len, int &type, int &addon)
{
int type = 0;
// First, look if the cart is HiROM or LoROM (and set snes_cart accordingly)
int hilo_mode = snes_find_hilo_mode(ROM, len);
@ -784,64 +877,88 @@ int base_sns_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len)
// check for add-on chips...
if (len >= hilo_mode + 0x1a)
{
int addon = snes_find_addon_chip(ROM, hilo_mode);
addon = snes_find_addon_chip(ROM, hilo_mode);
if (addon != -1)
{
if (type == SNES_MODE20 && addon == SNES_DSP)
// m_type handles DSP1,2,3 in the same way, but snes_add requires them to be separate...
switch (addon)
{
if (len > 0x100000)
type = SNES_DSP_2MB;
else
type = SNES_DSP;
case ADDON_CX4:
type = SNES_CX4;
break;
case ADDON_DSP1:
case ADDON_DSP1B:
case ADDON_DSP2:
case ADDON_DSP3:
if (type == SNES_MODE20 && len > 0x100000)
type = SNES_DSP_2MB;
else if (type == SNES_MODE21)
type = SNES_DSP_MODE21;
else
type = SNES_DSP;
break;
case ADDON_DSP4:
type = SNES_DSP4;
break;
case ADDON_OBC1:
type = SNES_OBC1;
break;
case ADDON_SA1:
type = SNES_SA1;
break;
case ADDON_SDD1:
type = SNES_SDD1;
break;
case ADDON_SFX:
type = SNES_SFX;
break;
case ADDON_SPC7110:
type = SNES_SPC7110;
break;
case ADDON_SPC7110_RTC:
type = SNES_SPC7110_RTC;
break;
case ADDON_ST010:
type = SNES_ST010;
break;
case ADDON_ST011:
type = SNES_ST011;
break;
case ADDON_ST018:
type = SNES_ST018;
break;
case ADDON_SRTC:
type = SNES_SRTC;
break;
case ADDON_Z80GB:
type = SNES_Z80GB;
break;
}
else if (type == SNES_MODE21 && addon == SNES_DSP)
type = SNES_DSP_MODE21;
else
type = addon;
}
}
// ...and turn them off if we are loading from fullpath a game which requires an add-on bios
switch (type)
{
case SNES_DSP:
case SNES_DSP_2MB:
case SNES_DSP4:
case SNES_ST010:
case SNES_ST011:
case SNES_ST018:
// case SNES_CX4:
printf("This type of cart requires the dump of on-cart CPU. You need to load it from softlist!\n");
type = SNES_MODE20;
break;
case SNES_DSP_MODE21:
printf("This type of cart requires the dump of on-cart CPU. You need to load it from softlist!\n");
type = SNES_MODE21;
break;
}
return type;
}
/*-------------------------------------------------
get default card software
-------------------------------------------------*/
const char * base_sns_cart_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
{
const char *slot_string = "lorom";
bool fullpath = open_image_file(options);
if (fullpath)
{
const char *slot_string = "lorom";
UINT32 offset = 0;
UINT32 len = core_fsize(m_file);
UINT8 *ROM = global_alloc_array(UINT8, len);
int type;
int type = 0, addon = 0;
core_fread(m_file, ROM, len);
offset = snes_skip_header(ROM, len);
type = get_cart_type(ROM + offset, len - offset);
get_cart_type_addon(ROM + offset, len - offset, type, addon);
slot_string = sns_get_slot(type);
global_free(ROM);
@ -854,7 +971,6 @@ const char * base_sns_cart_slot_device::get_default_card_software(const machine_
}
/*-------------------------------------------------
read
-------------------------------------------------*/
@ -920,6 +1036,17 @@ WRITE8_MEMBER(base_sns_cart_slot_device::chip_write)
}
/*-------------------------------------------------
snes_stop_addon_cpu
-------------------------------------------------*/
void base_sns_cart_slot_device::snes_stop_addon_cpu(const char *cputag)
{
astring cpu(m_cart->device().tag(), ":", cputag);
if (m_cart && machine().device(cpu))
machine().device(cpu.cstr())->execute().set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
}
/*-------------------------------------------------
Internal header logging
-------------------------------------------------*/

View File

@ -5,6 +5,18 @@
TYPE DEFINITIONS
***************************************************************************/
// offset of add-on dumps inside snes_add/snesp_add bios, to support old dumps missing add-on data
#define SNES_DSP1_OFFSET (0x00000)
#define SNES_DSP1B_OFFSET (0x03000)
#define SNES_DSP2_OFFSET (0x06000)
#define SNES_DSP3_OFFSET (0x09000)
#define SNES_DSP4_OFFSET (0x0c000)
#define SNES_ST10_OFFSET (0x0f000)
#define SNES_ST11_OFFSET (0x20000)
#define SNES_CX4_OFFSET (0x31000)
#define SNES_ST18_OFFSET1 (0x32000)
#define SNES_ST18_OFFSET2 (0x52000)
/* PCB */
enum
@ -46,6 +58,28 @@ enum
SNES_BUGS // wip
};
/* add-ons to handle legacy dumps in snes_add */
enum
{
ADDON_NONE = 0,
ADDON_CX4,
ADDON_DSP1,
ADDON_DSP1B,
ADDON_DSP2,
ADDON_DSP3,
ADDON_DSP4,
ADDON_OBC1,
ADDON_SA1,
ADDON_SDD1,
ADDON_SFX,
ADDON_SPC7110,
ADDON_SPC7110_RTC,
ADDON_ST010,
ADDON_ST011,
ADDON_ST018,
ADDON_SRTC,
ADDON_Z80GB
};
// ======================> sns_cart_interface
@ -123,11 +157,11 @@ public:
virtual void call_unload();
virtual bool call_softlist_load(char *swlist, char *swname, rom_entry *start_entry);
int get_cart_type(UINT8 *ROM, UINT32 len);
void get_cart_type_addon(UINT8 *ROM, UINT32 len, int &type, int &addon);
UINT32 snes_skip_header(UINT8 *ROM, UINT32 snes_rom_size);
int get_type() { return m_type; }
int get_addon() { return m_addon; }
void setup_custom_mappers();
void setup_nvram();
void internal_header_logging(UINT8 *ROM, UINT32 len);
@ -152,10 +186,22 @@ public:
virtual DECLARE_READ8_MEMBER(chip_read);
virtual DECLARE_WRITE8_MEMBER(chip_write);
// in order to support legacy dumps, we enable add-on CPUs even when loading from fullpath
// and then we stop them at MACHINE_RESET to avoid crashes
void snes_stop_addon_cpu(const char *cputag);
// in order to support legacy dumps + add-on CPU dump appended at the end of the file, we
// check if the required data is present and update bank map accordingly
void setup_appended_addon();
// m_cart cannot be made private yet, because we need to check nvram_size from the driver...
// more work needed
//private:
// this is used to support legacy DSPx/ST0xx/CX4 dumps not including the CPU data...
// i.e. it's only used for snes_add/snesp_add
int m_addon;
int m_type;
device_sns_cart_interface* m_cart;
};

View File

@ -68,17 +68,10 @@ gbpocket // Nintendo Game Boy Pocket Handheld
gblight // Nintendo Game Boy Light Handheld
gbcolor // Nintendo Game Boy Color Handheld
gba // Nintendo Game Boy Advance Handheld
snesnew // Nintendo Super Nintendo NTSC (test driver with slots)
snespnew // Nintendo Super Nintendo PAL (test driver with slots)
snes // Nintendo Super Nintendo NTSC
snespal // Nintendo Super Nintendo PAL
snessfx // Nintendo Super Nintendo NTSC w/SuperFX CPU
snespsfx // Nintendo Super Nintendo PAL w/SuperFX CPU
snesdsp // Nintendo Super Nintendo NTSC w/DSP-x CPU
snespdsp // Nintendo Super Nintendo PAL w/DSP-x CPU
snesst10 // Nintendo Super Nintendo NTSC w/ST-010 CPU
snesst11 // Nintendo Super Nintendo NTSC w/ST-011 CPU
snesst // Nintendo Super Nintendo NTSC w/Sufami Turbo base cart
snes_add // Nintendo Super Nintendo NTSC w/add-on CPUs as BIOS (legacy driver to run old dumps)
snesp_add // Nintendo Super Nintendo PAL w/add-on CPUs as BIOS (legacy driver to run old dumps)
n64 // Nintendo N64
n64dd // Nintendo N64 (64DD Attachment)
pokemini // Nintendo Pokemon Mini

View File

@ -1401,7 +1401,7 @@ $(MESSOBJ)/nintendo.a: \
$(MESS_VIDEO)/nes.o \
$(MESS_MACHINE)/nes.o \
$(MESS_DRIVERS)/nes.o \
$(MESS_MACHINE)/snescart.o \
$(MESS_MACHINE)/snescx4.o \
$(MESS_MACHINE)/sns_slot.o \
$(MESS_MACHINE)/sns_rom.o \
$(MESS_MACHINE)/sns_rom21.o \
@ -2116,15 +2116,10 @@ $(MESSOBJ)/skeleton.a: \
# miscellaneous dependencies
#-------------------------------------------------
$(MESS_MACHINE)/snescart.o: $(MESSSRC)/machine/snesobc1.c \
$(MESSSRC)/machine/snescx4.c \
$(MESSSRC)/machine/cx4ops.c \
$(MESS_MACHINE)/snescx4.o: $(MESSSRC)/machine/cx4ops.c \
$(MESSSRC)/machine/cx4oam.c \
$(MESSSRC)/machine/cx4fn.c \
$(MESSSRC)/machine/cx4data.c \
$(MESSSRC)/machine/snesrtc.c \
$(MESSSRC)/machine/snessdd1.c \
$(MESSSRC)/machine/snes7110.c \
$(MESS_VIDEO)/gba.o: $(MESSSRC)/video/gbamode0.c \
$(MESSSRC)/video/gbamode1.c \