summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/itech8.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/video/itech8.c')
-rw-r--r--src/mame/video/itech8.c670
1 files changed, 670 insertions, 0 deletions
diff --git a/src/mame/video/itech8.c b/src/mame/video/itech8.c
new file mode 100644
index 00000000000..9f90fb8ad33
--- /dev/null
+++ b/src/mame/video/itech8.c
@@ -0,0 +1,670 @@
+/***************************************************************************
+
+ Incredible Technologies/Strata system
+ (8-bit blitter variant)
+
+****************************************************************************
+
+ The games run in one of two modes, either 4bpp mode with a latched
+ palette nibble, or straight 8bpp.
+
+ arligntn: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+ hstennis: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+ neckneck: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+ ninclown: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+ peggle: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+ rimrockn: 4bpp mode, dp = 00/80, draw to 0xxxx/2xxxx
+
+ dynobop: 8bpp mode, dp = 00/FF, draw to 2xxxx/0xxxx
+ pokrdice: 8bpp mode, dp = 00/FF, draw to 2xxxx/0xxxx
+ slikshot: 8bpp mode, dp = 00/FF, draw to 2xxxx/0xxxx
+
+ gtg: 8bpp mode, dp = C0
+ stratab: 8bpp mode, dp = C0, always draws to 2xxxx
+ wfortune: 8bpp mode, dp = C0, always draws to 2xxxx
+
+****************************************************************************
+
+ 8-bit blitter data format:
+
+ +00 hhhhhhhh MSB of 16-bit source address
+ +01 llllllll LSB of 16-bit source address
+ +02 ---t---- Transparent: when set, don't write 0 nibbles
+ ----r--- RLE: when set, source data is RLE compressed
+ -----y-- Y-flip: when set, draw up instead of down
+ ------x- X-flip: when set, draw right instead of left
+ -------s Shift: when set, offset drawing by one nibble
+ +03 s------- Blit status: when set, blit is in progress
+ +03 -------- Blit start: a write here starts the blit
+ +04 wwwwwwww Width of blit, in bytes
+ +05 hhhhhhhh Height of blit, in rows
+ +06 mmmmmmmm Blit mask, applied to each source pixel
+ +07 ?------- Set by ninclown at startup
+ -4------ Set by games that use 4bpp latched output
+ --?----- Set by gtg, gtg2, peggle, pokrdice, stratab
+ ---l---- Video status LED
+ ----?--- Set by gtg2, ninclown, peggle, stratab
+ ------?- Set by arligntn, neckneck, gtg, gtg2, ninclown, peggle, pokrdice, rimrockn, stratab
+ +08 xxxxxxxx Number of pixels to skip before drawing each row
+ +09 yyyyyyyy Number of rows to draw (the first height - y rows are skipped)
+ +0A eeeeeeee Number of pixels to skip at the end of each row
+ +0B ssssssss Number of rows to skip at the end of drawing
+
+****************************************************************************
+
+ Blitter timing
+
+ Times are in 2MHz NOPs (@ 2 cycles/NOP) after issuing a blit start
+ command:
+
+ 1x1 = 1-2 1x 1 = 1-2
+ 2x1 = 2 1x 2 = 2
+ 3x1 = 2 1x 3 = 2
+ 4x1 = 2 1x 4 = 2
+ 5x1 = 3 1x 5 = 3
+ 6x1 = 3 1x 6 = 3
+ 7x1 = 3-4 1x 7 = 3
+ 8x1 = 4 1x 8 = 4
+ 9x1 = 4 1x 9 = 4
+ 10x1 = 4 1x 10 = 4-5
+ 11x1 = 5 1x 11 = 5
+ 12x1 = 5 1x 12 = 5
+ 13x1 = 5-6 1x 13 = 5
+ 14x1 = 6 1x 14 = 6
+ 15x1 = 6 1x 15 = 6
+ 16x1 = 6-7 1x 16 = 6
+ 24x1 = 9-10 1x 24 = 9
+ 32x1 = 12 1x 32 = 12
+ 48x1 = 17 1x 48 = 17
+ 64x1 = 23 1x 64 = 22
+ 96x1 = 33 1x 96 = 33
+ 128x1 = 44 1x128 = 44
+ 192x1 = 65 1x192 = 65
+ 240x1 = 81-82 1x240 = 81-82
+
+ Times are not affected by transparency or RLE settings at all.
+ Times are slightly variable in nature in my tests (within 1 NOP).
+
+***************************************************************************/
+
+#include "driver.h"
+#include "video/tms34061.h"
+#include "video/tlc34076.h"
+#include "cpu/m6809/m6809.h"
+#include "itech8.h"
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#define FULL_LOGGING 0
+#define BLIT_LOGGING 0
+
+
+
+/*************************************
+ *
+ * Blitter constants
+ *
+ *************************************/
+
+#define BLITTER_ADDRHI blitter_data[0]
+#define BLITTER_ADDRLO blitter_data[1]
+#define BLITTER_FLAGS blitter_data[2]
+#define BLITTER_STATUS blitter_data[3]
+#define BLITTER_WIDTH blitter_data[4]
+#define BLITTER_HEIGHT blitter_data[5]
+#define BLITTER_MASK blitter_data[6]
+#define BLITTER_OUTPUT blitter_data[7]
+#define BLITTER_XSTART blitter_data[8]
+#define BLITTER_YCOUNT blitter_data[9]
+#define BLITTER_XSTOP blitter_data[10]
+#define BLITTER_YSKIP blitter_data[11]
+
+#define BLITFLAG_SHIFT 0x01
+#define BLITFLAG_XFLIP 0x02
+#define BLITFLAG_YFLIP 0x04
+#define BLITFLAG_RLE 0x08
+#define BLITFLAG_TRANSPARENT 0x10
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+UINT8 *itech8_grom_bank;
+
+static UINT8 blitter_data[16];
+static UINT8 blit_in_progress;
+
+static UINT8 page_select;
+
+static offs_t fetch_offset;
+static UINT8 fetch_rle_count;
+static UINT8 fetch_rle_value;
+static UINT8 fetch_rle_literal;
+
+static struct tms34061_display tms_state;
+static UINT8 *grom_base;
+static UINT32 grom_size;
+
+
+
+/*************************************
+ *
+ * TMS34061 interfacing
+ *
+ *************************************/
+
+static void generate_interrupt(int state)
+{
+ itech8_update_interrupts(-1, state, -1);
+
+ if (FULL_LOGGING && state) logerror("------------ DISPLAY INT (%d) --------------\n", video_screen_get_vpos(0));
+}
+
+
+static struct tms34061_interface tms34061intf =
+{
+ 0, /* the screen we are acting on */
+ 8, /* VRAM address is (row << rowshift) | col */
+ 0x40000, /* size of video RAM */
+ generate_interrupt /* interrupt gen callback */
+};
+
+
+
+/*************************************
+ *
+ * Video start
+ *
+ *************************************/
+
+VIDEO_START( itech8 )
+{
+ /* initialize TMS34061 emulation */
+ tms34061_start(&tms34061intf);
+
+ /* get the TMS34061 display state */
+ tms34061_get_display_state(&tms_state);
+
+ /* reset statics */
+ page_select = 0xc0;
+
+ /* fetch the GROM base */
+ grom_base = memory_region(REGION_GFX1);
+ grom_size = memory_region_length(REGION_GFX1);
+}
+
+
+
+/*************************************
+ *
+ * Palette I/O
+ *
+ *************************************/
+
+WRITE8_HANDLER( itech8_palette_w )
+{
+ tlc34076_w(offset/2, data);
+}
+
+
+
+/*************************************
+ *
+ * Paging control
+ *
+ *************************************/
+
+WRITE8_HANDLER( itech8_page_w )
+{
+ video_screen_update_partial(0, video_screen_get_vpos(0));
+ logerror("%04x:display_page = %02X (%d)\n", activecpu_get_pc(), data, video_screen_get_vpos(0));
+ page_select = data;
+}
+
+
+
+
+/*************************************
+ *
+ * Blitter data fetchers
+ *
+ *************************************/
+
+INLINE UINT8 fetch_next_raw(void)
+{
+ return grom_base[fetch_offset++ % grom_size];
+}
+
+
+INLINE void consume_raw(int count)
+{
+ fetch_offset += count;
+}
+
+
+INLINE UINT8 fetch_next_rle(void)
+{
+ if (fetch_rle_count == 0)
+ {
+ fetch_rle_count = grom_base[fetch_offset++ % grom_size];
+ fetch_rle_literal = fetch_rle_count & 0x80;
+ fetch_rle_count &= 0x7f;
+
+ if (!fetch_rle_literal)
+ fetch_rle_value = grom_base[fetch_offset++ % grom_size];
+ }
+
+ fetch_rle_count--;
+ if (fetch_rle_literal)
+ fetch_rle_value = grom_base[fetch_offset++ % grom_size];
+
+ return fetch_rle_value;
+}
+
+
+INLINE void consume_rle(int count)
+{
+ while (count)
+ {
+ int num_to_consume;
+
+ if (fetch_rle_count == 0)
+ {
+ fetch_rle_count = grom_base[fetch_offset++ % grom_size];
+ fetch_rle_literal = fetch_rle_count & 0x80;
+ fetch_rle_count &= 0x7f;
+
+ if (!fetch_rle_literal)
+ fetch_rle_value = grom_base[fetch_offset++ % grom_size];
+ }
+
+ num_to_consume = (count < fetch_rle_count) ? count : fetch_rle_count;
+ count -= num_to_consume;
+
+ fetch_rle_count -= num_to_consume;
+ if (fetch_rle_literal)
+ fetch_offset += num_to_consume;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Core blitter
+ *
+ *************************************/
+
+static void perform_blit(void)
+{
+ offs_t addr = tms_state.regs[TMS34061_XYADDRESS] | ((tms_state.regs[TMS34061_XYOFFSET] & 0x300) << 8);
+ UINT8 shift = (BLITTER_FLAGS & BLITFLAG_SHIFT) ? 4 : 0;
+ int transparent = (BLITTER_FLAGS & BLITFLAG_TRANSPARENT);
+ int ydir = (BLITTER_FLAGS & BLITFLAG_YFLIP) ? -1 : 1;
+ int xdir = (BLITTER_FLAGS & BLITFLAG_XFLIP) ? -1 : 1;
+ int xflip = (BLITTER_FLAGS & BLITFLAG_XFLIP);
+ int rle = (BLITTER_FLAGS & BLITFLAG_RLE);
+ int color = tms34061_latch_r(0);
+ int width = BLITTER_WIDTH;
+ int height = BLITTER_HEIGHT;
+ UINT8 transmaskhi, transmasklo;
+ UINT8 mask = BLITTER_MASK;
+ UINT8 skip[3];
+ int x, y;
+
+ /* debugging */
+ if (FULL_LOGGING)
+ logerror("Blit: scan=%d src=%06x @ (%05x) for %dx%d ... flags=%02x\n",
+ video_screen_get_vpos(0),
+ (*itech8_grom_bank << 16) | (BLITTER_ADDRHI << 8) | BLITTER_ADDRLO,
+ tms_state.regs[TMS34061_XYADDRESS] | ((tms_state.regs[TMS34061_XYOFFSET] & 0x300) << 8),
+ BLITTER_WIDTH, BLITTER_HEIGHT, BLITTER_FLAGS);
+
+ /* initialize the fetcher */
+ fetch_offset = (*itech8_grom_bank << 16) | (BLITTER_ADDRHI << 8) | BLITTER_ADDRLO;
+ fetch_rle_count = 0;
+
+ /* RLE starts with a couple of extra 0's */
+ if (rle)
+ fetch_offset += 2;
+
+ /* select 4-bit versus 8-bit transparency */
+ if (BLITTER_OUTPUT & 0x40)
+ transmaskhi = 0xf0, transmasklo = 0x0f;
+ else
+ transmaskhi = transmasklo = 0xff;
+
+ /* compute horiz skip counts */
+ skip[0] = BLITTER_XSTART;
+ skip[1] = (width <= BLITTER_XSTOP) ? 0 : width - 1 - BLITTER_XSTOP;
+ if (xdir == -1) { int temp = skip[0]; skip[0] = skip[1]; skip[1] = temp; }
+ width -= skip[0] + skip[1];
+
+ /* compute vertical skip counts */
+ if (ydir == 1)
+ {
+ skip[2] = (height <= BLITTER_YCOUNT) ? 0 : height - BLITTER_YCOUNT;
+ if (BLITTER_YSKIP > 1) height -= BLITTER_YSKIP - 1;
+ }
+ else
+ {
+ skip[2] = (height <= BLITTER_YSKIP) ? 0 : height - BLITTER_YSKIP;
+ if (BLITTER_YCOUNT > 1) height -= BLITTER_YCOUNT - 1;
+ }
+
+ /* skip top */
+ for (y = 0; y < skip[2]; y++)
+ {
+ /* skip src and dest */
+ addr += xdir * (width + skip[0] + skip[1]);
+ if (rle)
+ consume_rle(width + skip[0] + skip[1]);
+ else
+ consume_raw(width + skip[0] + skip[1]);
+
+ /* back up one and reverse directions */
+ addr -= xdir;
+ addr += ydir * 256;
+ addr &= 0x3ffff;
+ xdir = -xdir;
+ }
+
+ /* loop over height */
+ for (y = skip[2]; y < height; y++)
+ {
+ /* skip left */
+ addr += xdir * skip[y & 1];
+ if (rle)
+ consume_rle(skip[y & 1]);
+ else
+ consume_raw(skip[y & 1]);
+
+ /* loop over width */
+ for (x = 0; x < width; x++)
+ {
+ UINT8 pix = rle ? fetch_next_rle() : fetch_next_raw();
+
+ /* swap pixels for X flip in 4bpp mode */
+ if (xflip && transmaskhi != 0xff)
+ pix = (pix >> 4) | (pix << 4);
+
+ /* draw upper pixel */
+ if (!transparent || (pix & transmaskhi))
+ {
+ tms_state.vram[addr] = (tms_state.vram[addr] & (0x0f << shift)) | ((pix & mask & 0xf0) >> shift);
+ tms_state.latchram[addr] = (tms_state.latchram[addr] & (0x0f << shift)) | ((color & 0xf0) >> shift);
+ }
+
+ /* draw lower pixel */
+ if (!transparent || (pix & transmasklo))
+ {
+ offs_t addr1 = addr + shift/4;
+ tms_state.vram[addr1] = (tms_state.vram[addr1] & (0xf0 >> shift)) | ((pix & mask & 0x0f) << shift);
+ tms_state.latchram[addr1] = (tms_state.latchram[addr1] & (0xf0 >> shift)) | ((color & 0x0f) << shift);
+ }
+
+ /* advance to the next byte */
+ addr += xdir;
+ }
+
+ /* skip right */
+ addr += xdir * skip[~y & 1];
+ if (rle)
+ consume_rle(skip[~y & 1]);
+ else
+ consume_raw(skip[~y & 1]);
+
+ /* back up one and reverse directions */
+ addr -= xdir;
+ addr += ydir * 256;
+ addr &= 0x3ffff;
+ xdir = -xdir;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Blitter finished callback
+ *
+ *************************************/
+
+static TIMER_CALLBACK( blitter_done )
+{
+ /* turn off blitting and generate an interrupt */
+ blit_in_progress = 0;
+ itech8_update_interrupts(-1, -1, 1);
+
+ if (FULL_LOGGING) logerror("------------ BLIT DONE (%d) --------------\n", video_screen_get_vpos(0));
+}
+
+
+
+/*************************************
+ *
+ * Blitter I/O
+ *
+ *************************************/
+
+READ8_HANDLER( itech8_blitter_r )
+{
+ int result = blitter_data[offset / 2];
+
+ /* debugging */
+ if (FULL_LOGGING) logerror("%04x:blitter_r(%02x)\n", activecpu_get_previouspc(), offset / 2);
+
+ /* low bit seems to be ignored */
+ offset /= 2;
+
+ /* a read from offset 3 clears the interrupt and returns the status */
+ if (offset == 3)
+ {
+ itech8_update_interrupts(-1, -1, 0);
+ if (blit_in_progress)
+ result |= 0x80;
+ else
+ result &= 0x7f;
+ }
+
+ /* a read from offsets 12-15 return input port values */
+ if (offset >= 12 && offset <= 15)
+ result = readinputport(3 + offset - 12);
+
+ return result;
+}
+
+
+WRITE8_HANDLER( itech8_blitter_w )
+{
+ /* low bit seems to be ignored */
+ offset /= 2;
+ blitter_data[offset] = data;
+
+ /* a write to offset 3 starts things going */
+ if (offset == 3)
+ {
+ /* log to the blitter file */
+ if (BLIT_LOGGING)
+ {
+ logerror("Blit: XY=%1X%04X SRC=%02X%02X%02X SIZE=%3dx%3d FLAGS=%02x",
+ (tms_state.regs[TMS34061_XYOFFSET] >> 8) & 0x0f, tms_state.regs[TMS34061_XYADDRESS],
+ *itech8_grom_bank, blitter_data[0], blitter_data[1],
+ blitter_data[4], blitter_data[5],
+ blitter_data[2]);
+ logerror(" %02X %02X %02X [%02X] %02X %02X %02X [%02X]-%02X %02X %02X %02X [%02X %02X %02X %02X]\n",
+ blitter_data[0], blitter_data[1],
+ blitter_data[2], blitter_data[3],
+ blitter_data[4], blitter_data[5],
+ blitter_data[6], blitter_data[7],
+ blitter_data[8], blitter_data[9],
+ blitter_data[10], blitter_data[11],
+ blitter_data[12], blitter_data[13],
+ blitter_data[14], blitter_data[15]);
+ }
+
+ /* perform the blit */
+ perform_blit();
+ blit_in_progress = 1;
+
+ /* set a timer to go off when we're done */
+ timer_set(attotime_mul(ATTOTIME_IN_HZ(12000000/4), BLITTER_WIDTH * BLITTER_HEIGHT + 12), 0, blitter_done);
+ }
+
+ /* debugging */
+ if (FULL_LOGGING) logerror("%04x:blitter_w(%02x)=%02x\n", activecpu_get_previouspc(), offset, data);
+}
+
+
+
+/*************************************
+ *
+ * TMS34061 I/O
+ *
+ *************************************/
+
+WRITE8_HANDLER( itech8_tms34061_w )
+{
+ int func = (offset >> 9) & 7;
+ int col = offset & 0xff;
+
+ /* Column address (CA0-CA8) is hooked up the A0-A7, with A1 being inverted
+ during register access. CA8 is ignored */
+ if (func == 0 || func == 2)
+ col ^= 2;
+
+ /* Row address (RA0-RA8) is not dependent on the offset */
+ tms34061_w(col, 0xff, func, data);
+}
+
+
+READ8_HANDLER( itech8_tms34061_r )
+{
+ int func = (offset >> 9) & 7;
+ int col = offset & 0xff;
+
+ /* Column address (CA0-CA8) is hooked up the A0-A7, with A1 being inverted
+ during register access. CA8 is ignored */
+ if (func == 0 || func == 2)
+ col ^= 2;
+
+ /* Row address (RA0-RA8) is not dependent on the offset */
+ return tms34061_r(col, 0xff, func);
+}
+
+
+
+/*************************************
+ *
+ * Main refresh
+ *
+ *************************************/
+
+VIDEO_UPDATE( itech8_2layer )
+{
+ UINT32 page_offset;
+ int x, y;
+
+ /* first get the current display state */
+ tms34061_get_display_state(&tms_state);
+
+ /* if we're blanked, just fill with black */
+ if (tms_state.blanked)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* there are two layers: */
+ /* top layer @ 0x00000 is only 4bpp, colors come from the first 16 palettes */
+ /* bottom layer @ 0x20000 is full 8bpp */
+ page_offset = tms_state.dispstart & 0x0ffff;
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT8 *base0 = &tms_state.vram[(0x00000 + page_offset + y * 256) & 0x3ffff];
+ UINT8 *base2 = &tms_state.vram[(0x20000 + page_offset + y * 256) & 0x3ffff];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ {
+ int pix0 = base0[x] & 0x0f;
+ dest[x] = pix0 ? pix0 : base2[x];
+ }
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( itech8_2page )
+{
+ UINT32 page_offset;
+ int x, y;
+
+ /* first get the current display state */
+ tms34061_get_display_state(&tms_state);
+
+ /* if we're blanked, just fill with black */
+ if (tms_state.blanked)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* there are two pages, each of which is a full 8bpp */
+ /* page index is selected by the top bit of the page_select register */
+ page_offset = ((page_select & 0x80) << 10) | (tms_state.dispstart & 0x0ffff);
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT8 *base = &tms_state.vram[(page_offset + y * 256) & 0x3ffff];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ for (x = cliprect->min_x; x <= cliprect->max_x; x++)
+ dest[x] = base[x];
+ }
+ return 0;
+}
+
+
+VIDEO_UPDATE( itech8_2page_large )
+{
+ UINT32 page_offset;
+ int x, y;
+
+ /* first get the current display state */
+ tms34061_get_display_state(&tms_state);
+
+ /* if we're blanked, just fill with black */
+ if (tms_state.blanked)
+ {
+ fillbitmap(bitmap, get_black_pen(machine), cliprect);
+ return 0;
+ }
+
+ /* there are two pages, each of which is a full 8bpp */
+ /* the low 4 bits come from the bitmap directly */
+ /* the upper 4 bits were latched on each write into a separate bitmap */
+ /* page index is selected by the top bit of the page_select register */
+ page_offset = ((~page_select & 0x80) << 10) | (tms_state.dispstart & 0x0ffff);
+ for (y = cliprect->min_y; y <= cliprect->max_y; y++)
+ {
+ UINT8 *base = &tms_state.vram[(page_offset + y * 256) & 0x3ffff];
+ UINT8 *latch = &tms_state.latchram[(page_offset + y * 256) & 0x3ffff];
+ UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0);
+
+ for (x = cliprect->min_x & ~1; x <= cliprect->max_x; x += 2)
+ {
+ dest[x + 0] = (latch[x/2] & 0xf0) | (base[x/2] >> 4);
+ dest[x + 1] = ((latch[x/2] << 4) & 0xf0) | (base[x/2] & 0x0f);
+ }
+ }
+ return 0;
+}