naomi: use boot rom id to configure eeprom
Make eeprom from scratch if it doesn't exist based on boot id info. Override eeprom settings to make game happy Change region to supported one Get rid of per-rom region info in rom list New option to configure Naomi games in free play
This commit is contained in:
parent
a92c2899c8
commit
ecc03e3ebc
|
@ -36,6 +36,7 @@ Option<bool> ForceWindowsCE("Dreamcast.ForceWindowsCE");
|
|||
Option<bool> AutoLoadState("Dreamcast.AutoLoadState");
|
||||
Option<bool> AutoSaveState("Dreamcast.AutoSaveState");
|
||||
Option<int> SavestateSlot("Dreamcast.SavestateSlot");
|
||||
Option<bool> ForceFreePlay("ForceFreePlay", true);
|
||||
|
||||
// Sound
|
||||
|
||||
|
|
|
@ -355,6 +355,7 @@ extern Option<bool> ForceWindowsCE;
|
|||
extern Option<bool> AutoLoadState;
|
||||
extern Option<bool> AutoSaveState;
|
||||
extern Option<int> SavestateSlot;
|
||||
extern Option<bool> ForceFreePlay;
|
||||
|
||||
// Sound
|
||||
|
||||
|
|
|
@ -512,6 +512,9 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
|
|||
naomi_cart_LoadBios(path);
|
||||
}
|
||||
mcfg_CreateDevices();
|
||||
if (settings.platform.isNaomi())
|
||||
// Must be done after the maple devices are created and EEPROM is accessible
|
||||
naomi_cart_ConfigureEEPROM();
|
||||
cheatManager.reset(settings.content.gameId);
|
||||
if (cheatManager.isWidescreen())
|
||||
{
|
||||
|
|
|
@ -410,18 +410,53 @@ void AWCartridge::AdvancePtr(u32 size)
|
|||
dma_offset += size;
|
||||
}
|
||||
|
||||
std::string AWCartridge::GetGameId()
|
||||
struct AtomiswaveBootID
|
||||
{
|
||||
if (RomSize < 0x30 + 0x20)
|
||||
return "(ROM too small)";
|
||||
char boardName[16]; // SYSTEM_X_APP
|
||||
char vendorName[32];
|
||||
char gameTitle[32];
|
||||
char year[4];
|
||||
char month[2];
|
||||
char day[2];
|
||||
u32 _unkn0;
|
||||
u32 _unkn1;
|
||||
u32 _unkn2;
|
||||
u32 gamePC;
|
||||
u32 _unkn3;
|
||||
u32 testPC;
|
||||
};
|
||||
|
||||
dma_offset = 0x30;
|
||||
u32 limit = 0x20;
|
||||
char *name = (char *)GetDmaPtr(limit);
|
||||
std::string game_id(name, limit);
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
return game_id;
|
||||
bool AWCartridge::GetBootId(RomBootID *bootId)
|
||||
{
|
||||
if (RomSize < sizeof(AtomiswaveBootID))
|
||||
return false;
|
||||
AtomiswaveBootID awBootId;
|
||||
u8 *p = (u8 *)&awBootId;
|
||||
u32 size = sizeof(AtomiswaveBootID);
|
||||
dma_offset = 0;
|
||||
recalc_dma_offset(EPR);
|
||||
while (size > 0)
|
||||
{
|
||||
u32 chunkSize = size;
|
||||
void *src = GetDmaPtr(chunkSize);
|
||||
if (chunkSize == 0)
|
||||
return false;
|
||||
memcpy(p, src, chunkSize);
|
||||
p += chunkSize;
|
||||
size -= chunkSize;
|
||||
AdvancePtr(chunkSize);
|
||||
}
|
||||
memset(bootId, 0, sizeof(RomBootID));
|
||||
memcpy(bootId->boardName, awBootId.boardName, sizeof(bootId->boardName));
|
||||
memcpy(bootId->vendorName, awBootId.vendorName, sizeof(bootId->vendorName));
|
||||
memcpy(bootId->gameTitle[0], awBootId.gameTitle, sizeof(bootId->gameTitle[0]));
|
||||
bootId->gamePC = awBootId.gamePC;
|
||||
bootId->testPC = awBootId.testPC;
|
||||
bootId->year = atoi(std::string(awBootId.year, awBootId.year + 4).c_str());
|
||||
bootId->month = atoi(std::string(awBootId.month, awBootId.month + 2).c_str());
|
||||
bootId->day = atoi(std::string(awBootId.day, awBootId.day + 2).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AWCartridge::Serialize(Serializer& ser) const
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
|
||||
void *GetDmaPtr(u32 &size) override;
|
||||
void AdvancePtr(u32 size) override;
|
||||
std::string GetGameId() override;
|
||||
bool GetBootId(RomBootID *bootId) override;
|
||||
|
||||
void SetKey(u32 key) override;
|
||||
void Serialize(Serializer& ser) const override;
|
||||
|
|
|
@ -273,26 +273,21 @@ M4Cartridge::~M4Cartridge()
|
|||
free(m_key_data);
|
||||
}
|
||||
|
||||
std::string M4Cartridge::GetGameId()
|
||||
bool M4Cartridge::GetBootId(RomBootID *bootId)
|
||||
{
|
||||
if (RomSize < 0x30 + 0x20)
|
||||
return "(ROM too small)";
|
||||
|
||||
std::string game_id;
|
||||
if (RomPtr[0] == 'N' && RomPtr[1] == 'A')
|
||||
game_id = std::string((char *)(RomPtr + 0x30), 0x20);
|
||||
else
|
||||
if (RomSize < sizeof(RomBootID))
|
||||
return false;
|
||||
RomBootID *pBootId = (RomBootID *)RomPtr;
|
||||
if (memcmp(pBootId->boardName, "NAOMI", 5))
|
||||
{
|
||||
rom_cur_address = 0;
|
||||
enc_reset();
|
||||
enc_fill();
|
||||
|
||||
game_id = std::string((char *)(buffer + 0x30), 0x20);
|
||||
pBootId = (RomBootID *)buffer;
|
||||
}
|
||||
memcpy(bootId, pBootId, sizeof(RomBootID));
|
||||
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
return game_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
void M4Cartridge::Serialize(Serializer& ser) const
|
||||
|
|
|
@ -44,9 +44,9 @@ public:
|
|||
|
||||
void* GetDmaPtr(u32 &size) override;
|
||||
void AdvancePtr(u32 size) override;
|
||||
std::string GetGameId() override;
|
||||
void Serialize(Serializer& ser) const override;
|
||||
void Deserialize(Deserializer& deser) override;
|
||||
bool GetBootId(RomBootID *bootId) override;
|
||||
|
||||
void SetKey(u32 key) override { this->m4id = key; }
|
||||
void SetKeyData(u8 *key_data) override { this->m_key_data = key_data; }
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "oslib/oslib.h"
|
||||
#include "serialize.h"
|
||||
#include "card_reader.h"
|
||||
#include "naomi_flashrom.h"
|
||||
|
||||
Cartridge *CurrentCartridge;
|
||||
bool bios_loaded = false;
|
||||
|
@ -188,12 +189,9 @@ void naomi_cart_LoadBios(const char *filename)
|
|||
const char *bios = "naomi";
|
||||
if (game->bios != nullptr)
|
||||
bios = game->bios;
|
||||
u32 region_flag = std::min((int)config::Region, (int)game->region_flag);
|
||||
if (game->region_flag == REGION_EXPORT_ONLY)
|
||||
region_flag = REGION_EXPORT;
|
||||
if (!loadBios(bios, archive.get(), parent_archive.get(), region_flag))
|
||||
if (!loadBios(bios, archive.get(), parent_archive.get(), config::Region))
|
||||
{
|
||||
WARN_LOG(NAOMI, "Warning: Region %d bios not found in %s", region_flag, bios);
|
||||
WARN_LOG(NAOMI, "Warning: Region %d bios not found in %s", (int)config::Region, bios);
|
||||
if (!loadBios(bios, archive.get(), parent_archive.get(), -1))
|
||||
{
|
||||
// If a specific BIOS is needed for this game, fail.
|
||||
|
@ -206,7 +204,7 @@ void naomi_cart_LoadBios(const char *filename)
|
|||
bios_loaded = true;
|
||||
}
|
||||
|
||||
static void naomi_cart_LoadZip(const char *filename, LoadProgress *progress)
|
||||
static void loadMameRom(const char *filename, LoadProgress *progress)
|
||||
{
|
||||
Game *game = FindGame(filename);
|
||||
if (game == NULL)
|
||||
|
@ -396,19 +394,8 @@ static void naomi_cart_LoadZip(const char *filename, LoadProgress *progress)
|
|||
}
|
||||
md5.getDigest(settings.network.md5.game);
|
||||
}
|
||||
|
||||
strcpy(naomi_game_id, CurrentCartridge->GetGameId().c_str());
|
||||
if (naomi_game_id[0] == '\0')
|
||||
strcpy(naomi_game_id, game->name);
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
|
||||
|
||||
if (CurrentCartridge->GetGameId() == "INITIAL D"
|
||||
|| CurrentCartridge->GetGameId() == "INITIAL D Ver.2"
|
||||
|| CurrentCartridge->GetGameId() == "INITIAL D Ver.3"
|
||||
|| CurrentCartridge->GetGameId() == "INITIAL D CYCRAFT")
|
||||
{
|
||||
card_reader::initialDCardReader.init();
|
||||
}
|
||||
// Default game name if ROM boot id isn't found
|
||||
strcpy(naomi_game_id, game->name);
|
||||
|
||||
} catch (...) {
|
||||
delete CurrentCartridge;
|
||||
|
@ -417,18 +404,8 @@ static void naomi_cart_LoadZip(const char *filename, LoadProgress *progress)
|
|||
}
|
||||
}
|
||||
|
||||
void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
||||
static void loadDecryptedRom(const char* file, LoadProgress *progress)
|
||||
{
|
||||
naomi_cart_Close();
|
||||
|
||||
std::string extension = get_file_extension(file);
|
||||
|
||||
if (extension == "zip" || extension == "7z")
|
||||
{
|
||||
naomi_cart_LoadZip(file, progress);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to load BIOS from naomi.zip
|
||||
if (!loadBios("naomi", NULL, NULL, config::Region))
|
||||
{
|
||||
|
@ -446,6 +423,7 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
|||
std::vector<u32> fsize;
|
||||
u32 romSize = 0;
|
||||
|
||||
std::string extension = get_file_extension(file);
|
||||
if (extension == "lst")
|
||||
{
|
||||
// LST file
|
||||
|
@ -576,8 +554,48 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
|||
DEBUG_LOG(NAOMI, "Legacy ROM loaded successfully");
|
||||
|
||||
CurrentCartridge = new DecryptedCartridge(romBase, romSize);
|
||||
strcpy(naomi_game_id, CurrentCartridge->GetGameId().c_str());
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
|
||||
}
|
||||
|
||||
void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
||||
{
|
||||
naomi_cart_Close();
|
||||
|
||||
std::string extension = get_file_extension(file);
|
||||
|
||||
if (extension == "zip" || extension == "7z")
|
||||
loadMameRom(file, progress);
|
||||
else
|
||||
loadDecryptedRom(file, progress);
|
||||
|
||||
RomBootID bootId;
|
||||
if (CurrentCartridge->GetBootId(&bootId))
|
||||
{
|
||||
std::string gameId = trim_trailing_ws(std::string(bootId.gameTitle[0], &bootId.gameTitle[0][32]));
|
||||
strcpy(naomi_game_id, gameId.c_str());
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s] region %x players %x vertical %x", naomi_game_id, (u8)bootId.country, bootId.cabinet, bootId.vertical);
|
||||
|
||||
if (gameId == "INITIAL D"
|
||||
|| gameId == "INITIAL D Ver.2"
|
||||
|| gameId == "INITIAL D Ver.3"
|
||||
|| gameId == "INITIAL D CYCRAFT")
|
||||
{
|
||||
card_reader::initialDCardReader.init();
|
||||
}
|
||||
}
|
||||
else
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
|
||||
}
|
||||
|
||||
void naomi_cart_ConfigureEEPROM()
|
||||
{
|
||||
if (!settings.platform.isNaomi())
|
||||
return;
|
||||
|
||||
RomBootID bootId;
|
||||
if (CurrentCartridge->GetBootId(&bootId))
|
||||
configure_naomi_eeprom(&bootId);
|
||||
else
|
||||
WARN_LOG(NAOMI, "Can't read ROM boot ID");
|
||||
}
|
||||
|
||||
void naomi_cart_Close()
|
||||
|
@ -649,19 +667,25 @@ void* Cartridge::GetPtr(u32 offset, u32& size)
|
|||
return &RomPtr[offset];
|
||||
}
|
||||
|
||||
std::string Cartridge::GetGameId() {
|
||||
if (RomSize < 0x30 + 0x20)
|
||||
return "(ROM too small)";
|
||||
|
||||
std::string game_id((char *)RomPtr + 0x30, 0x20);
|
||||
if (game_id == "AWNAOMI " && RomSize >= 0xFF50)
|
||||
bool NaomiCartridge::GetBootId(RomBootID *bootId)
|
||||
{
|
||||
if (RomSize < sizeof(RomBootID))
|
||||
return false;
|
||||
u8 *p = (u8 *)bootId;
|
||||
u32 size = sizeof(RomBootID);
|
||||
DmaOffset = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
game_id = std::string((char *)RomPtr + 0xFF30, 0x20);
|
||||
u32 chunkSize = size;
|
||||
void *src = GetDmaPtr(chunkSize);
|
||||
if (chunkSize == 0)
|
||||
return false;
|
||||
memcpy(p, src, chunkSize);
|
||||
p += chunkSize;
|
||||
size -= chunkSize;
|
||||
AdvancePtr(chunkSize);
|
||||
}
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
|
||||
return game_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
void* NaomiCartridge::GetDmaPtr(u32& size)
|
||||
|
@ -694,7 +718,7 @@ u32 NaomiCartridge::ReadMem(u32 address, u32 size)
|
|||
case 0x48: // 5f7048: DIMM PARAMETERH
|
||||
DEBUG_LOG(NAOMI, "DIMM PARAMETERH read<%d>", size);
|
||||
return reg_dimm_parameterh;
|
||||
case 0x04C: // 5f704c: DIMM STATUS
|
||||
case 0x4c: // 5f704c: DIMM STATUS
|
||||
DEBUG_LOG(NAOMI, "DIMM STATUS read<%d>: %x", size, reg_dimm_status);
|
||||
return reg_dimm_status;
|
||||
|
||||
|
@ -965,16 +989,21 @@ u16 M2Cartridge::ReadCipheredData(u32 offset)
|
|||
|
||||
}
|
||||
|
||||
std::string M2Cartridge::GetGameId()
|
||||
bool M2Cartridge::GetBootId(RomBootID *bootId)
|
||||
{
|
||||
std::string game_id = NaomiCartridge::GetGameId();
|
||||
if ((game_id.size() < 2 || ((u8)game_id[0] == 0xff && (u8)game_id[1] == 0xff)) && RomSize >= 0x800050)
|
||||
if (RomSize < sizeof(RomBootID))
|
||||
return false;
|
||||
RomBootID *pBootId = (RomBootID *)RomPtr;
|
||||
if ((pBootId->gameTitle[0][0] == '\0'
|
||||
|| ((u8)pBootId->gameTitle[0][0] == 0xff && (u8)pBootId->gameTitle[0][1] == 0xff)))
|
||||
{
|
||||
game_id = std::string((char *)RomPtr + 0x800030, 0x20);
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
if (RomSize < 0x800000 + sizeof(RomBootID))
|
||||
return false;
|
||||
pBootId = (RomBootID *)(RomPtr + 0x800000);
|
||||
}
|
||||
return game_id;
|
||||
memcpy(bootId, pBootId, sizeof(RomBootID));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void M2Cartridge::Serialize(Serializer& ser) const {
|
||||
|
|
|
@ -5,6 +5,44 @@
|
|||
#include "types.h"
|
||||
#include "emulator.h"
|
||||
|
||||
struct RomBootID
|
||||
{
|
||||
char boardName[16];
|
||||
char vendorName[32];
|
||||
char gameTitle[8][32];
|
||||
u16 year;
|
||||
u8 month;
|
||||
u8 day;
|
||||
char gameID[4]; // copied to eeprom[3]
|
||||
u16 romMode; // != 0 => offset | 0x20000000
|
||||
u16 romWaitFlag; // != 0 => configure G1 BUS
|
||||
u32 romWait[8]; // init values for SB_G1RRC, SB_G1RWC, SB_G1FRC, SB_G1FWC, SB_G1CRC, SB_G1CWC, SB_G1GDRC, SB_G1GDWC
|
||||
u16 romID[22][3]; // M2/M4-type ROM checksums
|
||||
u8 coinFlag[8][16];// Init instructions for EEPROM for each region
|
||||
// b0: if 0, use default BIOS settings, if 1, use settings below
|
||||
// b1: bit 0: vertical monitor, bit 1: forces attract mode sound off
|
||||
// b2: coin chute type: 0 common, 1; individual
|
||||
// b3: default coin setting (1-28)
|
||||
// b4: coin 1 rate (for manual coin setting)
|
||||
// b5: coin 2 rate (for manual coin setting)
|
||||
// b6: credit rate (for manual coin setting)
|
||||
// b7: bonus credit rate (for manual coin setting)
|
||||
// b8-15: coin sequences
|
||||
char sequence[8][32];// text ("CREDIT TO START", "CREDIT TO CONTINUE", ...)
|
||||
u32 gameLoad[8][3]; // regions to copy from ROM to system RAM: offset, RAM address, length (offset=0xffffffff means end of list)
|
||||
u32 testLoad[8][3]; // same for game test mode
|
||||
u32 gamePC; // main game entry point
|
||||
u32 testPC; // test mode entry point
|
||||
u8 country; // supported regions bitmap
|
||||
u8 cabinet; // supported # of players bitmap: b0 1 player, b1 2 players, ...
|
||||
u8 resolution; // 0: 31kHz, 1: 15kHz
|
||||
u8 vertical; // b0: horizontal mode, b1: vertical mode
|
||||
u8 serialID; // if 1, check the ROM/DIMM board serial# eeprom
|
||||
u8 _res[211]; // _res[210]: if 0xFF then the header is unencrypted. if not then the header is encrypted starting at offset 0x010.
|
||||
|
||||
// Note: this structure is copied to system RAM by the BIOS at location 0c01f400
|
||||
};
|
||||
|
||||
class Cartridge
|
||||
{
|
||||
public:
|
||||
|
@ -23,11 +61,11 @@ public:
|
|||
virtual void* GetPtr(u32 offset, u32& size);
|
||||
virtual void* GetDmaPtr(u32 &size) = 0;
|
||||
virtual void AdvancePtr(u32 size) = 0;
|
||||
virtual std::string GetGameId();
|
||||
virtual void Serialize(Serializer& ser) const {}
|
||||
virtual void Deserialize(Deserializer& deser) {}
|
||||
virtual void SetKey(u32 key) { }
|
||||
virtual void SetKeyData(u8 *key_data) { }
|
||||
virtual bool GetBootId(RomBootID *bootId) = 0;
|
||||
|
||||
protected:
|
||||
u8* RomPtr;
|
||||
|
@ -45,6 +83,7 @@ public:
|
|||
void AdvancePtr(u32 size) override {}
|
||||
void Serialize(Serializer& ser) const override;
|
||||
void Deserialize(Deserializer& deser) override;
|
||||
bool GetBootId(RomBootID *bootId) override;
|
||||
|
||||
void SetKey(u32 key) override { this->key = key; }
|
||||
|
||||
|
@ -75,7 +114,7 @@ public:
|
|||
void Serialize(Serializer& ser) const override;
|
||||
void Deserialize(Deserializer& deser) override;
|
||||
void* GetDmaPtr(u32& size) override;
|
||||
std::string GetGameId() override;
|
||||
bool GetBootId(RomBootID *bootId) override;
|
||||
|
||||
private:
|
||||
u8 naomi_cart_ram[64 * 1024];
|
||||
|
@ -91,6 +130,7 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress);
|
|||
void naomi_cart_Close();
|
||||
int naomi_cart_GetPlatform(const char *path);
|
||||
void naomi_cart_LoadBios(const char *filename);
|
||||
void naomi_cart_ConfigureEEPROM();
|
||||
|
||||
extern char naomi_game_id[];
|
||||
extern u8 *naomi_default_eeprom;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "hw/flashrom/flashrom.h"
|
||||
#include "hw/holly/sb_mem.h"
|
||||
#include "hw/maple/maple_devs.h"
|
||||
#include "cfg/option.h"
|
||||
|
||||
extern WritableChip *sys_nvmem;
|
||||
|
||||
|
@ -88,8 +89,7 @@ void write_naomi_flash(u32 addr, u8 value)
|
|||
// eeprom layout:
|
||||
// Offset Size
|
||||
// 0 2 CRC of bytes [2,17]
|
||||
// 2 1 size of record (16, sometimes 1, ignored)
|
||||
// 3 15 data
|
||||
// 2 16 data
|
||||
// 18 18 same record repeated
|
||||
// 36 2 CRC of bytes [44,44+size[
|
||||
// 38 1 record size
|
||||
|
@ -98,10 +98,27 @@ void write_naomi_flash(u32 addr, u8 value)
|
|||
// 44 size*2 Record data, repeated twice
|
||||
//
|
||||
// The first record contains naomi bios settings, and the second one game-specific settings
|
||||
// common settings:
|
||||
// 2 b0 vertical screen
|
||||
// b4 attract mode sound
|
||||
// 3 Game serial ID (4 chars)
|
||||
// 7 unknown (9 or x18)
|
||||
// 8 b0: coin chute type (0 common, 1 individual)
|
||||
// b4-5: cabinet type (0: 1P, 10: 2P, 20: 2P, 30: 4P)
|
||||
// 9 coin setting (-1), 27 is manual
|
||||
// 10 coin to credit
|
||||
// 11 chute 1 multiplier
|
||||
// 12 chute 2 multiplier
|
||||
// 13 bonus adder (coins)
|
||||
// 14 coin sequence: b0-3 seq 1, b4-7 seq 2
|
||||
// 15 coin sequence: b0-3 seq 3, b4-7 seq 4
|
||||
// 16 coin sequence: b0-3 seq 5, b4-7 seq 6
|
||||
// 17 coin sequence: b0-3 seq 7, b4-7 seq 8
|
||||
//
|
||||
|
||||
void write_naomi_eeprom(u32 offset, u8 value)
|
||||
{
|
||||
if (offset >= 3 && offset < 20)
|
||||
if (offset >= 2 && offset < 18)
|
||||
{
|
||||
EEPROM[offset] = value;
|
||||
EEPROM[offset + 18] = value;
|
||||
|
@ -121,3 +138,129 @@ void write_naomi_eeprom(u32 offset, u8 value)
|
|||
else
|
||||
WARN_LOG(NAOMI, "EEPROM record doesn't exist or is too short");
|
||||
}
|
||||
|
||||
static u8 readEeprom(u32 offset)
|
||||
{
|
||||
return EEPROM[offset & 127];
|
||||
}
|
||||
|
||||
static bool initEeprom(const RomBootID *bootId)
|
||||
{
|
||||
if (!memcmp(bootId->gameID, &EEPROM[3], sizeof(bootId->gameID)))
|
||||
return false;
|
||||
NOTICE_LOG(NAOMI, "Initializing Naomi EEPROM for game %.32s", bootId->gameTitle[0]);
|
||||
for (int i = 0; i < 4; i++)
|
||||
write_naomi_eeprom(3 + i, bootId->gameID[i]);
|
||||
write_naomi_eeprom(7, 9); // FIXME 9 or 0x18?
|
||||
if (bootId->cabinet & 8)
|
||||
write_naomi_eeprom(8, 30);
|
||||
else if (bootId->cabinet & 4)
|
||||
write_naomi_eeprom(8, 20);
|
||||
else if (bootId->cabinet & 2)
|
||||
write_naomi_eeprom(8, 10);
|
||||
else
|
||||
write_naomi_eeprom(8, 0);
|
||||
if (bootId->coinFlag[0][1] == 1)
|
||||
{
|
||||
// ROM-specific defaults
|
||||
write_naomi_eeprom(2, bootId->coinFlag[0][3] | (((bootId->coinFlag[0][3] & 2) ^ 2) << 3));
|
||||
write_naomi_eeprom(9, bootId->coinFlag[0][3] - 1);
|
||||
write_naomi_eeprom(10, bootId->coinFlag[0][6]);
|
||||
write_naomi_eeprom(11, bootId->coinFlag[0][4]);
|
||||
write_naomi_eeprom(12, bootId->coinFlag[0][5]);
|
||||
write_naomi_eeprom(13, bootId->coinFlag[0][7]);
|
||||
write_naomi_eeprom(14, bootId->coinFlag[0][8] | (bootId->coinFlag[0][9] << 4));
|
||||
write_naomi_eeprom(15, bootId->coinFlag[0][10] | (bootId->coinFlag[0][11] << 4));
|
||||
write_naomi_eeprom(16, bootId->coinFlag[0][12] | (bootId->coinFlag[0][13] << 4));
|
||||
write_naomi_eeprom(17, bootId->coinFlag[0][14] | (bootId->coinFlag[0][15] << 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
// BIOS defaults
|
||||
write_naomi_eeprom(2, (bootId->vertical & 2) ? 0x11 : 0x10);
|
||||
write_naomi_eeprom(9, 0);
|
||||
write_naomi_eeprom(10, 1);
|
||||
write_naomi_eeprom(11, 1);
|
||||
write_naomi_eeprom(12, 1);
|
||||
write_naomi_eeprom(13, 0);
|
||||
write_naomi_eeprom(14, 0x11);
|
||||
write_naomi_eeprom(15, 0x11);
|
||||
write_naomi_eeprom(16, 0x11);
|
||||
write_naomi_eeprom(17, 0x11);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void configure_naomi_eeprom(const RomBootID *bootId)
|
||||
{
|
||||
initEeprom(bootId);
|
||||
// Horizontal / vertical screen orientation
|
||||
if (bootId->vertical & 2)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: vertical monitor orientation");
|
||||
write_naomi_eeprom(2, readEeprom(2) | 1);
|
||||
config::Rotate90.override(true);
|
||||
}
|
||||
else if (bootId->vertical & 1)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: horizontal monitor orientation");
|
||||
write_naomi_eeprom(2, readEeprom(2) & ~1);
|
||||
}
|
||||
// Number of players
|
||||
if (bootId->cabinet != 0)
|
||||
{
|
||||
int nPlayers = readEeprom(8) >> 4; // 0 to 3
|
||||
if (!(bootId->cabinet & (1 << nPlayers)))
|
||||
{
|
||||
u8 coinChute = readEeprom(8) & 1;
|
||||
if (bootId->cabinet & 8)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: 4-player cabinet");
|
||||
write_naomi_eeprom(8, 0x30 | coinChute);
|
||||
}
|
||||
else if (bootId->cabinet & 4)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: 3-player cabinet");
|
||||
write_naomi_eeprom(8, 0x20 | coinChute);
|
||||
}
|
||||
else if (bootId->cabinet & 2)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: 2-player cabinet");
|
||||
write_naomi_eeprom(8, 0x10 | coinChute);
|
||||
}
|
||||
else if (bootId->cabinet & 1)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: 1-player cabinet");
|
||||
write_naomi_eeprom(8, 0x00 | coinChute);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Region
|
||||
if (bootId->country != 0 && (bootId->country & (1 << config::Region)) == 0)
|
||||
{
|
||||
if (bootId->country & 2)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "Forcing region USA");
|
||||
config::Region.override(1);
|
||||
}
|
||||
else if (bootId->country & 4)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "Forcing region Export");
|
||||
config::Region.override(2);
|
||||
}
|
||||
else if (bootId->country & 1)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "Forcing region Japan");
|
||||
config::Region.override(0);
|
||||
}
|
||||
else if (bootId->country & 8)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "Forcing region Korea");
|
||||
config::Region.override(3);
|
||||
}
|
||||
naomi_cart_LoadBios(settings.content.path.c_str());
|
||||
}
|
||||
// Coin settings
|
||||
if (config::ForceFreePlay)
|
||||
write_naomi_eeprom(9, 27 - 1);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "naomi_cart.h"
|
||||
|
||||
void write_naomi_flash(u32 addr, u8 value);
|
||||
void write_naomi_eeprom(u32 offset, u8 value);
|
||||
void configure_naomi_eeprom(const RomBootID *bootId);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -44,15 +44,6 @@ enum CartridgeType {
|
|||
GD
|
||||
};
|
||||
|
||||
enum RegionType {
|
||||
REGION_JAPAN = 0,
|
||||
REGION_USA = 1,
|
||||
REGION_EXPORT = 2,
|
||||
REGION_KOREA = 3,
|
||||
REGION_AUSTRALIA = 4,
|
||||
REGION_EXPORT_ONLY = 5
|
||||
};
|
||||
|
||||
enum RotationType {
|
||||
ROT0 = 0,
|
||||
ROT270 = 3,
|
||||
|
@ -85,7 +76,6 @@ struct Game
|
|||
u32 key;
|
||||
const char *bios;
|
||||
CartridgeType cart_type;
|
||||
RegionType region_flag;
|
||||
RotationType rotation_flag;
|
||||
struct
|
||||
{
|
||||
|
|
|
@ -1378,6 +1378,7 @@ static void gui_display_settings()
|
|||
ImGui::SameLine();
|
||||
OptionCheckbox("Save", config::AutoSaveState,
|
||||
"Save the state of the game when stopping");
|
||||
OptionCheckbox("Naomi Free Play", config::ForceFreePlay, "Configure Naomi games in Free Play mode.");
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::EndTabItem();
|
||||
|
|
|
@ -212,6 +212,20 @@ struct retro_core_option_v2_definition option_defs_us[] = {
|
|||
},
|
||||
"disabled",
|
||||
},
|
||||
{
|
||||
CORE_OPTION_NAME "_force_freeplay",
|
||||
"Set NAOMI Games to Free Play",
|
||||
NULL,
|
||||
"Modify to coin settings of the game to free play.",
|
||||
NULL,
|
||||
"system",
|
||||
{
|
||||
{ "disabled", NULL },
|
||||
{ "enabled", NULL },
|
||||
{ NULL, NULL },
|
||||
},
|
||||
"enabled",
|
||||
},
|
||||
{
|
||||
CORE_OPTION_NAME "_internal_resolution",
|
||||
"Internal Resolution",
|
||||
|
|
|
@ -37,6 +37,7 @@ Option<bool> ForceWindowsCE(CORE_OPTION_NAME "_force_wince");
|
|||
Option<bool> AutoLoadState("");
|
||||
Option<bool> AutoSaveState("");
|
||||
Option<int> SavestateSlot("");
|
||||
Option<bool> ForceFreePlay(CORE_OPTION_NAME "_force_freeplay", true);
|
||||
|
||||
// Sound
|
||||
|
||||
|
|
Loading…
Reference in New Issue