Files
ProSystem-Core/core/Cartridge.cpp
T
clobber 99a2f187bd Patch from Joseph Zatarski to correctly load supergame cart types.
Fixes loading of good ROM dumps where previously only their overdumps would load (Tower Toppler, Realsports Baseball, Water Ski, etc)
2014-07-18 17:09:47 -05:00

405 lines
13 KiB
C++
Executable File

// ----------------------------------------------------------------------------
// ___ ___ ___ ___ ___ ____ ___ _ _
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
//
// ----------------------------------------------------------------------------
// Copyright 2005 Greg Stanton
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// Cartridge.cpp
// ----------------------------------------------------------------------------
#include "Cartridge.h"
#define CARTRIDGE_SOURCE "Cartridge.cpp"
std::string cartridge_title;
std::string cartridge_description;
std::string cartridge_year;
std::string cartridge_maker;
std::string cartridge_digest;
std::string cartridge_filename;
byte cartridge_type;
byte cartridge_region;
bool cartridge_pokey;
byte cartridge_controller[2];
byte cartridge_bank;
uint cartridge_flags;
static byte* cartridge_buffer = NULL;
static uint cartridge_size = 0;
// ----------------------------------------------------------------------------
// HasHeader
// ----------------------------------------------------------------------------
static bool cartridge_HasHeader(const byte* header) {
const char HEADER_ID[ ] = {"ATARI7800"};
for(int index = 0; index < 9; index++) {
if(HEADER_ID[index] != header[index + 1]) {
return false;
}
}
return true;
}
// ----------------------------------------------------------------------------
// Header for CC2 hack
// ----------------------------------------------------------------------------
static bool cartridge_CC2(const byte* header) {
const char HEADER_ID[ ] = {">>"};
for(int index = 0; index < 2; index++) {
if(HEADER_ID[index] != header[index+1]) {
return false;
}
}
return true;
}
// ----------------------------------------------------------------------------
// GetBankOffset
// ----------------------------------------------------------------------------
static uint cartridge_GetBankOffset(byte bank) {
if ((cartridge_type == CARTRIDGE_TYPE_SUPERCART || cartridge_type == CARTRIDGE_TYPE_SUPERCART_ROM || cartridge_type == CARTRIDGE_TYPE_SUPERCART_RAM) && cartridge_size <= 65536) {
// for some of these carts, there are only 4 banks. in this case we ignore bit 3
// previously, games of this type had to be doubled. The first 4 banks needed to be duplicated at the end of the ROM
return (bank & 3) * 16384;
}
return bank * 16384;
}
// ----------------------------------------------------------------------------
// WriteBank
// ----------------------------------------------------------------------------
static void cartridge_WriteBank(word address, byte bank) {
uint offset = cartridge_GetBankOffset(bank);
if(offset < cartridge_size) {
memory_WriteROM(address, 16384, cartridge_buffer + offset);
cartridge_bank = bank;
}
}
// ----------------------------------------------------------------------------
// ReadHeader
// ----------------------------------------------------------------------------
static void cartridge_ReadHeader(const byte* header) {
char temp[33] = {0};
for(int index = 0; index < 32; index++) {
temp[index] = header[index + 17];
}
cartridge_title = temp;
cartridge_size = header[49] << 32;
cartridge_size |= header[50] << 16;
cartridge_size |= header[51] << 8;
cartridge_size |= header[52];
if(header[53] == 0) {
if(cartridge_size > 131072) {
cartridge_type = CARTRIDGE_TYPE_SUPERCART_LARGE;
}
else if(header[54] == 2 || header[54] == 3) {
cartridge_type = CARTRIDGE_TYPE_SUPERCART;
}
else if(header[54] == 4 || header[54] == 5 || header[54] == 6 || header[54] == 7) {
cartridge_type = CARTRIDGE_TYPE_SUPERCART_RAM;
}
else if(header[54] == 8 || header[54] == 9 || header[54] == 10 || header[54] == 11) {
cartridge_type = CARTRIDGE_TYPE_SUPERCART_ROM;
}
else {
cartridge_type = CARTRIDGE_TYPE_NORMAL;
}
}
else {
if(header[53] == 1) {
cartridge_type = CARTRIDGE_TYPE_ABSOLUTE;
}
else if(header[53] == 2) {
cartridge_type = CARTRIDGE_TYPE_ACTIVISION;
}
else {
cartridge_type = CARTRIDGE_TYPE_NORMAL;
}
}
//cartridge_pokey = (header[54] & 1)? true: false;
cartridge_pokey = true;
cartridge_controller[0] = header[55];
cartridge_controller[1] = header[56];
cartridge_region = header[57];
cartridge_flags = 0;
}
// ----------------------------------------------------------------------------
// Load
// ----------------------------------------------------------------------------
static bool cartridge_Load(const byte* data, uint size) {
if(size <= 128) {
logger_LogError("Cartridge data is invalid.", CARTRIDGE_SOURCE);
return false;
}
cartridge_Release( );
byte header[128] = {0};
for(int index = 0; index < 128; index++) {
header[index] = data[index];
}
if (cartridge_CC2(header)) {
logger_LogError("Prosystem doesn't support CC2 hacks.", CARTRIDGE_SOURCE);
return false;
}
uint offset = 0;
if(cartridge_HasHeader(header)) {
cartridge_ReadHeader(header);
size -= 128;
offset = 128;
cartridge_size = size;
}
else {
cartridge_size = size;
}
cartridge_buffer = new byte[cartridge_size];
for(int index = 0; index < cartridge_size; index++) {
cartridge_buffer[index] = data[index + offset];
}
cartridge_digest = hash_Compute(cartridge_buffer, cartridge_size);
return true;
}
// ----------------------------------------------------------------------------
// Load
// ----------------------------------------------------------------------------
bool cartridge_Load(std::string filename) {
if(filename.empty( ) || filename.length( ) == 0) {
logger_LogError("Cartridge filename is invalid.", CARTRIDGE_SOURCE);
return false;
}
cartridge_Release( );
logger_LogInfo("Opening cartridge file " + filename + ".", CARTRIDGE_SOURCE);
byte* data = NULL;
//uint size = archive_GetUncompressedFileSize(filename);
uint size = 0;
if(size == 0) {
FILE *file = fopen(filename.c_str( ), "rb");
if(file == NULL) {
logger_LogError("Failed to open the cartridge file " + filename + " for reading.", CARTRIDGE_SOURCE);
return false;
}
if(fseek(file, 0, SEEK_END)) {
fclose(file);
logger_LogError("Failed to find the end of the cartridge file.", CARTRIDGE_SOURCE);
return false;
}
size = ftell(file);
if(fseek(file, 0, SEEK_SET)) {
fclose(file);
logger_LogError("Failed to find the size of the cartridge file.", CARTRIDGE_SOURCE);
return false;
}
data = new byte[size];
if(fread(data, 1, size, file) != size && ferror(file)) {
fclose(file);
logger_LogError("Failed to read the cartridge data.", CARTRIDGE_SOURCE);
cartridge_Release( );
delete [ ] data;
return false;
}
fclose(file);
}
else {
data = new byte[size];
//archive_Uncompress(filename, data, size);
}
if(!cartridge_Load(data, size)) {
logger_LogError("Failed to load the cartridge data into memory.", CARTRIDGE_SOURCE);
delete [ ] data;
return false;
}
if(data != NULL) {
delete [ ] data;
}
cartridge_filename = filename;
return true;
}
// ----------------------------------------------------------------------------
// Store
// ----------------------------------------------------------------------------
void cartridge_Store( ) {
switch(cartridge_type) {
case CARTRIDGE_TYPE_NORMAL:
memory_WriteROM(65536 - cartridge_size, cartridge_size, cartridge_buffer);
break;
case CARTRIDGE_TYPE_SUPERCART:
if(cartridge_GetBankOffset(7) < cartridge_size) {
memory_WriteROM(49152, 16384, cartridge_buffer + cartridge_GetBankOffset(7));
}
break;
case CARTRIDGE_TYPE_SUPERCART_LARGE:
if(cartridge_GetBankOffset(8) < cartridge_size) {
memory_WriteROM(49152, 16384, cartridge_buffer + cartridge_GetBankOffset(8));
memory_WriteROM(16384, 16384, cartridge_buffer + cartridge_GetBankOffset(0));
}
break;
case CARTRIDGE_TYPE_SUPERCART_RAM:
if(cartridge_GetBankOffset(7) < cartridge_size) {
memory_WriteROM(49152, 16384, cartridge_buffer + cartridge_GetBankOffset(7));
memory_ClearROM(16384, 16384);
}
break;
case CARTRIDGE_TYPE_SUPERCART_ROM:
if(cartridge_GetBankOffset(7) < cartridge_size && cartridge_GetBankOffset(6) < cartridge_size) {
memory_WriteROM(49152, 16384, cartridge_buffer + cartridge_GetBankOffset(7));
memory_WriteROM(16384, 16384, cartridge_buffer + cartridge_GetBankOffset(6));
}
break;
case CARTRIDGE_TYPE_ABSOLUTE:
memory_WriteROM(16384, 16384, cartridge_buffer);
memory_WriteROM(32768, 32768, cartridge_buffer + cartridge_GetBankOffset(2));
break;
case CARTRIDGE_TYPE_ACTIVISION:
if(122880 < cartridge_size) {
memory_WriteROM(40960, 16384, cartridge_buffer);
memory_WriteROM(16384, 8192, cartridge_buffer + 106496);
memory_WriteROM(24576, 8192, cartridge_buffer + 98304);
memory_WriteROM(32768, 8192, cartridge_buffer + 122880);
memory_WriteROM(57344, 8192, cartridge_buffer + 114688);
}
break;
}
}
// ----------------------------------------------------------------------------
// Write
// ----------------------------------------------------------------------------
void cartridge_Write(word address, byte data) {
switch(cartridge_type) {
case CARTRIDGE_TYPE_SUPERCART:
case CARTRIDGE_TYPE_SUPERCART_RAM:
case CARTRIDGE_TYPE_SUPERCART_ROM:
if(address >= 32768 && address < 49152 && data < 9) {
cartridge_StoreBank(data);
}
break;
case CARTRIDGE_TYPE_SUPERCART_LARGE:
if(address >= 32768 && address < 49152 && data < 9) {
cartridge_StoreBank(data + 1);
}
break;
case CARTRIDGE_TYPE_ABSOLUTE:
if(address == 32768 && (data == 1 || data == 2)) {
cartridge_StoreBank(data - 1);
}
break;
case CARTRIDGE_TYPE_ACTIVISION:
if(address >= 65408) {
cartridge_StoreBank(address & 7);
}
break;
}
//if(cartridge_pokey && address >= 0x4000 && address < 0x4009) {
if(address >= 0x4000 && address < 0x4009) {
switch(address) {
case POKEY_AUDF1:
pokey_SetRegister(POKEY_AUDF1, data);
break;
case POKEY_AUDC1:
pokey_SetRegister(POKEY_AUDC1, data);
break;
case POKEY_AUDF2:
pokey_SetRegister(POKEY_AUDF2, data);
break;
case POKEY_AUDC2:
pokey_SetRegister(POKEY_AUDC2, data);
break;
case POKEY_AUDF3:
pokey_SetRegister(POKEY_AUDF3, data);
break;
case POKEY_AUDC3:
pokey_SetRegister(POKEY_AUDC3, data);
break;
case POKEY_AUDF4:
pokey_SetRegister(POKEY_AUDF4, data);
break;
case POKEY_AUDC4:
pokey_SetRegister(POKEY_AUDC4, data);
break;
case POKEY_AUDCTL:
pokey_SetRegister(POKEY_AUDCTL, data);
break;
}
}
}
// ----------------------------------------------------------------------------
// StoreBank
// ----------------------------------------------------------------------------
void cartridge_StoreBank(byte bank) {
switch(cartridge_type) {
case CARTRIDGE_TYPE_SUPERCART:
cartridge_WriteBank(32768, bank);
break;
case CARTRIDGE_TYPE_SUPERCART_RAM:
cartridge_WriteBank(32768, bank);
break;
case CARTRIDGE_TYPE_SUPERCART_ROM:
cartridge_WriteBank(32768, bank);
break;
case CARTRIDGE_TYPE_SUPERCART_LARGE:
cartridge_WriteBank(32768, bank);
break;
case CARTRIDGE_TYPE_ABSOLUTE:
cartridge_WriteBank(16384, bank);
break;
case CARTRIDGE_TYPE_ACTIVISION:
cartridge_WriteBank(40960, bank);
break;
}
}
// ----------------------------------------------------------------------------
// IsLoaded
// ----------------------------------------------------------------------------
bool cartridge_IsLoaded( ) {
return (cartridge_buffer != NULL)? true: false;
}
// ----------------------------------------------------------------------------
// Release
// ----------------------------------------------------------------------------
void cartridge_Release( ) {
if(cartridge_buffer != NULL) {
delete [ ] cartridge_buffer;
cartridge_size = 0;
cartridge_buffer = NULL;
}
}