Commit 423d65f4f9120b7e545ec209398033927373de1d

Authored by balrog
1 parent a8981dda

Gravis Ultrasound GF1 sound card emulation (malc).


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3921 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -421,6 +421,9 @@ endif
421 421 ifdef CONFIG_ADLIB
422 422 SOUND_HW += fmopl.o adlib.o
423 423 endif
  424 +ifdef CONFIG_GUS
  425 +SOUND_HW += gus.o gusemu_hal.o gusemu_mixer.o
  426 +endif
424 427  
425 428 ifdef CONFIG_VNC_TLS
426 429 CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
... ...
configure
... ... @@ -86,6 +86,7 @@ gdbstub="yes"
86 86 slirp="yes"
87 87 adlib="no"
88 88 ac97="no"
  89 +gus="no"
89 90 oss="no"
90 91 dsound="no"
91 92 coreaudio="no"
... ... @@ -283,6 +284,8 @@ for opt do
283 284 ;;
284 285 --enable-ac97) ac97="yes"
285 286 ;;
  287 + --enable-gus) gus="yes"
  288 + ;;
286 289 --disable-kqemu) kqemu="no"
287 290 ;;
288 291 --enable-profiler) profiler="yes"
... ... @@ -410,6 +413,7 @@ echo " --enable-cocoa enable COCOA (Mac OS X only)"
410 413 echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
411 414 echo " --enable-adlib enable Adlib emulation"
412 415 echo " --enable-ac97 enable AC97 emulation"
  416 +echo " --enable-gus enable Gravis Ultrasound emulation"
413 417 echo " --enable-coreaudio enable Coreaudio audio driver"
414 418 echo " --enable-alsa enable ALSA audio driver"
415 419 echo " --enable-esd enable EsoundD audio driver"
... ... @@ -724,6 +728,7 @@ fi
724 728 echo "mingw32 support $mingw32"
725 729 echo "Adlib support $adlib"
726 730 echo "AC97 support $ac97"
  731 +echo "GUS support $gus"
727 732 echo "CoreAudio support $coreaudio"
728 733 echo "ALSA support $alsa"
729 734 echo "EsounD support $esd"
... ... @@ -904,6 +909,10 @@ if test "$ac97" = "yes" ; then
904 909 echo "CONFIG_AC97=yes" >> $config_mak
905 910 echo "#define CONFIG_AC97 1" >> $config_h
906 911 fi
  912 +if test "$gus" = "yes" ; then
  913 + echo "CONFIG_GUS=yes" >> $config_mak
  914 + echo "#define CONFIG_GUS 1" >> $config_h
  915 +fi
