From cb06b9e78fc3c804bf8baa1eeeed095be18269fb Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 14 Jul 2023 23:38:04 +0200 Subject: [PATCH] Video features and fixes: Added the Mach8 and Mach32 ISA/VLB/PCI cards (initial implementation and MCA coming soon for the Mach32) and their corresponding EEPROM's. Added INMOS XGA ISA card and updated the SVGA core to reflect its mapping as well as the Mach8/32 mapping when in 8514 monitor mode. Mark the XGA button as already checked and locked when a standalone XGA BIOS card is present like the INMOS one. (QT only) Same concept as above, but applies to the Mach8 and 32 for the 8514 option as well. (QT only) --- src/include/86box/vid_8514a.h | 12 +- src/include/86box/vid_ati_eeprom.h | 1 + src/include/86box/vid_svga.h | 5 +- src/include/86box/vid_xga.h | 5 +- src/include/86box/vid_xga_device.h | 5 + src/include/86box/video.h | 15 +- src/qt/qt_settingsdisplay.cpp | 28 +- src/video/CMakeLists.txt | 2 +- src/video/vid_8514a.c | 594 ++- src/video/vid_ati_eeprom.c | 20 + src/video/vid_ati_mach8.c | 5568 ++++++++++++++++++++++++++++ src/video/vid_svga.c | 130 +- src/video/vid_table.c | 18 + src/video/vid_xga.c | 527 ++- src/win/Makefile.mingw | 1 + 15 files changed, 6648 insertions(+), 283 deletions(-) create mode 100644 src/video/vid_ati_mach8.c diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h index e6510e3f1..b21da9fba 100644 --- a/src/include/86box/vid_8514a.h +++ b/src/include/86box/vid_8514a.h @@ -24,6 +24,8 @@ typedef struct ibm8514_t { int force_old_addr; int type; + int local; + int bpp; uint32_t vram_size; uint32_t vram_mask; @@ -32,6 +34,7 @@ typedef struct ibm8514_t { uint8_t dac_mask, dac_status; uint32_t *map8; int dac_addr, dac_pos, dac_r, dac_g; + int internal_pitch; struct { uint16_t subsys_cntl; @@ -58,7 +61,7 @@ typedef struct ibm8514_t { uint8_t pix_trans[2]; int poly_draw; int ssv_state; - int x1, x2, y1, y2; + int16_t x1, x2, x3, y1, y2; int sys_cnt, sys_cnt2; int temp_cnt; int16_t cx, cy, oldcy; @@ -80,6 +83,7 @@ typedef struct ibm8514_t { uint16_t scratch; int fill_state, xdir, ydir; + uint32_t ge_offset; } accel; uint16_t test; @@ -90,7 +94,7 @@ typedef struct ibm8514_t { dispon, hdisp_on, linecountff, vc, linepos, oddeven, cursoron, blink, scrollcache, firstline, lastline, firstline_draw, lastline_draw, - displine, fullchange, x_add, y_add; + displine, fullchange; uint32_t ma, maback; uint8_t *vram, *changedvram, linedbl; @@ -103,11 +107,13 @@ typedef struct ibm8514_t { int disp_cntl, interlace; uint8_t subsys_cntl, subsys_stat; - volatile int force_busy, force_busy2; + atomic_int force_busy, force_busy2; int blitter_busy; uint64_t blitter_time; uint64_t status_time; int pitch; + int ext_pitch; + int ext_crt_pitch; } ibm8514_t; #endif /*VIDEO_8514A_H*/ diff --git a/src/include/86box/vid_ati_eeprom.h b/src/include/86box/vid_ati_eeprom.h index 1fa083eaa..7de5170d8 100644 --- a/src/include/86box/vid_ati_eeprom.h +++ b/src/include/86box/vid_ati_eeprom.h @@ -43,6 +43,7 @@ typedef struct ati_eeprom_t { } ati_eeprom_t; void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type); +void ati_eeprom_load_mach8(ati_eeprom_t *eeprom, char *fn); void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat); int ati_eeprom_read(ati_eeprom_t *eeprom); diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 93fb9f17c..f8dafdd20 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -31,8 +31,9 @@ # define FLAG_NOSKEW 16 # define FLAG_ADDR_BY16 32 # define FLAG_RAMDAC_SHIFT 64 -# define FLAG_128K_MASK 128 - +# define FLAG_ATI 128 +# define FLAG_S3_911_16BIT 256 +# define FLAG_512K_MASK 512 struct monitor_t; typedef struct { diff --git a/src/include/86box/vid_xga.h b/src/include/86box/vid_xga.h index 069718b9f..550ae7cd6 100644 --- a/src/include/86box/vid_xga.h +++ b/src/include/86box/vid_xga.h @@ -36,6 +36,7 @@ typedef struct xga_t { mem_mapping_t linear_mapping; mem_mapping_t video_mapping; rom_t bios_rom; + rom_t vga_bios_rom; xga_hwcursor_t hwcursor, hwcursor_latch; PALETTE extpal; @@ -57,7 +58,7 @@ typedef struct xga_t { uint8_t clk_sel_1, clk_sel_2; uint8_t hwc_control; uint8_t bus_arb; - uint8_t select_pos_isa; + uint8_t isa_pos_enable; uint8_t hwcursor_oddeven; uint8_t cfg_reg_instance; uint8_t rowcount; @@ -70,6 +71,8 @@ typedef struct xga_t { uint8_t sprite_data[1024]; uint8_t scrollcache; uint8_t direct_color; + uint8_t dma_channel; + uint8_t instance_isa, instance_num, ext_mem_addr; uint8_t *vram, *changedvram; int16_t hwc_pos_x; diff --git a/src/include/86box/vid_xga_device.h b/src/include/86box/vid_xga_device.h index a92c6d3c6..7aa274d30 100644 --- a/src/include/86box/vid_xga_device.h +++ b/src/include/86box/vid_xga_device.h @@ -17,6 +17,11 @@ #ifndef VIDEO_XGA_DEVICE_H #define VIDEO_XGA_DEVICE_H +extern int xga_has_vga; + +#ifdef EMU_DEVICE_H extern const device_t xga_device; extern const device_t xga_isa_device; +extern const device_t inmos_isa_device; +#endif #endif /*VIDEO_XGA_DEVICE_H*/ diff --git a/src/include/86box/video.h b/src/include/86box/video.h index fb7800685..b915fe35d 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -60,8 +60,10 @@ enum { #define VIDEO_FLAG_TYPE_CGA 0 #define VIDEO_FLAG_TYPE_MDA 1 #define VIDEO_FLAG_TYPE_SPECIAL 2 -#define VIDEO_FLAG_TYPE_NONE 3 -#define VIDEO_FLAG_TYPE_MASK 3 +#define VIDEO_FLAG_TYPE_8514 3 +#define VIDEO_FLAG_TYPE_XGA 4 +#define VIDEO_FLAG_TYPE_NONE 5 +#define VIDEO_FLAG_TYPE_MASK 7 typedef struct video_timings_t { int type; @@ -206,6 +208,7 @@ extern double cpuclock; extern int emu_fps; extern int frames; extern int readflash; +extern int ibm8514_has_vga; /* Function handler pointers. */ extern void (*video_recalctimings)(void); @@ -232,6 +235,8 @@ extern int video_card_get_flags(int card); extern int video_is_mda(void); extern int video_is_cga(void); extern int video_is_ega_vga(void); +extern int video_is_8514(void); +extern int video_is_xga(void); extern void video_inform_monitor(int type, const video_timings_t *ptr, int monitor_index); extern int video_get_type_monitor(int monitor_index); @@ -290,8 +295,12 @@ extern uint32_t video_color_transform(uint32_t color); /* IBM XGA */ extern void xga_device_add(void); -/* IBM 8514/A and generic clones*/ +/* IBM 8514/A and clones*/ extern void ibm8514_device_add(void); +extern const device_t mach8_isa_device; +extern const device_t mach32_isa_device; +extern const device_t mach32_vlb_device; +extern const device_t mach32_pci_device; /* ATi Mach64 */ extern const device_t mach64gx_isa_device; diff --git a/src/qt/qt_settingsdisplay.cpp b/src/qt/qt_settingsdisplay.cpp index e64dc74dd..5f2f81c58 100644 --- a/src/qt/qt_settingsdisplay.cpp +++ b/src/qt/qt_settingsdisplay.cpp @@ -36,7 +36,7 @@ SettingsDisplay::SettingsDisplay(QWidget *parent) { ui->setupUi(this); - videoCard[0] = gfxcard[0]; + videoCard[0] = gfxcard[0]; videoCard[1] = gfxcard[1]; onCurrentMachineChanged(machine); } @@ -102,6 +102,11 @@ SettingsDisplay::onCurrentMachineChanged(int machineId) ui->comboBoxVideoSecondary->setEnabled(true); ui->pushButtonConfigureSecondary->setEnabled(true); } + if (video_card_get_flags(gfxcard[0]) != VIDEO_FLAG_TYPE_8514) + ibm8514_has_vga = 0; + if (video_card_get_flags(gfxcard[0]) != VIDEO_FLAG_TYPE_XGA) + xga_has_vga = 0; + ui->comboBoxVideo->setCurrentIndex(selectedRow); if (gfxcard[1] == 0) ui->pushButtonConfigureSecondary->setEnabled(false); @@ -123,10 +128,12 @@ SettingsDisplay::on_pushButtonConfigureVoodoo_clicked() void SettingsDisplay::on_pushButtonConfigureXga_clicked() { - if (machine_has_bus(machineId, MACHINE_BUS_MCA) > 0) { - DeviceConfig::ConfigureDevice(&xga_device, 0, qobject_cast(Settings::settings)); - } else { - DeviceConfig::ConfigureDevice(&xga_isa_device, 0, qobject_cast(Settings::settings)); + if (!xga_has_vga) { + if (machine_has_bus(machineId, MACHINE_BUS_MCA) > 0) { + DeviceConfig::ConfigureDevice(&xga_device, 0, qobject_cast(Settings::settings)); + } else { + DeviceConfig::ConfigureDevice(&xga_isa_device, 0, qobject_cast(Settings::settings)); + } } } @@ -139,7 +146,6 @@ SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) auto curVideoCard_2 = videoCard[1]; videoCard[0] = ui->comboBoxVideo->currentData().toInt(); ui->pushButtonConfigure->setEnabled(video_card_has_config(videoCard[0]) > 0); - bool machineHasPci = machine_has_bus(machineId, MACHINE_BUS_PCI) > 0; ui->checkBoxVoodoo->setEnabled(machineHasPci); if (machineHasPci) { @@ -149,16 +155,16 @@ SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) bool hasIsa16 = machine_has_bus(machineId, MACHINE_BUS_ISA16) > 0; bool has_MCA = machine_has_bus(machineId, MACHINE_BUS_MCA) > 0; - ui->checkBox8514->setEnabled(hasIsa16 || has_MCA); + ui->checkBox8514->setEnabled((hasIsa16 || has_MCA) && !ibm8514_has_vga); if (hasIsa16 || has_MCA) { ui->checkBox8514->setChecked(ibm8514_enabled); } - ui->checkBoxXga->setEnabled(hasIsa16 || has_MCA); + ui->checkBoxXga->setEnabled((hasIsa16 || has_MCA) && !xga_has_vga); if (hasIsa16 || has_MCA) ui->checkBoxXga->setChecked(xga_enabled); - ui->pushButtonConfigureXga->setEnabled((hasIsa16 || has_MCA) && ui->checkBoxXga->isChecked()); + ui->pushButtonConfigureXga->setEnabled((hasIsa16 || has_MCA) && ui->checkBoxXga->isChecked() && !xga_has_vga); int c = 2; @@ -187,7 +193,7 @@ SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) c++; } - if (videoCard[1] == 0 || (machine_has_flags(machineId, MACHINE_VIDEO_ONLY) > 0)) { + if ((videoCard[1] == 0) || (machine_has_flags(machineId, MACHINE_VIDEO_ONLY) > 0)) { ui->comboBoxVideoSecondary->setCurrentIndex(0); ui->pushButtonConfigureSecondary->setEnabled(false); } @@ -202,7 +208,7 @@ SettingsDisplay::on_checkBoxVoodoo_stateChanged(int state) void SettingsDisplay::on_checkBoxXga_stateChanged(int state) { - ui->pushButtonConfigureXga->setEnabled(state == Qt::Checked); + ui->pushButtonConfigureXga->setEnabled((state == Qt::Checked) && !xga_has_vga); } void diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index b37e81134..3d3d2d466 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -18,7 +18,7 @@ add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c vid_incolor.c vid_colorplus.c vid_genius.c vid_pgc.c vid_im1024.c vid_sigma.c vid_wy700.c vid_ega.c vid_ega_render.c vid_svga.c vid_8514a.c vid_svga_render.c vid_ddc.c vid_vga.c vid_ati_eeprom.c vid_ati18800.c - vid_ati28800.c vid_ati_mach64.c vid_ati68860_ramdac.c vid_bt48x_ramdac.c + vid_ati28800.c vid_ati_mach8.c vid_ati_mach64.c vid_ati68860_ramdac.c vid_bt48x_ramdac.c vid_av9194.c vid_icd2061.c vid_ics2494.c vid_ics2595.c vid_cl54xx.c vid_et3000.c vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c vid_et4000w32.c vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 9ec196d86..115105d7a 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -7,13 +7,13 @@ * This file is part of the 86Box distribution. * * Emulation of the 8514/A card from IBM for the MCA bus and - * generic ISA bus clones without vendor extensions. + * ISA bus clones. * * * * Authors: TheCollector1995. * - * Copyright 2022 TheCollector1995. + * Copyright 2022-2023 TheCollector1995. */ #include #include @@ -21,6 +21,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> @@ -42,17 +43,53 @@ static void ibm8514_accel_outw(uint16_t port, uint16_t val, void *p); static uint8_t ibm8514_accel_inb(uint16_t port, void *p); static uint16_t ibm8514_accel_inw(uint16_t port, void *p); +#ifdef ENABLE_IBM8514_LOG +int ibm8514_do_log = ENABLE_IBM8514_LOG; + +static void +ibm8514_log(const char *fmt, ...) +{ + va_list ap; + + if (ibm8514_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define ibm8514_log(fmt, ...) +#endif + #define READ_PIXTRANS_WORD(cx, n) \ if ((cmd <= 1) || (cmd == 5)) { \ - temp = dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n)) & dev->vram_mask]; \ - temp |= (dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + if (dev->local) { \ + temp = svga->vram[((dev->accel.cy * dev->pitch) + (cx) + (n)) & svga->vram_mask]; \ + temp |= (svga->vram[((dev->accel.cy * dev->pitch) + (cx) + (n + 1)) & svga->vram_mask] << 8); \ + } else { \ + temp = dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + } \ } else { \ - temp = dev->vram[(dev->accel.dest + (cx) + (n)) & dev->vram_mask]; \ - temp |= (dev->vram[(dev->accel.dest + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + if (dev->local) { \ + temp = svga->vram[(dev->accel.dest + (cx) + (n)) & svga->vram_mask]; \ + temp |= (svga->vram[(dev->accel.dest + (cx) + (n + 1)) & svga->vram_mask] << 8); \ + } else { \ + temp = dev->vram[(dev->accel.dest + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[(dev->accel.dest + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + } \ } #define READ(addr, dat) \ - dat = dev->vram[(addr) & (dev->vram_mask)]; + if (dev->local) { \ + if ((svga->bpp == 15) || (svga->bpp == 16)) { \ + dat = vram_w[(addr) & (svga->vram_mask >> 1)]; \ + } else { \ + dat = (svga->vram[(addr) & (svga->vram_mask)]); \ + } \ + } else { \ + dat = (dev->vram[(addr) & (dev->vram_mask)]); \ + } #define MIX(mixmode, dest_dat, src_dat) \ { \ @@ -157,8 +194,20 @@ static uint16_t ibm8514_accel_inw(uint16_t port, void *p); } #define WRITE(addr, dat) \ - dev->vram[((addr)) & (dev->vram_mask)] = dat; \ - dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; + if (dev->local) { \ + if ((svga->bpp == 15) || (svga->bpp == 16)) { \ + vram_w[((addr)) & (svga->vram_mask >> 1)] = dat; \ + svga->changedvram[(((addr)) & (svga->vram_mask >> 1)) >> 11] = changeframecount; \ + } else { \ + svga->vram[((addr)) & (svga->vram_mask)] = dat; \ + svga->changedvram[(((addr)) & (svga->vram_mask)) >> 12] = changeframecount; \ + } \ + } else { \ + dev->vram[((addr)) & (dev->vram_mask)] = dat; \ + dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; \ + } + +int ibm8514_has_vga = 0; int ibm8514_cpu_src(svga_t *svga) @@ -557,10 +606,11 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) dev->accel.short_stroke = val; dev->accel.cx = dev->accel.cur_x; dev->accel.cy = dev->accel.cur_y; - if (dev->accel.cur_x & 0x400) - dev->accel.cx |= ~0x3ff; - if (dev->accel.cur_y & 0x400) - dev->accel.cy |= ~0x3ff; + if (dev->accel.cur_x >= 0x600) + dev->accel.cx |= ~0x5ff; + + if (dev->accel.cur_y >= 0x600) + dev->accel.cy |= ~0x5ff; if (dev->accel.cmd & 0x1000) { ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len); @@ -573,15 +623,16 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) break; case 0x9ee9: case 0xdee9: + dev->accel.ssv_state = 1; if (len == 1) { dev->accel.short_stroke = (dev->accel.short_stroke & 0xff) | (val << 8); dev->accel.cx = dev->accel.cur_x; dev->accel.cy = dev->accel.cur_y; - if (dev->accel.cur_x & 0x400) - dev->accel.cx |= ~0x3ff; - if (dev->accel.cur_y & 0x400) - dev->accel.cy |= ~0x3ff; + if (dev->accel.cur_x >= 0x600) + dev->accel.cx |= ~0x5ff; + if (dev->accel.cur_y >= 0x600) + dev->accel.cy |= ~0x5ff; if (dev->accel.cmd & 0x1000) { ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len); ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke >> 8, len); @@ -701,10 +752,14 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) dev->accel.multifunc_cntl = val; dev->accel.multifunc[dev->accel.multifunc_cntl >> 12] = dev->accel.multifunc_cntl & 0xfff; if ((dev->accel.multifunc_cntl >> 12) == 1) { - dev->accel.clip_top = val & 0x3ff; + dev->accel.clip_top = val & 0x7ff; + if (val & 0x400) + dev->accel.clip_top |= ~0x3ff; } if ((dev->accel.multifunc_cntl >> 12) == 2) { - dev->accel.clip_left = val & 0x3ff; + dev->accel.clip_left = val & 0x7ff; + if (val & 0x400) + dev->accel.clip_left |= ~0x3ff; } if (port == 0xfee8) dev->accel.cmd_back = 1; @@ -820,24 +875,24 @@ ibm8514_accel_out(uint16_t port, uint32_t val, svga_t *svga, int len) case 0x2e9: if (len != 1) { dev->htotal = (dev->htotal & 0xff) | (val << 8); - // pclog("IBM 8514/A: H_TOTAL write 02E8 = %d\n", dev->htotal + 1); + ibm8514_log("IBM 8514/A: H_TOTAL write 02E8 = %d\n", dev->htotal + 1); svga_recalctimings(svga); } break; case 0x6e8: dev->hdisp = val; - // pclog("IBM 8514/A: H_DISP write 06E8 = %d\n", dev->hdisp + 1); + ibm8514_log("IBM 8514/A: H_DISP write 06E8 = %d\n", dev->hdisp + 1); svga_recalctimings(svga); break; case 0xae8: - // pclog("IBM 8514/A: H_SYNC_STRT write 0AE8 = %d\n", val + 1); + ibm8514_log("IBM 8514/A: H_SYNC_STRT write 0AE8 = %d\n", val + 1); svga_recalctimings(svga); break; case 0xee8: - // pclog("IBM 8514/A: H_SYNC_WID write 0EE8 = %d\n", val + 1); + ibm8514_log("IBM 8514/A: H_SYNC_WID write 0EE8 = %d\n", val + 1); svga_recalctimings(svga); break; @@ -852,7 +907,7 @@ ibm8514_accel_out(uint16_t port, uint32_t val, svga_t *svga, int len) case 0x12e9: if (len == 1) { dev->vtotal = (dev->vtotal & 0xff) | ((val & 0x1f) << 8); - // pclog("IBM 8514/A: V_TOTAL write 12E8 = %d\n", dev->vtotal); + ibm8514_log("IBM 8514/A: V_TOTAL write 12E8 = %d\n", dev->vtotal); svga_recalctimings(svga); } break; @@ -868,7 +923,7 @@ ibm8514_accel_out(uint16_t port, uint32_t val, svga_t *svga, int len) case 0x16e9: if (len == 1) { dev->vdisp = (dev->vdisp & 0xff) | ((val & 0x1f) << 8); - // pclog("IBM 8514/A: V_DISP write 16E8 = %d\n", dev->vdisp); + ibm8514_log("IBM 8514/A: V_DISP write 16E8 = %d\n", dev->vdisp); svga_recalctimings(svga); } break; @@ -884,21 +939,21 @@ ibm8514_accel_out(uint16_t port, uint32_t val, svga_t *svga, int len) case 0x1ae9: if (len == 1) { dev->vsyncstart = (dev->vsyncstart & 0xff) | ((val & 0x1f) << 8); - // pclog("IBM 8514/A: V_SYNC_STRT write 1AE8 = %d\n", dev->vsyncstart); + ibm8514_log("IBM 8514/A: V_SYNC_STRT write 1AE8 = %d\n", dev->vsyncstart); svga_recalctimings(svga); } break; case 0x1ee8: dev->vsyncwidth = val; - // pclog("IBM 8514/A: V_SYNC_WID write 1EE8 = %02x\n", val); + ibm8514_log("IBM 8514/A: V_SYNC_WID write 1EE8 = %02x\n", val); svga_recalctimings(svga); break; case 0x22e8: dev->disp_cntl = val & 0x7e; dev->interlace = !!(val & 0x10); - // pclog("IBM 8514/A: DISP_CNTL write 22E8 = %02x, SCANMODULOS = %d\n", dev->disp_cntl, dev->scanmodulos); + ibm8514_log("IBM 8514/A: DISP_CNTL write 22E8 = %02x, SCANMODULOS = %d\n", dev->disp_cntl, dev->scanmodulos); svga_recalctimings(svga); break; @@ -922,7 +977,7 @@ ibm8514_accel_out(uint16_t port, uint32_t val, svga_t *svga, int len) dev->accel.advfunc_cntl = val & 7; ibm8514_on = (dev->accel.advfunc_cntl & 1); vga_on = !ibm8514_on; - //pclog("IBM 8514/A: VGA ON = %i, val = %02x\n", vga_on, val); + ibm8514_log("IBM 8514/A: VGA ON = %i, val = %02x\n", vga_on, val); svga_recalctimings(svga); break; } @@ -1105,26 +1160,33 @@ void ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, svga_t *svga, int len) { ibm8514_t *dev = &svga->dev8514; - uint8_t src_dat = 0; - uint8_t dest_dat; - uint8_t old_dest_dat; - int frgd_mix; - int bkgd_mix; - uint16_t clip_b = dev->accel.multifunc[3] & 0x7ff; - uint16_t clip_r = dev->accel.multifunc[4] & 0x7ff; + uint16_t *vram_w = (uint16_t *)svga->vram; + uint16_t src_dat = 0, dest_dat, old_dest_dat; + int frgd_mix, bkgd_mix; + uint16_t clip_b = dev->accel.multifunc[3]; + uint16_t clip_r = dev->accel.multifunc[4]; int pixcntl = (dev->accel.multifunc[0x0a] >> 6) & 3; - uint8_t mix_mask = 0x80; - uint8_t compare = dev->accel.color_cmp & 0xff; + uint16_t mix_mask = ((svga->bpp == 8) || (svga->bpp == 24)) ? 0x80 : 0x8000; + uint16_t compare = dev->accel.color_cmp; int compare_mode = dev->accel.multifunc[0x0a] & 0x38; int cmd = dev->accel.cmd >> 13; - uint8_t wrt_mask = dev->accel.wrt_mask & 0xff; - uint8_t rd_mask = ((dev->accel.rd_mask & 0x01) << 7) | ((dev->accel.rd_mask & 0xfe) >> 1); - uint8_t rd_mask_polygon = dev->accel.rd_mask & 0xff; - uint8_t frgd_color = dev->accel.frgd_color; - uint8_t bkgd_color = dev->accel.bkgd_color; + uint16_t wrt_mask = dev->accel.wrt_mask; + uint16_t rd_mask = dev->accel.rd_mask; + uint16_t rd_mask_polygon = dev->accel.rd_mask; + uint16_t frgd_color = dev->accel.frgd_color; + uint16_t bkgd_color = dev->accel.bkgd_color; uint32_t old_mix_dat; int and3 = dev->accel.cur_x & 3; - uint8_t poly_src = 0; + uint16_t poly_src = 0; + + if ((svga->bpp == 8) || (svga->bpp == 24)) { + compare &= 0xff; + frgd_color &= 0xff; + bkgd_color &= 0xff; + rd_mask = ((dev->accel.rd_mask & 0x01) << 7) | ((dev->accel.rd_mask & 0xfe) >> 1); + rd_mask &= 0xff; + rd_mask_polygon &= 0xff; + } if (dev->accel.cmd & 0x100) { dev->force_busy = 1; @@ -1147,6 +1209,11 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } else { count >>= 3; } + + if (((svga->bpp == 15) || (svga->bpp == 16))) { + if ((dev->accel.cmd & 0x200) && (count == 2)) + count >>= 1; + } } if (pixcntl == 1) { @@ -1246,7 +1313,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: src_dat = 0; @@ -1255,17 +1322,26 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); if ((compare_mode == 0) || ((compare_mode == 0x10) && (dest_dat >= compare)) || ((compare_mode == 0x18) && (dest_dat < compare)) || ((compare_mode == 0x20) && (dest_dat != compare)) || ((compare_mode == 0x28) && (dest_dat == compare)) || ((compare_mode == 0x30) && (dest_dat <= compare)) || ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); if (dev->accel.ssv_draw) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + if ((dev->accel.cmd & 4) && dev->accel.ssv_len) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } } } } mix_dat <<= 1; mix_dat |= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (!dev->accel.ssv_len) break; @@ -1303,10 +1379,116 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.ssv_len--; } + } else { + while (count-- && (dev->accel.ssv_len >= 0)) { + if ((dev->accel.cx >= dev->accel.clip_left && dev->accel.cx <= clip_r && dev->accel.cy >= dev->accel.clip_top && dev->accel.cy <= clip_b)) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + src_dat = 0; + break; + } - dev->accel.cur_x = dev->accel.cx; - dev->accel.cur_y = dev->accel.cy; + READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || ((compare_mode == 0x10) && (dest_dat >= compare)) || ((compare_mode == 0x18) && (dest_dat < compare)) || ((compare_mode == 0x20) && (dest_dat != compare)) || ((compare_mode == 0x28) && (dest_dat == compare)) || ((compare_mode == 0x30) && (dest_dat <= compare)) || ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + + if (dev->accel.ssv_draw) { + if ((dev->accel.cmd & 4) && dev->accel.ssv_len) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 4)) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } + } + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; + + if (!dev->accel.ssv_len) + break; + + if (dev->accel.err_term >= dev->accel.maj_axis_pcnt) { + dev->accel.err_term += dev->accel.destx_distp; + /*Step minor axis*/ + switch (dev->accel.cmd & 0xe0) { + case 0x00: + dev->accel.cy--; + break; + case 0x20: + dev->accel.cy--; + break; + case 0x40: + dev->accel.cx--; + break; + case 0x60: + dev->accel.cx++; + break; + case 0x80: + dev->accel.cy++; + break; + case 0xa0: + dev->accel.cy++; + break; + case 0xc0: + dev->accel.cx--; + break; + case 0xe0: + dev->accel.cx++; + break; + } + } else + dev->accel.err_term += dev->accel.desty_axstp; + + /*Step major axis*/ + switch (dev->accel.cmd & 0xe0) { + case 0x00: + dev->accel.cx--; + break; + case 0x20: + dev->accel.cx++; + break; + case 0x40: + dev->accel.cy--; + break; + case 0x60: + dev->accel.cy--; + break; + case 0x80: + dev->accel.cx--; + break; + case 0xa0: + dev->accel.cx++; + break; + case 0xc0: + dev->accel.cy++; + break; + case 0xe0: + dev->accel.cy++; + break; + } + + dev->accel.ssv_len--; + } } + dev->accel.cur_x = dev->accel.cx; + dev->accel.cur_y = dev->accel.cy; break; case 1: /*Draw line*/ @@ -1315,11 +1497,11 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.cx = dev->accel.cur_x; dev->accel.cy = dev->accel.cur_y; - if (dev->accel.cur_x & 0x400) { - dev->accel.cx |= ~0x3ff; + if (dev->accel.cur_x >= 0x600) { + dev->accel.cx |= ~0x5ff; } - if (dev->accel.cur_y & 0x400) { - dev->accel.cy |= ~0x3ff; + if (dev->accel.cur_y >= 0x600) { + dev->accel.cy |= ~0x5ff; } dev->accel.sy = dev->accel.maj_axis_pcnt; @@ -1392,7 +1574,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: src_dat = 0; @@ -1477,7 +1659,10 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat mix_dat <<= 1; mix_dat |= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (dev->accel.sy == 0) { break; @@ -1538,7 +1723,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: src_dat = 0; @@ -1561,7 +1746,10 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.temp_cnt--; mix_dat >>= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (dev->accel.sy == 0) { break; @@ -1654,7 +1842,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: src_dat = 0; @@ -1677,7 +1865,10 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat mix_dat <<= 1; mix_dat |= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (dev->accel.sy == 0) { break; @@ -1767,14 +1958,18 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; dev->accel.sy = dev->accel.multifunc[0] & 0x7ff; - dev->accel.cx = dev->accel.cur_x & 0x3ff; - if (dev->accel.cur_x & 0x400) - dev->accel.cx |= ~0x3ff; - dev->accel.cy = dev->accel.cur_y & 0x3ff; - if (dev->accel.cur_y & 0x400) - dev->accel.cy |= ~0x3ff; + dev->accel.cx = dev->accel.cur_x; + if (dev->accel.cur_x >= 0x600) + dev->accel.cx |= ~0x5ff; + dev->accel.cy = dev->accel.cur_y; + if (dev->accel.cur_y >= 0x600) + dev->accel.cy |= ~0x5ff; - dev->accel.dest = dev->accel.cy * dev->pitch; + if (dev->local && dev->accel.ge_offset && (svga->bpp == 24)) + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + else + dev->accel.dest = dev->accel.cy * dev->pitch; + dev->accel.fill_state = 0; if (cmd == 4) @@ -1822,7 +2017,10 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (!(dev->accel.cmd & 0x40) && (frgd_mix == 2) && (bkgd_mix == 2) && (pixcntl == 0) && (cmd == 2)) { if (!(dev->accel.sx & 1)) { dev->accel.output = 1; - dev->accel.newdest_out = (dev->accel.cy + 1) * dev->pitch; + if (dev->local && dev->accel.ge_offset && (svga->bpp == 24)) + dev->accel.newdest_out = (dev->accel.ge_offset << 2) + ((dev->accel.cy + 1) * dev->pitch); + else + dev->accel.newdest_out = (dev->accel.cy + 1) * dev->pitch; } } } @@ -1864,7 +2062,7 @@ rect_fill_pix: src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: src_dat = 0; @@ -1939,7 +2137,10 @@ rect_fill_pix: mix_dat <<= 1; mix_dat |= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; switch (dev->accel.cmd & 0xe0) { case 0x00: @@ -2033,7 +2234,7 @@ rect_fill_pix: src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: src_dat = 0; @@ -2052,7 +2253,10 @@ rect_fill_pix: mix_dat <<= 1; mix_dat |= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (dev->accel.cmd & 0x20) dev->accel.cx++; @@ -2077,7 +2281,11 @@ rect_fill_pix: else dev->accel.cy--; - dev->accel.dest = dev->accel.cy * dev->pitch; + if (dev->local && dev->accel.ge_offset && (svga->bpp == 24)) + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + else + dev->accel.dest = dev->accel.cy * dev->pitch; + dev->accel.sy--; return; } @@ -2107,7 +2315,7 @@ rect_fill_pix: src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: src_dat = 0; @@ -2125,7 +2333,10 @@ rect_fill_pix: } } mix_dat >>= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (dev->accel.cmd & 0x20) dev->accel.cx++; @@ -2148,9 +2359,9 @@ rect_fill_pix: if (dev->accel.cmd & 2) { if (dev->accel.cmd & 0x1000) { - dev->accel.cx = dev->accel.cur_x & 0x3ff; - if (dev->accel.cur_x & 0x400) - dev->accel.cx |= ~0x3ff; + dev->accel.cx = dev->accel.cur_x; + if (dev->accel.cur_x >= 0x600) + dev->accel.cx |= ~0x5ff; } } @@ -2159,7 +2370,11 @@ rect_fill_pix: else dev->accel.cy--; - dev->accel.dest = dev->accel.cy * dev->pitch; + if (dev->local && dev->accel.ge_offset && (svga->bpp == 24)) + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + else + dev->accel.dest = dev->accel.cy * dev->pitch; + dev->accel.sy--; return; } @@ -2262,7 +2477,10 @@ rect_fill_pix: } mix_dat <<= 1; mix_dat |= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (dev->accel.cmd & 0x20) dev->accel.cx++; @@ -2333,7 +2551,7 @@ rect_fill_pix: src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: src_dat = 0; @@ -2358,7 +2576,10 @@ rect_fill_pix: mix_dat <<= 1; mix_dat |= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (dev->accel.cmd & 0x20) dev->accel.cx++; @@ -2671,8 +2892,12 @@ rect_fill: if (!cpu_input) { dev->accel.cx = dev->accel.cur_x; dev->accel.cy = dev->accel.cur_y; - dev->accel.oldcy = dev->accel.cy; + if (dev->accel.cur_x >= 0x600) + dev->accel.cx |= ~0x5ff; + if (dev->accel.cur_y >= 0x600) + dev->accel.cy |= ~0x5ff; + dev->accel.oldcy = dev->accel.cy; dev->accel.sy = 0; if (ibm8514_cpu_src(svga)) { @@ -2687,9 +2912,6 @@ rect_fill: } while (count-- && (dev->accel.sy >= 0)) { - if (dev->accel.cur_x > 1023) - dev->accel.cx = 0; - if ((dev->accel.cx) >= dev->accel.clip_left && ((dev->accel.cx) <= clip_r) && (dev->accel.cy) >= dev->accel.clip_top && (dev->accel.cy) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: @@ -2699,7 +2921,7 @@ rect_fill: src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: src_dat = 0; @@ -2726,7 +2948,10 @@ rect_fill: mix_dat <<= 1; mix_dat |= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (dev->accel.sy == dev->accel.maj_axis_pcnt) { break; @@ -2813,21 +3038,21 @@ rect_fill: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; dev->accel.sy = dev->accel.multifunc[0] & 0x7ff; - dev->accel.dx = dev->accel.destx_distp & 0x3ff; - dev->accel.dy = dev->accel.desty_axstp & 0x3ff; + dev->accel.dx = dev->accel.destx_distp; + dev->accel.dy = dev->accel.desty_axstp; - if (dev->accel.destx_distp & 0x400) - dev->accel.dx |= ~0x3ff; - if (dev->accel.desty_axstp & 0x400) - dev->accel.dy |= ~0x3ff; + if (dev->accel.destx_distp >= 0x600) + dev->accel.dx |= ~0x5ff; + if (dev->accel.desty_axstp >= 0x600) + dev->accel.dy |= ~0x5ff; - dev->accel.cx = dev->accel.cur_x & 0x3ff; - dev->accel.cy = dev->accel.cur_y & 0x3ff; + dev->accel.cx = dev->accel.cur_x; + dev->accel.cy = dev->accel.cur_y; - if (dev->accel.cur_x & 0x400) - dev->accel.cx |= ~0x3ff; - if (dev->accel.cur_y & 0x400) - dev->accel.cy |= ~0x3ff; + if (dev->accel.cur_x >= 0x600) + dev->accel.cx |= ~0x5ff; + if (dev->accel.cur_y >= 0x600) + dev->accel.cy |= ~0x5ff; dev->accel.src = dev->accel.cy * dev->pitch; dev->accel.dest = dev->accel.dy * dev->pitch; @@ -2876,7 +3101,7 @@ bitblt_pix: src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: READ(dev->accel.src + dev->accel.cx, src_dat); @@ -2900,12 +3125,18 @@ bitblt_pix: mix_dat <<= 1; mix_dat |= 1; - cpu_dat >>= 8; - - if (dev->accel.cmd & 0x20) - dev->accel.cx++; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; else + cpu_dat >>= 8; + + if (dev->accel.cmd & 0x20) { + dev->accel.dx++; + dev->accel.cx++; + } else { + dev->accel.dx--; dev->accel.cx--; + } dev->accel.sx--; if (dev->accel.sx < 0) { @@ -2916,16 +3147,23 @@ bitblt_pix: } if (dev->accel.cmd & 0x20) { + dev->accel.dx -= (dev->accel.sx) + 1; dev->accel.cx -= (dev->accel.sx) + 1; - } else + } else { + dev->accel.dx += (dev->accel.sx) + 1; dev->accel.cx += (dev->accel.sx) + 1; + } - if (dev->accel.cmd & 0x80) + if (dev->accel.cmd & 0x80) { + dev->accel.dy++; dev->accel.cy++; - else + } else { + dev->accel.dy--; dev->accel.cy--; + } - dev->accel.dest = dev->accel.cy * dev->pitch; + dev->accel.src = dev->accel.cy * dev->pitch; + dev->accel.dest = dev->accel.dy * dev->pitch; dev->accel.sy--; return; } @@ -2952,7 +3190,7 @@ bitblt_pix: src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: READ(dev->accel.src + dev->accel.cx, src_dat); @@ -2974,7 +3212,10 @@ bitblt_pix: } } mix_dat >>= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (dev->accel.cmd & 0x20) { dev->accel.dx++; @@ -3003,12 +3244,12 @@ bitblt_pix: if (dev->accel.cmd & 2) { if (dev->accel.cmd & 0x1000) { - dev->accel.cx = dev->accel.cur_x & 0x3ff; - if (dev->accel.cur_x & 0x400) - dev->accel.cx |= ~0x3ff; - dev->accel.dx = dev->accel.destx_distp & 0x3ff; - if (dev->accel.destx_distp & 0x400) - dev->accel.dx |= ~0x3ff; + dev->accel.cx = dev->accel.cur_x; + if (dev->accel.cur_x >= 0x600) + dev->accel.cx |= ~0x5ff; + dev->accel.dx = dev->accel.destx_distp; + if (dev->accel.destx_distp >= 0x600) + dev->accel.dx |= ~0x5ff; } } @@ -3056,7 +3297,7 @@ bitblt_pix: src_dat = frgd_color; break; case 2: - src_dat = cpu_dat & 0xff; + src_dat = cpu_dat; break; case 3: READ(dev->accel.src + dev->accel.cx, src_dat); @@ -3079,7 +3320,10 @@ bitblt_pix: } mix_dat <<= 1; mix_dat |= 1; - cpu_dat >>= 8; + if ((svga->bpp == 15) || (svga->bpp == 16)) + cpu_dat >>= 16; + else + cpu_dat >>= 8; if (dev->accel.cmd & 0x20) { dev->accel.dx++; @@ -3123,7 +3367,7 @@ bitblt: count = dev->accel.maj_axis_pcnt + 1; dev->accel.temp_cnt = 8; while (count-- && dev->accel.sy >= 0) { - if (dev->accel.temp_cnt == 0) { + if (!dev->accel.temp_cnt) { mix_dat >>= 8; dev->accel.temp_cnt = 8; } @@ -3197,7 +3441,7 @@ bitblt: } else { dev->accel.temp_cnt = 8; while (count-- && dev->accel.sy >= 0) { - if (dev->accel.temp_cnt == 0) { + if (!dev->accel.temp_cnt) { dev->accel.temp_cnt = 8; mix_dat = old_mix_dat; } @@ -3269,6 +3513,32 @@ bitblt: } } } else { + if ((svga->bpp == 24) && dev->local && (dev->accel.cmd == 0xc2b5)) { + int64_t x, cx, dx; + + cx = (int64_t)dev->accel.cx; + dx = (int64_t)dev->accel.dx; + + while (1) { + if (((dx) >= (((int64_t)dev->accel.clip_left) * 3) && (dx) <= (((uint64_t)clip_r) * 3) && dev->accel.dy >= (dev->accel.clip_top << 1) && dev->accel.dy <= (clip_b << 1))) { + READ(dev->accel.src + (dev->accel.ge_offset << 2) + cx, src_dat); + READ(dev->accel.dest + (dev->accel.ge_offset << 2) + dx, dest_dat); + + dest_dat = (src_dat & wrt_mask) | (dest_dat & ~wrt_mask); + + WRITE(dev->accel.dest + (dev->accel.ge_offset << 2) + dx, dest_dat); + } + + cx++; + dx++; + + dev->accel.sx--; + if (dev->accel.sx < 0) + return; + } + return; + } + while (count-- && dev->accel.sy >= 0) { if (dev->accel.dx >= dev->accel.clip_left && dev->accel.dx <= clip_r && dev->accel.dy >= dev->accel.clip_top && dev->accel.dy <= clip_b) { if (pixcntl == 3) { @@ -3309,7 +3579,13 @@ bitblt: MIX(mix_dat & mix_mask, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + if (dev->accel.cmd & 4) { + if (dev->accel.sx > 0) { + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } + } else { + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } } } mix_dat <<= 1; @@ -3547,7 +3823,7 @@ ibm8514_recalctimings(svga_t *svga) if (ibm8514_on) { dev->h_disp = (dev->hdisp + 1) << 3; - dev->pitch = dev->h_disp; + dev->pitch = (dev->accel.advfunc_cntl & 4) ? 1024 : 640; dev->h_total = (dev->htotal + 1); dev->v_total = (dev->vtotal + 1); dev->v_syncstart = (dev->vsyncstart + 1); @@ -3555,46 +3831,9 @@ ibm8514_recalctimings(svga_t *svga) dev->dispend = ((dev->vdisp >> 1) + 1); if (dev->dispend == 766) dev->dispend = 768; - //pclog("HDISP = %d, VTOTAL = %d, DISPEND = %d, hires = %02x\n", dev->h_disp, dev->v_total, dev->dispend, dev->accel.advfunc_cntl & 4); - { -#if 0 - if (dev->dispend == 480) { - dev->h_disp = 640; - dev->rowoffset = 128; - dev->pitch = 1024; - } else if ((dev->dispend == 600) || (dev->dispend == 598)) { - dev->h_disp = 800; - dev->rowoffset = 128; - dev->dispend = 600; - dev->pitch = 1024; - if (!dev->vtotal) - dev->v_total = 816; - if (!dev->vsyncstart) - dev->v_syncstart = dev->dispend; - } else { - if (dev->accel.advfunc_cntl & 4) { - if (!dev->hdisp) { - dev->rowoffset = 128; - dev->h_disp = 1024; - dev->pitch = dev->h_disp; - } - if (!dev->vtotal) - dev->v_total = 816; - if (!dev->vsyncstart) - dev->v_syncstart = dev->dispend; - } else { - dev->rowoffset = 128; - dev->h_disp = 640; - dev->dispend = 480; - dev->pitch = 1024; - if (!dev->vtotal) - dev->v_total = 816; - if (!dev->vsyncstart) - dev->v_syncstart = dev->dispend; - } - } -#endif - } + + if (dev->dispend == 598) + dev->dispend = 600; if (dev->accel.advfunc_cntl & 4) { if (!vga_on && dev->ibm_mode) { @@ -3617,15 +3856,21 @@ ibm8514_recalctimings(svga_t *svga) dev->v_syncstart >>= 1; dev->v_total >>= 1; } - dev->rowoffset = 0x80; - dev->pitch = 1024; - // pclog("1024x768 clock mode, hdisp = %d, htotal = %d, vtotal = %d, vsyncstart = %d, interlace = %02x\n", dev->h_disp, dev->h_total, dev->v_total, dev->v_syncstart, dev->interlace); + if (ibm8514_has_vga) { + dev->pitch = dev->ext_pitch; + dev->rowoffset = dev->ext_crt_pitch; + } else + dev->rowoffset = 128; + + ibm8514_log("1024x768 clock mode, hdisp = %d, htotal = %d, vtotal = %d, vsyncstart = %d, interlace = %02x\n", dev->h_disp, dev->h_total, dev->v_total, dev->v_syncstart, dev->interlace); svga->clock = (cpuclock * (double) (1ULL << 32)) / 44900000.0; } else { if (!vga_on && dev->ibm_mode) { - dev->h_disp = 640; - dev->dispend = 480; + if (dev->h_disp == 1024) { + dev->h_disp = 640; + dev->dispend = 480; + } } if (dev->interlace) { @@ -3636,15 +3881,19 @@ ibm8514_recalctimings(svga_t *svga) dev->v_syncstart >>= 1; dev->v_total >>= 1; } - dev->rowoffset = 0x80; - dev->pitch = 1024; + + if (ibm8514_has_vga) { + dev->pitch = dev->ext_pitch; + dev->rowoffset = dev->ext_crt_pitch; + } else + dev->rowoffset = 128; svga->clock = (cpuclock * (double) (1ULL << 32)) / 25175000.0; } svga->render = ibm8514_render_8bpp; - //pclog("Pitch = %d, mode = %d.\n", dev->pitch, dev->ibm_mode); + ibm8514_log("BPP=%d, Pitch = %d, rowoffset = %d, crtc13 = %02x, mode = %d, highres bit = %02x, has_vga? = %d.\n", dev->bpp, dev->pitch, dev->rowoffset, svga->crtc[0x13], dev->ibm_mode, dev->accel.advfunc_cntl & 4, ibm8514_has_vga); } - // pclog("8514 enabled, hdisp=%d, vtotal=%d, htotal=%d, dispend=%d, rowoffset=%d, split=%d, vsyncstart=%d, split=%08x\n", dev->hdisp, dev->vtotal, dev->htotal, dev->dispend, dev->rowoffset, dev->split, dev->vsyncstart, dev->split); + ibm8514_log("8514 enabled, hdisp=%d, vtotal=%d, htotal=%d, dispend=%d, rowoffset=%d, split=%d, vsyncstart=%d, split=%08x\n", dev->hdisp, dev->vtotal, dev->htotal, dev->dispend, dev->rowoffset, dev->split, dev->vsyncstart, dev->split); } static uint8_t @@ -3697,6 +3946,7 @@ static void dev->type = info->flags; dev->ibm_mode = 1; + dev->bpp = 8; ibm8514_io_set(svga); @@ -3770,7 +4020,7 @@ const device_t ibm8514_mca_device = { void ibm8514_device_add(void) { - if (!ibm8514_enabled) + if (!ibm8514_enabled || (ibm8514_enabled && ibm8514_has_vga)) return; if (machine_has_bus(machine, MACHINE_BUS_MCA)) diff --git a/src/video/vid_ati_eeprom.c b/src/video/vid_ati_eeprom.c index 2e10216e4..10b37212d 100644 --- a/src/video/vid_ati_eeprom.c +++ b/src/video/vid_ati_eeprom.c @@ -45,6 +45,26 @@ ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type) fclose(f); } +void +ati_eeprom_load_mach8(ati_eeprom_t *eeprom, char *fn) +{ + FILE *f; + int size; + eeprom->type = 0; + strncpy(eeprom->fn, fn, sizeof(eeprom->fn) - 1); + f = nvr_fopen(eeprom->fn, "rb"); + size = 128; + if (!f) { /*The ATI Graphics Ultra bios expects an immediate write to nvram if none is present at boot time otherwise + it would hang the machine.*/ + memset(eeprom->data, 0, size); + f = nvr_fopen(eeprom->fn, "wb"); + fwrite(eeprom->data, 1, size, f); + } + if (fread(eeprom->data, 1, size, f) != size) + memset(eeprom->data, 0, size); + fclose(f); +} + void ati_eeprom_save(ati_eeprom_t *eeprom) { diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c new file mode 100644 index 000000000..c8996e0eb --- /dev/null +++ b/src/video/vid_ati_mach8.c @@ -0,0 +1,5568 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the 8514/A-compatible Mach8 and Mach32 graphics + * chips from ATI for the ISA/VLB/MCA/PCI buses. + * + * + * + * Authors: TheCollector1995. + * + * Copyright 2022-2023 TheCollector1995. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/mca.h> +#include <86box/pci.h> +#include <86box/rom.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> +#include <86box/vid_ati_eeprom.h> + +#define BIOS_MACH8_ROM_PATH "roms/video/mach8/BIOS.BIN" +#define BIOS_MACH32_ISA_ROM_PATH "roms/video/mach32/MACH32ISA.VBI" +#define BIOS_MACH32_VLB_ROM_PATH "roms/video/mach32/MACH32VLB.VBI" +#define BIOS_MACH32_PCI_ROM_PATH "roms/video/mach32/MACH32PCI.BIN" + +typedef struct mach_t { + ati_eeprom_t eeprom; + svga_t svga; + + rom_t bios_rom; + mem_mapping_t mmio_linear_mapping; + + int mca_bus; + int pci_bus; + int vlb_bus; + uint8_t regs[256]; + uint8_t pci_regs[256]; + uint8_t int_line; + int card; + int index; + + uint32_t memory; + + uint16_t config1; + uint16_t config2; + + uint8_t pos_regs[8]; + uint8_t cursor_col_0, cursor_col_1; + uint8_t ext_cur_col_0_r, ext_cur_col_1_r; + uint8_t ext_cur_col_0_g, ext_cur_col_1_g; + uint16_t cursor_offset_lo, cursor_offset_hi; + uint16_t cursor_x, cursor_y; + uint16_t misc; + uint16_t memory_aperture; + uint16_t local_cntl; + uint32_t linear_base; + uint8_t ap_size; + uint8_t bank_w, bank_r; + + struct { + uint8_t line_idx; + int16_t line_array[6]; + uint8_t patt_idx; + uint8_t patt_len; + uint8_t pix_trans[2]; + uint8_t eeprom_control; + uint16_t dest_x_end; + uint16_t dest_x_start; + uint16_t dest_y_end; + uint16_t src_x_end; + uint16_t src_x_start; + uint16_t src_x, src_y; + int16_t bres_count; + uint16_t clock_sel; + uint16_t crt_offset_lo; + uint16_t crt_offset_hi; + uint16_t dest_cmp_fn; + uint16_t dp_config; + uint16_t ext_ge_config; + uint16_t ge_offset_lo; + uint16_t ge_offset_hi; + uint16_t linedraw_opt; + uint16_t max_waitstates; + uint8_t patt_data_idx; + uint8_t patt_data[0x18]; + uint16_t scan_to_x; + uint16_t scratch0; + uint16_t scratch1; + uint16_t test; + uint16_t pattern; + uint8_t test2[2], test3[2]; + int src_y_dir; + int cmd_type; + int block_write_mono_pattern_enable; + int mono_pattern_enable; + int16_t cx_end_line, cy_end_line; + int16_t cx, cx_end, cy_end, dx, dx_end, dy_end; + int16_t dx_start, dy_start; + int16_t cy, sx_start, sx_end; + int16_t sx, x_count, xx_count, xxx_count; + int16_t sy, y_count; + int16_t err; + int16_t width, src_width; + int16_t height; + int poly_src, temp_cnt; + int stepx, stepy, src_stepx; + uint8_t color_pattern[16]; + uint8_t color_pattern_full[32]; + uint16_t color_pattern_word[8]; + int mono_pattern[8][8]; + uint32_t ge_offset; + uint32_t crt_offset; + uint32_t patt_len_reg; + int poly_fill; + uint16_t dst_clr_cmp_mask; + int clip_overrun; + int color_pattern_idx; + } accel; + + atomic_int force_busy, force_busy2; +} mach_t; + +static video_timings_t timing_gfxultra_isa = { .type = VIDEO_ISA, .write_b = 3, .write_w = 3, .write_l = 6, .read_b = 5, .read_w = 5, .read_l = 10 }; +static video_timings_t timing_mach32_vlb = { .type = VIDEO_BUS, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; +static video_timings_t timing_mach32_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; + + +static void mach_accel_outb(uint16_t port, uint8_t val, void *p); +static void mach_accel_outw(uint16_t port, uint16_t val, void *p); +static uint8_t mach_accel_inb(uint16_t port, void *p); +static uint16_t mach_accel_inw(uint16_t port, void *p); + +static void mach32_updatemapping(mach_t *mach); + +#ifdef ENABLE_MACH_LOG +int mach_do_log = ENABLE_MACH_LOG; + +static void +mach_log(const char *fmt, ...) +{ + va_list ap; + + if (mach_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define mach_log(fmt, ...) +#endif + +#define READ_PIXTRANS_BYTE_IO(cx, n, vgacore) \ + if ((mach->accel.cmd_type == 2) || (mach->accel.cmd_type == 5)) { \ + if (vgacore) { \ + if ((svga->bpp == 15) || (svga->bpp == 16)) \ + if (n == 0) \ + mach->accel.pix_trans[(n)] = vram_w[(dev->accel.dest + (cx) + (n)) & (svga->vram_mask >> 1)] & 0xff; \ + else \ + mach->accel.pix_trans[(n)] = vram_w[(dev->accel.dest + (cx) + (n)) & (svga->vram_mask >> 1)] >> 8; \ + else \ + mach->accel.pix_trans[(n)] = svga->vram[(dev->accel.dest + (cx) + (n)) & svga->vram_mask]; \ + } else \ + mach->accel.pix_trans[(n)] = dev->vram[(dev->accel.dest + (cx) + (n)) & dev->vram_mask]; \ + } + +#define READ_PIXTRANS_WORD(cx, n, vgacore) \ + if ((cmd == 0) || (cmd == 1) || (cmd == 5) || (mach->accel.cmd_type == -1)) { \ + if (vgacore) { \ + if ((svga->bpp == 15) || (svga->bpp == 16)) { \ + temp = vram_w[((dev->accel.cy * dev->pitch) + (cx) + (n)) & (svga->vram_mask >> 1)]; \ + } else { \ + temp = svga->vram[((dev->accel.cy * dev->pitch) + (cx) + (n)) & svga->vram_mask]; \ + temp |= (svga->vram[((dev->accel.cy * dev->pitch) + (cx) + (n + 1)) & svga->vram_mask] << 8); \ + } \ + } else { \ + temp = dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + } \ + } else if ((mach->accel.cmd_type == 2) || (mach->accel.cmd_type == 5)) { \ + if ((svga->bpp == 8) || (svga->bpp == 24)) { \ + if (vgacore) { \ + temp = svga->vram[((dev->accel.dest) + (cx) + (n)) & svga->vram_mask]; \ + temp |= (svga->vram[((dev->accel.dest) + (cx) + (n + 1)) & svga->vram_mask] << 8); \ + } else { \ + temp = dev->vram[((dev->accel.dest) + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[((dev->accel.dest) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + } \ + } else if ((svga->bpp == 15) || (svga->bpp == 16)) { \ + temp = vram_w[((dev->accel.dest) + (cx) + (n)) & (svga->vram_mask >> 1)]; \ + } \ + } else if ((mach->accel.cmd_type == 3) || (mach->accel.cmd_type == 4)) { \ + if ((svga->bpp == 8) || (svga->bpp == 24)) { \ + if (vgacore) { \ + temp = svga->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & svga->vram_mask]; \ + temp |= (svga->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n + 1)) & svga->vram_mask] << 8); \ + } else { \ + temp = dev->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + } \ + } else if ((svga->bpp == 15) || (svga->bpp == 16)) { \ + temp = vram_w[((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & (svga->vram_mask >> 1)]; \ + } \ + } + +#define READ(addr, dat, vgacore) \ + if ((svga->bpp == 8) || (svga->bpp == 24)) \ + dat = vgacore ? (svga->vram[(addr) & (svga->vram_mask)]) : (dev->vram[(addr) & (dev->vram_mask)]); \ + else if ((svga->bpp == 15) || (svga->bpp == 16)) \ + dat = vram_w[(addr) & (svga->vram_mask >> 1)]; + +#define MIX(mixmode, dest_dat, src_dat) \ + { \ + switch ((mixmode) ? (dev->accel.frgd_mix & 0x1f) : (dev->accel.bkgd_mix & 0x1f)) { \ + case 0x00: \ + dest_dat = ~dest_dat; \ + break; \ + case 0x01: \ + dest_dat = 0; \ + break; \ + case 0x02: \ + dest_dat = ~0; \ + break; \ + case 0x03: \ + dest_dat = dest_dat; \ + break; \ + case 0x04: \ + dest_dat = ~src_dat; \ + break; \ + case 0x05: \ + dest_dat = src_dat ^ dest_dat; \ + break; \ + case 0x06: \ + dest_dat = ~(src_dat ^ dest_dat); \ + break; \ + case 0x07: \ + dest_dat = src_dat; \ + break; \ + case 0x08: \ + dest_dat = ~(src_dat & dest_dat); \ + break; \ + case 0x09: \ + dest_dat = ~src_dat | dest_dat; \ + break; \ + case 0x0a: \ + dest_dat = src_dat | ~dest_dat; \ + break; \ + case 0x0b: \ + dest_dat = src_dat | dest_dat; \ + break; \ + case 0x0c: \ + dest_dat = src_dat & dest_dat; \ + break; \ + case 0x0d: \ + dest_dat = src_dat & ~dest_dat; \ + break; \ + case 0x0e: \ + dest_dat = ~src_dat & dest_dat; \ + break; \ + case 0x0f: \ + dest_dat = ~(src_dat | dest_dat); \ + break; \ + case 0x10: \ + dest_dat = MIN(src_dat, dest_dat); \ + break; \ + case 0x11: \ + dest_dat = dest_dat - src_dat; \ + break; \ + case 0x12: \ + dest_dat = src_dat - dest_dat; \ + break; \ + case 0x13: \ + dest_dat = src_dat + dest_dat; \ + break; \ + case 0x14: \ + dest_dat = MAX(src_dat, dest_dat); \ + break; \ + case 0x15: \ + dest_dat = (dest_dat - src_dat) / 2; \ + break; \ + case 0x16: \ + dest_dat = (src_dat - dest_dat) / 2; \ + break; \ + case 0x17: \ + dest_dat = (dest_dat + src_dat) / 2; \ + break; \ + case 0x18: \ + dest_dat = MAX(0, (dest_dat - src_dat)); \ + break; \ + case 0x19: \ + dest_dat = MAX(0, (dest_dat - src_dat)); \ + break; \ + case 0x1a: \ + dest_dat = MAX(0, (src_dat - dest_dat)); \ + break; \ + case 0x1b: \ + dest_dat = MIN(0xff, (dest_dat + src_dat)); \ + break; \ + case 0x1c: \ + dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ + break; \ + case 0x1d: \ + dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ + break; \ + case 0x1e: \ + dest_dat = MAX(0, (src_dat - dest_dat)) / 2; \ + break; \ + case 0x1f: \ + dest_dat = (0xff < (src_dat + dest_dat)) ? 0xff : ((src_dat + dest_dat) / 2); \ + break; \ + } \ + } + + +#define WRITE(addr, dat, vgacore) \ + if ((svga->bpp == 8) || (svga->bpp == 24)) { \ + if (vgacore) { \ + svga->vram[((addr)) & (svga->vram_mask)] = dat; \ + svga->changedvram[(((addr)) & (svga->vram_mask)) >> 12] = changeframecount; \ + } else { \ + dev->vram[((addr)) & (dev->vram_mask)] = dat; \ + dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; \ + } \ + } else if ((svga->bpp == 15) || (svga->bpp == 16)) { \ + vram_w[((addr)) & (svga->vram_mask >> 1)] = dat; \ + svga->changedvram[(((addr)) & (svga->vram_mask >> 1)) >> 11] = changeframecount; \ + } + + +static int +mach_pixel_write(mach_t *mach) +{ + if (mach->accel.dp_config & 1) + return 1; + + return 0; +} + +static int +mach_pixel_read(mach_t *mach) +{ + if (mach->accel.dp_config & 1) + return 0; + + return 1; +} + +static void +mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint32_t cpu_dat, mach_t *mach, ibm8514_t *dev, int len) +{ + svga_t *svga = &mach->svga; + int compare_mode; + int poly_src = 0; + uint16_t rd_mask = dev->accel.rd_mask; + uint16_t wrt_mask = dev->accel.wrt_mask; + uint16_t dest_cmp_clr = dev->accel.color_cmp; + int frgd_sel, bkgd_sel, mono_src; + int compare = 0; + uint16_t src_dat = 0, dest_dat; + uint16_t old_dest_dat; + uint16_t *vram_w = (uint16_t *) svga->vram; + uint16_t mix = 0; + int16_t clip_l = dev->accel.clip_left & 0x7ff; + int16_t clip_t = dev->accel.clip_top & 0x7ff; + int16_t clip_r = dev->accel.multifunc[4] & 0x7ff; + int16_t clip_b = dev->accel.multifunc[3] & 0x7ff; + uint32_t mono_dat0 = 0, mono_dat1 = 0; + + if ((svga->bpp == 8) || (svga->bpp == 24)) { + rd_mask &= 0xff; + dest_cmp_clr &= 0xff; + } + + compare_mode = (mach->accel.dest_cmp_fn >> 3) & 7; + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; + + mach->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); + + if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { + mach->force_busy = 1; + mach->force_busy2 = 1; + dev->force_busy = 1; + dev->force_busy2 = 1; + } + + if (cpu_input) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + if ((mach->accel.dp_config & 0x200) && (count == 2)) { + count >>= 1; + } + } + } + + if ((svga->bpp == 8) || (svga->bpp == 15) || (svga->bpp == 16) || (svga->bpp == 24)) { + if (svga->bpp == 24) + mach_log("24BPP: CMDType=%d, cwh(%d,%d,%d,%d), dpconfig=%04x\n", cmd_type, clip_l, clip_r, clip_t, clip_b, mach->accel.dp_config); + else + mach_log("BPP=%d, CMDType = %d, offs=%08x, DPCONFIG = %04x, cnt = %d, input = %d, mono_src = %d, frgdsel = %d, dstx = %d, dstxend = %d, pitch = %d, extcrt = %d, rw = %x, monpattern = %x.\n", svga->bpp, cmd_type, mach->accel.ge_offset, mach->accel.dp_config, count, cpu_input, mono_src, frgd_sel, dev->accel.cur_x, mach->accel.dest_x_end, dev->ext_pitch, dev->ext_crt_pitch, mach->accel.dp_config & 1, mach->accel.mono_pattern_enable); + } + + switch (cmd_type) { + case 1: /*Extended Raw Linedraw from bres_count register (0x96ee)*/ + if (!cpu_input) { + dev->accel.dx = dev->accel.cur_x; + if (dev->accel.cur_x >= 0x600) + dev->accel.dx |= ~0x5ff; + dev->accel.dy = dev->accel.cur_y; + if (dev->accel.cur_y >= 0x600) + dev->accel.dy |= ~0x5ff; + + dev->accel.cx = dev->accel.destx_distp; + if (dev->accel.destx_distp >= 0x600) + dev->accel.cx |= ~0x5ff; + dev->accel.cy = dev->accel.desty_axstp; + if (dev->accel.desty_axstp >= 0x600) + dev->accel.cy |= ~0x5ff; + + mach->accel.width = mach->accel.bres_count; + dev->accel.sx = 0; + mach->accel.poly_fill = 0; + + mach->accel.color_pattern_idx = ((dev->accel.cx + (dev->accel.cy << 3)) & mach->accel.patt_len); + + mach->accel.stepx = (mach->accel.linedraw_opt & 0x20) ? 1 : -1; + mach->accel.stepy = (mach->accel.linedraw_opt & 0x80) ? 1 : -1; + + mach_log("Extended bresenham, CUR(%d,%d), DEST(%d,%d), width = %d, options = %04x, dpconfig = %04x, opt_ena = %03x.\n", dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, mach->accel.width, mach->accel.linedraw_opt, mach->accel.dp_config, mach->accel.max_waitstates & 0x100); + + if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { + if (mach_pixel_write(mach)) { + dev->data_available = 0; + dev->data_available2 = 0; + return; + } else if (mach_pixel_read(mach)) { + dev->data_available = 1; + dev->data_available2 = 1; + return; + } + } + } + + if (frgd_sel == 5) { + for (int x = 0; x <= mach->accel.patt_len; x++) { + mach->accel.color_pattern[x] = mach->accel.patt_data[x & mach->accel.patt_len]; + } + + /*The destination coordinates should match the pattern index.*/ + if (mach->accel.color_pattern_idx != mach->accel.patt_idx) + mach->accel.color_pattern_idx = mach->accel.patt_idx; + } + + if (mono_src == 1) { + count = mach->accel.width; + mix_dat = mach->accel.patt_data[0x10]; + dev->accel.temp_cnt = 8; + } + + if (mach->accel.linedraw_opt & 0x08) { /*Vector Line*/ + while (count--) { + switch (mono_src) { + case 0: + mix = 1; + break; + case 1: + if (dev->accel.temp_cnt == 0) { + dev->accel.temp_cnt = 8; + mix_dat >>= 8; + } + mix = (mix_dat & 0x80); + dev->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + break; + case 2: + if (mach->accel.dp_config & 0x1000) { + mix = mix_dat >> 0x1f; + mix_dat <<= 1; + } else { + if (mach->accel.dp_config & 0x200) { + mix = mix_dat & 1; + mix_dat >>= 1; + } else { + mix = mix_dat & 0x80; + mix_dat <<= 1; + mix_dat |= 1; + } + } + break; + case 3: + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix, dev->local); + } + mix = (mix & rd_mask) == rd_mask; + break; + } + + if ((((dev->accel.dx) >= clip_l) && ((dev->accel.dx) <= clip_r) && ((dev->accel.dy) >= clip_t) && ((dev->accel.dy) <= clip_b))) { + if (mach->accel.linedraw_opt & 0x02) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src, dev->local); + } + poly_src = ((poly_src & rd_mask) == rd_mask); + if (poly_src) + mach->accel.poly_fill = !mach->accel.poly_fill; + } + + if (!mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = dev->accel.bkgd_color; + break; + case 1: + src_dat = dev->accel.frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + if (mach_pixel_read(mach)) + src_dat = cpu_dat; + else { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix, dev->local); + } + if (mono_src == 3) { + src_dat = (src_dat & rd_mask) == rd_mask; + } + } + break; + case 5: + if (mix) { + src_dat = mach->accel.color_pattern[((dev->accel.dx) + ((dev->accel.dy) << 3)) & mach->accel.patt_len]; + } else + src_dat = 0; + break; + } + + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } + } + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = ((dest_dat) >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = ((dest_dat) < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = ((dest_dat) != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = ((dest_dat) == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = ((dest_dat) <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = ((dest_dat) > dest_cmp_clr) ? 0 : 1; + break; + } + + if (!compare) { + if (mach_pixel_write(mach)) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + } + } + + if (mach->accel.dp_config & 0x10) { + if (mach->accel.linedraw_opt & 0x04) { + if (dev->accel.sx < mach->accel.width) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } else { + WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } + } + } else { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } else { + WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } + } + } + } + + if ((mono_src == 1) && !count) + break; + else if ((mono_src != 1) && (dev->accel.sx >= mach->accel.width)) + break; + + if (svga->bpp == 8) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + + switch (mach->accel.linedraw_opt & 0xe0) { + case 0x00: + dev->accel.cx++; + dev->accel.dx++; + break; + case 0x20: + dev->accel.cx++; + dev->accel.dx++; + dev->accel.cy--; + dev->accel.dy--; + break; + case 0x40: + dev->accel.cy--; + dev->accel.dy--; + break; + case 0x60: + dev->accel.cx--; + dev->accel.dx--; + dev->accel.cy--; + dev->accel.dy--; + break; + case 0x80: + dev->accel.cx--; + dev->accel.dx--; + break; + case 0xa0: + dev->accel.cx--; + dev->accel.dx--; + dev->accel.cy++; + dev->accel.dy++; + break; + case 0xc0: + dev->accel.cy++; + dev->accel.dy++; + break; + case 0xe0: + dev->accel.cx++; + dev->accel.dx++; + dev->accel.cy++; + dev->accel.dy++; + break; + } + + dev->accel.sx++; + } + } else { /*Bresenham*/ + while (count--) { + switch (mono_src) { + case 0: + mix = 1; + break; + case 1: + if (dev->accel.temp_cnt == 0) { + dev->accel.temp_cnt = 8; + mix_dat >>= 8; + } + mix = (mix_dat & 0x80); + dev->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + break; + case 2: + if (mach->accel.dp_config & 0x1000) { + mix = mix_dat >> 0x1f; + mix_dat <<= 1; + } else { + if (mach->accel.dp_config & 0x200) { + mix = mix_dat & 1; + mix_dat >>= 1; + } else { + mix = mix_dat & 0x80; + mix_dat <<= 1; + mix_dat |= 1; + } + } + break; + case 3: + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix, dev->local); + } + mix = (mix & rd_mask) == rd_mask; + break; + } + + if ((((dev->accel.dx) >= clip_l) && ((dev->accel.dx) <= clip_r) && ((dev->accel.dy) >= clip_t) && ((dev->accel.dy) <= clip_b))) { + if (mach->accel.linedraw_opt & 0x02) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src, dev->local); + } + poly_src = ((poly_src & rd_mask) == rd_mask); + if (poly_src) + mach->accel.poly_fill = !mach->accel.poly_fill; + } + + if (!mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = dev->accel.bkgd_color; + break; + case 1: + src_dat = dev->accel.frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + if (mach_pixel_read(mach)) + src_dat = cpu_dat; + else { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix, dev->local); + } + if (mono_src == 3) { + src_dat = (src_dat & rd_mask) == rd_mask; + } + } + break; + case 5: + if (mix) { + src_dat = mach->accel.color_pattern[((dev->accel.dx) + ((dev->accel.dy) << 3)) & mach->accel.patt_len]; + } else + src_dat = 0; + break; + } + + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } + } + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = ((dest_dat) >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = ((dest_dat) < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = ((dest_dat) != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = ((dest_dat) == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = ((dest_dat) <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = ((dest_dat) > dest_cmp_clr) ? 0 : 1; + break; + } + + if (!compare) { + if (mach_pixel_write(mach)) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + } + } + + if (mach->accel.dp_config & 0x10) { + if (mach->accel.linedraw_opt & 0x04) { + if (dev->accel.sx < mach->accel.width) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } else { + WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } + } + } else { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } else { + WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat, dev->local); + } + } + } + } + + if ((mono_src == 1) && !count) + break; + else if ((mono_src != 1) && (dev->accel.sx >= mach->accel.width)) + break; + + if (svga->bpp == 8) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + + if (mach->accel.linedraw_opt & 0x40) { + dev->accel.dy += mach->accel.stepy; + if ((frgd_sel == 3) || (bkgd_sel == 3)) + dev->accel.cy += mach->accel.stepy; + + if (dev->accel.err_term >= 0) { + dev->accel.err_term += dev->accel.destx_distp; + dev->accel.dx += mach->accel.stepx; + if ((frgd_sel == 3) || (bkgd_sel == 3)) + dev->accel.cx += mach->accel.stepx; + } else { + dev->accel.err_term += dev->accel.desty_axstp; + } + } else { + dev->accel.dx += mach->accel.stepx; + if ((frgd_sel == 3) || (bkgd_sel == 3)) + dev->accel.cx += mach->accel.stepx; + + if (dev->accel.err_term >= 0) { + dev->accel.err_term += dev->accel.destx_distp; + dev->accel.dy += mach->accel.stepy; + if ((frgd_sel == 3) || (bkgd_sel == 3)) + dev->accel.cy += mach->accel.stepy; + } else { + dev->accel.err_term += dev->accel.desty_axstp; + } + } + + dev->accel.sx++; + } + } + dev->accel.cur_x = dev->accel.dx; + dev->accel.cur_y = dev->accel.dy; + break; + + case 2: /*Non-conforming BitBLT from dest_y_end register (0xaeee)*/ + if (!cpu_input) { + mach->accel.stepx = 0; + mach->accel.stepy = 0; + + dev->accel.dx = dev->accel.cur_x; + if (dev->accel.cur_x >= 0x600) + dev->accel.dx |= ~0x5ff; + + dev->accel.dy = dev->accel.cur_y; + if (dev->accel.cur_y >= 0x600) + dev->accel.dy |= ~0x5ff; + + /*Destination Width*/ + if (mach->accel.dest_x_start != dev->accel.dx) + mach->accel.dest_x_start = dev->accel.dx; + + mach->accel.dx_start = mach->accel.dest_x_start; + if (mach->accel.dest_x_start >= 0x600) + mach->accel.dx_start |= ~0x5ff; + + mach->accel.dx_end = mach->accel.dest_x_end; + if (mach->accel.dest_x_end >= 0x600) + mach->accel.dx_end |= ~0x5ff; + + if (mach->accel.dx_end > mach->accel.dx_start) { + mach->accel.width = (mach->accel.dx_end - mach->accel.dx_start); + mach->accel.stepx = 1; + } else if (mach->accel.dx_end < mach->accel.dx_start) { + mach->accel.width = (mach->accel.dx_start - mach->accel.dx_end); + mach->accel.stepx = -1; + if (dev->accel.dx > 0) + dev->accel.dx--; + mach_log("BitBLT: Dst Negative X, dxstart = %d, end = %d, width = %d, dx = %d, dpconfig = %04x.\n", mach->accel.dest_x_start, mach->accel.dest_x_end, mach->accel.width, dev->accel.dx, mach->accel.dp_config); + } else { + mach->accel.stepx = 1; + mach->accel.width = 0; + mach_log("BitBLT: Dst Indeterminate X, dpconfig = %04x, destxend = %d, destxstart = %d.\n", mach->accel.dp_config, mach->accel.dest_x_end, mach->accel.dest_x_start); + } + + dev->accel.sx = 0; + mach->accel.poly_fill = 0; + mach->accel.color_pattern_idx = ((dev->accel.dx + (dev->accel.dy << 3)) & mach->accel.patt_len); + if ((svga->bpp == 24) && (mono_src != 1)) { + if (mach->accel.color_pattern_idx == mach->accel.patt_len) + mach->accel.color_pattern_idx = mach->accel.patt_data_idx; + } else if ((svga->bpp == 24) && (frgd_sel == 5) && (mono_src == 1) && (mach->accel.patt_len_reg & 0x4000)) + mach->accel.color_pattern_idx = 0; + + /*Height*/ + mach->accel.dy_start = dev->accel.cur_y; + if (dev->accel.cur_y >= 0x600) + mach->accel.dy_start |= ~0x5ff; + mach->accel.dy_end = mach->accel.dest_y_end; + if (mach->accel.dest_y_end >= 0x600) + mach->accel.dy_end |= ~0x5ff; + + if (mach->accel.dy_end > mach->accel.dy_start) { + mach->accel.height = (mach->accel.dy_end - mach->accel.dy_start); + mach->accel.stepy = 1; + } else if (mach->accel.dy_end < mach->accel.dy_start) { + mach->accel.height = (mach->accel.dy_start - mach->accel.dy_end); + mach->accel.stepy = -1; + } else { + mach->accel.height = 0; + mach->accel.stepy = 1; + } + + dev->accel.sy = 0; + if ((svga->bpp == 15) || (svga->bpp == 16)) + dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch)); + else + dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * (dev->pitch)); + + mach->accel.src_stepx = 0; + + /*Source Width*/ + dev->accel.cx = mach->accel.src_x; + if (mach->accel.src_x >= 0x600) + dev->accel.cx |= ~0x5ff; + + dev->accel.cy = mach->accel.src_y; + if (mach->accel.src_y >= 0x600) + dev->accel.cy |= ~0x5ff; + + mach->accel.sx_start = mach->accel.src_x_start; + if (mach->accel.src_x_start >= 0x600) + mach->accel.sx_start |= ~0x5ff; + + mach->accel.sx_end = mach->accel.src_x_end; + if (mach->accel.src_x_end >= 0x600) + mach->accel.sx_end |= ~0x5ff; + + if (mach->accel.sx_end > mach->accel.sx_start) { + mach->accel.src_width = (mach->accel.sx_end - mach->accel.sx_start); + mach->accel.src_stepx = 1; + mach_log("BitBLT: Src Positive X: wh(%d,%d), srcwidth = %d, coordinates: %d,%d px, start: %d, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", mach->accel.width, mach->accel.height, mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_start, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1); + } else if (mach->accel.sx_end < mach->accel.sx_start) { + mach->accel.src_width = (mach->accel.sx_start - mach->accel.sx_end); + mach->accel.src_stepx = -1; + if (dev->accel.cx > 0) + dev->accel.cx--; + mach_log("BitBLT: Src Negative X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1); + } else { + mach->accel.src_stepx = 1; + mach->accel.src_width = 0; + mach_log("BitBLT: Src Indeterminate X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1); + } + mach->accel.sx = 0; + if ((svga->bpp == 15) || (svga->bpp == 16)) + dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch)); + else + dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch)); + + if ((svga->bpp == 24) && (frgd_sel == 5)) { + mach_log("BitBLT=%04x, WH(%d,%d), SRCWidth=%d, c(%d,%d), s(%d,%d).\n", mach->accel.dp_config, mach->accel.width, mach->accel.height, mach->accel.src_width, dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy); + } else + mach_log("BitBLT=%04x, Pitch=%d, C(%d,%d), SRCWidth=%d, WH(%d,%d), geoffset=%08x.\n", mach->accel.dp_config, dev->ext_pitch, dev->accel.cx, dev->accel.cy, mach->accel.src_width, mach->accel.width, mach->accel.height, (mach->accel.ge_offset << 2)); + + if (mono_src == 1) { + if ((mach->accel.mono_pattern_enable) && !(mach->accel.patt_len_reg & 0x4000)) { + mono_dat0 = mach->accel.patt_data[0x10]; + mono_dat0 |= (mach->accel.patt_data[0x11] << 8); + mono_dat0 |= (mach->accel.patt_data[0x12] << 16); + mono_dat0 |= (mach->accel.patt_data[0x13] << 24); + mono_dat1 = mach->accel.patt_data[0x14]; + mono_dat1 |= (mach->accel.patt_data[0x15] << 8); + mono_dat1 |= (mach->accel.patt_data[0x16] << 16); + mono_dat1 |= (mach->accel.patt_data[0x17] << 24); + + for (uint8_t y = 0; y < 8; y++) { + for (uint8_t x = 0; x < 8; x++) { + uint32_t temp = (y & 4) ? mono_dat1 : mono_dat0; + mach->accel.mono_pattern[y][7 - x] = (temp >> (x + ((y & 3) << 3))) & 1; + } + } + } + } + + if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { + if (mach_pixel_write(mach)) { + dev->data_available = 0; + dev->data_available2 = 0; + return; + } else if (mach_pixel_read(mach)) { + dev->data_available = 1; + dev->data_available2 = 1; + return; + } + } + } + + if (mono_src == 1) { + if (!mach->accel.mono_pattern_enable && !(mach->accel.patt_len_reg & 0x4000)) { + count = mach->accel.width; + mix_dat = mach->accel.patt_data[0x10] ^ ((mach->accel.patt_idx & 1) ? 0xff : 0); + dev->accel.temp_cnt = 8; + } + } + + if (frgd_sel == 5) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + for (int x = 0; x <= mach->accel.patt_len; x += 2) { + mach->accel.color_pattern_word[x + (mach->accel.color_pattern_idx & 1)] = (mach->accel.patt_data[x & mach->accel.patt_len] & 0xff); + mach->accel.color_pattern_word[x + (mach->accel.color_pattern_idx & 1)] |= (mach->accel.patt_data[(x + 1) & mach->accel.patt_len] << 8); + } + } else { + if ((svga->bpp == 24) && (mach->accel.patt_len < 3)) { + for (int x = 0; x <= mach->accel.patt_len; x++) { + mach->accel.color_pattern[x] = mach->accel.patt_data[x]; + mach_log("BITBLT: Color Pattern 24bpp[%d]=%02x, dataidx=%d, pattlen=%d.\n", x, mach->accel.color_pattern[x], mach->accel.patt_data_idx, mach->accel.patt_len); + } + } else { + for (int x = 0; x <= mach->accel.patt_len; x++) { + mach->accel.color_pattern[x] = mach->accel.patt_data[x & mach->accel.patt_len]; + } + } + } + + /*The destination coordinates should match the pattern index.*/ + if (mach->accel.color_pattern_idx != mach->accel.patt_idx) + mach->accel.color_pattern_idx = mach->accel.patt_idx; + } + + if ((mach->accel.dy_end == mach->accel.dy_start)) { + mach_log("No DEST.\n"); + return; + } + + if ((mono_src == 3) || (bkgd_sel == 3) || (frgd_sel == 3)) { + if (mach->accel.sx_end == mach->accel.sx_start) { + mach_log("No SRC.\n"); + return; + } + } + + if (cpu_input) { + if (mach->accel.dp_config == 0x3251) { + if (dev->accel.sy == mach->accel.height) + return; + } + } + + while (count--) { + switch (mono_src) { + case 0: + mix = 1; + break; + case 1: + if (mach->accel.mono_pattern_enable) { + mix = mach->accel.mono_pattern[dev->accel.dy & 7][dev->accel.dx & 7]; + } else { + if ((svga->bpp == 24) && (frgd_sel == 5) && (mach->accel.patt_len_reg & 0x4000)) + mix = 1; + else { + if (!dev->accel.temp_cnt) { + dev->accel.temp_cnt = 8; + mix_dat >>= 8; + } + mix = (mix_dat & 0x80); + dev->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + } + } + break; + case 2: + if (mach->accel.dp_config & 0x1000) { + mix = mix_dat >> 0x1f; + mix_dat <<= 1; + } else { + if (mach->accel.dp_config & 0x200) { + mix = mix_dat & 1; + mix_dat >>= 1; + } else { + mix = mix_dat & 0x80; + mix_dat <<= 1; + mix_dat |= 1; + } + } + break; + case 3: + READ(dev->accel.src + ((dev->accel.cx)), mix, dev->local); + mix = (mix & rd_mask) == rd_mask; + break; + } + + if (((dev->accel.dx) >= (clip_l) && (dev->accel.dx) <= (clip_r) && + (dev->accel.dy) >= (clip_t) && (dev->accel.dy) <= (clip_b))) { + if (mach->accel.dp_config & 0x02) { + READ(dev->accel.src + (dev->accel.cx), poly_src, dev->local); + poly_src = ((poly_src & rd_mask) == rd_mask); + if (poly_src) + mach->accel.poly_fill = !mach->accel.poly_fill; + } + + if (!mach->accel.poly_fill || !(mach->accel.dp_config & 0x02)) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = dev->accel.bkgd_color; + break; + case 1: + src_dat = dev->accel.frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + if (mach_pixel_read(mach)) + src_dat = cpu_dat; + else { + READ(dev->accel.src + (dev->accel.cx), src_dat, dev->local); + if (mono_src == 3) { + src_dat = (src_dat & rd_mask) == rd_mask; + } + } + break; + case 5: + if (mix) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + src_dat = mach->accel.color_pattern_word[mach->accel.color_pattern_idx]; + } else { + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + } + } else + src_dat = 0; + break; + } + } + + if ((svga->bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && (mach->accel.patt_len_reg & 0x4000)) { + if (dev->accel.sy & 1) { + READ(dev->accel.dest + dev->accel.dx - dev->ext_pitch, dest_dat, dev->local); + } else { + READ(dev->accel.dest + dev->accel.dx, dest_dat, dev->local); + } + } else { + READ(dev->accel.dest + dev->accel.dx, dest_dat, dev->local); + } + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = ((dest_dat) >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = ((dest_dat) < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = ((dest_dat) != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = ((dest_dat) == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = ((dest_dat) <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = ((dest_dat) > dest_cmp_clr) ? 0 : 1; + break; + } + + if (!compare) { + if (mach_pixel_write(mach)) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + } + } + + if (mach->accel.dp_config & 0x10) { + if ((svga->bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && (mach->accel.patt_len_reg & 0x4000)) { + if (dev->accel.sy & 1) { + WRITE(dev->accel.dest + dev->accel.dx - dev->ext_pitch, dest_dat, dev->local); + } else { + WRITE(dev->accel.dest + dev->accel.dx, dest_dat, dev->local); + } + } else { + WRITE(dev->accel.dest + dev->accel.dx, dest_dat, dev->local); + } + } + } + + if ((svga->bpp == 8) || (svga->bpp == 24)) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + + if ((mono_src == 3) || (frgd_sel == 3) || (bkgd_sel == 3)) { + dev->accel.cx += mach->accel.src_stepx; + mach->accel.sx++; + if (mach->accel.sx >= mach->accel.src_width) { + mach->accel.sx = 0; + if (mach->accel.src_stepx == -1) + dev->accel.cx += mach->accel.src_width; + else + dev->accel.cx -= mach->accel.src_width; + dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1); + if ((svga->bpp == 15) || (svga->bpp == 16)) + dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch)); + else + dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch)); + } + } + + dev->accel.dx += mach->accel.stepx; + + if ((svga->bpp == 8) || ((svga->bpp == 24) && (mach->accel.patt_len >= 3) && (mono_src != 1))) + mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len; + + if ((svga->bpp == 24) && (mach->accel.color_pattern_idx == mach->accel.patt_len) && (mach->accel.patt_len >= 3) && (mono_src != 1)) { + mach->accel.color_pattern_idx = mach->accel.patt_data_idx; + } else if ((svga->bpp == 24) && (mach->accel.patt_len < 3)) { + if (mach->accel.patt_len == 2) { + mach->accel.color_pattern_idx++; + if (mach->accel.color_pattern_idx == 3) + mach->accel.color_pattern_idx = 0; + } else { + mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len; + } + } else if ((svga->bpp == 24) && (mach->accel.patt_len_reg & 0x4000) && (frgd_sel == 5)) { + mach->accel.color_pattern_idx++; + if (mach->accel.color_pattern_idx == 3) + mach->accel.color_pattern_idx = 0; + } + + if ((svga->bpp == 15) || (svga->bpp == 16)) { + mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len; + mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len; + } + + dev->accel.sx++; + if (dev->accel.sx >= mach->accel.width) { + mach->accel.poly_fill = 0; + dev->accel.sx = 0; + if (mach->accel.stepx == -1) + dev->accel.dx += mach->accel.width; + else + dev->accel.dx -= mach->accel.width; + + dev->accel.dy += mach->accel.stepy; + dev->accel.sy++; + + if ((svga->bpp == 15) || (svga->bpp == 16)) + dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch)); + else { + dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * (dev->pitch)); + } + if ((mono_src == 1) && (svga->bpp == 24) && (frgd_sel == 5)) + mach->accel.color_pattern_idx = 0; + else + mach->accel.color_pattern_idx = ((dev->accel.dx + (dev->accel.dy << 3)) & mach->accel.patt_len); + + if ((svga->bpp == 24) && (mach->accel.color_pattern_idx == mach->accel.patt_len) && (mono_src != 1)) + mach->accel.color_pattern_idx = 0; + if ((mono_src == 1) && !mach->accel.mono_pattern_enable && !(mach->accel.patt_len_reg & 0x4000)) { + dev->accel.cur_x = dev->accel.dx; + dev->accel.cur_y = dev->accel.dy; + return; + } + if (dev->accel.sy >= mach->accel.height) { + if ((mono_src == 2) || (mono_src == 3) || (frgd_sel == 2) || (frgd_sel == 3) || (bkgd_sel == 2) || (bkgd_sel == 3)) + return; + if ((mono_src == 1) && (frgd_sel == 5) && (svga->bpp == 24) && (mach->accel.patt_len_reg & 0x4000)) + return; + dev->accel.cur_x = dev->accel.dx; + dev->accel.cur_y = dev->accel.dy; + return; + } + } + } + break; + + case 3: /*Direct Linedraw (Polyline) from linedraw indexes (0xfeee)*/ + case 4: + if (!cpu_input) { + dev->accel.cx = dev->accel.cur_x; + dev->accel.cy = dev->accel.cur_y; + + if (dev->accel.cur_x >= 0x600) { + mach_log("Linedraw XOver = %d.\n", dev->accel.cur_x); + dev->accel.cx |= ~0x5ff; + } + if (dev->accel.cur_y >= 0x600) { + mach_log("Linedraw YOver = %d.\n", dev->accel.cur_y); + dev->accel.cy |= ~0x5ff; + } + + dev->accel.dx = ABS(mach->accel.cx_end_line - dev->accel.cx) << 1; + dev->accel.dy = ABS(mach->accel.cy_end_line - dev->accel.cy) << 1; + + mach->accel.stepx = (mach->accel.cx_end_line < dev->accel.cx) ? -1 : 1; + mach->accel.stepy = (mach->accel.cy_end_line < dev->accel.cy) ? -1 : 1; + + dev->accel.sx = 0; + + mach_log("Linedraw: c(%d,%d), d(%d,%d), cend(%d,%d).\n", dev->accel.cur_x, dev->accel.cur_y, dev->accel.dx, dev->accel.dy, mach->accel.cx_end_line, mach->accel.cy_end_line); + + if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { + if (mach_pixel_write(mach)) { + dev->data_available = 0; + dev->data_available2 = 0; + return; + } else if (mach_pixel_read(mach)) { + dev->data_available = 1; + dev->data_available2 = 1; + return; + } + } + } + + if (frgd_sel == 5) { + for (int x = 0; x <= mach->accel.patt_len; x++) { + mach->accel.color_pattern[x] = mach->accel.patt_data[x & mach->accel.patt_len]; + } + } + + if (mono_src == 1) { + mix_dat = mach->accel.patt_data[0x10]; + dev->accel.temp_cnt = 8; + } + + count = (dev->accel.dx > dev->accel.dy) ? (dev->accel.dx >> 1) : (dev->accel.dy >> 1); + mach->accel.width = count; + + if (dev->accel.dx > dev->accel.dy) { + mach->accel.err = (dev->accel.dy - dev->accel.dx) >> 1; + if (mono_src == 1) { + while (count--) { + if (!dev->accel.temp_cnt) { + dev->accel.temp_cnt = 8; + mix_dat >>= 8; + } + mix = (mix_dat & 0x80); + dev->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + + if ((((dev->accel.cx) >= clip_l) && ((dev->accel.cx) <= clip_r) && ((dev->accel.cy) >= clip_t) && ((dev->accel.cy) <= clip_b))) { + mach->accel.clip_overrun = 0; + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = dev->accel.bkgd_color; + break; + case 1: + src_dat = dev->accel.frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + if (mach_pixel_read(mach)) + src_dat = cpu_dat; + else { + src_dat = 0; + } + break; + case 5: + if (mix) { + src_dat = mach->accel.color_pattern[((dev->accel.cx) + ((dev->accel.cy) << 3)) & mach->accel.patt_len]; + } else + src_dat = 0; + break; + } + + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = ((dest_dat) >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = ((dest_dat) < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = ((dest_dat) != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = ((dest_dat) == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = ((dest_dat) <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = ((dest_dat) > dest_cmp_clr) ? 0 : 1; + break; + } + + if (!compare) { + if (mach_pixel_write(mach)) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + } + } + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } else { + WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } + } + } else + mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); + + if (!count) + break; + + if (svga->bpp == 8) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + + if (mach->accel.err >= 0) { + dev->accel.cy += mach->accel.stepy; + mach->accel.err -= dev->accel.dx; + } + dev->accel.cx += mach->accel.stepx; + mach->accel.err += dev->accel.dy; + } + } else { + while (count--) { + switch (mono_src) { + case 0: + case 3: + mix = 1; + break; + case 2: + if (mach->accel.dp_config & 0x1000) { + mix = mix_dat >> 0x1f; + mix_dat <<= 1; + } else { + if (mach->accel.dp_config & 0x200) { + mix = mix_dat & 1; + mix_dat >>= 1; + } else { + mix = mix_dat & 0x80; + mix_dat <<= 1; + mix_dat |= 1; + } + } + break; + } + + if ((((dev->accel.cx) >= clip_l) && ((dev->accel.cx) <= clip_r) && ((dev->accel.cy) >= clip_t) && ((dev->accel.cy) <= clip_b))) { + mach->accel.clip_overrun = 0; + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = dev->accel.bkgd_color; + break; + case 1: + src_dat = dev->accel.frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + if (mach_pixel_read(mach)) + src_dat = cpu_dat; + else { + src_dat = 0; + } + break; + case 5: + if (mix) { + src_dat = mach->accel.color_pattern[((dev->accel.cx) + ((dev->accel.cy) << 3)) & mach->accel.patt_len]; + } else + src_dat = 0; + break; + } + + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = ((dest_dat) >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = ((dest_dat) < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = ((dest_dat) != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = ((dest_dat) == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = ((dest_dat) <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = ((dest_dat) > dest_cmp_clr) ? 0 : 1; + break; + } + + if (!compare) { + if (mach_pixel_write(mach)) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + } + } + + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + if (mach->accel.linedraw_opt & 0x04) { + if (dev->accel.sx < mach->accel.width) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } else { + WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } + } + } else { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } else { + WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } + } + } + } else + mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); + + if (dev->accel.sx >= mach->accel.width) + break; + + if (svga->bpp == 8) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + + if (mach->accel.err >= 0) { + dev->accel.cy += mach->accel.stepy; + mach->accel.err -= dev->accel.dx; + } + dev->accel.cx += mach->accel.stepx; + mach->accel.err += dev->accel.dy; + + dev->accel.sx++; + } + } + } else { + mach->accel.err = (dev->accel.dx - dev->accel.dy) >> 1; + if (mono_src == 1) { + while (count--) { + if (dev->accel.temp_cnt == 0) { + dev->accel.temp_cnt = 8; + mix_dat >>= 8; + } + mix = (mix_dat & 0x80); + dev->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + + if ((((dev->accel.cx) >= clip_l) && ((dev->accel.cx) <= clip_r) && ((dev->accel.cy) >= clip_t) && ((dev->accel.cy) <= clip_b))) { + mach->accel.clip_overrun = 0; + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = dev->accel.bkgd_color; + break; + case 1: + src_dat = dev->accel.frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + if (mach_pixel_read(mach)) + src_dat = cpu_dat; + else { + src_dat = 0; + } + break; + case 5: + if (mix) { + src_dat = mach->accel.color_pattern[((dev->accel.cx) + ((dev->accel.cy) << 3)) & mach->accel.patt_len]; + } else + src_dat = 0; + break; + } + + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = ((dest_dat) >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = ((dest_dat) < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = ((dest_dat) != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = ((dest_dat) == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = ((dest_dat) <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = ((dest_dat) > dest_cmp_clr) ? 0 : 1; + break; + } + + if (!compare) { + if (mach_pixel_write(mach)) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + } + } + + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } else { + WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } + } + } else + mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); + + if (!count) + break; + + if (svga->bpp == 8) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + + if (mach->accel.err >= 0) { + dev->accel.cx += mach->accel.stepx; + mach->accel.err -= dev->accel.dy; + } + dev->accel.cy += mach->accel.stepy; + mach->accel.err += dev->accel.dx; + } + } else { + while (count--) { + switch (mono_src) { + case 0: + case 3: + mix = 1; + break; + case 2: + if (mach->accel.dp_config & 0x1000) { + mix = mix_dat >> 0x1f; + mix_dat <<= 1; + } else { + if (mach->accel.dp_config & 0x200) { + mix = mix_dat & 1; + mix_dat >>= 1; + } else { + mix = mix_dat & 0x80; + mix_dat <<= 1; + mix_dat |= 1; + } + } + break; + } + + if ((((dev->accel.cx) >= clip_l) && ((dev->accel.cx) <= clip_r) && ((dev->accel.cy) >= clip_t) && ((dev->accel.cy) <= clip_b))) { + mach->accel.clip_overrun = 0; + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = dev->accel.bkgd_color; + break; + case 1: + src_dat = dev->accel.frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + if (mach_pixel_read(mach)) + src_dat = cpu_dat; + else { + src_dat = 0; + } + break; + case 5: + if (mix) { + src_dat = mach->accel.color_pattern[((dev->accel.cx) + ((dev->accel.cy) << 3)) & mach->accel.patt_len]; + } else + src_dat = 0; + break; + } + + if ((svga->bpp == 15) || (svga->bpp == 16)) { + READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } else { + READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = ((dest_dat) >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = ((dest_dat) < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = ((dest_dat) != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = ((dest_dat) == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = ((dest_dat) <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = ((dest_dat) > dest_cmp_clr) ? 0 : 1; + break; + } + + if (!compare) { + if (mach_pixel_write(mach)) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + } + } + + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + if (mach->accel.linedraw_opt & 0x04) { + if (dev->accel.sx < mach->accel.width) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } else { + WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } + } + } else { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } else { + WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat, dev->local); + } + } + } + } else + mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); + + if (dev->accel.sx >= mach->accel.width) + break; + + if (svga->bpp == 8) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + + if (mach->accel.err >= 0) { + dev->accel.cx += mach->accel.stepx; + mach->accel.err -= dev->accel.dy; + } + dev->accel.cy += mach->accel.stepy; + mach->accel.err += dev->accel.dx; + + dev->accel.sx++; + } + } + } + mach->accel.line_array[(cmd_type == 4) ? 4 : 0] = dev->accel.cx; + mach->accel.line_array[(cmd_type == 4) ? 5 : 1] = dev->accel.cy; + dev->accel.cur_x = mach->accel.line_array[(cmd_type == 4) ? 4 : 0]; + dev->accel.cur_y = mach->accel.line_array[(cmd_type == 4) ? 5 : 1]; + break; + + case 5: /*Horizontal Raster Draw from scan_to_x register (0xcaee)*/ + if (!cpu_input) { + mach->accel.stepx = 0; + mach->accel.stepy = 0; + + dev->accel.dx = dev->accel.cur_x; + if (dev->accel.cur_x >= 0x600) + dev->accel.dx |= ~0x5ff; + dev->accel.dy = dev->accel.cur_y; + if (dev->accel.cur_y >= 0x600) + dev->accel.dy |= ~0x5ff; + + /*Destination Width*/ + mach->accel.dx_start = dev->accel.cur_x; + if (dev->accel.cur_x >= 0x600) + mach->accel.dx_start |= ~0x5ff; + mach->accel.dx_end = mach->accel.scan_to_x; + if (mach->accel.scan_to_x >= 0x600) + mach->accel.dx_end |= ~0x5ff; + + if (mach->accel.dx_end > mach->accel.dx_start) { + mach->accel.width = (mach->accel.dx_end - mach->accel.dx_start); + mach->accel.stepx = 1; + } else if (mach->accel.dx_end < mach->accel.dx_start) { + mach->accel.width = (mach->accel.dx_start - mach->accel.dx_end); + mach->accel.stepx = -1; + if (dev->accel.dx > 0) + dev->accel.dx--; + } else { + mach->accel.stepx = 1; + mach->accel.width = 0; + } + + dev->accel.sx = 0; + if ((svga->bpp == 24) && (mach->accel.patt_len < 0x17)) + mach->accel.color_pattern_idx = 0; + + /*Step Y*/ + mach->accel.dy_start = dev->accel.cur_y; + if (dev->accel.cur_y >= 0x600) + mach->accel.dy_start |= ~0x5ff; + mach->accel.dy_end = mach->accel.dest_y_end; + if (mach->accel.dest_y_end >= 0x600) + mach->accel.dy_end |= ~0x5ff; + + if (mach->accel.dy_end > mach->accel.dy_end) { + mach->accel.stepy = 1; + } else if (mach->accel.dy_end < mach->accel.dy_end) { + mach->accel.stepy = -1; + } else { + mach->accel.stepy = 0; + } + + if ((svga->bpp == 15) || (svga->bpp == 16)) + dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch)); + else + dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * (dev->pitch)); + + mach->accel.src_stepx = 0; + + /*Source Width*/ + dev->accel.cx = mach->accel.src_x; + if (mach->accel.src_x >= 0x600) + dev->accel.cx |= ~0x5ff; + dev->accel.cy = mach->accel.src_y; + if (mach->accel.src_y >= 0x600) + dev->accel.cy |= ~0x5ff; + + mach->accel.sx_start = mach->accel.src_x_start; + if (mach->accel.src_x_start >= 0x600) + mach->accel.sx_start |= ~0x5ff; + + mach->accel.sx_end = mach->accel.src_x_end; + if (mach->accel.src_x_end >= 0x600) + mach->accel.sx_end |= ~0x5ff; + + if (mach->accel.sx_end > mach->accel.sx_start) { + mach->accel.src_width = (mach->accel.sx_end - mach->accel.sx_start); + mach->accel.src_stepx = 1; + } else if (mach->accel.sx_end < mach->accel.sx_start) { + mach->accel.src_width = (mach->accel.sx_start - mach->accel.sx_end); + mach->accel.src_stepx = -1; + if (dev->accel.cx > 0) + dev->accel.cx--; + } else { + mach->accel.src_stepx = 1; + mach->accel.src_width = 0; + } + + mach->accel.sx = 0; + if ((svga->bpp == 15) || (svga->bpp == 16)) + dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch)); + else + dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch)); + + if ((svga->bpp == 24) && (frgd_sel == 5)) { + if (mach->accel.patt_len == 0x17) + mach->accel.color_pattern_idx = 0; + dev->accel.x1 = dev->accel.dx + mach->accel.width; + if (dev->accel.x1 == dev->pitch) { + dev->accel.x2 = mach->accel.width & 1; + } else if ((dev->accel.x1 == mach->accel.width) && (dev->accel.dy & 1) && !dev->accel.y1 && dev->accel.x2) { + if (mach->accel.patt_len == 0x17) + mach->accel.color_pattern_idx = 3; + dev->accel.x3 = 1; + } else + dev->accel.x3 = 0; + } else + mach_log("ScanToX=%04x, Pitch=%d, C(%d,%d), SRCWidth=%d, WH(%d,%d), geoffset=%08x.\n", mach->accel.dp_config, dev->ext_pitch, dev->accel.cx, dev->accel.cy, mach->accel.src_width, mach->accel.width, mach->accel.height, (mach->accel.ge_offset << 1)); + + dev->accel.y1 = 0; + + if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { + if (mach_pixel_write(mach)) { + dev->data_available = 0; + dev->data_available2 = 0; + return; + } else if (mach_pixel_read(mach)) { + dev->data_available = 1; + dev->data_available2 = 1; + return; + } + } + } + + if (mono_src == 1) { + count = mach->accel.width; + mix_dat = mach->accel.patt_data[0x10]; + dev->accel.temp_cnt = 8; + } + + if (frgd_sel == 5) { + if (svga->bpp != 24) { + for (int x = 0; x <= mach->accel.patt_len; x++) { + mach->accel.color_pattern[x] = mach->accel.patt_data[x & mach->accel.patt_len]; + } + } else { + if (mach->accel.patt_len == 0x17) { + for (int x = 0; x <= mach->accel.patt_len; x++) { + mach->accel.color_pattern_full[x] = mach->accel.patt_data[x]; + mach_log("ScanToX: Color Pattern 24bpp[%d]=%02x, dataidx=%d, pattlen=%d.\n", x, mach->accel.color_pattern_full[x], mach->accel.patt_data_idx, mach->accel.patt_len); + } + } else { + for (int x = 0; x <= mach->accel.patt_len; x++) { + mach->accel.color_pattern[x] = mach->accel.patt_data[x]; + mach_log("ScanToX: Color Pattern 24bpp[%d]=%02x, dataidx=%d, pattlen=%d.\n", x, mach->accel.color_pattern[x], mach->accel.patt_data_idx, mach->accel.patt_len); + } + } + } + } + + while (count--) { + switch (mono_src) { + case 0: + mix = 1; + break; + case 1: + if (dev->accel.temp_cnt == 0) { + dev->accel.temp_cnt = 8; + mix_dat >>= 8; + } + mix = (mix_dat & 0x80); + dev->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + break; + case 2: + if (mach->accel.dp_config & 0x1000) { + mix = mix_dat >> 0x1f; + mix_dat <<= 1; + } else { + if (mach->accel.dp_config & 0x200) { + mix = mix_dat & 1; + mix_dat >>= 1; + } else { + mix = mix_dat & 0x80; + mix_dat <<= 1; + mix_dat |= 1; + } + } + break; + case 3: + READ(dev->accel.src + (dev->accel.cx), mix, dev->local); + mix = (mix & rd_mask) == rd_mask; + break; + } + + if ((dev->accel.dx) >= (clip_l) && (dev->accel.dx) <= (clip_r) && + (dev->accel.dy) >= (clip_t) && (dev->accel.dy) <= (clip_b)) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = dev->accel.bkgd_color; + break; + case 1: + src_dat = dev->accel.frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + if (mach_pixel_read(mach)) + src_dat = cpu_dat; + else { + READ(dev->accel.src + (dev->accel.cx), src_dat, dev->local); + if (mono_src == 3) { + src_dat = (src_dat & rd_mask) == rd_mask; + } + } + break; + case 5: + if (mix) { + if (svga->bpp == 24) { + if (mach->accel.patt_len == 0x17) + src_dat = mach->accel.color_pattern_full[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + } else + src_dat = mach->accel.color_pattern[(dev->accel.dx + (dev->accel.dy << 3)) & mach->accel.patt_len]; + } else + src_dat = 0; + break; + } + + READ(dev->accel.dest + (dev->accel.dx), dest_dat, dev->local); + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = ((dest_dat) >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = ((dest_dat) < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = ((dest_dat) != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = ((dest_dat) == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = ((dest_dat) <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = ((dest_dat) > dest_cmp_clr) ? 0 : 1; + break; + } + + if (!compare) { + if (mach_pixel_write(mach)) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + } + } + + if (mach->accel.dp_config & 0x10) { + WRITE(dev->accel.dest + (dev->accel.dx), dest_dat, dev->local); + } + } + + if ((svga->bpp == 8) || (svga->bpp == 24)) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + + dev->accel.cx += mach->accel.src_stepx; + mach->accel.sx++; + if (mach->accel.sx >= mach->accel.src_width) { + mach->accel.sx = 0; + if (mach->accel.src_stepx == -1) { + dev->accel.cx += mach->accel.src_width; + } else + dev->accel.cx -= mach->accel.src_width; + dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1); + if ((svga->bpp == 15) || (svga->bpp == 16)) + dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch)); + else + dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch)); + } + + dev->accel.dx += mach->accel.stepx; + if ((svga->bpp == 24) && (mach->accel.patt_len == 0x17)) { + mach->accel.color_pattern_idx++; + if (dev->accel.x3) { + if (mach->accel.color_pattern_idx == 9) + mach->accel.color_pattern_idx = 3; + } else { + if (mach->accel.color_pattern_idx == 6) + mach->accel.color_pattern_idx = 0; + } + } else if ((svga->bpp == 24) && (mach->accel.patt_len < 3)) { + mach->accel.color_pattern_idx++; + if (mach->accel.color_pattern_idx == 3) + mach->accel.color_pattern_idx = 0; + } else + mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len; + + dev->accel.sx++; + if (dev->accel.sx >= mach->accel.width) { + dev->accel.sx = 0; + dev->accel.dy += mach->accel.stepy; + if ((svga->bpp == 15) || (svga->bpp == 16)) + dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch)); + else + dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * (dev->pitch)); + if (mach->accel.line_idx == 2) { + mach->accel.line_array[0] = dev->accel.dx; + mach->accel.line_array[4] = dev->accel.dx; + } + return; + } + } + break; + } +} + +static void +mach_accel_out_pixtrans(mach_t *mach, ibm8514_t *dev, uint16_t port, uint16_t val, uint16_t len) +{ + int frgd_sel, bkgd_sel, mono_src; + + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; + + if ((mach->accel.dp_config & 4) && (mach->accel.cmd_type != 5)) { + val = (val >> 8) | (val << 8); + } + + switch (mach->accel.dp_config & 0x200) { + case 0x000: /*8-bit size*/ + if ((mono_src == 2)) { + if ((frgd_sel != 2) && (bkgd_sel != 2)) { + if ((mach->accel.dp_config & 0x1000) && dev->local) + val = (val >> 8) | (val << 8); + mach_accel_start(mach->accel.cmd_type, 1, 8, val | (val << 16), 0, mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 1, -1, val | (val << 16), mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 1, -1, val | (val << 16), mach, dev, len); + break; + case 0x200: /*16-bit size*/ + if ((mono_src == 2)) { + if ((frgd_sel != 2) && (bkgd_sel != 2)) { + if (mach->accel.dp_config & 0x1000) + val = (val >> 8) | (val << 8); + mach_accel_start(mach->accel.cmd_type, 1, 16, val | (val << 16), 0, mach, dev, len); + } else { + mach_accel_start(mach->accel.cmd_type, 1, 2, -1, val | (val << 16), mach, dev, len); + } + } else { + mach_accel_start(mach->accel.cmd_type, 1, 2, -1, val | (val << 16), mach, dev, len); + } + break; + } +} + +static void +mach_out(uint16_t addr, uint8_t val, void *p) +{ + mach_t *mach = (mach_t *) p; + svga_t *svga = &mach->svga; + ibm8514_t *dev = &svga->dev8514; + uint8_t old; + uint8_t rs2; + + if (((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x1ce: + mach->index = val; + break; + case 0x1cf: + old = mach->regs[mach->index]; + mach->regs[mach->index] = val; + mach_log("ATI VGA write reg=0x%02X, val=0x%02X\n", mach->index, val); + switch (mach->index) { + case 0xa3: + if ((old ^ val) & 0x10) + svga_recalctimings(svga); + break; + case 0xa7: + if ((old ^ val) & 0x80) + svga_recalctimings(svga); + break; + case 0xad: + if (dev->local) { + if ((old ^ val) & 0x0c) + svga_recalctimings(svga); + } + break; + case 0xb0: + if ((old ^ val) & 0x60) + svga_recalctimings(svga); + break; + case 0xae: + case 0xb2: + case 0xbe: + mach_log("ATI VGA write reg=0x%02X, val=0x%02X\n", mach->index, val); + if (mach->regs[0xbe] & 0x08) { /* Read/write bank mode */ + mach->bank_r = (((mach->regs[0xb2] & 1) << 3) | ((mach->regs[0xb2] & 0xe0) >> 5)); + mach->bank_w = ((mach->regs[0xb2] & 0x1e) >> 1); + if (dev->local) { + mach->bank_r |= (((mach->regs[0xae] & 0x0c) << 2)); + mach->bank_w |= (((mach->regs[0xae] & 3) << 4)); + } + if (ibm8514_on) + mach_log("Separate B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]); + } else { /* Single bank mode */ + mach->bank_w = ((mach->regs[0xb2] & 0x1e) >> 1); + if (dev->local) { + mach->bank_w |= (((mach->regs[0xae] & 3) << 4)); + } + mach->bank_r = mach->bank_w; + if (ibm8514_on) + mach_log("Single B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]); + } + svga->read_bank = mach->bank_r << 16; + svga->write_bank = mach->bank_w << 16; + + if (mach->index == 0xbe) { + if ((old ^ val) & 0x10) + svga_recalctimings(svga); + } + break; + case 0xbd: + if ((old ^ val) & 4) { + mach32_updatemapping(mach); + } + break; + case 0xb3: + ati_eeprom_write(&mach->eeprom, val & 8, val & 2, val & 1); + break; + case 0xb6: + if ((old ^ val) & 0x10) + svga_recalctimings(svga); + break; + case 0xb8: + if (dev->local) { + if ((old ^ val) & 0x40) + svga_recalctimings(svga); + } else { + if ((old ^ val) & 0xc0) + svga_recalctimings(svga); + } + break; + case 0xb9: + if ((old ^ val) & 2) + svga_recalctimings(svga); + break; + } + break; + + case 0x2ea: + case 0x2eb: + case 0x2ec: + case 0x2ed: + rs2 = !!(mach->accel.ext_ge_config & 0x1000); + if (dev->local) { + if (mach->pci_bus) + ati68860_ramdac_out((addr & 3) | (rs2 << 2), val, svga->ramdac, svga); + else + svga_out(addr, val, svga); + } else + svga_out(addr, val, svga); + return; + + case 0x3C6: + case 0x3C7: + case 0x3C8: + case 0x3C9: + rs2 = !!(mach->accel.ext_ge_config & 0x1000); + if (dev->local) { + if (mach->pci_bus) + ati68860_ramdac_out((addr & 3) | (rs2 << 2), val, svga->ramdac, svga); + else + svga_out(addr, val, svga); + } else + svga_out(addr, val, svga); + return; + + case 0x3CF: + if (svga->gdcaddr == 6) { + uint8_t old_val = svga->gdcreg[6]; + svga->gdcreg[6] = val; + if ((svga->gdcreg[6] & 0xc) != (old_val & 0xc)) + mach32_updatemapping(mach); + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + } + break; + } + svga_out(addr, val, svga); +} + +static uint8_t +mach_in(uint16_t addr, void *p) +{ + mach_t *mach = (mach_t *) p; + svga_t *svga = &mach->svga; + ibm8514_t *dev = &svga->dev8514; + uint8_t temp; + uint8_t rs2; + + if (((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x1ce: + temp = mach->index; + break; + case 0x1cf: + switch (mach->index) { + case 0xa8: + temp = (svga->vc >> 8) & 3; + break; + case 0xa9: + temp = svga->vc & 0xff; + break; + case 0xb0: + temp = mach->regs[0xb0] | 0x80; + if (dev->local) { /*Mach32 VGA 1MB memory*/ + temp |= 0x08; + temp &= ~0x10; + } else { /*ATI 28800 VGA 512kB memory*/ + temp &= ~0x08; + temp |= 0x10; + } + break; + case 0xb7: + temp = mach->regs[0xb7] & ~8; + if (ati_eeprom_read(&mach->eeprom)) + temp |= 8; + break; + + default: + temp = mach->regs[mach->index]; + break; + } + break; + + case 0x2ea: + case 0x2eb: + case 0x2ec: + case 0x2ed: + rs2 = !!(mach->accel.ext_ge_config & 0x1000); + if (dev->local) { + if (mach->pci_bus) + return ati68860_ramdac_in((addr & 3) | (rs2 << 2), svga->ramdac, svga); + else + return svga_in(addr, svga); + } + return svga_in(addr, svga); + + case 0x3C6: + case 0x3C7: + case 0x3C8: + case 0x3C9: + rs2 = !!(mach->accel.ext_ge_config & 0x1000); + if (dev->local) { + if (mach->pci_bus) + return ati68860_ramdac_in((addr & 3) | (rs2 << 2), svga->ramdac, svga); + else + return svga_in(addr, svga); + } + return svga_in(addr, svga); + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + case 0x3DA: + svga->attrff = 0; + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x38; + else + svga->cgastat ^= 0x38; + return svga->cgastat; + + default: + temp = svga_in(addr, svga); + break; + } + return temp; +} + +static void +mach_recalctimings(svga_t *svga) +{ + mach_t *mach = (mach_t *) svga->p; + ibm8514_t *dev = &svga->dev8514; + + if (vga_on && !ibm8514_on) { + switch (((mach->regs[0xbe] & 0x10) >> 1) | ((mach->regs[0xb9] & 2) << 1) | ((svga->miscout & 0x0c) >> 2)) { + case 0x00: + svga->clock = (cpuclock * (double) (1ull << 32)) / 42954000.0; + break; + case 0x01: + svga->clock = (cpuclock * (double) (1ull << 32)) / 48771000.0; + break; + case 0x02: + mach_log("clock 2\n"); + break; + case 0x03: + svga->clock = (cpuclock * (double) (1ull << 32)) / 36000000.0; + break; + case 0x04: + svga->clock = (cpuclock * (double) (1ull << 32)) / 50350000.0; + break; + case 0x05: + svga->clock = (cpuclock * (double) (1ull << 32)) / 56640000.0; + break; + case 0x06: + mach_log("clock 2\n"); + break; + case 0x07: + svga->clock = (cpuclock * (double) (1ull << 32)) / 44900000.0; + break; + case 0x08: + svga->clock = (cpuclock * (double) (1ull << 32)) / 30240000.0; + break; + case 0x09: + svga->clock = (cpuclock * (double) (1ull << 32)) / 32000000.0; + break; + case 0x0A: + svga->clock = (cpuclock * (double) (1ull << 32)) / 37500000.0; + break; + case 0x0B: + svga->clock = (cpuclock * (double) (1ull << 32)) / 39000000.0; + break; + case 0x0C: + svga->clock = (cpuclock * (double) (1ull << 32)) / 50350000.0; + break; + case 0x0D: + svga->clock = (cpuclock * (double) (1ull << 32)) / 56644000.0; + break; + case 0x0E: + svga->clock = (cpuclock * (double) (1ull << 32)) / 75000000.0; + break; + case 0x0F: + svga->clock = (cpuclock * (double) (1ull << 32)) / 65000000.0; + break; + default: + break; + } + } + + if (mach->regs[0xa3] & 0x10) + svga->ma_latch |= 0x10000; + + if (mach->regs[0xb0] & 0x40) + svga->ma_latch |= 0x20000; + + if (dev->local) { + if (mach->regs[0xad] & 0x04) + svga->ma_latch |= 0x40000; + + if (mach->regs[0xad] & 0x08) + svga->ma_latch |= 0x80000; + + if (mach->regs[0xb8] & 0x40) + svga->clock *= 2; + } else { + switch (mach->regs[0xb8] & 0xc0) { + case 0x40: + svga->clock *= 2; + break; + case 0x80: + svga->clock *= 3; + break; + case 0xc0: + svga->clock *= 4; + break; + } + } + + if (mach->regs[0xa7] & 0x80) + svga->clock *= 3; + + if (mach->regs[0xb6] & 0x10) { + svga->hdisp <<= 1; + svga->htotal <<= 1; + svga->rowoffset <<= 1; + svga->gdcreg[5] &= ~0x40; + } + + if (mach->regs[0xb0] & 0x20) { + svga->gdcreg[5] |= 0x40; + } + + if (vga_on && !ibm8514_on) { + if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: + case 0x60: /*256+ colours*/ + switch (svga->bpp) { + case 8: + svga->map8 = svga->pallook; + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else { + svga->render = svga_render_8bpp_highres; + svga->ma_latch <<= 1; + svga->rowoffset <<= 1; + } + break; + + } + break; + } + } + } + } else if (dev->local) { + if (ibm8514_on) { + svga->hdisp_time = svga->hdisp = (dev->hdisp + 1) << 3; + dev->pitch = (dev->accel.advfunc_cntl & 4) ? 1024 : 640; + svga->htotal = (dev->htotal + 1); + svga->vtotal = (dev->vtotal + 1); + svga->vsyncstart = (dev->vsyncstart + 1); + svga->rowcount = !!(dev->disp_cntl & 0x08); + svga->dispend = ((dev->vdisp >> 1) + 1); + svga->interlace = dev->interlace; + svga->split = 0xffffff; + svga->vblankstart = svga->dispend; + + if (svga->dispend == 766) { + svga->dispend = 768; + svga->vblankstart = svga->dispend; + } + + if (svga->dispend == 598) { + svga->dispend = 600; + svga->vblankstart = svga->dispend; + } + + if (dev->accel.advfunc_cntl & 4) { + if (dev->ibm_mode) { + if (svga->hdisp == 8) { + svga->hdisp = 1024; + svga->dispend = 768; + svga->vtotal = 1536; + svga->vsyncstart = 1536; + } + } + + if (svga->interlace) { + svga->dispend >>= 1; + svga->vsyncstart >>= 2; + svga->vtotal >>= 2; + } else { + svga->vsyncstart >>= 1; + svga->vtotal >>= 1; + } + + dev->pitch = dev->ext_pitch; + svga->rowoffset = dev->ext_crt_pitch; + + svga->clock = (cpuclock * (double) (1ull << 32)) / 44900000.0; + } else { + if (dev->ibm_mode) { + if ((svga->hdisp == 1024) && !dev->internal_pitch) { + svga->hdisp = 640; + svga->dispend = 480; + } + } + + if (svga->interlace) { + svga->dispend >>= 1; + svga->vsyncstart >>= 2; + svga->vtotal >>= 2; + } else { + svga->vsyncstart >>= 1; + svga->vtotal >>= 1; + } + + dev->pitch = dev->ext_pitch; + svga->rowoffset = dev->ext_crt_pitch; + + svga->clock = (cpuclock * (double) (1ull << 32)) / 25175000.0; + } + switch (svga->bpp) { + case 8: + default: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + } + mach_log("BPP=%d, VRAM Mask=%08x, NormalPitch=%d, CRTPitch=%d, VSYNCSTART=%d, VTOTAL=%d, ROWCOUNT=%d, mode=%d, highres bit=%x, has_vga?=%d, override=%d.\n", svga->bpp, svga->vram_mask, dev->pitch, dev->ext_crt_pitch, svga->vsyncstart, svga->vtotal, svga->rowcount, dev->ibm_mode, dev->accel.advfunc_cntl & 4, ibm8514_has_vga, svga->override); + } + mach_log("8514 enabled, hdisp=%d, vtotal=%d, htotal=%d, dispend=%d, rowoffset=%d, split=%d, vsyncstart=%d, split=%08x\n", svga->hdisp, svga->vtotal, svga->htotal, svga->dispend, svga->rowoffset, svga->split, svga->vsyncstart, svga->split); + } +} + +static void +mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, uint32_t val, int len) +{ + int frgd_sel, bkgd_sel, mono_src; + switch (port) { + case 0x82e8: + case 0xc2e8: + if (len == 1) { + dev->accel.cur_y = (dev->accel.cur_y & 0x700) | val; + } else { + dev->accel.cur_y = val & 0x7ff; + } + break; + case 0x82e9: + case 0xc2e9: + if (len == 1) { + dev->accel.cur_y = (dev->accel.cur_y & 0xff) | ((val & 0x07) << 8); + } + break; + + case 0x86e8: + case 0xc6e8: + if (len == 1) { + dev->accel.cur_x = (dev->accel.cur_x & 0x700) | val; + } else { + dev->accel.cur_x = val & 0x7ff; + } + break; + case 0x86e9: + case 0xc6e9: + if (len == 1) { + dev->accel.cur_x = (dev->accel.cur_x & 0xff) | ((val & 0x07) << 8); + } + break; + + case 0x8ae8: + case 0xcae8: + if (len == 1) + dev->accel.desty_axstp = (dev->accel.desty_axstp & 0x3f00) | val; + else { + mach->accel.src_y = val; + dev->accel.desty_axstp = val & 0x3fff; + if (val & 0x2000) + dev->accel.desty_axstp |= ~0x1fff; + } + break; + case 0x8ae9: + case 0xcae9: + if (len == 1) { + dev->accel.desty_axstp = (dev->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + dev->accel.desty_axstp |= ~0x1fff; + } + break; + + case 0x8ee8: + case 0xcee8: + if (len == 1) + dev->accel.destx_distp = (dev->accel.destx_distp & 0x3f00) | val; + else { + mach->accel.src_x = val; + dev->accel.destx_distp = val & 0x3fff; + if (val & 0x2000) + dev->accel.destx_distp |= ~0x1fff; + } + break; + case 0x8ee9: + case 0xcee9: + if (len == 1) { + dev->accel.destx_distp = (dev->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + dev->accel.destx_distp |= ~0x1fff; + } + break; + + case 0x92e8: + if (len != 1) + dev->test = val; + case 0xd2e8: + mach_log("92E8 = %04x\n", val); + if (len == 1) + dev->accel.err_term = (dev->accel.err_term & 0x3f00) | val; + else { + dev->accel.err_term = val & 0x3fff; + if (val & 0x2000) + dev->accel.err_term |= ~0x1fff; + } + break; + case 0x92e9: + case 0xd2e9: + if (len == 1) { + dev->accel.err_term = (dev->accel.err_term & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + dev->accel.err_term |= ~0x1fff; + } + break; + + case 0x96e8: + case 0xd6e8: + if (len == 1) + dev->accel.maj_axis_pcnt = (dev->accel.maj_axis_pcnt & 0x0700) | val; + else { + mach->accel.test = val & 0x1fff; + dev->accel.maj_axis_pcnt = val & 0x07ff; + } + break; + case 0x96e9: + case 0xd6e9: + if (len == 1) { + dev->accel.maj_axis_pcnt = (dev->accel.maj_axis_pcnt & 0xff) | ((val & 0x07) << 8); + } + break; + + case 0x9ae8: + case 0xdae8: + dev->accel.ssv_state = 0; + if (len == 1) + dev->accel.cmd = (dev->accel.cmd & 0xff00) | val; + else { + dev->data_available = 0; + dev->data_available2 = 0; + dev->accel.cmd = val; + mach_log("CMD8514 = %04x.\n", val); + mach->accel.cmd_type = -1; + if (port == 0xdae8) { + if (dev->accel.cmd & 0x100) + dev->accel.cmd_back = 0; + } + ibm8514_accel_start(-1, 0, -1, 0, svga, len); + } + break; + case 0x9ae9: + case 0xdae9: + if (len == 1) { + dev->data_available = 0; + dev->data_available2 = 0; + dev->accel.cmd = (dev->accel.cmd & 0xff) | (val << 8); + mach->accel.cmd_type = -1; + if (port == 0xdae9) { + if (dev->accel.cmd & 0x100) + dev->accel.cmd_back = 0; + } + ibm8514_accel_start(-1, 0, -1, 0, svga, len); + } + break; + + case 0x9ee8: + case 0xdee8: + dev->accel.ssv_state = 1; + if (len == 1) + dev->accel.short_stroke = (dev->accel.short_stroke & 0xff00) | val; + else { + dev->accel.short_stroke = val; + dev->accel.cx = dev->accel.cur_x; + dev->accel.cy = dev->accel.cur_y; + + if (dev->accel.cur_x >= 0x600) { + dev->accel.cx |= ~0x5ff; + } + if (dev->accel.cur_y >= 0x600) { + dev->accel.cy |= ~0x5ff; + } + + if (dev->accel.cmd & 0x1000) { + ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len); + ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke >> 8, len); + } else { + ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke >> 8, len); + ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len); + } + } + break; + case 0x9ee9: + case 0xdee9: + if (len == 1) { + dev->accel.short_stroke = (dev->accel.short_stroke & 0xff) | (val << 8); + dev->accel.cx = dev->accel.cur_x; + dev->accel.cy = dev->accel.cur_y; + + if (dev->accel.cur_x >= 0x600) { + dev->accel.cx |= ~0x5ff; + } + if (dev->accel.cur_y >= 0x600) { + dev->accel.cy |= ~0x5ff; + } + + if (dev->accel.cmd & 0x1000) { + ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len); + ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke >> 8, len); + } else { + ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke >> 8, len); + ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len); + } + } + break; + + case 0xa2e8: + case 0xe2e8: + if (port == 0xe2e8) { + if (dev->accel.cmd_back) { + if (len == 1) + dev->accel.bkgd_color = (dev->accel.bkgd_color & 0x00ff) | val; + else + dev->accel.bkgd_color = val; + } else { + if (len == 1) { + if (mach->accel.cmd_type >= 0) { + if (mach_pixel_read(mach)) + break; + mach->accel.pix_trans[1] = val; + } + } else { + if (mach->accel.cmd_type >= 0) { + if (mach_pixel_read(mach)) + break; + mach_accel_out_pixtrans(mach, dev, port, val, len); + } else { + if (ibm8514_cpu_dest(svga)) + break; + ibm8514_accel_out_pixtrans(svga, port, val, len); + } + } + } + } else { + if (len == 1) + dev->accel.bkgd_color = (dev->accel.bkgd_color & 0x00ff) | val; + else + dev->accel.bkgd_color = val; + } + break; + case 0xa2e9: + case 0xe2e9: + if (port == 0xe2e9) { + if (dev->accel.cmd_back) { + if (len == 1) + dev->accel.bkgd_color = (dev->accel.bkgd_color & 0xff00) | (val << 8); + } else { + if (len == 1) { + if (mach->accel.cmd_type >= 0) { + if (mach_pixel_read(mach)) + break; + mach->accel.pix_trans[0] = val; + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; + + switch (mach->accel.dp_config & 0x200) { + case 0x000: /*8-bit size*/ + if (mono_src == 2) { + if ((frgd_sel != 2) && (bkgd_sel != 2)) { + mach_accel_start(mach->accel.cmd_type, 1, 8, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + break; + case 0x200: /*16-bit size*/ + if (mono_src == 2) { + if ((frgd_sel != 2) && (bkgd_sel != 2)) { + if (mach->accel.dp_config & 0x1000) + mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[1] | (mach->accel.pix_trans[0] << 8), 0, mach, dev, len); + else + mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + break; + } + } + } + } + } else { + if (len == 1) + dev->accel.bkgd_color = (dev->accel.bkgd_color & 0xff00) | (val << 8); + } + break; + + case 0xa6e8: + case 0xe6e8: + if (port == 0xe6e8) { + if (dev->accel.cmd_back) { + if (len == 1) + dev->accel.frgd_color = (dev->accel.frgd_color & 0x00ff) | val; + else + dev->accel.frgd_color = val; + } else { + if (len == 1) { + if (mach->accel.cmd_type >= 0) { + if (mach_pixel_read(mach)) + break; + mach->accel.pix_trans[1] = val; + } + } else { + if (mach->accel.cmd_type >= 0) { + if (mach_pixel_read(mach)) + break; + mach_accel_out_pixtrans(mach, dev, port, val, len); + } else { + if (ibm8514_cpu_dest(svga)) + break; + ibm8514_accel_out_pixtrans(svga, port, val, len); + } + } + } + } else { + if (len == 1) + dev->accel.frgd_color = (dev->accel.frgd_color & 0x00ff) | val; + else + dev->accel.frgd_color = val; + } + break; + case 0xa6e9: + case 0xe6e9: + if (port == 0xe6e9) { + if (dev->accel.cmd_back) { + if (len == 1) + dev->accel.frgd_color = (dev->accel.frgd_color & 0xff00) | (val << 8); + } else { + if (len == 1) { + if (mach->accel.cmd_type >= 0) { + if (mach_pixel_read(mach)) + break; + mach->accel.pix_trans[0] = val; + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; + + switch (mach->accel.dp_config & 0x200) { + case 0x000: /*8-bit size*/ + if (mono_src == 2) { + if ((frgd_sel != 2) && (bkgd_sel != 2)) { + mach_accel_start(mach->accel.cmd_type, 1, 8, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + break; + case 0x200: /*16-bit size*/ + if (mono_src == 2) { + if ((frgd_sel != 2) && (bkgd_sel != 2)) { + if (mach->accel.dp_config & 0x1000) + mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[1] | (mach->accel.pix_trans[0] << 8), 0, mach, dev, len); + else + mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + break; + } + } + } + } + } else { + if (len == 1) + dev->accel.frgd_color = (dev->accel.frgd_color & 0xff00) | (val << 8); + } + break; + + case 0xaae8: + case 0xeae8: + if (len == 1) + dev->accel.wrt_mask = (dev->accel.wrt_mask & 0x00ff) | val; + else + dev->accel.wrt_mask = val; + break; + case 0xaae9: + case 0xeae9: + if (len == 1) + dev->accel.wrt_mask = (dev->accel.wrt_mask & 0xff00) | (val << 8); + break; + + case 0xaee8: + case 0xeee8: + if (len == 1) + dev->accel.rd_mask = (dev->accel.rd_mask & 0x00ff) | val; + else + dev->accel.rd_mask = val; + break; + case 0xaee9: + case 0xeee9: + if (len == 1) + dev->accel.rd_mask = (dev->accel.rd_mask & 0xff00) | (val << 8); + break; + + case 0xb2e8: + case 0xf2e8: + if (len == 1) + dev->accel.color_cmp = (dev->accel.color_cmp & 0x00ff) | val; + else + dev->accel.color_cmp = val; + break; + case 0xb2e9: + case 0xf2e9: + if (len == 1) + dev->accel.color_cmp = (dev->accel.color_cmp & 0xff00) | (val << 8); + break; + + case 0xb6e8: + case 0xf6e8: + dev->accel.bkgd_mix = val & 0xff; + break; + + case 0xbae8: + case 0xfae8: + dev->accel.frgd_mix = val & 0xff; + break; + + case 0xbee8: + case 0xfee8: + if (len == 1) + dev->accel.multifunc_cntl = (dev->accel.multifunc_cntl & 0xff00) | val; + else { + dev->accel.multifunc_cntl = val; + dev->accel.multifunc[dev->accel.multifunc_cntl >> 12] = dev->accel.multifunc_cntl & 0xfff; + if ((dev->accel.multifunc_cntl >> 12) == 1) { + dev->accel.clip_top = val & 0x7ff; + } + if ((dev->accel.multifunc_cntl >> 12) == 2) { + dev->accel.clip_left = val & 0x7ff; + } + if ((dev->accel.multifunc_cntl >> 12) == 3) { + dev->accel.multifunc[3] = val & 0x7ff; + } + if ((dev->accel.multifunc_cntl >> 12) == 4) { + dev->accel.multifunc[4] = val & 0x7ff; + } + mach_log("CLIPBOTTOM=%d, CLIPRIGHT=%d, bpp=%d, pitch=%d.\n", dev->accel.multifunc[3], dev->accel.multifunc[4], svga->bpp, dev->pitch); + if ((dev->accel.multifunc_cntl >> 12) == 5) { + if (!dev->local || !dev->ext_crt_pitch) + dev->ext_crt_pitch = 128; + svga_recalctimings(svga); + } + if (port == 0xfee8) + dev->accel.cmd_back = 1; + else + dev->accel.cmd_back = 0; + } + break; + case 0xbee9: + case 0xfee9: + if (len == 1) { + dev->accel.multifunc_cntl = (dev->accel.multifunc_cntl & 0xff) | (val << 8); + dev->accel.multifunc[dev->accel.multifunc_cntl >> 12] = dev->accel.multifunc_cntl & 0xfff; + if ((dev->accel.multifunc_cntl >> 12) == 1) { + dev->accel.clip_top = dev->accel.multifunc_cntl & 0x7ff; + } + if ((dev->accel.multifunc_cntl >> 12) == 2) { + dev->accel.clip_left = dev->accel.multifunc_cntl & 0x7ff; + } + if ((dev->accel.multifunc_cntl >> 12) == 5) { + if (!dev->local || !dev->ext_crt_pitch) + dev->ext_crt_pitch = 128; + svga_recalctimings(svga); + } + if (port == 0xfee9) + dev->accel.cmd_back = 1; + else + dev->accel.cmd_back = 0; + } + break; + +/*ATI Mach8/32 specific registers*/ + case 0x82ee: + mach->accel.patt_data_idx = val & 0x1f; + mach_log("Pattern Data Index = %d.\n", val & 0x1f); + break; + + case 0x8eee: + if (len == 1) { + mach->accel.patt_data[mach->accel.patt_data_idx] = val; + } else { + mach->accel.patt_data[mach->accel.patt_data_idx] = val & 0xff; + mach->accel.patt_data[mach->accel.patt_data_idx + 1] = (val >> 8) & 0xff; + if (mach->accel.mono_pattern_enable) + mach->accel.patt_data_idx = (mach->accel.patt_data_idx + 2) & 0x17; + else { + frgd_sel = (mach->accel.dp_config >> 13) & 7; + mono_src = (mach->accel.dp_config >> 5) & 3; + if ((svga->bpp == 24) && (mach->accel.patt_len == 0x17) && (frgd_sel == 5)) { + mach->accel.patt_data_idx += 2; + dev->accel.y1 = 1; + } else { + if (svga->bpp == 24) + mach->accel.patt_data_idx += 2; + else + mach->accel.patt_data_idx = (mach->accel.patt_data_idx + 2) & mach->accel.patt_len; + + } + mach_log("ExtCONFIG = %04x, Pattern Mono = %04x, selidx = %d, dataidx = %d, bit 0 = %02x len = %d.\n", mach->accel.ext_ge_config, val, mach->accel.patt_idx, mach->accel.patt_data_idx, val & 1, mach->accel.patt_len); + } + } + break; + case 0x8eef: + if (len == 1) { + mach->accel.patt_data[mach->accel.patt_data_idx + 1] = val; + if (mach->accel.mono_pattern_enable) + mach->accel.patt_data_idx = (mach->accel.patt_data_idx + 2) & 7; + else { + frgd_sel = (mach->accel.dp_config >> 13) & 7; + if ((svga->bpp == 24) && (mach->accel.patt_len == 0x17) && (frgd_sel == 5)) { + mach->accel.patt_data_idx += 2; + dev->accel.y1 = 1; + } else + mach->accel.patt_data_idx = (mach->accel.patt_data_idx + 2) & mach->accel.patt_len; + } + } + break; + + case 0x96ee: + if (len == 1) + mach->accel.bres_count = (mach->accel.bres_count & 0x700) | val; + else { + mach->accel.bres_count = val & 0x7ff; + mach_log("96EE line draw.\n"); + dev->data_available = 0; + dev->data_available2 = 0; + mach->accel.cmd_type = 1; + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev, len); + } + break; + case 0x96ef: + if (len == 1) { + mach->accel.bres_count = (mach->accel.bres_count & 0xff) | ((val & 0x07) << 8); + mach_log("96EE (2) line draw.\n"); + dev->data_available = 0; + dev->data_available2 = 0; + mach->accel.cmd_type = 1; + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev, len); + } + break; + + case 0x9aee: + mach->accel.line_idx = val & 0x07; + break; + + case 0xa2ee: + mach_log("Line OPT = %04x\n", val); + if (len == 1) + mach->accel.linedraw_opt = (mach->accel.linedraw_opt & 0xff00) | val; + else { + mach->accel.linedraw_opt = val; + } + break; + case 0xa2ef: + if (len == 1) { + mach->accel.linedraw_opt = (mach->accel.linedraw_opt & 0x00ff) | (val << 8); + } + break; + + case 0xa6ee: + if (len == 1) + mach->accel.dest_x_start = (mach->accel.dest_x_start & 0x700) | val; + else + mach->accel.dest_x_start = val & 0x7ff; + break; + case 0xa6ef: + if (len == 1) + mach->accel.dest_x_start = (mach->accel.dest_x_start & 0x0ff) | ((val & 0x07) << 8); + break; + + case 0xaaee: + if (len == 1) + mach->accel.dest_x_end = (mach->accel.dest_x_end & 0x700) | val; + else { + mach->accel.dest_x_end = val & 0x7ff; + } + break; + case 0xaaef: + if (len == 1) + mach->accel.dest_x_end = (mach->accel.dest_x_end & 0x0ff) | ((val & 0x07) << 8); + break; + + case 0xaeee: + mach_log("AEEE write val = %04x.\n", val); + if (len == 1) + mach->accel.dest_y_end = (mach->accel.dest_y_end & 0x700) | val; + else { + mach->accel.dest_y_end = val & 0x7ff; + if ((val + 1) == 0x10000) { + mach_log("Dest_Y_end overflow val = %04x\n", val); + mach->accel.dest_y_end = 0; + } + dev->data_available = 0; + dev->data_available2 = 0; + mach_log("BitBLT = %04x.\n", mach->accel.dp_config); + mach->accel.cmd_type = 2; /*Non-conforming BitBLT from dest_y_end register (0xaeee)*/ + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev, len); + } + break; + case 0xaeef: + if (len == 1) { + mach->accel.dest_y_end = (mach->accel.dest_y_end & 0x0ff) | ((val & 0x07) << 8); + dev->data_available = 0; + dev->data_available2 = 0; + mach->accel.cmd_type = 2; /*Non-conforming BitBLT from dest_y_end register (0xaeee)*/ + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev, len); + } + break; + + case 0xb2ee: + if (len == 1) + mach->accel.src_x_start = (mach->accel.src_x_start & 0x700) | val; + else + mach->accel.src_x_start = val & 0x7ff; + break; + case 0xb2ef: + if (len == 1) + mach->accel.src_x_start = (mach->accel.src_x_start & 0x0ff) | ((val & 0x07) << 8); + break; + + case 0xb6ee: + dev->accel.bkgd_mix = val & 0xff; + break; + + case 0xbaee: + dev->accel.frgd_mix = val & 0xff; + break; + + case 0xbeee: + if (len == 1) + mach->accel.src_x_end = (mach->accel.src_x_end & 0x700) | val; + else { + mach->accel.src_x_end = val & 0x7ff; + } + break; + case 0xbeef: + if (len == 1) + mach->accel.src_x_end = (mach->accel.src_x_end & 0x0ff) | ((val & 0x07) << 8); + break; + + case 0xc2ee: + mach->accel.src_y_dir = val & 1; + break; + + case 0xc6ee: + mach->accel.cmd_type = 0; + mach_log("TODO: Short Stroke.\n"); + break; + + case 0xcaee: + mach_log("CAEE write val = %04x.\n", val); + if (len == 1) + mach->accel.scan_to_x = (mach->accel.scan_to_x & 0x700) | val; + else { + mach->accel.scan_to_x = (val & 0x7ff); + if ((val + 1) == 0x10000) { + mach_log("Scan_to_X overflow val = %04x\n", val); + mach->accel.scan_to_x = 0; + } + dev->data_available = 0; + dev->data_available2 = 0; + mach->accel.cmd_type = 5; /*Horizontal Raster Draw from scan_to_x register (0xcaee)*/ + mach_log("ScanToX = %04x.\n", mach->accel.dp_config); + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev, len); + } + break; + case 0xcaef: + if (len == 1) { + mach->accel.scan_to_x = (mach->accel.scan_to_x & 0x0ff) | ((val & 0x07) << 8); + dev->data_available = 0; + dev->data_available2 = 0; + mach->accel.cmd_type = 5; /*Horizontal Raster Draw from scan_to_x register (0xcaee)*/ + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev, len); + } + break; + + case 0xceee: + mach_log("CEEE write val = %04x.\n", val); + if (len == 1) + mach->accel.dp_config = (mach->accel.dp_config & 0xff00) | val; + else { + mach->accel.dp_config = val; + } + break; + case 0xceef: + if (len == 1) { + mach->accel.dp_config = (mach->accel.dp_config & 0x00ff) | (val << 8); + } + break; + + case 0xd2ee: + mach->accel.patt_len = val & 0x1f; + mach_log("Pattern Length = %d, val = %04x.\n", val & 0x1f, val); + mach->accel.mono_pattern_enable = !!(val & 0x80); + if (len != 1) { + mach->accel.patt_len_reg = val; + } else { + mach->accel.patt_len_reg = (mach->accel.patt_len_reg & 0xff00) | val; + } + break; + case 0xd2ef: + if (len == 1) + mach->accel.patt_len_reg = (mach->accel.patt_len_reg & 0x00ff) | (val << 8); + break; + + case 0xd6ee: + mach->accel.patt_idx = val & 0x1f; + mach_log("Pattern Index = %d, val = %02x.\n", val & 0x1f, val); + break; + + case 0xdaee: + mach_log("DAEE (extclipl) write val = %d\n", val); + if (len == 1) + dev->accel.clip_left = (dev->accel.clip_left & 0x700) | val; + else { + dev->accel.clip_left = val & 0x7ff; + } + break; + case 0xdaef: + if (len == 1) + dev->accel.clip_left = (dev->accel.clip_left & 0x0ff) | ((val & 0x07) << 8); + break; + + case 0xdeee: + mach_log("DEEE (extclipt) write val = %d\n", val); + if (len == 1) + dev->accel.clip_top = (dev->accel.clip_top & 0x700) | val; + else { + dev->accel.clip_top = val & 0x7ff; + } + break; + case 0xdeef: + if (len == 1) + dev->accel.clip_top = (dev->accel.clip_top & 0x0ff) | ((val & 0x07) << 8); + break; + + case 0xe2ee: + mach_log("E2EE (extclipr) write val = %d\n", val); + if (len == 1) + dev->accel.multifunc[4] = (dev->accel.multifunc[4] & 0x700) | val; + else { + dev->accel.multifunc[4] = val & 0x7ff; + } + break; + case 0xe2ef: + if (len == 1) + dev->accel.multifunc[4] = (dev->accel.multifunc[4] & 0x0ff) | ((val & 0x07) << 8); + break; + + case 0xe6ee: + mach_log("E6EE (extclipb) write val = %d\n", val); + if (len == 1) + dev->accel.multifunc[3] = (dev->accel.multifunc[3] & 0x700) | val; + else { + dev->accel.multifunc[3] = val & 0x7ff; + } + break; + case 0xe6ef: + if (len == 1) + dev->accel.multifunc[3] = (dev->accel.multifunc[3] & 0x0ff) | ((val & 0x07) << 8); + break; + + case 0xeeee: + if (len == 1) + mach->accel.dest_cmp_fn = (mach->accel.dest_cmp_fn & 0xff00) | val; + else + mach->accel.dest_cmp_fn = val; + break; + case 0xeeef: + if (len == 1) + mach->accel.dest_cmp_fn = (mach->accel.dest_cmp_fn & 0x00ff) | (val << 8); + break; + + case 0xf2ee: + mach_log("F2EE.\n"); + if (len == 1) + mach->accel.dst_clr_cmp_mask = (mach->accel.dst_clr_cmp_mask & 0xff00) | val; + else + mach->accel.dst_clr_cmp_mask = val; + break; + case 0xf2ef: + if (len == 1) + mach->accel.dst_clr_cmp_mask = (mach->accel.dst_clr_cmp_mask & 0x00ff) | (val << 8); + break; + + case 0xfeee: + if (mach->accel.dp_config == 0x2231 || mach->accel.dp_config == 0x2211) + mach_log("FEEE val = %d, lineidx = %d, DPCONFIG = %04x, CPUCX = %04x.\n", val, mach->accel.line_idx, mach->accel.dp_config, CX); + if (len != 1) { + mach->accel.line_array[mach->accel.line_idx] = val; + dev->accel.cur_x = mach->accel.line_array[(mach->accel.line_idx == 4) ? 4 : 0]; + dev->accel.cur_y = mach->accel.line_array[(mach->accel.line_idx == 5) ? 5 : 1]; + mach->accel.cx_end_line = mach->accel.line_array[2]; + mach->accel.cy_end_line = mach->accel.line_array[3]; + if ((mach->accel.line_idx == 3) || (mach->accel.line_idx == 5)) { + mach->accel.cmd_type = (mach->accel.line_idx == 5) ? 4 : 3; + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, mach, dev, len); + mach->accel.line_idx = (mach->accel.line_idx == 5) ? 4 : 2; + break; + } + mach->accel.line_idx++; + } + break; + } +} + +static void +mach_accel_out(uint16_t port, uint32_t val, mach_t *mach, int len) +{ + svga_t *svga = &mach->svga; + ibm8514_t *dev = &svga->dev8514; + + mach_log("Port accel out = %04x, val = %04x, len = %d.\n", port, val, len); + + if (port & 0x8000) { + mach_accel_out_fifo(mach, svga, dev, port, val, len); + } else { + switch (port) { + case 0x2e8: + if (len == 1) + dev->htotal = (dev->htotal & 0xff00) | val; + else { + dev->htotal = val; + svga_recalctimings(svga); + } + break; + case 0x2e9: + if (len != 1) { + dev->htotal = (dev->htotal & 0xff) | (val << 8); + mach_log("ATI 8514/A: H_TOTAL write 02E8 = %d\n", dev->htotal + 1); + svga_recalctimings(svga); + } + break; + + case 0x6e8: + dev->hdisp = val; + mach_log("ATI 8514/A: H_DISP write 06E8 = %d\n", dev->hdisp + 1); + svga_recalctimings(svga); + break; + + case 0xae8: + mach_log("ATI 8514/A: H_SYNC_STRT write 0AE8 = %d\n", val + 1); + svga_recalctimings(svga); + break; + + case 0xee8: + mach_log("ATI 8514/A: H_SYNC_WID write 0EE8 = %d\n", val + 1); + svga_recalctimings(svga); + break; + + case 0x12e8: + if (len == 1) + dev->vtotal = (dev->vtotal & 0x1f00) | val; + else { + dev->vtotal = val & 0x1fff; + svga_recalctimings(svga); + } + break; + case 0x12e9: + if (len == 1) { + dev->vtotal = (dev->vtotal & 0xff) | ((val & 0x1f) << 8); + mach_log("ATI 8514/A: V_TOTAL write 12E8 = %d\n", dev->vtotal); + svga_recalctimings(svga); + } + break; + + case 0x16e8: + if (len == 1) + dev->vdisp = (dev->vdisp & 0x1f00) | val; + else { + dev->vdisp = val & 0x1fff; + svga_recalctimings(svga); + } + break; + case 0x16e9: + if (len == 1) { + dev->vdisp = (dev->vdisp & 0xff) | ((val & 0x1f) << 8); + mach_log("ATI 8514/A: V_DISP write 16E8 = %d\n", dev->vdisp); + svga_recalctimings(svga); + } + break; + + case 0x1ae8: + if (len == 1) + dev->vsyncstart = (dev->vsyncstart & 0x1f00) | val; + else { + dev->vsyncstart = val & 0x1fff; + svga_recalctimings(svga); + } + break; + case 0x1ae9: + if (len == 1) { + dev->vsyncstart = (dev->vsyncstart & 0xff) | ((val & 0x1f) << 8); + mach_log("ATI 8514/A: V_SYNC_STRT write 1AE8 = %d\n", dev->vsyncstart); + svga_recalctimings(svga); + } + break; + + case 0x1ee8: + dev->vsyncwidth = val; + mach_log("ATI 8514/A: V_SYNC_WID write 1EE8 = %02x\n", val); + svga_recalctimings(svga); + break; + + case 0x22e8: + dev->disp_cntl = val & 0x7e; + dev->interlace = !!(val & 0x10); + mach_log("ATI 8514/A: DISP_CNTL write 22E8 = %02x, SCANMODULOS = %d\n", dev->disp_cntl, dev->scanmodulos); + svga_recalctimings(svga); + break; + + case 0x42e8: + if (len == 1) { + dev->subsys_stat &= ~val; + } else { + dev->subsys_stat &= ~(val & 0xff); + dev->subsys_cntl = (val >> 8); + mach_log("CNTL = %02x.\n", val >> 8); + } + break; + case 0x42e9: + if (len == 1) { + dev->subsys_cntl = val; + mach_log("CNTL = %02x.\n", val); + } + break; + + case 0x4ae8: + mach_log("ATI 8514/A: VGA ON (0x4ae8) = %i, val = %02x\n", vga_on, val); + if (!val) + break; + if (!dev->local || !dev->ext_crt_pitch) + dev->ext_crt_pitch = 128; + dev->accel.advfunc_cntl = val & 7; + ibm8514_on = (dev->accel.advfunc_cntl & 1); + vga_on = !ibm8514_on; + dev->ibm_mode = 1; + if (ibm8514_on) + svga->adv_flags |= FLAG_ATI; + else + svga->adv_flags &= ~FLAG_ATI; + svga_recalctimings(svga); + break; + + /*ATI Mach8/32 specific registers*/ + case 0x6ee: + mach_log("6EE write val = %02x, len = %d.\n", val, len); + break; + + case 0x6ef: + mach_log("6EF write val = %02x, len = %d.\n", val, len); + break; + + case 0xaee: + if (len == 1) + mach->cursor_offset_lo = (mach->cursor_offset_lo & 0xff00) | val; + else { + mach_log("AEE val=%02x.\n", val); + mach->cursor_offset_lo = val; + svga->hwcursor.addr = mach->cursor_offset_lo << 2; + } + break; + case 0xaef: + if (len == 1) { + mach->cursor_offset_lo = (mach->cursor_offset_lo & 0x00ff) | (val << 8); + svga->hwcursor.addr = mach->cursor_offset_lo << 2; + } + break; + + case 0xeee: + mach->cursor_offset_hi = val & 0x0f; + if (len != 1) { + svga->hwcursor.addr = ((mach->cursor_offset_lo | (mach->cursor_offset_hi << 16))) << 2; + svga->hwcursor.ena = !!(val & 0x8000); + } + mach_log("EEE val=%08x.\n", svga->hwcursor.addr); + break; + case 0xeef: + if (len == 1) { + svga->hwcursor.addr = ((mach->cursor_offset_lo | (mach->cursor_offset_hi << 16))) << 2; + svga->hwcursor.ena = !!(val & 0x80); + } + break; + + case 0x12ee: + if (len == 1) { + svga->hwcursor.x = (svga->hwcursor.x & 0x700) | val; + } else { + svga->hwcursor.x = val & 0x7ff; + mach_log("X = %03x.\n", val); + } + break; + case 0x12ef: + if (len == 1) { + svga->hwcursor.x = (svga->hwcursor.x & 0x0ff) | ((val & 0x07) << 8); + } + break; + + case 0x16ee: + if (len == 1) { + svga->hwcursor.y = (svga->hwcursor.y & 0xf00) | val; + } else { + svga->hwcursor.y = val & 0xfff; + } + break; + case 0x16ef: + if (len == 1) { + svga->hwcursor.y = (svga->hwcursor.y & 0x0ff) | ((val & 0x0f) << 8); + } + break; + + case 0x1aee: + if (len != 1) { + mach->cursor_col_0 = val & 0xff; + mach->cursor_col_1 = (val >> 8) & 0xff; + } else + mach->cursor_col_0 = val; + break; + case 0x1aef: + if (len == 1) + mach->cursor_col_1 = val; + break; + + case 0x1eee: + if (len != 1) { + svga->hwcursor.xoff = val & 0x3f; + svga->hwcursor.yoff = (val >> 8) & 0x3f; + } else + svga->hwcursor.xoff = val & 0x3f; + break; + case 0x1eef: + if (len == 1) + svga->hwcursor.yoff = val & 0x3f; + break; + + case 0x2aee: + mach_log("2AEE write val = %04x\n", val); + if (len == 1) + mach->accel.crt_offset_lo = (mach->accel.crt_offset_lo & 0xff00) | val; + else + mach->accel.crt_offset_lo = val; + break; + case 0x2aef: + if (len == 1) + mach->accel.crt_offset_lo = (mach->accel.crt_offset_lo & 0x00ff) | (val << 8); + break; + + case 0x2eee: + mach_log("2EEE write val = %04x\n", val); + if (len == 1) + mach->accel.crt_offset_hi = (mach->accel.crt_offset_hi & 0xff00) | val; + else + mach->accel.crt_offset_hi = val; + break; + case 0x2eef: + if (len == 1) + mach->accel.crt_offset_hi = (mach->accel.crt_offset_hi & 0x00ff) | (val << 8); + break; + + case 0x26ee: + mach_log("CRT Pitch = %d, original val = %d.\n", val << 3, val); + dev->ext_crt_pitch = val; + dev->internal_pitch = val; + if (svga->bpp > 8) { + if (svga->bpp == 24) + dev->ext_crt_pitch *= 3; + else + dev->ext_crt_pitch <<= 1; + } + if (dev->local) { + if (!ibm8514_on) { + ibm8514_on ^= 1; + svga->adv_flags |= FLAG_ATI; + } + } + svga_recalctimings(svga); + break; + + case 0x32ee: + if (len == 1) { + mach->local_cntl = (mach->local_cntl & 0xff00) | val; + } else { + mach->local_cntl = val; + mach32_updatemapping(mach); + } + break; + + case 0x32ef: + if (len == 1) { + mach->local_cntl = (mach->local_cntl & 0x00ff) | (val << 8); + mach32_updatemapping(mach); + } + break; + + case 0x36ee: + if (len == 1) { + mach->misc = (mach->misc & 0xff00) | (val); + } else { + mach->misc = val; + } + break; + case 0x36ef: + if (len == 1) { + mach->misc = (mach->misc & 0x00ff) | (val << 8); + } + break; + + case 0x3aee: + if (len == 1) { + mach->ext_cur_col_0_g = val; + } else { + mach->ext_cur_col_0_g = val & 0xff; + mach->ext_cur_col_0_r = (val >> 8) & 0xff; + } + break; + case 0x3aef: + if (len == 1) { + mach->ext_cur_col_0_r = val; + } + break; + + case 0x3eee: + if (len == 1) { + mach->ext_cur_col_1_g = val; + } else { + mach->ext_cur_col_1_g = val & 0xff; + mach->ext_cur_col_1_r = (val >> 8) & 0xff; + } + break; + case 0x3eef: + if (len == 1) { + mach->ext_cur_col_1_r = val; + } + break; + + case 0x42ee: + mach->accel.test2[0] = val; + break; + case 0x42ef: + mach->accel.test2[1] = val; + break; + + case 0x46ee: + mach->accel.test3[0] = val; + break; + case 0x46ef: + mach->accel.test3[1] = val; + break; + + case 0x4aee: + if (len == 1) + mach->accel.clock_sel = (mach->accel.clock_sel & 0xff00) | val; + else { + mach->accel.clock_sel = val; + ibm8514_on = (mach->accel.clock_sel & 1); + vga_on = !ibm8514_on; + dev->ibm_mode = 0; + if (ibm8514_on) + svga->adv_flags |= FLAG_ATI; + else + svga->adv_flags &= ~FLAG_ATI; + mach_log("ATI 8514/A: VGA ON (0x4aee) = %i, val = %04x\n", vga_on, val); + svga_recalctimings(svga); + } + break; + case 0x4aef: + if (len == 1) { + mach->accel.clock_sel = (mach->accel.clock_sel & 0x00ff) | (val << 8); + ibm8514_on = (mach->accel.clock_sel & 1); + vga_on = !ibm8514_on; + dev->ibm_mode = 0; + if (ibm8514_on) + svga->adv_flags |= FLAG_ATI; + else + svga->adv_flags &= ~FLAG_ATI; + mach_log("ATI 8514/A: VGA ON (0x4aef) = %i, val = %04x\n", vga_on, mach->accel.clock_sel); + svga_recalctimings(svga); + } + break; + + case 0x52ee: + if (len == 1) + mach->accel.scratch0 = (mach->accel.scratch0 & 0xff00) | val; + else + mach->accel.scratch0 = val; + break; + case 0x52ef: + if (len == 1) + mach->accel.scratch0 = (mach->accel.scratch0 & 0x00ff) | (val << 8); + break; + + case 0x56ee: + if (len == 1) + mach->accel.scratch1 = (mach->accel.scratch1 & 0xff00) | val; + else + mach->accel.scratch1 = val; + break; + case 0x56ef: + if (len == 1) + mach->accel.scratch1 = (mach->accel.scratch1 & 0x00ff) | (val << 8); + break; + + case 0x5aee: + mach_log("Shadow set = %04x\n", val); + break; + case 0x5aef: + mach_log("Shadow + 1 set = %02x\n", val); + break; + + case 0x5eee: + mach_log("Memory Aperture = %04x, len = %d.\n", val, len); + if (len == 1) { + mach->memory_aperture = (mach->memory_aperture & 0xff00) | val; + } else { + mach->memory_aperture = val; + if (!mach->pci_bus) + mach->linear_base = (mach->memory_aperture & 0xff00) << 12; + + mach32_updatemapping(mach); + } + break; + + case 0x5eef: + if (len == 1) { + mach->memory_aperture = (mach->memory_aperture & 0x00ff) | (val << 8); + if (!mach->pci_bus) + mach->linear_base = (mach->memory_aperture & 0xff00) << 12; + + mach32_updatemapping(mach); + } + break; + + case 0x62ee: + mach_log("62EE write val = %04x, len = %d.\n", val, len); + break; + + case 0x66ee: + mach_log("66EE write val = %04x, len = %d.\n", val, len); + break; + + case 0x6aee: + mach_log("6AEE write val = %04x.\n", val & 0x400); + if (len == 1) + mach->accel.max_waitstates = (mach->accel.max_waitstates & 0xff00) | val; + else { + mach->accel.max_waitstates = val; + } + break; + case 0x6aef: + if (len == 1) + mach->accel.max_waitstates = (mach->accel.max_waitstates & 0x00ff) | (val << 8); + break; + + case 0x6eee: + mach_log("6EEE write val = %04x\n", val); + if (len == 1) + mach->accel.ge_offset_lo = (mach->accel.ge_offset_lo & 0xff00) | val; + else { + mach->accel.ge_offset_lo = val; + dev->accel.ge_offset = mach->accel.ge_offset_lo; + } + break; + case 0x6eef: + if (len == 1) { + mach->accel.ge_offset_lo = (mach->accel.ge_offset_lo & 0x00ff) | (val << 8); + dev->accel.ge_offset = mach->accel.ge_offset_lo; + } + break; + + case 0x72ee: + mach_log("72EE write val = %04x\n", val); + if (len == 1) + mach->accel.ge_offset_hi = (mach->accel.ge_offset_hi & 0xff00) | val; + else { + mach->accel.ge_offset_hi = val; + dev->accel.ge_offset = mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16); + } + break; + case 0x72ef: + if (len == 1) { + mach->accel.ge_offset_hi = (mach->accel.ge_offset_hi & 0x00ff) | (val << 8); + dev->accel.ge_offset = mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16); + } + break; + + case 0x76ee: + mach_log("76EE write val=%d shifted, normal=%d.\n", val << 3, val); + dev->ext_pitch = val << 3; + svga_recalctimings(svga); + break; + + case 0x7aee: + mach_log("7AEE write val = %04x, len = %d.\n", val, len); + if (len == 1) + mach->accel.ext_ge_config = (mach->accel.ext_ge_config & 0xff00) | val; + else { + mach->accel.ext_ge_config = val; + dev->ext_crt_pitch = dev->internal_pitch; + switch (mach->accel.ext_ge_config & 0x30) { + case 0: + case 0x10: + svga->bpp = 8; + break; + case 0x20: + if ((mach->accel.ext_ge_config & 0xc0) == 0x40) + svga->bpp = 16; + else + svga->bpp = 15; + + dev->ext_crt_pitch <<= 1; + break; + case 0x30: + svga->bpp = 24; + dev->ext_crt_pitch *= 3; + break; + } + if (mach->accel.ext_ge_config & 0x800) { + svga_recalctimings(svga); + } + if (!(mach->accel.ext_ge_config & 0x8000) && !(mach->accel.ext_ge_config & 0x800)) + svga_recalctimings(svga); + } + break; + case 0x7aef: + mach_log("7AEF write val = %02x.\n", val); + if (len == 1) { + mach->accel.ext_ge_config = (mach->accel.ext_ge_config & 0x00ff) | (val << 8); + dev->ext_crt_pitch = dev->internal_pitch; + switch (mach->accel.ext_ge_config & 0x30) { + case 0: + case 0x10: + svga->bpp = 8; + break; + case 0x20: + if ((mach->accel.ext_ge_config & 0xc0) == 0x40) + svga->bpp = 16; + else + svga->bpp = 15; + + dev->ext_crt_pitch <<= 1; + break; + case 0x30: + svga->bpp = 24; + dev->ext_crt_pitch *= 3; + break; + } + if (mach->accel.ext_ge_config & 0x800) { + svga_recalctimings(svga); + } + if (!(mach->accel.ext_ge_config & 0x8000) && !(mach->accel.ext_ge_config & 0x800)) + svga_recalctimings(svga); + } + break; + + case 0x7eee: + mach->accel.eeprom_control = val; + break; + } + } +} + +static uint32_t +mach_accel_in(uint16_t port, mach_t *mach, int len) +{ + svga_t *svga = &mach->svga; + ibm8514_t *dev = &svga->dev8514; + uint16_t *vram_w = (uint16_t *) svga->vram; + uint16_t temp = 0; + int cmd; + int vpos = dev->displine + svga->y_add; + int vblankend = svga->vblankstart + svga->crtc[0x16]; + int frgd_sel, bkgd_sel, mono_src; + + switch (port) { + case 0x2e8: + if (dev->local) { + vpos = svga->displine + svga->y_add; + if (vblankend > svga->vtotal) { + vblankend -= svga->vtotal; + if (vpos >= svga->vblankstart || vpos <= vblankend) + temp |= 2; + } else { + if (vpos >= svga->vblankstart && vpos <= vblankend) + temp |= 2; + } + } else { + vpos = dev->displine + svga->y_add; + if (vblankend > dev->vtotal) { + vblankend -= dev->vtotal; + if (vpos >= svga->vblankstart || vpos <= vblankend) + temp |= 2; + } else { + if (vpos >= svga->vblankstart && vpos <= vblankend) + temp |= 2; + } + } + break; + + case 0x6e8: + temp = dev->hdisp; + break; + + case 0x22e8: + temp = dev->disp_cntl; + break; + + case 0x26e8: + if (len == 1) + temp = dev->htotal & 0xff; + else + temp = dev->htotal; + break; + case 0x26e9: + if (len == 1) + temp = dev->htotal >> 8; + break; + + case 0x2ee8: + temp = dev->subsys_cntl; + break; + + case 0x42e8: + if (dev->local) { + vpos = svga->displine + svga->y_add; + if (vblankend > svga->vtotal) { + vblankend -= svga->vtotal; + if (vpos >= svga->vblankstart || vpos <= vblankend) + dev->subsys_stat |= 1; + } else { + if (vpos >= svga->vblankstart && vpos <= vblankend) + dev->subsys_stat |= 1; + } + } else { + vpos = dev->displine + svga->y_add; + if (vblankend > dev->vtotal) { + vblankend -= dev->vtotal; + if (vpos >= svga->vblankstart || vpos <= vblankend) + dev->subsys_stat |= 1; + } else { + if (vpos >= svga->vblankstart && vpos <= vblankend) + dev->subsys_stat |= 1; + } + } + + if (len != 1) { + temp = dev->subsys_stat | 0xa0 | 0x8000; + } else { + temp = dev->subsys_stat | 0xa0; + } + break; + + case 0x4ae8: + temp = dev->accel.advfunc_cntl; + break; + + case 0x42e9: + if (len == 1) { + temp = dev->subsys_stat >> 8; + temp |= 0x80; + } + break; + + case 0x82e8: + case 0xc2e8: + if (len != 1) { + temp = dev->accel.cur_y; + } + break; + + case 0x86e8: + case 0xc6e8: + if (len != 1) { + temp = dev->accel.cur_x; + } + break; + + case 0x92e8: + if (len != 1) { + temp = dev->test; + } + break; + + case 0x96e8: + if (len != 1) { + temp = dev->accel.maj_axis_pcnt; + } + break; + + case 0x9ae8: + case 0xdae8: + if (len != 1) { + if (dev->force_busy) + temp |= 0x200; /*Hardware busy*/ + dev->force_busy = 0; + if (dev->data_available) { + temp |= 0x100; /*Read Data available*/ + if (mach->accel.cmd_type >= 0) { + switch (mach->accel.cmd_type) { + case 2: + if (dev->accel.sy >= mach->accel.height) + dev->data_available = 0; + break; + case 5: + if (dev->accel.sx >= mach->accel.width) + dev->data_available = 0; + break; + default: + if (dev->accel.sy < 0) + dev->data_available = 0; + break; + } + } else { + if (dev->accel.sy < 0) + dev->data_available = 0; + } + } + } + mach_log("[%04X:%08X]: 9AE8: Temp = %04x, len = %d\n\n", CS, cpu_state.pc, temp, len); + break; + case 0x9ae9: + case 0xdae9: + if (len == 1) { + if (dev->force_busy2) + temp |= 2; /*Hardware busy*/ + dev->force_busy2 = 0; + if (dev->data_available2) { + temp |= 1; /*Read Data available*/ + if (mach->accel.cmd_type >= 0) { + switch (mach->accel.cmd_type) { + case 2: + if (dev->accel.sy >= mach->accel.height) + dev->data_available2 = 0; + break; + case 5: + if (dev->accel.sx >= mach->accel.width) + dev->data_available2 = 0; + break; + default: + if (dev->accel.sy < 0) + dev->data_available2 = 0; + break; + } + } else { + if (dev->accel.sy < 0) + dev->data_available2 = 0; + } + } + } + mach_log("[%04X:%08X]: 9AE9: Temp = %04x, len = %d\n\n", CS, cpu_state.pc, temp, len); + break; + + case 0xe2e8: + case 0xe6e8: + if (mach->accel.cmd_type >= 0) { + if (mach_pixel_read(mach)) { + cmd = -1; + if (len == 1) { + READ_PIXTRANS_BYTE_IO(dev->accel.dx, 1, dev->local) + + temp = mach->accel.pix_trans[1]; + } else { + if (mach->accel.cmd_type == 3) { + READ_PIXTRANS_WORD(dev->accel.cx, 0, dev->local) + } else { + READ_PIXTRANS_WORD(dev->accel.dx, 0, dev->local) + } + mach_accel_out_pixtrans(mach, dev, port, temp, len); + } + } + } else { + if (ibm8514_cpu_dest(svga)) { + cmd = (dev->accel.cmd >> 13); + if (len == 1) { + ; // READ_PIXTRANS_BYTE_IO(0) + } else { + READ_PIXTRANS_WORD(dev->accel.cx, 0, dev->local) + if (dev->accel.input && !dev->accel.odd_in && !dev->accel.sx) { + temp &= ~0xff00; + if (dev->local) + temp |= (svga->vram[(dev->accel.newdest_in + dev->accel.cur_x) & svga->vram_mask] << 8); + else + temp |= (dev->vram[(dev->accel.newdest_in + dev->accel.cur_x) & dev->vram_mask] << 8); + } + if (dev->subsys_stat & 1) { + dev->force_busy = 1; + dev->data_available = 1; + } + } + ibm8514_accel_out_pixtrans(svga, port, temp, len); + } + } + break; + case 0xe2e9: + case 0xe6e9: + if (mach->accel.cmd_type >= 0) { + mach_log("%04x pixtrans read, len=%d.\n", port, len); + if (mach_pixel_read(mach)) { + if (len == 1) { + cmd = -1; + READ_PIXTRANS_BYTE_IO(dev->accel.dx, 0, dev->local) + + temp = mach->accel.pix_trans[0]; + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; + + switch (mach->accel.dp_config & 0x200) { + case 0x000: /*8-bit size*/ + if (mono_src == 2) { + if ((frgd_sel != 2) && (bkgd_sel != 2)) { + mach_accel_start(mach->accel.cmd_type, 1, 8, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + break; + case 0x200: /*16-bit size*/ + if (mono_src == 2) { + if ((frgd_sel != 2) && (bkgd_sel != 2)) { + if (mach->accel.dp_config & 0x1000) + mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[1] | (mach->accel.pix_trans[0] << 8), 0, mach, dev, len); + else + mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + } else + mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), mach, dev, len); + break; + } + } + } + } + break; + + case 0xbee8: + case 0xfee8: + if (len != 1) { + mach_log("Multifunc_cntl = %d.\n", dev->accel.multifunc_cntl >> 12); + switch ((dev->accel.multifunc_cntl >> 12) & 0x0f) { + case 0: + temp = dev->accel.multifunc[0]; + break; + case 1: + temp = dev->accel.clip_top; + break; + case 2: + temp = dev->accel.clip_left; + break; + case 3: + temp = dev->accel.multifunc[3]; + break; + case 4: + temp = dev->accel.multifunc[4]; + break; + case 5: + temp = dev->accel.multifunc[5]; + break; + case 8: + temp = dev->accel.multifunc[8]; + break; + case 9: + temp = dev->accel.multifunc[9]; + break; + case 0x0a: + temp = dev->accel.multifunc[0x0a]; + break; + } + } + break; + +/*ATI Mach8/32 specific registers*/ + case 0x12ee: + if (len == 1) + temp = mach->config1 & 0xff; + else + temp = mach->config1; + break; + case 0x12ef: + if (len == 1) + temp = mach->config1 >> 8; + break; + + case 0x16ee: + if (len == 1) + temp = mach->config2 & 0xff; + else + temp = mach->config2; + break; + case 0x16ef: + if (len == 1) + temp = mach->config2 >> 8; + break; + + case 0x32ee: + if (len == 1) + temp = mach->local_cntl & 0xff; + else + temp = mach->local_cntl; + break; + case 0x32ef: + if (len == 1) + temp = mach->local_cntl >> 8; + break; + + case 0x36ee: + if (len == 1) + temp = mach->misc & 0xff; + else + temp = mach->misc; + break; + case 0x36ef: + if (len == 1) + temp = mach->misc >> 8; + break; + + case 0x42ee: + temp = mach->accel.test2[0]; + break; + case 0x42ef: + temp = mach->accel.test2[1]; + break; + + case 0x46ee: + temp = mach->accel.test3[0]; + break; + case 0x46ef: + temp = mach->accel.test3[1]; + break; + + case 0x4aee: + if (len == 1) + temp = mach->accel.clock_sel & 0xff; + else + temp = mach->accel.clock_sel; + break; + case 0x4aef: + if (len == 1) + temp = mach->accel.clock_sel >> 8; + break; + + case 0x52ee: + if (len == 1) + temp = mach->accel.scratch0 & 0xff; + else + temp = mach->accel.scratch0; + break; + case 0x52ef: + if (len == 1) + temp = mach->accel.scratch0 >> 8; + break; + + case 0x56ee: + if (len == 1) + temp = mach->accel.scratch1 & 0xff; + else + temp = mach->accel.scratch1; + break; + case 0x56ef: + if (len == 1) + temp = mach->accel.scratch1 >> 8; + break; + + case 0x5eee: + if (mach->pci_bus) + mach->memory_aperture = (mach->memory_aperture & ~0xfff0) | ((mach->linear_base >> 20) << 4); + + if (len == 1) + temp = mach->memory_aperture & 0xff; + else + temp = mach->memory_aperture; + break; + case 0x5eef: + if (len == 1) + temp = mach->memory_aperture >> 8; + break; + + case 0x62ee: + temp = mach->accel.clip_overrun; + if (len != 1) { + if (mach->force_busy) + temp |= 0x2000; + mach->force_busy = 0; + if (ati_eeprom_read(&mach->eeprom)) + temp |= 0x4000; + } + mach_log("[%04X:%08X]: 62EE: Temp = %04x, len = %d\n\n", CS, cpu_state.pc, temp, len); + break; + case 0x62ef: + if (len == 1) { + if (mach->force_busy2) + temp |= 0x20; + mach->force_busy2 = 0; + if (ati_eeprom_read(&mach->eeprom)) + temp |= 0x40; + } + mach_log("[%04X:%08X]: 62EF: Temp = %04x, len = %d\n\n", CS, cpu_state.pc, temp, len); + break; + + case 0x6aee: + if (len == 1) + temp = mach->accel.max_waitstates & 0xff; + else + temp = mach->accel.max_waitstates; + break; + case 0x6aef: + if (len == 1) + temp = mach->accel.max_waitstates >> 8; + break; + + case 0x72ee: + if (len == 1) + temp = dev->accel.clip_left & 0xff; + else + temp = dev->accel.clip_left; + break; + case 0x72ef: + if (len == 1) + temp = dev->accel.clip_left >> 8; + break; + + case 0x76ee: + if (len == 1) + temp = dev->accel.clip_top & 0xff; + else + temp = dev->accel.clip_top; + break; + case 0x76ef: + if (len == 1) + temp = dev->accel.clip_top >> 8; + break; + + case 0x7aee: + if (len == 1) + temp = dev->accel.multifunc[4] & 0xff; + else + temp = dev->accel.multifunc[4]; + break; + case 0x7aef: + if (len == 1) + temp = dev->accel.multifunc[4] >> 8; + break; + + case 0x7eee: + if (len == 1) + temp = dev->accel.multifunc[3] & 0xff; + else + temp = dev->accel.multifunc[3]; + break; + case 0x7eef: + if (len == 1) + temp = dev->accel.multifunc[3] >> 8; + break; + + case 0x82ee: + temp = mach->accel.patt_data_idx; + break; + + case 0x8eee: + if (len == 1) + temp = mach->accel.ext_ge_config & 0xff; + else + temp = mach->accel.ext_ge_config; + break; + case 0x8eef: + if (len == 1) + temp = mach->accel.ext_ge_config >> 8; + break; + + case 0x92ee: + temp = mach->accel.eeprom_control; + break; + + case 0x96ee: + if (len == 1) { + temp = dev->accel.maj_axis_pcnt & 0xff; + } else { + temp = dev->accel.maj_axis_pcnt; + if ((mach->accel.test == 0x1555) || (mach->accel.test == 0x0aaa)) + temp = mach->accel.test; + } + break; + case 0x96ef: + if (len == 1) + temp = dev->accel.maj_axis_pcnt >> 8; + break; + + case 0xa2ee: + if (len == 1) + temp = mach->accel.linedraw_opt & 0xff; + else { + temp = mach->accel.linedraw_opt; + } + break; + case 0xa2ef: + if (len == 1) + temp = mach->accel.linedraw_opt >> 8; + break; + + case 0xb2ee: + if (len == 1) + temp = dev->hdisp; + else { + temp = dev->hdisp & 0xff; + temp |= (dev->htotal << 8); + mach_log("HDISP read=%d, HTOTAL read=%d.\n", temp & 0xff, temp >> 8); + } + break; + case 0xb2ef: + if (len == 1) { + temp = dev->htotal; + } + break; + + case 0xc2ee: + if (len == 1) + temp = dev->vtotal & 0xff; + else { + temp = dev->vtotal; + mach_log("VTOTAL read=%d.\n", temp); + } + break; + case 0xc2ef: + if (len == 1) + temp = dev->vtotal >> 8; + break; + + case 0xc6ee: + if (len == 1) + temp = dev->vdisp & 0xff; + else { + temp = dev->vdisp; + mach_log("VDISP read=%d.\n", temp); + } + break; + case 0xc6ef: + if (len == 1) + temp = dev->vdisp >> 8; + break; + + case 0xcaee: + if (len == 1) + temp = dev->vsyncstart & 0xff; + else + temp = dev->vsyncstart; + break; + case 0xcaef: + if (len == 1) + temp = dev->vsyncstart >> 8; + break; + + case 0xceee: + if (len == 1) + temp = svga->vc & 0xff; + else + temp = svga->vc & 0x7ff; + break; + case 0xceef: + if (len == 1) + temp = (svga->vc >> 8) & 7; + break; + + case 0xdaee: + if (len != 1) { + temp = mach->accel.src_x; + if (dev->local) { + temp &= 0x7ff; + } + } else + temp = dev->accel.destx_distp & 0xff; + break; + case 0xdaef: + if (len == 1) + temp = dev->accel.destx_distp >> 8; + break; + + case 0xdeee: + if (len != 1) { + temp = mach->accel.src_y; + if (dev->local) + temp &= 0x7ff; + } else + temp = dev->accel.desty_axstp & 0xff; + break; + case 0xdeef: + if (len == 1) + temp = dev->accel.desty_axstp >> 8; + break; + + case 0xfaee: + if (len != 1) { + if (mach->pci_bus) + temp = 0x0017; + else + temp = 0x22f7; + } else { + if (mach->pci_bus) + temp = 0x17; + else + temp = 0xf7; + } + break; + case 0xfaef: + if (len == 1) { + if (mach->pci_bus) + temp = 0x00; + else + temp = 0x22; + } + break; + } + if (port != 0x9ae8 && port != 0x9ae9 && port != 0x62ee && port != 0x9aee) { + mach_log("Port accel in = %04x, temp = %04x, len = %d, mode = %d.\n", port, temp, len, dev->ibm_mode); + } + return temp; +} + +static void +mach_accel_outb(uint16_t port, uint8_t val, void *p) +{ + mach_t *mach = (mach_t *) p; + mach_accel_out(port, val, mach, 1); +} + +static void +mach_accel_outw(uint16_t port, uint16_t val, void *p) +{ + mach_t *mach = (mach_t *) p; + mach_accel_out(port, val, mach, 2); +} + +static uint8_t +mach_accel_inb(uint16_t port, void *p) +{ + mach_t *mach = (mach_t *) p; + return mach_accel_in(port, mach, 1); +} + +static uint16_t +mach_accel_inw(uint16_t port, void *p) +{ + mach_t *mach = (mach_t *) p; + return mach_accel_in(port, mach, 2); +} + +static void +mach32_ap_writeb(uint32_t addr, uint8_t val, void *p) +{ + mach_t *mach = (mach_t *) p; + uint8_t port_dword = addr & 0xfc; + + if (((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { + if (addr & 0x100) { + mach_log("Port WORDB Write=%04x.\n", 0x02ee + (port_dword << 8)); + mach_accel_outb(0x02ee + (addr & 1) + (port_dword << 8), val, mach); + } else { + mach_log("Port WORDB Write=%04x.\n", 0x02e8 + (port_dword << 8)); + mach_accel_outb(0x02e8 + (addr & 1) + (port_dword << 8), val, mach); + } + } else { + mach_log("Linear WORDB Write=%08x.\n", addr); + svga_write_linear(addr, val, &mach->svga); + } +} + +static void +mach32_ap_writew(uint32_t addr, uint16_t val, void *p) +{ + mach_t *mach = (mach_t *) p; + uint8_t port_dword = addr & 0xfc; + + if (((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { + if (addr & 0x100) { + mach_log("Port WORDW Write=%04x.\n", 0x02ee + (port_dword << 8)); + mach_accel_outw(0x02ee + (port_dword << 8), val, mach); + } else { + mach_log("Port WORDW Write=%04x.\n", 0x02e8 + (port_dword << 8)); + mach_accel_outw(0x02e8 + (port_dword << 8), val, mach); + } + } else { + mach_log("Linear WORDW Write=%08x.\n", addr); + svga_writew_linear(addr, val, &mach->svga); + } +} + +static void +mach32_ap_writel(uint32_t addr, uint32_t val, void *p) +{ + mach_t *mach = (mach_t *) p; + uint8_t port_dword = addr & 0xfc; + + if (((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { + if (addr & 0x100) { + mach_log("Port WORDL Write=%04x.\n", 0x02ee + (port_dword << 8)); + mach_accel_outw(0x02ee + (port_dword << 8), val & 0xffff, mach); + mach_accel_outw(0x02ee + (port_dword << 8) + 4, val >> 16, mach); + } else { + mach_log("Port WORDL Write=%04x.\n", 0x02e8 + (port_dword << 8)); + mach_accel_outw(0x02e8 + (port_dword << 8), val & 0xffff, mach); + mach_accel_outw(0x02e8 + (port_dword << 8) + 4, val >> 16, mach); + } + } else { + mach_log("Linear WORDL Write=%08x, val=%08x, mode=%d, rop=%02x.\n", addr, val, mach->svga.writemode, mach->svga.gdcreg[3] & 0x18); + svga_writel_linear(addr, val, &mach->svga); + } +} + +static uint8_t +mach32_ap_readb(uint32_t addr, void *p) +{ + mach_t *mach = (mach_t *) p; + uint8_t temp; + uint8_t port_dword = addr & 0xfc; + + if (((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { + if (addr & 0x100) { + temp = mach_accel_inb(0x02ee + (addr & 1) + (port_dword << 8), mach); + } else { + temp = mach_accel_inb(0x02e8 + (addr & 1) + (port_dword << 8), mach); + } + } else + temp = svga_read_linear(addr, &mach->svga); + + return temp; +} + +static uint16_t +mach32_ap_readw(uint32_t addr, void *p) +{ + mach_t *mach = (mach_t *) p; + uint16_t temp; + uint8_t port_dword = addr & 0xfc; + + if (((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { + if (addr & 0x100) { + temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); + } else { + temp = mach_accel_inw(0x02e8 + (port_dword << 8), mach); + } + } else + temp = svga_readw_linear(addr, &mach->svga); + + return temp; +} + +static uint32_t +mach32_ap_readl(uint32_t addr, void *p) +{ + mach_t *mach = (mach_t *) p; + uint32_t temp; + uint8_t port_dword = addr & 0xfc; + + if (((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { + if (addr & 0x100) { + temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); + temp |= (mach_accel_inw(0x02ee + (port_dword << 8) + 4, mach) << 8); + } else { + temp = mach_accel_inw(0x02e8 + (port_dword << 8), mach); + temp |= (mach_accel_inw(0x02e8 + (port_dword << 8) + 4, mach) << 8); + } + } else + temp = svga_readl_linear(addr, &mach->svga); + + return temp; +} + +static void +mach32_updatemapping(mach_t *mach) +{ + svga_t *svga = &mach->svga; + + if ((mach->pci_bus && (!(mach->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)))) { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&mach->mmio_linear_mapping); + return; + } + + if (mach->regs[0xbd] & 4) { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + mach_log("Bit 2 of BD.\n"); + } else { + switch (svga->gdcreg[6] & 0x0c) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + + mach_log("Linear base = %08x, aperture = %04x, localcntl = %02x svgagdc = %x.\n", mach->linear_base, mach->memory_aperture, mach->local_cntl, svga->gdcreg[6] & 0x0c); + if (mach->linear_base) { + if (((mach->memory_aperture & 3) == 1) && !mach->pci_bus) { + /*1 MB aperture*/ + mach->ap_size = 1; + mem_mapping_set_addr(&mach->mmio_linear_mapping, mach->linear_base, mach->ap_size << 20); + } else { + /*4 MB aperture*/ + mach->ap_size = 4; + mem_mapping_set_addr(&mach->mmio_linear_mapping, mach->linear_base, mach->ap_size << 20); + } + /*Force IBM/ATI mode on when the MMIO registers are loaded.*/ + if (mach->local_cntl & 0x20) { + if (!ibm8514_on) { + ibm8514_on ^= 1; + svga->adv_flags |= FLAG_ATI; + svga_recalctimings(svga); + } + } + } else { + mach->ap_size = 4; + mem_mapping_disable(&mach->mmio_linear_mapping); + } +} + +static void +mach32_hwcursor_draw(svga_t *svga, int displine) +{ + mach_t *mach = (mach_t *) svga->p; + uint16_t dat; + int comb; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + uint32_t color0, color1; + + if (svga->bpp == 8) { + color0 = svga->pallook[mach->cursor_col_0]; + color1 = svga->pallook[mach->cursor_col_1]; + mach_log("8BPP: Offset = %x, XOFF = %02x, YOFF = %02x.\n", offset, svga->hwcursor_latch.xoff, svga->hwcursor_latch.yoff); + } else if (svga->bpp == 15) { + color0 = video_15to32[((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0) & 0xffff]; + color1 = video_15to32[((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1) & 0xffff]; + mach_log("15BPP: Offset = %x, XOFF = %02x, YOFF = %02x.\n", offset, svga->hwcursor_latch.xoff, svga->hwcursor_latch.yoff); + } else if (svga->bpp == 16) { + color0 = video_16to32[((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0) & 0xffff]; + color1 = video_16to32[((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1) & 0xffff]; + mach_log("16BPP: Offset = %x, XOFF = %02x, YOFF = %02x.\n", offset, svga->hwcursor_latch.xoff, svga->hwcursor_latch.yoff); + } else { + color0 = ((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0); + color1 = ((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1); + mach_log("24BPP: Offset = %x, XOFF = %02x, YOFF = %02x.\n", offset, svga->hwcursor_latch.xoff, svga->hwcursor_latch.yoff); + } + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; + + for (int x = 0; x < 64; x += 8) { + dat = svga->vram[svga->hwcursor_latch.addr & svga->vram_mask] | (svga->vram[(svga->hwcursor_latch.addr + 1) & svga->vram_mask] << 8); + for (int xx = 0; xx < 8; xx++) { + comb = (dat >> (xx << 1)) & 0x03; + if (offset >= svga->hwcursor_latch.x) { + switch (comb) { + case 0: + ((uint32_t *) svga->monitor->target_buffer->line[displine])[offset + svga->x_add] = color0; + break; + case 1: + ((uint32_t *) svga->monitor->target_buffer->line[displine])[offset + svga->x_add] = color1; + break; + case 3: + ((uint32_t *) svga->monitor->target_buffer->line[displine])[offset + svga->x_add] ^= 0xffffff; + break; + } + } + offset++; + } + svga->hwcursor_latch.addr += 2; + } + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; +} + +static void +mach_io_remove(mach_t *mach) +{ + io_removehandler(0x01ce, 2, + mach_in, NULL, NULL, + mach_out, NULL, NULL, mach); + io_removehandler(0x03c0, 32, + mach_in, NULL, NULL, + mach_out, NULL, NULL, mach); + + io_removehandler(0x2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x2ea, 0x0004, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); + io_removehandler(0x6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x12e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x16e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x1ae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x1ee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x22e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x26e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x2ee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x42e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x4ae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x52e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x56e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x5ae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x5ee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x82e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x86e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x8ae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x8ee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x92e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x96e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x9ae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x9ee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xa2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xa6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xaae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xaee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xb2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xb6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xbae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xbee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xe2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + + io_removehandler(0xc2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xc6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xcae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xcee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xd2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xd6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xdae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xdee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xe6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xeae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xeee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xf2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xf6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xfae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xfee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + + io_removehandler(0x06ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x0aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x0eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x12ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x16ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x1aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x1eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x26ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x2aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x2eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x32ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x36ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x3aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x3eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x42ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x46ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x4aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x52ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x56ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x5aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x5eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x62ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x66ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x6aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x6eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x72ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x76ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x7aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x7eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x82ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x8eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x92ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x96ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0x9aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xa2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xa6ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xaaee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xaeee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xb2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xb6ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xbaee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xbeee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xc2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xc6ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xcaee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xceee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xd2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xd6ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xdaee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xdeee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xe2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xe6ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xeeee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xf2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xfaee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_removehandler(0xfeee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); +} + +static void +mach_io_set(mach_t *mach) +{ + io_sethandler(0x01ce, 2, + mach_in, NULL, NULL, + mach_out, NULL, NULL, mach); + io_sethandler(0x03c0, 32, + mach_in, NULL, NULL, + mach_out, NULL, NULL, mach); + + io_sethandler(0x2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x2ea, 0x0004, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); + io_sethandler(0x6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x12e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x16e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x1ae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x1ee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x22e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x26e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x2ee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x42e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x4ae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x52e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x56e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x5ae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x5ee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x82e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x86e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x8ae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x8ee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x92e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x96e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x9ae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x9ee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xa2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xa6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xaae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xaee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xb2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xb6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xbae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xbee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xe2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + + io_sethandler(0xc2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xc6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xcae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xcee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xd2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xd6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xdae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xdee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xe6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xeae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xeee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xf2e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xf6e8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xfae8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xfee8, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + + io_sethandler(0x06ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x0aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x0eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x12ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x16ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x1aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x1eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x26ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x2aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x2eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x32ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x36ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x3aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x3eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x42ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x46ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x4aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x52ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x56ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x5aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x5eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x62ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x66ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x6aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x6eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x72ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x76ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x7aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x7eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x82ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x8eee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x92ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x96ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0x9aee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xa2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xa6ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xaaee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xaeee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xb2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xb6ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xbaee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xbeee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xc2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xc6ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xcaee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xceee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xd2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xd6ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xdaee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xdeee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xe2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xe6ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xeeee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xf2ee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xfaee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); + io_sethandler(0xfeee, 0x0002, mach_accel_inb, mach_accel_inw, NULL, mach_accel_outb, mach_accel_outw, NULL, mach); +} + +static uint8_t +mach32_pci_read(int func, int addr, void *p) +{ + mach_t *mach = (mach_t *) p; + svga_t *svga = &mach->svga; + uint8_t ret = 0x00; + + switch (addr) { + case 0x00: + ret = 0x02; /*ATI*/ + break; + case 0x01: + ret = 0x10; + break; + + case 0x02: + ret = 0x58; + break; + case 0x03: + ret = 0x41; + break; + + case PCI_REG_COMMAND: + ret = mach->pci_regs[PCI_REG_COMMAND] | 0x80; /*Respond to IO and memory accesses*/ + break; + + case 0x07: + ret = 0x01; /*Medium DEVSEL timing*/ + break; + + case 0x0a: + ret = 0x00; /*Supports VGA interface*/ + break; + case 0x0b: + ret = 0x03; + break; + + case 0x10: + ret = 0x00; /*Linear frame buffer address*/ + break; + case 0x11: + ret = 0x00; + break; + case 0x12: + ret = mach->linear_base >> 16; + break; + case 0x13: + ret = mach->linear_base >> 24; + break; + + case 0x30: + ret = (mach->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ + break; + case 0x31: + ret = 0x00; + break; + case 0x32: + ret = mach->pci_regs[0x32]; + break; + case 0x33: + ret = mach->pci_regs[0x33]; + break; + + case 0x3c: + ret = mach->int_line; + break; + case 0x3d: + ret = PCI_INTA; + break; + } + + return ret; +} + +static void +mach32_pci_write(int func, int addr, uint8_t val, void *p) +{ + mach_t *mach = (mach_t *) p; + svga_t *svga = &mach->svga; + + switch (addr) { + case PCI_REG_COMMAND: + mach->pci_regs[PCI_REG_COMMAND] = val & 0x27; + mach_io_remove(mach); + if (val & PCI_COMMAND_IO) { + mach_io_set(mach); + } + mach32_updatemapping(mach); + break; + + case 0x12: + mach->linear_base = (mach->linear_base & 0xff000000) | ((val & 0xc0) << 16); + mach32_updatemapping(mach); + break; + case 0x13: + mach->linear_base = (mach->linear_base & 0xc00000) | (val << 24); + mach32_updatemapping(mach); + break; + + case 0x30: + case 0x32: + case 0x33: + mach->pci_regs[addr] = val; + if (mach->pci_regs[0x30] & 0x01) { + uint32_t bios_addr = (mach->pci_regs[0x32] << 16) | (mach->pci_regs[0x33] << 24); + mach_log("Mach32 bios_rom enabled at %08x\n", bios_addr); + mem_mapping_set_addr(&mach->bios_rom.mapping, bios_addr, 0x8000); + } else { + mach_log("Mach32 bios_rom disabled\n"); + mem_mapping_disable(&mach->bios_rom.mapping); + } + return; + + case 0x3c: + mach->int_line = val; + break; + } +} + +static void * +mach8_init(const device_t *info) +{ + mach_t *mach; + svga_t *svga; + ibm8514_t *dev; + uint32_t memory; + + mach = malloc(sizeof(mach_t)); + memset(mach, 0x00, sizeof(mach_t)); + + svga = &mach->svga; + dev = &svga->dev8514; + + mach->pci_bus = !!(info->flags & DEVICE_PCI); + mach->vlb_bus = !!(info->flags & DEVICE_VLB); + dev->local = info->local; + dev->vram_size = (1024 << 10); + dev->vram = calloc(dev->vram_size, 1); + dev->changedvram = calloc(dev->vram_size >> 12, 1); + dev->vram_mask = dev->vram_size - 1; + dev->map8 = svga->pallook; + memory = device_get_config_int("memory"); + + if (dev->local) { + if (mach->vlb_bus) + rom_init(&mach->bios_rom, + BIOS_MACH32_VLB_ROM_PATH, + 0xc0000, 0x8000, 0x7fff, + 0, MEM_MAPPING_EXTERNAL); + else if (mach->pci_bus) + rom_init(&mach->bios_rom, + BIOS_MACH32_PCI_ROM_PATH, + 0xc0000, 0x8000, 0x7fff, + 0, MEM_MAPPING_EXTERNAL); + else + rom_init(&mach->bios_rom, + BIOS_MACH32_ISA_ROM_PATH, + 0xc0000, 0x8000, 0x7fff, + 0, MEM_MAPPING_EXTERNAL); + } else { + rom_init(&mach->bios_rom, + BIOS_MACH8_ROM_PATH, + 0xc0000, 0x8000, 0x7fff, + 0, MEM_MAPPING_EXTERNAL); + } + + svga_init(info, svga, mach, dev->local ? (memory << 10) : (512 << 10), /*default: 512kB for Mach8, 2MB for Mach32*/ + mach_recalctimings, + mach_in, mach_out, + dev->local ? mach32_hwcursor_draw : NULL, + NULL); + + if (dev->local) { + switch (memory) { + case 1024: + mach->misc |= 0x04; + break; + case 2048: + mach->misc |= 0x08; + break; + case 4096: + mach->misc |= 0x0c; + break; + } + svga->hwcursor.cur_ysize = 64; + mach->config1 = 0x20; + mach->config2 = 0x08; + /*Fake the RAMDAC to give the VLB/MCA variants full 24-bit support until said RAMDAC is implemented.*/ + if (mach->vlb_bus) { + video_inform(VIDEO_FLAG_TYPE_8514, &timing_mach32_vlb); + mach->config1 |= 0x0c; + mach->config1 |= 0x0400; + } else if (mach->pci_bus) { + video_inform(VIDEO_FLAG_TYPE_8514, &timing_mach32_pci); + mach->config1 |= 0x0e; + mach->config1 |= 0x0a00; + mach->config2 |= 0x2000; + svga->ramdac = device_add(&ati68860_ramdac_device); + } else { + video_inform(VIDEO_FLAG_TYPE_8514, &timing_gfxultra_isa); + } + mem_mapping_add(&mach->mmio_linear_mapping, 0, 0, mach32_ap_readb, mach32_ap_readw, mach32_ap_readl, mach32_ap_writeb, mach32_ap_writew, mach32_ap_writel, NULL, MEM_MAPPING_EXTERNAL, mach); + mem_mapping_disable(&mach->mmio_linear_mapping); + } else { + video_inform(VIDEO_FLAG_TYPE_8514, &timing_gfxultra_isa); + mach->config1 = 0x02 | 0x20 | 0x80; + mach->config2 = 0x02; + dev->ext_pitch = 1024; + } + + svga->force_old_addr = 1; + svga->miscout = 1; + svga->bpp = 8; + svga->packed_chain4 = 1; + ibm8514_enabled = 1; + ibm8514_has_vga = 1; + dev->ibm_mode = 1; + dev->rowoffset = 128; + mach_io_set(mach); + + if (dev->local) { + svga->decode_mask = (4 << 20) - 1; + mach->cursor_col_1 = 0xff; + mach->ext_cur_col_1_r = 0xff; + mach->ext_cur_col_1_g = 0xff; + dev->ext_crt_pitch = 128; + if (mach->vlb_bus) + ati_eeprom_load(&mach->eeprom, "mach32_vlb.nvr", 1); + else if (mach->pci_bus) { + ati_eeprom_load(&mach->eeprom, "mach32_pci.nvr", 1); + mem_mapping_disable(&mach->bios_rom.mapping); + mach->card = pci_add_card(PCI_ADD_VIDEO, mach32_pci_read, mach32_pci_write, mach); + mach->pci_regs[PCI_REG_COMMAND] = 0x83; + mach->pci_regs[0x30] = 0x00; + mach->pci_regs[0x32] = 0x0c; + mach->pci_regs[0x33] = 0x00; + } else + ati_eeprom_load(&mach->eeprom, "mach32.nvr", 1); + } else { + ati_eeprom_load_mach8(&mach->eeprom, "mach8.nvr"); + } + + return (mach); +} + +static int +mach8_available(void) +{ + return rom_present(BIOS_MACH8_ROM_PATH); +} + +static int +mach32_isa_available(void) +{ + return rom_present(BIOS_MACH32_ISA_ROM_PATH); +} + +static int +mach32_vlb_available(void) +{ + return rom_present(BIOS_MACH32_VLB_ROM_PATH); +} + +static int +mach32_pci_available(void) +{ + return rom_present(BIOS_MACH32_PCI_ROM_PATH); +} + +static void +mach_close(void *p) +{ + mach_t *mach = (mach_t *) p; + svga_t *svga = &mach->svga; + ibm8514_t *dev = &svga->dev8514; + + if (dev) { + free(dev->vram); + free(dev->changedvram); + } + + svga_close(svga); + free(mach); +} + +static void +mach_speed_changed(void *p) +{ + mach_t *mach = (mach_t *) p; + svga_t *svga = &mach->svga; + + svga_recalctimings(svga); +} + +static void +mach_force_redraw(void *p) +{ + mach_t *mach = (mach_t *) p; + svga_t *svga = &mach->svga; + + svga->fullchange = changeframecount; +} + +// clang-format off +static const device_config_t mach32_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 2048, + .selection = { + { + .description = "512 KB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "2 MB", + .value = 2048 + }, + { + .description = "4 MB", + .value = 4096 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } +}; + +const device_t mach8_isa_device = { + .name = "ATI Mach8 (ISA)", + .internal_name = "mach8_isa", + .flags = DEVICE_ISA, + .local = 0, + .init = mach8_init, + .close = mach_close, + .reset = NULL, + { .available = mach8_available }, + .speed_changed = mach_speed_changed, + .force_redraw = mach_force_redraw, + .config = NULL +}; + +const device_t mach32_isa_device = { + .name = "ATI Mach32 (ISA)", + .internal_name = "mach32_isa", + .flags = DEVICE_ISA, + .local = 1, + .init = mach8_init, + .close = mach_close, + .reset = NULL, + { .available = mach32_isa_available }, + .speed_changed = mach_speed_changed, + .force_redraw = mach_force_redraw, + .config = mach32_config +}; + +const device_t mach32_vlb_device = { + .name = "ATI Mach32 (VLB)", + .internal_name = "mach32_vlb", + .flags = DEVICE_VLB, + .local = 1, + .init = mach8_init, + .close = mach_close, + .reset = NULL, + { .available = mach32_vlb_available }, + .speed_changed = mach_speed_changed, + .force_redraw = mach_force_redraw, + .config = mach32_config +}; + +const device_t mach32_pci_device = { + .name = "ATI Mach32 (PCI)", + .internal_name = "mach32_pci", + .flags = DEVICE_PCI, + .local = 1, + .init = mach8_init, + .close = mach_close, + .reset = NULL, + { .available = mach32_pci_available }, + .speed_changed = mach_speed_changed, + .force_redraw = mach_force_redraw, + .config = mach32_config +}; diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index d8829eb2f..913a052ff 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -41,6 +41,7 @@ #include <86box/video.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> +#include <86box/vid_xga_device.h> void svga_doblit(int wx, int wy, svga_t *svga); @@ -131,7 +132,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) if (svga->attraddr < 16) svga->fullchange = svga->monitor->mon_changeframecount; if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { - for (uint8_t c = 0; c < 16; c++) { + for (int c = 0; c < 16; c++) { if (svga->attrregs[0x10] & 0x80) { svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); } else { @@ -165,6 +166,12 @@ svga_out(uint16_t addr, uint8_t val, void *p) io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); svga_recalctimings(svga); break; + case 0x3c3: + if (xga_enabled) { + svga->xga.on = (val & 0x01) ? 0 : 1; + vga_on = !svga->xga.on; + } + break; case 0x3c4: svga->seqaddr = val; break; @@ -407,7 +414,7 @@ svga_set_ramdac_type(svga_t *svga, int type) if (svga->ramdac_type != type) { svga->ramdac_type = type; - for (uint16_t c = 0; c < 256; c++) { + for (int c = 0; c < 256; c++) { if (svga->ramdac_type == RAMDAC_8BIT) svga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b); else @@ -583,8 +590,14 @@ svga_recalctimings(svga_t *svga) svga->recalctimings_ex(svga); } } else { - if (ibm8514_enabled) - ibm8514_recalctimings(svga); + if (ibm8514_enabled) { + if (svga->dev8514.local) { + if (svga->recalctimings_ex) { + svga->recalctimings_ex(svga); + } + } else + ibm8514_recalctimings(svga); + } if (xga_enabled) xga_recalctimings(svga); } @@ -597,8 +610,13 @@ svga_recalctimings(svga_t *svga) crtcconst = svga->clock * svga->char_width; - disptime = svga->htotal; - _dispontime = svga->hdisp_time; + if (ibm8514_on && !svga->dev8514.local) { + disptime = svga->dev8514.h_total; + _dispontime = svga->dev8514.h_disp; + } else { + disptime = svga->htotal; + _dispontime = svga->hdisp_time; + } if (svga->seqregs[1] & 8) { disptime *= 2; @@ -678,16 +696,20 @@ void svga_poll(void *p) { svga_t *svga = (svga_t *) p; + ibm8514_t *dev = &svga->dev8514; uint32_t x; uint32_t blink_delay; int wx; int wy; int ret; int old_ma; + int linecountff = 0; if (!vga_on && ibm8514_enabled && ibm8514_on) { - ibm8514_poll(&svga->dev8514, svga); - return; + if (!dev->local) { + ibm8514_poll(dev, svga); + return; + } } else if (!vga_on && xga_enabled && svga->xga.on) { xga_poll(&svga->xga, svga); return; @@ -695,22 +717,22 @@ svga_poll(void *p) if (!svga->linepos) { if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { - svga->hwcursor_on = svga->hwcursor.cur_ysize - svga->hwcursor_latch.yoff; + svga->hwcursor_on = svga->hwcursor_latch.cur_ysize - svga->hwcursor_latch.yoff; svga->hwcursor_oddeven = 0; } if (svga->displine == (svga->hwcursor_latch.y + 1) && svga->hwcursor_latch.ena && svga->interlace) { - svga->hwcursor_on = svga->hwcursor.cur_ysize - (svga->hwcursor_latch.yoff + 1); + svga->hwcursor_on = svga->hwcursor_latch.cur_ysize - (svga->hwcursor_latch.yoff + 1); svga->hwcursor_oddeven = 1; } if (svga->displine == svga->dac_hwcursor_latch.y && svga->dac_hwcursor_latch.ena) { - svga->dac_hwcursor_on = svga->dac_hwcursor.cur_ysize - svga->dac_hwcursor_latch.yoff; + svga->dac_hwcursor_on = svga->dac_hwcursor_latch.cur_ysize - svga->dac_hwcursor_latch.yoff; svga->dac_hwcursor_oddeven = 0; } if (svga->displine == (svga->dac_hwcursor_latch.y + 1) && svga->dac_hwcursor_latch.ena && svga->interlace) { - svga->dac_hwcursor_on = svga->dac_hwcursor.cur_ysize - (svga->dac_hwcursor_latch.yoff + 1); + svga->dac_hwcursor_on = svga->dac_hwcursor_latch.cur_ysize - (svga->dac_hwcursor_latch.yoff + 1); svga->dac_hwcursor_oddeven = 1; } @@ -783,8 +805,14 @@ svga_poll(void *p) if ((svga->sc == (svga->crtc[11] & 31)) || (svga->sc == svga->rowcount)) svga->con = 0; if (svga->dispon) { - if (svga->linedbl && !svga->linecountff) { - svga->linecountff = 1; + /*Real IBM 8514/A or compatibility mode doesn't have linedbl, so skip those.*/ + if (dev->local && ibm8514_on) { + svga->linedbl = 0; + svga->linecountff = 0; + linecountff = 1; + } + if (svga->linedbl && !svga->linecountff && !linecountff) { + svga->linecountff = 1; svga->ma = svga->maback; } else if (svga->sc == svga->rowcount) { svga->linecountff = 0; @@ -793,23 +821,24 @@ svga_poll(void *p) svga->maback += (svga->rowoffset << 3); if (svga->interlace) svga->maback += (svga->rowoffset << 3); + svga->maback &= svga->vram_display_mask; svga->ma = svga->maback; } else { svga->linecountff = 0; svga->sc++; - svga->sc &= 31; + svga->sc &= 0x1f; svga->ma = svga->maback; } } - svga->hsync_divisor = !svga->hsync_divisor; + svga->hsync_divisor ^= 1; if (svga->hsync_divisor && (svga->crtc[0x17] & 4)) return; svga->vc++; - svga->vc &= 2047; + svga->vc &= 0x7ff; if (svga->vc == svga->split) { ret = 1; @@ -835,6 +864,7 @@ svga_poll(void *p) if (svga->vc == svga->dispend) { if (svga->vblank_start) svga->vblank_start(svga); + svga->dispon = 0; blink_delay = (svga->crtc[11] & 0x60) >> 5; if (svga->crtc[10] & 0x20) @@ -846,6 +876,7 @@ svga_poll(void *p) if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) svga->fullchange = 2; + svga->blink = (svga->blink + 1) & 0x7f; for (x = 0; x < ((svga->vram_mask + 1) >> 12); x++) { @@ -888,12 +919,18 @@ svga_poll(void *p) svga->monitor->mon_changeframecount = svga->interlace ? 3 : 2; svga->vslines = 0; - if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[5] & 0x60) >> 5); - else - svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[5] & 0x60) >> 5); + if ((dev->local && vga_on) || !dev->local) { + if (svga->interlace && svga->oddeven) + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + ((svga->crtc[5] & 0x60) >> 5); + else + svga->ma = svga->maback = svga->ma_latch + ((svga->crtc[5] & 0x60) >> 5); + } else if (dev->local && ibm8514_on) { + if (svga->interlace && svga->oddeven) + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1); + else + svga->ma = svga->maback = svga->ma_latch; + } svga->ca = ((svga->crtc[0xe] << 8) | svga->crtc[0xf]) + ((svga->crtc[0xb] & 0x60) >> 5) + svga->ca_adj; - svga->ma = (svga->ma << 2); svga->maback = (svga->maback << 2); svga->ca = (svga->ca << 2); @@ -958,9 +995,9 @@ svga_init(const device_t *info, svga_t *svga, void *p, int memsize, svga->monitor_index = monitor_index_global; svga->monitor = &monitors[svga->monitor_index]; - for (uint16_t c = 0; c < 256; c++) { + for (int c = 0; c < 256; c++) { e = c; - for (uint8_t d = 0; d < 8; d++) { + for (int d = 0; d < 8; d++) { svga_rotate[d][c] = e; e = (e >> 1) | ((e & 1) ? 0x80 : 0); } @@ -1100,7 +1137,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) if (!linear) { if (xga_enabled) { - if (((svga->xga.op_mode & 7) >= 4) && (svga->xga.aperture_cntl == 1)) { + if (((svga->xga.op_mode & 7) >= 4) && (svga->xga.aperture_cntl >= 1)) { if (val == 0xa5) { /*Memory size test of XGA*/ svga->xga.test = val; svga->xga.a5_test = 1; @@ -1108,7 +1145,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) } else if (val == 0x5a) { svga->xga.test = val; return; - } else if (val == 0x12 || val == 0x34) { + } else if ((val == 0x12) || (val == 0x34)) { addr += svga->xga.write_bank; svga->xga.vram[addr & svga->xga.vram_mask] = val; svga->xga.linear_endian_reverse = 1; @@ -1145,10 +1182,18 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) if (addr & 1) writemask2 <<= 1; addr &= ~1; - addr <<= 2; - } else - addr <<= 2; - + if (linear && ibm8514_on && (svga->adv_flags & FLAG_ATI)) { + addr &= svga->vram_mask; + } else + addr <<= 2; + } else { + if (linear && ibm8514_on && (svga->adv_flags & FLAG_ATI)) { + writemask2 = 1 << (addr & 3); + addr &= ~3; + addr &= svga->vram_mask; + } else + addr <<= 2; + } addr &= svga->decode_mask; if (svga->translate_address) @@ -1303,7 +1348,7 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) if (!linear) { if (xga_enabled) { - if (((svga->xga.op_mode & 7) >= 4) && (svga->xga.aperture_cntl == 1)) { + 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; vga_on = !svga->xga.on; @@ -1312,7 +1357,7 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) svga->xga.on = 1; vga_on = !svga->xga.on; return svga->xga.test; - } else if (addr == 0xa0000 || addr == 0xa0010) { + } else if ((addr == 0xa0000) || (addr == 0xa0010)) { addr += svga->xga.read_bank; return svga->xga.vram[addr & svga->xga.vram_mask]; } @@ -1354,11 +1399,24 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) } else if (svga->chain2_read) { readplane = (readplane & 2) | (addr & 1); addr &= ~1; - addr <<= 2; - } else - addr <<= 2; - + if (linear && ibm8514_on && (svga->adv_flags & FLAG_ATI)) + addr &= svga->vram_mask; + else + addr <<= 2; + } else { + if (linear && ibm8514_on && (svga->adv_flags & FLAG_ATI)) { + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + latch_addr = (addr & svga->vram_mask) & ~3; + for (uint8_t i = 0; i < count; i++) + svga->latch.b[i] = svga->vram[latch_addr | i]; + return svga->vram[addr & svga->vram_mask]; + } else + addr <<= 2; + } addr &= svga->decode_mask; + if (svga->translate_address) { latch_addr = svga->translate_address(latch_addr, p); addr = svga->translate_address(addr, p); diff --git a/src/video/vid_table.c b/src/video/vid_table.c index a2cead1ec..aaf407ca4 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -36,6 +36,7 @@ #include <86box/vid_ega.h> #include <86box/vid_colorplus.h> #include <86box/vid_mda.h> +#include <86box/vid_xga_device.h> typedef struct { const device_t *device; @@ -79,6 +80,8 @@ video_cards[] = { { &vid_none_device }, { &vid_internal_device }, { &atiega_device }, + { &mach8_isa_device, VIDEO_FLAG_TYPE_8514 }, + { &mach32_isa_device, VIDEO_FLAG_TYPE_8514 }, { &mach64gx_isa_device }, { &ati28800k_device }, { &ati18800_vga88_device }, @@ -112,6 +115,7 @@ video_cards[] = { { &hercules_device, VIDEO_FLAG_TYPE_MDA }, { &herculesplus_device, VIDEO_FLAG_TYPE_MDA }, { &incolor_device }, + { &inmos_isa_device, VIDEO_FLAG_TYPE_XGA }, { &im1024_device }, { &iskra_ega_device }, { &et4000_kasan_isa_device }, @@ -154,6 +158,7 @@ video_cards[] = { { &gd5428_mca_device }, { &et4000_mca_device }, { &radius_svga_multiview_mca_device }, + { &mach32_pci_device, VIDEO_FLAG_TYPE_8514 }, { &mach64gx_pci_device }, { &mach64vt2_device }, { &et4000w32p_videomagic_revb_pci_device }, @@ -211,6 +216,7 @@ video_cards[] = { { &voodoo_3_1000_device }, { &voodoo_3_2000_device }, { &voodoo_3_3000_device }, + { &mach32_vlb_device, VIDEO_FLAG_TYPE_8514 }, { &mach64gx_vlb_device }, { &et4000w32i_vlb_device }, { &et4000w32p_videomagic_revb_vlb_device }, @@ -431,3 +437,15 @@ video_is_ega_vga(void) { return (video_get_type() == VIDEO_FLAG_TYPE_SPECIAL); } + +int +video_is_8514(void) +{ + return (video_get_type() == VIDEO_FLAG_TYPE_8514); +} + +int +video_is_xga(void) +{ + return (video_get_type() == VIDEO_FLAG_TYPE_XGA); +} diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 0c795d132..7933e74a8 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -37,6 +37,7 @@ #define XGA_BIOS_PATH "roms/video/xga/XGA_37F9576_Ver200.BIN" #define XGA2_BIOS_PATH "roms/video/xga/xga2_v300.bin" +#define INMOS_XGA_BIOS_PATH "roms/video/xga/InMOS XGA - Fairchild NM27C256Q-150.BIN" static video_timings_t timing_xga_isa = { .type = VIDEO_ISA, .write_b = 3, .write_w = 3, .write_l = 6, .read_b = 5, .read_w = 5, .read_l = 10 }; static video_timings_t timing_xga_mca = { .type = VIDEO_MCA, .write_b = 4, .write_w = 5, .write_l = 10, .read_b = 5, .read_w = 5, .read_l = 10 }; @@ -44,16 +45,86 @@ static video_timings_t timing_xga_mca = { .type = VIDEO_MCA, .write_b = 4, .writ static void xga_ext_outb(uint16_t addr, uint8_t val, void *p); static uint8_t xga_ext_inb(uint16_t addr, void *p); +int xga_has_vga = 0; + +void +svga_xga_out(uint16_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg & 0x20) + return; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t +svga_xga_in(uint16_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t temp; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } + return temp; +} + void xga_updatemapping(svga_t *svga) { xga_t *xga = &svga->xga; - //pclog("OpMode = %x, linear base = %08x, aperture cntl = %d, opmodereset1 = %d, access mode = %x, map = %x.\n", xga->op_mode, xga->linear_base, xga->aperture_cntl, xga->op_mode_reset, xga->access_mode, svga->gdcreg[6] & 0x0c); + //pclog("OpMode = %x, linear base = %08x, aperture cntl = %d, access mode = %x, map = %x, endian reverse = %d, a5test = %d, XGA on = %d.\n", xga->op_mode, xga->linear_base, xga->aperture_cntl, xga->access_mode, svga->gdcreg[6] & 0x0c, xga->linear_endian_reverse, xga->a5_test, xga->on); if (((xga->op_mode & 7) >= 4) || ((xga->op_mode & 7) == 0)) { - if (xga->aperture_cntl == 1) { + if ((xga->aperture_cntl == 1) || (xga->aperture_cntl == 2)) { mem_mapping_disable(&svga->mapping); - mem_mapping_set_addr(&xga->video_mapping, 0xa0000, 0x10000); + if (xga->aperture_cntl == 1) + mem_mapping_set_addr(&xga->video_mapping, 0xa0000, 0x10000); + else + mem_mapping_set_addr(&xga->video_mapping, 0xb0000, 0x10000); + mem_mapping_enable(&xga->video_mapping); xga->banked_mask = 0xffff; if (!xga->linear_endian_reverse) @@ -63,38 +134,23 @@ xga_updatemapping(svga_t *svga) mem_mapping_set_addr(&xga->video_mapping, 0xa0000, 0x10000); mem_mapping_enable(&xga->video_mapping); xga->banked_mask = 0xffff; - if (xga->pos_regs[4] & 1) - mem_mapping_set_addr(&xga->linear_mapping, xga->linear_base, 0x400000); - else if (xga->base_addr_1mb) + if (xga->base_addr_1mb) mem_mapping_set_addr(&xga->linear_mapping, xga->base_addr_1mb, 0x100000); else mem_mapping_set_addr(&xga->linear_mapping, xga->linear_base, 0x400000); if (((xga->op_mode & 7) == 4) && ((svga->gdcreg[6] & 0x0c) == 0x0c) && !xga->a5_test && xga->on) xga->linear_endian_reverse = 1; - else if (((xga->op_mode & 7) == 0) && ((svga->gdcreg[6] & 0x0c) == 0x0c) && !xga->a5_test && !xga->on) + else if (((xga->op_mode & 7) == 0) && ((svga->gdcreg[6] & 0x0c) == 0x0c) && !xga->a5_test && !xga->on) { xga->linear_endian_reverse = 1; - xga->on = 0; - vga_on = !xga->on; - } else { - mem_mapping_disable(&svga->mapping); - mem_mapping_set_addr(&xga->video_mapping, 0xb0000, 0x10000); - mem_mapping_enable(&xga->video_mapping); - xga->banked_mask = 0xffff; - mem_mapping_disable(&xga->linear_mapping); + } + if (xga->a5_test && (xga->access_mode & 8) && !xga->linear_endian_reverse) { + xga->on = 0; + vga_on = !xga->on; + } } - } else { - xga->on = 0; - vga_on = !xga->on; - mem_mapping_disable(&svga->mapping); - if (xga->aperture_cntl == 2) - mem_mapping_set_addr(&xga->video_mapping, 0xb0000, 0x10000); - else - mem_mapping_set_addr(&xga->video_mapping, 0xa0000, 0x10000); - mem_mapping_enable(&xga->video_mapping); - xga->banked_mask = 0xffff; - mem_mapping_disable(&xga->linear_mapping); - //pclog("XGA opmode (not extended) = %d, disp mode = %d, aperture = %d.\n", xga->op_mode & 7, xga->disp_cntl_2 & 7, xga->aperture_cntl); + //pclog("XGA opmode (extended) = %d, disp mode = %d, aperture = %d.\n", xga->op_mode & 7, xga->disp_cntl_2 & 7, xga->aperture_cntl); } + //pclog("VGA on = %d.\n", vga_on); } void @@ -126,19 +182,19 @@ xga_recalctimings(svga_t *svga) xga->ma_latch = xga->disp_start_addr; - switch (xga->clk_sel_1 & 0x0c) { + switch ((xga->clk_sel_1 >> 2) & 3) { case 0: if (xga->clk_sel_2 & 0x80) { - svga->clock = (cpuclock * (double) (1ULL << 32)) / 41539000.0; + svga->clock = (cpuclock * (double) (1ull << 32)) / 41539000.0; } else { - svga->clock = (cpuclock * (double) (1ULL << 32)) / 25175000.0; + svga->clock = (cpuclock * (double) (1ull << 32)) / 25175000.0; } break; - case 4: - svga->clock = (cpuclock * (double) (1ULL << 32)) / 28322000.0; + case 1: + svga->clock = (cpuclock * (double) (1ull << 32)) / 28322000.0; break; - case 0x0c: - svga->clock = (cpuclock * (double) (1ULL << 32)) / 44900000.0; + case 3: + svga->clock = (cpuclock * (double) (1ull << 32)) / 44900000.0; break; } } @@ -309,7 +365,7 @@ xga_ext_out_reg(xga_t *xga, svga_t *svga, uint8_t idx, uint8_t val) if ((xga->sprite_pos >= 0) && (xga->sprite_pos <= 16)) { if ((xga->op_mode & 7) >= 5) xga->cursor_data_on = 1; - else if (xga->sprite_pos >= 1) + else if ((xga->sprite_pos >= 1) || ((xga->disp_cntl_2 & 7) > 3)) xga->cursor_data_on = 1; else if (xga->aperture_cntl == 0) { if (xga->linear_endian_reverse && !(xga->access_mode & 8)) @@ -474,7 +530,10 @@ xga_ext_inb(uint16_t addr, void *p) case 0x0f: switch (xga->regs_idx) { case 4: - ret = (xga->bus & DEVICE_MCA) ? 1 : 0; + if (xga->bus & DEVICE_MCA) + ret = 0x01; /*32-bit MCA*/ + else + ret = 0x10; /*16-bit ISA*/ break; case 0x10: ret = xga->htotal & 0xff; @@ -653,6 +712,16 @@ xga_ext_inb(uint16_t addr, void *p) ret = xga->clk_sel_2; break; + case 0x74: + if (xga->bus & DEVICE_MCA) + ret = xga->regs[xga->regs_idx]; + else { + ret = (xga->dma_channel << 1); + if (xga->dma_channel) + ret |= 1; + } + break; + default: ret = xga->regs[xga->regs_idx]; break; @@ -678,15 +747,35 @@ xga_ext_inb(uint16_t addr, void *p) dat = xga->vram[(addr + 1) & (xga->vram_mask - 1)] & 0xff; \ dat |= (xga->vram[(addr) & (xga->vram_mask - 1)] << 8); +#define READL(addr, dat) \ + dat = *(uint32_t *) &xga->vram[(addr) & (xga->vram_mask)]; + +#define READL_REVERSE(addr, dat) \ + dat = xga->vram[(addr + 3) & (xga->vram_mask - 3)] & 0xff; \ + dat |= (xga->vram[(addr + 2) & (xga->vram_mask - 3)] << 8); \ + dat |= (xga->vram[(addr + 1) & (xga->vram_mask - 3)] << 16); \ + dat |= (xga->vram[(addr) & (xga->vram_mask - 3)] << 24); + #define WRITEW(addr, dat) \ *(uint16_t *) &xga->vram[((addr)) & (xga->vram_mask)] = dat; \ xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = svga->monitor->mon_changeframecount; +#define WRITEL(addr, dat) \ + *(uint32_t *) &xga->vram[((addr)) & (xga->vram_mask)] = dat; \ + xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = svga->monitor->mon_changeframecount; + #define WRITEW_REVERSE(addr, dat) \ xga->vram[((addr + 1)) & (xga->vram_mask - 1)] = dat & 0xff; \ xga->vram[((addr)) & (xga->vram_mask - 1)] = dat >> 8; \ xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = svga->monitor->mon_changeframecount; +#define WRITEL_REVERSE(addr, dat) \ + xga->vram[((addr + 3)) & (xga->vram_mask - 3)] = dat & 0xff; \ + xga->vram[((addr + 2)) & (xga->vram_mask - 3)] = dat >> 8; \ + xga->vram[((addr + 1)) & (xga->vram_mask - 3)] = dat >> 16; \ + xga->vram[((addr)) & (xga->vram_mask - 3)] = dat >> 24; \ + xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = svga->monitor->mon_changeframecount; + #define ROP(mix, d, s) \ { \ switch ((mix) ? (xga->accel.frgd_mix & 0x1f) : (xga->accel.bkgd_mix & 0x1f)) { \ @@ -859,6 +948,23 @@ xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int byte = mem_readw_phys(addr); } return byte; + case 5: /*24-bit*/ + addr += (y * (width << 2)); + addr += (x << 2); + if (!skip) { + if ((xga->accel.px_map_format[map] & 8)) { + if (xga->linear_endian_reverse) { + READL(addr, byte); + } else { + READL_REVERSE(addr, byte); + } + } else { + READL(addr, byte); + } + } else { + byte = mem_readl_phys(addr); + } + return byte; } return 0; @@ -936,6 +1042,22 @@ xga_accel_write_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, ui } mem_writew_phys(addr, pixel); break; + case 5: /*24-bit*/ + addr += (y * (width) << 2); + addr += (x << 2); + if (!skip) { + if ((xga->accel.px_map_format[map] & 8)) { + if (xga->linear_endian_reverse) { + WRITEL(addr, pixel); + } else { + WRITEL_REVERSE(addr, pixel); + } + } else { + WRITEL(addr, pixel); + } + } + mem_writel_phys(addr, pixel); + break; } } @@ -1447,6 +1569,10 @@ xga_mem_write(uint32_t addr, uint32_t val, xga_t *xga, svga_t *svga, int len) if (addr >= 0x1800) { switch (addr & 0x7f) { + case 0x11: + xga->accel.control = val; + break; + case 0x12: xga->accel.px_map_idx = val & 3; break; @@ -1923,11 +2049,21 @@ xga_mem_read(uint32_t addr, xga_t *xga, svga_t *svga) uint8_t temp = 0; addr &= 0x1fff; - if (addr < 0x1800) { - temp = xga->bios_rom.rom[addr]; + if (!xga_has_vga) + temp = xga->bios_rom.rom[addr]; + else + temp = xga->vga_bios_rom.rom[addr]; } else { switch (addr & 0x7f) { + case 0x11: + temp = xga->accel.control; + if (xga->accel.control & 0x08) + temp |= 0x10; + else + temp &= ~0x10; + break; + case 0x20: temp = xga->accel.bres_err_term & 0xff; break; @@ -2092,8 +2228,9 @@ xga_render_overscan_left(xga_t *xga, svga_t *svga) if (svga->scrblank || (xga->h_disp == 0)) return; + uint32_t *line_ptr = svga->monitor->target_buffer->line[xga->displine + svga->y_add]; for (int i = 0; i < svga->x_add; i++) - buffer32->line[xga->displine + svga->y_add][i] = svga->overscan_color; + *line_ptr++ = svga->overscan_color; } static void @@ -2107,9 +2244,10 @@ xga_render_overscan_right(xga_t *xga, svga_t *svga) if (svga->scrblank || (xga->h_disp == 0)) return; - right = (overscan_x >> 1); + uint32_t *line_ptr = &svga->monitor->target_buffer->line[xga->displine + svga->y_add][svga->x_add + xga->h_disp]; + right = (overscan_x >> 1); for (int i = 0; i < right; i++) - buffer32->line[xga->displine + svga->y_add][svga->x_add + xga->h_disp + i] = svga->overscan_color; + *line_ptr++ = svga->overscan_color; } static void @@ -2122,7 +2260,7 @@ xga_render_8bpp(xga_t *xga, svga_t *svga) 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]; + p = &svga->monitor->target_buffer->line[xga->displine + svga->y_add][svga->x_add]; if (xga->firstline_draw == 2000) xga->firstline_draw = xga->displine; @@ -2159,7 +2297,7 @@ xga_render_16bpp(xga_t *xga, svga_t *svga) 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]; + p = &svga->monitor->target_buffer->line[xga->displine + svga->y_add][svga->x_add]; if (xga->firstline_draw == 2000) xga->firstline_draw = xga->displine; @@ -2524,7 +2662,7 @@ xga_poll(xga_t *xga, svga_t *svga) } xga->vc++; - xga->vc &= 2047; + xga->vc &= 0x7ff; if (xga->vc == xga->split) { if (xga->interlace && xga->oddeven) @@ -2683,8 +2821,149 @@ static uint8_t xga_pos_in(uint16_t addr, void *priv) { svga_t *svga = (svga_t *) priv; + xga_t *xga = &svga->xga; + uint8_t ret; - return (xga_mca_read(addr, svga)); + if (xga_has_vga) { + switch (addr) { + case 0x0100: + case 0x0101: + if (xga->instance_isa == xga->instance_num) + ret = xga->pos_regs[addr & 7]; + else + ret = 0xff; + break; + case 0x0102: + case 0x0105: + ret = xga->pos_regs[addr & 7]; + break; + case 0x0106: + ret = xga->pos_idx >> 8; + break; + case 0x0107: + ret = xga->pos_idx & 0xff; + break; + case 0x0103: + if (!(xga->pos_idx & 3)) { + ret = xga->pos_regs[3]; + } else + ret = 0; + //pclog("POS IDX for 0103 = %d, ret = %02x.\n", xga->pos_idx & 3, ret); + break; + case 0x0104: + switch (xga->pos_idx & 3) { + case 0: + ret = xga->pos_regs[4]; + break; + case 1: + ret = xga->pos_regs[0]; + break; + case 2: + ret = xga->pos_regs[1]; + break; + case 3: + ret = 0; + break; + } + //pclog("POS IDX for 0104 = %d, ret = %02x.\n", xga->pos_idx & 3, ret); + break; + case 0x0108: + case 0x0109: + case 0x010a: + case 0x010b: + case 0x010c: + case 0x010d: + case 0x010e: + case 0x010f: + xga->instance_num = addr & 7; + if (xga->instance_isa == xga->instance_num) + ret = xga->instance_isa; + else + ret = 0; + + ret |= xga->isa_pos_enable; + break; + } + } else { + switch (addr) { + case 0x0100: + case 0x0101: + ret = xga->pos_regs[addr & 7]; + break; + case 0x0103: + ret = xga->pos_regs[3] | 7; + ret |= (xga->dma_channel << 3); + break; + case 0x0102: + case 0x0104: + case 0x0105: + case 0x0106: + case 0x0107: + ret = (xga_mca_read(addr, svga)); + break; + case 0x0108: + case 0x0109: + case 0x010a: + case 0x010b: + case 0x010c: + case 0x010d: + case 0x010e: + case 0x010f: + xga->instance_num = addr & 7; + if (xga->instance_isa == xga->instance_num) + ret = xga->instance_isa; + else + ret = 0; + + ret |= xga->isa_pos_enable; + break; + } + } + return ret; +} + +static void +xga_pos_out(uint16_t addr, uint8_t val, void *priv) +{ + svga_t *svga = (svga_t *) priv; + xga_t *xga = &svga->xga; + + if (xga_has_vga) { + switch (addr) { + case 0x0106: + xga->pos_idx = (xga->pos_idx & 0x00ff) | (val << 8); + break; + case 0x0107: + xga->pos_idx = (xga->pos_idx & 0xff00) | (val); + //pclog("POS IDX Write = %04x.\n", xga->pos_idx); + break; + case 0x0108: + case 0x0109: + case 0x010a: + case 0x010b: + case 0x010c: + case 0x010d: + case 0x010e: + case 0x010f: + xga->instance_num = addr & 7; + xga->isa_pos_enable = val & 0x08; + break; + } + } else { + switch (addr) { + case 0x0108: + case 0x0109: + case 0x010a: + case 0x010b: + case 0x010c: + case 0x010d: + case 0x010e: + case 0x010f: + xga->instance_num = addr & 7; + xga->isa_pos_enable = val & 0x08; + break; + } + } } static void @@ -2700,7 +2979,10 @@ static void uint32_t temp; uint8_t *rom = NULL; + xga->ext_mem_addr = device_get_config_hex16("ext_mem_addr"); + xga->instance_isa = device_get_config_int("instance"); xga->type = device_get_config_int("type"); + xga->dma_channel = device_get_config_int("dma"); xga->bus = info->flags; xga->vram_size = (1024 << 10); @@ -2739,12 +3021,16 @@ static void xga->rom_addr = 0; rom_init(&xga->bios_rom, xga->type ? XGA2_BIOS_PATH : XGA_BIOS_PATH, 0xc0000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); } else { - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_xga_isa); - xga->pos_regs[2] = 1 | 0x0c | 0xf0; + if (xga_has_vga) { + rom_init(&xga->vga_bios_rom, INMOS_XGA_BIOS_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + } else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_xga_isa); + + xga->pos_regs[2] = 1 | (xga->instance_isa << 1) | xga->ext_mem_addr; xga->instance = (xga->pos_regs[2] & 0x0e) >> 1; xga->pos_regs[4] = 1 | 2; xga->linear_base = ((xga->pos_regs[4] & 0xfe) * 0x1000000) + (xga->instance << 22); - xga->rom_addr = 0xc0000 + (((xga->pos_regs[2] & 0xf0) >> 4) * 0x2000); + xga->rom_addr = 0xc0000 + (((xga->pos_regs[2] & 0xf0) >> 4) * 0x2000); } mem_mapping_add(&xga->video_mapping, 0, 0, xga_readb, xga_readw, xga_readl, @@ -2755,7 +3041,7 @@ static void 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); + xga_has_vga ? xga->vga_bios_rom.rom : xga->bios_rom.rom, MEM_MAPPING_EXTERNAL, svga); mem_mapping_disable(&xga->video_mapping); mem_mapping_disable(&xga->linear_mapping); @@ -2768,13 +3054,41 @@ static void mca_add(xga_mca_read, xga_mca_write, xga_mca_feedb, xga_mca_reset, svga); } else { io_sethandler(0x0100, 0x0008, xga_pos_in, NULL, NULL, NULL, NULL, NULL, svga); + if (xga_has_vga) + io_sethandler(0x0106, 0x0002, NULL, NULL, NULL, xga_pos_out, NULL, NULL, svga); + io_sethandler(0x2100 + (xga->instance << 4), 0x0010, xga_ext_inb, NULL, NULL, xga_ext_outb, NULL, NULL, svga); + io_sethandler(0x0108, 0x0008, xga_pos_in, NULL, NULL, xga_pos_out, NULL, NULL, svga); mem_mapping_set_addr(&xga->memio_mapping, xga->rom_addr + 0x1c00 + (xga->instance * 0x80), 0x80); } - return svga; } +static void + * + svga_xga_init(const device_t *info) +{ + svga_t *svga = malloc(sizeof(svga_t)); + memset(svga, 0, sizeof(svga_t)); + + video_inform(VIDEO_FLAG_TYPE_XGA, &timing_xga_isa); + + svga_init(info, svga, svga, 1 << 18, /*256kB*/ + NULL, + svga_xga_in, svga_xga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, svga_xga_in, NULL, NULL, svga_xga_out, NULL, NULL, svga); + + svga->bpp = 8; + svga->miscout = 1; + xga_has_vga = 1; + xga_enabled = 1; + + return xga_init(info); +} + static void xga_close(void *p) { @@ -2793,6 +3107,12 @@ xga_available(void) return rom_present(XGA_BIOS_PATH) && rom_present(XGA2_BIOS_PATH); } +static int +inmos_xga_available(void) +{ + return rom_present(INMOS_XGA_BIOS_PATH); +} + static void xga_speed_changed(void *p) { @@ -2809,7 +3129,7 @@ xga_force_redraw(void *p) svga->fullchange = svga->monitor->mon_changeframecount; } -static const device_config_t xga_configuration[] = { +static const device_config_t xga_mca_configuration[] = { // clang-format off { .name = "type", @@ -2835,6 +3155,91 @@ static const device_config_t xga_configuration[] = { // clang-format on }; +static const device_config_t xga_isa_configuration[] = { + // clang-format off + { + .name = "type", + .description = "XGA type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "XGA-1", + .value = 0 + }, + { + .description = "XGA-2", + .value = 1 + }, + { .description = "" } + } + }, + { + .name = "instance", + .description = "Instance", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 6, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0 (2100h-210Fh)", .value = 0 }, + { .description = "1 (2110h-211Fh)", .value = 1 }, + { .description = "2 (2120h-212Fh)", .value = 2 }, + { .description = "3 (2130h-213Fh)", .value = 3 }, + { .description = "4 (2140h-214Fh)", .value = 4 }, + { .description = "5 (2150h-215Fh)", .value = 5 }, + { .description = "6 (2160h-216Fh)", .value = 6 }, + { .description = "7 (2170h-217Fh)", .value = 7 }, + { .description = "" } + }, + }, + { + .name = "ext_mem_addr", + .description = "MMIO address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x00f0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "C800h", .value = 0x0040 }, + { .description = "CA00h", .value = 0x0050 }, + { .description = "CC00h", .value = 0x0060 }, + { .description = "CE00h", .value = 0x0070 }, + { .description = "D000h", .value = 0x0080 }, + { .description = "D200h", .value = 0x0090 }, + { .description = "D400h", .value = 0x00a0 }, + { .description = "D600h", .value = 0x00b0 }, + { .description = "D800h", .value = 0x00c0 }, + { .description = "DA00h", .value = 0x00d0 }, + { .description = "DC00h", .value = 0x00e0 }, + { .description = "DE00h", .value = 0x00f0 }, + { .description = "" } + }, + }, + { + .name = "dma", + .description = "DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "DMA 6", .value = 6 }, + { .description = "DMA 7", .value = 7 }, + { .description = "" } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + const device_t xga_device = { .name = "XGA (MCA)", .internal_name = "xga_mca", @@ -2846,7 +3251,7 @@ const device_t xga_device = { { .available = xga_available }, .speed_changed = xga_speed_changed, .force_redraw = xga_force_redraw, - .config = xga_configuration + .config = xga_mca_configuration }; const device_t xga_isa_device = { @@ -2860,13 +3265,27 @@ const device_t xga_isa_device = { { .available = xga_available }, .speed_changed = xga_speed_changed, .force_redraw = xga_force_redraw, - .config = xga_configuration + .config = xga_isa_configuration +}; + +const device_t inmos_isa_device = { + .name = "INMOS XGA (ISA)", + .internal_name = "inmos_xga_isa", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = svga_xga_init, + .close = xga_close, + .reset = xga_reset, + { .available = inmos_xga_available }, + .speed_changed = xga_speed_changed, + .force_redraw = xga_force_redraw, + .config = xga_isa_configuration }; void xga_device_add(void) { - if (!xga_enabled) + if (!xga_enabled || (xga_has_vga && xga_enabled)) return; if (machine_has_bus(machine, MACHINE_BUS_MCA)) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 9c18ae72a..6946eff04 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -711,6 +711,7 @@ VIDOBJ := agpgart.o video.o \ vid_vga.o \ vid_ati_eeprom.o \ vid_ati18800.o vid_ati28800.o \ + vid_ati_mach8.o \ vid_ati_mach64.o vid_ati68860_ramdac.o \ vid_bt48x_ramdac.o \ vid_av9194.o vid_icd2061.o vid_ics2494.o vid_ics2595.o \