diff options
Diffstat (limited to 'src/mame/video/segag80v.c')
-rw-r--r-- | src/mame/video/segag80v.c | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/src/mame/video/segag80v.c b/src/mame/video/segag80v.c new file mode 100644 index 00000000000..42634261adf --- /dev/null +++ b/src/mame/video/segag80v.c @@ -0,0 +1,343 @@ +/************************************************************************* + + Sega vector hardware + +*************************************************************************/ + +#include "driver.h" +#include "avgdvg.h" +#include "video/vector.h" +#include "includes/segag80v.h" +#include <math.h> + +#define VECTOR_CLOCK 15468480 /* master clock */ +#define U34_CLOCK (VECTOR_CLOCK/3) /* clock for interrupt chain */ +#define VCL_CLOCK (U34_CLOCK/2) /* clock for vector generator */ +#define U51_CLOCK (VCL_CLOCK/16) /* clock for phase generator */ +#define IRQ_CLOCK (U34_CLOCK/0x1f788) /* 40Hz interrupt */ + + +static int min_x, min_y; + + +/* + + Vector system is clocked by a 15-phase clock. + + The counter is a LS161 4-bit binary counter at U51, and its output + goes to a LS154 1-of-16 decoder at U50. + + Each phase various things happen. The phases are: + + 0 -> (sheet 7/7) clocks CD7 in + + 1 -> (sheet 5/7) loads CD0-7 into counters at U15/U16 + (sheet 6/7) clear LS175 flip flops at U35, U36, U37, U38 + + 2 -> (sheet 5/7) loads CD0-3 into counter at U17 + + 3 -> (sheet 5/7) loads CD0-7 into counters at U18/U19 + + 4 -> (sheet 5/7) loads CD0-3 into counter at U20 + + 5 -> + + 6 -> + + 7 -> (sheet 6/7) at end, latches CD0-7 into LS374 tri-state flip flop at U55 (SYM angle) + + 8 -> (sheet 6/7) at end, latches CD0-1 into LS74 flip flops at U26 (upper SYM angle) + + 9 -> (sheet 4/7) at end, latches CD0-7 into 25LS14 multiplier X input at U8 (scale) + + 10 -> (sheet 4/7) at end, latches CD0-CD7 into LS374 tri-state flip flop at U2 (attributes) + (sheet 7/7) at end, latches CD7 into U52 (low), which sets the preload value + for the LS161 at U51 to be either 0 (if CD7==1) or 10 (if CD7==0) + + 11 -> (sheet 4/7) at end, starts multiply circuit + + 12 -> (sheet 6/7) at end, latches CD0-7 into LS374 tri-state flip flop at U56 (VEC angle) + + 13 -> (sheet 6/7) at end, latches output from 2708 PROM into tri-state flip flop at U48 + (sheet 6/7) at end, latches bit $200 of angle into D/UX output + + 14 -> (sheet 6/7) at end, latches output from 2708 PROM into tri-state flip flop at U49 + (sheet 6/7) at end, latches bit $200 of angle into D/UY output + (sheet 7/7) signals /PE on the LS161 at U51, loading the new value for the state clock + (sheet 7/7) sets up the DRAW signal to clock on the next VCL edge + + 15 -> + + + + PROM inputs: + A0 = GND + A1-A8 = sum of VEC angle and SYM angle (low 8 bits) + A9 = sum of bit 8 of VEC angle and SYM angle, plus 1 for phase 13 + + +*/ + + +INLINE int adjust_xy(int rawx, int rawy, int *outx, int *outy) +{ + int clipped = FALSE; + + /* first apply the XOR at 0x200 */ + *outx = (rawx & 0x7ff) ^ 0x200; + *outy = (rawy & 0x7ff) ^ 0x200; + + /* apply clipping logic to X */ + if ((*outx & 0x600) == 0x200) + *outx = 0x000, clipped = TRUE; + else if ((*outx & 0x600) == 0x400) + *outx = 0x3ff, clipped = TRUE; + else + *outx &= 0x3ff; + + /* apply clipping logic to Y */ + if ((*outy & 0x600) == 0x200) + *outy = 0x000, clipped = TRUE; + else if ((*outy & 0x600) == 0x400) + *outy = 0x3ff, clipped = TRUE; + else + *outy &= 0x3ff; + + /* convert into .16 values */ + *outx = (*outx - (min_x - 512)) << 16; + *outy = (*outy - (min_y - 512)) << 16; + return clipped; +} + + +static void sega_generate_vector_list(void) +{ + UINT8 *sintable = memory_region(REGION_PROMS); + double total_time = 1.0 / (double)IRQ_CLOCK; + UINT16 symaddr = 0; + + vector_clear_list(); + + /* Loop until we run out of time. */ + while (total_time > 0) + { + UINT16 curx, cury, xaccum, yaccum; + UINT16 vecaddr, symangle; + UINT8 scale, draw; + + /* The "draw" flag is clocked at the end of phase 0. */ + draw = vectorram[symaddr++ & 0xfff]; + + /* The low byte of the X coordinate is latched into the */ + /* up/down counters at U15/U16 during phase 1. */ + curx = vectorram[symaddr++ & 0xfff]; + + /* The low 3 bits of the high byte of the X coordinate are */ + /* latched into the up/down counter at U17 during phase 2. */ + /* Bit 2 of the input is latched as both bit 2 and 3. */ + curx |= (vectorram[symaddr++ & 0xfff] & 7) << 8; + curx |= (curx << 1) & 0x800; + + /* The low byte of the Y coordinate is latched into the */ + /* up/down counters at U18/U19 during phase 3. */ + cury = vectorram[symaddr++ & 0xfff]; + + /* The low 3 bits of the high byte of the X coordinate are */ + /* latched into the up/down counter at U17 during phase 4. */ + /* Bit 2 of the input is latched as both bit 2 and 3. */ + cury |= (vectorram[symaddr++ & 0xfff] & 7) << 8; + cury |= (cury << 1) & 0x800; + + /* The low byte of the vector address is latched into the */ + /* counters at U10/U11 during phase 5. */ + vecaddr = vectorram[symaddr++ & 0xfff]; + + /* The low 4 bits of the high byte of the vector address is */ + /* latched into the counter at U12 during phase 6. */ + vecaddr |= (vectorram[symaddr++ & 0xfff] & 0xf) << 8; + + /* The low byte of the symbol angle is latched into the tri- */ + /* state flip flop at U55 at the end of phase 7. */ + symangle = vectorram[symaddr++ & 0xfff]; + + /* The low 2 bits of the high byte of the symbol angle are */ + /* latched into flip flops at U26 at the end of phase 8. */ + symangle |= (vectorram[symaddr++ & 0xfff] & 3) << 8; + + /* The scale is latched in phase 9 as the X input to the */ + /* 25LS14 multiplier at U8. */ + scale = vectorram[symaddr++ & 0xfff]; + + /* Account for the 10 phases so far. */ + total_time -= 10.0 / (double)U51_CLOCK; + + /* Skip the rest if we're not drawing this symbol. */ + if (draw & 1) + { + int adjx, adjy, clipped; + + /* Add a starting point to the vector list. */ + clipped = adjust_xy(curx, cury, &adjx, &adjy); + if (!clipped) + vector_add_point(adjx, adjy, 0, 0); + + /* Loop until we run out of time. */ + while (total_time > 0) + { + UINT16 vecangle, length, deltax, deltay; + UINT8 attrib, intensity; + UINT32 color; + + /* The 'attribute' byte is latched at the end of phase 10 into */ + /* the tri-state flip flop at U2. The low bit controls whether */ + /* or not the beam is enabled. Bits 1-6 control the RGB color */ + /* (2 bits per component). In addition, bit 7 of this value is */ + /* latched into U52, which controls the pre-load value for the */ + /* phase generator. If bit 7 is high, then the phase generator */ + /* will reset back to 0 and draw a new symbol; if bit 7 is low */ + /* the phase generator will reset back to 10 and draw another */ + /* vector. */ + attrib = vectorram[vecaddr++ & 0xfff]; + + /* The length of the vector is loaded into the shift registers */ + /* at U6/U7 during phase 11. During phase 12, the 25LS14 */ + /* multiplier at U8 is used to multiply the length by the */ + /* scale that was loaded during phase 9. The length is clocked */ + /* bit by bit out of U6/U7 and the result is clocked into the */ + /* other side. After the multiply, the 9 MSBs are loaded into */ + /* the counter chain at U15/16/17 and are used to count how */ + /* long to draw the vector. */ + length = (vectorram[vecaddr++ & 0xfff] * scale) >> 7; + + /* The vector angle low byte is latched at the end of phase 12 */ + /* into the tri-state flip flop at U56. */ + vecangle = vectorram[vecaddr++ & 0xfff]; + + /* The vector angle high byte is preset on the CD bus during */ + /* phases 13 and 14, and is used as inputs to the adder at */ + /* U46. */ + vecangle |= (vectorram[vecaddr++ & 0xfff] & 3) << 8; + + /* The X increment value is looked up first (phase 13). The */ + /* sum of the latched symbol angle and the vector angle is */ + /* used as input to the PROM at U39. A0 is tied to ground. */ + /* A1-A9 map to bits 0-8 of the summed angles. The output from */ + /* the PROM is latched into U48. */ + deltax = sintable[((vecangle + symangle) & 0x1ff) << 1]; + + /* The Y increment value is looked up second (phase 14). The */ + /* angle sum is used once again as the input to the PROM, but */ + /* this time an additional 0x100 is effectively added to it */ + /* before it is used; this separates sin from cos. The output */ + /* from the PROM is latched into U49. */ + deltay = sintable[((vecangle + symangle + 0x100) & 0x1ff) << 1]; + + /* Account for the 4 phases for data fetching. */ + total_time -= 4.0 / (double)U51_CLOCK; + + /* Compute color/intensity values from the attributes */ + color = VECTOR_COLOR222((attrib >> 1) & 0x3f); + if ((attrib & 1) && color) + intensity = 0xff; + else + intensity = 0; + + /* Loop over the length of the vector. */ + clipped = adjust_xy(curx, cury, &adjx, &adjy); + xaccum = yaccum = 0; + while (length-- != 0 && total_time > 0) + { + int newclip; + + /* The adders at U44/U45 are used as X accumulators. The value */ + /* from U48 is repeatedly added to itself here. The carry out */ + /* of bit 8 clocks the up/down counters at U15/U16/U17. Bit 7 */ + /* of the input value from U48 is used as a carry in to round */ + /* small values downward and larger values upward. */ + xaccum += deltax + (deltax >> 7); + + /* Bit 9 of the summed angles controls the direction the up/ */ + /* down counters at U15/U16/U17. */ + if (((vecangle + symangle) & 0x200) == 0) + curx += xaccum >> 8; + else + curx -= xaccum >> 8; + xaccum &= 0xff; + + /* The adders at U46/U47 are used as Y accumulators. The value */ + /* from U49 is repeatedly added to itself here. The carry out */ + /* of bit 8 clocks the up/down counters at U18/U19/U20. Bit 7 */ + /* of the input value from U49 is used as a carry in to round */ + /* small values downward and larger values upward. */ + yaccum += deltay + (deltay >> 7); + + /* Bit 9 of the summed angles controls the direction the up/ */ + /* down counters at U18/U19/U20. */ + if (((vecangle + symangle + 0x100) & 0x200) == 0) + cury += yaccum >> 8; + else + cury -= yaccum >> 8; + yaccum &= 0xff; + + /* Apply the clipping from the DAC circuit. If the values clip */ + /* the beam is turned off, but the computations continue right */ + /* on going. */ + newclip = adjust_xy(curx, cury, &adjx, &adjy); + if (newclip != clipped) + { + /* if we're just becoming unclipped, add an empty point */ + if (!newclip) + vector_add_point(adjx, adjy, 0, 0); + + /* otherwise, add a colored point */ + else + vector_add_point(adjx, adjy, color, intensity); + } + clipped = newclip; + + /* account for vector drawing time */ + total_time -= 1.0 / (double)VCL_CLOCK; + } + + /* We're done; if we are not clipped, add a final point. */ + if (!clipped) + vector_add_point(adjx, adjy, color, intensity); + + /* if the high bit of the attribute is set, we break out of */ + /* this loop and fetch another symbol */ + if (attrib & 0x80) + break; + } + } + + /* if the high bit of the draw flag is set, we break out of this loop */ + /* and stop the rendering altogether for this frame. */ + if (draw & 0x80) + break; + } +} + + +/*************************************************************************** + + Start the video hardware emulation. + +***************************************************************************/ + +VIDEO_START( sega ) +{ + assert_always(vectorram_size != 0, "vectorram==0"); + + min_x =machine->screen[0].visarea.min_x; + min_y =machine->screen[0].visarea.min_y; + + video_start_vector(machine); +} + + +VIDEO_UPDATE( sega ) +{ + sega_generate_vector_list(); + video_update_vector(machine,screen,bitmap,cliprect); + return 0; +} |