naomi: derbyocw card support. serial pipes refactoring. systemsp fixes
common interface for most serial pipes jvs: MIE RS422 port support card reader: allow reading/writing of individual tracks systemsp: fix interrupt handling. refactor serial ports. isshoni wanwan puppy touchscreen support
This commit is contained in:
parent
92a19e9250
commit
7061c043d9
|
@ -291,3 +291,25 @@ void WriteMemArr(u8 *array, u32 addr, T data)
|
|||
{
|
||||
*(T *)&array[addr] = data;
|
||||
}
|
||||
|
||||
class SerialPort
|
||||
{
|
||||
public:
|
||||
class Pipe
|
||||
{
|
||||
public:
|
||||
// Serial TX
|
||||
virtual void write(u8 data) { }
|
||||
// RX buffer Size
|
||||
virtual int available() { return 0; }
|
||||
// Serial RX
|
||||
virtual u8 read() { return 0; }
|
||||
|
||||
virtual ~Pipe() = default;
|
||||
};
|
||||
|
||||
virtual void setPipe(Pipe *pipe) = 0;
|
||||
virtual void updateStatus() = 0;
|
||||
|
||||
virtual ~SerialPort() = default;
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "maple_helper.h"
|
||||
#include "maple_if.h"
|
||||
#include "hw/naomi/naomi_cart.h"
|
||||
#include "hw/naomi/card_reader.h"
|
||||
#include "cfg/option.h"
|
||||
#include "stdclass.h"
|
||||
#include "serialize.h"
|
||||
|
@ -238,6 +239,10 @@ static void createNaomiDevices()
|
|||
mcfg_Create(MDT_SegaController, 2, 5);
|
||||
mcfg_Create(MDT_SegaVMU, 2, 0);
|
||||
}
|
||||
if (settings.content.gameId == " DERBY OWNERS CLUB WE ---------"
|
||||
|| settings.content.gameId == " DERBY OWNERS CLUB ------------"
|
||||
|| settings.content.gameId == " DERBY OWNERS CLUB II-----------")
|
||||
card_reader::derbyInit();
|
||||
}
|
||||
|
||||
static void createAtomiswaveDevices()
|
||||
|
@ -370,15 +375,17 @@ void mcfg_CreateDevices()
|
|||
vmuDigest();
|
||||
}
|
||||
|
||||
void mcfg_DestroyDevices()
|
||||
// Don't destroy the JVS MIE if full is false
|
||||
void mcfg_DestroyDevices(bool full)
|
||||
{
|
||||
for (int i = 0; i < MAPLE_PORTS; i++)
|
||||
for (int j=0;j<=5;j++)
|
||||
for (int j = 0; j <= 5; j++)
|
||||
{
|
||||
if (MapleDevices[i][j] != NULL)
|
||||
if (MapleDevices[i][j] != nullptr
|
||||
&& (full || MapleDevices[i][j]->get_device_type() != MDT_NaomiJamma))
|
||||
{
|
||||
delete MapleDevices[i][j];
|
||||
MapleDevices[i][j] = NULL;
|
||||
MapleDevices[i][j] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -409,7 +416,7 @@ void mcfg_SerializeDevices(Serializer& ser)
|
|||
void mcfg_DeserializeDevices(Deserializer& deser)
|
||||
{
|
||||
if (!deser.rollback())
|
||||
mcfg_DestroyDevices();
|
||||
mcfg_DestroyDevices(false);
|
||||
u8 eeprom[sizeof(maple_naomi_jamma::eeprom)];
|
||||
if (deser.version() < Deserializer::V23)
|
||||
{
|
||||
|
@ -441,7 +448,7 @@ void mcfg_DeserializeDevices(Deserializer& deser)
|
|||
deser >> deviceType;
|
||||
if (deviceType != MDT_None)
|
||||
{
|
||||
if (!deser.rollback())
|
||||
if (!deser.rollback() && deviceType != MDT_NaomiJamma)
|
||||
mcfg_Create((MapleDeviceType)deviceType, i, j);
|
||||
MapleDevices[i][j]->deserialize(deser);
|
||||
}
|
||||
|
@ -449,3 +456,10 @@ void mcfg_DeserializeDevices(Deserializer& deser)
|
|||
if (deser.version() < Deserializer::V23 && EEPROM != nullptr)
|
||||
memcpy(EEPROM, eeprom, sizeof(eeprom));
|
||||
}
|
||||
|
||||
maple_naomi_jamma *getMieDevice()
|
||||
{
|
||||
if (MapleDevices[0][5] == nullptr || MapleDevices[0][5]->get_device_type() != MDT_NaomiJamma)
|
||||
return nullptr;
|
||||
return (maple_naomi_jamma *)MapleDevices[0][5];
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ struct MapleInputState
|
|||
extern MapleInputState mapleInputState[4];
|
||||
|
||||
void mcfg_CreateDevices();
|
||||
void mcfg_DestroyDevices();
|
||||
void mcfg_DestroyDevices(bool full = true);
|
||||
void mcfg_SerializeDevices(Serializer& ser);
|
||||
void mcfg_DeserializeDevices(Deserializer& deser);
|
||||
|
||||
|
@ -120,3 +120,6 @@ void push_vmu_screen(int bus_id, int bus_port, u8* buffer);
|
|||
void insertRfidCard(int playerNum);
|
||||
const u8 *getRfidCardData(int playerNum);
|
||||
void setRfidCardData(int playerNum, u8 *data);
|
||||
|
||||
struct maple_naomi_jamma;
|
||||
maple_naomi_jamma *getMieDevice();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <cmath>
|
||||
#include "input/gamepad.h"
|
||||
#include "serialize.h"
|
||||
#include "hw/hwreg.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
@ -257,7 +258,7 @@ struct maple_base: maple_device
|
|||
|
||||
class jvs_io_board;
|
||||
|
||||
struct maple_naomi_jamma : maple_base
|
||||
struct maple_naomi_jamma : maple_base, SerialPort
|
||||
{
|
||||
static constexpr u8 ALL_NODES = 0xff;
|
||||
|
||||
|
@ -295,4 +296,11 @@ struct maple_naomi_jamma : maple_base
|
|||
|
||||
void serialize(Serializer& ser) const override;
|
||||
void deserialize(Deserializer& deser) override;
|
||||
|
||||
void setPipe(Pipe *pipe) override {
|
||||
serialPipe = pipe;
|
||||
}
|
||||
void updateStatus() override {}
|
||||
|
||||
Pipe *serialPipe = nullptr;
|
||||
};
|
||||
|
|
|
@ -1464,6 +1464,47 @@ void maple_naomi_jamma::handle_86_subcommand()
|
|||
w8(0x0);
|
||||
break;
|
||||
|
||||
// RS422 port
|
||||
case 0x41: // reset?
|
||||
DEBUG_LOG(MAPLE, "JVS: RS422 reset");
|
||||
if (serialPipe != nullptr)
|
||||
while (serialPipe->available())
|
||||
serialPipe->read();
|
||||
break;
|
||||
|
||||
case 0x47: // send data
|
||||
DEBUG_LOG(MAPLE, "JVS: RS422 send %02x", dma_buffer_in[4]);
|
||||
if (serialPipe != nullptr)
|
||||
serialPipe->write(dma_buffer_in[4]);
|
||||
break;
|
||||
|
||||
case 0x4d: // receive data
|
||||
{
|
||||
int avail = 0;
|
||||
if (serialPipe != nullptr)
|
||||
avail = std::min(serialPipe->available(), 0xfe);
|
||||
DEBUG_LOG(MAPLE, "JVS: RS422 receive %d bytes", avail);
|
||||
w8(MDRS_JVSReply);
|
||||
w8(0);
|
||||
w8(0x20);
|
||||
w8(1 + (avail + 3) / 4);
|
||||
|
||||
w8(0);
|
||||
w8(0);
|
||||
w8(0);
|
||||
w8(avail == 0 ? 0xff : avail); // 0xff => no data, else byte count
|
||||
|
||||
for (int i = 0; i < ((avail + 3) / 4) * 4; i++)
|
||||
w8(i >= avail ? 0 : serialPipe->read());
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x49: // I?
|
||||
case 0x4b: // K?
|
||||
case 0x4f: // O?
|
||||
//DEBUG_LOG(MAPLE, "JVS: 0x86,%02x RS422 len %d", subcode, dma_count_in - 3);
|
||||
break;
|
||||
|
||||
default:
|
||||
INFO_LOG(MAPLE, "JVS: Unknown 0x86 sub-command %x", subcode);
|
||||
w8(MDRE_UnknownCmd);
|
||||
|
|
|
@ -20,57 +20,16 @@
|
|||
#include "oslib/oslib.h"
|
||||
#include "hw/sh4/modules/modules.h"
|
||||
#include "hw/maple/maple_cfg.h"
|
||||
#include "hw/maple/maple_devs.h"
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <errno.h>
|
||||
|
||||
namespace card_reader {
|
||||
|
||||
class CardReader
|
||||
{
|
||||
protected:
|
||||
u8 calcCrc(u8 *data, u32 len)
|
||||
{
|
||||
u32 crc = 0;
|
||||
for (u32 i = 0; i < len; i++)
|
||||
crc ^= data[i];
|
||||
return crc;
|
||||
}
|
||||
|
||||
bool loadCard(u8 *cardData, u32 len)
|
||||
{
|
||||
std::string path = hostfs::getArcadeFlashPath() + ".card";
|
||||
FILE *fp = nowide::fopen(path.c_str(), "rb");
|
||||
if (fp == nullptr)
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(NAOMI, "Loading card file from %s", path.c_str());
|
||||
if (fread(cardData, 1, len, fp) != len)
|
||||
WARN_LOG(NAOMI, "Truncated or empty card file: %s" ,path.c_str());
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void saveCard(const u8 *cardData, u32 len)
|
||||
{
|
||||
std::string path = hostfs::getArcadeFlashPath() + ".card";
|
||||
FILE *fp = nowide::fopen(path.c_str(), "wb");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
WARN_LOG(NAOMI, "Can't create card file %s: errno %d", path.c_str(), errno);
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(NAOMI, "Saving card file to %s", path.c_str());
|
||||
if (fwrite(cardData, 1, len, fp) != len)
|
||||
WARN_LOG(NAOMI, "Truncated write to file: %s", path.c_str());
|
||||
fclose(fp);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Initial D card reader protocol (from my good friend Metallic)
|
||||
Sanwa CRP-1231BR-10 card reader/writer protocol (from my good friend Metallic)
|
||||
used in InitialD and Derby Owners Club
|
||||
|
||||
>>> SEND PKT: [START 02][LEN][CMD][0][0][0]{optional data}[STOP 03][CRC]
|
||||
<<< RECV ACK: [OK 06]
|
||||
|
@ -99,18 +58,15 @@ protected:
|
|||
|
||||
Protocol dumps and more:
|
||||
https://www.arcade-projects.com/threads/naomi-2-chihiro-triforce-card-reader-emulator-initial-d3-wmmt-mario-kart-f-zero-ax.814/
|
||||
*/
|
||||
class InitialDCardReader final : public CardReader, SerialPipe
|
||||
|
||||
Bits from YACardEmu: https://github.com/GXTX/YACardEmu/
|
||||
Copyright (C) 2020-2023 wutno (https://github.com/GXTX)
|
||||
Copyright (C) 2022-2023 tugpoat (https://github.com/tugpoat)
|
||||
*/
|
||||
|
||||
class CardReader : public SerialPort::Pipe
|
||||
{
|
||||
public:
|
||||
InitialDCardReader() {
|
||||
serial_setPipe(this);
|
||||
}
|
||||
|
||||
~InitialDCardReader() {
|
||||
serial_setPipe(nullptr);
|
||||
}
|
||||
|
||||
void write(u8 b) override
|
||||
{
|
||||
if (inBufferIdx == 0 && b == 5)
|
||||
|
@ -204,7 +160,6 @@ private:
|
|||
return;
|
||||
outBuffer[outBufferLen++] = 2;
|
||||
u32 crcIdx = outBufferLen;
|
||||
u8 len = 6;
|
||||
u8 status1 = getStatus1();
|
||||
u8 status2 = '0';
|
||||
u8 status3 = '0';
|
||||
|
@ -222,14 +177,47 @@ private:
|
|||
break;
|
||||
|
||||
case CARD_WRITE:
|
||||
memcpy(cardData, &rxCommand[7], sizeof(cardData));
|
||||
// 4: mode ('0': read 0x45 bytes, '1': variable length write 1-47 bytes)
|
||||
// 5: parity ('0': 7-bit parity, '1': 8-bit no parity)
|
||||
// 6: track (see below)
|
||||
INFO_LOG(NAOMI, "Card write mode %c parity %c track %c", rxCommand[4], rxCommand[5], rxCommand[6]);
|
||||
switch (rxCommand[6])
|
||||
{
|
||||
case '0': // track 1
|
||||
memcpy(cardData, &rxCommand[7], TRACK_SIZE);
|
||||
break;
|
||||
case '1': // track 2
|
||||
memcpy(cardData + TRACK_SIZE, &rxCommand[7], TRACK_SIZE);
|
||||
break;
|
||||
case '2': // track 3
|
||||
memcpy(cardData + TRACK_SIZE * 2, &rxCommand[7], TRACK_SIZE);
|
||||
break;
|
||||
case '3': // track 1 & 2
|
||||
memcpy(cardData, &rxCommand[7], TRACK_SIZE * 2);
|
||||
break;
|
||||
case '4': // track 1 & 3
|
||||
memcpy(cardData, &rxCommand[7], TRACK_SIZE);
|
||||
memcpy(cardData + TRACK_SIZE * 2, &rxCommand[7 + TRACK_SIZE], TRACK_SIZE);
|
||||
break;
|
||||
case '5': // track 2 & 3
|
||||
memcpy(cardData + TRACK_SIZE, &rxCommand[7], TRACK_SIZE * 2);
|
||||
break;
|
||||
case '6': // track 1 2 & 3
|
||||
memcpy(cardData, &rxCommand[7], TRACK_SIZE * 3);
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(NAOMI, "Unknown track# %02x", rxCommand[6]);
|
||||
break;
|
||||
}
|
||||
saveCard(cardData, sizeof(cardData));
|
||||
break;
|
||||
|
||||
case CARD_READ:
|
||||
if (cardInserted && !doorOpen)
|
||||
len = 6 + sizeof(cardData);
|
||||
else
|
||||
// 4: mode ('0': read 0x45 bytes, '1': variable length read 1-47 bytes, '2': card capture, pull in card?)
|
||||
// 5: parity ('0': 7-bit parity, '1': 8-bit no parity)
|
||||
// 6: track (see below)
|
||||
INFO_LOG(NAOMI, "Card read mode %c parity %c track %c", rxCommand[4], rxCommand[5], rxCommand[6]);
|
||||
if (!cardInserted || doorOpen)
|
||||
status3 = cardInserted ? '0' : '4';
|
||||
break;
|
||||
|
||||
|
@ -251,21 +239,93 @@ private:
|
|||
WARN_LOG(NAOMI, "Unknown command %x", rxCommand[0]);
|
||||
break;
|
||||
}
|
||||
outBuffer[outBufferLen++] = len;
|
||||
outBuffer[outBufferLen++] = 6;
|
||||
outBuffer[outBufferLen++] = rxCommand[0];
|
||||
outBuffer[outBufferLen++] = status1;
|
||||
outBuffer[outBufferLen++] = status2;
|
||||
outBuffer[outBufferLen++] = status3;
|
||||
if (rxCommand[0] == CARD_READ && cardInserted && !doorOpen)
|
||||
if (rxCommand[0] == CARD_READ && cardInserted && !doorOpen && rxCommand[4] != '2')
|
||||
{
|
||||
memcpy(&outBuffer[outBufferLen], cardData, sizeof(cardData));
|
||||
outBufferLen += sizeof(cardData);
|
||||
u32 idx = 0;
|
||||
u32 size = TRACK_SIZE;
|
||||
switch (rxCommand[6])
|
||||
{
|
||||
case '0': // track 1
|
||||
break;
|
||||
case '1': // track 2
|
||||
idx = TRACK_SIZE;
|
||||
break;
|
||||
case '2': // track 3
|
||||
idx = TRACK_SIZE * 2;
|
||||
break;
|
||||
case '3': // track 1 & 2
|
||||
size = TRACK_SIZE * 2;
|
||||
break;
|
||||
case '4': // track 1 & 3
|
||||
memcpy(&outBuffer[outBufferLen], cardData, TRACK_SIZE);
|
||||
outBufferLen += TRACK_SIZE;
|
||||
outBuffer[crcIdx] += size;
|
||||
idx = TRACK_SIZE * 2;
|
||||
break;
|
||||
case '5': // track 2 & 3
|
||||
idx = TRACK_SIZE;
|
||||
size = TRACK_SIZE * 2;
|
||||
break;
|
||||
case '6': // track 1 2 & 3
|
||||
size = TRACK_SIZE * 3;
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(NAOMI, "Unknown track# %02x", rxCommand[6]);
|
||||
size = 0;
|
||||
break;
|
||||
}
|
||||
memcpy(&outBuffer[outBufferLen], cardData + idx, size);
|
||||
outBufferLen += size;
|
||||
outBuffer[crcIdx] += size;
|
||||
}
|
||||
outBuffer[outBufferLen++] = 3;
|
||||
outBuffer[outBufferLen] = calcCrc(&outBuffer[crcIdx], outBufferLen - crcIdx);
|
||||
outBufferLen++;
|
||||
}
|
||||
|
||||
u8 calcCrc(u8 *data, u32 len)
|
||||
{
|
||||
u32 crc = 0;
|
||||
for (u32 i = 0; i < len; i++)
|
||||
crc ^= data[i];
|
||||
return crc;
|
||||
}
|
||||
|
||||
bool loadCard(u8 *cardData, u32 len)
|
||||
{
|
||||
std::string path = hostfs::getArcadeFlashPath() + ".card";
|
||||
FILE *fp = nowide::fopen(path.c_str(), "rb");
|
||||
if (fp == nullptr)
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(NAOMI, "Loading card file from %s", path.c_str());
|
||||
if (fread(cardData, 1, len, fp) != len)
|
||||
WARN_LOG(NAOMI, "Truncated or empty card file: %s" ,path.c_str());
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void saveCard(const u8 *cardData, u32 len)
|
||||
{
|
||||
std::string path = hostfs::getArcadeFlashPath() + ".card";
|
||||
FILE *fp = nowide::fopen(path.c_str(), "wb");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
WARN_LOG(NAOMI, "Can't create card file %s: errno %d", path.c_str(), errno);
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(NAOMI, "Saving card file to %s", path.c_str());
|
||||
if (fwrite(cardData, 1, len, fp) != len)
|
||||
WARN_LOG(NAOMI, "Truncated write to file: %s", path.c_str());
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
u8 inBuffer[256];
|
||||
u32 inBufferIdx = 0;
|
||||
|
||||
|
@ -276,30 +336,63 @@ private:
|
|||
u32 outBufferIdx = 0;
|
||||
u32 outBufferLen = 0;
|
||||
|
||||
u8 cardData[207];
|
||||
static constexpr u32 TRACK_SIZE = 0x45;
|
||||
u8 cardData[TRACK_SIZE * 3];
|
||||
bool doorOpen = false;
|
||||
bool cardInserted = false;
|
||||
};
|
||||
|
||||
static std::unique_ptr<InitialDCardReader> initdReader;
|
||||
// Hooked to the SH4 SCIF serial port
|
||||
class InitialDCardReader final : public CardReader
|
||||
{
|
||||
public:
|
||||
InitialDCardReader() {
|
||||
SCIFSerialPort::Instance().setPipe(this);
|
||||
}
|
||||
|
||||
~InitialDCardReader() {
|
||||
SCIFSerialPort::Instance().setPipe(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
// Hooked to the MIE via a 838-13661 RS232/RS422 converter board
|
||||
class DerbyCardReader final : public CardReader
|
||||
{
|
||||
public:
|
||||
DerbyCardReader() {
|
||||
getMieDevice()->setPipe(this);
|
||||
}
|
||||
|
||||
~DerbyCardReader() {
|
||||
getMieDevice()->setPipe(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
static std::unique_ptr<CardReader> cardReader;
|
||||
|
||||
void initdInit() {
|
||||
initdReader = std::make_unique<InitialDCardReader>();
|
||||
term();
|
||||
cardReader = std::make_unique<InitialDCardReader>();
|
||||
}
|
||||
|
||||
void initdTerm() {
|
||||
initdReader.reset();
|
||||
void derbyInit() {
|
||||
term();
|
||||
cardReader = std::make_unique<DerbyCardReader>();
|
||||
}
|
||||
|
||||
class BarcodeReader final : public SerialPipe
|
||||
void term() {
|
||||
cardReader.reset();
|
||||
}
|
||||
|
||||
class BarcodeReader final : public SerialPort::Pipe
|
||||
{
|
||||
public:
|
||||
BarcodeReader() {
|
||||
serial_setPipe(this);
|
||||
SCIFSerialPort::Instance().setPipe(this);
|
||||
}
|
||||
|
||||
~BarcodeReader() {
|
||||
serial_setPipe(nullptr);
|
||||
SCIFSerialPort::Instance().setPipe(nullptr);
|
||||
}
|
||||
|
||||
int available() override {
|
||||
|
@ -320,7 +413,7 @@ public:
|
|||
INFO_LOG(NAOMI, "Card read: %s", card.c_str());
|
||||
std::string data = card + "*";
|
||||
toSend.insert(toSend.end(), (const u8 *)&data[0], (const u8 *)(&data.back() + 1));
|
||||
serial_updateStatusRegister();
|
||||
SCIFSerialPort::Instance().updateStatus();
|
||||
}
|
||||
|
||||
std::string getCard() const {
|
||||
|
@ -366,8 +459,8 @@ void barcodeSetCard(const std::string& card)
|
|||
|
||||
void insertCard(int playerNum)
|
||||
{
|
||||
if (initdReader != nullptr)
|
||||
initdReader->insertCard();
|
||||
if (cardReader != nullptr)
|
||||
cardReader->insertCard();
|
||||
else if (barcodeReader != nullptr)
|
||||
barcodeReader->insertCard();
|
||||
else
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
namespace card_reader {
|
||||
|
||||
void initdInit();
|
||||
void initdTerm();
|
||||
void derbyInit();
|
||||
void term();
|
||||
|
||||
void barcodeInit();
|
||||
void barcodeTerm();
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
namespace hopper
|
||||
{
|
||||
|
||||
class BaseHopper : public SerialPipe
|
||||
class BaseHopper : public SerialPort::Pipe
|
||||
{
|
||||
public:
|
||||
BaseHopper()
|
||||
|
@ -183,7 +183,7 @@ protected:
|
|||
chksum += *payload;
|
||||
}
|
||||
toSend.push_back(chksum);
|
||||
serial_updateStatusRegister();
|
||||
SCIFSerialPort::Instance().updateStatus();
|
||||
}
|
||||
|
||||
void bet(const u32 *values)
|
||||
|
@ -1281,7 +1281,7 @@ void init()
|
|||
hopper = new Sega837_14438Hopper();
|
||||
else
|
||||
hopper = new NaomiHopper();
|
||||
serial_setPipe(hopper);
|
||||
SCIFSerialPort::Instance().setPipe(hopper);
|
||||
config::ForceFreePlay.override(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -716,7 +716,7 @@ void initMidiForceFeedback()
|
|||
aica::setMidiReceiver(forceFeedbackMidiReceiver);
|
||||
}
|
||||
|
||||
struct DriveSimPipe : public SerialPipe
|
||||
struct DriveSimPipe : public SerialPort::Pipe
|
||||
{
|
||||
void write(u8 data) override
|
||||
{
|
||||
|
@ -773,7 +773,7 @@ void initDriveSimSerialPipe()
|
|||
static DriveSimPipe pipe;
|
||||
|
||||
pipe.reset();
|
||||
serial_setPipe(&pipe);
|
||||
SCIFSerialPort::Instance().setPipe(&pipe);
|
||||
}
|
||||
|
||||
G2PrinterConnection g2PrinterConnection;
|
||||
|
|
|
@ -652,7 +652,8 @@ void naomi_cart_LoadRom(const std::string& path, const std::string& fileName, Lo
|
|||
}
|
||||
else if (gameId.substr(0, 8) == "MKG TKOB"
|
||||
|| gameId.substr(0, 9) == "MUSHIKING"
|
||||
|| gameId == "DINOSAUR KING")
|
||||
|| gameId == "DINOSAUR KING"
|
||||
|| gameId == "INW PUPPY 2008 VER1.001") // SystemSP isshoni
|
||||
{
|
||||
card_reader::barcodeInit();
|
||||
}
|
||||
|
@ -730,7 +731,7 @@ void naomi_cart_Close()
|
|||
{
|
||||
touchscreen::term();
|
||||
printer::term();
|
||||
card_reader::initdTerm();
|
||||
card_reader::term();
|
||||
card_reader::barcodeTerm();
|
||||
serialModemTerm();
|
||||
hopper::term();
|
||||
|
|
|
@ -33,10 +33,10 @@
|
|||
#include "oslib/oslib.h"
|
||||
#include "cfg/option.h"
|
||||
#include "card_reader.h"
|
||||
#include "naomi_roms.h"
|
||||
#include "stdclass.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "hw/sh4/sh4_if.h"
|
||||
|
||||
#ifdef DEBUG_EEPROM
|
||||
#define EEPROM_LOG(...) DEBUG_LOG(FLASHROM, __VA_ARGS__)
|
||||
#else
|
||||
|
@ -162,67 +162,20 @@ void SerialEeprom93Cxx::writeCLK(int state)
|
|||
clk = state;
|
||||
}
|
||||
|
||||
u8 SerialPort::readReg(u32 addr)
|
||||
//
|
||||
// RS232C I/F board (838-14244) connected to RFID Chip R/W board (838-14243)
|
||||
//
|
||||
class RfidReaderWriter : public SerialPort::Pipe
|
||||
{
|
||||
switch ((addr & 0x3f) / 4)
|
||||
public:
|
||||
RfidReaderWriter(SerialPort *port, int index) : port(port), index(index)
|
||||
{
|
||||
case 0: // data in
|
||||
{
|
||||
u8 data = 0;
|
||||
if (!toSend.empty())
|
||||
{
|
||||
data = toSend.front();
|
||||
toSend.pop_front();
|
||||
}
|
||||
if (toSend.empty())
|
||||
asic_CancelInterrupt(holly_EXP_PCI);
|
||||
SERIAL_LOG("UART%d read data in %x", index, data);
|
||||
return data;
|
||||
}
|
||||
case 1: // out buffer len
|
||||
SERIAL_LOG("UART%d read out buf len", index);
|
||||
return 0;
|
||||
case 2: // in buffer len
|
||||
SERIAL_LOG("UART%d read in buf len %d", index, (int)toSend.size());
|
||||
return toSend.size();
|
||||
case 3: // errors?
|
||||
SERIAL_LOG("UART%d read errors", index);
|
||||
return 0;
|
||||
case 4: // unknown
|
||||
SERIAL_LOG("UART%d read reg4", index);
|
||||
return 0;
|
||||
case 5: // flow control
|
||||
SERIAL_LOG("UART%d read flow control", index);
|
||||
return 0;
|
||||
case 6: // status. bit 3: receive buffer not empty
|
||||
SERIAL_LOG("UART%d read status %x pr %x", index, (u8)(!toSend.empty()) << 3, p_sh4rcb->cntx.pr);
|
||||
return (u8)(!toSend.empty()) << 3;
|
||||
case 7: // interrupt status/mask?
|
||||
SERIAL_LOG("UART%d read interrupt mask/status?", index);
|
||||
return 0;
|
||||
case 8: // unknown
|
||||
SERIAL_LOG("UART%d read reg8", index);
|
||||
return 0;
|
||||
case 9: // control?
|
||||
SERIAL_LOG("UART%d read control?", index);
|
||||
return 0;
|
||||
case 10: // baudrate (lsb)
|
||||
SERIAL_LOG("UART%d read baudrate(lsb)", index);
|
||||
return 0;
|
||||
case 11: // baudrate (msb)
|
||||
SERIAL_LOG("UART%d read baudrate(msb)", index);
|
||||
return 0;
|
||||
default:
|
||||
INFO_LOG(NAOMI, "Unknown UART%d port %x\n", index, addr);
|
||||
return 0;
|
||||
port->setPipe(this);
|
||||
// TODO load card
|
||||
}
|
||||
}
|
||||
|
||||
void SerialPort::writeReg(u32 addr, u8 v)
|
||||
{
|
||||
switch ((addr & 0x3f) / 4)
|
||||
void write(u8 v) override
|
||||
{
|
||||
case 0: // data out
|
||||
if (expectedBytes > 0)
|
||||
{
|
||||
SERIAL_LOG("UART%d write data out: %02x", index, v);
|
||||
|
@ -248,7 +201,7 @@ void SerialPort::writeReg(u32 addr, u8 v)
|
|||
toSend.push_back(1);
|
||||
SERIAL_LOG("UART%d COUNT %x", index, recvBuffer[1]);
|
||||
}
|
||||
asic_RaiseInterrupt(holly_EXP_PCI);
|
||||
port->updateStatus();
|
||||
expectedBytes = 0;
|
||||
}
|
||||
return;
|
||||
|
@ -329,10 +282,312 @@ void SerialPort::writeReg(u32 addr, u8 v)
|
|||
toSend.push_back(0x3a); // ng
|
||||
break;
|
||||
}
|
||||
if (toSend.empty())
|
||||
asic_CancelInterrupt(holly_EXP_PCI);
|
||||
}
|
||||
|
||||
int available() override {
|
||||
return toSend.size();
|
||||
}
|
||||
|
||||
u8 read() override
|
||||
{
|
||||
u8 b = 0;
|
||||
if (!toSend.empty())
|
||||
{
|
||||
b = toSend.front();
|
||||
toSend.pop_front();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
void serialize(Serializer& ser) const override
|
||||
{
|
||||
ser << (u32)toSend.size();
|
||||
for (u8 b : toSend)
|
||||
ser << b;
|
||||
ser << expectedBytes;
|
||||
ser << (u32)recvBuffer.size();
|
||||
ser.serialize(recvBuffer.data(), recvBuffer.size());
|
||||
}
|
||||
|
||||
void deserialize(Deserializer& deser) override
|
||||
{
|
||||
u32 size;
|
||||
deser >> size;
|
||||
toSend.resize(size);
|
||||
for (u32 i = 0; i < size; i++)
|
||||
deser >> toSend[i];
|
||||
deser >> expectedBytes;
|
||||
deser >> size;
|
||||
recvBuffer.resize(size);
|
||||
deser.deserialize(recvBuffer.data(), recvBuffer.size());
|
||||
}
|
||||
|
||||
private:
|
||||
SerialPort *port;
|
||||
const int index;
|
||||
std::deque<u8> toSend;
|
||||
std::array<u8, 128> cardData;
|
||||
u8 expectedBytes = 0;
|
||||
std::vector<u8> recvBuffer;
|
||||
};
|
||||
|
||||
//
|
||||
// Isshoni Wanwan Waiwai Puppy touchscreen
|
||||
//
|
||||
class Touchscreen : public SerialPort::Pipe
|
||||
{
|
||||
public:
|
||||
Touchscreen(SerialPort *port) : port(port)
|
||||
{
|
||||
port->setPipe(this);
|
||||
schedId = sh4_sched_register(0, schedCallback, this);
|
||||
}
|
||||
|
||||
~Touchscreen()
|
||||
{
|
||||
sh4_sched_unregister(schedId);
|
||||
}
|
||||
|
||||
void write(u8 v) override
|
||||
{
|
||||
if (v == '\r')
|
||||
{
|
||||
if (recvBuffer.size() >= 2 && recvBuffer[0] == 1)
|
||||
{
|
||||
toSend.push_back(1);
|
||||
if (recvBuffer.size() == 3 && recvBuffer[1] == 'O' && recvBuffer[2] == 'I')
|
||||
{
|
||||
SERIAL_LOG("Received cmd OI: get name");
|
||||
toSend.push_back('A');
|
||||
toSend.push_back('3');
|
||||
toSend.push_back('0');
|
||||
toSend.push_back('9');
|
||||
toSend.push_back('9');
|
||||
toSend.push_back('9');
|
||||
}
|
||||
else if (recvBuffer.size() == 3 && recvBuffer[1] == 'N' && recvBuffer[2] == 'M')
|
||||
{
|
||||
SERIAL_LOG("Received cmd NM: unit verify");
|
||||
const std::array<u8, 19> id { 'E','X','I','I','-','7','7','2','0','S','C',' ','R','e','v',' ','3','.','0' };
|
||||
toSend.insert(toSend.end(), id.begin(), id.end());
|
||||
}
|
||||
else if (recvBuffer.size() == 3 && recvBuffer[1] == 'U' && recvBuffer[2] == 'V')
|
||||
{
|
||||
SERIAL_LOG("Received cmd UV: reset");
|
||||
const std::array<u8, 8> resp { 'Q','M','V','*','*','*','0','0' };
|
||||
toSend.insert(toSend.end(), resp.begin(), resp.end());
|
||||
}
|
||||
else if (recvBuffer.size() == 2 && recvBuffer[1] == 'R')
|
||||
{
|
||||
SERIAL_LOG("Received cmd R");
|
||||
toSend.push_back('0');
|
||||
sh4_sched_request(schedId, SCHED_CYCLES);
|
||||
}
|
||||
else
|
||||
{
|
||||
SERIAL_LOG("Received cmd %c", recvBuffer[1]);
|
||||
toSend.push_back('0');
|
||||
}
|
||||
toSend.push_back('\r');
|
||||
port->updateStatus();
|
||||
|
||||
// FIXME
|
||||
if (recvBuffer.size() == 2 && recvBuffer[1] == 'Z')
|
||||
sendPosition(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG(NAOMI, "\\r ignored. buf size %d", (int)recvBuffer.size());
|
||||
}
|
||||
recvBuffer.clear();
|
||||
}
|
||||
else
|
||||
asic_RaiseInterrupt(holly_EXP_PCI);
|
||||
{
|
||||
if (recvBuffer.size() == 9)
|
||||
{
|
||||
if (!memcmp(&recvBuffer[0], "Ua0000000", 9))
|
||||
{
|
||||
SERIAL_LOG("UART receive Ua...%c", v);
|
||||
sendPosition(1);
|
||||
}
|
||||
else
|
||||
WARN_LOG(NAOMI, "Unknown command %.9s", &recvBuffer[0]);
|
||||
recvBuffer.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
recvBuffer.push_back(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int available() override {
|
||||
return toSend.size();
|
||||
}
|
||||
|
||||
u8 read() override
|
||||
{
|
||||
u8 data = 0;
|
||||
if (!toSend.empty())
|
||||
{
|
||||
data = toSend.front();
|
||||
toSend.pop_front();
|
||||
}
|
||||
if (toSend.empty())
|
||||
port->updateStatus();
|
||||
SERIAL_LOG("UART read data %x", data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void serialize(Serializer& ser) const override
|
||||
{
|
||||
ser << (u32)toSend.size();
|
||||
for (u8 b : toSend)
|
||||
ser << b;
|
||||
ser << (u32)recvBuffer.size();
|
||||
ser.serialize(recvBuffer.data(), recvBuffer.size());
|
||||
}
|
||||
|
||||
void deserialize(Deserializer& deser) override
|
||||
{
|
||||
u32 size;
|
||||
deser >> size;
|
||||
toSend.resize(size);
|
||||
for (u32 i = 0; i < size; i++)
|
||||
deser >> toSend[i];
|
||||
deser >> size;
|
||||
recvBuffer.resize(size);
|
||||
deser.deserialize(recvBuffer.data(), recvBuffer.size());
|
||||
}
|
||||
|
||||
private:
|
||||
void sendPosition(int type)
|
||||
{
|
||||
MapleInputState input[4];
|
||||
ggpo::getInput(input);
|
||||
// 0-1023 ?
|
||||
const u32 x = (640 - input[0].absPos.x) * 1023 / 639;
|
||||
const u32 y = input[0].absPos.y * 1023 / 479;
|
||||
|
||||
size_t start = toSend.size();
|
||||
if (type == 1)
|
||||
{
|
||||
toSend.push_back('U');
|
||||
toSend.push_back('T');
|
||||
toSend.push_back(0x20); // bit 0 and 1 are checked
|
||||
toSend.push_back(x & 0xff);
|
||||
toSend.push_back((x >> 8) & 0x1f);
|
||||
toSend.push_back(y & 0xff);
|
||||
toSend.push_back((y >> 8) & 0x1f);
|
||||
toSend.push_back(0); // z pos
|
||||
u8 crc = 0xaa;
|
||||
for (; start < toSend.size(); start++)
|
||||
crc += toSend[start];
|
||||
toSend.push_back(crc);
|
||||
port->updateStatus();
|
||||
}
|
||||
else
|
||||
{
|
||||
bool button = (input[0].kcode & DC_BTN_B) == 0; // FIXME use button A instead
|
||||
if (button != lastButton || x != lastPosX || y != lastPosY)
|
||||
{
|
||||
// bit 6 is touch down
|
||||
if (button)
|
||||
toSend.push_back(0xc0);
|
||||
else
|
||||
toSend.push_back(0x80);
|
||||
toSend.push_back((x & 7) << 4);
|
||||
toSend.push_back((x >> 3) & 0x7f);
|
||||
toSend.push_back((y & 7) << 4);
|
||||
toSend.push_back((y >> 3) & 0x7f);
|
||||
lastButton = button;
|
||||
lastPosX = x;
|
||||
lastPosY = y;
|
||||
port->updateStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int schedCallback(int tag, int cycles, int jitter, void *p)
|
||||
{
|
||||
((Touchscreen *)p)->sendPosition(0);
|
||||
return SCHED_CYCLES;
|
||||
}
|
||||
|
||||
SerialPort *port;
|
||||
std::deque<u8> toSend;
|
||||
std::vector<u8> recvBuffer;
|
||||
int schedId = 0;
|
||||
u32 lastPosX = ~0;
|
||||
u32 lastPosY = ~0;
|
||||
bool lastButton = false;
|
||||
|
||||
static constexpr u32 SCHED_CYCLES = SH4_MAIN_CLOCK / 60;
|
||||
};
|
||||
|
||||
u8 SerialPort::readReg(u32 addr)
|
||||
{
|
||||
switch ((addr & 0x3f) / 4)
|
||||
{
|
||||
case 0: // data in
|
||||
if (pipe != nullptr)
|
||||
return pipe->read();
|
||||
else
|
||||
return 0;
|
||||
case 1: // out buffer len
|
||||
//SERIAL_LOG("UART%d read out buf len", index);
|
||||
return 0;
|
||||
case 2: // in buffer len
|
||||
//SERIAL_LOG("UART%d read in buf len %d", index, (int)toSend.size());
|
||||
if (pipe != nullptr)
|
||||
return pipe->available();
|
||||
else
|
||||
return 0;
|
||||
case 3: // errors?
|
||||
SERIAL_LOG("UART%d read errors", index);
|
||||
return 0;
|
||||
case 4: // unknown
|
||||
SERIAL_LOG("UART%d read reg4", index);
|
||||
return 0;
|
||||
case 5: // flow control
|
||||
SERIAL_LOG("UART%d read flow control", index);
|
||||
return 0;
|
||||
case 6: // status. bit 3: receive buffer not empty
|
||||
SERIAL_LOG("UART%d read status", index);
|
||||
if (pipe != nullptr && pipe->available() > 0)
|
||||
return 8;
|
||||
else
|
||||
return 0;
|
||||
case 7: // interrupt status/mask?
|
||||
SERIAL_LOG("UART%d read interrupt mask/status?", index);
|
||||
return 0;
|
||||
case 8: // unknown
|
||||
SERIAL_LOG("UART%d read reg8", index);
|
||||
return 0;
|
||||
case 9: // control?
|
||||
SERIAL_LOG("UART%d read control?", index);
|
||||
return 0;
|
||||
case 10: // baudrate (lsb)
|
||||
SERIAL_LOG("UART%d read baudrate(lsb)", index);
|
||||
return 0;
|
||||
case 11: // baudrate (msb)
|
||||
SERIAL_LOG("UART%d read baudrate(msb)", index);
|
||||
return 0;
|
||||
default:
|
||||
INFO_LOG(NAOMI, "Unknown UART%d port %x\n", index, addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SerialPort::writeReg(u32 addr, u8 v)
|
||||
{
|
||||
switch ((addr & 0x3f) / 4)
|
||||
{
|
||||
case 0: // data out
|
||||
if (pipe != nullptr)
|
||||
pipe->write(v);
|
||||
else
|
||||
INFO_LOG(NAOMI, "UART%d out: %02x %c", index, v, v);
|
||||
break;
|
||||
|
||||
case 1: // out buffer len
|
||||
|
@ -373,10 +628,12 @@ void SerialPort::writeReg(u32 addr, u8 v)
|
|||
|
||||
case 10: // baudrate (lsb)
|
||||
SERIAL_LOG("UART%d write baudrate(lsb): %x", index, v);
|
||||
flush();
|
||||
break;
|
||||
|
||||
case 11: // baudrate (msb)
|
||||
SERIAL_LOG("UART%d write baudrate(msb): %x", index, v);
|
||||
flush();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -385,6 +642,11 @@ void SerialPort::writeReg(u32 addr, u8 v)
|
|||
}
|
||||
}
|
||||
|
||||
void SerialPort::updateStatus()
|
||||
{
|
||||
cart->updateInterrupt(index == 1 ? SystemSpCart::INT_UART1 : SystemSpCart::INT_UART2);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T readMemArea0(u32 addr)
|
||||
{
|
||||
|
@ -455,9 +717,7 @@ T SystemSpCart::readMemArea0(u32 addr)
|
|||
if (ata.cylinder == 0)
|
||||
ata.driveHead.head++;
|
||||
readSectors();
|
||||
ata.interruptPending |= 0x10;
|
||||
if (ata.devCtrl.nien == 0)
|
||||
asic_RaiseInterrupt(holly_EXP_PCI);
|
||||
updateInterrupt(INT_ATA);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -544,11 +804,17 @@ T SystemSpCart::readMemArea0(u32 addr)
|
|||
case 0x30:
|
||||
return 0;
|
||||
case 0x80:
|
||||
// interrupt status
|
||||
asic_CancelInterrupt(holly_EXP_PCI);
|
||||
// bit3 is for DIMM
|
||||
// bit4 is for ATA controller
|
||||
return uart1.hasData() | (uart2.hasData() << 1) | ata.interruptPending;
|
||||
{
|
||||
// interrupt status
|
||||
const u8 intPending = ata.interruptPending;
|
||||
ata.interruptPending = 0;
|
||||
updateInterrupt();
|
||||
// b0: UART1
|
||||
// b1: UART2
|
||||
// b3: DIMM
|
||||
// b4: ATA controller
|
||||
return intPending;
|
||||
}
|
||||
case 0x84:
|
||||
// interrupt mask?
|
||||
// 10084: (dinoking) bit0,1 reset, sometimes set
|
||||
|
@ -961,7 +1227,17 @@ void SystemSpCart::writeMemArea0(u32 addr, T v)
|
|||
INFO_LOG(NAOMI, "systemsp::writeMemArea0<%d>: Unknown addr %x = %x", (int)sizeof(T), addr, (int)v);
|
||||
}
|
||||
|
||||
SystemSpCart::SystemSpCart(u32 size) : M4Cartridge(size), eeprom(128), uart1(1), uart2(2)
|
||||
void SystemSpCart::updateInterrupt(u32 mask)
|
||||
{
|
||||
ata.interruptPending |= mask;
|
||||
if ((ata.interruptPending & (INT_UART1 | INT_UART2 | INT_DIMM))
|
||||
|| ((ata.interruptPending & INT_ATA) && ata.devCtrl.nien == 0))
|
||||
asic_RaiseInterrupt(holly_EXP_PCI);
|
||||
else
|
||||
asic_CancelInterrupt(holly_EXP_PCI);
|
||||
}
|
||||
|
||||
SystemSpCart::SystemSpCart(u32 size) : M4Cartridge(size), eeprom(128), uart1(this, 1), uart2(this, 2)
|
||||
{
|
||||
schedId = sh4_sched_register(0, schedCallback, this);
|
||||
Instance = this;
|
||||
|
@ -1068,6 +1344,16 @@ void SystemSpCart::Init(LoadProgress *progress, std::vector<u8> *digest)
|
|||
ata.status.rdy = 0;
|
||||
ata.status.df = 1;
|
||||
}
|
||||
if ((!strncmp(game->name, "dinoki", 6) && strcmp(game->name, "dinoki4") != 0))
|
||||
{
|
||||
new RfidReaderWriter(&uart1, 1);
|
||||
new RfidReaderWriter(&uart2, 2);
|
||||
}
|
||||
else if (!strcmp(game->name, "isshoni"))
|
||||
{
|
||||
new Touchscreen(&uart1);
|
||||
}
|
||||
|
||||
EventManager::listen(Event::Pause, handleEvent, this);
|
||||
}
|
||||
|
||||
|
@ -1083,6 +1369,8 @@ void SystemSpCart::WriteMem(u32 address, u32 data, u32 size)
|
|||
|
||||
bool SystemSpCart::Read(u32 offset, u32 size, void *dst)
|
||||
{
|
||||
// TODO sram? if ((offset & 0x3f000000) == 0x39000000)
|
||||
|
||||
if ((offset & 0x3f000000) == 0x3f000000)
|
||||
{
|
||||
// network card present
|
||||
|
@ -1208,9 +1496,7 @@ int SystemSpCart::schedCallback()
|
|||
{
|
||||
ata.status.rdy = 1;
|
||||
ata.status.bsy = 0;
|
||||
ata.interruptPending |= 0x10;
|
||||
if (ata.devCtrl.nien == 0)
|
||||
asic_RaiseInterrupt(holly_EXP_PCI);
|
||||
updateInterrupt(INT_ATA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#pragma once
|
||||
#include "types.h"
|
||||
#include "emulator.h"
|
||||
#include "hw/hwreg.h"
|
||||
#include "hw/naomi/m4cartridge.h"
|
||||
#include "hw/flashrom/flashrom.h"
|
||||
#include "serialize.h"
|
||||
|
@ -35,6 +36,9 @@ T readMemArea0(u32 addr);
|
|||
template<typename T>
|
||||
void writeMemArea0(u32 addr, T v);
|
||||
|
||||
//
|
||||
// rom board eeprom
|
||||
//
|
||||
class SerialEeprom93Cxx : public WritableChip
|
||||
{
|
||||
public:
|
||||
|
@ -102,8 +106,6 @@ public:
|
|||
deser >> dataOutBits;
|
||||
}
|
||||
|
||||
void save(const std::string& path);
|
||||
|
||||
private:
|
||||
u8 getCommandAddress() const
|
||||
{
|
||||
|
@ -137,51 +139,63 @@ private:
|
|||
u8 dataOutBits = 0;
|
||||
};
|
||||
|
||||
class SerialPort
|
||||
class SystemSpCart;
|
||||
|
||||
// rom board custom UART ports
|
||||
class SerialPort : public ::SerialPort
|
||||
{
|
||||
public:
|
||||
SerialPort(int index) : index(index)
|
||||
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() {
|
||||
if (pipe != nullptr)
|
||||
delete pipe;
|
||||
}
|
||||
|
||||
u8 readReg(u32 addr);
|
||||
|
||||
void writeReg(u32 addr, u8 v);
|
||||
|
||||
bool hasData() const {
|
||||
return !toSend.empty();
|
||||
void serialize(Serializer& ser) const {
|
||||
if (pipe != nullptr)
|
||||
pipe->serialize(ser);
|
||||
}
|
||||
|
||||
void serialize(Serializer& ser) const
|
||||
{
|
||||
ser << (u32)toSend.size();
|
||||
for (u8 b : toSend)
|
||||
ser << b;
|
||||
ser << expectedBytes;
|
||||
ser << (u32)recvBuffer.size();
|
||||
ser.serialize(recvBuffer.data(), recvBuffer.size());
|
||||
void deserialize(Deserializer& deser) {
|
||||
if (pipe != nullptr)
|
||||
pipe->deserialize(deser);
|
||||
}
|
||||
void deserialize(Deserializer& deser)
|
||||
{
|
||||
u32 size;
|
||||
deser >> size;
|
||||
toSend.resize(size);
|
||||
for (u32 i = 0; i < size; i++)
|
||||
deser >> toSend[i];
|
||||
deser >> expectedBytes;
|
||||
deser >> size;
|
||||
recvBuffer.resize(size);
|
||||
deser.deserialize(recvBuffer.data(), recvBuffer.size());
|
||||
|
||||
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;
|
||||
std::deque<u8> toSend;
|
||||
std::array<u8, 128> cardData;
|
||||
u8 expectedBytes = 0;
|
||||
std::vector<u8> recvBuffer;
|
||||
Pipe *pipe = nullptr;
|
||||
};
|
||||
|
||||
//
|
||||
// ATA registers for CompactFlash interface
|
||||
//
|
||||
union AtaStatusRegister
|
||||
{
|
||||
u8 full;
|
||||
|
@ -256,6 +270,8 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
void updateInterrupt(u32 mask = 0);
|
||||
|
||||
private:
|
||||
static int schedCallback(int tag, int sch_cycl, int jitter, void *arg);
|
||||
int schedCallback();
|
||||
|
@ -319,6 +335,11 @@ private:
|
|||
} flash;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
@ -34,13 +34,13 @@ namespace touchscreen
|
|||
// 837-14672 touchscreen sensor board
|
||||
// used by Manic Panic Ghosts and Touch De Zunou
|
||||
//
|
||||
class TouchscreenPipe final : public SerialPipe
|
||||
class TouchscreenPipe final : public SerialPort::Pipe
|
||||
{
|
||||
public:
|
||||
TouchscreenPipe()
|
||||
{
|
||||
schedId = sh4_sched_register(0, schedCallback, this);
|
||||
serial_setPipe(this);
|
||||
SCIFSerialPort::Instance().setPipe(this);
|
||||
}
|
||||
|
||||
~TouchscreenPipe()
|
||||
|
@ -101,7 +101,7 @@ private:
|
|||
return;
|
||||
toSend.insert(toSend.end(), &msg[0], &msg[size]);
|
||||
toSend.push_back(calcChecksum(msg, size));
|
||||
serial_updateStatusRegister();
|
||||
SCIFSerialPort::Instance().updateStatus();
|
||||
}
|
||||
|
||||
u8 calcChecksum(const u8 *data, int size)
|
||||
|
|
|
@ -93,16 +93,22 @@ public:
|
|||
};
|
||||
extern SCIFRegisters scif;
|
||||
|
||||
struct SerialPipe
|
||||
class SCIFSerialPort : public SerialPort
|
||||
{
|
||||
// Serial TX
|
||||
virtual void write(u8 data) { }
|
||||
// RX buffer Size
|
||||
virtual int available() { return 0; }
|
||||
// Serial RX
|
||||
virtual u8 read() { return 0; }
|
||||
public:
|
||||
void setPipe(Pipe *pipe) override {
|
||||
this->pipe = pipe;
|
||||
}
|
||||
void updateStatus() override;
|
||||
|
||||
virtual ~SerialPipe() = default;
|
||||
static u8 readData(u32 addr);
|
||||
static void writeData(u32 addr, u8 data);
|
||||
static u16 readStatus(u32 addr);
|
||||
static void writeStatus(u32 addr, u16 data);
|
||||
static u16 readSCFDR2(u32 addr);
|
||||
|
||||
static SCIFSerialPort& Instance();
|
||||
|
||||
private:
|
||||
Pipe *pipe = nullptr;
|
||||
};
|
||||
void serial_setPipe(SerialPipe *pipe);
|
||||
void serial_updateStatusRegister();
|
||||
|
|
|
@ -20,43 +20,8 @@
|
|||
|
||||
SCIRegisters sci;
|
||||
SCIFRegisters scif;
|
||||
static SerialPipe *serialPipe;
|
||||
|
||||
/*
|
||||
//SCIF SCSMR2 0xFFE80000 0x1FE80000 16 0x0000 0x0000 Held Held Pclk
|
||||
SCSMR2_type SCIF_SCSMR2;
|
||||
|
||||
//SCIF SCBRR2 0xFFE80004 0x1FE80004 8 0xFF 0xFF Held Held Pclk
|
||||
u8 SCIF_SCBRR2;
|
||||
|
||||
//SCIF SCSCR2 0xFFE80008 0x1FE80008 16 0x0000 0x0000 Held Held Pclk
|
||||
SCSCR2_type SCIF_SCSCR2;
|
||||
|
||||
//SCIF SCFTDR2 0xFFE8000C 0x1FE8000C 8 Undefined Undefined Held Held Pclk
|
||||
u8 SCIF_SCFTDR2;
|
||||
|
||||
//SCIF SCFSR2 0xFFE80010 0x1FE80010 16 0x0060 0x0060 Held Held Pclk
|
||||
SCSCR2_type SCIF_SCFSR2;
|
||||
|
||||
//SCIF SCFRDR2 0xFFE80014 0x1FE80014 8 Undefined Undefined Held Held Pclk
|
||||
//Read OLNY
|
||||
u8 SCIF_SCFRDR2;
|
||||
|
||||
//SCIF SCFCR2 0xFFE80018 0x1FE80018 16 0x0000 0x0000 Held Held Pclk
|
||||
SCFCR2_type SCIF_SCFCR2;
|
||||
|
||||
//Read OLNY
|
||||
//SCIF SCFDR2 0xFFE8001C 0x1FE8001C 16 0x0000 0x0000 Held Held Pclk
|
||||
SCFDR2_type SCIF_SCFDR2;
|
||||
|
||||
//SCIF SCSPTR2 0xFFE80020 0x1FE80020 16 0x0000 0x0000 Held Held Pclk
|
||||
SCSPTR2_type SCIF_SCSPTR2;
|
||||
|
||||
//SCIF SCLSR2 0xFFE80024 0x1FE80024 16 0x0000 0x0000 Held Held Pclk
|
||||
SCLSR2_type SCIF_SCLSR2;
|
||||
*/
|
||||
|
||||
static void Serial_UpdateInterrupts()
|
||||
static void updateInterrupts()
|
||||
{
|
||||
InterruptPend(sh4_SCIF_TXI, SCIF_SCFSR2.TDFE);
|
||||
InterruptMask(sh4_SCIF_TXI, SCIF_SCSCR2.TIE);
|
||||
|
@ -65,42 +30,28 @@ static void Serial_UpdateInterrupts()
|
|||
InterruptMask(sh4_SCIF_RXI, SCIF_SCSCR2.RIE);
|
||||
}
|
||||
|
||||
void serial_updateStatusRegister()
|
||||
{
|
||||
if (serialPipe != nullptr)
|
||||
{
|
||||
constexpr int trigLevels[] { 1, 4, 8, 14 };
|
||||
int avail = serialPipe->available();
|
||||
|
||||
if (avail >= trigLevels[SCIF_SCFCR2.RTRG1 * 2 + SCIF_SCFCR2.RTRG0])
|
||||
SCIF_SCFSR2.RDF = 1;
|
||||
if (avail >= 1)
|
||||
SCIF_SCFSR2.DR = 1;
|
||||
Serial_UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
|
||||
// SCIF SCFTDR2
|
||||
static void SerialWrite(u32 addr, u8 data)
|
||||
void SCIFSerialPort::writeData(u32 addr, u8 data)
|
||||
{
|
||||
//DEBUG_LOG(COMMON, "serial %02x", data);
|
||||
if (serialPipe != nullptr)
|
||||
serialPipe->write(data);
|
||||
INFO_LOG(COMMON, "serial out %02x %c", data, data);
|
||||
if (Instance().pipe != nullptr)
|
||||
Instance().pipe->write(data);
|
||||
|
||||
SCIF_SCFSR2.TDFE = 1;
|
||||
SCIF_SCFSR2.TEND = 1;
|
||||
|
||||
Serial_UpdateInterrupts();
|
||||
updateInterrupts();
|
||||
}
|
||||
|
||||
//SCIF_SCFSR2 read
|
||||
static u16 ReadSerialStatus(u32 addr)
|
||||
// SCIF_SCFSR2 read
|
||||
u16 SCIFSerialPort::readStatus(u32 addr)
|
||||
{
|
||||
serial_updateStatusRegister();
|
||||
Instance().updateStatus();
|
||||
return SCIF_SCFSR2.full;
|
||||
}
|
||||
|
||||
static void WriteSerialStatus(u32 addr, u16 data)
|
||||
// SCIF_SCFSR2 write
|
||||
void SCIFSerialPort::writeStatus(u32 addr, u16 data)
|
||||
{
|
||||
if (!SCIF_SCFSR2.BRK)
|
||||
data &= ~0x10;
|
||||
|
@ -110,29 +61,53 @@ static void WriteSerialStatus(u32 addr, u16 data)
|
|||
SCIF_SCFSR2.TDFE = 1;
|
||||
SCIF_SCFSR2.TEND = 1;
|
||||
|
||||
serial_updateStatusRegister();
|
||||
Instance().updateStatus();
|
||||
}
|
||||
|
||||
//SCIF_SCFDR2 - 16b
|
||||
static u16 Read_SCFDR2(u32 addr)
|
||||
u16 SCIFSerialPort::readSCFDR2(u32 addr)
|
||||
{
|
||||
if (serialPipe != nullptr)
|
||||
return std::min(16, serialPipe->available());
|
||||
if (Instance().pipe != nullptr)
|
||||
return std::min(16, Instance().pipe->available());
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
//SCIF_SCFRDR2
|
||||
static u8 ReadSerialData(u32 addr)
|
||||
u8 SCIFSerialPort::readData(u32 addr)
|
||||
{
|
||||
u8 data = 0;
|
||||
if (serialPipe != nullptr)
|
||||
data = serialPipe->read();
|
||||
serial_updateStatusRegister();
|
||||
if (Instance().pipe != nullptr) {
|
||||
data = Instance().pipe->read();
|
||||
//DEBUG_LOG(COMMON, "serial in %02x %c", data, data);
|
||||
}
|
||||
Instance().updateStatus();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void SCIFSerialPort::updateStatus()
|
||||
{
|
||||
if (pipe == nullptr)
|
||||
return;
|
||||
|
||||
constexpr int trigLevels[] { 1, 4, 8, 14 };
|
||||
int avail = pipe->available();
|
||||
|
||||
if (avail >= trigLevels[SCIF_SCFCR2.RTRG1 * 2 + SCIF_SCFCR2.RTRG0])
|
||||
SCIF_SCFSR2.RDF = 1;
|
||||
if (avail >= 1)
|
||||
SCIF_SCFSR2.DR = 1;
|
||||
updateInterrupts();
|
||||
}
|
||||
|
||||
SCIFSerialPort& SCIFSerialPort::Instance()
|
||||
{
|
||||
static SCIFSerialPort instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
//SCSCR2
|
||||
|
||||
static u16 SCSCR2_read(u32 addr)
|
||||
|
@ -144,10 +119,10 @@ static void SCSCR2_write(u32 addr, u16 data)
|
|||
{
|
||||
SCIF_SCSCR2.full = data & 0x00fa;
|
||||
|
||||
Serial_UpdateInterrupts();
|
||||
updateInterrupts();
|
||||
}
|
||||
|
||||
struct PTYPipe : public SerialPipe
|
||||
struct PTYPipe : public SerialPort::Pipe
|
||||
{
|
||||
void write(u8 data) override {
|
||||
if (config::SerialConsole)
|
||||
|
@ -204,7 +179,7 @@ struct PTYPipe : public SerialPipe
|
|||
}
|
||||
#endif
|
||||
}
|
||||
serial_setPipe(this);
|
||||
SCIFSerialPort::Instance().setPipe(this);
|
||||
}
|
||||
|
||||
void term()
|
||||
|
@ -238,21 +213,21 @@ void SCIFRegisters::init()
|
|||
setHandlers<SCIF_SCSCR2_addr>(SCSCR2_read, SCSCR2_write);
|
||||
|
||||
//SCIF SCFTDR2 0xFFE8000C 0x1FE8000C 8 Undefined Undefined Held Held Pclk
|
||||
setWriteOnly<SCIF_SCFTDR2_addr>(SerialWrite);
|
||||
setWriteOnly<SCIF_SCFTDR2_addr>(SCIFSerialPort::writeData);
|
||||
|
||||
//SCIF SCFSR2 0xFFE80010 0x1FE80010 16 0x0060 0x0060 Held Held Pclk
|
||||
setHandlers<SCIF_SCFSR2_addr>(ReadSerialStatus, WriteSerialStatus);
|
||||
setHandlers<SCIF_SCFSR2_addr>(SCIFSerialPort::readStatus, SCIFSerialPort::writeStatus);
|
||||
|
||||
//READ only
|
||||
//SCIF SCFRDR2 0xFFE80014 0x1FE80014 8 Undefined Undefined Held Held Pclk
|
||||
setReadOnly<SCIF_SCFRDR2_addr>(ReadSerialData);
|
||||
setReadOnly<SCIF_SCFRDR2_addr>(SCIFSerialPort::readData);
|
||||
|
||||
//SCIF SCFCR2 0xFFE80018 0x1FE80018 16 0x0000 0x0000 Held Held Pclk
|
||||
setRW<SCIF_SCFCR2_addr, u16, 0x00ff>();
|
||||
|
||||
//Read only
|
||||
//SCIF SCFDR2 0xFFE8001C 0x1FE8001C 16 0x0000 0x0000 Held Held Pclk
|
||||
setReadOnly<SCIF_SCFDR2_addr>(Read_SCFDR2);
|
||||
setReadOnly<SCIF_SCFDR2_addr>(SCIFSerialPort::readSCFDR2);
|
||||
|
||||
//SCIF SCSPTR2 0xFFE80020 0x1FE80020 16 0x0000 0x0000 Held Held Pclk
|
||||
setRW<SCIF_SCSPTR2_addr, u16, 0x00f3>();
|
||||
|
@ -316,8 +291,3 @@ void SCIFRegisters::term()
|
|||
super::term();
|
||||
ptyPipe.term();
|
||||
}
|
||||
|
||||
void serial_setPipe(SerialPipe *pipe)
|
||||
{
|
||||
serialPipe = pipe;
|
||||
}
|
||||
|
|
|
@ -25,17 +25,17 @@
|
|||
#include <deque>
|
||||
#include <memory>
|
||||
|
||||
struct ModemEmu : public SerialPipe
|
||||
struct ModemEmu : public SerialPort::Pipe
|
||||
{
|
||||
ModemEmu() {
|
||||
serial_setPipe(this);
|
||||
SCIFSerialPort::Instance().setPipe(this);
|
||||
schedId = sh4_sched_register(0, schedCallback);
|
||||
}
|
||||
|
||||
~ModemEmu() {
|
||||
sh4_sched_unregister(schedId);
|
||||
stop_pico();
|
||||
serial_setPipe(nullptr);
|
||||
SCIFSerialPort::Instance().setPipe(nullptr);
|
||||
}
|
||||
|
||||
u8 read() override
|
||||
|
@ -132,12 +132,12 @@ private:
|
|||
{
|
||||
toSend.insert(toSend.end(), l.begin(), l.end());
|
||||
toSend.push_back('\n');
|
||||
serial_updateStatusRegister();
|
||||
SCIFSerialPort::Instance().updateStatus();
|
||||
}
|
||||
|
||||
static int schedCallback(int tag, int cycles, int lag, void *arg)
|
||||
{
|
||||
serial_updateStatusRegister();
|
||||
SCIFSerialPort::Instance().updateStatus();
|
||||
return SH4_MAIN_CLOCK / 60;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "hw/naomi/naomi_flashrom.h"
|
||||
#include <deque>
|
||||
|
||||
struct MaxSpeedNetPipe : public SerialPipe
|
||||
struct MaxSpeedNetPipe : public SerialPort::Pipe
|
||||
{
|
||||
class Exception : public FlycastException
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ private:
|
|||
else
|
||||
enableNetworkBroadcast(true);
|
||||
|
||||
serial_setPipe(this);
|
||||
SCIFSerialPort::Instance().setPipe(this);
|
||||
}
|
||||
|
||||
sock_t sock = INVALID_SOCKET;
|
||||
|
|
Loading…
Reference in New Issue