diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index d11ee5df1..9583123b0 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -99,6 +99,9 @@ extern const device_t gus_device; extern const device_t pas16_device; #endif +/* IBM PS/1 Audio Card */ +extern const device_t ps1snd_device; + /* Tandy PSSJ */ extern const device_t pssj_device; extern const device_t pssj_isa_device; diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 4c5c26dbc..7a14ce8a9 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -60,26 +60,10 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/port_6x.h> -#include <86box/sound.h> -#include <86box/snd_sn76489.h> #include <86box/video.h> #include <86box/machine.h> -typedef struct { - sn76489_t sn76489; - uint8_t status, ctrl; - uint64_t timer_latch; - pc_timer_t timer_count; - int timer_enable; - uint8_t fifo[2048]; - int fifo_read_idx, fifo_write_idx; - int fifo_threshold; - uint8_t dac_val; - int16_t buffer[SOUNDBUFLEN]; - int pos; -} ps1snd_t; - typedef struct { int model; @@ -100,178 +84,6 @@ typedef struct { } ps1_t; -static void -update_irq_status(ps1snd_t *snd) -{ - if (((snd->status & snd->ctrl) & 0x12) && (snd->ctrl & 0x01)) - picint(1 << 7); - else - picintc(1 << 7); -} - - -static uint8_t -snd_read(uint16_t port, void *priv) -{ - ps1snd_t *snd = (ps1snd_t *)priv; - uint8_t ret = 0xff; - - switch (port & 7) { - case 0: /* ADC data */ - snd->status &= ~0x10; - update_irq_status(snd); - ret = 0; - break; - - case 2: /* status */ - ret = snd->status; - ret |= (snd->ctrl & 0x01); - if ((snd->fifo_write_idx - snd->fifo_read_idx) >= 2048) - ret |= 0x08; /* FIFO full */ - if (snd->fifo_read_idx == snd->fifo_write_idx) - ret |= 0x04; /* FIFO empty */ - break; - - case 3: /* FIFO timer */ - /* - * The PS/1 Technical Reference says this should return - * thecurrent value, but the PS/1 BIOS and Stunt Island - * expect it not to change. - */ - ret = snd->timer_latch; - break; - - case 4: - case 5: - case 6: - case 7: - ret = 0; - } - - return(ret); -} - - -static void -snd_write(uint16_t port, uint8_t val, void *priv) -{ - ps1snd_t *snd = (ps1snd_t *)priv; - - switch (port & 7) { - case 0: /* DAC output */ - if ((snd->fifo_write_idx - snd->fifo_read_idx) < 2048) { - snd->fifo[snd->fifo_write_idx & 2047] = val; - snd->fifo_write_idx++; - } - break; - - case 2: /* control */ - snd->ctrl = val; - if (! (val & 0x02)) - snd->status &= ~0x02; - update_irq_status(snd); - break; - - case 3: /* timer reload value */ - snd->timer_latch = val; - if (val) - timer_set_delay_u64(&snd->timer_count, ((0xff-val) * TIMER_USEC)); - else - timer_disable(&snd->timer_count); - break; - - case 4: /* almost empty */ - snd->fifo_threshold = val * 4; - break; - } -} - - -static void -snd_update(ps1snd_t *snd) -{ - for (; snd->pos < sound_pos_global; snd->pos++) - snd->buffer[snd->pos] = (int8_t)(snd->dac_val ^ 0x80) * 0x20; -} - - -static void -snd_callback(void *priv) -{ - ps1snd_t *snd = (ps1snd_t *)priv; - - snd_update(snd); - - if (snd->fifo_read_idx != snd->fifo_write_idx) { - snd->dac_val = snd->fifo[snd->fifo_read_idx & 2047]; - snd->fifo_read_idx++; - } - - if ((snd->fifo_write_idx - snd->fifo_read_idx) == snd->fifo_threshold) - snd->status |= 0x02; /*FIFO almost empty*/ - - snd->status |= 0x10; /*ADC data ready*/ - update_irq_status(snd); - - timer_advance_u64(&snd->timer_count, snd->timer_latch * TIMER_USEC); -} - - -static void -snd_get_buffer(int32_t *buffer, int len, void *priv) -{ - ps1snd_t *snd = (ps1snd_t *)priv; - int c; - - snd_update(snd); - - for (c = 0; c < len * 2; c++) - buffer[c] += snd->buffer[c >> 1]; - - snd->pos = 0; -} - - -static void * -snd_init(const device_t *info) -{ - ps1snd_t *snd; - - snd = malloc(sizeof(ps1snd_t)); - memset(snd, 0x00, sizeof(ps1snd_t)); - - sn76489_init(&snd->sn76489, 0x0205, 0x0001, SN76496, 4000000); - - io_sethandler(0x0200, 1, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); - io_sethandler(0x0202, 6, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); - - timer_add(&snd->timer_count, snd_callback, snd, 0); - - sound_add_handler(snd_get_buffer, snd); - - return(snd); -} - - -static void -snd_close(void *priv) -{ - ps1snd_t *snd = (ps1snd_t *)priv; - - free(snd); -} - - -static const device_t snd_device = { - "PS/1 Audio Card", - 0, 0, - snd_init, snd_close, NULL, - { NULL }, - NULL, - NULL -}; - - static void recalc_memory(ps1_t *ps) { @@ -470,7 +282,7 @@ ps1_setup(int model) lpt2_remove(); - device_add(&snd_device); + device_add(&ps1snd_device); device_add(&fdc_at_ps1_device); @@ -499,7 +311,7 @@ ps1_setup(int model) device_add(&ide_isa_device); - device_add(&snd_device); + device_add(&ps1snd_device); } } diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index e3420ac01..e6c03e7ab 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -15,7 +15,7 @@ add_library(snd OBJECT sound.c openal.c snd_opl.c snd_opl_nuked.c snd_resid.cc midi.c midi_rtmidi.cpp snd_speaker.c snd_pssj.c snd_lpt_dac.c snd_ac97_codec.c snd_ac97_via.c - snd_lpt_dss.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c + snd_lpt_dss.c snd_ps1.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c snd_azt2316a.c snd_cms.c snd_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) diff --git a/src/sound/snd_ps1.c b/src/sound/snd_ps1.c new file mode 100644 index 000000000..d5c6aebf8 --- /dev/null +++ b/src/sound/snd_ps1.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/sound.h> +#include <86box/snd_sn76489.h> + + +typedef struct { + sn76489_t sn76489; + uint8_t status, ctrl; + uint64_t timer_latch; + pc_timer_t timer_count; + int timer_enable; + uint8_t fifo[2048]; + int fifo_read_idx, fifo_write_idx; + int fifo_threshold; + uint8_t dac_val; + int16_t buffer[SOUNDBUFLEN]; + int pos; +} ps1snd_t; + + +static void +ps1snd_update_irq_status(ps1snd_t *snd) +{ + if (((snd->status & snd->ctrl) & 0x12) && (snd->ctrl & 0x01)) + picint(1 << 7); + else + picintc(1 << 7); +} + + +static uint8_t +ps1snd_read(uint16_t port, void *priv) +{ + ps1snd_t *ps1snd = (ps1snd_t *)priv; + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: /* ADC data */ + ps1snd->status &= ~0x10; + ps1snd_update_irq_status(ps1snd); + ret = 0; + break; + + case 2: /* status */ + ret = ps1snd->status; + ret |= (ps1snd->ctrl & 0x01); + if ((ps1snd->fifo_write_idx - ps1snd->fifo_read_idx) >= 2048) + ret |= 0x08; /* FIFO full */ + if (ps1snd->fifo_read_idx == ps1snd->fifo_write_idx) + ret |= 0x04; /* FIFO empty */ + break; + + case 3: /* FIFO timer */ + /* + * The PS/1 Technical Reference says this should return + * thecurrent value, but the PS/1 BIOS and Stunt Island + * expect it not to change. + */ + ret = ps1snd->timer_latch; + break; + + case 4: + case 5: + case 6: + case 7: + ret = 0; + } + + return(ret); +} + + +static void +ps1snd_write(uint16_t port, uint8_t val, void *priv) +{ + ps1snd_t *ps1snd = (ps1snd_t *)priv; + + switch (port & 7) { + case 0: /* DAC output */ + if ((ps1snd->fifo_write_idx - ps1snd->fifo_read_idx) < 2048) { + ps1snd->fifo[ps1snd->fifo_write_idx & 2047] = val; + ps1snd->fifo_write_idx++; + } + break; + + case 2: /* control */ + ps1snd->ctrl = val; + if (! (val & 0x02)) + ps1snd->status &= ~0x02; + ps1snd_update_irq_status(ps1snd); + break; + + case 3: /* timer reload value */ + ps1snd->timer_latch = val; + if (val) + timer_set_delay_u64(&ps1snd->timer_count, ((0xff-val) * TIMER_USEC)); + else + timer_disable(&ps1snd->timer_count); + break; + + case 4: /* almost empty */ + ps1snd->fifo_threshold = val * 4; + break; + } +} + + +static void +ps1snd_update(ps1snd_t *ps1snd) +{ + for (; ps1snd->pos < sound_pos_global; ps1snd->pos++) + ps1snd->buffer[ps1snd->pos] = (int8_t)(ps1snd->dac_val ^ 0x80) * 0x20; +} + + +static void +ps1snd_callback(void *priv) +{ + ps1snd_t *ps1snd = (ps1snd_t *)priv; + + ps1snd_update(ps1snd); + + if (ps1snd->fifo_read_idx != ps1snd->fifo_write_idx) { + ps1snd->dac_val = ps1snd->fifo[ps1snd->fifo_read_idx & 2047]; + ps1snd->fifo_read_idx++; + } + + if ((ps1snd->fifo_write_idx - ps1snd->fifo_read_idx) == ps1snd->fifo_threshold) + ps1snd->status |= 0x02; /*FIFO almost empty*/ + + ps1snd->status |= 0x10; /*ADC data ready*/ + ps1snd_update_irq_status(ps1snd); + + timer_advance_u64(&ps1snd->timer_count, ps1snd->timer_latch * TIMER_USEC); +} + + +static void +ps1snd_get_buffer(int32_t *buffer, int len, void *priv) +{ + ps1snd_t *ps1snd = (ps1snd_t *)priv; + int c; + + ps1_snd_update(ps1snd); + + for (c = 0; c < len * 2; c++) + buffer[c] += ps1snd->buffer[c >> 1]; + + ps1snd->pos = 0; +} + + +static void * +ps1snd_init(const device_t *info) +{ + ps1snd_t *ps1snd = malloc(sizeof(ps1snd_t)); + memset(ps1snd, 0x00, sizeof(ps1snd_t)); + + sn76489_init(&ps1snd->sn76489, 0x0205, 0x0001, SN76496, 4000000); + + io_sethandler(0x0200, 1, ps1snd_read,NULL,NULL, ps1snd_write,NULL,NULL, ps1snd); + io_sethandler(0x0202, 6, ps1snd_read,NULL,NULL, ps1snd_write,NULL,NULL, ps1snd); + + timer_add(&ps1snd->timer_count, ps1snd_callback, ps1snd, 0); + + sound_add_handler(ps1snd_get_buffer, ps1snd); + + return(ps1snd); +} + + +static void +ps1snd_close(void *priv) +{ + ps1snd_t *ps1snd = (ps1snd_t *)priv; + + free(ps1snd); +} + + +static const device_t ps1snd_device = { + "IBM PS/1 Audio Card", + 0, + 0, + ps1snd_init, ps1snd_close, + NULL, + { NULL }, + NULL + NULL +}; diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 303e13961..61f79c8dd 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -620,6 +620,7 @@ SNDOBJ := sound.o \ midi.o midi_rtmidi.o \ snd_speaker.o \ snd_pssj.o \ + snd_ps1.o \ snd_lpt_dac.o snd_lpt_dss.o \ snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ snd_ac97_codec.o snd_ac97_via.o \