mirror of https://github.com/PCSX2/pcsx2.git
Merge pull request #2067 from RedPanda4552/master
Add PSX memory card support
This commit is contained in:
commit
af2278c3c2
|
@ -172,9 +172,8 @@ static __fi void _psxTestInterrupts()
|
|||
IopTestEvent(IopEvt_SIF0, sif0Interrupt); // SIF0
|
||||
IopTestEvent(IopEvt_SIF1, sif1Interrupt); // SIF1
|
||||
IopTestEvent(IopEvt_SIF2, sif2Interrupt); // SIF2
|
||||
#ifndef SIO_INLINE_IRQS
|
||||
IopTestEvent(IopEvt_SIO, sioInterrupt);
|
||||
#endif
|
||||
// Originally controlled by a preprocessor define, now PSX dependent.
|
||||
if (psxHu32(HW_ICFG) & (1 << 3)) IopTestEvent(IopEvt_SIO, sioInterruptR);
|
||||
IopTestEvent(IopEvt_CdvdRead, cdvdReadInterrupt);
|
||||
|
||||
// Profile-guided Optimization (sorta)
|
||||
|
|
|
@ -26,6 +26,7 @@ _mcd *mcd;
|
|||
SIO_MODE siomode = SIO_START;
|
||||
static void sioWrite8inl(u8 data);
|
||||
#define SIO_WRITE void inline
|
||||
#define SIO_FORCEINLINE __fi
|
||||
|
||||
// Magic psx values from nocash info
|
||||
static const u8 memcard_psx[] = {0x5A, 0x5D, 0x5C, 0x5D, 0x04, 0x00, 0x00, 0x80};
|
||||
|
@ -79,21 +80,6 @@ void ClearMcdEjectTimeoutNow()
|
|||
}
|
||||
}
|
||||
|
||||
// SIO Inline'd IRQs : Calls the SIO interrupt handlers directly instead of
|
||||
// feeding them through the IOP's branch test. (see SIO.H for details)
|
||||
|
||||
#ifdef SIO_INLINE_IRQS
|
||||
#define SIO_INT() sioInterrupt()
|
||||
#define SIO_FORCEINLINE __fi
|
||||
#else
|
||||
__fi void SIO_INT()
|
||||
{
|
||||
if( !(psxRegs.interrupt & (1<<IopEvt_SIO)) )
|
||||
PSX_INT(IopEvt_SIO, 64 ); // PSXCLK/250000);
|
||||
}
|
||||
#define SIO_FORCEINLINE __fi
|
||||
#endif
|
||||
|
||||
// Currently only check if pad wants mtap to be active.
|
||||
// Could lets PCSX2 have its own options, if anyone ever
|
||||
// wants to add support for using the extra memcard slots.
|
||||
|
@ -132,12 +118,32 @@ void sioInit()
|
|||
sio.packetsize = 0;
|
||||
}
|
||||
|
||||
void SIO_FORCEINLINE sioInterrupt()
|
||||
{
|
||||
PAD_LOG("Sio Interrupt");
|
||||
sio.StatReg|= IRQ;
|
||||
iopIntcIrq(7); //Should this be used instead of the one below?
|
||||
//psxHu32(0x1070)|=0x80;
|
||||
bool isR3000ATest = false;
|
||||
|
||||
// Check the active game's type, and fire the matching interrupt.
|
||||
// The 3rd bit of the HW_IFCG register lets us know if PSX mode is active. 1 = PSX, 0 = PS2
|
||||
// Note that the R3000A's call to interrupts only calls the PS2 based (lack of) delays.
|
||||
SIO_FORCEINLINE void sioInterrupt() {
|
||||
if ((psxHu32(HW_ICFG) & (1 << 3)) && !isR3000ATest) {
|
||||
if (!(psxRegs.interrupt & (1 << IopEvt_SIO)))
|
||||
PSX_INT(IopEvt_SIO, 64); // PSXCLK/250000);
|
||||
} else {
|
||||
PAD_LOG("Sio Interrupt");
|
||||
sio.StatReg |= IRQ;
|
||||
iopIntcIrq(7); //Should this be used instead of the one below?
|
||||
//psxHu32(0x1070)|=0x80;
|
||||
}
|
||||
|
||||
isR3000ATest = false;
|
||||
}
|
||||
|
||||
// An offhand way for the R3000A to access the sioInterrupt function.
|
||||
// Following the design of the old preprocessor system, the R3000A should
|
||||
// never call the PSX delays (oddly enough), and only the PS2. So we need
|
||||
// an extra layer here to help control that.
|
||||
__fi void sioInterruptR() {
|
||||
isR3000ATest = true;
|
||||
sioInterrupt();
|
||||
}
|
||||
|
||||
SIO_WRITE sioWriteStart(u8 data)
|
||||
|
@ -202,7 +208,7 @@ SIO_WRITE sioWriteController(u8 data)
|
|||
break;
|
||||
}
|
||||
//Console.WriteLn( "SIO: sent = %02X From pad data = %02X bufCnt %08X ", data, sio.buf[sio.bufCount], sio.bufCount);
|
||||
SIO_INT(); //Don't all commands(transfers) cause an interrupt?
|
||||
sioInterrupt(); //Don't all commands(transfers) cause an interrupt?
|
||||
}
|
||||
|
||||
SIO_WRITE sioWriteMultitap(u8 data)
|
||||
|
@ -290,7 +296,7 @@ SIO_WRITE sioWriteMultitap(u8 data)
|
|||
//default: sio.buf[sio.bufCount] = 0x00; break;
|
||||
}
|
||||
|
||||
SIO_INT();
|
||||
sioInterrupt();
|
||||
}
|
||||
|
||||
SIO_WRITE MemcardResponse()
|
||||
|
@ -365,7 +371,7 @@ SIO_WRITE memcardErase(u8 data)
|
|||
break;
|
||||
}
|
||||
}
|
||||
SIO_INT();
|
||||
sioInterrupt();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -427,7 +433,7 @@ SIO_WRITE memcardWrite(u8 data)
|
|||
}
|
||||
|
||||
}
|
||||
SIO_INT();
|
||||
sioInterrupt();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
@ -516,7 +522,7 @@ SIO_WRITE memcardRead(u8 data)
|
|||
break;
|
||||
}
|
||||
}
|
||||
SIO_INT();
|
||||
sioInterrupt();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
@ -629,7 +635,7 @@ SIO_WRITE sioWriteMemcard(u8 data)
|
|||
case 0:
|
||||
SIO_STAT_READY();
|
||||
memcardInit();
|
||||
SIO_INT();
|
||||
sioInterrupt();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
@ -703,7 +709,7 @@ SIO_WRITE sioWriteMemcard(u8 data)
|
|||
siomode = SIO_DUMMY;
|
||||
break;
|
||||
}
|
||||
SIO_INT();
|
||||
sioInterrupt();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
@ -725,7 +731,7 @@ SIO_WRITE sioWriteMemcardPSX(u8 data)
|
|||
case 0: // Same init stuff...
|
||||
SIO_STAT_READY();
|
||||
memcardInit();
|
||||
SIO_INT();
|
||||
sioInterrupt();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
@ -756,7 +762,7 @@ SIO_WRITE sioWriteMemcardPSX(u8 data)
|
|||
siomode = SIO_DUMMY;
|
||||
break;
|
||||
}
|
||||
SIO_INT();
|
||||
sioInterrupt();
|
||||
break;
|
||||
|
||||
case 2: break;
|
||||
|
@ -831,7 +837,7 @@ SIO_WRITE sioWriteInfraRed(u8 data)
|
|||
SIO_STAT_READY();
|
||||
DEVICE_PLUGGED();
|
||||
siomode = SIO_DUMMY;
|
||||
SIO_INT();
|
||||
sioInterrupt();
|
||||
}
|
||||
|
||||
//This bit-field in the STATUS register contains the (inveted) state of the /ACK linre from the Controller / MC.
|
||||
|
@ -856,12 +862,12 @@ SIO_WRITE sioWriteInfraRed(u8 data)
|
|||
void chkTriggerInt() {
|
||||
//Conditions for triggerring an interrupt.
|
||||
//this is not correct, but ... it can be fixed later
|
||||
SIO_INT(); return;
|
||||
if ((sio.StatReg & IRQ)) { SIO_INT(); return; } //The interrupt flag in the main INTR_STAT reg should go active on multiple occasions. Set it here for now (hack), until the correct mechanism is made.
|
||||
if ((sio.CtrlReg & ACK_INT_EN) && ((sio.StatReg & TX_RDY) || (sio.StatReg & TX_EMPTY))) { SIO_INT(); return; }
|
||||
if ((sio.CtrlReg & ACK_INT_EN) && (sio.StatReg & ACK_INP)) { SIO_INT(); return; }
|
||||
sioInterrupt(); return;
|
||||
if ((sio.StatReg & IRQ)) { sioInterrupt(); return; } //The interrupt flag in the main INTR_STAT reg should go active on multiple occasions. Set it here for now (hack), until the correct mechanism is made.
|
||||
if ((sio.CtrlReg & ACK_INT_EN) && ((sio.StatReg & TX_RDY) || (sio.StatReg & TX_EMPTY))) { sioInterrupt(); return; }
|
||||
if ((sio.CtrlReg & ACK_INT_EN) && (sio.StatReg & ACK_INP)) { sioInterrupt(); return; }
|
||||
//The following one may be incorrect.
|
||||
//if ((sio.CtrlReg & RX_INT_EN) && ((byteCnt >= (1<< ((sio.CtrlReg & RX_BYTES_INT) >>8))) ? 1:0) ) { SIO_INT(); return; }
|
||||
//if ((sio.CtrlReg & RX_INT_EN) && ((byteCnt >= (1<< ((sio.CtrlReg & RX_BYTES_INT) >>8))) ? 1:0) ) { sioInterrupt(); return; }
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -889,7 +895,7 @@ static void sioWrite8inl(u8 data)
|
|||
if (IS_LAST_BYTE_IN_PACKET != 1) //The following should be set after each byte transfer but the last one.
|
||||
sio.StatReg |= ACK_INP; //Signal that Controller (or MC) has brought the /ACK (Acknowledge) line active low.
|
||||
|
||||
SIO_INT();
|
||||
sioInterrupt();
|
||||
//chkTriggerInt();
|
||||
//Console.WriteLn( "SIO0 WR DATA COMMON %02X INT_STAT= %08X IOPpc= %08X " , data, psxHu32(0x1070), psxRegs.pc);
|
||||
byteCnt++;
|
||||
|
|
|
@ -15,10 +15,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// Let's enable this to free the IOP event handler of some considerable load.
|
||||
// Games are highly unlikely to need timed IRQ's for PAD and MemoryCard handling anyway (rama).
|
||||
#define SIO_INLINE_IRQS
|
||||
|
||||
#include "MemoryCardFile.h"
|
||||
|
||||
struct _mcd
|
||||
|
@ -125,6 +121,7 @@ extern u8 sioRead8();
|
|||
extern void sioWrite8(u8 value);
|
||||
extern void sioWriteCtrl16(u16 value);
|
||||
extern void sioInterrupt();
|
||||
extern void sioInterruptR();
|
||||
extern void InitializeSIO(u8 value);
|
||||
extern void SetForceMcdEjectTimeoutNow();
|
||||
extern void ClearMcdEjectTimeoutNow();
|
||||
|
|
|
@ -198,13 +198,14 @@ namespace Dialogs
|
|||
#ifdef __WXMSW__
|
||||
pxCheckBox* m_check_CompressNTFS;
|
||||
#endif
|
||||
pxCheckBox* m_check_psx;
|
||||
|
||||
public:
|
||||
virtual ~CreateMemoryCardDialog() = default;
|
||||
CreateMemoryCardDialog( wxWindow* parent, const wxDirName& mcdpath, const wxString& suggested_mcdfileName);
|
||||
|
||||
//duplicate of MemoryCardFile::Create. Don't know why the existing method isn't used. - avih
|
||||
static bool CreateIt( const wxString& mcdFile, uint sizeInMB );
|
||||
static bool CreateIt( const wxString& mcdFile, uint sizeInMB, bool isPSX );
|
||||
wxString result_createdMcdFilename;
|
||||
//wxDirName GetPathToMcds() const;
|
||||
|
||||
|
|
|
@ -87,6 +87,8 @@ Dialogs::CreateMemoryCardDialog::CreateMemoryCardDialog( wxWindow* parent, const
|
|||
s_padding += m_check_CompressNTFS | StdExpand();
|
||||
#endif
|
||||
|
||||
s_padding += m_check_psx;
|
||||
|
||||
s_padding += 12;
|
||||
s_padding += s_buttons | StdCenter();
|
||||
|
||||
|
@ -110,24 +112,44 @@ wxDirName Dialogs::CreateMemoryCardDialog::GetPathToMcds() const
|
|||
// When this GUI is moved into the FileMemoryCard plugin (where it eventually belongs),
|
||||
// this function will be removed and the MemoryCardFile::Create() function will be used
|
||||
// instead.
|
||||
bool Dialogs::CreateMemoryCardDialog::CreateIt( const wxString& mcdFile, uint sizeInMB )
|
||||
bool Dialogs::CreateMemoryCardDialog::CreateIt( const wxString& mcdFile, uint sizeInMB, bool isPSX )
|
||||
{
|
||||
//int enc[16] = {0x77,0x7f,0x7f,0x77,0x7f,0x7f,0x77,0x7f,0x7f,0x77,0x7f,0x7f,0,0,0,0};
|
||||
|
||||
u8 m_effeffs[528*16];
|
||||
memset8<0xff>( m_effeffs );
|
||||
// PS2 Memory Card
|
||||
u8 m_effeffs[528 * 16];
|
||||
memset8<0xff>(m_effeffs);
|
||||
|
||||
Console.WriteLn( L"(FileMcd) Creating new %uMB memory card: '%s'", sizeInMB, WX_STR(mcdFile) );
|
||||
// PSX Memory Card; 8192 is the size in bytes of a single block of a PSX memory card (8 KiB).
|
||||
u8 m_effeffs_psx[8192];
|
||||
memset8<0xff>(m_effeffs_psx);
|
||||
|
||||
// Since isPSX will have a default false state, it makes more sense to check "not PSX" first
|
||||
if (!isPSX) {
|
||||
Console.WriteLn(L"(FileMcd) Creating new PS2 %uMB memory card: '%s'", sizeInMB, WX_STR(mcdFile));
|
||||
}
|
||||
else {
|
||||
Console.WriteLn(L"(FileMcd) Creating new PSX 128 KiB memory card: '%s'", WX_STR(mcdFile));
|
||||
}
|
||||
|
||||
wxFFile fp( mcdFile, L"wb" );
|
||||
if( !fp.IsOpened() ) return false;
|
||||
|
||||
static const int MC2_MBSIZE = 1024 * 528 * 2; // Size of a single megabyte of card data
|
||||
|
||||
for( uint i=0; i<(MC2_MBSIZE*sizeInMB)/sizeof(m_effeffs); i++ )
|
||||
{
|
||||
if( fp.Write( m_effeffs, sizeof(m_effeffs) ) == 0 )
|
||||
return false;
|
||||
if (!isPSX) {
|
||||
for (uint i = 0; i<(MC2_MBSIZE*sizeInMB) / sizeof(m_effeffs); i++) {
|
||||
if (fp.Write(m_effeffs, sizeof(m_effeffs)) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// PSX cards consist of 16 blocks, each 8 KiB in size.
|
||||
for (uint i = 0; i < 16; i++) {
|
||||
if (fp.Write(m_effeffs_psx, sizeof(m_effeffs_psx)) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -170,9 +192,10 @@ void Dialogs::CreateMemoryCardDialog::OnOk_Click( wxCommandEvent& evt )
|
|||
}
|
||||
} else {
|
||||
// otherwise create a file
|
||||
if ( !CreateIt(
|
||||
if (!CreateIt(
|
||||
fullPath,
|
||||
m_radio_CardSize ? m_radio_CardSize->SelectedItem().SomeInt : 8
|
||||
m_radio_CardSize ? m_radio_CardSize->SelectedItem().SomeInt : 8,
|
||||
m_check_psx->GetValue()
|
||||
) ) {
|
||||
Msgbox::Alert(
|
||||
_( "Error: The memory card could not be created." ),
|
||||
|
@ -230,5 +253,7 @@ void Dialogs::CreateMemoryCardDialog::CreateControls()
|
|||
|
||||
m_radio_CardSize = new pxRadioPanel( this, tbl_CardSizes );
|
||||
m_radio_CardSize->SetDefaultItem(0);
|
||||
|
||||
m_check_psx = new pxCheckBox(this, "Make this a PSX card (128 KiB only, no folders!)");
|
||||
}
|
||||
|
||||
|
|
|
@ -551,7 +551,7 @@ void Panels::MemoryCardListPanel_Simple::AppStatusEvent_OnSettingsApplied()
|
|||
wxString errMsg;
|
||||
if (isValidNewFilename(m_Cards[slot].Filename.GetFullName(), GetMcdPath(), errMsg, 5))
|
||||
{
|
||||
if ( !Dialogs::CreateMemoryCardDialog::CreateIt(targetFile, 8) )
|
||||
if ( !Dialogs::CreateMemoryCardDialog::CreateIt(targetFile, 8, false) )
|
||||
Console.Error( L"Automatic createion of MCD '%s' failed. Hope for the best...", WX_STR(targetFile) );
|
||||
else
|
||||
Console.WriteLn( L"memcard created: '%s'.", WX_STR(targetFile) );
|
||||
|
|
Loading…
Reference in New Issue