On Wed, 31 Dec 2025, Chad Jablonski wrote:
While drivers use bus mastering modes, PIO is the simplest place to start.
This implements the PM4_FIFO_DATA_EVEN/ODD registers. Writing to these
registers in sequence places packets into the CCE FIFO directly without
need for a ring buffer. This enables testing of the CCE packet processing
itself. Ring buffer registers will follow in a future patch.
Type-0 and Type-1 packets write to registers. Type-2 packets are NOPs.
Type-3 packet headers are parsed but only logged as of now.
Hardware testing and poking at the microcode suggests that Type-0/1/2
packets may be implemented in hardware and not the microcode. Type-3,
however, definitely depends on the microcode.
Signed-off-by: Chad Jablonski <[email protected]>
---
hw/display/ati.c | 10 +++
hw/display/ati_cce.c | 156 ++++++++++++++++++++++++++++++++++++++++
hw/display/ati_cce.h | 56 +++++++++++++++
hw/display/meson.build | 2 +-
hw/display/trace-events | 9 +++
5 files changed, 232 insertions(+), 1 deletion(-)
create mode 100644 hw/display/ati_cce.c
diff --git a/hw/display/ati.c b/hw/display/ati.c
index 29a89b3f80..9edde2b0bc 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -997,6 +997,16 @@ void ati_reg_write(ATIVGAState *s, hwaddr addr,
s->cce.freerun = data & PM4_MICRO_FREERUN;
break;
}
+ case PM4_FIFO_DATA_EVEN:
+ /* fall through */
Fall through comment is not needed when cases follow each other without
anything inbetween so you can drop it here.
+ case PM4_FIFO_DATA_ODD:
+ /*
+ * Real hardware does seem to behave differently when the even/odd
+ * sequence is not strictly adhered to but it's difficult to determine
+ * exactly what is happenning. So for now we treat them the same.
+ */
+ ati_cce_receive_data(s, data);
+ break;
default:
break;
}
diff --git a/hw/display/ati_cce.c b/hw/display/ati_cce.c
new file mode 100644
index 0000000000..62a88a54df
--- /dev/null
+++ b/hw/display/ati_cce.c
@@ -0,0 +1,156 @@
+/*
+ * QEMU ATI SVGA emulation
+ * CCE engine functions
+ *
+ * Copyright (c) 2025 Chad Jablonski
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "ati_regs.h"
+#include "ati_int.h"
+#include "trace.h"
+
+static inline uint32_t
+ati_cce_data_packets_remaining(const ATIPM4PacketState *p)
+{
+ switch (p->type) {
+ case ATI_CCE_TYPE0:
+ return p->t0.count - p->dwords_processed;
+ case ATI_CCE_TYPE1:
+ return 2 - p->dwords_processed;
+ case ATI_CCE_TYPE2:
+ return 0;
+ case ATI_CCE_TYPE3:
+ return p->t3.count - p->dwords_processed;
+ default:
+ /* This should never happen, type is 2-bits wide */
g_assert_not_reached() then?
+ return 0;
+ }
+}