285 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			285 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * QEMU Cirrus CLGD 54xx VGA Emulator.
 | |
|  *
 | |
|  * Copyright (c) 2004 Fabrice Bellard
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a copy
 | |
|  * of this software and associated documentation files (the "Software"), to deal
 | |
|  * in the Software without restriction, including without limitation the rights
 | |
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | |
|  * copies of the Software, and to permit persons to whom the Software is
 | |
|  * furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice shall be included in
 | |
|  * all copies or substantial portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | |
|  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | |
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | |
|  * THE SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #if DEPTH == 8
 | |
| #define PUTPIXEL(s, a, c)    ROP_OP(s, a, c)
 | |
| #elif DEPTH == 16
 | |
| #define PUTPIXEL(s, a, c)    ROP_OP_16(s, a, c)
 | |
| #elif DEPTH == 24
 | |
| #define PUTPIXEL(s, a, c)    do {          \
 | |
|         ROP_OP(s, a,     c);               \
 | |
|         ROP_OP(s, a + 1, (c >> 8));        \
 | |
|         ROP_OP(s, a + 2, (c >> 16));       \
 | |
|     } while (0)
 | |
| #elif DEPTH == 32
 | |
| #define PUTPIXEL(s, a, c)    ROP_OP_32(s, a, c)
 | |
| #else
 | |
| #error unsupported DEPTH
 | |
| #endif
 | |
| 
 | |
| static void
 | |
| glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
 | |
|      (CirrusVGAState *s, uint32_t dstaddr,
 | |
|       uint32_t srcaddr,
 | |
|       int dstpitch, int srcpitch,
 | |
|       int bltwidth, int bltheight)
 | |
