From: Toni Wilen Date: Wed, 27 Mar 2024 19:25:33 +0000 (+0200) Subject: Merlin Z2/Z3 boards added. Blitter not yet functional. Some 86box updates. X-Git-Tag: 5300~56 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=3757357574d25779066ff75120ae3c5f4919dd59;p=francis%2Fwinuae.git Merlin Z2/Z3 boards added. Blitter not yet functional. Some 86box updates. --- diff --git a/gfxboard.cpp b/gfxboard.cpp index b3b37fa2..f60cdf48 100644 --- a/gfxboard.cpp +++ b/gfxboard.cpp @@ -2,8 +2,9 @@ * UAE - The Un*x Amiga Emulator * * Cirrus Logic based graphics board emulation +* PCem/86box glue interface + boards. * -* Copyright 2013 Toni Wilen +* Copyright 2013-2024 Toni Wilen * */ @@ -295,6 +296,20 @@ static const struct gfxboard boards[] = 0x00000000, 0x00100000, 0x00100000, 0x00100000, 0, 2, 0, false, false, 0, 0, NULL, &et4000_domino_device }, + { + GFXBOARD_ID_MERLIN_Z2, + _T("Merlin [Zorro II]"), _T("X-Pert Computer Services"), _T("MerlinZ2"), + 2117, 3, 4, 0, + 0x00000000, 0x00200000, 0x00200000, 0x00200000, 0, 2, 0, false, false, + 0, 0, NULL, &et4000w32_merlin_z2_device + }, + { + GFXBOARD_ID_MERLIN_Z3, + _T("Merlin [Zorro III]"), _T("X-Pert Computer Services"), _T("MerlinZ3"), + 2117, 3, 4, 0, + 0x00000000, 0x00200000, 0x00400000, 0x02000000, 0, 3, 0, false, false, + 0, 0, NULL, &et4000w32_merlin_z3_device + }, { GFXBOARD_ID_HARLEQUIN, _T("Harlequin [Zorro II]"), _T("ACS"), _T("Harlequin_PAL"), @@ -2845,6 +2860,17 @@ static void REGPARAM2 gfxboard_wput_mem_autoconfig (uaecptr addr, uae_u32 b) gb->configured_regs = gb->gfxmem_bank->start >> 16; gb->gfxboard_external_interrupt = true; + } else if (boardnum == GFXBOARD_ID_MERLIN_Z3) { + + map_banks_z3(&gb->gfxboard_bank_vram_pcem, start >> 16, gb->gfxboard_bank_vram_pcem.allocated_size >> 16); + gb->pcem_mmio_offset = 0x1000000; + gb->pcem_vram_mask = 0x3fffff; + gb->pcem_vram_offset = 0x800000; + map_banks_z3(&gb->gfxboard_bank_special_pcem, (start + 0x400000) >> 16, 0xc00000 >> 16); + map_banks_z3(&gb->gfxboard_bank_special_pcem, (start + 0x1000000) >> 16, 0x1000000 >> 16); + gb->pcem_mmio_mask = 0xffff; + gb->configured_regs = gb->gfxmem_bank->start >> 16; + } } else { @@ -6077,6 +6103,17 @@ static void special_pcem_put(uaecptr addr, uae_u32 v, int size) put_io_pcem(addr, v & 0xff, 0); } + } else if (boardnum == GFXBOARD_ID_MERLIN_Z2 || boardnum == GFXBOARD_ID_MERLIN_Z3) { + + addr &= 0xffff; + + if (size) { + put_io_pcem(addr + 0, (v >> 8) & 0xff, 0); + put_io_pcem(addr + 1, (v >> 0) & 0xff, 0); + } else if (size == 0) { + put_io_pcem(addr, v & 0xff, 0); + } + } else if (boardnum == GFXBOARD_ID_EGS_110_24) { addr &= 0xffff; @@ -6406,6 +6443,16 @@ static uae_u32 special_pcem_get(uaecptr addr, int size) v = get_io_pcem(addr, 0); } + } else if (boardnum == GFXBOARD_ID_MERLIN_Z2 || boardnum == GFXBOARD_ID_MERLIN_Z3) { + + addr &= 0xffff; + if (size) { + v = get_io_pcem(addr + 0, 0) << 8; + v |= get_io_pcem(addr + 1, 0) << 0; + } else if (size == 0) { + v = get_io_pcem(addr, 0); + } + } else if (boardnum == GFXBOARD_ID_EGS_110_24) { addr &= 0xffff; diff --git a/include/gfxboard.h b/include/gfxboard.h index 749ebaea..48909048 100644 --- a/include/gfxboard.h +++ b/include/gfxboard.h @@ -90,7 +90,9 @@ int pcem_getvramsize(void); #define GFXBOARD_ID_VISIONA 27 #define GFXBOARD_ID_EGS_110_24 28 #define GFXBOARD_ID_DOMINO 29 -#define GFXBOARD_ID_VOODOO5_PCI 30 +#define GFXBOARD_ID_MERLIN_Z2 30 +#define GFXBOARD_ID_MERLIN_Z3 31 +#define GFXBOARD_ID_VOODOO5_PCI 32 #define GFXBOARD_BUSTYPE_Z 0 #define GFXBOARD_BUSTYPE_PCI 1 diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj b/od-win32/winuae_msvc15/winuae_msvc.vcxproj index 1085d6bb..1d0b9fc9 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj @@ -1377,8 +1377,10 @@ + + diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters index 517f8322..5869048a 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters @@ -1018,6 +1018,12 @@ pcem + + pcem + + + pcem + diff --git a/pcem/vid_bt482_ramdac.cpp b/pcem/vid_bt482_ramdac.cpp new file mode 100644 index 00000000..38066ce5 --- /dev/null +++ b/pcem/vid_bt482_ramdac.cpp @@ -0,0 +1,282 @@ + +/* BT482 RAMDAC (based on 86box BT484) */ + +#include +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sdac_ramdac.h" + +enum { + BT481 = 0, + BT482, +}; + +static void +bt482_set_bpp(bt482_ramdac_t *ramdac, svga_t *svga) +{ + svga->swaprb = 0; + switch (ramdac->cmd_r0 >> 4) { + case 0x0f: + svga->bpp = 24; + svga->swaprb = (ramdac->cmd_r0 & 2) == 0; + break; + case 0x09: + svga->bpp = 32; + svga->swaprb = (ramdac->cmd_r0 & 2) == 0; + break; + case 0x0e: + case 0x0c: + svga->bpp = 16; + break; + case 0x08: + case 0x0a: + svga->bpp = 15; + break; + default: + svga->bpp = 8; + break; + } + svga_recalctimings(svga); +} + +void +bt482_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga) +{ + bt482_ramdac_t *ramdac = (bt482_ramdac_t *) priv; + uint8_t rs = (addr & 0x03); + uint16_t da_mask = 0x0ff; + rs |= (!!rs2 << 2); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + svga->dac_pos = 0; + svga->dac_status = addr & 0x03; + svga->dac_addr = val; + svga->dac_write = val; + if (svga->dac_status) + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x01: /* Palette Data Register (RS value = 0001) */ + svga_out(addr, val, svga); + break; + case 0x02: + if (ramdac->cmd_r0 & 1) { + switch(svga->dac_addr) + { + case 2: // command B + svga->ramdac_type = (val & 0x02) ? RAMDAC_8BIT : RAMDAC_6BIT; + break; + case 3: // cursor + ramdac->cursor_r = val; + svga->dac_hwcursor.xsize = 32; + svga->dac_hwcursor.ysize = 32; + svga->dac_hwcursor.ena = (val & 0x03) != 0; + break; + case 4: // cursor x low + ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + break; + case 5: // cursor x high + ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8); + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + break; + case 6: // cursor y low + ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + break; + case 7: // cursor y high + ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8); + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + break; + } + } else { + // pixel mask + } + break; + case 0x04: // overlay and cursor color write + svga->dac_addr = val; + svga->dac_pos = 0; + break; + case 0x05: // overlay/cursor color + if (ramdac->cursor_r & (1 << 3)) { + ramdac->cursor32_data[svga->dac_addr] = val; + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + } else { + ramdac->rgb[svga->dac_pos] = val; + svga->dac_pos++; + if (svga->dac_pos == 3) { + ramdac->extpallook[svga->dac_addr & 3] = makecol32(ramdac->rgb[0], ramdac->rgb[1], ramdac->rgb[2]); + svga->dac_addr++; + svga->dac_pos = 0; + } + } + break; + case 0x06: /* Command Register A (RS value = 0110) */ + ramdac->cmd_r0 = val; + bt482_set_bpp(ramdac, svga); + break; + } + + return; +} + +uint8_t +bt482_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga) +{ + bt482_ramdac_t *ramdac = (bt482_ramdac_t *) priv; + uint8_t temp = 0xff; + uint8_t rs = (addr & 0x03); + uint16_t da_mask = 0x00ff; + rs |= (!!rs2 << 2); + + // TODO + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + temp = svga_in(addr, svga); + break; + case 0x03: /* Palette Read Index Register (RS value = 0011) */ + temp = svga->dac_addr & 0xff; + break; + case 0x06: /* Command Register 0 (RS value = 0110) */ + temp = ramdac->cmd_r0; + break; + } + + return temp; +} + +void +bt482_recalctimings(void *priv, svga_t *svga) +{ + const bt482_ramdac_t *ramdac = (bt482_ramdac_t *) priv; +} + +void +bt482_hwcursor_draw(svga_t *svga, int displine) +{ + int comb; + int b0; + int b1; + uint16_t dat[2]; + int offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff; + int pitch; + int bppl; + int mode; + int x_pos; + int y_pos; + uint32_t clr1; + uint32_t clr2; + uint32_t clr3; + uint32_t *p; + const uint8_t *cd; + bt482_ramdac_t *ramdac = (bt482_ramdac_t *) svga->ramdac; + + clr1 = ramdac->extpallook[1]; + clr2 = ramdac->extpallook[2]; + clr3 = ramdac->extpallook[3]; + + /* The planes come in two parts, and each plane is 1bpp, + 32x32 cursor has 4 bytes per line */ + pitch = (svga->dac_hwcursor_latch.xsize >> 3); /* Bytes per line. */ + /* A 32x32 cursor has 128 bytes per line */ + bppl = (pitch * svga->dac_hwcursor_latch.ysize); /* Bytes per plane. */ + + if (svga->interlace && svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; + + cd = (uint8_t *) ramdac->cursor32_data; + mode = ramdac->cursor_r & 3; + + for (int x = 0; x < svga->dac_hwcursor_latch.xsize; x += 16) { + dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | cd[svga->dac_hwcursor_latch.addr + 1]; + dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | cd[svga->dac_hwcursor_latch.addr + bppl + 1]; + + for (uint8_t xx = 0; xx < 16; xx++) { + b0 = (dat[0] >> (15 - xx)) & 1; + b1 = (dat[1] >> (15 - xx)) & 1; + comb = (b0 | (b1 << 1)); + + y_pos = displine; + x_pos = offset + svga->x_add + 32; + p = (uint32_t*)(buffer32->line[y_pos]); + + if (offset >= svga->dac_hwcursor_latch.x) { + switch (mode) { + case 1: /* Three Color */ + switch (comb) { + case 1: + p[x_pos] = clr1; + break; + case 2: + p[x_pos] = clr2; + break; + case 3: + p[x_pos] = clr3; + break; + + default: + break; + } + break; + case 2: /* PM/Windows */ + switch (comb) { + case 0: + p[x_pos] = clr1; + break; + case 1: + p[x_pos] = clr2; + break; + case 3: + p[x_pos] ^= 0xffffff; + break; + + default: + break; + } + break; + case 3: /* X-Windows */ + switch (comb) { + case 2: + p[x_pos] = clr1; + break; + case 3: + p[x_pos] = clr2; + break; + + default: + break; + } + break; + + default: + break; + } + } + offset++; + } + svga->dac_hwcursor_latch.addr += 2; + } + + if (svga->interlace && !svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; +} + +void * +bt482_ramdac_init(const device_t *info) +{ + bt482_ramdac_t *ramdac = (bt482_ramdac_t *) malloc(sizeof(bt482_ramdac_t)); + memset(ramdac, 0, sizeof(bt482_ramdac_t)); + + return ramdac; +} + +void +bt482_ramdac_close(void *priv) +{ + bt482_ramdac_t *ramdac = (bt482_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} diff --git a/pcem/vid_et4000.h b/pcem/vid_et4000.h index b88574de..4bc9414f 100644 --- a/pcem/vid_et4000.h +++ b/pcem/vid_et4000.h @@ -1 +1,3 @@ extern device_t et4000_domino_device; +extern device_t et4000w32_merlin_z2_device; +extern device_t et4000w32_merlin_z3_device; diff --git a/pcem/vid_et4000w32.cpp b/pcem/vid_et4000w32.cpp new file mode 100644 index 00000000..f279e34e --- /dev/null +++ b/pcem/vid_et4000w32.cpp @@ -0,0 +1,3341 @@ +/* + * 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. + * + * ET4000/W32 series emulation. + * + * Known bugs: Accelerator doesn't work in planar modes + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "pci.h" +#include "mem.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_sdac_ramdac.h" + +#define BIOS_ROM_PATH_DIAMOND "roms/video/et4000w32/et4000w32.bin" +#define BIOS_ROM_PATH_CARDEX "roms/video/et4000w32/cardex.vbi" +#define BIOS_ROM_PATH_W32 "roms/video/et4000w32/ET4000W32VLB_bios_MX27C512.BIN" +#define BIOS_ROM_PATH_W32I_ISA "roms/video/et4000w32/ET4KW32I.VBI" +#define BIOS_ROM_PATH_W32I_VLB "roms/video/et4000w32/tseng.u41.bin" +#define BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB "roms/video/et4000w32/VideoMagic-BioS-HXIRTW32PWSRL.BIN" +#define BIOS_ROM_PATH_W32P "roms/video/et4000w32/ET4K_W32.BIN" +#define BIOS_ROM_PATH_W32P_REVC "roms/video/et4000w32/et4000w32pcardex.BIN" + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +enum { + ET4000W32, + ET4000W32I, + ET4000W32P_REVC, + ET4000W32P_VIDEOMAGIC_REVB, + ET4000W32P, + ET4000W32P_CARDEX, + ET4000W32P_DIAMOND +}; + +typedef struct et4000w32p_t { + mem_mapping_t linear_mapping; + mem_mapping_t mmu_mapping; + + void *ramdac; + + rom_t bios_rom; + + svga_t svga; + + uint8_t banking, banking2, adjust_cursor, rev, pci_slot; + + uint8_t regs[256], pci_regs[256]; + + int index, vlb, pci, interleaved, + bank, type; + + uint32_t linearbase; + uint32_t vram_mask; + + /* Accelerator */ + struct { + struct { + uint8_t vbus, pixel_depth, xy_dir, pattern_wrap, + source_wrap, ctrl_routing, ctrl_reload, rop_fg, + rop_bg; + + uint16_t pattern_off, source_off, dest_off, mix_off, + count_x, count_y, pos_x, pos_y, + error, dmin, dmaj; + + uint32_t pattern_addr, source_addr, dest_addr, mix_addr; + } queued, internal; + + uint8_t suspend_terminate, osr; + uint8_t status; + uint16_t x_count, y_count; + uint16_t cpu_x_cnt, cpu_x_cnt_back, cpu_y_cnt; + + int pattern_x, source_x, pattern_x_back, source_x_back, + pattern_y, source_y, cpu_dat_pos, pix_pos, + cpu_input_num, fifo_queue; + int mmu_start; + + uint32_t pattern_addr, source_addr, dest_addr, mix_addr, + pattern_back, source_back, dest_back, mix_back, + cpu_input; + + uint64_t cpu_dat; + } acl; + + struct { + uint32_t base[3]; + uint8_t ctrl; + } mmu; + + bool blitter_mmio; + uint32_t blitter_mmio_addr; + + volatile int busy; +} et4000w32p_t; + +static int et4000w32_vbus[4] = { 1, 2, 4, 4 }; + +static int et4000w32_max_x[8] = { 0, 0, 4, 8, 0x10, 0x20, 0x40, 0x70000000 }; +static int et4000w32_wrap_x[8] = { 0, 0, 3, 7, 0x0f, 0x1f, 0x3f, ~0 }; +static int et4000w32_wrap_y[8] = { 1, 2, 4, 8, ~0, ~0, ~0, ~0 }; + +//static video_timings_t timing_et4000w32_vlb = { .type = VIDEO_BUS, .write_b = 4, .write_w = 4, .write_l = 4, .read_b = 10, .read_w = 10, .read_l = 10 }; +//static video_timings_t timing_et4000w32_pci = { .type = VIDEO_PCI, .write_b = 4, .write_w = 4, .write_l = 4, .read_b = 10, .read_w = 10, .read_l = 10 }; +//static video_timings_t timing_et4000w32_isa = { .type = VIDEO_ISA, .write_b = 4, .write_w = 4, .write_l = 4, .read_b = 10, .read_w = 10, .read_l = 10 }; + +void et4000w32p_recalcmapping(et4000w32p_t *et4000); + +static uint8_t et4000w32p_mmu_read(uint32_t addr, void *priv); +static void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *priv); + +static void et4000w32_blit_start(et4000w32p_t *et4000); +static void et4000w32p_blit_start(et4000w32p_t *et4000); +static void et4000w32_blit(int count, int cpu_input, uint32_t src_dat, uint32_t mix_dat, et4000w32p_t *et4000); +static void et4000w32p_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000); +uint8_t et4000w32p_in(uint16_t addr, void *priv); + +#define et4000w32_log pclog + +#ifdef ENABLE_ET4000W32_LOG +int et4000w32_do_log = ENABLE_ET4000W32_LOG; + +static void +et4000w32_log(const char *fmt, ...) +{ + va_list ap; + + if (et4000w32_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +//# define et4000w32_log(fmt, ...) +#endif + +void +et4000w32p_out(uint16_t addr, uint8_t val, void *priv) +{ + et4000w32p_t *et4000 = (et4000w32p_t *) priv; + svga_t *svga = &et4000->svga; + uint8_t old; + uint32_t add2addr = 0; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c2: +// if (et4000->type == ET4000W32P_DIAMOND) +// icd2061_write(svga->clock_gen, (val >> 2) & 3); + break; + +#if 0 + case 0x3c6: + case 0x3c7: + case 0x3c8: + case 0x3c9: + if (et4000->type <= ET4000W32P_REVC) + sdac_ramdac_out(addr, val, &et4000->ramdac, svga); + else + stg_ramdac_out(addr, val, svga->ramdac, svga); + return; +#endif + case 0x3cb: /* Banking extension */ + if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (svga->write_bank & 0xfffff) | ((val & 1) << 20); + svga->read_bank = (svga->read_bank & 0xfffff) | ((val & 0x10) << 16); + } + et4000->banking2 = val; + return; + case 0x3cd: /* Banking */ + if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (svga->write_bank & 0x100000) | ((val & 0xf) * 65536); + svga->read_bank = (svga->read_bank & 0x100000) | (((val >> 4) & 0xf) * 65536); + } + et4000->banking = val; + return; + case 0x3cf: + switch (svga->gdcaddr & 15) { + case 6: + if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) { + svga->write_bank = ((et4000->banking2 & 1) << 20) | ((et4000->banking & 0xf) * 65536); + svga->read_bank = ((et4000->banking2 & 0x10) << 16) | (((et4000->banking >> 4) & 0xf) * 65536); + } else + svga->write_bank = svga->read_bank = 0; + + svga->gdcreg[svga->gdcaddr & 15] = val; + et4000w32p_recalcmapping(et4000); + return; + + default: + break; + } + break; + case 0x3d4: + svga->crtcreg = val & 0x3f; + return; + case 0x3d5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 0x35) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (svga->crtcreg == 0x36) { + if (!(val & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = ((et4000->banking2 & 1) << 20) | ((et4000->banking & 0xf) * 65536); + svga->read_bank = ((et4000->banking2 & 0x10) << 16) | (((et4000->banking >> 4) & 0xf) * 65536); + } else + svga->write_bank = svga->read_bank = 0; + } + 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); + } + } + } + if (svga->crtcreg == 0x30) { + if (et4000->pci && (et4000->rev != 5)) + et4000->linearbase = (et4000->linearbase & 0xc0000000) | ((val & 0xfc) << 22); + else + et4000->linearbase = val << 22; + et4000w32p_recalcmapping(et4000); + } + if (svga->crtcreg == 0x32 || svga->crtcreg == 0x36) + et4000w32p_recalcmapping(et4000); + break; + + case 0x210a: + case 0x211a: + case 0x212a: + case 0x213a: + case 0x214a: + case 0x215a: + case 0x216a: + case 0x217a: + et4000->index = val; + return; + case 0x210b: + case 0x211b: + case 0x212b: + case 0x213b: + case 0x214b: + case 0x215b: + case 0x216b: + case 0x217b: + et4000->regs[et4000->index] = val; + svga->hwcursor.x = et4000->regs[0xE0] | ((et4000->regs[0xE1] & 7) << 8); + svga->hwcursor.y = et4000->regs[0xE4] | ((et4000->regs[0xE5] & 7) << 8); + svga->hwcursor.ena = !!(et4000->regs[0xF7] & 0x80); + svga->hwcursor.xoff = et4000->regs[0xE2]; + svga->hwcursor.yoff = et4000->regs[0xE6]; + svga->hwcursor.xsize = svga->hwcursor.ysize = ((et4000->regs[0xEF] & 4) || ((et4000->type == ET4000W32) && (et4000->regs[0xe2] >= 0x1f) && (et4000->regs[0xe6] >= 0x1f))) ? 128 : 64; + + if (et4000->type == ET4000W32) { + if ((svga->bpp == 15) || (svga->bpp == 16)) { + svga->hwcursor.xsize = svga->hwcursor.ysize = 128; + } + } + + if ((et4000->type == ET4000W32) && (svga->hwcursor.xsize == 128)) { + switch (svga->bpp) { + case 8: + svga->hwcursor.xoff += 32; + break; + + default: + break; + } + } + + if (svga->hwcursor.xsize == 128) { + svga->hwcursor.xoff &= 0x7f; + svga->hwcursor.yoff &= 0x7f; + if (et4000->type > ET4000W32P_REVC) { + if (svga->bpp == 24) { + et4000->adjust_cursor = 2; + } + } + } else { + if (et4000->type > ET4000W32P_REVC) { + if ((svga->bpp == 24) && et4000->adjust_cursor) { + et4000->adjust_cursor = 0; + } + } + svga->hwcursor.xoff &= 0x3f; + svga->hwcursor.yoff &= 0x3f; + } + svga->hwcursor.addr = (et4000->regs[0xe8] | (et4000->regs[0xe9] << 8) | ((et4000->regs[0xea] & 7) << 16)) << 2; + + add2addr = svga->hwcursor.yoff * ((svga->hwcursor.xsize == 128) ? 32 : 16); + svga->hwcursor.addr += add2addr; + return; + + default: + break; + } + + svga_out(addr, val, svga); +} + +uint8_t +et4000w32p_in(uint16_t addr, void *priv) +{ + et4000w32p_t *et4000 = (et4000w32p_t *) priv; + svga_t *svga = &et4000->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c5: + if ((svga->seqaddr & 0xf) == 7) + return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; +#if 0 + case 0x3c6: + case 0x3c7: + case 0x3c8: + case 0x3c9: + if (et4000->type <= ET4000W32P_REVC) + return sdac_ramdac_in(addr, &et4000->ramdac, svga); + else + return stg_ramdac_in(addr, svga->ramdac, svga); +#endif + case 0x3cb: + return et4000->banking2; + case 0x3cd: + return et4000->banking; + case 0x3d4: + return svga->crtcreg; + case 0x3d5: + if (et4000->type == ET4000W32) { + if (svga->crtcreg == 0x37) + return 0x09; + } + return svga->crtc[svga->crtcreg]; + + case 0x3da: + svga->attrff = 0; + + /*Bit 1 of the Input Status Register is required by the OS/2 and NT ET4000W32/I drivers to be set otherwise + the guest will loop infinitely upon reaching the GUI*/ + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x32; + else + svga->cgastat ^= 0x32; + return svga->cgastat; + + case 0x210a: + case 0x211a: + case 0x212a: + case 0x213a: + case 0x214a: + case 0x215a: + case 0x216a: + case 0x217a: + return et4000->index; + case 0x210B: + case 0x211B: + case 0x212B: + case 0x213B: + case 0x214B: + case 0x215B: + case 0x216B: + case 0x217B: + if (et4000->index == 0xec) { + return (et4000->regs[0xec] & 0xf) | (et4000->rev << 4); + } + if (et4000->index == 0xee) { + if (svga->bpp == 8) { + if ((svga->gdcreg[5] & 0x60) >= 0x40) + return 3; + else if ((svga->gdcreg[5] & 0x60) == 0x20) + return 1; + else + return 2; + } else if (svga->bpp == 15 || svga->bpp == 16) + return 4; + else + break; + } + if (et4000->index == 0xef) { + if (et4000->pci) + return (et4000->regs[0xef] & 0x0f) | (et4000->rev << 4) | et4000->pci; + else + return (et4000->regs[0xef] & 0x8f) | (et4000->rev << 4) | et4000->vlb; + } + return et4000->regs[et4000->index]; + + default: + break; + } + + return svga_in(addr, svga); +} + +void +et4000w32p_recalctimings(svga_t *svga) +{ + et4000w32p_t *et4000 = (et4000w32p_t *) svga->p; + + svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; + + svga->hblankstart = (((svga->crtc[0x3f] & 0x4) >> 2) << 8) + svga->crtc[2]; + + if (svga->crtc[0x35] & 0x01) + svga->vblankstart |= 0x400; + if (svga->crtc[0x35] & 0x02) + svga->vtotal |= 0x400; + if (svga->crtc[0x35] & 0x04) + svga->dispend |= 0x400; + if (svga->crtc[0x35] & 0x08) + svga->vsyncstart |= 0x400; + if (svga->crtc[0x35] & 0x10) + svga->split |= 0x400; + if (svga->crtc[0x3F] & 0x80) + svga->rowoffset |= 0x100; + if (svga->crtc[0x3F] & 0x01) + svga->htotal |= 0x100; + if (svga->attrregs[0x16] & 0x20) { + svga->hdisp <<= 1; + svga->dots_per_clock <<= 1; + } + + bt482_recalctimings(et4000->ramdac, svga); + + //svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + + if (et4000->type != ET4000W32P_DIAMOND) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + if (svga->gdcreg[5] & 0x40) { + switch (svga->bpp) { + case 8: + svga->clock /= 2; + break; + case 15: + case 16: + svga->clock /= 3; + break; + case 24: + svga->clock /= 4; + break; + + default: + break; + } + } + } + } + + if (et4000->type == ET4000W32) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + if (svga->gdcreg[5] & 0x40) { + switch (svga->bpp) { + case 8: + if (svga->hdisp == 640 || svga->hdisp == 800 || svga->hdisp == 1024) + break; + svga->hdisp -= 24; + break; + + default: + break; + } + } + } + } + + et4000->adjust_cursor = 0; + + switch (svga->bpp) { + case 15: + case 16: + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + svga->hdisp >>= 1; + svga->dots_per_clock >>= 1; + } + if (et4000->type <= ET4000W32P_REVC) { + if (et4000->type == ET4000W32P_REVC) { + if (svga->hdisp != 1024) + et4000->adjust_cursor = 1; + } else + et4000->adjust_cursor = 1; + } + break; + case 24: + svga->hdisp /= 3; + svga->dots_per_clock /= 3; + if (et4000->type <= ET4000W32P_REVC) + et4000->adjust_cursor = 2; + if ((et4000->type == ET4000W32P_DIAMOND) && ((svga->hdisp == (640 / 2)) || (svga->hdisp == 1232))) { + svga->hdisp = 640; + } + break; + + default: + break; + } + + svga->render = svga_render_blank; + if (!svga->scrblank && svga->attr_palette_enable) { + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /* Text mode */ + if (svga->seqregs[1] & 8) /* 40 column */ + svga->render = svga_render_text_40; + else + svga->render = svga_render_text_80; + } else { + 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 */ + if (et4000->type <= ET4000W32P_REVC) + svga->clock /= 2; + + 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; + break; + case 15: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; +#if 0 + case 17: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_15bpp_mix_lowres; + else + svga->render = svga_render_15bpp_mix_highres; + break; +#endif + case 24: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres || (svga->seqregs[1] & 8)) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; + + default: + break; + } + break; + + default: + break; + } + } + } +} + +void +et4000w32p_recalcmapping(et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + int map; + + if (et4000->pci && !(et4000->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { + mem_mapping_disablex(&svga->mapping); + mem_mapping_disablex(&et4000->linear_mapping); + mem_mapping_disablex(&et4000->mmu_mapping); + return; + } + + if (svga->crtc[0x36] & 0x10) { /* Linear frame buffer */ + et4000->blitter_mmio = (svga->crtc[0x36] & 0x08) != 0; + et4000->blitter_mmio_addr = et4000->linearbase + svga->vram_max - 0x100; + mem_mapping_set_addrx(&et4000->linear_mapping, et4000->linearbase, svga->vram_max); + mem_mapping_disablex(&svga->mapping); + mem_mapping_disablex(&et4000->mmu_mapping); + } else { + map = (svga->gdcreg[6] & 0xc) >> 2; + if (svga->crtc[0x36] & 0x20) + map |= 4; + if (svga->crtc[0x36] & 0x08) + map |= 8; + mem_mapping_disablex(&et4000->linear_mapping); + switch (map) { + case 0x0: + case 0x4: + case 0x8: + case 0xc: /* 128k at A0000 */ + mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x20000); + mem_mapping_disablex(&et4000->mmu_mapping); + svga->banked_mask = 0x1ffff; + break; + case 0x1: /* 64k at A0000 */ + mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disablex(&et4000->mmu_mapping); + svga->banked_mask = 0xffff; + break; + case 0x2: /* 32k at B0000 */ + mem_mapping_set_addrx(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_disablex(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x3: /* 32k at B8000 */ + mem_mapping_set_addrx(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_disablex(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x5: + case 0x9: + case 0xd: /* 64k at A0000, MMU at B8000 */ + mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_set_addrx(&et4000->mmu_mapping, 0xb8000, 0x08000); + svga->banked_mask = 0xffff; + break; + case 0x6: + case 0xa: + case 0xe: /* 32k at B0000, MMU at A8000 */ + mem_mapping_set_addrx(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_set_addrx(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0x7: + case 0xb: + case 0xf: /* 32k at B8000, MMU at A8000 */ + mem_mapping_set_addrx(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_set_addrx(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + + default: + break; + } + } + + if (!et4000->interleaved && (svga->crtc[0x32] & 0x80)) + mem_mapping_disablex(&svga->mapping); +} + +static void +et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) +{ + et4000->acl.fifo_queue++; + switch (addr & 0xff) { + case 0x80: + et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xffffff00) | val; + break; + case 0x81: + et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xffff00ff) | (val << 8); + break; + case 0x82: + et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xff00ffff) | (val << 16); + break; + case 0x83: + et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0x00ffffff) | (val << 24); + break; + case 0x84: + et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xffffff00) | val; + break; + case 0x85: + et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xffff00ff) | (val << 8); + break; + case 0x86: + et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xff00ffff) | (val << 16); + break; + case 0x87: + et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0x00ffffff) | (val << 24); + break; + case 0x88: + et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0xff00) | val; + break; + case 0x89: + et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0x00ff) | (val << 8); + break; + case 0x8a: + et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0xff00) | val; + break; + case 0x8b: + et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0x00ff) | (val << 8); + break; + case 0x8c: + et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0xff00) | val; + break; + case 0x8d: + et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x00ff) | (val << 8); + break; + case 0x8e: + if (et4000->type >= ET4000W32P_REVC) + et4000->acl.queued.pixel_depth = val & 0x30; + else + et4000->acl.queued.vbus = val & 0x03; + break; + case 0x8f: + if (et4000->type >= ET4000W32P_REVC) + et4000->acl.queued.xy_dir = val & 0xb7; + else + et4000->acl.queued.xy_dir = val & 0x03; + break; + case 0x90: + et4000->acl.queued.pattern_wrap = val & 0x77; + break; + case 0x92: + et4000->acl.queued.source_wrap = val & 0x77; + break; + case 0x98: + et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0xff00) | val; + break; + case 0x99: + et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0x00ff) | (val << 8); + break; + case 0x9a: + et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0xff00) | val; + break; + case 0x9b: + et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x00ff) | (val << 8); + break; + case 0x9c: + if (et4000->type >= ET4000W32P_REVC) + et4000->acl.queued.ctrl_routing = val & 0xdb; + else + et4000->acl.queued.ctrl_routing = val & 0xb7; + break; + case 0x9d: + et4000->acl.queued.ctrl_reload = val & 0x03; + break; + case 0x9e: + et4000->acl.queued.rop_bg = val; + break; + case 0x9f: + et4000->acl.queued.rop_fg = val; + break; + case 0xa0: + et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xffffff00) | val; + break; + case 0xa1: + et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xffff00ff) | (val << 8); + break; + case 0xa2: + et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xff00ffff) | (val << 16); + break; + case 0xa3: + et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x00ffffff) | (val << 24); + et4000->acl.internal = et4000->acl.queued; + if (et4000->type >= ET4000W32P_REVC) { + et4000w32p_blit_start(et4000); + et4000w32_log("Destination Address write and start XY Block, xcnt = %i, ycnt = %i\n", et4000->acl.x_count + 1, et4000->acl.y_count + 1); + if (!(et4000->acl.queued.ctrl_routing & 0x43)) { + et4000w32p_blit(0xffffff, ~0, 0, 0, et4000); + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !(et4000->acl.internal.ctrl_routing & 3)) { + et4000w32p_blit(4, ~0, 0, 0, et4000); + } + } else { + et4000w32_blit_start(et4000); + et4000->acl.cpu_input_num = 0; + if (!(et4000->acl.queued.ctrl_routing & 0x37)) { + et4000->acl.mmu_start = 1; + et4000w32_blit(-1, 0, 0, 0xffffffff, et4000); + } else + et4000->acl.mmu_start = 0; + } + break; + case 0xa4: + et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFFFF00) | val; + break; + case 0xa5: + et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFF00FF) | (val << 8); + break; + case 0xa6: + et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFF00FFFF) | (val << 16); + break; + case 0xa7: + et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0x00FFFFFF) | (val << 24); + break; + case 0xa8: + et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0xFF00) | val; + break; + case 0xa9: + et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0x00FF) | (val << 8); + break; + case 0xaa: + et4000->acl.queued.error = (et4000->acl.queued.error & 0xFF00) | val; + break; + case 0xab: + et4000->acl.queued.error = (et4000->acl.queued.error & 0x00FF) | (val << 8); + break; + case 0xac: + et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0xFF00) | val; + break; + case 0xad: + et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0x00FF) | (val << 8); + break; + case 0xae: + et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0xFF00) | val; + break; + case 0xaf: + et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0x00FF) | (val << 8); + break; + + default: + break; + } +} + +static void +et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint8_t val, uint8_t bank) +{ + if (et4000->type >= ET4000W32P_REVC) { + if (!(et4000->acl.status & ACL_XYST)) { + et4000w32_log("XY MMU block not started\n"); + return; + } + if (et4000->acl.internal.ctrl_routing & 3) { + et4000->acl.fifo_queue++; + if ((et4000->acl.internal.ctrl_routing & 3) == 2) /*CPU data is Mix data*/ + et4000w32p_blit(8 - (et4000->acl.mix_addr & 7), val >> (et4000->acl.mix_addr & 7), 0, 1, et4000); + else if ((et4000->acl.internal.ctrl_routing & 3) == 1) /*CPU data is Source data*/ + et4000w32p_blit(1, ~0, val, 2, et4000); + } + } else { + if (!(et4000->acl.status & ACL_XYST)) { + et4000->acl.fifo_queue++; + et4000->acl.queued.dest_addr = ((addr & 0x1fff) + et4000->mmu.base[bank]); + et4000->acl.internal = et4000->acl.queued; + et4000w32_blit_start(et4000); + et4000w32_log("ET4000W32 Accelerated MMU aperture start XY Block (Implicit): bank = %i, patx = %i, paty = %i, wrap x = %i, wrap y = %i\n", et4000->bank, et4000->acl.pattern_x, et4000->acl.pattern_y, et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7], et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]); + et4000->acl.cpu_input_num = 0; + if (!(et4000->acl.queued.ctrl_routing & 0x37)) { + et4000->acl.mmu_start = 1; + et4000w32_blit(-1, 0, 0, 0xffffffff, et4000); + } else { + et4000->acl.mmu_start = 0; + } + } + + if (et4000->acl.internal.ctrl_routing & 7) { + et4000->acl.fifo_queue++; + et4000->acl.cpu_input = (et4000->acl.cpu_input & ~(0xff << (et4000->acl.cpu_input_num << 3))) | (val << (et4000->acl.cpu_input_num << 3)); + et4000->acl.cpu_input_num++; + + if (et4000->acl.cpu_input_num == et4000w32_vbus[et4000->acl.internal.vbus]) { + if ((et4000->acl.internal.ctrl_routing & 7) == 2) /*CPU data is Mix data*/ + et4000w32_blit(et4000->acl.cpu_input_num << 3, 2, 0, et4000->acl.cpu_input, et4000); + else if ((et4000->acl.internal.ctrl_routing & 7) == 1) /*CPU data is Source data*/ + et4000w32_blit(et4000->acl.cpu_input_num, 1, et4000->acl.cpu_input, 0xffffffff, et4000); + + et4000->acl.cpu_input_num = 0; + } + + if (et4000w32_vbus[et4000->acl.internal.vbus] == 1) { + if ((et4000->acl.internal.ctrl_routing & 7) == 4) { /*CPU data is X Count*/ + et4000w32_log("ET4000W32 Accelerated MMU aperture routing = %02x: val = %02x, cx = %02x.\n", et4000->acl.internal.ctrl_routing, val, et4000->acl.internal.count_x); + et4000->acl.cpu_x_cnt = val + 1; + et4000->acl.cpu_x_cnt |= ((et4000->acl.queued.count_x >> 8) << 8); + et4000w32_blit(et4000->acl.cpu_x_cnt, 3, 0, 0xffffffff, et4000); + } else if ((et4000->acl.internal.ctrl_routing & 7) == 5) { /*CPU data is Y Count*/ + et4000w32_log("ET4000W32 Accelerated MMU aperture routing = %02x: val = %02x, cy = %02x.\n", et4000->acl.internal.ctrl_routing, val, et4000->acl.internal.count_y); + et4000->acl.cpu_y_cnt = val + 1; + et4000->acl.cpu_y_cnt |= ((et4000->acl.queued.count_y >> 8) << 8); + et4000w32_blit(et4000->acl.cpu_y_cnt, 4, 0, 0xffffffff, et4000); + } + } + } + } +} + +static void +et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *priv) +{ + et4000w32p_t *et4000 = (et4000w32p_t *) priv; + svga_t *svga = &et4000->svga; + + switch (addr & 0x6000) { + case 0x0000: /* MMU 0 */ + case 0x2000: /* MMU 1 */ + case 0x4000: /* MMU 2 */ + et4000->bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << et4000->bank)) { + et4000w32p_accel_write_mmu(et4000, addr & 0x7fff, val, et4000->bank); + } else { + if (((addr & 0x1fff) + et4000->mmu.base[et4000->bank]) < svga->vram_max) { + svga->vram[((addr & 0x1fff) + et4000->mmu.base[et4000->bank]) & et4000->vram_mask] = val; + svga->changedvram[(((addr & 0x1fff) + et4000->mmu.base[et4000->bank]) & et4000->vram_mask) >> 12] = changeframecount; + } + } + break; + case 0x6000: + if ((addr & 0xff) >= 0x80) { + et4000w32p_accel_write_fifo(et4000, addr & 0x7fff, val); + } else { + switch (addr & 0xff) { + case 0x00: + et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xffffff00) | val; + break; + case 0x01: + et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xffff00ff) | (val << 8); + break; + case 0x02: + et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xff00ffff) | (val << 16); + break; + case 0x03: + et4000->mmu.base[0] = (et4000->mmu.base[0] & 0x00ffffff) | (val << 24); + break; + case 0x04: + et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xffffff00) | val; + break; + case 0x05: + et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xffff00ff) | (val << 8); + break; + case 0x06: + et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xff00ffff) | (val << 16); + break; + case 0x07: + et4000->mmu.base[1] = (et4000->mmu.base[1] & 0x00ffffff) | (val << 24); + break; + case 0x08: + et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xffffff00) | val; + break; + case 0x09: + et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xffff00ff) | (val << 8); + break; + case 0x0a: + et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xff00ffff) | (val << 16); + break; + case 0x0b: + et4000->mmu.base[2] = (et4000->mmu.base[2] & 0x00ffffff) | (val << 24); + break; + case 0x13: + et4000->mmu.ctrl = val; + break; + case 0x30: + et4000->acl.suspend_terminate = val; + break; + case 0x31: + et4000->acl.osr = val; + break; + + default: + break; + } + } + break; + + default: + break; + } +} + +static uint8_t +et4000w32p_mmu_read(uint32_t addr, void *priv) +{ + et4000w32p_t *et4000 = (et4000w32p_t *) priv; + const svga_t *svga = &et4000->svga; + uint8_t temp; + + switch (addr & 0x6000) { + case 0x0000: /* MMU 0 */ + case 0x2000: /* MMU 1 */ + case 0x4000: /* MMU 2 */ + et4000->bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << et4000->bank)) { + temp = 0xff; + if (et4000->acl.cpu_dat_pos) { + et4000->acl.cpu_dat_pos--; + temp = et4000->acl.cpu_dat & 0xff; + et4000->acl.cpu_dat >>= 8; + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !et4000->acl.cpu_dat_pos && !(et4000->acl.internal.ctrl_routing & 3)) + et4000w32p_blit(4, ~0, 0, 0, et4000); + + /* ???? */ + return temp; + } + + if ((addr & 0x1fff) + et4000->mmu.base[et4000->bank] >= svga->vram_max) + return 0xff; + + return svga->vram[(addr & 0x1fff) + et4000->mmu.base[et4000->bank]]; + + case 0x6000: + switch (addr & 0xff) { + case 0x00: + return et4000->mmu.base[0] & 0xff; + case 0x01: + return et4000->mmu.base[0] >> 8; + case 0x02: + return et4000->mmu.base[0] >> 16; + case 0x03: + return et4000->mmu.base[0] >> 24; + case 0x04: + return et4000->mmu.base[1] & 0xff; + case 0x05: + return et4000->mmu.base[1] >> 8; + case 0x06: + return et4000->mmu.base[1] >> 16; + case 0x07: + return et4000->mmu.base[1] >> 24; + case 0x08: + return et4000->mmu.base[2] & 0xff; + case 0x09: + return et4000->mmu.base[2] >> 8; + case 0x0a: + return et4000->mmu.base[2] >> 16; + case 0x0b: + return et4000->mmu.base[2] >> 24; + case 0x13: + return et4000->mmu.ctrl; + + case 0x36: + if (et4000->acl.fifo_queue) { + et4000->acl.status |= ACL_RDST; + et4000->acl.fifo_queue = 0; + } else + et4000->acl.status &= ~ACL_RDST; + return et4000->acl.status; + + case 0x80: + return et4000->acl.internal.pattern_addr & 0xff; + case 0x81: + return et4000->acl.internal.pattern_addr >> 8; + case 0x82: + return et4000->acl.internal.pattern_addr >> 16; + case 0x83: + return et4000->acl.internal.pattern_addr >> 24; + case 0x84: + return et4000->acl.internal.source_addr & 0xff; + case 0x85: + return et4000->acl.internal.source_addr >> 8; + case 0x86: + return et4000->acl.internal.source_addr >> 16; + case 0x87: + return et4000->acl.internal.source_addr >> 24; + case 0x88: + return et4000->acl.internal.pattern_off & 0xff; + case 0x89: + return et4000->acl.internal.pattern_off >> 8; + case 0x8a: + return et4000->acl.internal.source_off & 0xff; + case 0x8b: + return et4000->acl.internal.source_off >> 8; + case 0x8c: + return et4000->acl.internal.dest_off & 0xff; + case 0x8d: + return et4000->acl.internal.dest_off >> 8; + case 0x8e: + if (et4000->type >= ET4000W32P_REVC) + return et4000->acl.internal.pixel_depth; + return et4000->acl.internal.vbus; + case 0x8f: + return et4000->acl.internal.xy_dir; + case 0x90: + return et4000->acl.internal.pattern_wrap; + case 0x92: + return et4000->acl.internal.source_wrap; + case 0x98: + return et4000->acl.internal.count_x & 0xff; + case 0x99: + return et4000->acl.internal.count_x >> 8; + case 0x9a: + return et4000->acl.internal.count_y & 0xff; + case 0x9b: + return et4000->acl.internal.count_y >> 8; + case 0x9c: + return et4000->acl.internal.ctrl_routing; + case 0x9d: + return et4000->acl.internal.ctrl_reload; + case 0x9e: + return et4000->acl.internal.rop_bg; + case 0x9f: + return et4000->acl.internal.rop_fg; + case 0xa0: + return et4000->acl.internal.dest_addr & 0xff; + case 0xa1: + return et4000->acl.internal.dest_addr >> 8; + case 0xa2: + return et4000->acl.internal.dest_addr >> 16; + case 0xa3: + return et4000->acl.internal.dest_addr >> 24; + + default: + break; + } + + return 0xff; + + default: + break; + } + + return 0xff; +} + +void +et4000w32_blit_start(et4000w32p_t *et4000) +{ + et4000->acl.x_count = et4000->acl.internal.count_x; + et4000->acl.y_count = et4000->acl.internal.count_y; + + et4000->acl.pattern_addr = et4000->acl.internal.pattern_addr; + et4000->acl.source_addr = et4000->acl.internal.source_addr; + et4000->acl.dest_addr = et4000->acl.internal.dest_addr; + et4000->acl.dest_back = et4000->acl.dest_addr; + et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0; + + et4000->acl.status |= ACL_XYST; + et4000->acl.status &= ~ACL_SSO; + + if (!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) + et4000->acl.status |= ACL_SSO; + + if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) { + et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + } + et4000->acl.pattern_back = et4000->acl.pattern_addr; + + if (!(et4000->acl.internal.pattern_wrap & 0x40)) { + if ((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) == 0x00) { /*This is to avoid a division by zero crash*/ + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (0x7f + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + } else + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1); + } + et4000->acl.pattern_x_back = et4000->acl.pattern_x; + + if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) { + et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + } + et4000->acl.source_back = et4000->acl.source_addr; + + if (!(et4000->acl.internal.source_wrap & 0x40)) { + if ((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) == 0x00) { /*This is to avoid a division by zero crash*/ + et4000->acl.source_y = (et4000->acl.source_addr / (0x7f + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + } else + et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1); + } + et4000->acl.source_x_back = et4000->acl.source_x; + + if ((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] == 7) && !(et4000->acl.internal.ctrl_routing & 0x37) && (et4000->acl.internal.rop_fg == 0x5a)) { + if ((et4000->acl.internal.count_y > 0) && (et4000->acl.pattern_y > 0)) { + if (et4000->acl.pattern_addr == et4000->acl.pattern_back) + et4000->acl.pattern_y = 0; + else { + et4000->acl.pattern_y = (et4000->acl.pattern_addr - et4000->acl.pattern_back) & 0x70; + et4000->acl.pattern_y >>= 4; + } + } + } else if ((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] == 15) && !(et4000->acl.internal.ctrl_routing & 0x37) && (et4000->acl.internal.rop_fg == 0x5a)) { + if ((et4000->acl.internal.count_y > 0) && (et4000->acl.pattern_y > 0)) { + if (et4000->acl.pattern_addr == et4000->acl.pattern_back) + et4000->acl.pattern_y = 0; + else { + et4000->acl.pattern_y = (et4000->acl.pattern_addr - et4000->acl.pattern_back) & 0xf0; + et4000->acl.pattern_y >>= 5; + } + } + } +} + +static void +et4000w32p_blit_start(et4000w32p_t *et4000) +{ + et4000->acl.x_count = et4000->acl.internal.count_x; + et4000->acl.y_count = et4000->acl.internal.count_y; + + if (!(et4000->acl.queued.xy_dir & 0x20)) + et4000->acl.internal.error = et4000->acl.internal.dmaj / 2; + + et4000->acl.pattern_addr = et4000->acl.internal.pattern_addr; + et4000->acl.source_addr = et4000->acl.internal.source_addr; + et4000->acl.mix_addr = et4000->acl.internal.mix_addr; + et4000->acl.mix_back = et4000->acl.mix_addr; + et4000->acl.dest_addr = et4000->acl.internal.dest_addr; + et4000->acl.dest_back = et4000->acl.dest_addr; + et4000->acl.internal.pos_x = et4000->acl.internal.pos_y = 0; + et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0; + et4000->acl.status |= ACL_XYST; + + et4000w32_log("ACL status XYST set\n"); + if ((!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) && !(et4000->acl.internal.ctrl_routing & 0x40)) + et4000->acl.status |= ACL_SSO; + + if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) { + et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + } + et4000->acl.pattern_back = et4000->acl.pattern_addr; + if (!(et4000->acl.internal.pattern_wrap & 0x40)) { + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1); + } + et4000->acl.pattern_x_back = et4000->acl.pattern_x; + + if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) { + et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + } + et4000->acl.source_back = et4000->acl.source_addr; + + if (!(et4000->acl.internal.source_wrap & 0x40)) { + et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1); + } + et4000->acl.source_x_back = et4000->acl.source_x; + + et4000w32_max_x[2] = (et4000->acl.internal.pixel_depth == 0x20) ? 3 : 4; + + et4000->acl.internal.count_x += (et4000->acl.internal.pixel_depth >> 4) & 3; + et4000->acl.cpu_dat_pos = 0; + et4000->acl.cpu_dat = 0; + + et4000->acl.pix_pos = 0; +} + +void +et4000w32_incx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr += c; + et4000->acl.pattern_x += c; + et4000->acl.source_x += c; + et4000->acl.mix_addr += c; + if (et4000->acl.pattern_x >= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]) + et4000->acl.pattern_x -= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x >= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]) + et4000->acl.source_x -= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} + +void +et4000w32_decx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr -= c; + et4000->acl.pattern_x -= c; + et4000->acl.source_x -= c; + et4000->acl.mix_addr -= c; + if (et4000->acl.pattern_x < 0) + et4000->acl.pattern_x += et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x < 0) + et4000->acl.source_x += et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} + +void +et4000w32_incy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr += et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr += et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr += et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr += et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y++; + if (et4000->acl.pattern_y == et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) { + et4000->acl.pattern_y = 0; + et4000->acl.pattern_addr = et4000->acl.pattern_back; + } + et4000->acl.source_y++; + if (et4000->acl.source_y == et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) { + et4000->acl.source_y = 0; + et4000->acl.source_addr = et4000->acl.source_back; + } +} + +void +et4000w32_decy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr -= et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr -= et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr -= et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr -= et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y--; + if ((et4000->acl.pattern_y < 0) && !(et4000->acl.internal.pattern_wrap & 0x40)) { + et4000->acl.pattern_y = et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1; + et4000->acl.pattern_addr = et4000->acl.pattern_back + (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1)); + } + et4000->acl.source_y--; + if ((et4000->acl.source_y < 0) && !(et4000->acl.internal.source_wrap & 0x40)) { + et4000->acl.source_y = et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1; + et4000->acl.source_addr = et4000->acl.source_back + (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1)); + } +} + +static uint8_t ROPMIX(uint8_t R, uint8_t D, uint8_t P, uint8_t S) +{ + uint8_t out; + switch (R) { + case 0x00: + out = 0; + break; + case 0x01: + out = ~(D | (P | S)); + break; + case 0x02: + out = D & ~(P | S); + break; + case 0x03: + out = ~(P | S); + break; + case 0x04: + out = S & ~(D | P); + break; + case 0x05: + out = ~(D | P); + break; + case 0x06: + out = ~(P | ~(D ^ S)); + break; + case 0x07: + out = ~(P | (D & S)); + break; + case 0x08: + out = S & (D & ~P); + break; + case 0x09: + out = ~(P | (D ^ S)); + break; + case 0x0a: + out = D & ~P; + break; + case 0x0b: + out = ~(P | (S & ~D)); + break; + case 0x0c: + out = S & ~P; + break; + case 0x0d: + out = ~(P | (D & ~S)); + break; + case 0x0e: + out = ~(P | ~(D | S)); + break; + case 0x0f: + out = ~P; + break; + case 0x10: + out = P & ~(D | S); + break; + case 0x11: + out = ~(D | S); + break; + case 0x12: + out = ~(S | ~(D ^ P)); + break; + case 0x13: + out = ~(S | (D & P)); + break; + case 0x14: + out = ~(D | ~(P ^ S)); + break; + case 0x15: + out = ~(D | (P & S)); + break; + case 0x16: + out = P ^ (S ^ (D & ~(P & S))); + break; + case 0x17: + out = ~(S ^ ((S ^ P) & (D ^ S))); + break; + case 0x18: + out = (S ^ P) & (P ^ D); + break; + case 0x19: + out = ~(S ^ (D & ~(P & S))); + break; + case 0x1a: + out = P ^ (D | (S & P)); + break; + case 0x1b: + out = ~(S ^ (D & (P ^ S))); + break; + case 0x1c: + out = P ^ (S | (D & P)); + break; + case 0x1d: + out = ~(D ^ (S & (P ^ D))); + break; + case 0x1e: + out = P ^ (D | S); + break; + case 0x1f: + out = ~(P & (D | S)); + break; + case 0x20: + out = D & (P & ~S); + break; + case 0x21: + out = ~(S | (D ^ P)); + break; + case 0x22: + out = D & ~S; + break; + case 0x23: + out = ~(S | (P & ~D)); + break; + case 0x24: + out = (S ^ P) & (D ^ S); + break; + case 0x25: + out = ~(P ^ (D & ~(S & P))); + break; + case 0x26: + out = S ^ (D | (P & S)); + break; + case 0x27: + out = S ^ (D | ~(P ^ S)); + break; + case 0x28: + out = D & (P ^ S); + break; + case 0x29: + out = ~(P ^ (S ^ (D | (P & S)))); + break; + case 0x2a: + out = D & ~(P & S); + break; + case 0x2b: + out = ~(S ^ ((S ^ P) & (P ^ D))); + break; + case 0x2c: + out = S ^ (P & (D | S)); + break; + case 0x2d: + out = P ^ (S | ~D); + break; + case 0x2e: + out = P ^ (S | (D ^ P)); + break; + case 0x2f: + out = ~(P & (S | ~D)); + break; + case 0x30: + out = P & ~S; + break; + case 0x31: + out = ~(S | (D & ~P)); + break; + case 0x32: + out = S ^ (D | (P | S)); + break; + case 0x33: + out = ~S; + break; + case 0x34: + out = S ^ (P | (D & S)); + break; + case 0x35: + out = S ^ (P | ~(D ^ S)); + break; + case 0x36: + out = S ^ (D | P); + break; + case 0x37: + out = ~(S & (D | P)); + break; + case 0x38: + out = P ^ (S & (D | P)); + break; + case 0x39: + out = S ^ (P | ~D); + break; + case 0x3a: + out = S ^ (P | (D ^ S)); + break; + case 0x3b: + out = ~(S & (P | ~D)); + break; + case 0x3c: + out = P ^ S; + break; + case 0x3d: + out = S ^ (P | ~(D | S)); + break; + case 0x3e: + out = S ^ (P | (D & ~S)); + break; + case 0x3f: + out = ~(P & S); + break; + case 0x40: + out = P & (S & ~D); + break; + case 0x41: + out = ~(D | (P ^ S)); + break; + case 0x42: + out = (S ^ D) & (P ^ D); + break; + case 0x43: + out = ~(S ^ (P & ~(D & S))); + break; + case 0x44: + out = S & ~D; + break; + case 0x45: + out = ~(D | (P & ~S)); + break; + case 0x46: + out = D ^ (S | (P & D)); + break; + case 0x47: + out = ~(P ^ (S & (D ^ P))); + break; + case 0x48: + out = S & (D ^ P); + break; + case 0x49: + out = ~(P ^ (D ^ (S | (P & D)))); + break; + case 0x4a: + out = D ^ (P & (S | D)); + break; + case 0x4b: + out = P ^ (D | ~S); + break; + case 0x4c: + out = S & ~(D & P); + break; + case 0x4d: + out = ~(S ^ ((S ^ P) | (D ^ S))); + break; + case 0x4e: + out = P ^ (D | (S ^ P)); + break; + case 0x4f: + out = ~(P & (D | ~S)); + break; + case 0x50: + out = P & ~D; + break; + case 0x51: + out = ~(D | (S & ~P)); + break; + case 0x52: + out = D ^ (P | (S & D)); + break; + case 0x53: + out = ~(S ^ (P & (D ^ S))); + break; + case 0x54: + out = ~(D | ~(P | S)); + break; + case 0x55: + out = ~D; + break; + case 0x56: + out = D ^ (P | S); + break; + case 0x57: + out = ~(D & (P | S)); + break; + case 0x58: + out = P ^ (D & (S | P)); + break; + case 0x59: + out = D ^ (P | ~S); + break; + case 0x5a: + out = D ^ P; + break; + case 0x5b: + out = D ^ (P | ~(S | D)); + break; + case 0x5c: + out = D ^ (P | (S ^ D)); + break; + case 0x5d: + out = ~(D & (P | ~S)); + break; + case 0x5e: + out = D ^ (P | (S & ~D)); + break; + case 0x5f: + out = ~(D & P); + break; + case 0x60: + out = P & (D ^ S); + break; + case 0x61: + out = ~(D ^ (S ^ (P | (D & S)))); + break; + case 0x62: + out = D ^ (S & (P | D)); + break; + case 0x63: + out = S ^ (D | ~P); + break; + case 0x64: + out = S ^ (D & (P | S)); + break; + case 0x65: + out = D ^ (S | ~P); + break; + case 0x66: + out = D ^ S; + break; + case 0x67: + out = S ^ (D | ~(P | S)); + break; + case 0x68: + out = ~(D ^ (S ^ (P | ~(D | S)))); + break; + case 0x69: + out = ~(P ^ (D ^ S)); + break; + case 0x6a: + out = D ^ (P & S); + break; + case 0x6b: + out = ~(P ^ (S ^ (D & (P | S)))); + break; + case 0x6c: + out = S ^ (D & P); + break; + case 0x6d: + out = ~(P ^ (D ^ (S & (P | D)))); + break; + case 0x6e: + out = S ^ (D & (P | ~S)); + break; + case 0x6f: + out = ~(P & ~(D ^ S)); + break; + case 0x70: + out = P & ~(D & S); + break; + case 0x71: + out = ~(S ^ ((S ^ D) & (P ^ D))); + break; + case 0x72: + out = S ^ (D | (P ^ S)); + break; + case 0x73: + out = ~(S & (D | ~P)); + break; + case 0x74: + out = D ^ (S | (P ^ D)); + break; + case 0x75: + out = ~(D & (S | ~P)); + break; + case 0x76: + out = S ^ (D | (P & ~S)); + break; + case 0x77: + out = ~(D & S); + break; + case 0x78: + out = P ^ (D & S); + break; + case 0x79: + out = ~(D ^ (S ^ (P & (D | S)))); + break; + case 0x7a: + out = D ^ (P & (S | ~D)); + break; + case 0x7b: + out = ~(S & ~(D ^ P)); + break; + case 0x7c: + out = S ^ (P & (D | ~S)); + break; + case 0x7d: + out = ~(D & ~(P ^ S)); + break; + case 0x7e: + out = (S ^ P) | (D ^ S); + break; + case 0x7f: + out = ~(D & (P & S)); + break; + case 0x80: + out = D & (P & S); + break; + case 0x81: + out = ~((S ^ P) | (D ^ S)); + break; + case 0x82: + out = D & ~(P ^ S); + break; + case 0x83: + out = ~(S ^ (P & (D | ~S))); + break; + case 0x84: + out = S & ~(D ^ P); + break; + case 0x85: + out = ~(P ^ (D & (S | ~P))); + break; + case 0x86: + out = D ^ (S ^ (P & (D | S))); + break; + case 0x87: + out = ~(P ^ (D & S)); + break; + case 0x88: + out = D & S; + break; + case 0x89: + out = ~(S ^ (D | (P & ~S))); + break; + case 0x8a: + out = D & (S | ~P); + break; + case 0x8b: + out = ~(D ^ (S | (P ^ D))); + break; + case 0x8c: + out = S & (D | ~P); + break; + case 0x8d: + out = ~(S ^ (D | (P ^ S))); + break; + case 0x8e: + out = S ^ ((S ^ D) & (P ^ D)); + break; + case 0x8f: + out = ~(P & ~(D & S)); + break; + case 0x90: + out = P & ~(D ^ S); + break; + case 0x91: + out = ~(S ^ (D & (P | ~S))); + break; + case 0x92: + out = D ^ (P ^ (S & (D | P))); + break; + case 0x93: + out = ~(S ^ (P & D)); + break; + case 0x94: + out = P ^ (S ^ (D & (P | S))); + break; + case 0x95: + out = ~(D ^ (P & S)); + break; + case 0x96: + out = D ^ (P ^ S); + break; + case 0x97: + out = P ^ (S ^ (D | ~(P | S))); + break; + case 0x98: + out = ~(S ^ (D | ~(P | S))); + break; + case 0x99: + out = ~(D ^ S); + break; + case 0x9a: + out = D ^ (P & ~S); + break; + case 0x9b: + out = ~(S ^ (D & (P | S))); + break; + case 0x9c: + out = S ^ (P & ~D); + break; + case 0x9d: + out = ~(D ^ (S & (P | D))); + break; + case 0x9e: + out = D ^ (S ^ (P | (D & S))); + break; + case 0x9f: + out = ~(P & (D ^ S)); + break; + case 0xa0: + out = D & P; + break; + case 0xa1: + out = ~(P ^ (D | (S & ~P))); + break; + case 0xa2: + out = D & (P | ~S); + break; + case 0xa3: + out = ~(D ^ (P | (S ^ D))); + break; + case 0xa4: + out = ~(P ^ (D | ~(S | P))); + break; + case 0xa5: + out = ~(P ^ D); + break; + case 0xa6: + out = D ^ (S & ~P); + break; + case 0xa7: + out = ~(P ^ (D & (S | P))); + break; + case 0xa8: + out = D & (P | S); + break; + case 0xa9: + out = ~(D ^ (P | S)); + break; + case 0xaa: + out = D; + break; + case 0xab: + out = D | ~(P | S); + break; + case 0xac: + out = S ^ (P & (D ^ S)); + break; + case 0xad: + out = ~(D ^ (P | (S & D))); + break; + case 0xae: + out = D | (S & ~P); + break; + case 0xaf: + out = D | ~P; + break; + case 0xb0: + out = P & (D | ~S); + break; + case 0xb1: + out = ~(P ^ (D | (S ^ P))); + break; + case 0xb2: + out = S ^ ((S ^ P) | (D ^ S)); + break; + case 0xb3: + out = ~(S & ~(D & P)); + break; + case 0xb4: + out = P ^ (S & ~D); + break; + case 0xb5: + out = ~(D ^ (P & (S | D))); + break; + case 0xb6: + out = D ^ (P ^ (S | (D & P))); + break; + case 0xb7: + out = ~(S & (D ^ P)); + break; + case 0xb8: + out = P ^ (S & (D ^ P)); + break; + case 0xb9: + out = ~(D ^ (S | (P & D))); + break; + case 0xba: + out = D | (P & ~S); + break; + case 0xbb: + out = D | ~S; + break; + case 0xbc: + out = S ^ (P & ~(D & S)); + break; + case 0xbd: + out = ~((S ^ D) & (P ^ D)); + break; + case 0xbe: + out = D | (P ^ S); + break; + case 0xbf: + out = D | ~(P & S); + break; + case 0xc0: + out = P & S; + break; + case 0xc1: + out = ~(S ^ (P | (D & ~S))); + break; + case 0xc2: + out = ~(S ^ (P | ~(D | S))); + break; + case 0xc3: + out = ~(P ^ S); + break; + case 0xc4: + out = S & (P | ~D); + break; + case 0xc5: + out = ~(S ^ (P | (D ^ S))); + break; + case 0xc6: + out = S ^ (D & ~P); + break; + case 0xc7: + out = ~(P ^ (S & (D | P))); + break; + case 0xc8: + out = S & (D | P); + break; + case 0xc9: + out = ~(S ^ (P | D)); + break; + case 0xca: + out = D ^ (P & (S ^ D)); + break; + case 0xcb: + out = ~(S ^ (P | (D & S))); + break; + case 0xcc: + out = S; + break; + case 0xcd: + out = S | ~(D | P); + break; + case 0xce: + out = S | (D & ~P); + break; + case 0xcf: + out = S | ~P; + break; + case 0xd0: + out = P & (S | ~D); + break; + case 0xd1: + out = ~(P ^ (S | (D ^ P))); + break; + case 0xd2: + out = P ^ (D & ~S); + break; + case 0xd3: + out = ~(S ^ (P & (D | S))); + break; + case 0xd4: + out = S ^ ((S ^ P) & (P ^ D)); + break; + case 0xd5: + out = ~(D & ~(P & S)); + break; + case 0xd6: + out = P ^ (S ^ (D | (P & S))); + break; + case 0xd7: + out = ~(D & (P ^ S)); + break; + case 0xd8: + out = P ^ (D & (S ^ P)); + break; + case 0xd9: + out = ~(S ^ (D | (P & S))); + break; + case 0xda: + out = D ^ (P & ~(S & D)); + break; + case 0xdb: + out = ~((S ^ P) & (D ^ S)); + break; + case 0xdc: + out = S | (P & ~D); + break; + case 0xdd: + out = S | ~D; + break; + case 0xde: + out = S | (D ^ P); + break; + case 0xdf: + out = S | ~(D & P); + break; + case 0xe0: + out = P & (D | S); + break; + case 0xe1: + out = ~(P ^ (D | S)); + break; + case 0xe2: + out = D ^ (S & (P ^ D)); + break; + case 0xe3: + out = ~(P ^ (S | (D & P))); + break; + case 0xe4: + out = S ^ (D & (P ^ S)); + break; + case 0xe5: + out = ~(P ^ (D | (S & P))); + break; + case 0xe6: + out = S ^ (D & ~(P & S)); + break; + case 0xe7: + out = ~((S ^ P) & (P ^ D)); + break; + case 0xe8: + out = S ^ ((S ^ P) & (D ^ S)); + break; + case 0xe9: + out = ~(D ^ (S ^ (P & ~(D & S)))); + break; + case 0xea: + out = D | (P & S); + break; + case 0xeb: + out = D | ~(P ^ S); + break; + case 0xec: + out = S | (D & P); + break; + case 0xed: + out = S | ~(D ^ P); + break; + case 0xee: + out = D | S; + break; + case 0xef: + out = S | (D | ~P); + break; + case 0xf0: + out = P; + break; + case 0xf1: + out = P | ~(D | S); + break; + case 0xf2: + out = P | (D & ~S); + break; + case 0xf3: + out = P | ~S; + break; + case 0xf4: + out = P | (S & ~D); + break; + case 0xf5: + out = P | ~D; + break; + case 0xf6: + out = P | (D ^ S); + break; + case 0xf7: + out = P | ~(D & S); + break; + case 0xf8: + out = P | (D & S); + break; + case 0xf9: + out = P | ~(D ^ S); + break; + case 0xfa: + out = D | P; + break; + case 0xfb: + out = D | (P | ~S); + break; + case 0xfc: + out = P | S; + break; + case 0xfd: + out = P | (S | ~D); + break; + case 0xfe: + out = D | (P | S); + break; + case 0xff: + out = ~0; + break; + } + return out; +} + +static void +et4000w32_blit(int count, int cpu_input, uint32_t src_dat, uint32_t mix_dat, et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + uint8_t pattern; + uint8_t source; + uint8_t dest; + uint8_t rop; + uint8_t out = 0; + int mixmap; + + if (!(et4000->acl.status & ACL_XYST) && !et4000->acl.mmu_start) { + et4000w32_log("XY Block not started\n"); + return; + } + + if (cpu_input == 3) { + while (1) { + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask]; + + dest = svga->vram[et4000->acl.dest_addr & et4000->vram_mask]; + mixmap = mix_dat & 1; + + rop = mixmap ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + mix_dat >>= 1; + mix_dat |= 0x80000000; + + out = ROPMIX(rop, dest, pattern, source); + + /*Write the data*/ + svga->vram[et4000->acl.dest_addr & et4000->vram_mask] = out; + svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount; + + if (et4000->acl.internal.xy_dir & 1) + et4000w32_decx(1, et4000); + else + et4000w32_incx(1, et4000); + + count--; + if (!count) { + count = et4000->acl.cpu_x_cnt; + + if (et4000->acl.internal.xy_dir & 2) { + et4000w32_decy(et4000); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); + } else { + et4000w32_incy(et4000); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1; + } + + et4000->acl.pattern_x = et4000->acl.pattern_x_back; + et4000->acl.source_x = et4000->acl.source_x_back; + + et4000->acl.y_count--; + if (et4000->acl.y_count == 0xffff) { + et4000->acl.status &= ~ACL_XYST; + if (!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) { + et4000w32_log("W32i: end blit, xcount = %i\n", et4000->acl.x_count); + et4000->acl.status &= ~ACL_SSO; + } + return; + } + } + } + } else if (cpu_input == 4) { + while (1) { + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask]; + + dest = svga->vram[et4000->acl.dest_addr & et4000->vram_mask]; + mixmap = mix_dat & 1; + + rop = mixmap ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + mix_dat >>= 1; + mix_dat |= 0x80000000; + + out = ROPMIX(rop, dest, pattern, source); + + /*Write the data*/ + svga->vram[et4000->acl.dest_addr & et4000->vram_mask] = out; + svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount; + + if (et4000->acl.internal.xy_dir & 1) + et4000w32_decx(1, et4000); + else + et4000w32_incx(1, et4000); + + et4000->acl.x_count--; + if (et4000->acl.x_count == 0xffff) { + et4000->acl.x_count = et4000->acl.internal.count_x; + + if (et4000->acl.internal.xy_dir & 2) { + et4000w32_decy(et4000); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); + } else { + et4000w32_incy(et4000); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1; + } + + et4000->acl.pattern_x = et4000->acl.pattern_x_back; + et4000->acl.source_x = et4000->acl.source_x_back; + + count--; + if (!count) { + et4000->acl.status &= ~ACL_XYST; + if (!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) { + et4000w32_log("W32i: end blit, xcount = %i\n", et4000->acl.x_count); + et4000->acl.status &= ~ACL_SSO; + } + return; + } + } + } + } else { + while (count-- && (et4000->acl.y_count >= 0)) { + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask]; + + if (cpu_input == 1) { + source = src_dat & 0xff; + src_dat >>= 8; + } else /*The source data is from the display memory if the Control Routing register is not set to 1*/ + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask]; + + dest = svga->vram[et4000->acl.dest_addr & et4000->vram_mask]; + mixmap = mix_dat & 1; + + /*Now determine the Raster Operation*/ + rop = mixmap ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + mix_dat >>= 1; + mix_dat |= 0x80000000; + + out = ROPMIX(rop, dest, pattern, source); + + /*Write the data*/ + svga->vram[et4000->acl.dest_addr & et4000->vram_mask] = out; + svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount; + + if (et4000->acl.internal.xy_dir & 1) + et4000w32_decx(1, et4000); + else + et4000w32_incx(1, et4000); + + et4000->acl.x_count--; + if (et4000->acl.x_count == 0xffff) { + et4000->acl.x_count = et4000->acl.internal.count_x; + + if (et4000->acl.internal.xy_dir & 2) { + et4000w32_decy(et4000); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); + } else { + et4000w32_incy(et4000); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1; + } + + et4000->acl.pattern_x = et4000->acl.pattern_x_back; + et4000->acl.source_x = et4000->acl.source_x_back; + + et4000->acl.y_count--; + if (et4000->acl.y_count == 0xffff) { + et4000->acl.status &= ~ACL_XYST; + if (!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) { + et4000w32_log("W32i: end blit, xcount = %i\n", et4000->acl.x_count); + et4000->acl.status &= ~ACL_SSO; + } + et4000->acl.cpu_input_num = 0; + return; + } + + if (cpu_input) { + return; + } + } + } + } +} + +static void +et4000w32p_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + uint8_t pattern; + uint8_t source; + uint8_t dest; + uint8_t out; + uint8_t rop; + int mixdat; + + if (!(et4000->acl.status & ACL_XYST)) { + et4000w32_log("XY Block not started\n"); + return; + } + + if (et4000->acl.internal.xy_dir & 0x80) { /* Line draw */ + et4000w32_log("Line draw\n"); + while (count--) { + et4000w32_log("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask]; + et4000w32_log("%06X %06X ", (et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask, (et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask); + if (cpu_input == 2) { + source = sdat & 0xff; + sdat >>= 8; + } + dest = svga->vram[et4000->acl.dest_addr & et4000->vram_mask]; + out = 0; + et4000w32_log("%06X ", et4000->acl.dest_addr); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & et4000->vram_mask] & (1 << (et4000->acl.mix_addr & 7)); + et4000w32_log("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & et4000->vram_mask]); + } else { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + et4000->acl.mix_addr++; + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + + out = ROPMIX(rop, dest, pattern, source); + + et4000w32_log("%06X = %02X\n", et4000->acl.dest_addr & et4000->vram_mask, out); + if (!(et4000->acl.internal.ctrl_routing & 0x40)) { + svga->vram[et4000->acl.dest_addr & et4000->vram_mask] = out; + svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount; + } else { + et4000->acl.cpu_dat |= ((uint64_t) out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } + + et4000->acl.pix_pos++; + et4000->acl.internal.pos_x++; + if (et4000->acl.pix_pos <= ((et4000->acl.internal.pixel_depth >> 4) & 3)) { + if (et4000->acl.internal.xy_dir & 1) + et4000w32_decx(1, et4000); + else + et4000w32_incx(1, et4000); + } else { + if (et4000->acl.internal.xy_dir & 1) + et4000w32_incx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + else + et4000w32_decx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + et4000->acl.pix_pos = 0; + + /*Next pixel*/ + switch (et4000->acl.internal.xy_dir & 7) { + case 0: + case 1: /* Y+ */ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 2: + case 3: /* Y- */ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 4: + case 6: /* X+ */ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + break; + case 5: + case 7: /* X- */ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + break; + + default: + break; + } + et4000->acl.internal.error += et4000->acl.internal.dmin; + if (et4000->acl.internal.error > et4000->acl.internal.dmaj) { + et4000->acl.internal.error -= et4000->acl.internal.dmaj; + switch (et4000->acl.internal.xy_dir & 7) { + case 0: + case 2: /* X+ */ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 1: + case 3: /* X- */ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 4: + case 5: /* Y+ */ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + break; + case 6: + case 7: /* Y- */ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + break; + + default: + break; + } + } + if ((et4000->acl.internal.pos_x > et4000->acl.internal.count_x) || (et4000->acl.internal.pos_y > et4000->acl.internal.count_y)) { + et4000w32_log("ACL status linedraw 0\n"); + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); + return; + } + } + } + } else { + et4000w32_log("BitBLT: count = %i\n", count); + while (count-- && et4000->acl.y_count >= 0) { + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask]; + + if (cpu_input == 2) { + source = sdat & 0xff; + sdat >>= 8; + } else + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask]; + + dest = svga->vram[et4000->acl.dest_addr & et4000->vram_mask]; + out = 0; + + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & et4000->vram_mask] & (1 << (et4000->acl.mix_addr & 7)); + } else { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + + out = ROPMIX(rop, dest, pattern, source); + + if (!(et4000->acl.internal.ctrl_routing & 0x40)) { + svga->vram[et4000->acl.dest_addr & et4000->vram_mask] = out; + svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount; + } else { + et4000->acl.cpu_dat |= ((uint64_t) out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } + + if (et4000->acl.internal.xy_dir & 1) + et4000w32_decx(1, et4000); + else + et4000w32_incx(1, et4000); + + et4000->acl.x_count--; + if (et4000->acl.x_count == 0xffff) { + if (et4000->acl.internal.xy_dir & 2) { + et4000w32_decy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back - (et4000->acl.internal.mix_off + 1); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); + } else { + et4000w32_incy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back + et4000->acl.internal.mix_off + 1; + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1; + } + + et4000->acl.pattern_x = et4000->acl.pattern_x_back; + et4000->acl.source_x = et4000->acl.source_x_back; + + et4000->acl.y_count--; + et4000->acl.x_count = et4000->acl.internal.count_x; + if (et4000->acl.y_count == 0xffff) { + et4000w32_log("BitBLT end\n"); + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); + return; + } + + if (cpu_input) + return; + + if (et4000->acl.internal.ctrl_routing & 0x40) { + if (et4000->acl.cpu_dat_pos & 3) + et4000->acl.cpu_dat_pos += 4 - (et4000->acl.cpu_dat_pos & 3); + return; + } + } + } + } +} + +void +et4000w32p_hwcursor_draw(svga_t *svga, int displine) +{ + const et4000w32p_t *et4000 = (et4000w32p_t *) svga->p; + int offset; + int xx; + int xx2; + int shift = (et4000->adjust_cursor + 1); + int width = (svga->hwcursor_latch.xsize - svga->hwcursor_latch.xoff); + int pitch = (svga->hwcursor_latch.xsize == 128) ? 32 : 16; + int x_acc = 4; + int minus_width = 0; + uint8_t dat; + + offset = svga->hwcursor_latch.xoff; + + if ((et4000->type == ET4000W32) && (pitch == 32)) { + switch (svga->bpp) { + case 8: + minus_width = 0; + x_acc = 2; + break; + case 15: + case 16: + minus_width = 64; + x_acc = 2; + break; + + default: + break; + } + } + + for (int x = 0; x < (width - minus_width); x += x_acc) { + dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; + + xx = svga->hwcursor_latch.x + svga->x_add + x; + + if (!(xx % shift)) { + xx2 = xx / shift; + if (!(dat & 2)) + buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) + buffer32->line[displine][xx2] ^= 0xFFFFFF; + } + dat >>= 2; + xx++; + if (!(xx % shift)) { + xx2 = xx / shift; + if (!(dat & 2)) + buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) + buffer32->line[displine][xx2] ^= 0xFFFFFF; + } + dat >>= 2; + xx++; + if (!(xx % shift)) { + xx2 = xx / shift; + if (!(dat & 2)) + buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) + buffer32->line[displine][xx2] ^= 0xFFFFFF; + } + dat >>= 2; + xx++; + if (!(xx % shift)) { + xx2 = xx / shift; + if (!(dat & 2)) + buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) + buffer32->line[displine][xx2] ^= 0xFFFFFF; + } + dat >>= 2; + + offset += 4; + } + + svga->hwcursor_latch.addr += pitch; +} + +static void +et4000w32p_io_remove(et4000w32p_t *et4000) +{ + io_removehandlerx(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_removehandlerx(0x210a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandlerx(0x211a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandlerx(0x212a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandlerx(0x213a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandlerx(0x214a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandlerx(0x215a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandlerx(0x216a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandlerx(0x217a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +} + +static void +et4000w32p_io_set(et4000w32p_t *et4000) +{ + et4000w32p_io_remove(et4000); + + io_sethandlerx(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_sethandlerx(0x210a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandlerx(0x211a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandlerx(0x212a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandlerx(0x213a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandlerx(0x214a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandlerx(0x215a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandlerx(0x216a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandlerx(0x217a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +} + +uint8_t +et4000w32p_pci_read(int func, int addr, void *priv) +{ + const et4000w32p_t *et4000 = (et4000w32p_t *) priv; + + if (func > 0) + return 0xff; + + addr &= 0xff; + + switch (addr) { + case 0x00: + return 0x0c; /* Tseng Labs */ + case 0x01: + return 0x10; + + case 0x02: + return (et4000->rev); + case 0x03: + return 0x32; + + case PCI_REG_COMMAND: + return et4000->pci_regs[PCI_REG_COMMAND] | 0x80; /* Respond to IO and memory accesses */ + + case 0x07: + return 1 << 1; /* Medium DEVSEL timing */ + + case 0x08: + return (et4000->rev); /* Revision ID */ + case 0x09: + return 0; /* Programming interface */ + + case 0x0a: + return 0x00; /* Supports VGA interface */ + case 0x0b: + return 0x03; /* This has to be done in order to make this card work with the two 486 PCI machines. */ + + case 0x10: + return 0x00; /* Linear frame buffer address */ + case 0x11: + return 0x00; + case 0x12: + return 0x00; + case 0x13: + return (et4000->linearbase >> 24); + + case 0x30: + return et4000->pci_regs[0x30] & 0x01; /* BIOS ROM address */ + case 0x31: + return 0x00; + case 0x32: + return 0x00; + case 0x33: + return et4000->pci_regs[0x33] & 0xf0; + + default: + break; + } + + return 0; +} + +void +et4000w32p_pci_write(int func, int addr, uint8_t val, void *priv) +{ + et4000w32p_t *et4000 = (et4000w32p_t *) priv; + svga_t *svga = &et4000->svga; + + if (func > 0) + return; + + addr &= 0xff; + + switch (addr) { + case PCI_REG_COMMAND: + et4000->pci_regs[PCI_REG_COMMAND] = (val & 0x23) | 0x80; + if (val & PCI_COMMAND_IO) + et4000w32p_io_set(et4000); + else + et4000w32p_io_remove(et4000); + et4000w32p_recalcmapping(et4000); + break; + + case 0x13: + et4000->linearbase &= 0x00c00000; + et4000->linearbase |= (et4000->pci_regs[0x13] << 24); + svga->crtc[0x30] &= 3; + svga->crtc[0x30] |= ((et4000->linearbase & 0x3f000000) >> 22); + et4000w32p_recalcmapping(et4000); + break; + + case 0x30: + case 0x31: + case 0x32: + case 0x33: + et4000->pci_regs[addr] = val; + et4000->pci_regs[0x30] = 1; + et4000->pci_regs[0x31] = 0; + et4000->pci_regs[0x32] = 0; + et4000->pci_regs[0x33] &= 0xf0; + if (et4000->pci_regs[0x30] & 0x01) { + uint32_t biosaddr = (et4000->pci_regs[0x33] << 24); + if (!biosaddr) + biosaddr = 0xc0000; + et4000w32_log("ET4000 bios_rom enabled at %08x\n", biosaddr); + mem_mapping_set_addrx(&et4000->bios_rom.mapping, biosaddr, 0x8000); + } else { + et4000w32_log("ET4000 bios_rom disabled\n"); + mem_mapping_disablex(&et4000->bios_rom.mapping); + } + return; + + default: + break; + } +} + +static uint32_t et4000_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; + if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) { + uint32_t v = 0; + v |= et4000w32p_mmu_read((addr & 0xff) + 0x6000, p) << 0; + v |= et4000w32p_mmu_read((addr & 0xff) + 0x6001, p) << 8; + v |= et4000w32p_mmu_read((addr & 0xff) + 0x6002, p) << 16; + v |= et4000w32p_mmu_read((addr & 0xff) + 0x6003, p) << 24; + return v; + } + return svga_readl_linear(addr, p); +} + +static uint16_t et4000_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; + if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) { + uint16_t v = 0; + v |= et4000w32p_mmu_read((addr & 0xff) + 0x6000, p) << 0; + v |= et4000w32p_mmu_read((addr & 0xff) + 0x6001, p) << 8; + return v; + } + return svga_readw_linear(addr, p); +} + +static uint8_t et4000_read_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; + if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) { + uint8_t v = 0; + v |= et4000w32p_mmu_read((addr & 0xff) + 0x6000, p) << 0; + return v; + } + return svga_read_linear(addr, p); +} + +static void et4000_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t*)p; + et4000w32p_t *et4000 = (et4000w32p_t*)svga->p; + if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) { + et4000w32p_mmu_write((addr & 0xff) + 0x6000, val >> 0, et4000); + et4000w32p_mmu_write((addr & 0xff) + 0x6001, val >> 8, et4000); + et4000w32p_mmu_write((addr & 0xff) + 0x6002, val >> 16, et4000); + et4000w32p_mmu_write((addr & 0xff) + 0x6003, val >> 24, et4000); + return; + } + svga_writel_linear(addr, val, p); +} +static void et4000_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; + if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) { + et4000w32p_mmu_write((addr & 0xff) + 0x6000, val >> 0, et4000); + et4000w32p_mmu_write((addr & 0xff) + 0x6001, val >> 8, et4000); + return; + } + svga_writew_linear(addr, val, p); +} +static void et4000_write_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; + if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) { + et4000w32p_mmu_write((addr & 0xff) + 0x6000, val, et4000); + return; + } + svga_write_linear(addr, val, p); +} + + +static void bt_out(uint16_t addr, uint8_t val, void *priv) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)priv; + uint16_t saddr = 0x3c8 + ((addr >> 2) & 3); + bt482_ramdac_out(saddr, (addr >> 4) & 1, val, et4000->ramdac, &et4000->svga); +} +static uint8_t bt_in(uint16_t addr, void *priv) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)priv; + uint16_t saddr = 0x3c8 + ((addr >> 2) & 3); + uint8_t v = bt482_ramdac_in(saddr, (addr >> 4) & 1, et4000->ramdac, &et4000->svga); + return v; +} + +void * +et4000w32p_init(const device_t *info) +{ + int vram_size; + et4000w32p_t *et4000 = (et4000w32p_t*)malloc(sizeof(et4000w32p_t)); + memset(et4000, 0, sizeof(et4000w32p_t)); + +// et4000->pci = (info->flags & DEVICE_PCI) ? 0x80 : 0x00; +// et4000->vlb = (info->flags & DEVICE_VLB) ? 0x40 : 0x00; + + /*The ET4000/W32i ISA BIOS seems to not support 2MB of VRAM*/ +// if ((info->local == ET4000W32) || ((info->local == ET4000W32I) && !(et4000->vlb))) +// vram_size = 1; +// else + vram_size = device_get_config_int("memory"); + + /*The interleaved VRAM was introduced by the ET4000/W32i*/ + //et4000->interleaved = ((vram_size == 2) && (info->local != ET4000W32)) ? 1 : 0; + +#if 0 + if (info->flags & DEVICE_PCI) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_pci); + else if (info->flags & DEVICE_VLB) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_vlb); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_isa); +#endif + + et4000->type = ET4000W32P_REVC; + et4000->ramdac = bt482_ramdac_init(NULL); + io_sethandlerx(0x000, 0x0020, bt_in, NULL, NULL, bt_out, NULL, NULL, et4000); + + svga_init(&et4000->svga, et4000, vram_size << 20, + et4000w32p_recalctimings, + et4000w32p_in, et4000w32p_out, + et4000w32p_hwcursor_draw, + NULL); + et4000->svga.dac_hwcursor_draw = bt482_hwcursor_draw; + et4000->svga.ramdac = et4000->ramdac; + + et4000->vram_mask = (vram_size << 20) - 1; + et4000->svga.decode_mask = (vram_size << 20) - 1; + + //et4000->type = info->local; + + switch (et4000->type) { + case ET4000W32: + /* ET4000/W32 */ + et4000->rev = 0; +#if 0 + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&tseng_ics5301_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = sdac_getclock; +#endif + break; + + case ET4000W32I: + /* ET4000/W32i rev B */ + et4000->rev = 3; + +#if 0 + if (et4000->vlb) { + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32I_VLB, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + } else { + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32I_ISA, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + } + + et4000->svga.ramdac = device_add(&tseng_ics5301_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = sdac_getclock; +#endif + break; + + case ET4000W32P_VIDEOMAGIC_REVB: + /* ET4000/W32p rev B */ + et4000->rev = 5; + +#if 0 + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&stg_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = stg_getclock; +#endif + break; + + case ET4000W32P_REVC: + /* ET4000/W32p rev C */ + et4000->rev = 7; + +#if 0 + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_REVC, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&tseng_ics5341_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = sdac_getclock; +#endif + break; + + case ET4000W32P: + /* ET4000/W32p rev D */ + et4000->rev = 6; + +#if 0 + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&stg_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = stg_getclock; +#endif + break; + + case ET4000W32P_CARDEX: + /* ET4000/W32p rev D */ + et4000->rev = 6; + +#if 0 + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_CARDEX, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&stg_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = stg_getclock; +#endif + break; + + case ET4000W32P_DIAMOND: + /* ET4000/W32p rev D */ + et4000->rev = 6; + +#if 0 + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_DIAMOND, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&stg_ramdac_device); + et4000->svga.clock_gen = device_add(&icd2061_device); + et4000->svga.getclock = icd2061_getclock; +#endif + break; + + default: + break; + } + +#if 0 + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&et4000->bios_rom.mapping); +#endif + + mem_mapping_addx(&et4000->linear_mapping, 0, 0, et4000_read_linear, et4000_readw_linear, et4000_readl_linear, et4000_write_linear, et4000_writew_linear, et4000_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &et4000->svga); + mem_mapping_addx(&et4000->mmu_mapping, 0, 0, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, et4000); + + et4000w32p_io_set(et4000); + +// if (info->flags & DEVICE_PCI) +// pci_add_card(PCI_ADD_NORMAL, et4000w32p_pci_read, et4000w32p_pci_write, et4000, &et4000->pci_slot); + + /* Hardwired bits: 00000000 1xx0x0xx */ + /* R/W bits: xx xxxx */ + /* PCem bits: 111 */ + et4000->pci_regs[0x04] = 0x83; + + et4000->pci_regs[0x10] = 0x00; + et4000->pci_regs[0x11] = 0x00; + et4000->pci_regs[0x12] = 0xff; + et4000->pci_regs[0x13] = 0xff; + + et4000->pci_regs[0x30] = 0x00; + et4000->pci_regs[0x31] = 0x00; + et4000->pci_regs[0x32] = 0x00; + et4000->pci_regs[0x33] = 0xf0; + + et4000->svga.packed_chain4 = 1; + + svga_set_ramdac_type(&et4000->svga, RAMDAC_8BIT); + + return et4000; +} + +int +et4000w32_available(void) +{ + return rom_present(BIOS_ROM_PATH_W32); +} + +int +et4000w32i_isa_available(void) +{ + return rom_present(BIOS_ROM_PATH_W32I_ISA); +} + +int +et4000w32i_vlb_available(void) +{ + return rom_present(BIOS_ROM_PATH_W32I_VLB); +} + +int +et4000w32p_videomagic_revb_vlb_available(void) +{ + return rom_present(BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB); +} + +int +et4000w32p_revc_available(void) +{ + return rom_present(BIOS_ROM_PATH_W32P_REVC); +} + +int +et4000w32p_noncardex_available(void) +{ + return rom_present(BIOS_ROM_PATH_W32P); +} + +int +et4000w32p_available(void) +{ + return rom_present(BIOS_ROM_PATH_DIAMOND); +} + +int +et4000w32p_cardex_available(void) +{ + return rom_present(BIOS_ROM_PATH_CARDEX); +} + +void +et4000w32p_close(void *priv) +{ + et4000w32p_t *et4000 = (et4000w32p_t *) priv; + + svga_close(&et4000->svga); + + bt482_ramdac_close(et4000->ramdac); + + free(et4000); +} + +void +et4000w32p_speed_changed(void *priv) +{ + et4000w32p_t *et4000 = (et4000w32p_t *) priv; + + svga_recalctimings(&et4000->svga); +} + +void +et4000w32p_force_redraw(void *priv) +{ + et4000w32p_t *et4000 = (et4000w32p_t *) priv; + + et4000->svga.fullchange = changeframecount; +} + +#if 0 +static const device_config_t et4000w32p_config[] = { + // clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 2, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } + // clang-format on +}; + +const device_t et4000w32_device = { + .name = "Tseng Labs ET4000/w32 ISA", + .internal_name = "et4000w32", + .flags = DEVICE_ISA | DEVICE_AT, + .local = ET4000W32, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = NULL +}; + +const device_t et4000w32_onboard_device = { + .name = "Tseng Labs ET4000/w32 (ISA) (On-Board)", + .internal_name = "et4000w32_onboard", + .flags = DEVICE_ISA | DEVICE_AT, + .local = ET4000W32, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = NULL +}; + +const device_t et4000w32i_isa_device = { + .name = "Tseng Labs ET4000/w32i Rev. B ISA", + .internal_name = "et4000w32i", + .flags = DEVICE_ISA | DEVICE_AT, + .local = ET4000W32I, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32i_isa_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = NULL +}; + +const device_t et4000w32i_vlb_device = { + .name = "Tseng Labs ET4000/w32i Rev. B VLB", + .internal_name = "et4000w32i_vlb", + .flags = DEVICE_VLB, + .local = ET4000W32I, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32i_vlb_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_videomagic_revb_vlb_device = { + .name = "Tseng Labs ET4000/w32p Rev. B VLB (VideoMagic)", + .internal_name = "et4000w32p_videomagic_revb_vlb", + .flags = DEVICE_VLB, + .local = ET4000W32P_VIDEOMAGIC_REVB, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_videomagic_revb_vlb_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_videomagic_revb_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. B PCI (VideoMagic)", + .internal_name = "et4000w32p_videomagic_revb_pci", + .flags = DEVICE_PCI, + .local = ET4000W32P_VIDEOMAGIC_REVB, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_videomagic_revb_vlb_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_revc_vlb_device = { + .name = "Tseng Labs ET4000/w32p Rev. C VLB (Cardex)", + .internal_name = "et4000w32p_revc_vlb", + .flags = DEVICE_VLB, + .local = ET4000W32P_REVC, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_revc_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_revc_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. C PCI (Cardex)", + .internal_name = "et4000w32p_revc_pci", + .flags = DEVICE_PCI, + .local = ET4000W32P_REVC, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_revc_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_noncardex_vlb_device = { + .name = "Tseng Labs ET4000/w32p Rev. D VLB", + .internal_name = "et4000w32p_nc_vlb", + .flags = DEVICE_VLB, + .local = ET4000W32P, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_noncardex_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_noncardex_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. D PCI", + .internal_name = "et4000w32p_nc_pci", + .flags = DEVICE_PCI, + .local = ET4000W32P, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_noncardex_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_cardex_vlb_device = { + .name = "Tseng Labs ET4000/w32p Rev. D VLB (Cardex)", + .internal_name = "et4000w32p_vlb", + .flags = DEVICE_VLB, + .local = ET4000W32P_CARDEX, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_cardex_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_cardex_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. D PCI (Cardex)", + .internal_name = "et4000w32p_pci", + .flags = DEVICE_PCI, + .local = ET4000W32P_CARDEX, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_cardex_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_vlb_device = { + .name = "Tseng Labs ET4000/w32p Rev. D VLB (Diamond Stealth32)", + .internal_name = "stealth32_vlb", + .flags = DEVICE_VLB, + .local = ET4000W32P_DIAMOND, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. D PCI (Diamond Stealth32)", + .internal_name = "stealth32_pci", + .flags = DEVICE_PCI, + .local = ET4000W32P_DIAMOND, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + { .available = et4000w32p_available }, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; +#endif + +void *et4000w32_merlin_z3_init() +{ + void *p = et4000w32p_init(NULL); + et4000w32p_t *et4000w32p = (et4000w32p_t *)p; + + return p; +} +void *et4000w32_merlin_z2_init() +{ + void *p = et4000w32p_init(NULL); + et4000w32p_t *et4000w32p = (et4000w32p_t *)p; + + return p; +} + +device_t et4000w32_merlin_z2_device = +{ + "Merlin Z2", + 0, + et4000w32_merlin_z2_init, + et4000w32p_close, + NULL, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + NULL, + NULL +}; + + +device_t et4000w32_merlin_z3_device = +{ + "Merlin Z3", + 0, + et4000w32_merlin_z3_init, + et4000w32p_close, + NULL, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + NULL, + NULL +}; + diff --git a/pcem/vid_inmos.cpp b/pcem/vid_inmos.cpp index beb16865..6ece0147 100644 --- a/pcem/vid_inmos.cpp +++ b/pcem/vid_inmos.cpp @@ -127,10 +127,12 @@ void inmos_recalctimings(svga_t *svga) svga->bpp = 1 << ((control >> 17) & 3); int bs = 0; + inmos->syncdelay = 0; if ((control >> 8) & 1) { svga->bpp = 32; bs = 2; svga->rowoffset <<= 2; + inmos->syncdelay = 6; } int meminit = inmos->regs[0x12b]; @@ -215,14 +217,13 @@ void inmos_recalctimings(svga_t *svga) svga->rowoffset = 2048 + (svga->htotal << bs) - (len << bs); uint32_t start = inmos->regs[0x080]; - pclog("%08x\n", control); int row = start / 0x2000; int col = start % 0x2000; int width = svga->rowoffset / (4 * 4); svga->ma_latch = start * 2; svga->rowoffset >>= 3; - inmos->syncdelay = (control >> 15) & 7; + inmos->syncdelay = ((control >> 15) & 7) * ((bpp + 7) >> 3); svga->vtotal = (inmos->regs[0x02a] + inmos->regs[0x029] * 3 + inmos->regs[0x26]) / 2; svga->dispend = inmos->regs[0x02a] / 2; svga->split = 99999; @@ -467,7 +468,7 @@ static void inmos_adjust_panning(svga_t *svga) dst += 24; svga->scrollcache_dst = dst; - svga->scrollcache_src = src + inmos->syncdelay * ((svga->bpp + 7) >> 3) * 4; + svga->scrollcache_src = src + inmos->syncdelay * 4; } static inline uint32_t dword_remap(uint32_t in_addr) diff --git a/pcem/vid_permedia2.cpp b/pcem/vid_permedia2.cpp index 7b8b2db1..0c53d62d 100644 --- a/pcem/vid_permedia2.cpp +++ b/pcem/vid_permedia2.cpp @@ -1930,8 +1930,8 @@ void *permedia2_init() permedia2->svga.fb_only = -1; - permedia2->getclock = sdac_getclock; - permedia2->getclock_p = &permedia2->ramdac; + //permedia2->getclock = sdac_getclock; + //permedia2->getclock_p = &permedia2->ramdac; permedia2->id_ext_pci = 0x07; sdac_init(&permedia2->ramdac); svga_set_ramdac_type(&permedia2->svga, RAMDAC_8BIT); diff --git a/pcem/vid_sdac_ramdac.h b/pcem/vid_sdac_ramdac.h index 48126f7b..ec3f86fb 100644 --- a/pcem/vid_sdac_ramdac.h +++ b/pcem/vid_sdac_ramdac.h @@ -14,3 +14,24 @@ void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t * uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga); float sdac_getclock(int clock, void *p); + + +typedef struct bt482_ramdac_t { + uint32_t extpallook[4]; + uint8_t rgb[3]; + uint8_t cursor32_data[256]; + int hwc_y; + int hwc_x; + uint8_t cmd_r0; + uint8_t cmd_r1; + uint8_t cursor_r; + uint8_t status; + uint8_t type; +} bt482_ramdac_t; + +void *bt482_ramdac_init(const device_t *info); +void bt482_ramdac_close(void *priv); +void bt482_hwcursor_draw(svga_t *svga, int displine); +void bt482_recalctimings(void *priv, svga_t *svga); +uint8_t bt482_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga); +void bt482_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga); diff --git a/pcem/vid_svga.cpp b/pcem/vid_svga.cpp index a08eff71..f28b8e1e 100644 --- a/pcem/vid_svga.cpp +++ b/pcem/vid_svga.cpp @@ -563,6 +563,16 @@ int svga_poll(void *p) svga->hwcursor_oddeven = 1; } + if (svga->displine == ((svga->dac_hwcursor_latch.y < 0) ? 0 : svga->dac_hwcursor_latch.y) && svga->dac_hwcursor_latch.ena) { + svga->dac_hwcursor_on = svga->dac_hwcursor_latch.ysize - svga->dac_hwcursor_latch.yoff; + svga->dac_hwcursor_oddeven = 0; + } + + if (svga->displine == (((svga->dac_hwcursor_latch.y < 0) ? 0 : svga->dac_hwcursor_latch.y) + 1) && svga->dac_hwcursor_latch.ena && svga->interlace) { + svga->dac_hwcursor_on = svga->dac_hwcursor_latch.ysize - (svga->dac_hwcursor_latch.yoff + 1); + svga->dac_hwcursor_oddeven = 1; + } + if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; @@ -591,7 +601,7 @@ int svga_poll(void *p) video_wait_for_buffer(); } - if (svga->hwcursor_on || svga->overlay_on) + if (svga->hwcursor_on || svga->dac_hwcursor_on || svga->overlay_on) svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = svga->interlace ? 3 : 2; if (!svga->override) @@ -606,7 +616,7 @@ int svga_poll(void *p) svga->overlay_on--; } - if (svga->hwcursor_on) + if (svga->hwcursor_on && svga->hwcursor_draw) { if (!svga->override) svga->hwcursor_draw(svga, svga->displine); @@ -614,6 +624,14 @@ int svga_poll(void *p) if (svga->hwcursor_on && svga->interlace) svga->hwcursor_on--; } + if (svga->dac_hwcursor_on && svga->dac_hwcursor_draw) + { + if (!svga->override) + svga->dac_hwcursor_draw(svga, svga->displine); + svga->dac_hwcursor_on--; + if (svga->dac_hwcursor_on && svga->interlace) + svga->dac_hwcursor_on--; + } if (svga->lastline < svga->displine) svga->lastline = svga->displine; @@ -818,6 +836,9 @@ int svga_poll(void *p) svga->hwcursor_on = 0; svga->hwcursor_latch = svga->hwcursor; + svga->dac_hwcursor_on = 0; + svga->dac_hwcursor_latch = svga->dac_hwcursor; + svga->overlay_on = 0; svga->overlay_latch = svga->overlay; diff --git a/pcem/vid_svga.h b/pcem/vid_svga.h index 010131d6..a444a828 100644 --- a/pcem/vid_svga.h +++ b/pcem/vid_svga.h @@ -44,8 +44,9 @@ typedef struct svga_t uint8_t dac_mask, dac_status; int dac_read, dac_write, dac_pos; - int dac_r, dac_g; - + int dac_r, dac_g, dac_b; + int dac_addr; + uint8_t cgastat; uint8_t plane_mask; @@ -118,14 +119,16 @@ typedef struct svga_t uint32_t addr; uint32_t pitch; int v_acc, h_acc; - } hwcursor, hwcursor_latch, overlay, overlay_latch; - + } hwcursor, hwcursor_latch, overlay, overlay_latch, dac_hwcursor, dac_hwcursor_latch; + int hwcursor_on; int overlay_on; + int dac_hwcursor_on; int hwcursor_oddeven; int overlay_oddeven; - + uint8_t dac_hwcursor_oddeven; + void (*render)(struct svga_t *svga); void (*recalctimings_ex)(struct svga_t *svga); @@ -133,6 +136,7 @@ typedef struct svga_t uint8_t (*video_in) (uint16_t addr, void *p); void (*hwcursor_draw)(struct svga_t *svga, int displine); + void (*dac_hwcursor_draw)(struct svga_t *svga, int displine); void (*overlay_draw)(struct svga_t *svga, int displine); @@ -186,6 +190,9 @@ typedef struct svga_t uint8_t fcr; uint32_t *map8; uint32_t(*translate_address)(uint32_t addr, void *priv); + int x_add; + int y_add; + uint8_t ext_overscan; bool swaprb; } svga_t;