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;
+    }
+}

Reply via email to