907 916 if test "$oss" = "yes" ; then
908 917 echo "CONFIG_OSS=yes" >> $config_mak
909 918 echo "#define CONFIG_OSS 1" >> $config_h
... ...
hw/gus.c 0 → 100644
  1 +/*
  2 + * QEMU Proxy for Gravis Ultrasound GF1 emulation by Tibor "TS" Schütz
  3 + *
  4 + * Copyright (c) 2002-2005 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include "hw.h"
  25 +#include "audiodev.h"
  26 +#include "audio/audio.h"
  27 +#include "isa.h"
  28 +#include "gusemu.h"
  29 +#include "gustate.h"
  30 +
  31 +#define dolog(...) AUD_log ("audio", __VA_ARGS__)
  32 +#ifdef DEBUG
  33 +#define ldebug(...) dolog (__VA_ARGS__)
  34 +#else
  35 +#define ldebug(...)
  36 +#endif
  37 +
  38 +#ifdef WORDS_BIGENDIAN
  39 +#define GUS_ENDIANNESS 1
  40 +#else
  41 +#define GUS_ENDIANNESS 0
  42 +#endif
  43 +
  44 +#define IO_READ_PROTO(name) \
  45 + uint32_t name (void *opaque, uint32_t nport)
  46 +#define IO_WRITE_PROTO(name) \
  47 + void name (void *opaque, uint32_t nport, uint32_t val)
  48 +
  49 +static struct {
  50 + int port;
  51 + int irq;
  52 + int dma;
  53 + int freq;
  54 +} conf = {0x240, 7, 3, 44100};
  55 +
  56 +typedef struct GUSState {
  57 + GUSEmuState emu;
  58 + QEMUSoundCard card;
  59 + int freq;
  60 + int pos, left, shift, irqs;
  61 + uint16_t *mixbuf;
  62 + uint8_t himem[1024 * 1024 + 32 + 4096];
  63 + int samples;
  64 + SWVoiceOut *voice;
  65 + int64_t last_ticks;
  66 + qemu_irq *pic;
  67 +} GUSState;
  68 +
  69 +IO_READ_PROTO (gus_readb)
  70 +{
  71 + GUSState *s = opaque;
  72 +
  73 + return gus_read (&s->emu, nport, 1);
  74 +}
  75 +
  76 +IO_READ_PROTO (gus_readw)
  77 +{
  78 + GUSState *s = opaque;
  79 +
  80 + return gus_read (&s->emu, nport, 2);
  81 +}
  82 +
  83 +IO_WRITE_PROTO (gus_writeb)
  84 +{
  85 + GUSState *s = opaque;
  86 +
  87 + gus_write (&s->emu, nport, 1, val);
  88 +}
  89 +
  90 +IO_WRITE_PROTO (gus_writew)
  91 +{
  92 + GUSState *s = opaque;
  93 +
  94 + gus_write (&s->emu, nport, 2, val);
  95 +}
  96 +
  97 +static int write_audio (GUSState *s, int samples)
  98 +{
  99 + int net = 0;
  100 + int pos = s->pos;
  101 +
  102 + while (samples) {
  103 + int nbytes, wbytes, wsampl;
  104 +
  105 + nbytes = samples << s->shift;
  106 + wbytes = AUD_write (
  107 + s->voice,
  108 + s->mixbuf + (pos << (s->shift - 1)),
  109 + nbytes
  110 + );
  111 +
  112 + if (wbytes) {
  113 + wsampl = wbytes >> s->shift;
  114 +
  115 + samples -= wsampl;
  116 + pos = (pos + wsampl) % s->samples;
  117 +
  118 + net += wsampl;
  119 + }
  120 + else {
  121 + break;
  122 + }
  123 + }
  124 +
  125 + return net;
  126 +}
  127 +
  128 +static void GUS_callback (void *opaque, int free)
  129 +{
  130 + int samples, to_play, net = 0;
  131 + GUSState *s = opaque;
  132 +
  133 + samples = free >> s->shift;
  134 + to_play = audio_MIN (samples, s->left);
  135 +
  136 + while (to_play) {
  137 + int written = write_audio (s, to_play);
  138 +
  139 + if (!written) {
  140 + goto reset;
  141 + }
  142 +
  143 + s->left -= written;
  144 + to_play -= written;
  145 + samples -= written;
  146 + net += written;
  147 + }
  148 +
  149 + samples = audio_MIN (samples, s->samples);
  150 + if (samples) {
  151 + gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
  152 +
  153 + while (samples) {
  154 + int written = write_audio (s, samples);
  155 + if (!written) {
  156 + break;
  157 + }
  158 + samples -= written;
  159 + net += written;
  160 + }
  161 + }
  162 + s->left = samples;
  163 +
  164 +reset:
  165 + gus_irqgen (&s->emu, (double) (net * 1000000) / s->freq);
  166 +}
  167 +
  168 +int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n)
  169 +{
  170 + GUSState *s = emu->opaque;
  171 + /* qemu_irq_lower (s->pic[hwirq]); */
  172 + qemu_irq_raise (s->pic[hwirq]);
  173 + s->irqs += n;
  174 + ldebug ("irqrequest %d %d %d\n", hwirq, n, s->irqs);
  175 + return n;
  176 +}
  177 +
  178 +void GUS_irqclear (GUSEmuState *emu, int hwirq)
  179 +{
  180 + GUSState *s = emu->opaque;
  181 + ldebug ("irqclear %d %d\n", hwirq, s->irqs);
  182 + qemu_irq_lower (s->pic[hwirq]);
  183 + s->irqs -= 1;
  184 +#ifdef IRQ_STORM
  185 + if (s->irqs > 0) {
  186 + qemu_irq_raise (s->pic[hwirq]);
  187 + }
  188 +#endif
  189 +}
  190 +
  191 +void GUS_dmarequest (GUSEmuState *der)
  192 +{
  193 + /* GUSState *s = (GUSState *) der; */
  194 + ldebug ("dma request %d\n", der->gusdma);
  195 + DMA_hold_DREQ (der->gusdma);
  196 +}
  197 +
  198 +int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
  199 +{
  200 + GUSState *s = opaque;
  201 + int8_t tmpbuf[4096];
  202 + int pos = dma_pos, mode, left = dma_len - dma_pos;
  203 +
  204 + ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
  205 + mode = DMA_get_channel_mode (s->emu.gusdma);
  206 + while (left) {
  207 + int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf));
  208 + int copied;
  209 +
  210 + ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
  211 + copied = DMA_read_memory (nchan, tmpbuf, pos, to_copy);
  212 + gus_dma_transferdata (&s->emu, tmpbuf, copied, left == copied);
  213 + left -= copied;
  214 + pos += copied;
  215 + }
  216 +
  217 + if (0 == ((mode >> 4) & 1)) {
  218 + DMA_release_DREQ (s->emu.gusdma);
  219 + }
  220 + return dma_len;
  221 +}
  222 +
  223 +int GUS_init (AudioState *audio, qemu_irq *pic)
  224 +{
  225 + GUSState *s;
  226 + audsettings_t as;
  227 +
  228 + if (!audio) {
  229 + dolog ("No audio state\n");
  230 + return -1;
  231 + }
  232 +
  233 + s = qemu_mallocz (sizeof (*s));
  234 + if (!s) {
  235 + dolog ("Could not allocate memory for GUS (%zu bytes)\n",
  236 + sizeof (*s));
  237 + return -1;
  238 + }
  239 +
  240 + AUD_register_card (audio, "gus", &s->card);
  241 +
  242 + as.freq = conf.freq;
  243 + as.nchannels = 2;
  244 + as.fmt = AUD_FMT_S16;
  245 + as.endianness = GUS_ENDIANNESS;
  246 +
  247 + s->voice = AUD_open_out (
  248 + &s->card,
  249 + NULL,
  250 + "gus",
  251 + s,
  252 + GUS_callback,
  253 + &as
  254 + );
  255 +
  256 + if (!s->voice) {
  257 + AUD_remove_card (&s->card);
  258 + qemu_free (s);
  259 + return -1;
  260 + }
  261 +
  262 + s->shift = 2;
  263 + s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
  264 + s->mixbuf = qemu_mallocz (s->samples << s->shift);
  265 + if (!s->mixbuf) {
  266 + AUD_close_out (&s->card, s->voice);
  267 + AUD_remove_card (&s->card);
  268 + qemu_free (s);
  269 + return -1;
  270 + }
  271 +
  272 + register_ioport_write (conf.port, 1, 1, gus_writeb, s);
  273 + register_ioport_write (conf.port, 1, 2, gus_writew, s);
  274 +
  275 + register_ioport_read ((conf.port + 0x100) & 0xf00, 1, 1, gus_readb, s);
  276 + register_ioport_read ((conf.port + 0x100) & 0xf00, 1, 2, gus_readw, s);
  277 +
  278 + register_ioport_write (conf.port + 6, 10, 1, gus_writeb, s);
  279 + register_ioport_write (conf.port + 6, 10, 2, gus_writew, s);
  280 + register_ioport_read (conf.port + 6, 10, 1, gus_readb, s);
  281 + register_ioport_read (conf.port + 6, 10, 2, gus_readw, s);
  282 +
  283 +
  284 + register_ioport_write (conf.port + 0x100, 8, 1, gus_writeb, s);
  285 + register_ioport_write (conf.port + 0x100, 8, 2, gus_writew, s);
  286 + register_ioport_read (conf.port + 0x100, 8, 1, gus_readb, s);
  287 + register_ioport_read (conf.port + 0x100, 8, 2, gus_readw, s);
  288 +
  289 + DMA_register_channel (conf.dma, GUS_read_DMA, s);
  290 + s->emu.gusirq = conf.irq;
  291 + s->emu.gusdma = conf.dma;
  292 + s->emu.himemaddr = s->himem;
  293 + s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32;
  294 + s->emu.opaque = s;
  295 + s->freq = conf.freq;
  296 + s->pic = pic;
  297 +
  298 + AUD_set_active_out (s->voice, 1);
  299 + return 0;
  300 +}
