ia64/xen-unstable

view tools/ioemu/hw/cirrus_vga.c @ 17571:b6aa55ca599e

shadow: track video RAM dirty bits

This adds a new HVM op that enables tracking dirty bits of a range of
video RAM. The idea is to optimize just for the most common case
(only one guest mapping, with sometimes some temporary other
mappings), which permits to keep the overhead on shadow as low as
possible.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri May 02 15:08:27 2008 +0100 (2008-05-02)
parents 06242949ff56
children f472d708b9af
line source
1 /*
2 * QEMU Cirrus CLGD 54xx VGA Emulator.
3 *
4 * Copyright (c) 2004 Fabrice Bellard
5 * Copyright (c) 2004 Makoto Suzuki (suzu)
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25 /*
26 * Reference: Finn Thogersons' VGADOC4b
27 * available at http://home.worldonline.dk/~finth/
28 */
29 #include "vl.h"
30 #include "vga_int.h"
31 #ifndef _WIN32
32 #include <sys/mman.h>
33 #endif
35 /*
36 * TODO:
37 * - destination write mask support not complete (bits 5..7)
38 * - optimize linear mappings
39 * - optimize bitblt functions
40 */
42 //#define DEBUG_CIRRUS
43 //#define DEBUG_BITBLT
45 /***************************************
46 *
47 * definitions
48 *
49 ***************************************/
51 #define qemu_MIN(a,b) ((a) < (b) ? (a) : (b))
53 // ID
54 #define CIRRUS_ID_CLGD5422 (0x23<<2)
55 #define CIRRUS_ID_CLGD5426 (0x24<<2)
56 #define CIRRUS_ID_CLGD5424 (0x25<<2)
57 #define CIRRUS_ID_CLGD5428 (0x26<<2)
58 #define CIRRUS_ID_CLGD5430 (0x28<<2)
59 #define CIRRUS_ID_CLGD5434 (0x2A<<2)
60 #define CIRRUS_ID_CLGD5436 (0x2B<<2)
61 #define CIRRUS_ID_CLGD5446 (0x2E<<2)
63 // sequencer 0x07
64 #define CIRRUS_SR7_BPP_VGA 0x00
65 #define CIRRUS_SR7_BPP_SVGA 0x01
66 #define CIRRUS_SR7_BPP_MASK 0x0e
67 #define CIRRUS_SR7_BPP_8 0x00
68 #define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02
69 #define CIRRUS_SR7_BPP_24 0x04
70 #define CIRRUS_SR7_BPP_16 0x06
71 #define CIRRUS_SR7_BPP_32 0x08
72 #define CIRRUS_SR7_ISAADDR_MASK 0xe0
74 // sequencer 0x0f
75 #define CIRRUS_MEMSIZE_512k 0x08
76 #define CIRRUS_MEMSIZE_1M 0x10
77 #define CIRRUS_MEMSIZE_2M 0x18
78 #define CIRRUS_MEMFLAGS_BANKSWITCH 0x80 // bank switching is enabled.
80 // sequencer 0x12
81 #define CIRRUS_CURSOR_SHOW 0x01
82 #define CIRRUS_CURSOR_HIDDENPEL 0x02
83 #define CIRRUS_CURSOR_LARGE 0x04 // 64x64 if set, 32x32 if clear
85 // sequencer 0x17
86 #define CIRRUS_BUSTYPE_VLBFAST 0x10
87 #define CIRRUS_BUSTYPE_PCI 0x20
88 #define CIRRUS_BUSTYPE_VLBSLOW 0x30
89 #define CIRRUS_BUSTYPE_ISA 0x38
90 #define CIRRUS_MMIO_ENABLE 0x04
91 #define CIRRUS_MMIO_USE_PCIADDR 0x40 // 0xb8000 if cleared.
92 #define CIRRUS_MEMSIZEEXT_DOUBLE 0x80
94 // control 0x0b
95 #define CIRRUS_BANKING_DUAL 0x01
96 #define CIRRUS_BANKING_GRANULARITY_16K 0x20 // set:16k, clear:4k
98 // control 0x30
99 #define CIRRUS_BLTMODE_BACKWARDS 0x01
100 #define CIRRUS_BLTMODE_MEMSYSDEST 0x02
101 #define CIRRUS_BLTMODE_MEMSYSSRC 0x04
102 #define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08
103 #define CIRRUS_BLTMODE_PATTERNCOPY 0x40
104 #define CIRRUS_BLTMODE_COLOREXPAND 0x80
105 #define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30
106 #define CIRRUS_BLTMODE_PIXELWIDTH8 0x00
107 #define CIRRUS_BLTMODE_PIXELWIDTH16 0x10
108 #define CIRRUS_BLTMODE_PIXELWIDTH24 0x20
109 #define CIRRUS_BLTMODE_PIXELWIDTH32 0x30
111 // control 0x31
112 #define CIRRUS_BLT_BUSY 0x01
113 #define CIRRUS_BLT_START 0x02
114 #define CIRRUS_BLT_RESET 0x04
115 #define CIRRUS_BLT_FIFOUSED 0x10
116 #define CIRRUS_BLT_AUTOSTART 0x80
118 // control 0x32
119 #define CIRRUS_ROP_0 0x00
120 #define CIRRUS_ROP_SRC_AND_DST 0x05
121 #define CIRRUS_ROP_NOP 0x06
122 #define CIRRUS_ROP_SRC_AND_NOTDST 0x09
123 #define CIRRUS_ROP_NOTDST 0x0b
124 #define CIRRUS_ROP_SRC 0x0d
125 #define CIRRUS_ROP_1 0x0e
126 #define CIRRUS_ROP_NOTSRC_AND_DST 0x50
127 #define CIRRUS_ROP_SRC_XOR_DST 0x59
128 #define CIRRUS_ROP_SRC_OR_DST 0x6d
129 #define CIRRUS_ROP_NOTSRC_OR_NOTDST 0x90
130 #define CIRRUS_ROP_SRC_NOTXOR_DST 0x95
131 #define CIRRUS_ROP_SRC_OR_NOTDST 0xad
132 #define CIRRUS_ROP_NOTSRC 0xd0
133 #define CIRRUS_ROP_NOTSRC_OR_DST 0xd6
134 #define CIRRUS_ROP_NOTSRC_AND_NOTDST 0xda
136 #define CIRRUS_ROP_NOP_INDEX 2
137 #define CIRRUS_ROP_SRC_INDEX 5
139 // control 0x33
140 #define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04
141 #define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02
142 #define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01
144 // memory-mapped IO
145 #define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword
146 #define CIRRUS_MMIO_BLTFGCOLOR 0x04 // dword
147 #define CIRRUS_MMIO_BLTWIDTH 0x08 // word
148 #define CIRRUS_MMIO_BLTHEIGHT 0x0a // word
149 #define CIRRUS_MMIO_BLTDESTPITCH 0x0c // word
150 #define CIRRUS_MMIO_BLTSRCPITCH 0x0e // word
151 #define CIRRUS_MMIO_BLTDESTADDR 0x10 // dword
152 #define CIRRUS_MMIO_BLTSRCADDR 0x14 // dword
153 #define CIRRUS_MMIO_BLTWRITEMASK 0x17 // byte
154 #define CIRRUS_MMIO_BLTMODE 0x18 // byte
155 #define CIRRUS_MMIO_BLTROP 0x1a // byte
156 #define CIRRUS_MMIO_BLTMODEEXT 0x1b // byte
157 #define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c // word?
158 #define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20 // word?
159 #define CIRRUS_MMIO_LINEARDRAW_START_X 0x24 // word
160 #define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26 // word
161 #define CIRRUS_MMIO_LINEARDRAW_END_X 0x28 // word
162 #define CIRRUS_MMIO_LINEARDRAW_END_Y 0x2a // word
163 #define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c // byte
164 #define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d // byte
165 #define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e // byte
166 #define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f // byte
167 #define CIRRUS_MMIO_BRESENHAM_K1 0x30 // word
168 #define CIRRUS_MMIO_BRESENHAM_K3 0x32 // word
169 #define CIRRUS_MMIO_BRESENHAM_ERROR 0x34 // word
170 #define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36 // word
171 #define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38 // byte
172 #define CIRRUS_MMIO_LINEDRAW_MODE 0x39 // byte
173 #define CIRRUS_MMIO_BLTSTATUS 0x40 // byte
175 // PCI 0x00: vendor, 0x02: device
176 #define PCI_VENDOR_CIRRUS 0x1013
177 #define PCI_DEVICE_CLGD5462 0x00d0
178 #define PCI_DEVICE_CLGD5465 0x00d6
180 // PCI 0x04: command(word), 0x06(word): status
181 #define PCI_COMMAND_IOACCESS 0x0001
182 #define PCI_COMMAND_MEMACCESS 0x0002
183 #define PCI_COMMAND_BUSMASTER 0x0004
184 #define PCI_COMMAND_SPECIALCYCLE 0x0008
185 #define PCI_COMMAND_MEMWRITEINVALID 0x0010
186 #define PCI_COMMAND_PALETTESNOOPING 0x0020
187 #define PCI_COMMAND_PARITYDETECTION 0x0040
188 #define PCI_COMMAND_ADDRESSDATASTEPPING 0x0080
189 #define PCI_COMMAND_SERR 0x0100
190 #define PCI_COMMAND_BACKTOBACKTRANS 0x0200
191 // PCI 0x08, 0xff000000 (0x09-0x0b:class,0x08:rev)
192 #define PCI_CLASS_BASE_DISPLAY 0x03
193 // PCI 0x08, 0x00ff0000
194 #define PCI_CLASS_SUB_VGA 0x00
195 // PCI 0x0c, 0x00ff0000 (0x0c:cacheline,0x0d:latency,0x0e:headertype,0x0f:Built-in self test)
196 #define PCI_CLASS_HEADERTYPE_00h 0x00
197 // 0x10-0x3f (headertype 00h)
198 // PCI 0x10,0x14,0x18,0x1c,0x20,0x24: base address mapping registers
199 // 0x10: MEMBASE, 0x14: IOBASE(hard-coded in XFree86 3.x)
200 #define PCI_MAP_MEM 0x0
201 #define PCI_MAP_IO 0x1
202 #define PCI_MAP_MEM_ADDR_MASK (~0xf)
203 #define PCI_MAP_IO_ADDR_MASK (~0x3)
204 #define PCI_MAP_MEMFLAGS_32BIT 0x0
205 #define PCI_MAP_MEMFLAGS_32BIT_1M 0x1
206 #define PCI_MAP_MEMFLAGS_64BIT 0x4
207 #define PCI_MAP_MEMFLAGS_CACHEABLE 0x8
208 // PCI 0x28: cardbus CIS pointer
209 // PCI 0x2c: subsystem vendor id, 0x2e: subsystem id
210 // PCI 0x30: expansion ROM base address
211 #define PCI_ROMBIOS_ENABLED 0x1
212 // PCI 0x34: 0xffffff00=reserved, 0x000000ff=capabilities pointer
213 // PCI 0x38: reserved
214 // PCI 0x3c: 0x3c=int-line, 0x3d=int-pin, 0x3e=min-gnt, 0x3f=maax-lat
216 #define CIRRUS_PNPMMIO_SIZE 0x1000
219 /* I/O and memory hook */
220 #define CIRRUS_HOOK_NOT_HANDLED 0
221 #define CIRRUS_HOOK_HANDLED 1
223 struct CirrusVGAState;
224 typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
225 uint8_t * dst, const uint8_t * src,
226 int dstpitch, int srcpitch,
227 int bltwidth, int bltheight);
228 typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
229 uint8_t *dst, int dst_pitch, int width, int height);
231 typedef struct CirrusVGAState {
232 VGA_STATE_COMMON
234 int cirrus_linear_io_addr;
235 int cirrus_linear_bitblt_io_addr;
236 int cirrus_mmio_io_addr;
237 uint32_t cirrus_addr_mask;
238 uint32_t linear_mmio_mask;
239 uint8_t cirrus_shadow_gr0;
240 uint8_t cirrus_shadow_gr1;
241 uint8_t cirrus_hidden_dac_lockindex;
242 uint8_t cirrus_hidden_dac_data;
243 uint32_t cirrus_bank_base[2];
244 uint32_t cirrus_bank_limit[2];
245 uint8_t cirrus_hidden_palette[48];
246 uint32_t hw_cursor_x;
247 uint32_t hw_cursor_y;
248 int cirrus_blt_pixelwidth;
249 int cirrus_blt_width;
250 int cirrus_blt_height;
251 int cirrus_blt_dstpitch;
252 int cirrus_blt_srcpitch;
253 uint32_t cirrus_blt_fgcol;
254 uint32_t cirrus_blt_bgcol;
255 uint32_t cirrus_blt_dstaddr;
256 uint32_t cirrus_blt_srcaddr;
257 uint8_t cirrus_blt_mode;
258 uint8_t cirrus_blt_modeext;
259 cirrus_bitblt_rop_t cirrus_rop;
260 #define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
261 uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
262 uint8_t *cirrus_srcptr;
263 uint8_t *cirrus_srcptr_end;
264 uint32_t cirrus_srccounter;
265 /* hwcursor display state */
266 int last_hw_cursor_size;
267 int last_hw_cursor_x;
268 int last_hw_cursor_y;
269 int last_hw_cursor_y_start;
270 int last_hw_cursor_y_end;
271 int real_vram_size; /* XXX: suppress that */
272 CPUWriteMemoryFunc **cirrus_linear_write;
273 unsigned long map_addr;
274 unsigned long map_end;
275 } CirrusVGAState;
277 typedef struct PCICirrusVGAState {
278 PCIDevice dev;
279 CirrusVGAState cirrus_vga;
280 } PCICirrusVGAState;
282 static uint8_t rop_to_index[256];
284 void *shared_vram;
286 /***************************************
287 *
288 * prototypes.
289 *
290 ***************************************/
293 static void cirrus_bitblt_reset(CirrusVGAState *s);
294 static void cirrus_update_memory_access(CirrusVGAState *s);
295 static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val);
297 /***************************************
298 *
299 * raster operations
300 *
301 ***************************************/
303 static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
304 uint8_t *dst,const uint8_t *src,
305 int dstpitch,int srcpitch,
306 int bltwidth,int bltheight)
307 {
308 }
310 static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
311 uint8_t *dst,
312 int dstpitch, int bltwidth,int bltheight)
313 {
314 }
316 #define ROP_NAME 0
317 #define ROP_OP(d, s) d = 0
318 #include "cirrus_vga_rop.h"
320 #define ROP_NAME src_and_dst
321 #define ROP_OP(d, s) d = (s) & (d)
322 #include "cirrus_vga_rop.h"
324 #define ROP_NAME src_and_notdst
325 #define ROP_OP(d, s) d = (s) & (~(d))
326 #include "cirrus_vga_rop.h"
328 #define ROP_NAME notdst
329 #define ROP_OP(d, s) d = ~(d)
330 #include "cirrus_vga_rop.h"
332 #define ROP_NAME src
333 #define ROP_OP(d, s) d = s
334 #include "cirrus_vga_rop.h"
336 #define ROP_NAME 1
337 #define ROP_OP(d, s) d = ~0
338 #include "cirrus_vga_rop.h"
340 #define ROP_NAME notsrc_and_dst
341 #define ROP_OP(d, s) d = (~(s)) & (d)
342 #include "cirrus_vga_rop.h"
344 #define ROP_NAME src_xor_dst
345 #define ROP_OP(d, s) d = (s) ^ (d)
346 #include "cirrus_vga_rop.h"
348 #define ROP_NAME src_or_dst
349 #define ROP_OP(d, s) d = (s) | (d)
350 #include "cirrus_vga_rop.h"
352 #define ROP_NAME notsrc_or_notdst
353 #define ROP_OP(d, s) d = (~(s)) | (~(d))
354 #include "cirrus_vga_rop.h"
356 #define ROP_NAME src_notxor_dst
357 #define ROP_OP(d, s) d = ~((s) ^ (d))
358 #include "cirrus_vga_rop.h"
360 #define ROP_NAME src_or_notdst
361 #define ROP_OP(d, s) d = (s) | (~(d))
362 #include "cirrus_vga_rop.h"
364 #define ROP_NAME notsrc
365 #define ROP_OP(d, s) d = (~(s))
366 #include "cirrus_vga_rop.h"
368 #define ROP_NAME notsrc_or_dst
369 #define ROP_OP(d, s) d = (~(s)) | (d)
370 #include "cirrus_vga_rop.h"
372 #define ROP_NAME notsrc_and_notdst
373 #define ROP_OP(d, s) d = (~(s)) & (~(d))
374 #include "cirrus_vga_rop.h"
376 static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = {
377 cirrus_bitblt_rop_fwd_0,
378 cirrus_bitblt_rop_fwd_src_and_dst,
379 cirrus_bitblt_rop_nop,
380 cirrus_bitblt_rop_fwd_src_and_notdst,
381 cirrus_bitblt_rop_fwd_notdst,
382 cirrus_bitblt_rop_fwd_src,
383 cirrus_bitblt_rop_fwd_1,
384 cirrus_bitblt_rop_fwd_notsrc_and_dst,
385 cirrus_bitblt_rop_fwd_src_xor_dst,
386 cirrus_bitblt_rop_fwd_src_or_dst,
387 cirrus_bitblt_rop_fwd_notsrc_or_notdst,
388 cirrus_bitblt_rop_fwd_src_notxor_dst,
389 cirrus_bitblt_rop_fwd_src_or_notdst,
390 cirrus_bitblt_rop_fwd_notsrc,
391 cirrus_bitblt_rop_fwd_notsrc_or_dst,
392 cirrus_bitblt_rop_fwd_notsrc_and_notdst,
393 };
395 static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = {
396 cirrus_bitblt_rop_bkwd_0,
397 cirrus_bitblt_rop_bkwd_src_and_dst,
398 cirrus_bitblt_rop_nop,
399 cirrus_bitblt_rop_bkwd_src_and_notdst,
400 cirrus_bitblt_rop_bkwd_notdst,
401 cirrus_bitblt_rop_bkwd_src,
402 cirrus_bitblt_rop_bkwd_1,
403 cirrus_bitblt_rop_bkwd_notsrc_and_dst,
404 cirrus_bitblt_rop_bkwd_src_xor_dst,
405 cirrus_bitblt_rop_bkwd_src_or_dst,
406 cirrus_bitblt_rop_bkwd_notsrc_or_notdst,
407 cirrus_bitblt_rop_bkwd_src_notxor_dst,
408 cirrus_bitblt_rop_bkwd_src_or_notdst,
409 cirrus_bitblt_rop_bkwd_notsrc,
410 cirrus_bitblt_rop_bkwd_notsrc_or_dst,
411 cirrus_bitblt_rop_bkwd_notsrc_and_notdst,
412 };
414 #define ROP2(name) {\
415 name ## _8,\
416 name ## _16,\
417 name ## _24,\
418 name ## _32,\
419 }
421 #define ROP_NOP2(func) {\
422 func,\
423 func,\
424 func,\
425 func,\
426 }
428 static const cirrus_bitblt_rop_t cirrus_patternfill[16][4] = {
429 ROP2(cirrus_patternfill_0),
430 ROP2(cirrus_patternfill_src_and_dst),
431 ROP_NOP2(cirrus_bitblt_rop_nop),
432 ROP2(cirrus_patternfill_src_and_notdst),
433 ROP2(cirrus_patternfill_notdst),
434 ROP2(cirrus_patternfill_src),
435 ROP2(cirrus_patternfill_1),
436 ROP2(cirrus_patternfill_notsrc_and_dst),
437 ROP2(cirrus_patternfill_src_xor_dst),
438 ROP2(cirrus_patternfill_src_or_dst),
439 ROP2(cirrus_patternfill_notsrc_or_notdst),
440 ROP2(cirrus_patternfill_src_notxor_dst),
441 ROP2(cirrus_patternfill_src_or_notdst),
442 ROP2(cirrus_patternfill_notsrc),
443 ROP2(cirrus_patternfill_notsrc_or_dst),
444 ROP2(cirrus_patternfill_notsrc_and_notdst),
445 };
447 static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = {
448 ROP2(cirrus_colorexpand_transp_0),
449 ROP2(cirrus_colorexpand_transp_src_and_dst),
450 ROP_NOP2(cirrus_bitblt_rop_nop),
451 ROP2(cirrus_colorexpand_transp_src_and_notdst),
452 ROP2(cirrus_colorexpand_transp_notdst),
453 ROP2(cirrus_colorexpand_transp_src),
454 ROP2(cirrus_colorexpand_transp_1),
455 ROP2(cirrus_colorexpand_transp_notsrc_and_dst),
456 ROP2(cirrus_colorexpand_transp_src_xor_dst),
457 ROP2(cirrus_colorexpand_transp_src_or_dst),
458 ROP2(cirrus_colorexpand_transp_notsrc_or_notdst),
459 ROP2(cirrus_colorexpand_transp_src_notxor_dst),
460 ROP2(cirrus_colorexpand_transp_src_or_notdst),
461 ROP2(cirrus_colorexpand_transp_notsrc),
462 ROP2(cirrus_colorexpand_transp_notsrc_or_dst),
463 ROP2(cirrus_colorexpand_transp_notsrc_and_notdst),
464 };
466 static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = {
467 ROP2(cirrus_colorexpand_0),
468 ROP2(cirrus_colorexpand_src_and_dst),
469 ROP_NOP2(cirrus_bitblt_rop_nop),
470 ROP2(cirrus_colorexpand_src_and_notdst),
471 ROP2(cirrus_colorexpand_notdst),
472 ROP2(cirrus_colorexpand_src),
473 ROP2(cirrus_colorexpand_1),
474 ROP2(cirrus_colorexpand_notsrc_and_dst),
475 ROP2(cirrus_colorexpand_src_xor_dst),
476 ROP2(cirrus_colorexpand_src_or_dst),
477 ROP2(cirrus_colorexpand_notsrc_or_notdst),
478 ROP2(cirrus_colorexpand_src_notxor_dst),
479 ROP2(cirrus_colorexpand_src_or_notdst),
480 ROP2(cirrus_colorexpand_notsrc),
481 ROP2(cirrus_colorexpand_notsrc_or_dst),
482 ROP2(cirrus_colorexpand_notsrc_and_notdst),
483 };
485 static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern_transp[16][4] = {
486 ROP2(cirrus_colorexpand_pattern_transp_0),
487 ROP2(cirrus_colorexpand_pattern_transp_src_and_dst),
488 ROP_NOP2(cirrus_bitblt_rop_nop),
489 ROP2(cirrus_colorexpand_pattern_transp_src_and_notdst),
490 ROP2(cirrus_colorexpand_pattern_transp_notdst),
491 ROP2(cirrus_colorexpand_pattern_transp_src),
492 ROP2(cirrus_colorexpand_pattern_transp_1),
493 ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_dst),
494 ROP2(cirrus_colorexpand_pattern_transp_src_xor_dst),
495 ROP2(cirrus_colorexpand_pattern_transp_src_or_dst),
496 ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_notdst),
497 ROP2(cirrus_colorexpand_pattern_transp_src_notxor_dst),
498 ROP2(cirrus_colorexpand_pattern_transp_src_or_notdst),
499 ROP2(cirrus_colorexpand_pattern_transp_notsrc),
500 ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_dst),
501 ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_notdst),
502 };
504 static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern[16][4] = {
505 ROP2(cirrus_colorexpand_pattern_0),
506 ROP2(cirrus_colorexpand_pattern_src_and_dst),
507 ROP_NOP2(cirrus_bitblt_rop_nop),
508 ROP2(cirrus_colorexpand_pattern_src_and_notdst),
509 ROP2(cirrus_colorexpand_pattern_notdst),
510 ROP2(cirrus_colorexpand_pattern_src),
511 ROP2(cirrus_colorexpand_pattern_1),
512 ROP2(cirrus_colorexpand_pattern_notsrc_and_dst),
513 ROP2(cirrus_colorexpand_pattern_src_xor_dst),
514 ROP2(cirrus_colorexpand_pattern_src_or_dst),
515 ROP2(cirrus_colorexpand_pattern_notsrc_or_notdst),
516 ROP2(cirrus_colorexpand_pattern_src_notxor_dst),
517 ROP2(cirrus_colorexpand_pattern_src_or_notdst),
518 ROP2(cirrus_colorexpand_pattern_notsrc),
519 ROP2(cirrus_colorexpand_pattern_notsrc_or_dst),
520 ROP2(cirrus_colorexpand_pattern_notsrc_and_notdst),
521 };
523 static const cirrus_fill_t cirrus_fill[16][4] = {
524 ROP2(cirrus_fill_0),
525 ROP2(cirrus_fill_src_and_dst),
526 ROP_NOP2(cirrus_bitblt_fill_nop),
527 ROP2(cirrus_fill_src_and_notdst),
528 ROP2(cirrus_fill_notdst),
529 ROP2(cirrus_fill_src),
530 ROP2(cirrus_fill_1),
531 ROP2(cirrus_fill_notsrc_and_dst),
532 ROP2(cirrus_fill_src_xor_dst),
533 ROP2(cirrus_fill_src_or_dst),
534 ROP2(cirrus_fill_notsrc_or_notdst),
535 ROP2(cirrus_fill_src_notxor_dst),
536 ROP2(cirrus_fill_src_or_notdst),
537 ROP2(cirrus_fill_notsrc),
538 ROP2(cirrus_fill_notsrc_or_dst),
539 ROP2(cirrus_fill_notsrc_and_notdst),
540 };
542 static inline void cirrus_bitblt_fgcol(CirrusVGAState *s)
543 {
544 unsigned int color;
545 switch (s->cirrus_blt_pixelwidth) {
546 case 1:
547 s->cirrus_blt_fgcol = s->cirrus_shadow_gr1;
548 break;
549 case 2:
550 color = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8);
551 s->cirrus_blt_fgcol = le16_to_cpu(color);
552 break;
553 case 3:
554 s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 |
555 (s->gr[0x11] << 8) | (s->gr[0x13] << 16);
556 break;
557 default:
558 case 4:
559 color = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8) |
560 (s->gr[0x13] << 16) | (s->gr[0x15] << 24);
561 s->cirrus_blt_fgcol = le32_to_cpu(color);
562 break;
563 }
564 }
566 static inline void cirrus_bitblt_bgcol(CirrusVGAState *s)
567 {
568 unsigned int color;
569 switch (s->cirrus_blt_pixelwidth) {
570 case 1:
571 s->cirrus_blt_bgcol = s->cirrus_shadow_gr0;
572 break;
573 case 2:
574 color = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8);
575 s->cirrus_blt_bgcol = le16_to_cpu(color);
576 break;
577 case 3:
578 s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 |
579 (s->gr[0x10] << 8) | (s->gr[0x12] << 16);
580 break;
581 default:
582 case 4:
583 color = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8) |
584 (s->gr[0x12] << 16) | (s->gr[0x14] << 24);
585 s->cirrus_blt_bgcol = le32_to_cpu(color);
586 break;
587 }
588 }
590 static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
591 int off_pitch, int bytesperline,
592 int lines)
593 {
594 int y;
595 int off_cur;
596 int off_cur_end;
598 for (y = 0; y < lines; y++) {
599 off_cur = off_begin;
600 off_cur_end = off_cur + bytesperline;
601 off_cur &= TARGET_PAGE_MASK;
602 while (off_cur < off_cur_end) {
603 cpu_physical_memory_set_dirty(s->vram_offset +
604 (off_cur & s->cirrus_addr_mask));
605 off_cur += TARGET_PAGE_SIZE;
606 }
607 off_begin += off_pitch;
608 }
609 }
611 static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
612 const uint8_t * src)
613 {
614 uint8_t *dst;
616 dst = s->vram_ptr + s->cirrus_blt_dstaddr;
617 (*s->cirrus_rop) (s, dst, src,
618 s->cirrus_blt_dstpitch, 0,
619 s->cirrus_blt_width, s->cirrus_blt_height);
620 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
621 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
622 s->cirrus_blt_height);
623 return 1;
624 }
626 /* fill */
628 static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
629 {
630 cirrus_fill_t rop_func;
632 rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
633 rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr,
634 s->cirrus_blt_dstpitch,
635 s->cirrus_blt_width, s->cirrus_blt_height);
636 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
637 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
638 s->cirrus_blt_height);
639 cirrus_bitblt_reset(s);
640 return 1;
641 }
643 /***************************************
644 *
645 * bitblt (video-to-video)
646 *
647 ***************************************/
649 static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
650 {
651 return cirrus_bitblt_common_patterncopy(s,
652 s->vram_ptr +
653 (s->cirrus_blt_srcaddr & ~7));
654 }
656 static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
657 {
658 int sx, sy;
659 int dx, dy;
660 int width, height;
661 int depth;
662 int notify = 0;
664 depth = s->get_bpp((VGAState *)s) / 8;
665 s->get_resolution((VGAState *)s, &width, &height);
667 /* extra x, y */
668 sx = (src % (width * depth)) / depth;
669 sy = (src / (width * depth));
670 dx = (dst % (width *depth)) / depth;
671 dy = (dst / (width * depth));
673 /* normalize width */
674 w /= depth;
676 /* if we're doing a backward copy, we have to adjust
677 our x/y to be the upper left corner (instead of the lower
678 right corner) */
679 if (s->cirrus_blt_dstpitch < 0) {
680 sx -= (s->cirrus_blt_width / depth) - 1;
681 dx -= (s->cirrus_blt_width / depth) - 1;
682 sy -= s->cirrus_blt_height - 1;
683 dy -= s->cirrus_blt_height - 1;
684 }
686 /* are we in the visible portion of memory? */
687 if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
688 (sx + w) <= width && (sy + h) <= height &&
689 (dx + w) <= width && (dy + h) <= height) {
690 notify = 1;
691 }
693 /* make to sure only copy if it's a plain copy ROP */
694 if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src &&
695 *s->cirrus_rop != cirrus_bitblt_rop_bkwd_src)
696 notify = 0;
698 /* we have to flush all pending changes so that the copy
699 is generated at the appropriate moment in time */
700 if (notify)
701 vga_hw_update();
703 (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
704 s->vram_ptr + s->cirrus_blt_srcaddr,
705 s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
706 s->cirrus_blt_width, s->cirrus_blt_height);
708 if (notify)
709 s->ds->dpy_copy(s->ds,
710 sx, sy, dx, dy,
711 s->cirrus_blt_width / depth,
712 s->cirrus_blt_height);
714 /* we don't have to notify the display that this portion has
715 changed since dpy_copy implies this */
717 if (!notify)
718 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
719 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
720 s->cirrus_blt_height);
721 }
723 static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
724 {
725 if (s->ds->dpy_copy) {
726 cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
727 s->cirrus_blt_srcaddr - s->start_addr,
728 s->cirrus_blt_width, s->cirrus_blt_height);
729 } else {
730 (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
731 s->vram_ptr + s->cirrus_blt_srcaddr,
732 s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
733 s->cirrus_blt_width, s->cirrus_blt_height);
735 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
736 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
737 s->cirrus_blt_height);
738 }
740 return 1;
741 }
743 /***************************************
744 *
745 * bitblt (cpu-to-video)
746 *
747 ***************************************/
749 static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
750 {
751 int copy_count;
752 uint8_t *end_ptr;
754 if (s->cirrus_srccounter > 0) {
755 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
756 cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
757 the_end:
758 s->cirrus_srccounter = 0;
759 cirrus_bitblt_reset(s);
760 } else {
761 /* at least one scan line */
762 do {
763 (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr,
764 s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
765 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
766 s->cirrus_blt_width, 1);
767 s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
768 s->cirrus_srccounter -= s->cirrus_blt_srcpitch;
769 if (s->cirrus_srccounter <= 0)
770 goto the_end;
771 /* more bytes than needed can be transfered because of
772 word alignment, so we keep them for the next line */
773 /* XXX: keep alignment to speed up transfer */
774 end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
775 copy_count = s->cirrus_srcptr_end - end_ptr;
776 memmove(s->cirrus_bltbuf, end_ptr, copy_count);
777 s->cirrus_srcptr = s->cirrus_bltbuf + copy_count;
778 s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
779 } while (s->cirrus_srcptr >= s->cirrus_srcptr_end);
780 }
781 }
782 }
784 /***************************************
785 *
786 * bitblt wrapper
787 *
788 ***************************************/
790 static void cirrus_bitblt_reset(CirrusVGAState * s)
791 {
792 s->gr[0x31] &=
793 ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED);
794 s->cirrus_srcptr = &s->cirrus_bltbuf[0];
795 s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
796 s->cirrus_srccounter = 0;
797 cirrus_update_memory_access(s);
798 }
800 static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
801 {
802 int w;
804 s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
805 s->cirrus_srcptr = &s->cirrus_bltbuf[0];
806 s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
808 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
809 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
810 s->cirrus_blt_srcpitch = 8;
811 } else {
812 /* XXX: check for 24 bpp */
813 s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth;
814 }
815 s->cirrus_srccounter = s->cirrus_blt_srcpitch;
816 } else {
817 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
818 w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth;
819 if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)
820 s->cirrus_blt_srcpitch = ((w + 31) >> 5);
821 else
822 s->cirrus_blt_srcpitch = ((w + 7) >> 3);
823 } else {
824 /* always align input size to 32 bits */
825 s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3;
826 }
827 s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
828 }
829 s->cirrus_srcptr = s->cirrus_bltbuf;
830 s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
831 cirrus_update_memory_access(s);
832 return 1;
833 }
835 static int cirrus_bitblt_videotocpu(CirrusVGAState * s)
836 {
837 /* XXX */
838 #ifdef DEBUG_BITBLT
839 printf("cirrus: bitblt (video to cpu) is not implemented yet\n");
840 #endif
841 return 0;
842 }
844 static int cirrus_bitblt_videotovideo(CirrusVGAState * s)
845 {
846 int ret;
848 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
849 ret = cirrus_bitblt_videotovideo_patterncopy(s);
850 } else {
851 ret = cirrus_bitblt_videotovideo_copy(s);
852 }
853 if (ret)
854 cirrus_bitblt_reset(s);
855 return ret;
856 }
858 static void cirrus_bitblt_start(CirrusVGAState * s)
859 {
860 uint8_t blt_rop;
862 s->gr[0x31] |= CIRRUS_BLT_BUSY;
864 s->cirrus_blt_width = (s->gr[0x20] | (s->gr[0x21] << 8)) + 1;
865 s->cirrus_blt_height = (s->gr[0x22] | (s->gr[0x23] << 8)) + 1;
866 s->cirrus_blt_dstpitch = (s->gr[0x24] | (s->gr[0x25] << 8));
867 s->cirrus_blt_srcpitch = (s->gr[0x26] | (s->gr[0x27] << 8));
868 s->cirrus_blt_dstaddr =
869 (s->gr[0x28] | (s->gr[0x29] << 8) | (s->gr[0x2a] << 16));
870 s->cirrus_blt_srcaddr =
871 (s->gr[0x2c] | (s->gr[0x2d] << 8) | (s->gr[0x2e] << 16));
872 s->cirrus_blt_mode = s->gr[0x30];
873 s->cirrus_blt_modeext = s->gr[0x33];
874 blt_rop = s->gr[0x32];
876 #ifdef DEBUG_BITBLT
877 printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
878 blt_rop,
879 s->cirrus_blt_mode,
880 s->cirrus_blt_modeext,
881 s->cirrus_blt_width,
882 s->cirrus_blt_height,
883 s->cirrus_blt_dstpitch,
884 s->cirrus_blt_srcpitch,
885 s->cirrus_blt_dstaddr,
886 s->cirrus_blt_srcaddr,
887 s->gr[0x2f]);
888 #endif
890 switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
891 case CIRRUS_BLTMODE_PIXELWIDTH8:
892 s->cirrus_blt_pixelwidth = 1;
893 break;
894 case CIRRUS_BLTMODE_PIXELWIDTH16:
895 s->cirrus_blt_pixelwidth = 2;
896 break;
897 case CIRRUS_BLTMODE_PIXELWIDTH24:
898 s->cirrus_blt_pixelwidth = 3;
899 break;
900 case CIRRUS_BLTMODE_PIXELWIDTH32:
901 s->cirrus_blt_pixelwidth = 4;
902 break;
903 default:
904 #ifdef DEBUG_BITBLT
905 printf("cirrus: bitblt - pixel width is unknown\n");
906 #endif
907 goto bitblt_ignore;
908 }
909 s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK;
911 if ((s->
912 cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC |
913 CIRRUS_BLTMODE_MEMSYSDEST))
914 == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) {
915 #ifdef DEBUG_BITBLT
916 printf("cirrus: bitblt - memory-to-memory copy is requested\n");
917 #endif
918 goto bitblt_ignore;
919 }
921 if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) &&
922 (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST |
923 CIRRUS_BLTMODE_TRANSPARENTCOMP |
924 CIRRUS_BLTMODE_PATTERNCOPY |
925 CIRRUS_BLTMODE_COLOREXPAND)) ==
926 (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) {
927 cirrus_bitblt_fgcol(s);
928 cirrus_bitblt_solidfill(s, blt_rop);
929 } else {
930 if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND |
931 CIRRUS_BLTMODE_PATTERNCOPY)) ==
932 CIRRUS_BLTMODE_COLOREXPAND) {
934 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
935 if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
936 cirrus_bitblt_bgcol(s);
937 else
938 cirrus_bitblt_fgcol(s);
939 s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
940 } else {
941 cirrus_bitblt_fgcol(s);
942 cirrus_bitblt_bgcol(s);
943 s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
944 }
945 } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
946 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
947 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
948 if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
949 cirrus_bitblt_bgcol(s);
950 else
951 cirrus_bitblt_fgcol(s);
952 s->cirrus_rop = cirrus_colorexpand_pattern_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
953 } else {
954 cirrus_bitblt_fgcol(s);
955 cirrus_bitblt_bgcol(s);
956 s->cirrus_rop = cirrus_colorexpand_pattern[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
957 }
958 } else {
959 s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
960 }
961 } else {
962 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
963 s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
964 s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
965 s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]];
966 } else {
967 s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]];
968 }
969 }
971 // setup bitblt engine.
972 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) {
973 if (!cirrus_bitblt_cputovideo(s))
974 goto bitblt_ignore;
975 } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) {
976 if (!cirrus_bitblt_videotocpu(s))
977 goto bitblt_ignore;
978 } else {
979 if (!cirrus_bitblt_videotovideo(s))
980 goto bitblt_ignore;
981 }
982 }
983 return;
984 bitblt_ignore:;
985 cirrus_bitblt_reset(s);
986 }
988 static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value)
989 {
990 unsigned old_value;
992 old_value = s->gr[0x31];
993 s->gr[0x31] = reg_value;
995 if (((old_value & CIRRUS_BLT_RESET) != 0) &&
996 ((reg_value & CIRRUS_BLT_RESET) == 0)) {
997 cirrus_bitblt_reset(s);
998 } else if (((old_value & CIRRUS_BLT_START) == 0) &&
999 ((reg_value & CIRRUS_BLT_START) != 0)) {
1000 cirrus_bitblt_start(s);
1005 /***************************************
1007 * basic parameters
1009 ***************************************/
1011 static void cirrus_get_offsets(VGAState *s1,
1012 uint32_t *pline_offset,
1013 uint32_t *pstart_addr,
1014 uint32_t *pline_compare)
1016 CirrusVGAState * s = (CirrusVGAState *)s1;
1017 uint32_t start_addr, line_offset, line_compare;
1019 line_offset = s->cr[0x13]
1020 | ((s->cr[0x1b] & 0x10) << 4);
1021 line_offset <<= 3;
1022 *pline_offset = line_offset;
1024 start_addr = (s->cr[0x0c] << 8)
1025 | s->cr[0x0d]
1026 | ((s->cr[0x1b] & 0x01) << 16)
1027 | ((s->cr[0x1b] & 0x0c) << 15)
1028 | ((s->cr[0x1d] & 0x80) << 12);
1029 *pstart_addr = start_addr;
1031 line_compare = s->cr[0x18] |
1032 ((s->cr[0x07] & 0x10) << 4) |
1033 ((s->cr[0x09] & 0x40) << 3);
1034 *pline_compare = line_compare;
1037 static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
1039 uint32_t ret = 16;
1041 switch (s->cirrus_hidden_dac_data & 0xf) {
1042 case 0:
1043 ret = 15;
1044 break; /* Sierra HiColor */
1045 case 1:
1046 ret = 16;
1047 break; /* XGA HiColor */
1048 default:
1049 #ifdef DEBUG_CIRRUS
1050 printf("cirrus: invalid DAC value %x in 16bpp\n",
1051 (s->cirrus_hidden_dac_data & 0xf));
1052 #endif
1053 ret = 15; /* XXX */
1054 break;
1056 return ret;
1059 static int cirrus_get_bpp(VGAState *s1)
1061 CirrusVGAState * s = (CirrusVGAState *)s1;
1062 uint32_t ret = 8;
1064 if ((s->sr[0x07] & 0x01) != 0) {
1065 /* Cirrus SVGA */
1066 switch (s->sr[0x07] & CIRRUS_SR7_BPP_MASK) {
1067 case CIRRUS_SR7_BPP_8:
1068 ret = 8;
1069 break;
1070 case CIRRUS_SR7_BPP_16_DOUBLEVCLK:
1071 ret = cirrus_get_bpp16_depth(s);
1072 break;
1073 case CIRRUS_SR7_BPP_24:
1074 ret = 24;
1075 break;
1076 case CIRRUS_SR7_BPP_16:
1077 ret = cirrus_get_bpp16_depth(s);
1078 break;
1079 case CIRRUS_SR7_BPP_32:
1080 ret = 32;
1081 break;
1082 default:
1083 #ifdef DEBUG_CIRRUS
1084 printf("cirrus: unknown bpp - sr7=%x\n", s->sr[0x7]);
1085 #endif
1086 ret = 8;
1087 break;
1089 } else {
1090 /* VGA */
1091 ret = 0;
1094 return ret;
1097 static void cirrus_get_resolution(VGAState *s, int *pwidth, int *pheight)
1099 int width, height;
1101 width = (s->cr[0x01] + 1) * 8;
1102 height = s->cr[0x12] |
1103 ((s->cr[0x07] & 0x02) << 7) |
1104 ((s->cr[0x07] & 0x40) << 3);
1105 height = (height + 1);
1106 /* interlace support */
1107 if (s->cr[0x1a] & 0x01)
1108 height = height * 2;
1109 *pwidth = width;
1110 *pheight = height;
1113 /***************************************
1115 * bank memory
1117 ***************************************/
1119 static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
1121 unsigned offset;
1122 unsigned limit;
1124 if ((s->gr[0x0b] & 0x01) != 0) /* dual bank */
1125 offset = s->gr[0x09 + bank_index];
1126 else /* single bank */
1127 offset = s->gr[0x09];
1129 if ((s->gr[0x0b] & 0x20) != 0)
1130 offset <<= 14;
1131 else
1132 offset <<= 12;
1134 if (s->real_vram_size <= offset)
1135 limit = 0;
1136 else
1137 limit = s->real_vram_size - offset;
1139 if (((s->gr[0x0b] & 0x01) == 0) && (bank_index != 0)) {
1140 if (limit > 0x8000) {
1141 offset += 0x8000;
1142 limit -= 0x8000;
1143 } else {
1144 limit = 0;
1148 if (limit > 0) {
1149 s->cirrus_bank_base[bank_index] = offset;
1150 s->cirrus_bank_limit[bank_index] = limit;
1151 } else {
1152 s->cirrus_bank_base[bank_index] = 0;
1153 s->cirrus_bank_limit[bank_index] = 0;
1157 /***************************************
1159 * I/O access between 0x3c4-0x3c5
1161 ***************************************/
1163 static int
1164 cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
1166 switch (reg_index) {
1167 case 0x00: // Standard VGA
1168 case 0x01: // Standard VGA
1169 case 0x02: // Standard VGA
1170 case 0x03: // Standard VGA
1171 case 0x04: // Standard VGA
1172 return CIRRUS_HOOK_NOT_HANDLED;
1173 case 0x06: // Unlock Cirrus extensions
1174 *reg_value = s->sr[reg_index];
1175 break;
1176 case 0x10:
1177 case 0x30:
1178 case 0x50:
1179 case 0x70: // Graphics Cursor X
1180 case 0x90:
1181 case 0xb0:
1182 case 0xd0:
1183 case 0xf0: // Graphics Cursor X
1184 *reg_value = s->sr[0x10];
1185 break;
1186 case 0x11:
1187 case 0x31:
1188 case 0x51:
1189 case 0x71: // Graphics Cursor Y
1190 case 0x91:
1191 case 0xb1:
1192 case 0xd1:
1193 case 0xf1: // Graphics Cursor Y
1194 *reg_value = s->sr[0x11];
1195 break;
1196 case 0x05: // ???
1197 case 0x07: // Extended Sequencer Mode
1198 case 0x08: // EEPROM Control
1199 case 0x09: // Scratch Register 0
1200 case 0x0a: // Scratch Register 1
1201 case 0x0b: // VCLK 0
1202 case 0x0c: // VCLK 1
1203 case 0x0d: // VCLK 2
1204 case 0x0e: // VCLK 3
1205 case 0x0f: // DRAM Control
1206 case 0x12: // Graphics Cursor Attribute
1207 case 0x13: // Graphics Cursor Pattern Address
1208 case 0x14: // Scratch Register 2
1209 case 0x15: // Scratch Register 3
1210 case 0x16: // Performance Tuning Register
1211 case 0x17: // Configuration Readback and Extended Control
1212 case 0x18: // Signature Generator Control
1213 case 0x19: // Signal Generator Result
1214 case 0x1a: // Signal Generator Result
1215 case 0x1b: // VCLK 0 Denominator & Post
1216 case 0x1c: // VCLK 1 Denominator & Post
1217 case 0x1d: // VCLK 2 Denominator & Post
1218 case 0x1e: // VCLK 3 Denominator & Post
1219 case 0x1f: // BIOS Write Enable and MCLK select
1220 #ifdef DEBUG_CIRRUS
1221 printf("cirrus: handled inport sr_index %02x\n", reg_index);
1222 #endif
1223 *reg_value = s->sr[reg_index];
1224 break;
1225 default:
1226 #ifdef DEBUG_CIRRUS
1227 printf("cirrus: inport sr_index %02x\n", reg_index);
1228 #endif
1229 *reg_value = 0xff;
1230 break;
1233 return CIRRUS_HOOK_HANDLED;
1236 static int
1237 cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1239 switch (reg_index) {
1240 case 0x00: // Standard VGA
1241 case 0x01: // Standard VGA
1242 case 0x02: // Standard VGA
1243 case 0x03: // Standard VGA
1244 case 0x04: // Standard VGA
1245 return CIRRUS_HOOK_NOT_HANDLED;
1246 case 0x06: // Unlock Cirrus extensions
1247 reg_value &= 0x17;
1248 if (reg_value == 0x12) {
1249 s->sr[reg_index] = 0x12;
1250 } else {
1251 s->sr[reg_index] = 0x0f;
1253 break;
1254 case 0x10:
1255 case 0x30:
1256 case 0x50:
1257 case 0x70: // Graphics Cursor X
1258 case 0x90:
1259 case 0xb0:
1260 case 0xd0:
1261 case 0xf0: // Graphics Cursor X
1262 s->sr[0x10] = reg_value;
1263 s->hw_cursor_x = (reg_value << 3) | (reg_index >> 5);
1264 break;
1265 case 0x11:
1266 case 0x31:
1267 case 0x51:
1268 case 0x71: // Graphics Cursor Y
1269 case 0x91:
1270 case 0xb1:
1271 case 0xd1:
1272 case 0xf1: // Graphics Cursor Y
1273 s->sr[0x11] = reg_value;
1274 s->hw_cursor_y = (reg_value << 3) | (reg_index >> 5);
1275 break;
1276 case 0x07: // Extended Sequencer Mode
1277 case 0x08: // EEPROM Control
1278 case 0x09: // Scratch Register 0
1279 case 0x0a: // Scratch Register 1
1280 case 0x0b: // VCLK 0
1281 case 0x0c: // VCLK 1
1282 case 0x0d: // VCLK 2
1283 case 0x0e: // VCLK 3
1284 case 0x0f: // DRAM Control
1285 case 0x12: // Graphics Cursor Attribute
1286 case 0x13: // Graphics Cursor Pattern Address
1287 case 0x14: // Scratch Register 2
1288 case 0x15: // Scratch Register 3
1289 case 0x16: // Performance Tuning Register
1290 case 0x18: // Signature Generator Control
1291 case 0x19: // Signature Generator Result
1292 case 0x1a: // Signature Generator Result
1293 case 0x1b: // VCLK 0 Denominator & Post
1294 case 0x1c: // VCLK 1 Denominator & Post
1295 case 0x1d: // VCLK 2 Denominator & Post
1296 case 0x1e: // VCLK 3 Denominator & Post
1297 case 0x1f: // BIOS Write Enable and MCLK select
1298 s->sr[reg_index] = reg_value;
1299 #ifdef DEBUG_CIRRUS
1300 printf("cirrus: handled outport sr_index %02x, sr_value %02x\n",
1301 reg_index, reg_value);
1302 #endif
1303 break;
1304 case 0x17: // Configuration Readback and Extended Control
1305 s->sr[reg_index] = (s->sr[reg_index] & 0x38) | (reg_value & 0xc7);
1306 cirrus_update_memory_access(s);
1307 break;
1308 default:
1309 #ifdef DEBUG_CIRRUS
1310 printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index,
1311 reg_value);
1312 #endif
1313 break;
1316 return CIRRUS_HOOK_HANDLED;
1319 /***************************************
1321 * I/O access at 0x3c6
1323 ***************************************/
1325 static void cirrus_read_hidden_dac(CirrusVGAState * s, int *reg_value)
1327 *reg_value = 0xff;
1328 if (++s->cirrus_hidden_dac_lockindex == 5) {
1329 *reg_value = s->cirrus_hidden_dac_data;
1330 s->cirrus_hidden_dac_lockindex = 0;
1334 static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value)
1336 if (s->cirrus_hidden_dac_lockindex == 4) {
1337 s->cirrus_hidden_dac_data = reg_value;
1338 #if defined(DEBUG_CIRRUS)
1339 printf("cirrus: outport hidden DAC, value %02x\n", reg_value);
1340 #endif
1342 s->cirrus_hidden_dac_lockindex = 0;
1345 /***************************************
1347 * I/O access at 0x3c9
1349 ***************************************/
1351 static int cirrus_hook_read_palette(CirrusVGAState * s, int *reg_value)
1353 if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL))
1354 return CIRRUS_HOOK_NOT_HANDLED;
1355 *reg_value =
1356 s->cirrus_hidden_palette[(s->dac_read_index & 0x0f) * 3 +
1357 s->dac_sub_index];
1358 if (++s->dac_sub_index == 3) {
1359 s->dac_sub_index = 0;
1360 s->dac_read_index++;
1362 return CIRRUS_HOOK_HANDLED;
1365 static int cirrus_hook_write_palette(CirrusVGAState * s, int reg_value)
1367 if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL))
1368 return CIRRUS_HOOK_NOT_HANDLED;
1369 s->dac_cache[s->dac_sub_index] = reg_value;
1370 if (++s->dac_sub_index == 3) {
1371 memcpy(&s->cirrus_hidden_palette[(s->dac_write_index & 0x0f) * 3],
1372 s->dac_cache, 3);
1373 /* XXX update cursor */
1374 s->dac_sub_index = 0;
1375 s->dac_write_index++;
1377 return CIRRUS_HOOK_HANDLED;
1380 /***************************************
1382 * I/O access between 0x3ce-0x3cf
1384 ***************************************/
1386 static int
1387 cirrus_hook_read_gr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
1389 switch (reg_index) {
1390 case 0x00: // Standard VGA, BGCOLOR 0x000000ff
1391 *reg_value = s->cirrus_shadow_gr0;
1392 return CIRRUS_HOOK_HANDLED;
1393 case 0x01: // Standard VGA, FGCOLOR 0x000000ff
1394 *reg_value = s->cirrus_shadow_gr1;
1395 return CIRRUS_HOOK_HANDLED;
1396 case 0x02: // Standard VGA
1397 case 0x03: // Standard VGA
1398 case 0x04: // Standard VGA
1399 case 0x06: // Standard VGA
1400 case 0x07: // Standard VGA
1401 case 0x08: // Standard VGA
1402 return CIRRUS_HOOK_NOT_HANDLED;
1403 case 0x05: // Standard VGA, Cirrus extended mode
1404 default:
1405 break;
1408 if (reg_index < 0x3a) {
1409 *reg_value = s->gr[reg_index];
1410 } else {
1411 #ifdef DEBUG_CIRRUS
1412 printf("cirrus: inport gr_index %02x\n", reg_index);
1413 #endif
1414 *reg_value = 0xff;
1417 return CIRRUS_HOOK_HANDLED;
1420 static int
1421 cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1423 #if defined(DEBUG_BITBLT) && 0
1424 printf("gr%02x: %02x\n", reg_index, reg_value);
1425 #endif
1426 switch (reg_index) {
1427 case 0x00: // Standard VGA, BGCOLOR 0x000000ff
1428 s->cirrus_shadow_gr0 = reg_value;
1429 return CIRRUS_HOOK_NOT_HANDLED;
1430 case 0x01: // Standard VGA, FGCOLOR 0x000000ff
1431 s->cirrus_shadow_gr1 = reg_value;
1432 return CIRRUS_HOOK_NOT_HANDLED;
1433 case 0x02: // Standard VGA
1434 case 0x03: // Standard VGA
1435 case 0x04: // Standard VGA
1436 case 0x06: // Standard VGA
1437 case 0x07: // Standard VGA
1438 case 0x08: // Standard VGA
1439 return CIRRUS_HOOK_NOT_HANDLED;
1440 case 0x05: // Standard VGA, Cirrus extended mode
1441 s->gr[reg_index] = reg_value & 0x7f;
1442 cirrus_update_memory_access(s);
1443 break;
1444 case 0x09: // bank offset #0
1445 case 0x0A: // bank offset #1
1446 s->gr[reg_index] = reg_value;
1447 cirrus_update_bank_ptr(s, 0);
1448 cirrus_update_bank_ptr(s, 1);
1449 break;
1450 case 0x0B:
1451 s->gr[reg_index] = reg_value;
1452 cirrus_update_bank_ptr(s, 0);
1453 cirrus_update_bank_ptr(s, 1);
1454 cirrus_update_memory_access(s);
1455 break;
1456 case 0x10: // BGCOLOR 0x0000ff00
1457 case 0x11: // FGCOLOR 0x0000ff00
1458 case 0x12: // BGCOLOR 0x00ff0000
1459 case 0x13: // FGCOLOR 0x00ff0000
1460 case 0x14: // BGCOLOR 0xff000000
1461 case 0x15: // FGCOLOR 0xff000000
1462 case 0x20: // BLT WIDTH 0x0000ff
1463 case 0x22: // BLT HEIGHT 0x0000ff
1464 case 0x24: // BLT DEST PITCH 0x0000ff
1465 case 0x26: // BLT SRC PITCH 0x0000ff
1466 case 0x28: // BLT DEST ADDR 0x0000ff
1467 case 0x29: // BLT DEST ADDR 0x00ff00
1468 case 0x2c: // BLT SRC ADDR 0x0000ff
1469 case 0x2d: // BLT SRC ADDR 0x00ff00
1470 case 0x2f: // BLT WRITEMASK
1471 case 0x30: // BLT MODE
1472 case 0x32: // RASTER OP
1473 case 0x33: // BLT MODEEXT
1474 case 0x34: // BLT TRANSPARENT COLOR 0x00ff
1475 case 0x35: // BLT TRANSPARENT COLOR 0xff00
1476 case 0x38: // BLT TRANSPARENT COLOR MASK 0x00ff
1477 case 0x39: // BLT TRANSPARENT COLOR MASK 0xff00
1478 s->gr[reg_index] = reg_value;
1479 break;
1480 case 0x21: // BLT WIDTH 0x001f00
1481 case 0x23: // BLT HEIGHT 0x001f00
1482 case 0x25: // BLT DEST PITCH 0x001f00
1483 case 0x27: // BLT SRC PITCH 0x001f00
1484 s->gr[reg_index] = reg_value & 0x1f;
1485 break;
1486 case 0x2a: // BLT DEST ADDR 0x3f0000
1487 s->gr[reg_index] = reg_value & 0x3f;
1488 /* if auto start mode, starts bit blt now */
1489 if (s->gr[0x31] & CIRRUS_BLT_AUTOSTART) {
1490 cirrus_bitblt_start(s);
1492 break;
1493 case 0x2e: // BLT SRC ADDR 0x3f0000
1494 s->gr[reg_index] = reg_value & 0x3f;
1495 break;
1496 case 0x31: // BLT STATUS/START
1497 cirrus_write_bitblt(s, reg_value);
1498 break;
1500 // Extension to allow BIOS to clear 16K VRAM bank in one operation
1501 case 0xFE:
1502 s->gr[reg_index] = reg_value; // Lower byte of value to be written
1503 break;
1504 case 0xFF: {
1505 target_phys_addr_t addr;
1506 for (addr = 0xa0000; addr < 0xa4000; addr += 2)
1507 cirrus_vga_mem_writew(s, addr, (reg_value << 8) | s->gr[0xFE]);
1509 break;
1510 default:
1511 #ifdef DEBUG_CIRRUS
1512 printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index,
1513 reg_value);
1514 #endif
1515 break;
1518 return CIRRUS_HOOK_HANDLED;
1521 /***************************************
1523 * I/O access between 0x3d4-0x3d5
1525 ***************************************/
1527 static int
1528 cirrus_hook_read_cr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
1530 switch (reg_index) {
1531 case 0x00: // Standard VGA
1532 case 0x01: // Standard VGA
1533 case 0x02: // Standard VGA
1534 case 0x03: // Standard VGA
1535 case 0x04: // Standard VGA
1536 case 0x05: // Standard VGA
1537 case 0x06: // Standard VGA
1538 case 0x07: // Standard VGA
1539 case 0x08: // Standard VGA
1540 case 0x09: // Standard VGA
1541 case 0x0a: // Standard VGA
1542 case 0x0b: // Standard VGA
1543 case 0x0c: // Standard VGA
1544 case 0x0d: // Standard VGA
1545 case 0x0e: // Standard VGA
1546 case 0x0f: // Standard VGA
1547 case 0x10: // Standard VGA
1548 case 0x11: // Standard VGA
1549 case 0x12: // Standard VGA
1550 case 0x13: // Standard VGA
1551 case 0x14: // Standard VGA
1552 case 0x15: // Standard VGA
1553 case 0x16: // Standard VGA
1554 case 0x17: // Standard VGA
1555 case 0x18: // Standard VGA
1556 return CIRRUS_HOOK_NOT_HANDLED;
1557 case 0x19: // Interlace End
1558 case 0x1a: // Miscellaneous Control
1559 case 0x1b: // Extended Display Control
1560 case 0x1c: // Sync Adjust and Genlock
1561 case 0x1d: // Overlay Extended Control
1562 case 0x22: // Graphics Data Latches Readback (R)
1563 case 0x24: // Attribute Controller Toggle Readback (R)
1564 case 0x25: // Part Status
1565 case 0x27: // Part ID (R)
1566 *reg_value = s->cr[reg_index];
1567 break;
1568 case 0x26: // Attribute Controller Index Readback (R)
1569 *reg_value = s->ar_index & 0x3f;
1570 break;
1571 default:
1572 #ifdef DEBUG_CIRRUS
1573 printf("cirrus: inport cr_index %02x\n", reg_index);
1574 *reg_value = 0xff;
1575 #endif
1576 break;
1579 return CIRRUS_HOOK_HANDLED;
1582 static int
1583 cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1585 switch (reg_index) {
1586 case 0x00: // Standard VGA
1587 case 0x01: // Standard VGA
1588 case 0x02: // Standard VGA
1589 case 0x03: // Standard VGA
1590 case 0x04: // Standard VGA
1591 case 0x05: // Standard VGA
1592 case 0x06: // Standard VGA
1593 case 0x07: // Standard VGA
1594 case 0x08: // Standard VGA
1595 case 0x09: // Standard VGA
1596 case 0x0a: // Standard VGA
1597 case 0x0b: // Standard VGA
1598 case 0x0c: // Standard VGA
1599 case 0x0d: // Standard VGA
1600 case 0x0e: // Standard VGA
1601 case 0x0f: // Standard VGA
1602 case 0x10: // Standard VGA
1603 case 0x11: // Standard VGA
1604 case 0x12: // Standard VGA
1605 case 0x13: // Standard VGA
1606 case 0x14: // Standard VGA
1607 case 0x15: // Standard VGA
1608 case 0x16: // Standard VGA
1609 case 0x17: // Standard VGA
1610 case 0x18: // Standard VGA
1611 return CIRRUS_HOOK_NOT_HANDLED;
1612 case 0x19: // Interlace End
1613 case 0x1a: // Miscellaneous Control
1614 case 0x1b: // Extended Display Control
1615 case 0x1c: // Sync Adjust and Genlock
1616 case 0x1d: // Overlay Extended Control
1617 s->cr[reg_index] = reg_value;
1618 #ifdef DEBUG_CIRRUS
1619 printf("cirrus: handled outport cr_index %02x, cr_value %02x\n",
1620 reg_index, reg_value);
1621 #endif
1622 break;
1623 case 0x22: // Graphics Data Latches Readback (R)
1624 case 0x24: // Attribute Controller Toggle Readback (R)
1625 case 0x26: // Attribute Controller Index Readback (R)
1626 case 0x27: // Part ID (R)
1627 break;
1628 case 0x25: // Part Status
1629 default:
1630 #ifdef DEBUG_CIRRUS
1631 printf("cirrus: outport cr_index %02x, cr_value %02x\n", reg_index,
1632 reg_value);
1633 #endif
1634 break;
1637 return CIRRUS_HOOK_HANDLED;
1640 /***************************************
1642 * memory-mapped I/O (bitblt)
1644 ***************************************/
1646 static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
1648 int value = 0xff;
1650 switch (address) {
1651 case (CIRRUS_MMIO_BLTBGCOLOR + 0):
1652 cirrus_hook_read_gr(s, 0x00, &value);
1653 break;
1654 case (CIRRUS_MMIO_BLTBGCOLOR + 1):
1655 cirrus_hook_read_gr(s, 0x10, &value);
1656 break;
1657 case (CIRRUS_MMIO_BLTBGCOLOR + 2):
1658 cirrus_hook_read_gr(s, 0x12, &value);
1659 break;
1660 case (CIRRUS_MMIO_BLTBGCOLOR + 3):
1661 cirrus_hook_read_gr(s, 0x14, &value);
1662 break;
1663 case (CIRRUS_MMIO_BLTFGCOLOR + 0):
1664 cirrus_hook_read_gr(s, 0x01, &value);
1665 break;
1666 case (CIRRUS_MMIO_BLTFGCOLOR + 1):
1667 cirrus_hook_read_gr(s, 0x11, &value);
1668 break;
1669 case (CIRRUS_MMIO_BLTFGCOLOR + 2):
1670 cirrus_hook_read_gr(s, 0x13, &value);
1671 break;
1672 case (CIRRUS_MMIO_BLTFGCOLOR + 3):
1673 cirrus_hook_read_gr(s, 0x15, &value);
1674 break;
1675 case (CIRRUS_MMIO_BLTWIDTH + 0):
1676 cirrus_hook_read_gr(s, 0x20, &value);
1677 break;
1678 case (CIRRUS_MMIO_BLTWIDTH + 1):
1679 cirrus_hook_read_gr(s, 0x21, &value);
1680 break;
1681 case (CIRRUS_MMIO_BLTHEIGHT + 0):
1682 cirrus_hook_read_gr(s, 0x22, &value);
1683 break;
1684 case (CIRRUS_MMIO_BLTHEIGHT + 1):
1685 cirrus_hook_read_gr(s, 0x23, &value);
1686 break;
1687 case (CIRRUS_MMIO_BLTDESTPITCH + 0):
1688 cirrus_hook_read_gr(s, 0x24, &value);
1689 break;
1690 case (CIRRUS_MMIO_BLTDESTPITCH + 1):
1691 cirrus_hook_read_gr(s, 0x25, &value);
1692 break;
1693 case (CIRRUS_MMIO_BLTSRCPITCH + 0):
1694 cirrus_hook_read_gr(s, 0x26, &value);
1695 break;
1696 case (CIRRUS_MMIO_BLTSRCPITCH + 1):
1697 cirrus_hook_read_gr(s, 0x27, &value);
1698 break;
1699 case (CIRRUS_MMIO_BLTDESTADDR + 0):
1700 cirrus_hook_read_gr(s, 0x28, &value);
1701 break;
1702 case (CIRRUS_MMIO_BLTDESTADDR + 1):
1703 cirrus_hook_read_gr(s, 0x29, &value);
1704 break;
1705 case (CIRRUS_MMIO_BLTDESTADDR + 2):
1706 cirrus_hook_read_gr(s, 0x2a, &value);
1707 break;
1708 case (CIRRUS_MMIO_BLTSRCADDR + 0):
1709 cirrus_hook_read_gr(s, 0x2c, &value);
1710 break;
1711 case (CIRRUS_MMIO_BLTSRCADDR + 1):
1712 cirrus_hook_read_gr(s, 0x2d, &value);
1713 break;
1714 case (CIRRUS_MMIO_BLTSRCADDR + 2):
1715 cirrus_hook_read_gr(s, 0x2e, &value);
1716 break;
1717 case CIRRUS_MMIO_BLTWRITEMASK:
1718 cirrus_hook_read_gr(s, 0x2f, &value);
1719 break;
1720 case CIRRUS_MMIO_BLTMODE:
1721 cirrus_hook_read_gr(s, 0x30, &value);
1722 break;
1723 case CIRRUS_MMIO_BLTROP:
1724 cirrus_hook_read_gr(s, 0x32, &value);
1725 break;
1726 case CIRRUS_MMIO_BLTMODEEXT:
1727 cirrus_hook_read_gr(s, 0x33, &value);
1728 break;
1729 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
1730 cirrus_hook_read_gr(s, 0x34, &value);
1731 break;
1732 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
1733 cirrus_hook_read_gr(s, 0x35, &value);
1734 break;
1735 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
1736 cirrus_hook_read_gr(s, 0x38, &value);
1737 break;
1738 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
1739 cirrus_hook_read_gr(s, 0x39, &value);
1740 break;
1741 case CIRRUS_MMIO_BLTSTATUS:
1742 cirrus_hook_read_gr(s, 0x31, &value);
1743 break;
1744 default:
1745 #ifdef DEBUG_CIRRUS
1746 printf("cirrus: mmio read - address 0x%04x\n", address);
1747 #endif
1748 break;
1751 return (uint8_t) value;
1754 static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
1755 uint8_t value)
1757 switch (address) {
1758 case (CIRRUS_MMIO_BLTBGCOLOR + 0):
1759 cirrus_hook_write_gr(s, 0x00, value);
1760 break;
1761 case (CIRRUS_MMIO_BLTBGCOLOR + 1):
1762 cirrus_hook_write_gr(s, 0x10, value);
1763 break;
1764 case (CIRRUS_MMIO_BLTBGCOLOR + 2):
1765 cirrus_hook_write_gr(s, 0x12, value);
1766 break;
1767 case (CIRRUS_MMIO_BLTBGCOLOR + 3):
1768 cirrus_hook_write_gr(s, 0x14, value);
1769 break;
1770 case (CIRRUS_MMIO_BLTFGCOLOR + 0):
1771 cirrus_hook_write_gr(s, 0x01, value);
1772 break;
1773 case (CIRRUS_MMIO_BLTFGCOLOR + 1):
1774 cirrus_hook_write_gr(s, 0x11, value);
1775 break;
1776 case (CIRRUS_MMIO_BLTFGCOLOR + 2):
1777 cirrus_hook_write_gr(s, 0x13, value);
1778 break;
1779 case (CIRRUS_MMIO_BLTFGCOLOR + 3):
1780 cirrus_hook_write_gr(s, 0x15, value);
1781 break;
1782 case (CIRRUS_MMIO_BLTWIDTH + 0):
1783 cirrus_hook_write_gr(s, 0x20, value);
1784 break;
1785 case (CIRRUS_MMIO_BLTWIDTH + 1):
1786 cirrus_hook_write_gr(s, 0x21, value);
1787 break;
1788 case (CIRRUS_MMIO_BLTHEIGHT + 0):
1789 cirrus_hook_write_gr(s, 0x22, value);
1790 break;
1791 case (CIRRUS_MMIO_BLTHEIGHT + 1):
1792 cirrus_hook_write_gr(s, 0x23, value);
1793 break;
1794 case (CIRRUS_MMIO_BLTDESTPITCH + 0):
1795 cirrus_hook_write_gr(s, 0x24, value);
1796 break;
1797 case (CIRRUS_MMIO_BLTDESTPITCH + 1):
1798 cirrus_hook_write_gr(s, 0x25, value);
1799 break;
1800 case (CIRRUS_MMIO_BLTSRCPITCH + 0):
1801 cirrus_hook_write_gr(s, 0x26, value);
1802 break;
1803 case (CIRRUS_MMIO_BLTSRCPITCH + 1):
1804 cirrus_hook_write_gr(s, 0x27, value);
1805 break;
1806 case (CIRRUS_MMIO_BLTDESTADDR + 0):
1807 cirrus_hook_write_gr(s, 0x28, value);
1808 break;
1809 case (CIRRUS_MMIO_BLTDESTADDR + 1):
1810 cirrus_hook_write_gr(s, 0x29, value);
1811 break;
1812 case (CIRRUS_MMIO_BLTDESTADDR + 2):
1813 cirrus_hook_write_gr(s, 0x2a, value);
1814 break;
1815 case (CIRRUS_MMIO_BLTDESTADDR + 3):
1816 /* ignored */
1817 break;
1818 case (CIRRUS_MMIO_BLTSRCADDR + 0):
1819 cirrus_hook_write_gr(s, 0x2c, value);
1820 break;
1821 case (CIRRUS_MMIO_BLTSRCADDR + 1):
1822 cirrus_hook_write_gr(s, 0x2d, value);
1823 break;
1824 case (CIRRUS_MMIO_BLTSRCADDR + 2):
1825 cirrus_hook_write_gr(s, 0x2e, value);
1826 break;
1827 case CIRRUS_MMIO_BLTWRITEMASK:
1828 cirrus_hook_write_gr(s, 0x2f, value);
1829 break;
1830 case CIRRUS_MMIO_BLTMODE:
1831 cirrus_hook_write_gr(s, 0x30, value);
1832 break;
1833 case CIRRUS_MMIO_BLTROP:
1834 cirrus_hook_write_gr(s, 0x32, value);
1835 break;
1836 case CIRRUS_MMIO_BLTMODEEXT:
1837 cirrus_hook_write_gr(s, 0x33, value);
1838 break;
1839 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
1840 cirrus_hook_write_gr(s, 0x34, value);
1841 break;
1842 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
1843 cirrus_hook_write_gr(s, 0x35, value);
1844 break;
1845 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
1846 cirrus_hook_write_gr(s, 0x38, value);
1847 break;
1848 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
1849 cirrus_hook_write_gr(s, 0x39, value);
1850 break;
1851 case CIRRUS_MMIO_BLTSTATUS:
1852 cirrus_hook_write_gr(s, 0x31, value);
1853 break;
1854 default:
1855 #ifdef DEBUG_CIRRUS
1856 printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n",
1857 address, value);
1858 #endif
1859 break;
1863 /***************************************
1865 * write mode 4/5
1867 * assume TARGET_PAGE_SIZE >= 16
1869 ***************************************/
1871 static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
1872 unsigned mode,
1873 unsigned offset,
1874 uint32_t mem_value)
1876 int x;
1877 unsigned val = mem_value;
1878 uint8_t *dst;
1880 dst = s->vram_ptr + offset;
1881 for (x = 0; x < 8; x++) {
1882 if (val & 0x80) {
1883 *dst = s->cirrus_shadow_gr1;
1884 } else if (mode == 5) {
1885 *dst = s->cirrus_shadow_gr0;
1887 val <<= 1;
1888 dst++;
1890 cpu_physical_memory_set_dirty(s->vram_offset + offset);
1891 cpu_physical_memory_set_dirty(s->vram_offset + offset + 7);
1894 static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
1895 unsigned mode,
1896 unsigned offset,
1897 uint32_t mem_value)
1899 int x;
1900 unsigned val = mem_value;
1901 uint8_t *dst;
1903 dst = s->vram_ptr + offset;
1904 for (x = 0; x < 8; x++) {
1905 if (val & 0x80) {
1906 *dst = s->cirrus_shadow_gr1;
1907 *(dst + 1) = s->gr[0x11];
1908 } else if (mode == 5) {
1909 *dst = s->cirrus_shadow_gr0;
1910 *(dst + 1) = s->gr[0x10];
1912 val <<= 1;
1913 dst += 2;
1915 cpu_physical_memory_set_dirty(s->vram_offset + offset);
1916 cpu_physical_memory_set_dirty(s->vram_offset + offset + 15);
1919 /***************************************
1921 * memory access between 0xa0000-0xbffff
1923 ***************************************/
1925 static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
1927 CirrusVGAState *s = opaque;
1928 unsigned bank_index;
1929 unsigned bank_offset;
1930 uint32_t val;
1932 if ((s->sr[0x07] & 0x01) == 0) {
1933 return vga_mem_readb(s, addr);
1936 addr &= 0x1ffff;
1938 if (addr < 0x10000) {
1939 /* XXX handle bitblt */
1940 /* video memory */
1941 bank_index = addr >> 15;
1942 bank_offset = addr & 0x7fff;
1943 if (bank_offset < s->cirrus_bank_limit[bank_index]) {
1944 bank_offset += s->cirrus_bank_base[bank_index];
1945 if ((s->gr[0x0B] & 0x14) == 0x14) {
1946 bank_offset <<= 4;
1947 } else if (s->gr[0x0B] & 0x02) {
1948 bank_offset <<= 3;
1950 bank_offset &= s->cirrus_addr_mask;
1951 val = *(s->vram_ptr + bank_offset);
1952 } else
1953 val = 0xff;
1954 } else if (addr >= 0x18000 && addr < 0x18100) {
1955 /* memory-mapped I/O */
1956 val = 0xff;
1957 if ((s->sr[0x17] & 0x44) == 0x04) {
1958 val = cirrus_mmio_blt_read(s, addr & 0xff);
1960 } else {
1961 val = 0xff;
1962 #ifdef DEBUG_CIRRUS
1963 printf("cirrus: mem_readb %06x\n", addr);
1964 #endif
1966 return val;
1969 static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr)
1971 uint32_t v;
1972 #ifdef TARGET_WORDS_BIGENDIAN
1973 v = cirrus_vga_mem_readb(opaque, addr) << 8;
1974 v |= cirrus_vga_mem_readb(opaque, addr + 1);
1975 #else
1976 v = cirrus_vga_mem_readb(opaque, addr);
1977 v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
1978 #endif
1979 return v;
1982 static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr)
1984 uint32_t v;
1985 #ifdef TARGET_WORDS_BIGENDIAN
1986 v = cirrus_vga_mem_readb(opaque, addr) << 24;
1987 v |= cirrus_vga_mem_readb(opaque, addr + 1) << 16;
1988 v |= cirrus_vga_mem_readb(opaque, addr + 2) << 8;
1989 v |= cirrus_vga_mem_readb(opaque, addr + 3);
1990 #else
1991 v = cirrus_vga_mem_readb(opaque, addr);
1992 v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
1993 v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16;
1994 v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24;
1995 #endif
1996 return v;
1999 static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
2000 uint32_t mem_value)
2002 CirrusVGAState *s = opaque;
2003 unsigned bank_index;
2004 unsigned bank_offset;
2005 unsigned mode;
2007 if ((s->sr[0x07] & 0x01) == 0) {
2008 vga_mem_writeb(s, addr, mem_value);
2009 return;
2012 addr &= 0x1ffff;
2014 if (addr < 0x10000) {
2015 if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
2016 /* bitblt */
2017 *s->cirrus_srcptr++ = (uint8_t) mem_value;
2018 if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
2019 cirrus_bitblt_cputovideo_next(s);
2021 } else {
2022 /* video memory */
2023 bank_index = addr >> 15;
2024 bank_offset = addr & 0x7fff;
2025 if (bank_offset < s->cirrus_bank_limit[bank_index]) {
2026 bank_offset += s->cirrus_bank_base[bank_index];
2027 if ((s->gr[0x0B] & 0x14) == 0x14) {
2028 bank_offset <<= 4;
2029 } else if (s->gr[0x0B] & 0x02) {
2030 bank_offset <<= 3;
2032 bank_offset &= s->cirrus_addr_mask;
2033 mode = s->gr[0x05] & 0x7;
2034 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
2035 *(s->vram_ptr + bank_offset) = mem_value;
2036 cpu_physical_memory_set_dirty(s->vram_offset +
2037 bank_offset);
2038 } else {
2039 if ((s->gr[0x0B] & 0x14) != 0x14) {
2040 cirrus_mem_writeb_mode4and5_8bpp(s, mode,
2041 bank_offset,
2042 mem_value);
2043 } else {
2044 cirrus_mem_writeb_mode4and5_16bpp(s, mode,
2045 bank_offset,
2046 mem_value);
2051 } else if (addr >= 0x18000 && addr < 0x18100) {
2052 /* memory-mapped I/O */
2053 if ((s->sr[0x17] & 0x44) == 0x04) {
2054 cirrus_mmio_blt_write(s, addr & 0xff, mem_value);
2056 } else {
2057 #ifdef DEBUG_CIRRUS
2058 printf("cirrus: mem_writeb %06x value %02x\n", addr, mem_value);
2059 #endif
2063 static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
2065 #ifdef TARGET_WORDS_BIGENDIAN
2066 cirrus_vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
2067 cirrus_vga_mem_writeb(opaque, addr + 1, val & 0xff);
2068 #else
2069 cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
2070 cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2071 #endif
2074 static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2076 #ifdef TARGET_WORDS_BIGENDIAN
2077 cirrus_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
2078 cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
2079 cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
2080 cirrus_vga_mem_writeb(opaque, addr + 3, val & 0xff);
2081 #else
2082 cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
2083 cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2084 cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
2085 cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
2086 #endif
2089 static CPUReadMemoryFunc *cirrus_vga_mem_read[3] = {
2090 cirrus_vga_mem_readb,
2091 cirrus_vga_mem_readw,
2092 cirrus_vga_mem_readl,
2093 };
2095 static CPUWriteMemoryFunc *cirrus_vga_mem_write[3] = {
2096 cirrus_vga_mem_writeb,
2097 cirrus_vga_mem_writew,
2098 cirrus_vga_mem_writel,
2099 };
2101 /***************************************
2103 * hardware cursor
2105 ***************************************/
2107 static inline void invalidate_cursor1(CirrusVGAState *s)
2109 if (s->last_hw_cursor_size) {
2110 vga_invalidate_scanlines((VGAState *)s,
2111 s->last_hw_cursor_y + s->last_hw_cursor_y_start,
2112 s->last_hw_cursor_y + s->last_hw_cursor_y_end);
2116 static inline void cirrus_cursor_compute_yrange(CirrusVGAState *s)
2118 const uint8_t *src;
2119 uint32_t content;
2120 int y, y_min, y_max;
2122 src = s->vram_ptr + s->real_vram_size - 16 * 1024;
2123 if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
2124 src += (s->sr[0x13] & 0x3c) * 256;
2125 y_min = 64;
2126 y_max = -1;
2127 for(y = 0; y < 64; y++) {
2128 content = ((uint32_t *)src)[0] |
2129 ((uint32_t *)src)[1] |
2130 ((uint32_t *)src)[2] |
2131 ((uint32_t *)src)[3];
2132 if (content) {
2133 if (y < y_min)
2134 y_min = y;
2135 if (y > y_max)
2136 y_max = y;
2138 src += 16;
2140 } else {
2141 src += (s->sr[0x13] & 0x3f) * 256;
2142 y_min = 32;
2143 y_max = -1;
2144 for(y = 0; y < 32; y++) {
2145 content = ((uint32_t *)src)[0] |
2146 ((uint32_t *)(src + 128))[0];
2147 if (content) {
2148 if (y < y_min)
2149 y_min = y;
2150 if (y > y_max)
2151 y_max = y;
2153 src += 4;
2156 if (y_min > y_max) {
2157 s->last_hw_cursor_y_start = 0;
2158 s->last_hw_cursor_y_end = 0;
2159 } else {
2160 s->last_hw_cursor_y_start = y_min;
2161 s->last_hw_cursor_y_end = y_max + 1;
2165 /* NOTE: we do not currently handle the cursor bitmap change, so we
2166 update the cursor only if it moves. */
2167 static void cirrus_cursor_invalidate(VGAState *s1)
2169 CirrusVGAState *s = (CirrusVGAState *)s1;
2170 int size;
2172 if (!s->sr[0x12] & CIRRUS_CURSOR_SHOW) {
2173 size = 0;
2174 } else {
2175 if (s->sr[0x12] & CIRRUS_CURSOR_LARGE)
2176 size = 64;
2177 else
2178 size = 32;
2180 /* invalidate last cursor and new cursor if any change */
2181 if (s->last_hw_cursor_size != size ||
2182 s->last_hw_cursor_x != s->hw_cursor_x ||
2183 s->last_hw_cursor_y != s->hw_cursor_y) {
2185 invalidate_cursor1(s);
2187 s->last_hw_cursor_size = size;
2188 s->last_hw_cursor_x = s->hw_cursor_x;
2189 s->last_hw_cursor_y = s->hw_cursor_y;
2190 /* compute the real cursor min and max y */
2191 cirrus_cursor_compute_yrange(s);
2192 invalidate_cursor1(s);
2196 static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y)
2198 CirrusVGAState *s = (CirrusVGAState *)s1;
2199 int w, h, bpp, x1, x2, poffset;
2200 unsigned int color0, color1;
2201 const uint8_t *palette, *src;
2202 uint32_t content;
2204 if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW))
2205 return;
2206 /* fast test to see if the cursor intersects with the scan line */
2207 if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
2208 h = 64;
2209 } else {
2210 h = 32;
2212 if (scr_y < s->hw_cursor_y ||
2213 scr_y >= (s->hw_cursor_y + h))
2214 return;
2216 src = s->vram_ptr + s->real_vram_size - 16 * 1024;
2217 if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
2218 src += (s->sr[0x13] & 0x3c) * 256;
2219 src += (scr_y - s->hw_cursor_y) * 16;
2220 poffset = 8;
2221 content = ((uint32_t *)src)[0] |
2222 ((uint32_t *)src)[1] |
2223 ((uint32_t *)src)[2] |
2224 ((uint32_t *)src)[3];
2225 } else {
2226 src += (s->sr[0x13] & 0x3f) * 256;
2227 src += (scr_y - s->hw_cursor_y) * 4;
2228 poffset = 128;
2229 content = ((uint32_t *)src)[0] |
2230 ((uint32_t *)(src + 128))[0];
2232 /* if nothing to draw, no need to continue */
2233 if (!content)
2234 return;
2235 w = h;
2237 x1 = s->hw_cursor_x;
2238 if (x1 >= s->last_scr_width)
2239 return;
2240 x2 = s->hw_cursor_x + w;
2241 if (x2 > s->last_scr_width)
2242 x2 = s->last_scr_width;
2243 w = x2 - x1;
2244 palette = s->cirrus_hidden_palette;
2245 color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]),
2246 c6_to_8(palette[0x0 * 3 + 1]),
2247 c6_to_8(palette[0x0 * 3 + 2]));
2248 color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]),
2249 c6_to_8(palette[0xf * 3 + 1]),
2250 c6_to_8(palette[0xf * 3 + 2]));
2251 bpp = ((s->ds->depth + 7) >> 3);
2252 d1 += x1 * bpp;
2253 switch(s->ds->depth) {
2254 default:
2255 break;
2256 case 8:
2257 vga_draw_cursor_line_8(d1, src, poffset, w, color0, color1, 0xff);
2258 break;
2259 case 15:
2260 vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0x7fff);
2261 break;
2262 case 16:
2263 vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0xffff);
2264 break;
2265 case 32:
2266 vga_draw_cursor_line_32(d1, src, poffset, w, color0, color1, 0xffffff);
2267 break;
2271 /***************************************
2273 * LFB memory access
2275 ***************************************/
2277 static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
2279 CirrusVGAState *s = (CirrusVGAState *) opaque;
2280 uint32_t ret;
2282 addr &= s->cirrus_addr_mask;
2284 if (((s->sr[0x17] & 0x44) == 0x44) &&
2285 ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
2286 /* memory-mapped I/O */
2287 ret = cirrus_mmio_blt_read(s, addr & 0xff);
2288 } else if (0) {
2289 /* XXX handle bitblt */
2290 ret = 0xff;
2291 } else {
2292 /* video memory */
2293 if ((s->gr[0x0B] & 0x14) == 0x14) {
2294 addr <<= 4;
2295 } else if (s->gr[0x0B] & 0x02) {
2296 addr <<= 3;
2298 addr &= s->cirrus_addr_mask;
2299 ret = *(s->vram_ptr + addr);
2302 return ret;
2305 static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr)
2307 uint32_t v;
2308 #ifdef TARGET_WORDS_BIGENDIAN
2309 v = cirrus_linear_readb(opaque, addr) << 8;
2310 v |= cirrus_linear_readb(opaque, addr + 1);
2311 #else
2312 v = cirrus_linear_readb(opaque, addr);
2313 v |= cirrus_linear_readb(opaque, addr + 1) << 8;
2314 #endif
2315 return v;
2318 static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr)
2320 uint32_t v;
2321 #ifdef TARGET_WORDS_BIGENDIAN
2322 v = cirrus_linear_readb(opaque, addr) << 24;
2323 v |= cirrus_linear_readb(opaque, addr + 1) << 16;
2324 v |= cirrus_linear_readb(opaque, addr + 2) << 8;
2325 v |= cirrus_linear_readb(opaque, addr + 3);
2326 #else
2327 v = cirrus_linear_readb(opaque, addr);
2328 v |= cirrus_linear_readb(opaque, addr + 1) << 8;
2329 v |= cirrus_linear_readb(opaque, addr + 2) << 16;
2330 v |= cirrus_linear_readb(opaque, addr + 3) << 24;
2331 #endif
2332 return v;
2335 static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
2336 uint32_t val)
2338 CirrusVGAState *s = (CirrusVGAState *) opaque;
2339 unsigned mode;
2341 addr &= s->cirrus_addr_mask;
2343 if (((s->sr[0x17] & 0x44) == 0x44) &&
2344 ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
2345 /* memory-mapped I/O */
2346 cirrus_mmio_blt_write(s, addr & 0xff, val);
2347 } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
2348 /* bitblt */
2349 *s->cirrus_srcptr++ = (uint8_t) val;
2350 if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
2351 cirrus_bitblt_cputovideo_next(s);
2353 } else {
2354 /* video memory */
2355 if ((s->gr[0x0B] & 0x14) == 0x14) {
2356 addr <<= 4;
2357 } else if (s->gr[0x0B] & 0x02) {
2358 addr <<= 3;
2360 addr &= s->cirrus_addr_mask;
2362 mode = s->gr[0x05] & 0x7;
2363 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
2364 *(s->vram_ptr + addr) = (uint8_t) val;
2365 cpu_physical_memory_set_dirty(s->vram_offset + addr);
2366 } else {
2367 if ((s->gr[0x0B] & 0x14) != 0x14) {
2368 cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
2369 } else {
2370 cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val);
2376 static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr,
2377 uint32_t val)
2379 #ifdef TARGET_WORDS_BIGENDIAN
2380 cirrus_linear_writeb(opaque, addr, (val >> 8) & 0xff);
2381 cirrus_linear_writeb(opaque, addr + 1, val & 0xff);
2382 #else
2383 cirrus_linear_writeb(opaque, addr, val & 0xff);
2384 cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2385 #endif
2388 static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr,
2389 uint32_t val)
2391 #ifdef TARGET_WORDS_BIGENDIAN
2392 cirrus_linear_writeb(opaque, addr, (val >> 24) & 0xff);
2393 cirrus_linear_writeb(opaque, addr + 1, (val >> 16) & 0xff);
2394 cirrus_linear_writeb(opaque, addr + 2, (val >> 8) & 0xff);
2395 cirrus_linear_writeb(opaque, addr + 3, val & 0xff);
2396 #else
2397 cirrus_linear_writeb(opaque, addr, val & 0xff);
2398 cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2399 cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff);
2400 cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff);
2401 #endif
2405 static CPUReadMemoryFunc *cirrus_linear_read[3] = {
2406 cirrus_linear_readb,
2407 cirrus_linear_readw,
2408 cirrus_linear_readl,
2409 };
2411 static CPUWriteMemoryFunc *cirrus_linear_write[3] = {
2412 cirrus_linear_writeb,
2413 cirrus_linear_writew,
2414 cirrus_linear_writel,
2415 };
2417 static void cirrus_linear_mem_writeb(void *opaque, target_phys_addr_t addr,
2418 uint32_t val)
2420 CirrusVGAState *s = (CirrusVGAState *) opaque;
2422 addr &= s->cirrus_addr_mask;
2423 *(s->vram_ptr + addr) = val;
2424 cpu_physical_memory_set_dirty(s->vram_offset + addr);
2427 static void cirrus_linear_mem_writew(void *opaque, target_phys_addr_t addr,
2428 uint32_t val)
2430 CirrusVGAState *s = (CirrusVGAState *) opaque;
2432 addr &= s->cirrus_addr_mask;
2433 cpu_to_le16w((uint16_t *)(s->vram_ptr + addr), val);
2434 cpu_physical_memory_set_dirty(s->vram_offset + addr);
2437 static void cirrus_linear_mem_writel(void *opaque, target_phys_addr_t addr,
2438 uint32_t val)
2440 CirrusVGAState *s = (CirrusVGAState *) opaque;
2442 addr &= s->cirrus_addr_mask;
2443 cpu_to_le32w((uint32_t *)(s->vram_ptr + addr), val);
2444 cpu_physical_memory_set_dirty(s->vram_offset + addr);
2447 /***************************************
2449 * system to screen memory access
2451 ***************************************/
2454 static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr)
2456 uint32_t ret;
2458 /* XXX handle bitblt */
2459 ret = 0xff;
2460 return ret;
2463 static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr)
2465 uint32_t v;
2466 #ifdef TARGET_WORDS_BIGENDIAN
2467 v = cirrus_linear_bitblt_readb(opaque, addr) << 8;
2468 v |= cirrus_linear_bitblt_readb(opaque, addr + 1);
2469 #else
2470 v = cirrus_linear_bitblt_readb(opaque, addr);
2471 v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
2472 #endif
2473 return v;
2476 static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr)
2478 uint32_t v;
2479 #ifdef TARGET_WORDS_BIGENDIAN
2480 v = cirrus_linear_bitblt_readb(opaque, addr) << 24;
2481 v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 16;
2482 v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 8;
2483 v |= cirrus_linear_bitblt_readb(opaque, addr + 3);
2484 #else
2485 v = cirrus_linear_bitblt_readb(opaque, addr);
2486 v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
2487 v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 16;
2488 v |= cirrus_linear_bitblt_readb(opaque, addr + 3) << 24;
2489 #endif
2490 return v;
2493 static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr,
2494 uint32_t val)
2496 CirrusVGAState *s = (CirrusVGAState *) opaque;
2498 if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
2499 /* bitblt */
2500 *s->cirrus_srcptr++ = (uint8_t) val;
2501 if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
2502 cirrus_bitblt_cputovideo_next(s);
2507 static void cirrus_linear_bitblt_writew(void *opaque, target_phys_addr_t addr,
2508 uint32_t val)
2510 #ifdef TARGET_WORDS_BIGENDIAN
2511 cirrus_linear_bitblt_writeb(opaque, addr, (val >> 8) & 0xff);
2512 cirrus_linear_bitblt_writeb(opaque, addr + 1, val & 0xff);
2513 #else
2514 cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
2515 cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2516 #endif
2519 static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr,
2520 uint32_t val)
2522 #ifdef TARGET_WORDS_BIGENDIAN
2523 cirrus_linear_bitblt_writeb(opaque, addr, (val >> 24) & 0xff);
2524 cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 16) & 0xff);
2525 cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 8) & 0xff);
2526 cirrus_linear_bitblt_writeb(opaque, addr + 3, val & 0xff);
2527 #else
2528 cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
2529 cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2530 cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 16) & 0xff);
2531 cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff);
2532 #endif
2536 static CPUReadMemoryFunc *cirrus_linear_bitblt_read[3] = {
2537 cirrus_linear_bitblt_readb,
2538 cirrus_linear_bitblt_readw,
2539 cirrus_linear_bitblt_readl,
2540 };
2542 static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = {
2543 cirrus_linear_bitblt_writeb,
2544 cirrus_linear_bitblt_writew,
2545 cirrus_linear_bitblt_writel,
2546 };
2548 static void *set_vram_mapping(unsigned long begin, unsigned long end)
2550 xen_pfn_t *extent_start = NULL;
2551 unsigned long nr_extents;
2552 void *vram_pointer = NULL;
2553 int i;
2555 /* align begin and end address */
2556 begin = begin & TARGET_PAGE_MASK;
2557 end = begin + VGA_RAM_SIZE;
2558 end = (end + TARGET_PAGE_SIZE -1 ) & TARGET_PAGE_MASK;
2559 nr_extents = (end - begin) >> TARGET_PAGE_BITS;
2561 extent_start = malloc(sizeof(xen_pfn_t) * nr_extents);
2562 if (extent_start == NULL) {
2563 fprintf(stderr, "Failed malloc on set_vram_mapping\n");
2564 return NULL;
2567 memset(extent_start, 0, sizeof(xen_pfn_t) * nr_extents);
2569 for (i = 0; i < nr_extents; i++)
2570 extent_start[i] = (begin + i * TARGET_PAGE_SIZE) >> TARGET_PAGE_BITS;
2572 if (set_mm_mapping(xc_handle, domid, nr_extents, 0, extent_start) < 0) {
2573 fprintf(logfile, "Failed set_mm_mapping\n");
2574 free(extent_start);
2575 return NULL;
2578 (void)xc_domain_pin_memory_cacheattr(
2579 xc_handle, domid,
2580 begin >> TARGET_PAGE_BITS,
2581 end >> TARGET_PAGE_BITS,
2582 XEN_DOMCTL_MEM_CACHEATTR_WB);
2584 vram_pointer = xc_map_foreign_pages(xc_handle, domid,
2585 PROT_READ|PROT_WRITE,
2586 extent_start, nr_extents);
2587 if (vram_pointer == NULL) {
2588 fprintf(logfile, "xc_map_foreign_batch vgaram returned error %d\n",
2589 errno);
2590 free(extent_start);
2591 return NULL;
2594 memset(vram_pointer, 0, nr_extents * TARGET_PAGE_SIZE);
2596 #ifdef CONFIG_STUBDOM
2597 xenfb_pv_display_start(vram_pointer);
2598 #endif
2600 free(extent_start);
2602 return vram_pointer;
2605 static int unset_vram_mapping(unsigned long begin, unsigned long end,
2606 void *mapping)
2608 xen_pfn_t *extent_start = NULL;
2609 unsigned long nr_extents;
2610 int i;
2612 /* align begin and end address */
2614 end = begin + VGA_RAM_SIZE;
2615 begin = begin & TARGET_PAGE_MASK;
2616 end = (end + TARGET_PAGE_SIZE -1 ) & TARGET_PAGE_MASK;
2617 nr_extents = (end - begin) >> TARGET_PAGE_BITS;
2619 extent_start = malloc(sizeof(xen_pfn_t) * nr_extents);
2621 if (extent_start == NULL) {
2622 fprintf(stderr, "Failed malloc on set_mm_mapping\n");
2623 return -1;
2626 /* Drop our own references to the vram pages */
2627 munmap(mapping, nr_extents * TARGET_PAGE_SIZE);
2629 /* Now drop the guest's mappings */
2630 memset(extent_start, 0, sizeof(xen_pfn_t) * nr_extents);
2631 for (i = 0; i < nr_extents; i++)
2632 extent_start[i] = (begin + (i * TARGET_PAGE_SIZE)) >> TARGET_PAGE_BITS;
2633 unset_mm_mapping(xc_handle, domid, nr_extents, 0, extent_start);
2635 free(extent_start);
2637 return 0;
2640 /* Compute the memory access functions */
2641 static void cirrus_update_memory_access(CirrusVGAState *s)
2643 unsigned mode;
2645 if ((s->sr[0x17] & 0x44) == 0x44) {
2646 goto generic_io;
2647 } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
2648 goto generic_io;
2649 } else {
2650 if ((s->gr[0x0B] & 0x14) == 0x14) {
2651 goto generic_io;
2652 } else if (s->gr[0x0B] & 0x02) {
2653 goto generic_io;
2656 mode = s->gr[0x05] & 0x7;
2657 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
2658 if (s->lfb_addr && s->lfb_end && !s->map_addr) {
2659 void *vram_pointer, *old_vram;
2661 vram_pointer = set_vram_mapping(s->lfb_addr,
2662 s->lfb_end);
2663 if (!vram_pointer)
2664 fprintf(stderr, "NULL vram_pointer\n");
2665 else {
2666 old_vram = vga_update_vram((VGAState *)s, vram_pointer,
2667 VGA_RAM_SIZE);
2668 qemu_free(old_vram);
2670 s->map_addr = s->lfb_addr;
2671 s->map_end = s->lfb_end;
2673 s->cirrus_linear_write[0] = cirrus_linear_mem_writeb;
2674 s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
2675 s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
2676 } else {
2677 generic_io:
2678 if (s->lfb_addr && s->lfb_end && s->map_addr) {
2679 void *old_vram;
2681 old_vram = vga_update_vram((VGAState *)s, NULL, VGA_RAM_SIZE);
2683 unset_vram_mapping(s->lfb_addr,
2684 s->lfb_end,
2685 old_vram);
2687 s->map_addr = s->map_end = 0;
2689 s->cirrus_linear_write[0] = cirrus_linear_writeb;
2690 s->cirrus_linear_write[1] = cirrus_linear_writew;
2691 s->cirrus_linear_write[2] = cirrus_linear_writel;
2697 /* I/O ports */
2699 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
2701 CirrusVGAState *s = opaque;
2702 int val, index;
2704 /* check port range access depending on color/monochrome mode */
2705 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION))
2706 || (addr >= 0x3d0 && addr <= 0x3df
2707 && !(s->msr & MSR_COLOR_EMULATION))) {
2708 val = 0xff;
2709 } else {
2710 switch (addr) {
2711 case 0x3c0:
2712 if (s->ar_flip_flop == 0) {
2713 val = s->ar_index;
2714 } else {
2715 val = 0;
2717 break;
2718 case 0x3c1:
2719 index = s->ar_index & 0x1f;
2720 if (index < 21)
2721 val = s->ar[index];
2722 else
2723 val = 0;
2724 break;
2725 case 0x3c2:
2726 val = s->st00;
2727 break;
2728 case 0x3c4:
2729 val = s->sr_index;
2730 break;
2731 case 0x3c5:
2732 if (cirrus_hook_read_sr(s, s->sr_index, &val))
2733 break;
2734 val = s->sr[s->sr_index];
2735 #ifdef DEBUG_VGA_REG
2736 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
2737 #endif
2738 break;
2739 case 0x3c6:
2740 cirrus_read_hidden_dac(s, &val);
2741 break;
2742 case 0x3c7:
2743 val = s->dac_state;
2744 break;
2745 case 0x3c8:
2746 val = s->dac_write_index;
2747 s->cirrus_hidden_dac_lockindex = 0;
2748 break;
2749 case 0x3c9:
2750 if (cirrus_hook_read_palette(s, &val))
2751 break;
2752 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
2753 if (++s->dac_sub_index == 3) {
2754 s->dac_sub_index = 0;
2755 s->dac_read_index++;
2757 break;
2758 case 0x3ca:
2759 val = s->fcr;
2760 break;
2761 case 0x3cc:
2762 val = s->msr;
2763 break;
2764 case 0x3ce:
2765 val = s->gr_index;
2766 break;
2767 case 0x3cf:
2768 if (cirrus_hook_read_gr(s, s->gr_index, &val))
2769 break;
2770 val = s->gr[s->gr_index];
2771 #ifdef DEBUG_VGA_REG
2772 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
2773 #endif
2774 break;
2775 case 0x3b4:
2776 case 0x3d4:
2777 val = s->cr_index;
2778 break;
2779 case 0x3b5:
2780 case 0x3d5:
2781 if (cirrus_hook_read_cr(s, s->cr_index, &val))
2782 break;
2783 val = s->cr[s->cr_index];
2784 #ifdef DEBUG_VGA_REG
2785 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
2786 #endif
2787 break;
2788 case 0x3ba:
2789 case 0x3da:
2790 /* just toggle to fool polling */
2791 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
2792 val = s->st01;
2793 s->ar_flip_flop = 0;
2794 break;
2795 default:
2796 val = 0x00;
2797 break;
2800 #if defined(DEBUG_VGA)
2801 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
2802 #endif
2803 return val;
2806 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
2808 CirrusVGAState *s = opaque;
2809 int index;
2811 /* check port range access depending on color/monochrome mode */
2812 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION))
2813 || (addr >= 0x3d0 && addr <= 0x3df
2814 && !(s->msr & MSR_COLOR_EMULATION)))
2815 return;
2817 #ifdef DEBUG_VGA
2818 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
2819 #endif
2821 switch (addr) {
2822 case 0x3c0:
2823 if (s->ar_flip_flop == 0) {
2824 val &= 0x3f;
2825 s->ar_index = val;
2826 } else {
2827 index = s->ar_index & 0x1f;
2828 switch (index) {
2829 case 0x00 ... 0x0f:
2830 s->ar[index] = val & 0x3f;
2831 break;
2832 case 0x10:
2833 s->ar[index] = val & ~0x10;
2834 break;
2835 case 0x11:
2836 s->ar[index] = val;
2837 break;
2838 case 0x12:
2839 s->ar[index] = val & ~0xc0;
2840 break;
2841 case 0x13:
2842 s->ar[index] = val & ~0xf0;
2843 break;
2844 case 0x14:
2845 s->ar[index] = val & ~0xf0;
2846 break;
2847 default:
2848 break;
2851 s->ar_flip_flop ^= 1;
2852 break;
2853 case 0x3c2:
2854 s->msr = val & ~0x10;
2855 break;
2856 case 0x3c4:
2857 s->sr_index = val;
2858 break;
2859 case 0x3c5:
2860 if (cirrus_hook_write_sr(s, s->sr_index, val))
2861 break;
2862 #ifdef DEBUG_VGA_REG
2863 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
2864 #endif
2865 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
2866 break;
2867 case 0x3c6:
2868 cirrus_write_hidden_dac(s, val);
2869 break;
2870 case 0x3c7:
2871 s->dac_read_index = val;
2872 s->dac_sub_index = 0;
2873 s->dac_state = 3;
2874 break;
2875 case 0x3c8:
2876 s->dac_write_index = val;
2877 s->dac_sub_index = 0;
2878 s->dac_state = 0;
2879 break;
2880 case 0x3c9:
2881 if (cirrus_hook_write_palette(s, val))
2882 break;
2883 s->dac_cache[s->dac_sub_index] = val;
2884 if (++s->dac_sub_index == 3) {
2885 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
2886 s->dac_sub_index = 0;
2887 s->dac_write_index++;
2889 break;
2890 case 0x3ce:
2891 s->gr_index = val;
2892 break;
2893 case 0x3cf:
2894 if (cirrus_hook_write_gr(s, s->gr_index, val))
2895 break;
2896 #ifdef DEBUG_VGA_REG
2897 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
2898 #endif
2899 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
2900 break;
2901 case 0x3b4:
2902 case 0x3d4:
2903 s->cr_index = val;
2904 break;
2905 case 0x3b5:
2906 case 0x3d5:
2907 if (cirrus_hook_write_cr(s, s->cr_index, val))
2908 break;
2909 #ifdef DEBUG_VGA_REG
2910 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
2911 #endif
2912 /* handle CR0-7 protection */
2913 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
2914 /* can always write bit 4 of CR7 */
2915 if (s->cr_index == 7)
2916 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
2917 return;
2919 switch (s->cr_index) {
2920 case 0x01: /* horizontal display end */
2921 case 0x07:
2922 case 0x09:
2923 case 0x0c:
2924 case 0x0d:
2925 case 0x12: /* veritcal display end */
2926 s->cr[s->cr_index] = val;
2927 break;
2929 default:
2930 s->cr[s->cr_index] = val;
2931 break;
2933 break;
2934 case 0x3ba:
2935 case 0x3da:
2936 s->fcr = val & 0x10;
2937 break;
2941 /***************************************
2943 * memory-mapped I/O access
2945 ***************************************/
2947 static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr)
2949 CirrusVGAState *s = (CirrusVGAState *) opaque;
2951 addr &= CIRRUS_PNPMMIO_SIZE - 1;
2953 if (addr >= 0x100) {
2954 return cirrus_mmio_blt_read(s, addr - 0x100);
2955 } else {
2956 return vga_ioport_read(s, addr + 0x3c0);
2960 static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr)
2962 uint32_t v;
2963 #ifdef TARGET_WORDS_BIGENDIAN
2964 v = cirrus_mmio_readb(opaque, addr) << 8;
2965 v |= cirrus_mmio_readb(opaque, addr + 1);
2966 #else
2967 v = cirrus_mmio_readb(opaque, addr);
2968 v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
2969 #endif
2970 return v;
2973 static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr)
2975 uint32_t v;
2976 #ifdef TARGET_WORDS_BIGENDIAN
2977 v = cirrus_mmio_readb(opaque, addr) << 24;
2978 v |= cirrus_mmio_readb(opaque, addr + 1) << 16;
2979 v |= cirrus_mmio_readb(opaque, addr + 2) << 8;
2980 v |= cirrus_mmio_readb(opaque, addr + 3);
2981 #else
2982 v = cirrus_mmio_readb(opaque, addr);
2983 v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
2984 v |= cirrus_mmio_readb(opaque, addr + 2) << 16;
2985 v |= cirrus_mmio_readb(opaque, addr + 3) << 24;
2986 #endif
2987 return v;
2990 static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr,
2991 uint32_t val)
2993 CirrusVGAState *s = (CirrusVGAState *) opaque;
2995 addr &= CIRRUS_PNPMMIO_SIZE - 1;
2997 if (addr >= 0x100) {
2998 cirrus_mmio_blt_write(s, addr - 0x100, val);
2999 } else {
3000 vga_ioport_write(s, addr + 0x3c0, val);
3004 static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr,
3005 uint32_t val)
3007 #ifdef TARGET_WORDS_BIGENDIAN
3008 cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff);
3009 cirrus_mmio_writeb(opaque, addr + 1, val & 0xff);
3010 #else
3011 cirrus_mmio_writeb(opaque, addr, val & 0xff);
3012 cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
3013 #endif
3016 static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr,
3017 uint32_t val)
3019 #ifdef TARGET_WORDS_BIGENDIAN
3020 cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff);
3021 cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff);
3022 cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff);
3023 cirrus_mmio_writeb(opaque, addr + 3, val & 0xff);
3024 #else
3025 cirrus_mmio_writeb(opaque, addr, val & 0xff);
3026 cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
3027 cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff);
3028 cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff);
3029 #endif
3033 static CPUReadMemoryFunc *cirrus_mmio_read[3] = {
3034 cirrus_mmio_readb,
3035 cirrus_mmio_readw,
3036 cirrus_mmio_readl,
3037 };
3039 static CPUWriteMemoryFunc *cirrus_mmio_write[3] = {
3040 cirrus_mmio_writeb,
3041 cirrus_mmio_writew,
3042 cirrus_mmio_writel,
3043 };
3045 void cirrus_stop_acc(CirrusVGAState *s)
3047 if (s->map_addr){
3048 int error;
3049 s->map_addr = 0;
3050 error = unset_vram_mapping(s->lfb_addr,
3051 s->lfb_end, s->vram_ptr);
3052 fprintf(stderr, "cirrus_stop_acc:unset_vram_mapping.\n");
3056 void cirrus_restart_acc(CirrusVGAState *s)
3058 if (s->lfb_addr && s->lfb_end) {
3059 void *vram_pointer, *old_vram;
3060 fprintf(stderr, "cirrus_vga_load:re-enable vga acc.lfb_addr=0x%lx, lfb_end=0x%lx.\n",
3061 s->lfb_addr, s->lfb_end);
3062 vram_pointer = set_vram_mapping(s->lfb_addr ,s->lfb_end);
3063 if (!vram_pointer){
3064 fprintf(stderr, "cirrus_vga_load:NULL vram_pointer\n");
3065 } else {
3066 old_vram = vga_update_vram((VGAState *)s, vram_pointer,
3067 VGA_RAM_SIZE);
3068 qemu_free(old_vram);
3069 s->map_addr = s->lfb_addr;
3070 s->map_end = s->lfb_end;
3075 /* load/save state */
3077 static void cirrus_vga_save(QEMUFile *f, void *opaque)
3079 CirrusVGAState *s = opaque;
3080 uint8_t vga_acc;
3082 if (s->pci_dev)
3083 pci_device_save(s->pci_dev, f);
3085 qemu_put_be32s(f, &s->latch);
3086 qemu_put_8s(f, &s->sr_index);
3087 qemu_put_buffer(f, s->sr, 256);
3088 qemu_put_8s(f, &s->gr_index);
3089 qemu_put_8s(f, &s->cirrus_shadow_gr0);
3090 qemu_put_8s(f, &s->cirrus_shadow_gr1);
3091 qemu_put_buffer(f, s->gr + 2, 254);
3092 qemu_put_8s(f, &s->ar_index);
3093 qemu_put_buffer(f, s->ar, 21);
3094 qemu_put_be32s(f, &s->ar_flip_flop);
3095 qemu_put_8s(f, &s->cr_index);
3096 qemu_put_buffer(f, s->cr, 256);
3097 qemu_put_8s(f, &s->msr);
3098 qemu_put_8s(f, &s->fcr);
3099 qemu_put_8s(f, &s->st00);
3100 qemu_put_8s(f, &s->st01);
3102 qemu_put_8s(f, &s->dac_state);
3103 qemu_put_8s(f, &s->dac_sub_index);
3104 qemu_put_8s(f, &s->dac_read_index);
3105 qemu_put_8s(f, &s->dac_write_index);
3106 qemu_put_buffer(f, s->dac_cache, 3);
3107 qemu_put_buffer(f, s->palette, 768);
3109 qemu_put_be32s(f, &s->bank_offset);
3111 qemu_put_8s(f, &s->cirrus_hidden_dac_lockindex);
3112 qemu_put_8s(f, &s->cirrus_hidden_dac_data);
3114 qemu_put_be32s(f, &s->hw_cursor_x);
3115 qemu_put_be32s(f, &s->hw_cursor_y);
3116 /* XXX: we do not save the bitblt state - we assume we do not save
3117 the state when the blitter is active */
3119 vga_acc = (!!s->map_addr);
3120 qemu_put_8s(f, &vga_acc);
3121 qemu_put_be64s(f, (uint64_t*)&s->lfb_addr);
3122 qemu_put_be64s(f, (uint64_t*)&s->lfb_end);
3123 qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
3126 static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
3128 CirrusVGAState *s = opaque;
3129 uint8_t vga_acc = 0;
3130 int ret;
3132 if (version_id > 2)
3133 return -EINVAL;
3135 if (s->pci_dev && version_id >= 2) {
3136 ret = pci_device_load(s->pci_dev, f);
3137 if (ret < 0)
3138 return ret;
3141 qemu_get_be32s(f, &s->latch);
3142 qemu_get_8s(f, &s->sr_index);
3143 qemu_get_buffer(f, s->sr, 256);
3144 qemu_get_8s(f, &s->gr_index);
3145 qemu_get_8s(f, &s->cirrus_shadow_gr0);
3146 qemu_get_8s(f, &s->cirrus_shadow_gr1);
3147 s->gr[0x00] = s->cirrus_shadow_gr0 & 0x0f;
3148 s->gr[0x01] = s->cirrus_shadow_gr1 & 0x0f;
3149 qemu_get_buffer(f, s->gr + 2, 254);
3150 qemu_get_8s(f, &s->ar_index);
3151 qemu_get_buffer(f, s->ar, 21);
3152 qemu_get_be32s(f, &s->ar_flip_flop);
3153 qemu_get_8s(f, &s->cr_index);
3154 qemu_get_buffer(f, s->cr, 256);
3155 qemu_get_8s(f, &s->msr);
3156 qemu_get_8s(f, &s->fcr);
3157 qemu_get_8s(f, &s->st00);
3158 qemu_get_8s(f, &s->st01);
3160 qemu_get_8s(f, &s->dac_state);
3161 qemu_get_8s(f, &s->dac_sub_index);
3162 qemu_get_8s(f, &s->dac_read_index);
3163 qemu_get_8s(f, &s->dac_write_index);
3164 qemu_get_buffer(f, s->dac_cache, 3);
3165 qemu_get_buffer(f, s->palette, 768);
3167 qemu_get_be32s(f, &s->bank_offset);
3169 qemu_get_8s(f, &s->cirrus_hidden_dac_lockindex);
3170 qemu_get_8s(f, &s->cirrus_hidden_dac_data);
3172 qemu_get_be32s(f, &s->hw_cursor_x);
3173 qemu_get_be32s(f, &s->hw_cursor_y);
3175 qemu_get_8s(f, &vga_acc);
3176 qemu_get_be64s(f, (uint64_t*)&s->lfb_addr);
3177 qemu_get_be64s(f, (uint64_t*)&s->lfb_end);
3178 qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
3179 if (vga_acc){
3180 cirrus_restart_acc(s);
3183 /* force refresh */
3184 s->graphic_mode = -1;
3185 cirrus_update_bank_ptr(s, 0);
3186 cirrus_update_bank_ptr(s, 1);
3187 return 0;
3190 /***************************************
3192 * initialize
3194 ***************************************/
3196 static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
3198 int vga_io_memory, i;
3199 static int inited;
3201 if (!inited) {
3202 inited = 1;
3203 for(i = 0;i < 256; i++)
3204 rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */
3205 rop_to_index[CIRRUS_ROP_0] = 0;
3206 rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1;
3207 rop_to_index[CIRRUS_ROP_NOP] = 2;
3208 rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3;
3209 rop_to_index[CIRRUS_ROP_NOTDST] = 4;
3210 rop_to_index[CIRRUS_ROP_SRC] = 5;
3211 rop_to_index[CIRRUS_ROP_1] = 6;
3212 rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7;
3213 rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8;
3214 rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9;
3215 rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10;
3216 rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11;
3217 rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12;
3218 rop_to_index[CIRRUS_ROP_NOTSRC] = 13;
3219 rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14;
3220 rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15;
3223 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
3225 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
3226 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
3227 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
3228 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
3230 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
3232 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
3233 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
3234 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
3235 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
3237 vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read,
3238 cirrus_vga_mem_write, s);
3239 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
3240 vga_io_memory);
3242 s->sr[0x06] = 0x0f;
3243 if (device_id == CIRRUS_ID_CLGD5446) {
3244 /* 4MB 64 bit memory config, always PCI */
3245 s->sr[0x1F] = 0x2d; // MemClock
3246 s->gr[0x18] = 0x0f; // fastest memory configuration
3247 #if 1
3248 s->sr[0x0f] = 0x98;
3249 s->sr[0x17] = 0x20;
3250 s->sr[0x15] = 0x04; /* memory size, 3=2MB, 4=4MB */
3251 s->real_vram_size = 4096 * 1024;
3252 #else
3253 s->sr[0x0f] = 0x18;
3254 s->sr[0x17] = 0x20;
3255 s->sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */
3256 s->real_vram_size = 2048 * 1024;
3257 #endif
3258 } else {
3259 s->sr[0x1F] = 0x22; // MemClock
3260 s->sr[0x0F] = CIRRUS_MEMSIZE_2M;
3261 if (is_pci)
3262 s->sr[0x17] = CIRRUS_BUSTYPE_PCI;
3263 else
3264 s->sr[0x17] = CIRRUS_BUSTYPE_ISA;
3265 s->real_vram_size = 2048 * 1024;
3266 s->sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */
3268 s->cr[0x27] = device_id;
3270 /* Win2K seems to assume that the pattern buffer is at 0xff
3271 initially ! */
3272 memset(s->vram_ptr, 0xff, s->real_vram_size);
3274 s->cirrus_hidden_dac_lockindex = 5;
3275 s->cirrus_hidden_dac_data = 0;
3277 /* I/O handler for LFB */
3278 s->cirrus_linear_io_addr =
3279 cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write,
3280 s);
3281 s->cirrus_linear_write = cpu_get_io_memory_write(s->cirrus_linear_io_addr);
3283 /* I/O handler for LFB */
3284 s->cirrus_linear_bitblt_io_addr =
3285 cpu_register_io_memory(0, cirrus_linear_bitblt_read, cirrus_linear_bitblt_write,
3286 s);
3288 /* I/O handler for memory-mapped I/O */
3289 s->cirrus_mmio_io_addr =
3290 cpu_register_io_memory(0, cirrus_mmio_read, cirrus_mmio_write, s);
3292 /* XXX: s->vram_size must be a power of two */
3293 s->cirrus_addr_mask = s->real_vram_size - 1;
3294 s->linear_mmio_mask = s->real_vram_size - 256;
3296 s->get_bpp = cirrus_get_bpp;
3297 s->get_offsets = cirrus_get_offsets;
3298 s->get_resolution = cirrus_get_resolution;
3299 s->cursor_invalidate = cirrus_cursor_invalidate;
3300 s->cursor_draw_line = cirrus_cursor_draw_line;
3302 register_savevm("cirrus_vga", 0, 2, cirrus_vga_save, cirrus_vga_load, s);
3305 /***************************************
3307 * ISA bus support
3309 ***************************************/
3311 void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
3312 unsigned long vga_ram_offset, int vga_ram_size)
3314 CirrusVGAState *s;
3316 s = qemu_mallocz(sizeof(CirrusVGAState));
3318 vga_common_init((VGAState *)s,
3319 ds, vga_ram_base, vga_ram_offset, vga_ram_size);
3320 cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0);
3321 /* XXX ISA-LFB support */
3324 /***************************************
3326 * PCI bus support
3328 ***************************************/
3330 static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
3331 uint32_t addr, uint32_t size, int type)
3333 CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga;
3335 /* XXX: add byte swapping apertures */
3336 cpu_register_physical_memory(addr, s->vram_size,
3337 s->cirrus_linear_io_addr);
3338 s->lfb_addr = addr;
3339 s->lfb_end = addr + VGA_RAM_SIZE;
3341 if (s->map_addr && (s->lfb_addr != s->map_addr) &&
3342 (s->lfb_end != s->map_end))
3343 fprintf(logfile, "cirrus vga map change while on lfb mode\n");
3345 cpu_register_physical_memory(addr + 0x1000000, 0x400000,
3346 s->cirrus_linear_bitblt_io_addr);
3349 static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
3350 uint32_t addr, uint32_t size, int type)
3352 CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga;
3354 cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE,
3355 s->cirrus_mmio_io_addr);
3358 void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
3359 unsigned long vga_ram_offset, int vga_ram_size)
3361 PCICirrusVGAState *d;
3362 uint8_t *pci_conf;
3363 CirrusVGAState *s;
3364 int device_id;
3366 device_id = CIRRUS_ID_CLGD5446;
3368 /* setup PCI configuration registers */
3369 d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA",
3370 sizeof(PCICirrusVGAState),
3371 -1, NULL, NULL);
3372 pci_conf = d->dev.config;
3373 pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff);
3374 pci_conf[0x01] = (uint8_t) (PCI_VENDOR_CIRRUS >> 8);
3375 pci_conf[0x02] = (uint8_t) (device_id & 0xff);
3376 pci_conf[0x03] = (uint8_t) (device_id >> 8);
3377 pci_conf[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS;
3378 pci_conf[0x0a] = PCI_CLASS_SUB_VGA;
3379 pci_conf[0x0b] = PCI_CLASS_BASE_DISPLAY;
3380 pci_conf[0x0e] = PCI_CLASS_HEADERTYPE_00h;
3381 pci_conf[0x2c] = 0x53; /* subsystem vendor: XenSource */
3382 pci_conf[0x2d] = 0x58;
3383 pci_conf[0x2e] = 0x01; /* subsystem device */
3384 pci_conf[0x2f] = 0x00;
3386 /* setup VGA */
3387 s = &d->cirrus_vga;
3388 vga_common_init((VGAState *)s,
3389 ds, vga_ram_base, vga_ram_offset, vga_ram_size);
3390 cirrus_init_common(s, device_id, 1);
3391 s->pci_dev = (PCIDevice *)d;
3393 /* setup memory space */
3394 /* memory #0 LFB */
3395 /* memory #1 memory-mapped I/O */
3396 /* XXX: s->vram_size must be a power of two */
3397 pci_register_io_region((PCIDevice *)d, 0, 0x2000000,
3398 PCI_ADDRESS_SPACE_MEM_PREFETCH, cirrus_pci_lfb_map);
3399 if (device_id == CIRRUS_ID_CLGD5446) {
3400 pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE,
3401 PCI_ADDRESS_SPACE_MEM, cirrus_pci_mmio_map);
3403 /* XXX: ROM BIOS */