diff --git a/devices/ioctrl/amic.cpp b/devices/ioctrl/amic.cpp index 7ff5720..97c14bc 100644 --- a/devices/ioctrl/amic.cpp +++ b/devices/ioctrl/amic.cpp @@ -51,14 +51,17 @@ AMIC::AMIC() : MMIODevice() supports_types(HWCompType::MMIO_DEV | HWCompType::INT_CTRL); - // register I/O devices - this->scsi = std::unique_ptr (new Sc53C94()); - gMachineObj->add_subdevice("Curio_SCSI0", this->scsi.get()); + // connect internal SCSI controller + this->scsi = dynamic_cast(gMachineObj->get_comp_by_name("Sc53C94")); - this->escc = std::unique_ptr (new EsccController()); - this->mace = std::unique_ptr (new MaceController(MACE_ID)); - this->viacuda = std::unique_ptr (new ViaCuda()); - gMachineObj->add_subdevice("ViaCuda", this->viacuda.get()); + // connect serial HW + this->escc = dynamic_cast(gMachineObj->get_comp_by_name("Escc")); + + // connect Ethernet HW + this->mace = dynamic_cast(gMachineObj->get_comp_by_name("Mace")); + + // connect Cuda + this->viacuda = dynamic_cast(gMachineObj->get_comp_by_name("ViaCuda")); // initialize sound HW this->snd_out_dma = std::unique_ptr (new AmicSndOutDma()); @@ -69,11 +72,10 @@ AMIC::AMIC() : MMIODevice() this->disp_id = std::unique_ptr (new DisplayID()); this->def_vid = std::unique_ptr (new PdmOnboardVideo()); - // intialize floppy disk HW - this->swim3 = std::unique_ptr (new Swim3::Swim3Ctrl()); + // initialize floppy disk HW + this->swim3 = dynamic_cast(gMachineObj->get_comp_by_name("Swim3")); this->floppy_dma = std::unique_ptr (new AmicFloppyDma()); this->swim3->set_dma_channel(this->floppy_dma.get()); - gMachineObj->add_subdevice("SWIM3", this->swim3.get()); } int AMIC::device_postinit() @@ -530,7 +532,7 @@ DmaPullResult AmicFloppyDma::pull_data(uint32_t req_len, uint32_t *avail_len, } static vector Amic_Subdevices = { - "Swim3", "Escc" + "Sc53C94", "Escc", "Mace", "ViaCuda", "Swim3" }; static const DeviceDescription Amic_Descriptor = { diff --git a/devices/ioctrl/amic.h b/devices/ioctrl/amic.h index 0c5619d..7a55eac 100644 --- a/devices/ioctrl/amic.h +++ b/devices/ioctrl/amic.h @@ -228,13 +228,14 @@ private: uint32_t pseudo_vbl_tid; // ID for the pseudo-VBL timer - // AMIC subdevices instances - std::unique_ptr scsi; - std::unique_ptr escc; - std::unique_ptr mace; - std::unique_ptr viacuda; - std::unique_ptr awacs; + // AMIC subdevice instances + Sc53C94* scsi; + EsccController* escc; + MaceController* mace; + ViaCuda* viacuda; + Swim3::Swim3Ctrl* swim3; + std::unique_ptr awacs; std::unique_ptr snd_out_dma; std::unique_ptr floppy_dma; @@ -242,8 +243,6 @@ private: std::unique_ptr disp_id; std::unique_ptr def_vid; uint8_t mon_id; - - std::unique_ptr swim3; }; #endif // AMIC_H diff --git a/devices/ioctrl/grandcentral.cpp b/devices/ioctrl/grandcentral.cpp index c04a42a..42829c2 100644 --- a/devices/ioctrl/grandcentral.cpp +++ b/devices/ioctrl/grandcentral.cpp @@ -48,13 +48,11 @@ GrandCentral::GrandCentral() : PCIDevice("mac-io/grandcentral"), InterruptCtrl() this->notify_bar_change(bar_num); }; - // construct subdevices - this->mace = std::unique_ptr (new MaceController(MACE_ID)); - this->viacuda = std::unique_ptr (new ViaCuda()); - this->nvram = std::unique_ptr (new NVram()); + // NVRAM connection + this->nvram = dynamic_cast(gMachineObj->get_comp_by_name("NVRAM")); - gMachineObj->add_subdevice("ViaCuda", this->viacuda.get()); - gMachineObj->add_subdevice("NVRAM", this->nvram.get()); + // connect Cuda + this->viacuda = dynamic_cast(gMachineObj->get_comp_by_name("ViaCuda")); // initialize sound chip and its DMA output channel, then wire them together this->awacs = std::unique_ptr (new AwacsScreamer()); @@ -65,13 +63,17 @@ GrandCentral::GrandCentral() : PCIDevice("mac-io/grandcentral"), InterruptCtrl() std::bind(&AwacsScreamer::dma_end, this->awacs.get()) ); - this->escc = std::unique_ptr (new EsccController()); + // connect serial HW + this->escc = dynamic_cast(gMachineObj->get_comp_by_name("Escc")); - this->scsi_0 = std::unique_ptr (new Sc53C94()); - gMachineObj->add_subdevice("Curio_SCSI0", this->scsi_0.get()); + // connect SCSI HW + this->scsi_0 = dynamic_cast(gMachineObj->get_comp_by_name("Sc53C94")); - this->swim3 = std::unique_ptr (new Swim3::Swim3Ctrl()); - gMachineObj->add_subdevice("SWIM3", this->swim3.get()); + // connect Ethernet HW + this->mace = dynamic_cast(gMachineObj->get_comp_by_name("Mace")); + + // connect floppy disk HW + this->swim3 = dynamic_cast(gMachineObj->get_comp_by_name("Swim3")); } void GrandCentral::notify_bar_change(int bar_num) @@ -273,7 +275,7 @@ void GrandCentral::ack_dma_int(uint32_t irq_id, uint8_t irq_line_state) } static const vector GCSubdevices = { - "Swim3", "Escc" + "NVRAM", "ViaCuda", "Escc", "Sc53C94", "Mace", "Swim3" }; static const DeviceDescription GC_Descriptor = { diff --git a/devices/ioctrl/heathrow.cpp b/devices/ioctrl/heathrow.cpp index 20d2c2c..bd8bb0a 100644 --- a/devices/ioctrl/heathrow.cpp +++ b/devices/ioctrl/heathrow.cpp @@ -60,11 +60,11 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow"), InterruptCtrl() this->notify_bar_change(bar_num); }; - this->nvram = std::unique_ptr (new NVram()); - gMachineObj->add_subdevice("NVRAM", this->nvram.get()); + // NVRAM connection + this->nvram = dynamic_cast(gMachineObj->get_comp_by_name("NVRAM")); - this->viacuda = std::unique_ptr (new ViaCuda()); - gMachineObj->add_subdevice("ViaCuda", this->viacuda.get()); + // connect Cuda + this->viacuda = dynamic_cast(gMachineObj->get_comp_by_name("ViaCuda")); // initialize sound chip and its DMA output channel, then wire them together this->screamer = std::unique_ptr (new AwacsScreamer()); @@ -75,12 +75,14 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow"), InterruptCtrl() std::bind(&AwacsScreamer::dma_end, this->screamer.get()) ); - this->mesh = std::unique_ptr (new MESHController(HeathrowMESHID)); - this->escc = std::unique_ptr (new EsccController()); + // connect SCSI HW + this->mesh = dynamic_cast(gMachineObj->get_comp_by_name("Mesh")); - // intialize floppy disk HW - this->swim3 = std::unique_ptr (new Swim3::Swim3Ctrl()); - gMachineObj->add_subdevice("SWIM3", this->swim3.get()); + // connect serial HW + this->escc = dynamic_cast(gMachineObj->get_comp_by_name("Escc")); + + // connect floppy disk HW + this->swim3 = dynamic_cast(gMachineObj->get_comp_by_name("Swim3")); } void HeathrowIC::notify_bar_change(int bar_num) @@ -359,7 +361,7 @@ void HeathrowIC::ack_dma_int(uint32_t irq_id, uint8_t irq_line_state) } static const vector Heathrow_Subdevices = { - "Swim3", "Escc" + "NVRAM", "ViaCuda", "Mesh", "Escc", "Swim3" }; static const DeviceDescription Heathrow_Descriptor = { diff --git a/devices/ioctrl/macio.h b/devices/ioctrl/macio.h index c994d64..c76fb04 100644 --- a/devices/ioctrl/macio.h +++ b/devices/ioctrl/macio.h @@ -116,14 +116,15 @@ private: uint32_t nvram_addr_hi; - // device cells - std::unique_ptr mace; + // subdevice objects std::unique_ptr awacs; // AWACS audio codec instance - std::unique_ptr viacuda; // VIA cell with Cuda MCU attached to it - std::unique_ptr nvram; // NVRAM module - std::unique_ptr escc; // ESCC serial controller - std::unique_ptr scsi_0; // external SCSI - std::unique_ptr swim3; // floppy disk controller + + NVram* nvram; // NVRAM module + MaceController* mace; + ViaCuda* viacuda; // VIA cell with Cuda MCU attached to it + EsccController* escc; // ESCC serial controller + Sc53C94* scsi_0; // external SCSI + Swim3::Swim3Ctrl* swim3; // floppy disk controller std::unique_ptr snd_out_dma; }; @@ -194,15 +195,17 @@ private: uint32_t feat_ctrl = 0; // features control register uint32_t aux_ctrl = 0; // aux features control register - /* device cells */ - std::unique_ptr viacuda; // VIA cell with Cuda MCU attached to it - std::unique_ptr nvram; // NVRAM cell + // subdevice objects std::unique_ptr screamer; // Screamer audio codec instance - std::unique_ptr mesh; // MESH SCSI cell instance - std::unique_ptr escc; // ESCC serial controller - std::unique_ptr swim3; // floppy disk controller + //std::unique_ptr mesh; // MESH SCSI cell instance - std::unique_ptr snd_out_dma; + NVram* nvram; // NVRAM + ViaCuda* viacuda; // VIA cell with Cuda MCU attached to it + MESHController* mesh; // MESH SCSI cell instance + EsccController* escc; // ESCC serial controller + Swim3::Swim3Ctrl* swim3; // floppy disk controller + + std::unique_ptr snd_out_dma; }; #endif /* MACIO_H */ diff --git a/devices/video/atirage.cpp b/devices/video/atirage.cpp index 6f54aa3..2d81fe4 100644 --- a/devices/video/atirage.cpp +++ b/devices/video/atirage.cpp @@ -22,6 +22,7 @@ along with this program. If not, see . #include #include #include +#include #include #include #include @@ -89,14 +90,14 @@ static const std::map mach64_reg_names = { }; -ATIRage::ATIRage(uint16_t dev_id, uint32_t vmem_size_mb) +ATIRage::ATIRage(uint16_t dev_id) : PCIDevice("ati-rage"), VideoCtrlBase(1024, 768) { uint8_t asic_id; supports_types(HWCompType::MMIO_DEV | HWCompType::PCI_DEV); - this->vram_size = vmem_size_mb << 20; // convert MBs to bytes + this->vram_size = GET_INT_PROP("gfxmem_size") << 20; // convert MBs to bytes /* allocate video RAM */ this->vram_ptr = std::unique_ptr (new uint8_t[this->vram_size]); @@ -590,3 +591,21 @@ void ATIRage::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) { } } } + +static const PropMap AtiRage_Properties = { + {"gfxmem_size", + new IntProperty( 2, vector({2, 4, 6}))}, + {"mon_id", + new StrProperty("")}, +}; + +static const DeviceDescription AtiRageGT_Descriptor = { + ATIRage::create_gt, {}, AtiRage_Properties +}; + +static const DeviceDescription AtiRagePro_Descriptor = { + ATIRage::create_pro, {}, AtiRage_Properties +}; + +REGISTER_DEVICE(AtiRageGT, AtiRageGT_Descriptor); +REGISTER_DEVICE(AtiRagePro, AtiRagePro_Descriptor); diff --git a/devices/video/atirage.h b/devices/video/atirage.h index 6f10e89..a6825cf 100644 --- a/devices/video/atirage.h +++ b/devices/video/atirage.h @@ -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) @@ -44,9 +44,17 @@ enum { class ATIRage : public PCIDevice, public VideoCtrlBase { public: - ATIRage(uint16_t dev_id, uint32_t vmem_size_mb); + ATIRage(uint16_t dev_id); ~ATIRage() = default; + static std::unique_ptr create_gt() { + return std::unique_ptr(new ATIRage(ATI_RAGE_GT_DEV_ID)); + } + + static std::unique_ptr create_pro() { + return std::unique_ptr(new ATIRage(ATI_RAGE_PRO_DEV_ID)); + } + /* 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); @@ -91,4 +99,5 @@ private: int comp_index; /* color component index for DAC palette access */ }; + #endif /* ATI_RAGE_H */ diff --git a/machines/machinebase.cpp b/machines/machinebase.cpp index 6f234dd..de6c39a 100644 --- a/machines/machinebase.cpp +++ b/machines/machinebase.cpp @@ -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) @@ -33,59 +33,28 @@ MachineBase::MachineBase(std::string name) { this->name = name; /* initialize internal maps */ - this->comp_map.clear(); - this->subdev_map.clear(); - this->aliases.clear(); + this->device_map.clear(); } MachineBase::~MachineBase() { - for (auto it = this->comp_map.begin(); it != this->comp_map.end(); it++) { - delete it->second; - } - this->comp_map.clear(); - this->aliases.clear(); - this->subdev_map.clear(); + this->device_map.clear(); } -bool MachineBase::add_component(std::string name, HWComponent* dev_obj) { - if (this->comp_map.count(name)) { - LOG_F(ERROR, "Component %s already exists!", name.c_str()); - return false; +void MachineBase::add_device(std::string name, std::unique_ptr dev_obj) { + if (this->device_map.count(name)) { + LOG_F(ERROR, "Device %s already exists!", name.c_str()); + return; } - this->comp_map[name] = dev_obj; - - return true; -} - -bool MachineBase::add_subdevice(std::string name, HWComponent* dev_obj) { - if (this->subdev_map.count(name)) { - LOG_F(ERROR, "Subdevice %s already exists!", name.c_str()); - return false; - } - - this->subdev_map[name] = dev_obj; - - return true; -} - -void MachineBase::add_alias(std::string name, std::string alias) { - this->aliases[alias] = name; + this->device_map[name] = std::move(dev_obj); } HWComponent* MachineBase::get_comp_by_name(std::string name) { - if (this->aliases.count(name)) { - name = this->aliases[name]; - } - - if (this->comp_map.count(name)) { - return this->comp_map[name]; - } - - if (this->subdev_map.count(name)) { - return this->subdev_map[name]; + if (this->device_map.count(name)) { + return this->device_map[name].get(); } else { - return NULL; + LOG_F(WARNING, "Component name %s not found!", name.c_str()); + return nullptr; } } @@ -93,19 +62,7 @@ HWComponent* MachineBase::get_comp_by_type(HWCompType type) { std::string comp_name; bool found = false; - for (auto it = this->comp_map.begin(); it != this->comp_map.end(); it++) { - if (it->second->supports_type(type)) { - comp_name = it->first; - found = true; - break; - } - } - - if (found) { - return this->get_comp_by_name(comp_name); - } - - for (auto it = this->subdev_map.begin(); it != this->subdev_map.end(); it++) { + for (auto it = this->device_map.begin(); it != this->device_map.end(); it++) { if (it->second->supports_type(type)) { comp_name = it->first; found = true; @@ -116,19 +73,14 @@ HWComponent* MachineBase::get_comp_by_type(HWCompType type) { if (found) { return this->get_comp_by_name(comp_name); } else { - return NULL; + LOG_F(WARNING, "No component of type %lu was found!", type); + return nullptr; } } int MachineBase::postinit_devices() { - for (auto it = this->comp_map.begin(); it != this->comp_map.end(); it++) { - if (it->second->device_postinit()) { - return -1; - } - } - - for (auto it = this->subdev_map.begin(); it != this->subdev_map.end(); it++) { + for (auto it = this->device_map.begin(); it != this->device_map.end(); it++) { if (it->second->device_postinit()) { return -1; } diff --git a/machines/machinebase.h b/machines/machinebase.h index 1154fd2..6eed511 100644 --- a/machines/machinebase.h +++ b/machines/machinebase.h @@ -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) @@ -38,18 +38,14 @@ public: MachineBase(std::string name); ~MachineBase(); - bool add_component(std::string name, HWComponent* dev_obj); - bool add_subdevice(std::string name, HWComponent* dev_obj); - void add_alias(std::string name, std::string alias); + void add_device(std::string name, std::unique_ptr dev_obj); HWComponent* get_comp_by_name(std::string name); HWComponent* get_comp_by_type(HWCompType type); int postinit_devices(); private: std::string name; - std::map comp_map; - std::map subdev_map; - std::map aliases; + std::map> device_map; }; extern std::unique_ptr gMachineObj; diff --git a/machines/machinecatalyst.cpp b/machines/machinecatalyst.cpp index 34d1a0d..63240ef 100644 --- a/machines/machinecatalyst.cpp +++ b/machines/machinecatalyst.cpp @@ -26,48 +26,24 @@ along with this program. If not, see . #include #include #include -#include #include #include +#include #include +#include #include -int create_catalyst(std::string& id) +int initialize_catalyst(std::string& id) { PlatinumCtrl* platinum_obj; - if (gMachineObj) { - LOG_F(ERROR, "Global machine object not empty!"); - return -1; - } - - LOG_F(INFO, "Initializing the Catalyst hardware..."); - - // initialize the global machine object - gMachineObj.reset(new MachineBase("Catalyst")); - - // add memory controller - gMachineObj->add_component("Platinum", new PlatinumCtrl()); - - // add the ARBus-to-PCI bridge - gMachineObj->add_component("Bandit1", new Bandit(1, "Bandit-PCI1")); - PCIHost *pci_host = dynamic_cast(gMachineObj->get_comp_by_name("Bandit1")); - // start the sound server - gMachineObj->add_component("SoundServer", new SoundServer()); - // add the GrandCentral I/O controller - gMachineObj->add_component("GrandCentral", new GrandCentral()); pci_host->pci_register_device( 32, dynamic_cast(gMachineObj->get_comp_by_name("GrandCentral"))); - // HACK: attach temporary ATI Mach64 video card - //gMachineObj->add_component("AtiMach64", new AtiMach64Gx); - //pci_host->pci_register_device( - // 4, dynamic_cast(gMachineObj->get_comp_by_name("AtiMach64"))); - // get (raw) pointer to the memory controller platinum_obj = dynamic_cast(gMachineObj->get_comp_by_name("Platinum")); @@ -84,18 +60,39 @@ int create_catalyst(std::string& id) platinum_obj->map_phys_ram(); // add single SCSI bus - gMachineObj->add_component("SCSI0", new ScsiBus); + gMachineObj->add_device("SCSI0", std::unique_ptr(new ScsiBus())); // init virtual CPU and request MPC601 ppc_cpu_init(platinum_obj, PPC_VER::MPC601, 7833600ULL); - // post-initialize all devices - if (gMachineObj->postinit_devices()) { - LOG_F(ERROR, "Could not post-initialize devices!\n"); - return -1; - } - - LOG_F(INFO, "Initialization complete.\n"); - return 0; } + +static const PropMap pm7200_settings = { + {"rambank1_size", + new IntProperty(16, vector({4, 8, 16, 32, 64, 128}))}, + {"rambank2_size", + new IntProperty( 0, vector({0, 4, 8, 16, 32, 64, 128}))}, + {"rambank3_size", + new IntProperty( 0, vector({0, 4, 8, 16, 32, 64, 128}))}, + {"rambank4_size", + new IntProperty( 0, vector({0, 4, 8, 16, 32, 64, 128}))}, + {"gfxmem_size", + new IntProperty( 1, vector({1, 2, 4}))}, + {"mon_id", + new StrProperty("HiRes12-14in")}, +}; + +static vector pm7200_devices = { + "Platinum", "Bandit1", "GrandCentral" +}; + +static const MachineDescription pm7200_descriptor = { + .name = "pm7200", + .description = "Power Macintosh 7200", + .devices = pm7200_devices, + .settings = pm7200_settings, + .init_func = &initialize_catalyst +}; + +REGISTER_MACHINE(pm7200, pm7200_descriptor); diff --git a/machines/machinefactory.cpp b/machines/machinefactory.cpp index 0a4957c..516dc44 100644 --- a/machines/machinefactory.cpp +++ b/machines/machinefactory.cpp @@ -24,8 +24,11 @@ along with this program. If not, see . Author: Max Poliakovski */ +#include #include +#include #include +#include #include #include #include @@ -56,7 +59,7 @@ static const map> rom_identity = { //{"Come", "PowerBook 2400"}, // Comet {0x436F7264, {"pm5200", "Power Mac 5200/6200 series"}}, // Cordyceps {0x47617A65, {"pm6500", "Power Mac 6500"}}, // Gazelle - {0x476F7373, {"pmg3", "Power Mac G3 Beige"}}, // Gossamer + {0x476F7373, {"pmg3dt", "Power Mac G3 Beige"}}, // Gossamer {0x47525820, {"pbg3", "PowerBook G3 Wallstreet"}}, //{"Hoop", "PowerBook 3400"}, // Hooper {0x50425820, {"pb-preg3", "PowerBook Pre-G3"}}, @@ -67,67 +70,6 @@ static const map> rom_identity = { {0x5A616E7A, {"pm4400", "Power Mac 4400/7220"}}, // Zanzibar }; -static const vector WriteToggle = {"ON", "on", "OFF", "off"}; - -static const vector CharIoBackends = {"null", "stdio"}; - -static const PropMap CatalystSettings = { - {"rambank1_size", - new IntProperty(16, vector({4, 8, 16, 32, 64, 128}))}, - {"rambank2_size", - new IntProperty( 0, vector({0, 4, 8, 16, 32, 64, 128}))}, - {"rambank3_size", - new IntProperty( 0, vector({0, 4, 8, 16, 32, 64, 128}))}, - {"rambank4_size", - new IntProperty( 0, vector({0, 4, 8, 16, 32, 64, 128}))}, - {"gfxmem_size", - new IntProperty( 1, vector({1, 2, 4}))}, - {"mon_id", - new StrProperty("HiRes12-14in")}, - {"fdd_img", - new StrProperty("")}, - {"serial_backend", new StrProperty("null", CharIoBackends)}, -}; - -static const PropMap GossamerSettings = { - {"rambank1_size", - new IntProperty(256, vector({8, 16, 32, 64, 128, 256}))}, - {"rambank2_size", - new IntProperty( 0, vector({0, 8, 16, 32, 64, 128, 256}))}, - {"rambank3_size", - new IntProperty( 0, vector({0, 8, 16, 32, 64, 128, 256}))}, - {"gfxmem_size", - new IntProperty( 2, vector({2, 4, 6}))}, - {"mon_id", - new StrProperty("")}, - {"fdd_img", - new StrProperty("")}, - {"fdd_wr_prot", new StrProperty("OFF", WriteToggle)}, - {"serial_backend", new StrProperty("null", CharIoBackends)}, -}; - -/** Monitors supported by the PDM on-board video. */ -/* see displayid.cpp for the full list of supported monitor IDs. */ -static const vector PDMBuiltinMonitorIDs = { - "PortraitGS", "MacRGB12in", "MacRGB15in", "HiRes12-14in", "VGA-SVGA", - "MacRGB16in", "Multiscan15in", "Multiscan17in", "Multiscan20in", - "NotConnected" -}; - -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}))}, - {"mon_id", - new StrProperty("HiRes12-14in", PDMBuiltinMonitorIDs)}, - {"fdd_img", - new StrProperty("")}, - {"fdd_wr_prot", - new StrProperty("OFF", WriteToggle)}, - {"serial_backend", new StrProperty("null", CharIoBackends)}, -}; - static const map PropHelp = { {"rambank1_size", "specifies RAM bank 1 size in MB"}, {"rambank2_size", "specifies RAM bank 2 size in MB"}, @@ -135,18 +77,182 @@ static const map PropHelp = { {"rambank4_size", "specifies RAM bank 4 size in MB"}, {"gfxmem_size", "specifies video memory size in MB"}, {"fdd_img", "specifies path to floppy disk image"}, - {"fdd_wr_prot", "toggles floppy disks write protection"}, + {"fdd_wr_prot", "toggles floppy disk's write protection"}, {"mon_id", "specifies which monitor to emulate"}, {"serial_backend", "specifies the backend for the serial port"}, }; -static const map, string>> machines = { - {"pm6100", {PDMSettings, create_pdm, "PowerMacintosh 6100"}}, - {"pm7200", {CatalystSettings, create_catalyst, "PowerMacintosh 7200"}}, - {"pmg3", {GossamerSettings, create_gossamer, "Power Macintosh G3 (Beige)"}}, -}; +bool MachineFactory::add(const string& machine_id, MachineDescription desc) +{ + if (get_registry().find(machine_id) != get_registry().end()) { + return false; + } -string machine_name_from_rom(string& rom_filepath) { + get_registry()[machine_id] = desc; + return true; +} + +void MachineFactory::list_machines() +{ + cout << endl << "Supported machines:" << endl << endl; + + for (auto& m : get_registry()) { + cout << setw(13) << m.first << "\t\t" << m.second.description << endl; + } + + cout << endl; +} + +void MachineFactory::create_device(string& dev_name, DeviceDescription& dev) +{ + for (auto& subdev_name : dev.subdev_list) { + create_device(subdev_name, DeviceRegistry::get_descriptor(subdev_name)); + } + + gMachineObj->add_device(dev_name, dev.m_create_func()); +} + +int MachineFactory::create(string& mach_id) +{ + auto it = get_registry().find(mach_id); + if (it == get_registry().end()) { + LOG_F(ERROR, "Unknown machine id %s", mach_id.c_str()); + return -1; + } + + LOG_F(INFO, "Initializing %s hardware...", it->second.description.c_str()); + + // initialize global machine object + gMachineObj.reset(new MachineBase(it->second.name)); + + // create and register sound server + gMachineObj->add_device("SoundServer", std::unique_ptr(new SoundServer())); + + // recursively create device objects + for (auto& dev_name : it->second.devices) { + create_device(dev_name, DeviceRegistry::get_descriptor(dev_name)); + } + + if (it->second.init_func(mach_id)) { + LOG_F(ERROR, "Machine initialization function failed!"); + return -1; + } + + // post-initialize all devices + if (gMachineObj->postinit_devices()) { + LOG_F(ERROR, "Could not post-initialize devices!\n"); + return -1; + } + + LOG_F(INFO, "Initialization completed.\n"); + + return 0; +} + +void MachineFactory::list_properties() +{ + cout << endl; + + for (auto& mach : get_registry()) { + cout << mach.second.description << " supported properties:" << endl << endl; + + print_settings(mach.second.settings); + + for (auto& d : mach.second.devices) { + list_device_settings(DeviceRegistry::get_descriptor(d)); + } + } + + cout << endl; +} + +void MachineFactory::list_device_settings(DeviceDescription& dev) +{ + for (auto& d : dev.subdev_list) { + list_device_settings(DeviceRegistry::get_descriptor(d)); + } + + print_settings(dev.properties); +} + +void MachineFactory::print_settings(PropMap& prop_map) +{ + for (auto& p : prop_map) { + cout << setw(13) << p.first << "\t\t" << PropHelp.at(p.first) + << endl; + + cout << setw(13) << "\t\t\t" "Valid values: "; + + switch(p.second->get_type()) { + case PROP_TYPE_INTEGER: + cout << dynamic_cast(p.second)->get_valid_values_as_str() + << endl; + break; + case PROP_TYPE_STRING: + cout << dynamic_cast(p.second)->get_valid_values_as_str() + << endl; + break; + default: + break; + } + cout << endl; + } +} + +void MachineFactory::get_device_settings(DeviceDescription& dev, map &settings) +{ + for (auto& d : dev.subdev_list) { + get_device_settings(DeviceRegistry::get_descriptor(d), settings); + } + + for (auto& p : dev.properties) { + settings[p.first] = p.second->get_string(); + + // populate dynamic machine settings from presets + gMachineSettings[p.first] = unique_ptr(p.second->clone()); + } +} + +int MachineFactory::get_machine_settings(const string& id, map &settings) +{ + auto it = get_registry().find(id); + if (it != get_registry().end()) { + auto props = it->second.settings; + + gMachineSettings.clear(); + + for (auto& p : props) { + settings[p.first] = p.second->get_string(); + + // populate dynamic machine settings from presets + gMachineSettings[p.first] = unique_ptr(p.second->clone()); + } + + for (auto& dev : it->second.devices) { + get_device_settings(DeviceRegistry::get_descriptor(dev), settings); + } + } else { + LOG_F(ERROR, "Unknown machine id %s", id.c_str()); + return -1; + } + + return 0; +} + +void MachineFactory::set_machine_settings(map &settings) { + for (auto& s : settings) { + gMachineSettings.at(s.first)->set_string(s.second); + } + + // print machine settings summary + cout << endl << "Machine settings summary: " << endl; + + for (auto& p : gMachineSettings) { + cout << p.first << " : " << p.second->get_string() << endl; + } +} + +string MachineFactory::machine_name_from_rom(string& rom_filepath) { ifstream rom_file; uint32_t file_size, config_info_offset, rom_id; char rom_id_str[17]; @@ -202,96 +308,8 @@ bail_out: return machine_name; } -int get_machine_settings(string& id, map &settings) { - try { - auto props = get<0>(machines.at(id)); - - gMachineSettings.clear(); - - for (auto& p : props) { - settings[p.first] = p.second->get_string(); - - /* populate dynamic machine settings from presets */ - gMachineSettings[p.first] = unique_ptr(p.second->clone()); - } - } - catch(out_of_range ex) { - LOG_F(ERROR, "Unknown machine id %s", id.c_str()); - return -1; - } - return 0; -} - -void set_machine_settings(map &settings) { - for (auto& s : settings) { - gMachineSettings.at(s.first)->set_string(s.second); - } - - /* print machine settings summary */ - cout << endl << "Machine settings summary: " << endl; - - for (auto& p : gMachineSettings) { - cout << p.first << " : " << p.second->get_string() << endl; - } -} - -void list_machines() { - cout << endl << "Supported machines:" << endl << endl; - - for (auto& mach : machines) { - cout << setw(13) << mach.first << "\t\t" << get<2>(mach.second) << endl; - } - - cout << endl; -} - -void list_properties() { - cout << endl; - - for (auto& mach : machines) { - cout << get<2>(mach.second) << " supported properties:" << endl << endl; - - for (auto& p : get<0>(mach.second)) { - cout << setw(13) << p.first << "\t\t" << PropHelp.at(p.first) - << endl; - - cout << setw(13) << "\t\t\t" "Valid values: "; - - switch(p.second->get_type()) { - case PROP_TYPE_INTEGER: - cout << dynamic_cast(p.second)->get_valid_values_as_str() - << endl; - break; - case PROP_TYPE_STRING: - cout << dynamic_cast(p.second)->get_valid_values_as_str() - << endl; - break; - default: - break; - } - cout << endl; - } - } - - cout << endl; -} - /* Read ROM file content and transfer it to the dedicated ROM region */ -void load_rom(std::ifstream& rom_file, uint32_t file_size) { - unsigned char* sysrom_mem = new unsigned char[file_size]; - - rom_file.seekg(0, ios::beg); - rom_file.read((char*)sysrom_mem, file_size); - - MemCtrlBase* mem_ctrl = dynamic_cast( - gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL)); - - mem_ctrl->set_data(0xFFC00000, sysrom_mem, file_size); - delete[] sysrom_mem; -} - -/* Read ROM file content and transfer it to the dedicated ROM region */ -int load_boot_rom(string& rom_filepath) { +int MachineFactory::load_boot_rom(string& rom_filepath) { ifstream rom_file; size_t file_size; int result; @@ -336,17 +354,8 @@ int load_boot_rom(string& rom_filepath) { return result; } - -int create_machine_for_id(string& id, string& rom_filepath) { - try { - auto machine = machines.at(id); - - /* build machine and load boot ROM */ - if (get<1>(machine)(id) < 0 || load_boot_rom(rom_filepath) < 0) { - return -1; - } - } catch(out_of_range ex) { - LOG_F(ERROR, "Unknown machine id %s", id.c_str()); +int MachineFactory::create_machine_for_id(string& id, string& rom_filepath) { + if (MachineFactory::create(id) < 0 || load_boot_rom(rom_filepath) < 0) { return -1; } diff --git a/machines/machinefactory.h b/machines/machinefactory.h index 57460c2..e5d6e58 100644 --- a/machines/machinefactory.h +++ b/machines/machinefactory.h @@ -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) @@ -27,24 +27,58 @@ along with this program. If not, see . #ifndef MACHINE_FACTORY_H #define MACHINE_FACTORY_H +#include #include +#include #include +#include +#include #include +#include using namespace std; -std::string machine_name_from_rom(std::string& rom_filepath); +struct MachineDescription { + string name; + string description; + vector devices; + PropMap settings; + function init_func; +}; -int get_machine_settings(string& id, map &settings); -void set_machine_settings(map &settings); -int create_machine_for_id(string& id, string& rom_filepath); -void list_machines(void); -void list_properties(void); +class MachineFactory +{ +public: + MachineFactory() = delete; -/* Machine-specific factory functions. */ -int create_catalyst(string& id); -int create_gossamer(string& id); -int create_pdm(string& id); + static bool add(const string& machine_id, MachineDescription desc); + + static string machine_name_from_rom(string& rom_filepath); + + static int create(string& mach_id); + static int create_machine_for_id(string& id, string& rom_filepath); + + static int get_machine_settings(const string& id, map &settings); + static void set_machine_settings(map &settings); + + static void list_machines(); + static void list_properties(); + +private: + static void create_device(string& dev_name, DeviceDescription& dev); + static void print_settings(PropMap& p); + static void list_device_settings(DeviceDescription& dev); + static void get_device_settings(DeviceDescription& dev, map &settings); + static int load_boot_rom(string& rom_filepath); + + static map & get_registry() { + static map machine_registry; + return machine_registry; + } +}; + +#define REGISTER_MACHINE(mach_name, mach_desc) \ + static bool mach_name ## _registered = MachineFactory::add(#mach_name, (mach_desc)) #endif /* MACHINE_FACTORY_H */ diff --git a/machines/machinegossamer.cpp b/machines/machinegossamer.cpp index 28c0d89..4b6e50b 100644 --- a/machines/machinegossamer.cpp +++ b/machines/machinegossamer.cpp @@ -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) @@ -34,89 +34,86 @@ along with this program. If not, see . #include #include #include +#include #include +#include #include - static void setup_ram_slot(std::string name, int i2c_addr, int capacity_megs) { if (!capacity_megs) return; - gMachineObj->add_component(name, new SpdSdram168(i2c_addr)); + gMachineObj->add_device(name, std::unique_ptr(new SpdSdram168(i2c_addr))); SpdSdram168* ram_dimm = dynamic_cast(gMachineObj->get_comp_by_name(name)); ram_dimm->set_capacity(capacity_megs); - /* register RAM DIMM with the I2C bus */ + // register RAM DIMM with the I2C bus I2CBus* i2c_bus = dynamic_cast(gMachineObj->get_comp_by_type(HWCompType::I2C_HOST)); i2c_bus->register_device(i2c_addr, ram_dimm); } -int create_gossamer(std::string& id) { - if (gMachineObj) { - LOG_F(ERROR, "Global machine object not empty!"); - return -1; - } - - LOG_F(INFO, "Initializing the Gossamer hardware..."); - - /* initialize the global machine object */ - gMachineObj.reset(new MachineBase("Gossamer")); - - /* register MPC106 aka Grackle as memory controller and PCI host */ - gMachineObj->add_component("Grackle", new MPC106); - gMachineObj->add_alias("Grackle", "PCI_Host"); - - /* get raw pointer to MPC106 object */ +int initialize_gossamer(std::string& id) +{ + // get pointer to the memory controller/PCI host bridge object MPC106* grackle_obj = dynamic_cast(gMachineObj->get_comp_by_name("Grackle")); - /* add the machine ID register */ - gMachineObj->add_component("MachineID", new GossamerID(0xBF3D)); + // add the machine ID register + gMachineObj->add_device("MachineID", std::unique_ptr(new GossamerID(0xBF3D))); grackle_obj->add_mmio_region( 0xFF000004, 4096, dynamic_cast(gMachineObj->get_comp_by_name("MachineID"))); - gMachineObj->add_component("SoundServer", new SoundServer()); - - /* add the Heathrow I/O controller */ - gMachineObj->add_component("Heathrow", new HeathrowIC); + // register the Heathrow I/O controller with the PCI host bridge grackle_obj->pci_register_device( 16, dynamic_cast(gMachineObj->get_comp_by_name("Heathrow"))); - /* allocate ROM region */ + // allocate ROM region if (!grackle_obj->add_rom_region(0xFFC00000, 0x400000)) { LOG_F(ERROR, "Could not allocate ROM region!\n"); return -1; } - /* configure RAM slots */ + // configure RAM slots setup_ram_slot("RAM_DIMM_1", 0x57, GET_INT_PROP("rambank1_size")); setup_ram_slot("RAM_DIMM_2", 0x56, GET_INT_PROP("rambank2_size")); setup_ram_slot("RAM_DIMM_3", 0x55, GET_INT_PROP("rambank3_size")); - /* register ATI 3D Rage Pro video card with the PCI host bridge */ - gMachineObj->add_component("ATIRage", - new ATIRage(ATI_RAGE_PRO_DEV_ID, GET_INT_PROP("gfxmem_size"))); + // select built-in GPU name + std::string gpu_name = "AtiRageGT"; + if (id == "pmg3twr") { + gpu_name = "AtiRagePro"; + } + + // register built-in ATI Rage GPU with the PCI host bridge grackle_obj->pci_register_device( - 18, dynamic_cast(gMachineObj->get_comp_by_name("ATIRage"))); + 18, dynamic_cast(gMachineObj->get_comp_by_name(gpu_name))); - /* Init virtual CPU and request MPC750 CPU aka G3 */ + // initialize virtual CPU and request MPC750 CPU aka G3 ppc_cpu_init(grackle_obj, PPC_VER::MPC750, 16705000ULL); - // post-initialize all devices - if (gMachineObj->postinit_devices()) { - LOG_F(ERROR, "Could not post-initialize devices!\n"); - return -1; - } - - /* check for a floppy image to be inserted into the virtual superdrive */ - std::string fdd_path = GET_STR_PROP("fdd_img"); - std::string fd_write_prot = GET_STR_PROP("fdd_wr_prot"); - if (!fdd_path.empty()) { - open_floppy_image(fdd_path); - } - - LOG_F(INFO, "Initialization complete.\n"); - return 0; } + +static const PropMap gossamer_settings = { + {"rambank1_size", + new IntProperty(256, vector({8, 16, 32, 64, 128, 256}))}, + {"rambank2_size", + new IntProperty( 0, vector({0, 8, 16, 32, 64, 128, 256}))}, + {"rambank3_size", + new IntProperty( 0, vector({0, 8, 16, 32, 64, 128, 256}))}, +}; + +static vector pmg3_devices = { + "Grackle", "Heathrow", "AtiRageGT" +}; + +static const MachineDescription pmg3dt_descriptor = { + .name = "pmg3", + .description = "Power Macintosh G3 (Beige) Desktop", + .devices = pmg3_devices, + .settings = gossamer_settings, + .init_func = &initialize_gossamer +}; + +REGISTER_MACHINE(pmg3dt, pmg3dt_descriptor); diff --git a/machines/machinepdm.cpp b/machines/machinepdm.cpp index 6c244c6..a281033 100644 --- a/machines/machinepdm.cpp +++ b/machines/machinepdm.cpp @@ -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) @@ -27,97 +27,94 @@ along with this program. If not, see . #include #include #include -#include -#include #include -#include #include #include +#include #include #include +#include -int create_pdm(std::string& id) { - if (gMachineObj) { - LOG_F(ERROR, "PDM Factory: global machine object not empty!"); +int initialize_pdm(std::string& id) +{ + uint16_t machine_id; + + // get raw pointer to HMC object + HMC* hmc_obj = dynamic_cast(gMachineObj->get_comp_by_name("HMC")); + + if (id == "pm6100") { + machine_id = 0x3010; + } else if (id == "pm7100") { + machine_id = 0x3012; + } else if (id == "pm8100") { + machine_id = 0x3013; + } else { + LOG_F(ERROR, "Unknown machine ID: %s!", id.c_str()); 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); - - /* start the sound server. */ - gMachineObj->add_component("SoundServer", new SoundServer()); - - /* 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)); + // create machine ID register + //gMachineObj->add_component("MachineID", new NubusMacID(machine_id)); + gMachineObj->add_device("MachineID", std::unique_ptr(new NubusMacID(machine_id))); hmc_obj->add_mmio_region(0x5FFFFFFC, 4, dynamic_cast(gMachineObj->get_comp_by_name("MachineID"))); - /* allocate ROM region */ + // 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 */ + // 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 */ + // 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; } - /* add internal SCSI bus */ - gMachineObj->add_component("SCSI0", new ScsiBus); + // add internal SCSI bus + gMachineObj->add_device("SCSI0", std::unique_ptr(new ScsiBus())); - /* Init virtual CPU and request MPC601 */ + // Init virtual CPU and request MPC601 ppc_cpu_init(hmc_obj, PPC_VER::MPC601, 7812500ULL); - // post-initialize all devices - if (gMachineObj->postinit_devices()) { - LOG_F(ERROR, "Could not post-initialize devices!\n"); - return -1; - } - - // if a floppy image was given "insert" it into the virtual superdrive - std::string fd_image_path = GET_STR_PROP("fdd_img"); - std::string fd_write_prot = GET_STR_PROP("fdd_wr_prot"); - if (!fd_image_path.empty()) { - using namespace MacSuperdrive; - - MacSuperDrive* fdd = dynamic_cast - (gMachineObj->get_comp_by_name("Superdrive")); - - bool write_flag = false; - - if (!fd_write_prot.empty()) { - if ((fd_write_prot.compare("ON") == 0) || (fd_write_prot.compare("on") == 0)) { - write_flag = true; - } - } - - fdd->insert_disk(fd_image_path, write_flag); - } - - LOG_F(INFO, "Initialization completed.\n"); - return 0; } + +// Monitors supported by the PDM on-board video. +// see displayid.cpp for the full list of supported monitor IDs. +static const vector PDMBuiltinMonitorIDs = { + "PortraitGS", "MacRGB12in", "MacRGB15in", "HiRes12-14in", "VGA-SVGA", + "MacRGB16in", "Multiscan15in", "Multiscan17in", "Multiscan20in", + "NotConnected" +}; + +static const PropMap pm6100_settings = { + {"rambank1_size", + new IntProperty(0, vector({0, 8, 16, 32, 64, 128}))}, + {"rambank2_size", + new IntProperty(0, vector({0, 8, 16, 32, 64, 128}))}, + {"mon_id", + new StrProperty("HiRes12-14in", PDMBuiltinMonitorIDs)}, +}; + +static vector pm6100_devices = { + "HMC", "Amic" +}; + +static const MachineDescription pm6100_descriptor = { + .name = "pm6100", + .description = "Power Macintosh 6100", + .devices = pm6100_devices, + .settings = pm6100_settings, + .init_func = initialize_pdm +}; + +// self-registration with the MachineFactory +REGISTER_MACHINE(pm6100, pm6100_descriptor); diff --git a/main.cpp b/main.cpp index f9d0b5a..f77fff3 100644 --- a/main.cpp +++ b/main.cpp @@ -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) @@ -110,9 +110,9 @@ int main(int argc, char** argv) { if (*list_cmd) { if (sub_arg == "machines") { - list_machines(); + MachineFactory::list_machines(); } else if (sub_arg == "properties") { - list_properties(); + MachineFactory::list_properties(); } else { cout << "Unknown list subcommand " << sub_arg << endl; } @@ -142,7 +142,7 @@ int main(int argc, char** argv) { if (*machine_opt) { LOG_F(INFO, "Machine option was passed in: %s", machine_str.c_str()); } else { - machine_str = machine_name_from_rom(bootrom_path); + machine_str = MachineFactory::machine_name_from_rom(bootrom_path); if (machine_str.empty()) { LOG_F(ERROR, "Could not autodetect machine"); return 0; @@ -154,7 +154,7 @@ int main(int argc, char** argv) { /* handle overriding of machine settings from command line */ map settings; - if (get_machine_settings(machine_str, settings) < 0) { + if (MachineFactory::get_machine_settings(machine_str, settings) < 0) { return 0; } @@ -166,7 +166,7 @@ int main(int argc, char** argv) { } sa.parse(app.remaining_for_passthrough()); /* TODO: handle exceptions! */ - set_machine_settings(settings); + MachineFactory::set_machine_settings(settings); cout << "BootROM path: " << bootrom_path << endl; cout << "Execution mode: " << execution_mode << endl; @@ -179,7 +179,7 @@ int main(int argc, char** argv) { // initialize global profiler object gProfilerObj.reset(new Profiler()); - if (create_machine_for_id(machine_str, bootrom_path) < 0) { + if (MachineFactory::create_machine_for_id(machine_str, bootrom_path) < 0) { goto bail; }