... ...
hw/gusemu.h 0 → 100644
  1 +/*
  2 + * GUSEMU32 - API
  3 + *
  4 + * Copyright (C) 2000-2007 Tibor "TS" Schütz
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +#ifndef GUSEMU_H
  26 +#define GUSEMU_H
  27 +
  28 +/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */
  29 +
  30 +#if defined _WIN32 && defined _MSC_VER /* doesnt support other win32 compilers yet, do it yourself... */
  31 + typedef unsigned char GUSbyte;
  32 + typedef unsigned short GUSword;
  33 + typedef unsigned int GUSdword;
  34 + typedef signed char GUSchar;
  35 +#else
  36 + #include <stdint.h>
  37 + typedef int8_t GUSchar;
  38 + typedef uint8_t GUSbyte;
  39 + typedef uint16_t GUSword;
  40 + typedef uint32_t GUSdword;
  41 +#endif
  42 +
  43 +typedef struct _GUSEmuState
  44 +{
  45 + GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
  46 + GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
  47 + int gusirq;
  48 + int gusdma;
  49 + unsigned int timer1fraction;
  50 + unsigned int timer2fraction;
  51 + void *opaque;
  52 +} GUSEmuState;
  53 +
  54 +/* ** Callback functions needed: */
  55 +/* NMI is defined as hwirq=-1 (not supported (yet?)) */
  56 +/* GUS_irqrequest returns the number of IRQs actually scheduled into the virtual machine */
  57 +/* Level triggered IRQ simulations normally return 1 */
  58 +/* Event triggered IRQ simulation can safely ignore GUS_irqclear calls */
  59 +int GUS_irqrequest(GUSEmuState *state, int hwirq, int num);/* needed in both mixer and bus emulation functions. */
  60 +void GUS_irqclear( GUSEmuState *state, int hwirq); /* used by gus_write() only - can be left empty for mixer functions */
  61 +void GUS_dmarequest(GUSEmuState *state); /* used by gus_write() only - can be left empty for mixer functions */
  62 +
  63 +/* ** ISA bus interface functions: */
  64 +
  65 +/* Port I/O handlers */
  66 +/* support the following ports: */
  67 +/* 2x0,2x6,2x8...2xF,3x0...3x7; */
  68 +/* optional: 388,389 (at least writes should be forwarded or some GUS detection algorithms will fail) */
  69 +/* data is passed in host byte order */
  70 +unsigned int gus_read( GUSEmuState *state, int port, int size);
  71 +void gus_write(GUSEmuState *state, int port, int size, unsigned int data);
  72 +/* size is given in bytes (1 for byte, 2 for word) */
  73 +
  74 +/* DMA data transfer function */
  75 +/* data pointed to is passed in native x86 order */
  76 +void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count, int TC);
  77 +/* Called back by GUS_start_DMA as soon as the emulated DMA controller is ready for a transfer to or from GUS */
  78 +/* (might be immediately if the DMA controller was programmed first) */
  79 +/* dma_addr is an already translated address directly pointing to the beginning of the memory block */
  80 +/* do not forget to update DMA states after the call, including the DREQ and TC flags */
  81 +/* it is possible to break down a single transfer into multiple ones, but take care that: */
  82 +/* -dma_count is actually count-1 */
  83 +/* -before and during a transfer, DREQ is set and TC cleared */
  84 +/* -when calling gus_dma_transferdata(), TC is only set true for call transfering the last byte */
  85 +/* -after the last transfer, DREQ is cleared and TC is set */
  86 +
  87 +/* ** GF1 mixer emulation functions: */
  88 +/* Usually, gus_irqgen should be called directly after gus_mixvoices if you can meet the recommended ranges. */
  89 +/* If the interrupts are executed immediately (i.e., are synchronous), it may be useful to break this */
  90 +/* down into a sequence of gus_mixvoice();gus_irqgen(); calls while mixing an audio block. */
  91 +/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */
  92 +/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */
  93 +
  94 +void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, short *bufferpos);
  95 +/* recommended range: 10 < numsamples < 100 */
  96 +/* lower values may result in increased rounding error, higher values often cause audible timing delays */
  97 +
  98 +void gus_irqgen(GUSEmuState *state, unsigned int elapsed_time);
  99 +/* recommended range: 80us < elapsed_time < max(1000us, numsamples/playback_freq) */
  100 +/* lower values won´t provide any benefit at all, higher values can cause audible timing delays */
  101 +/* note: masked timers are also calculated by this function, thus it might be needed even without any IRQs in use! */
  102 +
  103 +#endif /* gusemu.h */
