Merge pull request #1676 from 86Box/master

Bring the branch up to par with master.
This commit is contained in:
Miran Grča
2021-09-08 00:08:23 +02:00
committed by GitHub
26 changed files with 1576 additions and 196 deletions

668
src/video/vid_f82c425.c Normal file
View File

@@ -0,0 +1,668 @@
/*
* 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.
*
* Chips & Technologies 82C425 display controller emulation,
* with support for 640x200 LCD and SMARTMAP text contrast
* enhancement.
*
* Relevant literature:
*
* [1] Chips and Technologies, Inc., 82C425 CGA LCD/CRT Controller,
* Data Sheet, Revision No. 2.2, September 1991.
* <https://archive.org/download/82C425/82C425.pdf>
*
* [2] Pleva et al., COLOR TO MONOCHROME CONVERSION,
* U.S. Patent 4,977,398, Dec. 11, 1990.
* <https://pimg-fpiw.uspto.gov/fdd/98/773/049/0.pdf>
*
* Based on Toshiba T1000 plasma display emulation code.
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
* Lubomir Rintel, <lkundrak@v3.sk>
*
* Copyright 2018,2019 Fred N. van Kempen.
* Copyright 2018,2019 Miran Grca.
* Copyright 2018,2019 Sarah Walker.
* Copyright 2021 Lubomir Rintel.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include "cpu.h"
#include <86box/video.h>
#include <86box/vid_cga.h>
#define F82C425_XSIZE 640
#define F82C425_YSIZE 200
/* Mapping of attributes to colours */
static uint32_t smartmap[256][2];
static uint32_t colormap[4];
static video_timings_t timing_f82c425 = {VIDEO_ISA, 8,16,32, 8,16,32};
static uint8_t st_video_options;
static uint8_t st_enabled = 1;
static int8_t st_display_internal = -1;
void f82c425_video_options_set(uint8_t options)
{
st_video_options = options;
}
void f82c425_video_enable(uint8_t enabled)
{
st_enabled = enabled;
}
void f82c425_display_set(uint8_t internal)
{
st_display_internal = (int8_t)internal;
}
uint8_t f82c425_display_get()
{
return (uint8_t)st_display_internal;
}
typedef struct f82c425_t
{
mem_mapping_t mapping;
cga_t cga;
uint8_t crtcreg;
uint64_t dispontime, dispofftime;
int linepos, displine;
int dispon;
uint8_t video_options;
uint8_t *vram;
/* Registers specific to 82C425. */
uint8_t ac_limit;
uint8_t threshold;
uint8_t shift;
uint8_t hsync;
uint8_t vsync_blink;
uint8_t timing;
uint8_t function;
} f82c425_t;
/* Convert IRGB representation to RGBI,
* useful in SMARTMAP calculations. */
static inline uint8_t f82c425_rgbi(uint8_t irgb)
{
return ((irgb & 0x7) << 1) | (irgb >> 3);
}
/* Convert IRGB SMARTMAP output to a RGB representation of one of 4/8 grey
* shades we'd see on an actual V86P display: with some bias toward lighter
* shades and a backlight with yellow/green-ish tint. */
static inline uint32_t f82c425_makecol(uint8_t rgbi, int gs4, int inv)
{
uint8_t c;
gs4 = 1 + !!gs4;
if (!inv)
{
rgbi = 15 - rgbi;
}
c = 0x10 * gs4 * ((rgbi >> gs4) + 2);
return makecol(c, c + 0x08, c - 0x20);
}
/* Saturating/non-saturating addition for SMARTMAP(see below). */
static inline int f82c425_smartmap_add(int a, int b, int sat)
{
int c = a + b;
/* (SATURATING OR NON SATURATING) */
if (sat)
{
if (c < 0)
c = 0;
else if (c > 15)
c = 15;
}
return c & 0xf;
}
/* Calculate and cache mapping of CGA text color attribute to a
* shade of gray enhanced via the SMARTMAP algorithm.
*
* This is a straightforward implementation of the algorithm as described
* in U.S. Patent 4,977,398 [2]. The comments in capitals refer to portions
* of a figure on page 4. */
static void f82c425_smartmap(f82c425_t *f82c425)
{
int i;
for (i = 0; i < 256; i++) {
uint8_t bg = f82c425_rgbi(i >> 4);
uint8_t fg = f82c425_rgbi(i & 0xf);
/* FIG._4. */
if (abs(bg - fg) <= (f82c425->threshold & 0x0f))
{
/* FOREGROUND=BACKGROUND */
if (bg == fg)
{
/* SPECIAL CASE */
if (f82c425->shift == 0xff)
{
/* CHECK MOST SIGNIFICANT BIT */
if (fg & 0x8)
{
/* FULL WHITE */
fg = bg = 15;
}
else
{
/* FULL BLACK */
fg = bg = 0;
}
}
}
else
{
uint8_t sat = f82c425->threshold & 0x10;
/* DETERMINE WHICH IS LIGHT */
if (fg > bg)
{
fg = f82c425_smartmap_add(fg, f82c425->shift & 0x0f, sat);
bg = f82c425_smartmap_add(bg, -(f82c425->shift >> 4), sat);
}
else
{
fg = f82c425_smartmap_add(fg, -(f82c425->shift & 0x0f), sat);
bg = f82c425_smartmap_add(bg, f82c425->shift >> 4, sat);
}
}
}
smartmap[i][0] = f82c425_makecol(bg, f82c425->threshold & 0x20, f82c425->function & 0x80);
smartmap[i][1] = f82c425_makecol(fg, f82c425->threshold & 0x20, f82c425->function & 0x80);
}
}
/* Calculate mapping of 320x200 graphical mode colors. */
static void f82c425_colormap(f82c425_t *f82c425)
{
int i;
for (i = 0; i < 4; i++)
colormap[i] = f82c425_makecol(5 * i, 0, f82c425->function & 0x80);
}
static void f82c425_out(uint16_t addr, uint8_t val, void *p)
{
f82c425_t *f82c425 = (f82c425_t *)p;
if (addr == 0x3d4)
f82c425->crtcreg = val;
if (((f82c425->function & 0x01) == 0) && ((f82c425->crtcreg != 0xdf) || (addr != 0x3d5)))
return;
if (addr != 0x3d5 || f82c425->crtcreg <= 31)
{
cga_out(addr, val, &f82c425->cga);
return;
}
switch (f82c425->crtcreg)
{
case 0xd9:
f82c425->ac_limit = val;
break;
case 0xda:
f82c425->threshold = val;
f82c425_smartmap(f82c425);
break;
case 0xdb:
f82c425->shift = val;
f82c425_smartmap(f82c425);
break;
case 0xdc:
f82c425->hsync = val;
break;
case 0xdd:
f82c425->vsync_blink = val;
break;
case 0xde:
f82c425->timing = val;
break;
case 0xdf:
f82c425->function = val;
f82c425_smartmap(f82c425);
f82c425_colormap(f82c425);
break;
}
}
static uint8_t f82c425_in(uint16_t addr, void *p)
{
f82c425_t *f82c425 = (f82c425_t *)p;
if ((f82c425->function & 0x01) == 0)
return 0xff;
if (addr == 0x3d4)
return f82c425->crtcreg;
if (addr != 0x3d5 || f82c425->crtcreg <= 31)
return cga_in(addr, &f82c425->cga);
switch (f82c425->crtcreg)
{
case 0xd9:
return f82c425->ac_limit;
case 0xda:
return f82c425->threshold;
case 0xdb:
return f82c425->shift;
case 0xdc:
return f82c425->hsync;
case 0xdd:
return f82c425->vsync_blink;
case 0xde:
return f82c425->timing;
case 0xdf:
return f82c425->function;
}
return 0xff;
}
static void f82c425_write(uint32_t addr, uint8_t val, void *p)
{
f82c425_t *f82c425 = (f82c425_t *)p;
f82c425->vram[addr & 0x3fff] = val;
cycles -= 4;
}
static uint8_t f82c425_read(uint32_t addr, void *p)
{
f82c425_t *f82c425 = (f82c425_t *)p;
cycles -= 4;
return f82c425->vram[addr & 0x3fff];
}
static void f82c425_recalctimings(f82c425_t *f82c425)
{
double disptime;
double _dispontime, _dispofftime;
if (f82c425->function & 0x08)
{
cga_recalctimings(&f82c425->cga);
return;
}
disptime = 651;
_dispontime = 640;
_dispofftime = disptime - _dispontime;
f82c425->dispontime = (uint64_t)(_dispontime * xt_cpu_multi);
f82c425->dispofftime = (uint64_t)(_dispofftime * xt_cpu_multi);
}
/* Draw a row of text. */
static void f82c425_text_row(f82c425_t *f82c425)
{
uint32_t colors[2];
int x, c;
uint8_t chr, attr;
int drawcursor;
int cursorline;
int blink;
uint16_t addr;
uint8_t sc;
uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff;
uint16_t ca = (f82c425->cga.crtc[0x0f] | (f82c425->cga.crtc[0x0e] << 8)) & 0x3fff;
uint8_t sl = f82c425->cga.crtc[9] + 1;
int columns = f82c425->cga.crtc[1];
sc = (f82c425->displine) & 7;
addr = ((ma & ~1) + (f82c425->displine >> 3) * columns) * 2;
ma += (f82c425->displine >> 3) * columns;
if ((f82c425->cga.crtc[0x0a] & 0x60) == 0x20)
{
cursorline = 0;
}
else
{
cursorline = ((f82c425->cga.crtc[0x0a] & 0x0F) <= sc) &&
((f82c425->cga.crtc[0x0b] & 0x0F) >= sc);
}
for (x = 0; x < columns; x++)
{
chr = f82c425->vram[(addr + 2 * x) & 0x3FFF];
attr = f82c425->vram[(addr + 2 * x + 1) & 0x3FFF];
drawcursor = ((ma == ca) && cursorline &&
(f82c425->cga.cgamode & 0x8) && (f82c425->cga.cgablink & 0x10));
blink = ((f82c425->cga.cgablink & 0x10) && (f82c425->cga.cgamode & 0x20) &&
(attr & 0x80) && !drawcursor);
if (drawcursor)
{
colors[0] = smartmap[~attr & 0xff][0];
colors[1] = smartmap[~attr & 0xff][1];
}
else
{
colors[0] = smartmap[attr][0];
colors[1] = smartmap[attr][1];
}
if (blink)
colors[1] = colors[0];
if (f82c425->cga.cgamode & 0x01)
{
/* High resolution (80 cols) */
for (c = 0; c < sl; c++)
{
((uint32_t *)buffer32->line[f82c425->displine])[(x << 3) + c] =
colors[(fontdat[chr][sc] & (1 <<(c ^ 7))) ? 1 : 0];
}
}
else
{
/* Low resolution (40 columns, stretch pixels horizontally) */
for (c = 0; c < sl; c++)
{
((uint32_t *)buffer32->line[f82c425->displine])[(x << 4) + c*2] =
((uint32_t *)buffer32->line[f82c425->displine])[(x << 4) + c*2+1] =
colors[(fontdat[chr][sc] & (1 <<(c ^ 7))) ? 1 : 0];
}
}
++ma;
}
}
/* Draw a line in CGA 640x200 mode */
static void f82c425_cgaline6(f82c425_t *f82c425)
{
int x, c;
uint8_t dat;
uint16_t addr;
uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff;
addr = ((f82c425->displine) & 1) * 0x2000 +
(f82c425->displine >> 1) * 80 +
((ma & ~1) << 1);
for (x = 0; x < 80; x++)
{
dat = f82c425->vram[addr & 0x3FFF];
addr++;
for (c = 0; c < 8; c++)
{
((uint32_t *)buffer32->line[f82c425->displine])[x*8+c] =
colormap[dat & 0x80 ? 3 : 0];
dat = dat << 1;
}
}
}
/* Draw a line in CGA 320x200 mode. */
static void f82c425_cgaline4(f82c425_t *f82c425)
{
int x, c;
uint8_t dat, pattern;
uint16_t addr;
uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff;
addr = ((f82c425->displine) & 1) * 0x2000 +
(f82c425->displine >> 1) * 80 +
((ma & ~1) << 1);
for (x = 0; x < 80; x++)
{
dat = f82c425->vram[addr & 0x3FFF];
addr++;
for (c = 0; c < 4; c++)
{
pattern = (dat & 0xC0) >> 6;
if (!(f82c425->cga.cgamode & 0x08)) pattern = 0;
((uint32_t *)buffer32->line[f82c425->displine])[x*8+2*c] =
((uint32_t *)buffer32->line[f82c425->displine])[x*8+2*c+1] =
colormap[pattern & 3];
dat = dat << 2;
}
}
}
static void f82c425_poll(void *p)
{
f82c425_t *f82c425 = (f82c425_t *)p;
if (f82c425->video_options != st_video_options ||
!!(f82c425->function & 1) != st_enabled)
{
f82c425->video_options = st_video_options;
f82c425->function &= ~1;
f82c425->function |= st_enabled ? 1 : 0;
if (f82c425->function & 0x01)
mem_mapping_enable(&f82c425->mapping);
else
mem_mapping_disable(&f82c425->mapping);
}
/* Switch between internal LCD and external CRT display. */
if (st_display_internal != -1 && st_display_internal != !!(f82c425->function & 0x08))
{
if (st_display_internal)
{
f82c425->function &= ~0x08;
f82c425->timing &= ~0x20;
}
else
{
f82c425->function |= 0x08;
f82c425->timing |= 0x20;
}
f82c425_recalctimings(f82c425);
}
if (f82c425->function & 0x08)
{
cga_poll(&f82c425->cga);
return;
}
if (!f82c425->linepos)
{
timer_advance_u64(&f82c425->cga.timer, f82c425->dispofftime);
f82c425->cga.cgastat |= 1;
f82c425->linepos = 1;
if (f82c425->dispon)
{
if (f82c425->displine == 0)
{
video_wait_for_buffer();
}
switch (f82c425->cga.cgamode & 0x13)
{
case 0x12:
f82c425_cgaline6(f82c425);
break;
case 0x02:
f82c425_cgaline4(f82c425);
break;
case 0x00:
case 0x01:
f82c425_text_row(f82c425);
break;
}
}
f82c425->displine++;
/* Hardcode a fixed refresh rate and VSYNC timing */
if (f82c425->displine >= 216)
{
/* End of VSYNC */
f82c425->displine = 0;
f82c425->cga.cgastat &= ~8;
f82c425->dispon = 1;
}
else
if (f82c425->displine == (f82c425->cga.crtc[9] + 1) * f82c425->cga.crtc[6])
{
/* Start of VSYNC */
f82c425->cga.cgastat |= 8;
f82c425->dispon = 0;
}
}
else
{
if (f82c425->dispon)
f82c425->cga.cgastat &= ~1;
timer_advance_u64(&f82c425->cga.timer, f82c425->dispontime);
f82c425->linepos = 0;
if (f82c425->displine == 200)
{
/* Hardcode 640x200 window size */
if ((F82C425_XSIZE != xsize) || (F82C425_YSIZE != ysize) || video_force_resize_get())
{
xsize = F82C425_XSIZE;
ysize = F82C425_YSIZE;
set_screen_size(xsize, ysize);
if (video_force_resize_get())
video_force_resize_set(0);
}
video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize);
frames++;
/* Fixed 640x200 resolution */
video_res_x = F82C425_XSIZE;
video_res_y = F82C425_YSIZE;
switch (f82c425->cga.cgamode & 0x12)
{
case 0x12:
video_bpp = 1;
break;
case 0x02:
video_bpp = 2;
break;
default:
video_bpp = 0;
}
f82c425->cga.cgablink++;
}
}
}
static void *f82c425_init(const device_t *info)
{
f82c425_t *f82c425 = malloc(sizeof(f82c425_t));
memset(f82c425, 0, sizeof(f82c425_t));
cga_init(&f82c425->cga);
video_inform(VIDEO_FLAG_TYPE_CGA, &timing_f82c425);
/* Initialize registers that don't default to zero. */
f82c425->hsync = 0x40;
f82c425->vsync_blink = 0x72;
/* 16k video RAM */
f82c425->vram = malloc(0x4000);
timer_set_callback(&f82c425->cga.timer, f82c425_poll);
timer_set_p(&f82c425->cga.timer, f82c425);
/* Occupy memory between 0xB8000 and 0xBFFFF */
mem_mapping_add(&f82c425->mapping, 0xb8000, 0x8000, f82c425_read, NULL, NULL, f82c425_write, NULL, NULL, NULL, 0, f82c425);
/* Respond to CGA I/O ports */
io_sethandler(0x03d0, 0x000c, f82c425_in, NULL, NULL, f82c425_out, NULL, NULL, f82c425);
/* Initialize color maps for text & graphic modes */
f82c425_smartmap(f82c425);
f82c425_colormap(f82c425);
/* Start off in 80x25 text mode */
f82c425->cga.cgastat = 0xF4;
f82c425->cga.vram = f82c425->vram;
f82c425->video_options = 0x01;
return f82c425;
}
static void f82c425_close(void *p)
{
f82c425_t *f82c425 = (f82c425_t *)p;
free(f82c425->vram);
free(f82c425);
}
static void f82c425_speed_changed(void *p)
{
f82c425_t *f82c425 = (f82c425_t *)p;
f82c425_recalctimings(f82c425);
}
const device_t f82c425_video_device = {
"82C425 CGA LCD/CRT Controller",
0, 0,
f82c425_init, f82c425_close, NULL,
{ NULL },
f82c425_speed_changed,
NULL,
NULL
};

