Commit 0add30cff44d681d0490b167e666c39d4d7b1e8d

Authored by aurel32
1 parent f0f2f976

G364 video adapter enhancement

This patch improves G364 video card emulation (used in MIPS Magnum machine):
- Use memory dirty tracking to not refresh whole screen each time
- Use macros for debugging messages
- Add support for hardware cursor
- Handle Y-panning
- Raise irq at each screen redraw
- Support retrieving of some registers
- Add load/save support

The emulation has been tested in Linux 2.1 and Windows NT 3.5, in
640x480, 800x600, 1024x768 and 1280x1024 resolutions.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6356 c046a42c-6fe2-441c-8c8c-71466251a162
hw/g364fb.c
1 /* 1 /*
2 * QEMU G364 framebuffer Emulator. 2 * QEMU G364 framebuffer Emulator.
3 * 3 *
4 - * Copyright (c) 2007-2008 Hervé Poussineau 4 + * Copyright (c) 2007-2009 Herve Poussineau
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as 7 * modify it under the terms of the GNU General Public License as
@@ -25,140 +25,275 @@ @@ -25,140 +25,275 @@
25 25
26 //#define DEBUG_G364 26 //#define DEBUG_G364
27 27
  28 +#ifdef DEBUG_G364
  29 +#define DPRINTF(fmt, args...) \
  30 +do { printf("g364: " fmt , ##args); } while (0)
  31 +#else
  32 +#define DPRINTF(fmt, args...) do {} while (0)
  33 +#endif
  34 +#define BADF(fmt, args...) \
  35 +do { fprintf(stderr, "g364 ERROR: " fmt , ##args);} while (0)
  36 +
28 typedef struct G364State { 37 typedef struct G364State {
29 - unsigned int vram_size;  
30 - uint8_t *vram_buffer; 38 + /* hardware */
  39 + uint8_t *vram;
  40 + ram_addr_t vram_offset;
  41 + int vram_size;
  42 + qemu_irq irq;
  43 + /* registers */
  44 + uint8_t color_palette[256][3];
  45 + uint8_t cursor_palette[3][3];
  46 + uint16_t cursor[512];
  47 + uint32_t cursor_position;
31 uint32_t ctla; 48 uint32_t ctla;
32 - uint8_t palette[256][3]; 49 + uint32_t top_of_screen;
  50 + uint32_t width, height; /* in pixels */
33 /* display refresh support */ 51 /* display refresh support */
34 DisplayState *ds; 52 DisplayState *ds;
35 - int graphic_mode;  
36 - uint32_t scr_width, scr_height; /* in pixels */ 53 + int depth;
  54 + int blanked;
37 } G364State; 55 } G364State;
38 56
39 -/*  
40 - * graphic modes  
41 - */  
42 -#define BPP 8  
43 -#define PIXEL_WIDTH 8  
44 -#include "g364fb_template.h"  
45 -#undef BPP  
46 -#undef PIXEL_WIDTH  
47 -  
48 -#define BPP 15  
49 -#define PIXEL_WIDTH 16  
50 -#include "g364fb_template.h"  
51 -#undef BPP  
52 -#undef PIXEL_WIDTH  
53 -  
54 -#define BPP 16  
55 -#define PIXEL_WIDTH 16  
56 -#include "g364fb_template.h"  
57 -#undef BPP  
58 -#undef PIXEL_WIDTH  
59 -  
60 -#define BPP 32  
61 -#define PIXEL_WIDTH 32  
62 -#include "g364fb_template.h"  
63 -#undef BPP  
64 -#undef PIXEL_WIDTH  
65 -  
66 -#define REG_DISPLAYX 0x0918  
67 -#define REG_DISPLAYY 0x0940  
68 -  
69 -#define CTLA_FORCE_BLANK 0x400  
70 -  
71 -static void g364fb_draw_graphic(G364State *s, int full_update) 57 +#define REG_ID 0x000000
  58 +#define REG_BOOT 0x080000
  59 +#define REG_DISPLAY 0x080118
  60 +#define REG_VDISPLAY 0x080150
  61 +#define REG_CTLA 0x080300
  62 +#define REG_TOP 0x080400
  63 +#define REG_CURS_PAL 0x080508
  64 +#define REG_CURS_POS 0x080638
  65 +#define REG_CLR_PAL 0x080800
  66 +#define REG_CURS_PAT 0x081000
  67 +#define REG_RESET 0x180000
  68 +
  69 +#define CTLA_FORCE_BLANK 0x00000400
  70 +#define CTLA_NO_CURSOR 0x00800000
  71 +
  72 +static inline int check_dirty(ram_addr_t page)
  73 +{
  74 + return cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
  75 +}
  76 +
  77 +static inline void reset_dirty(G364State *s,
  78 + ram_addr_t page_min, ram_addr_t page_max)
  79 +{
  80 + cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE - 1,
  81 + VGA_DIRTY_FLAG);
  82 +}
  83 +
  84 +static void g364fb_draw_graphic8(G364State *s)
