videoport.c 35 KB

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