From 6f4ac0de350d9d5ece2879adab9e0857a23e9208 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 25 Mar 2020 00:49:25 +0100 Subject: [PATCH] Added the Aztech Sound Galaxy 16 cards. Added the reset function of MCA from PCem. Made the MCA devices use the reset parameter if available. --- src/machine/m_ps2_mca.c | 4 +- src/mca.c | 87 ++- src/mca.h | 3 +- src/network/net_ne2000.c | 2 +- src/network/net_wd8003.c | 2 +- src/scsi/scsi_aha154x.c | 2 +- src/scsi/scsi_buslogic.c | 2 +- src/scsi/scsi_spock.c | 3 +- src/sound/snd_ad1848.c | 71 +- src/sound/snd_ad1848.h | 10 +- src/sound/snd_azt2316a.c | 1399 ++++++++++++++++++++++++++++++++++++ src/sound/snd_azt2316a.h | 1 + src/sound/snd_mpu401.c | 7 +- src/sound/snd_mpu401.h | 1 + src/sound/snd_pas16.c | 2 +- src/sound/snd_sb.c | 359 ++++----- src/sound/snd_sb.h | 143 ++++ src/sound/snd_sb_dsp.c | 107 ++- src/sound/snd_sb_dsp.h | 139 ++-- src/sound/snd_wss.c | 132 ++-- src/sound/sound.c | 3 + src/sound/sound.h | 4 + src/video/vid_cl54xx.c | 2 +- src/video/vid_et4000.c | 2 +- src/win/Makefile.mingw | 1 + src/win/Makefile_ndr.mingw | 1 + 26 files changed, 2049 insertions(+), 440 deletions(-) create mode 100644 src/sound/snd_azt2316a.c create mode 100644 src/sound/snd_azt2316a.h create mode 100644 src/sound/snd_sb.h diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index c4b755a6d..9560b50cd 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -718,6 +718,8 @@ static void ps2_mca_write(uint16_t port, uint8_t val, void *p) ps2.setup = val; break; case 0x96: + if ((val & 0x80) && !(ps2.adapter_setup & 0x80)) + mca_reset(); ps2.adapter_setup = val; mca_set_index(val & 7); break; @@ -856,7 +858,7 @@ static void ps2_mca_mem_fffc_init(int start_mb) break; } - mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, ps2_mem_expansion_feedb, NULL); + mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, ps2_mem_expansion_feedb, NULL, NULL); mem_mapping_add(&ps2.expansion_mapping, expansion_start, (mem_size - (start_mb << 10)) << 10, diff --git a/src/mca.c b/src/mca.c index b9ab31487..d2bd9270f 100644 --- a/src/mca.c +++ b/src/mca.c @@ -9,6 +9,7 @@ void (*mca_card_write[8])(int addr, uint8_t val, void *priv); uint8_t (*mca_card_read[8])(int addr, void *priv); uint8_t (*mca_card_feedb[8])(void *priv); +void (*mca_card_reset[8])(void *priv); void *mca_priv[8]; static int mca_index; @@ -17,62 +18,72 @@ static int mca_nr_cards; void mca_init(int nr_cards) { - int c; + int c; + + for (c = 0; c < 8; c++) { + mca_card_read[c] = NULL; + mca_card_write[c] = NULL; + mca_card_reset[c] = NULL; + mca_priv[c] = NULL; + } - for (c = 0; c < 8; c++) - { - mca_card_read[c] = NULL; - mca_card_write[c] = NULL; - mca_priv[c] = NULL; - } - - mca_index = 0; - mca_nr_cards = nr_cards; + mca_index = 0; + mca_nr_cards = nr_cards; } void mca_set_index(int index) { - mca_index = index; + mca_index = index; } uint8_t mca_read(uint16_t port) { - if (mca_index >= mca_nr_cards) - return 0xff; - if (!mca_card_read[mca_index]) - return 0xff; - return mca_card_read[mca_index](port, mca_priv[mca_index]); + if (mca_index >= mca_nr_cards) + return 0xff; + if (!mca_card_read[mca_index]) + return 0xff; + return mca_card_read[mca_index](port, mca_priv[mca_index]); } void mca_write(uint16_t port, uint8_t val) { - if (mca_index >= mca_nr_cards) - return; - if (mca_card_write[mca_index]) - mca_card_write[mca_index](port, val, mca_priv[mca_index]); + if (mca_index >= mca_nr_cards) + return; + if (mca_card_write[mca_index]) + mca_card_write[mca_index](port, val, mca_priv[mca_index]); } uint8_t mca_feedb(void) { - if (mca_card_feedb[mca_index]) - return !!(mca_card_feedb[mca_index](mca_priv[mca_index])); - else - return 0; + if (mca_card_feedb[mca_index]) + return !!(mca_card_feedb[mca_index](mca_priv[mca_index])); + else + return 0; } -void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void *priv) +void mca_reset(void) { - int c; - - for (c = 0; c < mca_nr_cards; c++) - { - if (!mca_card_read[c] && !mca_card_write[c]) - { - mca_card_read[c] = read; - mca_card_write[c] = write; - mca_card_feedb[c] = feedb; - mca_priv[c] = priv; - return; - } - } + int c; + + for (c = 0; c < 8; c++) { + if (mca_card_reset[c]) + mca_card_reset[c](mca_priv[c]); + } +} + + +void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void (*reset)(void *priv), void *priv) +{ + int c; + + for (c = 0; c < mca_nr_cards; c++) { + if (!mca_card_read[c] && !mca_card_write[c]) { + mca_card_read[c] = read; + mca_card_write[c] = write; + mca_card_feedb[c] = feedb; + mca_card_reset[c] = reset; + mca_priv[c] = priv; + return; + } + } } diff --git a/src/mca.h b/src/mca.h index d38156352..e0def3fe5 100644 --- a/src/mca.h +++ b/src/mca.h @@ -1,8 +1,9 @@ extern void mca_init(int nr_cards); -extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void *priv); +extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void (*reset)(void *priv), void *priv); extern void mca_set_index(int index); extern uint8_t mca_read(uint16_t port); extern void mca_write(uint16_t port, uint8_t val); extern uint8_t mca_feedb(void); +extern void mca_reset(void); extern void ps2_cache_clean(void); \ No newline at end of file diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 8feb13c5c..b4de899a1 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -1238,7 +1238,7 @@ nic_init(const device_t *info) } } else { - mca_add(nic_mca_read, nic_mca_write, nic_mca_feedb, dev); + mca_add(nic_mca_read, nic_mca_write, nic_mca_feedb, NULL, dev); } } diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index e11fb1e57..a8ecedeba 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -675,7 +675,7 @@ wd_init(const device_t *info) } if ((dev->board == WD8003ETA) || (dev->board == WD8003EA)) - mca_add(wd_mca_read, wd_mca_write, wd_mca_feedb, dev); + mca_add(wd_mca_read, wd_mca_write, wd_mca_feedb, NULL, dev); else { dev->base_address = device_get_config_hex16("base"); dev->irq = device_get_config_int("irq"); diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index b3ec5f4a9..5ff977f50 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -861,7 +861,7 @@ aha_init(const device_t *info) /* Enable MCA. */ dev->pos_regs[0] = 0x1F; /* MCA board ID */ dev->pos_regs[1] = 0x0F; - mca_add(aha_mca_read, aha_mca_write, aha_mca_feedb, dev); + mca_add(aha_mca_read, aha_mca_write, aha_mca_feedb, NULL, dev); dev->ha_bps = 5000000.0; /* normal SCSI */ break; } diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index 48d19c9f5..b03c453ed 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -1626,7 +1626,7 @@ buslogic_init(const device_t *info) dev->flags |= X54X_32BIT; dev->pos_regs[0] = 0x08; /* MCA board ID */ dev->pos_regs[1] = 0x07; - mca_add(buslogic_mca_read, buslogic_mca_write, buslogic_mca_feedb, dev); + mca_add(buslogic_mca_read, buslogic_mca_write, buslogic_mca_feedb, NULL, dev); dev->ha_bps = 5000000.0; /* normal SCSI */ dev->max_id = 7; /* narrow SCSI */ break; diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index 1a26b6b49..cbad41176 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -1091,8 +1091,7 @@ spock_init(const device_t *info) scsi->pos_regs[0] = 0xff; scsi->pos_regs[1] = 0x8e; - // mca_add(spock_mca_read, spock_mca_write, spock_mca_feedb, spock_mca_reset, scsi); - mca_add(spock_mca_read, spock_mca_write, spock_mca_feedb, scsi); + mca_add(spock_mca_read, spock_mca_write, spock_mca_feedb, spock_mca_reset, scsi); scsi->in_reset = 2; scsi->cmd_timer = SPOCK_TIME * 50; diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index f8681ff86..2817ed36d 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -15,7 +15,8 @@ #include "snd_ad1848.h" -static int ad1848_vols[64]; +static int ad1848_vols_6bits[64]; +static uint32_t ad1848_vols_5bits_aux_gain[32]; void ad1848_setirq(ad1848_t *ad1848, int irq) @@ -51,10 +52,14 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) { ad1848_t *ad1848 = (ad1848_t *)p; double freq; + uint32_t new_cd_vol_l, new_cd_vol_r; switch (addr & 3) { case 0: /*Index*/ - ad1848->index = val & 0xf; + if ((ad1848->regs[12] & 0x40) && (ad1848->type == AD1848_TYPE_CS4231)) + ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ + else + ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ ad1848->trd = val & 0x20; ad1848->mce = val & 0x40; break; @@ -93,6 +98,8 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) break; case 12: + if (ad1848->type != AD1848_TYPE_DEFAULT) + ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; return; case 14: @@ -100,6 +107,22 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) break; } ad1848->regs[ad1848->index] = val; + + if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ + if (ad1848->regs[0x12] & 0x80) + new_cd_vol_l = 0; + else + new_cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; + if (ad1848->regs[0x13] & 0x80) + new_cd_vol_r = 0; + else + new_cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; + + /* Apparently there is no master volume to modulate here + (The windows mixer just adjusts all registers at the same + time when the master slider is adjusted) */ + sound_set_cd_volume(new_cd_vol_l, new_cd_vol_r); + } break; case 2: ad1848->status &= 0xfe; @@ -161,12 +184,12 @@ static void ad1848_poll(void *p) if (ad1848->regs[6] & 0x80) ad1848->out_l = 0; else - ad1848->out_l = (ad1848->out_l * ad1848_vols[ad1848->regs[6] & 0x3f]) >> 16; + ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16; if (ad1848->regs[7] & 0x80) ad1848->out_r = 0; else - ad1848->out_r = (ad1848->out_r * ad1848_vols[ad1848->regs[7] & 0x3f]) >> 16; + ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; if (ad1848->count < 0) { @@ -184,10 +207,11 @@ static void ad1848_poll(void *p) else { ad1848->out_l = ad1848->out_r = 0; + sound_set_cd_volume(0, 0); } } -void ad1848_init(ad1848_t *ad1848) +void ad1848_init(ad1848_t *ad1848, int type) { int c; double attenuation; @@ -197,21 +221,29 @@ void ad1848_init(ad1848_t *ad1848) ad1848->mce = 0x40; ad1848->regs[0] = ad1848->regs[1] = 0; - ad1848->regs[2] = ad1848->regs[3] = 0x80; + ad1848->regs[2] = ad1848->regs[3] = 0x80; /* AZT2316A Line-in */ ad1848->regs[4] = ad1848->regs[5] = 0x80; - ad1848->regs[6] = ad1848->regs[7] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; /* AZT2316A Master? */ ad1848->regs[8] = 0; ad1848->regs[9] = 0x08; ad1848->regs[10] = ad1848->regs[11] = 0; - ad1848->regs[12] = 0xa; + if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231)) + ad1848->regs[12] = 0x8a; + else + ad1848->regs[12] = 0xa; ad1848->regs[13] = 0; ad1848->regs[14] = ad1848->regs[15] = 0; + if (type == AD1848_TYPE_CS4231) + { + ad1848->regs[0x12] = ad1848->regs[0x13] = 0x80; // AZT2316A CD + ad1848->regs[0x1A] = 0x80; // AZT2316A Mic + } + ad1848->out_l = 0; ad1848->out_r = 0; - for (c = 0; c < 64; c++) - { + for (c = 0; c < 64; c++) { attenuation = 0.0; if (c & 0x01) attenuation -= 1.5; if (c & 0x02) attenuation -= 3.0; @@ -222,8 +254,23 @@ void ad1848_init(ad1848_t *ad1848) attenuation = pow(10, attenuation / 10); - ad1848_vols[c] = (int)(attenuation * 65536); + ad1848_vols_6bits[c] = (int)(attenuation * 65536); } - timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); + for (c = 0; c < 32; c++) { + attenuation = 12.0; + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols_5bits_aux_gain[c] = (int)(attenuation * 65536); + } + + ad1848->type = type; + + timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); } diff --git a/src/sound/snd_ad1848.h b/src/sound/snd_ad1848.h index 0778cdfec..9c71f084b 100644 --- a/src/sound/snd_ad1848.h +++ b/src/sound/snd_ad1848.h @@ -1,7 +1,11 @@ +#define AD1848_TYPE_DEFAULT 0 +#define AD1848_TYPE_CS4248 1 +#define AD1848_TYPE_CS4231 2 + typedef struct ad1848_t { int index; - uint8_t regs[16]; + uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */ uint8_t status; int trd; @@ -22,6 +26,8 @@ typedef struct ad1848_t int16_t buffer[SOUNDBUFLEN * 2]; int pos; + + int type; } ad1848_t; void ad1848_setirq(ad1848_t *ad1848, int irq); @@ -33,4 +39,4 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p); void ad1848_update(ad1848_t *ad1848); void ad1848_speed_changed(ad1848_t *ad1848); -void ad1848_init(ad1848_t *ad1848); +void ad1848_init(ad1848_t *ad1848, int type); diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c new file mode 100644 index 000000000..3193f1af1 --- /dev/null +++ b/src/sound/snd_azt2316a.c @@ -0,0 +1,1399 @@ +/* + * TYPE 0x11: (Washington) + * Aztech MMPRO16AB, + * Aztech Sound Galaxy Pro 16 AB + * Aztech Sound Galaxy Washington 16 + * ...and other OEM names + * FCC ID I38-MMSN824 and others + * + * TYPE 0x0C: (Clinton) + * Packard Bell FORTE16 + * Aztech Sound Galaxy Nova 16 Extra + * Aztech Sound Galaxy Clinton 16 + * ...and other OEM names + * + * Also works more or less for drivers of other models with the same chipsets. + * + * Copyright (c) 2020 Eluan Costa Miranda All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * ============================================================================= + * + * The CS4248 DSP used is pin and software compatible with the AD1848. + * I also have one of these cards with a CS4231. The driver talks to the + * emulated card as if it was a CS4231 and I still don't know how to tell the + * drivers to see the CS4248. The CS4231 more advanced features are NOT used, + * just the new input/output channels. Apparently some drivers are hardcoded + * for one or the other, so there is an option for this. + * + * There is lots more to be learned form the Win95 drivers. The Linux driver is + * very straightforward and doesn't do much. + * + * Recording and voice modes in the windows mixer still do nothing in 86Box, so + * this is missing. + * + * There is a jumper to load the startup configuration from an EEPROM. This is + * implemented, so any software-configured parameters will be saved. + * + * The CD-ROM interface commands are just ignored, along with gameport. + * The MPU401 is always enabled. + * The OPL3 is always active in some (all?) drivers/cards, so there is no + * configuration for this. + * + * Tested with DOS (driver installation, tools, diagnostics), Win3.1 (driver + * installation, tools), Win95 (driver auto-detection), lots of games. + * + * I consider type 0x11 (Washington) to be very well tested. Type 0x0C (Clinton) + * wasn't fully tested, but works well for WSS/Windows. BEWARE that there are + * *too many* driver types and OEM versions for each card. Maybe yours isn't + * emulated or you have the wrong driver. Some features of each card may work + * when using wrong drivers. CODEC selection is also important. + * + * Any updates to the WSS and SBPROV2 sound cards should be synced here when + * appropriate. The WSS was completely cloned here, while the SBPROV2 tends + * to call the original functions, except for initialization. + * + * TODO/Notes: + * -Some stuff still not understood on I/O addresses 0x624 and 0x530-0x533. + * -Is the CS42xx dither mode used anywhere? Implement. + * -What are the voice commands mode in Win95 mixer again? + * -Configuration options not present on Aztech's CONFIG.EXE have been commented + * out or deleted. Other types of cards with this chipset may need them. + * -Sfademo on the Descent CD fails under Win95, works under DOS, see if it + * happens on real hardware (and OPL3 stops working after the failure) + * -There appears to be some differences in sound volumes bertween MIDI, + * SBPROV2, WSS and OPL3? Also check relationship between the SBPROV2 mixer and + * the WSS mixer! Are they independent? Current mode selects which mixer? Are + * they entangled? + * -Check real hardware to see if advanced, mic boost, etc appear in the mixer? + * -CD-ROM driver shipped with the card (SGIDECD.SYS) checks for model strings. + * I have implemented mine (Aztech CDA 468-02I 4x) in PCem. + * -Descent 2 W95 version can't start cd music. Happens on real hardware. + * Explanation further below. + * -DOSQuake and Descent 2 DOS cd music do not work under Win95. The mode + * selects get truncated and send all zeros for output channel selection and + * volume, Descent 2 also has excess zeros! This is a PCem bug, happens on all + * sound cards. CD audio works in Winquake and Descent 2 DOS setup program. + * -DOSQuake CD audio works under DOS with VIDE-CDD.SYS and SGIDECD.SYS. + * Descent 2 DOS is still mute but volume selection appears to be working. + * Descent 2 fails to launch with SGIDECD.SYS with "Device failed to request + * command". SGIDECD.SYS is the CD-ROM driver included with the sound card + * drivers. My real CD-ROM drive can't read anything so I can't check the + * real behavior of this driver. + * -Some cards just have regular IDE ports while other have proprietary ports. + * The regular IDE ports just have a option to enable an almost-generic CD-ROM + * driver in CONFIG.SYS/AUTOEXEC.BAT (like SGIDECD.SYS) and the onboard port + * is enabled/disabled by jumpers. The proprietary ones also have + * address/dma/irq settings. Since the configuration options are ignored here, + * this behaves like a card with a regular interface disabled by jumper and + * the configuration just adds/removes the drivers (which will see other IDE + * interfaces present) from the boot process. + * -Continue reverse engineering to see if the AZT1605 shares the SB DMA with + * WSS or if it is set separately by the TSR loaded on boot. Currently it is + * only set by PCem config and then saved to EEPROM (which would make it fixed + * if loading from EEPROM too). + * -Related to the previous note, part of the SBPROV2 emulation on the CLINTON + * family appears to be implemented with a TSR. It's better to remove the TSR + * for now. I need to investigate this. Mixer is also weird under DOS (and + * wants to save to EEPROM? I don't think the WASHINGTON does this). + * -Search for TODO in this file. :-) + * + * Misc things I use to test for regressions: Windows sounds, Descent under + * dos/windows, Descent 2 dos/windows (+ cd music option), Descent 2 W95 + cd + * music, Age of Empires (CD + Midi), cd-audio under Windows + volume, + * cd-audio under dos + volume, Aztech diagnose.exe, Aztech volset /M:3 then + * volset /D, Aztech setmode, mixer (volume + balance) under dos and windows, + * DOSQuake under dos and windows (+ cd music and volumes, + Winquake). + * + * Reason for Descent 2 Win95 CD-Audio not working: + * The game calls auxGetNumDevs() to check if any of the AUX devices has + * caps.wTechnology == AUXCAPS_CDAUDIO, but this fails because the Aztech + * Win95 driver only returns a "Line-In" device. I'm not aware of any other + * game that does this and this is completely unnecessary. Other games that + * play cd audio correctly have the exact *same* initialization code, minus + * this check that only Descent 2 Win95 does. It would work if it just skipped + * this check and progressed with calling mciSendCommand() with + * mciOpenParms.lpstrDeviceType = "cdaudio", like other games do. There are + * some sound cards listed as incompatible in the game's README.TXT file that + * are probably due to this. + */ + +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "86box_io.h" +#include "timer.h" +#include "pic.h" +#include "nvr.h" +#include "device.h" +#include "sound.h" +#include "midi.h" +#include "snd_ad1848.h" +#include "snd_azt2316a.h" +#include "snd_sb.h" + +/*530, 11, 3 - 530=23*/ +/*530, 11, 1 - 530=22*/ +/*530, 11, 0 - 530=21*/ +/*530, 10, 1 - 530=1a*/ +/*530, 10, 0 - 530=19*/ +/*530, 9, 1 - 530=12*/ +/*530, 7, 1 - 530=0a*/ +/*604, 11, 1 - 530=22*/ +/*e80, 11, 1 - 530=22*/ +/*f40, 11, 1 - 530=22*/ + + +static int azt2316a_wss_dma[4] = {0, 0, 1, 3}; +static int azt2316a_wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /* W95 only uses 7-10, others may be wrong */ +//static uint16_t azt2316a_wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; + +typedef struct azt2316a_t +{ + int type; + int wss_interrupt_after_config; + + 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; + + uint32_t config_word; + uint32_t config_word_unlocked; + + uint8_t cur_mode; + + ad1848_t ad1848; + mpu_t *mpu; + + sb_t *sb; +} azt2316a_t; + +static uint8_t +azt2316a_wss_read(uint16_t addr, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; + + /* 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) + temp = 4 | (azt2316a->wss_config & 0x40); + else + temp = 4 | (azt2316a->wss_config & 0xC0); + + return temp; +} + +static void +azt2316a_wss_write(uint16_t addr, uint8_t val, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + int interrupt = 0; + + if (azt2316a->wss_interrupt_after_config) + if ((azt2316a->wss_config & 0x40) && !(val & 0x40)) // TODO: is this the right edge? + interrupt = 1; + + azt2316a->wss_config = val; + azt2316a->cur_wss_dma = azt2316a_wss_dma[val & 3]; + azt2316a->cur_wss_irq = azt2316a_wss_irq[(val >> 3) & 7]; + ad1848_setdma(&azt2316a->ad1848, azt2316a_wss_dma[val & 3]); + ad1848_setirq(&azt2316a->ad1848, azt2316a_wss_irq[(val >> 3) & 7]); + + if (interrupt) + picint(1 << azt2316a->cur_wss_irq); +} + +/* generate a config word based on current settings */ +static void +azt1605_create_config_word(void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint32_t temp = 0; + + /* not implemented / hardcoded */ + uint8_t game_enable = 1; + uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ + uint8_t cd_dma8 = -1; + uint8_t cd_irq = 0; + + switch (azt2316a->cur_addr) { + case 0x220: + /* do nothing + temp += 0 << 0; */ + break; + case 0x240: + temp += 1 << 0; + break; +/* + case 0x260: // TODO: INVALID? + temp += 2 << 0; + break; + case 0x280: // TODO: INVALID? + temp += 3 << 0; + break; +*/ + } + + switch (azt2316a->cur_irq) { + case 2: + temp += 1 << 8; + break; + case 3: + temp += 1 << 9; + break; + case 5: + temp += 1 << 10; + break; + case 7: + temp += 1 << 11; + break; + } + + switch (azt2316a->cur_wss_addr) { + case 0x530: + /* do nothing + temp += 0 << 16; */ + break; + case 0x604: + temp += 1 << 16; + break; + case 0xE80: + temp += 2 << 16; + break; + case 0xF40: + temp += 3 << 16; + break; + } + + if (azt2316a->cur_wss_enabled) + temp += 1 << 18; + + if (game_enable) + temp += 1 << 4; + + switch (azt2316a->cur_mpu401_addr) { + case 0x300: + /* do nothing + temp += 0 << 2; */ + break; + case 0x330: + temp += 1 << 2; + break; + } + + if (azt2316a->cur_mpu401_enabled) + temp += 1 << 3; + + switch (cd_type) { + case 0: /* disabled + do nothing + temp += 0 << 5; */ + break; + case 1: // panasonic + temp += 1 << 5; + break; + case 2: // mitsumi/sony/aztech + temp += 2 << 5; + break; + case 3: // all enabled + temp += 3 << 5; + break; + case 4: // unused + temp += 4 << 5; + break; + case 5: // unused + temp += 5 << 5; + break; + case 6: // unused + temp += 6 << 5; + break; + case 7: // unused + temp += 7 << 5; + break; + } + + switch (cd_dma8) { + case 0xFF: /* -1 + do nothing + temp += 0 << 22;*/ + break; + case 0: + temp += 1 << 22; + break; + case 1: + temp += 2 << 22; + break; + case 3: + temp += 3 << 22; + break; + } + + switch (azt2316a->cur_mpu401_irq) { + case 2: + temp += 1 << 12; + break; + case 3: + temp += 1 << 13; + break; + case 5: + temp += 1 << 14; + break; + case 7: + temp += 1 << 15; + break; + } + + switch (cd_irq) { + case 0: // disabled + // do nothing + break; + case 11: + temp += 1 << 19; + break; + case 12: + temp += 1 << 20; + break; + case 15: + temp += 1 << 21; + break; + } + + azt2316a->config_word = temp; +} + +static void +azt2316a_create_config_word(void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint32_t temp = 0; + + /* not implemented / hardcoded */ + uint8_t game_enable = 1; + uint16_t cd_addr = 0x310; + uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ + uint8_t cd_dma8 = -1; + uint8_t cd_dma16 = -1; + uint8_t cd_irq = 15; + + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + azt1605_create_config_word(p); + return; + } + + switch (azt2316a->cur_addr) { + case 0x220: + /* do nothing + temp += 0 << 0; */ + break; + case 0x240: + temp += 1 << 0; + break; +/* + case 0x260: // TODO: INVALID? + temp += 2 << 0; + break; + case 0x280: // TODO: INVALID? + temp += 3 << 0; + break; +*/ + } + + switch (azt2316a->cur_irq) { + case 2: + temp += 1 << 2; + break; + case 5: + temp += 1 << 3; + break; + case 7: + temp += 1 << 4; + break; + case 10: + temp += 1 << 5; + break; + } + + switch (azt2316a->cur_dma) { +/* + // TODO: INVALID? + case 0xFF: // -1 + // do nothing + //temp += 0 << 6; + break; +*/ + case 0: + temp += 1 << 6; + break; + case 1: + temp += 2 << 6; + break; + case 3: + temp += 3 << 6; + break; + } + + switch (azt2316a->cur_wss_addr) + { + case 0x530: + // do nothing + //temp += 0 << 8; + break; + case 0x604: + temp += 1 << 8; + break; + case 0xE80: + temp += 2 << 8; + break; + case 0xF40: + temp += 3 << 8; + break; + } + if (azt2316a->cur_wss_enabled) + temp += 1 << 10; + if (game_enable) + temp += 1 << 11; + switch (azt2316a->cur_mpu401_addr) + { + case 0x300: + // do nothing + //temp += 0 << 12; + break; + case 0x330: + temp += 1 << 12; + break; + } + + if (azt2316a->cur_mpu401_enabled) + temp += 1 << 13; + + switch (cd_addr) { + case 0x310: + // do nothing + //temp += 0 << 14; + break; + case 0x320: + temp += 1 << 14; + break; + case 0x340: + temp += 2 << 14; + break; + case 0x350: + temp += 3 << 14; + break; + } + switch (cd_type) { + case 0: /* disabled + do nothing + temp += 0 << 16; */ + break; + case 1: /* panasonic */ + temp += 1 << 16; + break; + case 2: /* sony */ + temp += 2 << 16; + break; + case 3: /* mitsumi */ + temp += 3 << 16; + break; + case 4: /* aztech */ + temp += 4 << 16; + break; + case 5: /* unused */ + temp += 5 << 16; + break; + case 6: /* unused */ + temp += 6 << 16; + break; + case 7: /* unused */ + temp += 7 << 16; + break; + } + + switch (cd_dma8) { + case 0xFF: /* -1 + do nothing + temp += 0 << 20; */ + break; + case 0: + temp += 1 << 20; + break; +/* + case 1: // TODO: INVALID? + temp += 2 << 20; + break; +*/ + case 3: + temp += 3 << 20; + break; + } + + switch (cd_dma16) { + case 0xFF: /* -1 + do nothing + temp += 0 << 22; */ + break; + case 5: + temp += 1 << 22; + break; + case 6: + temp += 2 << 22; + break; + case 7: + temp += 3 << 22; + break; + } + + switch (azt2316a->cur_mpu401_irq) { + case 2: + temp += 1 << 24; + break; + case 5: + temp += 1 << 25; + break; + case 7: + temp += 1 << 26; + break; + case 10: + temp += 1 << 27; + break; + } + + switch (cd_irq) { + case 5: + temp += 1 << 28; + break; + case 11: + temp += 1 << 29; + break; + case 12: + temp += 1 << 30; + break; + case 15: + temp += 1 << 31; + break; + } + + azt2316a->config_word = temp; +} + +static uint8_t +azt2316a_config_read(uint16_t addr, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp = 0; + + /* Some WSS config here + config change enable bit + (setting bit 7 and writing back) */ + + if (addr == (azt2316a->cur_addr + 0x404)) { + /* TODO: what is the real meaning of the read value? + I got a mention of bit 0x10 for WSS from disassembling the source + code of the driver, and when playing with the I/O ports on real + hardware after doing some configuration, but didn't dig into it. + Bit 0x08 seems to be a busy flag and generates a timeout + (continuous re-reading when initializing windows 98) */ + temp = azt2316a->cur_mode ? 0x07 : 0x0F; + if (azt2316a->config_word_unlocked) { + temp |= 0x80; + } + } else { + // Rest of config. These are documented in the Linux driver. + switch (addr & 0x3) + { + case 0: + temp = azt2316a->config_word & 0xFF; + break; + case 1: + temp = (azt2316a->config_word >> 8); + break; + case 2: + temp = (azt2316a->config_word >> 16); + break; + case 3: + temp = (azt2316a->config_word >> 24); + break; + } + } + + return temp; +} + + +static void +azt1605_config_write(uint16_t addr, uint8_t val, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; + + if (addr == (azt2316a->cur_addr + 0x404)) { + if (val & 0x80) + azt2316a->config_word_unlocked = 1; + else + azt2316a->config_word_unlocked = 0; + } else if (azt2316a->config_word_unlocked) { + if (val == 0xFF) { /* TODO: check if this still happens on eeprom.sys after having more complete emulation! */ + return; + } + switch (addr & 3) { + case 0: + azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) | val; + + temp = val & 3; + if (temp == 0) + azt2316a->cur_addr = 0x220; + else if (temp == 1) + azt2316a->cur_addr = 0x240; +/* + else if (temp == 2) + azt2316a->cur_addr = 0x260; // TODO: INVALID + else if (temp == 3) + azt2316a->cur_addr = 0x280; // TODO: INVALID +*/ + if (val & 0x4) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (val & 0x8) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + break; + case 1: + azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) | (val << 8); + + if (val & 0x1) + azt2316a->cur_irq = 2; + else if (val & 0x2) + azt2316a->cur_irq = 3; + else if (val & 0x4) + azt2316a->cur_irq = 5; + else if (val & 0x8) + azt2316a->cur_irq = 7; + /* else undefined? */ + + if (val & 0x10) + azt2316a->cur_mpu401_irq = 2; + else if (val & 0x20) + azt2316a->cur_mpu401_irq = 3; + else if (val & 0x40) + azt2316a->cur_mpu401_irq = 5; + else if (val & 0x80) + azt2316a->cur_mpu401_irq = 7; + /* else undefined? */ + break; + case 2: + azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) | (val << 16); + + 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); + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_wss_addr = 0x530; + else if (temp == 1) + azt2316a->cur_wss_addr = 0x604; + else if (temp == 2) + azt2316a->cur_wss_addr = 0xE80; + else if (temp == 3) + azt2316a->cur_wss_addr = 0xF40; + + 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); + + /* no actual effect */ + if (val & 0x4) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + break; + case 3: + break; + } + /* update sbprov2 configs */ + 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); + + mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); + mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + } +} + +static void +azt2316a_config_write(uint16_t addr, uint8_t val, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; + + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + azt1605_config_write(addr, val, azt2316a); + return; + } + + if (addr == (azt2316a->cur_addr + 0x404)) { + if (val & 0x80) + azt2316a->config_word_unlocked = 1; + else + azt2316a->config_word_unlocked = 0; + } else if (azt2316a->config_word_unlocked) { + if (val == 0xFF) // TODO: check if this still happens on eeprom.sys after having more complete emulation! + return; + switch (addr & 3) { + case 0: + azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) | val; + temp = val & 3; + + if (temp == 0) + azt2316a->cur_addr = 0x220; + else if (temp == 1) + azt2316a->cur_addr = 0x240; + + if (val & 0x4) + azt2316a->cur_irq = 2; + else if (val & 0x8) + azt2316a->cur_irq = 5; + else if (val & 0x10) + azt2316a->cur_irq = 7; + else if (val & 0x20) + azt2316a->cur_irq = 10; + + temp = (val >> 6) & 3; + if (temp == 1) + azt2316a->cur_dma = 0; + else if (temp == 2) + azt2316a->cur_dma = 1; + else if (temp == 3) + azt2316a->cur_dma = 3; + break; + case 1: + azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) | (val << 8); + + 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); + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_wss_addr = 0x530; + else if (temp == 1) + azt2316a->cur_wss_addr = 0x604; + else if (temp == 2) + azt2316a->cur_wss_addr = 0xE80; + else if (temp == 3) + azt2316a->cur_wss_addr = 0xF40; + + 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); + + /* no actual effect */ + if (val & 0x4) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + if (val & 0x10) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (val & 0x20) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + break; + case 2: + azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) | (val << 16); + break; + case 3: + azt2316a->config_word = (azt2316a->config_word & 0x00FFFFFF) | (val << 24); + + if (val & 0x1) + azt2316a->cur_mpu401_irq = 2; + else if (val & 0x2) + azt2316a->cur_mpu401_irq = 5; + else if (val & 0x4) + azt2316a->cur_mpu401_irq = 7; + else if (val & 0x8) + azt2316a->cur_mpu401_irq = 10; + /* else undefined? */ + break; + } + /* update sbprov2 configs */ + 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); + + mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); + mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + } +} + +/* How it behaves when one or another is activated may affect games auto-detecting (and will also use more of the limited system resources!) */ +void +azt2316a_enable_wss(uint8_t enable, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + + if (enable) + azt2316a->cur_mode = 1; + else + azt2316a->cur_mode = 0; +} + +static void +azt2316a_get_buffer(int32_t *buffer, int len, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + int c; + + /* wss part */ + ad1848_update(&azt2316a->ad1848); + for (c = 0; c < len * 2; c++) + buffer[c] += (azt2316a->ad1848.buffer[c] / 2); + + azt2316a->ad1848.pos = 0; + + /* sbprov2 part */ + sb_get_buffer_sbpro(buffer, len, azt2316a->sb); +} + +static void * +azt_init(const device_t *info) +{ + FILE *f; + wchar_t *fn = NULL; + int i; + int loaded_from_eeprom = 0; + uint16_t addr_setting; + uint8_t read_eeprom[AZTECH_EEPROM_SIZE]; + azt2316a_t *azt2316a = malloc(sizeof(azt2316a_t)); + memset(azt2316a, 0, sizeof(azt2316a_t)); + + azt2316a->type = info->local; + + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + fn = L"azt1605.nvr"; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + fn = L"azt2316a.nvr"; + } + + /* config */ + f = nvr_fopen(fn, L"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(&saved_checksum, sizeof(saved_checksum), 1, f); + (void)res; + + fclose(f); + + if (checksum == saved_checksum) + loaded_from_eeprom = 1; + } + + if (!loaded_from_eeprom) { + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + read_eeprom[0] = 0x00; + read_eeprom[1] = 0x00; + read_eeprom[2] = 0x00; + read_eeprom[3] = 0x00; + read_eeprom[4] = 0x00; + read_eeprom[5] = 0x00; + read_eeprom[6] = 0x00; + read_eeprom[7] = 0x00; + read_eeprom[8] = 0x00; + read_eeprom[9] = 0x00; + read_eeprom[10] = 0x00; + read_eeprom[11] = 0x88; + read_eeprom[12] = 0xbc; + read_eeprom[13] = 0x00; + read_eeprom[14] = 0x01; + read_eeprom[15] = 0x00; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + read_eeprom[0] = 0x80; + read_eeprom[1] = 0x80; + read_eeprom[2] = 0x9F; + read_eeprom[3] = 0x13; + read_eeprom[4] = 0x16; + read_eeprom[5] = 0x13; + read_eeprom[6] = 0x00; + read_eeprom[7] = 0x00; + read_eeprom[8] = 0x16; + read_eeprom[9] = 0x0B; + read_eeprom[10] = 0x06; + read_eeprom[11] = 0x01; + read_eeprom[12] = 0x1C; + read_eeprom[13] = 0x14; + read_eeprom[14] = 0x04; + read_eeprom[15] = 0x1C; + } + } + + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + 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 = 2; + 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 = 2; + 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 */ + if (azt2316a->cur_irq == 10) + azt2316a->cur_wss_irq = 10; + else if (azt2316a->cur_irq == 7) + azt2316a->cur_wss_irq = 7; + else + azt2316a->cur_wss_irq = 10; + + azt2316a->cur_wss_dma = azt2316a->cur_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); + + switch (azt2316a->config_word & (3 << 0)) { + case 0: + azt2316a->cur_addr = 0x220; + break; + case 1: + azt2316a->cur_addr = 0x240; + break; + default: + fatal("AZT1605: invalid sb addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 2)) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (azt2316a->config_word & (1 << 3)) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + + if (azt2316a->config_word & (1 << 8)) + azt2316a->cur_irq = 2; + else if (azt2316a->config_word & (1 << 9)) + azt2316a->cur_irq = 3; + else if (azt2316a->config_word & (1 << 10)) + azt2316a->cur_irq = 5; + else if (azt2316a->config_word & (1 << 11)) + azt2316a->cur_irq = 7; + else + fatal("AZT1605: invalid sb irq in config word %08X\n", azt2316a->config_word); + + if (azt2316a->config_word & (1 << 12)) + azt2316a->cur_mpu401_irq = 2; + else if (azt2316a->config_word & (1 << 13)) + azt2316a->cur_mpu401_irq = 3; + else if (azt2316a->config_word & (1 << 14)) + azt2316a->cur_mpu401_irq = 5; + else if (azt2316a->config_word & (1 << 15)) + azt2316a->cur_mpu401_irq = 7; + else + fatal("AZT1605: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); + + switch (azt2316a->config_word & (3 << 16)) { + case 0: + azt2316a->cur_wss_addr = 0x530; + break; + case 1 << 16: + azt2316a->cur_wss_addr = 0x604; + break; + case 2 << 16: + azt2316a->cur_wss_addr = 0xE80; + break; + case 3 << 16: + azt2316a->cur_wss_addr = 0xF40; + break; + default: + fatal("AZT1605: invalid wss addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 18)) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + // these are not present on the EEPROM + azt2316a->cur_dma = device_get_config_int("sb_dma8"); // TODO: investigate TSR to make this work with it - there is no software configurable DMA8? + + if (azt2316a->cur_irq == 7) + azt2316a->cur_wss_irq = 7; + else + azt2316a->cur_wss_irq = 10; + + azt2316a->cur_wss_dma = azt2316a->cur_dma; + azt2316a->cur_mode = 0; + } + + addr_setting = device_get_config_hex16("addr"); + if (addr_setting) + azt2316a->cur_addr = addr_setting; + + azt2316a->wss_interrupt_after_config = device_get_config_int("wss_interrupt_after_config"); + + /* wss part */ + 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); + + 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); + + /* sbprov2 part */ + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices).*/ + azt2316a->sb = malloc(sizeof(sb_t)); + memset(azt2316a->sb, 0, sizeof(sb_t)); + + 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) + opl3_init(&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); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + if (azt2316a->sb->opl_enabled) { + io_sethandler(azt2316a->cur_addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + io_sethandler(azt2316a->cur_addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + } + + io_sethandler(azt2316a->cur_addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, azt2316a->sb); + + azt2316a_create_config_word(azt2316a); + sound_add_handler(azt2316a_get_buffer, azt2316a); + + if (azt2316a->cur_mpu401_enabled) { + azt2316a->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(azt2316a->mpu, 0, sizeof(mpu_t)); + mpu401_init(azt2316a->mpu, azt2316a->cur_mpu401_addr, azt2316a->cur_mpu401_irq, M_UART, device_get_config_int("receive_input401")); + } else + azt2316a->mpu = NULL; + sb_dsp_set_mpu(azt2316a->mpu); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &azt2316a->sb->dsp); + + return azt2316a; +} + +static void +azt_close(void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + wchar_t *fn = NULL; + FILE *f; + uint8_t checksum = 0x7f; + int i; + + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + fn = L"azt1605.nvr"; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + fn = L"azt2316a.nvr"; + } + + /* always save to eeprom (recover from bad values) */ + f = nvr_fopen(fn, L"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); + + fclose(f); + } + + sb_close(azt2316a->sb); + + free(azt2316a); +} + +static void +azt_speed_changed(void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + + ad1848_speed_changed(&azt2316a->ad1848); + sb_speed_changed(azt2316a->sb); +} + +static const device_config_t azt1605_config[] = +{ + { + .name = "codec", + .description = "CODEC", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "CS4248", + .value = AD1848_TYPE_CS4248 + }, + { + .description = "CS4231", + .value = AD1848_TYPE_CS4231 + }, + }, + .default_int = AD1848_TYPE_CS4248 + }, + { + .name = "wss_interrupt_after_config", + .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + "addr", "SB Address", CONFIG_HEX16, "", 0, + { + { + "0x220", 0x220 + }, + { + "0x240", 0x240 + }, + { + "Use EEPROM setting", 0 + }, + { + "" + } + } + }, + { + .name = "sb_dma8", + .description = "SB low DMA", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DMA 0", + .value = 0 + }, + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { + .description = "" + } + }, + .default_int = 1 + }, + { + "opl", "Enable OPL", CONFIG_BINARY, "", 1 + }, + { + "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 + }, + { + "receive_input401", "Receive input (MPU-401)", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + +static const device_config_t azt2316a_config[] = +{ + { + .name = "codec", + .description = "CODEC", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "CS4248", + .value = AD1848_TYPE_CS4248 + }, + { + .description = "CS4231", + .value = AD1848_TYPE_CS4231 + }, + }, + .default_int = AD1848_TYPE_CS4248 + }, + { + .name = "wss_interrupt_after_config", + .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + "addr", "SB Address", CONFIG_HEX16, "", 0, + { + { + "0x220", 0x220 + }, + { + "0x240", 0x240 + }, + { + "Use EEPROM setting", 0 + }, + { + "" + } + } + }, + { + "opl", "Enable OPL", CONFIG_BINARY, "", 1 + }, + { + "receive_input", "Receive input (SB MIDI)", CONFIG_BINARY, "", 1 + }, + { + "receive_input401", "Receive input (MPU-401)", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + +const device_t azt2316a_device = +{ + "Aztech Sound Galaxy Pro 16 AB (Washington)", + DEVICE_ISA | DEVICE_AT, + SB_SUBTYPE_CLONE_AZT2316A_0X11, + azt_init, azt_close, NULL, NULL, + azt_speed_changed, + NULL, + azt2316a_config +}; + +const device_t azt1605_device = +{ + "Aztech Sound Galaxy Nova 16 Extra (Clinton)", + DEVICE_ISA | DEVICE_AT, + SB_SUBTYPE_CLONE_AZT1605_0X0C, + azt_init, azt_close, NULL, NULL, + azt_speed_changed, + NULL, + azt1605_config +}; diff --git a/src/sound/snd_azt2316a.h b/src/sound/snd_azt2316a.h new file mode 100644 index 000000000..852de6c92 --- /dev/null +++ b/src/sound/snd_azt2316a.h @@ -0,0 +1 @@ +extern void azt2316a_enable_wss(uint8_t enable, void *p); \ No newline at end of file diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index bdea9d911..21ccc99d8 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -1593,6 +1593,11 @@ MPU401_InputMsg(void *p, uint8_t *msg) MPU401_QueueByte(mpu, msg[i]); } +void +mpu401_setirq(mpu_t *mpu, int irq) +{ + mpu->irq = irq; +} void mpu401_change_addr(mpu_t *mpu, uint16_t addr) @@ -1711,7 +1716,7 @@ mpu401_standalone_init(const device_t *info) mpu401_log("mpu_init\n"); if (info->flags & DEVICE_MCA) { - mca_add(mpu401_mca_read, mpu401_mca_write, mpu401_mca_feedb, mpu); + mca_add(mpu401_mca_read, mpu401_mca_write, mpu401_mca_feedb, NULL, mpu); mpu->pos_regs[0] = 0x0F; mpu->pos_regs[1] = 0x6C; base = 0; /* Tell mpu401_init() that this is the MCA variant. */ diff --git a/src/sound/snd_mpu401.h b/src/sound/snd_mpu401.h index 99fe8b288..61eaa654b 100644 --- a/src/sound/snd_mpu401.h +++ b/src/sound/snd_mpu401.h @@ -150,6 +150,7 @@ extern const device_t mpu401_mca_device; extern uint8_t MPU401_ReadData(mpu_t *mpu); +extern void mpu401_setirq(mpu_t *mpu, int irq); extern void mpu401_change_addr(mpu_t *mpu, uint16_t addr); extern void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode, int receive_input); extern void mpu401_device_add(void); diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 19aae50dc..717b45122 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -737,7 +737,7 @@ static void *pas16_init(const device_t *info) memset(pas16, 0, sizeof(pas16_t)); opl3_init(&pas16->opl); - sb_dsp_init(&pas16->dsp, SB2); + sb_dsp_init(&pas16->dsp, SB2, SB_SUBTYPE_DEFAULT, pas16); io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16); diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 25ed6b87d..ce489d022 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -35,10 +35,7 @@ #include "sound.h" #include "midi.h" #include "filters.h" -#include "snd_emu8k.h" -#include "snd_mpu401.h" -#include "snd_opl.h" -#include "snd_sb_dsp.h" +#include "snd_sb.h" //#define SB_DSP_RECORD_DEBUG @@ -48,102 +45,6 @@ FILE* soundfsbin = 0/*NULL*/; #endif - -/* SB 2.0 CD version */ -typedef struct sb_ct1335_mixer_t -{ - int32_t master; - int32_t voice; - int32_t fm; - int32_t cd; - - uint8_t index; - uint8_t regs[256]; -} sb_ct1335_mixer_t; -/* SB PRO */ -typedef struct sb_ct1345_mixer_t -{ - int32_t master_l, master_r; - int32_t voice_l, voice_r; - int32_t fm_l, fm_r; - int32_t cd_l, cd_r; - int32_t line_l, line_r; - int32_t mic; - /*see sb_ct1745_mixer for values for input selector*/ - int32_t input_selector; - - int input_filter; - int in_filter_freq; - int output_filter; - - int stereo; - int stereo_isleft; - - uint8_t index; - uint8_t regs[256]; - -} sb_ct1345_mixer_t; -/* SB16 and AWE32 */ -typedef struct sb_ct1745_mixer_t -{ - int32_t master_l, master_r; - int32_t voice_l, voice_r; - int32_t fm_l, fm_r; - int32_t cd_l, cd_r; - int32_t line_l, line_r; - int32_t mic; - int32_t speaker; - - int bass_l, bass_r; - int treble_l, treble_r; - - int output_selector; - #define OUTPUT_MIC 1 - #define OUTPUT_CD_R 2 - #define OUTPUT_CD_L 4 - #define OUTPUT_LINE_R 8 - #define OUTPUT_LINE_L 16 - - int input_selector_left; - int input_selector_right; - #define INPUT_MIC 1 - #define INPUT_CD_R 2 - #define INPUT_CD_L 4 - #define INPUT_LINE_R 8 - #define INPUT_LINE_L 16 - #define INPUT_MIDI_R 32 - #define INPUT_MIDI_L 64 - - int mic_agc; - - int32_t input_gain_L; - int32_t input_gain_R; - int32_t output_gain_L; - int32_t output_gain_R; - - uint8_t index; - uint8_t regs[256]; -} sb_ct1745_mixer_t; - -typedef struct sb_t -{ - uint8_t opl_enabled; - opl_t opl; - sb_dsp_t dsp; - union { - sb_ct1335_mixer_t mixer_sb2; - sb_ct1345_mixer_t mixer_sbpro; - sb_ct1745_mixer_t mixer_sb16; - }; - mpu_t *mpu; - emu8k_t emu8k; - - int pos; - - uint8_t pos_regs[8]; - - int opl_emu; -} sb_t; /* 0 to 7 -> -14dB to 0dB i 2dB steps. 8 to 15 -> 0 to +14dB in 2dB steps. Note that for positive dB values, this is not amplitude, it is amplitude-1. */ const float sb_bass_treble_4bits[]= { @@ -247,7 +148,7 @@ static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) sb->dsp.pos = 0; } -static void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) +void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; @@ -860,149 +761,147 @@ void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) uint8_t sb_ct1745_mixer_read(uint16_t addr, void *p) { - sb_t *sb = (sb_t *)p; - sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + sb_t *sb = (sb_t *)p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; uint8_t temp, ret = 0xff; - if (!(addr & 1)) - ret = mixer->index; + if (!(addr & 1)) + ret = mixer->index; - sb_log("sb_ct1745: received register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + sb_log("sb_ct1745: received register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); - if (mixer->index>=0x30 && mixer->index<=0x47) - ret = mixer->regs[mixer->index]; - else switch (mixer->index) - { - case 0x00: - ret = mixer->regs[mixer->index]; - break; + if (mixer->index>=0x30 && mixer->index<=0x47) + ret = mixer->regs[mixer->index]; + else switch (mixer->index) { + case 0x00: + ret = mixer->regs[mixer->index]; + break; - /*SB Pro compatibility*/ - case 0x04: - ret = ((mixer->regs[0x33] >> 4) & 0x0f) | (mixer->regs[0x32] & 0xf0); - break; - case 0x0a: - // ret = (mixer->regs[0x3a] - 10) / 3; - ret = (mixer->regs[0x3a] >> 5); - break; - case 0x02: - ret = ((mixer->regs[0x30] >> 4) & 0x0f); - break; - case 0x06: - ret = ((mixer->regs[0x34] >> 4) & 0x0f); - break; - case 0x08: - ret = ((mixer->regs[0x36] >> 4) & 0x0f); - break; - case 0x22: - ret = ((mixer->regs[0x31] >> 4) & 0x0f) | (mixer->regs[0x30] & 0xf0); - break; - case 0x26: - ret = ((mixer->regs[0x35] >> 4) & 0x0f) | (mixer->regs[0x34] & 0xf0); - break; - case 0x28: - ret = ((mixer->regs[0x37] >> 4) & 0x0f) | (mixer->regs[0x36] & 0xf0); - break; - case 0x2e: - ret = ((mixer->regs[0x39] >> 4) & 0x0f) | (mixer->regs[0x38] & 0xf0); - break; + /*SB Pro compatibility*/ + case 0x04: + ret = ((mixer->regs[0x33] >> 4) & 0x0f) | (mixer->regs[0x32] & 0xf0); + break; + case 0x0a: + // ret = (mixer->regs[0x3a] - 10) / 3; + ret = (mixer->regs[0x3a] >> 5); + break; + case 0x02: + ret = ((mixer->regs[0x30] >> 4) & 0x0f); + break; + case 0x06: + ret = ((mixer->regs[0x34] >> 4) & 0x0f); + break; + case 0x08: + ret = ((mixer->regs[0x36] >> 4) & 0x0f); + break; + case 0x22: + ret = ((mixer->regs[0x31] >> 4) & 0x0f) | (mixer->regs[0x30] & 0xf0); + break; + case 0x26: + ret = ((mixer->regs[0x35] >> 4) & 0x0f) | (mixer->regs[0x34] & 0xf0); + break; + case 0x28: + ret = ((mixer->regs[0x37] >> 4) & 0x0f) | (mixer->regs[0x36] & 0xf0); + break; + case 0x2e: + ret = ((mixer->regs[0x39] >> 4) & 0x0f) | (mixer->regs[0x38] & 0xf0); + break; - case 0x48: - // Undocumented. The Creative Windows Mixer calls this after calling 3C (input selector). even when writing. - // Also, the version I have (5.17) does not use the MIDI.L/R input selectors. it uses the volume to mute (Affecting the output, obviously) - ret = mixer->regs[mixer->index]; - break; + case 0x48: + // Undocumented. The Creative Windows Mixer calls this after calling 3C (input selector). even when writing. + // Also, the version I have (5.17) does not use the MIDI.L/R input selectors. it uses the volume to mute (Affecting the output, obviously) + ret = mixer->regs[mixer->index]; + break; - case 0x80: - /*TODO: Unaffected by mixer reset or soft reboot. - * Enabling multiple bits enables multiple IRQs. - */ + case 0x80: + /*TODO: Unaffected by mixer reset or soft reboot. + * Enabling multiple bits enables multiple IRQs. + */ - switch (sb->dsp.sb_irqnum) - { - case 2: ret = 1; break; - case 5: ret = 2; break; - case 7: ret = 4; break; - case 10: ret = 8; break; - } - break; + switch (sb->dsp.sb_irqnum) { + case 2: ret = 1; break; + case 5: ret = 2; break; + case 7: ret = 4; break; + case 10: ret = 8; break; + } + break; - case 0x81: - /* TODO: Unaffected by mixer reset or soft reboot. - * Enabling multiple 8 or 16-bit DMA bits enables multiple DMA channels. - * Disabling all 8-bit DMA channel bits disables 8-bit DMA requests, - including translated 16-bit DMA requests. - * Disabling all 16-bit DMA channel bits enables translation of 16-bit DMA - requests to 8-bit ones, using the selected 8-bit DMA channel.*/ + case 0x81: + /* TODO: Unaffected by mixer reset or soft reboot. + * Enabling multiple 8 or 16-bit DMA bits enables multiple DMA channels. + * Disabling all 8-bit DMA channel bits disables 8-bit DMA requests, + including translated 16-bit DMA requests. + * Disabling all 16-bit DMA channel bits enables translation of 16-bit DMA + requests to 8-bit ones, using the selected 8-bit DMA channel.*/ - ret = 0; - switch (sb->dsp.sb_8_dmanum) { - case 0: ret |= 1; break; - case 1: ret |= 2; break; - case 3: ret |= 8; break; - } - switch (sb->dsp.sb_16_dmanum) - { - case 5: ret |= 0x20; break; - case 6: ret |= 0x40; break; - case 7: ret |= 0x80; break; - } - break; + ret = 0; + switch (sb->dsp.sb_8_dmanum) { + case 0: ret |= 1; break; + case 1: ret |= 2; break; + case 3: ret |= 8; break; + } + switch (sb->dsp.sb_16_dmanum) { + case 5: ret |= 0x20; break; + case 6: ret |= 0x40; break; + case 7: ret |= 0x80; break; + } + break; - /* The Interrupt status register, addressed as register 82h on the Mixer register map, + /* The Interrupt status register, addressed as register 82h on the Mixer register map, is used by the ISR to determine whether the interrupt is meant for it or for some other ISR, - in which case it should chain to the previous routine. - */ - case 0x82: - /* 0 = none, 1 = digital 8bit or SBMIDI, 2 = digital 16bit, 4 = MPU-401 */ - /* 0x02000 DSP v4.04, 0x4000 DSP v4.05 0x8000 DSP v4.12. I haven't seen this making any difference, but I'm keeping it for now. */ - temp = ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | 0x4000; - if (sb->mpu) - temp |= ((sb->mpu->state.irq_pending) ? 4 : 0); - ret = temp; - break; + in which case it should chain to the previous routine. + */ + case 0x82: + /* 0 = none, 1 = digital 8bit or SBMIDI, 2 = digital 16bit, 4 = MPU-401 */ + /* 0x02000 DSP v4.04, 0x4000 DSP v4.05 0x8000 DSP v4.12. I haven't seen this making any difference, but I'm keeping it for now. */ + temp = ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | 0x4000; + if (sb->mpu) + temp |= ((sb->mpu->state.irq_pending) ? 4 : 0); + ret = temp; + break; case 0x83: - /* Interrupt mask. */ - ret = mixer->regs[mixer->index]; - break; + /* Interrupt mask. */ + ret = mixer->regs[mixer->index]; + break; case 0x84: - /* MPU Control. */ - if (sb->mpu == NULL) - ret = 0x02; - else { - if (sb->mpu->addr == 0x330) - ret = 0x00; - else if (sb->mpu->addr == 0x300) - ret = 0x04; - else if (sb->mpu->addr == 0) + /* MPU Control. */ + if (sb->mpu == NULL) ret = 0x02; - else - ret = 0x06; /* Should never happen. */ - } - break; + else { + if (sb->mpu->addr == 0x330) + ret = 0x00; + else if (sb->mpu->addr == 0x300) + ret = 0x04; + else if (sb->mpu->addr == 0) + ret = 0x02; + else + ret = 0x06; /* Should never happen. */ + } + break; case 0x90: - /* 3D Enhancement switch. */ - ret = mixer->regs[mixer->index]; - break; + /* 3D Enhancement switch. */ + ret = mixer->regs[mixer->index]; + break; /* TODO: creative drivers read and write on 0xFE and 0xFF. not sure what they are supposed to be. */ - case 0xfd: - ret = 16; - break; + case 0xfd: + ret = 16; + break; case 0xfe: - ret = 6; - break; + ret = 6; + break; - default: - sb_log("sb_ct1745: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); - break; - } + default: + sb_log("sb_ct1745: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } - return ret; + sb_log("CT1745: read REG%02X: %02X\n", mixer->index, ret); + return ret; } void sb_ct1745_mixer_reset(sb_t* sb) @@ -1126,7 +1025,7 @@ void *sb_1_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB1); + sb_dsp_init(&sb->dsp, SB1, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -1156,7 +1055,7 @@ void *sb_15_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB15); + sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -1185,13 +1084,13 @@ void *sb_mcv_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB15); + sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, 0);//addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); sound_add_handler(sb_get_buffer_sb2, sb); /* I/O handlers activated in sb_mcv_write */ - mca_add(sb_mcv_read, sb_mcv_write, sb_mcv_feedb, sb); + mca_add(sb_mcv_read, sb_mcv_write, sb_mcv_feedb, NULL, sb); sb->pos_regs[0] = 0x84; sb->pos_regs[1] = 0x50; @@ -1222,7 +1121,7 @@ void *sb_2_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB2); + sb_dsp_init(&sb->dsp, SB2, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -1266,7 +1165,7 @@ void *sb_pro_v1_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SBPRO); + sb_dsp_init(&sb->dsp, SBPRO, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -1302,7 +1201,7 @@ void *sb_pro_v2_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) opl3_init(&sb->opl); - sb_dsp_init(&sb->dsp, SBPRO2); + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -1334,13 +1233,13 @@ void *sb_pro_mcv_init(const device_t *info) sb->opl_enabled = 1; opl3_init(&sb->opl); - sb_dsp_init(&sb->dsp, SBPRO2); + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); sb_ct1345_mixer_reset(sb); /* I/O handlers activated in sb_mcv_write */ sound_add_handler(sb_get_buffer_sbpro, sb); /* I/O handlers activated in sb_pro_mcv_write */ - mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb_mcv_feedb, sb); + mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb_mcv_feedb, NULL, sb); sb->pos_regs[0] = 0x03; sb->pos_regs[1] = 0x51; @@ -1360,7 +1259,7 @@ void *sb_16_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) opl3_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB16); + sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -1406,7 +1305,7 @@ void *sb_awe32_init(const device_t *info) if (sb->opl_enabled) opl3_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB16 + 1); + sb_dsp_init(&sb->dsp, SB16 + 1, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); diff --git a/src/sound/snd_sb.h b/src/sound/snd_sb.h new file mode 100644 index 000000000..ee996b923 --- /dev/null +++ b/src/sound/snd_sb.h @@ -0,0 +1,143 @@ +/* + * 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. + * + * Sound Blaster emulation. + * + * Version: @(#)sound_sb.h 1.0.4 2020/02/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#ifndef SOUND_SND_SB_H +# define SOUND_SND_SB_H + +#include "snd_emu8k.h" +#include "snd_mpu401.h" +#include "snd_opl.h" +#include "snd_sb_dsp.h" + +#define SADLIB 1 /* No DSP */ +#define SB1 2 /* DSP v1.05 */ +#define SB15 3 /* DSP v2.00 */ +#define SB2 4 /* DSP v2.01 - needed for high-speed DMA */ +#define SBPRO 5 /* DSP v3.00 */ +#define SBPRO2 6 /* DSP v3.02 + OPL3 */ +#define SB16 7 /* DSP v4.05 + OPL3 */ +#define SADGOLD 8 /* AdLib Gold */ +#define SND_WSS 9 /* Windows Sound System */ +#define SND_PAS16 10 /* Pro Audio Spectrum 16 */ + +/* SB 2.0 CD version */ +typedef struct sb_ct1335_mixer_t +{ + int32_t master; + int32_t voice; + int32_t fm; + int32_t cd; + + uint8_t index; + uint8_t regs[256]; +} sb_ct1335_mixer_t; +/* SB PRO */ +typedef struct sb_ct1345_mixer_t +{ + int32_t master_l, master_r; + int32_t voice_l, voice_r; + int32_t fm_l, fm_r; + int32_t cd_l, cd_r; + int32_t line_l, line_r; + int32_t mic; + /*see sb_ct1745_mixer for values for input selector*/ + int32_t input_selector; + + int input_filter; + int in_filter_freq; + int output_filter; + + int stereo; + int stereo_isleft; + + uint8_t index; + uint8_t regs[256]; + +} sb_ct1345_mixer_t; +/* SB16 and AWE32 */ +typedef struct sb_ct1745_mixer_t +{ + int32_t master_l, master_r; + int32_t voice_l, voice_r; + int32_t fm_l, fm_r; + int32_t cd_l, cd_r; + int32_t line_l, line_r; + int32_t mic; + int32_t speaker; + + int bass_l, bass_r; + int treble_l, treble_r; + + int output_selector; + #define OUTPUT_MIC 1 + #define OUTPUT_CD_R 2 + #define OUTPUT_CD_L 4 + #define OUTPUT_LINE_R 8 + #define OUTPUT_LINE_L 16 + + int input_selector_left; + int input_selector_right; + #define INPUT_MIC 1 + #define INPUT_CD_R 2 + #define INPUT_CD_L 4 + #define INPUT_LINE_R 8 + #define INPUT_LINE_L 16 + #define INPUT_MIDI_R 32 + #define INPUT_MIDI_L 64 + + int mic_agc; + + int32_t input_gain_L; + int32_t input_gain_R; + int32_t output_gain_L; + int32_t output_gain_R; + + uint8_t index; + uint8_t regs[256]; +} sb_ct1745_mixer_t; + +typedef struct sb_t +{ + uint8_t opl_enabled; + opl_t opl; + sb_dsp_t dsp; + union { + sb_ct1335_mixer_t mixer_sb2; + sb_ct1345_mixer_t mixer_sbpro; + sb_ct1745_mixer_t mixer_sb16; + }; + mpu_t *mpu; + emu8k_t emu8k; + + int pos; + + uint8_t pos_regs[8]; + + int opl_emu; +} sb_t; + +extern void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p); +extern uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p); +extern void sb_ct1345_mixer_reset(sb_t* sb); + +extern void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p); +extern void sb_close(void *p); +extern void sb_speed_changed(void *p); + +#endif /*SOUND_SND_SB_H*/ diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 5f86e79e6..5006b9b25 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -22,8 +22,8 @@ #include "sound.h" #include "midi.h" #include "sound.h" -#include "snd_mpu401.h" -#include "snd_sb_dsp.h" +#include "snd_azt2316a.h" +#include "snd_sb.h" #define ADPCM_4 1 @@ -244,10 +244,16 @@ sb_doreset(sb_dsp_t *dsp) sb_dsp_reset(dsp); - if (dsp->sb_type==SB16) - sb_commands[8] = 1; - else - sb_commands[8] = -1; + + if (IS_AZTECH(dsp)) { + sb_commands[8] = 1; + sb_commands[9] = 1; + } else { + if (dsp->sb_type==SB16) + sb_commands[8] = 1; + else + sb_commands[8] = -1; + } for (c = 0; c < 256; c++) dsp->sb_asp_regs[c] = 0; @@ -648,6 +654,16 @@ sb_exec_command(sb_dsp_t *dsp) sb_add_data(dsp, ~dsp->sb_data[0]); break; case 0xE1: /* Get DSP version */ + if (IS_AZTECH(dsp)) { + if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + sb_add_data(dsp, 0x3); + sb_add_data(dsp, 0x1); + } else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) { + sb_add_data(dsp, 0x2); + sb_add_data(dsp, 0x1); + } + break; + } sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); break; @@ -687,6 +703,29 @@ sb_exec_command(sb_dsp_t *dsp) case 0x07: case 0xFF: /* No, that's not how you program auto-init DMA */ break; case 0x08: /* ASP get version */ + if (IS_AZTECH(dsp)) { + if ((dsp->sb_data[0] == 0x05 || dsp->sb_data[0] == 0x55)&& dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11) + sb_add_data(dsp, 0x11); /* AZTECH get type, WASHINGTON/latest - according to devkit. E.g.: The one in the Itautec Infoway Multimidia */ + else if ((dsp->sb_data[0] == 0x05 || dsp->sb_data[0] == 0x55) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) + sb_add_data(dsp, 0x0C); /* AZTECH get type, CLINTON - according to devkit. E.g.: The one in the Packard Bell Legend 100CD */ + else if (dsp->sb_data[0] == 0x08) { + /* EEPROM address to write followed by byte */ + if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) + fatal("AZT EEPROM: out of bounds write to %02X\n", dsp->sb_data[1]); + sb_dsp_log("EEPROM write = %02x\n", dsp->sb_data[2]); + dsp->azt_eeprom[dsp->sb_data[1]] = dsp->sb_data[2]; + break; + } else if (dsp->sb_data[0] == 0x07) { + /* EEPROM address to read */ + if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) + fatal("AZT EEPROM: out of bounds read to %02X\n", dsp->sb_data[1]); + sb_dsp_log("EEPROM read = %02x\n", dsp->azt_eeprom[dsp->sb_data[1]]); + sb_add_data(dsp, dsp->azt_eeprom[dsp->sb_data[1]]); + break; + } else + sb_dsp_log("AZT2316A: UNKNOWN 0x08 COMMAND: %02X\n", dsp->sb_data[0]); /* 0x08 (when shutting down, driver tries to read 1 byte of response), 0x55, 0x0D, 0x08D seen */ + break; + } if (dsp->sb_type >= SB16) sb_add_data(dsp, 0x18); break; @@ -716,6 +755,17 @@ sb_exec_command(sb_dsp_t *dsp) case 0x04: case 0x05: break; + case 0x09: /*AZTECH mode set*/ + if (dsp->sb_data[0] == 0x00) { + sb_dsp_log("AZT2316A: WSS MODE!\n"); + azt2316a_enable_wss(1, dsp->parent); + } else if (dsp->sb_data[0] == 0x01) { + sb_dsp_log("AZT2316A: SB8PROV2 MODE!\n"); + azt2316a_enable_wss(0, dsp->parent); + } else + sb_dsp_log("AZT2316A: UNKNOWN MODE! = %02x\n", dsp->sb_data[0]); // sequences 0x02->0xFF, 0x04->0xFF seen + break; + /* TODO: Some more data about the DSP registeres * http://the.earth.li/~tfm/oldpage/sb_dsp.html * http://www.synchrondata.com/pheaven/www/area19.htm @@ -770,11 +820,24 @@ sb_write(uint16_t a, uint8_t v, void *priv) if (v == 0x01) sb_add_data(dsp, 0); dsp->sb_data_stat++; - } else + } else { dsp->sb_data[dsp->sb_data_stat++] = v; + if (IS_AZTECH(dsp)) { + /* variable length commands */ + if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x08) + sb_commands[dsp->sb_command] = 3; + else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07) + sb_commands[dsp->sb_command] = 2; + } + } if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) { sb_exec_command(dsp); dsp->sb_data_stat = -1; + if (IS_AZTECH(dsp)) { + /* variable length commands */ + if (dsp->sb_command == 0x08) + sb_commands[dsp->sb_command] = 1; + } } break; } @@ -807,19 +870,39 @@ sb_read(uint16_t a, void *priv) dsp->busy_count = 0; if (dsp->wb_full || (dsp->busy_count & 2)) { dsp->wb_full = timer_is_enabled(&dsp->wb_timer); - return 0xff; + if (IS_AZTECH(dsp)) { + sb_dsp_log("SB Write Data Aztech read 0x80\n"); + return 0x80; + } else { + sb_dsp_log("SB Write Data Creative read 0xff\n"); + return 0xff; + } + } + if (IS_AZTECH(dsp)) { + sb_dsp_log("SB Write Data Aztech read 0x00\n"); + ret = 0x00; + } else { + sb_dsp_log("SB Write Data Creative read 0x7f\n"); + ret = 0x7f; } - ret = 0x7f; break; case 0xE: /* Read data ready */ picintc(1 << dsp->sb_irqnum); dsp->sb_irq8 = dsp->sb_irq16 = 0; - ret = (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; + /* Only bit 7 is defined but aztech diagnostics fail if the others are set. Keep the original behavior to not interfere with what's already working. */ + if (IS_AZTECH(dsp)) { + sb_dsp_log("SB Read Data Aztech read %02X, Read RP = %d, Read WP = %d\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80, dsp->sb_read_rp, dsp->sb_read_wp); + ret = (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80; + } else { + sb_dsp_log("SB Read Data Creative read %02X\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff); + ret = (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; + } break; case 0xF: /* 16-bit ack */ dsp->sb_irq16 = 0; if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum); + sb_dsp_log("SB 16-bit ACK read 0xFF\n"); ret = 0xff; break; } @@ -892,9 +975,11 @@ sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) } void -sb_dsp_init(sb_dsp_t *dsp, int type) +sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent) { dsp->sb_type = type; + dsp->sb_subtype = subtype; + dsp->parent = parent; /* Default values. Use sb_dsp_setxxx() methods to change. */ dsp->sb_irqnum = 7; diff --git a/src/sound/snd_sb_dsp.h b/src/sound/snd_sb_dsp.h index 96743e77e..47cc2570f 100644 --- a/src/sound/snd_sb_dsp.h +++ b/src/sound/snd_sb_dsp.h @@ -1,92 +1,96 @@ -#define SADLIB 1 /* No DSP */ -#define SB1 2 /* DSP v1.05 */ -#define SB15 3 /* DSP v2.00 */ -#define SB2 4 /* DSP v2.01 - needed for high-speed DMA */ -#define SBPRO 5 /* DSP v3.00 */ -#define SBPRO2 6 /* DSP v3.02 + OPL3 */ -#define SB16 7 /* DSP v4.05 + OPL3 */ -#define SADGOLD 8 /* AdLib Gold */ -#define SND_WSS 9 /* Windows Sound System */ -#define SND_PAS16 10 /* Pro Audio Spectrum 16 */ +#ifndef SOUND_SND_SB_DSP_H +#define SOUND_SND_SB_DSP_H +/*Sound Blaster Clones, for quirks*/ +#define SB_SUBTYPE_DEFAULT 0 /*Handle as a Creative card*/ +#define SB_SUBTYPE_CLONE_AZT2316A_0X11 1 /*Aztech Sound Galaxy Pro 16 AB, DSP 3.1 - SBPRO2 clone*/ +#define SB_SUBTYPE_CLONE_AZT1605_0X0C 2 /*Aztech Sound Galaxy Nova 16 Extra / Packard Bell Forte 16, DSP 2.1 - SBPRO2 clone*/ + +/* aztech-related */ +#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) /* check for future AZT cards here */ +#define AZTECH_EEPROM_SIZE 16 typedef struct sb_dsp_t { - int sb_type; + int sb_type; + int sb_subtype; /* which clone */ + void *parent; /* "sb_t *" if default subtype, "azt2316a_t *" if aztech. */ - int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; - int sb_8_dmanum; - int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; - int sb_16_dmanum; - int sb_pausetime; + int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; + int sb_8_dmanum; + int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; + int sb_16_dmanum; + int sb_pausetime; - uint8_t sb_read_data[256]; - int sb_read_wp, sb_read_rp; - int sb_speaker; - int muted; + uint8_t sb_read_data[256]; + int sb_read_wp, sb_read_rp; + int sb_speaker; + int muted; - int sb_data_stat; - - int midi_in_sysex; - int midi_in_poll; - int uart_midi; - int uart_irq; - int onebyte_midi; - int midi_in_timestamp; + int sb_data_stat; - int sb_irqnum; + int midi_in_sysex; + int midi_in_poll; + int uart_midi; + int uart_irq; + int onebyte_midi; + int midi_in_timestamp; - uint8_t sbe2; - int sbe2count; + int sb_irqnum; - uint8_t sb_data[8]; + uint8_t sbe2; + int sbe2count; - int sb_freq; + uint8_t sb_data[8]; + + int sb_freq; - int16_t sbdat; - int sbdat2; - int16_t sbdatl, sbdatr; + int16_t sbdat; + int sbdat2; + int16_t sbdatl, sbdatr; - uint8_t sbref; - int8_t sbstep; + uint8_t sbref; + int8_t sbstep; - int sbdacpos; + int sbdacpos; - int sbleftright; + int sbleftright; - int sbreset; - uint8_t sbreaddat; - uint8_t sb_command; - uint8_t sb_test; - int sb_timei, sb_timeo; + int sbreset; + uint8_t sbreaddat; + uint8_t sb_command; + uint8_t sb_test; + int sb_timei, sb_timeo; - int sb_irq8, sb_irq16; - int sb_irqm8, sb_irqm16; + int sb_irq8, sb_irq16; + int sb_irqm8, sb_irqm16; - uint8_t sb_asp_regs[256]; + uint8_t sb_asp_regs[256]; - int sbenable, sb_enable_i; + int sbenable, sb_enable_i; - pc_timer_t output_timer, input_timer; + pc_timer_t output_timer, input_timer; - uint64_t sblatcho, sblatchi; - - uint16_t sb_addr; - - int stereo; - - int asp_data_len; - - pc_timer_t wb_timer; - int wb_full; + uint64_t sblatcho, sblatchi; + + uint16_t sb_addr; + + int stereo; + + int asp_data_len; + + pc_timer_t wb_timer; + int wb_full; int busy_count; - int record_pos_read; - int record_pos_write; - int16_t record_buffer[0xFFFF]; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; + int record_pos_read; + int record_pos_write; + int16_t record_buffer[0xFFFF]; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; + + uint8_t azt_eeprom[AZTECH_EEPROM_SIZE]; /* the eeprom in the Aztech cards is attached to the DSP */ } sb_dsp_t; @@ -96,7 +100,7 @@ int sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort); void sb_dsp_set_mpu(mpu_t *src_mpu); -void sb_dsp_init(sb_dsp_t *dsp, int type); +void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent); void sb_dsp_close(sb_dsp_t *dsp); void sb_dsp_setirq(sb_dsp_t *dsp, int irq); @@ -111,4 +115,5 @@ void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r); void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo); void sb_dsp_update(sb_dsp_t *dsp); -void sb_irqc(sb_dsp_t *dsp, int irq8); + +#endif /* SOUND_SND_SB_DSP_H */ \ No newline at end of file diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 5de5674b9..48859c408 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -48,76 +48,75 @@ static int wss_dma[4] = {0, 0, 1, 3}; static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/ - typedef struct wss_t { - uint8_t config; + uint8_t config; - ad1848_t ad1848; - opl_t opl; - - int opl_enabled; - uint8_t pos_regs[8]; + ad1848_t ad1848; + opl_t opl; + + int opl_enabled; + uint8_t pos_regs[8]; } wss_t; uint8_t wss_read(uint16_t addr, void *p) { - wss_t *wss = (wss_t *)p; - uint8_t temp; - temp = 4 | (wss->config & 0x40); - return temp; + wss_t *wss = (wss_t *)p; + uint8_t temp; + temp = 4 | (wss->config & 0x40); + return temp; } void wss_write(uint16_t addr, uint8_t val, void *p) { - wss_t *wss = (wss_t *)p; + wss_t *wss = (wss_t *)p; - wss->config = val; - ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); - ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); + wss->config = val; + ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); + ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); } static void wss_get_buffer(int32_t *buffer, int len, void *p) { - wss_t *wss = (wss_t *)p; - + wss_t *wss = (wss_t *)p; int c; - opl3_update2(&wss->opl); - ad1848_update(&wss->ad1848); - for (c = 0; c < len * 2; c++) - { - buffer[c] += wss->opl.buffer[c]; - buffer[c] += (wss->ad1848.buffer[c] / 2); - } + opl3_update2(&wss->opl); + ad1848_update(&wss->ad1848); + for (c = 0; c < len * 2; c++) { + buffer[c] += wss->opl.buffer[c]; + buffer[c] += (wss->ad1848.buffer[c] / 2); + } - wss->opl.pos = 0; - wss->ad1848.pos = 0; + wss->opl.pos = 0; + wss->ad1848.pos = 0; } void *wss_init(const device_t *info) { - wss_t *wss = malloc(sizeof(wss_t)); - memset(wss, 0, sizeof(wss_t)); - - uint16_t addr = device_get_config_hex16("base"); - wss->opl_enabled = device_get_config_int("opl"); - - opl3_init(&wss->opl); - ad1848_init(&wss->ad1848); - - ad1848_setirq(&wss->ad1848, 7); - ad1848_setdma(&wss->ad1848, 3); + wss_t *wss = malloc(sizeof(wss_t)); + memset(wss, 0, sizeof(wss_t)); - if (wss->opl_enabled) - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + uint16_t addr = device_get_config_hex16("base"); + wss->opl_enabled = device_get_config_int("opl"); + + if (wss->opl_enabled) + opl3_init(&wss->opl); - io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); - - sound_add_handler(wss_get_buffer, wss); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); + + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); + + if (wss->opl_enabled) + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - return wss; + io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + sound_add_handler(wss_get_buffer, wss); + + return wss; } static uint8_t ncr_audio_mca_read(int port, void *p) @@ -129,10 +128,10 @@ static uint8_t ncr_audio_mca_read(int port, void *p) static void ncr_audio_mca_write(int port, uint8_t val, void *p) { - wss_t *wss = (wss_t *)p; + wss_t *wss = (wss_t *)p; uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604}; uint16_t addr; - + if (port < 0x102) return; @@ -142,15 +141,12 @@ static void ncr_audio_mca_write(int port, uint8_t val, void *p) io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); - - //pclog("WSS MCA: opl=%d, addr=%03x\n", wss->opl_enabled, addr); wss->pos_regs[port & 7] = val; - - if (wss->pos_regs[2] & 1) - { + + if (wss->pos_regs[2] & 1) { addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; - + if (wss->opl_enabled) io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); @@ -168,37 +164,37 @@ static uint8_t ncr_audio_mca_feedb(void *p) void *ncr_audio_init(const device_t *info) { - wss_t *wss = malloc(sizeof(wss_t)); + wss_t *wss = malloc(sizeof(wss_t)); - memset(wss, 0, sizeof(wss_t)); + memset(wss, 0, sizeof(wss_t)); - opl3_init(&wss->opl); - ad1848_init(&wss->ad1848); + opl3_init(&wss->opl); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); ad1848_setirq(&wss->ad1848, 7); ad1848_setdma(&wss->ad1848, 3); - - mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, wss); + + mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss); wss->pos_regs[0] = 0x16; wss->pos_regs[1] = 0x51; - - sound_add_handler(wss_get_buffer, wss); - - return wss; + + sound_add_handler(wss_get_buffer, wss); + + return wss; } void wss_close(void *p) { - wss_t *wss = (wss_t *)p; - - free(wss); + wss_t *wss = (wss_t *)p; + + free(wss); } void wss_speed_changed(void *p) { - wss_t *wss = (wss_t *)p; - - ad1848_speed_changed(&wss->ad1848); + wss_t *wss = (wss_t *)p; + + ad1848_speed_changed(&wss->ad1848); } static const device_config_t wss_config[] = diff --git a/src/sound/sound.c b/src/sound/sound.c index df17cb865..c67dcd3b4 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -34,6 +34,7 @@ #include "snd_opl.h" #include "snd_mpu401.h" #include "snd_sb_dsp.h" +#include "snd_azt2316a.h" #include "filters.h" @@ -80,6 +81,8 @@ static const SOUND_CARD sound_cards[] = { "None", "none", NULL }, { "[ISA] Adlib", "adlib", &adlib_device }, { "[ISA] Adlib Gold", "adlibgold", &adgold_device }, + { "[ISA] Aztech Sound Galaxy Pro 16 AB (Washington)", "azt2316a", &azt2316a_device }, + { "[ISA] Aztech Sound Galaxy Nova 16 Extra (Clinton)", "azt1605", &azt1605_device }, { "[ISA] Sound Blaster 1.0", "sb", &sb_1_device }, { "[ISA] Sound Blaster 1.5", "sb1.5", &sb_15_device }, { "[ISA] Sound Blaster 2.0", "sb2.0", &sb_2_device }, diff --git a/src/sound/sound.h b/src/sound/sound.h index 34f5d0ca9..31dca9afe 100644 --- a/src/sound/sound.h +++ b/src/sound/sound.h @@ -73,6 +73,10 @@ extern const device_t adlib_device; extern const device_t adlib_mca_device; extern const device_t adgold_device; +/* Aztech Sound Galaxy 16 */ +extern const device_t azt2316a_device; +extern const device_t azt1605_device; + /* Ensoniq AudioPCI */ extern const device_t es1371_device; diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 4b3df6ddc..55a50ce4d 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -3127,7 +3127,7 @@ static void if (gd54xx->mca) { gd54xx->pos_regs[0] = 0x7b; gd54xx->pos_regs[1] = 0x91; - mca_add(gd5428_mca_read, gd5428_mca_write, gd5428_mca_feedb, gd54xx); + mca_add(gd5428_mca_read, gd5428_mca_write, gd5428_mca_feedb, NULL, gd54xx); } return gd54xx; diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index ad4bd13a9..b5f27b3df 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -512,7 +512,7 @@ et4000_init(const device_t *info) et4000_in,NULL,NULL, et4000_out,NULL,NULL, dev); dev->pos_regs[0] = 0xf2; /* ET4000 MCA board ID */ dev->pos_regs[1] = 0x80; - mca_add(et4000_mca_read, et4000_mca_write, et4000_mca_feedb, dev); + mca_add(et4000_mca_read, et4000_mca_write, et4000_mca_feedb, NULL, dev); break; case 2: /* Korean ET4000 */ diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index bcc10bbd2..5ecbe9d47 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -673,6 +673,7 @@ SNDOBJ := sound.o \ snd_pssj.o \ snd_lpt_dac.o snd_lpt_dss.o \ snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ + snd_azt2316a.o \ snd_cms.o \ snd_gus.o \ snd_sb.o snd_sb_dsp.o \ diff --git a/src/win/Makefile_ndr.mingw b/src/win/Makefile_ndr.mingw index 23466a8f6..6d697ef4b 100644 --- a/src/win/Makefile_ndr.mingw +++ b/src/win/Makefile_ndr.mingw @@ -678,6 +678,7 @@ SNDOBJ := sound.o \ snd_pssj.o \ snd_lpt_dac.o snd_lpt_dss.o \ snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ + snd_azt2316a.o \ snd_cms.o \ snd_gus.o \ snd_sb.o snd_sb_dsp.o \