| {
 | |
|     uint32_t addr;
 | |
|     int x, y, pattern_y, pattern_pitch, pattern_x;
 | |
|     unsigned int col;
 | |
|     uint32_t src1addr;
 | |
| #if DEPTH == 24
 | |
|     int skipleft = s->vga.gr[0x2f] & 0x1f;
 | |
| #else
 | |
|     int skipleft = (s->vga.gr[0x2f] & 0x07) * (DEPTH / 8);
 | |
| #endif
 | |
| 
 | |
| #if DEPTH == 8
 | |
|     pattern_pitch = 8;
 | |
| #elif DEPTH == 16
 | |
|     pattern_pitch = 16;
 | |
| #else
 | |
|     pattern_pitch = 32;
 | |
| #endif
 | |
|     pattern_y = s->cirrus_blt_srcaddr & 7;
 | |
|     for(y = 0; y < bltheight; y++) {
 | |
|         pattern_x = skipleft;
 | |
|         addr = dstaddr + skipleft;
 | |
|         src1addr = srcaddr + pattern_y * pattern_pitch;
 | |
|         for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
 | |
| #if DEPTH == 8
 | |
|             col = cirrus_src(s, src1addr + pattern_x);
 | |
|             pattern_x = (pattern_x + 1) & 7;
 | |
| #elif DEPTH == 16
 | |
|             col = cirrus_src16(s, src1addr + pattern_x);
 | |
|             pattern_x = (pattern_x + 2) & 15;
 | |
| #elif DEPTH == 24
 | |
|             {
 | |
|                 uint32_t src2addr = src1addr + pattern_x * 3;
 | |
|                 col = cirrus_src(s, src2addr) |
 | |
|                     (cirrus_src(s, src2addr + 1) << 8) |
 | |
|                     (cirrus_src(s, src2addr + 2) << 16);
 | |
|                 pattern_x = (pattern_x + 1) & 7;
 | |
|             }
 | |
| #else
 | |
|             col = cirrus_src32(s, src1addr + pattern_x);
 | |
|             pattern_x = (pattern_x + 4) & 31;
 | |
| #endif
 | |
|             PUTPIXEL(s, addr, col);
 | |
|             addr += (DEPTH / 8);
 | |
|         }
 | |
|         pattern_y = (pattern_y + 1) & 7;
 | |
|         dstaddr += dstpitch;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* NOTE: srcpitch is ignored */
 | |
| static void
 | |
| glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
 | |
|      (CirrusVGAState *s, uint32_t dstaddr,
 | |
|       uint32_t srcaddr,
 | |
|       int dstpitch, int srcpitch,
 | |
|       int bltwidth, int bltheight)
 | |
| {
 | |
|     uint32_t addr;
 | |
|     int x, y;
 | |
|     unsigned bits, bits_xor;
 | |
|     unsigned int col;
 | |
|     unsigned bitmask;
 | |
|     unsigned index;
 | |
| #if DEPTH == 24
 | |
|     int dstskipleft = s->vga.gr[0x2f] & 0x1f;
 | |
|     int srcskipleft = dstskipleft / 3;
 | |
| #else
 | |
|     int srcskipleft = s->vga.gr[0x2f] & 0x07;
 | |
|     int dstskipleft = srcskipleft * (DEPTH / 8);
 | |
| #endif
 | |
| 
 | |
|     if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
 | |
|         bits_xor = 0xff;
 | |
|         col = s->cirrus_blt_bgcol;
 | |
|     } else {
 | |
|         bits_xor = 0x00;
 | |
|         col = s->cirrus_blt_fgcol;
 | |
|     }
 | |
| 
 | |
|     for(y = 0; y < bltheight; y++) {
 | |
|         bitmask = 0x80 >> srcskipleft;
 | |
|         bits = cirrus_src(s, srcaddr++) ^ bits_xor;
 | |
|         addr = dstaddr + dstskipleft;
 | |
|         for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
 | |
|             if ((bitmask & 0xff) == 0) {
 | |
|                 bitmask = 0x80;
 | |
|                 bits = cirrus_src(s, srcaddr++) ^ bits_xor;
 | |
|             }
 | |
|             index = (bits & bitmask);
 | |
|             if (index) {
 | |
|                 PUTPIXEL(s, addr, col);
 | |
|             }
 | |
|             addr += (DEPTH / 8);
 | |
|             bitmask >>= 1;
 | |
|         }
 | |
|         dstaddr += dstpitch;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
 | |
|      (CirrusVGAState *s, uint32_t dstaddr,
 | |
|       uint32_t srcaddr,
 | |
|       int dstpitch, int srcpitch,
 | |
|       int bltwidth, int bltheight)
 | |
| {
 | |
|     uint32_t colors[2];
 | |
|     uint32_t addr;
 | |
|     int x, y;
 | |
|     unsigned bits;
 | |
|     unsigned int col;
 | |
|     unsigned bitmask;
 | |
|     int srcskipleft = s->vga.gr[0x2f] & 0x07;
 | |
|     int dstskipleft = srcskipleft * (DEPTH / 8);
 | |
| 
 | |
|     colors[0] = s->cirrus_blt_bgcol;
 | |
|     colors[1] = s->cirrus_blt_fgcol;
 | |
|     for(y = 0; y < bltheight; y++) {
 | |
|         bitmask = 0x80 >> srcskipleft;
 | |
|         bits = cirrus_src(s, srcaddr++);
 | |
|         addr = dstaddr + dstskipleft;
 | |
|         for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
 | |
|             if ((bitmask & 0xff) == 0) {
 | |
|                 bitmask = 0x80;
 | |
|                 bits = cirrus_src(s, srcaddr++);
 | |
|             }
 | |
|             col = colors[!!(bits & bitmask)];
 | |
|             PUTPIXEL(s, addr, col);
 | |
|             addr += (DEPTH / 8);
 | |
|             bitmask >>= 1;
 | |
|         }
 | |
|         dstaddr += dstpitch;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
 | |
|      (CirrusVGAState *s, uint32_t dstaddr,
 | |
|       uint32_t srcaddr,
 | |
|       int dstpitch, int srcpitch,
 | |
|       int bltwidth, int bltheight)
 | |
| {
 | |
|     uint32_t addr;
 | |
|     int x, y, bitpos, pattern_y;
 | |
|     unsigned int bits, bits_xor;
 | |
|     unsigned int col;
 | |
| #if DEPTH == 24
 | |
|     int dstskipleft = s->vga.gr[0x2f] & 0x1f;
 | |
|     int srcskipleft = dstskipleft / 3;
 | |
| #else
 | |
|     int srcskipleft = s->vga.gr[0x2f] & 0x07;
 | |
|     int dstskipleft = srcskipleft * (DEPTH / 8);
 | |
| #endif
 | |
| 
 | |
|     if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
 | |
|         bits_xor = 0xff;
 | |
|         col = s->cirrus_blt_bgcol;
 | |
|     } else {
 | |
|         bits_xor = 0x00;
 | |
|         col = s->cirrus_blt_fgcol;
 | |
|     }
 | |
|     pattern_y = s->cirrus_blt_srcaddr & 7;
 | |
| 
 | |
|     for(y = 0; y < bltheight; y++) {
 | |
|         bits = cirrus_src(s, srcaddr + pattern_y) ^ bits_xor;
 | |
|         bitpos = 7 - srcskipleft;
 | |
|         addr = dstaddr + dstskipleft;
 | |
|         for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
 | |
|             if ((bits >> bitpos) & 1) {
 | |
|                 PUTPIXEL(s, addr, col);
 | |
|             }
 | |
|             addr += (DEPTH / 8);
 | |
|             bitpos = (bitpos - 1) & 7;
 | |
|         }
 | |
|         pattern_y = (pattern_y + 1) & 7;
 | |
|         dstaddr += dstpitch;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
 | |
|      (CirrusVGAState *s, uint32_t dstaddr,
 | |
|       uint32_t srcaddr,
 | |
|       int dstpitch, int srcpitch,
 | |
|       int bltwidth, int bltheight)
 | |
| {
 | |
|     uint32_t colors[2];
 | |
|     uint32_t addr;
 | |
|     int x, y, bitpos, pattern_y;
 | |
|     unsigned int bits;
 | |
|     unsigned int col;
 | |
|     int srcskipleft = s->vga.gr[0x2f] & 0x07;
 | |
|     int dstskipleft = srcskipleft * (DEPTH / 8);
 | |
| 
 | |
|     colors[0] = s->cirrus_blt_bgcol;
 | |
|     colors[1] = s->cirrus_blt_fgcol;
 | |
|     pattern_y = s->cirrus_blt_srcaddr & 7;
 | |
| 
 | |
|     for(y = 0; y < bltheight; y++) {
 | |
|         bits = cirrus_src(s, srcaddr + pattern_y);
 | |
|         bitpos = 7 - srcskipleft;
 | |
|         addr = dstaddr + dstskipleft;
 | |
|         for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
 | |
|             col = colors[(bits >> bitpos) & 1];
 | |
|             PUTPIXEL(s, addr, col);
 | |
|             addr += (DEPTH / 8);
 | |
|             bitpos = (bitpos - 1) & 7;
 | |
|         }
 | |
|         pattern_y = (pattern_y + 1) & 7;
 | |
|         dstaddr += dstpitch;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
 | |
|      (CirrusVGAState *s,
 | |
|       uint32_t dstaddr, int dst_pitch,
 | |
|       int width, int height)
 | |
| {
 | |
|     uint32_t addr;
 | |
|     uint32_t col;
 | |
|     int x, y;
 | |
| 
 | |
|     col = s->cirrus_blt_fgcol;
 | |
| 
 | |
|     for(y = 0; y < height; y++) {
 | |
|         addr = dstaddr;
 | |
|         for(x = 0; x < width; x += (DEPTH / 8)) {
 | |
|             PUTPIXEL(s, addr, col);
 | |
|             addr += (DEPTH / 8);
 | |
|         }
 | |
|         dstaddr += dst_pitch;
 | |
|     }
 | |
| }
 | |
| 
 | |
| #undef DEPTH
 | |
| #undef PUTPIXEL
 |