mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-23 21:29:28 +00:00
Rework ATA reset logic.
This commit is contained in:
parent
c543d0936c
commit
0f8e68d4bf
@ -1,6 +1,6 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-22 divingkatae and maximum
|
||||
Copyright (C) 2018-23 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
@ -30,32 +30,39 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using namespace ata_interface;
|
||||
|
||||
AtaBaseDevice::AtaBaseDevice(const std::string name)
|
||||
{
|
||||
AtaBaseDevice::AtaBaseDevice(const std::string name, uint8_t type) {
|
||||
this->set_name(name);
|
||||
supports_types(HWCompType::IDE_DEV);
|
||||
|
||||
device_reset();
|
||||
this->device_type = type;
|
||||
|
||||
device_reset(false);
|
||||
device_set_signature();
|
||||
}
|
||||
|
||||
void AtaBaseDevice::device_reset(const uint8_t dev_head_val)
|
||||
{
|
||||
this->r_error = 1; // Device 0 passed, Device 1 passed or not present
|
||||
void AtaBaseDevice::device_reset(bool is_soft_reset) {
|
||||
LOG_F(INFO, "%s: %s-reset triggered", this->name.c_str(),
|
||||
is_soft_reset ? "soft" : "hard");
|
||||
|
||||
// Diagnostic code
|
||||
this->r_error = 1; // device 0 passed, device 1 passed or not present
|
||||
}
|
||||
|
||||
void AtaBaseDevice::device_set_signature() {
|
||||
this->r_sect_count = 1;
|
||||
this->r_sect_num = 1;
|
||||
this->r_dev_ctrl = 0;
|
||||
this->r_dev_head = 0;
|
||||
|
||||
// set protocol signature
|
||||
if (this->device_type == DEVICE_TYPE_ATAPI) {
|
||||
this->r_cylinder_lo = 0x14;
|
||||
this->r_cylinder_hi = 0xEB;
|
||||
this->r_dev_head = dev_head_val;
|
||||
this->r_status_save = this->r_status; // for restoring on the first command
|
||||
this->r_status = 0;
|
||||
} else { // assume ATA by default
|
||||
this->r_cylinder_lo = 0;
|
||||
this->r_cylinder_hi = 0;
|
||||
this->r_dev_head = 0;
|
||||
this->r_status = DRDY | DSC;
|
||||
this->r_status = DRDY | DSC; // DSC=1 is required for ATA devices
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,13 +124,29 @@ void AtaBaseDevice::write(const uint8_t reg_addr, const uint16_t value) {
|
||||
}
|
||||
break;
|
||||
case ATA_Reg::DEV_CTRL:
|
||||
if (!(this->r_dev_ctrl & SRST) && (value & SRST)) {
|
||||
LOG_F(INFO, "%s: soft reset triggered", this->name.c_str());
|
||||
this->r_status |= BSY;
|
||||
}
|
||||
this->r_dev_ctrl = value;
|
||||
this->device_control(value);
|
||||
break;
|
||||
default:
|
||||
LOG_F(WARNING, "Attempted to write unknown IDE register: %x", reg_addr);
|
||||
}
|
||||
}
|
||||
|
||||
void AtaBaseDevice::device_control(const uint8_t new_ctrl) {
|
||||
// perform ATA Soft Reset if requested
|
||||
if ((this->r_dev_ctrl ^ new_ctrl) & SRST) {
|
||||
if (new_ctrl & SRST) { // SRST set -> phase 0 aka self-test
|
||||
this->r_status |= BSY;
|
||||
this->device_reset(true);
|
||||
} else { // SRST cleared -> phase 1 aka signature and error report
|
||||
if (!this->my_dev_id && this->host_obj->is_device1_present())
|
||||
this->r_error |= 0x80;
|
||||
this->device_set_signature();
|
||||
this->r_status &= ~BSY;
|
||||
|
||||
if (this->my_dev_id && this->r_error == 1) {
|
||||
this->host_obj->assert_pdiag();
|
||||
}
|
||||
}
|
||||
}
|
||||
this->r_dev_ctrl = new_ctrl;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-22 divingkatae and maximum
|
||||
Copyright (C) 2018-23 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#define ATA_BASE_DEVICE_H
|
||||
|
||||
#include <devices/common/ata/atadefs.h>
|
||||
#include <devices/common/ata/idechannel.h>
|
||||
#include <devices/common/hwcomponent.h>
|
||||
|
||||
#include <cinttypes>
|
||||
@ -32,17 +33,25 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
class AtaBaseDevice : public HWComponent, public AtaInterface
|
||||
{
|
||||
public:
|
||||
AtaBaseDevice(const std::string name);
|
||||
AtaBaseDevice(const std::string name, uint8_t type);
|
||||
~AtaBaseDevice() = default;
|
||||
|
||||
uint16_t read(const uint8_t reg_addr);
|
||||
void write(const uint8_t reg_addr, const uint16_t value);
|
||||
void set_host(IdeChannel* host) { this->host_obj = host; };
|
||||
|
||||
uint16_t read(const uint8_t reg_addr) override;
|
||||
void write(const uint8_t reg_addr, const uint16_t value) override;
|
||||
|
||||
virtual int perform_command() = 0;
|
||||
|
||||
int get_device_id() { return this->my_dev_id; };
|
||||
int get_device_id() override { return this->my_dev_id; };
|
||||
|
||||
void device_reset(const uint8_t dev_head_val = 0);
|
||||
void pdiag_callback() override {
|
||||
this->r_error &= 0x7F;
|
||||
};
|
||||
|
||||
void device_reset(bool is_soft_reset);
|
||||
void device_set_signature();
|
||||
void device_control(const uint8_t new_ctrl);
|
||||
|
||||
private:
|
||||
bool is_selected() { return ((this->r_dev_head >> 4) & 1) == this->my_dev_id; };
|
||||
@ -51,6 +60,8 @@ protected:
|
||||
uint8_t my_dev_id = 0; // my IDE device ID configured by the host
|
||||
uint8_t device_type = ata_interface::DEVICE_TYPE_UNKNOWN;
|
||||
|
||||
IdeChannel* host_obj = nullptr;
|
||||
|
||||
// IDE aka task file registers
|
||||
uint8_t r_error;
|
||||
uint8_t r_features;
|
||||
@ -61,7 +72,8 @@ protected:
|
||||
uint8_t r_dev_head;
|
||||
uint8_t r_command;
|
||||
uint8_t r_status;
|
||||
uint8_t r_dev_ctrl;
|
||||
uint8_t r_status_save;
|
||||
uint8_t r_dev_ctrl = 0x08;
|
||||
};
|
||||
|
||||
#endif // ATA_BASE_DEVICE_H
|
||||
|
@ -128,7 +128,8 @@ public:
|
||||
virtual uint16_t read(const uint8_t reg_addr) = 0;
|
||||
virtual void write(const uint8_t reg_addr, const uint16_t val) = 0;
|
||||
|
||||
virtual int get_device_id() = 0;
|
||||
virtual int get_device_id() = 0;
|
||||
virtual void pdiag_callback() {};
|
||||
};
|
||||
|
||||
/** Dummy ATA device. */
|
||||
@ -137,7 +138,7 @@ public:
|
||||
AtaNullDevice() = default;
|
||||
~AtaNullDevice() = default;
|
||||
|
||||
uint16_t read(const uint8_t reg_addr) {
|
||||
uint16_t read(const uint8_t reg_addr) override {
|
||||
// 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
|
||||
@ -146,10 +147,10 @@ public:
|
||||
return 0xFF7FU;
|
||||
};
|
||||
|
||||
void write(const uint8_t reg_addr, const uint16_t val) {};
|
||||
void write(const uint8_t reg_addr, const uint16_t val) override {};
|
||||
|
||||
// invalid device ID means no real device is present
|
||||
int get_device_id() { return ata_interface::DEVICE_ID_INVALID; };
|
||||
int get_device_id() override { return ata_interface::DEVICE_ID_INVALID; };
|
||||
};
|
||||
|
||||
#endif // ATA_INTERFACE_H
|
||||
|
@ -31,8 +31,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using namespace ata_interface;
|
||||
|
||||
AtaHardDisk::AtaHardDisk() : AtaBaseDevice("ATA-HD")
|
||||
{
|
||||
AtaHardDisk::AtaHardDisk() : AtaBaseDevice("ATA-HD", DEVICE_TYPE_ATA) {
|
||||
}
|
||||
|
||||
void AtaHardDisk::insert_image(std::string filename) {
|
||||
@ -57,7 +56,7 @@ int AtaHardDisk::perform_command()
|
||||
case NOP:
|
||||
break;
|
||||
case RESET_ATAPI:
|
||||
device_reset();
|
||||
device_reset(true);
|
||||
break;
|
||||
case RECALIBRATE:
|
||||
hdd_img.seekg(0, std::ios::beg);
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
~AtaHardDisk() = default;
|
||||
|
||||
void insert_image(std::string filename);
|
||||
int perform_command();
|
||||
int perform_command() override;
|
||||
|
||||
private:
|
||||
std::fstream hdd_img;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-22 divingkatae and maximum
|
||||
Copyright (C) 2018-23 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
@ -48,6 +48,14 @@ public:
|
||||
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);
|
||||
|
||||
void assert_pdiag() {
|
||||
this->devices[0]->pdiag_callback();
|
||||
};
|
||||
|
||||
bool is_device1_present() {
|
||||
return this->devices[1]->get_device_id() != ata_interface::DEVICE_ID_INVALID;
|
||||
}
|
||||
|
||||
private:
|
||||
int cur_dev = 0;
|
||||
uint32_t ch_config = 0; // timing configuration for this channel
|
||||
|
Loading…
Reference in New Issue
Block a user