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");