serial: fix RDF and TDFE status bits

RDF and TDFE can't be reset if tx/rx fifo is below/above trigger
Remove rx overrun check
Proper reset of scif state
Fixes maxspeed, vonot and hell gate battle cable.
Tetris connects but still has input responsiveness issues.

sh4 mmr: use unnamed bitfields
This commit is contained in:
Flyinghead 2023-11-25 17:06:45 +01:00
parent a18e3701c6
commit cb518b5481
3 changed files with 122 additions and 175 deletions

View File

@ -107,6 +107,7 @@ public:
void receiveBreak() override;
void init();
void term();
void reset();
void serialize(Serializer& ser);
void deserialize(Deserializer& deser);
@ -120,11 +121,25 @@ public:
void SCSPTR2_write(u16 data);
static void SCBRR2_write(u32 addr, u8 data);
static void SCSMR2_write(u32 addr, u16 data);
static void SCSCR2_write(u32 addr, u16 data);
void SCSCR2_write(u16 data);
static SCIFSerialPort& Instance();
private:
enum StatusBit {
DR = 0x01,
RDF = 0x02,
PER = 0x04,
FER = 0x08,
BRK = 0x10,
TDFE = 0x20,
TEND = 0x40,
ER = 0x80,
};
void setStatusBit(StatusBit bit);
bool isTDFE() const;
bool isRDF() const;
void updateBaudRate();
void setBreak(bool on);
void sendBreak();

View File

