Merge pull request #2870 from Cacodemon345/optimc_split

Split AcerMagic S20 code into its own file
This commit is contained in:
Miran Grča
2022-11-16 17:28:33 +01:00
committed by GitHub
3 changed files with 592 additions and 442 deletions

View File

@@ -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 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_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_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(OPENAL)
if(VCPKG_TOOLCHAIN) if(VCPKG_TOOLCHAIN)

View File

@@ -147,7 +147,6 @@
#include <86box/nvr.h> #include <86box/nvr.h>
#include <86box/pic.h> #include <86box/pic.h>
#include <86box/sound.h> #include <86box/sound.h>
#include <86box/gameport.h>
#include <86box/snd_ad1848.h> #include <86box/snd_ad1848.h>
#include <86box/snd_azt2316a.h> #include <86box/snd_azt2316a.h>
#include <86box/snd_sb.h> #include <86box/snd_sb.h>
@@ -171,7 +170,7 @@ typedef struct azt2316a_t {
int type; int type;
int wss_interrupt_after_config; 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; uint16_t cur_addr, cur_wss_addr, cur_mpu401_addr;
@@ -179,7 +178,6 @@ typedef struct azt2316a_t {
int cur_wss_enabled, cur_wss_irq, cur_wss_dma; int cur_wss_enabled, cur_wss_irq, cur_wss_dma;
int cur_mpu401_irq; int cur_mpu401_irq;
int cur_mpu401_enabled; int cur_mpu401_enabled;
void *gameport;
uint32_t config_word; uint32_t config_word;
uint32_t config_word_unlocked; uint32_t config_word_unlocked;
@@ -190,7 +188,6 @@ typedef struct azt2316a_t {
mpu_t *mpu; mpu_t *mpu;
sb_t *sb; sb_t *sb;
uint8_t opti_regs[6];
} azt2316a_t; } azt2316a_t;
static uint8_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 /* TODO: when windows is initializing, writing 0x48, 0x58 and 0x60 to
0x530 makes reading from 0x533 return 0x44, but writing 0x50 0x530 makes reading from 0x533 return 0x44, but writing 0x50
makes this return 0x04. Why? */ makes this return 0x04. Why? */
if ((addr & 1) || (azt2316a->opti)) if (addr & 1)
temp = 4 | (azt2316a->wss_config & 0x40); temp = 4 | (azt2316a->wss_config & 0x40);
else else
temp = 4 | (azt2316a->wss_config & 0xC0); 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; azt2316a_t *azt2316a = (azt2316a_t *) p;
int c; int c;
if (azt2316a->opti && azt2316a->opti_regs[3] & 0x4)
return;
/* wss part */ /* wss part */
ad1848_update(&azt2316a->ad1848); ad1848_update(&azt2316a->ad1848);
for (c = 0; c < len * 2; c++) 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); 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 * static void *
azt_init(const device_t *info) azt_init(const device_t *info)
{ {
@@ -1115,20 +891,15 @@ azt_init(const device_t *info)
azt2316a_t *azt2316a = malloc(sizeof(azt2316a_t)); azt2316a_t *azt2316a = malloc(sizeof(azt2316a_t));
memset(azt2316a, 0, sizeof(azt2316a_t)); memset(azt2316a, 0, sizeof(azt2316a_t));
azt2316a->type = info->local & 0x7fffffff; azt2316a->type = info->local;
azt2316a->opti = !!(info->local & 0x80000000);
if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) {
fn = "azt1605.nvr"; fn = "azt1605.nvr";
} else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { } 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). */ /* config */
if (!azt2316a->opti) {
f = nvr_fopen(fn, "rb"); f = nvr_fopen(fn, "rb");
if (f) { if (f) {
uint8_t checksum = 0x7f; uint8_t checksum = 0x7f;
@@ -1147,7 +918,6 @@ azt_init(const device_t *info)
if (checksum == saved_checksum) if (checksum == saved_checksum)
loaded_from_eeprom = 1; loaded_from_eeprom = 1;
} }
}
if (!loaded_from_eeprom) { if (!loaded_from_eeprom) {
if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) {
@@ -1188,28 +958,6 @@ azt_init(const device_t *info)
} }
if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { 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->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); azt2316a->config_word = read_eeprom[11] | (read_eeprom[12] << 8) | (read_eeprom[13] << 16) | (read_eeprom[14] << 24);
switch (azt2316a->config_word & (3 << 0)) { switch (azt2316a->config_word & (3 << 0)) {
@@ -1234,9 +982,6 @@ azt_init(const device_t *info)
else else
fatal("AZT2316A: invalid sb irq in config word %08X\n", azt2316a->config_word); 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)) { switch (azt2316a->config_word & (3 << 6)) {
case 1 << 6: case 1 << 6:
azt2316a->cur_dma = 0; azt2316a->cur_dma = 0;
@@ -1298,7 +1043,6 @@ azt_init(const device_t *info)
azt2316a->cur_wss_irq = device_get_config_int("wss_irq"); azt2316a->cur_wss_irq = device_get_config_int("wss_irq");
azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); azt2316a->cur_wss_dma = device_get_config_int("wss_dma");
azt2316a->cur_mode = 0; azt2316a->cur_mode = 0;
}
} else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) {
azt2316a->config_word = read_eeprom[12] + (read_eeprom[13] << 8) + (read_eeprom[14] << 16); 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; azt2316a->cur_wss_enabled = 0;
// these are not present on the EEPROM // 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_irq = device_get_config_int("wss_irq");
azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); azt2316a->cur_wss_dma = device_get_config_int("wss_dma");
azt2316a->cur_mode = 0; azt2316a->cur_mode = 0;
} }
addr_setting = (azt2316a->opti) ? 0 : device_get_config_hex16("addr"); addr_setting = device_get_config_hex16("addr");
if (addr_setting) if (addr_setting)
azt2316a->cur_addr = 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 */ /* 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_setirq(&azt2316a->ad1848, azt2316a->cur_wss_irq);
ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); 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); 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_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_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); 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)); azt2316a->sb = malloc(sizeof(sb_t));
memset(azt2316a->sb, 0, 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++) for (i = 0; i < AZTECH_EEPROM_SIZE; i++)
azt2316a->sb->dsp.azt_eeprom[i] = read_eeprom[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_init(&azt2316a->sb->dsp, SBPRO2, azt2316a->type, azt2316a);
sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr);
sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq);
sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma);
sb_ct1345_mixer_reset(azt2316a->sb); 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 */ /* DSP I/O handler is activated in sb_dsp_setaddr */
if (azt2316a->sb->opl_enabled) { 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); io_sethandler(azt2316a->cur_addr + 0, 0x0004, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv);
@@ -1458,7 +1191,6 @@ azt_close(void *p)
uint8_t checksum = 0x7f; uint8_t checksum = 0x7f;
int i; int i;
if (!azt2316a->opti) {
if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) {
fn = "azt1605.nvr"; fn = "azt1605.nvr";
} else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) {
@@ -1479,10 +1211,10 @@ azt_close(void *p)
fclose(f); fclose(f);
} }
}
sb_close(azt2316a->sb); sb_close(azt2316a->sb);
free(azt2316a->mpu);
free(azt2316a); free(azt2316a);
} }
@@ -1757,33 +1489,7 @@ static const device_config_t azt2316a_config[] = {
.default_int = 0 .default_int = 0
}, },
{ .name = "", .description = "", .type = CONFIG_END } { .name = "", .description = "", .type = CONFIG_END }
// clang-format on // 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
}; };
const device_t azt2316a_device = { const device_t azt2316a_device = {
@@ -1800,20 +1506,6 @@ const device_t azt2316a_device = {
.config = azt2316a_config .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 = { const device_t azt1605_device = {
.name = "Aztech Sound Galaxy Nova 16 Extra (Clinton)", .name = "Aztech Sound Galaxy Nova 16 Extra (Clinton)",
.internal_name = "azt1605", .internal_name = "azt1605",

457
src/sound/snd_optimc.c Normal file
View File

@@ -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 <eluancm@gmail.com>
*
* Copyright 2022 Cacodemon345.
* Copyright 2020 Eluan Costa Miranda.
*/
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#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
};