cdrom: delayed interrupts

This commit is contained in:
Jakub Czekański 2021-01-31 03:23:09 +01:00
parent 34a0f6560d
commit 4d309c90e9
3 changed files with 82 additions and 39 deletions

View file

@ -48,14 +48,14 @@ void CDROM::handleSector() {
auto posInTrack = pos - disc->getTrackStart(track);
postInterrupt(1);
writeResponse(stat._reg); // stat
writeResponse(bcd::toBcd(track)); // track
writeResponse(0x01); // index
writeResponse(stat._reg); // stat
writeResponse(bcd::toBcd(track)); // track
writeResponse(0x01); // index
writeResponse(bcd::toBcd(posInTrack.mm)); // minute (disc) <<< invalid
writeResponse(bcd::toBcd(posInTrack.ss) | 0x80); // second (disc) <<< invalid
writeResponse(bcd::toBcd(posInTrack.ff)); // sector (disc)
writeResponse(bcd::toBcd(0)); // peaklo
writeResponse(bcd::toBcd(0)); // peakhi
writeResponse(bcd::toBcd(0)); // peaklo
writeResponse(bcd::toBcd(0)); // peakhi
if (verbose) {
fmt::print("CDROM:CDDA report -> ({})\n", dumpFifo(interruptQueue.peek().response));
@ -135,21 +135,25 @@ void CDROM::handleSector() {
}
void CDROM::step(int cycles) {
static int intCycles = 0;
readcnt += cycles;
intCycles += cycles;
busyFor -= cycles;
if (!interruptQueue.is_empty()) {
interruptQueue.ref().delay -= cycles;
if (interruptQueue.peek().delay <= 0) {
status.transmissionBusy = 0;
if (intCycles >= 300) {
intCycles -= 300;
status.transmissionBusy = 0;
if (!interruptQueue.is_empty()) {
if ((interruptEnable & 7) & (interruptQueue.peek().irq & 7)) {
sys->interrupt->trigger(interrupt::CDROM);
}
}
}
if (busyFor < 0) {
status.transmissionBusy = 0;
}
const int sectorsPerSecond = mode.speed ? 150 : 75;
const int cyclesPerSector = timing::CPU_CLOCK / sectorsPerSecond;
for (int i = 0; i < readcnt / cyclesPerSector; i++) {
@ -210,7 +214,9 @@ uint8_t CDROM::read(uint32_t address) {
if (status.index == 1 || status.index == 3) { // Interrupt flags
uint8_t _status = 0b11100000;
if (!interruptQueue.is_empty()) {
_status |= interruptQueue.peek().irq & 7;
if (interruptQueue.peek().delay <= 0) {
_status |= interruptQueue.peek().irq & 7;
}
}
if (verbose == 2) fmt::print("CDROM: R INTF: 0x{:02x}\n", _status);
return _status;
@ -315,6 +321,7 @@ void CDROM::handleCommand(uint8_t cmd) {
break;
}
busyFor = 1000;
CDROM_params.clear();
status.transmissionBusy = 1;
status.xaFifoEmpty = 0;

View file

@ -41,7 +41,7 @@ class CDROM {
void setShell(bool opened) {
shellOpen = opened;
setMode(Mode::None);
setMode(Mode::None);
if (opened) {
motor = false;
}
@ -100,10 +100,11 @@ class CDROM {
uint8_t irq;
fifo<uint8_t, 16> response;
bool ack;
int delay;
template <class Archive>
void serialize(Archive& ar) {
ar(irq, response, ack);
ar(irq, response, ack, delay);
}
};
@ -165,7 +166,15 @@ class CDROM {
return param;
}
void postInterrupt(int irq) { interruptQueue.add(irq_response_t{.irq = (uint8_t)irq, .response = {}}); }
int busyFor = 0;
void postInterrupt(int irq, int delay = 50000) {
interruptQueue.add(irq_response_t{
.irq = (uint8_t)irq, //
.response = {}, //
.delay = delay //
});
}
std::string dumpFifo(const FIFO& f);
std::pair<int16_t, int16_t> mixSample(std::pair<int16_t, int16_t> sample);
@ -193,10 +202,20 @@ class CDROM {
uint8_t read(uint32_t address);
void write(uint32_t address, uint8_t data);
void setShell(bool opened) { stat.setShell(opened); }
void setShell(bool opened) {
stat.setShell(opened);
if (opened) {
if (disc) {
postInterrupt(0x05, 1000);
writeResponse(0x16);
writeResponse(0x08);
}
}
}
bool getShell() const { return stat.getShell(); }
void ackMoreData() {
postInterrupt(1);
postInterrupt(1, 0);
writeResponse(stat._reg);
}

View file

@ -17,11 +17,17 @@ void CDROM::cmdSetloc() {
uint8_t sector = bcd::toBinary(readParam());
seekSector = sector + (second * 75) + (minute * 60 * 75);
postInterrupt(3);
writeResponse(stat._reg);
if (verbose) fmt::print("CDROM: cmdSetloc(min = {}, sec = {}, sect = {})\n", minute, second, sector);
if (!discPresent()) {
postInterrupt(5);
writeResponse(0x11);
writeResponse(0x80);
return;
}
postInterrupt(3, 2000);
writeResponse(stat._reg);
}
void CDROM::cmdPlay() {
@ -29,7 +35,7 @@ void CDROM::cmdPlay() {
disc::Position pos;
if (!CDROM_params.is_empty()) {
int track = readParam(); // param or setloc used
if (track >= (int)disc->getTrackCount()) {
if (track > (int)disc->getTrackCount()) {
fmt::print("CDROM: Invalid PLAY track parameter ({})\n", track);
return;
}
@ -50,14 +56,20 @@ void CDROM::cmdPlay() {
}
void CDROM::cmdReadN() {
readSector = seekSector;
if (verbose) fmt::print("CDROM: cmdReadN\n");
if (!discPresent()) {
postInterrupt(5);
writeResponse(0x11);
writeResponse(0x80);
return;
}
readSector = seekSector;
stat.setMode(StatusCode::Mode::Reading);
postInterrupt(3);
postInterrupt(3, 5000);
writeResponse(stat._reg);
if (verbose) fmt::print("CDROM: cmdReadN\n");
}
void CDROM::cmdMotorOn() {
@ -98,7 +110,7 @@ void CDROM::cmdPause() {
}
void CDROM::cmdInit() {
postInterrupt(3);
postInterrupt(3, 0x13ce);
writeResponse(stat._reg);
stat.motor = 1;
@ -142,7 +154,7 @@ void CDROM::cmdSetmode() {
mode._reg = setmode;
postInterrupt(3);
postInterrupt(3, 2000);
writeResponse(stat._reg);
if (verbose) fmt::print("CDROM: cmdSetmode(0x{:02x})\n", setmode);
@ -177,9 +189,7 @@ void CDROM::cmdSeekP() {
postInterrupt(3);
writeResponse(stat._reg);
stat.setMode(StatusCode::Mode::Seeking);
postInterrupt(2);
postInterrupt(2, 500000);
writeResponse(stat._reg);
stat.setMode(StatusCode::Mode::None);
@ -222,7 +232,7 @@ void CDROM::cmdGetlocL() {
}
void CDROM::cmdGetlocP() {
postInterrupt(3);
postInterrupt(3, 1000);
writeResponse(lastQ.data[0]); // track
writeResponse(lastQ.data[1]); // index
writeResponse(lastQ.data[2]); // minute (track)
@ -284,17 +294,24 @@ void CDROM::cmdGetTD() {
}
void CDROM::cmdSeekL() {
if (verbose) fmt::print("CDROM: cmdSeekL\n");
readSector = seekSector;
postInterrupt(3);
if (!discPresent()) {
postInterrupt(5);
writeResponse(0x11);
writeResponse(0x80);
return;
}
postInterrupt(3, 5000);
writeResponse(stat._reg);
stat.setMode(StatusCode::Mode::Seeking);
postInterrupt(2);
postInterrupt(2, 500000);
writeResponse(stat._reg);
if (verbose) fmt::print("CDROM: cmdSeekL\n");
stat.setMode(StatusCode::Mode::None);
}
void CDROM::cmdTest() {
@ -396,7 +413,7 @@ void CDROM::cmdReadS() {
audio.clear();
stat.setMode(StatusCode::Mode::Reading);
postInterrupt(3);
postInterrupt(3, 500);
writeResponse(stat._reg);
if (verbose) fmt::print("CDROM: cmdReadS\n");