mirror of https://github.com/PCSX2/pcsx2.git
SIO: Separate SIO2 from SIO0, reimplement memcard protocol
[SAVEVERSION+] Fixes memcard issues in MGS3, Shining Force EXA, and others which do 4 sector reads
This commit is contained in:
parent
3f99d1d3cc
commit
1146175648
|
@ -141,16 +141,17 @@ set(pcsx2Sources
|
|||
IopHw.cpp
|
||||
IopIrq.cpp
|
||||
IopMem.cpp
|
||||
IopSio2.cpp
|
||||
PINE.cpp
|
||||
Mdec.cpp
|
||||
Memory.cpp
|
||||
MemoryCardFile.cpp
|
||||
MemoryCardFolder.cpp
|
||||
MemoryCardProtocol.cpp
|
||||
MMI.cpp
|
||||
MTGS.cpp
|
||||
MTVU.cpp
|
||||
MultipartFileReader.cpp
|
||||
MultitapProtocol.cpp
|
||||
Patch.cpp
|
||||
Patch_Memory.cpp
|
||||
Pcsx2Config.cpp
|
||||
|
@ -217,14 +218,15 @@ set(pcsx2Headers
|
|||
IopGte.h
|
||||
IopHw.h
|
||||
IopMem.h
|
||||
IopSio2.h
|
||||
PINE.h
|
||||
Mdec.h
|
||||
MTVU.h
|
||||
Memory.h
|
||||
MemoryCardFile.h
|
||||
MemoryCardFolder.h
|
||||
MemoryCardProtocol.h
|
||||
MemoryTypes.h
|
||||
MultitapProtocol.h
|
||||
Patch.h
|
||||
PCSX2Base.h
|
||||
PerformanceMetrics.h
|
||||
|
@ -239,7 +241,6 @@ set(pcsx2Headers
|
|||
Sif.h
|
||||
SingleRegisterTypes.h
|
||||
Sio.h
|
||||
sio_internal.h
|
||||
SPR.h
|
||||
SysForwardDefs.h
|
||||
System.h
|
||||
|
|
|
@ -240,12 +240,7 @@ void Host::Internal::UpdateEmuFolders()
|
|||
{
|
||||
FileMcd_EmuClose();
|
||||
FileMcd_EmuOpen();
|
||||
|
||||
for (u32 port = 0; port < 2; port++)
|
||||
{
|
||||
for (u32 slot = 0; slot < 4; slot++)
|
||||
SetForceMcdEjectTimeoutNow(port, slot);
|
||||
}
|
||||
AutoEject::SetAll();
|
||||
}
|
||||
|
||||
if (EmuFolders::Textures != old_textures_directory)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "IopCounters.h"
|
||||
#include "IopHw.h"
|
||||
#include "IopDma.h"
|
||||
#include "Sio.h"
|
||||
|
||||
#include "Sif.h"
|
||||
#include "DEV9/DEV9.h"
|
||||
|
@ -224,4 +225,72 @@ void psxDma10(u32 madr, u32 bcr, u32 chcr)
|
|||
SIF1Dma();
|
||||
}
|
||||
|
||||
/* psxDma11 & psxDma 12 are in IopSio2.cpp, along with the appropriate interrupt functions. */
|
||||
void psxDma11(u32 madr, u32 bcr, u32 chcr)
|
||||
{
|
||||
unsigned int i, j;
|
||||
int size = (bcr >> 16) * (bcr & 0xffff);
|
||||
PSXDMA_LOG("*** DMA 11 - SIO2 in *** %lx addr = %lx size = %lx", chcr, madr, bcr);
|
||||
// Set dmaBlockSize, so SIO2 knows to count based on the DMA block rather than SEND3 length.
|
||||
// When SEND3 is written, SIO2 will automatically reset this to zero.
|
||||
sio2.dmaBlockSize = (bcr & 0xffff) * 4;
|
||||
|
||||
if (chcr != 0x01000201)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < (bcr >> 16); i++)
|
||||
{
|
||||
for (j = 0; j < ((bcr & 0xFFFF) * 4); j++)
|
||||
{
|
||||
const u8 data = iopMemRead8(madr);
|
||||
sio2.Write(data);
|
||||
madr++;
|
||||
}
|
||||
}
|
||||
|
||||
HW_DMA11_MADR = madr;
|
||||
PSX_INT(IopEvt_Dma11, (size >> 2));
|
||||
}
|
||||
|
||||
void psxDMA11Interrupt()
|
||||
{
|
||||
if (HW_DMA11_CHCR & 0x01000000)
|
||||
{
|
||||
HW_DMA11_CHCR &= ~0x01000000;
|
||||
psxDmaInterrupt2(4);
|
||||
}
|
||||
}
|
||||
|
||||
void psxDma12(u32 madr, u32 bcr, u32 chcr)
|
||||
{
|
||||
int size = ((bcr >> 16) * (bcr & 0xFFFF)) * 4;
|
||||
PSXDMA_LOG("*** DMA 12 - SIO2 out *** %lx addr = %lx size = %lx", chcr, madr, size);
|
||||
|
||||
if (chcr != 0x41000200)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bcr = size;
|
||||
|
||||
while (bcr > 0)
|
||||
{
|
||||
const u8 data = sio2.Read();
|
||||
iopMemWrite8(madr, data);
|
||||
bcr--;
|
||||
madr++;
|
||||
}
|
||||
|
||||
HW_DMA12_MADR = madr;
|
||||
PSX_INT(IopEvt_Dma12, (size >> 2));
|
||||
}
|
||||
|
||||
void psxDMA12Interrupt()
|
||||
{
|
||||
if (HW_DMA12_CHCR & 0x01000000)
|
||||
{
|
||||
HW_DMA12_CHCR &= ~0x01000000;
|
||||
psxDmaInterrupt2(5);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,13 @@ extern void psxDma7(u32 madr, u32 bcr, u32 chcr);
|
|||
extern void psxDma8(u32 madr, u32 bcr, u32 chcr);
|
||||
extern void psxDma9(u32 madr, u32 bcr, u32 chcr);
|
||||
extern void psxDma10(u32 madr, u32 bcr, u32 chcr);
|
||||
extern void psxDma11(u32 madr, u32 bcr, u32 chcr);
|
||||
extern void psxDma12(u32 madr, u32 bcr, u32 chcr);
|
||||
|
||||
extern int psxDma4Interrupt();
|
||||
extern int psxDma7Interrupt();
|
||||
extern void psxDMA11Interrupt();
|
||||
extern void psxDMA12Interrupt();
|
||||
extern void dev9Interrupt();
|
||||
extern void dev9Irq(int cycles);
|
||||
extern void usbInterrupt();
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "iR5900.h"
|
||||
#include "Sio.h"
|
||||
#include "Mdec.h"
|
||||
#include "IopSio2.h"
|
||||
#include "IopCounters.h"
|
||||
#include "IopHw.h"
|
||||
#include "IopDma.h"
|
||||
|
@ -42,8 +41,8 @@ void psxHwReset() {
|
|||
cdrReset();
|
||||
cdvdReset();
|
||||
psxRcntInit();
|
||||
sioInit();
|
||||
//sio2Reset();
|
||||
sio0.FullReset();
|
||||
sio2.FullReset();
|
||||
}
|
||||
|
||||
__fi u8 psxHw4Read8(u32 add)
|
||||
|
|
|
@ -1,271 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "Common.h"
|
||||
|
||||
#include "Sio.h"
|
||||
#include "sio_internal.h"
|
||||
#include "IopSio2.h"
|
||||
#include "IopHw.h"
|
||||
#include "IopDma.h"
|
||||
|
||||
sio2Struct sio2;
|
||||
|
||||
/*
|
||||
w [8268]=0x3bc sio2_start/sio2man
|
||||
r [8270] padman_start/padman
|
||||
padman->7480[00]=bit4;
|
||||
padman->7480[13]=bit5;
|
||||
packetExchange(&703F8);
|
||||
w [8268]|=0x0C;
|
||||
........
|
||||
w [8268]|=0x01;
|
||||
|
||||
only recv2 & dataout influences padman
|
||||
*/
|
||||
|
||||
// 0xBF808200,0xBF808204,0xBF808208,0xBF80820C,
|
||||
// 0xBF808210,0xBF808214,0xBF808218,0xBF80821C, packet->sendArray3
|
||||
// 0xBF808220,0xBF808224,0xBF808228,0xBF80822C, call12/13_s/getparams
|
||||
// 0xBF808230,0xBF808234,0xBF808238,0xBF80823C,
|
||||
|
||||
// 0xBF808240,0xBF808248,0xBF808250,0xBF808258, packet->sendArray1/call_7/8
|
||||
// 0xBF808244,0xBF80824C,0xBF808254,0xBF80825C, packet->sendArray2/call_9/10
|
||||
|
||||
// 0xBF808260, serial data/fifo in/out s/get8260_datain/out packet->sendbuf(nomem!)
|
||||
// 0xBF808268, ctrl s/get8268_ctrl
|
||||
|
||||
// 0xBF80826C, packet->recv1/2/3 get826C_recv1, get8270_recv2, get8274_recv3
|
||||
// 0xBF808270,0xBF808274,
|
||||
|
||||
// 0xBF808278,0xBF80827C, s/get8278, s/get827C
|
||||
// 0xBF808280 interrupt related s/get8280_intr
|
||||
|
||||
|
||||
void sio2Reset() {
|
||||
DevCon.WriteLn( "Sio2 Reset" );
|
||||
memzero(sio2);
|
||||
sio2.packet.recvVal1 = 0x1D100; // Nothing is connected at start
|
||||
}
|
||||
|
||||
u32 sio2_getRecv1() {
|
||||
PAD_LOG("Reading Recv1 = %x",sio2.packet.recvVal1);
|
||||
|
||||
return sio2.packet.recvVal1;
|
||||
}
|
||||
|
||||
u32 sio2_getRecv2() {
|
||||
PAD_LOG("Reading Recv2 = %x",0xF);
|
||||
|
||||
return 0xf;
|
||||
}//0, 0x10, 0x20, 0x10 | 0x20; bits 4 & 5
|
||||
|
||||
u32 sio2_getRecv3() {
|
||||
if(sio2.packet.recvVal3 == 0x8C || sio2.packet.recvVal3 == 0x8b ||
|
||||
sio2.packet.recvVal3 == 0x83)
|
||||
{
|
||||
PAD_LOG("Reading Recv3 = %x",sio2.packet.recvVal3);
|
||||
|
||||
sio.packetsize = sio2.packet.recvVal3;
|
||||
sio2.packet.recvVal3 = 0; // Reset
|
||||
return sio.packetsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
PAD_LOG("Reading Recv3 = %x",sio.packetsize << 16);
|
||||
|
||||
return sio.packetsize << 16;
|
||||
}
|
||||
}
|
||||
|
||||
void sio2_setSend1(u32 index, u32 value){sio2.packet.sendArray1[index]=value;} //0->3
|
||||
u32 sio2_getSend1(u32 index){return sio2.packet.sendArray1[index];} //0->3
|
||||
void sio2_setSend2(u32 index, u32 value){sio2.packet.sendArray2[index]=value;} //0->3
|
||||
u32 sio2_getSend2(u32 index){return sio2.packet.sendArray2[index];} //0->3
|
||||
|
||||
void sio2_setSend3(u32 index, u32 value)
|
||||
{
|
||||
// int i;
|
||||
sio2.packet.sendArray3[index]=value;
|
||||
// if (index==15){
|
||||
// for (i=0; i<4; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray1[i]);}PAD_LOG("\n");
|
||||
// for (i=0; i<4; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray2[i]);}PAD_LOG("\n");
|
||||
// for (i=0; i<8; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray3[i]);}PAD_LOG("\n");
|
||||
// for ( ; i<16; i++){PAD_LOG("0x%08X ", sio2.packet.sendArray3[i]);}PAD_LOG("\n");
|
||||
PAD_LOG("[%d] : 0x%08X", index,sio2.packet.sendArray3[index]);
|
||||
// }
|
||||
} //0->15
|
||||
|
||||
u32 sio2_getSend3(u32 index) {return sio2.packet.sendArray3[index];} //0->15
|
||||
|
||||
void sio2_setCtrl(u32 value){
|
||||
sio2.ctrl=value;
|
||||
if (sio2.ctrl & 1){ //recv packet
|
||||
//handle data that had been sent
|
||||
|
||||
iopIntcIrq( 17 );
|
||||
//SBUS
|
||||
sio2.recvIndex=0;
|
||||
sio2.ctrl &= ~1;
|
||||
} else { // send packet
|
||||
//clean up
|
||||
sio2.packet.sendSize=0; //reset size
|
||||
sio2.cmdport=0;
|
||||
sio2.cmdlength=0;
|
||||
sioWriteCtrl16(SIO_RESET);
|
||||
}
|
||||
}
|
||||
u32 sio2_getCtrl(){return sio2.ctrl;}
|
||||
|
||||
void sio2_setIntr(u32 value){sio2.intr=value;}
|
||||
u32 sio2_getIntr(){
|
||||
return sio2.intr;
|
||||
}
|
||||
|
||||
void sio2_set8278(u32 value){sio2._8278=value;}
|
||||
u32 sio2_get8278(){return sio2._8278;}
|
||||
void sio2_set827C(u32 value){sio2._827C=value;}
|
||||
u32 sio2_get827C(){return sio2._827C;}
|
||||
|
||||
void sio2_serialIn(u8 value){
|
||||
u16 ctrl=0x0002;
|
||||
if (sio2.packet.sendArray3[sio2.cmdport] && (sio2.cmdlength==0))
|
||||
{
|
||||
|
||||
sio2.cmdlength=(sio2.packet.sendArray3[sio2.cmdport] >> 8) & 0x1FF;
|
||||
ctrl &= ~0x2000;
|
||||
ctrl |= (sio2.packet.sendArray3[sio2.cmdport] & 1) << 13;
|
||||
//sioWriteCtrl16(SIO_RESET);
|
||||
sioWriteCtrl16(ctrl);
|
||||
PSXDMA_LOG("sio2_fifoIn: ctrl = %x, cmdlength = %x, cmdport = %d (%x)", ctrl, sio2.cmdlength, sio2.cmdport, sio2.packet.sendArray3[sio2.cmdport]);
|
||||
|
||||
sio2.cmdport++;
|
||||
}
|
||||
|
||||
if (sio2.cmdlength) sio2.cmdlength--;
|
||||
sioWrite8(value);
|
||||
|
||||
if (sio2.packet.sendSize >= BUFSIZE) {//asadr
|
||||
Console.Warning("*PCSX2*: sendSize >= %d", BUFSIZE);
|
||||
} else {
|
||||
sio2.buf[sio2.packet.sendSize] = sioRead8();
|
||||
sio2.packet.sendSize++;
|
||||
}
|
||||
}
|
||||
extern void SIODMAWrite(u8 value);
|
||||
|
||||
void sio2_fifoIn(u8 value){
|
||||
u16 ctrl=0x0002;
|
||||
if (sio2.packet.sendArray3[sio2.cmdport] && (sio2.cmdlength==0))
|
||||
{
|
||||
|
||||
sio2.cmdlength=(sio2.packet.sendArray3[sio2.cmdport] >> 8) & 0x1FF;
|
||||
ctrl &= ~0x2000;
|
||||
ctrl |= (sio2.packet.sendArray3[sio2.cmdport] & 1) << 13;
|
||||
//sioWriteCtrl16(SIO_RESET);
|
||||
sioWriteCtrl16(ctrl);
|
||||
PSXDMA_LOG("sio2_fifoIn: ctrl = %x, cmdlength = %x, cmdport = %d (%x)", ctrl, sio2.cmdlength, sio2.cmdport, sio2.packet.sendArray3[sio2.cmdport]);
|
||||
|
||||
sio2.cmdport++;
|
||||
}
|
||||
|
||||
if (sio2.cmdlength) sio2.cmdlength--;
|
||||
SIODMAWrite(value);
|
||||
|
||||
if (sio2.packet.sendSize >= BUFSIZE) {//asadr
|
||||
Console.WriteLn("*PCSX2*: sendSize >= %d", BUFSIZE);
|
||||
} else {
|
||||
sio2.buf[sio2.packet.sendSize] = sioRead8();
|
||||
sio2.packet.sendSize++;
|
||||
}
|
||||
}
|
||||
|
||||
u8 sio2_fifoOut(){
|
||||
if (sio2.recvIndex <= sio2.packet.sendSize){
|
||||
//PAD_LOG("READING %x\n",sio2.buf[sio2.recvIndex]);
|
||||
return sio2.buf[sio2.recvIndex++];
|
||||
} else {
|
||||
Console.Error( "*PCSX2*: buffer overrun" );
|
||||
}
|
||||
return 0; // No Data
|
||||
}
|
||||
|
||||
void SaveStateBase::sio2Freeze()
|
||||
{
|
||||
FreezeTag( "sio2" );
|
||||
Freeze(sio2);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
//////////////////////////////////////////// DMA
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
void psxDma11(u32 madr, u32 bcr, u32 chcr) {
|
||||
unsigned int i, j;
|
||||
int size = (bcr >> 16) * (bcr & 0xffff);
|
||||
PSXDMA_LOG("*** DMA 11 - SIO2 in *** %lx addr = %lx size = %lx", chcr, madr, bcr);
|
||||
|
||||
if (chcr != 0x01000201) return;
|
||||
|
||||
for(i = 0; i < (bcr >> 16); i++)
|
||||
{
|
||||
sio.count = 1;
|
||||
for(j = 0; j < ((bcr & 0xFFFF) * 4); j++)
|
||||
{
|
||||
sio2_fifoIn(iopMemRead8(madr));
|
||||
madr++;
|
||||
if(sio2.packet.sendSize == BUFSIZE)
|
||||
goto finished;
|
||||
}
|
||||
}
|
||||
|
||||
finished:
|
||||
HW_DMA11_MADR = madr;
|
||||
PSX_INT(IopEvt_Dma11,(size>>2)); // Interrupts should always occur at the end
|
||||
}
|
||||
|
||||
void psxDMA11Interrupt()
|
||||
{
|
||||
HW_DMA11_CHCR &= ~0x01000000;
|
||||
psxDmaInterrupt2(4);
|
||||
}
|
||||
|
||||
void psxDma12(u32 madr, u32 bcr, u32 chcr) {
|
||||
int size = ((bcr >> 16) * (bcr & 0xFFFF)) * 4;
|
||||
PSXDMA_LOG("*** DMA 12 - SIO2 out *** %lx addr = %lx size = %lx", chcr, madr, size);
|
||||
|
||||
if (chcr != 0x41000200) return;
|
||||
|
||||
sio2.recvIndex = 0; // Set To start; saqib
|
||||
|
||||
bcr = size;
|
||||
while (bcr > 0) {
|
||||
iopMemWrite8( madr, sio2_fifoOut() );
|
||||
bcr--; madr++;
|
||||
if(sio2.recvIndex == sio2.packet.sendSize) break;
|
||||
}
|
||||
HW_DMA12_MADR = madr;
|
||||
PSX_INT(IopEvt_Dma12,(size>>2)); // Interrupts should always occur at the end
|
||||
}
|
||||
|
||||
void psxDMA12Interrupt()
|
||||
{
|
||||
HW_DMA12_CHCR &= ~0x01000000;
|
||||
psxDmaInterrupt2(5);
|
||||
}
|
||||
|
||||
//#endif
|
|
@ -1,91 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define BUFSIZE 8448
|
||||
|
||||
//from sio2man.c
|
||||
|
||||
struct SIO2_packet {
|
||||
unsigned int recvVal1; // 0x00
|
||||
unsigned int sendArray1[4]; // 0x04-0x10
|
||||
unsigned int sendArray2[4]; // 0x14-0x20
|
||||
|
||||
unsigned int recvVal2; // 0x24
|
||||
|
||||
unsigned int sendArray3[16]; // 0x28-0x64
|
||||
|
||||
unsigned int recvVal3; // 0x68
|
||||
|
||||
int sendSize; // 0x6C
|
||||
int recvSize; // 0x70
|
||||
|
||||
unsigned char *sendBuf; // 0x74
|
||||
unsigned char *recvBuf; // 0x78
|
||||
|
||||
unsigned int dmacAddress1;
|
||||
unsigned int dmacSize1;
|
||||
unsigned int dmacCount1;
|
||||
unsigned int dmacAddress2;
|
||||
unsigned int dmacSize2;
|
||||
unsigned int dmacCount2;
|
||||
};
|
||||
|
||||
struct sio2Struct {
|
||||
struct SIO2_packet packet;
|
||||
u32 ctrl;
|
||||
u32 intr;
|
||||
u32 _8278, _827C;
|
||||
int recvIndex;
|
||||
u32 hackedRecv;
|
||||
int cmdport;
|
||||
int cmdlength; //length of a command sent to a port
|
||||
//is less_equal than the dma send size
|
||||
u8 buf[BUFSIZE];
|
||||
};
|
||||
|
||||
extern sio2Struct sio2;
|
||||
|
||||
void sio2Reset();
|
||||
|
||||
u32 sio2_getRecv1();
|
||||
u32 sio2_getRecv2();
|
||||
u32 sio2_getRecv3();
|
||||
void sio2_setSend1(u32 index, u32 value); //0->3
|
||||
u32 sio2_getSend1(u32 index); //0->3
|
||||
void sio2_setSend2(u32 index, u32 value); //0->3
|
||||
u32 sio2_getSend2(u32 index); //0->3
|
||||
void sio2_setSend3(u32 index, u32 value); //0->15
|
||||
u32 sio2_getSend3(u32 index); //0->15
|
||||
|
||||
void sio2_setCtrl(u32 value);
|
||||
u32 sio2_getCtrl();
|
||||
void sio2_setIntr(u32 value);
|
||||
u32 sio2_getIntr();
|
||||
void sio2_set8278(u32 value);
|
||||
u32 sio2_get8278();
|
||||
void sio2_set827C(u32 value);
|
||||
u32 sio2_get827C();
|
||||
|
||||
void sio2_serialIn(u8 value);
|
||||
void sio2_fifoIn(u8 value);
|
||||
u8 sio2_fifoOut();
|
||||
|
||||
void psxDma11(u32 madr, u32 bcr, u32 chcr);
|
||||
void psxDma12(u32 madr, u32 bcr, u32 chcr);
|
||||
|
||||
void psxDMA11Interrupt();
|
||||
void psxDMA12Interrupt();
|
|
@ -0,0 +1,501 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "MemoryCardProtocol.h"
|
||||
#include "Sio.h"
|
||||
|
||||
#define MC_LOG_ENABLE 0
|
||||
#define MC_LOG if (MC_LOG_ENABLE) DevCon
|
||||
|
||||
#define PS1_FAIL() if (this->PS1Fail()) return;
|
||||
|
||||
MemoryCardProtocol g_MemoryCardProtocol;
|
||||
|
||||
// Check if the memcard is for PS1, and if we are working on a command sent over SIO2.
|
||||
// If so, return dead air.
|
||||
bool MemoryCardProtocol::PS1Fail()
|
||||
{
|
||||
if (mcd->IsPSX() && sio2.commandLength > 0)
|
||||
{
|
||||
while (fifoOut.size() < sio2.commandLength)
|
||||
{
|
||||
fifoOut.push_back(0x00);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// A repeated pattern in memcard commands is to pad with zero bytes,
|
||||
// then end with 0x2b and terminator bytes. This function is a shortcut for that.
|
||||
void MemoryCardProtocol::The2bTerminator(size_t length)
|
||||
{
|
||||
while (fifoOut.size() < length - 2)
|
||||
{
|
||||
fifoOut.push_back(0x00);
|
||||
}
|
||||
|
||||
fifoOut.push_back(0x2b);
|
||||
fifoOut.push_back(mcd->term);
|
||||
}
|
||||
|
||||
// After one read or write, the memcard is almost certainly going to be issued a new read or write
|
||||
// for the next segment of the same sector. Bump the transferAddr to where that segment begins.
|
||||
// If it is the end and a new sector is being accessed, the SetSector function will deal with
|
||||
// both sectorAddr and transferAddr.
|
||||
void MemoryCardProtocol::ReadWriteIncrement(size_t length)
|
||||
{
|
||||
mcd->transferAddr += length;
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::RecalculatePS1Addr()
|
||||
{
|
||||
mcd->sectorAddr = ((ps1McState.sectorAddrMSB << 8) | ps1McState.sectorAddrLSB);
|
||||
mcd->goodSector = (mcd->sectorAddr <= 0x03ff);
|
||||
mcd->transferAddr = 128 * mcd->sectorAddr;
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::ResetPS1State()
|
||||
{
|
||||
ps1McState.currentByte = 2;
|
||||
ps1McState.sectorAddrMSB = 0;
|
||||
ps1McState.sectorAddrLSB = 0;
|
||||
ps1McState.checksum = 0;
|
||||
ps1McState.expectedChecksum = 0;
|
||||
memset(ps1McState.buf.data(), 0, ps1McState.buf.size());
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::Probe()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
The2bTerminator(4);
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::UnknownWriteDeleteEnd()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
The2bTerminator(4);
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::SetSector()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
const u8 sectorLSB = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
const u8 sector2nd = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
const u8 sector3rd = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
const u8 sectorMSB = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
const u8 expectedChecksum = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
|
||||
u8 computedChecksum = sectorLSB ^ sector2nd ^ sector3rd ^ sectorMSB;
|
||||
mcd->goodSector = (computedChecksum == expectedChecksum);
|
||||
|
||||
if (!mcd->goodSector)
|
||||
{
|
||||
Console.Warning("%s() Warning! Memcard sector checksum failed! (Expected %02X != Actual %02X) Please report to the PCSX2 team!", __FUNCTION__, expectedChecksum, computedChecksum);
|
||||
}
|
||||
|
||||
u32 newSector = sectorLSB | (sector2nd << 8) | (sector3rd << 16) | (sectorMSB << 24);
|
||||
mcd->sectorAddr = newSector;
|
||||
|
||||
McdSizeInfo info;
|
||||
mcd->GetSizeInfo(info);
|
||||
mcd->transferAddr = (info.SectorSize + 16) * mcd->sectorAddr;
|
||||
|
||||
The2bTerminator(9);
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::GetSpecs()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
u8 checksum = 0x00;
|
||||
McdSizeInfo info;
|
||||
mcd->GetSizeInfo(info);
|
||||
fifoOut.push_back(0x2b);
|
||||
|
||||
const u8 sectorSizeLSB = (info.SectorSize & 0xff);
|
||||
checksum ^= sectorSizeLSB;
|
||||
fifoOut.push_back(sectorSizeLSB);
|
||||
|
||||
const u8 sectorSizeMSB = (info.SectorSize >> 8);
|
||||
checksum ^= sectorSizeMSB;
|
||||
fifoOut.push_back(sectorSizeMSB);
|
||||
|
||||
const u8 eraseBlockSizeLSB = (info.EraseBlockSizeInSectors & 0xff);
|
||||
checksum ^= eraseBlockSizeLSB;
|
||||
fifoOut.push_back(eraseBlockSizeLSB);
|
||||
|
||||
const u8 eraseBlockSizeMSB = (info.EraseBlockSizeInSectors >> 8);
|
||||
checksum ^= eraseBlockSizeMSB;
|
||||
fifoOut.push_back(eraseBlockSizeMSB);
|
||||
|
||||
const u8 sectorCountLSB = (info.McdSizeInSectors & 0xff);
|
||||
checksum ^= sectorCountLSB;
|
||||
fifoOut.push_back(sectorCountLSB);
|
||||
|
||||
const u8 sectorCount2nd = (info.McdSizeInSectors >> 8);
|
||||
checksum ^= sectorCount2nd;
|
||||
fifoOut.push_back(sectorCount2nd);
|
||||
|
||||
const u8 sectorCount3rd = (info.McdSizeInSectors >> 16);
|
||||
checksum ^= sectorCount3rd;
|
||||
fifoOut.push_back(sectorCount3rd);
|
||||
|
||||
const u8 sectorCountMSB = (info.McdSizeInSectors >> 24);
|
||||
checksum ^= sectorCountMSB;
|
||||
fifoOut.push_back(sectorCountMSB);
|
||||
|
||||
fifoOut.push_back(info.Xor);
|
||||
fifoOut.push_back(mcd->term);
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::SetTerminator()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
const u8 newTerminator = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
const u8 oldTerminator = mcd->term;
|
||||
mcd->term = newTerminator;
|
||||
fifoOut.push_back(0x00);
|
||||
fifoOut.push_back(0x2b);
|
||||
fifoOut.push_back(oldTerminator);
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::GetTerminator()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
fifoOut.push_back(0x2b);
|
||||
fifoOut.push_back(mcd->term);
|
||||
fifoOut.push_back(static_cast<u8>(Terminator::DEFAULT));
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::WriteData()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
fifoOut.push_back(0x00);
|
||||
fifoOut.push_back(0x2b);
|
||||
const u8 writeLength = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
u8 checksum = 0x00;
|
||||
std::vector<u8> buf;
|
||||
|
||||
for (size_t writeCounter = 0; writeCounter < writeLength; writeCounter++)
|
||||
{
|
||||
const u8 writeByte = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
checksum ^= writeByte;
|
||||
buf.push_back(writeByte);
|
||||
fifoOut.push_back(0x00);
|
||||
}
|
||||
|
||||
mcd->Write(buf.data(), buf.size());
|
||||
fifoOut.push_back(checksum);
|
||||
fifoOut.push_back(mcd->term);
|
||||
|
||||
ReadWriteIncrement(writeLength);
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::ReadData()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
const u8 readLength = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
fifoOut.push_back(0x00);
|
||||
fifoOut.push_back(0x2b);
|
||||
std::vector<u8> buf;
|
||||
buf.resize(readLength);
|
||||
mcd->Read(buf.data(), buf.size());
|
||||
u8 checksum = 0x00;
|
||||
|
||||
for (const u8 readByte : buf)
|
||||
{
|
||||
checksum ^= readByte;
|
||||
fifoOut.push_back(readByte);
|
||||
}
|
||||
|
||||
fifoOut.push_back(checksum);
|
||||
fifoOut.push_back(mcd->term);
|
||||
|
||||
ReadWriteIncrement(readLength);
|
||||
}
|
||||
|
||||
u8 MemoryCardProtocol::PS1Read(u8 data)
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
bool sendAck = true;
|
||||
u8 ret = 0;
|
||||
|
||||
switch (ps1McState.currentByte)
|
||||
{
|
||||
case 2:
|
||||
ret = 0x5a;
|
||||
break;
|
||||
case 3:
|
||||
ret = 0x5d;
|
||||
break;
|
||||
case 4:
|
||||
ps1McState.sectorAddrMSB = data;
|
||||
ret = 0x00;
|
||||
break;
|
||||
case 5:
|
||||
ps1McState.sectorAddrLSB = data;
|
||||
ret = 0x00;
|
||||
RecalculatePS1Addr();
|
||||
break;
|
||||
case 6:
|
||||
ret = 0x5c;
|
||||
break;
|
||||
case 7:
|
||||
ret = 0x5d;
|
||||
break;
|
||||
case 8:
|
||||
ret = ps1McState.sectorAddrMSB;
|
||||
break;
|
||||
case 9:
|
||||
ret = ps1McState.sectorAddrLSB;
|
||||
break;
|
||||
case 138:
|
||||
ret = ps1McState.checksum;
|
||||
break;
|
||||
case 139:
|
||||
ret = 0x47;
|
||||
sendAck = false;
|
||||
break;
|
||||
case 10:
|
||||
ps1McState.checksum = ps1McState.sectorAddrMSB ^ ps1McState.sectorAddrLSB;
|
||||
mcd->Read(ps1McState.buf.data(), ps1McState.buf.size());
|
||||
default:
|
||||
ret = ps1McState.buf.at(ps1McState.currentByte - 10);
|
||||
ps1McState.checksum ^= ret;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sendAck)
|
||||
{
|
||||
sio0.Acknowledge();
|
||||
}
|
||||
|
||||
ps1McState.currentByte++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
u8 MemoryCardProtocol::PS1State(u8 data)
|
||||
{
|
||||
DevCon.Error("%s(%02X) I do not exist, please change that ASAP.", __FUNCTION__, data);
|
||||
assert(false);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
u8 MemoryCardProtocol::PS1Write(u8 data)
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
bool sendAck = true;
|
||||
u8 ret = 0;
|
||||
|
||||
switch (ps1McState.currentByte)
|
||||
{
|
||||
case 2:
|
||||
ret = 0x5a;
|
||||
break;
|
||||
case 3:
|
||||
ret = 0x5d;
|
||||
break;
|
||||
case 4:
|
||||
ps1McState.sectorAddrMSB = data;
|
||||
ret = 0x00;
|
||||
break;
|
||||
case 5:
|
||||
ps1McState.sectorAddrLSB = data;
|
||||
ret = 0x00;
|
||||
RecalculatePS1Addr();
|
||||
break;
|
||||
case 134:
|
||||
ps1McState.expectedChecksum = data;
|
||||
ret = 0;
|
||||
break;
|
||||
case 135:
|
||||
ret = 0x5c;
|
||||
break;
|
||||
case 136:
|
||||
ret = 0x5d;
|
||||
break;
|
||||
case 137:
|
||||
if (!mcd->goodSector)
|
||||
{
|
||||
ret = 0xff;
|
||||
}
|
||||
else if (ps1McState.expectedChecksum != ps1McState.checksum)
|
||||
{
|
||||
ret = 0x4e;
|
||||
}
|
||||
else
|
||||
{
|
||||
mcd->Write(ps1McState.buf.data(), ps1McState.buf.size());
|
||||
ret = 0x47;
|
||||
// Clear the "directory unread" bit of the flag byte. Per no$psx, this is cleared
|
||||
// on writes, not reads.
|
||||
mcd->FLAG &= 0x07;
|
||||
}
|
||||
|
||||
sendAck = false;
|
||||
break;
|
||||
case 6:
|
||||
ps1McState.checksum = ps1McState.sectorAddrMSB ^ ps1McState.sectorAddrLSB;
|
||||
default:
|
||||
ps1McState.buf.at(ps1McState.currentByte - 6) = data;
|
||||
ps1McState.checksum ^= data;
|
||||
ret = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sendAck)
|
||||
{
|
||||
sio0.Acknowledge();
|
||||
}
|
||||
|
||||
ps1McState.currentByte++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
u8 MemoryCardProtocol::PS1Pocketstation(u8 data)
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
sio2.SetRecv1(Recv1::DISCONNECTED);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::ReadWriteEnd()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
The2bTerminator(4);
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::EraseBlock()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
mcd->EraseBlock();
|
||||
The2bTerminator(4);
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::UnknownBoot()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
The2bTerminator(5);
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::AuthXor()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
const u8 modeByte = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
|
||||
switch (modeByte)
|
||||
{
|
||||
// When encountered, the command length in RECV3 is guaranteed to be 14,
|
||||
// and the PS2 is expecting us to XOR the data it is about to send.
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x04:
|
||||
case 0x0f:
|
||||
case 0x11:
|
||||
case 0x13:
|
||||
{
|
||||
// Long + XOR
|
||||
fifoOut.push_back(0x00);
|
||||
fifoOut.push_back(0x2b);
|
||||
u8 xorResult = 0x00;
|
||||
|
||||
for (size_t xorCounter = 0; xorCounter < 8; xorCounter++)
|
||||
{
|
||||
const u8 toXOR = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
xorResult ^= toXOR;
|
||||
fifoOut.push_back(0x00);
|
||||
}
|
||||
|
||||
fifoOut.push_back(xorResult);
|
||||
fifoOut.push_back(mcd->term);
|
||||
break;
|
||||
}
|
||||
// When encountered, the command length in RECV3 is guaranteed to be 5,
|
||||
// and there is no attempt to XOR anything.
|
||||
case 0x00:
|
||||
case 0x03:
|
||||
case 0x05:
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0a:
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
case 0x0e:
|
||||
case 0x10:
|
||||
case 0x12:
|
||||
case 0x14:
|
||||
{
|
||||
// Short + No XOR
|
||||
The2bTerminator(5);
|
||||
break;
|
||||
}
|
||||
// When encountered, the command length in RECV3 is guaranteed to be 14,
|
||||
// and the PS2 is about to send us data, BUT the PS2 does NOT want us
|
||||
// to send the XOR, it wants us to send the 0x2b and terminator as the
|
||||
// last two bytes.
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x0b:
|
||||
{
|
||||
// Long + No XOR
|
||||
The2bTerminator(14);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Console.Warning("%s(queue) Unexpected modeByte (%02X), please report to the PCSX2 team", __FUNCTION__, modeByte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::AuthF3()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
The2bTerminator(5);
|
||||
}
|
||||
|
||||
void MemoryCardProtocol::AuthF7()
|
||||
{
|
||||
MC_LOG.WriteLn("%s", __FUNCTION__);
|
||||
PS1_FAIL();
|
||||
The2bTerminator(5);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
struct PS1MemoryCardState
|
||||
{
|
||||
size_t currentByte = 2;
|
||||
u8 sectorAddrMSB = 0;
|
||||
u8 sectorAddrLSB = 0;
|
||||
u8 checksum = 0;
|
||||
u8 expectedChecksum = 0;
|
||||
std::array<u8, 128> buf;
|
||||
};
|
||||
|
||||
// A global class which contains the behavior of each memory card command.
|
||||
class MemoryCardProtocol
|
||||
{
|
||||
private:
|
||||
PS1MemoryCardState ps1McState;
|
||||
|
||||
bool PS1Fail();
|
||||
void The2bTerminator(size_t length);
|
||||
void ReadWriteIncrement(size_t length);
|
||||
void RecalculatePS1Addr();
|
||||
|
||||
public:
|
||||
void ResetPS1State();
|
||||
|
||||
void Probe();
|
||||
void UnknownWriteDeleteEnd();
|
||||
void SetSector();
|
||||
void GetSpecs();
|
||||
void SetTerminator();
|
||||
void GetTerminator();
|
||||
void WriteData();
|
||||
void ReadData();
|
||||
u8 PS1Read(u8 data);
|
||||
u8 PS1State(u8 data);
|
||||
u8 PS1Write(u8 data);
|
||||
u8 PS1Pocketstation(u8 data);
|
||||
void ReadWriteEnd();
|
||||
void EraseBlock();
|
||||
void UnknownBoot();
|
||||
void AuthXor();
|
||||
void AuthF3();
|
||||
void AuthF7();
|
||||
};
|
||||
|
||||
extern MemoryCardProtocol g_MemoryCardProtocol;
|
|
@ -0,0 +1,89 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "MultitapProtocol.h"
|
||||
#include "Sio.h"
|
||||
|
||||
#define MT_LOG_ENABLE 0
|
||||
#define MT_LOG if (MT_LOG_ENABLE) DevCon
|
||||
|
||||
MultitapProtocol g_MultitapProtocol;
|
||||
|
||||
void MultitapProtocol::SupportCheck()
|
||||
{
|
||||
MT_LOG.WriteLn("%s", __FUNCTION__);
|
||||
fifoOut.push_back(0x5a);
|
||||
fifoOut.push_back(0x04);
|
||||
fifoOut.push_back(0x00);
|
||||
fifoOut.push_back(0x5a);
|
||||
}
|
||||
|
||||
void MultitapProtocol::Select()
|
||||
{
|
||||
MT_LOG.WriteLn("%s", __FUNCTION__);
|
||||
const u8 newSlot = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
const bool isInBounds = (newSlot >= 0 && newSlot < SIO::SLOTS);
|
||||
|
||||
if (isInBounds)
|
||||
{
|
||||
sio2.slot = newSlot;
|
||||
MT_LOG.WriteLn("Slot changed to %d", sio2.slot);
|
||||
}
|
||||
|
||||
fifoOut.push_back(0x5a);
|
||||
fifoOut.push_back(0x00);
|
||||
fifoOut.push_back(0x00);
|
||||
fifoOut.push_back(isInBounds ? newSlot : 0xff);
|
||||
fifoOut.push_back(isInBounds ? 0x5a : 0x66);
|
||||
}
|
||||
|
||||
MultitapProtocol::MultitapProtocol() = default;
|
||||
MultitapProtocol::~MultitapProtocol() = default;
|
||||
|
||||
void MultitapProtocol::SoftReset()
|
||||
{
|
||||
}
|
||||
|
||||
void MultitapProtocol::FullReset()
|
||||
{
|
||||
SoftReset();
|
||||
|
||||
sio2.slot = 0;
|
||||
}
|
||||
|
||||
void MultitapProtocol::SendToMultitap()
|
||||
{
|
||||
const u8 commandByte = fifoIn.front();
|
||||
fifoIn.pop_front();
|
||||
fifoOut.push_back(0x80);
|
||||
|
||||
switch (static_cast<MultitapMode>(commandByte))
|
||||
{
|
||||
case MultitapMode::PAD_SUPPORT_CHECK:
|
||||
case MultitapMode::MEMCARD_SUPPORT_CHECK:
|
||||
SupportCheck();
|
||||
break;
|
||||
case MultitapMode::SELECT_PAD:
|
||||
case MultitapMode::SELECT_MEMCARD:
|
||||
Select();
|
||||
break;
|
||||
default:
|
||||
DevCon.Warning("%s() Unhandled MultitapMode (%02X)", __FUNCTION__, commandByte);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
enum class MultitapMode
|
||||
{
|
||||
NOT_SET = 0xff,
|
||||
PAD_SUPPORT_CHECK = 0x12,
|
||||
MEMCARD_SUPPORT_CHECK = 0x13,
|
||||
SELECT_PAD = 0x21,
|
||||
SELECT_MEMCARD = 0x22,
|
||||
};
|
||||
|
||||
class MultitapProtocol
|
||||
{
|
||||
private:
|
||||
void SupportCheck();
|
||||
void Select();
|
||||
|
||||
public:
|
||||
MultitapProtocol();
|
||||
~MultitapProtocol();
|
||||
|
||||
void SoftReset();
|
||||
void FullReset();
|
||||
|
||||
void SendToMultitap();
|
||||
};
|
||||
|
||||
extern MultitapProtocol g_MultitapProtocol;
|
|
@ -24,8 +24,9 @@ void PADshutdown();
|
|||
s32 PADopen(const WindowInfo& wi);
|
||||
void PADupdate(int pad);
|
||||
void PADclose();
|
||||
u8 PADstartPoll(int pad);
|
||||
u8 PADstartPoll(int port, int slot);
|
||||
u8 PADpoll(u8 value);
|
||||
bool PADcomplete();
|
||||
HostKeyEvent* PADkeyEvent();
|
||||
void PADconfigure();
|
||||
s32 PADfreeze(FreezeAction mode, freezeData* data);
|
||||
|
|
|
@ -173,9 +173,9 @@ s32 PADfreeze(FreezeAction mode, freezeData* data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
u8 PADstartPoll(int pad)
|
||||
u8 PADstartPoll(int _port, int _slot)
|
||||
{
|
||||
return pad_start_poll(pad);
|
||||
return pad_start_poll(_port, _slot);
|
||||
}
|
||||
|
||||
u8 PADpoll(u8 value)
|
||||
|
@ -244,6 +244,11 @@ std::string PAD::GetConfigSection(u32 pad_index)
|
|||
return fmt::format("Pad{}", pad_index + 1);
|
||||
}
|
||||
|
||||
bool PADcomplete()
|
||||
{
|
||||
return pad_complete();
|
||||
}
|
||||
|
||||
void PAD::LoadConfig(const SettingsInterface& si)
|
||||
{
|
||||
PAD::s_macro_buttons = {};
|
||||
|
|
|
@ -33,8 +33,9 @@ s32 PADopen(const WindowInfo& wi);
|
|||
void PADclose();
|
||||
s32 PADsetSlot(u8 port, u8 slot);
|
||||
s32 PADfreeze(FreezeAction mode, freezeData* data);
|
||||
u8 PADstartPoll(int pad);
|
||||
u8 PADstartPoll(int _port, int _slot);
|
||||
u8 PADpoll(u8 value);
|
||||
bool PADcomplete();
|
||||
|
||||
namespace PAD
|
||||
{
|
||||
|
|
|
@ -62,7 +62,7 @@ void QueryInfo::reset()
|
|||
memset(response, 0xF3, sizeof(response));
|
||||
}
|
||||
|
||||
u8 QueryInfo::start_poll(int _port)
|
||||
u8 QueryInfo::start_poll(int _port, int _slot)
|
||||
{
|
||||
if (_port >= 2)
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ u8 QueryInfo::start_poll(int _port)
|
|||
}
|
||||
|
||||
port = _port;
|
||||
slot = slots[port];
|
||||
slot = _slot;
|
||||
|
||||
const u32 ext_port = sioConvertPortAndSlotToPad(port, slot);
|
||||
|
||||
|
@ -184,9 +184,9 @@ inline bool IsDualshock2()
|
|||
#endif
|
||||
}
|
||||
|
||||
u8 pad_start_poll(u8 pad)
|
||||
u8 pad_start_poll(u8 _port, u8 _slot)
|
||||
{
|
||||
return query.start_poll(pad - 1);
|
||||
return query.start_poll(_port, _slot);
|
||||
}
|
||||
|
||||
u8 pad_poll(u8 value)
|
||||
|
@ -516,3 +516,8 @@ u8 pad_poll(u8 value)
|
|||
return query.response[query.lastByte];
|
||||
}
|
||||
}
|
||||
|
||||
bool pad_complete()
|
||||
{
|
||||
return query.queryDone;
|
||||
}
|
|
@ -49,7 +49,7 @@ struct QueryInfo
|
|||
u8 response[42];
|
||||
|
||||
void reset();
|
||||
u8 start_poll(int port);
|
||||
u8 start_poll(int _port, int _slot);
|
||||
|
||||
template <size_t S>
|
||||
void set_result(const u8 (&rsp)[S])
|
||||
|
@ -127,5 +127,6 @@ extern QueryInfo query;
|
|||
extern Pad pads[2][4];
|
||||
extern int slots[2];
|
||||
|
||||
extern u8 pad_start_poll(u8 pad);
|
||||
extern u8 pad_start_poll(u8 _port, u8 _slot);
|
||||
extern u8 pad_poll(u8 value);
|
||||
extern bool pad_complete();
|
|
@ -199,9 +199,9 @@ s32 PADfreeze(FreezeAction mode, freezeData* data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
u8 PADstartPoll(int pad)
|
||||
u8 PADstartPoll(int port, int slot)
|
||||
{
|
||||
return pad_start_poll(pad);
|
||||
return pad_start_poll(port, slot);
|
||||
}
|
||||
|
||||
u8 PADpoll(u8 value)
|
||||
|
@ -209,6 +209,11 @@ u8 PADpoll(u8 value)
|
|||
return pad_poll(value);
|
||||
}
|
||||
|
||||
bool PADcomplete()
|
||||
{
|
||||
return pad_complete();
|
||||
}
|
||||
|
||||
// PADkeyEvent is called every vsync (return NULL if no event)
|
||||
HostKeyEvent* PADkeyEvent()
|
||||
{
|
||||
|
|
|
@ -51,7 +51,7 @@ void QueryInfo::reset()
|
|||
memset(response, 0xF3, sizeof(response));
|
||||
}
|
||||
|
||||
u8 QueryInfo::start_poll(int _port)
|
||||
u8 QueryInfo::start_poll(int _port, int _slot)
|
||||
{
|
||||
if (port > 1)
|
||||
{
|
||||
|
@ -61,7 +61,7 @@ u8 QueryInfo::start_poll(int _port)
|
|||
|
||||
queryDone = 0;
|
||||
port = _port;
|
||||
slot = slots[port];
|
||||
slot = _slot;
|
||||
numBytes = 2;
|
||||
lastByte = 0;
|
||||
|
||||
|
@ -160,9 +160,14 @@ inline bool IsDualshock2()
|
|||
#endif
|
||||
}
|
||||
|
||||
u8 pad_start_poll(u8 pad)
|
||||
u8 pad_start_poll(u8 port, u8 slot)
|
||||
{
|
||||
return query.start_poll(pad - 1);
|
||||
return query.start_poll(port, slot);
|
||||
}
|
||||
|
||||
bool pad_complete()
|
||||
{
|
||||
return query.queryDone;
|
||||
}
|
||||
|
||||
u8 pad_poll(u8 value)
|
||||
|
|
|
@ -48,7 +48,7 @@ struct QueryInfo
|
|||
u8 response[42];
|
||||
|
||||
void reset();
|
||||
u8 start_poll(int port);
|
||||
u8 start_poll(int port, int slot);
|
||||
|
||||
template <size_t S>
|
||||
void set_result(const u8 (&rsp)[S])
|
||||
|
@ -129,5 +129,6 @@ extern QueryInfo query;
|
|||
extern Pad pads[2][4];
|
||||
extern int slots[2];
|
||||
|
||||
extern u8 pad_start_poll(u8 pad);
|
||||
extern u8 pad_start_poll(u8 port, u8 slot);
|
||||
extern u8 pad_poll(u8 value);
|
||||
extern bool pad_complete();
|
||||
|
|
|
@ -1057,21 +1057,26 @@ void PADclose()
|
|||
}
|
||||
}
|
||||
|
||||
u8 PADstartPoll(int port)
|
||||
bool PADcomplete()
|
||||
{
|
||||
return query.queryDone;
|
||||
}
|
||||
|
||||
u8 PADstartPoll(int port, int slot)
|
||||
{
|
||||
DEBUG_NEW_SET();
|
||||
port--;
|
||||
if ((unsigned int)port <= 1 && pads[port][slots[port]].enabled)
|
||||
|
||||
if ((unsigned int)port <= 1 && pads[port][slot].enabled)
|
||||
{
|
||||
query.queryDone = 0;
|
||||
query.port = port;
|
||||
query.slot = slots[port];
|
||||
query.slot = slot;
|
||||
query.numBytes = 2;
|
||||
query.lastByte = 0;
|
||||
DEBUG_IN(port);
|
||||
DEBUG_OUT(0xFF);
|
||||
DEBUG_IN(slots[port]);
|
||||
DEBUG_OUT(pads[port][slots[port]].enabled);
|
||||
DEBUG_IN(slot);
|
||||
DEBUG_OUT(pads[port][slot].enabled);
|
||||
return 0xFF;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "Sif.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
#include "R5900OpcodeTables.h"
|
||||
#include "IopSio2.h"
|
||||
#include "IopCounters.h"
|
||||
#include "IopBios.h"
|
||||
#include "IopHw.h"
|
||||
|
@ -177,13 +176,30 @@ static __fi void IopTestEvent( IopEventId n, void (*callback)() )
|
|||
psxSetNextBranch( psxRegs.sCycle[n], psxRegs.eCycle[n] );
|
||||
}
|
||||
|
||||
static __fi void Sio0TestEvent(IopEventId n)
|
||||
{
|
||||
if (!(psxRegs.interrupt & (1 << n)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (psxTestCycle(psxRegs.sCycle[n], psxRegs.eCycle[n]))
|
||||
{
|
||||
psxRegs.interrupt &= ~(1 << n);
|
||||
sio0.Interrupt(Sio0Interrupt::TEST_EVENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
psxSetNextBranch(psxRegs.sCycle[n], psxRegs.eCycle[n]);
|
||||
}
|
||||
}
|
||||
|
||||
static __fi void _psxTestInterrupts()
|
||||
{
|
||||
IopTestEvent(IopEvt_SIF0, sif0Interrupt); // SIF0
|
||||
IopTestEvent(IopEvt_SIF1, sif1Interrupt); // SIF1
|
||||
IopTestEvent(IopEvt_SIF2, sif2Interrupt); // SIF2
|
||||
// Originally controlled by a preprocessor define, now PSX dependent.
|
||||
if (psxHu32(HW_ICFG) & (1 << 3)) IopTestEvent(IopEvt_SIO, sioInterruptR);
|
||||
Sio0TestEvent(IopEvt_SIO);
|
||||
IopTestEvent(IopEvt_CdvdRead, cdvdReadInterrupt);
|
||||
IopTestEvent(IopEvt_CdvdSectorReady, cdvdSectorReady);
|
||||
|
||||
|
|
|
@ -93,21 +93,21 @@ void InputRecording::RecordingReset()
|
|||
g_InputRecordingControls.Resume();
|
||||
}
|
||||
|
||||
void InputRecording::ControllerInterrupt(u8& data, u8& port, u16& bufCount, u8 buf[])
|
||||
void InputRecording::ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8 dataOut)
|
||||
{
|
||||
// TODO - Multi-Tap Support
|
||||
|
||||
if (bufCount == 1)
|
||||
fInterruptFrame = data == READ_DATA_AND_VIBRATE_FIRST_BYTE;
|
||||
else if (bufCount == 2)
|
||||
if (fifoSize == 1)
|
||||
fInterruptFrame = dataIn == READ_DATA_AND_VIBRATE_FIRST_BYTE;
|
||||
else if (fifoSize == 2)
|
||||
{
|
||||
if (buf[bufCount] != READ_DATA_AND_VIBRATE_SECOND_BYTE)
|
||||
if (dataOut != READ_DATA_AND_VIBRATE_SECOND_BYTE)
|
||||
fInterruptFrame = false;
|
||||
}
|
||||
else if (fInterruptFrame)
|
||||
{
|
||||
u8& bufVal = buf[bufCount];
|
||||
const u16 bufIndex = bufCount - 3;
|
||||
u8& bufVal = dataOut;
|
||||
const u16 bufIndex = fifoSize - 3;
|
||||
if (state == InputRecordingMode::Replaying)
|
||||
{
|
||||
if (frameCounter >= 0 && frameCounter < INT_MAX)
|
||||
|
@ -480,6 +480,7 @@ wxString InputRecording::resolveGameName()
|
|||
#include "InputRecordingControls.h"
|
||||
#include "Utilities/InputRecordingLogger.h"
|
||||
|
||||
#include <queue>
|
||||
#include <fmt/format.h>
|
||||
|
||||
void SaveStateBase::InputRecordingFreeze()
|
||||
|
@ -526,21 +527,21 @@ void InputRecording::RecordingReset()
|
|||
g_InputRecordingControls.Resume();
|
||||
}
|
||||
|
||||
void InputRecording::ControllerInterrupt(u8& data, u8& port, u16& bufCount, u8 buf[])
|
||||
// TODO: Refactor this
|
||||
void InputRecording::ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8 dataOut)
|
||||
{
|
||||
// TODO - Multi-Tap Support
|
||||
|
||||
if (bufCount == 1)
|
||||
fInterruptFrame = data == READ_DATA_AND_VIBRATE_FIRST_BYTE;
|
||||
else if (bufCount == 2)
|
||||
if (fifoSize == 1)
|
||||
fInterruptFrame = dataIn == READ_DATA_AND_VIBRATE_FIRST_BYTE;
|
||||
else if (fifoSize == 2)
|
||||
{
|
||||
if (buf[bufCount] != READ_DATA_AND_VIBRATE_SECOND_BYTE)
|
||||
if (dataOut != READ_DATA_AND_VIBRATE_SECOND_BYTE)
|
||||
fInterruptFrame = false;
|
||||
}
|
||||
else if (fInterruptFrame)
|
||||
{
|
||||
u8& bufVal = buf[bufCount];
|
||||
const u16 bufIndex = bufCount - 3;
|
||||
u8& bufVal = dataOut;
|
||||
const u16 bufIndex = fifoSize - 3;
|
||||
if (state == InputRecordingMode::Replaying)
|
||||
{
|
||||
if (frameCounter >= 0 && frameCounter < INT_MAX)
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
// TODO - Vaser - kill with wxWidgets
|
||||
|
||||
|
@ -36,7 +38,7 @@ public:
|
|||
|
||||
// Main handler for ingesting input data and either saving it to the recording file (recording)
|
||||
// or mutating it to the contents of the recording file (replaying)
|
||||
void ControllerInterrupt(u8& data, u8& port, u16& BufCount, u8 buf[]);
|
||||
void ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8 dataOut);
|
||||
|
||||
// The running frame counter for the input recording
|
||||
s32 GetFrameCounter();
|
||||
|
@ -168,7 +170,7 @@ public:
|
|||
|
||||
// Main handler for ingesting input data and either saving it to the recording file (recording)
|
||||
// or mutating it to the contents of the recording file (replaying)
|
||||
void ControllerInterrupt(u8& data, u8& port, u16& BufCount, u8 buf[]);
|
||||
void ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8 dataOut);
|
||||
|
||||
// The running frame counter for the input recording
|
||||
s32 GetFrameCounter();
|
||||
|
|
|
@ -33,7 +33,7 @@ enum class FreezeAction
|
|||
// [SAVEVERSION+]
|
||||
// This informs the auto updater that the users savestates will be invalidated.
|
||||
|
||||
static const u32 g_SaveVersion = (0x9A2F << 16) | 0x0000;
|
||||
static const u32 g_SaveVersion = (0x9A30 << 16) | 0x0000;
|
||||
|
||||
|
||||
// the freezing data between submodules and core
|
||||
|
|
1846
pcsx2/Sio.cpp
1846
pcsx2/Sio.cpp
File diff suppressed because it is too large
Load Diff
188
pcsx2/Sio.h
188
pcsx2/Sio.h
|
@ -1,5 +1,5 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
|
@ -13,26 +13,35 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Huge thanks to PSI for his work reversing the PS2, his documentation on SIO2 pretty much saved
|
||||
// this entire implementation. https://psi-rockin.github.io/ps2tek/#sio2registers
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SioTypes.h"
|
||||
#include "MemoryCardFile.h"
|
||||
#include <array>
|
||||
#include <deque>
|
||||
|
||||
struct _mcd
|
||||
{
|
||||
u8 currentCommand;
|
||||
u8 term; // terminator value;
|
||||
|
||||
bool goodSector; // xor sector check
|
||||
u8 msb;
|
||||
u8 lsb;
|
||||
u32 sectorAddr; // read/write sector address
|
||||
u32 transferAddr; // Transfer address
|
||||
|
||||
std::vector<u8> buf; // Buffer for reading and writing
|
||||
|
||||
u8 FLAG; // for PSX;
|
||||
|
||||
u8 port; // port
|
||||
u8 slot; // and slot for this memcard
|
||||
|
||||
// Auto Eject
|
||||
u32 ForceEjection_Timeout; // in SIO checks
|
||||
u64 ForceEjection_Timestamp;
|
||||
size_t autoEjectTicks;
|
||||
|
||||
void GetSizeInfo(McdSizeInfo &info)
|
||||
{
|
||||
|
@ -46,18 +55,21 @@ struct _mcd
|
|||
|
||||
void EraseBlock()
|
||||
{
|
||||
//DevCon.WriteLn("Memcard Erase (sectorAddr = %08X)", sectorAddr);
|
||||
FileMcd_EraseBlock(port, slot, transferAddr);
|
||||
}
|
||||
|
||||
// Read from memorycard to dest
|
||||
void Read(u8 *dest, int size)
|
||||
{
|
||||
//DevCon.WriteLn("Memcard Read (sectorAddr = %08X)", sectorAddr);
|
||||
FileMcd_Read(port, slot, dest, transferAddr, size);
|
||||
}
|
||||
|
||||
// Write to memorycard from src
|
||||
void Write(u8 *src, int size)
|
||||
{
|
||||
//DevCon.WriteLn("Memcard Write (sectorAddr = %08X)", sectorAddr);
|
||||
FileMcd_Save(port, slot, src,transferAddr, size);
|
||||
}
|
||||
|
||||
|
@ -66,11 +78,16 @@ struct _mcd
|
|||
return FileMcd_IsPresent(port, slot);
|
||||
}
|
||||
|
||||
u8 DoXor(const u8 *buf, uint length)
|
||||
u8 DoXor()
|
||||
{
|
||||
u8 i, x;
|
||||
for (x=0, i=0; i<length; i++) x ^= buf[i];
|
||||
return x;
|
||||
u8 ret = msb ^ lsb;
|
||||
|
||||
for (const u8 byte : buf)
|
||||
{
|
||||
ret ^= byte;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u64 GetChecksum()
|
||||
|
@ -87,45 +104,135 @@ struct _mcd
|
|||
}
|
||||
};
|
||||
|
||||
struct _sio
|
||||
class Sio0
|
||||
{
|
||||
u16 StatReg;
|
||||
u16 ModeReg;
|
||||
u16 CtrlReg;
|
||||
u16 BaudReg;
|
||||
private:
|
||||
u32 txData; // 0x1f801040
|
||||
u32 rxData; // 0x1f801040
|
||||
u32 stat; // 0x1f801044
|
||||
u16 mode; // 0x1f801048
|
||||
u16 ctrl; // 0x1f80104a
|
||||
u16 baud; // 0x1f80104e
|
||||
|
||||
u32 count; // old_sio remnant
|
||||
u32 packetsize;// old_sio remnant
|
||||
void ClearStatAcknowledge();
|
||||
|
||||
u8 buf[512];
|
||||
u8 ret; // default return value;
|
||||
u8 cmd; // command backup
|
||||
public:
|
||||
u8 flag = 0;
|
||||
|
||||
u16 bufCount; // current buffer counter
|
||||
u16 bufSize; // supposed buffer size
|
||||
SioStage sioStage = SioStage::IDLE;
|
||||
u8 sioMode = SioMode::NOT_SET;
|
||||
u8 sioCommand = 0;
|
||||
bool padStarted = false;
|
||||
bool rxDataSet = false;
|
||||
|
||||
u8 port; // current port
|
||||
u8 slot[2]; // current slot
|
||||
u8 port = 0;
|
||||
u8 slot = 0;
|
||||
|
||||
u8 GetPort() { return port; }
|
||||
u8 GetSlot() { return slot[port]; }
|
||||
Sio0();
|
||||
~Sio0();
|
||||
|
||||
void SoftReset();
|
||||
void FullReset();
|
||||
|
||||
void Acknowledge();
|
||||
void Interrupt(Sio0Interrupt sio0Interrupt);
|
||||
|
||||
u8 GetTxData();
|
||||
u8 GetRxData();
|
||||
u32 GetStat();
|
||||
u16 GetMode();
|
||||
u16 GetCtrl();
|
||||
u16 GetBaud();
|
||||
|
||||
void SetTxData(u8 value);
|
||||
void SetRxData(u8 value);
|
||||
void SetStat(u32 value);
|
||||
void SetMode(u16 value);
|
||||
void SetCtrl(u16 value);
|
||||
void SetBaud(u16 value);
|
||||
|
||||
bool IsPadCommand(u8 command);
|
||||
bool IsMemcardCommand(u8 command);
|
||||
bool IsPocketstationCommand(u8 command);
|
||||
|
||||
u8 Pad(u8 value);
|
||||
u8 Memcard(u8 value);
|
||||
};
|
||||
|
||||
extern _sio sio;
|
||||
class Sio2
|
||||
{
|
||||
private:
|
||||
void UpdateInputRecording(u8 dataIn, u8 dataOut);
|
||||
|
||||
public:
|
||||
std::array<u32, 16> send3; // 0x1f808200 - 0x1f80823f
|
||||
// SEND1 and SEND2 are an unusual bunch. It's not entirely clear just from
|
||||
// documentation but these registers almost seem like they are the same thing;
|
||||
// when bit 2 is set, SEND2 is being read/written. When bit 2 isn't set, it is
|
||||
// SEND1. Their use is not really known, either.
|
||||
std::array<u32, 4> send1; // 0x1f808240 - 0x1f80825f
|
||||
std::array<u32, 4> send2; // 0x1f808240 - 0x1f80825f
|
||||
u32 dataIn; // 0x1f808260
|
||||
u32 dataOut; // 0x1f808264
|
||||
u32 ctrl; // 0x1f808268
|
||||
u32 recv1; // 0x1f80826c
|
||||
u32 recv2; // 0x1f808270
|
||||
u32 recv3; // 0x1f808274
|
||||
u32 unknown1; // 0x1f808278
|
||||
u32 unknown2; // 0x1f80827c
|
||||
u32 iStat; // 0x1f808280
|
||||
|
||||
u8 port = 0;
|
||||
u8 slot = 0;
|
||||
|
||||
// The current working index of SEND3. The SEND3 register is a 16 position
|
||||
// array of command descriptors. Each descriptor describes the port the command
|
||||
// is targeting, as well as the length of the command in bytes.
|
||||
bool send3Read = false;
|
||||
size_t send3Position = 0;
|
||||
size_t commandLength = 0;
|
||||
size_t processedLength = 0;
|
||||
// Tracks the size of a single block of DMA11/DMA12 data. psxDma11 will set this prior
|
||||
// to doing writes, and Sio2::SetSend3 will clear this to ensure a non-DMA write into SIO2
|
||||
// does not accidentally use dmaBlockSize.
|
||||
size_t dmaBlockSize = 0;
|
||||
bool send3Complete = false;
|
||||
|
||||
std::unique_ptr<u8[]> fifoInBackup;
|
||||
size_t fifoInBackupSize;
|
||||
std::unique_ptr<u8[]> fifoOutBackup;
|
||||
size_t fifoOutBackupSize;
|
||||
|
||||
Sio2();
|
||||
~Sio2();
|
||||
|
||||
void SoftReset();
|
||||
void FullReset();
|
||||
|
||||
void Interrupt();
|
||||
|
||||
void SetCtrl(u32 value);
|
||||
void SetSend3(size_t position, u32 value);
|
||||
void SetRecv1(u32 value);
|
||||
|
||||
void Pad();
|
||||
void Multitap();
|
||||
void Infrared();
|
||||
void Memcard();
|
||||
|
||||
void Write(u8 data);
|
||||
u8 Read();
|
||||
};
|
||||
|
||||
extern std::deque<u8> fifoIn;
|
||||
extern std::deque<u8> fifoOut;
|
||||
|
||||
extern Sio0 sio0;
|
||||
extern Sio2 sio2;
|
||||
|
||||
extern _mcd mcds[2][4];
|
||||
extern _mcd *mcd;
|
||||
|
||||
extern void sioInit();
|
||||
extern u8 sioRead8();
|
||||
extern void sioWrite8(u8 value);
|
||||
extern void sioWriteCtrl16(u16 value);
|
||||
extern void sioInterrupt();
|
||||
extern void sioInterruptR();
|
||||
extern void SetForceMcdEjectTimeoutNow(uint port, uint slot);
|
||||
extern void SetForceMcdEjectTimeoutNow();
|
||||
extern void ClearMcdEjectTimeoutNow();
|
||||
extern void sioStatRead();
|
||||
extern void sioSetGameSerial(const std::string& serial);
|
||||
extern void sioNextFrame();
|
||||
|
||||
/// Converts a global pad index to a multitap port and slot.
|
||||
|
@ -137,3 +244,12 @@ extern u32 sioConvertPortAndSlotToPad(u32 port, u32 slot);
|
|||
/// Returns true if the given pad index is a multitap slot.
|
||||
extern bool sioPadIsMultitapSlot(u32 index);
|
||||
extern bool sioPortAndSlotIsMultitap(u32 port, u32 slot);
|
||||
extern void sioSetGameSerial(const std::string& serial);
|
||||
|
||||
namespace AutoEject
|
||||
{
|
||||
extern void Set(size_t port, size_t slot);
|
||||
extern void Clear(size_t port, size_t slot);
|
||||
extern void SetAll();
|
||||
extern void ClearAll();
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
enum class SioStage
|
||||
{
|
||||
IDLE,
|
||||
WAITING_COMMAND,
|
||||
WORKING
|
||||
};
|
||||
|
||||
namespace SioMode
|
||||
{
|
||||
static constexpr u8 NOT_SET = 0x00;
|
||||
static constexpr u8 PAD = 0x01;
|
||||
static constexpr u8 MULTITAP = 0x21;
|
||||
static constexpr u8 INFRARED = 0x61;
|
||||
static constexpr u8 MEMCARD = 0x81;
|
||||
} // namespace SioMode
|
||||
|
||||
namespace PadCommand
|
||||
{
|
||||
static constexpr u8 UNK_0 = 0x40;
|
||||
static constexpr u8 QUERY_BUTTONS = 0x41;
|
||||
static constexpr u8 POLL = 0x42;
|
||||
static constexpr u8 CONFIG = 0x43;
|
||||
static constexpr u8 MODE_SWITCH = 0x44;
|
||||
static constexpr u8 STATUS = 0x45;
|
||||
static constexpr u8 CONST_1 = 0x46;
|
||||
static constexpr u8 CONST_2 = 0x47;
|
||||
static constexpr u8 UNK_8 = 0x48;
|
||||
static constexpr u8 UNK_9 = 0x49;
|
||||
static constexpr u8 UNK_A = 0x4a;
|
||||
static constexpr u8 UNK_B = 0x4b;
|
||||
static constexpr u8 CONST_3 = 0x4c;
|
||||
static constexpr u8 VIBRATION = 0x4d;
|
||||
static constexpr u8 UNK_E = 0x4e;
|
||||
static constexpr u8 ANALOG = 0x4f;
|
||||
} // namespace PadCommand
|
||||
|
||||
namespace MemcardCommand
|
||||
{
|
||||
static constexpr u8 NOT_SET = 0x00;
|
||||
static constexpr u8 PROBE = 0x11;
|
||||
static constexpr u8 UNKNOWN_WRITE_DELETE_END = 0x12;
|
||||
static constexpr u8 SET_ERASE_SECTOR = 0x21;
|
||||
static constexpr u8 SET_WRITE_SECTOR = 0x22;
|
||||
static constexpr u8 SET_READ_SECTOR = 0x23;
|
||||
static constexpr u8 GET_SPECS = 0x26;
|
||||
static constexpr u8 SET_TERMINATOR = 0x27;
|
||||
static constexpr u8 GET_TERMINATOR = 0x28;
|
||||
static constexpr u8 WRITE_DATA = 0x42;
|
||||
static constexpr u8 READ_DATA = 0x43;
|
||||
static constexpr u8 PS1_READ = 0x52;
|
||||
static constexpr u8 PS1_STATE = 0x53;
|
||||
static constexpr u8 PS1_WRITE = 0x57;
|
||||
static constexpr u8 PS1_POCKETSTATION = 0x58;
|
||||
static constexpr u8 READ_WRITE_END = 0x81;
|
||||
static constexpr u8 ERASE_BLOCK = 0x82;
|
||||
static constexpr u8 UNKNOWN_BOOT = 0xbf;
|
||||
static constexpr u8 AUTH_XOR = 0xf0;
|
||||
static constexpr u8 AUTH_F3 = 0xf3;
|
||||
static constexpr u8 AUTH_F7 = 0xf7;
|
||||
} // namespace MemcardCommand
|
||||
|
||||
enum class Sio0Interrupt
|
||||
{
|
||||
TEST_EVENT,
|
||||
STAT_READ,
|
||||
TX_DATA_WRITE
|
||||
}; // namespace Sio0Interrupt
|
||||
|
||||
namespace SIO
|
||||
{
|
||||
static constexpr u8 PORTS = 2;
|
||||
static constexpr u8 SLOTS = 4;
|
||||
} // namespace SIO
|
||||
|
||||
namespace SIO0_STAT
|
||||
{
|
||||
static constexpr u32 TX_READY = 0x01;
|
||||
static constexpr u32 RX_FIFO_NOT_EMPTY = 0x02;
|
||||
static constexpr u32 TX_EMPTY = 0x04;
|
||||
static constexpr u32 RX_PARITY_ERROR = 0x08;
|
||||
static constexpr u32 ACK = 0x80;
|
||||
static constexpr u32 IRQ = 0x0200;
|
||||
} // namespace SIO0_STAT
|
||||
|
||||
namespace SIO0_CTRL
|
||||
{
|
||||
static constexpr u16 TX_ENABLE = 0x01;
|
||||
static constexpr u16 RX_ENABLE = 0x04;
|
||||
static constexpr u16 ACK = 0x10;
|
||||
static constexpr u16 RESET = 0x40;
|
||||
static constexpr u16 RX_INT_MODE_LSB = 0x0100;
|
||||
static constexpr u16 RX_INT_MODE_MSB = 0x0200;
|
||||
static constexpr u16 TX_INT_ENABLE = 0x0400;
|
||||
static constexpr u16 RX_INT_ENABLE = 0x0800;
|
||||
static constexpr u16 ACK_INT_ENABLE = 0x1000;
|
||||
static constexpr u16 PORT = 0x2000;
|
||||
} // namespace SIO0_CTRL
|
||||
|
||||
namespace Send3
|
||||
{
|
||||
static constexpr u32 PORT = 0x01;
|
||||
static constexpr u16 COMMAND_LENGTH_MASK = 0x3ff;
|
||||
} // namespace Send3
|
||||
|
||||
namespace Sio2Ctrl
|
||||
{
|
||||
static constexpr u32 START_TRANSFER = 0x1;
|
||||
static constexpr u32 RESET = 0xc;
|
||||
static constexpr u32 PORT = 0x2000;
|
||||
// The value which SIO2MAN resets SIO2_CTRL to after a system reset.
|
||||
static constexpr u32 SIO2MAN_RESET = 0x000003bc;
|
||||
} // namespace Sio2Ctrl
|
||||
|
||||
namespace Recv1
|
||||
{
|
||||
static constexpr u32 DISCONNECTED = 0x1d100;
|
||||
static constexpr u32 CONNECTED = 0x1100;
|
||||
} // namespace Recv1
|
||||
|
||||
namespace Recv2
|
||||
{
|
||||
static constexpr u32 DEFAULT = 0xf;
|
||||
} // namespace Recv2
|
||||
|
||||
// Most RECV3 values are mysterious, undocumented, and their purpose
|
||||
// can only be inferred from how old, mostly incorrect PCSX2 code tried
|
||||
// to use them. We're going to try and respect these where it seems like
|
||||
// it may make sense to do so, but these are still largely unknown and
|
||||
// tests suggest they are not even used at all.
|
||||
namespace Recv3
|
||||
{
|
||||
static constexpr u32 DEFAULT = 0x0;
|
||||
// Set when getting memcard specs
|
||||
static constexpr u32 SPECS = 0x83;
|
||||
// Set when getting or setting the terminator byte
|
||||
static constexpr u32 TERMINATOR = 0x8b;
|
||||
// Set when setting the read/write sector
|
||||
static constexpr u32 READ_WRITE_END = 0x8c;
|
||||
} // namespace Recv3
|
||||
|
||||
namespace Terminator
|
||||
{
|
||||
static constexpr u32 DEFAULT = 0x55;
|
||||
} // namespace Terminator
|
|
@ -678,7 +678,7 @@ void VMManager::UpdateRunningGame(bool resetting, bool game_starting)
|
|||
// If we don't reset the timer here, when using folder memcards the reindex will cause an eject,
|
||||
// which a bunch of games don't like since they access the memory card on boot.
|
||||
if (game_starting || resetting)
|
||||
ClearMcdEjectTimeoutNow();
|
||||
AutoEject::ClearAll();
|
||||
}
|
||||
|
||||
UpdateGameSettingsLayer();
|
||||
|
@ -687,7 +687,7 @@ void VMManager::UpdateRunningGame(bool resetting, bool game_starting)
|
|||
// Clear the memory card eject notification again when booting for the first time, or starting.
|
||||
// Otherwise, games think the card was removed on boot.
|
||||
if (game_starting || resetting)
|
||||
ClearMcdEjectTimeoutNow();
|
||||
AutoEject::ClearAll();
|
||||
|
||||
// Check this here, for two cases: dynarec on, and when enable cheats is set per-game.
|
||||
if (s_patches_crc != s_game_crc)
|
||||
|
@ -1691,8 +1691,8 @@ void VMManager::CheckForMemoryCardConfigChanges(const Pcsx2Config& old_config)
|
|||
if (EmuConfig.Mcd[index].Enabled != old_config.Mcd[index].Enabled ||
|
||||
EmuConfig.Mcd[index].Filename != old_config.Mcd[index].Filename)
|
||||
{
|
||||
Console.WriteLn("Replugging memory card %u (port %u slot %u) due to source change", index, port, slot);
|
||||
SetForceMcdEjectTimeoutNow(port, slot);
|
||||
Console.WriteLn("Ejecting memory card %u (port %u slot %u) due to source change", index, port, slot);
|
||||
AutoEject::Set(port, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -568,7 +568,7 @@ void AppCoreThread::GameStartingInThread()
|
|||
m_ExecMode = ExecMode_Paused;
|
||||
OnResumeReady();
|
||||
_reset_stuff_as_needed();
|
||||
ClearMcdEjectTimeoutNow(); // probably safe to do this when a game boots, eliminates annoying prompts
|
||||
AutoEject::ClearAll(); // probably safe to do this when a game boots, eliminates annoying prompts
|
||||
m_ExecMode = ExecMode_Opened;
|
||||
|
||||
_parent::GameStartingInThread();
|
||||
|
|
|
@ -563,7 +563,7 @@ void Panels::MemoryCardListPanel_Simple::Apply()
|
|||
if (!used)
|
||||
Console.WriteLn("No active slots.");
|
||||
|
||||
SetForceMcdEjectTimeoutNow();
|
||||
AutoEject::SetAll();
|
||||
}
|
||||
|
||||
void Panels::MemoryCardListPanel_Simple::AppStatusEvent_OnSettingsApplied()
|
||||
|
|
|
@ -378,6 +378,8 @@
|
|||
<ClCompile Include="Host.cpp" />
|
||||
<ClCompile Include="HostDisplay.cpp" />
|
||||
<ClCompile Include="IopGte.cpp" />
|
||||
<ClCompile Include="MemoryCardProtocol.cpp" />
|
||||
<ClCompile Include="MultitapProtocol.cpp" />
|
||||
<ClCompile Include="PINE.cpp" />
|
||||
<ClCompile Include="FW.cpp" />
|
||||
<ClCompile Include="MemoryCardFile.cpp" />
|
||||
|
@ -634,7 +636,6 @@
|
|||
<ClCompile Include="IopIrq.cpp" />
|
||||
<ClCompile Include="IopMem.cpp" />
|
||||
<ClCompile Include="windows\WinKeyCodes.cpp" />
|
||||
<ClCompile Include="IopSio2.cpp" />
|
||||
<ClCompile Include="R3000A.cpp" />
|
||||
<ClCompile Include="R3000AInterpreter.cpp" />
|
||||
<ClCompile Include="R3000AOpcodeTables.cpp" />
|
||||
|
@ -842,6 +843,8 @@
|
|||
<ClInclude Include="Host.h" />
|
||||
<ClInclude Include="HostDisplay.h" />
|
||||
<ClInclude Include="IopGte.h" />
|
||||
<ClInclude Include="MemoryCardProtocol.h" />
|
||||
<ClInclude Include="MultitapProtocol.h" />
|
||||
<ClInclude Include="PINE.h" />
|
||||
<ClInclude Include="FW.h" />
|
||||
<ClInclude Include="MemoryCardFile.h" />
|
||||
|
@ -957,7 +960,6 @@
|
|||
<ClInclude Include="Patch.h" />
|
||||
<ClInclude Include="PCSX2Base.h" />
|
||||
<ClInclude Include="PrecompiledHeader.h" />
|
||||
<ClInclude Include="sio_internal.h" />
|
||||
<ClInclude Include="ps2\pgif.h" />
|
||||
<ClInclude Include="Recording\InputRecording.h" />
|
||||
<ClInclude Include="Recording\InputRecordingControls.h" />
|
||||
|
@ -1080,7 +1082,6 @@
|
|||
<ClInclude Include="IopCounters.h" />
|
||||
<ClInclude Include="IopDma.h" />
|
||||
<ClInclude Include="IopMem.h" />
|
||||
<ClInclude Include="IopSio2.h" />
|
||||
<ClInclude Include="R3000A.h" />
|
||||
<ClInclude Include="Sio.h" />
|
||||
<ClInclude Include="x86\iR3000A.h" />
|
||||
|
|
|
@ -656,9 +656,6 @@
|
|||
<ClCompile Include="IopMem.cpp">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IopSio2.cpp">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="R3000A.cpp">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1799,6 +1796,12 @@
|
|||
<ClCompile Include="Frontend\ImGuiOverlays.cpp">
|
||||
<Filter>Host</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MemoryCardProtocol.cpp">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MultitapProtocol.cpp">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Patch.h">
|
||||
|
@ -1978,9 +1981,6 @@
|
|||
<ClInclude Include="IopMem.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IopSio2.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="R3000A.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
|
@ -2248,9 +2248,6 @@
|
|||
<ClInclude Include="IopGte.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sio_internal.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ps2\pgif.h">
|
||||
<Filter>System\Ps2</Filter>
|
||||
</ClInclude>
|
||||
|
@ -2999,6 +2996,12 @@
|
|||
<ClInclude Include="ShaderCacheVersion.h">
|
||||
<Filter>System\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MemoryCardProtocol.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MultitapProtocol.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="windows\wxResources.rc">
|
||||
|
|
|
@ -226,6 +226,8 @@
|
|||
<ClCompile Include="HostDisplay.cpp" />
|
||||
<ClCompile Include="Frontend\HostSettings.cpp" />
|
||||
<ClCompile Include="IopGte.cpp" />
|
||||
<ClCompile Include="MemoryCardProtocol.cpp" />
|
||||
<ClCompile Include="MultitapProtocol.cpp" />
|
||||
<ClCompile Include="PAD\Host\KeyStatus.cpp" />
|
||||
<ClCompile Include="PAD\Host\PAD.cpp" />
|
||||
<ClCompile Include="PAD\Host\StateManagement.cpp" />
|
||||
|
@ -406,7 +408,6 @@
|
|||
<ClCompile Include="IopDma.cpp" />
|
||||
<ClCompile Include="IopIrq.cpp" />
|
||||
<ClCompile Include="IopMem.cpp" />
|
||||
<ClCompile Include="IopSio2.cpp" />
|
||||
<ClCompile Include="R3000A.cpp" />
|
||||
<ClCompile Include="R3000AInterpreter.cpp" />
|
||||
<ClCompile Include="R3000AOpcodeTables.cpp" />
|
||||
|
@ -551,6 +552,8 @@
|
|||
<ClInclude Include="HostDisplay.h" />
|
||||
<ClInclude Include="HostSettings.h" />
|
||||
<ClInclude Include="IopGte.h" />
|
||||
<ClInclude Include="MemoryCardProtocol.h" />
|
||||
<ClInclude Include="MultitapProtocol.h" />
|
||||
<ClInclude Include="PAD\Gamepad.h" />
|
||||
<ClInclude Include="PAD\Host\Global.h" />
|
||||
<ClInclude Include="PAD\Host\KeyStatus.h" />
|
||||
|
@ -567,6 +570,7 @@
|
|||
<ClInclude Include="Recording\PadData.h" />
|
||||
<ClInclude Include="Recording\Utilities\InputRecordingLogger.h" />
|
||||
<ClInclude Include="ShaderCacheVersion.h" />
|
||||
<ClInclude Include="SioTypes.h" />
|
||||
<ClInclude Include="SPU2\Config.h" />
|
||||
<ClInclude Include="SPU2\Global.h" />
|
||||
<ClInclude Include="SPU2\Host\Config.h" />
|
||||
|
@ -651,7 +655,6 @@
|
|||
<ClInclude Include="Patch.h" />
|
||||
<ClInclude Include="PCSX2Base.h" />
|
||||
<ClInclude Include="PrecompiledHeader.h" />
|
||||
<ClInclude Include="sio_internal.h" />
|
||||
<ClInclude Include="ps2\pgif.h" />
|
||||
<ClInclude Include="USB\USB.h" />
|
||||
<ClInclude Include="Utilities\AsciiFile.h" />
|
||||
|
@ -716,7 +719,6 @@
|
|||
<ClInclude Include="IopCounters.h" />
|
||||
<ClInclude Include="IopDma.h" />
|
||||
<ClInclude Include="IopMem.h" />
|
||||
<ClInclude Include="IopSio2.h" />
|
||||
<ClInclude Include="R3000A.h" />
|
||||
<ClInclude Include="Sio.h" />
|
||||
<ClInclude Include="x86\iR3000A.h" />
|
||||
|
|
|
@ -569,9 +569,6 @@
|
|||
<ClCompile Include="IopMem.cpp">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IopSio2.cpp">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="R3000A.cpp">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1296,6 +1293,12 @@
|
|||
<ClCompile Include="Frontend\DInputSource.cpp">
|
||||
<Filter>Host</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MemoryCardProtocol.cpp">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MultitapProtocol.cpp">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Patch.h">
|
||||
|
@ -1478,9 +1481,6 @@
|
|||
<ClInclude Include="IopMem.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IopSio2.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="R3000A.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
|
@ -1640,9 +1640,6 @@
|
|||
<ClInclude Include="IopGte.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sio_internal.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ps2\pgif.h">
|
||||
<Filter>System\Ps2</Filter>
|
||||
</ClInclude>
|
||||
|
@ -2162,6 +2159,15 @@
|
|||
<ClInclude Include="Frontend\DInputSource.h">
|
||||
<Filter>Host</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SioTypes.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MemoryCardProtocol.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MultitapProtocol.h">
|
||||
<Filter>System\Ps2\Iop</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuildStep Include="rdebug\deci2.h">
|
||||
|
|
|
@ -24,12 +24,17 @@
|
|||
#include "DEV9/DEV9.h"
|
||||
#include "USB/USB.h"
|
||||
#include "IopCounters.h"
|
||||
#include "IopSio2.h"
|
||||
#include "IopDma.h"
|
||||
|
||||
#include "ps2/pgif.h"
|
||||
#include "Mdec.h"
|
||||
|
||||
#define SIO0LOG_ENABLE 0
|
||||
#define SIO2LOG_ENABLE 0
|
||||
|
||||
#define Sio0Log if (SIO0LOG_ENABLE) DevCon
|
||||
#define Sio2Log if (SIO2LOG_ENABLE) DevCon
|
||||
|
||||
namespace IopMemory
|
||||
{
|
||||
using namespace Internal;
|
||||
|
@ -46,12 +51,21 @@ mem8_t iopHwRead8_Page1( u32 addr )
|
|||
mem8_t ret; // using a return var can be helpful in debugging.
|
||||
switch( masked_addr )
|
||||
{
|
||||
mcase(HW_SIO_DATA) :
|
||||
// 1F801040h 1/4 JOY_DATA Joypad/Memory Card Data (R/W)
|
||||
// psxmode: documentation suggests a valid 8 bit read and the rest of the 32 bit register is unclear.
|
||||
// todo: check this and compare with the HW_SIO_DATA read around line 245 as well.
|
||||
ret = sioRead8();
|
||||
break;
|
||||
case (HW_SIO_DATA & 0x0fff):
|
||||
ret = sio0.GetRxData();
|
||||
break;
|
||||
case (HW_SIO_STAT & 0x0fff):
|
||||
Sio0Log.Error("%s(%08X) Unexpected SIO0 STAT 8 bit read", __FUNCTION__, addr);
|
||||
break;
|
||||
case (HW_SIO_MODE & 0x0fff):
|
||||
Sio0Log.Error("%s(%08X) Unexpected SIO0 MODE 8 bit read", __FUNCTION__, addr);
|
||||
break;
|
||||
case (HW_SIO_CTRL & 0x0fff):
|
||||
Sio0Log.Error("%s(%08X) Unexpected SIO0 CTRL 8 bit read", __FUNCTION__, addr);
|
||||
break;
|
||||
case (HW_SIO_BAUD & 0x0fff):
|
||||
Sio0Log.Error("%s(%08X) Unexpected SIO0 BAUD 8 bit read", __FUNCTION__, addr);
|
||||
break;
|
||||
|
||||
// for use of serial port ignore for now
|
||||
//case 0x50: ret = serial_read8(); break;
|
||||
|
@ -118,10 +132,14 @@ mem8_t iopHwRead8_Page8( u32 addr )
|
|||
|
||||
mem8_t ret;
|
||||
|
||||
if( addr == HW_SIO2_FIFO )
|
||||
ret = sio2_fifoOut();//sio2 serial data feed/fifo_out
|
||||
if (addr == HW_SIO2_FIFO)
|
||||
{
|
||||
ret = sio2.Read();
|
||||
}
|
||||
else
|
||||
ret = psxHu8( addr );
|
||||
{
|
||||
ret = psxHu8(addr);
|
||||
}
|
||||
|
||||
IopHwTraceLog<mem8_t>( addr, ret, true );
|
||||
return ret;
|
||||
|
@ -255,38 +273,34 @@ static __fi T _HwRead_16or32_Page1( u32 addr )
|
|||
switch( masked_addr )
|
||||
{
|
||||
// ------------------------------------------------------------------------
|
||||
mcase(HW_SIO_DATA):
|
||||
ret = sioRead8();
|
||||
ret |= sioRead8() << 8;
|
||||
if( sizeof(T) == 4 )
|
||||
case (HW_SIO_DATA & 0x0fff):
|
||||
Console.Warning("%s(%08X) Unexpected 16 or 32 bit access to SIO0 data register!", __FUNCTION__, addr);
|
||||
ret = sio0.GetRxData();
|
||||
ret |= sio0.GetRxData() << 8;
|
||||
if (sizeof(T) == 4)
|
||||
{
|
||||
ret |= sioRead8() << 16;
|
||||
ret |= sioRead8() << 24;
|
||||
ret |= sio0.GetRxData() << 16;
|
||||
ret |= sio0.GetRxData() << 24;
|
||||
}
|
||||
break;
|
||||
|
||||
mcase(HW_SIO_STAT):
|
||||
ret = sio.StatReg;
|
||||
sioStatRead();
|
||||
// Console.WriteLn( "SIO0 Read STAT %02X INT_STAT= %08X IOPpc= %08X " , ret, psxHu32(0x1070), psxRegs.pc);
|
||||
break;
|
||||
|
||||
mcase(HW_SIO_MODE):
|
||||
ret = sio.ModeReg;
|
||||
if( sizeof(T) == 4 )
|
||||
break;
|
||||
case (HW_SIO_STAT & 0x0fff):
|
||||
ret = sio0.GetStat();
|
||||
break;
|
||||
case (HW_SIO_MODE & 0x0fff):
|
||||
ret = sio0.GetMode();
|
||||
|
||||
if (sizeof(T) == 4)
|
||||
{
|
||||
// My guess on 32-bit accesses. Dunno yet what the real hardware does. --air
|
||||
ret |= sio.CtrlReg << 16;
|
||||
Console.Warning("%s(%08X) Unexpected 32 bit access to SIO0 MODE register!", __FUNCTION__, addr);
|
||||
}
|
||||
break;
|
||||
|
||||
mcase(HW_SIO_CTRL):
|
||||
ret = sio.CtrlReg;
|
||||
break;
|
||||
|
||||
mcase(HW_SIO_BAUD):
|
||||
ret = sio.BaudReg;
|
||||
break;
|
||||
|
||||
break;
|
||||
case (HW_SIO_CTRL & 0x0fff):
|
||||
ret = sio0.GetCtrl();
|
||||
break;
|
||||
case (HW_SIO_BAUD & 0x0fff):
|
||||
ret = sio0.GetBaud();
|
||||
break;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
//Serial port stuff not support now ;P
|
||||
|
@ -421,45 +435,60 @@ mem32_t iopHwRead32_Page8( u32 addr )
|
|||
if( masked_addr < 0x240 )
|
||||
{
|
||||
const int parm = (masked_addr-0x200) / 4;
|
||||
ret = sio2_getSend3( parm );
|
||||
ret = sio2.send3.at(parm);
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 SEND3 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
}
|
||||
else if( masked_addr < 0x260 )
|
||||
{
|
||||
// SIO2 Send commands alternate registers. First reg maps to Send1, second
|
||||
// to Send2, third to Send1, etc. And the following clever code does this:
|
||||
|
||||
const int parm = (masked_addr-0x240) / 8;
|
||||
ret = (masked_addr & 4) ? sio2_getSend2( parm ) : sio2_getSend1( parm );
|
||||
ret = (masked_addr & 4) ? sio2.send2.at(parm) : sio2.send1.at(parm);
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 SEND1/2 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
}
|
||||
else if( masked_addr <= 0x280 )
|
||||
{
|
||||
switch( masked_addr )
|
||||
{
|
||||
mcase(HW_SIO2_CTRL): ret = sio2_getCtrl(); break;
|
||||
mcase(HW_SIO2_RECV1): ret = sio2_getRecv1(); break;
|
||||
mcase(HW_SIO2_RECV2): ret = sio2_getRecv2(); break;
|
||||
mcase(HW_SIO2_RECV3): ret = sio2_getRecv3(); break;
|
||||
mcase(0x1f808278): ret = sio2_get8278(); break;
|
||||
mcase(0x1f80827C): ret = sio2_get827C(); break;
|
||||
mcase(HW_SIO2_INTR): ret = sio2_getIntr(); break;
|
||||
|
||||
// HW_SIO2_FIFO -- A yet unknown: Should this be ignored on 32 bit writes, or handled as a
|
||||
// 4-byte FIFO input?
|
||||
// The old IOP system just ignored it, so that's what we do here. I've included commented code
|
||||
// for treating it as a 16/32 bit write though [which is what the SIO does, for example).
|
||||
mcase(HW_SIO2_FIFO) :
|
||||
//ret = sio2_fifoOut();
|
||||
//ret |= sio2_fifoOut() << 8;
|
||||
//ret |= sio2_fifoOut() << 16;
|
||||
//ret |= sio2_fifoOut() << 24;
|
||||
//break;
|
||||
DevCon.Warning("HW_SIO2_FIFO read");
|
||||
case (HW_SIO2_DATAIN & 0x0fff):
|
||||
ret = psxHu32(addr);
|
||||
break;
|
||||
|
||||
Sio2Log.Warning("%s(%08X) Unexpected 32 bit read of HW_SIO2_DATAIN (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_FIFO & 0x0fff):
|
||||
ret = psxHu32(addr);
|
||||
Sio2Log.Warning("%s(%08X) Unexpected 32 bit read of HW_SIO2_FIFO (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_CTRL & 0x0fff):
|
||||
ret = sio2.ctrl;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 CTRL Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_RECV1 & 0xfff):
|
||||
ret = sio2.recv1;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 RECV1 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_RECV2 & 0x0fff):
|
||||
ret = sio2.recv2;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 RECV2 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_RECV3 & 0x0fff):
|
||||
ret = sio2.recv3;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 RECV3 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (0x1f808278 & 0x0fff):
|
||||
ret = sio2.unknown1;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 UNK1 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (0x1f80827C & 0x0fff):
|
||||
ret = sio2.unknown2;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 UNK2 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_INTR & 0x0fff):
|
||||
ret = sio2.iStat;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 ISTAT Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
default:
|
||||
ret = psxHu32(addr);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( masked_addr >= pgmsk(HW_FW_START) && masked_addr <= pgmsk(HW_FW_END) )
|
||||
|
|
|
@ -23,13 +23,18 @@
|
|||
#include "DEV9/DEV9.h"
|
||||
#include "USB/USB.h"
|
||||
#include "IopCounters.h"
|
||||
#include "IopSio2.h"
|
||||
#include "IopDma.h"
|
||||
#include "R3000A.h"
|
||||
|
||||
#include "ps2/pgif.h"
|
||||
#include "Mdec.h"
|
||||
|
||||
#define SIO0LOG_ENABLE 0
|
||||
#define SIO2LOG_ENABLE 0
|
||||
|
||||
#define Sio0Log if (SIO0LOG_ENABLE) DevCon
|
||||
#define Sio2Log if (SIO2LOG_ENABLE) DevCon
|
||||
|
||||
namespace IopMemory {
|
||||
|
||||
using namespace Internal;
|
||||
|
@ -80,8 +85,21 @@ void iopHwWrite8_Page1( u32 addr, mem8_t val )
|
|||
|
||||
switch( masked_addr )
|
||||
{
|
||||
mcase(HW_SIO_DATA): sioWrite8( val ); break;
|
||||
|
||||
case (HW_SIO_DATA & 0x0fff):
|
||||
sio0.SetTxData(val);
|
||||
break;
|
||||
case (HW_SIO_STAT & 0x0fff):
|
||||
Sio0Log.Error("%s(%08X, %08X) Unexpected SIO0 STAT 8 bit write", __FUNCTION__, addr, val);
|
||||
break;
|
||||
case (HW_SIO_MODE & 0x0fff):
|
||||
Sio0Log.Error("%s(%08X, %08X) Unexpected SIO0 MODE 8 bit write", __FUNCTION__, addr, val);
|
||||
break;
|
||||
case (HW_SIO_CTRL & 0x0fff):
|
||||
Sio0Log.Error("%s(%08X, %08X) Unexpected SIO0 CTRL 8 bit write", __FUNCTION__, addr, val);
|
||||
break;
|
||||
case (HW_SIO_BAUD & 0x0fff):
|
||||
Sio0Log.Error("%s(%08X, %08X) Unexpected SIO0 BAUD 8 bit write", __FUNCTION__, addr, val);
|
||||
break;
|
||||
// for use of serial port ignore for now
|
||||
//case 0x50: serial_write8( val ); break;
|
||||
|
||||
|
@ -156,10 +174,14 @@ void iopHwWrite8_Page8( u32 addr, mem8_t val )
|
|||
// all addresses are assumed to be prefixed with 0x1f808xxx:
|
||||
pxAssert( (addr >> 12) == 0x1f808 );
|
||||
|
||||
if( addr == HW_SIO2_DATAIN ) // sio2 serial data feed input
|
||||
sio2_serialIn( val );
|
||||
if (addr == HW_SIO2_DATAIN)
|
||||
{
|
||||
sio2.Write(val);
|
||||
}
|
||||
else
|
||||
psxHu8( addr ) = val;
|
||||
{
|
||||
psxHu8(addr) = val;
|
||||
}
|
||||
|
||||
IopHwTraceLog<mem8_t>( addr, val, false );
|
||||
}
|
||||
|
@ -277,39 +299,39 @@ static __fi void _HwWrite_16or32_Page1( u32 addr, T val )
|
|||
switch( masked_addr )
|
||||
{
|
||||
// ------------------------------------------------------------------------
|
||||
mcase(HW_SIO_DATA):
|
||||
sioWrite8( val & 0xFF );
|
||||
sioWrite8( (val >> 8) & 0xFF );
|
||||
if( sizeof(T) == 4 )
|
||||
case (HW_SIO_DATA & 0x0fff):
|
||||
Console.Error("%s(%08X, %08X) Unexpected 16 or 32 bit write to SIO0 DATA!", __FUNCTION__, addr, val);
|
||||
/*
|
||||
sio0.SetTxData(val & 0xFF);
|
||||
sio0.SetTxData((val >> 8) & 0xFF);
|
||||
|
||||
if (sizeof(T) == 4)
|
||||
{
|
||||
// u32 gets rid of compiler warnings when using the u16 version of this template
|
||||
sioWrite8( ((u32)val >> 16) & 0xFF );
|
||||
sioWrite8( ((u32)val >> 24) & 0xFF );
|
||||
sio0.SetTxData((static_cast<u32>(val) >> 16) & 0xFF);
|
||||
sio0.SetTxData((static_cast<u32>(val) >> 24) & 0xFF);
|
||||
}
|
||||
break;
|
||||
*/
|
||||
break;
|
||||
case (HW_SIO_STAT & 0x0fff):
|
||||
Console.Error("%s(%08X, %08X) Write issued to read-only SIO0 STAT!", __FUNCTION__, addr, val);
|
||||
break;
|
||||
case (HW_SIO_MODE & 0x0fff):
|
||||
sio0.SetMode(static_cast<u16>(val));
|
||||
|
||||
mcase(HW_SIO_STAT): // read-only?
|
||||
//regname = "SIO_STAT (read-only?)";
|
||||
//sio.StatReg;
|
||||
break;
|
||||
|
||||
mcase(HW_SIO_MODE):
|
||||
sio.ModeReg = (u16)val;
|
||||
if( sizeof(T) == 4 )
|
||||
if (sizeof(T) == 4)
|
||||
{
|
||||
// My guess on 32-bit accesses. Dunno yet what the real hardware does. --air
|
||||
sio.CtrlReg = (u16)((u32)val >> 16);
|
||||
Console.Error("%s(%08X, %08X) 32 bit write to 16 bit SIO0 MODE register!", __FUNCTION__, addr, val);
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
mcase(HW_SIO_CTRL):
|
||||
//sio.CtrlReg = (u16)val;
|
||||
sioWriteCtrl16((u16)val);
|
||||
break;
|
||||
|
||||
mcase(HW_SIO_BAUD):
|
||||
sio.BaudReg = (u16)val;
|
||||
break;
|
||||
case (HW_SIO_CTRL & 0x0fff):
|
||||
sio0.SetCtrl(static_cast<u16>(val));
|
||||
break;
|
||||
|
||||
case (HW_SIO_BAUD & 0x0fff):
|
||||
sio0.SetBaud(static_cast<u16>(val));
|
||||
break;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
//Serial port stuff not support now ;P
|
||||
|
@ -588,26 +610,66 @@ void iopHwWrite32_Page8( u32 addr, mem32_t val )
|
|||
{
|
||||
if( masked_addr < 0x240 )
|
||||
{
|
||||
const int parm = (masked_addr-0x200) / 4;
|
||||
sio2_setSend3( parm, val );
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 SEND3 Write (len = %d / %d) (port = %d)", __FUNCTION__, addr, val, (val >> 8) & Send3::COMMAND_LENGTH_MASK, (val >> 18) & Send3::COMMAND_LENGTH_MASK, val & 0x01);
|
||||
const int parm = (masked_addr - 0x200) / 4;
|
||||
sio2.SetSend3(parm, val);
|
||||
}
|
||||
else if( masked_addr < 0x260 )
|
||||
{
|
||||
// SIO2 Send commands alternate registers. First reg maps to Send1, second
|
||||
// to Send2, third to Send1, etc. And the following clever code does this:
|
||||
|
||||
const int parm = (masked_addr-0x240) / 8;
|
||||
if(masked_addr & 4) sio2_setSend2( parm, val ); else sio2_setSend1( parm, val );
|
||||
const int parm = (masked_addr - 0x240) / 8;
|
||||
|
||||
if (masked_addr & 4)
|
||||
{
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 SEND2 Write", __FUNCTION__, addr, val);
|
||||
sio2.send2.at(parm) = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 SEND1 Write", __FUNCTION__, addr, val);
|
||||
sio2.send1.at(parm) = val;
|
||||
}
|
||||
}
|
||||
else if( masked_addr <= 0x280 )
|
||||
{
|
||||
switch( masked_addr )
|
||||
{
|
||||
mcase(HW_SIO2_CTRL): sio2_setCtrl( val ); break;
|
||||
mcase(0x1f808278): sio2_set8278( val ); break;
|
||||
mcase(0x1f80827C): sio2_set827C( val ); break;
|
||||
mcase(HW_SIO2_INTR): sio2_setIntr( val ); break;
|
||||
|
||||
case (HW_SIO2_DATAIN & 0x0fff):
|
||||
Sio2Log.Warning("%s(%08X, %08X) Unexpected 32 bit write to HW_SIO2_DATAIN", __FUNCTION__, addr, val);
|
||||
break;
|
||||
case (HW_SIO2_FIFO & 0x0fff):
|
||||
Sio2Log.Warning("%s(%08X, %08X) Unexpected 32 bit write to HW_SIO2_FIFO", __FUNCTION__, addr, val);
|
||||
break;
|
||||
case (HW_SIO2_CTRL & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 CTRL Write", __FUNCTION__, addr, val);
|
||||
sio2.SetCtrl(val);
|
||||
break;
|
||||
case (HW_SIO2_RECV1 & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 RECV1 Write", __FUNCTION__, addr, val);
|
||||
sio2.recv1 = val;
|
||||
break;
|
||||
case (HW_SIO2_RECV2 & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 RECV2 Write", __FUNCTION__, addr, val);
|
||||
sio2.recv2 = val;
|
||||
break;
|
||||
case (HW_SIO2_RECV3 & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 RECV3 Write", __FUNCTION__, addr, val);
|
||||
sio2.recv3 = val;
|
||||
break;
|
||||
case (HW_SIO2_8278 & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 UNK1 Write", __FUNCTION__, addr, val);
|
||||
sio2.unknown1 = val;
|
||||
break;
|
||||
case (HW_SIO2_827C & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 UNK2 Write", __FUNCTION__, addr, val);
|
||||
sio2.unknown2 = val;
|
||||
break;
|
||||
case (HW_SIO2_INTR & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 ISTAT Write", __FUNCTION__, addr, val);
|
||||
sio2.iStat = val;
|
||||
break;
|
||||
// Other SIO2 registers are read-only, no-ops on write.
|
||||
default:
|
||||
psxHu32(addr) = val;
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "IopSio2.h"
|
||||
|
||||
// sio_internal.h -- contains defines and structs used by sio and sio2, which
|
||||
// are of little or no use to the rest of the world.
|
||||
|
||||
// Status Flags
|
||||
static const int
|
||||
TX_RDY = 0x0001,
|
||||
RX_RDY = 0x0002,
|
||||
TX_EMPTY = 0x0004,
|
||||
PARITY_ERR = 0x0008,
|
||||
RX_OVERRUN = 0x0010,
|
||||
FRAMING_ERR = 0x0020,
|
||||
SYNC_DETECT = 0x0040,
|
||||
DSR = 0x0080,
|
||||
CTS = 0x0100,
|
||||
IRQ = 0x0200;
|
||||
|
||||
// Control Flags
|
||||
static const int
|
||||
TX_PERM = 0x0001,
|
||||
DTR = 0x0002,
|
||||
RX_PERM = 0x0004,
|
||||
BREAK = 0x0008,
|
||||
RESET_ERR = 0x0010,
|
||||
RTS = 0x0020,
|
||||
SIO_RESET = 0x0040;
|
||||
|
||||
void inline SIO_STAT_READY()
|
||||
{
|
||||
sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
|
||||
sio.StatReg |= RX_RDY; // Transfer is Ready
|
||||
}
|
||||
|
||||
void inline SIO_STAT_EMPTY()
|
||||
{
|
||||
sio.StatReg &= ~RX_RDY; // Receive is not Ready now?
|
||||
sio.StatReg |= TX_EMPTY; // Buffer is Empty
|
||||
}
|
||||
|
||||
void inline DEVICE_PLUGGED()
|
||||
{
|
||||
sio.ret = 0xFF;
|
||||
sio2.packet.recvVal1 = 0x01100;
|
||||
memset8<0xFF>(sio.buf);
|
||||
}
|
||||
|
||||
void inline DEVICE_UNPLUGGED()
|
||||
{
|
||||
sio.ret = 0x00;
|
||||
sio2.packet.recvVal1 = 0x1D100;
|
||||
memset8<0x00>(sio.buf);
|
||||
}
|
||||
|
||||
enum SIO_MODE
|
||||
{
|
||||
SIO_START = 0,
|
||||
SIO_CONTROLLER,
|
||||
SIO_MULTITAP,
|
||||
SIO_INFRARED,
|
||||
SIO_MEMCARD,
|
||||
SIO_MEMCARD_AUTH,
|
||||
SIO_MEMCARD_ERASE,
|
||||
SIO_MEMCARD_WRITE,
|
||||
SIO_MEMCARD_READ,
|
||||
SIO_MEMCARD_SECTOR,
|
||||
SIO_MEMCARD_PSX,
|
||||
SIO_DUMMY
|
||||
};
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
struct mc_command_0x26_tag{
|
||||
u8 field_151; //+02 flags
|
||||
u16 sectorSize; //+03 Size of each sector(page), in bytes.
|
||||
u16 eraseBlocks; //+05 Number of sectors in the erase block
|
||||
u32 mcdSizeInSectors; //+07 card size in sectors (pages).
|
||||
u8 mc_xor; //+0b XOR Checksum of the superblock? (minus format ident and version?)
|
||||
u8 Z; //+0c terminator? Appears to be overwritten/unused.
|
||||
#ifdef _MSC_VER
|
||||
};
|
||||
#pragma pack()
|
||||
#else
|
||||
} __attribute__((packed));
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue