Fixes loading of good ROM dumps where previously only their overdumps would load (Tower Toppler, Realsports Baseball, Water Ski, etc)
405 lines
13 KiB
C++
Executable File
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;
|
|
}
|
|
}
|