diff --git a/devices/common/pci/bandit.cpp b/devices/common/pci/bandit.cpp index 4358c5e..64c2b60 100644 --- a/devices/common/pci/bandit.cpp +++ b/devices/common/pci/bandit.cpp @@ -41,9 +41,11 @@ const int MultiplyDeBruijnBitPosition2[] = #define WHAT_BIT_SET(val) (MultiplyDeBruijnBitPosition2[(uint32_t)(val * 0x077CB531U) >> 27]) Bandit::Bandit(int bridge_num, std::string name, int dev_id, int rev) - : PCIHost(), PCIDevice(name) + : BanditHost() { - supports_types(HWCompType::PCI_HOST | HWCompType::PCI_DEV); + this->name = name; + + supports_types(HWCompType::PCI_HOST); this->base_addr = 0xF0000000 + ((bridge_num & 3) << 25); @@ -58,6 +60,15 @@ Bandit::Bandit(int bridge_num, std::string name, int dev_id, int rev) // base_addr + 0x1000000 --> pass-through memory space (not included below) mem_ctrl->add_mmio_region(base_addr, 0x01000000, this); + std::string banditpcitname = "Bandit1PCI"; + attach_pci_device(banditpcitname, 1); +} + +BanditPCI::BanditPCI(int bridge_num, std::string name) + : PCIDevice(name) +{ + supports_types(HWCompType::PCI_DEV); + // prepare the PCI config header this->vendor_id = PCI_VENDOR_APPLE; this->device_id = 0x0001; @@ -80,195 +91,149 @@ Bandit::Bandit(int bridge_num, std::string name, int dev_id, int rev) this->rd_hold_off_cnt = 8; } -uint32_t Bandit::pci_cfg_read(uint32_t reg_offs, uint32_t size) +uint32_t BanditPCI::pci_cfg_read(uint32_t reg_offs, AccessDetails &details) { if (reg_offs < 64) { - return PCIDevice::pci_cfg_read(reg_offs, size); + return PCIDevice::pci_cfg_read(reg_offs, details); } switch (reg_offs) { case BANDIT_ADDR_MASK: - return BYTESWAP_32(this->addr_mask); + return this->addr_mask; case BANDIT_MODE_SELECT: - return BYTESWAP_32(this->mode_ctrl); + return this->mode_ctrl; case BANDIT_ARBUS_RD_HOLD_OFF: - return BYTESWAP_32(this->rd_hold_off_cnt); - default: - LOG_F(WARNING, "%s: reading from unimplemented config register at 0x%X", - this->pci_name.c_str(), reg_offs); + return this->rd_hold_off_cnt; } - + LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER(); return 0; } -void Bandit::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) +void BanditPCI::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details) { if (reg_offs < 64) { - PCIDevice::pci_cfg_write(reg_offs, value, size); + PCIDevice::pci_cfg_write(reg_offs, value, details); return; } - if (size == 4) { - value = BYTESWAP_32(value); - } else { - LOG_F(WARNING, "%s: non-DWORD writes to the control registers not supported", - this->pci_name.c_str()); - } - switch (reg_offs) { case BANDIT_ADDR_MASK: this->addr_mask = value; this->verbose_address_space(); - break; + return; case BANDIT_MODE_SELECT: this->mode_ctrl = value; - break; + return; case BANDIT_ARBUS_RD_HOLD_OFF: - this->rd_hold_off_cnt = value & 0x1F; - break; - default: - LOG_F(WARNING, "%s: writing to unimplemented config register at 0x%X", - this->pci_name.c_str(), reg_offs); + this->rd_hold_off_cnt = value & 0x1F; + return; + } + LOG_WRITE_UNIMPLEMENTED_CONFIG_REGISTER(); +} + +void BanditHost::cfg_setup(uint32_t offset, int size, int &bus_num, int &dev_num, int &fun_num, uint8_t ®_offs, AccessDetails &details, PCIDevice *&device) +{ + device = NULL; + details.size = size; + details.offset = offset & 3; + fun_num = (this->config_addr >> 8) & 7; + reg_offs = this->config_addr & 0xFCU; + if (this->config_addr & BANDIT_CAR_TYPE) { // type 1 configuration command + details.flags = PCI_CONFIG_TYPE_1; + bus_num = (this->config_addr >> 16) & 255; + dev_num = (this->config_addr >> 11) & 31; + device = pci_find_device(bus_num, dev_num, fun_num); + return; + } + details.flags = PCI_CONFIG_TYPE_0; + bus_num = 0; // bus number is meaningless for type 0 configuration command; a type 1 configuration command cannot reach devices attached directly to the host + uint32_t idsel = this->config_addr & 0xFFFFF800U; + if (!SINGLE_BIT_SET(idsel)) { + for (dev_num = -1, idsel = this->config_addr; idsel; idsel >>= 1, dev_num++) {} + LOG_F(ERROR, "%s: config_addr 0x%08x does not contain valid IDSEL", this->name.c_str(), (uint32_t)this->config_addr); + return; + } + dev_num = WHAT_BIT_SET(idsel); + if (this->dev_map.count(idsel >> 11)) { + device = this->dev_map[idsel >> 11]; } } -uint32_t Bandit::read(uint32_t rgn_start, uint32_t offset, int size) +uint32_t BanditHost::read(uint32_t rgn_start, uint32_t offset, int size) { - int bus_num, dev_num, fun_num; - uint8_t reg_offs; - uint32_t result, idsel; + switch (offset >> 22) { - if (offset & BANDIT_CONFIG_SPACE) { - if (offset & 0x00400000) { - fun_num = (this->config_addr >> 8) & 7; - reg_offs = this->config_addr & 0xFCU; - - // access to the CONFIG_DATA pseudo-register causes a Config Cycle - if (this->config_addr & BANDIT_CAR_TYPE) { - bus_num = (this->config_addr >> 16) & 255; - dev_num = (this->config_addr >> 11) & 31; - LOG_F( - WARNING, "%s: read config cycle type 1 not supported yet %02x:%02x.%x @%02x.%c", - this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size - ); - return 0xFFFFFFFFUL; // PCI spec §6.1 + case 3: // 0xC00000 // CONFIG_DATA + int bus_num, dev_num, fun_num; + uint8_t reg_offs; + AccessDetails details; + PCIDevice *device; + cfg_setup(offset, size, bus_num, dev_num, fun_num, reg_offs, details, device); + details.flags |= PCI_CONFIG_READ; + if (device) { + return pci_cfg_rev_read(device->pci_cfg_read(reg_offs, details), details); } + LOG_READ_NON_EXISTENT_PCI_DEVICE(); + return 0xFFFFFFFFUL; // PCI spec §6.1 - idsel = (this->config_addr >> 11) & 0x1FFFFFU; + case 2: // 0x800000 // CONFIG_ADDR + return this->config_addr; - if (!SINGLE_BIT_SET(idsel)) { - LOG_F( - ERROR, "%s: read invalid IDSEL=0x%X config:0x%X ??:??.%x? @%02x?.%c", - this->name.c_str(), idsel, this->config_addr, - fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size - ); - return 0xFFFFFFFFUL; // PCI spec §6.1 - } - - if (idsel == BANDIT_ID_SEL) { // access to myself - result = this->pci_cfg_read(reg_offs, size); - } else { - if (this->dev_map.count(idsel)) { - result = this->dev_map[idsel]->pci_cfg_read(reg_offs, size); - } else { - dev_num = WHAT_BIT_SET(idsel) + 11; - LOG_F( - ERROR, "%s err: read attempt from non-existing PCI device ??:%02x.%x @%02x.%c", - this->name.c_str(), dev_num, fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size - ); - return 0xFFFFFFFFUL; // PCI spec §6.1 + default: // 0x000000 // I/O space + { + uint32_t result; + // broadcast I/O request to devices that support I/O space + // until a device returns true that means "request accepted" + for (auto& dev : this->io_space_devs) { + if (dev->pci_io_read(offset, size, &result)) { + return result; } } - } else { - result = this->config_addr; + LOG_F(ERROR, "%s: attempt to read from unmapped PCI I/O space, offset=0x%X", + this->name.c_str(), offset); + return 0; } - } else { // I/O space access - // broadcast I/O request to devices that support I/O space - // until a device returns true that means "request accepted" - for (auto& dev : this->io_space_devs) { - if (dev->pci_io_read(offset, size, &result)) { - return result; - } - } - LOG_F(ERROR, "%s: attempt to read from unmapped PCI I/O space, offset=0x%X", - this->name.c_str(), offset); } - return result; } -void Bandit::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) +void BanditHost::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) { - int bus_num, dev_num, fun_num; - uint8_t reg_offs; - uint32_t idsel; + switch (offset >> 22) { - if (offset & BANDIT_CONFIG_SPACE) { - if (offset & 0x00400000) { - fun_num = (this->config_addr >> 8) & 7; - reg_offs = this->config_addr & 0xFCU; - - // access to the CONFIG_DATA pseudo-register causes a Config Cycle - if (this->config_addr & BANDIT_CAR_TYPE) { - bus_num = (this->config_addr >> 16) & 255; - dev_num = (this->config_addr >> 11) & 31; - LOG_F( - WARNING, "%s: write config cycle type 1 not supported yet %02x:%02x.%x @%02x.%c = %0*x", - this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, - size * 2, BYTESWAP_SIZED(value, size) - ); + case 3: // 0xC00000 // CONFIG_DATA + int bus_num, dev_num, fun_num; + uint8_t reg_offs; + AccessDetails details; + PCIDevice *device; + cfg_setup(offset, size, bus_num, dev_num, fun_num, reg_offs, details, device); + details.flags |= PCI_CONFIG_WRITE; + if (device) { + uint32_t oldvalue = details.size == 4 ? 0 : device->pci_cfg_read(reg_offs, details); + value = pci_cfg_rev_write(oldvalue, details, value); + device->pci_cfg_write(reg_offs, value, details); return; } + LOG_WRITE_NON_EXISTENT_PCI_DEVICE(); + break; - idsel = (this->config_addr >> 11) & 0x1FFFFFU; - - if (!SINGLE_BIT_SET(idsel)) { - LOG_F( - ERROR, "%s: write invalid IDSEL=0x%X config:0x%X ??:??.%x? @%02x?.%c = %0*x", - this->name.c_str(), idsel, this->config_addr, - fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, - size * 2, BYTESWAP_SIZED(value, size) - ); - return; - } - - if (idsel == BANDIT_ID_SEL) { // access to myself - this->pci_cfg_write(reg_offs, value, size); - return; - } - - if (this->dev_map.count(idsel)) { - this->dev_map[idsel]->pci_cfg_write(reg_offs, value, size); - } else { - dev_num = WHAT_BIT_SET(idsel) + 11; - LOG_F( - ERROR, "%s err: write attempt to non-existing PCI device ??:%02x.%x @%02x.%c = %0*x", - this->name.c_str(), dev_num, fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, - size * 2, BYTESWAP_SIZED(value, size) - ); - } - } else { + case 2: // 0x800000 // CONFIG_ADDR this->config_addr = BYTESWAP_32(value); - } - } else { // I/O space access - // broadcast I/O request to devices that support I/O space - // until a device returns true that means "request accepted" - for (auto& dev : this->io_space_devs) { - if (dev->pci_io_write(offset, value, size)) { - return; + break; + + default: // 0x000000 // I/O space + // broadcast I/O request to devices that support I/O space + // until a device returns true that means "request accepted" + for (auto& dev : this->io_space_devs) { + if (dev->pci_io_write(offset, value, size)) { + return; + } } - } - LOG_F(ERROR, "%s: attempt to write to unmapped PCI I/O space, offset=0x%X", - this->name.c_str(), offset); + LOG_F(ERROR, "%s: attempt to write to unmapped PCI I/O space, offset=0x%X", + this->name.c_str(), offset); } } -void Bandit::verbose_address_space() +void BanditPCI::verbose_address_space() { uint32_t mask; int bit_pos; @@ -296,7 +261,7 @@ void Bandit::verbose_address_space() } } -Chaos::Chaos(std::string name) : PCIHost() +Chaos::Chaos(std::string name) : BanditHost() { this->name = name; @@ -312,118 +277,6 @@ Chaos::Chaos(std::string name) : PCIHost() mem_ctrl->add_mmio_region(0xF0000000UL, 0x01000000, this); } -uint32_t Chaos::read(uint32_t rgn_start, uint32_t offset, int size) -{ - int bus_num, dev_num, fun_num; - uint8_t reg_offs; - uint32_t result, idsel; - - if (offset & BANDIT_CONFIG_SPACE) { - if (offset & 0x00400000) { - fun_num = (this->config_addr >> 8) & 7; - reg_offs = this->config_addr & 0xFCU; - - // access to the CONFIG_DATA pseudo-register causes a Config Cycle - if (this->config_addr & BANDIT_CAR_TYPE) { - bus_num = (this->config_addr >> 16) & 255; - dev_num = (this->config_addr >> 11) & 31; - LOG_F( - WARNING, "%s: read config cycle type 1 not supported yet %02x:%02x.%x @%02x.%c", - this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size - ); - return 0xFFFFFFFFUL; // PCI spec §6.1 - } - - idsel = (this->config_addr >> 11) & 0x1FFFFFU; - - if (!SINGLE_BIT_SET(idsel)) { - LOG_F( - ERROR, "%s: read invalid IDSEL=0x%X config:0x%X ??:??.%x? @%02x?.%c", - this->name.c_str(), idsel, this->config_addr, - fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size - ); - return 0xFFFFFFFFUL; // PCI spec §6.1 - } - - if (this->dev_map.count(idsel)) { - result = this->dev_map[idsel]->pci_cfg_read(reg_offs, size); - } else { - dev_num = WHAT_BIT_SET(idsel) + 11; - LOG_F( - ERROR, "%s err: read attempt from non-existing VCI device ??:%02x.%x @%02x.%c", - this->name.c_str(), dev_num, fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size - ); - return 0xFFFFFFFFUL; // PCI spec §6.1 - } - } else { - result = this->config_addr; - } - } else { // I/O space access - LOG_F(ERROR, "%s: I/O space not supported", this->name.c_str()); - return 0; - } - return result; -} - -void Chaos::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) -{ - int bus_num, dev_num, fun_num; - uint8_t reg_offs; - uint32_t idsel; - - if (offset & BANDIT_CONFIG_SPACE) { - if (offset & 0x00400000) { - fun_num = (this->config_addr >> 8) & 7; - reg_offs = this->config_addr & 0xFCU; - - // access to the CONFIG_DATA pseudo-register causes a Config Cycle - if (this->config_addr & BANDIT_CAR_TYPE) { - bus_num = (this->config_addr >> 16) & 255; - dev_num = (this->config_addr >> 11) & 31; - LOG_F( - WARNING, "%s: write config cycle type 1 not supported yet %02x:%02x.%x @%02x.%c = %0*x", - this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, - size * 2, BYTESWAP_SIZED(value, size) - ); - return; - } - - idsel = (this->config_addr >> 11) & 0x1FFFFFU; - - if (!SINGLE_BIT_SET(idsel)) { - LOG_F( - ERROR, "%s: write invalid IDSEL=0x%X config:0x%X ??:??.%x? @%02x?.%c = %0*x", - this->name.c_str(), idsel, this->config_addr, - fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, - size * 2, BYTESWAP_SIZED(value, size) - ); - return; - } - - if (this->dev_map.count(idsel)) { - this->dev_map[idsel]->pci_cfg_write(reg_offs, value, size); - } else { - dev_num = WHAT_BIT_SET(idsel) + 11; - LOG_F( - ERROR, "%s err: write attempt to non-existing VCI device ??:%02x.%x @%02x.%c = %0*x", - this->name.c_str(), dev_num, fun_num, reg_offs + (offset & 3), - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, - size * 2, BYTESWAP_SIZED(value, size) - ); - } - } else { - this->config_addr = BYTESWAP_32(value); - } - } else { // I/O space access - LOG_F(ERROR, "%s: I/O space not supported", this->name.c_str()); - } -} - static const DeviceDescription Bandit1_Descriptor = { Bandit::create_first, {}, {} }; @@ -436,6 +289,11 @@ static const DeviceDescription Chaos_Descriptor = { Chaos::create, {}, {} }; -REGISTER_DEVICE(Bandit1, Bandit1_Descriptor); -REGISTER_DEVICE(PsxPci1, PsxPci1_Descriptor); -REGISTER_DEVICE(Chaos, Chaos_Descriptor); +static const DeviceDescription Bandit1PCI_Descriptor = { + BanditPCI::create_first, {}, {} +}; + +REGISTER_DEVICE(Bandit1 , Bandit1_Descriptor); +REGISTER_DEVICE(Bandit1PCI, Bandit1PCI_Descriptor); +REGISTER_DEVICE(PsxPci1 , PsxPci1_Descriptor); +REGISTER_DEVICE(Chaos , Chaos_Descriptor); diff --git a/devices/common/pci/bandit.h b/devices/common/pci/bandit.h index edb991c7..4880014 100644 --- a/devices/common/pci/bandit.h +++ b/devices/common/pci/bandit.h @@ -38,7 +38,7 @@ along with this program. If not, see . #include #include -#define BANDIT_ID_SEL (1 << 0) // Bandit's own IDSEL +#define BANDIT_DEV (11) // Bandit's own device number #define BANDIT_CAR_TYPE (1 << 0) // Bandit config address type bit #define BANDIT_CONFIG_SPACE 0x00800000 // Bandit Config Space bit @@ -52,7 +52,19 @@ enum { /** checks if one bit is set at time, return 0 if not */ #define SINGLE_BIT_SET(val) ((val) && !((val) & ((val)-1))) -class Bandit : public PCIHost, public PCIDevice { +class BanditHost : public PCIHost, public MMIODevice { +public: + void cfg_setup(uint32_t offset, int size, int &bus_num, int &dev_num, int &fun_num, uint8_t ®_offs, AccessDetails &details, PCIDevice *&device); + + // MMIODevice methods + uint32_t read(uint32_t rgn_start, uint32_t offset, int size); + void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size); + +protected: + uint32_t config_addr; +}; + +class Bandit : public BanditHost { public: Bandit(int bridge_num, std::string name, int dev_id=1, int rev=3); ~Bandit() = default; @@ -65,19 +77,27 @@ public: return std::unique_ptr(new Bandit(1, "PSX-PCI1", 8, 0)); }; - uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size); - void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size); +private: + uint32_t base_addr; +}; - // MMIODevice methods - uint32_t read(uint32_t rgn_start, uint32_t offset, int size); - void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size); +class BanditPCI : public PCIDevice { +public: + BanditPCI(int bridge_num, std::string name); + ~BanditPCI() = default; + + static std::unique_ptr create_first() { + return std::unique_ptr(new BanditPCI(1, "BanditPCI")); + }; + // PCIDevice methods + uint32_t pci_cfg_read(uint32_t reg_offs, AccessDetails &details); + void pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details); + protected: void verbose_address_space(); private: - uint32_t base_addr; - uint32_t config_addr; uint32_t addr_mask; uint32_t mode_ctrl; // controls various chip modes/features uint32_t rd_hold_off_cnt; @@ -88,7 +108,7 @@ private: frequency as the CPU bus (40-50 MHz) and provides an interface between video input/output devices and the CPU bus. */ -class Chaos : public PCIHost, public MMIODevice { +class Chaos : public BanditHost { public: Chaos(std::string name); ~Chaos() = default; @@ -96,13 +116,6 @@ public: static std::unique_ptr create() { return std::unique_ptr(new Chaos("VCI0")); }; - - // MMIODevice methods - uint32_t read(uint32_t rgn_start, uint32_t offset, int size); - void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size); - -private: - uint32_t config_addr; }; #endif // BANDIT_PCI_H diff --git a/devices/common/pci/pcidevice.cpp b/devices/common/pci/pcidevice.cpp index bb03f66..615487c 100644 --- a/devices/common/pci/pcidevice.cpp +++ b/devices/common/pci/pcidevice.cpp @@ -50,81 +50,49 @@ PCIDevice::PCIDevice(std::string name) this->pci_notify_bar_change = [](int bar_num) {}; }; -uint32_t PCIDevice::pci_cfg_read(uint32_t reg_offs, uint32_t size) +uint32_t PCIDevice::pci_cfg_read(uint32_t reg_offs, AccessDetails &details) { - uint32_t result; - switch (reg_offs) { case PCI_CFG_DEV_ID: - result = (this->device_id << 16) | (this->vendor_id); - break; + return (this->device_id << 16) | (this->vendor_id); case PCI_CFG_STAT_CMD: - result = (this->pci_rd_stat() << 16) | (this->pci_rd_cmd()); - break; + return (this->pci_rd_stat() << 16) | (this->pci_rd_cmd()); case PCI_CFG_CLASS_REV: - result = this->class_rev; - break; + return this->class_rev; case PCI_CFG_DWORD_3: - result = (pci_rd_bist() << 24) | (this->hdr_type << 16) | - (pci_rd_lat_timer() << 8) | pci_rd_cache_lnsz(); - break; + return (pci_rd_bist() << 24) | (this->hdr_type << 16) | + (pci_rd_lat_timer() << 8) | pci_rd_cache_lnsz(); case PCI_CFG_BAR0: case PCI_CFG_BAR1: case PCI_CFG_BAR2: case PCI_CFG_BAR3: case PCI_CFG_BAR4: case PCI_CFG_BAR5: - result = this->bars[(reg_offs - 0x10) >> 2]; - break; + return this->bars[(reg_offs - 0x10) >> 2]; case PCI_CFG_SUBSYS_ID: - result = (this->subsys_id << 16) | (this->subsys_vndr); - break; + return (this->subsys_id << 16) | (this->subsys_vndr); case PCI_CFG_ROM_BAR: - result = this->exp_rom_bar; - break; + return this->exp_rom_bar; case PCI_CFG_DWORD_15: - result = (max_lat << 24) | (min_gnt << 16) | (irq_pin << 8) | irq_line; - break; + return (max_lat << 24) | (min_gnt << 16) | (irq_pin << 8) | irq_line; case PCI_CFG_CAP_PTR: - result = cap_ptr; - break; - default: - LOG_F( - WARNING, "%s: attempt to read from reserved/unimplemented register @%02x.%c", - this->pci_name.c_str(), reg_offs, - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size - ); - return 0; - } - - if (size == 4) { - return BYTESWAP_32(result); - } else { - return read_mem_rev(((uint8_t *)&result) + (reg_offs & 3), size); + return cap_ptr; } + LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER(); + return 0; } -void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) +void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details) { - uint32_t data; - - if (size == 4) { - data = BYTESWAP_32(value); - } else { - // get current register content as DWORD and update it partially - data = BYTESWAP_32(this->pci_cfg_read(reg_offs, 4)); - write_mem_rev(((uint8_t *)&data) + (reg_offs & 3), value, size); - } - switch (reg_offs) { case PCI_CFG_STAT_CMD: - this->pci_wr_stat(data >> 16); - this->pci_wr_cmd(data & 0xFFFFU); + this->pci_wr_stat(value >> 16); + this->pci_wr_cmd(value & 0xFFFFU); break; case PCI_CFG_DWORD_3: - this->pci_wr_bist(data >> 24); - this->pci_wr_lat_timer((data >> 8) & 0xFF); - this->pci_wr_cache_lnsz(data & 0xFF); + this->pci_wr_bist(value >> 24); + this->pci_wr_lat_timer((value >> 8) & 0xFF); + this->pci_wr_cache_lnsz(value & 0xFF); break; case PCI_CFG_BAR0: case PCI_CFG_BAR1: @@ -132,17 +100,17 @@ void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) case PCI_CFG_BAR3: case PCI_CFG_BAR4: case PCI_CFG_BAR5: - if (data == 0xFFFFFFFFUL) { + if (value == 0xFFFFFFFFUL) { this->do_bar_sizing((reg_offs - 0x10) >> 2); } else { - this->set_bar_value((reg_offs - 0x10) >> 2, data); + this->set_bar_value((reg_offs - 0x10) >> 2, value); } break; case PCI_CFG_ROM_BAR: - if ((data & this->exp_bar_cfg) == this->exp_bar_cfg) { - this->exp_rom_bar = (data & (this->exp_bar_cfg | 1)); + if ((value & this->exp_bar_cfg) == this->exp_bar_cfg) { + this->exp_rom_bar = (value & (this->exp_bar_cfg | 1)); } else { - this->exp_rom_bar = (data & (this->exp_bar_cfg | 1)); + this->exp_rom_bar = (value & (this->exp_bar_cfg | 1)); if (this->exp_rom_bar & 1) { this->map_exp_rom_mem(); } else { @@ -152,15 +120,10 @@ void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) } break; case PCI_CFG_DWORD_15: - this->irq_line = data >> 24; + this->irq_line = value >> 24; break; default: - LOG_F( - WARNING, "%s: attempt to write to reserved/unimplemented register @%02x.%c = %0*x", - this->pci_name.c_str(), reg_offs, - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, - size * 2, BYTESWAP_SIZED(value, size) - ); + LOG_WRITE_UNIMPLEMENTED_CONFIG_REGISTER(); } } diff --git a/devices/common/pci/pcidevice.h b/devices/common/pci/pcidevice.h index b1503a8..5ed7418 100644 --- a/devices/common/pci/pcidevice.h +++ b/devices/common/pci/pcidevice.h @@ -78,8 +78,8 @@ public: }; // configuration space access methods - virtual uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size); - virtual void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size); + virtual uint32_t pci_cfg_read(uint32_t reg_offs, AccessDetails &details); + virtual void pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details); // plugin interface for using in the derived classes std::function pci_rd_stat; @@ -101,6 +101,10 @@ public: this->host_instance = host_instance; }; + // MMIODevice methods + virtual uint32_t read(uint32_t rgn_start, uint32_t offset, int size) { return 0; } + virtual void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) { } + protected: void do_bar_sizing(int bar_num); void set_bar_value(int bar_num, uint32_t value); @@ -137,4 +141,124 @@ protected: std::unique_ptr exp_rom_data; }; +/* value is dword from PCI config. MSB..LSB of value is stored in PCI config as 0:LSB..3:MSB. + result is part of value at byte offset from LSB with size bytes (with wrap around) and flipped as required for pci_cfg_read result. */ +inline uint32_t pci_cfg_rev_read(uint32_t value, AccessDetails &details) { + switch (details.size << 2 | details.offset) { + case 0x04: return value & 0xff; // 0 + case 0x05: return (value >> 8) & 0xff; // 1 + case 0x06: return (value >> 16) & 0xff; // 2 + case 0x07: return (value >> 24) & 0xff; // 3 + + case 0x08: return ((value & 0xff) << 8) | ((value >> 8) & 0xff); // 0 1 + case 0x09: return ( value & 0xff00) | ((value >> 16) & 0xff); // 1 2 + case 0x0a: return ((value >> 8) & 0xff00) | ((value >> 24) & 0xff); // 2 3 + case 0x0b: return ((value >> 16) & 0xff00) | ( value & 0xff); // 3 0 + + case 0x10: return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value >> 8) & 0xff00) | ((value >> 24) & 0xff); // 0 1 2 3 + case 0x11: return ((value & 0xff00) << 16) | ( value & 0xff0000) | ((value >> 16) & 0xff00) | ( value & 0xff); // 1 2 3 0 + case 0x12: return ((value & 0xff0000) << 8) | ((value >> 8) & 0xff0000) | ((value & 0xff) << 8) | ((value >> 8) & 0xff); // 2 3 0 1 + case 0x13: return ( value & 0xff000000) | ((value & 0xff) << 16) | ( value & 0xff00) | ((value >> 16) & 0xff); // 3 0 1 2 + + default: return 0xffffffff; + } +} + +/* value is dword from PCI config. MSB..LSB of value (3.2.1.0) is stored in PCI config as 0:LSB..3:MSB. + newvalue is flipped bytes (d0.d1.d2.d3, as passed to pci_cfg_write) to be merged into value. + result is part of value at byte offset from LSB with size bytes (with wrap around) modified by newvalue. */ +inline uint32_t pci_cfg_rev_write(uint32_t value, AccessDetails &details, uint32_t newvalue) { + switch (details.size << 2 | details.offset) { + case 0x04: return (value & 0xffffff00) | (newvalue & 0xff); // 3 2 1 d0 + case 0x05: return (value & 0xffff00ff) | ((newvalue & 0xff) << 8); // 3 2 d0 0 + case 0x06: return (value & 0xff00ffff) | ((newvalue & 0xff) << 16); // 3 d0 1 0 + case 0x07: return (value & 0x00ffffff) | ((newvalue & 0xff) << 24); // d0 2 1 0 + + case 0x08: return (value & 0xffff0000) | ((newvalue >> 8) & 0xff) | ((newvalue & 0xff) << 8); // 3 2 d1 d0 + case 0x09: return (value & 0xff0000ff) | (newvalue & 0xff00) | ((newvalue & 0xff) << 16); // 3 d1 d0 0 + case 0x0a: return (value & 0x0000ffff) | ((newvalue & 0xff00) << 8) | ((newvalue & 0xff) << 24); // d1 d0 1 0 + case 0x0b: return (value & 0x00ffff00) | ((newvalue & 0xff00) << 16) | (newvalue & 0xff); // d0 2 1 d1 + + case 0x10: return ((newvalue & 0xff) << 24) | ((newvalue & 0xff00) << 8) | ((newvalue >> 8) & 0xff00) | ((newvalue >> 24) & 0xff); // d3 d2 d1 d0 + case 0x11: return ((newvalue & 0xff00) << 16) | ( newvalue & 0xff0000) | ((newvalue >> 16) & 0xff00) | ( newvalue & 0xff); // d2 d1 d0 d3 + case 0x12: return ((newvalue & 0xff0000) << 8) | ((newvalue >> 8) & 0xff0000) | ((newvalue & 0xff) << 8) | ((newvalue >> 8) & 0xff); // d1 d0 d3 d2 + case 0x13: return ( newvalue & 0xff000000) | ((newvalue & 0xff) << 16) | ( newvalue & 0xff00) | ((newvalue >> 16) & 0xff); // d0 d3 d2 d1 + + default: return 0xffffffff; + } +} + +inline uint32_t pci_cfg_log(uint32_t value, AccessDetails &details) { + switch (details.size << 2 | details.offset) { + case 0x04: return (uint8_t) value; + case 0x05: return (uint8_t)(value >> 8); + case 0x06: return (uint8_t)(value >> 16); + case 0x07: return (uint8_t)(value >> 24); + + case 0x08: return (uint16_t) value; + case 0x09: return (uint16_t) (value >> 8); + case 0x0a: return (uint16_t) (value >> 16); + case 0x0b: return (uint16_t)((value >> 24) | (value << 8)); + + case 0x10: return value; + case 0x11: return (value >> 8) | (value << 24); + case 0x12: return (value >> 16) | (value << 16); + case 0x13: return (value >> 24) | (value << 8); + + default: return 0xffffffff; + } +} + +#define SIZE_ARGS details.size == 4 ? 'l' : details.size == 2 ? 'w' : details.size == 1 ? 'b' : '0' + details.size + +#define LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER() \ + do { if ((details.flags & PCI_CONFIG_DIRECTION) == PCI_CONFIG_READ) { \ + VLOG_F( \ + (~-details.size & details.offset) ? loguru::Verbosity_ERROR : loguru::Verbosity_WARNING, \ + "%s: read unimplemented config register @%02x.%c", \ + this->name.c_str(), reg_offs + details.offset, \ + SIZE_ARGS \ + ); \ + } } while(0) + +#define LOG_NAMED_CONFIG_REGISTER(reg_verb, reg_name) \ + VLOG_F( \ + (~-details.size & details.offset) ? loguru::Verbosity_ERROR : loguru::Verbosity_WARNING, \ + "%s: %s %s register @%02x.%c = %0*x", \ + this->name.c_str(), reg_verb, reg_name, reg_offs + details.offset, \ + SIZE_ARGS, \ + details.size * 2, pci_cfg_log(value, details) \ + ) + +#define LOG_READ_NAMED_CONFIG_REGISTER(reg_name) \ + do { if ((details.flags & PCI_CONFIG_DIRECTION) == PCI_CONFIG_READ) { \ + LOG_NAMED_CONFIG_REGISTER("read ", reg_name); \ + } } while(0) + +#define LOG_WRITE_NAMED_CONFIG_REGISTER(reg_name) \ + LOG_NAMED_CONFIG_REGISTER("write", reg_name) + +#define LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER_WITH_VALUE() \ + LOG_READ_NAMED_CONFIG_REGISTER("unimplemented config") + +#define LOG_WRITE_UNIMPLEMENTED_CONFIG_REGISTER() \ + LOG_WRITE_NAMED_CONFIG_REGISTER("unimplemented config") + +#define LOG_READ_NON_EXISTENT_PCI_DEVICE() \ + LOG_F( \ + ERROR, \ + "%s err: read attempt from non-existent PCI device %02x:%02x.%x @%02x.%c", \ + this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + details.offset, \ + SIZE_ARGS \ + ) + +#define LOG_WRITE_NON_EXISTENT_PCI_DEVICE() \ + LOG_F( \ + ERROR, \ + "%s err: write attempt to non-existent PCI device %02x:%02x.%x @%02x.%c = %0*x", \ + this->name.c_str(), bus_num, dev_num, fun_num, reg_offs + details.offset, \ + SIZE_ARGS, \ + details.size * 2, BYTESWAP_SIZED(value, details.size) \ + ) + #endif /* PCI_DEVICE_H */ diff --git a/devices/common/pci/pcihost.cpp b/devices/common/pci/pcihost.cpp index 761a57a..47d997c 100644 --- a/devices/common/pci/pcihost.cpp +++ b/devices/common/pci/pcihost.cpp @@ -83,3 +83,8 @@ void PCIHost::attach_pci_device(std::string& dev_name, int slot_id) this->pci_register_device( slot_id, dynamic_cast(gMachineObj->get_comp_by_name(dev_name))); } + +PCIDevice *PCIHost::pci_find_device(uint8_t bus_num, uint8_t dev_num, uint8_t fun_num) +{ + return NULL; +} diff --git a/devices/common/pci/pcihost.h b/devices/common/pci/pcihost.h index 5a0499a..93e144e 100644 --- a/devices/common/pci/pcihost.h +++ b/devices/common/pci/pcihost.h @@ -29,6 +29,23 @@ along with this program. If not, see . #include #include +enum { + PCI_CONFIG_DIRECTION = 1, + PCI_CONFIG_READ = 0, + PCI_CONFIG_WRITE = 1, + + PCI_CONFIG_TYPE = 4, + PCI_CONFIG_TYPE_0 = 0, + PCI_CONFIG_TYPE_1 = 4, +}; + +/** PCI config space access details */ +typedef struct AccessDetails { + uint8_t size; + uint8_t offset; + uint8_t flags; +} AccessDetails; + class PCIDevice; // forward declaration to prevent errors class PCIHost { @@ -46,6 +63,8 @@ public: virtual void attach_pci_device(std::string& dev_name, int slot_id); + virtual PCIDevice *pci_find_device(uint8_t bus_num, uint8_t dev_num, uint8_t fun_num); + protected: std::unordered_map dev_map; std::vector io_space_devs; diff --git a/devices/memctrl/mpc106.cpp b/devices/memctrl/mpc106.cpp index 1b40ac7..19b772f 100644 --- a/devices/memctrl/mpc106.cpp +++ b/devices/memctrl/mpc106.cpp @@ -72,6 +72,32 @@ int MPC106::device_postinit() return 0; } +void MPC106::cfg_setup(uint32_t offset, int size, int &bus_num, int &dev_num, int &fun_num, uint8_t ®_offs, AccessDetails &details, PCIDevice *&device) +{ + device = NULL; + details.size = size; + details.offset = offset & 3; + + bus_num = (this->config_addr >> 8) & 0xFF; + dev_num = (this->config_addr >> 19) & 0x1F; + fun_num = (this->config_addr >> 16) & 0x07; + reg_offs = (this->config_addr >> 24) & 0xFC; + + if (bus_num) { + details.flags = PCI_CONFIG_TYPE_1; + device = pci_find_device(bus_num, dev_num, fun_num); + } + else { + details.flags = PCI_CONFIG_TYPE_0; + if (dev_num == 0 && fun_num == 0) { + device = this; // dev_num 0 is assigned to myself + } + else if (this->dev_map.count(dev_num)) { + device = this->dev_map[dev_num]; + } + } +} + uint32_t MPC106::read(uint32_t rgn_start, uint32_t offset, int size) { uint32_t result; @@ -87,7 +113,7 @@ uint32_t MPC106::read(uint32_t rgn_start, uint32_t offset, int size) { } else { if (offset >= 0x200000) { if (this->config_addr & 0x80) // process only if bit E (enable) is set - return pci_read(size); + return pci_read(offset, size); } } @@ -111,116 +137,83 @@ void MPC106::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size this->config_addr = value; } else { if (this->config_addr & 0x80) // process only if bit E (enable) is set - return pci_write(value, size); + return pci_write(offset, value, size); } } } -uint32_t MPC106::pci_read(uint32_t size) { - int bus_num, dev_num, fun_num, reg_offs; - - bus_num = (this->config_addr >> 8) & 0xFF; - dev_num = (this->config_addr >> 19) & 0x1F; - fun_num = (this->config_addr >> 16) & 0x07; - reg_offs = (this->config_addr >> 24) & 0xFC; - - if (bus_num) { - LOG_F( - ERROR, - "%s err: read attempt from non-local PCI bus, config_addr = %x %02x:%02x.%x @%02x.%c", - this->name.c_str(), this->config_addr, bus_num, dev_num, fun_num, reg_offs, - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size - ); - return 0xFFFFFFFFUL; // PCI spec §6.1 +uint32_t MPC106::pci_read(uint32_t offset, uint32_t size) { + int bus_num, dev_num, fun_num; + uint8_t reg_offs; + AccessDetails details; + PCIDevice *device; + cfg_setup(offset, size, bus_num, dev_num, fun_num, reg_offs, details, device); + details.flags |= PCI_CONFIG_READ; + if (device) { + return pci_cfg_rev_read(device->pci_cfg_read(reg_offs, details), details); } - - if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself - return this->pci_cfg_read(reg_offs, size); - } else { - if (this->dev_map.count(dev_num)) { - return this->dev_map[dev_num]->pci_cfg_read(reg_offs, size); - } else { - LOG_F( - ERROR, - "%s err: read attempt from non-existing PCI device %02x:%02x.%x @%02x.%c", - this->name.c_str(), bus_num, dev_num, fun_num, reg_offs, - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size - ); - return 0xFFFFFFFFUL; // PCI spec §6.1 - } - } - - return 0; + LOG_READ_NON_EXISTENT_PCI_DEVICE(); + return 0xFFFFFFFFUL; // PCI spec §6.1 } -void MPC106::pci_write(uint32_t value, uint32_t size) { - int bus_num, dev_num, fun_num, reg_offs; - - bus_num = (this->config_addr >> 8) & 0xFF; - dev_num = (this->config_addr >> 19) & 0x1F; - fun_num = (this->config_addr >> 16) & 0x07; - reg_offs = (this->config_addr >> 24) & 0xFC; - - if (bus_num) { - LOG_F( - ERROR, - "%s err: write attempt to non-local PCI bus, config_addr = %x %02x:%02x.%x @%02x.%c = %0*x", - this->name.c_str(), this->config_addr, bus_num, dev_num, fun_num, reg_offs, - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, - size * 2, BYTESWAP_SIZED(value, size) - ); +void MPC106::pci_write(uint32_t offset, uint32_t value, uint32_t size) { + int bus_num, dev_num, fun_num; + uint8_t reg_offs; + AccessDetails details; + PCIDevice *device; + cfg_setup(offset, size, bus_num, dev_num, fun_num, reg_offs, details, device); + details.flags |= PCI_CONFIG_WRITE; + if (device) { + uint32_t oldvalue = details.size == 4 ? 0 : device->pci_cfg_read(reg_offs, details); + value = pci_cfg_rev_write(oldvalue, details, value); + device->pci_cfg_write(reg_offs, value, details); return; } - - if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself - this->pci_cfg_write(reg_offs, value, size); - } else { - if (this->dev_map.count(dev_num)) { - this->dev_map[dev_num]->pci_cfg_write(reg_offs, value, size); - } else { - LOG_F( - ERROR, - "%s err: write attempt to non-existing PCI device %02x:%02x.%x @%02x.%c = %0*x", - this->name.c_str(), bus_num, dev_num, fun_num, reg_offs, - size == 4 ? 'l' : size == 2 ? 'w' : size == 1 ? 'b' : '0' + size, - size * 2, BYTESWAP_SIZED(value, size) - ); - } - } + LOG_WRITE_NON_EXISTENT_PCI_DEVICE(); } -uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, uint32_t size) { +uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, AccessDetails &details) { #ifdef MPC106_DEBUG LOG_F(9, "read from Grackle register %08X", reg_offs); #endif if (reg_offs < 64) { - return PCIDevice::pci_cfg_read(reg_offs, size); + return PCIDevice::pci_cfg_read(reg_offs, details); } - return read_mem(&this->my_pci_cfg_hdr[reg_offs], size); + uint32_t value = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[reg_offs]); + if ((reg_offs >= 0x80 && reg_offs <= 0xA0) || reg_offs == 0xF0) { + return value; + } + LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER_WITH_VALUE(); + return value; } -void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) { +void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details) { #ifdef MPC106_DEBUG LOG_F(9, "write %08X to Grackle register %08X", value, reg_offs); #endif if (reg_offs < 64) { - PCIDevice::pci_cfg_write(reg_offs, value, size); + PCIDevice::pci_cfg_write(reg_offs, value, details); return; } // FIXME: implement write-protection for read-only registers - write_mem(&this->my_pci_cfg_hdr[reg_offs], value, size); + uint32_t *addr = (uint32_t *)&this->my_pci_cfg_hdr[reg_offs]; + WRITE_DWORD_LE_A(addr, value); - if (this->my_pci_cfg_hdr[0xF2] & 8) { + if ((reg_offs >= 0x80 && reg_offs <= 0xA0) || reg_offs == 0xF0) { + if (this->my_pci_cfg_hdr[0xF2] & 8) { #ifdef MPC106_DEBUG - LOG_F(9, "MPC106: MCCR1[MEMGO] was set!"); + LOG_F(9, "MPC106: MCCR1[MEMGO] was set!"); #endif - setup_ram(); + setup_ram(); + } + return; } + LOG_WRITE_UNIMPLEMENTED_CONFIG_REGISTER(); } void MPC106::setup_ram() { diff --git a/devices/memctrl/mpc106.h b/devices/memctrl/mpc106.h index 5d62df2..c338d6c 100644 --- a/devices/memctrl/mpc106.h +++ b/devices/memctrl/mpc106.h @@ -59,12 +59,13 @@ public: protected: /* PCI access */ - uint32_t pci_read(uint32_t size); - void pci_write(uint32_t value, uint32_t size); + uint32_t pci_read(uint32_t offset, uint32_t size); + void pci_write(uint32_t offset, uint32_t value, uint32_t size); + void cfg_setup(uint32_t offset, int size, int &bus_num, int &dev_num, int &fun_num, uint8_t ®_offs, AccessDetails &details, PCIDevice *&device); /* my own PCI configuration registers access */ - uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size); - void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size); + uint32_t pci_cfg_read(uint32_t reg_offs, AccessDetails &details); + void pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details); bool supports_io_space(void) { return true; diff --git a/devices/video/atirage.cpp b/devices/video/atirage.cpp index 7b8d640..c88bd64 100644 --- a/devices/video/atirage.cpp +++ b/devices/video/atirage.cpp @@ -161,34 +161,35 @@ void ATIRage::notify_bar_change(int bar_num) } } -uint32_t ATIRage::pci_cfg_read(uint32_t reg_offs, uint32_t size) +uint32_t ATIRage::pci_cfg_read(uint32_t reg_offs, AccessDetails &details) { if (reg_offs < 64) { - return PCIDevice::pci_cfg_read(reg_offs, size); + return PCIDevice::pci_cfg_read(reg_offs, details); } switch (reg_offs) { case 0x40: return this->user_cfg; default: - LOG_F(WARNING, "ATIRage: reading from unimplemented config register at 0x%X", reg_offs); + LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER(); } return 0; } -void ATIRage::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) +void ATIRage::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details) { if (reg_offs < 64) { - PCIDevice::pci_cfg_write(reg_offs, value, size); - } else { - switch (reg_offs) { - case 0x40: - this->user_cfg = value; - break; - default: - LOG_F(WARNING, "ATIRage: writing to unimplemented config register at 0x%X", reg_offs); - } + PCIDevice::pci_cfg_write(reg_offs, value, details); + return; + } + + switch (reg_offs) { + case 0x40: + this->user_cfg = value; + break; + default: + LOG_WRITE_UNIMPLEMENTED_CONFIG_REGISTER(); } } diff --git a/devices/video/atirage.h b/devices/video/atirage.h index 30c3eb6..62dac2e 100644 --- a/devices/video/atirage.h +++ b/devices/video/atirage.h @@ -64,8 +64,8 @@ public: return true; }; - uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size); - void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size); + uint32_t pci_cfg_read(uint32_t reg_offs, AccessDetails &details); + void pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details); /* I/O space access methods */ bool pci_io_read(uint32_t offset, uint32_t size, uint32_t* res);