2 * QEMU TCX Frame buffer
4 * Copyright (c) 2003-2005 Fabrice Bellard
6 * 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
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 #define TCX_DAC_NREGS 16
30 typedef struct TCXState
{
34 unsigned long vram_offset
;
35 uint16_t width
, height
;
36 uint8_t r
[256], g
[256], b
[256];
37 uint8_t dac_index
, dac_state
;
40 static void tcx_screen_dump(void *opaque
, const char *filename
);
42 static void tcx_draw_line32(TCXState
*s1
, uint8_t *d
,
43 const uint8_t *s
, int width
)
48 for(x
= 0; x
< width
; x
++) {
57 static void tcx_draw_line24(TCXState
*s1
, uint8_t *d
,
58 const uint8_t *s
, int width
)
63 for(x
= 0; x
< width
; x
++) {
71 static void tcx_draw_line8(TCXState
*s1
, uint8_t *d
,
72 const uint8_t *s
, int width
)
77 for(x
= 0; x
< width
; x
++) {
79 /* XXX translate between palettes? */
84 /* Fixed line length 1024 allows us to do nice tricks not possible on
86 static void tcx_update_display(void *opaque
)
88 TCXState
*ts
= opaque
;
90 int y
, page_min
, page_max
, y_start
, dd
, ds
;
92 void (*f
)(TCXState
*s1
, uint8_t *d
, const uint8_t *s
, int width
);
94 if (ts
->ds
->depth
== 0)
96 page
= ts
->vram_offset
;
98 page_min
= 0x7fffffff;
102 dd
= ts
->ds
->linesize
;
105 switch (ts
->ds
->depth
) {
120 for(y
= 0; y
< ts
->height
; y
+= 4, page
+= TARGET_PAGE_SIZE
) {
121 if (cpu_physical_memory_get_dirty(page
, VGA_DIRTY_FLAG
)) {
128 f(ts
, d
, s
, ts
->width
);
131 f(ts
, d
, s
, ts
->width
);
134 f(ts
, d
, s
, ts
->width
);
137 f(ts
, d
, s
, ts
->width
);
142 /* flush to display */
143 dpy_update(ts
->ds
, 0, y_start
,
144 ts
->width
, y
- y_start
);
152 /* flush to display */
153 dpy_update(ts
->ds
, 0, y_start
,
154 ts
->width
, y
- y_start
);
156 /* reset modified pages */
157 if (page_max
!= -1) {
158 cpu_physical_memory_reset_dirty(page_min
, page_max
+ TARGET_PAGE_SIZE
,
163 static void tcx_invalidate_display(void *opaque
)
165 TCXState
*s
= opaque
;
168 for (i
= 0; i
< MAXX
*MAXY
; i
+= TARGET_PAGE_SIZE
) {
169 cpu_physical_memory_set_dirty(s
->vram_offset
+ i
);
173 static void tcx_save(QEMUFile
*f
, void *opaque
)
175 TCXState
*s
= opaque
;
177 qemu_put_be32s(f
, (uint32_t *)&s
->addr
);
178 qemu_put_be32s(f
, (uint32_t *)&s
->vram
);
179 qemu_put_be16s(f
, (uint16_t *)&s
->height
);
180 qemu_put_be16s(f
, (uint16_t *)&s
->width
);
181 qemu_put_buffer(f
, s
->r
, 256);
182 qemu_put_buffer(f
, s
->g
, 256);
183 qemu_put_buffer(f
, s
->b
, 256);
184 qemu_put_8s(f
, &s
->dac_index
);
185 qemu_put_8s(f
, &s
->dac_state
);
188 static int tcx_load(QEMUFile
*f
, void *opaque
, int version_id
)
190 TCXState
*s
= opaque
;
195 qemu_get_be32s(f
, (uint32_t *)&s
->addr
);
196 qemu_get_be32s(f
, (uint32_t *)&s
->vram
);
197 qemu_get_be16s(f
, (uint16_t *)&s
->height
);
198 qemu_get_be16s(f
, (uint16_t *)&s
->width
);
199 qemu_get_buffer(f
, s
->r
, 256);
200 qemu_get_buffer(f
, s
->g
, 256);
201 qemu_get_buffer(f
, s
->b
, 256);
202 qemu_get_8s(f
, &s
->dac_index
);
203 qemu_get_8s(f
, &s
->dac_state
);
207 static void tcx_reset(void *opaque
)
209 TCXState
*s
= opaque
;
211 /* Initialize palette */
212 memset(s
->r
, 0, 256);
213 memset(s
->g
, 0, 256);
214 memset(s
->b
, 0, 256);
215 s
->r
[255] = s
->g
[255] = s
->b
[255] = 255;
216 memset(s
->vram
, 0, MAXX
*MAXY
);
217 cpu_physical_memory_reset_dirty(s
->vram_offset
, s
->vram_offset
+ MAXX
*MAXY
,
223 static uint32_t tcx_dac_readl(void *opaque
, target_phys_addr_t addr
)
228 static void tcx_dac_writel(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
230 TCXState
*s
= opaque
;
233 saddr
= (addr
& (TCX_DAC_NREGS
- 1)) >> 2;
236 s
->dac_index
= val
>> 24;
240 switch (s
->dac_state
) {
242 s
->r
[s
->dac_index
] = val
>> 24;
246 s
->g
[s
->dac_index
] = val
>> 24;
250 s
->b
[s
->dac_index
] = val
>> 24;
262 static CPUReadMemoryFunc
*tcx_dac_read
[3] = {
268 static CPUWriteMemoryFunc
*tcx_dac_write
[3] = {
274 void tcx_init(DisplayState
*ds
, uint32_t addr
, uint8_t *vram_base
,
275 unsigned long vram_offset
, int vram_size
, int width
, int height
)
280 s
= qemu_mallocz(sizeof(TCXState
));
286 s
->vram_offset
= vram_offset
;
290 cpu_register_physical_memory(addr
+ 0x800000, vram_size
, vram_offset
);
291 io_memory
= cpu_register_io_memory(0, tcx_dac_read
, tcx_dac_write
, s
);
292 cpu_register_physical_memory(addr
+ 0x200000, TCX_DAC_NREGS
, io_memory
);
294 graphic_console_init(s
->ds
, tcx_update_display
, tcx_invalidate_display
,
296 register_savevm("tcx", addr
, 1, tcx_save
, tcx_load
, s
);
297 qemu_register_reset(tcx_reset
, s
);
299 dpy_resize(s
->ds
, width
, height
);
302 static void tcx_screen_dump(void *opaque
, const char *filename
)
304 TCXState
*s
= opaque
;
309 f
= fopen(filename
, "wb");
312 fprintf(f
, "P6\n%d %d\n%d\n", s
->width
, s
->height
, 255);
314 for(y
= 0; y
< s
->height
; y
++) {
316 for(x
= 0; x
< s
->width
; x
++) {