mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-26 09:29:28 +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 {
|
||||
public:
|
||||
// PCIHost methods
|
||||
virtual void pci_interrupt(uint8_t irq_line_state, PCIBase *dev) {}
|
||||
|
||||
// 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);
|
||||
|
@ -115,15 +115,20 @@ public:
|
||||
|
||||
virtual void set_host(PCIHost* host_instance) {
|
||||
this->host_instance = host_instance;
|
||||
};
|
||||
}
|
||||
|
||||
virtual void set_multi_function(bool is_multi_function) {
|
||||
this->hdr_type = is_multi_function ? (this->hdr_type | 0x80) : (this->hdr_type & 0x7f);
|
||||
}
|
||||
|
||||
virtual void set_irq_pin(uint8_t 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
|
||||
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) { }
|
||||
|
@ -77,6 +77,7 @@ public:
|
||||
|
||||
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:
|
||||
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. */
|
||||
|
||||
#include <devices/common/hwcomponent.h>
|
||||
#include <devices/common/hwinterrupt.h>
|
||||
#include <devices/deviceregistry.h>
|
||||
#include <devices/memctrl/memctrlbase.h>
|
||||
#include <devices/memctrl/mpc106.h>
|
||||
@ -68,9 +69,45 @@ int MPC106::device_postinit()
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (rgn_start == 0xFE000000) {
|
||||
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/pcihost.h>
|
||||
#include <devices/memctrl/memctrlbase.h>
|
||||
#include <machines/machinebase.h>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
|
||||
class InterruptCtrl;
|
||||
|
||||
/** Grackle configuration space registers. */
|
||||
enum GrackleReg : uint32_t {
|
||||
CFG10 = 0x40, // bus # + subordinate bus # + disconnect counter
|
||||
@ -79,6 +81,8 @@ public:
|
||||
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);
|
||||
|
||||
virtual void pci_interrupt(uint8_t irq_line_state, PCIBase *dev);
|
||||
|
||||
int device_postinit();
|
||||
|
||||
protected:
|
||||
@ -110,6 +114,14 @@ private:
|
||||
uint32_t mem_end[2] = {};
|
||||
uint32_t ext_mem_end[2] = {};
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user