diff --git a/devices/memctrl/mpc106.cpp b/devices/memctrl/mpc106.cpp
index 5f7c7c0..aaf6439 100644
--- a/devices/memctrl/mpc106.cpp
+++ b/devices/memctrl/mpc106.cpp
@@ -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);
}
}
diff --git a/devices/memctrl/mpc106.h b/devices/memctrl/mpc106.h
index c338d6c..640eb57 100644
--- a/devices/memctrl/mpc106.h
+++ b/devices/memctrl/mpc106.h
@@ -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 .
*/
-/** 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 .
- 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
#include
@@ -43,6 +43,32 @@ along with this program. If not, see .
#include
#include
+/** 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