diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj
index c005d8c2cb..368304870d 100644
--- a/Source/Core/Core/Core.vcproj
+++ b/Source/Core/Core/Core.vcproj
@@ -710,6 +710,14 @@
RelativePath=".\Src\Hw\EXI_DeviceAD16.h"
>
+
+
+
+
@@ -782,6 +790,14 @@
RelativePath=".\Src\HW\SI_Device.h"
>
+
+
+
+
diff --git a/Source/Core/Core/Src/HW/AudioInterface.cpp b/Source/Core/Core/Src/HW/AudioInterface.cpp
index 699257e4ec..fd8ba2363f 100644
--- a/Source/Core/Core/Src/HW/AudioInterface.cpp
+++ b/Source/Core/Core/Src/HW/AudioInterface.cpp
@@ -196,7 +196,7 @@ void Write32(const u32 _Value, const u32 _Address)
// This is the only new code in this ~3,326 revision, it seems to avoid hanging Crazy Taxi,
// while the 1080 and Wave Race music still works
- if (!tmpAICtrl.PSTAT) DVDInterface::m_bStream = false;
+ if (!tmpAICtrl.PSTAT) DVDInterface::g_bStream = false;
}
// AI Interrupt
diff --git a/Source/Core/Core/Src/HW/DVDInterface.cpp b/Source/Core/Core/Src/HW/DVDInterface.cpp
index 435520ee2c..e7b59e963a 100644
--- a/Source/Core/Core/Src/HW/DVDInterface.cpp
+++ b/Source/Core/Core/Src/HW/DVDInterface.cpp
@@ -31,26 +31,6 @@
namespace DVDInterface
{
-/*
-20975: 00000000 DVD (zzz_80146b84 ??, 0x80146bf8) : DVD(r): 0xcc006004
-20976: 00000000 DVD (zzz_80146b84 ??, 0x80146c00) : DVD(w): 0x00000000 @ 0xcc006004
-20977: 00000000 DVD (DVDLowRead, 0x801448a8) : DVD(w): 0x00000020 @ 0xcc006018
-20978: 00000000 DVD (Read, 0x80144744) : DVD(w): 0xa8000000 @ 0xcc006008
-20979: 00000000 DVD (Read, 0x80144750) : DVD(w): 0x01094227 @ 0xcc00600c
-20980: 00000000 DVD (Read, 0x80144758) : DVD(w): 0x00000020 @ 0xcc006010
-20981: 00000000 DVD (Read, 0x8014475c) : DVD(w): 0x8167cc80 @ 0xcc006014
-20982: 00000000 DVD (Read, 0x80144760) : DVD(w): 0x00000020 @ 0xcc006018
-20983: 00000000 DVD (Read, 0x80144768) : DVD(w): 0x00000003 @ 0xcc00601c
-20984: 00000000 DVD: DVD: Read ISO: DVDOffset=0425089c, DMABuffer=0167cc80, SrcLength=00000020, DMALength=00000020
-20989: 00000000 DVD (zzz_801442fc ??, 0x80144388) : DVD(r): 0xcc006000
-20990: 00000000 DVD (zzz_801442fc ??, 0x801443d8) : DVD(w): 0x0000003a @ 0xcc006000
-20992: 00000000 DVD (zzz_801442fc ??, 0x801444d0) : DVD(w): 0x00000000 @ 0xcc006004
-20993: 00000000 DVD (zzz_80146e44 ??, 0x80146fcc) : DVD(r): 0xcc006018
-
-After this, Cubivore infinitely calls DVDGetDriveStatus, which does not even
-bother to check any DVD regs. Waiting for interrupt?
-*/
-
// internal hardware addresses
enum
{
@@ -89,15 +69,15 @@ enum
union UDISR
{
u32 Hex;
- struct
- {
- unsigned BREAK : 1; // Stop the Device + Interrupt
- unsigned DEINITMASK : 1; // Access Device Error Int Mask
- unsigned DEINT : 1; // Access Device Error Int
- unsigned TCINTMASK : 1; // Transfer Complete Int Mask
- unsigned TCINT : 1; // Transfer Complete Int
+ struct
+ {
+ unsigned BREAK : 1; // Stop the Device + Interrupt
+ unsigned DEINITMASK : 1; // Access Device Error Int Mask
+ unsigned DEINT : 1; // Access Device Error Int
+ unsigned TCINTMASK : 1; // Transfer Complete Int Mask
+ unsigned TCINT : 1; // Transfer Complete Int
unsigned BRKINTMASK : 1;
- unsigned BRKINT : 1; // w 1: clear brkint
+ unsigned BRKINT : 1; // w 1: clear brkint
unsigned : 25;
};
UDISR() {Hex = 0;}
@@ -108,22 +88,39 @@ union UDISR
union UDICVR
{
u32 Hex;
- struct
- {
- unsigned CVR : 1; // 0: Cover closed 1: Cover open
- unsigned CVRINTMASK : 1; // 1: Interrupt enabled;
- unsigned CVRINT : 1; // r 1: Interrupt requested w 1: Interrupt clear
+ struct
+ {
+ unsigned CVR : 1; // 0: Cover closed 1: Cover open
+ unsigned CVRINTMASK : 1; // 1: Interrupt enabled
+ unsigned CVRINT : 1; // r 1: Interrupt requested w 1: Interrupt clear
unsigned : 29;
};
UDICVR() {Hex = 0;}
UDICVR(u32 _hex) {Hex = _hex;}
};
-// DI DMA Address Register
-union UDIDMAAddressRegister
+union UDICMDBUF
{
u32 Hex;
- struct
+ struct
+ {
+ u8 CMDBYTE3;
+ u8 CMDBYTE2;
+ u8 CMDBYTE1;
+ u8 CMDBYTE0;
+ };
+};
+
+// DI DMA Address Register
+union UDIMAR
+{
+ u32 Hex;
+ struct
+ {
+ unsigned Zerobits : 5; // Must be zero (32byte aligned)
+ unsigned : 27;
+ };
+ struct
{
unsigned Address : 26;
unsigned : 6;
@@ -131,71 +128,81 @@ union UDIDMAAddressRegister
};
// DI DMA Address Length Register
-union UDIDMAAddressLength
+union UDILENGTH
{
u32 Hex;
- struct
+ struct
{
- unsigned Length : 26;
+ unsigned Zerobits : 5; // Must be zero (32byte aligned)
+ unsigned : 27;
+ };
+ struct
+ {
+ unsigned Length : 26;
unsigned : 6;
};
};
// DI DMA Control Register
-union UDIDMAControlRegister
+union UDICR
{
u32 Hex;
- struct
+ struct
{
- unsigned TSTART : 1; // w:1 start r:0 ready
- unsigned DMA : 1; // 1: DMA Mode 0: Immediate Mode (can only do Access Register Command)
- unsigned RW : 1; // 0: Read Command (DVD to Memory) 1: Write COmmand (Memory to DVD)
+ unsigned TSTART : 1; // w:1 start r:0 ready
+ unsigned DMA : 1; // 1: DMA Mode 0: Immediate Mode (can only do Access Register Command)
+ unsigned RW : 1; // 0: Read Command (DVD to Memory) 1: Write COmmand (Memory to DVD)
unsigned : 29;
};
};
-// DI Config Register
-union UDIConfigRegister
+union UDIIMMBUF
{
u32 Hex;
- struct
+ struct
+ {
+ u8 REGVAL3;
+ u8 REGVAL2;
+ u8 REGVAL1;
+ u8 REGVAL0;
+ };
+};
+
+// DI Config Register
+union UDICFG
+{
+ u32 Hex;
+ struct
{
unsigned CONFIG : 8;
unsigned : 24;
};
- UDIConfigRegister() {Hex = 0;}
- UDIConfigRegister(u32 _hex) {Hex = _hex;}
+ UDICFG() {Hex = 0;}
+ UDICFG(u32 _hex) {Hex = _hex;}
};
-// HACK to allow multi-command debug-mode transfers
-struct SDIDebugTransfer
-{
- u32 Address;
- u16 Length;
- bool InProgress;
-};
-
-// hardware registers
-struct DVDMemStruct
-{
- UDISR StatusReg;
- UDICVR CoverReg;
- u32 Command[3];
- UDIDMAAddressRegister DMAAddress;
- UDIDMAAddressLength DMALength;
- UDIDMAControlRegister DMAControlReg;
- u32 Immediate;
- UDIConfigRegister ConfigReg;
- u32 AudioStart;
- u32 AudioPos;
- u32 AudioLength;
- SDIDebugTransfer DebugTransfer;
-};
// STATE_TO_SAVE
-DVDMemStruct dvdMem;
-u32 g_ErrorCode = 0x00;
+// hardware registers
+static UDISR m_DISR;
+static UDICVR m_DICVR;
+static UDICMDBUF m_DICMDBUF[3];
+static UDIMAR m_DIMAR;
+static UDILENGTH m_DILENGTH;
+static UDICR m_DICR;
+static UDIIMMBUF m_DIIMMBUF;
+static UDICFG m_DICFG;
+
+static u32 AudioStart;
+static u32 AudioPos;
+static u32 AudioLength;
+
+u32 g_ErrorCode = 0;
bool g_bDiscInside = false;
+bool g_bStream = false;
+
+// GC-AM only
+static unsigned char media_buffer[0x40];
Common::CriticalSection dvdread_section;
@@ -208,23 +215,35 @@ void ChangeDiscCallback(u64 userdata, int cyclesLate);
void DoState(PointerWrap &p)
{
- p.Do(dvdMem);
+ p.Do(m_DISR);
+ p.Do(m_DICVR);
+ p.DoArray(m_DICMDBUF, 3);
+ p.Do(m_DIMAR);
+ p.Do(m_DILENGTH);
+ p.Do(m_DICR);
+ p.Do(m_DIIMMBUF);
+ p.Do(m_DICFG);
+
+ p.Do(AudioStart);
+ p.Do(AudioPos);
+ p.Do(AudioLength);
+
p.Do(g_ErrorCode);
p.Do(g_bDiscInside);
}
void UpdateInterrupts();
void GenerateDVDInterrupt(DVDInterruptType _DVDInterrupt);
-void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg);
+void ExecuteCommand(UDICR& _DICR);
static int et_GenerateDVDInterrupt;
-static void GenerateDVDInterrupt_Wrapper(u64 userdata, int cyclesLate)
+static void GenerateDVDInterruptCallback(u64 userdata, int cyclesLate)
{
GenerateDVDInterrupt((DVDInterruptType)userdata);
}
-static void GenerateDVDInterruptFromDVDThread(DVDInterruptType type)
+static void GenerateDVDInterrupt_Threadsafe(DVDInterruptType type)
{
CoreTiming::ScheduleEvent_Threadsafe(0, et_GenerateDVDInterrupt, type);
}
@@ -238,8 +257,8 @@ static THREAD_RETURN DVDThreadFunc(void* arg)
if (g_dvdQuitSignal)
break;
- if (dvdMem.DMAControlReg.TSTART)
- ExecuteCommand(dvdMem.DMAControlReg);
+ if (m_DICR.TSTART)
+ ExecuteCommand(m_DICR);
}
return 0;
@@ -247,21 +266,23 @@ static THREAD_RETURN DVDThreadFunc(void* arg)
void Init()
{
- dvdMem.StatusReg.Hex = 0;
- dvdMem.CoverReg.Hex = 0;
- dvdMem.Command[0] = 0;
- dvdMem.Command[1] = 0;
- dvdMem.Command[2] = 0;
- dvdMem.DMAAddress.Hex = 0;
- dvdMem.DMALength.Hex = 0;
- dvdMem.DMAControlReg.Hex = 0;
- dvdMem.Immediate = 0;
- dvdMem.ConfigReg.Hex = 0;
- dvdMem.AudioStart = 0;
- dvdMem.AudioPos = 0;
- dvdMem.AudioLength = 0;
+ m_DISR.Hex = 0;
+ m_DICVR.Hex = 0;
+ m_DICMDBUF[0].Hex= 0;
+ m_DICMDBUF[1].Hex= 0;
+ m_DICMDBUF[2].Hex= 0;
+ m_DIMAR.Hex = 0;
+ m_DILENGTH.Hex = 0;
+ m_DICR.Hex = 0;
+ m_DIIMMBUF.Hex = 0;
+ m_DICFG.Hex = 0;
+ m_DICFG.CONFIG = 1; // Disable bootrom descrambler
- et_GenerateDVDInterrupt = CoreTiming::RegisterEvent("DVDint", GenerateDVDInterrupt_Wrapper);
+ AudioStart = 0;
+ AudioPos = 0;
+ AudioLength = 0;
+
+ et_GenerateDVDInterrupt = CoreTiming::RegisterEvent("DVDint", GenerateDVDInterruptCallback);
g_dvdAlert.Init();
g_dvdThread = new Common::Thread(DVDThreadFunc, NULL);
@@ -291,7 +312,7 @@ void Shutdown()
void SetDiscInside(bool _DiscInside)
{
- g_bDiscInside = _DiscInside;
+ g_bDiscInside = _DiscInside;
}
bool IsDiscInside()
@@ -346,19 +367,19 @@ void ChangeDisc(const char* _FileName)
void SetLidOpen(bool _bOpen)
{
- dvdMem.CoverReg.CVR = _bOpen ? 1 : 0;
+ m_DICVR.CVR = _bOpen ? 1 : 0;
- GenerateDVDInterrupt(INT_CVRINT);
+ GenerateDVDInterrupt_Threadsafe(INT_CVRINT);
}
bool IsLidOpen()
{
- return (dvdMem.CoverReg.CVR == 1);
+ return (m_DICVR.CVR == 1);
}
void ClearCoverInterrupt()
{
- dvdMem.CoverReg.CVRINT = 0;
+ m_DICVR.CVRINT = 0;
}
bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength)
@@ -372,7 +393,7 @@ bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength)
bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples)
{
- if (dvdMem.AudioPos == 0)
+ if (AudioPos == 0)
{
//MessageBox(0,"DVD: Trying to stream from 0", "bah", 0);
memset(_pDestBuffer, 0, _iNumSamples); // probably __AI_SRC_INIT :P
@@ -380,7 +401,7 @@ bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples)
}
_iNumSamples &= ~31;
dvdread_section.Enter();
- VolumeHandler::ReadToPtr(_pDestBuffer, dvdMem.AudioPos, _iNumSamples);
+ VolumeHandler::ReadToPtr(_pDestBuffer, AudioPos, _iNumSamples);
dvdread_section.Leave();
//
@@ -388,63 +409,57 @@ bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples)
//
// loop check
//
- dvdMem.AudioPos += _iNumSamples;
- if (dvdMem.AudioPos >= dvdMem.AudioStart + dvdMem.AudioLength)
+ AudioPos += _iNumSamples;
+ if (AudioPos >= AudioStart + AudioLength)
{
- dvdMem.AudioPos = dvdMem.AudioStart;
+ AudioPos = AudioStart;
NGCADPCM::InitFilter();
}
- //LOG(DVDINTERFACE,"ReadADPCM");
+ //WARN_LOG(DVDINTERFACE,"ReadADPCM");
return true;
}
void Read32(u32& _uReturnValue, const u32 _iAddress)
{
- DEBUG_LOG(DVDINTERFACE, "DVD(r): 0x%08x", _iAddress);
-
- switch (_iAddress & 0xFFF)
+ switch (_iAddress & 0xFF)
{
- case DI_STATUS_REGISTER: _uReturnValue = dvdMem.StatusReg.Hex; return;
- case DI_COVER_REGISTER: _uReturnValue = dvdMem.CoverReg.Hex; return;
- case DI_COMMAND_0: _uReturnValue = dvdMem.Command[0]; return;
- case DI_COMMAND_1: _uReturnValue = dvdMem.Command[1]; return;
- case DI_COMMAND_2: _uReturnValue = dvdMem.Command[2]; return;
- case DI_DMA_ADDRESS_REGISTER: _uReturnValue = dvdMem.DMAAddress.Hex; return;
- case DI_DMA_LENGTH_REGISTER: _uReturnValue = dvdMem.DMALength.Hex; return;
- case DI_DMA_CONTROL_REGISTER: _uReturnValue = dvdMem.DMAControlReg.Hex; return;
- case DI_IMMEDIATE_DATA_BUFFER: _uReturnValue = dvdMem.Immediate; return;
- case DI_CONFIG_REGISTER:
- {
- dvdMem.ConfigReg.Hex = 0x000000FF;
- _uReturnValue = dvdMem.ConfigReg.Hex;
- return;
- }
+ case DI_STATUS_REGISTER: _uReturnValue = m_DISR.Hex; break;
+ case DI_COVER_REGISTER: _uReturnValue = m_DICVR.Hex; break;
+ case DI_COMMAND_0: _uReturnValue = m_DICMDBUF[0].Hex; break;
+ case DI_COMMAND_1: _uReturnValue = m_DICMDBUF[1].Hex; break;
+ case DI_COMMAND_2: _uReturnValue = m_DICMDBUF[2].Hex; break;
+ case DI_DMA_ADDRESS_REGISTER: _uReturnValue = m_DIMAR.Hex; break;
+ case DI_DMA_LENGTH_REGISTER: _uReturnValue = m_DILENGTH.Hex; break;
+ case DI_DMA_CONTROL_REGISTER: _uReturnValue = m_DICR.Hex; break;
+ case DI_IMMEDIATE_DATA_BUFFER: _uReturnValue = m_DIIMMBUF.Hex; break;
+ case DI_CONFIG_REGISTER: _uReturnValue = m_DICFG.Hex; break;
default:
- _dbg_assert_(DVDINTERFACE,0);
+ _dbg_assert_(DVDINTERFACE, 0);
+ _uReturnValue = 0;
+ break;
}
-
- _uReturnValue = 0;
+ DEBUG_LOG(DVDINTERFACE, "(r32): 0x%08x - 0x%08x", _iAddress, _uReturnValue);
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
- DEBUG_LOG(DVDINTERFACE, "DVD(w): 0x%08x @ 0x%08x", _iValue, _iAddress);
+ DEBUG_LOG(DVDINTERFACE, "(w32): 0x%08x @ 0x%08x", _iValue, _iAddress);
- switch (_iAddress & 0x3FF)
+ switch (_iAddress & 0xFF)
{
case DI_STATUS_REGISTER:
{
UDISR tmpStatusReg(_iValue);
- dvdMem.StatusReg.DEINITMASK = tmpStatusReg.DEINITMASK;
- dvdMem.StatusReg.TCINTMASK = tmpStatusReg.TCINTMASK;
- dvdMem.StatusReg.BRKINTMASK = tmpStatusReg.BRKINTMASK;
-
- if (tmpStatusReg.DEINT) dvdMem.StatusReg.DEINT = 0;
- if (tmpStatusReg.TCINT) dvdMem.StatusReg.TCINT = 0;
- if (tmpStatusReg.BRKINT) dvdMem.StatusReg.BRKINT = 0;
+ m_DISR.DEINITMASK = tmpStatusReg.DEINITMASK;
+ m_DISR.TCINTMASK = tmpStatusReg.TCINTMASK;
+ m_DISR.BRKINTMASK = tmpStatusReg.BRKINTMASK;
+
+ if (tmpStatusReg.DEINT) m_DISR.DEINT = 0;
+ if (tmpStatusReg.TCINT) m_DISR.TCINT = 0;
+ if (tmpStatusReg.BRKINT) m_DISR.BRKINT = 0;
if (tmpStatusReg.BREAK)
{
@@ -459,38 +474,45 @@ void Write32(const u32 _iValue, const u32 _iAddress)
{
UDICVR tmpCoverReg(_iValue);
- dvdMem.CoverReg.CVRINTMASK = tmpCoverReg.CVRINTMASK;
+ m_DICVR.CVRINTMASK = tmpCoverReg.CVRINTMASK;
+
+ if (tmpCoverReg.CVRINT) m_DICVR.CVRINT = 0;
- if (tmpCoverReg.CVRINT) dvdMem.CoverReg.CVRINT = 0;
-
UpdateInterrupts();
}
break;
- case DI_COMMAND_0: dvdMem.Command[0] = _iValue; break;
- case DI_COMMAND_1: dvdMem.Command[1] = _iValue; break;
- case DI_COMMAND_2: dvdMem.Command[2] = _iValue; break;
+ case DI_COMMAND_0: m_DICMDBUF[0].Hex = _iValue; break;
+ case DI_COMMAND_1: m_DICMDBUF[1].Hex = _iValue; break;
+ case DI_COMMAND_2: m_DICMDBUF[2].Hex = _iValue; break;
case DI_DMA_ADDRESS_REGISTER:
{
- dvdMem.DMAAddress.Hex = _iValue;
- _dbg_assert_(DVDINTERFACE, ((dvdMem.DMAAddress.Hex & 0x1F) == 0));
+ m_DIMAR.Hex = _iValue;
+ _dbg_assert_msg_(DVDINTERFACE, m_DIMAR.Zerobits == 0, "DMA Addr not 32byte aligned!");
+ }
+ break;
+ case DI_DMA_LENGTH_REGISTER:
+ {
+ m_DILENGTH.Hex = _iValue;
+ _dbg_assert_msg_(DVDINTERFACE, m_DILENGTH.Zerobits == 0, "DMA Length not 32byte aligned!");
}
break;
- case DI_DMA_LENGTH_REGISTER: dvdMem.DMALength.Hex = _iValue; break;
case DI_DMA_CONTROL_REGISTER:
{
- dvdMem.DMAControlReg.Hex = _iValue;
+ m_DICR.Hex = _iValue;
+ // The thread loop checks if TSTART is set, don't need to check here
g_dvdAlert.Set();
}
break;
- case DI_IMMEDIATE_DATA_BUFFER: dvdMem.Immediate = _iValue; break;
+ case DI_IMMEDIATE_DATA_BUFFER: m_DIIMMBUF.Hex = _iValue; break;
+
case DI_CONFIG_REGISTER:
{
- UDIConfigRegister tmpConfigReg(_iValue);
-
- dvdMem.ConfigReg.CONFIG = tmpConfigReg.CONFIG;
+ UDICFG tmpConfigReg(_iValue);
+ m_DICFG.CONFIG = tmpConfigReg.CONFIG;
+ WARN_LOG(DVDINTERFACE, "Write to DICFG, should be read-only");
}
break;
@@ -502,10 +524,10 @@ void Write32(const u32 _iValue, const u32 _iAddress)
void UpdateInterrupts()
{
- if ((dvdMem.StatusReg.DEINT & dvdMem.StatusReg.DEINITMASK) ||
- (dvdMem.StatusReg.TCINT & dvdMem.StatusReg.TCINTMASK) ||
- (dvdMem.StatusReg.BRKINT & dvdMem.StatusReg.BRKINTMASK) ||
- (dvdMem.CoverReg.CVRINT & dvdMem.CoverReg.CVRINTMASK))
+ if ((m_DISR.DEINT & m_DISR.DEINITMASK) ||
+ (m_DISR.TCINT & m_DISR.TCINTMASK) ||
+ (m_DISR.BRKINT & m_DISR.BRKINTMASK) ||
+ (m_DICVR.CVRINT & m_DICVR.CVRINTMASK))
{
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DI, true);
}
@@ -519,53 +541,47 @@ void GenerateDVDInterrupt(DVDInterruptType _DVDInterrupt)
{
switch(_DVDInterrupt)
{
- case INT_DEINT: dvdMem.StatusReg.DEINT = 1; break;
- case INT_TCINT: dvdMem.StatusReg.TCINT = 1; break;
- case INT_BRKINT: dvdMem.StatusReg.BRKINT = 1; break;
- case INT_CVRINT: dvdMem.CoverReg.CVRINT = 1; break;
+ case INT_DEINT: m_DISR.DEINT = 1; break;
+ case INT_TCINT: m_DISR.TCINT = 1; break;
+ case INT_BRKINT: m_DISR.BRKINT = 1; break;
+ case INT_CVRINT: m_DICVR.CVRINT = 1; break;
}
UpdateInterrupts();
}
-bool m_bStream = false;
-
-void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg)
+void ExecuteCommand(UDICR& _DICR)
{
- _dbg_assert_(DVDINTERFACE, _DMAControlReg.RW == 0); // only DVD to Memory
+// _dbg_assert_(DVDINTERFACE, _DICR.RW == 0); // only DVD to Memory
+ int GCAM = ((SConfig::GetInstance().m_SIDevice[0] == SI_AM_BASEBOARD)
+ && (SConfig::GetInstance().m_EXIDevice[2] == EXIDEVICE_AM_BASEBOARD))
+ ? 1 : 0;
- // Catch multi-command transfers here
- if (dvdMem.DebugTransfer.InProgress)
+ if (GCAM)
{
- dvdMem.DebugTransfer.InProgress = false;
- // If we ever need to actually read/write the drive ram/cache, here would be the place
- // Up to 12bytes can be written at once (dvdMem.Command[0] through dvdMem.Command[2])
- INFO_LOG(DVDINTERFACE, "\t queued cmd: 0x%08x @ 0x%08x NOT IMPLEMENTED",
- dvdMem.Command[0], dvdMem.DebugTransfer.Address);
+ ERROR_LOG(DVDINTERFACE, "DVD: %08x, %08x, %08x, DMA=addr:%08x,len:%08x,ctrl:%08x",
+ m_DICMDBUF[0], m_DICMDBUF[1], m_DICMDBUF[2], m_DIMAR, m_DILENGTH, m_DICR);
+ // decrypt command. But we have a zero key, that simplifies things a lot.
+ // If you get crazy dvd command errors, make sure 0x80000000 - 0x8000000c is zero'd
+ m_DICMDBUF[0].Hex <<= 24;
}
- else
- { // The huge switch is in this else!
- switch ((dvdMem.Command[0] & 0xFF000000) >> 24)
+
+
+ switch (m_DICMDBUF[0].CMDBYTE0)
{
- //=========================================================================================================
- // DRIVE INFO (DMA)
- // Command/Subcommand/Padding <- 12000000
- // Command0 <- 0
- // Command1 <- 0x20
- // Command2 <- Address in ram of the buffer
- //
- // output buffer:
- // 0000-0001 revisionLevel
- // 0002-0003 deviceCode
- // 0004-0007 releaseDate
- // 0008-001F padding(0)
- //=========================================================================================================
case DVDLowInquiry:
+ if (GCAM)
+ {
+ // 0x29484100...
+ // was 21 i'm not entirely sure about this, but it works well.
+ m_DIIMMBUF.Hex = 0x21000000;
+ }
+ else
{
// small safety check, dunno if it's needed
- if ((dvdMem.Command[1] == 0) && (dvdMem.DMALength.Length == 0x20))
+ if ((m_DICMDBUF[1].Hex == 0) && (m_DILENGTH.Length == 0x20))
{
- u8* driveInfo = Memory::GetPointer(dvdMem.DMAAddress.Address);
+ u8* driveInfo = Memory::GetPointer(m_DIMAR.Address);
// gives the correct output in GCOS - 06 2001/08 (61)
// there may be other stuff missing ?
driveInfo[4] = 0x20;
@@ -581,218 +597,317 @@ void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg)
}
break;
- //=========================================================================================================
- // SET EXTENSION
- // Apparently the drive needs certain flags set explicitly?
- //=========================================================================================================
+ // "Set Extension"...not sure what it does
case 0x55:
- INFO_LOG(DVDINTERFACE, "SetExtension %x", _DMAControlReg);
+ INFO_LOG(DVDINTERFACE, "SetExtension");
break;
- //=========================================================================================================
- // READ (DMA)
- // Command/Subcommand/Padding <- A8000000
- // Command0 <- Position on DVD shr 2
- // Command1 <- Length of the read
- // Command2 <- Address in ram of the buffer
- //=========================================================================================================
+ // DMA Read from Disc
case 0xA8:
+ if (g_bDiscInside)
{
- if (g_bDiscInside)
+ switch (m_DICMDBUF[0].CMDBYTE3)
{
- u32 iDVDOffset = dvdMem.Command[1] << 2;
- u32 iSrcLength = dvdMem.Command[2];
-
- INFO_LOG(DVDINTERFACE, "Read ISO: DVDOffset=%08x, DMABuffer=%08x, SrcLength=%08x, DMALength=%08x",
- iDVDOffset, dvdMem.DMAAddress.Address, iSrcLength, dvdMem.DMALength.Length);
- _dbg_assert_(DVDINTERFACE, iSrcLength == dvdMem.DMALength.Length);
-
- if (!DVDRead(iDVDOffset, dvdMem.DMAAddress.Address, dvdMem.DMALength.Length))
+ case 0x00: // Read Sector
{
+ u32 iDVDOffset = m_DICMDBUF[1].Hex << 2;
+ u32 iSrcLength = m_DICMDBUF[2].Hex;
+
+ DEBUG_LOG(DVDINTERFACE, "Read: DVDOffset=%08x, DMABuffer=%08x, SrcLength=%08x, DMALength=%08x",
+ iDVDOffset, m_DIMAR.Address, iSrcLength, m_DILENGTH.Length);
+ _dbg_assert_(DVDINTERFACE, iSrcLength == m_DILENGTH.Length);
+
+ if (GCAM)
+ {
+ if (iDVDOffset & 0x80000000) // read request to hardware buffer
+ {
+ switch (iDVDOffset)
+ {
+ case 0x80000000:
+ ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (80000000)");
+ for (unsigned int i = 0; i < m_DILENGTH.Length / 4; i++)
+ Memory::Write_U32(0, m_DIMAR.Address + i * 4);
+ break;
+ case 0x80000040:
+ ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (2) (80000040)");
+ for (unsigned int i = 0; i < m_DILENGTH.Length / 4; i++)
+ Memory::Write_U32(~0, m_DIMAR.Address + i * 4);
+ Memory::Write_U32(0x00000020, m_DIMAR.Address); // DIMM SIZE, LE
+ Memory::Write_U32(0x4743414D, m_DIMAR.Address + 4); // GCAM signature
+ break;
+ case 0x80000120:
+ ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000120)");
+ for (unsigned int i = 0; i < m_DILENGTH.Length / 4; i++)
+ Memory::Write_U32(0x01010101, m_DIMAR.Address + i * 4);
+ break;
+ case 0x80000140:
+ ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000140)");
+ for (unsigned int i = 0; i < m_DILENGTH.Length / 4; i++)
+ Memory::Write_U32(0x01010101, m_DIMAR.Address + i * 4);
+ break;
+ case 0x84000020:
+ ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (1) (84000020)");
+ for (unsigned int i = 0; i < m_DILENGTH.Length / 4; i++)
+ Memory::Write_U32(0x00000000, m_DIMAR.Address + i * 4);
+ break;
+ default:
+ ERROR_LOG(DVDINTERFACE, "GC-AM: UNKNOWN MEDIA BOARD LOCATION %x", iDVDOffset);
+ break;
+ }
+ break;
+ }
+ else if ((iDVDOffset == 0x1f900000) || (iDVDOffset == 0x1f900020))
+ {
+ ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD COMM AREA (1f900020)");
+ memcpy(Memory::GetPointer(m_DIMAR.Address), media_buffer + iDVDOffset - 0x1f900000, m_DILENGTH.Length);
+ unsigned int i;
+ for (i = 0; i < m_DILENGTH.Length; i += 4)
+ ERROR_LOG(DVDINTERFACE, "GC-AM: %08x", Memory::Read_U32(m_DIMAR.Address + i));
+ break;
+ }
+ }
+
+ // Here is the actual Disk Reading
+ if (!DVDRead(iDVDOffset, m_DIMAR.Address, m_DILENGTH.Length))
+ {
+ PanicAlert("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
+ }
+ }
+ break;
+
+ case 0x40: // Read DiscID
+ _dbg_assert_(DVDINTERFACE, m_DICMDBUF[1].Hex == 0);
+ _dbg_assert_(DVDINTERFACE, m_DICMDBUF[1].Hex == m_DILENGTH.Length);
+ _dbg_assert_(DVDINTERFACE, m_DILENGTH.Length == 0x20);
+ if (!DVDRead(m_DICMDBUF[1].Hex, m_DIMAR.Address, m_DILENGTH.Length))
PanicAlert("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
+ break;
+
+ default:
+ _dbg_assert_msg_(DVDINTERFACE, 0, "Unknown Read Subcommand");
+ break;
+ }
+ }
+ else
+ {
+ // there is no disc to read
+ _DICR.TSTART = 0;
+ m_DILENGTH.Length = 0;
+ g_ErrorCode = ERROR_NO_DISK | ERROR_COVER_H;
+ GenerateDVDInterrupt_Threadsafe(INT_DEINT);
+ return;
+ }
+ break;
+
+ // GC-AM
+ case 0xAA:
+ if (GCAM)
+ {
+ ERROR_LOG(DVDINTERFACE, "GC-AM: 0xAA, DMABuffer=%08x, DMALength=%08x", m_DIMAR.Address, m_DILENGTH.Length);
+ u32 iDVDOffset = m_DICMDBUF[1].Hex << 2;
+ unsigned int len = m_DILENGTH.Length;
+ int offset = iDVDOffset - 0x1F900000;
+ /*
+ if (iDVDOffset == 0x84800000)
+ {
+ ERROR_LOG(DVDINTERFACE, "firmware upload");
+ }
+ else*/
+ if ((offset < 0) || ((offset + len) > 0x40) || len > 0x40)
+ {
+ unsigned long addr = m_DIMAR.Address;
+ if (iDVDOffset == 0x84800000) {
+ ERROR_LOG(DVDINTERFACE, "FIRMWARE UPLOAD");
+ } else {
+ ERROR_LOG(DVDINTERFACE, "ILLEGAL MEDIA WRITE");
+ }
+ while (len >= 4)
+ {
+ ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08x: %08x", iDVDOffset, Memory::Read_U32(addr));
+ addr += 4;
+ len -= 4;
+ iDVDOffset += 4;
}
}
else
{
- // there is no disc to read
- _DMAControlReg.TSTART = 0;
- dvdMem.DMALength.Length = 0;
- GenerateDVDInterruptFromDVDThread(INT_DEINT);
- g_ErrorCode = ERROR_NO_DISK | ERROR_COVER_H;
- return;
+ unsigned long addr = m_DIMAR.Address;
+ memcpy(media_buffer + offset, Memory::GetPointer(addr), len);
+ while (len >= 4)
+ {
+ ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08x: %08x", iDVDOffset, Memory::Read_U32(addr));
+ addr += 4;
+ len -= 4;
+ iDVDOffset += 4;
+ }
}
}
break;
- //=========================================================================================================
- // SEEK (Immediate)
- // Command/Subcommand/Padding <- AB000000
- // Command0 <- Position on DVD shr 2
- //=========================================================================================================
+ // Seek (immediate)
case DVDLowSeek:
+ if (!GCAM)
{
-#if MAX_LOGLEVEL >= DEBUG_LEVEL
- u32 offset = dvdMem.Command[1] << 2;
+ // We don't care :)
+ DEBUG_LOG(DVDINTERFACE, "Seek: offset=%08x (ignoring)", m_DICMDBUF[1].Hex << 2);
+ }
+ else
+ {
+ memset(media_buffer, 0, 0x20);
+ media_buffer[0] = media_buffer[0x20]; // ID
+ media_buffer[2] = media_buffer[0x22];
+ media_buffer[3] = media_buffer[0x23] | 0x80;
+ int cmd = (media_buffer[0x23]<<8)|media_buffer[0x22];
+ ERROR_LOG(DVDINTERFACE, "GC-AM: execute buffer, cmd=%04x", cmd);
+ switch (cmd)
+ {
+ case 0x00:
+ media_buffer[4] = 1;
+ break;
+ case 0x1:
+ media_buffer[7] = 0x20; // DIMM Size
+ break;
+ case 0x100:
+ {
+ static int percentage;
+ static int status = 0;
+ percentage++;
+ if (percentage > 100)
+ {
+ status++;
+ percentage = 0;
+ }
+ media_buffer[4] = status;
+ /* status:
+ 0 - "Initializing media board. Please wait.."
+ 1 - "Checking network. Please wait..."
+ 2 - "Found a system disc. Insert a game disc"
+ 3 - "Testing a game program. %d%%"
+ 4 - "Loading a game program. %d%%"
+ 5 - go
+ 6 - error xx
+ */
+ media_buffer[8] = percentage;
+ media_buffer[4] = 0x05;
+ media_buffer[8] = 0x64;
+ break;
+ }
+ case 0x101:
+ media_buffer[4] = 3; // version
+ media_buffer[5] = 3;
+ media_buffer[6] = 1; // xxx
+ media_buffer[8] = 1;
+ media_buffer[16] = 0xFF;
+ media_buffer[17] = 0xFF;
+ media_buffer[18] = 0xFF;
+ media_buffer[19] = 0xFF;
+ break;
+ case 0x102: // get error code
+ media_buffer[4] = 1; // 0: download incomplete (31), 1: corrupted, other error 1
+ media_buffer[5] = 0;
+ break;
+ case 0x103:
+ memcpy(media_buffer + 4, "A89E27A50364511", 15); // serial
+ break;
+#if 0
+ case 0x301: // unknown
+ memcpy(media_buffer + 4, media_buffer + 0x24, 0x1c);
+ break;
+ case 0x302:
+ break;
#endif
- DEBUG_LOG(DVDINTERFACE, "Seek: offset=%08x (ignoring)", offset);
- }
+ default:
+ ERROR_LOG(DVDINTERFACE, "GC-AM: execute buffer (unknown)");
+ break;
+ }
+ memset(media_buffer + 0x20, 0, 0x20);
+ m_DIIMMBUF.Hex = 0x66556677; // just a random value that works.
+ }
break;
case DVDLowOffset:
DEBUG_LOG(DVDINTERFACE, "DVDLowOffset: ignoring...");
break;
- //=========================================================================================================
- // REQUEST ERROR (Immediate)
- // Command/Subcommand/Padding <- E0000000
- //=========================================================================================================
+ // Request Error Code
case DVDLowRequestError:
- ERROR_LOG(DVDINTERFACE, "Requesting error");
- dvdMem.Immediate = g_ErrorCode;
+ ERROR_LOG(DVDINTERFACE, "Requesting error... (0x%08x)", g_ErrorCode);
+ m_DIIMMBUF.Hex = g_ErrorCode;
break;
- //=========================================================================================================
- // AUDIOSTREAM (Immediate)
- // Command/Subcommand/Padding <- E1??0000 ?? = subcommand
- // Command0 <- Position on DVD shr 2
- // Command1 <- Length of the stream
- //=========================================================================================================
+ // Audio Stream (Immediate)
+ // m_DICMDBUF[0].CMDBYTE1 = subcommand
+ // m_DICMDBUF[1].Hex << 2 = offset on disc
+ // m_DICMDBUF[2].Hex = Length of the stream
case 0xE1:
{
- // i dunno if we need this check
- // if (m_bStream)
- // MessageBox(NULL, "dont overwrite a stream while you play it", "FATAL ERROR", MB_OK);
-
- // subcommand
-
// ugly hack to catch the disable command
- if (dvdMem.Command[1]!=0)
+ if (m_DICMDBUF[1].Hex != 0)
{
-#if MAX_LOGLEVEL >= DEBUG_LEVEL
- u8 subCommand = (dvdMem.Command[0] & 0x00FF0000) >> 16;
-#endif
-
- dvdMem.AudioPos = dvdMem.Command[1] << 2;
- dvdMem.AudioStart = dvdMem.AudioPos;
- dvdMem.AudioLength = dvdMem.Command[2];
+ AudioPos = m_DICMDBUF[1].Hex << 2;
+ AudioStart = AudioPos;
+ AudioLength = m_DICMDBUF[2].Hex;
NGCADPCM::InitFilter();
- m_bStream = true;
+ g_bStream = true;
- DEBUG_LOG(DVDINTERFACE, "DVD(Audio) Stream subcmd = %02x offset = %08x length=%08x",
- subCommand, dvdMem.AudioPos, dvdMem.AudioLength);
- }
- }
- break;
-
- //=========================================================================================================
- // REQUEST AUDIO STATUS (Immediate)
- // Command/Subcommand/Padding <- E2000000
- //=========================================================================================================
- case 0xE2:
- {
- if (m_bStream)
- dvdMem.Immediate = 1;
+ WARN_LOG(DVDINTERFACE, "(Audio) Stream subcmd = %02x offset = %08x length=%08x",
+ m_DICMDBUF[0].CMDBYTE1, AudioPos, AudioLength);
+ }
else
- dvdMem.Immediate = 0;
+ WARN_LOG(DVDINTERFACE, "(Audio) Off?");
}
- DEBUG_LOG(DVDINTERFACE, "DVD(Audio): Request Audio status");
break;
- //=========================================================================================================
- // STOP MOTOR (Immediate)
- // Command/Subcommand/Padding <- E3000000
- //=========================================================================================================
+ // Request Audio Status (Immediate)
+ case 0xE2:
+ m_DIIMMBUF.Hex = g_bStream ? 1 : 0;
+ WARN_LOG(DVDINTERFACE, "(Audio): Request Audio status %s", g_bStream? "on":"off");
+ break;
+
case DVDLowStopMotor:
DEBUG_LOG(DVDINTERFACE, "Stop motor");
break;
- //=========================================================================================================
- // DVD AUDIO DISABLE (Immediate)`
- // Command/Subcommand/Padding <- E4000000 (disable)
- // Command/Subcommand/Padding <- E4010000 (enable)
- //=========================================================================================================
+ // DVD Audio Enable/Disable (Immediate)
case DVDLowAudioBufferConfig:
- if (((dvdMem.Command[0] & 0x00FF0000) >> 16) == 1)
+ if (m_DICMDBUF[0].CMDBYTE1 == 1)
{
- m_bStream = true;
- DEBUG_LOG(DVDINTERFACE, "DVD(Audio): Audio enabled");
+ g_bStream = true;
+ WARN_LOG(DVDINTERFACE, "(Audio): Audio enabled");
}
else
{
- m_bStream = false;
- DEBUG_LOG(DVDINTERFACE, "DVD(Audio): Audio disabled");
+ g_bStream = false;
+ WARN_LOG(DVDINTERFACE, "(Audio): Audio disabled");
}
break;
- //=========================================================================================================
- // SET STATUS
- //=========================================================================================================
+ // yet another command we prolly don't care about
case 0xEE:
- INFO_LOG(DVDINTERFACE, "SetStatus %x", _DMAControlReg);
+ DEBUG_LOG(DVDINTERFACE, "SetStatus - Unimplemented");
break;
- //=========================================================================================================
- // DEBUG COMMANDS
- // Subcommands:
- // 0x00: ?
- // 0x01: read/write memory/cache
- // 0x10: ?
- // 0x11: stop/start/accept copy/disk check CAN BE OR'd!
- // 0x12: jump (jsr) to address
- //=========================================================================================================
+ // Debug commands; see yagcd. We don't really care
+ // NOTE: commands to stream data will send...a raw data stream
+ // This will appear as unknown commands, unless the check is re-instated to catch such data.
case 0xFE:
- {
- u8 subCommand = (dvdMem.Command[0] & 0x00FF0000) >> 16;
- u16 argument = (u16)(dvdMem.Command[0] & 0x0000FFFF);
-
- switch (subCommand)
- {
- case 0x01:
- {
- dvdMem.DebugTransfer.Address = dvdMem.Command[1];
- dvdMem.DebugTransfer.Length = dvdMem.Command[2] >> 16; // can be up to 12 bytes
-
- INFO_LOG(DVDINTERFACE, "Next cmd will %s %i bytes to drive %s @ 0x%08x",
- (argument & 0x100) ? "write" : "read", dvdMem.DebugTransfer.Length,
- (argument & 0x8000) ? "cache" : "mem", dvdMem.DebugTransfer.Address);
-
- dvdMem.DebugTransfer.InProgress = true;
- }
- break;
-
- case 0x11:
- char flags[256];
- sprintf(flags, "%s%s%s%s",
- (argument & STOP_DRIVE) ? "StopDrive " : "",
- (argument & START_DRIVE) ? "StartDrive " : "",
- (argument & ACCEPT_COPY) ? "AcceptCopy " : "",
- (argument & DISC_CHECK) ? "DiscCheck" : "");
- INFO_LOG(DVDINTERFACE, "Debug cmd(s): %s", flags);
- break;
-
- default:
- WARN_LOG(DVDINTERFACE, "Unsupported DVD Drive debug command 0x%08x", dvdMem.Command[0]);
- break;
- }
- }
+ INFO_LOG(DVDINTERFACE, "Unsupported DVD Drive debug command 0x%08x", m_DICMDBUF[0].Hex);
break;
- //=========================================================================================================
- // UNLOCK COMMANDS 1: "MATSHITA" 2: "DVD-GAME"
- // LOL
- //=========================================================================================================
+ // Unlock Commands. 1: "MATSHITA" 2: "DVD-GAME"
+ // Just for fun
case 0xFF:
{
- if (dvdMem.Command[0] == 0xFF014D41
- && dvdMem.Command[1] == 0x54534849
- && dvdMem.Command[2] == 0x54410200)
+ if (m_DICMDBUF[0].Hex == 0xFF014D41
+ && m_DICMDBUF[1].Hex == 0x54534849
+ && m_DICMDBUF[2].Hex == 0x54410200)
{
INFO_LOG(DVDINTERFACE, "Unlock test 1 passed");
}
- else if (dvdMem.Command[0] == 0xFF004456
- && dvdMem.Command[1] == 0x442D4741
- && dvdMem.Command[2] == 0x4D450300)
+ else if (m_DICMDBUF[0].Hex == 0xFF004456
+ && m_DICMDBUF[1].Hex == 0x442D4741
+ && m_DICMDBUF[2].Hex == 0x4D450300)
{
INFO_LOG(DVDINTERFACE, "Unlock test 2 passed");
}
@@ -803,21 +918,17 @@ void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg)
}
break;
- //=========================================================================================================
- // UNKNOWN DVD COMMAND
- //=========================================================================================================
default:
- PanicAlert("Unknown DVD command %08x - fatal error", dvdMem.Command[0]);
+ PanicAlert("Unknown DVD command %08x - fatal error", m_DICMDBUF[0].Hex);
_dbg_assert_(DVDINTERFACE, 0);
break;
}
- } // end of if(dvdMem.DebugTransfer.InProgress)
// transfer is done
- _DMAControlReg.TSTART = 0;
- dvdMem.DMALength.Length = 0;
- GenerateDVDInterruptFromDVDThread(INT_TCINT);
- g_ErrorCode = 0x00;
+ _DICR.TSTART = 0;
+ m_DILENGTH.Length = 0;
+ GenerateDVDInterrupt_Threadsafe(INT_TCINT);
+ g_ErrorCode = 0;
}
} // namespace
diff --git a/Source/Core/Core/Src/HW/DVDInterface.h b/Source/Core/Core/Src/HW/DVDInterface.h
index ee7ef2ea9e..1fa4d32dec 100644
--- a/Source/Core/Core/Src/HW/DVDInterface.h
+++ b/Source/Core/Core/Src/HW/DVDInterface.h
@@ -42,8 +42,9 @@ void ClearCoverInterrupt();
// DVD Access Functions
bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength);
+// For AudioInterface
bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples);
-extern bool m_bStream;
+extern bool g_bStream;
// Read32
void Read32(u32& _uReturnValue, const u32 _iAddress);
@@ -119,5 +120,3 @@ enum DICommand
} // end of namespace DVDInterface
#endif
-
-
diff --git a/Source/Core/Core/Src/HW/EXI.cpp b/Source/Core/Core/Src/HW/EXI.cpp
index 8c360091e6..44a1200146 100644
--- a/Source/Core/Core/Src/HW/EXI.cpp
+++ b/Source/Core/Core/Src/HW/EXI.cpp
@@ -35,41 +35,39 @@ enum
NUM_CHANNELS = 3
};
-CEXIChannel *g_Channels;
+CEXIChannel *g_Channels[NUM_CHANNELS];
void Init()
{
- g_Channels = new CEXIChannel[NUM_CHANNELS];
- g_Channels[0].m_ChannelId = 0;
- g_Channels[1].m_ChannelId = 1;
- g_Channels[2].m_ChannelId = 2;
+ for (u32 i = 0; i < NUM_CHANNELS; i++)
+ g_Channels[i] = new CEXIChannel(i);
- // m_EXIDevice[0] = SlotA
- // m_EXIDevice[1] = SlotB
- // m_EXIDevice[2] = Serial Port 1 (ETH)
- g_Channels[0].AddDevice(SConfig::GetInstance().m_EXIDevice[0], 0);
- g_Channels[0].AddDevice(EXIDEVICE_IPL, 1);
- g_Channels[0].AddDevice(SConfig::GetInstance().m_EXIDevice[2], 2);
- g_Channels[1].AddDevice(SConfig::GetInstance().m_EXIDevice[1], 0);
- g_Channels[2].AddDevice(EXIDEVICE_AD16, 0);
+ g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[0], 0); // SlotA
+ g_Channels[0]->AddDevice(EXIDEVICE_MASKROM, 1);
+ g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[2], 2); // Serial Port 1
+ g_Channels[1]->AddDevice(SConfig::GetInstance().m_EXIDevice[1], 0); // SlotB
+ g_Channels[2]->AddDevice(EXIDEVICE_AD16, 0);
changeDevice = CoreTiming::RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback);
}
void Shutdown()
{
- delete [] g_Channels;
- g_Channels = 0;
+ for (u32 i = 0; i < NUM_CHANNELS; i++)
+ {
+ delete g_Channels[i];
+ g_Channels[i] = NULL;
+ }
}
void DoState(PointerWrap &p)
{
// TODO: Complete DoState for each IEXIDevice
- g_Channels[0].GetDevice(1)->DoState(p);
- g_Channels[0].GetDevice(2)->DoState(p);
- g_Channels[0].GetDevice(4)->DoState(p);
- g_Channels[1].GetDevice(1)->DoState(p);
- g_Channels[2].GetDevice(1)->DoState(p);
+ g_Channels[0]->GetDevice(1)->DoState(p);
+ g_Channels[0]->GetDevice(2)->DoState(p);
+ g_Channels[0]->GetDevice(4)->DoState(p);
+ g_Channels[1]->GetDevice(1)->DoState(p);
+ g_Channels[2]->GetDevice(1)->DoState(p);
}
void ChangeDeviceCallback(u64 userdata, int cyclesLate)
@@ -78,35 +76,37 @@ void ChangeDeviceCallback(u64 userdata, int cyclesLate)
u8 device = (u8)(userdata >> 16);
u8 slot = (u8)userdata;
- g_Channels[channel].AddDevice((TEXIDevices)device, slot);
+ g_Channels[channel]->AddDevice((TEXIDevices)device, slot);
}
void ChangeDevice(u8 channel, TEXIDevices device, u8 slot)
{
// Called from GUI, so we need to make it thread safe.
// Let the hardware see no device for .5b cycles
- CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_DUMMY << 16) | slot);
+ CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_NONE << 16) | slot);
CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | ((u64)device << 16) | slot);
}
+// Unused (?!)
void Update()
{
- g_Channels[0].Update();
- g_Channels[1].Update();
- g_Channels[2].Update();
+ g_Channels[0]->Update();
+ g_Channels[1]->Update();
+ g_Channels[2]->Update();
}
void Read32(u32& _uReturnValue, const u32 _iAddress)
{
- unsigned int iAddr = _iAddress & 0x3FF;
- unsigned int iRegister = (iAddr >> 2) % 5;
- unsigned int iChannel = (iAddr >> 2) / 5;
+ // TODO 0xfff00000 is mapped to EXI -> mapped to first MB of maskrom
+ u32 iAddr = _iAddress & 0x3FF;
+ u32 iRegister = (iAddr >> 2) % 5;
+ u32 iChannel = (iAddr >> 2) / 5;
_dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS);
if (iChannel < NUM_CHANNELS)
{
- g_Channels[iChannel].Read32(_uReturnValue, iRegister);
+ g_Channels[iChannel]->Read32(_uReturnValue, iRegister);
}
else
{
@@ -116,28 +116,30 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
void Write32(const u32 _iValue, const u32 _iAddress)
{
- int iAddr = _iAddress & 0x3FF;
- int iRegister = (iAddr >> 2) % 5;
- int iChannel = (iAddr >> 2) / 5;
+ // TODO 0xfff00000 is mapped to EXI -> mapped to first MB of maskrom
+ u32 iAddr = _iAddress & 0x3FF;
+ u32 iRegister = (iAddr >> 2) % 5;
+ u32 iChannel = (iAddr >> 2) / 5;
- _dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS)
+ _dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS);
if (iChannel < NUM_CHANNELS)
- g_Channels[iChannel].Write32(_iValue, iRegister);
+ g_Channels[iChannel]->Write32(_iValue, iRegister);
}
void UpdateInterrupts()
{
- for(int i=0; iSetEXIINT(g_Channels[0]->GetDevice(4)->IsInterruptSet());
- ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, false);
+ bool causeInt = false;
+ for (int i = 0; i < NUM_CHANNELS; i++)
+ causeInt |= g_Channels[i]->IsCausingInterrupt();
+
+ ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, causeInt);
}
} // end of namespace ExpansionInterface
diff --git a/Source/Core/Core/Src/HW/EXI_Channel.cpp b/Source/Core/Core/Src/HW/EXI_Channel.cpp
index 3143757a3a..c73ed0b275 100644
--- a/Source/Core/Core/Src/HW/EXI_Channel.cpp
+++ b/Source/Core/Core/Src/HW/EXI_Channel.cpp
@@ -27,24 +27,22 @@
#include "ProcessorInterface.h"
#include "../PowerPC/PowerPC.h"
-CEXIChannel::CEXIChannel() :
+CEXIChannel::CEXIChannel(u32 ChannelId) :
m_DMAMemoryAddress(0),
m_DMALength(0),
m_ImmData(0),
- m_ChannelId(-1)
+ m_ChannelId(ChannelId)
{
- m_Control.hex = 0;
- m_Status.hex = 0;
+ m_Control.Hex = 0;
+ m_Status.Hex = 0;
- m_Status.CHIP_SELECT = 1;
+ if (m_ChannelId == 0 || m_ChannelId == 1)
+ m_Status.EXTINT = 1;
+ if (m_ChannelId == 1)
+ m_Status.CHIP_SELECT = 1;
for (int i = 0; i < NUM_DEVICES; i++)
- {
- m_pDevices[i] = EXIDevice_Create(EXIDEVICE_DUMMY);
- _dbg_assert_(EXPANSIONINTERFACE, m_pDevices[i] != NULL);
- }
-
- m_Status.TCINTMASK = 1;
+ m_pDevices[i] = EXIDevice_Create(EXIDEVICE_NONE);
}
CEXIChannel::~CEXIChannel()
@@ -56,11 +54,8 @@ void CEXIChannel::RemoveDevices()
{
for (int i = 0; i < NUM_DEVICES; i++)
{
- if (m_pDevices[i] != NULL)
- {
- delete m_pDevices[i];
- m_pDevices[i] = NULL;
- }
+ delete m_pDevices[i];
+ m_pDevices[i] = NULL;
}
}
@@ -77,7 +72,14 @@ void CEXIChannel::AddDevice(const TEXIDevices _device, const unsigned int _iSlot
// create the new one
m_pDevices[_iSlot] = EXIDevice_Create(_device);
- _dbg_assert_(EXPANSIONINTERFACE, m_pDevices[_iSlot] != NULL);
+
+ // This means "device presence changed", software has to check
+ // m_Status.EXT to see if it is now present or not
+ if (m_ChannelId != 2)
+ {
+ m_Status.EXTINT = 1;
+ UpdateInterrupts();
+ }
}
void CEXIChannel::UpdateInterrupts()
@@ -87,18 +89,11 @@ void CEXIChannel::UpdateInterrupts()
bool CEXIChannel::IsCausingInterrupt()
{
- if (m_ChannelId != 2) /* Channels 0 and 1: Memcard slot (device 0) produces interrupt */
- {
- for (int i = 0; i < NUM_DEVICES; i++)
- if (m_pDevices[i]->IsInterruptSet())
- m_Status.EXIINT = 1;
- }
- else /* Channel 2: In fact, Channel 0, Device 2 (Serial A) produces interrupt */
- {
- // WTF? this[-2]??? EVIL HACK
- if (this[-2].m_pDevices[2]->IsInterruptSet())
+ if (m_ChannelId != 2 && GetDevice(1)->IsInterruptSet())
+ m_Status.EXIINT = 1; // Always check memcard slots
+ else if (GetDevice(m_Status.CHIP_SELECT))
+ if (GetDevice(m_Status.CHIP_SELECT)->IsInterruptSet())
m_Status.EXIINT = 1;
- }
if ((m_Status.EXIINT & m_Status.EXIINTMASK) ||
(m_Status.TCINT & m_Status.TCINTMASK) ||
@@ -134,22 +129,18 @@ void CEXIChannel::Update()
void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
{
- DEBUG_LOG(EXPANSIONINTERFACE, "ExtensionInterface(R): channel: %i reg: %i", m_ChannelId, _iRegister);
-
switch (_iRegister)
{
case EXI_STATUS:
{
- // check if a device is present
- for (int i = 0; i < NUM_DEVICES; i++)
- {
- if (m_pDevices[i]->IsPresent())
- {
- m_Status.EXT = 1;
- break;
- }
- }
- _uReturnValue = m_Status.hex;
+ // check if external device is present
+ // pretty sure it is memcard only, not entirely sure
+ if (m_ChannelId == 2)
+ m_Status.EXT = 0;
+ else
+ m_Status.EXT = GetDevice(1)->IsPresent() ? 1 : 0;
+
+ _uReturnValue = m_Status.Hex;
break;
}
@@ -162,7 +153,7 @@ void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
break;
case EXI_DMACONTROL:
- _uReturnValue = m_Control.hex;
+ _uReturnValue = m_Control.Hex;
break;
case EXI_IMMDATA:
@@ -174,11 +165,14 @@ void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
_uReturnValue = 0xDEADBEEF;
}
+ DEBUG_LOG(EXPANSIONINTERFACE, "(r32) 0x%08x channel: %i reg: %s",
+ _uReturnValue, m_ChannelId, Debug_GetRegisterName(_iRegister));
}
void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
{
- INFO_LOG(EXPANSIONINTERFACE, "ExtensionInterface(W): 0x%08x channel: %i reg: %i", _iValue, m_ChannelId, _iRegister);
+ DEBUG_LOG(EXPANSIONINTERFACE, "(w32) 0x%08x channel: %i reg: %s",
+ _iValue, m_ChannelId, Debug_GetRegisterName(_iRegister));
switch (_iRegister)
{
@@ -186,64 +180,45 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
{
UEXI_STATUS newStatus(_iValue);
- // static
m_Status.EXIINTMASK = newStatus.EXIINTMASK;
+ if (newStatus.EXIINT) m_Status.EXIINT = 0;
+
m_Status.TCINTMASK = newStatus.TCINTMASK;
- m_Status.EXTINTMASK = newStatus.EXTINTMASK;
+ if (newStatus.TCINT) m_Status.TCINT = 0;
+
m_Status.CLK = newStatus.CLK;
- m_Status.ROMDIS = newStatus.ROMDIS;
- // Device
- if (m_Status.CHIP_SELECT != newStatus.CHIP_SELECT)
+ if (m_ChannelId == 0 || m_ChannelId == 1)
{
- for (int i = 0; i < NUM_DEVICES; i++)
- {
- u8 dwDeviceMask = 1 << i;
- IEXIDevice* pDevice = GetDevice(dwDeviceMask);
- if (pDevice != NULL)
- {
- if (((newStatus.CHIP_SELECT & dwDeviceMask) == dwDeviceMask) &&
- ((m_Status.CHIP_SELECT & dwDeviceMask) == 0))
- // device gets activated
- pDevice->SetCS(1);
-
- if (((newStatus.CHIP_SELECT & dwDeviceMask) == 0) &&
- ((m_Status.CHIP_SELECT & dwDeviceMask) == dwDeviceMask))
- // device gets deactivated
- pDevice->SetCS(0);
- }
- }
- m_Status.CHIP_SELECT = newStatus.CHIP_SELECT;
+ m_Status.EXTINTMASK = newStatus.EXTINTMASK;
+ if (newStatus.EXTINT) m_Status.EXTINT = 0;
}
- // External Status
- IEXIDevice* pDevice = GetDevice(newStatus.CHIP_SELECT);
- if (pDevice != NULL)
- m_Status.EXT = pDevice->IsPresent() ? 1 : 0;
- else
- m_Status.EXT = 0;
+ if (m_ChannelId == 0)
+ m_Status.ROMDIS = newStatus.ROMDIS;
+
+ IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT ^ newStatus.CHIP_SELECT);
+ m_Status.CHIP_SELECT = newStatus.CHIP_SELECT;
+ if (pDevice != NULL)
+ pDevice->SetCS(m_Status.CHIP_SELECT);
- // interrupt
- if (newStatus.EXIINT) m_Status.EXIINT = 0;
- if (newStatus.TCINT) m_Status.TCINT = 0;
- if (newStatus.EXTINT) m_Status.EXTINT = 0;
UpdateInterrupts();
}
break;
case EXI_DMAADDR:
- INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote DMABuf, chan %i", m_ChannelId);
+ INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAAddr, chan %i", m_ChannelId);
m_DMAMemoryAddress = _iValue;
break;
case EXI_DMALENGTH:
- INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote DMASize, chan %i", m_ChannelId);
+ INFO_LOG(EXPANSIONINTERFACE, "Wrote DMALength, chan %i", m_ChannelId);
m_DMALength = _iValue;
break;
case EXI_DMACONTROL:
- INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote DMAControl, chan %i", m_ChannelId);
- m_Control.hex = _iValue;
+ INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAControl, chan %i", m_ChannelId);
+ m_Control.Hex = _iValue;
if (m_Control.TSTART)
{
@@ -289,7 +264,7 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
break;
case EXI_IMMDATA:
- INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote IMMData, chan %i", m_ChannelId);
+ INFO_LOG(EXPANSIONINTERFACE, "Wrote IMMData, chan %i", m_ChannelId);
m_ImmData = _iValue;
break;
}
diff --git a/Source/Core/Core/Src/HW/EXI_Channel.h b/Source/Core/Core/Src/HW/EXI_Channel.h
index bf77907d22..436fb05b26 100644
--- a/Source/Core/Core/Src/HW/EXI_Channel.h
+++ b/Source/Core/Core/Src/HW/EXI_Channel.h
@@ -38,33 +38,50 @@ private:
EXI_DMACONTROL = 3,
EXI_IMMDATA = 4
};
+ const char* Debug_GetRegisterName(u32 _register)
+ {
+ switch (_register)
+ {
+ case EXI_STATUS: return "STATUS";
+ case EXI_DMAADDR: return "DMAADDR";
+ case EXI_DMALENGTH: return "DMALENGTH";
+ case EXI_DMACONTROL: return "DMACONTROL";
+ case EXI_IMMDATA: return "IMMDATA";
+ default: return "!!! Unknown EXI Register !!!";
+ }
+ }
- // EXI Status Register
+ // EXI Status Register - "Channel Parameter Register"
union UEXI_STATUS
{
- u32 hex;
+ u32 Hex;
+ // DO NOT obey the warning and give this struct a name. Things will fail.
struct
{
- unsigned EXIINTMASK : 1; //31
- unsigned EXIINT : 1; //30
- unsigned TCINTMASK : 1; //29
- unsigned TCINT : 1; //28
- unsigned CLK : 3; //27
- unsigned CHIP_SELECT : 3; //24
- unsigned EXTINTMASK : 1; //21
- unsigned EXTINT : 1; //20
- unsigned EXT : 1; //19 // External Insertion Status (1: External EXI device present)
- unsigned ROMDIS : 1; //18 // ROM Disable
+ // Indentation Meaning:
+ // Channels 0, 1, 2
+ // Channels 0, 1 only
+ // Channel 0 only
+ unsigned EXIINTMASK : 1;
+ unsigned EXIINT : 1;
+ unsigned TCINTMASK : 1;
+ unsigned TCINT : 1;
+ unsigned CLK : 3;
+ unsigned CHIP_SELECT : 3; // CS1 and CS2 are Channel 0 only
+ unsigned EXTINTMASK : 1;
+ unsigned EXTINT : 1;
+ unsigned EXT : 1; // External Insertion Status (1: External EXI device present)
+ unsigned ROMDIS : 1; // ROM Disable
unsigned :18;
- }; // DO NOT obey the warning and give this struct a name. Things will fail.
- UEXI_STATUS() {hex = 0;}
- UEXI_STATUS(u32 _hex) {hex = _hex;}
+ };
+ UEXI_STATUS() {Hex = 0;}
+ UEXI_STATUS(u32 _hex) {Hex = _hex;}
};
// EXI Control Register
union UEXI_CONTROL
{
- u32 hex;
+ u32 Hex;
struct
{
unsigned TSTART : 1;
@@ -77,9 +94,9 @@ private:
// STATE_TO_SAVE
UEXI_STATUS m_Status;
- UEXI_CONTROL m_Control;
u32 m_DMAMemoryAddress;
u32 m_DMALength;
+ UEXI_CONTROL m_Control;
u32 m_ImmData;
// Devices
@@ -90,13 +107,14 @@ private:
IEXIDevice* m_pDevices[NUM_DEVICES];
+ // Since channels operate a bit differently from each other
+ u32 m_ChannelId;
+
public:
// get device
IEXIDevice* GetDevice(u8 _CHIP_SELECT);
- // channelId for debugging
- u32 m_ChannelId;
- CEXIChannel();
+ CEXIChannel(u32 ChannelId);
~CEXIChannel();
void AddDevice(const TEXIDevices _device, const unsigned int _iSlot);
@@ -110,6 +128,9 @@ public:
void Update();
bool IsCausingInterrupt();
void UpdateInterrupts();
+
+ // This should only be used to transition interrupts from SP1 to Channel 2
+ void SetEXIINT(bool exiint) { m_Status.EXIINT = !!exiint; }
};
#endif
diff --git a/Source/Core/Core/Src/HW/EXI_Device.cpp b/Source/Core/Core/Src/HW/EXI_Device.cpp
index 52da128ac1..83a766ad93 100644
--- a/Source/Core/Core/Src/HW/EXI_Device.cpp
+++ b/Source/Core/Core/Src/HW/EXI_Device.cpp
@@ -23,13 +23,13 @@
#include "EXI_DeviceAD16.h"
#include "EXI_DeviceMic.h"
#include "EXI_DeviceEthernet.h"
+#include "EXI_DeviceAMBaseboard.h"
#include "../Core.h"
#include "../ConfigManager.h"
// --- interface IEXIDevice ---
-
void IEXIDevice::ImmWrite(u32 _uData, u32 _uSize)
{
while (_uSize--)
@@ -76,9 +76,9 @@ void IEXIDevice::DMARead(u32 _uAddr, u32 _uSize)
// --- class CEXIDummy ---
-
// Just a dummy that logs reads and writes
// to be used for EXI devices we haven't emulated
+// DOES NOT FUNCTION AS "NO DEVICE INSERTED" -> Appears as unknown device
class CEXIDummy : public IEXIDevice
{
std::string m_strName;
@@ -94,15 +94,13 @@ public:
virtual ~CEXIDummy(){}
void ImmWrite(u32 data, u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmWrite: %08x", m_strName.c_str(), data);}
- u32 ImmRead (u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead", m_strName.c_str()); return 0;}
+ u32 ImmRead (u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead", m_strName.c_str()); return 0;}
void DMAWrite(u32 addr, u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMAWrite: %08x bytes, from %08x to device", m_strName.c_str(), size, addr);}
void DMARead (u32 addr, u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMARead: %08x bytes, from device to %08x", m_strName.c_str(), size, addr);}
};
// F A C T O R Y
-
-
IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
{
switch(_EXIDevice)
@@ -119,7 +117,7 @@ IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
return new CEXIMemoryCard("MemoryCardB", SConfig::GetInstance().m_strMemoryCardB, 1);
break;
- case EXIDEVICE_IPL:
+ case EXIDEVICE_MASKROM:
return new CEXIIPL();
break;
@@ -135,6 +133,13 @@ IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
return new CEXIETHERNET();
break;
+ case EXIDEVICE_AM_BASEBOARD:
+ return new CEXIAMBaseboard();
+ break;
+
+ case EXIDEVICE_NONE:
+ default:
+ return new IEXIDevice();
+ break;
}
- return NULL;
}
diff --git a/Source/Core/Core/Src/HW/EXI_Device.h b/Source/Core/Core/Src/HW/EXI_Device.h
index 3a09717219..ae79f213a4 100644
--- a/Source/Core/Core/Src/HW/EXI_Device.h
+++ b/Source/Core/Core/Src/HW/EXI_Device.h
@@ -53,13 +53,14 @@ enum TEXIDevices
EXIDEVICE_DUMMY,
EXIDEVICE_MEMORYCARD_A,
EXIDEVICE_MEMORYCARD_B,
- EXIDEVICE_IPL,
+ EXIDEVICE_MASKROM,
EXIDEVICE_AD16,
EXIDEVICE_MIC,
EXIDEVICE_ETH,
+ EXIDEVICE_AM_BASEBOARD,
+ EXIDEVICE_NONE = (u8)-1
};
extern IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice);
#endif
-
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp
new file mode 100644
index 0000000000..4a04a3dbb3
--- /dev/null
+++ b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp
@@ -0,0 +1,130 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// 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, version 2.0.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include "../Core.h"
+
+#include "EXI_Device.h"
+#include "EXI_DeviceAMBaseboard.h"
+
+CEXIAMBaseboard::CEXIAMBaseboard()
+ : m_position(0)
+ , m_have_irq(false)
+{
+}
+
+void CEXIAMBaseboard::SetCS(int cs)
+{
+ ERROR_LOG(SP1, "AM-BB ChipSelect=%d", cs);
+ if (cs)
+ m_position = 0;
+}
+
+bool CEXIAMBaseboard::IsPresent()
+{
+ return true;
+}
+
+void CEXIAMBaseboard::TransferByte(u8& _byte)
+{
+ /*
+ ID:
+ 00 00 xx xx xx xx
+ xx xx 06 04 10 00
+ CMD:
+ 01 00 00 b3 xx
+ xx xx xx xx 04
+ exi_lanctl_write:
+ ff 02 01 63 xx
+ xx xx xx xx 04
+ exi_imr_read:
+ 86 00 00 f5 xx xx xx
+ xx xx xx xx 04 rr rr
+ exi_imr_write:
+ 87 80 5c 17 xx
+ xx xx xx xx 04
+
+ exi_isr_read:
+ 82 .. .. .. xx xx xx
+ xx xx xx xx 04 rr rr
+ 3 byte command, 1 byte checksum
+ */
+ DEBUG_LOG(SP1, "AM-BB > %02x", _byte);
+ if (m_position < 4)
+ {
+ m_command[m_position] = _byte;
+ _byte = 0xFF;
+ }
+
+ if ((m_position >= 2) && (m_command[0] == 0 && m_command[1] == 0))
+ _byte = "\x06\x04\x10\x00"[(m_position-2)&3];
+ else if (m_position == 3)
+ {
+ unsigned int checksum = (m_command[0] << 24) | (m_command[1] << 16) | (m_command[2] << 8);
+ unsigned int bit = 0x80000000UL;
+ unsigned int check = 0x8D800000UL;
+ while (bit >= 0x100)
+ {
+ if (checksum & bit)
+ checksum ^= check;
+ check >>= 1;
+ bit >>= 1;
+ }
+ if (m_command[3] != (checksum & 0xFF))
+ ERROR_LOG(SP1, "AM-BB cs: %02x, w: %02x", m_command[3], checksum & 0xFF);
+ }
+ else
+ {
+ if (m_position == 4)
+ {
+ _byte = 4;
+ ERROR_LOG(SP1, "AM-BB COMMAND: %02x %02x %02x", m_command[0], m_command[1], m_command[2]);
+ if ((m_command[0] == 0xFF) && (m_command[1] == 0) && (m_command[2] == 0))
+ m_have_irq = true;
+ else if (m_command[0] == 0x82)
+ m_have_irq = false;
+ }
+ else if (m_position > 4)
+ {
+ switch (m_command[0])
+ {
+ case 0xFF: // lan
+ _byte = 0xFF;
+ break;
+ case 0x86: // imr
+ _byte = 0x00;
+ break;
+ case 0x82: // isr
+ _byte = m_have_irq ? 0xFF : 0;
+ break;
+ default:
+ _dbg_assert_msg_(SP1, 0, "Unknown AM-BB cmd");
+ break;
+ }
+ }
+ else
+ _byte = 0xFF;
+ }
+ DEBUG_LOG(SP1, "AM-BB < %02x", _byte);
+ m_position++;
+}
+
+bool CEXIAMBaseboard::IsInterruptSet()
+{
+ if (m_have_irq)
+ ERROR_LOG(SP1, "AM-BB IRQ");
+ return m_have_irq;
+}
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h
new file mode 100644
index 0000000000..3e91580e44
--- /dev/null
+++ b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// 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, version 2.0.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef _EXIDEVICE_AMBASEBOARD_H
+#define _EXIDEVICE_AMBASEBOARD_H
+
+class CEXIAMBaseboard : public IEXIDevice
+{
+public:
+ CEXIAMBaseboard();
+
+ virtual void SetCS(int _iCS);
+ virtual bool IsPresent();
+ virtual bool IsInterruptSet();
+
+private:
+ virtual void TransferByte(u8& _uByte);
+ int m_position;
+ bool m_have_irq;
+ unsigned char m_command[4];
+};
+
+#endif
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp
index e77fc2a93c..e61542184a 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp
+++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp
@@ -286,9 +286,23 @@ void CEXIMemoryCard::TransferByte(u8 &byte)
command = byte; // first byte is command
byte = 0xFF; // would be tristate, but we don't care.
- switch (command)
+ switch (command) // This seems silly, do we really need it?
{
- case 0x52:
+ case cmdNintendoID:
+ case cmdReadArray:
+ case cmdArrayToBuffer:
+ case cmdSetInterrupt:
+ case cmdWriteBuffer:
+ case cmdReadStatus:
+ case cmdReadID:
+ case cmdReadErrorBuffer:
+ case cmdWakeUp:
+ case cmdSleep:
+ case cmdClearStatus:
+ case cmdSectorErase:
+ case cmdPageProgram:
+ case cmdExtraByteProgram:
+ case cmdChipErase:
INFO_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: command %02x at position 0. seems normal.", command);
break;
default:
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h
index 46420e6616..2acc4d7577 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h
+++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h
@@ -57,11 +57,11 @@ private:
cmdArrayToBuffer = 0x53,
cmdSetInterrupt = 0x81,
cmdWriteBuffer = 0x82,
- cmdReadStatus = 0x83,
+ cmdReadStatus = 0x83,
cmdReadID = 0x85,
cmdReadErrorBuffer = 0x86,
cmdWakeUp = 0x87,
- cmdSleep = 0x88,
+ cmdSleep = 0x88,
cmdClearStatus = 0x89,
cmdSectorErase = 0xF1,
cmdPageProgram = 0xF2,
diff --git a/Source/Core/Core/Src/HW/SI.cpp b/Source/Core/Core/Src/HW/SI.cpp
index 868262742b..33317f4065 100644
--- a/Source/Core/Core/Src/HW/SI.cpp
+++ b/Source/Core/Core/Src/HW/SI.cpp
@@ -275,9 +275,9 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
// registers
switch (_iAddress & 0x3FF)
{
-
- // Channel 0
-
+ //////////////////////////////////////////////////////////////////////////
+ // Channel 0
+ //////////////////////////////////////////////////////////////////////////
case SI_CHANNEL_0_OUT:
_uReturnValue = g_Channel[0].m_Out.Hex;
return;
@@ -294,9 +294,9 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
_uReturnValue = g_Channel[0].m_InLo.Hex;
return;
-
- // Channel 1
-
+ //////////////////////////////////////////////////////////////////////////
+ // Channel 1
+ //////////////////////////////////////////////////////////////////////////
case SI_CHANNEL_1_OUT:
_uReturnValue = g_Channel[1].m_Out.Hex;
return;
@@ -313,9 +313,9 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
_uReturnValue = g_Channel[1].m_InLo.Hex;
return;
-
- // Channel 2
-
+ //////////////////////////////////////////////////////////////////////////
+ // Channel 2
+ //////////////////////////////////////////////////////////////////////////
case SI_CHANNEL_2_OUT:
_uReturnValue = g_Channel[2].m_Out.Hex;
return;
@@ -332,9 +332,9 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
_uReturnValue = g_Channel[2].m_InLo.Hex;
return;
-
- // Channel 3
-
+ //////////////////////////////////////////////////////////////////////////
+ // Channel 3
+ //////////////////////////////////////////////////////////////////////////
case SI_CHANNEL_3_OUT:
_uReturnValue = g_Channel[3].m_Out.Hex;
return;
@@ -351,6 +351,9 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
_uReturnValue = g_Channel[3].m_InLo.Hex;
return;
+ //////////////////////////////////////////////////////////////////////////
+ // Other
+ //////////////////////////////////////////////////////////////////////////
case SI_POLL: _uReturnValue = g_Poll.Hex; return;
case SI_COM_CSR: _uReturnValue = g_ComCSR.Hex; return;
case SI_STATUS_REG: _uReturnValue = g_StatusReg.Hex; return;
diff --git a/Source/Core/Core/Src/HW/SI_Device.cpp b/Source/Core/Core/Src/HW/SI_Device.cpp
index 228d722b3d..c747c1a368 100644
--- a/Source/Core/Core/Src/HW/SI_Device.cpp
+++ b/Source/Core/Core/Src/HW/SI_Device.cpp
@@ -18,10 +18,10 @@
#include "SI_Device.h"
#include "SI_DeviceGCController.h"
#include "SI_DeviceGBA.h"
+#include "SI_DeviceAMBaseboard.h"
// --- interface ISIDevice ---
-
int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength)
{
#ifdef _DEBUG
@@ -49,10 +49,9 @@ int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength)
// --- class CSIDummy ---
-
// Just a dummy that logs reads and writes
// to be used for SI devices we haven't emulated
-// and hopefully as an "emtpy" device
+// DOES NOT FUNCTION AS "NO DEVICE INSERTED" -> Appears as unknown device
class CSIDevice_Dummy : public ISIDevice
{
public:
@@ -71,14 +70,12 @@ public:
return 4;
}
- bool GetData(u32& _Hi, u32& _Low) {INFO_LOG(SERIALINTERFACE, "SI DUMMY %i GetData", this->m_iDeviceNumber); return false;}
- void SendCommand(u32 _Cmd, u8 _Poll){INFO_LOG(SERIALINTERFACE, "SI DUMMY %i SendCommand: %08x", this->m_iDeviceNumber, _Cmd);}
+ bool GetData(u32& _Hi, u32& _Low) {DEBUG_LOG(SERIALINTERFACE, "SI DUMMY %i GetData", this->m_iDeviceNumber); return false;}
+ void SendCommand(u32 _Cmd, u8 _Poll){DEBUG_LOG(SERIALINTERFACE, "SI DUMMY %i SendCommand: %08x", this->m_iDeviceNumber, _Cmd);}
};
// F A C T O R Y
-
-
ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber)
{
switch(_SIDevice)
@@ -95,6 +92,10 @@ ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber)
return new CSIDevice_GBA(_iDeviceNumber);
break;
+ case SI_AM_BASEBOARD:
+ return new CSIDevice_AMBaseboard(_iDeviceNumber);
+ break;
+
default:
return new CSIDevice_Dummy(_iDeviceNumber);
break;
diff --git a/Source/Core/Core/Src/HW/SI_Device.h b/Source/Core/Core/Src/HW/SI_Device.h
index 389cdb2dc5..65d7e4bfb0 100644
--- a/Source/Core/Core/Src/HW/SI_Device.h
+++ b/Source/Core/Core/Src/HW/SI_Device.h
@@ -69,6 +69,7 @@ enum TSIDevices
SI_GC_CONTROLLER = (SI_TYPE_GC | SI_GC_STANDARD),
SI_GC_KEYBOARD = (SI_TYPE_GC | 0x00200000),
SI_GC_STEERING = SI_TYPE_GC, // (shuffle2)I think the "chainsaw" is the same (Or else it's just standard)
+ SI_AM_BASEBOARD = 0x10110800 // gets ORd with dipswitch state
};
extern ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber);
diff --git a/Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp b/Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp
new file mode 100644
index 0000000000..0138f44563
--- /dev/null
+++ b/Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp
@@ -0,0 +1,469 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// 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, version 2.0.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include "SI.h"
+#include "SI_Device.h"
+#include "SI_DeviceAMBaseboard.h"
+
+#include "../PluginManager.h" // for pad state
+
+// where to put baseboard debug
+#define AMBASEBOARDDEBUG OSREPORT
+
+class JVSIOMessage
+{
+public:
+ int m_ptr, m_last_start, m_csum;
+ unsigned char m_msg[0x80];
+
+ JVSIOMessage()
+ {
+ m_ptr = 0;
+ m_last_start = 0;
+ }
+
+ void start(int node)
+ {
+ m_last_start = m_ptr;
+ unsigned char hdr[3] = {0xe0, node, 0};
+ m_csum = 0;
+ addData(hdr, 3, 1);
+ }
+ void addData(void *data, int len)
+ {
+ addData((unsigned char*)data, len);
+ }
+ void addData(char *data)
+ {
+ addData(data, strlen(data));
+ }
+ void addData(int n)
+ {
+ unsigned char cs = n;
+ addData(&cs, 1);
+ }
+
+ void end()
+ {
+ int len = m_ptr - m_last_start;
+ m_msg[m_last_start + 2] = len - 2; // assuming len <0xD0
+ addData(m_csum + len - 2);
+ }
+
+ void addData(unsigned char *dst, int len, int sync = 0)
+ {
+ while (len--)
+ {
+ int c = *dst++;
+ if (!sync && ((c == 0xE0) || (c == 0xD0)))
+ {
+ m_msg[m_ptr++] = 0xD0;
+ m_msg[m_ptr++] = c - 1;
+ } else
+ m_msg[m_ptr++] = c;
+ if (!sync)
+ m_csum += c;
+ sync = 0;
+ if (m_ptr >= 0x80)
+ PanicAlert("JVSIOMessage overrun!");
+ }
+ }
+}; // end class JVSIOMessage
+
+CSIDevice_AMBaseboard::CSIDevice_AMBaseboard(int _iDeviceNumber)
+ : ISIDevice(_iDeviceNumber)
+{
+}
+
+int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
+{
+ // for debug logging only
+ ISIDevice::RunBuffer(_pBuffer, _iLength);
+
+ int iPosition = 0;
+ while(iPosition < _iLength)
+ {
+ // read the command
+ EBufferCommands command = static_cast(_pBuffer[iPosition ^ 3]);
+ iPosition ++;
+
+ // handle it
+ switch(command)
+ {
+ case CMD_RESET: // returns ID and dip switches
+ {
+ *(u32*)&_pBuffer[0] = SI_AM_BASEBOARD|0x100; // 0x100 is progressive flag according to dip switch
+ iPosition = _iLength; // break the while loop
+ }
+ break;
+ case CMD_GCAM:
+ {
+ int i;
+
+ // calculate checksum over buffer
+ int csum = 0;
+ for (i=0; i<_iLength; ++i)
+ csum += _pBuffer[i];
+
+ unsigned char res[0x80];
+ int resp = 0;
+
+ int real_len = _pBuffer[1^3];
+ int p = 2;
+
+ static int d10_1 = 0xfe;
+
+ memset(res, 0, 0x80);
+ res[resp++] = 1;
+ res[resp++] = 1;
+
+#define ptr(x) _pBuffer[(p + x)^3]
+ while (p < real_len+2)
+ {
+ switch (ptr(0))
+ {
+ case 0x10:
+ {
+ DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 10, %02x (READ STATUS&SWITCHES)", ptr(1));
+ SPADStatus PadStatus;
+ memset(&PadStatus, 0 ,sizeof(PadStatus));
+ CPluginManager::GetInstance().GetPad(ISIDevice::m_iDeviceNumber)
+ ->PAD_GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
+ res[resp++] = 0x10;
+ res[resp++] = 0x2;
+ int d10_0 = 0xdf;
+
+ if (PadStatus.triggerLeft)
+ d10_0 &= ~0x80;
+ if (PadStatus.triggerRight)
+ d10_0 &= ~0x40;
+
+ res[resp++] = d10_0;
+ res[resp++] = d10_1;
+ break;
+ }
+ case 0x12:
+ ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 12, %02x %02x", ptr(1), ptr(2));
+ res[resp++] = 0x12;
+ res[resp++] = 0x00;
+ break;
+ case 0x11:
+ {
+ ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 11, %02x (READ SERIAL NR)", ptr(1));
+ char string[] = "AADE-01A14964511";
+ res[resp++] = 0x11;
+ res[resp++] = 0x10;
+ memcpy(res + resp, string, 0x10);
+ resp += 0x10;
+ break;
+ }
+ case 0x15:
+ ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 15, %02x (READ FIRM VERSION)", ptr(1));
+ res[resp++] = 0x15;
+ res[resp++] = 0x02;
+ res[resp++] = 0x00;
+ res[resp++] = 0x29; // FIRM VERSION
+ break;
+ case 0x16:
+ ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 16, %02x (READ FPGA VERSION)", ptr(1));
+ res[resp++] = 0x16;
+ res[resp++] = 0x02;
+ res[resp++] = 0x07;
+ res[resp++] = 0x06; // FPGAVERSION
+ /*
+ res[resp++] = 0x16;
+ res[resp++] = 0x00;
+ p += 2;
+ */
+ break;
+ case 0x1f:
+ {
+ ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 1f, %02x %02x %02x %02x %02x (REGION)", ptr(1), ptr(2), ptr(3), ptr(4), ptr(5));
+ unsigned char string[] =
+ "\x00\x00\x30\x00"
+ //"\x01\xfe\x00\x00" // JAPAN
+ "\x02\xfd\x00\x00" // USA
+ //"\x03\xfc\x00\x00" // export
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
+ res[resp++] = 0x1f;
+ res[resp++] = 0x14;
+
+ for (i=0; i<0x14; ++i)
+ res[resp++] = string[i];
+ break;
+ }
+ case 0x31:
+ ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 31 (UNKNOWN)");
+ res[resp++] = 0x31;
+ res[resp++] = 0x02;
+ res[resp++] = 0x00;
+ res[resp++] = 0x00;
+ break;
+ case 0x32:
+ ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 32 (UNKNOWN)");
+ res[resp++] = 0x32;
+ res[resp++] = 0x02;
+ res[resp++] = 0x00;
+ res[resp++] = 0x00;
+ break;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ {
+ DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD %02x, %02x %02x %02x %02x %02x %02x %02x (JVS IO)",
+ ptr(0), ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), ptr(6), ptr(7));
+ int total_length = ptr(1);
+ int pptr = 2;
+ JVSIOMessage msg;
+
+ msg.start(0);
+ msg.addData(1);
+
+ unsigned char jvs_io_buffer[0x80];
+ int nr_bytes = ptr(pptr + 2); // byte after e0 xx
+ int jvs_io_length = 0;
+ for (i=0; iPAD_GetStatus(i, &PadStatus);
+ unsigned char player_data[2] = {0,0};
+ if (PadStatus.button & PAD_BUTTON_START)
+ player_data[0] |= 0x80;
+ if (PadStatus.button & PAD_BUTTON_UP)
+ player_data[0] |= 0x20;
+ if (PadStatus.button & PAD_BUTTON_DOWN)
+ player_data[0] |= 0x10;
+ if (PadStatus.button & PAD_BUTTON_LEFT)
+ player_data[0] |= 0x08;
+ if (PadStatus.button & PAD_BUTTON_RIGHT)
+ player_data[0] |= 0x04;
+
+ if (PadStatus.button & PAD_BUTTON_A)
+ player_data[0] |= 0x02;
+ if (PadStatus.button & PAD_BUTTON_B)
+ player_data[0] |= 0x01;
+
+ if (PadStatus.button & PAD_BUTTON_X)
+ player_data[1] |= 0x80;
+ if (PadStatus.button & PAD_BUTTON_Y)
+ player_data[1] |= 0x40;
+ if (PadStatus.button & PAD_TRIGGER_L)
+ player_data[1] |= 0x20;
+ if (PadStatus.button & PAD_TRIGGER_R)
+ player_data[1] |= 0x10;
+
+ for (j=0; jPAD_GetStatus(0, &PadStatus);
+ while (slots--)
+ {
+ msg.addData(0);
+ msg.addData((PadStatus.button & PAD_BUTTON_START) ? 1 : 0);
+ }
+ break;
+ }
+ case 0x22: // analog
+ {
+ break;
+ }
+ case 0xf0:
+ if (*jvs_io++ == 0xD9)
+ {
+ ERROR_LOG(AMBASEBOARDDEBUG, "JVS RESET");
+ } else
+ unknown = 1;
+ msg.addData(1);
+
+ d10_1 |= 1;
+ break;
+ case 0xf1:
+ node = *jvs_io++;
+ ERROR_LOG(AMBASEBOARDDEBUG, "JVS SET ADDRESS, node=%d", node);
+ msg.addData(node == 1);
+ break;
+ default:
+ break;
+ }
+
+ pptr += jvs_io_length;
+
+ }
+
+ msg.end();
+
+ res[resp++] = ptr(0);
+
+ unsigned char *buf = msg.m_msg;
+ int len = msg.m_ptr;
+ res[resp++] = len;
+ for (i=0; i"
+#define DEV_DUMMY_STR "Dummy"
+
+#define SIDEV_STDCONT_STR "Standard Controller"
+#define SIDEV_GBA_STR "GBA"
+#define SIDEV_AM_BB_STR "AM-Baseboard"
+
+#define EXIDEV_MEMCARD_STR "Memory Card"
+#define EXIDEV_MIC_STR "Mic"
+#define EXIDEV_BBA_STR "BBA"
+#define EXIDEV_AM_BB_STR "AM-Baseboard"
+
BEGIN_EVENT_TABLE(CConfigMain, wxDialog)
@@ -352,10 +365,10 @@ void CConfigMain::CreateGUIControls()
GCEXIDeviceText[0] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SLOTA_TEXT, wxT("Slot A"), wxDefaultPosition, wxDefaultSize);
GCEXIDeviceText[1] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SLOTB_TEXT, wxT("Slot B"), wxDefaultPosition, wxDefaultSize);
GCEXIDeviceText[2] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SP1_TEXT, wxT("SP1 "), wxDefaultPosition, wxDefaultSize);
- GCEXIDeviceText[2]->SetToolTip(wxT("Serial Port 1 - This is the port the network adapter uses"));
- const wxString SlotDevices[] = {wxT(""),wxT("Memory Card"), wxT("Mic")};
+ GCEXIDeviceText[2]->SetToolTip(wxT("Serial Port 1 - This is the port which devices such as the net adapter use"));
+ const wxString SlotDevices[] = {wxT(DEV_NONE_STR),wxT(DEV_DUMMY_STR),wxT(EXIDEV_MEMCARD_STR), wxT(EXIDEV_MIC_STR)};
static const int numSlotDevices = sizeof(SlotDevices)/sizeof(wxString);
- const wxString SP1Devices[] = {wxT(""),wxT("BBA")};
+ const wxString SP1Devices[] = {wxT(DEV_NONE_STR),wxT(DEV_DUMMY_STR),wxT(EXIDEV_BBA_STR),wxT(EXIDEV_AM_BB_STR)};
static const int numSP1Devices = sizeof(SP1Devices)/sizeof(wxString);
GCEXIDevice[0] = new wxChoice(GamecubePage, ID_GC_EXIDEVICE_SLOTA, wxDefaultPosition, wxDefaultSize, numSlotDevices, SlotDevices, 0, wxDefaultValidator);
GCEXIDevice[1] = new wxChoice(GamecubePage, ID_GC_EXIDEVICE_SLOTB, wxDefaultPosition, wxDefaultSize, numSlotDevices, SlotDevices, 0, wxDefaultValidator);
@@ -365,16 +378,29 @@ void CConfigMain::CreateGUIControls()
for (int i = 0; i < 3; ++i)
{
bool isMemcard = false;
- if (SConfig::GetInstance().m_EXIDevice[i] == EXIDEVICE_MEMORYCARD_A)
- isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[1]);
- else if (SConfig::GetInstance().m_EXIDevice[i] == EXIDEVICE_MEMORYCARD_B)
- isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[1]);
- else if (SConfig::GetInstance().m_EXIDevice[i] == EXIDEVICE_MIC)
- GCEXIDevice[i]->SetStringSelection(SlotDevices[2]);
- else if (SConfig::GetInstance().m_EXIDevice[i] == EXIDEVICE_ETH)
- GCEXIDevice[i]->SetStringSelection(SP1Devices[1]);
- else
- GCEXIDevice[i]->SetStringSelection(wxT(""));
+ switch (SConfig::GetInstance().m_EXIDevice[i])
+ {
+ case EXIDEVICE_NONE:
+ GCEXIDevice[i]->SetStringSelection(SlotDevices[0]);
+ break;
+ case EXIDEVICE_MEMORYCARD_A:
+ case EXIDEVICE_MEMORYCARD_B:
+ isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[2]);
+ break;
+ case EXIDEVICE_MIC:
+ GCEXIDevice[i]->SetStringSelection(SlotDevices[3]);
+ break;
+ case EXIDEVICE_ETH:
+ GCEXIDevice[i]->SetStringSelection(SP1Devices[2]);
+ break;
+ case EXIDEVICE_AM_BASEBOARD:
+ GCEXIDevice[i]->SetStringSelection(SP1Devices[3]);
+ break;
+ case EXIDEVICE_DUMMY:
+ default:
+ GCEXIDevice[i]->SetStringSelection(SlotDevices[1]);
+ break;
+ }
if (!isMemcard && i < 2)
GCMemcardPath[i]->Disable();
}
@@ -384,7 +410,7 @@ void CConfigMain::CreateGUIControls()
GCSIDeviceText[1] = new wxStaticText(GamecubePage, ID_GC_SIDEVICE_TEXT, wxT("Port 2"), wxDefaultPosition, wxDefaultSize);
GCSIDeviceText[2] = new wxStaticText(GamecubePage, ID_GC_SIDEVICE_TEXT, wxT("Port 3"), wxDefaultPosition, wxDefaultSize);
GCSIDeviceText[3] = new wxStaticText(GamecubePage, ID_GC_SIDEVICE_TEXT, wxT("Port 4"), wxDefaultPosition, wxDefaultSize);
- const wxString SIDevices[] = {wxT(""), wxT("Standard Controller"), wxT("GBA")};
+ const wxString SIDevices[] = {wxT(DEV_DUMMY_STR),wxT(SIDEV_STDCONT_STR),wxT(SIDEV_GBA_STR),wxT(SIDEV_AM_BB_STR)};
static const int numSIDevices = sizeof(SIDevices)/sizeof(wxString);
GCSIDevice[0] = new wxChoice(GamecubePage, ID_GC_SIDEVICE0, wxDefaultPosition, wxDefaultSize, numSIDevices, SIDevices, 0, wxDefaultValidator);
GCSIDevice[1] = new wxChoice(GamecubePage, ID_GC_SIDEVICE1, wxDefaultPosition, wxDefaultSize, numSIDevices, SIDevices, 0, wxDefaultValidator);
@@ -392,12 +418,21 @@ void CConfigMain::CreateGUIControls()
GCSIDevice[3] = new wxChoice(GamecubePage, ID_GC_SIDEVICE3, wxDefaultPosition, wxDefaultSize, numSIDevices, SIDevices, 0, wxDefaultValidator);
for (int i = 0; i < 4; ++i)
{
- if (SConfig::GetInstance().m_SIDevice[i] == SI_GC_CONTROLLER)
+ switch (SConfig::GetInstance().m_SIDevice[i])
+ {
+ case SI_GC_CONTROLLER:
GCSIDevice[i]->SetStringSelection(SIDevices[1]);
- else if (SConfig::GetInstance().m_SIDevice[i] == SI_GBA)
+ break;
+ case SI_GBA:
GCSIDevice[i]->SetStringSelection(SIDevices[2]);
- else
+ break;
+ case SI_AM_BASEBOARD:
+ GCSIDevice[i]->SetStringSelection(SIDevices[3]);
+ break;
+ default:
GCSIDevice[i]->SetStringSelection(SIDevices[0]);
+ break;
+ }
}
sGamecube = new wxBoxSizer(wxVERTICAL);
@@ -678,7 +713,7 @@ void CConfigMain::GCSettingsChanged(wxCommandEvent& event)
SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage = GCSystemLang->GetSelection();
break;
- case ID_GC_EXIDEVICE_SP1: // The only thing we emulate on SP1 is the BBA
+ case ID_GC_EXIDEVICE_SP1:
exidevice++;
case ID_GC_EXIDEVICE_SLOTB:
exidevice++;
@@ -741,10 +776,12 @@ void CConfigMain::ChooseMemcardPath(std::string& strMemcard, bool isSlotA)
void CConfigMain::ChooseSIDevice(std::string deviceName, int deviceNum)
{
TSIDevices tempType;
- if (deviceName.compare("Standard Controller") == 0)
+ if (!deviceName.compare(SIDEV_STDCONT_STR))
tempType = SI_GC_CONTROLLER;
- else if (deviceName.compare("GBA") == 0)
+ else if (!deviceName.compare(SIDEV_GBA_STR))
tempType = SI_GBA;
+ else if (!deviceName.compare(SIDEV_AM_BB_STR))
+ tempType = SI_AM_BASEBOARD;
else
tempType = SI_DUMMY;
@@ -761,12 +798,16 @@ void CConfigMain::ChooseEXIDevice(std::string deviceName, int deviceNum)
{
TEXIDevices tempType;
- if (deviceName.compare("Memory Card") == 0)
+ if (!deviceName.compare(EXIDEV_MEMCARD_STR))
tempType = deviceNum ? EXIDEVICE_MEMORYCARD_B : EXIDEVICE_MEMORYCARD_A;
- else if (deviceName.compare("Mic") == 0)
+ else if (!deviceName.compare(EXIDEV_MIC_STR))
tempType = EXIDEVICE_MIC;
- else if (deviceName.compare("BBA") == 0)
+ else if (!deviceName.compare(EXIDEV_BBA_STR))
tempType = EXIDEVICE_ETH;
+ else if (!deviceName.compare(EXIDEV_AM_BB_STR))
+ tempType = EXIDEVICE_AM_BASEBOARD;
+ else if (!deviceName.compare(DEV_NONE_STR))
+ tempType = EXIDEVICE_NONE;
else
tempType = EXIDEVICE_DUMMY;
@@ -939,8 +980,6 @@ void CConfigMain::CallConfig(wxChoice* _pChoice)
void CConfigMain::FillChoiceBox(wxChoice* _pChoice, int _PluginType, const std::string& _SelectFilename)
{
- INFO_LOG(CONSOLE, "FillChoiceBox\n");
-
_pChoice->Clear();
int Index = -1;