mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-21 07:31:34 +00:00
idechannel: split MacIO specific stuff into a separate class.
Now we got two classes: IdeChannel and MacioIdeChannel. The former models a generic IDE channel so it can be used elsewhere. The latter implements MacIO specific configuration register(s) and interrupt signaling.
This commit is contained in:
parent
4e78ac33c5
commit
f5c91968a2
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||||
Copyright (C) 2018-23 divingkatae and maximum
|
Copyright (C) 2018-24 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)
|
||||||
@ -22,8 +22,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
/** IDE Channel (aka IDE port) emulation.
|
/** IDE Channel (aka IDE port) emulation.
|
||||||
|
|
||||||
One IDE channel is capable of controlling up to two IDE devices.
|
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.
|
from and to the host.
|
||||||
|
|
||||||
|
MacioIdeChannel class implements MacIO specific registers
|
||||||
|
and interrupt handling.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <devices/common/ata/atabasedevice.h>
|
#include <devices/common/ata/atabasedevice.h>
|
||||||
@ -51,15 +55,6 @@ IdeChannel::IdeChannel(const std::string name)
|
|||||||
this->devices[1] = this->device_stub.get();
|
this->devices[1] = this->device_stub.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
int IdeChannel::device_postinit() {
|
|
||||||
this->int_ctrl = dynamic_cast<InterruptCtrl*>(
|
|
||||||
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) {
|
void IdeChannel::register_device(int id, AtaInterface* dev_obj) {
|
||||||
if (id < 0 || id >= 2)
|
if (id < 0 || id >= 2)
|
||||||
ABORT_F("%s: invalid device ID", this->name.c_str());
|
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);
|
((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);
|
||||||
if (reg_addr == TIME_CONFIG) {
|
|
||||||
if (size != 4) {
|
|
||||||
LOG_F(WARNING, "%s: non-DWORD read from the channel config", this->name.c_str());
|
|
||||||
}
|
|
||||||
return this->ch_config;
|
|
||||||
} else {
|
|
||||||
return this->devices[this->cur_dev]->read(reg_addr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IdeChannel::write(const uint8_t reg_addr, const uint32_t val, const int size)
|
void IdeChannel::write(const uint8_t reg_addr, const uint32_t val, const int size)
|
||||||
{
|
{
|
||||||
if (reg_addr == TIME_CONFIG) {
|
// keep track of the currently selected device
|
||||||
if (size != 4) {
|
if (reg_addr == DEVICE_HEAD) {
|
||||||
LOG_F(WARNING, "%s: non-DWORD write to the channel config", this->name.c_str());
|
this->cur_dev = (val >> 4) & 1;
|
||||||
}
|
}
|
||||||
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
|
// redirect register writes to both devices
|
||||||
for (auto& dev : this->devices) {
|
for (auto& dev : this->devices) {
|
||||||
dev->write(reg_addr, val);
|
dev->write(reg_addr, val);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MacioIdeChannel::device_postinit() {
|
||||||
|
this->int_ctrl = dynamic_cast<InterruptCtrl*>(
|
||||||
|
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 TIME_CONFIG", this->name.c_str());
|
||||||
|
}
|
||||||
|
return this->ch_config;
|
||||||
|
} else
|
||||||
|
return IdeChannel::read(reg_addr, 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 TIME_CONFIG", this->name.c_str());
|
||||||
|
}
|
||||||
|
this->ch_config = val;
|
||||||
|
} else
|
||||||
|
IdeChannel::write(reg_addr, val, size);
|
||||||
|
}
|
||||||
|
|
||||||
static const DeviceDescription Ide0_Descriptor = {
|
static const DeviceDescription Ide0_Descriptor = {
|
||||||
IdeChannel::create_first, {}, {}
|
MacioIdeChannel::create_first, {}, {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const DeviceDescription Ide1_Descriptor = {
|
static const DeviceDescription Ide1_Descriptor = {
|
||||||
IdeChannel::create_second, {}, {}
|
MacioIdeChannel::create_second, {}, {}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_DEVICE(Ide0, Ide0_Descriptor);
|
REGISTER_DEVICE(Ide0, Ide0_Descriptor);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||||
Copyright (C) 2018-23 divingkatae and maximum
|
Copyright (C) 2018-24 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)
|
||||||
@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#include <devices/common/hwinterrupt.h>
|
#include <devices/common/hwinterrupt.h>
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -38,16 +39,6 @@ public:
|
|||||||
IdeChannel(const std::string name);
|
IdeChannel(const std::string name);
|
||||||
~IdeChannel() = default;
|
~IdeChannel() = default;
|
||||||
|
|
||||||
static std::unique_ptr<HWComponent> create_first() {
|
|
||||||
return std::unique_ptr<IdeChannel>(new IdeChannel("IDE0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::unique_ptr<HWComponent> create_second() {
|
|
||||||
return std::unique_ptr<IdeChannel>(new IdeChannel("IDE1"));
|
|
||||||
}
|
|
||||||
|
|
||||||
int device_postinit() override;
|
|
||||||
|
|
||||||
void register_device(int id, AtaInterface* dev_obj);
|
void register_device(int id, AtaInterface* dev_obj);
|
||||||
|
|
||||||
uint32_t read(const uint8_t reg_addr, const int size);
|
uint32_t read(const uint8_t reg_addr, const int size);
|
||||||
@ -55,26 +46,56 @@ public:
|
|||||||
|
|
||||||
void assert_pdiag() {
|
void assert_pdiag() {
|
||||||
this->devices[0]->pdiag_callback();
|
this->devices[0]->pdiag_callback();
|
||||||
};
|
}
|
||||||
|
|
||||||
bool is_device1_present() {
|
bool is_device1_present() {
|
||||||
return this->devices[1]->get_device_id() != ata_interface::DEVICE_ID_INVALID;
|
return this->devices[1]->get_device_id() != ata_interface::DEVICE_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void report_intrq(uint8_t intrq_state) {
|
void set_irq_callback(std::function<void(const uint8_t intrq_state)> cb) {
|
||||||
this->int_ctrl->ack_int(this->irq_id, intrq_state);
|
this->irq_callback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void report_intrq(uint8_t intrq_state) {
|
||||||
|
this->irq_callback(intrq_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::function<void(const uint8_t intrq_state)> irq_callback = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int cur_dev = 0;
|
int cur_dev = 0;
|
||||||
uint32_t ch_config = 0; // timing configuration for this channel
|
|
||||||
AtaInterface* devices[2];
|
AtaInterface* devices[2];
|
||||||
|
|
||||||
// interrupt related stuff
|
|
||||||
InterruptCtrl* int_ctrl = nullptr;
|
|
||||||
uint32_t irq_id = 0;
|
|
||||||
|
|
||||||
std::unique_ptr<AtaInterface> device_stub;
|
std::unique_ptr<AtaInterface> 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<HWComponent> create_first() {
|
||||||
|
return std::unique_ptr<IdeChannel>(new MacioIdeChannel("IDE0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<HWComponent> create_second() {
|
||||||
|
return std::unique_ptr<IdeChannel>(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;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // IDE_CHANNEL_H
|
#endif // IDE_CHANNEL_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user