summaryrefslogtreecommitdiffstats
path: root/usr.bin/doscmd/video.c
diff options
context:
space:
mode:
authortg <tg@FreeBSD.org>2001-07-24 11:44:20 +0000
committertg <tg@FreeBSD.org>2001-07-24 11:44:20 +0000
commit97507091ff20d3dc72113dfbd0c9532423d3acb4 (patch)
treef37909a1b76ac49ce96e941e94a62649b7210a4e /usr.bin/doscmd/video.c
parentdfb5f5d5892585bd43bea7a627c21456e0ff9687 (diff)
downloadFreeBSD-src-97507091ff20d3dc72113dfbd0c9532423d3acb4.zip
FreeBSD-src-97507091ff20d3dc72113dfbd0c9532423d3acb4.tar.gz
Rewrite video emulation. Features:
- slightly more accurate VGA hardware emulation; - more int 10 functions, especially wrt to palette handling; - first shot at graphics support; - mode switching. Bugs: - graphics too slow; - only 16 color modes work for now; - works only under X, and only with 16 bit TrueColor visuals; - far from being genuinely useful (I can play an old EGA game now, though (mahjongg.exe)). Also, the code has been cleaned up a bit (more to come in a separate commit).
Diffstat (limited to 'usr.bin/doscmd/video.c')
-rw-r--r--usr.bin/doscmd/video.c713
1 files changed, 713 insertions, 0 deletions
diff --git a/usr.bin/doscmd/video.c b/usr.bin/doscmd/video.c
new file mode 100644
index 0000000..6c5fabc3
--- /dev/null
+++ b/usr.bin/doscmd/video.c
@@ -0,0 +1,713 @@
+/*
+ * Copyright (c) 2001 The FreeBSD Project, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY The FreeBSD Project, Inc. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL The FreeBSD Project, Inc. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <err.h>
+#include <paths.h>
+#include <unistd.h>
+
+#include "doscmd.h"
+#include "AsyncIO.h"
+#include "tty.h"
+#include "video.h"
+#include "vparams.h"
+
+/*
+ * Global variables
+ */
+
+/* VGA registers */
+u_int8_t VGA_CRTC[CRTC_Size];
+u_int8_t VGA_ATC[ATC_Size];
+u_int8_t VGA_TSC[TSC_Size];
+u_int8_t VGA_GDC[GDC_Size];
+
+/* VGA status information */
+u_int8_t vga_status[64];
+
+/* Table of supported video modes. */
+vmode_t vmodelist[] = {
+ {0x00, 0x17, TEXT, 16, 8, 2, 0xb8000, FONT8x16},
+ {0x01, 0x17, TEXT, 16, 8, 2, 0xb8000, FONT8x16},
+ {0x02, 0x18, TEXT, 16, 8, 2, 0xb8000, FONT8x16},
+ {0x03, 0x18, TEXT, 16, 8, 2, 0xb8000, FONT8x16},
+ {0x04, 0x04, GRAPHICS, 4, 1, 0, 0xb8000, FONT8x8},
+ {0x05, 0x05, GRAPHICS, 4, 1, 0, 0xb8000, FONT8x8},
+ {0x06, 0x06, GRAPHICS, 2, 1, 0, 0xb8000, FONT8x8},
+ {0x07, 0x19, TEXT, 1, 8, 2, 0xb0000, FONT8x16},
+ {0x08, 0x08, NOMODE, 0, 0, 0, 0, 0},
+ {0x09, 0x09, NOMODE, 0, 0, 0, 0, 0},
+ {0x0a, 0x0a, NOMODE, 0, 0, 0, 0, 0},
+ {0x0b, 0x0b, NOMODE, 0, 0, 0, 0, 0},
+ {0x0c, 0x0c, NOMODE, 0, 0, 0, 0, 0},
+ {0x0d, 0x0d, GRAPHICS, 16, 8, 0, 0xa0000, FONT8x8},
+ {0x0e, 0x0e, GRAPHICS, 16, 4, 0, 0xa0000, FONT8x8},
+ {0x0f, 0x11, GRAPHICS, 1, 2, 1, 0xa0000, FONT8x14},
+ {0x10, 0x12, GRAPHICS, 16, 2, 1, 0xa0000, FONT8x14},
+ {0x11, 0x1a, GRAPHICS, 2, 1, 3, 0xa0000, FONT8x16},
+ {0x12, 0x1b, GRAPHICS, 16, 1, 3, 0xa0000, FONT8x16},
+ /* {0x13, 0x1c, GRAPHICS, 256, 1, 0, 0xa0000, FONT8x8}, */
+};
+
+#define NUMMODES (sizeof(vmodelist) / sizeof(vmode_t))
+
+/*
+ * Local functions
+ */
+static void init_vga(void);
+static u_int8_t video_inb(int);
+static void video_outb(int, u_int8_t);
+
+/*
+ * Local types and variables
+ */
+
+/* Save Table and assorted variables */
+struct VideoSaveTable {
+ u_short video_parameter_table[2];
+ u_short parameter_dynamic_save_area[2]; /* Not used */
+ u_short alphanumeric_character_set_override[2]; /* Not used */
+ u_short graphics_character_set_override[2]; /* Not used */
+ u_short secondary_save_table[2]; /* Not used */
+ u_short mbz[4];
+};
+
+struct SecondaryVideoSaveTable {
+ u_short length;
+ u_short display_combination_code_table[2];
+ u_short alphanumeric_character_set_override[2]; /* Not used */
+ u_short user_palette_profile_table[2]; /* Not used */
+ u_short mbz[6];
+};
+
+struct VideoSaveTable *vsp;
+struct SecondaryVideoSaveTable *svsp;
+
+/*
+ * Read and write the VGA port
+ */
+
+/* Save the selected index register */
+static u_int8_t crtc_index, atc_index, tsc_index, gdc_index;
+/* Toggle between index and data on port ATC_WritePort */
+static u_int8_t set_atc_index = 1;
+
+static u_int8_t
+video_inb(int port)
+{
+ switch(port) {
+ case CRTC_DataPortColor:
+ return VGA_CRTC[crtc_index];
+ case CRTC_IndexPortColor:
+ return crtc_index;
+ case ATC_ReadPort:
+ return VGA_ATC[atc_index];
+ case TSC_DataPort:
+ return VGA_TSC[tsc_index];
+ case TSC_IndexPort:
+ return tsc_index;
+ case GDC_DataPort:
+ return VGA_GDC[gdc_index];
+ case GDC_IndexPort:
+ return gdc_index;
+ case VGA_InputStatus1Port:
+ set_atc_index = 1;
+ return VGA_InputStatus1;
+ default:
+ return 0;
+ }
+}
+
+static void
+video_outb(int port, u_int8_t value)
+{
+/* XXX */
+#define row (CursRow0)
+#define col (CursCol0)
+
+ int cp;
+
+ switch (port) {
+ case CRTC_IndexPortColor:
+ crtc_index = value;
+ break;
+ case CRTC_DataPortColor:
+ VGA_CRTC[crtc_index] = value;
+ switch (crtc_index) {
+ case CRTC_CurLocHi: /* Update cursor position in BIOS */
+ cp = row * DpyCols + col;
+ cp &= 0xff;
+ cp |= value << 8;
+ row = cp / DpyCols;
+ col = cp % DpyCols;
+ break;
+ case CRTC_CurLocLo: /* Update cursor position in BIOS */
+ cp = row * DpyCols + col;
+ cp &= 0xff00;
+ cp |= value;
+ row = cp / DpyCols;
+ col = cp % DpyCols;
+ break;
+ default:
+ debug(D_VIDEO, "outb 0x%04x, 0x%02x at index 0x%02x\n",
+ port, value, crtc_index);
+ break;
+ }
+ case CRTC_IndexPortMono: /* Not used */
+ break;
+ case CRTC_DataPortMono: /* Not used */
+ break;
+ case ATC_WritePort:
+ if (set_atc_index)
+ atc_index = value;
+ else {
+ VGA_ATC[atc_index] = value;
+ switch (atc_index) {
+ default:
+ debug(D_VIDEO, "outb 0x%04x, 0x%02x at index 0x%02x\n",
+ port, value, crtc_index);
+ break;
+ }
+ }
+ set_atc_index = 1 - set_atc_index;
+ break;
+ case TSC_IndexPort:
+ tsc_index = value;
+ break;
+ case TSC_DataPort:
+ VGA_TSC[tsc_index] = value;
+ switch (tsc_index) {
+ default:
+ debug(D_VIDEO, "outb 0x%04x, 0x%02x at index 0x%02x\n",
+ port, value, crtc_index);
+ break;
+ }
+ break;
+ case GDC_IndexPort:
+ gdc_index = value;
+ break;
+ case GDC_DataPort:
+ VGA_GDC[gdc_index] = value;
+#if 0
+ switch (gdc_index) {
+ default:
+ debug(D_VIDEO, "outb 0x%04x, 0x%02x at index 0x%02x\n",
+ port, value, crtc_index);
+
+ break;
+ }
+#endif
+ break;
+ default:
+ debug(D_ALWAYS, "Unknown port 0x%4x\n", port);
+ break;
+ }
+
+ return;
+#undef row
+#undef col
+}
+
+void
+video_init()
+{
+ /* If we are running under X, get a connection to the X server and create
+ an empty window of size (1, 1). It makes a couple of init functions a
+ lot easier. */
+ if (xmode) {
+ init_window();
+
+ /* Set VGA emulator to a sane state */
+ init_vga();
+
+ /* Initialize mode 3 (text, 80x25, 16 colors) */
+ init_mode(3);
+ }
+
+ /* Define all known I/O port handlers */
+ if (!raw_kbd) {
+ define_input_port_handler(CRTC_IndexPortColor, video_inb);
+ define_input_port_handler(CRTC_DataPortColor, video_inb);
+ define_input_port_handler(ATC_ReadPort, video_inb);
+ define_input_port_handler(TSC_IndexPort, video_inb);
+ define_input_port_handler(TSC_DataPort, video_inb);
+ define_input_port_handler(GDC_IndexPort, video_inb);
+ define_input_port_handler(GDC_DataPort, video_inb);
+
+ define_output_port_handler(CRTC_IndexPortColor, video_outb);
+ define_output_port_handler(CRTC_DataPortColor, video_outb);
+ define_output_port_handler(ATC_WritePort, video_outb);
+ define_output_port_handler(TSC_IndexPort, video_outb);
+ define_output_port_handler(TSC_DataPort, video_outb);
+ define_output_port_handler(GDC_IndexPort, video_outb);
+ define_output_port_handler(GDC_DataPort, video_outb);
+ }
+
+ redirect0 = isatty(0) == 0 || !xmode ;
+ redirect1 = isatty(1) == 0 || !xmode ;
+ redirect2 = isatty(2) == 0 || !xmode ;
+
+ return;
+}
+
+void
+video_bios_init()
+{
+ u_char *p;
+ u_long vec;
+
+ if (raw_kbd)
+ return;
+
+ /*
+ * Put the Video Save Table Pointer @ C000:0000
+ * Put the Secondary Video Save Table Pointer @ C000:0020
+ * Put the Display Combination Code table @ C000:0040
+ * Put the Video Parameter table @ C000:1000 - C000:2FFF
+ */
+ BIOS_SaveTablePointer = 0xC0000000;
+
+ vsp = (struct VideoSaveTable *)0xC0000L;
+ memset(vsp, 0, sizeof(struct VideoSaveTable));
+ svsp = (struct SecondaryVideoSaveTable *)0xC0020L;
+
+ vsp->video_parameter_table[0] = 0x1000;
+ vsp->video_parameter_table[1] = 0xC000;
+
+ vsp->secondary_save_table[0] = 0x0020;
+ vsp->secondary_save_table[1] = 0xC000;
+
+ svsp->display_combination_code_table[0] = 0x0040;
+ svsp->display_combination_code_table[1] = 0xC000;
+
+ p = (u_char *)0xC0040;
+ *p++ = 2; /* Only support 2 combinations currently */
+ *p++ = 1; /* Version # */
+ *p++ = 8; /* We won't use more than type 8 */
+ *p++ = 0; /* Reserved */
+ *p++ = 0; *p++ = 0; /* No Display No Display */
+ *p++ = 0; *p++ = 8; /* No Display VGA Color */
+
+ memcpy((void *)0xC1000, videoparams, sizeof(videoparams));
+ ivec[0x1d] = 0xC0001000L; /* Video Parameter Table */
+
+ ivec[0x42] = ivec[0x10]; /* Copy of video interrupt */
+
+ /* Put the current font at C000:3000; the pixels are copied in
+ 'tty.c:load_font()'. */
+ ivec[0x1f] = 0xC0003000L;
+ ivec[0x43] = 0xC0003000L;
+
+ BIOSDATA[0x8a] = 1; /* Index into DCC table */
+
+ vec = insert_softint_trampoline();
+ ivec[0x10] = vec;
+ register_callback(vec, int10, "int 10");
+}
+
+/* Initialize the VGA emulator
+
+ XXX This is not nearly finished right now.
+*/
+static void
+init_vga(void)
+{
+ int i;
+
+ /* Zero-fill 'dac_rgb' on allocation; the default (EGA) table has only
+ 64 entries. */
+ dac_rgb = (struct dac_colors *)calloc(256, sizeof(struct dac_colors));
+ if (dac_rgb == NULL)
+ err(1, "Get memory for dac_rgb");
+
+ /* Copy the default DAC table to a working copy we can trash. */
+ for (i = 0; i < 64; i++)
+ dac_rgb[i] = dac_default64[i]; /* Structure copy */
+
+ /* Point 'palette[]' to the Attribute Controller space. We will only use
+ the first 16 slots. */
+ palette = VGA_ATC;
+
+ /* Get memory for the video RAM and adjust the plane pointers. */
+ vram = calloc(256 * 1024, 1); /* XXX */
+ if (vram == NULL)
+ warn("Could not get video memory; graphics modes not available.");
+
+ /* XXX There is probably a more efficient memory layout... */
+ vplane0 = vram;
+ vplane1 = vram + 0x10000;
+ vplane2 = vram + 0x20000;
+ vplane3 = vram + 0x30000;
+}
+
+/*
+ * Initialize the requested video mode.
+ */
+
+/* Indices into the video parameter table. We will use that array to
+ initialize the registers on startup and when the video mode changes. */
+#define CRTC_Ofs 10
+#define ATC_Ofs 35
+#define TSC_Ofs 5
+#define GDC_Ofs 55
+#define MiscOutput_Ofs 9
+
+void
+init_mode(int mode)
+{
+ vmode_t vmode;
+ int idx; /* Index into vmode */
+ int pidx; /* Index into videoparams */
+
+ debug(D_VIDEO, "Set video mode to 0x%02x\n", mode);
+
+ idx = find_vmode(mode & 0x7f);
+ if (idx == -1 || vmodelist[idx].type == NOMODE)
+ err(1, "Mode 0x%02x is not supported", mode);
+ vmode = vmodelist[idx];
+ pidx = vmode.paramindex;
+
+ /* Preset VGA registers. */
+ memcpy(VGA_CRTC, (u_int8_t *)&videoparams[pidx][CRTC_Ofs],
+ sizeof(VGA_CRTC));
+ memcpy(VGA_ATC, (u_int8_t *)&videoparams[pidx][ATC_Ofs],
+ sizeof(VGA_ATC));
+ /* Warning: the video parameter table does not contain the Sequencer's
+ Reset register. Its default value is 0x03.*/
+ VGA_TSC[TSC_Reset] = 0x03;
+ memcpy(VGA_TSC + 1, (u_int8_t *)&videoparams[pidx][TSC_Ofs],
+ sizeof(VGA_TSC) - 1);
+ memcpy(VGA_GDC, (u_int8_t *)&videoparams[pidx][GDC_Ofs],
+ sizeof(VGA_GDC));
+ VGA_MiscOutput = videoparams[pidx][MiscOutput_Ofs];
+
+ /* Paranoia */
+ if ((VGA_ATC[ATC_ModeCtrl] & 1) == 1 && vmode.type == TEXT)
+ err(1, "Text mode requested, but ATC switched to graphics mode!");
+ if ((VGA_ATC[ATC_ModeCtrl] & 1) == 0 && vmode.type == GRAPHICS)
+ err(1, "Graphics mode requested, but ATC switched to text mode!");
+
+ VideoMode = mode & 0x7f;
+ DpyCols = (u_int16_t)videoparams[pidx][0];
+ DpyPageSize = *(u_int16_t *)&videoparams[pidx][3];
+ ActivePageOfs = 0;
+ CursCol0 = 0;
+ CursRow0 = 0;
+ CursCol1 = 0;
+ CursRow1 = 0;
+ CursCol2 = 0;
+ CursRow2 = 0;
+ CursCol3 = 0;
+ CursRow3 = 0;
+ CursCol4 = 0;
+ CursRow4 = 0;
+ CursCol5 = 0;
+ CursRow5 = 0;
+ CursCol6 = 0;
+ CursRow6 = 0;
+ CursCol7 = 0;
+ CursRow7 = 0;
+ CursStart = VGA_CRTC[CRTC_CursStart];
+ CursEnd = VGA_CRTC[CRTC_CursEnd];
+ ActivePage = 0;
+ DpyRows = videoparams[pidx][1];
+ CharHeight = videoparams[pidx][2];
+
+ CRTCPort = vmode.numcolors > 1 ? CRTC_IndexPortColor : CRTC_IndexPortMono;
+ NumColors = vmode.numcolors;
+ NumPages = vmode.numpages;
+ VertResolution = vmode.vrescode;
+ vmem = (u_int16_t *)vmode.vmemaddr;
+
+ /* Copy VGA related BIOS variables from 'vga_status'. */
+ memcpy(&BIOS_VideoMode, &VideoMode, 33);
+ BIOS_DpyRows = DpyRows;
+ BIOS_CharHeight = CharHeight;
+
+ _BlockIO();
+ /* Load 'pixels[]' from default DAC values. */
+ update_pixels();
+
+ /* Update font. */
+ xfont = vmode.fontname;
+ load_font();
+
+ /* Resize window if necessary. */
+ resize_window();
+ _UnblockIO();
+
+ /* Mmap video memory for the graphics modes. Write access to 0xa0000 -
+ 0xaffff will generate a T_PAGEFAULT trap in VM86 mode (aside: why not a
+ SIGSEGV?), which is handled in 'trap.c:sigbus()'. */
+ if (vmode.type == GRAPHICS) {
+ vmem = mmap((void *)0xa0000, 64 * 1024, PROT_READ,
+ MAP_ANON | MAP_FIXED | MAP_INHERIT | MAP_SHARED, -1, 0);
+ if (vmem == NULL)
+ fatal("Could not mmap() video memory");
+
+ /* Create an XImage to display the graphics screen. */
+ get_ximage();
+ } else {
+ int i;
+
+ get_lines();
+ if (mode & 0x80)
+ return;
+ /* Initialize video memory with black background, white foreground */
+ vattr = 0x0700;
+ for (i = 0; i < DpyPageSize / 2; ++i)
+ vmem[i] = vattr;
+ }
+
+ return;
+}
+
+/* Find the requested mode in the 'vmodelist' table. This function returns the
+ index into this table; we will also use the index for accessing the
+ 'videoparams' array. */
+int find_vmode(int mode)
+{
+ int i;
+
+ for (i = 0; i < NUMMODES; i++)
+ if (vmodelist[i].modenumber == mode)
+ return i;
+
+ return -1;
+}
+
+
+
+/* Handle access to the graphics memory.
+
+ Simply changing the protection for the memory is not enough, unfortunately.
+ It would only work for the 256 color modes, where a memory byte contains
+ the color value of one pixel. The 16 color modes (and 4 color modes) make
+ use of four bit planes which overlay the first 64K of video memory. The
+ bits are distributed into these bit planes according to the GDC state, so
+ we will have to emulate the CPU instructions (see 'cpu.c:emu_instr()').
+
+ Handling the 256 color modes will be a bit easier, once we support those at
+ all. */
+int
+vmem_pageflt(struct sigframe *sf)
+{
+ regcontext_t *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
+
+ /* The ATC's Mode Control register tells us whether 4 or 8 color bits are
+ used */
+ if (VGA_ATC[ATC_ModeCtrl] & (1 << 6)) {
+ /* 256 colors, allow writes; the protection will be set back to
+ PROT_READ at the next display update */
+ mprotect(vmem, 64 * 1024, PROT_READ | PROT_WRITE);
+ return 0;
+ }
+
+ /* There's no need to change the protection in the 16 color modes, we will
+ write to 'vram'. Just emulate the next instruction. */
+ return emu_instr(REGS);
+}
+
+/* Write a byte to the video memory. 'vga_write()' is called from
+ 'cpu.c:write_word()' and will emulate the VGA write modes. Not all four
+ modes are implemented yet, nor are the addressing modes (odd/even, chain4).
+ (NB: I think the latter will have to be done in 'tty_graphics_update()').
+ */
+void
+vga_write(u_int32_t addr, u_int8_t val)
+{
+ u_int32_t dst;
+ u_int8_t *latch0, *latch1, *latch2, *latch3;
+ u_int8_t c0, c1, c2, c3;
+ u_int8_t m0, m1, m2, m3;
+ u_int8_t mask;
+#if 0
+ int i;
+
+ debug(D_VIDEO, "Write 0x%02x to 0x%x\n", val, addr);
+ debug(D_VIDEO, "GDC: ");
+ for (i = 0; i < sizeof(VGA_GDC); i++)
+ debug(D_VIDEO, "%02x ", VGA_GDC[i]);
+ debug(D_VIDEO, "\n");
+ debug(D_VIDEO, "TSC: ");
+ for (i = 0; i < sizeof(VGA_TSC); i++)
+ debug(D_VIDEO, "%02x ", VGA_TSC[i]);
+ debug(D_VIDEO, "\n");
+#endif
+
+ /* 'addr' lies between 0xa0000 and 0xaffff */
+ dst = addr - 0xa0000;
+
+ /* fill latches */
+ latch0 = vplane0 + dst;
+ latch1 = vplane1 + dst;
+ latch2 = vplane2 + dst;
+ latch3 = vplane3 + dst;
+
+ c0 = *latch0;
+ c1 = *latch1;
+ c2 = *latch2;
+ c3 = *latch3;
+
+ /* select write mode */
+ switch (VGA_GDC[GDC_Mode] & 3) {
+ case 0:
+ /* XXX to do: Enable Set Reset register */
+
+ mask = VGA_GDC[GDC_BitMask];
+
+ /* select function */
+ switch (VGA_GDC[GDC_DataRotate] & 0x18) {
+ case 0x00: /* replace */
+ m0 = VGA_GDC[GDC_SetReset] & 1 ? mask : 0x00;
+ m1 = VGA_GDC[GDC_SetReset] & 2 ? mask : 0x00;
+ m2 = VGA_GDC[GDC_SetReset] & 4 ? mask : 0x00;
+ m3 = VGA_GDC[GDC_SetReset] & 8 ? mask : 0x00;
+
+ c0 &= ~mask;
+ c1 &= ~mask;
+ c2 &= ~mask;
+ c3 &= ~mask;
+
+ c0 |= m0;
+ c1 |= m1;
+ c2 |= m2;
+ c3 |= m3;
+ break;
+ case 0x08: /* and */
+ m0 = VGA_GDC[GDC_SetReset] & 1 ? 0xff : ~mask;
+ m1 = VGA_GDC[GDC_SetReset] & 2 ? 0xff : ~mask;
+ m2 = VGA_GDC[GDC_SetReset] & 4 ? 0xff : ~mask;
+ m3 = VGA_GDC[GDC_SetReset] & 8 ? 0xff : ~mask;
+
+ c0 &= m0;
+ c1 &= m1;
+ c2 &= m2;
+ c3 &= m3;
+ break;
+ case 0x10: /* or */
+ m0 = VGA_GDC[GDC_SetReset] & 1 ? mask : 0x00;
+ m1 = VGA_GDC[GDC_SetReset] & 2 ? mask : 0x00;
+ m2 = VGA_GDC[GDC_SetReset] & 4 ? mask : 0x00;
+ m3 = VGA_GDC[GDC_SetReset] & 8 ? mask : 0x00;
+
+ c0 |= m0;
+ c1 |= m1;
+ c2 |= m2;
+ c3 |= m3;
+ break;
+ case 0x18: /* xor */
+ m0 = VGA_GDC[GDC_SetReset] & 1 ? mask : 0x00;
+ m1 = VGA_GDC[GDC_SetReset] & 2 ? mask : 0x00;
+ m2 = VGA_GDC[GDC_SetReset] & 4 ? mask : 0x00;
+ m3 = VGA_GDC[GDC_SetReset] & 8 ? mask : 0x00;
+
+ c0 ^= m0;
+ c1 ^= m1;
+ c2 ^= m2;
+ c3 ^= m3;
+ break;
+ }
+ break;
+ case 1:
+ /* not yet */
+ break;
+ case 2:
+ mask = VGA_GDC[GDC_BitMask];
+
+ /* select function */
+ switch (VGA_GDC[GDC_DataRotate] & 0x18) {
+ case 0x00: /* replace */
+ m0 = (val & 1 ? 0xff : 0x00) & mask;
+ m1 = (val & 2 ? 0xff : 0x00) & mask;
+ m2 = (val & 4 ? 0xff : 0x00) & mask;
+ m3 = (val & 8 ? 0xff : 0x00) & mask;
+
+ c0 &= ~mask;
+ c1 &= ~mask;
+ c2 &= ~mask;
+ c3 &= ~mask;
+
+ c0 |= m0;
+ c1 |= m1;
+ c2 |= m2;
+ c3 |= m3;
+ break;
+ case 0x08: /* AND */
+ m0 = (val & 1 ? 0xff : 0x00) | ~mask;
+ m1 = (val & 2 ? 0xff : 0x00) | ~mask;
+ m2 = (val & 4 ? 0xff : 0x00) | ~mask;
+ m3 = (val & 8 ? 0xff : 0x00) | ~mask;
+
+ c0 &= m0;
+ c1 &= m1;
+ c2 &= m2;
+ c3 &= m3;
+ break;
+ case 0x10: /* OR */
+ m0 = (val & 1 ? 0xff : 0x00) & mask;
+ m1 = (val & 2 ? 0xff : 0x00) & mask;
+ m2 = (val & 4 ? 0xff : 0x00) & mask;
+ m3 = (val & 8 ? 0xff : 0x00) & mask;
+
+ c0 |= m0;
+ c1 |= m1;
+ c2 |= m2;
+ c3 |= m3;
+ break;
+ case 0x18: /* XOR */
+ m0 = (val & 1 ? 0xff : 0x00) & mask;
+ m1 = (val & 2 ? 0xff : 0x00) & mask;
+ m2 = (val & 4 ? 0xff : 0x00) & mask;
+ m3 = (val & 8 ? 0xff : 0x00) & mask;
+
+ c0 ^= m0;
+ c1 ^= m1;
+ c2 ^= m2;
+ c3 ^= m3;
+ break;
+ }
+ break;
+ case 3:
+ /* not yet */
+ break;
+ }
+
+ /* write back changed byte, depending on Map Mask register */
+ if (VGA_TSC[TSC_MapMask] & 1)
+ *latch0 = c0;
+ if (VGA_TSC[TSC_MapMask] & 2)
+ *latch1 = c1;
+ if (VGA_TSC[TSC_MapMask] & 4)
+ *latch2 = c2;
+ if (VGA_TSC[TSC_MapMask] & 8)
+ *latch3 = c3;
+
+ return;
+}
OpenPOWER on IntegriCloud