diff --git a/core/bitops.h b/core/bitops.h new file mode 100644 index 0000000..d43fa76 --- /dev/null +++ b/core/bitops.h @@ -0,0 +1,59 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-23 divingkatae and maximum + (theweirdo) spatium + +(Contact divingkatae#1017 or powermax#2286 on Discord for more info) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +/** Non-standard low-level bitwise operations. */ + +#ifndef BIT_OPS_H +#define BIT_OPS_H + +#if defined(__GNUG__) && !defined(__clang__) // GCC, mybe ICC but not Clang + +# include + +# define ROTL_32(x, n) (_rotl((x), (n))) +# define ROTR_32(x, n) (_rotr((x), (n))) + +#elif defined(_MSC_VER) // MSVC + +# include + +# define ROTL_32(x, n) (_rotl((x), (n))) +# define ROTR_32(x, n) (_rotr((x), (n))) + +#else + + // cyclic rotation idioms that modern compilers will + // recognize and generate very compact code for + // evolving specific machine instructions + + inline unsigned ROTL_32(unsigned x, unsigned n) { + n &= 0x1F; + return (x << n) | (x >> (32 - n)); + } + + inline unsigned ROTR_32(unsigned x, unsigned n) { + n &= 0x1F; + return (x >> n) | (x << (32 - n)); + } + +#endif + +#endif // BIT_OPS_H diff --git a/devices/common/pci/bandit.cpp b/devices/common/pci/bandit.cpp index 2251ca9..19d01ed 100644 --- a/devices/common/pci/bandit.cpp +++ b/devices/common/pci/bandit.cpp @@ -212,7 +212,7 @@ void BanditHost::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int details.flags |= PCI_CONFIG_WRITE; if (device) { uint32_t oldvalue = details.size == 4 ? 0 : device->pci_cfg_read(reg_offs, details); - value = pci_cfg_rev_write(oldvalue, details, value); + value = pci_cfg_rev_write(oldvalue, value, details); device->pci_cfg_write(reg_offs, value, details); return; } diff --git a/devices/common/pci/pcidevice.h b/devices/common/pci/pcidevice.h index 5ed7418..f9afe2b 100644 --- a/devices/common/pci/pcidevice.h +++ b/devices/common/pci/pcidevice.h @@ -141,53 +141,6 @@ protected: std::unique_ptr exp_rom_data; }; -/* value is dword from PCI config. MSB..LSB of value is stored in PCI config as 0:LSB..3:MSB. - result is part of value at byte offset from LSB with size bytes (with wrap around) and flipped as required for pci_cfg_read result. */ -inline uint32_t pci_cfg_rev_read(uint32_t value, AccessDetails &details) { - switch (details.size << 2 | details.offset) { - case 0x04: return value & 0xff; // 0 - case 0x05: return (value >> 8) & 0xff; // 1 - case 0x06: return (value >> 16) & 0xff; // 2 - case 0x07: return (value >> 24) & 0xff; // 3 - - case 0x08: return ((value & 0xff) << 8) | ((value >> 8) & 0xff); // 0 1 - case 0x09: return ( value & 0xff00) | ((value >> 16) & 0xff); // 1 2 - case 0x0a: return ((value >> 8) & 0xff00) | ((value >> 24) & 0xff); // 2 3 - case 0x0b: return ((value >> 16) & 0xff00) | ( value & 0xff); // 3 0 - - case 0x10: return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value >> 8) & 0xff00) | ((value >> 24) & 0xff); // 0 1 2 3 - case 0x11: return ((value & 0xff00) << 16) | ( value & 0xff0000) | ((value >> 16) & 0xff00) | ( value & 0xff); // 1 2 3 0 - case 0x12: return ((value & 0xff0000) << 8) | ((value >> 8) & 0xff0000) | ((value & 0xff) << 8) | ((value >> 8) & 0xff); // 2 3 0 1 - case 0x13: return ( value & 0xff000000) | ((value & 0xff) << 16) | ( value & 0xff00) | ((value >> 16) & 0xff); // 3 0 1 2 - - default: return 0xffffffff; - } -} - -/* value is dword from PCI config. MSB..LSB of value (3.2.1.0) is stored in PCI config as 0:LSB..3:MSB. - newvalue is flipped bytes (d0.d1.d2.d3, as passed to pci_cfg_write) to be merged into value. - result is part of value at byte offset from LSB with size bytes (with wrap around) modified by newvalue. */ -inline uint32_t pci_cfg_rev_write(uint32_t value, AccessDetails &details, uint32_t newvalue) { - switch (details.size << 2 | details.offset) { - case 0x04: return (value & 0xffffff00) | (newvalue & 0xff); // 3 2 1 d0 - case 0x05: return (value & 0xffff00ff) | ((newvalue & 0xff) << 8); // 3 2 d0 0 - case 0x06: return (value & 0xff00ffff) | ((newvalue & 0xff) << 16); // 3 d0 1 0 - case 0x07: return (value & 0x00ffffff) | ((newvalue & 0xff) << 24); // d0 2 1 0 - - case 0x08: return (value & 0xffff0000) | ((newvalue >> 8) & 0xff) | ((newvalue & 0xff) << 8); // 3 2 d1 d0 - case 0x09: return (value & 0xff0000ff) | (newvalue & 0xff00) | ((newvalue & 0xff) << 16); // 3 d1 d0 0 - case 0x0a: return (value & 0x0000ffff) | ((newvalue & 0xff00) << 8) | ((newvalue & 0xff) << 24); // d1 d0 1 0 - case 0x0b: return (value & 0x00ffff00) | ((newvalue & 0xff00) << 16) | (newvalue & 0xff); // d0 2 1 d1 - - case 0x10: return ((newvalue & 0xff) << 24) | ((newvalue & 0xff00) << 8) | ((newvalue >> 8) & 0xff00) | ((newvalue >> 24) & 0xff); // d3 d2 d1 d0 - case 0x11: return ((newvalue & 0xff00) << 16) | ( newvalue & 0xff0000) | ((newvalue >> 16) & 0xff00) | ( newvalue & 0xff); // d2 d1 d0 d3 - case 0x12: return ((newvalue & 0xff0000) << 8) | ((newvalue >> 8) & 0xff0000) | ((newvalue & 0xff) << 8) | ((newvalue >> 8) & 0xff); // d1 d0 d3 d2 - case 0x13: return ( newvalue & 0xff000000) | ((newvalue & 0xff) << 16) | ( newvalue & 0xff00) | ((newvalue >> 16) & 0xff); // d0 d3 d2 d1 - - default: return 0xffffffff; - } -} - inline uint32_t pci_cfg_log(uint32_t value, AccessDetails &details) { switch (details.size << 2 | details.offset) { case 0x04: return (uint8_t) value; diff --git a/devices/common/pci/pcihost.h b/devices/common/pci/pcihost.h index 93e144e..1b7d3ef 100644 --- a/devices/common/pci/pcihost.h +++ b/devices/common/pci/pcihost.h @@ -22,7 +22,9 @@ along with this program. If not, see . #ifndef PCI_HOST_H #define PCI_HOST_H +#include #include +#include #include #include @@ -70,4 +72,84 @@ protected: std::vector io_space_devs; }; +/* value is dword from PCI config. MSB..LSB of value is stored in PCI config as 0:LSB..3:MSB. + result is part of value at byte offset from LSB with size bytes (with wrap around) and flipped as required for pci_cfg_read result. */ +inline uint32_t pci_cfg_rev_read(uint32_t value, AccessDetails &details) { + switch (details.size << 2 | details.offset) { + // Bytes + case 0x04: + return value & 0xFF; // 0 + case 0x05: + return (value >> 8) & 0xFF; // 1 + case 0x06: + return (value >> 16) & 0xFF; // 2 + case 0x07: + return (value >> 24) & 0xFF; // 3 + + // Words + case 0x08: + return BYTESWAP_16(value); // 0 1 + case 0x09: + return BYTESWAP_16((value >> 8) & 0xFFFFU); // 1 2 + case 0x0A: + return BYTESWAP_16((value >> 16) & 0xFFFFU); // 2 3 + case 0x0B: + return ((value >> 16) & 0xFF00) | (value & 0xFF); // 3 0 + + // Dwords + case 0x10: + return BYTESWAP_32(value); // 0 1 2 3 + case 0x11: + return ROTL_32(BYTESWAP_32(value), 8); // 1 2 3 0 + case 0x12: + return ROTL_32(BYTESWAP_32(value), 16); // 2 3 0 1 + case 0x13: + return ROTR_32(BYTESWAP_32(value), 8); // 3 0 1 2 + default: + return 0xFFFFFFFFUL; + } +} + +/* value is dword from PCI config. MSB..LSB of value (3.2.1.0) is stored in PCI config as 0:LSB..3:MSB. + newvalue is flipped bytes (d0.d1.d2.d3, as passed to pci_cfg_write) to be merged into value. + result is part of value at byte offset from LSB with size bytes (with wrap around) modified by newvalue. */ +inline uint32_t pci_cfg_rev_write(uint32_t v1, uint32_t v2, AccessDetails &details) +{ + switch (details.size << 2 | details.offset) { + // Bytes + case 0x04: + return (v1 & ~0xFF) | (v2 & 0xFF); // 3 2 1 d0 + case 0x05: + return (v1 & ~0xFF00) | ((v2 & 0xFF) << 8); // 3 2 d0 0 + case 0x06: + return (v1 & ~0xFF0000) | ((v2 & 0xFF) << 16); // 3 d0 1 0 + case 0x07: + return (v1 & 0x00FFFFFF) | ((v2 & 0xFF) << 24); // d0 2 1 0 + + // Words + case 0x08: + return (v1 & ~0xFFFF) | BYTESWAP_16(v2); // 3 2 d1 d0 + case 0x09: + return (v1 & ~0xFFFF00) | (BYTESWAP_16(v2) << 8); // 3 d1 d0 0 + case 0x0a: + return (v1 & 0x0000FFFF) | (BYTESWAP_16(v2) << 16); // d1 d0 1 0 + case 0x0b: + return (v1 & 0x00FFFF00) | ((v2 & 0xFF00) << 16) | + (v2 & 0xFF); // d0 2 1 d1 + + // Dwords + case 0x10: + return BYTESWAP_32(v2); // d3 d2 d1 d0 + case 0x11: + return ROTL_32(BYTESWAP_32(v2), 8); // d2 d1 d0 d3 + case 0x12: + return ROTL_32(BYTESWAP_32(v2), 16); // d1 d0 d3 d2 + case 0x13: + return ROTR_32(BYTESWAP_32(v2), 8); // d0 d3 d2 d1 + + default: + return 0xFFFFFFFFUL; + } +} + #endif /* PCI_HOST_H */ diff --git a/devices/memctrl/mpc106.cpp b/devices/memctrl/mpc106.cpp index 19b772f..5f7c7c0 100644 --- a/devices/memctrl/mpc106.cpp +++ b/devices/memctrl/mpc106.cpp @@ -165,7 +165,7 @@ void MPC106::pci_write(uint32_t offset, uint32_t value, uint32_t size) { details.flags |= PCI_CONFIG_WRITE; if (device) { uint32_t oldvalue = details.size == 4 ? 0 : device->pci_cfg_read(reg_offs, details); - value = pci_cfg_rev_write(oldvalue, details, value); + value = pci_cfg_rev_write(oldvalue, value, details); device->pci_cfg_write(reg_offs, value, details); return; }