2
0

gus.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. #define dolog(...) AUD_log ("audio", __VA_ARGS__)
  31. #ifdef DEBUG
  32. #define ldebug(...) dolog (__VA_ARGS__)
  33. #else
  34. #define ldebug(...)
  35. #endif
  36. #ifdef WORDS_BIGENDIAN
  37. #define GUS_ENDIANNESS 1
  38. #else
  39. #define GUS_ENDIANNESS 0
  40. #endif
  41. #define IO_READ_PROTO(name) \
  42. static uint32_t name (void *opaque, uint32_t nport)
  43. #define IO_WRITE_PROTO(name) \
  44. static void name (void *opaque, uint32_t nport, uint32_t val)
  45. static struct {
  46. int port;
  47. int irq;
  48. int dma;
  49. int freq;
  50. } conf = {0x240, 7, 3, 44100};
  51. typedef struct GUSState {
  52. GUSEmuState emu;
  53. QEMUSoundCard card;
  54. int freq;
  55. int pos, left, shift, irqs;
  56. GUSsample *mixbuf;
  57. uint8_t himem[1024 * 1024 + 32 + 4096];
  58. int samples;
  59. SWVoiceOut *voice;
  60. int64_t last_ticks;
  61. qemu_irq *pic;
  62. } GUSState;
  63. IO_READ_PROTO (gus_readb)
  64. {
  65. GUSState *s = opaque;
  66. return gus_read (&s->emu, nport, 1);
  67. }
  68. IO_READ_PROTO (gus_readw)
  69. {
  70. GUSState *s = opaque;
  71. return gus_read (&s->emu, nport, 2);
  72. }
  73. IO_WRITE_PROTO (gus_writeb)
  74. {
  75. GUSState *s = opaque;
  76. gus_write (&s->emu, nport, 1, val);
  77. }
  78. IO_WRITE_PROTO (gus_writew)
  79. {
  80. GUSState *s = opaque;
  81. gus_write (&s->emu, nport, 2, val);
  82. }
  83. static int write_audio (GUSState *s, int samples)
  84. {
  85. int net = 0;
  86. int pos = s->pos;
  87. while (samples) {
  88. int nbytes, wbytes, wsampl;
  89. nbytes = samples << s->shift;
  90. wbytes = AUD_write (
  91. s->voice,
  92. s->mixbuf + (pos << (s->shift - 1)),
  93. nbytes
  94. );
  95. if (wbytes) {
  96. wsampl = wbytes >> s->shift;
  97. samples -= wsampl;
  98. pos = (pos + wsampl) % s->samples;
  99. net += wsampl;
  100. }
  101. else {
  102. break;
  103. }
  104. }
  105. return net;
  106. }
  107. static void GUS_callback (void *opaque, int free)
  108. {
  109. int samples, to_play, net = 0;
  110. GUSState *s = opaque;
  111. samples = free >> s->shift;
  112. to_play = audio_MIN (samples, s->left);
  113. while (to_play) {
  114. int written = write_audio (s, to_play);
  115. if (!written) {
  116. goto reset;
  117. }
  118. s->left -= written;
  119. to_play -= written;
  120. samples -= written;
  121. net += written;
  122. }
  123. samples = audio_MIN (samples, s->samples);
  124. if (samples) {
  125. gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
  126. while (samples) {
  127. int written = write_audio (s, samples);
  128. if (!written) {
  129. break;
  130. }
  131. samples -= written;
  132. net += written;
  133. }
  134. }
  135. s->left = samples;
  136. reset:
  137. gus_irqgen (&s->emu, (double) (net * 1000000) / s->freq);
  138. }
  139. int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n)
  140. {
  141. GUSState *s = emu->opaque;
  142. /* qemu_irq_lower (s->pic[hwirq]); */
  143. qemu_irq_raise (s->pic[hwirq]);
  144. s->irqs += n;
  145. ldebug ("irqrequest %d %d %d\n", hwirq, n, s->irqs);
  146. return n;
  147. }
  148. void GUS_irqclear (GUSEmuState *emu, int hwirq)
  149. {
  150. GUSState *s = emu->opaque;
  151. ldebug ("irqclear %d %d\n", hwirq, s->irqs);
  152. qemu_irq_lower (s->pic[hwirq]);
  153. s->irqs -= 1;
  154. #ifdef IRQ_STORM
  155. if (s->irqs > 0) {
  156. qemu_irq_raise (s->pic[hwirq]);
  157. }
  158. #endif
  159. }
  160. void GUS_dmarequest (GUSEmuState *der)
  161. {
  162. /* GUSState *s = (GUSState *) der; */
  163. ldebug ("dma request %d\n", der->gusdma);
  164. DMA_hold_DREQ (der->gusdma);
  165. }
  166. static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
  167. {
  168. GUSState *s = opaque;
  169. char tmpbuf[4096];
  170. int pos = dma_pos, mode, left = dma_len - dma_pos;
  171. ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
  172. mode = DMA_get_channel_mode (s->emu.gusdma);
  173. while (left) {
  174. int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf));
  175. int copied;
  176. ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
  177. copied = DMA_read_memory (nchan, tmpbuf, pos, to_copy);
  178. gus_dma_transferdata (&s->emu, tmpbuf, copied, left == copied);
  179. left -= copied;
  180. pos += copied;
  181. }
  182. if (0 == ((mode >> 4) & 1)) {
  183. DMA_release_DREQ (s->emu.gusdma);
  184. }
  185. return dma_len;
  186. }
  187. static void GUS_save (QEMUFile *f, void *opaque)
  188. {
  189. GUSState *s = opaque;
  190. qemu_put_be32 (f, s->pos);
  191. qemu_put_be32 (f, s->left);
  192. qemu_put_be32 (f, s->shift);
  193. qemu_put_be32 (f, s->irqs);
  194. qemu_put_be32 (f, s->samples);
  195. qemu_put_be64 (f, s->last_ticks);
  196. qemu_put_buffer (f, s->himem, sizeof (s->himem));
  197. }
  198. static int GUS_load (QEMUFile *f, void *opaque, int version_id)
  199. {
  200. GUSState *s = opaque;
  201. if (version_id != 2)
  202. return -EINVAL;
  203. s->pos = qemu_get_be32 (f);
  204. s->left = qemu_get_be32 (f);
  205. s->shift = qemu_get_be32 (f);
  206. s->irqs = qemu_get_be32 (f);
  207. s->samples = qemu_get_be32 (f);
  208. s->last_ticks = qemu_get_be64 (f);
  209. qemu_get_buffer (f, s->himem, sizeof (s->himem));
  210. return 0;
  211. }
  212. int GUS_init (AudioState *audio, qemu_irq *pic)
  213. {
  214. GUSState *s;
  215. struct audsettings as;
  216. if (!audio) {
  217. dolog ("No audio state\n");
  218. return -1;
  219. }
  220. s = qemu_mallocz (sizeof (*s));
  221. AUD_register_card (audio, "gus", &s->card);
  222. as.freq = conf.freq;
  223. as.nchannels = 2;
  224. as.fmt = AUD_FMT_S16;
  225. as.endianness = GUS_ENDIANNESS;
  226. s->voice = AUD_open_out (
  227. &s->card,
  228. NULL,
  229. "gus",
  230. s,
  231. GUS_callback,
  232. &as
  233. );
  234. if (!s->voice) {
  235. AUD_remove_card (&s->card);
  236. qemu_free (s);
  237. return -1;
  238. }
  239. s->shift = 2;
  240. s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
  241. s->mixbuf = qemu_mallocz (s->samples << s->shift);
  242. register_ioport_write (conf.port, 1, 1, gus_writeb, s);
  243. register_ioport_write (conf.port, 1, 2, gus_writew, s);
  244. register_ioport_read ((conf.port + 0x100) & 0xf00, 1, 1, gus_readb, s);
  245. register_ioport_read ((conf.port + 0x100) & 0xf00, 1, 2, gus_readw, s);
  246. register_ioport_write (conf.port + 6, 10, 1, gus_writeb, s);
  247. register_ioport_write (conf.port + 6, 10, 2, gus_writew, s);
  248. register_ioport_read (conf.port + 6, 10, 1, gus_readb, s);
  249. register_ioport_read (conf.port + 6, 10, 2, gus_readw, s);
  250. register_ioport_write (conf.port + 0x100, 8, 1, gus_writeb, s);
  251. register_ioport_write (conf.port + 0x100, 8, 2, gus_writew, s);
  252. register_ioport_read (conf.port + 0x100, 8, 1, gus_readb, s);
  253. register_ioport_read (conf.port + 0x100, 8, 2, gus_readw, s);
  254. DMA_register_channel (conf.dma, GUS_read_DMA, s);
  255. s->emu.gusirq = conf.irq;
  256. s->emu.gusdma = conf.dma;
  257. s->emu.himemaddr = s->himem;
  258. s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32;
  259. s->emu.opaque = s;
  260. s->freq = conf.freq;
  261. s->pic = pic;
  262. AUD_set_active_out (s->voice, 1);
  263. register_savevm ("gus", 0, 2, GUS_save, GUS_load, s);
  264. return 0;
  265. }