Skip to content

Commit

Permalink
naomi: emulate dimm registers for gd cart
Browse files Browse the repository at this point in the history
Emulate 1.02 dimm board without network so that the bios detects it and
shows the expected GD-ROM SYSTEM boot screen.
Fix rom board serial id issue (error 04) with ikaruga, tetkiwam,
puyofev[j] and sprtjam.
Issue #1735

Add naomigd and naomidev bios definitions (unused).
Use netdimm for mj1 and wccf* series (still not working).
  • Loading branch information
flyinghead committed Nov 14, 2024
1 parent 76638df commit bdd2d5a
Show file tree
Hide file tree
Showing 10 changed files with 362 additions and 163 deletions.
5 changes: 5 additions & 0 deletions core/hw/flashrom/x76f100.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ class X76F100SerialFlash
memcpy(this->data, &data[index], sizeof(this->data));
}

const u8 *getProtectedData() const
{
return data;
}

void serialize(Serializer& ser) const;
void deserialize(Deserializer& deser);

Expand Down
239 changes: 239 additions & 0 deletions core/hw/naomi/gdcartridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
#include "stdclass.h"
#include "emulator.h"
#include "oslib/storage.h"
#include "naomi_regs.h"
#include "hw/holly/sb.h"
#include "hw/holly/holly_intc.h"
#include "hw/mem/addrspace.h"
#include "serialize.h"
#include "hw/sh4/sh4_sched.h"
#include "naomi.h"

