Refactor ATA/IDE classes.

This commit is contained in:
Maxim Poliakovski 2022-12-07 22:36:25 +01:00
parent 58908621e6
commit a892842b8f
9 changed files with 176 additions and 239 deletions

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
/** @file Heathrow hard drive controller */
#include <devices/deviceregistry.h>
#include <devices/common/ata/ata_bus.h>
#include <fstream>
#include <limits>
#include <stdio.h>
#include <loguru.hpp>
#define sector_size 512
using namespace std;
AtaBus::AtaBus() {
supports_types(HWCompType::IDE_BUS);
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
/** @file Null ATA device */
#include <devices/common/ata/ata_null.h>
#include <devices/deviceregistry.h>
#include <cinttypes>
#include <fstream>
#include <loguru.hpp>
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);

View File

@ -21,18 +21,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
/** @file Heathrow hard drive controller */ /** @file Heathrow hard drive controller */
#include <devices/common/ata/ata_full.h> #include <devices/common/ata/atabasedevice.h>
#include <devices/common/ata/atadefs.h>
#include <devices/deviceregistry.h> #include <devices/deviceregistry.h>
#include <fstream>
#include <limits>
#include <loguru.hpp> #include <loguru.hpp>
#include <stdio.h>
#include <cinttypes>
#define sector_size 512 #define sector_size 512
using namespace std; using namespace std;
AtaFullDevice::AtaFullDevice() { AtaBaseDevice::AtaBaseDevice(const std::string name)
{
this->set_name(name);
supports_types(HWCompType::IDE_DEV); supports_types(HWCompType::IDE_DEV);
regs[IDE_Reg::ERROR] = IDE_Error::ANMF; regs[IDE_Reg::ERROR] = IDE_Error::ANMF;
@ -42,19 +44,8 @@ AtaFullDevice::AtaFullDevice() {
regs[IDE_Reg::ALT_STATUS] = IDE_Status::DRDY | IDE_Status::DSC; regs[IDE_Reg::ALT_STATUS] = IDE_Status::DRDY | IDE_Status::DSC;
} }
void AtaFullDevice::insert_image(std::string filename) { uint16_t AtaBaseDevice::read(const uint8_t reg_addr) {
this->ide_img.open(filename, ios::out | ios::in | ios::binary); switch (reg_addr) {
// Taken from:
// https://stackoverflow.com/questions/22984956/tellg-function-give-wrong-size-of-file/22986486
ide_img.ignore(std::numeric_limits<std::streamsize>::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) {
case IDE_Reg::IDE_DATA: case IDE_Reg::IDE_DATA:
LOG_F(0, "Retrieving DATA from IDE: %x", regs[IDE_Reg::IDE_DATA]); LOG_F(0, "Retrieving DATA from IDE: %x", regs[IDE_Reg::IDE_DATA]);
return 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: case IDE_Reg::TIME_CONFIG:
return regs[IDE_Reg::TIME_CONFIG]; return regs[IDE_Reg::TIME_CONFIG];
default: default:
LOG_F(WARNING, "Attempted to read unknown IDE register: %x", reg); LOG_F(WARNING, "Attempted to read unknown IDE register: %x", reg_addr);
return 0x0; return 0;
} }
} }
void AtaFullDevice::write(int reg, uint32_t value) { void AtaBaseDevice::write(const uint8_t reg_addr, const uint16_t value) {
switch (reg) { switch (reg_addr) {
case IDE_Reg::IDE_DATA: case IDE_Reg::IDE_DATA:
regs[IDE_Reg::IDE_DATA] = value; regs[IDE_Reg::IDE_DATA] = value;
break; break;
@ -108,7 +99,7 @@ void AtaFullDevice::write(int reg, uint32_t value) {
case IDE_Reg::COMMAND: case IDE_Reg::COMMAND:
regs[IDE_Reg::COMMAND] = value; regs[IDE_Reg::COMMAND] = value;
LOG_F(0, "Executing COMMAND for IDE: %x", value); LOG_F(0, "Executing COMMAND for IDE: %x", value);
perform_command(value); perform_command();
break; break;
case IDE_Reg::DEV_CTRL: case IDE_Reg::DEV_CTRL:
regs[IDE_Reg::DEV_CTRL] = value; regs[IDE_Reg::DEV_CTRL] = value;
@ -117,28 +108,6 @@ void AtaFullDevice::write(int reg, uint32_t value) {
regs[IDE_Reg::TIME_CONFIG] = value; regs[IDE_Reg::TIME_CONFIG] = value;
break; break;
default: 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);

View File

@ -19,32 +19,29 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
/** @file Null ATA device */ /** @file Base class for ATA devices. */
#include <devices/common/ata/ata_bus.h> #ifndef ATA_BASE_DEVICE_H
#define ATA_BASE_DEVICE_H
#define SEC_SIZE 512 #include <devices/common/ata/atadefs.h>
#include <devices/common/hwcomponent.h>
#ifndef ATA_NULL_H #include <cinttypes>
#define ATA_NULL_H
class AtaNullDevice : public AtaBus { class AtaBaseDevice : public HWComponent, public AtaInterface
{
public: public:
AtaNullDevice(); AtaBaseDevice(const std::string name);
~AtaNullDevice() = default; ~AtaBaseDevice() = default;
static std::unique_ptr<HWComponent> create() { uint16_t read(const uint8_t reg_addr);
return std::unique_ptr<AtaNullDevice>(new AtaNullDevice()); void write(const uint8_t reg_addr, const uint16_t value);
}
int process_command(uint32_t cmd); virtual int perform_command() = 0;
uint32_t read(int reg);
void write(int reg, uint32_t value);
private: private:
uint32_t regs[33] = {0x0}; uint8_t regs[33] = {};
uint8_t buffer[SEC_SIZE];
}; };
#endif #endif // ATA_BASE_DEVICE_H

View File

@ -19,21 +19,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
/** @file ATA hard drive support */ /** @file ATA interface definitions. */
#ifndef IDEDEVICE_H #ifndef ATA_INTERFACE_H
#define IDEDEVICE_H #define ATA_INTERFACE_H
#include <devices/common/hwcomponent.h>
#include <cinttypes> #include <cinttypes>
#include <fstream>
#include <memory>
#include <stdio.h>
#include <string>
#define SEC_SIZE 512
using namespace std;
/** IDE register offsets. */ /** IDE register offsets. */
enum IDE_Reg : int { enum IDE_Reg : int {
@ -92,13 +83,31 @@ enum IDE_Cmd : int {
WRITE_DMA = 0xCA, WRITE_DMA = 0xCA,
}; };
class AtaBus : public HWComponent { /** Interface for ATA devices. */
class AtaInterface {
public: public:
AtaBus(); AtaInterface() = default;
~AtaBus() = default; virtual ~AtaInterface() = default;
virtual uint16_t read(const uint8_t reg_addr) = 0;
void connect_msg(); virtual void write(const uint8_t reg_addr, const uint16_t val) = 0;
void pass_msg();
}; };
#endif /** 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

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
/** 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 <devices/common/ata/atadefs.h>
#include <devices/common/ata/idechannel.h>
#include <devices/common/hwcomponent.h>
#include <devices/deviceregistry.h>
#include <cinttypes>
#include <memory>
#include <string>
IdeChannel::IdeChannel(const std::string name)
{
this->set_name(name);
this->supports_types(HWCompType::IDE_BUS);
this->devices[0] = std::unique_ptr<AtaNullDevice>(new AtaNullDevice());
this->devices[1] = std::unique_ptr<AtaNullDevice>(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);

View File

@ -19,37 +19,39 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
/** @file Full ATA device */ /** @file IDE Channel (aka IDE port) definitions. */
#include <devices/common/ata/ata_bus.h> #ifndef IDE_CHANNEL_H
#define IDE_CHANNEL_H
#define SEC_SIZE 512 #include <devices/common/ata/atadefs.h>
#include <devices/common/hwcomponent.h>
#ifndef ATA_FULL_H #include <cinttypes>
#define ATA_FULL_H #include <memory>
#include <string>
class AtaFullDevice : public AtaBus { class IdeChannel : public HWComponent
{
public: public:
AtaFullDevice(); IdeChannel(const std::string name);
~AtaFullDevice() = default; ~IdeChannel() = default;
static std::unique_ptr<HWComponent> create() { static std::unique_ptr<HWComponent> create_first() {
return std::unique_ptr<AtaFullDevice>(new AtaFullDevice()); return std::unique_ptr<IdeChannel>(new IdeChannel("IDEO"));
} }
void insert_image(std::string filename); static std::unique_ptr<HWComponent> create_second() {
uint32_t read(int reg); return std::unique_ptr<IdeChannel>(new IdeChannel("IDE1"));
void write(int reg, uint32_t value); }
int perform_command(uint32_t command); uint16_t read(const uint8_t reg_addr, const int size);
void get_status(); void write(const uint8_t reg_addr, const uint16_t val, const int size);
private: private:
uint32_t regs[33] = {0x0}; int cur_dev = 0;
uint8_t buffer[SEC_SIZE];
std::fstream ide_img; std::unique_ptr<AtaInterface> devices[2];
uint64_t img_size;
}; };
#endif // IDE_CHANNEL_H
#endif

View File

@ -21,11 +21,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <cpu/ppc/ppcemu.h> #include <cpu/ppc/ppcemu.h>
#include <devices/deviceregistry.h> #include <devices/deviceregistry.h>
#include <devices/common/ata/idechannel.h>
#include <devices/common/dbdma.h> #include <devices/common/dbdma.h>
#include <devices/common/hwcomponent.h> #include <devices/common/hwcomponent.h>
#include <devices/common/viacuda.h> #include <devices/common/viacuda.h>
#include <devices/common/ata/ata_full.h>
#include <devices/common/ata/ata_null.h>
#include <devices/floppy/swim3.h> #include <devices/floppy/swim3.h>
#include <devices/ioctrl/macio.h> #include <devices/ioctrl/macio.h>
#include <devices/serial/escc.h> #include <devices/serial/escc.h>
@ -81,13 +80,8 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow"), InterruptCtrl()
this->mesh = dynamic_cast<MESHController*>(gMachineObj->get_comp_by_name("Mesh")); this->mesh = dynamic_cast<MESHController*>(gMachineObj->get_comp_by_name("Mesh"));
// connect IDE HW // connect IDE HW
this->ide_0 = dynamic_cast<AtaNullDevice*>(gMachineObj->get_comp_by_name("AtaNullDevice")); this->ide_0 = dynamic_cast<IdeChannel*>(gMachineObj->get_comp_by_name("Ide0"));
this->ide_1 = dynamic_cast<AtaNullDevice*>(gMachineObj->get_comp_by_name("AtaNullDevice")); this->ide_1 = dynamic_cast<IdeChannel*>(gMachineObj->get_comp_by_name("Ide1"));
//std::string hd_image_path = GET_STR_PROP("hdd_img");
//if (!hd_image_path.empty()) {
// this->ide_1->insert_image(hd_image_path);
//}
// connect serial HW // connect serial HW
this->escc = dynamic_cast<EsccController*>(gMachineObj->get_comp_by_name("Escc")); this->escc = dynamic_cast<EsccController*>(gMachineObj->get_comp_by_name("Escc"));
@ -168,17 +162,15 @@ uint32_t HeathrowIC::read(uint32_t rgn_start, uint32_t offset, int size) {
break; break;
case 0x15: // SWIM3 case 0x15: // SWIM3
return this->swim3->read((offset >> 4 )& 0xF); return this->swim3->read((offset >> 4 )& 0xF);
case 0x16: case 0x16: // VIA-CUDA
case 0x17: case 0x17:
res = this->viacuda->read((offset - 0x16000) >> 9); res = this->viacuda->read((offset - 0x16000) >> 9);
break; break;
case 0x20: // IDE 0 case 0x20: // IDE 0
LOG_F(0, "Read IDE 0 - offset=0x%X", offset); res = this->ide_0->read((offset >> 4) & 0x1F, size);
res = this->ide_0->read((offset >> 4) & 0x1F);
break; break;
case 0x21: // IDE 1 case 0x21: // IDE 1
LOG_F(0, "Read IDE 1 - offset=0x%X", offset); res = this->ide_1->read((offset >> 4) & 0x1F, size);
res = this->ide_1->read((offset >> 4) & 0x1F);
break; break;
default: default:
if (sub_addr >= 0x60) { 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 case 0x15: // SWIM3
this->swim3->write((offset >> 4) & 0xF, value); this->swim3->write((offset >> 4) & 0xF, value);
break; break;
case 0x16: case 0x16: // VIA-CUDA
case 0x17: case 0x17:
this->viacuda->write((offset - 0x16000) >> 9, value); this->viacuda->write((offset - 0x16000) >> 9, value);
break; break;
case 0x20: case 0x20: // IDE O
LOG_F(0, "Write IDE 0 - offset=0x%X", offset); this->ide_0->write((offset >> 4) & 0x1F, value, size);
this->ide_0->write((offset >> 4) & 0x1F, value);
break; break;
case 0x21: case 0x21: // IDE 1
LOG_F(0, "Write IDE 1 - offset=0x%X", offset); this->ide_1->write((offset >> 4) & 0x1F, value, size);
this->ide_1->write((offset >> 4) & 0x1F, value);
break; break;
default: default:
if (sub_addr >= 0x60) { if (sub_addr >= 0x60) {
@ -409,7 +399,7 @@ void HeathrowIC::clear_cpu_int()
} }
static const vector<string> Heathrow_Subdevices = { static const vector<string> Heathrow_Subdevices = {
"NVRAM", "ViaCuda", "Mesh", "Escc", "Swim3", "AtaNullDevice"}; "NVRAM", "ViaCuda", "Mesh", "Escc", "Swim3", "Ide0", "Ide1"};
static const DeviceDescription Heathrow_Descriptor = { static const DeviceDescription Heathrow_Descriptor = {
HeathrowIC::create, Heathrow_Subdevices, {} HeathrowIC::create, Heathrow_Subdevices, {}

View File

@ -51,11 +51,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef MACIO_H #ifndef MACIO_H
#define MACIO_H #define MACIO_H
#include <devices/common/ata/idechannel.h>
#include <devices/common/dbdma.h> #include <devices/common/dbdma.h>
#include <devices/common/mmiodevice.h> #include <devices/common/mmiodevice.h>
#include <devices/common/nvram.h> #include <devices/common/nvram.h>
#include <devices/common/ata/ata_full.h>
#include <devices/common/ata/ata_null.h>
#include <devices/common/pci/pcidevice.h> #include <devices/common/pci/pcidevice.h>
#include <devices/common/pci/pcihost.h> #include <devices/common/pci/pcihost.h>
#include <devices/common/scsi/mesh.h> #include <devices/common/scsi/mesh.h>
@ -139,8 +138,6 @@ private:
MaceController* mace; MaceController* mace;
ViaCuda* viacuda; // VIA cell with Cuda MCU attached to it ViaCuda* viacuda; // VIA cell with Cuda MCU attached to it
EsccController* escc; // ESCC serial controller EsccController* escc; // ESCC serial controller
AtaNullDevice* ide_0; // Internal ATA
AtaNullDevice* ide_1; // Media Bay ATA
Sc53C94* scsi_0; // external SCSI Sc53C94* scsi_0; // external SCSI
Swim3::Swim3Ctrl* swim3; // floppy disk controller Swim3::Swim3Ctrl* swim3; // floppy disk controller
@ -233,8 +230,8 @@ private:
ViaCuda* viacuda; // VIA cell with Cuda MCU attached to it ViaCuda* viacuda; // VIA cell with Cuda MCU attached to it
MESHController* mesh; // MESH SCSI cell instance MESHController* mesh; // MESH SCSI cell instance
EsccController* escc; // ESCC serial controller EsccController* escc; // ESCC serial controller
AtaNullDevice* ide_0; // Internal ATA IdeChannel* ide_0; // Internal ATA
AtaNullDevice* ide_1; // Media Bay ATA IdeChannel* ide_1; // Media Bay ATA
Swim3::Swim3Ctrl* swim3; // floppy disk controller Swim3::Swim3Ctrl* swim3; // floppy disk controller
std::unique_ptr<DMAChannel> snd_out_dma; std::unique_ptr<DMAChannel> snd_out_dma;