2 * ZX Spectrum Video Emulation
4 * Copyright (c) 2007-2009 Stuart Brady <stuart.brady@gmail.com>
6 * Uses code from VGA emulation
7 * Copyright (c) 2003 Fabrice Bellard
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32 #include "pixel_ops.h"
33 #include "pixel_ops_dup.h"
35 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
,
58 rgb_to_pixel_dup_func
*rgb_to_pixel
;
61 static const uint32_t zx_cols
[16] = {
62 0x00000000, /* 0: Black */
63 0x000000c0, /* 1: Blue */
64 0x00c00000, /* 2: Red */
65 0x00c000c0, /* 3: Magenta */
66 0x0000c000, /* 4: Green */
67 0x0000c0c0, /* 5: Cyan */
68 0x00c0c000, /* 6: Yellow */
69 0x00c0c0c0, /* 7: Light grey */
71 0x00000000, /* 8: Black */
72 0x000000ff, /* 9: Bright blue */
73 0x00ff0000, /* 10: Bright red */
74 0x00ff00ff, /* 11: Bright magenta */
75 0x0000ff00, /* 12: Bright green */
76 0x0000ffff, /* 13: Bright cyan */
77 0x00ffff00, /* 14: Bright yellow */
78 0x00ffffff, /* 15: White */
81 /* copied from vga.c / vga_template.h */
83 #define cbswap_32(__x) \
85 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
86 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
87 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
88 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
90 #ifdef WORDS_BIGENDIAN
93 #define PAT(x) cbswap_32(x)
96 static const uint32_t dmask16
[16] = {
115 static const uint32_t dmask4
[4] = {
122 typedef void zx_draw_line_func(uint8_t *d
, uint32_t font_data
,
123 uint32_t xorcol
, uint32_t bgcol
);
126 #include "zx_glyphs.h"
129 #include "zx_glyphs.h"
132 #include "zx_glyphs.h"
143 static zx_draw_line_func
*zx_draw_line_table
[NB_DEPTHS
] = {
144 zx_draw_glyph_line_8
,
145 zx_draw_glyph_line_16
,
146 zx_draw_glyph_line_16
,
147 zx_draw_glyph_line_32
,
148 zx_draw_glyph_line_32
,
151 static rgb_to_pixel_dup_func
*rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
156 rgb_to_pixel32bgr_dup
,
159 static inline int get_pixfmt_index(DisplayState
*s
)
161 switch(ds_get_bits_per_pixel(s
)) {
166 return zx_pixfmt_15rgb
;
168 return zx_pixfmt_16rgb
;
170 if (is_surface_bgr(s
->surface
)) {
171 return zx_pixfmt_32bgr
;
173 return zx_pixfmt_32rgb
;
178 /* end of code copied from vga.c / vga_template.h */
180 static ZXVState
*zxvstate
;
182 void zx_video_set_border(int col
)
184 ZXVState
*s
= zxvstate
;
189 void zx_video_do_retrace(void)
191 ZXVState
*s
= zxvstate
;
193 if (++s
->flashcount
== 16) {
196 s
->flash
= !s
->flash
;
200 static void zx_draw_scanline(ZXVState
*s1
, uint8_t *d
,
201 const uint8_t *s
, const uint8_t *as
)
204 zx_draw_line_func
*zx_draw_line
;
206 zx_draw_line
= zx_draw_line_table
[get_pixfmt_index(s1
->ds
)];
207 x_incr
= (ds_get_bits_per_pixel(s1
->ds
) + 7) >> 3;
209 for (x
= 0; x
< 32; x
++) {
210 int attrib
, fg
, bg
, bright
, flash
;
213 bright
= (attrib
& 0x40) >> 3;
214 flash
= (attrib
& 0x80) && s1
->flash
;
216 fg
= (attrib
>> 3) & 0x07;
220 bg
= (attrib
>> 3) & 0x07;
225 zx_draw_line(d
, *s
, s1
->palette
[fg
] ^ s1
->palette
[bg
], s1
->palette
[bg
]);
232 static void zx_border_row(ZXVState
*s
, uint8_t *d
)
235 zx_draw_line_func
*zx_draw_line
;
237 zx_draw_line
= zx_draw_line_table
[get_pixfmt_index(s
->ds
)];
238 x_incr
= (ds_get_bits_per_pixel(s
->ds
) + 7) >> 3;
240 for (x
= 0; x
< s
->twidth
/ 8; x
++) {
241 zx_draw_line(d
, 0xff, s
->palette
[s
->border
], 0);
246 static void zx_border_sides(ZXVState
*s
, uint8_t *d
)
249 zx_draw_line_func
*zx_draw_line
;
251 zx_draw_line
= zx_draw_line_table
[get_pixfmt_index(s
->ds
)];
252 x_incr
= (ds_get_bits_per_pixel(s
->ds
) + 7) >> 3;
254 for (x
= 0; x
< s
->bwidth
/ 8; x
++) {
255 zx_draw_line(d
, 0xff, s
->palette
[s
->border
], 0);
258 d
+= s
->swidth
* x_incr
;
259 for (x
= 0; x
< s
->bwidth
/ 8; x
++) {
260 zx_draw_line(d
, 0xff, s
->palette
[s
->border
], 0);
265 static void update_palette(ZXVState
*s
)
268 for(i
= 0; i
< 16; i
++) {
269 r
= (zx_cols
[i
] >> 16) & 0xff;
270 g
= (zx_cols
[i
] >> 8) & 0xff;
271 b
= zx_cols
[i
] & 0xff;
272 s
->palette
[i
] = s
->rgb_to_pixel(r
, g
, b
);
276 static void zx_update_display(void *opaque
)
280 ZXVState
*s
= (ZXVState
*)opaque
;
281 uint32_t addr
, attrib
;
283 int dirty
= s
->invalidate
;
284 static int inited
= 0;
286 x_incr
= (ds_get_bits_per_pixel(s
->ds
) + 7) >> 3;
288 if (unlikely(inited
== 0)) {
289 s
->rgb_to_pixel
= rgb_to_pixel_dup_table
[get_pixfmt_index(s
->ds
)];
294 if (unlikely(ds_get_width(s
->ds
) != s
->twidth
||
295 ds_get_height(s
->ds
) != s
->theight
)) {
296 qemu_console_resize(s
->ds
, s
->twidth
, s
->theight
);
302 for (addr
= 0; addr
< 0x1b00; addr
+= TARGET_PAGE_SIZE
) {
303 if (cpu_physical_memory_get_dirty(addr
, VGA_DIRTY_FLAG
)) {
310 d
= ds_get_data(s
->ds
);
311 d
+= s
->bheight
* ds_get_linesize(s
->ds
);
312 d
+= s
->bwidth
* x_incr
;
314 for (y
= 0; y
< 192; y
++) {
315 addr
= ((y
& 0x07) << 8) | ((y
& 0x38) << 2) | ((y
& 0xc0) << 5);
316 attrib
= 0x1800 | ((y
& 0xf8) << 2);
317 zx_draw_scanline(s
, d
, s
->vram_ptr
+ addr
, s
->vram_ptr
+ attrib
);
318 d
+= ds_get_linesize(s
->ds
);
322 cpu_physical_memory_reset_dirty(0, 0x1b00, VGA_DIRTY_FLAG
);
325 if (s
->border
!= s
->prevborder
) {
326 d
= ds_get_data(s
->ds
);
327 for (y
= 0; y
< s
->bheight
; y
++) {
328 zx_border_row(s
, d
+ (y
* ds_get_linesize(s
->ds
)));
330 for (y
= s
->bheight
; y
< s
->theight
- s
->bheight
; y
++) {
331 zx_border_sides(s
, d
+ (y
* ds_get_linesize(s
->ds
)));
333 for (y
= s
->theight
- s
->bheight
; y
< s
->theight
; y
++) {
334 zx_border_row(s
, d
+ (y
* ds_get_linesize(s
->ds
)));
336 s
->prevborder
= s
->border
;
339 dpy_update(s
->ds
, 0, 0, s
->twidth
, s
->theight
);
342 static void zx_invalidate_display(void *opaque
)
344 ZXVState
*s
= (ZXVState
*)opaque
;
349 void zx_video_init(ram_addr_t zx_vram_offset
)
351 ZXVState
*s
= qemu_mallocz(sizeof(ZXVState
));
356 s
->vram_ptr
= qemu_get_ram_ptr(zx_vram_offset
);
358 s
->ds
= graphic_console_init(zx_update_display
, zx_invalidate_display
,
365 s
->twidth
= s
->swidth
+ s
->bwidth
* 2;
366 s
->theight
= s
->sheight
+ s
->bheight
* 2;