Revision 0add30cf hw/g364fb.c
b/hw/g364fb.c | ||
---|---|---|
1 | 1 |
/* |
2 | 2 |
* QEMU G364 framebuffer Emulator. |
3 | 3 |
* |
4 |
* Copyright (c) 2007-2008 Hervé Poussineau
|
|
4 |
* Copyright (c) 2007-2009 Herve Poussineau
|
|
5 | 5 |
* |
6 | 6 |
* This program is free software; you can redistribute it and/or |
7 | 7 |
* modify it under the terms of the GNU General Public License as |
... | ... | |
25 | 25 |
|
26 | 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 | 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 | 48 |
uint32_t ctla; |
32 |
uint8_t palette[256][3]; |
|
49 |
uint32_t top_of_screen; |
|
50 |
uint32_t width, height; /* in pixels */ |
|
33 | 51 |
/* display refresh support */ |
34 | 52 |
DisplayState *ds; |
35 |
int graphic_mode;
|
|
36 |
uint32_t scr_width, scr_height; /* in pixels */
|
|
53 |
int depth;
|
|
54 |
int blanked;
|
|
37 | 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 | 96 |
switch (ds_get_bits_per_pixel(s->ds)) { |
74 | 97 |
case 8: |
75 |
g364fb_draw_graphic8(s, full_update); |
|
98 |
rgb_to_pixel = rgb_to_pixel8; |
|
99 |
w = 1; |
|
76 | 100 |
break; |
77 | 101 |
case 15: |
78 |
g364fb_draw_graphic15(s, full_update); |
|
102 |
rgb_to_pixel = rgb_to_pixel15; |
|
103 |
w = 2; |
|
79 | 104 |
break; |
80 | 105 |
case 16: |
81 |
g364fb_draw_graphic16(s, full_update); |
|
106 |
rgb_to_pixel = rgb_to_pixel16; |
|
107 |
w = 2; |
|
82 | 108 |
break; |
83 | 109 |
case 32: |
84 |
g364fb_draw_graphic32(s, full_update); |
|
110 |
rgb_to_pixel = rgb_to_pixel32; |
|
111 |
w = 4; |
|
85 | 112 |
break; |
86 | 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 | 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 | 231 |
int i, w; |
97 | 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 | 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 | 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 | 242 |
memset(d, 0, w); |
106 | 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 | 250 |
static void g364fb_update_display(void *opaque) |
116 | 251 |
{ |
117 | 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 | 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 | 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 | 283 |
static void g364fb_reset(void *opaque) |
155 | 284 |
{ |
156 | 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 | 299 |
static void g364fb_screen_dump(void *opaque, const char *filename) |
... | ... | |
169 | 304 |
uint8_t *data_buffer; |
170 | 305 |
FILE *f; |
171 | 306 |
|
307 |
if (s->depth != 8) { |
|
308 |
BADF("unknown guest depth %d\n", s->depth); |
|
309 |
return; |
|
310 |
} |
|
311 |
|
|
172 | 312 |
f = fopen(filename, "wb"); |
173 | 313 |
if (!f) |
174 | 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 | 336 |
fclose(f); |
187 | 337 |
} |
188 | 338 |
|
189 | 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 | 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 | 380 |
return val; |
211 | 381 |
} |
212 | 382 |
|
213 | 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 | 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 | 444 |
} else { |
248 | 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 | 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 | 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 | 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 | 485 |
break; |
261 | 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 | 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 | 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 | 526 |
static CPUReadMemoryFunc *g364fb_ctrl_read[3] = { |
... | ... | |
294 | 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 | 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 | 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 | 592 |
G364State *s; |
360 |
int io_vram, io_ctrl;
|
|
593 |
int io_ctrl; |
|
361 | 594 |
|
362 | 595 |
s = qemu_mallocz(sizeof(G364State)); |
363 | 596 |
if (!s) |
364 | 597 |
return -1; |
365 | 598 |
|
599 |
s->vram = vram; |
|
600 |
s->vram_offset = vram_offset; |
|
366 | 601 |
s->vram_size = vram_size; |
367 |
s->vram_buffer = qemu_mallocz(s->vram_size);
|
|
602 |
s->irq = irq;
|
|
368 | 603 |
|
369 | 604 |
qemu_register_reset(g364fb_reset, s); |
605 |
register_savevm("g364fb", 0, 1, g364fb_save, g364fb_load, s); |
|
370 | 606 |
g364fb_reset(s); |
371 | 607 |
|
372 | 608 |
s->ds = graphic_console_init(g364fb_update_display, |
373 | 609 |
g364fb_invalidate_display, |
374 | 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 | 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 | 617 |
return 0; |
383 | 618 |
} |
Also available in: Unified diff