Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIO1 Synchronization Fixes #1124

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 31 additions & 31 deletions src/core/psxhw.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,23 +79,23 @@ uint8_t PCSX::HW::read8(uint32_t add) {
hard = PCSX::g_emulator->m_sio1->readData8();
SIO1_LOG("SIO1.DATA read8 %x; ret = %x\n", add & 0xf, hard);
break;
case 0x1f801054: // stat register
hard = PCSX::g_emulator->m_sio1->readStat8();
// case 0x1f801054: // stat register
// hard = PCSX::g_emulator->m_sio1->readStat8();
// Log command below is overly spammy
// SIO1_LOG("SIO1.STAT read8 %x; ret = %x\n", add & 0xf, hard);
break;
case 0x1f801058: // mode register
hard = PCSX::g_emulator->m_sio1->readMode8();
SIO1_LOG("SIO1.MODE read8 %x; ret = %x\n", add & 0xf, hard);
break;
case 0x1f80105a: // control register
hard = PCSX::g_emulator->m_sio1->readCtrl8();
SIO1_LOG("SIO1.CTRL read8 %x; ret = %x\n", add & 0xf, hard);
break;
case 0x1f80105e: // baudrate register
hard = PCSX::g_emulator->m_sio1->readBaud8();
SIO1_LOG("SIO1.BAUD read8 %x; ret = %x\n", add & 0xf, hard);
break;
// break;
// case 0x1f801058: // mode register
// hard = PCSX::g_emulator->m_sio1->readMode8();
// SIO1_LOG("SIO1.MODE read8 %x; ret = %x\n", add & 0xf, hard);
// break;
// case 0x1f80105a: // control register
// hard = PCSX::g_emulator->m_sio1->readCtrl8();
// SIO1_LOG("SIO1.CTRL read8 %x; ret = %x\n", add & 0xf, hard);
// break;
// case 0x1f80105e: // baudrate register
// hard = PCSX::g_emulator->m_sio1->readBaud8();
// SIO1_LOG("SIO1.BAUD read8 %x; ret = %x\n", add & 0xf, hard);
// break;
case 0x1f801800:
hard = PCSX::g_emulator->m_cdrom->read0();
break;
Expand Down Expand Up @@ -391,22 +391,22 @@ void PCSX::HW::write8(uint32_t add, uint32_t rawvalue) {
PCSX::g_emulator->m_sio1->writeData8(value);
SIO1_LOG("SIO1.DATA write8 %x; ret = %x\n", add & 0xf, value);
break;
case 0x1f801054: // stat register
PCSX::g_emulator->m_sio1->writeStat8(value);
SIO1_LOG("SIO1.STAT write8 %x; ret = %x\n", add & 0xf, value);
break;
case 0x1f801058: // mode register
PCSX::g_emulator->m_sio1->writeMode8(value);
SIO1_LOG("SIO1.MODE write8 %x; ret = %x\n", add & 0xf, value);
break;
case 0x1f80105a: // control register
PCSX::g_emulator->m_sio1->writeCtrl8(value);
SIO1_LOG("SIO1.CTRL write8 %x; ret = %x\n", add & 0xf, value);
break;
case 0x1f80105e: // baudrate register
PCSX::g_emulator->m_sio1->writeBaud8(value);
SIO1_LOG("SIO1.Baud write8 %x; ret = %x\n", add & 0xf, value);
break;
// case 0x1f801054: // stat register
// PCSX::g_emulator->m_sio1->writeStat8(value);
// SIO1_LOG("SIO1.STAT write8 %x; ret = %x\n", add & 0xf, value);
// break;
// case 0x1f801058: // mode register
// PCSX::g_emulator->m_sio1->writeMode8(value);
// SIO1_LOG("SIO1.MODE write8 %x; ret = %x\n", add & 0xf, value);
// break;
// case 0x1f80105a: // control register
// PCSX::g_emulator->m_sio1->writeCtrl8(value);
// SIO1_LOG("SIO1.CTRL write8 %x; ret = %x\n", add & 0xf, value);
// break;
// case 0x1f80105e: // baudrate register
// PCSX::g_emulator->m_sio1->writeBaud8(value);
// SIO1_LOG("SIO1.Baud write8 %x; ret = %x\n", add & 0xf, value);
// break;
case 0x1f801800:
PCSX::g_emulator->m_cdrom->write0(value);
break;
Expand Down
151 changes: 74 additions & 77 deletions src/core/sio1.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
PCSX::SIOPayload PCSX::SIO1::makeFlowControlMessage() {
return SIOPayload{
DataTransfer{},
FlowControl{m_flowControl.dxr, m_flowControl.xts},
FlowControl{m_regs.control},
};
}

Expand All @@ -31,7 +31,7 @@ PCSX::SIOPayload PCSX::SIO1::makeDataMessage(std::string &&data) {
DataTransfer{
DataTransferData{std::move(data)},
},
FlowControl{},
FlowControl{m_regs.control},
};
}

Expand Down Expand Up @@ -60,20 +60,9 @@ void PCSX::SIO1::sendDataMessage() {
void PCSX::SIO1::sendFlowControlMessage() {
if (fifoError()) return;

pollFlowControl();
if (!initialMessage) {
if (m_flowControl == m_prevFlowControl) return;
}
m_prevFlowControl = m_flowControl;

SIOPayload payload = makeFlowControlMessage();
std::string message = encodeMessage(payload);
transmitMessage(std::move(message));

if (initialMessage) {
if (!connecting() && !fifoError()) g_system->printf("%s", _("SIO1 client connected\n"));
initialMessage = false;
}
}

void PCSX::SIO1::decodeMessage() {
Expand All @@ -96,34 +85,66 @@ void PCSX::SIO1::decodeMessage() {
}

void PCSX::SIO1::processMessage(SIOPayload payload) {
if (!payload.get<DataTransferField>().get<DataTransferData>().hasData()) {
setDsr(payload.get<FlowControlField>().get<FlowControlDXR>().value);
setCts(payload.get<FlowControlField>().get<FlowControlXTS>().value);
} else {
// Flow control is always sent/received to ensure synchronization
setDsr(payload.get<FlowControlField>().get<FlowControlReg>().value & CR_DTR);
setCts(payload.get<FlowControlField>().get<FlowControlReg>().value & CR_RTS);
if (payload.get<DataTransferField>().get<DataTransferData>().hasData()) {
std::string &byte = payload.get<DataTransferField>().get<DataTransferData>().value;
PCSX::Slice pushByte;
pushByte.acquire(std::move(byte));
if (m_regs.control & CR_RTS) {
m_sio1fifo.asA<Fifo>()->pushSlice(std::move(pushByte));
receiveCallback();
m_sio1fifo.asA<Fifo>()->pushSlice(std::move(pushByte));
receiveCallback();
}

if (m_sio1fifo->size() > 8) {
m_regs.status |= SR_RXOVERRUN;
}

updateStat();

// DSR Interrupt
if (m_regs.control & CR_DSRIRQEN) {
if (m_regs.status & SR_DSR) {
if (!(m_regs.status & SR_IRQ)) {
scheduleInterrupt(m_cycleCount);
m_regs.status |= SR_IRQ;
}
}
}
}

void PCSX::SIO1::sio1StateMachine() {
void PCSX::SIO1::sio1StateMachine(bool data) {
if (fifoError()) return;

switch (m_decodeState) {
case READ_SIZE:
while (m_fifo->size() >= 1) {
messageSize = m_fifo->byte();
m_decodeState = READ_MESSAGE;
case READ_MESSAGE:
if (m_fifo->size() < messageSize) return;
decodeMessage();
m_decodeState = READ_SIZE;
}
// Server is master - send first, receive after
if (g_emulator->m_sio1Server->getServerStatus() == SIO1Server::SIO1ServerStatus::SERVER_STARTED) {
if (data) {
sendDataMessage();
} else {
sendFlowControlMessage();
}

waitOnMessage(); // Wait for the next message to be fully received
}

// Client is slave - receive first, send after
if (g_emulator->m_sio1Client->getClientStatus() == SIO1Client::SIO1ClientStatus::CLIENT_STARTED) {
// If connection is new, run slave delay
if (m_slaveDelay) {
slaveDelay();
return;
}

waitOnMessage(); // Wait for the next message to be fully received

if (data) {
sendDataMessage();
} else {
sendFlowControlMessage();
}
}

decodeMessage();
}

void PCSX::SIO1::interrupt() {
Expand All @@ -143,59 +164,39 @@ void PCSX::SIO1::interrupt() {
}

uint8_t PCSX::SIO1::readData8() {
updateStat();
if (m_sio1fifo || !m_sio1fifo->eof()) {
if (m_regs.status & SR_RXRDY) {
m_regs.data = m_sio1fifo->byte();
psxHu8(0x1050) = m_regs.data;
}
m_regs.data = m_sio1fifo->byte();
}
updateStat();
if (m_sio1Mode == SIO1Mode::Protobuf) sio1StateMachine();
return m_regs.data;
}

uint16_t PCSX::SIO1::readData16() {
updateStat();
if (m_sio1fifo || !m_sio1fifo->eof()) {
if (m_regs.status & SR_RXRDY) {
m_sio1fifo->read(&m_regs.data, 2);
psxHu16(0x1050) = m_regs.data;
}
m_sio1fifo->read(&m_regs.data, 2);
}
updateStat();
if (m_sio1Mode == SIO1Mode::Protobuf) sio1StateMachine();
return m_regs.data;
}

uint32_t PCSX::SIO1::readData32() {
updateStat();
if (m_sio1fifo || !m_sio1fifo->eof()) {
if (m_regs.status & SR_RXRDY) {
m_sio1fifo->read(&m_regs.data, 4);
psxHu32(0x1050) = m_regs.data;
}
m_sio1fifo->read(&m_regs.data, 4);
}
updateStat();
if (m_sio1Mode == SIO1Mode::Protobuf) sio1StateMachine();
return m_regs.data;
}

uint8_t PCSX::SIO1::readStat8() {
updateStat();
return m_regs.status;
}

uint16_t PCSX::SIO1::readStat16() {
updateStat();
if (m_sio1Mode == SIO1Mode::Protobuf) sio1StateMachine();
return m_regs.status;
}

uint32_t PCSX::SIO1::readStat32() {
updateStat();
return m_regs.status;
}
uint32_t PCSX::SIO1::readStat32() { return m_regs.status; }

void PCSX::SIO1::receiveCallback() {
updateStat();
if (!m_sio1fifo || m_sio1fifo->eof()) return;
// RX Interrupt
if (m_regs.control & CR_RXIRQEN) {
if (!(m_regs.status & SR_IRQ)) {
switch ((m_regs.control & 0x300) >> 8) {
Expand Down Expand Up @@ -224,14 +225,14 @@ void PCSX::SIO1::transmitData() {
switch (m_sio1Mode) {
case SIO1Mode::Protobuf:
if (fifoError()) return;
sendDataMessage();
sio1StateMachine(true);
break;
case SIO1Mode::Raw:
if (!m_sio1fifo || m_sio1fifo->eof()) return;
m_sio1fifo->write<uint8_t>(m_regs.data);
break;
}

// TX Interrupt
if (m_regs.control & CR_TXIRQEN) {
if (m_regs.status & SR_TXRDY || m_regs.status & SR_TXRDY2) {
if (!(m_regs.status & SR_IRQ)) {
Expand All @@ -253,16 +254,15 @@ void PCSX::SIO1::updateStat() {
} else {
m_regs.status &= ~SR_RXRDY;
}
psxHu32ref(0x1054) = SWAP_LEu32(m_regs.status);
}

void PCSX::SIO1::writeBaud16(uint16_t v) {
m_regs.baud = v;
psxHu8ref(0x105E) = m_regs.baud;
calcCycleCount();
}

void PCSX::SIO1::writeCtrl16(uint16_t v) {
uint16_t control_backup = m_regs.control;
m_regs.control = v;

if (m_regs.control & CR_ACK) {
Expand All @@ -284,33 +284,30 @@ void PCSX::SIO1::writeCtrl16(uint16_t v) {
PCSX::g_emulator->m_cpu->m_regs.interrupt &= ~(1 << PCSX::PSXINT_SIO1);
}

// Behavior to clear FIFO if RXEN is disabled
if (!(m_regs.control & CR_RXEN)) {
if (m_sio1fifo.isA<Fifo>()) {
m_sio1fifo.asA<Fifo>()->reset();
}
}

if (m_sio1Mode == SIO1Mode::Protobuf) sendFlowControlMessage();
psxHu16ref(0x105A) = SWAP_LE16(m_regs.control);
if (((m_regs.control >> 8) & 0x03) != ((control_backup >> 8) & 0x03)) {
if (m_sio1fifo.isA<Fifo>()) {
m_sio1fifo.asA<Fifo>()->reset();
}
}

if (m_sio1Mode == SIO1Mode::Protobuf) sio1StateMachine();
}

void PCSX::SIO1::writeData8(uint8_t v) {
m_regs.data = v;
if (isTransmitReady()) {
transmitData();
}
psxHu8ref(0x1050) = m_regs.data;
transmitData();
}

void PCSX::SIO1::writeMode16(uint16_t v) { m_regs.mode = v; }

void PCSX::SIO1::writeStat32(uint32_t v) {
m_regs.status = v;
if (isTransmitReady()) {
transmitData();
}
psxHu32ref(0x1054) = SWAP_LE32(m_regs.status);
}
void PCSX::SIO1::writeStat16(uint16_t v) { m_regs.status = v; }

void PCSX::SIO1::calcCycleCount() {
int reload = m_reloadFactor[m_regs.mode & 0x3];
Expand Down
Loading