[PATCH v4 1/9] ati-vga: Store DP_DATATYPE and DP_MIX fields independently

Chad Jablonski posted 9 patches 1 month ago
There is a newer version of this series
[PATCH v4 1/9] ati-vga: Store DP_DATATYPE and DP_MIX fields independently
Posted by Chad Jablonski 1 month ago
DP_GUI_MASTER_CNTL accesses the same values as DP_DATATYPE and DP_MIX.
This was not reflected in how we stored register state. This meant that
you could easily end up with stale state in one or the other register.

This stores each field directly instead of packing them into a field
named after the register. The register handlers then shift bits around
if needed. This not only keeps things in sync but means less shifting
and masking when using these values internally.

Signed-off-by: Chad Jablonski <chad@jablonski.xyz>
---
 hw/display/ati.c      | 41 +++++++++++++++++++++++++++++++++--------
 hw/display/ati_2d.c   | 12 ++++++------
 hw/display/ati_int.h  | 10 ++++++++--
 hw/display/ati_regs.h | 33 +++++++++++++++++++++++++++++----
 4 files changed, 76 insertions(+), 20 deletions(-)

diff --git a/hw/display/ati.c b/hw/display/ati.c
index e9c3ad2cd1..0bbe8915f1 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -460,7 +460,14 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
         val = s->regs.dst_y;
         break;
     case DP_GUI_MASTER_CNTL:
-        val = s->regs.dp_gui_master_cntl;
+        val = s->regs.dp_gui_master_cntl |
+              (s->regs.dp_brush_datatype << 4) |
+              (s->regs.dp_dst_datatype << 8) |
+              (s->regs.dp_src_datatype << 12) |
+              (s->regs.byte_pix_order << 14) |
+              (s->regs.conversion_temp << 15) |
+              (s->regs.dp_rop3 << 16) |
+              (s->regs.dp_src_source << 24);
         break;
     case SRC_OFFSET:
         val = s->regs.src_offset;
@@ -487,10 +494,15 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
         val = s->regs.dp_cntl;
         break;
     case DP_DATATYPE:
-        val = s->regs.dp_datatype;
+        val = (s->regs.dp_dst_datatype) |
+              (s->regs.dp_brush_datatype << 8) |
+              (s->regs.dp_src_datatype << 16) |
+              (s->regs.host_big_endian_en << 29) |
+              (s->regs.byte_pix_order << 30) |
+              (s->regs.conversion_temp << 31);
         break;
     case DP_MIX:
-        val = s->regs.dp_mix;
+        val = (s->regs.dp_rop3 << 16) | (s->regs.dp_src_source << 8);
         break;
     case DP_WRITE_MASK:
         val = s->regs.dp_write_mask;
