#include "qemu/units.h"
#include "sysemu/reset.h"
#include "qapi/error.h"
+#include "hw/core/cpu.h"
#include "hw/display/vga.h"
+#include "hw/i386/x86.h"
#include "hw/pci/pci.h"
#include "vga_int.h"
#include "vga_regs.h"
/* 16 state changes per vertical frame @60 Hz */
#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
+/* Address mask for non-VESA modes. */
+#define VGA_VRAM_SIZE (256 * KiB)
+
+/* This value corresponds to a shift of zero pixels
+ * in 9-dot text mode. In other modes, bit 3 is undefined;
+ * we just ignore it, so that 8 corresponds to zero pixels
+ * in all modes.
+ */
+#define VGA_HPEL_NEUTRAL 8
+
/*
* Video Graphics Array (VGA)
*
0x00, /* 0x0f */
};
-#define cbswap_32(__x) \
-((uint32_t)( \
- (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
- (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
- (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
- (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
-
-#if HOST_BIG_ENDIAN
-#define PAT(x) cbswap_32(x)
-#else
-#define PAT(x) (x)
-#endif
-
-#if HOST_BIG_ENDIAN
-#define BIG 1
-#else
-#define BIG 0
-#endif
-
-#if HOST_BIG_ENDIAN
-#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
-#else
-#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
-#endif
+#define GET_PLANE(data, p) ((cpu_to_le32(data) >> ((p) * 8)) & 0xff)
static const uint32_t mask16[16] = {
- PAT(0x00000000),
- PAT(0x000000ff),
- PAT(0x0000ff00),
- PAT(0x0000ffff),
- PAT(0x00ff0000),
- PAT(0x00ff00ff),
- PAT(0x00ffff00),
- PAT(0x00ffffff),
- PAT(0xff000000),
- PAT(0xff0000ff),
- PAT(0xff00ff00),
- PAT(0xff00ffff),
- PAT(0xffff0000),
- PAT(0xffff00ff),
- PAT(0xffffff00),
- PAT(0xffffffff),
+ const_le32(0x00000000),
+ const_le32(0x000000ff),
+ const_le32(0x0000ff00),
+ const_le32(0x0000ffff),
+ const_le32(0x00ff0000),
+ const_le32(0x00ff00ff),
+ const_le32(0x00ffff00),
+ const_le32(0x00ffffff),
+ const_le32(0xff000000),
+ const_le32(0xff0000ff),
+ const_le32(0xff00ff00),
+ const_le32(0xff00ffff),
+ const_le32(0xffff0000),
+ const_le32(0xffff00ff),
+ const_le32(0xffffff00),
+ const_le32(0xffffffff),
};
-#undef PAT
-
-#if HOST_BIG_ENDIAN
-#define PAT(x) (x)
-#else
-#define PAT(x) cbswap_32(x)
-#endif
-
static uint32_t expand4[256];
static uint16_t expand2[256];
static uint8_t expand4to8[16];
}
if (sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
- /* chain 4 mode : simplest access */
- assert(addr < s->vram_size);
- ret = s->vram_ptr[addr];
- } else if (s->gr[VGA_GFX_MODE] & 0x10) {
+ /* chain4 mode */
+ plane = addr & 3;
+ addr &= ~3;
+ } else if (s->gr[VGA_GFX_MODE] & VGA_GR05_HOST_ODD_EVEN) {
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- addr = ((addr & ~1) << 1) | plane;
- if (addr >= s->vram_size) {
- return 0xff;
- }
- ret = s->vram_ptr[addr];
} else {
/* standard VGA latched access */
- if (addr * sizeof(uint32_t) >= s->vram_size) {
- return 0xff;
- }
- s->latch = ((uint32_t *)s->vram_ptr)[addr];
+ plane = s->gr[VGA_GFX_PLANE_READ];
+ }
- if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
- /* read mode 0 */
- plane = s->gr[VGA_GFX_PLANE_READ];
- ret = GET_PLANE(s->latch, plane);
- } else {
- /* read mode 1 */
- ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
- mask16[s->gr[VGA_GFX_COMPARE_MASK]];
- ret |= ret >> 16;
- ret |= ret >> 8;
- ret = (~ret) & 0xff;
- }
+ if (s->gr[VGA_GFX_MISC] & VGA_GR06_CHAIN_ODD_EVEN) {
+ addr &= ~1;
+ }
+
+ /* Doubleword/word mode. See comment in vga_mem_writeb */
+ if (s->cr[VGA_CRTC_UNDERLINE] & VGA_CR14_DW) {
+ addr >>= 2;
+ } else if ((s->gr[VGA_GFX_MODE] & VGA_GR05_HOST_ODD_EVEN) &&
+ (s->cr[VGA_CRTC_MODE] & VGA_CR17_WORD_BYTE) == 0) {
+ addr >>= 1;
}
+
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return 0xff;
+ }
+
+ if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
+ /* chain 4 mode: simplified access (but it should use the same
+ * algorithms as below, see e.g. vga_mem_writeb's plane mask check).
+ */
+ return s->vram_ptr[(addr << 2) | plane];
+ }
+
+ s->latch = ((uint32_t *)s->vram_ptr)[addr];
+ if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
+ /* read mode 0 */
+ ret = GET_PLANE(s->latch, plane);
+ } else {
+ /* read mode 1 */
+ ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
+ mask16[s->gr[VGA_GFX_COMPARE_MASK]];
+ ret |= ret >> 16;
+ ret |= ret >> 8;
+ ret = (~ret) & 0xff;
+ }
+
return ret;
}
/* called for accesses between 0xa0000 and 0xc0000 */
void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
{
- int memory_map_mode, plane, write_mode, b, func_select, mask;
+ int memory_map_mode, write_mode, b, func_select, mask;
uint32_t write_mask, bit_mask, set_mask;
+ int plane = 0;
#ifdef DEBUG_VGA_MEM
- printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
+ printf("vga: [0x" HWADDR_FMT_plx "] = 0x%02x\n", addr, val);
#endif
/* convert to VGA memory offset */
memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
break;
}
+ mask = sr(s, VGA_SEQ_PLANE_WRITE);
if (sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
plane = addr & 3;
- mask = (1 << plane);
- if (sr(s, VGA_SEQ_PLANE_WRITE) & mask) {
- assert(addr < s->vram_size);
- s->vram_ptr[addr] = val;
-#ifdef DEBUG_VGA_MEM
- printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
-#endif
- s->plane_updated |= mask; /* only used to detect font change */
- memory_region_set_dirty(&s->vram, addr, 1);
+ mask &= (1 << plane);
+ addr &= ~3;
+ } else {
+ if ((sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_SEQ_MODE) == 0) {
+ mask &= (addr & 1) ? 0x0a : 0x05;
}
- } else if (s->gr[VGA_GFX_MODE] & 0x10) {
- /* odd/even mode (aka text mode mapping) */
- plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
- mask = (1 << plane);
- if (sr(s, VGA_SEQ_PLANE_WRITE) & mask) {
- addr = ((addr & ~1) << 1) | plane;
- if (addr >= s->vram_size) {
- return;
- }
- s->vram_ptr[addr] = val;
+ if (s->gr[VGA_GFX_MISC] & VGA_GR06_CHAIN_ODD_EVEN) {
+ addr &= ~1;
+ }
+ }
+
+ /* Doubleword/word mode. These should be honored when displaying,
+ * not when reading/writing to memory! For example, chain4 modes
+ * use double-word mode and, on real hardware, would fetch bytes
+ * 0,1,2,3, 16,17,18,19, 32,33,34,35, etc. Text modes use word
+ * mode and, on real hardware, would fetch bytes 0,1, 8,9, etc.
+ *
+ * QEMU instead shifted addresses on memory accesses because it
+ * allows more optimizations (e.g. chain4_alias) and simplifies
+ * the draw_line handlers. Unfortunately, there is one case where
+ * the difference shows. When fetching font data, accesses are
+ * always in consecutive bytes, even if the text/attribute pairs
+ * are done in word mode. Hence, doing a right shift when operating
+ * on font data is wrong. So check the odd/even mode bits together with
+ * word mode bit. The odd/even read bit is 0 when reading font data,
+ * and the odd/even write bit is 1 when writing it.
+ */
+ if (s->cr[VGA_CRTC_UNDERLINE] & VGA_CR14_DW) {
+ addr >>= 2;
+ } else if ((sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_SEQ_MODE) == 0 &&
+ (s->cr[VGA_CRTC_MODE] & VGA_CR17_WORD_BYTE) == 0) {
+ addr >>= 1;
+ }
+
+ if (addr * sizeof(uint32_t) >= s->vram_size) {
+ return;
+ }
+
+ if (sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
+ if (mask) {
+ s->vram_ptr[(addr << 2) | plane] = val;
#ifdef DEBUG_VGA_MEM
- printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
+ printf("vga: chain4: [0x" HWADDR_FMT_plx "]\n", addr);
#endif
s->plane_updated |= mask; /* only used to detect font change */
memory_region_set_dirty(&s->vram, addr, 1);
}
- } else {
- /* standard VGA latched access */
- write_mode = s->gr[VGA_GFX_MODE] & 3;
- switch(write_mode) {
- default:
- case 0:
- /* rotate */
- b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
- val = ((val >> b) | (val << (8 - b))) & 0xff;
- val |= val << 8;
- val |= val << 16;
-
- /* apply set/reset mask */
- set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
- val = (val & ~set_mask) |
- (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
- bit_mask = s->gr[VGA_GFX_BIT_MASK];
- break;
- case 1:
- val = s->latch;
- goto do_write;
- case 2:
- val = mask16[val & 0x0f];
- bit_mask = s->gr[VGA_GFX_BIT_MASK];
- break;
- case 3:
- /* rotate */
- b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
- val = (val >> b) | (val << (8 - b));
+ return;
+ }
- bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
- val = mask16[s->gr[VGA_GFX_SR_VALUE]];
- break;
- }
+ /* standard VGA latched access */
+ write_mode = s->gr[VGA_GFX_MODE] & 3;
+ switch(write_mode) {
+ default:
+ case 0:
+ /* rotate */
+ b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
+ val = ((val >> b) | (val << (8 - b))) & 0xff;
+ val |= val << 8;
+ val |= val << 16;
+
+ /* apply set/reset mask */
+ set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
+ val = (val & ~set_mask) |
+ (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
+ bit_mask = s->gr[VGA_GFX_BIT_MASK];
+ break;
+ case 1:
+ val = s->latch;
+ goto do_write;
+ case 2:
+ val = mask16[val & 0x0f];
+ bit_mask = s->gr[VGA_GFX_BIT_MASK];
+ break;
+ case 3:
+ /* rotate */
+ b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
+ val = (val >> b) | (val << (8 - b));
- /* apply logical operation */
- func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
- switch(func_select) {
- case 0:
- default:
- /* nothing to do */
- break;
- case 1:
- /* and */
- val &= s->latch;
- break;
- case 2:
- /* or */
- val |= s->latch;
- break;
- case 3:
- /* xor */
- val ^= s->latch;
- break;
- }
+ bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
+ val = mask16[s->gr[VGA_GFX_SR_VALUE]];
+ break;
+ }
- /* apply bit mask */
- bit_mask |= bit_mask << 8;
- bit_mask |= bit_mask << 16;
- val = (val & bit_mask) | (s->latch & ~bit_mask);
-
- do_write:
- /* mask data according to sr[2] */
- mask = sr(s, VGA_SEQ_PLANE_WRITE);
- s->plane_updated |= mask; /* only used to detect font change */
- write_mask = mask16[mask];
- if (addr * sizeof(uint32_t) >= s->vram_size) {
- return;
- }
- ((uint32_t *)s->vram_ptr)[addr] =
- (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
- (val & write_mask);
+ /* apply logical operation */
+ func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
+ switch(func_select) {
+ case 0:
+ default:
+ /* nothing to do */
+ break;
+ case 1:
+ /* and */
+ val &= s->latch;
+ break;
+ case 2:
+ /* or */
+ val |= s->latch;
+ break;
+ case 3:
+ /* xor */
+ val ^= s->latch;
+ break;
+ }
+
+ /* apply bit mask */
+ bit_mask |= bit_mask << 8;
+ bit_mask |= bit_mask << 16;
+ val = (val & bit_mask) | (s->latch & ~bit_mask);
+
+do_write:
+ /* mask data according to sr[2] */
+ s->plane_updated |= mask; /* only used to detect font change */
+ write_mask = mask16[mask];
+ ((uint32_t *)s->vram_ptr)[addr] =
+ (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
+ (val & write_mask);
#ifdef DEBUG_VGA_MEM
- printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
- addr * 4, write_mask, val);
+ printf("vga: latch: [0x" HWADDR_FMT_plx "] mask=0x%08x val=0x%08x\n",
+ addr * 4, write_mask, val);
#endif
- memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
- }
+ memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
}
-typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
- uint32_t srcaddr, int width);
+typedef void *vga_draw_line_func(VGACommonState *s1, uint8_t *d,
+ uint32_t srcaddr, int width, int hpel);
#include "vga-access.h"
#include "vga-helpers.h"
return full_update;
}
-static void vga_get_offsets(VGACommonState *s,
- uint32_t *pline_offset,
- uint32_t *pstart_addr,
- uint32_t *pline_compare)
+static void vga_get_params(VGACommonState *s,
+ VGADisplayParams *params)
{
- uint32_t start_addr, line_offset, line_compare;
-
if (vbe_enabled(s)) {
- line_offset = s->vbe_line_offset;
- start_addr = s->vbe_start_addr;
- line_compare = 65535;
+ params->line_offset = s->vbe_line_offset;
+ params->start_addr = s->vbe_start_addr;
+ params->line_compare = 65535;
+ params->hpel = VGA_HPEL_NEUTRAL;
+ params->hpel_split = false;
} else {
/* compute line_offset in bytes */
- line_offset = s->cr[VGA_CRTC_OFFSET];
- line_offset <<= 3;
+ params->line_offset = s->cr[VGA_CRTC_OFFSET] << 3;
/* starting address */
- start_addr = s->cr[VGA_CRTC_START_LO] |
+ params->start_addr = s->cr[VGA_CRTC_START_LO] |
(s->cr[VGA_CRTC_START_HI] << 8);
/* line compare */
- line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
+ params->line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
+
+ params->hpel = s->ar[VGA_ATC_PEL];
+ params->hpel_split = s->ar[VGA_ATC_MODE] & 0x20;
}
- *pline_offset = line_offset;
- *pstart_addr = start_addr;
- *pline_compare = line_compare;
}
/* update start_addr and line_offset. Return TRUE if modified */
static int update_basic_params(VGACommonState *s)
{
int full_update;
- uint32_t start_addr, line_offset, line_compare;
+ VGADisplayParams current;
full_update = 0;
- s->get_offsets(s, &line_offset, &start_addr, &line_compare);
+ s->get_params(s, ¤t);
- if (line_offset != s->line_offset ||
- start_addr != s->start_addr ||
- line_compare != s->line_compare) {
- s->line_offset = line_offset;
- s->start_addr = start_addr;
- s->line_compare = line_compare;
+ if (memcmp(¤t, &s->params, sizeof(current))) {
+ s->params = current;
full_update = 1;
}
return full_update;
}
full_update |= update_basic_params(s);
- line_offset = s->line_offset;
+ line_offset = s->params.line_offset;
vga_get_text_resolution(s, &width, &height, &cw, &cheight);
if ((height * width) <= 1) {
}
cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
- s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
+ s->cr[VGA_CRTC_CURSOR_LO]) - s->params.start_addr;
if (cursor_offset != s->cursor_offset ||
s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
}
- cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
+ cursor_ptr = s->vram_ptr + (s->params.start_addr + cursor_offset) * 4;
if (now >= s->cursor_blink_time) {
s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
s->cursor_visible_phase = !s->cursor_visible_phase;
linesize = surface_stride(surface);
ch_attr_ptr = s->last_ch_attr;
line = 0;
- offset = s->start_addr * 4;
+ offset = s->params.start_addr * 4;
for(cy = 0; cy < height; cy++) {
d1 = dest;
src = s->vram_ptr + offset;
dest += linesize * cheight;
line1 = line + cheight;
offset += line_offset;
- if (line < s->line_compare && line1 >= s->line_compare) {
+ if (line < s->params.line_compare && line1 >= s->params.line_compare) {
offset = 0;
}
line = line1;
ram_addr_t page0, page1, region_start, region_end;
DirtyBitmapSnapshot *snap = NULL;
int disp_width, multi_scan, multi_run;
+ int hpel;
uint8_t *d;
uint32_t v, addr1, addr;
vga_draw_line_func *vga_draw_line = NULL;
disp_width = width;
depth = s->get_bpp(s);
- region_start = (s->start_addr * 4);
- region_end = region_start + (ram_addr_t)s->line_offset * height;
- region_end += width * depth / 8; /* scanline length */
- region_end -= s->line_offset;
- if (region_end > s->vbe_size || depth == 0 || depth == 15) {
- /*
- * We land here on:
- * - wraps around (can happen with cirrus vbe modes)
- * - depth == 0 (256 color palette video mode)
- * - depth == 15
- *
- * Take the safe and slow route:
- * - create a dirty bitmap snapshot for all vga memory.
- * - force shadowing (so all vga memory access goes
- * through vga_read_*() helpers).
- *
- * Given this affects only vga features which are pretty much
- * unused by modern guests there should be no performance
- * impact.
- */
- region_start = 0;
- region_end = s->vbe_size;
- force_shadow = true;
- }
-
/* bits 5-6: 0 = 16-color mode, 1 = 4-color mode, 2 = 256-color mode. */
shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
}
if (shift_control == 0) {
+ full_update |= update_palette16(s);
if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
disp_width <<= 1;
+ v = VGA_DRAW_LINE4D2;
+ } else {
+ v = VGA_DRAW_LINE4;
}
+ bits = 4;
+
} else if (shift_control == 1) {
+ full_update |= update_palette16(s);
if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
disp_width <<= 1;
+ v = VGA_DRAW_LINE2D2;
+ } else {
+ v = VGA_DRAW_LINE2;
+ }
+ bits = 4;
+
+ } else {
+ switch (depth) {
+ default:
+ case 0:
+ full_update |= update_palette256(s);
+ v = VGA_DRAW_LINE8D2;
+ bits = 4;
+ break;
+ case 8:
+ full_update |= update_palette256(s);
+ v = VGA_DRAW_LINE8;
+ bits = 8;
+ break;
+ case 15:
+ v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE;
+ bits = 16;
+ break;
+ case 16:
+ v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE;
+ bits = 16;
+ break;
+ case 24:
+ v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE;
+ bits = 24;
+ break;
+ case 32:
+ v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE;
+ bits = 32;
+ break;
}
}
+ /* Horizontal pel panning bit 3 is only used in text mode. */
+ hpel = bits <= 8 ? s->params.hpel & 7 : 0;
+ bwidth = DIV_ROUND_UP(width * bits, 8); /* scanline length */
+ if (hpel) {
+ bwidth += 4;
+ }
+
+ region_start = (s->params.start_addr * 4);
+ region_end = region_start + (ram_addr_t)s->params.line_offset * (height - 1) + bwidth;
+ if (region_end > s->vbe_size) {
+ /*
+ * On wrap around take the safe and slow route:
+ * - create a dirty bitmap snapshot for all vga memory.
+ * - force shadowing (so all vga memory access goes
+ * through vga_read_*() helpers).
+ *
+ * Given this affects only vga features which are pretty much
+ * unused by modern guests there should be no performance
+ * impact.
+ */
+ region_start = 0;
+ region_end = s->vbe_size;
+ force_shadow = true;
+ }
+ if (s->params.line_compare < height) {
+ /* split screen mode */
+ region_start = 0;
+ }
+
/*
* Check whether we can share the surface with the backend
* or whether we need a shadow surface. We share native
share_surface = false;
}
- if (s->line_offset != s->last_line_offset ||
+ if (s->params.line_offset != s->last_line_offset ||
disp_width != s->last_width ||
height != s->last_height ||
s->last_depth != depth ||
s->last_scr_height = height;
s->last_width = disp_width;
s->last_height = height;
- s->last_line_offset = s->line_offset;
+ s->last_line_offset = s->params.line_offset;
s->last_depth = depth;
s->last_byteswap = byteswap;
+ /* 16 extra pixels are needed for double-width planar modes. */
+ s->panning_buf = g_realloc(s->panning_buf,
+ (disp_width + 16) * sizeof(uint32_t));
full_update = 1;
}
- if (surface_data(surface) != s->vram_ptr + (s->start_addr * 4)
+ if (surface_data(surface) != s->vram_ptr + (s->params.start_addr * 4)
&& is_buffer_shared(surface)) {
/* base address changed (page flip) -> shared display surfaces
* must be updated with the new base address */
if (full_update) {
if (share_surface) {
surface = qemu_create_displaysurface_from(disp_width,
- height, format, s->line_offset,
- s->vram_ptr + (s->start_addr * 4));
+ height, format, s->params.line_offset,
+ s->vram_ptr + (s->params.start_addr * 4));
dpy_gfx_replace_surface(s->con, surface);
} else {
qemu_console_resize(s->con, disp_width, height);
}
}
- if (shift_control == 0) {
- full_update |= update_palette16(s);
- if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
- v = VGA_DRAW_LINE4D2;
- } else {
- v = VGA_DRAW_LINE4;
- }
- bits = 4;
- } else if (shift_control == 1) {
- full_update |= update_palette16(s);
- if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
- v = VGA_DRAW_LINE2D2;
- } else {
- v = VGA_DRAW_LINE2;
- }
- bits = 4;
- } else {
- switch(s->get_bpp(s)) {
- default:
- case 0:
- full_update |= update_palette256(s);
- v = VGA_DRAW_LINE8D2;
- bits = 4;
- break;
- case 8:
- full_update |= update_palette256(s);
- v = VGA_DRAW_LINE8;
- bits = 8;
- break;
- case 15:
- v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE;
- bits = 16;
- break;
- case 16:
- v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE;
- bits = 16;
- break;
- case 24:
- v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE;
- bits = 24;
- break;
- case 32:
- v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE;
- bits = 32;
- break;
- }
- }
vga_draw_line = vga_draw_line_table[v];
if (!is_buffer_shared(surface) && s->cursor_invalidate) {
#if 0
printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
- s->line_compare, sr(s, VGA_SEQ_CLOCK_MODE));
+ s->params.line_compare, sr(s, VGA_SEQ_CLOCK_MODE));
#endif
- addr1 = (s->start_addr * 4);
- bwidth = DIV_ROUND_UP(width * bits, 8);
+ addr1 = (s->params.start_addr * 4);
y_start = -1;
d = surface_data(surface);
linesize = surface_stride(surface);
y1 = 0;
if (!full_update) {
- if (s->line_compare < height) {
- /* split screen mode */
- region_start = 0;
- }
snap = memory_region_snapshot_and_clear_dirty(&s->vram, region_start,
region_end - region_start,
DIRTY_MEMORY_VGA);
if (y_start < 0)
y_start = y;
if (!(is_buffer_shared(surface))) {
- vga_draw_line(s, d, addr, width);
+ uint8_t *p;
+ p = vga_draw_line(s, d, addr, width, hpel);
+ if (p) {
+ memcpy(d, p, disp_width * sizeof(uint32_t));
+ }
if (s->cursor_draw_line)
s->cursor_draw_line(s, d, y);
}
if (!multi_run) {
mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
if ((y1 & mask) == mask)
- addr1 += s->line_offset;
+ addr1 += s->params.line_offset;
y1++;
multi_run = multi_scan;
} else {
multi_run--;
}
/* line compare acts on the displayed lines */
- if (y == s->line_compare)
+ if (y == s->params.line_compare) {
+ if (s->params.hpel_split) {
+ hpel = VGA_HPEL_NEUTRAL;
+ }
addr1 = 0;
+ }
d += linesize;
}
if (y_start >= 0) {
s->graphic_mode = -1; /* force full update */
s->shift_control = 0;
s->double_scan = 0;
- s->line_offset = 0;
- s->line_compare = 0;
- s->start_addr = 0;
+ memset(&s->params, '\0', sizeof(s->params));
s->plane_updated = 0;
s->last_cw = 0;
s->last_ch = 0;
/* Update "hardware" cursor */
cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
- s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
+ s->cr[VGA_CRTC_CURSOR_LO]) - s->params.start_addr;
if (cursor_offset != s->cursor_offset ||
s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
}
- src = (uint32_t *) s->vram_ptr + s->start_addr;
+ src = (uint32_t *) s->vram_ptr + s->params.start_addr;
dst = chardata;
if (full_update) {
.version_id = 1,
.minimum_version_id = 1,
.needed = vga_endian_state_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_BOOL(big_endian_fb, VGACommonState),
VMSTATE_END_OF_LIST()
}
.version_id = 2,
.minimum_version_id = 2,
.post_load = vga_common_post_load,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(latch, VGACommonState),
VMSTATE_UINT8(sr_index, VGACommonState),
VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
VMSTATE_END_OF_LIST()
},
- .subsections = (const VMStateDescription*[]) {
+ .subsections = (const VMStateDescription * const []) {
&vmstate_vga_endian,
NULL
}
xen_register_framebuffer(&s->vram);
s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
s->get_bpp = vga_get_bpp;
- s->get_offsets = vga_get_offsets;
+ s->get_params = vga_get_params;
s->get_resolution = vga_get_resolution;
s->hw_ops = &vga_ops;
switch (vga_retrace_method) {
* into a device attribute set by the machine/platform to remove
* all target endian dependencies from this file.
*/
-#if TARGET_BIG_ENDIAN
- s->default_endian_fb = true;
-#else
- s->default_endian_fb = false;
-#endif
+ s->default_endian_fb = target_words_bigendian();
+
vga_dirty_log_start(s);
return true;
PORTIO_END_OF_LIST(),
};
-static const MemoryRegionPortio vbe_portio_list[] = {
+static const MemoryRegionPortio vbe_portio_list_x86[] = {
{ 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
-# ifdef TARGET_I386
{ 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
-# endif
+ { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
+ PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionPortio vbe_portio_list_no_x86[] = {
+ { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
{ 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
PORTIO_END_OF_LIST(),
};
const MemoryRegionPortio **vbe_ports)
{
MemoryRegion *vga_mem;
+ MachineState *ms = MACHINE(qdev_get_machine());
+
+ /*
+ * We unfortunately need two VBE lists since non-x86 machines might
+ * not be able to do 16-bit accesses at unaligned addresses (0x1cf)
+ */
+ if (object_dynamic_cast(OBJECT(ms), TYPE_X86_MACHINE)) {
+ *vbe_ports = vbe_portio_list_x86;
+ } else {
+ *vbe_ports = vbe_portio_list_no_x86;
+ }
*vga_ports = vga_portio_list;
- *vbe_ports = vbe_portio_list;
vga_mem = g_malloc(sizeof(*vga_mem));
memory_region_init_io(vga_mem, obj, &vga_mem_ops, s,