... ...
hw/gusemu_hal.c 0 → 100644
  1 +/*
  2 + * GUSEMU32 - bus interface part
  3 + *
  4 + * Copyright (C) 2000-2007 Tibor "TS" Schütz
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +/*
  26 + * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)?
  27 + */
  28 +
  29 +#include "gustate.h"
  30 +#include "gusemu.h"
  31 +
  32 +#define GUSregb(position) (* (gusptr+(position)))
  33 +#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
  34 +#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
  35 +
  36 +/* size given in bytes */
  37 +unsigned int gus_read(GUSEmuState * state, int port, int size)
  38 +{
  39 + int value_read = 0;
  40 +
  41 + GUSbyte *gusptr;
  42 + gusptr = state->gusdatapos;
  43 + GUSregd(portaccesses)++;
  44 +
  45 + switch (port & 0xff0f)
  46 + {
  47 + /* MixerCtrlReg (read not supported on GUS classic) */
  48 + /* case 0x200: return GUSregb(MixerCtrlReg2x0); */
  49 + case 0x206: /* IRQstatReg / SB2x6IRQ */
  50 + /* adlib/sb bits set in port handlers */
  51 + /* timer/voice bits set in gus_irqgen() */
  52 + /* dma bit set in gus_dma_transferdata */
  53 + /* midi not implemented yet */
  54 + return GUSregb(IRQStatReg2x6);
  55 + /* case 0x308: */ /* AdLib388 */
  56 + case 0x208:
  57 + if (GUSregb(GUS45TimerCtrl) & 1)
  58 + return GUSregb(TimerStatus2x8);
  59 + return GUSregb(AdLibStatus2x8); /* AdLibStatus */
  60 + case 0x309: /* AdLib389 */
  61 + case 0x209:
  62 + return GUSregb(AdLibData2x9); /* AdLibData */
  63 + case 0x20A:
  64 + return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */
  65 +
  66 +#if 0
  67 + case 0x20B: /* GUS hidden registers (read not supported on GUS classic) */
  68 + switch (GUSregb(RegCtrl_2xF) & 0x07)
  69 + {
  70 + case 0: /* IRQ/DMA select */
  71 + if (GUSregb(MixerCtrlReg2x0) & 0x40)
  72 + return GUSregb(IRQ_2xB); /* control register select bit */
  73 + else
  74 + return GUSregb(DMA_2xB);
  75 + /* case 1-5: */ /* general purpose emulation regs */
  76 + /* return ... */ /* + status reset reg (write only) */
  77 + case 6:
  78 + return GUSregb(Jumper_2xB); /* Joystick/MIDI enable (JumperReg) */
  79 + default:;
  80 + }
  81 + break;
  82 +#endif
  83 +
  84 + case 0x20C: /* SB2xCd */
  85 + value_read = GUSregb(SB2xCd);
  86 + if (GUSregb(StatRead_2xF) & 0x20)
  87 + GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */
  88 + return value_read;
  89 + /* case 0x20D: */ /* SB2xD is write only -> 2xE writes to it*/
  90 + case 0x20E:
  91 + if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */
  92 + {
  93 + GUSregb(StatRead_2xF) |= 0x80;
  94 + GUS_irqrequest(state, state->gusirq, 1);
  95 + }
  96 + return GUSregb(SB2xE); /* SB2xE */
  97 + case 0x20F: /* StatRead_2xF */
  98 + /*set/clear fixed bits */
  99 + /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/
  100 + value_read = (GUSregb(StatRead_2xF) & 0xf9);
  101 + if (GUSregb(MixerCtrlReg2x0) & 0x08)
  102 + value_read |= 2; /* DMA/IRQ enabled flag */
  103 + return value_read;
  104 + /* case 0x300: */ /* MIDI (not implemented) */
  105 + /* case 0x301: */ /* MIDI (not implemented) */
  106 + case 0x302:
  107 + return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */
  108 + case 0x303:
  109 + return GUSregb(FunkSelReg3x3); /* FunkSelReg */
  110 + case 0x304: /* DataRegLoByte3x4 + DataRegWord3x4 */
  111 + case 0x305: /* DataRegHiByte3x5 */
  112 + switch (GUSregb(FunkSelReg3x3))
  113 + {
  114 + /* common functions */
  115 + case 0x41: /* DramDMAContrReg */
  116 + value_read = GUSregb(GUS41DMACtrl); /* &0xfb */
  117 + GUSregb(GUS41DMACtrl) &= 0xbb;
  118 + if (state->gusdma >= 4)
  119 + value_read |= 0x04;
  120 + if (GUSregb(IRQStatReg2x6) & 0x80)
  121 + {
  122 + value_read |= 0x40;
  123 + GUSregb(IRQStatReg2x6) &= 0x7f;
  124 + if (!GUSregb(IRQStatReg2x6))
  125 + GUS_irqclear(state, state->gusirq);
  126 + }
  127 + return (GUSbyte) value_read;
  128 + /* DramDMAmemPosReg */
  129 + /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
  130 + /* 43h+44h write only */
  131 + case 0x45:
  132 + return GUSregb(GUS45TimerCtrl); /* TimerCtrlReg */
  133 + /* 46h+47h write only */
  134 + /* 48h: samp freq - write only */
  135 + case 0x49:
  136 + return GUSregb(GUS49SampCtrl) & 0xbf; /* SampCtrlReg */
  137 + /* case 4bh: */ /* joystick trim not supported */
  138 + /* case 0x4c: return GUSregb(GUS4cReset); */ /* GUSreset: write only*/
  139 + /* voice specific functions */
  140 + case 0x80:
  141 + case 0x81:
  142 + case 0x82:
  143 + case 0x83:
  144 + case 0x84:
  145 + case 0x85:
  146 + case 0x86:
  147 + case 0x87:
  148 + case 0x88:
  149 + case 0x89:
  150 + case 0x8a:
  151 + case 0x8b:
  152 + case 0x8c:
  153 + case 0x8d:
  154 + {
  155 + int offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
  156 + offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
  157 + value_read = GUSregw(offset);
  158 + }
  159 + break;
  160 + /* voice unspecific functions */
  161 + case 0x8e: /* NumVoice */
  162 + return GUSregb(NumVoices);
  163 + case 0x8f: /* irqstatreg */
  164 + /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */
  165 + return GUSregb(SynVoiceIRQ8f);
  166 + default:
  167 + return 0xffff;
  168 + }
  169 + if (size == 1)
  170 + {
  171 + if ((port & 0xff0f) == 0x305)
  172 + value_read = value_read >> 8;
  173 + value_read &= 0xff;
  174 + }
  175 + return (GUSword) value_read;
  176 + /* case 0x306: */ /* Mixer/Version info */
  177 + /* return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
  178 + case 0x307: /* DRAMaccess */
  179 + {
  180 + GUSbyte *adr;
  181 + adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
  182 + return *adr;
  183 + }
  184 + default:;
  185 + }
  186 + return 0xffff;
  187 +}
  188 +
  189 +void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
  190 +{
  191 + GUSbyte *gusptr;
  192 + gusptr = state->gusdatapos;
  193 + GUSregd(portaccesses)++;
  194 +
  195 + switch (port & 0xff0f)
  196 + {
  197 + case 0x200: /* MixerCtrlReg */
  198 + GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
  199 + break;
  200 + case 0x206: /* IRQstatReg / SB2x6IRQ */
  201 + if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
  202 + {
  203 + GUSregb(TimerStatus2x8) |= 0x08;
  204 + GUSregb(IRQStatReg2x6) = 0x10;
  205 + GUS_irqrequest(state, state->gusirq, 1);
  206 + }
  207 + break;
  208 + case 0x308: /* AdLib 388h */
  209 + case 0x208: /* AdLibCommandReg */
  210 + GUSregb(AdLibCommand2xA) = (GUSbyte) data;
  211 + break;
  212 + case 0x309: /* AdLib 389h */
  213 + case 0x209: /* AdLibDataReg */
  214 + if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */
  215 + {
  216 + if (data & 0x80)
  217 + GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
  218 + else
  219 + GUSregb(TimerDataReg2x9) = (GUSbyte) data;
  220 + }
  221 + else
  222 + {
  223 + GUSregb(AdLibData2x9) = (GUSbyte) data;
  224 + if (GUSregb(GUS45TimerCtrl) & 0x02)
  225 + {
  226 + GUSregb(TimerStatus2x8) |= 0x01;
  227 + GUSregb(IRQStatReg2x6) = 0x10;
  228 + GUS_irqrequest(state, state->gusirq, 1);
  229 + }
  230 + }
  231 + break;
  232 + case 0x20A:
  233 + GUSregb(AdLibStatus2x8) = (GUSbyte) data;
  234 + break; /* AdLibStatus2x8 */
  235 + case 0x20B: /* GUS hidden registers */
  236 + switch (GUSregb(RegCtrl_2xF) & 0x7)
  237 + {
  238 + case 0:
  239 + if (GUSregb(MixerCtrlReg2x0) & 0x40)
  240 + GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
  241 + else
  242 + GUSregb(DMA_2xB) = (GUSbyte) data;
  243 + break;
  244 + /* case 1-4: general purpose emulation regs */
  245 + case 5: /* clear stat reg 2xF */
  246 + GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */
  247 + if (!GUSregb(IRQStatReg2x6))
  248 + GUS_irqclear(state, state->gusirq);
  249 + break;
  250 + case 6: /* Jumper reg (Joystick/MIDI enable) */
  251 + GUSregb(Jumper_2xB) = (GUSbyte) data;
  252 + break;
  253 + default:;
  254 + }
  255 + break;
  256 + case 0x20C: /* SB2xCd */
  257 + if (GUSregb(GUS45TimerCtrl) & 0x20)
  258 + {
  259 + GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */
  260 + GUSregb(IRQStatReg2x6) = 0x10;
  261 + GUS_irqrequest(state, state->gusirq, 1);
  262 + }
  263 + case 0x20D: /* SB2xCd no IRQ */
  264 + GUSregb(SB2xCd) = (GUSbyte) data;
  265 + break;
  266 + case 0x20E: /* SB2xE */
  267 + GUSregb(SB2xE) = (GUSbyte) data;
  268 + break;
  269 + case 0x20F:
  270 + GUSregb(RegCtrl_2xF) = (GUSbyte) data;
  271 + break; /* CtrlReg2xF */
  272 + case 0x302: /* VoiceSelReg */
  273 + GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
  274 + break;
  275 + case 0x303: /* FunkSelReg */
  276 + GUSregb(FunkSelReg3x3) = (GUSbyte) data;
  277 + if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
  278 + {
  279 + int voice;
  280 + if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
  281 + {
  282 + for (voice = 0; voice < 31; voice++)
  283 + {
  284 + if (GUSregd(voicewavetableirq) & (1 << voice))
  285 + {
  286 + GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */
  287 + GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */
  288 + if (!GUSregd(voicewavetableirq))
  289 + GUSregb(IRQStatReg2x6) &= 0xdf;
  290 + if (!GUSregb(IRQStatReg2x6))
  291 + GUS_irqclear(state, state->gusirq);
  292 + GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */
  293 + return;
  294 + }
  295 + }
  296 + }
  297 + else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */
  298 + {
  299 + for (voice = 0; voice < 31; voice++)
  300 + {
  301 + if (GUSregd(voicevolrampirq) & (1 << voice))
  302 + {
  303 + GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */
  304 + GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */
  305 + if (!GUSregd(voicevolrampirq))
  306 + GUSregb(IRQStatReg2x6) &= 0xbf;
  307 + if (!GUSregb(IRQStatReg2x6))
  308 + GUS_irqclear(state, state->gusirq);
  309 + GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */
  310 + return;
  311 + }
  312 + }
  313 + }
  314 + GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */
  315 + }
  316 + break;
  317 + case 0x304:
  318 + case 0x305:
  319 + {
  320 + GUSword writedata = (GUSword) data;
  321 + GUSword readmask = 0x0000;
  322 + if (size == 1)
  323 + {
  324 + readmask = 0xff00;
  325 + writedata &= 0xff;
  326 + if ((port & 0xff0f) == 0x305)
  327 + {
  328 + writedata = (GUSword) (writedata << 8);
  329 + readmask = 0x00ff;
  330 + }
  331 + }
  332 + switch (GUSregb(FunkSelReg3x3))
  333 + {
  334 + /* voice specific functions */
  335 + case 0x00:
  336 + case 0x01:
  337 + case 0x02:
  338 + case 0x03:
  339 + case 0x04:
  340 + case 0x05:
  341 + case 0x06:
  342 + case 0x07:
  343 + case 0x08:
  344 + case 0x09:
  345 + case 0x0a:
  346 + case 0x0b:
  347 + case 0x0c:
  348 + case 0x0d:
  349 + {
  350 + int offset;
  351 + if (!(GUSregb(GUS4cReset) & 0x01))
  352 + break; /* reset flag active? */
  353 + offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
  354 + offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
  355 + GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
  356 + }
  357 + break;
  358 + /* voice unspecific functions */
  359 + case 0x0e: /* NumVoices */
  360 + GUSregb(NumVoices) = (GUSbyte) data;
  361 + break;
  362 + /* case 0x0f: */ /* read only */
  363 + /* common functions */
  364 + case 0x41: /* DramDMAContrReg */
  365 + GUSregb(GUS41DMACtrl) = (GUSbyte) data;
  366 + if (data & 0x01)
  367 + GUS_dmarequest(state);
  368 + break;
  369 + case 0x42: /* DramDMAmemPosReg */
  370 + GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata;
  371 + GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */
  372 + break;
  373 + case 0x43: /* DRAMaddrLo */
  374 + GUSregd(GUSDRAMPOS24bit) =
  375 + (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata;
  376 + break;
  377 + case 0x44: /* DRAMaddrHi */
  378 + GUSregd(GUSDRAMPOS24bit) =
  379 + (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
  380 + break;
  381 + case 0x45: /* TCtrlReg */
  382 + GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
  383 + if (!(data & 0x20))
  384 + GUSregb(TimerStatus2x8) &= 0xe7; /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
  385 + if (!(data & 0x02))
  386 + GUSregb(TimerStatus2x8) &= 0xfe; /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */
  387 + if (!(GUSregb(TimerStatus2x8) & 0x19))
  388 + GUSregb(IRQStatReg2x6) &= 0xef; /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */
  389 + /* catch up delayed timer IRQs: */
  390 + if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3))
  391 + {
  392 + if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
  393 + {
  394 + if (!(GUSregb(TimerDataReg2x9) & 0x40))
  395 + GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */
  396 + if (data & 4) /* timer1 irq enable */
  397 + {
  398 + GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */
  399 + GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */
  400 + }
  401 + }
  402 + if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */
  403 + {
  404 + if (!(GUSregb(TimerDataReg2x9) & 0x20))
  405 + GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */
  406 + if (data & 8) /* timer2 irq enable */
  407 + {
  408 + GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */
  409 + GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */
  410 + }
  411 + }
  412 + GUSregw(TimerIRQs)--;
  413 + if (GUSregw(BusyTimerIRQs) > 1)
  414 + GUSregw(BusyTimerIRQs)--;
  415 + else
  416 + GUSregw(BusyTimerIRQs) =
  417 + GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs));
  418 + }
  419 + else
  420 + GUSregw(TimerIRQs) = 0;
  421 +
  422 + if (!(data & 0x04))
  423 + {
  424 + GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */
  425 + GUSregb(IRQStatReg2x6) &= 0xfb;
  426 + }
  427 + if (!(data & 0x08))
  428 + {
  429 + GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */
  430 + GUSregb(IRQStatReg2x6) &= 0xf7;
  431 + }
  432 + if (!GUSregb(IRQStatReg2x6))
  433 + GUS_irqclear(state, state->gusirq);
  434 + break;
  435 + case 0x46: /* Counter1 */
  436 + GUSregb(GUS46Counter1) = (GUSbyte) data;
  437 + break;
  438 + case 0x47: /* Counter2 */
  439 + GUSregb(GUS47Counter2) = (GUSbyte) data;
  440 + break;
  441 + /* case 0x48: */ /* sampling freq reg not emulated (same as interwave) */
  442 + case 0x49: /* SampCtrlReg */
  443 + GUSregb(GUS49SampCtrl) = (GUSbyte) data;
  444 + break;
  445 + /* case 0x4b: */ /* joystick trim not emulated */
  446 + case 0x4c: /* GUSreset */
  447 + GUSregb(GUS4cReset) = (GUSbyte) data;
  448 + if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
  449 + {
  450 + GUSregd(voicewavetableirq) = 0;
  451 + GUSregd(voicevolrampirq) = 0;
  452 + GUSregw(TimerIRQs) = 0;
  453 + GUSregw(BusyTimerIRQs) = 0;
  454 + GUSregb(NumVoices) = 0xcd;
  455 + GUSregb(IRQStatReg2x6) = 0;
  456 + GUSregb(TimerStatus2x8) = 0;
  457 + GUSregb(AdLibData2x9) = 0;
  458 + GUSregb(TimerDataReg2x9) = 0;
  459 + GUSregb(GUS41DMACtrl) = 0;
  460 + GUSregb(GUS45TimerCtrl) = 0;
  461 + GUSregb(GUS49SampCtrl) = 0;
  462 + GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */
  463 + GUS_irqclear(state, state->gusirq);
  464 + }
  465 + /* IRQ enable bit checked elsewhere */
  466 + /* EnableDAC bit may be used by external callers */
  467 + break;
  468 + }
  469 + }
  470 + break;
  471 + case 0x307: /* DRAMaccess */
  472 + {
  473 + GUSbyte *adr;
  474 + adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
  475 + *adr = (GUSbyte) data;
  476 + }
  477 + break;
  478 + }
  479 +}
  480 +
  481 +/* Attention when breaking up a single DMA transfer to multiple ones:
  482 + * it may lead to multiple terminal count interrupts and broken transfers:
  483 + *
  484 + * 1. Whenever you transfer a piece of data, the gusemu callback is invoked
  485 + * 2. The callback may generate a TC irq (if the register was set up to do so)
  486 + * 3. The irq may result in the program using the GUS to reprogram the GUS
  487 + *
  488 + * Some programs also decide to upload by just checking if TC occurs
  489 + * (via interrupt or a cleared GUS dma flag)
  490 + * and then start the next transfer, without checking DMA state
  491 + *
  492 + * Thus: Always make sure to set the TC flag correctly!
  493 + *
  494 + * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA
  495 + * while later cards had atomic granularity provided by an additional GUS50DMAHigh register
  496 + * GUSemu also uses this register to support byte-granular transfers for better compatibility
  497 + * with emulators other than GUSemu32
  498 + */
  499 +
  500 +void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC)
  501 +{
  502 + /* this function gets called by the callback function as soon as a DMA transfer is about to start
  503 + * dma_addr is a translated address within accessible memory, not the physical one,
  504 + * count is (real dma count register)+1
  505 + * note that the amount of bytes transfered is fully determined by values in the DMA registers
  506 + * do not forget to update DMA states after transferring the entire block:
  507 + * DREQ cleared & TC asserted after the _whole_ transfer */
  508 +
  509 + char *srcaddr;
  510 + char *destaddr;
  511 + char msbmask = 0;
  512 + GUSbyte *gusptr;
  513 + gusptr = state->gusdatapos;
  514 +
  515 + srcaddr = dma_addr; /* system memory address */
  516 + {
  517 + int offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf);
  518 + if (state->gusdma >= 4)
  519 + offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */
  520 + destaddr = (char *) state->himemaddr + offset; /* wavetable RAM adress */
  521 + }
  522 +
  523 + GUSregw(GUS42DMAStart) += (GUSword) (count >> 4); /* ToDo: add 16bit GUS page limit? */
  524 + GUSregb(GUS50DMAHigh) = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
  525 +
  526 + if (GUSregb(GUS41DMACtrl) & 0x02) /* direction, 0 := sysram->gusram */
  527 + {
  528 + char *tmpaddr = destaddr;
  529 + destaddr = srcaddr;
  530 + srcaddr = tmpaddr;
  531 + }
  532 +
  533 + if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02)))
  534 + msbmask = (const char) 0x80; /* invert MSB */
  535 + for (; count > 0; count--)
  536 + {
  537 + if (GUSregb(GUS41DMACtrl) & 0x40)
  538 + *(destaddr++) = *(srcaddr++); /* 16 bit lobyte */
  539 + else
  540 + *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */
  541 + if (state->gusdma >= 4)
  542 + *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */
  543 + }
  544 +
  545 + if (TC)
  546 + {
  547 + (GUSregb(GUS41DMACtrl)) &= 0xfe; /* clear DMA request bit */
  548 + if (GUSregb(GUS41DMACtrl) & 0x20) /* DMA terminal count IRQ */
  549 + {
  550 + GUSregb(IRQStatReg2x6) |= 0x80;
  551 + GUS_irqrequest(state, state->gusirq, 1);
  552 + }
  553 + }
  554 +}
