grandcentral: cleanup interrupt acknowledgement.

This commit is contained in:
Maxim Poliakovski 2024-02-12 00:07:09 +01:00
parent cdc5589bcf
commit ce2f6ddadd
2 changed files with 74 additions and 45 deletions

View File

@ -1,6 +1,6 @@
/* /*
DingusPPC - The Experimental PowerPC Macintosh emulator DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-22 divingkatae and maximum Copyright (C) 2018-24 divingkatae and maximum
(theweirdo) spatium (theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info) (Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -150,12 +150,16 @@ uint32_t GrandCentral::read(uint32_t rgn_start, uint32_t offset, int size)
} }
} else { // Interrupt related registers } else { // Interrupt related registers
switch (offset) { switch (offset) {
case MIO_INT_MASK1:
return BYTESWAP_32(this->int_mask);
case MIO_INT_LEVELS1:
return BYTESWAP_32(this->int_levels);
case MIO_INT_EVENTS1: case MIO_INT_EVENTS1:
return BYTESWAP_32(this->int_events); return BYTESWAP_32(this->int_events);
case MIO_INT_MASK1:
return BYTESWAP_32(this->int_mask);
case MIO_INT_CLEAR1:
// some Mac OS drivers reads from this write-only register
// so we return zero here as real HW does
return 0;
case MIO_INT_LEVELS1:
return BYTESWAP_32(this->int_levels);
} }
} }
@ -245,15 +249,14 @@ void GrandCentral::write(uint32_t rgn_start, uint32_t offset, uint32_t value, in
this->int_mask = BYTESWAP_32(value); this->int_mask = BYTESWAP_32(value);
break; break;
case MIO_INT_CLEAR1: case MIO_INT_CLEAR1:
if (value & MACIO_INT_CLR) { if ((this->int_mask & MACIO_INT_MODE) && (value & MACIO_INT_CLR))
this->int_events = 0; this->int_events = 0;
this->cpu_int_latch = false; else
ppc_release_int(); this->int_events &= ~(BYTESWAP_32(value) & 0x7FFFFFFFUL);
LOG_F(5, "GC: CPU INT latch cleared"); clear_cpu_int();
} else {
this->int_events &= BYTESWAP_32(value);
}
break; break;
case MIO_INT_LEVELS1:
break; // ignore writes to this read-only register
default: default:
LOG_F(WARNING, "GC: writing to unmapped I/O memory 0x%X", LOG_F(WARNING, "GC: writing to unmapped I/O memory 0x%X",
this->base_addr + offset); this->base_addr + offset);
@ -268,8 +271,7 @@ void GrandCentral::attach_iodevice(int dev_num, IobusDevice* dev_obj)
} }
} }
uint32_t GrandCentral::register_dev_int(IntSrc src_id) uint32_t GrandCentral::register_dev_int(IntSrc src_id) {
{
switch (src_id) { switch (src_id) {
case IntSrc::VIA_CUDA: case IntSrc::VIA_CUDA:
return 1 << 18; return 1 << 18;
@ -278,29 +280,53 @@ uint32_t GrandCentral::register_dev_int(IntSrc src_id)
case IntSrc::SWIM3: case IntSrc::SWIM3:
return 1 << 19; return 1 << 19;
default: default:
ABORT_F("GC: unknown interrupt source %d", src_id); ABORT_F("%s: unknown interrupt source %d", this->name.c_str(), src_id);
} }
return 0; return 0;
} }
uint32_t GrandCentral::register_dma_int(IntSrc src_id) uint32_t GrandCentral::register_dma_int(IntSrc src_id) {
{ switch (src_id) {
ABORT_F("GC: register_dma_int() not implemened"); case IntSrc::DMA_SCSI_CURIO: return 1 << 0;
case IntSrc::DMA_SWIM3: return 1 << 1;
case IntSrc::DMA_SCSI_MESH: return 1 << 10;
default:
ABORT_F("%s: unknown DMA interrupt source %d", this->name.c_str(), src_id);
}
return 0; return 0;
} }
void GrandCentral::ack_int(uint32_t irq_id, uint8_t irq_line_state) void GrandCentral::ack_int_common(uint32_t irq_id, uint8_t irq_line_state) {
{ // native mode: set IRQ bits in int_events1 on a 0-to-1 transition
if (this->int_mask & MACIO_INT_MODE) { // 68k interrupt emulation mode? // emulated mode: set IRQ bits in int_events1 on all transitions
this->int_events |= irq_id; // signal IRQ line change if ((this->int_mask & MACIO_INT_MODE) ||
(irq_line_state && !(this->int_levels & irq_id))) {
this->int_events |= irq_id;
} else {
this->int_events &= ~irq_id;
}
this->int_events &= this->int_mask; this->int_events &= this->int_mask;
// update IRQ line state // update IRQ line state
if (irq_line_state) { if (irq_line_state) {
this->int_levels |= irq_id; this->int_levels |= irq_id;
} else { } else {
this->int_levels &= ~irq_id; this->int_levels &= ~irq_id;
} }
// signal CPU interrupt
this->signal_cpu_int(irq_id);
}
void GrandCentral::ack_int(uint32_t irq_id, uint8_t irq_line_state) {
this->ack_int_common(irq_id, irq_line_state);
}
void GrandCentral::ack_dma_int(uint32_t irq_id, uint8_t irq_line_state) {
this->ack_int_common(irq_id, irq_line_state);
}
void GrandCentral::signal_cpu_int(uint32_t irq_id) {
if (this->int_events) { if (this->int_events) {
if (!this->cpu_int_latch) { if (!this->cpu_int_latch) {
this->cpu_int_latch = true; this->cpu_int_latch = true;
@ -310,14 +336,14 @@ void GrandCentral::ack_int(uint32_t irq_id, uint8_t irq_line_state)
LOG_F(5, "GC: CPU INT already latched"); LOG_F(5, "GC: CPU INT already latched");
} }
} }
} else {
ABORT_F("GC: native interrupt mode not implemented");
}
} }
void GrandCentral::ack_dma_int(uint32_t irq_id, uint8_t irq_line_state) void GrandCentral::clear_cpu_int() {
{ if (!this->int_events) {
ABORT_F("GC: ack_dma_int() not implemened"); this->cpu_int_latch = false;
ppc_release_int();
LOG_F(5, "%s: CPU INT latch cleared", this->name.c_str());
}
} }
static const vector<string> GCSubdevices = { static const vector<string> GCSubdevices = {

View File

@ -1,6 +1,6 @@
/* /*
DingusPPC - The Experimental PowerPC Macintosh emulator DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-22 divingkatae and maximum Copyright (C) 2018-24 divingkatae and maximum
(theweirdo) spatium (theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info) (Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -115,6 +115,9 @@ public:
protected: protected:
void notify_bar_change(int bar_num); void notify_bar_change(int bar_num);
void ack_int_common(uint32_t irq_id, uint8_t irq_line_state);
void signal_cpu_int(uint32_t irq_id);
void clear_cpu_int();
private: private:
uint32_t base_addr = 0; uint32_t base_addr = 0;