diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 618991d63..66672d547 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -17,7 +17,8 @@ add_library(snd OBJECT sound.c snd_opl.c snd_opl_nuked.c snd_opl_ymfm.cpp snd_re midi.c snd_speaker.c snd_pssj.c snd_lpt_dac.c snd_ac97_codec.c snd_ac97_via.c snd_lpt_dss.c snd_ps1.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c snd_azt2316a.c snd_cms.c snd_cmi8x38.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) + snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c + snd_optimc.c) if(OPENAL) if(VCPKG_TOOLCHAIN) diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index cb845f916..8a734abd0 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -147,7 +147,6 @@ #include <86box/nvr.h> #include <86box/pic.h> #include <86box/sound.h> -#include <86box/gameport.h> #include <86box/snd_ad1848.h> #include <86box/snd_azt2316a.h> #include <86box/snd_sb.h> @@ -171,15 +170,14 @@ typedef struct azt2316a_t { int type; int wss_interrupt_after_config; - uint8_t wss_config, opti, opti_reg_enabled; + uint8_t wss_config; uint16_t cur_addr, cur_wss_addr, cur_mpu401_addr; - int cur_irq, cur_dma; - int cur_wss_enabled, cur_wss_irq, cur_wss_dma; - int cur_mpu401_irq; - int cur_mpu401_enabled; - void *gameport; + int cur_irq, cur_dma; + int cur_wss_enabled, cur_wss_irq, cur_wss_dma; + int cur_mpu401_irq; + int cur_mpu401_enabled; uint32_t config_word; uint32_t config_word_unlocked; @@ -189,8 +187,7 @@ typedef struct azt2316a_t { ad1848_t ad1848; mpu_t *mpu; - sb_t *sb; - uint8_t opti_regs[6]; + sb_t *sb; } azt2316a_t; static uint8_t @@ -202,7 +199,7 @@ azt2316a_wss_read(uint16_t addr, void *p) /* TODO: when windows is initializing, writing 0x48, 0x58 and 0x60 to 0x530 makes reading from 0x533 return 0x44, but writing 0x50 makes this return 0x04. Why? */ - if ((addr & 1) || (azt2316a->opti)) + if (addr & 1) temp = 4 | (azt2316a->wss_config & 0x40); else temp = 4 | (azt2316a->wss_config & 0xC0); @@ -871,9 +868,6 @@ azt2316a_get_buffer(int32_t *buffer, int len, void *p) azt2316a_t *azt2316a = (azt2316a_t *) p; int c; - if (azt2316a->opti && azt2316a->opti_regs[3] & 0x4) - return; - /* wss part */ ad1848_update(&azt2316a->ad1848); for (c = 0; c < len * 2; c++) @@ -885,224 +879,6 @@ azt2316a_get_buffer(int32_t *buffer, int len, void *p) sb_get_buffer_sbpro(buffer, len, azt2316a->sb); } -static void -optimc_remove_opl(azt2316a_t *azt2316a) -{ - io_removehandler(azt2316a->cur_addr + 0, 0x0004, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); - io_removehandler(azt2316a->cur_addr + 8, 0x0002, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); - io_removehandler(0x0388, 0x0004, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); -} - -static void -optimc_add_opl(azt2316a_t *azt2316a) -{ - if (!(azt2316a->opti_regs[3] & 0x8) && (azt2316a->opti_regs[1] & 0x20)) { - fm_driver_get(FM_YMF289B, &azt2316a->sb->opl); - } else { - fm_driver_get((azt2316a->opti_regs[3] & 0x8) ? FM_YM3812 : FM_YMF262, &azt2316a->sb->opl); - } - - /* DSP I/O handler is activated in sb_dsp_setaddr */ - io_sethandler(azt2316a->cur_addr + 0, 0x0004, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); - io_sethandler(azt2316a->cur_addr + 8, 0x0002, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); - io_sethandler(0x0388, 0x0004, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); -} - -static void -optimc_reload_opl(azt2316a_t *azt2316a) -{ - optimc_remove_opl(azt2316a); - optimc_add_opl(azt2316a); -} - -static void -optimc_reg_write(uint16_t addr, uint8_t val, void *p) -{ - azt2316a_t *azt2316a = (azt2316a_t *) p; - uint16_t idx = addr - 0xF8D; - uint8_t old = azt2316a->opti_regs[idx]; - static uint8_t reg_enable_phase = 0; - - if (azt2316a->opti_reg_enabled) { - switch (idx) { - case 0: /* MC1 */ - { - azt2316a->opti_regs[0] = val; - if (val != old) { - azt2316a->cur_mode = azt2316a->cur_wss_enabled = !!(val & 0x80); - io_removehandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); - io_removehandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); - switch ((val >> 4) & 0x3) { - case 0: /* WSBase = 0x530 */ - { - azt2316a->cur_wss_addr = 0x530; - break; - } - case 1: /* WSBase = 0xE80 */ - { - azt2316a->cur_wss_addr = 0xE80; - break; - } - case 2: /* WSBase = 0xF40 */ - { - azt2316a->cur_wss_addr = 0xF40; - break; - } - case 3: /* WSBase = 0x604 */ - { - azt2316a->cur_wss_addr = 0x604; - break; - } - } - io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); - io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); - - gameport_remap(azt2316a->gameport, (azt2316a->opti_regs[0] & 0x1) ? 0x00 : 0x200); - } - break; - } - case 1: /* MC2 */ - azt2316a->opti_regs[1] = val; - if (old != val) - optimc_reload_opl(azt2316a); - break; - case 2: /* MC3 */ - if (val == 0xE3) - break; - azt2316a->opti_regs[2] = val; - if (old != val) { - optimc_remove_opl(azt2316a); - azt2316a->cur_addr = (val & 0x4) ? 0x240 : 0x220; - switch ((val >> 4) & 0x3) { - case 0: - azt2316a->cur_dma = 1; - break; - case 1: - azt2316a->cur_dma = 0; - break; - case 2: - default: - azt2316a->cur_dma = 3; - break; - } - switch ((val >> 6) & 0x3) { - case 0: - azt2316a->cur_irq = 7; - break; - case 1: - azt2316a->cur_irq = 10; - break; - case 2: - default: - azt2316a->cur_irq = 5; - break; - } - sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); - sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); - sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); - optimc_add_opl(azt2316a); - } - break; - case 3: /* MC4 */ - azt2316a->opti_regs[3] = val; - if ((old & 0x8) != (val & 0x8)) - optimc_reload_opl(azt2316a); - break; - case 4: /* MC5 */ - azt2316a->opti_regs[4] = val; - break; - case 5: /* MC6 */ - azt2316a->opti_regs[5] = val; - if (old != val) { - switch ((val >> 3) & 0x3) { - case 0: - azt2316a->cur_mpu401_irq = 9; - break; - case 1: - azt2316a->cur_mpu401_irq = 10; - break; - case 2: - azt2316a->cur_mpu401_irq = 5; - break; - case 3: - azt2316a->cur_mpu401_irq = 7; - break; - } - switch ((val >> 5) & 0x3) { - case 0: - azt2316a->cur_mpu401_addr = 0x330; - break; - case 1: - azt2316a->cur_mpu401_addr = 0x320; - break; - case 2: - azt2316a->cur_mpu401_addr = 0x310; - break; - case 3: - azt2316a->cur_mpu401_addr = 0x300; - break; - } - mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); - mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); - } - break; - } - } - if (azt2316a->opti_reg_enabled) - azt2316a->opti_reg_enabled = 0; - if (addr == 0xF8F && (val == 0xE3 || val == 0x00)) { - if (addr == 0xF8F && val == 0xE3 && !azt2316a->opti_reg_enabled) { - azt2316a->opti_reg_enabled = 1; - } - if (reg_enable_phase) { - switch (reg_enable_phase) { - case 1: - if (val == 0xE3) { - reg_enable_phase++; - } - break; - case 2: - if (val == 0x00) { - reg_enable_phase++; - } - break; - case 3: - if (val == 0xE3) { - azt2316a->opti_regs[2] = 0x2; - reg_enable_phase = 1; - } - break; - } - } else - reg_enable_phase = 1; - return; - } -} - -static uint8_t -optimc_reg_read(uint16_t addr, void *p) -{ - azt2316a_t *azt2316a = (azt2316a_t *) p; - uint8_t temp = 0xFF; - - if (azt2316a->opti_reg_enabled) { - switch (addr - 0xF8D) { - case 0: /* MC1 */ - case 1: /* MC2 */ - case 3: /* MC4 */ - case 4: /* MC5 */ - temp = azt2316a->opti_regs[addr - 0xF8D]; - case 5: /* MC6 (not readable) */ - break; - case 2: /* MC3 */ - temp = (azt2316a->opti_regs[2] & ~0x3) | 0x2; - break; - } - azt2316a->opti_reg_enabled = 0; - } - return temp; -} - static void * azt_init(const device_t *info) { @@ -1115,38 +891,32 @@ azt_init(const device_t *info) azt2316a_t *azt2316a = malloc(sizeof(azt2316a_t)); memset(azt2316a, 0, sizeof(azt2316a_t)); - azt2316a->type = info->local & 0x7fffffff; - azt2316a->opti = !!(info->local & 0x80000000); + azt2316a->type = info->local; if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { fn = "azt1605.nvr"; } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { - if (info->local & 0x80000000) - fn = "acermagic_s20.nvr"; - else - fn = "azt2316a.nvr"; + fn = "azt2316a.nvr"; } - /* config (not saved for AcerMagic S20). */ - if (!azt2316a->opti) { - f = nvr_fopen(fn, "rb"); - if (f) { - uint8_t checksum = 0x7f; - uint8_t saved_checksum; - size_t res; + /* config */ + f = nvr_fopen(fn, "rb"); + if (f) { + uint8_t checksum = 0x7f; + uint8_t saved_checksum; + size_t res; - res = fread(read_eeprom, AZTECH_EEPROM_SIZE, 1, f); - for (i = 0; i < AZTECH_EEPROM_SIZE; i++) - checksum += read_eeprom[i]; + res = fread(read_eeprom, AZTECH_EEPROM_SIZE, 1, f); + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + checksum += read_eeprom[i]; - res = fread(&saved_checksum, sizeof(saved_checksum), 1, f); - (void) res; + res = fread(&saved_checksum, sizeof(saved_checksum), 1, f); + (void) res; - fclose(f); + fclose(f); - if (checksum == saved_checksum) - loaded_from_eeprom = 1; - } + if (checksum == saved_checksum) + loaded_from_eeprom = 1; } if (!loaded_from_eeprom) { @@ -1188,117 +958,91 @@ azt_init(const device_t *info) } if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { - if (azt2316a->opti) { - /* OPTi 82C929 has no EEPROM interface. */ - azt2316a->cur_wss_addr = 0x530; - azt2316a->cur_mode = 0; - azt2316a->cur_addr = 0x220; - azt2316a->cur_irq = 7; - azt2316a->cur_wss_enabled = 0; - azt2316a->cur_dma = 1; - azt2316a->cur_mpu401_irq = 9; - azt2316a->cur_mpu401_addr = 0x330; - azt2316a->cur_mpu401_enabled = 1; + azt2316a->config_word = read_eeprom[11] | (read_eeprom[12] << 8) | (read_eeprom[13] << 16) | (read_eeprom[14] << 24); - azt2316a->opti_regs[0] = ((device_get_config_int("gameport")) ? 0x01 : 0x00); - azt2316a->opti_regs[1] = 0x03; - azt2316a->opti_regs[2] = 0x00; - azt2316a->opti_regs[3] = 0x00; - azt2316a->opti_regs[4] = 0x2F; - azt2316a->opti_regs[5] = 0x83; - - azt2316a->gameport = gameport_add(&gameport_device); - gameport_remap(azt2316a->gameport, (azt2316a->opti_regs[0] & 0x1) ? 0x00 : 0x200); - } else { - azt2316a->config_word = read_eeprom[11] | (read_eeprom[12] << 8) | (read_eeprom[13] << 16) | (read_eeprom[14] << 24); - - switch (azt2316a->config_word & (3 << 0)) { - case 0: - azt2316a->cur_addr = 0x220; - break; - case 1: - azt2316a->cur_addr = 0x240; - break; - default: - fatal("AZT2316A: invalid sb addr in config word %08X\n", azt2316a->config_word); - } - - if (azt2316a->config_word & (1 << 2)) - azt2316a->cur_irq = 9; - else if (azt2316a->config_word & (1 << 3)) - azt2316a->cur_irq = 5; - else if (azt2316a->config_word & (1 << 4)) - azt2316a->cur_irq = 7; - else if (azt2316a->config_word & (1 << 5)) - azt2316a->cur_irq = 10; - else - fatal("AZT2316A: invalid sb irq in config word %08X\n", azt2316a->config_word); - - if (info->local & 0x80000000) - azt2316a->cur_dma = 1; - else - switch (azt2316a->config_word & (3 << 6)) { - case 1 << 6: - azt2316a->cur_dma = 0; - break; - case 2 << 6: - azt2316a->cur_dma = 1; - break; - case 3 << 6: - azt2316a->cur_dma = 3; - break; - default: - fatal("AZT2316A: invalid sb dma in config word %08X\n", azt2316a->config_word); - } - - switch (azt2316a->config_word & (3 << 8)) { - case 0: - azt2316a->cur_wss_addr = 0x530; - break; - case 1 << 8: - azt2316a->cur_wss_addr = 0x604; - break; - case 2 << 8: - azt2316a->cur_wss_addr = 0xE80; - break; - case 3 << 8: - azt2316a->cur_wss_addr = 0xF40; - break; - default: - fatal("AZT2316A: invalid wss addr in config word %08X\n", azt2316a->config_word); - } - - if (azt2316a->config_word & (1 << 10)) - azt2316a->cur_wss_enabled = 1; - else - azt2316a->cur_wss_enabled = 0; - - if (azt2316a->config_word & (1 << 12)) - azt2316a->cur_mpu401_addr = 0x330; - else - azt2316a->cur_mpu401_addr = 0x300; - - if (azt2316a->config_word & (1 << 13)) - azt2316a->cur_mpu401_enabled = 1; - else - azt2316a->cur_mpu401_enabled = 0; - - if (azt2316a->config_word & (1 << 24)) - azt2316a->cur_mpu401_irq = 9; - else if (azt2316a->config_word & (1 << 25)) - azt2316a->cur_mpu401_irq = 5; - else if (azt2316a->config_word & (1 << 26)) - azt2316a->cur_mpu401_irq = 7; - else if (azt2316a->config_word & (1 << 27)) - azt2316a->cur_mpu401_irq = 10; - else - fatal("AZT2316A: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); - - /* these are not present on the EEPROM */ - azt2316a->cur_wss_irq = device_get_config_int("wss_irq"); - azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); - azt2316a->cur_mode = 0; + switch (azt2316a->config_word & (3 << 0)) { + case 0: + azt2316a->cur_addr = 0x220; + break; + case 1: + azt2316a->cur_addr = 0x240; + break; + default: + fatal("AZT2316A: invalid sb addr in config word %08X\n", azt2316a->config_word); } + + if (azt2316a->config_word & (1 << 2)) + azt2316a->cur_irq = 9; + else if (azt2316a->config_word & (1 << 3)) + azt2316a->cur_irq = 5; + else if (azt2316a->config_word & (1 << 4)) + azt2316a->cur_irq = 7; + else if (azt2316a->config_word & (1 << 5)) + azt2316a->cur_irq = 10; + else + fatal("AZT2316A: invalid sb irq in config word %08X\n", azt2316a->config_word); + + switch (azt2316a->config_word & (3 << 6)) { + case 1 << 6: + azt2316a->cur_dma = 0; + break; + case 2 << 6: + azt2316a->cur_dma = 1; + break; + case 3 << 6: + azt2316a->cur_dma = 3; + break; + default: + fatal("AZT2316A: invalid sb dma in config word %08X\n", azt2316a->config_word); + } + + switch (azt2316a->config_word & (3 << 8)) { + case 0: + azt2316a->cur_wss_addr = 0x530; + break; + case 1 << 8: + azt2316a->cur_wss_addr = 0x604; + break; + case 2 << 8: + azt2316a->cur_wss_addr = 0xE80; + break; + case 3 << 8: + azt2316a->cur_wss_addr = 0xF40; + break; + default: + fatal("AZT2316A: invalid wss addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 10)) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + if (azt2316a->config_word & (1 << 12)) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (azt2316a->config_word & (1 << 13)) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + + if (azt2316a->config_word & (1 << 24)) + azt2316a->cur_mpu401_irq = 9; + else if (azt2316a->config_word & (1 << 25)) + azt2316a->cur_mpu401_irq = 5; + else if (azt2316a->config_word & (1 << 26)) + azt2316a->cur_mpu401_irq = 7; + else if (azt2316a->config_word & (1 << 27)) + azt2316a->cur_mpu401_irq = 10; + else + fatal("AZT2316A: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); + + /* these are not present on the EEPROM */ + azt2316a->cur_wss_irq = device_get_config_int("wss_irq"); + azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); + azt2316a->cur_mode = 0; } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { azt2316a->config_word = read_eeprom[12] + (read_eeprom[13] << 8) + (read_eeprom[14] << 16); @@ -1368,35 +1112,25 @@ azt_init(const device_t *info) azt2316a->cur_wss_enabled = 0; // these are not present on the EEPROM - if (info->local & 0x80000000) - azt2316a->cur_dma = 1; - else - azt2316a->cur_dma = device_get_config_int("sb_dma8"); // TODO: investigate TSR to make this work with it - there is no software configurable DMA8? + azt2316a->cur_dma = device_get_config_int("sb_dma8"); // TODO: investigate TSR to make this work with it - there is no software configurable DMA8? azt2316a->cur_wss_irq = device_get_config_int("wss_irq"); azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); azt2316a->cur_mode = 0; } - addr_setting = (azt2316a->opti) ? 0 : device_get_config_hex16("addr"); + addr_setting = device_get_config_hex16("addr"); if (addr_setting) azt2316a->cur_addr = addr_setting; - azt2316a->wss_interrupt_after_config = (!!(azt2316a->opti)) ? 0 : device_get_config_int("wss_interrupt_after_config"); + azt2316a->wss_interrupt_after_config = device_get_config_int("wss_interrupt_after_config"); /* wss part */ - if (info->local & 0x80000000) - ad1848_init(&azt2316a->ad1848, AD1848_TYPE_CS4231); - else - ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); + ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); ad1848_setirq(&azt2316a->ad1848, azt2316a->cur_wss_irq); ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); - if (!azt2316a->opti) { - io_sethandler(azt2316a->cur_addr + 0x0400, 0x0040, azt2316a_config_read, NULL, NULL, azt2316a_config_write, NULL, NULL, azt2316a); - } else { - io_sethandler(0xF8D, 6, optimc_reg_read, NULL, NULL, optimc_reg_write, NULL, NULL, azt2316a); - } + io_sethandler(azt2316a->cur_addr + 0x0400, 0x0040, azt2316a_config_read, NULL, NULL, azt2316a_config_write, NULL, NULL, azt2316a); io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); @@ -1409,20 +1143,19 @@ azt_init(const device_t *info) azt2316a->sb = malloc(sizeof(sb_t)); memset(azt2316a->sb, 0, sizeof(sb_t)); - azt2316a->sb->opl_enabled = (azt2316a->opti) ? 1 : device_get_config_int("opl"); + azt2316a->sb->opl_enabled = device_get_config_int("opl"); for (i = 0; i < AZTECH_EEPROM_SIZE; i++) azt2316a->sb->dsp.azt_eeprom[i] = read_eeprom[i]; + if (azt2316a->sb->opl_enabled) + fm_driver_get(FM_YMF262, &azt2316a->sb->opl); + sb_dsp_init(&azt2316a->sb->dsp, SBPRO2, azt2316a->type, azt2316a); sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); sb_ct1345_mixer_reset(azt2316a->sb); - - if (azt2316a->sb->opl_enabled) - fm_driver_get(FM_YMF262, &azt2316a->sb->opl); - /* DSP I/O handler is activated in sb_dsp_setaddr */ if (azt2316a->sb->opl_enabled) { io_sethandler(azt2316a->cur_addr + 0, 0x0004, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); @@ -1458,31 +1191,30 @@ azt_close(void *p) uint8_t checksum = 0x7f; int i; - if (!azt2316a->opti) { - if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { - fn = "azt1605.nvr"; - } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { - fn = "azt2316a.nvr"; - } + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + fn = "azt1605.nvr"; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + fn = "azt2316a.nvr"; + } - /* always save to eeprom (recover from bad values) */ - f = nvr_fopen(fn, "wb"); - if (f) { - for (i = 0; i < AZTECH_EEPROM_SIZE; i++) - checksum += azt2316a->sb->dsp.azt_eeprom[i]; - fwrite(azt2316a->sb->dsp.azt_eeprom, AZTECH_EEPROM_SIZE, 1, f); + /* always save to eeprom (recover from bad values) */ + f = nvr_fopen(fn, "wb"); + if (f) { + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + checksum += azt2316a->sb->dsp.azt_eeprom[i]; + fwrite(azt2316a->sb->dsp.azt_eeprom, AZTECH_EEPROM_SIZE, 1, f); - // TODO: confirm any models saving mixer settings to EEPROM and implement reading back - // TODO: should remember to save wss duplex setting if 86Box has voice recording implemented in the future? Also, default azt2316a->wss_config - // TODO: azt2316a->cur_mode is not saved to EEPROM? - fwrite(&checksum, sizeof(checksum), 1, f); + // TODO: confirm any models saving mixer settings to EEPROM and implement reading back + // TODO: should remember to save wss duplex setting if 86Box has voice recording implemented in the future? Also, default azt2316a->wss_config + // TODO: azt2316a->cur_mode is not saved to EEPROM? + fwrite(&checksum, sizeof(checksum), 1, f); - fclose(f); - } + fclose(f); } sb_close(azt2316a->sb); + free(azt2316a->mpu); free(azt2316a); } @@ -1757,33 +1489,7 @@ static const device_config_t azt2316a_config[] = { .default_int = 0 }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on -}; - -static const device_config_t acermagic_s20_config[] = { - // clang-format off - { - .name = "gameport", - .description = "Gameport", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - .name = "receive_input", - .description = "Receive input (SB MIDI)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 - }, - { - .name = "receive_input401", - .description = "Receive input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 - }, - { .name = "", .description = "", .type = CONFIG_END } - // clang-format on +// clang-format on }; const device_t azt2316a_device = { @@ -1800,20 +1506,6 @@ const device_t azt2316a_device = { .config = azt2316a_config }; -const device_t acermagic_s20_device = { - .name = "AcerMagic S20", - .internal_name = "acermagic_s20", - .flags = DEVICE_ISA | DEVICE_AT, - .local = SB_SUBTYPE_CLONE_AZT2316A_0X11 | 0x80000000, - .init = azt_init, - .close = azt_close, - .reset = NULL, - { .available = NULL }, - .speed_changed = azt_speed_changed, - .force_redraw = NULL, - .config = acermagic_s20_config -}; - const device_t azt1605_device = { .name = "Aztech Sound Galaxy Nova 16 Extra (Clinton)", .internal_name = "azt1605", diff --git a/src/sound/snd_optimc.c b/src/sound/snd_optimc.c new file mode 100644 index 000000000..d2aca8345 --- /dev/null +++ b/src/sound/snd_optimc.c @@ -0,0 +1,457 @@ +/* + * 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. + * + * OPTi MediaCHIPS 82C929 audio controller emulation. + * + * + * + * Authors: Cacodemon345 + * Eluan Costa Miranda + * + * Copyright 2022 Cacodemon345. + * Copyright 2020 Eluan Costa Miranda. + */ + +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H + +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/midi.h> +#include <86box/timer.h> +#include <86box/nvr.h> +#include <86box/pic.h> +#include <86box/sound.h> +#include <86box/gameport.h> +#include <86box/snd_ad1848.h> +#include <86box/snd_sb.h> + +static int optimc_wss_dma[4] = { 0, 0, 1, 3 }; +static int optimc_wss_irq[8] = { 5, 7, 9, 10, 11, 12, 14, 15 }; /* W95 only uses 7-10, others may be wrong */ + +enum optimc_local_flags { + OPTIMC_CS4231 = 0x100, + OPTIMC_OPL4 = 0x200, /* Unused */ +}; + +typedef struct optimc_t { + uint8_t type, fm_type; + + uint8_t wss_config, reg_enabled; + + uint16_t cur_addr, cur_wss_addr, cur_mpu401_addr; + + int cur_irq, cur_dma; + int cur_wss_enabled, cur_wss_irq, cur_wss_dma; + int cur_mpu401_irq; + int cur_mpu401_enabled; + void *gameport; + + uint8_t cur_mode; + + ad1848_t ad1848; + mpu_t *mpu; + + sb_t *sb; + uint8_t regs[6]; +} optimc_t, opti_82c929_t; + +static uint8_t +optimc_wss_read(uint16_t addr, void *priv) +{ + optimc_t *optimc = (optimc_t *) priv; + + if (!(optimc->regs[4] & 0x10) && optimc->cur_mode == 0) + return 0xFF; + + return 4 | (optimc->wss_config & 0x40); +} + +static void +optimc_wss_write(uint16_t addr, uint8_t val, void *priv) +{ + optimc_t *optimc = (optimc_t *) priv; + + if (!(optimc->regs[4] & 0x10) && optimc->cur_mode == 0) return; + optimc->wss_config = val; + ad1848_setdma(&optimc->ad1848, optimc_wss_dma[val & 3]); + ad1848_setirq(&optimc->ad1848, optimc_wss_irq[(val >> 3) & 7]); +} + +static void +optimc_get_buffer(int32_t *buffer, int len, void *p) +{ + optimc_t *optimc = (optimc_t *) p; + int c; + + if (optimc->regs[3] & 0x4) + return; + + /* wss part */ + ad1848_update(&optimc->ad1848); + for (c = 0; c < len * 2; c++) + buffer[c] += (optimc->ad1848.buffer[c] / 2); + + optimc->ad1848.pos = 0; + + /* sbprov2 part */ + sb_get_buffer_sbpro(buffer, len, optimc->sb); +} + +static void +optimc_remove_opl(optimc_t *optimc) +{ + io_removehandler(optimc->cur_addr + 0, 0x0004, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); + io_removehandler(optimc->cur_addr + 8, 0x0002, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); + io_removehandler(0x0388, 0x0004, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); +} + +static void +optimc_add_opl(optimc_t *optimc) +{ + fm_driver_get(FM_YMF262, &optimc->sb->opl); + + /* DSP I/O handler is activated in sb_dsp_setaddr */ + io_sethandler(optimc->cur_addr + 0, 0x0004, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); + io_sethandler(optimc->cur_addr + 8, 0x0002, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); + io_sethandler(0x0388, 0x0004, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); +} + +static void +optimc_reload_opl(optimc_t *optimc) +{ + optimc_remove_opl(optimc); + optimc_add_opl(optimc); +} + +static void +optimc_reg_write(uint16_t addr, uint8_t val, void *p) +{ + optimc_t *optimc = (optimc_t *) p; + uint16_t idx = addr - 0xF8D; + uint8_t old = optimc->regs[idx]; + static uint8_t reg_enable_phase = 0; + + if (optimc->reg_enabled) { + switch (idx) { + case 0: /* MC1 */ + { + optimc->regs[0] = val; + if (val != old) { + optimc->cur_mode = optimc->cur_wss_enabled = !!(val & 0x80); + io_removehandler(optimc->cur_wss_addr, 0x0004, optimc_wss_read, NULL, NULL, optimc_wss_write, NULL, NULL, optimc); + io_removehandler(optimc->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &optimc->ad1848); + switch ((val >> 4) & 0x3) { + case 0: /* WSBase = 0x530 */ + { + optimc->cur_wss_addr = 0x530; + break; + } + case 1: /* WSBase = 0xE80 */ + { + optimc->cur_wss_addr = 0xE80; + break; + } + case 2: /* WSBase = 0xF40 */ + { + optimc->cur_wss_addr = 0xF40; + break; + } + case 3: /* WSBase = 0x604 */ + { + optimc->cur_wss_addr = 0x604; + break; + } + } + io_sethandler(optimc->cur_wss_addr, 0x0004, optimc_wss_read, NULL, NULL, optimc_wss_write, NULL, NULL, optimc); + io_sethandler(optimc->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &optimc->ad1848); + + gameport_remap(optimc->gameport, (optimc->regs[0] & 0x1) ? 0x00 : 0x200); + } + break; + } + case 1: /* MC2 */ + optimc->regs[1] = val; + if (old != val) + optimc_reload_opl(optimc); + break; + case 2: /* MC3 */ + if (val == optimc->type) + break; + optimc->regs[2] = val; + if (old != val) { + io_removehandler(optimc->cur_addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, optimc->sb); + optimc_remove_opl(optimc); + optimc->cur_addr = (val & 0x4) ? 0x240 : 0x220; + switch ((val >> 4) & 0x3) { + case 0: + optimc->cur_dma = 1; + break; + case 1: + optimc->cur_dma = 0; + break; + case 2: + default: + optimc->cur_dma = 3; + break; + } + switch ((val >> 6) & 0x3) { + case 0: + optimc->cur_irq = 7; + break; + case 1: + optimc->cur_irq = 10; + break; + case 2: + default: + optimc->cur_irq = 5; + break; + } + sb_dsp_setaddr(&optimc->sb->dsp, optimc->cur_addr); + sb_dsp_setirq(&optimc->sb->dsp, optimc->cur_irq); + sb_dsp_setdma8(&optimc->sb->dsp, optimc->cur_dma); + optimc_add_opl(optimc); + io_sethandler(optimc->cur_addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, optimc->sb); + } + break; + case 3: /* MC4 */ + optimc->regs[3] = val; + if ((old & 0x8) != (val & 0x8)) + optimc_reload_opl(optimc); + break; + case 4: /* MC5 */ + optimc->regs[4] = val; + break; + case 5: /* MC6 */ + optimc->regs[5] = val; + if (old != val) { + switch ((val >> 3) & 0x3) { + case 0: + optimc->cur_mpu401_irq = 9; + break; + case 1: + optimc->cur_mpu401_irq = 10; + break; + case 2: + optimc->cur_mpu401_irq = 5; + break; + case 3: + optimc->cur_mpu401_irq = 7; + break; + } + switch ((val >> 5) & 0x3) { + case 0: + optimc->cur_mpu401_addr = 0x330; + break; + case 1: + optimc->cur_mpu401_addr = 0x320; + break; + case 2: + optimc->cur_mpu401_addr = 0x310; + break; + case 3: + optimc->cur_mpu401_addr = 0x300; + break; + } + mpu401_change_addr(optimc->mpu, optimc->cur_mpu401_addr); + mpu401_setirq(optimc->mpu, optimc->cur_mpu401_irq); + } + break; + } + } + if (optimc->reg_enabled) + optimc->reg_enabled = 0; + if (addr == 0xF8F && (val == optimc->type || val == 0x00)) { + if (addr == 0xF8F && val == optimc->type && !optimc->reg_enabled) { + optimc->reg_enabled = 1; + } + if (reg_enable_phase) { + switch (reg_enable_phase) { + case 1: + if (val == optimc->type) { + reg_enable_phase++; + } + break; + case 2: + if (val == 0x00) { + reg_enable_phase++; + } + break; + case 3: + if (val == optimc->type) { + optimc->regs[2] = 0x2; + reg_enable_phase = 1; + } + break; + } + } else + reg_enable_phase = 1; + return; + } +} + +static uint8_t +optimc_reg_read(uint16_t addr, void *p) +{ + optimc_t *optimc = (optimc_t *) p; + uint8_t temp = 0xFF; + + if (optimc->reg_enabled) { + switch (addr - 0xF8D) { + case 0: /* MC1 */ + case 1: /* MC2 */ + case 3: /* MC4 */ + case 4: /* MC5 */ + temp = optimc->regs[addr - 0xF8D]; + case 5: /* MC6 (not readable) */ + break; + case 2: /* MC3 */ + temp = (optimc->regs[2] & ~0x3) | 0x2; + break; + } + optimc->reg_enabled = 0; + } + return temp; +} + +static void * +optimc_init(const device_t *info) +{ + optimc_t *optimc = calloc(1, sizeof(optimc_t)); + + optimc->type = info->local & 0xFF; + + optimc->cur_wss_addr = 0x530; + optimc->cur_mode = 0; + optimc->cur_addr = 0x220; + optimc->cur_irq = 7; + optimc->cur_wss_enabled = 0; + optimc->cur_dma = 1; + optimc->cur_mpu401_irq = 9; + optimc->cur_mpu401_addr = 0x330; + optimc->cur_mpu401_enabled = 1; + + optimc->regs[0] = ((device_get_config_int("gameport")) ? 0x01 : 0x00); + optimc->regs[1] = 0x03; + optimc->regs[2] = 0x00; + optimc->regs[3] = 0x00; + optimc->regs[4] = 0x2F; + optimc->regs[5] = 0x83; + + optimc->gameport = gameport_add(&gameport_device); + gameport_remap(optimc->gameport, (optimc->regs[0] & 0x1) ? 0x00 : 0x200); + + if (info->local & 0x100) + ad1848_init(&optimc->ad1848, AD1848_TYPE_CS4231); + else + ad1848_init(&optimc->ad1848, AD1848_TYPE_DEFAULT); + + ad1848_setirq(&optimc->ad1848, optimc->cur_wss_irq); + ad1848_setdma(&optimc->ad1848, optimc->cur_wss_dma); + + io_sethandler(0xF8D, 6, optimc_reg_read, NULL, NULL, optimc_reg_write, NULL, NULL, optimc); + + io_sethandler(optimc->cur_wss_addr, 0x0004, optimc_wss_read, NULL, NULL, optimc_wss_write, NULL, NULL, optimc); + io_sethandler(optimc->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &optimc->ad1848); + + optimc->sb = calloc(1, sizeof(sb_t)); + optimc->sb->opl_enabled = 1; + + sb_dsp_init(&optimc->sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, optimc); + sb_dsp_setaddr(&optimc->sb->dsp, optimc->cur_addr); + sb_dsp_setirq(&optimc->sb->dsp, optimc->cur_irq); + sb_dsp_setdma8(&optimc->sb->dsp, optimc->cur_dma); + sb_ct1345_mixer_reset(optimc->sb); + + optimc->fm_type = (info->local & OPTIMC_OPL4) ? FM_YMF289B : FM_YMF262; + fm_driver_get(optimc->fm_type, &optimc->sb->opl); + io_sethandler(optimc->cur_addr + 0, 0x0004, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); + io_sethandler(optimc->cur_addr + 8, 0x0002, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); + io_sethandler(0x0388, 0x0004, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv); + + io_sethandler(optimc->cur_addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, optimc->sb); + + sound_add_handler(optimc_get_buffer, optimc); + sound_set_cd_audio_filter(sbpro_filter_cd_audio, optimc->sb); + + optimc->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(optimc->mpu, 0, sizeof(mpu_t)); + mpu401_init(optimc->mpu, optimc->cur_mpu401_addr, optimc->cur_mpu401_irq, M_UART, device_get_config_int("receive_input401")); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &optimc->sb->dsp); + + return optimc; +} + +static void +optimc_close(void *p) +{ + optimc_t* optimc = (optimc_t*)p; + + sb_close(optimc->sb); + free(optimc->mpu); + free(p); +} + +static void +optimc_speed_changed(void *p) +{ + optimc_t *optimc = (optimc_t *) p; + + ad1848_speed_changed(&optimc->ad1848); + sb_speed_changed(optimc->sb); +} + +static const device_config_t acermagic_s20_config[] = { + // clang-format off + { + .name = "gameport", + .description = "Gameport", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input401", + .description = "Receive input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + + +const device_t acermagic_s20_device = { + .name = "AcerMagic S20", + .internal_name = "acermagic_s20", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0xE3 | 0x100, + .init = optimc_init, + .close = optimc_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = optimc_speed_changed, + .force_redraw = NULL, + .config = acermagic_s20_config +}; \ No newline at end of file