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