2019-07-02 02:15:33 +00:00
|
|
|
//DingusPPC - Prototype 5bf2
|
|
|
|
//Written by divingkatae
|
|
|
|
//(c)2018-20 (theweirdo)
|
|
|
|
//Please ask for permission
|
|
|
|
//if you want to distribute this.
|
|
|
|
//(divingkatae#1017 on Discord)
|
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
/** MPC106 (Grackle) emulation
|
|
|
|
|
|
|
|
Author: Max Poliakovski
|
|
|
|
*/
|
2019-07-02 02:15:33 +00:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cinttypes>
|
2019-08-21 06:33:01 +00:00
|
|
|
|
|
|
|
#include "memctrlbase.h"
|
|
|
|
#include "mmiodevice.h"
|
2019-07-02 02:15:33 +00:00
|
|
|
#include "mpc106.h"
|
|
|
|
|
2019-07-15 00:05:10 +00:00
|
|
|
|
2019-08-23 19:30:30 +00:00
|
|
|
MPC106::MPC106() : MemCtrlBase("Grackle"), PCIDevice("Grackle PCI host bridge")
|
2019-07-15 00:05:10 +00:00
|
|
|
{
|
2019-08-21 06:33:01 +00:00
|
|
|
/* add memory mapped I/O region for MPC106 registers */
|
|
|
|
add_mmio_region(0xFEC00000, 0x300000, this);
|
2019-08-23 19:30:30 +00:00
|
|
|
|
|
|
|
this->pci_0_bus.clear();
|
2019-07-02 02:15:33 +00:00
|
|
|
}
|
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
MPC106::~MPC106()
|
|
|
|
{
|
2019-08-23 19:30:30 +00:00
|
|
|
this->pci_0_bus.clear();
|
2019-08-21 06:33:01 +00:00
|
|
|
}
|
2019-07-12 05:27:14 +00:00
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
uint32_t MPC106::read(uint32_t offset, int size)
|
|
|
|
{
|
|
|
|
if (offset >= 0x200000) {
|
|
|
|
if (this->config_addr & 0x80) // process only if bit E (enable) is set
|
|
|
|
return pci_read(size);
|
2019-07-07 06:10:32 +00:00
|
|
|
}
|
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
/* FIXME: reading from CONFIG_ADDR is ignored for now */
|
|
|
|
|
2019-07-07 06:10:32 +00:00
|
|
|
return 0;
|
2019-07-02 02:15:33 +00:00
|
|
|
}
|
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
void MPC106::write(uint32_t offset, uint32_t value, int size)
|
|
|
|
{
|
|
|
|
if (offset < 0x200000) {
|
|
|
|
this->config_addr = value;
|
|
|
|
} else {
|
|
|
|
if (this->config_addr & 0x80) // process only if bit E (enable) is set
|
|
|
|
return pci_write(value, size);
|
2019-07-07 06:10:32 +00:00
|
|
|
}
|
2019-07-15 00:05:10 +00:00
|
|
|
}
|
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
uint32_t MPC106::pci_read(uint32_t size)
|
|
|
|
{
|
2019-08-23 19:30:30 +00:00
|
|
|
int bus_num, dev_num, fun_num, reg_offs;
|
2019-07-15 00:05:10 +00:00
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
bus_num = (this->config_addr >> 8) & 0xFF;
|
|
|
|
if (bus_num) {
|
|
|
|
std::cout << this->name << " err: read attempt from non-local PCI bus, "
|
|
|
|
<< "config_addr = " << std::hex << this->config_addr << std::endl;
|
|
|
|
return 0;
|
|
|
|
}
|
2019-07-15 00:05:10 +00:00
|
|
|
|
2019-08-23 19:30:30 +00:00
|
|
|
dev_num = (this->config_addr >> 19) & 0x1F;
|
|
|
|
fun_num = (this->config_addr >> 16) & 0x07;
|
|
|
|
reg_offs = (this->config_addr >> 24) & 0xFC;
|
2019-07-15 00:05:10 +00:00
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
|
2019-08-23 19:30:30 +00:00
|
|
|
return this->pci_cfg_read(reg_offs, size);
|
2019-08-21 06:33:01 +00:00
|
|
|
} else {
|
2019-08-23 19:30:30 +00:00
|
|
|
if (this->pci_0_bus.count(dev_num)) {
|
|
|
|
return this->pci_0_bus[dev_num]->pci_cfg_read(reg_offs, size);
|
|
|
|
} else {
|
|
|
|
std::cout << this->name << " err: read attempt from non-existing PCI device "
|
|
|
|
<< dev_num << std::endl;
|
|
|
|
return 0;
|
|
|
|
}
|
2019-08-21 06:33:01 +00:00
|
|
|
}
|
2019-07-15 00:05:10 +00:00
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
return 0;
|
2019-07-15 00:05:10 +00:00
|
|
|
}
|
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
void MPC106::pci_write(uint32_t value, uint32_t size)
|
|
|
|
{
|
2019-08-23 19:30:30 +00:00
|
|
|
int bus_num, dev_num, fun_num, reg_offs;
|
2019-07-15 00:05:10 +00:00
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
bus_num = (this->config_addr >> 8) & 0xFF;
|
|
|
|
if (bus_num) {
|
|
|
|
std::cout << this->name << " err: write attempt to non-local PCI bus, "
|
|
|
|
<< "config_addr = " << std::hex << this->config_addr << std::endl;
|
|
|
|
return;
|
2019-07-15 00:05:10 +00:00
|
|
|
}
|
2019-07-02 02:15:33 +00:00
|
|
|
|
2019-08-23 19:30:30 +00:00
|
|
|
dev_num = (this->config_addr >> 19) & 0x1F;
|
|
|
|
fun_num = (this->config_addr >> 16) & 0x07;
|
|
|
|
reg_offs = (this->config_addr >> 24) & 0xFC;
|
2019-07-02 02:15:33 +00:00
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
|
2019-08-23 19:30:30 +00:00
|
|
|
this->pci_cfg_write(reg_offs, value, size);
|
2019-08-21 06:33:01 +00:00
|
|
|
} else {
|
2019-08-23 19:30:30 +00:00
|
|
|
if (this->pci_0_bus.count(dev_num)) {
|
|
|
|
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;
|
|
|
|
}
|
2019-08-21 06:33:01 +00:00
|
|
|
}
|
2019-07-02 02:15:33 +00:00
|
|
|
}
|
|
|
|
|
2019-08-23 19:30:30 +00:00
|
|
|
uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, uint32_t size)
|
2019-08-21 06:33:01 +00:00
|
|
|
{
|
|
|
|
#ifdef MPC106_DEBUG
|
2019-08-23 19:30:30 +00:00
|
|
|
printf("read from Grackle register %08X\n", reg_offs);
|
2019-08-21 06:33:01 +00:00
|
|
|
#endif
|
2019-07-02 02:15:33 +00:00
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
switch(size) {
|
|
|
|
case 1:
|
2019-08-23 19:30:30 +00:00
|
|
|
return this->my_pci_cfg_hdr[reg_offs];
|
2019-08-21 06:33:01 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2019-08-23 19:30:30 +00:00
|
|
|
return READ_WORD_BE(&this->my_pci_cfg_hdr[reg_offs]);
|
2019-08-21 06:33:01 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2019-08-23 19:30:30 +00:00
|
|
|
return READ_DWORD_BE(&this->my_pci_cfg_hdr[reg_offs]);
|
2019-08-21 06:33:01 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
std::cout << "MPC106 read error: invalid size parameter " << size
|
|
|
|
<< std::endl;
|
2019-07-15 00:05:10 +00:00
|
|
|
}
|
|
|
|
|
2019-08-21 06:33:01 +00:00
|
|
|
return 0;
|
2019-07-15 00:05:10 +00:00
|
|
|
}
|
|
|
|
|
2019-08-23 19:30:30 +00:00
|
|
|
void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
|
2019-08-21 06:33:01 +00:00
|
|
|
{
|
|
|
|
#ifdef MPC106_DEBUG
|
2019-08-23 19:30:30 +00:00
|
|
|
printf("write %08X to Grackle register %08X\n", value, reg_offs);
|
2019-08-21 06:33:01 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// FIXME: implement write-protection for read-only registers
|
|
|
|
switch(size) {
|
|
|
|
case 1:
|
2019-08-23 19:30:30 +00:00
|
|
|
this->my_pci_cfg_hdr[reg_offs] = value & 0xFF;
|
2019-08-21 06:33:01 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2019-08-23 19:30:30 +00:00
|
|
|
this->my_pci_cfg_hdr[reg_offs] = (value >> 8) & 0xFF;
|
|
|
|
this->my_pci_cfg_hdr[reg_offs+1] = value & 0xFF;
|
2019-08-21 06:33:01 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2019-08-23 19:30:30 +00:00
|
|
|
this->my_pci_cfg_hdr[reg_offs] = (value >> 24) & 0xFF;
|
|
|
|
this->my_pci_cfg_hdr[reg_offs+1] = (value >> 16) & 0xFF;
|
|
|
|
this->my_pci_cfg_hdr[reg_offs+2] = (value >> 8) & 0xFF;
|
|
|
|
this->my_pci_cfg_hdr[reg_offs+3] = value & 0xFF;
|
2019-08-21 06:33:01 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
std::cout << "MPC106 read error: invalid size parameter " << size
|
|
|
|
<< std::endl;
|
2019-07-02 02:15:33 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-23 19:30:30 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|