From b58b29d977a2273bb21f4aa219d02e408d57056b Mon Sep 17 00:00:00 2001
From: ergo720 <45463469+ergo720@users.noreply.github.com>
Date: Thu, 21 Mar 2024 21:26:25 +0100
Subject: [PATCH] nv2a: implemented more bits of NV_PMC_ENABLE

---
 src/hw/video/gpu/nv2a.cpp    | 20 +++++++--------
 src/hw/video/gpu/pbus.hpp    |  2 +-
 src/hw/video/gpu/pcrtc.cpp   | 47 ++++++++++++++++++++++++++++++---
 src/hw/video/gpu/pcrtc.hpp   |  8 +++---
 src/hw/video/gpu/pfb.cpp     | 47 ++++++++++++++++++++++++++++++---
 src/hw/video/gpu/pfb.hpp     |  8 +++---
 src/hw/video/gpu/pfifo.cpp   | 47 ++++++++++++++++++++++++++++++---
 src/hw/video/gpu/pfifo.hpp   |  8 +++---
 src/hw/video/gpu/pmc.cpp     | 22 ++++++++++++----
 src/hw/video/gpu/pmc.hpp     | 20 ++++++++++++++-
 src/hw/video/gpu/pramdac.hpp |  2 +-
 src/hw/video/gpu/pramin.hpp  |  2 +-
 src/hw/video/gpu/ptimer.cpp  | 50 ++++++++++++++++++++++++++++++++----
 src/hw/video/gpu/ptimer.hpp  | 11 ++++----
 src/hw/video/gpu/pvga.hpp    |  2 +-
 src/hw/video/gpu/pvideo.cpp  | 47 ++++++++++++++++++++++++++++++---
 src/hw/video/gpu/pvideo.hpp  |  8 +++---
 17 files changed, 293 insertions(+), 58 deletions(-)

diff --git a/src/hw/video/gpu/nv2a.cpp b/src/hw/video/gpu/nv2a.cpp
index c8fc367..31eaf22 100644
--- a/src/hw/video/gpu/nv2a.cpp
+++ b/src/hw/video/gpu/nv2a.cpp
@@ -50,14 +50,14 @@ nv2a::get_next_update_time(uint64_t now)
 void
 nv2a::apply_log_settings()
 {
-	m_pmc.update_io_logging();
-	m_pcrtc.update_io_logging();
-	m_pramdac.update_io_logging();
-	m_ptimer.update_io_logging();
-	m_pfb.update_io_logging();
-	m_pbus.update_io_logging();
-	m_pramin.update_io_logging();
-	m_pfifo.update_io_logging();
-	m_pvga.update_io_logging();
-	m_pvideo.update_io_logging();
+	m_pmc.update_io();
+	m_pcrtc.update_io();
+	m_pramdac.update_io();
+	m_ptimer.update_io();
+	m_pfb.update_io();
+	m_pbus.update_io();
+	m_pramin.update_io();
+	m_pfifo.update_io();
+	m_pvga.update_io();
+	m_pvideo.update_io();
 }
diff --git a/src/hw/video/gpu/pbus.hpp b/src/hw/video/gpu/pbus.hpp
index 8d837fd..32364d5 100644
--- a/src/hw/video/gpu/pbus.hpp
+++ b/src/hw/video/gpu/pbus.hpp
@@ -14,7 +14,7 @@ class pbus {
 	pbus(machine *machine) : m_machine(machine), m_pci_conf(nullptr) {}
 	bool init();
 	void reset();
-	void update_io_logging() { update_io(true); }
+	void update_io() { update_io(true); }
 	template<bool log = false>
 	uint32_t read(uint32_t addr);
 	template<bool log = false>
diff --git a/src/hw/video/gpu/pcrtc.cpp b/src/hw/video/gpu/pcrtc.cpp
index 6b9a058..312da88 100644
--- a/src/hw/video/gpu/pcrtc.cpp
+++ b/src/hw/video/gpu/pcrtc.cpp
@@ -17,9 +17,12 @@
 #define NV_PCRTC_UNKNOWN0 (NV2A_REGISTER_BASE + 0x00600804)
 
 
-template<bool log>
+template<bool log, bool enabled>
 void pcrtc::write(uint32_t addr, const uint32_t data)
 {
+	if constexpr (!enabled) {
+		return;
+	}
 	if constexpr (log) {
 		log_io_write();
 	}
@@ -49,9 +52,13 @@ void pcrtc::write(uint32_t addr, const uint32_t data)
 	}
 }
 