View File

@@ -279,11 +279,17 @@ static void
hercules_render_overscan_left(hercules_t *dev)
{
int i;
uint32_t width;
if (dev->ctrl & 0x02)
width = (((uint32_t) dev->crtc[1]) << 4);
else
width = (((uint32_t) dev->crtc[1]) * 9);
if ((dev->displine + 14) < 0)
return;
if ((((uint32_t) dev->crtc[1]) * 9) == 0)
if (width == 0)
return;
for (i = 0; i < 8; i++)
@@ -295,15 +301,21 @@ static void
hercules_render_overscan_right(hercules_t *dev)
{
int i;
uint32_t width;
if (dev->ctrl & 0x02)
width = (((uint32_t) dev->crtc[1]) << 4);
else
width = (((uint32_t) dev->crtc[1]) * 9);
if ((dev->displine + 14) < 0)
return;
if ((((uint32_t) dev->crtc[1]) * 9) == 0)
if (width == 0)
return;
for (i = 0; i < 8; i++)
buffer32->line[dev->displine + 14][8 + (((uint32_t) dev->crtc[1]) * 9) + i] = 0x00000000;
buffer32->line[dev->displine + 14][8 + width + i] = 0x00000000;
}

View File

@@ -649,7 +649,9 @@ ht216_recalctimings(svga_t *svga)
svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8;
svga->rowoffset <<= 1;
if ((svga->crtc[0x17] & 0x60) == 0x20) /*Would result in a garbled screen with trailing cursor glitches*/
svga->crtc[0x17] |= 0x40;
svga->force_byte_mode = 1;
else
svga->force_byte_mode = 0;
}
svga->render = svga_render_8bpp_highres;
}

