Refactored I/O and MMIO mapping

The mapping is now performed by a separate object which allows I/O devices to be registered to specified I/O and/or MMIO ranges. It also prevents overlapping ranges.

All I/O methods have been standardized to the same convention.
This commit is contained in:
StrikerX3 2018-03-11 13:04:09 -03:00
parent f6d6dfbbfb
commit 131b7f9c80
34 changed files with 442 additions and 524 deletions

View file

@ -27,11 +27,12 @@ void i8254::Reset() {
m_running = false;
}
void i8254::IORead(uint32_t addr, uint32_t *value, uint16_t size) {
bool i8254::IORead(uint32_t port, uint32_t *value, uint8_t size) {
*value = 0;
return true;
}
void i8254::IOWrite(uint32_t addr, uint32_t value, uint16_t size) {
bool i8254::IOWrite(uint32_t port, uint32_t value, uint8_t size) {
// HACK: The Xbox always inits the PIT to the same value:
// Timer 0, Mode 2, 1ms interrupt interval.
// Rather than fully implement the PIC, we just wait for the command to
@ -40,6 +41,7 @@ void i8254::IOWrite(uint32_t addr, uint32_t value, uint16_t size) {
m_running = true;
Thread_Create("[HW] i8254", i8254ThreadFunc, this);
}
return true;
}
void i8254::Run() {

View file

@ -3,6 +3,7 @@
#include <cstdint>
#include "i8259.h"
#include "openxbox/io.h"
namespace openxbox {
@ -11,16 +12,15 @@ namespace openxbox {
#define PORT_PIT_DATA_2 0x42
#define PORT_PIT_COMMAND 0x43
class i8254
{
class i8254 : public IODevice {
public:
i8254(i8259 *pic, float tickRate = 1000.0f);
void Reset();
void Run();
void IORead(uint32_t addr, uint32_t *value, uint16_t size);
void IOWrite(uint32_t addr, uint32_t value, uint16_t size);
bool IORead(uint32_t port, uint32_t *value, uint8_t size) override;
bool IOWrite(uint32_t port, uint32_t value, uint8_t size) override;
private:
i8259 *m_pic;
float m_tickRate;

View file

@ -1,6 +1,7 @@
#include "i8259.h"
#include "openxbox/log.h"
#include "openxbox/io.h"
namespace openxbox {
@ -121,54 +122,56 @@ void i8259::SetIRQ(int pic, int index, bool asserted) {
UpdateIRQ(pic);
}
void i8259::IORead(uint32_t addr, uint32_t *value, uint16_t size) {
switch (addr) {
bool i8259::IORead(uint32_t port, uint32_t *value, uint8_t size) {
switch (port) {
case PORT_PIC_MASTER_COMMAND:
*value = CommandRead(PIC_MASTER);
return;
return true;
case PORT_PIC_SLAVE_COMMAND:
*value = CommandRead(PIC_SLAVE);
return;
return true;
case PORT_PIC_MASTER_DATA:
*value = DataRead(PIC_MASTER);
return;
return true;
case PORT_PIC_SLAVE_DATA:
*value = DataRead(PIC_SLAVE);
return;
return true;
case PORT_PIC_MASTER_ELCR:
*value = m_ELCR[PIC_MASTER];
return;
return true;
case PORT_PIC_SLAVE_ELCR:
*value = m_ELCR[PIC_SLAVE];
return;
return true;
}
log_warning("i8295::IORead: Invalid address 0x%x\n", addr);
log_warning("i8259::IORead: Invalid address 0x%x\n", port);
return false;
}
void i8259::IOWrite(uint32_t addr, uint32_t value, uint16_t size) {
switch (addr) {
bool i8259::IOWrite(uint32_t port, uint32_t value, uint8_t size) {
switch (port) {
case PORT_PIC_MASTER_COMMAND:
CommandWrite(PIC_MASTER, value);
return;
return true;
case PORT_PIC_SLAVE_COMMAND:
CommandWrite(PIC_SLAVE, value);
return;
return true;
case PORT_PIC_MASTER_DATA:
DataWrite(PIC_MASTER, value);
return;
return true;
case PORT_PIC_SLAVE_DATA:
DataWrite(PIC_SLAVE, value);
return;
return true;
case PORT_PIC_MASTER_ELCR:
m_ELCR[PIC_MASTER] = value & m_ELCRMask[PIC_MASTER];
return;
return true;
case PORT_PIC_SLAVE_ELCR:
m_ELCR[PIC_SLAVE] = value & m_ELCRMask[PIC_SLAVE];
return;
return true;
}
log_warning("i8295::IOWrite: Invalid address 0x%x\n", addr);
log_warning("i8259::IOWrite: Invalid address 0x%x\n", port);
return false;
}
uint32_t i8259::CommandRead(int pic) {

View file

@ -16,13 +16,13 @@ namespace openxbox {
#define PIC_MASTER 0
#define PIC_SLAVE 1
class i8259 {
class i8259 : public IODevice {
public:
i8259(Cpu *cpu);
void Reset();
void IORead(uint32_t addr, uint32_t *value, uint16_t size);
void IOWrite(uint32_t addr, uint32_t value, uint16_t size);
bool IORead(uint32_t port, uint32_t *value, uint8_t size) override;
bool IOWrite(uint32_t port, uint32_t value, uint8_t size) override;
void RaiseIRQ(int index);
void LowerIRQ(int index);

View file

@ -85,20 +85,20 @@ void PCIBus::IOWriteConfigData(uint32_t pData, uint8_t size, uint8_t regOffset)
);
}
bool PCIBus::IORead(uint32_t addr, uint32_t* data, unsigned size) {
switch (addr) {
bool PCIBus::IORead(uint32_t port, uint32_t *value, uint8_t size) {
switch (port) {
case PORT_PCI_CONFIG_DATA: // 0xCFC
case PORT_PCI_CONFIG_DATA + 1: // 0xCFD
case PORT_PCI_CONFIG_DATA + 2: // 0xCFE
case PORT_PCI_CONFIG_DATA + 3: // 0xCFF
*data = IOReadConfigData(size, addr - PORT_PCI_CONFIG_DATA);
*value = IOReadConfigData(size, port - PORT_PCI_CONFIG_DATA);
return true;
default:
for (auto it = m_Devices.begin(); it != m_Devices.end(); ++it) {
uint8_t barIndex;
uint32_t baseAddress;
if (it->second->GetIOBar(addr, &barIndex, &baseAddress)) {
*data = it->second->IORead(barIndex, addr - (baseAddress << 2), size);
if (it->second->GetIOBar(port, &barIndex, &baseAddress)) {
it->second->PCIIORead(barIndex, port - (baseAddress << 2), value, size);
return true;
}
}
@ -107,15 +107,15 @@ bool PCIBus::IORead(uint32_t addr, uint32_t* data, unsigned size) {
return false;
}
bool PCIBus::IOWrite(uint32_t addr, uint32_t value, unsigned size) {
switch (addr) {
bool PCIBus::IOWrite(uint32_t port, uint32_t value, uint8_t size) {
switch (port) {
case PORT_PCI_CONFIG_ADDRESS: // 0xCF8
if (size == sizeof(uint32_t)) {
IOWriteConfigAddress(value);
return true;
}
else {
log_warning("PCIBus:IOWrite: Writing %d-bit PCI config address, address 0x%x, value 0x%x\n", size << 3, addr, value);
log_warning("PCIBus:IOWrite: Writing %d-bit PCI config address, address 0x%x, value 0x%x\n", size << 3, port, value);
IOWriteConfigAddress(value);
return true;
}
@ -124,14 +124,14 @@ bool PCIBus::IOWrite(uint32_t addr, uint32_t value, unsigned size) {
case PORT_PCI_CONFIG_DATA + 1: // 0xCFD
case PORT_PCI_CONFIG_DATA + 2: // 0xCFE
case PORT_PCI_CONFIG_DATA + 3: // 0xCFF
IOWriteConfigData(value, size, addr - PORT_PCI_CONFIG_DATA);
IOWriteConfigData(value, size, port - PORT_PCI_CONFIG_DATA);
return true; // TODO : Should IOWriteConfigData() success/failure be returned?
default:
for (auto it = m_Devices.begin(); it != m_Devices.end(); ++it) {
uint8_t barIndex;
uint32_t baseAddress;
if (it->second->GetIOBar(addr, &barIndex, &baseAddress)) {
it->second->IOWrite(barIndex, addr - (baseAddress << 2), value, size);
if (it->second->GetIOBar(port, &barIndex, &baseAddress)) {
it->second->PCIIOWrite(barIndex, port - (baseAddress << 2), value, size);
return true;
}
}
@ -140,12 +140,12 @@ bool PCIBus::IOWrite(uint32_t addr, uint32_t value, unsigned size) {
return false;
}
bool PCIBus::MMIORead(uint32_t addr, uint32_t* data, unsigned size) {
bool PCIBus::MMIORead(uint32_t addr, uint32_t *value, uint8_t size) {
for (auto it = m_Devices.begin(); it != m_Devices.end(); ++it) {
uint8_t barIndex;
uint32_t baseAddress;
if (it->second->GetMMIOBar(addr, &barIndex, &baseAddress)) {
*data = it->second->MMIORead(barIndex, addr - (baseAddress << 4), size);
it->second->PCIMMIORead(barIndex, addr - (baseAddress << 4), value, size);
return true;
}
}
@ -153,13 +153,13 @@ bool PCIBus::MMIORead(uint32_t addr, uint32_t* data, unsigned size) {
return false;
}
bool PCIBus::MMIOWrite(uint32_t addr, uint32_t value, unsigned size) {
bool PCIBus::MMIOWrite(uint32_t addr, uint32_t value, uint8_t size) {
for (auto it = m_Devices.begin(); it != m_Devices.end(); ++it) {
PCIDevice *dev = it->second;
uint8_t barIndex;
uint32_t baseAddress;
if (dev->GetMMIOBar(addr, &barIndex, &baseAddress)) {
dev->MMIOWrite(barIndex, addr - (baseAddress << 4), value, size);
dev->PCIMMIOWrite(barIndex, addr - (baseAddress << 4), value, size);
return true;
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "../pci/pci.h"
#include "openxbox/io.h"
#include <map>
@ -28,15 +29,15 @@ typedef struct {
uint8_t enable : 1;
} PCIConfigAddressRegister;
class PCIBus {
class PCIBus : public IODevice {
public:
void ConnectDevice(uint32_t deviceId, PCIDevice *pDevice);
bool IORead(uint32_t addr, uint32_t* value, unsigned size);
bool IOWrite(uint32_t addr, uint32_t value, unsigned size);
bool IORead(uint32_t port, uint32_t *value, uint8_t size) override;
bool IOWrite(uint32_t port, uint32_t value, uint8_t size) override;
bool MMIORead(uint32_t addr, uint32_t * data, unsigned size);
bool MMIOWrite(uint32_t addr, uint32_t value, unsigned size);
bool MMIORead(uint32_t addr, uint32_t *value, uint8_t size) override;
bool MMIOWrite(uint32_t addr, uint32_t value, uint8_t size) override;
void Reset();
private:

View file

@ -95,65 +95,63 @@ void SMBus::ExecuteTransaction() {
m_Status |= GS_HCYC_STS;
}
uint32_t SMBus::IORead(int barIndex, uint32_t addr, unsigned size) {
void SMBus::PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) {
if (barIndex != 1) {
log_debug("SMBus::IORead: unimplemented access to bar %d: address = 0x%x, size = %d\n", barIndex, addr, size);
return 0;
log_debug("SMBus::PCIIORead: unimplemented access to bar %d: port = 0x%x, size = %d\n", barIndex, port, size);
*value = 0;
return;
}
if (size != 1) {
log_debug("SMBus::IORead: unexpected size %d bar = %d, address = 0x%x\n", size, barIndex, addr);
log_debug("SMBus::PCIIORead: unexpected size %d bar = %d, port = 0x%x\n", size, barIndex, port);
}
uint32_t value;
addr &= 0x3f;
port &= 0x3f;
switch (addr) {
switch (port) {
case SMB_GLOBAL_STATUS:
value = m_Status;
*value = m_Status;
break;
case SMB_GLOBAL_ENABLE:
value = m_Control & 0x1f;
*value = m_Control & 0x1f;
break;
case SMB_HOST_COMMAND:
value = m_Command;
*value = m_Command;
break;
case SMB_HOST_ADDRESS:
value = m_Address;
*value = m_Address;
break;
case SMB_HOST_DATA:
value = m_Data0;
*value = m_Data0;
break;
case SMB_HOST_DATA + 1:
value = m_Data1;
*value = m_Data1;
break;
case SMB_HOST_BLOCK_DATA:
value = m_Data[m_Index++];
*value = m_Data[m_Index++];
if (m_Index > 31) {
m_Index = 0;
}
break;
default:
value = 0;
log_debug("SMBus::PCIIOWrite: Unhandled read! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
*value = 0;
break;
}
return value;
}
void SMBus::IOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
void SMBus::PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) {
if (barIndex != 1) {
log_debug("SMBus::IOWrite: unimplemented access to bar %d: address = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
log_debug("SMBus::PCIIOWrite: unimplemented access to bar %d: port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
return;
}
if (size != 1) {
log_debug("SMBus::IOWrite: unexpected size %d bar = %d, address = 0x%x, value = 0x%x\n", size, barIndex, addr, value);
log_debug("SMBus::PCIIOWrite: unexpected size %d bar = %d, port = 0x%x, value = 0x%x\n", size, barIndex, port, value);
}
addr &= 0x3f;
switch (addr) {
port &= 0x3f;
switch (port) {
case SMB_GLOBAL_STATUS:
// If a new status is being set and interrupts are enabled, trigger an interrupt
if ((m_Control & GE_HCYC_EN) && ((value & GS_CLEAR_STS) & (~(m_Status & GS_CLEAR_STS)))) {
@ -211,16 +209,9 @@ void SMBus::IOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size)
}
break;
default:
log_debug("SMBus::PCIIOWrite: Unhandled write! bar = %d, port = 0x%x, value = 0x%x, size = %d\n", barIndex, port, value, size);
break;
}
}
uint32_t SMBus::MMIORead(int barIndex, uint32_t addr, unsigned size) {
return 0;
}
void SMBus::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
}
}

View file

@ -56,11 +56,8 @@ public:
void Init();
void Reset();
uint32_t IORead(int barIndex, uint32_t addr, unsigned size = sizeof(uint8_t));
void IOWrite(int barIndex, uint32_t addr, uint32_t data, unsigned size = sizeof(uint8_t));
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override;
void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override;
// Misc
void ConnectDevice(uint8_t addr, SMDevice *device);

View file

@ -20,36 +20,4 @@ void AC97Device::Init() {
void AC97Device::Reset() {
}
uint32_t AC97Device::IORead(int barIndex, uint32_t port, unsigned size) {
//log_spew("AC97Device::IORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
// TODO
log_warning("AC97Device::IORead: Unimplemented! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
return 0;
}
void AC97Device::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) {
//log_spew("AC97Device::IOWrite: bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
// TODO
log_warning("AC97Device::IOWrite: Unimplemented! bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
}
uint32_t AC97Device::MMIORead(int barIndex, uint32_t addr, unsigned size) {
//log_spew("AC97Device::MMIORead: bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
// TODO
log_warning("AC97Device::MMIORead: Unimplemented! bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
return 0;
}
void AC97Device::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
//log_spew("AC97Device::MMIOWrite: bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
// TODO
log_warning("AC97Device::MMIOWrite: Unimplemented! bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
}
}

View file

@ -16,10 +16,7 @@ public:
void Init();
void Reset();
uint32_t IORead(int barIndex, uint32_t port, unsigned size);
void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size);
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
// TODO: implement I/O
};
}

View file

@ -21,36 +21,4 @@ void HostBridgeDevice::Init() {
void HostBridgeDevice::Reset() {
}
uint32_t HostBridgeDevice::IORead(int barIndex, uint32_t port, unsigned size) {
//log_spew("HostBridgeDevice::IORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
// TODO
log_warning("HostBridgeDevice::IORead: Unimplemented! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
return 0;
}
void HostBridgeDevice::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) {
//log_spew("HostBridgeDevice::IOWrite: bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
// TODO
log_warning("HostBridgeDevice::IOWrite: Unimplemented! bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
}
uint32_t HostBridgeDevice::MMIORead(int barIndex, uint32_t addr, unsigned size) {
//log_spew("HostBridgeDevice::MMIORead: bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
// TODO
log_warning("HostBridgeDevice::MMIORead: Unimplemented! bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
return 0;
}
void HostBridgeDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
//log_spew("HostBridgeDevice::MMIOWrite: bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
// TODO
log_warning("HostBridgeDevice::MMIOWrite: Unimplemented! bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
}
}

View file

@ -15,11 +15,6 @@ public:
// PCI Device functions
void Init();
void Reset();
uint32_t IORead(int barIndex, uint32_t port, unsigned size);
void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size);
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
};
}

View file

@ -18,36 +18,4 @@ void IDEDevice::Init() {
void IDEDevice::Reset() {
}
uint32_t IDEDevice::IORead(int barIndex, uint32_t port, unsigned size) {
//log_spew("IDEDevice::IORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
// TODO
log_warning("IDEDevice::IORead: Unimplemented! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
return 0;
}
void IDEDevice::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) {
//log_spew("IDEDevice::IOWrite: bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
// TODO
log_warning("IDEDevice::IOWrite: Unimplemented! bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
}
uint32_t IDEDevice::MMIORead(int barIndex, uint32_t addr, unsigned size) {
//log_spew("IDEDevice::MMIORead: bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
// TODO
log_warning("IDEDevice::MMIORead: Unimplemented! bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
return 0;
}
void IDEDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
//log_spew("IDEDevice::MMIOWrite: bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
// TODO
log_warning("IDEDevice::MMIOWrite: Unimplemented! bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
}
}

View file

@ -16,10 +16,7 @@ public:
void Init();
void Reset();
uint32_t IORead(int barIndex, uint32_t port, unsigned size);
void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size);
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
// TODO: implement I/O
};
}

View file

@ -19,11 +19,13 @@ void LPCDevice::Init() {
void LPCDevice::Reset() {
}
uint32_t LPCDevice::IORead(int barIndex, uint32_t port, unsigned size) {
log_spew("LPCDevice::IORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
void LPCDevice::PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) {
log_spew("LPCDevice::PCIIORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
if (barIndex != 0) {
return 0;
log_spew("LPCDevice::PCIIORead: Unhandled BAR access: %d, port = 0x%x, size = %d\n", barIndex, port, size);
*value = 0;
return;
}
// TODO
@ -32,7 +34,8 @@ uint32_t LPCDevice::IORead(int barIndex, uint32_t port, unsigned size) {
if (size == sizeof(uint32_t)) {
// This timer counts at 3375000 Hz
auto t = std::chrono::high_resolution_clock::now();
return static_cast<uint32_t>(t.time_since_epoch().count() * 0.003375000);
*value = static_cast<uint32_t>(t.time_since_epoch().count() * 0.003375000);
return;
}
break;
}
@ -40,37 +43,21 @@ uint32_t LPCDevice::IORead(int barIndex, uint32_t port, unsigned size) {
if (size == sizeof(uint8_t)) {
// field pin from tv encoder?
m_field_pin = (m_field_pin + 1) & 1;
return m_field_pin << 5;
*value = m_field_pin << 5;
return;
}
break;
}
}
log_warning("LPCDevice::IORead: Unimplemented! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
return 0;
log_warning("LPCDevice::PCIIORead: Unimplemented! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
}
void LPCDevice::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) {
//log_spew("LPCDevice::IOWrite: bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
void LPCDevice::PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) {
//log_spew("LPCDevice::PCIIOWrite: bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
// TODO
log_warning("LPCDevice::IOWrite: Unimplemented! bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
}
uint32_t LPCDevice::MMIORead(int barIndex, uint32_t addr, unsigned size) {
//log_spew("LPCDevice::MMIORead: bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
// TODO
log_warning("LPCDevice::MMIORead: Unimplemented! bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
return 0;
}
void LPCDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
//log_spew("LPCDevice::MMIOWrite: bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
// TODO
log_warning("LPCDevice::MMIOWrite: Unimplemented! bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
log_warning("LPCDevice::PCIIOWrite: Unimplemented! bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
}
}

View file

@ -16,10 +16,8 @@ public:
void Init();
void Reset();
uint32_t IORead(int barIndex, uint32_t port, unsigned size);
void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size);
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override;
void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override;
private:
int m_field_pin = 0;

View file

@ -18,36 +18,4 @@ void MCPXRAMDevice::Init() {
void MCPXRAMDevice::Reset() {
}
uint32_t MCPXRAMDevice::IORead(int barIndex, uint32_t port, unsigned size) {
//log_spew("MCPXRAMDevice::IORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
// TODO
log_warning("MCPXRAMDevice::IORead: Unimplemented! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
return 0;
}
void MCPXRAMDevice::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) {
//log_spew("MCPXRAMDevice::IOWrite: bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
// TODO
log_warning("MCPXRAMDevice::IOWrite: Unimplemented! bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
}
uint32_t MCPXRAMDevice::MMIORead(int barIndex, uint32_t addr, unsigned size) {
//log_spew("MCPXRAMDevice::MMIORead: bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
// TODO
log_warning("MCPXRAMDevice::MMIORead: Unimplemented! bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
return 0;
}
void MCPXRAMDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
//log_spew("MCPXRAMDevice::MMIOWrite: bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
// TODO
log_warning("MCPXRAMDevice::MMIOWrite: Unimplemented! bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
}
}

View file

@ -16,11 +16,6 @@ public:
// PCI Device functions
void Init();
void Reset();
uint32_t IORead(int barIndex, uint32_t port, unsigned size);
void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size);
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
private:
MCPXRevision m_revision;
};

View file

@ -18,36 +18,4 @@ void NVAPUDevice::Init() {
void NVAPUDevice::Reset() {
}
uint32_t NVAPUDevice::IORead(int barIndex, uint32_t port, unsigned size) {
//log_spew("NVAPUDevice::IORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
// TODO
log_warning("NVAPUDevice::IORead: Unimplemented! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
return 0;
}
void NVAPUDevice::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) {
//log_spew("NVAPUDevice::IOWrite: bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
// TODO
log_warning("NVAPUDevice::IOWrite: Unimplemented! bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
}
uint32_t NVAPUDevice::MMIORead(int barIndex, uint32_t addr, unsigned size) {
//log_spew("NVAPUDevice::MMIORead: bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
// TODO
log_warning("NVAPUDevice::MMIORead: Unimplemented! bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
return 0;
}
void NVAPUDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
//log_spew("NVAPUDevice::MMIOWrite: bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
// TODO
log_warning("NVAPUDevice::MMIOWrite: Unimplemented! bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
}
}

View file

@ -16,10 +16,7 @@ public:
void Init();
void Reset();
uint32_t IORead(int barIndex, uint32_t port, unsigned size);
void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size);
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
// TODO: implement I/O
};
}

View file

@ -470,31 +470,44 @@ void NVNetDevice::Init() {
void NVNetDevice::Reset() {
}
uint32_t NVNetDevice::IORead(int barIndex, uint32_t port, unsigned size) {
if (barIndex != 1) {
return 0;
}
return 0;
}
void NVNetDevice::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) {
void NVNetDevice::PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) {
//log_spew("NVNetDevice::PCIIORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
if (barIndex != 1) {
log_spew("NVNetDevice::PCIIORead: Unhandled BAR access: %d, port = 0x%x, size = %d\n", barIndex, port, size);
*value = 0;
return;
}
*value = 0;
log_warning("NVNetDevice::PCIIORead: Unimplemented read! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
}
uint32_t NVNetDevice::MMIORead(int barIndex, uint32_t addr, unsigned size) {
if (barIndex != 0) {
return 0;
void NVNetDevice::PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) {
//log_spew("NVNetDevice::PCIIOWrite: bar = %d, port = 0x%x, value = 0x%x, size = %d\n", barIndex, port, value, size);
if (barIndex != 1) {
log_spew("NVNetDevice::PCIIOWrite: Unhandled BAR access: %d, port = 0x%x, value = 0x%x, size = %d\n", barIndex, port, value, size);
return;
}
return EmuNVNet_Read(addr, size * 8); // For now, forward
log_warning("NVNetDevice::PCIIOWrite: Unimplemented write! bar = %d, port = 0x%x, value = 0x%x, size = %d\n", barIndex, port, value, size);
}
void NVNetDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
void NVNetDevice::PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) {
//log_spew("NVNetDevice::PCIMMIORead: bar = %d, address = 0x%x, size = %d\n", barIndex, addr, size);
if (barIndex != 0) {
log_spew("NVNetDevice::PCIMMIORead: Unhandled BAR access: %d, address = 0x%x, size = %d\n", barIndex, addr, size);
*value = 0;
return;
}
*value = EmuNVNet_Read(addr, size * 8); // For now, forward
return;
}
void NVNetDevice::PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) {
//log_spew("NVNetDevice::PCIMMIOWrite: bar = %d, address = 0x%x, value = 0x%x, size = %d\n", barIndex, addr, value, size);
if (barIndex != 0) {
log_spew("NVNetDevice::PCIMMIOWrite: Unhandled BAR access: %d, address = 0x%x, value = 0x%x, size = %d\n", barIndex, addr, value, size);
return;
}

View file

@ -14,10 +14,11 @@ public:
// PCI Device functions
void Init();
void Reset();
uint32_t IORead(int barIndex, uint32_t port, unsigned size);
void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size);
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override;
void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override;
void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) override;
void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override;
};
}

View file

@ -253,4 +253,22 @@ void PCIDevice::WriteConfig(uint32_t reg, uint32_t value, uint8_t size) {
// TODO: handle Message Signalled Interrupts
}
void PCIDevice::PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) {
log_spew("PCIDevice::PCIIORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
*value = 0;
}
void PCIDevice::PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) {
log_spew("PCIDevice::PCIIOWrite: bar = %d, port = 0x%x, value = 0x%x, size = %d\n", barIndex, port, value, size);
}
void PCIDevice::PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) {
log_spew("PCIDevice::PCIMMIORead: bar = %d, address = 0x%x, size = %d\n", barIndex, addr, size);
*value = 0;
}
void PCIDevice::PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) {
log_spew("PCIDevice::PCIMMIOWrite: bar = %d, address = 0x%x, value = 0x%x, size = %d\n", barIndex, addr, value, size);
}
}

View file

@ -3,6 +3,7 @@
#include <cstdint>
#include "pci_regs.h"
#include "openxbox/io.h"
namespace openxbox {
@ -49,20 +50,22 @@ class PCIDevice {
public:
virtual void Init() = 0;
virtual void Reset() = 0;
virtual uint32_t IORead(int barIndex, uint32_t port, unsigned size) = 0;
virtual void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) = 0;
virtual uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size) = 0;
virtual void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) = 0;
virtual void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size);
virtual void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size);
virtual void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size);
virtual void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size);
// PCI Device Implementation
public:
PCIDevice(uint8_t type, uint16_t vendorID, uint16_t deviceID,
uint8_t revisionID, uint8_t classID, uint8_t subclass, uint8_t progIF,
uint16_t subsystemVendorID = 0x00, uint16_t subsystemID = 0x00);
bool GetIOBar(uint32_t port, uint8_t* barIndex, uint32_t *baseAddress);
bool GetMMIOBar(uint32_t addr, uint8_t* barIndex, uint32_t *baseAddress);
bool RegisterBAR(int index, uint32_t size, uint32_t type);
void ReadConfig(uint32_t reg, uint8_t *value, uint8_t size);
virtual void WriteConfig(uint32_t reg, uint32_t value, uint8_t size);
protected:

View file

@ -64,36 +64,4 @@ void PCIBridgeDevice::WriteConfig(uint32_t reg, uint32_t value, uint8_t size) {
}
}
uint32_t PCIBridgeDevice::IORead(int barIndex, uint32_t port, unsigned size) {
//log_spew("PCIBridgeDevice::IORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
// TODO
log_warning("PCIBridgeDevice::IORead: Unimplemented! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
return 0;
}
void PCIBridgeDevice::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) {
//log_spew("PCIBridgeDevice::IOWrite: bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
// TODO
log_warning("PCIBridgeDevice::IOWrite: Unimplemented! bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
}
uint32_t PCIBridgeDevice::MMIORead(int barIndex, uint32_t addr, unsigned size) {
//log_spew("PCIBridgeDevice::MMIORead: bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
// TODO
log_warning("PCIBridgeDevice::MMIORead: Unimplemented! bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
return 0;
}
void PCIBridgeDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
//log_spew("PCIBridgeDevice::MMIOWrite: bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
// TODO
log_warning("PCIBridgeDevice::MMIOWrite: Unimplemented! bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
}
}

View file

@ -16,11 +16,6 @@ public:
virtual void Init() override;
virtual void Reset() override;
virtual uint32_t IORead(int barIndex, uint32_t port, unsigned size) override;
virtual void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) override;
virtual uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size) override;
virtual void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) override;
void WriteConfig(uint32_t reg, uint32_t value, uint8_t size) override;
};

View file

@ -18,36 +18,4 @@ void USBPCIDevice::Init() {
void USBPCIDevice::Reset() {
}
uint32_t USBPCIDevice::IORead(int barIndex, uint32_t port, unsigned size) {
//log_spew("USBPCIDevice::IORead: bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
// TODO
log_warning("USBPCIDevice::IORead: Unimplemented! bar = %d, port = 0x%x, size = %d\n", barIndex, port, size);
return 0;
}
void USBPCIDevice::IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size) {
//log_spew("USBPCIDevice::IOWrite: bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
// TODO
log_warning("USBPCIDevice::IOWrite: Unimplemented! bar = %d, port = 0x%x, size = %d, value = 0x%x\n", barIndex, port, size, value);
}
uint32_t USBPCIDevice::MMIORead(int barIndex, uint32_t addr, unsigned size) {
//log_spew("USBPCIDevice::MMIORead: bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
// TODO
log_warning("USBPCIDevice::MMIORead: Unimplemented! bar = %d, addr = 0x%x, size = %d\n", barIndex, addr, size);
return 0;
}
void USBPCIDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size) {
//log_spew("USBPCIDevice::MMIOWrite: bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
// TODO
log_warning("USBPCIDevice::MMIOWrite: Unimplemented! bar = %d, addr = 0x%x, size = %d, value = 0x%x\n", barIndex, addr, size, value);
}
}

View file

@ -16,10 +16,7 @@ public:
void Init();
void Reset();
uint32_t IORead(int barIndex, uint32_t port, unsigned size);
void IOWrite(int barIndex, uint32_t port, uint32_t value, unsigned size);
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
// TODO: implement I/O
};
}

View file

@ -143,7 +143,7 @@ int Xbox::Initialize(OpenXBOXSettings *settings)
log_fatal("CPU instantiation failed\n");
return -1;
}
m_cpu->Initialize(this);
m_cpu->Initialize(&m_ioMapper);
// Allow CPU to update memory map based on device allocation, etc
m_cpu->MemMap(m_memRegion);
@ -223,6 +223,19 @@ int Xbox::Initialize(OpenXBOXSettings *settings)
m_PCIBus->ConnectDevice(PCI_DEVID(0, PCI_DEVFN(30, 0)), m_AGPBridge);
m_PCIBus->ConnectDevice(PCI_DEVID(1, PCI_DEVFN(0, 0)), m_NV2A);
// Map I/O ports and MMIO addresses
m_ioMapper.MapIODevice(PORT_PIC_MASTER_COMMAND, 2, m_i8259);
m_ioMapper.MapIODevice(PORT_PIC_SLAVE_COMMAND, 2, m_i8259);
m_ioMapper.MapIODevice(PORT_PIC_MASTER_ELCR, 2, m_i8259);
m_ioMapper.MapIODevice(PORT_PIT_DATA_0, 4, m_i8254);
m_ioMapper.MapIODevice(PORT_PCI_CONFIG_ADDRESS, 1, m_PCIBus);
m_ioMapper.MapIODevice(PORT_PCI_CONFIG_DATA, 4, m_PCIBus);
// Add the PCI bus as a dynamic I/O mapper
m_ioMapper.AddDevice(m_PCIBus);
// TODO: Handle other SMBUS Addresses, like PIC_ADDRESS, XCALIBUR_ADDRESS
// Resources:
// http://pablot.com/misc/fancontroller.cpp
@ -344,109 +357,6 @@ void Xbox::Stop() {
m_should_run = false;
}
void Xbox::IORead(uint32_t addr, uint32_t *value, uint16_t size) {
log_spew("Xbox::IORead address = 0x%x, size = %d\n", addr, size);
// TODO: proper I/O port mapping
switch (addr) {
case PORT_PIC_MASTER_COMMAND:
case PORT_PIC_MASTER_DATA:
case PORT_PIC_SLAVE_COMMAND:
case PORT_PIC_SLAVE_DATA:
case PORT_PIC_MASTER_ELCR:
case PORT_PIC_SLAVE_ELCR:
m_i8259->IORead(addr, value, size);
break;
case PORT_PIT_DATA_0:
case PORT_PIT_DATA_1:
case PORT_PIT_DATA_2:
case PORT_PIT_COMMAND: {
m_i8254->IORead(addr, value, size);
return;
}
default:
// Pass the IO Read to the PCI Bus.
// This will handle devices with BARs set to IO addresses
if (m_PCIBus->IORead(addr, value, size)) {
return;
}
break;
}
log_warning("Unhandled I/O! address = 0x%x, size = %d, read\n", addr, size);
*value = 0;
}
void Xbox::IOWrite(uint32_t addr, uint32_t value, uint16_t size) {
log_spew("Xbox::IOWrite address = 0x%x, size = %d, value = 0x%x\n", addr, size, value);
// TODO: proper I/O port mapping
switch (addr) {
case PORT_PIC_MASTER_COMMAND:
case PORT_PIC_MASTER_DATA:
case PORT_PIC_MASTER_ELCR:
case PORT_PIC_SLAVE_COMMAND:
case PORT_PIC_SLAVE_DATA:
case PORT_PIC_SLAVE_ELCR:
m_i8259->IOWrite(addr, value, size);
return;
case PORT_PIT_DATA_0:
case PORT_PIT_DATA_1:
case PORT_PIT_DATA_2:
case PORT_PIT_COMMAND:
m_i8254->IOWrite(addr, value, size);
return;
default:
// Pass the IO Write to the PCI Bus.
// This will handle devices with BARs set to IO addresses
if (m_PCIBus->IOWrite(addr, value, size)) {
return;
}
break;
}
log_warning("Unhandled I/O! address = 0x%x, size = %d, write 0x%x\n", addr, size, value);
}
void Xbox::MMIORead(uint32_t addr, uint32_t *value, uint8_t size) {
log_spew("Xbox::MMIORead address = 0x%x, size = %d\n", addr, size);
if ((addr & (size - 1)) != 0) {
log_warning("Unaligned MMIO read! address = 0x%x, size = %d\n", addr, size);
return;
}
// Pass the read to the PCI Bus.
// This will handle devices with BARs set to MMIO addresses
if (m_PCIBus->MMIORead(addr, value, size)) {
return;
}
log_warning("Unhandled MMIO! address = 0x%x, size = %d, read\n", addr, size);
*value = 0;
}
void Xbox::MMIOWrite(uint32_t addr, uint32_t value, uint8_t size) {
log_spew("Xbox::MMIOWrite address = 0x%x, size = %d, value = 0x%x\n", addr, size, value);
if ((addr & (size - 1)) != 0) {
log_warning("Unaligned MMIO write! address = 0x%x, size = %d, value = 0x%x\n", addr, size, value);
return;
}
// Pass the write to the PCI Bus.
// This will handle devices with BARs set to MMIO addresses
if (m_PCIBus->MMIOWrite(addr, value, size)) {
return;
}
log_warning("Unhandled MMIO! address = 0x%x, size = %d, write 0x%x\n", addr, size, value);
}
void Xbox::Cleanup() {
if (LOG_LEVEL >= LOG_LEVEL_DEBUG) {
log_debug("CPU state at the end of execution:\n");

View file

@ -52,7 +52,7 @@ namespace openxbox {
* This class is the top-level class, will perform initialization and high-level
* management of the overall emulation flow.
*/
class Xbox : Emulator, IOMapper {
class Xbox : Emulator {
protected:
// ----- Modules ----------------------------------------------------------
IOpenXBOXCPUModule * m_cpuModule;
@ -62,6 +62,7 @@ protected:
char *m_ram;
char *m_rom;
MemoryRegion *m_memRegion;
IOMapper m_ioMapper;
i8254 *m_i8254;
i8259 *m_i8259;
@ -105,13 +106,6 @@ public:
int Run();
int RunCpu();
void Stop();
// IOMapper implementation
void IORead(uint32_t addr, uint32_t *value, uint16_t size);
void IOWrite(uint32_t addr, uint32_t value, uint16_t size);
void MMIORead(uint32_t addr, uint32_t *value, uint8_t size);
void MMIOWrite(uint32_t addr, uint32_t value, uint8_t size);
};
}

View file

@ -6,7 +6,7 @@
#include "openxbox/memregion.h"
#include "openxbox/gdt.h"
#include "openxbox/idt.h"
#include "openxbox/iomapper.h"
#include "openxbox/io.h"
namespace openxbox {

View file

@ -0,0 +1,188 @@
#include "io.h"
#include "openxbox/log.h"
namespace openxbox {
// ----- Default I/O device implementation ------------------------------------
bool IODevice::IORead(uint32_t addr, uint32_t *value, uint8_t size) {
*value = 0;
return false;
}
bool IODevice::IOWrite(uint32_t addr, uint32_t value, uint8_t size) {
return false;
}
bool IODevice::MMIORead(uint32_t addr, uint32_t *value, uint8_t size) {
*value = 0;
return false;
}
bool IODevice::MMIOWrite(uint32_t addr, uint32_t value, uint8_t size) {
return false;
}
// ----- I/O mapper -----------------------------------------------------------
bool IOMapper::MapIODevice(uint32_t basePort, uint32_t numPorts, IODevice *device) {
return MapDevice(m_mappedIODevices, basePort, numPorts, device);
}
bool IOMapper::MapMMIODevice(uint32_t baseAddress, uint32_t numAddresses, IODevice *device) {
return MapDevice(m_mappedMMIODevices, baseAddress, numAddresses, device);
}
bool IOMapper::MapDevice(std::map<uint32_t, MappedDevice>& iomap, uint32_t base, uint32_t size, IODevice *device) {
uint32_t last = base + size - 1;
// Ensure there are no overlapping ranges
auto pu = iomap.upper_bound(base);
if (pu != iomap.end()) {
if ((base >= pu->first && base <= pu->second.lastAddress) || (last >= pu->first && last <= pu->second.lastAddress)) {
log_warning("IOMapper::MapDevice: Attempted to map a device to %s range 0x%x..0x%x, but another device is already mapped to range 0x%x..0x%x\n",
(&iomap == &m_mappedIODevices) ? "I/O" : "MMIO",
base, last,
pu->first, pu->second.lastAddress);
return false;
}
}
auto pl = iomap.lower_bound(last);
if (pl != iomap.begin()) pl--;
if (pl != iomap.begin()) {
if ((base >= pl->first && base <= pl->second.lastAddress) || (last >= pl->first && last <= pl->second.lastAddress)) {
log_warning("IOMapper::MapDevice: Attempted to map a device to %s range 0x%x..0x%x, but another device is already mapped to range 0x%x..0x%x\n",
(&iomap == &m_mappedIODevices) ? "I/O" : "MMIO",
base, last,
pu->first, pu->second.lastAddress);
return false;
}
}
// Map the device to the specified I/O or MMIO range
iomap[base] = MappedDevice{ base, last, device };
return true;
}
bool IOMapper::AddDevice(IODevice *device) {
return m_dynamicDevices.emplace(device).second;
}
bool IOMapper::LookupDevice(std::map<uint32_t, MappedDevice>& iomap, uint32_t addr, IODevice **device) {
auto p = iomap.upper_bound(addr);
// p->first > addr
if (p == iomap.begin()) {
return false;
}
// p->first <= addr
--p;
if (addr >= p->first && addr <= p->second.lastAddress) {
*device = p->second.device;
return true;
}
return false;
}
bool IOMapper::IORead(uint32_t addr, uint32_t *value, uint8_t size) {
log_spew("IOMapper::IORead: address = 0x%x, size = %d\n", addr, size);
// Try looking up a device mapped to the specified port first
IODevice *dev;
if (LookupDevice(m_mappedIODevices, addr, &dev)) {
return dev->IORead(addr, value, size);
}
// Otherwise search for one of the dynamically mapped devices
for (auto it = m_dynamicDevices.begin(); it != m_dynamicDevices.end(); it++) {
auto dev = *it;
if (dev->IORead(addr, value, size)) {
return true;
}
}
log_warning("IOMapper::IORead: Unhandled I/O! address = 0x%x, size = %d, read\n", addr, size);
*value = 0;
return false;
}
bool IOMapper::IOWrite(uint32_t addr, uint32_t value, uint8_t size) {
log_spew("IOMapper::IOWrite: address = 0x%x, size = %d, value = 0x%x\n", addr, size, value);
// Try looking up a device mapped to the specified port first
IODevice *dev;
if (LookupDevice(m_mappedIODevices, addr, &dev)) {
return dev->IOWrite(addr, value, size);
}
// Otherwise search for one of the dynamically mapped devices
for (auto it = m_dynamicDevices.begin(); it != m_dynamicDevices.end(); it++) {
auto dev = *it;
if (dev->IOWrite(addr, value, size)) {
return true;
}
}
log_warning("IOMapper::IOWrite: Unhandled I/O! address = 0x%x, size = %d, write 0x%x\n", addr, size, value);
return false;
}
bool IOMapper::MMIORead(uint32_t addr, uint32_t *value, uint8_t size) {
log_spew("IOMapper::MMIORead: address = 0x%x, size = %d\n", addr, size);
if ((addr & (size - 1)) != 0) {
log_warning("IOMapper::MMIORead: Unaligned MMIO read! address = 0x%x, size = %d\n", addr, size);
return false;
}
// Try looking up a device mapped to the specified port first
IODevice *dev;
if (LookupDevice(m_mappedMMIODevices, addr, &dev)) {
return dev->MMIORead(addr, value, size);
}
// Otherwise search for one of the dynamically mapped devices
for (auto it = m_dynamicDevices.begin(); it != m_dynamicDevices.end(); it++) {
auto dev = *it;
if (dev->MMIORead(addr, value, size)) {
return true;
}
}
log_warning("IOMapper::MMIORead: Unhandled MMIO! address = 0x%x, size = %d, read\n", addr, size);
*value = 0;
return false;
}
bool IOMapper::MMIOWrite(uint32_t addr, uint32_t value, uint8_t size) {
log_spew("IOMapper::MMIOWrite: address = 0x%x, size = %d, value = 0x%x\n", addr, size, value);
if ((addr & (size - 1)) != 0) {
log_warning("IOMapper::MMIOWrite: Unaligned MMIO write! address = 0x%x, size = %d, value = 0x%x\n", addr, size, value);
return false;
}
// Try looking up a device mapped to the specified port first
IODevice *dev;
if (LookupDevice(m_mappedMMIODevices, addr, &dev)) {
return dev->MMIOWrite(addr, value, size);
}
// Otherwise search for one of the dynamically mapped devices
for (auto it = m_dynamicDevices.begin(); it != m_dynamicDevices.end(); it++) {
auto dev = *it;
if (dev->MMIOWrite(addr, value, size)) {
return true;
}
}
log_warning("IOMapper::MMIOWrite: Unhandled MMIO! address = 0x%x, size = %d, write 0x%x\n", addr, size, value);
return false;
}
}

View file

@ -0,0 +1,83 @@
#pragma once
#include <cstdint>
#include <map>
#include <set>
namespace openxbox {
/*!
* Abstract base class that represents devices that respond to port-mapped
* and/or memory-mapped I/O.
*
* I/O functions return true if the I/O operation was handled by the device.
*
* The default implementations read the value 0 and don't handle I/O.
*/
class IODevice {
public:
virtual bool IORead(uint32_t port, uint32_t *value, uint8_t size);
virtual bool IOWrite(uint32_t port, uint32_t value, uint8_t size);
virtual bool MMIORead(uint32_t addr, uint32_t *value, uint8_t size);
virtual bool MMIOWrite(uint32_t addr, uint32_t value, uint8_t size);
};
/*!
* A mapped I/O device with specified I/O or MMIO ranges.
*/
struct MappedDevice {
// I/O or MMIO addresses
uint32_t baseAddress;
uint32_t lastAddress;
// The device itself
IODevice *device;
};
/*!
* Maps I/O and MMIO reads and writes to the corresponding devices.
*/
class IOMapper {
public:
/*!
* Maps a device to the specified range of ports.
*/
bool MapIODevice(uint32_t basePort, uint32_t numPorts, IODevice *device);
/*!
* Maps a device to the specified MMIO range.
*/
bool MapMMIODevice(uint32_t baseAddress, uint32_t numAddresses, IODevice *device);
/*!
* Adds a device with dynamic I/O address mapping.
*/
bool AddDevice(IODevice *device);
bool IORead(uint32_t addr, uint32_t *value, uint8_t size);
bool IOWrite(uint32_t addr, uint32_t value, uint8_t size);
bool MMIORead(uint32_t addr, uint32_t *value, uint8_t size);
bool MMIOWrite(uint32_t addr, uint32_t value, uint8_t size);
private:
/*!
* Looks up the I/O device mapped to the specified I/O or MMIO address,
* depending on the map used.
*
* Returns true if found.
*/
bool LookupDevice(std::map<uint32_t, MappedDevice>& iomap, uint32_t addr, IODevice **device);
/*!
* Maps a device to the specified address range.
*/
bool MapDevice(std::map<uint32_t, MappedDevice>& iomap, uint32_t base, uint32_t size, IODevice *device);
std::map<uint32_t, MappedDevice> m_mappedIODevices;
std::map<uint32_t, MappedDevice> m_mappedMMIODevices;
std::set<IODevice *> m_dynamicDevices;
};
}

View file

@ -1,20 +0,0 @@
#pragma once
#include <cstdint>
namespace openxbox {
/*!
* Maps I/O and MMIO reads and writes to the corresponding devices.
*/
class IOMapper {
public:
virtual void IORead(uint32_t addr, uint32_t *value, uint16_t size) = 0;
virtual void IOWrite(uint32_t addr, uint32_t value, uint16_t size) = 0;
virtual void MMIORead(uint32_t addr, uint32_t *value, uint8_t size) = 0;
virtual void MMIOWrite(uint32_t addr, uint32_t value, uint8_t size) = 0;
};
}