]> git.proxmox.com Git - qemu.git/blame - hw/cirrus_vga.c
better to use different ID for ISA and PCI
[qemu.git] / hw / cirrus_vga.c
CommitLineData
e6e5ad80 1/*
aeb3c85f 2 * QEMU Cirrus CLGD 54xx VGA Emulator.
e6e5ad80
FB
3 *
4 * Copyright (c) 2004 Fabrice Bellard
aeb3c85f 5 * Copyright (c) 2004 Makoto Suzuki (suzu)
e6e5ad80
FB
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 */
aeb3c85f
FB
25/*
26 * Reference: Finn Thogersons' VGADOC4b
27 * available at http://home.worldonline.dk/~finth/
28 */
e6e5ad80
FB
29#include "vl.h"
30#include "vga_int.h"
31
e36f36e1 32//#define DEBUG_CIRRUS
a21ae81d 33//#define DEBUG_BITBLT
e36f36e1 34
e6e5ad80
FB
35/***************************************
36 *
37 * definitions
38 *
39 ***************************************/
40
41#define qemu_MIN(a,b) ((a) < (b) ? (a) : (b))
42
43// ID
44#define CIRRUS_ID_CLGD5422 (0x23<<2)
45#define CIRRUS_ID_CLGD5426 (0x24<<2)
46#define CIRRUS_ID_CLGD5424 (0x25<<2)
47#define CIRRUS_ID_CLGD5428 (0x26<<2)
48#define CIRRUS_ID_CLGD5430 (0x28<<2)
49#define CIRRUS_ID_CLGD5434 (0x2A<<2)
a21ae81d 50#define CIRRUS_ID_CLGD5436 (0x2B<<2)
e6e5ad80
FB
51#define CIRRUS_ID_CLGD5446 (0x2E<<2)
52
53// sequencer 0x07
54#define CIRRUS_SR7_BPP_VGA 0x00
55#define CIRRUS_SR7_BPP_SVGA 0x01
56#define CIRRUS_SR7_BPP_MASK 0x0e
57#define CIRRUS_SR7_BPP_8 0x00
58#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02
59#define CIRRUS_SR7_BPP_24 0x04
60#define CIRRUS_SR7_BPP_16 0x06
61#define CIRRUS_SR7_BPP_32 0x08
62#define CIRRUS_SR7_ISAADDR_MASK 0xe0
63
64// sequencer 0x0f
65#define CIRRUS_MEMSIZE_512k 0x08
66#define CIRRUS_MEMSIZE_1M 0x10
67#define CIRRUS_MEMSIZE_2M 0x18
68#define CIRRUS_MEMFLAGS_BANKSWITCH 0x80 // bank switching is enabled.
69
70// sequencer 0x12
71#define CIRRUS_CURSOR_SHOW 0x01
72#define CIRRUS_CURSOR_HIDDENPEL 0x02
73#define CIRRUS_CURSOR_LARGE 0x04 // 64x64 if set, 32x32 if clear
74
75// sequencer 0x17
76#define CIRRUS_BUSTYPE_VLBFAST 0x10
77#define CIRRUS_BUSTYPE_PCI 0x20
78#define CIRRUS_BUSTYPE_VLBSLOW 0x30
79#define CIRRUS_BUSTYPE_ISA 0x38
80#define CIRRUS_MMIO_ENABLE 0x04
81#define CIRRUS_MMIO_USE_PCIADDR 0x40 // 0xb8000 if cleared.
82#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80
83
84// control 0x0b
85#define CIRRUS_BANKING_DUAL 0x01
86#define CIRRUS_BANKING_GRANULARITY_16K 0x20 // set:16k, clear:4k
87
88// control 0x30
89#define CIRRUS_BLTMODE_BACKWARDS 0x01
90#define CIRRUS_BLTMODE_MEMSYSDEST 0x02
91#define CIRRUS_BLTMODE_MEMSYSSRC 0x04
92#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08
93#define CIRRUS_BLTMODE_PATTERNCOPY 0x40
94#define CIRRUS_BLTMODE_COLOREXPAND 0x80
95#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30
96#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00
97#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10
98#define CIRRUS_BLTMODE_PIXELWIDTH24 0x20
99#define CIRRUS_BLTMODE_PIXELWIDTH32 0x30
100
101// control 0x31
102#define CIRRUS_BLT_BUSY 0x01
103#define CIRRUS_BLT_START 0x02
104#define CIRRUS_BLT_RESET 0x04
105#define CIRRUS_BLT_FIFOUSED 0x10
106
107// control 0x32
108#define CIRRUS_ROP_0 0x00
109#define CIRRUS_ROP_SRC_AND_DST 0x05
110#define CIRRUS_ROP_NOP 0x06
111#define CIRRUS_ROP_SRC_AND_NOTDST 0x09
112#define CIRRUS_ROP_NOTDST 0x0b
113#define CIRRUS_ROP_SRC 0x0d
114#define CIRRUS_ROP_1 0x0e
115#define CIRRUS_ROP_NOTSRC_AND_DST 0x50
116#define CIRRUS_ROP_SRC_XOR_DST 0x59
117#define CIRRUS_ROP_SRC_OR_DST 0x6d
118#define CIRRUS_ROP_NOTSRC_OR_NOTDST 0x90
119#define CIRRUS_ROP_SRC_NOTXOR_DST 0x95
120#define CIRRUS_ROP_SRC_OR_NOTDST 0xad
121#define CIRRUS_ROP_NOTSRC 0xd0
122#define CIRRUS_ROP_NOTSRC_OR_DST 0xd6
123#define CIRRUS_ROP_NOTSRC_AND_NOTDST 0xda
124
a21ae81d
FB
125// control 0x33
126#define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04
127
e6e5ad80
FB
128// memory-mapped IO
129#define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword
130#define CIRRUS_MMIO_BLTFGCOLOR 0x04 // dword
131#define CIRRUS_MMIO_BLTWIDTH 0x08 // word
132#define CIRRUS_MMIO_BLTHEIGHT 0x0a // word
133#define CIRRUS_MMIO_BLTDESTPITCH 0x0c // word
134#define CIRRUS_MMIO_BLTSRCPITCH 0x0e // word
135#define CIRRUS_MMIO_BLTDESTADDR 0x10 // dword
136#define CIRRUS_MMIO_BLTSRCADDR 0x14 // dword
137#define CIRRUS_MMIO_BLTWRITEMASK 0x17 // byte
138#define CIRRUS_MMIO_BLTMODE 0x18 // byte
139#define CIRRUS_MMIO_BLTROP 0x1a // byte
140#define CIRRUS_MMIO_BLTMODEEXT 0x1b // byte
141#define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c // word?
142#define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20 // word?
143#define CIRRUS_MMIO_LINEARDRAW_START_X 0x24 // word
144#define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26 // word
145#define CIRRUS_MMIO_LINEARDRAW_END_X 0x28 // word
146#define CIRRUS_MMIO_LINEARDRAW_END_Y 0x2a // word
147#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c // byte
148#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d // byte
149#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e // byte
150#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f // byte
151#define CIRRUS_MMIO_BRESENHAM_K1 0x30 // word
152#define CIRRUS_MMIO_BRESENHAM_K3 0x32 // word
153#define CIRRUS_MMIO_BRESENHAM_ERROR 0x34 // word
154#define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36 // word
155#define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38 // byte
156#define CIRRUS_MMIO_LINEDRAW_MODE 0x39 // byte
157#define CIRRUS_MMIO_BLTSTATUS 0x40 // byte
158
159// PCI 0x00: vendor, 0x02: device
160#define PCI_VENDOR_CIRRUS 0x1013
e6e5ad80
FB
161#define PCI_DEVICE_CLGD5462 0x00d0
162#define PCI_DEVICE_CLGD5465 0x00d6
a21ae81d 163
e6e5ad80
FB
164// PCI 0x04: command(word), 0x06(word): status
165#define PCI_COMMAND_IOACCESS 0x0001
166#define PCI_COMMAND_MEMACCESS 0x0002
167#define PCI_COMMAND_BUSMASTER 0x0004
168#define PCI_COMMAND_SPECIALCYCLE 0x0008
169#define PCI_COMMAND_MEMWRITEINVALID 0x0010
170#define PCI_COMMAND_PALETTESNOOPING 0x0020
171#define PCI_COMMAND_PARITYDETECTION 0x0040
172#define PCI_COMMAND_ADDRESSDATASTEPPING 0x0080
173#define PCI_COMMAND_SERR 0x0100
174#define PCI_COMMAND_BACKTOBACKTRANS 0x0200
175// PCI 0x08, 0xff000000 (0x09-0x0b:class,0x08:rev)
176#define PCI_CLASS_BASE_DISPLAY 0x03
177// PCI 0x08, 0x00ff0000
178#define PCI_CLASS_SUB_VGA 0x00
179// PCI 0x0c, 0x00ff0000 (0x0c:cacheline,0x0d:latency,0x0e:headertype,0x0f:Built-in self test)
180#define PCI_CLASS_HEADERTYPE_00h 0x00
181// 0x10-0x3f (headertype 00h)
182// PCI 0x10,0x14,0x18,0x1c,0x20,0x24: base address mapping registers
183// 0x10: MEMBASE, 0x14: IOBASE(hard-coded in XFree86 3.x)
184#define PCI_MAP_MEM 0x0
185#define PCI_MAP_IO 0x1
186#define PCI_MAP_MEM_ADDR_MASK (~0xf)
187#define PCI_MAP_IO_ADDR_MASK (~0x3)
188#define PCI_MAP_MEMFLAGS_32BIT 0x0
189#define PCI_MAP_MEMFLAGS_32BIT_1M 0x1
190#define PCI_MAP_MEMFLAGS_64BIT 0x4
191#define PCI_MAP_MEMFLAGS_CACHEABLE 0x8
192// PCI 0x28: cardbus CIS pointer
193// PCI 0x2c: subsystem vendor id, 0x2e: subsystem id
194// PCI 0x30: expansion ROM base address
195#define PCI_ROMBIOS_ENABLED 0x1
196// PCI 0x34: 0xffffff00=reserved, 0x000000ff=capabilities pointer
197// PCI 0x38: reserved
198// PCI 0x3c: 0x3c=int-line, 0x3d=int-pin, 0x3e=min-gnt, 0x3f=maax-lat
199
a21ae81d 200#define CIRRUS_PNPMMIO_SIZE 0x1000
e6e5ad80
FB
201
202
203/* I/O and memory hook */
204#define CIRRUS_HOOK_NOT_HANDLED 0
205#define CIRRUS_HOOK_HANDLED 1
206
207typedef void (*cirrus_bitblt_rop_t) (uint8_t * dst, const uint8_t * src,
208 int dstpitch, int srcpitch,
209 int bltwidth, int bltheight);
210
211typedef void (*cirrus_bitblt_handler_t) (void *opaque);
212
213typedef struct CirrusVGAState {
4e3e9d0b 214 VGA_STATE_COMMON
e6e5ad80
FB
215
216 int cirrus_linear_io_addr;
217 int cirrus_mmio_io_addr;
218 uint32_t cirrus_addr_mask;
219 uint8_t cirrus_shadow_gr0;
220 uint8_t cirrus_shadow_gr1;
221 uint8_t cirrus_hidden_dac_lockindex;
222 uint8_t cirrus_hidden_dac_data;
223 uint32_t cirrus_bank_base[2];
224 uint32_t cirrus_bank_limit[2];
225 uint8_t cirrus_hidden_palette[48];
226 uint32_t cirrus_hw_cursor_x;
227 uint32_t cirrus_hw_cursor_y;
228 int cirrus_blt_pixelwidth;
229 int cirrus_blt_width;
230 int cirrus_blt_height;
231 int cirrus_blt_dstpitch;
232 int cirrus_blt_srcpitch;
233 uint32_t cirrus_blt_dstaddr;
234 uint32_t cirrus_blt_srcaddr;
235 uint8_t cirrus_blt_mode;
236 cirrus_bitblt_rop_t cirrus_rop;
237#define CIRRUS_BLTBUFSIZE 256
238 uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
239 uint8_t *cirrus_srcptr;
240 uint8_t *cirrus_srcptr_end;
241 uint32_t cirrus_srccounter;
242 uint8_t *cirrus_dstptr;
243 uint8_t *cirrus_dstptr_end;
244 uint32_t cirrus_dstcounter;
245 cirrus_bitblt_handler_t cirrus_blt_handler;
246 int cirrus_blt_horz_counter;
247} CirrusVGAState;
248
249typedef struct PCICirrusVGAState {
250 PCIDevice dev;
251 CirrusVGAState cirrus_vga;
252} PCICirrusVGAState;
253
254/***************************************
255 *
256 * prototypes.
257 *
258 ***************************************/
259
260
261static void cirrus_bitblt_reset(CirrusVGAState * s);
262
263/***************************************
264 *
265 * raster operations
266 *
267 ***************************************/
268
a21ae81d 269#define IMPLEMENT_BITBLT(name,opline) \
e6e5ad80
FB
270 static void \
271 cirrus_bitblt_rop_fwd_##name( \
272 uint8_t *dst,const uint8_t *src, \
273 int dstpitch,int srcpitch, \
274 int bltwidth,int bltheight) \
275 { \
276 int x,y; \
277 dstpitch -= bltwidth; \
278 srcpitch -= bltwidth; \
279 for (y = 0; y < bltheight; y++) { \
280 for (x = 0; x < bltwidth; x++) { \
281 opline; \
282 dst++; \
283 src++; \
284 } \
285 dst += dstpitch; \
286 src += srcpitch; \
287 } \
a21ae81d
FB
288 } \
289 \
e6e5ad80
FB
290 static void \
291 cirrus_bitblt_rop_bkwd_##name( \
292 uint8_t *dst,const uint8_t *src, \
293 int dstpitch,int srcpitch, \
294 int bltwidth,int bltheight) \
295 { \
296 int x,y; \
297 dstpitch += bltwidth; \
298 srcpitch += bltwidth; \
299 for (y = 0; y < bltheight; y++) { \
300 for (x = 0; x < bltwidth; x++) { \
301 opline; \
302 dst--; \
303 src--; \
304 } \
305 dst += dstpitch; \
306 src += srcpitch; \
307 } \
308 }
309
a21ae81d
FB
310IMPLEMENT_BITBLT(0, *dst = 0)
311IMPLEMENT_BITBLT(src_and_dst, *dst = (*src) & (*dst))
312IMPLEMENT_BITBLT(nop, (void) 0)
313IMPLEMENT_BITBLT(src_and_notdst, *dst = (*src) & (~(*dst)))
314IMPLEMENT_BITBLT(notdst, *dst = ~(*dst))
315IMPLEMENT_BITBLT(src, *dst = *src)
316IMPLEMENT_BITBLT(1, *dst = 0xff)
317IMPLEMENT_BITBLT(notsrc_and_dst, *dst = (~(*src)) & (*dst))
318IMPLEMENT_BITBLT(src_xor_dst, *dst = (*src) ^ (*dst))
319IMPLEMENT_BITBLT(src_or_dst, *dst = (*src) | (*dst))
320IMPLEMENT_BITBLT(notsrc_or_notdst, *dst = (~(*src)) | (~(*dst)))
321IMPLEMENT_BITBLT(src_notxor_dst, *dst = ~((*src) ^ (*dst)))
322IMPLEMENT_BITBLT(src_or_notdst, *dst = (*src) | (~(*dst)))
323IMPLEMENT_BITBLT(notsrc, *dst = (~(*src)))
324IMPLEMENT_BITBLT(notsrc_or_dst, *dst = (~(*src)) | (*dst))
325IMPLEMENT_BITBLT(notsrc_and_notdst, *dst = (~(*src)) & (~(*dst)))
e6e5ad80
FB
326
327static cirrus_bitblt_rop_t cirrus_get_fwd_rop_handler(uint8_t rop)
328{
329 cirrus_bitblt_rop_t rop_handler = cirrus_bitblt_rop_fwd_nop;
330
331 switch (rop) {
332 case CIRRUS_ROP_0:
333 rop_handler = cirrus_bitblt_rop_fwd_0;
334 break;
335 case CIRRUS_ROP_SRC_AND_DST:
336 rop_handler = cirrus_bitblt_rop_fwd_src_and_dst;
337 break;
338 case CIRRUS_ROP_NOP:
339 rop_handler = cirrus_bitblt_rop_fwd_nop;
340 break;
341 case CIRRUS_ROP_SRC_AND_NOTDST:
342 rop_handler = cirrus_bitblt_rop_fwd_src_and_notdst;
343 break;
344 case CIRRUS_ROP_NOTDST:
345 rop_handler = cirrus_bitblt_rop_fwd_notdst;
346 break;
347 case CIRRUS_ROP_SRC:
348 rop_handler = cirrus_bitblt_rop_fwd_src;
349 break;
350 case CIRRUS_ROP_1:
351 rop_handler = cirrus_bitblt_rop_fwd_1;
352 break;
353 case CIRRUS_ROP_NOTSRC_AND_DST:
354 rop_handler = cirrus_bitblt_rop_fwd_notsrc_and_dst;
355 break;
356 case CIRRUS_ROP_SRC_XOR_DST:
357 rop_handler = cirrus_bitblt_rop_fwd_src_xor_dst;
358 break;
359 case CIRRUS_ROP_SRC_OR_DST:
360 rop_handler = cirrus_bitblt_rop_fwd_src_or_dst;
361 break;
362 case CIRRUS_ROP_NOTSRC_OR_NOTDST:
363 rop_handler = cirrus_bitblt_rop_fwd_notsrc_or_notdst;
364 break;
365 case CIRRUS_ROP_SRC_NOTXOR_DST:
366 rop_handler = cirrus_bitblt_rop_fwd_src_notxor_dst;
367 break;
368 case CIRRUS_ROP_SRC_OR_NOTDST:
369 rop_handler = cirrus_bitblt_rop_fwd_src_or_notdst;
370 break;
371 case CIRRUS_ROP_NOTSRC:
372 rop_handler = cirrus_bitblt_rop_fwd_notsrc;
373 break;
374 case CIRRUS_ROP_NOTSRC_OR_DST:
375 rop_handler = cirrus_bitblt_rop_fwd_notsrc_or_dst;
376 break;
377 case CIRRUS_ROP_NOTSRC_AND_NOTDST:
378 rop_handler = cirrus_bitblt_rop_fwd_notsrc_and_notdst;
379 break;
380 default:
381#ifdef DEBUG_CIRRUS
382 printf("unknown ROP %02x\n", rop);
383#endif
384 break;
385 }
386
387 return rop_handler;
388}
389
390static cirrus_bitblt_rop_t cirrus_get_bkwd_rop_handler(uint8_t rop)
391{
392 cirrus_bitblt_rop_t rop_handler = cirrus_bitblt_rop_bkwd_nop;
393
394 switch (rop) {
395 case CIRRUS_ROP_0:
396 rop_handler = cirrus_bitblt_rop_bkwd_0;
397 break;
398 case CIRRUS_ROP_SRC_AND_DST:
399 rop_handler = cirrus_bitblt_rop_bkwd_src_and_dst;
400 break;
401 case CIRRUS_ROP_NOP:
402 rop_handler = cirrus_bitblt_rop_bkwd_nop;
403 break;
404 case CIRRUS_ROP_SRC_AND_NOTDST:
405 rop_handler = cirrus_bitblt_rop_bkwd_src_and_notdst;
406 break;
407 case CIRRUS_ROP_NOTDST:
408 rop_handler = cirrus_bitblt_rop_bkwd_notdst;
409 break;
410 case CIRRUS_ROP_SRC:
411 rop_handler = cirrus_bitblt_rop_bkwd_src;
412 break;
413 case CIRRUS_ROP_1:
414 rop_handler = cirrus_bitblt_rop_bkwd_1;
415 break;
416 case CIRRUS_ROP_NOTSRC_AND_DST:
417 rop_handler = cirrus_bitblt_rop_bkwd_notsrc_and_dst;
418 break;
419 case CIRRUS_ROP_SRC_XOR_DST:
420 rop_handler = cirrus_bitblt_rop_bkwd_src_xor_dst;
421 break;
422 case CIRRUS_ROP_SRC_OR_DST:
423 rop_handler = cirrus_bitblt_rop_bkwd_src_or_dst;
424 break;
425 case CIRRUS_ROP_NOTSRC_OR_NOTDST:
426 rop_handler = cirrus_bitblt_rop_bkwd_notsrc_or_notdst;
427 break;
428 case CIRRUS_ROP_SRC_NOTXOR_DST:
429 rop_handler = cirrus_bitblt_rop_bkwd_src_notxor_dst;
430 break;
431 case CIRRUS_ROP_SRC_OR_NOTDST:
432 rop_handler = cirrus_bitblt_rop_bkwd_src_or_notdst;
433 break;
434 case CIRRUS_ROP_NOTSRC:
435 rop_handler = cirrus_bitblt_rop_bkwd_notsrc;
436 break;
437 case CIRRUS_ROP_NOTSRC_OR_DST:
438 rop_handler = cirrus_bitblt_rop_bkwd_notsrc_or_dst;
439 break;
440 case CIRRUS_ROP_NOTSRC_AND_NOTDST:
441 rop_handler = cirrus_bitblt_rop_bkwd_notsrc_and_notdst;
442 break;
443 default:
444#ifdef DEBUG_CIRRUS
445 printf("unknown ROP %02x\n", rop);
446#endif
447 break;
448 }
449
450 return rop_handler;
451}
452
453/***************************************
454 *
455 * color expansion
456 *
457 ***************************************/
458
459static void
460cirrus_colorexpand_8(CirrusVGAState * s, uint8_t * dst,
461 const uint8_t * src, int count)
462{
463 int x;
464 uint8_t colors[2];
465 unsigned bits;
466 unsigned bitmask;
467 int srcskipleft = 0;
468
aeb3c85f
FB
469 colors[0] = s->cirrus_shadow_gr0;
470 colors[1] = s->cirrus_shadow_gr1;
e6e5ad80
FB
471
472 bitmask = 0x80 >> srcskipleft;
473 bits = *src++;
474 for (x = 0; x < count; x++) {
475 if ((bitmask & 0xff) == 0) {
476 bitmask = 0x80;
477 bits = *src++;
478 }
479 *dst++ = colors[!!(bits & bitmask)];
480 bitmask >>= 1;
481 }
482}
483
484static void
485cirrus_colorexpand_16(CirrusVGAState * s, uint8_t * dst,
486 const uint8_t * src, int count)
487{
488 int x;
489 uint8_t colors[2][2];
490 unsigned bits;
491 unsigned bitmask;
492 unsigned index;
493 int srcskipleft = 0;
494
aeb3c85f 495 colors[0][0] = s->cirrus_shadow_gr0;
e6e5ad80 496 colors[0][1] = s->gr[0x10];
aeb3c85f 497 colors[1][0] = s->cirrus_shadow_gr1;
e6e5ad80
FB
498 colors[1][1] = s->gr[0x11];
499
500 bitmask = 0x80 >> srcskipleft;
501 bits = *src++;
502 for (x = 0; x < count; x++) {
503 if ((bitmask & 0xff) == 0) {
504 bitmask = 0x80;
505 bits = *src++;
506 }
507 index = !!(bits & bitmask);
508 *dst++ = colors[index][0];
509 *dst++ = colors[index][1];
510 bitmask >>= 1;
511 }
512}
513
514static void
515cirrus_colorexpand_24(CirrusVGAState * s, uint8_t * dst,
516 const uint8_t * src, int count)
517{
518 int x;
519 uint8_t colors[2][3];
520 unsigned bits;
521 unsigned bitmask;
522 unsigned index;
523 int srcskipleft = 0;
524
aeb3c85f 525 colors[0][0] = s->cirrus_shadow_gr0;
e6e5ad80
FB
526 colors[0][1] = s->gr[0x10];
527 colors[0][2] = s->gr[0x12];
aeb3c85f 528 colors[1][0] = s->cirrus_shadow_gr1;
e6e5ad80
FB
529 colors[1][1] = s->gr[0x11];
530 colors[1][2] = s->gr[0x13];
531
532 bitmask = 0x80 << srcskipleft;
533 bits = *src++;
534 for (x = 0; x < count; x++) {
535 if ((bitmask & 0xff) == 0) {
536 bitmask = 0x80;
537 bits = *src++;
538 }
539 index = !!(bits & bitmask);
540 *dst++ = colors[index][0];
541 *dst++ = colors[index][1];
542 *dst++ = colors[index][2];
543 bitmask >>= 1;
544 }
545}
546
547static void
548cirrus_colorexpand_32(CirrusVGAState * s, uint8_t * dst,
549 const uint8_t * src, int count)
550{
551 int x;
552 uint8_t colors[2][4];
553 unsigned bits;
554 unsigned bitmask;
555 unsigned index;
556 int srcskipleft = 0;
557
aeb3c85f 558 colors[0][0] = s->cirrus_shadow_gr0;
e6e5ad80
FB
559 colors[0][1] = s->gr[0x10];
560 colors[0][2] = s->gr[0x12];
561 colors[0][3] = s->gr[0x14];
aeb3c85f 562 colors[1][0] = s->cirrus_shadow_gr1;
e6e5ad80
FB
563 colors[1][1] = s->gr[0x11];
564 colors[1][2] = s->gr[0x13];
565 colors[1][3] = s->gr[0x15];
566
567 bitmask = 0x80 << srcskipleft;
568 bits = *src++;
569 for (x = 0; x < count; x++) {
570 if ((bitmask & 0xff) == 0) {
571 bitmask = 0x80;
572 bits = *src++;
573 }
574 index = !!(bits & bitmask);
575 *dst++ = colors[index][0];
576 *dst++ = colors[index][1];
577 *dst++ = colors[index][2];
578 *dst++ = colors[index][3];
579 bitmask >>= 1;
580 }
581}
582
583static void
584cirrus_colorexpand(CirrusVGAState * s, uint8_t * dst, const uint8_t * src,
585 int count)
586{
587 switch (s->cirrus_blt_pixelwidth) {
588 case 1:
589 cirrus_colorexpand_8(s, dst, src, count);
590 break;
591 case 2:
592 cirrus_colorexpand_16(s, dst, src, count);
593 break;
594 case 3:
595 cirrus_colorexpand_24(s, dst, src, count);
596 break;
597 case 4:
598 cirrus_colorexpand_32(s, dst, src, count);
599 break;
600 default:
601#ifdef DEBUG_CIRRUS
602 printf("cirrus: COLOREXPAND pixelwidth %d - unimplemented\n",
603 s->cirrus_blt_pixelwidth);
604#endif
605 break;
606 }
607}
608
609static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
610 int off_pitch, int bytesperline,
611 int lines)
612{
613 int y;
614 int off_cur;
615 int off_cur_end;
616
617 for (y = 0; y < lines; y++) {
618 off_cur = off_begin;
619 off_cur_end = off_cur + bytesperline;
620 off_cur &= TARGET_PAGE_MASK;
621 while (off_cur < off_cur_end) {
622 cpu_physical_memory_set_dirty(s->vram_offset + off_cur);
623 off_cur += TARGET_PAGE_SIZE;
624 }
625 off_begin += off_pitch;
626 }
627}
628
629
630
631static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
632 const uint8_t * src)
633{
634 uint8_t work_colorexp[256];
635 uint8_t *dst;
636 uint8_t *dstc;
637 int x, y;
638 int tilewidth, tileheight;
639 int patternbytes = s->cirrus_blt_pixelwidth * 8;
640
641 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
642 cirrus_colorexpand(s, work_colorexp, src, 8 * 8);
643 src = work_colorexp;
644 s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_COLOREXPAND;
645 }
646 if (s->cirrus_blt_mode & ~CIRRUS_BLTMODE_PATTERNCOPY) {
647#ifdef DEBUG_CIRRUS
648 printf("cirrus: blt mode %02x (pattercopy) - unimplemented\n",
649 s->cirrus_blt_mode);
650#endif
651 return 0;
652 }
a21ae81d 653
e6e5ad80
FB
654 dst = s->vram_ptr + s->cirrus_blt_dstaddr;
655 for (y = 0; y < s->cirrus_blt_height; y += 8) {
656 dstc = dst;
657 tileheight = qemu_MIN(8, s->cirrus_blt_height - y);
658 for (x = 0; x < s->cirrus_blt_width; x += patternbytes) {
659 tilewidth = qemu_MIN(patternbytes, s->cirrus_blt_width - x);
660 (*s->cirrus_rop) (dstc, src,
661 s->cirrus_blt_dstpitch, patternbytes,
662 tilewidth, tileheight);
663 dstc += patternbytes;
664 }
665 dst += s->cirrus_blt_dstpitch * 8;
666 }
667 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
668 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
669 s->cirrus_blt_height);
670 return 1;
671}
672
a21ae81d
FB
673/* fill */
674
675static void cirrus_fill_8(CirrusVGAState *s,
676 uint8_t *dst, int dst_pitch, int width, int height)
677{
678 uint8_t *d, *d1;
679 uint32_t val;
680 int x, y;
681
682 val = s->cirrus_shadow_gr1;
683
684 d1 = dst;
685 for(y = 0; y < height; y++) {
686 d = d1;
687 for(x = 0; x < width; x++) {
688 *d++ = val;
689 }
690 d1 += dst_pitch;
691 }
692}
693
694static void cirrus_fill_16(CirrusVGAState *s,
695 uint8_t *dst, int dst_pitch, int width, int height)
696{
697 uint8_t *d, *d1;
698 uint32_t val;
699 int x, y;
700
701 val = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8);
702 val = le16_to_cpu(val);
703 width >>= 1;
704
705 d1 = dst;
706 for(y = 0; y < height; y++) {
707 d = d1;
708 for(x = 0; x < width; x++) {
709 ((uint16_t *)d)[0] = val;
710 d += 2;
711 }
712 d1 += dst_pitch;
713 }
714}
715
716static void cirrus_fill_24(CirrusVGAState *s,
717 uint8_t *dst, int dst_pitch, int width, int height)
718{
719 uint8_t *d, *d1;
720 int x, y;
721
722 d1 = dst;
723 for(y = 0; y < height; y++) {
724 d = d1;
725 for(x = 0; x < width; x += 3) {
726 *d++ = s->cirrus_shadow_gr1;
727 *d++ = s->gr[0x11];
728 *d++ = s->gr[0x13];
729 }
730 d1 += dst_pitch;
731 }
732}
733
734static void cirrus_fill_32(CirrusVGAState *s,
735 uint8_t *dst, int dst_pitch, int width, int height)
736{
737 uint8_t *d, *d1;
738 uint32_t val;
739 int x, y;
740
741 val = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8) |
742 (s->gr[0x13] << 8) | (s->gr[0x15] << 8);
743 val = le32_to_cpu(val);
744 width >>= 2;
745
746 d1 = dst;
747 for(y = 0; y < height; y++) {
748 d = d1;
749 for(x = 0; x < width; x++) {
750 ((uint32_t *)d)[0] = val;
751 d += 4;
752 }
753 d1 += dst_pitch;
754 }
755}
756
757static int cirrus_bitblt_solidfill(CirrusVGAState *s)
758{
759 uint8_t *dst;
760 dst = s->vram_ptr + s->cirrus_blt_dstaddr;
761 switch (s->cirrus_blt_pixelwidth) {
762 case 1:
763 cirrus_fill_8(s, dst, s->cirrus_blt_dstpitch,
764 s->cirrus_blt_width, s->cirrus_blt_height);
765 break;
766 case 2:
767 cirrus_fill_16(s, dst, s->cirrus_blt_dstpitch,
768 s->cirrus_blt_width, s->cirrus_blt_height);
769 break;
770 case 3:
771 cirrus_fill_24(s, dst, s->cirrus_blt_dstpitch,
772 s->cirrus_blt_width, s->cirrus_blt_height);
773 break;
774 default:
775 case 4:
776 cirrus_fill_32(s, dst, s->cirrus_blt_dstpitch,
777 s->cirrus_blt_width, s->cirrus_blt_height);
778 break;
779 }
780 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
781 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
782 s->cirrus_blt_height);
783 cirrus_bitblt_reset(s);
784 return 1;
785}
786
e6e5ad80
FB
787/***************************************
788 *
789 * bitblt (video-to-video)
790 *
791 ***************************************/
792
793static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
794{
795 return cirrus_bitblt_common_patterncopy(s,
796 s->vram_ptr +
797 s->cirrus_blt_srcaddr);
798}
799
800static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
801{
802 if ((s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) != 0) {
803#ifdef DEBUG_CIRRUS
804 printf("cirrus: CIRRUS_BLTMODE_COLOREXPAND - unimplemented\n");
805#endif
806 return 0;
807 }
808 if ((s->cirrus_blt_mode & (~CIRRUS_BLTMODE_BACKWARDS)) != 0) {
809#ifdef DEBUG_CIRRUS
810 printf("cirrus: blt mode %02x - unimplemented\n",
811 s->cirrus_blt_mode);
812#endif
813 return 0;
814 }
815
816 (*s->cirrus_rop) (s->vram_ptr + s->cirrus_blt_dstaddr,
817 s->vram_ptr + s->cirrus_blt_srcaddr,
818 s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
819 s->cirrus_blt_width, s->cirrus_blt_height);
820 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
821 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
822 s->cirrus_blt_height);
823 return 1;
824}
825
826/***************************************
827 *
828 * bitblt (cpu-to-video)
829 *
830 ***************************************/
831
832static void cirrus_bitblt_cputovideo_patterncopy(void *opaque)
833{
834 CirrusVGAState *s = (CirrusVGAState *) opaque;
835 int data_count;
836
837 data_count = s->cirrus_srcptr - &s->cirrus_bltbuf[0];
838
839 if (data_count > 0) {
840 if (data_count != s->cirrus_srccounter) {
841#ifdef DEBUG_CIRRUS
842 printf("cirrus: internal error\n");
843#endif
844 } else {
845 cirrus_bitblt_common_patterncopy(s, &s->cirrus_bltbuf[0]);
846 }
847 cirrus_bitblt_reset(s);
848 }
849}
850
851static void cirrus_bitblt_cputovideo_copy(void *opaque)
852{
853 CirrusVGAState *s = (CirrusVGAState *) opaque;
854 int data_count;
855 int data_avail;
856 uint8_t work_colorexp[256];
857 uint8_t *src_ptr = NULL;
858 int src_avail = 0;
859 int src_processing;
860 int src_linepad = 0;
861
862 if (s->cirrus_blt_height <= 0) {
863 s->cirrus_srcptr = s->cirrus_srcptr_end;
864 return;
865 }
866
867 s->cirrus_srcptr = &s->cirrus_bltbuf[0];
868 while (1) {
869 /* get BLT source. */
870 if (src_avail <= 0) {
871 data_count = s->cirrus_srcptr_end - s->cirrus_srcptr;
872 if (data_count <= 0)
873 break;
874
875 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
876 if (s->cirrus_blt_mode & ~CIRRUS_BLTMODE_COLOREXPAND) {
877#ifdef DEBUG_CIRRUS
878 printf("cirrus: unsupported\n");
879#endif
880 cirrus_bitblt_reset(s);
881 return;
882 }
883 data_avail = qemu_MIN(data_count, 256 / 32);
884 cirrus_colorexpand(s, work_colorexp, s->cirrus_srcptr,
885 data_avail * 8);
886 src_ptr = &work_colorexp[0];
887 src_avail = data_avail * 8 * s->cirrus_blt_pixelwidth;
888 s->cirrus_srcptr += data_avail;
889 src_linepad =
890 ((s->cirrus_blt_width + 7) / 8) * 8 -
891 s->cirrus_blt_width;
892 src_linepad *= s->cirrus_blt_pixelwidth;
893 } else {
894 if (s->cirrus_blt_mode != 0) {
895#ifdef DEBUG_CIRRUS
896 printf("cirrus: unsupported\n");
897#endif
898 cirrus_bitblt_reset(s);
899 return;
900 }
901 src_ptr = s->cirrus_srcptr;
902 src_avail =
903 data_count / s->cirrus_blt_pixelwidth *
904 s->cirrus_blt_pixelwidth;
905 s->cirrus_srcptr += src_avail;
906 }
907 if (src_avail <= 0)
908 break;
909 }
910
911 /* 1-line BLT */
912 src_processing =
913 s->cirrus_blt_srcpitch - s->cirrus_blt_horz_counter;
914 src_processing = qemu_MIN(src_avail, src_processing);
915 (*s->cirrus_rop) (s->vram_ptr + s->cirrus_blt_dstaddr,
916 src_ptr, 0, 0, src_processing, 1);
917 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
918 src_processing, 1);
919
920 s->cirrus_blt_dstaddr += src_processing;
921 src_ptr += src_processing;
922 src_avail -= src_processing;
923 s->cirrus_blt_horz_counter += src_processing;
924 if (s->cirrus_blt_horz_counter >= s->cirrus_blt_srcpitch) {
925 src_ptr += src_linepad;
926 src_avail -= src_linepad;
927 s->cirrus_blt_dstaddr +=
928 s->cirrus_blt_dstpitch - s->cirrus_blt_srcpitch;
929 s->cirrus_blt_horz_counter = 0;
930 s->cirrus_blt_height--;
931 if (s->cirrus_blt_height <= 0) {
932 s->cirrus_srcptr = s->cirrus_srcptr_end;
933 return;
934 }
935 }
936 }
937}
938
939static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
940{
941 int copy_count;
942 int avail_count;
943
944 s->cirrus_blt_handler(s);
945
946 if (s->cirrus_srccounter > 0) {
947 s->cirrus_srccounter -= s->cirrus_srcptr - &s->cirrus_bltbuf[0];
948 copy_count = s->cirrus_srcptr_end - s->cirrus_srcptr;
949 memmove(&s->cirrus_bltbuf[0], s->cirrus_srcptr, copy_count);
950 avail_count = qemu_MIN(CIRRUS_BLTBUFSIZE, s->cirrus_srccounter);
951 s->cirrus_srcptr = &s->cirrus_bltbuf[0];
952 s->cirrus_srcptr_end = s->cirrus_srcptr + avail_count;
953 if (s->cirrus_srccounter <= 0) {
954 cirrus_bitblt_reset(s);
955 }
956 }
957}
958
959/***************************************
960 *
961 * bitblt wrapper
962 *
963 ***************************************/
964
965static void cirrus_bitblt_reset(CirrusVGAState * s)
966{
967 s->gr[0x31] &=
968 ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED);
969 s->cirrus_srcptr = &s->cirrus_bltbuf[0];
970 s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
971 s->cirrus_srccounter = 0;
972 s->cirrus_dstptr = &s->cirrus_bltbuf[0];
973 s->cirrus_dstptr_end = &s->cirrus_bltbuf[0];
974 s->cirrus_dstcounter = 0;
975 s->cirrus_blt_handler = NULL;
976}
977
978static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
979{
980 s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
981 s->cirrus_srcptr = &s->cirrus_bltbuf[0];
982 s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
983
984 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
985 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
986 s->cirrus_srccounter = 8;
987 } else {
988 s->cirrus_srccounter = 8 * 8 * s->cirrus_blt_pixelwidth;
989 }
990 s->cirrus_blt_srcpitch = 0;
991 s->cirrus_blt_handler = cirrus_bitblt_cputovideo_patterncopy;
992 } else {
993 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
994 s->cirrus_srccounter =
995 ((s->cirrus_blt_width + 7) / 8) * s->cirrus_blt_height;
996 s->cirrus_blt_srcpitch =
997 s->cirrus_blt_width * s->cirrus_blt_pixelwidth;
998 } else {
999 s->cirrus_srccounter =
1000 s->cirrus_blt_width * s->cirrus_blt_height;
1001 s->cirrus_blt_srcpitch = s->cirrus_blt_width;
1002 }
1003 /* 4-byte alignment */
1004 s->cirrus_srccounter = (s->cirrus_srccounter + 3) & (~3);
1005
1006 s->cirrus_blt_handler = cirrus_bitblt_cputovideo_copy;
1007 s->cirrus_blt_horz_counter = 0;
1008 }
1009
1010 cirrus_bitblt_cputovideo_next(s);
1011 return 1;
1012}
1013
1014static int cirrus_bitblt_videotocpu(CirrusVGAState * s)
1015{
1016 /* XXX */
1017#ifdef DEBUG_CIRRUS
1018 printf("cirrus: bitblt (video to cpu) is not implemented yet\n");
1019#endif
1020 return 0;
1021}
1022
1023static int cirrus_bitblt_videotovideo(CirrusVGAState * s)
1024{
1025 int ret;
1026
1027 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
1028 ret = cirrus_bitblt_videotovideo_patterncopy(s);
1029 } else {
1030 ret = cirrus_bitblt_videotovideo_copy(s);
1031 }
1032
1033 if (ret)
1034 cirrus_bitblt_reset(s);
1035 return ret;
1036}
1037
1038static void cirrus_bitblt_start(CirrusVGAState * s)
1039{
1040 uint8_t blt_rop;
1041
1042 s->cirrus_blt_width = (s->gr[0x20] | (s->gr[0x21] << 8)) + 1;
1043 s->cirrus_blt_height = (s->gr[0x22] | (s->gr[0x23] << 8)) + 1;
1044 s->cirrus_blt_dstpitch = (s->gr[0x24] | (s->gr[0x25] << 8));
1045 s->cirrus_blt_srcpitch = (s->gr[0x26] | (s->gr[0x27] << 8));
1046 s->cirrus_blt_dstaddr =
1047 (s->gr[0x28] | (s->gr[0x29] << 8) | (s->gr[0x2a] << 16));
1048 s->cirrus_blt_srcaddr =
1049 (s->gr[0x2c] | (s->gr[0x2d] << 8) | (s->gr[0x2e] << 16));
1050 s->cirrus_blt_mode = s->gr[0x30];
1051 blt_rop = s->gr[0x32];
1052
a21ae81d
FB
1053#ifdef DEBUG_BITBLT
1054 printf("rop=%02x mode=%02x modeext=%02x w=%d h=%d dpitch=%d spicth=%d daddr=%08x saddr=%08x\n",
1055 blt_rop,
1056 s->cirrus_blt_mode,
1057 s->gr[0x33],
1058 s->cirrus_blt_width,
1059 s->cirrus_blt_height,
1060 s->cirrus_blt_dstpitch,
1061 s->cirrus_blt_srcpitch,
1062 s->cirrus_blt_dstaddr,
1063 s->cirrus_blt_srcaddr);
1064#endif
1065
e6e5ad80
FB
1066 switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
1067 case CIRRUS_BLTMODE_PIXELWIDTH8:
1068 s->cirrus_blt_pixelwidth = 1;
1069 break;
1070 case CIRRUS_BLTMODE_PIXELWIDTH16:
1071 s->cirrus_blt_pixelwidth = 2;
1072 break;
1073 case CIRRUS_BLTMODE_PIXELWIDTH24:
1074 s->cirrus_blt_pixelwidth = 3;
1075 break;
1076 case CIRRUS_BLTMODE_PIXELWIDTH32:
1077 s->cirrus_blt_pixelwidth = 4;
1078 break;
1079 default:
1080#ifdef DEBUG_CIRRUS
1081 printf("cirrus: bitblt - pixel width is unknown\n");
1082#endif
1083 goto bitblt_ignore;
1084 }
1085 s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK;
1086
1087 if ((s->
1088 cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC |
1089 CIRRUS_BLTMODE_MEMSYSDEST))
1090 == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) {
1091#ifdef DEBUG_CIRRUS
1092 printf("cirrus: bitblt - memory-to-memory copy is requested\n");
1093#endif
1094 goto bitblt_ignore;
1095 }
1096
a21ae81d
FB
1097 if ((s->gr[0x33] & CIRRUS_BLTMODEEXT_SOLIDFILL) &&
1098 (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST |
1099 CIRRUS_BLTMODE_TRANSPARENTCOMP |
1100 CIRRUS_BLTMODE_PATTERNCOPY |
1101 CIRRUS_BLTMODE_COLOREXPAND)) ==
1102 (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) {
1103 cirrus_bitblt_solidfill(s);
e6e5ad80 1104 } else {
a21ae81d
FB
1105 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
1106 s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
1107 s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
1108 s->cirrus_rop = cirrus_get_bkwd_rop_handler(blt_rop);
1109 } else {
1110 s->cirrus_rop = cirrus_get_fwd_rop_handler(blt_rop);
1111 }
1112
1113 // setup bitblt engine.
1114 if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) {
1115 if (!cirrus_bitblt_cputovideo(s))
1116 goto bitblt_ignore;
1117 } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) {
1118 if (!cirrus_bitblt_videotocpu(s))
1119 goto bitblt_ignore;
1120 } else {
1121 if (!cirrus_bitblt_videotovideo(s))
1122 goto bitblt_ignore;
1123 }
e6e5ad80 1124 }
e6e5ad80
FB
1125 return;
1126 bitblt_ignore:;
1127 cirrus_bitblt_reset(s);
1128}
1129
1130static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value)
1131{
1132 unsigned old_value;
1133
1134 old_value = s->gr[0x31];
1135 s->gr[0x31] = reg_value;
1136
1137 if (((old_value & CIRRUS_BLT_RESET) != 0) &&
1138 ((reg_value & CIRRUS_BLT_RESET) == 0)) {
1139 cirrus_bitblt_reset(s);
1140 } else if (((old_value & CIRRUS_BLT_START) == 0) &&
1141 ((reg_value & CIRRUS_BLT_START) != 0)) {
1142 s->gr[0x31] |= CIRRUS_BLT_BUSY;
1143 cirrus_bitblt_start(s);
1144 }
1145}
1146
1147
1148/***************************************
1149 *
1150 * basic parameters
1151 *
1152 ***************************************/
1153
1154static void cirrus_get_offsets(VGAState *s1,
1155 uint32_t *pline_offset,
1156 uint32_t *pstart_addr)
1157{
1158 CirrusVGAState * s = (CirrusVGAState *)s1;
1159 uint32_t start_addr;
1160 uint32_t line_offset;
1161
1162 line_offset = s->cr[0x13]
e36f36e1 1163 | ((s->cr[0x1b] & 0x10) << 4);
e6e5ad80
FB
1164 line_offset <<= 3;
1165 *pline_offset = line_offset;
1166
1167 start_addr = (s->cr[0x0c] << 8)
1168 | s->cr[0x0d]
1169 | ((s->cr[0x1b] & 0x01) << 16)
1170 | ((s->cr[0x1b] & 0x0c) << 15)
1171 | ((s->cr[0x1d] & 0x80) << 12);
1172 *pstart_addr = start_addr;
1173}
1174
1175static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
1176{
1177 uint32_t ret = 16;
1178
1179 switch (s->cirrus_hidden_dac_data & 0xf) {
1180 case 0:
1181 ret = 15;
1182 break; /* Sierra HiColor */
1183 case 1:
1184 ret = 16;
1185 break; /* XGA HiColor */
1186 default:
1187#ifdef DEBUG_CIRRUS
1188 printf("cirrus: invalid DAC value %x in 16bpp\n",
1189 (s->cirrus_hidden_dac_data & 0xf));
1190#endif
1191 ret = 15; /* XXX */
1192 break;
1193 }
1194 return ret;
1195}
1196
1197static int cirrus_get_bpp(VGAState *s1)
1198{
1199 CirrusVGAState * s = (CirrusVGAState *)s1;
1200 uint32_t ret = 8;
1201
1202 if ((s->sr[0x07] & 0x01) != 0) {
1203 /* Cirrus SVGA */
1204 switch (s->sr[0x07] & CIRRUS_SR7_BPP_MASK) {
1205 case CIRRUS_SR7_BPP_8:
1206 ret = 8;
1207 break;
1208 case CIRRUS_SR7_BPP_16_DOUBLEVCLK:
1209 ret = cirrus_get_bpp16_depth(s);
1210 break;
1211 case CIRRUS_SR7_BPP_24:
1212 ret = 24;
1213 break;
1214 case CIRRUS_SR7_BPP_16:
1215 ret = cirrus_get_bpp16_depth(s);
1216 break;
1217 case CIRRUS_SR7_BPP_32:
1218 ret = 32;
1219 break;
1220 default:
1221#ifdef DEBUG_CIRRUS
1222 printf("cirrus: unknown bpp - sr7=%x\n", s->sr[0x7]);
1223#endif
1224 ret = 8;
1225 break;
1226 }
1227 } else {
1228 /* VGA */
aeb3c85f 1229 ret = 0;
e6e5ad80
FB
1230 }
1231
1232 return ret;
1233}
1234
1235/***************************************
1236 *
1237 * bank memory
1238 *
1239 ***************************************/
1240
1241static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
1242{
1243 unsigned offset;
1244 unsigned limit;
1245
1246 if ((s->gr[0x0b] & 0x01) != 0) /* dual bank */
1247 offset = s->gr[0x09 + bank_index];
1248 else /* single bank */
1249 offset = s->gr[0x09];
1250
1251 if ((s->gr[0x0b] & 0x20) != 0)
1252 offset <<= 14;
1253 else
1254 offset <<= 12;
1255
1256 if (s->vram_size <= offset)
1257 limit = 0;
1258 else
1259 limit = s->vram_size - offset;
1260
1261 if (((s->gr[0x0b] & 0x01) == 0) && (bank_index != 0)) {
1262 if (limit > 0x8000) {
1263 offset += 0x8000;
1264 limit -= 0x8000;
1265 } else {
1266 limit = 0;
1267 }
1268 }
1269
1270 if (limit > 0) {
1271 s->cirrus_bank_base[bank_index] = offset;
1272 s->cirrus_bank_limit[bank_index] = limit;
1273 } else {
1274 s->cirrus_bank_base[bank_index] = 0;
1275 s->cirrus_bank_limit[bank_index] = 0;
1276 }
1277}
1278
1279/***************************************
1280 *
1281 * I/O access between 0x3c4-0x3c5
1282 *
1283 ***************************************/
1284
1285static int
1286cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
1287{
1288 switch (reg_index) {
1289 case 0x00: // Standard VGA
1290 case 0x01: // Standard VGA
1291 case 0x02: // Standard VGA
1292 case 0x03: // Standard VGA
1293 case 0x04: // Standard VGA
1294 return CIRRUS_HOOK_NOT_HANDLED;
1295 case 0x06: // Unlock Cirrus extensions
1296 *reg_value = s->sr[reg_index];
1297 break;
e6e5ad80
FB
1298 case 0x10:
1299 case 0x30:
1300 case 0x50:
1301 case 0x70: // Graphics Cursor X
1302 case 0x90:
1303 case 0xb0:
1304 case 0xd0:
1305 case 0xf0: // Graphics Cursor X
aeb3c85f
FB
1306 *reg_value = s->sr[0x10];
1307 break;
e6e5ad80
FB
1308 case 0x11:
1309 case 0x31:
1310 case 0x51:
1311 case 0x71: // Graphics Cursor Y
1312 case 0x91:
1313 case 0xb1:
1314 case 0xd1:
aeb3c85f
FB
1315 *reg_value = s->sr[0x11];
1316 break;
1317 case 0x05: // ???
1318 case 0x07: // Extended Sequencer Mode
1319 case 0x08: // EEPROM Control
1320 case 0x09: // Scratch Register 0
1321 case 0x0a: // Scratch Register 1
1322 case 0x0b: // VCLK 0
1323 case 0x0c: // VCLK 1
1324 case 0x0d: // VCLK 2
1325 case 0x0e: // VCLK 3
1326 case 0x0f: // DRAM Control
e6e5ad80
FB
1327 case 0xf1: // Graphics Cursor Y
1328 case 0x12: // Graphics Cursor Attribute
1329 case 0x13: // Graphics Cursor Pattern Address
1330 case 0x14: // Scratch Register 2
1331 case 0x15: // Scratch Register 3
1332 case 0x16: // Performance Tuning Register
1333 case 0x17: // Configuration Readback and Extended Control
1334 case 0x18: // Signature Generator Control
1335 case 0x19: // Signal Generator Result
1336 case 0x1a: // Signal Generator Result
1337 case 0x1b: // VCLK 0 Denominator & Post
1338 case 0x1c: // VCLK 1 Denominator & Post
1339 case 0x1d: // VCLK 2 Denominator & Post
1340 case 0x1e: // VCLK 3 Denominator & Post
1341 case 0x1f: // BIOS Write Enable and MCLK select
1342#ifdef DEBUG_CIRRUS
1343 printf("cirrus: handled inport sr_index %02x\n", reg_index);
1344#endif
1345 *reg_value = s->sr[reg_index];
1346 break;
1347 default:
1348#ifdef DEBUG_CIRRUS
1349 printf("cirrus: inport sr_index %02x\n", reg_index);
1350#endif
1351 *reg_value = 0xff;
1352 break;
1353 }
1354
1355 return CIRRUS_HOOK_HANDLED;
1356}
1357
1358static int
1359cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1360{
1361 switch (reg_index) {
1362 case 0x00: // Standard VGA
1363 case 0x01: // Standard VGA
1364 case 0x02: // Standard VGA
1365 case 0x03: // Standard VGA
1366 case 0x04: // Standard VGA
1367 return CIRRUS_HOOK_NOT_HANDLED;
1368 case 0x06: // Unlock Cirrus extensions
1369 reg_value &= 0x17;
1370 if (reg_value == 0x12) {
1371 s->sr[reg_index] = 0x12;
1372 } else {
1373 s->sr[reg_index] = 0x0f;
1374 }
1375 break;
1376 case 0x10:
1377 case 0x30:
1378 case 0x50:
1379 case 0x70: // Graphics Cursor X
1380 case 0x90:
1381 case 0xb0:
1382 case 0xd0:
1383 case 0xf0: // Graphics Cursor X
1384 s->sr[0x10] = reg_value;
1385 s->cirrus_hw_cursor_x = ((reg_index << 3) & 0x700) | reg_value;
1386 break;
1387 case 0x11:
1388 case 0x31:
1389 case 0x51:
1390 case 0x71: // Graphics Cursor Y
1391 case 0x91:
1392 case 0xb1:
1393 case 0xd1:
1394 case 0xf1: // Graphics Cursor Y
1395 s->sr[0x11] = reg_value;
1396 s->cirrus_hw_cursor_y = ((reg_index << 3) & 0x700) | reg_value;
1397 break;
1398 case 0x07: // Extended Sequencer Mode
1399 case 0x08: // EEPROM Control
1400 case 0x09: // Scratch Register 0
1401 case 0x0a: // Scratch Register 1
1402 case 0x0b: // VCLK 0
1403 case 0x0c: // VCLK 1
1404 case 0x0d: // VCLK 2
1405 case 0x0e: // VCLK 3
1406 case 0x0f: // DRAM Control
1407 case 0x12: // Graphics Cursor Attribute
1408 case 0x13: // Graphics Cursor Pattern Address
1409 case 0x14: // Scratch Register 2
1410 case 0x15: // Scratch Register 3
1411 case 0x16: // Performance Tuning Register
1412 case 0x17: // Configuration Readback and Extended Control
1413 case 0x18: // Signature Generator Control
1414 case 0x19: // Signature Generator Result
1415 case 0x1a: // Signature Generator Result
1416 case 0x1b: // VCLK 0 Denominator & Post
1417 case 0x1c: // VCLK 1 Denominator & Post
1418 case 0x1d: // VCLK 2 Denominator & Post
1419 case 0x1e: // VCLK 3 Denominator & Post
1420 case 0x1f: // BIOS Write Enable and MCLK select
1421 s->sr[reg_index] = reg_value;
1422#ifdef DEBUG_CIRRUS
1423 printf("cirrus: handled outport sr_index %02x, sr_value %02x\n",
1424 reg_index, reg_value);
1425#endif
1426 break;
1427 default:
1428#ifdef DEBUG_CIRRUS
1429 printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index,
1430 reg_value);
1431#endif
1432 break;
1433 }
1434
1435 return CIRRUS_HOOK_HANDLED;
1436}
1437
1438/***************************************
1439 *
1440 * I/O access at 0x3c6
1441 *
1442 ***************************************/
1443
1444static void cirrus_read_hidden_dac(CirrusVGAState * s, int *reg_value)
1445{
1446 *reg_value = 0xff;
a21ae81d
FB
1447 if (++s->cirrus_hidden_dac_lockindex == 5) {
1448 *reg_value = s->cirrus_hidden_dac_data;
1449 s->cirrus_hidden_dac_lockindex = 0;
e6e5ad80
FB
1450 }
1451}
1452
1453static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value)
1454{
1455 if (s->cirrus_hidden_dac_lockindex == 4) {
1456 s->cirrus_hidden_dac_data = reg_value;
a21ae81d 1457#if defined(DEBUG_CIRRUS)
e6e5ad80
FB
1458 printf("cirrus: outport hidden DAC, value %02x\n", reg_value);
1459#endif
1460 }
1461 s->cirrus_hidden_dac_lockindex = 0;
1462}
1463
1464/***************************************
1465 *
1466 * I/O access at 0x3c9
1467 *
1468 ***************************************/
1469
1470static int cirrus_hook_read_palette(CirrusVGAState * s, int *reg_value)
1471{
1472 if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL))
1473 return CIRRUS_HOOK_NOT_HANDLED;
1474 if (s->dac_read_index < 0x10) {
1475 *reg_value =
1476 s->cirrus_hidden_palette[s->dac_read_index * 3 +
1477 s->dac_sub_index];
1478 } else {
1479 *reg_value = 0xff; /* XXX */
1480 }
1481 if (++s->dac_sub_index == 3) {
1482 s->dac_sub_index = 0;
1483 s->dac_read_index++;
1484 }
1485 return CIRRUS_HOOK_HANDLED;
1486}
1487
1488static int cirrus_hook_write_palette(CirrusVGAState * s, int reg_value)
1489{
1490 if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL))
1491 return CIRRUS_HOOK_NOT_HANDLED;
1492 s->dac_cache[s->dac_sub_index] = reg_value;
1493 if (++s->dac_sub_index == 3) {
1494 if (s->dac_read_index < 0x10) {
1495 memcpy(&s->cirrus_hidden_palette[s->dac_write_index * 3],
1496 s->dac_cache, 3);
1497 /* XXX update cursor */
1498 }
1499 s->dac_sub_index = 0;
1500 s->dac_write_index++;
1501 }
1502 return CIRRUS_HOOK_HANDLED;
1503}
1504
1505/***************************************
1506 *
1507 * I/O access between 0x3ce-0x3cf
1508 *
1509 ***************************************/
1510
1511static int
1512cirrus_hook_read_gr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
1513{
1514 switch (reg_index) {
aeb3c85f
FB
1515 case 0x00: // Standard VGA, BGCOLOR 0x000000ff
1516 *reg_value = s->cirrus_shadow_gr0;
1517 return CIRRUS_HOOK_HANDLED;
1518 case 0x01: // Standard VGA, FGCOLOR 0x000000ff
1519 *reg_value = s->cirrus_shadow_gr1;
1520 return CIRRUS_HOOK_HANDLED;
e6e5ad80
FB
1521 case 0x02: // Standard VGA
1522 case 0x03: // Standard VGA
1523 case 0x04: // Standard VGA
1524 case 0x06: // Standard VGA
1525 case 0x07: // Standard VGA
1526 case 0x08: // Standard VGA
1527 return CIRRUS_HOOK_NOT_HANDLED;
1528 case 0x05: // Standard VGA, Cirrus extended mode
1529 default:
1530 break;
1531 }
1532
1533 if (reg_index < 0x3a) {
1534 *reg_value = s->gr[reg_index];
1535 } else {
1536#ifdef DEBUG_CIRRUS
1537 printf("cirrus: inport gr_index %02x\n", reg_index);
1538#endif
1539 *reg_value = 0xff;
1540 }
1541
1542 return CIRRUS_HOOK_HANDLED;
1543}
1544
1545static int
1546cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1547{
1548 switch (reg_index) {
1549 case 0x00: // Standard VGA, BGCOLOR 0x000000ff
aeb3c85f 1550 s->cirrus_shadow_gr0 = reg_value;
e6e5ad80
FB
1551 return CIRRUS_HOOK_NOT_HANDLED;
1552 case 0x01: // Standard VGA, FGCOLOR 0x000000ff
aeb3c85f 1553 s->cirrus_shadow_gr1 = reg_value;
e6e5ad80
FB
1554 return CIRRUS_HOOK_NOT_HANDLED;
1555 case 0x02: // Standard VGA
1556 case 0x03: // Standard VGA
1557 case 0x04: // Standard VGA
1558 case 0x06: // Standard VGA
1559 case 0x07: // Standard VGA
1560 case 0x08: // Standard VGA
1561 return CIRRUS_HOOK_NOT_HANDLED;
1562 case 0x05: // Standard VGA, Cirrus extended mode
1563 s->gr[reg_index] = reg_value & 0x7f;
1564 break;
1565 case 0x09: // bank offset #0
1566 case 0x0A: // bank offset #1
1567 case 0x0B:
1568 s->gr[reg_index] = reg_value;
1569 cirrus_update_bank_ptr(s, 0);
1570 cirrus_update_bank_ptr(s, 1);
1571 break;
1572 case 0x10: // BGCOLOR 0x0000ff00
1573 case 0x11: // FGCOLOR 0x0000ff00
1574 case 0x12: // BGCOLOR 0x00ff0000
1575 case 0x13: // FGCOLOR 0x00ff0000
1576 case 0x14: // BGCOLOR 0xff000000
1577 case 0x15: // FGCOLOR 0xff000000
1578 case 0x20: // BLT WIDTH 0x0000ff
1579 case 0x22: // BLT HEIGHT 0x0000ff
1580 case 0x24: // BLT DEST PITCH 0x0000ff
1581 case 0x26: // BLT SRC PITCH 0x0000ff
1582 case 0x28: // BLT DEST ADDR 0x0000ff
1583 case 0x29: // BLT DEST ADDR 0x00ff00
1584 case 0x2c: // BLT SRC ADDR 0x0000ff
1585 case 0x2d: // BLT SRC ADDR 0x00ff00
1586 case 0x30: // BLT MODE
1587 case 0x32: // RASTER OP
a21ae81d 1588 case 0x33: // BLT MODEEXT
e6e5ad80
FB
1589 case 0x34: // BLT TRANSPARENT COLOR 0x00ff
1590 case 0x35: // BLT TRANSPARENT COLOR 0xff00
1591 case 0x38: // BLT TRANSPARENT COLOR MASK 0x00ff
1592 case 0x39: // BLT TRANSPARENT COLOR MASK 0xff00
1593 s->gr[reg_index] = reg_value;
1594 break;
1595 case 0x21: // BLT WIDTH 0x001f00
1596 case 0x23: // BLT HEIGHT 0x001f00
1597 case 0x25: // BLT DEST PITCH 0x001f00
1598 case 0x27: // BLT SRC PITCH 0x001f00
1599 s->gr[reg_index] = reg_value & 0x1f;
1600 break;
1601 case 0x2a: // BLT DEST ADDR 0x3f0000
1602 case 0x2e: // BLT SRC ADDR 0x3f0000
1603 s->gr[reg_index] = reg_value & 0x3f;
1604 break;
1605 case 0x31: // BLT STATUS/START
1606 cirrus_write_bitblt(s, reg_value);
1607 break;
1608 default:
1609#ifdef DEBUG_CIRRUS
1610 printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index,
1611 reg_value);
1612#endif
1613 break;
1614 }
1615
1616 return CIRRUS_HOOK_HANDLED;
1617}
1618
1619/***************************************
1620 *
1621 * I/O access between 0x3d4-0x3d5
1622 *
1623 ***************************************/
1624
1625static int
1626cirrus_hook_read_cr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
1627{
1628 switch (reg_index) {
1629 case 0x00: // Standard VGA
1630 case 0x01: // Standard VGA
1631 case 0x02: // Standard VGA
1632 case 0x03: // Standard VGA
1633 case 0x04: // Standard VGA
1634 case 0x05: // Standard VGA
1635 case 0x06: // Standard VGA
1636 case 0x07: // Standard VGA
1637 case 0x08: // Standard VGA
1638 case 0x09: // Standard VGA
1639 case 0x0a: // Standard VGA
1640 case 0x0b: // Standard VGA
1641 case 0x0c: // Standard VGA
1642 case 0x0d: // Standard VGA
1643 case 0x0e: // Standard VGA
1644 case 0x0f: // Standard VGA
1645 case 0x10: // Standard VGA
1646 case 0x11: // Standard VGA
1647 case 0x12: // Standard VGA
1648 case 0x13: // Standard VGA
1649 case 0x14: // Standard VGA
1650 case 0x15: // Standard VGA
1651 case 0x16: // Standard VGA
1652 case 0x17: // Standard VGA
1653 case 0x18: // Standard VGA
1654 return CIRRUS_HOOK_NOT_HANDLED;
1655 case 0x19: // Interlace End
1656 case 0x1a: // Miscellaneous Control
1657 case 0x1b: // Extended Display Control
1658 case 0x1c: // Sync Adjust and Genlock
1659 case 0x1d: // Overlay Extended Control
1660 case 0x22: // Graphics Data Latches Readback (R)
1661 case 0x24: // Attribute Controller Toggle Readback (R)
1662 case 0x25: // Part Status
1663 case 0x27: // Part ID (R)
1664 *reg_value = s->cr[reg_index];
1665 break;
1666 case 0x26: // Attribute Controller Index Readback (R)
1667 *reg_value = s->ar_index & 0x3f;
1668 break;
1669 default:
1670#ifdef DEBUG_CIRRUS
1671 printf("cirrus: inport cr_index %02x\n", reg_index);
1672 *reg_value = 0xff;
1673#endif
1674 break;
1675 }
1676
1677 return CIRRUS_HOOK_HANDLED;
1678}
1679
1680static int
1681cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1682{
1683 switch (reg_index) {
1684 case 0x00: // Standard VGA
1685 case 0x01: // Standard VGA
1686 case 0x02: // Standard VGA
1687 case 0x03: // Standard VGA
1688 case 0x04: // Standard VGA
1689 case 0x05: // Standard VGA
1690 case 0x06: // Standard VGA
1691 case 0x07: // Standard VGA
1692 case 0x08: // Standard VGA
1693 case 0x09: // Standard VGA
1694 case 0x0a: // Standard VGA
1695 case 0x0b: // Standard VGA
1696 case 0x0c: // Standard VGA
1697 case 0x0d: // Standard VGA
1698 case 0x0e: // Standard VGA
1699 case 0x0f: // Standard VGA
1700 case 0x10: // Standard VGA
1701 case 0x11: // Standard VGA
1702 case 0x12: // Standard VGA
1703 case 0x13: // Standard VGA
1704 case 0x14: // Standard VGA
1705 case 0x15: // Standard VGA
1706 case 0x16: // Standard VGA
1707 case 0x17: // Standard VGA
1708 case 0x18: // Standard VGA
1709 return CIRRUS_HOOK_NOT_HANDLED;
1710 case 0x19: // Interlace End
1711 case 0x1a: // Miscellaneous Control
1712 case 0x1b: // Extended Display Control
1713 case 0x1c: // Sync Adjust and Genlock
1714 s->cr[reg_index] = reg_value;
1715#ifdef DEBUG_CIRRUS
1716 printf("cirrus: handled outport cr_index %02x, cr_value %02x\n",
1717 reg_index, reg_value);
1718#endif
1719 break;
1720 case 0x22: // Graphics Data Latches Readback (R)
1721 case 0x24: // Attribute Controller Toggle Readback (R)
1722 case 0x26: // Attribute Controller Index Readback (R)
1723 case 0x27: // Part ID (R)
1724 break;
1725 case 0x1d: // Overlay Extended Control
1726 case 0x25: // Part Status
1727 default:
1728#ifdef DEBUG_CIRRUS
1729 printf("cirrus: outport cr_index %02x, cr_value %02x\n", reg_index,
1730 reg_value);
1731#endif
1732 break;
1733 }
1734
1735 return CIRRUS_HOOK_HANDLED;
1736}
1737
1738/***************************************
1739 *
1740 * memory-mapped I/O (bitblt)
1741 *
1742 ***************************************/
1743
1744static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
1745{
1746 int value = 0xff;
1747
1748 switch (address) {
1749 case (CIRRUS_MMIO_BLTBGCOLOR + 0):
1750 cirrus_hook_read_gr(s, 0x00, &value);
1751 break;
1752 case (CIRRUS_MMIO_BLTBGCOLOR + 1):
1753 cirrus_hook_read_gr(s, 0x10, &value);
1754 break;
1755 case (CIRRUS_MMIO_BLTBGCOLOR + 2):
1756 cirrus_hook_read_gr(s, 0x12, &value);
1757 break;
1758 case (CIRRUS_MMIO_BLTBGCOLOR + 3):
1759 cirrus_hook_read_gr(s, 0x14, &value);
1760 break;
1761 case (CIRRUS_MMIO_BLTFGCOLOR + 0):
1762 cirrus_hook_read_gr(s, 0x01, &value);
1763 break;
1764 case (CIRRUS_MMIO_BLTFGCOLOR + 1):
1765 cirrus_hook_read_gr(s, 0x11, &value);
1766 break;
1767 case (CIRRUS_MMIO_BLTFGCOLOR + 2):
1768 cirrus_hook_read_gr(s, 0x13, &value);
1769 break;
1770 case (CIRRUS_MMIO_BLTFGCOLOR + 3):
1771 cirrus_hook_read_gr(s, 0x15, &value);
1772 break;
1773 case (CIRRUS_MMIO_BLTWIDTH + 0):
1774 cirrus_hook_read_gr(s, 0x20, &value);
1775 break;
1776 case (CIRRUS_MMIO_BLTWIDTH + 1):
1777 cirrus_hook_read_gr(s, 0x21, &value);
1778 break;
1779 case (CIRRUS_MMIO_BLTHEIGHT + 0):
1780 cirrus_hook_read_gr(s, 0x22, &value);
1781 break;
1782 case (CIRRUS_MMIO_BLTHEIGHT + 1):
1783 cirrus_hook_read_gr(s, 0x23, &value);
1784 break;
1785 case (CIRRUS_MMIO_BLTDESTPITCH + 0):
1786 cirrus_hook_read_gr(s, 0x24, &value);
1787 break;
1788 case (CIRRUS_MMIO_BLTDESTPITCH + 1):
1789 cirrus_hook_read_gr(s, 0x25, &value);
1790 break;
1791 case (CIRRUS_MMIO_BLTSRCPITCH + 0):
1792 cirrus_hook_read_gr(s, 0x26, &value);
1793 break;
1794 case (CIRRUS_MMIO_BLTSRCPITCH + 1):
1795 cirrus_hook_read_gr(s, 0x27, &value);
1796 break;
1797 case (CIRRUS_MMIO_BLTDESTADDR + 0):
1798 cirrus_hook_read_gr(s, 0x28, &value);
1799 break;
1800 case (CIRRUS_MMIO_BLTDESTADDR + 1):
1801 cirrus_hook_read_gr(s, 0x29, &value);
1802 break;
1803 case (CIRRUS_MMIO_BLTDESTADDR + 2):
1804 cirrus_hook_read_gr(s, 0x2a, &value);
1805 break;
1806 case (CIRRUS_MMIO_BLTSRCADDR + 0):
1807 cirrus_hook_read_gr(s, 0x2c, &value);
1808 break;
1809 case (CIRRUS_MMIO_BLTSRCADDR + 1):
1810 cirrus_hook_read_gr(s, 0x2d, &value);
1811 break;
1812 case (CIRRUS_MMIO_BLTSRCADDR + 2):
1813 cirrus_hook_read_gr(s, 0x2e, &value);
1814 break;
1815 case CIRRUS_MMIO_BLTWRITEMASK:
1816 cirrus_hook_read_gr(s, 0x2f, &value);
1817 break;
1818 case CIRRUS_MMIO_BLTMODE:
1819 cirrus_hook_read_gr(s, 0x30, &value);
1820 break;
1821 case CIRRUS_MMIO_BLTROP:
1822 cirrus_hook_read_gr(s, 0x32, &value);
1823 break;
a21ae81d
FB
1824 case CIRRUS_MMIO_BLTMODEEXT:
1825 cirrus_hook_read_gr(s, 0x33, &value);
1826 break;
e6e5ad80
FB
1827 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
1828 cirrus_hook_read_gr(s, 0x34, &value);
1829 break;
1830 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
1831 cirrus_hook_read_gr(s, 0x35, &value);
1832 break;
1833 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
1834 cirrus_hook_read_gr(s, 0x38, &value);
1835 break;
1836 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
1837 cirrus_hook_read_gr(s, 0x39, &value);
1838 break;
1839 case CIRRUS_MMIO_BLTSTATUS:
1840 cirrus_hook_read_gr(s, 0x31, &value);
1841 break;
1842 default:
1843#ifdef DEBUG_CIRRUS
1844 printf("cirrus: mmio read - address 0x%04x\n", address);
1845#endif
1846 break;
1847 }
1848
1849 return (uint8_t) value;
1850}
1851
1852static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
1853 uint8_t value)
1854{
1855 switch (address) {
1856 case (CIRRUS_MMIO_BLTBGCOLOR + 0):
1857 cirrus_hook_write_gr(s, 0x00, value);
1858 break;
1859 case (CIRRUS_MMIO_BLTBGCOLOR + 1):
1860 cirrus_hook_write_gr(s, 0x10, value);
1861 break;
1862 case (CIRRUS_MMIO_BLTBGCOLOR + 2):
1863 cirrus_hook_write_gr(s, 0x12, value);
1864 break;
1865 case (CIRRUS_MMIO_BLTBGCOLOR + 3):
1866 cirrus_hook_write_gr(s, 0x14, value);
1867 break;
1868 case (CIRRUS_MMIO_BLTFGCOLOR + 0):
1869 cirrus_hook_write_gr(s, 0x01, value);
1870 break;
1871 case (CIRRUS_MMIO_BLTFGCOLOR + 1):
1872 cirrus_hook_write_gr(s, 0x11, value);
1873 break;
1874 case (CIRRUS_MMIO_BLTFGCOLOR + 2):
1875 cirrus_hook_write_gr(s, 0x13, value);
1876 break;
1877 case (CIRRUS_MMIO_BLTFGCOLOR + 3):
1878 cirrus_hook_write_gr(s, 0x15, value);
1879 break;
1880 case (CIRRUS_MMIO_BLTWIDTH + 0):
1881 cirrus_hook_write_gr(s, 0x20, value);
1882 break;
1883 case (CIRRUS_MMIO_BLTWIDTH + 1):
1884 cirrus_hook_write_gr(s, 0x21, value);
1885 break;
1886 case (CIRRUS_MMIO_BLTHEIGHT + 0):
1887 cirrus_hook_write_gr(s, 0x22, value);
1888 break;
1889 case (CIRRUS_MMIO_BLTHEIGHT + 1):
1890 cirrus_hook_write_gr(s, 0x23, value);
1891 break;
1892 case (CIRRUS_MMIO_BLTDESTPITCH + 0):
1893 cirrus_hook_write_gr(s, 0x24, value);
1894 break;
1895 case (CIRRUS_MMIO_BLTDESTPITCH + 1):
1896 cirrus_hook_write_gr(s, 0x25, value);
1897 break;
1898 case (CIRRUS_MMIO_BLTSRCPITCH + 0):
1899 cirrus_hook_write_gr(s, 0x26, value);
1900 break;
1901 case (CIRRUS_MMIO_BLTSRCPITCH + 1):
1902 cirrus_hook_write_gr(s, 0x27, value);
1903 break;
1904 case (CIRRUS_MMIO_BLTDESTADDR + 0):
1905 cirrus_hook_write_gr(s, 0x28, value);
1906 break;
1907 case (CIRRUS_MMIO_BLTDESTADDR + 1):
1908 cirrus_hook_write_gr(s, 0x29, value);
1909 break;
1910 case (CIRRUS_MMIO_BLTDESTADDR + 2):
1911 cirrus_hook_write_gr(s, 0x2a, value);
1912 break;
1913 case (CIRRUS_MMIO_BLTDESTADDR + 3):
1914 /* ignored */
1915 break;
1916 case (CIRRUS_MMIO_BLTSRCADDR + 0):
1917 cirrus_hook_write_gr(s, 0x2c, value);
1918 break;
1919 case (CIRRUS_MMIO_BLTSRCADDR + 1):
1920 cirrus_hook_write_gr(s, 0x2d, value);
1921 break;
1922 case (CIRRUS_MMIO_BLTSRCADDR + 2):
1923 cirrus_hook_write_gr(s, 0x2e, value);
1924 break;
1925 case CIRRUS_MMIO_BLTWRITEMASK:
1926 cirrus_hook_write_gr(s, 0x2f, value);
1927 break;
1928 case CIRRUS_MMIO_BLTMODE:
1929 cirrus_hook_write_gr(s, 0x30, value);
1930 break;
1931 case CIRRUS_MMIO_BLTROP:
1932 cirrus_hook_write_gr(s, 0x32, value);
1933 break;
a21ae81d
FB
1934 case CIRRUS_MMIO_BLTMODEEXT:
1935 cirrus_hook_write_gr(s, 0x33, value);
1936 break;
e6e5ad80
FB
1937 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
1938 cirrus_hook_write_gr(s, 0x34, value);
1939 break;
1940 case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
1941 cirrus_hook_write_gr(s, 0x35, value);
1942 break;
1943 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
1944 cirrus_hook_write_gr(s, 0x38, value);
1945 break;
1946 case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
1947 cirrus_hook_write_gr(s, 0x39, value);
1948 break;
1949 case CIRRUS_MMIO_BLTSTATUS:
1950 cirrus_hook_write_gr(s, 0x31, value);
1951 break;
1952 default:
1953#ifdef DEBUG_CIRRUS
1954 printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n",
1955 address, value);
1956#endif
1957 break;
1958 }
1959}
1960
e6e5ad80
FB
1961/***************************************
1962 *
1963 * write mode 4/5
1964 *
1965 * assume TARGET_PAGE_SIZE >= 16
1966 *
1967 ***************************************/
1968
1969static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
1970 unsigned mode,
1971 unsigned offset,
1972 uint32_t mem_value)
1973{
1974 int x;
1975 unsigned val = mem_value;
1976 uint8_t *dst;
1977
1978 dst = s->vram_ptr + offset;
1979 for (x = 0; x < 8; x++) {
1980 if (val & 0x80) {
aeb3c85f 1981 *dst++ = s->cirrus_shadow_gr1;
e6e5ad80 1982 } else if (mode == 5) {
aeb3c85f 1983 *dst++ = s->cirrus_shadow_gr0;
e6e5ad80
FB
1984 }
1985 val <<= 1;
1986 }
1987 cpu_physical_memory_set_dirty(s->vram_offset + offset);
1988 cpu_physical_memory_set_dirty(s->vram_offset + offset + 7);
1989}
1990
1991static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
1992 unsigned mode,
1993 unsigned offset,
1994 uint32_t mem_value)
1995{
1996 int x;
1997 unsigned val = mem_value;
1998 uint8_t *dst;
1999
2000 dst = s->vram_ptr + offset;
2001 for (x = 0; x < 8; x++) {
2002 if (val & 0x80) {
aeb3c85f 2003 *dst++ = s->cirrus_shadow_gr1;
e6e5ad80
FB
2004 *dst++ = s->gr[0x11];
2005 } else if (mode == 5) {
aeb3c85f 2006 *dst++ = s->cirrus_shadow_gr0;
e6e5ad80
FB
2007 *dst++ = s->gr[0x10];
2008 }
2009 val <<= 1;
2010 }
2011 cpu_physical_memory_set_dirty(s->vram_offset + offset);
2012 cpu_physical_memory_set_dirty(s->vram_offset + offset + 15);
2013}
2014
2015/***************************************
2016 *
2017 * memory access between 0xa0000-0xbffff
2018 *
2019 ***************************************/
2020
2021static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
2022{
2023 CirrusVGAState *s = opaque;
2024 unsigned bank_index;
2025 unsigned bank_offset;
2026 uint32_t val;
2027
2028 if ((s->sr[0x07] & 0x01) == 0) {
2029 return vga_mem_readb(s, addr);
2030 }
2031
aeb3c85f
FB
2032 addr &= 0x1ffff;
2033
e6e5ad80
FB
2034 if (addr < 0x10000) {
2035 /* XXX handle bitblt */
2036 /* video memory */
2037 bank_index = addr >> 15;
2038 bank_offset = addr & 0x7fff;
2039 if (bank_offset < s->cirrus_bank_limit[bank_index]) {
2040 bank_offset += s->cirrus_bank_base[bank_index];
2041 if ((s->gr[0x0B] & 0x14) == 0x14) {
2042 bank_offset <<= 4;
2043 } else if (s->gr[0x0B] & 0x02) {
2044 bank_offset <<= 3;
2045 }
2046 bank_offset &= s->cirrus_addr_mask;
2047 val = *(s->vram_ptr + bank_offset);
2048 } else
2049 val = 0xff;
2050 } else if (addr >= 0x18000 && addr < 0x18100) {
2051 /* memory-mapped I/O */
2052 val = 0xff;
2053 if ((s->sr[0x17] & 0x44) == 0x04) {
2054 val = cirrus_mmio_blt_read(s, addr & 0xff);
2055 }
2056 } else {
2057 val = 0xff;
2058#ifdef DEBUG_CIRRUS
2059 printf("cirrus: mem_readb %06x\n", addr);
2060#endif
2061 }
2062 return val;
2063}
2064
2065static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr)
2066{
2067 uint32_t v;
2068#ifdef TARGET_WORDS_BIGENDIAN
2069 v = cirrus_vga_mem_readb(opaque, addr) << 8;
2070 v |= cirrus_vga_mem_readb(opaque, addr + 1);
2071#else
2072 v = cirrus_vga_mem_readb(opaque, addr);
2073 v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
2074#endif
2075 return v;
2076}
2077
2078static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr)
2079{
2080 uint32_t v;
2081#ifdef TARGET_WORDS_BIGENDIAN
2082 v = cirrus_vga_mem_readb(opaque, addr) << 24;
2083 v |= cirrus_vga_mem_readb(opaque, addr + 1) << 16;
2084 v |= cirrus_vga_mem_readb(opaque, addr + 2) << 8;
2085 v |= cirrus_vga_mem_readb(opaque, addr + 3);
2086#else
2087 v = cirrus_vga_mem_readb(opaque, addr);
2088 v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
2089 v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16;
2090 v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24;
2091#endif
2092 return v;
2093}
2094
2095static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
2096 uint32_t mem_value)
2097{
2098 CirrusVGAState *s = opaque;
2099 unsigned bank_index;
2100 unsigned bank_offset;
2101 unsigned mode;
2102
2103 if ((s->sr[0x07] & 0x01) == 0) {
2104 vga_mem_writeb(s, addr, mem_value);
2105 return;
2106 }
2107
aeb3c85f
FB
2108 addr &= 0x1ffff;
2109
e6e5ad80
FB
2110 if (addr < 0x10000) {
2111 if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
2112 /* bitblt */
2113 *s->cirrus_srcptr++ = (uint8_t) mem_value;
2114 if (s->cirrus_srcptr == s->cirrus_srcptr_end) {
2115 cirrus_bitblt_cputovideo_next(s);
2116 }
2117 } else {
2118 /* video memory */
2119 bank_index = addr >> 15;
2120 bank_offset = addr & 0x7fff;
2121 if (bank_offset < s->cirrus_bank_limit[bank_index]) {
2122 bank_offset += s->cirrus_bank_base[bank_index];
2123 if ((s->gr[0x0B] & 0x14) == 0x14) {
2124 bank_offset <<= 4;
2125 } else if (s->gr[0x0B] & 0x02) {
2126 bank_offset <<= 3;
2127 }
2128 bank_offset &= s->cirrus_addr_mask;
2129 mode = s->gr[0x05] & 0x7;
2130 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
2131 *(s->vram_ptr + bank_offset) = mem_value;
2132 cpu_physical_memory_set_dirty(s->vram_offset +
2133 bank_offset);
2134 } else {
2135 if ((s->gr[0x0B] & 0x14) != 0x14) {
2136 cirrus_mem_writeb_mode4and5_8bpp(s, mode,
2137 bank_offset,
2138 mem_value);
2139 } else {
2140 cirrus_mem_writeb_mode4and5_16bpp(s, mode,
2141 bank_offset,
2142 mem_value);
2143 }
2144 }
2145 }
2146 }
2147 } else if (addr >= 0x18000 && addr < 0x18100) {
2148 /* memory-mapped I/O */
2149 if ((s->sr[0x17] & 0x44) == 0x04) {
2150 cirrus_mmio_blt_write(s, addr & 0xff, mem_value);
2151 }
2152 } else {
2153#ifdef DEBUG_CIRRUS
2154 printf("cirrus: mem_writeb %06x value %02x\n", addr, mem_value);
2155#endif
2156 }
2157}
2158
2159static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
2160{
2161#ifdef TARGET_WORDS_BIGENDIAN
2162 cirrus_vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
2163 cirrus_vga_mem_writeb(opaque, addr + 1, val & 0xff);
2164#else
2165 cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
2166 cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2167#endif
2168}
2169
2170static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2171{
2172#ifdef TARGET_WORDS_BIGENDIAN
2173 cirrus_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
2174 cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
2175 cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
2176 cirrus_vga_mem_writeb(opaque, addr + 3, val & 0xff);
2177#else
2178 cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
2179 cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2180 cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
2181 cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
2182#endif
2183}
2184
2185static CPUReadMemoryFunc *cirrus_vga_mem_read[3] = {
2186 cirrus_vga_mem_readb,
2187 cirrus_vga_mem_readw,
2188 cirrus_vga_mem_readl,
2189};
2190
2191static CPUWriteMemoryFunc *cirrus_vga_mem_write[3] = {
2192 cirrus_vga_mem_writeb,
2193 cirrus_vga_mem_writew,
2194 cirrus_vga_mem_writel,
2195};
2196
2197/***************************************
2198 *
2199 * LFB memory access
2200 *
2201 ***************************************/
2202
2203static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
2204{
2205 CirrusVGAState *s = (CirrusVGAState *) opaque;
2206 uint32_t ret;
2207
2208 /* XXX: s->vram_size must be a power of two */
2209 addr &= s->cirrus_addr_mask;
2210
2211 if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & 0x1fff00) == 0x1fff00)) {
2212 /* memory-mapped I/O */
2213 ret = cirrus_mmio_blt_read(s, addr & 0xff);
2214 } else if (0) {
2215 /* XXX handle bitblt */
2216 ret = 0xff;
2217 } else {
2218 /* video memory */
2219 if ((s->gr[0x0B] & 0x14) == 0x14) {
2220 addr <<= 4;
2221 } else if (s->gr[0x0B] & 0x02) {
2222 addr <<= 3;
2223 }
2224 addr &= s->cirrus_addr_mask;
2225 ret = *(s->vram_ptr + addr);
2226 }
2227
2228 return ret;
2229}
2230
2231static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr)
2232{
2233 uint32_t v;
2234#ifdef TARGET_WORDS_BIGENDIAN
2235 v = cirrus_linear_readb(opaque, addr) << 8;
2236 v |= cirrus_linear_readb(opaque, addr + 1);
2237#else
2238 v = cirrus_linear_readb(opaque, addr);
2239 v |= cirrus_linear_readb(opaque, addr + 1) << 8;
2240#endif
2241 return v;
2242}
2243
2244static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr)
2245{
2246 uint32_t v;
2247#ifdef TARGET_WORDS_BIGENDIAN
2248 v = cirrus_linear_readb(opaque, addr) << 24;
2249 v |= cirrus_linear_readb(opaque, addr + 1) << 16;
2250 v |= cirrus_linear_readb(opaque, addr + 2) << 8;
2251 v |= cirrus_linear_readb(opaque, addr + 3);
2252#else
2253 v = cirrus_linear_readb(opaque, addr);
2254 v |= cirrus_linear_readb(opaque, addr + 1) << 8;
2255 v |= cirrus_linear_readb(opaque, addr + 2) << 16;
2256 v |= cirrus_linear_readb(opaque, addr + 3) << 24;
2257#endif
2258 return v;
2259}
2260
2261static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
2262 uint32_t val)
2263{
2264 CirrusVGAState *s = (CirrusVGAState *) opaque;
2265 unsigned mode;
2266
2267 addr &= s->cirrus_addr_mask;
2268
2269 if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & 0x1fff00) == 0x1fff00)) {
2270 /* memory-mapped I/O */
2271 cirrus_mmio_blt_write(s, addr & 0xff, val);
2272 } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
2273 /* bitblt */
2274 *s->cirrus_srcptr++ = (uint8_t) val;
2275 if (s->cirrus_srcptr == s->cirrus_srcptr_end) {
2276 cirrus_bitblt_cputovideo_next(s);
2277 }
2278 } else {
2279 /* video memory */
2280 if ((s->gr[0x0B] & 0x14) == 0x14) {
2281 addr <<= 4;
2282 } else if (s->gr[0x0B] & 0x02) {
2283 addr <<= 3;
2284 }
2285 addr &= s->cirrus_addr_mask;
2286
2287 mode = s->gr[0x05] & 0x7;
2288 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
2289 *(s->vram_ptr + addr) = (uint8_t) val;
2290 cpu_physical_memory_set_dirty(s->vram_offset + addr);
2291 } else {
2292 if ((s->gr[0x0B] & 0x14) != 0x14) {
2293 cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
2294 } else {
2295 cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val);
2296 }
2297 }
2298 }
2299}
2300
2301static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr,
2302 uint32_t val)
2303{
2304#ifdef TARGET_WORDS_BIGENDIAN
2305 cirrus_linear_writeb(opaque, addr, (val >> 8) & 0xff);
2306 cirrus_linear_writeb(opaque, addr + 1, val & 0xff);
2307#else
2308 cirrus_linear_writeb(opaque, addr, val & 0xff);
2309 cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2310#endif
2311}
2312
2313static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr,
2314 uint32_t val)
2315{
2316#ifdef TARGET_WORDS_BIGENDIAN
2317 cirrus_linear_writeb(opaque, addr, (val >> 24) & 0xff);
2318 cirrus_linear_writeb(opaque, addr + 1, (val >> 16) & 0xff);
2319 cirrus_linear_writeb(opaque, addr + 2, (val >> 8) & 0xff);
2320 cirrus_linear_writeb(opaque, addr + 3, val & 0xff);
2321#else
2322 cirrus_linear_writeb(opaque, addr, val & 0xff);
2323 cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2324 cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff);
2325 cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff);
2326#endif
2327}
2328
2329
2330static CPUReadMemoryFunc *cirrus_linear_read[3] = {
2331 cirrus_linear_readb,
2332 cirrus_linear_readw,
2333 cirrus_linear_readl,
2334};
2335
2336static CPUWriteMemoryFunc *cirrus_linear_write[3] = {
2337 cirrus_linear_writeb,
2338 cirrus_linear_writew,
2339 cirrus_linear_writel,
2340};
2341
e6e5ad80
FB
2342/* I/O ports */
2343
2344static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
2345{
2346 CirrusVGAState *s = opaque;
2347 int val, index;
2348
2349 /* check port range access depending on color/monochrome mode */
2350 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION))
2351 || (addr >= 0x3d0 && addr <= 0x3df
2352 && !(s->msr & MSR_COLOR_EMULATION))) {
2353 val = 0xff;
2354 } else {
2355 switch (addr) {
2356 case 0x3c0:
2357 if (s->ar_flip_flop == 0) {
2358 val = s->ar_index;
2359 } else {
2360 val = 0;
2361 }
2362 break;
2363 case 0x3c1:
2364 index = s->ar_index & 0x1f;
2365 if (index < 21)
2366 val = s->ar[index];
2367 else
2368 val = 0;
2369 break;
2370 case 0x3c2:
2371 val = s->st00;
2372 break;
2373 case 0x3c4:
2374 val = s->sr_index;
2375 break;
2376 case 0x3c5:
2377 if (cirrus_hook_read_sr(s, s->sr_index, &val))
2378 break;
2379 val = s->sr[s->sr_index];
2380#ifdef DEBUG_VGA_REG
2381 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
2382#endif
2383 break;
2384 case 0x3c6:
2385 cirrus_read_hidden_dac(s, &val);
2386 break;
2387 case 0x3c7:
2388 val = s->dac_state;
2389 break;
2390 case 0x3c9:
2391 if (cirrus_hook_read_palette(s, &val))
2392 break;
2393 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
2394 if (++s->dac_sub_index == 3) {
2395 s->dac_sub_index = 0;
2396 s->dac_read_index++;
2397 }
2398 break;
2399 case 0x3ca:
2400 val = s->fcr;
2401 break;
2402 case 0x3cc:
2403 val = s->msr;
2404 break;
2405 case 0x3ce:
2406 val = s->gr_index;
2407 break;
2408 case 0x3cf:
2409 if (cirrus_hook_read_gr(s, s->gr_index, &val))
2410 break;
2411 val = s->gr[s->gr_index];
2412#ifdef DEBUG_VGA_REG
2413 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
2414#endif
2415 break;
2416 case 0x3b4:
2417 case 0x3d4:
2418 val = s->cr_index;
2419 break;
2420 case 0x3b5:
2421 case 0x3d5:
2422 if (cirrus_hook_read_cr(s, s->cr_index, &val))
2423 break;
2424 val = s->cr[s->cr_index];
2425#ifdef DEBUG_VGA_REG
2426 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
e6e5ad80
FB
2427#endif
2428 break;
2429 case 0x3ba:
2430 case 0x3da:
2431 /* just toggle to fool polling */
2432 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
2433 val = s->st01;
2434 s->ar_flip_flop = 0;
2435 break;
2436 default:
2437 val = 0x00;
2438 break;
2439 }
2440 }
2441#if defined(DEBUG_VGA)
2442 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
2443#endif
2444 return val;
2445}
2446
2447static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
2448{
2449 CirrusVGAState *s = opaque;
2450 int index;
2451
2452 /* check port range access depending on color/monochrome mode */
2453 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION))
2454 || (addr >= 0x3d0 && addr <= 0x3df
2455 && !(s->msr & MSR_COLOR_EMULATION)))
2456 return;
2457
2458#ifdef DEBUG_VGA
2459 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
2460#endif
2461
2462 switch (addr) {
2463 case 0x3c0:
2464 if (s->ar_flip_flop == 0) {
2465 val &= 0x3f;
2466 s->ar_index = val;
2467 } else {
2468 index = s->ar_index & 0x1f;
2469 switch (index) {
2470 case 0x00 ... 0x0f:
2471 s->ar[index] = val & 0x3f;
2472 break;
2473 case 0x10:
2474 s->ar[index] = val & ~0x10;
2475 break;
2476 case 0x11:
2477 s->ar[index] = val;
2478 break;
2479 case 0x12:
2480 s->ar[index] = val & ~0xc0;
2481 break;
2482 case 0x13:
2483 s->ar[index] = val & ~0xf0;
2484 break;
2485 case 0x14:
2486 s->ar[index] = val & ~0xf0;
2487 break;
2488 default:
2489 break;
2490 }
2491 }
2492 s->ar_flip_flop ^= 1;
2493 break;
2494 case 0x3c2:
2495 s->msr = val & ~0x10;
2496 break;
2497 case 0x3c4:
2498 s->sr_index = val;
2499 break;
2500 case 0x3c5:
2501 if (cirrus_hook_write_sr(s, s->sr_index, val))
2502 break;
2503#ifdef DEBUG_VGA_REG
2504 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
2505#endif
2506 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
2507 break;
2508 case 0x3c6:
2509 cirrus_write_hidden_dac(s, val);
2510 break;
2511 case 0x3c7:
2512 s->dac_read_index = val;
2513 s->dac_sub_index = 0;
2514 s->dac_state = 3;
2515 break;
2516 case 0x3c8:
2517 s->dac_write_index = val;
2518 s->dac_sub_index = 0;
2519 s->dac_state = 0;
2520 break;
2521 case 0x3c9:
2522 if (cirrus_hook_write_palette(s, val))
2523 break;
2524 s->dac_cache[s->dac_sub_index] = val;
2525 if (++s->dac_sub_index == 3) {
2526 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
2527 s->dac_sub_index = 0;
2528 s->dac_write_index++;
2529 }
2530 break;
2531 case 0x3ce:
2532 s->gr_index = val;
2533 break;
2534 case 0x3cf:
2535 if (cirrus_hook_write_gr(s, s->gr_index, val))
2536 break;
2537#ifdef DEBUG_VGA_REG
2538 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
2539#endif
2540 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
2541 break;
2542 case 0x3b4:
2543 case 0x3d4:
2544 s->cr_index = val;
2545 break;
2546 case 0x3b5:
2547 case 0x3d5:
2548 if (cirrus_hook_write_cr(s, s->cr_index, val))
2549 break;
2550#ifdef DEBUG_VGA_REG
2551 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
2552#endif
2553 /* handle CR0-7 protection */
2554 if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
2555 /* can always write bit 4 of CR7 */
2556 if (s->cr_index == 7)
2557 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
2558 return;
2559 }
2560 switch (s->cr_index) {
2561 case 0x01: /* horizontal display end */
2562 case 0x07:
2563 case 0x09:
2564 case 0x0c:
2565 case 0x0d:
2566 case 0x12: /* veritcal display end */
2567 s->cr[s->cr_index] = val;
2568 break;
2569
2570 default:
2571 s->cr[s->cr_index] = val;
2572 break;
2573 }
2574 break;
2575 case 0x3ba:
2576 case 0x3da:
2577 s->fcr = val & 0x10;
2578 break;
2579 }
2580}
2581
e36f36e1
FB
2582/***************************************
2583 *
2584 * memory-mapped I/O access
2585 *
2586 ***************************************/
2587
2588static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr)
2589{
2590 CirrusVGAState *s = (CirrusVGAState *) opaque;
2591
2592 addr &= CIRRUS_PNPMMIO_SIZE - 1;
2593
2594 if (addr >= 0x100) {
2595 return cirrus_mmio_blt_read(s, addr - 0x100);
2596 } else {
2597 return vga_ioport_read(s, addr + 0x3c0);
2598 }
2599}
2600
2601static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr)
2602{
2603 uint32_t v;
2604#ifdef TARGET_WORDS_BIGENDIAN
2605 v = cirrus_mmio_readb(opaque, addr) << 8;
2606 v |= cirrus_mmio_readb(opaque, addr + 1);
2607#else
2608 v = cirrus_mmio_readb(opaque, addr);
2609 v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
2610#endif
2611 return v;
2612}
2613
2614static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr)
2615{
2616 uint32_t v;
2617#ifdef TARGET_WORDS_BIGENDIAN
2618 v = cirrus_mmio_readb(opaque, addr) << 24;
2619 v |= cirrus_mmio_readb(opaque, addr + 1) << 16;
2620 v |= cirrus_mmio_readb(opaque, addr + 2) << 8;
2621 v |= cirrus_mmio_readb(opaque, addr + 3);
2622#else
2623 v = cirrus_mmio_readb(opaque, addr);
2624 v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
2625 v |= cirrus_mmio_readb(opaque, addr + 2) << 16;
2626 v |= cirrus_mmio_readb(opaque, addr + 3) << 24;
2627#endif
2628 return v;
2629}
2630
2631static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr,
2632 uint32_t val)
2633{
2634 CirrusVGAState *s = (CirrusVGAState *) opaque;
2635
2636 addr &= CIRRUS_PNPMMIO_SIZE - 1;
2637
2638 if (addr >= 0x100) {
2639 cirrus_mmio_blt_write(s, addr - 0x100, val);
2640 } else {
2641 vga_ioport_write(s, addr + 0x3c0, val);
2642 }
2643}
2644
2645static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr,
2646 uint32_t val)
2647{
2648#ifdef TARGET_WORDS_BIGENDIAN
2649 cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff);
2650 cirrus_mmio_writeb(opaque, addr + 1, val & 0xff);
2651#else
2652 cirrus_mmio_writeb(opaque, addr, val & 0xff);
2653 cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2654#endif
2655}
2656
2657static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr,
2658 uint32_t val)
2659{
2660#ifdef TARGET_WORDS_BIGENDIAN
2661 cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff);
2662 cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff);
2663 cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff);
2664 cirrus_mmio_writeb(opaque, addr + 3, val & 0xff);
2665#else
2666 cirrus_mmio_writeb(opaque, addr, val & 0xff);
2667 cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
2668 cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff);
2669 cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff);
2670#endif
2671}
2672
2673
2674static CPUReadMemoryFunc *cirrus_mmio_read[3] = {
2675 cirrus_mmio_readb,
2676 cirrus_mmio_readw,
2677 cirrus_mmio_readl,
2678};
2679
2680static CPUWriteMemoryFunc *cirrus_mmio_write[3] = {
2681 cirrus_mmio_writeb,
2682 cirrus_mmio_writew,
2683 cirrus_mmio_writel,
2684};
2685
e6e5ad80
FB
2686/***************************************
2687 *
2688 * initialize
2689 *
2690 ***************************************/
2691
20ba3ae1 2692static void cirrus_init_common(CirrusVGAState * s, int device_id)
e6e5ad80
FB
2693{
2694 int vga_io_memory;
2695
2696 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2697
2698 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2699 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2700 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2701 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2702
2703 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2704
2705 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2706 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2707 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2708 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2709
2710 vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read,
2711 cirrus_vga_mem_write, s);
2712 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2713 vga_io_memory);
2714
2715 s->sr[0x06] = 0x0f;
2716 s->sr[0x0F] = CIRRUS_MEMSIZE_2M;
2717 s->sr[0x1F] = 0x22; // MemClock
2718
20ba3ae1 2719 s->cr[0x27] = device_id;
e6e5ad80
FB
2720
2721 s->cirrus_hidden_dac_lockindex = 5;
2722 s->cirrus_hidden_dac_data = 0;
2723
2724 /* I/O handler for LFB */
2725 s->cirrus_linear_io_addr =
2726 cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write,
2727 s);
2728 /* I/O handler for memory-mapped I/O */
2729 s->cirrus_mmio_io_addr =
2730 cpu_register_io_memory(0, cirrus_mmio_read, cirrus_mmio_write, s);
2731
2732 /* XXX: s->vram_size must be a power of two */
2733 s->cirrus_addr_mask = s->vram_size - 1;
2734
2735 s->get_bpp = cirrus_get_bpp;
2736 s->get_offsets = cirrus_get_offsets;
2737}
2738
2739/***************************************
2740 *
2741 * ISA bus support
2742 *
2743 ***************************************/
2744
2745void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
2746 unsigned long vga_ram_offset, int vga_ram_size)
2747{
2748 CirrusVGAState *s;
2749
2750 s = qemu_mallocz(sizeof(CirrusVGAState));
2751
2752 vga_common_init((VGAState *)s,
2753 ds, vga_ram_base, vga_ram_offset, vga_ram_size);
20ba3ae1 2754 cirrus_init_common(s, CIRRUS_ID_CLGD5430);
e6e5ad80
FB
2755 s->sr[0x17] = CIRRUS_BUSTYPE_ISA;
2756 /* XXX ISA-LFB support */
2757}
2758
2759/***************************************
2760 *
2761 * PCI bus support
2762 *
2763 ***************************************/
2764
2765static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
2766 uint32_t addr, uint32_t size, int type)
2767{
2768 CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga;
2769
2770 cpu_register_physical_memory(addr, s->vram_size,
2771 s->cirrus_linear_io_addr);
2772}
2773
2774static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
2775 uint32_t addr, uint32_t size, int type)
2776{
2777 CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga;
2778
2779 cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE,
2780 s->cirrus_mmio_io_addr);
2781}
2782
2783void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
2784 unsigned long vga_ram_offset, int vga_ram_size)
2785{
2786 PCICirrusVGAState *d;
2787 uint8_t *pci_conf;
2788 CirrusVGAState *s;
20ba3ae1
FB
2789 int device_id;
2790
2791 device_id = CIRRUS_ID_CLGD5446;
e6e5ad80
FB
2792
2793 /* setup PCI configuration registers */
2794 d = (PCICirrusVGAState *)pci_register_device("Cirrus VGA",
2795 sizeof(PCICirrusVGAState),
2796 0, -1, NULL, NULL);
2797 pci_conf = d->dev.config;
2798 pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff);
2799 pci_conf[0x01] = (uint8_t) (PCI_VENDOR_CIRRUS >> 8);
20ba3ae1
FB
2800 pci_conf[0x02] = (uint8_t) (device_id & 0xff);
2801 pci_conf[0x03] = (uint8_t) (device_id >> 8);
e6e5ad80
FB
2802 pci_conf[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS;
2803 pci_conf[0x0a] = PCI_CLASS_SUB_VGA;
2804 pci_conf[0x0b] = PCI_CLASS_BASE_DISPLAY;
2805 pci_conf[0x0e] = PCI_CLASS_HEADERTYPE_00h;
2806
2807 /* setup VGA */
2808 s = &d->cirrus_vga;
2809 vga_common_init((VGAState *)s,
2810 ds, vga_ram_base, vga_ram_offset, vga_ram_size);
20ba3ae1 2811 cirrus_init_common(s, device_id);
e6e5ad80
FB
2812 s->sr[0x17] = CIRRUS_BUSTYPE_PCI;
2813
2814 /* setup memory space */
2815 /* memory #0 LFB */
2816 /* memory #1 memory-mapped I/O */
2817 /* XXX: s->vram_size must be a power of two */
2818 pci_register_io_region((PCIDevice *)d, 0, s->vram_size,
a21ae81d 2819 PCI_ADDRESS_SPACE_MEM_PREFETCH, cirrus_pci_lfb_map);
20ba3ae1 2820 if (device_id == CIRRUS_ID_CLGD5446) {
a21ae81d
FB
2821 pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE,
2822 PCI_ADDRESS_SPACE_MEM, cirrus_pci_mmio_map);
2823 }
e6e5ad80
FB
2824 /* XXX: ROM BIOS */
2825}