From 756e1dfc83ddaeba3118a628485d3f87f7c15c96 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 May 2021 00:30:56 -0300 Subject: [PATCH 01/25] Fix quaternary IDE PnP ROM --- src/disk/hdc_ide.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index d8bbb9762..6953bda83 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -168,8 +168,8 @@ static uint8_t ide_qua_pnp_rom[] = { 0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */ 0x30, /* start dependent functions, acceptable */ 0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */ - 0x47, 0x01, 0x68, 0x01, 0x68, 0x01, 0x01, 0x08, /* I/O 0x168, decodes 16-bit, 1-byte alignment, 8 addresses */ - 0x47, 0x01, 0x6e, 0x03, 0x6e, 0x03, 0x01, 0x01, /* I/O 0x36E, decodes 16-bit, 1-byte alignment, 1 address */ + 0x47, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x01, 0x08, /* I/O 0x1E8, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */ 0x30, /* start dependent functions, acceptable */ 0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */ 0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ From 1ba56e268198aa3ffda190c3aefb19adc1528c4c Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 19 May 2021 00:46:15 -0300 Subject: [PATCH 02/25] Crystal CS4237, part 1 --- src/include/86box/snd_ad1848.h | 1 + src/include/86box/snd_sb.h | 3 + src/include/86box/sound.h | 6 +- src/sound/snd_ad1848.c | 20 +- src/sound/snd_cs423x.c | 467 +++++++++++++++++++++++++++++++++ src/sound/snd_sb.c | 36 +++ src/sound/sound.c | 1 + src/win/Makefile.mingw | 2 +- 8 files changed, 529 insertions(+), 7 deletions(-) create mode 100644 src/sound/snd_cs423x.c diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index b6782c139..a25e46951 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -1,6 +1,7 @@ #define AD1848_TYPE_DEFAULT 0 #define AD1848_TYPE_CS4248 1 #define AD1848_TYPE_CS4231 2 +#define AD1848_TYPE_CS4236 3 typedef struct ad1848_t { diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 3bb2a6496..8195345df 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -134,6 +134,9 @@ extern void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p); extern uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p); extern void sb_ct1345_mixer_reset(sb_t* sb); +extern uint8_t sb_pro_v1_opl_read(uint16_t port, void *priv); +extern void sb_pro_v1_opl_write(uint16_t port, uint8_t val, void *priv); + extern void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p); extern void sbpro_filter_cd_audio(int channel, double *buffer, void *p); extern void sb_close(void *p); diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index 00ce1fb95..af10917e0 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -99,7 +99,7 @@ extern const device_t gus_device; extern const device_t pas16_device; #endif -/* PSSJ - What is this device? */ +/* Tandy PSSJ */ extern const device_t pssj_device; /* Creative Labs Sound Blaster */ @@ -110,6 +110,7 @@ extern const device_t sb_2_device; extern const device_t sb_pro_v1_device; extern const device_t sb_pro_v2_device; extern const device_t sb_pro_mcv_device; +extern const device_t sb_pro_cs423x_device; extern const device_t sb_16_device; extern const device_t sb_16_pnp_device; extern const device_t sb_32_pnp_device; @@ -122,6 +123,9 @@ extern const device_t ssi2001_device; /* Windows Sound System */ extern const device_t wss_device; extern const device_t ncr_business_audio_device; + +/* Crystal CS423x */ +extern const device_t cs4237b_device; #endif #endif /*EMU_SOUND_H*/ diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index fc859f8cc..c45d69063 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -14,6 +14,7 @@ #include <86box/snd_ad1848.h> #define CS4231 0x80 +#define CS4236 0x03 static int ad1848_vols_6bits[64]; static double ad1848_vols_5bits_aux_gain[32]; @@ -59,7 +60,7 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) switch (addr & 3) { case 0: /*Index*/ - if ((ad1848->regs[12] & 0x40) && (ad1848->type == AD1848_TYPE_CS4231)) + if ((ad1848->regs[12] & 0x40) && (ad1848->type >= AD1848_TYPE_CS4231)) ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ else ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ @@ -247,15 +248,14 @@ void ad1848_init(ad1848_t *ad1848, int type) ad1848->regs[8] = 0; ad1848->regs[9] = 0x08; ad1848->regs[10] = ad1848->regs[11] = 0; - if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231)) + if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type == AD1848_TYPE_CS4236)) ad1848->regs[12] = 0x8a; else ad1848->regs[12] = 0xa; ad1848->regs[13] = 0; ad1848->regs[14] = ad1848->regs[15] = 0; - if (type == AD1848_TYPE_CS4231) - { + if (type == AD1848_TYPE_CS4231) { ad1848->regs[16] = ad1848->regs[17] = 0; ad1848->regs[18] = ad1848->regs[19] = 0x88; ad1848->regs[22] = 0x80; @@ -263,7 +263,17 @@ void ad1848_init(ad1848_t *ad1848, int type) ad1848->regs[25] = CS4231; ad1848->regs[26] = 0x80; ad1848->regs[29] = 0x80; - } + } else if (type == AD1848_TYPE_CS4236) { + ad1848->regs[16] = ad1848->regs[17] = 0; + ad1848->regs[18] = ad1848->regs[19] = 0; + ad1848->regs[20] = ad1848->regs[21] = 0; + ad1848->regs[22] = ad1848->regs[23] = 0; + ad1848->regs[24] = 0; + ad1848->regs[25] = CS4236; + ad1848->regs[26] = 0xa0; + ad1848->regs[27] = ad1848->regs[29] = 0; + ad1848->regs[30] = ad1848->regs[31] = 0; + } ad1848->out_l = 0; ad1848->out_r = 0; diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c new file mode 100644 index 000000000..6456d5a8d --- /dev/null +++ b/src/sound/snd_cs423x.c @@ -0,0 +1,467 @@ +/* + * 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. + * + * Crystal CS423x (SBPro/WSS compatible sound chips) emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2021 RichardG. + */ +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/pic.h> +#include <86box/dma.h> +#include <86box/device.h> +#include <86box/i2c.h> +#include <86box/isapnp.h> +#include <86box/sound.h> +#include <86box/midi.h> +#include <86box/snd_ad1848.h> +#include <86box/snd_opl.h> +#include <86box/snd_sb.h> + + +enum { + CRYSTAL_CS4237B = 37 +}; + + +static const uint8_t cs4237b_eeprom[384] = { + 0x55, 0xbb, 0x00, 0x00, 0x00, 0x03, 0x80, 0x80, 0x0b, 0x20, 0x04, 0x08, 0x10, 0x80, 0x00, 0x00, 0x00, 0x48, 0x75, 0xb9, 0xfc, 0x10, 0x03, /* CS4237B stuff */ + + 0x0e, 0x63, 0x42, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, /* CSC4237, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x01, /* PnP version 1.0, vendor version 0.1 */ + 0x82, 0x0e, 0x00, 'C', 'r', 'y', 's', 't', 'a', 'l', ' ', 'C', 'o', 'd', 'e' ,'c', 0x00, /* ANSI identifier */ + + 0x15, 0x0e, 0x63, 0x00, 0x00, 0x00, /* logical device CSC0000 */ + 0x82, 0x07, 0x00, 'W', 'S', 'S', '/', 'S', 'B', 0x00, /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x2a, 0x02, 0x28, /* DMA 1, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x2a, 0x09, 0x28, /* DMA 0/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x22, 0x20, 0x00, /* IRQ 5 */ + 0x47, 0x01, 0x34, 0x05, 0x34, 0x05, 0x04, 0x04, /* I/O 0x534, decodes 16-bit, 4-byte alignment, 4 addresses */ + 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x08, 0x04, /* I/O 0x388, decodes 16-bit, 8-byte alignment, 4 addresses */ + 0x47, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x10, /* I/O 0x220, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x2a, 0x0a, 0x28, /* DMA 1/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x2a, 0x0b, 0x28, /* DMA 0/1/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x22, 0xa0, 0x9a, /* IRQ 5/7/9/11/12/15 */ + 0x47, 0x01, 0x34, 0x05, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x534-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */ + 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x08, 0x04, /* I/O 0x388, decodes 16-bit, 8-byte alignment, 4 addresses */ + 0x47, 0x01, 0x20, 0x02, 0x60, 0x02, 0x20, 0x10, /* I/O 0x220-0x260, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x31, 0x02, /* start dependent functions, sub-optimal */ + 0x2a, 0x0b, 0x28, /* DMA 0/1/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x22, 0xa0, 0x9a, /* IRQ 5/7/9/11/12/15 */ + 0x47, 0x01, 0x34, 0x05, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x534-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */ + 0x47, 0x01, 0x88, 0x03, 0xf8, 0x03, 0x08, 0x04, /* I/O 0x388-0x3F8, decodes 16-bit, 8-byte alignment, 4 addresses */ + 0x47, 0x01, 0x20, 0x02, 0x00, 0x03, 0x20, 0x10, /* I/O 0x220-0x300, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x38, /* end dependent functions */ +#if 0 + 0x15, 0x0e, 0x63, 0x00, 0x01, 0x00, /* logical device CSC0001 */ + 0x82, 0x05, 0x00, 'G', 'A', 'M', 'E', 0x00, /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x38, /* end dependent functions */ +#endif + 0x15, 0x0e, 0x63, 0x00, 0x10, 0x00, /* logical device CSC0010 */ + 0x82, 0x05, 0x00, 'C', 'T', 'R', 'L', 0x00, /* ANSI identifier */ + 0x47, 0x01, 0x20, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x120-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x0e, 0x63, 0x00, 0x03, 0x00, /* logical device CSC0003 */ + 0x82, 0x04, 0x00, 'M', 'P', 'U', 0x00, /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x22, 0x00, 0x02, /* IRQ 9 */ + 0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x08, 0x02, /* I/O 0x330, decodes 16-bit, 8-byte alignment, 2 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x22, 0x00, 0x9a, /* IRQ 9/11/12/15 */ + 0x47, 0x01, 0x30, 0x03, 0x60, 0x03, 0x08, 0x02, /* I/O 0x330-0x360, decodes 16-bit, 8-byte alignment, 2 addresses */ + 0x31, 0x02, /* start dependent functions, sub-optimal */ + 0x47, 0x01, 0x30, 0x03, 0xe0, 0x03, 0x08, 0x02, /* I/O 0x330-0x3E0, decodes 16-bit, 8-byte alignment, 2 addresses */ + 0x38, /* end dependent functions */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; + + +typedef struct cs423x_t +{ + void *pnp_card; + ad1848_t ad1848; + sb_t *sb; + void *i2c, *eeprom; + + uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size; + uint8_t regs[8], indirect_regs[16], eeprom_data[2048], ram_dl; +} cs423x_t; + + +static uint8_t +cs423x_read(uint16_t port, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t reg = port & 7; + uint8_t ret = dev->regs[reg]; + + switch (reg) { + case 1: /* EEPROM Interface */ + ret &= ~0x04; + if ((dev->regs[1] & 0x04) && i2c_gpio_get_sda(dev->i2c)) + ret |= 0x04; + break; + + case 4: /* Control Indirect Data Register */ + ret = dev->indirect_regs[dev->regs[3]]; + break; + + case 7: /* Global Status */ + ret = 0x00; + if (dev->sb->mpu->state.irq_pending) + ret |= 0x08; + if (dev->ad1848.regs[10] & 2) + ret |= 0x10; + if (dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16 || dev->sb->dsp.sb_irq401) + ret |= 0x20; + } + + return ret; +} + + +static void +cs423x_write(uint16_t port, uint8_t val, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t reg = port & 7; + + switch (reg) { + case 1: /* EEPROM Interface */ + if (val & 0x04) + i2c_gpio_set(dev->i2c, val & 0x01, val & 0x02); + break; + + case 3: /* Control Indirect Access Register */ + val &= 0x0f; + break; + + case 4: /* Control Indirect Data Register */ + switch (dev->regs[3] & 15) { + case 0: /* WSS Master Control */ + if (val & 0x80) + ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); + val = 0x00; + break; + + case 1: /* Version / Chip ID */ + case 7: /* Reserved */ + case 9 ... 15: /* unspecified */ + return; + + case 3: /* 3D Enable */ + val &= 0xe0; + break; + + case 4: /* Consumer Serial Port Enable */ + val &= 0xf0; + break; + + case 5: /* Lower Channel Status */ + val &= 0xfe; + break; + + case 8: /* CS9236 Wavetable Control */ + val &= 0xf0; + break; + } + dev->indirect_regs[dev->regs[3]] = val; + break; + + case 5: /* Control/RAM Access */ + switch (dev->ram_dl) { + case 0: /* commands */ + switch (val) { + case 0x55: /* Disable PnP Key */ + isapnp_enable_card(dev->pnp_card, 0); + break; + + /* TODO: Crystal's PnP bypass method? */ + + case 0xaa: /* Download RAM */ + dev->ram_dl = 1; + break; + } + break; + + case 1: /* low address byte */ + dev->ram_addr = val; + dev->ram_dl++; + break; + + case 2: /* high address byte */ + dev->ram_addr |= (val << 8); + dev->ram_dl++; + break; + + case 3: /* data */ + /* The only documented RAM region is 0x4000 (384 bytes in size), for + loading the chip's configuration and PnP ROM without an EEPROM. */ + if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) + dev->eeprom_data[dev->ram_addr - 0x3ffc] = val; /* skip first 4 bytes (EEPROM header) */ + dev->ram_addr++; + break; + } + break; + + case 6: /* RAM Access End */ + if (!val) + dev->ram_dl = 0; + break; + + case 7: /* Global Status */ + return; + } + + dev->regs[reg] = val; +} + + +static uint8_t +cs423x_ctxswitch_read(uint16_t addr, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t prev_context = dev->regs[7] & 0x80, switched = 0; + + /* Determine the active context (WSS or SBPro) through the address being read/written. */ + if ((prev_context == 0x80) && ((addr & 0xfff0) == dev->sb_base)) { + dev->regs[7] &= ~0x80; + switched = 1; + } else if ((prev_context == 0x00) && ((addr & 0xfffc) == dev->wss_base)) { + dev->regs[7] |= 0x80; + switched = 1; + } + + /* Fire the context switch interrupt if enabled. */ + if (switched && (dev->regs[0] & 0x20) && dev->ad1848.irq) + picint(1 << dev->ad1848.irq); + + return 0xff; /* don't interfere with the actual handlers */ +} + + +static void +cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) +{ + cs423x_ctxswitch_read(addr, priv); +} + + +static void +cs423x_get_buffer(int32_t *buffer, int len, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + int c; + + /* Output audio from the WSS codec. SBPro and OPL3 are + already handled by the Sound Blaster emulation. */ + ad1848_update(&dev->ad1848); + + for (c = 0; c < len * 2; c++) { + buffer[c] += (dev->ad1848.buffer[c] / 2); + } + + dev->ad1848.pos = 0; +} + + +static void +cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + switch (ld) { + case 0: /* WSS, OPL3 and SBPro */ + if (dev->wss_base) { + io_removehandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); + io_removehandler(dev->wss_base, 4, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + dev->wss_base = 0; + } + + if (dev->opl_base) { + io_removehandler(dev->opl_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + dev->opl_base = 0; + } + + if (dev->sb_base) { + sb_dsp_setaddr(&dev->sb->dsp, 0); + io_removehandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_removehandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_removehandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); + io_removehandler(dev->sb_base, 16, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + dev->sb_base = 0; + } + + ad1848_setirq(&dev->ad1848, 0); + sb_dsp_setirq(&dev->sb->dsp, 0); + + ad1848_setdma(&dev->ad1848, 0); + sb_dsp_setdma8(&dev->sb->dsp, 0); + + if (config->activate) { + if (config->io[0].base != ISAPNP_IO_DISABLED) { + dev->wss_base = config->io[0].base; + io_sethandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); + io_sethandler(dev->wss_base, 4, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + } + + if (config->io[1].base != ISAPNP_IO_DISABLED) { + dev->opl_base = config->io[1].base; + io_sethandler(dev->opl_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + } + + if (config->io[2].base != ISAPNP_IO_DISABLED) { + dev->sb_base = config->io[2].base; + sb_dsp_setaddr(&dev->sb->dsp, dev->sb_base); + io_sethandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_sethandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_sethandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); + io_sethandler(dev->sb_base, 16, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + } + + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) { + ad1848_setirq(&dev->ad1848, config->irq[0].irq); + sb_dsp_setirq(&dev->sb->dsp, config->irq[0].irq); + } + + if (config->dma[0].dma != ISAPNP_DMA_DISABLED) { + ad1848_setdma(&dev->ad1848, config->dma[0].dma); + sb_dsp_setdma8(&dev->sb->dsp, config->dma[0].dma); + } + } + + break; + +#if 0 + case 1: /* Game Port */ + gameport_remap(0); + + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) + gameport_remap(config->io[0].base); + + break; +#endif + + case 1: /* Control Registers */ + if (dev->ctrl_base) { + io_removehandler(dev->ctrl_base, 8, cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, dev); + dev->ctrl_base = 0; + } + + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { + dev->ctrl_base = config->io[0].base; + io_sethandler(dev->ctrl_base, 8, cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, dev); + } + + break; + + case 2: /* MPU-401 */ + mpu401_change_addr(dev->sb->mpu, 0); + mpu401_setirq(dev->sb->mpu, 0); + + if (config->activate) { + if (config->io[0].base != ISAPNP_IO_DISABLED) + mpu401_change_addr(dev->sb->mpu, config->io[0].base); + + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) + mpu401_setirq(dev->sb->mpu, config->irq[0].irq); + } + + break; + } +} + + +static void * +cs423x_init(const device_t *info) +{ + cs423x_t *dev = malloc(sizeof(cs423x_t)); + memset(dev, 0, sizeof(cs423x_t)); + + dev->indirect_regs[1] = 0x88; + + switch (info->local) { + case CRYSTAL_CS4237B: + dev->eeprom_size = sizeof(cs4237b_eeprom); + memcpy(dev->eeprom_data, cs4237b_eeprom, dev->eeprom_size); + break; + } + + dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); + + ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); + + sound_add_handler(cs423x_get_buffer, dev); + + dev->i2c = i2c_gpio_init("nvr_cs423x"); + + if (dev->eeprom_size) { + dev->eeprom_data[2] = dev->eeprom_size >> 8; + dev->eeprom_data[3] = dev->eeprom_size & 0xff; + + dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->eeprom_data, sizeof(dev->eeprom_data), 1); + } + + dev->pnp_card = isapnp_add_card(&dev->eeprom_data[23], dev->eeprom_size - 23, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); + + return dev; +} + + +static void +cs423x_close(void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + if (dev->eeprom) + i2c_eeprom_close(dev->eeprom); + + i2c_gpio_close(dev->i2c); + + free(dev); +} + + +static void +cs423x_speed_changed(void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + ad1848_speed_changed(&dev->ad1848); +} + + +const device_t cs4237b_device = +{ + "Crystal CS4237B", + DEVICE_ISA | DEVICE_AT, + CRYSTAL_CS4237B, + cs423x_init, cs423x_close, NULL, + { NULL }, + cs423x_speed_changed, + NULL, + NULL +}; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 2dc147285..bc08c2956 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1602,6 +1602,31 @@ sb_pro_mcv_init(const device_t *info) } +static void * +sb_pro_cs423x_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = 1; + opl3_init(&sb->opl); + + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); + sb_ct1345_mixer_reset(sb); + + sb->mixer_enabled = 1; + sound_add_handler(sb_get_buffer_sbpro, sb); + sound_set_cd_audio_filter(sbpro_filter_cd_audio, sb); + + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, 0, 0, M_UART, 1); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + return sb; +} + + static void * sb_16_init(const device_t *info) { @@ -2483,6 +2508,17 @@ const device_t sb_pro_mcv_device = NULL }; +const device_t sb_pro_cs423x_device = +{ + "Crystal CS423x Sound Blaster Pro compatibility", + DEVICE_ISA | DEVICE_AT, + 0, + sb_pro_cs423x_init, sb_close, NULL, { NULL }, + sb_speed_changed, + NULL, + NULL +}; + const device_t sb_16_device = { "Sound Blaster 16", diff --git a/src/sound/sound.c b/src/sound/sound.c index 16e092c01..39a3a44b6 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -88,6 +88,7 @@ static const SOUND_CARD sound_cards[] = { "adlibgold", &adgold_device }, { "azt2316a", &azt2316a_device }, { "azt1605", &azt1605_device }, + { "cs4237b", &cs4237b_device }, { "sb", &sb_1_device }, { "sb1.5", &sb_15_device }, { "sb2.0", &sb_2_device }, diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index fb1a320d4..79ee75f06 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -724,7 +724,7 @@ SNDOBJ := sound.o \ snd_pssj.o \ snd_lpt_dac.o snd_lpt_dss.o \ snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ - snd_azt2316a.o \ + snd_azt2316a.o snd_cs423x.o \ snd_cms.o \ snd_gus.o \ snd_sb.o snd_sb_dsp.o \ From 1de2e3dd2fb95c7084071bb8bb1080e209685583 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 20 May 2021 00:30:12 -0300 Subject: [PATCH 03/25] Crystal CS4237, part 2 --- src/device/isapnp.c | 40 ++++-- src/include/86box/isapnp.h | 8 ++ src/include/86box/snd_sb.h | 3 - src/sio/sio_um8669f.c | 4 +- src/sound/snd_cs423x.c | 284 ++++++++++++++++++++++++++++++++----- 5 files changed, 283 insertions(+), 56 deletions(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index f611a18ae..e08e2d300 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -478,9 +478,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) isapnp_log("ISAPnP: Reset CSN\n"); card = dev->first_card; while (card) { - card->csn = 0; - if (card->csn_changed) - card->csn_changed(card->csn, card->priv); + isapnp_set_csn(card, 0); card = card->next; } } @@ -506,9 +504,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) case 0x06: /* Card Select Number */ if (dev->isolated_card) { isapnp_log("ISAPnP: Set CSN %02X\n", val); - dev->isolated_card->csn = val; - if (dev->isolated_card->csn_changed) - dev->isolated_card->csn_changed(dev->isolated_card->csn, dev->isolated_card->priv); + isapnp_set_csn(dev->isolated_card, val); dev->isolated_card->state = PNP_STATE_CONFIG; dev->isolated_card = NULL; } else { @@ -685,8 +681,6 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, memset(card, 0, sizeof(isapnp_card_t)); card->enable = 1; - card->rom = rom; - card->rom_size = rom_size; card->priv = priv; card->config_changed = config_changed; card->csn_changed = csn_changed; @@ -702,6 +696,18 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, prev_card->next = card; } + isapnp_update_card_rom(card, rom, rom_size); + return card; +} + + +void +isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + card->rom = rom; + card->rom_size = rom_size; + /* Parse resources in ROM to allocate logical devices, and determine the state of read-only register bits. */ #ifdef ENABLE_ISAPNP_LOG @@ -712,8 +718,16 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, uint8_t ldn = 0, res, in_df = 0; uint8_t irq = 0, io = 0, mem_range = 0, mem_range_32 = 0, irq_df = 0, io_df = 0, mem_range_df = 0, mem_range_32_df = 0; uint32_t len; - isapnp_device_t *ld = NULL, *prev_ld = NULL; + isapnp_device_t *ld = card->first_ld, *prev_ld = NULL; + /* Clear any existing logical devices. */ + while (ld) { + prev_ld = ld->next; + free(ld); + ld = prev_ld; + } + + /* Iterate through ROM resources. */ while (i < card->rom_size) { if (card->rom[i] & 0x80) { /* large resource */ res = card->rom[i] & 0x7f; @@ -890,8 +904,6 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, /* We're done with the last logical device. */ if (ld) isapnp_reset_ld_regs(ld); - - return card; } @@ -907,10 +919,8 @@ isapnp_enable_card(void *priv, uint8_t enable) while (card) { if (card == priv) { /* Enable or disable the card. */ - card->enable = !!enable; - - /* enable=2 is a cheat code to jump straight into CONFIG state. */ - card->state = (enable == 2) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY; + card->enable = (enable >= ISAPNP_CARD_ENABLE); + card->state = (enable == ISAPNP_CARD_FORCE_CONFIG) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY; /* Invalidate other references if we're disabling this card. */ if (!card->enable) { diff --git a/src/include/86box/isapnp.h b/src/include/86box/isapnp.h index d241d74f3..38fc59d07 100644 --- a/src/include/86box/isapnp.h +++ b/src/include/86box/isapnp.h @@ -25,6 +25,13 @@ #define ISAPNP_DMA_DISABLED 4 +enum { + ISAPNP_CARD_DISABLE = 0, + ISAPNP_CARD_ENABLE = 1, + ISAPNP_CARD_FORCE_CONFIG /* cheat code for UMC UM8669F */ +}; + + typedef struct { uint8_t activate; struct { @@ -51,6 +58,7 @@ void *isapnp_add_card(uint8_t *rom, uint16_t rom_size, uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv), void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv), void *priv); +void isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size); void isapnp_enable_card(void *priv, uint8_t enable); void isapnp_set_csn(void *priv, uint8_t csn); void isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config); diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 8195345df..3bb2a6496 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -134,9 +134,6 @@ extern void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p); extern uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p); extern void sb_ct1345_mixer_reset(sb_t* sb); -extern uint8_t sb_pro_v1_opl_read(uint16_t port, void *priv); -extern void sb_pro_v1_opl_write(uint16_t port, uint8_t val, void *priv); - extern void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p); extern void sbpro_filter_cd_audio(int channel, double *buffer, void *p); extern void sb_close(void *p); diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index 2cfff686c..4a6869a02 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -39,7 +39,7 @@ #include <86box/isapnp.h> -/* This ROM is reconstructed out of the several assumptions, some of which are based on the IT8671F. */ +/* This ROM is reconstructed out of several assumptions, some of which are based on the IT8671F. */ static uint8_t um8669f_pnp_rom[] = { 0x55, 0xa3, 0x86, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, /* UMC8669, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ @@ -211,7 +211,7 @@ um8669f_write(uint16_t port, uint8_t val, void *priv) if (dev->cur_reg_108 == 0xc1) { um8669f_log("UM8669F: ISAPnP %sabled\n", (val & 0x80) ? "en" : "dis"); - isapnp_enable_card(dev->pnp_card, (val & 0x80) ? 2 : 0); + isapnp_enable_card(dev->pnp_card, (val & 0x80) ? ISAPNP_CARD_FORCE_CONFIG : ISAPNP_CARD_DISABLE); } } } diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 6456d5a8d..88f15c49c 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -36,13 +36,35 @@ enum { - CRYSTAL_CS4237B = 37 + CRYSTAL_CS4237B = 0xc8 +}; +enum { + CRYSTAL_SLAM_NONE = 0, + CRYSTAL_SLAM_INDEX, + CRYSTAL_SLAM_BYTE1, + CRYSTAL_SLAM_BYTE2 }; -static const uint8_t cs4237b_eeprom[384] = { - 0x55, 0xbb, 0x00, 0x00, 0x00, 0x03, 0x80, 0x80, 0x0b, 0x20, 0x04, 0x08, 0x10, 0x80, 0x00, 0x00, 0x00, 0x48, 0x75, 0xb9, 0xfc, 0x10, 0x03, /* CS4237B stuff */ +static const uint8_t slam_init_key[32] = { 0x96, 0x35, 0x9A, 0xCD, 0xE6, 0xF3, 0x79, 0xBC, + 0x5E, 0xAF, 0x57, 0x2B, 0x15, 0x8A, 0xC5, 0xE2, + 0xF1, 0xF8, 0x7C, 0x3E, 0x9F, 0x4F, 0x27, 0x13, + 0x09, 0x84, 0x42, 0xA1, 0xD0, 0x68, 0x34, 0x1A }; +static const uint8_t cs4237b_eeprom[] = { + /* CS4237B configuration */ + 0x55, 0xbb, /* magic */ + 0x00, 0x00, /* length */ + 0x00, 0x03, /* CD-ROM and modem decode */ + 0x80, /* misc. config */ + 0x80, /* global config */ + 0x0b, /* chip ID */ + 0x20, 0x04, 0x08, 0x10, 0x80, 0x00, 0x00, /* reserved */ + 0x00, /* external decode length */ + 0x48, /* reserved */ + 0x75, 0xb9, 0xfc, /* IRQ routing */ + 0x10, 0x03, /* DMA routing */ + /* PnP resources */ 0x0e, 0x63, 0x42, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, /* CSC4237, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x01, /* PnP version 1.0, vendor version 0.1 */ 0x82, 0x0e, 0x00, 'C', 'r', 'y', 's', 't', 'a', 'l', ' ', 'C', 'o', 'd', 'e' ,'c', 0x00, /* ANSI identifier */ @@ -106,11 +128,19 @@ typedef struct cs423x_t sb_t *sb; void *i2c, *eeprom; - uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size; - uint8_t regs[8], indirect_regs[16], eeprom_data[2048], ram_dl; + uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11; + uint8_t type, regs[8], indirect_regs[16], eeprom_data[2048], ram_dl; + + uint8_t key_pos: 5, enable_slam: 1, slam_state: 2, slam_ld, slam_reg; + isapnp_device_config_t *slam_config; } cs423x_t; +static void cs423x_slam_remap(cs423x_t *dev, uint8_t enable); +static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv); +static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); + + static uint8_t cs423x_read(uint16_t port, void *priv) { @@ -130,12 +160,15 @@ cs423x_read(uint16_t port, void *priv) break; case 7: /* Global Status */ - ret = 0x00; - if (dev->sb->mpu->state.irq_pending) + /* Context switching: take active context and interrupt flag, then clear interrupt flag. */ + ret &= 0xc0; + dev->regs[7] &= 0x80; + + if (dev->sb->mpu->state.irq_pending) /* MPU interrupt */ ret |= 0x08; - if (dev->ad1848.regs[10] & 2) + if (dev->ad1848.regs[10] & 2) /* WSS interrupt */ ret |= 0x10; - if (dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16 || dev->sb->dsp.sb_irq401) + if (dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16 || dev->sb->dsp.sb_irq401) /* SBPro interrupt */ ret |= 0x20; } @@ -148,6 +181,7 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; uint8_t reg = port & 7; + uint16_t eeprom_addr; switch (reg) { case 1: /* EEPROM Interface */ @@ -199,7 +233,16 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) isapnp_enable_card(dev->pnp_card, 0); break; - /* TODO: Crystal's PnP bypass method? */ + case 0x56: /* Disable Crystal Key */ + cs423x_slam_remap(dev, 0); + break; + + case 0x57: /* Jump to ROM */ + break; + + case 0x5a: /* Update Hardware Configuration Data */ + isapnp_update_card_rom(dev->pnp_card, dev->eeprom_data + 23, dev->eeprom_size - 23); + break; case 0xaa: /* Download RAM */ dev->ram_dl = 1; @@ -220,8 +263,12 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) case 3: /* data */ /* The only documented RAM region is 0x4000 (384 bytes in size), for loading the chip's configuration and PnP ROM without an EEPROM. */ - if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) - dev->eeprom_data[dev->ram_addr - 0x3ffc] = val; /* skip first 4 bytes (EEPROM header) */ + if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) { + eeprom_addr = dev->ram_addr - 0x3ffc; /* skip first 4 bytes (header on real EEPROM) */ + dev->eeprom_data[eeprom_addr] = val; + if (dev->eeprom_size < ++eeprom_addr) /* update EEPROM size if required */ + dev->eeprom_size = eeprom_addr; + } dev->ram_addr++; break; } @@ -240,25 +287,149 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) } +static void +cs423x_slam_write(uint16_t addr, uint8_t val, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t idx; + + switch (dev->slam_state) { + case CRYSTAL_SLAM_NONE: + /* Not in SLAM: read and compare Crystal key. */ + if (val == slam_init_key[dev->key_pos]) { + dev->key_pos++; + /* Was the key successfully written? */ + if (!dev->key_pos) { + /* Discard any pending logical device configuration, just to be safe. */ + if (dev->slam_config) { + free(dev->slam_config); + dev->slam_config = NULL; + } + + /* Enter SLAM. */ + dev->slam_state = CRYSTAL_SLAM_INDEX; + } + } else { + dev->key_pos = 0; + } + break; + + case CRYSTAL_SLAM_INDEX: + /* Write register index. */ + dev->slam_reg = val; + dev->slam_state = CRYSTAL_SLAM_BYTE1; + break; + + case CRYSTAL_SLAM_BYTE1: + case CRYSTAL_SLAM_BYTE2: + /* Write register value: two bytes for I/O ports, single byte otherwise. */ + switch (dev->slam_reg) { + case 0x06: /* Card Select Number */ + isapnp_set_csn(dev->pnp_card, val); + break; + + case 0x15: /* Logical Device ID */ + /* Apply the previous logical device's configuration, and reuse its config structure. */ + if (dev->slam_config) + cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev); + else + dev->slam_config = (isapnp_device_config_t *) malloc(sizeof(isapnp_device_config_t)); + + /* Start new logical device. */ + memset(dev->slam_config, 0, sizeof(isapnp_device_config_t)); + dev->slam_ld = val; + break; + + case 0x47: /* I/O Port Base Address 0 */ + case 0x48: /* I/O Port Base Address 1 */ + case 0x42: /* I/O Port Base Address 2 */ + idx = (dev->slam_reg == 0x42) ? 2 : (dev->slam_reg - 0x47); + if (dev->slam_state == CRYSTAL_SLAM_BYTE1) { + /* Set high byte, or ignore it if no logical device is selected. */ + if (dev->slam_config) + dev->slam_config->io[idx].base = val << 8; + + /* Prepare for the second (low byte) write. */ + dev->slam_state = CRYSTAL_SLAM_BYTE2; + return; + } else if (dev->slam_config) { + /* Set low byte, or ignore it if no logical device is selected. */ + dev->slam_config->io[idx].base |= val; + } + break; + + case 0x22: /* Interrupt Select 0 */ + case 0x27: /* Interrupt Select 1 */ + /* Stop if no logical device is selected. */ + if (!dev->slam_config) + break; + + /* Set IRQ value. */ + idx = (dev->slam_reg == 0x22) ? 0 : 1; + dev->slam_config->irq[idx].irq = val & 15; + break; + + case 0x2a: /* DMA Select 0 */ + case 0x25: /* DMA Select 1 */ + /* Stop if no logical device is selected. */ + if (!dev->slam_config) + break; + + /* Set DMA value. */ + idx = (dev->slam_reg == 0x2a) ? 0 : 1; + dev->slam_config->dma[idx].dma = val & 7; + break; + + case 0x33: /* Activate Device */ + /* Stop if no logical device is selected. */ + if (!dev->slam_config) + break; + + /* Activate or deactivate the device. */ + dev->slam_config->activate = val & 0x01; + break; + + case 0x79: /* activate chip */ + /* Apply the last logical device's configuration. */ + if (dev->slam_config) { + cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev); + free(dev->slam_config); + dev->slam_config = NULL; + } + + /* Exit out of SLAM. */ + dev->slam_state = CRYSTAL_SLAM_NONE; + break; + } + + /* Prepare for the next register, unless a two-byte read returns above. */ + dev->slam_state = CRYSTAL_SLAM_INDEX; + break; + } +} + + +static void +cs423x_slam_remap(cs423x_t *dev, uint8_t enable) +{ + /* Disable SLAM. */ + if (dev->enable_slam) { + dev->enable_slam = 0; + io_removehandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); + } + + /* Enable SLAM if not blocked by EEPROM configuration. */ + if (enable && !(dev->eeprom_data[7] & 0x10)) { + dev->enable_slam = 1; + io_sethandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); + } +} + + static uint8_t cs423x_ctxswitch_read(uint16_t addr, void *priv) { - cs423x_t *dev = (cs423x_t *) priv; - uint8_t prev_context = dev->regs[7] & 0x80, switched = 0; - - /* Determine the active context (WSS or SBPro) through the address being read/written. */ - if ((prev_context == 0x80) && ((addr & 0xfff0) == dev->sb_base)) { - dev->regs[7] &= ~0x80; - switched = 1; - } else if ((prev_context == 0x00) && ((addr & 0xfffc) == dev->wss_base)) { - dev->regs[7] |= 0x80; - switched = 1; - } - - /* Fire the context switch interrupt if enabled. */ - if (switched && (dev->regs[0] & 0x20) && dev->ad1848.irq) - picint(1 << dev->ad1848.irq); - + cs423x_ctxswitch_write(addr, 0, priv); return 0xff; /* don't interfere with the actual handlers */ } @@ -266,7 +437,23 @@ cs423x_ctxswitch_read(uint16_t addr, void *priv) static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) { - cs423x_ctxswitch_read(addr, priv); + cs423x_t *dev = (cs423x_t *) priv; + uint8_t prev_context = dev->regs[7] & 0x80, switched = 0; + + /* Determine the active context (WSS or SBPro) through the address being read/written. */ + if ((prev_context == 0x80) && ((addr & 0xfff0) == dev->sb_base)) { + dev->regs[7] &= ~0x80; + switched = 1; + } else if ((prev_context == 0x00) && ((addr & 0xfffc) == dev->wss_base)) { + dev->regs[7] |= 0x80; + switched = 1; + } + + /* Fire the context switch interrupt if enabled. */ + if (switched && (dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { + dev->regs[7] |= 0x40; /* set interrupt flag */ + picint(1 << dev->ad1848.irq); /* control device shares its IRQ with WSS and SBPro */ + } } @@ -395,37 +582,62 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv } +static void +cs423x_reset(void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + /* Reset registers. */ + memset(dev->indirect_regs, 0, sizeof(dev->indirect_regs)); + dev->indirect_regs[1] = dev->type; + + /* Reset logical devices. */ + for (uint8_t i = 0; i < 6; i++) + isapnp_reset_device(dev->pnp_card, i); + + /* Enable SLAM. */ + cs423x_slam_remap(dev, 1); +} + + static void * cs423x_init(const device_t *info) { cs423x_t *dev = malloc(sizeof(cs423x_t)); memset(dev, 0, sizeof(cs423x_t)); - dev->indirect_regs[1] = 0x88; - - switch (info->local) { + dev->type = info->local; + switch (dev->type) { case CRYSTAL_CS4237B: dev->eeprom_size = sizeof(cs4237b_eeprom); memcpy(dev->eeprom_data, cs4237b_eeprom, dev->eeprom_size); break; } + /* Initialize codecs. */ dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); - - ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); - + ad1848_init(&dev->ad1848, AD1848_TYPE_CS4236); sound_add_handler(cs423x_get_buffer, dev); + /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); if (dev->eeprom_size) { + /* Set EEPROM length. */ dev->eeprom_data[2] = dev->eeprom_size >> 8; dev->eeprom_data[3] = dev->eeprom_size & 0xff; + /* Initialize I2C EEPROM. */ dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->eeprom_data, sizeof(dev->eeprom_data), 1); } + /* Initialize ISAPnP. */ dev->pnp_card = isapnp_add_card(&dev->eeprom_data[23], dev->eeprom_size - 23, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); + if (dev->eeprom_data[7] & 0x20) /* hide PnP card if PKD is set */ + isapnp_enable_card(dev->pnp_card, 0); + + /* Initialize registers. */ + cs423x_reset(dev); return dev; } @@ -459,7 +671,7 @@ const device_t cs4237b_device = "Crystal CS4237B", DEVICE_ISA | DEVICE_AT, CRYSTAL_CS4237B, - cs423x_init, cs423x_close, NULL, + cs423x_init, cs423x_close, cs423x_reset, { NULL }, cs423x_speed_changed, NULL, From 77f311b179fe3d1646a8efc3c708b17eda29f5ba Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 20 May 2021 22:51:55 -0300 Subject: [PATCH 04/25] Game port overhaul --- src/game/gameport.c | 335 +++++++++++++++++++++++------------ src/include/86box/gameport.h | 41 ++--- src/include/86box/snd_sb.h | 1 + src/machine/m_amstrad.c | 3 +- src/machine/m_at.c | 3 +- src/machine/m_ps1.c | 3 +- src/machine/m_tandy.c | 3 +- src/machine/m_xt.c | 3 +- src/machine/m_xt_compaq.c | 3 +- src/machine/m_xt_laserxt.c | 3 +- src/machine/m_xt_olivetti.c | 3 +- src/machine/m_xt_philips.c | 3 +- src/machine/m_xt_xi8088.c | 3 +- src/machine/machine.c | 2 + src/sio/sio_um8669f.c | 21 ++- src/sound/snd_audiopci.c | 6 +- src/sound/snd_sb.c | 150 +++++++++------- 17 files changed, 352 insertions(+), 234 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index 7df2e7eda..d7f399ab3 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 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 VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of a generic Game Port. * @@ -12,27 +12,11 @@ * * Authors: Miran Grca, * Sarah Walker, + * RichardG, * * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. + * Copyright 2021 RichardG. */ #include #include @@ -45,6 +29,7 @@ #include <86box/device.h> #include <86box/io.h> #include <86box/timer.h> +#include <86box/isapnp.h> #include <86box/gameport.h> #include <86box/joystick_ch_flightstick_pro.h> #include <86box/joystick_standard.h> @@ -55,21 +40,25 @@ typedef struct { pc_timer_t timer; int axis_nr; - struct _gameport_ *gameport; + struct _joystick_instance_ *joystick; } g_axis_t; typedef struct _gameport_ { - uint8_t state; uint16_t addr; - - g_axis_t axis[4]; - - const joystick_if_t *joystick; - void *joystick_dat; + struct _joystick_instance_ *joystick; + struct _gameport_ *next; } gameport_t; +typedef struct _joystick_instance_ { + uint8_t state; + g_axis_t axis[4]; -int joystick_type = 0; + const joystick_if_t *intf; + void *dat; +} joystick_instance_t; + + +int joystick_type = 1; static const joystick_if_t joystick_none = { @@ -101,22 +90,54 @@ static const struct { { "thrustmaster_fcs", &joystick_tm_fcs }, { "", NULL } }; -static gameport_t *gameport_global = NULL; +static joystick_instance_t *joystick_instance = NULL; + + +static uint8_t gameport_pnp_rom[] = { + 0x09, 0xf8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, /* BOX0002, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ + 0x82, 0x09, 0x00, 'G', 'a', 'm', 'e', ' ', 'P', 'o', 'r', 't', /* ANSI identifier */ + + 0x15, 0x09, 0xf8, 0x00, 0x02, 0x01, /* logical device BOX0002, can participate in boot */ + 0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x30, /* start dependent functions, acceptable */ + 0x47, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x31, 0x02, /* start dependent functions, sub-optimal */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x38, /* end dependent functions */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; +static const isapnp_device_config_t gameport_pnp_defaults[] = { + { + .activate = 1, + .io = { { .base = 0x200 }, } + } +}; + + +const device_t *standalone_gameport_type; +static int gameport_instance_id = 0; +/* Linked list of active game ports. Only the top port responds to reads + or writes, and ports at the standard 200h location are prioritized. */ +static gameport_t *active_gameports = NULL; char * joystick_get_name(int js) { - if (! joysticks[js].joystick) - return(NULL); - return((char *)joysticks[js].joystick->name); + if (!joysticks[js].joystick) + return NULL; + return (char *) joysticks[js].joystick->name; } char * joystick_get_internal_name(int js) { - return((char *) joysticks[js].internal_name); + return (char *) joysticks[js].internal_name; } @@ -125,8 +146,7 @@ joystick_get_from_internal_name(char *s) { int c = 0; - while (strlen((char *) joysticks[c].internal_name)) - { + while (strlen((char *) joysticks[c].internal_name)) { if (!strcmp((char *) joysticks[c].internal_name, s)) return c; c++; @@ -139,62 +159,63 @@ joystick_get_from_internal_name(char *s) int joystick_get_max_joysticks(int js) { - return(joysticks[js].joystick->max_joysticks); + return joysticks[js].joystick->max_joysticks; } int joystick_get_axis_count(int js) { - return(joysticks[js].joystick->axis_count); + return joysticks[js].joystick->axis_count; } int joystick_get_button_count(int js) { - return(joysticks[js].joystick->button_count); + return joysticks[js].joystick->button_count; } int joystick_get_pov_count(int js) { - return(joysticks[js].joystick->pov_count); + return joysticks[js].joystick->pov_count; } char * joystick_get_axis_name(int js, int id) { - return((char *)joysticks[js].joystick->axis_names[id]); + return (char *) joysticks[js].joystick->axis_names[id]; } char * joystick_get_button_name(int js, int id) { - return((char *)joysticks[js].joystick->button_names[id]); + return (char *) joysticks[js].joystick->button_names[id]; } char * joystick_get_pov_name(int js, int id) { - return (char *)joysticks[js].joystick->pov_names[id]; + return (char *) joysticks[js].joystick->pov_names[id]; } static void -gameport_time(gameport_t *gameport, int nr, int axis) +gameport_time(joystick_instance_t *joystick, int nr, int axis) { if (axis == AXIS_NOT_PRESENT) - timer_disable(&gameport->axis[nr].timer); + timer_disable(&joystick->axis[nr].timer); else { + /* Convert axis value to 555 timing. */ axis += 32768; - axis = (axis * 100) / 65; /*Axis now in ohms*/ + axis = (axis * 100) / 65; /* axis now in ohms */ axis = (axis * 11) / 1000; - timer_set_delay_u64(&gameport->axis[nr].timer, TIMER_USEC * (axis + 24)); /*max = 11.115 ms*/ + timer_set_delay_u64(&joystick->axis[nr].timer, TIMER_USEC * (axis + 24)); /* max = 11.115 ms */ } } @@ -202,16 +223,23 @@ gameport_time(gameport_t *gameport, int nr, int axis) static void gameport_write(uint16_t addr, uint8_t val, void *priv) { - gameport_t *p = (gameport_t *)priv; + gameport_t *dev = (gameport_t *) priv; + joystick_instance_t *joystick = dev->joystick; - p->state |= 0x0f; + /* Respond only if a joystick is present and this port is at the top of the active ports list. */ + if (!joystick || (active_gameports != dev)) + return; - gameport_time(p, 0, p->joystick->read_axis(p->joystick_dat, 0)); - gameport_time(p, 1, p->joystick->read_axis(p->joystick_dat, 1)); - gameport_time(p, 2, p->joystick->read_axis(p->joystick_dat, 2)); - gameport_time(p, 3, p->joystick->read_axis(p->joystick_dat, 3)); - - p->joystick->write(p->joystick_dat); + /* Read all axes. */ + joystick->state |= 0x0f; + + gameport_time(joystick, 0, joystick->intf->read_axis(joystick->dat, 0)); + gameport_time(joystick, 1, joystick->intf->read_axis(joystick->dat, 1)); + gameport_time(joystick, 2, joystick->intf->read_axis(joystick->dat, 2)); + gameport_time(joystick, 3, joystick->intf->read_axis(joystick->dat, 3)); + + /* Notify the interface. */ + joystick->intf->write(joystick->dat); cycles -= ISA_CYCLES(8); } @@ -220,114 +248,184 @@ gameport_write(uint16_t addr, uint8_t val, void *priv) static uint8_t gameport_read(uint16_t addr, void *priv) { - gameport_t *p = (gameport_t *)priv; - uint8_t ret; + gameport_t *dev = (gameport_t *) priv; + joystick_instance_t *joystick = dev->joystick; - ret = p->state | p->joystick->read(p->joystick_dat); + /* Respond only if a joystick is present and this port is at the top of the active ports list. */ + if (!joystick || (active_gameports != dev)) + return 0xff; + + /* Merge axis state with button state. */ + uint8_t ret = joystick->state | joystick->intf->read(joystick->dat); cycles -= ISA_CYCLES(8); - return(ret); + return ret; } static void timer_over(void *priv) { - g_axis_t *axis = (g_axis_t *)priv; - gameport_t *p = axis->gameport; + g_axis_t *axis = (g_axis_t *) priv; - p->state &= ~(1 << axis->axis_nr); + axis->joystick->state &= ~(1 << axis->axis_nr); - if (axis == &p->axis[0]) - p->joystick->a0_over(p->joystick_dat); + if (axis == &axis->joystick->axis[0]) + axis->joystick->intf->a0_over(axis->joystick->dat); } void gameport_update_joystick_type(void) { - gameport_t *p = gameport_global; + /* Add a standalone game port if a joystick is enabled but no other game ports exist. */ + if (standalone_gameport_type) + gameport_add(standalone_gameport_type); - if (p != NULL) { - p->joystick->close(p->joystick_dat); - p->joystick = joysticks[joystick_type].joystick; - p->joystick_dat = p->joystick->init(); + /* Reset the joystick interface. */ + if (joystick_instance) { + joystick_instance->intf->close(joystick_instance->dat); + joystick_instance->intf = joysticks[joystick_type].joystick; + joystick_instance->dat = joystick_instance->intf->init(); } } void -gameport_remap(uint16_t address) +gameport_remap(void *priv, uint16_t address) { - gameport_t *p = gameport_global; - if (!p) + gameport_t *dev = (gameport_t *) priv, *other_dev; + + if (dev->addr) { + /* Remove this port from the active ports list. */ + if (active_gameports == dev) { + active_gameports = dev->next; + dev->next = NULL; + } else { + other_dev = active_gameports; + while (other_dev) { + if (other_dev->next == dev) { + other_dev->next = dev->next; + dev->next = NULL; + break; + } + other_dev = other_dev->next; + } + } + + io_removehandler(dev->addr, (dev->addr & 1) ? 1 : 8, + gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev); + } + + dev->addr = address; + + if (dev->addr) { + /* Add this port to the active ports list. */ + if ((dev->addr & 0xfff8) == 0x200) { + /* Port within 200-207h: add to top. */ + dev->next = active_gameports; + active_gameports = dev; + } else { + /* Port at other addresses: add to bottom. */ + other_dev = active_gameports; + while (other_dev->next) + other_dev = other_dev->next; + other_dev->next = dev; + } + + io_sethandler(dev->addr, (dev->addr & 1) ? 1 : 8, + gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev); + } +} + + +static void +gameport_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + if (ld > 0) return; - if (p->addr) - io_removehandler(p->addr, (p->addr & 1) ? 1 : 8, - gameport_read, NULL, NULL, gameport_write, NULL, NULL, p); + gameport_t *dev = (gameport_t *) priv; - p->addr = address; + /* Remap the game port to the specified address, or disable it. */ + gameport_remap(dev, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); +} - if (p->addr) - io_sethandler(p->addr, (p->addr & 1) ? 1 : 8, - gameport_read, NULL, NULL, gameport_write, NULL, NULL, p); + +void * +gameport_add(const device_t *gameport_type) +{ + /* Prevent a standalone game port from being added later on. */ + standalone_gameport_type = NULL; + + /* Add game port device. */ + return device_add_inst(gameport_type, gameport_instance_id++); } static void * gameport_init(const device_t *info) { - gameport_t *p = NULL; + gameport_t *dev = NULL; - if (!joystick_type) { - gameport_global = p = NULL; - return(p); + dev = malloc(sizeof(gameport_t)); + memset(dev, 0x00, sizeof(gameport_t)); + + /* Allocate global instance. */ + if (!joystick_instance && joystick_type) { + joystick_instance = malloc(sizeof(joystick_instance_t)); + memset(joystick_instance, 0x00, sizeof(joystick_instance_t)); + + joystick_instance->axis[0].joystick = joystick_instance; + joystick_instance->axis[1].joystick = joystick_instance; + joystick_instance->axis[2].joystick = joystick_instance; + joystick_instance->axis[3].joystick = joystick_instance; + + joystick_instance->axis[0].axis_nr = 0; + joystick_instance->axis[1].axis_nr = 1; + joystick_instance->axis[2].axis_nr = 2; + joystick_instance->axis[3].axis_nr = 3; + + timer_add(&joystick_instance->axis[0].timer, timer_over, &joystick_instance->axis[0], 0); + timer_add(&joystick_instance->axis[1].timer, timer_over, &joystick_instance->axis[1], 0); + timer_add(&joystick_instance->axis[2].timer, timer_over, &joystick_instance->axis[2], 0); + timer_add(&joystick_instance->axis[3].timer, timer_over, &joystick_instance->axis[3], 0); + + joystick_instance->intf = joysticks[joystick_type].joystick; + joystick_instance->dat = joystick_instance->intf->init(); } - p = malloc(sizeof(gameport_t)); + dev->joystick = joystick_instance; - memset(p, 0x00, sizeof(gameport_t)); + /* Map game port to the default address. Not applicable on PnP-only ports. */ + gameport_remap(dev, info->local); - p->axis[0].gameport = p; - p->axis[1].gameport = p; - p->axis[2].gameport = p; - p->axis[3].gameport = p; + /* Register ISAPnP if this is a standard game port card. */ + if (info->local == 0x200) + isapnp_set_device_defaults(isapnp_add_card(gameport_pnp_rom, sizeof(gameport_pnp_rom), gameport_pnp_config_changed, NULL, NULL, NULL, dev), 0, gameport_pnp_defaults); - p->axis[0].axis_nr = 0; - p->axis[1].axis_nr = 1; - p->axis[2].axis_nr = 2; - p->axis[3].axis_nr = 3; - - timer_add(&p->axis[0].timer, timer_over, &p->axis[0], 0); - timer_add(&p->axis[1].timer, timer_over, &p->axis[1], 0); - timer_add(&p->axis[2].timer, timer_over, &p->axis[2], 0); - timer_add(&p->axis[3].timer, timer_over, &p->axis[3], 0); - - p->joystick = joysticks[joystick_type].joystick; - p->joystick_dat = p->joystick->init(); - - gameport_global = p; - - gameport_remap(info->local); - - return(p); + return dev; } static void gameport_close(void *priv) { - gameport_t *p = (gameport_t *)priv; + gameport_t *dev = (gameport_t *) priv; - if (p == NULL) return; + /* If this port was active, remove it from the active ports list. */ + gameport_remap(dev, 0); - p->joystick->close(p->joystick_dat); + /* Free the global instance here, if it wasn't already freed. */ + if (joystick_instance) { + joystick_instance->intf->close(joystick_instance->dat); - gameport_global = NULL; + free(joystick_instance); + joystick_instance = NULL; + } - free(p); + free(dev); } @@ -348,3 +446,12 @@ const device_t gameport_201_device = { NULL, { NULL }, NULL, NULL }; + +const device_t gameport_pnp_device = { + "Game port (Plug and Play only)", + 0, 0, + gameport_init, + gameport_close, + NULL, { NULL }, NULL, + NULL +}; diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index 4ceac12e9..406234f45 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -1,40 +1,22 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 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 VARCem Project. + * This file is part of the 86Box distribution. * * Definitions for the generic game port handlers. * - * NOTE: This module needs a good cleanup someday. - * * * * Authors: Miran Grca, * Sarah Walker, + * RichardG, * * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2017 Sarah Walker. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2021 RichardG. */ #ifndef EMU_GAMEPORT_H # define EMU_GAMEPORT_H @@ -125,8 +107,10 @@ extern "C" { #ifdef EMU_DEVICE_H extern const device_t gameport_device; extern const device_t gameport_201_device; -#endif +extern const device_t gameport_pnp_device; +extern const device_t *standalone_gameport_type; +#endif extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; extern joystick_t joystick_state[MAX_JOYSTICKS]; extern int joysticks_present; @@ -150,7 +134,8 @@ extern char *joystick_get_button_name(int js, int id); extern char *joystick_get_pov_name(int js, int id); extern void gameport_update_joystick_type(void); -extern void gameport_remap(uint16_t address); +extern void gameport_remap(void *priv, uint16_t address); +extern void *gameport_add(const device_t *gameport_type); #ifdef __cplusplus } diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 3bb2a6496..7889380f5 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -122,6 +122,7 @@ typedef struct sb_t }; mpu_t *mpu; emu8k_t emu8k; + void *gameport; int pos; diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 6996ab1da..ddddc6705 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -2516,8 +2516,7 @@ machine_amstrad_init(const machine_t *model, int type) mouse_set_poll(ms_poll, ams); } - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; } diff --git a/src/machine/m_at.c b/src/machine/m_at.c index e10e1f549..0e5589927 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -74,8 +74,7 @@ machine_at_common_init_ex(const machine_t *model, int type) else if (type == 0) device_add(&at_nvr_device); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; } diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 7edc81883..33b67aabe 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -516,8 +516,7 @@ ps1_common_init(const machine_t *model) device_add(&keyboard_ps2_ps1_device); /* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */ - if (joystick_type) - device_add(&gameport_201_device); + standalone_gameport_type = &gameport_201_device; } diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 0ec09c21f..c09ca21c8 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -1541,8 +1541,7 @@ machine_tandy1k_init(const machine_t *model, int type) break; } - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; eep_data_out = 0x0000; } diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 581a5d7c9..127495259 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -30,8 +30,7 @@ machine_xt_common_init(const machine_t *model) device_add(&fdc_xt_device); nmi_init(); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; } diff --git a/src/machine/m_xt_compaq.c b/src/machine/m_xt_compaq.c index 4874106f6..5950ec3f9 100644 --- a/src/machine/m_xt_compaq.c +++ b/src/machine/m_xt_compaq.c @@ -56,8 +56,7 @@ machine_xt_compaq_deskpro_init(const machine_t *model) if (fdc_type == FDC_INTERNAL) device_add(&fdc_xt_device); nmi_init(); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; lpt1_remove(); lpt1_init(0x03bc); diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index cc9d32dd7..58b7d3774 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -174,8 +174,7 @@ machine_xt_lxt3_init(const machine_t *model) if (fdc_type == FDC_INTERNAL) device_add(&fdc_xt_device); nmi_init(); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; laserxt_init(1); diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index 331ebdcac..bc9edb672 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -738,8 +738,7 @@ machine_xt_m24_init(const machine_t *model) /* FIXME: make sure this is correct?? */ device_add(&at_nvr_device); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; nmi_init(); diff --git a/src/machine/m_xt_philips.c b/src/machine/m_xt_philips.c index f9b205d4c..164e8b093 100644 --- a/src/machine/m_xt_philips.c +++ b/src/machine/m_xt_philips.c @@ -155,8 +155,7 @@ machine_xt_philips_common_init(const machine_t *model) nmi_init(); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; device_add(&keyboard_pc_device); diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index e5cd0e87a..d7a127119 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -181,8 +181,7 @@ machine_xt_xi8088_init(const machine_t *model) nmi_init(); device_add(&ibmat_nvr_device); pic2_init(); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; return ret; } diff --git a/src/machine/machine.c b/src/machine/machine.c index 685165f89..e3f2ef600 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -34,6 +34,7 @@ #include <86box/rom.h> #include <86box/lpt.h> #include <86box/serial.h> +#include <86box/gameport.h> #include "cpu.h" #include <86box/video.h> #include <86box/machine.h> @@ -74,6 +75,7 @@ machine_init_ex(int m) machine_log("Initializing as \"%s\"\n", machine_getname()); is_vpc = 0; + standalone_gameport_type = NULL; /* Set up the architecture flags. */ AT = IS_AT(machine); diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index 4a6869a02..e7131bb45 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -117,14 +117,15 @@ um8669f_log(const char *fmt, ...) typedef struct um8669f_t { - int locked, cur_reg_108; - void *pnp_card; + int locked, cur_reg_108; + void *pnp_card; isapnp_device_config_t *pnp_config[5]; - uint8_t regs_108[256]; + uint8_t regs_108[256]; - fdc_t *fdc; - serial_t *uart[2]; + fdc_t *fdc; + serial_t *uart[2]; + void *gameport; } um8669f_t; @@ -179,13 +180,13 @@ um8669f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri break; case 5: - gameport_remap(0); - if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { um8669f_log("UM8669F: Game port enabled at port %04X\n", config->io[0].base); - gameport_remap(config->io[0].base); - } else + gameport_remap(dev->gameport, config->io[0].base); + } else { um8669f_log("UM8669F: Game port disabled\n"); + gameport_remap(dev->gameport, 0); + } } } @@ -286,6 +287,8 @@ um8669f_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); + dev->gameport = gameport_add(&gameport_pnp_device); + io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, dev); diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index bfa4d7eb0..1c697a3a8 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -8,6 +8,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> +#include <86box/gameport.h> #include <86box/io.h> #include <86box/nmi.h> #include <86box/mem.h> @@ -1352,13 +1353,16 @@ static void *es1371_init(const device_t *info) sound_add_handler(es1371_get_buffer, es1371); sound_set_cd_audio_filter(es1371_filter_cd_audio, es1371); + /* Add our own always-present game port to override the standalone ISAPnP one. */ + gameport_remap(gameport_add(&gameport_pnp_device), 0x200); + es1371->card = pci_add_card(info->local ? PCI_ADD_SOUND : PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371); timer_add(&es1371->dac[1].timer, es1371_poll, es1371, 1); generate_es1371_filter(); - /* Return a CS4297A like VMWare does. */ + /* Return a CS4297A like VMware does. */ es1371->codec_regs[0x7c] = 0x4352; es1371->codec_regs[0x7e] = 0x5910; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index bc08c2956..9712f9cc6 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -31,6 +31,7 @@ #include <86box/mem.h> #include <86box/rom.h> #include <86box/device.h> +#include <86box/gameport.h> #include <86box/pic.h> #include <86box/sound.h> #include <86box/midi.h> @@ -71,6 +72,9 @@ static const uint16_t sb_mcv_addr[8] = {0x200, 0x210, 0x220, 0x230, 0x240, 0x250 static const int sb_pro_mcv_irqs[4] = {7, 5, 3, 3}; +/* Each card in the SB16 family has a million variants, and it shows in the large variety of device IDs for the PnP models. + These ROMs were reconstructed in a best-effort basis, around what Linux pnpdump configs and kernel logs could be found + in mailing lists, forums and other places, as well as Linux's own SB PnP card tables for ALSA and OSS. */ static uint8_t sb_16_pnp_rom[] = { 0x0e, 0x8c, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0028, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ @@ -87,14 +91,19 @@ static uint8_t sb_16_pnp_rom[] = { 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */ 0x38, /* end dependent functions */ + 0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */ + 0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */ + 0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ }; static uint8_t sb_32_pnp_rom[] = { - 0x0e, 0x8c, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL009C, dummy checksum (filled in by isapnp_add_card) */ + 0x0e, 0x8c, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0048, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ 0x82, 0x11, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', '3', '2', ' ', 'P', 'n', 'P', /* ANSI identifier */ - 0x16, 0x0e, 0x8c, 0x00, 0x41, 0x00, 0xa9, /* logical device CTL0041, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */ + 0x16, 0x0e, 0x8c, 0x00, 0x31, 0x00, 0xa9, /* logical device CTL0031, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */ 0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */ 0x31, 0x00, /* start dependent functions, preferred */ 0x22, 0x20, 0x00, /* IRQ 5 */ @@ -153,14 +162,19 @@ static uint8_t sb_32_pnp_rom[] = { 0x47, 0x01, 0x20, 0x06, 0x80, 0x06, 0x20, 0x04, /* I/O 0x620-0x680, decodes 16-bit, 32-byte alignment, 4 addresses */ 0x38, /* end dependent functions */ + 0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */ + 0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */ + 0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ }; static uint8_t sb_awe32_pnp_rom[] = { - 0x0e, 0x8c, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL009A, dummy checksum (filled in by isapnp_add_card) */ + 0x0e, 0x8c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0043, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ 0x82, 0x15, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', ' ', 'A', 'W', 'E', '3', '2', ' ', 'P', 'n', 'P', /* ANSI identifier */ - 0x16, 0x0e, 0x8c, 0x00, 0x41, 0x00, 0xa9, /* logical device CTL0041, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */ + 0x16, 0x0e, 0x8c, 0x00, 0x31, 0x00, 0xa9, /* logical device CTL0031, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */ 0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */ 0x31, 0x00, /* start dependent functions, preferred */ 0x22, 0x20, 0x00, /* IRQ 5 */ @@ -223,6 +237,11 @@ static uint8_t sb_awe32_pnp_rom[] = { 0x47, 0x01, 0x20, 0x0e, 0x80, 0x0e, 0x20, 0x04, /* I/O 0xE20-0xE80, decodes 16-bit, 32-byte alignment, 4 addresses */ 0x38, /* end dependent functions */ + 0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */ + 0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */ + 0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ }; @@ -1188,69 +1207,75 @@ sb_pro_mcv_write(int port, uint8_t val, void *p) static void sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) { - if (ld != 0) - return; - sb_t *sb = (sb_t *) priv; uint16_t addr = sb->dsp.sb_addr; uint8_t val; - io_removehandler(addr, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - io_removehandler(addr + 8, 0x0002, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - io_removehandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, - sb_ct1745_mixer_write, NULL, NULL, sb); + switch (ld) { + case 0: /* Audio */ + io_removehandler(addr, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + io_removehandler(addr + 8, 0x0002, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + io_removehandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, sb); - addr = sb->opl_pnp_addr; - if (addr) { - sb->opl_pnp_addr = 0; - io_removehandler(addr, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - } + addr = sb->opl_pnp_addr; + if (addr) { + sb->opl_pnp_addr = 0; + io_removehandler(addr, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + } - sb_dsp_setaddr(&sb->dsp, 0); - sb_dsp_setirq(&sb->dsp, 0); - sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED); - sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED); + sb_dsp_setaddr(&sb->dsp, 0); + sb_dsp_setirq(&sb->dsp, 0); + sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED); + sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED); - mpu401_change_addr(sb->mpu, 0); + mpu401_change_addr(sb->mpu, 0); - if (config->activate) { - addr = config->io[0].base; - if (addr != ISAPNP_IO_DISABLED) { - io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, - sb_ct1745_mixer_write, NULL, NULL, sb); + if (config->activate) { + addr = config->io[0].base; + if (addr != ISAPNP_IO_DISABLED) { + io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, sb); - sb_dsp_setaddr(&sb->dsp, addr); - } + sb_dsp_setaddr(&sb->dsp, addr); + } - addr = config->io[1].base; - if (addr != ISAPNP_IO_DISABLED) - mpu401_change_addr(sb->mpu, addr); + addr = config->io[1].base; + if (addr != ISAPNP_IO_DISABLED) + mpu401_change_addr(sb->mpu, addr); - addr = config->io[2].base; - if (addr != ISAPNP_IO_DISABLED) { - sb->opl_pnp_addr = addr; - io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - } + addr = config->io[2].base; + if (addr != ISAPNP_IO_DISABLED) { + sb->opl_pnp_addr = addr; + io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + } - val = config->irq[0].irq; - if (val != ISAPNP_IRQ_DISABLED) - sb_dsp_setirq(&sb->dsp, val); + val = config->irq[0].irq; + if (val != ISAPNP_IRQ_DISABLED) + sb_dsp_setirq(&sb->dsp, val); - val = config->dma[0].dma; - if (val != ISAPNP_DMA_DISABLED) - sb_dsp_setdma8(&sb->dsp, val); + val = config->dma[0].dma; + if (val != ISAPNP_DMA_DISABLED) + sb_dsp_setdma8(&sb->dsp, val); - val = config->dma[1].dma; - if (val != ISAPNP_DMA_DISABLED) - sb_dsp_setdma16(&sb->dsp, val); + val = config->dma[1].dma; + if (val != ISAPNP_DMA_DISABLED) + sb_dsp_setdma16(&sb->dsp, val); + } + + break; + + case 1: /* Game */ + gameport_remap(sb->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + break; } } @@ -1259,21 +1284,18 @@ static void sb_awe32_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) { sb_t *sb = (sb_t *) priv; - uint16_t addr; switch (ld) { - case 0: + case 0: /* Audio */ sb_16_pnp_config_changed(0, config, sb); break; - case 1: - emu8k_change_addr(&sb->emu8k, 0); + case 1: /* WaveTable */ + emu8k_change_addr(&sb->emu8k, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + break; - if (config->activate) { - addr = config->io[0].base; - if (addr != ISAPNP_IO_DISABLED) - emu8k_change_addr(&sb->emu8k, addr); - } + case 2: /* Game */ + sb_16_pnp_config_changed(1, config, sb); break; } } @@ -1701,6 +1723,8 @@ sb_16_pnp_init(const device_t *info) if (device_get_config_int("receive_input")) midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + sb->gameport = gameport_add(&gameport_pnp_device); + isapnp_add_card(sb_16_pnp_rom, sizeof(sb_16_pnp_rom), sb_16_pnp_config_changed, NULL, NULL, NULL, sb); return sb; @@ -1796,6 +1820,8 @@ sb_awe32_pnp_init(const device_t *info) if (device_get_config_int("receive_input")) midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + sb->gameport = gameport_add(&gameport_pnp_device); + if (info->local == 1) isapnp_add_card(sb_32_pnp_rom, sizeof(sb_32_pnp_rom), sb_awe32_pnp_config_changed, NULL, NULL, NULL, sb); else From 7461108f38142c2210202941fde8b2b8ed04ff29 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 20 May 2021 23:06:29 -0300 Subject: [PATCH 05/25] Crystal CS4237, part 3: just the game port --- src/sound/snd_cs423x.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 88f15c49c..d7a332b7b 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -26,6 +26,7 @@ #include <86box/pic.h> #include <86box/dma.h> #include <86box/device.h> +#include <86box/gameport.h> #include <86box/i2c.h> #include <86box/isapnp.h> #include <86box/sound.h> @@ -92,15 +93,15 @@ static const uint8_t cs4237b_eeprom[] = { 0x47, 0x01, 0x88, 0x03, 0xf8, 0x03, 0x08, 0x04, /* I/O 0x388-0x3F8, decodes 16-bit, 8-byte alignment, 4 addresses */ 0x47, 0x01, 0x20, 0x02, 0x00, 0x03, 0x20, 0x10, /* I/O 0x220-0x300, decodes 16-bit, 32-byte alignment, 16 addresses */ 0x38, /* end dependent functions */ -#if 0 + 0x15, 0x0e, 0x63, 0x00, 0x01, 0x00, /* logical device CSC0001 */ 0x82, 0x05, 0x00, 'G', 'A', 'M', 'E', 0x00, /* ANSI identifier */ 0x31, 0x00, /* start dependent functions, preferred */ 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */ 0x31, 0x01, /* start dependent functions, acceptable */ - 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x47, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */ 0x38, /* end dependent functions */ -#endif + 0x15, 0x0e, 0x63, 0x00, 0x10, 0x00, /* logical device CSC0010 */ 0x82, 0x05, 0x00, 'C', 'T', 'R', 'L', 0x00, /* ANSI identifier */ 0x47, 0x01, 0x20, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x120-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ @@ -126,6 +127,7 @@ typedef struct cs423x_t void *pnp_card; ad1848_t ad1848; sb_t *sb; + void *gameport; void *i2c, *eeprom; uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11; @@ -452,7 +454,7 @@ cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) /* Fire the context switch interrupt if enabled. */ if (switched && (dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { dev->regs[7] |= 0x40; /* set interrupt flag */ - picint(1 << dev->ad1848.irq); /* control device shares its IRQ with WSS and SBPro */ + picint(1 << dev->ad1848.irq); /* control device shares IRQ with WSS and SBPro */ } } @@ -542,17 +544,11 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv break; -#if 0 case 1: /* Game Port */ - gameport_remap(0); - - if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) - gameport_remap(config->io[0].base); - + gameport_remap(dev->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); break; -#endif - case 1: /* Control Registers */ + case 2: /* Control Registers */ if (dev->ctrl_base) { io_removehandler(dev->ctrl_base, 8, cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, dev); dev->ctrl_base = 0; @@ -565,7 +561,7 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv break; - case 2: /* MPU-401 */ + case 3: /* MPU-401 */ mpu401_change_addr(dev->sb->mpu, 0); mpu401_setirq(dev->sb->mpu, 0); @@ -616,9 +612,12 @@ cs423x_init(const device_t *info) /* Initialize codecs. */ dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); - ad1848_init(&dev->ad1848, AD1848_TYPE_CS4236); + ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); sound_add_handler(cs423x_get_buffer, dev); + /* Initialize game port. */ + dev->gameport = gameport_add(&gameport_pnp_device); + /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); From ef4c900b8fd13d17045b67d43596616b1c4b2508 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 20 May 2021 23:17:07 -0300 Subject: [PATCH 06/25] Clean up formatting on the AD1848 and WSS code --- src/include/86box/snd_ad1848.h | 82 +++-- src/sound/snd_ad1848.c | 562 +++++++++++++++++---------------- src/sound/snd_wss.c | 332 +++++++++---------- 3 files changed, 520 insertions(+), 456 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index a25e46951..d1f4a4499 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -1,45 +1,65 @@ +/* + * 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. + * + * Definitions for AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation. + * + * + * + * Authors: Sarah Walker, + * TheCollector1995, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2018-2020 TheCollector1995. + */ + #define AD1848_TYPE_DEFAULT 0 #define AD1848_TYPE_CS4248 1 #define AD1848_TYPE_CS4231 2 #define AD1848_TYPE_CS4236 3 -typedef struct ad1848_t -{ - int index; - uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */ - uint8_t status; - - int trd; - int mce; - - int count; - - int16_t out_l, out_r; - double cd_vol_l, cd_vol_r; +typedef struct { + int index; + uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */ + uint8_t status; + + int trd; + int mce; + + int count; + + int16_t out_l, out_r; - int enable; + double cd_vol_l, cd_vol_r; - int irq, dma; - - int freq; - - pc_timer_t timer_count; - uint64_t timer_latch; + int enable; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; - - int type; + int irq, dma; + + int freq; + + pc_timer_t timer_count; + uint64_t timer_latch; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; + + int type; } ad1848_t; -void ad1848_setirq(ad1848_t *ad1848, int irq); -void ad1848_setdma(ad1848_t *ad1848, int dma); -uint8_t ad1848_read(uint16_t addr, void *p); -void ad1848_write(uint16_t addr, uint8_t val, void *p); +extern void ad1848_setirq(ad1848_t *ad1848, int irq); +extern void ad1848_setdma(ad1848_t *ad1848, int dma); -void ad1848_update(ad1848_t *ad1848); -void ad1848_speed_changed(ad1848_t *ad1848); +extern uint8_t ad1848_read(uint16_t addr, void *p); +extern void ad1848_write(uint16_t addr, uint8_t val, void *p); -void ad1848_init(ad1848_t *ad1848, int type); +extern void ad1848_update(ad1848_t *ad1848); +extern void ad1848_speed_changed(ad1848_t *ad1848); + +extern void ad1848_init(ad1848_t *ad1848, int type); diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index c45d69063..51c0423bd 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -1,6 +1,21 @@ /* - AD1848 / CS4248 / CS4231 CODEC emulation (Windows Sound System compatible)*/ - + * 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. + * + * AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation. + * + * + * + * Authors: Sarah Walker, + * TheCollector1995, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2018-2020 TheCollector1995. + */ #include #include #include @@ -13,302 +28,317 @@ #include <86box/sound.h> #include <86box/snd_ad1848.h> + #define CS4231 0x80 #define CS4236 0x03 -static int ad1848_vols_6bits[64]; -static double ad1848_vols_5bits_aux_gain[32]; + +static int ad1848_vols_6bits[64]; +static double ad1848_vols_5bits_aux_gain[32]; -void ad1848_setirq(ad1848_t *ad1848, int irq) +void +ad1848_setirq(ad1848_t *ad1848, int irq) { - ad1848->irq = irq; + ad1848->irq = irq; } -void ad1848_setdma(ad1848_t *ad1848, int dma) + +void +ad1848_setdma(ad1848_t *ad1848, int dma) { - ad1848->dma = dma; + ad1848->dma = dma; } -uint8_t ad1848_read(uint16_t addr, void *p) + +uint8_t +ad1848_read(uint16_t addr, void *priv) { - ad1848_t *ad1848 = (ad1848_t *)p; - uint8_t temp = 0xff; - switch (addr & 3) - { - case 0: /*Index*/ - temp = ad1848->index | ad1848->trd | ad1848->mce; - break; - case 1: - temp = ad1848->regs[ad1848->index]; - if (ad1848->index == 0x0b) { - temp ^= 0x20; - ad1848->regs[ad1848->index] = temp; + ad1848_t *ad1848 = (ad1848_t *) priv; + uint8_t ret = 0xff; + + switch (addr & 3) { + case 0: /*Index*/ + ret = ad1848->index | ad1848->trd | ad1848->mce; + break; + + case 1: + ret = ad1848->regs[ad1848->index]; + if (ad1848->index == 0x0b) { + ret ^= 0x20; + ad1848->regs[ad1848->index] = ret; } - break; - case 2: - temp = ad1848->status; - break; - } - return temp; + break; + + case 2: + ret = ad1848->status; + break; + } + + return ret; } -void ad1848_write(uint16_t addr, uint8_t val, void *p) + +void +ad1848_write(uint16_t addr, uint8_t val, void *priv) { - ad1848_t *ad1848 = (ad1848_t *)p; - double freq; - switch (addr & 3) - { - case 0: /*Index*/ - if ((ad1848->regs[12] & 0x40) && (ad1848->type >= AD1848_TYPE_CS4231)) - ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ - else - ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ - ad1848->trd = val & 0x20; - ad1848->mce = val & 0x40; - break; - case 1: - switch (ad1848->index) - { - case 8: - freq = (val & 1) ? 16934400LL : 24576000LL; - switch ((val >> 1) & 7) - { - case 0: freq /= 3072; break; - case 1: freq /= 1536; break; - case 2: freq /= 896; break; - case 3: freq /= 768; break; - case 4: freq /= 448; break; - case 5: freq /= 384; break; - case 6: freq /= 512; break; - case 7: freq /= 2560; break; - } - ad1848->freq = freq; - ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); - break; - - case 9: - if (!ad1848->enable && (val & 0x41) == 0x01) { - if (ad1848->timer_latch) - timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch); - else - timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC); - } - ad1848->enable = ((val & 0x41) == 0x01); - if (!ad1848->enable) { - timer_disable(&ad1848->timer_count); - ad1848->out_l = ad1848->out_r = 0; - } - break; - - - case 11: - break; - - case 12: - if (ad1848->type != AD1848_TYPE_DEFAULT) - ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; - return; - - case 14: - ad1848->count = ad1848->regs[15] | (val << 8); - break; + ad1848_t *ad1848 = (ad1848_t *) priv; + double freq; + switch (addr & 3) { + case 0: /* Index */ + if ((ad1848->regs[12] & 0x40) && (ad1848->type >= AD1848_TYPE_CS4231)) + ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ + else + ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ + ad1848->trd = val & 0x20; + ad1848->mce = val & 0x40; + break; - case 24: - if (! (val & 0x70)) - ad1848->status &= 0xfe; - break; - - case 25: + case 1: + switch (ad1848->index) { + case 8: + freq = (val & 1) ? 16934400LL : 24576000LL; + switch ((val >> 1) & 7) { + case 0: freq /= 3072; break; + case 1: freq /= 1536; break; + case 2: freq /= 896; break; + case 3: freq /= 768; break; + case 4: freq /= 448; break; + case 5: freq /= 384; break; + case 6: freq /= 512; break; + case 7: freq /= 2560; break; + } + ad1848->freq = freq; + ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + break; + + case 9: + if (!ad1848->enable && (val & 0x41) == 0x01) { + if (ad1848->timer_latch) + timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch); + else + timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC); + } + ad1848->enable = ((val & 0x41) == 0x01); + if (!ad1848->enable) { + timer_disable(&ad1848->timer_count); + ad1848->out_l = ad1848->out_r = 0; + } break; - } - ad1848->regs[ad1848->index] = val; - if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ - if (ad1848->regs[0x12] & 0x80) - ad1848->cd_vol_l = 0; - else - ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; - if (ad1848->regs[0x13] & 0x80) - ad1848->cd_vol_r = 0; - else - ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; - } - break; - case 2: - ad1848->status &= 0xfe; - break; - } + case 11: + break; + + case 12: + if (ad1848->type != AD1848_TYPE_DEFAULT) + ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; + return; + + case 14: + ad1848->count = ad1848->regs[15] | (val << 8); + break; + + case 24: + if (!(val & 0x70)) + ad1848->status &= 0xfe; + break; + + case 25: + break; + } + ad1848->regs[ad1848->index] = val; + + if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ + if (ad1848->regs[0x12] & 0x80) + ad1848->cd_vol_l = 0; + else + ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; + if (ad1848->regs[0x13] & 0x80) + ad1848->cd_vol_r = 0; + else + ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; + } + break; + + case 2: + ad1848->status &= 0xfe; + break; + } } -void ad1848_speed_changed(ad1848_t *ad1848) + +void +ad1848_speed_changed(ad1848_t *ad1848) { - ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); } -void ad1848_update(ad1848_t *ad1848) + +void +ad1848_update(ad1848_t *ad1848) { - for (; ad1848->pos < sound_pos_global; ad1848->pos++) - { - ad1848->buffer[ad1848->pos*2] = ad1848->out_l; - ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r; - } + for (; ad1848->pos < sound_pos_global; ad1848->pos++) { + ad1848->buffer[ad1848->pos*2] = ad1848->out_l; + ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r; + } } -static void ad1848_poll(void *p) + +static void +ad1848_poll(void *priv) { - ad1848_t *ad1848 = (ad1848_t *)p; - - if (ad1848->timer_latch) - timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch); - else - timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000); + ad1848_t *ad1848 = (ad1848_t *) priv; - ad1848_update(ad1848); - - if (ad1848->enable) - { - int32_t temp; - - switch (ad1848->regs[8] & 0x70) - { - case 0x00: /*Mono, 8-bit PCM*/ - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - case 0x10: /*Stereo, 8-bit PCM*/ - ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - - case 0x40: /*Mono, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; - case 0x50: /*Stereo, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; - temp = dma_channel_read(ad1848->dma); - ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; - } + if (ad1848->timer_latch) + timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch); + else + timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000); - if (ad1848->regs[6] & 0x80) - ad1848->out_l = 0; - else - ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16; + ad1848_update(ad1848); - if (ad1848->regs[7] & 0x80) - ad1848->out_r = 0; - else - ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; - - if (ad1848->count < 0) - { - ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); - if (!(ad1848->status & 0x01)) - { - ad1848->status |= 0x01; - if (ad1848->regs[10] & 2) - picint(1 << ad1848->irq); - } - } - - ad1848->count--; - } - else - { - ad1848->out_l = ad1848->out_r = 0; - ad1848->cd_vol_l = ad1848->cd_vol_r = 0; - } -} - -static void ad1848_filter_cd_audio(int channel, double *buffer, void *p) -{ - ad1848_t *ad1848 = (ad1848_t *)p; - double c; - double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; - - c = ((*buffer) * volume) / 65536.0; - *buffer = c; -} - -void ad1848_init(ad1848_t *ad1848, int type) -{ - int c; - double attenuation; - - ad1848->status = 0xcc; - ad1848->index = ad1848->trd = 0; - ad1848->mce = 0x40; - - ad1848->regs[0] = ad1848->regs[1] = 0; - ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */ - ad1848->regs[4] = ad1848->regs[5] = 0x80; - ad1848->regs[6] = ad1848->regs[7] = 0x80; /* Left/right Output */ - ad1848->regs[8] = 0; - ad1848->regs[9] = 0x08; - ad1848->regs[10] = ad1848->regs[11] = 0; - if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type == AD1848_TYPE_CS4236)) - ad1848->regs[12] = 0x8a; - else - ad1848->regs[12] = 0xa; - ad1848->regs[13] = 0; - ad1848->regs[14] = ad1848->regs[15] = 0; - - if (type == AD1848_TYPE_CS4231) { - ad1848->regs[16] = ad1848->regs[17] = 0; - ad1848->regs[18] = ad1848->regs[19] = 0x88; - ad1848->regs[22] = 0x80; - ad1848->regs[24] = 0; - ad1848->regs[25] = CS4231; - ad1848->regs[26] = 0x80; - ad1848->regs[29] = 0x80; - } else if (type == AD1848_TYPE_CS4236) { - ad1848->regs[16] = ad1848->regs[17] = 0; - ad1848->regs[18] = ad1848->regs[19] = 0; - ad1848->regs[20] = ad1848->regs[21] = 0; - ad1848->regs[22] = ad1848->regs[23] = 0; - ad1848->regs[24] = 0; - ad1848->regs[25] = CS4236; - ad1848->regs[26] = 0xa0; - ad1848->regs[27] = ad1848->regs[29] = 0; - ad1848->regs[30] = ad1848->regs[31] = 0; - } + if (ad1848->enable) { + int32_t temp; - ad1848->out_l = 0; - ad1848->out_r = 0; - - for (c = 0; c < 64; c++) { - attenuation = 0.0; - if (c & 0x01) attenuation -= 1.5; - if (c & 0x02) attenuation -= 3.0; - if (c & 0x04) attenuation -= 6.0; - if (c & 0x08) attenuation -= 12.0; - if (c & 0x10) attenuation -= 24.0; - if (c & 0x20) attenuation -= 48.0; - - attenuation = pow(10, attenuation / 10); - - ad1848_vols_6bits[c] = (int)(attenuation * 65536); - } - - for (c = 0; c < 32; c++) { - attenuation = 12.0; - if (c & 0x01) attenuation -= 1.5; - if (c & 0x02) attenuation -= 3.0; - if (c & 0x04) attenuation -= 6.0; - if (c & 0x08) attenuation -= 12.0; - if (c & 0x10) attenuation -= 24.0; - - attenuation = pow(10, attenuation / 10); - - ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); - } + switch (ad1848->regs[8] & 0x70) { + case 0x00: /*Mono, 8-bit PCM*/ + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + case 0x10: /*Stereo, 8-bit PCM*/ + ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; - ad1848->type = type; - - timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); + case 0x40: /*Mono, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + case 0x50: /*Stereo, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + } - if (ad1848->type != AD1848_TYPE_DEFAULT && ad1848->type != AD1848_TYPE_CS4248) - sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); + if (ad1848->regs[6] & 0x80) + ad1848->out_l = 0; + else + ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16; + + if (ad1848->regs[7] & 0x80) + ad1848->out_r = 0; + else + ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; + + if (ad1848->count < 0) + { + ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); + if (!(ad1848->status & 0x01)) + { + ad1848->status |= 0x01; + if (ad1848->regs[10] & 2) + picint(1 << ad1848->irq); + } + } + + ad1848->count--; + } else { + ad1848->out_l = ad1848->out_r = 0; + ad1848->cd_vol_l = ad1848->cd_vol_r = 0; + } +} + + +static void +ad1848_filter_cd_audio(int channel, double *buffer, void *priv) +{ + ad1848_t *ad1848 = (ad1848_t *) priv; + double c; + double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; + + c = ((*buffer) * volume) / 65536.0; + *buffer = c; +} + + +void +ad1848_init(ad1848_t *ad1848, int type) +{ + int c; + double attenuation; + + ad1848->status = 0xcc; + ad1848->index = ad1848->trd = 0; + ad1848->mce = 0x40; + + ad1848->regs[0] = ad1848->regs[1] = 0; + ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */ + ad1848->regs[4] = ad1848->regs[5] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; /* Left/right Output */ + ad1848->regs[8] = 0; + ad1848->regs[9] = 0x08; + ad1848->regs[10] = ad1848->regs[11] = 0; + if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type == AD1848_TYPE_CS4236)) + ad1848->regs[12] = 0x8a; + else + ad1848->regs[12] = 0xa; + ad1848->regs[13] = 0; + ad1848->regs[14] = ad1848->regs[15] = 0; + + if (type == AD1848_TYPE_CS4231) { + ad1848->regs[16] = ad1848->regs[17] = 0; + ad1848->regs[18] = ad1848->regs[19] = 0x88; + ad1848->regs[22] = 0x80; + ad1848->regs[24] = 0; + ad1848->regs[25] = CS4231; + ad1848->regs[26] = 0x80; + ad1848->regs[29] = 0x80; + } else if (type == AD1848_TYPE_CS4236) { + ad1848->regs[16] = ad1848->regs[17] = 0; + ad1848->regs[18] = ad1848->regs[19] = 0; + ad1848->regs[20] = ad1848->regs[21] = 0; + ad1848->regs[22] = ad1848->regs[23] = 0; + ad1848->regs[24] = 0; + ad1848->regs[25] = CS4236; + ad1848->regs[26] = 0xa0; + ad1848->regs[27] = ad1848->regs[29] = 0; + ad1848->regs[30] = ad1848->regs[31] = 0; + } + + ad1848->out_l = 0; + ad1848->out_r = 0; + + for (c = 0; c < 64; c++) { + attenuation = 0.0; + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + if (c & 0x20) attenuation -= 48.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols_6bits[c] = (int)(attenuation * 65536); + } + + for (c = 0; c < 32; c++) { + attenuation = 12.0; + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); + } + + ad1848->type = type; + + timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); + + if (ad1848->type != AD1848_TYPE_DEFAULT && ad1848->type != AD1848_TYPE_CS4248) + sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); } diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index f7f813098..d77b781ea 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -34,217 +34,231 @@ #include <86box/snd_opl.h> -/*530, 11, 3 - 530=23*/ -/*530, 11, 1 - 530=22*/ -/*530, 11, 0 - 530=21*/ -/*530, 10, 1 - 530=1a*/ -/*530, 9, 1 - 530=12*/ -/*530, 7, 1 - 530=0a*/ -/*604, 11, 1 - 530=22*/ -/*e80, 11, 1 - 530=22*/ -/*f40, 11, 1 - 530=22*/ +/* 530, 11, 3 - 530=23 + * 530, 11, 1 - 530=22 + * 530, 11, 0 - 530=21 + * 530, 10, 1 - 530=1a + * 530, 9, 1 - 530=12 + * 530, 7, 1 - 530=0a + * 604, 11, 1 - 530=22 + * e80, 11, 1 - 530=22 + * f40, 11, 1 - 530=22 + */ -static int wss_dma[4] = {0, 0, 1, 3}; -static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/ +static const int wss_dma[4] = {0, 0, 1, 3}; +static const int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /* W95 only uses 7-9, others may be wrong */ -typedef struct wss_t -{ - uint8_t config; - ad1848_t ad1848; - opl_t opl; +typedef struct wss_t { + uint8_t config; - int opl_enabled; - uint8_t pos_regs[8]; + ad1848_t ad1848; + opl_t opl; + + int opl_enabled; + uint8_t pos_regs[8]; } wss_t; -uint8_t wss_read(uint16_t addr, void *p) -{ - wss_t *wss = (wss_t *)p; - uint8_t temp; - temp = 4 | (wss->config & 0x40); - return temp; + +uint8_t +wss_read(uint16_t addr, void *priv) { + wss_t *wss = (wss_t *) priv; + return 4 | (wss->config & 0x40); } -void wss_write(uint16_t addr, uint8_t val, void *p) -{ - wss_t *wss = (wss_t *)p; - wss->config = val; - ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); - ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); +void +wss_write(uint16_t addr, uint8_t val, void *priv) +{ + wss_t *wss = (wss_t *) priv; + + wss->config = val; + ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); + ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); } -static void wss_get_buffer(int32_t *buffer, int len, void *p) + +static void +wss_get_buffer(int32_t *buffer, int len, void *priv) { - wss_t *wss = (wss_t *)p; - int c; + wss_t *wss = (wss_t *) priv; + int c; - opl3_update(&wss->opl); - ad1848_update(&wss->ad1848); - for (c = 0; c < len * 2; c++) { - buffer[c] += wss->opl.buffer[c]; - buffer[c] += (wss->ad1848.buffer[c] / 2); - } + opl3_update(&wss->opl); + ad1848_update(&wss->ad1848); + for (c = 0; c < len * 2; c++) { + buffer[c] += wss->opl.buffer[c]; + buffer[c] += (wss->ad1848.buffer[c] / 2); + } - wss->opl.pos = 0; - wss->ad1848.pos = 0; + wss->opl.pos = 0; + wss->ad1848.pos = 0; } -void *wss_init(const device_t *info) + +void * +wss_init(const device_t *info) { - wss_t *wss = malloc(sizeof(wss_t)); - memset(wss, 0, sizeof(wss_t)); + wss_t *wss = malloc(sizeof(wss_t)); + memset(wss, 0, sizeof(wss_t)); - uint16_t addr = device_get_config_hex16("base"); - wss->opl_enabled = device_get_config_int("opl"); + uint16_t addr = device_get_config_hex16("base"); + wss->opl_enabled = device_get_config_int("opl"); - if (wss->opl_enabled) - opl3_init(&wss->opl); - - ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); + if (wss->opl_enabled) + opl3_init(&wss->opl); - ad1848_setirq(&wss->ad1848, 7); - ad1848_setdma(&wss->ad1848, 3); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - if (wss->opl_enabled) + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); + + if (wss->opl_enabled) + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + + io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + sound_add_handler(wss_get_buffer, wss); + + return wss; +} + + +static uint8_t +ncr_audio_mca_read(int port, void *priv) +{ + wss_t *wss = (wss_t *) priv; + return wss->pos_regs[port & 7]; +} + + +static void +ncr_audio_mca_write(int port, uint8_t val, void *priv) +{ + wss_t *wss = (wss_t *) priv; + uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604}; + uint16_t addr; + + if (port < 0x102) + return; + + wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0; + addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + + io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + wss->pos_regs[port & 7] = val; + + if (wss->pos_regs[2] & 1) { + addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + + if (wss->opl_enabled) io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - + io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); - - sound_add_handler(wss_get_buffer, wss); - - return wss; + } } -static uint8_t ncr_audio_mca_read(int port, void *p) + +static uint8_t +ncr_audio_mca_feedb(void *priv) { - wss_t *wss = (wss_t *)p; - - return wss->pos_regs[port & 7]; + wss_t *wss = (wss_t *) priv; + return (wss->pos_regs[2] & 1); } -static void ncr_audio_mca_write(int port, uint8_t val, void *p) + +void * +ncr_audio_init(const device_t *info) { - wss_t *wss = (wss_t *)p; - uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604}; - uint16_t addr; + wss_t *wss = malloc(sizeof(wss_t)); + memset(wss, 0, sizeof(wss_t)); - if (port < 0x102) - return; + opl3_init(&wss->opl); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0; - addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; - - io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); - wss->pos_regs[port & 7] = val; + mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss); + wss->pos_regs[0] = 0x16; + wss->pos_regs[1] = 0x51; - if (wss->pos_regs[2] & 1) { - addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + sound_add_handler(wss_get_buffer, wss); - if (wss->opl_enabled) - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - - io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); - } + return wss; } -static uint8_t ncr_audio_mca_feedb(void *p) -{ - wss_t *wss = (wss_t *)p; - return (wss->pos_regs[2] & 1); +void +wss_close(void *priv) +{ + wss_t *wss = (wss_t *) priv; + free(wss); } -void *ncr_audio_init(const device_t *info) + +void +wss_speed_changed(void *priv) { - wss_t *wss = malloc(sizeof(wss_t)); - - memset(wss, 0, sizeof(wss_t)); - - opl3_init(&wss->opl); - ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - - ad1848_setirq(&wss->ad1848, 7); - ad1848_setdma(&wss->ad1848, 3); - - mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss); - wss->pos_regs[0] = 0x16; - wss->pos_regs[1] = 0x51; - - sound_add_handler(wss_get_buffer, wss); - - return wss; + wss_t *wss = (wss_t *) priv; + ad1848_speed_changed(&wss->ad1848); } -void wss_close(void *p) -{ - wss_t *wss = (wss_t *)p; - free(wss); -} - -void wss_speed_changed(void *p) -{ - wss_t *wss = (wss_t *)p; - - ad1848_speed_changed(&wss->ad1848); -} - -static const device_config_t wss_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x530, "", { 0 }, - { - { - "0x530", 0x530 - }, - { - "0x604", 0x604 - }, - { - "0xe80", 0xe80 - }, - { - "0xf40", 0xf40 - }, - { - "" - } - } - }, +static const device_config_t wss_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x530, "", { 0 }, { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 - } + { + "0x530", 0x530 + }, + { + "0x604", 0x604 + }, + { + "0xe80", 0xe80 + }, + { + "0xf40", 0xf40 + }, + { + "" + } + } + }, + { + "opl", "Enable OPL", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } }; + const device_t wss_device = { - "Windows Sound System", - DEVICE_ISA | DEVICE_AT, 0, - wss_init, wss_close, NULL, - { NULL }, - wss_speed_changed, - NULL, - wss_config + "Windows Sound System", + DEVICE_ISA | DEVICE_AT, 0, + wss_init, wss_close, NULL, + { NULL }, + wss_speed_changed, + NULL, + wss_config }; const device_t ncr_business_audio_device = { - "NCR Business Audio", - DEVICE_MCA, 0, - ncr_audio_init, wss_close, NULL, - { NULL }, - wss_speed_changed, - NULL, - NULL + "NCR Business Audio", + DEVICE_MCA, 0, + ncr_audio_init, wss_close, NULL, + { NULL }, + wss_speed_changed, + NULL, + NULL }; From f2f8d4a02e4bca5c7681c6a93ea283995b8e52a6 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 21 May 2021 12:52:14 -0300 Subject: [PATCH 07/25] Some AD1848 cleanups I forgot --- src/include/86box/snd_ad1848.h | 30 ++++++++++-------------------- src/sound/snd_ad1848.c | 10 +++++----- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index d1f4a4499..51579cd09 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -24,32 +24,22 @@ typedef struct { - int index; - uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */ - uint8_t status; + int index; + uint8_t regs[32], status; /* 16 original registers + 16 CS4231A extensions */ - int trd; - int mce; + int trd, mce, count; - int count; - - int16_t out_l, out_r; + int16_t out_l, out_r; - double cd_vol_l, cd_vol_r; + double cd_vol_l, cd_vol_r; - int enable; + int enable, irq, dma, freq; - int irq, dma; - - int freq; - - pc_timer_t timer_count; - uint64_t timer_latch; + pc_timer_t timer_count; + uint64_t timer_latch; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; - - int type; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos, type; } ad1848_t; diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 51c0423bd..c991ff381 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -40,14 +40,14 @@ static double ad1848_vols_5bits_aux_gain[32]; void ad1848_setirq(ad1848_t *ad1848, int irq) { - ad1848->irq = irq; + ad1848->irq = irq; } void ad1848_setdma(ad1848_t *ad1848, int dma) { - ad1848->dma = dma; + ad1848->dma = dma; } @@ -90,8 +90,8 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ else ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ - ad1848->trd = val & 0x20; - ad1848->mce = val & 0x40; + ad1848->trd = val & 0x20; + ad1848->mce = val & 0x40; break; case 1: @@ -109,7 +109,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 7: freq /= 2560; break; } ad1848->freq = freq; - ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); break; case 9: From c8c4aac16788ebfecee1b873308ba22661bea4ff Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 22 May 2021 22:27:21 -0300 Subject: [PATCH 08/25] ISAPnP tweaks: allow initialization with a null ROM; disable fatals for bad resource data; only change state on enable/disable if a change occurred. --- src/device/isapnp.c | 70 +++++++++++++++++++++++++++++++++++-------- src/sio/sio_um8669f.c | 2 +- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index e08e2d300..44885f837 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -527,7 +527,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) } if (!ld) - fatal("ISAPnP: CSN %02X has no device %02X\n", card->csn, val); + isapnp_log("ISAPnP: CSN %02X has no device %02X\n", card->csn, val); break; @@ -696,7 +696,9 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, prev_card->next = card; } - isapnp_update_card_rom(card, rom, rom_size); + if (rom && rom_size) + isapnp_update_card_rom(card, rom, rom_size); + return card; } @@ -737,15 +739,29 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) case 0x01: /* memory range */ case 0x05: /* 32-bit memory range */ if (res == 0x01) { - if (mem_range > 3) - fatal("ISAPnP: Memory descriptor overflow (%d)\n", mem_range); + if (!ld) { + isapnp_log("ISAPnP: >>%s Memory descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (mem_range > 3) { + isapnp_log("ISAPnP: >>%s Memory descriptor overflow (%d)\n", in_df ? ">" : "", mem_range++); + break; + } isapnp_log("ISAPnP: >>%s Memory range %d uses upper limit = ", in_df ? ">" : "", mem_range); res = 1 << mem_range; mem_range++; } else { - if (mem_range_32 > 3) - fatal("ISAPnP: 32-bit memory descriptor overflow (%d)\n", mem_range_32); + if (!ld) { + isapnp_log("ISAPnP: >>%s 32-bit memory descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (mem_range_32 > 3) { + isapnp_log("ISAPnP: >>%s 32-bit memory descriptor overflow (%d)\n", in_df ? ">" : "", mem_range_32++); + break; + } isapnp_log("ISAPnP: >>%s 32-bit memory range %d uses upper limit = ", in_df ? ">" : "", mem_range_32); res = 1 << (4 + mem_range_32); @@ -812,14 +828,26 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) #ifdef ENABLE_ISAPNP_LOG case 0x03: /* compatible device ID */ + if (!ld) { + isapnp_log("ISAPnP: >> Compatible device ID with no logical device\n"); + break; + } + vendor = (card->rom[i + 1] << 8) | card->rom[i + 2]; isapnp_log("ISAPnP: >> Compatible device ID: %c%c%c%02X%02X\n", '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[i + 3], card->rom[i + 4]); break; #endif case 0x04: /* IRQ */ - if (irq > 1) - fatal("ISAPnP: IRQ descriptor overflow (%d)\n", irq); + if (!ld) { + isapnp_log("ISAPnP: >>%s IRQ descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (irq > 1) { + isapnp_log("ISAPnP: >>%s IRQ descriptor overflow (%d)\n", in_df ? ">" : "", irq++); + break; + } if (len == 2) /* default */ res = 0x01; /* high true edge sensitive */ @@ -836,6 +864,11 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) break; case 0x06: /* start dependent function */ + if (!ld) { + isapnp_log("ISAPnP: >> Start dependent function with no logical device\n"); + break; + } + isapnp_log("ISAPnP: >> Start dependent function: %s\n", (((len == 0) || (card->rom[i + 1] == 1)) ? "acceptable" : ((card->rom[i + 1] == 0) ? "good" : ((card->rom[i + 1] == 2) ? "sub-optimal" : "unknown priority")))); if (in_df) { @@ -862,8 +895,15 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) break; case 0x08: /* I/O port */ - if (io > 7) - fatal("ISAPnP: I/O descriptor overflow (%d)\n", io); + if (!ld) { + isapnp_log("ISAPnP: >>%s I/O descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (io > 7) { + isapnp_log("ISAPnP: >>%s I/O descriptor overflow (%d)\n", in_df ? ">" : "", io++); + break; + } isapnp_log("ISAPnP: >>%s I/O range %d %d-bit decode, %d ports\n", in_df ? ">" : "", io, (card->rom[i + 1] & 0x01) ? 16 : 10, card->rom[i + 7]); @@ -887,6 +927,9 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) card->rom[i + 1] = -res; isapnp_log("ISAPnP: End card resources (checksum %02X)\n", card->rom[i + 1]); + + /* Stop parsing here. */ + card->rom_size = i + 2; break; #ifdef ENABLE_ISAPNP_LOG @@ -916,11 +959,14 @@ isapnp_enable_card(void *priv, uint8_t enable) /* Look for a matching card. */ isapnp_card_t *card = dev->first_card; + uint8_t will_enable; while (card) { if (card == priv) { /* Enable or disable the card. */ - card->enable = (enable >= ISAPNP_CARD_ENABLE); - card->state = (enable == ISAPNP_CARD_FORCE_CONFIG) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY; + will_enable = (enable >= ISAPNP_CARD_ENABLE); + if (will_enable ^ card->enable) + card->state = (enable == ISAPNP_CARD_FORCE_CONFIG) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY; + card->enable = will_enable; /* Invalidate other references if we're disabling this card. */ if (!card->enable) { diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index e7131bb45..5087c7439 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -251,7 +251,7 @@ um8669f_reset(um8669f_t *dev) lpt1_remove(); - isapnp_enable_card(dev->pnp_card, 0); + isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_DISABLE); dev->locked = 1; From 8b9b6c885d3c796033f04959be3e2f556ebd6aff Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 22 May 2021 22:28:42 -0300 Subject: [PATCH 09/25] Minor formatting cleanups --- src/sound/snd_sb.c | 2 +- src/sound/snd_wss.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 9712f9cc6..aa00b33a4 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1630,7 +1630,7 @@ sb_pro_cs423x_init(const device_t *info) sb_t *sb = malloc(sizeof(sb_t)); memset(sb, 0, sizeof(sb_t)); - sb->opl_enabled = 1; + sb->opl_enabled = 1; /* WSS can disable this to take ownership of the OPL */ opl3_init(&sb->opl); sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index d77b781ea..80b27cf9d 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -89,7 +89,7 @@ wss_get_buffer(int32_t *buffer, int len, void *priv) ad1848_update(&wss->ad1848); for (c = 0; c < len * 2; c++) { buffer[c] += wss->opl.buffer[c]; - buffer[c] += (wss->ad1848.buffer[c] / 2); + buffer[c] += wss->ad1848.buffer[c] / 2; } wss->opl.pos = 0; From 18289a9a647c6140145e7eeda10956643ee5d573 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 22 May 2021 22:29:25 -0300 Subject: [PATCH 10/25] Crystal CS4236, part 4: the one that took two days --- src/include/86box/snd_ad1848.h | 15 +- src/include/86box/sound.h | 2 +- src/sound/snd_ad1848.c | 334 +++++++++++++++++++++++++-------- src/sound/snd_cs423x.c | 220 ++++++++++++++-------- src/sound/sound.c | 2 +- 5 files changed, 413 insertions(+), 160 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index 51579cd09..ac1b1a85f 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -24,14 +24,15 @@ typedef struct { - int index; - uint8_t regs[32], status; /* 16 original registers + 16 CS4231A extensions */ + int index, xindex; + uint8_t regs[32], xregs[32], status; /* 16 original registers + 16 CS4231A extensions + 32 CS4236 extensions */ - int trd, mce, count; + int trd, mce, count, wten; int16_t out_l, out_r; - double cd_vol_l, cd_vol_r; + int fm_vol_l, fm_vol_r; + uint8_t fmt_mask, wave_vol_mask; int enable, irq, dma, freq; @@ -45,11 +46,13 @@ typedef struct { extern void ad1848_setirq(ad1848_t *ad1848, int irq); extern void ad1848_setdma(ad1848_t *ad1848, int dma); +extern void ad1848_updatevolmask(ad1848_t *ad1848); -extern uint8_t ad1848_read(uint16_t addr, void *p); -extern void ad1848_write(uint16_t addr, uint8_t val, void *p); +extern uint8_t ad1848_read(uint16_t addr, void *priv); +extern void ad1848_write(uint16_t addr, uint8_t val, void *priv); extern void ad1848_update(ad1848_t *ad1848); extern void ad1848_speed_changed(ad1848_t *ad1848); +extern void ad1848_filter_cd_audio(int channel, double *buffer, void *priv); extern void ad1848_init(ad1848_t *ad1848, int type); diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index af10917e0..d280460e5 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -125,7 +125,7 @@ extern const device_t wss_device; extern const device_t ncr_business_audio_device; /* Crystal CS423x */ -extern const device_t cs4237b_device; +extern const device_t cs4236b_device; #endif #endif /*EMU_SOUND_H*/ diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index c991ff381..3b452a607 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -29,12 +29,14 @@ #include <86box/snd_ad1848.h> -#define CS4231 0x80 -#define CS4236 0x03 +#define CS4231 0x80 +#define CS4236 0x03 -static int ad1848_vols_6bits[64]; +static int ad1848_vols_7bits[128]; static double ad1848_vols_5bits_aux_gain[32]; +static double ad1848_vols_7bits_debug[128]; +static double ad1848_vols_5bits_debug[32]; void @@ -51,6 +53,67 @@ ad1848_setdma(ad1848_t *ad1848, int dma) } +void +ad1848_updatevolmask(ad1848_t *ad1848) +{ + if ((ad1848->type == AD1848_TYPE_CS4236) && ((ad1848->xregs[4] & 0x10) || ad1848->wten)) + ad1848->wave_vol_mask = 0x3f; + else + ad1848->wave_vol_mask = 0x7f; +} + + +static void +ad1848_updatefreq(ad1848_t *ad1848) +{ + double freq; + uint8_t set = 0; + + if (ad1848->type == AD1848_TYPE_CS4236) { + if (ad1848->xregs[11] & 0x20) { + freq = 16934400LL; + switch (ad1848->xregs[13]) { + case 1: freq /= 353; break; + case 2: freq /= 529; break; + case 3: freq /= 617; break; + case 4: freq /= 1058; break; + case 5: freq /= 1764; break; + case 6: freq /= 2117; break; + case 7: freq /= 2558; break; + default: freq /= 16 * MAX(ad1848->xregs[13], 21); break; + } + set = 1; + } else if (ad1848->regs[22] & 0x80) { + freq = (ad1848->regs[22] & 1) ? 33868800LL : 49152000LL; + set = (ad1848->regs[22] >> 1) & 0x3f; + switch (ad1848->regs[10] & 0x30) { + case 0x00: freq /= 128 * set; break; + case 0x10: freq /= 64 * set; break; + case 0x20: freq /= 256 * set; break; + } + set = 1; + } + } + + if (!set) { + freq = (ad1848->regs[8] & 1) ? 16934400LL : 24576000LL; + switch ((ad1848->regs[8] >> 1) & 7) { + case 0: freq /= 3072; break; + case 1: freq /= 1536; break; + case 2: freq /= 896; break; + case 3: freq /= 768; break; + case 4: freq /= 448; break; + case 5: freq /= 384; break; + case 6: freq /= 512; break; + case 7: freq /= 2560; break; + } + } + + ad1848->freq = freq; + ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); +} + + uint8_t ad1848_read(uint16_t addr, void *priv) { @@ -58,15 +121,35 @@ ad1848_read(uint16_t addr, void *priv) uint8_t ret = 0xff; switch (addr & 3) { - case 0: /*Index*/ + case 0: /* Index */ ret = ad1848->index | ad1848->trd | ad1848->mce; break; case 1: ret = ad1848->regs[ad1848->index]; - if (ad1848->index == 0x0b) { - ret ^= 0x20; - ad1848->regs[ad1848->index] = ret; + switch (ad1848->index) { + case 11: + ret ^= 0x20; + ad1848->regs[ad1848->index] = ret; + break; + + case 18: case 19: + if (ad1848->type == AD1848_TYPE_CS4236) { + if (ad1848->xregs[4] & 0x04) /* FM remapping */ + return ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ + else if (ad1848->xregs[4] & 0x08) /* wavetable remapping */ + return ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */ + } + break; + + case 23: + if ((ad1848->type == AD1848_TYPE_CS4236) && (ad1848->regs[23] & 0x08)) { + if ((ad1848->xindex & 0xfe) == 0x00) /* remapped line volume */ + ret = ad1848->regs[18 + ad1848->xindex]; + else + ret = ad1848->xregs[ad1848->xindex]; + } + break; } break; @@ -83,33 +166,29 @@ void ad1848_write(uint16_t addr, uint8_t val, void *priv) { ad1848_t *ad1848 = (ad1848_t *) priv; - double freq; + uint8_t temp, updatefreq = 0; + switch (addr & 3) { case 0: /* Index */ if ((ad1848->regs[12] & 0x40) && (ad1848->type >= AD1848_TYPE_CS4231)) ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ else ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ + if (ad1848->type == AD1848_TYPE_CS4236) + ad1848->regs[23] &= ~0x08; /* clear XRAE */ ad1848->trd = val & 0x20; ad1848->mce = val & 0x40; break; case 1: switch (ad1848->index) { + case 10: + if (ad1848->type != AD1848_TYPE_CS4236) + break; + /* fall-through */ + case 8: - freq = (val & 1) ? 16934400LL : 24576000LL; - switch ((val >> 1) & 7) { - case 0: freq /= 3072; break; - case 1: freq /= 1536; break; - case 2: freq /= 896; break; - case 3: freq /= 768; break; - case 4: freq /= 448; break; - case 5: freq /= 384; break; - case 6: freq /= 512; break; - case 7: freq /= 2560; break; - } - ad1848->freq = freq; - ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); + updatefreq = 1; break; case 9: @@ -127,7 +206,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) break; case 11: - break; + return; case 12: if (ad1848->type != AD1848_TYPE_DEFAULT) @@ -138,25 +217,94 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) ad1848->count = ad1848->regs[15] | (val << 8); break; + case 17: + if (ad1848->type >= AD1848_TYPE_CS4231) /* enable additional data formats on modes 2 and 3 */ + ad1848->fmt_mask = (val & 0x40) ? 0xf0 : 0x70; + break; + + case 18: case 19: + if (ad1848->type == AD1848_TYPE_CS4236) { + if (ad1848->xregs[4] & 0x04) { /* FM remapping */ + temp = val; + val = ad1848->xregs[ad1848->index - 18]; /* real line volume on registers 0 and 1 */ + ad1848->xregs[ad1848->index - 12] = temp; /* real FM volume on registers 6 and 7 */ + } else if (ad1848->xregs[4] & 0x08) { /* wavetable remapping */ + temp = val; + val = ad1848->xregs[ad1848->index - 18]; /* real line volume on registers 0 and 1 */ + ad1848->xregs[ad1848->index - 2] = temp; /* real wavetable volume on registers 16 and 17 */ + } + } + break; + + case 22: + updatefreq = 1; + break; + + case 23: + if ((ad1848->type == AD1848_TYPE_CS4236) && ((ad1848->regs[12] & 0x60) == 0x60)) { + if (!(ad1848->regs[23] & 0x08)) { /* existing (not new) XRAE is clear */ + ad1848->xindex = (((val & 0x04) << 2) | (val >> 4)) & 0x1f; + break; + } + switch (ad1848->xindex) { + case 0: case 1: /* remapped line volume */ + ad1848->regs[18 + ad1848->xindex] = val; + return; + + case 6: + if (val & 0x80) + ad1848->fm_vol_l = 0; + else + ad1848->fm_vol_l = ad1848_vols_7bits[val & 0x3f]; + break; + + case 7: + if (val & 0x80) + ad1848->fm_vol_r = 0; + else + ad1848->fm_vol_r = ad1848_vols_7bits[val & 0x3f]; + break; + + case 11: case 13: + updatefreq = 1; + break; + + case 25: + return; + } + ad1848->xregs[ad1848->xindex] = val; + + if (updatefreq) + ad1848_updatefreq(ad1848); + + return; + } + break; + case 24: if (!(val & 0x70)) ad1848->status &= 0xfe; break; case 25: - break; + return; } ad1848->regs[ad1848->index] = val; - if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ - if (ad1848->regs[0x12] & 0x80) + if (updatefreq) + ad1848_updatefreq(ad1848); + + if ((ad1848->type == AD1848_TYPE_CS4231) || (ad1848->type == AD1848_TYPE_CS4236)) { /* TODO: configure CD volume for CS4248/AD1848 too */ + temp = (ad1848->type == AD1848_TYPE_CS4231) ? 18 : 4; + if (ad1848->regs[temp] & 0x80) ad1848->cd_vol_l = 0; else - ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; - if (ad1848->regs[0x13] & 0x80) + ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f]; + temp++; + if (ad1848->regs[temp] & 0x80) ad1848->cd_vol_r = 0; else - ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; + ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f]; } break; @@ -198,43 +346,55 @@ ad1848_poll(void *priv) if (ad1848->enable) { int32_t temp; + + switch (ad1848->regs[8] & ad1848->fmt_mask) { + case 0x00: /* Mono, 8-bit PCM */ + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + + case 0x10: /* Stereo, 8-bit PCM */ + ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; - switch (ad1848->regs[8] & 0x70) { - case 0x00: /*Mono, 8-bit PCM*/ - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - case 0x10: /*Stereo, 8-bit PCM*/ - ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - - case 0x40: /*Mono, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; - case 0x50: /*Stereo, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; - temp = dma_channel_read(ad1848->dma); - ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; + case 0x40: /* Mono, 16-bit PCM little endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + + case 0x50: /* Stereo, 16-bit PCM little endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + + case 0xc0: /* Mono, 16-bit PCM big endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = dma_channel_read(ad1848->dma) | (temp << 8); + break; + + case 0xd0: /* Stereo, 16-bit PCM big endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = dma_channel_read(ad1848->dma) | (temp << 8); + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = dma_channel_read(ad1848->dma) | (temp << 8); + break; } if (ad1848->regs[6] & 0x80) ad1848->out_l = 0; else - ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16; + ad1848->out_l = (ad1848->out_l * ad1848_vols_7bits[ad1848->regs[6] & ad1848->wave_vol_mask]) >> 16; if (ad1848->regs[7] & 0x80) ad1848->out_r = 0; else - ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; + ad1848->out_r = (ad1848->out_r * ad1848_vols_7bits[ad1848->regs[7] & ad1848->wave_vol_mask]) >> 16; - if (ad1848->count < 0) - { + if (ad1848->count < 0) { ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); - if (!(ad1848->status & 0x01)) - { + if (!(ad1848->status & 0x01)) { ad1848->status |= 0x01; if (ad1848->regs[10] & 2) picint(1 << ad1848->irq); @@ -249,7 +409,7 @@ ad1848_poll(void *priv) } -static void +void ad1848_filter_cd_audio(int channel, double *buffer, void *priv) { ad1848_t *ad1848 = (ad1848_t *) priv; @@ -270,7 +430,8 @@ ad1848_init(ad1848_t *ad1848, int type) ad1848->status = 0xcc; ad1848->index = ad1848->trd = 0; ad1848->mce = 0x40; - + ad1848->wten = 0; + ad1848->regs[0] = ad1848->regs[1] = 0; ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */ ad1848->regs[4] = ad1848->regs[5] = 0x80; @@ -284,7 +445,7 @@ ad1848_init(ad1848_t *ad1848, int type) ad1848->regs[12] = 0xa; ad1848->regs[13] = 0; ad1848->regs[14] = ad1848->regs[15] = 0; - + if (type == AD1848_TYPE_CS4231) { ad1848->regs[16] = ad1848->regs[17] = 0; ad1848->regs[18] = ad1848->regs[19] = 0x88; @@ -303,25 +464,42 @@ ad1848_init(ad1848_t *ad1848, int type) ad1848->regs[26] = 0xa0; ad1848->regs[27] = ad1848->regs[29] = 0; ad1848->regs[30] = ad1848->regs[31] = 0; - } - - ad1848->out_l = 0; - ad1848->out_r = 0; - for (c = 0; c < 64; c++) { - attenuation = 0.0; - if (c & 0x01) attenuation -= 1.5; - if (c & 0x02) attenuation -= 3.0; - if (c & 0x04) attenuation -= 6.0; - if (c & 0x08) attenuation -= 12.0; - if (c & 0x10) attenuation -= 24.0; - if (c & 0x20) attenuation -= 48.0; - - attenuation = pow(10, attenuation / 10); - - ad1848_vols_6bits[c] = (int)(attenuation * 65536); + ad1848->xregs[0] = ad1848->xregs[1] = 0xe8; + ad1848->xregs[2] = ad1848->xregs[3] = 0xcf; + ad1848->xregs[4] = 0x84; + ad1848->xregs[5] = 0; + ad1848->xregs[6] = ad1848->xregs[7] = 0x80; + ad1848->xregs[8] = ad1848->xregs[9] = 0; + ad1848->xregs[10] = 0x3f; + ad1848->xregs[11] = 0xc0; + ad1848->xregs[14] = ad1848->xregs[15] = 0; + ad1848->xregs[16] = ad1848->xregs[17] = 0; } - + + ad1848->out_l = ad1848->out_r = 0; + ad1848->fm_vol_l = ad1848->fm_vol_r = 1; + ad1848_updatevolmask(ad1848); + ad1848->fmt_mask = 0x70; + + for (c = 0; c < 128; c++) { + attenuation = 0.0; + if (c & 0x40) { + if (c < 72) attenuation = (c - 72) * -1.5; + } else { + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + if (c & 0x20) attenuation -= 48.0; + } +ad1848_vols_7bits_debug[c] = attenuation; + attenuation = pow(10, attenuation / 10); + + ad1848_vols_7bits[c] = (int) (attenuation * 65536); + } + for (c = 0; c < 32; c++) { attenuation = 12.0; if (c & 0x01) attenuation -= 1.5; @@ -329,16 +507,16 @@ ad1848_init(ad1848_t *ad1848, int type) if (c & 0x04) attenuation -= 6.0; if (c & 0x08) attenuation -= 12.0; if (c & 0x10) attenuation -= 24.0; - +ad1848_vols_5bits_debug[c] = attenuation; attenuation = pow(10, attenuation / 10); ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); - } - + } + ad1848->type = type; - + timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); - if (ad1848->type != AD1848_TYPE_DEFAULT && ad1848->type != AD1848_TYPE_CS4248) + if ((ad1848->type != AD1848_TYPE_DEFAULT) && (ad1848->type != AD1848_TYPE_CS4248)) sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); } diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index d7a332b7b..b95d0618d 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -37,7 +37,9 @@ enum { - CRYSTAL_CS4237B = 0xc8 + CRYSTAL_CS4236B = 0xcb, + CRYSTAL_CS4237B = 0xc8, + CRYSTAL_CS4238B = 0xc9 }; enum { CRYSTAL_SLAM_NONE = 0, @@ -51,8 +53,8 @@ static const uint8_t slam_init_key[32] = { 0x96, 0x35, 0x9A, 0xCD, 0xE6, 0xF3, 0 0x5E, 0xAF, 0x57, 0x2B, 0x15, 0x8A, 0xC5, 0xE2, 0xF1, 0xF8, 0x7C, 0x3E, 0x9F, 0x4F, 0x27, 0x13, 0x09, 0x84, 0x42, 0xA1, 0xD0, 0x68, 0x34, 0x1A }; -static const uint8_t cs4237b_eeprom[] = { - /* CS4237B configuration */ +static const uint8_t cs4236b_eeprom[] = { + /* Chip configuration */ 0x55, 0xbb, /* magic */ 0x00, 0x00, /* length */ 0x00, 0x03, /* CD-ROM and modem decode */ @@ -66,7 +68,7 @@ static const uint8_t cs4237b_eeprom[] = { 0x10, 0x03, /* DMA routing */ /* PnP resources */ - 0x0e, 0x63, 0x42, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, /* CSC4237, dummy checksum (filled in by isapnp_add_card) */ + 0x0e, 0x63, 0x42, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, /* CSC4236, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x01, /* PnP version 1.0, vendor version 0.1 */ 0x82, 0x0e, 0x00, 'C', 'r', 'y', 's', 't', 'a', 'l', ' ', 'C', 'o', 'd', 'e' ,'c', 0x00, /* ANSI identifier */ @@ -131,14 +133,16 @@ typedef struct cs423x_t void *i2c, *eeprom; uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11; - uint8_t type, regs[8], indirect_regs[16], eeprom_data[2048], ram_dl; + uint8_t type, pnp_offset, regs[8], indirect_regs[16], eeprom_data[2048], ram_data[384], ram_dl; + int ad1848_type; - uint8_t key_pos: 5, enable_slam: 1, slam_state: 2, slam_ld, slam_reg; + uint8_t pnp_enable: 1, key_pos: 5, slam_enable: 1, slam_state: 2, slam_ld, slam_reg; isapnp_device_config_t *slam_config; } cs423x_t; -static void cs423x_slam_remap(cs423x_t *dev, uint8_t enable); +static void cs423x_slam_enable(cs423x_t *dev, uint8_t enable); +static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom); static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv); static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); @@ -183,7 +187,6 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; uint8_t reg = port & 7; - uint16_t eeprom_addr; switch (reg) { case 1: /* EEPROM Interface */ @@ -199,7 +202,7 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) switch (dev->regs[3] & 15) { case 0: /* WSS Master Control */ if (val & 0x80) - ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); + ad1848_init(&dev->ad1848, dev->ad1848_type); val = 0x00; break; @@ -221,10 +224,15 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) break; case 8: /* CS9236 Wavetable Control */ - val &= 0xf0; + val &= 0x0f; break; } dev->indirect_regs[dev->regs[3]] = val; + + if (dev->ad1848.wten ^ !!(dev->indirect_regs[8] & 0x08)) { + dev->ad1848.wten ^= 1; + ad1848_updatevolmask(&dev->ad1848); + } break; case 5: /* Control/RAM Access */ @@ -232,20 +240,20 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) case 0: /* commands */ switch (val) { case 0x55: /* Disable PnP Key */ - isapnp_enable_card(dev->pnp_card, 0); + dev->pnp_enable = 0; + /* fall-through */ + + case 0x5a: /* Update Hardware Configuration Data */ + cs423x_pnp_enable(dev, 0); break; case 0x56: /* Disable Crystal Key */ - cs423x_slam_remap(dev, 0); + cs423x_slam_enable(dev, 0); break; case 0x57: /* Jump to ROM */ break; - case 0x5a: /* Update Hardware Configuration Data */ - isapnp_update_card_rom(dev->pnp_card, dev->eeprom_data + 23, dev->eeprom_size - 23); - break; - case 0xaa: /* Download RAM */ dev->ram_dl = 1; break; @@ -264,21 +272,21 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) case 3: /* data */ /* The only documented RAM region is 0x4000 (384 bytes in size), for - loading the chip's configuration and PnP ROM without an EEPROM. */ - if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) { - eeprom_addr = dev->ram_addr - 0x3ffc; /* skip first 4 bytes (header on real EEPROM) */ - dev->eeprom_data[eeprom_addr] = val; - if (dev->eeprom_size < ++eeprom_addr) /* update EEPROM size if required */ - dev->eeprom_size = eeprom_addr; - } + loading chip configuration and PnP resources without an EEPROM. */ + if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) + dev->ram_data[dev->ram_addr & 0x01ff] = val; dev->ram_addr++; break; } break; case 6: /* RAM Access End */ - if (!val) + if (!val) { dev->ram_dl = 0; + + /* Update PnP resource data and state. */ + cs423x_pnp_enable(dev, 1); + } break; case 7: /* Global Status */ @@ -412,17 +420,18 @@ cs423x_slam_write(uint16_t addr, uint8_t val, void *priv) static void -cs423x_slam_remap(cs423x_t *dev, uint8_t enable) +cs423x_slam_enable(cs423x_t *dev, uint8_t enable) { /* Disable SLAM. */ - if (dev->enable_slam) { - dev->enable_slam = 0; + if (dev->slam_enable) { + dev->slam_state = CRYSTAL_SLAM_NONE; + dev->slam_enable = 0; io_removehandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); } - /* Enable SLAM if not blocked by EEPROM configuration. */ - if (enable && !(dev->eeprom_data[7] & 0x10)) { - dev->enable_slam = 1; + /* Enable SLAM if the CKD bit is not set. */ + if (enable && !(dev->ram_data[2] & 0x10)) { + dev->slam_enable = 1; io_sethandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); } } @@ -440,21 +449,26 @@ static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - uint8_t prev_context = dev->regs[7] & 0x80, switched = 0; - /* Determine the active context (WSS or SBPro) through the address being read/written. */ - if ((prev_context == 0x80) && ((addr & 0xfff0) == dev->sb_base)) { - dev->regs[7] &= ~0x80; - switched = 1; - } else if ((prev_context == 0x00) && ((addr & 0xfffc) == dev->wss_base)) { - dev->regs[7] |= 0x80; - switched = 1; - } + /* Check if a context switch (WSS=1 <-> SBPro=0) occurred through the address being read/written. */ + if ((dev->regs[7] & 0x80) ? ((addr & 0xfff0) == dev->sb_base) : ((addr & 0xfffc) == dev->wss_base)) { + /* Flip context bit. */ + dev->regs[7] ^= 0x80; - /* Fire the context switch interrupt if enabled. */ - if (switched && (dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { - dev->regs[7] |= 0x40; /* set interrupt flag */ - picint(1 << dev->ad1848.irq); /* control device shares IRQ with WSS and SBPro */ + /* Switch the CD audio filter and OPL ownership. + FIXME: not thread-safe: filter function TOCTTOU in sound_cd_thread! */ + sound_set_cd_audio_filter(NULL, NULL); + dev->sb->opl_enabled = !(dev->regs[7] & 0x80); + if (dev->sb->opl_enabled) /* SBPro */ + sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); + else /* WSS */ + sound_set_cd_audio_filter(ad1848_filter_cd_audio, &dev->ad1848); + + /* Fire a context switch interrupt if enabled. */ + if ((dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { + dev->regs[7] |= 0x40; /* set interrupt flag */ + picint(1 << dev->ad1848.irq); /* control device shares IRQ with WSS and SBPro */ + } } } @@ -463,17 +477,44 @@ static void cs423x_get_buffer(int32_t *buffer, int len, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - int c; + int c, opl_wss = !dev->sb->opl_enabled; - /* Output audio from the WSS codec. SBPro and OPL3 are - already handled by the Sound Blaster emulation. */ + /* Output audio from the WSS codec, and also the OPL if we're in WSS mode. */ ad1848_update(&dev->ad1848); + if (opl_wss) + opl3_update(&dev->sb->opl); - for (c = 0; c < len * 2; c++) { - buffer[c] += (dev->ad1848.buffer[c] / 2); + for (c = 0; c < len * 2; c += 2) { + if (opl_wss) { + buffer[c] += (dev->sb->opl.buffer[c] * dev->ad1848.fm_vol_l) >> 16; + buffer[c + 1] += (dev->sb->opl.buffer[c + 1] * dev->ad1848.fm_vol_r) >> 16; + } + + buffer[c] += dev->ad1848.buffer[c] / 2; + buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; } dev->ad1848.pos = 0; + if (opl_wss) + dev->sb->opl.pos = 0; +} + + +static void +cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom) +{ + uint8_t enable = ISAPNP_CARD_ENABLE; + + /* Hide PnP card if the PKD bit is set, or if PnP was disabled by command 0x55. */ + if ((dev->ram_data[2] & 0x20) || !dev->pnp_enable) + enable = ISAPNP_CARD_DISABLE; + + /* Update PnP resource data if requested. */ + if (update_rom) + isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], sizeof(dev->ram_data) - dev->pnp_offset); + + /* Update PnP state. */ + isapnp_enable_card(dev->pnp_card, enable); } @@ -541,7 +582,6 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv sb_dsp_setdma8(&dev->sb->dsp, config->dma[0].dma); } } - break; case 1: /* Game Port */ @@ -583,16 +623,28 @@ cs423x_reset(void *priv) { cs423x_t *dev = (cs423x_t *) priv; + /* Load EEPROM data to RAM, or just clear RAM if there's no EEPROM. */ + if (dev->eeprom) + memcpy(dev->ram_data, &dev->eeprom_data[4], MIN(sizeof(dev->ram_data), sizeof(dev->eeprom_data) - 4)); + else + memset(dev->ram_data, 0, sizeof(dev->ram_data)); + /* Reset registers. */ memset(dev->indirect_regs, 0, sizeof(dev->indirect_regs)); dev->indirect_regs[1] = dev->type; - /* Reset logical devices. */ - for (uint8_t i = 0; i < 6; i++) - isapnp_reset_device(dev->pnp_card, i); + /* Reset WSS codec. */ + ad1848_init(&dev->ad1848, dev->ad1848_type); - /* Enable SLAM. */ - cs423x_slam_remap(dev, 1); + /* Reset PnP resource data, state and logical devices. */ + dev->pnp_enable = 1; + if (dev->pnp_card) { + cs423x_pnp_enable(dev, 1); + isapnp_reset_card(dev->pnp_card); + } + + /* Reset SLAM. */ + cs423x_slam_enable(dev, 1); } @@ -602,17 +654,46 @@ cs423x_init(const device_t *info) cs423x_t *dev = malloc(sizeof(cs423x_t)); memset(dev, 0, sizeof(cs423x_t)); + /* Initialize model-specific data. */ dev->type = info->local; switch (dev->type) { + case CRYSTAL_CS4236B: case CRYSTAL_CS4237B: - dev->eeprom_size = sizeof(cs4237b_eeprom); - memcpy(dev->eeprom_data, cs4237b_eeprom, dev->eeprom_size); + case CRYSTAL_CS4238B: + /* Same WSS codec and EEPROM structure. */ + dev->ad1848_type = AD1848_TYPE_CS4236; + dev->pnp_offset = 19; + + /* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init */ + dev->ad1848.xregs[25] = dev->type; + + /* Load EEPROM contents from template. */ + memcpy(dev->eeprom_data, cs4236b_eeprom, sizeof(cs4236b_eeprom)); + + /* Set content size. */ + dev->eeprom_data[2] = sizeof(cs4236b_eeprom) >> 8; + dev->eeprom_data[3] = sizeof(cs4236b_eeprom) & 0xff; + + /* Set PnP card ID. */ + switch (dev->type) { + case CRYSTAL_CS4237B: + dev->eeprom_data[26] = 0x37; + break; + + case CRYSTAL_CS4238B: + dev->eeprom_data[26] = 0x38; + break; + } + break; } - /* Initialize codecs. */ + /* Initialize SBPro codec first to get the correct CD audio filter for the default + context, which is SBPro. The WSS codec is initialized later by cs423x_reset */ dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); - ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); + + /* Initialize RAM, registers and WSS codec. */ + cs423x_reset(dev); sound_add_handler(cs423x_get_buffer, dev); /* Initialize game port. */ @@ -621,22 +702,13 @@ cs423x_init(const device_t *info) /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); - if (dev->eeprom_size) { - /* Set EEPROM length. */ - dev->eeprom_data[2] = dev->eeprom_size >> 8; - dev->eeprom_data[3] = dev->eeprom_size & 0xff; - - /* Initialize I2C EEPROM. */ + /* Initialize I2C EEPROM if the contents are valid. */ + if ((dev->eeprom_data[0] == 0x55) && (dev->eeprom_data[1] == 0xbb)) dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->eeprom_data, sizeof(dev->eeprom_data), 1); - } /* Initialize ISAPnP. */ - dev->pnp_card = isapnp_add_card(&dev->eeprom_data[23], dev->eeprom_size - 23, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); - if (dev->eeprom_data[7] & 0x20) /* hide PnP card if PKD is set */ - isapnp_enable_card(dev->pnp_card, 0); - - /* Initialize registers. */ - cs423x_reset(dev); + dev->pnp_card = isapnp_add_card(NULL, 0, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); + cs423x_pnp_enable(dev, 1); return dev; } @@ -665,11 +737,11 @@ cs423x_speed_changed(void *priv) } -const device_t cs4237b_device = +const device_t cs4236b_device = { - "Crystal CS4237B", + "Crystal CS4236B", DEVICE_ISA | DEVICE_AT, - CRYSTAL_CS4237B, + CRYSTAL_CS4236B, cs423x_init, cs423x_close, cs423x_reset, { NULL }, cs423x_speed_changed, diff --git a/src/sound/sound.c b/src/sound/sound.c index 39a3a44b6..851ccc92a 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -88,7 +88,7 @@ static const SOUND_CARD sound_cards[] = { "adlibgold", &adgold_device }, { "azt2316a", &azt2316a_device }, { "azt1605", &azt1605_device }, - { "cs4237b", &cs4237b_device }, + { "cs4236b", &cs4236b_device }, { "sb", &sb_1_device }, { "sb1.5", &sb_15_device }, { "sb2.0", &sb_2_device }, From 19d2bda4cee3f6f03ff1ec3f112c92b303ce54ad Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 23 May 2021 12:57:41 -0300 Subject: [PATCH 11/25] Confirm P2B-LS onboard SCSI and LAN slot numbers (props to computerguy08 on Discord) --- src/machine/m_at_slot1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 2f3edfd82..1ab48f7b4 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -204,8 +204,8 @@ machine_at_p2bls_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* SCSI */ + pci_register_slot(0x07, PCI_CARD_NORMAL, 3, 4, 1, 2); /* LAN */ pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); From ff4f0ee59e713697631fe1c226262342e3c800d7 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 23 May 2021 23:00:42 -0300 Subject: [PATCH 12/25] Crystal CS4236, part 5: Windows 9x now works --- src/include/86box/snd_ad1848.h | 27 ++++++----- src/sound/snd_ad1848.c | 83 ++++++++++++++++++++++++---------- src/sound/snd_cs423x.c | 83 ++++++++++++++++++++++++---------- src/sound/snd_wss.c | 2 +- 4 files changed, 136 insertions(+), 59 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index ac1b1a85f..3e61deea7 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -12,35 +12,40 @@ * * Authors: Sarah Walker, * TheCollector1995, + * RichardG, * * Copyright 2008-2020 Sarah Walker. * Copyright 2018-2020 TheCollector1995. + * Copyright 2021 RichardG. */ -#define AD1848_TYPE_DEFAULT 0 -#define AD1848_TYPE_CS4248 1 -#define AD1848_TYPE_CS4231 2 -#define AD1848_TYPE_CS4236 3 +enum { + AD1848_TYPE_DEFAULT = 0, + AD1848_TYPE_CS4248, + AD1848_TYPE_CS4231, + AD1848_TYPE_CS4236 +}; typedef struct { - int index, xindex; - uint8_t regs[32], xregs[32], status; /* 16 original registers + 16 CS4231A extensions + 32 CS4236 extensions */ - - int trd, mce, count, wten; + uint8_t type, index, xindex, regs[32], xregs[32], status; /* 16 original registers + 16 CS4231A extensions + 32 CS4236 extensions */ + + int count; + uint8_t trd, mce, wten: 1; int16_t out_l, out_r; double cd_vol_l, cd_vol_r; int fm_vol_l, fm_vol_r; uint8_t fmt_mask, wave_vol_mask; - int enable, irq, dma, freq; + uint8_t enable: 1, irq: 4, dma: 3; + int freq; pc_timer_t timer_count; uint64_t timer_latch; int16_t buffer[SOUNDBUFLEN * 2]; - int pos, type; + int pos; } ad1848_t; @@ -55,4 +60,4 @@ extern void ad1848_update(ad1848_t *ad1848); extern void ad1848_speed_changed(ad1848_t *ad1848); extern void ad1848_filter_cd_audio(int channel, double *buffer, void *priv); -extern void ad1848_init(ad1848_t *ad1848, int type); +extern void ad1848_init(ad1848_t *ad1848, uint8_t type); diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 3b452a607..176da40da 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -12,9 +12,11 @@ * * Authors: Sarah Walker, * TheCollector1995, + * RichardG, * * Copyright 2008-2020 Sarah Walker. * Copyright 2018-2020 TheCollector1995. + * Copyright 2021 RichardG. */ #include #include @@ -35,8 +37,6 @@ static int ad1848_vols_7bits[128]; static double ad1848_vols_5bits_aux_gain[32]; -static double ad1848_vols_7bits_debug[128]; -static double ad1848_vols_5bits_debug[32]; void @@ -136,9 +136,9 @@ ad1848_read(uint16_t addr, void *priv) case 18: case 19: if (ad1848->type == AD1848_TYPE_CS4236) { if (ad1848->xregs[4] & 0x04) /* FM remapping */ - return ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ + ret = ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ else if (ad1848->xregs[4] & 0x08) /* wavetable remapping */ - return ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */ + ret = ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */ } break; @@ -166,7 +166,7 @@ void ad1848_write(uint16_t addr, uint8_t val, void *priv) { ad1848_t *ad1848 = (ad1848_t *) priv; - uint8_t temp, updatefreq = 0; + uint8_t temp = 0, updatefreq = 0; switch (addr & 3) { case 0: /* Index */ @@ -224,14 +224,43 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 18: case 19: if (ad1848->type == AD1848_TYPE_CS4236) { - if (ad1848->xregs[4] & 0x04) { /* FM remapping */ - temp = val; - val = ad1848->xregs[ad1848->index - 18]; /* real line volume on registers 0 and 1 */ - ad1848->xregs[ad1848->index - 12] = temp; /* real FM volume on registers 6 and 7 */ - } else if (ad1848->xregs[4] & 0x08) { /* wavetable remapping */ - temp = val; - val = ad1848->xregs[ad1848->index - 18]; /* real line volume on registers 0 and 1 */ - ad1848->xregs[ad1848->index - 2] = temp; /* real wavetable volume on registers 16 and 17 */ + if ((ad1848->xregs[4] & 0x14) == 0x14) { /* FM remapping */ + ad1848->xregs[ad1848->index - 12] = val; /* real FM volume on extended registers 6 and 7 */ + temp = 1; + + if (ad1848->index == 18) { + if (val & 0x80) + ad1848->fm_vol_l = 0; + else + ad1848->fm_vol_l = ad1848_vols_7bits[val & 0x3f]; + } else { + if (val & 0x80) + ad1848->fm_vol_r = 0; + else + ad1848->fm_vol_r = ad1848_vols_7bits[val & 0x3f]; + } + } + if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) { /* wavetable remapping */ + ad1848->xregs[ad1848->index - 2] = val; /* real wavetable volume on extended registers 16 and 17 */ + temp = 1; + } + + /* Stop here if any remapping is enabled. */ + if (temp) + return; + + /* HACK: the Windows 9x driver's "Synth" control writes to this + register with no remapping, even if internal FM is enabled. */ + if (ad1848->index == 18) { + if (val & 0x80) + ad1848->fm_vol_l = 0; + else + ad1848->fm_vol_l = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; + } else { + if (val & 0x80) + ad1848->fm_vol_r = 0; + else + ad1848->fm_vol_r = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; } } break; @@ -243,9 +272,10 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 23: if ((ad1848->type == AD1848_TYPE_CS4236) && ((ad1848->regs[12] & 0x60) == 0x60)) { if (!(ad1848->regs[23] & 0x08)) { /* existing (not new) XRAE is clear */ - ad1848->xindex = (((val & 0x04) << 2) | (val >> 4)) & 0x1f; + ad1848->xindex = ((val & 0x04) << 2) | (val >> 4); break; } + switch (ad1848->xindex) { case 0: case 1: /* remapped line volume */ ad1848->regs[18 + ad1848->xindex] = val; @@ -282,8 +312,11 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) break; case 24: - if (!(val & 0x70)) + val = ad1848->regs[24] & ((val & 0x70) | 0x0f); + if (!(val & 0x70)) { ad1848->status &= 0xfe; + picintc(1 << ad1848->irq); + } break; case 25: @@ -310,6 +343,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 2: ad1848->status &= 0xfe; + ad1848->regs[24] &= 0x0f; break; } } @@ -391,14 +425,15 @@ ad1848_poll(void *priv) ad1848->out_r = 0; else ad1848->out_r = (ad1848->out_r * ad1848_vols_7bits[ad1848->regs[7] & ad1848->wave_vol_mask]) >> 16; - + if (ad1848->count < 0) { ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); if (!(ad1848->status & 0x01)) { ad1848->status |= 0x01; + ad1848->regs[24] |= 0x10; if (ad1848->regs[10] & 2) picint(1 << ad1848->irq); - } + } } ad1848->count--; @@ -422,11 +457,11 @@ ad1848_filter_cd_audio(int channel, double *buffer, void *priv) void -ad1848_init(ad1848_t *ad1848, int type) +ad1848_init(ad1848_t *ad1848, uint8_t type) { - int c; + uint8_t c; double attenuation; - + ad1848->status = 0xcc; ad1848->index = ad1848->trd = 0; ad1848->mce = 0x40; @@ -477,8 +512,10 @@ ad1848_init(ad1848_t *ad1848, int type) ad1848->xregs[16] = ad1848->xregs[17] = 0; } + ad1848_updatefreq(ad1848); + ad1848->out_l = ad1848->out_r = 0; - ad1848->fm_vol_l = ad1848->fm_vol_r = 1; + ad1848->fm_vol_l = ad1848->fm_vol_r = 65536; ad1848_updatevolmask(ad1848); ad1848->fmt_mask = 0x70; @@ -494,7 +531,7 @@ ad1848_init(ad1848_t *ad1848, int type) if (c & 0x10) attenuation -= 24.0; if (c & 0x20) attenuation -= 48.0; } -ad1848_vols_7bits_debug[c] = attenuation; + attenuation = pow(10, attenuation / 10); ad1848_vols_7bits[c] = (int) (attenuation * 65536); @@ -507,7 +544,7 @@ ad1848_vols_7bits_debug[c] = attenuation; if (c & 0x04) attenuation -= 6.0; if (c & 0x08) attenuation -= 12.0; if (c & 0x10) attenuation -= 24.0; -ad1848_vols_5bits_debug[c] = attenuation; + attenuation = pow(10, attenuation / 10); ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index b95d0618d..57bf083ca 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -42,10 +42,10 @@ enum { CRYSTAL_CS4238B = 0xc9 }; enum { - CRYSTAL_SLAM_NONE = 0, - CRYSTAL_SLAM_INDEX, - CRYSTAL_SLAM_BYTE1, - CRYSTAL_SLAM_BYTE2 + CRYSTAL_SLAM_NONE = 0, + CRYSTAL_SLAM_INDEX = 1, + CRYSTAL_SLAM_BYTE1 = 2, + CRYSTAL_SLAM_BYTE2 = 3 }; @@ -133,8 +133,7 @@ typedef struct cs423x_t void *i2c, *eeprom; uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11; - uint8_t type, pnp_offset, regs[8], indirect_regs[16], eeprom_data[2048], ram_data[384], ram_dl; - int ad1848_type; + uint8_t type, ad1848_type, pnp_offset, regs[8], indirect_regs[16], eeprom_data[2048], ram_data[384], ram_dl; uint8_t pnp_enable: 1, key_pos: 5, slam_enable: 1, slam_state: 2, slam_ld, slam_reg; isapnp_device_config_t *slam_config; @@ -148,10 +147,10 @@ static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config static uint8_t -cs423x_read(uint16_t port, void *priv) +cs423x_read(uint16_t addr, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - uint8_t reg = port & 7; + uint8_t reg = addr & 7; uint8_t ret = dev->regs[reg]; switch (reg) { @@ -165,6 +164,17 @@ cs423x_read(uint16_t port, void *priv) ret = dev->indirect_regs[dev->regs[3]]; break; + case 5: /* Control/RAM Access */ + /* Reading RAM is undocumented; the WDM driver does so. */ + if (dev->ram_dl) { + if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) /* chip configuration and PnP resources */ + ret = dev->ram_data[dev->ram_addr & 0x01ff]; + else + ret = 0xff; + dev->ram_addr++; + } + break; + case 7: /* Global Status */ /* Context switching: take active context and interrupt flag, then clear interrupt flag. */ ret &= 0xc0; @@ -172,10 +182,12 @@ cs423x_read(uint16_t port, void *priv) if (dev->sb->mpu->state.irq_pending) /* MPU interrupt */ ret |= 0x08; - if (dev->ad1848.regs[10] & 2) /* WSS interrupt */ + if (dev->ad1848.status & 0x01) /* WSS interrupt */ ret |= 0x10; if (dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16 || dev->sb->dsp.sb_irq401) /* SBPro interrupt */ ret |= 0x20; + + break; } return ret; @@ -183,10 +195,10 @@ cs423x_read(uint16_t port, void *priv) static void -cs423x_write(uint16_t port, uint8_t val, void *priv) +cs423x_write(uint16_t addr, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - uint8_t reg = port & 7; + uint8_t reg = addr & 0x07; switch (reg) { case 1: /* EEPROM Interface */ @@ -199,7 +211,7 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) break; case 4: /* Control Indirect Data Register */ - switch (dev->regs[3] & 15) { + switch (dev->regs[3] & 0x0f) { case 0: /* WSS Master Control */ if (val & 0x80) ad1848_init(&dev->ad1848, dev->ad1848_type); @@ -211,28 +223,36 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) case 9 ... 15: /* unspecified */ return; + case 2: /* 3D Space and {Center|Volume} */ + case 6: /* Upper Channel Status */ + if (dev->type < CRYSTAL_CS4237B) + return; + break; + case 3: /* 3D Enable */ + if (dev->type < CRYSTAL_CS4237B) + return; val &= 0xe0; break; case 4: /* Consumer Serial Port Enable */ + if (dev->type < CRYSTAL_CS4237B) + return; val &= 0xf0; break; case 5: /* Lower Channel Status */ + if (dev->type < CRYSTAL_CS4237B) + return; val &= 0xfe; break; case 8: /* CS9236 Wavetable Control */ val &= 0x0f; + cs423x_pnp_enable(dev, 0); /* update WTEN bit */ break; } dev->indirect_regs[dev->regs[3]] = val; - - if (dev->ad1848.wten ^ !!(dev->indirect_regs[8] & 0x08)) { - dev->ad1848.wten ^= 1; - ad1848_updatevolmask(&dev->ad1848); - } break; case 5: /* Control/RAM Access */ @@ -271,9 +291,7 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) break; case 3: /* data */ - /* The only documented RAM region is 0x4000 (384 bytes in size), for - loading chip configuration and PnP resources without an EEPROM. */ - if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) + if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) /* chip configuration and PnP resources */ dev->ram_data[dev->ram_addr & 0x01ff] = val; dev->ram_addr++; break; @@ -424,7 +442,7 @@ cs423x_slam_enable(cs423x_t *dev, uint8_t enable) { /* Disable SLAM. */ if (dev->slam_enable) { - dev->slam_state = CRYSTAL_SLAM_NONE; + dev->slam_state = CRYSTAL_SLAM_NONE; dev->slam_enable = 0; io_removehandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); } @@ -455,10 +473,10 @@ cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) /* Flip context bit. */ dev->regs[7] ^= 0x80; - /* Switch the CD audio filter and OPL ownership. + /* Switch OPL ownership and CD audio filter. FIXME: not thread-safe: filter function TOCTTOU in sound_cd_thread! */ - sound_set_cd_audio_filter(NULL, NULL); dev->sb->opl_enabled = !(dev->regs[7] & 0x80); + sound_set_cd_audio_filter(NULL, NULL); if (dev->sb->opl_enabled) /* SBPro */ sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); else /* WSS */ @@ -496,7 +514,7 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv) dev->ad1848.pos = 0; if (opl_wss) - dev->sb->opl.pos = 0; + dev->sb->opl.pos = 0; } @@ -515,6 +533,21 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom) /* Update PnP state. */ isapnp_enable_card(dev->pnp_card, enable); + + /* While we're here, update FM and wavetable enable bits based on the config data in RAM. */ + if (dev->ram_data[3] & 0x08) { + dev->indirect_regs[8] |= 0x08; + dev->ad1848.wten = 1; + } else { + dev->indirect_regs[8] &= ~0x08; + dev->ad1848.wten = 0; + } + if (dev->ram_data[3] & 0x80) + dev->ad1848.xregs[4] |= 0x10; + else + dev->ad1848.xregs[4] &= ~0x10; + + ad1848_updatevolmask(&dev->ad1848); } @@ -632,6 +665,8 @@ cs423x_reset(void *priv) /* Reset registers. */ memset(dev->indirect_regs, 0, sizeof(dev->indirect_regs)); dev->indirect_regs[1] = dev->type; + if (dev->type == CRYSTAL_CS4238B) + dev->indirect_regs[2] = 0x20; /* Reset WSS codec. */ ad1848_init(&dev->ad1848, dev->ad1848_type); diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 80b27cf9d..9017fe2c1 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -53,7 +53,7 @@ static const int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /* W95 only uses 7- typedef struct wss_t { uint8_t config; - ad1848_t ad1848; + ad1848_t ad1848; opl_t opl; int opl_enabled; From 82a38618050df5909f7cf505191a7c28b9c4d7aa Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 00:28:05 -0300 Subject: [PATCH 13/25] Make PCI TRC reset all devices --- src/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pci.c b/src/pci.c index 2283ca60d..a8c76b003 100644 --- a/src/pci.c +++ b/src/pci.c @@ -709,7 +709,7 @@ trc_reset(uint8_t val) { if (val & 2) { dma_reset(); - device_reset_all_pci(); + device_reset_all(); cpu_alt_reset = 0; From b5a295e91dad42b934ded20527fe21c9b4fecb26 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 00:53:52 -0300 Subject: [PATCH 14/25] Continuing the game port overhaul: added support for Super I/O game ports not being broken out --- src/game/gameport.c | 19 +++++++++++++++---- src/include/86box/gameport.h | 2 ++ src/include/86box/machine.h | 1 + src/machine/machine.c | 1 + src/machine/machine_table.c | 2 +- src/sio/sio_um8669f.c | 4 ++-- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index d7f399ab3..2c56f13b8 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -119,7 +119,7 @@ static const isapnp_device_config_t gameport_pnp_defaults[] = { const device_t *standalone_gameport_type; -static int gameport_instance_id = 0; +int gameport_instance_id = 0; /* Linked list of active game ports. Only the top port responds to reads or writes, and ports at the standard 200h location are prioritized. */ static gameport_t *active_gameports = NULL; @@ -356,8 +356,10 @@ gameport_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pr void * gameport_add(const device_t *gameport_type) { - /* Prevent a standalone game port from being added later on. */ - standalone_gameport_type = NULL; + /* Prevent a standalone game port from being added later on, unless this + is an unused Super I/O game port (no MACHINE_GAMEPORT machine flag). */ + if (!(gameport_type->local & 0x10000) || (machines[machine].flags & MACHINE_GAMEPORT)) + standalone_gameport_type = NULL; /* Add game port device. */ return device_add_inst(gameport_type, gameport_instance_id++); @@ -399,7 +401,7 @@ gameport_init(const device_t *info) dev->joystick = joystick_instance; /* Map game port to the default address. Not applicable on PnP-only ports. */ - gameport_remap(dev, info->local); + gameport_remap(dev, info->local & 0xffff); /* Register ISAPnP if this is a standard game port card. */ if (info->local == 0x200) @@ -455,3 +457,12 @@ const device_t gameport_pnp_device = { NULL, { NULL }, NULL, NULL }; + +const device_t gameport_sio_device = { + "Game port (Super I/O)", + 0, 0x10000, + gameport_init, + gameport_close, + NULL, { NULL }, NULL, + NULL +}; diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index 406234f45..9f5da7f00 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -108,9 +108,11 @@ extern "C" { extern const device_t gameport_device; extern const device_t gameport_201_device; extern const device_t gameport_pnp_device; +extern const device_t gameport_sio_device; extern const device_t *standalone_gameport_type; #endif +extern int gameport_instance_id; extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; extern joystick_t joystick_state[MAX_JOYSTICKS]; extern int joysticks_present; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 9e627a7e7..677dc7027 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -61,6 +61,7 @@ #define MACHINE_SOUND 0x00008000 /* sys has int sound */ #define MACHINE_FDC 0x00010000 /* sys has int FDC */ #define MACHINE_NIC 0x00020000 /* sys has int NIC */ +#define MACHINE_GAMEPORT 0x00040000 /* sys has int game port */ /* Combined flags. */ #define MACHINE_VIDEO_FIXED 0x00003000 /* sys has fixed int video */ /* Feature flags for internal storage controllers. */ diff --git a/src/machine/machine.c b/src/machine/machine.c index e3f2ef600..ae731e522 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -76,6 +76,7 @@ machine_init_ex(int m) is_vpc = 0; standalone_gameport_type = NULL; + gameport_instance_id = 0; /* Set up the architecture flags. */ AT = IS_AT(machine); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d33ffd2a3..117afc4d4 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -340,7 +340,7 @@ const machine_t machines[] = { { "[i430VX] HP Brio 80xx", "brio80xx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 2200, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_brio80xx_init, NULL }, { "[i430VX] Packard Bell PB680", "pb680", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_pb680_init, NULL }, { "[i430VX] PC Partner MB520N", "mb520n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mb520n_init, NULL }, - { "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_i430vx_init, NULL }, + { "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_GAMEPORT, 8192, 131072, 8192, 127, machine_at_i430vx_init, NULL }, /* 430TX */ { "[i430TX] ADLink NuPRO-592", "nupro592", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 1900, 2800, 1.5, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_nupro592_init, NULL }, diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index 5087c7439..516685629 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -89,7 +89,7 @@ static const isapnp_device_config_t um8669f_pnp_defaults[] = { }, { .activate = 0 }, { - .activate = 1, + .activate = 0, .io = { { .base = 0x200 }, } } }; @@ -287,7 +287,7 @@ um8669f_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); - dev->gameport = gameport_add(&gameport_pnp_device); + dev->gameport = gameport_add(&gameport_sio_device); io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, dev); From 80fb5775e45102b2c19c14cfad1d7405eb8688a7 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 00:58:59 -0300 Subject: [PATCH 15/25] LM78 no longer needs to be a PCI device with the TRC change --- src/device/hwm_lm78.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index 3cc5812e6..e849190cf 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -776,7 +776,7 @@ lm78_init(const device_t *info) /* National Semiconductor LM78 on ISA and SMBus. */ const device_t lm78_device = { "National Semiconductor LM78 Hardware Monitor", - DEVICE_ISA | DEVICE_PCI, + DEVICE_ISA, 0x290 | LM78_I2C, lm78_init, lm78_close, lm78_reset, { NULL }, NULL, NULL, @@ -787,7 +787,7 @@ const device_t lm78_device = { /* Winbond W83781D on ISA and SMBus. */ const device_t w83781d_device = { "Winbond W83781D Hardware Monitor", - DEVICE_ISA | DEVICE_PCI, + DEVICE_ISA, 0x290 | LM78_I2C | LM78_W83781D, lm78_init, lm78_close, lm78_reset, { NULL }, NULL, NULL, @@ -799,7 +799,7 @@ const device_t w83781d_device = { I2C-only W83781D clone with additional voltages, GPIOs and fan control. */ const device_t as99127f_device = { "ASUS AS99127F Rev. 1 Hardware Monitor", - DEVICE_ISA | DEVICE_PCI, + DEVICE_ISA, LM78_I2C | LM78_AS99127F_REV1, lm78_init, lm78_close, lm78_reset, { NULL }, NULL, NULL, @@ -810,7 +810,7 @@ const device_t as99127f_device = { /* Rev. 2 is manufactured by Winbond and differs only in GPI registers. */ const device_t as99127f_rev2_device = { "ASUS AS99127F Rev. 2 Hardware Monitor", - DEVICE_ISA | DEVICE_PCI, + DEVICE_ISA, LM78_I2C | LM78_AS99127F_REV2, lm78_init, lm78_close, lm78_reset, { NULL }, NULL, NULL, @@ -821,7 +821,7 @@ const device_t as99127f_rev2_device = { /* Winbond W83782D on ISA and SMBus. */ const device_t w83782d_device = { "Winbond W83782D Hardware Monitor", - DEVICE_ISA | DEVICE_PCI, + DEVICE_ISA, 0x290 | LM78_I2C | LM78_W83782D, lm78_init, lm78_close, lm78_reset, { NULL }, NULL, NULL, From dfd6d4e2df6f22bdd18c0c40c422db5b4f97c25a Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 01:14:48 -0300 Subject: [PATCH 16/25] Add game port device with 6 I/O ports for the Crystal CS4237/8B --- src/game/gameport.c | 25 ++++++++++++++++++------- src/include/86box/gameport.h | 1 + src/sound/snd_cs423x.c | 7 ++++--- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index 2c56f13b8..d33efb897 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -45,6 +45,7 @@ typedef struct { typedef struct _gameport_ { uint16_t addr; + uint8_t len; struct _joystick_instance_ *joystick; struct _gameport_ *next; } gameport_t; @@ -314,7 +315,7 @@ gameport_remap(void *priv, uint16_t address) } } - io_removehandler(dev->addr, (dev->addr & 1) ? 1 : 8, + io_removehandler(dev->addr, dev->len, gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev); } @@ -334,7 +335,7 @@ gameport_remap(void *priv, uint16_t address) other_dev->next = dev; } - io_sethandler(dev->addr, (dev->addr & 1) ? 1 : 8, + io_sethandler(dev->addr, dev->len, gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev); } } @@ -358,7 +359,7 @@ gameport_add(const device_t *gameport_type) { /* Prevent a standalone game port from being added later on, unless this is an unused Super I/O game port (no MACHINE_GAMEPORT machine flag). */ - if (!(gameport_type->local & 0x10000) || (machines[machine].flags & MACHINE_GAMEPORT)) + if (!(gameport_type->local & 0x1000000) || (machines[machine].flags & MACHINE_GAMEPORT)) standalone_gameport_type = NULL; /* Add game port device. */ @@ -401,6 +402,7 @@ gameport_init(const device_t *info) dev->joystick = joystick_instance; /* Map game port to the default address. Not applicable on PnP-only ports. */ + dev->len = (info->local >> 16) & 0xff; gameport_remap(dev, info->local & 0xffff); /* Register ISAPnP if this is a standard game port card. */ @@ -433,7 +435,7 @@ gameport_close(void *priv) const device_t gameport_device = { "Game port", - 0, 0x200, + 0, 0x080200, gameport_init, gameport_close, NULL, { NULL }, NULL, @@ -442,7 +444,7 @@ const device_t gameport_device = { const device_t gameport_201_device = { "Game port (port 201h only)", - 0, 0x201, + 0, 0x010201, gameport_init, gameport_close, NULL, { NULL }, NULL, @@ -451,7 +453,16 @@ const device_t gameport_201_device = { const device_t gameport_pnp_device = { "Game port (Plug and Play only)", - 0, 0, + 0, 0x080000, + gameport_init, + gameport_close, + NULL, { NULL }, NULL, + NULL +}; + +const device_t gameport_pnp_6io_device = { + "Game port (Plug and Play only, 6 I/O ports)", + 0, 0x060000, gameport_init, gameport_close, NULL, { NULL }, NULL, @@ -460,7 +471,7 @@ const device_t gameport_pnp_device = { const device_t gameport_sio_device = { "Game port (Super I/O)", - 0, 0x10000, + 0, 0x1080000, gameport_init, gameport_close, NULL, { NULL }, NULL, diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index 9f5da7f00..be8eec813 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -108,6 +108,7 @@ extern "C" { extern const device_t gameport_device; extern const device_t gameport_201_device; extern const device_t gameport_pnp_device; +extern const device_t gameport_pnp_6io_device; extern const device_t gameport_sio_device; extern const device_t *standalone_gameport_type; diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 57bf083ca..fbc8595b1 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -720,6 +720,10 @@ cs423x_init(const device_t *info) break; } + /* Initialize game port. The '7B and '8B game port only responds to 6 I/O ports; the remaining + 2 ports are reserved on those chips, and probably connected to the Digital Assist feature. */ + dev->gameport = gameport_add((dev->type == CRYSTAL_CS4236B) ? &gameport_pnp_device : &gameport_pnp_6io_device); + break; } @@ -731,9 +735,6 @@ cs423x_init(const device_t *info) cs423x_reset(dev); sound_add_handler(cs423x_get_buffer, dev); - /* Initialize game port. */ - dev->gameport = gameport_add(&gameport_pnp_device); - /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); From ce7db25d7c9bc2c3ea49f406cc9d533badd7c1f3 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 01:15:23 -0300 Subject: [PATCH 17/25] Add hidden CS4237B and CS4238B devices --- src/include/86box/sound.h | 2 ++ src/sound/snd_cs423x.c | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index d280460e5..b15724cdd 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -126,6 +126,8 @@ extern const device_t ncr_business_audio_device; /* Crystal CS423x */ extern const device_t cs4236b_device; +extern const device_t cs4237b_device; +extern const device_t cs4238b_device; #endif #endif /*EMU_SOUND_H*/ diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index fbc8595b1..c900fb994 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -784,3 +784,27 @@ const device_t cs4236b_device = NULL, NULL }; + +const device_t cs4237b_device = +{ + "Crystal CS4237B", + DEVICE_ISA | DEVICE_AT, + CRYSTAL_CS4237B, + cs423x_init, cs423x_close, cs423x_reset, + { NULL }, + cs423x_speed_changed, + NULL, + NULL +}; + +const device_t cs4238b_device = +{ + "Crystal CS4238B", + DEVICE_ISA | DEVICE_AT, + CRYSTAL_CS4238B, + cs423x_init, cs423x_close, cs423x_reset, + { NULL }, + cs423x_speed_changed, + NULL, + NULL +}; From ea3d8448268355fb4e0ec4b8c736491292f54b7d Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 01:16:18 -0300 Subject: [PATCH 18/25] Add missing NULL check to CS423x game port. --- src/sound/snd_cs423x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index c900fb994..e11acc88b 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -618,7 +618,8 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv break; case 1: /* Game Port */ - gameport_remap(dev->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + if (dev->gameport) + gameport_remap(dev->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); break; case 2: /* Control Registers */ From ff46734e5eb8d38267f72cdc4138c6c0cd67b635 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 14:18:21 -0300 Subject: [PATCH 19/25] Preserve logical device configuration on ISAPnP ROM update --- src/device/isapnp.c | 55 +++++++++++++++++++++++++++--------------- src/sound/snd_cs423x.c | 19 +++++++-------- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 44885f837..62abb3202 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -53,7 +53,7 @@ static const uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; static const device_t isapnp_device; - +#define ENABLE_ISAPNP_LOG 1 #ifdef ENABLE_ISAPNP_LOG int isapnp_do_log = ENABLE_ISAPNP_LOG; @@ -717,17 +717,15 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) isapnp_log("ISAPnP: Parsing ROM resources for card %c%c%c%02X%02X (serial %08X)\n", '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[2], card->rom[3], (card->rom[7] << 24) | (card->rom[6] << 16) | (card->rom[5] << 8) | card->rom[4]); #endif uint16_t i = 9, j; - uint8_t ldn = 0, res, in_df = 0; + uint8_t existing = 0, ldn = 0, res, in_df = 0; uint8_t irq = 0, io = 0, mem_range = 0, mem_range_32 = 0, irq_df = 0, io_df = 0, mem_range_df = 0, mem_range_32_df = 0; uint32_t len; - isapnp_device_t *ld = card->first_ld, *prev_ld = NULL; + isapnp_device_t *ld = NULL, *prev_ld = NULL; - /* Clear any existing logical devices. */ - while (ld) { - prev_ld = ld->next; - free(ld); - ld = prev_ld; - } + /* Check if this is an existing card which already has logical devices. + Any new logical devices will be added to the list after existing ones. + Removed LDs are not flushed as we may end up with an invalid ROM. */ + existing = !!card->first_ld; /* Iterate through ROM resources. */ while (i < card->rom_size) { @@ -805,22 +803,39 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) #endif /* We're done with the previous logical device. */ - if (ld) { - prev_ld = ld; + if (ld && !existing) isapnp_reset_ld_regs(ld); + + /* Look for an existing logical device with this number, + and create one if none exist. */ + if (existing) { + ld = card->first_ld; + while (ld && (ld->number != ldn)) + ld = ld->next; + } + if (ld) { + /* Reset some logical device state. */ + ld->mem_upperlimit = ld->io_16bit = ld->irq_types = 0; + memset(ld->io_len, 0, sizeof(ld->io_len)); + } else { + /* Create logical device. */ + ld = (isapnp_device_t *) malloc(sizeof(isapnp_device_t)); + memset(ld, 0, sizeof(isapnp_device_t)); + + /* Add to end of list. */ + prev_ld = card->first_ld; + if (prev_ld) { + while (prev_ld->next) + prev_ld = prev_ld->next; + prev_ld->next = ld; + } else { + card->first_ld = ld; + } } - /* Create logical device. */ - ld = (isapnp_device_t *) malloc(sizeof(isapnp_device_t)); - memset(ld, 0, sizeof(isapnp_device_t)); - + /* Set and increment logical device number. */ ld->number = ldn++; - if (prev_ld) - prev_ld->next = ld; - else - card->first_ld = ld; - /* Start the position counts over. */ irq = io = mem_range = mem_range_32 = irq_df = io_df = mem_range_df = mem_range_32_df = 0; diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index e11acc88b..d8a8c1eee 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -302,7 +302,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) if (!val) { dev->ram_dl = 0; - /* Update PnP resource data and state. */ + /* Update PnP state and resource data. */ cs423x_pnp_enable(dev, 1); } break; @@ -728,14 +728,6 @@ cs423x_init(const device_t *info) break; } - /* Initialize SBPro codec first to get the correct CD audio filter for the default - context, which is SBPro. The WSS codec is initialized later by cs423x_reset */ - dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); - - /* Initialize RAM, registers and WSS codec. */ - cs423x_reset(dev); - sound_add_handler(cs423x_get_buffer, dev); - /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); @@ -745,7 +737,14 @@ cs423x_init(const device_t *info) /* Initialize ISAPnP. */ dev->pnp_card = isapnp_add_card(NULL, 0, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); - cs423x_pnp_enable(dev, 1); + + /* Initialize SBPro codec first to get the correct CD audio filter for the default + context, which is SBPro. The WSS codec is initialized later by cs423x_reset */ + dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); + + /* Initialize RAM, registers and WSS codec. */ + cs423x_reset(dev); + sound_add_handler(cs423x_get_buffer, dev); return dev; } From 915981582334b7b035febb9feb2249943c3c1fac Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 15:30:52 -0300 Subject: [PATCH 20/25] CS423x: Implement internal FM control and analog power down --- src/sound/snd_cs423x.c | 137 +++++++++++++++++++++++------------------ src/sound/snd_sb.c | 2 +- 2 files changed, 79 insertions(+), 60 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index d8a8c1eee..0f70c2f8d 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -133,7 +133,8 @@ typedef struct cs423x_t void *i2c, *eeprom; uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11; - uint8_t type, ad1848_type, pnp_offset, regs[8], indirect_regs[16], eeprom_data[2048], ram_data[384], ram_dl; + uint8_t type, ad1848_type, pnp_offset, regs[8], indirect_regs[16], + eeprom_data[2048], ram_data[384], ram_dl: 2, opl_wss: 1; uint8_t pnp_enable: 1, key_pos: 5, slam_enable: 1, slam_state: 2, slam_ld, slam_reg; isapnp_device_config_t *slam_config; @@ -141,8 +142,7 @@ typedef struct cs423x_t static void cs423x_slam_enable(cs423x_t *dev, uint8_t enable); -static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom); -static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv); +static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig); static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); @@ -166,7 +166,7 @@ cs423x_read(uint16_t addr, void *priv) case 5: /* Control/RAM Access */ /* Reading RAM is undocumented; the WDM driver does so. */ - if (dev->ram_dl) { + if (dev->ram_dl == 3) { if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) /* chip configuration and PnP resources */ ret = dev->ram_data[dev->ram_addr & 0x01ff]; else @@ -249,7 +249,11 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) case 8: /* CS9236 Wavetable Control */ val &= 0x0f; - cs423x_pnp_enable(dev, 0); /* update WTEN bit */ + cs423x_pnp_enable(dev, 0, 0); + + /* Update WTEN state on the WSS codec. */ + dev->ad1848.wten = !!(val & 0x08); + ad1848_updatevolmask(&dev->ad1848); break; } dev->indirect_regs[dev->regs[3]] = val; @@ -264,7 +268,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) /* fall-through */ case 0x5a: /* Update Hardware Configuration Data */ - cs423x_pnp_enable(dev, 0); + cs423x_pnp_enable(dev, 0, 1); break; case 0x56: /* Disable Crystal Key */ @@ -303,7 +307,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) dev->ram_dl = 0; /* Update PnP state and resource data. */ - cs423x_pnp_enable(dev, 1); + cs423x_pnp_enable(dev, 1, 0); } break; @@ -455,32 +459,26 @@ cs423x_slam_enable(cs423x_t *dev, uint8_t enable) } -static uint8_t -cs423x_ctxswitch_read(uint16_t addr, void *priv) -{ - cs423x_ctxswitch_write(addr, 0, priv); - return 0xff; /* don't interfere with the actual handlers */ -} - - static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; + uint8_t ctx = (dev->regs[7] & 0x80), + enable_opl = (dev->ad1848.xregs[4] & 0x10) && !(dev->indirect_regs[2] & 0x85); - /* Check if a context switch (WSS=1 <-> SBPro=0) occurred through the address being read/written. */ + /* Check if a context switch (WSS=1 <-> SBPro=0) occurred through the address being written. */ if ((dev->regs[7] & 0x80) ? ((addr & 0xfff0) == dev->sb_base) : ((addr & 0xfffc) == dev->wss_base)) { /* Flip context bit. */ dev->regs[7] ^= 0x80; + ctx ^= 0x80; - /* Switch OPL ownership and CD audio filter. + /* Update CD audio filter. FIXME: not thread-safe: filter function TOCTTOU in sound_cd_thread! */ - dev->sb->opl_enabled = !(dev->regs[7] & 0x80); sound_set_cd_audio_filter(NULL, NULL); - if (dev->sb->opl_enabled) /* SBPro */ - sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); - else /* WSS */ + if (ctx) /* WSS */ sound_set_cd_audio_filter(ad1848_filter_cd_audio, &dev->ad1848); + else /* SBPro */ + sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); /* Fire a context switch interrupt if enabled. */ if ((dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { @@ -488,6 +486,11 @@ cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) picint(1 << dev->ad1848.irq); /* control device shares IRQ with WSS and SBPro */ } } + + /* Update OPL ownership and state regardless of context switch, + to trap writes to other registers which may disable the OPL. */ + dev->sb->opl_enabled = !ctx && enable_opl; + dev->opl_wss = ctx && enable_opl; } @@ -495,21 +498,24 @@ static void cs423x_get_buffer(int32_t *buffer, int len, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - int c, opl_wss = !dev->sb->opl_enabled; + int c, opl_wss = dev->opl_wss; - /* Output audio from the WSS codec, and also the OPL if we're in WSS mode. */ + /* Output audio from the WSS codec, and also the OPL if we're in charge of it. */ ad1848_update(&dev->ad1848); if (opl_wss) opl3_update(&dev->sb->opl); - for (c = 0; c < len * 2; c += 2) { - if (opl_wss) { - buffer[c] += (dev->sb->opl.buffer[c] * dev->ad1848.fm_vol_l) >> 16; - buffer[c + 1] += (dev->sb->opl.buffer[c + 1] * dev->ad1848.fm_vol_r) >> 16; - } + /* Don't output anything if the analog section is powered down. */ + if (!(dev->indirect_regs[2] & 0xa4)) { + for (c = 0; c < len * 2; c += 2) { + if (opl_wss) { + buffer[c] += (dev->sb->opl.buffer[c] * dev->ad1848.fm_vol_l) >> 16; + buffer[c + 1] += (dev->sb->opl.buffer[c + 1] * dev->ad1848.fm_vol_r) >> 16; + } - buffer[c] += dev->ad1848.buffer[c] / 2; - buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; + buffer[c] += dev->ad1848.buffer[c] / 2; + buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; + } } dev->ad1848.pos = 0; @@ -519,35 +525,49 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv) static void -cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom) +cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) { uint8_t enable = ISAPNP_CARD_ENABLE; - /* Hide PnP card if the PKD bit is set, or if PnP was disabled by command 0x55. */ - if ((dev->ram_data[2] & 0x20) || !dev->pnp_enable) - enable = ISAPNP_CARD_DISABLE; + if (dev->pnp_card) { + /* Hide PnP card if the PKD bit is set, or if PnP was disabled by command 0x55. */ + if ((dev->ram_data[2] & 0x20) || !dev->pnp_enable) + enable = ISAPNP_CARD_DISABLE; - /* Update PnP resource data if requested. */ - if (update_rom) - isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], sizeof(dev->ram_data) - dev->pnp_offset); + /* Update PnP resource data if requested. */ + if (update_rom) + isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], sizeof(dev->ram_data) - dev->pnp_offset); - /* Update PnP state. */ - isapnp_enable_card(dev->pnp_card, enable); - - /* While we're here, update FM and wavetable enable bits based on the config data in RAM. */ - if (dev->ram_data[3] & 0x08) { - dev->indirect_regs[8] |= 0x08; - dev->ad1848.wten = 1; - } else { - dev->indirect_regs[8] &= ~0x08; - dev->ad1848.wten = 0; + /* Update PnP state. */ + isapnp_enable_card(dev->pnp_card, enable); } - if (dev->ram_data[3] & 0x80) - dev->ad1848.xregs[4] |= 0x10; - else - dev->ad1848.xregs[4] &= ~0x10; - ad1848_updatevolmask(&dev->ad1848); + /* Update some register bits based on the config data in RAM if requested. */ + if (update_hwconfig) { + /* Update WTEN. */ + if (dev->ram_data[3] & 0x08) { + dev->indirect_regs[8] |= 0x08; + dev->ad1848.wten = 1; + } else { + dev->indirect_regs[8] &= ~0x08; + dev->ad1848.wten = 0; + } + + /* Update SPS. */ + if (dev->ram_data[3] & 0x04) + dev->indirect_regs[8] |= 0x04; + else + dev->indirect_regs[8] &= ~0x04; + + /* Update IFM. */ + if (dev->ram_data[3] & 0x80) + dev->ad1848.xregs[4] |= 0x10; + else + dev->ad1848.xregs[4] &= ~0x10; + + /* Inform WSS codec of the changes. */ + ad1848_updatevolmask(&dev->ad1848); + } } @@ -560,7 +580,7 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv case 0: /* WSS, OPL3 and SBPro */ if (dev->wss_base) { io_removehandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); - io_removehandler(dev->wss_base, 4, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + io_removehandler(dev->wss_base, 4, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); dev->wss_base = 0; } @@ -574,7 +594,7 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv io_removehandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); io_removehandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); io_removehandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); - io_removehandler(dev->sb_base, 16, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + io_removehandler(dev->sb_base, 16, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); dev->sb_base = 0; } @@ -588,7 +608,7 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv if (config->io[0].base != ISAPNP_IO_DISABLED) { dev->wss_base = config->io[0].base; io_sethandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); - io_sethandler(dev->wss_base, 4, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + io_sethandler(dev->wss_base, 4, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); } if (config->io[1].base != ISAPNP_IO_DISABLED) { @@ -602,7 +622,7 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv io_sethandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); io_sethandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); io_sethandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); - io_sethandler(dev->sb_base, 16, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + io_sethandler(dev->sb_base, 16, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); } if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) { @@ -674,10 +694,9 @@ cs423x_reset(void *priv) /* Reset PnP resource data, state and logical devices. */ dev->pnp_enable = 1; - if (dev->pnp_card) { - cs423x_pnp_enable(dev, 1); + cs423x_pnp_enable(dev, 1, 1); + if (dev->pnp_card) isapnp_reset_card(dev->pnp_card); - } /* Reset SLAM. */ cs423x_slam_enable(dev, 1); diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index aa00b33a4..8e1ea61a4 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1630,7 +1630,7 @@ sb_pro_cs423x_init(const device_t *info) sb_t *sb = malloc(sizeof(sb_t)); memset(sb, 0, sizeof(sb_t)); - sb->opl_enabled = 1; /* WSS can disable this to take ownership of the OPL */ + sb->opl_enabled = 0; /* updated by cs423x code */ opl3_init(&sb->opl); sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); From 5cd255a0e0e576db3346c2932d98c895be098865 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 15:31:10 -0300 Subject: [PATCH 21/25] Fix CS4236 codec remapped register reads --- src/sound/snd_ad1848.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 176da40da..ff4c0be83 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -135,9 +135,9 @@ ad1848_read(uint16_t addr, void *priv) case 18: case 19: if (ad1848->type == AD1848_TYPE_CS4236) { - if (ad1848->xregs[4] & 0x04) /* FM remapping */ + if ((ad1848->xregs[4] & 0x14) == 0x14) /* FM remapping */ ret = ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ - else if (ad1848->xregs[4] & 0x08) /* wavetable remapping */ + else if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) /* wavetable remapping */ ret = ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */ } break; From 62afe317570662a7831d1ca632d9d404f32a8fd1 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 16:02:04 -0300 Subject: [PATCH 22/25] Remove EBGA368 due to poor research (CPUs are Samuel 2 and newer only) --- src/cpu/cpu.c | 55 ---------------------------- src/cpu/cpu.h | 7 ++-- src/cpu/cpu_table.c | 11 ------ src/include/86box/machine.h | 4 --- src/machine/CMakeLists.txt | 3 +- src/machine/m_at_ebga368.c | 71 ------------------------------------- src/machine/machine_table.c | 5 --- src/win/Makefile.mingw | 1 - 8 files changed, 4 insertions(+), 153 deletions(-) delete mode 100644 src/machine/m_at_ebga368.c diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 34d3db534..62e497578 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -1278,7 +1278,6 @@ cpu_set(void) break; case CPU_CYRIX3S: - case CPU_EDEN: /* This until proper timings get discovered */ #ifdef USE_DYNAREC x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f); #else @@ -2015,58 +2014,6 @@ cpu_CPUID(void) break; } break; - - case CPU_EDEN: - switch (EAX) { - case 0: - EAX = 1; - if (msr.fcr2 & (1 << 14)) { - EBX = msr.fcr3 >> 32; - ECX = msr.fcr3 & 0xffffffff; - EDX = msr.fcr2 >> 32; - } else { - EBX = 0x746e6543; /* CentaurHauls */ - ECX = 0x736c7561; - EDX = 0x48727561; - } - break; - case 1: - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MMX | CPUID_MTRR; - if (cpu_has_feature(CPU_FEATURE_CX8)) - EDX |= CPUID_CMPXCHG8B; - break; - case 0x80000000: - EAX = 0x80000006; - break; - case 0x80000001: - EAX = CPUID; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MMX | CPUID_MTRR | CPUID_3DNOW; - if (cpu_has_feature(CPU_FEATURE_CX8)) - EDX |= CPUID_CMPXCHG8B; - break; - case 0x80000002: /* Processor name string */ - case 0x80000003: - case 0x80000004: - EAX = 0x20414956; /* VIA Samuel 2 */ - EBX = 0x756d6153; - ECX = 0x32206c65; - EDX = 0x00000000; - break; - case 0x80000005: /* Cache information */ - EBX = 0x08800880; /* TLBs */ - ECX = 0x40040120; /* L1 data cache */ - EDX = 0x40020120; /* L1 instruction cache */ - break; - case 0x80000006: - ECX = 0x40040120; /* L2 data cache */ - break; - default: - EAX = EBX = ECX = EDX = 0; - break; - } - break; } } @@ -2157,7 +2104,6 @@ cpu_RDMSR(void) break; case CPU_CYRIX3S: - case CPU_EDEN: EAX = EDX = 0; switch (ECX) { case 0x10: @@ -2609,7 +2555,6 @@ cpu_WRMSR(void) break; case CPU_CYRIX3S: - case CPU_EDEN: switch (ECX) { case 0x10: tsc = EAX | ((uint64_t)EDX << 32); diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 35209bc1a..d336b9a26 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -76,7 +76,6 @@ enum { CPU_K6_2P, CPU_K6_3P, CPU_CYRIX3S, - CPU_EDEN, CPU_PENTIUMPRO, /* 686 class CPUs */ CPU_PENTIUM2, CPU_PENTIUM2D @@ -247,7 +246,7 @@ typedef struct { uint64_t ia32_pmc[8]; /* 0x000000c1 - 0x000000c8 */ uint64_t mtrr_cap; /* 0x000000fe */ - /* IDT WinChip and WinChip 2 MSR's that are also on the VIA Cyrix III and Eden */ + /* IDT WinChip and WinChip 2 MSR's that are also on the VIA Cyrix III */ uint32_t fcr; /* 0x00000107 (IDT), 0x00001107 (VIA) */ uint64_t fcr2, fcr3; /* 0x00000108 (IDT), 0x00001108 (VIA) */ @@ -266,7 +265,7 @@ typedef struct { uint64_t ecx1e0; /* 0x000001e0 */ /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's that are also - on the VIA Cyrix III and Eden */ + on the VIA Cyrix III */ uint64_t mtrr_physbase[8]; /* 0x00000200 - 0x0000020f */ uint64_t mtrr_physmask[8]; /* 0x00000200 - 0x0000020f (ECX & 1) */ uint64_t mtrr_fix64k_8000; /* 0x00000250 */ @@ -278,7 +277,7 @@ typedef struct { uint64_t pat; /* 0x00000277 */ /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's that are also - on the VIA Cyrix III and Eden */ + on the VIA Cyrix III */ uint64_t mtrr_deftype; /* 0x000002ff */ /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 9f8d94ca4..fca0d60e3 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -1036,17 +1036,6 @@ const cpu_family_t cpu_families[] = { {"733", CPU_CYRIX3S, fpus_internal, 733333333, 5.5, 2050, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 66, 66, 18, 18, 88}, {"", 0} } - }, { - .package = CPU_PKG_EBGA368, - .manufacturer = "VIA", - .name = "Eden Model 7", - .internal_name = "c3_eden", - .cpus = (const CPU[]) { - {"66", CPU_EDEN, fpus_internal, 66666666, 1.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 6, 6, 3, 3, 8}, /* out of spec */ - {"100", CPU_EDEN, fpus_internal, 100000000, 1.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 9, 9, 4, 4, 12}, /* out of spec */ - {"400", CPU_EDEN, fpus_internal, 400000000, 6.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 36, 36, 17, 17, 48}, - {"600", CPU_EDEN, fpus_internal, 600000000, 6.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 54, 54, 18, 18, 72}, - } }, { .package = 0, } diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 677dc7027..5c6ee5567 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -111,7 +111,6 @@ enum { MACHINE_TYPE_SLOT1_2, MACHINE_TYPE_SLOT2, MACHINE_TYPE_SOCKET370, - MACHINE_TYPE_EBGA368, MACHINE_TYPE_MISC, MACHINE_TYPE_MAX }; @@ -565,9 +564,6 @@ extern int machine_at_603tcf_init(const machine_t *); extern int machine_at_trinity371_init(const machine_t *); extern int machine_at_p6bap_init(const machine_t *); -/* m_at_ebga368.c */ -extern int machine_at_arb9673_init(const machine_t *); - /* m_at_misc.c */ extern int machine_at_vpc2007_init(const machine_t *); diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 6c1745ea8..9b16413f6 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -20,8 +20,7 @@ add_library(mch OBJECT machine.c machine_table.c m_xt.c m_xt_compaq.c m_at_t3100e.c m_at_t3100e_vid.c m_ps1.c m_ps1_hdc.c m_ps2_isa.c m_ps2_mca.c m_at_compaq.c m_at_286_386sx.c m_at_386dx_486.c m_at_socket4_5.c m_at_socket7.c m_at_sockets7.c m_at_socket8.c - m_at_slot1.c m_at_slot2.c m_at_socket370.c m_at_ebga368.c - m_at_misc.c) + m_at_slot1.c m_at_slot2.c m_at_socket370.c m_at_misc.c) if(HEDAKA) target_compile_definitions(mch PRIVATE USE_HEDAKA) diff --git a/src/machine/m_at_ebga368.c b/src/machine/m_at_ebga368.c deleted file mode 100644 index 48f19390f..000000000 --- a/src/machine/m_at_ebga368.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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 VIA EBGA368 Based Single Board Computers. - * - * Note: 86Box doesn't emulate all the components a SBC may have. - * - * Authors: Miran Grca, - * Tiseno100 - * - * Copyright 2016-2019 Miran Grca. - * Copyright 2021 Tiseno100. - */ -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/mem.h> -#include <86box/io.h> -#include <86box/rom.h> -#include <86box/pci.h> -#include <86box/device.h> -#include <86box/chipset.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> -#include <86box/keyboard.h> -#include <86box/flash.h> -#include <86box/sio.h> -#include <86box/hwm.h> -#include <86box/spd.h> -#include <86box/video.h> -#include "cpu.h" -#include <86box/machine.h> - -int -machine_at_arb9673_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/arb9673/W9673.v12", - 0x00080000, 524288, 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(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); - device_add(&via_vt8601_device); - device_add(&via_vt82c686b_device); - device_add(&via_vt82c686_sio_device); - device_add(&via_vt82c686_hwm_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&sst_flash_39sf040_device); - spd_register(SPD_TYPE_SDRAM, 0xf, 32); - - - return ret; -} diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 117afc4d4..a1487d534 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -54,7 +54,6 @@ const machine_type_t machine_types[] = { { "Slot 1/2", MACHINE_TYPE_SLOT1_2 }, { "Slot 2", MACHINE_TYPE_SLOT2 }, { "Socket 370", MACHINE_TYPE_SOCKET370 }, - { "EBGA 368", MACHINE_TYPE_EBGA368 }, { "Miscellaneous", MACHINE_TYPE_MISC } }; @@ -464,10 +463,6 @@ const machine_t machines[] = { { "[VIA Apollo Pro133A] Acorp 6VIA90AP", "6via90ap", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, MACHINE_MULTIPLIER_FIXED, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_6via90ap_init, NULL }, { "[VIA Apollo ProMedia] Jetway 603TCF", "603tcf", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_603tcf_init, NULL }, - /* EBGA368 machines */ - /* VIA Apollo Pro */ - { "[VIA Apollo ProMedia] Acrosser AR-B9673","arb9673", MACHINE_TYPE_EBGA368, CPU_PKG_EBGA368, 0, 100000000, 133333333, 2050, 2050, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 131072, 131072, 0, 31, machine_at_arb9673_init, NULL }, - /* Miscellaneous/Fake/Hypervisor machines */ { "[i440BX] Microsoft Virtual PC 2007", "vpc2007", MACHINE_TYPE_MISC, CPU_PKG_SLOT1, CPU_BLOCK(CPU_PENTIUM2, CPU_CYRIX3S), 0, 0, 0, 0, 0, 0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_vpc2007_init, NULL }, diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 79ee75f06..258dec2bc 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -634,7 +634,6 @@ MCHOBJ := machine.o machine_table.o \ m_at_286_386sx.o m_at_386dx_486.o \ m_at_socket4_5.o m_at_socket7.o m_at_sockets7.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ - m_at_ebga368.o \ m_at_misc.o DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ From 2b692640e128bc68689ba88c0885c224ffbf98ae Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 16:02:15 -0300 Subject: [PATCH 23/25] Disable ISAPnP logging --- src/device/isapnp.c | 2 +- src/game/gameport.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 62abb3202..69da4ca13 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -53,7 +53,7 @@ static const uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; static const device_t isapnp_device; -#define ENABLE_ISAPNP_LOG 1 + #ifdef ENABLE_ISAPNP_LOG int isapnp_do_log = ENABLE_ISAPNP_LOG; diff --git a/src/game/gameport.c b/src/game/gameport.c index d33efb897..ce9e4b086 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -272,6 +272,7 @@ timer_over(void *priv) axis->joystick->state &= ~(1 << axis->axis_nr); + /* Notify the joystick when the first axis' period is finished. */ if (axis == &axis->joystick->axis[0]) axis->joystick->intf->a0_over(axis->joystick->dat); } From dc4906a23fa591ec58cd71bf15274c2459fce9b1 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 17:30:50 -0300 Subject: [PATCH 24/25] Fix ISAPnP logical devices going missing --- src/device/isapnp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 69da4ca13..e948d97f9 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -813,7 +813,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) while (ld && (ld->number != ldn)) ld = ld->next; } - if (ld) { + if (ld && (ld->number == ldn)) { /* Reset some logical device state. */ ld->mem_upperlimit = ld->io_16bit = ld->irq_types = 0; memset(ld->io_len, 0, sizeof(ld->io_len)); @@ -960,7 +960,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) } /* We're done with the last logical device. */ - if (ld) + if (ld && !existing) isapnp_reset_ld_regs(ld); } From 15888eeff87cb8362ee7cdc3d4269e7091e2cca1 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 17:40:54 -0300 Subject: [PATCH 25/25] Add snd_cs423x.c to CMake list --- src/sound/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 32d72a34f..d991e5cc2 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -16,8 +16,8 @@ add_library(snd OBJECT sound.c openal.c snd_opl.c snd_opl_nuked.c snd_resid.cc midi.c midi_system.c snd_speaker.c snd_pssj.c snd_lpt_dac.c snd_lpt_dss.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c - snd_azt2316a.c snd_cms.c snd_gus.c snd_sb.c snd_sb_dsp.c snd_emu8k.c - snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c) + snd_azt2316a.c snd_cms.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c + snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c) if(FLUIDSYNTH) target_compile_definitions(snd PRIVATE USE_FLUIDSYNTH)