/*
Expand Down Expand Up @@ -642,3 +649,235 @@ bool GDCartridge::Read(u32 offset, u32 size, void *dst)
memcpy(dst, &dimm_data[addr], std::min(size, dimm_data_size - addr));
return true;
}

GDCartridge::GDCartridge(u32 size) : NaomiCartridge(size)
{
schedId = sh4_sched_register(0, [](int tag, int sch_cycl, int jitter, void *arg){
return ((GDCartridge *)arg)->schedCallback();
}, this);
}

GDCartridge::~GDCartridge()
{
free(dimm_data);
sh4_sched_unregister(schedId);
}

u32 GDCartridge::ReadMem(u32 address, u32 size)
{
switch (address)
{
case NAOMI_DIMM_COMMAND:
DEBUG_LOG(NAOMI, "DIMM COMMAND read -> %x", dimm_command);
return dimm_command;
case NAOMI_DIMM_OFFSETL:
DEBUG_LOG(NAOMI, "DIMM OFFSETL read -> %x", dimm_offsetl);
return dimm_offsetl;
case NAOMI_DIMM_PARAMETERL:
DEBUG_LOG(NAOMI, "DIMM PARAMETERL read -> %x", dimm_parameterl);
return dimm_parameterl;
case NAOMI_DIMM_PARAMETERH:
DEBUG_LOG(NAOMI, "DIMM PARAMETERH read -> %x", dimm_parameterh);
return dimm_parameterh;
case NAOMI_DIMM_STATUS:
{
u32 rc = DIMM_STATUS & ~(((SB_ISTEXT >> 3) & 1) << 8);
static u32 lastRc;
if (rc != lastRc)
DEBUG_LOG(NAOMI, "DIMM STATUS read -> %x", rc);
lastRc = rc;
return rc;
}
default:
return NaomiCartridge::ReadMem(address, size);
}
}

void GDCartridge::WriteMem(u32 address, u32 data, u32 size)
{
switch (address)
{
case NAOMI_DIMM_COMMAND:
dimm_command = data;
DEBUG_LOG(NAOMI, "DIMM COMMAND Write<%d>: %x", size, data);
return;

case NAOMI_DIMM_OFFSETL:
dimm_offsetl = data;
DEBUG_LOG(NAOMI, "DIMM OFFSETL Write<%d>: %x", size, data);
return;
case NAOMI_DIMM_PARAMETERL:
dimm_parameterl = data;
DEBUG_LOG(NAOMI, "DIMM PARAMETERL Write<%d>: %x", size, data);
return;
case NAOMI_DIMM_PARAMETERH:
dimm_parameterh = data;
DEBUG_LOG(NAOMI, "DIMM PARAMETERH Write<%d>: %x", size, data);
return;

case NAOMI_DIMM_STATUS:
DEBUG_LOG(NAOMI, "DIMM STATUS Write<%d>: %x", size, data);
if (data & 0x100)
// write 0 seems ignored
asic_CancelInterrupt(holly_EXP_PCI);
if ((data & 1) == 0)
// irq to dimm
process();
return;

default:
NaomiCartridge::WriteMem(address, data, size);
return;
}
}

void GDCartridge::process()
{
INFO_LOG(NAOMI, "NetDIMM cmd %04x sock %d offset %04x paramh/l %04x %04x", (dimm_command >> 9) & 0x3f,
dimm_command & 0xff, dimm_offsetl, dimm_parameterh, dimm_parameterl);

int cmdGroup = (dimm_command >> 13) & 3;
int cmd = (dimm_command >> 9) & 0xf;
switch (cmdGroup)
{
case 0: // system commands
systemCmd(cmd);
break;
case 1: // network commands
WARN_LOG(NAOMI, "Network command received cmd %x. Need full NetDIMM?", cmd);
returnToNaomi(true, 0, -1);
break;
default:
WARN_LOG(NAOMI, "Unknown DIMM command group %d cmd %x", cmdGroup, cmd);
returnToNaomi(true, 0, -1);
break;
}
}

void GDCartridge::returnToNaomi(bool failed, u16 offsetl, u32 parameter)
{
dimm_command = ((dimm_command & 0x7e00) + 0x400) | (failed ? 0xff : 0x4);
dimm_offsetl = offsetl;
dimm_parameterh = parameter >> 16;
dimm_parameterl = parameter;
verify(((SB_ISTEXT >> 3) & 1) == 0);
asic_RaiseInterrupt(holly_EXP_PCI);
}

void GDCartridge::systemCmd(int cmd)
{
switch (cmd)
{
case 0xf: // startup
INFO_LOG(NAOMI, "NetDIMM startup");
// bit 16,17: dimm0 size (none, 128, 256, 512)
// bit 18,19: dimm1 size
// bit 28: network enabled (network settings appear in bios menu)
// bit 29: set
// bit 30: gd-rom connected
// bit 31: mobile/ppp network?
// (| 30, 70, F0, 1F0, 3F0, 7F0)
// | offset >> 20 (dimm buffers offset @ size - 16MB)
// offset = (64MB << 0-5) - 16MB
// vf4 forces this value to 0f000000 (256MB) if != 1f000000 (512MB)
if (dimm_data_size == 512_MB)
addrspace::write32(0xc01fc04, (3 << 16) | 0x60000000 | (dimm_data_size >> 20)); // dimm board config 1 x 512 MB
else if (dimm_data_size == 256_MB)
addrspace::write32(0xc01fc04, (2 << 16) | 0x60000000 | (dimm_data_size >> 20)); // dimm board config 1 x 256 MB
else
addrspace::write32(0xc01fc04, (1 << 16) | 0x60000000 | (dimm_data_size >> 20)); // dimm board config 1 x 128 MB
addrspace::write32(0xc01fc0c, 0x1020000 | 0x264); // fw version 1.02
// DIMM board serial Id
{
const u32 *serial = (u32 *)(getGameSerialId() + 0x20); // get only the serial id
addrspace::write32(0xc01fc40, *serial++);
addrspace::write32(0xc01fc44, *serial++);
addrspace::write32(0xc01fc48, *serial++);
addrspace::write32(0xc01fc4c, *serial++);
}
// SET_BASE_ADDRESS(0c000000, 0)
dimm_command = 0x8600;
dimm_offsetl = 0;
dimm_parameterl = 0;
dimm_parameterh = 0x0c00;
asic_RaiseInterrupt(holly_EXP_PCI);
sh4_sched_request(schedId, SH4_MAIN_CLOCK);

break;

case 0: // nop
case 1: // control read
case 3: // set base address
case 4: // peek8
case 5: // peek16
case 6: // peek32
case 8: // poke8
case 9: // poke16
case 10: // poke32
// These are callbacks from naomi
INFO_LOG(NAOMI, "System callback command %x", cmd);
break;

default:
WARN_LOG(NAOMI, "Unknown system command %x", cmd);
break;
}
}

void GDCartridge::Serialize(Serializer &ser) const
{
NaomiCartridge::Serialize(ser);
ser << dimm_command;
ser << dimm_offsetl;
ser << dimm_parameterl;
ser << dimm_parameterh;
sh4_sched_serialize(ser, schedId);
}

void GDCartridge::Deserialize(Deserializer &deser)
{
NaomiCartridge::Deserialize(deser);
if (deser.version() >= Deserializer::V53)
{
deser >> dimm_command;
deser >> dimm_offsetl;
deser >> dimm_parameterl;
deser >> dimm_parameterh;
sh4_sched_deserialize(deser, schedId);
}
}

int GDCartridge::schedCallback()
{
if (SB_ISTEXT & 8) // holly_EXP_PCI
return SH4_MAIN_CLOCK;

// regularly peek the test request address
peek<u32>(0xc01fc08);
asic_RaiseInterrupt(holly_EXP_PCI);

u32 testRequest = addrspace::read32(0xc01fc08);
if (testRequest & 1)
{
// bios dimm (fake) test
addrspace::write32(0xc01fc08, testRequest & ~1);
bool isMem;
char *p = (char *)addrspace::writeConst(0xc01fd00, isMem, 4);
strcpy(p, "CHECKING DIMM BD");
p = (char *)addrspace::writeConst(0xc01fd10, isMem, 4);
strcpy(p, "DIMM0 - GOOD");
p = (char *)addrspace::writeConst(0xc01fd20, isMem, 4);
strcpy(p, "DIMM1 - GOOD");
p = (char *)addrspace::writeConst(0xc01fd30, isMem, 4);
strcpy(p, "--- COMPLETED---");
addrspace::write32(0xc01fc0c, 0x0102a264);
}
else if (testRequest != 0)
{
addrspace::write32(0xc01fc08, 0);
addrspace::write32(0xc01fc0c, 0x03170100);
INFO_LOG(NAOMI, "TEST REQUEST %x", testRequest);
}

return SH4_MAIN_CLOCK;
}
56 changes: 43 additions & 13 deletions core/hw/naomi/gdcartridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,66 @@
* // copyright-holders:Olivier Galibert
*
*/

