diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 9ccba8dc6..6147a2ccf 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -92,5 +92,6 @@ add_library(chipset OBJECT via_apollo.c via_pipc.c vl82c480.c + vl82c59x.c wd76c10.c ) diff --git a/src/chipset/vl82c59x.c b/src/chipset/vl82c59x.c new file mode 100644 index 000000000..468978718 --- /dev/null +++ b/src/chipset/vl82c59x.c @@ -0,0 +1,644 @@ +/* + * 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. + * + * Implementation of the VLSI SuperCore and Wildcat chipsets. + * + * + * + * Authors: Miran Grca, + * win2kgamer + * + * Copyright 2020-2025 Miran Grca. + * Copyright 2025 win2kgamer + */ + +#ifdef ENABLE_VL82C59X_LOG +#include +#endif + +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/device.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/apm.h> +#include <86box/machine.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/pit_fast.h> +#include <86box/plat_unused.h> +#include <86box/mem.h> +#include <86box/nvr.h> +#include <86box/smram.h> +#include <86box/pci.h> +#include <86box/port_92.h> +#include <86box/spd.h> +#include <86box/keyboard.h> +#include <86box/chipset.h> +#include <86box/log.h> + +#ifdef ENABLE_VL82C59X_LOG +int vl82c59x_do_log = ENABLE_VL82C59X_LOG; + +static void +vl82c59x_log(void *priv, const char *fmt, ...) +{ + if (vl82c59x_do_log) { + va_list ap; + va_start(ap, fmt); + log_out(priv, fmt, ap); + va_end(ap); + } +} +#else +# define vl82c59x_log(fmt, ...) +#endif + +typedef struct vl82c59x_t { + uint8_t nb_slot; + uint8_t sb_slot; + uint8_t type; + uint8_t is_compaq; + + uint8_t pci_conf[256]; + uint8_t pci_conf_sb[256]; + + uint16_t pmio; + uint8_t pmio_set; + uint8_t pmreg; + + smram_t *smram[4]; + port_92_t *port_92; + nvr_t *nvr; + + void * log; /* New logging system */ +} vl82c59x_t; + +static int +vl82c59x_shflags(uint8_t access) +{ + int ret = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + + switch (access) { + default: + case 0x00: + ret = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + break; + case 0x01: + ret = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + break; + case 0x02: + ret = MEM_READ_INTERNAL | MEM_WRITE_EXTANY; + break; + case 0x03: + ret = MEM_READ_INTERNAL | MEM_WRITE_INTERNAL; + break; + } + + return ret; +} + +static void +vl82c59x_recalc(vl82c59x_t *dev) +{ + uint32_t base; + uint8_t access; + + shadowbios = 0; + shadowbios_write = 0; + + for (uint8_t i = 0; i < 4; i++) { + for (uint8_t j = 0; j < 8; j += 2) { + base = 0x000c0000 + (i << 16) + (j << 13); + access = (dev->pci_conf[0x66 + i] >> j) & 3; + mem_set_mem_state_both(base, 0x4000, vl82c59x_shflags(access)); + shadowbios |= ((base >= 0xe0000) && (access & 0x02)); + shadowbios_write |= ((base >= 0xe0000) && (access & 0x01)); + } + } + + flushmmucache(); +} + +static void +vl82c59x_smram(vl82c59x_t *dev) +{ + smram_disable_all(); + + /* A/B region SMRAM seems to not be controlled by 591 reg 0x7C/SMRAM enable */ + /* Dell Dimension BIOS breaks if A0000 region is controlled by SMRAM enable */ + if (dev->pci_conf[0x64] & 0x55) { + smram_enable(dev->smram[0], 0x000a0000, 0x000a0000, 0x10000, dev->pci_conf[0x64] & 0xAA, dev->pci_conf[0x64] & 0x55); + } + if (dev->pci_conf[0x65] & 0x55) { + smram_enable(dev->smram[1], 0x000b0000, 0x000b0000, 0x10000, dev->pci_conf[0x65] & 0xAA, dev->pci_conf[0x65] & 0x55); + } + + /* Handle E region SMRAM */ + if (dev->pci_conf[0x7C] & 0x80) { + if (dev->pci_conf[0x68] & 0x05) { + smram_enable(dev->smram[2], 0x000e0000, 0x000e0000, 0x8000, dev->pci_conf[0x68] & 0x0A, dev->pci_conf[0x68] & 0x05); + } + if (dev->pci_conf[0x68] & 0x50) { + smram_enable(dev->smram[3], 0x000e8000, 0x000e8000, 0x8000, dev->pci_conf[0x68] & 0xA0, dev->pci_conf[0x68] & 0x50); + } + } + + flushmmucache(); +} + +static void +vl82c59x_pm_write(uint16_t addr, uint8_t val, void *priv) +{ + vl82c59x_t *dev = (vl82c59x_t *) priv; + + vl82c59x_log(dev->log, "VL82c593 SMI I/O: [W] (%04X) = %02X\n", addr, val); + + /* Verify SMI Global Enable and Software SMI Enable are set */ + if ((dev->pci_conf_sb[0x6D] & 0x80) && (dev->pci_conf_sb[0x60] & 0x80)) { + dev->pci_conf_sb[0x61] = 0x80; + dev->pmreg = val; + smi_raise(); + } + +} + +static uint8_t +vl82c59x_pm_read(uint16_t addr, void *priv) +{ + vl82c59x_t *dev = (vl82c59x_t *) priv; + uint8_t ret = 0x00; + + ret = dev->pmreg; + vl82c59x_log(dev->log, "VL82c593 SMI I/O: [R] (%04X) = %02X\n", addr, ret); + + return ret; +} + +static void +vl82c59x_set_pm_io(void *priv) +{ + vl82c59x_t *dev = (vl82c59x_t *) priv; + uint8_t highbyte = dev->pci_conf_sb[0x62]; + uint8_t lowbyte = dev->pci_conf_sb[0x63]; + + /* Check for existing I/O mapping and remove it */ + if (dev->pmio_set == 1) { + vl82c59x_log(dev->log, "VL82c59x: Removing SMI IO handler for %04X\n", dev->pmio); + io_removehandler(dev->pmio, 0x0001, vl82c59x_pm_read, NULL, NULL, vl82c59x_pm_write, NULL, NULL, dev); + dev->pmio_set = 0; + } + + if ((highbyte != 0x00) | (lowbyte != 0x00)) { + dev->pmio = ((highbyte << 8) + lowbyte); + vl82c59x_log(dev->log, "VL82c59x: Adding SMI IO handler for %04X\n", dev->pmio); + io_sethandler(dev->pmio, 0x0001, vl82c59x_pm_read, NULL, NULL, vl82c59x_pm_write, NULL, NULL, dev); + dev->pmio_set = 1; + } + +} + +static void +vl82c59x_write(int func, int addr, uint8_t val, void *priv) +{ + vl82c59x_t *dev = (vl82c59x_t *) priv; + + vl82c59x_log(dev->log, "[%04X:%08X] VL82c591: [W] (%02X, %02X) = %02X\n", CS, cpu_state.pc, func, addr, val); + + if (func == 0x00) + switch (addr) { + case 0x04: + case 0x05: /* PCI Command Register */ + dev->pci_conf[addr] = val; + break; + case 0x54: /* Cache Control Register 1 */ + dev->pci_conf[addr] = val; + cpu_cache_ext_enabled = (val & 0xc0); + cpu_update_waitstates(); + break; + case 0x55: /* Cache Control Register 2 */ + dev->pci_conf[addr] = val; + cpu_cache_int_enabled = (val & 0x40); + cpu_update_waitstates(); + break; + case 0x58: /* RAMCFG0 */ + case 0x59: /* RAMCFG1 */ + dev->pci_conf[addr] = val; + break; + case 0x5A: /* Wildcat EDO RAM control */ + if (dev->type == 0x01) { + dev->pci_conf[addr] = val; + } + break; + case 0x5C: /* RAMCTL0 */ + case 0x5D: /* RAMCTL1 */ + case 0x5E: /* RAMCTL2 */ + case 0x5F: + case 0x60: + case 0x62: + /* Apricot XEN-PC Ruby/Jade BIOS requires bit 2 to be set or */ + /* CMOS setup hangs on subsequent runs after NVRAM is initialized */ + dev->pci_conf[addr] = val; + break; + case 0x64: /* A-B SMRAM regs */ + case 0x65: + dev->pci_conf[addr] = val; + vl82c59x_smram(dev); + break; + case 0x66: /* Shadow RAM */ + case 0x67: + case 0x68: + case 0x69: + dev->pci_conf[addr] = val; + vl82c59x_recalc(dev); + vl82c59x_smram(dev); + break; + case 0x6C: /* L2 Cacheability registers */ + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x74: /* Suspected PMRA registers */ + case 0x75: + case 0x76: + case 0x78: + case 0x79: + case 0x7A: + dev->pci_conf[addr] = val; + break; + case 0x7C: /* MISCSSET, bit 7 is SMRAM enable (for the E region) */ + /* io.c logging shows BIOSes setting Bit 7 here */ + dev->pci_conf[addr] = val; + vl82c59x_smram(dev); + break; + case 0x7D: /* Unknown but seems Wildcat-specific, Zeos and PB600 BIOSes hang if bit 3 is writable */ + if (dev->type == 0x01) { + dev->pci_conf[addr] = val & 0xf7; + } + break; + default: + if (addr > 0x3F) + vl82c59x_log(dev->log, "VL82c591: Unknown reg [W] (%02X, %02X) = %02X\n", func, addr, val); + break; + } + +} + +static uint8_t +vl82c59x_read(int func, int addr, void *priv) +{ + const vl82c59x_t *dev = (vl82c59x_t *) priv; + uint8_t ret = 0xff; + + if (func == 0x00) { + switch (addr) { + default: + ret = dev->pci_conf[addr]; + break; + } + } + + vl82c59x_log(dev->log, "[%04X:%08X] VL82c591: [R] (%02X, %02X) = %02X\n", CS, cpu_state.pc, func, addr, ret); + + return ret; +} + +static void +vl82c59x_sb_write(int func, int addr, uint8_t val, void *priv) +{ + vl82c59x_t *dev = (vl82c59x_t *) priv; + uint8_t irq; + const uint8_t irq_array[8] = { 3, 5, 9, 10, 11, 12, 14, 15 }; + + vl82c59x_log(dev->log, "[%04X:%08X] VL82c593: [W] (%02X, %02X) = %02X\n", CS, cpu_state.pc, func, addr, val); + + if (func == 0x00) + switch (addr) { + case 0x04: + case 0x05: /* PCI Command Register */ + dev->pci_conf_sb[addr] = val; + break; + case 0x50: /* MISCSETC */ + case 0x51: /* MISCSETB */ + case 0x52: /* MISCSETA */ + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + /* Has at least one GPIO bit. Compaq Presario 700/900 586 BIOS */ + /* uses bit 2 as an output to set the onboard ES688's base I/O */ + /* address. Bit 2 cleared = 220, bit 2 set = 240 */ + case 0x5C: /* Interrupt Assertion Level Register */ + case 0x5D: + dev->pci_conf_sb[addr] = val; + break; + case 0x60: /* SMI Enable Register */ + dev->pci_conf_sb[addr] = val; + break; + case 0x61: /* SMI Status Register */ + dev->pci_conf_sb[addr] = 0x00; + break; + case 0x62: /* SMI I/O port high byte */ + case 0x63: /* SMI I/O port low byte */ + dev->pci_conf_sb[addr] = val; + vl82c59x_set_pm_io(dev); + break; + case 0x64: /* System Event Enable Register 1 */ + dev->pci_conf_sb[addr] = val; + break; + case 0x65: /* System Event Status Register 1 */ + dev->pci_conf_sb[addr] = 0x00; + break; + case 0x66: /* System Event Enable Register 2 */ + dev->pci_conf_sb[addr] = val; + break; + case 0x67: /* System Event Status Register 2 */ + dev->pci_conf_sb[addr] = 0x00; + break; + case 0x68: /* System Event Enable Register 3 */ + dev->pci_conf_sb[addr] = val; + break; + case 0x69: /* System Event Status Register 3 */ + dev->pci_conf_sb[addr] = 0x00; + break; + case 0x6A: /* PCI Activity Control Register */ + dev->pci_conf_sb[addr] = val & 0x0f; /* Top 4 bits are Read/Clear */ + break; + case 0x6B: /* Programmable I/O Range Register High Byte */ + dev->pci_conf_sb[addr] = val; + break; + case 0x6C: /* Programmable I/O Range Register Low Byte */ + dev->pci_conf_sb[addr] = val; + break; + case 0x6D: /* System Event Control Register/SMI Global Enable */ + dev->pci_conf_sb[addr] = val; + break; + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: /* GPIO */ + /* Compaq Presario and Prolinea use bits 6-4 for setting ECP DMA */ + /* 011 (0x03) = DMA 3 (Default) */ + /* 100 (0x04) = DMA 0 */ + /* 111 (0x07) = DMA disabled */ + case 0x73: /* GPIO */ + dev->pci_conf_sb[addr] = val; + break; + case 0x74: /* PCI Interrupt Connection Register (PCIINT0/1) */ + dev->pci_conf_sb[addr] = val; + irq = irq_array[val & 0x07]; + pci_set_irq_routing(PCI_INTA, (irq != 0) ? irq : PCI_IRQ_DISABLED); + irq = irq_array[(val & 0x70) >> 4]; + pci_set_irq_routing(PCI_INTB, (irq != 0) ? irq : PCI_IRQ_DISABLED); + break; + case 0x75: /* PCI Interrupt Connection Register (PCIINT2/3) */ + dev->pci_conf_sb[addr] = val; + irq = irq_array[val & 0x07]; + pci_set_irq_routing(PCI_INTC, (irq != 0) ? irq : PCI_IRQ_DISABLED); + irq = irq_array[(val & 0x70) >> 4]; + pci_set_irq_routing(PCI_INTD, (irq != 0) ? irq : PCI_IRQ_DISABLED); + break; + case 0x76: /* PCI Interrupt Connection Register (ISA/PCIINT) */ + dev->pci_conf_sb[addr] = val; + break; + case 0x77: + case 0x78: + dev->pci_conf_sb[addr] = val; + break; + default: + if (addr > 0x3F) + vl82c59x_log(dev->log, "VL82c593: Unknown reg [W] (%02X, %02X) = %02X\n", func, addr, val); + break; + } + +} + +static uint8_t +vl82c59x_sb_read(int func, int addr, void *priv) +{ + const vl82c59x_t *dev = (vl82c59x_t *) priv; + uint8_t ret = 0xff; + + if (func == 0x00) + switch (addr) { + case 0x69: /* Lower two bits are a CPU speed readout per Compaq's Prolinea E series TRG */ + /* Per the Prolinea TRG bits 5/3/1 of 593 reg 0x73 must be set to 1 to read the jumpers */ + if (dev->is_compaq && (dev->pci_conf_sb[0x73] & 0x2A)) { + /* Set bit 2 to 1 as this is required for the Prolinea E to be properly identified + in Compaq Computer Setup. */ + ret = (dev->pci_conf_sb[addr] | 0x04); + if (cpu_busspeed <= 50000000) + ret = (ret & 0xfd); /* 50MHz: Bit 1 = 0 */ + else + ret = (ret | 0x02); /* 60MHz: Bit 1 = 1 */ + + if (cpu_dmulti <= 1.5) + ret = (ret | 0x01); /* 1.5x mult: Bit 0 = 1 */ + else + ret = (ret & 0xfe); /* 2.0x mult: Bit 0 = 0 */ + } else { + ret = dev->pci_conf_sb[addr]; + } + break; + default: + ret = dev->pci_conf_sb[addr]; + break; + } + + vl82c59x_log(dev->log, "[%04X:%08X] VL82c593: [R] (%02X, %02X) = %02X\n", CS, cpu_state.pc, func, addr, ret); + + return ret; + +} + +static void +vl82c59x_reset(void *priv) +{ + vl82c59x_t *dev = (vl82c59x_t *) priv; + + /* Northbridge (VLSI VL82c591) */ + dev->pci_conf[0x00] = 0x04; + dev->pci_conf[0x01] = 0x10; + switch (dev->type) { + case 0: /* SuperCore */ + dev->pci_conf[0x02] = 0x05; + dev->pci_conf[0x03] = 0x00; + break; + case 1: /* Wildcat */ + dev->pci_conf[0x02] = 0x07; + dev->pci_conf[0x03] = 0x00; + break; + } + dev->pci_conf[0x08] = 0x00; + dev->pci_conf[0x09] = 0x00; + dev->pci_conf[0x0a] = 0x00; + dev->pci_conf[0x0b] = 0x06; + + /* Southbridge (VLSI VL82c593) */ + dev->pci_conf_sb[0x00] = 0x04; + dev->pci_conf_sb[0x01] = 0x10; + switch (dev->type) { + case 0: /* SuperCore */ + dev->pci_conf_sb[0x02] = 0x06; + dev->pci_conf_sb[0x03] = 0x00; + break; + case 1: /* Wildcat */ + dev->pci_conf_sb[0x02] = 0x08; + dev->pci_conf_sb[0x03] = 0x00; + break; + } + dev->pci_conf_sb[0x08] = 0x00; + dev->pci_conf_sb[0x09] = 0x00; + dev->pci_conf_sb[0x0a] = 0x01; + dev->pci_conf_sb[0x0b] = 0x06; + + /* Unsure on which register configures this (if any), per Compaq's + * Pentium-based Presario 700/900 Series and Prolinea E Series Desktop + * Technical Reference Guides the ISA bus runs at 8MHz while the + * Zeos Pantera Wildcat user manual says that the ISA bus runs at + * 7.5MHz on 90MHz (60MHz bus) systems and 8.25MHz on 100MHz (66MHz bus) + * systems. + */ + if (cpu_busspeed > 50000000) + cpu_set_isa_pci_div(4); + else + cpu_set_isa_pci_div(3); + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + vl82c59x_smram(dev); + + /* Reset SMI IO port */ + dev->pmio = 0x0000; + dev->pmio_set = 0; + + cpu_cache_int_enabled = 1; + cpu_cache_ext_enabled = 1; + cpu_update_waitstates(); +} + +static void +vl82c59x_close(void *priv) +{ + vl82c59x_t *dev = (vl82c59x_t *) priv; + + smram_del(dev->smram[0]); + smram_del(dev->smram[1]); + smram_del(dev->smram[2]); + smram_del(dev->smram[3]); + + if (dev->log != NULL) { + log_close(dev->log); + dev->log = NULL; + } + + free(dev); +} + +static void * +vl82c59x_init(UNUSED(const device_t *info)) +{ + vl82c59x_t *dev = (vl82c59x_t *) calloc(1, sizeof(vl82c59x_t)); + + dev->type = (info->local & 0x0f); + + dev->is_compaq = (info->local >> 4); + + dev->log = log_open("VL82c59x"); + + /* VL82c591 (Northbridge) */ + pci_add_card(PCI_ADD_NORTHBRIDGE, vl82c59x_read, vl82c59x_write, dev, &dev->nb_slot); + + /* VL82c593 (Southbridge) */ + pci_add_card(PCI_ADD_SOUTHBRIDGE, vl82c59x_sb_read, vl82c59x_sb_write, dev, &dev->sb_slot); + + dev->port_92 = device_add(&port_92_device); + + /* NVR */ + dev->nvr = device_add(&at_nvr_device); + + dev->smram[0] = smram_add(); + dev->smram[1] = smram_add(); + dev->smram[2] = smram_add(); + dev->smram[3] = smram_add(); + + vl82c59x_reset(dev); + + return dev; +} + +const device_t vl82c59x_device = { + .name = "VLSI VL82c59x (SuperCore)", + .internal_name = "vl82c59x", + .flags = DEVICE_PCI, + .local = 0, + .init = vl82c59x_init, + .close = vl82c59x_close, + .reset = vl82c59x_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t vl82c59x_compaq_device = { + .name = "VLSI VL82c59x (SuperCore with Compaq readout)", + .internal_name = "vl82c59x_compaq", + .flags = DEVICE_PCI, + .local = 0x10, + .init = vl82c59x_init, + .close = vl82c59x_close, + .reset = vl82c59x_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t vl82c59x_wildcat_device = { + .name = "VLSI VL82c59x (Wildcat)", + .internal_name = "vl82c59x_wildcat", + .flags = DEVICE_PCI, + .local = 1, + .init = vl82c59x_init, + .close = vl82c59x_close, + .reset = vl82c59x_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t vl82c59x_wildcat_compaq_device = { + .name = "VLSI VL82c59x (Wildcat with Compaq readout)", + .internal_name = "vl82c59x_wildcat_compaq", + .flags = DEVICE_PCI, + .local = 0x11, + .init = vl82c59x_init, + .close = vl82c59x_close, + .reset = vl82c59x_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index dcad64149..47330955a 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -18,6 +18,8 @@ add_library(dev OBJECT access_bus.c + ast_nvr.c + ast_readout.c bugger.c cartridge.c cassette.c diff --git a/src/device/ast_nvr.c b/src/device/ast_nvr.c new file mode 100644 index 000000000..21585dbe3 --- /dev/null +++ b/src/device/ast_nvr.c @@ -0,0 +1,180 @@ +/* + * 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. + * + * Implementation of the AST Bravo MS secondary NVR + * + * + * + * Authors: win2kgamer + * + * Copyright 2025 win2kgamer. + */ + +#ifdef ENABLE_AST_NVR_LOG +#include +#endif + +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/machine.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/rom.h> +#include <86box/log.h> + +#ifdef ENABLE_AST_NVR_LOG +int ast_nvr_do_log = ENABLE_AST_NVR_LOG; + +static void +ast_nvr_log(void *priv, const char *fmt, ...) +{ + if (ast_nvr_do_log) { + va_list ap; + va_start(ap, fmt); + log_out(priv, fmt, ap); + va_end(ap); + } +} +#else +# define ast_nvr_log(fmt, ...) +#endif + +typedef struct ast_nvr_t { + int addr; + int bank; + + uint8_t *ram; + int size; + + char *fn; + + void * log; // New logging system +} ast_nvr_t; + +static uint8_t +ast_nvr_read(uint16_t port, void *priv) +{ + ast_nvr_t *nvr = (ast_nvr_t *) priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x800 ... 0x8FF: + nvr->addr = ((nvr->bank << 8) + (port - 0x800)); + ret = nvr->ram[nvr->addr]; + break; + default: + break; + } + + ast_nvr_log(nvr->log, "AST NVR Read [%02X:%02X] = %02X\n", nvr->bank, port, ret); + + return ret; +} + +static void +ast_nvr_write(uint16_t port, uint8_t val, void *priv) +{ + ast_nvr_t *nvr = (ast_nvr_t *) priv; + + ast_nvr_log(nvr->log, "AST NVR Write [%02X:%02X] = %02X\n", nvr->bank, port, val); + + switch (port) { + case 0x800 ... 0x8FF: + nvr->addr = ((nvr->bank << 8) + (port - 0x800)); + nvr->ram[nvr->addr] = val; + break; + case 0xC00: + nvr->bank = val; + default: + break; + } + +} + +static void * +ast_nvr_init(const device_t *info) +{ + ast_nvr_t *nvr; + FILE *fp = NULL; + int c; + + nvr = (ast_nvr_t *) calloc(1, sizeof(ast_nvr_t)); + memset(nvr, 0x00, sizeof(ast_nvr_t)); + + nvr->log = log_open("ASTNVR"); + + nvr->size = 8192; + + /* Set up the NVR file's name */ + c = strlen(machine_get_internal_name()) + 9; + nvr->fn = (char *) calloc(1, (c + 1)); + sprintf(nvr->fn, "%s_sec.nvr", machine_get_internal_name()); + + io_sethandler(0x0800, 0x100, + ast_nvr_read, NULL, NULL, ast_nvr_write, NULL, NULL, nvr); + io_sethandler(0x0C00, 0x01, + ast_nvr_read, NULL, NULL, ast_nvr_write, NULL, NULL, nvr); + + fp = nvr_fopen(nvr->fn, "rb"); + + nvr->ram = (uint8_t *) calloc(1, nvr->size); + memset(nvr->ram, 0xff, nvr->size); + if (fp != NULL) { + if (fread(nvr->ram, 1, nvr->size, fp) != nvr->size) + fatal("ast_nvr_init(): Error reading EEPROM data\n"); + fclose(fp); + } + + return nvr; +} + +static void +ast_nvr_close (void *priv) +{ + ast_nvr_t *nvr = (ast_nvr_t *) priv; + FILE *fp = NULL; + + fp = nvr_fopen(nvr->fn, "wb"); + + if (fp != NULL) { + (void) fwrite(nvr->ram, nvr->size, 1, fp); + fclose(fp); + } + + if (nvr->ram != NULL) + free(nvr->ram); + + if (nvr->log != NULL) { + log_close(nvr->log); + nvr->log = NULL; + } + + free(nvr); +} + +const device_t ast_nvr_device = { + .name = "AST Secondary NVRAM for Bravo MS", + .internal_name = "ast_nvr", + .flags = 0, + .local = 0, + .init = ast_nvr_init, + .close = ast_nvr_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/ast_readout.c b/src/device/ast_readout.c new file mode 100644 index 000000000..e583ae34d --- /dev/null +++ b/src/device/ast_readout.c @@ -0,0 +1,198 @@ +/* + * 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. + * + * Implementation of the AST Bravo MS jumper readout. + * + * + * + * Authors: win2kgamer + * + * Copyright 2025 win2kgamer + */ + +#ifdef ENABLE_AST_READOUT_LOG +#include +#endif + +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/chipset.h> +#include <86box/plat_unused.h> +#include <86box/lpt.h> +#include <86box/machine.h> +#include <86box/log.h> + +/* + The AST readout device has multiple indexed registers that handle + jumper readout, software ECP DMA configuration and other unknown functions. + + Register 0x00: + Bits 6-4 = ECP DMA configuration + 010 (0x02) = DMA 0 + 101 (0x05) = DMA 1 + 111 (0x07) = DMA 3 + + Register 0x03: + Bit 7 = Force flash + Bit 6 = Password disable + Bit 5 = Mono/Color primary video (0=Color/1=Mono) + Bit 4 = Setup disable (0=Enable Setup/1=Disable Setup) + Bit 3 = Enable onboard video (0=Enable/1=Disable) + Bit 2 = ???? + Bit 1 = ???? + Bit 0 = ???? +*/ + +typedef struct ast_readout_t { + uint8_t index; + uint8_t jumper[4]; + + void * log; // New logging system +} ast_readout_t; + +#ifdef ENABLE_AST_READOUT_LOG +int ast_readout_do_log = ENABLE_AST_READOUT_LOG; + +static void +ast_readout_log(void *priv, const char *fmt, ...) +{ + if (ast_readout_do_log) { + va_list ap; + va_start(ap, fmt); + log_out(priv, fmt, ap); + va_end(ap); + } +} +#else +# define ast_readout_log(fmt, ...) +#endif + +static void +ast_readout_write(uint16_t port, uint8_t val, void *priv) +{ + ast_readout_t *dev = (ast_readout_t *) priv; + switch (port) { + case 0xE0: + ast_readout_log(dev->log, "[%04X:%08X] AST Bravo Readout: Set Index %02X\n", CS, cpu_state.pc, val); + dev->index = val; + break; + case 0xE1: + ast_readout_log(dev->log, "[%04X:%08X] AST Bravo Readout: Write %02X:%02X\n", CS, cpu_state.pc, dev->index, val); + if ((dev->index == 0x00) && (!strcmp(machine_get_internal_name(), "bravoms586"))) { + uint8_t dmaval = ((val >> 4) & 0x07); + dev->jumper[dev->index] = val; + switch (dmaval) { + case 0x02: + ast_readout_log(dev->log, "ECP DMA set to 0\n"); + lpt1_dma(0); + break; + case 0x05: + ast_readout_log(dev->log, "ECP DMA set to 1\n"); + lpt1_dma(1); + break; + case 0x07: + ast_readout_log(dev->log, "ECP DMA set to 3\n"); + lpt1_dma(3); + break; + default: + ast_readout_log(dev->log, "Unknown ECP DMA!\n"); + break; + } + } else if (dev->index == 0x03) { + dev->jumper[dev->index] = (val & 0x07); + if (gfxcard[0] != 0x01) + dev->jumper[dev->index] |= 0x08; + } + else + dev->jumper[dev->index] = val; + break; + default: + break; + } +} + +static uint8_t +ast_readout_read(uint16_t port, void *priv) +{ + const ast_readout_t *dev = (ast_readout_t *) priv; + uint8_t ret = 0xff; + + switch (port) { + case 0xE0: + ast_readout_log(dev->log, "[%04X:%08X] AST Bravo Readout: Read Index %02X\n", CS, cpu_state.pc, dev->index); + ret = dev->index; + break; + case 0xE1: + ast_readout_log(dev->log, "[%04X:%08X] AST Bravo Readout: Read %02X:%02X\n", CS, cpu_state.pc, dev->index, dev->jumper[dev->index]); + ret = dev->jumper[dev->index]; + break; + default: + break; + } + return ret; +} + +static void +ast_readout_reset(void *priv) +{ + ast_readout_t *dev = (ast_readout_t *) priv; + + dev->jumper[0x03] = 0x06; + if (gfxcard[0] != 0x01) + dev->jumper[0x03] |= 0x08; +} + +static void +ast_readout_close(void *priv) +{ + ast_readout_t *dev = (ast_readout_t *) priv; + + if (dev->log != NULL) { + log_close(dev->log); + dev->log = NULL; + } + + free(dev); +} + +static void * +ast_readout_init(const device_t *info) +{ + ast_readout_t *dev = (ast_readout_t *) calloc(1, sizeof(ast_readout_t)); + + dev->log = log_open("AST Readout"); + + ast_readout_reset(dev); + + io_sethandler(0x00E0, 0x0002, ast_readout_read, NULL, NULL, ast_readout_write, NULL, NULL, dev); + + return dev; +} + +const device_t ast_readout_device = { + .name = "AST Bravo MS Readout", + .internal_name = "ast_readout", + .flags = 0, + .local = 0, + .init = ast_readout_init, + .close = ast_readout_close, + .reset = ast_readout_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/phoenix_486_jumper.c b/src/device/phoenix_486_jumper.c index 1b6270984..ed4349082 100644 --- a/src/device/phoenix_486_jumper.c +++ b/src/device/phoenix_486_jumper.c @@ -40,6 +40,18 @@ Bit 0 = ????. */ +/* + PB600 bit meanings: + Bit 7 = ???? (if 1 BIOS throws beep codes and won't POST) + Bit 6 = Super I/O chip: 1 = disabled, 0 = enabled + Bit 5 = ???? + Bit 4 = ???? + Bit 3 = ???? + Bit 2 = ???? + Bit 1 = Quick Boot: 1 = normal boot, 0 = quick boot/skip POST + Bit 0 = ???? +*/ + typedef struct phoenix_486_jumper_t { uint8_t type; uint8_t jumper; @@ -70,6 +82,8 @@ phoenix_486_jumper_write(UNUSED(uint16_t addr), uint8_t val, void *priv) phoenix_486_jumper_log("Phoenix 486 Jumper: Write %02x\n", val); if (dev->type == 1) dev->jumper = val & 0xbf; + else if (dev->type == 2) /* PB600 */ + dev->jumper = ((val & 0xbf) | 0x02); else dev->jumper = val; } @@ -90,6 +104,8 @@ phoenix_486_jumper_reset(void *priv) if (dev->type == 1) dev->jumper = 0x00; + else if (dev->type == 2) /* PB600 */ + dev->jumper = 0x02; else { dev->jumper = 0x9f; if (gfxcard[0] != 0x01) @@ -146,3 +162,17 @@ const device_t phoenix_486_jumper_pci_device = { .force_redraw = NULL, .config = NULL }; + +const device_t phoenix_486_jumper_pci_pb600_device = { + .name = "Phoenix 486 Jumper Readout (PB600)", + .internal_name = "phoenix_486_jumper_pci_pb600", + .flags = 0, + .local = 2, + .init = phoenix_486_jumper_init, + .close = phoenix_486_jumper_close, + .reset = phoenix_486_jumper_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index e9ee7083f..566f255e9 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -810,7 +810,7 @@ ide_set_signature(ide_t *ide) ide->tf->sector = 1; ide->tf->head = 0; ide->tf->secount = 1; - ide->tf->cylinder = (ide->type == IDE_ATAPI_SHADOW) ? 0x0000 : ide_signatures[ide->type & ~IDE_SHADOW]; + ide->tf->cylinder = ide_signatures[ide->type & ~IDE_SHADOW]; if (ide->type == IDE_HDD) ide->drive = 0; @@ -1579,7 +1579,7 @@ ide_reset_registers(ide_t *ide) ide->tf->atastat = DRDY_STAT | DSC_STAT; ide->tf->error = 1; ide->tf->secount = 1; - ide->tf->cylinder = (ide->type == IDE_ATAPI_SHADOW) ? 0x0000 : ide_signatures[ide->type & ~IDE_SHADOW]; + ide->tf->cylinder = ide_signatures[ide->type & ~IDE_SHADOW]; ide->tf->sector = 1; ide->tf->head = 0; @@ -2098,6 +2098,8 @@ ide_readb(uint16_t addr, void *priv) case 0x4: /* Cylinder low */ if (ide->type == IDE_NONE) ret = 0x7f; + else if (ide->type == IDE_ATAPI_SHADOW) + ret = 0x00; else ret = ide->tf->cylinder & 0xff; #if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) @@ -2109,6 +2111,8 @@ ide_readb(uint16_t addr, void *priv) case 0x5: /* Cylinder high */ if (ide->type == IDE_NONE) ret = 0x7f; + else if (ide->type == IDE_ATAPI_SHADOW) + ret = 0x00; else ret = ide->tf->cylinder >> 8; #if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) diff --git a/src/disk/hdc_ide_cmd640.c b/src/disk/hdc_ide_cmd640.c index dbdf32dcf..ea2a195d9 100644 --- a/src/disk/hdc_ide_cmd640.c +++ b/src/disk/hdc_ide_cmd640.c @@ -694,3 +694,18 @@ const device_t ide_cmd640_pci_single_channel_sec_device = { .force_redraw = NULL, .config = NULL }; + +const device_t ide_cmd640_pci_single_channel_legacy_only_device = { + .name = "CMD PCI-0640B PCI (Legacy Mode Only)", + .internal_name = "ide_cmd640_pci_single_channel_legacy_only", + .flags = DEVICE_PCI, + .local = 0x20000, + .init = cmd640_init, + .close = cmd640_close, + .reset = cmd640_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + diff --git a/src/disk/hdc_ide_rz1000.c b/src/disk/hdc_ide_rz1000.c index 6b7aa68e8..56568cc2c 100644 --- a/src/disk/hdc_ide_rz1000.c +++ b/src/disk/hdc_ide_rz1000.c @@ -51,6 +51,7 @@ typedef struct rz1000_t { int irq_mode[2]; int irq_pin; int irq_line; + uint8_t type; } rz1000_t; static int next_id = 0; @@ -197,9 +198,12 @@ rz1000_reset(void *priv) rz1000_log("dev->local = %08X\n", dev->local); + dev->type = ((dev->local >> 8) & 0x01); + rz1000_log("dev->type = %04X\n", dev->type); + dev->regs[0x00] = 0x42; /* PC Technology */ dev->regs[0x01] = 0x10; - dev->regs[0x02] = 0x00; /* RZ-1000 */ + dev->regs[0x02] = dev->type; /* RZ-1000/RZ-1001 */ dev->regs[0x03] = 0x10; dev->regs[0x04] = 0x00; dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */ @@ -296,3 +300,17 @@ const device_t ide_rz1000_pci_single_channel_device = { .force_redraw = NULL, .config = NULL }; + +const device_t ide_rz1001_pci_device = { + .name = "PC Technology RZ-1001 PCI", + .internal_name = "ide_rz1001_pci", + .flags = DEVICE_PCI, + .local = 0x60100, + .init = rz1000_init, + .close = rz1000_close, + .reset = rz1000_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 4693890e3..d14bf69d6 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -1940,6 +1940,16 @@ fdc_callback(void *priv) case 0x0f: /*Seek*/ fdc->st0 = 0x20 | (fdc->params[0] & 3); fdc->stat = 0x10 | (1 << fdc->rw_drive); + if (fdd_get_turbo(1 << fdc->rw_drive)) { + if (fdc->flags & FDC_FLAG_PCJR) { + fdc->fintr = 1; + fdc->interrupt = -4; + timer_set_delay_u64(&fdc->timer, 1024 * TIMER_USEC); + } else { + fdc->interrupt = -3; + fdc_callback(fdc); + } + } // Interrupts and callbacks in the fdd callback function return; case 0x10: /*Version*/ diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 212317f49..d4d9d4476 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -385,31 +385,35 @@ fdd_seek(int drive, int track_diff) fdd_changed[drive] = 0; - /* Trigger appropriate audio for track movements */ - int actual_track_diff = abs(old_track - fdd[drive].track); - if (actual_track_diff == 1) { - /* Single track movement */ - fdd_audio_play_single_track_step(drive, old_track, fdd[drive].track); - } else if (actual_track_diff > 1) { - /* Multi-track seek */ - fdd_audio_play_multi_track_seek(drive, old_track, fdd[drive].track); - } - - if (old_track + track_diff < 0) { + if (fdd[drive].turbo) fdd_do_seek(drive, fdd[drive].track); - return; + else { + /* Trigger appropriate audio for track movements */ + int actual_track_diff = abs(old_track - fdd[drive].track); + if (actual_track_diff == 1) { + /* Single track movement */ + fdd_audio_play_single_track_step(drive, old_track, fdd[drive].track); + } else if (actual_track_diff > 1) { + /* Multi-track seek */ + fdd_audio_play_multi_track_seek(drive, old_track, fdd[drive].track); + } + + if (old_track + track_diff < 0) { + fdd_do_seek(drive, fdd[drive].track); + return; + } + + fdd_seek_in_progress[drive] = 1; + + if (!fdd_seek_timer[drive].callback) { + timer_add(&(fdd_seek_timer[drive]), fdd_seek_complete_callback, &drives[drive], 0); + } + + double initial_seek_time = FDC_FLAG_PCJR & fdd_fdc->flags ? 40000.0 : 15000.0; + double track_seek_time = FDC_FLAG_PCJR & fdd_fdc->flags ? 10000.0 : 6000.0; + uint64_t seek_time_us = (initial_seek_time + (abs(actual_track_diff) * track_seek_time)) * TIMER_USEC; + timer_set_delay_u64(&fdd_seek_timer[drive], seek_time_us); } - - fdd_seek_in_progress[drive] = 1; - - if (!fdd_seek_timer[drive].callback) { - timer_add(&(fdd_seek_timer[drive]), fdd_seek_complete_callback, &drives[drive], 0); - } - - double initial_seek_time = FDC_FLAG_PCJR & fdd_fdc->flags ? 40000.0 : 15000.0; - double track_seek_time = FDC_FLAG_PCJR & fdd_fdc->flags ? 10000.0 : 6000.0; - uint64_t seek_time_us = (initial_seek_time + (abs(actual_track_diff) * track_seek_time)) * TIMER_USEC; - timer_set_delay_u64(&fdd_seek_timer[drive], seek_time_us); } int diff --git a/src/floppy/fdd_audio.c b/src/floppy/fdd_audio.c index 04ae9ba68..feb434535 100644 --- a/src/floppy/fdd_audio.c +++ b/src/floppy/fdd_audio.c @@ -387,7 +387,7 @@ fdd_audio_close(void) void fdd_audio_set_motor_enable(int drive, int motor_enable) { - if (!fdd_sounds_enabled) + if (!fdd_sounds_enabled || fdd_get_turbo(drive)) return; drive_audio_samples_t *samples = get_drive_samples(drive); @@ -421,7 +421,7 @@ fdd_audio_set_motor_enable(int drive, int motor_enable) void fdd_audio_play_single_track_step(int drive, int from_track, int to_track) { - if (!fdd_sounds_enabled) + if (!fdd_sounds_enabled || fdd_get_turbo(drive)) return; if (drive < 0 || drive >= FDD_NUM) @@ -436,7 +436,7 @@ fdd_audio_play_single_track_step(int drive, int from_track, int to_track) void fdd_audio_play_multi_track_seek(int drive, int from_track, int to_track) { - if (!fdd_sounds_enabled) + if (!fdd_sounds_enabled || fdd_get_turbo(drive)) return; if (drive < 0 || drive >= FDD_NUM) diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 9cd037d1f..66ae082ef 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -214,6 +214,10 @@ extern const device_t via_vt8231_device; /* VLSI */ extern const device_t vl82c480_device; extern const device_t vl82c486_device; +extern const device_t vl82c59x_device; +extern const device_t vl82c59x_compaq_device; +extern const device_t vl82c59x_wildcat_device; +extern const device_t vl82c59x_wildcat_compaq_device; extern const device_t vlsi_scamp_device; /* WD */ @@ -228,6 +232,10 @@ extern const device_t nec_mate_unk_device; extern const device_t phoenix_486_jumper_device; extern const device_t phoenix_486_jumper_pci_device; +extern const device_t phoenix_486_jumper_pci_pb600_device; + +extern const device_t ast_readout_device; +extern const device_t ast_nvr_device; extern const device_t radisys_config_device; diff --git a/src/include/86box/filters.h b/src/include/86box/filters.h index 3e20fa653..572137ef0 100644 --- a/src/include/86box/filters.h +++ b/src/include/86box/filters.h @@ -5,7 +5,7 @@ /* fc=150Hz */ static inline float -adgold_highpass_iir(int c, int i, float NewSample) +adgold_highpass_iir(int i, float NewSample) { float ACoef[NCoef + 1] = { 0.98657437157334349000, @@ -19,76 +19,6 @@ adgold_highpass_iir(int c, int i, float NewSample) 0.97261396931534050000 }; - static float y[2][2][NCoef + 1]; /* output samples */ - static float x[2][2][NCoef + 1]; /* input samples */ - int n; - - /* shift the old samples */ - for (n = NCoef; n > 0; n--) { - x[c][i][n] = x[c][i][n - 1]; - y[c][i][n] = y[c][i][n - 1]; - } - - /* Calculate the new output */ - x[c][i][0] = NewSample; - y[c][i][0] = ACoef[0] * x[c][i][0]; - for (n = 1; n <= NCoef; n++) - y[c][i][0] += ACoef[n] * x[c][i][n] - BCoef[n] * y[c][i][n]; - - return y[c][i][0]; -} - -/* fc=150Hz */ -static inline float -adgold_lowpass_iir(int c, int i, float NewSample) -{ - float ACoef[NCoef + 1] = { - 0.00009159473951071446, - 0.00018318947902142891, - 0.00009159473951071446 - }; - - float BCoef[NCoef + 1] = { - 1.00000000000000000000, - -1.97223372919526560000, - 0.97261396931306277000 - }; - - static float y[2][2][NCoef + 1]; /* output samples */ - static float x[2][2][NCoef + 1]; /* input samples */ - int n; - - /* shift the old samples */ - for (n = NCoef; n > 0; n--) { - x[c][i][n] = x[c][i][n - 1]; - y[c][i][n] = y[c][i][n - 1]; - } - - /* Calculate the new output */ - x[c][i][0] = NewSample; - y[c][i][0] = ACoef[0] * x[c][i][0]; - for (n = 1; n <= NCoef; n++) - y[c][i][0] += ACoef[n] * x[c][i][n] - BCoef[n] * y[c][i][n]; - - return y[c][i][0]; -} - -/* fc=56Hz */ -static inline float -adgold_pseudo_stereo_iir(int i, float NewSample) -{ - float ACoef[NCoef + 1] = { - 0.00001409030866231767, - 0.00002818061732463533, - 0.00001409030866231767 - }; - - float BCoef[NCoef + 1] = { - 1.00000000000000000000, - -1.98733021473466760000, - 0.98738361004063568000 - }; - static float y[2][NCoef + 1]; /* output samples */ static float x[2][NCoef + 1]; /* input samples */ int n; @@ -108,6 +38,76 @@ adgold_pseudo_stereo_iir(int i, float NewSample) return y[i][0]; } +/* fc=150Hz */ +static inline float +adgold_lowpass_iir(int i, float NewSample) +{ + float ACoef[NCoef + 1] = { + 0.00009159473951071446, + 0.00018318947902142891, + 0.00009159473951071446 + }; + + float BCoef[NCoef + 1] = { + 1.00000000000000000000, + -1.97223372919526560000, + 0.97261396931306277000 + }; + + static float y[2][NCoef + 1]; /* output samples */ + static float x[2][NCoef + 1]; /* input samples */ + int n; + + /* shift the old samples */ + for (n = NCoef; n > 0; n--) { + x[i][n] = x[i][n - 1]; + y[i][n] = y[i][n - 1]; + } + + /* Calculate the new output */ + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for (n = 1; n <= NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +/* fc=56Hz */ +static inline float +adgold_pseudo_stereo_iir(float NewSample) +{ + float ACoef[NCoef + 1] = { + 0.00001409030866231767, + 0.00002818061732463533, + 0.00001409030866231767 + }; + + float BCoef[NCoef + 1] = { + 1.00000000000000000000, + -1.98733021473466760000, + 0.98738361004063568000 + }; + + static float y[NCoef + 1]; /* output samples */ + static float x[NCoef + 1]; /* input samples */ + int n; + + /* shift the old samples */ + for (n = NCoef; n > 0; n--) { + x[n] = x[n - 1]; + y[n] = y[n - 1]; + } + + /* Calculate the new output */ + x[0] = NewSample; + y[0] = ACoef[0] * x[0]; + for (n = 1; n <= NCoef; n++) + y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; + + return y[0]; +} + /* fc=3.2kHz - probably incorrect */ static inline float dss_iir(float NewSample) diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 214ed84e5..91a4c68cd 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -76,6 +76,7 @@ extern const device_t ide_cmd640_pci_device; /* CMD PCI-640B extern const device_t ide_cmd640_pci_legacy_only_device; /* CMD PCI-640B PCI (Legacy Mode Only) */ extern const device_t ide_cmd640_pci_single_channel_device; /* CMD PCI-640B PCI (Only primary channel) */ extern const device_t ide_cmd640_pci_single_channel_sec_device; /* CMD PCI-640B PCI (Only secondary channel) */ +extern const device_t ide_cmd640_pci_single_channel_legacy_only_device; /* CMD PCI-640B PCI (Legacy Mode Only/Only primary channel) */ extern const device_t ide_cmd646_device; /* CMD PCI-646 */ extern const device_t ide_cmd646_legacy_only_device; /* CMD PCI-646 (Legacy Mode Only) */ extern const device_t ide_cmd646_single_channel_device; /* CMD PCI-646 (Only primary channel) */ @@ -89,6 +90,7 @@ extern const device_t ide_opti611_vlb_sec_device; /* OPTi 82c611/6 extern const device_t ide_rz1000_pci_device; /* PC Technology RZ-1000 PCI */ extern const device_t ide_rz1000_pci_single_channel_device; /* PC Technology RZ-1000 PCI (Only primary channel) */ +extern const device_t ide_rz1001_pci_device; /* PC Technology RZ-1001 PCI */ extern const device_t ide_um8673f_device; /* UMC UM8673F */ extern const device_t ide_um8886af_device; /* UMC UM8886AF */ diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index b88d8f492..00562d455 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -301,6 +301,8 @@ enum { MACHINE_CHIPSET_VLSI_VL82C480, MACHINE_CHIPSET_VLSI_VL82C481, MACHINE_CHIPSET_VLSI_VL82C486, + MACHINE_CHIPSET_VLSI_SUPERCORE, + MACHINE_CHIPSET_VLSI_WILDCAT, MACHINE_CHIPSET_WD76C10, MACHINE_CHIPSET_ZYMOS_POACH, MACHINE_CHIPSET_MAX @@ -890,6 +892,9 @@ extern int machine_at_ecs50x_init(const machine_t *); /* OPTi 597 */ extern int machine_at_pci56001_init(const machine_t *); +/* VLSI SuperCore */ +extern int machine_at_celebris5xx_init(const machine_t *); + /* m_at_socket5.c */ /* i430NX */ extern int machine_at_p54np4_init(const machine_t *); @@ -930,6 +935,15 @@ extern int machine_at_torino_init(const machine_t *); /* UMC 889x */ extern int machine_at_hot539_init(const machine_t *); +/* VLSI SuperCore */ +extern int machine_at_bravoms586_init(const machine_t *); +extern int machine_at_g586vpmc_init(const machine_t *); +extern int machine_at_m54si_init(const machine_t *); +extern int machine_at_pb600_init(const machine_t *); + +/* VLSI Wildcat */ +extern int machine_at_globalyst620_init(const machine_t *); + /* m_at_socket7_3v.c */ /* i430FX */ #ifdef EMU_DEVICE_H @@ -976,6 +990,9 @@ extern int machine_at_ap5s_init(const machine_t *); extern int machine_at_pc140_6260_init(const machine_t *); extern int machine_at_ms5124_init(const machine_t *); +/* VLSI Wildcat */ +extern int machine_at_zeoswildcat_init(const machine_t *); + /* m_at_socket7.c */ /* i430HX */ extern int machine_at_acerm3a_init(const machine_t *); diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index 4ad6f1709..435b2aac4 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -66,10 +66,10 @@ typedef struct ad1848_t { uint8_t enable : 1; uint8_t irq : 4; uint8_t dma : 3; - uint8_t adpcm_ref; - int8_t adpcm_step; + int adpcm_predictor[2]; + int16_t adpcm_step_index[2]; int freq; - int adpcm_data; + uint8_t adpcm_data; int adpcm_pos; uint8_t dma_ff; diff --git a/src/include/86box/snd_opl.h b/src/include/86box/snd_opl.h index 62c62e965..fbc66a1c2 100644 --- a/src/include/86box/snd_opl.h +++ b/src/include/86box/snd_opl.h @@ -49,6 +49,9 @@ enum fm_type { FM_MAX = 26 }; +#define FM_TYPE_MASK 255 +#define FM_FORCE_48K 256 + enum fm_driver { FM_DRV_NUKED = 0, FM_DRV_YMFM = 1, @@ -65,9 +68,11 @@ typedef struct fm_drv_t { void (*generate)(void *priv, int32_t *data, uint32_t num_samples); /* daughterboard only. */ } fm_drv_t; +extern uint8_t fm_driver_get_ex(int chip_id, fm_drv_t *drv, int is_48k); extern uint8_t fm_driver_get(int chip_id, fm_drv_t *drv); extern const fm_drv_t nuked_opl_drv; +extern const fm_drv_t nuked_opl_drv_48k; extern const fm_drv_t ymfm_drv; extern const fm_drv_t esfmu_opl_drv; extern const fm_drv_t ymfm_opl2board_drv; diff --git a/src/include/86box/snd_opl_nuked.h b/src/include/86box/snd_opl_nuked.h index 0b203fe31..9fdbe16c4 100644 --- a/src/include/86box/snd_opl_nuked.h +++ b/src/include/86box/snd_opl_nuked.h @@ -147,7 +147,7 @@ struct _opl3_chip { typedef struct { opl3_chip opl; int8_t flags; - int8_t pad; + int8_t is_48k; uint16_t port; uint8_t status; @@ -159,6 +159,8 @@ typedef struct { int pos; int32_t buffer[MUSICBUFLEN * 2]; + + int32_t *(*update)(void *priv); } nuked_drv_t; enum { diff --git a/src/include/86box/snd_ym7128.h b/src/include/86box/snd_ym7128.h index f0657425f..a0796b1fa 100644 --- a/src/include/86box/snd_ym7128.h +++ b/src/include/86box/snd_ym7128.h @@ -19,18 +19,18 @@ typedef struct ym7128_t { int c1; int t[9]; - int16_t filter_dat[2]; - int16_t prev_l[2]; - int16_t prev_r[2]; + int16_t filter_dat; + int16_t prev_l; + int16_t prev_r; - int16_t delay_buffer[2][2400]; - int delay_pos[2]; + int16_t delay_buffer[2400]; + int delay_pos; int16_t last_samp; } ym7128_t; void ym7128_init(ym7128_t *ym7128); void ym7128_write(ym7128_t *ym7128, uint8_t val); -void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int i, int len); +void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len); #endif /*SOUND_YM7128_H*/ diff --git a/src/machine/m_at_socket4_5.c b/src/machine/m_at_socket4_5.c index 368f8397f..f5b7ae87c 100644 --- a/src/machine/m_at_socket4_5.c +++ b/src/machine/m_at_socket4_5.c @@ -70,3 +70,36 @@ machine_at_pci56001_init(const machine_t *model) return ret; } + +/* VLSI SuperCore */ +int +machine_at_celebris5xx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/celebris5xx/CELEBRIS.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_IDE, 4, 1, 2, 3); /* Onboard */ + pci_register_slot(0x09, PCI_CARD_VIDEO, 4, 1, 2, 3); /* Onboard */ + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 3, 2, 1); /* Slot 01 */ + pci_register_slot(0x0C, PCI_CARD_NORMAL, 2, 1, 3, 2); /* Slot 02 */ + + device_add(&vl82c59x_device); + device_add(&intel_flash_bxt_device); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add_params(&fdc37c6xx_device, (void *) FDC37C665); + device_add(&ide_cmd640_pci_device); + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + return ret; +} diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index cb3803e0d..c61f4c8bb 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -765,3 +765,165 @@ machine_at_hot539_init(const machine_t *model) return ret; } + +/* VLSI SuperCore */ +int +machine_at_bravoms586_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/bravoms586/asttest.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_IDE, 2, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); + + device_add(&vl82c59x_device); + device_add(&intel_flash_bxt_device); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add_params(&fdc37c6xx_device, (void *) (FDC37C665 | FDC37C6XX_IDE_SEC)); + device_add(&ide_cmd640_pci_single_channel_device); + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + device_add(&ast_readout_device); /* AST custom jumper readout */ + device_add(&ast_nvr_device); /* AST custom secondary NVR device */ + + return ret; +} + +int +machine_at_g586vpmc_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/g586vpmc/Vpm_c3.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x02, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x08, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_IDE, 0, 0, 0, 0); + device_add(&vl82c59x_device); + device_add(&sst_flash_29ee010_device); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add_params(&pc873xx_device, (void *) (PC87332 | PCX730X_398)); + device_add(&ide_cmd646_device); + return ret; +} + +int +machine_at_m54si_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/m54si/M54SI.03", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_IDE, 0, 0, 0, 0); /* Onboard device */ + pci_register_slot(0x10, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + /* Slots are a guess since this BIOS won't work with pcireg */ + device_add(&vl82c59x_device); + device_add(&intel_flash_bxt_device); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add_params(&fdc37c6xx_device, (void *) (FDC37C665 | FDC37C6XX_IDE_SEC)); + device_add(&ide_cmd640_pci_single_channel_device); + + return ret; +} + +int +machine_at_pb600_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pb600/BIOS.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0A, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_IDE, 4, 0, 0, 0); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + device_add(&vl82c59x_device); + device_add(&intel_flash_bxt_device); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add_params(&fdc37c6xx_device, (void *) FDC37C665); + device_add(&phoenix_486_jumper_pci_pb600_device); + device_add(&ide_cmd640_pci_device); + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + return ret; +} + +/* VLSI Wildcat */ +int +machine_at_globalyst620_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/globalyst620/p107.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_VIDEO, 0, 0, 0, 0); /* Onboard device */ + pci_register_slot(0x10, PCI_CARD_IDE, 0, 0, 0, 0); /* Onboard device */ + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); /* Slot 04 */ + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); /* Slot 05 */ + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); /* Slot 06 */ + device_add(&vl82c59x_wildcat_device); + device_add(&intel_flash_bxt_device); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add(&ide_cmd640_pci_single_channel_legacy_only_device); + device_add_params(&fdc37c6xx_device, (void *) (FDC37C665 | FDC37C6XX_IDE_SEC)); + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + return ret; +} diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index f289b2275..068782db7 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -1020,3 +1020,36 @@ machine_at_ms5124_init(const machine_t *model) return ret; } + +/* VLSI Wildcat */ +int +machine_at_zeoswildcat_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/zeoswildcat/003606.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_IDE, 1, 2, 0, 0); /* Onboard device */ + pci_register_slot(0x0E, PCI_CARD_SCSI, 1, 0, 0, 0); /* Onboard device */ + pci_register_slot(0x0F, PCI_CARD_NETWORK, 1, 0, 0, 0); /* Onboard device */ + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); /* Slot 03 */ + pci_register_slot(0x12, PCI_CARD_NORMAL, 4, 2, 3, 1); /* Slot 04 */ + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); /* Slot 05 */ + /* Per the machine's manual there was an option for AMD SCSI and/or LAN controllers */ + device_add(&vl82c59x_wildcat_device); + device_add(&intel_flash_bxt_device); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add_params(&fdc37c6xx_device, (void *) FDC37C665); + device_add(&ide_rz1001_pci_device); + + return ret; +} diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 8c8dc6b91..9fa4ab81b 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -163,6 +163,8 @@ const machine_filter_t machine_chipsets[] = { { "VLSI VL82C480", MACHINE_CHIPSET_VLSI_VL82C480 }, { "VLSI VL82C481", MACHINE_CHIPSET_VLSI_VL82C481 }, { "VLSI VL82C486", MACHINE_CHIPSET_VLSI_VL82C486 }, + { "VLSI SuperCore", MACHINE_CHIPSET_VLSI_SUPERCORE }, + { "VLSI Wildcat", MACHINE_CHIPSET_VLSI_WILDCAT }, { "WD76C10", MACHINE_CHIPSET_WD76C10 } }; @@ -11939,6 +11941,51 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* VLSI SuperCore */ + /* This has Phoenix KBC firmware. */ + { + .name = "[VLSI SuperCore] DEC Celebris 5xx", + .internal_name = "celebris5xx", + .type = MACHINE_TYPE_SOCKET4_5, + .chipset = MACHINE_CHIPSET_VLSI_SUPERCORE, + .init = machine_at_celebris5xx_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET4 | CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK(CPU_Cx6x86), + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 5000, + .min_multi = 1.0, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_VIDEO, + .ram = { + .min = 4096, + .max = 131072, + .step = 4096 + }, + .nvrmask = 127, + .jumpered_ecp_dma = MACHINE_DMA_3, + .default_jumpered_ecp_dma = 3, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_PHOENIX | 0x00021400, /* Guess */ + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &s3_phoenix_vision864_pci_device, + .snd_device = NULL, + .net_device = NULL + }, /* Socket 5 machines */ /* 430NX */ @@ -12879,6 +12926,232 @@ const machine_t machines[] = { .net_device = NULL }, + /* VLSI SuperCore */ + /* This has AST KBC firmware, likely a Phoenix variant since the BIOS */ + /* calls KBC command D5h to read the KBC revision. */ + { + .name = "[VLSI SuperCore] AST Bravo MS P/90", + .internal_name = "bravoms586", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_VLSI_SUPERCORE, + .init = machine_at_bravoms586_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK(CPU_Cx6x86), + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_VIDEO, + .ram = { + .min = 4096, + .max = 131072, + .step = 4096 + }, + .nvrmask = 127, + .jumpered_ecp_dma = MACHINE_DMA_USE_CONFIG, + .default_jumpered_ecp_dma = -1, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_PHOENIX | 0x00021400, /* Guess */ + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5434_onboard_pci_device, + .snd_device = NULL, + .net_device = NULL + }, + /* Has a VIA KBC chip */ + { + .name = "[VLSI SuperCore] DFI G586VPM Rev C", + .internal_name = "g586vpmc", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_VLSI_SUPERCORE, + .init = machine_at_g586vpmc_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM, + .ram = { + .min = 4096, + .max = 262144, + .step = 4096 + }, + .nvrmask = 127, + .jumpered_ecp_dma = MACHINE_DMA_1 | MACHINE_DMA_3, + .default_jumpered_ecp_dma = 1, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_VIA | 0x00424600, /* Guess */ + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, + /* KBC firmware is unknown. No commands outside of the base PS/2 */ + /* KBC command set are used. */ + { + .name = "[VLSI SuperCore] Micronics M54Si", + .internal_name = "m54si", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_VLSI_SUPERCORE, + .init = machine_at_m54si_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK(CPU_Cx6x86), + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM, + .ram = { + .min = 4096, + .max = 131072, + .step = 4096 + }, + .nvrmask = 127, + .jumpered_ecp_dma = MACHINE_DMA_DISABLED | MACHINE_DMA_1 | MACHINE_DMA_3, + .default_jumpered_ecp_dma = 4, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_PHOENIX | 0x00021400, /* Guess */ + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, + /* This has Phoenix KBC firmware. */ + { + .name = "[VLSI SuperCore] Packard Bell PB600", + .internal_name = "pb600", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_VLSI_SUPERCORE, + .init = machine_at_pb600_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_VIDEO, + .ram = { + .min = 8192, + .max = 139264, + .step = 4096 + }, + .nvrmask = 127, + .jumpered_ecp_dma = MACHINE_DMA_1 | MACHINE_DMA_3, + .default_jumpered_ecp_dma = 3, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_PHOENIX | 0x00012900, /* Guess */ + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5430_onboard_pci_device, + .snd_device = NULL, + .net_device = NULL + }, + + /* VLSI Wildcat */ + /* This has Phoenix KBC firmware. */ + { + .name = "[VLSI Wildcat] AT&T Globalyst 620/630 (NCR 3248/3348)", + .internal_name = "globalyst620", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_VLSI_WILDCAT, + .init = machine_at_globalyst620_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK(CPU_Cx6x86), + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_VIDEO, + .ram = { + .min = 4096, + .max = 196608, + .step = 4096 + }, + .nvrmask = 127, + .jumpered_ecp_dma = MACHINE_DMA_3, + .default_jumpered_ecp_dma = 3, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_PHOENIX | 0x00012900, /* Guess */ + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &s3_phoenix_trio64_onboard_pci_device, + .snd_device = NULL, + .net_device = NULL + }, + /* Socket 7 (Single Voltage) machines */ /* 430FX */ /* This has an AMIKey-2, which is type 'H'. @@ -13736,6 +14009,53 @@ const machine_t machines[] = { .net_device = NULL }, + /* VLSI Wildcat */ + /* KBC firmware is unknown. No PS/2 port is present and no commands outside */ + /* of the base AT KBC command set are used. */ + { + .name = "[VLSI Wildcat] Zeos Pantera Wildcat", + .internal_name = "zeoswildcat", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_VLSI_WILDCAT, + .init = machine_at_zeoswildcat_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK(CPU_Cx6x86, CPU_PENTIUMMMX), + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 3520, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 2.5 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM, + .ram = { + .min = 4096, + .max = 393216, + .step = 4096 + }, + .nvrmask = 127, + .jumpered_ecp_dma = MACHINE_DMA_3, + .default_jumpered_ecp_dma = 3, + .kbc_device = &kbc_at_device, + .kbc_params = 0x00000000, + .kbc_p1 = 0x000004f0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, + /* Socket 7 (Dual Voltage) machines */ /* ALi ALADDiN IV+ */ /* Has the ALi M1543 southbridge with on-chip KBC. */ diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 94520070e..6c32b1892 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -56,9 +56,22 @@ ad1848_log(const char *fmt, ...) static int ad1848_vols_7bits[128]; static double ad1848_vols_5bits_aux_gain[32]; -/* Borrowed from snd_sb_dsp */ -extern int8_t scaleMap4[64]; -extern uint8_t adjustMap4[64]; +/* Borrowed from ffmpeg. */ +static const int8_t adpcm_index_table[16] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 +}; +static const int16_t adpcm_step_table[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; void ad1848_setirq(ad1848_t *ad1848, int irq) @@ -311,6 +324,8 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 9: if (!ad1848->enable && (val & 0x41) == 0x01) { ad1848->adpcm_pos = 0; + ad1848->adpcm_predictor[0] = ad1848->adpcm_predictor[1] = 0; + ad1848->adpcm_step_index[0] = ad1848->adpcm_step_index[1] = 0; ad1848->dma_ff = 0; if (ad1848->timer_latch) timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch); @@ -358,6 +373,11 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) } break; + case 17: + if (val & 0x08) + ad1848->adpcm_predictor[0] = ad1848->adpcm_predictor[1] = 0; + break; + case 18 ... 19: if (ad1848->type >= AD1848_TYPE_CS4236B) { if (ad1848->type >= AD1848_TYPE_CS4235) { @@ -622,29 +642,33 @@ ad1848_dma_channel_read(ad1848_t *ad1848, int channel) } static int16_t -ad1848_process_adpcm(ad1848_t *ad1848) +ad1848_process_adpcm(ad1848_t *ad1848, int channel) { int temp; if (ad1848->adpcm_pos++ & 1) { - temp = (ad1848->adpcm_data & 0x0f) + ad1848->adpcm_step; + temp = ad1848->adpcm_data >> 4; } else { - ad1848->adpcm_data = (int) (ad1848_dma_channel_read(ad1848, ad1848->dma) & 0xffff); - temp = (ad1848->adpcm_data >> 4) + ad1848->adpcm_step; + ad1848->adpcm_data = ad1848_dma_channel_read(ad1848, ad1848->dma); + temp = ad1848->adpcm_data & 0x0f; } - if (temp < 0) - temp = 0; - else if (temp > 63) - temp = 63; - ad1848->adpcm_ref += scaleMap4[temp]; - if (ad1848->adpcm_ref > 0xff) - ad1848->adpcm_ref = 0xff; - else if (ad1848->adpcm_ref < 0x00) - ad1848->adpcm_ref = 0x00; + int step = adpcm_step_table[ad1848->adpcm_step_index[channel]]; + int step_index = ad1848->adpcm_step_index[channel] + adpcm_index_table[temp]; + if (step_index < 0) + step_index = 0; + else if (step_index > 88) + step_index = 88; - ad1848->adpcm_step = (int8_t) ((ad1848->adpcm_step + adjustMap4[temp]) & 0xff); + int diff = ((2 * (temp & 7) + 1) * step) >> 3; + int predictor = ad1848->adpcm_predictor[channel] + ((temp & 8) ? -diff : diff); + if (predictor < -32768) + predictor = -32768; + else if (predictor > 32767) + predictor = 32767; + ad1848->adpcm_predictor[channel] = predictor; + ad1848->adpcm_step_index[channel] = step_index; - return (int16_t) ((ad1848->adpcm_ref ^ 0x80) << 8); + return (int16_t) predictor; } static void @@ -705,12 +729,12 @@ ad1848_poll(void *priv) /* 0x80 and 0x90 reserved */ case 0xa0: /* Mono, 4-bit ADPCM */ - ad1848->out_l = ad1848->out_r = ad1848_process_adpcm(ad1848); + ad1848->out_l = ad1848->out_r = ad1848_process_adpcm(ad1848, 0); break; case 0xb0: /* Stereo, 4-bit ADPCM */ - ad1848->out_l = ad1848_process_adpcm(ad1848); - ad1848->out_r = ad1848_process_adpcm(ad1848); + ad1848->out_l = ad1848_process_adpcm(ad1848, 0); + ad1848->out_r = ad1848_process_adpcm(ad1848, 1); break; case 0xc0: /* Mono, 16-bit PCM big endian */ diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index f8c89c554..87243e8d9 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -82,8 +82,6 @@ typedef struct adgold_t { int treble; int bass; - int16_t samp_buffer[SOUNDBUFLEN * 2]; - int16_t opl_buffer[MUSICBUFLEN * 2]; int16_t mma_buffer[2][SOUNDBUFLEN]; int pos; @@ -779,30 +777,37 @@ static void adgold_get_buffer(int32_t *buffer, int len, void *priv) { adgold_t *adgold = (adgold_t *) priv; + int16_t *adgold_buffer = malloc(sizeof(int16_t) * len * 2); + if (adgold_buffer == NULL) + fatal("adgold_buffer = NULL"); + int c; + int32_t *opl_buf = adgold->opl.update(adgold->opl.priv); adgold_update(adgold); for (c = 0; c < len * 2; c += 2) { - adgold->samp_buffer[c] = ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4; - adgold->samp_buffer[c + 1] = ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; + adgold_buffer[c] = ((opl_buf[c] * adgold->fm_vol_l) >> 7) / 2; + adgold_buffer[c] += ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4; + adgold_buffer[c + 1] = ((opl_buf[c + 1] * adgold->fm_vol_r) >> 7) / 2; + adgold_buffer[c + 1] += ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; } if (adgold->surround_enabled) - ym7128_apply(&adgold->ym7128, adgold->samp_buffer, 0, len); + ym7128_apply(&adgold->ym7128, adgold_buffer, len); switch (adgold->adgold_38x_regs[0x8] & 6) { case 0: for (c = 0; c < len * 2; c++) - adgold->samp_buffer[c] = 0; + adgold_buffer[c] = 0; break; case 2: /*Left channel only*/ for (c = 0; c < len * 2; c += 2) - adgold->samp_buffer[c + 1] = adgold->samp_buffer[c]; + adgold_buffer[c + 1] = adgold_buffer[c]; break; case 4: /*Right channel only*/ for (c = 0; c < len * 2; c += 2) - adgold->samp_buffer[c] = adgold->samp_buffer[c + 1]; + adgold_buffer[c] = adgold_buffer[c + 1]; break; case 6: /*Left and right channels*/ break; @@ -814,7 +819,7 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) switch (adgold->adgold_38x_regs[0x8] & 0x18) { case 0x00: /*Forced mono*/ for (c = 0; c < len * 2; c += 2) - adgold->samp_buffer[c] = adgold->samp_buffer[c + 1] = ((int32_t) adgold->samp_buffer[c] + (int32_t) adgold->samp_buffer[c + 1]) / 2; + adgold_buffer[c] = adgold_buffer[c + 1] = ((int32_t) adgold_buffer[c] + (int32_t) adgold_buffer[c + 1]) / 2; break; case 0x08: /*Linear stereo*/ break; @@ -822,17 +827,17 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) /*Filter left channel, leave right channel unchanged*/ /*Filter cutoff is largely a guess*/ for (c = 0; c < len * 2; c += 2) - adgold->samp_buffer[c] += adgold_pseudo_stereo_iir(0, adgold->samp_buffer[c]); + adgold_buffer[c] += adgold_pseudo_stereo_iir(adgold_buffer[c]); break; case 0x18: /*Spatial stereo*/ /*Quite probably wrong, I only have the diagram in the TDA8425 datasheet and a very vague understanding of how op-amps work to go on*/ for (c = 0; c < len * 2; c += 2) { - int16_t l = adgold->samp_buffer[c]; - int16_t r = adgold->samp_buffer[c + 1]; + int16_t l = adgold_buffer[c]; + int16_t r = adgold_buffer[c + 1]; - adgold->samp_buffer[c] += (r / 3) + ((l * 2) / 3); - adgold->samp_buffer[c + 1] += (l / 3) + ((r * 2) / 3); + adgold_buffer[c] += (r / 3) + ((l * 2) / 3); + adgold_buffer[c + 1] += (l / 3) + ((r * 2) / 3); } break; @@ -846,9 +851,9 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) int32_t highpass; /*Output is deliberately halved to avoid clipping*/ - temp = ((int32_t) adgold->samp_buffer[c] * adgold->vol_l) >> 17; - lowpass = adgold_lowpass_iir(0, 0, temp); - highpass = adgold_highpass_iir(0, 0, temp); + temp = ((int32_t) adgold_buffer[c] * adgold->vol_l) >> 17; + lowpass = adgold_lowpass_iir(0, temp); + highpass = adgold_highpass_iir(0, temp); if (adgold->bass > 6) temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; else if (adgold->bass < 6) @@ -863,118 +868,9 @@ adgold_get_buffer(int32_t *buffer, int len, void *priv) temp = 32767; buffer[c] += temp; - temp = ((int32_t) adgold->samp_buffer[c + 1] * adgold->vol_r) >> 17; - lowpass = adgold_lowpass_iir(0, 1, temp); - highpass = adgold_highpass_iir(0, 1, temp); - if (adgold->bass > 6) - temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; - else if (adgold->bass < 6) - temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); - if (adgold->treble > 6) - temp += (highpass * treble_attenuation[adgold->treble]) >> 14; - else if (adgold->treble < 6) - temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); - if (temp < -32768) - temp = -32768; - if (temp > 32767) - temp = 32767; - buffer[c + 1] += temp; - } - - adgold->pos = 0; -} - -static void -adgold_get_music_buffer(int32_t *buffer, int len, void *priv) -{ - adgold_t *adgold = (adgold_t *) priv; - int c; - - const int32_t *opl_buf = adgold->opl.update(adgold->opl.priv); - - for (c = 0; c < len * 2; c += 2) { - adgold->opl_buffer[c] = ((opl_buf[c] * adgold->fm_vol_l) >> 7) / 2; - adgold->opl_buffer[c + 1] = ((opl_buf[c + 1] * adgold->fm_vol_r) >> 7) / 2; - } - - if (adgold->surround_enabled) - ym7128_apply(&adgold->ym7128, adgold->opl_buffer, 1, len); - - switch (adgold->adgold_38x_regs[0x8] & 6) { - case 0: - for (c = 0; c < len * 2; c++) - adgold->opl_buffer[c] = 0; - break; - case 2: /*Left channel only*/ - for (c = 0; c < len * 2; c += 2) - adgold->opl_buffer[c + 1] = adgold->opl_buffer[c]; - break; - case 4: /*Right channel only*/ - for (c = 0; c < len * 2; c += 2) - adgold->opl_buffer[c] = adgold->opl_buffer[c + 1]; - break; - case 6: /*Left and right channels*/ - break; - - default: - break; - } - - switch (adgold->adgold_38x_regs[0x8] & 0x18) { - case 0x00: /*Forced mono*/ - for (c = 0; c < len * 2; c += 2) - adgold->opl_buffer[c] = adgold->opl_buffer[c + 1] = ((int32_t) adgold->opl_buffer[c] + (int32_t) adgold->opl_buffer[c + 1]) / 2; - break; - case 0x08: /*Linear stereo*/ - break; - case 0x10: /*Pseudo stereo*/ - /*Filter left channel, leave right channel unchanged*/ - /*Filter cutoff is largely a guess*/ - for (c = 0; c < len * 2; c += 2) - adgold->opl_buffer[c] += adgold_pseudo_stereo_iir(1, adgold->opl_buffer[c]); - break; - case 0x18: /*Spatial stereo*/ - /*Quite probably wrong, I only have the diagram in the TDA8425 datasheet - and a very vague understanding of how op-amps work to go on*/ - for (c = 0; c < len * 2; c += 2) { - int16_t l = adgold->opl_buffer[c]; - int16_t r = adgold->opl_buffer[c + 1]; - - adgold->opl_buffer[c] += (r / 3) + ((l * 2) / 3); - adgold->opl_buffer[c + 1] += (l / 3) + ((r * 2) / 3); - } - break; - - default: - break; - } - - for (c = 0; c < len * 2; c += 2) { - int32_t temp; - int32_t lowpass; - int32_t highpass; - - /*Output is deliberately halved to avoid clipping*/ - temp = ((int32_t) adgold->opl_buffer[c] * adgold->vol_l) >> 17; - lowpass = adgold_lowpass_iir(1, 0, temp); - highpass = adgold_highpass_iir(1, 0, temp); - if (adgold->bass > 6) - temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; - else if (adgold->bass < 6) - temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); - if (adgold->treble > 6) - temp += (highpass * treble_attenuation[adgold->treble]) >> 14; - else if (adgold->treble < 6) - temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); - if (temp < -32768) - temp = -32768; - if (temp > 32767) - temp = 32767; - buffer[c] += temp; - - temp = ((int32_t) adgold->opl_buffer[c + 1] * adgold->vol_r) >> 17; - lowpass = adgold_lowpass_iir(1, 1, temp); - highpass = adgold_highpass_iir(1, 1, temp); + temp = ((int32_t) adgold_buffer[c + 1] * adgold->vol_r) >> 17; + lowpass = adgold_lowpass_iir(1, temp); + highpass = adgold_highpass_iir(1, temp); if (adgold->bass > 6) temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; else if (adgold->bass < 6) @@ -991,6 +887,9 @@ adgold_get_music_buffer(int32_t *buffer, int len, void *priv) } adgold->opl.reset_buffer(adgold->opl.priv); + adgold->pos = 0; + + free(adgold_buffer); } static void @@ -1058,7 +957,7 @@ adgold_init(UNUSED(const device_t *info)) adgold->surround_enabled = device_get_config_int("surround"); adgold->gameport_enabled = device_get_config_int("gameport"); - fm_driver_get(FM_YMF289B, &adgold->opl); + fm_driver_get_ex(FM_YMF262, &adgold->opl, 1); if (adgold->surround_enabled) ym7128_init(&adgold->ym7128); @@ -1149,7 +1048,6 @@ adgold_init(UNUSED(const device_t *info)) timer_add(&adgold->adgold_mma_timer_count, adgold_timer_poll, adgold, 1); sound_add_handler(adgold_get_buffer, adgold); - music_add_handler(adgold_get_music_buffer, adgold); sound_set_cd_audio_filter(adgold_filter_cd_audio, adgold); diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index 1ee687f1e..6bbd634a7 100644 --- a/src/sound/snd_opl.c +++ b/src/sound/snd_opl.c @@ -36,150 +36,152 @@ static uint32_t fm_dev_inst[FM_DRV_MAX][FM_MAX]; uint8_t -fm_driver_get(int chip_id, fm_drv_t *drv) +fm_driver_get_ex(int chip_id, fm_drv_t *drv, int is_48k) { + void *flag_48k = is_48k ? ((void *) FM_FORCE_48K) : NULL; + switch (chip_id) { case FM_YM2149: /* SSG */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2149_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2149_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM3526: /* OPL */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym3526_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym3526_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_Y8950: /* MSX-Audio (OPL with ADPCM) */ *drv = ymfm_drv; - drv->priv = device_add_inst(&y8950_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&y8950_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM3812: /* OPL2 */ if (fm_driver == FM_DRV_NUKED) { - *drv = nuked_opl_drv; - drv->priv = device_add_inst(&ym3812_nuked_device, fm_dev_inst[fm_driver][chip_id]++); + *drv = is_48k ? nuked_opl_drv_48k : nuked_opl_drv; + drv->priv = device_add_inst_params(&ym3812_nuked_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); } else { *drv = ymfm_drv; - drv->priv = device_add_inst(&ym3812_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym3812_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); } break; case FM_YMF262: /* OPL3 */ if (fm_driver == FM_DRV_NUKED) { - *drv = nuked_opl_drv; - drv->priv = device_add_inst(&ymf262_nuked_device, fm_dev_inst[fm_driver][chip_id]++); + *drv = is_48k ? nuked_opl_drv_48k : nuked_opl_drv; + drv->priv = device_add_inst_params(&ymf262_nuked_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); } else { *drv = ymfm_drv; - drv->priv = device_add_inst(&ymf262_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ymf262_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); } break; case FM_YMF289B: /* OPL3-L */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ymf289b_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ymf289b_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YMF278B: /* OPL4 */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ymf278b_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ymf278b_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM2413: /* OPLL */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2413_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2413_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM2423: /* OPLL-X */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2423_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2423_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YMF281: /* OPLLP */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ymf281_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ymf281_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_DS1001: /* Konami VRC7 MMC */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ds1001_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ds1001_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM2151: /* OPM */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2151_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2151_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM2203: /* OPN */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2203_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2203_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM2608: /* OPNA */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2608_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2608_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YMF288: /* OPN3L */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ymf288_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ymf288_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM2610: /* OPNB */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2610_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2610_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM2610B: /* OPNB2 */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2610b_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2610b_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM2612: /* OPN2 */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2612_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2612_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM3438: /* OPN2C */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym3438_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym3438_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YMF276: /* OPN2L */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ymf276_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ymf276_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM2164: /* OPP */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2164_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2164_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_YM3806: /* OPQ */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym3806_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym3806_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; #if 0 case FM_YMF271: /* OPX */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ymf271_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ymf271_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; #endif case FM_YM2414: /* OPZ */ *drv = ymfm_drv; - drv->priv = device_add_inst(&ym2414_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym2414_ymfm_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; case FM_ESFM: *drv = esfmu_opl_drv; - drv->priv = device_add_inst(&esfm_esfmu_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&esfm_esfmu_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; #ifdef USE_LIBSERIALPORT case FM_OPL2BOARD: *drv = ymfm_opl2board_drv; - drv->priv = device_add_inst(&ym_opl2board_device, fm_dev_inst[fm_driver][chip_id]++); + drv->priv = device_add_inst_params(&ym_opl2board_device, fm_dev_inst[fm_driver][chip_id]++, flag_48k); break; #endif @@ -189,3 +191,9 @@ fm_driver_get(int chip_id, fm_drv_t *drv) return 1; }; + +uint8_t +fm_driver_get(int chip_id, fm_drv_t *drv) +{ + return fm_driver_get_ex(chip_id, drv, 0); +} diff --git a/src/sound/snd_opl_nuked.c b/src/sound/snd_opl_nuked.c index 60f5ed2a6..a69b2e758 100644 --- a/src/sound/snd_opl_nuked.c +++ b/src/sound/snd_opl_nuked.c @@ -1460,6 +1460,15 @@ OPL3_GenerateStream(opl3_chip *chip, int32_t *sndptr, uint32_t numsamples) } } +void +OPL3_GenerateResampledStream(opl3_chip *chip, int32_t *sndptr, uint32_t numsamples) +{ + for (uint_fast32_t i = 0; i < numsamples; i++) { + OPL3_GenerateResampled(chip, sndptr); + sndptr += 2; + } +} + static void nuked_timer_tick(nuked_drv_t *dev, int tmr) { @@ -1525,32 +1534,6 @@ nuked_drv_set_do_cycles(void *priv, int8_t do_cycles) dev->flags &= ~FLAG_CYCLES; } -static void * -nuked_drv_init(const device_t *info) -{ - nuked_drv_t *dev = (nuked_drv_t *) calloc(1, sizeof(nuked_drv_t)); - dev->flags = FLAG_CYCLES; - if (info->local == FM_YMF262) - dev->flags |= FLAG_OPL3; - else - dev->status = 0x06; - - /* Initialize the NukedOPL object. */ - OPL3_Reset(&dev->opl, FREQ_49716); - - timer_add(&dev->timers[0], nuked_timer_1, dev, 0); - timer_add(&dev->timers[1], nuked_timer_2, dev, 0); - - return dev; -} - -static void -nuked_drv_close(void *priv) -{ - nuked_drv_t *dev = (nuked_drv_t *) priv; - free(dev); -} - static int32_t * nuked_drv_update(void *priv) { @@ -1560,8 +1543,8 @@ nuked_drv_update(void *priv) return dev->buffer; OPL3_GenerateStream(&dev->opl, - &dev->buffer[dev->pos * 2], - music_pos_global - dev->pos); + &dev->buffer[dev->pos * 2], + music_pos_global - dev->pos); for (; dev->pos < music_pos_global; dev->pos++) { dev->buffer[dev->pos * 2] /= 2; @@ -1571,6 +1554,26 @@ nuked_drv_update(void *priv) return dev->buffer; } +static int32_t * +nuked_drv_update_48k(void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *) priv; + + if (dev->pos >= sound_pos_global) + return dev->buffer; + + OPL3_GenerateResampledStream(&dev->opl, + &dev->buffer[dev->pos * 2], + sound_pos_global - dev->pos); + + for (; dev->pos < sound_pos_global; dev->pos++) { + dev->buffer[dev->pos * 2] /= 2; + dev->buffer[(dev->pos * 2) + 1] /= 2; + } + + return dev->buffer; +} + static uint8_t nuked_drv_read(uint16_t port, void *priv) { @@ -1579,7 +1582,7 @@ nuked_drv_read(uint16_t port, void *priv) if (dev->flags & FLAG_CYCLES) cycles -= ((int) (isa_timing * 8)); - nuked_drv_update(dev); + dev->update(dev); uint8_t ret = 0xff; @@ -1598,7 +1601,8 @@ static void nuked_drv_write(uint16_t port, uint8_t val, void *priv) { nuked_drv_t *dev = (nuked_drv_t *) priv; - nuked_drv_update(dev); + + dev->update(dev); if ((port & 0x0001) == 0x0001) { OPL3_WriteRegBuffered(&dev->opl, dev->port, val); @@ -1649,6 +1653,40 @@ nuked_drv_reset_buffer(void *priv) dev->pos = 0; } +static void +nuked_drv_close(void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *) priv; + free(dev); +} + +static void * +nuked_drv_init(const device_t *info) +{ + nuked_drv_t *dev = (nuked_drv_t *) calloc(1, sizeof(nuked_drv_t)); + dev->flags = FLAG_CYCLES; + if ((info->local & FM_TYPE_MASK) == FM_YMF262) + dev->flags |= FLAG_OPL3; + else + dev->status = 0x06; + + dev->is_48k = !!(info->local & FM_FORCE_48K); + + /* Initialize the NukedOPL object. */ + if (dev->is_48k) { + dev->update = nuked_drv_update_48k; + OPL3_Reset(&dev->opl, FREQ_48000); + } else { + dev->update = nuked_drv_update; + OPL3_Reset(&dev->opl, FREQ_49716); + } + + timer_add(&dev->timers[0], nuked_timer_1, dev, 0); + timer_add(&dev->timers[1], nuked_timer_2, dev, 0); + + return dev; +} + const device_t ym3812_nuked_device = { .name = "Yamaha YM3812 OPL2 (NUKED)", .internal_name = "ym3812_nuked", @@ -1686,3 +1724,13 @@ const fm_drv_t nuked_opl_drv = { .priv = NULL, .generate = NULL, }; + +const fm_drv_t nuked_opl_drv_48k = { + .read = &nuked_drv_read, + .write = &nuked_drv_write, + .update = &nuked_drv_update_48k, + .reset_buffer = &nuked_drv_reset_buffer, + .set_do_cycles = &nuked_drv_set_do_cycles, + .priv = NULL, + .generate = NULL, +}; diff --git a/src/sound/snd_opl_ymfm.cpp b/src/sound/snd_opl_ymfm.cpp index 815b6cb4b..37363aa74 100644 --- a/src/sound/snd_opl_ymfm.cpp +++ b/src/sound/snd_opl_ymfm.cpp @@ -56,11 +56,12 @@ enum { class YMFMChipBase { public: - YMFMChipBase(UNUSED(uint32_t clock), fm_type type, uint32_t samplerate) + YMFMChipBase(UNUSED(uint32_t clock), fm_type type, uint32_t samplerate, int is_48k) : m_buf_pos(0) , m_flags(0) , m_type(type) , m_samplerate(samplerate) + , m_48k(is_48k) { memset(m_buffer, 0, sizeof(m_buffer)); } @@ -74,11 +75,13 @@ public: void set_do_cycles(int8_t do_cycles) { do_cycles ? m_flags |= FLAG_CYCLES : m_flags &= ~FLAG_CYCLES; } int32_t *buffer() const { return (int32_t *) m_buffer; } void reset_buffer() { m_buf_pos = 0; } + int is_48k() const { return m_48k; } virtual uint32_t sample_rate() const = 0; virtual void write(uint16_t addr, uint8_t data) = 0; virtual void generate(int32_t *data, uint32_t num_samples) = 0; + virtual void generate_resampled(int32_t *data, uint32_t num_samples) = 0; virtual int32_t *update() = 0; virtual uint8_t read(uint16_t addr) = 0; virtual void set_clock(uint32_t clock) = 0; @@ -90,17 +93,19 @@ protected: int8_t m_flags; fm_type m_type; uint32_t m_samplerate; + int m_48k; }; template class YMFMChip : public YMFMChipBase, public ymfm::ymfm_interface { public: - YMFMChip(uint32_t clock, fm_type type, uint32_t samplerate) - : YMFMChipBase(clock, type, samplerate) + YMFMChip(uint32_t clock, fm_type type, uint32_t samplerate, int m_48k) + : YMFMChipBase(clock, type, samplerate, m_48k) , m_chip(*this) , m_clock(clock) , m_samplerate(samplerate) , m_samplecnt(0) + , m_48k(0) { memset(m_samples, 0, sizeof(m_samples)); memset(m_oldsamples, 0, sizeof(m_oldsamples)); @@ -109,7 +114,10 @@ public: m_subtract[0] = 80.0; m_subtract[1] = 320.0; m_type = type; - m_buf_pos_global = (samplerate == FREQ_49716) ? &music_pos_global : &wavetable_pos_global; + if (m_48k) + m_buf_pos_global = &sound_pos_global; + else + m_buf_pos_global = (samplerate == FREQ_49716) ? &music_pos_global : &wavetable_pos_global; if (m_type == FM_YMF278B) { if (rom_load_linear("roms/sound/yamaha/yrw801.rom", 0, 0x200000, 0, m_yrw801) == 0) { @@ -176,14 +184,8 @@ public: } } -#if 0 virtual void generate_resampled(int32_t *data, uint32_t num_samples) override { - if ((m_samplerate == FREQ_49716) || (m_samplerate == FREQ_44100)) { - generate(data, num_samples); - return; - } - for (uint32_t i = 0; i < num_samples; i++) { while (m_samplecnt >= m_rateratio) { m_oldsamples[0] = m_samples[0]; @@ -217,14 +219,16 @@ public: m_samplecnt += 1 << RSM_FRAC; } } -#endif virtual int32_t *update() override { if (m_buf_pos >= *m_buf_pos_global) return m_buffer; - generate(&m_buffer[m_buf_pos * 2], *m_buf_pos_global - m_buf_pos); + if (m_48k) + generate_resampled(&m_buffer[m_buf_pos * 2], *m_buf_pos_global - m_buf_pos); + else + generate(&m_buffer[m_buf_pos * 2], *m_buf_pos_global - m_buf_pos); for (; m_buf_pos < *m_buf_pos_global; m_buf_pos++) { m_buffer[m_buf_pos * 2] /= 2; @@ -287,6 +291,8 @@ private: int32_t m_samplecnt; int32_t m_oldsamples[2]; int32_t m_samples[2]; + + int m_48k; }; extern "C" { @@ -325,127 +331,128 @@ static void * ymfm_drv_init(const device_t *info) { YMFMChipBase *fm; + int is_48k = !!(info->local & FM_FORCE_48K); - switch (info->local) { + switch (info->local & FM_TYPE_MASK) { case FM_YM2149: /* OPL */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2149, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2149, FREQ_49716, is_48k); break; case FM_YM3526: /* OPL */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM3526, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM3526, FREQ_49716, is_48k); break; case FM_Y8950: /* MSX-Audio (OPL with ADPCM) */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_Y8950, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_Y8950, FREQ_49716, is_48k); break; default: case FM_YM3812: /* OPL2 */ - fm = (YMFMChipBase *) new YMFMChip(3579545, FM_YM3812, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(3579545, FM_YM3812, FREQ_49716, is_48k); break; case FM_YMF262: /* OPL3 */ - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF262, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF262, FREQ_49716, is_48k); break; case FM_YMF289B: /* OPL3-L */ /* According to the datasheet, we should be using 33868800, but YMFM appears to cheat and does it using the same values as the YMF262. */ - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF289B, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF289B, FREQ_49716, is_48k); break; case FM_YMF278B: /* OPL4 */ - fm = (YMFMChipBase *) new YMFMChip(33868800, FM_YMF278B, FREQ_44100); + fm = (YMFMChipBase *) new YMFMChip(33868800, FM_YMF278B, FREQ_44100, is_48k); break; case FM_YM2413: /* OPLL */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2413, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2413, FREQ_49716, is_48k); break; case FM_YM2423: /* OPLL-X */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2423, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2423, FREQ_49716, is_48k); break; case FM_YMF281: /* OPLLP */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF281, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF281, FREQ_49716, is_48k); break; case FM_DS1001: /* Konami VRC7 MMC */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_DS1001, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_DS1001, FREQ_49716, is_48k); break; case FM_YM2151: /* OPM */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2151, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2151, FREQ_49716, is_48k); break; case FM_YM2203: /* OPN */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2203, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2203, FREQ_49716, is_48k); break; case FM_YM2608: /* OPNA */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2608, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2608, FREQ_49716, is_48k); break; case FM_YMF288: /* OPN3L */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF288, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF288, FREQ_49716, is_48k); break; case FM_YM2610: /* OPNB */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2610, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2610, FREQ_49716, is_48k); break; case FM_YM2610B: /* OPNB2 */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2610B, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2610B, FREQ_49716, is_48k); break; case FM_YM2612: /* OPN2 */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2612, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2612, FREQ_49716, is_48k); break; case FM_YM3438: /* OPN2C */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM3438, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM3438, FREQ_49716, is_48k); break; case FM_YMF276: /* OPN2L */ // TODO: Check function call, rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF276, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF276, FREQ_49716, is_48k); break; case FM_YM2164: /* OPP */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2164, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2164, FREQ_49716, is_48k); break; case FM_YM3806: /* OPQ */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM3806, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM3806, FREQ_49716, is_48k); break; #if 0 case FM_YMF271: /* OPX */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF271, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF271, FREQ_49716, is_48k); break; #endif case FM_YM2414: /* OPZ */ // TODO: Check rates and frequency - fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2414, FREQ_49716); + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YM2414, FREQ_49716, is_48k); break; } @@ -523,8 +530,10 @@ ymfm_drv_generate(void *priv, int32_t *data, uint32_t num_samples) { YMFMChipBase *drv = (YMFMChipBase *) priv; - // drv->generate_resampled(data, num_samples); - drv->generate(data, num_samples); + if (drv->is_48k()) + drv->generate_resampled(data, num_samples); + else + drv->generate(data, num_samples); } const device_t ym2149_ymfm_device = { diff --git a/src/sound/snd_ym7128.c b/src/sound/snd_ym7128.c index 08b33f414..59e5691e9 100644 --- a/src/sound/snd_ym7128.c +++ b/src/sound/snd_ym7128.c @@ -111,10 +111,10 @@ ym7128_write(ym7128_t *ym7128, uint8_t val) ym7128->a0 = new_a0; } -#define GET_DELAY_SAMPLE(ym7128, offset) (((ym7128->delay_pos[i] - offset) < 0) ? ym7128->delay_buffer[i][(ym7128->delay_pos[i] - offset) + 2400] : ym7128->delay_buffer[i][ym7128->delay_pos[i] - offset]) +#define GET_DELAY_SAMPLE(ym7128, offset) (((ym7128->delay_pos - offset) < 0) ? ym7128->delay_buffer[(ym7128->delay_pos - offset) + 2400] : ym7128->delay_buffer[ym7128->delay_pos - offset]) void -ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int i, int len) +ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len) { for (int c = 0; c < len * 2; c += 4) { /*YM7128 samples a mono stream at ~24 kHz, so downsample*/ @@ -125,13 +125,13 @@ ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int i, int len) int32_t samp_r = 0; filter_temp = GET_DELAY_SAMPLE(ym7128, ym7128->t[0]); - filter_out = ((filter_temp * ym7128->c0) >> 11) + ((ym7128->filter_dat[i] * ym7128->c1) >> 11); + filter_out = ((filter_temp * ym7128->c0) >> 11) + ((ym7128->filter_dat * ym7128->c1) >> 11); filter_out = (filter_out * ym7128->vc) >> 16; samp = (samp * ym7128->vm) >> 16; samp += filter_out; - ym7128->delay_buffer[i][ym7128->delay_pos[i]] = samp; + ym7128->delay_buffer[ym7128->delay_pos] = samp; for (uint8_t d = 0; d < 8; d++) { samp_l += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d + 1]) * ym7128->gl[d]) >> 16; @@ -141,17 +141,17 @@ ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int i, int len) samp_l = (samp_l * ym7128->vl * 2) >> 16; samp_r = (samp_r * ym7128->vr * 2) >> 16; - buffer[c] += (samp_l + (int32_t) ym7128->prev_l[i]) / 2; - buffer[c + 1] += (samp_r + (int32_t) ym7128->prev_r[i]) / 2; + buffer[c] += (samp_l + (int32_t) ym7128->prev_l) / 2; + buffer[c + 1] += (samp_r + (int32_t) ym7128->prev_r) / 2; buffer[c + 2] += samp_l; buffer[c + 3] += samp_r; - ym7128->delay_pos[i]++; - if (ym7128->delay_pos[i] >= 2400) - ym7128->delay_pos[i] = 0; + ym7128->delay_pos++; + if (ym7128->delay_pos >= 2400) + ym7128->delay_pos = 0; - ym7128->filter_dat[i] = filter_temp; - ym7128->prev_l[i] = samp_l; - ym7128->prev_r[i] = samp_r; + ym7128->filter_dat = filter_temp; + ym7128->prev_l = samp_l; + ym7128->prev_r = samp_r; } } diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index ac96aedef..8a139793c 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -1967,9 +1967,9 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) if (val & 0x800) virge->streams.k1_horiz_scale |= ~0x7ff; - virge->streams.k2_horiz_scale = (val >> 16) & 0x7ff; - if ((val >> 16) & 0x800) - virge->streams.k2_horiz_scale |= ~0x7ff; + virge->streams.k2_horiz_scale = (val >> 16) & 0x3ff; + if ((val >> 16) & 0x400) + virge->streams.k2_horiz_scale |= ~0x3ff; svga_recalctimings(svga); svga->fullchange = changeframecount; @@ -2025,9 +2025,9 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) virge->streams.k1_vert_scale |= ~0x7ff; break; case 0x81e4: - virge->streams.k2_vert_scale = val & 0x7ff; - if (val & 0x800) - virge->streams.k2_vert_scale |= ~0x7ff; + virge->streams.k2_vert_scale = val & 0x3ff; + if (val & 0x400) + virge->streams.k2_vert_scale |= ~0x3ff; break; case 0x81e8: virge->streams.dda_vert_accumulator = val & 0x7ff;