1 |
/* |
/* |
2 |
* QEMU Sun4m System Emulator |
* QEMU TCX Frame buffer |
3 |
* |
* |
4 |
* Copyright (c) 2003-2004 Fabrice Bellard |
* Copyright (c) 2003-2005 Fabrice Bellard |
5 |
* |
* |
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
7 |
* of this software and associated documentation files (the "Software"), to deal |
* of this software and associated documentation files (the "Software"), to deal |
25 |
|
|
26 |
#define MAXX 1024 |
#define MAXX 1024 |
27 |
#define MAXY 768 |
#define MAXY 768 |
28 |
/* |
#define TCX_DAC_NREGS 16 |
|
* Proll uses only small part of display, we need to switch to full |
|
|
* display when we get linux framebuffer console or X11 running. For |
|
|
* now it's just slower and awkward. |
|
|
*/ |
|
|
#if 1 |
|
|
#define XSZ (8*80) |
|
|
#define YSZ (24*11) |
|
|
#define XOFF (MAXX-XSZ) |
|
|
#define YOFF (MAXY-YSZ) |
|
|
#else |
|
|
#define XSZ MAXX |
|
|
#define YSZ MAXY |
|
|
#define XOFF 0 |
|
|
#define YOFF 0 |
|
|
#endif |
|
29 |
|
|
30 |
typedef struct TCXState { |
typedef struct TCXState { |
31 |
uint32_t addr; |
uint32_t addr; |
32 |
DisplayState *ds; |
DisplayState *ds; |
33 |
uint8_t *vram; |
uint8_t *vram; |
34 |
unsigned long vram_offset; |
unsigned long vram_offset; |
35 |
|
uint16_t width, height; |
36 |
uint8_t r[256], g[256], b[256]; |
uint8_t r[256], g[256], b[256]; |
37 |
|
uint8_t dac_index, dac_state; |
38 |
} TCXState; |
} TCXState; |
39 |
|
|
40 |
static void tcx_draw_line32(TCXState *s1, uint8_t *d, |
static void tcx_draw_line32(TCXState *s1, uint8_t *d, |
45 |
|
|
46 |
for(x = 0; x < width; x++) { |
for(x = 0; x < width; x++) { |
47 |
val = *s++; |
val = *s++; |
|
*d++ = s1->r[val]; |
|
|
*d++ = s1->g[val]; |
|
48 |
*d++ = s1->b[val]; |
*d++ = s1->b[val]; |
49 |
|
*d++ = s1->g[val]; |
50 |
|
*d++ = s1->r[val]; |
51 |
d++; |
d++; |
52 |
} |
} |
53 |
} |
} |
60 |
|
|
61 |
for(x = 0; x < width; x++) { |
for(x = 0; x < width; x++) { |
62 |
val = *s++; |
val = *s++; |
|
*d++ = s1->r[val]; |
|
|
*d++ = s1->g[val]; |
|
63 |
*d++ = s1->b[val]; |
*d++ = s1->b[val]; |
64 |
|
*d++ = s1->g[val]; |
65 |
|
*d++ = s1->r[val]; |
66 |
} |
} |
67 |
} |
} |
68 |
|
|
91 |
|
|
92 |
if (ts->ds->depth == 0) |
if (ts->ds->depth == 0) |
93 |
return; |
return; |
94 |
page = ts->vram_offset + YOFF*MAXX; |
page = ts->vram_offset; |
95 |
y_start = -1; |
y_start = -1; |
96 |
page_min = 0x7fffffff; |
page_min = 0x7fffffff; |
97 |
page_max = -1; |
page_max = -1; |
98 |
d = ts->ds->data; |
d = ts->ds->data; |
99 |
s = ts->vram + YOFF*MAXX + XOFF; |
s = ts->vram; |
100 |
dd = ts->ds->linesize; |
dd = ts->ds->linesize; |
101 |
ds = 1024; |
ds = 1024; |
102 |
|
|
115 |
return; |
return; |
116 |
} |
} |
117 |
|
|
118 |
for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) { |
for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { |
119 |
if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) { |
if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) { |
120 |
if (y_start < 0) |
if (y_start < 0) |
121 |
y_start = y; |
y_start = y; |
123 |
page_min = page; |
page_min = page; |
124 |
if (page > page_max) |
if (page > page_max) |
125 |
page_max = page; |
page_max = page; |
126 |
f(ts, d, s, XSZ); |
f(ts, d, s, ts->width); |
127 |
d += dd; |
d += dd; |
128 |
s += ds; |
s += ds; |
129 |
f(ts, d, s, XSZ); |
f(ts, d, s, ts->width); |
130 |
d += dd; |
d += dd; |
131 |
s += ds; |
s += ds; |
132 |
f(ts, d, s, XSZ); |
f(ts, d, s, ts->width); |
133 |
d += dd; |
d += dd; |
134 |
s += ds; |
s += ds; |
135 |
f(ts, d, s, XSZ); |
f(ts, d, s, ts->width); |
136 |
d += dd; |
d += dd; |
137 |
s += ds; |
s += ds; |
138 |
} else { |
} else { |
139 |
if (y_start >= 0) { |
if (y_start >= 0) { |
140 |
/* flush to display */ |
/* flush to display */ |
141 |
dpy_update(ts->ds, 0, y_start, |
dpy_update(ts->ds, 0, y_start, |
142 |
XSZ, y - y_start); |
ts->width, y - y_start); |
143 |
y_start = -1; |
y_start = -1; |
144 |
} |
} |
145 |
d += dd * 4; |
d += dd * 4; |
149 |
if (y_start >= 0) { |
if (y_start >= 0) { |
150 |
/* flush to display */ |
/* flush to display */ |
151 |
dpy_update(ts->ds, 0, y_start, |
dpy_update(ts->ds, 0, y_start, |
152 |
XSZ, y - y_start); |
ts->width, y - y_start); |
153 |
} |
} |
154 |
/* reset modified pages */ |
/* reset modified pages */ |
155 |
if (page_max != -1) { |
if (page_max != -1) { |
174 |
|
|
175 |
qemu_put_be32s(f, (uint32_t *)&s->addr); |
qemu_put_be32s(f, (uint32_t *)&s->addr); |
176 |
qemu_put_be32s(f, (uint32_t *)&s->vram); |
qemu_put_be32s(f, (uint32_t *)&s->vram); |
177 |
|
qemu_put_be16s(f, (uint16_t *)&s->height); |
178 |
|
qemu_put_be16s(f, (uint16_t *)&s->width); |
179 |
qemu_put_buffer(f, s->r, 256); |
qemu_put_buffer(f, s->r, 256); |
180 |
qemu_put_buffer(f, s->g, 256); |
qemu_put_buffer(f, s->g, 256); |
181 |
qemu_put_buffer(f, s->b, 256); |
qemu_put_buffer(f, s->b, 256); |
182 |
|
qemu_put_8s(f, &s->dac_index); |
183 |
|
qemu_put_8s(f, &s->dac_state); |
184 |
} |
} |
185 |
|
|
186 |
static int tcx_load(QEMUFile *f, void *opaque, int version_id) |
static int tcx_load(QEMUFile *f, void *opaque, int version_id) |
192 |
|
|
193 |
qemu_get_be32s(f, (uint32_t *)&s->addr); |
qemu_get_be32s(f, (uint32_t *)&s->addr); |
194 |
qemu_get_be32s(f, (uint32_t *)&s->vram); |
qemu_get_be32s(f, (uint32_t *)&s->vram); |
195 |
|
qemu_get_be16s(f, (uint16_t *)&s->height); |
196 |
|
qemu_get_be16s(f, (uint16_t *)&s->width); |
197 |
qemu_get_buffer(f, s->r, 256); |
qemu_get_buffer(f, s->r, 256); |
198 |
qemu_get_buffer(f, s->g, 256); |
qemu_get_buffer(f, s->g, 256); |
199 |
qemu_get_buffer(f, s->b, 256); |
qemu_get_buffer(f, s->b, 256); |
200 |
|
qemu_get_8s(f, &s->dac_index); |
201 |
|
qemu_get_8s(f, &s->dac_state); |
202 |
return 0; |
return 0; |
203 |
} |
} |
204 |
|
|
214 |
memset(s->vram, 0, MAXX*MAXY); |
memset(s->vram, 0, MAXX*MAXY); |
215 |
cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY, |
cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY, |
216 |
VGA_DIRTY_FLAG); |
VGA_DIRTY_FLAG); |
217 |
|
s->dac_index = 0; |
218 |
|
s->dac_state = 0; |
219 |
|
} |
220 |
|
|
221 |
|
static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr) |
222 |
|
{ |
223 |
|
return 0; |
224 |
} |
} |
225 |
|
|
226 |
|
static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
227 |
|
{ |
228 |
|
TCXState *s = opaque; |
229 |
|
uint32_t saddr; |
230 |
|
|
231 |
|
saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2; |
232 |
|
switch (saddr) { |
233 |
|
case 0: |
234 |
|
s->dac_index = val >> 24; |
235 |
|
s->dac_state = 0; |
236 |
|
break; |
237 |
|
case 1: |
238 |
|
switch (s->dac_state) { |
239 |
|
case 0: |
240 |
|
s->r[s->dac_index] = val >> 24; |
241 |
|
s->dac_state++; |
242 |
|
break; |
243 |
|
case 1: |
244 |
|
s->g[s->dac_index] = val >> 24; |
245 |
|
s->dac_state++; |
246 |
|
break; |
247 |
|
case 2: |
248 |
|
s->b[s->dac_index] = val >> 24; |
249 |
|
default: |
250 |
|
s->dac_state = 0; |
251 |
|
break; |
252 |
|
} |
253 |
|
break; |
254 |
|
default: |
255 |
|
break; |
256 |
|
} |
257 |
|
return; |
258 |
|
} |
259 |
|
|
260 |
|
static CPUReadMemoryFunc *tcx_dac_read[3] = { |
261 |
|
tcx_dac_readl, |
262 |
|
tcx_dac_readl, |
263 |
|
tcx_dac_readl, |
264 |
|
}; |
265 |
|
|
266 |
|
static CPUWriteMemoryFunc *tcx_dac_write[3] = { |
267 |
|
tcx_dac_writel, |
268 |
|
tcx_dac_writel, |
269 |
|
tcx_dac_writel, |
270 |
|
}; |
271 |
|
|
272 |
void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, |
void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, |
273 |
unsigned long vram_offset, int vram_size) |
unsigned long vram_offset, int vram_size, int width, int height) |
274 |
{ |
{ |
275 |
TCXState *s; |
TCXState *s; |
276 |
|
int io_memory; |
277 |
|
|
278 |
s = qemu_mallocz(sizeof(TCXState)); |
s = qemu_mallocz(sizeof(TCXState)); |
279 |
if (!s) |
if (!s) |
282 |
s->addr = addr; |
s->addr = addr; |
283 |
s->vram = vram_base; |
s->vram = vram_base; |
284 |
s->vram_offset = vram_offset; |
s->vram_offset = vram_offset; |
285 |
|
s->width = width; |
286 |
|
s->height = height; |
287 |
|
|
288 |
cpu_register_physical_memory(addr, vram_size, vram_offset); |
cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset); |
289 |
|
io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s); |
290 |
|
cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory); |
291 |
|
|
292 |
register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); |
register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); |
293 |
qemu_register_reset(tcx_reset, s); |
qemu_register_reset(tcx_reset, s); |
294 |
tcx_reset(s); |
tcx_reset(s); |
295 |
dpy_resize(s->ds, XSZ, YSZ); |
dpy_resize(s->ds, width, height); |
296 |
return s; |
return s; |
297 |
} |
} |
298 |
|
|
306 |
f = fopen(filename, "wb"); |
f = fopen(filename, "wb"); |
307 |
if (!f) |
if (!f) |
308 |
return; |
return; |
309 |
fprintf(f, "P6\n%d %d\n%d\n", XSZ, YSZ, 255); |
fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); |
310 |
d1 = s->vram + YOFF*MAXX + XOFF; |
d1 = s->vram; |
311 |
for(y = 0; y < YSZ; y++) { |
for(y = 0; y < s->height; y++) { |
312 |
d = d1; |
d = d1; |
313 |
for(x = 0; x < XSZ; x++) { |
for(x = 0; x < s->width; x++) { |
314 |
v = *d; |
v = *d; |
315 |
fputc(s->r[v], f); |
fputc(s->r[v], f); |
316 |
fputc(s->g[v], f); |
fputc(s->g[v], f); |