#ifndef CORE_HW_NAOMI_GDCARTRIDGE_H_
#define CORE_HW_NAOMI_GDCARTRIDGE_H_

#pragma once
#include "naomi_cart.h"
#include "imgread/common.h"

class GDCartridge: public NaomiCartridge {
public:
GDCartridge(u32 size) : NaomiCartridge(size)
{
}
~GDCartridge() override
{
free(dimm_data);
}
GDCartridge(u32 size);
~GDCartridge() override;

void Init(LoadProgress *progress = nullptr, std::vector<u8> *digest = nullptr) override
{
device_start(progress, digest);
device_reset();
}
void* GetDmaPtr(u32 &size) override;
bool Read(u32 offset, u32 size, void* dst) override;
u32 ReadMem(u32 address, u32 size) override;
void WriteMem(u32 address, u32 data, u32 size) override;

void SetGDRomName(const char *name, const char *parentName) { this->gdrom_name = name; this->gdrom_parent_name = parentName; }

void Serialize(Serializer &ser) const override;
void Deserialize(Deserializer &deser) override;

protected:
virtual void process();
virtual int schedCallback();
void returnToNaomi(bool failed, u16 offsetl, u32 parameter);

template<typename T>
void peek(u32 address)
{
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4);
int size;
switch (sizeof(T))
{
case 1:
size = 4;
break;
case 2:
size = 5;
break;
case 4:
size = 6;
break;
}
dimm_command = ((address >> 16) & 0x1ff) | (size << 9) | 0x8000;
dimm_offsetl = address & 0xffff;
dimm_parameterl = 0;
dimm_parameterh = 0;
}

u8 *dimm_data = nullptr;
u32 dimm_data_size = 0;
u16 dimm_command;
u16 dimm_offsetl;
u16 dimm_parameterl;
u16 dimm_parameterh;
static constexpr u16 DIMM_STATUS = 0x111;
int schedId;

private:
enum { FILENAME_LENGTH=24 };
Expand Down Expand Up @@ -70,6 +101,5 @@ class GDCartridge: public NaomiCartridge {
u64 des_encrypt_decrypt(u64 src, const u32 *des_subkeys);
u64 rev64(u64 src);
void read_gdrom(Disc *gdrom, u32 sector, u8* dst, u32 count = 1, LoadProgress *progress = nullptr);
void systemCmd(int cmd);
};

#endif /* CORE_HW_NAOMI_GDCARTRIDGE_H_ */
9 changes: 9 additions & 0 deletions core/hw/naomi/naomi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,20 @@ void naomi_reg_Init()
dmaSchedId = sh4_sched_register(0, naomiDmaSched);
}

// Sets the full content of the rom board serial eeprom (132 bytes)
// including response to reset and read/write passwords.
void setGameSerialId(const u8 *data)
{
romSerialId.setData(data);
}

// Return the protected data from the rom board serial eeprom (112 bytes)
// excluding response to reset and passwords.
const u8 *getGameSerialId()
{
return romSerialId.getProtectedData();
}

void naomi_reg_Term()
{
if (multiboard != nullptr)
Expand Down
5 changes: 3 additions & 2 deletions core/hw/naomi/naomi.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ u16 NaomiBoardIDRead();
u16 NaomiGameIDRead();
void NaomiGameIDWrite(u16 data);
void setGameSerialId(const u8 *data);
const u8 *getGameSerialId();

void initDriveSimSerialPipe();
void Naomi_setDmaDelay();
Expand Down Expand Up @@ -60,7 +61,7 @@ static inline u32 g2ext_readMem(u32 addr, u32 size)
if (multiboard != nullptr)
return multiboard->readG2Ext(addr, size);

INFO_LOG(NAOMI, "Unhandled G2 Ext read<%d> at %x", size, addr);
DEBUG_LOG(NAOMI, "Unhandled G2 Ext read<%d> at %x", size, addr);
return 0;
}

Expand All @@ -71,5 +72,5 @@ static inline void g2ext_writeMem(u32 addr, u32 data, u32 size)
else if (multiboard != nullptr)
multiboard->writeG2Ext(addr, size, data);
else
INFO_LOG(NAOMI, "Unhandled G2 Ext write<%d> at %x: %x", size, addr, data);
DEBUG_LOG(NAOMI, "Unhandled G2 Ext write<%d> at %x: %x", size, addr, data);
}
Loading

0 comments on commit bdd2d5a

Please sign in to comment.