2
0

gus.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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 const MemoryRegionPortio gus_portio_list1[] = {
  200. {0x000, 1, 1, .write = gus_writeb },
  201. {0x000, 1, 2, .write = gus_writew },
  202. {0x006, 10, 1, .read = gus_readb, .write = gus_writeb },
  203. {0x006, 10, 2, .read = gus_readw, .write = gus_writew },
  204. {0x100, 8, 1, .read = gus_readb, .write = gus_writeb },
  205. {0x100, 8, 2, .read = gus_readw, .write = gus_writew },
  206. PORTIO_END_OF_LIST (),
  207. };
  208. static const MemoryRegionPortio gus_portio_list2[] = {
  209. {0, 1, 1, .read = gus_readb },
  210. {0, 1, 2, .read = gus_readw },
  211. PORTIO_END_OF_LIST (),
  212. };
  213. static int gus_initfn (ISADevice *dev)
  214. {
  215. GUSState *s = DO_UPCAST (GUSState, dev, dev);
  216. struct audsettings as;
  217. AUD_register_card ("gus", &s->card);
  218. as.freq = s->freq;
  219. as.nchannels = 2;
  220. as.fmt = AUD_FMT_S16;
  221. as.endianness = GUS_ENDIANNESS;
  222. s->voice = AUD_open_out (
  223. &s->card,
  224. NULL,
  225. "gus",
  226. s,
  227. GUS_callback,
  228. &as
  229. );
  230. if (!s->voice) {
  231. AUD_remove_card (&s->card);
  232. return -1;
  233. }
  234. s->shift = 2;
  235. s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
  236. s->mixbuf = g_malloc0 (s->samples << s->shift);
  237. isa_register_portio_list (dev, s->port, gus_portio_list1, s, "gus");
  238. isa_register_portio_list (dev, (s->port + 0x100) & 0xf00,
  239. gus_portio_list2, s, "gus");
  240. DMA_register_channel (s->emu.gusdma, GUS_read_DMA, s);
  241. s->emu.himemaddr = s->himem;
  242. s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32;
  243. s->emu.opaque = s;
  244. isa_init_irq (dev, &s->pic, s->emu.gusirq);
  245. AUD_set_active_out (s->voice, 1);
  246. return 0;
  247. }
  248. int GUS_init (ISABus *bus)
  249. {
  250. isa_create_simple (bus, "gus");
  251. return 0;
  252. }
  253. static Property gus_properties[] = {
  254. DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
  255. DEFINE_PROP_HEX32 ("iobase", GUSState, port, 0x240),
  256. DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
  257. DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3),
  258. DEFINE_PROP_END_OF_LIST (),
  259. };
  260. static void gus_class_initfn (ObjectClass *klass, void *data)
  261. {
  262. DeviceClass *dc = DEVICE_CLASS (klass);
  263. ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
  264. ic->init = gus_initfn;
  265. dc->desc = "Gravis Ultrasound GF1";
  266. dc->vmsd = &vmstate_gus;
  267. dc->props = gus_properties;
  268. }
  269. static const TypeInfo gus_info = {
  270. .name = "gus",
  271. .parent = TYPE_ISA_DEVICE,
  272. .instance_size = sizeof (GUSState),
  273. .class_init = gus_class_initfn,
  274. };
  275. static void gus_register_types (void)
  276. {
  277. type_register_static (&gus_info);
  278. }
  279. type_init (gus_register_types)