Reworked interrupts for AMIC and Heathrow

This commit is contained in:
dingusdev 2021-12-17 21:37:27 -07:00
parent 9291a093d5
commit fd6cc0f388
6 changed files with 118 additions and 86 deletions

View File

@ -45,6 +45,7 @@ ViaCuda::ViaCuda() {
this->via_regs[VIA_DIRB] = 0;
this->via_regs[VIA_DIRA] = 0;
this->via_regs[VIA_IER] = 0;
this->via_regs[VIA_SR] = 0;
this->via_regs[VIA_ACR] = 0;
this->via_regs[VIA_PCR] = 0;
this->via_regs[VIA_IFR] = 0;
@ -89,6 +90,20 @@ uint8_t ViaCuda::read(int reg) {
case VIA_ANH:
LOG_F(WARNING, "Attempted read from VIA Port A!");
break;
case VIA_T1CL:
res = this->via_regs[VIA_T1CL];
this->via_regs[VIA_IFR] &= ~IFR_T1;
case VIA_T2CL:
res = this->via_regs[VIA_T2CL];
this->via_regs[VIA_IFR] &= ~IFR_T2;
case VIA_SR:
res = this->via_regs[VIA_SR];
this->via_regs[VIA_IFR] &= ~IFR_SR;
case VIA_IFR:
res = this->via_regs[VIA_IFR];
if (this->via_regs[VIA_IFR] & this->via_regs[VIA_IER])
res |= 0x80;
break;
case VIA_IER:
res |= 0x80; /* bit 7 always reads as "1" */
}

View File

@ -72,6 +72,20 @@ enum {
VIA_ANH = 0x0F, /* input/output register A, no handshake */
};
/** IFR and IER register bits */
enum {
IER_SET = 0x80,
IER_CLR = 0x00,
IFR_CA2 = 0x01,
IFR_CA1 = 0x02,
IFR_SR = 0x04,
IFR_CB2 = 0x08,
IFR_CB1 = 0x10,
IFR_T2 = 0x20,
IFR_T1 = 0x40,
};
/** Cuda communication signals. */
enum {
CUDA_TIP = 0x20, /* transaction in progress: 0 - true, 1 - false */

View File

@ -68,50 +68,53 @@ bool AMIC::supports_type(HWCompType type) {
return false;
}
}
//Interrupt Register
void AMIC::process_interrupt(uint32_t cookie) {
bool confirm_interrupt = false;
uint32_t bit_field = 0;
if (this->int_ctrl_reg & 0x40) {
confirm_interrupt = true;
}
switch (cookie) {
case DEV_ID::PDM_HZTICK:
case DEV_ID::VIA_CUDA:
case DEV_ID::PDM_TIMER2:
case DEV_ID::PDM_TIMER1:
bit_field = (1 << VIA1_Interrupt);
confirm_interrupt = true;
break;
case DEV_ID::NUBUS_SLOT3:
case DEV_ID::NUBUS_SLOT0:
case DEV_ID::NUBUS_SLOT1:
case DEV_ID::NUBUS_SLOT2:
case DEV_ID::SCSI0:
case DEV_ID::SWIM3:
case DEV_ID::SCSI1:
bit_field = (1 << VIA2_Interrupt);
confirm_interrupt = true;
if (this->viacuda->read(VIA_IFR)) {
bit_field = (1 << VIA1_Interrupt);
confirm_interrupt = true;
}
else if (via2_slot_int_enable || via2_int_enable) {
bit_field = (1 << VIA2_Interrupt);
confirm_interrupt = true;
}
break;
case DEV_ID::SCC_B:
case DEV_ID::SCC_A:
bit_field = (1 << SCC_Interrupt);
confirm_interrupt = true;
break;
case DEV_ID::BMAC:
case DEV_ID::ETHERNET:
bit_field = (1 << Eth_Interrupt);
confirm_interrupt = true;
break;
case DEV_ID::SCSI_DMA:
case DEV_ID::Swim3_DMA:
case DEV_ID::IDE0_DMA:
case DEV_ID::IDE1_DMA:
case DEV_ID::ETHERNET_DMA_OUT:
case DEV_ID::ETHERNET_DMA_IN:
case DEV_ID::SCC_A_DMA_OUT:
case DEV_ID::SCC_A_DMA_IN:
case DEV_ID::SCC_B_DMA_OUT:
case DEV_ID::SCC_B_DMA_IN:
if (dma_int_reg0) {
bit_field = (1 << DMA_Interrupt);
confirm_interrupt = true;
}
break;
case DEV_ID::SOUND_DMA_OUT:
case DEV_ID::SOUND_DMA_IN:
case DEV_ID::PERCH_DMA:
bit_field = (1 << DMA_Interrupt);
confirm_interrupt = true;
if (dma_int_reg1) {
bit_field = (1 << DMA_Interrupt);
confirm_interrupt = true;
}
break;
case DEV_ID::NMI:
bit_field = (1 << NMI_Interrupt);
@ -125,9 +128,9 @@ void AMIC::process_interrupt(uint32_t cookie) {
uint32_t AMIC::ack_interrupt(uint32_t device_bits) {
bool confirm_interrupt = false;
bool ack_bit = this->int_mask1 & 0x80;
bool ack_bit = this->int_ctrl_reg & 0x80;
if (device_bits & int_mask1)
if (device_bits & this->int_ctrl_reg)
confirm_interrupt = true;
if (confirm_interrupt && ack_bit)
@ -143,9 +146,11 @@ uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size) {
switch(offset >> 12) {
case 0: // VIA1 registers
case 1:
process_interrupt(VIA_CUDA);
return this->viacuda->read(offset >> 9);
case 4: // SCC registers
this->escc->read_compat((offset >> 1) & 0xF);
this->process_interrupt(SCC_A);
return 0;
case 0xA: // MACE registers
return this->mace->read((offset >> 4) & 0xF);
@ -180,7 +185,10 @@ uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size) {
case AMICReg::SCSI_DMA_Ctrl:
return this->scsi_dma_cs;
case AMICReg::Int_Ctrl:
return this->int_mask1;
if (this->int_ctrl_reg & 0x80) {
ack_cpu_interrupt();
}
return this->int_ctrl_reg;
default:
LOG_F(WARNING, "Unknown AMIC register read, offset=%x", offset);
}
@ -253,6 +261,7 @@ void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size)
return;
case AMICReg::Snd_Out_DMA:
this->snd_out_dma->write_dma_out_ctrl(value);
this->dma_int_reg1 |= 0x2;
this->process_interrupt(DEV_ID::SOUND_DMA_OUT);
return;
}
@ -261,16 +270,22 @@ void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size)
switch(offset) {
case AMICReg::VIA2_Slot_IER:
LOG_F(INFO, "AMIC VIA2 Slot Interrupt Enable Register updated, val=%x", value);
via2_slot_int_enable = value;
break;
case AMICReg::VIA2_IER:
LOG_F(INFO, "AMIC VIA2 Interrupt Enable Register updated, val=%x", value);
via2_int_enable = value;
break;
case AMICReg::Video_Mode_Reg:
LOG_F(INFO, "AMIC Video Mode Register set to %x", value);
break;
case AMICReg::Int_Ctrl:
LOG_F(INFO, "AMIC Interrupt Control Register set to %X", value);
this->int_mask1 = value;
if (value & 0x80) {
value &= 0xC0;
ack_cpu_interrupt();
}
this->int_ctrl_reg = value;
break;
case AMICReg::DMA_Base_Addr_0:
case AMICReg::DMA_Base_Addr_1:

View File

@ -95,13 +95,20 @@ enum AMICReg : uint32_t {
Snd_Out_DMA = 0x14018, // sound output DMA status/control register
// VIA2 registers
VIA2_Slot_INT = 0x26002,
VIA2_Slot_IER = 0x26012,
VIA2_INT = 0x26003,
VIA2_IER = 0x26013,
// Video control registers
Video_Mode_Reg = 0x28000,
// Interrupt registers
Int_Ctrl = 0x2A000,
DMA_Int_0 = 0x2A008,
Bus_Error_Int_0 = 0x2A009,
DMA_Int_1 = 0x2A00A,
Bus_Error_Int_1 = 0x2A00B,
// Undocumented diagnostics register
Diag_Reg = 0x2C000,
@ -132,6 +139,10 @@ enum AMICIntReg : uint32_t {
ACK_Bit = 7,
};
enum {
FDC_PENDING = 0x40,
};
/** Apple Memory-mapped I/O controller device. */
class AMIC : public MMIODevice, public InterruptCtrl {
public:
@ -152,11 +163,16 @@ protected:
private:
uint8_t imm_snd_regs[4]; // temporary storage for sound control registers
uint32_t dma_base = 0; // DMA physical base address
uint16_t snd_buf_size = 0; // sound buffer size in bytes
uint8_t snd_out_ctrl = 0;
uint32_t dma_base = 0; // DMA physical base address
uint16_t snd_buf_size = 0; // sound buffer size in bytes
uint8_t snd_out_ctrl = 0;
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_reg = 0;
uint8_t dma_int_reg0 = 0;
uint8_t dma_int_reg1 = 0;
uint8_t via2_int_enable = 0;
uint8_t via2_slot_int_enable = 0;
// AMIC subdevices instances
std::unique_ptr<Ncr53C94> scsi;

View File

@ -161,9 +161,6 @@ uint32_t HeathrowIC::read(uint32_t reg_start, uint32_t offset, int size) {
case 0x10:
res = this->mesh->read((offset >> 4) & 0xF);
break;
case 0x11: // BMAC
LOG_F(WARNING, "Attempted to read from BMAC: %x \n", (offset - 0x11000));
break;
case 0x12: // ESCC compatible
return this->escc->read_compat((offset >> 4) & 0xF);
case 0x13: // ESCC MacRISC
@ -171,17 +168,10 @@ uint32_t HeathrowIC::read(uint32_t reg_start, uint32_t offset, int size) {
case 0x14:
res = this->screamer->snd_ctrl_read(offset - 0x14000, size);
break;
case 0x15: // BMAC
LOG_F(WARNING, "Attempted to read from SWIM3: %x \n", (offset - 0x15000));
break;
case 0x16:
case 0x17:
res = this->viacuda->read((offset - 0x16000) >> 9);
break;
case 0x20: // IDE
case 0x21:
LOG_F(WARNING, "Attempted to read from IDE: %x \n", (offset - 0x20000));
break;
default:
if (sub_addr >= 0x60) {
res = this->nvram->read_byte((offset - 0x60000) >> 4);
@ -209,9 +199,6 @@ void HeathrowIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int
this->mesh->write((offset >> 4) & 0xF, value);
this->process_interrupt(DEV_ID::SCSI0);
break;
case 0x11: // BMAC
LOG_F(WARNING, "Attempted to write to BMAC: %x \n", (offset - 0x11000));
break;
case 0x12: // ESCC compatible
this->escc->write_compat((offset >> 4) & 0xF, value);
break;
@ -222,18 +209,11 @@ void HeathrowIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int
this->screamer->snd_ctrl_write(offset - 0x14000, value, size);
this->process_interrupt(DEV_ID::DAVBUS);
break;
case 0x15: // SWIM 3
LOG_F(WARNING, "Attempted to write to SWIM 3: %x \n", (offset - 0x15000));
break;
case 0x16:
case 0x17:
this->viacuda->write((offset - 0x16000) >> 9, value);
this->process_interrupt(DEV_ID::VIA_CUDA);
break;
case 0x20: // IDE
case 0x21:
LOG_F(WARNING, "Attempted to write to IDE: %x \n", (offset - 0x20000));
break;
default:
if (sub_addr >= 0x60) {
this->nvram->write_byte((offset - 0x60000) >> 4, value);

View File

@ -27,41 +27,33 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <memory>
enum DEV_ID {
SCSI_DMA = 0,
Swim3_DMA = 1,
IDE0_DMA = 2,
IDE1_DMA = 3,
SCC_A_DMA_OUT = 4,
SCC_A_DMA_IN = 5,
SCC_B_DMA_OUT = 6,
SCC_B_DMA_IN = 7,
SOUND_DMA_OUT = 8,
SOUND_DMA_IN = 9,
VIDEO_OUT = 10,
VIDEO_IN = 11,
SCSI0 = 12,
IDE0 = 13,
IDE1 = 14,
SCC_A = 15,
SCC_B = 16,
DAVBUS = 17,
VIA_CUDA = 18,
SWIM3 = 19,
NMI = 20,
PERCH_DMA = 21,
PERCH = 22,
BMAC_DMA_OUT = 23,
BMAC_DMA_IN = 24,
BMAC = 25,
PDM_HZTICK = 26,
PDM_TIMER2 = 27,
PDM_TIMER1 = 28,
SCSI1 = 29,
NUBUS_SLOT3 = 30,
NUBUS_SLOT0 = 31,
NUBUS_SLOT1 = 32,
NUBUS_SLOT2 = 33,
PDM_VBL = 34,
SCSI_DMA = 0,
Swim3_DMA = 1,
IDE0_DMA = 2,
IDE1_DMA = 3,
SCC_A_DMA_OUT = 4,
SCC_A_DMA_IN = 5,
SCC_B_DMA_OUT = 6,
SCC_B_DMA_IN = 7,
SOUND_DMA_OUT = 8,
SOUND_DMA_IN = 9,
VIDEO_OUT = 10,
VIDEO_IN = 11,
SCSI0 = 12,
IDE0 = 13,
IDE1 = 14,
SCC_A = 15,
SCC_B = 16,
DAVBUS = 17,
VIA_CUDA = 18,
SWIM3 = 19,
NMI = 20,
PERCH_DMA = 21,
PERCH = 22,
ETHERNET_DMA_OUT = 23,
ETHERNET_DMA_IN = 24,
ETHERNET = 25,
SCSI1 = 26,
};
enum REG_ID {