Add interrupt processing to AMIC.

This commit is contained in:
Maxim Poliakovski 2022-01-10 17:39:24 +01:00
parent d9d8384d4a
commit d61d1d71eb
3 changed files with 66 additions and 17 deletions

View File

@ -1,6 +1,6 @@
/* /*
DingusPPC - The Experimental PowerPC Macintosh emulator DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-21 divingkatae and maximum Copyright (C) 2018-22 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)
@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
Author: Max Poliakovski Author: Max Poliakovski
*/ */
#include <cpu/ppc/ppcemu.h>
#include <cpu/ppc/ppcmmu.h> #include <cpu/ppc/ppcmmu.h>
#include <devices/common/scsi/ncr53c94.h> #include <devices/common/scsi/ncr53c94.h>
#include <devices/common/viacuda.h> #include <devices/common/viacuda.h>
@ -41,7 +42,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <loguru.hpp> #include <loguru.hpp>
#include <memory> #include <memory>
AMIC::AMIC() AMIC::AMIC() : MMIODevice()
{ {
this->name = "Apple Memory-mapped I/O Controller"; this->name = "Apple Memory-mapped I/O Controller";
@ -72,14 +73,6 @@ AMIC::AMIC()
this->swim3 = std::unique_ptr<Swim3::Swim3Ctrl> (new Swim3::Swim3Ctrl()); this->swim3 = std::unique_ptr<Swim3::Swim3Ctrl> (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 AMIC::read(uint32_t reg_start, uint32_t offset, int size)
{ {
uint32_t phase_val; 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(); return this->def_vid->get_video_mode();
case AMICReg::Monitor_Id: case AMICReg::Monitor_Id:
return this->mon_id; return this->mon_id;
case AMICReg::Int_Ctrl:
return (this->int_ctrl & 0xC0) | (this->dev_irq_lines & 0x3F);
case AMICReg::Diag_Reg: case AMICReg::Diag_Reg:
return 0xFFU; // this value allows the machine to boot normally return 0xFFU; // this value allows the machine to boot normally
case AMICReg::SCSI_DMA_Ctrl: 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; break;
case AMICReg::Int_Ctrl: 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; break;
case AMICReg::DMA_Base_Addr_0: case AMICReg::DMA_Base_Addr_0:
case AMICReg::DMA_Base_Addr_1: 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 ============================= // =========================== DMA related stuff =============================
AmicSndOutDma::AmicSndOutDma() AmicSndOutDma::AmicSndOutDma()
{ {

View File

@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef AMIC_H #ifndef AMIC_H
#define AMIC_H #define AMIC_H
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h> #include <devices/common/mmiodevice.h>
#include <devices/common/scsi/ncr53c94.h> #include <devices/common/scsi/ncr53c94.h>
#include <devices/common/viacuda.h> #include <devices/common/viacuda.h>
@ -37,12 +38,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <cinttypes> #include <cinttypes>
#include <memory> #include <memory>
/** 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. */ /** AMIC sound buffers are located at fixed offsets from DMA base. */
#define AMIC_SND_BUF0_OFFS 0x10000 #define AMIC_SND_BUF0_OFFS 0x10000
#define AMIC_SND_BUF1_OFFS 0x12000 #define AMIC_SND_BUF1_OFFS 0x12000
// PDM HWInit source defines two constants: kExpBit = 0x80 and kCmdBit = 0x40 // 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. // cause sound control parameters to be transferred to the sound chip.
#define PDM_SND_CTRL_VALID 0xC0 #define PDM_SND_CTRL_VALID 0xC0
@ -110,6 +115,7 @@ enum AMICReg : uint32_t {
Pixel_Depth = 0x28001, Pixel_Depth = 0x28001,
Monitor_Id = 0x28002, Monitor_Id = 0x28002,
// Interrupt registers
Int_Ctrl = 0x2A000, Int_Ctrl = 0x2A000,
// Undocumented diagnostics register // Undocumented diagnostics register
@ -131,19 +137,24 @@ enum AMICReg : uint32_t {
}; };
/** Apple Memory-mapped I/O controller device. */ /** Apple Memory-mapped I/O controller device. */
class AMIC : public MMIODevice { class AMIC : public MMIODevice, public InterruptCtrl {
public: public:
AMIC(); AMIC();
~AMIC() = default; ~AMIC() = default;
bool supports_type(HWCompType type); bool supports_type(HWCompType type) {
return (type == HWCompType::MMIO_DEV) || (type == HWCompType::INT_CTRL);
};
/* MMIODevice methods */ /* MMIODevice methods */
uint32_t read(uint32_t reg_start, uint32_t offset, int size); 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); void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size);
protected: // InterruptCtrl methods
void dma_reg_write(uint32_t offset, uint32_t value, int size); 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: private:
uint8_t imm_snd_regs[4]; // temporary storage for sound control registers 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 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 // AMIC subdevices instances
std::unique_ptr<Ncr53C94> scsi; std::unique_ptr<Ncr53C94> scsi;
std::unique_ptr<EsccController> escc; std::unique_ptr<EsccController> escc;

View File

@ -99,7 +99,7 @@ public:
~HeathrowIC() = default; ~HeathrowIC() = default;
bool supports_type(HWCompType type) { bool supports_type(HWCompType type) {
return type == HWCompType::MMIO_DEV; return (type == HWCompType::MMIO_DEV) || (type == HWCompType::INT_CTRL);
}; };
/* PCI device methods */ /* PCI device methods */