videoport.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053
  1. /*
  2. * PicoDrive
  3. * (c) Copyright Dave, 2004
  4. * (C) notaz, 2006-2009
  5. * (C) kub, 2020
  6. *
  7. * This work is licensed under the terms of MAME license.
  8. * See COPYING file in the top-level directory.
  9. */
  10. #include "pico_int.h"
  11. #define NEED_DMA_SOURCE
  12. #include "memory.h"
  13. extern const unsigned char hcounts_32[], hcounts_40[];
  14. extern const unsigned char vdpcyc2sl_32_bl[], vdpcyc2sl_40_bl[];
  15. extern const unsigned char vdpcyc2sl_32[], vdpcyc2sl_40[];
  16. extern const unsigned short vdpsl2cyc_32_bl[], vdpsl2cyc_40_bl[];
  17. extern const unsigned short vdpsl2cyc_32[], vdpsl2cyc_40[];
  18. static int blankline; // display disabled for this line
  19. u32 SATaddr, SATmask; // VRAM addr of sprite attribute table
  20. int (*PicoDmaHook)(u32 source, int len, unsigned short **base, unsigned int *mask) = NULL;
  21. /* VDP FIFO implementation
  22. *
  23. * fifo_slot: last slot executed in this scanline
  24. * fifo_cnt: #slots remaining for active FIFO write (#writes<<#bytep)
  25. * fifo_total: #total FIFO entries pending
  26. * fifo_data: last values transferred through fifo
  27. * fifo_queue: fifo transfer queue (#writes, flags)
  28. *
  29. * FIFO states: empty total=0
  30. * inuse total>0 && total<4
  31. * full total==4
  32. * wait total>4
  33. * Conditions:
  34. * fifo_slot is always behind slot2cyc[cycles]. Advancing it beyond cycles
  35. * implies blocking the 68k up to that slot.
  36. *
  37. * A FIFO write goes to the end of the FIFO queue, but DMA running in background
  38. * is always the last queue entry (transfers by CPU intervene and come 1st).
  39. * There can be more pending writes than FIFO slots, but the CPU will be blocked
  40. * until FIFO level (without background DMA) <= 4.
  41. * This is only about correct timing, data xfer must be handled by the caller.
  42. * Blocking the CPU means burning cycles via SekCyclesBurn*(), which is to be
  43. * executed by the caller.
  44. *
  45. * FIFOSync "executes" FIFO write slots up to the given cycle in the current
  46. * scanline. A queue entry completely executed is removed from the queue.
  47. * FIFOWrite pushes writes to the transfer queue. If it's a blocking write, 68k
  48. * is blocked if more than 4 FIFO writes are pending.
  49. * FIFORead executes a 68k read. 68k is blocked until the next transfer slot.
  50. */
  51. // NB code assumes fifo_* arrays have size 2^n
  52. static struct VdpFIFO { // XXX this must go into save file!
  53. // last transferred FIFO data, ...x = index XXX currently only CPU
  54. unsigned short fifo_data[4], fifo_dx;
  55. // queued FIFO transfers, ...x = index, ...l = queue length
  56. // each entry has 2 values: [n]>>3 = #writes, [n]&7 = flags (FQ_*)
  57. unsigned int fifo_queue[8], fifo_qx, fifo_ql;
  58. int fifo_total; // total# of pending FIFO entries (w/o BGDMA)
  59. unsigned short fifo_slot; // last executed slot in current scanline
  60. unsigned short fifo_maxslot;// #slots in scanline
  61. const unsigned char *fifo_cyc2sl;
  62. const unsigned short *fifo_sl2cyc;
  63. } VdpFIFO;
  64. enum { FQ_BYTE = 1, FQ_BGDMA = 2, FQ_FGDMA = 4 }; // queue flags, NB: BYTE = 1!
  65. // NB must limit cyc2sl to table size in case 68k overdraws its aim. That can
  66. // happen if the last insn is a blocking acess to VDP, or for exceptions (e.g.irq)
  67. #define Cyc2Sl(vf,lc) ((lc) < 256*2 ? vf->fifo_cyc2sl[(lc)>>1] : vf->fifo_cyc2sl[255])
  68. #define Sl2Cyc(vf,sl) (vf->fifo_sl2cyc[sl]*2)
  69. // do the FIFO math
  70. static __inline int AdvanceFIFOEntry(struct VdpFIFO *vf, struct PicoVideo *pv, int slots)
  71. {
  72. int l = slots, b = vf->fifo_queue[vf->fifo_qx] & FQ_BYTE;
  73. int cnt = pv->fifo_cnt;
  74. // advance currently active FIFO entry
  75. if (l > cnt)
  76. l = cnt;
  77. if (!(vf->fifo_queue[vf->fifo_qx] & FQ_BGDMA))
  78. if ((vf->fifo_total -= ((cnt & b) + l) >> b) < 0) vf->fifo_total = 0;
  79. cnt -= l;
  80. // if entry has been processed...
  81. if (cnt == 0) {
  82. // remove entry from FIFO
  83. if (vf->fifo_ql) {
  84. vf->fifo_queue[vf->fifo_qx] = 0;
  85. vf->fifo_qx = (vf->fifo_qx+1) & 7, vf->fifo_ql --;
  86. }
  87. // start processing for next entry if there is one
  88. if (vf->fifo_ql) {
  89. b = vf->fifo_queue[vf->fifo_qx] & FQ_BYTE;
  90. cnt = (vf->fifo_queue[vf->fifo_qx] >> 3) << b;
  91. } else { // FIFO empty
  92. pv->status &= ~PVS_FIFORUN;
  93. vf->fifo_total = 0;
  94. }
  95. }
  96. pv->fifo_cnt = cnt;
  97. return l;
  98. }
  99. static __inline void SetFIFOState(struct VdpFIFO *vf, struct PicoVideo *pv)
  100. {
  101. unsigned int st = pv->status, cmd = pv->command;
  102. // release CPU and terminate DMA if FIFO isn't blocking the 68k anymore
  103. if (vf->fifo_total <= 4) {
  104. st &= ~PVS_CPUWR;
  105. if (!(st & (PVS_DMABG|PVS_DMAFILL))) {
  106. st &= ~SR_DMA;
  107. cmd &= ~0x80;
  108. }
  109. }
  110. if (pv->fifo_cnt == 0) {
  111. st &= ~PVS_CPURD;
  112. // terminate DMA if applicable
  113. if (!(st & (PVS_FIFORUN|PVS_DMAFILL))) {
  114. st &= ~(SR_DMA|PVS_DMABG);
  115. cmd &= ~0x80;
  116. }
  117. }
  118. pv->status = st;
  119. pv->command = cmd;
  120. }
  121. // sync FIFO to cycles
  122. void PicoVideoFIFOSync(int cycles)
  123. {
  124. struct VdpFIFO *vf = &VdpFIFO;
  125. struct PicoVideo *pv = &Pico.video;
  126. int slots, done;
  127. // calculate #slots since last executed slot
  128. slots = Cyc2Sl(vf, cycles) - vf->fifo_slot;
  129. // advance FIFO queue by #done slots
  130. done = slots;
  131. while (done > 0 && pv->fifo_cnt) {
  132. int l = AdvanceFIFOEntry(vf, pv, done);
  133. vf->fifo_slot += l;
  134. done -= l;
  135. }
  136. if (done != slots)
  137. SetFIFOState(vf, pv);
  138. }
  139. // drain FIFO, blocking 68k on the way. FIFO must be synced prior to drain.
  140. static int PicoVideoFIFODrain(int level, int cycles, int bgdma)
  141. {
  142. struct VdpFIFO *vf = &VdpFIFO;
  143. struct PicoVideo *pv = &Pico.video;
  144. unsigned ocyc = cycles;
  145. int burn = 0;
  146. // process FIFO entries until low level is reached
  147. while (vf->fifo_slot <= vf->fifo_maxslot && cycles < 488 &&
  148. ((vf->fifo_total > level) | (vf->fifo_queue[vf->fifo_qx] & bgdma))) {
  149. int b = vf->fifo_queue[vf->fifo_qx] & FQ_BYTE;
  150. int cnt = bgdma ? pv->fifo_cnt : ((vf->fifo_total-level)<<b) - (pv->fifo_cnt&b);
  151. int slot = (pv->fifo_cnt<cnt ? pv->fifo_cnt:cnt) + vf->fifo_slot;
  152. if (slot > vf->fifo_maxslot) {
  153. // target slot in later scanline, advance to eol
  154. slot = vf->fifo_maxslot;
  155. cycles = 488;
  156. } else {
  157. // advance FIFO to target slot and CPU to cycles at that slot
  158. cycles = Sl2Cyc(vf, slot);
  159. }
  160. if (slot > vf->fifo_slot) {
  161. AdvanceFIFOEntry(vf, pv, slot - vf->fifo_slot);
  162. vf->fifo_slot = slot;
  163. }
  164. }
  165. if (cycles > ocyc)
  166. burn = cycles - ocyc;
  167. SetFIFOState(vf, pv);
  168. return burn;
  169. }
  170. // read VDP data port
  171. static int PicoVideoFIFORead(void)
  172. {
  173. struct VdpFIFO *vf = &VdpFIFO;
  174. struct PicoVideo *pv = &Pico.video;
  175. int lc = SekCyclesDone()-Pico.t.m68c_line_start;
  176. int burn = 0;
  177. if (pv->fifo_cnt) {
  178. PicoVideoFIFOSync(lc);
  179. // advance FIFO and CPU until FIFO is empty
  180. burn = PicoVideoFIFODrain(0, lc, FQ_BGDMA);
  181. lc += burn;
  182. }
  183. if (pv->fifo_cnt)
  184. pv->status |= PVS_CPURD; // target slot is in later scanline
  185. else {
  186. // use next VDP access slot for reading, block 68k until then
  187. vf->fifo_slot = Cyc2Sl(vf, lc) + 1;
  188. burn += Sl2Cyc(vf, vf->fifo_slot) - lc;
  189. }
  190. return burn;
  191. }
  192. // write VDP data port
  193. int PicoVideoFIFOWrite(int count, int flags, unsigned sr_mask,unsigned sr_flags)
  194. {
  195. struct VdpFIFO *vf = &VdpFIFO;
  196. struct PicoVideo *pv = &Pico.video;
  197. int lc = SekCyclesDone()-Pico.t.m68c_line_start;
  198. int burn = 0;
  199. if (pv->fifo_cnt)
  200. PicoVideoFIFOSync(lc);
  201. pv->status = (pv->status & ~sr_mask) | sr_flags;
  202. if (count && vf->fifo_ql < 8) {
  203. // determine queue position for entry
  204. int x = (vf->fifo_qx + vf->fifo_ql - 1) & 7;
  205. if (unlikely(vf->fifo_queue[x] & FQ_BGDMA)) {
  206. // CPU FIFO writes have priority over a background DMA Fill/Copy
  207. // XXX if interrupting a DMA fill, fill data changes
  208. if (x == vf->fifo_qx) { // overtaking to queue head?
  209. int f = vf->fifo_queue[x] & 7;
  210. vf->fifo_queue[(x+1) & 7] = (pv->fifo_cnt >> (f & FQ_BYTE) << 3) | f;
  211. pv->status &= ~PVS_FIFORUN;
  212. } else
  213. // push background DMA back
  214. vf->fifo_queue[(x+1) & 7] = vf->fifo_queue[x];
  215. x = (x-1) & 7;
  216. }
  217. if ((pv->status & PVS_FIFORUN) && (vf->fifo_queue[x] & 7) == flags) {
  218. // amalgamate entries if of same type
  219. vf->fifo_queue[x] += (count << 3);
  220. if (x == vf->fifo_qx)
  221. pv->fifo_cnt += count << (flags & FQ_BYTE);
  222. } else {
  223. // create new xfer queue entry
  224. vf->fifo_ql ++;
  225. x = (x+1) & 7;
  226. vf->fifo_queue[x] = (count << 3) | flags;
  227. }
  228. // update FIFO state if it was empty
  229. if (!(pv->status & PVS_FIFORUN)) {
  230. vf->fifo_slot = Cyc2Sl(vf, lc+8); // FIFO latency ~3 vdp slots
  231. pv->status |= PVS_FIFORUN;
  232. pv->fifo_cnt = count << (flags & FQ_BYTE);
  233. }
  234. if (!(flags & FQ_BGDMA))
  235. vf->fifo_total += count;
  236. }
  237. // if CPU is waiting for the bus, advance CPU and FIFO until bus is free
  238. if (pv->status & PVS_CPUWR)
  239. burn = PicoVideoFIFODrain(4, lc, 0);
  240. return burn;
  241. }
  242. // at HINT, advance FIFO to new scanline
  243. int PicoVideoFIFOHint(void)
  244. {
  245. struct VdpFIFO *vf = &VdpFIFO;
  246. struct PicoVideo *pv = &Pico.video;
  247. int burn = 0;
  248. // reset slot to start of scanline
  249. vf->fifo_slot = 0;
  250. // if CPU is waiting for the bus, advance CPU and FIFO until bus is free
  251. if (pv->status & PVS_CPUWR)
  252. burn = PicoVideoFIFOWrite(0, 0, 0, 0);
  253. else if (pv->status & PVS_CPURD)
  254. burn = PicoVideoFIFORead();
  255. return burn;
  256. }
  257. // switch FIFO mode between active/inactive display
  258. void PicoVideoFIFOMode(int active, int h40)
  259. {
  260. static const unsigned char *vdpcyc2sl[2][2] =
  261. { {vdpcyc2sl_32_bl, vdpcyc2sl_40_bl} , {vdpcyc2sl_32, vdpcyc2sl_40} };
  262. static const unsigned short *vdpsl2cyc[2][2] =
  263. { {vdpsl2cyc_32_bl, vdpsl2cyc_40_bl} , {vdpsl2cyc_32, vdpsl2cyc_40} };
  264. struct VdpFIFO *vf = &VdpFIFO;
  265. struct PicoVideo *pv = &Pico.video;
  266. int lc = SekCyclesDone() - Pico.t.m68c_line_start;
  267. active = active && !(pv->status & PVS_VB2);
  268. if (vf->fifo_maxslot)
  269. PicoVideoFIFOSync(lc);
  270. vf->fifo_cyc2sl = vdpcyc2sl[active][h40];
  271. vf->fifo_sl2cyc = vdpsl2cyc[active][h40];
  272. // recalculate FIFO slot for new mode
  273. vf->fifo_slot = Cyc2Sl(vf, lc)-1;
  274. vf->fifo_maxslot = Cyc2Sl(vf, 488);
  275. }
  276. // VDP memory rd/wr
  277. static __inline void AutoIncrement(void)
  278. {
  279. Pico.video.addr=(unsigned short)(Pico.video.addr+Pico.video.reg[0xf]);
  280. if (Pico.video.addr < Pico.video.reg[0xf]) Pico.video.addr_u ^= 1;
  281. }
  282. static NOINLINE void VideoWriteVRAM128(u32 a, u16 d)
  283. {
  284. // nasty
  285. u32 b = ((a & 2) >> 1) | ((a & 0x400) >> 9) | (a & 0x3FC) | ((a & 0x1F800) >> 1);
  286. ((u8 *)PicoMem.vram)[b] = d;
  287. if (!(u16)((b^SATaddr) & SATmask))
  288. Pico.est.rendstatus |= PDRAW_DIRTY_SPRITES;
  289. if (((a^SATaddr) & SATmask) == 0)
  290. UpdateSAT(a, d);
  291. }
  292. static void VideoWrite(u16 d)
  293. {
  294. unsigned int a = Pico.video.addr;
  295. switch (Pico.video.type)
  296. {
  297. case 1: if (a & 1)
  298. d = (u16)((d << 8) | (d >> 8));
  299. a |= Pico.video.addr_u << 16;
  300. VideoWriteVRAM(a, d);
  301. break;
  302. case 3: if (PicoMem.cram [(a >> 1) & 0x3f] != d) Pico.m.dirtyPal = 1;
  303. PicoMem.cram [(a >> 1) & 0x3f] = d & 0xeee; break;
  304. case 5: PicoMem.vsram[(a >> 1) & 0x3f] = d & 0x7ff; break;
  305. case 0x81:
  306. a |= Pico.video.addr_u << 16;
  307. VideoWriteVRAM128(a, d);
  308. break;
  309. //default:elprintf(EL_ANOMALY, "VDP write %04x with bad type %i", d, Pico.video.type); break;
  310. }
  311. AutoIncrement();
  312. }
  313. static unsigned int VideoRead(int is_from_z80)
  314. {
  315. unsigned int a, d = VdpFIFO.fifo_data[(VdpFIFO.fifo_dx+1)&3];
  316. a=Pico.video.addr; a>>=1;
  317. if (!is_from_z80)
  318. SekCyclesBurnRun(PicoVideoFIFORead());
  319. switch (Pico.video.type)
  320. {
  321. case 0: d=PicoMem.vram [a & 0x7fff]; break;
  322. case 8: d=PicoMem.cram [a & 0x003f] | (d & ~0x0eee); break;
  323. case 4: if ((a & 0x3f) >= 0x28) a = 0;
  324. d=PicoMem.vsram [a & 0x003f] | (d & ~0x07ff); break;
  325. case 12:a=PicoMem.vram [a & 0x7fff]; if (Pico.video.addr&1) a >>= 8;
  326. d=(a & 0x00ff) | (d & ~0x00ff); break;
  327. default:elprintf(EL_ANOMALY, "VDP read with bad type %i", Pico.video.type); break;
  328. }
  329. AutoIncrement();
  330. return d;
  331. }
  332. // VDP DMA
  333. static int GetDmaLength(void)
  334. {
  335. struct PicoVideo *pvid=&Pico.video;
  336. int len=0;
  337. // 16-bit words to transfer:
  338. len =pvid->reg[0x13];
  339. len|=pvid->reg[0x14]<<8;
  340. len = ((len - 1) & 0xffff) + 1;
  341. return len;
  342. }
  343. static void DmaSlow(int len, u32 source)
  344. {
  345. u32 inc = Pico.video.reg[0xf];
  346. u32 a = Pico.video.addr | (Pico.video.addr_u << 16);
  347. u16 *r, *base = NULL;
  348. u32 mask = 0x1ffff;
  349. elprintf(EL_VDPDMA, "DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%u] @ %06x",
  350. Pico.video.type, source, a, len, inc, (Pico.video.status&SR_VB)||!(Pico.video.reg[1]&0x40),
  351. SekCyclesDone(), SekPc);
  352. SekCyclesBurnRun(PicoVideoFIFOWrite(len, FQ_FGDMA | (Pico.video.type == 1),
  353. PVS_DMABG, SR_DMA | PVS_CPUWR));
  354. if ((source & 0xe00000) == 0xe00000) { // Ram
  355. base = (u16 *)PicoMem.ram;
  356. mask = 0xffff;
  357. }
  358. else if (PicoIn.AHW & PAHW_MCD)
  359. {
  360. u8 r3 = Pico_mcd->s68k_regs[3];
  361. elprintf(EL_VDPDMA, "DmaSlow CD, r3=%02x", r3);
  362. if (source < 0x20000) { // Bios area
  363. base = (u16 *)Pico_mcd->bios;
  364. } else if ((source & 0xfc0000) == 0x200000) { // Word Ram
  365. if (!(r3 & 4)) { // 2M mode
  366. base = (u16 *)(Pico_mcd->word_ram2M + (source & 0x20000));
  367. } else {
  368. if (source < 0x220000) { // 1M mode
  369. int bank = r3 & 1;
  370. base = (u16 *)(Pico_mcd->word_ram1M[bank]);
  371. } else {
  372. DmaSlowCell(source - 2, a, len, inc);
  373. return;
  374. }
  375. }
  376. source -= 2;
  377. } else if ((source & 0xfe0000) == 0x020000) { // Prg Ram
  378. base = (u16 *)Pico_mcd->prg_ram_b[r3 >> 6];
  379. source -= 2; // XXX: test
  380. }
  381. }
  382. else
  383. {
  384. // if we have DmaHook, let it handle ROM because of possible DMA delay
  385. u32 source2;
  386. if (PicoDmaHook && (source2 = PicoDmaHook(source, len, &base, &mask)))
  387. source = source2;
  388. else // Rom
  389. base = m68k_dma_source(source);
  390. }
  391. if (!base) {
  392. elprintf(EL_VDPDMA|EL_ANOMALY, "DmaSlow[%i] %06x->%04x: invalid src", Pico.video.type, source, a);
  393. return;
  394. }
  395. // operate in words
  396. source >>= 1;
  397. mask >>= 1;
  398. switch (Pico.video.type)
  399. {
  400. case 1: // vram
  401. r = PicoMem.vram;
  402. if (inc == 2 && !(a & 1) && (a & ~0xffff) == ((a + len*2-1) & ~0xffff) &&
  403. ((a >= SATaddr+0x280) | ((a + len*2-1) < SATaddr)) &&
  404. (source & ~mask) == ((source + len-1) & ~mask))
  405. {
  406. // most used DMA mode
  407. memcpy((char *)r + a, base + (source & mask), len * 2);
  408. a += len * 2;
  409. break;
  410. }
  411. for(; len; len--)
  412. {
  413. u16 d = base[source++ & mask];
  414. if(a & 1) d=(d<<8)|(d>>8);
  415. VideoWriteVRAM(a, d);
  416. // AutoIncrement
  417. a = (a+inc) & ~0x20000;
  418. }
  419. break;
  420. case 3: // cram
  421. Pico.m.dirtyPal = 1;
  422. r = PicoMem.cram;
  423. for (; len; len--)
  424. {
  425. r[(a / 2) & 0x3f] = base[source++ & mask] & 0xeee;
  426. // AutoIncrement
  427. a = (a+inc) & ~0x20000;
  428. }
  429. break;
  430. case 5: // vsram
  431. r = PicoMem.vsram;
  432. for (; len; len--)
  433. {
  434. r[(a / 2) & 0x3f] = base[source++ & mask] & 0x7ff;
  435. // AutoIncrement
  436. a = (a+inc) & ~0x20000;
  437. }
  438. break;
  439. case 0x81: // vram 128k
  440. for(; len; len--)
  441. {
  442. u16 d = base[source++ & mask];
  443. VideoWriteVRAM128(a, d);
  444. // AutoIncrement
  445. a = (a+inc) & ~0x20000;
  446. }
  447. break;
  448. default:
  449. if (Pico.video.type != 0 || (EL_LOGMASK & EL_VDPDMA))
  450. elprintf(EL_VDPDMA|EL_ANOMALY, "DMA with bad type %i", Pico.video.type);
  451. break;
  452. }
  453. // remember addr
  454. Pico.video.addr = a;
  455. Pico.video.addr_u = a >> 16;
  456. }
  457. static void DmaCopy(int len)
  458. {
  459. u32 a = Pico.video.addr | (Pico.video.addr_u << 16);
  460. u8 *vr = (u8 *)PicoMem.vram;
  461. u8 inc = Pico.video.reg[0xf];
  462. int source;
  463. elprintf(EL_VDPDMA, "DmaCopy len %i [%u]", len, SekCyclesDone());
  464. // XXX implement VRAM 128k? Is this even working? xfer/count still FQ_BYTE?
  465. SekCyclesBurnRun(PicoVideoFIFOWrite(len, FQ_BGDMA | FQ_BYTE,
  466. PVS_CPUWR, SR_DMA | PVS_DMABG));
  467. source =Pico.video.reg[0x15];
  468. source|=Pico.video.reg[0x16]<<8;
  469. for (; len; len--)
  470. {
  471. vr[(u16)a] = vr[(u16)(source++)];
  472. if (((a^SATaddr) & SATmask) == 0)
  473. UpdateSAT(a, ((u16 *)vr)[(u16)a >> 1]);
  474. // AutoIncrement
  475. a = (a+inc) & ~0x20000;
  476. }
  477. // remember addr
  478. Pico.video.addr = a;
  479. Pico.video.addr_u = a >> 16;
  480. }
  481. static NOINLINE void DmaFill(int data)
  482. {
  483. u32 a = Pico.video.addr | (Pico.video.addr_u << 16);
  484. u8 *vr = (u8 *)PicoMem.vram;
  485. u8 high = (u8)(data >> 8);
  486. u8 inc = Pico.video.reg[0xf];
  487. int source;
  488. int len, l;
  489. len = GetDmaLength();
  490. elprintf(EL_VDPDMA, "DmaFill len %i inc %i [%u]", len, inc, SekCyclesDone());
  491. SekCyclesBurnRun(PicoVideoFIFOWrite(len, FQ_BGDMA | (Pico.video.type == 1),
  492. PVS_CPUWR | PVS_DMAFILL, SR_DMA | PVS_DMABG));
  493. switch (Pico.video.type)
  494. {
  495. case 1: // vram
  496. if (inc == 1 && (a & ~0xffff) == ((a + len-1) & ~0xffff) &&
  497. ((a >= SATaddr+0x280) | ((a + len-1) < SATaddr)))
  498. {
  499. // most used DMA mode
  500. memset(vr + (u16)a, high, len);
  501. a += len;
  502. break;
  503. }
  504. for (l = len; l; l--) {
  505. // Write upper byte to adjacent address
  506. // (here we are byteswapped, so address is already 'adjacent')
  507. vr[(u16)a] = high;
  508. if (((a^SATaddr) & SATmask) == 0)
  509. UpdateSAT(a, ((u16 *)vr)[(u16)a >> 1]);
  510. // Increment address register
  511. a = (a+inc) & ~0x20000;
  512. }
  513. break;
  514. case 3: // cram
  515. Pico.m.dirtyPal = 1;
  516. data &= 0xeee;
  517. for (l = len; l; l--) {
  518. PicoMem.cram[(a/2) & 0x3f] = data;
  519. // Increment address register
  520. a = (a+inc) & ~0x20000;
  521. }
  522. break;
  523. case 5: { // vsram
  524. data &= 0x7ff;
  525. for (l = len; l; l--) {
  526. PicoMem.vsram[(a/2) & 0x3f] = data;
  527. // Increment address register
  528. a = (a+inc) & ~0x20000;
  529. }
  530. break;
  531. }
  532. case 0x81: // vram 128k
  533. for (l = len; l; l--) {
  534. VideoWriteVRAM128(a, data);
  535. // Increment address register
  536. a = (a+inc) & ~0x20000;
  537. }
  538. break;
  539. default:
  540. a += len * inc;
  541. break;
  542. }
  543. // remember addr
  544. Pico.video.addr = a;
  545. Pico.video.addr_u = a >> 16;
  546. // register update
  547. Pico.video.reg[0x13] = Pico.video.reg[0x14] = 0;
  548. source = Pico.video.reg[0x15];
  549. source |= Pico.video.reg[0x16] << 8;
  550. source += len;
  551. Pico.video.reg[0x15] = source;
  552. Pico.video.reg[0x16] = source >> 8;
  553. }
  554. // VDP command handling
  555. static NOINLINE void CommandDma(void)
  556. {
  557. struct PicoVideo *pvid=&Pico.video;
  558. u32 len, method;
  559. u32 source;
  560. PicoVideoFIFOSync(SekCyclesDone()-Pico.t.m68c_line_start);
  561. if (pvid->status & SR_DMA) {
  562. elprintf(EL_VDPDMA, "Dma overlap, left=%d @ %06x",
  563. VdpFIFO.fifo_total, SekPc);
  564. pvid->fifo_cnt = VdpFIFO.fifo_total = VdpFIFO.fifo_ql = 0;
  565. pvid->status &= ~(PVS_FIFORUN|PVS_DMAFILL);
  566. }
  567. len = GetDmaLength();
  568. source =Pico.video.reg[0x15];
  569. source|=Pico.video.reg[0x16] << 8;
  570. source|=Pico.video.reg[0x17] << 16;
  571. method=pvid->reg[0x17]>>6;
  572. if (method < 2)
  573. DmaSlow(len, source << 1); // 68000 to VDP
  574. else if (method == 3)
  575. DmaCopy(len); // VRAM Copy
  576. else {
  577. pvid->status |= SR_DMA|PVS_DMAFILL;
  578. return;
  579. }
  580. source += len;
  581. Pico.video.reg[0x13] = Pico.video.reg[0x14] = 0;
  582. Pico.video.reg[0x15] = source;
  583. Pico.video.reg[0x16] = source >> 8;
  584. }
  585. static NOINLINE void CommandChange(struct PicoVideo *pvid)
  586. {
  587. unsigned int cmd, addr;
  588. cmd = pvid->command;
  589. // Get type of transfer 0xc0000030 (v/c/vsram read/write)
  590. pvid->type = (u8)(((cmd >> 2) & 0xc) | (cmd >> 30));
  591. if (pvid->type == 1) // vram
  592. pvid->type |= pvid->reg[1] & 0x80; // 128k
  593. // Get address 0x3fff0003
  594. addr = (cmd >> 16) & 0x3fff;
  595. addr |= (cmd << 14) & 0xc000;
  596. pvid->addr = (u16)addr;
  597. pvid->addr_u = (u8)((cmd >> 2) & 1);
  598. }
  599. // VDP interface
  600. static void DrawSync(int skip)
  601. {
  602. int lines = Pico.video.reg[1]&0x08 ? 240 : 224;
  603. int last = Pico.m.scanline - (skip || blankline == Pico.m.scanline);
  604. if (last < lines && !(PicoIn.opt & POPT_ALT_RENDERER) &&
  605. !PicoIn.skipFrame && Pico.est.DrawScanline <= last) {
  606. //elprintf(EL_ANOMALY, "sync");
  607. if (blankline >= 0 && blankline < last) {
  608. PicoDrawSync(blankline, 1);
  609. blankline = -1;
  610. }
  611. PicoDrawSync(last, 0);
  612. }
  613. }
  614. PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
  615. {
  616. struct PicoVideo *pvid=&Pico.video;
  617. //elprintf(EL_STATUS, "PicoVideoWrite [%06x] %04x [%u] @ %06x",
  618. // a, d, SekCyclesDone(), SekPc);
  619. a &= 0x1c;
  620. switch (a)
  621. {
  622. case 0x00: // Data port 0 or 2
  623. // try avoiding the sync..
  624. if (Pico.m.scanline < (pvid->reg[1]&0x08 ? 240 : 224) && (pvid->reg[1]&0x40) &&
  625. !(!pvid->pending &&
  626. ((pvid->command & 0xc00000f0) == 0x40000010 && PicoMem.vsram[pvid->addr>>1] == (d & 0x7ff)))
  627. )
  628. DrawSync(0); // XXX it's unclear when vscroll data is fetched from vsram?
  629. if (pvid->pending) {
  630. CommandChange(pvid);
  631. pvid->pending=0;
  632. }
  633. if (!(PicoIn.opt&POPT_DIS_VDP_FIFO))
  634. {
  635. VdpFIFO.fifo_data[++VdpFIFO.fifo_dx&3] = d;
  636. SekCyclesBurnRun(PicoVideoFIFOWrite(1, pvid->type == 1, 0, PVS_CPUWR));
  637. elprintf(EL_ASVDP, "VDP data write: [%04x] %04x [%u] {%i} @ %06x",
  638. Pico.video.addr, d, SekCyclesDone(), Pico.video.type, SekPc);
  639. }
  640. VideoWrite(d);
  641. // start DMA fill on write. NB VSRAM and CRAM fills use wrong FIFO data.
  642. if (pvid->status & PVS_DMAFILL)
  643. DmaFill(VdpFIFO.fifo_data[(VdpFIFO.fifo_dx + !!(pvid->type&~0x81))&3]);
  644. break;
  645. case 0x04: // Control (command) port 4 or 6
  646. if (pvid->status & SR_DMA)
  647. SekCyclesBurnRun(PicoVideoFIFORead()); // kludge, flush out running DMA
  648. if (pvid->pending)
  649. {
  650. // Low word of command:
  651. if (!(pvid->reg[1]&0x10))
  652. d = (d&~0x80)|(pvid->command&0x80);
  653. pvid->command &= 0xffff0000;
  654. pvid->command |= d;
  655. pvid->pending = 0;
  656. CommandChange(pvid);
  657. // Check for dma:
  658. if (d & 0x80) {
  659. DrawSync(SekCyclesDone() - Pico.t.m68c_line_start <= 488-390);
  660. CommandDma();
  661. }
  662. }
  663. else
  664. {
  665. if ((d&0xc000)==0x8000)
  666. {
  667. // Register write:
  668. int num=(d>>8)&0x1f;
  669. int dold=pvid->reg[num];
  670. pvid->type=0; // register writes clear command (else no Sega logo in Golden Axe II)
  671. if (num > 0x0a && !(pvid->reg[1]&4)) {
  672. elprintf(EL_ANOMALY, "%02x written to reg %02x in SMS mode @ %06x", d, num, SekPc);
  673. return;
  674. }
  675. if (num == 0 && !(pvid->reg[0]&2) && (d&2))
  676. pvid->hv_latch = PicoVideoRead(0x08);
  677. if (num == 1 && ((pvid->reg[1]^d)&0x40)) {
  678. PicoVideoFIFOMode(d & 0x40, pvid->reg[12]&1);
  679. // handle line blanking before line rendering
  680. if (SekCyclesDone() - Pico.t.m68c_line_start <= 488-390)
  681. blankline = d&0x40 ? -1 : Pico.m.scanline;
  682. }
  683. if (num == 12 && ((pvid->reg[12]^d)&0x01))
  684. PicoVideoFIFOMode(pvid->reg[1]&0x40, d & 1);
  685. DrawSync(SekCyclesDone() - Pico.t.m68c_line_start <= 488-390);
  686. pvid->reg[num]=(unsigned char)d;
  687. switch (num)
  688. {
  689. case 0x00:
  690. elprintf(EL_INTSW, "hint_onoff: %i->%i [%u] pend=%i @ %06x", (dold&0x10)>>4,
  691. (d&0x10)>>4, SekCyclesDone(), (pvid->pending_ints&0x10)>>4, SekPc);
  692. goto update_irq;
  693. case 0x01:
  694. elprintf(EL_INTSW, "vint_onoff: %i->%i [%u] pend=%i @ %06x", (dold&0x20)>>5,
  695. (d&0x20)>>5, SekCyclesDone(), (pvid->pending_ints&0x20)>>5, SekPc);
  696. if (!(pvid->status & PVS_VB2))
  697. pvid->status &= ~SR_VB;
  698. pvid->status |= ((d >> 3) ^ SR_VB) & SR_VB; // forced blanking
  699. goto update_irq;
  700. case 0x05:
  701. case 0x06:
  702. if (d^dold) Pico.est.rendstatus |= PDRAW_SPRITES_MOVED;
  703. break;
  704. case 0x0c:
  705. // renderers should update their palettes if sh/hi mode is changed
  706. if ((d^dold)&8) Pico.m.dirtyPal = 1;
  707. break;
  708. default:
  709. return;
  710. }
  711. SATaddr = ((pvid->reg[5]&0x7f) << 9) | ((pvid->reg[6]&0x20) << 11);
  712. SATmask = ~0x1ff;
  713. if (Pico.video.reg[12]&1)
  714. SATaddr &= ~0x200, SATmask &= ~0x200; // H40, zero lowest SAT bit
  715. //elprintf(EL_STATUS, "spritep moved to %04x", SATaddr);
  716. return;
  717. update_irq:
  718. #ifndef EMU_CORE_DEBUG
  719. // update IRQ level
  720. if (!SekShouldInterrupt()) // hack
  721. {
  722. int lines, pints, irq = 0;
  723. lines = (pvid->reg[1] & 0x20) | (pvid->reg[0] & 0x10);
  724. pints = pvid->pending_ints & lines;
  725. if (pints & 0x20) irq = 6;
  726. else if (pints & 0x10) irq = 4;
  727. SekInterrupt(irq); // update line
  728. // this is broken because cost of current insn isn't known here
  729. if (irq) SekEndRun(21); // make it delayed
  730. }
  731. #endif
  732. }
  733. else
  734. {
  735. // High word of command:
  736. pvid->command&=0x0000ffff;
  737. pvid->command|=d<<16;
  738. pvid->pending=1;
  739. }
  740. }
  741. break;
  742. // case 0x08: // 08 0a - HV counter - lock up
  743. // case 0x0c: // 0c 0e - HV counter - lock up
  744. // case 0x10: // 10 12 - PSG - handled by caller
  745. // case 0x14: // 14 16 - PSG - handled by caller
  746. // case 0x18: // 18 1a - no effect?
  747. case 0x1c: // 1c 1e - debug
  748. pvid->debug = d;
  749. pvid->debug_p = 0;
  750. if (d & (1 << 6)) {
  751. pvid->debug_p |= PVD_KILL_A | PVD_KILL_B;
  752. pvid->debug_p |= PVD_KILL_S_LO | PVD_KILL_S_HI;
  753. }
  754. switch ((d >> 7) & 3) {
  755. case 1:
  756. pvid->debug_p &= ~(PVD_KILL_S_LO | PVD_KILL_S_HI);
  757. pvid->debug_p |= PVD_FORCE_S;
  758. break;
  759. case 2:
  760. pvid->debug_p &= ~PVD_KILL_A;
  761. pvid->debug_p |= PVD_FORCE_A;
  762. break;
  763. case 3:
  764. pvid->debug_p &= ~PVD_KILL_B;
  765. pvid->debug_p |= PVD_FORCE_B;
  766. break;
  767. }
  768. break;
  769. }
  770. }
  771. static u32 VideoSr(const struct PicoVideo *pv)
  772. {
  773. unsigned int hp = pv->reg[12]&1 ? 15*488/210+1 : 15*488/171+1; // HBLANK start
  774. unsigned int hl = pv->reg[12]&1 ? 37*488/210+1 : 28*488/171+1; // HBLANK len
  775. unsigned int c;
  776. u32 d = pv->status;
  777. c = SekCyclesDone() - Pico.t.m68c_line_start;
  778. if (c - hp < hl)
  779. d |= SR_HB;
  780. PicoVideoFIFOSync(c);
  781. if (VdpFIFO.fifo_total >= 4)
  782. d |= SR_FULL;
  783. else if (!VdpFIFO.fifo_total)
  784. d |= SR_EMPT;
  785. return d;
  786. }
  787. PICO_INTERNAL_ASM u32 PicoVideoRead(u32 a)
  788. {
  789. a &= 0x1c;
  790. if (a == 0x04) // control port
  791. {
  792. struct PicoVideo *pv = &Pico.video;
  793. u32 d = VideoSr(pv);
  794. if (pv->pending) {
  795. CommandChange(pv);
  796. pv->pending = 0;
  797. }
  798. elprintf(EL_SR, "SR read: %04x [%u] @ %06x", d, SekCyclesDone(), SekPc);
  799. return d;
  800. }
  801. // H-counter info (based on Generator):
  802. // frame:
  803. // | <- hblank? -> |
  804. // start <416> hint <36> hdisplay <38> end // CPU cycles
  805. // |---------...---------|------------|-------------|
  806. // 0 B6 E4 FF // 40 cells
  807. // 0 93 E8 FF // 32 cells
  808. // Gens (?) v-render
  809. // start <hblank=84> hint hdisplay <404> |
  810. // |---------------------|--------------------------|
  811. // E4 (hc[0x43]==0) 07 B1 // 40
  812. // E8 (hc[0x45]==0) 05 91 // 32
  813. // check: Sonic 3D Blast bonus, Cannon Fodder, Chase HQ II, 3 Ninjas kick back, Road Rash 3, Skitchin', Wheel of Fortune
  814. if ((a&0x1c)==0x08)
  815. {
  816. unsigned int c;
  817. u32 d;
  818. c = (SekCyclesDone() - Pico.t.m68c_line_start) & 0x1ff; // FIXME
  819. if (Pico.video.reg[0]&2)
  820. d = Pico.video.hv_latch;
  821. else if (Pico.video.reg[12]&1)
  822. d = hcounts_40[c/2] | (Pico.video.v_counter << 8);
  823. else d = hcounts_32[c/2] | (Pico.video.v_counter << 8);
  824. elprintf(EL_HVCNT, "hv: %02x %02x [%u] @ %06x", d, Pico.video.v_counter, SekCyclesDone(), SekPc);
  825. return d;
  826. }
  827. if (a==0x00) // data port
  828. {
  829. return VideoRead(0);
  830. }
  831. return 0;
  832. }
  833. unsigned char PicoVideoRead8DataH(int is_from_z80)
  834. {
  835. return VideoRead(is_from_z80) >> 8;
  836. }
  837. unsigned char PicoVideoRead8DataL(int is_from_z80)
  838. {
  839. return VideoRead(is_from_z80);
  840. }
  841. unsigned char PicoVideoRead8CtlH(int is_from_z80)
  842. {
  843. struct PicoVideo *pv = &Pico.video;
  844. u8 d = VideoSr(pv) >> 8;
  845. if (pv->pending) {
  846. CommandChange(pv);
  847. pv->pending = 0;
  848. }
  849. elprintf(EL_SR, "SR read (h): %02x @ %06x", d, SekPc);
  850. return d;
  851. }
  852. unsigned char PicoVideoRead8CtlL(int is_from_z80)
  853. {
  854. struct PicoVideo *pv = &Pico.video;
  855. u8 d = VideoSr(pv);
  856. if (pv->pending) {
  857. CommandChange(pv);
  858. pv->pending = 0;
  859. }
  860. elprintf(EL_SR, "SR read (l): %02x @ %06x", d, SekPc);
  861. return d;
  862. }
  863. unsigned char PicoVideoRead8HV_H(int is_from_z80)
  864. {
  865. elprintf(EL_HVCNT, "vcounter: %02x [%u] @ %06x", Pico.video.v_counter, SekCyclesDone(), SekPc);
  866. return Pico.video.v_counter;
  867. }
  868. // FIXME: broken
  869. unsigned char PicoVideoRead8HV_L(int is_from_z80)
  870. {
  871. u32 d = (SekCyclesDone() - Pico.t.m68c_line_start) & 0x1ff; // FIXME
  872. if (Pico.video.reg[0]&2)
  873. d = Pico.video.hv_latch;
  874. else if (Pico.video.reg[12]&1)
  875. d = hcounts_40[d/2];
  876. else d = hcounts_32[d/2];
  877. elprintf(EL_HVCNT, "hcounter: %02x [%u] @ %06x", d, SekCyclesDone(), SekPc);
  878. return d;
  879. }
  880. void PicoVideoCacheSAT(void)
  881. {
  882. struct PicoVideo *pv = &Pico.video;
  883. int l;
  884. SATaddr = ((pv->reg[5]&0x7f) << 9) | ((pv->reg[6]&0x20) << 11);
  885. SATmask = ~0x1ff;
  886. if (pv->reg[12]&1)
  887. SATaddr &= ~0x200, SATmask &= ~0x200; // H40, zero lowest SAT bit
  888. // rebuild SAT cache XXX wrong since cache and memory can differ
  889. for (l = 0; l < 80; l++) {
  890. ((u16 *)VdpSATCache)[l*2 ] = PicoMem.vram[(SATaddr>>1) + l*4 ];
  891. ((u16 *)VdpSATCache)[l*2 + 1] = PicoMem.vram[(SATaddr>>1) + l*4 + 1];
  892. }
  893. Pico.est.rendstatus |= PDRAW_SPRITES_MOVED;
  894. }
  895. void PicoVideoSave(void)
  896. {
  897. struct VdpFIFO *vf = &VdpFIFO;
  898. struct PicoVideo *pv = &Pico.video;
  899. int l, x;
  900. // account for all outstanding xfers XXX kludge, entry attr's not saved
  901. for (l = vf->fifo_ql, x = vf->fifo_qx + l-1; l > 1; l--, x--)
  902. pv->fifo_cnt += (vf->fifo_queue[x&7] >> 3) << (vf->fifo_queue[x&7] & FQ_BYTE);
  903. }
  904. void PicoVideoLoad(void)
  905. {
  906. struct VdpFIFO *vf = &VdpFIFO;
  907. struct PicoVideo *pv = &Pico.video;
  908. // convert former dma_xfers (why was this in PicoMisc anyway?)
  909. if (Pico.m.dma_xfers) {
  910. pv->status |= SR_DMA|PVS_FIFORUN;
  911. pv->fifo_cnt = Pico.m.dma_xfers * (pv->type == 1 ? 2 : 1);
  912. vf->fifo_total = Pico.m.dma_xfers;
  913. Pico.m.dma_xfers = 0;
  914. }
  915. PicoVideoCacheSAT();
  916. }
  917. // vim:shiftwidth=2:ts=2:expandtab