cdrom: fixed interrupt/response queue

This commit is contained in:
Jakub Czekański 2021-01-02 16:59:22 +01:00
parent 1cdf1b349f
commit ff674d52db
3 changed files with 74 additions and 48 deletions

View file

@ -19,7 +19,7 @@ CDROM::CDROM(System* sys) : sys(sys) {
void CDROM::step() {
status.transmissionBusy = 0;
if (!interruptQueue.is_empty()) {
if ((interruptEnable & 7) & (interruptQueue.peek() & 7)) {
if ((interruptEnable & 7) & (interruptQueue.peek().irq & 7)) {
sys->interrupt->trigger(interrupt::CDROM);
}
}
@ -67,7 +67,7 @@ void CDROM::step() {
writeResponse(bcd::toBcd(0)); // peakhi
if (verbose) {
fmt::print("CDROM: CDDA report -> ({})\n", dumpFifo(CDROM_response));
fmt::print("CDROM:CDDA report -> ({})\n", dumpFifo(interruptQueue.peek().response));
}
}
@ -144,23 +144,44 @@ void CDROM::step() {
}
}
void CDROM::writeResponse(uint8_t byte) {
if (interruptQueue.is_empty()) {
fmt::print("CDROM: Fatal: Trying to write response to empty interruptQueue\n");
return;
}
auto& entry = interruptQueue.ref(interruptQueue.size() - 1);
if (entry.response.is_full()) {
return;
}
entry.response.add(byte);
}
uint8_t CDROM::read(uint32_t address) {
if (address == 0) { // CD Status
// status.transmissionBusy = !interruptQueue.empty();
if (verbose == 2) fmt::print("CDROM: R STATUS: 0x{:02x}\n", status._reg);
bool responseFifoEmpty = interruptQueue.is_empty() || interruptQueue.peek().response.is_empty();
status.parameterFifoEmpty = CDROM_params.is_empty();
status.parameterFifoFull = !CDROM_params.is_full(); // Inverse logic
status.responseFifoEmpty = !responseFifoEmpty; // Inverse logic
return status._reg;
}
if (address == 1) { // CD Response
uint8_t response = 0;
if (!CDROM_response.is_empty()) {
response = CDROM_response.get();
uint8_t ret = 0;
if (CDROM_response.is_empty()) {
status.responseFifoEmpty = 0;
if (!interruptQueue.is_empty()) {
auto& response = interruptQueue.ref();
if (!response.response.is_empty()) {
ret = response.response.get();
if (response.response.is_empty() && response.ack == true) {
interruptQueue.get();
}
}
}
if (verbose == 2) fmt::print("CDROM: R RESPONSE: 0x{:02x}\n", response);
return response;
if (verbose == 2) fmt::print("CDROM: R RESPONSE: 0x{:02x}\n", ret);
return ret;
}
if (address == 2) { // CD Data
uint8_t byte = readByte();
@ -175,7 +196,7 @@ 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() & 7;
_status |= interruptQueue.peek().irq & 7;
}
if (verbose == 2) fmt::print("CDROM: R INTF: 0x{:02x}\n", _status);
return _status;
@ -234,7 +255,6 @@ std::string CDROM::dumpFifo(const FIFO& f) {
void CDROM::handleCommand(uint8_t cmd) {
interruptQueue.clear();
CDROM_response.clear();
switch (cmd) {
case 0x01: cmdGetstat(); break;
case 0x02: cmdSetloc(); break;
@ -282,8 +302,6 @@ void CDROM::handleCommand(uint8_t cmd) {
}
CDROM_params.clear();
status.parameterFifoEmpty = 1;
status.parameterFifoFull = 1;
status.transmissionBusy = 1;
status.xaFifoEmpty = 0;
}
@ -299,10 +317,7 @@ void CDROM::write(uint32_t address, uint8_t data) {
return handleCommand(data);
}
if (address == 2 && status.index == 0) { // Parameter fifo
assert(CDROM_params.size() < 16);
CDROM_params.add(data);
status.parameterFifoEmpty = 0;
status.parameterFifoFull = !(CDROM_params.size() >= 16);
if (verbose == 3) fmt::print("CDROM: W PARAMFIFO: 0x{:02x}\n", data);
return;
}
@ -332,12 +347,13 @@ void CDROM::write(uint32_t address, uint8_t data) {
if (data & 0x40) // reset parameter fifo
{
CDROM_params.clear();
status.parameterFifoEmpty = 1;
status.parameterFifoFull = 1;
}
if (!interruptQueue.is_empty()) {
interruptQueue.get();
interruptQueue.ref().ack = true;
if (interruptQueue.ref().response.is_empty()) {
interruptQueue.get();
}
}
if (verbose == 2) fmt::print("CDROM: W INTF: 0x{:02x}\n", data);
return;

View file

@ -62,11 +62,11 @@ class CDROM {
union CDROM_Status {
struct {
uint8_t index : 2;
uint8_t xaFifoEmpty : 1;
uint8_t parameterFifoEmpty : 1; // triggered before writing first byte
uint8_t parameterFifoFull : 1; // triggered after writing 16 bytes
uint8_t responseFifoEmpty : 1; // triggered after reading last byte
uint8_t dataFifoEmpty : 1; // triggered after reading last byte
uint8_t xaFifoEmpty : 1; // 1 - NOT empty, 0 - empty, INVERSE LOGIC
uint8_t parameterFifoEmpty : 1; // 1 - empty, 0 - not empty
uint8_t parameterFifoFull : 1; // 1 - NOT full, 0 - full, INVERSE LOGIC
uint8_t responseFifoEmpty : 1; // 1 - NOT empty, 0 - empty, INVERSE LOGIC
uint8_t dataFifoEmpty : 1; // 1 - NOT empty, 0 - empty, INVERSE LOGIC
uint8_t transmissionBusy : 1;
};
uint8_t _reg;
@ -102,6 +102,18 @@ class CDROM {
}
};
// Hack
struct irq_response_t {
uint8_t irq;
fifo<uint8_t, 16> response;
bool ack;
template <class Archive>
void serialize(Archive& ar) {
ar(irq, response, ack);
}
};
using FIFO = fifo<uint8_t, 16>;
int verbose = 1;
@ -109,8 +121,7 @@ class CDROM {
CDROM_Status status;
uint8_t interruptEnable = 0;
FIFO CDROM_params;
FIFO CDROM_response;
FIFO interruptQueue;
fifo<irq_response_t, 16> interruptQueue;
Mode mode;
Filter filter;
@ -154,28 +165,14 @@ class CDROM {
void cmdSeekP();
void handleCommand(uint8_t cmd);
void writeResponse(uint8_t byte) {
if (CDROM_response.is_full()) {
return;
}
CDROM_response.add(byte);
status.responseFifoEmpty = 1;
}
void writeResponse(uint8_t byte);
uint8_t readParam() {
uint8_t param = CDROM_params.get();
status.parameterFifoEmpty = CDROM_params.is_empty();
status.parameterFifoFull = 1;
return param;
}
void postInterrupt(int irq) {
assert(irq <= 7);
interruptQueue.add(irq);
}
void postInterrupt(int irq) { interruptQueue.add(irq_response_t{.irq = (uint8_t)irq, .response = {}}); }
std::string dumpFifo(const FIFO& f);
std::pair<int16_t, int16_t> mixSample(std::pair<int16_t, int16_t> sample);
@ -213,7 +210,7 @@ class CDROM {
void serialize(Archive& ar) {
ar(status._reg, interruptEnable);
ar(CDROM_params);
ar(CDROM_response);
// ar(CDROM_response);
ar(interruptQueue);
ar(mode._reg);
ar(filter);

View file

@ -8,7 +8,7 @@ void CDROM::cmdGetstat() {
postInterrupt(3);
writeResponse(stat._reg);
if (verbose) fmt::print("CDROM: cmdGetstat -> 0x{:02x}\n", CDROM_response[0]);
if (verbose) fmt::print("CDROM: cmdGetstat -> 0x{:02x}\n", interruptQueue.peek().response[0]);
}
void CDROM::cmdSetloc() {
@ -156,7 +156,7 @@ void CDROM::cmdGetparam() {
writeResponse(filter.file);
writeResponse(filter.channel);
if (verbose) fmt::print("CDROM: cmdGetparam({})\n", dumpFifo(CDROM_response));
if (verbose) fmt::print("CDROM: cmdGetparam({})\n", dumpFifo(interruptQueue.peek().response));
}
void CDROM::cmdSetSession() {
@ -205,6 +205,7 @@ void CDROM::cmdGetlocL() {
writeResponse(rawSector[19]); // ci
if (verbose) {
auto CDROM_response = interruptQueue.peek().response;
fmt::print(
"CDROM: cmdGetlocL -> ("
"pos = (0x{:02x}:0x{:02x}:0x{:02x}), "
@ -232,6 +233,7 @@ void CDROM::cmdGetlocP() {
writeResponse(lastQ.data[8]); // sector (disc)
if (verbose) {
auto CDROM_response = interruptQueue.peek().response;
fmt::print("CDROM: cmdGetlocP -> ({})\n", dumpFifo(CDROM_response));
}
}
@ -243,6 +245,7 @@ void CDROM::cmdGetTN() {
writeResponse(bcd::toBcd(disc->getTrackCount()));
if (verbose) {
auto CDROM_response = interruptQueue.peek().response;
fmt::print("CDROM: cmdGetTN -> ({})\n", dumpFifo(CDROM_response));
}
}
@ -275,6 +278,7 @@ void CDROM::cmdGetTD() {
}
if (verbose) {
auto CDROM_response = interruptQueue.peek().response;
fmt::print("CDROM: cmdGetTD(0x{:02x}) -> ({})\n", track, dumpFifo(CDROM_response));
}
}
@ -331,7 +335,8 @@ void CDROM::cmdTest() {
}
if (verbose) {
fmt::print("CDROM: cmdTest(0x{:02x}) -> ({})\n", opcode, dumpFifo(CDROM_response));
auto CDROM_response = interruptQueue.peek().response;
fmt::print("//CDROM: cmdTest(0x{:02x}) -> ({})\n", opcode, dumpFifo(CDROM_response));
}
}
@ -347,6 +352,10 @@ void CDROM::cmdGetId() {
postInterrupt(3);
writeResponse(stat._reg);
if (disc->getTrackCount() == 0) {
stat.idError = 1;
}
// No CD
if (disc->getTrackCount() == 0) {
postInterrupt(5);
@ -356,7 +365,7 @@ void CDROM::cmdGetId() {
}
// Audio CD
else if (disc->read(disc::Position(0, 2, 0)).second == disc::TrackType::AUDIO) {
postInterrupt(5);
postInterrupt(2);
writeResponse(0x0a);
writeResponse(0x90);
for (int i = 0; i < 6; i++) writeResponse(0);
@ -374,7 +383,10 @@ void CDROM::cmdGetId() {
}
if (verbose) {
fmt::print("CDROM: cmdGetId -> ({})\n", dumpFifo(CDROM_response));
for (int i = 0; i < interruptQueue.size(); i++) {
auto CDROM_response = interruptQueue.peek(i).response;
fmt::print("CDROM: cmdGetId -> INT{} ({})\n", interruptQueue.peek(i).irq, dumpFifo(CDROM_response));
}
}
}
@ -407,6 +419,7 @@ void CDROM::cmdUnlock() {
writeResponse(0x40);
if (verbose) {
auto CDROM_response = interruptQueue.peek().response;
fmt::print("CDROM: cmdUnlock -> ({})\n", dumpFifo(CDROM_response));
}
}