summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/namco/polepos_v.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/namco/polepos_v.cpp')
-rw-r--r--src/mame/namco/polepos_v.cpp471
1 files changed, 471 insertions, 0 deletions
diff --git a/src/mame/namco/polepos_v.cpp b/src/mame/namco/polepos_v.cpp
new file mode 100644
index 00000000000..e6823539c76
--- /dev/null
+++ b/src/mame/namco/polepos_v.cpp
@@ -0,0 +1,471 @@
+// license:BSD-3-Clause
+// copyright-holders:Ernesto Corvi, Juergen Buchmueller, Alex Pasadyn, Aaron Giles, Nicola Salmoria
+#include "emu.h"
+#include "polepos.h"
+
+
+/* modified vertical position built from three nibbles (12 bit)
+ * of ROMs 136014-142, 136014-143, 136014-144
+ * The value RVP (road vertical position, lower 12 bits) is added
+ * to this value and the upper 10 bits of the result are used to
+ * address the playfield video memory (AB0 - AB9).
+ */
+
+
+/***************************************************************************
+
+ Convert the color PROMs.
+
+ Pole Position has three 256x4 palette PROMs (one per gun)
+ and a lot ;-) of 256x4 lookup table PROMs.
+ The palette PROMs are connected to the RGB output this way:
+
+ bit 3 -- 220 ohm resistor -- RED/GREEN/BLUE
+ -- 470 ohm resistor -- RED/GREEN/BLUE
+ -- 1 kohm resistor -- RED/GREEN/BLUE
+ bit 0 -- 2.2kohm resistor -- RED/GREEN/BLUE
+
+***************************************************************************/
+
+void polepos_state::polepos_palette(palette_device &palette)
+{
+ uint8_t const *const color_prom = memregion("proms")->base();
+
+ /*******************************************************
+ * Color PROMs
+ * Sheet 15B: middle, 136014-137,138,139
+ * Inputs: MUX0 ... MUX3, ALPHA/BACK, SPRITE/BACK, 128V, COMPBLANK
+ *
+ * Note that we only decode the lower 128 colors because
+ * the upper 128 are all black and used during the
+ * horizontal and vertical blanking periods.
+ * The purpose of the 128V input is to use a different palette for the
+ * background and for the road; it is irrelevant for alpha and
+ * sprites because their palette is the same in both halves.
+ * Anyway, we emulate that to a certain extent, using different
+ * colortables for the two halves of the screen. We don't support the
+ * palette change in the middle of a sprite, however.
+ * Also, note that priority encoding is done is such a way that alpha
+ * will use palette bank 2 or 3 depending on whether there is a sprite
+ * below the pixel or not. That would be tricky to emulate, and it's
+ * not needed because of course the two banks are the same.
+ *******************************************************/
+ for (int i = 0; i < 128; i++)
+ {
+ int bit0, bit1, bit2, bit3;
+
+ // Sheet 15B: 136014-0137 red component
+ bit0 = BIT(color_prom[0x000 + i], 0);
+ bit1 = BIT(color_prom[0x000 + i], 1);
+ bit2 = BIT(color_prom[0x000 + i], 2);
+ bit3 = BIT(color_prom[0x000 + i], 3);
+ int const r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ // Sheet 15B: 136014-0138 green component
+ bit0 = BIT(color_prom[0x100 + i], 0);
+ bit1 = BIT(color_prom[0x100 + i], 1);
+ bit2 = BIT(color_prom[0x100 + i], 2);
+ bit3 = BIT(color_prom[0x100 + i], 3);
+ int const g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ // Sheet 15B: 136014-0139 blue component
+ bit0 = BIT(color_prom[0x200 + i], 0);
+ bit1 = BIT(color_prom[0x200 + i], 1);
+ bit2 = BIT(color_prom[0x200 + i], 2);
+ bit3 = BIT(color_prom[0x200 + i], 3);
+ int const b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
+
+ palette.set_indirect_color(i, rgb_t(r, g, b));
+ }
+
+ /*******************************************************
+ * Alpha colors (colors 0x000-0x1ff)
+ * Sheet 15B: top left, 136014-140
+ * Inputs: SHFT0, SHFT1 and CHA8* ... CHA13*
+ *******************************************************/
+ for (int i = 0; i < 64*4; i++)
+ {
+ int const color = color_prom[0x300 + i];
+ palette.set_pen_indirect(0x0000 + i, (color != 15) ? (0x020 + color) : 0x2f);
+ palette.set_pen_indirect(0x0100 + i, (color != 15) ? (0x060 + color) : 0x2f);
+ }
+
+ /*******************************************************
+ * Background colors (colors 0x200-0x2ff)
+ * Sheet 13A: left, 136014-141
+ * Inputs: SHFT2, SHFT3 and CHA8 ... CHA13
+ * The background is only in the top half of the screen
+ *******************************************************/
+ for (int i = 0; i < 64*4; i++)
+ {
+ int const color = color_prom[0x400 + i];
+ palette.set_pen_indirect(0x0200 + i, 0x000 + color);
+ }
+
+ /*******************************************************
+ * Sprite colors (colors 0x300-0xaff)
+ * Sheet 14B: right, 136014-146
+ * Inputs: CUSTOM0 ... CUSTOM3 and DATA0 ... DATA5
+ *******************************************************/
+ for (int i = 0; i < 64*16; i++)
+ {
+ int const color = color_prom[0xc00 + i];
+ palette.set_pen_indirect(0x0300 + i, (color != 15) ? (0x010 + color) : 0x1f);
+ palette.set_pen_indirect(0x0700 + i, (color != 15) ? (0x050 + color) : 0x1f);
+ }
+
+ /*******************************************************
+ * Road colors (colors 0xb00-0x0eff)
+ * Sheet 13A: bottom left, 136014-145
+ * Inputs: R1 ... R6 and CHA0 ... CHA3
+ * The road is only in the bottom half of the screen
+ *******************************************************/
+ for (int i = 0; i < 64*16; i++)
+ {
+ int const color = color_prom[0x800 + i];
+ palette.set_pen_indirect(0x0b00 + i, 0x040 + color);
+ }
+
+ /* 136014-142, 136014-143, 136014-144 Vertical position modifiers */
+ for (int i = 0; i < 256; i++)
+ {
+ int const j = color_prom[0x500 + i] + (color_prom[0x600 + i] << 4) + (color_prom[0x700 + i] << 8);
+ m_vertical_position_modifier[i] = j;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Callbacks for the TileMap code
+
+***************************************************************************/
+
+TILE_GET_INFO_MEMBER(polepos_state::bg_get_tile_info)
+{
+ uint16_t word = m_view16_memory[tile_index];
+ int code = (word & 0xff) | ((word & 0x4000) >> 6);
+ int color = (word & 0x3f00) >> 8;
+ tileinfo.set(1,
+ code,
+ color,
+ 0);
+}
+
+TILE_GET_INFO_MEMBER(polepos_state::tx_get_tile_info)
+{
+ uint16_t word = m_alpha16_memory[tile_index];
+ int code = (word & 0xff) | ((word & 0x4000) >> 6);
+ int color = (word & 0x3f00) >> 8;
+
+ /* I assume the purpose of CHACL is to allow the Z80 to control
+ the display (therefore using only the bottom 8 bits of tilemap RAM)
+ in case the Z8002 is not working. */
+ if (m_chacl == 0)
+ {
+ code &= 0xff;
+ color = 0;
+ }
+
+ /* 128V input to the palette PROM */
+ if (tile_index >= 32*16) color |= 0x40;
+
+ tileinfo.set(0,
+ code,
+ color,
+ 0);
+ tileinfo.group = color;
+}
+
+
+
+/***************************************************************************
+
+ Start the video hardware emulation.
+
+***************************************************************************/
+
+void polepos_state::video_start()
+{
+ m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(polepos_state::bg_get_tile_info)), TILEMAP_SCAN_COLS, 8, 8, 64, 16);
+ m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(polepos_state::tx_get_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
+
+ m_tx_tilemap->configure_groups(*m_gfxdecode->gfx(0), 0x2f);
+
+ save_item(NAME(m_road16_vscroll));
+ save_item(NAME(m_chacl));
+ save_item(NAME(m_scroll));
+}
+
+
+/***************************************************************************
+
+ Sprite memory
+
+***************************************************************************/
+
+uint8_t polepos_state::sprite_r(offs_t offset)
+{
+ return m_sprite16_memory[offset] & 0xff;
+}
+
+void polepos_state::sprite_w(offs_t offset, uint8_t data)
+{
+ m_sprite16_memory[offset] = (m_sprite16_memory[offset] & 0xff00) | data;
+}
+
+
+/***************************************************************************
+
+ Road memory
+
+***************************************************************************/
+
+uint8_t polepos_state::road_r(offs_t offset)
+{
+ return m_road16_memory[offset] & 0xff;
+}
+
+void polepos_state::road_w(offs_t offset, uint8_t data)
+{
+ m_road16_memory[offset] = (m_road16_memory[offset] & 0xff00) | data;
+}
+
+void polepos_state::road16_vscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_road16_vscroll);
+}
+
+
+/***************************************************************************
+
+ View memory
+
+***************************************************************************/
+
+void polepos_state::view16_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_view16_memory[offset]);
+ if (offset < 0x400)
+ m_bg_tilemap->mark_tile_dirty(offset);
+}
+
+uint8_t polepos_state::view_r(offs_t offset)
+{
+ return m_view16_memory[offset] & 0xff;
+}
+
+void polepos_state::view_w(offs_t offset, uint8_t data)
+{
+ m_view16_memory[offset] = (m_view16_memory[offset] & 0xff00) | data;
+ if (offset < 0x400)
+ m_bg_tilemap->mark_tile_dirty(offset);
+}
+
+void polepos_state::view16_hscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_scroll);
+ m_bg_tilemap->set_scrollx(0,m_scroll);
+}
+
+void polepos_state::chacl_w(int state)
+{
+ m_chacl = state;
+ m_tx_tilemap->mark_all_dirty();
+}
+
+
+/***************************************************************************
+
+ Alpha memory
+
+***************************************************************************/
+
+void polepos_state::alpha16_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_alpha16_memory[offset]);
+ m_tx_tilemap->mark_tile_dirty(offset);
+}
+
+uint8_t polepos_state::alpha_r(offs_t offset)
+{
+ return m_alpha16_memory[offset] & 0xff;
+}
+
+void polepos_state::alpha_w(offs_t offset, uint8_t data)
+{
+ m_alpha16_memory[offset] = (m_alpha16_memory[offset] & 0xff00) | data;
+ m_tx_tilemap->mark_tile_dirty(offset);
+}
+
+
+
+/***************************************************************************
+
+ Display refresh
+
+***************************************************************************/
+
+void polepos_state::draw_road(bitmap_ind16 &bitmap)
+{
+ const uint8_t *road_control = memregion("gfx5")->base();
+ const uint8_t *road_bits1 = road_control + 0x2000;
+ const uint8_t *road_bits2 = road_control + 0x4000;
+
+ /* loop over the lower half of the screen */
+ for (int y = 128; y < 256; y++)
+ {
+ int xoffs, yoffs, xscroll, roadpal;
+ uint16_t scanline[256 + 8];
+ uint16_t *dest = scanline;
+ pen_t pen_base;
+
+ /* first add the vertical position modifier and the vertical scroll */
+ yoffs = ((m_vertical_position_modifier[y] + m_road16_vscroll) >> 3) & 0x1ff;
+
+ /* then use that as a lookup into the road memory */
+ roadpal = m_road16_memory[yoffs] & 15;
+
+ /* this becomes the palette base for the scanline */
+ pen_base = 0x0b00 + (roadpal << 6);
+
+ /* now fetch the horizontal scroll offset for this scanline */
+ xoffs = m_road16_memory[0x380 + (y & 0x7f)] & 0x3ff;
+
+ /* the road is drawn in 8-pixel chunks, so round downward and adjust the base */
+ /* note that we assume there is at least 8 pixels of slop on the left/right */
+ xscroll = xoffs & 7;
+ xoffs &= ~7;
+
+ /* loop over 8-pixel chunks */
+ for (int x = 0; x < 256 / 8 + 1; x++, xoffs += 8)
+ {
+ /* if the 0x200 bit of the xoffset is set, a special pin on the custom */
+ /* chip is set and the /CE and /OE for the road chips is disabled */
+ if (xoffs & 0x200)
+ {
+ /* in this case, it looks like we just fill with 0 */
+ for (int i = 0; i < 8; i++)
+ *dest++ = pen_base | 0;
+ }
+
+ /* otherwise, we clock in the bits and compute the road value */
+ else
+ {
+ /* the road ROM offset comes from the current scanline and the X offset */
+ int romoffs = ((y & 0x07f) << 6) + ((xoffs & 0x1f8) >> 3);
+
+ /* fetch the current data from the road ROMs */
+ int control = road_control[romoffs];
+ int bits1 = road_bits1[romoffs];
+ int bits2 = road_bits2[(romoffs & 0xfff) | ((romoffs & 0x1000) >> 1)];
+
+ /* extract the road value and the carry-in bit */
+ int roadval = control & 0x3f;
+ int carin = control >> 7;
+
+ /* draw this 8-pixel chunk */
+ for (int i = 8; i > 0; i--)
+ {
+ int bits = BIT(bits1,i) + (BIT(bits2,i) << 1);
+ if (!carin && bits) bits++;
+ *dest++ = pen_base | (roadval & 0x3f);
+ roadval += bits;
+ }
+ }
+ }
+
+ /* draw the scanline */
+ draw_scanline16(bitmap, 0, y, 256, &scanline[xscroll], nullptr);
+ }
+}
+
+void polepos_state::zoom_sprite(bitmap_ind16 &bitmap,int big,
+ uint32_t code,uint32_t color,int flipx,int sx,int sy,
+ int sizex,int sizey)
+{
+ gfx_element *gfx = m_gfxdecode->gfx(big ? 3 : 2);
+ const uint8_t *gfxdata = gfx->get_data(code % gfx->elements());
+ uint8_t *scaling_rom = memregion("gfx6")->base();
+ uint32_t transmask = m_palette->transpen_mask(*gfx, color, 0x1f);
+ int coloroffs = gfx->colorbase() + color * gfx->granularity();
+
+ if (flipx) flipx = big ? 0x1f : 0x0f;
+
+ for (int y = 0;y <= sizey;y++)
+ {
+ int yy = (sy + y) & 0x1ff;
+
+ /* the following should be a reasonable reproduction of how the real hardware works */
+ if (yy >= 0x10 && yy < 0xf0)
+ {
+ int dy = scaling_rom[(y << 6) + sizey] & 0x1f;
+ int xx = sx & 0x3ff;
+ int siz = 0;
+ int offs = 0;
+ const uint8_t *src;
+
+ if (!big) dy >>= 1;
+ src = gfxdata + dy * gfx->rowbytes();
+
+ for (int x = (big ? 0x40 : 0x20);x > 0;x--)
+ {
+ if (xx < 0x100)
+ {
+ int pen = src[offs/2 ^ flipx];
+
+ if (!((transmask >> pen) & 1))
+ bitmap.pix(yy, xx) = pen + coloroffs;
+ }
+ offs++;
+
+ siz = siz+1+sizex;
+ if (siz & 0x40)
+ {
+ siz &= 0x3f;
+ xx = (xx+1) & 0x3ff;
+ }
+ }
+ }
+ }
+}
+
+void polepos_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect )
+{
+ uint16_t *posmem = &m_sprite16_memory[0x380];
+ uint16_t *sizmem = &m_sprite16_memory[0x780];
+
+ for (int i = 0; i < 64; i++, posmem += 2, sizmem += 2)
+ {
+ int sx = (posmem[1] & 0x3ff) - 0x40 + 4;
+ int sy = 512 - (posmem[0] & 0x1ff) + 1; // sprites are buffered and delayed by one scanline
+ int sizex = (sizmem[1] & 0x3f00) >> 8;
+ int sizey = (sizmem[0] & 0x3f00) >> 8;
+ int code = sizmem[0] & 0x7f;
+ int flipx = sizmem[0] & 0x80;
+ int color = sizmem[1] & 0x3f;
+
+ /* 128V input to the palette PROM */
+ if (sy >= 128) color |= 0x40;
+
+ zoom_sprite(bitmap, (sizmem[0] & 0x8000) ? 1 : 0,
+ code,
+ color,
+ flipx,
+ sx, sy,
+ sizex,sizey);
+ }
+}
+
+
+uint32_t polepos_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ rectangle clip = cliprect;
+ clip.max_y = 127;
+ m_bg_tilemap->draw(screen, bitmap, clip, 0,0);
+ draw_road(bitmap);
+ draw_sprites(bitmap,cliprect);
+ m_tx_tilemap->draw(screen, bitmap, cliprect, 0,0);
+ return 0;
+}