72 { 85 {
  86 + int i, w;
  87 + uint8_t *vram;
  88 + uint8_t *data_display, *dd;
  89 + ram_addr_t page, page_min, page_max;
  90 + int x, y;
  91 + int xmin, xmax;
  92 + int ymin, ymax;
  93 + int xcursor, ycursor;
  94 + unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);
  95 +
73 switch (ds_get_bits_per_pixel(s->ds)) { 96 switch (ds_get_bits_per_pixel(s->ds)) {
74 case 8: 97 case 8:
75 - g364fb_draw_graphic8(s, full_update); 98 + rgb_to_pixel = rgb_to_pixel8;
  99 + w = 1;
76 break; 100 break;
77 case 15: 101 case 15:
78 - g364fb_draw_graphic15(s, full_update); 102 + rgb_to_pixel = rgb_to_pixel15;
  103 + w = 2;
79 break; 104 break;
80 case 16: 105 case 16:
81 - g364fb_draw_graphic16(s, full_update); 106 + rgb_to_pixel = rgb_to_pixel16;
  107 + w = 2;
82 break; 108 break;
83 case 32: 109 case 32:
84 - g364fb_draw_graphic32(s, full_update); 110 + rgb_to_pixel = rgb_to_pixel32;
  111 + w = 4;
85 break; 112 break;
86 default: 113 default:
87 - printf("g364fb: unknown depth %d\n", ds_get_bits_per_pixel(s->ds)); 114 + BADF("unknown host depth %d\n", ds_get_bits_per_pixel(s->ds));
88 return; 115 return;
89 } 116 }
90 117
91 - dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); 118 + page = s->vram_offset;
  119 + page_min = (ram_addr_t)-1;
  120 + page_max = 0;
  121 +
  122 + x = y = 0;
  123 + xmin = s->width;
  124 + xmax = 0;
  125 + ymin = s->height;
  126 + ymax = 0;
  127 +
  128 + if (!(s->ctla & CTLA_NO_CURSOR)) {
  129 + xcursor = s->cursor_position >> 12;
  130 + ycursor = s->cursor_position & 0xfff;
  131 + } else {
  132 + xcursor = ycursor = -65;
  133 + }
  134 +
  135 + vram = s->vram + s->top_of_screen;
  136 + /* XXX: out of range in vram? */
  137 + data_display = dd = ds_get_data(s->ds);
  138 + while (y < s->height) {
  139 + if (check_dirty(page)) {
  140 + if (y < ymin)
  141 + ymin = ymax = y;
  142 + if (page_min == (ram_addr_t)-1)
  143 + page_min = page;
  144 + page_max = page;
  145 + if (x < xmin)
  146 + xmin = x;
  147 + for (i = 0; i < TARGET_PAGE_SIZE; i++) {
  148 + uint8_t index;
  149 + unsigned int color;
  150 + if (unlikely((y >= ycursor && y < ycursor + 64) &&
  151 + (x >= xcursor && x < xcursor + 64))) {
  152 + /* pointer area */
  153 + int xdiff = x - xcursor;
  154 + uint16_t curs = s->cursor[(y - ycursor) * 8 + xdiff / 8];
  155 + int op = (curs >> ((xdiff & 7) * 2)) & 3;
  156 + if (likely(op == 0)) {
  157 + /* transparent */
  158 + index = *vram;
  159 + color = (*rgb_to_pixel)(
  160 + s->color_palette[index][0],
  161 + s->color_palette[index][1],
  162 + s->color_palette[index][2]);
  163 + } else {
  164 + /* get cursor color */
  165 + index = op - 1;
  166 + color = (*rgb_to_pixel)(
  167 + s->cursor_palette[index][0],
  168 + s->cursor_palette[index][1],
  169 + s->cursor_palette[index][2]);
  170 + }
  171 + } else {
  172 + /* normal area */
  173 + index = *vram;
  174 + color = (*rgb_to_pixel)(
  175 + s->color_palette[index][0],
  176 + s->color_palette[index][1],
  177 + s->color_palette[index][2]);
  178 + }
  179 + memcpy(dd, &color, w);
  180 + dd += w;
  181 + x++;
  182 + vram++;
  183 + if (x == s->width) {
  184 + xmax = s->width - 1;
  185 + y++;
  186 + if (y == s->height) {
  187 + ymax = s->height - 1;
  188 + goto done;
  189 + }
  190 + data_display = dd = data_display + ds_get_linesize(s->ds);
  191 + xmin = 0;
  192 + x = 0;
  193 + }
  194 + }
  195 + if (x > xmax)
  196 + xmax = x;
  197 + if (y > ymax)
  198 + ymax = y;
  199 + } else {
  200 + int dy;
  201 + if (page_min != (ram_addr_t)-1) {
  202 + reset_dirty(s, page_min, page_max);
  203 + page_min = (ram_addr_t)-1;
  204 + page_max = 0;
  205 + dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
  206 + xmin = s->width;
  207 + xmax = 0;
  208 + ymin = s->height;
  209 + ymax = 0;
  210 + }
  211 + x += TARGET_PAGE_SIZE;
  212 + dy = x / s->width;
  213 + x = x % s->width;
  214 + y += dy;
  215 + vram += TARGET_PAGE_SIZE;
  216 + data_display += dy * ds_get_linesize(s->ds);
  217 + dd = data_display + x * w;
  218 + }
  219 + page += TARGET_PAGE_SIZE;
  220 + }
  221 +
  222 +done:
  223 + if (page_min != (ram_addr_t)-1) {
  224 + dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
  225 + reset_dirty(s, page_min, page_max);
  226 + }
