From a892842b8f6cf03aaf0263cb25fe8b87b75c53c9 Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Wed, 7 Dec 2022 22:36:25 +0100 Subject: [PATCH] Refactor ATA/IDE classes. --- devices/common/ata/ata_bus.cpp | 37 ---------- devices/common/ata/ata_null.cpp | 64 ---------------- .../ata/{ata_full.cpp => atabasedevice.cpp} | 61 ++++----------- .../ata/{ata_null.h => atabasedevice.h} | 33 ++++----- devices/common/ata/{ata_bus.h => atadefs.h} | 51 +++++++------ devices/common/ata/idechannel.cpp | 74 +++++++++++++++++++ .../common/ata/{ata_full.h => idechannel.h} | 48 ++++++------ devices/ioctrl/heathrow.cpp | 38 ++++------ devices/ioctrl/macio.h | 9 +-- 9 files changed, 176 insertions(+), 239 deletions(-) delete mode 100644 devices/common/ata/ata_bus.cpp delete mode 100644 devices/common/ata/ata_null.cpp rename devices/common/ata/{ata_full.cpp => atabasedevice.cpp} (69%) rename devices/common/ata/{ata_null.h => atabasedevice.h} (61%) rename devices/common/ata/{ata_bus.h => atadefs.h} (69%) create mode 100644 devices/common/ata/idechannel.cpp rename devices/common/ata/{ata_full.h => idechannel.h} (50%) diff --git a/devices/common/ata/ata_bus.cpp b/devices/common/ata/ata_bus.cpp deleted file mode 100644 index 22a0afa..0000000 --- a/devices/common/ata/ata_bus.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* -DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-22 divingkatae and maximum - (theweirdo) spatium - -(Contact divingkatae#1017 or powermax#2286 on Discord for more info) - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -/** @file Heathrow hard drive controller */ - -#include -#include -#include -#include -#include -#include - -#define sector_size 512 - -using namespace std; - -AtaBus::AtaBus() { - supports_types(HWCompType::IDE_BUS); -} \ No newline at end of file diff --git a/devices/common/ata/ata_null.cpp b/devices/common/ata/ata_null.cpp deleted file mode 100644 index 6862a0f..0000000 --- a/devices/common/ata/ata_null.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* -DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-22 divingkatae and maximum - (theweirdo) spatium - -(Contact divingkatae#1017 or powermax#2286 on Discord for more info) - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -/** @file Null ATA device */ - -#include -#include -#include -#include -#include - -AtaNullDevice::AtaNullDevice() { - supports_types(HWCompType::IDE_DEV); - - regs[IDE_Reg::STATUS] = IDE_Status::DRDY | IDE_Status::DSC; - regs[IDE_Reg::ALT_STATUS] = IDE_Status::DRDY | IDE_Status::DSC; -} - -uint32_t AtaNullDevice::read(int reg) { - if (reg == IDE_Reg::ERROR) { - return IDE_Error::TK0NF; - } - else if (reg == IDE_Reg::STATUS) { - return IDE_Status::ERR; - } - LOG_F(WARNING, "Dummy read for IDE register 0x%x", reg); - return 0x0; -} - -void AtaNullDevice::write(int reg, uint32_t value) { - if (reg == IDE_Reg::COMMAND) { - process_command(value); - } - LOG_F(WARNING, "Dummy write for IDE register 0x%x with value 0x%x", reg, value); -} - -int AtaNullDevice::process_command(uint32_t cmd) { - LOG_F(ERROR, "Attempted to execute command %x", cmd); - return 0; -} - -static const DeviceDescription ATA_Null_Descriptor = { - AtaNullDevice::create, {}, {} -}; - -REGISTER_DEVICE(AtaNullDevice, ATA_Null_Descriptor); \ No newline at end of file diff --git a/devices/common/ata/ata_full.cpp b/devices/common/ata/atabasedevice.cpp similarity index 69% rename from devices/common/ata/ata_full.cpp rename to devices/common/ata/atabasedevice.cpp index 7b43b9d..bf1f463 100644 --- a/devices/common/ata/ata_full.cpp +++ b/devices/common/ata/atabasedevice.cpp @@ -21,18 +21,20 @@ along with this program. If not, see . /** @file Heathrow hard drive controller */ -#include +#include +#include #include -#include -#include #include -#include + +#include #define sector_size 512 using namespace std; -AtaFullDevice::AtaFullDevice() { +AtaBaseDevice::AtaBaseDevice(const std::string name) +{ + this->set_name(name); supports_types(HWCompType::IDE_DEV); regs[IDE_Reg::ERROR] = IDE_Error::ANMF; @@ -42,19 +44,8 @@ AtaFullDevice::AtaFullDevice() { regs[IDE_Reg::ALT_STATUS] = IDE_Status::DRDY | IDE_Status::DSC; } -void AtaFullDevice::insert_image(std::string filename) { - this->ide_img.open(filename, ios::out | ios::in | ios::binary); - - // Taken from: - // https://stackoverflow.com/questions/22984956/tellg-function-give-wrong-size-of-file/22986486 - ide_img.ignore(std::numeric_limits::max()); - img_size = this->ide_img.gcount(); - ide_img.clear(); // Since ignore will have set eof. - ide_img.seekg(0, std::ios_base::beg); -} - -uint32_t AtaFullDevice::read(int reg) { - switch (reg) { +uint16_t AtaBaseDevice::read(const uint8_t reg_addr) { + switch (reg_addr) { case IDE_Reg::IDE_DATA: LOG_F(0, "Retrieving DATA from IDE: %x", regs[IDE_Reg::IDE_DATA]); return regs[IDE_Reg::IDE_DATA]; @@ -77,13 +68,13 @@ uint32_t AtaFullDevice::read(int reg) { case IDE_Reg::TIME_CONFIG: return regs[IDE_Reg::TIME_CONFIG]; default: - LOG_F(WARNING, "Attempted to read unknown IDE register: %x", reg); - return 0x0; + LOG_F(WARNING, "Attempted to read unknown IDE register: %x", reg_addr); + return 0; } } -void AtaFullDevice::write(int reg, uint32_t value) { - switch (reg) { +void AtaBaseDevice::write(const uint8_t reg_addr, const uint16_t value) { + switch (reg_addr) { case IDE_Reg::IDE_DATA: regs[IDE_Reg::IDE_DATA] = value; break; @@ -108,7 +99,7 @@ void AtaFullDevice::write(int reg, uint32_t value) { case IDE_Reg::COMMAND: regs[IDE_Reg::COMMAND] = value; LOG_F(0, "Executing COMMAND for IDE: %x", value); - perform_command(value); + perform_command(); break; case IDE_Reg::DEV_CTRL: regs[IDE_Reg::DEV_CTRL] = value; @@ -117,28 +108,6 @@ void AtaFullDevice::write(int reg, uint32_t value) { regs[IDE_Reg::TIME_CONFIG] = value; break; default: - LOG_F(WARNING, "Attempted to write unknown IDE register: %x", reg); + LOG_F(WARNING, "Attempted to write unknown IDE register: %x", reg_addr); } } - -int AtaFullDevice::perform_command(uint32_t command) { - switch (command) { - case IDE_Cmd::READ_SECTOR: - LOG_F(WARNING, "Trying to read sector with: %x", command); - break; - case IDE_Cmd::WRITE_SECTOR: - LOG_F(WARNING, "Trying to write sector with: %x", command); - break; - default: - LOG_F(WARNING, "Attempted to execute IDE command: %x", command); - } - - return 0; -} - - -static const DeviceDescription ATA_Full_Descriptor = { - AtaFullDevice::create, {}, {} -}; - -REGISTER_DEVICE(AtaFullDevice, ATA_Full_Descriptor); \ No newline at end of file diff --git a/devices/common/ata/ata_null.h b/devices/common/ata/atabasedevice.h similarity index 61% rename from devices/common/ata/ata_null.h rename to devices/common/ata/atabasedevice.h index 22982d8..0da84ff 100644 --- a/devices/common/ata/ata_null.h +++ b/devices/common/ata/atabasedevice.h @@ -19,32 +19,29 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** @file Null ATA device */ +/** @file Base class for ATA devices. */ -#include +#ifndef ATA_BASE_DEVICE_H +#define ATA_BASE_DEVICE_H -#define SEC_SIZE 512 +#include +#include -#ifndef ATA_NULL_H -#define ATA_NULL_H +#include -class AtaNullDevice : public AtaBus { +class AtaBaseDevice : public HWComponent, public AtaInterface +{ public: - AtaNullDevice(); - ~AtaNullDevice() = default; + AtaBaseDevice(const std::string name); + ~AtaBaseDevice() = default; - static std::unique_ptr create() { - return std::unique_ptr(new AtaNullDevice()); - } + uint16_t read(const uint8_t reg_addr); + void write(const uint8_t reg_addr, const uint16_t value); - int process_command(uint32_t cmd); - - uint32_t read(int reg); - void write(int reg, uint32_t value); + virtual int perform_command() = 0; private: - uint32_t regs[33] = {0x0}; - uint8_t buffer[SEC_SIZE]; + uint8_t regs[33] = {}; }; -#endif \ No newline at end of file +#endif // ATA_BASE_DEVICE_H diff --git a/devices/common/ata/ata_bus.h b/devices/common/ata/atadefs.h similarity index 69% rename from devices/common/ata/ata_bus.h rename to devices/common/ata/atadefs.h index e988e85..73095ce 100644 --- a/devices/common/ata/ata_bus.h +++ b/devices/common/ata/atadefs.h @@ -19,21 +19,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** @file ATA hard drive support */ +/** @file ATA interface definitions. */ -#ifndef IDEDEVICE_H -#define IDEDEVICE_H +#ifndef ATA_INTERFACE_H +#define ATA_INTERFACE_H -#include #include -#include -#include -#include -#include - -#define SEC_SIZE 512 - -using namespace std; /** IDE register offsets. */ enum IDE_Reg : int { @@ -53,8 +44,8 @@ enum IDE_Reg : int { }; /** Status Register Bits */ -enum IDE_Status : int { - ERR = 0x1, +enum IDE_Status : int { + ERR = 0x1, IDX = 0x2, CORR = 0x4, DRQ = 0x8, @@ -92,13 +83,31 @@ enum IDE_Cmd : int { WRITE_DMA = 0xCA, }; -class AtaBus : public HWComponent { +/** Interface for ATA devices. */ +class AtaInterface { public: - AtaBus(); - ~AtaBus() = default; - - void connect_msg(); - void pass_msg(); + AtaInterface() = default; + virtual ~AtaInterface() = default; + virtual uint16_t read(const uint8_t reg_addr) = 0; + virtual void write(const uint8_t reg_addr, const uint16_t val) = 0; }; -#endif \ No newline at end of file +/** Dummy ATA device. */ +class AtaNullDevice : public AtaInterface { +public: + AtaNullDevice() = default; + ~AtaNullDevice() = default; + + uint16_t read(const uint8_t reg_addr) { + // return all one's except DD7 if no device is present + // DD7 corresponds to the BSY bit of the status register + // The host should have a pull-down resistor on DD7 + // to prevent the software from waiting for a long time + // for empty slots + return 0xFF7FU; + }; + + void write(const uint8_t reg_addr, const uint16_t val) {}; +}; + +#endif // ATA_INTERFACE_H diff --git a/devices/common/ata/idechannel.cpp b/devices/common/ata/idechannel.cpp new file mode 100644 index 0000000..fba111e --- /dev/null +++ b/devices/common/ata/idechannel.cpp @@ -0,0 +1,74 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-22 divingkatae and maximum + (theweirdo) spatium + +(Contact divingkatae#1017 or powermax#2286 on Discord for more info) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +/** 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 + from and to the host. + */ + +#include +#include +#include +#include + +#include +#include +#include + +IdeChannel::IdeChannel(const std::string name) +{ + this->set_name(name); + this->supports_types(HWCompType::IDE_BUS); + + this->devices[0] = std::unique_ptr(new AtaNullDevice()); + this->devices[1] = std::unique_ptr(new AtaNullDevice()); +} + +uint16_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 uint16_t val, const int size) +{ + // keep track of the currently selected device + if (reg_addr == IDE_Reg::DRIVE_HEAD) { + this->cur_dev = (val >> 4) & 1; + } + + // redirect register writes to both devices + for (auto& dev : this->devices) { + dev->write(reg_addr, val); + } +} + +static const DeviceDescription Ide0_Descriptor = { + IdeChannel::create_first, {}, {} +}; + +static const DeviceDescription Ide1_Descriptor = { + IdeChannel::create_second, {}, {} +}; + +REGISTER_DEVICE(Ide0, Ide0_Descriptor); +REGISTER_DEVICE(Ide1, Ide1_Descriptor); diff --git a/devices/common/ata/ata_full.h b/devices/common/ata/idechannel.h similarity index 50% rename from devices/common/ata/ata_full.h rename to devices/common/ata/idechannel.h index 58c2adb..427ea02 100644 --- a/devices/common/ata/ata_full.h +++ b/devices/common/ata/idechannel.h @@ -19,37 +19,39 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** @file Full ATA device */ +/** @file IDE Channel (aka IDE port) definitions. */ -#include +#ifndef IDE_CHANNEL_H +#define IDE_CHANNEL_H -#define SEC_SIZE 512 +#include +#include -#ifndef ATA_FULL_H -#define ATA_FULL_H +#include +#include +#include -class AtaFullDevice : public AtaBus { - public: - AtaFullDevice(); - ~AtaFullDevice() = default; +class IdeChannel : public HWComponent +{ +public: + IdeChannel(const std::string name); + ~IdeChannel() = default; - static std::unique_ptr create() { - return std::unique_ptr(new AtaFullDevice()); + static std::unique_ptr create_first() { + return std::unique_ptr(new IdeChannel("IDEO")); } - void insert_image(std::string filename); - uint32_t read(int reg); - void write(int reg, uint32_t value); + static std::unique_ptr create_second() { + return std::unique_ptr(new IdeChannel("IDE1")); + } - int perform_command(uint32_t command); - void get_status(); + uint16_t read(const uint8_t reg_addr, const int size); + void write(const uint8_t reg_addr, const uint16_t val, const int size); - private: - uint32_t regs[33] = {0x0}; - uint8_t buffer[SEC_SIZE]; - std::fstream ide_img; - uint64_t img_size; +private: + int cur_dev = 0; + + std::unique_ptr devices[2]; }; - -#endif \ No newline at end of file +#endif // IDE_CHANNEL_H diff --git a/devices/ioctrl/heathrow.cpp b/devices/ioctrl/heathrow.cpp index 7edb011..f22b82f 100644 --- a/devices/ioctrl/heathrow.cpp +++ b/devices/ioctrl/heathrow.cpp @@ -21,11 +21,10 @@ along with this program. If not, see . #include #include +#include #include #include #include -#include -#include #include #include #include @@ -81,13 +80,8 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow"), InterruptCtrl() this->mesh = dynamic_cast(gMachineObj->get_comp_by_name("Mesh")); // connect IDE HW - this->ide_0 = dynamic_cast(gMachineObj->get_comp_by_name("AtaNullDevice")); - this->ide_1 = dynamic_cast(gMachineObj->get_comp_by_name("AtaNullDevice")); - - //std::string hd_image_path = GET_STR_PROP("hdd_img"); - //if (!hd_image_path.empty()) { - // this->ide_1->insert_image(hd_image_path); - //} + this->ide_0 = dynamic_cast(gMachineObj->get_comp_by_name("Ide0")); + this->ide_1 = dynamic_cast(gMachineObj->get_comp_by_name("Ide1")); // connect serial HW this->escc = dynamic_cast(gMachineObj->get_comp_by_name("Escc")); @@ -168,17 +162,15 @@ uint32_t HeathrowIC::read(uint32_t rgn_start, uint32_t offset, int size) { break; case 0x15: // SWIM3 return this->swim3->read((offset >> 4 )& 0xF); - case 0x16: + case 0x16: // VIA-CUDA case 0x17: res = this->viacuda->read((offset - 0x16000) >> 9); break; - case 0x20: // IDE 0 - LOG_F(0, "Read IDE 0 - offset=0x%X", offset); - res = this->ide_0->read((offset >> 4) & 0x1F); + case 0x20: // IDE 0 + res = this->ide_0->read((offset >> 4) & 0x1F, size); break; - case 0x21: //IDE 1 - LOG_F(0, "Read IDE 1 - offset=0x%X", offset); - res = this->ide_1->read((offset >> 4) & 0x1F); + case 0x21: // IDE 1 + res = this->ide_1->read((offset >> 4) & 0x1F, size); break; default: if (sub_addr >= 0x60) { @@ -221,17 +213,15 @@ void HeathrowIC::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int case 0x15: // SWIM3 this->swim3->write((offset >> 4) & 0xF, value); break; - case 0x16: + case 0x16: // VIA-CUDA case 0x17: this->viacuda->write((offset - 0x16000) >> 9, value); break; - case 0x20: - LOG_F(0, "Write IDE 0 - offset=0x%X", offset); - this->ide_0->write((offset >> 4) & 0x1F, value); + case 0x20: // IDE O + this->ide_0->write((offset >> 4) & 0x1F, value, size); break; - case 0x21: - LOG_F(0, "Write IDE 1 - offset=0x%X", offset); - this->ide_1->write((offset >> 4) & 0x1F, value); + case 0x21: // IDE 1 + this->ide_1->write((offset >> 4) & 0x1F, value, size); break; default: if (sub_addr >= 0x60) { @@ -409,7 +399,7 @@ void HeathrowIC::clear_cpu_int() } static const vector Heathrow_Subdevices = { - "NVRAM", "ViaCuda", "Mesh", "Escc", "Swim3", "AtaNullDevice"}; + "NVRAM", "ViaCuda", "Mesh", "Escc", "Swim3", "Ide0", "Ide1"}; static const DeviceDescription Heathrow_Descriptor = { HeathrowIC::create, Heathrow_Subdevices, {} diff --git a/devices/ioctrl/macio.h b/devices/ioctrl/macio.h index f528bfa..ad7951c 100644 --- a/devices/ioctrl/macio.h +++ b/devices/ioctrl/macio.h @@ -51,11 +51,10 @@ along with this program. If not, see . #ifndef MACIO_H #define MACIO_H +#include #include #include #include -#include -#include #include #include #include @@ -139,8 +138,6 @@ private: MaceController* mace; ViaCuda* viacuda; // VIA cell with Cuda MCU attached to it EsccController* escc; // ESCC serial controller - AtaNullDevice* ide_0; // Internal ATA - AtaNullDevice* ide_1; // Media Bay ATA Sc53C94* scsi_0; // external SCSI Swim3::Swim3Ctrl* swim3; // floppy disk controller @@ -233,8 +230,8 @@ private: ViaCuda* viacuda; // VIA cell with Cuda MCU attached to it MESHController* mesh; // MESH SCSI cell instance EsccController* escc; // ESCC serial controller - AtaNullDevice* ide_0; // Internal ATA - AtaNullDevice* ide_1; // Media Bay ATA + IdeChannel* ide_0; // Internal ATA + IdeChannel* ide_1; // Media Bay ATA Swim3::Swim3Ctrl* swim3; // floppy disk controller std::unique_ptr snd_out_dma;