diff --git a/core/hw/sh4/modules/modules.h b/core/hw/sh4/modules/modules.h index d7dfed99a..57244e24e 100644 --- a/core/hw/sh4/modules/modules.h +++ b/core/hw/sh4/modules/modules.h @@ -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(); diff --git a/core/hw/sh4/modules/serial.cpp b/core/hw/sh4/modules/serial.cpp index 26c11fdd8..4140b7326 100644 --- a/core/hw/sh4/modules/serial.cpp +++ b/core/hw/sh4/modules/serial.cpp @@ -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(SCIFSerialPort::SCBRR2_write); //SCIF SCSCR2 0xFFE80008 0x1FE80008 16 0x0000 0x0000 Held Held Pclk - setHandlers(SCSCR2_read, SCIFSerialPort::SCSCR2_write); + setHandlers(SCSCR2_read, SINGLETON_FORWARD(SCIFSerialPort::Instance(), SCSCR2_write)); //SCIF SCFTDR2 0xFFE8000C 0x1FE8000C 8 Undefined Undefined Held Held Pclk setWriteOnly(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() diff --git a/core/hw/sh4/sh4_mmr.h b/core/hw/sh4/sh4_mmr.h index 19cd688c9..cf9d782e7 100644 --- a/core/hw/sh4/sh4_mmr.h +++ b/core/hw/sh4/sh4_mmr.h @@ -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�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;