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