mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-06-14 09:29:33 +00:00
Add PCI interrupt method.
A PCI device passes an interrupt to its host. The host will determine from the PCI device which interrupt to trigger.
This commit is contained in:
parent
be80595834
commit
6503a300cc
|
@ -70,6 +70,9 @@ enum {
|
||||||
*/
|
*/
|
||||||
class BanditHost : public PCIHost, public MMIODevice {
|
class BanditHost : public PCIHost, public MMIODevice {
|
||||||
public:
|
public:
|
||||||
|
// PCIHost methods
|
||||||
|
virtual void pci_interrupt(uint8_t irq_line_state, PCIBase *dev) {}
|
||||||
|
|
||||||
// MMIODevice methods
|
// MMIODevice methods
|
||||||
uint32_t read(uint32_t rgn_start, uint32_t offset, int size);
|
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);
|
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size);
|
||||||
|
|
|
@ -115,15 +115,20 @@ public:
|
||||||
|
|
||||||
virtual void set_host(PCIHost* host_instance) {
|
virtual void set_host(PCIHost* host_instance) {
|
||||||
this->host_instance = host_instance;
|
this->host_instance = host_instance;
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual void set_multi_function(bool is_multi_function) {
|
virtual void set_multi_function(bool is_multi_function) {
|
||||||
this->hdr_type = is_multi_function ? (this->hdr_type | 0x80) : (this->hdr_type & 0x7f);
|
this->hdr_type = is_multi_function ? (this->hdr_type | 0x80) : (this->hdr_type & 0x7f);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void set_irq_pin(uint8_t irq_pin) {
|
virtual void set_irq_pin(uint8_t irq_pin) {
|
||||||
this->irq_pin = irq_pin;
|
this->irq_pin = irq_pin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void pci_interrupt(uint8_t irq_line_state) {
|
||||||
|
this->host_instance->pci_interrupt(irq_line_state, this);
|
||||||
|
}
|
||||||
|
|
||||||
// MMIODevice methods
|
// MMIODevice methods
|
||||||
virtual uint32_t read(uint32_t rgn_start, uint32_t offset, int size) { return 0; }
|
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) { }
|
virtual void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) { }
|
||||||
|
|
|
@ -77,6 +77,7 @@ public:
|
||||||
|
|
||||||
virtual PCIBase *pci_find_device(uint8_t bus_num, uint8_t dev_num, uint8_t fun_num);
|
virtual PCIBase *pci_find_device(uint8_t bus_num, uint8_t dev_num, uint8_t fun_num);
|
||||||
|
|
||||||
|
virtual void pci_interrupt(uint8_t irq_line_state, PCIBase *dev) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unordered_map<int, PCIBase*> dev_map;
|
std::unordered_map<int, PCIBase*> dev_map;
|
||||||
|
|
|
@ -22,6 +22,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
/** MPC106 (Grackle) emulation. */
|
/** MPC106 (Grackle) emulation. */
|
||||||
|
|
||||||
#include <devices/common/hwcomponent.h>
|
#include <devices/common/hwcomponent.h>
|
||||||
|
#include <devices/common/hwinterrupt.h>
|
||||||
#include <devices/deviceregistry.h>
|
#include <devices/deviceregistry.h>
|
||||||
#include <devices/memctrl/memctrlbase.h>
|
#include <devices/memctrl/memctrlbase.h>
|
||||||
#include <devices/memctrl/mpc106.h>
|
#include <devices/memctrl/mpc106.h>
|
||||||
|
@ -68,9 +69,45 @@ int MPC106::device_postinit()
|
||||||
this->attach_pci_device(pci_dev_name, slot.second);
|
this->attach_pci_device(pci_dev_name, slot.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->int_ctrl = dynamic_cast<InterruptCtrl*>(
|
||||||
|
gMachineObj->get_comp_by_type(HWCompType::INT_CTRL));
|
||||||
|
this->irq_id_PCI_A = this->int_ctrl->register_dev_int(IntSrc::PCI_A );
|
||||||
|
this->irq_id_PCI_B = this->int_ctrl->register_dev_int(IntSrc::PCI_B );
|
||||||
|
this->irq_id_PCI_C = this->int_ctrl->register_dev_int(IntSrc::PCI_C );
|
||||||
|
this->irq_id_PCI_GPU = this->int_ctrl->register_dev_int(IntSrc::PCI_GPU );
|
||||||
|
this->irq_id_PCI_PERCH = this->int_ctrl->register_dev_int(IntSrc::PCI_PERCH);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MPC106::pci_interrupt(uint8_t irq_line_state, PCIBase *dev) {
|
||||||
|
auto it = std::find_if(dev_map.begin(), dev_map.end(),
|
||||||
|
[&dev](const std::pair<int, PCIBase*> &p) {
|
||||||
|
return p.second == dev;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (it == dev_map.end()) {
|
||||||
|
LOG_F(ERROR, "Interrupt from unknown device %s", dev->get_name().c_str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint32_t irq_id;
|
||||||
|
switch (it->first) {
|
||||||
|
case DEV_FUN(0x0C,0): irq_id = this->irq_id_PCI_PERCH; break;
|
||||||
|
case DEV_FUN(0x0D,0): irq_id = this->irq_id_PCI_A ; break;
|
||||||
|
case DEV_FUN(0x0E,0): irq_id = this->irq_id_PCI_B ; break;
|
||||||
|
case DEV_FUN(0x0F,0): irq_id = this->irq_id_PCI_C ; break;
|
||||||
|
case DEV_FUN(0x12,0): irq_id = this->irq_id_PCI_GPU ; break;
|
||||||
|
default:
|
||||||
|
LOG_F(ERROR, "Interrupt from device %s at unexpected device/function %02x.%x", dev->get_name().c_str(), it->first >> 3, it->first & 7);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this->int_ctrl)
|
||||||
|
this->int_ctrl->ack_int(irq_id, irq_line_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t MPC106::read(uint32_t rgn_start, uint32_t offset, int size) {
|
uint32_t MPC106::read(uint32_t rgn_start, uint32_t offset, int size) {
|
||||||
if (rgn_start == 0xFE000000) {
|
if (rgn_start == 0xFE000000) {
|
||||||
return pci_io_read_broadcast(offset, size);
|
return pci_io_read_broadcast(offset, size);
|
||||||
|
|
|
@ -36,11 +36,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include <devices/common/pci/pcidevice.h>
|
#include <devices/common/pci/pcidevice.h>
|
||||||
#include <devices/common/pci/pcihost.h>
|
#include <devices/common/pci/pcihost.h>
|
||||||
#include <devices/memctrl/memctrlbase.h>
|
#include <machines/machinebase.h>
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
class InterruptCtrl;
|
||||||
|
|
||||||
/** Grackle configuration space registers. */
|
/** Grackle configuration space registers. */
|
||||||
enum GrackleReg : uint32_t {
|
enum GrackleReg : uint32_t {
|
||||||
CFG10 = 0x40, // bus # + subordinate bus # + disconnect counter
|
CFG10 = 0x40, // bus # + subordinate bus # + disconnect counter
|
||||||
|
@ -79,6 +81,8 @@ public:
|
||||||
uint32_t read(uint32_t rgn_start, uint32_t offset, int size);
|
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);
|
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size);
|
||||||
|
|
||||||
|
virtual void pci_interrupt(uint8_t irq_line_state, PCIBase *dev);
|
||||||
|
|
||||||
int device_postinit();
|
int device_postinit();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -110,6 +114,14 @@ private:
|
||||||
uint32_t mem_end[2] = {};
|
uint32_t mem_end[2] = {};
|
||||||
uint32_t ext_mem_end[2] = {};
|
uint32_t ext_mem_end[2] = {};
|
||||||
uint8_t mem_bank_en = 0;
|
uint8_t mem_bank_en = 0;
|
||||||
|
|
||||||
|
// interrupt related stuff
|
||||||
|
InterruptCtrl* int_ctrl = nullptr;
|
||||||
|
uint32_t irq_id_PCI_A = 0;
|
||||||
|
uint32_t irq_id_PCI_B = 0;
|
||||||
|
uint32_t irq_id_PCI_C = 0;
|
||||||
|
uint32_t irq_id_PCI_GPU = 0;
|
||||||
|
uint32_t irq_id_PCI_PERCH = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MPC106_H
|
#endif // MPC106_H
|
||||||
|
|
Loading…
Reference in New Issue
Block a user