msx: fix loading small cartridge images
[qemu/z80.git] / hw / zx_video.c
blob2e34c581cb8ae9e16346613f078ac16ea576b571
1 /*
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
25 * THE SOFTWARE.
28 #include "hw.h"
29 #include "isa.h"
30 #include "console.h"
31 #include "zx_video.h"
32 #include "pixel_ops.h"
33 #include "pixel_ops_dup.h"
35 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r,
36 unsigned int g,
37 unsigned int b);
39 typedef struct {
40 DisplayState *ds;
41 uint8_t *vram_ptr;
43 int bwidth;
44 int bheight;
45 int swidth;
46 int sheight;
47 int twidth;
48 int theight;
50 int border;
51 int prevborder;
53 int flash;
54 int flashcount;
56 int invalidate;
57 uint32_t palette[16];
58 rgb_to_pixel_dup_func *rgb_to_pixel;
59 } ZXVState;
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) \
84 ((uint32_t)( \
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
91 #define PAT(x) (x)
92 #else
93 #define PAT(x) cbswap_32(x)
94 #endif
96 static const uint32_t dmask16[16] = {
97 PAT(0x00000000),
98 PAT(0x000000ff),
99 PAT(0x0000ff00),
100 PAT(0x0000ffff),
101 PAT(0x00ff0000),
102 PAT(0x00ff00ff),
103 PAT(0x00ffff00),
104 PAT(0x00ffffff),
105 PAT(0xff000000),
106 PAT(0xff0000ff),
107 PAT(0xff00ff00),
108 PAT(0xff00ffff),
109 PAT(0xffff0000),
110 PAT(0xffff00ff),
111 PAT(0xffffff00),
112 PAT(0xffffffff),
115 static const uint32_t dmask4[4] = {
116 PAT(0x00000000),
117 PAT(0x0000ffff),
118 PAT(0xffff0000),
119 PAT(0xffffffff),
122 typedef void zx_draw_line_func(uint8_t *d, uint32_t font_data,
123 uint32_t xorcol, uint32_t bgcol);
125 #define DEPTH 8
126 #include "zx_glyphs.h"
128 #define DEPTH 16
129 #include "zx_glyphs.h"
131 #define DEPTH 32
132 #include "zx_glyphs.h"
134 enum {
135 zx_pixfmt_8 = 0,
136 zx_pixfmt_15rgb,
137 zx_pixfmt_16rgb,
138 zx_pixfmt_32rgb,
139 zx_pixfmt_32bgr,
140 NB_DEPTHS
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] = {
152 rgb_to_pixel8_dup,
153 rgb_to_pixel15_dup,
154 rgb_to_pixel16_dup,
155 rgb_to_pixel32_dup,
156 rgb_to_pixel32bgr_dup,
159 static inline int get_pixfmt_index(DisplayState *s)
161 switch(ds_get_bits_per_pixel(s)) {
162 default:
163 case 8:
164 return zx_pixfmt_8;
165 case 15:
166 return zx_pixfmt_15rgb;
167 case 16:
168 return zx_pixfmt_16rgb;
169 case 32:
170 if (is_surface_bgr(s->surface)) {
171 return zx_pixfmt_32bgr;
172 } else {
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;
186 s->border = col;
189 void zx_video_do_retrace(void)
191 ZXVState *s = zxvstate;
193 if (++s->flashcount == 16) {
194 s->flashcount = 0;
195 s->invalidate = 1;
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)
203 int x, x_incr;
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;
212 attrib = *as;
213 bright = (attrib & 0x40) >> 3;
214 flash = (attrib & 0x80) && s1->flash;
215 if (flash) {
216 fg = (attrib >> 3) & 0x07;
217 bg = attrib & 0x07;
218 } else {
219 fg = attrib & 0x07;
220 bg = (attrib >> 3) & 0x07;
222 fg |= bright;
223 bg |= bright;
225 zx_draw_line(d, *s, s1->palette[fg] ^ s1->palette[bg], s1->palette[bg]);
227 d += 8 * x_incr;
228 s++; as++;
232 static void zx_border_row(ZXVState *s, uint8_t *d)
234 int x, x_incr;
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);
242 d += 8 * x_incr;
246 static void zx_border_sides(ZXVState *s, uint8_t *d)
248 int x, x_incr;
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);
256 d += 8 * x_incr;
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);
261 d += 8 * x_incr;
265 static void update_palette(ZXVState *s)
267 int i, r, g, b;
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)
278 int y;
279 uint8_t *d;
280 ZXVState *s = (ZXVState *)opaque;
281 uint32_t addr, attrib;
282 int x_incr;
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)];
290 update_palette(s);
291 inited = 1;
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);
297 s->invalidate = 1;
298 s->prevborder = -1;
301 if (!dirty) {
302 for (addr = 0; addr < 0x1b00; addr += TARGET_PAGE_SIZE) {
303 if (cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG)) {
304 dirty = 1;
309 if (dirty) {
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);
321 s->invalidate = 0;
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;
345 s->invalidate = 1;
346 s->prevborder = -1;
349 void zx_video_init(ram_addr_t zx_vram_offset)
351 ZXVState *s = qemu_mallocz(sizeof(ZXVState));
352 zxvstate = s;
353 s->invalidate = 1;
354 s->prevborder = -1;
355 s->flashcount = 0;
356 s->vram_ptr = qemu_get_ram_ptr(zx_vram_offset);
358 s->ds = graphic_console_init(zx_update_display, zx_invalidate_display,
359 NULL, NULL, s);
361 s->bwidth = 32;
362 s->bheight = 24;
363 s->swidth = 256;
364 s->sheight = 192;
365 s->twidth = s->swidth + s->bwidth * 2;
366 s->theight = s->sheight + s->bheight * 2;
367 s->border = 0;
368 s->flash = 0;