Merge pull request #2067 from RedPanda4552/master

Add PSX memory card support
This commit is contained in:
ramapcsx2 2017-09-17 16:53:36 +02:00 committed by GitHub
commit af2278c3c2
6 changed files with 84 additions and 56 deletions

View File

@ -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)

View File

@ -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++;

View File

@ -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();

View File

@ -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;

View File

@ -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!)");
}

View File

@ -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) );