1 /*************************************************************************
2
3 avgdvg.c: Atari DVG and AVG simulators
4
5 Copyright 1991, 1992, 1996 Eric Smith
6
7 Modified for the MAME project 1997 by
8 Brad Oliver, Bernd Wiebelt, Aaron Giles, Andrew Caldwell
9
10 971108 Disabled vector timing routines, introduced an ugly (but fast!)
11 busy flag hack instead. BW
12 980202 New anti aliasing code by Andrew Caldwell (.ac)
13 980206 New (cleaner) busy flag handling.
14 Moved LBO's buffered point into generic vector code. BW
15 980212 Introduced timing code based on Aaron timer routines. BW
16 980318 Better color handling, Bzone and MHavoc clipping. BW
17
18 Battlezone uses a red overlay for the top of the screen and a green one
19 for the rest. There is a circuit to clip color 0 lines extending to the
20 red zone. This is emulated now. Thanks to Neil Bradley for the info. BW
21
22 Frame and interrupt rates (Neil Bradley) BW
23 ~60 fps/4.0ms: Asteroid, Asteroid Deluxe
24 ~40 fps/4.0ms: Lunar Lander
25 ~40 fps/4.1ms: Battle Zone
26 ~45 fps/5.4ms: Space Duel, Red Baron
27 ~30 fps/5.4ms: StarWars
28
29 Games with self adjusting framerate
30 4.1ms: Black Widow, Gravitar
31 4.1ms: Tempest
32 Major Havoc
33 Quantum
34
35 TODO: accurate vector timing (need timing diagramm)
36
37 ************************************************************************/
38
39 #include "driver.h"
40 #include "avgdvg.h"
41 #include "vector.h"
42
43
44 //#define VG_DEBUG
45 #ifdef VG_DEBUG
46 #define VGLOG(x) logerror x
47 #else
48 #define VGLOG(x)
49 #endif
50
51
52 /*************************************
53 *
54 * Constants
55 *
56 *************************************/
57
58 #define BRIGHTNESS 12
59
60 #define MAXSTACK 8 /* Tempest needs more than 4 */
61
62 /* AVG commands */
63 #define VCTR 0
64 #define HALT 1
65 #define SVEC 2
66 #define STAT 3
67 #define CNTR 4
68 #define JSRL 5
69 #define RTSL 6
70 #define JMPL 7
71 #define SCAL 8
72
73 /* DVG commands */
74 #define DVCTR 0x01
75 #define DLABS 0x0a
76 #define DHALT 0x0b
77 #define DJSRL 0x0c
78 #define DRTSL 0x0d
79 #define DJMPL 0x0e
80 #define DSVEC 0x0f
81
82
83
84 /*************************************
85 *
86 * Static variables
87 *
88 *************************************/
89
90 static UINT8 vector_engine;
91 static UINT8 flipword;
92 static UINT8 busy;
93 static rgb_t colorram[32];
94
95 static int width, height;
96 static int xcenter, ycenter;
97 static int xmin, xmax;
98 static int ymin, ymax;
99
100 static int flip_x, flip_y, swap_xy;
101
102 int vector_updates; /* avgdvg_go_w()'s per Mame frame, should be 1 */
103
104
105 #define BANK_SIZE (0x2000)
106 #define NUM_BANKS (2)
107 static unsigned char *vectorbank[NUM_BANKS];
108
109 static rgb_t sparkle_callback(void);
110
111
112
113 /*************************************
114 *
115 * Compute 2's complement value
116 *
117 *************************************/
118
twos_comp_val(int num,int bits)119 static INLINE int twos_comp_val(int num, int bits)
120 {
121 return (INT32)(num << (32 - bits)) >> (32 - bits);
122 }
123
124
125
126 /*************************************
127 *
128 * Vector RAM accesses
129 *
130 *************************************/
131
vector_word(UINT16 offset)132 static INLINE UINT16 vector_word(UINT16 offset)
133 {
134 UINT8 *base;
135
136 /* convert from word offset to byte */
137 offset *= 2;
138
139 /* get address of the word */
140 base = &vectorbank[offset / BANK_SIZE][offset % BANK_SIZE];
141
142 /* result is based on flipword */
143 if (flipword)
144 return base[1] | (base[0] << 8);
145 else
146 return base[0] | (base[1] << 8);
147 }
148
149
150
151 /*************************************
152 *
153 * Vector timing
154 *
155 *************************************/
156
vector_timer(int deltax,int deltay)157 static INLINE int vector_timer(int deltax, int deltay)
158 {
159 deltax = abs(deltax);
160 deltay = abs(deltay);
161 if (deltax > deltay)
162 return deltax >> 16;
163 else
164 return deltay >> 16;
165 }
166
167
dvg_vector_timer(int scale)168 static INLINE int dvg_vector_timer(int scale)
169 {
170 return scale;
171 }
172
173
174
175 /*************************************
176 *
177 * AVG brightness computation
178 *
179 *************************************/
180
effective_z(int z,int statz)181 static INLINE int effective_z(int z, int statz)
182 {
183 /* Star Wars blends Z and an 8-bit STATZ */
184 /* STATZ of 128 should give highest intensity */
185 if (vector_engine == USE_AVG_SWARS)
186 {
187 z = (z * statz) / (options.translucency ? 12 : 8);
188 if (z > 0xff)
189 z = 0xff;
190 }
191
192 /* everyone else uses this */
193 else
194 {
195 /* special case for Alpha One -- no idea if this is right */
196 if (vector_engine == USE_AVG_ALPHAONE)
197 {
198 if (z)
199 z ^= 0x15;
200 }
201
202 /* Z == 2 means use the value from STATZ */
203 else if (z == 2)
204 z = statz;
205
206 z *= (options.translucency) ? BRIGHTNESS : 16;
207 }
208
209 return z;
210 }
211
212
213
214 /*************************************
215 *
216 * DVG vector generator
217 *
218 *************************************/
219
dvg_generate_vector_list(void)220 static int dvg_generate_vector_list(void)
221 {
222 static const char *dvg_mnem[] =
223 {
224 "????", "vct1", "vct2", "vct3",
225 "vct4", "vct5", "vct6", "vct7",
226 "vct8", "vct9", "labs", "halt",
227 "jsrl", "rtsl", "jmpl", "svec"
228 };
229
230 int stack[MAXSTACK];
231 int pc = 0;
232 int sp = 0;
233 int scale = 0;
234 int currentx = 0, currenty = 0;
235 int total_length = 1;
236 int done = 0;
237
238 int firstwd, secondwd = 0;
239 int opcode;
240 int x, y, z, temp, a;
241 int deltax, deltay;
242
243 /* reset the vector list */
244 vector_clear_list();
245
246 /* loop until finished */
247 while (!done)
248 {
249 /* fetch the first word and get its opcode */
250 firstwd = vector_word(pc++);
251 opcode = firstwd >> 12;
252
253 /* the DVCTR and DLABS opcodes take two words */
254 if (opcode >= 0 && opcode <= DLABS)
255 secondwd = vector_word(pc++);
256
257 /* debugging */
258 VGLOG(("%4x: %4x ", pc, firstwd));
259 if (opcode <= DLABS)
260 {
261 (void)dvg_mnem;
262 VGLOG(("%s ", dvg_mnem[opcode]));
263 VGLOG(("%4x ", secondwd));
264 }
265
266 /* switch off the opcode */
267 switch (opcode)
268 {
269 /* 0 is an invalid opcode */
270 case 0:
271 VGLOG(("Error: DVG opcode 0! Addr %4x Instr %4x %4x\n", pc-2, firstwd, secondwd));
272 #ifdef VG_DEBUG
273 done = 1;
274 break;
275 #endif
276
277 /* 1-9 are DVCTR ops: draw a vector */
278 case 1:
279 case 2:
280 case 3:
281 case 4:
282 case 5:
283 case 6:
284 case 7:
285 case 8:
286 case 9:
287
288 /* compute raw X and Y values */
289 y = firstwd & 0x03ff;
290 x = secondwd & 0x3ff;
291 if (firstwd & 0x400)
292 y = -y;
293 if (secondwd & 0x400)
294 x = -x;
295
296 /* determine the brightness */
297 z = secondwd >> 12;
298 VGLOG(("(%d,%d) z: %d scal: %d", x, y, z, opcode));
299
300 /* compute the effective brightness */
301 z = effective_z(z, z);
302
303 /* determine the scale factor; scale 9 means -1 */
304 temp = ((scale + opcode) & 0x0f);
305 if (temp > 9)
306 temp = -1;
307
308 /* compute the deltas */
309 deltax = (x << 16) >> (9-temp);
310 deltay = (y << 16) >> (9-temp);
311
312 /* adjust the current position and compute timing */
313 currentx += deltax;
314 currenty -= deltay;
315 total_length += dvg_vector_timer(temp);
316
317 /* add the new point */
318 vector_add_point(currentx, currenty, colorram[1], z);
319 break;
320
321 /* DSVEC: draw a short vector */
322 case DSVEC:
323
324 /* compute raw X and Y values */
325 y = firstwd & 0x0300;
326 x = (firstwd & 0x03) << 8;
327 if (firstwd & 0x0400)
328 y = -y;
329 if (firstwd & 0x04)
330 x = -x;
331
332 /* determine the brightness */
333 z = (firstwd >> 4) & 0x0f;
334
335 /* compute the effective brightness */
336 z = effective_z(z, z);
337
338 /* determine the scale factor; scale 9 means -1 */
339 temp = 2 + ((firstwd >> 2) & 0x02) + ((firstwd >> 11) & 0x01);
340 temp = (scale + temp) & 0x0f;
341 if (temp > 9)
342 temp = -1;
343 VGLOG(("(%d,%d) z: %d scal: %d", x, y, z, temp));
344
345 /* compute the deltas */
346 deltax = (x << 16) >> (9 - temp);
347 deltay = (y << 16) >> (9 - temp);
348
349 /* adjust the current position and compute timing */
350 currentx += deltax;
351 currenty -= deltay;
352 total_length += dvg_vector_timer(temp);
353
354 /* add the new point */
355 vector_add_point(currentx, currenty, colorram[1], z);
356 break;
357
358 /* DLABS: move to an absolute location */
359 case DLABS:
360
361 /* extract the new X,Y coordinates */
362 y = twos_comp_val(firstwd, 12);
363 x = twos_comp_val(secondwd, 12);
364
365 /* global scale comes from upper 4 bits of second word */
366 scale = secondwd >> 12;
367
368 /* set the current X,Y */
369 currentx = (x - xmin) << 16;
370 currenty = (ymax - y) << 16;
371 VGLOG(("(%d,%d) scal: %d", x, y, secondwd >> 12));
372 break;
373
374 /* DRTSL: return from subroutine */
375 case DRTSL:
376
377 /* handle stack underflow */
378 if (sp == 0)
379 {
380 logerror("\n*** Vector generator stack underflow! ***\n");
381 done = 1;
382 sp = MAXSTACK - 1;
383 }
384 else
385 sp--;
386
387 /* pull the new PC from the stack */
388 pc = stack[sp];
389
390 /* debugging */
391 if (firstwd & 0x1fff)
392 VGLOG(("(%d?)", firstwd & 0x1fff));
393 break;
394
395 /* DHALT: all done! */
396 case DHALT:
397 done = 1;
398
399 /* debugging */
400 if (firstwd & 0x1fff)
401 VGLOG(("(%d?)", firstwd & 0x0fff));
402 break;
403
404 /* DJMPL: jump to a new program location */
405 case DJMPL:
406 a = firstwd & 0x0fff;
407 VGLOG(("%4x", a));
408 pc = a;
409
410 if (!pc)
411 done=1;
412 break;
413
414 /* DJSRL: jump to a new program location as subroutine */
415 case DJSRL:
416 a = firstwd & 0x0fff;
417 VGLOG(("%4x", a));
418
419 /* push the next PC on the stack */
420 stack[sp] = pc;
421
422 /* check for stack overflows */
423 if (sp == (MAXSTACK - 1))
424 {
425 logerror("\n*** Vector generator stack overflow! ***\n");
426 done = 1;
427 sp = 0;
428 }
429 else
430 sp++;
431
432 /* jump to the new location */
433 pc = a;
434 break;
435
436 /* anything else gets caught here */
437 default:
438 logerror("Unknown DVG opcode found\n");
439 done = 1;
440 }
441 VGLOG(("\n"));
442 }
443
444 /* return the total length of everything drawn */
445 return total_length;
446 }
447
avg_set_flip_x(int flip)448 void avg_set_flip_x(int flip)
449 {
450 if (flip)
451 flip_x = 1;
452 }
453
avg_set_flip_y(int flip)454 void avg_set_flip_y(int flip)
455 {
456 if (flip)
457 flip_y = 1;
458 }
459
avg_apply_flipping_and_swapping(int * x,int * y)460 void avg_apply_flipping_and_swapping(int *x, int *y)
461 {
462 if (flip_x)
463 *x += (xcenter-*x)<<1;
464 if (flip_y)
465 *y += (ycenter-*y)<<1;
466
467 if (swap_xy)
468 {
469 int temp = *x;
470 *x = *y - ycenter + xcenter;
471 *y = temp - xcenter + ycenter;
472 }
473 }
474
avg_add_point(int x,int y,rgb_t color,int intensity)475 void avg_add_point(int x, int y, rgb_t color, int intensity)
476 {
477 avg_apply_flipping_and_swapping(&x, &y);
478 vector_add_point(x, y, color, intensity);
479 }
480
avg_add_point_callback(int x,int y,rgb_t (* color_callback)(void),int intensity)481 void avg_add_point_callback(int x, int y, rgb_t (*color_callback)(void), int intensity)
482 {
483 avg_apply_flipping_and_swapping(&x, &y);
484 vector_add_point_callback(x, y, color_callback, intensity);
485 }
486
487 /*************************************
488 *
489 * AVG vector generator
490 *
491 *************************************
492
493 Atari Analog Vector Generator Instruction Set
494
495 Compiled from Atari schematics and specifications
496 Eric Smith 7/2/92
497 ---------------------------------------------
498
499 NOTE: The vector generator is little-endian. The instructions are 16 bit
500 words, which need to be stored with the least significant byte in the
501 lower (even) address. They are shown here with the MSB on the left.
502
503 The stack allows four levels of subroutine calls in the TTL version, but only
504 three levels in the gate array version.
505
506 inst bit pattern description
507 ---- ------------------- -------------------
508 VCTR 000- yyyy yyyy yyyy normal vector
509 zzz- xxxx xxxx xxxx
510 HALT 001- ---- ---- ---- halt - does CNTR also on newer hardware
511 SVEC 010y yyyy zzzx xxxx short vector - don't use zero length
512 STAT 0110 ---- zzzz cccc status
513 SCAL 0111 -bbb llll llll scaling
514 CNTR 100- ---- dddd dddd center
515 JSRL 101a aaaa aaaa aaaa jump to subroutine
516 RTSL 110- ---- ---- ---- return
517 JMPL 111a aaaa aaaa aaaa jump
518
519 - unused bits
520 x, y relative x and y coordinates in two's complement (5 or 13 bit,
521 5 bit quantities are scaled by 2, so x=1 is really a length 2 vector.
522 z intensity, 0 = blank, 1 means use z from STAT instruction, 2-7 are
523 doubled for actual range of 4-14
524 c color
525 b binary scaling, multiplies all lengths by 2**(1-b), 0 is double size,
526 1 is normal, 2 is half, 3 is 1/4, etc.
527 l linear scaling, multiplies all lengths by 1-l/256, don't exceed $80
528 d delay time, use $40
529 a address (word address relative to base of vector memory)
530
531 Notes:
532
533 Quantum:
534 the VCTR instruction has a four bit Z field, that is not
535 doubled. The value 2 means use Z from STAT instruction.
536
537 the SVEC instruction can't be used
538
539 Major Havoc:
540 SCAL bit 11 is used for setting a Y axis window.
541
542 STAT bit 11 is used to enable "sparkle" color.
543 STAT bit 10 inverts the X axis of vectors.
544 STAT bits 9 and 8 are the Vector ROM bank select.
545
546 Star Wars:
547 STAT bits 10, 9, and 8 are used directly for R, G, and B.
548
549 *************************************/
550
avg_generate_vector_list(void)551 static int avg_generate_vector_list(void)
552 {
553 static const char *avg_mnem[] =
554 {
555 "vctr", "halt", "svec", "stat", "cntr",
556 "jsrl", "rtsl", "jmpl", "scal"
557 };
558
559 int stack[MAXSTACK];
560 int pc = 0;
561 int sp = 0;
562 int scale = 0;
563 int statz = 0;
564 int sparkle = 0;
565 int xflip = 0;
566 int color = 0;
567 int ywindow = 1;
568 int currentx = xcenter;
569 int currenty = ycenter;
570 int total_length = 1;
571 int done = 0;
572
573 int firstwd, secondwd = 0;
574 int opcode;
575 int x, y, z = 0, b, l, d, a;
576 int deltax, deltay;
577
578 /* check for zeroed vector RAM */
579 if (vector_word(pc) == 0 && vector_word(pc + 1) == 0)
580 {
581 logerror("VGO with zeroed vector memory\n");
582 return total_length;
583 }
584
585 /* kludge to bypass Major Havoc's empty frames */
586 if ((vector_engine == USE_AVG_MHAVOC || vector_engine == USE_AVG_ALPHAONE) && vector_word(pc) == 0xafe2)
587 return total_length;
588
589 /* reset the vector list */
590 vector_clear_list();
591
592 /* loop until finished... */
593 while (!done)
594 {
595 /* fetch the first word and get its opcode */
596 firstwd = vector_word(pc++);
597 opcode = firstwd >> 13;
598
599 /* the VCTR opcode takes two words */
600 if (opcode == VCTR)
601 secondwd = vector_word(pc++);
602
603 /* SCAL is a variant of STAT; convert it here */
604 else if (opcode == STAT && (firstwd & 0x1000))
605 opcode = SCAL;
606
607 /* debugging */
608 (void)avg_mnem;
609 VGLOG(("%4x: %4x ", pc, firstwd));
610 if (opcode == VCTR)
611 VGLOG(("%4x ", secondwd));
612 else
613 VGLOG((" "));
614 VGLOG(("%s ", avg_mnem[opcode]));
615
616 /* switch off the opcode */
617 switch (opcode)
618 {
619 /* VCTR: draw a long vector */
620 case VCTR:
621
622 /* Quantum uses 12-bit vectors and a 4-bit Z value */
623 if (vector_engine == USE_AVG_QUANTUM)
624 {
625 x = twos_comp_val(secondwd, 12);
626 y = twos_comp_val(firstwd, 12);
627 z = (secondwd >> 12) & 0x0f;
628 }
629
630 /* everyone else uses 13-bit vectors and a 3-bit Z value */
631 else
632 {
633 x = twos_comp_val(secondwd, 13);
634 y = twos_comp_val(firstwd, 13);
635 z = (secondwd >> 12) & 0x0e;
636 }
637
638 /* compute the effective brightness */
639 z = effective_z(z, statz);
640
641 /* compute the deltas */
642 deltax = x * scale;
643 deltay = y * scale;
644 if (xflip) deltax = -deltax;
645
646 /* adjust the current position and compute timing */
647 currentx += deltax;
648 currenty -= deltay;
649 total_length += vector_timer(deltax, deltay);
650
651 /* add the new point */
652 if (sparkle)
653 avg_add_point_callback(currentx, currenty, sparkle_callback, z);
654 else
655 avg_add_point(currentx, currenty, colorram[color], z);
656 VGLOG(("VCTR x:%d y:%d z:%d statz:%d", x, y, z, statz));
657 break;
658
659 /* SVEC: draw a short vector */
660 case SVEC:
661
662 /* Quantum doesn't support this */
663 if (vector_engine == USE_AVG_QUANTUM)
664 break;
665
666 /* two 5-bit vectors plus a 3-bit Z value */
667 x = twos_comp_val(firstwd, 5) * 2;
668 y = twos_comp_val(firstwd >> 8, 5) * 2;
669 z = (firstwd >> 4) & 0x0e;
670
671 /* compute the effective brightness */
672 z = effective_z(z, statz);
673
674 /* compute the deltas */
675 deltax = x * scale;
676 deltay = y * scale;
677 if (xflip) deltax = -deltax;
678
679 /* adjust the current position and compute timing */
680 currentx += deltax;
681 currenty -= deltay;
682 total_length += vector_timer(deltax, deltay);
683
684 /* add the new point */
685 if (sparkle)
686 avg_add_point_callback(currentx, currenty, sparkle_callback, z);
687 else
688 avg_add_point(currentx, currenty, colorram[color], z);
689 VGLOG(("SVEC x:%d y:%d z:%d statz:%d", x, y, z, statz));
690 break;
691
692 /* STAT: control colors, clipping, sparkling, and flipping */
693 case STAT:
694
695 /* Star Wars takes RGB directly and has an 8-bit brightness */
696 if (vector_engine == USE_AVG_SWARS)
697 {
698 color = (firstwd >> 8) & 7;
699 statz = firstwd & 0xff;
700 }
701
702 /* everyone else has a 4-bit color and 4-bit brightness */
703 else
704 {
705 color = firstwd & 0x0f;
706 statz = (firstwd >> 4) & 0x0f;
707 }
708
709 /* Tempest has the sparkle bit in bit 11 */
710 if (vector_engine == USE_AVG_TEMPEST)
711 sparkle = !(firstwd & 0x0800);
712
713 /* Major Havoc/Alpha One have sparkle bit, xflip, and banking */
714 else if (vector_engine == USE_AVG_MHAVOC || vector_engine == USE_AVG_ALPHAONE)
715 {
716 sparkle = firstwd & 0x0800;
717 xflip = firstwd & 0x0400;
718 vectorbank[1] = &memory_region(REGION_CPU1)[0x18000 + ((firstwd >> 8) & 3) * 0x2000];
719 }
720
721 /* BattleZone has a clipping circuit */
722 else if (vector_engine == USE_AVG_BZONE)
723 {
724 int newymin = (color == 0) ? 0x0050 : ymin;
725 vector_add_clip(xmin << 16, newymin << 16,
726 xmax << 16, ymax << 16);
727 }
728
729 /* debugging */
730 VGLOG(("STAT: statz: %d color: %d", statz, color));
731 if (xflip || sparkle)
732 VGLOG(("xflip: %02x sparkle: %02x\n", xflip, sparkle));
733 break;
734
735 /* SCAL: set the scale factor */
736 case SCAL:
737 b = ((firstwd >> 8) & 7) + 8;
738 l = ~firstwd & 0xff;
739 scale = (l << 16) >> b;
740
741 /* Y-Window toggle for Major Havoc */
742 if (vector_engine == USE_AVG_MHAVOC || vector_engine == USE_AVG_ALPHAONE)
743 if (firstwd & 0x0800)
744 {
745 int newymin = ymin;
746 logerror("CLIP %d\n", firstwd & 0x0800);
747
748 /* toggle the current state */
749 ywindow = !ywindow;
750
751 /* adjust accordingly */
752 if (ywindow)
753 newymin = (vector_engine == USE_AVG_MHAVOC) ? 0x0048 : 0x0083;
754 vector_add_clip(xmin << 16, newymin << 16,
755 xmax << 16, ymax << 16);
756 }
757
758 /* debugging */
759 VGLOG(("bin: %d, lin: ", b));
760 if (l > 0x80)
761 VGLOG(("(%d?)", l));
762 else
763 VGLOG(("%d", l));
764 VGLOG((" scale: %f", (scale/(float)(1<<16))));
765 break;
766
767 /* CNTR: center the beam */
768 case CNTR:
769
770 /* delay stored in low 8 bits; normally is 0x40 */
771 d = firstwd & 0xff;
772 if (d != 0x40) VGLOG(("%d", d));
773
774 /* move back to the middle */
775 currentx = xcenter;
776 currenty = ycenter;
777 avg_add_point(currentx, currenty, 0, 0);
778 break;
779
780 /* RTSL: return from subroutine */
781 case RTSL:
782
783 /* handle stack underflow */
784 if (sp == 0)
785 {
786 logerror("\n*** Vector generator stack underflow! ***\n");
787 done = 1;
788 sp = MAXSTACK - 1;
789 }
790 else
791 sp--;
792
793 /* pull the new PC from the stack */
794 pc = stack[sp];
795
796 /* debugging */
797 if (firstwd & 0x1fff)
798 VGLOG(("(%d?)", firstwd & 0x1fff));
799 break;
800
801 /* HALT: all done! */
802 case HALT:
803 done = 1;
804
805 /* debugging */
806 if (firstwd & 0x1fff)
807 VGLOG(("(%d?)", firstwd & 0x1fff));
808 break;
809
810 /* JMPL: jump to a new program location */
811 case JMPL:
812 a = firstwd & 0x1fff;
813 VGLOG(("%4x", a));
814
815 /* if a = 0x0000, treat as HALT */
816 if (a == 0x0000)
817 done = 1;
818 else
819 pc = a;
820 break;
821
822 /* JSRL: jump to a new program location as subroutine */
823 case JSRL:
824 a = firstwd & 0x1fff;
825 VGLOG(("%4x", a));
826
827 /* if a = 0x0000, treat as HALT */
828 if (a == 0x0000)
829 done = 1;
830 else
831 {
832 /* push the next PC on the stack */
833 stack[sp] = pc;
834
835 /* check for stack overflows */
836 if (sp == (MAXSTACK - 1))
837 {
838 logerror("\n*** Vector generator stack overflow! ***\n");
839 done = 1;
840 sp = 0;
841 }
842 else
843 sp++;
844
845 /* jump to the new location */
846 pc = a;
847 }
848 break;
849
850 /* anything else gets caught here */
851 default:
852 logerror("internal error\n");
853 }
854 VGLOG(("\n"));
855 }
856
857 /* return the total length of everything drawn */
858 return total_length;
859 }
860
861
862
863 /*************************************
864 *
865 * AVG execution/busy detection
866 *
867 ************************************/
868
avgdvg_done(void)869 int avgdvg_done(void)
870 {
871 return !busy;
872 }
873
874
avgdvg_clr_busy(int dummy)875 static void avgdvg_clr_busy(int dummy)
876 {
877 busy = 0;
878 }
879
880
WRITE_HANDLER(avgdvg_go_w)881 WRITE_HANDLER( avgdvg_go_w )
882 {
883 int total_length;
884
885 /* skip if already busy */
886 if (busy)
887 return;
888
889 /* count vector updates and mark ourselves busy */
890 vector_updates++;
891 busy = 1;
892
893 /* DVG case */
894 if (vector_engine == USE_DVG)
895 {
896 total_length = dvg_generate_vector_list();
897 timer_set(TIME_IN_NSEC(4500) * total_length, 0, avgdvg_clr_busy);
898 }
899
900 /* AVG case */
901 else
902 {
903 total_length = avg_generate_vector_list();
904
905 /* for Major Havoc, we need to look for empty frames */
906 if (total_length > 1)
907 timer_set(TIME_IN_NSEC(1500) * total_length, 0, avgdvg_clr_busy);
908 else
909 {
910 vector_updates--;
911 busy = 0;
912 }
913 }
914 }
915
916
WRITE16_HANDLER(avgdvg_go_word_w)917 WRITE16_HANDLER( avgdvg_go_word_w )
918 {
919 avgdvg_go_w(offset, data);
920 }
921
922
923
924 /*************************************
925 *
926 * AVG reset
927 *
928 ************************************/
929
WRITE_HANDLER(avgdvg_reset_w)930 WRITE_HANDLER( avgdvg_reset_w )
931 {
932 avgdvg_clr_busy(0);
933 }
934
935
WRITE16_HANDLER(avgdvg_reset_word_w)936 WRITE16_HANDLER( avgdvg_reset_word_w )
937 {
938 avgdvg_clr_busy(0);
939 }
940
941
942
943 /*************************************
944 *
945 * Vector generator init
946 *
947 ************************************/
948
avgdvg_init(int vector_type)949 int avgdvg_init(int vector_type)
950 {
951 int i;
952
953 /* 0 vector RAM size is invalid */
954 if (vectorram_size == 0)
955 {
956 logerror("Error: vectorram_size not initialized\n");
957 return 1;
958 }
959
960 /* initialize the pages */
961 for (i = 0; i < NUM_BANKS; i++)
962 vectorbank[i] = vectorram + i * BANK_SIZE;
963 if (vector_type == USE_AVG_MHAVOC || vector_type == USE_AVG_ALPHAONE)
964 vectorbank[1] = &memory_region(REGION_CPU1)[0x18000];
965
966 /* set the engine type and validate it */
967 vector_engine = vector_type;
968 if (vector_engine < AVGDVG_MIN || vector_engine > AVGDVG_MAX)
969 {
970 logerror("Error: unknown Atari Vector Game Type\n");
971 return 1;
972 }
973
974 /* Star Wars is reverse-endian */
975 if (vector_engine == USE_AVG_SWARS)
976 flipword = 1;
977
978 /* Quantum may be reverse-endian depending on the platform */
979 #ifdef MSB_FIRST
980 else if (vector_engine==USE_AVG_QUANTUM)
981 flipword = 1;
982 #endif
983
984 /* everyone else is standard */
985 else
986 flipword = 0;
987
988 /* clear the busy state */
989 busy = 0;
990
991 /* compute the min/max values */
992 xmin = Machine->visible_area.min_x;
993 ymin = Machine->visible_area.min_y;
994 xmax = Machine->visible_area.max_x;
995 ymax = Machine->visible_area.max_y;
996 width = xmax - xmin;
997 height = ymax - ymin;
998
999 /* determine the center points */
1000 xcenter = ((xmax + xmin) / 2) << 16;
1001 ycenter = ((ymax + ymin) / 2) << 16;
1002
1003 /* initialize to no avg flipping */
1004 flip_x = flip_y = 0;
1005
1006 /* Tempest and Quantum have X and Y swapped */
1007 if ((vector_type == USE_AVG_TEMPEST) ||
1008 (vector_type == USE_AVG_QUANTUM))
1009 swap_xy = 1;
1010 else
1011 swap_xy = 0;
1012
1013 return video_start_vector();
1014 }
1015
1016
1017
1018 /*************************************
1019 *
1020 * Video startup
1021 *
1022 ************************************/
1023
VIDEO_START(dvg)1024 VIDEO_START( dvg )
1025 {
1026 return avgdvg_init(USE_DVG);
1027 }
1028
1029
VIDEO_START(avg)1030 VIDEO_START( avg )
1031 {
1032 return avgdvg_init(USE_AVG);
1033 }
1034
1035
VIDEO_START(avg_starwars)1036 VIDEO_START( avg_starwars )
1037 {
1038 return avgdvg_init(USE_AVG_SWARS);
1039 }
1040
1041
VIDEO_START(avg_tempest)1042 VIDEO_START( avg_tempest )
1043 {
1044 return avgdvg_init(USE_AVG_TEMPEST);
1045 }
1046
1047
VIDEO_START(avg_mhavoc)1048 VIDEO_START( avg_mhavoc )
1049 {
1050 return avgdvg_init(USE_AVG_MHAVOC);
1051 }
1052
1053
VIDEO_START(avg_alphaone)1054 VIDEO_START( avg_alphaone )
1055 {
1056 return avgdvg_init(USE_AVG_ALPHAONE);
1057 }
1058
1059
VIDEO_START(avg_bzone)1060 VIDEO_START( avg_bzone )
1061 {
1062 return avgdvg_init(USE_AVG_BZONE);
1063 }
1064
1065
VIDEO_START(avg_quantum)1066 VIDEO_START( avg_quantum )
1067 {
1068 return avgdvg_init(USE_AVG_QUANTUM);
1069 }
1070
1071
VIDEO_START(avg_redbaron)1072 VIDEO_START( avg_redbaron )
1073 {
1074 return avgdvg_init(USE_AVG_RBARON);
1075 }
1076
1077
1078
1079 /*************************************
1080 *
1081 * Palette generation
1082 *
1083 ************************************/
1084
1085 /* Black and White vector colors for Asteroids, Lunar Lander, Omega Race */
PALETTE_INIT(avg_white)1086 PALETTE_INIT( avg_white )
1087 {
1088 int i;
1089 for (i = 0; i < 32; i++)
1090 colorram[i] = MAKE_RGB(0xff, 0xff, 0xff);
1091 }
1092
1093
1094 /* Basic 8 rgb vector colors for Tempest, Gravitar, Major Havoc etc. */
PALETTE_INIT(avg_multi)1095 PALETTE_INIT( avg_multi )
1096 {
1097 int i;
1098 for (i = 0; i < 32; i++)
1099 colorram[i] = VECTOR_COLOR111(i);
1100 }
1101
1102
1103
1104 /*************************************
1105 *
1106 * Color RAM handling
1107 *
1108 ************************************/
1109
WRITE_HANDLER(tempest_colorram_w)1110 WRITE_HANDLER( tempest_colorram_w )
1111 {
1112 int bit3 = (~data >> 3) & 1;
1113 int bit2 = (~data >> 2) & 1;
1114 int bit1 = (~data >> 1) & 1;
1115 int bit0 = (~data >> 0) & 1;
1116 int r = bit1 * 0xee + bit0 * 0x11;
1117 int g = bit3 * 0xee;
1118 int b = bit2 * 0xee;
1119
1120 colorram[offset] = MAKE_RGB(r, g, b);
1121 }
1122
1123
WRITE_HANDLER(mhavoc_colorram_w)1124 WRITE_HANDLER( mhavoc_colorram_w )
1125 {
1126 int bit3 = (~data >> 3) & 1;
1127 int bit2 = (~data >> 2) & 1;
1128 int bit1 = (~data >> 1) & 1;
1129 int bit0 = (~data >> 0) & 1;
1130 int r = bit3 * 0xee + bit2 * 0x11;
1131 int g = bit1 * 0xee;
1132 int b = bit0 * 0xee;
1133
1134 colorram[offset] = MAKE_RGB(r, g, b);
1135 }
1136
1137
WRITE16_HANDLER(quantum_colorram_w)1138 WRITE16_HANDLER( quantum_colorram_w )
1139 {
1140 if (ACCESSING_LSB)
1141 {
1142 int bit3 = (~data >> 3) & 1;
1143 int bit2 = (~data >> 2) & 1;
1144 int bit1 = (~data >> 1) & 1;
1145 int bit0 = (~data >> 0) & 1;
1146 int r = bit3 * 0xee;
1147 int g = bit1 * 0xee + bit0 * 0x11;
1148 int b = bit2 * 0xee;
1149
1150 colorram[offset & 0x0f] = MAKE_RGB(r, g, b);
1151 }
1152 }
1153
1154
sparkle_callback(void)1155 static rgb_t sparkle_callback(void)
1156 {
1157 return colorram[16 + ((rand() >> 8) & 15)];
1158 }
1159