diff options
Diffstat (limited to 'src/mame/video/xavix.cpp')
-rw-r--r-- | src/mame/video/xavix.cpp | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/src/mame/video/xavix.cpp b/src/mame/video/xavix.cpp new file mode 100644 index 00000000000..6c576f8eb8d --- /dev/null +++ b/src/mame/video/xavix.cpp @@ -0,0 +1,730 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#include "emu.h" +#include "includes/xavix.h" + +inline void xavix_state::set_data_address(int address, int bit) +{ + m_tmp_dataaddress = address; + m_tmp_databit = bit; +} + +inline uint8_t xavix_state::get_next_bit() +{ + uint8_t bit = m_rgn[m_tmp_dataaddress & (m_rgnlen - 1)]; + bit = bit >> m_tmp_databit; + bit &= 1; + + m_tmp_databit++; + + if (m_tmp_databit == 8) + { + m_tmp_databit = 0; + m_tmp_dataaddress++; + } + + return bit; +} + +inline uint8_t xavix_state::get_next_byte() +{ + uint8_t dat = 0; + for (int i = 0; i < 8; i++) + { + dat |= (get_next_bit() << i); + } + return dat; +} + +inline int xavix_state::get_current_address_byte() +{ + return m_tmp_dataaddress; +} + + +void xavix_state::video_start() +{ +} + + +double xavix_state::hue2rgb(double p, double q, double t) +{ + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6.0f) return p + (q - p) * 6 * t; + if (t < 1 / 2.0f) return q; + if (t < 2 / 3.0f) return p + (q - p) * (2 / 3.0f - t) * 6; + return p; +} + + +void xavix_state::handle_palette(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + // not verified + int offs = 0; + for (int index = 0; index < 256; index++) + { + uint16_t dat = m_palram1[offs]; + dat |= m_palram2[offs]<<8; + offs++; + + int l_raw = (dat & 0x1f00) >> 8; + int sl_raw =(dat & 0x00e0) >> 5; + int h_raw = (dat & 0x001f) >> 0; + + //if (h_raw > 24) + // logerror("hraw >24 (%02x)\n", h_raw); + + //if (l_raw > 17) + // logerror("lraw >17 (%02x)\n", l_raw); + + //if (sl_raw > 7) + // logerror("sl_raw >5 (%02x)\n", sl_raw); + + double l = (double)l_raw / 17.0f; + double s = (double)sl_raw / 7.0f; + double h = (double)h_raw / 24.0f; + + double r, g, b; + + if (s == 0) { + r = g = b = l; // greyscale + } + else { + double q = l < 0.5f ? l * (1 + s) : l + s - l * s; + double p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3.0f); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3.0f); + } + + int r_real = r * 255.0f; + int g_real = g * 255.0f; + int b_real = b * 255.0f; + + m_palette->set_pen_color(index, r_real, g_real, b_real); + + } +} + +void xavix_state::draw_tilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int which) +{ + int alt_tileaddressing = 0; + int alt_tileaddressing2 = 0; + + int ydimension = 0; + int xdimension = 0; + int ytilesize = 0; + int xtilesize = 0; + int offset_multiplier = 0; + int opaque = 0; + + uint8_t* tileregs; + address_space& mainspace = m_maincpu->space(AS_PROGRAM); + + if (which == 0) + { + tileregs = m_tmap1_regs; + opaque = 1; + } + else + { + tileregs = m_tmap2_regs; + opaque = 0; + } + + switch (tileregs[0x3] & 0x30) + { + case 0x00: + ydimension = 32; + xdimension = 32; + ytilesize = 8; + xtilesize = 8; + break; + + case 0x10: + ydimension = 32; + xdimension = 16; + ytilesize = 8; + xtilesize = 16; + break; + + case 0x20: // guess + ydimension = 16; + xdimension = 32; + ytilesize = 16; + xtilesize = 8; + break; + + case 0x30: + ydimension = 16; + xdimension = 16; + ytilesize = 16; + xtilesize = 16; + break; + } + + offset_multiplier = (ytilesize * xtilesize)/8; + + if (tileregs[0x7] & 0x10) + alt_tileaddressing = 1; + else + alt_tileaddressing = 0; + + if (tileregs[0x7] & 0x02) + alt_tileaddressing2 = 1; + + static int hackx = 1; + + if (machine().input().code_pressed_once(KEYCODE_Q)) + { + hackx--; + logerror("%02x\n", hackx); + } + + if (machine().input().code_pressed_once(KEYCODE_W)) + { + hackx++; + logerror("%02x\n", hackx); + } + + if (tileregs[0x7] & 0x80) + { + //logerror("draw tilemap %d, regs base0 %02x base1 %02x base2 %02x tilesize,bpp %02x scrollx %02x scrolly %02x pal %02x mode %02x\n", which, tileregs[0x0], tileregs[0x1], tileregs[0x2], tileregs[0x3], tileregs[0x4], tileregs[0x5], tileregs[0x6], tileregs[0x7]); + + // there's a tilemap register to specify base in main ram, although in the monster truck test mode it points to an unmapped region + // and expected a fixed layout, we handle that in the memory map at the moment + int count; + + count = 0;// ; + for (int y = 0; y < ydimension; y++) + { + for (int x = 0; x < xdimension; x++) + { + int bpp, pal, scrolly, scrollx; + int tile = 0; + int extraattr = 0; + + // the register being 0 probably isn't the condition here + if (tileregs[0x0] != 0x00) tile |= mainspace.read_byte((tileregs[0x0] << 8) + count); + if (tileregs[0x1] != 0x00) tile |= mainspace.read_byte((tileregs[0x1] << 8) + count) << 8; + + // at the very least boxing leaves unwanted bits set in ram after changing between mode 0x8a and 0x82, expecting them to not be used + if (tileregs[0x7] & 0x08) + extraattr = mainspace.read_byte((tileregs[0x2] << 8) + count); + + count++; + + bpp = (tileregs[0x3] & 0x0e) >> 1; + bpp++; + pal = (tileregs[0x6] & 0xf0) >> 4; + scrolly = tileregs[0x5]; + scrollx = tileregs[0x4]; + + int basereg; + int flipx = 0; + int flipy = 0; + int gfxbase; + + // tile 0 is always skipped, doesn't even point to valid data packets in alt mode + // this is consistent with the top layer too + // should we draw as solid in solid layer? + if (tile == 0) + continue; + + const int debug_packets = 0; + int test = 0; + + if (!alt_tileaddressing) + { + if (!alt_tileaddressing2) + { + basereg = 0; + gfxbase = (m_spr_attra[(basereg * 2) + 1] << 16) | (m_spr_attra[(basereg * 2)] << 8); + + tile = tile * (offset_multiplier * bpp); + tile += gfxbase; + } + else + { + tile = tile * 8; + basereg = (tile & 0x70000) >> 16; + tile &= 0xffff; + gfxbase = (m_spr_attra[(basereg * 2) + 1] << 16) | (m_spr_attra[(basereg * 2)] << 8); + tile += gfxbase; + + if (tileregs[0x7] & 0x08) + { + // make use of the extraattr stuff? + pal = (extraattr & 0xf0)>>4; + // low bits are priority? + } + } + } + else + { + if (debug_packets) logerror("for tile %04x (at %d %d): ", tile, (((x * 16) + scrollx) & 0xff), (((y * 16) + scrolly) & 0xff)); + + + basereg = (tile & 0xf000) >> 12; + tile &= 0x0fff; + gfxbase = (m_spr_attra[(basereg * 2) + 1] << 16) | (m_spr_attra[(basereg * 2)] << 8); + + tile += gfxbase; + set_data_address(tile, 0); + + // there seems to be a packet stored before the tile?! + // the offset used for flipped sprites seems to specifically be changed so that it picks up an extra byte which presumably triggers the flipping + uint8_t byte1 = 0; + int done = 0; + int skip = 0; + + do + { + byte1 = get_next_byte(); + + if (debug_packets) logerror(" %02x, ", byte1); + + if (skip == 1) + { + skip = 0; + //test = 1; + } + else if ((byte1 & 0x0f) == 0x01) + { + // used + } + else if ((byte1 & 0x0f) == 0x03) + { + // causes next byte to be skipped?? + skip = 1; + } + else if ((byte1 & 0x0f) == 0x05) + { + // the upper bits are often 0x00, 0x10, 0x20, 0x30, why? + flipx = 1; + } + else if ((byte1 & 0x0f) == 0x06) // there must be other finish conditions too because sometimes this fails.. + { + // tile data will follow after this, always? + pal = (byte1 & 0xf0) >> 4; + done = 1; + } + else if ((byte1 & 0x0f) == 0x07) + { + // causes next byte to be skipped?? + skip = 1; + } + else if ((byte1 & 0x0f) == 0x09) + { + // used + } + else if ((byte1 & 0x0f) == 0x0a) + { + // not seen + } + else if ((byte1 & 0x0f) == 0x0b) + { + // used + } + else if ((byte1 & 0x0f) == 0x0c) + { + // not seen + } + else if ((byte1 & 0x0f) == 0x0d) + { + // used + } + else if ((byte1 & 0x0f) == 0x0e) + { + // not seen + } + else if ((byte1 & 0x0f) == 0x0f) + { + // used + } + + } while (done == 0); + if (debug_packets) logerror("\n"); + tile = get_current_address_byte(); + } + + if (test == 1) pal = machine().rand() & 0xf; + + + draw_tile(screen, bitmap, cliprect, tile, bpp, (x * xtilesize) + scrollx, ((y * ytilesize) - 16) - scrolly, ytilesize, xtilesize, flipx, flipy, pal, opaque); + draw_tile(screen, bitmap, cliprect, tile, bpp, (x * xtilesize) + scrollx, (((y * ytilesize) - 16) - scrolly) + 256, ytilesize, xtilesize, flipx, flipy, pal, opaque); // wrap-y + draw_tile(screen, bitmap, cliprect, tile, bpp, ((x * xtilesize) + scrollx) - 256, ((y * ytilesize) - 16) - scrolly, ytilesize, xtilesize, flipx, flipy, pal, opaque); // wrap-x + draw_tile(screen, bitmap, cliprect, tile, bpp, ((x * xtilesize) + scrollx) - 256, (((y * ytilesize) - 16) - scrolly) + 256, ytilesize, xtilesize, flipx, flipy, pal, opaque); // wrap-y and x + } + } + } +} + +void xavix_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + //logerror("frame\n"); + // priority doesn't seem to be based on list order, there are bad sprite-sprite priorities with either forward or reverse + + for (int i = 0xff; i >= 0; i--) + { + /* attribute 0 bits + pppp bbb- p = palette, b = bpp + + attribute 1 bits + ---- ss-f s = size, f = flipx + */ + + int ypos = m_spr_ypos[i]; + int xpos = m_spr_xpos[i]; + int tile = (m_spr_addr_hi[i] << 16) | (m_spr_addr_md[i] << 8) | m_spr_addr_lo[i]; + int attr0 = m_spr_attr0[i]; + int attr1 = m_spr_attr1[i]; + + int pal = (attr0 & 0xf0) >> 4; + int flipx = (attr1 & 0x01); + + int drawheight = 16; + int drawwidth = 16; + + tile &= (m_rgnlen - 1); + + // taito nostalgia 1 also seems to use a different addressing, is it selectable or is the chip different? + // taito nost attr1 is 84 / 80 / 88 / 8c for the various elements of the xavix logo. monster truck uses ec / fc / dc / 4c / 5c / 6c (final 6 sprites ingame are 00 00 f0 f0 f0 f0, radar?) + + if ((attr1 & 0x0c) == 0x0c) + { + drawheight = 16; + drawwidth = 16; + if (m_alt_addressing == 1) + tile = tile * 128; + else if (m_alt_addressing == 2) + tile = tile * 8; + } + else if ((attr1 & 0x0c) == 0x08) + { + drawheight = 16; + drawwidth = 8; + xpos += 4; + if (m_alt_addressing == 1) + tile = tile * 64; + else if (m_alt_addressing == 2) + tile = tile * 8; + } + else if ((attr1 & 0x0c) == 0x04) + { + drawheight = 8; + drawwidth = 16; + ypos -= 4; + if (m_alt_addressing == 1) + tile = tile * 64; + else if (m_alt_addressing == 2) + tile = tile * 8; + } + else if ((attr1 & 0x0c) == 0x00) + { + drawheight = 8; + drawwidth = 8; + xpos += 4; + ypos -= 4; + if (m_alt_addressing == 1) + tile = tile * 32; + else if (m_alt_addressing == 2) + tile = tile * 8; + } + + if (m_alt_addressing != 0) + { + int basereg = (tile & 0xf0000) >> 16; + tile &= 0xffff; + int gfxbase = (m_spr_attra[(basereg * 2) + 1] << 16) | (m_spr_attra[(basereg * 2)] << 8); + tile+= gfxbase; + } + + ypos = 0x100 - ypos; + + xpos -= 136; + ypos -= 152; + + xpos &= 0xff; + ypos &= 0xff; + + if (ypos >= 192) + ypos -= 256; + + int bpp = 1; + + bpp = (attr0 & 0x0e) >> 1; + bpp += 1; + + draw_tile(screen, bitmap, cliprect, tile, bpp, xpos, ypos, drawheight, drawwidth, flipx, 0, pal, 0); + draw_tile(screen, bitmap, cliprect, tile, bpp, xpos - 256, ypos, drawheight, drawwidth, flipx, 0, pal, 0); // wrap-x + draw_tile(screen, bitmap, cliprect, tile, bpp, xpos, ypos - 256, drawheight, drawwidth, flipx, 0, pal, 0); // wrap-y + draw_tile(screen, bitmap, cliprect, tile, bpp, xpos - 256, ypos - 256, drawheight, drawwidth, flipx, 0, pal, 0); // wrap-x,y + + /* + if ((m_spr_ypos[i] != 0x81) && (m_spr_ypos[i] != 0x80) && (m_spr_ypos[i] != 0x00)) + { + logerror("sprite with enable? %02x attr0 %02x attr1 %02x attr3 %02x attr5 %02x attr6 %02x attr7 %02x\n", m_spr_ypos[i], m_spr_attr0[i], m_spr_attr1[i], m_spr_xpos[i], m_spr_addr_lo[i], m_spr_addr_md[i], m_spr_addr_hi[i] ); + } + */ + } +} + +void xavix_state::draw_tile(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int tile, int bpp, int xpos, int ypos, int drawheight, int drawwidth, int flipx, int flipy, int pal, int opaque) +{ + // set the address here so we can increment in bits in the draw function + set_data_address(tile, 0); + + for (int y = 0; y < drawheight; y++) + { + int row; + if (flipy) + { + row = ypos + (drawheight-1) - y; + } + else + { + row = ypos + y; + } + + for (int x = 0; x < drawwidth; x++) + { + + int col; + + if (flipx) + { + col = xpos + (drawwidth-1) - x; + } + else + { + col = xpos + x; + } + + uint8_t dat = 0; + + for (int i = 0; i < bpp; i++) + { + dat |= (get_next_bit() << i); + } + + if ((row >= cliprect.min_y && row <= cliprect.max_y) && (col >= cliprect.min_x && col <= cliprect.max_x)) + { + uint16_t* rowptr; + + rowptr = &bitmap.pix16(row); + + if (opaque) + { + rowptr[col] = (dat + (pal << 4)) & 0xff; + } + else + { + if (dat) + rowptr[col] = (dat + (pal << 4)) & 0xff; + } + } + } + } +} + +uint32_t xavix_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + handle_palette(screen, bitmap, cliprect); + + bitmap.fill(0, cliprect); + + draw_tilemap(screen,bitmap,cliprect,0); + draw_sprites(screen,bitmap,cliprect); + draw_tilemap(screen,bitmap,cliprect,1); + + //popmessage("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", m_75fx[0],m_75fx[1],m_75fx[2],m_75fx[3],m_75fx[4],m_75fx[5],m_75fx[6],m_75fx[7],m_75fx[8],m_75fx[9],m_75fx[10],m_75fx[11],m_75fx[12],m_75fx[13],m_75fx[14],m_75fx[15]); + + return 0; +} + + +WRITE8_MEMBER(xavix_state::vid_dma_params_1_w) +{ + m_vid_dma_param1[offset] = data; +} + +WRITE8_MEMBER(xavix_state::vid_dma_params_2_w) +{ + m_vid_dma_param2[offset] = data; +} + +WRITE8_MEMBER(xavix_state::vid_dma_trigger_w) +{ + uint16_t len = data & 0x07; + uint16_t src = (m_vid_dma_param1[1]<<8) | m_vid_dma_param1[0]; + uint16_t dst = (m_vid_dma_param2[0]<<8); + dst += 0x6000; + + uint8_t unk = m_vid_dma_param2[1]; + + logerror("%s: vid_dma_trigger_w with trg %02x size %04x src %04x dest %04x unk (%02x)\n", machine().describe_context(), data & 0xf8, len,src,dst,unk); + + if (unk) + { + fatalerror("m_vid_dma_param2[1] != 0x00 (is %02x)\n", m_vid_dma_param2[1]); + } + + if (len == 0x00) + { + len = 0x08; + logerror(" (length was 0x0, assuming 0x8)\n"); + } + + len = len << 8; + + address_space& dmaspace = m_maincpu->space(AS_PROGRAM); + + if (data & 0x40) + { + for (int i = 0; i < len; i++) + { + uint8_t dat = dmaspace.read_byte(src + i); + dmaspace.write_byte(dst + i, dat); + } + } +} + +READ8_MEMBER(xavix_state::vid_dma_trigger_r) +{ + // expects bit 0x40 to clear in most cases + return 0x00; +} + +READ8_MEMBER(xavix_state::pal_ntsc_r) +{ + // only seen 0x10 checked in code + // in monster truck the tile base address gets set based on this, there are 2 copies of the test screen in rom, one for pal, one for ntsc, see 1854c + // likewise card night has entirely different tilesets for each region title + return m_region->read(); +} + +WRITE8_MEMBER(xavix_state::xavix_6fc0_w) // also related to tilemap 1? +{ + logerror("%s: xavix_6fc0_w data %02x\n", machine().describe_context(), data); +} + +WRITE8_MEMBER(xavix_state::tmap1_regs_w) +{ + /* + 0x0 pointer to address where tile data is + it gets set to 0x40 in monster truck test mode, which is outside of ram but test mode requires a fixed 'column scan' layout + so that might be special + + 0x1 pointer to middle tile bits (if needed, depends on mode) (usually straight after the ram needed for above) + + 0x2 pointer to tile highest tile bits (if needed, depends on mode) (usually straight after the ram needed for above) + + 0x3 --tt bbb- - = ? tt = tile/tilemap size b = bpp (0x36 xavix logo, 0x3c title screen, 0x36 course select) + + 0x4 and 0x5 are scroll + + 0x6 pppp ---- p = palette - = ? (0x02 xavix logo, 0x01 course select) + + 0x7 could be mode (16x16, 8x8 etc.) + 0x00 is disabled? + 0x80 means 16x16 tiles + 0x81 might be 8x8 tiles + 0x93 course / mode select bg / ingame (weird addressing?) + + + */ + + /* + 6aff base registers + -- ingame + + ae 80 + 02 80 + 02 90 + 02 a0 + 02 b0 + 02 c0 + 02 d0 + 02 e0 + + 02 00 + 04 80 + 04 90 + 04 a0 + 04 b0 + 04 c0 + 04 d0 + 04 e0 + + -- menu + af 80 + 27 80 + 27 90 + 27 a0 + 27 b0 + 27 c0 + 27 d0 + 27 e0 + + 27 00 + 00 80 + 00 90 + 00 a0 + 00 b0 + 00 c0 + 00 d0 + 00 e0 + */ + + + if ((offset != 0x4) && (offset != 0x5)) + { + logerror("%s: tmap1_regs_w offset %02x data %02x\n", machine().describe_context(), offset, data); + } + + COMBINE_DATA(&m_tmap1_regs[offset]); +} + +WRITE8_MEMBER(xavix_state::xavix_6fd8_w) // also related to tilemap 2? +{ + // possibly just a mirror of tmap2_regs_w, at least it writes 0x04 here which would be the correct + // base address to otherwise write at tmap2_regs_w offset 0 +// tmap2_regs_w(space,offset,data); + + logerror("%s: xavix_6fd8_w data %02x\n", machine().describe_context(), data); +} + +WRITE8_MEMBER(xavix_state::tmap2_regs_w) +{ + // same as above but for 2nd tilemap + if ((offset != 0x4) && (offset != 0x5)) + { + //logerror("%s: tmap2_regs_w offset %02x data %02x\n", machine().describe_context(), offset, data); + } + + COMBINE_DATA(&m_tmap2_regs[offset]); +} + +READ8_MEMBER(xavix_state::tmap2_regs_r) +{ + // does this return the same data or a status? + + logerror("%s: tmap2_regs_r offset %02x\n", offset, machine().describe_context()); + return m_tmap2_regs[offset]; +} + +READ8_MEMBER(xavix_state::xavix_4000_r) +{ + if (offset < 0x100) + { + return ((offset>>4) | (offset<<4)); + } + else + { + return 0x00; + } +} + |