From 55610fc2f386c9730c53e0873df2120f00fa77ce Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 23 Mar 2024 14:05:21 +0200 Subject: [PATCH] Domino RTG board (ET4000 from x86box) --- gfxboard.cpp | 51 + include/gfxboard.h | 3 +- od-win32/winuae_msvc15/winuae_msvc.vcxproj | 2 + .../winuae_msvc15/winuae_msvc.vcxproj.filters | 6 + pcem/pcemglue.cpp | 2 +- pcem/rom.h | 4 +- pcem/vid_et4000.cpp | 1203 +++++++++++++++++ pcem/vid_et4000.h | 1 + pcem/vid_sc1502x_ramdac.cpp | 253 ++++ pcem/vid_svga.h | 30 + 10 files changed, 1551 insertions(+), 4 deletions(-) create mode 100644 pcem/vid_et4000.cpp create mode 100644 pcem/vid_et4000.h create mode 100644 pcem/vid_sc1502x_ramdac.cpp diff --git a/gfxboard.cpp b/gfxboard.cpp index 1fc6aa8a..b3b37fa2 100644 --- a/gfxboard.cpp +++ b/gfxboard.cpp @@ -54,6 +54,7 @@ static bool memlogw = true; #include "pcem/vid_ncr.h" #include "pcem/vid_permedia2.h" #include "pcem/vid_inmos.h" +#include "pcem/vid_et4000.h" #include "pci.h" #include "pci_hw.h" #include "pcem/pcemglue.h" @@ -287,6 +288,13 @@ static const struct gfxboard boards[] = 0x00000000, 0x00400000, 0x00400000, 0x02000000, 0, 3, 6, false, false, 0, 0, NULL, &inmos_rainbow3_z3_device }, + { + GFXBOARD_ID_DOMINO, + _T("Domino [Zorro II]"), _T("X-Pert Computer Services"), _T("Domino"), + 2167, 1, 2, 0, + 0x00000000, 0x00100000, 0x00100000, 0x00100000, 0, 2, 0, false, false, + 0, 0, NULL, &et4000_domino_device + }, { GFXBOARD_ID_HARLEQUIN, _T("Harlequin [Zorro II]"), _T("ACS"), _T("Harlequin_PAL"), @@ -3012,6 +3020,21 @@ static void REGPARAM2 gfxboard_bput_mem_autoconfig (uaecptr addr, uae_u32 b) gb->pcem_mmio_offset = 0x800000; gb->gfxboard_external_interrupt = true; + } else if (boardnum == GFXBOARD_ID_DOMINO) { + + + ab = &gb->gfxboard_bank_vram_pcem; + gb->gfxboardmem_start = b << 16; + map_banks_z2(ab, b, gb->board->banksize >> 16); + + init_board(gb); + + gb->configured_mem = b; + gb->mem_start[0] = b << 16; + gb->mem_end[0] = gb->mem_start[0] + gb->board->banksize; + gb->pcem_vram_offset = 0x800000; + gb->pcem_vram_mask = 0x3fffff; + } else { // Picasso II, Picasso II+ @@ -6040,6 +6063,20 @@ static void special_pcem_put(uaecptr addr, uae_u32 v, int size) gb->gfxboard_intreq_marked = false; } + } else if (boardnum == GFXBOARD_ID_DOMINO) { + + addr &= 0xffff; + if (addr & 0x1000) { + addr++; + } + addr &= 0xfff; + 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; @@ -6355,6 +6392,20 @@ static uae_u32 special_pcem_get(uaecptr addr, int size) v = gb->gfxboard_intreq_marked ? 4 : 0; } + } else if (boardnum == GFXBOARD_ID_DOMINO) { + + addr &= 0xffff; + if (addr & 0x1000) { + addr++; + } + addr &= 0xfff; + 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 996321f5..749ebaea 100644 --- a/include/gfxboard.h +++ b/include/gfxboard.h @@ -89,7 +89,8 @@ int pcem_getvramsize(void); #define GFXBOARD_ID_RAINBOWIII 26 #define GFXBOARD_ID_VISIONA 27 #define GFXBOARD_ID_EGS_110_24 28 -#define GFXBOARD_ID_VOODOO5_PCI 29 +#define GFXBOARD_ID_DOMINO 29 +#define GFXBOARD_ID_VOODOO5_PCI 30 #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 ab467929..1085d6bb 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj @@ -1378,11 +1378,13 @@ + + diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters index 01a36910..517f8322 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters @@ -1012,6 +1012,12 @@ pcem + + pcem + + + pcem + diff --git a/pcem/pcemglue.cpp b/pcem/pcemglue.cpp index bbfd7829..e9829cc6 100644 --- a/pcem/pcemglue.cpp +++ b/pcem/pcemglue.cpp @@ -711,7 +711,7 @@ void pci_clear_irq(int card, int pci_int) //write_log(_T("pci_clear_irq %d %d\n"), card, pci_int); gfxboard_intreq(gfxboard_priv, 0, true); } -int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags) +int rom_init(rom_t *rom, const char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags) { return 0; } diff --git a/pcem/rom.h b/pcem/rom.h index e7f746fa..aa662094 100644 --- a/pcem/rom.h +++ b/pcem/rom.h @@ -11,8 +11,8 @@ typedef struct rom_t mem_mapping_t mapping; } rom_t; -int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); -int rom_init_interleaved(rom_t *rom, char *fn_low, char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags); +int rom_init(rom_t *rom, const char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); +int rom_init_interleaved(rom_t *rom, const char *fn_low, const char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags); uint8_t rom_read(uint32_t addr, void *p); uint16_t rom_readw(uint32_t addr, void *p); diff --git a/pcem/vid_et4000.cpp b/pcem/vid_et4000.cpp new file mode 100644 index 00000000..68e76338 --- /dev/null +++ b/pcem/vid_et4000.cpp @@ -0,0 +1,1203 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the Tseng Labs ET4000. + * + * + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * GreatPsycho, + * Sarah Walker, + * + * Copyright 2017-2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#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" + +void *sc1502x_ramdac_init(const device_t *info); +void sc1502x_ramdac_close(void *priv); + +#define ET4000_TYPE_TC6058AF 0 /* ISA ET4000AX (TC6058AF) */ +#define ET4000_TYPE_ISA 1 /* ISA ET4000AX */ +#define ET4000_TYPE_MCA 2 /* MCA ET4000AX */ +#define ET4000_TYPE_KOREAN 3 /* Korean ET4000 */ +#define ET4000_TYPE_TRIGEM 4 /* Trigem 286M ET4000 */ +#define ET4000_TYPE_KASAN 5 /* Kasan ET4000 */ + +#define BIOS_ROM_PATH "roms/video/et4000/ET4000.BIN" +#define V8_06_BIOS_ROM_PATH "roms/video/et4000/ET4000_V8_06.BIN" +#define TC6058AF_BIOS_ROM_PATH "roms/video/et4000/Tseng_Labs_VGA-4000_BIOS_V1.1.bin" +#define V1_21_BIOS_ROM_PATH "roms/video/et4000/Tseng_Labs_VGA-4000_BIOS_V1.21.bin" +#define KOREAN_BIOS_ROM_PATH "roms/video/et4000/tgkorvga.bin" +#define KOREAN_FONT_ROM_PATH "roms/video/et4000/tg_ksc5601.rom" +#define KASAN_BIOS_ROM_PATH "roms/video/et4000/et4000_kasan16.bin" +#define KASAN_FONT_ROM_PATH "roms/video/et4000/kasan_ksc5601.rom" + +typedef struct { + const char *name; + int type; + + svga_t svga; + + uint8_t pos_regs[8]; + + rom_t bios_rom; + + uint8_t banking; + uint32_t vram_size, + vram_mask; + + uint8_t port_22cb_val; + uint8_t port_32cb_val; + int get_korean_font_enabled; + int get_korean_font_index; + uint16_t get_korean_font_base; + + uint8_t kasan_cfg_index; + uint8_t kasan_cfg_regs[16]; + uint16_t kasan_access_addr; + uint8_t kasan_font_data[4]; + + mem_mapping_t linear_mapping; +} et4000_t; + +static const uint8_t crtc_mask[0x40] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +//static video_timings_t timing_et4000_isa = { .type = VIDEO_ISA, .write_b = 3, .write_w = 3, .write_l = 6, .read_b = 5, .read_w = 5, .read_l = 10 }; +//static video_timings_t timing_et4000_mca = { .type = VIDEO_MCA, .write_b = 4, .write_w = 5, .write_l = 10, .read_b = 5, .read_w = 5, .read_l = 10 }; + +//static void et4000_kasan_out(uint16_t addr, uint8_t val, void *priv); +//static uint8_t et4000_kasan_in(uint16_t addr, void *priv); + +static uint8_t +et4000_in(uint16_t addr, void *priv) +{ + et4000_t *dev = (et4000_t *) priv; + svga_t *svga = &dev->svga; + uint8_t ret; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c2: + if (dev->type == ET4000_TYPE_MCA) { + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + return 0; + else + return 0x10; + } + break; + + case 0x3c5: + if ((svga->seqaddr & 0xf) == 7) + return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; + + case 0x3c6: + case 0x3c7: + case 0x3c8: + case 0x3c9: + if (dev->type >= ET4000_TYPE_ISA) + return sc1502x_ramdac_in(addr, svga->ramdac, svga); + break; + + case 0x3cd: /*Banking*/ + return dev->banking; + + case 0x3d4: + return svga->crtcreg; + + case 0x3d5: + return svga->crtc[svga->crtcreg]; + + case 0x3da: + svga->attrff = 0; + + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x30; + else + svga->cgastat ^= 0x30; + + ret = svga->cgastat; + + if ((svga->fcr & 0x08) && svga->dispon) + ret |= 0x08; + + if (ret & 0x08) + ret &= 0x7f; + else + ret |= 0x80; + + return ret; + + default: + break; + } + + return svga_in(addr, svga); +} + +#if 0 +static uint8_t +et4000k_in(uint16_t addr, void *priv) +{ + et4000_t *dev = (et4000_t *) priv; + uint8_t val = 0xff; + + switch (addr) { + case 0x22cb: + return dev->port_22cb_val; + + case 0x22cf: + val = 0; + switch (dev->get_korean_font_enabled) { + case 3: + if ((dev->port_32cb_val & 0x30) == 0x30) { + val = fontdatksc5601[dev->get_korean_font_base].chr[dev->get_korean_font_index++]; + dev->get_korean_font_index &= 0x1f; + } else if ((dev->port_32cb_val & 0x30) == 0x20 && (dev->get_korean_font_base & 0x7f) > 0x20 && (dev->get_korean_font_base & 0x7f) < 0x7f) { + switch (dev->get_korean_font_base & 0x3f80) { + case 0x2480: + if (dev->get_korean_font_index < 16) + val = fontdatksc5601_user[(dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index]; + else if (dev->get_korean_font_index >= 24 && dev->get_korean_font_index < 40) + val = fontdatksc5601_user[(dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index - 8]; + break; + + case 0x3f00: + if (dev->get_korean_font_index < 16) + val = fontdatksc5601_user[96 + (dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index]; + else if (dev->get_korean_font_index >= 24 && dev->get_korean_font_index < 40) + val = fontdatksc5601_user[96 + (dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index - 8]; + break; + + default: + break; + } + dev->get_korean_font_index++; + dev->get_korean_font_index %= 72; + } + break; + + case 4: + val = 0x0f; + break; + + default: + break; + } + return val; + + case 0x32cb: + return dev->port_32cb_val; + + default: + return et4000_in(addr, priv); + } +} +#endif + +static void +et4000_out(uint16_t addr, uint8_t val, void *priv) +{ + et4000_t *dev = (et4000_t *) priv; + svga_t *svga = &dev->svga; + uint8_t old; + uint8_t pal4to16[16] = { 0, 7, 0x38, 0x3f, 0, 3, 4, 0x3f, 0, 2, 4, 0x3e, 0, 3, 5, 0x3f }; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 0x1f; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + if ((svga->attraddr == 0x13) && (svga->attrregs[0x13] != val)) + svga->fullchange = changeframecount; + old = svga->attrregs[svga->attraddr & 0x1f]; + svga->attrregs[svga->attraddr & 0x1f] = val; + if (svga->attraddr < 0x10) + svga->fullchange = changeframecount; + + if ((svga->attraddr == 0x10) || (svga->attraddr == 0x14) || (svga->attraddr < 0x10)) { + for (int c = 0; c < 0x10; c++) { + if (svga->attrregs[0x10] & 0x80) + svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); + else if (svga->ati_4color) + svga->egapal[c] = pal4to16[(c & 0x03) | ((val >> 2) & 0xc)]; + else + svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); + } + svga->fullchange = changeframecount; + } + /* Recalculate timings on change of attribute register 0x11 + (overscan border color) too. */ + if (svga->attraddr == 0x10) { + svga->chain4 &= ~0x02; + if ((val & 0x40) && (svga->attrregs[0x10] & 0x40)) + svga->chain4 |= (svga->seqregs[0x0e] & 0x02); + if (old != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (old != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + return; + + case 0x3c5: + if (svga->seqaddr == 4) { + svga->seqregs[4] = val; + + svga->chain2_write = !(val & 4); + svga->chain4 = (svga->chain4 & ~8) | (val & 8); + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4 && !(svga->adv_flags & FLAG_ADDR_BY8); + return; + } else if (svga->seqaddr == 0x0e) { + svga->seqregs[0x0e] = val; + svga->chain4 &= ~0x02; + if ((svga->gdcreg[5] & 0x40) && svga->lowres) + svga->chain4 |= (svga->seqregs[0x0e] & 0x02); + svga_recalctimings(svga); + return; + } + break; + + case 0x3c6: + case 0x3c7: + case 0x3c8: + case 0x3c9: + if (dev->type >= ET4000_TYPE_ISA) { + sc1502x_ramdac_out(addr, val, svga->ramdac, svga); + return; + } + break; + + case 0x3cd: /*Banking*/ + if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (val & 0xf) * 0x10000; + svga->read_bank = ((val >> 4) & 0xf) * 0x10000; + } + dev->banking = val; + return; + + case 0x3cf: + if ((svga->gdcaddr & 15) == 5) { + svga->chain4 &= ~0x02; + if ((val & 0x40) && svga->lowres) + svga->chain4 |= (svga->seqregs[0x0e] & 0x02); + } else if ((svga->gdcaddr & 15) == 6) { + if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) { + svga->write_bank = (dev->banking & 0x0f) * 0x10000; + svga->read_bank = ((dev->banking >> 4) & 0x0f) * 0x10000; + } else + svga->write_bank = svga->read_bank = 0; + + old = svga->gdcreg[6]; + svga_out(addr, val, svga); + if ((old & 0xc) != 0 && (val & 0xc) == 0) { + /*override mask - ET4000 supports linear 128k at A0000*/ + svga->banked_mask = 0x1ffff; + } + return; + } + 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]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (svga->crtcreg == 0x36) { + if (!(val & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (dev->banking & 0x0f) * 0x10000; + svga->read_bank = ((dev->banking >> 4) & 0x0f) * 0x10000; + } 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); + } + } + } + break; + + default: + break; + } + + svga_out(addr, val, svga); +} + +#if 0 +static void +et4000k_out(uint16_t addr, uint8_t val, void *priv) +{ + et4000_t *dev = (et4000_t *) priv; + + switch (addr) { + case 0x22cb: + dev->port_22cb_val = (dev->port_22cb_val & 0xf0) | (val & 0x0f); + dev->get_korean_font_enabled = val & 7; + if (dev->get_korean_font_enabled == 3) + dev->get_korean_font_index = 0; + break; + + case 0x22cf: + switch (dev->get_korean_font_enabled) { + case 1: + dev->get_korean_font_base = ((val & 0x7f) << 7) | (dev->get_korean_font_base & 0x7f); + break; + + case 2: + dev->get_korean_font_base = (dev->get_korean_font_base & 0x3f80) | (val & 0x7f) | (((val ^ 0x80) & 0x80) << 8); + break; + + case 3: + if ((dev->port_32cb_val & 0x30) == 0x20 && (dev->get_korean_font_base & 0x7f) > 0x20 && (dev->get_korean_font_base & 0x7f) < 0x7f) { + switch (dev->get_korean_font_base & 0x3f80) { + case 0x2480: + if (dev->get_korean_font_index < 16) + fontdatksc5601_user[(dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index] = val; + else if (dev->get_korean_font_index >= 24 && dev->get_korean_font_index < 40) + fontdatksc5601_user[(dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index - 8] = val; + break; + + case 0x3f00: + if (dev->get_korean_font_index < 16) + fontdatksc5601_user[96 + (dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index] = val; + else if (dev->get_korean_font_index >= 24 && dev->get_korean_font_index < 40) + fontdatksc5601_user[96 + (dev->get_korean_font_base & 0x7f) - 0x20].chr[dev->get_korean_font_index - 8] = val; + break; + + default: + break; + } + dev->get_korean_font_index++; + } + break; + + default: + break; + } + break; + case 0x32cb: + dev->port_32cb_val = val; + svga_recalctimings(&dev->svga); + break; + + default: + et4000_out(addr, val, priv); + break; + } +} +#endif + +#if 0 +static uint8_t +et4000_kasan_in(uint16_t addr, void *priv) +{ + const et4000_t *et4000 = (et4000_t *) priv; + uint8_t val = 0xFF; + + if (addr == 0x258) { + val = et4000->kasan_cfg_index; + } else if (addr == 0x259) { + if (et4000->kasan_cfg_index >= 0xF0) { + val = et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0]; + if (et4000->kasan_cfg_index == 0xF4 && et4000->kasan_cfg_regs[0] & 0x20) + val |= 0x80; + } + } else if (addr >= et4000->kasan_access_addr && addr < et4000->kasan_access_addr + 8) { + switch (addr - ((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1]))) { + case 2: + val = 0; + break; + case 5: + if (((et4000->get_korean_font_base >> 7) & 0x7F) == (et4000->svga.ksc5601_udc_area_msb[0] & 0x7F) && (et4000->svga.ksc5601_udc_area_msb[0] & 0x80)) + val = fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index]; + else if (((et4000->get_korean_font_base >> 7) & 0x7F) == (et4000->svga.ksc5601_udc_area_msb[1] & 0x7F) && (et4000->svga.ksc5601_udc_area_msb[1] & 0x80)) + val = fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index]; + else + val = fontdatksc5601[et4000->get_korean_font_base].chr[et4000->get_korean_font_index]; + break; + default: + break; + } + } else + val = et4000_in(addr, priv); + + return val; +} + +static void +et4000_kasan_out(uint16_t addr, uint8_t val, void *priv) +{ + et4000_t *et4000 = (et4000_t *) priv; + + if (addr == 0x258) { + et4000->kasan_cfg_index = val; + } else if (addr == 0x259) { + if (et4000->kasan_cfg_index >= 0xF0) { + switch (et4000->kasan_cfg_index - 0xF0) { + case 0: + if (et4000->kasan_cfg_regs[4] & 8) + val = (val & 0xFC) | (et4000->kasan_cfg_regs[0] & 3); + et4000->kasan_cfg_regs[0] = val; + svga_recalctimings(&et4000->svga); + break; + case 1: + case 2: + if ((et4000->kasan_cfg_index - 0xF0) <= 16) + et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0] = val; + io_removehandler(et4000->kasan_access_addr, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); + et4000->kasan_access_addr = (et4000->kasan_cfg_regs[2] << 8) | et4000->kasan_cfg_regs[1]; + io_sethandler(et4000->kasan_access_addr, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); + break; + case 4: + if (et4000->kasan_cfg_regs[0] & 0x20) + val |= 0x80; + et4000->svga.ksc5601_swap_mode = (val & 4) >> 2; + et4000->kasan_cfg_regs[4] = val; + svga_recalctimings(&et4000->svga); + break; + case 5: + et4000->kasan_cfg_regs[5] = val; + et4000->svga.ksc5601_english_font_type = 0x100 | val; + fallthrough; + case 6: + case 7: + et4000->svga.ksc5601_udc_area_msb[et4000->kasan_cfg_index - 0xF6] = val; + default: + et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0] = val; + svga_recalctimings(&et4000->svga); + break; + } + } + } else if (addr >= et4000->kasan_access_addr && addr < et4000->kasan_access_addr + 8) { + switch (addr - ((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1]))) { + case 0: + if (et4000->kasan_cfg_regs[0] & 2) { + et4000->get_korean_font_index = ((val & 1) << 4) | ((val & 0x1E) >> 1); + et4000->get_korean_font_base = (et4000->get_korean_font_base & ~7) | (val >> 5); + } + break; + case 1: + if (et4000->kasan_cfg_regs[0] & 2) + et4000->get_korean_font_base = (et4000->get_korean_font_base & ~0x7F8) | (val << 3); + break; + case 2: + if (et4000->kasan_cfg_regs[0] & 2) + et4000->get_korean_font_base = (et4000->get_korean_font_base & ~0x7F800) | ((val & 7) << 11); + break; + case 3: + case 4: + case 5: + if (et4000->kasan_cfg_regs[0] & 1) { + if ((addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)) <= 4) + et4000->kasan_font_data[addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)] = val; + } + break; + case 6: + if ((et4000->kasan_cfg_regs[0] & 1) && (et4000->kasan_font_data[3] & !(val & 0x80)) && (et4000->get_korean_font_base & 0x7F) >= 0x20 && (et4000->get_korean_font_base & 0x7F) < 0x7F) { + if (((et4000->get_korean_font_base >> 7) & 0x7F) == (et4000->svga.ksc5601_udc_area_msb[0] & 0x7F) && (et4000->svga.ksc5601_udc_area_msb[0] & 0x80)) + fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index] = et4000->kasan_font_data[2]; + else if (((et4000->get_korean_font_base >> 7) & 0x7F) == (et4000->svga.ksc5601_udc_area_msb[1] & 0x7F) && (et4000->svga.ksc5601_udc_area_msb[1] & 0x80)) + fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index] = et4000->kasan_font_data[2]; + } + et4000->kasan_font_data[3] = val; + break; + default: + break; + } + } else + et4000_out(addr, val, priv); +} +#endif + +uint32_t +get_et4000_addr(uint32_t addr, void *priv) +{ + const svga_t *svga = (svga_t *) priv; + uint32_t nbank; + + switch (svga->crtc[0x37] & 0x0B) { + case 0x00: + case 0x01: + nbank = 0; + addr &= 0xFFFF; + break; + case 0x02: + nbank = (addr & 1) << 1; + addr = (addr >> 1) & 0xFFFF; + break; + case 0x03: + nbank = addr & 3; + addr = (addr >> 2) & 0xFFFF; + break; + case 0x08: + case 0x09: + nbank = 0; + addr &= 0x3FFFF; + break; + case 0x0A: + nbank = (addr & 1) << 1; + addr = (addr >> 1) & 0x3FFFF; + break; + case 0x0B: + nbank = addr & 3; + addr = (addr >> 2) & 0x3FFFF; + break; + default: + nbank = 0; + break; + } + + if (svga->vram_max >= 1024 * 1024) { + addr = (addr << 2) | (nbank & 3); + if ((svga->crtc[0x37] & 3) == 2) + addr >>= 1; + else if ((svga->crtc[0x37] & 3) < 2) + addr >>= 2; + } else if (svga->vram_max >= 512 * 1024) { + addr = (addr << 1) | ((nbank & 2) >> 1) | ((nbank & 1) << 19); + if ((svga->crtc[0x37] & 3) < 2) + addr >>= 1; + } else if (svga->vram_max >= 256 * 1024) + addr = addr | (nbank << 18); + else if (svga->vram_max > 128 * 1024) { + addr = (addr << 1) | ((nbank & 2) >> 1) | ((nbank & 1) << 17); + if ((svga->crtc[0x37] & 3) < 2) + addr >>= 1; + } else + addr = addr | (nbank << 16); + + return addr; +} + +static void +et4000_recalctimings(svga_t *svga) +{ + const et4000_t *dev = (et4000_t *) svga->p; + + svga->ma_latch |= (svga->crtc[0x33] & 3) << 16; + + svga->hblankstart = (((svga->crtc[0x3f] & 0x4) >> 2) << 8) + svga->crtc[2]; + + if (svga->crtc[0x35] & 1) + svga->vblankstart |= 0x400; + if (svga->crtc[0x35] & 2) + svga->vtotal |= 0x400; + if (svga->crtc[0x35] & 4) + svga->dispend |= 0x400; + if (svga->crtc[0x35] & 8) + svga->vsyncstart |= 0x400; + if (svga->crtc[0x35] & 0x10) + svga->split |= 0x400; + if (!svga->rowoffset) + svga->rowoffset = 0x100; + if (svga->crtc[0x3f] & 1) + svga->htotal |= 0x100; + if (svga->attrregs[0x16] & 0x20) { + svga->hdisp <<= 1; + svga->dots_per_clock <<= 1; + } + + switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) { + case 0: + case 1: + break; + case 3: + svga->clock = (cpuclock * (double) (1ULL << 32)) / 40000000.0; + break; + case 5: + svga->clock = (cpuclock * (double) (1ULL << 32)) / 65000000.0; + break; + default: + svga->clock = (cpuclock * (double) (1ULL << 32)) / 36000000.0; + break; + } + + switch (svga->bpp) { + case 15: + case 16: + svga->hdisp /= 2; + svga->dots_per_clock /= 2; + break; + + case 24: + svga->hdisp /= 3; + svga->dots_per_clock /= 3; + break; + + default: + break; + } + +#if 0 + if (dev->type == ET4000_TYPE_KOREAN || dev->type == ET4000_TYPE_TRIGEM || dev->type == ET4000_TYPE_KASAN) { + if ((svga->render == svga_render_text_80) && ((svga->crtc[0x37] & 0x0A) == 0x0A)) { + if (dev->port_32cb_val & 0x80) { + svga->ma_latch -= 2; + svga->ca_adj = -2; + } + if ((dev->port_32cb_val & 0xB4) == ((svga->crtc[0x37] & 3) == 2 ? 0xB4 : 0xB0)) { + svga->render = svga_render_text_80_ksc5601; + } + } + } +#endif + + if ((svga->bpp == 8) && ((svga->gdcreg[5] & 0x60) >= 0x40)) { + svga->map8 = svga->pallook; + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + } + + if ((svga->seqregs[0x0e] & 0x02) && ((svga->gdcreg[5] & 0x60) >= 0x40) && svga->lowres) { + svga->ma_latch <<= 1; + svga->rowoffset <<= 1; + svga->render = svga_render_8bpp_highres; + } + +#if 0 + if (dev->type == ET4000_TYPE_TC6058AF) { + if (svga->render == svga_render_8bpp_lowres) + svga->render = svga_render_8bpp_tseng_lowres; + else if (svga->render == svga_render_8bpp_highres) + svga->render = svga_render_8bpp_tseng_highres; + } +#endif +} + +#if 0 +static void +et4000_kasan_recalctimings(svga_t *svga) +{ + const et4000_t *et4000 = (et4000_t *) svga->p; + + et4000_recalctimings(svga); + + if (svga->render == svga_render_text_80 && (et4000->kasan_cfg_regs[0] & 8)) { + svga->hdisp += svga->dots_per_clock; + svga->ma_latch -= 4; + svga->ca_adj = (et4000->kasan_cfg_regs[0] >> 6) - 3; + svga->ksc5601_sbyte_mask = (et4000->kasan_cfg_regs[0] & 4) << 5; + if ((et4000->kasan_cfg_regs[0] & 0x23) == 0x20 && (et4000->kasan_cfg_regs[4] & 0x80) && ((svga->crtc[0x37] & 0x0B) == 0x0A)) + svga->render = svga_render_text_80_ksc5601; + } +} +#endif + +#if 0 +static uint8_t +et4000_mca_read(int port, void *priv) +{ + const et4000_t *et4000 = (et4000_t *) priv; + + return (et4000->pos_regs[port & 7]); +} + +static void +et4000_mca_write(int port, uint8_t val, void *priv) +{ + et4000_t *et4000 = (et4000_t *) priv; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) + return; + + /* Save the MCA register value. */ + et4000->pos_regs[port & 7] = val; +} + +static uint8_t +et4000_mca_feedb(UNUSED(void *priv)) +{ + return 1; +} +#endif + +static void * +et4000_init(const device_t *info) +{ + const char *bios_ver = NULL; + const char *fn; + et4000_t *dev; + int i; + + dev = (et4000_t *) malloc(sizeof(et4000_t)); + memset(dev, 0x00, sizeof(et4000_t)); + //dev->name = info->name; + dev->type = 1; + fn = BIOS_ROM_PATH; + + switch (dev->type) { + case ET4000_TYPE_TC6058AF: /* ISA ET4000AX (TC6058AF) */ + case ET4000_TYPE_ISA: /* ISA ET4000AX */ + dev->vram_size = device_get_config_int("memory") << 20; + //video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_isa); + svga_init(&dev->svga, dev, dev->vram_size, + et4000_recalctimings, et4000_in, et4000_out, + NULL, NULL); + io_sethandlerx(0x03c0, 32, + et4000_in, NULL, NULL, et4000_out, NULL, NULL, dev); + //bios_ver = (char *) device_get_config_bios("bios_ver"); + //fn = (char *) device_get_bios_file(info, bios_ver, 0); + + mem_mapping_addx(&dev->linear_mapping, 0, dev->vram_size, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &dev->svga); + mem_mapping_enablex(&dev->linear_mapping); + break; + +#if 0 + case ET4000_TYPE_MCA: /* MCA ET4000AX */ + dev->vram_size = 1024 << 10; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_mca); + svga_init(info, &dev->svga, dev, dev->vram_size, + et4000_recalctimings, et4000_in, et4000_out, + NULL, NULL); + io_sethandler(0x03c0, 32, + et4000_in, NULL, NULL, et4000_out, NULL, NULL, dev); + dev->pos_regs[0] = 0xf2; /* ET4000 MCA board ID */ + dev->pos_regs[1] = 0x80; + mca_add(et4000_mca_read, et4000_mca_write, et4000_mca_feedb, NULL, dev); + break; + + case ET4000_TYPE_KOREAN: /* Korean ET4000 */ + case ET4000_TYPE_TRIGEM: /* Trigem 286M ET4000 */ + dev->vram_size = device_get_config_int("memory") << 10; + dev->port_22cb_val = 0x60; + dev->port_32cb_val = 0; + dev->svga.ksc5601_sbyte_mask = 0x80; + dev->svga.ksc5601_udc_area_msb[0] = 0xC9; + dev->svga.ksc5601_udc_area_msb[1] = 0xFE; + dev->svga.ksc5601_swap_mode = 0; + dev->svga.ksc5601_english_font_type = 0; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_isa); + svga_init(info, &dev->svga, dev, dev->vram_size, + et4000_recalctimings, et4000k_in, et4000k_out, + NULL, NULL); + io_sethandler(0x03c0, 32, + et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, dev); + io_sethandler(0x22cb, 1, + et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, dev); + io_sethandler(0x22cf, 1, + et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, dev); + io_sethandler(0x32cb, 1, + et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, dev); + loadfont(KOREAN_FONT_ROM_PATH, 6); + fn = KOREAN_BIOS_ROM_PATH; + break; + + case ET4000_TYPE_KASAN: /* Kasan ET4000 */ + dev->vram_size = device_get_config_int("memory") << 10; + dev->svga.ksc5601_sbyte_mask = 0; + dev->svga.ksc5601_udc_area_msb[0] = 0xC9; + dev->svga.ksc5601_udc_area_msb[1] = 0xFE; + dev->svga.ksc5601_swap_mode = 0; + dev->svga.ksc5601_english_font_type = 0x1FF; + dev->kasan_cfg_index = 0; + for (i = 0; i < 16; i++) + dev->kasan_cfg_regs[i] = 0; + for (i = 0; i < 4; i++) + dev->kasan_font_data[i] = 0; + dev->kasan_cfg_regs[1] = 0x50; + dev->kasan_cfg_regs[2] = 2; + dev->kasan_cfg_regs[3] = 6; + dev->kasan_cfg_regs[4] = 0x78; + dev->kasan_cfg_regs[5] = 0xFF; + dev->kasan_cfg_regs[6] = 0xC9; + dev->kasan_cfg_regs[7] = 0xFE; + dev->kasan_access_addr = 0x250; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_isa); + svga_init(info, &dev->svga, dev, dev->vram_size, + et4000_kasan_recalctimings, et4000_in, et4000_out, + NULL, NULL); + io_sethandler(0x03c0, 32, + et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, dev); + io_sethandler(0x0250, 8, + et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, dev); + io_sethandler(0x0258, 2, + et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, dev); + loadfont(KASAN_FONT_ROM_PATH, 6); + fn = KASAN_BIOS_ROM_PATH; + break; +#endif + default: + break; + } + +// if (dev->type >= ET4000_TYPE_ISA) +// dev->svga.ramdac = device_add(&sc1502x_ramdac_device); + + dev->vram_mask = dev->vram_size - 1; + + rom_init(&dev->bios_rom, fn, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + dev->svga.translate_address = get_et4000_addr; + + dev->svga.packed_chain4 = 1; + + return dev; +} + +static void +et4000_close(void *priv) +{ + et4000_t *dev = (et4000_t *) priv; + + svga_close(&dev->svga); + + sc1502x_ramdac_close(dev->svga.ramdac); + + free(dev); +} + +static void +et4000_speed_changed(void *priv) +{ + et4000_t *dev = (et4000_t *) priv; + + svga_recalctimings(&dev->svga); +} + +static void +et4000_force_redraw(void *priv) +{ + et4000_t *dev = (et4000_t *) priv; + + dev->svga.fullchange = changeframecount; +} + +static int +et4000_available(void) +{ + return rom_present(BIOS_ROM_PATH); +} + +#if 0 +static int +et4000k_available(void) +{ + return rom_present(KOREAN_BIOS_ROM_PATH) && rom_present(KOREAN_FONT_ROM_PATH); +} + +static int +et4000_kasan_available(void) +{ + return rom_present(KASAN_BIOS_ROM_PATH) && rom_present(KASAN_FONT_ROM_PATH); +} +#endif + +#if 0 +static const device_config_t et4000_tc6058af_config[] = { + // clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 512, + .selection = { + { + .description = "256 KB", + .value = 256 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "" + } + } + }, + { + .name = "bios_ver", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "v1_10", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, /*W1*/ + .bios = { + { .name = "Version 1.10", .internal_name = "v1_10", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 32768, .files = { TC6058AF_BIOS_ROM_PATH, "" } }, + { .name = "Version 1.21", .internal_name = "v1_21", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 32768, .files = { V1_21_BIOS_ROM_PATH, "" } }, + { .files_no = 0 } + }, + }, + { + .type = CONFIG_END + } +// clang-format on +}; + +static const device_config_t et4000_bios_config[] = { + // clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 1024, + .selection = { + { + .description = "256 KB", + .value = 256 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } + } + }, + { + .name = "bios_ver", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "v8_01", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, /*W1*/ + .bios = { + { .name = "Version 8.01", .internal_name = "v8_01", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 32768, .files = { BIOS_ROM_PATH, "" } }, + { .name = "Version 8.06", .internal_name = "v8_06", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 32768, .files = { V8_06_BIOS_ROM_PATH, "" } }, + { .files_no = 0 } + }, + }, + { + .type = CONFIG_END + } + // clang-format on +}; + +static const device_config_t et4000_config[] = { + // clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 1024, + .selection = { + { + .description = "256 KB", + .value = 256 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } + } + }, + { + .type = CONFIG_END + } + // clang-format on +}; + +const device_t et4000_tc6058af_isa_device = { + .name = "Tseng Labs ET4000AX (TC6058AF) (ISA)", + .internal_name = "et4000ax_tc6058af", + .flags = DEVICE_ISA, + .local = 0, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_tc6058af_config +}; + +const device_t et4000_isa_device = { + .name = "Tseng Labs ET4000AX (ISA)", + .internal_name = "et4000ax", + .flags = DEVICE_ISA, + .local = ET4000_TYPE_ISA, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_bios_config +}; + +const device_t et4000_mca_device = { + .name = "Tseng Labs ET4000AX (MCA)", + .internal_name = "et4000mca", + .flags = DEVICE_MCA, + .local = ET4000_TYPE_MCA, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = et4000_available }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_config +}; + +const device_t et4000k_isa_device = { + .name = "Trigem Korean VGA (Tseng Labs ET4000AX Korean)", + .internal_name = "tgkorvga", + .flags = DEVICE_ISA, + .local = ET4000_TYPE_KOREAN, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = et4000k_available }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_config +}; + +const device_t et4000k_tg286_isa_device = { + .name = "Trigem Korean VGA (Trigem 286M)", + .internal_name = "et4000k_tg286_isa", + .flags = DEVICE_ISA, + .local = ET4000_TYPE_TRIGEM, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = et4000k_available }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_config +}; + +const device_t et4000_kasan_isa_device = { + .name = "Kasan Hangulmadang-16 VGA (Tseng Labs ET4000AX Korean)", + .internal_name = "kasan16vga", + .flags = DEVICE_ISA, + .local = ET4000_TYPE_KASAN, + .init = et4000_init, + .close = et4000_close, + .reset = NULL, + { .available = et4000_kasan_available }, + .speed_changed = et4000_speed_changed, + .force_redraw = et4000_force_redraw, + .config = et4000_config +}; +#endif + +void *et4000_domino_init() +{ + void *p = et4000_init(NULL); + et4000_t *et4000 = (et4000_t *)p; + + void *ramdac = sc1502x_ramdac_init(NULL); + et4000->svga.ramdac = ramdac; + + return p; +} + +device_t et4000_domino_device = +{ + "Domino", + 0, + et4000_domino_init, + et4000_close, + NULL, + et4000_speed_changed, + et4000_force_redraw, + NULL, + NULL +}; diff --git a/pcem/vid_et4000.h b/pcem/vid_et4000.h new file mode 100644 index 00000000..b88574de --- /dev/null +++ b/pcem/vid_et4000.h @@ -0,0 +1 @@ +extern device_t et4000_domino_device; diff --git a/pcem/vid_sc1502x_ramdac.cpp b/pcem/vid_sc1502x_ramdac.cpp new file mode 100644 index 00000000..57024c57 --- /dev/null +++ b/pcem/vid_sc1502x_ramdac.cpp @@ -0,0 +1,253 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of a Sierra SC1502X RAMDAC. + * + * Used by the TLIVESA1 driver for ET4000. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sdac_ramdac.h" + + +typedef struct sc1502x_ramdac_t { + int state; + uint8_t ctrl; + uint8_t idx; + uint8_t regs[256]; + uint32_t pixel_mask; + uint8_t enable_ext; +} sc1502x_ramdac_t; + +static void +sc1502x_ramdac_bpp(uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga) +{ + int oldbpp = 0; + if (val == 0xff) + return; + ramdac->ctrl = val; + oldbpp = svga->bpp; + switch ((val & 1) | ((val & 0xc0) >> 5)) { + case 0: + svga->bpp = 8; + break; + case 2: + case 3: + switch (val & 0x20) { + case 0x00: + svga->bpp = 32; + break; + case 0x20: + svga->bpp = 24; + break; + + default: + break; + } + break; + case 4: + case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 16; + break; + case 7: + if (val & 4) { + switch (val & 0x20) { + case 0x00: + svga->bpp = 32; + break; + case 0x20: + svga->bpp = 24; + break; + + default: + break; + } + } else + svga->bpp = 16; + break; + + default: + break; + } + if (oldbpp != svga->bpp) + svga_recalctimings(svga); +} + +void +sc1502x_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga) +{ + sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) priv; + + switch (addr) { + case 0x3C6: + if (ramdac->state == 0) + ramdac->enable_ext = (val == 0x10); + + if (ramdac->state == 4) { + ramdac->state = 0; + sc1502x_ramdac_bpp(val, ramdac, svga); + return; + } + ramdac->state = 0; + break; + case 0x3C7: + if (ramdac->enable_ext) { + ramdac->idx = val; + return; + } + ramdac->state = 0; + break; + case 0x3C8: + if (ramdac->enable_ext) { + switch (ramdac->idx) { + case 8: + ramdac->regs[ramdac->idx] = val; + svga_set_ramdac_type(svga, (ramdac->regs[ramdac->idx] & 1) ? RAMDAC_8BIT : RAMDAC_6BIT); + break; + case 0x0d: + ramdac->pixel_mask = val & svga->dac_mask; + break; + case 0x0e: + ramdac->pixel_mask |= ((val & svga->dac_mask) << 8); + break; + case 0x0f: + ramdac->pixel_mask |= ((val & svga->dac_mask) << 16); + break; + default: + ramdac->regs[ramdac->idx] = val; + break; + } + return; + } + ramdac->state = 0; + break; + case 0x3C9: + if (ramdac->enable_ext) + return; + ramdac->state = 0; + break; + + default: + break; + } + svga_out(addr, val, svga); +} + +uint8_t +sc1502x_ramdac_in(uint16_t addr, void *priv, svga_t *svga) +{ + sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) priv; + uint8_t temp = svga_in(addr, svga); + + switch (addr) { + case 0x3C6: + if (ramdac->state == 4) { + ramdac->state = 0; + temp = ramdac->ctrl; + break; + } + ramdac->state++; + break; + case 0x3C7: + ramdac->state = 0; + break; + case 0x3C8: + if (ramdac->enable_ext) { + switch (ramdac->idx) { + case 9: + temp = 0x53; + break; + case 0x0a: + temp = 0x3a; + break; + case 0x0b: + temp = 0xb1; + break; + case 0x0c: + temp = 0x41; + break; + case 0x0d: + temp = ramdac->pixel_mask & 0xff; + break; + case 0x0e: + temp = ramdac->pixel_mask >> 8; + break; + case 0x0f: + temp = ramdac->pixel_mask >> 16; + break; + default: + temp = ramdac->regs[ramdac->idx]; + break; + } + } else + ramdac->state = 0; + break; + case 0x3C9: + if (ramdac->enable_ext) + temp = ramdac->idx; + else + ramdac->state = 0; + break; + + default: + break; + } + + return temp; +} + +void * +sc1502x_ramdac_init(const device_t *info) +{ + sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) malloc(sizeof(sc1502x_ramdac_t)); + memset(ramdac, 0, sizeof(sc1502x_ramdac_t)); + + ramdac->ctrl = 0; + ramdac->pixel_mask = 0xffffff; + + return ramdac; +} + +void +sc1502x_ramdac_close(void *priv) +{ + sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + +#if 0 +const device_t sc1502x_ramdac_device = { + .name = "Sierra SC1502x RAMDAC", + .internal_name = "sc1502x_ramdac", + .flags = 0, + .local = 0, + .init = sc1502x_ramdac_init, + .close = sc1502x_ramdac_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; +#endif diff --git a/pcem/vid_svga.h b/pcem/vid_svga.h index 1cff4095..010131d6 100644 --- a/pcem/vid_svga.h +++ b/pcem/vid_svga.h @@ -1,3 +1,15 @@ + +# define FLAG_EXTRA_BANKS 1 +# define FLAG_ADDR_BY8 2 +# define FLAG_EXT_WRITE 4 +# define FLAG_LATCH8 8 +# define FLAG_NOSKEW 16 +# define FLAG_ADDR_BY16 32 +# define FLAG_RAMDAC_SHIFT 64 +# define FLAG_ATI 128 +# define FLAG_S3_911_16BIT 256 +# define FLAG_512K_MASK 512 + typedef struct svga_t { mem_mapping_t mapping; @@ -160,6 +172,21 @@ typedef struct svga_t int remap_required; uint32_t (*remap_func)(struct svga_t *svga, uint32_t in_addr); + uint32_t overscan_color; + int ati_4color; + void *ramdac; + uint32_t adv_flags; + int hblankstart; + int hblankend; + int hblank_end_val; + int hblank_end_len; + int hblank_end_mask; + int hblank_sub; + int dots_per_clock; + uint8_t fcr; + uint32_t *map8; + uint32_t(*translate_address)(uint32_t addr, void *priv); + bool swaprb; } svga_t; @@ -201,3 +228,6 @@ void svga_set_override(svga_t *svga, int val); void svga_set_ramdac_type(svga_t *svga, int type); void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); + +extern void sc1502x_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga); +extern uint8_t sc1502x_ramdac_in(uint16_t addr, void *priv, svga_t *svga); -- 2.47.3