gus.c 8.3 KB

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