Files
86Box/src/video/vid_incolor.c
OBattler 552a87ea3d Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g  / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00

1106 lines
25 KiB
C

/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Hercules InColor emulation.
*
* Version: @(#)vid_incolor.c 1.0.14 2019/02/08
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2008-2018 Sarah Walker.
* Copyright 2016-2018 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "../86box.h"
#include "../io.h"
#include "../timer.h"
#include "../lpt.h"
#include "../pit.h"
#include "../mem.h"
#include "../rom.h"
#include "../device.h"
#include "video.h"
#include "vid_incolor.h"
/* extended CRTC registers */
#define INCOLOR_CRTC_XMODE 20 /* xMode register */
#define INCOLOR_CRTC_UNDER 21 /* Underline */
#define INCOLOR_CRTC_OVER 22 /* Overstrike */
#define INCOLOR_CRTC_EXCEPT 23 /* Exception */
#define INCOLOR_CRTC_MASK 24 /* Plane display mask & write mask */
#define INCOLOR_CRTC_RWCTRL 25 /* Read/write control */
#define INCOLOR_CRTC_RWCOL 26 /* Read/write colour */
#define INCOLOR_CRTC_PROTECT 27 /* Latch protect */
#define INCOLOR_CRTC_PALETTE 28 /* Palette */
/* character width */
#define INCOLOR_CW ((dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) ? 8 : 9)
/* mode control register */
#define INCOLOR_CTRL_GRAPH 0x02
#define INCOLOR_CTRL_ENABLE 0x08
#define INCOLOR_CTRL_BLINK 0x20
#define INCOLOR_CTRL_PAGE1 0x80
/* CRTC status register */
#define INCOLOR_STATUS_HSYNC 0x01 /* horizontal sync */
#define INCOLOR_STATUS_LIGHT 0x02
#define INCOLOR_STATUS_VIDEO 0x08
#define INCOLOR_STATUS_ID 0x50 /* Card identification */
#define INCOLOR_STATUS_VSYNC 0x80 /* -vertical sync */
/* configuration switch register */
#define INCOLOR_CTRL2_GRAPH 0x01
#define INCOLOR_CTRL2_PAGE1 0x02
/* extended mode register */
#define INCOLOR_XMODE_RAMFONT 0x01
#define INCOLOR_XMODE_90COL 0x02
/* Read/write control */
#define INCOLOR_RWCTRL_WRMODE 0x30
#define INCOLOR_RWCTRL_POLARITY 0x40
/* exception register */
#define INCOLOR_EXCEPT_CURSOR 0x0F /* Cursor colour */
#define INCOLOR_EXCEPT_PALETTE 0x10 /* Enable palette register */
#define INCOLOR_EXCEPT_ALTATTR 0x20 /* Use alternate attributes */
/* Default palette */
static const uint8_t defpal[16] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
};
/* Mapping of inks to RGB */
static const uint8_t init_rgb[64][3] = {
/* rgbRGB */
{ 0x00, 0x00, 0x00 }, /* 000000 */
{ 0x00, 0x00, 0xaa }, /* 000001 */
{ 0x00, 0xaa, 0x00 }, /* 000010 */
{ 0x00, 0xaa, 0xaa }, /* 000011 */
{ 0xaa, 0x00, 0x00 }, /* 000100 */
{ 0xaa, 0x00, 0xaa }, /* 000101 */
{ 0xaa, 0xaa, 0x00 }, /* 000110 */
{ 0xaa, 0xaa, 0xaa }, /* 000111 */
{ 0x00, 0x00, 0x55 }, /* 001000 */
{ 0x00, 0x00, 0xff }, /* 001001 */
{ 0x00, 0xaa, 0x55 }, /* 001010 */
{ 0x00, 0xaa, 0xff }, /* 001011 */
{ 0xaa, 0x00, 0x55 }, /* 001100 */
{ 0xaa, 0x00, 0xff }, /* 001101 */
{ 0xaa, 0xaa, 0x55 }, /* 001110 */
{ 0xaa, 0xaa, 0xff }, /* 001111 */
{ 0x00, 0x55, 0x00 }, /* 010000 */
{ 0x00, 0x55, 0xaa }, /* 010001 */
{ 0x00, 0xff, 0x00 }, /* 010010 */
{ 0x00, 0xff, 0xaa }, /* 010011 */
{ 0xaa, 0x55, 0x00 }, /* 010100 */
{ 0xaa, 0x55, 0xaa }, /* 010101 */
{ 0xaa, 0xff, 0x00 }, /* 010110 */
{ 0xaa, 0xff, 0xaa }, /* 010111 */
{ 0x00, 0x55, 0x55 }, /* 011000 */
{ 0x00, 0x55, 0xff }, /* 011001 */
{ 0x00, 0xff, 0x55 }, /* 011010 */
{ 0x00, 0xff, 0xff }, /* 011011 */
{ 0xaa, 0x55, 0x55 }, /* 011100 */
{ 0xaa, 0x55, 0xff }, /* 011101 */
{ 0xaa, 0xff, 0x55 }, /* 011110 */
{ 0xaa, 0xff, 0xff }, /* 011111 */
{ 0x55, 0x00, 0x00 }, /* 100000 */
{ 0x55, 0x00, 0xaa }, /* 100001 */
{ 0x55, 0xaa, 0x00 }, /* 100010 */
{ 0x55, 0xaa, 0xaa }, /* 100011 */
{ 0xff, 0x00, 0x00 }, /* 100100 */
{ 0xff, 0x00, 0xaa }, /* 100101 */
{ 0xff, 0xaa, 0x00 }, /* 100110 */
{ 0xff, 0xaa, 0xaa }, /* 100111 */
{ 0x55, 0x00, 0x55 }, /* 101000 */
{ 0x55, 0x00, 0xff }, /* 101001 */
{ 0x55, 0xaa, 0x55 }, /* 101010 */
{ 0x55, 0xaa, 0xff }, /* 101011 */
{ 0xff, 0x00, 0x55 }, /* 101100 */
{ 0xff, 0x00, 0xff }, /* 101101 */
{ 0xff, 0xaa, 0x55 }, /* 101110 */
{ 0xff, 0xaa, 0xff }, /* 101111 */
{ 0x55, 0x55, 0x00 }, /* 110000 */
{ 0x55, 0x55, 0xaa }, /* 110001 */
{ 0x55, 0xff, 0x00 }, /* 110010 */
{ 0x55, 0xff, 0xaa }, /* 110011 */
{ 0xff, 0x55, 0x00 }, /* 110100 */
{ 0xff, 0x55, 0xaa }, /* 110101 */
{ 0xff, 0xff, 0x00 }, /* 110110 */
{ 0xff, 0xff, 0xaa }, /* 110111 */
{ 0x55, 0x55, 0x55 }, /* 111000 */
{ 0x55, 0x55, 0xff }, /* 111001 */
{ 0x55, 0xff, 0x55 }, /* 111010 */
{ 0x55, 0xff, 0xff }, /* 111011 */
{ 0xff, 0x55, 0x55 }, /* 111100 */
{ 0xff, 0x55, 0xff }, /* 111101 */
{ 0xff, 0xff, 0x55 }, /* 111110 */
{ 0xff, 0xff, 0xff }, /* 111111 */
};
typedef struct {
mem_mapping_t mapping;
uint8_t crtc[32];
int crtcreg;
uint8_t ctrl, ctrl2, stat;
uint64_t dispontime, dispofftime;
pc_timer_t timer;
int firstline, lastline;
int linepos, displine;
int vc, sc;
uint16_t ma, maback;
int con, coff, cursoron;
int dispon, blink;
int vsynctime;
int vadj;
uint8_t palette[16]; /* EGA-style 16 -> 64 palette registers */
uint8_t palette_idx; /* Palette write index */
uint8_t latch[4]; /* Memory read/write latches */
uint32_t rgb[64];
uint8_t *vram;
} incolor_t;
static video_timings_t timing_incolor = {VIDEO_ISA, 8, 16, 32, 8, 16, 32};
static void
recalc_timings(incolor_t *dev)
{
double disptime;
double _dispontime, _dispofftime;
disptime = dev->crtc[0] + 1;
_dispontime = dev->crtc[1];
_dispofftime = disptime - _dispontime;
_dispontime *= HERCCONST;
_dispofftime *= HERCCONST;
dev->dispontime = (uint64_t)(_dispontime);
dev->dispofftime = (uint64_t)(_dispofftime);
}
static void
incolor_out(uint16_t port, uint8_t val, void *priv)
{
incolor_t *dev = (incolor_t *)priv;
uint8_t old;
switch (port) {
case 0x3b0:
case 0x3b2:
case 0x3b4:
case 0x3b6:
dev->crtcreg = val & 31;
return;
case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7:
if (dev->crtcreg > 28) return;
/* Palette load register */
if (dev->crtcreg == INCOLOR_CRTC_PALETTE) {
dev->palette[dev->palette_idx % 16] = val;
++dev->palette_idx;
}
old = dev->crtc[dev->crtcreg];
dev->crtc[dev->crtcreg] = val;
if (dev->crtc[10] == 6 && dev->crtc[11] == 7) {
/*Fix for Generic Turbo XT BIOS,
* which sets up cursor registers wrong*/
dev->crtc[10] = 0xb;
dev->crtc[11] = 0xc;
}
if (old ^ val)
recalc_timings(dev);
return;
case 0x3b8:
old = dev->ctrl;
dev->ctrl = val;
if (old ^ val)
recalc_timings(dev);
return;
case 0x3bf:
dev->ctrl2 = val;
if (val & 2)
mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x10000);
else
mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x08000);
return;
}
}
static uint8_t
incolor_in(uint16_t port, void *priv)
{
incolor_t *dev = (incolor_t *)priv;
uint8_t ret = 0xff;
switch (port) {
case 0x3b0:
case 0x3b2:
case 0x3b4:
case 0x3b6:
ret = dev->crtcreg;
break;
case 0x3b1:
case 0x3b3:
case 0x3b5:
case 0x3b7:
if (dev->crtcreg > 28) break;
dev->palette_idx = 0; /* Read resets the palette index */
ret = dev->crtc[dev->crtcreg];
break;
case 0x3ba:
/* 0x50: InColor card identity */
ret = (dev->stat & 0xf) | ((dev->stat & 8) << 4) | 0x50;
break;
default:
break;
}
return ret;
}
static void
incolor_write(uint32_t addr, uint8_t val, void *priv)
{
incolor_t *dev = (incolor_t *)priv;
unsigned char wmask = dev->crtc[INCOLOR_CRTC_MASK];
unsigned char wmode = dev->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_WRMODE;
unsigned char fg = dev->crtc[INCOLOR_CRTC_RWCOL] & 0x0F;
unsigned char bg = (dev->crtc[INCOLOR_CRTC_RWCOL] >> 4)&0x0F;
unsigned char w = 0;
unsigned char vmask; /* Mask of bit within byte */
unsigned char pmask; /* Mask of plane within colour value */
unsigned char latch;
int plane;
addr &= 0xffff;
/* In text mode, writes to the bottom 16k always touch all 4 planes */
if (!(dev->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) {
dev->vram[addr] = val;
return;
}
/* There are four write modes:
* 0: 1 => foreground, 0 => background
* 1: 1 => foreground, 0 => source latch
* 2: 1 => source latch, 0 => background
* 3: 1 => source latch, 0 => ~source latch
*/
pmask = 1;
for (plane = 0; plane < 4; pmask <<= 1, wmask >>= 1, addr += 0x10000, plane++) {
if (wmask & 0x10) /* Ignore writes to selected plane */
{
continue;
}
latch = dev->latch[plane];
for (vmask = 0x80; vmask != 0; vmask >>= 1) {
switch (wmode) {
case 0x00:
if (val & vmask) w = (fg & pmask);
else w = (bg & pmask);
break;
case 0x10:
if (val & vmask) w = (fg & pmask);
else w = (latch & vmask);
break;
case 0x20:
if (val & vmask) w = (latch & vmask);
else w = (bg & pmask);
break;
case 0x30:
if (val & vmask) w = (latch & vmask);
else w = ((~latch) & vmask);
break;
}
/* w is nonzero to write a 1, zero to write a 0 */
if (w) dev->vram[addr] |= vmask;
else dev->vram[addr] &= ~vmask;
}
}
}
static uint8_t
incolor_read(uint32_t addr, void *priv)
{
incolor_t *dev = (incolor_t *)priv;
unsigned plane;
unsigned char lp = dev->crtc[INCOLOR_CRTC_PROTECT];
unsigned char value = 0;
unsigned char dc; /* "don't care" register */
unsigned char bg; /* background colour */
unsigned char fg;
unsigned char mask, pmask;
addr &= 0xffff;
/* Read the four planes into latches */
for (plane = 0; plane < 4; plane++, addr += 0x10000) {
dev->latch[plane] &= lp;
dev->latch[plane] |= (dev->vram[addr] & ~lp);
}
addr &= 0xffff;
/* In text mode, reads from the bottom 16k assume all planes have
* the same contents */
if (!(dev->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) {
return dev->latch[0];
}
/* For each pixel, work out if its colour matches the background */
for (mask = 0x80; mask != 0; mask >>= 1) {
fg = 0;
dc = dev->crtc[INCOLOR_CRTC_RWCTRL] & 0x0F;
bg = (dev->crtc[INCOLOR_CRTC_RWCOL] >> 4) & 0x0F;
for (plane = 0, pmask = 1; plane < 4; plane++, pmask <<= 1) {
if (dc & pmask) {
fg |= (bg & pmask);
} else if (dev->latch[plane] & mask) {
fg |= pmask;
}
}
if (bg == fg) value |= mask;
}
if (dev->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_POLARITY)
value = ~value;
return value;
}
static void
draw_char_rom(incolor_t *dev, int x, uint8_t chr, uint8_t attr)
{
int i;
int elg, blk;
unsigned ull;
unsigned val;
unsigned ifg, ibg;
const unsigned char *fnt;
uint32_t fg, bg;
int cw = INCOLOR_CW;
blk = 0;
if (dev->ctrl & INCOLOR_CTRL_BLINK)
{
if (attr & 0x80)
{
blk = (dev->blink & 16);
}
attr &= 0x7f;
}
if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR)
{
/* MDA-compatible attributes */
ibg = 0;
ifg = 7;
if ((attr & 0x77) == 0x70) /* Invert */
{
ifg = 0;
ibg = 7;
}
if (attr & 8)
{
ifg |= 8; /* High intensity FG */
}
if (attr & 0x80)
{
ibg |= 8; /* High intensity BG */
}
if ((attr & 0x77) == 0) /* Blank */
{
ifg = ibg;
}
ull = ((attr & 0x07) == 1) ? 13 : 0xffff;
}
else
{
/* CGA-compatible attributes */
ull = 0xffff;
ifg = attr & 0x0F;
ibg = (attr >> 4) & 0x0F;
}
if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE)
{
fg = dev->rgb[dev->palette[ifg]];
bg = dev->rgb[dev->palette[ibg]];
}
else
{
fg = dev->rgb[defpal[ifg]];
bg = dev->rgb[defpal[ibg]];
}
/* ELG set to stretch 8px character to 9px */
if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL)
{
elg = 0;
}
else
{
elg = ((chr >= 0xc0) && (chr <= 0xdf));
}
fnt = &(fontdatm[chr][dev->sc]);
if (blk)
{
val = 0x000; /* Blinking, draw all background */
}
else if (dev->sc == ull)
{
val = 0x1ff; /* Underscore, draw all foreground */
}
else
{
val = fnt[0] << 1;
if (elg)
{
val |= (val >> 1) & 1;
}
}
for (i = 0; i < cw; i++)
{
buffer32->line[dev->displine][x * cw + i] = (val & 0x100) ? fg : bg;
val = val << 1;
}
}
static void
draw_char_ram4(incolor_t *dev, int x, uint8_t chr, uint8_t attr)
{
int i;
int elg, blk;
unsigned ull;
unsigned val[4];
unsigned ifg, ibg, cfg, pmask, plane;
const unsigned char *fnt;
uint32_t fg;
int cw = INCOLOR_CW;
int blink = dev->ctrl & INCOLOR_CTRL_BLINK;
int altattr = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR;
int palette = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE;
blk = 0;
if (blink)
{
if (attr & 0x80)
{
blk = (dev->blink & 16);
}
attr &= 0x7f;
}
if (altattr)
{
/* MDA-compatible attributes */
ibg = 0;
ifg = 7;
if ((attr & 0x77) == 0x70) /* Invert */
{
ifg = 0;
ibg = 7;
}
if (attr & 8)
{
ifg |= 8; /* High intensity FG */
}
if (attr & 0x80)
{
ibg |= 8; /* High intensity BG */
}
if ((attr & 0x77) == 0) /* Blank */
{
ifg = ibg;
}
ull = ((attr & 0x07) == 1) ? 13 : 0xffff;
}
else
{
/* CGA-compatible attributes */
ull = 0xffff;
ifg = attr & 0x0F;
ibg = (attr >> 4) & 0x0F;
}
if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL)
{
elg = 0;
}
else
{
elg = ((chr >= 0xc0) && (chr <= 0xdf));
}
fnt = dev->vram + 0x4000 + 16 * chr + dev->sc;
if (blk)
{
/* Blinking, draw all background */
val[0] = val[1] = val[2] = val[3] = 0x000;
}
else if (dev->sc == ull)
{
/* Underscore, draw all foreground */
val[0] = val[1] = val[2] = val[3] = 0x1ff;
}
else
{
val[0] = fnt[0x00000] << 1;
val[1] = fnt[0x10000] << 1;
val[2] = fnt[0x20000] << 1;
val[3] = fnt[0x30000] << 1;
if (elg)
{
val[0] |= (val[0] >> 1) & 1;
val[1] |= (val[1] >> 1) & 1;
val[2] |= (val[2] >> 1) & 1;
val[3] |= (val[3] >> 1) & 1;
}
}
for (i = 0; i < cw; i++)
{
/* Generate pixel colour */
cfg = 0;
pmask = 1;
for (plane = 0; plane < 4; plane++, pmask = pmask << 1)
{
if (val[plane] & 0x100) cfg |= (ifg & pmask);
else cfg |= (ibg & pmask);
}
/* cfg = colour of foreground pixels */
if (altattr && (attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */
if (palette)
{
fg = dev->rgb[dev->palette[cfg]];
}
else
{
fg = dev->rgb[defpal[cfg]];
}
buffer32->line[dev->displine][x * cw + i] = fg;
val[0] = val[0] << 1;
val[1] = val[1] << 1;
val[2] = val[2] << 1;
val[3] = val[3] << 1;
}
}
static void
draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr)
{
int i;
int elg, blk, ul, ol, bld;
unsigned ull, oll, ulc = 0, olc = 0;
unsigned val[4];
unsigned ifg = 0, ibg, cfg, pmask, plane;
const unsigned char *fnt;
uint32_t fg;
int cw = INCOLOR_CW;
int blink = dev->ctrl & INCOLOR_CTRL_BLINK;
int altattr = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR;
int palette = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE;
int font = (attr & 0x0F);
if (font >= 12) font &= 7;
blk = 0;
if (blink && altattr)
{
if (attr & 0x40)
{
blk = (dev->blink & 16);
}
attr &= 0x7f;
}
if (altattr)
{
/* MDA-compatible attributes */
if (blink)
{
ibg = (attr & 0x80) ? 8 : 0;
bld = 0;
ol = (attr & 0x20) ? 1 : 0;
ul = (attr & 0x10) ? 1 : 0;
}
else
{
bld = (attr & 0x80) ? 1 : 0;
ibg = (attr & 0x40) ? 0x0F : 0;
ol = (attr & 0x20) ? 1 : 0;
ul = (attr & 0x10) ? 1 : 0;
}
}
else
{
/* CGA-compatible attributes */
ibg = 0;
ifg = (attr >> 4) & 0x0F;
ol = 0;
ul = 0;
bld = 0;
}
if (ul)
{
ull = dev->crtc[INCOLOR_CRTC_UNDER] & 0x0F;
ulc = (dev->crtc[INCOLOR_CRTC_UNDER] >> 4) & 0x0F;
if (ulc == 0) ulc = 7;
}
else
{
ull = 0xFFFF;
}
if (ol)
{
oll = dev->crtc[INCOLOR_CRTC_OVER] & 0x0F;
olc = (dev->crtc[INCOLOR_CRTC_OVER] >> 4) & 0x0F;
if (olc == 0) olc = 7;
}
else
{
oll = 0xFFFF;
}
if (dev->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL)
{
elg = 0;
}
else
{
elg = ((chr >= 0xc0) && (chr <= 0xdf));
}
fnt = dev->vram + 0x4000 + 16 * chr + 4096 * font + dev->sc;
if (blk)
{
/* Blinking, draw all background */
val[0] = val[1] = val[2] = val[3] = 0x000;
}
else if (dev->sc == ull)
{
/* Underscore, draw all foreground */
val[0] = val[1] = val[2] = val[3] = 0x1ff;
}
else
{
val[0] = fnt[0x00000] << 1;
val[1] = fnt[0x10000] << 1;
val[2] = fnt[0x20000] << 1;
val[3] = fnt[0x30000] << 1;
if (elg)
{
val[0] |= (val[0] >> 1) & 1;
val[1] |= (val[1] >> 1) & 1;
val[2] |= (val[2] >> 1) & 1;
val[3] |= (val[3] >> 1) & 1;
}
if (bld)
{
val[0] |= (val[0] >> 1);
val[1] |= (val[1] >> 1);
val[2] |= (val[2] >> 1);
val[3] |= (val[3] >> 1);
}
}
for (i = 0; i < cw; i++)
{
/* Generate pixel colour */
cfg = 0;
pmask = 1;
if (dev->sc == oll)
{
cfg = olc ^ ibg; /* Strikethrough */
}
else if (dev->sc == ull)
{
cfg = ulc ^ ibg; /* Underline */
}
else
{
for (plane = 0; plane < 4; plane++, pmask = pmask << 1)
{
if (val[plane] & 0x100)
{
if (altattr) cfg |= ((~ibg) & pmask);
else cfg |= ((~ifg) & pmask);
}
else if (altattr) cfg |= (ibg & pmask);
}
}
if (palette)
{
fg = dev->rgb[dev->palette[cfg]];
}
else
{
fg = dev->rgb[defpal[cfg]];
}
buffer32->line[dev->displine][x * cw + i] = fg;
val[0] = val[0] << 1;
val[1] = val[1] << 1;
val[2] = val[2] << 1;
val[3] = val[3] << 1;
}
}
static void
text_line(incolor_t *dev, uint16_t ca)
{
int drawcursor;
int x, c;
uint8_t chr, attr;
uint32_t col;
for (x = 0; x < dev->crtc[1]; x++) {
if (dev->ctrl & 8) {
chr = dev->vram[(dev->ma << 1) & 0xfff];
attr = dev->vram[((dev->ma << 1) + 1) & 0xfff];
} else
chr = attr = 0;
drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron);
switch (dev->crtc[INCOLOR_CRTC_XMODE] & 5) {
case 0:
case 4: /* ROM font */
draw_char_rom(dev, x, chr, attr);
break;
case 1: /* 4k RAMfont */
draw_char_ram4(dev, x, chr, attr);
break;
case 5: /* 48k RAMfont */
draw_char_ram48(dev, x, chr, attr);
break;
}
++dev->ma;
if (drawcursor) {
int cw = INCOLOR_CW;
uint8_t ink = dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_CURSOR;
if (ink == 0) ink = (attr & 0x08) | 7;
/* In MDA-compatible mode, cursor brightness comes from
* background */
if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR)
{
ink = (attr & 0x08) | (ink & 7);
}
if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE)
{
col = dev->rgb[dev->palette[ink]];
}
else
{
col = dev->rgb[defpal[ink]];
}
for (c = 0; c < cw; c++)
{
buffer32->line[dev->displine][x * cw + c] = col;
}
}
}
}
static void
graphics_line(incolor_t *dev)
{
uint8_t mask;
uint16_t ca;
int x, c, plane, col;
uint8_t ink;
uint16_t val[4];
/* Graphics mode. */
ca = (dev->sc & 3) * 0x2000;
if ((dev->ctrl & INCOLOR_CTRL_PAGE1) && (dev->ctrl2 & INCOLOR_CTRL2_PAGE1))
ca += 0x8000;
for (x = 0; x < dev->crtc[1]; x++) {
mask = dev->crtc[INCOLOR_CRTC_MASK]; /* Planes to display */
for (plane = 0; plane < 4; plane++, mask = mask >> 1)
{
if (dev->ctrl & 8) {
if (mask & 1)
val[plane] = (dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) |
dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1];
else val[plane] = 0;
} else
val[plane] = 0;
}
dev->ma++;
for (c = 0; c < 16; c++)
{
ink = 0;
for (plane = 0; plane < 4; plane++)
{
ink = ink >> 1;
if (val[plane] & 0x8000) ink |= 8;
val[plane] = val[plane] << 1;
}
/* Is palette in use? */
if (dev->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE)
col = dev->palette[ink];
else col = defpal[ink];
buffer32->line[dev->displine][(x << 4) + c] = dev->rgb[col];
}
}
}
static void
incolor_poll(void *priv)
{
incolor_t *dev = (incolor_t *)priv;
uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff;
int x;
int oldvc;
int oldsc;
if (! dev->linepos) {
timer_advance_u64(&dev->timer, dev->dispofftime);
dev->stat |= 1;
dev->linepos = 1;
oldsc = dev->sc;
if ((dev->crtc[8] & 3) == 3)
dev->sc = (dev->sc << 1) & 7;
if (dev->dispon) {
if (dev->displine < dev->firstline) {
dev->firstline = dev->displine;
video_wait_for_buffer();
}
dev->lastline = dev->displine;
if ((dev->ctrl & INCOLOR_CTRL_GRAPH) && (dev->ctrl2 & INCOLOR_CTRL2_GRAPH))
graphics_line(dev);
else
text_line(dev, ca);
}
dev->sc = oldsc;
if (dev->vc == dev->crtc[7] && !dev->sc)
dev->stat |= 8;
dev->displine++;
if (dev->displine >= 500)
dev->displine = 0;
} else {
timer_advance_u64(&dev->timer, dev->dispontime);
if (dev->dispon)
dev->stat &= ~1;
dev->linepos = 0;
if (dev->vsynctime) {
dev->vsynctime--;
if (! dev->vsynctime)
dev->stat &= ~8;
}
if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) {
dev->con = 0;
dev->coff = 1;
}
if (dev->vadj) {
dev->sc++;
dev->sc &= 31;
dev->ma = dev->maback;
dev->vadj--;
if (! dev->vadj) {
dev->dispon = 1;
dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff;
dev->sc = 0;
}
} else if (dev->sc == dev->crtc[9] || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) {
dev->maback = dev->ma;
dev->sc = 0;
oldvc = dev->vc;
dev->vc++;
dev->vc &= 127;
if (dev->vc == dev->crtc[6])
dev->dispon = 0;
if (oldvc == dev->crtc[4]) {
dev->vc = 0;
dev->vadj = dev->crtc[5];
if (!dev->vadj) dev->dispon=1;
if (!dev->vadj) dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff;
if ((dev->crtc[10] & 0x60) == 0x20) dev->cursoron = 0;
else dev->cursoron = dev->blink & 16;
}
if (dev->vc == dev->crtc[7]) {
dev->dispon = 0;
dev->displine = 0;
dev->vsynctime = 16;
if (dev->crtc[7]) {
if ((dev->ctrl & INCOLOR_CTRL_GRAPH) && (dev->ctrl2 & INCOLOR_CTRL2_GRAPH))
x = dev->crtc[1] << 4;
else
x = dev->crtc[1] * 9;
dev->lastline++;
if ((dev->ctrl & 8) &&
((x != xsize) || ((dev->lastline - dev->firstline) != ysize) || video_force_resize_get())) {
xsize = x;
ysize = dev->lastline - dev->firstline;
if (xsize < 64) xsize = 656;
if (ysize < 32) ysize = 200;
set_screen_size(xsize, ysize);
if (video_force_resize_get())
video_force_resize_set(0);
}
video_blit_memtoscreen(0, dev->firstline, 0, dev->lastline - dev->firstline, xsize, dev->lastline - dev->firstline);
frames++;
if ((dev->ctrl & INCOLOR_CTRL_GRAPH) && (dev->ctrl2 & INCOLOR_CTRL2_GRAPH)) {
video_res_x = dev->crtc[1] * 16;
video_res_y = dev->crtc[6] * 4;
video_bpp = 1;
} else {
video_res_x = dev->crtc[1];
video_res_y = dev->crtc[6];
video_bpp = 0;
}
}
dev->firstline = 1000;
dev->lastline = 0;
dev->blink++;
}
} else {
dev->sc++;
dev->sc &= 31;
dev->ma = dev->maback;
}
if ((dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1))))
dev->con = 1;
}
}
static void *
incolor_init(const device_t *info)
{
incolor_t *dev;
int c;
dev = (incolor_t *)malloc(sizeof(incolor_t));
memset(dev, 0x00, sizeof(incolor_t));
dev->vram = (uint8_t *)malloc(0x40000); /* 4 planes of 64k */
timer_add(&dev->timer, incolor_poll, dev, 1);
mem_mapping_add(&dev->mapping, 0xb0000, 0x08000,
incolor_read,NULL,NULL, incolor_write,NULL,NULL,
NULL, MEM_MAPPING_EXTERNAL, dev);
io_sethandler(0x03b0, 16,
incolor_in,NULL,NULL, incolor_out,NULL,NULL, dev);
for (c = 0; c < 64; c++) {
dev->rgb[c] = makecol32(init_rgb[c][0], init_rgb[c][1], init_rgb[c][2]);
}
/* Initialise CRTC regs to safe values */
dev->crtc[INCOLOR_CRTC_MASK ] = 0x0F; /* All planes displayed */
dev->crtc[INCOLOR_CRTC_RWCTRL] = INCOLOR_RWCTRL_POLARITY;
dev->crtc[INCOLOR_CRTC_RWCOL ] = 0x0F; /* White on black */
dev->crtc[INCOLOR_CRTC_EXCEPT] = INCOLOR_EXCEPT_ALTATTR;
for (c = 0; c < 16; c++)
dev->palette[c] = defpal[c];
dev->palette_idx = 0;
video_inform(VIDEO_FLAG_TYPE_MDA, &timing_incolor);
/* Force the LPT3 port to be enabled. */
lpt3_init(0x3BC);
return dev;
}
static void
incolor_close(void *priv)
{
incolor_t *dev = (incolor_t *)priv;
if (!dev)
return;
if (dev->vram)
free(dev->vram);
free(dev);
}
static void
speed_changed(void *priv)
{
incolor_t *dev = (incolor_t *)priv;
recalc_timings(dev);
}
const device_t incolor_device = {
"Hercules InColor",
DEVICE_ISA,
0,
incolor_init, incolor_close, NULL,
NULL,
speed_changed,
NULL,
NULL
};