92 } 227 }
93 228
94 -static void g364fb_draw_blank(G364State *s, int full_update) 229 +static void g364fb_draw_blank(G364State *s)
95 { 230 {
96 int i, w; 231 int i, w;
97 uint8_t *d; 232 uint8_t *d;
98 233
99 - if (!full_update) 234 + if (s->blanked) {
  235 + /* Screen is already blank. No need to redraw it */
100 return; 236 return;
  237 + }
101 238
102 - w = s->scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); 239 + w = s->width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
103 d = ds_get_data(s->ds); 240 d = ds_get_data(s->ds);
104 - for(i = 0; i < s->scr_height; i++) { 241 + for (i = 0; i < s->height; i++) {
105 memset(d, 0, w); 242 memset(d, 0, w);
106 d += ds_get_linesize(s->ds); 243 d += ds_get_linesize(s->ds);
107 } 244 }
108 245
109 - dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); 246 + dpy_update(s->ds, 0, 0, s->width, s->height);
  247 + s->blanked = 1;
110 } 248 }
111 249
112 -#define GMODE_GRAPH 0  
113 -#define GMODE_BLANK 1  
114 -  
115 static void g364fb_update_display(void *opaque) 250 static void g364fb_update_display(void *opaque)
116 { 251 {
117 G364State *s = opaque; 252 G364State *s = opaque;
118 - int full_update, graphic_mode;  
119 253
120 - if (s->scr_width == 0 || s->scr_height == 0) 254 + if (s->width == 0 || s->height == 0)
121 return; 255 return;
122 256
123 - if (s->ctla & CTLA_FORCE_BLANK)  
124 - graphic_mode = GMODE_BLANK;  
125 - else  
126 - graphic_mode = GMODE_GRAPH;  
127 - full_update = 0;  
128 - if (graphic_mode != s->graphic_mode) {  
129 - s->graphic_mode = graphic_mode;  
130 - full_update = 1;  
131 - }  
132 - if (s->scr_width != ds_get_width(s->ds) || s->scr_height != ds_get_height(s->ds)) {  
133 - qemu_console_resize(s->ds, s->scr_width, s->scr_height);  
134 - full_update = 1; 257 + if (s->width != ds_get_width(s->ds) || s->height != ds_get_height(s->ds)) {
  258 + qemu_console_resize(s->ds, s->width, s->height);
135 } 259 }
136 - switch(graphic_mode) {  
137 - case GMODE_GRAPH:  
138 - g364fb_draw_graphic(s, full_update);  
139 - break;  
140 - case GMODE_BLANK:  
141 - default:  
142 - g364fb_draw_blank(s, full_update);  
143 - break; 260 +
  261 + if (s->ctla & CTLA_FORCE_BLANK) {
  262 + g364fb_draw_blank(s);
  263 + } else if (s->depth == 8) {
  264 + g364fb_draw_graphic8(s);
  265 + } else {
  266 + BADF("unknown guest depth %d\n", s->depth);
144 } 267 }
  268 +
  269 + qemu_irq_raise(s->irq);
145 } 270 }
146 271
147 -/* force a full display refresh */  
148 -static void g364fb_invalidate_display(void *opaque) 272 +static void inline g364fb_invalidate_display(void *opaque)
149 { 273 {
150 G364State *s = opaque; 274 G364State *s = opaque;
151 - s->graphic_mode = -1; /* force full update */ 275 + int i;
  276 +
  277 + s->blanked = 0;
  278 + for (i = 0; i < s->vram_size; i += TARGET_PAGE_SIZE) {
  279 + cpu_physical_memory_set_dirty(s->vram_offset + i);
  280 + }
152 } 281 }
153 282
154 static void g364fb_reset(void *opaque) 283 static void g364fb_reset(void *opaque)
155 { 284 {
156 G364State *s = opaque; 285 G364State *s = opaque;
157 -  
158 - memset(s->palette, 0, sizeof(s->palette));  
159 - s->scr_width = s->scr_height = 0;  
160 - memset(s->vram_buffer, 0, s->vram_size);  
161 - s->graphic_mode = -1; /* force full update */ 286 + qemu_irq_lower(s->irq);
  287 +
  288 + memset(s->color_palette, 0, sizeof(s->color_palette));
  289 + memset(s->cursor_palette, 0, sizeof(s->cursor_palette));
  290 + memset(s->cursor, 0, sizeof(s->cursor));
  291 + s->cursor_position = 0;
  292 + s->ctla = 0;
  293 + s->top_of_screen = 0;
  294 + s->width = s->height = 0;
  295 + memset(s->vram, 0, s->vram_size);
  296 + g364fb_invalidate_display(opaque);
162 } 297 }
163 298
164 static void g364fb_screen_dump(void *opaque, const char *filename) 299 static void g364fb_screen_dump(void *opaque, const char *filename)
@@ -169,117 +304,223 @@ static void g364fb_screen_dump(void *opaque, const char *filename) @@ -169,117 +304,223 @@ static void g364fb_screen_dump(void *opaque, const char *filename)
169 uint8_t *data_buffer; 304 uint8_t *data_buffer;
170 FILE *f; 305 FILE *f;
171 306
  307 + if (s->depth != 8) {
  308 + BADF("unknown guest depth %d\n", s->depth);
  309 + return;
  310 + }
  311 +
