@samitouri / QOSamiQemu / commits / 69051f7293

ati-vga: Implement HOST_DATA register writes

Writing to any of the HOST_DATA0-7 registers pushes the written data into a 128-bit accumulator. When the accumulator is full a flush is triggered to copy it to the framebuffer. A final write to HOST_DATA_LAST will also initiate a flush. The flush itself is left for the next patch. Unaligned HOST_DATA* writes result in, from what I can tell, undefined behavior on real hardware. A well-behaved driver shouldn't be doing this anyway. For that reason they are not handled here at all. Signed-off-by: Chad Jablonski <chad@jablonski.xyz> Reviewed-by: BALATON Zoltan <balaton@eik.bme.hu> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> Message-ID: <235adb69787c818afd023e7f32286166cc70744c.1773020351.git.balaton@eik.bme.hu> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Chad Jablonski committed Mar 9, 2026 at 02:47 UTC 69051f729317337d58c3f847efbb8593a5a0ba26
4 files changed +53
hw/display/ati.c
+26
@@ -1023,6 +1023,27 @@ static void ati_mm_write(void *opaque, hwaddr addr,
1023 case SRC_SC_BOTTOM:
1024 s->regs.src_sc_bottom = data & 0x3fff;
1025 break;
1026 + case HOST_DATA0:
1027 + case HOST_DATA1:
1028 + case HOST_DATA2:
1029 + case HOST_DATA3:
1030 + case HOST_DATA4:
1031 + case HOST_DATA5:
1032 + case HOST_DATA6:
1033 + case HOST_DATA7:
1034 + case HOST_DATA_LAST:
1035 + if (!s->host_data.active) {
1036 + break;
1037 + }
1038 + s->host_data.acc[s->host_data.next++] = data;
1039 + if (addr == HOST_DATA_LAST) {
1040 + qemu_log_mask(LOG_UNIMP, "HOST_DATA finish not yet implemented\n");
1041 + s->host_data.next = 0;
1042 + } else if (s->host_data.next >= 4) {
1043 + qemu_log_mask(LOG_UNIMP, "HOST_DATA flush not yet implemented\n");
1044 + s->host_data.next = 0;
1045 + }
1046 + break;
1047 default:
1048 break;
1049 }
@@ -1128,6 +1149,11 @@ static void ati_vga_reset(DeviceState *dev)
1149 /* reset vga */
1150 vga_common_reset(&s->vga);
1151 s->mode = VGA_MODE;
1152 +
1153 + s->host_data.active = false;
1154 + s->host_data.next = 0;
1155 + s->host_data.row = 0;
1156 + s->host_data.col = 0;
1157 }
1158
1159 static void ati_vga_exit(PCIDevice *dev)
hw/display/ati_dbg.c
+9
@@ -252,6 +252,15 @@ static struct ati_regdesc ati_reg_names[] = {
252 {"MC_SRC1_CNTL", 0x19D8},
253 {"TEX_CNTL", 0x1800},
254 {"RAGE128_MPP_TB_CONFIG", 0x01c0},
255 + {"HOST_DATA0", 0x17c0},
256 + {"HOST_DATA1", 0x17c4},
257 + {"HOST_DATA2", 0x17c8},
258 + {"HOST_DATA3", 0x17cc},
259 + {"HOST_DATA4", 0x17d0},
260 + {"HOST_DATA5", 0x17d4},
261 + {"HOST_DATA6", 0x17d8},
262 + {"HOST_DATA7", 0x17dc},
263 + {"HOST_DATA_LAST", 0x17e0},
264 {NULL, -1}
265 };
266
hw/display/ati_int.h
+9
@@ -96,6 +96,14 @@ typedef struct ATIVGARegs {
96 uint32_t default_tile;
97 } ATIVGARegs;
98
99 +typedef struct ATIHostDataState {
100 + bool active;
101 + uint32_t row;
102 + uint32_t col;
103 + uint32_t next;
104 + uint32_t acc[4];
105 +} ATIHostDataState;
106 +
107 struct ATIVGAState {
108 PCIDevice dev;
109 VGACommonState vga;
@@ -114,6 +122,7 @@ struct ATIVGAState {
122 MemoryRegion io;
123 MemoryRegion mm;
124 ATIVGARegs regs;
125 + ATIHostDataState host_data;
126 };
127
128 const char *ati_reg_name(int num);
hw/display/ati_regs.h
+9
@@ -252,6 +252,15 @@
252 #define DP_T12_CNTL 0x178c
253 #define DST_BRES_T1_LNTH 0x1790
254 #define DST_BRES_T2_LNTH 0x1794
255 +#define HOST_DATA0 0x17c0
256 +#define HOST_DATA1 0x17c4
257 +#define HOST_DATA2 0x17c8
258 +#define HOST_DATA3 0x17cc
259 +#define HOST_DATA4 0x17d0
260 +#define HOST_DATA5 0x17d4
261 +#define HOST_DATA6 0x17d8
262 +#define HOST_DATA7 0x17dc
263 +#define HOST_DATA_LAST 0x17e0
264 #define SCALE_SRC_HEIGHT_WIDTH 0x1994
265 #define SCALE_OFFSET_0 0x1998
266 #define SCALE_PITCH 0x199c