Refactor MachineBase and MachineFactory classes.

Adding new machines is much easier now.
A significant amount of duplicated code has been reduced.
This commit is contained in:
Maxim Poliakovski 2022-07-18 11:48:23 +02:00
parent 9971052a78
commit c0078ce97d
15 changed files with 481 additions and 463 deletions

View File

@ -51,14 +51,17 @@ AMIC::AMIC() : MMIODevice()
supports_types(HWCompType::MMIO_DEV | HWCompType::INT_CTRL); supports_types(HWCompType::MMIO_DEV | HWCompType::INT_CTRL);
// register I/O devices // connect internal SCSI controller
this->scsi = std::unique_ptr<Sc53C94> (new Sc53C94()); this->scsi = dynamic_cast<Sc53C94*>(gMachineObj->get_comp_by_name("Sc53C94"));
gMachineObj->add_subdevice("Curio_SCSI0", this->scsi.get());
this->escc = std::unique_ptr<EsccController> (new EsccController()); // connect serial HW
this->mace = std::unique_ptr<MaceController> (new MaceController(MACE_ID)); this->escc = dynamic_cast<EsccController*>(gMachineObj->get_comp_by_name("Escc"));
this->viacuda = std::unique_ptr<ViaCuda> (new ViaCuda());
gMachineObj->add_subdevice("ViaCuda", this->viacuda.get()); // connect Ethernet HW
this->mace = dynamic_cast<MaceController*>(gMachineObj->get_comp_by_name("Mace"));
// connect Cuda
this->viacuda = dynamic_cast<ViaCuda*>(gMachineObj->get_comp_by_name("ViaCuda"));
// initialize sound HW // initialize sound HW
this->snd_out_dma = std::unique_ptr<AmicSndOutDma> (new AmicSndOutDma()); this->snd_out_dma = std::unique_ptr<AmicSndOutDma> (new AmicSndOutDma());
@ -69,11 +72,10 @@ AMIC::AMIC() : MMIODevice()
this->disp_id = std::unique_ptr<DisplayID> (new DisplayID()); this->disp_id = std::unique_ptr<DisplayID> (new DisplayID());
this->def_vid = std::unique_ptr<PdmOnboardVideo> (new PdmOnboardVideo()); this->def_vid = std::unique_ptr<PdmOnboardVideo> (new PdmOnboardVideo());
// intialize floppy disk HW // initialize floppy disk HW
this->swim3 = std::unique_ptr<Swim3::Swim3Ctrl> (new Swim3::Swim3Ctrl()); this->swim3 = dynamic_cast<Swim3::Swim3Ctrl*>(gMachineObj->get_comp_by_name("Swim3"));
this->floppy_dma = std::unique_ptr<AmicFloppyDma> (new AmicFloppyDma()); this->floppy_dma = std::unique_ptr<AmicFloppyDma> (new AmicFloppyDma());
this->swim3->set_dma_channel(this->floppy_dma.get()); this->swim3->set_dma_channel(this->floppy_dma.get());
gMachineObj->add_subdevice("SWIM3", this->swim3.get());
} }
int AMIC::device_postinit() int AMIC::device_postinit()
@ -530,7 +532,7 @@ DmaPullResult AmicFloppyDma::pull_data(uint32_t req_len, uint32_t *avail_len,
} }
static vector<string> Amic_Subdevices = { static vector<string> Amic_Subdevices = {
"Swim3", "Escc" "Sc53C94", "Escc", "Mace", "ViaCuda", "Swim3"
}; };
static const DeviceDescription Amic_Descriptor = { static const DeviceDescription Amic_Descriptor = {

View File

@ -228,13 +228,14 @@ private:
uint32_t pseudo_vbl_tid; // ID for the pseudo-VBL timer uint32_t pseudo_vbl_tid; // ID for the pseudo-VBL timer
// AMIC subdevices instances // AMIC subdevice instances
std::unique_ptr<Sc53C94> scsi; Sc53C94* scsi;
std::unique_ptr<EsccController> escc; EsccController* escc;
std::unique_ptr<MaceController> mace; MaceController* mace;
std::unique_ptr<ViaCuda> viacuda; ViaCuda* viacuda;
std::unique_ptr<AwacDevicePdm> awacs; Swim3::Swim3Ctrl* swim3;
std::unique_ptr<AwacDevicePdm> awacs;
std::unique_ptr<AmicSndOutDma> snd_out_dma; std::unique_ptr<AmicSndOutDma> snd_out_dma;
std::unique_ptr<AmicFloppyDma> floppy_dma; std::unique_ptr<AmicFloppyDma> floppy_dma;
@ -242,8 +243,6 @@ private:
std::unique_ptr<DisplayID> disp_id; std::unique_ptr<DisplayID> disp_id;
std::unique_ptr<PdmOnboardVideo> def_vid; std::unique_ptr<PdmOnboardVideo> def_vid;
uint8_t mon_id; uint8_t mon_id;
std::unique_ptr<Swim3::Swim3Ctrl> swim3;
}; };
#endif // AMIC_H #endif // AMIC_H

View File

