8514/A changes: 1. Correct interlaced display resolution. 2. Added a limit to cursor coordinates. 3. Test/WIP features of the add-on Mach8 side (ATI 8514/A Ultra) such as configurable BIOS. 4. Made the CMD 5 of the acceleration (Polygon Boundary) more accurate per manual (as much as I could regarding the clipping). Cirrus related: 1. Added SUBSYS PCI vendor/device ID of the 5480 (per manual). IBM VGA: 1. Built-in/option rom-less VGA don't need the "available" flag. ATI Mach8/32: 1. As with 8514/A, corrected interlaced display. XGA-1/-2: 1. Moved the XGA R/W memory size tests out of the SVGA R/W routines to reflect the per card basis, although anything that uses its own SVGA mapping would call the tests there (such as Cirrus, Headland and ATI) when not accessing the LFB. This finally puts an end to the XGA MCA mapping enabling bugs. 2. Re-organized the ISA standalone and non-standalone (INMOS) sides of the chips so that they work properly and remove the FILE rom loading hack from init. 3. The Memory Mapped R/W sides now account for instance in their address range. 4. INMOS only: prevent any ROM address access to anything lower than 0xc8000 to not conflict with the main BIOS rom loading. 5. Fixed native pitch by using the correct register, this fixes non 1024x768 resolutions under NT. 6. More logs when enabled to see any future bugs.
5283 lines
183 KiB
C
5283 lines
183 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/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_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 fc; /* Feature Connector */
|
|
|
|
int id;
|
|
|
|
uint8_t pci_slot;
|
|
uint8_t irq_state;
|
|
|
|
uint8_t pos_regs[8];
|
|
|
|
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->ma - (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 = ((val & CIRRUS_CURSOR_LARGE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422)) ? 64 : 32;
|
|
else
|
|
svga->hwcursor.cur_xsize = 32;
|
|
|
|
if ((svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422))
|
|
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->seqregs[0x12] & CIRRUS_CURSOR_LARGE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422))
|
|
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->gdcaddr > 0x1f) && ((svga->crtc[0x27] <= CIRRUS_ID_CLGD5422) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5424)))
|
|
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 (((svga->crtcreg == 0x19) || (svga->crtcreg == 0x1a) || (svga->crtcreg == 0x1b) || (svga->crtcreg == 0x1d) || (svga->crtcreg == 0x25) || (svga->crtcreg == 0x27)) && !gd54xx->unlocked)
|
|
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->ma_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:
|
|
ret |= (gd54xx_is_5434(svga)) ? 0x98 : 0x18; /*32-bit (Pre-5434)/64-bit (5434 and up) DRAM data bus width for 2M of memory*/
|
|
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->gdcaddr > 0x1f) && ((svga->crtc[0x27] <= CIRRUS_ID_CLGD5422) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5424)))
|
|
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->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5426) && (svga->crtc[0x27] != CIRRUS_ID_CLGD5424))
|
|
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->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5426) && (svga->crtc[0x27] != CIRRUS_ID_CLGD5424))
|
|
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;
|
|
uint32_t base;
|
|
uint32_t size;
|
|
|
|
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;
|
|
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->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x07] & CIRRUS_SR7_BPP_SVGA) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429)) {
|
|
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*/
|
|
base = 128 * 1024 * 1024;
|
|
if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436)
|
|
size = 16 * 1024 * 1024;
|
|
else
|
|
size = 4 * 1024 * 1024;
|
|
}
|
|
|
|
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)
|
|
mem_mapping_disable(&gd54xx->mmio_mapping); /* MMIO is handled in the linear read/write functions */
|
|
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->ma_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(uint32_t addr)
|
|
{
|
|
uint32_t ap = addr >> 22;
|
|
return (uint8_t) (ap & 0x03);
|
|
}
|
|
|
|
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)
|
|
{
|
|
gd54xx_t *gd54xx = (gd54xx_t *) priv;
|
|
svga_t *svga = &gd54xx->svga;
|
|
|
|
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)
|
|
{
|
|
gd54xx_t *gd54xx = (gd54xx_t *) priv;
|
|
svga_t *svga = &gd54xx->svga;
|
|
|
|
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
|
|
gd54xx_write(addr, val, gd54xx);
|
|
gd54xx_write(addr + 1, val >> 8, gd54xx);
|
|
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)
|
|
{
|
|
gd54xx_t *gd54xx = (gd54xx_t *) priv;
|
|
svga_t *svga = &gd54xx->svga;
|
|
|
|
if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
|
|
gd54xx_write(addr, val, gd54xx);
|
|
gd54xx_write(addr + 1, val >> 8, gd54xx);
|
|
gd54xx_write(addr + 2, val >> 16, gd54xx);
|
|
gd54xx_write(addr + 3, val >> 24, gd54xx);
|
|
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(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(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(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(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(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(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(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(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)
|
|
{
|
|
gd54xx_t *gd54xx = (gd54xx_t *) priv;
|
|
svga_t *svga = &gd54xx->svga;
|
|
|
|
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)
|
|
{
|
|
gd54xx_t *gd54xx = (gd54xx_t *) priv;
|
|
svga_t *svga = &gd54xx->svga;
|
|
uint16_t ret;
|
|
|
|
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
|
|
ret = gd54xx_read(addr, priv);
|
|
ret |= gd54xx_read(addr + 1, priv) << 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)
|
|
{
|
|
gd54xx_t *gd54xx = (gd54xx_t *) priv;
|
|
svga_t *svga = &gd54xx->svga;
|
|
uint32_t ret;
|
|
|
|
if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) {
|
|
ret = gd54xx_read(addr, priv);
|
|
ret |= gd54xx_read(addr + 1, priv) << 8;
|
|
ret |= gd54xx_read(addr + 2, priv) << 16;
|
|
ret |= gd54xx_read(addr + 3, priv) << 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, gd54xx);
|
|
}
|
|
|
|
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, gd54xx);
|
|
gd54xx_write(addr + 1, val >> 8, gd54xx);
|
|
}
|
|
}
|
|
}
|
|
|
|
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, gd54xx);
|
|
gd54xx_write(addr + 1, val >> 8, gd54xx);
|
|
gd54xx_write(addr + 2, val >> 16, gd54xx);
|
|
gd54xx_write(addr + 3, val >> 24, gd54xx);
|
|
}
|
|
}
|
|
}
|
|
|
|
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, gd54xx);
|
|
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, gd54xx) | (gd54xx_read(addr + 1, gd54xx) << 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, gd54xx) | (gd54xx_read(addr + 1, gd54xx) << 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;
|
|
return;
|
|
} 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. */
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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) {
|
|
gd54xx_reset_blit(gd54xx);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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. */
|
|
goto request_more_data;
|
|
}
|
|
}
|
|
|
|
/* End of while. */
|
|
request_more_data:
|
|
/* 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
|
|
gd54xx->blt.pattern_x = (gd54xx->blt.mask & 0x07) * gd54xx->blt.pixel_width; /* (Mask & 0x07) pixels. */
|
|
} 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:
|
|
ret = gd54xx->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/
|
|
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_set_p(&svga->mapping, gd54xx);
|
|
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 = malloc(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;
|
|
|
|
memset(gd54xx, 0, sizeof(gd54xx_t));
|
|
|
|
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;
|
|
|
|
switch (id) {
|
|
case CIRRUS_ID_CLGD5401:
|
|
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:
|
|
romfn = BIOS_GD5420_PATH;
|
|
break;
|
|
|
|
case CIRRUS_ID_CLGD5422:
|
|
case CIRRUS_ID_CLGD5424:
|
|
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 & 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) {
|
|
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)
|
|
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;
|
|
|
|
if (gd54xx->bit32) {
|
|
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 {
|
|
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 (romfn == NULL)
|
|
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);
|
|
}
|
|
|
|
mem_mapping_set_p(&svga->mapping, gd54xx);
|
|
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;
|
|
|
|
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,
|
|
.selection = {
|
|
{
|
|
.description = "512 KB",
|
|
.value = 512
|
|
},
|
|
{
|
|
.description = "1 MB",
|
|
.value = 1024
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 512
|
|
},
|
|
{
|
|
.type = CONFIG_END
|
|
}
|
|
};
|
|
|
|
static const device_config_t gd5426_config[] = {
|
|
{
|
|
.name = "memory",
|
|
.description = "Memory size",
|
|
.type = CONFIG_SELECTION,
|
|
.selection = {
|
|
{
|
|
.description = "512 KB",
|
|
.value = 512
|
|
},
|
|
{
|
|
.description = "1 MB",
|
|
.value = 1024
|
|
},
|
|
{
|
|
.description = "2 MB",
|
|
.value = 2048
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 2048
|
|
},
|
|
{
|
|
.type = CONFIG_END
|
|
}
|
|
};
|
|
|
|
static const device_config_t gd5428_onboard_config[] = {
|
|
{
|
|
.name = "memory",
|
|
.description = "Onboard memory size",
|
|
.type = CONFIG_SELECTION,
|
|
.selection = {
|
|
{
|
|
.description = "512 KB",
|
|
.value = 512
|
|
},
|
|
{
|
|
.description = "1 MB",
|
|
.value = 1024
|
|
},
|
|
{
|
|
.description = "2 MB",
|
|
.value = 2048
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 2048
|
|
},
|
|
{
|
|
.type = CONFIG_END
|
|
}
|
|
};
|
|
|
|
static const device_config_t gd5429_config[] = {
|
|
{
|
|
.name = "memory",
|
|
.description = "Memory size",
|
|
.type = CONFIG_SELECTION,
|
|
.selection = {
|
|
{
|
|
.description = "1 MB",
|
|
.value = 1
|
|
},
|
|
{
|
|
.description = "2 MB",
|
|
.value = 2
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 2
|
|
},
|
|
{
|
|
.type = CONFIG_END
|
|
}
|
|
};
|
|
|
|
static const device_config_t gd5440_onboard_config[] = {
|
|
{
|
|
.name = "memory",
|
|
.description = "Onboard memory size",
|
|
.type = CONFIG_SELECTION,
|
|
.selection = {
|
|
{
|
|
.description = "1 MB",
|
|
.value = 1
|
|
},
|
|
{
|
|
.description = "2 MB",
|
|
.value = 2
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 2
|
|
},
|
|
{
|
|
.type = CONFIG_END
|
|
}
|
|
};
|
|
|
|
static const device_config_t gd5434_config[] = {
|
|
{
|
|
.name = "memory",
|
|
.description = "Memory size",
|
|
.type = CONFIG_SELECTION,
|
|
.selection = {
|
|
{
|
|
.description = "1 MB",
|
|
.value = 1
|
|
},
|
|
{
|
|
.description = "2 MB",
|
|
.value = 2
|
|
},
|
|
{
|
|
.description = "4 MB",
|
|
.value = 4
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 4
|
|
},
|
|
{
|
|
.type = CONFIG_END
|
|
}
|
|
};
|
|
|
|
static const device_config_t gd5434_onboard_config[] = {
|
|
{
|
|
.name = "memory",
|
|
.description = "Onboard memory size",
|
|
.type = CONFIG_SELECTION,
|
|
.selection = {
|
|
{
|
|
.description = "1 MB",
|
|
.value = 1
|
|
},
|
|
{
|
|
.description = "2 MB",
|
|
.value = 2
|
|
},
|
|
{
|
|
.description = "4 MB",
|
|
.value = 4
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 4
|
|
},
|
|
{
|
|
.type = CONFIG_END
|
|
}
|
|
};
|
|
|
|
static const device_config_t gd5480_config[] = {
|
|
{
|
|
.name = "memory",
|
|
.description = "Memory size",
|
|
.type = CONFIG_SELECTION,
|
|
.selection = {
|
|
{
|
|
.description = "2 MB",
|
|
.value = 2
|
|
},
|
|
{
|
|
.description = "4 MB",
|
|
.value = 4
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 4
|
|
},
|
|
{
|
|
.type = -1
|
|
}
|
|
};
|
|
// 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 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_AT | DEVICE_ISA,
|
|
.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_AT | DEVICE_ISA,
|
|
.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 gd5422_isa_device = {
|
|
.name = "Cirrus Logic GD5422 (ISA)",
|
|
.internal_name = "cl_gd5422_isa",
|
|
.flags = DEVICE_AT | DEVICE_ISA,
|
|
.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 gd5426_isa_device = {
|
|
.name = "Cirrus Logic GD5426 (ISA)",
|
|
.internal_name = "cl_gd5426_isa",
|
|
.flags = DEVICE_AT | DEVICE_ISA,
|
|
.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_AT | DEVICE_ISA,
|
|
.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_AT | DEVICE_ISA,
|
|
.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_AT | DEVICE_ISA,
|
|
.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_AT | DEVICE_ISA,
|
|
.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 = gd5428_onboard_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 = gd5428_onboard_config
|
|
};
|
|
|
|
const device_t gd5429_isa_device = {
|
|
.name = "Cirrus Logic GD5429 (ISA)",
|
|
.internal_name = "cl_gd5429_isa",
|
|
.flags = DEVICE_AT | DEVICE_ISA,
|
|
.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 = gd5429_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 = gd5429_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 = gd5429_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_AT | DEVICE_ISA,
|
|
.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_AT | DEVICE_ISA,
|
|
.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_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
|
|
};
|