172 f = fopen(filename, "wb"); 312 f = fopen(filename, "wb");
173 if (!f) 313 if (!f)
174 return; 314 return;
175 315
176 - data_buffer = s->vram_buffer;  
177 - fprintf(f, "P6\n%d %d\n%d\n",  
178 - s->scr_width, s->scr_height, 255);  
179 - for(y = 0; y < s->scr_height; y++)  
180 - for(x = 0; x < s->scr_width; x++, data_buffer++) {  
181 - index = *data_buffer;  
182 - fputc(s->palette[index][0], f);  
183 - fputc(s->palette[index][1], f);  
184 - fputc(s->palette[index][2], f); 316 + if (s->ctla & CTLA_FORCE_BLANK) {
  317 + /* blank screen */
  318 + fprintf(f, "P4\n%d %d\n",
  319 + s->width, s->height);
  320 + for (y = 0; y < s->height; y++)
  321 + for (x = 0; x < s->width; x++)
  322 + fputc(0, f);
  323 + } else {
  324 + data_buffer = s->vram + s->top_of_screen;
  325 + fprintf(f, "P6\n%d %d\n%d\n",
  326 + s->width, s->height, 255);
  327 + for (y = 0; y < s->height; y++)
  328 + for (x = 0; x < s->width; x++, data_buffer++) {
  329 + index = *data_buffer;
  330 + fputc(s->color_palette[index][0], f);
  331 + fputc(s->color_palette[index][1], f);
  332 + fputc(s->color_palette[index][2], f);
185 } 333 }
  334 + }
  335 +
