pcidevice: improve BAR configuration.

This commit is contained in:
Maxim Poliakovski 2023-02-04 17:57:46 +01:00
parent 654ff0219c
commit cc17035e67
8 changed files with 92 additions and 72 deletions

View File

@ -1,6 +1,6 @@
/*
DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-22 divingkatae and maximum
Copyright (C) 2018-23 divingkatae and maximum
(theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -123,6 +123,18 @@ void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &
}
}
void PCIDevice::setup_bars(std::vector<BarConfig> cfg_data)
{
for (auto cfg_entry : cfg_data) {
if (cfg_entry.bar_num > 5) {
ABORT_F("BAR number %d out of range", cfg_entry.bar_num);
}
this->bars_cfg[cfg_entry.bar_num] = cfg_entry.bar_cfg;
}
this->finish_config_bars();
}
int PCIDevice::attach_exp_rom_image(const std::string img_path)
{
std::ifstream img_file;
@ -201,74 +213,73 @@ int PCIDevice::attach_exp_rom_image(const std::string img_path)
return result;
}
void PCIDevice::do_bar_sizing(int bar_num)
{
}
void PCIDevice::set_bar_value(int bar_num, uint32_t value)
{
uint32_t bar_cfg = this->bars_cfg[bar_num];
switch (bars_typ[bar_num]) {
case BAR_Unused:
case PCIBarType::Unused:
return;
case BAR_IO_16Bit:
case BAR_IO_32Bit:
case PCIBarType::Io_16_Bit:
case PCIBarType::Io_32_Bit:
this->bars[bar_num] = (value & bar_cfg & ~3) | (bar_cfg & 3);
break;
case BAR_MEM_20Bit:
case BAR_MEM_32Bit:
case BAR_MEM_64Bit:
case PCIBarType::Mem_20_Bit:
case PCIBarType::Mem_32_Bit:
case PCIBarType::Mem_64_Bit_Lo:
this->bars[bar_num] = (value & bar_cfg & ~0xF) | (bar_cfg & 0xF);
break;
case BAR_MEM_64BitHi:
this->bars[bar_num] = (value & bar_cfg);
case PCIBarType::Mem_64_Bit_Hi:
this->bars[bar_num] = value & bar_cfg;
break;
}
if (value == 0xFFFFFFFFUL) {
do_bar_sizing(bar_num);
return;
}
this->pci_notify_bar_change(bar_num);
if (value != 0xFFFFFFFFUL) // don't notify the device during BAR sizing
this->pci_notify_bar_change(bar_num);
}
void PCIDevice::finish_config_bars()
{
for (int bar_num = 0; bar_num < 6; bar_num++) {
uint32_t bar_cfg = this->bars_cfg[bar_num];
if (!bar_cfg) // skip unimplemented BARs
continue;
if (bar_cfg & 1) {
bars_typ[bar_num] = (bar_cfg & 0xffff0000) ? BAR_IO_32Bit : BAR_IO_16Bit;
bars_typ[bar_num] = (bar_cfg & 0xffff0000) ? PCIBarType::Io_32_Bit :
PCIBarType::Io_16_Bit;
}
else if (bar_cfg != 0) {
else {
int pci_space_type = (bar_cfg >> 1) & 3;
switch (pci_space_type) {
case 0:
bars_typ[bar_num] = BAR_MEM_32Bit;
break;
case 1:
bars_typ[bar_num] = BAR_MEM_20Bit;
break;
case 2:
if (bar_num > 4) {
ABORT_F("%s: BAR %d cannot be 64-bit", this->pci_name.c_str(), bar_num);
}
else if (this->bars_cfg[bar_num+1] == 0) {
ABORT_F("%s: 64-bit BAR %d has zero for upper 32 bits", this->pci_name.c_str(), bar_num);
}
else {
bars_typ[bar_num++] = BAR_MEM_64Bit;
bars_typ[bar_num] = BAR_MEM_64BitHi;
}
break;
case 3:
ABORT_F("%s: invalid or unsupported PCI space type %d for BAR %d", this->pci_name.c_str(), pci_space_type, bar_num);
break;
case 0:
bars_typ[bar_num] = PCIBarType::Mem_32_Bit;
break;
case 1:
bars_typ[bar_num] = PCIBarType::Mem_20_Bit;
break;
case 2:
if (bar_num >= 5) {
ABORT_F("%s: BAR %d cannot be 64-bit",
this->pci_name.c_str(), bar_num);
}
else if (this->bars_cfg[bar_num+1] == 0) {
ABORT_F("%s: 64-bit BAR %d has zero for upper 32 bits",
this->pci_name.c_str(), bar_num);
}
else {
bars_typ[bar_num] = PCIBarType::Mem_64_Bit_Hi;
bars_typ[bar_num++] = PCIBarType::Mem_64_Bit_Lo;
}
break;
default:
ABORT_F("%s: invalid or unsupported PCI space type %d for BAR %d",
this->pci_name.c_str(), pci_space_type, bar_num);
} // switch pci_space_type
} // if BAR_MEM
}
} // for bar_num
}

View File

@ -1,6 +1,6 @@
/*
DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-22 divingkatae and maximum
Copyright (C) 2018-23 divingkatae and maximum
(theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <functional>
#include <memory>
#include <string>
#include <vector>
/** PCI configuration space registers offsets */
enum {
@ -59,16 +60,21 @@ enum {
};
/** PCI BAR types */
enum PCIBarType {
BAR_Unused,
BAR_IO_16Bit,
BAR_IO_32Bit,
BAR_MEM_20Bit, // < 1M
BAR_MEM_32Bit,
BAR_MEM_64Bit,
BAR_MEM_64BitHi,
enum PCIBarType : uint32_t {
Unused = 0,
Io_16_Bit,
Io_32_Bit,
Mem_20_Bit, // legacy type for < 1MB memory
Mem_32_Bit,
Mem_64_Bit_Lo,
Mem_64_Bit_Hi
};
typedef struct {
uint32_t bar_num;
uint32_t bar_cfg;
} BarConfig;
class PCIDevice : public MMIODevice {
public:
PCIDevice(std::string name);
@ -116,8 +122,8 @@ public:
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);
void setup_bars(std::vector<BarConfig> cfg_data);
void finish_config_bars();
void map_exp_rom_mem();
@ -143,7 +149,7 @@ protected:
uint32_t bars[6] = { 0 }; // base address registers
uint32_t bars_cfg[6] = { 0 }; // configuration values for base address registers
PCIBarType bars_typ[6] = { BAR_Unused }; // types for base address registers
PCIBarType bars_typ[6] = { PCIBarType::Unused }; // types for base address registers
uint32_t exp_bar_cfg = 0; // expansion ROM configuration
uint32_t exp_rom_bar = 0; // expansion ROM base address register

View File

@ -42,8 +42,8 @@ GrandCentral::GrandCentral() : PCIDevice("mac-io/grandcentral"), InterruptCtrl()
this->device_id = 0x0002;
this->class_rev = 0xFF000002;
this->cache_ln_sz = 8;
this->bars_cfg[0] = 0xFFFE0000UL; // declare 128Kb of memory-mapped I/O space
this->finish_config_bars();
this->setup_bars({{0, 0xFFFE0000UL}}); // declare 128Kb of memory-mapped I/O space
this->pci_notify_bar_change = [this](int bar_num) {
this->notify_bar_change(bar_num);

View File

@ -1,6 +1,6 @@
/*
DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-22 divingkatae and maximum
Copyright (C) 2018-23 divingkatae and maximum
(theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
@ -34,7 +34,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <cinttypes>
#include <functional>
#include <iostream>
#include <memory>
/** Heathrow Mac I/O device emulation.
@ -54,8 +53,8 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow"), InterruptCtrl()
this->class_rev = 0xFF000001;
this->cache_ln_sz = 8;
this->lat_timer = 0x40;
this->bars_cfg[0] = 0xFFF80000UL; // declare 512Kb of memory-mapped I/O space
this->finish_config_bars();
this->setup_bars({{0, 0xFFF80000UL}}); // declare 512Kb of memory-mapped I/O space
this->pci_notify_bar_change = [this](int bar_num) {
this->notify_bar_change(bar_num);

View File

@ -36,8 +36,8 @@ OHare::OHare() : PCIDevice("mac-io/ohare"), InterruptCtrl()
this->device_id = 0x0007;
this->class_rev = 0xFF000001;
this->cache_ln_sz = 8;
this->bars_cfg[0] = 0xFFF80000UL; // declare 512Kb of memory-mapped I/O space
this->finish_config_bars();
this->setup_bars({{0, 0xFFF80000UL}}); // declare 512Kb of memory-mapped I/O space
this->pci_notify_bar_change = [this](int bar_num) {
this->notify_bar_change(bar_num);

View File

@ -44,8 +44,8 @@ AtiMach64Gx::AtiMach64Gx()
this->vendor_id = PCI_VENDOR_ATI;
this->device_id = ATI_MACH64_GX_DEV_ID;
this->class_rev = (0x030000 << 8) | 3;
this->bars_cfg[0] = 0xFF000000UL; // declare main aperture (16MB)
this->finish_config_bars();
this->setup_bars({{0, 0xFF000000UL}}); // declare main aperture (16MB)
this->pci_notify_bar_change = [this](int bar_num) {
this->notify_bar_change(bar_num);

View File

@ -124,10 +124,12 @@ ATIRage::ATIRage(uint16_t dev_id)
this->class_rev = (0x030000 << 8) | asic_id;
this->min_gnt = 8;
this->irq_pin = 1;
this->bars_cfg[0] = 0xFF000000UL; // declare main aperture (16MB)
this->bars_cfg[1] = 0xFFFFFF01UL; // declare I/O region (256 bytes)
this->bars_cfg[2] = 0xFFFFF000UL; // declare register aperture (4KB)
this->finish_config_bars();
this->setup_bars({
{0, 0xFF000000UL}, // declare main aperture (16MB)
{1, 0xFFFFFF01UL}, // declare I/O region (256 bytes)
{2, 0xFFFFF000UL} // declare register aperture (4KB)
});
this->pci_notify_bar_change = [this](int bar_num) {
this->notify_bar_change(bar_num);

View File

@ -59,10 +59,12 @@ ControlVideo::ControlVideo()
this->vendor_id = PCI_VENDOR_APPLE;
this->device_id = 3;
this->class_rev = 0;
this->bars_cfg[0] = 0xFFFFFFFFUL; // I/O region (4 bytes but it's weird because bit 1 is set)
this->bars_cfg[1] = 0xFFFFF000UL; // base address for the HW registers (4KB)
this->bars_cfg[2] = 0xFC000000UL; // base address for the VRAM (64MB)
this->finish_config_bars();
this->setup_bars({
{0, 0xFFFFFFFFUL}, // I/O region (4 bytes but it's weird because bit 1 is set)
{1, 0xFFFFF000UL}, // base address for the HW registers (4KB)
{2, 0xFC000000UL} // base address for the VRAM (64MB)
});
this->pci_notify_bar_change = [this](int bar_num) {
this->notify_bar_change(bar_num);