mpc106: rewrite control registers handling.
This commit is contained in:
parent
ec97a671d8
commit
99e92a5679
|
@ -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)
|
||||
|
@ -173,80 +173,120 @@ void MPC106::pci_write(uint32_t offset, uint32_t value, uint32_t size) {
|
|||
}
|
||||
|
||||
uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, AccessDetails &details) {
|
||||
#ifdef MPC106_DEBUG
|
||||
LOG_F(9, "read from Grackle register %08X", reg_offs);
|
||||
#endif
|
||||
|
||||
if (reg_offs < 64) {
|
||||
return PCIDevice::pci_cfg_read(reg_offs, details);
|
||||
}
|
||||
|
||||
uint32_t value = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[reg_offs]);
|
||||
if ((reg_offs >= 0x80 && reg_offs <= 0xA0) || reg_offs == 0xF0) {
|
||||
return value;
|
||||
switch (reg_offs) {
|
||||
case GrackleReg::CFG10:
|
||||
return 0;
|
||||
case GrackleReg::PMCR1:
|
||||
return (this->odcr << 24) | (this->pmcr2 << 16) | this->pmcr1;
|
||||
case GrackleReg::MBER:
|
||||
return this->mem_bank_en;
|
||||
case GrackleReg::PICR1:
|
||||
return this->picr1;
|
||||
case GrackleReg::PICR2:
|
||||
return this->picr2;
|
||||
case GrackleReg::MCCR1:
|
||||
return this->mccr1;
|
||||
default:
|
||||
LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER();
|
||||
}
|
||||
LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER_WITH_VALUE();
|
||||
return value;
|
||||
|
||||
return 0; // PCI Spec §6.1
|
||||
}
|
||||
|
||||
void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details) {
|
||||
#ifdef MPC106_DEBUG
|
||||
LOG_F(9, "write %08X to Grackle register %08X", value, reg_offs);
|
||||
#endif
|
||||
|
||||
if (reg_offs < 64) {
|
||||
PCIDevice::pci_cfg_write(reg_offs, value, details);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: implement write-protection for read-only registers
|
||||
|
||||
uint32_t *addr = (uint32_t *)&this->my_pci_cfg_hdr[reg_offs];
|
||||
WRITE_DWORD_LE_A(addr, value);
|
||||
|
||||
if ((reg_offs >= 0x80 && reg_offs <= 0xA0) || reg_offs == 0xF0) {
|
||||
if (this->my_pci_cfg_hdr[0xF2] & 8) {
|
||||
#ifdef MPC106_DEBUG
|
||||
LOG_F(9, "MPC106: MCCR1[MEMGO] was set!");
|
||||
#endif
|
||||
setup_ram();
|
||||
switch (reg_offs) {
|
||||
case GrackleReg::CFG10:
|
||||
// Open Firmware writes 0 to subordinate bus # - we don't care
|
||||
break;
|
||||
case GrackleReg::PMCR1:
|
||||
this->pmcr1 = value & 0xFFFFU;
|
||||
this->pmcr2 = (value >> 16) & 0xFF;
|
||||
this->odcr = value >> 24;
|
||||
break;
|
||||
case GrackleReg::MSAR1:
|
||||
case GrackleReg::MSAR2:
|
||||
this->mem_start[(reg_offs >> 2) & 1] = value;
|
||||
break;
|
||||
case GrackleReg::EMSAR1:
|
||||
case GrackleReg::EMSAR2:
|
||||
this->ext_mem_start[(reg_offs >> 2) & 1] = value;
|
||||
break;
|
||||
case GrackleReg::MEAR1:
|
||||
case GrackleReg::MEAR2:
|
||||
this->mem_end[(reg_offs >> 2) & 1] = value;
|
||||
break;
|
||||
case GrackleReg::EMEAR1:
|
||||
case GrackleReg::EMEAR2:
|
||||
this->ext_mem_end[(reg_offs >> 2) & 1] = value;
|
||||
break;
|
||||
case GrackleReg::MBER:
|
||||
this->mem_bank_en = value & 0xFFU;
|
||||
break;
|
||||
case GrackleReg::PICR1:
|
||||
this->picr1 = value;
|
||||
break;
|
||||
case GrackleReg::PICR2:
|
||||
this->picr2 = value;
|
||||
break;
|
||||
case GrackleReg::MCCR1:
|
||||
if ((value ^ this->mccr1) & MEMGO) {
|
||||
if (value & MEMGO)
|
||||
setup_ram();
|
||||
}
|
||||
return;
|
||||
this->mccr1 = value;
|
||||
break;
|
||||
case GrackleReg::MCCR2:
|
||||
this->mccr2 = value;
|
||||
break;
|
||||
case GrackleReg::MCCR3:
|
||||
this->mccr3 = value;
|
||||
break;
|
||||
case GrackleReg::MCCR4:
|
||||
this->mccr4 = value;
|
||||
break;
|
||||
default:
|
||||
LOG_WRITE_UNIMPLEMENTED_CONFIG_REGISTER();
|
||||
}
|
||||
LOG_WRITE_UNIMPLEMENTED_CONFIG_REGISTER();
|
||||
}
|
||||
|
||||
void MPC106::setup_ram() {
|
||||
uint32_t mem_start, mem_end, ext_mem_start, ext_mem_end, bank_start, bank_end;
|
||||
uint32_t ram_size = 0;
|
||||
|
||||
uint8_t bank_en = this->my_pci_cfg_hdr[0xA0];
|
||||
|
||||
for (int bank = 0; bank < 8; bank++) {
|
||||
if (bank_en & (1 << bank)) {
|
||||
if (this->mem_bank_en & (1 << bank)) {
|
||||
if (bank < 4) {
|
||||
mem_start = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x80]);
|
||||
ext_mem_start = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x88]);
|
||||
mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x90]);
|
||||
ext_mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x98]);
|
||||
mem_start = this->mem_start[0];
|
||||
ext_mem_start = this->ext_mem_start[0];
|
||||
mem_end = this->mem_end[0];
|
||||
ext_mem_end = this->ext_mem_end[0];
|
||||
} else {
|
||||
mem_start = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x84]);
|
||||
ext_mem_start = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x8C]);
|
||||
mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x94]);
|
||||
ext_mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x9C]);
|
||||
mem_start = this->mem_start[1];
|
||||
ext_mem_start = this->ext_mem_start[1];
|
||||
mem_end = this->mem_end[1];
|
||||
ext_mem_end = this->ext_mem_end[1];
|
||||
}
|
||||
bank_start = (((ext_mem_start >> bank * 8) & 3) << 30) |
|
||||
(((mem_start >> bank * 8) & 0xFF) << 20);
|
||||
bank_end = (((ext_mem_end >> bank * 8) & 3) << 30) |
|
||||
(((mem_end >> bank * 8) & 0xFF) << 20) | 0xFFFFFUL;
|
||||
if (bank && bank_start != ram_size)
|
||||
LOG_F(WARNING, "MPC106: RAM not contiguous!");
|
||||
LOG_F(WARNING, "Grackle: RAM not contiguous!");
|
||||
ram_size += bank_end - bank_start + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->add_ram_region(0, ram_size)) {
|
||||
LOG_F(WARNING, "MPC106 RAM allocation 0x%X..0x%X failed (maybe already exists?)",
|
||||
LOG_F(WARNING, "Grackle: RAM allocation 0x%X..0x%X failed (maybe already exists?)",
|
||||
0, ram_size - 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** MPC106 (Grackle) emulation
|
||||
/** MPC106 (Grackle) definitions.
|
||||
|
||||
Grackle IC is a combined memory and PCI controller manufactured by Motorola.
|
||||
It's the central device in the Gossamer architecture.
|
||||
|
@ -31,8 +31,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
- our virtual device reports revision 4.0 as expected by machine firmware
|
||||
*/
|
||||
|
||||
#ifndef MPC106_H_
|
||||
#define MPC106_H_
|
||||
#ifndef MPC106_H
|
||||
#define MPC106_H
|
||||
|
||||
#include <devices/common/mmiodevice.h>
|
||||
#include <devices/common/pci/pcidevice.h>
|
||||
|
@ -43,6 +43,32 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
/** Grackle configuration space registers. */
|
||||
enum GrackleReg : uint32_t {
|
||||
CFG10 = 0x40, // bus # + subordinate bus # + disconnect counter
|
||||
PMCR1 = 0x70, // power management config 1
|
||||
MSAR1 = 0x80, // memory starting address 1
|
||||
MSAR2 = 0x84, // memory starting address 2
|
||||
EMSAR1 = 0x88, // extended memory starting address 1
|
||||
EMSAR2 = 0x8C, // extended memory starting address 2
|
||||
MEAR1 = 0x90, // memory ending address 1
|
||||
MEAR2 = 0x94, // memory ending address 2
|
||||
EMEAR1 = 0x98, // extended memory ending address 1
|
||||
EMEAR2 = 0x9C, // extended memory ending address 2
|
||||
MBER = 0xA0, // memory bank enable
|
||||
PICR1 = 0xA8, // processor interface configuration 1
|
||||
PICR2 = 0xAC, // processor interface configuration 2
|
||||
MCCR1 = 0xF0, // memory control configuration 1
|
||||
MCCR2 = 0xF4, // memory control configuration 2
|
||||
MCCR3 = 0xF8, // memory control configuration 3
|
||||
MCCR4 = 0xFC // memory control configuration 4
|
||||
};
|
||||
|
||||
/* MCCR1 bit definitions. */
|
||||
enum {
|
||||
MEMGO = 1 << 19,
|
||||
};
|
||||
|
||||
class MPC106 : public MemCtrlBase, public PCIDevice, public PCIHost {
|
||||
public:
|
||||
MPC106();
|
||||
|
@ -74,92 +100,23 @@ protected:
|
|||
void setup_ram(void);
|
||||
|
||||
private:
|
||||
uint8_t my_pci_cfg_hdr[256] = {
|
||||
0x57, 0x10, // vendor ID: Motorola
|
||||
0x02, 0x00, // device ID: MPC106
|
||||
0x06, 0x00, // PCI command
|
||||
0x80, 0x00, // PCI status
|
||||
0x40, // revision ID: 4.0
|
||||
0x00, // standard programming
|
||||
0x00, // subclass code: host bridge
|
||||
0x06, // class code: bridge device
|
||||
0x08, // cache line size
|
||||
0x00, // latency timer
|
||||
0x00, // header type
|
||||
0x00, // BIST Control
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, // Interrupt line
|
||||
0x00, // Interrupt pin
|
||||
0x00, // MIN GNT
|
||||
0x00, // MAX LAT
|
||||
0x00, // Bus number
|
||||
0x00, // Subordinate bus number
|
||||
0x00, // Discount counter
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // Performance monitor command
|
||||
0x00, 0x00, // Performance monitor mode control
|
||||
0xFF, 0xFF,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 0
|
||||
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 1
|
||||
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 2
|
||||
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 3
|
||||
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF,
|
||||
|
||||
0x00, 0x00, // Power mgt config 1
|
||||
0x00, // Power mgt config 2
|
||||
0xCD, // default value for ODCR
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, // Memory Starting Address
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Extended Memory Starting Address
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Memory Ending Address
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Extended Memory Ending Address
|
||||
|
||||
0x00, // Memory bank enable
|
||||
0xFF, 0xFF,
|
||||
0x00, // Memory page mode
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
|
||||
0x10, 0x00, 0x00, 0xFF, // PICR1
|
||||
0x0C, 0x06, 0x0C, 0x00, // PICR2
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, // ECC single-bit error counter
|
||||
0x00, // ECC single-bit error trigger
|
||||
0x04, // Alternate OS visible paramaters 1
|
||||
0x01, // Alternate OS visible paramaters 2
|
||||
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
|
||||
0x01, // Error enabling 1
|
||||
0x00, // Error detection 1
|
||||
0xFF,
|
||||
0x00, // 60x bus error status
|
||||
0x00, // Error enabling 2
|
||||
0x00, // Error detection 2
|
||||
0xFF,
|
||||
0x00, // PCI bus error status
|
||||
0x00, 0x00, 0x00, 0x00, // 60x/PCI ERROR address
|
||||
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF,
|
||||
|
||||
0x42, 0x00, 0xFF, 0x0F, // Emulation support config 1
|
||||
0x00, 0x00, 0x00, 0x00, // Modified memory status (no clear)
|
||||
0x20, 0x00, 0x00, 0x00, // Emulation support config 2
|
||||
0x00, 0x00, 0x00, 0x00, // Modified memory status (clear)
|
||||
|
||||
0x00, 0x00, 0x02, 0xFF, // Memory ctrl config 1
|
||||
0x03, 0x00, 0x00, 0x00, // Memory ctrl config 2
|
||||
0x00, 0x00, 0x00, 0x00, // Memory ctrl config 3
|
||||
0x00, 0x00, 0x10, 0x00 // Memory ctrl config 4
|
||||
};
|
||||
|
||||
uint32_t config_addr;
|
||||
|
||||
uint16_t pmcr1 = 0; // power management config 1
|
||||
uint8_t pmcr2 = 0; // power management config 2
|
||||
uint8_t odcr = 0xCD; // output driver control
|
||||
uint32_t picr1 = 0xFF100010; // ROM on CPU bus, address map B, CPU type = MPC601
|
||||
uint32_t picr2 = 0x000C060C;
|
||||
uint32_t mccr1 = 0xFF820000; // 64bit ROM bus
|
||||
uint32_t mccr2 = 3;
|
||||
uint32_t mccr3 = 0;
|
||||
uint32_t mccr4 = 0x00100000;
|
||||
|
||||
uint32_t mem_start[2] = {};
|
||||
uint32_t ext_mem_start[2] = {};
|
||||
uint32_t mem_end[2] = {};
|
||||
uint32_t ext_mem_end[2] = {};
|
||||
uint8_t mem_bank_en = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // MPC106_H
|
||||
|
|
Loading…
Reference in New Issue