diff --git a/src/hw/cmos.cpp b/src/hw/cmos.cpp index 6fa1602..cdf6ab9 100644 --- a/src/hw/cmos.cpp +++ b/src/hw/cmos.cpp @@ -135,6 +135,7 @@ template void cmos::write(uint32_t addr, const uint8_t data) { if constexpr (log) { + uint8_t value = data; log_io_write(); } diff --git a/src/hw/pci.cpp b/src/hw/pci.cpp index 6f96fe4..af0cbda 100644 --- a/src/hw/pci.cpp +++ b/src/hw/pci.cpp @@ -14,6 +14,7 @@ template void pci::write8(uint32_t addr, const uint8_t data) { if constexpr (log) { + uint8_t value = data; log_io_write(); } @@ -134,6 +135,7 @@ template void pci::write16(uint32_t addr, const uint16_t data) { if constexpr (log) { + uint16_t value = data; log_io_write(); } @@ -145,6 +147,7 @@ template void pci::write32(uint32_t addr, const uint32_t data) { if constexpr (log) { + uint32_t value = data; log_io_write(); } diff --git a/src/hw/pic.cpp b/src/hw/pic.cpp index cde8589..ac5b448 100644 --- a/src/hw/pic.cpp +++ b/src/hw/pic.cpp @@ -235,6 +235,7 @@ template void pic::write(uint32_t addr, const uint8_t data) { if constexpr (log) { + uint8_t value = data; log_io_write(); } @@ -287,6 +288,7 @@ template void pic::write_elcr(uint32_t addr, const uint8_t data) { if constexpr (log) { + uint8_t value = data; log_io_write(); } diff --git a/src/hw/pit.cpp b/src/hw/pit.cpp index 51cb339..f4aa293 100644 --- a/src/hw/pit.cpp +++ b/src/hw/pit.cpp @@ -49,9 +49,14 @@ pit::start_timer(uint8_t channel) cpu_set_timeout(m_machine->get(), m_machine->get().check_periodic_events(m_chan[channel].last_irq_time)); } -void -pit::write_handler(uint32_t addr, const uint8_t data) +template +void pit::write(uint32_t addr, const uint8_t data) { + if constexpr (log) { + uint8_t value = data; + log_io_write(); + } + uint8_t channel = addr & 3; switch (channel) @@ -121,13 +126,6 @@ pit::write_handler(uint32_t addr, const uint8_t data) } } -void -pit::write_handler_logger(uint32_t addr, const uint8_t data) -{ - log_io_write(); - write_handler(addr, data); -} - void pit::channel_reset(uint8_t channel) { @@ -143,7 +141,7 @@ pit::update_io(bool is_update) bool log = module_enabled(); if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), 0x40, 4, true, { - .fnw8 = log ? cpu_write : cpu_write + .fnw8 = log ? cpu_write> : cpu_write> }, this, is_update, is_update))) { logger_en(error, "Failed to update io ports"); diff --git a/src/hw/pit.hpp b/src/hw/pit.hpp index 0edc78f..148dd30 100644 --- a/src/hw/pit.hpp +++ b/src/hw/pit.hpp @@ -23,8 +23,8 @@ class pit { void reset(); void update_io_logging() { update_io(true); } uint64_t get_next_irq_time(uint64_t now); - void write_handler(uint32_t addr, const uint8_t data); - void write_handler_logger(uint32_t addr, const uint8_t data); + template + void write(uint32_t addr, const uint8_t data); private: bool update_io(bool is_update); diff --git a/src/hw/video/gpu/pbus.cpp b/src/hw/video/gpu/pbus.cpp index 4d00ddf..a7f34fb 100644 --- a/src/hw/video/gpu/pbus.cpp +++ b/src/hw/video/gpu/pbus.cpp @@ -90,9 +90,13 @@ nv2a_pci_write(uint8_t *ptr, uint8_t addr, uint8_t data, void *opaque) return 0; // pass-through the write } -template +template void pbus::write(uint32_t addr, const uint32_t data) { + uint32_t value = data; + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (should_log) { log_io_write(); } @@ -100,15 +104,15 @@ void pbus::write(uint32_t addr, const uint32_t data) switch (addr) { case NV_PBUS_FBIO_RAM: - fbio_ram = data; + fbio_ram = value; break; default: - nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, data); + nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, value); } } -template +template uint32_t pbus::read(uint32_t addr) { uint32_t value = 0; @@ -123,6 +127,9 @@ uint32_t pbus::read(uint32_t addr) nxbx_fatal("Unhandled read at address 0x%" PRIX32, addr); } + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (should_log) { log_io_read(); } @@ -130,23 +137,30 @@ uint32_t pbus::read(uint32_t addr) return value; } -template +template void pbus::pci_write(uint32_t addr, const uint32_t data) { + uint32_t value = data; + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (should_log) { log_io_write(); } uint32_t *pci_conf = (uint32_t *)m_pci_conf; - pci_conf[(addr - NV_PBUS_PCI_BASE) / 4] = data; + pci_conf[(addr - NV_PBUS_PCI_BASE) / 4] = value; } -template +template uint32_t pbus::pci_read(uint32_t addr) { uint32_t *pci_conf = (uint32_t *)m_pci_conf; uint32_t value = pci_conf[(addr - NV_PBUS_PCI_BASE) / 4]; + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (should_log) { log_io_read(); } @@ -163,14 +177,56 @@ pbus::pci_init() m_pci_conf = pci_conf; } +template +auto pbus::get_io_func(bool log, bool is_be) +{ + if constexpr (is_pci) { + if constexpr (is_write) { + if (log) { + return is_be ? cpu_write> : cpu_write>; + } + else { + return is_be ? cpu_write> : cpu_write>; + } + } + else { + if (log) { + return is_be ? cpu_read> : cpu_read>; + } + else { + return is_be ? cpu_read> : cpu_read>; + } + } + } + else { + if constexpr (is_write) { + if (log) { + return is_be ? cpu_write> : cpu_write>; + } + else { + return is_be ? cpu_write> : cpu_write>; + } + } + else { + if (log) { + return is_be ? cpu_read> : cpu_read>; + } + else { + return is_be ? cpu_read> : cpu_read>; + } + } + } +} + bool pbus::update_io(bool is_update) { bool log = module_enabled(); + bool is_be = m_machine->get().endianness & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK; if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), NV_PBUS_BASE, NV_PBUS_SIZE, false, { - .fnr32 = log ? cpu_read> : cpu_read>, - .fnw32 = log ? cpu_write> : cpu_write> + .fnr32 = get_io_func(log, is_be), + .fnw32 = get_io_func(log, is_be) }, this, is_update, is_update))) { logger_en(error, "Failed to update mmio region"); @@ -179,8 +235,8 @@ pbus::update_io(bool is_update) if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), NV_PBUS_PCI_BASE, sizeof(default_pci_configuration), false, { - .fnr32 = log ? cpu_read> : cpu_read>, - .fnw32 = log ? cpu_write> : cpu_write> + .fnr32 = get_io_func(log, is_be), + .fnw32 = get_io_func(log, is_be) }, this, is_update, is_update))) { logger_en(error, "Failed to update pci mmio region"); diff --git a/src/hw/video/gpu/pbus.hpp b/src/hw/video/gpu/pbus.hpp index 32364d5..458862a 100644 --- a/src/hw/video/gpu/pbus.hpp +++ b/src/hw/video/gpu/pbus.hpp @@ -15,17 +15,19 @@ class pbus { bool init(); void reset(); void update_io() { update_io(true); } - template + template uint32_t read(uint32_t addr); - template + template void write(uint32_t addr, const uint32_t data); - template + template uint32_t pci_read(uint32_t addr); - template + template void pci_write(uint32_t addr, const uint32_t data); private: bool update_io(bool is_update); + template + auto get_io_func(bool log, bool is_be); void pci_init(); machine *const m_machine; diff --git a/src/hw/video/gpu/pcrtc.cpp b/src/hw/video/gpu/pcrtc.cpp index 312da88..570a2bc 100644 --- a/src/hw/video/gpu/pcrtc.cpp +++ b/src/hw/video/gpu/pcrtc.cpp @@ -17,12 +17,16 @@ #define NV_PCRTC_UNKNOWN0 (NV2A_REGISTER_BASE + 0x00600804) -template +template void pcrtc::write(uint32_t addr, const uint32_t data) { if constexpr (!enabled) { return; } + uint32_t value = data; + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_write(); } @@ -30,29 +34,29 @@ void pcrtc::write(uint32_t addr, const uint32_t data) switch (addr) { case NV_PCRTC_INTR_0: - int_status &= ~data; + int_status &= ~value; m_machine->get().update_irq(); break; case NV_PCRTC_INTR_EN_0: - int_enabled = data; + int_enabled = value; m_machine->get().update_irq(); break; case NV_PCRTC_START: - fb_addr = data & 0x7FFFFFC; // fb is 4 byte aligned + fb_addr = value & 0x7FFFFFC; // fb is 4 byte aligned break; case NV_PCRTC_UNKNOWN0: - unknown[0] = data; + unknown[0] = value; break; default: - nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, data); + nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, value); } } -template +template uint32_t pcrtc::read(uint32_t addr) { if constexpr (!enabled) { @@ -83,6 +87,9 @@ uint32_t pcrtc::read(uint32_t addr) nxbx_fatal("Unhandled read at address 0x%" PRIX32, addr); } + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_read(); } @@ -91,15 +98,15 @@ uint32_t pcrtc::read(uint32_t addr) } template -auto pcrtc::get_io_func(bool log, bool enabled) +auto pcrtc::get_io_func(bool log, bool enabled, bool is_be) { if constexpr (is_write) { if (enabled) { if (log) { - return cpu_write>; + return is_be ? cpu_write> : cpu_write>; } else { - return cpu_write>; + return is_be ? cpu_write> : cpu_write>; } } else { @@ -109,10 +116,10 @@ auto pcrtc::get_io_func(bool log, bool enabled) else { if (enabled) { if (log) { - return cpu_read>; + return is_be ? cpu_read> : cpu_read>; } else { - return cpu_read>; + return is_be ? cpu_read> : cpu_read>; } } else { @@ -126,10 +133,11 @@ pcrtc::update_io(bool is_update) { bool log = module_enabled(); bool enabled = m_machine->get().engine_enabled & NV_PMC_ENABLE_PCRTC; + bool is_be = m_machine->get().endianness & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK; if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), NV_PCRTC_BASE, NV_PCRTC_SIZE, false, { - .fnr32 = get_io_func(log, enabled), - .fnw32 = get_io_func(log, enabled) + .fnr32 = get_io_func(log, enabled, is_be), + .fnw32 = get_io_func(log, enabled, is_be) }, this, is_update, is_update))) { logger_en(error, "Failed to update mmio region"); diff --git a/src/hw/video/gpu/pcrtc.hpp b/src/hw/video/gpu/pcrtc.hpp index f3dc5e6..31a8021 100644 --- a/src/hw/video/gpu/pcrtc.hpp +++ b/src/hw/video/gpu/pcrtc.hpp @@ -18,15 +18,15 @@ class pcrtc { bool init(); void reset(); void update_io() { update_io(true); } - template + template uint32_t read(uint32_t addr); - template + template void write(uint32_t addr, const uint32_t data); private: bool update_io(bool is_update); template - auto get_io_func(bool log, bool enabled); + auto get_io_func(bool log, bool enabled, bool is_be); friend class pmc; machine *const m_machine; diff --git a/src/hw/video/gpu/pfb.cpp b/src/hw/video/gpu/pfb.cpp index edcca47..7a59f9a 100644 --- a/src/hw/video/gpu/pfb.cpp +++ b/src/hw/video/gpu/pfb.cpp @@ -16,12 +16,16 @@ #define NV_PFB_NVM (NV2A_REGISTER_BASE + 0x00100214) -template +template void pfb::write(uint32_t addr, const uint32_t data) { if constexpr (!enabled) { return; } + uint32_t value = data; + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_write(); } @@ -29,11 +33,11 @@ void pfb::write(uint32_t addr, const uint32_t data) switch (addr) { case NV_PFB_CFG0: - cfg0 = data; + cfg0 = value; break; case NV_PFB_CFG1: - cfg1 = data; + cfg1 = value; break; case NV_PFB_CSTATUS: @@ -41,15 +45,15 @@ void pfb::write(uint32_t addr, const uint32_t data) break; case NV_PFB_NVM: - nvm = data; + nvm = value; break; default: - nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, data); + nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, value); } } -template +template uint32_t pfb::read(uint32_t addr) { if constexpr (!enabled) { @@ -80,6 +84,9 @@ uint32_t pfb::read(uint32_t addr) nxbx_fatal("Unhandled read at address 0x%" PRIX32, addr); } + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_read(); } @@ -88,15 +95,15 @@ uint32_t pfb::read(uint32_t addr) } template -auto pfb::get_io_func(bool log, bool enabled) +auto pfb::get_io_func(bool log, bool enabled, bool is_be) { if constexpr (is_write) { if (enabled) { if (log) { - return cpu_write>; + return is_be ? cpu_write> : cpu_write>; } else { - return cpu_write>; + return is_be ? cpu_write> : cpu_write>; } } else { @@ -106,10 +113,10 @@ auto pfb::get_io_func(bool log, bool enabled) else { if (enabled) { if (log) { - return cpu_read>; + return is_be ? cpu_read> : cpu_read>; } else { - return cpu_read>; + return is_be ? cpu_read> : cpu_read>; } } else { @@ -123,10 +130,11 @@ pfb::update_io(bool is_update) { bool log = module_enabled(); bool enabled = m_machine->get().engine_enabled & NV_PMC_ENABLE_PFB; + bool is_be = m_machine->get().endianness & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK; if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), NV_PFB_BASE, NV_PFB_SIZE, false, { - .fnr32 = get_io_func(log, enabled), - .fnw32 = get_io_func(log, enabled) + .fnr32 = get_io_func(log, enabled, is_be), + .fnw32 = get_io_func(log, enabled, is_be) }, this, is_update, is_update))) { logger_en(error, "Failed to update mmio region"); diff --git a/src/hw/video/gpu/pfb.hpp b/src/hw/video/gpu/pfb.hpp index 34c41df..c40e496 100644 --- a/src/hw/video/gpu/pfb.hpp +++ b/src/hw/video/gpu/pfb.hpp @@ -16,15 +16,15 @@ class pfb { bool init(); void reset(); void update_io() { update_io(true); } - template + template uint32_t read(uint32_t addr); - template + template void write(uint32_t addr, const uint32_t data); private: bool update_io(bool is_update); template - auto get_io_func(bool log, bool enabled); + auto get_io_func(bool log, bool enabled, bool is_be); friend class pramin; machine *const m_machine; diff --git a/src/hw/video/gpu/pfifo.cpp b/src/hw/video/gpu/pfifo.cpp index 71e2d2b..ae04f7c 100644 --- a/src/hw/video/gpu/pfifo.cpp +++ b/src/hw/video/gpu/pfifo.cpp @@ -15,12 +15,16 @@ #define NV_PFIFO_RAMRO (NV2A_REGISTER_BASE + 0x00002218) -template +template void pfifo::write(uint32_t addr, const uint32_t data) { if constexpr (!enabled) { return; } + uint32_t value = data; + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_write(); } @@ -28,15 +32,15 @@ void pfifo::write(uint32_t addr, const uint32_t data) switch (addr) { case NV_PFIFO_RAMHT: - ramht = data; + ramht = value; break; case NV_PFIFO_RAMFC: - ramfc = data; + ramfc = value; break; case NV_PFIFO_RAMRO: - ramro = data; + ramro = value; break; default: @@ -44,7 +48,7 @@ void pfifo::write(uint32_t addr, const uint32_t data) } } -template +template uint32_t pfifo::read(uint32_t addr) { if constexpr (!enabled) { @@ -71,6 +75,9 @@ uint32_t pfifo::read(uint32_t addr) nxbx_fatal("Unhandled read at address 0x%" PRIX32, addr); } + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_read(); } @@ -79,15 +86,15 @@ uint32_t pfifo::read(uint32_t addr) } template -auto pfifo::get_io_func(bool log, bool enabled) +auto pfifo::get_io_func(bool log, bool enabled, bool is_be) { if constexpr (is_write) { if (enabled) { if (log) { - return cpu_write>; + return is_be ? cpu_write> : cpu_write>; } else { - return cpu_write>; + return is_be ? cpu_write> : cpu_write>; } } else { @@ -97,10 +104,10 @@ auto pfifo::get_io_func(bool log, bool enabled) else { if (enabled) { if (log) { - return cpu_read>; + return is_be ? cpu_read> : cpu_read>; } else { - return cpu_read>; + return is_be ? cpu_read> : cpu_read>; } } else { @@ -114,10 +121,11 @@ pfifo::update_io(bool is_update) { bool log = module_enabled(); bool enabled = m_machine->get().engine_enabled & NV_PMC_ENABLE_PFIFO; + bool is_be = m_machine->get().endianness & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK; if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), NV_PFIFO_BASE, NV_PFIFO_SIZE, false, { - .fnr32 = get_io_func(log, enabled), - .fnw32 = get_io_func(log, enabled) + .fnr32 = get_io_func(log, enabled, is_be), + .fnw32 = get_io_func(log, enabled, is_be) }, this, is_update, is_update))) { logger_en(error, "Failed to update mmio region"); diff --git a/src/hw/video/gpu/pfifo.hpp b/src/hw/video/gpu/pfifo.hpp index c749d75..8c25e09 100644 --- a/src/hw/video/gpu/pfifo.hpp +++ b/src/hw/video/gpu/pfifo.hpp @@ -15,15 +15,15 @@ class pfifo { bool init(); void reset(); void update_io() { update_io(true); } - template + template uint32_t read(uint32_t addr); - template + template void write(uint32_t addr, const uint32_t data); private: bool update_io(bool is_update); template - auto get_io_func(bool log, bool enabled); + auto get_io_func(bool log, bool enabled, bool is_be); machine *const m_machine; struct { diff --git a/src/hw/video/gpu/pmc.cpp b/src/hw/video/gpu/pmc.cpp index 8cd467b..5947bb5 100644 --- a/src/hw/video/gpu/pmc.cpp +++ b/src/hw/video/gpu/pmc.cpp @@ -12,15 +12,6 @@ #define NV_PMC_BOOT_0 (NV2A_REGISTER_BASE + 0x00000000) #define NV_PMC_BOOT_0_ID_NV2A_A3_DEVID0 0x02A000A3 -#define NV_PMC_BOOT_1 (NV2A_REGISTER_BASE + 0x00000004) -#define NV_PMC_BOOT_1_ENDIAN00_LITTLE 0x00000000 -#define NV_PMC_BOOT_1_ENDIAN00_BIG 0x00000001 -#define NV_PMC_BOOT_1_ENDIAN24_LITTLE 0x00000000 -#define NV_PMC_BOOT_1_ENDIAN24_BIG 0x00000001 -#define NV_PMC_BOOT_1_ENDIAN0_LITTLE_MASK (0x00000000 << 0) -#define NV_PMC_BOOT_1_ENDIAN0_BIG_MASK (0x00000001 << 0) -#define NV_PMC_BOOT_1_ENDIAN24_LITTLE_MASK (0x00000000 << 24) -#define NV_PMC_BOOT_1_ENDIAN24_BIG_MASK (0x00000001 << 24) #define NV_PMC_INTR_0 (NV2A_REGISTER_BASE + 0x00000100) #define NV_PMC_INTR_0_PTIMER 20 #define NV_PMC_INTR_0_PCRTC 24 @@ -34,12 +25,16 @@ #define NV_PMC_INTR_EN_0_INTA_SOFTWARE 0x00000002 -template +template void pmc::write(uint32_t addr, const uint32_t data) { + uint32_t value = data; if constexpr (log) { log_io_write(); } + if constexpr (is_be) { + value = util::byteswap(value); + } switch (addr) { @@ -48,47 +43,54 @@ void pmc::write(uint32_t addr, const uint32_t data) break; case NV_PMC_BOOT_1: { - // This register switches the endianness of all accesses done through BAR0 and BAR2/3 (when present) - uint32_t mask = NV_PMC_BOOT_1_ENDIAN0_LITTLE_MASK; - if (data & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK) { - mask = NV_PMC_BOOT_1_ENDIAN0_BIG_MASK; - nxbx_fatal("NV_PMC_BOOT_1: big endian switch not implemented"); - break; + uint32_t old_state = endianness; + uint32_t new_endianness = (value ^ NV_PMC_BOOT_1_ENDIAN24_BIG_MASK) & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK; + endianness = (new_endianness | (new_endianness >> 24)); + if ((old_state ^ endianness) & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK) { + update_io(); + m_machine->get().update_io(); + m_machine->get().update_io(); + m_machine->get().update_io(); + m_machine->get().update_io(); + m_machine->get().update_io(); + m_machine->get().update_io(); + m_machine->get().update_io(); + m_machine->get().update_io(); + mem_init_region_io(m_machine->get(), 0, 0, true, {}, m_machine->get(), true, 3); // trigger the update in lib86cpu too } - endianness = ((data & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK) | mask); } break; case NV_PMC_INTR_0: // Only NV_PMC_INTR_0_SOFTWARE is writable, the other bits are read-only - int_status = (int_status & ~NV_PMC_INTR_0_SOFTWARE_MASK) | (data & NV_PMC_INTR_0_SOFTWARE_MASK); + int_status = (int_status & ~NV_PMC_INTR_0_SOFTWARE_MASK) | (value & NV_PMC_INTR_0_SOFTWARE_MASK); update_irq(); break; case NV_PMC_INTR_EN_0: - int_enabled = data; + int_enabled = value; update_irq(); break; case NV_PMC_ENABLE: { bool has_int_state_changed = false; uint32_t old_state = engine_enabled; - engine_enabled = data; - if ((data & NV_PMC_ENABLE_PFIFO) == 0) { + engine_enabled = value; + if ((value & NV_PMC_ENABLE_PFIFO) == 0) { m_machine->get().reset(); } - if ((data & NV_PMC_ENABLE_PTIMER) == 0) { + if ((value & NV_PMC_ENABLE_PTIMER) == 0) { m_machine->get().reset(); has_int_state_changed = true; } - if ((data & NV_PMC_ENABLE_PFB) == 0) { + if ((value & NV_PMC_ENABLE_PFB) == 0) { m_machine->get().reset(); } - if ((data & NV_PMC_ENABLE_PCRTC) == 0) { + if ((value & NV_PMC_ENABLE_PCRTC) == 0) { m_machine->get().reset(); has_int_state_changed = true; } - if ((data & NV_PMC_ENABLE_PVIDEO) == 0) { + if ((value & NV_PMC_ENABLE_PVIDEO) == 0) { m_machine->get().reset(); } if ((old_state ^ engine_enabled) & NV_PMC_ENABLE_MASK) { @@ -106,11 +108,11 @@ void pmc::write(uint32_t addr, const uint32_t data) break; default: - nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, data); + nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, value); } } -template +template uint32_t pmc::read(uint32_t addr) { uint32_t value = 0; @@ -143,6 +145,9 @@ uint32_t pmc::read(uint32_t addr) nxbx_fatal("Unhandled %s read at address 0x%" PRIX32, addr); } + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_read(); } @@ -196,14 +201,36 @@ pmc::update_irq() } } +template +auto pmc::get_io_func(bool log, bool is_be) +{ + if constexpr (is_write) { + if (log) { + return is_be ? cpu_write> : cpu_write>; + } + else { + return is_be ? cpu_write> : cpu_write>; + } + } + else { + if (log) { + return is_be ? cpu_read> : cpu_read>; + } + else { + return is_be ? cpu_read> : cpu_read>; + } + } +} + bool pmc::update_io(bool is_update) { bool log = module_enabled(); + bool is_be = endianness & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK; if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), NV_PMC_BASE, NV_PMC_SIZE, false, { - .fnr32 = log ? cpu_read> : cpu_read>, - .fnw32 = log ? cpu_write> : cpu_write> + .fnr32 = get_io_func(log, is_be), + .fnw32 = get_io_func(log, is_be) }, this, is_update, is_update))) { logger_en(error, "Failed to update mmio region"); diff --git a/src/hw/video/gpu/pmc.hpp b/src/hw/video/gpu/pmc.hpp index 44c648f..a1196f3 100644 --- a/src/hw/video/gpu/pmc.hpp +++ b/src/hw/video/gpu/pmc.hpp @@ -6,6 +6,15 @@ #include +#define NV_PMC_BOOT_1 (NV2A_REGISTER_BASE + 0x00000004) +#define NV_PMC_BOOT_1_ENDIAN00_LITTLE 0x00000000 +#define NV_PMC_BOOT_1_ENDIAN00_BIG 0x00000001 +#define NV_PMC_BOOT_1_ENDIAN24_LITTLE 0x00000000 +#define NV_PMC_BOOT_1_ENDIAN24_BIG 0x00000001 +#define NV_PMC_BOOT_1_ENDIAN0_LITTLE_MASK (0x00000000 << 0) +#define NV_PMC_BOOT_1_ENDIAN0_BIG_MASK (0x00000001 << 0) +#define NV_PMC_BOOT_1_ENDIAN24_LITTLE_MASK (0x00000000 << 24) +#define NV_PMC_BOOT_1_ENDIAN24_BIG_MASK (0x00000001 << 24) #define NV_PMC_ENABLE (NV2A_REGISTER_BASE + 0x00000200) #define NV_PMC_ENABLE_PFIFO (1 << 8) #define NV_PMC_ENABLE_PTIMER (1 << 16) @@ -21,6 +30,9 @@ class ptimer; class pfb; class pcrtc; class pvideo; +class pbus; +class pramdac; +class pramin; class pmc { public: @@ -29,21 +41,28 @@ class pmc { void reset(); void update_io() { update_io(true); } void update_irq(); - template + template uint32_t read(uint32_t addr); - template + template void write(uint32_t addr, const uint32_t data); private: bool update_io(bool is_update); + template + auto get_io_func(bool log, bool is_be); friend class pfifo; friend class ptimer; friend class pfb; friend class pcrtc; friend class pvideo; + friend class pbus; + friend class pramdac; + friend class pramin; machine *const m_machine; struct { + // This register switches the endianness of all accesses done through BAR0 and BAR2/3 (when present). PVGA is not affected + // because all its register are single bytes uint32_t endianness; // Pending interrupts of all engines uint32_t int_status; diff --git a/src/hw/video/gpu/pramdac.cpp b/src/hw/video/gpu/pramdac.cpp index 9c4d284..cb07095 100644 --- a/src/hw/video/gpu/pramdac.cpp +++ b/src/hw/video/gpu/pramdac.cpp @@ -19,9 +19,13 @@ #define NV_PRAMDAC_VPLL_COEFF (NV2A_REGISTER_BASE + 0x00680508) -template +template void pramdac::write32(uint32_t addr, const uint32_t data) { + uint32_t value = data; + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_write(); } @@ -30,10 +34,10 @@ void pramdac::write32(uint32_t addr, const uint32_t data) { case NV_PRAMDAC_NVPLL_COEFF: { // NOTE: if the m value is zero, then the final frequency is also zero - nvpll_coeff = data; - uint64_t m = data & NV_PRAMDAC_NVPLL_COEFF_MDIV_MASK; - uint64_t n = (data & NV_PRAMDAC_NVPLL_COEFF_NDIV_MASK) >> 8; - uint64_t p = (data & NV_PRAMDAC_NVPLL_COEFF_PDIV_MASK) >> 16; + nvpll_coeff = value; + uint64_t m = value & NV_PRAMDAC_NVPLL_COEFF_MDIV_MASK; + uint64_t n = (value & NV_PRAMDAC_NVPLL_COEFF_NDIV_MASK) >> 8; + uint64_t p = (value & NV_PRAMDAC_NVPLL_COEFF_PDIV_MASK) >> 16; core_freq = m ? ((NV2A_CRYSTAL_FREQ * n) / (1ULL << p) / m) : 0; if (m_machine->get().counter_active) { m_machine->get().counter_period = m_machine->get().counter_to_us(); @@ -43,19 +47,19 @@ void pramdac::write32(uint32_t addr, const uint32_t data) break; case NV_PRAMDAC_MPLL_COEFF: - mpll_coeff = data; + mpll_coeff = value; break; case NV_PRAMDAC_VPLL_COEFF: - vpll_coeff = data; + vpll_coeff = value; break; default: - nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, data); + nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, value); } } -template +template uint32_t pramdac::read32(uint32_t addr) { uint32_t value = 0; @@ -78,6 +82,9 @@ uint32_t pramdac::read32(uint32_t addr) nxbx_fatal("Unhandled %s read at address 0x%" PRIX32, addr); } + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_read(); } @@ -85,7 +92,7 @@ uint32_t pramdac::read32(uint32_t addr) return value; } -template +template uint8_t pramdac::read8(uint32_t addr) { // This handler is necessary because Direct3D_CreateDevice reads the n value by accessing the second byte of the register, even though the coefficient @@ -93,7 +100,10 @@ uint8_t pramdac::read8(uint32_t addr) uint32_t addr_base = addr & ~3; uint32_t addr_offset = (addr & 3) << 3; - uint32_t value32 = read32(addr_base); + uint32_t value32 = read32(addr_base); + if constexpr (is_be) { + value32 = util::byteswap(value32); + } uint8_t value = uint8_t((value32 & (0xFF << addr_offset)) >> addr_offset); if constexpr (log) { @@ -103,15 +113,47 @@ uint8_t pramdac::read8(uint32_t addr) return value; } +template +auto pramdac::get_io_func(bool log, bool is_be) +{ + if constexpr (is_write) { + if (log) { + return is_be ? cpu_write> : cpu_write>; + } + else { + return is_be ? cpu_write> : cpu_write>; + } + } + else { + if constexpr (sizeof(T) == 1) { + if (log) { + return is_be ? cpu_read> : cpu_read>; + } + else { + return is_be ? cpu_read> : cpu_read>; + } + } + else { + if (log) { + return is_be ? cpu_read> : cpu_read>; + } + else { + return is_be ? cpu_read> : cpu_read>; + } + } + } +} + bool pramdac::update_io(bool is_update) { bool log = module_enabled(); + bool is_be = m_machine->get().endianness & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK; if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), NV_PRAMDAC_BASE, NV_PRAMDAC_SIZE, false, { - .fnr8 = log ? cpu_read> : cpu_read>, - .fnr32 = log ? cpu_read> : cpu_read>, - .fnw32 = log ? cpu_write> : cpu_write> + .fnr8 = get_io_func(log, is_be), + .fnr32 = get_io_func(log, is_be), + .fnw32 = get_io_func(log, is_be), }, this, is_update, is_update))) { logger_en(error, "Failed to update mmio region"); diff --git a/src/hw/video/gpu/pramdac.hpp b/src/hw/video/gpu/pramdac.hpp index 86f3c67..48d792f 100644 --- a/src/hw/video/gpu/pramdac.hpp +++ b/src/hw/video/gpu/pramdac.hpp @@ -16,15 +16,17 @@ class pramdac { bool init(); void reset(); void update_io() { update_io(true); } - template + template uint8_t read8(uint32_t addr); - template + template uint32_t read32(uint32_t addr); - template + template void write32(uint32_t addr, const uint32_t data); private: bool update_io(bool is_update); + template + auto get_io_func(bool log, bool is_be); friend class ptimer; machine *const m_machine; diff --git a/src/hw/video/gpu/pramin.cpp b/src/hw/video/gpu/pramin.cpp index 66073b3..7201008 100644 --- a/src/hw/video/gpu/pramin.cpp +++ b/src/hw/video/gpu/pramin.cpp @@ -13,37 +13,15 @@ #define RAMIN_UNIT_SIZE 64 -template -uint8_t pramin::read8(uint32_t addr) -{ - uint8_t value = m_ram[ramin_to_ram_addr(addr)]; - - if constexpr (log) { - log_io_read(); - } - - return value; -} - -template -uint16_t pramin::read16(uint32_t addr) +template +T pramin::read(uint32_t addr) { uint8_t *ram_ptr = m_ram + ramin_to_ram_addr(addr); - uint16_t value = *(uint16_t *)ram_ptr; + T value = *(T *)ram_ptr; - if constexpr (log) { - log_io_read(); + if constexpr (is_be) { + value = (T)util::byteswap(value); } - - return value; -} - -template -uint32_t pramin::read32(uint32_t addr) -{ - uint8_t *ram_ptr = m_ram + ramin_to_ram_addr(addr); - uint32_t value = *(uint32_t *)ram_ptr; - if constexpr (log) { log_io_read(); } @@ -51,36 +29,19 @@ uint32_t pramin::read32(uint32_t addr) return value; } -template -void pramin::write8(uint32_t addr, const uint8_t data) +template +void pramin::write(uint32_t addr, const T data) { - if constexpr (log) { - log_io_write(); + T value = data; + if constexpr (is_be) { + value = (T)util::byteswap(value); } - - m_ram[ramin_to_ram_addr(addr)] = data; -} - -template -void pramin::write16(uint32_t addr, const uint16_t data) -{ - if constexpr (log) { - log_io_write(); - } - - uint8_t *ram_ptr = m_ram + ramin_to_ram_addr(addr); - *(uint16_t *)ram_ptr = data; -} - -template -void pramin::write32(uint32_t addr, const uint32_t data) -{ if constexpr (log) { log_io_write(); } uint8_t *ram_ptr = m_ram + ramin_to_ram_addr(addr); - *(uint32_t *)ram_ptr = data; + *(T *)ram_ptr = value; } uint32_t @@ -90,18 +51,40 @@ pramin::ramin_to_ram_addr(uint32_t ramin_addr) return m_machine->get().cstatus - (ramin_addr - (ramin_addr % RAMIN_UNIT_SIZE)) - RAMIN_UNIT_SIZE + (ramin_addr % RAMIN_UNIT_SIZE); } +template +auto pramin::get_io_func(bool log, bool is_be) +{ + if constexpr (is_write) { + if (log) { + return is_be ? cpu_write> : cpu_write>; + } + else { + return is_be ? cpu_write> : cpu_write>; + } + } + else { + if (log) { + return is_be ? cpu_read> : cpu_read>; + } + else { + return is_be ? cpu_read> : cpu_read>; + } + } +} + bool pramin::update_io(bool is_update) { bool log = module_enabled(); + bool is_be = m_machine->get().endianness & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK; if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), NV_PRAMIN_BASE, NV_PRAMIN_SIZE, false, { - .fnr8 = log ? cpu_read> : cpu_read>, - .fnr16 = log ? cpu_read> : cpu_read>, - .fnr32 = log ? cpu_read> : cpu_read>, - .fnw8 = log ? cpu_write> : cpu_write>, - .fnw16 = log ? cpu_write> : cpu_write>, - .fnw32 = log ? cpu_write> : cpu_write> + .fnr8 = get_io_func(log, is_be), + .fnr16 = get_io_func(log, is_be), + .fnr32 = get_io_func(log, is_be), + .fnw8 = get_io_func(log, is_be), + .fnw16 = get_io_func(log, is_be), + .fnw32 = get_io_func(log, is_be), }, this, is_update, is_update))) { logger_en(error, "Failed to update mmio region"); diff --git a/src/hw/video/gpu/pramin.hpp b/src/hw/video/gpu/pramin.hpp index da5da16..e14121f 100644 --- a/src/hw/video/gpu/pramin.hpp +++ b/src/hw/video/gpu/pramin.hpp @@ -14,21 +14,15 @@ class pramin { pramin(machine *machine) : m_machine(machine) {} bool init(); void update_io() { update_io(true); } - template - uint8_t read8(uint32_t addr); - template - uint16_t read16(uint32_t addr); - template - uint32_t read32(uint32_t addr); - template - void write8(uint32_t addr, const uint8_t data); - template - void write16(uint32_t addr, const uint16_t data); - template - void write32(uint32_t addr, const uint32_t data); + template + T read(uint32_t addr); + template + void write(uint32_t addr, const T data); private: bool update_io(bool is_update); + template + auto get_io_func(bool log, bool is_be); uint32_t ramin_to_ram_addr(uint32_t ramin_addr); machine *const m_machine; uint8_t *m_ram; diff --git a/src/hw/video/gpu/ptimer.cpp b/src/hw/video/gpu/ptimer.cpp index 3019c23..a0924c5 100644 --- a/src/hw/video/gpu/ptimer.cpp +++ b/src/hw/video/gpu/ptimer.cpp @@ -62,12 +62,16 @@ ptimer::get_next_alarm_time(uint64_t now) return std::numeric_limits::max(); } -template +template void ptimer::write(uint32_t addr, const uint32_t data) { if constexpr (!enabled) { return; } + uint32_t value = data; + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_write(); } @@ -75,17 +79,17 @@ void ptimer::write(uint32_t addr, const uint32_t data) switch (addr) { case NV_PTIMER_INTR_0: - int_status &= ~data; + int_status &= ~value; m_machine->get().update_irq(); break; case NV_PTIMER_INTR_EN_0: - int_enabled = data; + int_enabled = value; m_machine->get().update_irq(); break; case NV_PTIMER_NUMERATOR: - divider = data & NV_PTIMER_NUMERATOR_MASK; + divider = value & NV_PTIMER_NUMERATOR_MASK; if (counter_active) { counter_period = counter_to_us(); cpu_set_timeout(m_machine->get(), m_machine->get().check_periodic_events(timer::get_now())); @@ -93,7 +97,7 @@ void ptimer::write(uint32_t addr, const uint32_t data) break; case NV_PTIMER_DENOMINATOR: { - multiplier = data & NV_PTIMER_DENOMINATOR_MASK; + multiplier = value & NV_PTIMER_DENOMINATOR_MASK; if (multiplier > divider) [[unlikely]] { // Testing on a Retail 1.0 xbox shows that, when this condition is hit, the console hangs. We don't actually want to freeze the emulator, so // we will just terminate the emulation instead @@ -114,11 +118,11 @@ void ptimer::write(uint32_t addr, const uint32_t data) // Tested on a Retail 1.0 xbox: writing to the NV_PTIMER_TIME_0/1 registers causes the timer to start counting from the written value case NV_PTIMER_TIME_0: - counter_offset = (counter_offset & (0xFFFFFFFFULL << 32)) | data; + counter_offset = (counter_offset & (0xFFFFFFFFULL << 32)) | value; break; case NV_PTIMER_TIME_1: - counter_offset = (counter_offset & 0xFFFFFFFFULL) | ((uint64_t)data << 32); + counter_offset = (counter_offset & 0xFFFFFFFFULL) | ((uint64_t)value << 32); break; case NV_PTIMER_ALARM_0: { @@ -134,7 +138,7 @@ void ptimer::write(uint32_t addr, const uint32_t data) a1 n bias+ (period larger for one cycle) */ uint32_t old_alarm = alarm >> 5; - alarm = data & ~0x1F; // tested on hw: writes of 1s to the first five bits have no impact + alarm = value & ~0x1F; // tested on hw: writes of 1s to the first five bits have no impact uint32_t new_alarm = alarm >> 5; counter_bias = new_alarm - old_alarm; if (counter_active) { @@ -144,11 +148,11 @@ void ptimer::write(uint32_t addr, const uint32_t data) break; default: - nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, data); + nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, value); } } -template +template uint32_t ptimer::read(uint32_t addr) { if constexpr (!enabled) { @@ -197,6 +201,9 @@ uint32_t ptimer::read(uint32_t addr) nxbx_fatal("Unhandled read at address 0x%" PRIX32, addr); } + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_read(); } @@ -205,15 +212,15 @@ uint32_t ptimer::read(uint32_t addr) } template -auto ptimer::get_io_func(bool log, bool enabled) +auto ptimer::get_io_func(bool log, bool enabled, bool is_be) { if constexpr (is_write) { if (enabled) { if (log) { - return cpu_write>; + return is_be ? cpu_write> : cpu_write>; } else { - return cpu_write>; + return is_be ? cpu_write> : cpu_write>; } } else { @@ -223,10 +230,10 @@ auto ptimer::get_io_func(bool log, bool enabled) else { if (enabled) { if (log) { - return cpu_read>; + return is_be ? cpu_read> : cpu_read>; } else { - return cpu_read>; + return is_be ? cpu_read> : cpu_read>; } } else { @@ -240,10 +247,11 @@ ptimer::update_io(bool is_update) { bool log = module_enabled(); bool enabled = m_machine->get().engine_enabled & NV_PMC_ENABLE_PTIMER; + bool is_be = m_machine->get().endianness & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK; if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), NV_PTIMER_BASE, NV_PTIMER_SIZE, false, { - .fnr32 = get_io_func(log, enabled), - .fnw32 = get_io_func(log, enabled) + .fnr32 = get_io_func(log, enabled, is_be), + .fnw32 = get_io_func(log, enabled, is_be) }, this, is_update, is_update))) { logger_en(error, "Failed to update mmio region"); diff --git a/src/hw/video/gpu/ptimer.hpp b/src/hw/video/gpu/ptimer.hpp index de4719b..fe693e3 100644 --- a/src/hw/video/gpu/ptimer.hpp +++ b/src/hw/video/gpu/ptimer.hpp @@ -18,15 +18,15 @@ class ptimer { void reset(); void update_io() { update_io(true); } uint64_t get_next_alarm_time(uint64_t now); - template + template uint32_t read(uint32_t addr); - template + template void write(uint32_t addr, const uint32_t data); private: bool update_io(bool is_update); template - auto get_io_func(bool log, bool enabled); + auto get_io_func(bool log, bool enabled, bool is_be); uint64_t counter_to_us(); friend class pmc; diff --git a/src/hw/video/gpu/pvga.cpp b/src/hw/video/gpu/pvga.cpp index a9d96e3..9a7b02a 100644 --- a/src/hw/video/gpu/pvga.cpp +++ b/src/hw/video/gpu/pvga.cpp @@ -35,21 +35,23 @@ uint8_t pvga::io_read8(uint32_t addr) template void pvga::io_write8(uint32_t addr, const uint8_t data) { + uint8_t value = data; if constexpr (log) { log_io_write(); } - m_machine->get().io_write8(addr, data); + m_machine->get().io_write8(addr, value); } template void pvga::io_write16(uint32_t addr, const uint16_t data) { + uint16_t value = data; if constexpr (log) { log_io_write(); } - m_machine->get().io_write16(addr, data); + m_machine->get().io_write16(addr, value); } template @@ -79,21 +81,23 @@ uint16_t pvga::mem_read16(uint32_t addr) template void pvga::mem_write8(uint32_t addr, const uint8_t data) { + uint8_t value = data; if constexpr (log) { log_io_write(); } - m_machine->get().mem_write8(addr, data); + m_machine->get().mem_write8(addr, value); } template void pvga::mem_write16(uint32_t addr, const uint16_t data) { + uint16_t value = data; if constexpr (log) { log_io_write(); } - m_machine->get().mem_write16(addr, data); + m_machine->get().mem_write16(addr, value); } bool diff --git a/src/hw/video/gpu/pvideo.cpp b/src/hw/video/gpu/pvideo.cpp index 6bfd674..30e9b3a 100644 --- a/src/hw/video/gpu/pvideo.cpp +++ b/src/hw/video/gpu/pvideo.cpp @@ -23,12 +23,16 @@ #define NV_PVIDEO_DEBUG_10 (NV2A_REGISTER_BASE + 0x000080A8) -template +template void pvideo::write(uint32_t addr, const uint32_t data) { if constexpr (!enabled) { return; } + uint32_t value = data; + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_write(); } @@ -46,15 +50,15 @@ void pvideo::write(uint32_t addr, const uint32_t data) case NV_PVIDEO_DEBUG_8: case NV_PVIDEO_DEBUG_9: case NV_PVIDEO_DEBUG_10: - debug[(addr - NV_PVIDEO_DEBUG_0) >> 2] = data; + debug[(addr - NV_PVIDEO_DEBUG_0) >> 2] = value; break; default: - nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, data); + nxbx_fatal("Unhandled write at address 0x%" PRIX32 " with value 0x%" PRIX32, addr, value); } } -template +template uint32_t pvideo::read(uint32_t addr) { if constexpr (!enabled) { @@ -83,6 +87,9 @@ uint32_t pvideo::read(uint32_t addr) nxbx_fatal("Unhandled read at address 0x%" PRIX32, addr); } + if constexpr (is_be) { + value = util::byteswap(value); + } if constexpr (log) { log_io_read(); } @@ -91,15 +98,15 @@ uint32_t pvideo::read(uint32_t addr) } template -auto pvideo::get_io_func(bool log, bool enabled) +auto pvideo::get_io_func(bool log, bool enabled, bool is_be) { if constexpr (is_write) { if (enabled) { if (log) { - return cpu_write>; + return is_be ? cpu_write> : cpu_write>; } else { - return cpu_write>; + return is_be ? cpu_write> : cpu_write>; } } else { @@ -109,10 +116,10 @@ auto pvideo::get_io_func(bool log, bool enabled) else { if (enabled) { if (log) { - return cpu_read>; + return is_be ? cpu_read> : cpu_read>; } else { - return cpu_read>; + return is_be ? cpu_read> : cpu_read>; } } else { @@ -126,10 +133,11 @@ pvideo::update_io(bool is_update) { bool log = module_enabled(); bool enabled = m_machine->get().engine_enabled & NV_PMC_ENABLE_PVIDEO; + bool is_be = m_machine->get().endianness & NV_PMC_BOOT_1_ENDIAN24_BIG_MASK; if (!LC86_SUCCESS(mem_init_region_io(m_machine->get(), NV_PVIDEO_BASE, NV_PVIDEO_SIZE, false, { - .fnr32 = get_io_func(log, enabled), - .fnw32 = get_io_func(log, enabled) + .fnr32 = get_io_func(log, enabled, is_be), + .fnw32 = get_io_func(log, enabled, is_be) }, this, is_update, is_update))) { logger_en(error, "Failed to update mmio region"); diff --git a/src/hw/video/gpu/pvideo.hpp b/src/hw/video/gpu/pvideo.hpp index 226b2f2..b73c8b3 100644 --- a/src/hw/video/gpu/pvideo.hpp +++ b/src/hw/video/gpu/pvideo.hpp @@ -15,15 +15,15 @@ class pvideo { bool init(); void reset(); void update_io() { update_io(true); } - template + template uint32_t read(uint32_t addr); - template + template void write(uint32_t addr, const uint32_t data); private: bool update_io(bool is_update); template - auto get_io_func(bool log, bool enabled); + auto get_io_func(bool log, bool enabled, bool is_be); machine *const m_machine; struct { diff --git a/src/kernel.cpp b/src/kernel.cpp index 9774232..5351aad 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -92,6 +92,7 @@ namespace kernel { void write(addr_t addr, const uint32_t data, void *opaque) { if constexpr (log) { + uint32_t value = data; log_io_write(); } diff --git a/src/logger.hpp b/src/logger.hpp index c1037a5..064fcb8 100644 --- a/src/logger.hpp +++ b/src/logger.hpp @@ -14,7 +14,7 @@ #define logger_en(lv, msg, ...) do { logger(msg __VA_OPT__(,) __VA_ARGS__); } while(0) #define logger_nxbx(lv, msg, ...) do { logger(msg __VA_OPT__(,) __VA_ARGS__); } while(0) #define log_io_read() do { logger("Read at address 0x%08X of value 0x%08X", addr, value); } while(0) -#define log_io_write() do { logger("Write at address 0x%08X of value 0x%08X", addr, data); } while(0) +#define log_io_write() do { logger("Write at address 0x%08X of value 0x%08X", addr, value); } while(0) #define module_enabled() check_if_enabled() #define NUM_OF_LOG_MODULES32 static_cast>(log_module::max) / 32 + 1 diff --git a/src/util.cpp b/src/util.cpp index 9d1b377..26120ce 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -25,6 +25,13 @@ namespace util { #endif } + uint32_t + byteswap(uint32_t value) + { + // NOTE: this can be removed with std::byteswap of C++23 + return (value << 24) | ((value << 8) & 0x00FF0000) | ((value >> 8) & 0x0000FF00) | (value >> 24); + } + char xbox_toupper(char c) { diff --git a/src/util.hpp b/src/util.hpp index 4fdd924..6bfbc6c 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -11,6 +11,7 @@ namespace util { uint64_t muldiv128(uint64_t a, uint64_t b, uint64_t c); + uint32_t byteswap(uint32_t value); char xbox_toupper(char c); // Case-insensitive variant of std::char_traits, used to compare xbox strings