From 1eb7478ab911b0cc08167d26b636ce80a5ad64ac Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 15 Sep 2022 15:57:26 +0200 Subject: [PATCH 1/3] Use one more bit for AT NVR type Use bottom 4 bits (instead of 3) for the NVR type. This will be necessary in order to support more NVR types (the Epson Equity LT in particular). No functional change. --- src/nvr_at.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/nvr_at.c b/src/nvr_at.c index 91ee4a949..9a98968d2 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -981,9 +981,9 @@ nvr_at_init(const device_t *info) memset(local->lock, 0x00, nvr->size); local->def = 0xff /*0x00*/; local->flags = 0x00; - switch (info->local & 7) { + switch (info->local & 0x0f) { case 0: /* standard AT, no century register */ - if (info->local == 16) { + if (info->local == 32) { local->flags |= FLAG_P6RP4_HACK; nvr->irq = 8; local->cent = RTC_CENTURY_AT; @@ -996,13 +996,13 @@ nvr_at_init(const device_t *info) case 1: /* standard AT */ case 5: /* AMI WinBIOS 1994 */ case 6: /* AMI BIOS 1995 */ - if (info->local == 9) + if ((info->local & 0x0f) == 1) local->flags |= FLAG_PIIX4; else { local->def = 0x00; - if ((info->local & 7) == 5) + if ((info->local & 0x0f) == 5) local->flags |= FLAG_AMI_1994_HACK; - else if ((info->local & 7) == 6) + else if ((info->local & 0x0f) == 6) local->flags |= FLAG_AMI_1995_HACK; else local->def = 0xff; @@ -1015,7 +1015,7 @@ nvr_at_init(const device_t *info) nvr->irq = 8; local->cent = RTC_CENTURY_PS; local->def = 0x00; - if (info->local & 8) + if (info->local & 0x10) local->flags |= FLAG_NO_NMI; break; @@ -1023,15 +1023,15 @@ nvr_at_init(const device_t *info) nvr->irq = 1; local->cent = RTC_CENTURY_AT; local->def = 0xff; - if (info->local & 8) + if (info->local & 0x10) local->flags |= FLAG_NO_NMI; break; case 4: /* IBM AT */ - if (info->local == 12) { + if (info->local & 0x10) { local->def = 0x00; local->flags |= FLAG_AMI_1992_HACK; - } else if (info->local == 20) + } else if (info->local == 36) local->def = 0x00; else local->def = 0xff; @@ -1069,7 +1069,7 @@ nvr_at_init(const device_t *info) /* Set up the I/O handler for this device. */ io_sethandler(0x0070, 2, nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); - if (info->local & 8) { + if (info->local & 0x10) { io_sethandler(0x0072, 2, nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); } @@ -1180,7 +1180,7 @@ const device_t piix4_nvr_device = { .name = "Intel PIIX4 PC/AT NVRAM", .internal_name = "piix4_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 9, + .local = 0x10 | 1, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1220,7 +1220,7 @@ const device_t ami_1992_nvr_device = { .name = "AMI Color 1992 PC/AT NVRAM", .internal_name = "ami_1992_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 12, + .local = 0x10 | 4, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1234,7 +1234,7 @@ const device_t ami_1994_nvr_device = { .name = "AMI WinBIOS 1994 PC/AT NVRAM", .internal_name = "ami_1994_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 13, + .local = 0x10 | 5, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1248,7 +1248,7 @@ const device_t ami_1995_nvr_device = { .name = "AMI WinBIOS 1995 PC/AT NVRAM", .internal_name = "ami_1995_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 14, + .local = 0x10 | 6, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1262,7 +1262,7 @@ const device_t via_nvr_device = { .name = "VIA PC/AT NVRAM", .internal_name = "via_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 15, + .local = 0x10 | 7, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1276,7 +1276,7 @@ const device_t p6rp4_nvr_device = { .name = "ASUS P/I-P6RP4 PC/AT NVRAM", .internal_name = "p6rp4_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 16, + .local = 32, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, @@ -1290,7 +1290,7 @@ const device_t amstrad_megapc_nvr_device = { .name = "Amstrad MegapC NVRAM", .internal_name = "amstrad_megapc_nvr", .flags = DEVICE_ISA | DEVICE_AT, - .local = 20, + .local = 36, .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, From b9241aff7af11f58b98b724f347cf32995de520f Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 15 Sep 2022 16:10:30 +0200 Subject: [PATCH 2/3] Add NVR on Epson Equity LT It's a HD146818 chip mapped at 11B4h-11B5h. The century byte is at 1Ah. The IRQ line doesn't seem to be hooked on. --- src/include/86box/nvr.h | 1 + src/nvr_at.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/include/86box/nvr.h b/src/include/86box/nvr.h index 34f11efd4..d10191a79 100644 --- a/src/include/86box/nvr.h +++ b/src/include/86box/nvr.h @@ -97,6 +97,7 @@ extern const device_t ami_1994_nvr_device; extern const device_t ami_1995_nvr_device; extern const device_t via_nvr_device; extern const device_t p6rp4_nvr_device; +extern const device_t elt_nvr_device; #endif extern void rtc_tick(void); diff --git a/src/nvr_at.c b/src/nvr_at.c index 9a98968d2..ee2678ab5 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -280,6 +280,7 @@ #define REGD_VRT 0x80 #define RTC_CENTURY_AT 0x32 /* century register for AT etc */ #define RTC_CENTURY_PS 0x37 /* century register for PS/1 PS/2 */ +#define RTC_CENTURY_ELT 0x1A /* century register for Epson Equity LT */ #define RTC_ALDAY 0x7D /* VIA VT82C586B - alarm day */ #define RTC_ALMONTH 0x7E /* VIA VT82C586B - alarm month */ #define RTC_CENTURY_VIA 0x7F /* century register for VIA VT82C586B */ @@ -1043,6 +1044,10 @@ nvr_at_init(const device_t *info) nvr->irq = 8; local->cent = RTC_CENTURY_VIA; break; + case 8: /* Epson Equity LT */ + nvr->irq = -1; + local->cent = RTC_CENTURY_ELT; + break; } local->read_addr = 1; @@ -1067,8 +1072,13 @@ nvr_at_init(const device_t *info) timer_load_count(nvr); /* Set up the I/O handler for this device. */ - io_sethandler(0x0070, 2, - nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); + if (info->local == 8) { + io_sethandler(0x11b4, 2, + nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); + } else { + io_sethandler(0x0070, 2, + nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); + } if (info->local & 0x10) { io_sethandler(0x0072, 2, nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); @@ -1299,3 +1309,17 @@ const device_t amstrad_megapc_nvr_device = { .force_redraw = NULL, .config = NULL }; + +const device_t elt_nvr_device = { + .name = "Epson Equity LT NVRAM", + .internal_name = "elt_nvr", + .flags = DEVICE_ISA, + .local = 8, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + { .available = NULL }, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL +}; From 7026204aea684d3e796753544e94445a631c426d Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 13 Sep 2022 12:56:08 +0200 Subject: [PATCH 3/3] Add the Epson Equity LT Machine This is a portable computer based around NEC V30 processor and what seems to be a proprietary Epson chip set. The chip set provides a XT-class keyboard controller/PPI, controller for two DD floppy drives, CGA-compatible video, one serial and one parallel port. There's no datasheet for the chip set. The machine has a 640x200 monochromatic LCD display, optionally backlit and an external CRT connector. There can be up to two floppy drives, one of them optionally connected to an external connector (shared with the parallel port). There are physical switches to enable the external CRT and floppy connectors. There's a battery-backed RTC/NVRAM that holds configuration, including backlight timeout, UART configuration and floppy types. The machine has two expansion slots, half the pich of a regular 8-bit ISA, but electrically compatible. Hard drive and modem adapters were available, I don't have them. The checksums of the ROM images are as follows: SHA1(2d58397f81f006e7729648dd3720e3004e20ac36) = roms/machines/elt/HLO-B2.rom SHA1(8c06cd3905f71f15fec2a3759cea5b2c5dc602c3) = roms/machines/elt/HLO-A2.rom --- src/include/86box/machine.h | 3 + src/machine/CMakeLists.txt | 2 +- src/machine/m_elt.c | 199 ++++++++++++++++++++++++++++++++++++ src/machine/machine_table.c | 36 +++++++ src/win/Makefile.mingw | 1 + 5 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 src/machine/m_elt.c diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 0ba9e38f3..dee4df77d 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -708,6 +708,9 @@ extern int machine_at_vpc2007_init(const machine_t *); /* m_at_t3100e.c */ extern int machine_at_t3100e_init(const machine_t *); +/* m_elt.c */ +extern int machine_elt_init(const machine_t *); + /* m_europc.c */ extern int machine_europc_init(const machine_t *); #ifdef EMU_DEVICE_H diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 62bd5c61f..c96747f47 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -16,7 +16,7 @@ add_library(mch OBJECT machine.c machine_table.c m_xt.c m_xt_compaq.c m_xt_philips.c m_xt_t1000.c m_xt_t1000_vid.c m_xt_xi8088.c m_xt_zenith.c m_pcjr.c - m_amstrad.c m_europc.c m_xt_olivetti.c m_tandy.c m_v86p.c + m_amstrad.c m_europc.c m_elt.c m_xt_olivetti.c m_tandy.c m_v86p.c m_at.c m_at_commodore.c m_at_t3100e.c m_at_t3100e_vid.c m_ps1.c m_ps1_hdc.c m_ps2_isa.c m_ps2_mca.c m_at_compaq.c m_at_286_386sx.c m_at_386dx_486.c diff --git a/src/machine/m_elt.c b/src/machine/m_elt.c new file mode 100644 index 000000000..be0e26cb3 --- /dev/null +++ b/src/machine/m_elt.c @@ -0,0 +1,199 @@ +/* + * 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. + * + * Epson Equity LT portable computer emulation. + * + * Author: Lubomir Rintel, + * + * Copyright 2022 Lubomir Rintel. + * + * 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. + */ + +// clang-format off +#include +#include +#include +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/io.h> +#include <86box/keyboard.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/nmi.h> +#include <86box/nvr.h> +#include <86box/pit.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/vid_cga.h> +// clang-format on + +static void +elt_vid_off_poll(void *p) +{ + cga_t *cga = p; + uint8_t hdisp = cga->crtc[1]; + + /* Don't display anything. + * TODO: Do something less stupid to emulate backlight off. */ + cga->crtc[1] = 0; + cga_poll(cga); + cga->crtc[1] = hdisp; +} + +static void +sysstat_out(uint16_t port, uint8_t val, void *p) +{ + cga_t *cga = p; + + switch (val) { + case 0: + break; + case 1: + /* Backlight off. */ + if (cga) + timer_set_callback(&cga->timer, elt_vid_off_poll); + break; + case 2: + /* Backlight on. */ + if (cga) + timer_set_callback(&cga->timer, cga_poll); + break; + default: + pclog("Unknown sysstat command: 0x%02x\n", val); + } +} + +static uint8_t +sysstat_in(uint16_t port, void *p) +{ + cga_t *cga = p; + uint8_t ret = 0x0a; /* No idea what these bits are */ + + /* External CRT. We don't emulate the LCD/CRT switching, let's just + * frivolously use this bit to indicate we're using the LCD if the + * user didn't override the video card for now. */ + if (cga == NULL) + ret |= 0x40; + + return ret; +} + +static void +elt_vid_out(uint16_t addr, uint8_t val, void *p) +{ + cga_t *cga = p; + + /* The Equity LT chipset's CRTC contains more registers than the + * regular CGA. The BIOS writes one of them, register 36 (0x24). + * Nothing is known about the number or function of those registers, + * let's just ignore them so that we don't clobber the CGA register. + * Also, the BIOS writes that register via the 3D0h/3D1h alias + * instead of the usual 3D4h/3D5h, possibly to keep the wraparound + * behavior on the usual addresses (just an assumption, not + * verified). */ + switch (addr) { + case 0x3d0: + cga->crtcreg = val; + return; + case 0x3d1: + if (cga->crtcreg >= 32) + return; + /* FALLTHROUGH */ + default: + cga->crtcreg &= 31; + cga_out(addr, val, p); + } +} + +static uint8_t +elt_vid_in(uint16_t addr, void *p) +{ + cga_t *cga = p; + + /* Just make sure we don't ever let regular CGA code run with crtcreg + * pointing out of crtcregs[] bounds. */ + cga->crtcreg &= 31; + return cga_in(addr, p); +} + +static void +load_font_rom(uint32_t font_data) +{ + int c, d; + for (c = 0; c < 256; c++) + for (d = 0; d < 8; d++) + fontdat[c][d] = mem_readb_phys(font_data++); +} + +int +machine_elt_init(const machine_t *model) +{ + cga_t *cga = NULL; + int ret; + + ret = bios_load_interleavedr("roms/machines/elt/HLO-B2.rom", + "roms/machines/elt/HLO-A2.rom", + 0x000fc000, 65536, 0); + + if (bios_only || !ret) + return ret; + + /* The machine doesn't have any separate font ROM chip. The text mode + * font is likely a mask ROM in the chipset. video_reset() will try + * to load a MDA font, but let's have a reasonable fall back if it's + * not available. Read in the graphical mode font from the BIOS ROM + * image. */ + load_font_rom(0xffa6e); + + machine_common_init(model); + + nmi_init(); + + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); + + if (fdc_type == FDC_INTERNAL) + device_add(&fdc_xt_device); + + if (gfxcard == VID_INTERNAL) { + cga = device_add(&cga_device); + io_removehandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); + io_sethandler(0x03d0, 0x0010, elt_vid_in, NULL, NULL, elt_vid_out, NULL, NULL, cga); + } + + /* Keyboard goes after the video, because on XT compatibles it's dealt + * with by the same PPI as the config switches and we need them to + * indicate the correct display type */ + device_add(&keyboard_xt_device); + + device_add(&elt_nvr_device); + + io_sethandler(0x11b8, 1, sysstat_in, NULL, NULL, sysstat_out, NULL, NULL, cga); + + return ret; +} diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index cbfdccab9..48419bfbe 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -2117,6 +2117,42 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + { + .name = "[8086] Epson Equity LT", + .internal_name = "elt", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_elt_init, + .pad = 0, + .pad0 = 0, + .pad1 = MACHINE_AVAILABLE, + .pad2 = 0, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO, + .ram = { + .min = 640, + .max = 640, + .step = 640 + }, + .nvrmask = 0x3f, + .kbc = KBC_IBM_PC_XT, + .kbc_p1 = 0xff00, + .gpio = 0xffffffff, + .device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) { diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index e8eb299a4..27b601f2c 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -560,6 +560,7 @@ MCHOBJ := machine.o machine_table.o \ m_xt_xi8088.o m_xt_zenith.o \ m_pcjr.o \ m_amstrad.o m_europc.o \ + m_elt.o \ m_xt_olivetti.o m_tandy.o m_v86p.o \ m_at.o m_at_commodore.o \ m_at_t3100e.o m_at_t3100e_vid.o \