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 */