Skip to content

Commit bdd2d5a

Browse files
committed
naomi: emulate dimm registers for gd cart
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).
1 parent 76638df commit bdd2d5a

File tree

10 files changed

+362
-163
lines changed

10 files changed

+362
-163
lines changed

core/hw/flashrom/x76f100.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ class X76F100SerialFlash
6262
memcpy(this->data, &data[index], sizeof(this->data));
6363
}
6464

65+
const u8 *getProtectedData() const
66+
{
67+
return data;
68+
}
69+
6570
void serialize(Serializer& ser) const;
6671
void deserialize(Deserializer& deser);
6772

core/hw/naomi/gdcartridge.cpp

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
#include "stdclass.h"
1515
#include "emulator.h"
1616
#include "oslib/storage.h"
17+
#include "naomi_regs.h"
18+
#include "hw/holly/sb.h"
19+
#include "hw/holly/holly_intc.h"
20+
#include "hw/mem/addrspace.h"
21+
#include "serialize.h"
22+
#include "hw/sh4/sh4_sched.h"
23+
#include "naomi.h"
1724

1825
/*
1926
@@ -642,3 +649,235 @@ bool GDCartridge::Read(u32 offset, u32 size, void *dst)
642649
memcpy(dst, &dimm_data[addr], std::min(size, dimm_data_size - addr));
643650
return true;
644651
}
652+
653+
GDCartridge::GDCartridge(u32 size) : NaomiCartridge(size)
654+
{
655+
schedId = sh4_sched_register(0, [](int tag, int sch_cycl, int jitter, void *arg){
656+
return ((GDCartridge *)arg)->schedCallback();
657+
}, this);
658+
}
659+
660+
GDCartridge::~GDCartridge()
661+
{
662+
free(dimm_data);
663+
sh4_sched_unregister(schedId);
664+
}
665+
666+
u32 GDCartridge::ReadMem(u32 address, u32 size)
667+
{
668+
switch (address)
669+
{
670+
case NAOMI_DIMM_COMMAND:
671+
DEBUG_LOG(NAOMI, "DIMM COMMAND read -> %x", dimm_command);
672+
return dimm_command;
673+
case NAOMI_DIMM_OFFSETL:
674+
DEBUG_LOG(NAOMI, "DIMM OFFSETL read -> %x", dimm_offsetl);
675+
return dimm_offsetl;
676+
case NAOMI_DIMM_PARAMETERL:
677+
DEBUG_LOG(NAOMI, "DIMM PARAMETERL read -> %x", dimm_parameterl);
678+
return dimm_parameterl;
679+
case NAOMI_DIMM_PARAMETERH:
680+
DEBUG_LOG(NAOMI, "DIMM PARAMETERH read -> %x", dimm_parameterh);
681+
return dimm_parameterh;
682+
case NAOMI_DIMM_STATUS:
683+
{
684+
u32 rc = DIMM_STATUS & ~(((SB_ISTEXT >> 3) & 1) << 8);
685+
static u32 lastRc;
686+
if (rc != lastRc)
687+
DEBUG_LOG(NAOMI, "DIMM STATUS read -> %x", rc);
688+
lastRc = rc;
689+
return rc;
690+
}
691+
default:
692+
return NaomiCartridge::ReadMem(address, size);
693+
}
694+
}
695+
696+
void GDCartridge::WriteMem(u32 address, u32 data, u32 size)
697+
{
698+
switch (address)
699+
{
700+
case NAOMI_DIMM_COMMAND:
701+
dimm_command = data;
702+
DEBUG_LOG(NAOMI, "DIMM COMMAND Write<%d>: %x", size, data);
703+
return;
704+
705+
case NAOMI_DIMM_OFFSETL:
706+
dimm_offsetl = data;
707+
DEBUG_LOG(NAOMI, "DIMM OFFSETL Write<%d>: %x", size, data);
708+
return;
709+
case NAOMI_DIMM_PARAMETERL:
710+
dimm_parameterl = data;
711+
DEBUG_LOG(NAOMI, "DIMM PARAMETERL Write<%d>: %x", size, data);
712+
return;
713+
case NAOMI_DIMM_PARAMETERH:
714+
dimm_parameterh = data;
715+
DEBUG_LOG(NAOMI, "DIMM PARAMETERH Write<%d>: %x", size, data);
716+
return;
717+
718+
case NAOMI_DIMM_STATUS:
719+
DEBUG_LOG(NAOMI, "DIMM STATUS Write<%d>: %x", size, data);
720+
if (data & 0x100)
721+
// write 0 seems ignored
722+
asic_CancelInterrupt(holly_EXP_PCI);
723+
if ((data & 1) == 0)
724+
// irq to dimm
725+
process();
726+
return;
727+
728+
default:
729+
NaomiCartridge::WriteMem(address, data, size);
730+
return;
731+
}
732+
}
733+
734+
void GDCartridge::process()
735+
{
736+
INFO_LOG(NAOMI, "NetDIMM cmd %04x sock %d offset %04x paramh/l %04x %04x", (dimm_command >> 9) & 0x3f,
737+
dimm_command & 0xff, dimm_offsetl, dimm_parameterh, dimm_parameterl);
738+
739+
int cmdGroup = (dimm_command >> 13) & 3;
740+
int cmd = (dimm_command >> 9) & 0xf;
741+
switch (cmdGroup)
742+
{
743+
case 0: // system commands
744+
systemCmd(cmd);
745+
break;
746+
case 1: // network commands
747+
WARN_LOG(NAOMI, "Network command received cmd %x. Need full NetDIMM?", cmd);
748+
returnToNaomi(true, 0, -1);
749+
break;
750+
default:
751+
WARN_LOG(NAOMI, "Unknown DIMM command group %d cmd %x", cmdGroup, cmd);
752+
returnToNaomi(true, 0, -1);
753+
break;
754+
}
755+
}
756+
757+
void GDCartridge::returnToNaomi(bool failed, u16 offsetl, u32 parameter)
758+
{
759+
dimm_command = ((dimm_command & 0x7e00) + 0x400) | (failed ? 0xff : 0x4);
760+
dimm_offsetl = offsetl;
761+
dimm_parameterh = parameter >> 16;
762+
dimm_parameterl = parameter;
763+
verify(((SB_ISTEXT >> 3) & 1) == 0);
764+
asic_RaiseInterrupt(holly_EXP_PCI);
765+
}
766+
767+
void GDCartridge::systemCmd(int cmd)
768+
{
769+
switch (cmd)
770+
{
771+
case 0xf: // startup
772+
INFO_LOG(NAOMI, "NetDIMM startup");
773+
// bit 16,17: dimm0 size (none, 128, 256, 512)
774+
// bit 18,19: dimm1 size
775+
// bit 28: network enabled (network settings appear in bios menu)
776+
// bit 29: set
777+
// bit 30: gd-rom connected
778+
// bit 31: mobile/ppp network?
779+
// (| 30, 70, F0, 1F0, 3F0, 7F0)
780+
// | offset >> 20 (dimm buffers offset @ size - 16MB)
781+
// offset = (64MB << 0-5) - 16MB
782+
// vf4 forces this value to 0f000000 (256MB) if != 1f000000 (512MB)
783+
if (dimm_data_size == 512_MB)
784+
addrspace::write32(0xc01fc04, (3 << 16) | 0x60000000 | (dimm_data_size >> 20)); // dimm board config 1 x 512 MB
785+
else if (dimm_data_size == 256_MB)
786+
addrspace::write32(0xc01fc04, (2 << 16) | 0x60000000 | (dimm_data_size >> 20)); // dimm board config 1 x 256 MB
787+
else
788+
addrspace::write32(0xc01fc04, (1 << 16) | 0x60000000 | (dimm_data_size >> 20)); // dimm board config 1 x 128 MB
789+
addrspace::write32(0xc01fc0c, 0x1020000 | 0x264); // fw version 1.02
790+
// DIMM board serial Id
791+
{
792+
const u32 *serial = (u32 *)(getGameSerialId() + 0x20); // get only the serial id
793+
addrspace::write32(0xc01fc40, *serial++);
794+
addrspace::write32(0xc01fc44, *serial++);
795+
addrspace::write32(0xc01fc48, *serial++);
796+
addrspace::write32(0xc01fc4c, *serial++);
797+
}
798+
// SET_BASE_ADDRESS(0c000000, 0)
799+
dimm_command = 0x8600;
800+
dimm_offsetl = 0;
801+
dimm_parameterl = 0;
802+
dimm_parameterh = 0x0c00;
803+
asic_RaiseInterrupt(holly_EXP_PCI);
804+
sh4_sched_request(schedId, SH4_MAIN_CLOCK);
805+
806+
break;
807+
808+
case 0: // nop
809+
case 1: // control read
810+
case 3: // set base address
811+
case 4: // peek8
812+
case 5: // peek16
813+
case 6: // peek32
814+
case 8: // poke8
815+
case 9: // poke16
816+
case 10: // poke32
817+
// These are callbacks from naomi
818+
INFO_LOG(NAOMI, "System callback command %x", cmd);
819+
break;
820+
821+
default:
822+
WARN_LOG(NAOMI, "Unknown system command %x", cmd);
823+
break;
824+
}
825+
}
826+
827+
void GDCartridge::Serialize(Serializer &ser) const
828+
{
829+
NaomiCartridge::Serialize(ser);
830+
ser << dimm_command;
831+
ser << dimm_offsetl;
832+
ser << dimm_parameterl;
833+
ser << dimm_parameterh;
834+
sh4_sched_serialize(ser, schedId);
835+
}
836+
837+
void GDCartridge::Deserialize(Deserializer &deser)
838+
{
839+
NaomiCartridge::Deserialize(deser);
840+
if (deser.version() >= Deserializer::V53)
841+
{
842+
deser >> dimm_command;
843+
deser >> dimm_offsetl;
844+
deser >> dimm_parameterl;
845+
deser >> dimm_parameterh;
846+
sh4_sched_deserialize(deser, schedId);
847+
}
848+
}
849+
850+
int GDCartridge::schedCallback()
851+
{
852+
if (SB_ISTEXT & 8) // holly_EXP_PCI
853+
return SH4_MAIN_CLOCK;
854+
855+
// regularly peek the test request address
856+
peek<u32>(0xc01fc08);
857+
asic_RaiseInterrupt(holly_EXP_PCI);
858+
859+
u32 testRequest = addrspace::read32(0xc01fc08);
860+
if (testRequest & 1)
861+
{
862+
// bios dimm (fake) test
863+
addrspace::write32(0xc01fc08, testRequest & ~1);
864+
bool isMem;
865+
char *p = (char *)addrspace::writeConst(0xc01fd00, isMem, 4);
866+
strcpy(p, "CHECKING DIMM BD");
867+
p = (char *)addrspace::writeConst(0xc01fd10, isMem, 4);
868+
strcpy(p, "DIMM0 - GOOD");
869+
p = (char *)addrspace::writeConst(0xc01fd20, isMem, 4);
870+
strcpy(p, "DIMM1 - GOOD");
871+
p = (char *)addrspace::writeConst(0xc01fd30, isMem, 4);
872+
strcpy(p, "--- COMPLETED---");
873+
addrspace::write32(0xc01fc0c, 0x0102a264);
874+
}
875+
else if (testRequest != 0)
876+
{
877+
addrspace::write32(0xc01fc08, 0);
878+
addrspace::write32(0xc01fc0c, 0x03170100);
879+
INFO_LOG(NAOMI, "TEST REQUEST %x", testRequest);
880+
}
881+
882+
return SH4_MAIN_CLOCK;
883+
}

core/hw/naomi/gdcartridge.h

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,66 @@
99
* // copyright-holders:Olivier Galibert
1010
*
1111
*/
12-
13-
#ifndef CORE_HW_NAOMI_GDCARTRIDGE_H_
14-
#define CORE_HW_NAOMI_GDCARTRIDGE_H_
15-
12+
#pragma once
1613
#include "naomi_cart.h"
1714
#include "imgread/common.h"
1815

