flycast/core/hw/naomi/systemsp.h

328 lines
6.8 KiB
C++

/*
Copyright 2023 flyinghead
This file is part of Flycast.
Flycast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Flycast 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 Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "types.h"
#include "emulator.h"
#include "hw/hwreg.h"
#include "hw/naomi/m4cartridge.h"
#include "hw/flashrom/at93cxx.h"
#include "serialize.h"
#include "network/net_platform.h"
#include <memory>
#include <libchdr/chd.h>
namespace systemsp
{
template<typename T>
T readMemArea0(u32 addr);
template<typename T>
void writeMemArea0(u32 addr, T v);
class SystemSpCart;
// rom board custom UART ports
class SerialPort : public ::SerialPort
{
public:
class Pipe : public ::SerialPort::Pipe
{
public:
virtual void serialize(Serializer& ser) const {}
virtual void deserialize(Deserializer& deser) {}
};
SerialPort(SystemSpCart *cart, int index) : cart(cart), index(index) {
}
~SerialPort() override {
if (pipe != nullptr)
delete pipe;
}
u8 readReg(u32 addr);
void writeReg(u32 addr, u8 v);
void serialize(Serializer& ser) const {
if (pipe != nullptr)
pipe->serialize(ser);
}
void deserialize(Deserializer& deser) {
if (pipe != nullptr)
pipe->deserialize(deser);
}
void setPipe(::SerialPort::Pipe *pipe) override {
this->pipe = (Pipe *)pipe;
}
void updateStatus() override;
private:
void flush()
{
if (pipe != nullptr)
while (pipe->available())
pipe->read();
}
SystemSpCart *cart;
const int index;
Pipe *pipe = nullptr;
};
//
// ATA registers for CompactFlash interface
//
union AtaStatusRegister
{
u8 full;
struct {
u8 err:1; // error
u8 idx:1; // index, always 0
u8 corr:1; // corrected data, always 0
u8 drq:1; // pio data available
u8 dsc:1; // seek complete
u8 df:1; // drive fault error
u8 rdy:1; // drive ready
u8 bsy:1; // drive busy
};
};
union AtaDriveHeadRegister
{
u8 full;
struct {
u8 head:4;
u8 drv:1;
u8 :1;
u8 lba:1;
u8 :1;
};
};
union AtaDevCtrlRegister
{
u8 full;
struct {
u8 :1;
u8 nien:1; // disable interrupts
u8 srst:1; // software reset
u8 :4;
u8 hob:1; // high-order byte
};
};
class IOPortManager
{
public:
virtual u8 getCN9_17_24() = 0;
virtual u8 getCN9_25_32() = 0;
virtual u8 getCN9_33_40() = 0;
virtual u8 getCN9_41_48() = 0;
virtual u8 getCN9_49_56() = 0;
virtual u8 getCN10_9_16() = 0;
virtual void setCN9_33_40(u8 v) {}
virtual void setCN9_49_56(u8 v) {}
virtual void setCN10_17_24(u8 v) {}
virtual ~IOPortManager() = default;
};
class SystemSpCart : public M4Cartridge
{
public:
SystemSpCart(u32 size);
~SystemSpCart() override;
void Init(LoadProgress *progress = nullptr, std::vector<u8> *digest = nullptr) override;
void setMediaName(const char *mediaName, const char *parentName) {
this->mediaName = mediaName;
this->parentName = parentName;
}
u32 ReadMem(u32 address, u32 size) override;
void WriteMem(u32 address, u32 data, u32 size) override;
bool Read(u32 offset, u32 size, void *data) override;
bool Write(u32 offset, u32 size, u32 data) override;
template<typename T>
T readMemArea0(u32 addr);
template<typename T>
void writeMemArea0(u32 addr, T v);
void Serialize(Serializer &ser) const override;
void Deserialize(Deserializer &deser) override;
bool GetBootId(RomBootID *bootId) override
{
if (mediaName == nullptr)
return M4Cartridge::GetBootId(bootId);
if (!romBootId)
return false;
memcpy(bootId, romBootId.get(), sizeof(RomBootID));
return true;
}
void updateInterrupt(u32 mask = 0);
private:
static int schedCallback(int tag, int sch_cycl, int jitter, void *arg);
int schedCallback();
chd_file *openChd(const std::string path);
void readSectors();
void saveFiles();
std::string getEepromPath() const;
static void handleEvent(Event event, void *p) {
((SystemSpCart *)p)->saveFiles();
}
void process();
template<typename T>
T readNetMem(u32 addr) {
return ReadMemArr<T>(netmem, addr & (sizeof(netmem) - sizeof(T)));
}
template<typename T>
void writeNetMem(u32 addr, T data) {
WriteMemArr(netmem, addr & (sizeof(netmem) - sizeof(T)), data);
}
int schedId;
const char *mediaName = nullptr;
const char *parentName = nullptr;
FILE *chdFile = nullptr;
chd_file *chd = nullptr;
u32 hunkbytes = 0;
std::unique_ptr<u8[]> hunkmem;
u32 hunknum = ~0;
std::unique_ptr<RomBootID> romBootId;
AT93C46SerialEeprom eeprom;
SerialPort uart1;
SerialPort uart2;
u16 bank = 0;
int region = 0;
std::unique_ptr<IOPortManager> ioPortManager;
static constexpr u32 SECTOR_SIZE = 512;
struct {
u8 features = 0;
u16 cylinder = 0;
u8 sectorCount = 0;
u8 sectorNumber = 0;
AtaStatusRegister status = { 0x50 };
u8 error = 0;
AtaDriveHeadRegister driveHead = { 0xa0 };
AtaDevCtrlRegister devCtrl = { 0 };
u8 interruptPending = 0;
u8 reg84 = 0;
u8 buffer[SECTOR_SIZE];
u32 bufferIndex = 0;
} ata;
enum class CmdState {
INIT,
AAA_AA_1,
_555_55_1,
WRITE_BUF_1,
WRITE_BUF_2,
PROGRAM,
AAA_80,
AAA_AA_2,
_555_55_2,
};
struct {
CmdState cmdState = CmdState::INIT;
u32 progAddress = ~0;
u16 wordCount = 0;
} flash;
static constexpr u16 DIMM_STATUS = 0x8102;
u8 netmem[8_MB] {};
u32 inetaddr = 0x641ea8c0; // 192.168.30.100
u32 netmask = 0x00ffffff; // 255.255.255.0
struct Socket
{
Socket() = default;
Socket(sock_t fd) : fd(fd) {}
int close()
{
int rc = 0;
if (fd != INVALID_SOCKET)
rc = ::closesocket(fd);
fd = INVALID_SOCKET;
connecting = false;
receiving = false;
sending = false;
connectTimeout = 0;
connectTime = 0;
sendTimeout = 0;
sendTime = 0;
recvTimeout = 0;
recvTime = 0;
return rc;
}
bool isClosed() const {
return fd == INVALID_SOCKET;
}
bool isBusy() const {
return connecting || receiving || sending;
}
sock_t fd = INVALID_SOCKET;
bool connecting = false;
bool receiving = false;
u8 *recvData = nullptr;
u32 recvLen = 0;
bool sending = false;
const u8 *sendData = nullptr;
u32 sendLen = 0;
u64 connectTimeout = 0;
u64 connectTime = 0;
u64 sendTimeout = 0;
u64 sendTime = 0;
u64 recvTimeout = 0;
u64 recvTime = 0;
int lastError = 0;
};
std::vector<Socket> sockets;
static constexpr u16 NET_OK = 0x8001;
static constexpr u16 NET_ERROR = 0x8000;
public:
static constexpr u32 INT_UART1 = 0x01;
static constexpr u32 INT_UART2 = 0x02;
static constexpr u32 INT_DIMM = 0x08;
static constexpr u32 INT_ATA = 0x10;
static SystemSpCart *Instance;
friend class BootIdLoader;
};
}