186 fclose(f); 336 fclose(f);
187 } 337 }
188 338
189 /* called for accesses to io ports */ 339 /* called for accesses to io ports */
190 -static uint32_t g364fb_ctrl_readb(void *opaque, target_phys_addr_t addr) 340 +static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr)
191 { 341 {
192 - //G364State *s = opaque; 342 + G364State *s = opaque;
193 uint32_t val; 343 uint32_t val;
194 344
195 - addr &= 0xffff;  
196 -  
197 - switch (addr) {  
198 - default:  
199 -#ifdef DEBUG_G364  
200 - printf("g364fb/ctrl: invalid read at [" TARGET_FMT_lx "]\n", addr);  
201 -#endif  
202 - val = 0;  
203 - break; 345 + if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
  346 + /* cursor pattern */
  347 + int idx = (addr - REG_CURS_PAT) >> 3;
  348 + val = s->cursor[idx];
  349 + } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
  350 + /* cursor palette */
  351 + int idx = (addr - REG_CURS_PAL) >> 3;
  352 + val = ((uint32_t)s->cursor_palette[idx][0] << 16);
  353 + val |= ((uint32_t)s->cursor_palette[idx][1] << 8);
  354 + val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
  355 + } else {
  356 + switch (addr) {
  357 + case REG_ID:
  358 + val = 0x10; /* Mips G364 */
  359 + break;
  360 + case REG_DISPLAY:
  361 + val = s->width / 4;
  362 + break;
  363 + case REG_VDISPLAY:
  364 + val = s->height * 2;
  365 + break;
  366 + case REG_CTLA:
  367 + val = s->ctla;
  368 + break;
  369 + default:
  370 + {
  371 + BADF("invalid read at [" TARGET_FMT_plx "]\n", addr);
  372 + val = 0;
  373 + break;
  374 + }
  375 + }
204 } 376 }
205 377
206 -#ifdef DEBUG_G364  
207 - printf("g364fb/ctrl: read 0x%02x at [" TARGET_FMT_lx "]\n", val, addr);  
208 -#endif 378 + DPRINTF("read 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
209 379
210 return val; 380 return val;
211 } 381 }
212 382
213 static uint32_t g364fb_ctrl_readw(void *opaque, target_phys_addr_t addr) 383 static uint32_t g364fb_ctrl_readw(void *opaque, target_phys_addr_t addr)
214 { 384 {
215 - uint32_t v;  
216 - v = g364fb_ctrl_readb(opaque, addr);  
217 - v |= g364fb_ctrl_readb(opaque, addr + 1) << 8;  
218 - return v; 385 + uint32_t v = g364fb_ctrl_readl(opaque, addr & ~0x3);
  386 + if (addr & 0x2)
  387 + return v >> 16;
  388 + else
  389 + return v & 0xffff;
219 } 390 }
220 391
221 -static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr) 392 +static uint32_t g364fb_ctrl_readb(void *opaque, target_phys_addr_t addr)
222 { 393 {
223 - uint32_t v;  
224 - v = g364fb_ctrl_readb(opaque, addr);  
225 - v |= g364fb_ctrl_readb(opaque, addr + 1) << 8;  
226 - v |= g364fb_ctrl_readb(opaque, addr + 2) << 16;  
227 - v |= g364fb_ctrl_readb(opaque, addr + 3) << 24;  
228 - return v; 394 + uint32_t v = g364fb_ctrl_readl(opaque, addr & ~0x3);
  395 + return (v >> (8 * (addr & 0x3))) & 0xff;
229 } 396 }
230 397
231 -static void g364fb_ctrl_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) 398 +static void g364fb_update_depth(G364State *s)
232 { 399 {
233 - G364State *s = opaque; 400 + const static int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
  401 + s->depth = depths[(s->ctla & 0x00700000) >> 20];
  402 +}
234 403
235 - addr &= 0xffff; 404 +static void g364_invalidate_cursor_position(G364State *s)
  405 +{
  406 + int ymin, ymax, start, end, i;
236 407
237 -#ifdef DEBUG_G364  
238 - printf("g364fb/ctrl: write 0x%02x at [" TARGET_FMT_lx "]\n", val, addr);  
239 -#endif 408 + /* invalidate only near the cursor */
  409 + ymin = s->cursor_position & 0xfff;
  410 + ymax = MIN(s->height, ymin + 64);
  411 + start = ymin * ds_get_linesize(s->ds);
  412 + end = (ymax + 1) * ds_get_linesize(s->ds);
240 413
241 - if (addr < 0x0800) { 414 + for (i = start; i < end; i += TARGET_PAGE_SIZE) {
  415 + cpu_physical_memory_set_dirty(s->vram_offset + i);
  416 + }
  417 +}
  418 +
  419 +static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
  420 +{
  421 + G364State *s = opaque;
  422 +
  423 + DPRINTF("write 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
  424 +
  425 + if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
242 /* color palette */ 426 /* color palette */
243 - int idx = addr >> 3;  
244 - int c = addr & 7;  
245 - if (c < 3)  
246 - s->palette[idx][c] = (uint8_t)val; 427 + int idx = (addr - REG_CLR_PAL) >> 3;
  428 + s->color_palette[idx][0] = (val >> 16) & 0xff;
  429 + s->color_palette[idx][1] = (val >> 8) & 0xff;
  430 + s->color_palette[idx][2] = val & 0xff;
  431 + g364fb_invalidate_display(s);
  432 + } else if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
  433 + /* cursor pattern */
  434 + int idx = (addr - REG_CURS_PAT) >> 3;
  435 + s->cursor[idx] = val;
  436 + g364fb_invalidate_display(s);
  437 + } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
  438 + /* cursor palette */
  439 + int idx = (addr - REG_CURS_PAL) >> 3;
  440 + s->cursor_palette[idx][0] = (val >> 16) & 0xff;
  441 + s->cursor_palette[idx][1] = (val >> 8) & 0xff;
  442 + s->cursor_palette[idx][2] = val & 0xff;
  443 + g364fb_invalidate_display(s);
247 } else { 444 } else {
248 switch (addr) { 445 switch (addr) {
249 - case REG_DISPLAYX:  
250 - s->scr_width = (s->scr_width & 0xfffffc03) | (val << 2); 446 + case REG_ID: /* Card identifier; read-only */
  447 + case REG_BOOT: /* Boot timing */
  448 + case 0x80108: /* Line timing: half sync */
  449 + case 0x80110: /* Line timing: back porch */
  450 + case 0x80120: /* Line timing: short display */
  451 + case 0x80128: /* Frame timing: broad pulse */
  452 + case 0x80130: /* Frame timing: v sync */
  453 + case 0x80138: /* Frame timing: v preequalise */
  454 + case 0x80140: /* Frame timing: v postequalise */
  455 + case 0x80148: /* Frame timing: v blank */
  456 + case 0x80158: /* Line timing: line time */
  457 + case 0x80160: /* Frame store: line start */
  458 + case 0x80168: /* vram cycle: mem init */
  459 + case 0x80170: /* vram cycle: transfer delay */
  460 + case 0x80200: /* vram cycle: mask register */
  461 + /* ignore */
  462 + break;
  463 + case REG_TOP:
  464 + s->top_of_screen = val;
  465 + g364fb_invalidate_display(s);
  466 + break;
  467 + case REG_DISPLAY:
  468 + s->width = val * 4;
251 break; 469 break;
252 - case REG_DISPLAYX + 1:  
253 - s->scr_width = (s->scr_width & 0xfffc03ff) | (val << 10); 470 + case REG_VDISPLAY:
  471 + s->height = val / 2;
254 break; 472 break;
255 - case REG_DISPLAYY:  
256 - s->scr_height = (s->scr_height & 0xffffff80) | (val >> 1); 473 + case REG_CTLA:
  474 + s->ctla = val;
  475 + g364fb_update_depth(s);
  476 + g364fb_invalidate_display(s);
257 break; 477 break;
258 - case REG_DISPLAYY + 1:  
259 - s->scr_height = (s->scr_height & 0xffff801f) | (val << 7); 478 + case REG_CURS_POS:
  479 + g364_invalidate_cursor_position(s);
  480 + s->cursor_position = val;
  481 + g364_invalidate_cursor_position(s);
  482 + break;
  483 + case REG_RESET:
  484 + g364fb_reset(s);
260 break; 485 break;
261 default: 486 default:
262 -#ifdef DEBUG_G364  
263 - printf("g364fb/ctrl: invalid write of 0x%02x at [" TARGET_FMT_lx "]\n", val, addr);  
264 -#endif 487 + BADF("invalid write of 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
265 break; 488 break;
266 } 489 }
267 } 490 }
268 - s->graphic_mode = -1; /* force full update */ 491 + qemu_irq_lower(s->irq);
269 } 492 }
270 493
271 static void g364fb_ctrl_writew(void *opaque, target_phys_addr_t addr, uint32_t val) 494 static void g364fb_ctrl_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
272 { 495 {
273 - g364fb_ctrl_writeb(opaque, addr, val & 0xff);  
274 - g364fb_ctrl_writeb(opaque, addr + 1, (val >> 8) & 0xff); 496 + uint32_t old_val = g364fb_ctrl_readl(opaque, addr & ~0x3);
  497 +
  498 + if (addr & 0x2)
  499 + val = (val << 16) | (old_val & 0x0000ffff);
  500 + else
  501 + val = val | (old_val & 0xffff0000);
  502 + g364fb_ctrl_writel(opaque, addr & ~0x3, val);
275 } 503 }
276 504
277 -static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t val) 505 +static void g364fb_ctrl_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
278 { 506 {
279 - g364fb_ctrl_writeb(opaque, addr, val & 0xff);  
280 - g364fb_ctrl_writeb(opaque, addr + 1, (val >> 8) & 0xff);  
281 - g364fb_ctrl_writeb(opaque, addr + 2, (val >> 16) & 0xff);  
282 - g364fb_ctrl_writeb(opaque, addr + 3, (val >> 24) & 0xff); 507 + uint32_t old_val = g364fb_ctrl_readl(opaque, addr & ~0x3);
  508 +
  509 + switch (addr & 3) {
  510 + case 0:
  511 + val = val | (old_val & 0xffffff00);
  512 + break;
  513 + case 1:
  514 + val = (val << 8) | (old_val & 0xffff00ff);
  515 + break;
  516 + case 2:
  517 + val = (val << 16) | (old_val & 0xff00ffff);
  518 + break;
  519 + case 3:
  520 + val = (val << 24) | (old_val & 0x00ffffff);
  521 + break;
  522 + }
  523 + g364fb_ctrl_writel(opaque, addr & ~0x3, val);
283 } 524 }
284 525
285 static CPUReadMemoryFunc *g364fb_ctrl_read[3] = { 526 static CPUReadMemoryFunc *g364fb_ctrl_read[3] = {
@@ -294,90 +535,84 @@ static CPUWriteMemoryFunc *g364fb_ctrl_write[3] = { @@ -294,90 +535,84 @@ static CPUWriteMemoryFunc *g364fb_ctrl_write[3] = {
294 g364fb_ctrl_writel, 535 g364fb_ctrl_writel,
295 }; 536 };
296 537
297 -/* called for accesses to video ram */  
298 -static uint32_t g364fb_mem_readb(void *opaque, target_phys_addr_t addr) 538 +static int g364fb_load(QEMUFile *f, void *opaque, int version_id)
299 { 539 {
300 G364State *s = opaque; 540 G364State *s = opaque;
  541 + unsigned int i, vram_size;
  542 +
  543 + if (version_id != 1)
  544 + return -EINVAL;
  545 +
  546 + vram_size = qemu_get_be32(f);
  547 + if (vram_size < s->vram_size)
  548 + return -EINVAL;
  549 + qemu_get_buffer(f, s->vram, s->vram_size);
  550 + for (i = 0; i < 256; i++)
  551 + qemu_get_buffer(f, s->color_palette[i], 3);
  552 + for (i = 0; i < 3; i++)
  553 + qemu_get_buffer(f, s->cursor_palette[i], 3);
  554 + qemu_get_buffer(f, (uint8_t *)s->cursor, sizeof(s->cursor));
  555 + s->cursor_position = qemu_get_be32(f);
  556 + s->ctla = qemu_get_be32(f);
  557 + s->top_of_screen = qemu_get_be32(f);
  558 + s->width = qemu_get_be32(f);
  559 + s->height = qemu_get_be32(f);
  560 +
  561 + /* force refresh */
  562 + g364fb_update_depth(s);
  563 + g364fb_invalidate_display(s);
301 564
302 - return s->vram_buffer[addr];  
303 -}  
304 -  
305 -static uint32_t g364fb_mem_readw(void *opaque, target_phys_addr_t addr)  
306 -{  
307 - uint32_t v;  
308 - v = g364fb_mem_readb(opaque, addr);  
309 - v |= g364fb_mem_readb(opaque, addr + 1) << 8;  
310 - return v;  
311 -}  
312 -  
313 -static uint32_t g364fb_mem_readl(void *opaque, target_phys_addr_t addr)  
314 -{  
315 - uint32_t v;  
316 - v = g364fb_mem_readb(opaque, addr);  
317 - v |= g364fb_mem_readb(opaque, addr + 1) << 8;  
318 - v |= g364fb_mem_readb(opaque, addr + 2) << 16;  
319 - v |= g364fb_mem_readb(opaque, addr + 3) << 24;  
320 - return v; 565 + return 0;
321 } 566 }
322 567
323 -static void g364fb_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) 568 +static void g364fb_save(QEMUFile *f, void *opaque)
324 { 569 {
325 G364State *s = opaque; 570 G364State *s = opaque;
326 -  
327 - s->vram_buffer[addr] = val; 571 + int i;
  572 +
  573 + qemu_put_be32(f, s->vram_size);
  574 + qemu_put_buffer(f, s->vram, s->vram_size);
  575 + for (i = 0; i < 256; i++)
  576 + qemu_put_buffer(f, s->color_palette[i], 3);
  577 + for (i = 0; i < 3; i++)
  578 + qemu_put_buffer(f, s->cursor_palette[i], 3);
  579 + qemu_put_buffer(f, (uint8_t *)s->cursor, sizeof(s->cursor));
  580 + qemu_put_be32(f, s->cursor_position);
  581 + qemu_put_be32(f, s->ctla);
  582 + qemu_put_be32(f, s->top_of_screen);
  583 + qemu_put_be32(f, s->width);
  584 + qemu_put_be32(f, s->height);
328 } 585 }
329 586
330 -static void g364fb_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)  
331 -{  
332 - g364fb_mem_writeb(opaque, addr, val & 0xff);  
333 - g364fb_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);  
334 -}  
335 -  
336 -static void g364fb_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)  
337 -{  
338 - g364fb_mem_writeb(opaque, addr, val & 0xff);  
339 - g364fb_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);  
340 - g364fb_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);  
341 - g364fb_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);  
342 -}  
343 -  
344 -static CPUReadMemoryFunc *g364fb_mem_read[3] = {  
345 - g364fb_mem_readb,  
346 - g364fb_mem_readw,  
347 - g364fb_mem_readl,  
348 -};  
349 -  
350 -static CPUWriteMemoryFunc *g364fb_mem_write[3] = {  
351 - g364fb_mem_writeb,  
352 - g364fb_mem_writew,  
353 - g364fb_mem_writel,  
354 -};  
355 -  
356 -int g364fb_mm_init(int vram_size, int it_shift,  
357 - target_phys_addr_t vram_base, target_phys_addr_t ctrl_base) 587 +int g364fb_mm_init(uint8_t *vram, ram_addr_t vram_offset,
  588 + int vram_size, target_phys_addr_t vram_base,
  589 + target_phys_addr_t ctrl_base, int it_shift,
  590 + qemu_irq irq)
