diff --git a/devices/ioctrl/amic.cpp b/devices/ioctrl/amic.cpp
index 213cf85..3f671db 100644
--- a/devices/ioctrl/amic.cpp
+++ b/devices/ioctrl/amic.cpp
@@ -1,6 +1,6 @@
/*
DingusPPC - The Experimental PowerPC Macintosh emulator
-Copyright (C) 2018-21 divingkatae and maximum
+Copyright (C) 2018-22 divingkatae and maximum
(theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@@ -24,6 +24,7 @@ along with this program. If not, see .
Author: Max Poliakovski
*/
+#include
#include
#include
#include
@@ -41,7 +42,7 @@ along with this program. If not, see .
#include
#include
-AMIC::AMIC()
+AMIC::AMIC() : MMIODevice()
{
this->name = "Apple Memory-mapped I/O Controller";
@@ -72,14 +73,6 @@ AMIC::AMIC()
this->swim3 = std::unique_ptr (new Swim3::Swim3Ctrl());
}
-bool AMIC::supports_type(HWCompType type) {
- if (type == HWCompType::MMIO_DEV) {
- return true;
- } else {
- return false;
- }
-}
-
uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size)
{
uint32_t phase_val;
@@ -129,6 +122,8 @@ uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size)
return this->def_vid->get_video_mode();
case AMICReg::Monitor_Id:
return this->mon_id;
+ case AMICReg::Int_Ctrl:
+ return (this->int_ctrl & 0xC0) | (this->dev_irq_lines & 0x3F);
case AMICReg::Diag_Reg:
return 0xFFU; // this value allows the machine to boot normally
case AMICReg::SCSI_DMA_Ctrl:
@@ -248,7 +243,13 @@ void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size)
}
break;
case AMICReg::Int_Ctrl:
- LOG_F(INFO, "AMIC Interrupt Control Register set to %X", value);
+ // reset CPU interrupt bit if requested
+ if (value & AMIC_INT_CLR) {
+ this->int_ctrl &= ~AMIC_INT_CLR;
+ }
+ // keep interrupt mode bit
+ // and discard read-only IQR state bits
+ this->int_ctrl |= value & AMIC_INT_MODE;
break;
case AMICReg::DMA_Base_Addr_0:
case AMICReg::DMA_Base_Addr_1:
@@ -290,6 +291,40 @@ void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size)
}
}
+// ======================== Interrupt related stuff ==========================
+uint32_t AMIC::register_dev_int(IntSrc src_id) {
+ switch (src_id) {
+ case IntSrc::VIA_CUDA:
+ return 1;
+ default:
+ ABORT_F("AMIC: unknown interrupt source %d", src_id);
+ }
+ return 0;
+}
+
+uint32_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) {
+ if (this->int_ctrl & AMIC_INT_MODE) { // 68k interrupt emulation mode?
+ this->int_ctrl |= 0x80; // set CPU interrupt bit
+ if (irq_line_state) {
+ this->dev_irq_lines |= irq_id;
+ } else {
+ this->dev_irq_lines &= ~irq_id;
+ }
+ ppc_ext_int();
+ } else {
+ ABORT_F("AMIC: interrupt mode 0 not implemented");
+ }
+}
+
+void AMIC::ack_dma_int(uint32_t irq_id, uint8_t irq_line_state) {
+ ABORT_F("AMIC: ack_dma_int() not implemented");
+}
+
// =========================== DMA related stuff =============================
AmicSndOutDma::AmicSndOutDma()
{
diff --git a/devices/ioctrl/amic.h b/devices/ioctrl/amic.h
index c8bd2f7..8373ab6 100644
--- a/devices/ioctrl/amic.h
+++ b/devices/ioctrl/amic.h
@@ -24,6 +24,7 @@ along with this program. If not, see .
#ifndef AMIC_H
#define AMIC_H
+#include
#include
#include
#include
@@ -37,12 +38,16 @@ along with this program. If not, see .
#include
#include
+/** Interrupt related constants. */
+#define AMIC_INT_CLR 0x80 // clears CPU interrupt
+#define AMIC_INT_MODE 0x40 // interrupt mode: 0 - native, 1 - 68k-style
+
/** AMIC sound buffers are located at fixed offsets from DMA base. */
#define AMIC_SND_BUF0_OFFS 0x10000
#define AMIC_SND_BUF1_OFFS 0x12000
// PDM HWInit source defines two constants: kExpBit = 0x80 and kCmdBit = 0x40
-// I don't know what they means but it seems that their combination will
+// I don't know what they mean but it seems that their combination will
// cause sound control parameters to be transferred to the sound chip.
#define PDM_SND_CTRL_VALID 0xC0
@@ -110,6 +115,7 @@ enum AMICReg : uint32_t {
Pixel_Depth = 0x28001,
Monitor_Id = 0x28002,
+ // Interrupt registers
Int_Ctrl = 0x2A000,
// Undocumented diagnostics register
@@ -131,19 +137,24 @@ enum AMICReg : uint32_t {
};
/** Apple Memory-mapped I/O controller device. */
-class AMIC : public MMIODevice {
+class AMIC : public MMIODevice, public InterruptCtrl {
public:
AMIC();
~AMIC() = default;
- bool supports_type(HWCompType type);
+ bool supports_type(HWCompType type) {
+ return (type == HWCompType::MMIO_DEV) || (type == HWCompType::INT_CTRL);
+ };
/* MMIODevice methods */
uint32_t read(uint32_t reg_start, uint32_t offset, int size);
void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size);
-protected:
- void dma_reg_write(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);
private:
uint8_t imm_snd_regs[4]; // temporary storage for sound control registers
@@ -154,6 +165,9 @@ private:
uint8_t scsi_dma_cs = 0; // SCSI DMA control/status register value
+ uint8_t int_ctrl = 0;
+ uint8_t dev_irq_lines = 0; // state of the IRQ lines
+
// AMIC subdevices instances
std::unique_ptr scsi;
std::unique_ptr escc;
diff --git a/devices/ioctrl/macio.h b/devices/ioctrl/macio.h
index 67385fb..91200f5 100644
--- a/devices/ioctrl/macio.h
+++ b/devices/ioctrl/macio.h
@@ -99,7 +99,7 @@ public:
~HeathrowIC() = default;
bool supports_type(HWCompType type) {
- return type == HWCompType::MMIO_DEV;
+ return (type == HWCompType::MMIO_DEV) || (type == HWCompType::INT_CTRL);
};
/* PCI device methods */