@@ -858,10 +870,17 @@ static void ati_mm_write(void *opaque, hwaddr addr,
         ati_2d_blt(s);
         break;
     case DP_GUI_MASTER_CNTL:
+        /* Mask out fields that are stored independently */
         s->regs.dp_gui_master_cntl = data & 0xf800000f;
-        s->regs.dp_datatype = (data & 0x0f00) >> 8 | (data & 0x30f0) << 4 |
-                              (data & 0x4000) << 16;
-        s->regs.dp_mix = (data & GMC_ROP3_MASK) | (data & 0x7000000) >> 16;
+        /* DP_DATATYPE fields */
+        s->regs.dp_brush_datatype = (data & GMC_BRUSH_DATATYPE_MASK) >> 4;
+        s->regs.dp_dst_datatype = (data & GMC_DST_DATATYPE_MASK) >> 8;
+        s->regs.dp_src_datatype = (data & GMC_SRC_DATATYPE_MASK) >> 12;
+        s->regs.byte_pix_order = (data & GMC_BYTE_PIX_ORDER) >> 14;
+        s->regs.conversion_temp = (data & GMC_CONVERSION_TEMP) >> 15;
+        /* DP_MIX fields */
+        s->regs.dp_rop3 = (data & GMC_ROP3_MASK) >> 16;
+        s->regs.dp_src_source = (data & GMC_SRC_SOURCE_MASK) >> 24;
         break;
     case DST_WIDTH_X:
         s->regs.dst_x = data & 0x3fff;
@@ -910,10 +929,16 @@ static void ati_mm_write(void *opaque, hwaddr addr,
         s->regs.dp_cntl = data;
         break;
     case DP_DATATYPE:
-        s->regs.dp_datatype = data & 0xe0070f0f;
+        s->regs.dp_dst_datatype = (data & DP_DATATYPE_DST_DATATYPE_MASK);
+        s->regs.dp_brush_datatype = (data & DP_DATATYPE_BRUSH_DATATYPE_MASK) >> 8;
+        s->regs.dp_src_datatype = (data & DP_DATATYPE_SRC_DATATYPE_MASK) >> 16;
+        s->regs.host_big_endian_en = (data & DP_DATATYPE_HOST_BE_EN) >> 29;
+        s->regs.byte_pix_order = (data & DP_DATATYPE_BYTE_PIX_ORDER) >> 30;
+        s->regs.conversion_temp = (data & DP_DATATYPE_CONVERSION_TEMP) >> 31;
         break;
     case DP_MIX:
-        s->regs.dp_mix = data & 0x00ff0700;
+        s->regs.dp_src_source = (data & DP_MIX_SRC_SOURCE_MASK) >> 8;
+        s->regs.dp_rop3 = (data & DP_MIX_ROP3_MASK) >> 16;
         break;
     case DP_WRITE_MASK:
         s->regs.dp_write_mask = data;
diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c
index 309bb5ccb6..0531d1a526 100644
--- a/hw/display/ati_2d.c
+++ b/hw/display/ati_2d.c
@@ -26,7 +26,7 @@
 
 static int ati_bpp_from_datatype(ATIVGAState *s)
 {
-    switch (s->regs.dp_datatype & 0xf) {
+    switch (s->regs.dp_dst_datatype) {
     case 2:
         return 8;
     case 3:
@@ -38,7 +38,7 @@ static int ati_bpp_from_datatype(ATIVGAState *s)
         return 32;
     default:
         qemu_log_mask(LOG_UNIMP, "Unknown dst datatype %d\n",
-                      s->regs.dp_datatype & 0xf);
+                      s->regs.dp_dst_datatype);
         return 0;
     }
 }
@@ -53,7 +53,7 @@ void ati_2d_blt(ATIVGAState *s)
     DPRINTF("%p %u ds: %p %d %d rop: %x\n", s->vga.vram_ptr,
             s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds),
             surface_bits_per_pixel(ds),
-            (s->regs.dp_mix & GMC_ROP3_MASK) >> 16);
+            (s->regs.dp_rop3));
     unsigned dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
                       s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width);
     unsigned dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
@@ -89,7 +89,7 @@ void ati_2d_blt(ATIVGAState *s)
             s->regs.dst_width, s->regs.dst_height,
             (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? '>' : '<'),
             (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? 'v' : '^'));