1916
class GDCartridge: public NaomiCartridge {
2017
public:
21-
GDCartridge(u32 size) : NaomiCartridge(size)
22-
{
23-
}
24-
~GDCartridge() override
25-
{
26-
free(dimm_data);
27-
}
18+
GDCartridge(u32 size);
19+
~GDCartridge() override;
20+
2821
void Init(LoadProgress *progress = nullptr, std::vector<u8> *digest = nullptr) override
2922
{
3023
device_start(progress, digest);
3124
device_reset();
3225
}
3326
void* GetDmaPtr(u32 &size) override;
3427
bool Read(u32 offset, u32 size, void* dst) override;
28+
u32 ReadMem(u32 address, u32 size) override;
29+
void WriteMem(u32 address, u32 data, u32 size) override;
3530

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

33+
void Serialize(Serializer &ser) const override;
34+
void Deserialize(Deserializer &deser) override;
35+
3836
protected:
37+
virtual void process();
38+
virtual int schedCallback();
39+
void returnToNaomi(bool failed, u16 offsetl, u32 parameter);
40+
41+
template<typename T>
42+
void peek(u32 address)
43+
{
44+
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4);
45+
int size;
46+
switch (sizeof(T))
47+
{
48+
case 1:
49+
size = 4;
50+
break;
51+
case 2:
52+
size = 5;
53+
break;
54+
case 4:
55+
size = 6;
56+
break;
57+
}
58+
dimm_command = ((address >> 16) & 0x1ff) | (size << 9) | 0x8000;
59+
dimm_offsetl = address & 0xffff;
60+
dimm_parameterl = 0;
61+
dimm_parameterh = 0;
62+
}
63+
3964
u8 *dimm_data = nullptr;
4065
u32 dimm_data_size = 0;
66+
u16 dimm_command;
67+
u16 dimm_offsetl;
68+
u16 dimm_parameterl;
69+
u16 dimm_parameterh;
70+
static constexpr u16 DIMM_STATUS = 0x111;
71+
int schedId;
4172

