diff --git a/devices/common/ata/idechannel.cpp b/devices/common/ata/idechannel.cpp index ca8c37131..948888632 100644 --- a/devices/common/ata/idechannel.cpp +++ b/devices/common/ata/idechannel.cpp @@ -1,6 +1,6 @@ /* DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-23 divingkatae and maximum +Copyright (C) 2018-24 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) @@ -22,8 +22,12 @@ along with this program. If not, see . /** IDE Channel (aka IDE port) emulation. One IDE channel is capable of controlling up to two IDE devices. - This class handles device registration and passing of messages + + IdeChannel class handles device registration and passing of messages from and to the host. + + MacioIdeChannel class implements MacIO specific registers + and interrupt handling. */ #include @@ -51,15 +55,6 @@ IdeChannel::IdeChannel(const std::string name) this->devices[1] = this->device_stub.get(); } -int IdeChannel::device_postinit() { - this->int_ctrl = dynamic_cast( - gMachineObj->get_comp_by_type(HWCompType::INT_CTRL)); - this->irq_id = this->int_ctrl->register_dev_int( - this->name == "IDE0" ? IntSrc::IDE0 : IntSrc::IDE1); - - return 0; -} - void IdeChannel::register_device(int id, AtaInterface* dev_obj) { if (id < 0 || id >= 2) ABORT_F("%s: invalid device ID", this->name.c_str()); @@ -69,44 +64,64 @@ void IdeChannel::register_device(int id, AtaInterface* dev_obj) { ((AtaBaseDevice*)dev_obj)->set_host(this, id); } -uint32_t IdeChannel::read(const uint8_t reg_addr, const int size) +uint32_t IdeChannel::read(const uint8_t reg_addr, const int size) { + return this->devices[this->cur_dev]->read(reg_addr); +} + +void IdeChannel::write(const uint8_t reg_addr, const uint32_t val, const int size) +{ + // keep track of the currently selected device + if (reg_addr == DEVICE_HEAD) { + this->cur_dev = (val >> 4) & 1; + } + + // redirect register writes to both devices + for (auto& dev : this->devices) { + dev->write(reg_addr, val); + } +} + +int MacioIdeChannel::device_postinit() { + this->int_ctrl = dynamic_cast( + gMachineObj->get_comp_by_type(HWCompType::INT_CTRL)); + this->irq_id = this->int_ctrl->register_dev_int( + this->name == "IDE0" ? IntSrc::IDE0 : IntSrc::IDE1); + + this->irq_callback = [this](const uint8_t intrq_state) { + this->int_ctrl->ack_int(this->irq_id, intrq_state); + }; + + return 0; +} + +uint32_t MacioIdeChannel::read(const uint8_t reg_addr, const int size) { if (reg_addr == TIME_CONFIG) { if (size != 4) { - LOG_F(WARNING, "%s: non-DWORD read from the channel config", this->name.c_str()); + LOG_F(WARNING, "%s: non-DWORD read from TIME_CONFIG", this->name.c_str()); } return this->ch_config; - } else { - return this->devices[this->cur_dev]->read(reg_addr); - } + } else + return IdeChannel::read(reg_addr, size); } -void IdeChannel::write(const uint8_t reg_addr, const uint32_t val, const int size) +void MacioIdeChannel::write(const uint8_t reg_addr, const uint32_t val, const int size) { if (reg_addr == TIME_CONFIG) { if (size != 4) { - LOG_F(WARNING, "%s: non-DWORD write to the channel config", this->name.c_str()); + LOG_F(WARNING, "%s: non-DWORD write to TIME_CONFIG", this->name.c_str()); } this->ch_config = val; - } else { - // keep track of the currently selected device - if (reg_addr == DEVICE_HEAD) { - this->cur_dev = (val >> 4) & 1; - } - - // redirect register writes to both devices - for (auto& dev : this->devices) { - dev->write(reg_addr, val); - } - } + } else + IdeChannel::write(reg_addr, val, size); } static const DeviceDescription Ide0_Descriptor = { - IdeChannel::create_first, {}, {} + MacioIdeChannel::create_first, {}, {} }; static const DeviceDescription Ide1_Descriptor = { - IdeChannel::create_second, {}, {} + MacioIdeChannel::create_second, {}, {} }; REGISTER_DEVICE(Ide0, Ide0_Descriptor); diff --git a/devices/common/ata/idechannel.h b/devices/common/ata/idechannel.h index 14608377e..427c49be8 100644 --- a/devices/common/ata/idechannel.h +++ b/devices/common/ata/idechannel.h @@ -1,6 +1,6 @@ /* DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-23 divingkatae and maximum +Copyright (C) 2018-24 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) @@ -29,6 +29,7 @@ along with this program. If not, see . #include #include +#include #include #include @@ -38,16 +39,6 @@ class IdeChannel : public HWComponent IdeChannel(const std::string name); ~IdeChannel() = default; - static std::unique_ptr create_first() { - return std::unique_ptr(new IdeChannel("IDE0")); - } - - static std::unique_ptr create_second() { - return std::unique_ptr(new IdeChannel("IDE1")); - } - - int device_postinit() override; - void register_device(int id, AtaInterface* dev_obj); uint32_t read(const uint8_t reg_addr, const int size); @@ -55,26 +46,56 @@ class IdeChannel : public HWComponent void assert_pdiag() { this->devices[0]->pdiag_callback(); - }; + } bool is_device1_present() { return this->devices[1]->get_device_id() != ata_interface::DEVICE_ID_INVALID; } + void set_irq_callback(std::function cb) { + this->irq_callback = cb; + } + void report_intrq(uint8_t intrq_state) { - this->int_ctrl->ack_int(this->irq_id, intrq_state); + this->irq_callback(intrq_state); } +protected: + std::function irq_callback = nullptr; + private: int cur_dev = 0; - uint32_t ch_config = 0; // timing configuration for this channel AtaInterface* devices[2]; - // interrupt related stuff + std::unique_ptr device_stub; +}; + +/** This class models an IDE channel specific to MacIO ASICs. */ +class MacioIdeChannel : public IdeChannel +{ +public: + MacioIdeChannel(const std::string name) : IdeChannel(name) {}; + ~MacioIdeChannel() = default; + + static std::unique_ptr create_first() { + return std::unique_ptr(new MacioIdeChannel("IDE0")); + } + + static std::unique_ptr create_second() { + return std::unique_ptr(new MacioIdeChannel("IDE1")); + } + + int device_postinit() override; + + uint32_t read(const uint8_t reg_addr, const int size); + void write(const uint8_t reg_addr, const uint32_t val, const int size); + +private: + uint32_t ch_config = 0; // timing configuration for this channel + + // interrupt stuff InterruptCtrl* int_ctrl = nullptr; uint32_t irq_id = 0; - - std::unique_ptr device_stub; }; #endif // IDE_CHANNEL_H