Files
86Box/src/video/vid_rtg310x.c
TC1995 d2c6452ff5 Reworked the HTVGA/Video7 clocks. Fixes the HT209 2401 error on MCA.
Fixed 16 color in the Realtek 3106 card.
Reworked the Sierra 1148x for the second time.
Registers that only exist on 928/80x and up are not used by the 911/924 anymore.
2021-05-20 20:57:54 +02:00

381 lines
7.5 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.
*
* Emulation of the Realtek RTG series of VGA ISA chips.
*
*
*
* Authors: TheCollector1995, <mariogplayer90@gmail.com>
*
* Copyright 2021 TheCollector1995.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
#include <86box/vid_svga_render.h>
#define BIOS_ROM_PATH "roms/video/rtg/realtekrtg3106.BIN"
typedef struct {
const char *name;
int type;
svga_t svga;
rom_t bios_rom;
uint8_t bank3d6,
bank3d7;
uint32_t vram_size,
vram_mask;
} rtg_t;
static video_timings_t timing_rtg_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10};
static void rtg_recalcbanking(rtg_t *dev)
{
svga_t *svga = &dev->svga;
svga->write_bank = (dev->bank3d7 & 0x0f) * 65536;
if (svga->gdcreg[0x0f] & 4)
svga->read_bank = (dev->bank3d6 & 0x0f) * 65536;
else
svga->read_bank = svga->write_bank;
}
static uint8_t
rtg_in(uint16_t addr, void *priv)
{
rtg_t *dev = (rtg_t *)priv;
svga_t *svga = &dev->svga;
uint8_t ret = 0;
if (((addr & 0xfff0) == 0x3d0 ||
(addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60;
switch (addr) {
case 0x3ce:
return svga->gdcaddr;
case 0x3cf:
if (svga->gdcaddr == 0x0c)
return svga->gdcreg[0x0c] | 4;
else if ((svga->gdcaddr > 8) && (svga->gdcaddr != 0x0c))
return svga->gdcreg[svga->gdcaddr];
break;
case 0x3d4:
return svga->crtcreg;
case 0x3d5:
if (!(svga->crtc[0x1e] & 0x80) && (svga->crtcreg > 0x18))
return 0xff;
if (svga->crtcreg == 0x1a)
return dev->type << 6;
if (svga->crtcreg == 0x1e) {
if (dev->vram_size == 1024)
ret = 2;
else if (dev->vram_size == 512)
ret = 1;
else
ret = 0;
return svga->crtc[0x1e] | ret;
}
return svga->crtc[svga->crtcreg];
case 0x3d6:
return dev->bank3d6;
case 0x3d7:
return dev->bank3d7;
}
return svga_in(addr, svga);
}
static void
rtg_out(uint16_t addr, uint8_t val, void *priv)
{
rtg_t *dev = (rtg_t *)priv;
svga_t *svga = &dev->svga;
uint8_t old;
if (((addr & 0xfff0) == 0x3d0 ||
(addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60;
switch (addr) {
case 0x3ce:
svga->gdcaddr = val;
return;
case 0x3cf:
if (svga->gdcaddr > 8) {
svga->gdcreg[svga->gdcaddr] = val;
switch (svga->gdcaddr) {
case 0x0b:
case 0x0c:
svga->fullchange = changeframecount;
svga_recalctimings(svga);
break;
case 0x0f:
rtg_recalcbanking(dev);
return;
}
}
break;
case 0x3d4:
svga->crtcreg = val & 0x3f;
return;
case 0x3d5:
if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
return;
if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
val = (svga->crtc[7] & ~0x10) | (val & 0x10);
old = svga->crtc[svga->crtcreg];
svga->crtc[svga->crtcreg] = val;
if (svga->crtc[0x1e] & 0x80) {
switch (svga->crtcreg) {
case 0x19:
svga->vram_display_mask = (val & 0x20) ? dev->vram_mask : 0x3ffff;
svga->fullchange = changeframecount;
svga_recalctimings(svga);
break;
}
}
if (old != val) {
if (svga->crtcreg < 0x0e || svga->crtcreg > 0x10) {
svga->fullchange = changeframecount;
svga_recalctimings(svga);
}
}
break;
case 0x3d6:
dev->bank3d6 = val;
rtg_recalcbanking(dev);
return;
case 0x3d7:
dev->bank3d7 = val;
rtg_recalcbanking(dev);
return;
}
svga_out(addr, val, svga);
}
static void
rtg_recalctimings(svga_t *svga)
{
svga->ma_latch = ((svga->crtc[0x19] & 0x10) << 16) | ((svga->crtc[0x19] & 0x40) << 17);
svga->interlace = (svga->crtc[0x19] & 1);
/*Clock table not available, currently a guesswork*/
switch (((svga->miscout >> 2) & 3) | ((svga->gdcreg[0x0c] & 0x20) >> 3)) {
case 0:
case 1:
break;
case 2:
svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0;
break;
case 3:
svga->clock = (cpuclock * (double)(1ull << 32)) / 65100000.0;
break;
case 4:
svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0;
break;
case 5:
svga->clock = (cpuclock * (double)(1ull << 32)) / 50000000.0;
break;
case 6:
svga->clock = (cpuclock * (double)(1ull << 32)) / 80000000.0;
break;
case 7:
svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0;
break;
}
switch (svga->gdcreg[0x0c] & 3) {
case 1:
svga->clock /= 1.5;
break;
case 2:
svga->clock /= 2;
break;
case 3:
svga->clock /= 4;
break;
}
if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) {
switch (svga->gdcreg[5] & 0x60) {
case 0x00:
if (svga->seqregs[1] & 8) /*Low res (320)*/
svga->render = svga_render_4bpp_lowres;
else {
svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5);
svga->hdisp++;
svga->hdisp *= 8;
if (svga->hdisp == 1280)
svga->rowoffset >>= 1;
svga->render = svga_render_4bpp_highres;
}
break;
case 0x20: /*4 colours*/
if (svga->seqregs[1] & 8) /*Low res (320)*/
svga->render = svga_render_2bpp_lowres;
else
svga->render = svga_render_2bpp_highres;
break;
case 0x40: case 0x60:
if (svga->crtc[0x19] & 2) {
svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5);
svga->hdisp++;
svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8;
if (svga->hdisp == 1280) {
svga->hdisp >>= 1;
} else
svga->rowoffset <<= 1;
svga->render = svga_render_8bpp_highres;
}
break;
}
}
}
static void *
rtg_init(const device_t *info)
{
const char *fn;
rtg_t *dev;
dev = (rtg_t *)malloc(sizeof(rtg_t));
memset(dev, 0x00, sizeof(rtg_t));
dev->name = info->name;
dev->type = info->local;
fn = BIOS_ROM_PATH;
switch(dev->type) {
case 2: /* ISA RTG3106 */
dev->vram_size = device_get_config_int("memory") << 10;
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_rtg_isa);
svga_init(info, &dev->svga, dev, dev->vram_size,
rtg_recalctimings, rtg_in, rtg_out,
NULL, NULL);
io_sethandler(0x03c0, 32,
rtg_in,NULL,NULL, rtg_out,NULL,NULL, dev);
break;
}
dev->svga.bpp = 8;
dev->svga.miscout = 1;
dev->vram_mask = dev->vram_size - 1;
rom_init(&dev->bios_rom, (char *) fn,
0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
return(dev);
}
static void
rtg_close(void *priv)
{
rtg_t *dev = (rtg_t *)priv;
svga_close(&dev->svga);
free(dev);
}
static void
rtg_speed_changed(void *priv)
{
rtg_t *dev = (rtg_t *)priv;
svga_recalctimings(&dev->svga);
}
static void
rtg_force_redraw(void *priv)
{
rtg_t *dev = (rtg_t *)priv;
dev->svga.fullchange = changeframecount;
}
static int
rtg_available(void)
{
return rom_present(BIOS_ROM_PATH);
}
static const device_config_t rtg_config[] =
{
{
"memory", "Memory size", CONFIG_SELECTION, "", 1024, "", { 0 },
{
{
"256 KB", 256
},
{
"512 KB", 512
},
{
"1 MB", 1024
},
{
""
}
}
},
{
"", "", -1
}
};
const device_t realtek_rtg3106_device = {
"Realtek RTG3106 (ISA)",
DEVICE_ISA | DEVICE_AT,
2,
rtg_init, rtg_close, NULL,
{ rtg_available },
rtg_speed_changed,
rtg_force_redraw,
rtg_config
};