cff531af |
1 | /*\r |
2 | * PicoDrive\r |
3 | * (c) Copyright Dave, 2004\r |
4 | * (C) notaz, 2006-2009\r |
5 | *\r |
6 | * This work is licensed under the terms of MAME license.\r |
7 | * See COPYING file in the top-level directory.\r |
8 | */\r |
cc68a136 |
9 | \r |
efcba75f |
10 | #include "pico_int.h"\r |
0c7d1ba3 |
11 | #define NEED_DMA_SOURCE\r |
7feeb880 |
12 | #include "memory.h"\r |
cc68a136 |
13 | \r |
53f948c9 |
14 | int line_base_cycles;\r |
cc68a136 |
15 | extern const unsigned char hcounts_32[];\r |
16 | extern const unsigned char hcounts_40[];\r |
cc68a136 |
17 | \r |
eff55556 |
18 | #ifndef UTYPES_DEFINED\r |
ab0607f7 |
19 | typedef unsigned char u8;\r |
cc68a136 |
20 | typedef unsigned short u16;\r |
eff55556 |
21 | typedef unsigned int u32;\r |
22 | #define UTYPES_DEFINED\r |
23 | #endif\r |
cc68a136 |
24 | \r |
0c7d1ba3 |
25 | int (*PicoDmaHook)(unsigned int source, int len, unsigned short **base, unsigned int *mask) = NULL;\r |
cc68a136 |
26 | \r |
69996cb7 |
27 | static __inline void AutoIncrement(void)\r |
cc68a136 |
28 | {\r |
29 | Pico.video.addr=(unsigned short)(Pico.video.addr+Pico.video.reg[0xf]);\r |
30 | }\r |
31 | \r |
32 | static void VideoWrite(u16 d)\r |
33 | {\r |
34 | unsigned int a=Pico.video.addr;\r |
35 | \r |
36 | switch (Pico.video.type)\r |
37 | {\r |
38 | case 1: if(a&1) d=(u16)((d<<8)|(d>>8)); // If address is odd, bytes are swapped (which game needs this?)\r |
39 | Pico.vram [(a>>1)&0x7fff]=d;\r |
947fb5f9 |
40 | if (a - ((unsigned)(Pico.video.reg[5]&0x7f) << 9) < 0x400)\r |
ea38612f |
41 | Pico.est.rendstatus |= PDRAW_DIRTY_SPRITES;\r |
947fb5f9 |
42 | break;\r |
cc68a136 |
43 | case 3: Pico.m.dirtyPal = 1;\r |
cc68a136 |
44 | Pico.cram [(a>>1)&0x003f]=d; break; // wraps (Desert Strike)\r |
45 | case 5: Pico.vsram[(a>>1)&0x003f]=d; break;\r |
d26dc685 |
46 | //default:elprintf(EL_ANOMALY, "VDP write %04x with bad type %i", d, Pico.video.type); break;\r |
cc68a136 |
47 | }\r |
48 | \r |
cc68a136 |
49 | AutoIncrement();\r |
50 | }\r |
51 | \r |
69996cb7 |
52 | static unsigned int VideoRead(void)\r |
cc68a136 |
53 | {\r |
54 | unsigned int a=0,d=0;\r |
55 | \r |
56 | a=Pico.video.addr; a>>=1;\r |
57 | \r |
58 | switch (Pico.video.type)\r |
59 | {\r |
60 | case 0: d=Pico.vram [a&0x7fff]; break;\r |
61 | case 8: d=Pico.cram [a&0x003f]; break;\r |
62 | case 4: d=Pico.vsram[a&0x003f]; break;\r |
69996cb7 |
63 | default:elprintf(EL_ANOMALY, "VDP read with bad type %i", Pico.video.type); break;\r |
cc68a136 |
64 | }\r |
4f672280 |
65 | \r |
cc68a136 |
66 | AutoIncrement();\r |
67 | return d;\r |
68 | }\r |
69 | \r |
69996cb7 |
70 | static int GetDmaLength(void)\r |
cc68a136 |
71 | {\r |
72 | struct PicoVideo *pvid=&Pico.video;\r |
73 | int len=0;\r |
74 | // 16-bit words to transfer:\r |
75 | len =pvid->reg[0x13];\r |
76 | len|=pvid->reg[0x14]<<8;\r |
0c7d1ba3 |
77 | len = ((len - 1) & 0xffff) + 1;\r |
cc68a136 |
78 | return len;\r |
79 | }\r |
80 | \r |
0c7d1ba3 |
81 | static void DmaSlow(int len, unsigned int source)\r |
cc68a136 |
82 | {\r |
0c7d1ba3 |
83 | u32 inc = Pico.video.reg[0xf];\r |
84 | u32 a = Pico.video.addr;\r |
85 | u16 *r, *base = NULL;\r |
86 | u32 mask = 0x1ffff;\r |
cc68a136 |
87 | \r |
0c7d1ba3 |
88 | elprintf(EL_VDPDMA, "DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%u] @ %06x",\r |
312e9ce1 |
89 | Pico.video.type, source, a, len, inc, (Pico.video.status&8)||!(Pico.video.reg[1]&0x40),\r |
69996cb7 |
90 | SekCyclesDone(), SekPc);\r |
cc68a136 |
91 | \r |
2aa27095 |
92 | Pico.m.dma_xfers += len;\r |
0c7d1ba3 |
93 | if (Pico.m.dma_xfers < len) // lame 16bit var\r |
94 | Pico.m.dma_xfers = ~0;\r |
ae214f1c |
95 | SekCyclesBurnRun(CheckDMA());\r |
672ad671 |
96 | \r |
0c7d1ba3 |
97 | if ((source & 0xe00000) == 0xe00000) { // Ram\r |
98 | base = (u16 *)Pico.ram;\r |
99 | mask = 0xffff;\r |
602133e1 |
100 | }\r |
101 | else if (PicoAHW & PAHW_MCD)\r |
102 | {\r |
0c7d1ba3 |
103 | u8 r3 = Pico_mcd->s68k_regs[3];\r |
104 | elprintf(EL_VDPDMA, "DmaSlow CD, r3=%02x", r3);\r |
105 | if (source < 0x20000) { // Bios area\r |
106 | base = (u16 *)Pico_mcd->bios;\r |
107 | } else if ((source & 0xfc0000) == 0x200000) { // Word Ram\r |
108 | if (!(r3 & 4)) { // 2M mode\r |
109 | base = (u16 *)(Pico_mcd->word_ram2M + (source & 0x20000));\r |
ab0607f7 |
110 | } else {\r |
fa1e5e29 |
111 | if (source < 0x220000) { // 1M mode\r |
0c7d1ba3 |
112 | int bank = r3 & 1;\r |
113 | base = (u16 *)(Pico_mcd->word_ram1M[bank]);\r |
69996cb7 |
114 | } else {\r |
0c7d1ba3 |
115 | DmaSlowCell(source - 2, a, len, inc);\r |
fa1e5e29 |
116 | return;\r |
69996cb7 |
117 | }\r |
ab0607f7 |
118 | }\r |
0c7d1ba3 |
119 | source -= 2;\r |
120 | } else if ((source & 0xfe0000) == 0x020000) { // Prg Ram\r |
121 | base = (u16 *)Pico_mcd->prg_ram_b[r3 >> 6];\r |
122 | source -= 2; // XXX: test\r |
ab0607f7 |
123 | }\r |
602133e1 |
124 | }\r |
125 | else\r |
126 | {\r |
50483b53 |
127 | // if we have DmaHook, let it handle ROM because of possible DMA delay\r |
0c7d1ba3 |
128 | u32 source2;\r |
129 | if (PicoDmaHook && (source2 = PicoDmaHook(source, len, &base, &mask)))\r |
130 | source = source2;\r |
131 | else // Rom\r |
132 | base = m68k_dma_source(source);\r |
ab0607f7 |
133 | }\r |
0c7d1ba3 |
134 | if (!base) {\r |
135 | elprintf(EL_VDPDMA|EL_ANOMALY, "DmaSlow[%i] %06x->%04x: invalid src", Pico.video.type, source, a);\r |
136 | return;\r |
672ad671 |
137 | }\r |
cc68a136 |
138 | \r |
0c7d1ba3 |
139 | // operate in words\r |
140 | source >>= 1;\r |
141 | mask >>= 1;\r |
142 | \r |
cc68a136 |
143 | switch (Pico.video.type)\r |
144 | {\r |
145 | case 1: // vram\r |
146 | r = Pico.vram;\r |
0c7d1ba3 |
147 | if (inc == 2 && !(a & 1) && a + len * 2 < 0x10000\r |
148 | && !(((source + len - 1) ^ source) & ~mask))\r |
cc68a136 |
149 | {\r |
cea65903 |
150 | // most used DMA mode\r |
0c7d1ba3 |
151 | memcpy((char *)r + a, base + (source & mask), len * 2);\r |
152 | a += len * 2;\r |
cea65903 |
153 | }\r |
154 | else\r |
155 | {\r |
156 | for(; len; len--)\r |
157 | {\r |
0c7d1ba3 |
158 | u16 d = base[source++ & mask];\r |
159 | if(a & 1) d=(d<<8)|(d>>8);\r |
160 | r[a >> 1] = d;\r |
cea65903 |
161 | // AutoIncrement\r |
0c7d1ba3 |
162 | a = (u16)(a + inc);\r |
cea65903 |
163 | }\r |
cc68a136 |
164 | }\r |
ea38612f |
165 | Pico.est.rendstatus |= PDRAW_DIRTY_SPRITES;\r |
cc68a136 |
166 | break;\r |
4f672280 |
167 | \r |
cc68a136 |
168 | case 3: // cram\r |
cc68a136 |
169 | Pico.m.dirtyPal = 1;\r |
170 | r = Pico.cram;\r |
0c7d1ba3 |
171 | for (; len; len--)\r |
cc68a136 |
172 | {\r |
0c7d1ba3 |
173 | r[(a / 2) & 0x3f] = base[source++ & mask];\r |
cc68a136 |
174 | // AutoIncrement\r |
0c7d1ba3 |
175 | a += inc;\r |
cc68a136 |
176 | }\r |
cc68a136 |
177 | break;\r |
178 | \r |
0c7d1ba3 |
179 | case 5: // vsram\r |
cc68a136 |
180 | r = Pico.vsram;\r |
0c7d1ba3 |
181 | for (; len; len--)\r |
cc68a136 |
182 | {\r |
0c7d1ba3 |
183 | r[(a / 2) & 0x3f] = base[source++ & mask];\r |
cc68a136 |
184 | // AutoIncrement\r |
0c7d1ba3 |
185 | a += inc;\r |
cc68a136 |
186 | }\r |
cc68a136 |
187 | break;\r |
69996cb7 |
188 | \r |
189 | default:\r |
e7b3ad1b |
190 | if (Pico.video.type != 0 || (EL_LOGMASK & EL_VDPDMA))\r |
191 | elprintf(EL_VDPDMA|EL_ANOMALY, "DMA with bad type %i", Pico.video.type);\r |
69996cb7 |
192 | break;\r |
cc68a136 |
193 | }\r |
194 | // remember addr\r |
195 | Pico.video.addr=(u16)a;\r |
196 | }\r |
197 | \r |
198 | static void DmaCopy(int len)\r |
199 | {\r |
200 | u16 a=Pico.video.addr;\r |
201 | unsigned char *vr = (unsigned char *) Pico.vram;\r |
cc68a136 |
202 | unsigned char inc=Pico.video.reg[0xf];\r |
203 | int source;\r |
69996cb7 |
204 | elprintf(EL_VDPDMA, "DmaCopy len %i [%i]", len, SekCyclesDone());\r |
4f672280 |
205 | \r |
69996cb7 |
206 | Pico.m.dma_xfers += len;\r |
0c7d1ba3 |
207 | if (Pico.m.dma_xfers < len)\r |
208 | Pico.m.dma_xfers = ~0;\r |
2aa27095 |
209 | Pico.video.status |= 2; // dma busy\r |
cc68a136 |
210 | \r |
211 | source =Pico.video.reg[0x15];\r |
212 | source|=Pico.video.reg[0x16]<<8;\r |
cc68a136 |
213 | \r |
2aa27095 |
214 | for (; len; len--)\r |
cc68a136 |
215 | {\r |
0c7d1ba3 |
216 | vr[a] = vr[source++ & 0xffff];\r |
cc68a136 |
217 | // AutoIncrement\r |
218 | a=(u16)(a+inc);\r |
219 | }\r |
220 | // remember addr\r |
221 | Pico.video.addr=a;\r |
ea38612f |
222 | Pico.est.rendstatus |= PDRAW_DIRTY_SPRITES;\r |
cc68a136 |
223 | }\r |
224 | \r |
0c7d1ba3 |
225 | static NOINLINE void DmaFill(int data)\r |
cc68a136 |
226 | {\r |
cc68a136 |
227 | unsigned short a=Pico.video.addr;\r |
228 | unsigned char *vr=(unsigned char *) Pico.vram;\r |
229 | unsigned char high = (unsigned char) (data >> 8);\r |
230 | unsigned char inc=Pico.video.reg[0xf];\r |
0c7d1ba3 |
231 | int source;\r |
232 | int len, l;\r |
4f672280 |
233 | \r |
0c7d1ba3 |
234 | len = GetDmaLength();\r |
69996cb7 |
235 | elprintf(EL_VDPDMA, "DmaFill len %i inc %i [%i]", len, inc, SekCyclesDone());\r |
4f672280 |
236 | \r |
69996cb7 |
237 | Pico.m.dma_xfers += len;\r |
0c7d1ba3 |
238 | if (Pico.m.dma_xfers < len) // lame 16bit var\r |
239 | Pico.m.dma_xfers = ~0;\r |
2aa27095 |
240 | Pico.video.status |= 2; // dma busy\r |
cc68a136 |
241 | \r |
0c7d1ba3 |
242 | switch (Pico.video.type)\r |
243 | {\r |
244 | case 1: // vram\r |
245 | for (l = len; l; l--) {\r |
246 | // Write upper byte to adjacent address\r |
247 | // (here we are byteswapped, so address is already 'adjacent')\r |
248 | vr[a] = high;\r |
cc68a136 |
249 | \r |
0c7d1ba3 |
250 | // Increment address register\r |
251 | a = (u16)(a + inc);\r |
252 | }\r |
253 | break;\r |
254 | case 3: // cram\r |
255 | case 5: { // vsram\r |
256 | // TODO: needs fifo; anyone using these?\r |
257 | static int once;\r |
258 | if (!once++)\r |
259 | elprintf(EL_STATUS|EL_ANOMALY|EL_VDPDMA, "TODO: cram/vsram fill");\r |
260 | }\r |
261 | default:\r |
262 | a += len * inc;\r |
263 | break;\r |
cc68a136 |
264 | }\r |
0c7d1ba3 |
265 | \r |
cc68a136 |
266 | // remember addr\r |
0c7d1ba3 |
267 | Pico.video.addr = a;\r |
268 | // register update\r |
269 | Pico.video.reg[0x13] = Pico.video.reg[0x14] = 0;\r |
270 | source = Pico.video.reg[0x15];\r |
271 | source |= Pico.video.reg[0x16] << 8;\r |
272 | source += len;\r |
273 | Pico.video.reg[0x15] = source;\r |
274 | Pico.video.reg[0x16] = source >> 8;\r |
cc68a136 |
275 | \r |
ea38612f |
276 | Pico.est.rendstatus |= PDRAW_DIRTY_SPRITES;\r |
cc68a136 |
277 | }\r |
278 | \r |
0c7d1ba3 |
279 | static NOINLINE void CommandDma(void)\r |
cc68a136 |
280 | {\r |
281 | struct PicoVideo *pvid=&Pico.video;\r |
0c7d1ba3 |
282 | u32 len, method;\r |
283 | u32 source;\r |
cc68a136 |
284 | \r |
285 | if ((pvid->reg[1]&0x10)==0) return; // DMA not enabled\r |
286 | \r |
0c7d1ba3 |
287 | len = GetDmaLength();\r |
288 | source =Pico.video.reg[0x15];\r |
289 | source|=Pico.video.reg[0x16] << 8;\r |
290 | source|=Pico.video.reg[0x17] << 16;\r |
cc68a136 |
291 | \r |
292 | method=pvid->reg[0x17]>>6;\r |
0c7d1ba3 |
293 | if (method < 2)\r |
294 | DmaSlow(len, source << 1); // 68000 to VDP\r |
295 | else if (method == 3)\r |
296 | DmaCopy(len); // VRAM Copy\r |
297 | else\r |
298 | return;\r |
299 | \r |
300 | source += len;\r |
301 | Pico.video.reg[0x13] = Pico.video.reg[0x14] = 0;\r |
302 | Pico.video.reg[0x15] = source;\r |
303 | Pico.video.reg[0x16] = source >> 8;\r |
cc68a136 |
304 | }\r |
305 | \r |
69996cb7 |
306 | static void CommandChange(void)\r |
cc68a136 |
307 | {\r |
308 | struct PicoVideo *pvid=&Pico.video;\r |
309 | unsigned int cmd=0,addr=0;\r |
310 | \r |
311 | cmd=pvid->command;\r |
312 | \r |
313 | // Get type of transfer 0xc0000030 (v/c/vsram read/write)\r |
314 | pvid->type=(unsigned char)(((cmd>>2)&0xc)|(cmd>>30));\r |
315 | \r |
316 | // Get address 0x3fff0003\r |
317 | addr =(cmd>>16)&0x3fff;\r |
318 | addr|=(cmd<<14)&0xc000;\r |
319 | pvid->addr=(unsigned short)addr;\r |
cc68a136 |
320 | }\r |
321 | \r |
697746df |
322 | static void DrawSync(int blank_on)\r |
b6d7ac70 |
323 | {\r |
324 | if (Pico.m.scanline < 224 && !(PicoOpt & POPT_ALT_RENDERER) &&\r |
ea38612f |
325 | !PicoSkipFrame && Pico.est.DrawScanline <= Pico.m.scanline) {\r |
2aa27095 |
326 | //elprintf(EL_ANOMALY, "sync");\r |
b6d7ac70 |
327 | PicoDrawSync(Pico.m.scanline, blank_on);\r |
328 | }\r |
329 | }\r |
330 | \r |
eff55556 |
331 | PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)\r |
cc68a136 |
332 | {\r |
333 | struct PicoVideo *pvid=&Pico.video;\r |
334 | \r |
2aa27095 |
335 | //if (Pico.m.scanline < 224)\r |
336 | // elprintf(EL_STATUS, "PicoVideoWrite [%06x] %04x", a, d);\r |
cc68a136 |
337 | a&=0x1c;\r |
338 | \r |
339 | if (a==0x00) // Data port 0 or 2\r |
4f672280 |
340 | {\r |
b6d7ac70 |
341 | // try avoiding the sync..\r |
342 | if (Pico.m.scanline < 224 && (pvid->reg[1]&0x40) &&\r |
343 | !(!pvid->pending &&\r |
344 | ((pvid->command & 0xc00000f0) == 0x40000010 && Pico.vsram[pvid->addr>>1] == d))\r |
345 | )\r |
346 | DrawSync(0);\r |
347 | \r |
69996cb7 |
348 | if (pvid->pending) {\r |
349 | CommandChange();\r |
350 | pvid->pending=0;\r |
351 | }\r |
cc68a136 |
352 | \r |
0c7d1ba3 |
353 | // preliminary FIFO emulation for Chaos Engine, The (E)\r |
354 | if (!(pvid->status&8) && (pvid->reg[1]&0x40) && !(PicoOpt&POPT_DIS_VDP_FIFO)) // active display?\r |
cc68a136 |
355 | {\r |
0c7d1ba3 |
356 | pvid->status&=~0x200; // FIFO no longer empty\r |
357 | pvid->lwrite_cnt++;\r |
358 | if (pvid->lwrite_cnt >= 4) pvid->status|=0x100; // FIFO full\r |
359 | if (pvid->lwrite_cnt > 4) {\r |
360 | SekCyclesBurnRun(32); // penalty // 488/12-8\r |
69996cb7 |
361 | }\r |
0c7d1ba3 |
362 | elprintf(EL_ASVDP, "VDP data write: %04x [%06x] {%i} #%i @ %06x", d, Pico.video.addr,\r |
363 | Pico.video.type, pvid->lwrite_cnt, SekPc);\r |
cc68a136 |
364 | }\r |
0c7d1ba3 |
365 | VideoWrite(d);\r |
366 | \r |
367 | if ((pvid->command&0x80) && (pvid->reg[1]&0x10) && (pvid->reg[0x17]>>6)==2)\r |
368 | DmaFill(d);\r |
369 | \r |
cc68a136 |
370 | return;\r |
371 | }\r |
372 | \r |
373 | if (a==0x04) // Control (command) port 4 or 6\r |
374 | {\r |
b6d7ac70 |
375 | if (pvid->pending)\r |
cc68a136 |
376 | {\r |
377 | // Low word of command:\r |
0c7d1ba3 |
378 | pvid->command &= 0xffff0000;\r |
379 | pvid->command |= d;\r |
380 | pvid->pending = 0;\r |
cc68a136 |
381 | CommandChange();\r |
0c7d1ba3 |
382 | // Check for dma:\r |
383 | if (d & 0x80) {\r |
384 | DrawSync(0);\r |
385 | CommandDma();\r |
386 | }\r |
602133e1 |
387 | }\r |
388 | else\r |
389 | {\r |
390 | if ((d&0xc000)==0x8000)\r |
cc68a136 |
391 | {\r |
392 | // Register write:\r |
393 | int num=(d>>8)&0x1f;\r |
0ffefdb8 |
394 | int dold=pvid->reg[num];\r |
147f8df1 |
395 | int blank_on = 0;\r |
602133e1 |
396 | pvid->type=0; // register writes clear command (else no Sega logo in Golden Axe II)\r |
0ffefdb8 |
397 | if (num > 0x0a && !(pvid->reg[1]&4)) {\r |
398 | elprintf(EL_ANOMALY, "%02x written to reg %02x in SMS mode @ %06x", d, num, SekPc);\r |
602133e1 |
399 | return;\r |
b6d7ac70 |
400 | }\r |
602133e1 |
401 | \r |
53f948c9 |
402 | if (num == 1 && !(d&0x40) && SekCyclesDone() - line_base_cycles <= 488-390)\r |
403 | blank_on = 1;\r |
147f8df1 |
404 | DrawSync(blank_on);\r |
405 | pvid->reg[num]=(unsigned char)d;\r |
602133e1 |
406 | switch (num)\r |
407 | {\r |
408 | case 0x00:\r |
409 | elprintf(EL_INTSW, "hint_onoff: %i->%i [%i] pend=%i @ %06x", (dold&0x10)>>4,\r |
410 | (d&0x10)>>4, SekCyclesDone(), (pvid->pending_ints&0x10)>>4, SekPc);\r |
147f8df1 |
411 | goto update_irq;\r |
602133e1 |
412 | case 0x01:\r |
413 | elprintf(EL_INTSW, "vint_onoff: %i->%i [%i] pend=%i @ %06x", (dold&0x20)>>5,\r |
414 | (d&0x20)>>5, SekCyclesDone(), (pvid->pending_ints&0x20)>>5, SekPc);\r |
147f8df1 |
415 | goto update_irq;\r |
602133e1 |
416 | case 0x05:\r |
4c436138 |
417 | //elprintf(EL_STATUS, "spritep moved to %04x", (unsigned)(Pico.video.reg[5]&0x7f) << 9);\r |
ea38612f |
418 | if (d^dold) Pico.est.rendstatus |= PDRAW_SPRITES_MOVED;\r |
602133e1 |
419 | break;\r |
420 | case 0x0c:\r |
421 | // renderers should update their palettes if sh/hi mode is changed\r |
422 | if ((d^dold)&8) Pico.m.dirtyPal = 2;\r |
423 | break;\r |
424 | }\r |
147f8df1 |
425 | return;\r |
602133e1 |
426 | \r |
147f8df1 |
427 | update_irq:\r |
03e4f2a3 |
428 | #ifndef EMU_CORE_DEBUG\r |
b6d7ac70 |
429 | // update IRQ level\r |
08769494 |
430 | if (!SekShouldInterrupt()) // hack\r |
03e4f2a3 |
431 | {\r |
602133e1 |
432 | int lines, pints, irq=0;\r |
433 | lines = (pvid->reg[1] & 0x20) | (pvid->reg[0] & 0x10);\r |
434 | pints = (pvid->pending_ints&lines);\r |
b6d7ac70 |
435 | if (pints & 0x20) irq = 6;\r |
436 | else if (pints & 0x10) irq = 4;\r |
602133e1 |
437 | SekInterrupt(irq); // update line\r |
438 | \r |
2aa27095 |
439 | if (irq) SekEndRun(24); // make it delayed\r |
cc68a136 |
440 | }\r |
cc68a136 |
441 | #endif\r |
602133e1 |
442 | }\r |
443 | else\r |
444 | {\r |
cc68a136 |
445 | // High word of command:\r |
446 | pvid->command&=0x0000ffff;\r |
447 | pvid->command|=d<<16;\r |
448 | pvid->pending=1;\r |
449 | }\r |
450 | }\r |
451 | }\r |
452 | }\r |
453 | \r |
eff55556 |
454 | PICO_INTERNAL_ASM unsigned int PicoVideoRead(unsigned int a)\r |
cc68a136 |
455 | {\r |
cc68a136 |
456 | a&=0x1c;\r |
457 | \r |
cc68a136 |
458 | if (a==0x04) // control port\r |
459 | {\r |
69996cb7 |
460 | struct PicoVideo *pv=&Pico.video;\r |
b6d7ac70 |
461 | unsigned int d;\r |
69996cb7 |
462 | d=pv->status;\r |
9761a7d0 |
463 | //if (PicoOpt&POPT_ALT_RENDERER) d|=0x0020; // sprite collision (Shadow of the Beast)\r |
53f948c9 |
464 | if (SekCyclesDone() - line_base_cycles >= 488-88)\r |
465 | d|=0x0004; // H-Blank (Sonic3 vs)\r |
69996cb7 |
466 | \r |
9761a7d0 |
467 | d |= ((pv->reg[1]&0x40)^0x40) >> 3; // set V-Blank if display is disabled\r |
468 | d |= (pv->pending_ints&0x20)<<2; // V-int pending?\r |
69996cb7 |
469 | if (d&0x100) pv->status&=~0x100; // FIFO no longer full\r |
cc68a136 |
470 | \r |
9761a7d0 |
471 | pv->pending = 0; // ctrl port reads clear write-pending flag (Charles MacDonald)\r |
cc68a136 |
472 | \r |
69996cb7 |
473 | elprintf(EL_SR, "SR read: %04x @ %06x", d, SekPc);\r |
b6d7ac70 |
474 | return d;\r |
cc68a136 |
475 | }\r |
476 | \r |
477 | // H-counter info (based on Generator):\r |
478 | // frame:\r |
479 | // | <- hblank? -> |\r |
480 | // start <416> hint <36> hdisplay <38> end // CPU cycles\r |
481 | // |---------...---------|------------|-------------|\r |
482 | // 0 B6 E4 FF // 40 cells\r |
483 | // 0 93 E8 FF // 32 cells\r |
484 | \r |
485 | // Gens (?) v-render\r |
486 | // start <hblank=84> hint hdisplay <404> |\r |
487 | // |---------------------|--------------------------|\r |
488 | // E4 (hc[0x43]==0) 07 B1 // 40\r |
489 | // E8 (hc[0x45]==0) 05 91 // 32\r |
4f672280 |
490 | \r |
cc68a136 |
491 | // check: Sonic 3D Blast bonus, Cannon Fodder, Chase HQ II, 3 Ninjas kick back, Road Rash 3, Skitchin', Wheel of Fortune\r |
492 | if ((a&0x1c)==0x08)\r |
493 | {\r |
9761a7d0 |
494 | unsigned int d;\r |
947fb5f9 |
495 | \r |
53f948c9 |
496 | d = (SekCyclesDone() - line_base_cycles) & 0x1ff; // FIXME\r |
2aa27095 |
497 | if (Pico.video.reg[12]&1)\r |
53f948c9 |
498 | d = hcounts_40[d];\r |
499 | else d = hcounts_32[d];\r |
cc68a136 |
500 | \r |
9761a7d0 |
501 | elprintf(EL_HVCNT, "hv: %02x %02x (%i) @ %06x", d, Pico.video.v_counter, SekCyclesDone(), SekPc);\r |
502 | return d | (Pico.video.v_counter << 8);\r |
503 | }\r |
cc68a136 |
504 | \r |
9761a7d0 |
505 | if (a==0x00) // data port\r |
506 | {\r |
507 | return VideoRead();\r |
508 | }\r |
cc68a136 |
509 | \r |
9761a7d0 |
510 | return 0;\r |
511 | }\r |
512 | \r |
513 | unsigned int PicoVideoRead8(unsigned int a)\r |
514 | {\r |
515 | unsigned int d;\r |
516 | a&=0x1d;\r |
517 | \r |
518 | switch (a)\r |
519 | {\r |
520 | case 0: return VideoRead() >> 8;\r |
521 | case 1: return VideoRead() & 0xff;\r |
522 | case 4: // control port/status reg\r |
523 | d = Pico.video.status >> 8;\r |
524 | if (d&1) Pico.video.status&=~0x100; // FIFO no longer full\r |
525 | Pico.video.pending = 0;\r |
526 | elprintf(EL_SR, "SR read (h): %02x @ %06x", d, SekPc);\r |
527 | return d;\r |
528 | case 5:\r |
529 | d = Pico.video.status & 0xff;\r |
530 | //if (PicoOpt&POPT_ALT_RENDERER) d|=0x0020; // sprite collision (Shadow of the Beast)\r |
531 | d |= ((Pico.video.reg[1]&0x40)^0x40) >> 3; // set V-Blank if display is disabled\r |
532 | d |= (Pico.video.pending_ints&0x20)<<2; // V-int pending?\r |
53f948c9 |
533 | if (SekCyclesDone() - line_base_cycles >= 488-88) d |= 4; // H-Blank\r |
9761a7d0 |
534 | Pico.video.pending = 0;\r |
535 | elprintf(EL_SR, "SR read (l): %02x @ %06x", d, SekPc);\r |
536 | return d;\r |
537 | case 8: // hv counter\r |
538 | elprintf(EL_HVCNT, "vcounter: %02x (%i) @ %06x", Pico.video.v_counter, SekCyclesDone(), SekPc);\r |
539 | return Pico.video.v_counter;\r |
540 | case 9:\r |
53f948c9 |
541 | d = (SekCyclesDone() - line_base_cycles) & 0x1ff; // FIXME\r |
9761a7d0 |
542 | if (Pico.video.reg[12]&1)\r |
543 | d = hcounts_40[d];\r |
544 | else d = hcounts_32[d];\r |
545 | elprintf(EL_HVCNT, "hcounter: %02x (%i) @ %06x", d, SekCyclesDone(), SekPc);\r |
546 | return d;\r |
cc68a136 |
547 | }\r |
548 | \r |
b6d7ac70 |
549 | return 0;\r |
cc68a136 |
550 | }\r |
e7b3ad1b |
551 | \r |
552 | // vim:shiftwidth=2:ts=2:expandtab\r |