From 9e44719f134c8f6641b945a8c455a8bc8c3f2e23 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 17 Jun 2022 21:26:26 +0200 Subject: [PATCH 1/2] Added initial (and a bit buggy on OS/2, so use 8514/A on it instead) emulation of XGA for both MCA and ISA buses. --- src/config.c | 6 + src/include/86box/vid_svga.h | 5 + src/include/86box/vid_xga.h | 162 ++ src/qt/qt_settingsdisplay.cpp | 7 +- src/qt/qt_settingsdisplay.ui | 9 +- src/video/CMakeLists.txt | 3 +- src/video/vid_svga.c | 37 + src/video/vid_xga.c | 3026 +++++++++++++++++++++++++++++++++ src/win/Makefile.mingw | 3 +- 9 files changed, 3254 insertions(+), 4 deletions(-) create mode 100644 src/include/86box/vid_xga.h create mode 100644 src/video/vid_xga.c diff --git a/src/config.c b/src/config.c index 763453a36..ca14b567a 100644 --- a/src/config.c +++ b/src/config.c @@ -931,6 +931,7 @@ load_video(void) voodoo_enabled = !!config_get_int(cat, "voodoo", 0); ibm8514_enabled = !!config_get_int(cat, "8514a", 0); + xga_enabled = !!config_get_int(cat, "xga", 0); } @@ -2474,6 +2475,11 @@ save_video(void) else config_set_int(cat, "8514a", ibm8514_enabled); + if (xga_enabled == 0) + config_delete_var(cat, "xga"); + else + config_set_int(cat, "xga", xga_enabled); + delete_section_if_empty(cat); } diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 42f15ce96..40613fe99 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -19,6 +19,7 @@ #include <86box/thread.h> #include <86box/vid_8514a.h> +#include <86box/vid_xga.h> #ifndef VIDEO_SVGA_H # define VIDEO_SVGA_H @@ -49,6 +50,7 @@ typedef union { typedef struct svga_t { ibm8514_t dev8514; + xga_t xga; mem_mapping_t mapping; uint8_t fast, chain4, chain2_write, chain2_read, @@ -176,6 +178,9 @@ extern int vga_on, ibm8514_on; extern void ibm8514_poll(ibm8514_t *dev, svga_t *svga); extern void ibm8514_recalctimings(svga_t *svga); +extern void xga_poll(xga_t *xga, svga_t *svga); +extern void xga_recalctimings(svga_t *svga); + extern int svga_init(const device_t *info, svga_t *svga, void *p, int memsize, void (*recalctimings_ex)(struct svga_t *svga), uint8_t (*video_in) (uint16_t addr, void *p), diff --git a/src/include/86box/vid_xga.h b/src/include/86box/vid_xga.h new file mode 100644 index 000000000..8da92bbe0 --- /dev/null +++ b/src/include/86box/vid_xga.h @@ -0,0 +1,162 @@ +/* + * 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. + * + * IBM XGA emulation. + * + * + * + * Authors: TheCollector1995. + * + * Copyright 2022 TheCollector1995. + */ + +#ifndef VIDEO_XGA_H +# define VIDEO_XGA_H + +#include <86box/rom.h> + +typedef struct { + int ena; + int x, y, xoff, yoff, xsize, ysize; + uint32_t addr; +} xga_hwcursor_t; + +typedef struct xga_t +{ + mem_mapping_t memio_mapping; + mem_mapping_t linear_mapping; + mem_mapping_t video_mapping; + rom_t bios_rom; + xga_hwcursor_t hwcursor, hwcursor_latch; + PALETTE extpal; + + uint8_t test, atest[2], testpixel;; + uint8_t pos_regs[8]; + uint8_t disp_addr; + uint8_t cfg_reg; + uint8_t instance; + uint8_t op_mode; + uint8_t aperture_cntl; + uint8_t ap_idx; + uint8_t access_mode; + uint8_t regs[0x100]; + uint8_t regs_idx; + uint8_t hwc_hotspot_x; + uint8_t hwc_hotspot_y; + uint8_t disp_cntl_1, disp_cntl_2; + uint8_t clk_sel_1, clk_sel_2; + uint8_t hwc_control; + uint8_t bus_arb; + uint8_t select_pos_isa; + uint8_t hwcursor_oddeven; + uint8_t cfg_reg_instance; + uint8_t rowcount; + uint8_t pal_idx, pal_idx_prefetch; + uint8_t pal_seq; + uint8_t pal_mask; + uint8_t pal_r, pal_r_prefetch; + uint8_t pal_g, pal_g_prefetch; + uint8_t pal_b, pal_b_prefetch; + uint8_t sprite_data[1024]; + uint8_t *vram, *changedvram; + + int16_t hwc_pos_x; + int16_t hwc_pos_y; + + uint16_t pos_idx; + uint16_t htotal; + uint16_t sprite_idx, sprite_idx_prefetch; + uint16_t hdisp; + uint16_t vtotal; + uint16_t vdispend; + uint16_t vblankstart; + uint16_t vsyncstart; + uint16_t linecmp; + uint16_t pix_map_width; + uint16_t sprite_pal_addr_idx, old_pal_addr_idx; + uint16_t sprite_pal_addr_idx_prefetch; + + int v_total, dispend, v_syncstart, split, v_blankstart, + h_disp, h_disp_old, h_total, h_disp_time, rowoffset, + dispon, h_disp_on, vc, sc, linepos, oddeven, firstline, lastline, + firstline_draw, lastline_draw, displine, fullchange, interlace, + char_width, hwcursor_on; + int pal_pos, pal_pos_prefetch; + int on; + int op_mode_reset; + int sprite_pos, sprite_pos_prefetch, cursor_data_on; + int pal_test; + int from_to_vram; + + uint32_t linear_base, linear_size; + uint32_t base_addr_1mb; + uint32_t hwc_color0, hwc_color1; + uint32_t disp_start_addr; + uint32_t ma_latch; + uint32_t vram_size; + uint32_t vram_mask; + uint32_t rom_addr; + uint32_t ma, maback; + uint32_t extpallook[256]; + uint32_t read_bank, write_bank; + uint32_t px_map_base; + + uint64_t dispontime, dispofftime; + + struct + { + uint8_t control; + uint8_t px_map_idx; + uint8_t frgd_mix, bkgd_mix; + uint8_t cc_cond; + uint8_t octant; + uint8_t draw_mode; + uint8_t mask_mode; + uint8_t short_stroke_vector1; + uint8_t short_stroke_vector2; + uint8_t short_stroke_vector3; + uint8_t short_stroke_vector4; + + int16_t bres_err_term; + int16_t bres_k1, bres_k2; + + uint16_t blt_width; + uint16_t blt_height; + uint16_t mask_map_origin_x_off; + uint16_t mask_map_origin_y_off; + uint16_t src_map_x, src_map_y; + uint16_t dst_map_x, dst_map_y; + uint16_t pat_map_x, pat_map_y; + + int ssv_state; + int pat_src; + int src_map; + int dst_map; + int bkgd_src; + int fore_src; + int x, y, sx, sy, dx, dy, px, py; + int pattern; + int command_len; + + uint32_t short_stroke; + uint32_t color_cmp; + uint32_t carry_chain; + uint32_t plane_mask; + uint32_t frgd_color, bkgd_color; + uint32_t command; + uint32_t dir_cmd; + + uint8_t px_map_format[4]; + uint16_t px_map_width[4]; + uint16_t px_map_height[4]; + uint32_t px_map_base[4]; + } accel; + + volatile int force_busy; +} xga_t; +#endif /*VIDEO_XGA_H*/ diff --git a/src/qt/qt_settingsdisplay.cpp b/src/qt/qt_settingsdisplay.cpp index 84963e833..8686d1ace 100644 --- a/src/qt/qt_settingsdisplay.cpp +++ b/src/qt/qt_settingsdisplay.cpp @@ -47,6 +47,7 @@ void SettingsDisplay::save() { gfxcard = ui->comboBoxVideo->currentData().toInt(); voodoo_enabled = ui->checkBoxVoodoo->isChecked() ? 1 : 0; ibm8514_enabled = ui->checkBox8514->isChecked() ? 1 : 0; + xga_enabled = ui->checkBoxXga->isChecked() ? 1 : 0; } void SettingsDisplay::onCurrentMachineChanged(int machineId) { @@ -119,8 +120,12 @@ void SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) { bool has_MCA = machine_has_bus(machineId, MACHINE_BUS_MCA) > 0; ui->checkBox8514->setEnabled(hasIsa16 || has_MCA); if (hasIsa16 || has_MCA) { - ui->checkBox8514->setChecked(ibm8514_enabled > 0); + ui->checkBox8514->setChecked(ibm8514_enabled); } + + ui->checkBoxXga->setEnabled(hasIsa16 || has_MCA); + if (hasIsa16 || has_MCA) + ui->checkBoxXga->setChecked(xga_enabled); } void SettingsDisplay::on_checkBoxVoodoo_stateChanged(int state) { diff --git a/src/qt/qt_settingsdisplay.ui b/src/qt/qt_settingsdisplay.ui index 275af9fd3..cb927e7c2 100644 --- a/src/qt/qt_settingsdisplay.ui +++ b/src/qt/qt_settingsdisplay.ui @@ -70,7 +70,14 @@ - + + + + XGA + + + + Qt::Vertical diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index ca455ba72..fd88103c7 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -24,7 +24,8 @@ add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c vid_rtg310x.c vid_f82c425.c vid_ti_cf62011.c vid_tvga.c vid_tgui9440.c vid_tkd8001_ramdac.c vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.c vid_ibm_rgb528_ramdac.c - vid_sdac_ramdac.c vid_ogc.c vid_nga.c vid_tvp3026_ramdac.c vid_att2xc498_ramdac.c) + vid_sdac_ramdac.c vid_ogc.c vid_nga.c vid_tvp3026_ramdac.c vid_att2xc498_ramdac.c + vid_xga.c) if(MGA) target_compile_definitions(vid PRIVATE USE_MGA) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 7e794cbac..a102d71f0 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -560,6 +560,8 @@ svga_recalctimings(svga_t *svga) } else { if (ibm8514_on && ibm8514_enabled) ibm8514_recalctimings(svga); + if (xga_enabled) + xga_recalctimings(svga); } svga->y_add = (overscan_y >> 1) - (svga->crtc[8] & 0x1f); @@ -660,6 +662,9 @@ svga_poll(void *p) if (!vga_on && ibm8514_enabled && ibm8514_on) { ibm8514_poll(&svga->dev8514, svga); return; + } else if (!vga_on && xga_enabled && svga->xga.on) { + xga_poll(&svga->xga, svga); + return; } if (!svga->linepos) { @@ -1070,6 +1075,23 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) cycles -= video_timing_write_b; if (!linear) { + if (xga_enabled) { + if (((svga->xga.op_mode & 7) == 4) && (svga->xga.aperture_cntl == 1)) { + if (val == 0xa5) { /*Memory size test of XGA*/ + svga->xga.test = val; + return; + } else if (val == 0x5a) { + svga->xga.test = val; + return; + } else if (val == 0x12 || val == 0x34) { + addr += svga->xga.write_bank; + svga->xga.vram[addr & svga->xga.vram_mask] = val; + svga->xga.op_mode_reset = 1; + return; + } + } else + svga->xga.on = 0; + } addr = svga_decode_addr(svga, addr, 1); if (addr == 0xffffffff) @@ -1254,6 +1276,21 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) cycles -= video_timing_read_b; if (!linear) { + if (xga_enabled) { + if (((svga->xga.op_mode & 7) == 4) && (svga->xga.aperture_cntl == 1)) { + if (svga->xga.test == 0xa5) { /*Memory size test of XGA*/ + svga->xga.on = 1; + return svga->xga.test; + } else if (svga->xga.test == 0x5a) { + svga->xga.on = 1; + return svga->xga.test; + } else if (addr == 0xa0000 || addr == 0xa0010) { + addr += svga->xga.read_bank; + return svga->xga.vram[addr & svga->xga.vram_mask]; + } + } else + svga->xga.on = 0; + } addr = svga_decode_addr(svga, addr, 0); if (addr == 0xffffffff) diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c new file mode 100644 index 000000000..e1250257b --- /dev/null +++ b/src/video/vid_xga.c @@ -0,0 +1,3026 @@ +/* + * 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. + * + * IBM XGA emulation. + * + * + * + * Authors: TheCollector1995. + * + * Copyright 2022 TheCollector1995. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/dma.h> +#include <86box/rom.h> +#include <86box/mca.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> +#include "cpu.h" + +#define XGA_BIOS_PATH "roms/video/xga/XGA_37F9576_Ver200.BIN" + +static void xga_ext_outb(uint16_t addr, uint8_t val, void *p); +static uint8_t xga_ext_inb(uint16_t addr, void *p); + +static void +xga_updatemapping(svga_t *svga) +{ + xga_t *xga = &svga->xga; + + //pclog("OpMode = %x, linear base = %08x, aperture cntl = %d\n", xga->op_mode, xga->linear_base, xga->aperture_cntl); + if ((xga->op_mode & 7) == 4) { + if (xga->aperture_cntl == 1) { + xga->op_mode_reset = 0; + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&xga->video_mapping, 0xa0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); + svga->banked_mask = 0xffff; + mem_mapping_disable(&xga->linear_mapping); + } else if (xga->aperture_cntl == 0) { +linear: + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&xga->video_mapping, 0xa0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); + svga->banked_mask = 0xffff; + if ((xga->pos_regs[4] & 1) && !xga->base_addr_1mb) { + mem_mapping_set_addr(&xga->linear_mapping, xga->linear_base, 0x400000); + } else { + if (xga->base_addr_1mb) { + mem_mapping_set_addr(&xga->linear_mapping, xga->base_addr_1mb, 0x100000); + } else + mem_mapping_disable(&xga->linear_mapping); + } + xga->on = 0; + vga_on = 1; + } else { + xga->op_mode_reset = 0; + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&xga->video_mapping, 0xb0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); + svga->banked_mask = 0xffff; + mem_mapping_disable(&xga->linear_mapping); + } + } else { + if (!(xga->op_mode & 7)) { + xga->op_mode_reset = 1; + goto linear; + } + xga->op_mode_reset = 0; + if (xga->aperture_cntl == 2) { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&xga->video_mapping, 0xb0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); + svga->banked_mask = 0xffff; + } else { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&xga->video_mapping, 0xa0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); + svga->banked_mask = 0xffff; + } + mem_mapping_disable(&xga->linear_mapping); + xga->on = 0; + vga_on = 1; + } +} + +void +xga_recalctimings(svga_t *svga) +{ + xga_t *xga = &svga->xga; + + if (xga->on) { + xga->v_total = xga->vtotal + 1; + xga->dispend = xga->vdispend + 1; + xga->v_syncstart = xga->vsyncstart + 1; + xga->split = xga->linecmp + 1; + xga->v_blankstart = xga->vblankstart + 1; + + xga->h_disp = (xga->hdisp + 1) << 3; + xga->h_total = (xga->htotal + 1) << 3; + + xga->rowoffset = (xga->hdisp + 1); + + xga->interlace = !!(xga->disp_cntl_1 & 0x08); + xga->rowcount = (xga->disp_cntl_2 & 0xc0) >> 6; + + if (xga->interlace) { + xga->v_total >>= 1; + xga->dispend >>= 1; + xga->v_syncstart >>= 1; + xga->split >>= 1; + xga->v_blankstart >>= 1; + } + + xga->ma_latch = xga->disp_start_addr; + xga->h_disp_time = xga->h_disp; + + switch (xga->clk_sel_1 & 0x0c) { + case 0: + if (xga->clk_sel_2 & 0x80) { + svga->clock = (cpuclock * (double)(1ull << 32)) / 41539000.0; + } else { + svga->clock = (cpuclock * (double)(1ull << 32)) / 25175000.0; + } + break; + case 4: + svga->clock = (cpuclock * (double)(1ull << 32)) / 28322000.0; + break; + case 0x0c: + svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0; + break; + } + } else { + vga_on = 1; + } +} + +static void +xga_ext_out_reg(xga_t *xga, svga_t *svga, uint8_t idx, uint8_t val) +{ + uint8_t index; + + switch (idx) { + case 0x10: + xga->htotal = (xga->htotal & 0xff00) | val; + break; + case 0x11: + xga->htotal = (xga->htotal & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x12: + xga->hdisp = (xga->hdisp & 0xff00) | val; + break; + case 0x13: + xga->hdisp = (xga->hdisp & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x20: + xga->vtotal = (xga->vtotal & 0xff00) | val; + break; + case 0x21: + xga->vtotal = (xga->vtotal & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x22: + xga->vdispend = (xga->vdispend & 0xff00) | val; + break; + case 0x23: + xga->vdispend = (xga->vdispend & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x24: + xga->vblankstart = (xga->vblankstart & 0xff00) | val; + break; + case 0x25: + xga->vblankstart = (xga->vblankstart & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x28: + xga->vsyncstart = (xga->vsyncstart & 0xff00) | val; + break; + case 0x29: + xga->vsyncstart = (xga->vsyncstart & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x2c: + xga->linecmp = (xga->linecmp & 0xff00) | val; + break; + case 0x2d: + xga->linecmp = (xga->linecmp & 0xff) | (val << 8); + svga_recalctimings(svga); + break; + + case 0x30: + xga->hwc_pos_x = (xga->hwc_pos_x & 0x0700) | val; + xga->hwcursor.x = xga->hwc_pos_x; + break; + case 0x31: + xga->hwc_pos_x = (xga->hwc_pos_x & 0xff) | ((val & 0x07) << 8); + xga->hwcursor.x = xga->hwc_pos_x; + break; + + case 0x32: + xga->hwc_hotspot_x = val & 0x3f; + xga->hwcursor.xoff = val & 0x3f; + break; + + case 0x33: + xga->hwc_pos_y = (xga->hwc_pos_y & 0x0700) | val; + xga->hwcursor.y = xga->hwc_pos_y; + break; + case 0x34: + xga->hwc_pos_y = (xga->hwc_pos_y & 0xff) | ((val & 0x07) << 8); + xga->hwcursor.y = xga->hwc_pos_y; + break; + + case 0x35: + xga->hwc_hotspot_y = val & 0x3f; + xga->hwcursor.yoff = val & 0x3f; + break; + + case 0x36: + xga->hwc_control = val; + xga->hwcursor.ena = xga->hwc_control & 1; + break; + + case 0x38: + xga->hwc_color0 = (xga->hwc_color0 & 0xffff00) | val; + break; + case 0x39: + xga->hwc_color0 = (xga->hwc_color0 & 0xff00ff) | (val << 8); + break; + case 0x3a: + xga->hwc_color0 = (xga->hwc_color0 & 0x00ffff) | (val << 16); + break; + + case 0x3b: + xga->hwc_color1 = (xga->hwc_color1 & 0xffff00) | val; + break; + case 0x3c: + xga->hwc_color1 = (xga->hwc_color1 & 0xff00ff) | (val << 8); + break; + case 0x3d: + xga->hwc_color1 = (xga->hwc_color1 & 0x00ffff) | (val << 16); + break; + + case 0x40: + xga->disp_start_addr = (xga->disp_start_addr & 0x7ff00) | val; + break; + case 0x41: + xga->disp_start_addr = (xga->disp_start_addr & 0x700ff) | (val << 8); + break; + case 0x42: + xga->disp_start_addr = (xga->disp_start_addr & 0x0ffff) | ((val & 0x07) << 16); + svga_recalctimings(svga); + break; + + case 0x43: + xga->pix_map_width = (xga->pix_map_width & 0x700) | val; + break; + case 0x44: + xga->pix_map_width = (xga->pix_map_width & 0xff) | ((val & 0x07) << 8); + break; + + case 0x50: + xga->disp_cntl_1 = val; + svga_recalctimings(svga); + break; + + case 0x51: + xga->disp_cntl_2 = val; + svga_recalctimings(svga); + break; + + case 0x54: + xga->clk_sel_1 = val; + svga_recalctimings(svga); + break; + + case 0x60: + xga->sprite_pal_addr_idx = (xga->sprite_pal_addr_idx & 0x3f00) | val; + svga->dac_pos = 0; + svga->dac_addr = val & 0xff; + break; + case 0x61: + xga->sprite_pal_addr_idx = (xga->sprite_pal_addr_idx & 0xff) | ((val & 0x3f) << 8); + xga->sprite_pos = xga->sprite_pal_addr_idx & 0x1ff; + if ((xga->sprite_pos >= 1) && (xga->sprite_pos <= 16)) + xga->cursor_data_on = 1; + if ((xga->sprite_pos > 16) && (xga->sprite_pos <= 0x1ff)) + xga->cursor_data_on = 0; + break; + + case 0x62: + xga->sprite_pal_addr_idx_prefetch = (xga->sprite_pal_addr_idx_prefetch & 0x3f00) | val; + svga->dac_pos = 0; + svga->dac_addr = val & 0xff; + break; + case 0x63: + xga->sprite_pal_addr_idx_prefetch = (xga->sprite_pal_addr_idx_prefetch & 0xff) | ((val & 0x3f) << 8); + xga->sprite_pos_prefetch = xga->sprite_pal_addr_idx_prefetch & 0x1ff; + break; + + case 0x64: + svga->dac_mask = val; + break; + + case 0x65: + 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; + xga->pal_b = val; + svga->vgapal[index].r = svga->dac_r; + svga->vgapal[index].g = svga->dac_g; + svga->vgapal[index].b = xga->pal_b; + svga->pallook[index] = makecol32(svga->vgapal[index].r, svga->vgapal[index].g, svga->vgapal[index].b); + svga->dac_pos = 0; + svga->dac_addr = (svga->dac_addr + 1) & 0xff; + break; + } + break; + + case 0x66: + xga->pal_seq = val; + break; + + case 0x67: + svga->dac_r = val; + break; + case 0x68: + xga->pal_b = val; + break; + case 0x69: + svga->dac_g = val; + break; + + case 0x6a: + xga->sprite_data[xga->sprite_pos] = val; + xga->sprite_pos = (xga->sprite_pos + 1) & 0x3ff; + break; + + case 0x70: + xga->clk_sel_2 = val; + svga_recalctimings(svga); + break; + } +} + +static void +xga_ext_outb(uint16_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + //pclog("[%04X:%08X]: EXT OUTB = %02x, val = %02x\n", CS, cpu_state.pc, addr, val); + switch (addr & 0x0f) { + case 0: + xga->op_mode = val; + break; + case 1: + xga->aperture_cntl = val; + xga_updatemapping(svga); + break; + case 6: + vga_on = 0; + xga->on = 1; + break; + case 8: + xga->ap_idx = val; + if (xga->aperture_cntl == 1) { + if ((xga->op_mode & 7) < 4) { + xga->write_bank = xga->read_bank = 0; + } else { + xga->write_bank = (xga->ap_idx & 0x3f) << 16; + xga->read_bank = xga->write_bank; + } + } + break; + case 9: + xga->access_mode = val; + break; + case 0x0a: + xga->regs_idx = val; + break; + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + xga->regs[xga->regs_idx] = val; + xga_ext_out_reg(xga, svga, xga->regs_idx, xga->regs[xga->regs_idx]); + break; + } +} + +static uint8_t +xga_ext_inb(uint16_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint8_t ret, index; + uint16_t sprite_idx; + + switch (addr & 0x0f) { + case 0: + ret = xga->op_mode; + break; + case 1: + ret = xga->aperture_cntl; + break; + case 8: + ret = xga->ap_idx; + break; + case 9: + ret = xga->access_mode; + break; + case 0x0a: + ret = xga->regs_idx; + break; + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + switch (xga->regs_idx) { + case 4: + ret = 1; + break; + case 0x10: + ret = xga->htotal & 0xff; + break; + case 0x11: + ret = xga->htotal >> 8; + break; + case 0x12: + ret = xga->hdisp & 0xff; + break; + case 0x13: + ret = xga->hdisp >> 8; + break; + case 0x20: + ret = xga->vtotal & 0xff; + break; + case 0x21: + ret = xga->vtotal >> 8; + break; + case 0x22: + ret = xga->vdispend & 0xff; + break; + case 0x23: + ret = xga->vdispend >> 8; + break; + case 0x24: + ret = xga->vblankstart & 0xff; + break; + case 0x25: + ret = xga->vblankstart >> 8; + break; + case 0x28: + ret = xga->vsyncstart & 0xff; + break; + case 0x29: + ret = xga->vsyncstart >> 8; + break; + case 0x2c: + ret = xga->linecmp & 0xff; + break; + case 0x2d: + ret = xga->linecmp >> 8; + break; + case 0x30: + ret = xga->hwc_pos_x & 0xff; + break; + case 0x31: + ret = xga->hwc_pos_x >> 8; + break; + case 0x32: + ret = xga->hwc_hotspot_x; + break; + case 0x33: + ret = xga->hwc_pos_y & 0xff; + break; + case 0x34: + ret = xga->hwc_pos_y >> 8; + break; + case 0x35: + ret = xga->hwc_hotspot_y; + break; + case 0x36: + ret = xga->hwc_control; + break; + case 0x38: + ret = xga->hwc_color0 & 0xff; + break; + case 0x39: + ret = xga->hwc_color0 >> 8; + break; + case 0x3a: + ret = xga->hwc_color0 >> 16; + break; + case 0x3b: + ret = xga->hwc_color1 & 0xff; + break; + case 0x3c: + ret = xga->hwc_color1 >> 8; + break; + case 0x3d: + ret = xga->hwc_color1 >> 16; + break; + case 0x40: + ret = xga->disp_start_addr & 0xff; + break; + case 0x41: + ret = xga->disp_start_addr >> 8; + break; + case 0x42: + ret = xga->disp_start_addr >> 16; + break; + case 0x43: + ret = xga->pix_map_width & 0xff; + break; + case 0x44: + ret = xga->pix_map_width >> 8; + break; + case 0x50: + ret = xga->disp_cntl_1 | 0x20; + break; + case 0x51: + ret = xga->disp_cntl_2; + break; + case 0x52: + ret = 0x0a; + break; + case 0x53: + ret = 0xa0; + break; + case 0x54: + ret = xga->clk_sel_1; + break; + + case 0x60: + ret = xga->sprite_pal_addr_idx & 0xff; + break; + case 0x61: + ret = xga->sprite_pal_addr_idx >> 8; + break; + + case 0x62: + ret = xga->sprite_pal_addr_idx_prefetch & 0xff; + break; + case 0x63: + ret = xga->sprite_pal_addr_idx_prefetch >> 8; + break; + + case 0x64: + ret = svga->dac_mask; + break; + + case 0x65: + index = svga->dac_addr & 0xff; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + ret = svga->vgapal[index].r; + break; + case 1: + svga->dac_pos++; + ret = svga->vgapal[index].g; + break; + case 2: + svga->dac_pos = 0; + svga->dac_addr = (svga->dac_addr + 1) & 0xff; + ret = svga->vgapal[index].b; + break; + } + break; + + case 0x66: + ret = xga->pal_seq; + break; + + case 0x67: + ret = svga->dac_r; + break; + case 0x68: + ret = xga->pal_b; + break; + case 0x69: + ret = svga->dac_g; + break; + + case 0x6a: + //pclog("Sprite POS Read = %d, addr idx = %04x\n", xga->sprite_pos, xga->sprite_pal_addr_idx_prefetch); + ret = xga->sprite_data[xga->sprite_pos_prefetch]; + xga->sprite_pos_prefetch = (xga->sprite_pos_prefetch + 1) & 0x3ff; + break; + + case 0x70: + ret = xga->clk_sel_2; + break; + + default: + ret = xga->regs[xga->regs_idx]; + break; + } + break; + } + + //pclog("[%04X:%08X]: EXT INB = %02x, ret = %02x\n", CS, cpu_state.pc, addr, ret); + return ret; +} + + +#define READ(addr, dat) \ + dat = xga->vram[(addr) & (xga->vram_mask)]; + +#define WRITE(addr, dat) \ + xga->vram[((addr)) & (xga->vram_mask)] = dat; \ + xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = changeframecount; + +#define READW(addr, dat) \ + dat = *(uint16_t *)&xga->vram[(addr) & (xga->vram_mask)]; + +#define WRITEW(addr, dat) \ + *(uint16_t *)&xga->vram[((addr)) & (xga->vram_mask)] = dat; \ + xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = changeframecount; + +static uint32_t +xga_rop(uint32_t s, uint8_t d, uint8_t op) +{ + switch(op) { + default: + case 0: + return 0; + case 1: + return s & d; + case 2: + return s & ~d; + case 3: + return s; + case 4: + return ~s & d; + case 5: + return d; + case 6: + return s ^ d; + case 7: + return s | d; + case 8: + return ~s & ~d; + case 9: + return s ^ ~d; + case 0x0a: + return ~d; + case 0x0b: + return s | ~d; + case 0x0c: + return ~s; + case 0x0d: + return ~s | d; + case 0x0e: + return ~s | ~d; + case 0x0f: + return -1; + case 0x10: + return MAX(s, d); + case 0x11: + return MIN(s, d); + case 0x12: + return MIN(0xff, s + d); + case 0x13: + return MAX(0, d - s); + case 0x14: + return MAX(0, s - d); + case 0x15: + return (s + d) >> 1; + } +} + +static uint32_t +xga_accel_read_pattern_map_pixel(svga_t *svga, int x, int y, int map, int width) +{ + xga_t *xga = &svga->xga; + uint32_t addr = xga->accel.px_map_base[map]; + int bits; + uint32_t byte; + uint8_t px; + + addr += (y * (width) >> 3); + addr += (x >> 3); + READ(addr, byte); + if (xga->op_mode_reset) { + if (xga->from_to_vram == 2) { + dma_bm_read(addr, (uint8_t *)&byte, 1, 1); + } + } + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8) && !xga->op_mode_reset) + bits = (x & 7); + else + bits = 7 - (x & 7); + px = (byte >> bits) & 1; + return px; +} + + +static uint32_t +xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, int width, int height) +{ + xga_t *xga = &svga->xga; + uint32_t addr = xga->accel.px_map_base[map]; + int bits; + uint32_t byte; + uint8_t px; + + switch (xga->accel.px_map_format[map] & 7) { + case 0: /*1-bit*/ + addr += (y * (width) >> 3); + addr += (x >> 3); + READ(addr, byte); + if (xga->op_mode_reset) { + if (xga->from_to_vram == 2) { + dma_bm_read(addr, (uint8_t *)&byte, 1, 1); + } + } + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8) && !xga->op_mode_reset) + bits = (x & 7); + else + bits = 7 - (x & 7); + px = (byte >> bits) & 1; + return px; + case 1: /*2-bit*/ + addr += (y * (width) >> 2); + addr += (x >> 2); + READ(addr, byte); + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) + bits = (x & 3); + else + bits = 3 - (x & 3); + return (byte >> (bits << 1)) & 3; + case 2: /*4-bit*/ + addr += (y * (width) >> 1); + addr += (x >> 1); + READ(addr, byte); + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) + bits = (x & 1); + else + bits = 1 - (x & 1); + return (byte >> (bits << 2)) & 0x0f; + case 3: /*8-bit*/ + READ(addr + (y * width) + x, byte); + if (xga->op_mode_reset) { + if (xga->from_to_vram == 2) { + dma_bm_read(addr + (y * width) + x, (uint8_t *)&byte, 1, 1); + } + } + return byte; + case 4: /*16-bit*/ + addr += (y * (width) << 1); + addr += (x << 1); + READW(addr, byte); + return byte; + } + + return 0; +} + +static void +xga_accel_write_map_pixel(svga_t *svga, int x, int y, int map, uint32_t pixel, int width, int height) +{ + xga_t *xga = &svga->xga; + uint32_t addr = xga->accel.px_map_base[map]; + uint8_t byte, mask; + + switch (xga->accel.px_map_format[map] & 7) { + case 0: /*1-bit*/ + addr += (y * (width) >> 3); + addr += (x >> 3); + READ(addr, byte); + if (xga->op_mode_reset) { + if (xga->from_to_vram == 1) { + dma_bm_read(addr, (uint8_t *)&byte, 1, 1); + } + } + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8) && !xga->op_mode_reset) + mask = 1 << (x & 7); + else + mask = 1 << (7 - (x & 7)); + byte = (byte & ~mask) | ((pixel ? 0xff : 0) & mask); + WRITE(addr, byte); + if (xga->op_mode_reset) { + if (xga->from_to_vram == 1) { + dma_bm_write(addr, &byte, 1, 1); + } + } + break; + case 1: /*2-bit*/ + addr += (y * (width) >> 2); + addr += (x >> 2); + READ(addr, byte); + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) + mask = 3 << ((x & 3) << 1); + else + mask = 3 << ((3 - (x & 3)) << 1); + byte = (byte & ~mask) | ((pixel ? 0xff : 0) & mask); + WRITE(addr, byte); + break; + case 2: /*4-bit*/ + addr += (y * (width) >> 1); + addr += (x >> 1); + READ(addr, byte); + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) + mask = 0x0f << ((x & 1) << 2); + else + mask = 0x0f << ((1 - (x & 1)) << 2); + byte = (byte & ~mask) | ((pixel ? 0xff : 0) & mask); + WRITE(addr, byte); + break; + case 3: /*8-bit*/ + WRITE(addr + (y * width) + x, pixel & 0xff); + if (xga->op_mode_reset) { + if (xga->from_to_vram == 1) { + dma_bm_write(addr + (y * width) + x, (uint8_t *)&pixel, 1, 1); + } + } else { + if (!xga->on && vga_on) { + dma_bm_write(addr + (y * width) + x, (uint8_t *)&pixel, 1, 1); + } + } + break; + case 4: /*16-bit*/ + addr += (y * (width) << 1); + addr += (x << 1); + WRITEW(addr, pixel); + break; + } +} + +static void +xga_short_stroke(svga_t *svga, uint8_t ssv) +{ + xga_t *xga = &svga->xga; + uint32_t src_dat, dest_dat, old_dest_dat; + uint32_t color_cmp = xga->accel.color_cmp; + uint32_t plane_mask = xga->accel.plane_mask; + int mix; + int count = -1; + int y = ssv & 0x0f; + int x = 0; + int dx, dy, dirx, diry; + + dx = xga->accel.dst_map_x & 0x1fff; + if (xga->accel.dst_map_x & 0x1800) + dx |= ~0x17ff; + + dy = xga->accel.dst_map_y & 0x1fff; + if (xga->accel.dst_map_y & 0x1800) + dy |= ~0x17ff; + + switch ((ssv >> 5) & 7) { + case 0: + dirx = 1; + diry = 0; + break; + case 1: + dirx = 1; + diry = -1; + break; + case 2: + dirx = 0; + diry = -1; + break; + case 3: + dirx = -1; + diry = -1; + break; + case 4: + dirx = -1; + diry = 0; + break; + case 5: + dirx = -1; + diry = 1; + break; + case 6: + dirx = 0; + diry = 1; + break; + case 7: + dirx = 1; + diry = 1; + break; + } + + if (xga->accel.pat_src == 8) { + while (y >= 0) { + if (xga->accel.command & 0xc0) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && + (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + dest_dat = (dest_dat & ~plane_mask) | (xga_rop(src_dat, dest_dat, xga->accel.frgd_mix & 0x1f) & plane_mask); + if ((xga->accel.command & 0x30) == 0) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } else if (((xga->accel.command & 0x30) == 0x10) && x) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } else if (((xga->accel.command & 0x30) == 0x20) && y) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } + } else { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + dest_dat = (dest_dat & ~plane_mask) | (xga_rop(src_dat, dest_dat, xga->accel.frgd_mix & 0x1f) & plane_mask); + if ((xga->accel.command & 0x30) == 0) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } else if (((xga->accel.command & 0x30) == 0x10) && x) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } else if (((xga->accel.command & 0x30) == 0x20) && y) { + if (ssv & 0x10) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } + + if (!y) { + break; + } + + dx += dirx; + dy += diry; + + x++; + y--; + } + } + + xga->accel.dst_map_x = dx; + xga->accel.dst_map_y = dy; +} + +#define SWAP(a,b) tmpswap = a; a = b; b = tmpswap; + +static void +xga_line_draw_write(svga_t *svga) +{ + xga_t *xga = &svga->xga; + uint32_t src_dat, dest_dat, old_dest_dat; + uint32_t color_cmp = xga->accel.color_cmp; + uint32_t plane_mask = xga->accel.plane_mask; + int mix; + int dminor, destxtmp, dmajor, err, tmpswap; + int steep = 1; + int xdir, ydir; + int count = -1; + int y = xga->accel.blt_width; + int x = 0; + int dx, dy; + + dminor = ((int16_t)xga->accel.bres_k1); + if (xga->accel.bres_k1 & 0x2000) + dminor |= ~0x1fff; + dminor >>= 1; + + destxtmp = ((int16_t)xga->accel.bres_k2); + if (xga->accel.bres_k2 & 0x2000) + destxtmp |= ~0x1fff; + + dmajor = -(destxtmp - (dminor << 1)) >> 1; + + err = ((int16_t)xga->accel.bres_err_term); + if (xga->accel.bres_err_term & 0x2000) + destxtmp |= ~0x1fff; + + if (xga->accel.octant & 0x02) { + ydir = -1; + } else { + ydir = 1; + } + + if (xga->accel.octant & 0x04) { + xdir = -1; + } else { + xdir = 1; + } + + dx = xga->accel.dst_map_x & 0x1fff; + if (xga->accel.dst_map_x & 0x1800) + dx |= ~0x17ff; + + dy = xga->accel.dst_map_y & 0x1fff; + if (xga->accel.dst_map_y & 0x1800) + dy |= ~0x17ff; + + if (xga->accel.octant & 0x01) { + steep = 0; + SWAP(dx, dy); + SWAP(xdir, ydir); + } + + if (xga->accel.pat_src == 8) { + while (y >= 0) { + if (xga->accel.command & 0xc0) { + if (steep) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && + (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + dest_dat = (dest_dat & ~plane_mask) | (xga_rop(src_dat, dest_dat, xga->accel.frgd_mix & 0x1f) & plane_mask); + if ((xga->accel.command & 0x30) == 0) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x10) && x) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x20) && y) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } else { + if ((dy >= xga->accel.mask_map_origin_x_off) && (dy <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && + (dx >= xga->accel.mask_map_origin_y_off) && (dx <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dy, dx, xga->accel.dst_map, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + dest_dat = (dest_dat & ~plane_mask) | (xga_rop(src_dat, dest_dat, xga->accel.frgd_mix & 0x1f) & plane_mask); + if ((xga->accel.command & 0x30) == 0) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x10) && x) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x20) && y) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } + } else { + if (steep) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + dest_dat = (dest_dat & ~plane_mask) | (xga_rop(src_dat, dest_dat, xga->accel.frgd_mix & 0x1f) & plane_mask); + if ((xga->accel.command & 0x30) == 0) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x10) && x) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x20) && y) + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } else { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.src_map_x & 0xfff, xga->accel.src_map_y & 0xfff, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dy, dx, xga->accel.dst_map, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + dest_dat = (dest_dat & ~plane_mask) | (xga_rop(src_dat, dest_dat, xga->accel.frgd_mix & 0x1f) & plane_mask); + if ((xga->accel.command & 0x30) == 0) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x10) && x) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + else if (((xga->accel.command & 0x30) == 0x20) && y) + xga_accel_write_map_pixel(svga, dy, dx, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } + + if (!y) { + break; + } + + while (err > 0) { + dy += ydir; + err -= (dmajor << 1); + } + + dx += xdir; + err += (dminor << 1); + + x++; + y--; + } + } + + if (steep) { + xga->accel.dst_map_x = dx; + xga->accel.dst_map_y = dy; + } else { + xga->accel.dst_map_x = dy; + xga->accel.dst_map_y = dx; + } +} + +#if 0 +static void +xga_line_draw_read(xga_t *xga) +{ + uint32_t src_dat = 0, dest_dat, old_dest_dat; + uint32_t out = 0; + int clip_t = xga->accel.mask_map_origin_y_off & 0xfff; + int clip_l = xga->accel.mask_map_origin_x_off & 0xfff; + int clip_b = xga->accel.px_map[0].height & 0xfff; + int clip_r = xga->accel.px_map[0].width & 0xfff; + int pixcnt = xga->accel.blt_width; + int count = -1; + int16_t dminor, dmajor, destxtmp, tmpswap; + int16_t cx, cy, dx, dy, err; + int16_t sx, sy, px, py; + int xdir = (xga->accel.octant & 0x04) ? -1 : 1; + int ydir = (xga->accel.octant & 0x02) ? -1 : 1; + int steep = 1; + int mix = 0; + uint8_t color_cmp = xga->accel.color_cmp & 0xff; + + + + dminor = xga->accel.bres_k1; + if (xga->accel.bres_k1 & 0x1000) + dminor |= ~0xfff; + dminor >>= 1; + + destxtmp = xga->accel.bres_k2; + if (xga->accel.bres_k2 & 0x1000) + destxtmp |= ~0xfff; + + dmajor = -(destxtmp - (dminor << 1)) >> 1; + + cx = dmajor; + cy = dminor; + + sx = xga->accel.dst_map_x & 0xfff; + sy = xga->accel.dst_map_y & 0xfff; + + dx = xga->accel.src_map_x & 0xfff; + dy = xga->accel.src_map_y & 0xfff; + + px = xga->accel.pat_map_x & 0xfff; + py = xga->accel.pat_map_y & 0xfff; + + err = xga->accel.bres_err_term; + if (xga->accel.bres_err_term & 0x1000) + err |= ~0xfff; + + if (xga->accel.octant & 0x01) { + steep = 0; + SWAP(sx, sy); + SWAP(dx, dy); + SWAP(px, py); + SWAP(xdir, ydir); + } + + xga->force_busy = 1; + + while (count--) { + if (steep) { + if (((dx >= clip_l) && (dx <= clip_r) && + (dy >= clip_t) && (dy <= clip_b)) || (xga->accel.mask_mode == 0)){ + if (xga->accel.pat_src == 8) + mix = xga_accel_read_map_pixel(xga, sx, sy, xga->accel.src_map + 1) & 0xff; + else if (xga->accel.pat_src == 7) { + mix = 1; + } else if (xga->accel.pat_src <= 2) { + mix = xga_accel_read_map_pixel(xga, px, py, xga->accel.pat_src + 1) & 0xff; + } + + if (mix) { + if (xga->accel.fore_src) + src_dat = xga_accel_read_map_pixel(xga, sx, sy, xga->accel.src_map + 1) & 0xff; + else + src_dat = xga->accel.frgd_color & 0xff; + } else { + if (xga->accel.bkgd_src) + src_dat = xga_accel_read_map_pixel(xga, sx, sy, xga->accel.src_map + 1) & 0xff; + else + src_dat = xga->accel.bkgd_color & 0xff; + } + + dest_dat = xga_accel_read_map_pixel(xga, dx, dy, xga->accel.dst_map + 1) & 0xff; + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + if (xga->accel.mask_mode) + dest_dat = (dest_dat & xga->accel.plane_mask) | (old_dest_dat & ~xga->accel.plane_mask); + if ((xga->accel.draw_mode == 0x20) && (pixcnt < xga->accel.blt_width)) + xga_accel_write_map_pixel(xga, dx, dy, xga->accel.dst_map + 1, dest_dat); + else if ((xga->accel.draw_mode == 0x10) && (pixcnt > 0)) + xga_accel_write_map_pixel(xga, dx, dy, xga->accel.dst_map + 1, dest_dat); + else + xga_accel_write_map_pixel(xga, dx, dy, xga->accel.dst_map + 1, dest_dat); + } + } + } else { + if (((dy >= clip_l) && (dy <= clip_r) && + (dx >= clip_t) && (dx <= clip_b)) || (xga->accel.mask_mode == 0)) { + if (xga->accel.pat_src == 8) + mix = xga_accel_read_map_pixel(xga, sy, sx, xga->accel.src_map + 1) & 0xff; + else if (xga->accel.pat_src == 7) { + mix = 1; + } else if (xga->accel.pat_src <= 2) { + mix = xga_accel_read_map_pixel(xga, py, px, xga->accel.pat_src + 1) & 0xff; + } + + if (mix) { + if (xga->accel.fore_src) + src_dat = xga_accel_read_map_pixel(xga, sy, sx, xga->accel.src_map + 1) & 0xff; + else + src_dat = xga->accel.frgd_color & 0xff; + } else { + if (xga->accel.bkgd_src) + src_dat = xga_accel_read_map_pixel(xga, sy, sx, xga->accel.src_map + 1) & 0xff; + else + src_dat = xga->accel.bkgd_color & 0xff; + } + + dest_dat = xga_accel_read_map_pixel(xga, dy, dx, xga->accel.dst_map + 1) & 0xff; + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + if (xga->accel.mask_mode) + dest_dat = (dest_dat & xga->accel.plane_mask) | (old_dest_dat & ~xga->accel.plane_mask); + if ((xga->accel.draw_mode == 0x20) && (pixcnt < xga->accel.blt_width)) + xga_accel_write_map_pixel(xga, dy, dx, xga->accel.dst_map + 1, dest_dat); + else if ((xga->accel.draw_mode == 0x10) && (pixcnt > 0)) + xga_accel_write_map_pixel(xga, dy, dx, xga->accel.dst_map + 1, dest_dat); + else + xga_accel_write_map_pixel(xga, dy, dx, xga->accel.dst_map + 1, dest_dat); + } + } + } + + if (pixcnt == xga->accel.blt_width) { + break; + } + + while (err > 0) { + sy += ydir; + dy += ydir; + py += ydir; + err -= (cx << 1); + } + sx += xdir; + dx += xdir; + px += xdir; + err += (cy << 1); + + pixcnt++; + } +} +#endif + +static int16_t +xga_dst_wrap(int16_t addr) +{ + addr &= 0x1fff; + return (addr & 0x1800) == 0x1800 ? (addr | 0xf800) : addr; +} + +static void +xga_bitblt(svga_t *svga) +{ + xga_t *xga = &svga->xga; + uint32_t src_dat, dest_dat, old_dest_dat; + uint32_t color_cmp = xga->accel.color_cmp; + uint32_t plane_mask = xga->accel.plane_mask; + int mix = 0; + int tmpswap; + int xdir, ydir; + + if (xga->accel.octant & 0x02) { + ydir = -1; + } else { + ydir = 1; + } + + if (xga->accel.octant & 0x04) { + xdir = -1; + } else { + xdir = 1; + } + + xga->accel.x = xga->accel.blt_width & 0xfff; + xga->accel.y = xga->accel.blt_height & 0xfff; + + xga->accel.sx = xga->accel.src_map_x & 0xfff; + xga->accel.sy = xga->accel.src_map_y & 0xfff; + xga->accel.px = xga->accel.pat_map_x & 0xfff; + xga->accel.py = xga->accel.pat_map_y & 0xfff; + xga->accel.dx = xga_dst_wrap(xga->accel.dst_map_x); + xga->accel.dy = xga_dst_wrap(xga->accel.dst_map_y); + + xga->accel.pattern = 0; + xga->accel.dir_cmd = xga->accel.command & 0x30000; + + if (xga->accel.dir_cmd == 0x20000) + xga->from_to_vram = 1; + else if (xga->accel.dir_cmd == 0x10000) + xga->from_to_vram = 2; + else + xga->from_to_vram = 0; + + if (xga->accel.pat_src == 8) { + if ((xga->accel.px_map_height[xga->accel.src_map] == 7)) { + xga->accel.pattern = 1; + } + + //pclog("CMD = %08x: Y = %d, X = %d, patsrc = %02x, srcmap = %d, dstmap = %d, py = %d, sy = %d, dy = %d, width0 = %d, width1 = %d, width2 = %d, width3 = %d\n", xga->accel.command, xga->accel.y, xga->accel.x, xga->accel.pat_src, xga->accel.src_map, xga->accel.dst_map, xga->accel.py, xga->accel.sy, xga->accel.dy, xga->accel.px_map_width[0], xga->accel.px_map_width[1], xga->accel.px_map_width[2], xga->accel.px_map_width[3]); + while (xga->accel.y >= 0) { + if (xga->accel.command & 0xc0) { + if ((xga->accel.dx >= xga->accel.mask_map_origin_x_off) && (xga->accel.dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && + (xga->accel.dy >= xga->accel.mask_map_origin_y_off) && (xga->accel.dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + dest_dat = (dest_dat & ~plane_mask) | (xga_rop(src_dat, dest_dat, xga->accel.frgd_mix & 0x1f) & plane_mask); + xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } else { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + dest_dat = (dest_dat & ~plane_mask) | (xga_rop(src_dat, dest_dat, xga->accel.frgd_mix & 0x1f) & plane_mask); + xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + + if (xga->accel.pattern) + xga->accel.sx = ((xga->accel.sx + xdir) & xga->accel.px_map_width[xga->accel.src_map]) | (xga->accel.sx & ~xga->accel.px_map_width[xga->accel.src_map]); + else + xga->accel.sx += xdir; + xga->accel.dx = xga_dst_wrap(xga->accel.dx + xdir); + xga->accel.x--; + if (xga->accel.x < 0) { + xga->accel.x = (xga->accel.blt_width & 0xfff); + + xga->accel.dx = xga_dst_wrap(xga->accel.dst_map_x); + xga->accel.sx = xga->accel.src_map_x & 0xfff; + + xga->accel.dy = xga_dst_wrap(xga->accel.dy + ydir); + if (xga->accel.pattern == 1) + xga->accel.sy = ((xga->accel.sy + ydir) & 7) | (xga->accel.sy & ~7); + else if (xga->accel.pattern == 2) + xga->accel.sy = ((xga->accel.sy + ydir) & xga->accel.px_map_height[xga->accel.src_map]) | (xga->accel.sy & ~xga->accel.px_map_height[xga->accel.src_map]); + else + xga->accel.sy += ydir; + + xga->accel.y--; + + if (xga->accel.y < 0) { + xga->accel.dst_map_x = xga->accel.dx; + xga->accel.dst_map_y = xga->accel.dy; + xga->accel.src_map_x = xga->accel.sx; + xga->accel.src_map_y = xga->accel.sy; + return; + } + } + } + } else if (xga->accel.pat_src >= 1) { + if (xga->op_mode_reset) { + if (xga->accel.pat_src == 2) { + xga->accel.pattern = 2; + } + } else { + if (xga->accel.px_map_height[xga->accel.pat_src] == 7) + xga->accel.pattern = 1; + } + + //pclog("CMD = %08x: Y = %d, X = %d, patsrc = %02x, srcmap = %d, dstmap = %d, py = %d, sy = %d, dy = %d, width0 = %d, width1 = %d, width2 = %d, width3 = %d\n", xga->accel.command, xga->accel.y, xga->accel.x, xga->accel.pat_src, xga->accel.src_map, xga->accel.dst_map, xga->accel.py, xga->accel.sy, xga->accel.dy, xga->accel.px_map_width[0], xga->accel.px_map_width[1], xga->accel.px_map_width[2], xga->accel.px_map_width[3]); + while (xga->accel.y >= 0) { + mix = xga_accel_read_pattern_map_pixel(svga, xga->accel.px, xga->accel.py, xga->accel.pat_src, xga->accel.px_map_width[xga->accel.pat_src] + 1); + + if (xga->accel.command & 0xc0) { + if ((xga->accel.dx >= xga->accel.mask_map_origin_x_off) && (xga->accel.dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && + (xga->accel.dy >= xga->accel.mask_map_origin_y_off) && (xga->accel.dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + if (mix) + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + else + src_dat = (((xga->accel.command >> 30) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.bkgd_color; + + dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + dest_dat = (dest_dat & ~plane_mask) | (xga_rop(src_dat, dest_dat, mix ? (xga->accel.frgd_mix & 0x1f) : (xga->accel.bkgd_mix & 0x1f)) & plane_mask); + xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + } else { + if (mix) + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.frgd_color; + else + src_dat = (((xga->accel.command >> 30) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, xga->accel.px_map_width[xga->accel.src_map] + 1, xga->accel.px_map_height[xga->accel.src_map] + 1) : xga->accel.bkgd_color; + + dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + dest_dat = (dest_dat & ~plane_mask) | (xga_rop(src_dat, dest_dat, mix ? (xga->accel.frgd_mix & 0x1f) : (xga->accel.bkgd_mix & 0x1f)) & plane_mask); + xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1, xga->accel.px_map_height[xga->accel.dst_map] + 1); + } + } + + xga->accel.sx += xdir; + if (xga->accel.pattern) + xga->accel.px = ((xga->accel.px + xdir) & xga->accel.px_map_width[xga->accel.pat_src]) | (xga->accel.px & ~xga->accel.px_map_width[xga->accel.pat_src]); + else + xga->accel.px += xdir; + xga->accel.dx = xga_dst_wrap(xga->accel.dx + xdir); + xga->accel.x--; + if (xga->accel.x < 0) { + xga->accel.y--; + xga->accel.x = (xga->accel.blt_width & 0xfff); + + xga->accel.dx = xga_dst_wrap(xga->accel.dst_map_x); + xga->accel.sx = xga->accel.src_map_x & 0xfff; + xga->accel.px = xga->accel.pat_map_x & 0xfff; + + xga->accel.sy += ydir; + if ((xga->accel.sy < 0) && (ydir == -1)) + xga->accel.sy = 1; + if (xga->accel.pattern == 1) + xga->accel.py = ((xga->accel.py + ydir) & 7) | (xga->accel.py & ~7); + else if (xga->accel.pattern == 2) + xga->accel.py = ((xga->accel.py + ydir) & xga->accel.px_map_height[xga->accel.pat_src]) | (xga->accel.py & ~xga->accel.px_map_height[xga->accel.pat_src]); + else + xga->accel.py += ydir; + xga->accel.dy = xga_dst_wrap(xga->accel.dy + ydir); + + if (xga->accel.y < 0) { + xga->accel.dst_map_x = xga->accel.dx; + xga->accel.dst_map_y = xga->accel.dy; + xga->accel.src_map_x = xga->accel.sx; + xga->accel.src_map_y = xga->accel.sy; + xga->accel.pat_map_x = xga->accel.px; + xga->accel.pat_map_y = xga->accel.py; + return; + } + } + } + } +} + +#if 0 +static void +xga_inverting_bitblt(xga_t *xga) +{ + uint32_t src_dat = 0, dest_dat, old_dest_dat; + uint32_t out = 0; + int clip_t = xga->accel.mask_map_origin_y_off & 0xfff; + int clip_l = xga->accel.mask_map_origin_x_off & 0xfff; + int clip_b = xga->accel.px_map[0].height & 0xfff; + int clip_r = xga->accel.px_map[0].width & 0xfff; + int count = -1; + int xdir = (xga->accel.octant & 0x04) ? 1 : -1; + int ydir = (xga->accel.octant & 0x02) ? 1 : -1; + int mix = 0; + int x = 0, y = 0; + int sx, sy, dx, dy, px, py; + uint8_t color_cmp = xga->accel.color_cmp & 0xff; + + sx = xga->accel.src_map_x & 0xfff; + sy = xga->accel.src_map_y & 0xfff; + + dx = xga->accel.dst_map_x & 0xfff; + dy = xga->accel.dst_map_y & 0xfff; + + px = xga->accel.pat_map_x & 0xfff; + py = xga->accel.pat_map_y & 0xfff; + + xga->force_busy = 1; + + while (count--) { + if (((dx <= clip_l) && (dx >= clip_r) && + (dy <= clip_t) && (dy >= clip_b)) || (xga->accel.mask_mode == 0)) { + if (xga->accel.pat_src == 8) + mix = xga_accel_read_map_pixel(xga, sx, sy, xga->accel.src_map + 1) & 0xff; + else if (xga->accel.pat_src == 7) { + mix = 1; + } else if (xga->accel.pat_src <= 2) { + mix = xga_accel_read_map_pixel(xga, px, py, xga->accel.pat_src + 1) & 0xff; + } + + if (mix) { + if (xga->accel.fore_src) + src_dat = xga_accel_read_map_pixel(xga, sx, sy, xga->accel.src_map + 1) & 0xff; + else + src_dat = xga->accel.frgd_color & 0xff; + } else { + if (xga->accel.bkgd_src) + src_dat = xga_accel_read_map_pixel(xga, sx, sy, xga->accel.src_map + 1) & 0xff; + else + src_dat = xga->accel.bkgd_color & 0xff; + } + + dest_dat = xga_accel_read_map_pixel(xga, dx, dy, xga->accel.dst_map + 1) & 0xff; + + if ((xga->accel.cc_cond == 4) || + ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || + ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || + ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || + ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || + ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || + ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + if (xga->accel.mask_mode) + dest_dat = (dest_dat & xga->accel.plane_mask) | (old_dest_dat & ~xga->accel.plane_mask); + xga_accel_write_map_pixel(xga, dx, dy, xga->accel.dst_map + 1, dest_dat); + } + } + + sx += xdir; + dx = xga_dstwrap(xga, dx + xdir); + px += xdir; + x++; + + if (x > xga->accel.blt_width) { + x = 0; + + px = xga->accel.pat_map_x & 0xfff; + py += ydir; + + dx = xga->accel.dst_map_x & 0xfff; + dy = xga_dstwrap(xga, dy + ydir); + + sx = xga->accel.src_map_x & 0xfff; + sy += ydir; + + y++; + + if (y > xga->accel.blt_height) + return; + } + } +} +#endif + +static void +xga_mem_write(uint32_t addr, uint32_t val, xga_t *xga, svga_t *svga, int len) +{ + addr &= 0x1fff; + + if (addr >= 0x1800) { + switch (addr & 0x7f) { + case 0x12: + xga->accel.px_map_idx = val & 3; + break; + + case 0x14: + if (len == 4) + xga->accel.px_map_base[xga->accel.px_map_idx] = val; + else if (len == 2) + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0xffff0000) | val; + else + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0xffffff00) | val; + break; + case 0x15: + if (len == 1) + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0xffff00ff) | (val << 8); + break; + case 0x16: + if (len == 2) + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0x0000ffff) | (val << 16); + else + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0xff00ffff) | (val << 16); + break; + case 0x17: + if (len == 1) + xga->accel.px_map_base[xga->accel.px_map_idx] = (xga->accel.px_map_base[xga->accel.px_map_idx] & 0x00ffffff) | (val << 24); + break; + + case 0x18: + if (len == 4) { + xga->accel.px_map_width[xga->accel.px_map_idx] = val & 0xffff; + xga->accel.px_map_height[xga->accel.px_map_idx] = (val >> 16) & 0xffff; + } else if (len == 2) { + xga->accel.px_map_width[xga->accel.px_map_idx] = val; + } else + xga->accel.px_map_width[xga->accel.px_map_idx] = (xga->accel.px_map_width[xga->accel.px_map_idx] & 0xff00) | val; + break; + case 0x19: + if (len == 1) + xga->accel.px_map_width[xga->accel.px_map_idx] = (xga->accel.px_map_width[xga->accel.px_map_idx] & 0xff) | (val << 8); + break; + + case 0x1a: + if (len == 2) + xga->accel.px_map_height[xga->accel.px_map_idx] = val; + else + xga->accel.px_map_height[xga->accel.px_map_idx] = (xga->accel.px_map_height[xga->accel.px_map_idx] & 0xff00) | val; + break; + case 0x1b: + if (len == 1) + xga->accel.px_map_height[xga->accel.px_map_idx] = (xga->accel.px_map_height[xga->accel.px_map_idx] & 0xff) | (val << 8); + break; + + case 0x1c: + xga->accel.px_map_format[xga->accel.px_map_idx] = val; + break; + + case 0x20: + if (len >= 2) { + xga->accel.bres_err_term = val & 0x3fff; + if (val & 0x2000) + xga->accel.bres_err_term |= ~0x3fff; + } else + xga->accel.bres_err_term = (xga->accel.bres_err_term & 0x3f00) | val; + break; + case 0x21: + if (len == 1) { + xga->accel.bres_err_term = (xga->accel.bres_err_term & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + xga->accel.bres_err_term |= ~0x3fff; + } + break; + + case 0x24: + if (len >= 2) { + xga->accel.bres_k1 = val & 0x3fff; + if (val & 0x2000) + xga->accel.bres_k1 |= ~0x3fff; + } else + xga->accel.bres_k1 = (xga->accel.bres_k1 & 0x3f00) | val; + break; + case 0x25: + if (len == 1) { + xga->accel.bres_k1 = (xga->accel.bres_k1 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + xga->accel.bres_k1 |= ~0x3fff; + } + break; + + case 0x28: + if (len >= 2) { + xga->accel.bres_k2 = val & 0x3fff; + if (val & 0x2000) + xga->accel.bres_k2 |= ~0x3fff; + } else + xga->accel.bres_k2 = (xga->accel.bres_k2 & 0x3f00) | val; + break; + case 0x29: + if (len == 1) { + xga->accel.bres_k2 = (xga->accel.bres_k2 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + xga->accel.bres_k2 |= ~0x3fff; + } + break; + + case 0x2c: + if (len == 4) { + xga->accel.short_stroke = val; + xga->accel.short_stroke_vector1 = xga->accel.short_stroke & 0xff; + xga->accel.short_stroke_vector2 = (xga->accel.short_stroke >> 8) & 0xff; + xga->accel.short_stroke_vector3 = (xga->accel.short_stroke >> 16) & 0xff; + xga->accel.short_stroke_vector4 = (xga->accel.short_stroke >> 24) & 0xff; + + //pclog("1Vector = %02x, 2Vector = %02x, 3Vector = %02x, 4Vector = %02x\n", xga->accel.short_stroke_vector1, xga->accel.short_stroke_vector2, xga->accel.short_stroke_vector3, xga->accel.short_stroke_vector4); + xga_short_stroke(svga, xga->accel.short_stroke_vector1); + xga_short_stroke(svga, xga->accel.short_stroke_vector2); + xga_short_stroke(svga, xga->accel.short_stroke_vector3); + xga_short_stroke(svga, xga->accel.short_stroke_vector4); + } else if (len == 2) + xga->accel.short_stroke = (xga->accel.short_stroke & 0xffff0000) | val; + else + xga->accel.short_stroke = (xga->accel.short_stroke & 0xffffff00) | val; + break; + case 0x2d: + if (len == 1) + xga->accel.short_stroke = (xga->accel.short_stroke & 0xffff00ff) | (val << 8); + break; + case 0x2e: + if (len == 2) { + xga->accel.short_stroke = (xga->accel.short_stroke & 0x0000ffff) | (val << 16); + } else + xga->accel.short_stroke = (xga->accel.short_stroke & 0xff00ffff) | (val << 16); + break; + case 0x2f: + if (len == 1) { + xga->accel.short_stroke = (xga->accel.short_stroke & 0x00ffffff) | (val << 24); + } + break; + + case 0x48: + xga->accel.frgd_mix = val & 0xff; + if (len == 4) { + xga->accel.bkgd_mix = (val >> 8) & 0xff; + xga->accel.cc_cond = (val >> 16) & 0x07; + } else if (len == 2) { + xga->accel.bkgd_mix = (val >> 8) & 0xff; + } + break; + + case 0x49: + xga->accel.bkgd_mix = val & 0xff; + break; + + case 0x4a: + xga->accel.cc_cond = val & 0x07; + break; + + case 0x4c: + if (len == 4) + xga->accel.color_cmp = val; + else if (len == 2) + xga->accel.color_cmp = (xga->accel.color_cmp & 0xffff0000) | val; + else + xga->accel.color_cmp = (xga->accel.color_cmp & 0xffffff00) | val; + break; + case 0x4d: + if (len == 1) + xga->accel.color_cmp = (xga->accel.color_cmp & 0xffff00ff) | (val << 8); + break; + case 0x4e: + if (len == 2) + xga->accel.color_cmp = (xga->accel.color_cmp & 0x0000ffff) | (val << 16); + else + xga->accel.color_cmp = (xga->accel.color_cmp & 0xff00ffff) | (val << 16); + break; + case 0x4f: + if (len == 1) + xga->accel.color_cmp = (xga->accel.color_cmp & 0x00ffffff) | (val << 24); + break; + + case 0x50: + if (len == 4) + xga->accel.plane_mask = val; + else if (len == 2) + xga->accel.plane_mask = (xga->accel.plane_mask & 0xffff0000) | val; + else + xga->accel.plane_mask = (xga->accel.plane_mask & 0xffffff00) | val; + break; + case 0x51: + if (len == 1) + xga->accel.plane_mask = (xga->accel.plane_mask & 0xffff00ff) | (val << 8); + break; + case 0x52: + if (len == 2) + xga->accel.plane_mask = (xga->accel.plane_mask & 0x0000ffff) | (val << 16); + else + xga->accel.plane_mask = (xga->accel.plane_mask & 0xff00ffff) | (val << 16); + break; + case 0x53: + if (len == 1) + xga->accel.plane_mask = (xga->accel.plane_mask & 0x00ffffff) | (val << 24); + break; + + case 0x58: + if (len == 4) + xga->accel.frgd_color = val; + else if (len == 2) + xga->accel.frgd_color = (xga->accel.frgd_color & 0xffff0000) | val; + else + xga->accel.frgd_color = (xga->accel.frgd_color & 0xffffff00) | val; + break; + case 0x59: + if (len == 1) + xga->accel.frgd_color = (xga->accel.frgd_color & 0xffff00ff) | (val << 8); + break; + case 0x5a: + if (len == 2) + xga->accel.frgd_color = (xga->accel.frgd_color & 0x0000ffff) | (val << 16); + else + xga->accel.frgd_color = (xga->accel.frgd_color & 0xff00ffff) | (val << 16); + break; + case 0x5b: + if (len == 1) + xga->accel.frgd_color = (xga->accel.frgd_color & 0x00ffffff) | (val << 24); + break; + + case 0x5c: + if (len == 4) + xga->accel.bkgd_color = val; + else if (len == 2) + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0xffff0000) | val; + else + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0xffffff00) | val; + break; + case 0x5d: + if (len == 1) + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0xffff00ff) | (val << 8); + break; + case 0x5e: + if (len == 2) + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0x0000ffff) | (val << 16); + else + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0xff00ffff) | (val << 16); + break; + case 0x5f: + if (len == 1) + xga->accel.bkgd_color = (xga->accel.bkgd_color & 0x00ffffff) | (val << 24); + break; + + case 0x60: + if (len == 4) { + xga->accel.blt_width = val & 0xffff; + xga->accel.blt_height = (val >> 16) & 0xffff; + } else if (len == 2) { + xga->accel.blt_width = val; + } else + xga->accel.blt_width = (xga->accel.blt_width & 0xff00) | val; + break; + case 0x61: + if (len == 1) + xga->accel.blt_width = (xga->accel.blt_width & 0xff) | (val << 8); + break; + + case 0x62: + if (len == 2) + xga->accel.blt_height = val; + else + xga->accel.blt_height = (xga->accel.blt_height & 0xff00) | val; + break; + case 0x63: + if (len == 1) + xga->accel.blt_height = (xga->accel.blt_height & 0xff) | (val << 8); + break; + + case 0x6c: + if (len == 4) { + xga->accel.mask_map_origin_x_off = val & 0xffff; + xga->accel.mask_map_origin_y_off = (val >> 16) & 0xffff; + } else if (len == 2) { + xga->accel.mask_map_origin_x_off = val; + } else + xga->accel.mask_map_origin_x_off = (xga->accel.mask_map_origin_x_off & 0xff00) | val; + break; + case 0x6d: + if (len == 1) + xga->accel.mask_map_origin_x_off = (xga->accel.mask_map_origin_x_off & 0xff) | (val << 8); + break; + + case 0x6e: + if (len == 2) + xga->accel.mask_map_origin_y_off = val; + else + xga->accel.mask_map_origin_y_off = (xga->accel.mask_map_origin_y_off & 0xff00) | val; + break; + case 0x6f: + if (len == 1) + xga->accel.mask_map_origin_y_off = (xga->accel.mask_map_origin_y_off & 0xff) | (val << 8); + break; + + case 0x70: + if (len == 4) { + xga->accel.src_map_x = val & 0xffff; + xga->accel.src_map_y = (val >> 16) & 0xffff; + } else if (len == 2) + xga->accel.src_map_x = val; + else + xga->accel.src_map_x = (xga->accel.src_map_x & 0xff00) | val; + break; + case 0x71: + if (len == 1) + xga->accel.src_map_x = (xga->accel.src_map_x & 0xff) | (val << 8); + break; + + case 0x72: + if (len == 2) + xga->accel.src_map_y = val; + else + xga->accel.src_map_y = (xga->accel.src_map_y & 0xff00) | val; + break; + case 0x73: + if (len == 1) + xga->accel.src_map_y = (xga->accel.src_map_y & 0xff) | (val << 8); + break; + + case 0x74: + if (len == 4) { + xga->accel.pat_map_x = val & 0xffff; + xga->accel.pat_map_y = (val >> 16) & 0xffff; + } else if (len == 2) + xga->accel.pat_map_x = val; + else + xga->accel.pat_map_x = (xga->accel.pat_map_x & 0xff00) | val; + break; + case 0x75: + if (len == 1) + xga->accel.pat_map_x = (xga->accel.pat_map_x & 0xff) | (val << 8); + break; + + case 0x76: + if (len == 2) + xga->accel.pat_map_y = val; + else + xga->accel.pat_map_y = (xga->accel.pat_map_y & 0xff00) | val; + break; + case 0x77: + if (len == 1) + xga->accel.pat_map_y = (xga->accel.pat_map_y & 0xff) | (val << 8); + break; + + case 0x78: + if (len == 4) { + xga->accel.dst_map_x = val & 0xffff; + xga->accel.dst_map_y = (val >> 16) & 0xffff; + } else if (len == 2) + xga->accel.dst_map_x = val; + else + xga->accel.dst_map_x = (xga->accel.dst_map_x & 0xff00) | val; + break; + case 0x79: + if (len == 1) + xga->accel.dst_map_x = (xga->accel.dst_map_x & 0xff) | (val << 8); + break; + + case 0x7a: + if (len == 2) + xga->accel.dst_map_y = val; + else + xga->accel.dst_map_y = (xga->accel.dst_map_y & 0xff00) | val; + break; + case 0x7b: + if (len == 1) + xga->accel.dst_map_y = (xga->accel.dst_map_y & 0xff) | (val << 8); + break; + + case 0x7c: + if (len == 4) { + xga->accel.command = val; +exec_command: + xga->accel.octant = xga->accel.command & 0x07; + xga->accel.draw_mode = xga->accel.command & 0x30; + xga->accel.mask_mode = xga->accel.command & 0xc0; + xga->accel.pat_src = ((xga->accel.command >> 12) & 0x0f); + xga->accel.dst_map = ((xga->accel.command >> 16) & 0x0f); + xga->accel.src_map = ((xga->accel.command >> 20) & 0x0f); + //pclog("Accel Command = %02x\n", ((xga->accel.command >> 24) & 0x0f)); + switch ((xga->accel.command >> 24) & 0x0f) { + case 3: /*Bresenham Line Draw Read*/ + //xga_line_draw_read(xga); + break; + case 4: /*Short Stroke Vectors*/ + break; + case 5: /*Bresenham Line Draw Write*/ + xga_line_draw_write(svga); + break; + case 8: /*BitBLT*/ + xga_bitblt(svga); + break; + case 9: /*Inverting BitBLT*/ + //xga_inverting_bitblt(xga); + break; + } + } else if (len == 2) { + xga->accel.command = (xga->accel.command & 0xffff0000) | val; + } else + xga->accel.command = (xga->accel.command & 0xffffff00) | val; + break; + case 0x7d: + if (len == 1) + xga->accel.command = (xga->accel.command & 0xffff00ff) | (val << 8); + break; + case 0x7e: + if (len == 2) { + xga->accel.command = (xga->accel.command & 0x0000ffff) | (val << 16); + goto exec_command; + } else + xga->accel.command = (xga->accel.command & 0xff00ffff) | (val << 16); + break; + case 0x7f: + if (len == 1) { + xga->accel.command = (xga->accel.command & 0x00ffffff) | (val << 24); + goto exec_command; + } + break; + } + } +} + +static void +xga_memio_writeb(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + xga_mem_write(addr, val, xga, svga, 1); + //pclog("Write MEMIOB = %04x, val = %02x\n", addr & 0x7f, val); +} + +static void +xga_memio_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + xga_mem_write(addr, val, xga, svga, 2); + //pclog("Write MEMIOW = %04x, val = %04x\n", addr & 0x7f, val); +} + +static void +xga_memio_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + xga_mem_write(addr, val, xga, svga, 4); + //pclog("Write MEMIOL = %04x, val = %08x\n", addr & 0x7f, val); +} + +static uint8_t +xga_mem_read(uint32_t addr, xga_t *xga, svga_t *svga) +{ + uint8_t temp; + + addr &= 0x1fff; + + if (addr < 0x1800) { + temp = xga->bios_rom.rom[addr]; + } else { + switch (addr & 0x7f) { + case 0x20: + temp = xga->accel.bres_err_term & 0xff; + break; + case 0x21: + temp = xga->accel.bres_err_term >> 8; + break; + case 0x22: + temp = xga->accel.bres_err_term >> 16; + break; + case 0x23: + temp = xga->accel.bres_err_term >> 24; + break; + + case 0x70: + temp = xga->accel.src_map_x & 0xff; + break; + case 0x71: + temp = xga->accel.src_map_x >> 8; + break; + + case 0x72: + temp = xga->accel.src_map_y & 0xff; + break; + case 0x73: + temp = xga->accel.src_map_y >> 8; + break; + + case 0x74: + temp = xga->accel.pat_map_x & 0xff; + break; + case 0x75: + temp = xga->accel.pat_map_x >> 8; + break; + + case 0x76: + temp = xga->accel.pat_map_y & 0xff; + break; + case 0x77: + temp = xga->accel.pat_map_y >> 8; + break; + + case 0x78: + temp = xga->accel.dst_map_x & 0xff; + break; + case 0x79: + temp = xga->accel.dst_map_x >> 8; + break; + + case 0x7a: + temp = xga->accel.dst_map_y & 0xff; + break; + case 0x7b: + temp = xga->accel.dst_map_y >> 8; + break; + } + } + + return temp; +} + +static uint8_t +xga_memio_readb(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint8_t temp; + + temp = xga_mem_read(addr, xga, svga); + + //pclog("[%04X:%08X]: Read MEMIOB = %04x, temp = %02x\n", CS, cpu_state.pc, addr, temp); + return temp; +} + +static uint16_t +xga_memio_readw(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint16_t temp; + + temp = xga_mem_read(addr, xga, svga); + temp |= (xga_mem_read(addr + 1, xga, svga) << 8); + + //pclog("[%04X:%08X]: Read MEMIOW = %04x, temp = %04x\n", CS, cpu_state.pc, addr, temp); + return temp; +} + +static uint32_t +xga_memio_readl(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint32_t temp; + + temp = xga_mem_read(addr, xga, svga); + temp |= (xga_mem_read(addr + 1, xga, svga) << 8); + temp |= (xga_mem_read(addr + 2, xga, svga) << 16); + temp |= (xga_mem_read(addr + 3, xga, svga) << 24); + + //pclog("Read MEMIOL = %04x, temp = %08x\n", addr, temp); + return temp; +} + +static void +xga_hwcursor_draw(svga_t *svga, int displine) +{ + xga_t *xga = &svga->xga; + uint8_t dat; + int offset = xga->hwcursor_latch.x - xga->hwcursor_latch.xoff; + int x, x_pos, y_pos; + int comb; + uint32_t *p; + uint8_t *cd; + int idx = (xga->cursor_data_on ? 32 : 0); + + if (xga->interlace && xga->hwcursor_oddeven) + xga->hwcursor_latch.addr += 16; + + cd = (uint8_t *) xga->sprite_data; + + y_pos = displine; + x_pos = offset + svga->x_add; + p = buffer32->line[y_pos]; + + for (x = 0; x < xga->hwcursor_latch.xsize; x++) { + if (x >= idx) { + if (!(x & 0x03)) + dat = xga->sprite_data[xga->hwcursor_latch.addr & 0x3ff]; + + comb = (dat >> ((x & 0x03) << 1)) & 0x03; + + x_pos = offset + svga->x_add + x; + + switch (comb) { + case 0x00: + /* Cursor Color 1 */ + p[x_pos] = xga->hwc_color0; + break; + case 0x01: + /* Cursor Color 2 */ + p[x_pos] = xga->hwc_color1; + break; + case 0x03: + /* Complement */ + p[x_pos] ^= 0xffffff; + break; + } + } + + if ((x & 0x03) == 0x03) + xga->hwcursor_latch.addr++; + } + + if (xga->interlace && !xga->hwcursor_oddeven) + xga->hwcursor_latch.addr += 16; +} + +static void +xga_render_overscan_left(xga_t *xga, svga_t *svga) +{ + int i; + + if ((xga->displine + svga->y_add) < 0) + return; + + if (svga->scrblank || (xga->h_disp == 0)) + return; + + for (i = 0; i < svga->x_add; i++) + buffer32->line[xga->displine + svga->y_add][i] = svga->overscan_color; +} + +static void +xga_render_overscan_right(xga_t *xga, svga_t *svga) +{ + int i, right; + + if ((xga->displine + svga->y_add) < 0) + return; + + if (svga->scrblank || (xga->h_disp == 0)) + return; + + right = (overscan_x >> 1); + for (i = 0; i < right; i++) + buffer32->line[xga->displine + svga->y_add][svga->x_add + xga->h_disp + i] = svga->overscan_color; +} + +static void +xga_render_8bpp(xga_t *xga, svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + + if ((xga->displine + svga->y_add) < 0) + return; + + if (xga->changedvram[xga->ma >> 12] || xga->changedvram[(xga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[xga->displine + svga->y_add][svga->x_add]; + + if (xga->firstline_draw == 2000) + xga->firstline_draw = xga->displine; + xga->lastline_draw = xga->displine; + + for (x = 0; x <= xga->h_disp; x += 8) { + dat = *(uint32_t *)(&xga->vram[xga->ma & xga->vram_mask]); + p[0] = svga->pallook[dat & 0xff]; + p[1] = svga->pallook[(dat >> 8) & 0xff]; + p[2] = svga->pallook[(dat >> 16) & 0xff]; + p[3] = svga->pallook[(dat >> 24) & 0xff]; + + dat = *(uint32_t *)(&xga->vram[(xga->ma + 4) & xga->vram_mask]); + p[4] = svga->pallook[dat & 0xff]; + p[5] = svga->pallook[(dat >> 8) & 0xff]; + p[6] = svga->pallook[(dat >> 16) & 0xff]; + p[7] = svga->pallook[(dat >> 24) & 0xff]; + + xga->ma += 8; + p += 8; + } + xga->ma &= xga->vram_mask; + } +} + +static void +xga_render_16bpp(xga_t *xga, svga_t *svga) +{ + int x; + uint32_t *p; + uint32_t dat; + uint32_t addr; + + if ((xga->displine + svga->y_add) < 0) + return; + + if (xga->changedvram[svga->ma >> 12] || xga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[xga->displine + svga->y_add][svga->x_add]; + + if (xga->firstline_draw == 2000) + xga->firstline_draw = xga->displine; + xga->lastline_draw = xga->displine; + + for (x = 0; x <= (xga->h_disp); x += 8) { + uint32_t dat = *(uint32_t *)(&xga->vram[(xga->ma + (x << 1)) & xga->vram_mask]); + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&xga->vram[(xga->ma + (x << 1) + 4) & xga->vram_mask]); + p[x + 2] = video_16to32[dat & 0xffff]; + p[x + 3] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&xga->vram[(xga->ma + (x << 1) + 8) & xga->vram_mask]); + p[x + 4] = video_16to32[dat & 0xffff]; + p[x + 5] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&xga->vram[(xga->ma + (x << 1) + 12) & xga->vram_mask]); + p[x + 6] = video_16to32[dat & 0xffff]; + p[x + 7] = video_16to32[dat >> 16]; + } + xga->ma += x << 1; + xga->ma &= xga->vram_mask; + } +} + +static void +xga_write(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) { + svga_write(addr, val, svga); + return; + } + + addr &= svga->banked_mask; + addr += xga->write_bank; + + cycles -= video_timing_write_b; + + xga->changedvram[(addr & xga->vram_mask) >> 12] = changeframecount; + xga->vram[addr & xga->vram_mask] = val; +} + +static void +xga_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + xga_write(addr, val, p); + xga_write(addr + 1, val >> 8, p); +} + +static void +xga_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + xga_write(addr, val, p); + xga_write(addr + 1, val >> 8, p); + xga_write(addr + 2, val >> 16, p); + xga_write(addr + 3, val >> 24, p); +} + +static void +xga_write_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) { + svga_write_linear(addr, val, svga); + return; + } + + addr &= svga->decode_mask; + + if (addr >= xga->vram_size) + return; + + cycles -= video_timing_write_b; + + xga->changedvram[(addr & xga->vram_mask) >> 12] = changeframecount; + xga->vram[addr & xga->vram_mask] = val; +} + +static void +xga_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) { + svga_writew_linear(addr, val, svga); + return; + } + + xga_write_linear(addr, val, p); + xga_write_linear(addr + 1, val >> 8, p); +} + +static void +xga_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) { + svga_writel_linear(addr, val, svga); + return; + } + + xga_write_linear(addr, val, p); + xga_write_linear(addr + 1, val >> 8, p); + xga_write_linear(addr + 2, val >> 16, p); + xga_write_linear(addr + 3, val >> 24, p); +} + +static uint8_t +xga_read(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) + return svga_read(addr, svga); + + addr &= svga->banked_mask; + addr += xga->read_bank; + + cycles -= video_timing_read_b; + + return xga->vram[addr & xga->vram_mask]; +} + +static uint16_t +xga_readw(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint16_t ret; + + ret = xga_read(addr, p); + ret |= (xga_read(addr + 1, p) << 8); + + return ret; +} + +static uint32_t +xga_readl(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + uint32_t ret; + + ret = xga_read(addr, p); + ret |= (xga_read(addr + 1, p) << 8); + ret |= (xga_read(addr + 2, p) << 16); + ret |= (xga_read(addr + 3, p) << 24); + + return ret; +} + +static uint8_t +xga_read_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) + return svga_read_linear(addr, svga); + + addr &= svga->decode_mask; + + if (addr >= xga->vram_size) + return 0xff; + + cycles -= video_timing_read_b; + + return xga->vram[addr & xga->vram_mask]; +} + +static uint16_t +xga_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) + return svga_readw_linear(addr, svga); + + return xga_read_linear(addr, p) | (xga_read_linear(addr + 1, p) << 8); +} + +static uint32_t +xga_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (!xga->on) + return svga_readl_linear(addr, svga); + + return xga_read_linear(addr, p) | (xga_read_linear(addr + 1, p) << 8) | + (xga_read_linear(addr + 2, p) << 16) | (xga_read_linear(addr + 3, p) << 24); +} + +static void +xga_do_render(svga_t *svga) +{ + xga_t *xga = &svga->xga; + + switch (xga->disp_cntl_2 & 7) { + case 3: + xga_render_8bpp(xga, svga); + break; + case 4: + xga_render_16bpp(xga, svga); + break; + } + + svga->x_add = (overscan_x >> 1); + xga_render_overscan_left(xga, svga); + xga_render_overscan_right(xga, svga); + svga->x_add = (overscan_x >> 1); + + if (xga->hwcursor_on) { + xga_hwcursor_draw(svga, xga->displine + svga->y_add); + xga->hwcursor_on--; + if (xga->hwcursor_on && xga->interlace) + xga->hwcursor_on--; + } +} + +static void +xga_doblit(int wx, int wy, svga_t *svga) +{ + int y_add, x_add, y_start, x_start, bottom; + uint32_t *p; + int i, j; + int xs_temp, ys_temp; + + y_add = (enable_overscan) ? overscan_y : 0; + x_add = (enable_overscan) ? overscan_x : 0; + y_start = (enable_overscan) ? 0 : (overscan_y >> 1); + x_start = (enable_overscan) ? 0 : (overscan_x >> 1); + bottom = (overscan_y >> 1); + + if ((wx <= 0) || (wy <= 0)) + return; + + xs_temp = wx; + ys_temp = wy + 1; + if (xs_temp < 64) + xs_temp = 640; + if (ys_temp < 32) + ys_temp = 200; + + if ((svga->crtc[0x17] & 0x80) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + /* Screen res has changed.. fix up, and let them know. */ + xsize = xs_temp; + ysize = ys_temp; + + if ((xsize > 1984) || (ysize > 2016)) { + /* 2048x2048 is the biggest safe render texture, to account for overscan, + we suppress overscan starting from x 1984 and y 2016. */ + x_add = 0; + y_add = 0; + suppress_overscan = 1; + } else + suppress_overscan = 0; + + /* Block resolution changes while in DPMS mode to avoid getting a bogus + screen width (320). We're already rendering a blank screen anyway. */ + set_screen_size(xsize + x_add, ysize + y_add); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if ((wx >= 160) && ((wy + 1) >= 120)) { + /* Draw (overscan_size - scroll size) lines of overscan on top and bottom. */ + for (i = 0; i < svga->y_add; i++) { + p = &buffer32->line[i & 0x7ff][0]; + + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga->overscan_color; + } + + for (i = 0; i < bottom; i++) { + p = &buffer32->line[(ysize + svga->y_add + i) & 0x7ff][0]; + + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga->overscan_color; + } + } + + video_blit_memtoscreen(x_start, y_start, xsize + x_add, ysize + y_add); +} + +void +xga_poll(xga_t *xga, svga_t *svga) +{ + uint32_t x; + int wx, wy; + + if (!xga->linepos) { + if (xga->displine == xga->hwcursor_latch.y && xga->hwcursor_latch.ena) { + xga->hwcursor_on = xga->hwcursor_latch.ysize - (xga->cursor_data_on ? 32 : 0); + xga->hwcursor_oddeven = 0; + } + + if (xga->displine == (xga->hwcursor_latch.y + 1) && xga->hwcursor_latch.ena && + xga->interlace) { + xga->hwcursor_on = xga->hwcursor_latch.ysize - (xga->cursor_data_on ? 33 : 1); + xga->hwcursor_oddeven = 1; + } + + timer_advance_u64(&svga->timer, svga->dispofftime); + xga->linepos = 1; + + if (xga->dispon) { + xga->h_disp_on = 1; + + xga->ma &= xga->vram_mask; + + if (xga->firstline == 2000) { + xga->firstline = xga->displine; + video_wait_for_buffer(); + } + + if (xga->hwcursor_on) { + xga->changedvram[xga->ma >> 12] = xga->changedvram[(xga->ma >> 12) + 1] = + xga->interlace ? 3 : 2; + } + + xga_do_render(svga); + + if (xga->lastline < xga->displine) + xga->lastline = xga->displine; + } + + xga->displine++; + if (xga->interlace) + xga->displine++; + if (xga->displine > 1500) + xga->displine = 0; + } else { + timer_advance_u64(&svga->timer, svga->dispontime); + xga->h_disp_on = 0; + + xga->linepos = 0; + if (xga->dispon) { + if (xga->sc == xga->rowcount) { + xga->sc = 0; + + xga->maback += (xga->rowoffset << 3); + if (xga->interlace) + xga->maback += (xga->rowoffset << 3); + xga->maback &= xga->vram_mask; + xga->ma = xga->maback; + } else { + xga->sc++; + xga->sc &= 0x1f; + xga->ma = xga->maback; + } + } + + xga->vc++; + xga->vc &= 2047; + + if (xga->vc == xga->split) { + if (xga->interlace && xga->oddeven) + xga->ma = xga->maback = (xga->rowoffset << 1); + else + xga->ma = xga->maback = 0; + xga->ma = (xga->ma << 2); + xga->maback = (xga->maback << 2); + + xga->sc = 0; + } + if (xga->vc == xga->dispend) { + xga->dispon = 0; + + for (x = 0; x < ((xga->vram_mask + 1) >> 12); x++) { + if (xga->changedvram[x]) + xga->changedvram[x]--; + } + if (svga->fullchange) + svga->fullchange--; + } + if (xga->vc == xga->v_syncstart) { + xga->dispon = 0; + x = xga->h_disp; + + if (xga->interlace && !xga->oddeven) + xga->lastline++; + if (xga->interlace && xga->oddeven) + xga->firstline--; + + wx = x; + + wy = xga->lastline - xga->firstline; + svga_doblit(wx, wy, svga); + + xga->firstline = 2000; + xga->lastline = 0; + + xga->firstline_draw = 2000; + xga->lastline_draw = 0; + + xga->oddeven ^= 1; + + changeframecount = xga->interlace ? 3 : 2; + + if (xga->interlace && xga->oddeven) + xga->ma = xga->maback = xga->ma_latch + (xga->rowoffset << 1); + else + xga->ma = xga->maback = xga->ma_latch; + + xga->ma = (xga->ma << 2); + xga->maback = (xga->maback << 2); + } + if (xga->vc == xga->v_total) { + xga->vc = 0; + xga->sc = 0; + xga->dispon = 1; + xga->displine = (xga->interlace && xga->oddeven) ? 1 : 0; + + svga->x_add = (overscan_x >> 1); + + xga->hwcursor_on = 0; + xga->hwcursor_latch = xga->hwcursor; + } + } +} + +static uint8_t +xga_mca_read(int port, void *priv) +{ + svga_t *svga = (svga_t *)priv; + xga_t *xga = &svga->xga; + + //pclog("[%04X:%08X]: POS Read Port = %x, val = %02x\n", CS, cpu_state.pc, port & 7, xga->pos_regs[port & 7]); + return (xga->pos_regs[port & 7]); +} + +static void +xga_mca_write(int port, uint8_t val, void *priv) +{ + svga_t *svga = (svga_t *)priv; + xga_t *xga = &svga->xga; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) + return; + + io_removehandler(0x2100 + (xga->instance << 4), 0x0010, xga_ext_inb, NULL, NULL, xga_ext_outb, NULL, NULL, svga); + mem_mapping_disable(&xga->bios_rom.mapping); + mem_mapping_disable(&xga->memio_mapping); + xga->on = 0; + vga_on = 1; + xga->op_mode_reset = 0; + + /* Save the MCA register value. */ + xga->pos_regs[port & 7] = val; + if (!(xga->pos_regs[4] & 1)) /*MCA 4MB addressing on systems with more than 16MB of memory*/ + xga->pos_regs[4] |= 1; + + //pclog("[%04X:%08X]: POS Write Port = %x, val = %02x, linear base = %08x, instance = %d, rom addr = %05x\n", CS, cpu_state.pc, port & 7, val, xga->linear_base, xga->instance, xga->rom_addr); + if (xga->pos_regs[2] & 1) { + xga->instance = (xga->pos_regs[2] & 0x0e) >> 1; + xga->base_addr_1mb = (xga->pos_regs[5] & 0x0f) << 20; + xga->linear_base = ((xga->pos_regs[4] & 0xfe) * 0x1000000) + (xga->instance << 22); + xga->rom_addr = 0xc0000 + (((xga->pos_regs[2] & 0xf0) >> 4) * 0x2000); + + io_sethandler(0x2100 + (xga->instance << 4), 0x0010, xga_ext_inb, NULL, NULL, xga_ext_outb, NULL, NULL, svga); + mem_mapping_set_addr(&xga->bios_rom.mapping, xga->rom_addr, 0x2000); + mem_mapping_set_addr(&xga->memio_mapping, xga->rom_addr + 0x1c00 + (xga->instance * 0x80), 0x80); + } +} + +static uint8_t +xga_mca_feedb(void *priv) +{ + svga_t *svga = (svga_t *)priv; + xga_t *xga = &svga->xga; + + return xga->pos_regs[2] & 1; +} + +static void +xga_pos_out(uint16_t addr, uint8_t val, void *priv) +{ + svga_t *svga = (svga_t *)priv; + xga_t *xga = &svga->xga; + + mem_mapping_disable(&svga->mapping); + if (val & 0x08) { + mem_mapping_enable(&svga->mapping); + xga_updatemapping(svga); + } +} + +static uint8_t +xga_pos_in(uint16_t addr, void *priv) +{ + svga_t *svga = (svga_t *)priv; + + return (xga_mca_read(addr, svga)); +} + +static void +*xga_init(const device_t *info) +{ + svga_t *svga = svga_get_pri(); + xga_t *xga = &svga->xga; + FILE *f; + uint32_t temp; + uint8_t *rom = NULL; + + xga->vram_size = (1024 << 10); + xga->vram_mask = xga->vram_size - 1; + xga->vram = calloc(xga->vram_size, 1); + xga->changedvram = calloc(xga->vram_size >> 12, 1); + xga->on = 0; + xga->hwcursor.xsize = 64; + xga->hwcursor.ysize = 64; + + f = rom_fopen(XGA_BIOS_PATH, "rb"); + (void)fseek(f, 0L, SEEK_END); + temp = ftell(f); + (void)fseek(f, 0L, SEEK_SET); + + rom = malloc(0x2000); + (void)fread(rom, 0x2000, 1, f); + temp -= 0x2000; + (void)fclose(f); + + xga->bios_rom.rom = rom; + xga->bios_rom.mask = 0x1fff; + if (f != NULL) { + free(rom); + } + + if (info->flags & DEVICE_MCA) { + xga->linear_base = 0; + xga->instance = 0; + xga->rom_addr = 0; + rom_init(&xga->bios_rom, XGA_BIOS_PATH, 0xdc000, 0x2000, xga->bios_rom.mask, 0, MEM_MAPPING_EXTERNAL); + } else { + xga->pos_regs[2] = 1 | 0x0c | 0xf0; + xga->instance = (xga->pos_regs[2] & 0x0e) >> 1; + xga->pos_regs[4] = 3; + xga->linear_base = ((xga->pos_regs[4] & 0xfe) * 0x1000000) + (xga->instance << 22); + xga->rom_addr = 0xc0000 + (((xga->pos_regs[2] & 0xf0) >> 4) * 0x2000); + } + xga->base_addr_1mb = 0; + + mem_mapping_add(&xga->video_mapping, 0, 0, xga_read, xga_readw, xga_readl, + xga_write, xga_writew, xga_writel, + NULL, MEM_MAPPING_EXTERNAL, svga); + mem_mapping_add(&xga->linear_mapping, 0, 0, xga_read_linear, xga_readw_linear, xga_readl_linear, + xga_write_linear, xga_writew_linear, xga_writel_linear, + NULL, MEM_MAPPING_EXTERNAL, svga); + mem_mapping_add(&xga->memio_mapping, 0, 0, xga_memio_readb, xga_memio_readw, xga_memio_readl, + xga_memio_writeb, xga_memio_writew, xga_memio_writel, + xga->bios_rom.rom, MEM_MAPPING_EXTERNAL, svga); + + mem_mapping_disable(&xga->video_mapping); + mem_mapping_disable(&xga->linear_mapping); + mem_mapping_disable(&xga->memio_mapping); + + xga->pos_regs[0] = 0xdb; + xga->pos_regs[1] = 0x8f; + + if (info->flags & DEVICE_MCA) { + mca_add(xga_mca_read, xga_mca_write, xga_mca_feedb, NULL, svga); + } else { + io_sethandler(0x0100, 0x0008, xga_pos_in, NULL, NULL, NULL, NULL, NULL, svga); + io_sethandler(0x2100 + (xga->instance << 4), 0x0010, xga_ext_inb, NULL, NULL, xga_ext_outb, NULL, NULL, svga); + mem_mapping_set_addr(&xga->memio_mapping, xga->rom_addr + 0x1c00 + (xga->instance * 0x80), 0x80); + } + + return svga; +} + +static void +xga_close(void *p) +{ + svga_t *svga = (svga_t *)p; + xga_t *xga = &svga->xga; + + if (svga) { + free(xga->vram); + free(xga->changedvram); + } +} + +static int +xga_available(void) +{ + return rom_present(XGA_BIOS_PATH); +} + +static void +xga_speed_changed(void *p) +{ + svga_t *svga = (svga_t *)p; + + svga_recalctimings(svga); +} + +static void +xga_force_redraw(void *p) +{ + svga_t *svga = (svga_t *)p; + + svga->fullchange = changeframecount; +} + +const device_t xga_device = { + .name = "XGA (MCA)", + .internal_name = "xga_mca", + .flags = DEVICE_MCA, + .local = 0, + .init = xga_init, + .close = xga_close, + .reset = NULL, + { .available = xga_available }, + .speed_changed = xga_speed_changed, + .force_redraw = xga_force_redraw, + .config = NULL +}; + +const device_t xga_isa_device = { + .name = "XGA (ISA)", + .internal_name = "xga_isa", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = xga_init, + .close = xga_close, + .reset = NULL, + { .available = xga_available }, + .speed_changed = xga_speed_changed, + .force_redraw = xga_force_redraw, + .config = NULL +}; + +void +xga_device_add(void) +{ + if (!xga_enabled) + return; + + if (machine_has_bus(machine, MACHINE_BUS_MCA)) + device_add(&xga_device); + else + device_add(&xga_isa_device); +} diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 028dc34a7..9d657989a 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -715,7 +715,8 @@ VIDOBJ := agpgart.o video.o \ vid_ibm_rgb528_ramdac.o vid_sdac_ramdac.o \ vid_ogc.o \ vid_nga.o \ - vid_tvp3026_ramdac.o + vid_tvp3026_ramdac.o \ + vid_xga.o VOODOOOBJ := vid_voodoo.o vid_voodoo_banshee.o \ vid_voodoo_banshee_blitter.o \ From 08efa5086cd0cfd0ce565ea648b500bd933a1786 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 17 Jun 2022 21:32:01 +0200 Subject: [PATCH 2/2] Forgot the relevant xga_enabled activation variables, fixed compile. --- src/86box.c | 1 + src/include/86box/86box.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/86box.c b/src/86box.c index 34cd3891c..148eb63f8 100644 --- a/src/86box.c +++ b/src/86box.c @@ -172,6 +172,7 @@ int GUS = 0; /* (C) sound option */ int SSI2001 = 0; /* (C) sound option */ int voodoo_enabled = 0; /* (C) video option */ int ibm8514_enabled = 0; /* (C) video option */ +int xga_enabled = 0; /* (C) video option */ uint32_t mem_size = 0; /* (C) memory size (Installed on system board)*/ uint32_t isa_mem_size = 0; /* (C) memory size (ISA Memory Cards) */ int cpu_use_dynarec = 0; /* (C) cpu uses/needs Dyna */ diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 61269fddb..c4ddaed4b 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -112,7 +112,8 @@ extern int sound_is_float, /* (C) sound uses FP values */ GUS, GUSMAX, /* (C) sound option */ SSI2001, /* (C) sound option */ voodoo_enabled, /* (C) video option */ - ibm8514_enabled; /* (C) video option */ + ibm8514_enabled, /* (C) video option */ + xga_enabled; /* (C) video option */ extern uint32_t mem_size; /* (C) memory size (Installed on system board) */ extern uint32_t isa_mem_size; /* (C) memory size (ISA Memory Cards) */ extern int cpu, /* (C) cpu type */