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_draw_line32(TCXState
*s1
, uint8_t *d
,
41 const uint8_t *s
, int width
)
46 for(x
= 0; x
< width
; x
++) {
55 static void tcx_draw_line24(TCXState
*s1
, uint8_t *d
,
56 const uint8_t *s
, int width
)
61 for(x
= 0; x
< width
; x
++) {
69 static void tcx_draw_line8(TCXState
*s1
, uint8_t *d
,
70 const uint8_t *s
, int width
)
75 for(x
= 0; x
< width
; x
++) {
77 /* XXX translate between palettes? */
82 /* Fixed line length 1024 allows us to do nice tricks not possible on
84 void tcx_update_display(void *opaque
)
86 TCXState
*ts
= opaque
;
88 int y
, page_min
, page_max
, y_start
, dd
, ds
;
90 void (*f
)(TCXState
*s1
, uint8_t *d
, const uint8_t *s
, int width
);
92 if (ts
->ds
->depth
== 0)
94 page
= ts
->vram_offset
;
96 page_min
= 0x7fffffff;
100 dd
= ts
->ds
->linesize
;
103 switch (ts
->ds
->depth
) {
118 for(y
= 0; y
< ts
->height
; y
+= 4, page
+= TARGET_PAGE_SIZE
) {
119 if (cpu_physical_memory_get_dirty(page
, VGA_DIRTY_FLAG
)) {
126 f(ts
, d
, s
, ts
->width
);
129 f(ts
, d
, s
, ts
->width
);
132 f(ts
, d
, s
, ts
->width
);
135 f(ts
, d
, s
, ts
->width
);
140 /* flush to display */
141 dpy_update(ts
->ds
, 0, y_start
,
142 ts
->width
, y
- y_start
);
150 /* flush to display */
151 dpy_update(ts
->ds
, 0, y_start
,
152 ts
->width
, y
- y_start
);
154 /* reset modified pages */
155 if (page_max
!= -1) {
156 cpu_physical_memory_reset_dirty(page_min
, page_max
+ TARGET_PAGE_SIZE
,
161 void tcx_invalidate_display(void *opaque
)
163 TCXState
*s
= opaque
;
166 for (i
= 0; i
< MAXX
*MAXY
; i
+= TARGET_PAGE_SIZE
) {
167 cpu_physical_memory_set_dirty(s
->vram_offset
+ i
);
171 static void tcx_save(QEMUFile
*f
, void *opaque
)
173 TCXState
*s
= opaque
;
175 qemu_put_be32s(f
, (uint32_t *)&s
->addr
);
176 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);
180 qemu_put_buffer(f
, s
->g
, 256);
181 qemu_put_buffer(f
, s
->b
, 256);
182 qemu_put_8s(f
, &s
->dac_index
);
183 qemu_put_8s(f
, &s
->dac_state
);
186 static int tcx_load(QEMUFile
*f
, void *opaque
, int version_id
)
188 TCXState
*s
= opaque
;
193 qemu_get_be32s(f
, (uint32_t *)&s
->addr
);
194 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);
198 qemu_get_buffer(f
, s
->g
, 256);
199 qemu_get_buffer(f
, s
->b
, 256);
200 qemu_get_8s(f
, &s
->dac_index
);
201 qemu_get_8s(f
, &s
->dac_state
);
205 static void tcx_reset(void *opaque
)
207 TCXState
*s
= opaque
;
209 /* Initialize palette */
210 memset(s
->r
, 0, 256);
211 memset(s
->g
, 0, 256);
212 memset(s
->b
, 0, 256);
213 s
->r
[255] = s
->g
[255] = s
->b
[255] = 255;
214 memset(s
->vram
, 0, MAXX
*MAXY
);
215 cpu_physical_memory_reset_dirty(s
->vram_offset
, s
->vram_offset
+ MAXX
*MAXY
,
221 static uint32_t tcx_dac_readl(void *opaque
, target_phys_addr_t addr
)
226 static void tcx_dac_writel(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
228 TCXState
*s
= opaque
;
231 saddr
= (addr
& (TCX_DAC_NREGS
- 1)) >> 2;
234 s
->dac_index
= val
>> 24;
238 switch (s
->dac_state
) {
240 s
->r
[s
->dac_index
] = val
>> 24;
244 s
->g
[s
->dac_index
] = val
>> 24;
248 s
->b
[s
->dac_index
] = val
>> 24;
260 static CPUReadMemoryFunc
*tcx_dac_read
[3] = {
266 static CPUWriteMemoryFunc
*tcx_dac_write
[3] = {
272 void *tcx_init(DisplayState
*ds
, uint32_t addr
, uint8_t *vram_base
,
273 unsigned long vram_offset
, int vram_size
, int width
, int height
)
278 s
= qemu_mallocz(sizeof(TCXState
));
284 s
->vram_offset
= vram_offset
;
288 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
);
292 register_savevm("tcx", addr
, 1, tcx_save
, tcx_load
, s
);
293 qemu_register_reset(tcx_reset
, s
);
295 dpy_resize(s
->ds
, width
, height
);
299 void tcx_screen_dump(void *opaque
, const char *filename
)
301 TCXState
*s
= opaque
;
306 f
= fopen(filename
, "wb");
309 fprintf(f
, "P6\n%d %d\n%d\n", s
->width
, s
->height
, 255);
311 for(y
= 0; y
< s
->height
; y
++) {
313 for(x
= 0; x
< s
->width
; x
++) {