Files
86Box/src/video/vid_cl54xx.c
2025-09-21 12:24:17 +02:00

5518 lines
192 KiB
C

/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Emulation of select Cirrus Logic cards (CL-GD 5428,
* CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported).
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* tonioni,
* TheCollector1995,
*
* Copyright 2016-2020 Miran Grca.
* Copyright 2020 tonioni.
* Copyright 2016-2020 TheCollector1995.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <wchar.h>
#include <86box/86box.h>
#include "cpu.h"
#include <86box/io.h>
#include <86box/mca.h>
#include <86box/mem.h>
#include <86box/pci.h>
#include <86box/rom.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/i2c.h>
#include <86box/vid_ddc.h>
#include <86box/vid_xga.h>
#include <86box/vid_svga.h>
#include <86box/vid_svga_render.h>
#include <86box/plat_fallthrough.h>
#include <86box/plat_unused.h>
#define BIOS_GD5401_PATH "roms/video/cirruslogic/avga1.rom"
#define BIOS_GD5401_ONBOARD_PATH "roms/machines/drsm35286/qpaw01-6658237d5e3c2611427518.bin"
#define BIOS_GD5402_PATH "roms/video/cirruslogic/avga2.rom"
#define BIOS_GD5402_ONBOARD_PATH "roms/machines/cmdsl386sx25/c000.rom"
#define BIOS_GD5420_PATH "roms/video/cirruslogic/5420.vbi"
#define BIOS_GD5422_PATH "roms/video/cirruslogic/cl5422.bin"
#define BIOS_GD5426_DIAMOND_A1_ISA_PATH "roms/video/cirruslogic/diamond5426.vbi"
#define BIOS_GD5426_MCA_PATH "roms/video/cirruslogic/Reply.BIN"
#define BIOS_GD5428_DIAMOND_B1_VLB_PATH "roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin"
#define BIOS_GD5428_ISA_PATH "roms/video/cirruslogic/5428.bin"
#define BIOS_GD5428_MCA_PATH "roms/video/cirruslogic/SVGA141.ROM"
#define BIOS_GD5428_PATH "roms/video/cirruslogic/vlbusjapan.BIN"
#define BIOS_GD5428_BOCA_ISA_PATH_1 "roms/video/cirruslogic/boca_gd5428_1.30b_1.bin"
#define BIOS_GD5428_BOCA_ISA_PATH_2 "roms/video/cirruslogic/boca_gd5428_1.30b_2.bin"
#define BIOS_GD5429_PATH "roms/video/cirruslogic/5429.vbi"
#define BIOS_GD5430_DIAMOND_A8_VLB_PATH "roms/video/cirruslogic/diamondvlbus.bin"
#define BIOS_GD5430_ORCHID_VLB_PATH "roms/video/cirruslogic/orchidvlbus.bin"
#define BIOS_GD5430_PATH "roms/video/cirruslogic/pci.bin"
#define BIOS_GD5434_DIAMOND_A3_ISA_PATH "roms/video/cirruslogic/Diamond Multimedia SpeedStar 64 v2.02 EPROM Backup from ST M27C256B-12F1.BIN"
#define BIOS_GD5434_PATH "roms/video/cirruslogic/gd5434.BIN"
#define BIOS_GD5436_PATH "roms/video/cirruslogic/5436.vbi"
#define BIOS_GD5440_PATH "roms/video/cirruslogic/BIOS.BIN"
#define BIOS_GD5446_PATH "roms/video/cirruslogic/5446bv.vbi"
#define BIOS_GD5446_STB_PATH "roms/video/cirruslogic/stb nitro64v.BIN"
#define BIOS_GD5480_PATH "roms/video/cirruslogic/clgd5480.rom"
#define CIRRUS_ID_CLGD5401 0x88
#define CIRRUS_ID_CLGD5402 0x89
#define CIRRUS_ID_CLGD5420 0x8a
#define CIRRUS_ID_CLGD5422 0x8c
#define CIRRUS_ID_CLGD5424 0x94
#define CIRRUS_ID_CLGD5426 0x90
#define CIRRUS_ID_CLGD5428 0x98
#define CIRRUS_ID_CLGD5429 0x9c
#define CIRRUS_ID_CLGD5430 0xa0
#define CIRRUS_ID_CLGD5432 0xa2
#define CIRRUS_ID_CLGD5434_4 0xa4
#define CIRRUS_ID_CLGD5434 0xa8
#define CIRRUS_ID_CLGD5436 0xac
#define CIRRUS_ID_CLGD5440 0xa0 /* Yes, the 5440 has the same ID as the 5430. */
#define CIRRUS_ID_CLGD5446 0xb8
#define CIRRUS_ID_CLGD5480 0xbc
/* sequencer 0x07 */
#define CIRRUS_SR7_BPP_VGA 0x00
#define CIRRUS_SR7_BPP_SVGA 0x01
#define CIRRUS_SR7_BPP_MASK 0x0e
#define CIRRUS_SR7_BPP_8 0x00
#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02
#define CIRRUS_SR7_BPP_24 0x04
#define CIRRUS_SR7_BPP_16 0x06
#define CIRRUS_SR7_BPP_32 0x08
#define CIRRUS_SR7_ISAADDR_MASK 0xe0
/* sequencer 0x12 */
#define CIRRUS_CURSOR_SHOW 0x01
#define CIRRUS_CURSOR_HIDDENPEL 0x02
#define CIRRUS_CURSOR_LARGE 0x04 /* 64x64 if set, 32x32 if clear */
/* sequencer 0x17 */
#define CIRRUS_BUSTYPE_VLBFAST 0x10
#define CIRRUS_BUSTYPE_PCI 0x20
#define CIRRUS_BUSTYPE_VLBSLOW 0x30
#define CIRRUS_BUSTYPE_ISA 0x38
#define CIRRUS_MMIO_ENABLE 0x04
#define CIRRUS_MMIO_USE_PCIADDR 0x40 /* 0xb8000 if cleared. */
#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80
/* control 0x0b */
#define CIRRUS_BANKING_DUAL 0x01
#define CIRRUS_BANKING_GRANULARITY_16K 0x20 /* set:16k, clear:4k */
/* control 0x30 */
#define CIRRUS_BLTMODE_BACKWARDS 0x01
#define CIRRUS_BLTMODE_MEMSYSDEST 0x02
#define CIRRUS_BLTMODE_MEMSYSSRC 0x04
#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08
#define CIRRUS_BLTMODE_PATTERNCOPY 0x40
#define CIRRUS_BLTMODE_COLOREXPAND 0x80
#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30
#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00
#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10
#define CIRRUS_BLTMODE_PIXELWIDTH24 0x20
#define CIRRUS_BLTMODE_PIXELWIDTH32 0x30
/* control 0x31 */
#define CIRRUS_BLT_BUSY 0x01
#define CIRRUS_BLT_START 0x02
#define CIRRUS_BLT_RESET 0x04
#define CIRRUS_BLT_FIFOUSED 0x10
#define CIRRUS_BLT_PAUSED 0x20
#define CIRRUS_BLT_APERTURE2 0x40
#define CIRRUS_BLT_AUTOSTART 0x80
/* control 0x33 */
#define CIRRUS_BLTMODEEXT_BACKGROUNDONLY 0x08
#define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04
#define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02
#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01
#define CL_GD5428_SYSTEM_BUS_MCA 5
#define CL_GD5428_SYSTEM_BUS_VESA 6
#define CL_GD5428_SYSTEM_BUS_ISA 7
#define CL_GD5429_SYSTEM_BUS_VESA 5
#define CL_GD5429_SYSTEM_BUS_ISA 7
#define CL_GD543X_SYSTEM_BUS_PCI 4
#define CL_GD543X_SYSTEM_BUS_VESA 6
#define CL_GD543X_SYSTEM_BUS_ISA 7
typedef struct gd54xx_t {
mem_mapping_t mmio_mapping;
mem_mapping_t linear_mapping;
mem_mapping_t aperture2_mapping;
mem_mapping_t vgablt_mapping;
svga_t svga;
int has_bios;
int rev;
int bit32;
rom_t bios_rom;
uint32_t vram_size;
uint32_t vram_mask;
uint8_t vclk_n[4];
uint8_t vclk_d[4];
struct {
uint8_t state;
int ctrl;
} ramdac;
struct {
uint16_t width;
uint16_t height;
uint16_t dst_pitch;
uint16_t src_pitch;
uint16_t trans_col;
uint16_t trans_mask;
uint16_t height_internal;
uint16_t msd_buf_pos;
uint16_t msd_buf_cnt;
uint8_t status;
uint8_t mask;
uint8_t mode;
uint8_t rop;
uint8_t modeext;
uint8_t ms_is_dest;
uint8_t msd_buf[32];
uint32_t fg_col;
uint32_t bg_col;
uint32_t dst_addr_backup;
uint32_t src_addr_backup;
uint32_t dst_addr;
uint32_t src_addr;
uint32_t sys_src32;
uint32_t sys_cnt;
/* Internal state */
int pixel_width;
int pattern_x;
int x_count;
int y_count;
int xx_count;
int dir;
int unlock_special;
} blt;
struct {
int mode;
uint16_t stride;
uint16_t r1sz;
uint16_t r1adjust;
uint16_t r2sz;
uint16_t r2adjust;
uint16_t r2sdz;
uint16_t wvs;
uint16_t wve;
uint16_t hzoom;
uint16_t vzoom;
uint8_t occlusion;
uint8_t colorkeycomparemask;
uint8_t colorkeycompare;
int region1size;
int region2size;
int colorkeymode;
uint32_t ck;
} overlay;
int pci;
int vlb;
int mca;
int countminusone;
int vblank_irq;
int vportsync;
uint8_t pci_regs[256];
uint8_t int_line;
uint8_t unlocked;
uint8_t status;
uint8_t extensions;
uint8_t crtcreg_mask;
uint8_t aperture_mask;
uint8_t fc; /* Feature Connector */
int id;
uint8_t pci_slot;
uint8_t irq_state;
uint8_t pos_regs[8];
uint32_t vlb_lfb_base;
uint32_t lfb_base;
uint32_t vgablt_base;
int mmio_vram_overlap;
uint32_t extpallook[256];
PALETTE extpal;
void *i2c;
void *ddc;
} gd54xx_t;
static video_timings_t timing_gd54xx_isa = { .type = VIDEO_ISA,
.write_b = 3, .write_w = 3, .write_l = 6,
.read_b = 8, .read_w = 8, .read_l = 12 };
static video_timings_t timing_gd54xx_vlb = { .type = VIDEO_BUS,
.write_b = 4, .write_w = 4, .write_l = 8,
.read_b = 10, .read_w = 10, .read_l = 20 };
static video_timings_t timing_gd54xx_pci = { .type = VIDEO_PCI, .write_b = 4,
.write_w = 4, .write_l = 8, .read_b = 10,
.read_w = 10, .read_l = 20 };
static void
gd543x_mmio_write(uint32_t addr, uint8_t val, void *priv);
static void
gd543x_mmio_writeb(uint32_t addr, uint8_t val, void *priv);
static void
gd543x_mmio_writew(uint32_t addr, uint16_t val, void *priv);
static void
gd543x_mmio_writel(uint32_t addr, uint32_t val, void *priv);
static uint8_t
gd543x_mmio_read(uint32_t addr, void *priv);
static uint16_t
gd543x_mmio_readw(uint32_t addr, void *priv);
static uint32_t
gd543x_mmio_readl(uint32_t addr, void *priv);
static void
gd54xx_recalc_banking(gd54xx_t *gd54xx);
static void
gd543x_recalc_mapping(gd54xx_t *gd54xx);
static void
gd54xx_reset_blit(gd54xx_t *gd54xx);
static void
gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *svga);
#define CLAMP(x) \
do { \
if ((x) & ~0xff) \
x = ((x) < 0) ? 0 : 0xff; \
} while (0)
#define DECODE_YCbCr() \
do { \
int c; \
\
for (c = 0; c < 2; c++) { \
uint8_t y1, y2; \
int8_t Cr, Cb; \
int dR, dG, dB; \
\
y1 = src[0]; \
Cr = src[1] - 0x80; \
y2 = src[2]; \
Cb = src[3] - 0x80; \
src += 4; \
\
dR = (359 * Cr) >> 8; \
dG = (88 * Cb + 183 * Cr) >> 8; \
dB = (453 * Cb) >> 8; \
\
r[x_write] = y1 + dR; \
CLAMP(r[x_write]); \
g[x_write] = y1 - dG; \
CLAMP(g[x_write]); \
b[x_write] = y1 + dB; \
CLAMP(b[x_write]); \
\
r[x_write + 1] = y2 + dR; \
CLAMP(r[x_write + 1]); \
g[x_write + 1] = y2 - dG; \
CLAMP(g[x_write + 1]); \
b[x_write + 1] = y2 + dB; \
CLAMP(b[x_write + 1]); \
\
x_write = (x_write + 2) & 7; \
} \
} while (0)
/*Both YUV formats are untested*/
#define DECODE_YUV211() \
do { \
uint8_t y1, y2, y3, y4; \
int8_t U, V; \
int dR, dG, dB; \
\
U = src[0] - 0x80; \
y1 = (298 * (src[1] - 16)) >> 8; \
y2 = (298 * (src[2] - 16)) >> 8; \
V = src[3] - 0x80; \
y3 = (298 * (src[4] - 16)) >> 8; \
y4 = (298 * (src[5] - 16)) >> 8; \
src += 6; \
\
dR = (309 * V) >> 8; \
dG = (100 * U + 208 * V) >> 8; \
dB = (516 * U) >> 8; \
\
r[x_write] = y1 + dR; \
CLAMP(r[x_write]); \
g[x_write] = y1 - dG; \
CLAMP(g[x_write]); \
b[x_write] = y1 + dB; \
CLAMP(b[x_write]); \
\
r[x_write + 1] = y2 + dR; \
CLAMP(r[x_write + 1]); \
g[x_write + 1] = y2 - dG; \
CLAMP(g[x_write + 1]); \
b[x_write + 1] = y2 + dB; \
CLAMP(b[x_write + 1]); \
\
r[x_write + 2] = y3 + dR; \
CLAMP(r[x_write + 2]); \
g[x_write + 2] = y3 - dG; \
CLAMP(g[x_write + 2]); \
b[x_write + 2] = y3 + dB; \
CLAMP(b[x_write + 2]); \
\
r[x_write + 3] = y4 + dR; \
CLAMP(r[x_write + 3]); \
g[x_write + 3] = y4 - dG; \
CLAMP(g[x_write + 3]); \
b[x_write + 3] = y4 + dB; \
CLAMP(b[x_write + 3]); \
\
x_write = (x_write + 4) & 7; \
} while (0)
#define DECODE_YUV422() \
do { \
int c; \
\
for (c = 0; c < 2; c++) { \
uint8_t y1, y2; \
int8_t U, V; \
int dR, dG, dB; \
\
U = src[0] - 0x80; \
y1 = (298 * (src[1] - 16)) >> 8; \
V = src[2] - 0x80; \
y2 = (298 * (src[3] - 16)) >> 8; \
src += 4; \
\
dR = (309 * V) >> 8; \
dG = (100 * U + 208 * V) >> 8; \
dB = (516 * U) >> 8; \
\
r[x_write] = y1 + dR; \
CLAMP(r[x_write]); \
g[x_write] = y1 - dG; \
CLAMP(g[x_write]); \
b[x_write] = y1 + dB; \
CLAMP(b[x_write]); \
\
r[x_write + 1] = y2 + dR; \
CLAMP(r[x_write + 1]); \
g[x_write + 1] = y2 - dG; \
CLAMP(g[x_write + 1]); \
b[x_write + 1] = y2 + dB; \
CLAMP(b[x_write + 1]); \
\
x_write = (x_write + 2) & 7; \
} \
} while (0)
#define DECODE_RGB555() \
do { \
int c; \
\
for (c = 0; c < 4; c++) { \
uint16_t dat; \
\
dat = *(uint16_t *) src; \
src += 2; \
\
r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \
g[x_write + c] = ((dat & 0x03e0) >> 2) | ((dat & 0x03e0) >> 7); \
b[x_write + c] = ((dat & 0x7c00) >> 7) | ((dat & 0x7c00) >> 12); \
} \
x_write = (x_write + 4) & 7; \
} while (0)
#define DECODE_RGB565() \
do { \
int c; \
\
for (c = 0; c < 4; c++) { \
uint16_t dat; \
\
dat = *(uint16_t *) src; \
src += 2; \
\
r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \
g[x_write + c] = ((dat & 0x07e0) >> 3) | ((dat & 0x07e0) >> 9); \
b[x_write + c] = ((dat & 0xf800) >> 8) | ((dat & 0xf800) >> 13); \
} \
x_write = (x_write + 4) & 7; \
} while (0)
#define DECODE_CLUT() \
do { \
int c; \
\
for (c = 0; c < 4; c++) { \
uint8_t dat; \
\
dat = *(uint8_t *) src; \
src++; \
\
r[x_write + c] = svga->pallook[dat] >> 0; \
g[x_write + c] = svga->pallook[dat] >> 8; \
b[x_write + c] = svga->pallook[dat] >> 16; \
} \
x_write = (x_write + 4) & 7; \
} while (0)
#define OVERLAY_SAMPLE() \
do { \
switch (gd54xx->overlay.mode) { \
case 0: \
DECODE_YUV422(); \
break; \
case 2: \
DECODE_CLUT(); \
break; \
case 3: \
DECODE_YUV211(); \
break; \
case 4: \
DECODE_RGB555(); \
break; \
case 5: \
DECODE_RGB565(); \
break; \
} \
} while (0)
static int
gd54xx_interrupt_enabled(gd54xx_t *gd54xx)
{
return !gd54xx->pci || (gd54xx->svga.gdcreg[0x17] & 0x04);
}
static int
gd54xx_vga_vsync_enabled(gd54xx_t *gd54xx)
{
if (!(gd54xx->svga.crtc[0x11] & 0x20) && (gd54xx->svga.crtc[0x11] & 0x10) &&
gd54xx_interrupt_enabled(gd54xx))
return 1;
return 0;
}
static void
gd54xx_update_irqs(gd54xx_t *gd54xx)
{
if (!gd54xx->pci)
return;
if ((gd54xx->vblank_irq > 0) && gd54xx_vga_vsync_enabled(gd54xx))
pci_set_irq(gd54xx->pci_slot, PCI_INTA, &gd54xx->irq_state);
else
pci_clear_irq(gd54xx->pci_slot, PCI_INTA, &gd54xx->irq_state);
}
static void
gd54xx_vblank_start(svga_t *svga)
{
gd54xx_t *gd54xx = (gd54xx_t *) svga->priv;
if (gd54xx->vblank_irq >= 0) {
gd54xx->vblank_irq = 1;
gd54xx_update_irqs(gd54xx);
}
}
/* Returns 1 if the card is a 5422+ */
static int
gd54xx_is_5422(svga_t *svga)
{
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422)
return 1;
else
return 0;
}
static void
gd54xx_overlay_draw(svga_t *svga, int displine)
{
const gd54xx_t *gd54xx = (gd54xx_t *) svga->priv;
int shift = (svga->crtc[0x27] >= CIRRUS_ID_CLGD5446) ? 2 : 0;
int h_acc = svga->overlay_latch.h_acc;
int r[8];
int g[8];
int b[8];
int x_read = 4;
int x_write = 4;
uint32_t *p;
uint8_t *src = &svga->vram[(svga->overlay_latch.addr << shift) & svga->vram_mask];
int bpp = svga->bpp;
int bytesperpix = (bpp + 7) / 8;
uint8_t *src2 = &svga->vram[(svga->memaddr - (svga->hdisp * bytesperpix)) & svga->vram_display_mask];
int occl;
int ckval;
p = &(svga->monitor->target_buffer->line[displine])[gd54xx->overlay.region1size + svga->x_add];
src2 += gd54xx->overlay.region1size * bytesperpix;
OVERLAY_SAMPLE();
for (int x = 0; (x < gd54xx->overlay.region2size) &&
((x + gd54xx->overlay.region1size) < svga->hdisp); x++) {
if (gd54xx->overlay.occlusion) {
occl = 1;
ckval = gd54xx->overlay.ck;
if (bytesperpix == 1) {
if (*src2 == ckval)
occl = 0;
} else if (bytesperpix == 2) {
if (*((uint16_t *) src2) == ckval)
occl = 0;
} else
occl = 0;
if (!occl)
*p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16);
src2 += bytesperpix;
} else
*p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16);
h_acc += gd54xx->overlay.hzoom;
if (h_acc >= 256) {
if ((x_read ^ (x_read + 1)) & ~3)
OVERLAY_SAMPLE();
x_read = (x_read + 1) & 7;
h_acc -= 256;
}
}
svga->overlay_latch.v_acc += gd54xx->overlay.vzoom;
if (svga->overlay_latch.v_acc >= 256) {
svga->overlay_latch.v_acc -= 256;
svga->overlay_latch.addr += svga->overlay.pitch << 1;
}
}
static void
gd54xx_update_overlay(gd54xx_t *gd54xx)
{
svga_t *svga = &gd54xx->svga;
int bpp = svga->bpp;
svga->overlay.cur_ysize = gd54xx->overlay.wve - gd54xx->overlay.wvs + 1;
gd54xx->overlay.region1size = 32 * gd54xx->overlay.r1sz / bpp +
(gd54xx->overlay.r1adjust * 8 / bpp);
gd54xx->overlay.region2size = 32 * gd54xx->overlay.r2sz / bpp +
(gd54xx->overlay.r2adjust * 8 / bpp);
gd54xx->overlay.occlusion = (svga->crtc[0x3e] & 0x80) != 0 && svga->bpp <= 16;
/* Mask and chroma key ignored. */
if (gd54xx->overlay.colorkeymode == 0)
gd54xx->overlay.ck = gd54xx->overlay.colorkeycompare;
else if (gd54xx->overlay.colorkeymode == 1)
gd54xx->overlay.ck = gd54xx->overlay.colorkeycompare |
(gd54xx->overlay.colorkeycomparemask << 8);
else
gd54xx->overlay.occlusion = 0;
}
/* Returns 1 if the card supports the 8-bpp/16-bpp transparency color or mask. */
static int
gd54xx_has_transp(svga_t *svga, int mask)
{
if (((svga->crtc[0x27] == CIRRUS_ID_CLGD5446) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5480)) &&
!mask)
return 1; /* 5446 and 5480 have mask but not transparency. */
if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5426) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5428))
return 1; /* 5426 and 5428 have both. */
else
return 0; /* The rest have neither. */
}
/* Returns 1 if the card is a 5434, 5436/46, or 5480. */
static int
gd54xx_is_5434(svga_t *svga)
{
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5434)
return 1;
else
return 0;
}
static void
gd54xx_set_svga_fast(gd54xx_t *gd54xx)
{
svga_t *svga = &gd54xx->svga;
if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5422) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5424))
svga->fast = ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) &&
!svga->gdcreg[1]) &&
((svga->chain4 && svga->packed_chain4) || svga->fb_only) &&
!(svga->adv_flags & FLAG_ADDR_BY8);
/* TODO: needs verification on other Cirrus chips */
else
svga->fast = ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) &&
!svga->gdcreg[1]) && ((svga->chain4 && svga->packed_chain4) ||
svga->fb_only);
}
static void
gd54xx_out(uint16_t addr, uint8_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint8_t old;
uint8_t o;
uint8_t index;
uint32_t o32;
if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
addr ^= 0x60;
switch (addr) {
case 0x3c0:
case 0x3c1:
if (!svga->attrff) {
svga->attraddr = val & 31;
if ((val & 0x20) != svga->attr_palette_enable) {
svga->fullchange = 3;
svga->attr_palette_enable = val & 0x20;
svga_recalctimings(svga);
}
} else {
o = svga->attrregs[svga->attraddr & 31];
svga->attrregs[svga->attraddr & 31] = val;
if (svga->attraddr < 16)
svga->fullchange = changeframecount;
if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) {
for (uint8_t c = 0; c < 16; c++) {
if (svga->attrregs[0x10] & 0x80)
svga->egapal[c] = (svga->attrregs[c] & 0xf) |
((svga->attrregs[0x14] & 0xf) << 4);
else
svga->egapal[c] = (svga->attrregs[c] & 0x3f) |
((svga->attrregs[0x14] & 0xc) << 4);
}
}
/*
Recalculate timings on change of attribute register
0x11 (overscan border color) too.
*/
if (svga->attraddr == 0x10) {
if (o != val)
svga_recalctimings(svga);
} else if (svga->attraddr == 0x11) {
if (!(svga->seqregs[0x12] & 0x80)) {
svga->overscan_color = svga->pallook[svga->attrregs[0x11]];
if (o != val)
svga_recalctimings(svga);
}
} else if (svga->attraddr == 0x12) {
if ((val & 0xf) != svga->plane_mask)
svga->fullchange = changeframecount;
svga->plane_mask = val & 0xf;
}
}
svga->attrff ^= 1;
return;
case 0x3c4:
svga->seqaddr = val;
break;
case 0x3c5:
if ((svga->seqaddr == 2) && !gd54xx->unlocked) {
o = svga->seqregs[svga->seqaddr & 0x1f];
svga_out(addr, val, svga);
if (svga->gdcreg[0xb] & 0x04)
svga->seqregs[svga->seqaddr & 0x1f] = (o & 0xf0) | (val & 0x0f);
return;
} else if ((svga->seqaddr > 6) && !gd54xx->unlocked)
return;
if (svga->seqaddr > 5) {
o = svga->seqregs[svga->seqaddr & 0x1f];
svga->seqregs[svga->seqaddr & 0x1f] = val;
switch (svga->seqaddr) {
case 6:
val &= 0x17;
if (val == 0x12)
svga->seqregs[6] = 0x12;
else
svga->seqregs[6] = 0x0f;
if (svga->crtc[0x27] < CIRRUS_ID_CLGD5429)
gd54xx->unlocked = (svga->seqregs[6] == 0x12);
break;
case 0x08:
if (gd54xx->i2c)
i2c_gpio_set(gd54xx->i2c, !!(val & 0x01), !!(val & 0x02));
break;
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e: /* VCLK stuff */
gd54xx->vclk_n[svga->seqaddr - 0x0b] = val;
break;
case 0x1b:
case 0x1c:
case 0x1d:
case 0x1e: /* VCLK stuff */
gd54xx->vclk_d[svga->seqaddr - 0x1b] = val;
break;
case 0x10:
case 0x30:
case 0x50:
case 0x70:
case 0x90:
case 0xb0:
case 0xd0:
case 0xf0:
svga->hwcursor.x = (val << 3) | (svga->seqaddr >> 5);
break;
case 0x11:
case 0x31:
case 0x51:
case 0x71:
case 0x91:
case 0xb1:
case 0xd1:
case 0xf1:
svga->hwcursor.y = (val << 3) | (svga->seqaddr >> 5);
break;
case 0x12:
svga->ext_overscan = !!(val & 0x80);
if (svga->ext_overscan && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5426))
svga->overscan_color = gd54xx->extpallook[2];
else
svga->overscan_color = svga->pallook[svga->attrregs[0x11]];
svga_recalctimings(svga);
svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW;
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422)
svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize =
((svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) &&
(val & CIRRUS_CURSOR_LARGE)) ? 64 : 32;
else
svga->hwcursor.cur_xsize = 32;
if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) &&
(svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE))
svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) +
((svga->seqregs[0x13] & 0x3c) * 256));
else
svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) +
((svga->seqregs[0x13] & 0x3f) * 256));
break;
case 0x13:
if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) &&
(svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE))
svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) +
((val & 0x3c) * 256));
else
svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) +
((val & 0x3f) * 256));
break;
case 0x07:
svga->packed_chain4 = svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA;
if (gd54xx_is_5422(svga))
gd543x_recalc_mapping(gd54xx);
else
svga->seqregs[svga->seqaddr] &= 0x0f;
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429)
svga->set_reset_disabled = svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA;
gd54xx_set_svga_fast(gd54xx);
svga_recalctimings(svga);
break;
case 0x17:
if (gd54xx_is_5422(svga))
gd543x_recalc_mapping(gd54xx);
else
return;
break;
default:
break;
}
return;
}
break;
case 0x3c6:
if (!gd54xx->unlocked)
break;
if (gd54xx->ramdac.state == 4) {
gd54xx->ramdac.state = 0;
gd54xx->ramdac.ctrl = val;
svga_recalctimings(svga);
return;
}
gd54xx->ramdac.state = 0;
break;
case 0x3c7:
case 0x3c8:
gd54xx->ramdac.state = 0;
break;
case 0x3c9:
gd54xx->ramdac.state = 0;
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 & 0xff;
if (svga->seqregs[0x12] & 2) {
index &= 0x0f;
gd54xx->extpal[index].r = svga->dac_r;
gd54xx->extpal[index].g = svga->dac_g;
gd54xx->extpal[index].b = val;
gd54xx->extpallook[index] = makecol32(video_6to8[gd54xx->extpal[index].r & 0x3f],
video_6to8[gd54xx->extpal[index].g & 0x3f],
video_6to8[gd54xx->extpal[index].b & 0x3f]);
if (svga->ext_overscan && (index == 2)) {
o32 = svga->overscan_color;
svga->overscan_color = gd54xx->extpallook[2];
if (o32 != svga->overscan_color)
svga_recalctimings(svga);
}
} else {
svga->vgapal[index].r = svga->dac_r;
svga->vgapal[index].g = svga->dac_g;
svga->vgapal[index].b = val;
svga->pallook[index] = makecol32(video_6to8[svga->vgapal[index].r & 0x3f],
video_6to8[svga->vgapal[index].g & 0x3f],
video_6to8[svga->vgapal[index].b & 0x3f]);
}
svga->dac_addr = (svga->dac_addr + 1) & 255;
svga->dac_pos = 0;
break;
default:
break;
}
return;
case 0x3ce:
/* Per the CL-GD 5446 manual: bits 0-5 are the GDC register index, bits 6-7 are reserved. */
svga->gdcaddr = val /* & 0x3f*/;
return;
case 0x3cf:
if (((svga->crtc[0x27] <= CIRRUS_ID_CLGD5422) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5424)) &&
(svga->gdcaddr > 0x1f))
return;
o = svga->gdcreg[svga->gdcaddr];
if ((svga->gdcaddr < 2) && !gd54xx->unlocked)
svga->gdcreg[svga->gdcaddr] = (svga->gdcreg[svga->gdcaddr] & 0xf0) | (val & 0x0f);
else if ((svga->gdcaddr <= 8) || gd54xx->unlocked)
svga->gdcreg[svga->gdcaddr] = val;
if (svga->gdcaddr <= 8) {
switch (svga->gdcaddr) {
case 0:
gd543x_mmio_write(0xb8000, val, gd54xx);
break;
case 1:
gd543x_mmio_write(0xb8004, val, gd54xx);
break;
case 2:
svga->colourcompare = val;
break;
case 4:
svga->readplane = val & 3;
break;
case 5:
if (svga->gdcreg[0xb] & 0x04)
svga->writemode = val & 7;
else
svga->writemode = val & 3;
svga->readmode = val & 8;
svga->chain2_read = val & 0x10;
break;
case 6:
if ((o ^ val) & 0x0c)
gd543x_recalc_mapping(gd54xx);
break;
case 7:
svga->colournocare = val;
break;
default:
break;
}
gd54xx_set_svga_fast(gd54xx);
if (((svga->gdcaddr == 5) && ((val ^ o) & 0x70)) ||
((svga->gdcaddr == 6) && ((val ^ o) & 1)))
svga_recalctimings(svga);
} else {
switch (svga->gdcaddr) {
case 0x0b:
svga->adv_flags = 0;
if (svga->gdcreg[0xb] & 0x01)
svga->adv_flags = FLAG_EXTRA_BANKS;
if (svga->gdcreg[0xb] & 0x02)
svga->adv_flags |= FLAG_ADDR_BY8;
if (svga->gdcreg[0xb] & 0x04)
svga->adv_flags |= FLAG_EXT_WRITE;
if (svga->gdcreg[0xb] & 0x08)
svga->adv_flags |= FLAG_LATCH8;
if ((svga->gdcreg[0xb] & 0x10) && (svga->adv_flags & FLAG_EXT_WRITE))
svga->adv_flags |= FLAG_ADDR_BY16;
if (svga->gdcreg[0xb] & 0x04)
svga->writemode = svga->gdcreg[5] & 7;
else if (o & 0x4) {
svga->gdcreg[5] &= ~0x04;
svga->writemode = svga->gdcreg[5] & 3;
svga->adv_flags &= (FLAG_EXTRA_BANKS | FLAG_ADDR_BY8 | FLAG_LATCH8);
if (svga->crtc[0x27] != CIRRUS_ID_CLGD5436) {
svga->gdcreg[0] &= 0x0f;
gd543x_mmio_write(0xb8000, svga->gdcreg[0], gd54xx);
svga->gdcreg[1] &= 0x0f;
gd543x_mmio_write(0xb8004, svga->gdcreg[1], gd54xx);
}
svga->seqregs[2] &= 0x0f;
}
fallthrough;
case 0x09:
case 0x0a:
gd54xx_recalc_banking(gd54xx);
break;
case 0x0c:
gd54xx->overlay.colorkeycompare = val;
gd54xx_update_overlay(gd54xx);
break;
case 0x0d:
gd54xx->overlay.colorkeycomparemask = val;
gd54xx_update_overlay(gd54xx);
break;
case 0x0e:
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) {
svga->dpms = (val & 0x06) && ((svga->miscout & ((val & 0x06) << 5)) != 0xc0);
svga_recalctimings(svga);
}
break;
case 0x10:
gd543x_mmio_write(0xb8001, val, gd54xx);
break;
case 0x11:
gd543x_mmio_write(0xb8005, val, gd54xx);
break;
case 0x12:
gd543x_mmio_write(0xb8002, val, gd54xx);
break;
case 0x13:
gd543x_mmio_write(0xb8006, val, gd54xx);
break;
case 0x14:
gd543x_mmio_write(0xb8003, val, gd54xx);
break;
case 0x15:
gd543x_mmio_write(0xb8007, val, gd54xx);
break;
case 0x20:
gd543x_mmio_write(0xb8008, val, gd54xx);
break;
case 0x21:
gd543x_mmio_write(0xb8009, val, gd54xx);
break;
case 0x22:
gd543x_mmio_write(0xb800a, val, gd54xx);
break;
case 0x23:
gd543x_mmio_write(0xb800b, val, gd54xx);
break;
case 0x24:
gd543x_mmio_write(0xb800c, val, gd54xx);
break;
case 0x25:
gd543x_mmio_write(0xb800d, val, gd54xx);
break;
case 0x26:
gd543x_mmio_write(0xb800e, val, gd54xx);
break;
case 0x27:
gd543x_mmio_write(0xb800f, val, gd54xx);
break;
case 0x28:
gd543x_mmio_write(0xb8010, val, gd54xx);
break;
case 0x29:
gd543x_mmio_write(0xb8011, val, gd54xx);
break;
case 0x2a:
gd543x_mmio_write(0xb8012, val, gd54xx);
break;
case 0x2c:
gd543x_mmio_write(0xb8014, val, gd54xx);
break;
case 0x2d:
gd543x_mmio_write(0xb8015, val, gd54xx);
break;
case 0x2e:
gd543x_mmio_write(0xb8016, val, gd54xx);
break;
case 0x2f:
gd543x_mmio_write(0xb8017, val, gd54xx);
break;
case 0x30:
gd543x_mmio_write(0xb8018, val, gd54xx);
break;
case 0x32:
gd543x_mmio_write(0xb801a, val, gd54xx);
break;
case 0x33:
gd543x_mmio_write(0xb801b, val, gd54xx);
break;
case 0x31:
gd543x_mmio_write(0xb8040, val, gd54xx);
break;
case 0x34:
gd543x_mmio_write(0xb801c, val, gd54xx);
break;
case 0x35:
gd543x_mmio_write(0xb801d, val, gd54xx);
break;
case 0x38:
gd543x_mmio_write(0xb8020, val, gd54xx);
break;
case 0x39:
gd543x_mmio_write(0xb8021, val, gd54xx);
break;
default:
break;
}
}
return;
case 0x3d4:
svga->crtcreg = val & gd54xx->crtcreg_mask;
return;
case 0x3d5:
if (!gd54xx->unlocked &&
((svga->crtcreg == 0x19) || (svga->crtcreg == 0x1a) ||
(svga->crtcreg == 0x1b) || (svga->crtcreg == 0x1d) ||
(svga->crtcreg == 0x25) || (svga->crtcreg == 0x27)))
return;
if ((svga->crtcreg == 0x25) || (svga->crtcreg == 0x27))
return;
if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
return;
if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
val = (svga->crtc[7] & ~0x10) | (val & 0x10);
old = svga->crtc[svga->crtcreg];
svga->crtc[svga->crtcreg] = val;
if (svga->crtcreg == 0x11) {
if (!(val & 0x10)) {
if (gd54xx->vblank_irq > 0)
gd54xx->vblank_irq = -1;
} else if (gd54xx->vblank_irq < 0)
gd54xx->vblank_irq = 0;
gd54xx_update_irqs(gd54xx);
if ((val & ~0x30) == (old & ~0x30))
old = val;
}
if (old != val) {
/* Overlay registers */
switch (svga->crtcreg) {
case 0x1d:
if (((old >> 3) & 7) != ((val >> 3) & 7)) {
gd54xx->overlay.colorkeymode = (val >> 3) & 7;
gd54xx_update_overlay(gd54xx);
}
break;
case 0x31:
gd54xx->overlay.hzoom = val == 0 ? 256 : val;
gd54xx_update_overlay(gd54xx);
break;
case 0x32:
gd54xx->overlay.vzoom = val == 0 ? 256 : val;
gd54xx_update_overlay(gd54xx);
break;
case 0x33:
gd54xx->overlay.r1sz &= ~0xff;
gd54xx->overlay.r1sz |= val;
gd54xx_update_overlay(gd54xx);
break;
case 0x34:
gd54xx->overlay.r2sz &= ~0xff;
gd54xx->overlay.r2sz |= val;
gd54xx_update_overlay(gd54xx);
break;
case 0x35:
gd54xx->overlay.r2sdz &= ~0xff;
gd54xx->overlay.r2sdz |= val;
gd54xx_update_overlay(gd54xx);
break;
case 0x36:
gd54xx->overlay.r1sz &= 0xff;
gd54xx->overlay.r1sz |= (val << 8) & 0x300;
gd54xx->overlay.r2sz &= 0xff;
gd54xx->overlay.r2sz |= (val << 6) & 0x300;
gd54xx->overlay.r2sdz &= 0xff;
gd54xx->overlay.r2sdz |= (val << 4) & 0x300;
gd54xx_update_overlay(gd54xx);
break;
case 0x37:
gd54xx->overlay.wvs &= ~0xff;
gd54xx->overlay.wvs |= val;
svga->overlay.y = gd54xx->overlay.wvs;
break;
case 0x38:
gd54xx->overlay.wve &= ~0xff;
gd54xx->overlay.wve |= val;
gd54xx_update_overlay(gd54xx);
break;
case 0x39:
gd54xx->overlay.wvs &= 0xff;
gd54xx->overlay.wvs |= (val << 8) & 0x300;
gd54xx->overlay.wve &= 0xff;
gd54xx->overlay.wve |= (val << 6) & 0x300;
gd54xx_update_overlay(gd54xx);
break;
case 0x3a:
svga->overlay.addr &= ~0xff;
svga->overlay.addr |= val;
gd54xx_update_overlay(gd54xx);
break;
case 0x3b:
svga->overlay.addr &= ~0xff00;
svga->overlay.addr |= val << 8;
gd54xx_update_overlay(gd54xx);
break;
case 0x3c:
svga->overlay.addr &= ~0x0f0000;
svga->overlay.addr |= (val << 16) & 0x0f0000;
svga->overlay.pitch &= ~0x100;
svga->overlay.pitch |= (val & 0x20) << 3;
gd54xx_update_overlay(gd54xx);
break;
case 0x3d:
svga->overlay.pitch &= ~0xff;
svga->overlay.pitch |= val;
gd54xx_update_overlay(gd54xx);
break;
case 0x3e:
gd54xx->overlay.mode = (val >> 1) & 7;
svga->overlay.ena = (val & 1) != 0;
gd54xx_update_overlay(gd54xx);
break;
default:
break;
}
if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) {
if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) {
svga->fullchange = 3;
svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) +
((svga->crtc[8] & 0x60) >> 5);
} else {
svga->fullchange = changeframecount;
svga_recalctimings(svga);
}
}
}
break;
default:
break;
}
svga_out(addr, val, svga);
}
static uint8_t
gd54xx_in(uint16_t addr, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint8_t index;
uint8_t ret = 0xff;
if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
addr ^= 0x60;
switch (addr) {
case 0x3c2:
ret = svga_in(addr, svga);
ret |= gd54xx->vblank_irq > 0 ? 0x80 : 0x00;
break;
case 0x3c4:
if (svga->seqregs[6] == 0x12) {
ret = svga->seqaddr;
if ((ret & 0x1e) == 0x10) {
if (ret & 1)
ret = ((svga->hwcursor.y & 7) << 5) | 0x11;
else
ret = ((svga->hwcursor.x & 7) << 5) | 0x10;
}
} else
ret = svga->seqaddr;
break;
case 0x3c5:
if ((svga->seqaddr == 2) && !gd54xx->unlocked)
ret = svga_in(addr, svga) & 0x0f;
else if ((svga->seqaddr > 6) && !gd54xx->unlocked)
ret = 0xff;
else if (svga->seqaddr > 5) {
ret = svga->seqregs[svga->seqaddr & 0x3f];
switch (svga->seqaddr) {
case 6:
ret = svga->seqregs[6];
break;
case 0x08:
if (gd54xx->i2c) {
ret &= 0x7b;
if (i2c_gpio_get_scl(gd54xx->i2c))
ret |= 0x04;
if (i2c_gpio_get_sda(gd54xx->i2c))
ret |= 0x80;
}
break;
case 0x0a:
/* Scratch Pad 1 (Memory size for 5402/542x) */
ret = svga->seqregs[0x0a] & ~0x1a;
if (svga->crtc[0x27] == CIRRUS_ID_CLGD5402) {
ret |= 0x01; /*512K of memory*/
} else if (svga->crtc[0x27] > CIRRUS_ID_CLGD5402) {
switch (gd54xx->vram_size >> 10) {
case 512:
ret |= 0x08;
break;
case 1024:
ret |= 0x10;
break;
case 2048:
ret |= 0x18;
break;
default:
break;
}
}
break;
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e:
ret = gd54xx->vclk_n[svga->seqaddr - 0x0b];
break;
case 0x0f: /* DRAM control */
ret = svga->seqregs[0x0f] & ~0x98;
switch (gd54xx->vram_size >> 10) {
case 512:
ret |= 0x08; /* 16-bit DRAM data bus width */
break;
case 1024:
ret |= 0x10; /* 32-bit DRAM data bus width for 1M of memory */
break;
case 2048:
/*
32-bit (Pre-5434)/64-bit (5434 and up) DRAM data bus width
for 2M of memory
*/
ret |= 0x18;
break;
case 4096:
ret |= 0x98; /*64-bit (5434 and up) DRAM data bus width for 4M of memory*/
break;
default:
break;
}
break;
case 0x15: /*Scratch Pad 3 (Memory size for 543x)*/
ret = svga->seqregs[0x15] & ~0x0f;
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5430) {
switch (gd54xx->vram_size >> 20) {
case 1:
ret |= 0x02;
break;
case 2:
ret |= 0x03;
break;
case 4:
ret |= 0x04;
break;
default:
break;
}
}
break;
case 0x17:
ret = svga->seqregs[0x17] & ~(7 << 3);
if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) {
if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5428) ||
(svga->crtc[0x27] == CIRRUS_ID_CLGD5426)) {
if (gd54xx->vlb)
ret |= (CL_GD5428_SYSTEM_BUS_VESA << 3);
else if (gd54xx->mca)
ret |= (CL_GD5428_SYSTEM_BUS_MCA << 3);
else
ret |= (CL_GD5428_SYSTEM_BUS_ISA << 3);
} else {
if (gd54xx->vlb)
ret |= (CL_GD5429_SYSTEM_BUS_VESA << 3);
else
ret |= (CL_GD5429_SYSTEM_BUS_ISA << 3);
}
} else {
if (gd54xx->pci)
ret |= (CL_GD543X_SYSTEM_BUS_PCI << 3);
else if (gd54xx->vlb)
ret |= (CL_GD543X_SYSTEM_BUS_VESA << 3);
else
ret |= (CL_GD543X_SYSTEM_BUS_ISA << 3);
}
break;
case 0x18:
ret = svga->seqregs[0x18] & 0xfe;
break;
case 0x1b:
case 0x1c:
case 0x1d:
case 0x1e:
ret = gd54xx->vclk_d[svga->seqaddr - 0x1b];
break;
default:
break;
}
break;
} else
ret = svga_in(addr, svga);
break;
case 0x3c6:
if (!gd54xx->unlocked)
ret = svga_in(addr, svga);
else if (gd54xx->ramdac.state == 4) {
/* CL-GD 5428 does not lock the register when it's read. */
if (svga->crtc[0x27] != CIRRUS_ID_CLGD5428)
gd54xx->ramdac.state = 0;
ret = gd54xx->ramdac.ctrl;
} else {
gd54xx->ramdac.state++;
if (gd54xx->ramdac.state == 4)
ret = gd54xx->ramdac.ctrl;
else
ret = svga_in(addr, svga);
}
break;
case 0x3c7:
case 0x3c8:
gd54xx->ramdac.state = 0;
ret = svga_in(addr, svga);
break;
case 0x3c9:
gd54xx->ramdac.state = 0;
svga->dac_status = 3;
index = (svga->dac_addr - 1) & 0xff;
if (svga->seqregs[0x12] & 2)
index &= 0x0f;
switch (svga->dac_pos) {
case 0:
svga->dac_pos++;
if (svga->seqregs[0x12] & 2)
ret = gd54xx->extpal[index].r & 0x3f;
else
ret = svga->vgapal[index].r & 0x3f;
break;
case 1:
svga->dac_pos++;
if (svga->seqregs[0x12] & 2)
ret = gd54xx->extpal[index].g & 0x3f;
else
ret = svga->vgapal[index].g & 0x3f;
break;
case 2:
svga->dac_pos = 0;
svga->dac_addr = (svga->dac_addr + 1) & 255;
if (svga->seqregs[0x12] & 2)
ret = gd54xx->extpal[index].b & 0x3f;
else
ret = svga->vgapal[index].b & 0x3f;
break;
default:
break;
}
break;
case 0x3ce:
ret = svga->gdcaddr & 0x3f;
break;
case 0x3cf:
if (svga->gdcaddr >= 0x10) {
if ((svga->gdcaddr > 8) && !gd54xx->unlocked)
ret = 0xff;
else if (((svga->crtc[0x27] <= CIRRUS_ID_CLGD5422) ||
(svga->crtc[0x27] == CIRRUS_ID_CLGD5424)) &&
(svga->gdcaddr > 0x1f))
ret = 0xff;
else
switch (svga->gdcaddr) {
case 0x10:
ret = gd543x_mmio_read(0xb8001, gd54xx);
break;
case 0x11:
ret = gd543x_mmio_read(0xb8005, gd54xx);
break;
case 0x12:
ret = gd543x_mmio_read(0xb8002, gd54xx);
break;
case 0x13:
ret = gd543x_mmio_read(0xb8006, gd54xx);
break;
case 0x14:
ret = gd543x_mmio_read(0xb8003, gd54xx);
break;
case 0x15:
ret = gd543x_mmio_read(0xb8007, gd54xx);
break;
case 0x20:
ret = gd543x_mmio_read(0xb8008, gd54xx);
break;
case 0x21:
ret = gd543x_mmio_read(0xb8009, gd54xx);
break;
case 0x22:
ret = gd543x_mmio_read(0xb800a, gd54xx);
break;
case 0x23:
ret = gd543x_mmio_read(0xb800b, gd54xx);
break;
case 0x24:
ret = gd543x_mmio_read(0xb800c, gd54xx);
break;
case 0x25:
ret = gd543x_mmio_read(0xb800d, gd54xx);
break;
case 0x26:
ret = gd543x_mmio_read(0xb800e, gd54xx);
break;
case 0x27:
ret = gd543x_mmio_read(0xb800f, gd54xx);
break;
case 0x28:
ret = gd543x_mmio_read(0xb8010, gd54xx);
break;
case 0x29:
ret = gd543x_mmio_read(0xb8011, gd54xx);
break;
case 0x2a:
ret = gd543x_mmio_read(0xb8012, gd54xx);
break;
case 0x2c:
ret = gd543x_mmio_read(0xb8014, gd54xx);
break;
case 0x2d:
ret = gd543x_mmio_read(0xb8015, gd54xx);
break;
case 0x2e:
ret = gd543x_mmio_read(0xb8016, gd54xx);
break;
case 0x2f:
ret = gd543x_mmio_read(0xb8017, gd54xx);
break;
case 0x30:
ret = gd543x_mmio_read(0xb8018, gd54xx);
break;
case 0x32:
ret = gd543x_mmio_read(0xb801a, gd54xx);
break;
case 0x33:
ret = gd543x_mmio_read(0xb801b, gd54xx);
break;
case 0x31:
ret = gd543x_mmio_read(0xb8040, gd54xx);
break;
case 0x34:
ret = gd543x_mmio_read(0xb801c, gd54xx);
break;
case 0x35:
ret = gd543x_mmio_read(0xb801d, gd54xx);
break;
case 0x38:
ret = gd543x_mmio_read(0xb8020, gd54xx);
break;
case 0x39:
ret = gd543x_mmio_read(0xb8021, gd54xx);
break;
case 0x3f:
if (svga->crtc[0x27] == CIRRUS_ID_CLGD5446)
gd54xx->vportsync = !gd54xx->vportsync;
ret = gd54xx->vportsync ? 0x80 : 0x00;
break;
default:
break;
}
} else {
if ((svga->gdcaddr < 2) && !gd54xx->unlocked)
ret = (svga->gdcreg[svga->gdcaddr] & 0x0f);
else {
if (svga->gdcaddr == 0)
ret = gd543x_mmio_read(0xb8000, gd54xx);
else if (svga->gdcaddr == 1)
ret = gd543x_mmio_read(0xb8004, gd54xx);
else
ret = svga->gdcreg[svga->gdcaddr];
}
}
break;
case 0x3d4:
ret = svga->crtcreg;
break;
case 0x3d5:
ret = svga->crtc[svga->crtcreg];
if (((svga->crtcreg == 0x19) || (svga->crtcreg == 0x1a) ||
(svga->crtcreg == 0x1b) || (svga->crtcreg == 0x1d) ||
(svga->crtcreg == 0x25) || (svga->crtcreg == 0x27)) &&
!gd54xx->unlocked)
ret = 0xff;
else
switch (svga->crtcreg) {
case 0x22: /*Graphics Data Latches Readback Register*/
/*Should this be & 7 if 8 byte latch is enabled? */
ret = svga->latch.b[svga->gdcreg[4] & 3];
break;
case 0x24: /*Attribute controller toggle readback (R)*/
ret = svga->attrff << 7;
break;
case 0x26: /*Attribute controller index readback (R)*/
ret = svga->attraddr & 0x3f;
break;
case 0x27: /*ID*/
ret = svga->crtc[0x27]; /*GD542x/GD543x*/
break;
case 0x28: /*Class ID*/
if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5430) ||
(svga->crtc[0x27] == CIRRUS_ID_CLGD5440))
ret = 0xff; /*Standard CL-GD5430/40*/
break;
default:
break;
}
break;
default:
ret = svga_in(addr, svga);
break;
}
return ret;
}
static void
gd54xx_recalc_banking(gd54xx_t *gd54xx)
{
svga_t *svga = &gd54xx->svga;
if (!gd54xx_is_5422(svga)) {
svga->extra_banks[0] = (svga->gdcreg[0x09] & 0x7f) << 12;
if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL)
svga->extra_banks[1] = (svga->gdcreg[0x0a] & 0x7f) << 12;
else
svga->extra_banks[1] = svga->extra_banks[0] + 0x8000;
} else {
if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5426) && (svga->crtc[0x27] != CIRRUS_ID_CLGD5424) &&
(svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K))
svga->extra_banks[0] = svga->gdcreg[0x09] << 14;
else
svga->extra_banks[0] = svga->gdcreg[0x09] << 12;
if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) {
if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5426) && (svga->crtc[0x27] != CIRRUS_ID_CLGD5424) &&
(svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K))
svga->extra_banks[1] = svga->gdcreg[0x0a] << 14;
else
svga->extra_banks[1] = svga->gdcreg[0x0a] << 12;
} else
svga->extra_banks[1] = svga->extra_banks[0] + 0x8000;
}
}
static void
gd543x_recalc_mapping(gd54xx_t *gd54xx)
{
svga_t *svga = &gd54xx->svga;
xga_t *xga = (xga_t *) svga->xga;
uint32_t base;
uint32_t size;
gd54xx->aperture_mask = 0x00;
if (gd54xx->pci && (!(gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM))) {
mem_mapping_disable(&svga->mapping);
mem_mapping_disable(&gd54xx->linear_mapping);
mem_mapping_disable(&gd54xx->mmio_mapping);
return;
}
gd54xx->mmio_vram_overlap = 0;
if (!gd54xx_is_5422(svga) || !(svga->seqregs[0x07] & 0xf0) ||
!(svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA)) {
mem_mapping_disable(&gd54xx->linear_mapping);
mem_mapping_disable(&gd54xx->aperture2_mapping);
switch (svga->gdcreg[6] & 0x0c) {
case 0x0: /*128k at A0000*/
mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000);
svga->banked_mask = 0xffff;
break;
case 0x4: /*64k at A0000*/
mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
svga->banked_mask = 0xffff;
if (xga_active && (svga->xga != NULL)) {
xga->on = 0;
mem_mapping_set_handler(&svga->mapping, svga->read, svga->readw, svga->readl, svga->write, svga->writew, svga->writel);
}
break;
case 0x8: /*32k at B0000*/
mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
svga->banked_mask = 0x7fff;
break;
case 0xC: /*32k at B8000*/
mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
svga->banked_mask = 0x7fff;
gd54xx->mmio_vram_overlap = 1;
break;
default:
break;
}
if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) && (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) &&
(svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA)) {
if (gd54xx->mmio_vram_overlap) {
mem_mapping_disable(&svga->mapping);
mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x08000);
} else
mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100);
} else
mem_mapping_disable(&gd54xx->mmio_mapping);
} else {
if ((svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) ||
(!gd54xx->pci && !gd54xx->vlb)) {
if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) {
base = (svga->seqregs[0x07] & 0xf0) << 16;
size = 1 * 1024 * 1024;
} else {
base = (svga->seqregs[0x07] & 0xe0) << 16;
size = 2 * 1024 * 1024;
}
} else if (gd54xx->pci) {
base = gd54xx->lfb_base;
#if 0
if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480)
size = 32 * 1024 * 1024;
else
#endif
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436)
size = 16 * 1024 * 1024;
else
size = 4 * 1024 * 1024;
} else { /*VLB/ISA/MCA*/
if (gd54xx->vlb_lfb_base != 0x00000000)
base = gd54xx->vlb_lfb_base;
else
base = 128 * 1024 * 1024;
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436)
size = 16 * 1024 * 1024;
else
size = 4 * 1024 * 1024;
}
if (size >= (16 * 1024 * 1024))
gd54xx->aperture_mask = 0x03;
mem_mapping_disable(&svga->mapping);
mem_mapping_set_addr(&gd54xx->linear_mapping, base, size);
if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) &&
(svga->crtc[0x27] >= CIRRUS_ID_CLGD5429)) {
if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)
/* MMIO is handled in the linear read/write functions */
mem_mapping_disable(&gd54xx->mmio_mapping);
else
mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100);
} else
mem_mapping_disable(&gd54xx->mmio_mapping);
if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) &&
(gd54xx->blt.status & CIRRUS_BLT_APERTURE2) &&
((gd54xx->blt.mode & (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC)) ==
(CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC))) {
if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480)
mem_mapping_set_addr(&gd54xx->aperture2_mapping,
gd54xx->lfb_base + 16777216, 16777216);
else
mem_mapping_set_addr(&gd54xx->aperture2_mapping, 0xbc000, 0x04000);
} else
mem_mapping_disable(&gd54xx->aperture2_mapping);
}
}
static void
gd54xx_recalctimings(svga_t *svga)
{
const gd54xx_t *gd54xx = (gd54xx_t *) svga->priv;
uint8_t clocksel;
uint8_t rdmask;
uint8_t linedbl = svga->dispend * 9 / 10 >= svga->hdisp;
svga->hblankstart = svga->crtc[2];
if (svga->crtc[0x1b] & ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5424) ? 0xa0 : 0x20)) {
/*
Special blanking mode: the blank start and end become components
of the window generator, and the actual blanking comes from the
display enable signal.
This means blanking during overscan, we already calculate it that
way, so just use the same calculation and force otvercan to 0.
*/
svga->hblank_end_val = (svga->crtc[3] & 0x1f) | ((svga->crtc[5] & 0x80) ? 0x20 : 0x00) |
(((svga->crtc[0x1a] >> 4) & 3) << 6);
svga->hblank_end_mask = 0x000000ff;
if (svga->crtc[0x1b] & 0x20) {
svga->hblankstart = svga->crtc[1]/* + ((svga->crtc[3] >> 5) & 3) + 1*/;
svga->hblank_end_val = svga->htotal - 1 /* + ((svga->crtc[3] >> 5) & 3)*/;
/* In this mode, the dots per clock are always 8 or 16, never 9 or 18. */
if (!svga->scrblank && svga->attr_palette_enable)
svga->dots_per_clock = (svga->seqregs[1] & 8) ? 16 : 8;
svga->monitor->mon_overscan_y = 0;
svga->monitor->mon_overscan_x = 0;
/* Also make sure vertical blanking starts on display end. */
svga->vblankstart = svga->dispend;
}
}
svga->rowoffset = (svga->crtc[0x13]) | (((int) (uint32_t) (svga->crtc[0x1b] & 0x10)) << 4);
svga->interlace = (svga->crtc[0x1a] & 0x01);
if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/
svga->interlace = 0;
}
svga->map8 = svga->pallook;
if (svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA) {
if (linedbl)
svga->render = svga_render_8bpp_lowres;
else {
svga->render = svga_render_8bpp_highres;
if ((svga->dispend == 512) && !svga->interlace && gd54xx_is_5434(svga)) {
svga->hdisp <<= 1;
svga->dots_per_clock <<= 1;
}
}
} else if (svga->gdcreg[5] & 0x40)
svga->render = svga_render_8bpp_lowres;
svga->memaddr_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15);
svga->bpp = 8;
if (gd54xx->ramdac.ctrl & 0x80) {
if (gd54xx->ramdac.ctrl & 0x40) {
if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5428) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5426))
rdmask = 0xf;
else
rdmask = 0x7;
switch (gd54xx->ramdac.ctrl & rdmask) {
case 0:
svga->bpp = 15;
if (linedbl) {
if (gd54xx->ramdac.ctrl & 0x10)
svga->render = svga_render_15bpp_mix_lowres;
else
svga->render = svga_render_15bpp_lowres;
} else {
if (gd54xx->ramdac.ctrl & 0x10)
svga->render = svga_render_15bpp_mix_highres;
else
svga->render = svga_render_15bpp_highres;
}
break;
case 1:
svga->bpp = 16;
if (linedbl)
svga->render = svga_render_16bpp_lowres;
else
svga->render = svga_render_16bpp_highres;
break;
case 5:
if (gd54xx_is_5434(svga) && (svga->seqregs[0x07] & CIRRUS_SR7_BPP_32)) {
svga->bpp = 32;
if (linedbl)
svga->render = svga_render_32bpp_lowres;
else
svga->render = svga_render_32bpp_highres;
if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) {
svga->rowoffset *= 2;
}
} else {
svga->bpp = 24;
if (linedbl)
svga->render = svga_render_24bpp_lowres;
else
svga->render = svga_render_24bpp_highres;
}
break;
case 8:
svga->bpp = 8;
svga->map8 = video_8togs;
if (linedbl)
svga->render = svga_render_8bpp_lowres;
else
svga->render = svga_render_8bpp_highres;
break;
case 9:
svga->bpp = 8;
svga->map8 = video_8to32;
if (linedbl)
svga->render = svga_render_8bpp_lowres;
else
svga->render = svga_render_8bpp_highres;
break;
case 0xf:
switch (svga->seqregs[0x07] & CIRRUS_SR7_BPP_MASK) {
case CIRRUS_SR7_BPP_32:
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5430) {
svga->bpp = 32;
if (linedbl)
svga->render = svga_render_32bpp_lowres;
else
svga->render = svga_render_32bpp_highres;
svga->rowoffset *= 2;
}
break;
case CIRRUS_SR7_BPP_24:
svga->bpp = 24;
if (linedbl)
svga->render = svga_render_24bpp_lowres;
else
svga->render = svga_render_24bpp_highres;
break;
case CIRRUS_SR7_BPP_16:
if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5428) ||
(svga->crtc[0x27] == CIRRUS_ID_CLGD5426)) {
svga->bpp = 16;
if (linedbl)
svga->render = svga_render_16bpp_lowres;
else
svga->render = svga_render_16bpp_highres;
}
break;
case CIRRUS_SR7_BPP_16_DOUBLEVCLK:
svga->bpp = 16;
if (linedbl)
svga->render = svga_render_16bpp_lowres;
else
svga->render = svga_render_16bpp_highres;
break;
case CIRRUS_SR7_BPP_8:
svga->bpp = 8;
if (linedbl)
svga->render = svga_render_8bpp_lowres;
else
svga->render = svga_render_8bpp_highres;
break;
default:
break;
}
break;
default:
break;
}
} else {
svga->bpp = 15;
if (linedbl) {
if (gd54xx->ramdac.ctrl & 0x10)
svga->render = svga_render_15bpp_mix_lowres;
else
svga->render = svga_render_15bpp_lowres;
} else {
if (gd54xx->ramdac.ctrl & 0x10)
svga->render = svga_render_15bpp_mix_highres;
else
svga->render = svga_render_15bpp_highres;
}
}
}
clocksel = (svga->miscout >> 2) & 3;
if (!gd54xx->vclk_n[clocksel] || !gd54xx->vclk_d[clocksel])
svga->clock = (cpuclock * (float) (1ULL << 32)) /
((svga->miscout & 0xc) ? 28322000.0 : 25175000.0);
else {
int n = gd54xx->vclk_n[clocksel] & 0x7f;
int d = (gd54xx->vclk_d[clocksel] & 0x3e) >> 1;
uint8_t m = gd54xx->vclk_d[clocksel] & 0x01 ? 2 : 1;
float freq = (14318184.0F * ((float) n / ((float) d * m)));
if (gd54xx_is_5422(svga)) {
switch (svga->seqregs[0x07] & (gd54xx_is_5434(svga) ? 0xe : 6)) {
case 2:
freq /= 2.0F;
break;
case 4:
if (!gd54xx_is_5434(svga))
freq /= 3.0F;
break;
default:
break;
}
}
svga->clock = (cpuclock * (double) (1ULL << 32)) / freq;
}
svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff;
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5430)
svga->htotal += ((svga->crtc[0x1c] >> 3) & 0x07);
if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/
if (svga->seqregs[1] & 8)
svga->render = svga_render_text_40;
else
svga->render = svga_render_text_80;
}
if (!(svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA)) {
svga->extra_banks[0] = 0;
svga->extra_banks[1] = 0x8000;
}
}
static void
gd54xx_hwcursor_draw(svga_t *svga, int displine)
{
const gd54xx_t *gd54xx = (gd54xx_t *) svga->priv;
int comb;
int b0;
int b1;
uint8_t dat[2];
int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
int pitch = (svga->hwcursor.cur_xsize == 64) ? 16 : 4;
uint32_t bgcol = gd54xx->extpallook[0x00];
uint32_t fgcol = gd54xx->extpallook[0x0f];
uint8_t linedbl = svga->dispend * 9 / 10 >= svga->hdisp;
offset <<= linedbl;
if (svga->interlace && svga->hwcursor_oddeven)
svga->hwcursor_latch.addr += pitch;
for (int x = 0; x < svga->hwcursor.cur_xsize; x += 8) {
dat[0] = svga->vram[svga->hwcursor_latch.addr & gd54xx->vram_mask];
if (svga->hwcursor.cur_xsize == 64)
dat[1] = svga->vram[(svga->hwcursor_latch.addr + 0x08) & gd54xx->vram_mask];
else
dat[1] = svga->vram[(svga->hwcursor_latch.addr + 0x80) & gd54xx->vram_mask];
for (uint8_t xx = 0; xx < 8; xx++) {
b0 = (dat[0] >> (7 - xx)) & 1;
b1 = (dat[1] >> (7 - xx)) & 1;
comb = (b1 | (b0 << 1));
if (offset >= svga->hwcursor_latch.x) {
switch (comb) {
case 0:
/* The original screen pixel is shown (invisible cursor) */
break;
case 1:
/* The pixel is shown in the cursor background color */
(svga->monitor->target_buffer->line[displine])[offset + svga->x_add] = bgcol;
break;
case 2:
/* The pixel is shown as the inverse of the original screen pixel
(XOR cursor) */
(svga->monitor->target_buffer->line[displine])[offset + svga->x_add] ^= 0xffffff;
break;
case 3:
/* The pixel is shown in the cursor foreground color */
(svga->monitor->target_buffer->line[displine])[offset + svga->x_add] = fgcol;
break;
default:
break;
}
}
offset++;
}
svga->hwcursor_latch.addr++;
}
if (svga->hwcursor.cur_xsize == 64)
svga->hwcursor_latch.addr += 8;
if (svga->interlace && !svga->hwcursor_oddeven)
svga->hwcursor_latch.addr += pitch;
}
static void
gd54xx_rop(gd54xx_t *gd54xx, uint8_t *res, uint8_t *dst, const uint8_t *src)
{
switch (gd54xx->blt.rop) {
case 0x00:
*res = 0x00;
break;
case 0x05:
*res = *src & *dst;
break;
case 0x06:
*res = *dst;
break;
case 0x09:
*res = *src & ~*dst;
break;
case 0x0b:
*res = ~*dst;
break;
case 0x0d:
*res = *src;
break;
case 0x0e:
*res = 0xff;
break;
case 0x50:
*res = ~*src & *dst;
break;
case 0x59:
*res = *src ^ *dst;
break;
case 0x6d:
*res = *src | *dst;
break;
case 0x90:
*res = ~(*src | *dst);
break;
case 0x95:
*res = ~(*src ^ *dst);
break;
case 0xad:
*res = *src | ~*dst;
break;
case 0xd0:
*res = ~*src;
break;
case 0xd6:
*res = ~*src | *dst;
break;
case 0xda:
*res = ~(*src & *dst);
break;
default:
break;
}
}
static uint8_t
gd54xx_get_aperture(gd54xx_t *gd54xx, uint32_t addr)
{
uint32_t ap = addr >> 22;
return (uint8_t) (ap & gd54xx->aperture_mask);
}
static uint32_t
gd54xx_mem_sys_pos_adj(gd54xx_t *gd54xx, uint8_t ap, uint32_t pos)
{
uint32_t ret = pos;
if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) &&
!(gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) {
switch (ap) {
case 1:
ret ^= 1;
break;
case 2:
ret ^= 3;
break;
}
}
return ret;
}
static uint8_t
gd54xx_mem_sys_dest_read(gd54xx_t *gd54xx, uint8_t ap)
{
uint32_t adj_pos = gd54xx_mem_sys_pos_adj(gd54xx, ap, gd54xx->blt.msd_buf_pos);
uint8_t ret = 0xff;
if (gd54xx->blt.msd_buf_cnt != 0) {
ret = gd54xx->blt.msd_buf[adj_pos];
gd54xx->blt.msd_buf_pos++;
gd54xx->blt.msd_buf_cnt--;
if (gd54xx->blt.msd_buf_cnt == 0) {
if (gd54xx->countminusone == 1) {
gd54xx->blt.msd_buf_pos = 0;
if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) &&
!(gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY))
gd54xx_start_blit(0xff, 8, gd54xx, &gd54xx->svga);
else
gd54xx_start_blit(0xffffffff, 32, gd54xx, &gd54xx->svga);
} else
gd54xx_reset_blit(gd54xx); /* End of blit, do no more. */
}
}
return ret;
}
static void
gd54xx_mem_sys_src_write(gd54xx_t *gd54xx, uint8_t val, uint8_t ap)
{
uint32_t adj_pos = gd54xx_mem_sys_pos_adj(gd54xx, ap, gd54xx->blt.sys_cnt);
gd54xx->blt.sys_src32 &= ~(0xff << (adj_pos << 3));
gd54xx->blt.sys_src32 |= (val << (adj_pos << 3));
gd54xx->blt.sys_cnt = (gd54xx->blt.sys_cnt + 1) & 3;
if (gd54xx->blt.sys_cnt == 0) {
if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) &&
!(gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) {
for (uint8_t i = 0; i < 32; i += 8)
gd54xx_start_blit((gd54xx->blt.sys_src32 >> i) & 0xff, 8, gd54xx, &gd54xx->svga);
} else
gd54xx_start_blit(gd54xx->blt.sys_src32, 32, gd54xx, &gd54xx->svga);
}
}
static void
gd54xx_write(uint32_t addr, uint8_t val, void *priv)
{
svga_t *svga = (svga_t *) priv;
gd54xx_t *gd54xx = (gd54xx_t *) svga->local;
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
gd54xx_mem_sys_src_write(gd54xx, val, 0);
return;
}
xga_write_test(addr, val, svga);
addr &= svga->banked_mask;
addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1];
svga_write_linear(addr, val, svga);
}
static void
gd54xx_writew(uint32_t addr, uint16_t val, void *priv)
{
svga_t *svga = (svga_t *) priv;
gd54xx_t *gd54xx = (gd54xx_t *) svga->local;
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY))
val = (val >> 8) | (val << 8);
gd54xx_write(addr, val, svga);
gd54xx_write(addr + 1, val >> 8, svga);
return;
}
xga_write_test(addr, val, svga);
xga_write_test(addr + 1, val >> 8, svga);
addr &= svga->banked_mask;
addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1];
if (svga->writemode < 4)
svga_writew_linear(addr, val, svga);
else {
svga_write_linear(addr, val, svga);
svga_write_linear(addr + 1, val >> 8, svga);
}
}
static void
gd54xx_writel(uint32_t addr, uint32_t val, void *priv)
{
svga_t *svga = (svga_t *) priv;
gd54xx_t *gd54xx = (gd54xx_t *) svga->local;
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY))
val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24);
gd54xx_write(addr, val, svga);
gd54xx_write(addr + 1, val >> 8, svga);
gd54xx_write(addr + 2, val >> 16, svga);
gd54xx_write(addr + 3, val >> 24, svga);
return;
}
xga_write_test(addr, val, svga);
xga_write_test(addr + 1, val >> 8, svga);
xga_write_test(addr + 2, val >> 16, svga);
xga_write_test(addr + 3, val >> 24, svga);
addr &= svga->banked_mask;
addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1];
if (svga->writemode < 4)
svga_writel_linear(addr, val, svga);
else {
svga_write_linear(addr, val, svga);
svga_write_linear(addr + 1, val >> 8, svga);
svga_write_linear(addr + 2, val >> 16, svga);
svga_write_linear(addr + 3, val >> 24, svga);
}
}
/* This adds write modes 4 and 5 to SVGA. */
static void
gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr)
{
uint32_t i;
uint32_t j;
switch (svga->writemode) {
case 4:
if (svga->adv_flags & FLAG_ADDR_BY16) {
addr &= svga->decode_mask;
for (i = 0; i < 8; i++) {
if (val & svga->seqregs[2] & (0x80 >> i)) {
svga->vram[addr + (i << 1)] = svga->gdcreg[1];
svga->vram[addr + (i << 1) + 1] = svga->gdcreg[0x11];
}
}
} else {
addr <<= 1;
addr &= svga->decode_mask;
for (i = 0; i < 8; i++) {
if (val & svga->seqregs[2] & (0x80 >> i))
svga->vram[addr + i] = svga->gdcreg[1];
}
}
break;
case 5:
if (svga->adv_flags & FLAG_ADDR_BY16) {
addr &= svga->decode_mask;
for (i = 0; i < 8; i++) {
j = (0x80 >> i);
if (svga->seqregs[2] & j) {
svga->vram[addr + (i << 1)] = (val & j) ?
svga->gdcreg[1] : svga->gdcreg[0];
svga->vram[addr + (i << 1) + 1] = (val & j) ?
svga->gdcreg[0x11] : svga->gdcreg[0x10];
}
}
} else {
addr <<= 1;
addr &= svga->decode_mask;
for (i = 0; i < 8; i++) {
j = (0x80 >> i);
if (svga->seqregs[2] & j)
svga->vram[addr + i] = (val & j) ? svga->gdcreg[1] : svga->gdcreg[0];
}
}
break;
default:
break;
}
svga->changedvram[addr >> 12] = changeframecount;
}
static int
gd54xx_aperture2_enabled(gd54xx_t *gd54xx)
{
const svga_t *svga = &gd54xx->svga;
if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436)
return 0;
if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND))
return 0;
if (!(gd54xx->blt.status & CIRRUS_BLT_APERTURE2))
return 0;
return 1;
}
static uint8_t
gd54xx_readb_linear(uint32_t addr, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint8_t ap = gd54xx_get_aperture(gd54xx, addr);
addr &= 0x003fffff; /* 4 MB mask */
if (!(svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA))
return svga_read_linear(addr, svga);
if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) {
if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) &&
(svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR))
return gd543x_mmio_read(addr & 0x000000ff, gd54xx);
}
/*
Do mem sys dest reads here if the blitter is neither paused,
nor is there a second aperture.
*/
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
!gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED))
return gd54xx_mem_sys_dest_read(gd54xx, ap);
switch (ap) {
default:
case 0:
break;
case 1:
/* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */
addr ^= 0x00000001;
break;
case 2:
/* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */
addr ^= 0x00000003;
break;
case 3:
return 0xff;
}
return svga_read_linear(addr, svga);
}
static uint16_t
gd54xx_readw_linear(uint32_t addr, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint32_t old_addr = addr;
uint8_t ap = gd54xx_get_aperture(gd54xx, addr);
uint16_t temp;
addr &= 0x003fffff; /* 4 MB mask */
if (!(svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA))
return svga_readw_linear(addr, svga);
if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) {
if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) {
temp = gd543x_mmio_readw(addr & 0x000000ff, gd54xx);
return temp;
}
}
/*
Do mem sys dest reads here if the blitter is neither paused,
nor is there a second aperture.
*/
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
!gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
temp = gd54xx_readb_linear(old_addr, priv);
temp |= gd54xx_readb_linear(old_addr + 1, priv) << 8;
return temp;
}
switch (ap) {
default:
case 0:
return svga_readw_linear(addr, svga);
case 2:
/* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */
addr ^= 0x00000002;
fallthrough;
case 1:
temp = svga_readb_linear(addr + 1, svga);
temp |= (svga_readb_linear(addr, svga) << 8);
if (svga->fast)
cycles -= svga->monitor->mon_video_timing_read_w;
return temp;
case 3:
return 0xffff;
}
}
static uint32_t
gd54xx_readl_linear(uint32_t addr, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint32_t old_addr = addr;
uint8_t ap = gd54xx_get_aperture(gd54xx, addr);
uint32_t temp;
addr &= 0x003fffff; /* 4 MB mask */
if (!(svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA))
return svga_readl_linear(addr, svga);
if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) {
if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) {
temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx);
return temp;
}
}
/*
Do mem sys dest reads here if the blitter is neither paused,
nor is there a second aperture.
*/
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
!gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
temp = gd54xx_readb_linear(old_addr, priv);
temp |= gd54xx_readb_linear(old_addr + 1, priv) << 8;
temp |= gd54xx_readb_linear(old_addr + 2, priv) << 16;
temp |= gd54xx_readb_linear(old_addr + 3, priv) << 24;
return temp;
}
switch (ap) {
default:
case 0:
return svga_readl_linear(addr, svga);
case 1:
temp = svga_readb_linear(addr + 1, svga);
temp |= (svga_readb_linear(addr, svga) << 8);
temp |= (svga_readb_linear(addr + 3, svga) << 16);
temp |= (svga_readb_linear(addr + 2, svga) << 24);
if (svga->fast)
cycles -= svga->monitor->mon_video_timing_read_l;
return temp;
case 2:
temp = svga_readb_linear(addr + 3, svga);
temp |= (svga_readb_linear(addr + 2, svga) << 8);
temp |= (svga_readb_linear(addr + 1, svga) << 16);
temp |= (svga_readb_linear(addr, svga) << 24);
if (svga->fast)
cycles -= svga->monitor->mon_video_timing_read_l;
return temp;
case 3:
return 0xffffffff;
}
}
static uint8_t
gd5436_aperture2_readb(UNUSED(uint32_t addr), void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
uint8_t ap = gd54xx_get_aperture(gd54xx, addr);
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED))
return gd54xx_mem_sys_dest_read(gd54xx, ap);
return 0xff;
}
static uint16_t
gd5436_aperture2_readw(uint32_t addr, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
uint16_t ret = 0xffff;
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
ret = gd5436_aperture2_readb(addr, priv);
ret |= gd5436_aperture2_readb(addr + 1, priv) << 8;
return ret;
}
return ret;
}
static uint32_t
gd5436_aperture2_readl(uint32_t addr, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
uint32_t ret = 0xffffffff;
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
ret = gd5436_aperture2_readb(addr, priv);
ret |= gd5436_aperture2_readb(addr + 1, priv) << 8;
ret |= gd5436_aperture2_readb(addr + 2, priv) << 16;
ret |= gd5436_aperture2_readb(addr + 3, priv) << 24;
return ret;
}
return ret;
}
static void
gd5436_aperture2_writeb(UNUSED(uint32_t addr), uint8_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
uint8_t ap = gd54xx_get_aperture(gd54xx, addr);
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED))
gd54xx_mem_sys_src_write(gd54xx, val, ap);
}
static void
gd5436_aperture2_writew(uint32_t addr, uint16_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
gd5436_aperture2_writeb(addr, val, gd54xx);
gd5436_aperture2_writeb(addr + 1, val >> 8, gd54xx);
}
}
static void
gd5436_aperture2_writel(uint32_t addr, uint32_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
gd5436_aperture2_writeb(addr, val, gd54xx);
gd5436_aperture2_writeb(addr + 1, val >> 8, gd54xx);
gd5436_aperture2_writeb(addr + 2, val >> 16, gd54xx);
gd5436_aperture2_writeb(addr + 3, val >> 24, gd54xx);
}
}
static void
gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint8_t ap = gd54xx_get_aperture(gd54xx, addr);
if (!(svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA)) {
svga_write_linear(addr, val, svga);
return;
}
addr &= 0x003fffff; /* 4 MB mask */
if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) {
if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) &&
(svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) {
gd543x_mmio_write(addr & 0x000000ff, val, gd54xx);
return;
}
}
/*
Do mem sys src writes here if the blitter is neither paused,
nor is there a second aperture.
*/
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
!gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
gd54xx_mem_sys_src_write(gd54xx, val, ap);
return;
}
switch (ap) {
default:
case 0:
break;
case 1:
/* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */
addr ^= 0x00000001;
break;
case 2:
/* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */
addr ^= 0x00000003;
break;
case 3:
return;
}
svga_write_linear(addr, val, svga);
}
static void
gd54xx_writew_linear(uint32_t addr, uint16_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint32_t old_addr = addr;
uint8_t ap = gd54xx_get_aperture(gd54xx, addr);
if (!(svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA)) {
svga_writew_linear(addr, val, svga);
return;
}
addr &= 0x003fffff; /* 4 MB mask */
if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) {
if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) &&
(svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) {
gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx);
return;
}
}
/*
Do mem sys src writes here if the blitter is neither paused,
nor is there a second aperture.
*/
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
!gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
gd54xx_writeb_linear(old_addr, val, gd54xx);
gd54xx_writeb_linear(old_addr + 1, val >> 8, gd54xx);
return;
}
if (svga->writemode < 4) {
switch (ap) {
default:
case 0:
svga_writew_linear(addr, val, svga);
return;
case 2:
addr ^= 0x00000002;
case 1:
svga_writeb_linear(addr + 1, val & 0xff, svga);
svga_writeb_linear(addr, val >> 8, svga);
if (svga->fast)
cycles -= svga->monitor->mon_video_timing_write_w;
return;
case 3:
return;
}
} else {
switch (ap) {
default:
case 0:
svga_write_linear(addr, val & 0xff, svga);
svga_write_linear(addr + 1, val >> 8, svga);
return;
case 2:
addr ^= 0x00000002;
fallthrough;
case 1:
svga_write_linear(addr + 1, val & 0xff, svga);
svga_write_linear(addr, val >> 8, svga);
return;
case 3:
return;
}
}
}
static void
gd54xx_writel_linear(uint32_t addr, uint32_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint32_t old_addr = addr;
uint8_t ap = gd54xx_get_aperture(gd54xx, addr);
if (!(svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA)) {
svga_writel_linear(addr, val, svga);
return;
}
addr &= 0x003fffff; /* 4 MB mask */
if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) {
if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) &&
(svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) {
gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx);
return;
}
}
/*
Do mem sys src writes here if the blitter is neither paused,
nor is there a second aperture.
*/
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
!gd54xx_aperture2_enabled(gd54xx) && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
gd54xx_writeb_linear(old_addr, val, gd54xx);
gd54xx_writeb_linear(old_addr + 1, val >> 8, gd54xx);
gd54xx_writeb_linear(old_addr + 2, val >> 16, gd54xx);
gd54xx_writeb_linear(old_addr + 3, val >> 24, gd54xx);
return;
}
if (svga->writemode < 4) {
switch (ap) {
default:
case 0:
svga_writel_linear(addr, val, svga);
return;
case 1:
svga_writeb_linear(addr + 1, val & 0xff, svga);
svga_writeb_linear(addr, val >> 8, svga);
svga_writeb_linear(addr + 3, val >> 16, svga);
svga_writeb_linear(addr + 2, val >> 24, svga);
return;
case 2:
svga_writeb_linear(addr + 3, val & 0xff, svga);
svga_writeb_linear(addr + 2, val >> 8, svga);
svga_writeb_linear(addr + 1, val >> 16, svga);
svga_writeb_linear(addr, val >> 24, svga);
return;
case 3:
return;
}
} else {
switch (ap) {
default:
case 0:
svga_write_linear(addr, val & 0xff, svga);
svga_write_linear(addr + 1, val >> 8, svga);
svga_write_linear(addr + 2, val >> 16, svga);
svga_write_linear(addr + 3, val >> 24, svga);
return;
case 1:
svga_write_linear(addr + 1, val & 0xff, svga);
svga_write_linear(addr, val >> 8, svga);
svga_write_linear(addr + 3, val >> 16, svga);
svga_write_linear(addr + 2, val >> 24, svga);
return;
case 2:
svga_write_linear(addr + 3, val & 0xff, svga);
svga_write_linear(addr + 2, val >> 8, svga);
svga_write_linear(addr + 1, val >> 16, svga);
svga_write_linear(addr, val >> 24, svga);
return;
case 3:
return;
}
}
}
static uint8_t
gd54xx_read(uint32_t addr, void *priv)
{
svga_t *svga = (svga_t *) priv;
gd54xx_t *gd54xx = (gd54xx_t *) svga->local;
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED))
return gd54xx_mem_sys_dest_read(gd54xx, 0);
(void) xga_read_test(addr, svga);
addr &= svga->banked_mask;
addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1];
return svga_read_linear(addr, svga);
}
static uint16_t
gd54xx_readw(uint32_t addr, void *priv)
{
svga_t *svga = (svga_t *) priv;
gd54xx_t *gd54xx = (gd54xx_t *) svga->local;
uint16_t ret;
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
ret = gd54xx_read(addr, svga);
ret |= gd54xx_read(addr + 1, svga) << 8;
return ret;
}
(void) xga_read_test(addr, svga);
(void) xga_read_test(addr + 1, svga);
addr &= svga->banked_mask;
addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1];
return svga_readw_linear(addr, svga);
}
static uint32_t
gd54xx_readl(uint32_t addr, void *priv)
{
svga_t *svga = (svga_t *) priv;
gd54xx_t *gd54xx = (gd54xx_t *) svga->local;
uint32_t ret;
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
ret = gd54xx_read(addr, svga);
ret |= gd54xx_read(addr + 1, svga) << 8;
ret |= gd54xx_read(addr + 2, svga) << 16;
ret |= gd54xx_read(addr + 3, svga) << 24;
return ret;
}
(void) xga_read_test(addr, svga);
(void) xga_read_test(addr + 1, svga);
(void) xga_read_test(addr + 2, svga);
(void) xga_read_test(addr + 3, svga);
addr &= svga->banked_mask;
addr = (addr & 0x7fff) + svga->extra_banks[(addr >> 15) & 1];
return svga_readl_linear(addr, svga);
}
static int
gd543x_do_mmio(svga_t *svga, uint32_t addr)
{
if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)
return 1;
else
return ((addr & ~0xff) == 0xb8000);
}
static void
gd543x_mmio_write(uint32_t addr, uint8_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint8_t old;
if (gd543x_do_mmio(svga, addr)) {
switch (addr & 0xff) {
case 0x00:
if (gd54xx_is_5434(svga))
gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffffff00) | val;
else
gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00) | val;
break;
case 0x01:
if (gd54xx_is_5434(svga))
gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffff00ff) | (val << 8);
else
gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ff) | (val << 8);
break;
case 0x02:
if (gd54xx_is_5434(svga))
gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00ffff) | (val << 16);
break;
case 0x03:
if (gd54xx_is_5434(svga))
gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ffffff) | (val << 24);
break;
case 0x04:
if (gd54xx_is_5434(svga))
gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffffff00) | val;
else
gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00) | val;
break;
case 0x05:
if (gd54xx_is_5434(svga))
gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffff00ff) | (val << 8);
else
gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ff) | (val << 8);
break;
case 0x06:
if (gd54xx_is_5434(svga))
gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00ffff) | (val << 16);
break;
case 0x07:
if (gd54xx_is_5434(svga))
gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ffffff) | (val << 24);
break;
case 0x08:
gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val;
break;
case 0x09:
gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8);
if (gd54xx_is_5434(svga))
gd54xx->blt.width &= 0x1fff;
else
gd54xx->blt.width &= 0x07ff;
break;
case 0x0a:
gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val;
break;
case 0x0b:
gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8);
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436)
gd54xx->blt.height &= 0x07ff;
else
gd54xx->blt.height &= 0x03ff;
break;
case 0x0c:
gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val;
break;
case 0x0d:
gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8);
gd54xx->blt.dst_pitch &= 0x1fff;
break;
case 0x0e:
gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val;
break;
case 0x0f:
gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8);
gd54xx->blt.src_pitch &= 0x1fff;
break;
case 0x10:
gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val;
break;
case 0x11:
gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8);
break;
case 0x12:
gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16);
if (gd54xx_is_5434(svga))
gd54xx->blt.dst_addr &= 0x3fffff;
else
gd54xx->blt.dst_addr &= 0x1fffff;
if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) &&
(gd54xx->blt.status & CIRRUS_BLT_AUTOSTART) &&
!(gd54xx->blt.status & CIRRUS_BLT_BUSY)) {
gd54xx->blt.status |= CIRRUS_BLT_BUSY;
gd54xx_start_blit(0, 0xffffffff, gd54xx, svga);
}
break;
case 0x14:
gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val;
break;
case 0x15:
gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8);
break;
case 0x16:
gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16);
if (gd54xx_is_5434(svga))
gd54xx->blt.src_addr &= 0x3fffff;
else
gd54xx->blt.src_addr &= 0x1fffff;
break;
case 0x17:
gd54xx->blt.mask = val;
break;
case 0x18:
gd54xx->blt.mode = val;
gd543x_recalc_mapping(gd54xx);
break;
case 0x1a:
gd54xx->blt.rop = val;
break;
case 0x1b:
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436)
gd54xx->blt.modeext = val;
break;
case 0x1c:
gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val;
break;
case 0x1d:
gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8);
break;
case 0x20:
gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val;
break;
case 0x21:
gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8);
break;
case 0x40:
old = gd54xx->blt.status;
gd54xx->blt.status = val;
gd543x_recalc_mapping(gd54xx);
if (!(old & CIRRUS_BLT_RESET) && (gd54xx->blt.status & CIRRUS_BLT_RESET))
gd54xx_reset_blit(gd54xx);
else if (!(old & CIRRUS_BLT_START) && (gd54xx->blt.status & CIRRUS_BLT_START)) {
gd54xx->blt.status |= CIRRUS_BLT_BUSY;
gd54xx_start_blit(0, 0xffffffff, gd54xx, svga);
}
break;
default:
break;
}
} else if (gd54xx->mmio_vram_overlap)
gd54xx_write(addr, val, svga);
}
static void
gd543x_mmio_writeb(uint32_t addr, uint8_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
if (!gd543x_do_mmio(svga, addr) && !gd54xx->blt.ms_is_dest && gd54xx->countminusone &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
gd54xx_mem_sys_src_write(gd54xx, val, 0);
return;
}
gd543x_mmio_write(addr, val, priv);
}
static void
gd543x_mmio_writew(uint32_t addr, uint16_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
if (gd543x_do_mmio(svga, addr)) {
gd543x_mmio_write(addr, val & 0xff, gd54xx);
gd543x_mmio_write(addr + 1, val >> 8, gd54xx);
} else if (gd54xx->mmio_vram_overlap) {
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
gd543x_mmio_write(addr, val & 0xff, gd54xx);
gd543x_mmio_write(addr + 1, val >> 8, gd54xx);
} else {
gd54xx_write(addr, val, svga);
gd54xx_write(addr + 1, val >> 8, svga);
}
}
}
static void
gd543x_mmio_writel(uint32_t addr, uint32_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
if (gd543x_do_mmio(svga, addr)) {
gd543x_mmio_write(addr, val & 0xff, gd54xx);
gd543x_mmio_write(addr + 1, val >> 8, gd54xx);
gd543x_mmio_write(addr + 2, val >> 16, gd54xx);
gd543x_mmio_write(addr + 3, val >> 24, gd54xx);
} else if (gd54xx->mmio_vram_overlap) {
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
gd543x_mmio_write(addr, val & 0xff, gd54xx);
gd543x_mmio_write(addr + 1, val >> 8, gd54xx);
gd543x_mmio_write(addr + 2, val >> 16, gd54xx);
gd543x_mmio_write(addr + 3, val >> 24, gd54xx);
} else {
gd54xx_write(addr, val, svga);
gd54xx_write(addr + 1, val >> 8, svga);
gd54xx_write(addr + 2, val >> 16, svga);
gd54xx_write(addr + 3, val >> 24, svga);
}
}
}
static uint8_t
gd543x_mmio_read(uint32_t addr, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint8_t ret = 0xff;
if (gd543x_do_mmio(svga, addr)) {
switch (addr & 0xff) {
case 0x00:
ret = gd54xx->blt.bg_col & 0xff;
break;
case 0x01:
ret = (gd54xx->blt.bg_col >> 8) & 0xff;
break;
case 0x02:
if (gd54xx_is_5434(svga))
ret = (gd54xx->blt.bg_col >> 16) & 0xff;
break;
case 0x03:
if (gd54xx_is_5434(svga))
ret = (gd54xx->blt.bg_col >> 24) & 0xff;
break;
case 0x04:
ret = gd54xx->blt.fg_col & 0xff;
break;
case 0x05:
ret = (gd54xx->blt.fg_col >> 8) & 0xff;
break;
case 0x06:
if (gd54xx_is_5434(svga))
ret = (gd54xx->blt.fg_col >> 16) & 0xff;
break;
case 0x07:
if (gd54xx_is_5434(svga))
ret = (gd54xx->blt.fg_col >> 24) & 0xff;
break;
case 0x08:
ret = gd54xx->blt.width & 0xff;
break;
case 0x09:
if (gd54xx_is_5434(svga))
ret = (gd54xx->blt.width >> 8) & 0x1f;
else
ret = (gd54xx->blt.width >> 8) & 0x07;
break;
case 0x0a:
ret = gd54xx->blt.height & 0xff;
break;
case 0x0b:
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436)
ret = (gd54xx->blt.height >> 8) & 0x07;
else
ret = (gd54xx->blt.height >> 8) & 0x03;
break;
case 0x0c:
ret = gd54xx->blt.dst_pitch & 0xff;
break;
case 0x0d:
ret = (gd54xx->blt.dst_pitch >> 8) & 0x1f;
break;
case 0x0e:
ret = gd54xx->blt.src_pitch & 0xff;
break;
case 0x0f:
ret = (gd54xx->blt.src_pitch >> 8) & 0x1f;
break;
case 0x10:
ret = gd54xx->blt.dst_addr & 0xff;
break;
case 0x11:
ret = (gd54xx->blt.dst_addr >> 8) & 0xff;
break;
case 0x12:
if (gd54xx_is_5434(svga))
ret = (gd54xx->blt.dst_addr >> 16) & 0x3f;
else
ret = (gd54xx->blt.dst_addr >> 16) & 0x1f;
break;
case 0x14:
ret = gd54xx->blt.src_addr & 0xff;
break;
case 0x15:
ret = (gd54xx->blt.src_addr >> 8) & 0xff;
break;
case 0x16:
if (gd54xx_is_5434(svga))
ret = (gd54xx->blt.src_addr >> 16) & 0x3f;
else
ret = (gd54xx->blt.src_addr >> 16) & 0x1f;
break;
case 0x17:
ret = gd54xx->blt.mask;
break;
case 0x18:
ret = gd54xx->blt.mode;
break;
case 0x1a:
ret = gd54xx->blt.rop;
break;
case 0x1b:
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436)
ret = gd54xx->blt.modeext;
break;
case 0x1c:
ret = gd54xx->blt.trans_col & 0xff;
break;
case 0x1d:
ret = (gd54xx->blt.trans_col >> 8) & 0xff;
break;
case 0x20:
ret = gd54xx->blt.trans_mask & 0xff;
break;
case 0x21:
ret = (gd54xx->blt.trans_mask >> 8) & 0xff;
break;
case 0x40:
ret = gd54xx->blt.status;
break;
default:
break;
}
} else if (gd54xx->mmio_vram_overlap)
ret = gd54xx_read(addr, svga);
else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED))
ret = gd54xx_mem_sys_dest_read(gd54xx, 0);
return ret;
}
static uint16_t
gd543x_mmio_readw(uint32_t addr, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint16_t ret = 0xffff;
if (gd543x_do_mmio(svga, addr))
ret = gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr + 1, gd54xx) << 8);
else if (gd54xx->mmio_vram_overlap)
ret = gd54xx_read(addr, svga) | (gd54xx_read(addr + 1, svga) << 8);
else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
ret = gd543x_mmio_read(addr, priv);
ret |= gd543x_mmio_read(addr + 1, priv) << 8;
return ret;
}
return ret;
}
static uint32_t
gd543x_mmio_readl(uint32_t addr, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
uint32_t ret = 0xffffffff;
if (gd543x_do_mmio(svga, addr))
ret = gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr + 1, gd54xx) << 8) |
(gd543x_mmio_read(addr + 2, gd54xx) << 16) |
(gd543x_mmio_read(addr + 3, gd54xx) << 24);
else if (gd54xx->mmio_vram_overlap)
ret = gd54xx_read(addr, svga) | (gd54xx_read(addr + 1, svga) << 8) |
(gd54xx_read(addr + 2, gd54xx) << 16) | (gd54xx_read(addr + 3, gd54xx) << 24);
else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest &&
!(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
ret = gd543x_mmio_read(addr, priv);
ret |= gd543x_mmio_read(addr + 1, priv) << 8;
ret |= gd543x_mmio_read(addr + 2, priv) << 16;
ret |= gd543x_mmio_read(addr + 3, priv) << 24;
return ret;
}
return ret;
}
static void
gd5480_vgablt_write(uint32_t addr, uint8_t val, void *priv)
{
addr &= 0x00000fff;
if ((addr >= 0x00000100) && (addr < 0x00000200))
gd543x_mmio_writeb((addr & 0x000000ff) | 0x000b8000, val, priv);
else if (addr < 0x00000100)
gd54xx_out(0x03c0 + addr, val, priv);
}
static void
gd5480_vgablt_writew(uint32_t addr, uint16_t val, void *priv)
{
addr &= 0x00000fff;
if ((addr >= 0x00000100) && (addr < 0x00000200))
gd543x_mmio_writew((addr & 0x000000ff) | 0x000b8000, val, priv);
else if (addr < 0x00000100) {
gd5480_vgablt_write(addr, val & 0xff, priv);
gd5480_vgablt_write(addr + 1, val >> 8, priv);
}
}
static void
gd5480_vgablt_writel(uint32_t addr, uint32_t val, void *priv)
{
addr &= 0x00000fff;
if ((addr >= 0x00000100) && (addr < 0x00000200))
gd543x_mmio_writel((addr & 0x000000ff) | 0x000b8000, val, priv);
else if (addr < 0x00000100) {
gd5480_vgablt_writew(addr, val & 0xffff, priv);
gd5480_vgablt_writew(addr + 2, val >> 16, priv);
}
}
static uint8_t
gd5480_vgablt_read(uint32_t addr, void *priv)
{
uint8_t ret = 0xff;
addr &= 0x00000fff;
if ((addr >= 0x00000100) && (addr < 0x00000200))
ret = gd543x_mmio_read((addr & 0x000000ff) | 0x000b8000, priv);
else if (addr < 0x00000100)
ret = gd54xx_in(0x03c0 + addr, priv);
return ret;
}
static uint16_t
gd5480_vgablt_readw(uint32_t addr, void *priv)
{
uint16_t ret = 0xffff;
addr &= 0x00000fff;
if ((addr >= 0x00000100) && (addr < 0x00000200))
ret = gd543x_mmio_readw((addr & 0x000000ff) | 0x000b8000, priv);
else if (addr < 0x00000100) {
ret = gd5480_vgablt_read(addr, priv);
ret |= (gd5480_vgablt_read(addr + 1, priv) << 8);
}
return ret;
}
static uint32_t
gd5480_vgablt_readl(uint32_t addr, void *priv)
{
uint32_t ret = 0xffffffff;
addr &= 0x00000fff;
if ((addr >= 0x00000100) && (addr < 0x00000200))
ret = gd543x_mmio_readl((addr & 0x000000ff) | 0x000b8000, priv);
else if (addr < 0x00000100) {
ret = gd5480_vgablt_readw(addr, priv);
ret |= (gd5480_vgablt_readw(addr + 2, priv) << 16);
}
return ret;
}
static uint8_t
gd54xx_color_expand(gd54xx_t *gd54xx, int mask, int shift)
{
uint8_t ret;
if (gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP)
ret = gd54xx->blt.fg_col >> (shift << 3);
else
ret = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3));
return ret;
}
static int
gd54xx_get_pixel_width(gd54xx_t *gd54xx)
{
int ret = 1;
switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
case CIRRUS_BLTMODE_PIXELWIDTH8:
ret = 1;
break;
case CIRRUS_BLTMODE_PIXELWIDTH16:
ret = 2;
break;
case CIRRUS_BLTMODE_PIXELWIDTH24:
ret = 3;
break;
case CIRRUS_BLTMODE_PIXELWIDTH32:
ret = 4;
break;
default:
break;
}
return ret;
}
static void
gd54xx_blit(gd54xx_t *gd54xx, uint8_t mask, uint8_t *dst, uint8_t target, int skip)
{
int is_transp;
int is_bgonly;
/*
skip indicates whether or not it is a pixel to be skipped (used for left skip);
mask indicates transparency or not (only when transparent comparison is enabled):
color expand: direct pattern bit; 1 = write, 0 = do not write
(the other way around in inverse mode);
normal 8-bpp or 16-bpp: does not match transparent color = write,
matches transparent color = do not write
*/
/* Make sure to always ignore transparency and skip in case of mem sys dest. */
is_transp = (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSDEST) ?
0 : (gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP);
is_bgonly = (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSDEST) ?
0 : (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_BACKGROUNDONLY);
skip = (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSDEST) ? 0 : skip;
if (is_transp) {
if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) &&
(gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV))
mask = !mask;
/* If mask is 1 and it is not a pixel to be skipped, write it. */
if (mask && !skip)
*dst = target;
} else if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && is_bgonly) {
/* If mask is 1 or it is not a pixel to be skipped, write it.
(Skip only background pixels.) */
if (mask || !skip)
*dst = target;
} else {
/* If if it is not a pixel to be skipped, write it. */
if (!skip)
*dst = target;
}
}
static int
gd54xx_transparent_comp(gd54xx_t *gd54xx, uint32_t xx, uint8_t src)
{
svga_t *svga = &gd54xx->svga;
int ret = 1;
if ((gd54xx->blt.pixel_width <= 2) && gd54xx_has_transp(svga, 0)) {
ret = src ^ ((uint8_t *) &(gd54xx->blt.trans_col))[xx];
if (gd54xx_has_transp(svga, 1))
ret &= ~(((uint8_t *) &(gd54xx->blt.trans_mask))[xx]);
ret = !ret;
}
return ret;
}
static void
gd54xx_pattern_copy(gd54xx_t *gd54xx)
{
uint8_t target;
uint8_t src;
uint8_t *dst;
int pattern_y;
int pattern_pitch;
uint32_t bitmask = 0;
uint32_t pixel;
uint32_t srca;
uint32_t srca2;
uint32_t dsta;
svga_t *svga = &gd54xx->svga;
pattern_pitch = gd54xx->blt.pixel_width << 3;
if (gd54xx->blt.pixel_width == 3)
pattern_pitch = 32;
if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)
pattern_pitch = 1;
dsta = gd54xx->blt.dst_addr & gd54xx->vram_mask;
/* The vertical offset is in the three low-order bits of the Source Address register. */
pattern_y = gd54xx->blt.src_addr & 0x07;
/* Mode Pattern bytes Pattern line bytes
---------------------------------------------------
Color Expansion 8 1
8-bpp 64 8
16-bpp 128 16
24-bpp 256 32
32-bpp 256 32
*/
/* The boundary has to be equal to the size of the pattern. */
srca = (gd54xx->blt.src_addr & ~0x07) & gd54xx->vram_mask;
for (uint16_t y = 0; y <= gd54xx->blt.height; y++) {
/* Go to the correct pattern line. */
srca2 = srca + (pattern_y * pattern_pitch);
pixel = 0;
for (uint16_t x = 0; x <= gd54xx->blt.width; x += gd54xx->blt.pixel_width) {
if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) {
if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL)
bitmask = 1;
else
bitmask = svga->vram[srca2 & gd54xx->vram_mask] & (0x80 >> pixel);
}
for (int xx = 0; xx < gd54xx->blt.pixel_width; xx++) {
if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)
src = gd54xx_color_expand(gd54xx, bitmask, xx);
else {
src = svga->vram[(srca2 + (x % (gd54xx->blt.pixel_width << 3)) + xx) & gd54xx->vram_mask];
bitmask = gd54xx_transparent_comp(gd54xx, xx, src);
}
dst = &(svga->vram[(dsta + x + xx) & gd54xx->vram_mask]);
target = *dst;
gd54xx_rop(gd54xx, &target, &target, &src);
if (gd54xx->blt.pixel_width == 3)
gd54xx_blit(gd54xx, bitmask, dst, target, ((x + xx) < gd54xx->blt.pattern_x));
else
gd54xx_blit(gd54xx, bitmask, dst, target, (x < gd54xx->blt.pattern_x));
}
pixel = (pixel + 1) & 7;
svga->changedvram[((dsta + x) & gd54xx->vram_mask) >> 12] = changeframecount;
}
pattern_y = (pattern_y + 1) & 7;
dsta += gd54xx->blt.dst_pitch;
}
}
static void
gd54xx_reset_blit(gd54xx_t *gd54xx)
{
gd54xx->countminusone = 0;
gd54xx->blt.status &= ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED);
}
/* Each blit is either 1 byte -> 1 byte (non-color expand blit)
or 1 byte -> 8/16/24/32 bytes (color expand blit). */
static void
gd54xx_mem_sys_src(gd54xx_t *gd54xx, uint32_t cpu_dat, uint32_t count)
{
uint8_t *dst;
uint8_t exp;
uint8_t target;
int mask_shift;
uint32_t byte_pos;
uint32_t bitmask = 0;
svga_t *svga = &gd54xx->svga;
gd54xx->blt.ms_is_dest = 0;
if (gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSDEST | CIRRUS_BLTMODE_PATTERNCOPY))
gd54xx_reset_blit(gd54xx);
else if (count == 0xffffffff) {
gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr;
gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr;
gd54xx->blt.x_count = gd54xx->blt.xx_count = 0;
gd54xx->blt.y_count = 0;
gd54xx->countminusone = 1;
gd54xx->blt.sys_src32 = 0x00000000;
gd54xx->blt.sys_cnt = 0;
} else if (gd54xx->countminusone) {
if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) ||
(gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) {
if (!gd54xx->blt.xx_count && !gd54xx->blt.x_count)
byte_pos = (((gd54xx->blt.mask >> 5) & 3) << 3);
else
byte_pos = 0;
mask_shift = 31 - byte_pos;
if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND))
cpu_dat >>= byte_pos;
} else
mask_shift = 7;
while (mask_shift > -1) {
if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) {
bitmask = (cpu_dat >> mask_shift) & 0x01;
exp = gd54xx_color_expand(gd54xx, bitmask, gd54xx->blt.xx_count);
} else {
exp = cpu_dat & 0xff;
bitmask = gd54xx_transparent_comp(gd54xx, gd54xx->blt.xx_count, exp);
}
dst = &(svga->vram[gd54xx->blt.dst_addr_backup & gd54xx->vram_mask]);
target = *dst;
gd54xx_rop(gd54xx, &target, &target, &exp);
if ((gd54xx->blt.pixel_width == 3) && (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND))
gd54xx_blit(gd54xx, bitmask, dst, target,
((gd54xx->blt.x_count + gd54xx->blt.xx_count) < gd54xx->blt.pattern_x));
else
gd54xx_blit(gd54xx, bitmask, dst, target, (gd54xx->blt.x_count < gd54xx->blt.pattern_x));
gd54xx->blt.dst_addr_backup += gd54xx->blt.dir;
if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)
gd54xx->blt.xx_count = (gd54xx->blt.xx_count + 1) % gd54xx->blt.pixel_width;
svga->changedvram[(gd54xx->blt.dst_addr_backup & gd54xx->vram_mask) >> 12] = changeframecount;
if (!gd54xx->blt.xx_count) {
/* 1 mask bit = 1 blitted pixel */
if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)
mask_shift--;
else {
cpu_dat >>= 8;
mask_shift -= 8;
}
if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)
gd54xx->blt.x_count = (gd54xx->blt.x_count + gd54xx->blt.pixel_width) % (gd54xx->blt.width + 1);
else
gd54xx->blt.x_count = (gd54xx->blt.x_count + 1) % (gd54xx->blt.width + 1);
if (!gd54xx->blt.x_count) {
gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) % (gd54xx->blt.height + 1);
if (gd54xx->blt.y_count)
gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr +
(gd54xx->blt.dst_pitch * gd54xx->blt.y_count *
gd54xx->blt.dir);
else
/* If we're here, the blit is over, reset. */
gd54xx_reset_blit(gd54xx);
/* Stop blitting and request new data if end of line reached. */
break;
}
}
}
}
}
static void
gd54xx_normal_blit(uint32_t count, gd54xx_t *gd54xx, svga_t *svga)
{
uint8_t src = 0;
uint8_t dst;
uint16_t width = gd54xx->blt.width;
int x_max = 0;
int shift = 0;
int mask = 0;
uint32_t src_addr = gd54xx->blt.src_addr;
uint32_t dst_addr = gd54xx->blt.dst_addr;
x_max = gd54xx->blt.pixel_width << 3;
gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr;
gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr;
gd54xx->blt.height_internal = gd54xx->blt.height;
gd54xx->blt.x_count = 0;
gd54xx->blt.y_count = 0;
while (count) {
src = 0;
mask = 0;
if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) {
mask = svga->vram[src_addr & gd54xx->vram_mask] & (0x80 >> (gd54xx->blt.x_count / gd54xx->blt.pixel_width));
shift = (gd54xx->blt.x_count % gd54xx->blt.pixel_width);
src = gd54xx_color_expand(gd54xx, mask, shift);
} else {
src = svga->vram[src_addr & gd54xx->vram_mask];
src_addr += gd54xx->blt.dir;
mask = 1;
}
count--;
dst = svga->vram[dst_addr & gd54xx->vram_mask];
svga->changedvram[(dst_addr & gd54xx->vram_mask) >> 12] = changeframecount;
gd54xx_rop(gd54xx, &dst, &dst, (const uint8_t *) &src);
if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV))
mask = !mask;
/* This handles 8bpp and 16bpp non-color-expanding transparent comparisons. */
if ((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) &&
!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) &&
((gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) <= CIRRUS_BLTMODE_PIXELWIDTH16) &&
(src != ((gd54xx->blt.trans_mask >> (shift << 3)) & 0xff)))
mask = 0;
if (((gd54xx->blt.width - width) >= gd54xx->blt.pattern_x) &&
!((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask))
svga->vram[dst_addr & gd54xx->vram_mask] = dst;
dst_addr += gd54xx->blt.dir;
gd54xx->blt.x_count++;
if (gd54xx->blt.x_count == x_max) {
gd54xx->blt.x_count = 0;
if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)
src_addr++;
}
width--;
if (width == 0xffff) {
width = gd54xx->blt.width;
dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup +
(gd54xx->blt.dst_pitch * gd54xx->blt.dir);
gd54xx->blt.y_count = (gd54xx->blt.y_count + gd54xx->blt.dir) & 7;
if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) {
if (gd54xx->blt.x_count != 0)
src_addr++;
} else
src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup +
(gd54xx->blt.src_pitch * gd54xx->blt.dir);
dst_addr &= gd54xx->vram_mask;
gd54xx->blt.dst_addr_backup &= gd54xx->vram_mask;
src_addr &= gd54xx->vram_mask;
gd54xx->blt.src_addr_backup &= gd54xx->vram_mask;
gd54xx->blt.x_count = 0;
gd54xx->blt.height_internal--;
if (gd54xx->blt.height_internal == 0xffff) {
break;
}
}
}
/* Count exhausted, stuff still left to blit. */
gd54xx_reset_blit(gd54xx);
}
static void
gd54xx_mem_sys_dest(uint32_t count, gd54xx_t *gd54xx, svga_t *svga)
{
gd54xx->blt.ms_is_dest = 1;
if (gd54xx->blt.mode & CIRRUS_BLTMODE_PATTERNCOPY) {
fatal("mem sys dest pattern copy not allowed (see 1994 manual)\n");
gd54xx_reset_blit(gd54xx);
} else if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) {
fatal("mem sys dest color expand not allowed (see 1994 manual)\n");
gd54xx_reset_blit(gd54xx);
} else {
if (count == 0xffffffff) {
gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr;
gd54xx->blt.msd_buf_cnt = 0;
gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr;
gd54xx->blt.x_count = gd54xx->blt.xx_count = 0;
gd54xx->blt.y_count = 0;
gd54xx->countminusone = 1;
count = 32;
}
gd54xx->blt.msd_buf_pos = 0;
while (gd54xx->blt.msd_buf_pos < 32) {
gd54xx->blt.msd_buf[gd54xx->blt.msd_buf_pos & 0x1f] = svga->vram[gd54xx->blt.src_addr_backup &
gd54xx->vram_mask];
gd54xx->blt.src_addr_backup += gd54xx->blt.dir;
gd54xx->blt.msd_buf_pos++;
gd54xx->blt.x_count = (gd54xx->blt.x_count + 1) % (gd54xx->blt.width + 1);
if (!gd54xx->blt.x_count) {
gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) % (gd54xx->blt.height + 1);
if (gd54xx->blt.y_count)
gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr +
(gd54xx->blt.src_pitch * gd54xx->blt.y_count * gd54xx->blt.dir);
else
gd54xx->countminusone = 2; /* Signal end of blit. */
/* End of line reached, stop and notify regardless of how much we already transferred. */
break;
}
}
/*
End of while.
If the byte count we have blitted are not divisible by 4,
round them up.
*/
if (gd54xx->blt.msd_buf_pos & 3)
gd54xx->blt.msd_buf_cnt = (gd54xx->blt.msd_buf_pos & ~3) + 4;
else
gd54xx->blt.msd_buf_cnt = gd54xx->blt.msd_buf_pos;
gd54xx->blt.msd_buf_pos = 0;
return;
}
}
static void
gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *svga)
{
if ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) &&
!(gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) &&
!(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP))
gd54xx->blt.dir = -1;
else
gd54xx->blt.dir = 1;
gd54xx->blt.pixel_width = gd54xx_get_pixel_width(gd54xx);
if (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) {
if (gd54xx->blt.pixel_width == 3)
gd54xx->blt.pattern_x = gd54xx->blt.mask & 0x1f; /* (Mask & 0x1f) bytes. */
else
/* (Mask & 0x07) pixels. */
gd54xx->blt.pattern_x = (gd54xx->blt.mask & 0x07) * gd54xx->blt.pixel_width;
} else
gd54xx->blt.pattern_x = 0; /* No skip in normal blit mode. */
if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC)
gd54xx_mem_sys_src(gd54xx, cpu_dat, count);
else if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSDEST)
gd54xx_mem_sys_dest(count, gd54xx, svga);
else if (gd54xx->blt.mode & CIRRUS_BLTMODE_PATTERNCOPY) {
gd54xx_pattern_copy(gd54xx);
gd54xx_reset_blit(gd54xx);
} else
gd54xx_normal_blit(count, gd54xx, svga);
}
static uint8_t
cl_pci_read(UNUSED(int func), int addr, void *priv)
{
const gd54xx_t *gd54xx = (gd54xx_t *) priv;
const svga_t *svga = &gd54xx->svga;
uint8_t ret = 0x00;
if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios))
ret = 0x00;
else switch (addr) {
case 0x00:
ret = 0x13; /*Cirrus Logic*/
break;
case 0x01:
ret = 0x10;
break;
case 0x02:
ret = svga->crtc[0x27];
break;
case 0x03:
ret = 0x00;
break;
case PCI_REG_COMMAND:
/* Respond to IO and memory accesses */
ret = gd54xx->pci_regs[PCI_REG_COMMAND];
break;
case 0x07:
ret = 0x02; /*Fast DEVSEL timing*/
break;
case 0x08:
ret = gd54xx->rev; /*Revision ID*/
break;
case 0x09:
ret = 0x00; /*Programming interface*/
break;
case 0x0a:
ret = 0x00; /*Supports VGA interface*/
break;
case 0x0b:
ret = 0x03;
break;
case 0x10:
ret = 0x08; /*Linear frame buffer address*/
break;
case 0x11:
ret = 0x00;
break;
case 0x12:
ret = 0x00;
break;
case 0x13:
ret = gd54xx->lfb_base >> 24;
if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480)
ret &= 0xfe;
break;
case 0x14:
ret = 0x00; /*PCI VGA/BitBLT Register Base Address*/
break;
case 0x15:
ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? ((gd54xx->vgablt_base >> 8) & 0xf0) : 0x00;
break;
case 0x16:
ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? ((gd54xx->vgablt_base >> 16) & 0xff) : 0x00;
break;
case 0x17:
ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? ((gd54xx->vgablt_base >> 24) & 0xff) : 0x00;
break;
case 0x2c:
ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? gd54xx->bios_rom.rom[0x7ffc] : 0x00;
break;
case 0x2d:
ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? gd54xx->bios_rom.rom[0x7ffd] : 0x00;
break;
case 0x2e:
ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? gd54xx->bios_rom.rom[0x7ffe] : 0x00;
break;
case 0x30:
ret = (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/
break;
case 0x31:
ret = 0x00;
break;
case 0x32:
ret = gd54xx->pci_regs[0x32];
break;
case 0x33:
ret = gd54xx->pci_regs[0x33];
break;
case 0x3c:
ret = gd54xx->int_line;
break;
case 0x3d:
ret = PCI_INTA;
break;
default:
break;
}
return ret;
}
static void
cl_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
const svga_t *svga = &gd54xx->svga;
uint32_t byte;
if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios))
return;
switch (addr) {
case PCI_REG_COMMAND:
gd54xx->pci_regs[PCI_REG_COMMAND] = val & 0x23;
mem_mapping_disable(&gd54xx->vgablt_mapping);
io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx);
if (val & PCI_COMMAND_IO)
io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx);
if ((val & PCI_COMMAND_MEM) && (gd54xx->vgablt_base != 0x00000000) && (gd54xx->vgablt_base < 0xfff00000))
mem_mapping_set_addr(&gd54xx->vgablt_mapping, gd54xx->vgablt_base, 0x1000);
if ((gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM) && (gd54xx->pci_regs[0x30] & 0x01)) {
uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24);
mem_mapping_set_addr(&gd54xx->bios_rom.mapping, addr, 0x8000);
} else
mem_mapping_disable(&gd54xx->bios_rom.mapping);
gd543x_recalc_mapping(gd54xx);
break;
case 0x13:
/*
5480, like 5446 rev. B, has a 32 MB aperture, with the second set used for
BitBLT transfers.
*/
if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480)
val &= 0xfe;
gd54xx->lfb_base = val << 24;
gd543x_recalc_mapping(gd54xx);
break;
case 0x15:
case 0x16:
case 0x17:
if (svga->crtc[0x27] != CIRRUS_ID_CLGD5480)
return;
byte = (addr & 3) << 3;
gd54xx->vgablt_base &= ~(0xff << byte);
if (addr == 0x15)
val &= 0xf0;
gd54xx->vgablt_base |= (val << byte);
mem_mapping_disable(&gd54xx->vgablt_mapping);
if ((gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM) &&
(gd54xx->vgablt_base != 0x00000000) && (gd54xx->vgablt_base < 0xfff00000))
mem_mapping_set_addr(&gd54xx->vgablt_mapping, gd54xx->vgablt_base, 0x1000);
break;
case 0x30:
case 0x32:
case 0x33:
gd54xx->pci_regs[addr] = val;
if ((gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM) && (gd54xx->pci_regs[0x30] & 0x01)) {
uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24);
mem_mapping_set_addr(&gd54xx->bios_rom.mapping, addr, 0x8000);
} else
mem_mapping_disable(&gd54xx->bios_rom.mapping);
return;
case 0x3c:
gd54xx->int_line = val;
return;
default:
break;
}
}
static uint8_t
gd5428_mca_read(int port, void *priv)
{
const gd54xx_t *gd54xx = (gd54xx_t *) priv;
return gd54xx->pos_regs[port & 7];
}
static void
gd5428_mca_write(int port, uint8_t val, void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
if (port < 0x102)
return;
gd54xx->pos_regs[port & 7] = val;
mem_mapping_disable(&gd54xx->bios_rom.mapping);
if (gd54xx->pos_regs[2] & 0x01)
mem_mapping_enable(&gd54xx->bios_rom.mapping);
}
static uint8_t
gd5428_mca_feedb(void *priv)
{
const gd54xx_t *gd54xx = (gd54xx_t *) priv;
return gd54xx->pos_regs[2] & 0x01;
}
static void
gd54xx_reset(void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_t *svga = &gd54xx->svga;
memset(svga->crtc, 0x00, sizeof(svga->crtc));
memset(svga->seqregs, 0x00, sizeof(svga->seqregs));
memset(svga->gdcreg, 0x00, sizeof(svga->gdcreg));
svga->crtc[0] = 63;
svga->crtc[6] = 255;
svga->dispontime = 1000ULL << 32;
svga->dispofftime = 1000ULL << 32;
svga->bpp = 8;
io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx);
io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx);
mem_mapping_disable(&gd54xx->vgablt_mapping);
if (gd54xx->has_bios && (gd54xx->pci || gd54xx->mca))
mem_mapping_disable(&gd54xx->bios_rom.mapping);
memset(gd54xx->pci_regs, 0x00, 256);
mem_mapping_disable(&gd54xx->mmio_mapping);
mem_mapping_disable(&gd54xx->linear_mapping);
mem_mapping_disable(&gd54xx->aperture2_mapping);
mem_mapping_disable(&gd54xx->vgablt_mapping);
gd543x_recalc_mapping(gd54xx);
gd54xx_recalc_banking(gd54xx);
svga->hwcursor.yoff = svga->hwcursor.xoff = 0;
if (gd54xx->id >= CIRRUS_ID_CLGD5420) {
gd54xx->vclk_n[0] = 0x4a;
gd54xx->vclk_d[0] = 0x2b;
gd54xx->vclk_n[1] = 0x5b;
gd54xx->vclk_d[1] = 0x2f;
gd54xx->vclk_n[2] = 0x45;
gd54xx->vclk_d[2] = 0x30;
gd54xx->vclk_n[3] = 0x7e;
gd54xx->vclk_d[3] = 0x33;
} else {
gd54xx->vclk_n[0] = 0x66;
gd54xx->vclk_d[0] = 0x3b;
gd54xx->vclk_n[1] = 0x5b;
gd54xx->vclk_d[1] = 0x2f;
gd54xx->vclk_n[2] = 0x45;
gd54xx->vclk_d[2] = 0x2c;
gd54xx->vclk_n[3] = 0x7e;
gd54xx->vclk_d[3] = 0x33;
}
svga->extra_banks[1] = 0x8000;
gd54xx->pci_regs[PCI_REG_COMMAND] = 7;
gd54xx->pci_regs[0x30] = 0x00;
gd54xx->pci_regs[0x32] = 0x0c;
gd54xx->pci_regs[0x33] = 0x00;
svga->crtc[0x27] = gd54xx->id;
svga->seqregs[6] = 0x0f;
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429)
gd54xx->unlocked = 1;
else
gd54xx->unlocked = 0;
}
static void *
gd54xx_init(const device_t *info)
{
gd54xx_t *gd54xx = calloc(1, sizeof(gd54xx_t));
svga_t *svga = &gd54xx->svga;
int id = info->local & 0xff;
int vram;
const char *romfn = NULL;
const char *romfn1 = NULL;
const char *romfn2 = NULL;
gd54xx->pci = !!(info->flags & DEVICE_PCI);
gd54xx->vlb = !!(info->flags & DEVICE_VLB);
gd54xx->mca = !!(info->flags & DEVICE_MCA);
gd54xx->bit32 = gd54xx->pci || gd54xx->vlb;
gd54xx->rev = 0;
gd54xx->has_bios = 1;
gd54xx->id = id;
if (gd54xx->vlb && ((gd54xx->id == CIRRUS_ID_CLGD5430) ||
(gd54xx->id == CIRRUS_ID_CLGD5434) ||
(gd54xx->id == CIRRUS_ID_CLGD5434_4) ||
(gd54xx->id == CIRRUS_ID_CLGD5440)))
gd54xx->vlb_lfb_base = device_get_config_int("lfb_base") << 20;
switch (id) {
case CIRRUS_ID_CLGD5401:
if (info->local & 0x100)
romfn = BIOS_GD5401_ONBOARD_PATH;
else
romfn = BIOS_GD5401_PATH;
break;
case CIRRUS_ID_CLGD5402:
if (info->local & 0x200)
romfn = BIOS_GD5402_ONBOARD_PATH;
else
romfn = BIOS_GD5402_PATH;
break;
case CIRRUS_ID_CLGD5420:
if (info->local & 0x200)
romfn = NULL;
else
romfn = BIOS_GD5420_PATH;
break;
case CIRRUS_ID_CLGD5422:
romfn = BIOS_GD5422_PATH;
break;
case CIRRUS_ID_CLGD5424:
if (info->local & 0x200)
romfn = /*NULL*/ "roms/machines/advantage40xxd/AST101.09A";
else
romfn = BIOS_GD5422_PATH;
break;
case CIRRUS_ID_CLGD5426:
if (info->local & 0x200)
romfn = NULL;
else {
if (info->local & 0x100)
romfn = BIOS_GD5426_DIAMOND_A1_ISA_PATH;
else {
if (gd54xx->vlb)
romfn = BIOS_GD5428_PATH;
else if (gd54xx->mca)
romfn = BIOS_GD5426_MCA_PATH;
else
romfn = BIOS_GD5428_ISA_PATH;
}
}
break;
case CIRRUS_ID_CLGD5428:
if (info->local & 0x200) {
romfn = NULL;
gd54xx->has_bios = 0;
} else if (info->local & 0x100)
if (gd54xx->vlb)
romfn = BIOS_GD5428_DIAMOND_B1_VLB_PATH;
else {
romfn1 = BIOS_GD5428_BOCA_ISA_PATH_1;
romfn2 = BIOS_GD5428_BOCA_ISA_PATH_2;
}
else {
if (gd54xx->vlb)
romfn = BIOS_GD5428_PATH;
else if (gd54xx->mca)
romfn = BIOS_GD5428_MCA_PATH;
else
romfn = BIOS_GD5428_ISA_PATH;
}
break;
case CIRRUS_ID_CLGD5429:
romfn = BIOS_GD5429_PATH;
break;
case CIRRUS_ID_CLGD5432:
case CIRRUS_ID_CLGD5434_4:
if (info->local & 0x200) {
romfn = NULL;
gd54xx->has_bios = 0;
}
break;
case CIRRUS_ID_CLGD5434:
if (info->local & 0x200) {
romfn = NULL;
gd54xx->has_bios = 0;
} else if (gd54xx->vlb) {
romfn = BIOS_GD5430_ORCHID_VLB_PATH;
} else {
if (info->local & 0x100)
romfn = BIOS_GD5434_DIAMOND_A3_ISA_PATH;
else
romfn = BIOS_GD5434_PATH;
}
break;
case CIRRUS_ID_CLGD5436:
if ((info->local & 0x200) &&
(machines[machine].init != machine_at_sb486pv_init)) {
romfn = NULL;
gd54xx->has_bios = 0;
} else
romfn = BIOS_GD5436_PATH;
break;
case CIRRUS_ID_CLGD5430:
if (info->local & 0x400) {
/* CL-GD 5440 */
gd54xx->rev = 0x47;
if (info->local & 0x200) {
romfn = NULL;
gd54xx->has_bios = 0;
} else
romfn = BIOS_GD5440_PATH;
} else {
/* CL-GD 5430 */
if (info->local & 0x200) {
romfn = NULL;
gd54xx->has_bios = 0;
} else if (gd54xx->pci)
romfn = BIOS_GD5430_PATH;
else if ((gd54xx->vlb) && (info->local & 0x100))
romfn = BIOS_GD5430_ORCHID_VLB_PATH;
else
romfn = BIOS_GD5430_DIAMOND_A8_VLB_PATH;
}
break;
case CIRRUS_ID_CLGD5446:
if (info->local & 0x100)
romfn = BIOS_GD5446_STB_PATH;
else
romfn = BIOS_GD5446_PATH;
break;
case CIRRUS_ID_CLGD5480:
romfn = BIOS_GD5480_PATH;
break;
default:
break;
}
if (info->flags & DEVICE_MCA) {
if (id == CIRRUS_ID_CLGD5428)
vram = 1024;
else
vram = device_get_config_int("memory");
gd54xx->vram_size = vram << 10;
} else {
if (id <= CIRRUS_ID_CLGD5428) {
if ((id == CIRRUS_ID_CLGD5426) && (info->local & 0x200))
vram = 1024;
else if (id == CIRRUS_ID_CLGD5401)
vram = 256;
else if (id == CIRRUS_ID_CLGD5402)
vram = 512;
else
vram = device_get_config_int("memory");
gd54xx->vram_size = vram << 10;
} else {
vram = device_get_config_int("memory");
gd54xx->vram_size = vram << 20;
}
}
gd54xx->vram_mask = gd54xx->vram_size - 1;
if (romfn)
rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
else if (romfn1 && romfn2)
rom_init_interleaved(&gd54xx->bios_rom, BIOS_GD5428_BOCA_ISA_PATH_1, BIOS_GD5428_BOCA_ISA_PATH_2, 0xc0000,
0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
if ((info->flags & DEVICE_ISA) || (info->flags & DEVICE_ISA16))
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_isa);
else if (info->flags & DEVICE_PCI)
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_pci);
else
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_vlb);
if (id >= CIRRUS_ID_CLGD5426) {
svga_init(info, &gd54xx->svga, gd54xx, gd54xx->vram_size,
gd54xx_recalctimings, gd54xx_in, gd54xx_out,
gd54xx_hwcursor_draw, gd54xx_overlay_draw);
} else {
svga_init(info, &gd54xx->svga, gd54xx, gd54xx->vram_size,
gd54xx_recalctimings, gd54xx_in, gd54xx_out,
gd54xx_hwcursor_draw, NULL);
}
svga->vblank_start = gd54xx_vblank_start;
svga->ven_write = gd54xx_write_modes45;
if ((vram == 1) || (vram >= 256 && vram <= 1024))
svga->decode_mask = gd54xx->vram_mask;
svga->read = gd54xx_read;
svga->readw = gd54xx_readw;
svga->write = gd54xx_write;
svga->writew = gd54xx_writew;
if (gd54xx->bit32) {
svga->readl = gd54xx_readl;
svga->writel = gd54xx_writel;
mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl,
gd54xx_write, gd54xx_writew, gd54xx_writel);
mem_mapping_add(&gd54xx->mmio_mapping, 0, 0,
gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl,
gd543x_mmio_writeb, gd543x_mmio_writew, gd543x_mmio_writel,
NULL, MEM_MAPPING_EXTERNAL, gd54xx);
mem_mapping_add(&gd54xx->linear_mapping, 0, 0,
gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear,
gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear,
NULL, MEM_MAPPING_EXTERNAL, gd54xx);
mem_mapping_add(&gd54xx->aperture2_mapping, 0, 0,
gd5436_aperture2_readb, gd5436_aperture2_readw, gd5436_aperture2_readl,
gd5436_aperture2_writeb, gd5436_aperture2_writew, gd5436_aperture2_writel,
NULL, MEM_MAPPING_EXTERNAL, gd54xx);
mem_mapping_add(&gd54xx->vgablt_mapping, 0, 0,
gd5480_vgablt_read, gd5480_vgablt_readw, gd5480_vgablt_readl,
gd5480_vgablt_write, gd5480_vgablt_writew, gd5480_vgablt_writel,
NULL, MEM_MAPPING_EXTERNAL, gd54xx);
} else {
svga->readl = NULL;
svga->writel = NULL;
mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, NULL,
gd54xx_write, gd54xx_writew, NULL);
mem_mapping_add(&gd54xx->mmio_mapping, 0, 0,
gd543x_mmio_read, gd543x_mmio_readw, NULL,
gd543x_mmio_writeb, gd543x_mmio_writew, NULL,
NULL, MEM_MAPPING_EXTERNAL, gd54xx);
mem_mapping_add(&gd54xx->linear_mapping, 0, 0,
gd54xx_readb_linear, gd54xx_readw_linear, NULL,
gd54xx_writeb_linear, gd54xx_writew_linear, NULL,
NULL, MEM_MAPPING_EXTERNAL, gd54xx);
mem_mapping_add(&gd54xx->aperture2_mapping, 0, 0,
gd5436_aperture2_readb, gd5436_aperture2_readw, NULL,
gd5436_aperture2_writeb, gd5436_aperture2_writew, NULL,
NULL, MEM_MAPPING_EXTERNAL, gd54xx);
mem_mapping_add(&gd54xx->vgablt_mapping, 0, 0,
gd5480_vgablt_read, gd5480_vgablt_readw, NULL,
gd5480_vgablt_write, gd5480_vgablt_writew, NULL,
NULL, MEM_MAPPING_EXTERNAL, gd54xx);
}
io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx);
if (gd54xx->pci && (id >= CIRRUS_ID_CLGD5430)) {
if (info->local & 0x200)
pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx, &gd54xx->pci_slot);
else
pci_add_card(PCI_ADD_NORMAL, cl_pci_read, cl_pci_write, gd54xx, &gd54xx->pci_slot);
mem_mapping_disable(&gd54xx->bios_rom.mapping);
}
if ((id <= CIRRUS_ID_CLGD5429) || (!gd54xx->pci && !gd54xx->vlb))
mem_mapping_set_base_ignore(&gd54xx->linear_mapping, 0xff000000);
mem_mapping_disable(&gd54xx->mmio_mapping);
mem_mapping_disable(&gd54xx->linear_mapping);
mem_mapping_disable(&gd54xx->aperture2_mapping);
mem_mapping_disable(&gd54xx->vgablt_mapping);
svga->hwcursor.yoff = svga->hwcursor.xoff = 0;
if (id >= CIRRUS_ID_CLGD5420) {
gd54xx->vclk_n[0] = 0x4a;
gd54xx->vclk_d[0] = 0x2b;
gd54xx->vclk_n[1] = 0x5b;
gd54xx->vclk_d[1] = 0x2f;
gd54xx->vclk_n[2] = 0x45;
gd54xx->vclk_d[2] = 0x30;
gd54xx->vclk_n[3] = 0x7e;
gd54xx->vclk_d[3] = 0x33;
} else {
gd54xx->vclk_n[0] = 0x66;
gd54xx->vclk_d[0] = 0x3b;
gd54xx->vclk_n[1] = 0x5b;
gd54xx->vclk_d[1] = 0x2f;
gd54xx->vclk_n[2] = 0x45;
gd54xx->vclk_d[2] = 0x2c;
gd54xx->vclk_n[3] = 0x7e;
gd54xx->vclk_d[3] = 0x33;
}
svga->extra_banks[1] = 0x8000;
gd54xx->pci_regs[PCI_REG_COMMAND] = 7;
gd54xx->pci_regs[0x30] = 0x00;
gd54xx->pci_regs[0x32] = 0x0c;
gd54xx->pci_regs[0x33] = 0x00;
svga->crtc[0x27] = id;
svga->seqregs[6] = 0x0f;
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429)
gd54xx->unlocked = 1;
if (gd54xx->mca) {
gd54xx->pos_regs[0] = svga->crtc[0x27] == CIRRUS_ID_CLGD5426 ? 0x82 : 0x7b;
gd54xx->pos_regs[1] = svga->crtc[0x27] == CIRRUS_ID_CLGD5426 ? 0x81 : 0x91;
mem_mapping_disable(&gd54xx->bios_rom.mapping);
mca_add(gd5428_mca_read, gd5428_mca_write, gd5428_mca_feedb, NULL, gd54xx);
io_sethandler(0x46e8, 0x0001, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx);
}
if (gd54xx_is_5434(svga)) {
gd54xx->i2c = i2c_gpio_init("ddc_cl54xx");
gd54xx->ddc = ddc_init(i2c_gpio_get_bus(gd54xx->i2c));
}
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5446)
gd54xx->crtcreg_mask = 0x7f;
else
gd54xx->crtcreg_mask = 0x3f;
gd54xx->overlay.colorkeycompare = 0xff;
svga->local = gd54xx;
return gd54xx;
}
static int
gd5401_available(void)
{
return rom_present(BIOS_GD5401_PATH);
}
static int
gd5402_available(void)
{
return rom_present(BIOS_GD5402_PATH);
}
static int
gd5420_available(void)
{
return rom_present(BIOS_GD5420_PATH);
}
static int
gd5422_available(void)
{
return rom_present(BIOS_GD5422_PATH);
}
static int
gd5426_diamond_a1_available(void)
{
return rom_present(BIOS_GD5426_DIAMOND_A1_ISA_PATH);
}
static int
gd5428_available(void)
{
return rom_present(BIOS_GD5428_PATH);
}
static int
gd5428_diamond_b1_available(void)
{
return rom_present(BIOS_GD5428_DIAMOND_B1_VLB_PATH);
}
static int
gd5428_boca_isa_available(void)
{
return rom_present(BIOS_GD5428_BOCA_ISA_PATH_1) && rom_present(BIOS_GD5428_BOCA_ISA_PATH_2);
}
static int
gd5428_isa_available(void)
{
return rom_present(BIOS_GD5428_ISA_PATH);
}
static int
gd5426_mca_available(void)
{
return rom_present(BIOS_GD5426_MCA_PATH);
}
static int
gd5428_mca_available(void)
{
return rom_present(BIOS_GD5428_MCA_PATH);
}
static int
gd5429_available(void)
{
return rom_present(BIOS_GD5429_PATH);
}
static int
gd5430_diamond_a8_available(void)
{
return rom_present(BIOS_GD5430_DIAMOND_A8_VLB_PATH);
}
static int
gd5430_available(void)
{
return rom_present(BIOS_GD5430_PATH);
}
static int
gd5434_available(void)
{
return rom_present(BIOS_GD5434_PATH);
}
static int
gd5434_isa_available(void)
{
return rom_present(BIOS_GD5434_PATH);
}
static int
gd5430_orchid_vlb_available(void)
{
return rom_present(BIOS_GD5430_ORCHID_VLB_PATH);
}
static int
gd5434_diamond_a3_available(void)
{
return rom_present(BIOS_GD5434_DIAMOND_A3_ISA_PATH);
}
static int
gd5436_available(void)
{
return rom_present(BIOS_GD5436_PATH);
}
static int
gd5440_available(void)
{
return rom_present(BIOS_GD5440_PATH);
}
static int
gd5446_available(void)
{
return rom_present(BIOS_GD5446_PATH);
}
static int
gd5446_stb_available(void)
{
return rom_present(BIOS_GD5446_STB_PATH);
}
static int
gd5480_available(void)
{
return rom_present(BIOS_GD5480_PATH);
}
void
gd54xx_close(void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_close(&gd54xx->svga);
if (gd54xx->i2c) {
ddc_close(gd54xx->ddc);
i2c_gpio_close(gd54xx->i2c);
}
free(gd54xx);
}
void
gd54xx_speed_changed(void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
svga_recalctimings(&gd54xx->svga);
}
void
gd54xx_force_redraw(void *priv)
{
gd54xx_t *gd54xx = (gd54xx_t *) priv;
gd54xx->svga.fullchange = gd54xx->svga.monitor->mon_changeframecount;
}
// clang-format off
static const device_config_t gd542x_config[] = {
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 512,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "512 KB", .value = 512 },
{ .description = "1 MB", .value = 1024 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t gd5426_config[] = {
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 2048,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "512 KB", .value = 512 },
{ .description = "1 MB", .value = 1024 },
{ .description = "2 MB", .value = 2048 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t gd5429_config[] = {
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 2,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "1 MB", .value = 1 },
{ .description = "2 MB", .value = 2 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t gd5430_vlb_config[] = {
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 2,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "1 MB", .value = 1 },
{ .description = "2 MB", .value = 2 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "lfb_base",
.description = "Linear framebuffer base",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 2048,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "32 MB", .value = 32 },
{ .description = "64 MB", .value = 64 },
{ .description = "2048 MB", .value = 2048 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t gd5440_onboard_config[] = {
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 2,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "1 MB", .value = 1 },
{ .description = "2 MB", .value = 2 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t gd5434_config[] = {
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 4,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "1 MB", .value = 1 },
{ .description = "2 MB", .value = 2 },
{ .description = "4 MB", .value = 4 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t gd5434_vlb_config[] = {
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 4,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "1 MB", .value = 1 },
{ .description = "2 MB", .value = 2 },
{ .description = "4 MB", .value = 4 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "lfb_base",
.description = "Linear framebuffer base",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 2048,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "32 MB", .value = 32 },
{ .description = "64 MB", .value = 64 },
{ .description = "2048 MB", .value = 2048 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t gd5434_onboard_config[] = {
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 4,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "1 MB", .value = 1 },
{ .description = "2 MB", .value = 2 },
{ .description = "4 MB", .value = 4 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t gd5480_config[] = {
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 4,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "2 MB", .value = 2 },
{ .description = "4 MB", .value = 4 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
// clang-format on
const device_t gd5401_isa_device = {
.name = "Cirrus Logic GD5401 (ISA) (ACUMOS AVGA1)",
.internal_name = "cl_gd5401_isa",
.flags = DEVICE_ISA,
.local = CIRRUS_ID_CLGD5401,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5401_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = NULL,
};
const device_t gd5401_onboard_device = {
.name = "Cirrus Logic GD5401 (ISA) (ACUMOS AVGA1) (On-Board)",
.internal_name = "cl_gd5402_onboard",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5401 | 0x100,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = NULL,
};
const device_t gd5402_isa_device = {
.name = "Cirrus Logic GD5402 (ISA) (ACUMOS AVGA2)",
.internal_name = "cl_gd5402_isa",
.flags = DEVICE_ISA,
.local = CIRRUS_ID_CLGD5402,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5402_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = NULL,
};
const device_t gd5402_onboard_device = {
.name = "Cirrus Logic GD5402 (ISA) (ACUMOS AVGA2) (On-Board)",
.internal_name = "cl_gd5402_onboard",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5402 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = NULL,
};
const device_t gd5420_isa_device = {
.name = "Cirrus Logic GD5420 (ISA)",
.internal_name = "cl_gd5420_isa",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5420,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5420_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd542x_config,
};
const device_t gd5420_onboard_device = {
.name = "Cirrus Logic GD5420 (ISA) (On-Board)",
.internal_name = "cl_gd5420_onboard",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5420 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd542x_config,
};
const device_t gd5422_isa_device = {
.name = "Cirrus Logic GD5422 (ISA)",
.internal_name = "cl_gd5422_isa",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5422,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5422_available, /* Common BIOS between 5422 and 5424 */
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd542x_config,
};
const device_t gd5424_vlb_device = {
.name = "Cirrus Logic GD5424 (VLB)",
.internal_name = "cl_gd5424_vlb",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5424,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5422_available, /* Common BIOS between 5422 and 5424 */
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd542x_config,
};
const device_t gd5424_onboard_device = {
.name = "Cirrus Logic GD5424 (VLB) (On-Board)",
.internal_name = "cl_gd5424_onboard",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5424 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd542x_config,
};
const device_t gd5426_isa_device = {
.name = "Cirrus Logic GD5426 (ISA)",
.internal_name = "cl_gd5426_isa",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5426,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5428_isa_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
};
/*According to a Diamond bios file listing and vgamuseum*/
const device_t gd5426_diamond_speedstar_pro_a1_isa_device = {
.name = "Cirrus Logic GD5426 (ISA) (Diamond SpeedStar Pro Rev. A1)",
.internal_name = "cl_gd5426_diamond_a1_isa",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5426 | 0x100,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5426_diamond_a1_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
};
const device_t gd5426_vlb_device = {
.name = "Cirrus Logic GD5426 (VLB)",
.internal_name = "cl_gd5426_vlb",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5426,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5428_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
};
const device_t gd5426_onboard_device = {
.name = "Cirrus Logic GD5426 (VLB) (On-Board)",
.internal_name = "cl_gd5426_onboard",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5426 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = NULL
};
const device_t gd5428_isa_device = {
.name = "Cirrus Logic GD5428 (ISA)",
.internal_name = "cl_gd5428_isa",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5428,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5428_isa_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
};
const device_t gd5428_vlb_device = {
.name = "Cirrus Logic GD5428 (VLB)",
.internal_name = "cl_gd5428_vlb",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5428,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5428_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
};
/*According to a Diamond bios file listing and vgamuseum*/
const device_t gd5428_diamond_speedstar_pro_b1_vlb_device = {
.name = "Cirrus Logic GD5428 (VLB) (Diamond SpeedStar Pro Rev. B1)",
.internal_name = "cl_gd5428_diamond_b1_vlb",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5428 | 0x100,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5428_diamond_b1_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
};
const device_t gd5428_boca_isa_device = {
.name = "Cirrus Logic GD5428 (ISA) (BOCA Research 4610)",
.internal_name = "cl_gd5428_boca_isa",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5428 | 0x100,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5428_boca_isa_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
};
const device_t gd5428_mca_device = {
.name = "Cirrus Logic GD5428 (MCA) (IBM SVGA Adapter/A)",
.internal_name = "ibm1mbsvga",
.flags = DEVICE_MCA,
.local = CIRRUS_ID_CLGD5428,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5428_mca_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = NULL
};
const device_t gd5426_mca_device = {
.name = "Cirrus Logic GD5426 (MCA) (Reply Video Adapter)",
.internal_name = "replymcasvga",
.flags = DEVICE_MCA,
.local = CIRRUS_ID_CLGD5426,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5426_mca_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
};
const device_t gd5428_onboard_device = {
.name = "Cirrus Logic GD5428 (ISA) (On-Board)",
.internal_name = "cl_gd5428_onboard",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5428,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5428_isa_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
};
const device_t gd5428_vlb_onboard_device = {
.name = "Cirrus Logic GD5428 (VLB) (On-Board)",
.internal_name = "cl_gd5428_vlb_onboard",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5428,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
};
const device_t gd5428_onboard_vlb_device = {
.name = "Cirrus Logic GD5428 (VLB) (On-Board) (Dell)",
.internal_name = "cl_gd5428_onboard_vlb",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5428 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd542x_config
};
const device_t gd5429_isa_device = {
.name = "Cirrus Logic GD5429 (ISA)",
.internal_name = "cl_gd5429_isa",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5429,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5429_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5429_config
};
const device_t gd5429_vlb_device = {
.name = "Cirrus Logic GD5429 (VLB)",
.internal_name = "cl_gd5429_vlb",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5429,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5429_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5429_config
};
/*According to a Diamond bios file listing and vgamuseum*/
const device_t gd5430_diamond_speedstar_pro_se_a8_vlb_device = {
.name = "Cirrus Logic GD5430 (VLB) (Diamond SpeedStar Pro SE Rev. A8)",
.internal_name = "cl_gd5430_vlb_diamond",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5430,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5430_diamond_a8_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5430_vlb_config
};
const device_t gd5430_vlb_device = {
.name = "Cirrus Logic GD5430",
.internal_name = "cl_gd5430_vlb",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5430 | 0x100,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5430_orchid_vlb_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5430_vlb_config
};
const device_t gd5430_onboard_vlb_device = {
.name = "Cirrus Logic GD5430 (On-Board)",
.internal_name = "cl_gd5430_onboard_vlb",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5430 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5430_vlb_config
};
const device_t gd5430_pci_device = {
.name = "Cirrus Logic GD5430 (PCI)",
.internal_name = "cl_gd5430_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5430,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5430_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5429_config
};
const device_t gd5430_onboard_pci_device = {
.name = "Cirrus Logic GD5430 (PCI) (On-Board)",
.internal_name = "cl_gd5430_onboard_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5430 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5429_config
};
const device_t gd5434_isa_device = {
.name = "Cirrus Logic GD5434 (ISA)",
.internal_name = "cl_gd5434_isa",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5434,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5434_isa_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5434_config
};
/*According to a Diamond bios file listing and vgamuseum*/
const device_t gd5434_diamond_speedstar_64_a3_isa_device = {
.name = "Cirrus Logic GD5434 (ISA) (Diamond SpeedStar 64 Rev. A3)",
.internal_name = "cl_gd5434_diamond_a3_isa",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5434 | 0x100,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5434_diamond_a3_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5429_config
};
const device_t gd5434_onboard_pci_device = {
.name = "Cirrus Logic GD5434-4 (PCI) (On-Board)",
.internal_name = "cl_gd5434_onboard_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5434 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5434_onboard_config
};
const device_t gd5434_vlb_device = {
.name = "Cirrus Logic GD5434 (VLB)",
.internal_name = "cl_gd5434_vlb",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5434,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5430_orchid_vlb_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5434_vlb_config
};
const device_t gd5434_pci_device = {
.name = "Cirrus Logic GD5434 (PCI)",
.internal_name = "cl_gd5434_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5434,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5434_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5434_config
};
const device_t gd5436_onboard_pci_device = {
.name = "Cirrus Logic GD5436 (PCI) (On-Board)",
.internal_name = "cl_gd5436_onboard_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5436 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5434_config
};
const device_t gd5436_pci_device = {
.name = "Cirrus Logic GD5436 (PCI)",
.internal_name = "cl_gd5436_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5436,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5436_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5434_config
};
const device_t gd5440_onboard_pci_device = {
.name = "Cirrus Logic GD5440 (PCI) (On-Board)",
.internal_name = "cl_gd5440_onboard_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5440 | 0x600,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5440_onboard_config
};
const device_t gd5440_pci_device = {
.name = "Cirrus Logic GD5440 (PCI)",
.internal_name = "cl_gd5440_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5440 | 0x400,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5440_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5429_config
};
const device_t gd5446_pci_device = {
.name = "Cirrus Logic GD5446 (PCI)",
.internal_name = "cl_gd5446_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5446,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5446_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5434_config
};
const device_t gd5446_stb_pci_device = {
.name = "Cirrus Logic GD5446 (PCI) (STB Nitro 64V)",
.internal_name = "cl_gd5446_stb_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5446 | 0x100,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5446_stb_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5434_config
};
const device_t gd5480_pci_device = {
.name = "Cirrus Logic GD5480 (PCI)",
.internal_name = "cl_gd5480_pci",
.flags = DEVICE_PCI,
.local = CIRRUS_ID_CLGD5480,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5480_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5480_config
};