mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-24 12:30:05 +00:00
MPC106: add support for PCI devices.
This commit is contained in:
parent
78e8b06cf1
commit
af5a096532
@ -16,20 +16,20 @@
|
|||||||
|
|
||||||
#include "memctrlbase.h"
|
#include "memctrlbase.h"
|
||||||
#include "mmiodevice.h"
|
#include "mmiodevice.h"
|
||||||
#include "../viacuda.h"
|
|
||||||
#include "mpc106.h"
|
#include "mpc106.h"
|
||||||
#include "../ppcemumain.h"
|
|
||||||
#include "../ppcmemory.h"
|
|
||||||
|
|
||||||
|
|
||||||
MPC106::MPC106() : MemCtrlBase("Grackle")
|
MPC106::MPC106() : MemCtrlBase("Grackle"), PCIDevice("Grackle PCI host bridge")
|
||||||
{
|
{
|
||||||
/* add memory mapped I/O region for MPC106 registers */
|
/* add memory mapped I/O region for MPC106 registers */
|
||||||
add_mmio_region(0xFEC00000, 0x300000, this);
|
add_mmio_region(0xFEC00000, 0x300000, this);
|
||||||
|
|
||||||
|
this->pci_0_bus.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
MPC106::~MPC106()
|
MPC106::~MPC106()
|
||||||
{
|
{
|
||||||
|
this->pci_0_bus.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MPC106::read(uint32_t offset, int size)
|
uint32_t MPC106::read(uint32_t offset, int size)
|
||||||
@ -56,7 +56,7 @@ void MPC106::write(uint32_t offset, uint32_t value, int size)
|
|||||||
|
|
||||||
uint32_t MPC106::pci_read(uint32_t size)
|
uint32_t MPC106::pci_read(uint32_t size)
|
||||||
{
|
{
|
||||||
int bus_num, dev_num, fun_num, reg_num;
|
int bus_num, dev_num, fun_num, reg_offs;
|
||||||
|
|
||||||
bus_num = (this->config_addr >> 8) & 0xFF;
|
bus_num = (this->config_addr >> 8) & 0xFF;
|
||||||
if (bus_num) {
|
if (bus_num) {
|
||||||
@ -65,16 +65,20 @@ uint32_t MPC106::pci_read(uint32_t size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_num = (this->config_addr >> 19) & 0x1F;
|
dev_num = (this->config_addr >> 19) & 0x1F;
|
||||||
fun_num = (this->config_addr >> 16) & 0x07;
|
fun_num = (this->config_addr >> 16) & 0x07;
|
||||||
reg_num = (this->config_addr >> 24) & 0xFC;
|
reg_offs = (this->config_addr >> 24) & 0xFC;
|
||||||
|
|
||||||
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
|
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
|
||||||
return myself_read(reg_num, size);
|
return this->pci_cfg_read(reg_offs, size);
|
||||||
} else {
|
} else {
|
||||||
std::cout << this->name << " err: reading from device " << dev_num
|
if (this->pci_0_bus.count(dev_num)) {
|
||||||
<< " not supported yet" << std::endl;
|
return this->pci_0_bus[dev_num]->pci_cfg_read(reg_offs, size);
|
||||||
return 0;
|
} else {
|
||||||
|
std::cout << this->name << " err: read attempt from non-existing PCI device "
|
||||||
|
<< dev_num << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -82,7 +86,7 @@ uint32_t MPC106::pci_read(uint32_t size)
|
|||||||
|
|
||||||
void MPC106::pci_write(uint32_t value, uint32_t size)
|
void MPC106::pci_write(uint32_t value, uint32_t size)
|
||||||
{
|
{
|
||||||
int bus_num, dev_num, fun_num, reg_num;
|
int bus_num, dev_num, fun_num, reg_offs;
|
||||||
|
|
||||||
bus_num = (this->config_addr >> 8) & 0xFF;
|
bus_num = (this->config_addr >> 8) & 0xFF;
|
||||||
if (bus_num) {
|
if (bus_num) {
|
||||||
@ -91,33 +95,37 @@ void MPC106::pci_write(uint32_t value, uint32_t size)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_num = (this->config_addr >> 19) & 0x1F;
|
dev_num = (this->config_addr >> 19) & 0x1F;
|
||||||
fun_num = (this->config_addr >> 16) & 0x07;
|
fun_num = (this->config_addr >> 16) & 0x07;
|
||||||
reg_num = (this->config_addr >> 24) & 0xFC;
|
reg_offs = (this->config_addr >> 24) & 0xFC;
|
||||||
|
|
||||||
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
|
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
|
||||||
myself_write(reg_num, value, size);
|
this->pci_cfg_write(reg_offs, value, size);
|
||||||
} else {
|
} else {
|
||||||
std::cout << this->name << " err: writing to device " << dev_num
|
if (this->pci_0_bus.count(dev_num)) {
|
||||||
<< " not supported yet" << std::endl;
|
this->pci_0_bus[dev_num]->pci_cfg_write(reg_offs, value, size);
|
||||||
|
} else {
|
||||||
|
std::cout << this->name << " err: write attempt to non-existing PCI device "
|
||||||
|
<< dev_num << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MPC106::myself_read(int reg_num, uint32_t size)
|
uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, uint32_t size)
|
||||||
{
|
{
|
||||||
#ifdef MPC106_DEBUG
|
#ifdef MPC106_DEBUG
|
||||||
printf("read from Grackle register %08X\n", reg_num);
|
printf("read from Grackle register %08X\n", reg_offs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch(size) {
|
switch(size) {
|
||||||
case 1:
|
case 1:
|
||||||
return this->my_pci_cfg_hdr[reg_num];
|
return this->my_pci_cfg_hdr[reg_offs];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
return READ_WORD_BE(&this->my_pci_cfg_hdr[reg_num]);
|
return READ_WORD_BE(&this->my_pci_cfg_hdr[reg_offs]);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
return READ_DWORD_BE(&this->my_pci_cfg_hdr[reg_num]);
|
return READ_DWORD_BE(&this->my_pci_cfg_hdr[reg_offs]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
std::cout << "MPC106 read error: invalid size parameter " << size
|
std::cout << "MPC106 read error: invalid size parameter " << size
|
||||||
@ -127,29 +135,47 @@ uint32_t MPC106::myself_read(int reg_num, uint32_t size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPC106::myself_write(int reg_num, uint32_t value, uint32_t size)
|
void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
|
||||||
{
|
{
|
||||||
#ifdef MPC106_DEBUG
|
#ifdef MPC106_DEBUG
|
||||||
printf("write %08X to Grackle register %08X\n", value, reg_num);
|
printf("write %08X to Grackle register %08X\n", value, reg_offs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// FIXME: implement write-protection for read-only registers
|
// FIXME: implement write-protection for read-only registers
|
||||||
switch(size) {
|
switch(size) {
|
||||||
case 1:
|
case 1:
|
||||||
this->my_pci_cfg_hdr[reg_num] = value & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs] = value & 0xFF;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
this->my_pci_cfg_hdr[reg_num] = (value >> 8) & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs] = (value >> 8) & 0xFF;
|
||||||
this->my_pci_cfg_hdr[reg_num+1] = value & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs+1] = value & 0xFF;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
this->my_pci_cfg_hdr[reg_num] = (value >> 24) & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs] = (value >> 24) & 0xFF;
|
||||||
this->my_pci_cfg_hdr[reg_num+1] = (value >> 16) & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs+1] = (value >> 16) & 0xFF;
|
||||||
this->my_pci_cfg_hdr[reg_num+2] = (value >> 8) & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs+2] = (value >> 8) & 0xFF;
|
||||||
this->my_pci_cfg_hdr[reg_num+3] = value & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs+3] = value & 0xFF;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
std::cout << "MPC106 read error: invalid size parameter " << size
|
std::cout << "MPC106 read error: invalid size parameter " << size
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MPC106::pci_register_device(int dev_num, PCIDevice *dev_instance)
|
||||||
|
{
|
||||||
|
if (this->pci_0_bus.count(dev_num)) // is dev_num already registered?
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->pci_0_bus[dev_num] = dev_instance;
|
||||||
|
|
||||||
|
dev_instance->set_host(this);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MPC106::pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice *obj)
|
||||||
|
{
|
||||||
|
// FIXME: add sanity checks!
|
||||||
|
return this->add_mmio_region(start_addr, size, obj);
|
||||||
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
Author: Max Poliakovski
|
Author: Max Poliakovski
|
||||||
|
|
||||||
Grackle IC is a combined memory and PCI controller manufactored by Motorola.
|
Grackle IC is a combined memory and PCI controller manufactured by Motorola.
|
||||||
It's the central device in the Gossamer architecture.
|
It's the central device in the Gossamer architecture.
|
||||||
Manual: https://www.nxp.com/docs/en/reference-manual/MPC106UM.pdf
|
Manual: https://www.nxp.com/docs/en/reference-manual/MPC106UM.pdf
|
||||||
|
|
||||||
@ -23,11 +23,14 @@
|
|||||||
#define MPC106_H_
|
#define MPC106_H_
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <unordered_map>
|
||||||
#include "memctrlbase.h"
|
#include "memctrlbase.h"
|
||||||
#include "mmiodevice.h"
|
#include "mmiodevice.h"
|
||||||
|
#include "pcidevice.h"
|
||||||
|
#include "pcihost.h"
|
||||||
|
|
||||||
|
|
||||||
class MPC106 : public MemCtrlBase, public MMIODevice
|
class MPC106 : public MemCtrlBase, public PCIDevice, public PCIHost
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using MemCtrlBase::name;
|
using MemCtrlBase::name;
|
||||||
@ -37,14 +40,23 @@ public:
|
|||||||
uint32_t read(uint32_t offset, int size);
|
uint32_t read(uint32_t offset, int size);
|
||||||
void write(uint32_t offset, uint32_t value, int size);
|
void write(uint32_t offset, uint32_t value, int size);
|
||||||
|
|
||||||
|
/* PCI host bridge API */
|
||||||
|
bool pci_register_device(int dev_num, PCIDevice *dev_instance);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* PCI access */
|
/* PCI access */
|
||||||
uint32_t pci_read(uint32_t size);
|
uint32_t pci_read(uint32_t size);
|
||||||
void pci_write(uint32_t value, uint32_t size);
|
void pci_write(uint32_t value, uint32_t size);
|
||||||
|
|
||||||
/* my own registers access */
|
/* my own PCI configuration registers access */
|
||||||
uint32_t myself_read(int reg_num, uint32_t size);
|
uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size);
|
||||||
void myself_write(int reg_num, uint32_t value, uint32_t size);
|
void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size);
|
||||||
|
|
||||||
|
void set_host(PCIHost *host_instance) {}; // unimplemented for now
|
||||||
|
|
||||||
|
/* PCI host bridge API */
|
||||||
|
//bool pci_register_device(int dev_num, PCIDevice *dev_instance);
|
||||||
|
bool pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice *obj);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t my_pci_cfg_hdr[256] = {
|
uint8_t my_pci_cfg_hdr[256] = {
|
||||||
@ -54,8 +66,8 @@ private:
|
|||||||
0x80, 0x00, // PCI status
|
0x80, 0x00, // PCI status
|
||||||
0x40, // revision ID: 4.0
|
0x40, // revision ID: 4.0
|
||||||
0x00, // standard programming
|
0x00, // standard programming
|
||||||
0x00, // subclass code
|
0x00, // subclass code: host bridge
|
||||||
0x06, // class code
|
0x06, // class code: bridge device
|
||||||
[0x73] = 0xCD, // default value for ODCR
|
[0x73] = 0xCD, // default value for ODCR
|
||||||
[0xA8] = 0x10, 0x00, 0x00, 0xFF, // PICR1
|
[0xA8] = 0x10, 0x00, 0x00, 0xFF, // PICR1
|
||||||
[0xAC] = 0x0C, 0x06, 0x0C, 0x00, // PICR2
|
[0xAC] = 0x0C, 0x06, 0x0C, 0x00, // PICR2
|
||||||
@ -70,6 +82,8 @@ private:
|
|||||||
|
|
||||||
uint32_t config_addr;
|
uint32_t config_addr;
|
||||||
//uint32_t config_data;
|
//uint32_t config_data;
|
||||||
|
|
||||||
|
std::unordered_map<int, PCIDevice*> pci_0_bus;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user