cd: pull in Genesis-Plus-GX CD gfx code
[picodrive.git] / pico / cd / gfx_cd.c
CommitLineData
6cadc2da 1// This is a direct rewrite of gfx_cd.asm (x86 asm to C).
2// You can even find some x86 register names :)
3// Original code (c) 2002 by Stéphane Dallongeville
4
5// (c) Copyright 2007, Grazvydas "notaz" Ignotas
6
cb4a513a 7
efcba75f 8#include "../pico_int.h"
cb4a513a 9
9c9cda8c 10#undef dprintf
11#define dprintf(...)
12
87650acd 13#define UPDATE_CYCLES 20000
14
eff55556 15#define _rot_comp Pico_mcd->rot_comp
d1df8786 16
ae214f1c 17static void gfx_do_line(unsigned int func, unsigned short *stamp_base,
18 unsigned int H_Dot);
d1df8786 19
cb4a513a 20static void gfx_cd_start(void)
21{
87650acd 22 int w, h, cycles;
23 int y_step;
ae214f1c 24
25 w = _rot_comp.Reg_62;
26 h = _rot_comp.Reg_64;
27 if (w == 0 || h == 0) {
28 elprintf(EL_CD|EL_ANOMALY, "gfx_cd_start with %ux%u", w, h);
29 _rot_comp.Reg_64 = 0;
30 // irq?
31 return;
32 }
d1df8786 33
eff55556 34 // _rot_comp.XD_Mul = ((_rot_comp.Reg_5C & 0x1f) + 1) * 4; // unused
35 _rot_comp.Function = (_rot_comp.Reg_58 & 7) | (Pico_mcd->s68k_regs[3] & 0x18); // Jmp_Adr
36 // _rot_comp.Buffer_Adr = (_rot_comp.Reg_5E & 0xfff8) << 2; // unused?
37 _rot_comp.YD = (_rot_comp.Reg_60 >> 3) & 7;
38 _rot_comp.Vector_Adr = (_rot_comp.Reg_66 & 0xfffe) << 2;
a4030801 39
eff55556 40 switch (_rot_comp.Reg_58 & 6) // Scr_16?
a4030801 41 {
42 case 0: // ?
eff55556 43 _rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xff80) << 2;
a4030801 44 break;
45 case 2: // .Dot_32
eff55556 46 _rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xffe0) << 2;
a4030801 47 break;
48 case 4: // .Scr_16
eff55556 49 _rot_comp.Stamp_Map_Adr = 0x20000;
a4030801 50 break;
51 case 6: // .Scr_16_Dot_32
eff55556 52 _rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xe000) << 2;
a4030801 53 break;
54 }
55
87650acd 56 _rot_comp.Reg_58 |= 0x8000; // Stamp_Size, we start a new GFX operation
57
58 cycles = 5 * w * h;
59 if (cycles > UPDATE_CYCLES)
60 y_step = (UPDATE_CYCLES + 5 * w - 1) / (5 * w);
61 else
62 y_step = h;
63
64 _rot_comp.y_step = y_step;
65 pcd_event_schedule_s68k(PCD_EVENT_GFX, 5 * w * y_step);
66}
67
68void gfx_cd_update(unsigned int cycles)
69{
70 int w = _rot_comp.Reg_62;
71 int h, next;
72
73 if (!(Pico_mcd->rot_comp.Reg_58 & 0x8000))
74 return;
75
76 h = _rot_comp.Reg_64;
77 _rot_comp.Reg_64 -= _rot_comp.y_step;
78
79 if ((int)_rot_comp.Reg_64 <= 0) {
80 Pico_mcd->rot_comp.Reg_58 &= 0x7fff;
81 Pico_mcd->rot_comp.Reg_64 = 0;
82 if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1) {
83 elprintf(EL_INTS |EL_CD, "s68k: gfx_cd irq 1");
84 SekInterruptS68k(1);
85 }
86 }
87 else {
88 next = _rot_comp.Reg_64;
89 if (next > _rot_comp.y_step)
90 next = _rot_comp.y_step;
91
92 pcd_event_schedule(cycles, PCD_EVENT_GFX, 5 * w * next);
93 h = _rot_comp.y_step;
94 }
95
ae214f1c 96 if (PicoOpt & POPT_EN_MCD_GFX)
97 {
98 unsigned int func = _rot_comp.Function;
87650acd 99 unsigned short *stamp_base = (unsigned short *)
100 (Pico_mcd->word_ram2M + _rot_comp.Stamp_Map_Adr);
c008977e 101
ae214f1c 102 while (h--)
103 gfx_do_line(func, stamp_base, w);
104 }
d1df8786 105}
106
ae214f1c 107PICO_INTERNAL_ASM unsigned int gfx_cd_read(unsigned int a)
d1df8786 108{
ae214f1c 109 unsigned int d = 0;
110
111 switch (a) {
112 case 0x58: d = _rot_comp.Reg_58; break;
113 case 0x5A: d = _rot_comp.Reg_5A; break;
114 case 0x5C: d = _rot_comp.Reg_5C; break;
115 case 0x5E: d = _rot_comp.Reg_5E; break;
116 case 0x60: d = _rot_comp.Reg_60; break;
117 case 0x62: d = _rot_comp.Reg_62; break;
87650acd 118 case 0x64: d = _rot_comp.Reg_64; break;
ae214f1c 119 case 0x66: break;
120 default: dprintf("gfx_cd_read FIXME: unexpected address: %02x", a); break;
cb4a513a 121 }
cb4a513a 122
ae214f1c 123 dprintf("gfx_cd_read(%02x) = %04x", a, d);
124
125 return d;
126
127}
d1df8786 128
ae214f1c 129static void gfx_do_line(unsigned int func, unsigned short *stamp_base,
130 unsigned int H_Dot)
a4030801 131{
528ec956 132 unsigned int eax, ebx, ecx, edx, esi, edi, pixel;
00bd648e 133 unsigned int XD, Buffer_Adr;
528ec956 134 int DYXS;
a4030801 135
eff55556 136 XD = _rot_comp.Reg_60 & 7;
137 Buffer_Adr = ((_rot_comp.Reg_5E & 0xfff8) + _rot_comp.YD) << 2;
138 ecx = *(unsigned int *)(Pico_mcd->word_ram2M + _rot_comp.Vector_Adr);
a4030801 139 edx = ecx >> 16;
140 ecx = (ecx & 0xffff) << 8;
141 edx <<= 8;
eff55556 142 DYXS = *(int *)(Pico_mcd->word_ram2M + _rot_comp.Vector_Adr + 4);
143 _rot_comp.Vector_Adr += 8;
a4030801 144
145 // MAKE_IMAGE_LINE
528ec956 146 while (H_Dot)
a4030801 147 {
c008977e 148 // MAKE_IMAGE_PIXEL
149 if (!(func & 1)) // NOT TILED
150 {
151 int mask = (func & 4) ? 0x00800000 : 0x00f80000;
152 if ((ecx | edx) & mask)
153 {
154 if (func & 0x18) goto Next_Pixel;
155 pixel = 0;
156 goto Pixel_Out;
157 }
158 }
159
a4030801 160 if (func & 2) // mode 32x32 dot
161 {
162 if (func & 4) // 16x16 screen
163 {
00bd648e 164 ebx = ((ecx >> (11+5)) & 0x007f) |
165 ((edx >> (11-2)) & 0x3f80);
a4030801 166 }
167 else // 1x1 screen
168 {
00bd648e 169 ebx = ((ecx >> (11+5)) & 0x07) |
170 ((edx >> (11+2)) & 0x38);
a4030801 171 }
172 }
173 else // mode 16x16 dot
174 {
175 if (func & 4) // 16x16 screen
176 {
00bd648e 177 ebx = ((ecx >> (11+4)) & 0x00ff) |
178 ((edx >> (11-4)) & 0xff00);
a4030801 179 }
180 else // 1x1 screen
181 {
00bd648e 182 ebx = ((ecx >> (11+4)) & 0x0f) |
183 ((edx >> (11+0)) & 0xf0);
a4030801 184 }
185 }
a4030801 186
c008977e 187 edi = stamp_base[ebx];
00bd648e 188 esi = (edi & 0x7ff) << 7;
528ec956 189 if (!esi) { pixel = 0; goto Pixel_Out; }
00bd648e 190 edi >>= (11+1);
a4030801 191 edi &= (0x1c>>1);
192 eax = ecx;
193 ebx = edx;
194 if (func & 2) edi |= 1; // 32 dots?
195 switch (edi)
196 {
197 case 0x00: // No_Flip_0, 16x16 dots
198 ebx = (ebx >> 9) & 0x3c;
199 ebx += esi;
200 edi = (eax & 0x3800) ^ 0x1000; // bswap
201 eax = ((eax >> 8) & 0x40) + ebx;
a4030801 202 break;
203 case 0x01: // No_Flip_0, 32x32 dots
204 ebx = (ebx >> 9) & 0x7c;
205 ebx += esi;
206 edi = (eax & 0x3800) ^ 0x1000; // bswap
207 eax = ((eax >> 7) & 0x180) + ebx;
a4030801 208 break;
209 case 0x02: // No_Flip_90, 16x16 dots
210 eax = (eax >> 9) & 0x3c;
211 eax += esi;
212 edi = (ebx & 0x3800) ^ 0x2800; // bswap
213 eax += ((ebx >> 8) & 0x40) ^ 0x40;
a4030801 214 break;
215 case 0x03: // No_Flip_90, 32x32 dots
216 eax = (eax >> 9) & 0x7c;
217 eax += esi;
218 edi = (ebx & 0x3800) ^ 0x2800; // bswap
01bc6b19 219 eax += ((ebx >> 7) & 0x180) ^ 0x180;
a4030801 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;
a4030801 226 break;
227 case 0x05: // No_Flip_180, 32x32 dots
228 ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
229 ebx += esi;
230 edi = (eax & 0x3800) ^ 0x2800; // bswap and flip
231 eax = (((eax >> 7) & 0x180) ^ 0x180) + ebx;
a4030801 232 break;
233 case 0x06: // No_Flip_270, 16x16 dots
234 eax = ((eax >> 9) & 0x3c) ^ 0x3c;
235 eax += esi;
236 edi = (ebx & 0x3800) ^ 0x1000; // bswap
237 eax += (ebx >> 8) & 0x40;
a4030801 238 break;
239 case 0x07: // No_Flip_270, 32x32 dots
240 eax = ((eax >> 9) & 0x7c) ^ 0x7c;
241 eax += esi;
242 edi = (ebx & 0x3800) ^ 0x1000; // bswap
243 eax += (ebx >> 7) & 0x180;
a4030801 244 break;
245 case 0x08: // Flip_0, 16x16 dots
01bc6b19 246 ebx = (ebx >> 9) & 0x3c;
a4030801 247 ebx += esi;
248 edi = (eax & 0x3800) ^ 0x2800; // bswap, flip
249 eax = (((eax >> 8) & 0x40) ^ 0x40) + ebx;
a4030801 250 break;
251 case 0x09: // Flip_0, 32x32 dots
01bc6b19 252 ebx = (ebx >> 9) & 0x7c;
a4030801 253 ebx += esi;
254 edi = (eax & 0x3800) ^ 0x2800; // bswap, flip
255 eax = (((eax >> 7) & 0x180) ^ 0x180) + ebx;
a4030801 256 break;
257 case 0x0a: // Flip_90, 16x16 dots
258 eax = ((eax >> 9) & 0x3c) ^ 0x3c;
259 eax += esi;
260 edi = (ebx & 0x3800) ^ 0x2800; // bswap, flip
261 eax += ((ebx >> 8) & 0x40) ^ 0x40;
a4030801 262 break;
263 case 0x0b: // Flip_90, 32x32 dots
264 eax = ((eax >> 9) & 0x7c) ^ 0x7c;
265 eax += esi;
266 edi = (ebx & 0x3800) ^ 0x2800; // bswap, flip
267 eax += ((ebx >> 7) & 0x180) ^ 0x180;
a4030801 268 break;
269 case 0x0c: // Flip_180, 16x16 dots
270 ebx = ((ebx >> 9) & 0x3c) ^ 0x3c;
271 ebx += esi;
272 edi = (eax & 0x3800) ^ 0x1000; // bswap
273 eax = ((eax >> 8) & 0x40) + ebx;
a4030801 274 break;
275 case 0x0d: // Flip_180, 32x32 dots
276 ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
277 ebx += esi;
278 edi = (eax & 0x3800) ^ 0x1000; // bswap
279 eax = ((eax >> 7) & 0x180) + ebx;
a4030801 280 break;
281 case 0x0e: // Flip_270, 16x16 dots
282 eax = (eax >> 9) & 0x3c;
283 eax += esi;
284 edi = (ebx & 0x3800) ^ 0x1000; // bswap, flip
285 eax += (ebx >> 8) & 0x40;
a4030801 286 break;
287 case 0x0f: // Flip_270, 32x32 dots
288 eax = (eax >> 9) & 0x7c;
289 eax += esi;
290 edi = (ebx & 0x3800) ^ 0x1000; // bswap, flip
291 eax += (ebx >> 7) & 0x180;
a4030801 292 break;
293 }
294
01bc6b19 295 pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
296 if (!(edi & 0x800)) pixel >>= 4;
528ec956 297 else pixel &= 0x0f;
01bc6b19 298
a4030801 299Pixel_Out:
a4030801 300 if (!pixel && (func & 0x18)) goto Next_Pixel;
528ec956 301 esi = Buffer_Adr + ((XD>>1)^1); // pixel addr
a4030801 302 eax = *(Pico_mcd->word_ram2M + esi); // old pixel
528ec956 303 if (XD & 1)
a4030801 304 {
305 if ((eax & 0x0f) && (func & 0x18) == 0x08) goto Next_Pixel; // underwrite
306 *(Pico_mcd->word_ram2M + esi) = pixel | (eax & 0xf0);
307 }
308 else
309 {
310 if ((eax & 0xf0) && (func & 0x18) == 0x08) goto Next_Pixel; // underwrite
311 *(Pico_mcd->word_ram2M + esi) = (pixel << 4) | (eax & 0xf);
312 }
313
314
315Next_Pixel:
eff55556 316 ecx += (DYXS << 16) >> 16; // _rot_comp.DXS;
317 edx += DYXS >> 16; // _rot_comp.DYS;
528ec956 318 XD++;
319 if (XD >= 8)
a4030801 320 {
eff55556 321 Buffer_Adr += ((_rot_comp.Reg_5C & 0x1f) + 1) << 5;
528ec956 322 XD = 0;
a4030801 323 }
528ec956 324 H_Dot--;
a4030801 325 }
528ec956 326 // end while
a4030801 327
328
00bd648e 329// nothing_to_draw:
eff55556 330 _rot_comp.YD++;
331 // _rot_comp.V_Dot--; // will be done by caller
a4030801 332}
d1df8786 333
334
eff55556 335PICO_INTERNAL_ASM void gfx_cd_write16(unsigned int a, unsigned int d)
cb4a513a 336{
5c69a605 337 dprintf("gfx_cd_write16(%x, %04x)", a, d);
cb4a513a 338
ae214f1c 339 if (_rot_comp.Reg_58 & 0x8000)
340 elprintf(EL_CD|EL_ANOMALY, "cd: busy gfx reg write %02x %04x", a, d);
341
cb4a513a 342 switch (a) {
d1df8786 343 case 0x58: // .Reg_Stamp_Size
eff55556 344 _rot_comp.Reg_58 = d & 7;
d1df8786 345 return;
346
347 case 0x5A: // .Reg_Stamp_Adr
eff55556 348 _rot_comp.Reg_5A = d & 0xffe0;
d1df8786 349 return;
350
351 case 0x5C: // .Reg_IM_VCell_Size
eff55556 352 _rot_comp.Reg_5C = d & 0x1f;
d1df8786 353 return;
354
355 case 0x5E: // .Reg_IM_Adr
eff55556 356 _rot_comp.Reg_5E = d & 0xFFF8;
d1df8786 357 return;
358
359 case 0x60: // .Reg_IM_Offset
eff55556 360 _rot_comp.Reg_60 = d & 0x3f;
d1df8786 361 return;
362
363 case 0x62: // .Reg_IM_HDot_Size
eff55556 364 _rot_comp.Reg_62 = d & 0x1ff;
d1df8786 365 return;
366
367 case 0x64: // .Reg_IM_VDot_Size
eff55556 368 _rot_comp.Reg_64 = d & 0xff; // V_Dot, must be 32bit?
d1df8786 369 return;
370
371 case 0x66: // .Reg_Vector_Adr
eff55556 372 _rot_comp.Reg_66 = d & 0xfffe;
cb4a513a 373 if (Pico_mcd->s68k_regs[3]&4) return; // can't do tanformations in 1M mode
374 gfx_cd_start();
375 return;
d1df8786 376
5c69a605 377 default: dprintf("gfx_cd_write16 FIXME: unexpected address: %02x", a); return;
cb4a513a 378 }
379}
380
d1df8786 381
eff55556 382PICO_INTERNAL void gfx_cd_reset(void)
51a902ae 383{
eff55556 384 memset(&_rot_comp.Reg_58, 0, sizeof(_rot_comp));
fa1e5e29 385}
386
387
388// --------------------------------
389
390#include "cell_map.c"
391
eff55556 392#ifndef UTYPES_DEFINED
fa1e5e29 393typedef unsigned short u16;
eff55556 394#endif
fa1e5e29 395
0a051f55 396// check: Heart of the alien, jaguar xj 220
eff55556 397PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc)
fa1e5e29 398{
399 unsigned char *base;
400 unsigned int asrc, a2;
401 u16 *r;
402
403 base = Pico_mcd->word_ram1M[Pico_mcd->s68k_regs[3]&1];
404
405 switch (Pico.video.type)
406 {
407 case 1: // vram
408 r = Pico.vram;
409 for(; len; len--)
410 {
411 asrc = cell_map(source >> 2) << 2;
412 asrc |= source & 2;
413 // if(a&1) d=(d<<8)|(d>>8); // ??
414 r[a>>1] = *(u16 *)(base + asrc);
415 source += 2;
416 // AutoIncrement
417 a=(u16)(a+inc);
418 }
602133e1 419 rendstatus |= PDRAW_SPRITES_MOVED;
fa1e5e29 420 break;
421
422 case 3: // cram
423 Pico.m.dirtyPal = 1;
424 r = Pico.cram;
425 for(a2=a&0x7f; len; len--)
426 {
427 asrc = cell_map(source >> 2) << 2;
428 asrc |= source & 2;
429 r[a2>>1] = *(u16 *)(base + asrc);
430 source += 2;
431 // AutoIncrement
432 a2+=inc;
433 // good dest?
434 if(a2 >= 0x80) break;
435 }
436 a=(a&0xff00)|a2;
437 break;
438
439 case 5: // vsram[a&0x003f]=d;
440 r = Pico.vsram;
441 for(a2=a&0x7f; len; len--)
442 {
443 asrc = cell_map(source >> 2) << 2;
444 asrc |= source & 2;
445 r[a2>>1] = *(u16 *)(base + asrc);
446 source += 2;
447 // AutoIncrement
448 a2+=inc;
449 // good dest?
450 if(a2 >= 0x80) break;
451 }
452 a=(a&0xff00)|a2;
453 break;
454 }
455 // remember addr
456 Pico.video.addr=(u16)a;
51a902ae 457}
458