From 1eb7478ab911b0cc08167d26b636ce80a5ad64ac Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 15 Sep 2022 15:57:26 +0200 Subject: [PATCH 1/7] 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/7] 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/7] 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 \ From 9f4a21d1ae0d7b2488868fd81effc318871672db Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 13 Sep 2022 14:32:16 +0200 Subject: [PATCH 4/7] Fix build with -DENABLE_PC_LOG=1 Global "AT" is not there since commit bc90f993503f ('Finally got rid of the AT and PCI global variables.'). --- src/86box.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/86box.c b/src/86box.c index e96506c92..19465a17f 100644 --- a/src/86box.c +++ b/src/86box.c @@ -761,7 +761,7 @@ void pc_full_speed(void) { if (!atfullspeed) { - pc_log("Set fullspeed - %i %i\n", is386, AT); + pc_log("Set fullspeed - %i %i\n", is386, is486); pc_speed_changed(); } atfullspeed = 1; From 24e0cb3829b3dc5cda7e4d99ddc7362510f5ff3b Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 14 Sep 2022 13:15:34 +0200 Subject: [PATCH 5/7] Fix build with ENABLE_VIDEO_LOG This fixes a copy & paste error. --- src/video/video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/video.c b/src/video/video.c index 9b07b9e1f..ae2fcf5eb 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -252,7 +252,7 @@ static uint32_t cga_2_table[16]; static void (*blit_func)(int x, int y, int w, int h, int monitor_index); #ifdef ENABLE_VIDEO_LOG -int sdl_do_log = ENABLE_VIDEO_LOG; +int video_do_log = ENABLE_VIDEO_LOG; static void video_log(const char *fmt, ...) From e902399035fee1837c3a7373ef61312bb223f745 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 14 Sep 2022 13:17:07 +0200 Subject: [PATCH 6/7] vid_table: Fix build with logging enabled --- src/video/vid_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 79189cdc0..73ad0cdd3 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -330,7 +330,7 @@ video_reset(int card) /* Do not initialize internal cards here. */ if (!(card == VID_NONE) && !(card == VID_INTERNAL) && !machine_has_flags(machine, MACHINE_VIDEO_ONLY)) { - vid_table_log("VIDEO: initializing '%s'\n", video_cards[card].name); + vid_table_log("VIDEO: initializing '%s'\n", video_cards[card].device->name); video_prepare(); From b20e72f37f7f4627d7f184e33aa25ec2bef03163 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 9 Sep 2021 15:39:26 +0200 Subject: [PATCH 7/7] Add a Victor V86P disk driver This emulates a JVC-branded controller/drive pair, using RLL encoding, connected via a small connector electrically compatible with ST-506. The controller is ST-506 compatible with an extra command for self-power-off. The option ROM is made by SMS. Commented disassembly is available for study [1]. The disk is a 3.5" 20MiB "made by Victor", labeled JD3824T100 on the outer protective casing, JD3824T00-1 on the actual drive. It's 615/2/34 physically, pretends to be a 614/4/17 so that it's type 3 compatible. [1] https://archive.org/details/v86p-hd --- src/disk/hdc.c | 1 + src/disk/hdc_st506_xt.c | 76 +++++++++++++++++++++++++++++++++++++++++ src/include/86box/hdc.h | 1 + 3 files changed, 78 insertions(+) diff --git a/src/disk/hdc.c b/src/disk/hdc.c index 0f2bc8599..1df1cd39b 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -115,6 +115,7 @@ static const struct { { &st506_xt_wd1002a_27x_device }, { &st506_xt_wd1004_27x_device }, { &st506_xt_wd1004a_27x_device }, + { &st506_xt_victor_v86p_device }, { &esdi_at_wd1007vse1_device }, { &ide_isa_device }, { &ide_isa_2ch_device }, diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index cedeb1220..ddf137f9c 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -99,6 +99,7 @@ #define WD1002A_27X_BIOS_FILE "roms/hdd/st506/wd1002a_27x-62-000094-032.bin" #define WD1004_27X_BIOS_FILE "roms/hdd/st506/western_digital_WD1004A-27X.bin" #define WD1004A_27X_BIOS_FILE "roms/hdd/st506/western_digital_WD1004A-27X.bin" +#define VICTOR_V86P_BIOS_FILE "roms/machines/v86p/2793VG.10010688.rom" #define ST506_TIME (250 * TIMER_USEC) #define ST506_TIME_MS (1000 * TIMER_USEC) @@ -182,6 +183,7 @@ #define CMD_WRITE_BUFFER 0x0f #define CMD_ALT_TRACK 0x11 #define CMD_INQUIRY_ST11 0x12 /* ST-11 BIOS */ +#define CMD_V86P_POWEROFF 0x1a /* Victor V86P */ #define CMD_RAM_DIAGNOSTIC 0xe0 /* reserved 0xe1 */ /* reserved 0xe2 */ @@ -819,6 +821,29 @@ st506_callback(void *priv) /* For a 615/4/26 we get 666/2/31 geometry. */ st506_xt_log("ST506: drive%i: cyls=%i, heads=%i\n", dev->drive_sel, drive->cfg_cyl, drive->cfg_hpc); + if (dev->type == 23 && drive->cfg_hpc == 2) { + /* + * On Victor V86P, there's a disagreement between + * the physical geometry, what the controller + * pretends it to be, and what the BIOS uses. + * + * The disk physically has 2/34 heads/sectors per + * track, but it is treated as 4/17 in order to + * look like a regular type 3 drive (see [1], + * line 1859). The controller accepts the 4/17 + * geometry, so this should not really matter. + * + * However, the BIOS issues SPECIFY (see [1], + * line 2089) with head count of two. Let's + * hardwire the correct number instead, just like + * the real hardware seems to. + * + * [1] https://archive.org/download/v86p-hd/V86P-HD.TXT + */ + drive->cfg_hpc = 4; + st506_xt_log("ST506: drive%i: corrected to heads=%i\n", + dev->drive_sel, drive->cfg_hpc); + } st506_complete(dev); break; } @@ -949,6 +974,34 @@ st506_callback(void *priv) } break; + case CMD_V86P_POWEROFF: + if (dev->type == 23) { + /* + * Main BIOS (not the option ROM on disk) issues this. + * Not much we can do, since we don't have a physical disk + * to spin down, but handle this anyways so that we log + * something more reasonable than "unknown command". + * + * Entirely undocumented, but this is what's been observed: + * BIOS setting | Command sent + * 1 minutes | 1a 00 00 0c 02 00 + * 2 minutes | 1a 00 00 18 02 00 + * 3 minutes | 1a 00 00 24 02 00 + * 4 minutes | 1a 00 00 30 02 00 + * 5 minutes | 1a 00 00 3c 02 00 + * off | 1a 00 00 00 02 00 + */ + if (dev->command[3]) + st506_xt_log("ST506: Auto power-off in %d seconds (type=%i)\n", + dev->command[3] * 5, dev->type); + else + st506_xt_log("ST506: Auto power-off disabled (type=%i)\n", dev->type); + } else { + st506_error(dev, ERR_BAD_COMMAND); + } + st506_complete(dev); + break; + case CMD_RAM_DIAGNOSTIC: #ifdef ENABLE_ST506_XT_LOG st506_xt_log("ST506: RAM_DIAG\n"); @@ -1485,6 +1538,9 @@ st506_init(const device_t *info) dev->switches |= 0x40; dev->bios_addr = device_get_config_hex20("bios_addr"); break; + case 23: /* Victor V86P (RLL) */ + fn = VICTOR_V86P_BIOS_FILE; + break; } /* Load the ROM BIOS. */ @@ -1605,6 +1661,12 @@ wd1004a_27x_available(void) return (rom_present(WD1004A_27X_BIOS_FILE)); } +static int +victor_v86p_available(void) +{ + return (rom_present(VICTOR_V86P_BIOS_FILE)); +} + // clang-format off static const device_config_t dtc_config[] = { { @@ -2036,3 +2098,17 @@ const device_t st506_xt_wd1004a_27x_device = { .force_redraw = NULL, .config = wd_rll_config }; + +const device_t st506_xt_victor_v86p_device = { + .name = "Victor V86P RLL Fixed Disk Adapter", + .internal_name = "st506_xt_victor_v86p", + .flags = DEVICE_ISA, + .local = (HDD_BUS_MFM << 8) | 23, + .init = st506_init, + .close = st506_close, + .reset = NULL, + { .available = victor_v86p_available }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 0c20aaa32..bde423337 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -40,6 +40,7 @@ extern const device_t st506_at_wd1003_device; /* st506_at_wd1003 */ extern const device_t st506_xt_wd1004a_wx1_device; /* st506_xt_wd1004a_wx1 */ extern const device_t st506_xt_wd1004_27x_device; /* st506_xt_wd1004_27x */ extern const device_t st506_xt_wd1004a_27x_device; /* st506_xt_wd1004a_27x */ +extern const device_t st506_xt_victor_v86p_device; /* st506_xt_victor_v86p */ extern const device_t esdi_at_wd1007vse1_device; /* esdi_at */ extern const device_t esdi_ps2_device; /* esdi_mca */