mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-06-15 15:29:36 +00:00
pcihost: refactor data access helpers.
This commit is contained in:
parent
289ddf10b7
commit
31db015105
59
core/bitops.h
Normal file
59
core/bitops.h
Normal file
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 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 <x86intrin.h>
|
||||||
|
|
||||||
|
# define ROTL_32(x, n) (_rotl((x), (n)))
|
||||||
|
# define ROTR_32(x, n) (_rotr((x), (n)))
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER) // MSVC
|
||||||
|
|
||||||
|
# include <intrin.h>
|
||||||
|
|
||||||
|
# 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
|
|
@ -212,7 +212,7 @@ void BanditHost::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int
|
||||||
details.flags |= PCI_CONFIG_WRITE;
|
details.flags |= PCI_CONFIG_WRITE;
|
||||||
if (device) {
|
if (device) {
|
||||||
uint32_t oldvalue = details.size == 4 ? 0 : device->pci_cfg_read(reg_offs, details);
|
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);
|
device->pci_cfg_write(reg_offs, value, details);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,53 +141,6 @@ protected:
|
||||||
std::unique_ptr<uint8_t[]> exp_rom_data;
|
std::unique_ptr<uint8_t[]> 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) {
|
inline uint32_t pci_cfg_log(uint32_t value, AccessDetails &details) {
|
||||||
switch (details.size << 2 | details.offset) {
|
switch (details.size << 2 | details.offset) {
|
||||||
case 0x04: return (uint8_t) value;
|
case 0x04: return (uint8_t) value;
|
||||||
|
|
|
@ -22,7 +22,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
#ifndef PCI_HOST_H
|
#ifndef PCI_HOST_H
|
||||||
#define PCI_HOST_H
|
#define PCI_HOST_H
|
||||||
|
|
||||||
|
#include <core/bitops.h>
|
||||||
#include <devices/deviceregistry.h>
|
#include <devices/deviceregistry.h>
|
||||||
|
#include <endianswap.h>
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -70,4 +72,84 @@ protected:
|
||||||
std::vector<PCIDevice*> io_space_devs;
|
std::vector<PCIDevice*> 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 */
|
#endif /* PCI_HOST_H */
|
||||||
|
|
|
@ -165,7 +165,7 @@ void MPC106::pci_write(uint32_t offset, uint32_t value, uint32_t size) {
|
||||||
details.flags |= PCI_CONFIG_WRITE;
|
details.flags |= PCI_CONFIG_WRITE;
|
||||||
if (device) {
|
if (device) {
|
||||||
uint32_t oldvalue = details.size == 4 ? 0 : device->pci_cfg_read(reg_offs, details);
|
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);
|
device->pci_cfg_write(reg_offs, value, details);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user