@ -48,13 +48,11 @@ GrandCentral::GrandCentral() : PCIDevice("mac-io/grandcentral"), InterruptCtrl()
this->notify_bar_change(bar_num); this->notify_bar_change(bar_num);
}; };
// construct subdevices // NVRAM connection
this->mace = std::unique_ptr<MaceController> (new MaceController(MACE_ID)); this->nvram = dynamic_cast<NVram*>(gMachineObj->get_comp_by_name("NVRAM"));
this->viacuda = std::unique_ptr<ViaCuda> (new ViaCuda());
this->nvram = std::unique_ptr<NVram> (new NVram());
gMachineObj->add_subdevice("ViaCuda", this->viacuda.get()); // connect Cuda
gMachineObj->add_subdevice("NVRAM", this->nvram.get()); this->viacuda = dynamic_cast<ViaCuda*>(gMachineObj->get_comp_by_name("ViaCuda"));
// initialize sound chip and its DMA output channel, then wire them together // initialize sound chip and its DMA output channel, then wire them together
this->awacs = std::unique_ptr<AwacsScreamer> (new AwacsScreamer()); this->awacs = std::unique_ptr<AwacsScreamer> (new AwacsScreamer());
@ -65,13 +63,17 @@ GrandCentral::GrandCentral() : PCIDevice("mac-io/grandcentral"), InterruptCtrl()
std::bind(&AwacsScreamer::dma_end, this->awacs.get()) std::bind(&AwacsScreamer::dma_end, this->awacs.get())
); );
this->escc = std::unique_ptr<EsccController> (new EsccController()); // connect serial HW
this->escc = dynamic_cast<EsccController*>(gMachineObj->get_comp_by_name("Escc"));
this->scsi_0 = std::unique_ptr<Sc53C94> (new Sc53C94()); // connect SCSI HW
gMachineObj->add_subdevice("Curio_SCSI0", this->scsi_0.get()); this->scsi_0 = dynamic_cast<Sc53C94*>(gMachineObj->get_comp_by_name("Sc53C94"));
this->swim3 = std::unique_ptr<Swim3::Swim3Ctrl> (new Swim3::Swim3Ctrl()); // connect Ethernet HW
gMachineObj->add_subdevice("SWIM3", this->swim3.get()); this->mace = dynamic_cast<MaceController*>(gMachineObj->get_comp_by_name("Mace"));
// connect floppy disk HW
this->swim3 = dynamic_cast<Swim3::Swim3Ctrl*>(gMachineObj->get_comp_by_name("Swim3"));
} }
void GrandCentral::notify_bar_change(int bar_num) 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<string> GCSubdevices = { static const vector<string> GCSubdevices = {
"Swim3", "Escc" "NVRAM", "ViaCuda", "Escc", "Sc53C94", "Mace", "Swim3"
}; };
static const DeviceDescription GC_Descriptor = { static const DeviceDescription GC_Descriptor = {

View File

@ -60,11 +60,11 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow"), InterruptCtrl()
this->notify_bar_change(bar_num); this->notify_bar_change(bar_num);
}; };
this->nvram = std::unique_ptr<NVram> (new NVram()); // NVRAM connection
gMachineObj->add_subdevice("NVRAM", this->nvram.get()); this->nvram = dynamic_cast<NVram*>(gMachineObj->get_comp_by_name("NVRAM"));
this->viacuda = std::unique_ptr<ViaCuda> (new ViaCuda()); // connect Cuda
gMachineObj->add_subdevice("ViaCuda", this->viacuda.get()); this->viacuda = dynamic_cast<ViaCuda*>(gMachineObj->get_comp_by_name("ViaCuda"));
// initialize sound chip and its DMA output channel, then wire them together // initialize sound chip and its DMA output channel, then wire them together
this->screamer = std::unique_ptr<AwacsScreamer> (new AwacsScreamer()); this->screamer = std::unique_ptr<AwacsScreamer> (new AwacsScreamer());
@ -75,12 +75,14 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow"), InterruptCtrl()
std::bind(&AwacsScreamer::dma_end, this->screamer.get()) std::bind(&AwacsScreamer::dma_end, this->screamer.get())
); );
this->mesh = std::unique_ptr<MESHController> (new MESHController(HeathrowMESHID)); // connect SCSI HW
this->escc = std::unique_ptr<EsccController> (new EsccController()); this->mesh = dynamic_cast<MESHController*>(gMachineObj->get_comp_by_name("Mesh"));
// intialize floppy disk HW // connect serial HW
this->swim3 = std::unique_ptr<Swim3::Swim3Ctrl> (new Swim3::Swim3Ctrl()); this->escc = dynamic_cast<EsccController*>(gMachineObj->get_comp_by_name("Escc"));
gMachineObj->add_subdevice("SWIM3", this->swim3.get());
// connect floppy disk HW
this->swim3 = dynamic_cast<Swim3::Swim3Ctrl*>(gMachineObj->get_comp_by_name("Swim3"));
} }
void HeathrowIC::notify_bar_change(int bar_num) 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<string> Heathrow_Subdevices = { static const vector<string> Heathrow_Subdevices = {
"Swim3", "Escc" "NVRAM", "ViaCuda", "Mesh", "Escc", "Swim3"
}; };
static const DeviceDescription Heathrow_Descriptor = { static const DeviceDescription Heathrow_Descriptor = {

View File

@ -116,14 +116,15 @@ private:
uint32_t nvram_addr_hi; uint32_t nvram_addr_hi;
// device cells // subdevice objects
std::unique_ptr<MaceController> mace;
std::unique_ptr<AwacsScreamer> awacs; // AWACS audio codec instance std::unique_ptr<AwacsScreamer> awacs; // AWACS audio codec instance
std::unique_ptr<ViaCuda> viacuda; // VIA cell with Cuda MCU attached to it
std::unique_ptr<NVram> nvram; // NVRAM module NVram* nvram; // NVRAM module
std::unique_ptr<EsccController> escc; // ESCC serial controller MaceController* mace;
std::unique_ptr<Sc53C94> scsi_0; // external SCSI ViaCuda* viacuda; // VIA cell with Cuda MCU attached to it
std::unique_ptr<Swim3::Swim3Ctrl> swim3; // floppy disk controller EsccController* escc; // ESCC serial controller
Sc53C94* scsi_0; // external SCSI
Swim3::Swim3Ctrl* swim3; // floppy disk controller
std::unique_ptr<DMAChannel> snd_out_dma; std::unique_ptr<DMAChannel> snd_out_dma;
}; };
@ -194,15 +195,17 @@ private:
uint32_t feat_ctrl = 0; // features control register uint32_t feat_ctrl = 0; // features control register
uint32_t aux_ctrl = 0; // aux features control register uint32_t aux_ctrl = 0; // aux features control register
/* device cells */ // subdevice objects
std::unique_ptr<ViaCuda> viacuda; // VIA cell with Cuda MCU attached to it
std::unique_ptr<NVram> nvram; // NVRAM cell
std::unique_ptr<AwacsScreamer> screamer; // Screamer audio codec instance std::unique_ptr<AwacsScreamer> screamer; // Screamer audio codec instance
std::unique_ptr<MESHController> mesh; // MESH SCSI cell instance //std::unique_ptr<MESHController> mesh; // MESH SCSI cell instance
std::unique_ptr<EsccController> escc; // ESCC serial controller
std::unique_ptr<Swim3::Swim3Ctrl> swim3; // floppy disk controller
std::unique_ptr<DMAChannel> 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<DMAChannel> snd_out_dma;
}; };
#endif /* MACIO_H */ #endif /* MACIO_H */