358 { 591 {
359 G364State *s; 592 G364State *s;
360 - int io_vram, io_ctrl; 593 + int io_ctrl;
361 594
362 s = qemu_mallocz(sizeof(G364State)); 595 s = qemu_mallocz(sizeof(G364State));
363 if (!s) 596 if (!s)
364 return -1; 597 return -1;
365 598
  599 + s->vram = vram;
  600 + s->vram_offset = vram_offset;
366 s->vram_size = vram_size; 601 s->vram_size = vram_size;
367 - s->vram_buffer = qemu_mallocz(s->vram_size); 602 + s->irq = irq;
368 603
369 qemu_register_reset(g364fb_reset, s); 604 qemu_register_reset(g364fb_reset, s);
  605 + register_savevm("g364fb", 0, 1, g364fb_save, g364fb_load, s);
370 g364fb_reset(s); 606 g364fb_reset(s);
371 607
372 s->ds = graphic_console_init(g364fb_update_display, 608 s->ds = graphic_console_init(g364fb_update_display,
373 g364fb_invalidate_display, 609 g364fb_invalidate_display,
374 g364fb_screen_dump, NULL, s); 610 g364fb_screen_dump, NULL, s);
375 611
376 - io_vram = cpu_register_io_memory(0, g364fb_mem_read, g364fb_mem_write, s);  
377 - cpu_register_physical_memory(vram_base, vram_size, io_vram); 612 + cpu_register_physical_memory(vram_base, s->vram_size, s->vram_offset);
378 613
379 io_ctrl = cpu_register_io_memory(0, g364fb_ctrl_read, g364fb_ctrl_write, s); 614 io_ctrl = cpu_register_io_memory(0, g364fb_ctrl_read, g364fb_ctrl_write, s);
380 - cpu_register_physical_memory(ctrl_base, 0x10000, io_ctrl); 615 + cpu_register_physical_memory(ctrl_base, 0x200000, io_ctrl);
381 616
382 return 0; 617 return 0;
383 } 618 }
hw/g364fb_template.h deleted 100644 → 0
1 -/*  
2 - * QEMU G364 framebuffer Emulator.  
3 - *  
4 - * Copyright (c) 2007 Hervé Poussineau  
5 - *  
6 - * This program is free software; you can redistribute it and/or  
7 - * modify it under the terms of the GNU General Public License as  
8 - * published by the Free Software Foundation; either version 2 of  
9 - * the License, or (at your option) any later version.  
10 - *  
11 - * This program is distributed in the hope that it will be useful,  
12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of  
13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
14 - * GNU General Public License for more details.  
15 - *  
16 - * You should have received a copy of the GNU General Public License along  
17 - * with this program; if not, write to the Free Software Foundation, Inc.,  
18 - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.  
19 - */  
20 -  
21 -static void glue(g364fb_draw_graphic, BPP)(G364State *s, int full_update)  
22 -{  
23 - int i, j;  
24 - int w_display;  
25 - uint8_t *data_buffer;  
26 - uint8_t *data_display, *dd;  
27 -  
28 - data_buffer = s->vram_buffer;  
29 - w_display = s->scr_width * PIXEL_WIDTH / 8;  
30 - data_display = ds_get_data(s->ds);  
31 - for(i = 0; i < s->scr_height; i++) {  
32 - dd = data_display;  
33 - for (j = 0; j < s->scr_width; j++, dd += PIXEL_WIDTH / 8, data_buffer++) {  
34 - uint8_t index = *data_buffer;  
35 - *((glue(glue(uint, PIXEL_WIDTH), _t) *)dd) = glue(rgb_to_pixel, BPP)(  
36 - s->palette[index][0],  
37 - s->palette[index][1],  
38 - s->palette[index][2]);  
39 - }  
40 - data_display += ds_get_linesize(s->ds);  
41 - }  
42 -}  
hw/mips.h
@@ -10,8 +10,10 @@ void *ds1225y_init(target_phys_addr_t mem_base, const char *filename); @@ -10,8 +10,10 @@ void *ds1225y_init(target_phys_addr_t mem_base, const char *filename);
10 void ds1225y_set_protection(void *opaque, int protection); 10 void ds1225y_set_protection(void *opaque, int protection);
11 11
12 /* g364fb.c */ 12 /* g364fb.c */
13 -int g364fb_mm_init(int vram_size, int it_shift,  
14 - target_phys_addr_t vram_base, target_phys_addr_t ctrl_base); 13 +int g364fb_mm_init(uint8_t *vram, ram_addr_t vram_offset,
  14 + int vram_size, target_phys_addr_t vram_base,
  15 + target_phys_addr_t ctrl_base, int it_shift,
  16 + qemu_irq irq);
15 17
16 /* mipsnet.c */ 18 /* mipsnet.c */
17 void mipsnet_init(int base, qemu_irq irq, NICInfo *nd); 19 void mipsnet_init(int base, qemu_irq irq, NICInfo *nd);
hw/mips_jazz.c
@@ -201,7 +201,8 @@ void mips_jazz_init (ram_addr_t ram_size, int vga_ram_size, @@ -201,7 +201,8 @@ void mips_jazz_init (ram_addr_t ram_size, int vga_ram_size,
201 /* Video card */ 201 /* Video card */
202 switch (jazz_model) { 202 switch (jazz_model) {
203 case JAZZ_MAGNUM: 203 case JAZZ_MAGNUM:
204 - g364fb_mm_init(vga_ram_size, 0, 0x40000000, 0x60000000); 204 + g364fb_mm_init(phys_ram_base + ram_size, ram_size, vga_ram_size,
  205 + 0x40000000, 0x60000000, 0, rc4030[3]);
205 break; 206 break;
206 case JAZZ_PICA61: 207 case JAZZ_PICA61:
207 isa_vga_mm_init(phys_ram_base + ram_size, ram_size, vga_ram_size, 208 isa_vga_mm_init(phys_ram_base + ram_size, ram_size, vga_ram_size,