From 5dc487c34d79bb1e18929d79b2ee774b9d6ea2e5 Mon Sep 17 00:00:00 2001 From: David Haywood <28625134+DavidHaywood@users.noreply.github.com> Date: Tue, 5 Nov 2019 02:34:40 +0000 Subject: Plug & Play improvements (Elan / Air Blaster Joystick) (#5856) * elan video code improvements (nw) * fix x scroll on some air blaster bosses (non-split mode scrolling) --- src/mame/drivers/elan_eu3a05.cpp | 31 +++---- src/mame/video/elan_eu3a05vid.cpp | 174 ++++++++++++++++---------------------- src/mame/video/elan_eu3a05vid.h | 10 +-- 3 files changed, 92 insertions(+), 123 deletions(-) diff --git a/src/mame/drivers/elan_eu3a05.cpp b/src/mame/drivers/elan_eu3a05.cpp index 0d1c8a10154..903918779ff 100644 --- a/src/mame/drivers/elan_eu3a05.cpp +++ b/src/mame/drivers/elan_eu3a05.cpp @@ -242,13 +242,8 @@ void elan_eu3a05_state::elan_eu3a05_map(address_map &map) map(0x502a, 0x502a).rw(m_vid, FUNC(elan_eu3a05vid_device::tile_gfxbase_hi_r), FUNC(elan_eu3a05vid_device::tile_gfxbase_hi_w)); // tilebase map(0x502b, 0x502b).rw(m_vid, FUNC(elan_eu3a05vid_device::sprite_gfxbase_lo_r), FUNC(elan_eu3a05vid_device::sprite_gfxbase_lo_w)); // tilebase (spr?) map(0x502c, 0x502c).rw(m_vid, FUNC(elan_eu3a05vid_device::sprite_gfxbase_hi_r), FUNC(elan_eu3a05vid_device::sprite_gfxbase_hi_w)); // tilebase (spr?) - map(0x502d, 0x502d).ram(); - map(0x502e, 0x502e).rw(m_vid, FUNC(elan_eu3a05vid_device::splitpos_r), FUNC(elan_eu3a05vid_device::splitpos_w)); // split position - map(0x502f, 0x502f).ram(); - - map(0x5030, 0x5030).ram(); - map(0x5031, 0x5032).rw(m_vid, FUNC(elan_eu3a05vid_device::tile_scroll_r), FUNC(elan_eu3a05vid_device::tile_scroll_w)); - map(0x5033, 0x5036).rw(m_vid, FUNC(elan_eu3a05vid_device::tile_xscroll_r), FUNC(elan_eu3a05vid_device::tile_xscroll_w)); // there are 2 scroll values in here, air blaster 3d stages uses split scrolling like huntin'3 on eu3a14 + map(0x502d, 0x502e).rw(m_vid, FUNC(elan_eu3a05vid_device::splitpos_r), FUNC(elan_eu3a05vid_device::splitpos_w)); // split position + map(0x502f, 0x5036).rw(m_vid, FUNC(elan_eu3a05vid_device::tile_scroll_r), FUNC(elan_eu3a05vid_device::tile_scroll_w)); // there are 4 scroll values in here, x scroll, y scroll, xscroll1 for split, xscroll2 for split (eu3a14 can do split too) // 5037 map(0x5038, 0x5038).ram(); @@ -444,20 +439,26 @@ INTERRUPT_GEN_MEMBER(elan_eu3a05_state::interrupt) } -// Tetris (PAL version) has XTAL of 21.281370 -// Air Blaster (PAL version) has XTAL of 21.2813 -// what are the NTSC clocks? +/* Tetris (PAL version) has XTAL of 21.281370 + Air Blaster (PAL version) has XTAL of 21.2813 + what are the NTSC clocks? -// not confirmed on Space Invaders, actual CPU clock unknown. -// 21281370 is the same value as a PAL SNES -// game speed in Air Blaster appears to be limited entirely by CPU speed (and therefore needs to be around 2mhz at most to match hardware) -// low clock speed also helps with the badly programmed controls in Tetris + not confirmed on Space Invaders, actual CPU clock unknown. + 21281370 is the same value as a PAL SNES + game logic speed (but not level scroll speed) in Air Blaster appears to be limited entirely by CPU speed (and therefore needs to be around 2-3mhz + at most to match hardware) - a divider of 8 gives something close to original hardware + it is unclear exactly what limits the clock speed (maybe video / sound causes waitstates? - dma in progress could also slow / stop the CPU + and is not going to be 'instant' on hardware) + + using a low clock speed also helps with the badly programmed controls in Tetris as that likewise seems to run the game logic 'as fast as possible' + there don't appear to be any kind of blanking bits being checked. +*/ void elan_eu3a05_state::elan_eu3a05(machine_config &config) { /* basic machine hardware */ - M6502(config, m_maincpu, XTAL(21'281'370)/12); // wrong, this is the PAL clock + M6502(config, m_maincpu, XTAL(21'281'370)/8); // wrong, this is the PAL clock m_maincpu->set_addrmap(AS_PROGRAM, &elan_eu3a05_state::elan_eu3a05_map); m_maincpu->set_vblank_int("screen", FUNC(elan_eu3a05_state::interrupt)); diff --git a/src/mame/video/elan_eu3a05vid.cpp b/src/mame/video/elan_eu3a05vid.cpp index d21d324ebb9..ec472fb1fe5 100644 --- a/src/mame/video/elan_eu3a05vid.cpp +++ b/src/mame/video/elan_eu3a05vid.cpp @@ -35,19 +35,17 @@ void elan_eu3a05vid_device::device_reset() m_vidctrl = 0x00; // need to default to an 8x8 mode for Space Invaders test mode at least - for (int i=0;i<2;i++) + for (int i=0;i<4*2;i++) m_tile_scroll[i] = 0x00; - for (int i=0;i<2;i++) - m_tile_xscroll[i] = 0x00; - m_tile_gfxbase_lo_data = 0x00; m_tile_gfxbase_hi_data = 0x00; m_sprite_gfxbase_lo_data = 0x00; m_sprite_gfxbase_hi_data = 0x00; - m_splitpos = 0x00; + for (int i=0;i<2;i++) + m_splitpos[i] = 0x00; } uint8_t elan_eu3a05vid_device::read_spriteram(int offset) @@ -258,11 +256,11 @@ bool elan_eu3a05vid_device::get_tile_data(int base, int drawpri, int& tile, int } void elan_eu3a05vid_device::draw_tilemaps(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect, int drawpri) { - /* + /* this doesn't handle 8x8 4bpp (not used by anything yet) */ - int scroll = (m_tile_scroll[1] << 8) | m_tile_scroll[0]; + int scroll = get_scroll(1); address_space& fullbankspace = m_bank->space(AS_PROGRAM); // Phoenix scrolling actually skips a pixel, jumping from 0x001 to 0x1bf, scroll 0x000 isn't used, maybe it has other meanings? @@ -331,10 +329,20 @@ void elan_eu3a05vid_device::draw_tilemaps(screen_device& screen, bitmap_ind16& b int scrollx; // split can be probably configured in more ways than this - if (drawline > m_splitpos) - scrollx = get_xscroll(1); + // exact enable conditions unclear + int splitpos = (m_splitpos[0] << 8) | m_splitpos[1]; + + if (splitpos != 0xffff) + { + if (drawline > splitpos) + scrollx = get_scroll(3); + else + scrollx = get_scroll(2); + } else - scrollx = get_xscroll(0); + { + scrollx = get_scroll(0); + } int base; @@ -362,92 +370,64 @@ void elan_eu3a05vid_device::draw_tilemaps(screen_device& screen, bitmap_ind16& b int colour = attr & 0xf0; - if (m_vidctrl & 0x40) // 16x16 tiles - { - if (m_vidctrl & 0x20) // 4bpp mode - { - tile = (tile & 0xf) + ((tile & ~0xf) * 16); - tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5); - } - else - { - tile = (tile & 0xf) + ((tile & ~0xf) * 16); - tile <<= 1; + /* 'tiles' are organized / extracted from 'texture' lines that form a 'page' the length of the rom + each texture line in 8bpp mode is 256 bytes + each texture line in 4bpp mode is 128 bytes + in 8x8 mode these pages are 32 tiles wide + in 16x16 mode these pages are 16 tiles wide + tiles can start on any line - tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5); - } - } - else - { - if (m_vidctrl & 0x20) // 4bpp - { - // TODO - tile = 0x0000;//machine().rand() & 0x1ff; - } - else - { - tile = (tile & 0x1f) + ((tile & ~0x1f) * 8); - tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5); - } - } + it is unclear what the behavior is if the tile starts at the far edge of a line (wrap around on line?) + + this is eu3a05 specific, eu3a14 uses a more traditional approach + */ + + const int tilespersrcline = 256 / tilexsize; + const int tilespersrcline_mask = tilespersrcline - 1; + + tile = (tile & tilespersrcline_mask) + ((tile & ~tilespersrcline_mask) * tilexsize); + + if (!(m_vidctrl & 0x20)) // 8bpp + tile <<= 1; + + if (!(m_vidctrl & 0x40)) // 8*8 tiles + tile >>= 1; + + tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5); uint16_t* row = &bitmap.pix16(drawline); - if (m_vidctrl & 0x40) // 16x16 tiles + if (m_vidctrl & 0x20) // 4bpp { - if (m_vidctrl & 0x20) // 4bpp - { - for (int xx = 0; xx < tilexsize; xx += 2) - { - int realaddr = ((tile + i * 16) << 3) + (xx >> 1); - uint8_t pix = fullbankspace.read_byte(realaddr); - - int drawxpos; - - drawxpos = x * 16 + xx + 0; - drawxpos &= 0x1ff; - if ((drawxpos >= 0) && (drawxpos < 256)) - row[drawxpos] = ((pix & 0xf0) >> 4) + colour; - - drawxpos = x * 16 + xx + 1; - drawxpos &= 0x1ff; - if ((drawxpos >= 0) && (drawxpos < 256)) - row[drawxpos] = ((pix & 0x0f) >> 0) + colour; - } - } - else // 8bpp + for (int xx = 0; xx < tilexsize; xx += 2) { - for (int xx = 0; xx < tilexsize; xx++) - { - int realaddr = ((tile + i * 32) << 3) + xx; - uint8_t pix = fullbankspace.read_byte(realaddr); - - int drawxpos = x * 16 + xx; - drawxpos &= 0x1ff; - if ((drawxpos >= 0) && (drawxpos < 256)) - row[drawxpos] = (pix + ((colour & 0x70) << 1)) & 0xff; - } + int realaddr = ((tile + i * 16) << 3) + (xx >> 1); + uint8_t pix = fullbankspace.read_byte(realaddr); + + int drawxpos; + + drawxpos = x * tilexsize + xx + 0 - scrollx; + drawxpos &= 0x1ff; + if ((drawxpos >= 0) && (drawxpos < 256)) + row[drawxpos] = ((pix & 0xf0) >> 4) + colour; + + drawxpos = x * tilexsize + xx + 1 - scrollx; + drawxpos &= 0x1ff; + if ((drawxpos >= 0) && (drawxpos < 256)) + row[drawxpos] = ((pix & 0x0f) >> 0) + colour; } } - else // 8x8 tiles + else // 8bpp { - if (m_vidctrl & 0x20) // 4bpp - { - // TODO - } - else + for (int xx = 0; xx < tilexsize; xx++) { - for (int xx = 0; xx < tilexsize; xx++) - { - const int realaddr = ((tile + i * 32) << 3) + xx; - const uint8_t pix = fullbankspace.read_byte(realaddr); - - int drawxpos = x * tilexsize + xx - scrollx; - drawxpos &= 0x1ff; + int realaddr = ((tile + i * 32) << 3) + xx; + uint8_t pix = fullbankspace.read_byte(realaddr); - if ((drawxpos >= 0) && (drawxpos < 256)) - row[drawxpos] = (pix + ((colour & 0x70) << 1)) & 0xff; - } + int drawxpos = x * tilexsize + xx - scrollx; + drawxpos &= 0x1ff; + if ((drawxpos >= 0) && (drawxpos < 256)) + row[drawxpos] = (pix + ((colour & 0x70) << 1)) & 0xff; } } } @@ -533,34 +513,26 @@ WRITE8_MEMBER(elan_eu3a05vid_device::tile_scroll_w) m_tile_scroll[offset] = data; } -READ8_MEMBER(elan_eu3a05vid_device::tile_xscroll_r) -{ - return m_tile_xscroll[offset]; -} - -WRITE8_MEMBER(elan_eu3a05vid_device::tile_xscroll_w) -{ - m_tile_xscroll[offset] = data; -} - READ8_MEMBER(elan_eu3a05vid_device::splitpos_r) { - return m_splitpos; + return m_splitpos[offset]; } WRITE8_MEMBER(elan_eu3a05vid_device::splitpos_w) { - m_splitpos = data; + m_splitpos[offset] = data; } -uint16_t elan_eu3a05vid_device::get_xscroll(int which) +uint16_t elan_eu3a05vid_device::get_scroll(int which) { switch (which) { - case 0x0: return (m_tile_xscroll[1] << 8) | (m_tile_xscroll[0]); - case 0x1: return (m_tile_xscroll[3] << 8) | (m_tile_xscroll[2]); + case 0x0: return (m_tile_scroll[1] << 8) | (m_tile_scroll[0]); // xscroll + case 0x1: return (m_tile_scroll[3] << 8) | (m_tile_scroll[2]); // yscroll + case 0x2: return (m_tile_scroll[5] << 8) | (m_tile_scroll[4]); // xsplit 1 scroll + case 0x3: return (m_tile_scroll[7] << 8) | (m_tile_scroll[6]); // scplit 2 scroll } - + return 0x0000; } diff --git a/src/mame/video/elan_eu3a05vid.h b/src/mame/video/elan_eu3a05vid.h index 4f4f52ad2f9..1580fa10840 100644 --- a/src/mame/video/elan_eu3a05vid.h +++ b/src/mame/video/elan_eu3a05vid.h @@ -34,13 +34,10 @@ public: DECLARE_READ8_MEMBER(tile_scroll_r); DECLARE_WRITE8_MEMBER(tile_scroll_w); - DECLARE_READ8_MEMBER(tile_xscroll_r); - DECLARE_WRITE8_MEMBER(tile_xscroll_w); - DECLARE_READ8_MEMBER(splitpos_r); DECLARE_WRITE8_MEMBER(splitpos_w); - uint16_t get_xscroll(int which); + uint16_t get_scroll(int which); uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); @@ -61,10 +58,9 @@ private: uint8_t m_sprite_gfxbase_lo_data; uint8_t m_sprite_gfxbase_hi_data; - uint8_t m_tile_scroll[2]; - uint8_t m_tile_xscroll[4]; + uint8_t m_tile_scroll[4*2]; - uint8_t m_splitpos; + uint8_t m_splitpos[2]; bool get_tile_data(int base, int drawpri, int& tile, int &attr, int &unk2); void draw_tilemaps(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int drawpri); -- cgit v1.2.3