diff --git a/devices/hmc.cpp b/devices/hmc.cpp new file mode 100644 index 0000000..52d54d7 --- /dev/null +++ b/devices/hmc.cpp @@ -0,0 +1,70 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-20 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 . +*/ + +/** Highspeed Memory Controller emulation. + + Author: Max Poliakovski +*/ + +#include "hmc.h" + +HMC::HMC() : MemCtrlBase() +{ + this->name = "Highspeed Memory Controller"; + + /* add memory mapped I/O region for the HMC control register */ + add_mmio_region(0x50F40000, 0xFFFF, this); + + this->config_reg = 0ULL; + this->bit_pos = 0; +} + +bool HMC::supports_type(HWCompType type) { + if (type == HWCompType::MEM_CTRL || type == HWCompType::MMIO_DEV) { + return true; + } else { + return false; + } +} + +uint32_t HMC::read(uint32_t reg_start, uint32_t offset, int size) +{ + if (!offset) + return !!(this->config_reg & (1ULL << this->bit_pos++)); + else + return 0; /* FIXME: what should be returned for invalid offsets? */ +} + +void HMC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) +{ + uint64_t bit; + + switch(offset) { + case 0: + bit = 1ULL << this->bit_pos++; + this->config_reg = (value & 1) ? this->config_reg | bit : + this->config_reg & ~bit; + break; + case 8: /* writing to HMCBase + 8 resets internal bit position */ + this->bit_pos = 0; + break; + } +} diff --git a/devices/hmc.h b/devices/hmc.h new file mode 100644 index 0000000..f996e04 --- /dev/null +++ b/devices/hmc.h @@ -0,0 +1,54 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-20 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 . +*/ + +/** Highspeed Memory Controller emulation. + + Author: Max Poliakovski + + Highspeed Memory Controller (HMC) is a custom memory + and L2 cache controller designed especially for the + first generation of the PowerMacintosh computer. +*/ + +#ifndef HMC_H +#define HMC_H + +#include "hwcomponent.h" +#include "memctrlbase.h" +#include "mmiodevice.h" + +class HMC : public MemCtrlBase, public MMIODevice { +public: + HMC(); + ~HMC() = 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); + +private: + int bit_pos; + uint64_t config_reg; +}; + +#endif // HMC_H diff --git a/machines/machinefactory.cpp b/machines/machinefactory.cpp index 743fed8..8d3f501 100644 --- a/machines/machinefactory.cpp +++ b/machines/machinefactory.cpp @@ -36,6 +36,7 @@ along with this program. If not, see . #include #include #include +#include #include #include @@ -76,6 +77,13 @@ static const PropMap GossamerSettings = { new IntProperty( 2, vector({2, 4, 6}))}, }; +static const PropMap PDMSettings = { + {"rambank1_size", + new IntProperty(0, vector({0, 8, 16, 32, 64, 128}))}, + {"rambank2_size", + new IntProperty(0, vector({0, 8, 16, 32, 64, 128}))}, +}; + static const map PropHelp = { {"rambank1_size", "specifies RAM bank 1 size in MB"}, {"rambank2_size", "specifies RAM bank 2 size in MB"}, @@ -83,8 +91,9 @@ static const map PropHelp = { {"gfxmem_size", "specifies video memory size in MB"}, }; -static const map, string>> machines = { - {"pmg3", {GossamerSettings, create_gossamer, "Power Macintosh G3 (Beige)"}}, +static const map, string>> machines = { + {"pm6100", {PDMSettings, create_pdm, "PowerMacintosh 6100"}}, + {"pmg3", {GossamerSettings, create_gossamer, "Power Macintosh G3 (Beige)"}}, }; string machine_name_from_rom(string& rom_filepath) { @@ -267,7 +276,7 @@ int create_machine_for_id(string& id, string& rom_filepath) { auto machine = machines.at(id); /* build machine and load boot ROM */ - if (get<1>(machine)() < 0 || load_boot_rom(rom_filepath) < 0) { + if (get<1>(machine)(id) < 0 || load_boot_rom(rom_filepath) < 0) { return -1; } } catch(out_of_range ex) { diff --git a/machines/machinefactory.h b/machines/machinefactory.h index 7cff1bf..12f44fe 100644 --- a/machines/machinefactory.h +++ b/machines/machinefactory.h @@ -42,6 +42,7 @@ void list_machines(void); void list_properties(void); /* Machine-specific factory functions. */ -int create_gossamer(void); +int create_gossamer(string& id); +int create_pdm(string& id); #endif /* MACHINE_FACTORY_H */ diff --git a/machines/machinegossamer.cpp b/machines/machinegossamer.cpp index 4a3062a..b63d002 100644 --- a/machines/machinegossamer.cpp +++ b/machines/machinegossamer.cpp @@ -35,6 +35,7 @@ along with this program. If not, see . #include "machinebase.h" #include "machineproperties.h" #include +#include static void setup_ram_slot(std::string name, int i2c_addr, int capacity_megs) { @@ -51,7 +52,7 @@ static void setup_ram_slot(std::string name, int i2c_addr, int capacity_megs) { } -int create_gossamer() { +int create_gossamer(std::string& id) { if (gMachineObj) { LOG_F(ERROR, "Global machine object not empty!"); return -1; diff --git a/machines/machinepdm.cpp b/machines/machinepdm.cpp new file mode 100644 index 0000000..48a1316 --- /dev/null +++ b/machines/machinepdm.cpp @@ -0,0 +1,74 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-20 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 Construct a PDM-style PowerMacintosh machine. + + Author: Max Poliakovski + */ + +#include "cpu/ppc/ppcemu.h" +#include "devices/hmc.h" +#include "machinebase.h" +#include "machineproperties.h" +#include + +int create_pdm(std::string& id) { + if (gMachineObj) { + LOG_F(ERROR, "PDM Factory: global machine object not empty!"); + return -1; + } + + LOG_F(INFO, "Initializing the %s hardware...", id.c_str()); + + /* initialize the global machine object */ + gMachineObj.reset(new MachineBase("PDM")); + + /* register HMC memory controller */ + gMachineObj->add_component("HMC", new HMC); + + /* get raw pointer to HMC object */ + HMC* hmc_obj = dynamic_cast(gMachineObj->get_comp_by_name("HMC")); + + /* allocate ROM region */ + if (!hmc_obj->add_rom_region(0x40000000, 0x400000)) { + LOG_F(ERROR, "Could not allocate ROM region!\n"); + return -1; + } + + /* mirror ROM to 0xFFC00000 for a PowerPC CPU to start */ + if (!hmc_obj->add_mem_mirror(0xFFC00000, 0x40000000)) { + LOG_F(ERROR, "Could not create ROM mirror!\n"); + return -1; + } + + /* add 8MB of soldered on-board RAM */ + if (!hmc_obj->add_ram_region(0x00000000, 0x800000)) { + LOG_F(ERROR, "Could not allocate built-in RAM region!\n"); + return -1; + } + + /* Init virtual CPU and request MPC601 */ + ppc_cpu_init(hmc_obj, PPC_VER::MPC601); + + LOG_F(INFO, "Initialization completed.\n"); + + return 0; +}