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
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 <https://www.gnu.org/licenses/>.
Author: Max Poliakovski
*/
#include <cpu/ppc/ppcemu.h>
#include <cpu/ppc/ppcmmu.h>
#include <devices/common/scsi/ncr53c94.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 <memory>
AMIC::AMIC()
AMIC::AMIC() : MMIODevice()
{
this->name = "Apple Memory-mapped I/O Controller";
@ -72,14 +73,6 @@ AMIC::AMIC()
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 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()
{

View File

@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef AMIC_H
#define AMIC_H
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h>
#include <devices/common/scsi/ncr53c94.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 <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. */
#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<Ncr53C94> scsi;
std::unique_ptr<EsccController> escc;

View File

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