Make irq_id 64 bits.

- So that DMA and other interrupts can fit without overlap.
- To simplify conversion to interrupt mask.
- To reduce variables, defines, and code.
This commit is contained in:
joevt
2024-11-11 05:46:03 -08:00
committed by dingusdev
parent 662166d7c6
commit 101bb826f1
14 changed files with 262 additions and 325 deletions

View File

@@ -95,7 +95,7 @@ private:
// interrupt stuff
InterruptCtrl* int_ctrl = nullptr;
uint32_t irq_id = 0;
uint64_t irq_id = 0;
};
#endif // IDE_CHANNEL_H

View File

@@ -123,7 +123,7 @@ public:
void end_pull_data();
void end_push_data();
void register_dma_int(InterruptCtrl* int_ctrl_obj, uint32_t irq_id) {
void register_dma_int(InterruptCtrl* int_ctrl_obj, uint64_t irq_id) {
this->int_ctrl = int_ctrl_obj;
this->irq_id = irq_id;
};
@@ -163,7 +163,7 @@ private:
// Interrupt related stuff
InterruptCtrl* int_ctrl = nullptr;
uint32_t irq_id = 0;
uint64_t irq_id = 0;
};
#endif // DB_DMA_H

View File

@@ -30,9 +30,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
enum IntSrc : uint32_t {
INT_UNKNOWN = 0,
VIA_CUDA,
VIA2,
SCSI_MESH,
SCSI_CURIO,
SWIM3,
ESCC,
SCCA,
SCCB,
ETHERNET,
@@ -58,6 +60,7 @@ enum IntSrc : uint32_t {
PLANB,
VCI,
PLATINUM,
DMA_ALL,
DMA_SCSI_MESH,
DMA_SCSI_CURIO,
DMA_SWIM3,
@@ -80,6 +83,16 @@ enum IntSrc : uint32_t {
USB,
PIPPIN_E,
PIPPIN_F,
ZIVA,
PCI_CARDBUS,
MEDIA_BAY,
SLOT_ALL,
SLOT_0,
SLOT_1,
SLOT_2,
SLOT_PDS,
SLOT_VDS,
VBL,
};
/** Base class for interrupt controllers. */
@@ -89,17 +102,17 @@ public:
virtual ~InterruptCtrl() = default;
// register interrupt sources for a device
virtual uint32_t register_dev_int(IntSrc src_id) = 0;
virtual uint32_t register_dma_int(IntSrc src_id) = 0;
virtual uint64_t register_dev_int(IntSrc src_id) = 0;
virtual uint64_t register_dma_int(IntSrc src_id) = 0;
// acknowledge HW interrupt
virtual void ack_int(uint32_t irq_id, uint8_t irq_line_state) = 0;
virtual void ack_dma_int(uint32_t irq_id, uint8_t irq_line_state) = 0;
virtual void ack_int(uint64_t irq_id, uint8_t irq_line_state) = 0;
virtual void ack_dma_int(uint64_t irq_id, uint8_t irq_line_state) = 0;
};
typedef struct {
InterruptCtrl *int_ctrl_obj;
uint32_t irq_id;
uint64_t irq_id;
} IntDetails;
#endif // HW_INTERRUPT_H

View File

@@ -290,7 +290,7 @@ private:
// interrupt related stuff
InterruptCtrl* int_ctrl = nullptr;
uint32_t irq_id = 0;
uint64_t irq_id = 0;
uint8_t irq = 0;
// DMA related stuff

View File

@@ -113,7 +113,7 @@ protected:
// interrupt related stuff
InterruptCtrl* int_ctrl = nullptr;
uint32_t irq_id = 0;
uint64_t irq_id = 0;
uint8_t irq = 0;
uint8_t int_mask = 0;
uint8_t int_stat = 0;

View File

@@ -207,7 +207,7 @@ private:
// VIA interrupt related stuff
InterruptCtrl* int_ctrl;
uint32_t irq_id;
uint64_t irq_id;
uint8_t _via_ifr;
uint8_t _via_ier;
uint8_t old_ifr = 0;

View File

@@ -147,7 +147,7 @@ private:
// Interrupt related stuff
InterruptCtrl* int_ctrl = nullptr;
uint32_t irq_id = 0;
uint64_t irq_id = 0;
uint8_t irq = 0;
};

View File