-    switch (s->regs.dp_mix & GMC_ROP3_MASK) {
+    switch (s->regs.dp_rop3) {
     case ROP3_SRCCOPY:
     {
         bool fallback = false;
@@ -191,7 +191,7 @@ void ati_2d_blt(ATIVGAState *s)
     {
         uint32_t filler = 0;
 
-        switch (s->regs.dp_mix & GMC_ROP3_MASK) {
+        switch (s->regs.dp_rop3) {
         case ROP3_PATCOPY:
             filler = s->regs.dp_brush_frgd_clr;
             break;
@@ -239,6 +239,6 @@ void ati_2d_blt(ATIVGAState *s)
     }
     default:
         qemu_log_mask(LOG_UNIMP, "Unimplemented ati_2d blt op %x\n",
-                      (s->regs.dp_mix & GMC_ROP3_MASK) >> 16);
+                      s->regs.dp_rop3);
     }
 }
diff --git a/hw/display/ati_int.h b/hw/display/ati_int.h
index f5a47b82b0..59a1812034 100644
--- a/hw/display/ati_int.h
+++ b/hw/display/ati_int.h
@@ -75,13 +75,19 @@ typedef struct ATIVGARegs {
     uint32_t dp_src_frgd_clr;
     uint32_t dp_src_bkgd_clr;
     uint32_t dp_cntl;
-    uint32_t dp_datatype;
-    uint32_t dp_mix;
     uint32_t dp_write_mask;
     uint32_t default_offset;
     uint32_t default_pitch;
     uint32_t default_tile;
     uint32_t default_sc_bottom_right;
+    uint8_t dp_src_source;
+    uint8_t dp_rop3;
+    uint8_t dp_dst_datatype;
+    uint8_t dp_brush_datatype;
+    uint8_t dp_src_datatype;
+    bool host_big_endian_en;
+    bool byte_pix_order;
+    bool conversion_temp;
 } ATIVGARegs;
 
 struct ATIVGAState {
diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h
index d7127748ff..fce9270635 100644
--- a/hw/display/ati_regs.h
+++ b/hw/display/ati_regs.h
@@ -381,6 +381,12 @@
 #define PM4_BUFFER_CNTL_NONPM4                  0x00000000
 
 /* DP_DATATYPE bit constants */
+#define DP_DATATYPE_DST_DATATYPE_MASK           0x0000000f
+#define DP_DATATYPE_BRUSH_DATATYPE_MASK         0x00000f00
+#define DP_DATATYPE_SRC_DATATYPE_MASK           0x00030000
+#define DP_DATATYPE_HOST_BE_EN                  0x20000000
+#define DP_DATATYPE_BYTE_PIX_ORDER              0x40000000
+#define DP_DATATYPE_CONVERSION_TEMP             0x80000000
 #define DST_8BPP                                0x00000002
 #define DST_15BPP                               0x00000003
 #define DST_16BPP                               0x00000004
@@ -394,6 +400,11 @@
 #define GMC_DST_PITCH_OFFSET_CNTL               0x00000002
 #define GMC_SRC_CLIP_DEFAULT                    0x00000000
 #define GMC_DST_CLIP_DEFAULT                    0x00000000
+#define GMC_BRUSH_DATATYPE_MASK                 0x000000f0
+#define GMC_DST_DATATYPE_MASK                   0x00000f00
+#define GMC_SRC_DATATYPE_MASK                   0x00003000
+#define GMC_BYTE_PIX_ORDER                      0x00004000
+#define GMC_CONVERSION_TEMP                     0x00008000
 #define GMC_BRUSH_SOLIDCOLOR                    0x000000d0
 #define GMC_SRC_DSTCOLOR                        0x00003000
 #define GMC_BYTE_ORDER_MSB_TO_LSB               0x00000000
@@ -404,12 +415,24 @@
 #define GMC_WRITE_MASK_SET                      0x40000000
 #define GMC_DP_CONVERSION_TEMP_6500             0x00000000
 
+/* DP_GUI_MASTER_CNTL DP_SRC_DATATYPE named constants */
+#define GMC_SRC_DATATYPE_MASK                   0x00003000
+#define GMC_SRC_DATATYPE_MONO_FRGD_BKGD         0
+#define GMC_SRC_DATATYPE_MONO_FRGD              1
+#define GMC_SRC_DATATYPE_COLOR                  3
+
+/* DP_GUI_MASTER_CNTL DP_SRC_SOURCE named constants */
+#define GMC_SRC_SOURCE_MASK                     0x07000000
+#define GMC_SRC_SOURCE_MEMORY                   2
+#define GMC_SRC_SOURCE_HOST_DATA                3
+#define GMC_SRC_SOURCE_HOST_DATA_ALIGNED        4
+
 /* DP_GUI_MASTER_CNTL ROP3 named constants */
 #define GMC_ROP3_MASK                           0x00ff0000
-#define ROP3_BLACKNESS                          0x00000000
-#define ROP3_SRCCOPY                            0x00cc0000
-#define ROP3_PATCOPY                            0x00f00000
-#define ROP3_WHITENESS                          0x00ff0000
+#define ROP3_BLACKNESS                          0
+#define ROP3_SRCCOPY                            0xcc
+#define ROP3_PATCOPY                            0xf0
+#define ROP3_WHITENESS                          0xff
 
 #define SRC_DSTCOLOR                            0x00030000
 
@@ -434,6 +457,8 @@
 #define DST_POLY_EDGE                           0x00040000
 
 /* DP_MIX bit constants */
+#define DP_MIX_SRC_SOURCE_MASK                  0x00000700
+#define DP_MIX_ROP3_MASK                        0x00ff0000
 #define DP_SRC_RECT                             0x00000200
 #define DP_SRC_HOST                             0x00000300
 #define DP_SRC_HOST_BYTEALIGN                   0x00000400
-- 
2.51.2
Re: [PATCH v4 1/9] ati-vga: Store DP_DATATYPE and DP_MIX fields independently
Posted by BALATON Zoltan 1 month ago
On Tue, 6 Jan 2026, Chad Jablonski wrote:
> DP_GUI_MASTER_CNTL accesses the same values as DP_DATATYPE and DP_MIX.
> This was not reflected in how we stored register state. This meant that
> you could easily end up with stale state in one or the other register.
>
> This stores each field directly instead of packing them into a field
> named after the register. The register handlers then shift bits around
> if needed. This not only keeps things in sync but means less shifting
> and masking when using these values internally.
>
> Signed-off-by: Chad Jablonski <chad@jablonski.xyz>
> ---
> hw/display/ati.c      | 41 +++++++++++++++++++++++++++++++++--------
> hw/display/ati_2d.c   | 12 ++++++------
> hw/display/ati_int.h  | 10 ++++++++--
> hw/display/ati_regs.h | 33 +++++++++++++++++++++++++++++----
> 4 files changed, 76 insertions(+), 20 deletions(-)
[...]
> diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h
> index d7127748ff..fce9270635 100644
> --- a/hw/display/ati_regs.h
> +++ b/hw/display/ati_regs.h
> @@ -381,6 +381,12 @@
> #define PM4_BUFFER_CNTL_NONPM4                  0x00000000
>
> /* DP_DATATYPE bit constants */
> +#define DP_DATATYPE_DST_DATATYPE_MASK           0x0000000f
> +#define DP_DATATYPE_BRUSH_DATATYPE_MASK         0x00000f00
> +#define DP_DATATYPE_SRC_DATATYPE_MASK           0x00030000
> +#define DP_DATATYPE_HOST_BE_EN                  0x20000000
> +#define DP_DATATYPE_BYTE_PIX_ORDER              0x40000000
> +#define DP_DATATYPE_CONVERSION_TEMP             0x80000000
> #define DST_8BPP                                0x00000002
> #define DST_15BPP                               0x00000003
> #define DST_16BPP                               0x00000004
> @@ -394,6 +400,11 @@
> #define GMC_DST_PITCH_OFFSET_CNTL               0x00000002
> #define GMC_SRC_CLIP_DEFAULT                    0x00000000
> #define GMC_DST_CLIP_DEFAULT                    0x00000000
> +#define GMC_BRUSH_DATATYPE_MASK                 0x000000f0
> +#define GMC_DST_DATATYPE_MASK                   0x00000f00
> +#define GMC_SRC_DATATYPE_MASK                   0x00003000

This will probably be gone in next version but for naming I'd stick to the 
docs and use the names that it calls the fields as so no need to add _MASK 
as these names seem to be meant for the field so we can name the mask that 
extract that field like that so would just be GMC_SRC_DATATYPE and so on.

Regards,
BALATON Zoltan

> +#define GMC_BYTE_PIX_ORDER                      0x00004000
> +#define GMC_CONVERSION_TEMP                     0x00008000
> #define GMC_BRUSH_SOLIDCOLOR                    0x000000d0
> #define GMC_SRC_DSTCOLOR                        0x00003000
> #define GMC_BYTE_ORDER_MSB_TO_LSB               0x00000000
> @@ -404,12 +415,24 @@
> #define GMC_WRITE_MASK_SET                      0x40000000
> #define GMC_DP_CONVERSION_TEMP_6500             0x00000000
>
> +/* DP_GUI_MASTER_CNTL DP_SRC_DATATYPE named constants */
> +#define GMC_SRC_DATATYPE_MASK                   0x00003000
> +#define GMC_SRC_DATATYPE_MONO_FRGD_BKGD         0
> +#define GMC_SRC_DATATYPE_MONO_FRGD              1
> +#define GMC_SRC_DATATYPE_COLOR                  3
> +
> +/* DP_GUI_MASTER_CNTL DP_SRC_SOURCE named constants */
> +#define GMC_SRC_SOURCE_MASK                     0x07000000
> +#define GMC_SRC_SOURCE_MEMORY                   2
> +#define GMC_SRC_SOURCE_HOST_DATA                3
> +#define GMC_SRC_SOURCE_HOST_DATA_ALIGNED        4
> +
> /* DP_GUI_MASTER_CNTL ROP3 named constants */
> #define GMC_ROP3_MASK                           0x00ff0000
> -#define ROP3_BLACKNESS                          0x00000000
> -#define ROP3_SRCCOPY                            0x00cc0000
> -#define ROP3_PATCOPY                            0x00f00000
> -#define ROP3_WHITENESS                          0x00ff0000
> +#define ROP3_BLACKNESS                          0
> +#define ROP3_SRCCOPY                            0xcc
> +#define ROP3_PATCOPY                            0xf0
> +#define ROP3_WHITENESS                          0xff
>
> #define SRC_DSTCOLOR                            0x00030000
>
> @@ -434,6 +457,8 @@
> #define DST_POLY_EDGE                           0x00040000
>
> /* DP_MIX bit constants */
> +#define DP_MIX_SRC_SOURCE_MASK                  0x00000700
> +#define DP_MIX_ROP3_MASK                        0x00ff0000
> #define DP_SRC_RECT                             0x00000200
> #define DP_SRC_HOST                             0x00000300
> #define DP_SRC_HOST_BYTEALIGN                   0x00000400
>
Re: [PATCH v4 1/9] ati-vga: Store DP_DATATYPE and DP_MIX fields independently
Posted by BALATON Zoltan 1 month ago
On Tue, 6 Jan 2026, Chad Jablonski wrote:
> DP_GUI_MASTER_CNTL accesses the same values as DP_DATATYPE and DP_MIX.
> This was not reflected in how we stored register state. This meant that
> you could easily end up with stale state in one or the other register.
>
> This stores each field directly instead of packing them into a field
> named after the register. The register handlers then shift bits around
> if needed. This not only keeps things in sync but means less shifting
> and masking when using these values internally.
>
> Signed-off-by: Chad Jablonski <chad@jablonski.xyz>
> ---
> hw/display/ati.c      | 41 +++++++++++++++++++++++++++++++++--------
> hw/display/ati_2d.c   | 12 ++++++------
> hw/display/ati_int.h  | 10 ++++++++--
> hw/display/ati_regs.h | 33 +++++++++++++++++++++++++++++----
> 4 files changed, 76 insertions(+), 20 deletions(-)

If this made the code simpler I wouldn't be against it but this does not 
seem to save much as these values are either never used or not used often 
enough to store them separately but doing so makes the register 
read/writes more complex. It's easy enough to extract the needed fields 
from the regs into a local once at the beginning of a block where there 
are used and that way we at least store and return the unimplemented bits 
in the registers even if we do nothing with them yet without having to 
handle them separately. So I'm sorry it's causing you another rebase but I 
think we should drop this patch. I came to this conclusion after searching 
for the added uint8_t and bool fields after this series and most usages 
are in register read/write and the others that aren't often just compare 
to a constant that can be already shifted so maybe rop3 is the only one 
that might benefit but that can be stored in a local variable. As for 
which register to store them in as the authorative place I'd use the 
M6/RV100 register reference which lists DP_GUI_MASTER_CNTL fields as alias 
of other regs so maybe this patch only needs to fix the DP_GUI_MASTER_CNTL 
in mm_read to return the missing fields.

Regards,
BALATON Zoltan

> diff --git a/hw/display/ati.c b/hw/display/ati.c
> index e9c3ad2cd1..0bbe8915f1 100644
> --- a/hw/display/ati.c
> +++ b/hw/display/ati.c
> @@ -460,7 +460,14 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
>         val = s->regs.dst_y;
>         break;
>     case DP_GUI_MASTER_CNTL:
> -        val = s->regs.dp_gui_master_cntl;
> +        val = s->regs.dp_gui_master_cntl |
> +              (s->regs.dp_brush_datatype << 4) |
> +              (s->regs.dp_dst_datatype << 8) |
> +              (s->regs.dp_src_datatype << 12) |
> +              (s->regs.byte_pix_order << 14) |
> +              (s->regs.conversion_temp << 15) |
> +              (s->regs.dp_rop3 << 16) |
> +              (s->regs.dp_src_source << 24);
>         break;
>     case SRC_OFFSET:
>         val = s->regs.src_offset;
> @@ -487,10 +494,15 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
>         val = s->regs.dp_cntl;
>         break;
>     case DP_DATATYPE:
> -        val = s->regs.dp_datatype;
> +        val = (s->regs.dp_dst_datatype) |
> +              (s->regs.dp_brush_datatype << 8) |
> +              (s->regs.dp_src_datatype << 16) |
> +              (s->regs.host_big_endian_en << 29) |
> +              (s->regs.byte_pix_order << 30) |
> +              (s->regs.conversion_temp << 31);
>         break;
>     case DP_MIX:
> -        val = s->regs.dp_mix;
> +        val = (s->regs.dp_rop3 << 16) | (s->regs.dp_src_source << 8);
>         break;
>     case DP_WRITE_MASK:
>         val = s->regs.dp_write_mask;
> @@ -858,10 +870,17 @@ static void ati_mm_write(void *opaque, hwaddr addr,
>         ati_2d_blt(s);
>         break;
>     case DP_GUI_MASTER_CNTL:
> +        /* Mask out fields that are stored independently */
>         s->regs.dp_gui_master_cntl = data & 0xf800000f;
> -        s->regs.dp_datatype = (data & 0x0f00) >> 8 | (data & 0x30f0) << 4 |
> -                              (data & 0x4000) << 16;
> -        s->regs.dp_mix = (data & GMC_ROP3_MASK) | (data & 0x7000000) >> 16;
> +        /* DP_DATATYPE fields */
> +        s->regs.dp_brush_datatype = (data & GMC_BRUSH_DATATYPE_MASK) >> 4;
> +        s->regs.dp_dst_datatype = (data & GMC_DST_DATATYPE_MASK) >> 8;
> +        s->regs.dp_src_datatype = (data & GMC_SRC_DATATYPE_MASK) >> 12;
> +        s->regs.byte_pix_order = (data & GMC_BYTE_PIX_ORDER) >> 14;
> +        s->regs.conversion_temp = (data & GMC_CONVERSION_TEMP) >> 15;
> +        /* DP_MIX fields */
> +        s->regs.dp_rop3 = (data & GMC_ROP3_MASK) >> 16;
> +        s->regs.dp_src_source = (data & GMC_SRC_SOURCE_MASK) >> 24;
>         break;
>     case DST_WIDTH_X:
>         s->regs.dst_x = data & 0x3fff;
> @@ -910,10 +929,16 @@ static void ati_mm_write(void *opaque, hwaddr addr,
>         s->regs.dp_cntl = data;
>         break;
>     case DP_DATATYPE:
> -        s->regs.dp_datatype = data & 0xe0070f0f;
> +        s->regs.dp_dst_datatype = (data & DP_DATATYPE_DST_DATATYPE_MASK);
> +        s->regs.dp_brush_datatype = (data & DP_DATATYPE_BRUSH_DATATYPE_MASK) >> 8;
> +        s->regs.dp_src_datatype = (data & DP_DATATYPE_SRC_DATATYPE_MASK) >> 16;
> +        s->regs.host_big_endian_en = (data & DP_DATATYPE_HOST_BE_EN) >> 29;
> +        s->regs.byte_pix_order = (data & DP_DATATYPE_BYTE_PIX_ORDER) >> 30;
> +        s->regs.conversion_temp = (data & DP_DATATYPE_CONVERSION_TEMP) >> 31;
>         break;
>     case DP_MIX:
> -        s->regs.dp_mix = data & 0x00ff0700;
> +        s->regs.dp_src_source = (data & DP_MIX_SRC_SOURCE_MASK) >> 8;
> +        s->regs.dp_rop3 = (data & DP_MIX_ROP3_MASK) >> 16;
>         break;
>     case DP_WRITE_MASK:
>         s->regs.dp_write_mask = data;
> diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c
> index 309bb5ccb6..0531d1a526 100644
> --- a/hw/display/ati_2d.c
> +++ b/hw/display/ati_2d.c
> @@ -26,7 +26,7 @@
>
> static int ati_bpp_from_datatype(ATIVGAState *s)
> {
> -    switch (s->regs.dp_datatype & 0xf) {
> +    switch (s->regs.dp_dst_datatype) {
>     case 2:
>         return 8;
>     case 3:
> @@ -38,7 +38,7 @@ static int ati_bpp_from_datatype(ATIVGAState *s)
>         return 32;
>     default:
>         qemu_log_mask(LOG_UNIMP, "Unknown dst datatype %d\n",
> -                      s->regs.dp_datatype & 0xf);
> +                      s->regs.dp_dst_datatype);
>         return 0;
>     }
> }
> @@ -53,7 +53,7 @@ void ati_2d_blt(ATIVGAState *s)
>     DPRINTF("%p %u ds: %p %d %d rop: %x\n", s->vga.vram_ptr,
>             s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds),
>             surface_bits_per_pixel(ds),
> -            (s->regs.dp_mix & GMC_ROP3_MASK) >> 16);
> +            (s->regs.dp_rop3));
>     unsigned dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ?
>                       s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width);
>     unsigned dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ?
> @@ -89,7 +89,7 @@ void ati_2d_blt(ATIVGAState *s)
>             s->regs.dst_width, s->regs.dst_height,
>             (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? '>' : '<'),
>             (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? 'v' : '^'));
> -    switch (s->regs.dp_mix & GMC_ROP3_MASK) {
> +    switch (s->regs.dp_rop3) {
>     case ROP3_SRCCOPY:
>     {
>         bool fallback = false;
> @@ -191,7 +191,7 @@ void ati_2d_blt(ATIVGAState *s)
>     {
>         uint32_t filler = 0;
>
> -        switch (s->regs.dp_mix & GMC_ROP3_MASK) {
> +        switch (s->regs.dp_rop3) {
>         case ROP3_PATCOPY:
>             filler = s->regs.dp_brush_frgd_clr;
>             break;
> @@ -239,6 +239,6 @@ void ati_2d_blt(ATIVGAState *s)
>     }
>     default:
>         qemu_log_mask(LOG_UNIMP, "Unimplemented ati_2d blt op %x\n",
> -                      (s->regs.dp_mix & GMC_ROP3_MASK) >> 16);
> +                      s->regs.dp_rop3);
>     }
> }
> diff --git a/hw/display/ati_int.h b/hw/display/ati_int.h
> index f5a47b82b0..59a1812034 100644
> --- a/hw/display/ati_int.h
> +++ b/hw/display/ati_int.h
> @@ -75,13 +75,19 @@ typedef struct ATIVGARegs {
>     uint32_t dp_src_frgd_clr;
>     uint32_t dp_src_bkgd_clr;
>     uint32_t dp_cntl;
> -    uint32_t dp_datatype;
> -    uint32_t dp_mix;
>     uint32_t dp_write_mask;
>     uint32_t default_offset;
>     uint32_t default_pitch;
>     uint32_t default_tile;
>     uint32_t default_sc_bottom_right;
> +    uint8_t dp_src_source;
> +    uint8_t dp_rop3;
> +    uint8_t dp_dst_datatype;
> +    uint8_t dp_brush_datatype;
> +    uint8_t dp_src_datatype;
> +    bool host_big_endian_en;
> +    bool byte_pix_order;
> +    bool conversion_temp;
> } ATIVGARegs;
>
> struct ATIVGAState {
> diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h
> index d7127748ff..fce9270635 100644
> --- a/hw/display/ati_regs.h
> +++ b/hw/display/ati_regs.h
> @@ -381,6 +381,12 @@
> #define PM4_BUFFER_CNTL_NONPM4                  0x00000000
>
> /* DP_DATATYPE bit constants */
> +#define DP_DATATYPE_DST_DATATYPE_MASK           0x0000000f
> +#define DP_DATATYPE_BRUSH_DATATYPE_MASK         0x00000f00
> +#define DP_DATATYPE_SRC_DATATYPE_MASK           0x00030000
> +#define DP_DATATYPE_HOST_BE_EN                  0x20000000
> +#define DP_DATATYPE_BYTE_PIX_ORDER              0x40000000
> +#define DP_DATATYPE_CONVERSION_TEMP             0x80000000
> #define DST_8BPP                                0x00000002
> #define DST_15BPP                               0x00000003
> #define DST_16BPP                               0x00000004
> @@ -394,6 +400,11 @@
> #define GMC_DST_PITCH_OFFSET_CNTL               0x00000002
> #define GMC_SRC_CLIP_DEFAULT                    0x00000000
> #define GMC_DST_CLIP_DEFAULT                    0x00000000
> +#define GMC_BRUSH_DATATYPE_MASK                 0x000000f0
> +#define GMC_DST_DATATYPE_MASK                   0x00000f00
> +#define GMC_SRC_DATATYPE_MASK                   0x00003000
> +#define GMC_BYTE_PIX_ORDER                      0x00004000
> +#define GMC_CONVERSION_TEMP                     0x00008000
> #define GMC_BRUSH_SOLIDCOLOR                    0x000000d0
> #define GMC_SRC_DSTCOLOR                        0x00003000
> #define GMC_BYTE_ORDER_MSB_TO_LSB               0x00000000
> @@ -404,12 +415,24 @@
> #define GMC_WRITE_MASK_SET                      0x40000000
> #define GMC_DP_CONVERSION_TEMP_6500             0x00000000
>
> +/* DP_GUI_MASTER_CNTL DP_SRC_DATATYPE named constants */
> +#define GMC_SRC_DATATYPE_MASK                   0x00003000
> +#define GMC_SRC_DATATYPE_MONO_FRGD_BKGD         0
> +#define GMC_SRC_DATATYPE_MONO_FRGD              1
> +#define GMC_SRC_DATATYPE_COLOR                  3
> +
> +/* DP_GUI_MASTER_CNTL DP_SRC_SOURCE named constants */
> +#define GMC_SRC_SOURCE_MASK                     0x07000000
> +#define GMC_SRC_SOURCE_MEMORY                   2
> +#define GMC_SRC_SOURCE_HOST_DATA                3
> +#define GMC_SRC_SOURCE_HOST_DATA_ALIGNED        4
> +
> /* DP_GUI_MASTER_CNTL ROP3 named constants */
> #define GMC_ROP3_MASK                           0x00ff0000
> -#define ROP3_BLACKNESS                          0x00000000
> -#define ROP3_SRCCOPY                            0x00cc0000
> -#define ROP3_PATCOPY                            0x00f00000
> -#define ROP3_WHITENESS                          0x00ff0000
> +#define ROP3_BLACKNESS                          0
> +#define ROP3_SRCCOPY                            0xcc
> +#define ROP3_PATCOPY                            0xf0
> +#define ROP3_WHITENESS                          0xff
>
> #define SRC_DSTCOLOR                            0x00030000
>
> @@ -434,6 +457,8 @@
> #define DST_POLY_EDGE                           0x00040000
>
> /* DP_MIX bit constants */
> +#define DP_MIX_SRC_SOURCE_MASK                  0x00000700
> +#define DP_MIX_ROP3_MASK                        0x00ff0000
> #define DP_SRC_RECT                             0x00000200
> #define DP_SRC_HOST                             0x00000300
> #define DP_SRC_HOST_BYTEALIGN                   0x00000400
>
Re: [PATCH v4 1/9] ati-vga: Store DP_DATATYPE and DP_MIX fields independently
Posted by Chad Jablonski 1 month ago
>
> If this made the code simpler I wouldn't be against it but this does not 
> seem to save much as these values are either never used or not used often 
> enough to store them separately but doing so makes the register 
> read/writes more complex. It's easy enough to extract the needed fields 
> from the regs into a local once at the beginning of a block where there 
> are used and that way we at least store and return the unimplemented bits 
> in the registers even if we do nothing with them yet without having to 
> handle them separately. So I'm sorry it's causing you another rebase but I 
> think we should drop this patch. I came to this conclusion after searching 
> for the added uint8_t and bool fields after this series and most usages 
> are in register read/write and the others that aren't often just compare 
> to a constant that can be already shifted so maybe rop3 is the only one 
> that might benefit but that can be stored in a local variable. As for 
> which register to store them in as the authorative place I'd use the 
> M6/RV100 register reference which lists DP_GUI_MASTER_CNTL fields as alias 
> of other regs so maybe this patch only needs to fix the DP_GUI_MASTER_CNTL 
> in mm_read to return the missing fields.
>

Fair enough! Not a problem at all. I've been struggling to decide when to
split out state like this and this gives me an idea of how to think about
it in general. I'll store these values in DP_MIX and DP_DATATYPE and fix
the DP_GUI_MASTER_CNTL read in V5.