... ...
hw/gusemu_mixer.c 0 → 100644
  1 +/*
  2 + * GUSEMU32 - mixing engine (similar to Interwave GF1 compatibility)
  3 + *
  4 + * Copyright (C) 2000-2007 Tibor "TS" Schütz
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +#include "gusemu.h"
  26 +#include "gustate.h"
  27 +
  28 +#define GUSregb(position) (* (gusptr+(position)))
  29 +#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
  30 +#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
  31 +
  32 +#define GUSvoice(position) (*(GUSword *)(voiceptr+(position)))
  33 +
  34 +/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */
  35 +void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples,
  36 + short *bufferpos)
  37 +{
  38 + /* note that byte registers are stored in the upper half of each voice register! */
  39 + GUSbyte *gusptr;
  40 + int Voice;
  41 + GUSword *voiceptr;
  42 +
  43 + unsigned int count;
  44 + for (count = 0; count < numsamples * 2; count++)
  45 + *(bufferpos + count) = 0; /* clear */
  46 +
  47 + gusptr = state->gusdatapos;
  48 + voiceptr = (GUSword *) gusptr;
  49 + if (!(GUSregb(GUS4cReset) & 0x01)) /* reset flag active? */
  50 + return;
  51 +
  52 + for (Voice = 0; Voice <= (GUSregb(NumVoices) & 31); Voice++)
  53 + {
  54 + if (GUSvoice(wVSRControl) & 0x200)
  55 + GUSvoice(wVSRControl) |= 0x100; /* voice stop request */
  56 + if (GUSvoice(wVSRVolRampControl) & 0x200)
  57 + GUSvoice(wVSRVolRampControl) |= 0x100; /* Volume ramp stop request */
  58 + if (!(GUSvoice(wVSRControl) & GUSvoice(wVSRVolRampControl) & 0x100)) /* neither voice nor volume calculation active - save some time here ;) */
  59 + {
  60 + unsigned int sample;
  61 +
  62 + unsigned int LoopStart = (GUSvoice(wVSRLoopStartHi) << 16) | GUSvoice(wVSRLoopStartLo); /* 23.9 format */
  63 + unsigned int LoopEnd = (GUSvoice(wVSRLoopEndHi) << 16) | GUSvoice(wVSRLoopEndLo); /* 23.9 format */
  64 + unsigned int CurrPos = (GUSvoice(wVSRCurrPosHi) << 16) | GUSvoice(wVSRCurrPosLo); /* 23.9 format */
  65 + int VoiceIncrement = ((((unsigned long) GUSvoice(wVSRFreq) * 44100) / playback_freq) * (14 >> 1)) /
  66 + ((GUSregb(NumVoices) & 31) + 1); /* 6.10 increment/frame to 23.9 increment/sample */
  67 +
  68 + int PanningPos = (GUSvoice(wVSRPanning) >> 8) & 0xf;
  69 +
  70 + unsigned int Volume32 = 32 * GUSvoice(wVSRCurrVol); /* 32 times larger than original gus for maintaining precision while ramping */
  71 + unsigned int StartVol32 = (GUSvoice(wVSRVolRampStartVol) & 0xff00) * 32;
  72 + unsigned int EndVol32 = (GUSvoice(wVSRVolRampEndVol) & 0xff00) * 32;
  73 + int VolumeIncrement32 = (32 * 16 * (GUSvoice(wVSRVolRampRate) & 0x3f00) >> 8) >> ((((GUSvoice(wVSRVolRampRate) & 0xc000) >> 8) >> 6) * 3); /* including 1/8/64/512 volume speed divisor */
  74 + VolumeIncrement32 = (((VolumeIncrement32 * 44100 / 2) / playback_freq) * 14) / ((GUSregb(NumVoices) & 31) + 1); /* adjust ramping speed to playback speed */
  75 +
  76 + if (GUSvoice(wVSRControl) & 0x4000)
  77 + VoiceIncrement = -VoiceIncrement; /* reverse playback */
  78 + if (GUSvoice(wVSRVolRampControl) & 0x4000)
  79 + VolumeIncrement32 = -VolumeIncrement32; /* reverse ramping */
  80 +
  81 + for (sample = 0; sample < numsamples; sample++)
  82 + {
  83 + int sample1, sample2, Volume;
  84 + if (GUSvoice(wVSRControl) & 0x400) /* 16bit */
  85 + {
  86 + int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1);
  87 + GUSchar *adr;
  88 + adr = (GUSchar *) state->himemaddr + offset;
  89 + sample1 = (*adr & 0xff) + (*(adr + 1) * 256);
  90 + sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256);
  91 + }
  92 + else /* 8bit */
  93 + {
  94 + int offset = (CurrPos >> 9) & 0xfffff;
  95 + GUSchar *adr;
  96 + adr = (GUSchar *) state->himemaddr + offset;
  97 + sample1 = (*adr) * 256;
  98 + sample2 = (*(adr + 1)) * 256;
  99 + }
  100 +
  101 + Volume = ((((Volume32 >> (4 + 5)) & 0xff) + 256) << (Volume32 >> ((4 + 8) + 5))) / 512; /* semi-logarithmic volume, +5 due to additional precision */
  102 + sample1 = (((sample1 * Volume) >> 16) * (512 - (CurrPos % 512))) / 512;
  103 + sample2 = (((sample2 * Volume) >> 16) * (CurrPos % 512)) / 512;
  104 + sample1 += sample2;
  105 +
  106 + if (!(GUSvoice(wVSRVolRampControl) & 0x100))
  107 + {
  108 + Volume32 += VolumeIncrement32;
  109 + if ((GUSvoice(wVSRVolRampControl) & 0x4000) ? (Volume32 <= StartVol32) : (Volume32 >= EndVol32)) /* ramp up boundary cross */
  110 + {
  111 + if (GUSvoice(wVSRVolRampControl) & 0x2000)
  112 + GUSvoice(wVSRVolRampControl) |= 0x8000; /* volramp IRQ enabled? -> IRQ wait flag */
  113 + if (GUSvoice(wVSRVolRampControl) & 0x800) /* loop enabled */
  114 + {
  115 + if (GUSvoice(wVSRVolRampControl) & 0x1000) /* bidir. loop */
  116 + {
  117 + GUSvoice(wVSRVolRampControl) ^= 0x4000; /* toggle dir */
  118 + VolumeIncrement32 = -VolumeIncrement32;
  119 + }
  120 + else
  121 + Volume32 = (GUSvoice(wVSRVolRampControl) & 0x4000) ? EndVol32 : StartVol32; /* unidir. loop ramp */
  122 + }
  123 + else
  124 + {
  125 + GUSvoice(wVSRVolRampControl) |= 0x100;
  126 + Volume32 =
  127 + (GUSvoice(wVSRVolRampControl) & 0x4000) ? StartVol32 : EndVol32;
  128 + }
  129 + }
  130 + }
  131 + if ((GUSvoice(wVSRVolRampControl) & 0xa000) == 0xa000) /* volramp IRQ set and enabled? */
  132 + {
  133 + GUSregd(voicevolrampirq) |= 1 << Voice; /* set irq slot */
  134 + }
  135 + else
  136 + {
  137 + GUSregd(voicevolrampirq) &= (~(1 << Voice)); /* clear irq slot */
  138 + GUSvoice(wVSRVolRampControl) &= 0x7f00;
  139 + }
  140 +
  141 + if (!(GUSvoice(wVSRControl) & 0x100))
  142 + {
  143 + CurrPos += VoiceIncrement;
  144 + if ((GUSvoice(wVSRControl) & 0x4000) ? (CurrPos <= LoopStart) : (CurrPos >= LoopEnd)) /* playback boundary cross */
  145 + {
  146 + if (GUSvoice(wVSRControl) & 0x2000)
  147 + GUSvoice(wVSRControl) |= 0x8000; /* voice IRQ enabled -> IRQ wait flag */
  148 + if (GUSvoice(wVSRControl) & 0x800) /* loop enabled */
  149 + {
  150 + if (GUSvoice(wVSRControl) & 0x1000) /* pingpong loop */
  151 + {
  152 + GUSvoice(wVSRControl) ^= 0x4000; /* toggle dir */
  153 + VoiceIncrement = -VoiceIncrement;
  154 + }
  155 + else
  156 + CurrPos = (GUSvoice(wVSRControl) & 0x4000) ? LoopEnd : LoopStart; /* unidir. loop */
  157 + }
  158 + else if (!(GUSvoice(wVSRVolRampControl) & 0x400))
  159 + GUSvoice(wVSRControl) |= 0x100; /* loop disabled, rollover check */
  160 + }
  161 + }
  162 + if ((GUSvoice(wVSRControl) & 0xa000) == 0xa000) /* wavetable IRQ set and enabled? */
  163 + {
  164 + GUSregd(voicewavetableirq) |= 1 << Voice; /* set irq slot */
  165 + }
  166 + else
  167 + {
  168 + GUSregd(voicewavetableirq) &= (~(1 << Voice)); /* clear irq slot */
  169 + GUSvoice(wVSRControl) &= 0x7f00;
  170 + }
  171 +
  172 + /* mix samples into buffer */
  173 + *(bufferpos + 2 * sample) += (short) ((sample1 * PanningPos) >> 4); /* right */
  174 + *(bufferpos + 2 * sample + 1) += (short) ((sample1 * (15 - PanningPos)) >> 4); /* left */
  175 + }
  176 + /* write back voice and volume */
  177 + GUSvoice(wVSRCurrVol) = Volume32 / 32;
  178 + GUSvoice(wVSRCurrPosHi) = CurrPos >> 16;
  179 + GUSvoice(wVSRCurrPosLo) = CurrPos & 0xffff;
  180 + }
  181 + voiceptr += 16; /* next voice */
  182 + }
  183 +}
  184 +
  185 +void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time)
  186 +/* time given in microseconds */
  187 +{
  188 + int requestedIRQs = 0;
  189 + GUSbyte *gusptr;
  190 + gusptr = state->gusdatapos;
  191 + if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
  192 + {
  193 + unsigned int timer1fraction = state->timer1fraction;
  194 + int newtimerirqs;
  195 + newtimerirqs = (elapsed_time + timer1fraction) / (80 * (256 - GUSregb(GUS46Counter1)));
  196 + state->timer1fraction = (elapsed_time + timer1fraction) % (80 * (256 - GUSregb(GUS46Counter1)));
  197 + if (newtimerirqs)
  198 + {
  199 + if (!(GUSregb(TimerDataReg2x9) & 0x40))
  200 + GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */
  201 + if (GUSregb(GUS45TimerCtrl) & 4) /* timer1 irq enable */
  202 + {
  203 + GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */
  204 + GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */
  205 + GUSregw(TimerIRQs) += newtimerirqs;
  206 + requestedIRQs += newtimerirqs;
  207 + }
  208 + }
  209 + }
  210 + if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */
  211 + {
  212 + unsigned int timer2fraction = state->timer2fraction;
  213 + int newtimerirqs;
  214 + newtimerirqs = (elapsed_time + timer2fraction) / (320 * (256 - GUSregb(GUS47Counter2)));
  215 + state->timer2fraction = (elapsed_time + timer2fraction) % (320 * (256 - GUSregb(GUS47Counter2)));
  216 + if (newtimerirqs)
  217 + {
  218 + if (!(GUSregb(TimerDataReg2x9) & 0x20))
  219 + GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */
  220 + if (GUSregb(GUS45TimerCtrl) & 8) /* timer2 irq enable */
  221 + {
  222 + GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */
  223 + GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */
  224 + GUSregw(TimerIRQs) += newtimerirqs;
  225 + requestedIRQs += newtimerirqs;
  226 + }
  227 + }
  228 + }
  229 + if (GUSregb(GUS4cReset) & 0x4) /* synth IRQ enable */
  230 + {
  231 + if (GUSregd(voicewavetableirq))
  232 + GUSregb(IRQStatReg2x6) |= 0x20;
  233 + if (GUSregd(voicevolrampirq))
  234 + GUSregb(IRQStatReg2x6) |= 0x40;
  235 + }
  236 + if ((!requestedIRQs) && GUSregb(IRQStatReg2x6))
  237 + requestedIRQs++;
  238 + if (GUSregb(IRQStatReg2x6))
  239 + GUSregw(BusyTimerIRQs) = GUS_irqrequest(state, state->gusirq, requestedIRQs);
  240 +}
