mirror of https://github.com/PCSX2/pcsx2.git
250 lines
5.8 KiB
C++
250 lines
5.8 KiB
C++
/* 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/>.
|
|
*/
|
|
|
|
// 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
|
|
|
|
size_t autoEjectTicks;
|
|
|
|
void GetSizeInfo(McdSizeInfo &info)
|
|
{
|
|
FileMcd_GetSizeInfo(port, slot, &info);
|
|
}
|
|
|
|
bool IsPSX()
|
|
{
|
|
return FileMcd_IsPSX(port, slot);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
bool IsPresent()
|
|
{
|
|
return FileMcd_IsPresent(port, slot);
|
|
}
|
|
|
|
u8 DoXor()
|
|
{
|
|
u8 ret = msb ^ lsb;
|
|
|
|
for (const u8 byte : buf)
|
|
{
|
|
ret ^= byte;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
u64 GetChecksum()
|
|
{
|
|
return FileMcd_GetCRC(port, slot);
|
|
}
|
|
|
|
void NextFrame() {
|
|
FileMcd_NextFrame( port, slot );
|
|
}
|
|
|
|
bool ReIndex(const std::string& filter) {
|
|
return FileMcd_ReIndex(port, slot, filter);
|
|
}
|
|
};
|
|
|
|
class Sio0
|
|
{
|
|
private:
|
|
u32 txData; // 0x1f801040
|
|
u32 rxData; // 0x1f801040
|
|
u32 stat; // 0x1f801044
|
|
u16 mode; // 0x1f801048
|
|
u16 ctrl; // 0x1f80104a
|
|
u16 baud; // 0x1f80104e
|
|
|
|
void ClearStatAcknowledge();
|
|
|
|
public:
|
|
u8 flag = 0;
|
|
|
|
SioStage sioStage = SioStage::IDLE;
|
|
u8 sioMode = SioMode::NOT_SET;
|
|
u8 sioCommand = 0;
|
|
bool padStarted = false;
|
|
bool rxDataSet = false;
|
|
|
|
u8 port = 0;
|
|
u8 slot = 0;
|
|
|
|
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);
|
|
};
|
|
|
|
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;
|
|
|
|
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 sioNextFrame();
|
|
|
|
/// Converts a global pad index to a multitap port and slot.
|
|
extern std::tuple<u32, u32> sioConvertPadToPortAndSlot(u32 index);
|
|
|
|
/// Converts a multitap port and slot to a global pad index.
|
|
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();
|
|
} |