diff --git a/devices/amic.cpp b/devices/amic.cpp
new file mode 100644
index 0000000..b3aa790
--- /dev/null
+++ b/devices/amic.cpp
@@ -0,0 +1,121 @@
+/*
+DingusPPC - The Experimental PowerPC Macintosh emulator
+Copyright (C) 2018-21 divingkatae and maximum
+ (theweirdo) spatium
+
+(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+/** Apple memory-mapped I/O controller emulation.
+
+ Author: Max Poliakovski
+*/
+
+#include "amic.h"
+#include "machines/machinebase.h"
+#include "memctrlbase.h"
+#include "viacuda.h"
+#include
+#include
+
+AMIC::AMIC()
+{
+ this->name = "Apple Memory-mapped I/O Controller";
+
+ MemCtrlBase *mem_ctrl = dynamic_cast
+ (gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
+
+ /* add memory mapped I/O region for the AMIC control registers */
+ if (!mem_ctrl->add_mmio_region(0x50F00000, 0x00040000, this)) {
+ LOG_F(ERROR, "Couldn't register AMIC registers!");
+ }
+
+ this->viacuda = std::unique_ptr (new ViaCuda());
+}
+
+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)
+{
+ if (offset < 0x2000) {
+ return this->viacuda->read(offset >> 9);
+ }
+
+ LOG_F(INFO, "AMIC read!");
+ return 0;
+}
+
+void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size)
+{
+ if (offset < 0x2000) {
+ this->viacuda->write(offset >> 9, value);
+ return;
+ }
+
+ switch(offset) {
+ case AMICReg::Snd_Out_Cntl:
+ LOG_F(INFO, "AMIC Sound Out Ctrl updated, val=%x", value);
+ break;
+ case AMICReg::Snd_In_Cntl:
+ LOG_F(INFO, "AMIC Sound In Ctrl updated, val=%x", value);
+ break;
+ case AMICReg::VIA2_Slot_IER:
+ LOG_F(INFO, "AMIC VIA2 Slot Interrupt Enable Register updated, val=%x", value);
+ break;
+ case AMICReg::VIA2_IER:
+ LOG_F(INFO, "AMIC VIA2 Interrupt Enable Register updated, val=%x", value);
+ break;
+ case AMICReg::Video_Mode_Reg:
+ LOG_F(INFO, "AMIC Video Mode Register set to %x", value);
+ break;
+ case AMICReg::Int_Cntl:
+ LOG_F(INFO, "AMIC Interrupt Control Register set to %X", value);
+ break;
+ case AMICReg::Enet_DMA_Xmt_Cntl:
+ LOG_F(INFO, "AMIC Ethernet Transmit DMA Ctrl updated, val=%x", value);
+ break;
+ case AMICReg::SCSI_DMA_Cntl:
+ LOG_F(INFO, "AMIC SCSI DMA Ctrl updated, val=%x", value);
+ break;
+ case AMICReg::Enet_DMA_Rcv_Cntl:
+ LOG_F(INFO, "AMIC Ethernet Receive DMA Ctrl updated, val=%x", value);
+ break;
+ case AMICReg::SWIM3_DMA_Cntl:
+ LOG_F(INFO, "AMIC SWIM3 DMA Ctrl updated, val=%x", value);
+ break;
+ case AMICReg::SCC_DMA_Xmt_A_Cntl:
+ LOG_F(INFO, "AMIC SCC Transmit Ch A DMA Ctrl updated, val=%x", value);
+ break;
+ case AMICReg::SCC_DMA_Rcv_A_Cntl:
+ LOG_F(INFO, "AMIC SCC Receive Ch A DMA Ctrl updated, val=%x", value);
+ break;
+ case AMICReg::SCC_DMA_Xmt_B_Cntl:
+ LOG_F(INFO, "AMIC SCC Transmit Ch B DMA Ctrl updated, val=%x", value);
+ break;
+ case AMICReg::SCC_DMA_Rcv_B_Cntl:
+ LOG_F(INFO, "AMIC SCC Receive Ch B DMA Ctrl updated, val=%x", value);
+ break;
+ default:
+ LOG_F(WARNING, "Unknown AMIC register write, offset=%x, val=%x",
+ offset, value);
+ }
+}
diff --git a/devices/amic.h b/devices/amic.h
new file mode 100644
index 0000000..88a00c4
--- /dev/null
+++ b/devices/amic.h
@@ -0,0 +1,76 @@
+/*
+DingusPPC - The Experimental PowerPC Macintosh emulator
+Copyright (C) 2018-21 divingkatae and maximum
+ (theweirdo) spatium
+
+(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+/** @file Apple memory-mapped I/O controller emulation. */
+
+#ifndef AMIC_H
+#define AMIC_H
+
+#include "mmiodevice.h"
+#include "viacuda.h"
+#include
+#include
+
+/* AMIC DMA registers offsets from AMIC base (0x50F00000). */
+enum AMICReg : uint32_t {
+ // Sound control registers
+ Snd_Out_Cntl = 0x14010,
+ Snd_In_Cntl = 0x14011,
+
+ // VIA2 registers
+ VIA2_Slot_IER = 0x26012,
+ VIA2_IER = 0x26013,
+
+ // Video control registers
+ Video_Mode_Reg = 0x28000,
+
+ Int_Cntl = 0x2A000,
+
+ // DMA control registers
+ Enet_DMA_Xmt_Cntl = 0x31C20,
+ SCSI_DMA_Cntl = 0x32008,
+ Enet_DMA_Rcv_Cntl = 0x32028,
+ SWIM3_DMA_Cntl = 0x32068,
+ SCC_DMA_Xmt_A_Cntl = 0x32088,
+ SCC_DMA_Rcv_A_Cntl = 0x32098,
+ SCC_DMA_Xmt_B_Cntl = 0x320A8,
+ SCC_DMA_Rcv_B_Cntl = 0x320B8,
+};
+
+class AMIC : public MMIODevice {
+public:
+ AMIC();
+ ~AMIC() = default;
+
+ bool supports_type(HWCompType type);
+
+ /* 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);
+
+private:
+ std::unique_ptr viacuda;
+};
+
+#endif // AMIC_H
diff --git a/devices/machineid.h b/devices/machineid.h
index c5f0ef2..4e6eae1 100644
--- a/devices/machineid.h
+++ b/devices/machineid.h
@@ -35,6 +35,39 @@ along with this program. If not, see .
Register location and value meaning are board-dependent.
*/
+/**
+ Machine ID register for Nubus Power Macs.
+ It's located at physical address 0x5FFFFFFC and contains four bytes:
+ +0 uint16_t signature = 0xA55A
+ +1 uint8_t machine_type (3 - PowerMac)
+ +2 uint8_t model (0x10 = PDM, 0x12 = Carl Sagan, 0x13 = Cold Fusion)
+ */
+class NubusMacID : public MMIODevice {
+public:
+ NubusMacID(const uint16_t id) {
+ this->name = "Nubus-Machine-id";
+ this->id[0] = 0xA5;
+ this->id[1] = 0x5A;
+ this->id[2] = (id >> 8) & 0xFF;
+ this->id[3] = id & 0xFF;
+ };
+ ~NubusMacID() = default;
+
+ bool supports_type(HWCompType type) {
+ return type == HWCompType::MMIO_DEV;
+ };
+
+ uint32_t read(uint32_t reg_start, uint32_t offset, int size) {
+ return (offset < 4 ? this->id[offset] : 0);
+ };
+
+ /* not writable */
+ void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) {};
+
+private:
+ uint8_t id[4];
+};
+
/**
The machine ID for the Gossamer board is accesible at 0xFF000004 (phys).
It contains a 16-bit value revealing machine's capabilities like bus speed,
@@ -57,7 +90,8 @@ public:
return ((!offset && size == 2) ? this->id : 0);
};
- void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size){}; /* not writable */
+ /* not writable */
+ void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) {};
private:
uint16_t id;
diff --git a/machines/machinepdm.cpp b/machines/machinepdm.cpp
index 4810d4a..967d442 100644
--- a/machines/machinepdm.cpp
+++ b/machines/machinepdm.cpp
@@ -25,7 +25,9 @@ along with this program. If not, see .
*/
#include "cpu/ppc/ppcemu.h"
+#include "devices/amic.h"
#include "devices/hmc.h"
+#include "devices/machineid.h"
#include "machinebase.h"
#include "machineproperties.h"
#include
@@ -45,9 +47,19 @@ int create_pdm(std::string& id) {
/* register HMC memory controller */
gMachineObj->add_component("HMC", new HMC);
+ /* register AMIC I/O controller */
+ gMachineObj->add_component("AMIC", new AMIC);
+
/* get raw pointer to HMC object */
HMC* hmc_obj = dynamic_cast(gMachineObj->get_comp_by_name("HMC"));
+ /* allocate machine ID register and tell we're running PowerMac 6100 */
+ // TODO: add a possibility to select another machine
+ // to be used with the same ROM
+ gMachineObj->add_component("MachineID", new NubusMacID(0x3010));
+ hmc_obj->add_mmio_region(0x5FFFFFFC, 4,
+ dynamic_cast(gMachineObj->get_comp_by_name("MachineID")));
+
/* allocate ROM region */
if (!hmc_obj->add_rom_region(0x40000000, 0x400000)) {
LOG_F(ERROR, "Could not allocate ROM region!\n");