1 /***************************************************************************************
2 * Genesis Plus
3 * CD graphics processor
4 *
5 * Copyright (C) 2012-2019 Eke-Eke (Genesis Plus GX)
6 *
7 * Redistribution and use of this code or any derivative works are permitted
8 * provided that the following conditions are met:
9 *
10 * - Redistributions may not be sold, nor may they be used in a commercial
11 * product or activity.
12 *
13 * - Redistributions that are modified from the original source must include the
14 * complete source code, including the source code for all components used by a
15 * binary built from the modified sources. However, as a special exception, the
16 * source code distributed need not include anything that is normally distributed
17 * (in either source or binary form) with the major components (compiler, kernel,
18 * and so on) of the operating system on which the executable runs, unless that
19 * component itself accompanies the executable.
20 *
21 * - Redistributions must reproduce the above copyright notice, this list of
22 * conditions and the following disclaimer in the documentation and/or other
23 * materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 ****************************************************************************************/
38 #include "shared.h"
39
40 /***************************************************************/
41 /* WORD-RAM DMA interfaces (1M & 2M modes) */
42 /***************************************************************/
43
word_ram_0_dma_w(unsigned int words)44 void word_ram_0_dma_w(unsigned int words)
45 {
46 uint16 data;
47
48 /* CDC buffer source address */
49 uint16 src_index = cdc.dac.w & 0x3ffe;
50
51 /* WORD-RAM destination address*/
52 uint32 dst_index = (scd.regs[0x0a>>1].w << 3) & 0x1fffe;
53
54 /* update DMA destination address */
55 scd.regs[0x0a>>1].w += (words >> 2);
56
57 /* update DMA source address */
58 cdc.dac.w += (words << 1);
59
60 /* DMA transfer */
61 while (words--)
62 {
63 /* read 16-bit word from CDC RAM buffer (big-endian format) */
64 data = READ_WORD(cdc.ram, src_index);
65
66 /* write 16-bit word to WORD-RAM */
67 *(uint16 *)(scd.word_ram[0] + dst_index) = data ;
68
69 /* increment CDC buffer source address */
70 src_index = (src_index + 2) & 0x3ffe;
71
72 /* increment WORD-RAM destination address */
73 dst_index = (dst_index + 2) & 0x1fffe;
74 }
75 }
76
word_ram_1_dma_w(unsigned int words)77 void word_ram_1_dma_w(unsigned int words)
78 {
79 uint16 data;
80
81 /* CDC buffer source address */
82 uint16 src_index = cdc.dac.w & 0x3ffe;
83
84 /* WORD-RAM destination address*/
85 uint32 dst_index = ((scd.regs[0x0a>>1].w << 3) & 0x1fffe);
86
87 /* update DMA destination address */
88 scd.regs[0x0a>>1].w += (words >> 2);
89
90 /* update DMA source address */
91 cdc.dac.w += (words << 1);
92
93 /* DMA transfer */
94 while (words--)
95 {
96 /* read 16-bit word from CDC RAM buffer (big-endian format) */
97 data = READ_WORD(cdc.ram, src_index);
98
99 /* write 16-bit word to WORD-RAM */
100 *(uint16 *)(scd.word_ram[1] + dst_index) = data ;
101
102 /* increment CDC buffer source address */
103 src_index = (src_index + 2) & 0x3ffe;
104
105 /* increment WORD-RAM destination address */
106 dst_index = (dst_index + 2) & 0x1fffe;
107 }
108 }
109
word_ram_2M_dma_w(unsigned int words)110 void word_ram_2M_dma_w(unsigned int words)
111 {
112 uint16 data;
113
114 /* CDC buffer source address */
115 uint16 src_index = cdc.dac.w & 0x3ffe;
116
117 /* WORD-RAM destination address*/
118 uint32 dst_index = (scd.regs[0x0a>>1].w << 3) & 0x3fffe;
119
120 /* update DMA destination address */
121 scd.regs[0x0a>>1].w += (words >> 2);
122
123 /* update DMA source address */
124 cdc.dac.w += (words << 1);
125
126 /* DMA transfer */
127 while (words--)
128 {
129 /* read 16-bit word from CDC RAM buffer (big-endian format) */
130 data = READ_WORD(cdc.ram, src_index);
131
132 /* write 16-bit word to WORD-RAM */
133 *(uint16 *)(scd.word_ram_2M + dst_index) = data ;
134
135 /* increment CDC buffer source address */
136 src_index = (src_index + 2) & 0x3ffe;
137
138 /* increment WORD-RAM destination address */
139 dst_index = (dst_index + 2) & 0x3fffe;
140 }
141 }
142
143
144 /***************************************************************/
145 /* WORD-RAM 0 & 1 DOT image SUB-CPU interface (1M Mode) */
146 /***************************************************************/
147
dot_ram_0_read16(unsigned int address)148 unsigned int dot_ram_0_read16(unsigned int address)
149 {
150 uint8 data = READ_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff);
151 return ((data & 0x0f) | ((data << 4) & 0xf00));
152 }
153
dot_ram_1_read16(unsigned int address)154 unsigned int dot_ram_1_read16(unsigned int address)
155 {
156 uint8 data = READ_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff);
157 return ((data & 0x0f) | ((data << 4) & 0xf00));
158 }
159
dot_ram_0_write16(unsigned int address,unsigned int data)160 void dot_ram_0_write16(unsigned int address, unsigned int data)
161 {
162 uint8 prev;
163 address = (address >> 1) & 0x1ffff;
164 prev = READ_BYTE(scd.word_ram[0], address);
165 data = (data & 0x0f) | ((data >> 4) & 0xf0);
166 data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
167 WRITE_BYTE(scd.word_ram[0], address, data);
168 }
169
dot_ram_1_write16(unsigned int address,unsigned int data)170 void dot_ram_1_write16(unsigned int address, unsigned int data)
171 {
172 uint8 prev;
173 address = (address >> 1) & 0x1ffff;
174 prev = READ_BYTE(scd.word_ram[1], address);
175 data = (data & 0x0f) | ((data >> 4) & 0xf0);
176 data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
177 WRITE_BYTE(scd.word_ram[1], address, data);
178 }
179
dot_ram_0_read8(unsigned int address)180 unsigned int dot_ram_0_read8(unsigned int address)
181 {
182 uint8 data = READ_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff);
183
184 if (address & 1)
185 {
186 return (data & 0x0f);
187 }
188
189 return (data >> 4);
190 }
191
dot_ram_1_read8(unsigned int address)192 unsigned int dot_ram_1_read8(unsigned int address)
193 {
194 uint8 data = READ_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff);
195
196 if (address & 1)
197 {
198 return (data & 0x0f);
199 }
200
201 return (data >> 4);
202 }
203
dot_ram_0_write8(unsigned int address,unsigned int data)204 void dot_ram_0_write8(unsigned int address, unsigned int data)
205 {
206 uint8 prev = READ_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff);
207
208 if (address & 1)
209 {
210 data = (prev & 0xf0) | (data & 0x0f);
211 }
212 else
213 {
214 data = (prev & 0x0f) | (data << 4);
215 }
216
217 data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
218 WRITE_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff, data);
219 }
220
dot_ram_1_write8(unsigned int address,unsigned int data)221 void dot_ram_1_write8(unsigned int address, unsigned int data)
222 {
223 uint8 prev = READ_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff);
224
225 if (address & 1)
226 {
227 data = (prev & 0xf0) | (data & 0x0f);
228 }
229 else
230 {
231 data = (prev & 0x0f) | (data << 4);
232 }
233
234 data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
235 WRITE_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff, data);
236 }
237
238
239 /***************************************************************/
240 /* WORD-RAM 0 & 1 CELL image MAIN-CPU interface (1M Mode) */
241 /***************************************************************/
242
cell_ram_0_read16(unsigned int address)243 unsigned int cell_ram_0_read16(unsigned int address)
244 {
245 address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
246 return *(uint16 *)(scd.word_ram[0] + address);
247 }
248
cell_ram_1_read16(unsigned int address)249 unsigned int cell_ram_1_read16(unsigned int address)
250 {
251 address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
252 return *(uint16 *)(scd.word_ram[1] + address);
253 }
254
cell_ram_0_write16(unsigned int address,unsigned int data)255 void cell_ram_0_write16(unsigned int address, unsigned int data)
256 {
257 address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
258 *(uint16 *)(scd.word_ram[0] + address) = data;
259 }
260
cell_ram_1_write16(unsigned int address,unsigned int data)261 void cell_ram_1_write16(unsigned int address, unsigned int data)
262 {
263 address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
264 *(uint16 *)(scd.word_ram[1] + address) = data;
265 }
266
cell_ram_0_read8(unsigned int address)267 unsigned int cell_ram_0_read8(unsigned int address)
268 {
269 address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
270 return READ_BYTE(scd.word_ram[0], address);
271 }
272
cell_ram_1_read8(unsigned int address)273 unsigned int cell_ram_1_read8(unsigned int address)
274 {
275 address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
276 return READ_BYTE(scd.word_ram[1], address);
277 }
278
cell_ram_0_write8(unsigned int address,unsigned int data)279 void cell_ram_0_write8(unsigned int address, unsigned int data)
280 {
281 address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
282 WRITE_BYTE(scd.word_ram[0], address, data);
283 }
284
cell_ram_1_write8(unsigned int address,unsigned int data)285 void cell_ram_1_write8(unsigned int address, unsigned int data)
286 {
287 address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
288 WRITE_BYTE(scd.word_ram[1], address, data);
289 }
290
291
292 /***************************************************************/
293 /* Rotation / Scaling operation (2M Mode) */
294 /***************************************************************/
295
gfx_init(void)296 void gfx_init(void)
297 {
298 int i, j;
299 uint16 offset;
300 uint8 mask, row, col, temp;
301
302 memset(&gfx, 0, sizeof(gfx_t));
303
304 /* Initialize cell image lookup table */
305 /* $220000-$22FFFF corresponds to $200000-$20FFFF */
306 for (i=0; i<0x4000; i++)
307 {
308 offset = (i & 0x07) << 8; /* cell vline (0-7) */
309 offset = offset | (((i >> 8) & 0x3f) << 2); /* cell x offset (0-63) */
310 offset = offset | (((i >> 3) & 0x1f) << 11); /* cell y offset (0-31) */
311 gfx.lut_offset[i] = offset;
312 }
313
314 /* $230000-$237FFF corresponds to $210000-$217FFF */
315 for (i=0x4000; i<0x6000; i++)
316 {
317 offset = (i & 0x07) << 8; /* cell vline (0-7) */
318 offset = offset | (((i >> 7) & 0x3f) << 2); /* cell x offset (0-63) */
319 offset = offset | (((i >> 3) & 0x0f) << 11); /* cell y offset (0-15) */
320 gfx.lut_offset[i] = offset;
321 }
322
323 /* $238000-$23BFFF corresponds to $218000-$21BFFF */
324 for (i=0x6000; i<0x7000; i++)
325 {
326 offset = (i & 0x07) << 8; /* cell vline (0-7) */
327 offset = offset | (((i >> 6) & 0x3f) << 2); /* cell x offset (0-63) */
328 offset = offset | (((i >> 3) & 0x07) << 11); /* cell y offset (0-7) */
329 gfx.lut_offset[i] = offset | 0x8000;
330 }
331
332 /* $23C000-$23DFFF corresponds to $21C000-$21DFFF */
333 for (i=0x7000; i<0x7800; i++)
334 {
335 offset = (i & 0x07) << 8; /* cell vline (0-7) */
336 offset = offset | (((i >> 5) & 0x3f) << 2); /* cell x offset (0-63) */
337 offset = offset | (((i >> 3) & 0x03) << 11); /* cell y offset (0-3) */
338 gfx.lut_offset[i] = offset | 0xc000;
339 }
340
341 /* $23E000-$23FFFF corresponds to $21E000-$21FFFF */
342 for (i=0x7800; i<0x8000; i++)
343 {
344 offset = (i & 0x07) << 8; /* cell vline (0-7) */
345 offset = offset | (((i >> 5) & 0x3f) << 2); /* cell x offset (0-63) */
346 offset = offset | (((i >> 3) & 0x03) << 11); /* cell y offset (0-3) */
347 gfx.lut_offset[i] = offset | 0xe000;
348 }
349
350 /* Initialize priority modes lookup table */
351 for (i=0; i<0x100; i++)
352 {
353 for (j=0; j<0x100; j++)
354 {
355 /* normal */
356 gfx.lut_prio[0][i][j] = j;
357 /* underwrite */
358 gfx.lut_prio[1][i][j] = ((i & 0x0f) ? (i & 0x0f) : (j & 0x0f)) | ((i & 0xf0) ? (i & 0xf0) : (j & 0xf0));
359 /* overwrite */
360 gfx.lut_prio[2][i][j] = ((j & 0x0f) ? (j & 0x0f) : (i & 0x0f)) | ((j & 0xf0) ? (j & 0xf0) : (i & 0xf0));
361 /* invalid */
362 gfx.lut_prio[3][i][j] = i;
363 }
364 }
365
366 /* Initialize cell lookup table */
367 /* table entry = yyxxshrr (8 bits) */
368 /* with: yy = cell row (0-3) */
369 /* xx = cell column (0-3) */
370 /* s = stamp size (0=16x16, 1=32x32) */
371 /* hrr = HFLIP & ROTATION bits */
372 for (i=0; i<0x100; i++)
373 {
374 /* one stamp = 2x2 cells (16x16) or 4x4 cells (32x32) */
375 mask = (i & 8) ? 3 : 1;
376 row = (i >> 6) & mask;
377 col = (i >> 4) & mask;
378
379 if (i & 4) { col = col ^ mask; } /* HFLIP (always first) */
380 if (i & 2) { col = col ^ mask; row = row ^ mask; } /* ROLL1 */
381 if (i & 1) { temp = col; col = row ^ mask; row = temp; } /* ROLL0 */
382
383 /* cell offset (0-3 or 0-15) */
384 gfx.lut_cell[i] = row + col * (mask + 1);
385 }
386
387 /* Initialize pixel lookup table */
388 /* table entry = yyyxxxhrr (9 bits) */
389 /* with: yyy = pixel row (0-7) */
390 /* xxx = pixel column (0-7) */
391 /* hrr = HFLIP & ROTATION bits */
392 for (i=0; i<0x200; i++)
393 {
394 /* one cell = 8x8 pixels */
395 row = (i >> 6) & 7;
396 col = (i >> 3) & 7;
397
398 if (i & 4) { col = col ^ 7; } /* HFLIP (always first) */
399 if (i & 2) { col = col ^ 7; row = row ^ 7; } /* ROLL1 */
400 if (i & 1) { temp = col; col = row ^ 7; row = temp; } /* ROLL0 */
401
402 /* pixel offset (0-63) */
403 gfx.lut_pixel[i] = col + row * 8;
404 }
405 }
406
gfx_reset(void)407 void gfx_reset(void)
408 {
409 /* Reset cycle counter */
410 gfx.cycles = 0;
411 }
412
gfx_context_save(uint8 * state)413 int gfx_context_save(uint8 *state)
414 {
415 uint32 tmp32;
416 int bufferptr = 0;
417
418 save_param(&gfx.cycles, sizeof(gfx.cycles));
419 save_param(&gfx.cyclesPerLine, sizeof(gfx.cyclesPerLine));
420 save_param(&gfx.dotMask, sizeof(gfx.dotMask));
421 save_param(&gfx.stampShift, sizeof(gfx.stampShift));
422 save_param(&gfx.mapShift, sizeof(gfx.mapShift));
423 save_param(&gfx.bufferOffset, sizeof(gfx.bufferOffset));
424 save_param(&gfx.bufferStart, sizeof(gfx.bufferStart));
425
426 tmp32 = (uint8 *)(gfx.tracePtr) - scd.word_ram_2M;
427 save_param(&tmp32, 4);
428
429 tmp32 = (uint8 *)(gfx.mapPtr) - scd.word_ram_2M;
430 save_param(&tmp32, 4);
431
432 return bufferptr;
433 }
434
gfx_context_load(uint8 * state)435 int gfx_context_load(uint8 *state)
436 {
437 uint32 tmp32;
438 int bufferptr = 0;
439
440 load_param(&gfx.cycles, sizeof(gfx.cycles));
441 load_param(&gfx.cyclesPerLine, sizeof(gfx.cyclesPerLine));
442 load_param(&gfx.dotMask, sizeof(gfx.dotMask));
443 load_param(&gfx.stampShift, sizeof(gfx.stampShift));
444 load_param(&gfx.mapShift, sizeof(gfx.mapShift));
445 load_param(&gfx.bufferOffset, sizeof(gfx.bufferOffset));
446 load_param(&gfx.bufferStart, sizeof(gfx.bufferStart));
447
448 load_param(&tmp32, 4);
449 gfx.tracePtr = (uint16 *)(scd.word_ram_2M + tmp32);
450
451 load_param(&tmp32, 4);
452 gfx.mapPtr = (uint16 *)(scd.word_ram_2M + tmp32);
453
454 return bufferptr;
455 }
456
gfx_render(uint32 bufferIndex,uint32 width)457 INLINE void gfx_render(uint32 bufferIndex, uint32 width)
458 {
459 uint8 pixel_in, pixel_out;
460 uint16 stamp_data;
461 uint32 stamp_index;
462
463 /* pixel map start position for current line (13.3 format converted to 13.11) */
464 uint32 xpos = *gfx.tracePtr++ << 8;
465 uint32 ypos = *gfx.tracePtr++ << 8;
466
467 /* pixel map offset values for current line (5.11 format) */
468 uint32 xoffset = (int16) *gfx.tracePtr++;
469 uint32 yoffset = (int16) *gfx.tracePtr++;
470
471 /* process all dots */
472 while (width--)
473 {
474 /* check if stamp map is repeated */
475 if (scd.regs[0x58>>1].byte.l & 0x01)
476 {
477 /* stamp map range */
478 xpos &= gfx.dotMask;
479 ypos &= gfx.dotMask;
480 }
481 else
482 {
483 /* 24-bit range */
484 xpos &= 0xffffff;
485 ypos &= 0xffffff;
486 }
487
488 /* check if pixel is outside stamp map */
489 if ((xpos | ypos) & ~gfx.dotMask)
490 {
491 /* force pixel output to 0 */
492 pixel_out = 0x00;
493 }
494 else
495 {
496 /* read stamp map table data */
497 stamp_data = gfx.mapPtr[(xpos >> gfx.stampShift) | ((ypos >> gfx.stampShift) << gfx.mapShift)];
498
499 /* stamp generator base index */
500 /* sss ssssssss ccyyyxxx (16x16) or sss sssssscc ccyyyxxx (32x32) */
501 /* with: s = stamp number (1 stamp = 16x16 or 32x32 pixels) */
502 /* c = cell offset (0-3 for 16x16, 0-15 for 32x32) */
503 /* yyy = line offset (0-7) */
504 /* xxx = pixel offset (0-7) */
505 stamp_index = (stamp_data & 0x7ff) << 8;
506
507 if (stamp_index)
508 {
509 /* extract HFLIP & ROTATION bits */
510 stamp_data = (stamp_data >> 13) & 7;
511
512 /* cell offset (0-3 or 0-15) */
513 /* table entry = yyxxshrr (8 bits) */
514 /* with: yy = cell row (0-3) = (ypos >> (11 + 3)) & 3 */
515 /* xx = cell column (0-3) = (xpos >> (11 + 3)) & 3 */
516 /* s = stamp size (0=16x16, 1=32x32) */
517 /* hrr = HFLIP & ROTATION bits */
518 stamp_index |= gfx.lut_cell[stamp_data | ((scd.regs[0x58>>1].byte.l & 0x02) << 2 ) | ((ypos >> 8) & 0xc0) | ((xpos >> 10) & 0x30)] << 6;
519
520 /* pixel offset (0-63) */
521 /* table entry = yyyxxxhrr (9 bits) */
522 /* with: yyy = pixel row (0-7) = (ypos >> 11) & 7 */
523 /* xxx = pixel column (0-7) = (xpos >> 11) & 7 */
524 /* hrr = HFLIP & ROTATION bits */
525 stamp_index |= gfx.lut_pixel[stamp_data | ((xpos >> 8) & 0x38) | ((ypos >> 5) & 0x1c0)];
526
527 /* read pixel pair (2 pixels/byte) */
528 pixel_out = READ_BYTE(scd.word_ram_2M, stamp_index >> 1);
529
530 /* extract left or rigth pixel */
531 if (stamp_index & 1)
532 {
533 pixel_out &= 0x0f;
534 }
535 else
536 {
537 pixel_out >>= 4;
538 }
539 }
540 else
541 {
542 /* stamp 0 is not used: force pixel output to 0 */
543 pixel_out = 0x00;
544 }
545 }
546
547 /* read out paired pixel data */
548 pixel_in = READ_BYTE(scd.word_ram_2M, bufferIndex >> 1);
549
550 /* update left or rigth pixel */
551 if (bufferIndex & 1)
552 {
553 pixel_out |= (pixel_in & 0xf0);
554 }
555 else
556 {
557 pixel_out = (pixel_out << 4) | (pixel_in & 0x0f);
558 }
559
560 /* priority mode write */
561 pixel_out = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][pixel_in][pixel_out];
562
563 /* write data to image buffer */
564 WRITE_BYTE(scd.word_ram_2M, bufferIndex >> 1, pixel_out);
565
566 /* check current pixel position */
567 if ((bufferIndex & 7) != 7)
568 {
569 /* next pixel */
570 bufferIndex++;
571 }
572 else
573 {
574 /* next cell: increment image buffer offset by one column (minus 7 pixels) */
575 bufferIndex += gfx.bufferOffset;
576 }
577
578 /* increment pixel position */
579 xpos += xoffset;
580 ypos += yoffset;
581 }
582 }
583
gfx_start(unsigned int base,int cycles)584 void gfx_start(unsigned int base, int cycles)
585 {
586 /* make sure 2M mode is enabled */
587 if (!(scd.regs[0x02>>1].byte.l & 0x04))
588 {
589 uint32 mask;
590
591 /* trace vector pointer */
592 gfx.tracePtr = (uint16 *)(scd.word_ram_2M + ((base << 2) & 0x3fff8));
593
594 /* stamps & stamp map size */
595 switch ((scd.regs[0x58>>1].byte.l >> 1) & 0x03)
596 {
597 case 0:
598 gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
599 gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
600 gfx.mapShift = 4; /* 16x16 stamps/map */
601 mask = 0x3fe00; /* 512 bytes/table */
602 break;
603
604 case 1:
605 gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
606 gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
607 gfx.mapShift = 3; /* 8x8 stamps/map */
608 mask = 0x3ff80; /* 128 bytes/table */
609 break;
610
611 case 2:
612 gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
613 gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
614 gfx.mapShift = 8; /* 256x256 stamps/map */
615 mask = 0x20000; /* 131072 bytes/table */
616 break;
617
618 case 3:
619 gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
620 gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
621 gfx.mapShift = 7; /* 128x128 stamps/map */
622 mask = 0x38000; /* 32768 bytes/table */
623 break;
624 }
625
626 /* stamp map table base address */
627 gfx.mapPtr = (uint16 *)(scd.word_ram_2M + ((scd.regs[0x5a>>1].w << 2) & mask));
628
629 /* image buffer column offset (64 pixels/cell, minus 7 pixels to restart at cell beginning) */
630 gfx.bufferOffset = (((scd.regs[0x5c>>1].byte.l & 0x1f) + 1) << 6) - 7;
631
632 /* image buffer start index in dot units (2 pixels/byte) */
633 gfx.bufferStart = (scd.regs[0x5e>>1].w << 3) & 0x7ffc0;
634
635 /* add image buffer horizontal dot offset */
636 gfx.bufferStart += (scd.regs[0x60>>1].byte.l & 0x3f);
637
638 /* reset GFX chip cycle counter */
639 gfx.cycles = cycles;
640
641 /* update GFX chip timings (see AC3:Thunderhawk / Thunderstrike) */
642 gfx.cyclesPerLine = 4 * 5 * scd.regs[0x62>>1].w;
643
644 /* start graphics operation */
645 scd.regs[0x58>>1].byte.h = 0x80;
646 }
647 }
648
gfx_update(int cycles)649 void gfx_update(int cycles)
650 {
651 /* synchronize GFX chip with SUB-CPU */
652 cycles -= gfx.cycles;
653
654 /* make sure SUB-CPU is ahead */
655 if (cycles > 0)
656 {
657 /* number of lines to process */
658 unsigned int lines = (cycles + gfx.cyclesPerLine - 1) / gfx.cyclesPerLine;
659
660 /* check against remaining lines */
661 if (lines < scd.regs[0x64>>1].byte.l)
662 {
663 /* update Vdot remaining size */
664 scd.regs[0x64>>1].byte.l -= lines;
665
666 /* increment cycle counter */
667 gfx.cycles += lines * gfx.cyclesPerLine;
668 }
669 else
670 {
671 /* process remaining lines */
672 lines = scd.regs[0x64>>1].byte.l;
673
674 /* clear Vdot remaining size */
675 scd.regs[0x64>>1].byte.l = 0;
676
677 /* end of graphics operation */
678 scd.regs[0x58>>1].byte.h = 0;
679
680 /* SUB-CPU idle on register $58 polling ? */
681 if (s68k.stopped & (1<<0x08))
682 {
683 /* sync SUB-CPU with GFX chip */
684 s68k.cycles = scd.cycles;
685
686 /* restart SUB-CPU */
687 s68k.stopped = 0;
688 #ifdef LOG_SCD
689 error("s68k started from %d cycles\n", s68k.cycles);
690 #endif
691 }
692
693 /* level 1 interrupt enabled ? */
694 if (scd.regs[0x32>>1].byte.l & 0x02)
695 {
696 /* trigger level 1 interrupt */
697 scd.pending |= (1 << 1);
698
699 /* update IRQ level */
700 s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
701 }
702 }
703
704 /* render lines */
705 while (lines--)
706 {
707 /* process dots to image buffer */
708 gfx_render(gfx.bufferStart, scd.regs[0x62>>1].w);
709
710 /* increment image buffer start index for next line (8 pixels/line) */
711 gfx.bufferStart += 8;
712 }
713 }
714 }
715