2 * QEMU Proxy for Gravis Ultrasound GF1 emulation by Tibor "TS" Schütz
4 * Copyright (c) 2002-2005 Vassili Karpov (malc)
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
26 #include "audio/audio.h"
31 #define dolog(...) AUD_log ("audio", __VA_ARGS__)
33 #define ldebug(...) dolog (__VA_ARGS__)
38 #ifdef WORDS_BIGENDIAN
39 #define GUS_ENDIANNESS 1
41 #define GUS_ENDIANNESS 0
44 #define IO_READ_PROTO(name) \
45 static uint32_t name (void *opaque, uint32_t nport)
46 #define IO_WRITE_PROTO(name) \
47 static void name (void *opaque, uint32_t nport, uint32_t val)
54 } conf
= {0x240, 7, 3, 44100};
56 typedef struct GUSState
{
60 int pos
, left
, shift
, irqs
;
62 uint8_t himem
[1024 * 1024 + 32 + 4096];
69 IO_READ_PROTO (gus_readb
)
73 return gus_read (&s
->emu
, nport
, 1);
76 IO_READ_PROTO (gus_readw
)
80 return gus_read (&s
->emu
, nport
, 2);
83 IO_WRITE_PROTO (gus_writeb
)
87 gus_write (&s
->emu
, nport
, 1, val
);
90 IO_WRITE_PROTO (gus_writew
)
94 gus_write (&s
->emu
, nport
, 2, val
);
97 static int write_audio (GUSState
*s
, int samples
)
103 int nbytes
, wbytes
, wsampl
;
105 nbytes
= samples
<< s
->shift
;
108 s
->mixbuf
+ (pos
<< (s
->shift
- 1)),
113 wsampl
= wbytes
>> s
->shift
;
116 pos
= (pos
+ wsampl
) % s
->samples
;
128 static void GUS_callback (void *opaque
, int free
)
130 int samples
, to_play
, net
= 0;
131 GUSState
*s
= opaque
;
133 samples
= free
>> s
->shift
;
134 to_play
= audio_MIN (samples
, s
->left
);
137 int written
= write_audio (s
, to_play
);
149 samples
= audio_MIN (samples
, s
->samples
);
151 gus_mixvoices (&s
->emu
, s
->freq
, samples
, s
->mixbuf
);
154 int written
= write_audio (s
, samples
);
165 gus_irqgen (&s
->emu
, (double) (net
* 1000000) / s
->freq
);
168 int GUS_irqrequest (GUSEmuState
*emu
, int hwirq
, int n
)
170 GUSState
*s
= emu
->opaque
;
171 /* qemu_irq_lower (s->pic[hwirq]); */
172 qemu_irq_raise (s
->pic
[hwirq
]);
174 ldebug ("irqrequest %d %d %d\n", hwirq
, n
, s
->irqs
);
178 void GUS_irqclear (GUSEmuState
*emu
, int hwirq
)
180 GUSState
*s
= emu
->opaque
;
181 ldebug ("irqclear %d %d\n", hwirq
, s
->irqs
);
182 qemu_irq_lower (s
->pic
[hwirq
]);
186 qemu_irq_raise (s
->pic
[hwirq
]);
191 void GUS_dmarequest (GUSEmuState
*der
)
193 /* GUSState *s = (GUSState *) der; */
194 ldebug ("dma request %d\n", der
->gusdma
);
195 DMA_hold_DREQ (der
->gusdma
);
198 static int GUS_read_DMA (void *opaque
, int nchan
, int dma_pos
, int dma_len
)
200 GUSState
*s
= opaque
;
202 int pos
= dma_pos
, mode
, left
= dma_len
- dma_pos
;
204 ldebug ("read DMA %#x %d\n", dma_pos
, dma_len
);
205 mode
= DMA_get_channel_mode (s
->emu
.gusdma
);
207 int to_copy
= audio_MIN ((size_t) left
, sizeof (tmpbuf
));
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
);
217 if (0 == ((mode
>> 4) & 1)) {
218 DMA_release_DREQ (s
->emu
.gusdma
);
223 static void GUS_save (QEMUFile
*f
, void *opaque
)
225 GUSState
*s
= opaque
;
227 qemu_put_be32 (f
, s
->pos
);
228 qemu_put_be32 (f
, s
->left
);
229 qemu_put_be32 (f
, s
->shift
);
230 qemu_put_be32 (f
, s
->irqs
);
231 qemu_put_be32 (f
, s
->samples
);
232 qemu_put_be64 (f
, s
->last_ticks
);
233 qemu_put_buffer (f
, s
->himem
, sizeof (s
->himem
));
236 static int GUS_load (QEMUFile
*f
, void *opaque
, int version_id
)
238 GUSState
*s
= opaque
;
243 s
->pos
= qemu_get_be32 (f
);
244 s
->left
= qemu_get_be32 (f
);
245 s
->shift
= qemu_get_be32 (f
);
246 s
->irqs
= qemu_get_be32 (f
);
247 s
->samples
= qemu_get_be32 (f
);
248 s
->last_ticks
= qemu_get_be64 (f
);
249 qemu_get_buffer (f
, s
->himem
, sizeof (s
->himem
));
253 int GUS_init (AudioState
*audio
, qemu_irq
*pic
)
256 struct audsettings as
;
259 dolog ("No audio state\n");
263 s
= qemu_mallocz (sizeof (*s
));
265 AUD_register_card (audio
, "gus", &s
->card
);
269 as
.fmt
= AUD_FMT_S16
;
270 as
.endianness
= GUS_ENDIANNESS
;
272 s
->voice
= AUD_open_out (
282 AUD_remove_card (&s
->card
);
288 s
->samples
= AUD_get_buffer_size_out (s
->voice
) >> s
->shift
;
289 s
->mixbuf
= qemu_mallocz (s
->samples
<< s
->shift
);
291 register_ioport_write (conf
.port
, 1, 1, gus_writeb
, s
);
292 register_ioport_write (conf
.port
, 1, 2, gus_writew
, s
);
294 register_ioport_read ((conf
.port
+ 0x100) & 0xf00, 1, 1, gus_readb
, s
);
295 register_ioport_read ((conf
.port
+ 0x100) & 0xf00, 1, 2, gus_readw
, s
);
297 register_ioport_write (conf
.port
+ 6, 10, 1, gus_writeb
, s
);
298 register_ioport_write (conf
.port
+ 6, 10, 2, gus_writew
, s
);
299 register_ioport_read (conf
.port
+ 6, 10, 1, gus_readb
, s
);
300 register_ioport_read (conf
.port
+ 6, 10, 2, gus_readw
, s
);
303 register_ioport_write (conf
.port
+ 0x100, 8, 1, gus_writeb
, s
);
304 register_ioport_write (conf
.port
+ 0x100, 8, 2, gus_writew
, s
);
305 register_ioport_read (conf
.port
+ 0x100, 8, 1, gus_readb
, s
);
306 register_ioport_read (conf
.port
+ 0x100, 8, 2, gus_readw
, s
);
308 DMA_register_channel (conf
.dma
, GUS_read_DMA
, s
);
309 s
->emu
.gusirq
= conf
.irq
;
310 s
->emu
.gusdma
= conf
.dma
;
311 s
->emu
.himemaddr
= s
->himem
;
312 s
->emu
.gusdatapos
= s
->emu
.himemaddr
+ 1024 * 1024 + 32;
317 AUD_set_active_out (s
->voice
, 1);
319 register_savevm ("gus", 0, 2, GUS_save
, GUS_load
, s
);