View File

@ -22,6 +22,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/timermanager.h> #include <core/timermanager.h>
#include <devices/common/hwcomponent.h> #include <devices/common/hwcomponent.h>
#include <devices/common/pci/pcidevice.h> #include <devices/common/pci/pcidevice.h>
#include <devices/deviceregistry.h>
#include <devices/video/atirage.h> #include <devices/video/atirage.h>
#include <devices/video/displayid.h> #include <devices/video/displayid.h>
#include <endianswap.h> #include <endianswap.h>
@ -89,14 +90,14 @@ static const std::map<uint16_t, std::string> 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) : PCIDevice("ati-rage"), VideoCtrlBase(1024, 768)
{ {
uint8_t asic_id; uint8_t asic_id;
supports_types(HWCompType::MMIO_DEV | HWCompType::PCI_DEV); 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 */ /* allocate video RAM */
this->vram_ptr = std::unique_ptr<uint8_t[]> (new uint8_t[this->vram_size]); this->vram_ptr = std::unique_ptr<uint8_t[]> (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<uint32_t>({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);

View File

@ -1,6 +1,6 @@
/* /*
DingusPPC - The Experimental PowerPC Macintosh emulator DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-21 divingkatae and maximum Copyright (C) 2018-22 divingkatae and maximum
(theweirdo) spatium (theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info) (Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -44,9 +44,17 @@ enum {
class ATIRage : public PCIDevice, public VideoCtrlBase { class ATIRage : public PCIDevice, public VideoCtrlBase {
public: public:
ATIRage(uint16_t dev_id, uint32_t vmem_size_mb); ATIRage(uint16_t dev_id);
~ATIRage() = default; ~ATIRage() = default;
static std::unique_ptr<HWComponent> create_gt() {
return std::unique_ptr<ATIRage>(new ATIRage(ATI_RAGE_GT_DEV_ID));
}
static std::unique_ptr<HWComponent> create_pro() {
return std::unique_ptr<ATIRage>(new ATIRage(ATI_RAGE_PRO_DEV_ID));
}
/* MMIODevice methods */ /* MMIODevice methods */
uint32_t read(uint32_t reg_start, uint32_t offset, int size); 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); 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 */ int comp_index; /* color component index for DAC palette access */
}; };
#endif /* ATI_RAGE_H */ #endif /* ATI_RAGE_H */

View File

@ -1,6 +1,6 @@
/* /*
DingusPPC - The Experimental PowerPC Macintosh emulator DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-21 divingkatae and maximum Copyright (C) 2018-22 divingkatae and maximum
(theweirdo) spatium (theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info) (Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -33,59 +33,28 @@ MachineBase::MachineBase(std::string name) {
this->name = name; this->name = name;
/* initialize internal maps */ /* initialize internal maps */
this->comp_map.clear(); this->device_map.clear();
this->subdev_map.clear();
this->aliases.clear();
} }
MachineBase::~MachineBase() { MachineBase::~MachineBase() {
for (auto it = this->comp_map.begin(); it != this->comp_map.end(); it++) { this->device_map.clear();
delete it->second;
}
this->comp_map.clear();
this->aliases.clear();
this->subdev_map.clear();
} }
bool MachineBase::add_component(std::string name, HWComponent* dev_obj) { void MachineBase::add_device(std::string name, std::unique_ptr<HWComponent> dev_obj) {
if (this->comp_map.count(name)) { if (this->device_map.count(name)) {
LOG_F(ERROR, "Component %s already exists!", name.c_str()); LOG_F(ERROR, "Device %s already exists!", name.c_str());
return false; return;
} }
this->comp_map[name] = dev_obj; this->device_map[name] = std::move(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;
} }
HWComponent* MachineBase::get_comp_by_name(std::string name) { HWComponent* MachineBase::get_comp_by_name(std::string name) {
if (this->aliases.count(name)) { if (this->device_map.count(name)) {
name = this->aliases[name]; return this->device_map[name].get();
}
if (this->comp_map.count(name)) {
return this->comp_map[name];
}
if (this->subdev_map.count(name)) {
return this->subdev_map[name];
} else { } 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; std::string comp_name;
bool found = false; bool found = false;
for (auto it = this->comp_map.begin(); it != this->comp_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;
break;
}
}
if (found) {
return this->get_comp_by_name(comp_name);
}
for (auto it = this->subdev_map.begin(); it != this->subdev_map.end(); it++) {
if (it->second->supports_type(type)) { if (it->second->supports_type(type)) {
comp_name = it->first; comp_name = it->first;
found = true; found = true;
@ -116,19 +73,14 @@ HWComponent* MachineBase::get_comp_by_type(HWCompType type) {
if (found) { if (found) {
return this->get_comp_by_name(comp_name); return this->get_comp_by_name(comp_name);
} else { } else {
return NULL; LOG_F(WARNING, "No component of type %lu was found!", type);
return nullptr;
} }
} }
int MachineBase::postinit_devices() int MachineBase::postinit_devices()
{ {
for (auto it = this->comp_map.begin(); it != this->comp_map.end(); it++) { for (auto it = this->device_map.begin(); it != this->device_map.end(); it++) {
if (it->second->device_postinit()) {
return -1;
}
}
for (auto it = this->subdev_map.begin(); it != this->subdev_map.end(); it++) {
if (it->second->device_postinit()) { if (it->second->device_postinit()) {
return -1; return -1;
} }

View File

@ -1,6 +1,6 @@
/* /*
DingusPPC - The Experimental PowerPC Macintosh emulator DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-21 divingkatae and maximum Copyright (C) 2018-22 divingkatae and maximum
(theweirdo) spatium (theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info) (Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -38,18 +38,14 @@ public:
MachineBase(std::string name); MachineBase(std::string name);
~MachineBase(); ~MachineBase();
bool add_component(std::string name, HWComponent* dev_obj); void add_device(std::string name, std::unique_ptr<HWComponent> dev_obj);
bool add_subdevice(std::string name, HWComponent* dev_obj);
void add_alias(std::string name, std::string alias);
HWComponent* get_comp_by_name(std::string name); HWComponent* get_comp_by_name(std::string name);
HWComponent* get_comp_by_type(HWCompType type); HWComponent* get_comp_by_type(HWCompType type);
int postinit_devices(); int postinit_devices();
private: private:
std::string name; std::string name;
std::map<std::string, HWComponent*> comp_map; std::map<std::string, std::unique_ptr<HWComponent>> device_map;
std::map<std::string, HWComponent*> subdev_map;
std::map<std::string, std::string> aliases;
}; };
extern std::unique_ptr<MachineBase> gMachineObj; extern std::unique_ptr<MachineBase> gMachineObj;

View File

@ -26,48 +26,24 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/scsi/scsi.h> #include <devices/common/scsi/scsi.h>
#include <devices/ioctrl/macio.h> #include <devices/ioctrl/macio.h>
#include <devices/memctrl/platinum.h> #include <devices/memctrl/platinum.h>
#include <devices/video/atimach64gx.h>
#include <loguru.hpp> #include <loguru.hpp>
#include <machines/machinebase.h> #include <machines/machinebase.h>
#include <machines/machinefactory.h>
#include <machines/machineproperties.h> #include <machines/machineproperties.h>
#include <memory>
#include <string> #include <string>
int create_catalyst(std::string& id) int initialize_catalyst(std::string& id)
{ {
PlatinumCtrl* platinum_obj; 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<PCIHost*>(gMachineObj->get_comp_by_name("Bandit1")); PCIHost *pci_host = dynamic_cast<PCIHost*>(gMachineObj->get_comp_by_name("Bandit1"));
// start the sound server
gMachineObj->add_component("SoundServer", new SoundServer());
// add the GrandCentral I/O controller // add the GrandCentral I/O controller
gMachineObj->add_component("GrandCentral", new GrandCentral());
pci_host->pci_register_device( pci_host->pci_register_device(
32, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("GrandCentral"))); 32, dynamic_cast<PCIDevice*>(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<PCIDevice*>(gMachineObj->get_comp_by_name("AtiMach64")));
// get (raw) pointer to the memory controller // get (raw) pointer to the memory controller
platinum_obj = dynamic_cast<PlatinumCtrl*>(gMachineObj->get_comp_by_name("Platinum")); platinum_obj = dynamic_cast<PlatinumCtrl*>(gMachineObj->get_comp_by_name("Platinum"));
@ -84,18 +60,39 @@ int create_catalyst(std::string& id)
platinum_obj->map_phys_ram(); platinum_obj->map_phys_ram();
// add single SCSI bus // add single SCSI bus
gMachineObj->add_component("SCSI0", new ScsiBus); gMachineObj->add_device("SCSI0", std::unique_ptr<ScsiBus>(new ScsiBus()));
// init virtual CPU and request MPC601 // init virtual CPU and request MPC601
ppc_cpu_init(platinum_obj, PPC_VER::MPC601, 7833600ULL); 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; return 0;
} }
static const PropMap pm7200_settings = {
{"rambank1_size",
new IntProperty(16, vector<uint32_t>({4, 8, 16, 32, 64, 128}))},
{"rambank2_size",
new IntProperty( 0, vector<uint32_t>({0, 4, 8, 16, 32, 64, 128}))},
{"rambank3_size",
new IntProperty( 0, vector<uint32_t>({0, 4, 8, 16, 32, 64, 128}))},
{"rambank4_size",
new IntProperty( 0, vector<uint32_t>({0, 4, 8, 16, 32, 64, 128}))},
{"gfxmem_size",
new IntProperty( 1, vector<uint32_t>({1, 2, 4}))},
{"mon_id",
new StrProperty("HiRes12-14in")},
};
static vector<string> 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);

View File

@ -24,8 +24,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
Author: Max Poliakovski Author: Max Poliakovski
*/ */
#include <devices/deviceregistry.h>
#include <devices/memctrl/memctrlbase.h> #include <devices/memctrl/memctrlbase.h>
#include <devices/sound/soundserver.h>
#include <loguru.hpp> #include <loguru.hpp>
#include <machines/machinebase.h>
#include <machines/machinefactory.h> #include <machines/machinefactory.h>
#include <machines/machineproperties.h> #include <machines/machineproperties.h>
#include <memaccess.h> #include <memaccess.h>
@ -56,7 +59,7 @@ static const map<uint32_t, std::tuple<string, const char*>> rom_identity = {
//{"Come", "PowerBook 2400"}, // Comet //{"Come", "PowerBook 2400"}, // Comet
{0x436F7264, {"pm5200", "Power Mac 5200/6200 series"}}, // Cordyceps {0x436F7264, {"pm5200", "Power Mac 5200/6200 series"}}, // Cordyceps
{0x47617A65, {"pm6500", "Power Mac 6500"}}, // Gazelle {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"}}, {0x47525820, {"pbg3", "PowerBook G3 Wallstreet"}},
//{"Hoop", "PowerBook 3400"}, // Hooper //{"Hoop", "PowerBook 3400"}, // Hooper
{0x50425820, {"pb-preg3", "PowerBook Pre-G3"}}, {0x50425820, {"pb-preg3", "PowerBook Pre-G3"}},
@ -67,67 +70,6 @@ static const map<uint32_t, std::tuple<string, const char*>> rom_identity = {
{0x5A616E7A, {"pm4400", "Power Mac 4400/7220"}}, // Zanzibar {0x5A616E7A, {"pm4400", "Power Mac 4400/7220"}}, // Zanzibar
}; };
static const vector<string> WriteToggle = {"ON", "on", "OFF", "off"};
static const vector<string> CharIoBackends = {"null", "stdio"};
static const PropMap CatalystSettings = {
{"rambank1_size",
new IntProperty(16, vector<uint32_t>({4, 8, 16, 32, 64, 128}))},
{"rambank2_size",
new IntProperty( 0, vector<uint32_t>({0, 4, 8, 16, 32, 64, 128}))},
{"rambank3_size",
new IntProperty( 0, vector<uint32_t>({0, 4, 8, 16, 32, 64, 128}))},
{"rambank4_size",
new IntProperty( 0, vector<uint32_t>({0, 4, 8, 16, 32, 64, 128}))},
{"gfxmem_size",
new IntProperty( 1, vector<uint32_t>({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<uint32_t>({8, 16, 32, 64, 128, 256}))},
{"rambank2_size",
new IntProperty( 0, vector<uint32_t>({0, 8, 16, 32, 64, 128, 256}))},
{"rambank3_size",
new IntProperty( 0, vector<uint32_t>({0, 8, 16, 32, 64, 128, 256}))},
{"gfxmem_size",
new IntProperty( 2, vector<uint32_t>({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<string> PDMBuiltinMonitorIDs = {
"PortraitGS", "MacRGB12in", "MacRGB15in", "HiRes12-14in", "VGA-SVGA",
"MacRGB16in", "Multiscan15in", "Multiscan17in", "Multiscan20in",
"NotConnected"
};
static const PropMap PDMSettings = {
{"rambank1_size",
new IntProperty(0, vector<uint32_t>({0, 8, 16, 32, 64, 128}))},
{"rambank2_size",
new IntProperty(0, vector<uint32_t>({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<string, string> PropHelp = { static const map<string, string> PropHelp = {
{"rambank1_size", "specifies RAM bank 1 size in MB"}, {"rambank1_size", "specifies RAM bank 1 size in MB"},
{"rambank2_size", "specifies RAM bank 2 size in MB"}, {"rambank2_size", "specifies RAM bank 2 size in MB"},
@ -135,18 +77,182 @@ static const map<string, string> PropHelp = {
{"rambank4_size", "specifies RAM bank 4 size in MB"}, {"rambank4_size", "specifies RAM bank 4 size in MB"},
{"gfxmem_size", "specifies video memory size in MB"}, {"gfxmem_size", "specifies video memory size in MB"},
{"fdd_img", "specifies path to floppy disk image"}, {"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"}, {"mon_id", "specifies which monitor to emulate"},
{"serial_backend", "specifies the backend for the serial port"}, {"serial_backend", "specifies the backend for the serial port"},
}; };
static const map<string, tuple<PropMap, function<int(string&)>, string>> machines = { bool MachineFactory::add(const string& machine_id, MachineDescription desc)
{"pm6100", {PDMSettings, create_pdm, "PowerMacintosh 6100"}}, {
{"pm7200", {CatalystSettings, create_catalyst, "PowerMacintosh 7200"}}, if (get_registry().find(machine_id) != get_registry().end()) {
{"pmg3", {GossamerSettings, create_gossamer, "Power Macintosh G3 (Beige)"}}, 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<SoundServer>(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<IntProperty*>(p.second)->get_valid_values_as_str()
<< endl;
break;
case PROP_TYPE_STRING:
cout << dynamic_cast<StrProperty*>(p.second)->get_valid_values_as_str()
<< endl;
break;
default:
break;
}
cout << endl;
}
}
void MachineFactory::get_device_settings(DeviceDescription& dev, map<string, string> &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<BasicProperty>(p.second->clone());
}
}
int MachineFactory::get_machine_settings(const string& id, map<string, string> &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<BasicProperty>(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<string, string> &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; ifstream rom_file;
uint32_t file_size, config_info_offset, rom_id; uint32_t file_size, config_info_offset, rom_id;
char rom_id_str[17]; char rom_id_str[17];
@ -202,96 +308,8 @@ bail_out:
return machine_name; return machine_name;
} }
int get_machine_settings(string& id, map<string, string> &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<BasicProperty>(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<string, string> &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<IntProperty*>(p.second)->get_valid_values_as_str()
<< endl;
break;
case PROP_TYPE_STRING:
cout << dynamic_cast<StrProperty*>(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 */ /* Read ROM file content and transfer it to the dedicated ROM region */
void load_rom(std::ifstream& rom_file, uint32_t file_size) { int MachineFactory::load_boot_rom(string& rom_filepath) {
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<MemCtrlBase*>(
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) {
ifstream rom_file; ifstream rom_file;
size_t file_size; size_t file_size;
int result; int result;
@ -336,17 +354,8 @@ int load_boot_rom(string& rom_filepath) {
return result; return result;
} }
int MachineFactory::create_machine_for_id(string& id, string& rom_filepath) {
int create_machine_for_id(string& id, string& rom_filepath) { if (MachineFactory::create(id) < 0 || load_boot_rom(rom_filepath) < 0) {
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());
return -1; return -1;
} }

View File

@ -1,6 +1,6 @@
/* /*
DingusPPC - The Experimental PowerPC Macintosh emulator DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-21 divingkatae and maximum Copyright (C) 2018-22 divingkatae and maximum
(theweirdo) spatium (theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info) (Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -27,24 +27,58 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef MACHINE_FACTORY_H #ifndef MACHINE_FACTORY_H
#define MACHINE_FACTORY_H #define MACHINE_FACTORY_H
#include <devices/deviceregistry.h>
#include <machines/machinebase.h> #include <machines/machinebase.h>
#include <machines/machineproperties.h>
#include <fstream> #include <fstream>
#include <functional>
#include <map>
#include <string> #include <string>
#include <vector>
using namespace std; using namespace std;
std::string machine_name_from_rom(std::string& rom_filepath); struct MachineDescription {
string name;
string description;
vector<string> devices;
PropMap settings;
function<int(string&)> init_func;
};
int get_machine_settings(string& id, map<string, string> &settings); class MachineFactory
void set_machine_settings(map<string, string> &settings); {
int create_machine_for_id(string& id, string& rom_filepath); public:
void list_machines(void); MachineFactory() = delete;
void list_properties(void);
/* Machine-specific factory functions. */ static bool add(const string& machine_id, MachineDescription desc);
int create_catalyst(string& id);
int create_gossamer(string& id); static string machine_name_from_rom(string& rom_filepath);
int create_pdm(string& id);
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<string, string> &settings);
static void set_machine_settings(map<string, string> &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<string, string> &settings);
static int load_boot_rom(string& rom_filepath);
static map<string, MachineDescription> & get_registry() {
static map<string, MachineDescription> 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 */ #endif /* MACHINE_FACTORY_H */

View File

@ -1,6 +1,6 @@
/* /*
DingusPPC - The Experimental PowerPC Macintosh emulator DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-21 divingkatae and maximum Copyright (C) 2018-22 divingkatae and maximum
(theweirdo) spatium (theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info) (Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -34,89 +34,86 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/video/atirage.h> #include <devices/video/atirage.h>
#include <loguru.hpp> #include <loguru.hpp>
#include <machines/machinebase.h> #include <machines/machinebase.h>
#include <machines/machinefactory.h>
#include <machines/machineproperties.h> #include <machines/machineproperties.h>
#include <memory>
#include <string> #include <string>
static void setup_ram_slot(std::string name, int i2c_addr, int capacity_megs) { static void setup_ram_slot(std::string name, int i2c_addr, int capacity_megs) {
if (!capacity_megs) if (!capacity_megs)
return; return;
gMachineObj->add_component(name, new SpdSdram168(i2c_addr)); gMachineObj->add_device(name, std::unique_ptr<SpdSdram168>(new SpdSdram168(i2c_addr)));
SpdSdram168* ram_dimm = dynamic_cast<SpdSdram168*>(gMachineObj->get_comp_by_name(name)); SpdSdram168* ram_dimm = dynamic_cast<SpdSdram168*>(gMachineObj->get_comp_by_name(name));
ram_dimm->set_capacity(capacity_megs); 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<I2CBus*>(gMachineObj->get_comp_by_type(HWCompType::I2C_HOST)); I2CBus* i2c_bus = dynamic_cast<I2CBus*>(gMachineObj->get_comp_by_type(HWCompType::I2C_HOST));
i2c_bus->register_device(i2c_addr, ram_dimm); i2c_bus->register_device(i2c_addr, ram_dimm);
} }
int create_gossamer(std::string& id) { int initialize_gossamer(std::string& id)
if (gMachineObj) { {
LOG_F(ERROR, "Global machine object not empty!"); // get pointer to the memory controller/PCI host bridge object
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 */
MPC106* grackle_obj = dynamic_cast<MPC106*>(gMachineObj->get_comp_by_name("Grackle")); MPC106* grackle_obj = dynamic_cast<MPC106*>(gMachineObj->get_comp_by_name("Grackle"));
/* add the machine ID register */ // add the machine ID register
gMachineObj->add_component("MachineID", new GossamerID(0xBF3D)); gMachineObj->add_device("MachineID", std::unique_ptr<GossamerID>(new GossamerID(0xBF3D)));
grackle_obj->add_mmio_region( grackle_obj->add_mmio_region(
0xFF000004, 4096, dynamic_cast<MMIODevice*>(gMachineObj->get_comp_by_name("MachineID"))); 0xFF000004, 4096, dynamic_cast<MMIODevice*>(gMachineObj->get_comp_by_name("MachineID")));
gMachineObj->add_component("SoundServer", new SoundServer()); // register the Heathrow I/O controller with the PCI host bridge
/* add the Heathrow I/O controller */
gMachineObj->add_component("Heathrow", new HeathrowIC);
grackle_obj->pci_register_device( grackle_obj->pci_register_device(
16, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("Heathrow"))); 16, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("Heathrow")));
/* allocate ROM region */ // allocate ROM region
if (!grackle_obj->add_rom_region(0xFFC00000, 0x400000)) { if (!grackle_obj->add_rom_region(0xFFC00000, 0x400000)) {
LOG_F(ERROR, "Could not allocate ROM region!\n"); LOG_F(ERROR, "Could not allocate ROM region!\n");
return -1; 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_1", 0x57, GET_INT_PROP("rambank1_size"));
setup_ram_slot("RAM_DIMM_2", 0x56, GET_INT_PROP("rambank2_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")); setup_ram_slot("RAM_DIMM_3", 0x55, GET_INT_PROP("rambank3_size"));
/* register ATI 3D Rage Pro video card with the PCI host bridge */ // select built-in GPU name
gMachineObj->add_component("ATIRage", std::string gpu_name = "AtiRageGT";
new ATIRage(ATI_RAGE_PRO_DEV_ID, GET_INT_PROP("gfxmem_size"))); if (id == "pmg3twr") {
gpu_name = "AtiRagePro";
}
// register built-in ATI Rage GPU with the PCI host bridge
grackle_obj->pci_register_device( grackle_obj->pci_register_device(
18, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("ATIRage"))); 18, dynamic_cast<PCIDevice*>(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); 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; return 0;
} }
static const PropMap gossamer_settings = {
{"rambank1_size",
new IntProperty(256, vector<uint32_t>({8, 16, 32, 64, 128, 256}))},
{"rambank2_size",
new IntProperty( 0, vector<uint32_t>({0, 8, 16, 32, 64, 128, 256}))},
{"rambank3_size",
new IntProperty( 0, vector<uint32_t>({0, 8, 16, 32, 64, 128, 256}))},
};
static vector<string> 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);

View File

@ -1,6 +1,6 @@
/* /*
DingusPPC - The Experimental PowerPC Macintosh emulator DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-21 divingkatae and maximum Copyright (C) 2018-22 divingkatae and maximum
(theweirdo) spatium (theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info) (Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -27,97 +27,94 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <cpu/ppc/ppcemu.h> #include <cpu/ppc/ppcemu.h>
#include <devices/common/machineid.h> #include <devices/common/machineid.h>
#include <devices/common/scsi/scsi.h> #include <devices/common/scsi/scsi.h>
#include <devices/floppy/superdrive.h>
#include <devices/ioctrl/amic.h>
#include <devices/memctrl/hmc.h> #include <devices/memctrl/hmc.h>
#include <devices/sound/soundserver.h>
#include <loguru.hpp> #include <loguru.hpp>
#include <machines/machinebase.h> #include <machines/machinebase.h>
#include <machines/machinefactory.h>
#include <machines/machineproperties.h> #include <machines/machineproperties.h>
#include <string> #include <string>
#include <vector>
int create_pdm(std::string& id) { int initialize_pdm(std::string& id)
if (gMachineObj) { {
LOG_F(ERROR, "PDM Factory: global machine object not empty!"); uint16_t machine_id;
// get raw pointer to HMC object
HMC* hmc_obj = dynamic_cast<HMC*>(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; return -1;
} }
LOG_F(INFO, "Initializing the %s hardware...", id.c_str()); // create machine ID register
//gMachineObj->add_component("MachineID", new NubusMacID(machine_id));
/* initialize the global machine object */ gMachineObj->add_device("MachineID", std::unique_ptr<NubusMacID>(new NubusMacID(machine_id)));
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<HMC*>(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, hmc_obj->add_mmio_region(0x5FFFFFFC, 4,
dynamic_cast<MMIODevice*>(gMachineObj->get_comp_by_name("MachineID"))); dynamic_cast<MMIODevice*>(gMachineObj->get_comp_by_name("MachineID")));
/* allocate ROM region */ // allocate ROM region
if (!hmc_obj->add_rom_region(0x40000000, 0x400000)) { if (!hmc_obj->add_rom_region(0x40000000, 0x400000)) {
LOG_F(ERROR, "Could not allocate ROM region!\n"); LOG_F(ERROR, "Could not allocate ROM region!\n");
return -1; 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)) { if (!hmc_obj->add_mem_mirror(0xFFC00000, 0x40000000)) {
LOG_F(ERROR, "Could not create ROM mirror!\n"); LOG_F(ERROR, "Could not create ROM mirror!\n");
return -1; return -1;
} }
/* add 8MB of soldered on-board RAM */ // add 8MB of soldered on-board RAM
if (!hmc_obj->add_ram_region(0x00000000, 0x800000)) { if (!hmc_obj->add_ram_region(0x00000000, 0x800000)) {
LOG_F(ERROR, "Could not allocate built-in RAM region!\n"); LOG_F(ERROR, "Could not allocate built-in RAM region!\n");
return -1; return -1;
} }
/* add internal SCSI bus */ // add internal SCSI bus
gMachineObj->add_component("SCSI0", new ScsiBus); gMachineObj->add_device("SCSI0", std::unique_ptr<ScsiBus>(new ScsiBus()));
/* Init virtual CPU and request MPC601 */ // Init virtual CPU and request MPC601
ppc_cpu_init(hmc_obj, PPC_VER::MPC601, 7812500ULL); 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<MacSuperDrive*>
(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; return 0;
} }
// Monitors supported by the PDM on-board video.
// see displayid.cpp for the full list of supported monitor IDs.
static const vector<string> PDMBuiltinMonitorIDs = {
"PortraitGS", "MacRGB12in", "MacRGB15in", "HiRes12-14in", "VGA-SVGA",
"MacRGB16in", "Multiscan15in", "Multiscan17in", "Multiscan20in",
"NotConnected"
};
static const PropMap pm6100_settings = {
{"rambank1_size",
new IntProperty(0, vector<uint32_t>({0, 8, 16, 32, 64, 128}))},
{"rambank2_size",
new IntProperty(0, vector<uint32_t>({0, 8, 16, 32, 64, 128}))},
{"mon_id",
new StrProperty("HiRes12-14in", PDMBuiltinMonitorIDs)},
};
static vector<string> 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);

View File

@ -1,6 +1,6 @@
/* /*
DingusPPC - The Experimental PowerPC Macintosh emulator DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-21 divingkatae and maximum Copyright (C) 2018-22 divingkatae and maximum
(theweirdo) spatium (theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info) (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 (*list_cmd) {
if (sub_arg == "machines") { if (sub_arg == "machines") {
list_machines(); MachineFactory::list_machines();
} else if (sub_arg == "properties") { } else if (sub_arg == "properties") {
list_properties(); MachineFactory::list_properties();
} else { } else {
cout << "Unknown list subcommand " << sub_arg << endl; cout << "Unknown list subcommand " << sub_arg << endl;
} }
@ -142,7 +142,7 @@ int main(int argc, char** argv) {
if (*machine_opt) { if (*machine_opt) {
LOG_F(INFO, "Machine option was passed in: %s", machine_str.c_str()); LOG_F(INFO, "Machine option was passed in: %s", machine_str.c_str());
} else { } else {
machine_str = machine_name_from_rom(bootrom_path); machine_str = MachineFactory::machine_name_from_rom(bootrom_path);
if (machine_str.empty()) { if (machine_str.empty()) {
LOG_F(ERROR, "Could not autodetect machine"); LOG_F(ERROR, "Could not autodetect machine");
return 0; return 0;
@ -154,7 +154,7 @@ int main(int argc, char** argv) {
/* handle overriding of machine settings from command line */ /* handle overriding of machine settings from command line */
map<string, string> settings; map<string, string> settings;
if (get_machine_settings(machine_str, settings) < 0) { if (MachineFactory::get_machine_settings(machine_str, settings) < 0) {
return 0; return 0;
} }
@ -166,7 +166,7 @@ int main(int argc, char** argv) {
} }
sa.parse(app.remaining_for_passthrough()); /* TODO: handle exceptions! */ 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 << "BootROM path: " << bootrom_path << endl;
cout << "Execution mode: " << execution_mode << endl; cout << "Execution mode: " << execution_mode << endl;
@ -179,7 +179,7 @@ int main(int argc, char** argv) {
// initialize global profiler object // initialize global profiler object
gProfilerObj.reset(new Profiler()); 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; goto bail;
} }