4273
private:
4374
enum { FILENAME_LENGTH=24 };
@@ -70,6 +101,5 @@ class GDCartridge: public NaomiCartridge {
70101
u64 des_encrypt_decrypt(u64 src, const u32 *des_subkeys);
71102
u64 rev64(u64 src);
72103
void read_gdrom(Disc *gdrom, u32 sector, u8* dst, u32 count = 1, LoadProgress *progress = nullptr);
104+
void systemCmd(int cmd);
73105
};
74-
75-
#endif /* CORE_HW_NAOMI_GDCARTRIDGE_H_ */

core/hw/naomi/naomi.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,20 @@ void naomi_reg_Init()
217217
dmaSchedId = sh4_sched_register(0, naomiDmaSched);
218218
}
219219

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

227+
// Return the protected data from the rom board serial eeprom (112 bytes)
228+
// excluding response to reset and passwords.
229+
const u8 *getGameSerialId()
230+
{
231+
return romSerialId.getProtectedData();
232+
}
233+
225234
void naomi_reg_Term()
226235
{
227236
if (multiboard != nullptr)

core/hw/naomi/naomi.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ u16 NaomiBoardIDRead();
1919
u16 NaomiGameIDRead();
2020
void NaomiGameIDWrite(u16 data);
2121
void setGameSerialId(const u8 *data);
22+
const u8 *getGameSerialId();
2223

2324
void initDriveSimSerialPipe();
2425
void Naomi_setDmaDelay();
@@ -60,7 +61,7 @@ static inline u32 g2ext_readMem(u32 addr, u32 size)
6061
if (multiboard != nullptr)
6162
return multiboard->readG2Ext(addr, size);
6263

63-
INFO_LOG(NAOMI, "Unhandled G2 Ext read<%d> at %x", size, addr);
64+
DEBUG_LOG(NAOMI, "Unhandled G2 Ext read<%d> at %x", size, addr);
6465
return 0;
6566
}
6667

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

0 commit comments

Comments
 (0)