Flesh out SuperIO and make devices map themselves

Only enable SuperIO on Debug Kits
This commit is contained in:
StrikerX3 2018-03-11 14:04:56 -03:00
parent bc09528869
commit 550a870680
12 changed files with 204 additions and 25 deletions

View file

@ -11,6 +11,12 @@ CMOS::CMOS() {
void CMOS::Reset() {
}
bool CMOS::MapIO(IOMapper *mapper) {
if (!mapper->MapIODevice(PORT_CMOS_BASE, PORT_CMOS_COUNT, this)) return false;
return true;
}
bool CMOS::IORead(uint32_t port, uint32_t *value, uint8_t size) {
log_warning("CMOS::IORead: Unhandled read! port = 0x%x, size = %d\n", port, size);
return false;

View file

@ -18,6 +18,8 @@ public:
CMOS();
void Reset();
bool MapIO(IOMapper *mapper);
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:

View file

@ -27,6 +27,12 @@ void i8254::Reset() {
m_running = false;
}
bool i8254::MapIO(IOMapper *mapper) {
if (!mapper->MapIODevice(PORT_PIT_BASE, PORT_PIT_COUNT, this)) return false;
return true;
}
bool i8254::IORead(uint32_t port, uint32_t *value, uint8_t size) {
*value = 0;
return true;

View file

@ -20,10 +20,12 @@ public:
i8254(i8259 *pic, float tickRate = 1000.0f);
void Reset();
void Run();
bool MapIO(IOMapper *mapper);
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 Run();
private:
i8259 *m_pic;
float m_tickRate;

View file

@ -71,6 +71,14 @@ void i8259::Reset(int pic) {
UpdateIRQ(pic);
}
bool i8259::MapIO(IOMapper *mapper) {
if (!mapper->MapIODevice(PORT_PIC_MASTER_BASE, PORT_PIC_COUNT, this)) return false;
if (!mapper->MapIODevice(PORT_PIC_SLAVE_BASE, PORT_PIC_COUNT, this)) return false;
if (!mapper->MapIODevice(PORT_PIC_ELCR_BASE, PORT_PIC_COUNT, this)) return false;
return true;
}
void i8259::RaiseIRQ(int index) {
if (index <= 7) {
SetIRQ(PIC_MASTER, index, true);

View file

@ -26,6 +26,8 @@ public:
i8259(Cpu *cpu);
void Reset();
bool MapIO(IOMapper *mapper);
bool IORead(uint32_t port, uint32_t *value, uint8_t size) override;
bool IOWrite(uint32_t port, uint32_t value, uint8_t size) override;

View file

@ -6,17 +6,119 @@
namespace openxbox {
SuperIO::SuperIO() {
memset(m_configRegs, 0, sizeof(m_configRegs));
memset(m_deviceRegs, 0, sizeof(m_deviceRegs));
m_configRegs[CONFIG_PORT_LOW] = (uint8_t)(PORT_SUPERIO_BASE & 0xFF);
m_configRegs[CONFIG_PORT_HIGH] = (uint8_t)(PORT_SUPERIO_BASE >> 8);
m_inConfigMode = false;
m_selectedReg = 0;
// TODO: init serial cores
}
void SuperIO::Reset() {
}
bool SuperIO::MapIO(IOMapper *mapper) {
if (!mapper->MapIODevice(PORT_SUPERIO_BASE, PORT_SUPERIO_COUNT, this)) return false;
if (!mapper->MapIODevice(PORT_SUPERIO_UART_BASE_1, PORT_SUPERIO_UART_COUNT_1, this)) return false;
if (!mapper->MapIODevice(PORT_SUPERIO_UART_BASE_2, PORT_SUPERIO_UART_COUNT_2, this)) return false;
return true;
}
void SuperIO::UpdateDevices() {
// TODO: update serial cores
}
bool SuperIO::IORead(uint32_t port, uint32_t *value, uint8_t size) {
log_spew("SuperIO::IORead: port = 0x%x, size = %d\n", port, size);
switch (port) {
case PORT_SUPERIO_CONFIG:
*value = 0;
return true;
case PORT_SUPERIO_DATA:
if (m_selectedReg < MAX_CONFIG_REG) {
*value = m_configRegs[m_selectedReg];
}
else {
if (m_configRegs[CONFIG_DEVICE_NUMBER] >= MAX_DEVICE) {
log_warning("SuperIO::IORead: Device number out of range! %d >= %d\n", m_configRegs[CONFIG_DEVICE_NUMBER], MAX_DEVICE);
*value = 0;
}
else {
uint8_t* dev = m_deviceRegs[m_configRegs[CONFIG_DEVICE_NUMBER]];
*value = dev[m_selectedReg];
}
}
return true;
}
if (port >= PORT_SUPERIO_UART_BASE_1 && port <= PORT_SUPERIO_UART_END_1) {
// TODO: redirect to serial device 1
}
if (port >= PORT_SUPERIO_UART_BASE_2 && port <= PORT_SUPERIO_UART_END_2) {
// TODO: redirect to serial device 2
}
log_warning("SuperIO::IORead: Unhandled read! port = 0x%x, size = %d\n", port, size);
return false;
}
bool SuperIO::IOWrite(uint32_t port, uint32_t value, uint8_t size) {
log_spew("SuperIO::IOWrite: port = 0x%x, size = %d, value = 0x%x\n", port, size, value);
switch (port) {
case PORT_SUPERIO_CONFIG:
if (value == ENTER_CONFIG_KEY) {
#ifdef _DEBUG
if (m_inConfigMode) {
log_warning("SuperIO::IOWrite: Attempted to reenter configuration mode\n");
}
log_debug("SuperIO::IOWrite: Entering configuration mode\n");
#endif
m_inConfigMode = true;
}
else if (value == EXIT_CONFIG_KEY) {
#ifdef _DEBUG
if (!m_inConfigMode) {
log_warning("SuperIO::IOWrite: Attempted to reexit configuration mode\n");
}
log_debug("SuperIO::IOWrite: Exiting configuration mode\n");
#endif
m_inConfigMode = false;
UpdateDevices();
}
else {
m_selectedReg = value;
}
return true;
case PORT_SUPERIO_DATA:
if (m_selectedReg < MAX_CONFIG_REG) {
// Global configuration register
m_configRegs[m_selectedReg] = value;
}
else {
// Device register
#ifdef _DEBUG
if (m_configRegs[CONFIG_DEVICE_NUMBER] >= MAX_DEVICE) {
log_warning("SuperIO::IOWrite: Device number out of range! %d >= %d\n", m_configRegs[CONFIG_DEVICE_NUMBER], MAX_DEVICE);
}
else
#endif
{
uint8_t* dev = m_deviceRegs[m_configRegs[CONFIG_DEVICE_NUMBER]];
dev[m_selectedReg] = value;
}
}
return true;
}
log_warning("SuperIO::IOWrite: Unhandled write! port = 0x%x, size = %d, value = 0x%x\n", port, size, value);
return false;
}

View file

@ -6,23 +6,65 @@
namespace openxbox {
#define PORT_SUPERIO_CONFIG 0x2E
#define PORT_SUPERIO_DATA 0x2F
#define PORT_SUPERIO_CONFIG 0x2E
#define PORT_SUPERIO_DATA 0x2F
#define PORT_SUPERIO_BASE PORT_SUPERIO_CONFIG
#define PORT_SUPERIO_COUNT 2
#define PORT_SUPERIO_BASE PORT_SUPERIO_CONFIG
#define PORT_SUPERIO_COUNT 2
#define PORT_SUPERIO_UART_BASE_1 0x3F8
#define PORT_SUPERIO_UART_END_1 0x3FF
#define PORT_SUPERIO_UART_COUNT_1 (PORT_SUPERIO_UART_END_1 - PORT_SUPERIO_UART_BASE_1 + 1)
#define PORT_SUPERIO_UART_BASE_2 0x2F8
#define PORT_SUPERIO_UART_END_2 0x2FF
#define PORT_SUPERIO_UART_COUNT_2 (PORT_SUPERIO_UART_END_2 - PORT_SUPERIO_UART_BASE_2 + 1)
#define DEVICE_FDD 0x0
#define DEVICE_PARALLEL_PORT 0x3
#define DEVICE_SERIAL_PORT_1 0x4
#define DEVICE_SERIAL_PORT_2 0x5
#define DEVICE_KEYBOARD 0x7
#define DEVICE_GAME_PORT 0x9
#define DEVICE_PME 0xA
#define DEVICE_MPU_401 0xB
#define MAX_DEVICE 0xC
#define ENTER_CONFIG_KEY 0x55
#define EXIT_CONFIG_KEY 0xAA
#define MAX_CONFIG_REG 0x30
#define MAX_DEVICE_REGS 0xFF
#define CONFIG_DEVICE_NUMBER 0x07
#define CONFIG_PORT_LOW 0x26
#define CONFIG_PORT_HIGH 0x27
#define CONFIG_DEVICE_ACTIVATE 0x30
#define CONFIG_DEVICE_BASE_ADDRESS_HIGH 0x60
#define CONFIG_DEVICE_BASE_ADDRESS_LOW 0x61
#define CONFIG_DEVICE_INETRRUPT 0x70
#define PORT_SUPERIO_UART_BASE 0x3F8
#define PORT_SUPERIO_UART_COUNT 8
class SuperIO : public IODevice {
public:
SuperIO();
void Reset();
bool MapIO(IOMapper *mapper);
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:
void UpdateDevices();
bool m_inConfigMode;
uint32_t m_selectedReg;
uint8_t m_configRegs[MAX_CONFIG_REG];
uint8_t m_deviceRegs[MAX_DEVICE][MAX_DEVICE_REGS];
};
}

View file

@ -5,6 +5,14 @@
namespace openxbox {
bool PCIBus::MapIO(IOMapper *mapper) {
if (!mapper->MapIODevice(PORT_PCI_CONFIG_ADDRESS, 1, this)) return false;
if (!mapper->MapIODevice(PORT_PCI_CONFIG_DATA, 4, this)) return false;
if (!mapper->AddDevice(this)) return false;
return true;
}
void PCIBus::ConnectDevice(uint32_t deviceId, PCIDevice *pDevice) {
if (m_Devices.find(deviceId) != m_Devices.end()) {
log_warning("PCIBus: Attempting to connect two devices to the same device address\n");

View file

@ -31,6 +31,8 @@ typedef struct {
class PCIBus : public IODevice {
public:
bool MapIO(IOMapper *mapper);
void ConnectDevice(uint32_t deviceId, PCIDevice *pDevice);
bool IORead(uint32_t port, uint32_t *value, uint8_t size) override;

View file

@ -187,13 +187,17 @@ int Xbox::Initialize(OpenXBOXSettings *settings)
// Create PIT and PIC
m_i8259 = new i8259(m_cpu);
m_i8254 = new i8254(m_i8259, settings->hw_sysclock_tickRate);
m_SuperIO = new SuperIO();
m_CMOS = new CMOS();
if (settings->hw_model == DebugKit) {
m_SuperIO = new SuperIO();
}
m_i8259->Reset();
m_i8254->Reset();
m_SuperIO->Reset();
m_CMOS->Reset();
if (settings->hw_model == DebugKit) {
m_SuperIO->Reset();
}
// Create busses
m_PCIBus = new PCIBus();
@ -254,22 +258,13 @@ int Xbox::Initialize(OpenXBOXSettings *settings)
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_BASE, PORT_PIC_COUNT, m_i8259);
m_ioMapper.MapIODevice(PORT_PIC_SLAVE_BASE, PORT_PIC_COUNT, m_i8259);
m_ioMapper.MapIODevice(PORT_PIC_ELCR_BASE, PORT_PIC_COUNT, m_i8259);
m_ioMapper.MapIODevice(PORT_PIT_BASE, PORT_PIT_COUNT, m_i8254);
m_ioMapper.MapIODevice(PORT_PCI_CONFIG_ADDRESS, 1, m_PCIBus);
m_ioMapper.MapIODevice(PORT_PCI_CONFIG_DATA, 4, m_PCIBus);
m_ioMapper.MapIODevice(PORT_SUPERIO_BASE, PORT_SUPERIO_COUNT, m_SuperIO);
m_ioMapper.MapIODevice(PORT_SUPERIO_UART_BASE, PORT_SUPERIO_UART_COUNT, m_SuperIO);
m_ioMapper.MapIODevice(PORT_CMOS_BASE, PORT_CMOS_COUNT, m_CMOS);
// Add the PCI bus as a dynamic I/O mapper
m_ioMapper.AddDevice(m_PCIBus);
m_i8259->MapIO(&m_ioMapper);
m_i8254->MapIO(&m_ioMapper);
m_CMOS->MapIO(&m_ioMapper);
m_PCIBus->MapIO(&m_ioMapper);
if (settings->hw_model == DebugKit) {
m_SuperIO->MapIO(&m_ioMapper);
}
// TODO: Handle other SMBUS Addresses, like PIC_ADDRESS, XCALIBUR_ADDRESS
// Resources:

View file

@ -6,6 +6,8 @@
namespace openxbox {
class IOMapper;
/*!
* Abstract base class that represents devices that respond to port-mapped
* and/or memory-mapped I/O.
@ -16,6 +18,8 @@ namespace openxbox {
*/
class IODevice {
public:
virtual bool MapIO(IOMapper *mapper) = 0;
virtual bool IORead(uint32_t port, uint32_t *value, uint8_t size);
virtual bool IOWrite(uint32_t port, uint32_t value, uint8_t size);