@ -64,15 +64,22 @@ int SCIFSerialPort::schedCallback(int tag, int cycles, int lag, void *arg)
}
}
bool SCIFSerialPort::isTDFE() const {
return (int)txFifo.size() <= 1 << (3 - SCIF_SCFCR2.TTRG);
}
bool SCIFSerialPort::isRDF() const {
constexpr u32 trigLevels[] { 1, 4, 8, 14 };
return rxFifo.size() >= trigLevels[SCIF_SCFCR2.RTRG];
}
bool SCIFSerialPort::txDone()
{
if (!transmitting || SCIF_SCFCR2.TFRST == 1)
return false;
if (txFifo.empty())
{
SCIF_SCFSR2.TEND = 1;
SCIF_SCFSR2.TDFE = 1; // should not be set since the tx fifo hasn't changed but vonot needs it
updateInterrupts();
setStatusBit(TEND);
transmitting = false;
return false; // don't reschedule
}
@ -80,9 +87,8 @@ bool SCIFSerialPort::txDone()
txFifo.pop_front();
if (pipe != nullptr)
pipe->write(v);
u32 txTrigger = 1 << (3 - SCIF_SCFCR2.TTRG);
if (txFifo.size() <= txTrigger) {
SCIF_SCFSR2.TDFE = 1;
if (isTDFE()) {
setStatusBit(TDFE);
updateInterrupts();
}
return true;
@ -92,13 +98,6 @@ void SCIFSerialPort::rxSched()
{
if (pipe == nullptr)
return;
// FIXME fifo size checked to avoid overruns but incorrect
if (rxFifo.size() >= 16)
{
SCIF_SCFSR2.RDF = 1;
updateInterrupts();
return;
}
if (pipe->available() > 0)
{
@ -115,9 +114,8 @@ void SCIFSerialPort::rxSched()
else
{
rxFifo.push_back(v);
constexpr u32 trigLevels[] { 1, 4, 8, 14 };
if (rxFifo.size() >= trigLevels[SCIF_SCFCR2.RTRG]) {
SCIF_SCFSR2.RDF = 1;
if (isRDF()) {
setStatusBit(RDF);
updateInterrupts();
}
}
@ -125,7 +123,7 @@ void SCIFSerialPort::rxSched()
// TODO fifo might have been emptied since last rx
else if (!rxFifo.empty())
{
SCIF_SCFSR2.DR = 1;
setStatusBit(DR);
updateInterrupts();
}
}
@ -154,9 +152,9 @@ void SCIFSerialPort::SCFTDR2_write(u8 data)
if (pipe != nullptr)
pipe->write(data);
transmitting = true;
// Need to reschedule so it's doesn't happen too early (f355)
// Need to reschedule so it doesn't happen too early (f355)
sh4_sched_request(schedId, frameSize * cyclesPerBit);
SCIF_SCFSR2.TDFE = 1; // immediately transfer SCFTDR2 into the shift register
setStatusBit(TDFE); // immediately transfer SCFTDR2 into the shift register
updateInterrupts();
}
else if (txFifo.size() < 16) {
@ -180,19 +178,30 @@ u16 SCIFSerialPort::readStatus()
return SCIF_SCFSR2.full;
}
void SCIFSerialPort::setStatusBit(StatusBit bit)
{
statusLastRead &= ~bit;
SCIF_SCFSR2.full |= bit;
}
// SCIF_SCFSR2 write - Serial Status Register
void SCIFSerialPort::writeStatus(u16 data)
{
data = data | ~0x00f3 | ~statusLastRead;
// RDF and TDFE cannot be reset until the trigger level is reached
if (isRDF())
data |= RDF;
if (isTDFE())
data |= TDFE;
SCIF_LOG("SCIF_SCFSR2.reset %s%s%s%s%s%s%s%s",
(data & 0x80) ? "" : "ER ",
(data & 0x40) ? "" : "TEND ",
(data & 0x20) ? "" : "TDFE ",
(data & 0x10) ? "" : "BRK ",
(data & 0x08) ? "" : "FER ",
(data & 0x04) ? "" : "PER ",
(data & 0x02) ? "" : "RDF ",
(data & 0x01) ? "" : "DR");
(data & ER) ? "" : "ER ",
(data & TEND) ? "" : "TEND ",
(data & TDFE) ? "" : "TDFE ",
(data & BRK) ? "" : "BRK ",
(data & FER) ? "" : "FER ",
(data & PER) ? "" : "PER ",
(data & RDF) ? "" : "RDF ",
(data & DR) ? "" : "DR");
SCIF_SCFSR2.full &= data;
statusLastRead &= data;
@ -235,18 +244,17 @@ static u16 SCSCR2_read(u32 addr)
return SCIF_SCSCR2.full;
}
void SCIFSerialPort::SCSCR2_write(u32 addr, u16 data)
void SCIFSerialPort::SCSCR2_write(u16 data)
{
SCIF_SCSCR2.full = data & 0x00fa;
if (SCIF_SCSCR2.TE == 0)
{
SCIF_SCFSR2.TEND = 1;
//SCIF_SCFSR2.TDFE = 1; // TODO not sure about this one
setStatusBit(TEND);
// TE must be cleared to send a break
Instance().setBreak(SCIF_SCSPTR2.SPB2IO == 1 && SCIF_SCSPTR2.SPB2DT == 0);
setBreak(SCIF_SCSPTR2.SPB2IO == 1 && SCIF_SCSPTR2.SPB2DT == 0);
}
else {
Instance().setBreak(false);
setBreak(false);
}
updateInterrupts();
SCIF_LOG("SCIF_SCSCR2= %s%s%s%s%s",
@ -307,8 +315,8 @@ void SCIFSerialPort::SCFCR2_write(u16 data)
{
// when TFRST 1 -> 0
// seems to help tetris send data during sync
SCIF_SCFSR2.TEND = 1;
SCIF_SCFSR2.TDFE = 1;
setStatusBit(TEND);
setStatusBit(TDFE);
updateInterrupts();
}
SCIF_SCFCR2.full = data & 0x00ff;
@ -346,7 +354,7 @@ void SCIFSerialPort::SCSMR2_write(u32 addr, u16 data)
void SCIFSerialPort::receiveBreak()
{
SCIF_LOG("Break received");
SCIF_SCFSR2.BRK = 1;
setStatusBit(BRK);
updateInterrupts();
}
@ -377,6 +385,16 @@ void SCIFSerialPort::term()
}
}
void SCIFSerialPort::reset()
{
sh4_sched_request(brkSchedId, -1);
transmitting = false;
statusLastRead = 0;
txFifo.clear();
rxFifo.clear();
updateBaudRate();
}
void SCIFSerialPort::serialize(Serializer& ser)
{
sh4_sched_serialize(ser, schedId);
@ -553,7 +571,7 @@ void SCIFRegisters::init()
setWriteHandler<SCIF_SCBRR2_addr, u8>(SCIFSerialPort::SCBRR2_write);
//SCIF SCSCR2 0xFFE80008 0x1FE80008 16 0x0000 0x0000 Held Held Pclk
setHandlers<SCIF_SCSCR2_addr>(SCSCR2_read, SCIFSerialPort::SCSCR2_write);
setHandlers<SCIF_SCSCR2_addr>(SCSCR2_read, SINGLETON_FORWARD(SCIFSerialPort::Instance(), SCSCR2_write));
//SCIF SCFTDR2 0xFFE8000C 0x1FE8000C 8 Undefined Undefined Held Held Pclk
setWriteOnly<SCIF_SCFTDR2_addr>(SINGLETON_FORWARD(SCIFSerialPort::Instance(), SCFTDR2_write));
@ -605,6 +623,7 @@ void SCIFRegisters::reset(bool hard)
if (hard)
SCIFSerialPort::Instance().setPipe(nullptr);
SCIFSerialPort::Instance().reset();
}
void SCIFRegisters::term()

View File

@ -435,7 +435,7 @@ union BSC_BCR1_type
struct
{
u32 A56PCM : 1;
u32 res_0 : 1;
u32 : 1;
u32 DRAMTP0 : 1;
u32 DRAMTP1 : 1;
u32 DRAMTP2 : 1;
@ -452,20 +452,17 @@ union BSC_BCR1_type
u32 HIZCNT : 1;
u32 HIZMEM : 1;
//16
u32 res_1 : 1;
u32 : 1;
u32 MEMMPX : 1;
u32 PSHR : 1;
u32 BREQEN : 1;
u32 A4MBC : 1;
u32 A1MBC : 1;
u32 res_2 : 1;
u32 res_3 : 1;
u32 : 2;
//24
u32 OPUP : 1;
u32 IPUP : 1;
u32 res_4 : 1;
u32 res_5 : 1;
u32 res_6 : 1;
u32 : 3;
u32 A0MPX : 1; // Set to 1 (area 0 is mpx)
u32 MASTER : 1; // What is it on the Dreamcast ?
u32 ENDIAN : 1; // This is 1 on the Dreamcast
@ -483,7 +480,7 @@ union BSC_BCR2_type
struct
{
u32 PORTEN : 1;
u32 res_0 : 1;
u32 : 1;
u32 A0SZ0 : 1;
u32 A1SZ1 : 1;
u32 A2SZ0 : 1;
@ -514,38 +511,38 @@ union BSC_WCR1_type
u32 A0IW0 : 1;
u32 A0IW1 : 1;
u32 A0IW2 : 1;
u32 res_0 : 1;
u32 : 1;
u32 A1IW0 : 1;
u32 A1IW1 : 1;
u32 A1IW2 : 1;
u32 res_1 : 1;
u32 : 1;
//8
u32 A2IW0 : 1;
u32 A2IW1 : 1;
u32 A2IW2 : 1;
u32 res_2 : 1;
u32 : 1;
u32 A3IW0 : 1;
u32 A3IW1 : 1;
u32 A3IW2 : 1;
u32 res_3 : 1;
u32 : 1;
//16
u32 A4IW0 : 1;
u32 A4IW1 : 1;
u32 A4IW2 : 1;
u32 res_4 : 1;
u32 : 1;
u32 A5IW0 : 1;
u32 A5IW1 : 1;
u32 A5IW2 : 1;
u32 res_5 : 1;
u32 : 1;
//24
u32 A6IW0 : 1;
u32 A6IW1 : 1;
u32 A6IW2 : 1;
u32 res_6 : 1;
u32 : 1;
u32 DMAIW0 : 1;
u32 DMAIW1 : 1;
u32 DMAIW2 : 1;
u32 res_7 : 1;
u32 : 1;
};
u32 full;
@ -570,12 +567,12 @@ union BSC_WCR2_type
u32 A2W0 : 1;
u32 A2W1 : 1;
u32 A2W2 : 1;
u32 res_0 : 1;
u32 : 1;
u32 A3W0 : 1;
u32 A3W1 : 1;
u32 A3W2 : 1;
//16
u32 res_1 : 1;
u32 : 1;
u32 A4W0 : 1;
u32 A4W1 : 1;
u32 A4W2 : 1;
@ -607,38 +604,34 @@ union BSC_WCR3_type
u32 A0H0 : 1;
u32 A0H1 : 1;
u32 A0S0 : 1;
u32 res_0 : 1;
u32 : 1;
u32 A1H0 : 1; //TODO: check if this is correct, on the manual it says A1H0 .. typo in the manual ?
u32 A1H1 : 1;
u32 A1S0 : 1;
u32 res_1 : 1;
u32 : 1;
//8
u32 A2H0 : 1;
u32 A2H1 : 1;
u32 A2S0 : 1;
u32 res_2 : 1;
u32 : 1;
u32 A3H0 : 1;
u32 A3H1 : 1;
u32 A3S0 : 1;
u32 res_3 : 1;
u32 : 1;
//16
u32 A4H0 : 1;
u32 A4H1 : 1;
u32 A4S0 : 1;
u32 res_4 : 1;
u32 : 1;
u32 A5H0 : 1;
u32 A5H1 : 1;
u32 A5S0 : 1;
u32 res_5 : 1;
u32 : 1;
//24
u32 A6H0 : 1;
u32 A6H1 : 1;
u32 A6S0 : 1;
u32 res_6 : 1;
u32 res_7 : 1;
u32 res_8 : 1;
u32 res_9 : 1;
u32 res_10 : 1;
u32 : 5;
};
u32 full;
@ -672,16 +665,14 @@ union BSC_MCR_type
//16
u32 RCD0 : 1;
u32 RCD1 : 1;
u32 res_0 : 1;
u32 : 1;
u32 TPC0 : 1;
u32 TPC1 : 1;
u32 TPC2 : 1;
u32 res_1 : 1;
u32 : 1;
u32 TCAS : 1;
//24
u32 res_2 : 1;
u32 res_3 : 1;
u32 res_4 : 1;
u32 : 3;
u32 TRC0 : 1;
u32 TRC1 : 1;
u32 TRC2 : 1;
@ -738,14 +729,7 @@ union BSC_RTCSR_type
u32 CMIE : 1;
u32 CMF : 1;
//8
u32 res_0 : 1;
u32 res_1 : 1;
u32 res_2 : 1;
u32 res_3 : 1;
u32 res_4 : 1;
u32 res_5 : 1;
u32 res_6 : 1;
u32 res_7 : 1;
u32 : 8;
//16
};
u16 full;
@ -760,14 +744,7 @@ union BSC_RTCNT_type
{
u32 VALUE : 8;
//8
u32 res_0 : 1;
u32 res_1 : 1;
u32 res_2 : 1;
u32 res_3 : 1;
u32 res_4 : 1;
u32 res_5 : 1;
u32 res_6 : 1;
u32 res_7 : 1;
u32 : 8;
//16
};
u16 full;
@ -782,14 +759,7 @@ union BSC_RTCOR_type
{
u32 VALUE : 8;
//8
u32 res_0 : 1;
u32 res_1 : 1;
u32 res_2 : 1;
u32 res_3 : 1;
u32 res_4 : 1;
u32 res_5 : 1;
u32 res_6 : 1;
u32 res_7 : 1;
u32 : 8;
//16
};
u16 full;
@ -804,13 +774,7 @@ union BSC_RFCR_type
struct
{
u32 VALUE : 10;
//10
u32 res_2 : 1;
u32 res_3 : 1;
u32 res_4 : 1;
u32 res_5 : 1;
u32 res_6 : 1;
u32 res_7 : 1;
u32 : 6;
//16
};
u16 full;
@ -908,32 +872,7 @@ union BSC_PCTRB_type
u32 PB19IO : 1;
u32 PB19PUP : 1;
//8
u32 res_0 : 1;
u32 res_1 : 1;
u32 res_2 : 1;
u32 res_3 : 1;
u32 res_4 : 1;
u32 res_5 : 1;
u32 res_6 : 1;
u32 res_7 : 1;
//16
u32 res_8 : 1;
u32 res_9 : 1;
u32 res_10 : 1;
u32 res_11 : 1;
u32 res_12 : 1;
u32 res_13 : 1;
u32 res_14 : 1;
u32 res_15 : 1;
//24
u32 res_16 : 1;
u32 res_17 : 1;
u32 res_18 : 1;
u32 res_19 : 1;
u32 res_20 : 1;
u32 res_21 : 1;
u32 res_22 : 1;
u32 res_23 : 1;
u32 :24;
};
u32 full;
@ -950,19 +889,7 @@ union BSC_PDTRB_type
u32 PB17DT : 1;
u32 PB18DT : 1;
u32 PB19DT : 1;
u32 res_0 : 1;
u32 res_1 : 1;
u32 res_2 : 1;
u32 res_3 : 1;
//8
u32 res_4 : 1;
u32 res_5 : 1;
u32 res_6 : 1;
u32 res_7 : 1;
u32 res_8 : 1;
u32 res_9 : 1;
u32 res_10 : 1;
u32 res_11 : 1;
u32 :12;
//16
};
u16 full;
@ -1006,7 +933,7 @@ union CCN_PTEH_type
struct
{
u32 ASID : 8; //0-7 ASID
u32 res : 2; //8,9 reserved
u32 : 2;
u32 VPN : 22; //10-31 VPN
};
u32 reg_data;
@ -1026,9 +953,9 @@ union CCN_PTEL_type
u32 SZ1 : 1;
u32 V : 1;
u32 res_0 : 1;
u32 : 1;
u32 PPN : 19; //PPN 10-28
u32 res_1 : 3;
u32 : 3;
};
u32 reg_data;
};
@ -1058,7 +985,7 @@ union CCN_PTEA_type
{
u32 SA : 3;
u32 TC : 1;
u32 res : 28;
u32 : 28;
};
u32 reg_data;
};
@ -1071,16 +998,16 @@ union CCN_CCR_type
u32 WT : 1;
u32 CB : 1;
u32 OCI : 1;
u32 res : 1;
u32 : 1;
u32 ORA : 1;
u32 res_1 : 1;
u32 : 1;
u32 OIX : 1;
u32 ICE : 1;
u32 res_2 : 2;
u32 : 2;
u32 ICI : 1;
u32 res_3 : 3;
u32 : 3;
u32 IIX : 1;
u32 res_4 : 16;
u32 : 16;
};
u32 reg_data;
};
@ -1089,9 +1016,9 @@ union CCN_QACR_type
{
struct
{
u32 res : 2;
u32 : 2;
u32 Area : 3;
u32 res_1 : 27;
u32 : 27;
};
u32 reg_data;
};
@ -1129,39 +1056,28 @@ union DMAC_CHCR_type
u32 DE : 1; //Channel Enable
u32 TE : 1; //Transfer End
u32 IE : 1; //Interrupt Enable
u32 res0 : 1;
u32 : 1;
u32 TS : 3; //Transmit Size
//u32 TS1 :1;
//u32 TS2 :1;
u32 TM : 1; //Transmit Mode
u32 RS : 4; //Resource Select
//u32 RS1 :1;
//u32 RS2 :1;
//u32 RS3 :1;
u32 SM : 2; //SRC mode
//u32 SM1 :1;
u32 DM : 2; //DST mode
//u32 DM1 :1;
u32 AL : 1; //Acknowledge Level
u32 AM : 1; //Acknowledge Mode
u32 RL : 1; //In normal DMA mode, this bit is valid only in CHCR0 and CHCR1. In DDT mode, this bit is invalid.
u32 DS : 1; //In normal DMA mode, this bit is valid only in CHCR0 and CHCR1. In DDT mode, it is valid in CHCR0<52>CHCR3.
u32 res1 : 4;
u32 : 4;
u32 DTC : 1;
u32 DSA : 3;
//u32 DSA1:1;
//u32 DSA2:1;
u32 STC : 1;
u32 SSA : 3;
//u32 SSA1:1;
//u32 SSA2:1;
};
u32 full;
};
@ -1173,19 +1089,16 @@ union DMAC_DMAOR_type
u32 DME : 1;
u32 NMIF : 1;
u32 AE : 1;
u32 res0 : 1;
u32 : 1;
u32 COD : 1;
u32 res1 : 3;
u32 : 3;
u32 PR0 : 1;
u32 PR1 : 1;
u32 res2 : 2;
u32 res3 : 3;
u32 : 5;
u32 DDT : 1;
u32 res4 : 16;
u32 : 16;
};
u32 full;
};
@ -1393,11 +1306,11 @@ union INTC_ICR_type
u16 reg_data;
struct
{
u32 res : 7;
u32 : 7;
u32 IRLM : 1;
u32 NMIE : 1;
u32 NMIB : 1;
u32 res_2 : 4;
u32 : 4;
u32 MAI : 1;
u32 NMIL : 1;
};
@ -1420,7 +1333,7 @@ union INTC_IPRB_type
u16 reg_data;
struct
{
u32 Reserved : 4;
u32 : 4;
u32 SCI1 : 4;
u32 REF : 4;
u32 WDT : 4;