ia64/xen-unstable

view tools/ioemu/hw/cirrus_vga.c @ 18394:dade7f0bdc8d

hvm: Use main memory for video memory.

When creating an HVM domain, if e.g. another domain is created before
qemu allocates video memory, the extra 8MB memory ballooning is not
available any more, because it got consumed by the other domain.

This fixes it by taking video memory from the main memory:

- make hvmloader use e820_malloc to reserve some of the main memory
and notify ioemu of its address through the Xen platform PCI card.
- add XENMAPSPACE_mfn to the xen_add_to_physmap memory op, to allow
ioemu to move the MFNs between the original position and the PCI
mapping, when LFB acceleration is disabled/enabled
- add a remove_from_physmap memory op, to allow ioemu to unmap it
completely for the case of old guests with acceleration disabled.
- add xc_domain_memory_translate_gpfn_list to libxc to allow ioemu to
get the MFNs of the video memory.
- have xend save the PCI memory space instead of ioemu: if a memory
page is there, the guest can access it like usual memory, so xend
can safely be responsible to save it. The extra benefit is that
live migration will apply the logdirty optimization there too.
- handle old saved images, populating the video memory from ioemu if
really needed.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Aug 27 14:53:39 2008 +0100 (2008-08-27)
parents f472d708b9af
children 33d907ff2b04
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 /***************************************
285 *
286 * prototypes.
287 *
288 ***************************************/
291 static void cirrus_bitblt_reset(CirrusVGAState *s);
292 static void cirrus_update_memory_access(CirrusVGAState *s);
293 static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val);
295 /***************************************
296 *
297 * raster operations
298 *
299 ***************************************/
301 static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
302 uint8_t *dst,const uint8_t *src,
303 int dstpitch,int srcpitch,
304 int bltwidth,int bltheight)
305 {
306 }
308 static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
309 uint8_t *dst,
310 int dstpitch, int bltwidth,int bltheight)
311 {
312 }
314 #define ROP_NAME 0
315 #define ROP_OP(d, s) d = 0
316 #include "cirrus_vga_rop.h"
318 #define ROP_NAME src_and_dst
319 #define ROP_OP(d, s) d = (s) & (d)
320 #include "cirrus_vga_rop.h"
322 #define ROP_NAME src_and_notdst
323 #define ROP_OP(d, s) d = (s) & (~(d))
324 #include "cirrus_vga_rop.h"
326 #define ROP_NAME notdst
327 #define ROP_OP(d, s) d = ~(d)
328 #include "cirrus_vga_rop.h"
330 #define ROP_NAME src
331 #define ROP_OP(d, s) d = s
332 #include "cirrus_vga_rop.h"
334 #define ROP_NAME 1
335 #define ROP_OP(d, s) d = ~0
336 #include "cirrus_vga_rop.h"
338 #define ROP_NAME notsrc_and_dst
339 #define ROP_OP(d, s) d = (~(s)) & (d)
340 #include "cirrus_vga_rop.h"
342 #define ROP_NAME src_xor_dst
343 #define ROP_OP(d, s) d = (s) ^ (d)
344 #include "cirrus_vga_rop.h"
346 #define ROP_NAME src_or_dst
347 #define ROP_OP(d, s) d = (s) | (d)
348 #include "cirrus_vga_rop.h"
350 #define ROP_NAME notsrc_or_notdst
351 #define ROP_OP(d, s) d = (~(s)) | (~(d))
352 #include "cirrus_vga_rop.h"
354 #define ROP_NAME src_notxor_dst
355 #define ROP_OP(d, s) d = ~((s) ^ (d))
356 #include "cirrus_vga_rop.h"
358 #define ROP_NAME src_or_notdst
359 #define ROP_OP(d, s) d = (s) | (~(d))
360 #include "cirrus_vga_rop.h"
362 #define ROP_NAME notsrc
363 #define ROP_OP(d, s) d = (~(s))
364 #include "cirrus_vga_rop.h"
366 #define ROP_NAME notsrc_or_dst
367 #define ROP_OP(d, s) d = (~(s)) | (d)
368 #include "cirrus_vga_rop.h"
370 #define ROP_NAME notsrc_and_notdst
371 #define ROP_OP(d, s) d = (~(s)) & (~(d))
372 #include "cirrus_vga_rop.h"
374 static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = {
375 cirrus_bitblt_rop_fwd_0,
376 cirrus_bitblt_rop_fwd_src_and_dst,
377 cirrus_bitblt_rop_nop,
378 cirrus_bitblt_rop_fwd_src_and_notdst,
379 cirrus_bitblt_rop_fwd_notdst,
380 cirrus_bitblt_rop_fwd_src,
381 cirrus_bitblt_rop_fwd_1,
382 cirrus_bitblt_rop_fwd_notsrc_and_dst,
383 cirrus_bitblt_rop_fwd_src_xor_dst,
384 cirrus_bitblt_rop_fwd_src_or_dst,
385 cirrus_bitblt_rop_fwd_notsrc_or_notdst,
386 cirrus_bitblt_rop_fwd_src_notxor_dst,
387 cirrus_bitblt_rop_fwd_src_or_notdst,
388 cirrus_bitblt_rop_fwd_notsrc,
389 cirrus_bitblt_rop_fwd_notsrc_or_dst,
390 cirrus_bitblt_rop_fwd_notsrc_and_notdst,
391 };
393 static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = {
394 cirrus_bitblt_rop_bkwd_0,
395 cirrus_bitblt_rop_bkwd_src_and_dst,
396 cirrus_bitblt_rop_nop,
397 cirrus_bitblt_rop_bkwd_src_and_notdst,
398 cirrus_bitblt_rop_bkwd_notdst,
399 cirrus_bitblt_rop_bkwd_src,
400 cirrus_bitblt_rop_bkwd_1,
401 cirrus_bitblt_rop_bkwd_notsrc_and_dst,
402 cirrus_bitblt_rop_bkwd_src_xor_dst,
403 cirrus_bitblt_rop_bkwd_src_or_dst,
404 cirrus_bitblt_rop_bkwd_notsrc_or_notdst,
405 cirrus_bitblt_rop_bkwd_src_notxor_dst,
406 cirrus_bitblt_rop_bkwd_src_or_notdst,
407 cirrus_bitblt_rop_bkwd_notsrc,
408 cirrus_bitblt_rop_bkwd_notsrc_or_dst,
409 cirrus_bitblt_rop_bkwd_notsrc_and_notdst,
410 };
412 #define ROP2(name) {\
413 name ## _8,\
414 name ## _16,\
415 name ## _24,\
416 name ## _32,\
417 }
419 #define ROP_NOP2(func) {\
420 func,\
421 func,\
422 func,\
423 func,\
424 }
426 static const cirrus_bitblt_rop_t cirrus_patternfill[16][4] = {
427 ROP2(cirrus_patternfill_0),
428 ROP2(cirrus_patternfill_src_and_dst),
429 ROP_NOP2(cirrus_bitblt_rop_nop),
430 ROP2(cirrus_patternfill_src_and_notdst),
431 ROP2(cirrus_patternfill_notdst),
432 ROP2(cirrus_patternfill_src),
433 ROP2(cirrus_patternfill_1),
434 ROP2(cirrus_patternfill_notsrc_and_dst),
435 ROP2(cirrus_patternfill_src_xor_dst),
436 ROP2(cirrus_patternfill_src_or_dst),
437 ROP2(cirrus_patternfill_notsrc_or_notdst),
438 ROP2(cirrus_patternfill_src_notxor_dst),
439 ROP2(cirrus_patternfill_src_or_notdst),
440 ROP2(cirrus_patternfill_notsrc),
441 ROP2(cirrus_patternfill_notsrc_or_dst),
442 ROP2(cirrus_patternfill_notsrc_and_notdst),
443 };
445 static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = {
446 ROP2(cirrus_colorexpand_transp_0),
447 ROP2(cirrus_colorexpand_transp_src_and_dst),
448 ROP_NOP2(cirrus_bitblt_rop_nop),
449 ROP2(cirrus_colorexpand_transp_src_and_notdst),
450 ROP2(cirrus_colorexpand_transp_notdst),
451 ROP2(cirrus_colorexpand_transp_src),
452 ROP2(cirrus_colorexpand_transp_1),
453 ROP2(cirrus_colorexpand_transp_notsrc_and_dst),
454 ROP2(cirrus_colorexpand_transp_src_xor_dst),
455 ROP2(cirrus_colorexpand_transp_src_or_dst),
456 ROP2(cirrus_colorexpand_transp_notsrc_or_notdst),
457 ROP2(cirrus_colorexpand_transp_src_notxor_dst),
458 ROP2(cirrus_colorexpand_transp_src_or_notdst),
459 ROP2(cirrus_colorexpand_transp_notsrc),
460 ROP2(cirrus_colorexpand_transp_notsrc_or_dst),
461 ROP2(cirrus_colorexpand_transp_notsrc_and_notdst),
462 };
464 static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = {
465 ROP2(cirrus_colorexpand_0),
466 ROP2(cirrus_colorexpand_src_and_dst),
467 ROP_NOP2(cirrus_bitblt_rop_nop),
468 ROP2(cirrus_colorexpand_src_and_notdst),
469 ROP2(cirrus_colorexpand_notdst),
470 ROP2(cirrus_colorexpand_src),
471 ROP2(cirrus_colorexpand_1),
472 ROP2(cirrus_colorexpand_notsrc_and_dst),
473 ROP2(cirrus_colorexpand_src_xor_dst),
474 ROP2(cirrus_colorexpand_src_or_dst),
475 ROP2(cirrus_colorexpand_notsrc_or_notdst),
476 ROP2(cirrus_colorexpand_src_notxor_dst),
477 ROP2(cirrus_colorexpand_src_or_notdst),
478 ROP2(cirrus_colorexpand_notsrc),
479 ROP2(cirrus_colorexpand_notsrc_or_dst),
480 ROP2(cirrus_colorexpand_notsrc_and_notdst),
481 };
483 static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern_transp[16][4] = {
484 ROP2(cirrus_colorexpand_pattern_transp_0),
485 ROP2(cirrus_colorexpand_pattern_transp_src_and_dst),
486 ROP_NOP2(cirrus_bitblt_rop_nop),
487 ROP2(cirrus_colorexpand_pattern_transp_src_and_notdst),
488 ROP2(cirrus_colorexpand_pattern_transp_notdst),
489 ROP2(cirrus_colorexpand_pattern_transp_src),
490 ROP2(cirrus_colorexpand_pattern_transp_1),
491 ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_dst),
492 ROP2(cirrus_colorexpand_pattern_transp_src_xor_dst),
493 ROP2(cirrus_colorexpand_pattern_transp_src_or_dst),
494 ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_notdst),
495 ROP2(cirrus_colorexpand_pattern_transp_src_notxor_dst),
496 ROP2(cirrus_colorexpand_pattern_transp_src_or_notdst),
497 ROP2(cirrus_colorexpand_pattern_transp_notsrc),
498 ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_dst),
499 ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_notdst),
500 };
502 static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern[16][4] = {
503 ROP2(cirrus_colorexpand_pattern_0),
504 ROP2(cirrus_colorexpand_pattern_src_and_dst),
505 ROP_NOP2(cirrus_bitblt_rop_nop),
506 ROP2(cirrus_colorexpand_pattern_src_and_notdst),
507 ROP2(cirrus_colorexpand_pattern_notdst),
508 ROP2(cirrus_colorexpand_pattern_src),
509 ROP2(cirrus_colorexpand_pattern_1),
510 ROP2(cirrus_colorexpand_pattern_notsrc_and_dst),
511 ROP2(cirrus_colorexpand_pattern_src_xor_dst),
512 ROP2(cirrus_colorexpand_pattern_src_or_dst),
513 ROP2(cirrus_colorexpand_pattern_notsrc_or_notdst),
514 ROP2(cirrus_colorexpand_pattern_src_notxor_dst),
515 ROP2(cirrus_colorexpand_pattern_src_or_notdst),
516 ROP2(cirrus_colorexpand_pattern_notsrc),
517 ROP2(cirrus_colorexpand_pattern_notsrc_or_dst),
518 ROP2(cirrus_colorexpand_pattern_notsrc_and_notdst),
519 };
521 static const cirrus_fill_t cirrus_fill[16][4] = {
522 ROP2(cirrus_fill_0),
523 ROP2(cirrus_fill_src_and_dst),
524 ROP_NOP2(cirrus_bitblt_fill_nop),
525 ROP2(cirrus_fill_src_and_notdst),
526 ROP2(cirrus_fill_notdst),
527 ROP2(cirrus_fill_src),
528 ROP2(cirrus_fill_1),
529 ROP2(cirrus_fill_notsrc_and_dst),
530 ROP2(cirrus_fill_src_xor_dst),
531 ROP2(cirrus_fill_src_or_dst),
532 ROP2(cirrus_fill_notsrc_or_notdst),
533 ROP2(cirrus_fill_src_notxor_dst),
534 ROP2(cirrus_fill_src_or_notdst),
535 ROP2(cirrus_fill_notsrc),
536 ROP2(cirrus_fill_notsrc_or_dst),
537 ROP2(cirrus_fill_notsrc_and_notdst),
538 };
540 static inline void cirrus_bitblt_fgcol(CirrusVGAState *s)
541 {
542 unsigned int color;
543 switch (s->cirrus_blt_pixelwidth) {
544 case 1:
545 s->cirrus_blt_fgcol = s->cirrus_shadow_gr1;
546 break;
547 case 2:
548 color = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8);
549 s->cirrus_blt_fgcol = le16_to_cpu(color);
550 break;
551 case 3:
552 s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 |
553 (s->gr[0x11] << 8) | (s->gr[0x13] << 16);
554 break;
555 default:
556 case 4:
557 color = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8) |
558 (s->gr[0x13] << 16) | (s->gr[0x15] << 24);
559 s->cirrus_blt_fgcol = le32_to_cpu(color);
560 break;
561 }
562 }
564 static inline void cirrus_bitblt_bgcol(CirrusVGAState *s)
565 {
566 unsigned int color;
567 switch (s->cirrus_blt_pixelwidth) {
568 case 1:
569 s->cirrus_blt_bgcol = s->cirrus_shadow_gr0;
570 break;
571 case 2:
572 color = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8);
573 s->cirrus_blt_bgcol = le16_to_cpu(color);
574 break;
575 case 3:
576 s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 |
577 (s->gr[0x10] << 8) | (s->gr[0x12] << 16);
578 break;
579 default:
580 case 4:
581 color = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8) |
582 (s->gr[0x12] << 16) | (s->gr[0x14] << 24);
583 s->cirrus_blt_bgcol = le32_to_cpu(color);
584 break;
585 }
586 }
588 static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
589 int off_pitch, int bytesperline,
590 int lines)
591 {
592 int y;
593 int off_cur;
594 int off_cur_end;
596 for (y = 0; y < lines; y++) {
597 off_cur = off_begin;
598 off_cur_end = off_cur + bytesperline;
599 off_cur &= TARGET_PAGE_MASK;
600 while (off_cur < off_cur_end) {
601 cpu_physical_memory_set_dirty(s->vram_offset +
602 (off_cur & s->cirrus_addr_mask));
603 off_cur += TARGET_PAGE_SIZE;
604 }
605 off_begin += off_pitch;
606 }
607 }
609 static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
610 const uint8_t * src)
611 {
612 uint8_t *dst;
614 dst = s->vram_ptr + s->cirrus_blt_dstaddr;
615 (*s->cirrus_rop) (s, dst, src,
616 s->cirrus_blt_dstpitch, 0,
617 s->cirrus_blt_width, s->cirrus_blt_height);
618 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
619 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
620 s->cirrus_blt_height);
621 return 1;
622 }
624 /* fill */
626 static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
627 {
628 cirrus_fill_t rop_func;
630 rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
631 rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr,
632 s->cirrus_blt_dstpitch,
633 s->cirrus_blt_width, s->cirrus_blt_height);
634 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
635 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
636 s->cirrus_blt_height);
637 cirrus_bitblt_reset(s);
638 return 1;
639 }
641 /***************************************
642 *
643 * bitblt (video-to-video)
644 *
645 ***************************************/
647 static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
648 {
649 return cirrus_bitblt_common_patterncopy(s,
650 s->vram_ptr +
651 (s->cirrus_blt_srcaddr & ~7));
652 }
654 static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
655 {
656 int sx, sy;
657 int dx, dy;
658 int width, height;
659 int depth;
660 int notify = 0;
662 depth = s->get_bpp((VGAState *)s) / 8;
663 s->get_resolution((VGAState *)s, &width, &height);
665 /* extra x, y */
666 sx = (src % (width * depth)) / depth;
667 sy = (src / (width * depth));
668 dx = (dst % (width *depth)) / depth;
669 dy = (dst / (width * depth));
671 /* normalize width */
672 w /= depth;
674 /* if we're doing a backward copy, we have to adjust
675 our x/y to be the upper left corner (instead of the lower
676 right corner) */
677 if (s->cirrus_blt_dstpitch < 0) {
678 sx -= (s->cirrus_blt_width / depth) - 1;
679 dx -= (s->cirrus_blt_width / depth) - 1;
680 sy -= s->cirrus_blt_height - 1;
681 dy -= s->cirrus_blt_height - 1;
682 }
684 /* are we in the visible portion of memory? */
685 if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
686 (sx + w) <= width && (sy + h) <= height &&
687 (dx + w) <= width && (dy + h) <= height) {
688 notify = 1;
689 }
691 /* make to sure only copy if it's a plain copy ROP */
692 if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src &&
693 *s->cirrus_rop != cirrus_bitblt_rop_bkwd_src)
694 notify = 0;
696 /* we have to flush all pending changes so that the copy
697 is generated at the appropriate moment in time */
698 if (notify)
699 vga_hw_update();
701 (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
702 s->vram_ptr + s->cirrus_blt_srcaddr,
703 s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
704 s->cirrus_blt_width, s->cirrus_blt_height);
706 if (notify)
707 s->ds->dpy_copy(s->ds,
708 sx, sy, dx, dy,
709 s->cirrus_blt_width / depth,
710 s->cirrus_blt_height);
712 /* we don't have to notify the display that this portion has
713 changed since dpy_copy implies this */
715 if (!notify)
716 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
717 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
718 s->cirrus_blt_height);
719 }
721 static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
722 {
723 if (s->ds->dpy_copy) {
724 cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
725 s->cirrus_blt_srcaddr - s->start_addr,
726 s->cirrus_blt_width, s->cirrus_blt_height);
727 } else {
728 (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
729 s->vram_ptr + s->cirrus_blt_srcaddr,
730 s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
731 s->cirrus_blt_width, s->cirrus_blt_height);
733 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
734 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
735 s->cirrus_blt_height);
736 }
738 return 1;
739 }
741 /***************************************
742 *
743 * bitblt (cpu-to-video)
744 *
745 ***************************************/
747 static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
748 {
749 int copy_count;
750 uint8_t *end_ptr;
752 if (s->cirrus_srccounter > 0) {
753 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
754 cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
755 the_end:
756 s->cirrus_srccounter = 0;
757 cirrus_bitblt_reset(s);
758 } else {
759 /* at least one scan line */
760 do {
761 (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr,
762 s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
763 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
764 s->cirrus_blt_width, 1);
765 s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
766 s->cirrus_srccounter -= s->cirrus_blt_srcpitch;
767 if (s->cirrus_srccounter <= 0)
768 goto the_end;
769 /* more bytes than needed can be transfered because of
770 word alignment, so we keep them for the next line */
771 /* XXX: keep alignment to speed up transfer */
772 end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
773 copy_count = s->cirrus_srcptr_end - end_ptr;
774 memmove(s->cirrus_bltbuf, end_ptr, copy_count);
775 s->cirrus_srcptr = s->cirrus_bltbuf + copy_count;
776 s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
777 } while (s->cirrus_srcptr >= s->cirrus_srcptr_end);
778 }
779 }
780 }
782 /***************************************
783 *
784 * bitblt wrapper
785 *
786 ***************************************/
788 static void cirrus_bitblt_reset(CirrusVGAState * s)
789 {
790 s->gr[0x31] &=
791 ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED);
792 s->cirrus_srcptr = &s->cirrus_bltbuf[0];
793 s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
794 s->cirrus_srccounter = 0;
795 cirrus_update_memory_access(s);
796 }
798 static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
799 {
800 int w;
802 s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
803 s->cirrus_srcptr = &s->cirrus_bltbuf[0];
804 s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
806 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
807 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
808 s->cirrus_blt_srcpitch = 8;
809 } else {
810 /* XXX: check for 24 bpp */
811 s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth;
812 }
813 s->cirrus_srccounter = s->cirrus_blt_srcpitch;
814 } else {
815 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
816 w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth;
817 if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)
818 s->cirrus_blt_srcpitch = ((w + 31) >> 5);
819 else
820 s->cirrus_blt_srcpitch = ((w + 7) >> 3);
821 } else {
822 /* always align input size to 32 bits */
823 s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3;
824 }
825 s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
826 }
827 s->cirrus_srcptr = s->cirrus_bltbuf;
828 s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
829 cirrus_update_memory_access(s);
830 return 1;
831 }
833 static int cirrus_bitblt_videotocpu(CirrusVGAState * s)
834 {
835 /* XXX */
836 #ifdef DEBUG_BITBLT
837 printf("cirrus: bitblt (video to cpu) is not implemented yet\n");
838 #endif
839 return 0;
840 }
842 static int cirrus_bitblt_videotovideo(CirrusVGAState * s)
843 {
844 int ret;
846 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
847 ret = cirrus_bitblt_videotovideo_patterncopy(s);
848 } else {
849 ret = cirrus_bitblt_videotovideo_copy(s);
850 }
851 if (ret)
852 cirrus_bitblt_reset(s);
853 return ret;
854 }
856 static void cirrus_bitblt_start(CirrusVGAState * s)
857 {
858 uint8_t blt_rop;
860 s->gr[0x31] |= CIRRUS_BLT_BUSY;
862 s->cirrus_blt_width = (s->gr[0x20] | (s->gr[0x21] << 8)) + 1;
863 s->cirrus_blt_height = (s->gr[0x22] | (s->gr[0x23] << 8)) + 1;
864 s->cirrus_blt_dstpitch = (s->gr[0x24] | (s->gr[0x25] << 8));
865 s->cirrus_blt_srcpitch = (s->gr[0x26] | (s->gr[0x27] << 8));
866 s->cirrus_blt_dstaddr =
867 (s->gr[0x28] | (s->gr[0x29] << 8) | (s->gr[0x2a] << 16));
868 s->cirrus_blt_srcaddr =
869 (s->gr[0x2c] | (s->gr[0x2d] << 8) | (s->gr[0x2e] << 16));
870 s->cirrus_blt_mode = s->gr[0x30];
871 s->cirrus_blt_modeext = s->gr[0x33];
872 blt_rop = s->gr[0x32];
874 #ifdef DEBUG_BITBLT
875 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",
876 blt_rop,
877 s->cirrus_blt_mode,
878 s->cirrus_blt_modeext,
879 s->cirrus_blt_width,
880 s->cirrus_blt_height,
881 s->cirrus_blt_dstpitch,
882 s->cirrus_blt_srcpitch,
883 s->cirrus_blt_dstaddr,
884 s->cirrus_blt_srcaddr,
885 s->gr[0x2f]);
886 #endif
888 switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
889 case CIRRUS_BLTMODE_PIXELWIDTH8:
890 s->cirrus_blt_pixelwidth = 1;
891 break;
892 case CIRRUS_BLTMODE_PIXELWIDTH16:
893 s->cirrus_blt_pixelwidth = 2;
894 break;
895 case CIRRUS_BLTMODE_PIXELWIDTH24:
896 s->cirrus_blt_pixelwidth = 3;
897 break;
898 case CIRRUS_BLTMODE_PIXELWIDTH32:
899 s->cirrus_blt_pixelwidth = 4;
900 break;
901 default:
902 #ifdef DEBUG_BITBLT
903 printf("cirrus: bitblt - pixel width is unknown\n");
904 #endif
905 goto bitblt_ignore;
906 }
907 s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK;
909 if ((s->
910 cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC |
911 CIRRUS_BLTMODE_MEMSYSDEST))
912 == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) {
913 #ifdef DEBUG_BITBLT
914 printf("cirrus: bitblt - memory-to-memory copy is requested\n");
915 #endif
916 goto bitblt_ignore;
917 }
919 if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) &&
920 (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST |
921 CIRRUS_BLTMODE_TRANSPARENTCOMP |
922 CIRRUS_BLTMODE_PATTERNCOPY |
923 CIRRUS_BLTMODE_COLOREXPAND)) ==
924 (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) {
925 cirrus_bitblt_fgcol(s);
926 cirrus_bitblt_solidfill(s, blt_rop);
927 } else {
928 if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND |
929 CIRRUS_BLTMODE_PATTERNCOPY)) ==
930 CIRRUS_BLTMODE_COLOREXPAND) {
932 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
933 if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
934 cirrus_bitblt_bgcol(s);
935 else
936 cirrus_bitblt_fgcol(s);
937 s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
938 } else {
939 cirrus_bitblt_fgcol(s);
940 cirrus_bitblt_bgcol(s);
941 s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
942 }
943 } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
944 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
945 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
946 if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
947 cirrus_bitblt_bgcol(s);
948 else
949 cirrus_bitblt_fgcol(s);
950 s->cirrus_rop = cirrus_colorexpand_pattern_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
951 } else {
952 cirrus_bitblt_fgcol(s);
953 cirrus_bitblt_bgcol(s);
954 s->cirrus_rop = cirrus_colorexpand_pattern[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
955 }
956 } else {
957 s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
958 }
959 } else {
960 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
961 s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
962 s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
963 s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]];
964 } else {
965 s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]];
966 }
967 }
969 // setup bitblt engine.
970 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) {
971 if (!cirrus_bitblt_cputovideo(s))
972 goto bitblt_ignore;
973 } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) {
974 if (!cirrus_bitblt_videotocpu(s))
975 goto bitblt_ignore;
976 } else {
977 if (!cirrus_bitblt_videotovideo(s))
978 goto bitblt_ignore;
979 }
980 }
981 return;
982 bitblt_ignore:;
983 cirrus_bitblt_reset(s);
984 }
986 static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value)
987 {
988 unsigned old_value;
990 old_value = s->gr[0x31];
991 s->gr[0x31] = reg_value;
993 if (((old_value & CIRRUS_BLT_RESET) != 0) &&
994 ((reg_value & CIRRUS_BLT_RESET) == 0)) {
995 cirrus_bitblt_reset(s);
996 } else if (((old_value & CIRRUS_BLT_START) == 0) &&
997 ((reg_value & CIRRUS_BLT_START) != 0)) {
998 cirrus_bitblt_start(s);
999 }
1003 /***************************************
1005 * basic parameters
1007 ***************************************/
1009 static void cirrus_get_offsets(VGAState *s1,
1010 uint32_t *pline_offset,
1011 uint32_t *pstart_addr,
1012 uint32_t *pline_compare)
1014 CirrusVGAState * s = (CirrusVGAState *)s1;
1015 uint32_t start_addr, line_offset, line_compare;
1017 line_offset = s->cr[0x13]
1018 | ((s->cr[0x1b] & 0x10) << 4);
1019 line_offset <<= 3;
1020 *pline_offset = line_offset;
1022 start_addr = (s->cr[0x0c] << 8)
1023 | s->cr[0x0d]
1024 | ((s->cr[0x1b] & 0x01) << 16)
1025 | ((s->cr[0x1b] & 0x0c) << 15)
1026 | ((s->cr[0x1d] & 0x80) << 12);
1027 *pstart_addr = start_addr;
1029 line_compare = s->cr[0x18] |
1030 ((s->cr[0x07] & 0x10) << 4) |
1031 ((s->cr[0x09] & 0x40) << 3);
1032 *pline_compare = line_compare;
1035 static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
1037 uint32_t ret = 16;
1039 switch (s->cirrus_hidden_dac_data & 0xf) {
1040 case 0:
1041 ret = 15;
1042 break; /* Sierra HiColor */
1043 case 1:
1044 ret = 16;
1045 break; /* XGA HiColor */
1046 default:
1047 #ifdef DEBUG_CIRRUS
1048 printf("cirrus: invalid DAC value %x in 16bpp\n",
1049 (s->cirrus_hidden_dac_data & 0xf));
1050 #endif
1051 ret = 15; /* XXX */
1052 break;
1054 return ret;
1057 static int cirrus_get_bpp(VGAState *s1)
1059 CirrusVGAState * s = (CirrusVGAState *)s1;
1060 uint32_t ret = 8;
1062 if ((s->sr[0x07] & 0x01) != 0) {
1063 /* Cirrus SVGA */
1064 switch (s->sr[0x07] & CIRRUS_SR7_BPP_MASK) {
1065 case CIRRUS_SR7_BPP_8:
1066 ret = 8;
1067 break;
1068 case CIRRUS_SR7_BPP_16_DOUBLEVCLK:
1069 ret = cirrus_get_bpp16_depth(s);
1070 break;
1071 case CIRRUS_SR7_BPP_24:
1072 ret = 24;
1073 break;
1074 case CIRRUS_SR7_BPP_16:
1075 ret = cirrus_get_bpp16_depth(s);
1076 break;
1077 case CIRRUS_SR7_BPP_32:
1078 ret = 32;
1079 break;
1080 default:
1081 #ifdef DEBUG_CIRRUS
1082 printf("cirrus: unknown bpp - sr7=%x\n", s->sr[0x7]);
1083 #endif
1084 ret = 8;
1085 break;
1087 } else {
1088 /* VGA */
1089 ret = 0;
1092 return ret;
1095 static void cirrus_get_resolution(VGAState *s, int *pwidth, int *pheight)
1097 int width, height;
1099 width = (s->cr[0x01] + 1) * 8;
1100 height = s->cr[0x12] |
1101 ((s->cr[0x07] & 0x02) << 7) |
1102 ((s->cr[0x07] & 0x40) << 3);
1103 height = (height + 1);
1104 /* interlace support */
1105 if (s->cr[0x1a] & 0x01)
1106 height = height * 2;
1107 *pwidth = width;
1108 *pheight = height;
1111 /***************************************
1113 * bank memory
1115 ***************************************/
1117 static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
1119 unsigned offset;
1120 unsigned limit;
1122 if ((s->gr[0x0b] & 0x01) != 0) /* dual bank */
1123 offset = s->gr[0x09 + bank_index];
1124 else /* single bank */
1125 offset = s->gr[0x09];
1127 if ((s->gr[0x0b] & 0x20) != 0)
1128 offset <<= 14;
1129 else
1130 offset <<= 12;
1132 if (s->real_vram_size <= offset)
1133 limit = 0;
1134 else
1135 limit = s->real_vram_size - offset;
1137 if (((s->gr[0x0b] & 0x01) == 0) && (bank_index != 0)) {
1138 if (limit > 0x8000) {
1139 offset += 0x8000;
1140 limit -= 0x8000;
1141 } else {
1142 limit = 0;
1146 if (limit > 0) {
1147 s->cirrus_bank_base[bank_index] = offset;
1148 s->cirrus_bank_limit[bank_index] = limit;
1149 } else {
1150 s->cirrus_bank_base[bank_index] = 0;
1151 s->cirrus_bank_limit[bank_index] = 0;
1155 /***************************************
1157 * I/O access between 0x3c4-0x3c5
1159 ***************************************/
1161 static int
1162 cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
1164 switch (reg_index) {
1165 case 0x00: // Standard VGA
1166 case 0x01: // Standard VGA
1167 case 0x02: // Standard VGA
1168 case 0x03: // Standard VGA
1169 case 0x04: // Standard VGA
1170 return CIRRUS_HOOK_NOT_HANDLED;
1171 case 0x06: // Unlock Cirrus extensions
1172 *reg_value = s->sr[reg_index];
1173 break;
1174 case 0x10:
1175 case 0x30:
1176 case 0x50:
1177 case 0x70: // Graphics Cursor X
1178 case 0x90:
1179 case 0xb0:
1180 case 0xd0:
1181 case 0xf0: // Graphics Cursor X
1182 *reg_value = s->sr[0x10];
1183 break;
1184 case 0x11:
1185 case 0x31:
1186 case 0x51:
1187 case 0x71: // Graphics Cursor Y
1188 case 0x91:
1189 case 0xb1:
1190 case 0xd1:
1191 case 0xf1: // Graphics Cursor Y
1192 *reg_value = s->sr[0x11];
1193 break;
1194 case 0x05: // ???
1195 case 0x07: // Extended Sequencer Mode
1196 case 0x08: // EEPROM Control
1197 case 0x09: // Scratch Register 0
1198 case 0x0a: // Scratch Register 1
1199 case 0x0b: // VCLK 0
1200 case 0x0c: // VCLK 1
1201 case 0x0d: // VCLK 2
1202 case 0x0e: // VCLK 3
1203 case 0x0f: // DRAM Control
1204 case 0x12: // Graphics Cursor Attribute
1205 case 0x13: // Graphics Cursor Pattern Address
1206 case 0x14: // Scratch Register 2
1207 case 0x15: // Scratch Register 3
1208 case 0x16: // Performance Tuning Register
1209 case 0x17: // Configuration Readback and Extended Control
1210 case 0x18: // Signature Generator Control
1211 case 0x19: // Signal Generator Result
1212 case 0x1a: // Signal Generator Result
1213 case 0x1b: // VCLK 0 Denominator & Post
1214 case 0x1c: // VCLK 1 Denominator & Post
1215 case 0x1d: // VCLK 2 Denominator & Post
1216 case 0x1e: // VCLK 3 Denominator & Post
1217 case 0x1f: // BIOS Write Enable and MCLK select
1218 #ifdef DEBUG_CIRRUS
1219 printf("cirrus: handled inport sr_index %02x\n", reg_index);
1220 #endif
1221 *reg_value = s->sr[reg_index];
1222 break;
1223 default:
1224 #ifdef DEBUG_CIRRUS
1225 printf("cirrus: inport sr_index %02x\n", reg_index);
1226 #endif
1227 *reg_value = 0xff;
1228 break;
1231 return CIRRUS_HOOK_HANDLED;
1234 static int
1235 cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1237 switch (reg_index) {
1238 case 0x00: // Standard VGA
1239 case 0x01: // Standard VGA
1240 case 0x02: // Standard VGA
1241 case 0x03: // Standard VGA
1242 case 0x04: // Standard VGA
1243 return CIRRUS_HOOK_NOT_HANDLED;
1244 case 0x06: // Unlock Cirrus extensions
1245 reg_value &= 0x17;
1246 if (reg_value == 0x12) {
1247 s->sr[reg_index] = 0x12;
1248 } else {
1249 s->sr[reg_index] = 0x0f;
1251 break;
1252 case 0x10:
1253 case 0x30:
1254 case 0x50:
1255 case 0x70: // Graphics Cursor X
1256 case 0x90:
1257 case 0xb0:
1258 case 0xd0:
1259 case 0xf0: // Graphics Cursor X
1260 s->sr[0x10] = reg_value;
1261 s->hw_cursor_x = (reg_value << 3) | (reg_index >> 5);
1262 break;
1263 case 0x11:
1264 case 0x31:
1265 case 0x51:
1266 case 0x71: // Graphics Cursor Y
1267 case 0x91:
1268 case 0xb1:
1269 case 0xd1:
1270 case 0xf1: // Graphics Cursor Y
1271 s->sr[0x11] = reg_value;
1272 s->hw_cursor_y = (reg_value << 3) | (reg_index >> 5);
1273 break;
1274 case 0x07: // Extended Sequencer Mode
1275 case 0x08: // EEPROM Control
1276 case 0x09: // Scratch Register 0
1277 case 0x0a: // Scratch Register 1
1278 case 0x0b: // VCLK 0
1279 case 0x0c: // VCLK 1
1280 case 0x0d: // VCLK 2
1281 case 0x0e: // VCLK 3
1282 case 0x0f: // DRAM Control
1283 case 0x12: // Graphics Cursor Attribute
1284 case 0x13: // Graphics Cursor Pattern Address
1285 case 0x14: // Scratch Register 2
1286 case 0x15: // Scratch Register 3
1287 case 0x16: // Performance Tuning Register
1288 case 0x18: // Signature Generator Control
1289 case 0x19: // Signature Generator Result
1290 case 0x1a: // Signature Generator Result
1291 case 0x1b: // VCLK 0 Denominator & Post
1292 case 0x1c: // VCLK 1 Denominator & Post
1293 case 0x1d: // VCLK 2 Denominator & Post
1294 case 0x1e: // VCLK 3 Denominator & Post
1295 case 0x1f: // BIOS Write Enable and MCLK select
1296 s->sr[reg_index] = reg_value;
1297 #ifdef DEBUG_CIRRUS
1298 printf("cirrus: handled outport sr_index %02x, sr_value %02x\n",
1299 reg_index, reg_value);
1300 #endif
1301 break;
1302 case 0x17: // Configuration Readback and Extended Control
1303 s->sr[reg_index] = (s->sr[reg_index] & 0x38) | (reg_value & 0xc7);
1304 cirrus_update_memory_access(s);
1305 break;
1306 default:
1307 #ifdef DEBUG_CIRRUS
1308 printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index,
1309 reg_value);
1310 #endif
1311 break;
1314 return CIRRUS_HOOK_HANDLED;
1317 /***************************************
1319 * I/O access at 0x3c6
1321 ***************************************/
1323 static void cirrus_read_hidden_dac(CirrusVGAState * s, int *reg_value)
1325 *reg_value = 0xff;
1326 if (++s->cirrus_hidden_dac_lockindex == 5) {
1327 *reg_value = s->cirrus_hidden_dac_data;
1328 s->cirrus_hidden_dac_lockindex = 0;
1332 static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value)
1334 if (s->cirrus_hidden_dac_lockindex == 4) {
1335 s->cirrus_hidden_dac_data = reg_value;
1336 #if defined(DEBUG_CIRRUS)
1337 printf("cirrus: outport hidden DAC, value %02x\n", reg_value);
1338 #endif
1340 s->cirrus_hidden_dac_lockindex = 0;
1343 /***************************************
1345 * I/O access at 0x3c9
1347 ***************************************/
1349 static int cirrus_hook_read_palette(CirrusVGAState * s, int *reg_value)
1351 if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL))
1352 return CIRRUS_HOOK_NOT_HANDLED;
1353 *reg_value =
1354 s->cirrus_hidden_palette[(s->dac_read_index & 0x0f) * 3 +
1355 s->dac_sub_index];
1356 if (++s->dac_sub_index == 3) {
1357 s->dac_sub_index = 0;
1358 s->dac_read_index++;
1360 return CIRRUS_HOOK_HANDLED;
1363 static int cirrus_hook_write_palette(CirrusVGAState * s, int reg_value)
1365 if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL))
1366 return CIRRUS_HOOK_NOT_HANDLED;
1367 s->dac_cache[s->dac_sub_index] = reg_value;
1368 if (++s->dac_sub_index == 3) {
1369 memcpy(&s->cirrus_hidden_palette[(s->dac_write_index & 0x0f) * 3],
1370 s->dac_cache, 3);
1371 /* XXX update cursor */
1372 s->dac_sub_index = 0;
1373 s->dac_write_index++;
1375 return CIRRUS_HOOK_HANDLED;
1378 /***************************************
1380 * I/O access between 0x3ce-0x3cf
1382 ***************************************/
1384 static int
1385 cirrus_hook_read_gr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
1387 switch (reg_index) {
1388 case 0x00: // Standard VGA, BGCOLOR 0x000000ff
1389 *reg_value = s->cirrus_shadow_gr0;
1390 return CIRRUS_HOOK_HANDLED;
1391 case 0x01: // Standard VGA, FGCOLOR 0x000000ff
1392 *reg_value = s->cirrus_shadow_gr1;
1393 return CIRRUS_HOOK_HANDLED;
1394 case 0x02: // Standard VGA
1395 case 0x03: // Standard VGA
1396 case 0x04: // Standard VGA
1397 case 0x06: // Standard VGA
1398 case 0x07: // Standard VGA
1399 case 0x08: // Standard VGA
1400 return CIRRUS_HOOK_NOT_HANDLED;
1401 case 0x05: // Standard VGA, Cirrus extended mode
1402 default:
1403 break;
1406 if (reg_index < 0x3a) {
1407 *reg_value = s->gr[reg_index];
1408 } else {
1409 #ifdef DEBUG_CIRRUS
1410 printf("cirrus: inport gr_index %02x\n", reg_index);
1411 #endif
1412 *reg_value = 0xff;
1415 return CIRRUS_HOOK_HANDLED;
1418 static int
1419 cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1421 #if defined(DEBUG_BITBLT) && 0
1422 printf("gr%02x: %02x\n", reg_index, reg_value);
1423 #endif
1424 switch (reg_index) {
1425 case 0x00: // Standard VGA, BGCOLOR 0x000000ff
1426 s->cirrus_shadow_gr0 = reg_value;
1427 return CIRRUS_HOOK_NOT_HANDLED;
1428 case 0x01: // Standard VGA, FGCOLOR 0x000000ff
1429 s->cirrus_shadow_gr1 = reg_value;
1430 return CIRRUS_HOOK_NOT_HANDLED;
1431 case 0x02: // Standard VGA
1432 case 0x03: // Standard VGA
1433 case 0x04: // Standard VGA
1434 case 0x06: // Standard VGA
1435 case 0x07: // Standard VGA
1436 case 0x08: // Standard VGA
1437 return CIRRUS_HOOK_NOT_HANDLED;
1438 case 0x05: // Standard VGA, Cirrus extended mode
1439 s->gr[reg_index] = reg_value & 0x7f;
1440 cirrus_update_memory_access(s);
1441 break;
1442 case 0x09: // bank offset #0
1443 case 0x0A: // bank offset #1
1444 s->gr[reg_index] = reg_value;
1445 cirrus_update_bank_ptr(s, 0);
1446 cirrus_update_bank_ptr(s, 1);
1447 break;
1448 case 0x0B:
1449 s->gr[reg_index] = reg_value;
1450 cirrus_update_bank_ptr(s, 0);
1451 cirrus_update_bank_ptr(s, 1);
1452 cirrus_update_memory_access(s);
1453 break;
1454 case 0x10: // BGCOLOR 0x0000ff00
1455 case 0x11: // FGCOLOR 0x0000ff00
1456 case 0x12: // BGCOLOR 0x00ff0000
1457 case 0x13: // FGCOLOR 0x00ff0000
1458 case 0x14: // BGCOLOR 0xff000000
1459 case 0x15: // FGCOLOR 0xff000000
1460 case 0x20: // BLT WIDTH 0x0000ff
1461 case 0x22: // BLT HEIGHT 0x0000ff
1462 case 0x24: // BLT DEST PITCH 0x0000ff
1463 case 0x26: // BLT SRC PITCH 0x0000ff
1464 case 0x28: // BLT DEST ADDR 0x0000ff
1465 case 0x29: // BLT DEST ADDR 0x00ff00
1466 case 0x2c: // BLT SRC ADDR 0x0000ff
1467 case 0x2d: // BLT SRC ADDR 0x00ff00
1468 case 0x2f: // BLT WRITEMASK
1469 case 0x30: // BLT MODE
1470 case 0x32: // RASTER OP
1471 case 0x33: // BLT MODEEXT
1472 case 0x34: // BLT TRANSPARENT COLOR 0x00ff
1473 case 0x35: // BLT TRANSPARENT COLOR 0xff00
1474 case 0x38: // BLT TRANSPARENT COLOR MASK 0x00ff
1475 case 0x39: // BLT TRANSPARENT COLOR MASK 0xff00
1476 s->gr[reg_index] = reg_value;
1477 break;
1478 case 0x21: // BLT WIDTH 0x001f00
1479 case 0x23: // BLT HEIGHT 0x001f00
1480 case 0x25: // BLT DEST PITCH 0x001f00
1481 case 0x27: // BLT SRC PITCH 0x001f00
1482 s->gr[reg_index] = reg_value & 0x1f;
1483 break;
1484 case 0x2a: // BLT DEST ADDR 0x3f0000
1485 s->gr[reg_index] = reg_value & 0x3f;
1486 /* if auto start mode, starts bit blt now */
1487 if (s->gr[0x31] & CIRRUS_BLT_AUTOSTART) {
1488 cirrus_bitblt_start(s);
1490 break;
1491 case 0x2e: // BLT SRC ADDR 0x3f0000
1492 s->gr[reg_index] = reg_value & 0x3f;
1493 break;
1494 case 0x31: // BLT STATUS/START
1495 cirrus_write_bitblt(s, reg_value);
1496 break;
1498 // Extension to allow BIOS to clear 16K VRAM bank in one operation
1499 case 0xFE:
1500 s->gr[reg_index] = reg_value; // Lower byte of value to be written
1501 break;
1502 case 0xFF: {
1503 target_phys_addr_t addr;
1504 for (addr = 0xa0000; addr < 0xa4000; addr += 2)
1505 cirrus_vga_mem_writew(s, addr, (reg_value << 8) | s->gr[0xFE]);
1507 break;
1508 default:
1509 #ifdef DEBUG_CIRRUS
1510 printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index,
1511 reg_value);
1512 #endif
1513 break;
1516 return CIRRUS_HOOK_HANDLED;
1519 /***************************************
1521 * I/O access between 0x3d4-0x3d5
1523 ***************************************/
1525 static int
1526 cirrus_hook_read_cr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
1528 switch (reg_index) {
1529 case 0x00: // Standard VGA
1530 case 0x01: // Standard VGA
1531 case 0x02: // Standard VGA
1532 case 0x03: // Standard VGA
1533 case 0x04: // Standard VGA
1534 case 0x05: // Standard VGA
1535 case 0x06: // Standard VGA
1536 case 0x07: // Standard VGA
1537 case 0x08: // Standard VGA
1538 case 0x09: // Standard VGA
1539 case 0x0a: // Standard VGA
1540 case 0x0b: // Standard VGA
1541 case 0x0c: // Standard VGA
1542 case 0x0d: // Standard VGA
1543 case 0x0e: // Standard VGA
1544 case 0x0f: // Standard VGA
1545 case 0x10: // Standard VGA
1546 case 0x11: // Standard VGA
1547 case 0x12: // Standard VGA
1548 case 0x13: // Standard VGA
1549 case 0x14: // Standard VGA
1550 case 0x15: // Standard VGA
1551 case 0x16: // Standard VGA
1552 case 0x17: // Standard VGA
1553 case 0x18: // Standard VGA
1554 return CIRRUS_HOOK_NOT_HANDLED;
1555 case 0x19: // Interlace End
1556 case 0x1a: // Miscellaneous Control
1557 case 0x1b: // Extended Display Control
1558 case 0x1c: // Sync Adjust and Genlock
1559 case 0x1d: // Overlay Extended Control
1560 case 0x22: // Graphics Data Latches Readback (R)
1561 case 0x24: // Attribute Controller Toggle Readback (R)
1562 case 0x25: // Part Status
1563 case 0x27: // Part ID (R)
1564 *reg_value = s->cr[reg_index];
1565 break;
1566 case 0x26: // Attribute Controller Index Readback (R)
1567 *reg_value = s->ar_index & 0x3f;
1568 break;
1569 default:
1570 #ifdef DEBUG_CIRRUS
1571 printf("cirrus: inport cr_index %02x\n", reg_index);
1572 *reg_value = 0xff;
1573 #endif
1574 break;
1577 return CIRRUS_HOOK_HANDLED;
1580 static int
1581 cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1583 switch (reg_index) {
1584 case 0x00: // Standard VGA
1585 case 0x01: // Standard VGA
1586 case 0x02: // Standard VGA
1587 case 0x03: // Standard VGA
1588 case 0x04: // Standard VGA
1589 case 0x05: // Standard VGA
1590 case 0x06: // Standard VGA
1591 case 0x07: // Standard VGA
1592 case 0x08: // Standard VGA
1593 case 0x09: // Standard VGA
1594 case 0x0a: // Standard VGA
1595 case 0x0b: // Standard VGA
1596 case 0x0c: // Standard VGA
1597 case 0x0d: // Standard VGA
1598 case 0x0e: // Standard VGA
1599 case 0x0f: // Standard VGA
1600 case 0x10: // Standard VGA
1601 case 0x11: // Standard VGA
1602 case 0x12: // Standard VGA
1603 case 0x13: // Standard VGA
1604 case 0x14: // Standard VGA
1605 case 0x15: // Standard VGA
1606 case 0x16: // Standard VGA
1607 case 0x17: // Standard VGA
1608 case 0x18: // Standard VGA
1609 return CIRRUS_HOOK_NOT_HANDLED;
1610 case 0x19: // Interlace End
1611 case 0x1a: // Miscellaneous Control
1612 case 0x1b: // Extended Display Control
1613 case 0x1c: // Sync Adjust and Genlock
1614 case 0x1d: // Overlay Extended Control
1615 s->cr[reg_index] = reg_value;
1616 #ifdef DEBUG_CIRRUS
1617 printf("cirrus: handled outport cr_index %02x, cr_value %02x\n",
1618 reg_index, reg_value);
1619 #endif
1620 break;
1621 case 0x22: // Graphics Data Latches Readback (R)
1622 case 0x24: // Attribute Controller Toggle Readback (R)
1623 case 0x26: // Attribute Controller Index Readback (R)
1624 case 0x27: // Part ID (R)
1625 break;
1626 case 0x25: // Part Status
1627 default:
1628 #ifdef DEBUG_CIRRUS
1629 printf("cirrus: outport cr_index %02x, cr_value %02x\n", reg_index,
1630 reg_value);
1631 #endif
1632 break;
1635 return CIRRUS_HOOK_HANDLED;
1638 /***************************************
1640 * memory-mapped I/O (bitblt)
1642 ***************************************/
1644 static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
1646 int value = 0xff;
1648 switch (address) {
1649 case (CIRRUS_MMIO_BLTBGCOLOR + 0):
1650 cirrus_hook_read_gr(s, 0x00, &value);
1651 break;
1652 case (CIRRUS_MMIO_BLTBGCOLOR + 1):
1653 cirrus_hook_read_gr(s, 0x10, &value);
1654 break;
1655 case (CIRRUS_MMIO_BLTBGCOLOR + 2):
1656 cirrus_hook_read_gr(s, 0x12, &value);
1657 break;
1658 case (CIRRUS_MMIO_BLTBGCOLOR + 3):
1659 cirrus_hook_read_gr(s, 0x14, &value);
1660 break;
1661 case (CIRRUS_MMIO_BLTFGCOLOR + 0):
1662 cirrus_hook_read_gr(s, 0x01, &value);
1663 break;
1664 case (CIRRUS_MMIO_BLTFGCOLOR + 1):
1665 cirrus_hook_read_gr(s, 0x11, &value);
1666 break;
1667 case (CIRRUS_MMIO_BLTFGCOLOR + 2):
1668 cirrus_hook_read_gr(s, 0x13, &value);
1669 break;
1670 case (CIRRUS_MMIO_BLTFGCOLOR + 3):
1671 cirrus_hook_read_gr(s, 0x15, &value);
1672 break;
1673 case (CIRRUS_MMIO_BLTWIDTH + 0):
1674 cirrus_hook_read_gr(s, 0x20, &value);
1675 break;
1676 case (CIRRUS_MMIO_BLTWIDTH + 1):
1677 cirrus_hook_read_gr(s, 0x21, &value);
1678 break;
1679 case (CIRRUS_MMIO_BLTHEIGHT + 0):
1680 cirrus_hook_read_gr(s, 0x22, &value);
1681 break;
1682 case (CIRRUS_MMIO_BLTHEIGHT + 1):
1683 cirrus_hook_read_gr(s, 0x23, &value);
1684 break;
1685 case (CIRRUS_MMIO_BLTDESTPITCH + 0):
1686 cirrus_hook_read_gr(s, 0x24, &value);
1687 break;
1688 case (CIRRUS_MMIO_BLTDESTPITCH + 1):
1689 cirrus_hook_read_gr(s, 0x25, &value);
1690 break;
1691 case (CIRRUS_MMIO_BLTSRCPITCH + 0):
1692 cirrus_hook_read_gr(s, 0x26, &value);
1693 break;
1694 case (CIRRUS_MMIO_BLTSRCPITCH + 1):
1695 cirrus_hook_read_gr(s, 0x27, &value);
1696 break;
1697 case (CIRRUS_MMIO_BLTDESTADDR + 0):
1698 cirrus_hook_read_gr(s, 0x28, &value);
1699 break;
1700 case (CIRRUS_MMIO_BLTDESTADDR + 1):
1701 cirrus_hook_read_gr(s, 0x29, &value);
1702 break;
1703 case (CIRRUS_MMIO_BLTDESTADDR + 2):
1704 cirrus_hook_read_gr(s, 0x2a, &value);
1705 break;
1706 case (CIRRUS_MMIO_BLTSRCADDR + 0):
1707 cirrus_hook_read_gr(s, 0x2c, &value);
1708 break;
1709 case (CIRRUS_MMIO_BLTSRCADDR + 1):
1710 cirrus_hook_read_gr(s, 0x2d, &value);
1711 break;
1712 case (CIRRUS_MMIO_BLTSRCADDR + 2):
1713 cirrus_hook_read_gr(s, 0x2e, &value);
1714 break;
1715 case CIRRUS_MMIO_BLTWRITEMASK:
1716 cirrus_hook_read_gr(s, 0x2f, &value);
1717 break;
1718 case CIRRUS_MMIO_BLTMODE:
1719 cirrus_hook_read_gr(s, 0x30, &value);
1720 break;
1721 case CIRRUS_MMIO_BLTROP:
1722 cirrus_hook_read_gr(s, 0x32, &value);
1723 break;
1724 case CIRRUS_MMIO_BLTMODEEXT:
1725 cirrus_hook_read_gr(s, 0x33, &value);
1726 break;
1727 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
1728 cirrus_hook_read_gr(s, 0x34, &value);
1729 break;
1730 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
1731 cirrus_hook_read_gr(s, 0x35, &value);
1732 break;
1733 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
1734 cirrus_hook_read_gr(s, 0x38, &value);
1735 break;
1736 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
1737 cirrus_hook_read_gr(s, 0x39, &value);
1738 break;
1739 case CIRRUS_MMIO_BLTSTATUS:
1740 cirrus_hook_read_gr(s, 0x31, &value);
1741 break;
1742 default:
1743 #ifdef DEBUG_CIRRUS
1744 printf("cirrus: mmio read - address 0x%04x\n", address);
1745 #endif
1746 break;
1749 return (uint8_t) value;
1752 static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
1753 uint8_t value)
1755 switch (address) {
1756 case (CIRRUS_MMIO_BLTBGCOLOR + 0):
1757 cirrus_hook_write_gr(s, 0x00, value);
1758 break;
1759 case (CIRRUS_MMIO_BLTBGCOLOR + 1):
1760 cirrus_hook_write_gr(s, 0x10, value);
1761 break;
1762 case (CIRRUS_MMIO_BLTBGCOLOR + 2):
1763 cirrus_hook_write_gr(s, 0x12, value);
1764 break;
1765 case (CIRRUS_MMIO_BLTBGCOLOR + 3):
1766 cirrus_hook_write_gr(s, 0x14, value);
1767 break;
1768 case (CIRRUS_MMIO_BLTFGCOLOR + 0):
1769 cirrus_hook_write_gr(s, 0x01, value);
1770 break;
1771 case (CIRRUS_MMIO_BLTFGCOLOR + 1):
1772 cirrus_hook_write_gr(s, 0x11, value);
1773 break;
1774 case (CIRRUS_MMIO_BLTFGCOLOR + 2):
1775 cirrus_hook_write_gr(s, 0x13, value);
1776 break;
1777 case (CIRRUS_MMIO_BLTFGCOLOR + 3):
1778 cirrus_hook_write_gr(s, 0x15, value);
1779 break;
1780 case (CIRRUS_MMIO_BLTWIDTH + 0):
1781 cirrus_hook_write_gr(s, 0x20, value);
1782 break;
1783 case (CIRRUS_MMIO_BLTWIDTH + 1):
1784 cirrus_hook_write_gr(s, 0x21, value);
1785 break;
1786 case (CIRRUS_MMIO_BLTHEIGHT + 0):
1787 cirrus_hook_write_gr(s, 0x22, value);
1788 break;
1789 case (CIRRUS_MMIO_BLTHEIGHT + 1):
1790 cirrus_hook_write_gr(s, 0x23, value);
1791 break;
1792 case (CIRRUS_MMIO_BLTDESTPITCH + 0):
1793 cirrus_hook_write_gr(s, 0x24, value);
1794 break;
1795 case (CIRRUS_MMIO_BLTDESTPITCH + 1):
1796 cirrus_hook_write_gr(s, 0x25, value);
1797 break;
1798 case (CIRRUS_MMIO_BLTSRCPITCH + 0):
1799 cirrus_hook_write_gr(s, 0x26, value);
1800 break;
1801 case (CIRRUS_MMIO_BLTSRCPITCH + 1):
1802 cirrus_hook_write_gr(s, 0x27, value);
1803 break;
1804 case (CIRRUS_MMIO_BLTDESTADDR + 0):
1805 cirrus_hook_write_gr(s, 0x28, value);
1806 break;
1807 case (CIRRUS_MMIO_BLTDESTADDR + 1):
1808 cirrus_hook_write_gr(s, 0x29, value);
1809 break;
1810 case (CIRRUS_MMIO_BLTDESTADDR + 2):
1811 cirrus_hook_write_gr(s, 0x2a, value);
1812 break;
1813 case (CIRRUS_MMIO_BLTDESTADDR + 3):
1814 /* ignored */
1815 break;
1816 case (CIRRUS_MMIO_BLTSRCADDR + 0):
1817 cirrus_hook_write_gr(s, 0x2c, value);
1818 break;
1819 case (CIRRUS_MMIO_BLTSRCADDR + 1):
1820 cirrus_hook_write_gr(s, 0x2d, value);
1821 break;
1822 case (CIRRUS_MMIO_BLTSRCADDR + 2):
1823 cirrus_hook_write_gr(s, 0x2e, value);
1824 break;
1825 case CIRRUS_MMIO_BLTWRITEMASK:
1826 cirrus_hook_write_gr(s, 0x2f, value);
1827 break;
1828 case CIRRUS_MMIO_BLTMODE:
1829 cirrus_hook_write_gr(s, 0x30, value);
1830 break;
1831 case CIRRUS_MMIO_BLTROP:
1832 cirrus_hook_write_gr(s, 0x32, value);
1833 break;
1834 case CIRRUS_MMIO_BLTMODEEXT:
1835 cirrus_hook_write_gr(s, 0x33, value);
1836 break;
1837 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
1838 cirrus_hook_write_gr(s, 0x34, value);
1839 break;
1840 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
1841 cirrus_hook_write_gr(s, 0x35, value);
1842 break;
1843 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
1844 cirrus_hook_write_gr(s, 0x38, value);
1845 break;
1846 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
1847 cirrus_hook_write_gr(s, 0x39, value);
1848 break;
1849 case CIRRUS_MMIO_BLTSTATUS:
1850 cirrus_hook_write_gr(s, 0x31, value);
1851 break;
1852 default:
1853 #ifdef DEBUG_CIRRUS
1854 printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n",
1855 address, value);
1856 #endif
1857 break;
1861 /***************************************
1863 * write mode 4/5
1865 * assume TARGET_PAGE_SIZE >= 16
1867 ***************************************/
1869 static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
1870 unsigned mode,
1871 unsigned offset,
1872 uint32_t mem_value)
1874 int x;
1875 unsigned val = mem_value;
1876 uint8_t *dst;
1878 dst = s->vram_ptr + offset;
1879 for (x = 0; x < 8; x++) {
1880 if (val & 0x80) {
1881 *dst = s->cirrus_shadow_gr1;
1882 } else if (mode == 5) {
1883 *dst = s->cirrus_shadow_gr0;
1885 val <<= 1;
1886 dst++;
1888 cpu_physical_memory_set_dirty(s->vram_offset + offset);
1889 cpu_physical_memory_set_dirty(s->vram_offset + offset + 7);
1892 static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
1893 unsigned mode,
1894 unsigned offset,
1895 uint32_t mem_value)
1897 int x;
1898 unsigned val = mem_value;
1899 uint8_t *dst;
1901 dst = s->vram_ptr + offset;
1902 for (x = 0; x < 8; x++) {
1903 if (val & 0x80) {
1904 *dst = s->cirrus_shadow_gr1;
1905 *(dst + 1) = s->gr[0x11];
1906 } else if (mode == 5) {
1907 *dst = s->cirrus_shadow_gr0;
1908 *(dst + 1) = s->gr[0x10];
1910 val <<= 1;
1911 dst += 2;
1913 cpu_physical_memory_set_dirty(s->vram_offset + offset);
1914 cpu_physical_memory_set_dirty(s->vram_offset + offset + 15);
1917 /***************************************
1919 * memory access between 0xa0000-0xbffff
1921 ***************************************/
1923 static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
1925 CirrusVGAState *s = opaque;
1926 unsigned bank_index;
1927 unsigned bank_offset;
1928 uint32_t val;
1930 if ((s->sr[0x07] & 0x01) == 0) {
1931 return vga_mem_readb(s, addr);
1934 addr &= 0x1ffff;
1936 if (addr < 0x10000) {
1937 /* XXX handle bitblt */
1938 /* video memory */
1939 bank_index = addr >> 15;
1940 bank_offset = addr & 0x7fff;
1941 if (bank_offset < s->cirrus_bank_limit[bank_index]) {
1942 bank_offset += s->cirrus_bank_base[bank_index];
1943 if ((s->gr[0x0B] & 0x14) == 0x14) {
1944 bank_offset <<= 4;
1945 } else if (s->gr[0x0B] & 0x02) {
1946 bank_offset <<= 3;
1948 bank_offset &= s->cirrus_addr_mask;
1949 val = *(s->vram_ptr + bank_offset);
1950 } else
1951 val = 0xff;
1952 } else if (addr >= 0x18000 && addr < 0x18100) {
1953 /* memory-mapped I/O */
1954 val = 0xff;
1955 if ((s->sr[0x17] & 0x44) == 0x04) {
1956 val = cirrus_mmio_blt_read(s, addr & 0xff);
1958 } else {
1959 val = 0xff;
1960 #ifdef DEBUG_CIRRUS
1961 printf("cirrus: mem_readb %06x\n", addr);
1962 #endif
1964 return val;
1967 static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr)
1969 uint32_t v;
1970 #ifdef TARGET_WORDS_BIGENDIAN
1971 v = cirrus_vga_mem_readb(opaque, addr) << 8;
1972 v |= cirrus_vga_mem_readb(opaque, addr + 1);
1973 #else
1974 v = cirrus_vga_mem_readb(opaque, addr);
1975 v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
1976 #endif
1977 return v;
1980 static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr)
1982 uint32_t v;
1983 #ifdef TARGET_WORDS_BIGENDIAN
1984 v = cirrus_vga_mem_readb(opaque, addr) << 24;
1985 v |= cirrus_vga_mem_readb(opaque, addr + 1) << 16;
1986 v |= cirrus_vga_mem_readb(opaque, addr + 2) << 8;
1987 v |= cirrus_vga_mem_readb(opaque, addr + 3);
1988 #else
1989 v = cirrus_vga_mem_readb(opaque, addr);
1990 v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
1991 v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16;
1992 v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24;
1993 #endif
1994 return v;
1997 static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
1998 uint32_t mem_value)
2000 CirrusVGAState *s = opaque;
2001 unsigned bank_index;
2002 unsigned bank_offset;
2003 unsigned mode;
2005 if ((s->sr[0x07] & 0x01) == 0) {
2006 vga_mem_writeb(s, addr, mem_value);
2007 return;
2010 addr &= 0x1ffff;
2012 if (addr < 0x10000) {
2013 if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
2014 /* bitblt */
2015 *s->cirrus_srcptr++ = (uint8_t) mem_value;
2016 if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
2017 cirrus_bitblt_cputovideo_next(s);
2019 } else {
2020 /* video memory */
2021 bank_index = addr >> 15;
2022 bank_offset = addr & 0x7fff;
2023 if (bank_offset < s->cirrus_bank_limit[bank_index]) {
2024 bank_offset += s->cirrus_bank_base[bank_index];
2025 if ((s->gr[0x0B] & 0x14) == 0x14) {
2026 bank_offset <<= 4;
2027 } else if (s->gr[0x0B] & 0x02) {
2028 bank_offset <<= 3;
2030 bank_offset &= s->cirrus_addr_mask;
2031 mode = s->gr[0x05] & 0x7;
2032 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
2033 *(s->vram_ptr + bank_offset) = mem_value;
2034 cpu_physical_memory_set_dirty(s->vram_offset +
2035 bank_offset);
2036 } else {
2037 if ((s->gr[0x0B] & 0x14) != 0x14) {
2038 cirrus_mem_writeb_mode4and5_8bpp(s, mode,
2039 bank_offset,
2040 mem_value);
2041 } else {
2042 cirrus_mem_writeb_mode4and5_16bpp(s, mode,
2043 bank_offset,
2044 mem_value);
2049 } else if (addr >= 0x18000 && addr < 0x18100) {
2050 /* memory-mapped I/O */
2051 if ((s->sr[0x17] & 0x44) == 0x04) {
2052 cirrus_mmio_blt_write(s, addr & 0xff, mem_value);
2054 } else {
2055 #ifdef DEBUG_CIRRUS
2056 printf("cirrus: mem_writeb %06x value %02x\n", addr, mem_value);
2057 #endif
2061 static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
2063 #ifdef TARGET_WORDS_BIGENDIAN
2064 cirrus_vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
2065 cirrus_vga_mem_writeb(opaque, addr + 1, val & 0xff);
2066 #else
2067 cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
2068 cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2069 #endif
2072 static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2074 #ifdef TARGET_WORDS_BIGENDIAN
2075 cirrus_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
2076 cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
2077 cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
2078 cirrus_vga_mem_writeb(opaque, addr + 3, val & 0xff);
2079 #else
2080 cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
2081 cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2082 cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
2083 cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
2084 #endif
2087 static CPUReadMemoryFunc *cirrus_vga_mem_read[3] = {
2088 cirrus_vga_mem_readb,
2089 cirrus_vga_mem_readw,
2090 cirrus_vga_mem_readl,
2091 };
2093 static CPUWriteMemoryFunc *cirrus_vga_mem_write[3] = {
2094 cirrus_vga_mem_writeb,
2095 cirrus_vga_mem_writew,
2096 cirrus_vga_mem_writel,
2097 };
2099 /***************************************
2101 * hardware cursor
2103 ***************************************/
2105 static inline void invalidate_cursor1(CirrusVGAState *s)
2107 if (s->last_hw_cursor_size) {
2108 vga_invalidate_scanlines((VGAState *)s,
2109 s->last_hw_cursor_y + s->last_hw_cursor_y_start,
2110 s->last_hw_cursor_y + s->last_hw_cursor_y_end);
2114 static inline void cirrus_cursor_compute_yrange(CirrusVGAState *s)
2116 const uint8_t *src;
2117 uint32_t content;
2118 int y, y_min, y_max;
2120 src = s->vram_ptr + s->real_vram_size - 16 * 1024;
2121 if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
2122 src += (s->sr[0x13] & 0x3c) * 256;
2123 y_min = 64;
2124 y_max = -1;
2125 for(y = 0; y < 64; y++) {
2126 content = ((uint32_t *)src)[0] |
2127 ((uint32_t *)src)[1] |
2128 ((uint32_t *)src)[2] |
2129 ((uint32_t *)src)[3];
2130 if (content) {
2131 if (y < y_min)
2132 y_min = y;
2133 if (y > y_max)
2134 y_max = y;
2136 src += 16;
2138 } else {
2139 src += (s->sr[0x13] & 0x3f) * 256;
2140 y_min = 32;
2141 y_max = -1;
2142 for(y = 0; y < 32; y++) {
2143 content = ((uint32_t *)src)[0] |
2144 ((uint32_t *)(src + 128))[0];
2145 if (content) {
2146 if (y < y_min)
2147 y_min = y;
2148 if (y > y_max)
2149 y_max = y;
2151 src += 4;
2154 if (y_min > y_max) {
2155 s->last_hw_cursor_y_start = 0;
2156 s->last_hw_cursor_y_end = 0;
2157 } else {
2158 s->last_hw_cursor_y_start = y_min;
2159 s->last_hw_cursor_y_end = y_max + 1;
2163 /* NOTE: we do not currently handle the cursor bitmap change, so we
2164 update the cursor only if it moves. */
2165 static void cirrus_cursor_invalidate(VGAState *s1)
2167 CirrusVGAState *s = (CirrusVGAState *)s1;
2168 int size;
2170 if (!s->sr[0x12] & CIRRUS_CURSOR_SHOW) {
2171 size = 0;
2172 } else {
2173 if (s->sr[0x12] & CIRRUS_CURSOR_LARGE)
2174 size = 64;
2175 else
2176 size = 32;
2178 /* invalidate last cursor and new cursor if any change */
2179 if (s->last_hw_cursor_size != size ||
2180 s->last_hw_cursor_x != s->hw_cursor_x ||
2181 s->last_hw_cursor_y != s->hw_cursor_y) {
2183 invalidate_cursor1(s);
2185 s->last_hw_cursor_size = size;
2186 s->last_hw_cursor_x = s->hw_cursor_x;
2187 s->last_hw_cursor_y = s->hw_cursor_y;
2188 /* compute the real cursor min and max y */
2189 cirrus_cursor_compute_yrange(s);
2190 invalidate_cursor1(s);
2194 static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y)
2196 CirrusVGAState *s = (CirrusVGAState *)s1;
2197 int w, h, bpp, x1, x2, poffset;
2198 unsigned int color0, color1;
2199 const uint8_t *palette, *src;
2200 uint32_t content;
2202 if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW))
2203 return;
2204 /* fast test to see if the cursor intersects with the scan line */
2205 if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
2206 h = 64;
2207 } else {
2208 h = 32;
2210 if (scr_y < s->hw_cursor_y ||
2211 scr_y >= (s->hw_cursor_y + h))
2212 return;
2214 src = s->vram_ptr + s->real_vram_size - 16 * 1024;
2215 if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
2216 src += (s->sr[0x13] & 0x3c) * 256;
2217 src += (scr_y - s->hw_cursor_y) * 16;
2218 poffset = 8;
2219 content = ((uint32_t *)src)[0] |
2220 ((uint32_t *)src)[1] |
2221 ((uint32_t *)src)[2] |
2222 ((uint32_t *)src)[3];
2223 } else {
2224 src += (s->sr[0x13] & 0x3f) * 256;
2225 src += (scr_y - s->hw_cursor_y) * 4;
2226 poffset = 128;
2227 content = ((uint32_t *)src)[0] |
2228 ((uint32_t *)(src + 128))[0];
2230 /* if nothing to draw, no need to continue */
2231 if (!content)
2232 return;
2233 w = h;
2235 x1 = s->hw_cursor_x;
2236 if (x1 >= s->last_scr_width)
2237 return;
2238 x2 = s->hw_cursor_x + w;
2239 if (x2 > s->last_scr_width)
2240 x2 = s->last_scr_width;
2241 w = x2 - x1;
2242 palette = s->cirrus_hidden_palette;
2243 color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]),
2244 c6_to_8(palette[0x0 * 3 + 1]),
2245 c6_to_8(palette[0x0 * 3 + 2]));
2246 color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]),
2247 c6_to_8(palette[0xf * 3 + 1]),
2248 c6_to_8(palette[0xf * 3 + 2]));
2249 bpp = ((s->ds->depth + 7) >> 3);
2250 d1 += x1 * bpp;
2251 switch(s->ds->depth) {
2252 default:
2253 break;
2254 case 8:
2255 vga_draw_cursor_line_8(d1, src, poffset, w, color0, color1, 0xff);
2256 break;
2257 case 15:
2258 vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0x7fff);
2259 break;
2260 case 16:
2261 vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0xffff);
2262 break;
2263 case 32:
2264 vga_draw_cursor_line_32(d1, src, poffset, w, color0, color1, 0xffffff);
2265 break;
2269 /***************************************
2271 * LFB memory access
2273 ***************************************/
2275 static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
2277 CirrusVGAState *s = (CirrusVGAState *) opaque;
2278 uint32_t ret;
2280 addr &= s->cirrus_addr_mask;
2282 if (((s->sr[0x17] & 0x44) == 0x44) &&
2283 ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
2284 /* memory-mapped I/O */
2285 ret = cirrus_mmio_blt_read(s, addr & 0xff);
2286 } else if (0) {
2287 /* XXX handle bitblt */
2288 ret = 0xff;
2289 } else {
2290 /* video memory */
2291 if ((s->gr[0x0B] & 0x14) == 0x14) {
2292 addr <<= 4;
2293 } else if (s->gr[0x0B] & 0x02) {
2294 addr <<= 3;
2296 addr &= s->cirrus_addr_mask;
2297 ret = *(s->vram_ptr + addr);
2300 return ret;
2303 static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr)
2305 uint32_t v;
2306 #ifdef TARGET_WORDS_BIGENDIAN
2307 v = cirrus_linear_readb(opaque, addr) << 8;
2308 v |= cirrus_linear_readb(opaque, addr + 1);
2309 #else
2310 v = cirrus_linear_readb(opaque, addr);
2311 v |= cirrus_linear_readb(opaque, addr + 1) << 8;
2312 #endif
2313 return v;
2316 static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr)
2318 uint32_t v;
2319 #ifdef TARGET_WORDS_BIGENDIAN
2320 v = cirrus_linear_readb(opaque, addr) << 24;
2321 v |= cirrus_linear_readb(opaque, addr + 1) << 16;
2322 v |= cirrus_linear_readb(opaque, addr + 2) << 8;
2323 v |= cirrus_linear_readb(opaque, addr + 3);
2324 #else
2325 v = cirrus_linear_readb(opaque, addr);
2326 v |= cirrus_linear_readb(opaque, addr + 1) << 8;
2327 v |= cirrus_linear_readb(opaque, addr + 2) << 16;
2328 v |= cirrus_linear_readb(opaque, addr + 3) << 24;
2329 #endif
2330 return v;
2333 static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
2334 uint32_t val)
2336 CirrusVGAState *s = (CirrusVGAState *) opaque;
2337 unsigned mode;
2339 addr &= s->cirrus_addr_mask;
2341 if (((s->sr[0x17] & 0x44) == 0x44) &&
2342 ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
2343 /* memory-mapped I/O */
2344 cirrus_mmio_blt_write(s, addr & 0xff, val);
2345 } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
2346 /* bitblt */
2347 *s->cirrus_srcptr++ = (uint8_t) val;
2348 if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
2349 cirrus_bitblt_cputovideo_next(s);
2351 } else {
2352 /* video memory */
2353 if ((s->gr[0x0B] & 0x14) == 0x14) {
2354 addr <<= 4;
2355 } else if (s->gr[0x0B] & 0x02) {
2356 addr <<= 3;
2358 addr &= s->cirrus_addr_mask;
2360 mode = s->gr[0x05] & 0x7;
2361 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
2362 *(s->vram_ptr + addr) = (uint8_t) val;
2363 cpu_physical_memory_set_dirty(s->vram_offset + addr);
2364 } else {
2365 if ((s->gr[0x0B] & 0x14) != 0x14) {
2366 cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
2367 } else {
2368 cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val);
2374 static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr,
2375 uint32_t val)
2377 #ifdef TARGET_WORDS_BIGENDIAN
2378 cirrus_linear_writeb(opaque, addr, (val >> 8) & 0xff);
2379 cirrus_linear_writeb(opaque, addr + 1, val & 0xff);
2380 #else
2381 cirrus_linear_writeb(opaque, addr, val & 0xff);
2382 cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2383 #endif
2386 static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr,
2387 uint32_t val)
2389 #ifdef TARGET_WORDS_BIGENDIAN
2390 cirrus_linear_writeb(opaque, addr, (val >> 24) & 0xff);
2391 cirrus_linear_writeb(opaque, addr + 1, (val >> 16) & 0xff);
2392 cirrus_linear_writeb(opaque, addr + 2, (val >> 8) & 0xff);
2393 cirrus_linear_writeb(opaque, addr + 3, val & 0xff);
2394 #else
2395 cirrus_linear_writeb(opaque, addr, val & 0xff);
2396 cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2397 cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff);
2398 cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff);
2399 #endif
2403 static CPUReadMemoryFunc *cirrus_linear_read[3] = {
2404 cirrus_linear_readb,
2405 cirrus_linear_readw,
2406 cirrus_linear_readl,
2407 };
2409 static CPUWriteMemoryFunc *cirrus_linear_write[3] = {
2410 cirrus_linear_writeb,
2411 cirrus_linear_writew,
2412 cirrus_linear_writel,
2413 };
2415 static void cirrus_linear_mem_writeb(void *opaque, target_phys_addr_t addr,
2416 uint32_t val)
2418 CirrusVGAState *s = (CirrusVGAState *) opaque;
2420 addr &= s->cirrus_addr_mask;
2421 *(s->vram_ptr + addr) = val;
2422 cpu_physical_memory_set_dirty(s->vram_offset + addr);
2425 static void cirrus_linear_mem_writew(void *opaque, target_phys_addr_t addr,
2426 uint32_t val)
2428 CirrusVGAState *s = (CirrusVGAState *) opaque;
2430 addr &= s->cirrus_addr_mask;
2431 cpu_to_le16w((uint16_t *)(s->vram_ptr + addr), val);
2432 cpu_physical_memory_set_dirty(s->vram_offset + addr);
2435 static void cirrus_linear_mem_writel(void *opaque, target_phys_addr_t addr,
2436 uint32_t val)
2438 CirrusVGAState *s = (CirrusVGAState *) opaque;
2440 addr &= s->cirrus_addr_mask;
2441 cpu_to_le32w((uint32_t *)(s->vram_ptr + addr), val);
2442 cpu_physical_memory_set_dirty(s->vram_offset + addr);
2445 /***************************************
2447 * system to screen memory access
2449 ***************************************/
2452 static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr)
2454 uint32_t ret;
2456 /* XXX handle bitblt */
2457 ret = 0xff;
2458 return ret;
2461 static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr)
2463 uint32_t v;
2464 #ifdef TARGET_WORDS_BIGENDIAN
2465 v = cirrus_linear_bitblt_readb(opaque, addr) << 8;
2466 v |= cirrus_linear_bitblt_readb(opaque, addr + 1);
2467 #else
2468 v = cirrus_linear_bitblt_readb(opaque, addr);
2469 v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
2470 #endif
2471 return v;
2474 static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr)
2476 uint32_t v;
2477 #ifdef TARGET_WORDS_BIGENDIAN
2478 v = cirrus_linear_bitblt_readb(opaque, addr) << 24;
2479 v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 16;
2480 v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 8;
2481 v |= cirrus_linear_bitblt_readb(opaque, addr + 3);
2482 #else
2483 v = cirrus_linear_bitblt_readb(opaque, addr);
2484 v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
2485 v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 16;
2486 v |= cirrus_linear_bitblt_readb(opaque, addr + 3) << 24;
2487 #endif
2488 return v;
2491 static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr,
2492 uint32_t val)
2494 CirrusVGAState *s = (CirrusVGAState *) opaque;
2496 if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
2497 /* bitblt */
2498 *s->cirrus_srcptr++ = (uint8_t) val;
2499 if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
2500 cirrus_bitblt_cputovideo_next(s);
2505 static void cirrus_linear_bitblt_writew(void *opaque, target_phys_addr_t addr,
2506 uint32_t val)
2508 #ifdef TARGET_WORDS_BIGENDIAN
2509 cirrus_linear_bitblt_writeb(opaque, addr, (val >> 8) & 0xff);
2510 cirrus_linear_bitblt_writeb(opaque, addr + 1, val & 0xff);
2511 #else
2512 cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
2513 cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2514 #endif
2517 static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr,
2518 uint32_t val)
2520 #ifdef TARGET_WORDS_BIGENDIAN
2521 cirrus_linear_bitblt_writeb(opaque, addr, (val >> 24) & 0xff);
2522 cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 16) & 0xff);
2523 cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 8) & 0xff);
2524 cirrus_linear_bitblt_writeb(opaque, addr + 3, val & 0xff);
2525 #else
2526 cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
2527 cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2528 cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 16) & 0xff);
2529 cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff);
2530 #endif
2534 static CPUReadMemoryFunc *cirrus_linear_bitblt_read[3] = {
2535 cirrus_linear_bitblt_readb,
2536 cirrus_linear_bitblt_readw,
2537 cirrus_linear_bitblt_readl,
2538 };
2540 static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = {
2541 cirrus_linear_bitblt_writeb,
2542 cirrus_linear_bitblt_writew,
2543 cirrus_linear_bitblt_writel,
2544 };
2546 static void set_vram_mapping(CirrusVGAState *s, unsigned long begin, unsigned long end)
2548 unsigned long i;
2549 struct xen_add_to_physmap xatp;
2550 int rc;
2552 if (end > begin + VGA_RAM_SIZE)
2553 end = begin + VGA_RAM_SIZE;
2555 fprintf(logfile,"mapping vram to %lx - %lx\n", begin, end);
2557 xatp.domid = domid;
2558 xatp.space = XENMAPSPACE_mfn;
2560 for (i = 0; i < (end - begin) >> TARGET_PAGE_BITS; i++) {
2561 xatp.idx = s->vram_mfns[i];
2562 xatp.gpfn = (begin >> TARGET_PAGE_BITS) + i;
2563 rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
2564 if (rc) {
2565 fprintf(stderr, "add_to_physmap MFN %"PRI_xen_pfn" to PFN %"PRI_xen_pfn" failed: %d\n", xatp.idx, xatp.gpfn, rc);
2566 return;
2570 (void)xc_domain_pin_memory_cacheattr(
2571 xc_handle, domid,
2572 begin >> TARGET_PAGE_BITS,
2573 end >> TARGET_PAGE_BITS,
2574 XEN_DOMCTL_MEM_CACHEATTR_WB);
2577 static void unset_vram_mapping(CirrusVGAState *s, unsigned long begin, unsigned long end)
2579 if (s->stolen_vram_addr) {
2580 /* We can put it there for xend to save it efficiently */
2581 set_vram_mapping(s, s->stolen_vram_addr, s->stolen_vram_addr + VGA_RAM_SIZE);
2582 } else {
2583 /* Old image, we have to unmap them completely */
2584 struct xen_remove_from_physmap xrfp;
2585 unsigned long i;
2586 int rc;
2588 if (end > begin + VGA_RAM_SIZE)
2589 end = begin + VGA_RAM_SIZE;
2591 fprintf(logfile,"unmapping vram from %lx - %lx\n", begin, end);
2593 xrfp.domid = domid;
2595 for (i = 0; i < (end - begin) >> TARGET_PAGE_BITS; i++) {
2596 xrfp.gpfn = (begin >> TARGET_PAGE_BITS) + i;
2597 rc = xc_memory_op(xc_handle, XENMEM_remove_from_physmap, &xrfp);
2598 if (rc) {
2599 fprintf(stderr, "remove_from_physmap PFN %"PRI_xen_pfn" failed: %d\n", xrfp.gpfn, rc);
2600 return;
2606 void cirrus_restart_acc(CirrusVGAState *s)
2608 set_vram_mapping(s, s->lfb_addr, s->lfb_end);
2609 s->map_addr = s->lfb_addr;
2610 s->map_end = s->lfb_end;
2613 /* Compute the memory access functions */
2614 static void cirrus_update_memory_access(CirrusVGAState *s)
2616 unsigned mode;
2618 if ((s->sr[0x17] & 0x44) == 0x44) {
2619 goto generic_io;
2620 } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
2621 goto generic_io;
2622 } else {
2623 if ((s->gr[0x0B] & 0x14) == 0x14) {
2624 goto generic_io;
2625 } else if (s->gr[0x0B] & 0x02) {
2626 goto generic_io;
2629 mode = s->gr[0x05] & 0x7;
2630 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
2631 if (s->lfb_addr && s->lfb_end && !s->map_addr) {
2632 set_vram_mapping(s, s->lfb_addr, s->lfb_end);
2633 s->map_addr = s->lfb_addr;
2634 s->map_end = s->lfb_end;
2636 s->cirrus_linear_write[0] = cirrus_linear_mem_writeb;
2637 s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
2638 s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
2639 } else {
2640 generic_io:
2641 if (s->lfb_addr && s->lfb_end && s->map_addr) {
2642 unset_vram_mapping(s, s->map_addr, s->map_end);
2643 s->map_addr = s->map_end = 0;
2645 s->cirrus_linear_write[0] = cirrus_linear_writeb;
2646 s->cirrus_linear_write[1] = cirrus_linear_writew;
2647 s->cirrus_linear_write[2] = cirrus_linear_writel;
2653 /* I/O ports */
2655 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
2657 CirrusVGAState *s = opaque;
2658 int val, index;
2660 /* check port range access depending on color/monochrome mode */
2661 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION))
2662 || (addr >= 0x3d0 && addr <= 0x3df
2663 && !(s->msr & MSR_COLOR_EMULATION))) {
2664 val = 0xff;
2665 } else {
2666 switch (addr) {
2667 case 0x3c0:
2668 if (s->ar_flip_flop == 0) {
2669 val = s->ar_index;
2670 } else {
2671 val = 0;
2673 break;
2674 case 0x3c1:
2675 index = s->ar_index & 0x1f;
2676 if (index < 21)
2677 val = s->ar[index];
2678 else
2679 val = 0;
2680 break;
2681 case 0x3c2:
2682 val = s->st00;
2683 break;
2684 case 0x3c4:
2685 val = s->sr_index;
2686 break;
2687 case 0x3c5:
2688 if (cirrus_hook_read_sr(s, s->sr_index, &val))
2689 break;
2690 val = s->sr[s->sr_index];
2691 #ifdef DEBUG_VGA_REG
2692 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
2693 #endif
2694 break;
2695 case 0x3c6:
2696 cirrus_read_hidden_dac(s, &val);
2697 break;
2698 case 0x3c7:
2699 val = s->dac_state;
2700 break;
2701 case 0x3c8:
2702 val = s->dac_write_index;
2703 s->cirrus_hidden_dac_lockindex = 0;
2704 break;
2705 case 0x3c9:
2706 if (cirrus_hook_read_palette(s, &val))
2707 break;
2708 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
2709 if (++s->dac_sub_index == 3) {
2710 s->dac_sub_index = 0;
2711 s->dac_read_index++;
2713 break;
2714 case 0x3ca:
2715 val = s->fcr;
2716 break;
2717 case 0x3cc:
2718 val = s->msr;
2719 break;
2720 case 0x3ce:
2721 val = s->gr_index;
2722 break;
2723 case 0x3cf:
2724 if (cirrus_hook_read_gr(s, s->gr_index, &val))
2725 break;
2726 val = s->gr[s->gr_index];
2727 #ifdef DEBUG_VGA_REG
2728 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
2729 #endif
2730 break;
2731 case 0x3b4:
2732 case 0x3d4:
2733 val = s->cr_index;
2734 break;
2735 case 0x3b5:
2736 case 0x3d5:
2737 if (cirrus_hook_read_cr(s, s->cr_index, &val))
2738 break;
2739 val = s->cr[s->cr_index];
2740 #ifdef DEBUG_VGA_REG
2741 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
2742 #endif
2743 break;
2744 case 0x3ba:
2745 case 0x3da:
2746 /* just toggle to fool polling */
2747 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
2748 val = s->st01;
2749 s->ar_flip_flop = 0;
2750 break;
2751 default:
2752 val = 0x00;
2753 break;
2756 #if defined(DEBUG_VGA)
2757 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
2758 #endif
2759 return val;
2762 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
2764 CirrusVGAState *s = opaque;
2765 int index;
2767 /* check port range access depending on color/monochrome mode */
2768 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION))
2769 || (addr >= 0x3d0 && addr <= 0x3df
2770 && !(s->msr & MSR_COLOR_EMULATION)))
2771 return;
2773 #ifdef DEBUG_VGA
2774 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
2775 #endif
2777 switch (addr) {
2778 case 0x3c0:
2779 if (s->ar_flip_flop == 0) {
2780 val &= 0x3f;
2781 s->ar_index = val;
2782 } else {
2783 index = s->ar_index & 0x1f;
2784 switch (index) {
2785 case 0x00 ... 0x0f:
2786 s->ar[index] = val & 0x3f;
2787 break;
2788 case 0x10:
2789 s->ar[index] = val & ~0x10;
2790 break;
2791 case 0x11:
2792 s->ar[index] = val;
2793 break;
2794 case 0x12:
2795 s->ar[index] = val & ~0xc0;
2796 break;
2797 case 0x13:
2798 s->ar[index] = val & ~0xf0;
2799 break;
2800 case 0x14:
2801 s->ar[index] = val & ~0xf0;
2802 break;
2803 default:
2804 break;
2807 s->ar_flip_flop ^= 1;
2808 break;
2809 case 0x3c2:
2810 s->msr = val & ~0x10;
2811 break;
2812 case 0x3c4:
2813 s->sr_index = val;
2814 break;
2815 case 0x3c5:
2816 if (cirrus_hook_write_sr(s, s->sr_index, val))
2817 break;
2818 #ifdef DEBUG_VGA_REG
2819 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
2820 #endif
2821 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
2822 break;
2823 case 0x3c6:
2824 cirrus_write_hidden_dac(s, val);
2825 break;
2826 case 0x3c7:
2827 s->dac_read_index = val;
2828 s->dac_sub_index = 0;
2829 s->dac_state = 3;
2830 break;
2831 case 0x3c8:
2832 s->dac_write_index = val;
2833 s->dac_sub_index = 0;
2834 s->dac_state = 0;
2835 break;
2836 case 0x3c9:
2837 if (cirrus_hook_write_palette(s, val))
2838 break;
2839 s->dac_cache[s->dac_sub_index] = val;
2840 if (++s->dac_sub_index == 3) {
2841 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
2842 s->dac_sub_index = 0;
2843 s->dac_write_index++;
2845 break;
2846 case 0x3ce:
2847 s->gr_index = val;
2848 break;
2849 case 0x3cf:
2850 if (cirrus_hook_write_gr(s, s->gr_index, val))
2851 break;
2852 #ifdef DEBUG_VGA_REG
2853 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
2854 #endif
2855 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
2856 break;
2857 case 0x3b4:
2858 case 0x3d4:
2859 s->cr_index = val;
2860 break;
2861 case 0x3b5:
2862 case 0x3d5:
2863 if (cirrus_hook_write_cr(s, s->cr_index, val))
2864 break;
2865 #ifdef DEBUG_VGA_REG
2866 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
2867 #endif
2868 /* handle CR0-7 protection */
2869 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
2870 /* can always write bit 4 of CR7 */
2871 if (s->cr_index == 7)
2872 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
2873 return;
2875 switch (s->cr_index) {
2876 case 0x01: /* horizontal display end */
2877 case 0x07:
2878 case 0x09:
2879 case 0x0c:
2880 case 0x0d:
2881 case 0x12: /* veritcal display end */
2882 s->cr[s->cr_index] = val;
2883 break;
2885 default:
2886 s->cr[s->cr_index] = val;
2887 break;
2889 break;
2890 case 0x3ba:
2891 case 0x3da:
2892 s->fcr = val & 0x10;
2893 break;
2897 /***************************************
2899 * memory-mapped I/O access
2901 ***************************************/
2903 static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr)
2905 CirrusVGAState *s = (CirrusVGAState *) opaque;
2907 addr &= CIRRUS_PNPMMIO_SIZE - 1;
2909 if (addr >= 0x100) {
2910 return cirrus_mmio_blt_read(s, addr - 0x100);
2911 } else {
2912 return vga_ioport_read(s, addr + 0x3c0);
2916 static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr)
2918 uint32_t v;
2919 #ifdef TARGET_WORDS_BIGENDIAN
2920 v = cirrus_mmio_readb(opaque, addr) << 8;
2921 v |= cirrus_mmio_readb(opaque, addr + 1);
2922 #else
2923 v = cirrus_mmio_readb(opaque, addr);
2924 v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
2925 #endif
2926 return v;
2929 static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr)
2931 uint32_t v;
2932 #ifdef TARGET_WORDS_BIGENDIAN
2933 v = cirrus_mmio_readb(opaque, addr) << 24;
2934 v |= cirrus_mmio_readb(opaque, addr + 1) << 16;
2935 v |= cirrus_mmio_readb(opaque, addr + 2) << 8;
2936 v |= cirrus_mmio_readb(opaque, addr + 3);
2937 #else
2938 v = cirrus_mmio_readb(opaque, addr);
2939 v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
2940 v |= cirrus_mmio_readb(opaque, addr + 2) << 16;
2941 v |= cirrus_mmio_readb(opaque, addr + 3) << 24;
2942 #endif
2943 return v;
2946 static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr,
2947 uint32_t val)
2949 CirrusVGAState *s = (CirrusVGAState *) opaque;
2951 addr &= CIRRUS_PNPMMIO_SIZE - 1;
2953 if (addr >= 0x100) {
2954 cirrus_mmio_blt_write(s, addr - 0x100, val);
2955 } else {
2956 vga_ioport_write(s, addr + 0x3c0, val);
2960 static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr,
2961 uint32_t val)
2963 #ifdef TARGET_WORDS_BIGENDIAN
2964 cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff);
2965 cirrus_mmio_writeb(opaque, addr + 1, val & 0xff);
2966 #else
2967 cirrus_mmio_writeb(opaque, addr, val & 0xff);
2968 cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2969 #endif
2972 static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr,
2973 uint32_t val)
2975 #ifdef TARGET_WORDS_BIGENDIAN
2976 cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff);
2977 cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff);
2978 cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff);
2979 cirrus_mmio_writeb(opaque, addr + 3, val & 0xff);
2980 #else
2981 cirrus_mmio_writeb(opaque, addr, val & 0xff);
2982 cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2983 cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff);
2984 cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff);
2985 #endif
2989 static CPUReadMemoryFunc *cirrus_mmio_read[3] = {
2990 cirrus_mmio_readb,
2991 cirrus_mmio_readw,
2992 cirrus_mmio_readl,
2993 };
2995 static CPUWriteMemoryFunc *cirrus_mmio_write[3] = {
2996 cirrus_mmio_writeb,
2997 cirrus_mmio_writew,
2998 cirrus_mmio_writel,
2999 };
3001 /* load/save state */
3003 static void cirrus_vga_save(QEMUFile *f, void *opaque)
3005 CirrusVGAState *s = opaque;
3006 uint8_t vga_acc;
3008 if (s->pci_dev)
3009 pci_device_save(s->pci_dev, f);
3011 qemu_put_be32s(f, &s->latch);
3012 qemu_put_8s(f, &s->sr_index);
3013 qemu_put_buffer(f, s->sr, 256);
3014 qemu_put_8s(f, &s->gr_index);
3015 qemu_put_8s(f, &s->cirrus_shadow_gr0);
3016 qemu_put_8s(f, &s->cirrus_shadow_gr1);
3017 qemu_put_buffer(f, s->gr + 2, 254);
3018 qemu_put_8s(f, &s->ar_index);
3019 qemu_put_buffer(f, s->ar, 21);
3020 qemu_put_be32s(f, &s->ar_flip_flop);
3021 qemu_put_8s(f, &s->cr_index);
3022 qemu_put_buffer(f, s->cr, 256);
3023 qemu_put_8s(f, &s->msr);
3024 qemu_put_8s(f, &s->fcr);
3025 qemu_put_8s(f, &s->st00);
3026 qemu_put_8s(f, &s->st01);
3028 qemu_put_8s(f, &s->dac_state);
3029 qemu_put_8s(f, &s->dac_sub_index);
3030 qemu_put_8s(f, &s->dac_read_index);
3031 qemu_put_8s(f, &s->dac_write_index);
3032 qemu_put_buffer(f, s->dac_cache, 3);
3033 qemu_put_buffer(f, s->palette, 768);
3035 qemu_put_be32s(f, &s->bank_offset);
3037 qemu_put_8s(f, &s->cirrus_hidden_dac_lockindex);
3038 qemu_put_8s(f, &s->cirrus_hidden_dac_data);
3040 qemu_put_be32s(f, &s->hw_cursor_x);
3041 qemu_put_be32s(f, &s->hw_cursor_y);
3042 /* XXX: we do not save the bitblt state - we assume we do not save
3043 the state when the blitter is active */
3045 vga_acc = (!!s->map_addr);
3046 qemu_put_8s(f, &vga_acc);
3047 qemu_put_be64s(f, (uint64_t*)&s->lfb_addr);
3048 qemu_put_be64s(f, (uint64_t*)&s->lfb_end);
3049 qemu_put_be64s(f, &s->stolen_vram_addr);
3050 if (!s->stolen_vram_addr && !vga_acc)
3051 /* Old guest: VRAM is not mapped, we have to save it ourselves */
3052 qemu_put_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
3055 static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
3057 CirrusVGAState *s = opaque;
3058 uint8_t vga_acc = 0;
3059 int ret;
3061 if (version_id > 3)
3062 return -EINVAL;
3064 if (s->pci_dev && version_id >= 2) {
3065 ret = pci_device_load(s->pci_dev, f);
3066 if (ret < 0)
3067 return ret;
3070 qemu_get_be32s(f, &s->latch);
3071 qemu_get_8s(f, &s->sr_index);
3072 qemu_get_buffer(f, s->sr, 256);
3073 qemu_get_8s(f, &s->gr_index);
3074 qemu_get_8s(f, &s->cirrus_shadow_gr0);
3075 qemu_get_8s(f, &s->cirrus_shadow_gr1);
3076 s->gr[0x00] = s->cirrus_shadow_gr0 & 0x0f;
3077 s->gr[0x01] = s->cirrus_shadow_gr1 & 0x0f;
3078 qemu_get_buffer(f, s->gr + 2, 254);
3079 qemu_get_8s(f, &s->ar_index);
3080 qemu_get_buffer(f, s->ar, 21);
3081 qemu_get_be32s(f, &s->ar_flip_flop);
3082 qemu_get_8s(f, &s->cr_index);
3083 qemu_get_buffer(f, s->cr, 256);
3084 qemu_get_8s(f, &s->msr);
3085 qemu_get_8s(f, &s->fcr);
3086 qemu_get_8s(f, &s->st00);
3087 qemu_get_8s(f, &s->st01);
3089 qemu_get_8s(f, &s->dac_state);
3090 qemu_get_8s(f, &s->dac_sub_index);
3091 qemu_get_8s(f, &s->dac_read_index);
3092 qemu_get_8s(f, &s->dac_write_index);
3093 qemu_get_buffer(f, s->dac_cache, 3);
3094 qemu_get_buffer(f, s->palette, 768);
3096 qemu_get_be32s(f, &s->bank_offset);
3098 qemu_get_8s(f, &s->cirrus_hidden_dac_lockindex);
3099 qemu_get_8s(f, &s->cirrus_hidden_dac_data);
3101 qemu_get_be32s(f, &s->hw_cursor_x);
3102 qemu_get_be32s(f, &s->hw_cursor_y);
3104 qemu_get_8s(f, &vga_acc);
3105 qemu_get_be64s(f, (uint64_t*)&s->lfb_addr);
3106 qemu_get_be64s(f, (uint64_t*)&s->lfb_end);
3107 if (version_id >= 3) {
3108 qemu_get_be64s(f, &s->stolen_vram_addr);
3109 if (!s->stolen_vram_addr && !vga_acc) {
3110 /* Old guest, VRAM is not mapped, we have to restore it ourselves */
3111 qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
3112 xen_vga_populate_vram(s->lfb_addr);
3113 } else
3114 xen_vga_vram_map(vga_acc ? s->lfb_addr : s->stolen_vram_addr, 0);
3115 } else {
3116 /* Old image, we have to populate and restore VRAM ourselves */
3117 xen_vga_populate_vram(s->lfb_addr);
3118 qemu_get_buffer(f, s->vram_ptr, VGA_RAM_SIZE);
3119 if (vga_acc)
3120 cirrus_restart_acc(s);
3123 /* force refresh */
3124 s->graphic_mode = -1;
3125 cirrus_update_bank_ptr(s, 0);
3126 cirrus_update_bank_ptr(s, 1);
3127 return 0;
3130 /***************************************
3132 * initialize
3134 ***************************************/
3136 static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
3138 int vga_io_memory, i;
3139 static int inited;
3141 if (!inited) {
3142 inited = 1;
3143 for(i = 0;i < 256; i++)
3144 rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */
3145 rop_to_index[CIRRUS_ROP_0] = 0;
3146 rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1;
3147 rop_to_index[CIRRUS_ROP_NOP] = 2;
3148 rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3;
3149 rop_to_index[CIRRUS_ROP_NOTDST] = 4;
3150 rop_to_index[CIRRUS_ROP_SRC] = 5;
3151 rop_to_index[CIRRUS_ROP_1] = 6;
3152 rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7;
3153 rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8;
3154 rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9;
3155 rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10;
3156 rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11;
3157 rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12;
3158 rop_to_index[CIRRUS_ROP_NOTSRC] = 13;
3159 rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14;
3160 rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15;
3163 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
3165 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
3166 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
3167 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
3168 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
3170 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
3172 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
3173 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
3174 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
3175 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
3177 vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read,
3178 cirrus_vga_mem_write, s);
3179 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
3180 vga_io_memory);
3182 s->sr[0x06] = 0x0f;
3183 if (device_id == CIRRUS_ID_CLGD5446) {
3184 /* 4MB 64 bit memory config, always PCI */
3185 s->sr[0x1F] = 0x2d; // MemClock
3186 s->gr[0x18] = 0x0f; // fastest memory configuration
3187 #if 1
3188 s->sr[0x0f] = 0x98;
3189 s->sr[0x17] = 0x20;
3190 s->sr[0x15] = 0x04; /* memory size, 3=2MB, 4=4MB */
3191 s->real_vram_size = 4096 * 1024;
3192 #else
3193 s->sr[0x0f] = 0x18;
3194 s->sr[0x17] = 0x20;
3195 s->sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */
3196 s->real_vram_size = 2048 * 1024;
3197 #endif
3198 } else {
3199 s->sr[0x1F] = 0x22; // MemClock
3200 s->sr[0x0F] = CIRRUS_MEMSIZE_2M;
3201 if (is_pci)
3202 s->sr[0x17] = CIRRUS_BUSTYPE_PCI;
3203 else
3204 s->sr[0x17] = CIRRUS_BUSTYPE_ISA;
3205 s->real_vram_size = 2048 * 1024;
3206 s->sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */
3208 s->cr[0x27] = device_id;
3210 /* Win2K seems to assume that the pattern buffer is at 0xff
3211 initially ! */
3212 memset(s->vram_ptr, 0xff, s->real_vram_size);
3214 s->cirrus_hidden_dac_lockindex = 5;
3215 s->cirrus_hidden_dac_data = 0;
3217 /* I/O handler for LFB */
3218 s->cirrus_linear_io_addr =
3219 cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write,
3220 s);
3221 s->cirrus_linear_write = cpu_get_io_memory_write(s->cirrus_linear_io_addr);
3223 /* I/O handler for LFB */
3224 s->cirrus_linear_bitblt_io_addr =
3225 cpu_register_io_memory(0, cirrus_linear_bitblt_read, cirrus_linear_bitblt_write,
3226 s);
3228 /* I/O handler for memory-mapped I/O */
3229 s->cirrus_mmio_io_addr =
3230 cpu_register_io_memory(0, cirrus_mmio_read, cirrus_mmio_write, s);
3232 /* XXX: s->vram_size must be a power of two */
3233 s->cirrus_addr_mask = s->real_vram_size - 1;
3234 s->linear_mmio_mask = s->real_vram_size - 256;
3236 s->get_bpp = cirrus_get_bpp;
3237 s->get_offsets = cirrus_get_offsets;
3238 s->get_resolution = cirrus_get_resolution;
3239 s->cursor_invalidate = cirrus_cursor_invalidate;
3240 s->cursor_draw_line = cirrus_cursor_draw_line;
3242 register_savevm("cirrus_vga", 0, 3, cirrus_vga_save, cirrus_vga_load, s);
3245 /***************************************
3247 * ISA bus support
3249 ***************************************/
3251 void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
3252 unsigned long vga_ram_offset, int vga_ram_size)
3254 CirrusVGAState *s;
3256 s = qemu_mallocz(sizeof(CirrusVGAState));
3258 vga_common_init((VGAState *)s,
3259 ds, vga_ram_base, vga_ram_offset, vga_ram_size);
3260 cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0);
3261 /* XXX ISA-LFB support */
3264 /***************************************
3266 * PCI bus support
3268 ***************************************/
3270 static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
3271 uint32_t addr, uint32_t size, int type)
3273 CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga;
3275 /* XXX: add byte swapping apertures */
3276 cpu_register_physical_memory(addr, s->vram_size,
3277 s->cirrus_linear_io_addr);
3278 s->lfb_addr = addr;
3279 s->lfb_end = addr + VGA_RAM_SIZE;
3281 if (s->map_addr && (s->lfb_addr != s->map_addr) &&
3282 (s->lfb_end != s->map_end))
3283 fprintf(logfile, "cirrus vga map change while on lfb mode\n");
3285 cpu_register_physical_memory(addr + 0x1000000, 0x400000,
3286 s->cirrus_linear_bitblt_io_addr);
3289 static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
3290 uint32_t addr, uint32_t size, int type)
3292 CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga;
3294 cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE,
3295 s->cirrus_mmio_io_addr);
3298 void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
3299 unsigned long vga_ram_offset, int vga_ram_size)
3301 PCICirrusVGAState *d;
3302 uint8_t *pci_conf;
3303 CirrusVGAState *s;
3304 int device_id;
3306 device_id = CIRRUS_ID_CLGD5446;
3308 /* setup PCI configuration registers */
3309 d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA",
3310 sizeof(PCICirrusVGAState),
3311 -1, NULL, NULL);
3312 pci_conf = d->dev.config;
3313 pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff);
3314 pci_conf[0x01] = (uint8_t) (PCI_VENDOR_CIRRUS >> 8);
3315 pci_conf[0x02] = (uint8_t) (device_id & 0xff);
3316 pci_conf[0x03] = (uint8_t) (device_id >> 8);
3317 pci_conf[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS;
3318 pci_conf[0x0a] = PCI_CLASS_SUB_VGA;
3319 pci_conf[0x0b] = PCI_CLASS_BASE_DISPLAY;
3320 pci_conf[0x0e] = PCI_CLASS_HEADERTYPE_00h;
3321 pci_conf[0x2c] = 0x53; /* subsystem vendor: XenSource */
3322 pci_conf[0x2d] = 0x58;
3323 pci_conf[0x2e] = 0x01; /* subsystem device */
3324 pci_conf[0x2f] = 0x00;
3326 /* setup VGA */
3327 s = &d->cirrus_vga;
3328 vga_common_init((VGAState *)s,
3329 ds, vga_ram_base, vga_ram_offset, vga_ram_size);
3330 cirrus_init_common(s, device_id, 1);
3331 s->pci_dev = (PCIDevice *)d;
3333 /* setup memory space */
3334 /* memory #0 LFB */
3335 /* memory #1 memory-mapped I/O */
3336 /* XXX: s->vram_size must be a power of two */
3337 pci_register_io_region((PCIDevice *)d, 0, 0x2000000,
3338 PCI_ADDRESS_SPACE_MEM_PREFETCH, cirrus_pci_lfb_map);
3339 if (device_id == CIRRUS_ID_CLGD5446) {
3340 pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE,
3341 PCI_ADDRESS_SPACE_MEM, cirrus_pci_mmio_map);
3343 /* XXX: ROM BIOS */