mirror of
https://github.com/dingusdev/dingusppc.git
synced 2026-04-20 18:17:02 +00:00
Merge branch 'master' into awacs-pdm-fix
This commit is contained in:
@@ -114,6 +114,8 @@ enum SPR : int {
|
||||
PMC2 = 954,
|
||||
SIA = 955,
|
||||
MMCR1 = 956,
|
||||
PMC3 = 957,
|
||||
PMC4 = 958,
|
||||
SDA = 959,
|
||||
HID0 = 1008,
|
||||
HID1 = 1009,
|
||||
|
||||
+2
-1
@@ -899,7 +899,8 @@ static map<string, int> SPRName2Num = {
|
||||
{"SDR1", SPR::SDR1}, {"MQ", SPR::MQ}, {"RTCU", SPR::RTCU_S},
|
||||
{"RTCL", SPR::RTCL_S}, {"DSISR", SPR::DSISR}, {"DAR", SPR::DAR},
|
||||
{"MMCR0", SPR::MMCR0}, {"PMC1", SPR::PMC1}, {"PMC2", SPR::PMC2},
|
||||
{"SDA", SPR::SDA}, {"SIA", SPR::SIA}, {"MMCR1", SPR::MMCR1}
|
||||
{"SDA", SPR::SDA}, {"SIA", SPR::SIA}, {"MMCR1", SPR::MMCR1},
|
||||
{"PMC3", SPR::PMC3}, {"PMC4", SPR::PMC4},
|
||||
};
|
||||
|
||||
static uint64_t reg_op(string& reg_name, uint64_t val, bool is_write) {
|
||||
|
||||
@@ -21,13 +21,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/** @file Basic ATA device emulation. */
|
||||
|
||||
#include <core/timermanager.h>
|
||||
#include <devices/common/ata/atabasedevice.h>
|
||||
#include <devices/common/ata/atadefs.h>
|
||||
#include <devices/common/ata/idechannel.h>
|
||||
#include <loguru.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
#include <core/timermanager.h>
|
||||
|
||||
using namespace ata_interface;
|
||||
|
||||
@@ -191,6 +192,38 @@ void AtaBaseDevice::device_control(const uint8_t new_ctrl) {
|
||||
this->r_dev_ctrl = new_ctrl;
|
||||
}
|
||||
|
||||
int AtaBaseDevice::pull_data(uint8_t *buf, int len) {
|
||||
if (!this->xfer_cnt || !this->is_dma_xfer)
|
||||
return 0;
|
||||
|
||||
int xfer_size = std::min(this->xfer_cnt, len);
|
||||
|
||||
if (this->xfer_cnt != len)
|
||||
LOG_F(WARNING, "%s: xfer_cnt != len", this->name.c_str());
|
||||
|
||||
//for (int i = 0; i < xfer_size >> 1; i++)
|
||||
// this->data_ptr[i] = BYTESWAP_16(this->data_ptr[i]);
|
||||
|
||||
std::memcpy(buf, this->data_ptr, xfer_size);
|
||||
|
||||
this->xfer_cnt -= xfer_size;
|
||||
if (!this->xfer_cnt) {
|
||||
TimerManager::get_instance()->add_oneshot_timer(500, [this]() {
|
||||
this->r_status &= ~(BSY | DRQ);
|
||||
this->update_intrq(1);
|
||||
});
|
||||
} else {
|
||||
this->r_status &= ~BSY;
|
||||
this->r_status |= DRQ;
|
||||
}
|
||||
|
||||
return xfer_size;
|
||||
}
|
||||
|
||||
int AtaBaseDevice::push_data(uint8_t *buf, int len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AtaBaseDevice::update_intrq(uint8_t new_intrq_state) {
|
||||
if (!this->is_selected() || (this->r_dev_ctrl & IEN))
|
||||
return;
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
|
||||
uint16_t read(const uint8_t reg_addr) override;
|
||||
void write(const uint8_t reg_addr, const uint16_t value) override;
|
||||
int pull_data(uint8_t *buf, int len) override;
|
||||
int push_data(uint8_t *buf, int len) override;
|
||||
|
||||
virtual int perform_command() = 0;
|
||||
|
||||
@@ -103,6 +105,7 @@ protected:
|
||||
int xfer_cnt = 0;
|
||||
int chunk_cnt = 0;
|
||||
int chunk_size = 0;
|
||||
bool is_dma_xfer = false;
|
||||
|
||||
std::function<void()> post_xfer_action = nullptr;
|
||||
};
|
||||
|
||||
@@ -163,6 +163,8 @@ public:
|
||||
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;
|
||||
virtual int pull_data(uint8_t *buf, int len) { return 0; };
|
||||
virtual int push_data(uint8_t *buf, int len) { return 0; };
|
||||
|
||||
virtual int get_device_id() = 0;
|
||||
virtual void pdiag_callback() {}
|
||||
|
||||
@@ -245,29 +245,32 @@ void AtaHardDisk::prepare_identify_info() {
|
||||
|
||||
std::memset(this->data_buf, 0, sizeof(this->data_buf));
|
||||
|
||||
buf_ptr[ 0] = 0x0040; // ATA device, non-removable media, non-removable drive
|
||||
buf_ptr[49] = 0x0200; // report LBA support
|
||||
WRITE_WORD_LE_A(&buf_ptr[ 0], 0x0040); // ATA device, non-removable media, non-removable drive
|
||||
WRITE_WORD_LE_A(&buf_ptr[49], 0x0200); // report LBA support
|
||||
|
||||
// Maximum number of logical sectors per data block that the device supports
|
||||
// for READ_MULTIPLE/WRITE_MULTIPLE commands.
|
||||
buf_ptr[47] = 0x8000 | SECTORS_PER_INT;
|
||||
WRITE_WORD_LE_A(&buf_ptr[47], 0x8000 | SECTORS_PER_INT);
|
||||
|
||||
// If bit 8 of word 59 is set to one, then bits 7:0 indicate the number of
|
||||
// logical sectors that shall be transferred per data block for
|
||||
// READ_MULTIPLE/WRITE_MULTIPLE commands.
|
||||
if (this->sectors_per_int)
|
||||
buf_ptr[59] = 0x100 | this->sectors_per_int;
|
||||
WRITE_WORD_LE_A(&buf_ptr[59], 0x100 | this->sectors_per_int);
|
||||
|
||||
buf_ptr[ 1] = this->cylinders;
|
||||
buf_ptr[ 3] = this->heads;
|
||||
buf_ptr[ 6] = this->sectors;
|
||||
WRITE_WORD_LE_A(&buf_ptr[ 1], this->cylinders);
|
||||
WRITE_WORD_LE_A(&buf_ptr[ 3], this->heads);
|
||||
WRITE_WORD_LE_A(&buf_ptr[ 6], this->sectors);
|
||||
|
||||
buf_ptr[57] = this->total_sectors & 0xFFFFU;
|
||||
buf_ptr[58] = (this->total_sectors >> 16) & 0xFFFFU;
|
||||
WRITE_WORD_LE_A(&buf_ptr[51], 0x0200); // max. PIO mode for a basic device
|
||||
|
||||
// report validity for the advanced PIO and MWDMA fields
|
||||
//WRITE_WORD_LE_A(&buf_ptr[53], 0x0003);
|
||||
|
||||
WRITE_DWORD_LE_A(&buf_ptr[57], this->total_sectors);
|
||||
|
||||
// report LBA capacity
|
||||
WRITE_WORD_LE_A(&buf_ptr[60], (this->total_sectors & 0xFFFFU));
|
||||
WRITE_WORD_LE_A(&buf_ptr[61], (this->total_sectors >> 16) & 0xFFFFU);
|
||||
WRITE_DWORD_LE_A(&buf_ptr[60], this->total_sectors);
|
||||
|
||||
WRITE_WORD_LE_A(&buf_ptr[63], ((1 << this->cur_dma_mode) << 8) | 7);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
and interrupt handling.
|
||||
*/
|
||||
|
||||
#include <core/timermanager.h>
|
||||
#include <devices/common/ata/atabasedevice.h>
|
||||
#include <devices/common/ata/atadefs.h>
|
||||
#include <devices/common/ata/idechannel.h>
|
||||
@@ -81,6 +82,21 @@ void IdeChannel::write(const uint8_t reg_addr, const uint32_t val, const int siz
|
||||
}
|
||||
}
|
||||
|
||||
int IdeChannel::xfer_from(uint8_t *buf, int len) {
|
||||
return this->devices[this->cur_dev]->pull_data(buf, len);
|
||||
}
|
||||
|
||||
int IdeChannel::xfer_to(uint8_t *buf, int len) {
|
||||
return this->devices[this->cur_dev]->push_data(buf, len);
|
||||
}
|
||||
|
||||
void IdeChannel::assert_dmareq(uint64_t delay) {
|
||||
TimerManager::get_instance()->add_oneshot_timer(delay, [this]() {
|
||||
//LOG_F(INFO, "%s: DMAREQ asserted", this->name.c_str());
|
||||
this->channel_obj->xfer_retry();
|
||||
});
|
||||
}
|
||||
|
||||
int MacioIdeChannel::device_postinit() {
|
||||
this->int_ctrl = dynamic_cast<InterruptCtrl*>(
|
||||
gMachineObj->get_comp_by_type(HWCompType::INT_CTRL));
|
||||
|
||||
@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#define IDE_CHANNEL_H
|
||||
|
||||
#include <devices/common/ata/atadefs.h>
|
||||
#include <devices/common/dmacore.h>
|
||||
#include <devices/common/hwcomponent.h>
|
||||
#include <devices/common/hwinterrupt.h>
|
||||
|
||||
@@ -33,7 +34,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class IdeChannel : public HWComponent
|
||||
class IdeChannel : public HWComponent, public DmaDevice
|
||||
{
|
||||
public:
|
||||
IdeChannel(const std::string name);
|
||||
@@ -44,6 +45,9 @@ 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);
|
||||
|
||||
int xfer_from(uint8_t *buf, int len) override;
|
||||
int xfer_to(uint8_t *buf, int len) override;
|
||||
|
||||
void assert_pdiag() {
|
||||
this->devices[0]->pdiag_callback();
|
||||
}
|
||||
@@ -60,6 +64,8 @@ public:
|
||||
this->irq_callback(intrq_state);
|
||||
}
|
||||
|
||||
void assert_dmareq(uint64_t delay);
|
||||
|
||||
protected:
|
||||
std::function<void(const uint8_t intrq_state)> irq_callback = nullptr;
|
||||
|
||||
|
||||
@@ -39,9 +39,16 @@ MacIoTwo::MacIoTwo(std::string name, uint16_t dev_id) : MacIoBase(name, dev_id)
|
||||
|
||||
// connect IDE HW
|
||||
this->ide_0 = dynamic_cast<IdeChannel*>(gMachineObj->get_comp_by_name("Ide0"));
|
||||
this->ide_1 = dynamic_cast<IdeChannel*>(gMachineObj->get_comp_by_name("Ide1"));
|
||||
this->ide0_dma = std::unique_ptr<DMAChannel> (new DMAChannel("Ide0-Dma"));
|
||||
this->ide0_dma->register_dma_int(this, this->register_dma_int(IntSrc::DMA_IDE0));
|
||||
this->ide0_dma->connect(this->ide_0);
|
||||
this->ide_0->connect(this->ide0_dma.get());
|
||||
|
||||
this->ide_1 = dynamic_cast<IdeChannel*>(gMachineObj->get_comp_by_name("Ide1"));
|
||||
this->ide1_dma = std::unique_ptr<DMAChannel> (new DMAChannel("Ide1-Dma"));
|
||||
this->ide1_dma->register_dma_int(this, this->register_dma_int(IntSrc::DMA_IDE1));
|
||||
this->ide1_dma->connect(this->ide_1);
|
||||
this->ide_1->connect(this->ide1_dma.get());
|
||||
|
||||
// connect Ethernet HW (Heathrow and Paddington)
|
||||
if (this->device_id != MIO_DEV_ID_OHARE) {
|
||||
|
||||
@@ -135,12 +135,31 @@ uint32_t CdromDrive::mode_sense_ex(bool is_sense_6, uint8_t* cmd_ptr, uint8_t* d
|
||||
resp_ptr[0] = page_code;
|
||||
|
||||
switch (page_code) {
|
||||
case 0x01:
|
||||
case ModePage::READ_ERROR_RECOVERY:
|
||||
resp_ptr[1] = 6; // data size
|
||||
std::memset(&resp_ptr[2], 0, 6);
|
||||
data_ptr[1] += 8; // adjust overall length
|
||||
break;
|
||||
case 0x1A:
|
||||
case ModePage::CDROM_AUDIO:
|
||||
resp_ptr[1] = 16; // page length
|
||||
std::memset(&resp_ptr[2], 0, 16);
|
||||
resp_ptr[2] = (1 << 2); //immediately return status
|
||||
|
||||
WRITE_WORD_BE_A(&resp_ptr[6], 75); // logical block per second of audio playback
|
||||
|
||||
resp_ptr[8] = 0x01; // Left Channel
|
||||
resp_ptr[9] = 0xFF; // Volume (0-255)
|
||||
resp_ptr[10] = 0x02; // Right Channel
|
||||
resp_ptr[11] = 0xFF; // Volume (0-255)
|
||||
|
||||
resp_ptr[12] = 0x04; // Output Port 2
|
||||
resp_ptr[13] = 0x00; // Volume (0-255)
|
||||
resp_ptr[14] = 0x08; // Output Port 3
|
||||
resp_ptr[15] = 0x00; // Volume (0-255)
|
||||
|
||||
data_ptr[1] += 8; // adjust overall length
|
||||
break;
|
||||
case ModePage::POWER_CONDITION:
|
||||
resp_ptr[1] = 10; // page length
|
||||
std::memset(&resp_ptr[2], 0, 10);
|
||||
resp_ptr[3] = 0; //idle and standby off
|
||||
@@ -148,7 +167,7 @@ uint32_t CdromDrive::mode_sense_ex(bool is_sense_6, uint8_t* cmd_ptr, uint8_t* d
|
||||
WRITE_DWORD_BE_A(&resp_ptr[8], 0); // Standby Timer (100ms units)
|
||||
data_ptr[1] += 12; // adjust overall length
|
||||
break;
|
||||
case 0x2A:
|
||||
case ModePage::CDROM_CAPABILITIES:
|
||||
resp_ptr[1] = 18; // page data length
|
||||
std::memset(&resp_ptr[2], 0, 18);
|
||||
resp_ptr[2] = 0x03; // supports reading CD-R and CD-E
|
||||
@@ -160,7 +179,7 @@ uint32_t CdromDrive::mode_sense_ex(bool is_sense_6, uint8_t* cmd_ptr, uint8_t* d
|
||||
WRITE_WORD_BE_A(&resp_ptr[14], 706); // report current speed (4x)
|
||||
data_ptr[1] += 20; // adjust overall length
|
||||
break;
|
||||
case 0x31:
|
||||
case ModePage::VENDOR_PAGE_31:
|
||||
resp_ptr[1] = 14; // page data length
|
||||
std::memset(&resp_ptr[2], 0, 14);
|
||||
resp_ptr[8] = 0x31;
|
||||
|
||||
@@ -44,6 +44,16 @@ typedef struct {
|
||||
uint32_t start_lba;
|
||||
} TrackDescriptor;
|
||||
|
||||
enum ModePage {
|
||||
READ_ERROR_RECOVERY = 1,
|
||||
CDROM_PARAMS = 0xD,
|
||||
CDROM_AUDIO = 0xE,
|
||||
POWER_CONDITION = 0x1A,
|
||||
CDROM_CAPABILITIES = 0x2A,
|
||||
VENDOR_PAGE_31 = 0x31,
|
||||
ALL_PAGES = 0x3F,
|
||||
};
|
||||
|
||||
constexpr auto CDROM_MAX_TRACKS = 100;
|
||||
constexpr auto LEAD_OUT_TRK_NUM = 0xAA;
|
||||
constexpr auto CDR_STD_DATA_SIZE = 2048;
|
||||
|
||||
Reference in New Issue
Block a user