... ...
hw/gustate.h 0 → 100644
  1 +/*
  2 + * GUSEMU32 - persistent GUS register state
  3 + *
  4 + * Copyright (C) 2000-2007 Tibor "TS" Schütz
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +#ifndef GUSTATE_H
  26 +#define GUSTATE_H
  27 +
  28 +/*state block offset*/
  29 +#define gusdata (0)
  30 +
  31 +/* data stored using this structure is in host byte order! */
  32 +
  33 +/*access type*/
  34 +#define PortRead (0)
  35 +#define PortWrite (1)
  36 +
  37 +#define Port8Bitacc (0)
  38 +#define Port16Bitacc (1)
  39 +
  40 +/*voice register offsets (in bytes)*/
  41 +#define VSRegs (0)
  42 +#define VSRControl (0)
  43 +#define VSRegsEnd (VSRControl+VSRegs + 32*(16*2))
  44 +#define VSRFreq (2)
  45 +#define VSRLoopStartHi (4)
  46 +#define VSRLoopStartLo (6)
  47 +#define VSRLoopEndHi (8)
  48 +#define VSRLoopEndLo (10)
  49 +#define VSRVolRampRate (12)
  50 +#define VSRVolRampStartVol (14)
  51 +#define VSRVolRampEndVol (16)
  52 +#define VSRCurrVol (18)
  53 +#define VSRCurrPosHi (20)
  54 +#define VSRCurrPosLo (22)
  55 +#define VSRPanning (24)
  56 +#define VSRVolRampControl (26)
  57 +
  58 +/*voice register offsets (in words)*/
  59 +#define wVSRegs (0)
  60 +#define wVSRControl (0)
  61 +#define wVSRegsEnd (wVSRControl+wVSRegs + 32*(16))
  62 +#define wVSRFreq (1)
  63 +#define wVSRLoopStartHi (2)
  64 +#define wVSRLoopStartLo (3)
  65 +#define wVSRLoopEndHi (4)
  66 +#define wVSRLoopEndLo (5)
  67 +#define wVSRVolRampRate (6)
  68 +#define wVSRVolRampStartVol (7)
  69 +#define wVSRVolRampEndVol (8)
  70 +#define wVSRCurrVol (9)
  71 +#define wVSRCurrPosHi (10)
  72 +#define wVSRCurrPosLo (11)
  73 +#define wVSRPanning (12)
  74 +#define wVSRVolRampControl (13)
  75 +
  76 +/*GUS register state block: 32 voices, padding filled with remaining registers*/
  77 +#define DataRegLoByte3x4 (VSRVolRampControl+2)
  78 +#define DataRegWord3x4 (DataRegLoByte3x4)
  79 +#define DataRegHiByte3x5 (VSRVolRampControl+2 +1)
  80 +#define DMA_2xB (VSRVolRampControl+2+2)
  81 +#define IRQ_2xB (VSRVolRampControl+2+3)
  82 +
  83 +#define RegCtrl_2xF (VSRVolRampControl+2+(16*2))
  84 +#define Jumper_2xB (VSRVolRampControl+2+(16*2)+1)
  85 +#define GUS42DMAStart (VSRVolRampControl+2+(16*2)+2)
  86 +
  87 +#define GUS43DRAMIOlo (VSRVolRampControl+2+(16*2)*2)
  88 +#define GUSDRAMPOS24bit (GUS43DRAMIOlo)
  89 +#define GUS44DRAMIOhi (VSRVolRampControl+2+(16*2)*2+2)
  90 +
  91 +#define voicewavetableirq (VSRVolRampControl+2+(16*2)*3) /* voice IRQ pseudoqueue: 1 bit per voice */
  92 +
  93 +#define voicevolrampirq (VSRVolRampControl+2+(16*2)*4) /* voice IRQ pseudoqueue: 1 bit per voice */
  94 +
  95 +#define startvoices (VSRVolRampControl+2+(16*2)*5) /* statistics / optimizations */
  96 +
  97 +#define IRQStatReg2x6 (VSRVolRampControl+2+(16*2)*6)
  98 +#define TimerStatus2x8 (VSRVolRampControl+2+(16*2)*6+1)
  99 +#define TimerDataReg2x9 (VSRVolRampControl+2+(16*2)*6+2)
  100 +#define MixerCtrlReg2x0 (VSRVolRampControl+2+(16*2)*6+3)
  101 +
  102 +#define VoiceSelReg3x2 (VSRVolRampControl+2+(16*2)*7)
  103 +#define FunkSelReg3x3 (VSRVolRampControl+2+(16*2)*7+1)
  104 +#define AdLibStatus2x8 (VSRVolRampControl+2+(16*2)*7+2)
  105 +#define StatRead_2xF (VSRVolRampControl+2+(16*2)*7+3)
  106 +
  107 +#define GUS48SampSpeed (VSRVolRampControl+2+(16*2)*8)
  108 +#define GUS41DMACtrl (VSRVolRampControl+2+(16*2)*8+1)
  109 +#define GUS45TimerCtrl (VSRVolRampControl+2+(16*2)*8+2)
  110 +#define GUS46Counter1 (VSRVolRampControl+2+(16*2)*8+3)
  111 +
  112 +#define GUS47Counter2 (VSRVolRampControl+2+(16*2)*9)
  113 +#define GUS49SampCtrl (VSRVolRampControl+2+(16*2)*9+1)
  114 +#define GUS4cReset (VSRVolRampControl+2+(16*2)*9+2)
  115 +#define NumVoices (VSRVolRampControl+2+(16*2)*9+3)
  116 +
  117 +#define TimerIRQs (VSRVolRampControl+2+(16*2)*10) /* delayed IRQ, statistics */
  118 +#define BusyTimerIRQs (VSRVolRampControl+2+(16*2)*10+2) /* delayed IRQ, statistics */
  119 +
  120 +#define AdLibCommand2xA (VSRVolRampControl+2+(16*2)*11)
  121 +#define AdLibData2x9 (VSRVolRampControl+2+(16*2)*11+1)
  122 +#define SB2xCd (VSRVolRampControl+2+(16*2)*11+2)
  123 +#define SB2xE (VSRVolRampControl+2+(16*2)*11+3)
  124 +
  125 +#define SynVoiceIRQ8f (VSRVolRampControl+2+(16*2)*12)
  126 +#define GUS50DMAHigh (VSRVolRampControl+2+(16*2)*12+1)
  127 +
  128 +#define portaccesses (VSRegsEnd) /* statistics / suspend mode */
  129 +
  130 +#define gusdataend (VSRegsEnd+4)
  131 +
  132 +#endif /* gustate.h */
... ...
qemu-doc.texi
... ... @@ -175,14 +175,16 @@ PCI UHCI USB controller and a virtual USB hub.
175 175  
176 176 SMP is supported with up to 255 CPUs.
177 177  
178   -Note that adlib and ac97 are only available when QEMU was configured
179   -with --enable-adlib, --enable-ac97 respectively.
  178 +Note that adlib, ac97 and gus are only available when QEMU was configured
  179 +with --enable-adlib, --enable-ac97 or --enable-gus respectively.
180 180  
181 181 QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL
182 182 VGA BIOS.
183 183  
184 184 QEMU uses YM3812 emulation by Tatsuyuki Satoh.
185 185  
  186 +QEMU uses GUS emulation(GUSEMU32) by Tibor "TS" Schütz.
  187 +
186 188 @c man end
187 189  
188 190 @node pcsys_quickstart
... ...