Move components of video cards (external ramdacs and clock generators that could be paired with many cards) to their own folders. Reorganise video cmakelists

This commit is contained in:
starfrost013
2025-06-17 01:07:26 +01:00
parent 07b418d470
commit c826294a96
18 changed files with 80 additions and 30 deletions

View File

@@ -0,0 +1,338 @@
/*
* 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.
*
* ATI 68860 RAMDAC emulation (for Mach64)
*
* ATI 68860/68880 Truecolor DACs:
* REG08 (R/W):
* bit 0-? Always 2 ??
*
* REG0A (R/W):
* bit 0-? Always 1Dh ??
*
* REG0B (R/W): (GMR ?)
* bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp,
* A0h: 15bpp, A1h: 16bpp, C0h: 24bpp,
* E3h: 32bpp (80h for VGA modes ?)
*
* REG0C (R/W): Device Setup Register A
* bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT
* 2-3 Depends on Video memory (= VRAM width ?) .
* 1: Less than 1Mb, 2: 1Mb, 3: > 1Mb
* 5-6 Always set ?
* 7 If set can remove "snow" in some cases
* (A860_Delay_L ?) ??
*
*
*
* Authors: Sarah Walker, <https://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/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_8514a.h>
#include <86box/vid_svga.h>
#include <86box/vid_svga_render.h>
#include <86box/plat_unused.h>
typedef struct ati68860_ramdac_t {
uint8_t regs[16];
void (*render)(struct svga_t *svga);
int dac_addr;
int dac_pos;
int dac_r;
int dac_g;
PALETTE pal;
uint32_t pallook[2];
int ramdac_type;
} ati68860_ramdac_t;
void
ati68860_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga)
{
ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) priv;
switch (addr) {
case 0:
svga_out(0x3c8, val, svga);
break;
case 1:
svga_out(0x3c9, val, svga);
break;
case 2:
svga_out(0x3c6, val, svga);
break;
case 3:
svga_out(0x3c7, val, svga);
break;
default:
ramdac->regs[addr & 0xf] = val;
switch (addr & 0xf) {
case 0x4:
ramdac->dac_addr = val;
ramdac->dac_pos = 0;
break;
case 0x5:
switch (ramdac->dac_pos) {
case 0:
ramdac->dac_r = val;
ramdac->dac_pos++;
break;
case 1:
ramdac->dac_g = val;
ramdac->dac_pos++;
break;
case 2:
if (ramdac->dac_addr > 1)
break;
ramdac->pal[ramdac->dac_addr].r = ramdac->dac_r;
ramdac->pal[ramdac->dac_addr].g = ramdac->dac_g;
ramdac->pal[ramdac->dac_addr].b = val;
if (ramdac->ramdac_type == RAMDAC_8BIT)
ramdac->pallook[ramdac->dac_addr] = makecol32(ramdac->pal[ramdac->dac_addr].r,
ramdac->pal[ramdac->dac_addr].g,
ramdac->pal[ramdac->dac_addr].b);
else
ramdac->pallook[ramdac->dac_addr] = makecol32(video_6to8[ramdac->pal[ramdac->dac_addr].r & 0x3f],
video_6to8[ramdac->pal[ramdac->dac_addr].g & 0x3f],
video_6to8[ramdac->pal[ramdac->dac_addr].b & 0x3f]);
ramdac->dac_pos = 0;
ramdac->dac_addr = (ramdac->dac_addr + 1) & 255;
break;
default:
break;
}
break;
case 0xb:
switch (val) {
case 0x82:
ramdac->render = svga_render_4bpp_highres;
break;
case 0x83:
/*FIXME*/
ramdac->render = svga_render_8bpp_clone_highres;
break;
case 0xa0:
case 0xb0:
ramdac->render = svga_render_15bpp_highres;
break;
case 0xa1:
case 0xb1:
ramdac->render = svga_render_16bpp_highres;
break;
case 0xc0:
case 0xd0:
ramdac->render = svga_render_24bpp_highres;
break;
case 0xe2:
case 0xf7:
ramdac->render = svga_render_32bpp_highres;
break;
case 0xe3:
ramdac->render = svga_render_ABGR8888_highres;
break;
case 0xf2:
ramdac->render = svga_render_RGBA8888_highres;
break;
default:
/*FIXME*/
ramdac->render = svga_render_8bpp_clone_highres;
break;
}
break;
case 0xc:
svga_set_ramdac_type(svga, (val & 1) ? RAMDAC_6BIT : RAMDAC_8BIT);
break;
default:
break;
}
break;
}
}
uint8_t
ati68860_ramdac_in(uint16_t addr, void *priv, svga_t *svga)
{
const ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) priv;
uint8_t temp = 0;
switch (addr) {
case 0:
temp = svga_in(0x3c8, svga);
break;
case 1:
temp = svga_in(0x3c9, svga);
break;
case 2:
temp = svga_in(0x3c6, svga);
break;
case 3:
temp = svga_in(0x3c7, svga);
break;
case 4:
case 8:
temp = 2;
break;
case 6:
case 0xa:
temp = 0x1d;
break;
case 0xf:
temp = 0xd0;
break;
default:
temp = ramdac->regs[addr & 0xf];
break;
}
return temp;
}
void
ati68860_set_ramdac_type(void *priv, int type)
{
ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) priv;
if (ramdac->ramdac_type != type) {
ramdac->ramdac_type = type;
for (uint8_t c = 0; c < 2; c++) {
if (ramdac->ramdac_type == RAMDAC_8BIT)
ramdac->pallook[c] = makecol32(ramdac->pal[c].r, ramdac->pal[c].g,
ramdac->pal[c].b);
else
ramdac->pallook[c] = makecol32(video_6to8[ramdac->pal[c].r & 0x3f], video_6to8[ramdac->pal[c].g & 0x3f],
video_6to8[ramdac->pal[c].b & 0x3f]);
}
}
}
static void *
ati68860_ramdac_init(UNUSED(const device_t *info))
{
ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) malloc(sizeof(ati68860_ramdac_t));
memset(ramdac, 0, sizeof(ati68860_ramdac_t));
/*FIXME*/
ramdac->render = svga_render_8bpp_clone_highres;
return ramdac;
}
void
ati68860_ramdac_set_render(void *priv, svga_t *svga)
{
ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) priv;
svga->render = ramdac->render;
}
void
ati68860_ramdac_set_pallook(void *priv, int i, uint32_t col)
{
ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) priv;
ramdac->pallook[i] = col;
}
void
ati68860_hwcursor_draw(svga_t *svga, int displine)
{
const ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) svga->ramdac;
int comb;
int offset;
int x_pos;
int y_pos;
int shift = 0;
uint16_t dat;
uint32_t col0 = ramdac->pallook[0];
uint32_t col1 = ramdac->pallook[1];
uint32_t *p;
offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff;
if (svga->packed_4bpp)
shift = 1;
for (int x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += (8 >> shift)) {
if (shift) {
dat = svga->vram[(svga->dac_hwcursor_latch.addr) & svga->vram_mask] & 0x0f;
dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 1) & svga->vram_mask] << 4);
dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 2) & svga->vram_mask] << 8);
dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 3) & svga->vram_mask] << 12);
} else {
dat = svga->vram[svga->dac_hwcursor_latch.addr & svga->vram_mask];
dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 1) & svga->vram_mask] << 8);
}
for (int xx = 0; xx < (8 >> shift); xx++) {
comb = (dat >> (xx << 1)) & 0x03;
y_pos = displine;
x_pos = offset + svga->x_add;
p = buffer32->line[y_pos];
if (offset >= svga->dac_hwcursor_latch.x) {
switch (comb) {
case 0:
p[x_pos] = col0;
break;
case 1:
p[x_pos] = col1;
break;
case 3:
p[x_pos] ^= 0xffffff;
break;
default:
break;
}
}
offset++;
}
svga->dac_hwcursor_latch.addr += 2;
}
}
static void
ati68860_ramdac_close(void *priv)
{
ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t ati68860_ramdac_device = {
.name = "ATI-68860 RAMDAC",
.internal_name = "ati68860_ramdac",
.flags = 0,
.local = 0,
.init = ati68860_ramdac_init,
.close = ati68860_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,167 @@
/*
* 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 Mach32-compatible ATI 68875 RAMDAC and clones.
*
*
*
* Authors: TheCollector1995.
*
* Copyright 2022-2023 TheCollector1995.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
#include <86box/vid_svga_render.h>
#include <86box/plat_unused.h>
typedef struct ati68875_ramdac_t {
uint8_t gen_cntl;
uint8_t in_clk_sel;
uint8_t out_clk_sel;
uint8_t mux_cntl;
uint8_t palette_page_sel;
uint8_t test_reg;
} ati68875_ramdac_t;
void
ati68875_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *priv, svga_t *svga)
{
ati68875_ramdac_t *ramdac = (ati68875_ramdac_t *) priv;
uint8_t rs = (addr & 0x03);
rs |= (!!rs2 << 2);
rs |= (!!rs3 << 3);
switch (rs) {
case 0x00: /* Palette Write Index Register (RS value = 0000) */
case 0x01: /* Palette Data Register (RS value = 0001) */
case 0x02: /* Pixel Read Mask Register (RS value = 0010) */
case 0x03:
svga_out(addr, val, svga);
break;
case 0x08: /* General Control Register (RS value = 1000) */
ramdac->gen_cntl = val;
break;
case 0x09: /* Input Clock Selection Register (RS value = 1001) */
ramdac->in_clk_sel = val;
break;
case 0x0a: /* Output Clock Selection Register (RS value = 1010) */
ramdac->out_clk_sel = val;
break;
case 0x0b: /* MUX Control Register (RS value = 1011) */
ramdac->mux_cntl = val;
break;
case 0x0c: /* Palette Page Register (RS value = 1100) */
ramdac->palette_page_sel = val;
break;
case 0x0e: /* Test Register (RS value = 1110) */
ramdac->test_reg = val;
break;
case 0x0f: /* Reset State (RS value = 1111) */
ramdac->mux_cntl = 0x2d;
break;
default:
break;
}
return;
}
uint8_t
ati68875_ramdac_in(uint16_t addr, int rs2, int rs3, void *priv, svga_t *svga)
{
const ati68875_ramdac_t *ramdac = (ati68875_ramdac_t *) priv;
uint8_t rs = (addr & 0x03);
uint8_t temp = 0;
rs |= (!!rs2 << 2);
rs |= (!!rs3 << 3);
switch (rs) {
case 0x00: /* Palette Write Index Register (RS value = 0000) */
case 0x01: /* Palette Data Register (RS value = 0001) */
case 0x02: /* Pixel Read Mask Register (RS value = 0010) */
case 0x03:
temp = svga_in(addr, svga);
break;
case 0x08: /* General Control Register (RS value = 1000) */
temp = ramdac->gen_cntl;
break;
case 0x09: /* Input Clock Selection Register (RS value = 1001) */
temp = ramdac->in_clk_sel;
break;
case 0x0a: /* Output Clock Selection Register (RS value = 1010) */
temp = ramdac->out_clk_sel;
break;
case 0x0b: /* MUX Control Register (RS value = 1011) */
temp = ramdac->mux_cntl;
break;
case 0x0c: /* Palette Page Register (RS value = 1100) */
temp = ramdac->palette_page_sel;
break;
case 0x0e: /* Test Register (RS value = 1110) */
switch (ramdac->test_reg & 0x07) {
case 0x03:
temp = 0x75;
break;
default:
break;
}
break;
default:
break;
}
return temp;
}
static void *
ati68875_ramdac_init(UNUSED(const device_t *info))
{
ati68875_ramdac_t *ramdac = (ati68875_ramdac_t *) malloc(sizeof(ati68875_ramdac_t));
memset(ramdac, 0, sizeof(ati68875_ramdac_t));
ramdac->mux_cntl = 0x2d;
return ramdac;
}
static void
ati68875_ramdac_close(void *priv)
{
ati68875_ramdac_t *ramdac = (ati68875_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t ati68875_ramdac_device = {
.name = "ATI 68875 RAMDAC",
.internal_name = "ati68875_ramdac",
.flags = 0,
.local = 0,
.init = ati68875_ramdac_init,
.close = ati68875_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,217 @@
/*
* 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 a AT&T 20c490/491 and 492/493 RAMDAC.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2016-2018 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
typedef struct att49x_ramdac_t {
int type;
int state;
uint8_t ctrl;
} att49x_ramdac_t;
enum {
ATT_490 = 0,
ATT_491,
ATT_492
};
static void
att49x_ramdac_control(uint8_t val, void *priv, svga_t *svga)
{
att49x_ramdac_t *ramdac = (att49x_ramdac_t *) priv;
ramdac->ctrl = val;
switch ((ramdac->ctrl >> 5) & 7) {
case 0:
case 1:
case 2:
case 3:
svga->bpp = 8;
break;
case 4:
case 5:
svga->bpp = 15;
break;
case 6:
svga->bpp = 16;
break;
case 7:
svga->bpp = 24;
break;
default:
break;
}
if (ramdac->type == ATT_490 || ramdac->type == ATT_491)
svga_set_ramdac_type(svga, (val & 2) ? RAMDAC_8BIT : RAMDAC_6BIT);
svga_recalctimings(svga);
}
void
att49x_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga)
{
att49x_ramdac_t *ramdac = (att49x_ramdac_t *) priv;
uint8_t rs = (addr & 0x03);
rs |= ((!!rs2) << 2);
switch (rs) {
case 0x00:
case 0x01:
case 0x03:
case 0x04:
case 0x05:
case 0x07:
svga_out(addr, val, svga);
ramdac->state = 0;
break;
case 0x02:
switch (ramdac->state) {
case 4:
att49x_ramdac_control(val, ramdac, svga);
break;
default:
svga_out(addr, val, svga);
break;
}
break;
case 0x06:
att49x_ramdac_control(val, ramdac, svga);
ramdac->state = 0;
break;
default:
break;
}
}
uint8_t
att49x_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga)
{
att49x_ramdac_t *ramdac = (att49x_ramdac_t *) priv;
uint8_t temp = 0xff;
uint8_t rs = (addr & 0x03);
rs |= ((!!rs2) << 2);
switch (rs) {
case 0x00:
case 0x01:
case 0x03:
case 0x04:
case 0x05:
case 0x07:
temp = svga_in(addr, svga);
ramdac->state = 0;
break;
case 0x02:
switch (ramdac->state) {
case 1:
case 2:
case 3:
temp = 0x00;
ramdac->state++;
break;
case 4:
temp = ramdac->ctrl;
ramdac->state = 0;
break;
default:
temp = svga_in(addr, svga);
ramdac->state++;
break;
}
break;
case 0x06:
temp = ramdac->ctrl;
ramdac->state = 0;
break;
default:
break;
}
return temp;
}
static void *
att49x_ramdac_init(const device_t *info)
{
att49x_ramdac_t *ramdac = (att49x_ramdac_t *) malloc(sizeof(att49x_ramdac_t));
memset(ramdac, 0, sizeof(att49x_ramdac_t));
ramdac->type = info->local;
return ramdac;
}
static void
att49x_ramdac_close(void *priv)
{
att49x_ramdac_t *ramdac = (att49x_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t att490_ramdac_device = {
.name = "AT&T 20c490 RAMDAC",
.internal_name = "att490_ramdac",
.flags = 0,
.local = ATT_490,
.init = att49x_ramdac_init,
.close = att49x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t att491_ramdac_device = {
.name = "AT&T 20c491 RAMDAC",
.internal_name = "att491_ramdac",
.flags = 0,
.local = ATT_491,
.init = att49x_ramdac_init,
.close = att49x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t att492_ramdac_device = {
.name = "AT&T 20c492 RAMDAC",
.internal_name = "att492_ramdac",
.flags = 0,
.local = ATT_492,
.init = att49x_ramdac_init,
.close = att49x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,190 @@
/*
* 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 a AT&T 2xc498 RAMDAC.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2016-2018 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
typedef struct att498_ramdac_t {
int type;
int state;
int loop;
uint8_t ctrl;
} att498_ramdac_t;
static void
att498_ramdac_control(uint8_t val, void *priv, svga_t *svga)
{
att498_ramdac_t *ramdac = (att498_ramdac_t *) priv;
ramdac->ctrl = val;
if (val == 0xff)
return;
switch ((ramdac->ctrl >> 4) & 0x0f) {
default:
svga->bpp = 8;
break;
case 1:
if (ramdac->ctrl & 4)
svga->bpp = 15;
else
svga->bpp = 8;
break;
case 3:
case 6:
svga->bpp = 16;
break;
case 5:
case 7:
svga->bpp = 32;
break;
case 0x0e:
svga->bpp = 24;
break;
}
svga_set_ramdac_type(svga, (ramdac->ctrl & 2) ? RAMDAC_8BIT : RAMDAC_6BIT);
svga_recalctimings(svga);
}
void
att498_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga)
{
att498_ramdac_t *ramdac = (att498_ramdac_t *) priv;
uint8_t rs = (addr & 0x03);
rs |= ((!!rs2) << 2);
switch (rs) {
case 0x00:
case 0x01:
case 0x03:
case 0x04:
case 0x05:
case 0x07:
svga_out(addr, val, svga);
ramdac->state = 0;
break;
case 0x02:
switch (ramdac->state) {
case 4:
att498_ramdac_control(val, ramdac, svga);
break;
default:
svga_out(addr, val, svga);
break;
}
break;
case 0x06:
att498_ramdac_control(val, ramdac, svga);
break;
default:
break;
}
}
uint8_t
att498_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga)
{
att498_ramdac_t *ramdac = (att498_ramdac_t *) priv;
uint8_t temp = 0xff;
uint8_t rs = (addr & 0x03);
rs |= ((!!rs2) << 2);
switch (rs) {
case 0x00:
case 0x01:
case 0x03:
case 0x04:
case 0x05:
case 0x07:
temp = svga_in(addr, svga);
ramdac->state = 0;
break;
case 0x02:
switch (ramdac->state) {
case 4:
temp = ramdac->ctrl;
ramdac->state++;
break;
case 5:
temp = 0x84;
ramdac->state++;
break;
case 6:
temp = ramdac->ctrl;
ramdac->state = 0;
break;
default:
temp = svga_in(addr, svga);
ramdac->state++;
break;
}
break;
case 0x06:
temp = ramdac->ctrl;
ramdac->state = 0;
break;
default:
break;
}
return temp;
}
static void *
att498_ramdac_init(const device_t *info)
{
att498_ramdac_t *ramdac = (att498_ramdac_t *) malloc(sizeof(att498_ramdac_t));
memset(ramdac, 0, sizeof(att498_ramdac_t));
ramdac->type = info->local;
return ramdac;
}
static void
att498_ramdac_close(void *priv)
{
att498_ramdac_t *ramdac = (att498_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t att498_ramdac_device = {
.name = "AT&T 22c498 RAMDAC",
.internal_name = "att498_ramdac",
.flags = 0,
.local = 0,
.init = att498_ramdac_init,
.close = att498_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,161 @@
/*
* 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 Brooktree BT481 true colour RAMDAC
* family.
*
*
*
* Authors: TheCollector1995.
*
* Copyright 2024 TheCollector1995.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
#include <86box/plat_unused.h>
typedef struct bt481_ramdac_t {
int state;
uint8_t cmd;
} bt481_ramdac_t;
static void
bt481_ramdac_command(uint8_t val, void *priv, svga_t *svga)
{
bt481_ramdac_t *ramdac = (bt481_ramdac_t *) priv;
ramdac->cmd = val;
pclog("RAMDAC CMD=%02x.\n", val);
switch ((ramdac->cmd >> 4) & 0x0f) {
default:
case 0x00:
svga->bpp = 8;
break;
case 0x08:
case 0x0a:
svga->bpp = 15;
break;
case 0x09:
case 0x0c:
svga->bpp = 16;
break;
case 0x0e:
case 0x0f:
svga->bpp = 24;
break;
}
svga_recalctimings(svga);
}
void
bt481_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga)
{
bt481_ramdac_t *ramdac = (bt481_ramdac_t *) priv;
uint8_t rs = (addr & 0x03) | ((!!rs2) << 2);
switch (rs) {
case 0x00:
case 0x01:
case 0x03:
case 0x04:
case 0x05:
case 0x07:
svga_out(addr, val, svga);
ramdac->state = 0;
break;
case 0x02:
pclog("RAMDAC Write State=%x.\n", ramdac->state);
switch (ramdac->state) {
case 4:
bt481_ramdac_command(val, ramdac, svga);
break;
default:
svga_out(addr, val, svga);
break;
}
break;
case 0x06:
bt481_ramdac_command(val, ramdac, svga);
ramdac->state = 0;
break;
default:
break;
}
}
uint8_t
bt481_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga)
{
bt481_ramdac_t * ramdac = (bt481_ramdac_t *) priv;
uint8_t temp = 0xff;
uint8_t rs = (addr & 0x03) | ((!!rs2) << 2);
switch (rs) {
case 0x02:
case 0x06:
switch (ramdac->state) {
case 4:
temp = ramdac->cmd;
break;
default:
temp = svga_in(addr, svga);
ramdac->state++;
break;
}
break;
default:
temp = svga_in(addr, svga);
ramdac->state = 0;
break;
}
pclog("RAMDAC IN=%02x, ret=%02x.\n", rs, temp);
return temp;
}
static void *
bt481_ramdac_init(UNUSED(const device_t *info))
{
bt481_ramdac_t *ramdac = (bt481_ramdac_t *) malloc(sizeof(bt481_ramdac_t));
memset(ramdac, 0, sizeof(bt481_ramdac_t));
return ramdac;
}
static void
bt481_ramdac_close(void *priv)
{
bt481_ramdac_t *ramdac = (bt481_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t bt481_ramdac_device = {
.name = "Brooktree Bt481 RAMDAC",
.internal_name = "bt481_ramdac",
.flags = 0,
.local = 0,
.init = bt481_ramdac_init,
.close = bt481_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,601 @@
/*
* 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 Brooktree BT484-485A true colour RAMDAC
* family.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* TheCollector1995,
*
* Copyright 2016-2018 Miran Grca.
* Copyright 2018 TheCollector1995.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
typedef struct bt48x_ramdac_t {
PALETTE extpal;
uint32_t extpallook[256];
uint8_t cursor32_data[256];
uint8_t cursor64_data[1024];
int hwc_y;
int hwc_x;
uint8_t cmd_r0;
uint8_t cmd_r1;
uint8_t cmd_r2;
uint8_t cmd_r3;
uint8_t cmd_r4;
uint8_t status;
uint8_t type;
} bt48x_ramdac_t;
enum {
BT484 = 0,
ATT20C504,
BT485,
ATT20C505,
BT485A
};
static void
bt48x_set_bpp(bt48x_ramdac_t *ramdac, svga_t *svga)
{
if ((!(ramdac->cmd_r2 & 0x20)) || ((ramdac->type >= BT485A) && ((ramdac->cmd_r3 & 0x60) == 0x60)))
svga->bpp = 8;
else if ((ramdac->type >= BT485A) && ((ramdac->cmd_r3 & 0x60) == 0x40))
svga->bpp = 24;
else
switch (ramdac->cmd_r1 & 0x60) {
case 0x00:
svga->bpp = 32;
break;
case 0x20:
if (ramdac->cmd_r1 & 0x08)
svga->bpp = 16;
else
svga->bpp = 15;
break;
case 0x40:
svga->bpp = 8;
break;
case 0x60:
svga->bpp = 4;
break;
default:
break;
}
svga_recalctimings(svga);
}
void
bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *priv, svga_t *svga)
{
bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) priv;
uint32_t o32;
uint8_t *cd;
uint16_t index;
uint8_t rs = (addr & 0x03);
uint16_t da_mask = 0x03ff;
rs |= (!!rs2 << 2);
rs |= (!!rs3 << 3);
if (ramdac->type < BT485)
da_mask = 0x00ff;
switch (rs) {
case 0x00: /* Palette Write Index Register (RS value = 0000) */
case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */
case 0x03:
case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */
svga->dac_pos = 0;
svga->dac_status = addr & 0x03;
svga->dac_addr = val;
if (ramdac->type >= BT485)
svga->dac_addr |= ((ramdac->cmd_r3 & 0x03) << 8);
if (svga->dac_status)
svga->dac_addr = (svga->dac_addr + 1) & da_mask;
break;
case 0x01: /* Palette Data Register (RS value = 0001) */
case 0x02: /* Pixel Read Mask Register (RS value = 0010) */
svga_out(addr, val, svga);
break;
case 0x05: /* Ext Palette Data Register (RS value = 0101) */
svga->dac_status = 0;
svga->fullchange = changeframecount;
switch (svga->dac_pos) {
case 0:
svga->dac_r = val;
svga->dac_pos++;
break;
case 1:
svga->dac_g = val;
svga->dac_pos++;
break;
case 2:
index = svga->dac_addr & 3;
ramdac->extpal[index].r = svga->dac_r;
ramdac->extpal[index].g = svga->dac_g;
ramdac->extpal[index].b = val;
if (svga->ramdac_type == RAMDAC_8BIT)
ramdac->extpallook[index] = makecol32(ramdac->extpal[index].r, ramdac->extpal[index].g, ramdac->extpal[index].b);
else
ramdac->extpallook[index] = makecol32(video_6to8[ramdac->extpal[index].r & 0x3f], video_6to8[ramdac->extpal[index].g & 0x3f], video_6to8[ramdac->extpal[index].b & 0x3f]);
if (svga->ext_overscan && !index) {
o32 = svga->overscan_color;
svga->overscan_color = ramdac->extpallook[0];
if (o32 != svga->overscan_color)
svga_recalctimings(svga);
}
svga->dac_addr = (svga->dac_addr + 1) & 0xff;
svga->dac_pos = 0;
break;
default:
break;
}
break;
case 0x06: /* Command Register 0 (RS value = 0110) */
ramdac->cmd_r0 = val;
svga->ramdac_type = (val & 0x02) ? RAMDAC_8BIT : RAMDAC_6BIT;
break;
case 0x08: /* Command Register 1 (RS value = 1000) */
ramdac->cmd_r1 = val;
bt48x_set_bpp(ramdac, svga);
break;
case 0x09: /* Command Register 2 (RS value = 1001) */
ramdac->cmd_r2 = val;
svga->dac_hwcursor.ena = !!(val & 0x03);
bt48x_set_bpp(ramdac, svga);
break;
case 0x0a:
if ((ramdac->type >= BT485) && (ramdac->cmd_r0 & 0x80)) {
switch (svga->dac_addr & ((ramdac->type >= BT485A) ? 0xff : 0x3f)) {
case 0x01:
/* Command Register 3 (RS value = 1010) */
ramdac->cmd_r3 = val;
if (ramdac->type >= BT485A)
bt48x_set_bpp(ramdac, svga);
svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = (val & 4) ? 64 : 32;
svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
svga->dac_addr = (svga->dac_addr & 0x00ff) | ((val & 0x03) << 8);
svga_recalctimings(svga);
break;
case 0x02:
case 0x20:
case 0x21:
case 0x22:
if (ramdac->type != BT485A)
break;
else if (svga->dac_addr == 2) {
ramdac->cmd_r4 = val;
break;
}
break;
default:
break;
}
}
break;
case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */
index = svga->dac_addr & da_mask;
if ((ramdac->type >= BT485) && (svga->dac_hwcursor.cur_xsize == 64))
cd = (uint8_t *) ramdac->cursor64_data;
else {
index &= 0xff;
cd = (uint8_t *) ramdac->cursor32_data;
}
cd[index] = val;
svga->dac_addr = (svga->dac_addr + 1) & da_mask;
break;
case 0x0c: /* Cursor X Low Register (RS value = 1100) */
ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val;
svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
break;
case 0x0d: /* Cursor X High Register (RS value = 1101) */
ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8);
svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
break;
case 0x0e: /* Cursor Y Low Register (RS value = 1110) */
ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val;
svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
break;
case 0x0f: /* Cursor Y High Register (RS value = 1111) */
ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8);
svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
break;
default:
break;
}
return;
}
uint8_t
bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, void *priv, svga_t *svga)
{
bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) priv;
uint8_t temp = 0xff;
const uint8_t *cd;
uint16_t index;
uint8_t rs = (addr & 0x03);
uint16_t da_mask = 0x03ff;
rs |= (!!rs2 << 2);
rs |= (!!rs3 << 3);
if (ramdac->type < BT485)
da_mask = 0x00ff;
switch (rs) {
case 0x00: /* Palette Write Index Register (RS value = 0000) */
case 0x01: /* Palette Data Register (RS value = 0001) */
case 0x02: /* Pixel Read Mask Register (RS value = 0010) */
case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */
temp = svga_in(addr, svga);
break;
case 0x03: /* Palette Read Index Register (RS value = 0011) */
case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */
temp = svga->dac_addr & 0xff;
break;
case 0x05: /* Ext Palette Data Register (RS value = 0101) */
index = (svga->dac_addr - 1) & 3;
svga->dac_status = 3;
switch (svga->dac_pos) {
case 0:
svga->dac_pos++;
if (svga->ramdac_type == RAMDAC_8BIT)
temp = ramdac->extpal[index].r;
else
temp = ramdac->extpal[index].r & 0x3f;
break;
case 1:
svga->dac_pos++;
if (svga->ramdac_type == RAMDAC_8BIT)
temp = ramdac->extpal[index].g;
else
temp = ramdac->extpal[index].g & 0x3f;
break;
case 2:
svga->dac_pos = 0;
svga->dac_addr = svga->dac_addr + 1;
if (svga->ramdac_type == RAMDAC_8BIT)
temp = ramdac->extpal[index].b;
else
temp = ramdac->extpal[index].b & 0x3f;
break;
default:
break;
}
break;
case 0x06: /* Command Register 0 (RS value = 0110) */
temp = ramdac->cmd_r0;
break;
case 0x08: /* Command Register 1 (RS value = 1000) */
temp = ramdac->cmd_r1;
break;
case 0x09: /* Command Register 2 (RS value = 1001) */
temp = ramdac->cmd_r2;
break;
case 0x0a:
if ((ramdac->type >= BT485) && (ramdac->cmd_r0 & 0x80)) {
switch (svga->dac_addr & ((ramdac->type >= BT485A) ? 0xff : 0x3f)) {
default:
case 0x00:
temp = ramdac->status | (svga->dac_status ? 0x04 : 0x00);
break;
case 0x01:
temp = ramdac->cmd_r3 & 0xfc;
temp |= (svga->dac_addr & 0x300) >> 8;
break;
case 0x02:
case 0x20:
case 0x21:
case 0x22:
if (ramdac->type != BT485A)
break;
else if (svga->dac_addr == 2) {
temp = ramdac->cmd_r4;
break;
} else {
/* TODO: Red, Green, and Blue Signature Analysis Registers */
temp = 0xff;
break;
}
}
} else
temp = ramdac->status | (svga->dac_status ? 0x04 : 0x00);
break;
case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */
index = (svga->dac_addr - 1) & da_mask;
if ((ramdac->type >= BT485) && (svga->dac_hwcursor.cur_xsize == 64))
cd = (uint8_t *) ramdac->cursor64_data;
else {
index &= 0xff;
cd = (uint8_t *) ramdac->cursor32_data;
}
temp = cd[index];
svga->dac_addr = (svga->dac_addr + 1) & da_mask;
break;
case 0x0c: /* Cursor X Low Register (RS value = 1100) */
temp = ramdac->hwc_x & 0xff;
break;
case 0x0d: /* Cursor X High Register (RS value = 1101) */
temp = (ramdac->hwc_x >> 8) & 0xff;
break;
case 0x0e: /* Cursor Y Low Register (RS value = 1110) */
temp = ramdac->hwc_y & 0xff;
break;
case 0x0f: /* Cursor Y High Register (RS value = 1111) */
temp = (ramdac->hwc_y >> 8) & 0xff;
break;
default:
break;
}
return temp;
}
void
bt48x_recalctimings(void *priv, svga_t *svga)
{
const bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) priv;
svga->interlace = ramdac->cmd_r2 & 0x08;
if (ramdac->cmd_r3 & 0x08)
svga->hdisp *= 2; /* x2 clock multiplier */
}
void
bt48x_hwcursor_draw(svga_t *svga, int displine)
{
int comb;
int b0;
int b1;
uint16_t dat[2];
int offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff;
int pitch;
int bppl;
int mode;
int x_pos;
int y_pos;
uint32_t clr1;
uint32_t clr2;
uint32_t clr3;
uint32_t *p;
const uint8_t *cd;
bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) svga->ramdac;
clr1 = ramdac->extpallook[1];
clr2 = ramdac->extpallook[2];
clr3 = ramdac->extpallook[3];
/* The planes come in two parts, and each plane is 1bpp,
so a 32x32 cursor has 4 bytes per line, and a 64x64
cursor has 8 bytes per line. */
pitch = (svga->dac_hwcursor_latch.cur_xsize >> 3); /* Bytes per line. */
/* A 32x32 cursor has 128 bytes per line, and a 64x64
cursor has 512 bytes per line. */
bppl = (pitch * svga->dac_hwcursor_latch.cur_ysize); /* Bytes per plane. */
mode = ramdac->cmd_r2 & 0x03;
if (svga->interlace && svga->dac_hwcursor_oddeven)
svga->dac_hwcursor_latch.addr += pitch;
if (svga->dac_hwcursor_latch.cur_xsize == 64)
cd = (uint8_t *) ramdac->cursor64_data;
else
cd = (uint8_t *) ramdac->cursor32_data;
for (int x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += 16) {
dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | cd[svga->dac_hwcursor_latch.addr + 1];
dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | cd[svga->dac_hwcursor_latch.addr + bppl + 1];
for (uint8_t xx = 0; xx < 16; xx++) {
b0 = (dat[0] >> (15 - xx)) & 1;
b1 = (dat[1] >> (15 - xx)) & 1;
comb = (b0 | (b1 << 1));
y_pos = displine;
x_pos = (offset + svga->x_add) & 2047;
p = buffer32->line[y_pos];
if (offset >= svga->dac_hwcursor_latch.x) {
switch (mode) {
case 1: /* Three Color */
switch (comb) {
case 1:
p[x_pos] = clr1;
break;
case 2:
p[x_pos] = clr2;
break;
case 3:
p[x_pos] = clr3;
break;
default:
break;
}
break;
case 2: /* PM/Windows */
switch (comb) {
case 0:
p[x_pos] = clr1;
break;
case 1:
p[x_pos] = clr2;
break;
case 3:
p[x_pos] ^= 0xffffff;
break;
default:
break;
}
break;
case 3: /* X-Windows */
switch (comb) {
case 2:
p[x_pos] = clr1;
break;
case 3:
p[x_pos] = clr2;
break;
default:
break;
}
break;
default:
break;
}
}
offset++;
}
svga->dac_hwcursor_latch.addr += 2;
}
if (svga->interlace && !svga->dac_hwcursor_oddeven)
svga->dac_hwcursor_latch.addr += pitch;
}
void *
bt48x_ramdac_init(const device_t *info)
{
bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) malloc(sizeof(bt48x_ramdac_t));
memset(ramdac, 0, sizeof(bt48x_ramdac_t));
ramdac->type = info->local;
/* Set the RAM DAC status byte to the correct ID bits.
Both the BT484 and BT485 datasheets say this:
SR7-SR6: These bits are identification values. SR7=0 and SR6=1.
But all other sources seem to assume SR7=1 and SR6=0. */
switch (ramdac->type) {
case BT484:
ramdac->status = 0x40;
break;
case ATT20C504:
ramdac->status = 0x40;
break;
case BT485:
ramdac->status = 0x60;
break;
case ATT20C505:
ramdac->status = 0xd0;
break;
case BT485A:
ramdac->status = 0x20;
break;
default:
break;
}
return ramdac;
}
static void
bt48x_ramdac_close(void *priv)
{
bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t bt484_ramdac_device = {
.name = "Brooktree Bt484 RAMDAC",
.internal_name = "bt484_ramdac",
.flags = 0,
.local = BT484,
.init = bt48x_ramdac_init,
.close = bt48x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t att20c504_ramdac_device = {
.name = "AT&T 20c504 RAMDAC",
.internal_name = "att20c504_ramdac",
.flags = 0,
.local = ATT20C504,
.init = bt48x_ramdac_init,
.close = bt48x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t bt485_ramdac_device = {
.name = "Brooktree Bt485 RAMDAC",
.internal_name = "bt485_ramdac",
.flags = 0,
.local = BT485,
.init = bt48x_ramdac_init,
.close = bt48x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t att20c505_ramdac_device = {
.name = "AT&T 20c505 RAMDAC",
.internal_name = "att20c505_ramdac",
.flags = 0,
.local = ATT20C505,
.init = bt48x_ramdac_init,
.close = bt48x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t bt485a_ramdac_device = {
.name = "Brooktree Bt485A RAMDAC",
.internal_name = "bt485a_ramdac",
.flags = 0,
.local = BT485A,
.init = bt48x_ramdac_init,
.close = bt48x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,989 @@
/*
* 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 IBM RGB 528 true colour RAMDAC.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2020 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
#include <86box/plat_unused.h>
typedef union ibm_rgb528_pixel8_t {
uint8_t pixel;
struct {
uint8_t b : 2;
uint8_t g : 3;
uint8_t r : 2;
};
} ibm_rgb528_pixel8_t;
typedef union ibm_rgb528_pixel16_t {
uint16_t pixel;
struct {
uint16_t b_ : 5;
uint16_t g_ : 6;
uint16_t r_ : 5;
};
struct {
uint16_t b : 5;
uint16_t g : 5;
uint16_t r : 5;
uint16_t c : 1;
};
} ibm_rgb528_pixel16_t;
typedef union ibm_rgb528_pixel32_t {
uint32_t pixel;
struct {
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
};
} ibm_rgb528_pixel32_t;
typedef struct ibm_rgb528_ramdac_t {
PALETTE extpal;
uint32_t extpallook[256];
uint8_t indexed_data[2048];
uint8_t cursor32_data[256];
uint8_t cursor64_data[1024];
uint8_t palettes[3][256];
ibm_rgb528_pixel32_t extra_pal[4];
int16_t hwc_y;
int16_t hwc_x;
uint16_t index;
uint16_t smlc_part;
uint8_t cmd_r0;
uint8_t cmd_r1;
uint8_t cmd_r2;
uint8_t cmd_r3;
uint8_t cmd_r4;
uint8_t status;
uint8_t indx_cntl;
uint8_t cursor_array;
uint8_t cursor_hotspot_x;
uint8_t cursor_hotspot_y;
} ibm_rgb528_ramdac_t;
void
ibm_rgb528_render_4bpp(svga_t *svga)
{
uint32_t *p;
ibm_rgb528_pixel32_t dat_out;
uint8_t dat;
uint32_t dat32 = 0x00000000;
uint64_t dat64 = 0x0000000000000000ULL;
uint64_t dat642 = 0x0000000000000000ULL;
const ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac;
uint8_t b8_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6;
uint8_t partition = (ramdac->indexed_data[0x07] & 0x0f) << 4;
uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10;
uint8_t swap_nib = ramdac->indexed_data[0x72] & 0x21;
uint8_t vram_size = ramdac->indexed_data[0x70] & 0x03;
if ((svga->displine + svga->y_add) < 0)
return;
if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) {
p = &buffer32->line[svga->displine + svga->y_add][svga->x_add];
if (svga->firstline_draw == 2000)
svga->firstline_draw = svga->displine;
svga->lastline_draw = svga->displine;
for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x++) {
if (vram_size == 3) {
if (!(x & 31)) {
dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]);
dat642 = *(uint64_t *) (&svga->vram[svga->memaddr + 8]);
if (swap_word) {
dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL);
dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL);
}
}
if (swap_nib)
dat = (((x & 16) ? dat642 : dat64) >> ((x & 15) << 2)) & 0xf;
else
dat = (((x & 16) ? dat642 : dat64) >> (((x & 15) << 2) ^ 4)) & 0xf;
} else if (vram_size == 1) {
if (!(x & 15)) {
dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]);
if (swap_word)
dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL);
}
if (swap_nib)
dat = (dat64 >> ((x & 15) << 2)) & 0xf;
else
dat = (dat64 >> (((x & 15) << 2) ^ 4)) & 0xf;
} else {
if (!(x & 7))
dat32 = *(uint32_t *) (&svga->vram[svga->memaddr]);
if (swap_nib)
dat = (dat32 >> ((x & 7) << 2)) & 0xf;
else
dat = (dat32 >> (((x & 7) << 2) ^ 4)) & 0xf;
}
if (b8_dcol == 0x00) {
dat_out.a = 0x00;
dat_out.r = ramdac->palettes[0][partition | dat];
dat_out.g = ramdac->palettes[1][partition | dat];
dat_out.b = ramdac->palettes[2][partition | dat];
} else
dat_out.pixel = video_8togs[dat];
if (svga->lowres) {
p[x << 1] = p[(x << 1) + 1] = dat_out.pixel & 0xffffff;
} else
p[x] = dat_out.pixel & 0xffffff;
if ((vram_size == 3) && ((x & 31) == 31))
svga->memaddr = (svga->memaddr + 16) & svga->vram_display_mask;
if ((vram_size == 1) && ((x & 15) == 15))
svga->memaddr = (svga->memaddr + 8) & svga->vram_display_mask;
else if ((!vram_size) && ((x & 7) == 7))
svga->memaddr = (svga->memaddr + 4) & svga->vram_display_mask;
}
}
}
void
ibm_rgb528_render_8bpp(svga_t *svga)
{
uint32_t *p;
ibm_rgb528_pixel32_t dat_out;
uint8_t dat;
uint32_t dat32 = 0x00000000;
uint64_t dat64 = 0x0000000000000000ULL;
uint64_t dat642 = 0x0000000000000000ULL;
const ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac;
uint8_t b8_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6;
uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10;
uint8_t vram_size = ramdac->indexed_data[0x70] & 0x03;
if ((svga->displine + svga->y_add) < 0)
return;
if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) {
p = &buffer32->line[svga->displine + svga->y_add][svga->x_add];
if (svga->firstline_draw == 2000)
svga->firstline_draw = svga->displine;
svga->lastline_draw = svga->displine;
for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x++) {
if (vram_size == 3) {
if (!(x & 15)) {
dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]);
dat642 = *(uint64_t *) (&svga->vram[svga->memaddr + 8]);
if (swap_word) {
dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL);
dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL);
}
}
dat = (((x & 8) ? dat642 : dat64) >> ((x & 7) << 3)) & 0xff;
} else if (vram_size == 1) {
if (!(x & 7)) {
dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]);
if (swap_word)
dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL);
}
dat = (dat64 >> ((x & 7) << 3)) & 0xff;
} else {
if (!(x & 3))
dat32 = *(uint32_t *) (&svga->vram[svga->memaddr]);
dat = (dat32 >> ((x & 3) << 3)) & 0xff;
}
if (b8_dcol == 0x00) {
dat_out.a = 0x00;
dat_out.r = ramdac->palettes[0][dat];
dat_out.g = ramdac->palettes[1][dat];
dat_out.b = ramdac->palettes[2][dat];
} else
dat_out.pixel = video_8togs[dat];
if (svga->lowres) {
p[x << 1] = p[(x << 1) + 1] = dat_out.pixel & 0xffffff;
} else
p[x] = dat_out.pixel & 0xffffff;
if ((vram_size == 3) && ((x & 15) == 15))
svga->memaddr = (svga->memaddr + 16) & svga->vram_display_mask;
else if ((vram_size == 1) && ((x & 7) == 7))
svga->memaddr = (svga->memaddr + 8) & svga->vram_display_mask;
else if ((!vram_size) && ((x & 3) == 3))
svga->memaddr = (svga->memaddr + 4) & svga->vram_display_mask;
}
}
}
void
ibm_rgb528_render_15_16bpp(svga_t *svga)
{
uint32_t *p;
ibm_rgb528_pixel16_t *dat_ex;
ibm_rgb528_pixel32_t dat_out;
uint16_t dat;
uint32_t dat32 = 0x00000000;
uint64_t dat64 = 0x0000000000000000ULL;
uint64_t dat642 = 0x0000000000000000ULL;
const ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac;
uint8_t b16_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6;
uint8_t by16_pol = ramdac->indexed_data[0x0c] & 0x20;
uint8_t b555_565 = ramdac->indexed_data[0x0c] & 0x02;
uint8_t bspr_cnt = ramdac->indexed_data[0x0c] & 0x01;
uint8_t partition = (ramdac->indexed_data[0x07] & 0x0e) << 4;
uint8_t b6bit_lin = ramdac->indexed_data[0x07] & 0x80;
uint8_t swaprb = ramdac->indexed_data[0x72] & 0x80;
uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10;
uint8_t vram_size = ramdac->indexed_data[0x70] & 0x01;
uint8_t temp;
if ((svga->displine + svga->y_add) < 0)
return;
if (b555_565 && (b16_dcol != 0x01))
partition &= 0xc0;
if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) {
p = &buffer32->line[svga->displine + svga->y_add][svga->x_add];
if (svga->firstline_draw == 2000)
svga->firstline_draw = svga->displine;
svga->lastline_draw = svga->displine;
for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x++) {
if (vram_size == 2) {
if (!(x & 7)) {
dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]);
dat642 = *(uint64_t *) (&svga->vram[svga->memaddr + 8]);
if (swap_word) {
dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL);
dat642 = (dat64 << 32ULL) | (dat642 >> 32ULL);
}
}
dat = (((x & 4) ? dat642 : dat64) >> ((x & 3) << 4)) & 0xffff;
} else if (vram_size == 1) {
if (!(x & 3)) {
dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]);
if (swap_word)
dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL);
}
dat = (dat64 >> ((x & 3) << 4)) & 0xffff;
} else {
if (!(x & 1))
dat32 = *(uint32_t *) (&svga->vram[svga->memaddr]);
dat = (dat32 >> ((x & 1) << 4)) & 0xffff;
}
dat_ex = (ibm_rgb528_pixel16_t *) &dat;
if (b555_565 && (b16_dcol != 0x01)) {
if (swaprb) {
temp = dat_ex->r_;
dat_ex->r_ = dat_ex->b_;
dat_ex->b_ = temp;
}
if (b16_dcol == 0x00) {
dat_out.a = 0x00;
if (bspr_cnt) {
dat_out.r = ramdac->palettes[0][partition | dat_ex->r_];
dat_out.g = ramdac->palettes[1][partition | dat_ex->g_];
dat_out.b = ramdac->palettes[2][partition | dat_ex->b_];
} else {
dat_out.r = ramdac->palettes[0][dat_ex->r_ << 3];
dat_out.g = ramdac->palettes[1][dat_ex->g_ << 2];
dat_out.b = ramdac->palettes[2][dat_ex->b_ << 3];
}
if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) {
dat_out.r |= ((dat_out.r & 0xc0) >> 6);
dat_out.g |= ((dat_out.g & 0xc0) >> 6);
dat_out.b |= ((dat_out.b & 0xc0) >> 6);
}
} else
dat_out.pixel = video_16to32[dat_ex->pixel];
} else {
if (swaprb) {
temp = dat_ex->r;
dat_ex->r = dat_ex->b;
dat_ex->b = temp;
}
if (by16_pol)
dat ^= 0x8000;
if ((b16_dcol == 0x00) || ((b16_dcol == 0x01) && !(dat & 0x8000))) {
dat_out.a = 0x00;
if (bspr_cnt) {
dat_out.r = ramdac->palettes[0][partition | dat_ex->r];
dat_out.g = ramdac->palettes[1][partition | dat_ex->g];
dat_out.b = ramdac->palettes[2][partition | dat_ex->b];
} else {
dat_out.r = ramdac->palettes[0][dat_ex->r << 3];
dat_out.g = ramdac->palettes[1][dat_ex->g << 3];
dat_out.b = ramdac->palettes[2][dat_ex->b << 3];
}
if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) {
dat_out.r |= ((dat_out.r & 0xc0) >> 6);
dat_out.g |= ((dat_out.g & 0xc0) >> 6);
dat_out.b |= ((dat_out.b & 0xc0) >> 6);
}
} else
dat_out.pixel = video_15to32[dat_ex->pixel & 0x7fff];
}
if (svga->lowres) {
p[x << 1] = p[(x << 1) + 1] = dat_out.pixel & 0xffffff;
} else
p[x] = dat_out.pixel & 0xffffff;
if ((vram_size == 3) && ((x & 7) == 7))
svga->memaddr = (svga->memaddr + 16) & svga->vram_display_mask;
else if ((vram_size == 1) && ((x & 3) == 3))
svga->memaddr = (svga->memaddr + 8) & svga->vram_display_mask;
else if (!vram_size && ((x & 1) == 1))
svga->memaddr = (svga->memaddr + 4) & svga->vram_display_mask;
}
}
}
void
ibm_rgb528_render_24bpp(svga_t *svga)
{
uint32_t *p;
ibm_rgb528_pixel32_t *dat_ex;
uint32_t dat;
uint64_t dat64[6];
uint8_t *dat8 = (uint8_t *) dat64;
const ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac;
uint8_t b24_dcol = ramdac->indexed_data[0x0d] & 0x01;
uint8_t swaprb = ramdac->indexed_data[0x72] & 0x80;
uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10;
uint8_t vram_size = ramdac->indexed_data[0x70] & 0x01;
uint8_t b6bit_lin = ramdac->indexed_data[0x07] & 0x80;
uint8_t temp;
if ((svga->displine + svga->y_add) < 0)
return;
if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) {
p = &buffer32->line[svga->displine + svga->y_add][svga->x_add];
if (svga->firstline_draw == 2000)
svga->firstline_draw = svga->displine;
svga->lastline_draw = svga->displine;
for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x++) {
dat_ex = (ibm_rgb528_pixel32_t *) &dat;
if (vram_size == 3) {
if ((x & 15) == 0) {
dat64[0] = *(uint64_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]);
dat64[1] = *(uint64_t *) (&svga->vram[(svga->memaddr + 8) & svga->vram_display_mask]);
dat64[2] = *(uint64_t *) (&svga->vram[(svga->memaddr + 16) & svga->vram_display_mask]);
dat64[3] = *(uint64_t *) (&svga->vram[(svga->memaddr + 24) & svga->vram_display_mask]);
dat64[4] = *(uint64_t *) (&svga->vram[(svga->memaddr + 32) & svga->vram_display_mask]);
dat64[5] = *(uint64_t *) (&svga->vram[(svga->memaddr + 40) & svga->vram_display_mask]);
if (swap_word) {
dat64[0] = (dat64[0] << 32ULL) | (dat64[0] >> 32ULL);
dat64[1] = (dat64[1] << 32ULL) | (dat64[1] >> 32ULL);
dat64[2] = (dat64[2] << 32ULL) | (dat64[2] >> 32ULL);
dat64[3] = (dat64[3] << 32ULL) | (dat64[3] >> 32ULL);
dat64[4] = (dat64[4] << 32ULL) | (dat64[4] >> 32ULL);
dat64[5] = (dat64[5] << 32ULL) | (dat64[5] >> 32ULL);
}
}
dat_ex = (ibm_rgb528_pixel32_t *) &(dat8[(x & 15) * 3]);
} else if (vram_size == 1) {
if ((x & 7) == 0) {
dat64[0] = *(uint64_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]);
dat64[1] = *(uint64_t *) (&svga->vram[(svga->memaddr + 8) & svga->vram_display_mask]);
dat64[2] = *(uint64_t *) (&svga->vram[(svga->memaddr + 16) & svga->vram_display_mask]);
if (swap_word) {
dat64[0] = (dat64[0] << 32ULL) | (dat64[0] >> 32ULL);
dat64[1] = (dat64[1] << 32ULL) | (dat64[1] >> 32ULL);
dat64[2] = (dat64[2] << 32ULL) | (dat64[2] >> 32ULL);
}
}
dat_ex = (ibm_rgb528_pixel32_t *) &(dat8[(x & 7) * 3]);
} else
dat = 0x00000000;
if (swaprb) {
temp = dat_ex->r;
dat_ex->r = dat_ex->b;
dat_ex->b = temp;
}
if (b24_dcol == 0x00) {
dat_ex->a = 0x00;
dat_ex->r = ramdac->palettes[0][dat_ex->r];
dat_ex->g = ramdac->palettes[1][dat_ex->g];
dat_ex->g = ramdac->palettes[2][dat_ex->b];
if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) {
dat_ex->r |= ((dat_ex->r & 0xc0) >> 6);
dat_ex->g |= ((dat_ex->g & 0xc0) >> 6);
dat_ex->b |= ((dat_ex->b & 0xc0) >> 6);
}
}
if (svga->lowres) {
p[x << 1] = p[(x << 1) + 1] = dat_ex->pixel & 0xffffff;
} else
p[x] = dat_ex->pixel & 0xffffff;
if ((vram_size == 3) && ((x & 15) == 15))
svga->memaddr = (svga->memaddr + 48) & svga->vram_display_mask;
else if ((vram_size == 1) && ((x & 7) == 7))
svga->memaddr = (svga->memaddr + 24) & svga->vram_display_mask;
}
}
}
void
ibm_rgb528_render_32bpp(svga_t *svga)
{
uint32_t *p;
ibm_rgb528_pixel32_t *dat_ex;
uint32_t dat = 0x00000000;
uint64_t dat64 = 0x0000000000000000ULL;
uint64_t dat642 = 0x0000000000000000ULL;
const ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac;
uint8_t b32_dcol = ramdac->indexed_data[0x0e] & 0x03;
uint8_t by32_pol = ramdac->indexed_data[0x0e] & 0x04;
uint8_t swaprb = ramdac->indexed_data[0x72] & 0x80;
uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10;
uint8_t vram_size = ramdac->indexed_data[0x70] & 0x01;
uint8_t b6bit_lin = ramdac->indexed_data[0x07] & 0x80;
uint8_t temp;
if ((svga->displine + svga->y_add) < 0)
return;
if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) {
p = &buffer32->line[svga->displine + svga->y_add][svga->x_add];
if (svga->firstline_draw == 2000)
svga->firstline_draw = svga->displine;
svga->lastline_draw = svga->displine;
for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x++) {
if (vram_size == 3) {
if (!(x & 3)) {
dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]);
dat642 = *(uint64_t *) (&svga->vram[svga->memaddr + 8]);
if (swap_word) {
dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL);
dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL);
}
}
dat = (((x & 2) ? dat642 : dat64) >> ((x & 1ULL) << 5ULL)) & 0xffffffff;
} else if (vram_size == 1) {
if (!(x & 1)) {
dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]);
if (swap_word)
dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL);
}
dat = (dat64 >> ((x & 1ULL) << 5ULL)) & 0xffffffff;
} else
dat = *(uint32_t *) (&svga->vram[svga->memaddr]);
dat_ex = (ibm_rgb528_pixel32_t *) &dat;
if (swaprb) {
temp = dat_ex->r;
dat_ex->r = dat_ex->b;
dat_ex->b = temp;
}
if ((b32_dcol < 0x03) && by32_pol)
dat ^= 0x01000000;
if ((b32_dcol == 0x00) || ((b32_dcol == 0x01) && !(dat & 0x01000000))) {
dat_ex->a = 0x00;
dat_ex->r = ramdac->palettes[0][dat_ex->r];
dat_ex->g = ramdac->palettes[1][dat_ex->g];
dat_ex->g = ramdac->palettes[2][dat_ex->b];
if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) {
dat_ex->r |= ((dat_ex->r & 0xc0) >> 6);
dat_ex->g |= ((dat_ex->g & 0xc0) >> 6);
dat_ex->b |= ((dat_ex->b & 0xc0) >> 6);
}
}
if (svga->lowres) {
p[x << 1] = p[(x << 1) + 1] = dat_ex->pixel & 0xffffff;
} else
p[x] = dat_ex->pixel & 0xffffff;
if ((vram_size == 3) && ((x & 3) == 3))
svga->memaddr = (svga->memaddr + 16) & svga->vram_display_mask;
else if ((vram_size == 1) && ((x & 1) == 1))
svga->memaddr = (svga->memaddr + 8) & svga->vram_display_mask;
else if (!vram_size)
svga->memaddr = (svga->memaddr + 4) & svga->vram_display_mask;
}
}
}
static void
ibm_rgb528_set_bpp(ibm_rgb528_ramdac_t *ramdac, svga_t *svga)
{
uint8_t b16_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6;
uint8_t b555_565 = ramdac->indexed_data[0x0c] & 0x02;
if (ramdac->indexed_data[0x071] & 0x01)
switch (ramdac->indexed_data[0x00a] & 0x07) {
case 0x02:
svga->bpp = 4;
break;
case 0x03:
default:
svga->bpp = 8;
break;
case 0x04:
if (b555_565 && (b16_dcol != 0x01))
svga->bpp = 16;
else
svga->bpp = 15;
break;
case 0x05:
svga->bpp = 24;
break;
case 0x06:
svga->bpp = 32;
break;
}
else
svga->bpp = 8;
svga_recalctimings(svga);
}
void
ibm_rgb528_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga)
{
ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) priv;
uint16_t index;
uint8_t rs = (addr & 0x03);
uint16_t da_mask = 0x03ff;
uint8_t updt_cntl = (ramdac->indexed_data[0x30] & 0x08);
rs |= (!!rs2 << 2);
switch (rs) {
case 0x00: /* Palette Write Index Register (RS value = 0000) */
case 0x03:
svga->dac_pos = 0;
svga->dac_status = addr & 0x03;
svga->dac_addr = val;
if (svga->dac_status)
svga->dac_addr = (svga->dac_addr + 1) & da_mask;
break;
case 0x01: /* Palette Data Register (RS value = 0001) */
index = svga->dac_addr & 255;
if (svga->ramdac_type == RAMDAC_8BIT)
ramdac->palettes[svga->dac_pos][index] = val;
else
ramdac->palettes[svga->dac_pos][index] = (val & 0x3f) << 2;
svga_out(addr, val, svga);
break;
case 0x02: /* Pixel Read Mask Register (RS value = 0010) */
svga_out(addr, val, svga);
break;
case 0x04:
ramdac->index = (ramdac->index & 0x0700) | val;
if ((ramdac->index >= 0x0100) && (ramdac->index <= 0x04ff))
ramdac->cursor_array = 1;
break;
case 0x05:
ramdac->index = (ramdac->index & 0x00ff) | ((val & 0x07) << 0x08);
if ((ramdac->index >= 0x0100) && (ramdac->index <= 0x04ff))
ramdac->cursor_array = 1;
break;
case 0x06:
if ((ramdac->index < 0x0100) || (ramdac->index > 0x04ff) || ramdac->cursor_array)
ramdac->indexed_data[ramdac->index] = val;
switch (ramdac->index) {
case 0x00a:
case 0x00c:
ibm_rgb528_set_bpp(ramdac, svga);
break;
case 0x030:
switch (val & 0xc0) {
case 0x00:
ramdac->smlc_part = 0x0100;
break;
case 0x40:
ramdac->smlc_part = 0x0200;
break;
case 0x80:
ramdac->smlc_part = 0x0300;
break;
case 0xc0:
ramdac->smlc_part = 0x0400;
break;
default:
break;
}
svga->dac_hwcursor.addr = ramdac->smlc_part;
svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = (val & 0x04) ? 64 : 32;
svga->dac_hwcursor.ena = ((val & 0x03) != 0x00);
break;
case 0x031:
if (!updt_cntl)
break;
ramdac->hwc_x = (ramdac->hwc_x & 0xff00) | val;
svga->dac_hwcursor.x = ((int) ramdac->hwc_x) - ramdac->cursor_hotspot_x;
break;
case 0x032:
/* Sign-extend the sign bit (7) to the remaining bits (6-4). */
val &= 0x8f;
if (val & 0x80)
val |= 0x70;
ramdac->indexed_data[ramdac->index] = val;
if (!updt_cntl)
break;
ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | (val << 8);
svga->dac_hwcursor.x = ((int) ramdac->hwc_x) - ramdac->cursor_hotspot_x;
break;
case 0x033:
if (!updt_cntl)
break;
ramdac->hwc_y = (ramdac->hwc_y & 0xff00) | val;
svga->dac_hwcursor.y = ((int) ramdac->hwc_y) - ramdac->cursor_hotspot_y;
break;
case 0x034:
/* Sign-extend the sign bit (7) to the remaining bits (6-4). */
val &= 0x8f;
if (val & 0x80)
val |= 0x70;
ramdac->indexed_data[ramdac->index] = val;
if (updt_cntl) {
ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | (val << 8);
svga->dac_hwcursor.y = ((int) ramdac->hwc_y) - ramdac->cursor_hotspot_y;
} else {
ramdac->hwc_x = ramdac->indexed_data[0x031];
ramdac->hwc_x |= (ramdac->indexed_data[0x032] << 8);
ramdac->hwc_y = ramdac->indexed_data[0x033];
ramdac->hwc_y |= (val << 8);
svga->dac_hwcursor.x = ((int) ramdac->hwc_x) - ramdac->cursor_hotspot_x;
svga->dac_hwcursor.y = ((int) ramdac->hwc_y) - ramdac->cursor_hotspot_y;
}
break;
case 0x035:
if (svga->dac_hwcursor.cur_xsize == 64)
ramdac->cursor_hotspot_x = (val & 0x3f);
else
ramdac->cursor_hotspot_x = (val & 0x1f);
svga->dac_hwcursor.x = ((int) ramdac->hwc_x) - ramdac->cursor_hotspot_x;
break;
case 0x036:
if (svga->dac_hwcursor.cur_xsize == 64)
ramdac->cursor_hotspot_y = (val & 0x3f);
else
ramdac->cursor_hotspot_y = (val & 0x1f);
svga->dac_hwcursor.y = ((int) ramdac->hwc_y) - ramdac->cursor_hotspot_y;
break;
case 0x040:
case 0x043:
case 0x046:
ramdac->extra_pal[(ramdac->index - 0x40) / 3].r = val;
break;
case 0x041:
case 0x044:
case 0x047:
ramdac->extra_pal[(ramdac->index - 0x41) / 3].g = val;
break;
case 0x042:
case 0x045:
case 0x048:
ramdac->extra_pal[(ramdac->index - 0x42) / 3].b = val;
break;
case 0x060:
ramdac->extra_pal[3].r = val;
break;
case 0x061:
ramdac->extra_pal[3].g = val;
break;
case 0x062:
ramdac->extra_pal[3].b = val;
break;
case 0x071:
svga->ramdac_type = (val & 0x04) ? RAMDAC_8BIT : RAMDAC_6BIT;
ibm_rgb528_set_bpp(ramdac, svga);
break;
default:
break;
}
if (ramdac->indx_cntl) {
if (ramdac->index == 0x00ff)
ramdac->cursor_array = 0;
ramdac->index = (ramdac->index + 1) & 0x07ff;
}
break;
case 0x07:
ramdac->indx_cntl = val & 0x01;
break;
default:
break;
}
return;
}
uint8_t
ibm_rgb528_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga)
{
ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) priv;
uint8_t temp = 0xff;
uint8_t rs = (addr & 0x03);
uint8_t loc_read = (ramdac->indexed_data[0x30] & 0x10);
rs |= (!!rs2 << 2);
switch (rs) {
case 0x00: /* Palette Write Index Register (RS value = 0000) */
case 0x01: /* Palette Data Register (RS value = 0001) */
case 0x02: /* Pixel Read Mask Register (RS value = 0010) */
temp = svga_in(addr, svga);
break;
case 0x03: /* Palette Read Index Register (RS value = 0011) */
temp = svga->dac_addr & 0xff;
if (ramdac->indexed_data[0x070] & 0x20)
temp = (temp & 0xfc) | svga->dac_status;
break;
case 0x04:
temp = ramdac->index & 0xff;
break;
case 0x05:
temp = ramdac->index >> 8;
break;
case 0x06:
temp = ramdac->indexed_data[ramdac->index];
switch (ramdac->index) {
case 0x0000: /* Revision */
temp = 0xe0;
break;
case 0x0001: /* ID */
temp = 0x02;
break;
case 0x0031:
if (loc_read)
temp = ramdac->hwc_x & 0xff;
break;
case 0x0032:
if (loc_read)
temp = ramdac->hwc_x >> 8;
break;
case 0x0033:
if (loc_read)
temp = ramdac->hwc_y & 0xff;
break;
case 0x0034:
if (loc_read)
temp = ramdac->hwc_y >> 8;
break;
default:
temp = ramdac->indexed_data[ramdac->index];
break;
}
if (ramdac->indx_cntl) {
if (ramdac->index == 0x00ff)
ramdac->cursor_array = 0;
ramdac->index = (ramdac->index + 1) & 0x07ff;
}
break;
case 0x07:
temp = ramdac->indx_cntl;
break;
default:
break;
}
return temp;
}
void
ibm_rgb528_recalctimings(void *priv, svga_t *svga)
{
const ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) priv;
svga->interlace = ramdac->indexed_data[0x071] & 0x20;
if (svga->scrblank || !svga->attr_palette_enable) {
if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) {
if (((svga->gdcreg[5] & 0x60) == 0x40) || ((svga->gdcreg[5] & 0x60) == 0x60)) {
if (ramdac->indexed_data[0x071] & 0x01) {
switch (svga->bpp) {
case 4:
svga->render = ibm_rgb528_render_4bpp;
break;
case 8:
svga->render = ibm_rgb528_render_8bpp;
break;
case 15:
case 16:
svga->render = ibm_rgb528_render_15_16bpp;
break;
case 24:
svga->render = ibm_rgb528_render_24bpp;
break;
case 32:
svga->render = ibm_rgb528_render_32bpp;
break;
default:
break;
}
}
}
}
}
}
void
ibm_rgb528_hwcursor_draw(svga_t *svga, int displine)
{
uint8_t dat;
uint8_t four_pixels = 0x00;
int pitch;
int x_pos;
int y_pos;
int offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff;
uint32_t *p;
const ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) svga->ramdac;
uint8_t pix_ordr = ramdac->indexed_data[0x30] & 0x20;
uint8_t cursor_mode = ramdac->indexed_data[0x30] & 0x03;
/* The planes come in one part, and each plane is 2bpp,
so a 32x32 cursor has 8 bytes per line, and a 64x64
cursor has 16 bytes per line. */
pitch = (svga->dac_hwcursor_latch.cur_xsize >> 2); /* Bytes per line. */
if ((ramdac->indexed_data[0x071] & 0x20) && svga->dac_hwcursor_oddeven)
svga->dac_hwcursor_latch.addr += pitch;
y_pos = displine;
x_pos = offset + svga->x_add;
p = buffer32->line[y_pos];
for (int x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x++) {
if (!(x & 3))
four_pixels = ramdac->indexed_data[svga->dac_hwcursor_latch.addr];
if (pix_ordr)
dat = (four_pixels >> (((3 - x) & 3) << 1)) & 0x03;
else
dat = (four_pixels >> ((x & 3) << 1)) & 0x03;
x_pos = offset + svga->x_add + x;
switch (cursor_mode) {
case 0x01:
switch (dat) {
case 0x01:
/* Cursor Color 1 */
p[x_pos] = ramdac->extra_pal[0].pixel;
break;
case 0x02:
/* Cursor Color 2 */
p[x_pos] = ramdac->extra_pal[1].pixel;
break;
case 0x03:
/* Cursor Color 3 */
p[x_pos] = ramdac->extra_pal[2].pixel;
break;
default:
break;
}
break;
case 0x02:
switch (dat) {
case 0x00:
/* Cursor Color 1 */
p[x_pos] = ramdac->extra_pal[0].pixel;
break;
case 0x01:
/* Cursor Color 2 */
p[x_pos] = ramdac->extra_pal[1].pixel;
break;
case 0x03:
/* Complement */
p[x_pos] ^= 0xffffff;
break;
default:
break;
}
break;
case 0x03:
switch (dat) {
case 0x02:
/* Cursor Color 1 */
p[x_pos] = ramdac->extra_pal[0].pixel;
break;
case 0x03:
/* Cursor Color 2 */
p[x_pos] = ramdac->extra_pal[1].pixel;
break;
default:
break;
}
break;
default:
break;
}
if ((x & 3) == 3)
svga->dac_hwcursor_latch.addr++;
}
if ((ramdac->indexed_data[0x071] & 0x20) && !svga->dac_hwcursor_oddeven)
svga->dac_hwcursor_latch.addr += pitch;
}
void *
ibm_rgb528_ramdac_init(UNUSED(const device_t *info))
{
ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) malloc(sizeof(ibm_rgb528_ramdac_t));
memset(ramdac, 0, sizeof(ibm_rgb528_ramdac_t));
ramdac->smlc_part = 0x0100;
ramdac->indexed_data[0x0008] = 0x0001;
ramdac->indexed_data[0x0015] = 0x0008;
ramdac->indexed_data[0x0016] = 0x0041;
return ramdac;
}
static void
ibm_rgb528_ramdac_close(void *priv)
{
ibm_rgb528_ramdac_t *ramdac = (ibm_rgb528_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t ibm_rgb528_ramdac_device = {
.name = "IBM RGB528 RAMDAC",
.internal_name = "ibm_rgb528_ramdac",
.flags = 0,
.local = 0,
.init = ibm_rgb528_ramdac_init,
.close = ibm_rgb528_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,205 @@
/*
* 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 Sierra SC1148x RAMDACs and clones (e.g.: Winbond).
*
* Used by the S3 911 and 924 chips.
*
*
*
* Authors: TheCollector1995, <mariogplayer90@gmail.com>
*
* Copyright 2020 TheCollector1995.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
typedef struct sc1148x_ramdac_t {
int type;
int state;
int rs2;
uint8_t ctrl;
} sc1148x_ramdac_t;
void
sc1148x_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga)
{
sc1148x_ramdac_t *ramdac = (sc1148x_ramdac_t *) priv;
uint8_t rs = (addr & 0x03) | ((!!rs2) << 2);
int oldbpp = 0;
switch (rs) {
case 2:
case 6:
switch (ramdac->state) {
case 4:
ramdac->state = 0;
if (val == 0xff)
break;
ramdac->ctrl = val;
ramdac->ctrl = (ramdac->ctrl & ~1) | ((((val >> 2) ^ val) & (val & 0x20)) >> 5);
oldbpp = svga->bpp;
switch (ramdac->type) {
case 0: /* Sierra Mark 2 (11483)*/
case 2: /* Sierra Mark 2 (11484)*/
case 3: /* Sierra Mark 1 (11486)*/
if (val & 0xa0) {
svga->bpp = 15;
} else if (val == 0x00)
svga->bpp = 8;
break;
case 1: /* Sierra Mark 3 (11487)*/
if (val & 0xa0) {
if (val & 0x40)
svga->bpp = 16;
else
svga->bpp = 15;
} else if (val == 0x00)
svga->bpp = 8;
break;
default:
break;
}
if (oldbpp != svga->bpp)
svga_recalctimings(svga);
return;
default:
svga_out(addr, val, svga);
break;
}
break;
default:
ramdac->state = 0;
svga_out(addr, val, svga);
break;
}
}
uint8_t
sc1148x_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga)
{
sc1148x_ramdac_t *ramdac = (sc1148x_ramdac_t *) priv;
uint8_t ret = 0xff;
uint8_t rs = (addr & 0x03) | ((!!rs2) << 2);
switch (rs) {
case 2:
case 6:
switch (ramdac->state) {
case 1:
case 2:
case 3:
ret = 0x00;
ramdac->state++;
break;
case 4:
ret = ramdac->ctrl;
ret = (ret & ~0x18) | (svga->dac_mask & 0x18);
break;
default:
ret = svga_in(addr, svga);
ramdac->state++;
break;
}
break;
default:
ret = svga_in(addr, svga);
ramdac->state = 0;
break;
}
return ret;
}
static void *
sc1148x_ramdac_init(const device_t *info)
{
sc1148x_ramdac_t *ramdac = (sc1148x_ramdac_t *) malloc(sizeof(sc1148x_ramdac_t));
memset(ramdac, 0, sizeof(sc1148x_ramdac_t));
ramdac->type = info->local;
return ramdac;
}
static void
sc1148x_ramdac_close(void *priv)
{
sc1148x_ramdac_t *ramdac = (sc1148x_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t sc11483_ramdac_device = {
.name = "Sierra SC11483 RAMDAC",
.internal_name = "sc11483_ramdac",
.flags = 0,
.local = 0,
.init = sc1148x_ramdac_init,
.close = sc1148x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sc11487_ramdac_device = {
.name = "Sierra SC11487 RAMDAC",
.internal_name = "sc11487_ramdac",
.flags = 0,
.local = 1,
.init = sc1148x_ramdac_init,
.close = sc1148x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sc11484_nors2_ramdac_device = {
.name = "Sierra SC11484 RAMDAC (no RS2 signal)",
.internal_name = "sc11484_nors2_ramdac",
.flags = 0,
.local = 2,
.init = sc1148x_ramdac_init,
.close = sc1148x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sc11486_ramdac_device = {
.name = "Sierra SC11486 RAMDAC",
.internal_name = "sc11486_ramdac",
.flags = 0,
.local = 3,
.init = sc1148x_ramdac_init,
.close = sc1148x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,256 @@
/*
* 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 a Sierra SC1502X RAMDAC.
*
* Used by the TLIVESA1 driver for ET4000.
*
*
*
* Authors: Sarah Walker, <https://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/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
#include <86box/plat_unused.h>
typedef struct sc1502x_ramdac_t {
int state;
uint8_t ctrl;
uint8_t idx;
uint8_t regs[256];
uint32_t pixel_mask;
uint8_t enable_ext;
} sc1502x_ramdac_t;
static void
sc1502x_ramdac_bpp(uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga)
{
int oldbpp = 0;
if (val == 0xff)
return;
ramdac->ctrl = val;
oldbpp = svga->bpp;
switch ((val & 1) | ((val & 0xc0) >> 5)) {
case 0:
svga->bpp = 8;
break;
case 2:
case 3:
switch (val & 0x20) {
case 0x00:
svga->bpp = 32;
break;
case 0x20:
svga->bpp = 24;
break;
default:
break;
}
break;
case 4:
case 5:
svga->bpp = 15;
break;
case 6:
svga->bpp = 16;
break;
case 7:
if (val & 4) {
switch (val & 0x20) {
case 0x00:
svga->bpp = 32;
break;
case 0x20:
svga->bpp = 24;
break;
default:
break;
}
} else
svga->bpp = 16;
break;
default:
break;
}
if (oldbpp != svga->bpp)
svga_recalctimings(svga);
}
void
sc1502x_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga)
{
sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) priv;
switch (addr) {
case 0x3C6:
if (ramdac->state == 0)
ramdac->enable_ext = (val == 0x10);
if (ramdac->state == 4) {
ramdac->state = 0;
sc1502x_ramdac_bpp(val, ramdac, svga);
return;
}
ramdac->state = 0;
break;
case 0x3C7:
if (ramdac->enable_ext) {
ramdac->idx = val;
return;
}
ramdac->state = 0;
break;
case 0x3C8:
if (ramdac->enable_ext) {
switch (ramdac->idx) {
case 8:
ramdac->regs[ramdac->idx] = val;
svga_set_ramdac_type(svga, (ramdac->regs[ramdac->idx] & 1) ? RAMDAC_8BIT : RAMDAC_6BIT);
break;
case 0x0d:
ramdac->pixel_mask = val & svga->dac_mask;
break;
case 0x0e:
ramdac->pixel_mask |= ((val & svga->dac_mask) << 8);
break;
case 0x0f:
ramdac->pixel_mask |= ((val & svga->dac_mask) << 16);
break;
default:
ramdac->regs[ramdac->idx] = val;
break;
}
return;
}
ramdac->state = 0;
break;
case 0x3C9:
if (ramdac->enable_ext)
return;
ramdac->state = 0;
break;
default:
break;
}
svga_out(addr, val, svga);
}
uint8_t
sc1502x_ramdac_in(uint16_t addr, void *priv, svga_t *svga)
{
sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) priv;
uint8_t temp = svga_in(addr, svga);
switch (addr) {
case 0x3C6:
if (ramdac->state == 4) {
ramdac->state = 0;
temp = ramdac->ctrl;
break;
}
ramdac->state++;
break;
case 0x3C7:
ramdac->state = 0;
break;
case 0x3C8:
if (ramdac->enable_ext) {
switch (ramdac->idx) {
case 9:
temp = 0x53;
break;
case 0x0a:
temp = 0x3a;
break;
case 0x0b:
temp = 0xb1;
break;
case 0x0c:
temp = 0x41;
break;
case 0x0d:
temp = ramdac->pixel_mask & 0xff;
break;
case 0x0e:
temp = ramdac->pixel_mask >> 8;
break;
case 0x0f:
temp = ramdac->pixel_mask >> 16;
break;
default:
temp = ramdac->regs[ramdac->idx];
break;
}
} else
ramdac->state = 0;
break;
case 0x3C9:
if (ramdac->enable_ext)
temp = ramdac->idx;
else
ramdac->state = 0;
break;
default:
break;
}
return temp;
}
static void *
sc1502x_ramdac_init(UNUSED(const device_t *info))
{
sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) malloc(sizeof(sc1502x_ramdac_t));
memset(ramdac, 0, sizeof(sc1502x_ramdac_t));
ramdac->ctrl = 0;
ramdac->pixel_mask = 0xffffff;
return ramdac;
}
static void
sc1502x_ramdac_close(void *priv)
{
sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t sc1502x_ramdac_device = {
.name = "Sierra SC1502x RAMDAC",
.internal_name = "sc1502x_ramdac",
.flags = 0,
.local = 0,
.init = sc1502x_ramdac_init,
.close = sc1502x_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,362 @@
/*
* 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.
*
* 87C716 'SDAC' true colour RAMDAC emulation.
*
*
*
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2008-2019 Sarah Walker.
* Copyright 2016-2019 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
enum {
ICS_5300 = 0,
ICS_5301,
ICS_5340,
ICS_5341,
ICS_5342
};
#define ICS_S3_MASK 7
#define ICS_S3 8
#define S3_86C708 (ICS_5300 | ICS_S3)
#define S3_86C716 (ICS_5342 | ICS_S3)
typedef struct sdac_ramdac_t {
uint16_t regs[256];
int magic_count;
int windex;
int rindex;
int reg_ff;
int rs2;
uint8_t type;
uint8_t command;
} sdac_ramdac_t;
static void
sdac_control_write(sdac_ramdac_t *ramdac, svga_t *svga, uint8_t val)
{
ramdac->command = val;
switch (ramdac->type & ICS_S3_MASK) {
case ICS_5300:
case ICS_5301:
switch (val >> 5) {
default:
case 0x00:
svga->bpp = 8;
break;
case 0x01:
case 0x04:
case 0x05:
svga->bpp = 15;
break;
case 0x03:
case 0x06:
svga->bpp = 16;
break;
case 0x02:
case 0x07:
svga->bpp = 24;
break;
}
break;
case ICS_5340:
case ICS_5341:
case ICS_5342:
switch (val >> 4) {
default:
case 0x00:
case 0x01: /* This is actually 8bpp with two pixels read at a time. */
svga->bpp = 8;
break;
case 0x02:
case 0x03:
case 0x08:
case 0x0a:
svga->bpp = 15;
break;
case 0x05:
case 0x06:
case 0x0c:
svga->bpp = 16;
break;
case 0x04:
case 0x09:
case 0x0e:
svga->bpp = 24;
break;
case 0x07:
svga->bpp = 32;
break;
}
break;
default:
break;
}
svga_recalctimings(svga);
}
static void
sdac_reg_write(sdac_ramdac_t *ramdac, int reg, uint8_t val)
{
if ((reg >= 2 && reg <= 7) || (reg == 0xa) || (reg == 0xe)) {
if (!ramdac->reg_ff)
ramdac->regs[reg] = (ramdac->regs[reg] & 0xff00) | val;
else
ramdac->regs[reg] = (ramdac->regs[reg] & 0x00ff) | (val << 8);
}
ramdac->reg_ff = !ramdac->reg_ff;
if (!ramdac->reg_ff)
ramdac->windex++;
}
static uint8_t
sdac_reg_read(sdac_ramdac_t *ramdac, int reg)
{
uint8_t temp;
if (!ramdac->reg_ff)
temp = ramdac->regs[reg] & 0xff;
else
temp = ramdac->regs[reg] >> 8;
ramdac->reg_ff = !ramdac->reg_ff;
if (!ramdac->reg_ff)
ramdac->rindex++;
return temp;
}
void
sdac_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga)
{
sdac_ramdac_t *ramdac = (sdac_ramdac_t *) priv;
uint8_t rs = (addr & 0x03);
rs |= ((!!rs2) << 2);
if (rs != 0x02)
ramdac->magic_count = 0;
switch (rs) {
case 0x02:
switch (ramdac->magic_count) {
case 4:
sdac_control_write(ramdac, svga, val);
ramdac->magic_count = 0;
break;
default:
svga_out(addr, val, svga);
break;
}
break;
case 0x00:
case 0x01:
case 0x03:
svga_out(addr, val, svga);
break;
case 0x04:
ramdac->windex = val;
ramdac->reg_ff = 0;
break;
case 0x05:
sdac_reg_write(ramdac, ramdac->windex & 0xff, val);
break;
case 0x06:
sdac_control_write(ramdac, svga, val);
break;
case 0x07:
ramdac->rindex = val;
ramdac->reg_ff = 0;
break;
default:
break;
}
}
uint8_t
sdac_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga)
{
sdac_ramdac_t *ramdac = (sdac_ramdac_t *) priv;
uint8_t temp = 0xff;
uint8_t rs = (addr & 0x03);
rs |= ((!!rs2) << 2);
if (rs != 0x02)
ramdac->magic_count = 0;
switch (rs) {
case 0x02:
switch (ramdac->magic_count) {
case 1:
case 2:
temp = 0x00;
ramdac->magic_count++;
break;
case 3:
temp = (ramdac->type & ICS_S3) ? 0x70 : 0x00;
ramdac->magic_count++;
break;
case 4:
temp = ramdac->command;
ramdac->magic_count = 0;
break;
default:
temp = svga_in(addr, svga);
ramdac->magic_count++;
break;
}
break;
case 0x00:
case 0x01:
case 0x03:
temp = svga_in(addr, svga);
break;
case 0x04:
temp = ramdac->windex;
break;
case 0x05:
temp = sdac_reg_read(ramdac, ramdac->rindex & 0xff);
break;
case 0x06:
temp = ramdac->command;
break;
case 0x07:
temp = ramdac->rindex;
break;
default:
break;
}
return temp;
}
float
sdac_getclock(int clock, void *priv)
{
const sdac_ramdac_t *ramdac = (sdac_ramdac_t *) priv;
float t;
int m;
int n1;
int n2;
if (ramdac->regs[0xe] & (1 << 5))
clock = ramdac->regs[0xe] & 7;
clock &= 7;
if (clock == 0)
return 25175000.0;
if (clock == 1)
return 28322000.0;
m = (ramdac->regs[clock] & 0x7f) + 2;
n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2;
n2 = ((ramdac->regs[clock] >> 13) & 0x07);
n2 = (1 << n2);
t = (14318184.0f * (float) m) / (float) (n1 * n2);
return t;
}
void *
sdac_ramdac_init(const device_t *info)
{
sdac_ramdac_t *ramdac = (sdac_ramdac_t *) malloc(sizeof(sdac_ramdac_t));
memset(ramdac, 0, sizeof(sdac_ramdac_t));
ramdac->type = info->local;
ramdac->regs[0] = 0x6128;
ramdac->regs[1] = 0x623d;
return ramdac;
}
static void
sdac_ramdac_close(void *priv)
{
sdac_ramdac_t *ramdac = (sdac_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t gendac_ramdac_device = {
.name = "S3 GENDAC 86c708 RAMDAC",
.internal_name = "gendac_ramdac",
.flags = 0,
.local = S3_86C708,
.init = sdac_ramdac_init,
.close = sdac_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t tseng_ics5301_ramdac_device = {
.name = "Tseng ICS5301 GENDAC RAMDAC",
.internal_name = "tseng_ics5301_ramdac",
.flags = 0,
.local = ICS_5301,
.init = sdac_ramdac_init,
.close = sdac_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t tseng_ics5341_ramdac_device = {
.name = "Tseng ICS5341 GENDAC RAMDAC",
.internal_name = "tseng_ics5341_ramdac",
.flags = 0,
.local = ICS_5341,
.init = sdac_ramdac_init,
.close = sdac_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t sdac_ramdac_device = {
.name = "S3 SDAC 86c716 RAMDAC",
.internal_name = "sdac_ramdac",
.flags = 0,
.local = S3_86C716,
.init = sdac_ramdac_init,
.close = sdac_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,270 @@
/*
* 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.
*
* STG1702 true colour RAMDAC emulation.
*
*
*
* Authors: Sarah Walker, <https://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/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
#include <86box/plat_unused.h>
typedef struct stg_ramdac_t {
int magic_count, index;
uint8_t regs[256];
uint8_t command;
} stg_ramdac_t;
static int stg_state_read[2][8] = {
{1, 2, 3, 4, 0, 0, 0, 0},
{ 1, 2, 3, 4, 5, 6, 7, 7}
};
static int stg_state_write[8] = { 0, 0, 0, 0, 0, 6, 7, 7 };
void
stg_ramdac_set_bpp(svga_t *svga, stg_ramdac_t *ramdac)
{
if (ramdac->command & 0x8) {
switch (ramdac->regs[3]) {
default:
case 0:
case 5:
case 7:
svga->bpp = 8;
break;
case 1:
case 2:
case 8:
svga->bpp = 15;
break;
case 3:
case 6:
svga->bpp = 16;
break;
case 4:
case 9:
svga->bpp = 24;
break;
}
} else {
switch (ramdac->command >> 5) {
default:
case 0:
svga->bpp = 8;
break;
case 5:
svga->bpp = 15;
break;
case 6:
svga->bpp = 16;
break;
case 7:
svga->bpp = 24;
break;
}
}
svga_recalctimings(svga);
}
void
stg_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga)
{
stg_ramdac_t *ramdac = (stg_ramdac_t *) priv;
int didwrite;
int old;
switch (addr) {
case 0x3c6:
switch (ramdac->magic_count) {
/* 0 = PEL mask register */
case 0:
case 1:
case 2:
case 3:
break;
case 4: /* REG06 */
old = ramdac->command;
ramdac->command = val;
if ((old ^ val) & 8)
stg_ramdac_set_bpp(svga, ramdac);
else {
if ((old ^ val) & 0xE0)
stg_ramdac_set_bpp(svga, ramdac);
}
break;
case 5:
ramdac->index = (ramdac->index & 0xff00) | val;
break;
case 6:
ramdac->index = (ramdac->index & 0xff) | (val << 8);
break;
case 7:
if (ramdac->index < 0x100)
ramdac->regs[ramdac->index] = val;
if ((ramdac->index == 3) && (ramdac->command & 8))
stg_ramdac_set_bpp(svga, ramdac);
ramdac->index++;
break;
default:
break;
}
didwrite = (ramdac->magic_count >= 4);
ramdac->magic_count = stg_state_write[ramdac->magic_count & 7];
if (didwrite)
return;
break;
case 0x3c7:
case 0x3c8:
case 0x3c9:
ramdac->magic_count = 0;
break;
default:
break;
}
svga_out(addr, val, svga);
}
uint8_t
stg_ramdac_in(uint16_t addr, void *priv, svga_t *svga)
{
stg_ramdac_t *ramdac = (stg_ramdac_t *) priv;
uint8_t temp = 0xff;
switch (addr) {
case 0x3c6:
switch (ramdac->magic_count) {
case 0:
case 1:
case 2:
case 3:
temp = 0xff;
break;
case 4:
temp = ramdac->command;
break;
case 5:
temp = ramdac->index & 0xff;
break;
case 6:
temp = ramdac->index >> 8;
break;
case 7:
switch (ramdac->index) {
case 0:
temp = 0x44;
break;
case 1:
temp = 0x03;
break;
case 7:
temp = 0x88;
break;
default:
if (ramdac->index < 0x100)
temp = ramdac->regs[ramdac->index];
else
temp = 0xff;
break;
}
ramdac->index++;
break;
default:
break;
}
ramdac->magic_count = stg_state_read[(ramdac->command & 0x10) ? 1 : 0][ramdac->magic_count & 7];
return temp;
case 0x3c7:
case 0x3c8:
case 0x3c9:
ramdac->magic_count = 0;
break;
default:
break;
}
return svga_in(addr, svga);
}
float
stg_getclock(int clock, void *priv)
{
stg_ramdac_t *ramdac = (stg_ramdac_t *) priv;
float t;
int m;
int n;
int n2;
const uint16_t *c;
if (clock == 0)
return 25175000.0;
if (clock == 1)
return 28322000.0;
clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/
c = (uint16_t *) &ramdac->regs[0x20 + (clock << 1)];
m = (*c & 0xff) + 2; /* B+2 */
n = ((*c >> 8) & 0x1f) + 2; /* N1+2 */
n2 = ((*c >> 13) & 0x07); /* D */
n2 = (1 << n2);
t = (14318184.0f * (float) m) / (float) (n * n2);
return t;
}
static void *
stg_ramdac_init(UNUSED(const device_t *info))
{
stg_ramdac_t *ramdac = (stg_ramdac_t *) malloc(sizeof(stg_ramdac_t));
memset(ramdac, 0, sizeof(stg_ramdac_t));
return ramdac;
}
static void
stg_ramdac_close(void *priv)
{
stg_ramdac_t *ramdac = (stg_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t stg_ramdac_device = {
.name = "SGS-Thompson STG170x RAMDAC",
.internal_name = "stg_ramdac",
.flags = 0,
.local = 0,
.init = stg_ramdac_init,
.close = stg_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,136 @@
/*
* 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.
*
* Trident TKD8001 RAMDAC emulation.
*
*
*
* Authors: Sarah Walker, <https://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/86box.h>
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/mem.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
#include <86box/plat_unused.h>
typedef struct tkd8001_ramdac_t {
int state;
uint8_t ctrl;
} tkd8001_ramdac_t;
void
tkd8001_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga)
{
tkd8001_ramdac_t *ramdac = (tkd8001_ramdac_t *) priv;
switch (addr) {
case 0x3C6:
if (ramdac->state == 4) {
ramdac->state = 0;
ramdac->ctrl = val;
switch (val >> 5) {
case 0:
case 1:
case 2:
case 3:
svga->bpp = 8;
break;
case 5:
svga->bpp = 15;
break;
case 6:
svga->bpp = 24;
break;
case 7:
svga->bpp = 16;
break;
default:
break;
}
return;
}
break;
case 0x3C7:
case 0x3C8:
case 0x3C9:
ramdac->state = 0;
break;
default:
break;
}
svga_out(addr, val, svga);
}
uint8_t
tkd8001_ramdac_in(uint16_t addr, void *priv, svga_t *svga)
{
tkd8001_ramdac_t *ramdac = (tkd8001_ramdac_t *) priv;
switch (addr) {
case 0x3C6:
if (ramdac->state == 4)
return ramdac->ctrl;
ramdac->state++;
break;
case 0x3C7:
case 0x3C8:
case 0x3C9:
ramdac->state = 0;
break;
default:
break;
}
return svga_in(addr, svga);
}
static void *
tkd8001_ramdac_init(UNUSED(const device_t *info))
{
tkd8001_ramdac_t *ramdac = (tkd8001_ramdac_t *) malloc(sizeof(tkd8001_ramdac_t));
memset(ramdac, 0, sizeof(tkd8001_ramdac_t));
return ramdac;
}
static void
tkd8001_ramdac_close(void *priv)
{
tkd8001_ramdac_t *ramdac = (tkd8001_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t tkd8001_ramdac_device = {
.name = "Trident TKD8001 RAMDAC",
.internal_name = "tkd8001_ramdac",
.flags = 0,
.local = 0,
.init = tkd8001_ramdac_init,
.close = tkd8001_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -0,0 +1,740 @@
/*
* 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 Texas Instruments TVP3026 true colour RAMDAC
* family.
*
*
* TODO: Clock and other parts.
*
* Authors: TheCollector1995,
*
* Copyright 2021 TheCollector1995.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/vid_svga.h>
#include <86box/plat_fallthrough.h>
typedef struct tvp3026_ramdac_t {
PALETTE extpal;
uint32_t extpallook[256];
uint8_t cursor64_data[1024];
int hwc_y;
int hwc_x;
uint8_t ind_idx;
uint8_t dcc;
uint8_t dc_init;
uint8_t ccr;
uint8_t true_color;
uint8_t latch_cntl;
uint8_t mcr;
uint8_t ppr;
uint8_t general_cntl;
uint8_t mclk;
uint8_t misc;
uint8_t type;
uint8_t mode;
uint8_t pll_addr;
uint8_t clock_sel;
struct {
uint8_t m;
uint8_t n;
uint8_t p;
} pix, mem, loop;
uint8_t gpio_cntl;
uint8_t gpio_data;
uint8_t (*gpio_read)(uint8_t cntl, void *priv);
void (*gpio_write)(uint8_t cntl, uint8_t val, void *priv);
void *gpio_priv;
} tvp3026_ramdac_t;
static void
tvp3026_set_bpp(tvp3026_ramdac_t *ramdac, svga_t *svga)
{
if (ramdac->true_color & 0x80) {
if (ramdac->mcr & 0x08)
svga->bpp = 8;
else
svga->bpp = 4;
} else {
switch (ramdac->true_color & 0x0f) {
case 0x01:
case 0x03:
case 0x05:
svga->bpp = 16;
break;
case 0x04:
svga->bpp = 15;
break;
case 0x06:
case 0x07:
if (ramdac->true_color & 0x10)
svga->bpp = 24;
else
svga->bpp = 32;
break;
case 0x0e:
case 0x0f:
svga->bpp = 24;
break;
default:
break;
}
}
svga_recalctimings(svga);
}
void
tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *priv, svga_t *svga)
{
tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
uint32_t o32;
uint8_t *cd;
uint16_t index;
uint8_t rs = (addr & 0x03);
uint16_t da_mask = 0x03ff;
rs |= (!!rs2 << 2);
rs |= (!!rs3 << 3);
switch (rs) {
case 0x00: /* Palette Write Index Register (RS value = 0000) */
ramdac->ind_idx = val;
fallthrough;
case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */
case 0x03:
case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */
svga->dac_pos = 0;
svga->dac_status = addr & 0x03;
svga->dac_addr = val;
if (svga->dac_status)
svga->dac_addr = (svga->dac_addr + 1) & da_mask;
break;
case 0x01: /* Palette Data Register (RS value = 0001) */
case 0x02: /* Pixel Read Mask Register (RS value = 0010) */
svga_out(addr, val, svga);
break;
case 0x05: /* Ext Palette Data Register (RS value = 0101) */
svga->dac_status = 0;
svga->fullchange = changeframecount;
switch (svga->dac_pos) {
case 0:
svga->dac_r = val;
svga->dac_pos++;
break;
case 1:
svga->dac_g = val;
svga->dac_pos++;
break;
case 2:
index = svga->dac_addr & 3;
ramdac->extpal[index].r = svga->dac_r;
ramdac->extpal[index].g = svga->dac_g;
ramdac->extpal[index].b = val;
if (svga->ramdac_type == RAMDAC_8BIT)
ramdac->extpallook[index] = makecol32(ramdac->extpal[index].r, ramdac->extpal[index].g, ramdac->extpal[index].b);
else
ramdac->extpallook[index] = makecol32(video_6to8[ramdac->extpal[index].r & 0x3f], video_6to8[ramdac->extpal[index].g & 0x3f], video_6to8[ramdac->extpal[index].b & 0x3f]);
if (svga->ext_overscan && !index) {
o32 = svga->overscan_color;
svga->overscan_color = ramdac->extpallook[0];
if (o32 != svga->overscan_color)
svga_recalctimings(svga);
}
svga->dac_addr = (svga->dac_addr + 1) & 0xff;
svga->dac_pos = 0;
break;
default:
break;
}
break;
case 0x09: /* Direct Cursor Control (RS value = 1001) */
ramdac->dcc = val;
if (ramdac->ccr & 0x80) {
svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64;
svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
svga->dac_hwcursor.ena = !!(val & 0x03);
ramdac->mode = val & 0x03;
}
break;
case 0x0a: /* Indexed Data (RS value = 1010) */
switch (ramdac->ind_idx) {
case 0x06: /* Indirect Cursor Control */
ramdac->ccr = val;
if (!(ramdac->ccr & 0x80)) {
svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64;
svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
svga->dac_hwcursor.ena = !!(val & 0x03);
ramdac->mode = val & 0x03;
} else {
svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64;
svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
svga->dac_hwcursor.ena = !!(ramdac->dcc & 0x03);
ramdac->mode = ramdac->dcc & 0x03;
}
break;
case 0x0f: /* Latch Control */
ramdac->latch_cntl = val;
break;
case 0x18: /* True Color Control */
ramdac->true_color = val;
tvp3026_set_bpp(ramdac, svga);
break;
case 0x19: /* Multiplex Control */
ramdac->mcr = val;
tvp3026_set_bpp(ramdac, svga);
break;
case 0x1a: /* Clock Selection */
ramdac->clock_sel = val;
break;
case 0x1c: /* Palette-Page Register */
ramdac->ppr = val;
break;
case 0x1d: /* General Control Register */
ramdac->general_cntl = val;
break;
case 0x1e: /* Miscellaneous Control */
ramdac->misc = val;
svga->ramdac_type = (val & 0x08) ? RAMDAC_8BIT : RAMDAC_6BIT;
break;
case 0x2a: /* General-Purpose I/O Control */
ramdac->gpio_cntl = val;
if (ramdac->gpio_write)
ramdac->gpio_write(ramdac->gpio_cntl, ramdac->gpio_data, ramdac->gpio_priv);
break;
case 0x2b: /* General-Purpose I/O Data */
ramdac->gpio_data = val;
if (ramdac->gpio_write)
ramdac->gpio_write(ramdac->gpio_cntl, ramdac->gpio_data, ramdac->gpio_priv);
break;
case 0x2c: /* PLL Address */
ramdac->pll_addr = val;
break;
case 0x2d: /* Pixel clock PLL data */
switch (ramdac->pll_addr & 3) {
case 0:
ramdac->pix.n = val;
break;
case 1:
ramdac->pix.m = val;
break;
case 2:
ramdac->pix.p = val;
break;
default:
break;
}
ramdac->pll_addr = ((ramdac->pll_addr + 1) & 3) | (ramdac->pll_addr & 0xfc);
break;
case 0x2e: /* Memory Clock PLL Data */
switch ((ramdac->pll_addr >> 2) & 3) {
case 0:
ramdac->mem.n = val;
break;
case 1:
ramdac->mem.m = val;
break;
case 2:
ramdac->mem.p = val;
break;
default:
break;
}
ramdac->pll_addr = ((ramdac->pll_addr + 4) & 0x0c) | (ramdac->pll_addr & 0xf3);
break;
case 0x2f: /* Loop Clock PLL Data */
switch ((ramdac->pll_addr >> 4) & 3) {
case 0:
ramdac->loop.n = val;
break;
case 1:
ramdac->loop.m = val;
break;
case 2:
ramdac->loop.p = val;
break;
default:
break;
}
ramdac->pll_addr = ((ramdac->pll_addr + 0x10) & 0x30) | (ramdac->pll_addr & 0xcf);
break;
case 0x39: /* MCLK/Loop Clock Control */
ramdac->mclk = val;
break;
default:
break;
}
break;
case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */
index = (svga->dac_addr & da_mask) | ((ramdac->ccr & 0x0c) << 6);
cd = (uint8_t *) ramdac->cursor64_data;
cd[index] = val;
svga->dac_addr = (svga->dac_addr + 1) & da_mask;
break;
case 0x0c: /* Cursor X Low Register (RS value = 1100) */
ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val;
svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
break;
case 0x0d: /* Cursor X High Register (RS value = 1101) */
ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8);
svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
break;
case 0x0e: /* Cursor Y Low Register (RS value = 1110) */
ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val;
svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
break;
case 0x0f: /* Cursor Y High Register (RS value = 1111) */
ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8);
svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
break;
default:
break;
}
return;
}
uint8_t
tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *priv, svga_t *svga)
{
tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
uint8_t temp = 0xff;
const uint8_t *cd;
uint16_t index;
uint8_t rs = (addr & 0x03);
uint16_t da_mask = 0x03ff;
rs |= (!!rs2 << 2);
rs |= (!!rs3 << 3);
switch (rs) {
case 0x00: /* Palette Write Index Register (RS value = 0000) */
case 0x01: /* Palette Data Register (RS value = 0001) */
case 0x02: /* Pixel Read Mask Register (RS value = 0010) */
case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */
temp = svga_in(addr, svga);
break;
case 0x03: /* Palette Read Index Register (RS value = 0011) */
case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */
temp = svga->dac_addr & 0xff;
break;
case 0x05: /* Ext Palette Data Register (RS value = 0101) */
index = (svga->dac_addr - 1) & 3;
svga->dac_status = 3;
switch (svga->dac_pos) {
case 0:
svga->dac_pos++;
if (svga->ramdac_type == RAMDAC_8BIT)
temp = ramdac->extpal[index].r;
else
temp = ramdac->extpal[index].r & 0x3f;
break;
case 1:
svga->dac_pos++;
if (svga->ramdac_type == RAMDAC_8BIT)
temp = ramdac->extpal[index].g;
else
temp = ramdac->extpal[index].g & 0x3f;
break;
case 2:
svga->dac_pos = 0;
svga->dac_addr = svga->dac_addr + 1;
if (svga->ramdac_type == RAMDAC_8BIT)
temp = ramdac->extpal[index].b;
else
temp = ramdac->extpal[index].b & 0x3f;
break;
default:
break;
}
break;
case 0x09: /* Direct Cursor Control (RS value = 1001) */
temp = ramdac->dcc;
break;
case 0x0a: /* Indexed Data (RS value = 1010) */
switch (ramdac->ind_idx) {
case 0x01: /* Silicon Revision */
temp = 0x00;
break;
case 0x06: /* Indirect Cursor Control */
temp = ramdac->ccr;
break;
case 0x0f: /* Latch Control */
temp = ramdac->latch_cntl;
break;
case 0x18: /* True Color Control */
temp = ramdac->true_color;
break;
case 0x19: /* Multiplex Control */
temp = ramdac->mcr;
break;
case 0x1a: /* Clock Selection */
temp = ramdac->clock_sel;
break;
case 0x1c: /* Palette-Page Register */
temp = ramdac->ppr;
break;
case 0x1d: /* General Control Register */
temp = ramdac->general_cntl;
break;
case 0x1e: /* Miscellaneous Control */
temp = ramdac->misc;
break;
case 0x2a: /* General-Purpose I/O Control */
temp = ramdac->gpio_cntl;
break;
case 0x2b: /* General-Purpose I/O Data */
if (ramdac->gpio_read) {
temp = 0xe0 | (ramdac->gpio_cntl & 0x1f); /* keep upper bits untouched */
ramdac->gpio_data = (ramdac->gpio_data & temp) | (ramdac->gpio_read(ramdac->gpio_cntl, ramdac->gpio_priv) & ~temp);
}
temp = ramdac->gpio_data;
break;
case 0x2c: /* PLL Address */
temp = ramdac->pll_addr;
break;
case 0x2d: /* Pixel clock PLL data */
switch (ramdac->pll_addr & 3) {
case 0:
temp = ramdac->pix.n;
break;
case 1:
temp = ramdac->pix.m;
break;
case 2:
temp = ramdac->pix.p;
break;
case 3:
temp = 0x40; /*PLL locked to frequency*/
break;
default:
break;
}
break;
case 0x2e: /* Memory Clock PLL Data */
switch ((ramdac->pll_addr >> 2) & 3) {
case 0:
temp = ramdac->mem.n;
break;
case 1:
temp = ramdac->mem.m;
break;
case 2:
temp = ramdac->mem.p;
break;
case 3:
temp = 0x40; /*PLL locked to frequency*/
break;
default:
break;
}
break;
case 0x2f: /* Loop Clock PLL Data */
switch ((ramdac->pll_addr >> 4) & 3) {
case 0:
temp = ramdac->loop.n;
break;
case 1:
temp = ramdac->loop.m;
break;
case 2:
temp = ramdac->loop.p;
break;
default:
break;
}
break;
case 0x39: /* MCLK/Loop Clock Control */
temp = ramdac->mclk;
break;
case 0x3f: /* ID */
temp = 0x26;
break;
default:
break;
}
break;
case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */
index = ((svga->dac_addr - 1) & da_mask) | ((ramdac->ccr & 0x0c) << 6);
cd = (uint8_t *) ramdac->cursor64_data;
temp = cd[index];
svga->dac_addr = (svga->dac_addr + 1) & da_mask;
break;
case 0x0c: /* Cursor X Low Register (RS value = 1100) */
temp = ramdac->hwc_x & 0xff;
break;
case 0x0d: /* Cursor X High Register (RS value = 1101) */
temp = (ramdac->hwc_x >> 8) & 0xff;
break;
case 0x0e: /* Cursor Y Low Register (RS value = 1110) */
temp = ramdac->hwc_y & 0xff;
break;
case 0x0f: /* Cursor Y High Register (RS value = 1111) */
temp = (ramdac->hwc_y >> 8) & 0xff;
break;
default:
break;
}
return temp;
}
void
tvp3026_recalctimings(void *priv, svga_t *svga)
{
const tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
svga->interlace = !!(ramdac->ccr & 0x40);
/* TODO: Figure out gamma correction for 15/16 bpp color. */
svga->lut_map = !!((svga->bpp >= 15 && (svga->bpp != 24)) && (ramdac->true_color & 0xf0) != 0x00);
if (!(ramdac->clock_sel & 0x70)) {
if (ramdac->mcr != 0x98) {
svga->hdisp <<= 1;
svga->dots_per_clock <<= 1;
}
}
}
uint32_t
tvp3026_conv_16to32(svga_t* svga, uint16_t color, uint8_t bpp)
{
uint32_t ret = 0x00000000;
if (svga->lut_map) {
if (bpp == 15) {
uint8_t b = getcolr(svga->pallook[(color & 0x1f) << 3]);
uint8_t g = getcolg(svga->pallook[(color & 0x3e0) >> 2]);
uint8_t r = getcolb(svga->pallook[(color & 0x7c00) >> 7]);
ret = (video_15to32[color] & 0xFF000000) | makecol(r, g, b);
} else {
uint8_t b = getcolr(svga->pallook[(color & 0x1f) << 3]);
uint8_t g = getcolg(svga->pallook[(color & 0x7e0) >> 3]);
uint8_t r = getcolb(svga->pallook[(color & 0xf800) >> 8]);
ret = (video_16to32[color] & 0xFF000000) | makecol(r, g, b);
}
} else
ret = (bpp == 15) ? video_15to32[color] : video_16to32[color];
return ret;
}
void
tvp3026_hwcursor_draw(svga_t *svga, int displine)
{
int comb;
int b0;
int b1;
uint16_t dat[2];
int offset = svga->dac_hwcursor_latch.x + svga->dac_hwcursor_latch.xoff;
int pitch;
int bppl;
int mode;
int x_pos;
int y_pos;
uint32_t clr1;
uint32_t clr2;
uint32_t clr3;
uint32_t *p;
const uint8_t *cd;
tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) svga->ramdac;
clr1 = ramdac->extpallook[1];
clr2 = ramdac->extpallook[2];
clr3 = ramdac->extpallook[3];
/* The planes come in two parts, and each plane is 1bpp,
so a 32x32 cursor has 4 bytes per line, and a 64x64
cursor has 8 bytes per line. */
pitch = (svga->dac_hwcursor_latch.cur_xsize >> 3); /* Bytes per line. */
/* A 32x32 cursor has 128 bytes per line, and a 64x64
cursor has 512 bytes per line. */
bppl = (pitch * svga->dac_hwcursor_latch.cur_ysize); /* Bytes per plane. */
mode = ramdac->mode;
if (svga->interlace && svga->dac_hwcursor_oddeven)
svga->dac_hwcursor_latch.addr += pitch;
cd = (uint8_t *) ramdac->cursor64_data;
for (int x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += 16) {
dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | cd[svga->dac_hwcursor_latch.addr + 1];
dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | cd[svga->dac_hwcursor_latch.addr + bppl + 1];
for (uint8_t xx = 0; xx < 16; xx++) {
b0 = (dat[0] >> (15 - xx)) & 1;
b1 = (dat[1] >> (15 - xx)) & 1;
comb = (b0 | (b1 << 1));
y_pos = displine;
x_pos = (offset + svga->x_add) & 2047;
p = svga->monitor->target_buffer->line[y_pos];
if (offset >= svga->dac_hwcursor_latch.x) {
switch (mode) {
case 1: /* Three Color */
switch (comb) {
case 1:
p[x_pos] = clr1;
break;
case 2:
p[x_pos] = clr2;
break;
case 3:
p[x_pos] = clr3;
break;
default:
break;
}
break;
case 2: /* XGA */
switch (comb) {
case 0:
p[x_pos] = clr1;
break;
case 1:
p[x_pos] = clr2;
break;
case 3:
p[x_pos] ^= 0xffffff;
break;
default:
break;
}
break;
case 3: /* X-Windows */
switch (comb) {
case 2:
p[x_pos] = clr1;
break;
case 3:
p[x_pos] = clr2;
break;
default:
break;
}
break;
default:
break;
}
}
offset++;
}
svga->dac_hwcursor_latch.addr += 2;
}
if (svga->interlace && !svga->dac_hwcursor_oddeven)
svga->dac_hwcursor_latch.addr += pitch;
}
float
tvp3026_getclock(int clock, void *priv)
{
const tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
int n;
int m;
int pl;
float f_vco;
float f_pll;
if (clock == 0)
return 25175000.0;
if (clock == 1)
return 28322000.0;
/*Fvco = 8 x Fref x (65 - M) / (65 - N)*/
/*Fpll = Fvco / 2^P*/
n = ramdac->pix.n & 0x3f;
m = ramdac->pix.m & 0x3f;
pl = ramdac->pix.p & 0x03;
f_vco = 8.0f * 14318184 * (float) (65 - m) / (float) (65 - n);
f_pll = f_vco / (float) (1 << pl);
return f_pll;
}
void
tvp3026_gpio(uint8_t (*read)(uint8_t cntl, void *priv),
void (*write)(uint8_t cntl, uint8_t val, void *priv),
void *cb_priv, void *priv)
{
tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
ramdac->gpio_read = read;
ramdac->gpio_write = write;
ramdac->gpio_priv = cb_priv;
}
void *
tvp3026_ramdac_init(const device_t *info)
{
tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) malloc(sizeof(tvp3026_ramdac_t));
memset(ramdac, 0, sizeof(tvp3026_ramdac_t));
ramdac->type = info->local;
ramdac->latch_cntl = 0x06;
ramdac->true_color = 0x80;
ramdac->mcr = 0x98;
ramdac->clock_sel = 0x07;
ramdac->mclk = 0x18;
return ramdac;
}
static void
tvp3026_ramdac_close(void *priv)
{
tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
if (ramdac)
free(ramdac);
}
const device_t tvp3026_ramdac_device = {
.name = "TI TVP3026 RAMDAC",
.internal_name = "tvp3026_ramdac",
.flags = 0,
.local = 0,
.init = tvp3026_ramdac_init,
.close = tvp3026_ramdac_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};