Split AcerMagic S20 code into its own file
It isn't really a Aztech clone, more like a sound card incorporating the OPTi MAD16 Pro sound chip * Fix mixer address changes * Make the OPL chip type constant
This commit is contained in:
@@ -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)
|
||||
|
@@ -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",
|
||||
|
457
src/sound/snd_optimc.c
Normal file
457
src/sound/snd_optimc.c
Normal 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
|
||||
};
|
Reference in New Issue
Block a user