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 */
#include <devices/common/ata/ata_full.h>
#include <devices/common/ata/atabasedevice.h>
#include <devices/common/ata/atadefs.h>
#include <devices/deviceregistry.h>
#include <fstream>
#include <limits>
#include <loguru.hpp>
#include <stdio.h>
#include <cinttypes>
#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<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) {
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);

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/>.
*/
/** @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
#define ATA_NULL_H
#include <cinttypes>
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<HWComponent> create() {
return std::unique_ptr<AtaNullDevice>(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
#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/>.
*/
/** @file ATA hard drive support */
/** @file ATA interface definitions. */
#ifndef IDEDEVICE_H
#define IDEDEVICE_H
#ifndef ATA_INTERFACE_H
#define ATA_INTERFACE_H
#include <devices/common/hwcomponent.h>
#include <cinttypes>
#include <fstream>
#include <memory>
#include <stdio.h>
#include <string>
#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
/** 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/>.
*/
/** @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
#define ATA_FULL_H
#include <cinttypes>
#include <memory>
#include <string>
class AtaFullDevice : public AtaBus {
public:
AtaFullDevice();
~AtaFullDevice() = default;
class IdeChannel : public HWComponent
{
public:
IdeChannel(const std::string name);
~IdeChannel() = default;
static std::unique_ptr<HWComponent> create() {
return std::unique_ptr<AtaFullDevice>(new AtaFullDevice());
static std::unique_ptr<HWComponent> create_first() {
return std::unique_ptr<IdeChannel>(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<HWComponent> create_second() {
return std::unique_ptr<IdeChannel>(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<AtaInterface> devices[2];
};
#endif
#endif // IDE_CHANNEL_H

View File

@ -21,11 +21,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <cpu/ppc/ppcemu.h>
#include <devices/deviceregistry.h>
#include <devices/common/ata/idechannel.h>
#include <devices/common/dbdma.h>
#include <devices/common/hwcomponent.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/ioctrl/macio.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"));
// connect IDE HW
this->ide_0 = dynamic_cast<AtaNullDevice*>(gMachineObj->get_comp_by_name("AtaNullDevice"));
this->ide_1 = dynamic_cast<AtaNullDevice*>(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<IdeChannel*>(gMachineObj->get_comp_by_name("Ide0"));
this->ide_1 = dynamic_cast<IdeChannel*>(gMachineObj->get_comp_by_name("Ide1"));
// connect serial HW
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;
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<string> Heathrow_Subdevices = {
"NVRAM", "ViaCuda", "Mesh", "Escc", "Swim3", "AtaNullDevice"};
"NVRAM", "ViaCuda", "Mesh", "Escc", "Swim3", "Ide0", "Ide1"};
static const DeviceDescription Heathrow_Descriptor = {
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
#define MACIO_H
#include <devices/common/ata/idechannel.h>
#include <devices/common/dbdma.h>
#include <devices/common/mmiodevice.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/pcihost.h>
#include <devices/common/scsi/mesh.h>
@ -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<DMAChannel> snd_out_dma;