-template<bool log>
+template<bool log, bool enabled>
 uint32_t pcrtc::read(uint32_t addr)
 {
+	if constexpr (!enabled) {
+		return 0;
+	}
+
 	uint32_t value = 0;
 
 	switch (addr)
@@ -83,14 +90,46 @@ uint32_t pcrtc::read(uint32_t addr)
 	return value;
 }
 
+template<bool is_write>
+auto pcrtc::get_io_func(bool log, bool enabled)
+{
+	if constexpr (is_write) {
+		if (enabled) {
+			if (log) {
+				return cpu_write<pcrtc, uint32_t, &pcrtc::write<true>>;
+			}
+			else {
+				return cpu_write<pcrtc, uint32_t, &pcrtc::write<false>>;
+			}
+		}
+		else {
+			return cpu_write<pcrtc, uint32_t, &pcrtc::write<false, false>>;
+		}
+	}
+	else {
+		if (enabled) {
+			if (log) {
+				return cpu_read<pcrtc, uint32_t, &pcrtc::read<true>>;
+			}
+			else {
+				return cpu_read<pcrtc, uint32_t, &pcrtc::read<false>>;
+			}
+		}
+		else {
+			return cpu_read<pcrtc, uint32_t, &pcrtc::read<false, false>>;
+		}
+	}
+}
+
 bool
 pcrtc::update_io(bool is_update)
 {
 	bool log = module_enabled();
+	bool enabled = m_machine->get<pmc>().engine_enabled & NV_PMC_ENABLE_PCRTC;
 	if (!LC86_SUCCESS(mem_init_region_io(m_machine->get<cpu_t *>(), NV_PCRTC_BASE, NV_PCRTC_SIZE, false,
 		{
-			.fnr32 = log ? cpu_read<pcrtc, uint32_t, &pcrtc::read<true>> : cpu_read<pcrtc, uint32_t, &pcrtc::read<false>>,
-			.fnw32 = log ? cpu_write<pcrtc, uint32_t, &pcrtc::write<true>> : cpu_write<pcrtc, uint32_t, &pcrtc::write<false>>
+			.fnr32 = get_io_func<false>(log, enabled),
+			.fnw32 = get_io_func<true>(log, enabled)
 		},
 		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 4e611e9..f3dc5e6 100644
--- a/src/hw/video/gpu/pcrtc.hpp
+++ b/src/hw/video/gpu/pcrtc.hpp
@@ -17,14 +17,16 @@ class pcrtc {
 	pcrtc(machine *machine) : m_machine(machine) {}
 	bool init();
 	void reset();
-	void update_io_logging() { update_io(true); }
-	template<bool log = false>
+	void update_io() { update_io(true); }
+	template<bool log = false, bool enabled = true>
 	uint32_t read(uint32_t addr);
-	template<bool log = false>
+	template<bool log = false, bool enabled = true>
 	void write(uint32_t addr, const uint32_t data);
 
 private:
 	bool update_io(bool is_update);
+	template<bool is_write>
+	auto get_io_func(bool log, bool enabled);
 
 	friend class pmc;
 	machine *const m_machine;
diff --git a/src/hw/video/gpu/pfb.cpp b/src/hw/video/gpu/pfb.cpp
index fc8c50e..edcca47 100644
--- a/src/hw/video/gpu/pfb.cpp
+++ b/src/hw/video/gpu/pfb.cpp
@@ -16,9 +16,12 @@
 #define NV_PFB_NVM (NV2A_REGISTER_BASE + 0x00100214)
 
 
-template<bool log>
+template<bool log, bool enabled>
 void pfb::write(uint32_t addr, const uint32_t data)
 {
+	if constexpr (!enabled) {
+		return;
+	}
 	if constexpr (log) {
 		log_io_write();
 	}
@@ -46,9 +49,13 @@ void pfb::write(uint32_t addr, const uint32_t data)
 	}
 }
 
-template<bool log>
+template<bool log, bool enabled>
 uint32_t pfb::read(uint32_t addr)
 {
+	if constexpr (!enabled) {
+		return 0;
+	}
+
 	uint32_t value = 0;
 
 	switch (addr)
@@ -80,14 +87,46 @@ uint32_t pfb::read(uint32_t addr)
 	return value;
 }
 
+template<bool is_write>
+auto pfb::get_io_func(bool log, bool enabled)
+{
+	if constexpr (is_write) {
+		if (enabled) {
+			if (log) {
+				return cpu_write<pfb, uint32_t, &pfb::write<true>>;
+			}
+			else {
+				return cpu_write<pfb, uint32_t, &pfb::write<false>>;
+			}
+		}
+		else {
+			return cpu_write<pfb, uint32_t, &pfb::write<false, false>>;
+		}
+	}
+	else {
+		if (enabled) {
+			if (log) {
+				return cpu_read<pfb, uint32_t, &pfb::read<true>>;
+			}
+			else {
+				return cpu_read<pfb, uint32_t, &pfb::read<false>>;
+			}
+		}
+		else {
+			return cpu_read<pfb, uint32_t, &pfb::read<false, false>>;
+		}
+	}
+}
+
 bool
 pfb::update_io(bool is_update)
 {
 	bool log = module_enabled();
+	bool enabled = m_machine->get<pmc>().engine_enabled & NV_PMC_ENABLE_PFB;
 	if (!LC86_SUCCESS(mem_init_region_io(m_machine->get<cpu_t *>(), NV_PFB_BASE, NV_PFB_SIZE, false,
 		{
-			.fnr32 = log ? cpu_read<pfb, uint32_t, &pfb::read<true>> : cpu_read<pfb, uint32_t, &pfb::read<false>>,
-			.fnw32 = log ? cpu_write<pfb, uint32_t, &pfb::write<true>> : cpu_write<pfb, uint32_t, &pfb::write<false>>
+			.fnr32 = get_io_func<false>(log, enabled),
+			.fnw32 = get_io_func<true>(log, enabled)
 		},
 		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 49c7bde..34c41df 100644
--- a/src/hw/video/gpu/pfb.hpp
+++ b/src/hw/video/gpu/pfb.hpp
@@ -15,14 +15,16 @@ class pfb {
 	pfb(machine *machine) : m_machine(machine) {}
 	bool init();
 	void reset();
-	void update_io_logging() { update_io(true); }
-	template<bool log = false>
+	void update_io() { update_io(true); }
+	template<bool log = false, bool enabled = true>
 	uint32_t read(uint32_t addr);
-	template<bool log = false>
+	template<bool log = false, bool enabled = true>
 	void write(uint32_t addr, const uint32_t data);
 
 private:
 	bool update_io(bool is_update);
+	template<bool is_write>
+	auto get_io_func(bool log, bool enabled);
 
 	friend class pramin;
 	machine *const m_machine;
diff --git a/src/hw/video/gpu/pfifo.cpp b/src/hw/video/gpu/pfifo.cpp
index ca4d67c..71e2d2b 100644
--- a/src/hw/video/gpu/pfifo.cpp
+++ b/src/hw/video/gpu/pfifo.cpp
@@ -15,9 +15,12 @@
 #define NV_PFIFO_RAMRO (NV2A_REGISTER_BASE + 0x00002218)
 
 
-template<bool log>
+template<bool log, bool enabled>
 void pfifo::write(uint32_t addr, const uint32_t data)
 {
+	if constexpr (!enabled) {
+		return;
+	}
 	if constexpr (log) {
 		log_io_write();
 	}
@@ -41,9 +44,13 @@ void pfifo::write(uint32_t addr, const uint32_t data)
 	}
 }
 
-template<bool log>
+template<bool log, bool enabled>
 uint32_t pfifo::read(uint32_t addr)
 {
+	if constexpr (!enabled) {
+		return 0;
+	}
+
 	uint32_t value = 0;
 
 	switch (addr)
@@ -71,14 +78,46 @@ uint32_t pfifo::read(uint32_t addr)
 	return value;
 }
 
+template<bool is_write>
+auto pfifo::get_io_func(bool log, bool enabled)
+{
+	if constexpr (is_write) {
+		if (enabled) {
+			if (log) {
+				return cpu_write<pfifo, uint32_t, &pfifo::write<true>>;
+			}
+			else {
+				return cpu_write<pfifo, uint32_t, &pfifo::write<false>>;
+			}
+		}
+		else {
+			return cpu_write<pfifo, uint32_t, &pfifo::write<false, false>>;
+		}
+	}
+	else {
+		if (enabled) {
+			if (log) {
+				return cpu_read<pfifo, uint32_t, &pfifo::read<true>>;
+			}
+			else {
+				return cpu_read<pfifo, uint32_t, &pfifo::read<false>>;
+			}
+		}
+		else {
+			return cpu_read<pfifo, uint32_t, &pfifo::read<false, false>>;
+		}
+	}
+}
+
 bool
 pfifo::update_io(bool is_update)
 {
 	bool log = module_enabled();
+	bool enabled = m_machine->get<pmc>().engine_enabled & NV_PMC_ENABLE_PFIFO;
 	if (!LC86_SUCCESS(mem_init_region_io(m_machine->get<cpu_t *>(), NV_PFIFO_BASE, NV_PFIFO_SIZE, false,
 		{
-			.fnr32 = log ? cpu_read<pfifo, uint32_t, &pfifo::read<true>> : cpu_read<pfifo, uint32_t, &pfifo::read<false>>,
-			.fnw32 = log ? cpu_write<pfifo, uint32_t, &pfifo::write<true>> : cpu_write<pfifo, uint32_t, &pfifo::write<false>>
+			.fnr32 = get_io_func<false>(log, enabled),
+			.fnw32 = get_io_func<true>(log, enabled)
 		},
 		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 d493142..c749d75 100644
--- a/src/hw/video/gpu/pfifo.hpp
+++ b/src/hw/video/gpu/pfifo.hpp
@@ -14,14 +14,16 @@ class pfifo {
 	pfifo(machine *machine) : m_machine(machine) {}
 	bool init();
 	void reset();
-	void update_io_logging() { update_io(true); }
-	template<bool log = false>
+	void update_io() { update_io(true); }
+	template<bool log = false, bool enabled = true>
 	uint32_t read(uint32_t addr);
-	template<bool log = false>
+	template<bool log = false, bool enabled = true>
 	void write(uint32_t addr, const uint32_t data);
 
 private:
 	bool update_io(bool is_update);
+	template<bool is_write>
+	auto get_io_func(bool log, bool enabled);
 
 	machine *const m_machine;
 	struct {
diff --git a/src/hw/video/gpu/pmc.cpp b/src/hw/video/gpu/pmc.cpp
index 6475166..8cd467b 100644
--- a/src/hw/video/gpu/pmc.cpp
+++ b/src/hw/video/gpu/pmc.cpp
@@ -32,10 +32,6 @@
 #define NV_PMC_INTR_EN_0_INTA_DISABLED 0x00000000
 #define NV_PMC_INTR_EN_0_INTA_HARDWARE 0x00000001
 #define NV_PMC_INTR_EN_0_INTA_SOFTWARE 0x00000002
-#define NV_PMC_ENABLE (NV2A_REGISTER_BASE + 0x00000200)
-#define NV_PMC_ENABLE_PTIMER (1 << 16)
-#define NV_PMC_ENABLE_PFB (1 << 20)
-#define NV_PMC_ENABLE_PCRTC (1 << 24)
 
 
 template<bool log>
@@ -76,7 +72,11 @@ void pmc::write(uint32_t addr, const uint32_t data)
 
 	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) {
+			m_machine->get<pfifo>().reset();
+		}
 		if ((data & NV_PMC_ENABLE_PTIMER) == 0) {
 			m_machine->get<ptimer>().reset();
 			has_int_state_changed = true;
@@ -88,6 +88,17 @@ void pmc::write(uint32_t addr, const uint32_t data)
 			m_machine->get<pcrtc>().reset();
 			has_int_state_changed = true;
 		}
+		if ((data & NV_PMC_ENABLE_PVIDEO) == 0) {
+			m_machine->get<pvideo>().reset();
+		}
+		if ((old_state ^ engine_enabled) & NV_PMC_ENABLE_MASK) {
+			m_machine->get<pfifo>().update_io();
+			m_machine->get<ptimer>().update_io();
+			m_machine->get<pfb>().update_io();
+			m_machine->get<pcrtc>().update_io();
+			m_machine->get<pvideo>().update_io();
+			mem_init_region_io(m_machine->get<cpu_t *>(), 0, 0, true, {}, m_machine->get<cpu_t *>(), true, 3); // trigger the update in lib86cpu too
+		}
 		if (has_int_state_changed) {
 			update_irq();
 		}
@@ -205,10 +216,11 @@ pmc::update_io(bool is_update)
 void
 pmc::reset()
 {
+	// Values dumped from a Retail 1.0 xbox
 	endianness = NV_PMC_BOOT_1_ENDIAN0_LITTLE_MASK | NV_PMC_BOOT_1_ENDIAN24_LITTLE_MASK;
 	int_status = NV_PMC_INTR_0_NOT_PENDING;
 	int_enabled = NV_PMC_INTR_EN_0_INTA_DISABLED;
-	engine_enabled = 0;
+	engine_enabled = NV_PMC_ENABLE_PTIMER | NV_PMC_ENABLE_PFB | NV_PMC_ENABLE_PCRTC;
 }
 
 bool
diff --git a/src/hw/video/gpu/pmc.hpp b/src/hw/video/gpu/pmc.hpp
index 85efb73..44c648f 100644
--- a/src/hw/video/gpu/pmc.hpp
+++ b/src/hw/video/gpu/pmc.hpp
@@ -6,15 +6,28 @@
 
 #include <cstdint>
 
+#define NV_PMC_ENABLE (NV2A_REGISTER_BASE + 0x00000200)
+#define NV_PMC_ENABLE_PFIFO (1 << 8)
+#define NV_PMC_ENABLE_PTIMER (1 << 16)
+#define NV_PMC_ENABLE_PFB (1 << 20)
+#define NV_PMC_ENABLE_PCRTC (1 << 24)
+#define NV_PMC_ENABLE_PVIDEO (1 << 28)
+#define NV_PMC_ENABLE_MASK (NV_PMC_ENABLE_PFIFO | NV_PMC_ENABLE_PTIMER | NV_PMC_ENABLE_PFB | NV_PMC_ENABLE_PCRTC | NV_PMC_ENABLE_PVIDEO)
+
 
 class machine;
+class pfifo;
+class ptimer;
+class pfb;
+class pcrtc;
+class pvideo;
 
 class pmc {
 public:
 	pmc(machine *machine) : m_machine(machine) {}
 	bool init();
 	void reset();
-	void update_io_logging() { update_io(true); }
+	void update_io() { update_io(true); }
 	void update_irq();
 	template<bool log = false>
 	uint32_t read(uint32_t addr);
@@ -24,6 +37,11 @@ class pmc {
 private:
 	bool update_io(bool is_update);
 
+	friend class pfifo;
+	friend class ptimer;
+	friend class pfb;
+	friend class pcrtc;
+	friend class pvideo;
 	machine *const m_machine;
 	struct {
 		uint32_t endianness;
diff --git a/src/hw/video/gpu/pramdac.hpp b/src/hw/video/gpu/pramdac.hpp
index abe2dd9..86f3c67 100644
--- a/src/hw/video/gpu/pramdac.hpp
+++ b/src/hw/video/gpu/pramdac.hpp
@@ -15,7 +15,7 @@ class pramdac {
 	pramdac(machine *machine) : m_machine(machine) {}
 	bool init();
 	void reset();
-	void update_io_logging() { update_io(true); }
+	void update_io() { update_io(true); }
 	template<bool log = false>
 	uint8_t read8(uint32_t addr);
 	template<bool log = false>
diff --git a/src/hw/video/gpu/pramin.hpp b/src/hw/video/gpu/pramin.hpp
index 524254b..da5da16 100644
--- a/src/hw/video/gpu/pramin.hpp
+++ b/src/hw/video/gpu/pramin.hpp
@@ -13,7 +13,7 @@ class pramin {
 public:
 	pramin(machine *machine) : m_machine(machine) {}
 	bool init();
-	void update_io_logging() { update_io(true); }
+	void update_io() { update_io(true); }
 	template<bool log = false>
 	uint8_t read8(uint32_t addr);
 	template<bool log = false>
diff --git a/src/hw/video/gpu/ptimer.cpp b/src/hw/video/gpu/ptimer.cpp
index 68c4e16..3019c23 100644
--- a/src/hw/video/gpu/ptimer.cpp
+++ b/src/hw/video/gpu/ptimer.cpp
@@ -62,9 +62,12 @@ ptimer::get_next_alarm_time(uint64_t now)
 	return std::numeric_limits<uint64_t>::max();
 }
 
-template<bool log>
+template<bool log, bool enabled>
 void ptimer::write(uint32_t addr, const uint32_t data)
 {
+	if constexpr (!enabled) {
+		return;
+	}
 	if constexpr (log) {
 		log_io_write();
 	}
@@ -145,9 +148,13 @@ void ptimer::write(uint32_t addr, const uint32_t data)
 	}
 }
 
-template<bool log>
+template<bool log, bool enabled>
 uint32_t ptimer::read(uint32_t addr)
 {
+	if constexpr (!enabled) {
+		return 0;
+	}
+
 	uint32_t value = 0;
 
 	switch (addr)
@@ -197,14 +204,46 @@ uint32_t ptimer::read(uint32_t addr)
 	return value;
 }
 
+template<bool is_write>
+auto ptimer::get_io_func(bool log, bool enabled)
+{
+	if constexpr (is_write) {
+		if (enabled) {
+			if (log) {
+				return cpu_write<ptimer, uint32_t, &ptimer::write<true>>;
+			}
+			else {
+				return cpu_write<ptimer, uint32_t, &ptimer::write<false>>;
+			}
+		}
+		else {
+			return cpu_write<ptimer, uint32_t, &ptimer::write<false, false>>;
+		}
+	}
+	else {
+		if (enabled) {
+			if (log) {
+				return cpu_read<ptimer, uint32_t, &ptimer::read<true>>;
+			}
+			else {
+				return cpu_read<ptimer, uint32_t, &ptimer::read<false>>;
+			}
+		}
+		else {
+			return cpu_read<ptimer, uint32_t, &ptimer::read<false, false>>;
+		}
+	}
+}
+
 bool
 ptimer::update_io(bool is_update)
 {
 	bool log = module_enabled();
+	bool enabled = m_machine->get<pmc>().engine_enabled & NV_PMC_ENABLE_PTIMER;
 	if (!LC86_SUCCESS(mem_init_region_io(m_machine->get<cpu_t *>(), NV_PTIMER_BASE, NV_PTIMER_SIZE, false,
 		{
-			.fnr32 = log ? cpu_read<ptimer, uint32_t, &ptimer::read<true>> : cpu_read<ptimer, uint32_t, &ptimer::read<false>>,
-			.fnw32 = log ? cpu_write<ptimer, uint32_t, &ptimer::write<true>> : cpu_write<ptimer, uint32_t, &ptimer::write<false>>
+			.fnr32 = get_io_func<false>(log, enabled),
+			.fnw32 = get_io_func<true>(log, enabled)
 		},
 		this, is_update, is_update))) {
 		logger_en(error, "Failed to update mmio region");
@@ -223,10 +262,11 @@ ptimer::reset()
 	multiplier = 0x00001DCD;
 	divider = 0x0000DE86;
 	alarm = 0xFFFFFFE0;
-	counter_period = 0;
+	counter_period = counter_to_us();
 	counter_active = COUNTER_ON;
 	counter_offset = 0;
 	counter_bias = 0;
+	cpu_set_timeout(m_machine->get<cpu_t *>(), m_machine->get<cpu>().check_periodic_events(timer::get_now()));
 }
 
 bool
diff --git a/src/hw/video/gpu/ptimer.hpp b/src/hw/video/gpu/ptimer.hpp
index ab3c36e..de4719b 100644
--- a/src/hw/video/gpu/ptimer.hpp
+++ b/src/hw/video/gpu/ptimer.hpp
@@ -16,20 +16,21 @@ class ptimer {
 	ptimer(machine *machine) : m_machine(machine) {}
 	bool init();
 	void reset();
-	void update_io_logging() { update_io(true); }
+	void update_io() { update_io(true); }
 	uint64_t get_next_alarm_time(uint64_t now);
-	template<bool log = false>
+	template<bool log = false, bool enabled = true>
 	uint32_t read(uint32_t addr);
-	template<bool log = false>
+	template<bool log = false, bool enabled = true>
 	void write(uint32_t addr, const uint32_t data);
 
 private:
 	bool update_io(bool is_update);
+	template<bool is_write>
+	auto get_io_func(bool log, bool enabled);
+	uint64_t counter_to_us();
 
 	friend class pmc;
 	friend class pramdac;
-	uint64_t counter_to_us();
-
 	machine *const m_machine;
 	// Host time when the last alarm interrupt was triggered
 	uint64_t last_alarm_time;
diff --git a/src/hw/video/gpu/pvga.hpp b/src/hw/video/gpu/pvga.hpp
index 2041acc..ccd4462 100644
--- a/src/hw/video/gpu/pvga.hpp
+++ b/src/hw/video/gpu/pvga.hpp
@@ -14,7 +14,7 @@ class pvga {
 	pvga(machine *machine) : m_machine(machine) {}
 	bool init();
 	void reset();
-	void update_io_logging() { update_io(true); }
+	void update_io() { update_io(true); }
 	template<bool log = false>
 	uint8_t io_read8(uint32_t addr);
 	template<bool log = false>
diff --git a/src/hw/video/gpu/pvideo.cpp b/src/hw/video/gpu/pvideo.cpp
index da10bd5..6bfd674 100644
--- a/src/hw/video/gpu/pvideo.cpp
+++ b/src/hw/video/gpu/pvideo.cpp
@@ -23,9 +23,12 @@
 #define NV_PVIDEO_DEBUG_10 (NV2A_REGISTER_BASE + 0x000080A8)
 
 
-template<bool log>
+template<bool log, bool enabled>
 void pvideo::write(uint32_t addr, const uint32_t data)
 {
+	if constexpr (!enabled) {
+		return;
+	}
 	if constexpr (log) {
 		log_io_write();
 	}
@@ -51,9 +54,13 @@ void pvideo::write(uint32_t addr, const uint32_t data)
 	}
 }
 
-template<bool log>
+template<bool log, bool enabled>
 uint32_t pvideo::read(uint32_t addr)
 {
+	if constexpr (!enabled) {
+		return 0;
+	}
+
 	uint32_t value = 0;
 
 	switch (addr)
@@ -83,14 +90,46 @@ uint32_t pvideo::read(uint32_t addr)
 	return value;
 }
 
+template<bool is_write>
+auto pvideo::get_io_func(bool log, bool enabled)
+{
+	if constexpr (is_write) {
+		if (enabled) {
+			if (log) {
+				return cpu_write<pvideo, uint32_t, &pvideo::write<true>>;
+			}
+			else {
+				return cpu_write<pvideo, uint32_t, &pvideo::write<false>>;
+			}
+		}
+		else {
+			return cpu_write<pvideo, uint32_t, &pvideo::write<false, false>>;
+		}
+	}
+	else {
+		if (enabled) {
+			if (log) {
+				return cpu_read<pvideo, uint32_t, &pvideo::read<true>>;
+			}
+			else {
+				return cpu_read<pvideo, uint32_t, &pvideo::read<false>>;
+			}
+		}
+		else {
+			return cpu_read<pvideo, uint32_t, &pvideo::read<false, false>>;
+		}
+	}
+}
+
 bool
 pvideo::update_io(bool is_update)
 {
 	bool log = module_enabled();
+	bool enabled = m_machine->get<pmc>().engine_enabled & NV_PMC_ENABLE_PVIDEO;
 	if (!LC86_SUCCESS(mem_init_region_io(m_machine->get<cpu_t *>(), NV_PVIDEO_BASE, NV_PVIDEO_SIZE, false,
 		{
-			.fnr32 = log ? cpu_read<pvideo, uint32_t, &pvideo::read<true>> : cpu_read<pvideo, uint32_t, &pvideo::read<false>>,
-			.fnw32 = log ? cpu_write<pvideo, uint32_t, &pvideo::write<true>> : cpu_write<pvideo, uint32_t, &pvideo::write<false>>
+			.fnr32 = get_io_func<false>(log, enabled),
+			.fnw32 = get_io_func<true>(log, enabled)
 		},
 		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 d544695..226b2f2 100644
--- a/src/hw/video/gpu/pvideo.hpp
+++ b/src/hw/video/gpu/pvideo.hpp
@@ -14,14 +14,16 @@ class pvideo {
 	pvideo(machine *machine) : m_machine(machine) {}
 	bool init();
 	void reset();
-	void update_io_logging() { update_io(true); }
-	template<bool log = false>
+	void update_io() { update_io(true); }
+	template<bool log = false, bool enabled = true>
 	uint32_t read(uint32_t addr);
-	template<bool log = false>
+	template<bool log = false, bool enabled = true>
 	void write(uint32_t addr, const uint32_t data);
 
 private:
 	bool update_io(bool is_update);
+	template<bool is_write>
+	auto get_io_func(bool log, bool enabled);
 
 	machine *const m_machine;
 	struct {