View File

@@ -491,26 +491,45 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if ((s3->accel.cmd & 0x1000) && (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)))
val = (val >> 8) | (val << 8);
s3_accel_start(8, 1, val | (val << 16), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
val = (val >> 8) | (val << 8);
s3_accel_start(8, 1, val | (val << 16), 0, s3);
} else
s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3);
} else
s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3);
break;
case 0x200:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if ((s3->accel.cmd & 0x1000) && (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)))
val = (val >> 8) | (val << 8);
s3_accel_start(16, 1, val | (val << 16), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
val = (val >> 8) | (val << 8);
s3_accel_start(16, 1, val | (val << 16), 0, s3);
} else
s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3);
} else
s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3);
break;
case 0x400:
if (svga->crtc[0x53] & 0x08) {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if ((s3->accel.cmd & 0x1000) && (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)))
val = (val >> 8) | (val << 8);
s3_accel_start(32, 1, val | (val << 16), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
val = (val >> 8) | (val << 8);
s3_accel_start(32, 1, val | (val << 16), 0, s3);
} else
s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3);
} else
s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3);
} else {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
val = (val >> 8) | (val << 8);
s3_accel_start(16, 1, val | (val << 16), 0, s3);
} else
s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3);
} else
s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3);
}
@@ -518,10 +537,12 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val)
case 0x600:
if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868 || s3->chip >= S3_TRIO64V) {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if ((s3->accel.cmd & 0x1000) && (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)))
val = (val >> 8) | (val << 8);
s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3);
s3_accel_start(8, 1, val & 0xff, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
val = (val >> 8) | (val << 8);
s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3);
s3_accel_start(8, 1, val & 0xff, 0, s3);
}
}
}
break;
@@ -536,21 +557,31 @@ s3_accel_out_pixtrans_l(s3_t *s3, uint32_t val)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if ((s3->accel.cmd & 0x1000) && (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)))
val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
s3_accel_start(8, 1, val, 0, s3);
s3_accel_start(8, 1, val >> 16, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
s3_accel_start(8, 1, val, 0, s3);
s3_accel_start(8, 1, val >> 16, 0, s3);
} else {
s3_accel_start(1, 1, 0xffffffff, val, s3);
s3_accel_start(1, 1, 0xffffffff, val >> 16, s3);
}
} else {
s3_accel_start(2, 1, 0xffffffff, val, s3);
s3_accel_start(2, 1, 0xffffffff, val >> 16, s3);
s3_accel_start(1, 1, 0xffffffff, val, s3);
s3_accel_start(1, 1, 0xffffffff, val >> 16, s3);
}
break;
case 0x200:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if ((s3->accel.cmd & 0x1000) && (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)))
val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
s3_accel_start(16, 1, val, 0, s3);
s3_accel_start(16, 1, val >> 16, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
s3_accel_start(16, 1, val, 0, s3);
s3_accel_start(16, 1, val >> 16, 0, s3);
} else {
s3_accel_start(2, 1, 0xffffffff, val, s3);
s3_accel_start(2, 1, 0xffffffff, val >> 16, s3);
}
} else {
s3_accel_start(2, 1, 0xffffffff, val, s3);
s3_accel_start(2, 1, 0xffffffff, val >> 16, s3);
@@ -558,21 +589,26 @@ s3_accel_out_pixtrans_l(s3_t *s3, uint32_t val)
break;
case 0x400:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if ((s3->accel.cmd & 0x1000) && (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)))
val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
s3_accel_start(32, 1, val, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
s3_accel_start(32, 1, val, 0, s3);
} else
s3_accel_start(4, 1, 0xffffffff, val, s3);
} else
s3_accel_start(4, 1, 0xffffffff, val, s3);
break;
case 0x600:
if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868 || s3->chip >= S3_TRIO64V) {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if ((s3->accel.cmd & 0x1000) && (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)))
val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3);
s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3);
s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3);
s3_accel_start(8, 1, val & 0xff, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3);
s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3);
s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3);
s3_accel_start(8, 1, val & 0xff, 0, s3);
}
}
}
break;
@@ -1024,7 +1060,10 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val)
if (s3->accel.cmd & 0x100) {
if (!(s3->accel.cmd & 0x600)) {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3);
} else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3);
}
@@ -1039,59 +1078,51 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
} else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
break;
case 0x200:
/*Windows 95's built-in driver expects this to be loaded regardless of the byte swap bit (0xE2E9) in the 86c928*/
if (s3->accel.cmd & 0x1000) {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3);
else {
if (s3->chip == S3_86C928)
s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8));
else
s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3);
}
} else {
if (s3->chip == S3_86C928)
s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8));
else
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3);
}
} else {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
else {
if (s3->chip == S3_86C928)
s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8));
else
s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
}
} else {
if (s3->chip == S3_86C928)
s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8));
else
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
}
else {
if (s3->accel.cmd & 0x1000)
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3);
else
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
}
}
}
break;
case 0x400:
if (svga->crtc[0x53] & 0x08) {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
else
s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
} else
s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
}
break;
case 0x600:
if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip >= S3_TRIO64V) {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3);
s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3);
s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
}
}
}
break;
@@ -1111,59 +1142,51 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
} else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
break;
case 0x200:
/*Windows 95's built-in driver expects the upper 16 bits to be loaded instead of the whole 32-bit one, regardless of the byte swap bit (0xE2EB) in the 86c928*/
if (s3->accel.cmd & 0x1000) {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
if (s3->accel.cmd & 0x1000)
s3_accel_start(16, 1, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), 0, s3);
else {
if (s3->chip == S3_86C928)
s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[2] | (s3->accel.pix_trans[3] << 8));
else
s3_accel_start(16, 1, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), 0, s3);
}
} else {
if (s3->chip == S3_86C928)
s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8));
else
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), s3);
}
} else {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
else {
if (s3->chip == S3_86C928)
s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[2] | (s3->accel.pix_trans[3] << 8));
else
s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
}
} else {
if (s3->chip == S3_86C928)
s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8));
else
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
}
s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[2] | (s3->accel.pix_trans[3] << 8));
else {
if (s3->accel.cmd & 0x1000)
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), s3);
else
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
}
}
}
break;
case 0x400:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
else
s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
} else
s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
break;
case 0x600:
if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip >= S3_TRIO64V) {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, s3->accel.pix_trans[3], 0, s3);
s3_accel_start(8, 1, s3->accel.pix_trans[2], 0, s3);
s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3);
s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
s3_accel_start(8, 1, s3->accel.pix_trans[3], 0, s3);
s3_accel_start(8, 1, s3->accel.pix_trans[2], 0, s3);
s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3);
s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
}
}
}
break;
@@ -1353,14 +1376,20 @@ s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val)
if (s3->accel.cmd & 0x100) {
if ((s3->accel.cmd & 0x600) == 0x200) {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(16, 1, val, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(16, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3);
else
s3_accel_start(2, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3);
} else
s3_accel_start(2, 1, 0xffffffff, val, s3);
s3_accel_start(2, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3);
} else {
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, val, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3);
else
s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3);
} else
s3_accel_start(1, 1, 0xffffffff, val, s3);
s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3);
}
}
}
@@ -2720,8 +2749,14 @@ static void s3_recalctimings(svga_t *svga)
svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10));
if (((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) || (svga->crtc[0x3a] & 0x10)) {
if (((svga->crtc[0x17] & 0x60) == 0x20) && (svga->crtc[0x31] & 0x08))
svga->crtc[0x17] |= 0x40;
pclog("CRTC14 bit 6 byte mode = %02x, CRTC17 bit 6 byte mode = %02x, CRTC17 bit 5 word mode ma15 = %02x, CRTC31 bit 3 dword mode = %02x\n",
svga->crtc[0x14] & 0x40, svga->crtc[0x17] & 0x40, svga->crtc[0x17] & 0x20, svga->crtc[0x31] & 0x08);
if (svga->crtc[0x31] & 0x08) /*This would typically force dword mode, but we are encountering accel bugs with it, so force byte mode instead*/
svga->force_byte_mode = 1;
else
svga->force_byte_mode = 0;
switch (svga->bpp) {
case 8:
svga->render = svga_render_8bpp_highres;
@@ -2880,8 +2915,6 @@ static void s3_trio64v_recalctimings(svga_t *svga)
svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10));
if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) {
if (((svga->crtc[0x17] & 0x60) == 0x20) && (svga->crtc[0x31] & 0x08))
svga->crtc[0x17] |= 0x40;
switch (svga->bpp) {
case 8:
svga->render = svga_render_8bpp_highres;
@@ -3507,7 +3540,10 @@ s3_accel_in(uint16_t port, void *p)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3);
else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
} else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
break;
@@ -3532,13 +3568,19 @@ s3_accel_in(uint16_t port, void *p)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
} else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
break;
case 0x200:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3);
else
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
} else
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3);
break;
@@ -3560,13 +3602,19 @@ s3_accel_in(uint16_t port, void *p)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
} else
s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
break;
case 0x200:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3);
else
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
} else
s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3);
break;
@@ -3603,13 +3651,19 @@ s3_accel_in_w(uint16_t port, void *p)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, temp | (temp << 16), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(8, 1, temp | (temp << 16), 0, s3);
else
s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3);
} else
s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3);
break;
case 0x200:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(16, 1, temp | (temp << 16), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(16, 1, temp | (temp << 16), 0, s3);
else
s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3);
} else
s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3);
break;
@@ -3635,8 +3689,13 @@ s3_accel_in_l(uint16_t port, void *p)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, temp, 0, s3);
s3_accel_start(8, 1, temp >> 16, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
s3_accel_start(8, 1, temp, 0, s3);
s3_accel_start(8, 1, temp >> 16, 0, s3);
} else {
s3_accel_start(1, 1, 0xffffffff, temp, s3);
s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3);
}
} else {
s3_accel_start(1, 1, 0xffffffff, temp, s3);
s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3);
@@ -3644,8 +3703,13 @@ s3_accel_in_l(uint16_t port, void *p)
break;
case 0x200:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(16, 1, temp, 0, s3);
s3_accel_start(16, 1, temp >> 16, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
s3_accel_start(16, 1, temp, 0, s3);
s3_accel_start(16, 1, temp >> 16, 0, s3);
} else {
s3_accel_start(2, 1, 0xffffffff, temp, s3);
s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3);
}
} else {
s3_accel_start(2, 1, 0xffffffff, temp, s3);
s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3);
@@ -3757,15 +3821,21 @@ s3_accel_read(uint32_t addr, void *p)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, temp, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(8, 1, temp | (temp << 8) | (temp << 16) | (temp << 24), 0, s3);
else
s3_accel_start(1, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3);
} else
s3_accel_start(1, 1, 0xffffffff, temp, s3);
s3_accel_start(1, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3);
break;
case 0x200:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(16, 1, temp, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(16, 1, temp | (temp << 8) | (temp << 16) | (temp << 24), 0, s3);
else
s3_accel_start(2, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3);
} else
s3_accel_start(2, 1, 0xffffffff, temp, s3);
s3_accel_start(2, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3);
break;
}
}
@@ -3802,13 +3872,19 @@ s3_accel_read_w(uint32_t addr, void *p)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, temp | (temp << 16), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(8, 1, temp | (temp << 16), 0, s3);
else
s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3);
} else
s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3);
break;
case 0x200:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(16, 1, temp | (temp << 16), 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))
s3_accel_start(16, 1, temp | (temp << 16), 0, s3);
else
s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3);
} else
s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3);
break;
@@ -3954,8 +4030,13 @@ s3_accel_read_l(uint32_t addr, void *p)
switch (s3->accel.cmd & 0x600) {
case 0x000:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(8, 1, temp, 0, s3);
s3_accel_start(8, 1, temp >> 16, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
s3_accel_start(8, 1, temp, 0, s3);
s3_accel_start(8, 1, temp >> 16, 0, s3);
} else {
s3_accel_start(1, 1, 0xffffffff, temp, s3);
s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3);
}
} else {
s3_accel_start(1, 1, 0xffffffff, temp, s3);
s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3);
@@ -3963,8 +4044,13 @@ s3_accel_read_l(uint32_t addr, void *p)
break;
case 0x200:
if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) {
s3_accel_start(16, 1, temp, 0, s3);
s3_accel_start(16, 1, temp >> 16, 0, s3);
if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) {
s3_accel_start(16, 1, temp, 0, s3);
s3_accel_start(16, 1, temp >> 16, 0, s3);
} else {
s3_accel_start(2, 1, 0xffffffff, temp, s3);
s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3);
}
} else {
s3_accel_start(2, 1, 0xffffffff, temp, s3);
s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3);
@@ -4757,32 +4843,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
if (!cpu_input)
s3->accel.dat_count = 0;
/*If the mask source is the CPU, the color source can't be the same as the mask, or vice versa*/
if (cpu_input) {
if (mix_dat & mix_mask) {
if ((s3->accel.cmd & 0x600) != 0x600) {
if (((s3->accel.frgd_mix & 0x60) == 0x40) && ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)) {
cpu_dat = mix_dat;
count >>= 3;
}
}
} else {
if (cmd == 3) {
if (((s3->accel.frgd_mix & 0x60) == 0x40) && ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)) {
cpu_dat = mix_dat;
count >>= 3;
}
} else {
if ((s3->accel.cmd & 0x600) != 0x600) {
if (((s3->accel.bkgd_mix & 0x60) == 0x40) && ((s3->accel.multifunc[0xa] & 0xc0) == 0x80)) {
cpu_dat = mix_dat;
count >>= 3;
}
}
}
}
}
if (cpu_input && (((s3->accel.multifunc[0xa] & 0xc0) != 0x80) || (!(s3->accel.cmd & 2)))) {
if ((s3->bpp == 3) && count == 2) {
@@ -4806,6 +4866,9 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
else if (s3->bpp == 1)
rd_mask &= 0xffff;
if (s3->bpp == 0) compare &= 0xff;
if (s3->bpp == 1) compare &= 0xffff;
switch (s3->accel.cmd & 0x600)
{
case 0x000: mix_mask = 0x80; break;
@@ -4814,9 +4877,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_
case 0x600: mix_mask = (s3->chip == S3_TRIO32 || s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) ? 0x80 : 0x80000000; break;
}
if (s3->bpp == 0) compare &= 0xff;
if (s3->bpp == 1) compare &= 0xffff;
/*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled.
When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on
the NOP command)*/