buggy port of gfx/cd, silpheed started working?
[picodrive.git] / Pico / cd / gfx_cd.c
1 // TODO...
2
3 // #include <string.h>
4 #include "../PicoInt.h"
5
6 #define rot_comp Pico_mcd->rot_comp
7
8 static const int Table_Rot_Time[] =
9 {
10         0x00054000, 0x00048000, 0x00040000, 0x00036000,          //; 008-032               ; briefing - sprite
11         0x0002E000, 0x00028000, 0x00024000, 0x00022000,          //; 036-064               ; arbre souvent
12         0x00021000, 0x00020000, 0x0001E000, 0x0001B800,          //; 068-096               ; map thunderstrike
13         0x00019800, 0x00017A00, 0x00015C00, 0x00013E00,          //; 100-128               ; logo défoncé
14
15         0x00012000, 0x00011800, 0x00011000, 0x00010800,          //; 132-160               ; briefing - map
16         0x00010000, 0x0000F800, 0x0000F000, 0x0000E800,          //; 164-192
17         0x0000E000, 0x0000D800, 0x0000D000, 0x0000C800,          //; 196-224
18         0x0000C000, 0x0000B800, 0x0000B000, 0x0000A800,          //; 228-256               ; batman visage
19
20         0x0000A000, 0x00009F00, 0x00009E00, 0x00009D00,          //; 260-288
21         0x00009C00, 0x00009B00, 0x00009A00, 0x00009900,          //; 292-320
22         0x00009800, 0x00009700, 0x00009600, 0x00009500,          //; 324-352
23         0x00009400, 0x00009300, 0x00009200, 0x00009100,          //; 356-384
24
25         0x00009000, 0x00008F00, 0x00008E00, 0x00008D00,          //; 388-416
26         0x00008C00, 0x00008B00, 0x00008A00, 0x00008900,          //; 420-448
27         0x00008800, 0x00008700, 0x00008600, 0x00008500,          //; 452-476
28         0x00008400, 0x00008300, 0x00008200, 0x00008100,          //; 480-512
29 };
30
31
32 #if 1*0
33 typedef struct
34 {
35         unsigned int Reg_58;    // Stamp_Size
36         unsigned int Reg_5A;
37         unsigned int Reg_5C;
38         unsigned int Reg_5E;
39         unsigned int Reg_60;
40         unsigned int Reg_62;
41         unsigned int Reg_64;    // V_Dot
42         unsigned int Reg_66;
43
44         unsigned int Stamp_Map_Adr;
45         unsigned int Buffer_Adr;
46         unsigned int Vector_Adr;
47         unsigned int Function;  // Jmp_Adr;
48         unsigned int Float_Part;
49         unsigned int Draw_Speed;
50
51         unsigned int XS;
52         unsigned int YS;
53         /*unsigned*/ int DXS;
54         /*unsigned*/ int DYS;
55         unsigned int XD;
56         unsigned int YD;
57         unsigned int XD_Mul;
58         unsigned int H_Dot;
59 } Rot_Comp;
60 #endif
61
62 static void gfx_cd_start(void)
63 {
64         int upd_len;
65
66         dprintf("gfx_cd_start()");
67
68         rot_comp.XD_Mul = ((rot_comp.Reg_5C & 0x1f) + 1) * 4;
69         rot_comp.Function = (rot_comp.Reg_58 & 7) | (Pico_mcd->s68k_regs[3] & 0x18);    // Jmp_Adr
70         rot_comp.Buffer_Adr = (rot_comp.Reg_5E & 0xfff8) << 2;
71         rot_comp.YD = (rot_comp.Reg_60 >> 3) & 7;
72         rot_comp.Vector_Adr = (rot_comp.Reg_66 & 0xfffe) << 2;
73
74         upd_len = (rot_comp.Reg_62 >> 3) & 0x3f;
75         upd_len = Table_Rot_Time[upd_len];
76         rot_comp.Draw_Speed = rot_comp.Float_Part = upd_len;
77
78         rot_comp.Reg_58 |= 0x8000;      // Stamp_Size,  we start a new GFX operation
79
80         switch (rot_comp.Reg_58 & 6)    // Scr_16?
81         {
82                 case 0: // ?
83                         rot_comp.Stamp_Map_Adr = (rot_comp.Reg_5A & 0xff80) << 2;
84                         break;
85                 case 2: // .Dot_32
86                         rot_comp.Stamp_Map_Adr = (rot_comp.Reg_5A & 0xffe0) << 2;
87                         break;
88                 case 4: // .Scr_16
89                         rot_comp.Stamp_Map_Adr = 0x20000;
90                         break;
91                 case 6: // .Scr_16_Dot_32
92                         rot_comp.Stamp_Map_Adr = (rot_comp.Reg_5A & 0xe000) << 2;
93                         break;
94         }
95
96         gfx_cd_update();
97 }
98
99
100 static void gfx_completed(void)
101 {
102         rot_comp.Reg_58 &= 0x7fff;      // Stamp_Size
103         rot_comp.Reg_64  = 0;
104         if (Pico_mcd->s68k_regs[0x33] & (1<<1))
105         {
106                 dprintf("gfx_cd irq 1");
107                 SekInterruptS68k(1);
108         }
109 }
110
111
112 static void gfx_do(void)
113 {
114         unsigned int eax, ebx, ecx, edx, esi, edi, pixel = 0;
115         unsigned int func = rot_comp.Function;
116         unsigned short *ptrs;
117
118         rot_comp.XD = rot_comp.Reg_60 & 7;
119         rot_comp.Buffer_Adr = ((rot_comp.Reg_5E & 0xfff8) + rot_comp.YD) << 2;
120         rot_comp.H_Dot = rot_comp.Reg_62 & 0x1ff;
121         ecx = *(unsigned int *)(Pico_mcd->word_ram2M + rot_comp.Vector_Adr);
122         edx = ecx >> 16;
123         ecx = (ecx & 0xffff) << 8;
124         edx <<= 8;
125         rot_comp.DXS = *(int *)(Pico_mcd->word_ram2M + rot_comp.Vector_Adr + 4);
126         rot_comp.DYS =  rot_comp.DXS >> 16;
127         rot_comp.DXS = (rot_comp.DXS << 16) >> 16; // sign extend
128         rot_comp.Vector_Adr += 8;
129         //if ((rot_comp.H_Dot & 0x1ff) == 0)
130         //      goto nothing_to_draw;
131
132         // MAKE_IMAGE_LINE
133         while (rot_comp.H_Dot)
134         {
135                 if (func & 2)           // mode 32x32 dot
136                 {
137                         if (func & 4)   // 16x16 screen
138                         {
139                                 eax = (ecx >> (11+5)) & 0x7f;
140                                 ebx = (edx >> (11-2)) & 0x3f80;
141                         }
142                         else            // 1x1 screen
143                         {
144                                 eax = (ecx >> (11+5)) & 0x0f;
145                                 ebx = (edx >> (11+2)) & 0x38;
146                         }
147                 }
148                 else                    // mode 16x16 dot
149                 {
150                         if (func & 4)   // 16x16 screen
151                         {
152                                 eax = (ecx >> (11+4)) & 0xff;
153                                 ebx = (edx >> (11-4)) & 0xff00;
154                         }
155                         else            // 1x1 screen
156                         {
157                                 eax = (ecx >> (11+4)) & 0x0f;
158                                 ebx = (edx >> (11+0)) & 0xf0;
159                         }
160                 }
161                 ebx += eax;
162
163                 esi = rot_comp.Stamp_Map_Adr;
164                 ptrs = (unsigned short *) (Pico_mcd->word_ram2M + rot_comp.Stamp_Map_Adr + ebx*2);
165                 edi = ptrs[0] | (ptrs[1] << 16);
166
167                 // MAKE_IMAGE_PIXEL
168                 if (!(func & 1))        // NOT TILED
169                 {
170                         if (func & 4)   // 16x16 screen
171                         {
172                                 if ((edx & 0x00800000) || (ecx & 0x00800000)) goto Pixel_Out;
173                         }
174                         else            // 1x1 screen
175                         {
176                                 if ((edx & 0x00f80000) || (ecx & 0x00f80000)) goto Pixel_Out;
177                         }
178                 }
179                 esi = edi;
180                 edi >>= (11+1);
181                 esi = (esi & 0x7ff) << 7;
182                 if (!esi) goto Pixel_Out;
183                 edi &= (0x1c>>1);
184                 eax = ecx;
185                 ebx = edx;
186                 if (func & 2) edi |= 1; // 32 dots?
187                 switch (edi)
188                 {
189                         case 0x00:      // No_Flip_0, 16x16 dots
190                                 ebx = (ebx >> 9) & 0x3c;
191                                 ebx += esi;
192                                 edi = (eax & 0x3800) ^ 0x1000;          // bswap
193                                 eax = ((eax >> 8) & 0x40) + ebx;
194                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
195                                 if (!(edi & 0x800)) pixel >>= 4;
196                                 break;
197                         case 0x01:      // No_Flip_0, 32x32 dots
198                                 ebx = (ebx >> 9) & 0x7c;
199                                 ebx += esi;
200                                 edi = (eax & 0x3800) ^ 0x1000;          // bswap
201                                 eax = ((eax >> 7) & 0x180) + ebx;
202                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
203                                 if (!(edi & 0x800)) pixel >>= 4;
204                                 break;
205                         case 0x02:      // No_Flip_90, 16x16 dots
206                                 eax = (eax >> 9) & 0x3c;
207                                 eax += esi;
208                                 edi = (ebx & 0x3800) ^ 0x2800;          // bswap
209                                 eax += ((ebx >> 8) & 0x40) ^ 0x40;
210                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
211                                 if (!(edi & 0x800)) pixel >>= 4;
212                                 break;
213                         case 0x03:      // No_Flip_90, 32x32 dots
214                                 eax = (eax >> 9) & 0x7c;
215                                 eax += esi;
216                                 edi = (ebx & 0x3800) ^ 0x2800;          // bswap
217                                 eax += (ebx >> 7) & 0x180;
218                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
219                                 if (!(edi & 0x800)) pixel >>= 4;
220                                 break;
221                         case 0x04:      // No_Flip_180, 16x16 dots
222                                 ebx = ((ebx >> 9) & 0x3c) ^ 0x3c;
223                                 ebx += esi;
224                                 edi = (eax & 0x3800) ^ 0x2800;          // bswap and flip
225                                 eax = (((eax >> 8) & 0x40) ^ 0x40) + ebx;
226                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
227                                 if (!(edi & 0x800)) pixel >>= 4;
228                                 break;
229                         case 0x05:      // No_Flip_180, 32x32 dots
230                                 ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
231                                 ebx += esi;
232                                 edi = (eax & 0x3800) ^ 0x2800;          // bswap and flip
233                                 eax = (((eax >> 7) & 0x180) ^ 0x180) + ebx;
234                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
235                                 if (!(edi & 0x800)) pixel >>= 4;
236                                 break;
237                         case 0x06:      // No_Flip_270, 16x16 dots
238                                 eax = ((eax >> 9) & 0x3c) ^ 0x3c;
239                                 eax += esi;
240                                 edi = (ebx & 0x3800) ^ 0x1000;          // bswap
241                                 eax += (ebx >> 8) & 0x40;
242                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
243                                 if (!(edi & 0x800)) pixel >>= 4;
244                                 break;
245                         case 0x07:      // No_Flip_270, 32x32 dots
246                                 eax = ((eax >> 9) & 0x7c) ^ 0x7c;
247                                 eax += esi;
248                                 edi = (ebx & 0x3800) ^ 0x1000;          // bswap
249                                 eax += (ebx >> 7) & 0x180;
250                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
251                                 if (!(edi & 0x800)) pixel >>= 4;
252                                 break;
253                         case 0x08:      // Flip_0, 16x16 dots
254                                 ebx = ((ebx >> 9) & 0x3c) ^ 0x3c;
255                                 ebx += esi;
256                                 edi = (eax & 0x3800) ^ 0x2800;          // bswap, flip
257                                 eax = (((eax >> 8) & 0x40) ^ 0x40) + ebx;
258                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
259                                 if (!(edi & 0x800)) pixel >>= 4;
260                                 break;
261                         case 0x09:      // Flip_0, 32x32 dots
262                                 ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
263                                 ebx += esi;
264                                 edi = (eax & 0x3800) ^ 0x2800;          // bswap, flip
265                                 eax = (((eax >> 7) & 0x180) ^ 0x180) + ebx;
266                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
267                                 if (!(edi & 0x800)) pixel >>= 4;
268                                 break;
269                         case 0x0a:      // Flip_90, 16x16 dots
270                                 eax = ((eax >> 9) & 0x3c) ^ 0x3c;
271                                 eax += esi;
272                                 edi = (ebx & 0x3800) ^ 0x2800;          // bswap, flip
273                                 eax += ((ebx >> 8) & 0x40) ^ 0x40;
274                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
275                                 if (!(edi & 0x800)) pixel >>= 4;
276                                 break;
277                         case 0x0b:      // Flip_90, 32x32 dots
278                                 eax = ((eax >> 9) & 0x7c) ^ 0x7c;
279                                 eax += esi;
280                                 edi = (ebx & 0x3800) ^ 0x2800;          // bswap, flip
281                                 eax += ((ebx >> 7) & 0x180) ^ 0x180;
282                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
283                                 if (!(edi & 0x800)) pixel >>= 4;
284                                 break;
285                         case 0x0c:      // Flip_180, 16x16 dots
286                                 ebx = ((ebx >> 9) & 0x3c) ^ 0x3c;
287                                 ebx += esi;
288                                 edi = (eax & 0x3800) ^ 0x1000;          // bswap
289                                 eax = ((eax >> 8) & 0x40) + ebx;
290                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
291                                 if (!(edi & 0x800)) pixel >>= 4;
292                                 break;
293                         case 0x0d:      // Flip_180, 32x32 dots
294                                 ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
295                                 ebx += esi;
296                                 edi = (eax & 0x3800) ^ 0x1000;          // bswap
297                                 eax = ((eax >> 7) & 0x180) + ebx;
298                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
299                                 if (!(edi & 0x800)) pixel >>= 4;
300                                 break;
301                         case 0x0e:      // Flip_270, 16x16 dots
302                                 eax = (eax >> 9) & 0x3c;
303                                 eax += esi;
304                                 edi = (ebx & 0x3800) ^ 0x1000;          // bswap, flip
305                                 eax += (ebx >> 8) & 0x40;
306                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
307                                 if (!(edi & 0x800)) pixel >>= 4;
308                                 break;
309                         case 0x0f:      // Flip_270, 32x32 dots
310                                 eax = (eax >> 9) & 0x7c;
311                                 eax += esi;
312                                 edi = (ebx & 0x3800) ^ 0x1000;          // bswap, flip
313                                 eax += (ebx >> 7) & 0x180;
314                                 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
315                                 if (!(edi & 0x800)) pixel >>= 4;
316                                 break;
317                 }
318
319 Pixel_Out:
320 //              pixel = 0;
321 //Finish:
322                 pixel &= 0x0f;
323                 if (!pixel && (func & 0x18)) goto Next_Pixel;
324                 esi = rot_comp.Buffer_Adr + ((rot_comp.XD>>1)^1);       // pixel addr
325                 eax = *(Pico_mcd->word_ram2M + esi);                    // old pixel
326                 if (rot_comp.XD & 1)
327                 {
328                         if ((eax & 0x0f) && (func & 0x18) == 0x08) goto Next_Pixel; // underwrite
329                         *(Pico_mcd->word_ram2M + esi) = pixel | (eax & 0xf0);
330                 }
331                 else
332                 {
333                         if ((eax & 0xf0) && (func & 0x18) == 0x08) goto Next_Pixel; // underwrite
334                         *(Pico_mcd->word_ram2M + esi) = (pixel << 4) | (eax & 0xf);
335                 }
336
337
338 Next_Pixel:
339                 ecx += rot_comp.DXS;
340                 edx += rot_comp.DYS;
341                 rot_comp.XD++;
342                 if (rot_comp.XD >= 8)
343                 {
344                         rot_comp.Buffer_Adr += ((rot_comp.Reg_5C & 0x1f) + 1) << 5;
345                         rot_comp.XD = 0;
346                 }
347                 rot_comp.H_Dot--;
348         }
349
350
351 //nothing_to_draw:
352         rot_comp.YD++;
353         // rot_comp.V_Dot--; // will be done by caller
354 }
355
356
357 void gfx_cd_update(void)
358 {
359         unsigned char *V_Dot = (unsigned char *) &rot_comp.Reg_64;
360         int jobs;
361
362         dprintf("gfx_cd_update, Reg_64 = %04x", rot_comp.Reg_64);
363
364         if (!*V_Dot)
365         {
366                 gfx_completed();
367                 return;
368         }
369
370         jobs = rot_comp.Float_Part >> 16;
371
372         if (!jobs)
373         {
374                 rot_comp.Float_Part += rot_comp.Draw_Speed;
375                 return;
376         }
377
378         rot_comp.Float_Part &= 0xffff;
379         rot_comp.Float_Part += rot_comp.Draw_Speed;
380
381         while (jobs--)
382         {
383                 if (PicoOpt & 0x1000)
384                         gfx_do();       // jmp [Jmp_Adr]:
385
386                 (*V_Dot)--;             // dec byte [V_Dot]
387
388                 if (!*V_Dot)
389                 {
390                         // GFX_Completed:
391                         gfx_completed();
392                         return;
393                 }
394         }
395 }
396
397
398 unsigned int gfx_cd_read(unsigned int a)
399 {
400         unsigned int d = 0;
401
402         switch (a) {
403                 case 0x58: d = rot_comp.Reg_58; break;
404                 case 0x5A: d = rot_comp.Reg_5A; break;
405                 case 0x5C: d = rot_comp.Reg_5C; break;
406                 case 0x5E: d = rot_comp.Reg_5E; break;
407                 case 0x60: d = rot_comp.Reg_60; break;
408                 case 0x62: d = rot_comp.Reg_62; break;
409                 case 0x64: d = rot_comp.Reg_64; break;
410                 case 0x66: break;
411                 default: dprintf("gfx_cd_read FIXME: unexpected address: %02x", a); break;
412         }
413
414         dprintf("gfx_cd_read(%02x) = %04x", a, d);
415
416         return 0;
417 }
418
419 void gfx_cd_write16(unsigned int a, unsigned int d)
420 {
421         dprintf("gfx_cd_write16(%x, %04x)", a, d);
422
423         switch (a) {
424                 case 0x58: // .Reg_Stamp_Size
425                         rot_comp.Reg_58 = d & 7;
426                         return;
427
428                 case 0x5A: // .Reg_Stamp_Adr
429                         rot_comp.Reg_5A = d & 0xffe0;
430                         return;
431
432                 case 0x5C: // .Reg_IM_VCell_Size
433                         rot_comp.Reg_5C = d & 0x1f;
434                         return;
435
436                 case 0x5E: // .Reg_IM_Adr
437                         rot_comp.Reg_5E = d & 0xFFF8;
438                         return;
439
440                 case 0x60: // .Reg_IM_Offset
441                         rot_comp.Reg_60 = d & 0x3f;
442                         return;
443
444                 case 0x62: // .Reg_IM_HDot_Size
445                         rot_comp.Reg_62 = d & 0x1ff;
446                         return;
447
448                 case 0x64: // .Reg_IM_VDot_Size
449                         rot_comp.Reg_64 = d & 0xff;     // V_Dot, must be 32bit?
450                         return;
451
452                 case 0x66: // .Reg_Vector_Adr
453                         rot_comp.Reg_66 = d & 0xfffe;
454                         if (Pico_mcd->s68k_regs[3]&4) return; // can't do tanformations in 1M mode
455                         gfx_cd_start();
456                         return;
457
458                 default: dprintf("gfx_cd_write16 FIXME: unexpected address: %02x", a); return;
459         }
460 }
461
462
463 void gfx_cd_reset(void)
464 {
465         memset(&rot_comp.Reg_58, 0, sizeof(rot_comp));
466 }
467
468
469 // --------------------------------
470
471 #include "cell_map.c"
472
473 typedef unsigned short u16;
474
475 // check: Heart of the alien, jaguar xj 220
476 void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc)
477 {
478   unsigned char *base;
479   unsigned int asrc, a2;
480   u16 *r;
481
482   base = Pico_mcd->word_ram1M[Pico_mcd->s68k_regs[3]&1];
483
484   switch (Pico.video.type)
485   {
486     case 1: // vram
487       r = Pico.vram;
488       for(; len; len--)
489       {
490         asrc = cell_map(source >> 2) << 2;
491         asrc |= source & 2;
492         // if(a&1) d=(d<<8)|(d>>8); // ??
493         r[a>>1] = *(u16 *)(base + asrc);
494         source += 2;
495         // AutoIncrement
496         a=(u16)(a+inc);
497       }
498       rendstatus|=0x10;
499       break;
500
501     case 3: // cram
502       Pico.m.dirtyPal = 1;
503       r = Pico.cram;
504       for(a2=a&0x7f; len; len--)
505       {
506         asrc = cell_map(source >> 2) << 2;
507         asrc |= source & 2;
508         r[a2>>1] = *(u16 *)(base + asrc);
509         source += 2;
510         // AutoIncrement
511         a2+=inc;
512         // good dest?
513         if(a2 >= 0x80) break;
514       }
515       a=(a&0xff00)|a2;
516       break;
517
518     case 5: // vsram[a&0x003f]=d;
519       r = Pico.vsram;
520       for(a2=a&0x7f; len; len--)
521       {
522         asrc = cell_map(source >> 2) << 2;
523         asrc |= source & 2;
524         r[a2>>1] = *(u16 *)(base + asrc);
525         source += 2;
526         // AutoIncrement
527         a2+=inc;
528         // good dest?
529         if(a2 >= 0x80) break;
530       }
531       a=(a&0xff00)|a2;
532       break;
533   }
534   // remember addr
535   Pico.video.addr=(u16)a;
536 }
537