Revision 423d65f4

b/Makefile.target
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)
b/configure
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 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 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 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 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
b/hw/gus.c
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
}
b/hw/gusemu.h
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 */
b/hw/gusemu_hal.c
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
}
b/hw/gusemu_mixer.c
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
}
b/hw/gustate.h
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 */
b/qemu-doc.texi
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

Also available in: Unified diff