@@ -75,8 +75,8 @@ AMIC::AMIC() : MMIODevice()
this->viacuda = dynamic_cast<ViaCuda*>(gMachineObj->get_comp_by_name("ViaCuda"));
// initialize sound HW
this->snd_out_dma = std::unique_ptr<AmicSndOutDma> (new AmicSndOutDma());
this->snd_out_dma->init_interrupts(this, 2 << 8);
this->snd_out_dma = std::unique_ptr<AmicSndOutDma>(new AmicSndOutDma());
this->snd_out_dma->init_interrupts(this, DMA1_INT_SOUND << DMA1_INT_SHIFT);
this->awacs = std::unique_ptr<AwacDevicePdm> (new AwacDevicePdm());
this->awacs->set_dma_out(this->snd_out_dma.get());
@@ -448,50 +448,63 @@ void AMIC::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size)
}
// ======================== Interrupt related stuff ==========================
uint32_t AMIC::register_dev_int(IntSrc src_id) {
uint64_t AMIC::register_dev_int(IntSrc src_id) {
switch (src_id) {
case IntSrc::VIA_CUDA:
return CPU_INT_VIA1;
case IntSrc::SCSI_CURIO:
return VIA2_INT_SCSI_IRQ << 8;
case IntSrc::SWIM3:
return VIA2_INT_SWIM3 << 8;
case IntSrc::NMI:
return CPU_INT_NMI;
case IntSrc::VIA_CUDA : return CPU_INT_VIA1 << CPU_INT_SHIFT;
case IntSrc::VIA2 : return CPU_INT_VIA2 << CPU_INT_SHIFT;
case IntSrc::ESCC : return CPU_INT_ESCC << CPU_INT_SHIFT;
case IntSrc::ETHERNET : return CPU_INT_ENET << CPU_INT_SHIFT;
case IntSrc::DMA_ALL : return CPU_INT_ALL_DMA << CPU_INT_SHIFT;
case IntSrc::NMI : return CPU_INT_NMI << CPU_INT_SHIFT;
case IntSrc::DMA_SCSI_CURIO: return VIA2_INT_SCSI_DRQ << VIA2_INT_SHIFT;
case IntSrc::SLOT_ALL : return VIA2_INT_ALL_SLOT << VIA2_INT_SHIFT;
case IntSrc::SCSI_CURIO : return VIA2_INT_SCSI_IRQ << VIA2_INT_SHIFT;
case IntSrc::DAVBUS : return VIA2_INT_SOUND << VIA2_INT_SHIFT;
case IntSrc::SWIM3 : return VIA2_INT_SWIM3 << VIA2_INT_SHIFT;
case IntSrc::SLOT_0 : return SLOT_INT_SLOT_0 << SLOT_INT_SHIFT;
case IntSrc::SLOT_1 : return SLOT_INT_SLOT_1 << SLOT_INT_SHIFT;
case IntSrc::SLOT_2 : return SLOT_INT_SLOT_2 << SLOT_INT_SHIFT;
case IntSrc::SLOT_PDS : return SLOT_INT_SLOT_PDS << SLOT_INT_SHIFT;
case IntSrc::SLOT_VDS : return SLOT_INT_SLOT_VDS << SLOT_INT_SHIFT;
case IntSrc::VBL : return SLOT_INT_VBL << SLOT_INT_SHIFT;
case IntSrc::DMA_DAVBUS_Tx : return DMA1_INT_SOUND << DMA1_INT_SHIFT;
default:
ABORT_F("AMIC: unknown interrupt source %d", src_id);
}
return 0;
}
uint32_t AMIC::register_dma_int(IntSrc src_id) {
uint64_t AMIC::register_dma_int(IntSrc src_id) {
ABORT_F("AMIC: register_dma_int() not implemented");
return 0;
}
void AMIC::ack_int(uint32_t irq_id, uint8_t irq_line_state) {
void AMIC::ack_int(uint64_t irq_id, uint8_t irq_line_state) {
// dispatch cascaded AMIC interrupts from various sources
// irq_id format: 00DDCCBBAA where
// - AA -> CPU interrupts
// - BB -> pseudo VIA2 interrupts
// - CC -> slot interrupts
if (irq_id < 0x100) {
this->ack_cpu_int(irq_id, irq_line_state);
} else if (irq_id < 0x10000) {
this->ack_via2_int(irq_id >> 8, irq_line_state);
} else if (irq_id < 0x1000000) {
this->ack_slot_int(irq_id >> 16, irq_line_state);
if (irq_id >> SLOT_INT_SHIFT) {
this->ack_slot_int(irq_id >> SLOT_INT_SHIFT, irq_line_state);
} else if (irq_id >> VIA2_INT_SHIFT) {
this->ack_via2_int(irq_id >> VIA2_INT_SHIFT, irq_line_state);
} else if (irq_id >> CPU_INT_SHIFT) {
this->ack_cpu_int(irq_id >> CPU_INT_SHIFT, irq_line_state);
} else {
ABORT_F("AMIC: unknown interrupt source ID 0x%X", irq_id);
ABORT_F("AMIC: unknown interrupt source ID 0x%llX", irq_id);
}
}
void AMIC::ack_slot_int(uint32_t irq_id, uint8_t irq_line_state) {
void AMIC::ack_slot_int(uint8_t slot_int, uint8_t irq_line_state) {
// CAUTION: reverse logic (0 - true, 1 - false) in the IFR register!
if (irq_line_state) {
this->via2_slot_ifr &= ~irq_id;
this->via2_slot_ifr &= ~slot_int;
} else {
this->via2_slot_ifr |= irq_id;
this->via2_slot_ifr |= slot_int;
}
uint8_t new_irq = !!(~this->via2_slot_ifr & this->via2_slot_ier & 0x7F);
if (new_irq != this->via2_slot_irq) {
@@ -509,26 +522,26 @@ void AMIC::update_via2_irq() {
}
}
void AMIC::ack_via2_int(uint32_t irq_id, uint8_t irq_line_state) {
void AMIC::ack_via2_int(uint8_t via2_int, uint8_t irq_line_state) {
if (irq_line_state) {
this->via2_ifr |= irq_id;
this->via2_ifr |= via2_int;
} else {
this->via2_ifr &= ~irq_id;
this->via2_ifr &= ~via2_int;
}
this->update_via2_irq();
}
void AMIC::ack_cpu_int(uint32_t irq_id, uint8_t irq_line_state) {
void AMIC::ack_cpu_int(uint8_t cpu_int, uint8_t irq_line_state) {
if (this->int_ctrl & CPU_INT_MODE) { // 68k interrupt emulation mode?
if (irq_line_state) {
this->dev_irq_lines |= irq_id;
this->dev_irq_lines |= cpu_int;
} else {
this->dev_irq_lines &= ~irq_id;
this->dev_irq_lines &= ~cpu_int;
}
if (!(this->int_ctrl & CPU_INT_FLAG)) {
this->int_ctrl |= CPU_INT_FLAG;
ppc_assert_int();
LOG_F(5, "AMIC: CPU INT asserted, source: %d", irq_id);
LOG_F(5, "AMIC: CPU INT asserted, source: 0x%02x", cpu_int);
} else {
LOG_F(5, "AMIC: CPU INT already latched");
}
@@ -538,15 +551,15 @@ void AMIC::ack_cpu_int(uint32_t irq_id, uint8_t irq_line_state) {
}
}
void AMIC::ack_dma_int(uint32_t irq_id, uint8_t irq_line_state) {
if (irq_id >= 0x100) { // DMA Interrupt Flags 1
irq_id = (irq_id >> 8) & 0xFFU;
void AMIC::ack_dma_int(uint64_t irq_id, uint8_t irq_line_state) {
if (irq_id >> DMA1_INT_SHIFT) { // DMA Interrupt Flags 1
irq_id = (irq_id >> DMA1_INT_SHIFT) & 0xFFU;
if (irq_line_state)
this->dma_ifr1 |= irq_id;
else
this->dma_ifr1 &= ~irq_id;
} else { // DMA Interrupt Flags 0
irq_id &= 0xFFU;
} else if (irq_id >> DMA0_INT_SHIFT) { // DMA Interrupt Flags 0
irq_id = (irq_id >> DMA0_INT_SHIFT) & 0xFFU;
if (irq_line_state)
this->dma_ifr0 |= irq_id;
else
@@ -588,7 +601,7 @@ void AmicSndOutDma::update_irq() {
if (new_level != this->irq_level) {
this->irq_level = new_level;
TimerManager::get_instance()->add_immediate_timer([this] {
this->int_ctrl->ack_dma_int(this->irq_id, this->irq_level);
this->int_ctrl->ack_dma_int(this->snd_dma_irq_id, this->irq_level);
});
}
}

View File

@@ -43,7 +43,8 @@ namespace Swim3 { class Swim3Ctrl; }
/** Interrupt related constants. */
/** CPU interrupt register bits. */
enum : uint8_t {
enum : uint64_t {
CPU_INT_SHIFT = 0,
CPU_INT_VIA1 = 1 << 0, // (R) VIA1 interrupts
CPU_INT_VIA2 = 1 << 1, // (R) pseudo VIA2 interrupts
CPU_INT_ESCC = 1 << 2, // (R) ESCC interrupt
@@ -56,7 +57,8 @@ enum : uint8_t {
};
/** Pseudo VIA2 interrupt flag/enable register bits. */
enum : uint8_t {
enum : uint64_t {
VIA2_INT_SHIFT = 8,
VIA2_INT_SCSI_DRQ = 1 << 0, // (R) SCSI DRQ interrupt
VIA2_INT_ALL_SLOT = 1 << 1, // (R) all slot interrupts are signalled here
VIA2_INT_SCSI_IRQ = 1 << 3, // (R) SCSI IRQ interrupt
@@ -66,7 +68,8 @@ enum : uint8_t {
};
/** Slot interrupt flag/enable register bits. */
enum : uint8_t {
enum : uint64_t {
SLOT_INT_SHIFT = 16,
SLOT_INT_SLOT_0 = 1 << 2, // (R) ColdFusion Nubus slot 0 interrupt
SLOT_INT_SLOT_1 = 1 << 3, // (R) ColdFusion Nubus slot 1 interrupt
SLOT_INT_SLOT_2 = 1 << 4, // (R) ColdFusion Nubus slot 2 interrupt
@@ -75,6 +78,13 @@ enum : uint8_t {
SLOT_INT_VBL = 1 << 6, // (R) built-in video VBL interrupt
};
/** DMA interrupt bits. */
enum : uint64_t {
DMA0_INT_SHIFT = 24,
DMA1_INT_SHIFT = 32,
DMA1_INT_SOUND = 1 << 1,
};
/** AMIC sound buffers are located at fixed offsets from DMA base. */
#define AMIC_SND_BUF0_OFFS 0x10000
#define AMIC_SND_BUF1_OFFS 0x12000
@@ -104,9 +114,9 @@ public:
DmaPullResult pull_data(uint32_t req_len, uint32_t *avail_len,
uint8_t **p_data);
void init_interrupts(InterruptCtrl *int_ctrl, uint32_t irq_id) {
void init_interrupts(InterruptCtrl *int_ctrl, uint64_t irq_id) {
this->int_ctrl = int_ctrl;
this->irq_id = irq_id;
this->snd_dma_irq_id = irq_id;
};
private:
@@ -120,7 +130,7 @@ private:
uint32_t cur_buf_pos;
InterruptCtrl *int_ctrl = nullptr;
uint32_t irq_id = 0;
uint64_t snd_dma_irq_id = 0;
uint8_t irq_level = 0;
};
@@ -288,22 +298,22 @@ public:
}
// HWComponent methods
int device_postinit();
int device_postinit() override;
/* MMIODevice methods */
uint32_t read(uint32_t rgn_start, uint32_t offset, int size);
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size);
uint32_t read(uint32_t rgn_start, uint32_t offset, int size) override;
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) override;
// InterruptCtrl methods
uint32_t register_dev_int(IntSrc src_id);
uint32_t register_dma_int(IntSrc src_id);
void ack_int(uint32_t irq_id, uint8_t irq_line_state);
void ack_dma_int(uint32_t irq_id, uint8_t irq_line_state);
uint64_t register_dev_int(IntSrc src_id) override;
uint64_t register_dma_int(IntSrc src_id) override;
void ack_int(uint64_t irq_id, uint8_t irq_line_state) override;
void ack_dma_int(uint64_t irq_id, uint8_t irq_line_state) override;
protected:
void ack_slot_int(uint32_t irq_id, uint8_t irq_line_state);
void ack_via2_int(uint32_t irq_id, uint8_t irq_line_state);
void ack_cpu_int(uint32_t irq_id, uint8_t irq_line_state);
void ack_slot_int(uint8_t slot_int, uint8_t irq_line_state);
void ack_via2_int(uint8_t via2_int, uint8_t irq_line_state);
void ack_cpu_int(uint8_t cpu_int, uint8_t irq_line_state);
void update_via2_irq();
private:

View File

@@ -434,7 +434,7 @@ void GrandCentral::attach_iodevice(int dev_num, IobusDevice* dev_obj)
#define INT_TO_IRQ_ID(intx) (1 << intx)
uint32_t GrandCentral::register_dev_int(IntSrc src_id) {
uint64_t GrandCentral::register_dev_int(IntSrc src_id) {
switch (src_id) {
case IntSrc::SCSI_CURIO : return INT_TO_IRQ_ID(0x0C);
case IntSrc::SCSI_MESH : return INT_TO_IRQ_ID(0x0D);
@@ -473,61 +473,60 @@ uint32_t GrandCentral::register_dev_int(IntSrc src_id) {
return 0;
}
#define DMA_INT_TO_IRQ_ID(intx) (1 << intx)
uint32_t GrandCentral::register_dma_int(IntSrc src_id) {
uint64_t GrandCentral::register_dma_int(IntSrc src_id) {
switch (src_id) {
case IntSrc::DMA_SCSI_CURIO : return DMA_INT_TO_IRQ_ID(0x00);
case IntSrc::DMA_SWIM3 : return DMA_INT_TO_IRQ_ID(0x01);
case IntSrc::DMA_ETHERNET_Tx : return DMA_INT_TO_IRQ_ID(0x02);
case IntSrc::DMA_ETHERNET_Rx : return DMA_INT_TO_IRQ_ID(0x03);
case IntSrc::DMA_SCCA_Tx : return DMA_INT_TO_IRQ_ID(0x04);
case IntSrc::DMA_SCCA_Rx : return DMA_INT_TO_IRQ_ID(0x05);
case IntSrc::DMA_SCCB_Tx : return DMA_INT_TO_IRQ_ID(0x06);
case IntSrc::DMA_SCCB_Rx : return DMA_INT_TO_IRQ_ID(0x07);
case IntSrc::DMA_DAVBUS_Tx : return DMA_INT_TO_IRQ_ID(0x08);
case IntSrc::DMA_DAVBUS_Rx : return DMA_INT_TO_IRQ_ID(0x09);
case IntSrc::DMA_SCSI_MESH : return DMA_INT_TO_IRQ_ID(0x0A);
case IntSrc::DMA_SCSI_CURIO : return INT_TO_IRQ_ID(0x00);
case IntSrc::DMA_SWIM3 : return INT_TO_IRQ_ID(0x01);
case IntSrc::DMA_ETHERNET_Tx: return INT_TO_IRQ_ID(0x02);
case IntSrc::DMA_ETHERNET_Rx: return INT_TO_IRQ_ID(0x03);
case IntSrc::DMA_SCCA_Tx : return INT_TO_IRQ_ID(0x04);
case IntSrc::DMA_SCCA_Rx : return INT_TO_IRQ_ID(0x05);
case IntSrc::DMA_SCCB_Tx : return INT_TO_IRQ_ID(0x06);
case IntSrc::DMA_SCCB_Rx : return INT_TO_IRQ_ID(0x07);
case IntSrc::DMA_DAVBUS_Tx : return INT_TO_IRQ_ID(0x08);
case IntSrc::DMA_DAVBUS_Rx : return INT_TO_IRQ_ID(0x09);
case IntSrc::DMA_SCSI_MESH : return INT_TO_IRQ_ID(0x0A);
default:
ABORT_F("%s: unknown DMA interrupt source %d", this->name.c_str(), src_id);
}
return 0;
}
void GrandCentral::ack_int_common(uint32_t irq_id, uint8_t irq_line_state) {
void GrandCentral::ack_int_common(uint64_t irq_id, uint8_t irq_line_state) {
// native mode: set IRQ bits in int_events on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events on all transitions
if ((this->int_mask & MACIO_INT_MODE) ||
(irq_line_state && !(this->int_levels & irq_id))) {
this->int_events |= irq_id;
this->int_events |= (uint32_t)irq_id;
} else {
this->int_events &= ~irq_id;
this->int_events &= ~(uint32_t)irq_id;
}
// update IRQ line state
if (irq_line_state) {
this->int_levels |= irq_id;
this->int_levels |= (uint32_t)irq_id;
} else {
this->int_levels &= ~irq_id;
this->int_levels &= ~(uint32_t)irq_id;
}
this->signal_cpu_int(irq_id);
}
void GrandCentral::ack_int(uint32_t irq_id, uint8_t irq_line_state) {
void GrandCentral::ack_int(uint64_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) {
void GrandCentral::ack_dma_int(uint64_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) {
void GrandCentral::signal_cpu_int(uint64_t irq_id) {
if (this->int_events & this->int_mask) {
if (!this->cpu_int_latch) {
this->cpu_int_latch = true;
ppc_assert_int();
LOG_F(5, "%s: CPU INT asserted, source: %d", this->name.c_str(), irq_id);
LOG_F(5, "%s: CPU INT asserted, source: 0x%08llx", this->name.c_str(), irq_id);
} else {
LOG_F(5, "%s: CPU INT already latched", this->name.c_str());
}

View File

@@ -299,22 +299,22 @@ uint32_t HeathrowIC::mio_ctrl_read(uint32_t offset, int size) {
switch (offset & 0xFC) {
case MIO_INT_EVENTS2:
value = this->int_events2;
value = this->int_events >> 32;
break;
case MIO_INT_MASK2:
value = this->int_mask2;
value = this->int_mask >> 32;
break;
case MIO_INT_LEVELS2:
value = this->int_levels2;
value = this->int_levels >> 32;
break;
case MIO_INT_EVENTS1:
value = this->int_events1;
value = uint32_t(this->int_events);
break;
case MIO_INT_MASK1:
value = this->int_mask1;
value = uint32_t(this->int_mask);
break;
case MIO_INT_LEVELS1:
value = this->int_levels1;
value = uint32_t(int_levels);
break;
case MIO_INT_CLEAR1:
case MIO_INT_CLEAR2:
@@ -343,25 +343,24 @@ uint32_t HeathrowIC::mio_ctrl_read(uint32_t offset, int size) {
void HeathrowIC::mio_ctrl_write(uint32_t offset, uint32_t value, int size) {
switch (offset & 0xFC) {
case MIO_INT_MASK2:
this->int_mask2 |= BYTESWAP_32(value) & ~MACIO_INT_MODE;
this->int_mask |= uint64_t(BYTESWAP_32(value) & ~MACIO_INT_MODE) << 32;
this->signal_cpu_int();
break;
case MIO_INT_CLEAR2:
this->int_events2 &= ~(BYTESWAP_32(value) & 0x7FFFFFFFUL);
this->int_events &= ~(uint64_t(BYTESWAP_32(value) & 0x7FFFFFFFUL) << 32);
clear_cpu_int();
break;
case MIO_INT_MASK1:
this->int_mask1 = BYTESWAP_32(value);
this->int_mask = (this->int_mask & 0x7FFFFFFF00000000ULL) | BYTESWAP_32(value);
// copy IntMode bit to InterruptMask2 register
this->int_mask2 = (this->int_mask2 & ~MACIO_INT_MODE) | (this->int_mask1 & MACIO_INT_MODE);
this->int_mask |= uint64_t(this->int_mask & MACIO_INT_MODE) << 32;
this->signal_cpu_int();
break;
case MIO_INT_CLEAR1:
if ((this->int_mask1 & MACIO_INT_MODE) && (value & MACIO_INT_CLR)) {
this->int_events1 = 0;
this->int_events2 = 0;
if ((this->int_mask & MACIO_INT_MODE) && (value & MACIO_INT_CLR)) {
this->int_events = 0;
} else {
this->int_events1 &= ~(BYTESWAP_32(value) & 0x7FFFFFFFUL);
this->int_events &= ~uint64_t(BYTESWAP_32(value) & 0x7FFFFFFFUL);
}
clear_cpu_int();
break;
@@ -381,7 +380,7 @@ void HeathrowIC::mio_ctrl_write(uint32_t offset, uint32_t value, int size) {
}
}
void HeathrowIC::feature_control(const uint32_t value)
void HeathrowIC::feature_control(uint32_t value)
{
LOG_F(9, "write %x to MIO:Feat_Ctrl register", value);
@@ -394,22 +393,9 @@ void HeathrowIC::feature_control(const uint32_t value)
}
}
#define FIRST_INT1_BIT 12 // The first ten are DMA, the next 2 appear to be unused.
// We'll map 1:1 the INT1 bits 31..12 (0x1F..0x0C) as IRQ_ID bits.
#define FIRST_INT2_BIT 2 // Skip the first two which are Ethernet DMA.
// We'll map INT2 bits 13..2 (interrupts 45..34 or 0x2D..0x22) as IRQ_ID bits 11..0.
#define FIRST_INT1_IRQ_ID_BIT 12 // Same as INT1_BIT so there won't be any shifting required.
#define FIRST_INT2_IRQ_ID_BIT 0
#define INT_TO_IRQ_ID(intx) (1ULL << intx)
#define INT1_TO_IRQ_ID(int1) (1 << (int1 - FIRST_INT1_BIT + FIRST_INT1_IRQ_ID_BIT))
#define INT2_TO_IRQ_ID(int2) (1 << (int2 - FIRST_INT2_BIT + FIRST_INT2_IRQ_ID_BIT - 32))
#define INT_TO_IRQ_ID(intx) (intx < 32 ? INT1_TO_IRQ_ID(intx) : INT2_TO_IRQ_ID(intx))
#define IS_INT1(irq_id) (irq_id >= 1 << FIRST_INT1_IRQ_ID_BIT)
#define IRQ_ID_TO_INT1_MASK(irq_id) (irq_id <<= (FIRST_INT1_BIT - FIRST_INT1_IRQ_ID_BIT))
#define IRQ_ID_TO_INT2_MASK(irq_id) (irq_id <<= (FIRST_INT2_BIT - FIRST_INT2_IRQ_ID_BIT))
uint32_t HeathrowIC::register_dev_int(IntSrc src_id)
uint64_t HeathrowIC::register_dev_int(IntSrc src_id)
{
switch (src_id) {
case IntSrc::SCSI_MESH : return INT_TO_IRQ_ID(0x0C);
@@ -446,193 +432,65 @@ uint32_t HeathrowIC::register_dev_int(IntSrc src_id)
return 0;
}
#define FIRST_DMA_INT1_BIT 0 // bit 0 is SCSI DMA
#define FIRST_DMA_INT2_BIT 0 // bit 0 is Ethernet DMA Tx
#define FIRST_DMA_INT1_IRQ_ID_BIT 0
#define FIRST_DMA_INT2_IRQ_ID_BIT 16 // There's only 10 INT1 DMA bits but we'll put INT2 DMA bits in the upper 16 bits
#define DMA_INT1_TO_IRQ_ID(int1) (1 << (int1 - FIRST_DMA_INT1_BIT + FIRST_DMA_INT1_IRQ_ID_BIT))
#define DMA_INT2_TO_IRQ_ID(int2) (1 << (int2 - FIRST_DMA_INT2_BIT + FIRST_DMA_INT2_IRQ_ID_BIT - 32))
#define DMA_INT_TO_IRQ_ID(intx) (intx < 32 ? DMA_INT1_TO_IRQ_ID(intx) : DMA_INT2_TO_IRQ_ID(intx))
#define IS_DMA_INT1(irq_id) (irq_id < 1 << FIRST_DMA_INT2_IRQ_ID_BIT)
#define DMA_IRQ_ID_TO_INT1_MASK(irq_id) (irq_id <<= (FIRST_DMA_INT1_BIT - FIRST_DMA_INT1_IRQ_ID_BIT))
#define DMA_IRQ_ID_TO_INT2_MASK(irq_id) (irq_id >>= (FIRST_DMA_INT2_IRQ_ID_BIT - FIRST_DMA_INT2_BIT))
uint32_t HeathrowIC::register_dma_int(IntSrc src_id)
uint64_t HeathrowIC::register_dma_int(IntSrc src_id)
{
switch (src_id) {
case IntSrc::DMA_SCSI_MESH : return DMA_INT_TO_IRQ_ID(0x00);
case IntSrc::DMA_SWIM3 : return DMA_INT_TO_IRQ_ID(0x01);
case IntSrc::DMA_IDE0 : return DMA_INT_TO_IRQ_ID(0x02);
case IntSrc::DMA_IDE1 : return DMA_INT_TO_IRQ_ID(0x03);
case IntSrc::DMA_SCCA_Tx : return DMA_INT_TO_IRQ_ID(0x04);
case IntSrc::DMA_SCCA_Rx : return DMA_INT_TO_IRQ_ID(0x05);
case IntSrc::DMA_SCCB_Tx : return DMA_INT_TO_IRQ_ID(0x06);
case IntSrc::DMA_SCCB_Rx : return DMA_INT_TO_IRQ_ID(0x07);
case IntSrc::DMA_DAVBUS_Tx : return DMA_INT_TO_IRQ_ID(0x08);
case IntSrc::DMA_DAVBUS_Rx : return DMA_INT_TO_IRQ_ID(0x09);
case IntSrc::DMA_ETHERNET_Tx : return DMA_INT_TO_IRQ_ID(0x20);
case IntSrc::DMA_ETHERNET_Rx : return DMA_INT_TO_IRQ_ID(0x21);
case IntSrc::DMA_SCSI_MESH : return INT_TO_IRQ_ID(0x00);
case IntSrc::DMA_SWIM3 : return INT_TO_IRQ_ID(0x01);
case IntSrc::DMA_IDE0 : return INT_TO_IRQ_ID(0x02);
case IntSrc::DMA_IDE1 : return INT_TO_IRQ_ID(0x03);
case IntSrc::DMA_SCCA_Tx : return INT_TO_IRQ_ID(0x04);
case IntSrc::DMA_SCCA_Rx : return INT_TO_IRQ_ID(0x05);
case IntSrc::DMA_SCCB_Tx : return INT_TO_IRQ_ID(0x06);
case IntSrc::DMA_SCCB_Rx : return INT_TO_IRQ_ID(0x07);
case IntSrc::DMA_DAVBUS_Tx : return INT_TO_IRQ_ID(0x08);
case IntSrc::DMA_DAVBUS_Rx : return INT_TO_IRQ_ID(0x09);
case IntSrc::DMA_ETHERNET_Tx : return INT_TO_IRQ_ID(0x20);
case IntSrc::DMA_ETHERNET_Rx : return INT_TO_IRQ_ID(0x21);
default:
ABORT_F("Heathrow: unknown DMA interrupt source %d", src_id);
}
return 0;
}
void HeathrowIC::ack_int(uint32_t irq_id, uint8_t irq_line_state)
void HeathrowIC::ack_int_common(uint64_t irq_id, uint8_t irq_line_state)
{
#if 1
if (!IS_INT1(irq_id)) { // does this irq_id belong to the second set?
IRQ_ID_TO_INT2_MASK(irq_id);
// native mode: set IRQ bits in int_events on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events on all transitions
#if 0
LOG_F(INFO, "%s: native interrupt events:%08x.%08x levels:%08x.%08x change2:%08x state:%d",
this->name.c_str(), this->int_events1 + 0, this->int_events2 + 0,
this->int_levels1 + 0, this->int_levels2 + 0, irq_id, irq_line_state
);
LOG_F(INTERRUPT, "%s: native interrupt events:%08x.%08x levels:%08x.%08x change:%08x.%08x state:%d",
this->name.c_str(), uint32_t(this->int_events >> 32), uint32_t(this->int_events), uint32_t(this->int_levels >> 32),
uint32_t(this->int_levels), uint32_t(irq_id >> 32), uint32_t(irq_id), irq_line_state
);
#endif
// native mode: set IRQ bits in int_events2 on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events2 on all transitions
if ((this->int_mask1 & MACIO_INT_MODE) ||
(irq_line_state && !(this->int_levels2 & irq_id))) {
this->int_events2 |= irq_id;
} else {
this->int_events2 &= ~irq_id;
}
// update IRQ line state
if (irq_line_state) {
this->int_levels2 |= irq_id;
} else {
this->int_levels2 &= ~irq_id;
}
if ((this->int_mask & MACIO_INT_MODE) ||
(irq_line_state && !(this->int_levels & irq_id))) {
this->int_events |= irq_id;
} else {
IRQ_ID_TO_INT1_MASK(irq_id);
// native mode: set IRQ bits in int_events1 on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events1 on all transitions
#if 0
LOG_F(INFO, "%s: native interrupt events:%08x.%08x levels:%08x.%08x change1:%08x state:%d",
this->name.c_str(), this->int_events1 + 0, this->int_events2 + 0,
this->int_levels1 + 0, this->int_levels2 + 0, irq_id, irq_line_state);
#endif
if ((this->int_mask1 & MACIO_INT_MODE) ||
(irq_line_state && !(this->int_levels1 & irq_id))) {
this->int_events1 |= irq_id;
} else {
this->int_events1 &= ~irq_id;
}
// update IRQ line state
if (irq_line_state) {
this->int_levels1 |= irq_id;
} else {
this->int_levels1 &= ~irq_id;
}
this->int_events &= ~irq_id;
}
// update IRQ line state
if (irq_line_state) {
this->int_levels |= irq_id;
} else {
this->int_levels &= ~irq_id;
}
this->signal_cpu_int();
#endif
#if 0
if (this->int_mask1 & MACIO_INT_MODE) { // 68k interrupt emulation mode?
if (!IS_INT1(irq_id)) {
IRQ_ID_TO_INT2_MASK(irq_id);
this->int_events2 |= irq_id; // signal IRQ line change
this->int_events2 &= this->int_mask2;
// update IRQ line state
if (irq_line_state) {
this->int_levels2 |= irq_id;
} else {
this->int_levels2 &= ~irq_id;
}
} else {
IRQ_ID_TO_INT1_MASK(irq_id);
this->int_events1 |= irq_id; // signal IRQ line change
this->int_events1 &= this->int_mask1;
// update IRQ line state
if (irq_line_state) {
this->int_levels1 |= irq_id;
} else {
this->int_levels1 &= ~irq_id;
}
}
this->signal_cpu_int();
} else {
LOG_F(WARNING, "%s: native interrupt mode not implemented", this->name.c_str());
}
#endif
}
void HeathrowIC::ack_dma_int(uint32_t irq_id, uint8_t irq_line_state)
void HeathrowIC::ack_int(uint64_t irq_id, uint8_t irq_line_state)
{
#if 1
if (!IS_DMA_INT1(irq_id)) {
DMA_IRQ_ID_TO_INT2_MASK(irq_id);
// native mode: set IRQ bits in int_events2 on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events2 on all transitions
if ((this->int_mask1 & MACIO_INT_MODE) ||
(irq_line_state && !(this->int_levels2 & irq_id))) {
this->int_events2 |= irq_id;
} else {
this->int_events2 &= ~irq_id;
}
// update IRQ line state
if (irq_line_state) {
this->int_levels2 |= irq_id;
} else {
this->int_levels2 &= ~irq_id;
}
} else {
DMA_IRQ_ID_TO_INT1_MASK(irq_id);
// native mode: set IRQ bits in int_events1 on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events1 on all transitions
if ((this->int_mask1 & MACIO_INT_MODE) ||
(irq_line_state && !(this->int_levels1 & irq_id))) {
this->int_events1 |= irq_id;
} else {
this->int_events1 &= ~irq_id;
}
// update IRQ line state
if (irq_line_state) {
this->int_levels1 |= irq_id;
} else {
this->int_levels1 &= ~irq_id;
}
}
this->ack_int_common(irq_id, irq_line_state);
}
this->signal_cpu_int();
#endif
#if 0
if (this->int_mask1 & MACIO_INT_MODE) { // 68k interrupt emulation mode?
if (!IS_DMA_INT1(irq_id)) {
DMA_IRQ_ID_TO_INT2_MASK(irq_id);
this->int_events2 |= irq_id; // signal IRQ line change
this->int_events2 &= this->int_mask2;
// update IRQ line state
if (irq_line_state) {
this->int_levels2 |= irq_id;
} else {
this->int_levels2 &= ~irq_id;
}
} else {
DMA_IRQ_ID_TO_INT1_MASK(irq_id);
this->int_events1 |= irq_id; // signal IRQ line change
this->int_events1 &= this->int_mask1;
// update IRQ line state
if (irq_line_state) {
this->int_levels1 |= irq_id;
} else {
this->int_levels1 &= ~irq_id;
}
}
this->signal_cpu_int();
} else {
ABORT_F("%s: native interrupt mode not implemented", this->name.c_str());
}
#endif
void HeathrowIC::ack_dma_int(uint64_t irq_id, uint8_t irq_line_state)
{
this->ack_int_common(irq_id, irq_line_state);
}
void HeathrowIC::signal_cpu_int() {
if ((this->int_events1 & this->int_mask1) || (this->int_events2 & this->int_mask2)) {
if (this->int_events & this->int_mask) {
if (!this->cpu_int_latch) {
this->cpu_int_latch = true;
ppc_assert_int();
@@ -644,8 +502,7 @@ void HeathrowIC::signal_cpu_int() {
void HeathrowIC::clear_cpu_int()
{
if (!(this->int_events1 & this->int_mask1) && !(this->int_events2 & this->int_mask2) &&
this->cpu_int_latch) {
if (!(this->int_events & this->int_mask) && this->cpu_int_latch) {
this->cpu_int_latch = false;
ppc_release_int();
LOG_F(5, "Heathrow: CPU INT latch cleared");

View File

@@ -144,17 +144,17 @@ public:
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size);
// InterruptCtrl methods
uint32_t register_dev_int(IntSrc src_id);
uint32_t register_dma_int(IntSrc src_id);
void ack_int(uint32_t irq_id, uint8_t irq_line_state);
void ack_dma_int(uint32_t irq_id, uint8_t irq_line_state);
void attach_iodevice(int dev_num, IobusDevice* dev_obj);
uint64_t register_dev_int(IntSrc src_id) override;
uint64_t register_dma_int(IntSrc src_id) override;
void ack_int(uint64_t irq_id, uint8_t irq_line_state) override;
void ack_dma_int(uint64_t irq_id, uint8_t irq_line_state) override;
protected:
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 ack_int_common(uint64_t irq_id, uint8_t irq_line_state);
void signal_cpu_int(uint64_t irq_id);
void clear_cpu_int();
private:
@@ -208,19 +208,26 @@ public:
}
// MMIO device methods
uint32_t read(uint32_t rgn_start, uint32_t offset, int size);
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size);
uint32_t read(uint32_t rgn_start, uint32_t offset, int size) override;
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) override;
// InterruptCtrl methods
uint32_t register_dev_int(IntSrc src_id);
uint32_t register_dma_int(IntSrc src_id);
void ack_int(uint32_t irq_id, uint8_t irq_line_state);
void ack_dma_int(uint32_t irq_id, uint8_t irq_line_state);
uint64_t register_dev_int(IntSrc src_id) override;
uint64_t register_dma_int(IntSrc src_id) override;
void ack_int(uint64_t irq_id, uint8_t irq_line_state) override;
void ack_dma_int(uint64_t irq_id, uint8_t irq_line_state) override;
protected:
void notify_bar_change(int bar_num);
uint32_t read_ctrl(uint32_t offset, int size);
void write_ctrl(uint32_t offset, uint32_t value, int size);
void ack_int_common(uint64_t irq_id, uint8_t irq_line_state);
uint32_t mio_ctrl_read(uint32_t offset, int size);
uint32_t mio_ctrl_read_aligned(uint32_t offset);
void mio_ctrl_write(uint32_t offset, uint32_t value, int size);
uint32_t dma_read(uint32_t offset, int size);
void dma_write(uint32_t offset, uint32_t value, int size);
@@ -235,6 +242,7 @@ private:
std::atomic<uint32_t> int_levels{0};
std::atomic<uint32_t> int_events{0};
bool cpu_int_latch = false;
uint32_t feat_ctrl = 0; // features control register
std::unique_ptr<AwacsScreamer> awacs; // AWACS audio codec instance
std::unique_ptr<DMAChannel> snd_out_dma;
@@ -350,14 +358,14 @@ public:
void set_media_bay_id(uint8_t id);
// MMIO device methods
uint32_t read(uint32_t rgn_start, uint32_t offset, int size);
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size);
uint32_t read(uint32_t rgn_start, uint32_t offset, int size) override;
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) override;
// InterruptCtrl methods
uint32_t register_dev_int(IntSrc src_id);
uint32_t register_dma_int(IntSrc src_id);
void ack_int(uint32_t irq_id, uint8_t irq_line_state);
void ack_dma_int(uint32_t irq_id, uint8_t irq_line_state);
uint64_t register_dev_int(IntSrc src_id) override;
uint64_t register_dma_int(IntSrc src_id) override;
void ack_int(uint64_t irq_id, uint8_t irq_line_state) override;
void ack_dma_int(uint64_t irq_id, uint8_t irq_line_state) override;
protected:
uint32_t dma_read(uint32_t offset, int size);
@@ -367,23 +375,24 @@ protected:
void mio_ctrl_write(uint32_t offset, uint32_t value, int size);
void notify_bar_change(int bar_num);
void ack_int_common(uint64_t irq_id, uint8_t irq_line_state);
void feature_control(const uint32_t value);
void feature_control(uint32_t value);
void signal_cpu_int();
void clear_cpu_int();
private:
uint32_t base_addr = 0;
std::atomic<uint32_t> int_events2{0};
uint32_t int_mask2 = 0;
std::atomic<uint32_t> int_levels2{0};
std::atomic<uint32_t> int_events1{0};
uint32_t int_mask1 = 0;
std::atomic<uint32_t> int_levels1{0};
// interrupt state
uint64_t int_mask = 0;
std::atomic<uint64_t> int_levels{0};
std::atomic<uint64_t> int_events{0};
bool cpu_int_latch = false;
uint32_t feat_ctrl = 0; // features control register
uint32_t aux_ctrl = 0; // aux features control register
bool cpu_int_latch = false;
uint8_t cpu_id = 0xE0; // CPUID field (LSB of the MIO_HEAT_ID)
uint8_t mb_id = 0x70; // Media Bay ID (bits 15:8 of the MIO_HEAT_ID)

View File

@@ -217,19 +217,51 @@ void OHare::dma_write(uint32_t offset, uint32_t value, int size)
}
}
uint32_t OHare::register_dev_int(IntSrc src_id)
/*
Commenting out temporarily due to compile issues
void OHare::feature_control(uint32_t value)
{
LOG_F(9, "write %x to MIO:Feat_Ctrl register", value);
this->feat_ctrl = value;
if (!(this->feat_ctrl & 1)) {
LOG_F(9, "%s: Monitor sense enabled", this->get_name().c_str());
} else {
LOG_F(9, "%s: Monitor sense disabled", this->get_name().c_str());
}
}
*/
#define INT_TO_IRQ_ID(intx) (1 << intx)
uint64_t OHare::register_dev_int(IntSrc src_id)
{
LOG_F(ERROR, "OHare: register_dev_int() not implemented");
return 0;
}
uint32_t OHare::register_dma_int(IntSrc src_id)
uint64_t OHare::register_dma_int(IntSrc src_id)
{
LOG_F(ERROR, "OHare: register_dma_int() not implemented");
switch (src_id) {
case IntSrc::DMA_SCSI_MESH: return INT_TO_IRQ_ID(0x00);
case IntSrc::DMA_SWIM3 : return INT_TO_IRQ_ID(0x01);
case IntSrc::DMA_IDE0 : return INT_TO_IRQ_ID(0x02);
//
case IntSrc::DMA_SCCA_Tx : return INT_TO_IRQ_ID(0x04);
case IntSrc::DMA_SCCA_Rx : return INT_TO_IRQ_ID(0x05);
case IntSrc::DMA_SCCB_Tx : return INT_TO_IRQ_ID(0x06);
case IntSrc::DMA_SCCB_Rx : return INT_TO_IRQ_ID(0x07);
case IntSrc::DMA_DAVBUS_Tx: return INT_TO_IRQ_ID(0x08);
case IntSrc::DMA_DAVBUS_Rx: return INT_TO_IRQ_ID(0x09);
default:
ABORT_F("%s: unknown DMA interrupt source %d", this->name.c_str(), src_id);
}
return 0;
}
void OHare::ack_int(uint32_t irq_id, uint8_t irq_line_state)
void OHare::ack_int_common(uint64_t irq_id, uint8_t irq_line_state)
{
// native mode: set IRQ bits in int_events1 on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events1 on all transitions
@@ -240,22 +272,22 @@ void OHare::ack_int(uint32_t irq_id, uint8_t irq_line_state)
#endif
if ((this->int_mask & MACIO_INT_MODE) ||
(irq_line_state && !(this->int_levels & irq_id))) {
this->int_events |= irq_id;
this->int_events |= (uint32_t)irq_id;
} else {
this->int_events &= ~irq_id;
this->int_events &= ~(uint32_t)irq_id;
}
this->int_events &= this->int_mask;
// update IRQ line state
if (irq_line_state) {
this->int_levels |= irq_id;
this->int_levels |= (uint32_t)irq_id;
} else {
this->int_levels &= ~irq_id;
this->int_levels &= ~(uint32_t)irq_id;
}
this->signal_cpu_int();
}
void OHare::ack_dma_int(uint32_t irq_id, uint8_t irq_line_state)
void OHare::ack_int(uint64_t irq_id, uint8_t irq_line_state)
{
// native mode: set IRQ bits in int_events1 on a 0-to-1 transition
// emulated mode: set IRQ bits in int_events1 on all transitions
@@ -272,8 +304,12 @@ void OHare::ack_dma_int(uint32_t irq_id, uint8_t irq_line_state)
} else {
this->int_levels &= ~irq_id;
}
this->ack_int_common(irq_id, irq_line_state);
}
this->signal_cpu_int();
void OHare::ack_dma_int(uint64_t irq_id, uint8_t irq_line_state)
{
this->ack_int_common(irq_id, irq_line_state);
}
void OHare::signal_cpu_int() {
@@ -301,7 +337,7 @@ static const std::vector<std::string> OHare_Subdevices = {
};
static const DeviceDescription OHare_Descriptor = {
OHare::create, OHare_Subdevices, {}
};
OHare::create, OHare_Subdevices, {
}};
REGISTER_DEVICE(OHare, OHare_Descriptor);

View File

@@ -103,7 +103,7 @@ protected:
// interrupt suff
InterruptCtrl* int_ctrl = nullptr;
uint32_t irq_id = 0;
uint64_t irq_id = 0;
std::function<void(uint8_t irq_line_state)> vbl_cb = [this](uint8_t irq_line_state) {
if (this->int_ctrl)
this->int_ctrl->ack_int(this->irq_id, irq_line_state);