gusemu_hal.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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. * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)?
  26. */
  27. #include "qemu/osdep.h"
  28. #include "gustate.h"
  29. #include "gusemu.h"
  30. #define GUSregb(position) (* (gusptr+(position)))
  31. #define GUSregw(position) (*(uint16_t *) (gusptr+(position)))
  32. #define GUSregd(position) (*(uint32_t *)(gusptr + (position)))
  33. /* size given in bytes */
  34. unsigned int gus_read(GUSEmuState * state, int port, int size)
  35. {
  36. int value_read = 0;
  37. uint8_t *gusptr;
  38. gusptr = state->gusdatapos;
  39. GUSregd(portaccesses)++;
  40. switch (port & 0xff0f)
  41. {
  42. /* MixerCtrlReg (read not supported on GUS classic) */
  43. /* case 0x200: return GUSregb(MixerCtrlReg2x0); */
  44. case 0x206: /* IRQstatReg / SB2x6IRQ */
  45. /* adlib/sb bits set in port handlers */
  46. /* timer/voice bits set in gus_irqgen() */
  47. /* dma bit set in gus_dma_transferdata */
  48. /* midi not implemented yet */
  49. return GUSregb(IRQStatReg2x6);
  50. /* case 0x308: */ /* AdLib388 */
  51. case 0x208:
  52. if (GUSregb(GUS45TimerCtrl) & 1)
  53. return GUSregb(TimerStatus2x8);
  54. return GUSregb(AdLibStatus2x8); /* AdLibStatus */
  55. case 0x309: /* AdLib389 */
  56. case 0x209:
  57. return GUSregb(AdLibData2x9); /* AdLibData */
  58. case 0x20A:
  59. return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */
  60. #if 0
  61. case 0x20B: /* GUS hidden registers (read not supported on GUS classic) */
  62. switch (GUSregb(RegCtrl_2xF) & 0x07)
  63. {
  64. case 0: /* IRQ/DMA select */
  65. if (GUSregb(MixerCtrlReg2x0) & 0x40)
  66. return GUSregb(IRQ_2xB); /* control register select bit */
  67. else
  68. return GUSregb(DMA_2xB);
  69. /* case 1-5: */ /* general purpose emulation regs */
  70. /* return ... */ /* + status reset reg (write only) */
  71. case 6:
  72. return GUSregb(Jumper_2xB); /* Joystick/MIDI enable (JumperReg) */
  73. default:;
  74. }
  75. break;
  76. #endif
  77. case 0x20C: /* SB2xCd */
  78. value_read = GUSregb(SB2xCd);
  79. if (GUSregb(StatRead_2xF) & 0x20)
  80. GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */
  81. return value_read;
  82. /* case 0x20D: */ /* SB2xD is write only -> 2xE writes to it*/
  83. case 0x20E:
  84. if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */
  85. {
  86. GUSregb(StatRead_2xF) |= 0x80;
  87. GUS_irqrequest(state, state->gusirq, 1);
  88. }
  89. return GUSregb(SB2xE); /* SB2xE */
  90. case 0x20F: /* StatRead_2xF */
  91. /*set/clear fixed bits */
  92. /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/
  93. value_read = (GUSregb(StatRead_2xF) & 0xf9);
  94. if (GUSregb(MixerCtrlReg2x0) & 0x08)
  95. value_read |= 2; /* DMA/IRQ enabled flag */
  96. return value_read;
  97. /* case 0x300: */ /* MIDI (not implemented) */
  98. /* case 0x301: */ /* MIDI (not implemented) */
  99. case 0x302:
  100. return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */
  101. case 0x303:
  102. return GUSregb(FunkSelReg3x3); /* FunkSelReg */
  103. case 0x304: /* DataRegLoByte3x4 + DataRegWord3x4 */
  104. case 0x305: /* DataRegHiByte3x5 */
  105. switch (GUSregb(FunkSelReg3x3))
  106. {
  107. /* common functions */
  108. case 0x41: /* DramDMAContrReg */
  109. value_read = GUSregb(GUS41DMACtrl); /* &0xfb */
  110. GUSregb(GUS41DMACtrl) &= 0xbb;
  111. if (state->gusdma >= 4)
  112. value_read |= 0x04;
  113. if (GUSregb(IRQStatReg2x6) & 0x80)
  114. {
  115. value_read |= 0x40;
  116. GUSregb(IRQStatReg2x6) &= 0x7f;
  117. if (!GUSregb(IRQStatReg2x6))
  118. GUS_irqclear(state, state->gusirq);
  119. }
  120. return (uint8_t) value_read;
  121. /* DramDMAmemPosReg */
  122. /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
  123. /* 43h+44h write only */
  124. case 0x45:
  125. return GUSregb(GUS45TimerCtrl); /* TimerCtrlReg */
  126. /* 46h+47h write only */
  127. /* 48h: samp freq - write only */
  128. case 0x49:
  129. return GUSregb(GUS49SampCtrl) & 0xbf; /* SampCtrlReg */
  130. /* case 4bh: */ /* joystick trim not supported */
  131. /* case 0x4c: return GUSregb(GUS4cReset); */ /* GUSreset: write only*/
  132. /* voice specific functions */
  133. case 0x80:
  134. case 0x81:
  135. case 0x82:
  136. case 0x83:
  137. case 0x84:
  138. case 0x85:
  139. case 0x86:
  140. case 0x87:
  141. case 0x88:
  142. case 0x89:
  143. case 0x8a:
  144. case 0x8b:
  145. case 0x8c:
  146. case 0x8d:
  147. {
  148. int offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
  149. offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Function*2 */
  150. value_read = GUSregw(offset);
  151. }
  152. break;
  153. /* voice unspecific functions */
  154. case 0x8e: /* NumVoice */
  155. return GUSregb(NumVoices);
  156. case 0x8f: /* irqstatreg */
  157. /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */
  158. return GUSregb(SynVoiceIRQ8f);
  159. default:
  160. return 0xffff;
  161. }
  162. if (size == 1)
  163. {
  164. if ((port & 0xff0f) == 0x305)
  165. value_read = value_read >> 8;
  166. value_read &= 0xff;
  167. }
  168. return (uint16_t) value_read;
  169. /* case 0x306: */ /* Mixer/Version info */
  170. /* return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
  171. case 0x307: /* DRAMaccess */
  172. {
  173. uint8_t *adr;
  174. adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
  175. return *adr;
  176. }
  177. default:;
  178. }
  179. return 0xffff;
  180. }
  181. void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
  182. {
  183. uint8_t *gusptr;
  184. gusptr = state->gusdatapos;
  185. GUSregd(portaccesses)++;
  186. switch (port & 0xff0f)
  187. {
  188. case 0x200: /* MixerCtrlReg */
  189. GUSregb(MixerCtrlReg2x0) = (uint8_t) data;
  190. break;
  191. case 0x206: /* IRQstatReg / SB2x6IRQ */
  192. if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
  193. {
  194. GUSregb(TimerStatus2x8) |= 0x08;
  195. GUSregb(IRQStatReg2x6) = 0x10;
  196. GUS_irqrequest(state, state->gusirq, 1);
  197. }
  198. break;
  199. case 0x308: /* AdLib 388h */
  200. case 0x208: /* AdLibCommandReg */
  201. GUSregb(AdLibCommand2xA) = (uint8_t) data;
  202. break;
  203. case 0x309: /* AdLib 389h */
  204. case 0x209: /* AdLibDataReg */
  205. if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */
  206. {
  207. if (data & 0x80)
  208. GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
  209. else
  210. GUSregb(TimerDataReg2x9) = (uint8_t) data;
  211. }
  212. else
  213. {
  214. GUSregb(AdLibData2x9) = (uint8_t) data;
  215. if (GUSregb(GUS45TimerCtrl) & 0x02)
  216. {
  217. GUSregb(TimerStatus2x8) |= 0x01;
  218. GUSregb(IRQStatReg2x6) = 0x10;
  219. GUS_irqrequest(state, state->gusirq, 1);
  220. }
  221. }
  222. break;
  223. case 0x20A:
  224. GUSregb(AdLibStatus2x8) = (uint8_t) data;
  225. break; /* AdLibStatus2x8 */
  226. case 0x20B: /* GUS hidden registers */
  227. switch (GUSregb(RegCtrl_2xF) & 0x7)
  228. {
  229. case 0:
  230. if (GUSregb(MixerCtrlReg2x0) & 0x40)
  231. GUSregb(IRQ_2xB) = (uint8_t) data; /* control register select bit */
  232. else
  233. GUSregb(DMA_2xB) = (uint8_t) data;
  234. break;
  235. /* case 1-4: general purpose emulation regs */
  236. case 5: /* clear stat reg 2xF */
  237. GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */
  238. if (!GUSregb(IRQStatReg2x6))
  239. GUS_irqclear(state, state->gusirq);
  240. break;
  241. case 6: /* Jumper reg (Joystick/MIDI enable) */
  242. GUSregb(Jumper_2xB) = (uint8_t) data;
  243. break;
  244. default:;
  245. }
  246. break;
  247. case 0x20C: /* SB2xCd */
  248. if (GUSregb(GUS45TimerCtrl) & 0x20)
  249. {
  250. GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */
  251. GUSregb(IRQStatReg2x6) = 0x10;
  252. GUS_irqrequest(state, state->gusirq, 1);
  253. }
  254. /* fall through */
  255. case 0x20D: /* SB2xCd no IRQ */
  256. GUSregb(SB2xCd) = (uint8_t) data;
  257. break;
  258. case 0x20E: /* SB2xE */
  259. GUSregb(SB2xE) = (uint8_t) data;
  260. break;
  261. case 0x20F:
  262. GUSregb(RegCtrl_2xF) = (uint8_t) data;
  263. break; /* CtrlReg2xF */
  264. case 0x302: /* VoiceSelReg */
  265. GUSregb(VoiceSelReg3x2) = (uint8_t) data;
  266. break;
  267. case 0x303: /* FunkSelReg */
  268. GUSregb(FunkSelReg3x3) = (uint8_t) data;
  269. if ((uint8_t) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
  270. {
  271. int voice;
  272. if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
  273. {
  274. for (voice = 0; voice < 31; voice++)
  275. {
  276. if (GUSregd(voicewavetableirq) & (1 << voice))
  277. {
  278. GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */
  279. GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */
  280. if (!GUSregd(voicewavetableirq))
  281. GUSregb(IRQStatReg2x6) &= 0xdf;
  282. if (!GUSregb(IRQStatReg2x6))
  283. GUS_irqclear(state, state->gusirq);
  284. GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */
  285. return;
  286. }
  287. }
  288. }
  289. else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */
  290. {
  291. for (voice = 0; voice < 31; voice++)
  292. {
  293. if (GUSregd(voicevolrampirq) & (1 << voice))
  294. {
  295. GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */
  296. GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */
  297. if (!GUSregd(voicevolrampirq))
  298. GUSregb(IRQStatReg2x6) &= 0xbf;
  299. if (!GUSregb(IRQStatReg2x6))
  300. GUS_irqclear(state, state->gusirq);
  301. GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */
  302. return;
  303. }
  304. }
  305. }
  306. GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */
  307. }
  308. break;
  309. case 0x304:
  310. case 0x305:
  311. {
  312. uint16_t writedata = (uint16_t) data;
  313. uint16_t readmask = 0x0000;
  314. if (size == 1)
  315. {
  316. readmask = 0xff00;
  317. writedata &= 0xff;
  318. if ((port & 0xff0f) == 0x305)
  319. {
  320. writedata = (uint16_t) (writedata << 8);
  321. readmask = 0x00ff;
  322. }
  323. }
  324. switch (GUSregb(FunkSelReg3x3))
  325. {
  326. /* voice specific functions */
  327. case 0x00:
  328. case 0x01:
  329. case 0x02:
  330. case 0x03:
  331. case 0x04:
  332. case 0x05:
  333. case 0x06:
  334. case 0x07:
  335. case 0x08:
  336. case 0x09:
  337. case 0x0a:
  338. case 0x0b:
  339. case 0x0c:
  340. case 0x0d:
  341. {
  342. int offset;
  343. if (!(GUSregb(GUS4cReset) & 0x01))
  344. break; /* reset flag active? */
  345. offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
  346. offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Function*2 */
  347. GUSregw(offset) = (uint16_t) ((GUSregw(offset) & readmask) | writedata);
  348. }
  349. break;
  350. /* voice unspecific functions */
  351. case 0x0e: /* NumVoices */
  352. GUSregb(NumVoices) = (uint8_t) data;
  353. break;
  354. /* case 0x0f: */ /* read only */
  355. /* common functions */
  356. case 0x41: /* DramDMAContrReg */
  357. GUSregb(GUS41DMACtrl) = (uint8_t) data;
  358. if (data & 0x01)
  359. GUS_dmarequest(state);
  360. break;
  361. case 0x42: /* DramDMAmemPosReg */
  362. GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata;
  363. GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */
  364. break;
  365. case 0x43: /* DRAMaddrLo */
  366. GUSregd(GUSDRAMPOS24bit) =
  367. (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata;
  368. break;
  369. case 0x44: /* DRAMaddrHi */
  370. GUSregd(GUSDRAMPOS24bit) =
  371. (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
  372. break;
  373. case 0x45: /* TCtrlReg */
  374. GUSregb(GUS45TimerCtrl) = (uint8_t) data;
  375. if (!(data & 0x20))
  376. GUSregb(TimerStatus2x8) &= 0xe7; /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
  377. if (!(data & 0x02))
  378. GUSregb(TimerStatus2x8) &= 0xfe; /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */
  379. if (!(GUSregb(TimerStatus2x8) & 0x19))
  380. GUSregb(IRQStatReg2x6) &= 0xef; /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */
  381. /* catch up delayed timer IRQs: */
  382. if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3))
  383. {
  384. if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
  385. {
  386. if (!(GUSregb(TimerDataReg2x9) & 0x40))
  387. GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */
  388. if (data & 4) /* timer1 irq enable */
  389. {
  390. GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */
  391. GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */
  392. }
  393. }
  394. if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */
  395. {
  396. if (!(GUSregb(TimerDataReg2x9) & 0x20))
  397. GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */
  398. if (data & 8) /* timer2 irq enable */
  399. {
  400. GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */
  401. GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */
  402. }
  403. }
  404. GUSregw(TimerIRQs)--;
  405. if (GUSregw(BusyTimerIRQs) > 1)
  406. GUSregw(BusyTimerIRQs)--;
  407. else
  408. GUSregw(BusyTimerIRQs) =
  409. GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs));
  410. }
  411. else
  412. GUSregw(TimerIRQs) = 0;
  413. if (!(data & 0x04))
  414. {
  415. GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */
  416. GUSregb(IRQStatReg2x6) &= 0xfb;
  417. }
  418. if (!(data & 0x08))
  419. {
  420. GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */
  421. GUSregb(IRQStatReg2x6) &= 0xf7;
  422. }
  423. if (!GUSregb(IRQStatReg2x6))
  424. GUS_irqclear(state, state->gusirq);
  425. break;
  426. case 0x46: /* Counter1 */
  427. GUSregb(GUS46Counter1) = (uint8_t) data;
  428. break;
  429. case 0x47: /* Counter2 */
  430. GUSregb(GUS47Counter2) = (uint8_t) data;
  431. break;
  432. /* case 0x48: */ /* sampling freq reg not emulated (same as interwave) */
  433. case 0x49: /* SampCtrlReg */
  434. GUSregb(GUS49SampCtrl) = (uint8_t) data;
  435. break;
  436. /* case 0x4b: */ /* joystick trim not emulated */
  437. case 0x4c: /* GUSreset */
  438. GUSregb(GUS4cReset) = (uint8_t) data;
  439. if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
  440. {
  441. GUSregd(voicewavetableirq) = 0;
  442. GUSregd(voicevolrampirq) = 0;
  443. GUSregw(TimerIRQs) = 0;
  444. GUSregw(BusyTimerIRQs) = 0;
  445. GUSregb(NumVoices) = 0xcd;
  446. GUSregb(IRQStatReg2x6) = 0;
  447. GUSregb(TimerStatus2x8) = 0;
  448. GUSregb(AdLibData2x9) = 0;
  449. GUSregb(TimerDataReg2x9) = 0;
  450. GUSregb(GUS41DMACtrl) = 0;
  451. GUSregb(GUS45TimerCtrl) = 0;
  452. GUSregb(GUS49SampCtrl) = 0;
  453. GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */
  454. GUS_irqclear(state, state->gusirq);
  455. }
  456. /* IRQ enable bit checked elsewhere */
  457. /* EnableDAC bit may be used by external callers */
  458. break;
  459. }
  460. }
  461. break;
  462. case 0x307: /* DRAMaccess */
  463. {
  464. uint8_t *adr;
  465. adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
  466. *adr = (uint8_t) data;
  467. }
  468. break;
  469. }
  470. }
  471. /* Attention when breaking up a single DMA transfer to multiple ones:
  472. * it may lead to multiple terminal count interrupts and broken transfers:
  473. *
  474. * 1. Whenever you transfer a piece of data, the gusemu callback is invoked
  475. * 2. The callback may generate a TC irq (if the register was set up to do so)
  476. * 3. The irq may result in the program using the GUS to reprogram the GUS
  477. *
  478. * Some programs also decide to upload by just checking if TC occurs
  479. * (via interrupt or a cleared GUS dma flag)
  480. * and then start the next transfer, without checking DMA state
  481. *
  482. * Thus: Always make sure to set the TC flag correctly!
  483. *
  484. * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA
  485. * while later cards had atomic granularity provided by an additional GUS50DMAHigh register
  486. * GUSemu also uses this register to support byte-granular transfers for better compatibility
  487. * with emulators other than GUSemu32
  488. */
  489. void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC)
  490. {
  491. /* this function gets called by the callback function as soon as a DMA transfer is about to start
  492. * dma_addr is a translated address within accessible memory, not the physical one,
  493. * count is (real dma count register)+1
  494. * note that the amount of bytes transferred is fully determined by values in the DMA registers
  495. * do not forget to update DMA states after transferring the entire block:
  496. * DREQ cleared & TC asserted after the _whole_ transfer */
  497. char *srcaddr;
  498. char *destaddr;
  499. char msbmask = 0;
  500. uint8_t *gusptr;
  501. gusptr = state->gusdatapos;
  502. srcaddr = dma_addr; /* system memory address */
  503. {
  504. int offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf);
  505. if (state->gusdma >= 4)
  506. offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */
  507. destaddr = (char *) state->himemaddr + offset; /* wavetable RAM address */
  508. }
  509. GUSregw(GUS42DMAStart) += (uint16_t) (count >> 4); /* ToDo: add 16bit GUS page limit? */
  510. GUSregb(GUS50DMAHigh) = (uint8_t) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
  511. if (GUSregb(GUS41DMACtrl) & 0x02) /* direction, 0 := sysram->gusram */
  512. {
  513. char *tmpaddr = destaddr;
  514. destaddr = srcaddr;
  515. srcaddr = tmpaddr;
  516. }
  517. if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02)))
  518. msbmask = (const char) 0x80; /* invert MSB */
  519. for (; count > 0; count--)
  520. {
  521. if (GUSregb(GUS41DMACtrl) & 0x40)
  522. *(destaddr++) = *(srcaddr++); /* 16 bit lobyte */
  523. else
  524. *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */
  525. if (state->gusdma >= 4)
  526. *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */
  527. }
  528. if (TC)
  529. {
  530. (GUSregb(GUS41DMACtrl)) &= 0xfe; /* clear DMA request bit */
  531. if (GUSregb(GUS41DMACtrl) & 0x20) /* DMA terminal count IRQ */
  532. {
  533. GUSregb(IRQStatReg2x6) |= 0x80;
  534. GUS_irqrequest(state, state->gusirq, 1);
  535. }
  536. }
  537. }