jaleco/aeroboto.cpp, jaleco/exerion.cpp, jaleco/ginganin.cpp, jaleco/homerun.cpp, jaleco/momoko.cpp, jaleco/skyfox.cpp, omori/popper.cpp: consolidated drivers in single files, minor cleanups

This commit is contained in:
Ivan Vangelista 2022-09-06 07:16:15 +02:00
parent 753b54667f
commit fa33564c68
25 changed files with 2953 additions and 3028 deletions

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders: Carlos A. Lozano, Uki
/****************************************************************************
Formation Z / Aeroboto
@ -26,23 +27,321 @@ Revisions:
****************************************************************************/
#include "emu.h"
#include "aeroboto.h"
#include "cpu/m6809/m6809.h"
#include "machine/gen_latch.h"
#include "sound/ay8910.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "tilemap.h"
uint8_t aeroboto_state::aeroboto_201_r()
// configurable logging
#define LOG_3004 (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_3004)
#include "logmacro.h"
#define LOG3004(...) LOGMASKED(LOG_3004, __VA_ARGS__)
namespace {
class aeroboto_state : public driver_device
{
/* if you keep a button pressed during boot, the game will expect this */
/* serie of values to be returned from 3004, and display "PASS 201" if it is */
public:
aeroboto_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_mainram(*this, "mainram"),
m_videoram(*this, "videoram"),
m_hscroll(*this, "hscroll"),
m_tilecolor(*this, "tilecolor"),
m_spriteram(*this, "spriteram"),
m_vscroll(*this, "vscroll"),
m_starx(*this, "starx"),
m_stary(*this, "stary"),
m_bgcolor(*this, "bgcolor"),
m_stars_rom(*this, "starfield_data"),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
m_p(*this, "P%u", 1U)
{ }
void formatz(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
private:
// memory pointers
required_shared_ptr<uint8_t> m_mainram;
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_hscroll;
required_shared_ptr<uint8_t> m_tilecolor;
required_shared_ptr<uint8_t> m_spriteram;
required_shared_ptr<uint8_t> m_vscroll;
required_shared_ptr<uint8_t> m_starx;
required_shared_ptr<uint8_t> m_stary;
required_shared_ptr<uint8_t> m_bgcolor;
// stars layout
required_region_ptr<uint8_t> m_stars_rom;
// devices
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_audiocpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
// I/O
required_ioport_array<2> m_p;
// video-related
tilemap_t *m_bg_tilemap = nullptr;
uint8_t m_charbank = 0U;
uint8_t m_starsoff = 0U;
uint8_t m_sx = 0U;
uint8_t m_sy = 0U;
uint8_t m_ox = 0U;
uint8_t m_oy = 0U;
// misc
uint32_t m_count = 0U;
uint8_t m_disable_irq = 0U;
uint8_t _201_r();
uint8_t irq_ack_r();
uint8_t _2973_r();
void _1a2_w(uint8_t data);
uint8_t in0_r();
void _3000_w(uint8_t data);
void videoram_w(offs_t offset, uint8_t data);
void tilecolor_w(offs_t offset, uint8_t data);
TILE_GET_INFO_MEMBER(get_tile_info);
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(vblank_irq);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
void main_map(address_map &map);
void sound_map(address_map &map);
};
// video
// how the starfield ROM is interpreted: 0 = 256 x 256 x 1 linear bitmap, 1 = 8 x 8 x 1 x 1024 tilemap
static constexpr uint8_t STARS_LAYOUT = 1;
// scroll speed of the stars: 1 = normal, 2 = half, 3 = one-third...etc. (positive integers only)
static constexpr uint8_t SCROLL_SPEED = 1;
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
TILE_GET_INFO_MEMBER(aeroboto_state::get_tile_info)
{
uint8_t const code = m_videoram[tile_index];
tileinfo.set(0,
code + (m_charbank << 8),
m_tilecolor[code],
(m_tilecolor[code] >= 0x33) ? 0 : TILE_FORCE_LAYER0);
}
// transparency should only affect tiles with color 0x33 or higher
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
void aeroboto_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(aeroboto_state::get_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 64);
m_bg_tilemap->set_transparent_pen(0);
m_bg_tilemap->set_scroll_rows(64);
save_item(NAME(m_charbank));
save_item(NAME(m_starsoff));
save_item(NAME(m_sx));
save_item(NAME(m_sy));
save_item(NAME(m_ox));
save_item(NAME(m_oy));
if (STARS_LAYOUT)
{
int len = m_stars_rom.bytes();
std::vector<uint8_t> temp(len);
memcpy(&temp[0], &m_stars_rom[0], len);
for (int i = 0; i < len; i++)
m_stars_rom[(i & ~0xff) + (i << 5 & 0xe0) + (i >> 3 & 0x1f)] = temp[i];
}
}
/***************************************************************************
Memory handlers
***************************************************************************/
uint8_t aeroboto_state::in0_r()
{
return flip_screen() ? m_p[1]->read() : m_p[0]->read();
}
void aeroboto_state::_3000_w(uint8_t data)
{
// bit 0 selects both flip screen and player1 / player2 controls
flip_screen_set(data & 0x01);
// bit 1 = char bank select
if (m_charbank != ((data & 0x02) >> 1))
{
m_bg_tilemap->mark_all_dirty();
m_charbank = (data & 0x02) >> 1;
}
// bit 2 = disable star field?
m_starsoff = data & 0x04;
}
void aeroboto_state::videoram_w(offs_t offset, uint8_t data)
{
m_videoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
void aeroboto_state::tilecolor_w(offs_t offset, uint8_t data)
{
if (m_tilecolor[offset] != data)
{
m_tilecolor[offset] = data;
m_bg_tilemap->mark_all_dirty();
}
}
/***************************************************************************
Display refresh
***************************************************************************/
void aeroboto_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
for (int offs = 0; offs < m_spriteram.bytes(); offs += 4)
{
int x = m_spriteram[offs + 3];
int y = 240 - m_spriteram[offs];
if (flip_screen())
{
x = 248 - x;
y = 240 - y;
}
m_gfxdecode->gfx(1)->transpen(bitmap, cliprect,
m_spriteram[offs + 1],
m_spriteram[offs + 2] & 0x07,
flip_screen(), flip_screen(),
((x + 8) & 0xff) - 8, y, 0);
}
}
uint32_t aeroboto_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
rectangle const splitrect1(0, 255, 0, 39);
rectangle const splitrect2(0, 255, 40, 255);
int star_color = *m_bgcolor << 2;
int sky_color = *m_bgcolor << 2;
// the star field is supposed to be seen through tile pen 0 when active
if (!m_starsoff)
{
if (star_color < 0xd0)
{
star_color = 0xd0;
sky_color = 0;
}
star_color += 2;
bitmap.fill(sky_color, cliprect);
// actual scroll speed is unknown but it can be adjusted by changing the SCROLL_SPEED constant
m_sx += char(*m_starx - m_ox);
m_ox = *m_starx;
int const x = m_sx / SCROLL_SPEED;
if (*m_vscroll != 0xff)
m_sy += char(*m_stary - m_oy);
m_oy = *m_stary;
int const y = m_sy / SCROLL_SPEED;
for (int i = 0; i < 256; i++)
{
int src_offsx = (x + i) & 0xff;
int const src_colmask = 1 << (src_offsx & 7);
src_offsx >>= 3;
uint8_t const *const src_colptr = &m_stars_rom[src_offsx];
int const pen = star_color + ((i + 8) >> 4 & 1);
for (int j = 0; j < 256; j++)
{
uint8_t const *const src_rowptr = src_colptr + (((y + j) & 0xff) << 5 );
if (!((unsigned)*src_rowptr & src_colmask))
bitmap.pix(j, i) = pen;
}
}
}
else
{
m_sx = m_ox = *m_starx;
m_sy = m_oy = *m_stary;
bitmap.fill(sky_color, cliprect);
}
for (int y = 0; y < 64; y++)
m_bg_tilemap->set_scrollx(y, m_hscroll[y]);
// the playfield is part of a splitscreen and should not overlap with status display
m_bg_tilemap->set_scrolly(0, *m_vscroll);
m_bg_tilemap->draw(screen, bitmap, splitrect2, 0, 0);
draw_sprites(bitmap, cliprect);
// the status display behaves more closely to a 40-line splitscreen than an overlay
m_bg_tilemap->set_scrolly(0, 0);
m_bg_tilemap->draw(screen, bitmap, splitrect1, 0, 0);
return 0;
}
// machine
uint8_t aeroboto_state::_201_r()
{
/* if you keep a button pressed during boot, the game will expect this
series of values to be returned from 3004, and display "PASS 201" if it is */
static const uint8_t res[4] = { 0xff, 0x9f, 0x1b, 0x03 };
logerror("PC %04x: read 3004\n", m_maincpu->pc());
LOG3004("PC %04x: read 3004\n", m_maincpu->pc());
return res[(m_count++) & 3];
}
@ -60,19 +359,19 @@ WRITE_LINE_MEMBER(aeroboto_state::vblank_irq)
}
}
uint8_t aeroboto_state::aeroboto_irq_ack_r()
uint8_t aeroboto_state::irq_ack_r()
{
m_maincpu->set_input_line(0, CLEAR_LINE);
return 0xff;
}
uint8_t aeroboto_state::aeroboto_2973_r()
uint8_t aeroboto_state::_2973_r()
{
m_mainram[0x02be] = 0;
return 0xff;
}
void aeroboto_state::aeroboto_1a2_w(uint8_t data)
void aeroboto_state::_1a2_w(uint8_t data)
{
m_mainram[0x01a2] = data;
if (data)
@ -81,26 +380,26 @@ void aeroboto_state::aeroboto_1a2_w(uint8_t data)
void aeroboto_state::main_map(address_map &map)
{
map(0x0000, 0x07ff).ram().share("mainram"); // main RAM
map(0x01a2, 0x01a2).w(FUNC(aeroboto_state::aeroboto_1a2_w)); // affects IRQ line (more protection?)
map(0x0000, 0x07ff).ram().share(m_mainram);
map(0x01a2, 0x01a2).w(FUNC(aeroboto_state::_1a2_w)); // affects IRQ line (more protection?)
map(0x0800, 0x08ff).ram(); // tile color buffer; copied to 0x2000
map(0x0900, 0x09ff).writeonly().share("colors2"); // a backup of default tile colors
map(0x1000, 0x17ff).ram().w(FUNC(aeroboto_state::aeroboto_videoram_w)).share("videoram"); // tile RAM
map(0x1800, 0x183f).ram().share("hscroll"); // horizontal scroll regs
map(0x1000, 0x17ff).ram().w(FUNC(aeroboto_state::videoram_w)).share(m_videoram);
map(0x1800, 0x183f).ram().share(m_hscroll);
map(0x1840, 0x27ff).nopw(); // cleared during custom LSI test
map(0x2000, 0x20ff).ram().w(FUNC(aeroboto_state::aeroboto_tilecolor_w)).share("tilecolor"); // tile color RAM
map(0x2800, 0x28ff).ram().share("spriteram"); // sprite RAM
map(0x2000, 0x20ff).ram().w(FUNC(aeroboto_state::tilecolor_w)).share(m_tilecolor);
map(0x2800, 0x28ff).ram().share(m_spriteram);
map(0x2900, 0x2fff).nopw(); // cleared along with sprite RAM
map(0x2973, 0x2973).r(FUNC(aeroboto_state::aeroboto_2973_r)); // protection read
map(0x3000, 0x3000).rw(FUNC(aeroboto_state::aeroboto_in0_r), FUNC(aeroboto_state::aeroboto_3000_w));
map(0x2973, 0x2973).r(FUNC(aeroboto_state::_2973_r)); // protection read
map(0x3000, 0x3000).rw(FUNC(aeroboto_state::in0_r), FUNC(aeroboto_state::_3000_w));
map(0x3001, 0x3001).portr("DSW1").w("soundlatch", FUNC(generic_latch_8_device::write));
map(0x3002, 0x3002).portr("DSW2").w("soundlatch2", FUNC(generic_latch_8_device::write));
map(0x3003, 0x3003).writeonly().share("vscroll");
map(0x3004, 0x3004).r(FUNC(aeroboto_state::aeroboto_201_r)).writeonly().share("starx");
map(0x3005, 0x3005).writeonly().share("stary"); // usable but probably wrong
map(0x3006, 0x3006).writeonly().share("bgcolor");
map(0x3800, 0x3800).r(FUNC(aeroboto_state::aeroboto_irq_ack_r)); // watchdog or IRQ ack
map(0x4000, 0xffff).rom(); // main ROM
map(0x3003, 0x3003).writeonly().share(m_vscroll);
map(0x3004, 0x3004).r(FUNC(aeroboto_state::_201_r)).writeonly().share(m_starx);
map(0x3005, 0x3005).writeonly().share(m_stary); // usable but probably wrong
map(0x3006, 0x3006).writeonly().share(m_bgcolor);
map(0x3800, 0x3800).r(FUNC(aeroboto_state::irq_ack_r)); // watchdog or IRQ ack
map(0x4000, 0xffff).rom();
}
void aeroboto_state::sound_map(address_map &map)
@ -147,7 +446,7 @@ static INPUT_PORTS_START( formatz )
PORT_DIPSETTING( 0x08, "40000" )
PORT_DIPSETTING( 0x04, "70000" )
PORT_DIPSETTING( 0x00, "100000" )
PORT_DIPUNUSED_DIPLOC( 0x10, 0x00, "SW1:5" ) /* Listed as "Unused" */
PORT_DIPUNUSED_DIPLOC( 0x10, 0x00, "SW1:5" ) // Listed as "Unused"
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION("SW1:6")
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x20, DEF_STR( On ) )
@ -174,9 +473,9 @@ static INPUT_PORTS_START( formatz )
PORT_DIPSETTING( 0x08, DEF_STR( Normal ) )
PORT_DIPSETTING( 0x10, DEF_STR( Medium ) )
PORT_DIPSETTING( 0x18, DEF_STR( Hard ) )
PORT_DIPUNUSED_DIPLOC( 0x20, 0x00, "SW2:6" ) /* Listed as "Unused" */
PORT_DIPUNUSED_DIPLOC( 0x40, 0x00, "SW2:7" ) /* Listed as "Unused" */
PORT_DIPUNUSED_DIPLOC( 0x80, 0x00, "SW2:8" ) /* Listed as "Unused" */
PORT_DIPUNUSED_DIPLOC( 0x20, 0x00, "SW2:6" ) // Listed as "Unused"
PORT_DIPUNUSED_DIPLOC( 0x40, 0x00, "SW2:7" ) // Listed as "Unused"
PORT_DIPUNUSED_DIPLOC( 0x80, 0x00, "SW2:8" ) // Listed as "Unused"
INPUT_PORTS_END
@ -217,16 +516,13 @@ static const gfx_layout spritelayout =
};
static GFXDECODE_START( gfx_aeroboto )
GFXDECODE_ENTRY( "gfx1", 0, charlayout, 0, 64 ) /* chars */
// GFXDECODE_ENTRY( "gfx2", 0, starlayout, 0, 128 ) /* sky */
GFXDECODE_ENTRY( "gfx3", 0, spritelayout, 0, 8 )
GFXDECODE_ENTRY( "tiles", 0, charlayout, 0, 64 )
// GFXDECODE_ENTRY( "starfield_data", 0, starlayout, 0, 128 )
GFXDECODE_ENTRY( "sprites", 0, spritelayout, 0, 8 )
GFXDECODE_END
void aeroboto_state::machine_start()
{
m_stars_rom = memregion("gfx2")->base();
m_stars_length = memregion("gfx2")->bytes();
save_item(NAME(m_disable_irq));
save_item(NAME(m_count));
}
@ -246,20 +542,20 @@ void aeroboto_state::machine_reset()
void aeroboto_state::formatz(machine_config &config)
{
/* basic machine hardware */
MC6809(config, m_maincpu, XTAL(10'000'000)/2); /* verified on pcb */
// basic machine hardware
MC6809(config, m_maincpu, XTAL(10'000'000) / 2); // verified on PCB
m_maincpu->set_addrmap(AS_PROGRAM, &aeroboto_state::main_map);
MC6809(config, m_audiocpu, XTAL(10'000'000)/4); /* verified on pcb */
MC6809(config, m_audiocpu, XTAL(10'000'000) / 4); // verified on PCB
m_audiocpu->set_addrmap(AS_PROGRAM, &aeroboto_state::sound_map);
/* video hardware */
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_size(32*8, 32*8);
screen.set_visarea(0*8, 31*8-1, 2*8, 30*8-1);
screen.set_screen_update(FUNC(aeroboto_state::screen_update_aeroboto));
screen.set_screen_update(FUNC(aeroboto_state::screen_update));
screen.set_palette(m_palette);
screen.screen_vblank().set(FUNC(aeroboto_state::vblank_irq));
@ -267,18 +563,18 @@ void aeroboto_state::formatz(machine_config &config)
PALETTE(config, m_palette, palette_device::RGB_444_PROMS, "proms", 256);
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
GENERIC_LATCH_8(config, "soundlatch");
GENERIC_LATCH_8(config, "soundlatch2");
ay8910_device &ay1(AY8910(config, "ay1", XTAL(10'000'000)/8)); /* verified on pcb */
ay8910_device &ay1(AY8910(config, "ay1", XTAL(10'000'000) / 8)); // verified on PCB
ay1.port_a_read_callback().set("soundlatch", FUNC(generic_latch_8_device::read));
ay1.port_b_read_callback().set("soundlatch2", FUNC(generic_latch_8_device::read));
ay1.add_route(ALL_OUTPUTS, "mono", 0.25);
AY8910(config, "ay2", XTAL(10'000'000)/16).add_route(ALL_OUTPUTS, "mono", 0.25); /* verified on pcb */
AY8910(config, "ay2", XTAL(10'000'000) / 16).add_route(ALL_OUTPUTS, "mono", 0.25); // verified on PCB
}
@ -298,16 +594,16 @@ ROM_START( formatz )
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "format_z.9", 0xf000, 0x1000, CRC(6b9215ad) SHA1(3ab416d070bf6b9a8be3e19d4dbc3a399d9ab5cb) )
ROM_REGION( 0x2000, "gfx1", 0 )
ROM_LOAD( "format_z.5", 0x0000, 0x2000, CRC(ba50be57) SHA1(aa37b644e8c1944b4c0ba81164d5a52be8ab491f) ) /* characters */
ROM_REGION( 0x2000, "tiles", 0 )
ROM_LOAD( "format_z.5", 0x0000, 0x2000, CRC(ba50be57) SHA1(aa37b644e8c1944b4c0ba81164d5a52be8ab491f) )
ROM_REGION( 0x2000, "gfx2", 0 ) // starfield data
ROM_LOAD( "format_z.4", 0x0000, 0x2000, CRC(910375a0) SHA1(1044e0f45ce34c15986d9ab520c0e7d08fd46dde) ) /* characters */
ROM_REGION( 0x2000, "starfield_data", 0 ) // starfield data
ROM_LOAD( "format_z.4", 0x0000, 0x2000, CRC(910375a0) SHA1(1044e0f45ce34c15986d9ab520c0e7d08fd46dde) )
ROM_REGION( 0x3000, "gfx3", 0 )
ROM_LOAD( "format_z.1", 0x0000, 0x1000, CRC(5739afd2) SHA1(3a645bc8a5ac69f1dc878a589c580f2bf033d3cb) ) /* sprites */
ROM_LOAD( "format_z.2", 0x1000, 0x1000, CRC(3a821391) SHA1(476507ba5e5d64ca3729244590beadb9b3a6a018) ) /* sprites */
ROM_LOAD( "format_z.3", 0x2000, 0x1000, CRC(7d1aec79) SHA1(bb19d6c91a14df26706226cfe22853bb8383c63d) ) /* sprites */
ROM_REGION( 0x3000, "sprites", 0 )
ROM_LOAD( "format_z.1", 0x0000, 0x1000, CRC(5739afd2) SHA1(3a645bc8a5ac69f1dc878a589c580f2bf033d3cb) )
ROM_LOAD( "format_z.2", 0x1000, 0x1000, CRC(3a821391) SHA1(476507ba5e5d64ca3729244590beadb9b3a6a018) )
ROM_LOAD( "format_z.3", 0x2000, 0x1000, CRC(7d1aec79) SHA1(bb19d6c91a14df26706226cfe22853bb8383c63d) )
ROM_REGION( 0x0300, "proms", 0 )
ROM_LOAD( "10c", 0x0000, 0x0100, CRC(b756dd6d) SHA1(ea79f87f84ded2f0a66458af24cbc792e5ff77e3) )
@ -324,16 +620,16 @@ ROM_START( aeroboto )
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "format_z.9", 0xf000, 0x1000, CRC(6b9215ad) SHA1(3ab416d070bf6b9a8be3e19d4dbc3a399d9ab5cb) )
ROM_REGION( 0x2000, "gfx1", 0 )
ROM_LOAD( "aeroboto.5", 0x0000, 0x2000, CRC(32fc00f9) SHA1(fd912fe2ab0101057c15c846f0cc4259cd94b035) ) /* characters */
ROM_REGION( 0x2000, "tiles", 0 )
ROM_LOAD( "aeroboto.5", 0x0000, 0x2000, CRC(32fc00f9) SHA1(fd912fe2ab0101057c15c846f0cc4259cd94b035) )
ROM_REGION( 0x2000, "gfx2", 0 ) // starfield data
ROM_LOAD( "format_z.4", 0x0000, 0x2000, CRC(910375a0) SHA1(1044e0f45ce34c15986d9ab520c0e7d08fd46dde) ) /* characters */
ROM_REGION( 0x2000, "starfield_data", 0 ) // starfield data
ROM_LOAD( "format_z.4", 0x0000, 0x2000, CRC(910375a0) SHA1(1044e0f45ce34c15986d9ab520c0e7d08fd46dde) )
ROM_REGION( 0x3000, "gfx3", 0 )
ROM_LOAD( "aeroboto.1", 0x0000, 0x1000, CRC(7820eeaf) SHA1(dedd15295bb02f417d0f51a29df686b66b94dee1) ) /* sprites */
ROM_LOAD( "aeroboto.2", 0x1000, 0x1000, CRC(c7f81a3c) SHA1(21476a4146d5c57e2b15125c304fc61d82edf4af) ) /* sprites */
ROM_LOAD( "aeroboto.3", 0x2000, 0x1000, CRC(5203ad04) SHA1(d16eb370de9033793a502e23c82a3119cd633aa9) ) /* sprites */
ROM_REGION( 0x3000, "sprites", 0 )
ROM_LOAD( "aeroboto.1", 0x0000, 0x1000, CRC(7820eeaf) SHA1(dedd15295bb02f417d0f51a29df686b66b94dee1) )
ROM_LOAD( "aeroboto.2", 0x1000, 0x1000, CRC(c7f81a3c) SHA1(21476a4146d5c57e2b15125c304fc61d82edf4af) )
ROM_LOAD( "aeroboto.3", 0x2000, 0x1000, CRC(5203ad04) SHA1(d16eb370de9033793a502e23c82a3119cd633aa9) )
ROM_REGION( 0x0300, "proms", 0 )
ROM_LOAD( "10c", 0x0000, 0x0100, CRC(b756dd6d) SHA1(ea79f87f84ded2f0a66458af24cbc792e5ff77e3) )
@ -341,6 +637,7 @@ ROM_START( aeroboto )
ROM_LOAD( "10a", 0x0200, 0x0100, CRC(e8733c8f) SHA1(105b44c9108ee173a417f8c79ec8381f824dd675) )
ROM_END
} // anonymous namespace
GAME( 1984, formatz, 0, formatz, formatz, aeroboto_state, empty_init, ROT0, "Jaleco", "Formation Z", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )

View File

@ -1,89 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Carlos A. Lozano, Uki
/***************************************************************************
Aeroboto
***************************************************************************/
#ifndef MAME_INCLUDES_AEROBOTO_H
#define MAME_INCLUDES_AEROBOTO_H
#pragma once
#include "emupal.h"
#include "tilemap.h"
class aeroboto_state : public driver_device
{
public:
aeroboto_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_mainram(*this, "mainram"),
m_videoram(*this, "videoram"),
m_hscroll(*this, "hscroll"),
m_tilecolor(*this, "tilecolor"),
m_spriteram(*this, "spriteram"),
m_vscroll(*this, "vscroll"),
m_starx(*this, "starx"),
m_stary(*this, "stary"),
m_bgcolor(*this, "bgcolor"),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette")
{ }
void formatz(machine_config &config);
private:
/* memory pointers */
required_shared_ptr<uint8_t> m_mainram;
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_hscroll;
required_shared_ptr<uint8_t> m_tilecolor;
required_shared_ptr<uint8_t> m_spriteram;
required_shared_ptr<uint8_t> m_vscroll;
required_shared_ptr<uint8_t> m_starx;
required_shared_ptr<uint8_t> m_stary;
required_shared_ptr<uint8_t> m_bgcolor;
/* stars layout */
uint8_t * m_stars_rom = 0U;
int m_stars_length = 0;
/* video-related */
tilemap_t *m_bg_tilemap = nullptr;
int m_charbank = 0;
int m_starsoff = 0;
int m_sx = 0;
int m_sy = 0;
uint8_t m_ox = 0U;
uint8_t m_oy = 0U;
/* misc */
int m_count = 0;
int m_disable_irq = 0;
uint8_t aeroboto_201_r();
uint8_t aeroboto_irq_ack_r();
uint8_t aeroboto_2973_r();
void aeroboto_1a2_w(uint8_t data);
uint8_t aeroboto_in0_r();
void aeroboto_3000_w(uint8_t data);
void aeroboto_videoram_w(offs_t offset, uint8_t data);
void aeroboto_tilecolor_w(offs_t offset, uint8_t data);
TILE_GET_INFO_MEMBER(get_tile_info);
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
uint32_t screen_update_aeroboto(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(vblank_irq);
void draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect );
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_audiocpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
void main_map(address_map &map);
void sound_map(address_map &map);
};
#endif // MAME_INCLUDES_AEROBOTO_H

View File

@ -1,212 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Carlos A. Lozano, Uki
/***************************************************************************
video/aeroboto.c
***************************************************************************/
#include "emu.h"
#include "aeroboto.h"
// how the starfield ROM is interpreted: 0=256x256x1 linear bitmap, 1=8x8x1x1024 tilemap
#define STARS_LAYOUT 1
// scroll speed of the stars: 1=normal, 2=half, 3=one-third...etc.(possitive integers only)
#define SCROLL_SPEED 1
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
TILE_GET_INFO_MEMBER(aeroboto_state::get_tile_info)
{
uint8_t code = m_videoram[tile_index];
tileinfo.set(0,
code + (m_charbank << 8),
m_tilecolor[code],
(m_tilecolor[code] >= 0x33) ? 0 : TILE_FORCE_LAYER0);
}
// transparency should only affect tiles with color 0x33 or higher
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
void aeroboto_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(aeroboto_state::get_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 64);
m_bg_tilemap->set_transparent_pen(0);
m_bg_tilemap->set_scroll_rows(64);
save_item(NAME(m_charbank));
save_item(NAME(m_starsoff));
save_item(NAME(m_sx));
save_item(NAME(m_sy));
save_item(NAME(m_ox));
save_item(NAME(m_oy));
#if STARS_LAYOUT
{
int i;
std::vector<uint8_t> temp(m_stars_length);
memcpy(&temp[0], m_stars_rom, m_stars_length);
for (i = 0; i < m_stars_length; i++)
m_stars_rom[(i & ~0xff) + (i << 5 & 0xe0) + (i >> 3 & 0x1f)] = temp[i];
}
#endif
}
/***************************************************************************
Memory handlers
***************************************************************************/
uint8_t aeroboto_state::aeroboto_in0_r()
{
return ioport(flip_screen() ? "P2" : "P1")->read();
}
void aeroboto_state::aeroboto_3000_w(uint8_t data)
{
/* bit 0 selects both flip screen and player1/player2 controls */
flip_screen_set(data & 0x01);
/* bit 1 = char bank select */
if (m_charbank != ((data & 0x02) >> 1))
{
m_bg_tilemap->mark_all_dirty();
m_charbank = (data & 0x02) >> 1;
}
/* bit 2 = disable star field? */
m_starsoff = data & 0x4;
}
void aeroboto_state::aeroboto_videoram_w(offs_t offset, uint8_t data)
{
m_videoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
void aeroboto_state::aeroboto_tilecolor_w(offs_t offset, uint8_t data)
{
if (m_tilecolor[offset] != data)
{
m_tilecolor[offset] = data;
m_bg_tilemap->mark_all_dirty();
}
}
/***************************************************************************
Display refresh
***************************************************************************/
void aeroboto_state::draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect )
{
for (int offs = 0; offs < m_spriteram.bytes(); offs += 4)
{
int x = m_spriteram[offs + 3];
int y = 240 - m_spriteram[offs];
if (flip_screen())
{
x = 248 - x;
y = 240 - y;
}
m_gfxdecode->gfx(1)->transpen(bitmap,cliprect,
m_spriteram[offs + 1],
m_spriteram[offs + 2] & 0x07,
flip_screen(), flip_screen(),
((x + 8) & 0xff) - 8, y, 0);
}
}
uint32_t aeroboto_state::screen_update_aeroboto(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
rectangle const splitrect1(0, 255, 0, 39);
rectangle const splitrect2(0, 255, 40, 255);
int sky_color, star_color;
sky_color = star_color = *m_bgcolor << 2;
// the star field is supposed to be seen through tile pen 0 when active
if (!m_starsoff)
{
if (star_color < 0xd0)
{
star_color = 0xd0;
sky_color = 0;
}
star_color += 2;
bitmap.fill(sky_color, cliprect);
// actual scroll speed is unknown but it can be adjusted by changing the SCROLL_SPEED constant
m_sx += char(*m_starx - m_ox);
m_ox = *m_starx;
int const x = m_sx / SCROLL_SPEED;
if (*m_vscroll != 0xff)
m_sy += char(*m_stary - m_oy);
m_oy = *m_stary;
int const y = m_sy / SCROLL_SPEED;
uint8_t const *const src_base = m_stars_rom;
for (int i = 0; i < 256; i++)
{
int src_offsx = (x + i) & 0xff;
int const src_colmask = 1 << (src_offsx & 7);
src_offsx >>= 3;
uint8_t const *const src_colptr = src_base + src_offsx;
int const pen = star_color + ((i + 8) >> 4 & 1);
for (int j = 0; j < 256; j++)
{
uint8_t const *const src_rowptr = src_colptr + (((y + j) & 0xff) << 5 );
if (!((unsigned)*src_rowptr & src_colmask))
bitmap.pix(j, i) = pen;
}
}
}
else
{
m_sx = m_ox = *m_starx;
m_sy = m_oy = *m_stary;
bitmap.fill(sky_color, cliprect);
}
for (int y = 0; y < 64; y++)
m_bg_tilemap->set_scrollx(y, m_hscroll[y]);
// the playfield is part of a splitscreen and should not overlap with status display
m_bg_tilemap->set_scrolly(0, *m_vscroll);
m_bg_tilemap->draw(screen, bitmap, splitrect2, 0, 0);
draw_sprites(bitmap, cliprect);
// the status display behaves more closely to a 40-line splitscreen than an overlay
m_bg_tilemap->set_scrolly(0, 0);
m_bg_tilemap->draw(screen, bitmap, splitrect1, 0, 0);
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders: Aaron Giles
/***************************************************************************
Jaleco Exerion hardware
@ -44,15 +45,15 @@ Stephh's notes (based on the games Z80 code and some tests) :
to 0x4dff (code at 0x07d8) if 1st score in the high-score table is >= 80000.
If checksum doesn't match the hardcoded value (0x63), you get 255 credits !
Notice that the displayed number of credits won't be correct as the game
isn't suppose to allow more than 9 credits.
- In a 2 players game, when player changes, if player it was player 2 turn,
isn't supposed to allow more than 9 credits.
- In a 2 players game, when player changes, if it was player 2 turn,
values from 0x6030 to 0x6032 (see above) are compared with hard-coded values
(code at 0x04c8). If they don't match respectively 0xfe, 0xb3 and 0x4c,
and if 9th score in the high-score table is not 0, the game resets !
- Before entering player's initials, a checksum is computed from 0x5f00 to 0x5fff
(code at 0x5bd0) if player has reached level 6 (2nd kind of enemies after bonus
stage). If checksum doesn't match the hardcoded value (0x9a), the game resets !
- There is sort of protection routine at 0x4120 which has an effect when
- There is a sort of protection routine at 0x4120 which has an effect when
player loses a life on reaching first bonus stage or after. If values read
from 0x6008 to 0x600b don't match values from ROM area 0x33c0-0x33ff,
the game resets. See 'protection_r' read handler.
@ -120,14 +121,509 @@ Stephh's notes (based on the games Z80 code and some tests) :
***************************************************************************/
#include "emu.h"
#include "exerion.h"
#include "cpu/z80/z80.h"
#include "machine/gen_latch.h"
#include "sound/ay8910.h"
#include "video/resnet.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
// configurable logging
#define LOG_AYPORTB (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_AYPORTB)
#include "logmacro.h"
#define LOGAYPORTB(...) LOGMASKED(LOG_AYPORTB, __VA_ARGS__)
namespace {
class exerion_state : public driver_device
{
public:
exerion_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_main_ram(*this, "main_ram"),
m_videoram(*this, "videoram"),
m_spriteram(*this, "spriteram"),
m_maincpu_region(*this, "maincpu"),
m_background_mixer(*this, "bg_char_mixer_prom"),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_inputs(*this, "P%u", 1U)
{ }
void exerion(machine_config &config);
void irion(machine_config &config);
void init_exerion();
void init_exerionb();
void init_irion();
DECLARE_CUSTOM_INPUT_MEMBER(controls_r);
DECLARE_INPUT_CHANGED_MEMBER(coin_inserted);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
private:
// memory pointers
required_shared_ptr<uint8_t> m_main_ram;
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_spriteram;
required_region_ptr<uint8_t> m_maincpu_region;
required_region_ptr<uint8_t> m_background_mixer;
// video-related
uint8_t m_cocktail_flip = 0U;
uint8_t m_char_palette = 0U;
uint8_t m_sprite_palette = 0U;
uint8_t m_char_bank = 0U;
std::unique_ptr<uint16_t[]> m_background_gfx[4]{};
uint8_t m_background_latches[13]{};
// protection?
uint8_t m_porta = 0U;
uint8_t m_portb = 0U;
// devices
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_ioport_array<2> m_inputs;
uint8_t protection_r(offs_t offset);
void videoreg_w(uint8_t data);
void video_latch_w(offs_t offset, uint8_t data);
uint8_t video_timing_r();
uint8_t porta_r();
void portb_w(uint8_t data);
void palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect);
void main_map(address_map &map);
void sub_map(address_map &map);
};
// video
static constexpr XTAL MASTER_CLOCK = XTAL(19'968'000); // verified on PCB
static constexpr XTAL CPU_CLOCK = MASTER_CLOCK / 6;
static constexpr XTAL AY8910_CLOCK = CPU_CLOCK / 2;
static constexpr XTAL PIXEL_CLOCK = MASTER_CLOCK / 3;
static constexpr int HCOUNT_START = 0x58;
static constexpr int HTOTAL = 512 - HCOUNT_START;
static constexpr int HBEND = 12 * 8; // ??
static constexpr int HBSTART = 52 * 8; // ??
static constexpr int VTOTAL = 256;
static constexpr int VBEND = 16;
static constexpr int VBSTART = 240;
static constexpr int BACKGROUND_X_START = 32;
static constexpr int VISIBLE_X_MIN = 12 * 8;
static constexpr int VISIBLE_X_MAX = 52 * 8;
static constexpr int VISIBLE_Y_MIN = 2 * 8;
static constexpr int VISIBLE_Y_MAX = 30 * 8;
/***************************************************************************
Convert the color PROMs into a more useable format.
The palette PROM is connected to the RGB output this way:
bit 7 -- 220 ohm resistor -- BLUE
-- 470 ohm resistor -- BLUE
-- 220 ohm resistor -- GREEN
-- 470 ohm resistor -- GREEN
-- 1 kohm resistor -- GREEN
-- 220 ohm resistor -- RED
-- 470 ohm resistor -- RED
bit 0 -- 1 kohm resistor -- RED
***************************************************************************/
void exerion_state::palette(palette_device &palette) const
{
const uint8_t *color_prom = memregion("proms")->base();
static constexpr int resistances_rg[3] = { 1000, 470, 220 };
static constexpr int resistances_b [2] = { 470, 220 };
// compute the color output resistor weights
double rweights[3], gweights[3], bweights[2];
compute_resistor_weights(0, 255, -1.0,
3, &resistances_rg[0], rweights, 0, 0,
3, &resistances_rg[0], gweights, 0, 0,
2, &resistances_b[0], bweights, 0, 0);
// create a lookup table for the palette
for (int i = 0; i < 0x20; i++)
{
int bit0, bit1, bit2;
// red component
bit0 = BIT(color_prom[i], 0);
bit1 = BIT(color_prom[i], 1);
bit2 = BIT(color_prom[i], 2);
int const r = combine_weights(rweights, bit0, bit1, bit2);
// green component
bit0 = BIT(color_prom[i], 3);
bit1 = BIT(color_prom[i], 4);
bit2 = BIT(color_prom[i], 5);
int const g = combine_weights(gweights, bit0, bit1, bit2);
// blue component
bit0 = BIT(color_prom[i], 6);
bit1 = BIT(color_prom[i], 7);
int const b = combine_weights(bweights, bit0, bit1);
palette.set_indirect_color(i, rgb_t(r, g, b));
}
// color_prom now points to the beginning of the lookup table
color_prom += 0x20;
// fg chars and sprites
for (int i = 0; i < 0x200; i++)
{
uint8_t const ctabentry = 0x10 | (color_prom[(i & 0x1c0) | ((i & 3) << 4) | ((i >> 2) & 0x0f)] & 0x0f);
palette.set_pen_indirect(i, ctabentry);
}
// bg chars (this is not the full story... there are four layers mixed using another PROM)
for (int i = 0x200; i < 0x300; i++)
{
uint8_t const ctabentry = color_prom[i] & 0x0f;
palette.set_pen_indirect(i, ctabentry);
}
}
/*************************************
*
* Video system startup
*
*************************************/
void exerion_state::video_start()
{
// allocate memory for the decoded background graphics
m_background_gfx[0] = std::make_unique<uint16_t[]>(256 * 256);
m_background_gfx[1] = std::make_unique<uint16_t[]>(256 * 256);
m_background_gfx[2] = std::make_unique<uint16_t[]>(256 * 256);
m_background_gfx[3] = std::make_unique<uint16_t[]>(256 * 256);
save_pointer(NAME(m_background_gfx[0]), 256 * 256);
save_pointer(NAME(m_background_gfx[1]), 256 * 256);
save_pointer(NAME(m_background_gfx[2]), 256 * 256);
save_pointer(NAME(m_background_gfx[3]), 256 * 256);
m_cocktail_flip = 0;
/*---------------------------------
* Decode the background graphics
*
* We decode the 4 background layers separately, but shuffle the bits so that
* we can OR all four layers together. Each layer has 2 bits per pixel. Each
* layer is decoded into the following bit patterns:
*
* 000a 0000 00AA
* 00b0 0000 BB00
* 0c00 00CC 0000
* d000 DD00 0000
*
* Where AA,BB,CC,DD are the 2bpp data for the pixel,and a,b,c,d are the OR
* of these two bits together.
*/
uint8_t *gfx = memregion("bgdata")->base();
for (int i = 0; i < 4; i++)
{
uint8_t *src = gfx + i * 0x2000;
uint16_t *dst = m_background_gfx[i].get();
for (int y = 0; y < 0x100; y++)
{
int x;
for (x = 0; x < 0x80; x += 4)
{
uint8_t data = *src++;
uint16_t val;
val = ((data >> 3) & 2) | ((data >> 0) & 1);
if (val) val |= 0x100 >> i;
*dst++ = val << (2 * i);
val = ((data >> 4) & 2) | ((data >> 1) & 1);
if (val) val |= 0x100 >> i;
*dst++ = val << (2 * i);
val = ((data >> 5) & 2) | ((data >> 2) & 1);
if (val) val |= 0x100 >> i;
*dst++ = val << (2 * i);
val = ((data >> 6) & 2) | ((data >> 3) & 1);
if (val) val |= 0x100 >> i;
*dst++ = val << (2 * i);
}
for (; x < 0x100; x++)
*dst++ = 0;
}
}
}
/*************************************
*
* Video register I/O
*
*************************************/
void exerion_state::videoreg_w(uint8_t data)
{
// bit 0 = flip screen and joystick input multiplexer
m_cocktail_flip = data & 1;
// bits 1-2 char lookup table bank
m_char_palette = (data & 0x06) >> 1;
// bits 3 char bank
m_char_bank = (data & 0x08) >> 3;
// bits 4-5 unused
// bits 6-7 sprite lookup table bank
m_sprite_palette = (data & 0xc0) >> 6;
}
void exerion_state::video_latch_w(offs_t offset, uint8_t data)
{
int const scanline = m_screen->vpos();
if (scanline > 0)
m_screen->update_partial(scanline - 1);
m_background_latches[offset] = data;
}
uint8_t exerion_state::video_timing_r()
{
// bit 0 is the SNMI signal, which is the negated value of H6, if H7=1 & H8=1 & VBLANK=0, otherwise 1
// bit 1 is VBLANK
uint16_t const hcounter = m_screen->hpos() + HCOUNT_START;
uint8_t snmi = 1;
if (((hcounter & 0x180) == 0x180) && !m_screen->vblank())
snmi = !((hcounter >> 6) & 0x01);
return (m_screen->vblank() << 1) | snmi;
}
/*************************************
*
* Background rendering
*
*************************************/
void exerion_state::draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// loop over all visible scanlines
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
uint16_t const *src0 = &m_background_gfx[0][m_background_latches[1] * 256];
uint16_t const *src1 = &m_background_gfx[1][m_background_latches[3] * 256];
uint16_t const *src2 = &m_background_gfx[2][m_background_latches[5] * 256];
uint16_t const *src3 = &m_background_gfx[3][m_background_latches[7] * 256];
int xoffs0 = m_background_latches[0];
int xoffs1 = m_background_latches[2];
int xoffs2 = m_background_latches[4];
int xoffs3 = m_background_latches[6];
int start0 = m_background_latches[8] & 0x0f;
int start1 = m_background_latches[9] & 0x0f;
int start2 = m_background_latches[10] & 0x0f;
int start3 = m_background_latches[11] & 0x0f;
int stop0 = m_background_latches[8] >> 4;
int stop1 = m_background_latches[9] >> 4;
int stop2 = m_background_latches[10] >> 4;
int stop3 = m_background_latches[11] >> 4;
uint8_t *const mixer = &m_background_mixer[(m_background_latches[12] << 4) & 0xf0];
uint16_t scanline[VISIBLE_X_MAX];
pen_t const pen_base = 0x200 + ((m_background_latches[12] >> 4) << 4);
// the cocktail flip flag controls whether we count up or down in X
if (!m_cocktail_flip)
{
// skip processing anything that's not visible
for (int x = BACKGROUND_X_START; x < cliprect.min_x; x++)
{
if (!(++xoffs0 & 0x1f)) start0++, stop0++;
if (!(++xoffs1 & 0x1f)) start1++, stop1++;
if (!(++xoffs2 & 0x1f)) start2++, stop2++;
if (!(++xoffs3 & 0x1f)) start3++, stop3++;
}
// draw the rest of the scanline fully
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
uint16_t combined = 0;
// the output enable is controlled by the carries on the start/stop counters
// they are only active when the start has carried but the stop hasn't
if ((start0 ^ stop0) & 0x10) combined |= src0[xoffs0 & 0xff];
if ((start1 ^ stop1) & 0x10) combined |= src1[xoffs1 & 0xff];
if ((start2 ^ stop2) & 0x10) combined |= src2[xoffs2 & 0xff];
if ((start3 ^ stop3) & 0x10) combined |= src3[xoffs3 & 0xff];
// bits 8-11 of the combined value contains the lookup for the mixer PROM
uint8_t const lookupval = mixer[combined >> 8] & 3;
// the color index comes from the looked up value combined with the pixel data
scanline[x] = pen_base | (lookupval << 2) | ((combined >> (2 * lookupval)) & 3);
// the start/stop counters are clocked when the low 5 bits of the X counter overflow
if (!(++xoffs0 & 0x1f)) start0++, stop0++;
if (!(++xoffs1 & 0x1f)) start1++, stop1++;
if (!(++xoffs2 & 0x1f)) start2++, stop2++;
if (!(++xoffs3 & 0x1f)) start3++, stop3++;
}
}
else
{
// skip processing anything that's not visible
for (int x = BACKGROUND_X_START; x < cliprect.min_x; x++)
{
if (!(xoffs0-- & 0x1f)) start0++, stop0++;
if (!(xoffs1-- & 0x1f)) start1++, stop1++;
if (!(xoffs2-- & 0x1f)) start2++, stop2++;
if (!(xoffs3-- & 0x1f)) start3++, stop3++;
}
// draw the rest of the scanline fully
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
uint16_t combined = 0;
// the output enable is controlled by the carries on the start/stop counters
// they are only active when the start has carried but the stop hasn't
if ((start0 ^ stop0) & 0x10) combined |= src0[xoffs0 & 0xff];
if ((start1 ^ stop1) & 0x10) combined |= src1[xoffs1 & 0xff];
if ((start2 ^ stop2) & 0x10) combined |= src2[xoffs2 & 0xff];
if ((start3 ^ stop3) & 0x10) combined |= src3[xoffs3 & 0xff];
// bits 8-11 of the combined value contains the lookup for the mixer PROM
uint8_t const lookupval = mixer[combined >> 8] & 3;
// the color index comes from the looked up value combined with the pixel data
scanline[x] = pen_base | (lookupval << 2) | ((combined >> (2 * lookupval)) & 3);
// the start/stop counters are clocked when the low 5 bits of the X counter overflow
if (!(xoffs0-- & 0x1f)) start0++, stop0++;
if (!(xoffs1-- & 0x1f)) start1++, stop1++;
if (!(xoffs2-- & 0x1f)) start2++, stop2++;
if (!(xoffs3-- & 0x1f)) start3++, stop3++;
}
}
// draw the scanline
draw_scanline16(bitmap, cliprect.min_x, y, cliprect.width(), &scanline[cliprect.min_x], nullptr);
}
}
/*************************************
*
* Core refresh routine
*
*************************************/
uint32_t exerion_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// draw background
draw_background(bitmap, cliprect);
// draw sprites
for (int i = 0; i < m_spriteram.bytes(); i += 4)
{
int const flags = m_spriteram[i + 0];
int y = m_spriteram[i + 1] ^ 255;
int code = m_spriteram[i + 2];
int x = m_spriteram[i + 3] * 2 + 72;
int xflip = flags & 0x80;
int yflip = flags & 0x40;
int const doubled = flags & 0x10;
int const wide = flags & 0x08;
int code2 = code;
int const color = ((flags >> 1) & 0x03) | ((code >> 5) & 0x04) | (code & 0x08) | (m_sprite_palette * 16);
gfx_element *gfx = doubled ? m_gfxdecode->gfx(2) : m_gfxdecode->gfx(1);
if (m_cocktail_flip)
{
x = 64 * 8 - gfx->width() - x;
y = 32 * 8 - gfx->height() - y;
if (wide) y -= gfx->height();
xflip = !xflip;
yflip = !yflip;
}
if (wide)
{
if (yflip)
code |= 0x10, code2 &= ~0x10;
else
code &= ~0x10, code2 |= 0x10;
gfx->transmask(bitmap, cliprect, code2, color, xflip, yflip, x, y + gfx->height(),
m_palette->transpen_mask(*gfx, color, 0x10));
}
gfx->transmask(bitmap, cliprect, code, color, xflip, yflip, x, y,
m_palette->transpen_mask(*gfx, color, 0x10));
if (doubled) i += 4;
}
// draw the visible text layer
for (int sy = cliprect.min_y / 8; sy <= cliprect.max_y / 8; sy++)
for (int sx = VISIBLE_X_MIN / 8; sx < VISIBLE_X_MAX / 8; sx++)
{
int const x = m_cocktail_flip ? (63 * 8 - 8 * sx) : 8 * sx;
int const y = m_cocktail_flip ? (31 * 8 - 8 * sy) : 8 * sy;
int const offs = sx + sy * 64;
m_gfxdecode->gfx(0)->transpen(bitmap, cliprect,
m_videoram[offs] + 256 * m_char_bank,
((m_videoram[offs] & 0xf0) >> 4) + m_char_palette * 16,
m_cocktail_flip, m_cocktail_flip, x, y, 0);
}
return 0;
}
// machine
/*************************************
*
* Interrupts & inputs
@ -170,7 +666,7 @@ void exerion_state::portb_w(uint8_t data)
m_porta = m_maincpu_region[0x5f76];
m_portb = data;
logerror("Port B = %02X\n", data);
LOGAYPORTB("Port B = %02X\n", data);
}
@ -371,16 +867,16 @@ void exerion_state::machine_reset()
void exerion_state::exerion(machine_config &config)
{
Z80(config, m_maincpu, EXERION_CPU_CLOCK);
Z80(config, m_maincpu, CPU_CLOCK);
m_maincpu->set_addrmap(AS_PROGRAM, &exerion_state::main_map);
z80_device &sub(Z80(config, "sub", EXERION_CPU_CLOCK));
z80_device &sub(Z80(config, "sub", CPU_CLOCK));
sub.set_addrmap(AS_PROGRAM, &exerion_state::sub_map);
// video hardware
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_raw(EXERION_PIXEL_CLOCK, EXERION_HTOTAL, EXERION_HBEND, EXERION_HBSTART, EXERION_VTOTAL, EXERION_VBEND, EXERION_VBSTART);
m_screen->set_raw(PIXEL_CLOCK, HTOTAL, HBEND, HBSTART, VTOTAL, VBEND, VBSTART);
m_screen->set_screen_update(FUNC(exerion_state::screen_update));
m_screen->set_palette(m_palette);
@ -392,9 +888,9 @@ void exerion_state::exerion(machine_config &config)
GENERIC_LATCH_8(config, "soundlatch");
AY8910(config, "ay1", EXERION_AY8910_CLOCK).add_route(ALL_OUTPUTS, "mono", 0.30);
AY8910(config, "ay1", AY8910_CLOCK).add_route(ALL_OUTPUTS, "mono", 0.30);
ay8910_device &ay2(AY8910(config, "ay2", EXERION_AY8910_CLOCK));
ay8910_device &ay2(AY8910(config, "ay2", AY8910_CLOCK));
ay2.port_a_read_callback().set(FUNC(exerion_state::porta_r));
ay2.port_b_write_callback().set(FUNC(exerion_state::portb_w));
ay2.add_route(ALL_OUTPUTS, "mono", 0.30);
@ -673,7 +1169,7 @@ void exerion_state::init_exerionb()
void exerion_state::init_irion()
{
// convert the gfx and cpu roms like in ExerionB
// convert the gfx and cpu ROMS like in ExerionB
init_exerionb();
// a further unscramble of gfx2
@ -689,6 +1185,7 @@ void exerion_state::init_irion()
}
}
} // anonymous namespace
/*************************************

View File

@ -1,103 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/*************************************************************************
Jaleco Exerion
*************************************************************************/
#ifndef MAME_INCLUDES_EXERION_H
#define MAME_INCLUDES_EXERION_H
#pragma once
#include "emupal.h"
#include "screen.h"
#define EXERION_MASTER_CLOCK (XTAL(19'968'000)) /* verified on pcb */
#define EXERION_CPU_CLOCK (EXERION_MASTER_CLOCK / 6)
#define EXERION_AY8910_CLOCK (EXERION_CPU_CLOCK / 2)
#define EXERION_PIXEL_CLOCK (EXERION_MASTER_CLOCK / 3)
#define EXERION_HCOUNT_START (0x58)
#define EXERION_HTOTAL (512-EXERION_HCOUNT_START)
#define EXERION_HBEND (12*8) /* ?? */
#define EXERION_HBSTART (52*8) /* ?? */
#define EXERION_VTOTAL (256)
#define EXERION_VBEND (16)
#define EXERION_VBSTART (240)
class exerion_state : public driver_device
{
public:
exerion_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_main_ram(*this, "main_ram"),
m_videoram(*this, "videoram"),
m_spriteram(*this, "spriteram"),
m_maincpu_region(*this, "maincpu"),
m_background_mixer(*this, "bg_char_mixer_prom"),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_inputs(*this, "P%u", 1U)
{ }
void exerion(machine_config &config);
void irion(machine_config &config);
void init_exerion();
void init_exerionb();
void init_irion();
DECLARE_CUSTOM_INPUT_MEMBER(controls_r);
DECLARE_INPUT_CHANGED_MEMBER(coin_inserted);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
private:
// memory pointers
required_shared_ptr<uint8_t> m_main_ram;
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_spriteram;
required_region_ptr<uint8_t> m_maincpu_region;
required_region_ptr<uint8_t> m_background_mixer;
// video-related
uint8_t m_cocktail_flip = 0U;
uint8_t m_char_palette = 0U;
uint8_t m_sprite_palette = 0U;
uint8_t m_char_bank = 0U;
std::unique_ptr<uint16_t[]> m_background_gfx[4]{};
uint8_t m_background_latches[13]{};
// protection?
uint8_t m_porta = 0U;
uint8_t m_portb = 0U;
// devices
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_ioport_array<2> m_inputs;
uint8_t protection_r(offs_t offset);
void videoreg_w(uint8_t data);
void video_latch_w(offs_t offset, uint8_t data);
uint8_t video_timing_r();
uint8_t porta_r();
void portb_w(uint8_t data);
void palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_background( bitmap_ind16 &bitmap, const rectangle &cliprect);
void main_map(address_map &map);
void sub_map(address_map &map);
};
#endif // MAME_INCLUDES_EXERION_H

View File

@ -1,403 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
Jaleco Exerion
***************************************************************************/
#include "emu.h"
#include "video/resnet.h"
#include "exerion.h"
#define BACKGROUND_X_START 32
#define VISIBLE_X_MIN (12*8)
#define VISIBLE_X_MAX (52*8)
#define VISIBLE_Y_MIN (2*8)
#define VISIBLE_Y_MAX (30*8)
/***************************************************************************
Convert the color PROMs into a more useable format.
The palette PROM is connected to the RGB output this way:
bit 7 -- 220 ohm resistor -- BLUE
-- 470 ohm resistor -- BLUE
-- 220 ohm resistor -- GREEN
-- 470 ohm resistor -- GREEN
-- 1 kohm resistor -- GREEN
-- 220 ohm resistor -- RED
-- 470 ohm resistor -- RED
bit 0 -- 1 kohm resistor -- RED
***************************************************************************/
void exerion_state::palette(palette_device &palette) const
{
const uint8_t *color_prom = memregion("proms")->base();
static constexpr int resistances_rg[3] = { 1000, 470, 220 };
static constexpr int resistances_b [2] = { 470, 220 };
// compute the color output resistor weights
double rweights[3], gweights[3], bweights[2];
compute_resistor_weights(0, 255, -1.0,
3, &resistances_rg[0], rweights, 0, 0,
3, &resistances_rg[0], gweights, 0, 0,
2, &resistances_b[0], bweights, 0, 0);
// create a lookup table for the palette
for (int i = 0; i < 0x20; i++)
{
int bit0, bit1, bit2;
// red component
bit0 = BIT(color_prom[i], 0);
bit1 = BIT(color_prom[i], 1);
bit2 = BIT(color_prom[i], 2);
int const r = combine_weights(rweights, bit0, bit1, bit2);
// green component
bit0 = BIT(color_prom[i], 3);
bit1 = BIT(color_prom[i], 4);
bit2 = BIT(color_prom[i], 5);
int const g = combine_weights(gweights, bit0, bit1, bit2);
// blue component
bit0 = BIT(color_prom[i], 6);
bit1 = BIT(color_prom[i], 7);
int const b = combine_weights(bweights, bit0, bit1);
palette.set_indirect_color(i, rgb_t(r, g, b));
}
// color_prom now points to the beginning of the lookup table
color_prom += 0x20;
// fg chars and sprites
for (int i = 0; i < 0x200; i++)
{
uint8_t const ctabentry = 0x10 | (color_prom[(i & 0x1c0) | ((i & 3) << 4) | ((i >> 2) & 0x0f)] & 0x0f);
palette.set_pen_indirect(i, ctabentry);
}
// bg chars (this is not the full story... there are four layers mixed using another PROM
for (int i = 0x200; i < 0x300; i++)
{
uint8_t const ctabentry = color_prom[i] & 0x0f;
palette.set_pen_indirect(i, ctabentry);
}
}
/*************************************
*
* Video system startup
*
*************************************/
void exerion_state::video_start()
{
// allocate memory for the decoded background graphics
m_background_gfx[0] = std::make_unique<uint16_t[]>(256 * 256);
m_background_gfx[1] = std::make_unique<uint16_t[]>(256 * 256);
m_background_gfx[2] = std::make_unique<uint16_t[]>(256 * 256);
m_background_gfx[3] = std::make_unique<uint16_t[]>(256 * 256);
save_pointer(NAME(m_background_gfx[0]), 256 * 256);
save_pointer(NAME(m_background_gfx[1]), 256 * 256);
save_pointer(NAME(m_background_gfx[2]), 256 * 256);
save_pointer(NAME(m_background_gfx[3]), 256 * 256);
m_cocktail_flip = 0;
/*---------------------------------
* Decode the background graphics
*
* We decode the 4 background layers separately, but shuffle the bits so that
* we can OR all four layers together. Each layer has 2 bits per pixel. Each
* layer is decoded into the following bit patterns:
*
* 000a 0000 00AA
* 00b0 0000 BB00
* 0c00 00CC 0000
* d000 DD00 0000
*
* Where AA,BB,CC,DD are the 2bpp data for the pixel,and a,b,c,d are the OR
* of these two bits together.
*/
uint8_t *gfx = memregion("bgdata")->base();
for (int i = 0; i < 4; i++)
{
uint8_t *src = gfx + i * 0x2000;
uint16_t *dst = m_background_gfx[i].get();
for (int y = 0; y < 0x100; y++)
{
int x;
for (x = 0; x < 0x80; x += 4)
{
uint8_t data = *src++;
uint16_t val;
val = ((data >> 3) & 2) | ((data >> 0) & 1);
if (val) val |= 0x100 >> i;
*dst++ = val << (2 * i);
val = ((data >> 4) & 2) | ((data >> 1) & 1);
if (val) val |= 0x100 >> i;
*dst++ = val << (2 * i);
val = ((data >> 5) & 2) | ((data >> 2) & 1);
if (val) val |= 0x100 >> i;
*dst++ = val << (2 * i);
val = ((data >> 6) & 2) | ((data >> 3) & 1);
if (val) val |= 0x100 >> i;
*dst++ = val << (2 * i);
}
for (; x < 0x100; x++)
*dst++ = 0;
}
}
}
/*************************************
*
* Video register I/O
*
*************************************/
void exerion_state::videoreg_w(uint8_t data)
{
// bit 0 = flip screen and joystick input multiplexer
m_cocktail_flip = data & 1;
// bits 1-2 char lookup table bank
m_char_palette = (data & 0x06) >> 1;
// bits 3 char bank
m_char_bank = (data & 0x08) >> 3;
// bits 4-5 unused
// bits 6-7 sprite lookup table bank
m_sprite_palette = (data & 0xc0) >> 6;
}
void exerion_state::video_latch_w(offs_t offset, uint8_t data)
{
int scanline = m_screen->vpos();
if (scanline > 0)
m_screen->update_partial(scanline - 1);
m_background_latches[offset] = data;
}
uint8_t exerion_state::video_timing_r()
{
// bit 0 is the SNMI signal, which is the negated value of H6, if H7=1 & H8=1 & VBLANK=0, otherwise 1
// bit 1 is VBLANK
uint16_t hcounter = m_screen->hpos() + EXERION_HCOUNT_START;
uint8_t snmi = 1;
if (((hcounter & 0x180) == 0x180) && !m_screen->vblank())
snmi = !((hcounter >> 6) & 0x01);
return (m_screen->vblank() << 1) | snmi;
}
/*************************************
*
* Background rendering
*
*************************************/
void exerion_state::draw_background( bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// loop over all visible scanlines
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
uint16_t *src0 = &m_background_gfx[0][m_background_latches[1] * 256];
uint16_t *src1 = &m_background_gfx[1][m_background_latches[3] * 256];
uint16_t *src2 = &m_background_gfx[2][m_background_latches[5] * 256];
uint16_t *src3 = &m_background_gfx[3][m_background_latches[7] * 256];
int xoffs0 = m_background_latches[0];
int xoffs1 = m_background_latches[2];
int xoffs2 = m_background_latches[4];
int xoffs3 = m_background_latches[6];
int start0 = m_background_latches[8] & 0x0f;
int start1 = m_background_latches[9] & 0x0f;
int start2 = m_background_latches[10] & 0x0f;
int start3 = m_background_latches[11] & 0x0f;
int stop0 = m_background_latches[8] >> 4;
int stop1 = m_background_latches[9] >> 4;
int stop2 = m_background_latches[10] >> 4;
int stop3 = m_background_latches[11] >> 4;
uint8_t *mixer = &m_background_mixer[(m_background_latches[12] << 4) & 0xf0];
uint16_t scanline[VISIBLE_X_MAX];
pen_t pen_base = 0x200 + ((m_background_latches[12] >> 4) << 4);
// the cocktail flip flag controls whether we count up or down in X
if (!m_cocktail_flip)
{
// skip processing anything that's not visible
for (int x = BACKGROUND_X_START; x < cliprect.min_x; x++)
{
if (!(++xoffs0 & 0x1f)) start0++, stop0++;
if (!(++xoffs1 & 0x1f)) start1++, stop1++;
if (!(++xoffs2 & 0x1f)) start2++, stop2++;
if (!(++xoffs3 & 0x1f)) start3++, stop3++;
}
// draw the rest of the scanline fully
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
uint16_t combined = 0;
uint8_t lookupval;
// the output enable is controlled by the carries on the start/stop counters
// they are only active when the start has carried but the stop hasn't
if ((start0 ^ stop0) & 0x10) combined |= src0[xoffs0 & 0xff];
if ((start1 ^ stop1) & 0x10) combined |= src1[xoffs1 & 0xff];
if ((start2 ^ stop2) & 0x10) combined |= src2[xoffs2 & 0xff];
if ((start3 ^ stop3) & 0x10) combined |= src3[xoffs3 & 0xff];
// bits 8-11 of the combined value contains the lookup for the mixer PROM
lookupval = mixer[combined >> 8] & 3;
// the color index comes from the looked up value combined with the pixel data
scanline[x] = pen_base | (lookupval << 2) | ((combined >> (2 * lookupval)) & 3);
// the start/stop counters are clocked when the low 5 bits of the X counter overflow
if (!(++xoffs0 & 0x1f)) start0++, stop0++;
if (!(++xoffs1 & 0x1f)) start1++, stop1++;
if (!(++xoffs2 & 0x1f)) start2++, stop2++;
if (!(++xoffs3 & 0x1f)) start3++, stop3++;
}
}
else
{
// skip processing anything that's not visible
for (int x = BACKGROUND_X_START; x < cliprect.min_x; x++)
{
if (!(xoffs0-- & 0x1f)) start0++, stop0++;
if (!(xoffs1-- & 0x1f)) start1++, stop1++;
if (!(xoffs2-- & 0x1f)) start2++, stop2++;
if (!(xoffs3-- & 0x1f)) start3++, stop3++;
}
// draw the rest of the scanline fully
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
uint16_t combined = 0;
uint8_t lookupval;
// the output enable is controlled by the carries on the start/stop counters
// they are only active when the start has carried but the stop hasn't
if ((start0 ^ stop0) & 0x10) combined |= src0[xoffs0 & 0xff];
if ((start1 ^ stop1) & 0x10) combined |= src1[xoffs1 & 0xff];
if ((start2 ^ stop2) & 0x10) combined |= src2[xoffs2 & 0xff];
if ((start3 ^ stop3) & 0x10) combined |= src3[xoffs3 & 0xff];
// bits 8-11 of the combined value contains the lookup for the mixer PROM
lookupval = mixer[combined >> 8] & 3;
// the color index comes from the looked up value combined with the pixel data
scanline[x] = pen_base | (lookupval << 2) | ((combined >> (2 * lookupval)) & 3);
// the start/stop counters are clocked when the low 5 bits of the X counter overflow
if (!(xoffs0-- & 0x1f)) start0++, stop0++;
if (!(xoffs1-- & 0x1f)) start1++, stop1++;
if (!(xoffs2-- & 0x1f)) start2++, stop2++;
if (!(xoffs3-- & 0x1f)) start3++, stop3++;
}
}
// draw the scanline
draw_scanline16(bitmap, cliprect.min_x, y, cliprect.width(), &scanline[cliprect.min_x], nullptr);
}
}
/*************************************
*
* Core refresh routine
*
*************************************/
uint32_t exerion_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// draw background
draw_background(bitmap, cliprect);
// draw sprites
for (int i = 0; i < m_spriteram.bytes(); i += 4)
{
int flags = m_spriteram[i + 0];
int y = m_spriteram[i + 1] ^ 255;
int code = m_spriteram[i + 2];
int x = m_spriteram[i + 3] * 2 + 72;
int xflip = flags & 0x80;
int yflip = flags & 0x40;
int doubled = flags & 0x10;
int wide = flags & 0x08;
int code2 = code;
int color = ((flags >> 1) & 0x03) | ((code >> 5) & 0x04) | (code & 0x08) | (m_sprite_palette * 16);
gfx_element *gfx = doubled ? m_gfxdecode->gfx(2) : m_gfxdecode->gfx(1);
if (m_cocktail_flip)
{
x = 64*8 - gfx->width() - x;
y = 32*8 - gfx->height() - y;
if (wide) y -= gfx->height();
xflip = !xflip;
yflip = !yflip;
}
if (wide)
{
if (yflip)
code |= 0x10, code2 &= ~0x10;
else
code &= ~0x10, code2 |= 0x10;
gfx->transmask(bitmap,cliprect, code2, color, xflip, yflip, x, y + gfx->height(),
m_palette->transpen_mask(*gfx, color, 0x10));
}
gfx->transmask(bitmap,cliprect, code, color, xflip, yflip, x, y,
m_palette->transpen_mask(*gfx, color, 0x10));
if (doubled) i += 4;
}
// draw the visible text layer
for (int sy = cliprect.min_y/8; sy <= cliprect.max_y/8; sy++)
for (int sx = VISIBLE_X_MIN/8; sx < VISIBLE_X_MAX/8; sx++)
{
int x = m_cocktail_flip ? (63*8 - 8*sx) : 8*sx;
int y = m_cocktail_flip ? (31*8 - 8*sy) : 8*sy;
int offs = sx + sy * 64;
m_gfxdecode->gfx(0)->transpen(bitmap,cliprect,
m_videoram[offs] + 256 * m_char_bank,
((m_videoram[offs] & 0xf0) >> 4) + m_char_palette * 16,
m_cocktail_flip, m_cocktail_flip, x, y, 0);
}
return 0;
}

View File

@ -5,7 +5,7 @@
TS 2004.10.22.
- fixed sprite issues
- added backgrounds and terrain info (external roms)
- added backgrounds and terrain info (external ROMs)
(press buttons 1+2 at the same time, to release 'army' ;)
@ -32,26 +32,326 @@ inputs + notes by stephh
*/
#include "emu.h"
#include "fcombat.h"
#include "cpu/z80/z80.h"
#include "machine/gen_latch.h"
#include "sound/ay8910.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "tilemap.h"
// configurable logging
#define LOG_PALETTEBANK (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_PALETTEBANK)
#include "logmacro.h"
#define LOGPALETTEBANK(...) LOGMASKED(LOG_PALETTEBANK, __VA_ARGS__)
namespace {
class fcombat_state : public driver_device
{
public:
fcombat_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_videoram(*this, "videoram"),
m_spriteram(*this, "spriteram"),
m_bgdata_rom(*this, "bgdata"),
m_terrain_rom(*this, "terrain_info"),
m_io_in(*this, "IN%u", 0U),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette")
{ }
void fcombat(machine_config &config);
void init_fcombat();
DECLARE_INPUT_CHANGED_MEMBER(coin_inserted);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
private:
/* memory pointers */
required_shared_ptr<u8> m_videoram;
required_shared_ptr<u8> m_spriteram;
required_region_ptr<u8> m_bgdata_rom;
required_region_ptr<u8> m_terrain_rom;
required_ioport_array<2> m_io_in;
// video-related
tilemap_t *m_bgmap = nullptr;
u8 m_cocktail_flip = 0U;
u8 m_char_palette = 0U;
u8 m_sprite_palette = 0U;
u8 m_char_bank = 0U;
// misc
u8 m_fcombat_sh = 0;
u16 m_fcombat_sv = 0;
u8 m_tx = 0;
u8 m_ty = 0;
// devices
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
u8 protection_r();
u8 port01_r();
void e900_w(u8 data);
void ea00_w(u8 data);
void eb00_w(u8 data);
void ec00_w(u8 data);
void ed00_w(u8 data);
u8 e300_r();
void ee00_w(u8 data);
void videoreg_w(u8 data);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
void fcombat_palette(palette_device &palette) const;
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void audio_map(address_map &map);
void main_map(address_map &map);
};
// video
// this is copied from Exerion, but it should be correct
static constexpr XTAL MASTER_CLOCK = 20_MHz_XTAL;
static constexpr XTAL CPU_CLOCK = MASTER_CLOCK / 6;
static constexpr XTAL AY8910_CLOCK = CPU_CLOCK / 2;
static constexpr XTAL PIXEL_CLOCK = MASTER_CLOCK / 3;
static constexpr int HCOUNT_START = 0x58;
static constexpr int HTOTAL = 512 - HCOUNT_START;
static constexpr int HBEND = 12 * 8; // ??
static constexpr int HBSTART = 52 * 8; //
static constexpr int VTOTAL = 256;
static constexpr int VBEND = 16;
static constexpr int VBSTART = 240;
static constexpr int BACKGROUND_X_START = 32;
static constexpr int BACKGROUND_X_START_FLIP = 72;
static constexpr int VISIBLE_X_MIN = 12 * 8;
static constexpr int VISIBLE_X_MAX = 52 * 8;
static constexpr int VISIBLE_Y_MIN = 2 * 8;
static constexpr int VISIBLE_Y_MAX = 30 * 8;
TILE_GET_INFO_MEMBER(fcombat_state::get_bg_tile_info)
{
//int palno = (tile_index - (tile_index / 32 * 16) * 32 * 16) / 32;
const int tileno = m_bgdata_rom[tile_index];
const int palno = 0x18; //m_terrain_rom[tile_index] >> 3;
tileinfo.set(2, tileno, palno, 0);
}
/***************************************************************************
Convert the color PROMs into a more useable format.
The palette PROM is connected to the RGB output this way:
bit 7 -- 220 ohm resistor -- BLUE
-- 470 ohm resistor -- BLUE
-- 220 ohm resistor -- GREEN
-- 470 ohm resistor -- GREEN
-- 1 kohm resistor -- GREEN
-- 220 ohm resistor -- RED
-- 470 ohm resistor -- RED
bit 0 -- 1 kohm resistor -- RED
***************************************************************************/
void fcombat_state::fcombat_palette(palette_device &palette) const
{
const u8 *color_prom = memregion("proms")->base();
// create a lookup table for the palette
for (int i = 0; i < 0x20; i++)
{
int bit0, bit1, bit2;
// red component
bit0 = BIT(color_prom[i], 0);
bit1 = BIT(color_prom[i], 1);
bit2 = BIT(color_prom[i], 2);
const u8 r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// green component
bit0 = BIT(color_prom[i], 3);
bit1 = BIT(color_prom[i], 4);
bit2 = BIT(color_prom[i], 5);
const u8 g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// blue component
bit0 = 0;
bit1 = BIT(color_prom[i], 6);
bit2 = BIT(color_prom[i], 7);
const u8 b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
palette.set_indirect_color(i, rgb_t(r, g, b));
}
// color_prom now points to the beginning of the lookup table
color_prom += 0x20;
// fg chars/sprites
for (int i = 0; i < 0x200; i++)
{
const u8 ctabentry = (color_prom[(i & 0x1c0) | ((i & 3) << 4) | ((i >> 2) & 0x0f)] & 0x0f) | 0x10;
palette.set_pen_indirect(i, ctabentry);
}
// bg chars (this is not the full story... there are four layers mixed using another PROM)
for (int i = 0x200; i < 0x300; i++)
{
const u8 ctabentry = color_prom[i] & 0x0f;
palette.set_pen_indirect(i, ctabentry);
}
}
/*************************************
*
* Video system startup
*
*************************************/
void fcombat_state::video_start()
{
m_bgmap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(fcombat_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 16, 16, 32 * 8 * 2, 32);
}
/*************************************
*
* Video register I/O
*
*************************************/
void fcombat_state::videoreg_w(u8 data)
{
// bit 0 = flip screen and joystick input multiplexer
m_cocktail_flip = data & 1;
// bits 1-2 char lookup table bank
m_char_palette = (data & 0x06) >> 1;
// bits 3 char bank
m_char_bank = (data & 0x08) >> 3;
// bits 4-5 unused
// bits 6-7 sprite lookup table bank
m_sprite_palette = 0; //(data & 0xc0) >> 6;
LOGPALETTEBANK("sprite palette bank: %02x", data);
}
u32 fcombat_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// draw background
m_bgmap->set_scrolly(0, m_fcombat_sh);
m_bgmap->set_scrollx(0, m_fcombat_sv - 24);
m_bgmap->mark_all_dirty();
m_bgmap->draw(screen, bitmap, cliprect, 0, 0);
//draw_background(bitmap, cliprect);
// draw sprites
for (int i = 0; i < m_spriteram.bytes(); i += 4)
{
const int flags = m_spriteram[i + 0];
int y = m_spriteram[i + 1] ^ 255;
int code = m_spriteram[i + 2] + ((flags & 0x20) << 3);
int x = m_spriteram[i + 3] * 2 + 72;
int xflip = flags & 0x80;
int yflip = flags & 0x40;
const bool doubled = false;// flags & 0x10;
const bool wide = flags & 0x08;
int code2 = code;
const int color = ((flags >> 1) & 0x03) | ((code >> 5) & 0x04) | (code & 0x08) | (m_sprite_palette * 16);
gfx_element *gfx = m_gfxdecode->gfx(1);
if (m_cocktail_flip)
{
x = 64 * 8 - gfx->width() - x;
y = 32 * 8 - gfx->height() - y;
if (wide) y -= gfx->height();
xflip = !xflip;
yflip = !yflip;
}
if (wide)
{
if (yflip)
code |= 0x10, code2 &= ~0x10;
else
code &= ~0x10, code2 |= 0x10;
gfx->transpen(bitmap, cliprect, code2, color, xflip, yflip, x, y + gfx->height(), 0);
}
if (flags & 0x10)
{
gfx->transpen(bitmap, cliprect, code2 + 16, color, xflip, yflip, x, y + gfx->height(), 0);
gfx->transpen(bitmap, cliprect, code2 + 16 * 2, color, xflip, yflip, x, y + 2 * gfx->height(), 0);
gfx->transpen(bitmap, cliprect, code2 + 16 * 3, color, xflip, yflip, x, y + 3 * gfx->height(), 0);
}
gfx->transpen(bitmap, cliprect, code, color, xflip, yflip, x, y, 0);
if (doubled) i += 4;
}
// draw the visible text layer
for (int sy = VISIBLE_Y_MIN / 8; sy < VISIBLE_Y_MAX / 8; sy++)
for (int sx = VISIBLE_X_MIN / 8; sx < VISIBLE_X_MAX / 8; sx++)
{
const int x = m_cocktail_flip ? (63 * 8 - 8 * sx) : 8 * sx;
const int y = m_cocktail_flip ? (31 * 8 - 8 * sy) : 8 * sy;
const int offs = sx + sy * 64;
m_gfxdecode->gfx(0)->transpen(bitmap, cliprect,
m_videoram[offs] + 256 * m_char_bank,
((m_videoram[offs] & 0xf0) >> 4) + m_char_palette * 16,
m_cocktail_flip, m_cocktail_flip, x, y, 0);
}
return 0;
}
// machine
INPUT_CHANGED_MEMBER(fcombat_state::coin_inserted)
{
/* coin insertion causes an NMI */
// coin insertion causes an NMI
m_maincpu->set_input_line(INPUT_LINE_NMI, newval ? CLEAR_LINE : ASSERT_LINE);
}
/* is it protection? */
// is it protection?
u8 fcombat_state::protection_r()
{
/* Must match ONE of these values after a "and $3E" intruction :
/* Must match ONE of these values after a "and $3E" instruction :
76F0: 1E 04 2E 26 34 32 3A 16 3E 36
@ -61,11 +361,11 @@ u8 fcombat_state::protection_r()
}
/* same as exerion again */
// same as exerion again
u8 fcombat_state::port01_r()
{
/* the cocktail flip bit muxes between ports 0 and 1 */
// the cocktail flip bit muxes between ports 0 and 1
return m_io_in[m_cocktail_flip ? 1 : 0]->read();
}
@ -88,7 +388,7 @@ void fcombat_state::eb00_w(u8 data)
}
// terrain info (ec00=x, ed00=y, return val in e300
// terrain info (ec00=x, ed00=y, return val in e300)
void fcombat_state::ec00_w(u8 data)
{
@ -105,7 +405,7 @@ u8 fcombat_state::e300_r()
const int wx = (m_tx + m_fcombat_sh) / 16;
const int wy = (m_ty * 2 + m_fcombat_sv) / 16;
return m_user2_region[wx * 32 * 16 + wy];
return m_terrain_rom[wx * 32 * 16 + wy];
}
void fcombat_state::ee00_w(u8 data)
@ -116,14 +416,14 @@ void fcombat_state::main_map(address_map &map)
{
map(0x0000, 0x7fff).rom();
map(0xc000, 0xc7ff).ram();
map(0xd000, 0xd7ff).ram().share("videoram");
map(0xd800, 0xd8ff).ram().share("spriteram");
map(0xd000, 0xd7ff).ram().share(m_videoram);
map(0xd800, 0xd8ff).ram().share(m_spriteram);
map(0xe000, 0xe000).r(FUNC(fcombat_state::port01_r));
map(0xe100, 0xe100).portr("DSW0");
map(0xe200, 0xe200).portr("DSW1");
map(0xe300, 0xe300).r(FUNC(fcombat_state::e300_r));
map(0xe400, 0xe400).r(FUNC(fcombat_state::protection_r)); // protection?
map(0xe800, 0xe800).w(FUNC(fcombat_state::videoreg_w)); // at least bit 0 for flip screen and joystick input multiplexor
map(0xe800, 0xe800).w(FUNC(fcombat_state::videoreg_w)); // at least bit 0 for flip screen and joystick input multiplexer
map(0xe900, 0xe900).w(FUNC(fcombat_state::e900_w));
map(0xea00, 0xea00).w(FUNC(fcombat_state::ea00_w));
map(0xeb00, 0xeb00).w(FUNC(fcombat_state::eb00_w));
@ -155,7 +455,7 @@ void fcombat_state::audio_map(address_map &map)
*************************************/
static INPUT_PORTS_START( fcombat )
PORT_START("IN0") /* player 1 inputs (muxed on 0xe000) */
PORT_START("IN0") // player 1 inputs (muxed on 0xe000)
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
@ -165,7 +465,7 @@ static INPUT_PORTS_START( fcombat )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START1 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START2 )
PORT_START("IN1") /* player 2 inputs (muxed on 0xe000) */
PORT_START("IN1") // player 2 inputs (muxed on 0xe000)
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
@ -175,7 +475,7 @@ static INPUT_PORTS_START( fcombat )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START1 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START2 )
PORT_START("DSW0") /* dip switches (0xe100) */
PORT_START("DSW0") // dip switches (0xe100)
PORT_DIPNAME( 0x07, 0x02, DEF_STR( Lives ) )
PORT_DIPSETTING( 0x00, "1" )
PORT_DIPSETTING( 0x01, "2" )
@ -198,7 +498,7 @@ static INPUT_PORTS_START( fcombat )
PORT_DIPSETTING( 0x00, DEF_STR( Upright ) )
PORT_DIPSETTING( 0x80, DEF_STR( Cocktail ) )
PORT_START("DSW1") /* dip switches/VBLANK (0xe200) */
PORT_START("DSW1") // dip switches/VBLANK (0xe200)
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_VBLANK("screen")
PORT_DIPNAME( 0x02, 0x00, DEF_STR( Unknown ) ) // related to vblank
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
@ -247,9 +547,9 @@ static const gfx_layout spritelayout =
static GFXDECODE_START( gfx_fcombat )
GFXDECODE_ENTRY( "gfx1", 0, charlayout, 0, 64 )
GFXDECODE_ENTRY( "gfx2", 0, spritelayout, 256, 64 )
GFXDECODE_ENTRY( "gfx3", 0, spritelayout, 512, 64 )
GFXDECODE_ENTRY( "fgtiles", 0, charlayout, 0, 64 )
GFXDECODE_ENTRY( "sprites", 0, spritelayout, 256, 64 )
GFXDECODE_ENTRY( "bgtiles", 0, spritelayout, 512, 64 )
GFXDECODE_END
@ -286,32 +586,32 @@ void fcombat_state::machine_reset()
void fcombat_state::fcombat(machine_config &config)
{
/* basic machine hardware */
Z80(config, m_maincpu, 10000000/3);
// basic machine hardware
Z80(config, m_maincpu, CPU_CLOCK);
m_maincpu->set_addrmap(AS_PROGRAM, &fcombat_state::main_map);
z80_device &audiocpu(Z80(config, "audiocpu", 10000000/3));
z80_device &audiocpu(Z80(config, "audiocpu", CPU_CLOCK));
audiocpu.set_addrmap(AS_PROGRAM, &fcombat_state::audio_map);
/* video hardware */
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_raw(FCOMBAT_PIXEL_CLOCK, FCOMBAT_HTOTAL, FCOMBAT_HBEND, FCOMBAT_HBSTART, FCOMBAT_VTOTAL, FCOMBAT_VBEND, FCOMBAT_VBSTART);
screen.set_raw(PIXEL_CLOCK, HTOTAL, HBEND, HBSTART, VTOTAL, VBEND, VBSTART);
screen.set_screen_update(FUNC(fcombat_state::screen_update));
screen.set_palette(m_palette);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_fcombat);
PALETTE(config, m_palette, FUNC(fcombat_state::fcombat_palette), 256 * 3, 32);
/* audio hardware */
// audio hardware
SPEAKER(config, "mono").front_center();
GENERIC_LATCH_8(config, "soundlatch");
YM2149(config, "ay1", 1500000).add_route(ALL_OUTPUTS, "mono", 0.12);
YM2149(config, "ay1", 1'500'000).add_route(ALL_OUTPUTS, "mono", 0.12); // TODO: should this and the following be CPU_CLOCK / 2?
YM2149(config, "ay2", 1500000).add_route(ALL_OUTPUTS, "mono", 0.12);
YM2149(config, "ay2", 1'500'000).add_route(ALL_OUTPUTS, "mono", 0.12);
YM2149(config, "ay3", 1500000).add_route(ALL_OUTPUTS, "mono", 0.12);
YM2149(config, "ay3", 1'500'000).add_route(ALL_OUTPUTS, "mono", 0.12);
}
/*************************************
@ -322,65 +622,65 @@ void fcombat_state::fcombat(machine_config &config)
void fcombat_state::init_fcombat()
{
/* allocate some temporary space */
// allocate some temporary space
std::vector<u8> temp(0x10000);
/* make a temporary copy of the character data */
// make a temporary copy of the character data
u8 *src = &temp[0];
u8 *dst = memregion("gfx1")->base();
u32 length = memregion("gfx1")->bytes();
u8 *dst = memregion("fgtiles")->base();
u32 length = memregion("fgtiles")->bytes();
memcpy(src, dst, length);
/* decode the characters */
/* the bits in the ROM are ordered: n8-n7 n6 n5 n4-v2 v1 v0 n3-n2 n1 n0 h2 */
/* we want them ordered like this: n8-n7 n6 n5 n4-n3 n2 n1 n0-v2 v1 v0 h2 */
/* decode the characters
the bits in the ROM are ordered: n8-n7 n6 n5 n4-v2 v1 v0 n3-n2 n1 n0 h2
we want them ordered like this: n8-n7 n6 n5 n4-n3 n2 n1 n0-v2 v1 v0 h2 */
for (u32 oldaddr = 0; oldaddr < length; oldaddr++)
{
u32 newaddr = ((oldaddr ) & 0x1f00) | /* keep n8-n4 */
((oldaddr << 3) & 0x00f0) | /* move n3-n0 */
((oldaddr >> 4) & 0x000e) | /* move v2-v0 */
((oldaddr ) & 0x0001); /* keep h2 */
u32 newaddr = ((oldaddr ) & 0x1f00) | // keep n8-n4
((oldaddr << 3) & 0x00f0) | // move n3-n0
((oldaddr >> 4) & 0x000e) | // move v2-v0
((oldaddr ) & 0x0001); // keep h2
dst[newaddr] = src[oldaddr];
}
/* make a temporary copy of the sprite data */
// make a temporary copy of the sprite data
src = &temp[0];
dst = memregion("gfx2")->base();
length = memregion("gfx2")->bytes();
dst = memregion("sprites")->base();
length = memregion("sprites")->bytes();
memcpy(src, dst, length);
/* decode the sprites */
/* the bits in the ROMs are ordered: n9 n8 n3 n7-n6 n5 n4 v3-v2 v1 v0 n2-n1 n0 h3 h2 */
/* we want them ordered like this: n9 n8 n7 n6-n5 n4 n3 n2-n1 n0 v3 v2-v1 v0 h3 h2 */
/* decode the sprites
the bits in the ROMs are ordered: n9 n8 n3 n7-n6 n5 n4 v3-v2 v1 v0 n2-n1 n0 h3 h2
we want them ordered like this: n9 n8 n7 n6-n5 n4 n3 n2-n1 n0 v3 v2-v1 v0 h3 h2 */
for (u32 oldaddr = 0; oldaddr < length; oldaddr++)
{
u32 newaddr = ((oldaddr << 1) & 0x3c00) | /* move n7-n4 */
((oldaddr >> 4) & 0x0200) | /* move n3 */
((oldaddr << 4) & 0x01c0) | /* move n2-n0 */
((oldaddr >> 3) & 0x003c) | /* move v3-v0 */
((oldaddr ) & 0xc003); /* keep n9-n8 h3-h2 */
u32 newaddr = ((oldaddr << 1) & 0x3c00) | // move n7-n4
((oldaddr >> 4) & 0x0200) | // move n3
((oldaddr << 4) & 0x01c0) | // move n2-n0
((oldaddr >> 3) & 0x003c) | // move v3-v0
((oldaddr ) & 0xc003); // keep n9-n8 h3-h2
dst[newaddr] = src[oldaddr];
}
/* make a temporary copy of the character data */
// make a temporary copy of the character data
src = &temp[0];
dst = memregion("gfx3")->base();
length = memregion("gfx3")->bytes();
dst = memregion("bgtiles")->base();
length = memregion("bgtiles")->bytes();
memcpy(src, dst, length);
/* decode the characters */
/* the bits in the ROM are ordered: n8-n7 n6 n5 n4-v2 v1 v0 n3-n2 n1 n0 h2 */
/* we want them ordered like this: n8-n7 n6 n5 n4-n3 n2 n1 n0-v2 v1 v0 h2 */
/* decode the characters
the bits in the ROM are ordered: n8-n7 n6 n5 n4-v2 v1 v0 n3-n2 n1 n0 h2
we want them ordered like this: n8-n7 n6 n5 n4-n3 n2 n1 n0-v2 v1 v0 h2 */
for (u32 oldaddr = 0; oldaddr < length; oldaddr++)
{
u32 newaddr = ((oldaddr << 1) & 0x3c00) | /* move n7-n4 */
((oldaddr >> 4) & 0x0200) | /* move n3 */
((oldaddr << 4) & 0x01c0) | /* move n2-n0 */
((oldaddr >> 3) & 0x003c) | /* move v3-v0 */
((oldaddr ) & 0xc003); /* keep n9-n8 h3-h2 */
u32 newaddr = ((oldaddr << 1) & 0x3c00) | // move n7-n4
((oldaddr >> 4) & 0x0200) | // move n3
((oldaddr << 4) & 0x01c0) | // move n2-n0
((oldaddr >> 3) & 0x003c) | // move v3-v0
((oldaddr ) & 0xc003); // keep n9-n8 h3-h2
dst[newaddr] = src[oldaddr];
}
@ -397,8 +697,8 @@ void fcombat_state::init_fcombat()
src = &temp[0];
dst = memregion("user2")->base();
length = memregion("user2")->bytes();
dst = memregion("terrain_info")->base();
length = memregion("terrain_info")->bytes();
memcpy(src, dst, length);
for (u32 oldaddr = 0; oldaddr < 32; oldaddr++)
@ -413,31 +713,34 @@ ROM_START( fcombat )
ROM_LOAD( "fcombat2.t9", 0x0000, 0x4000, CRC(30cb0c14) SHA1(8b5b6a4efaca2f138709184725e9e0e0b9cfc4c7) )
ROM_LOAD( "fcombat3.10t", 0x4000, 0x4000, CRC(e8511da0) SHA1(bab5c9244c970b97c025381c37ad372aa3b5cddf) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* 64k for the second CPU */
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "fcombat1.t5", 0x0000, 0x4000, CRC(a0cc1216) SHA1(3a8963ffde2ff4a3f428369133f94bb37717cae5) )
ROM_REGION( 0x02000, "gfx1", 0 )
ROM_LOAD( "fcombat7.l11", 0x00000, 0x2000, CRC(401061b5) SHA1(09dd23e86a56db8021e14432aced0eaf013fefe2) ) /* fg chars */
ROM_REGION( 0x02000, "fgtiles", 0 )
ROM_LOAD( "fcombat7.l11", 0x00000, 0x2000, CRC(401061b5) SHA1(09dd23e86a56db8021e14432aced0eaf013fefe2) )
ROM_REGION( 0x0c000, "gfx2", 0 )
ROM_LOAD( "fcombat8.d10", 0x00000, 0x4000, CRC(e810941e) SHA1(19ae85af0bf245caf3afe10d65e618cfb47d33c2) ) /* sprites */
ROM_REGION( 0x0c000, "sprites", 0 )
ROM_LOAD( "fcombat8.d10", 0x00000, 0x4000, CRC(e810941e) SHA1(19ae85af0bf245caf3afe10d65e618cfb47d33c2) )
ROM_LOAD( "fcombat9.d11", 0x04000, 0x4000, CRC(f95988e6) SHA1(25876652decca7ec1e9b37a16536c15ca2d1cb12) )
ROM_LOAD( "fcomba10.d12", 0x08000, 0x4000, CRC(908f154c) SHA1(b3761ee60d4a5ea36376759875105d23c57b4bf2) )
ROM_REGION( 0x04000, "gfx3", 0 )
ROM_REGION( 0x04000, "bgtiles", 0 )
ROM_LOAD( "fcombat6.f3", 0x00000, 0x4000, CRC(97282729) SHA1(72db0593551c2d15631341bf621b96013b46ce72) )
ROM_REGION( 0x04000, "bgdata", 0 )
ROM_LOAD( "fcombat5.l3", 0x00000, 0x4000, CRC(96194ca7) SHA1(087d6ac8f93f087cb5e378dbe9a8cfcffa2cdddc) ) /* bg data */
ROM_LOAD( "fcombat5.l3", 0x00000, 0x4000, CRC(96194ca7) SHA1(087d6ac8f93f087cb5e378dbe9a8cfcffa2cdddc) )
ROM_REGION( 0x04000, "user2", 0 )
ROM_LOAD( "fcombat4.p3", 0x00000, 0x4000, CRC(efe098ab) SHA1(fe64a5e9170835d242368109b1b221b0f8090e7e) ) /* terrain info */
ROM_REGION( 0x04000, "terrain_info", 0 )
ROM_LOAD( "fcombat4.p3", 0x00000, 0x4000, CRC(efe098ab) SHA1(fe64a5e9170835d242368109b1b221b0f8090e7e) )
ROM_REGION( 0x0420, "proms", 0 )
ROM_LOAD( "fcprom_a.c2", 0x0000, 0x0020, CRC(7ac480f0) SHA1(f491fe4da19d8c037e3733a5836de35cc438907e) ) /* palette */
ROM_LOAD( "fcprom_d.k12", 0x0020, 0x0100, CRC(9a348250) SHA1(faf8db4c42adee07795d06bea20704f8c51090ff) ) /* fg char lookup table */
ROM_LOAD( "fcprom_b.c4", 0x0120, 0x0100, CRC(ac9049f6) SHA1(57aa5b5df3e181bad76149745a422c3dd1edad49) ) /* sprite lookup table */
ROM_LOAD( "fcprom_c.a9", 0x0220, 0x0100, CRC(768ac120) SHA1(ceede1d6cbeae08da96ef52bdca2718a839d88ab) ) /* bg char mixer */
ROM_LOAD( "fcprom_a.c2", 0x0000, 0x0020, CRC(7ac480f0) SHA1(f491fe4da19d8c037e3733a5836de35cc438907e) ) // palette
ROM_LOAD( "fcprom_d.k12", 0x0020, 0x0100, CRC(9a348250) SHA1(faf8db4c42adee07795d06bea20704f8c51090ff) ) // fg char lookup table
ROM_LOAD( "fcprom_b.c4", 0x0120, 0x0100, CRC(ac9049f6) SHA1(57aa5b5df3e181bad76149745a422c3dd1edad49) ) // sprite lookup table
ROM_LOAD( "fcprom_c.a9", 0x0220, 0x0100, CRC(768ac120) SHA1(ceede1d6cbeae08da96ef52bdca2718a839d88ab) ) // bg char mixer
ROM_END
} // anonymous namespace
GAME( 1985, fcombat, 0, fcombat, fcombat, fcombat_state, init_fcombat, ROT90, "Jaleco", "Field Combat", MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE )

View File

@ -1,102 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Tomasz Slanina
#ifndef MAME_INCLUDES_FCOMBAT_H
#define MAME_INCLUDES_FCOMBAT_H
#pragma once
#include "emupal.h"
#include "tilemap.h"
// this is copied from Exerion, but it should be correct
#define FCOMBAT_MASTER_CLOCK (20000000)
#define FCOMBAT_CPU_CLOCK (FCOMBAT_MASTER_CLOCK / 6)
#define FCOMBAT_AY8910_CLOCK (FCOMBAT_CPU_CLOCK / 2)
#define FCOMBAT_PIXEL_CLOCK (FCOMBAT_MASTER_CLOCK / 3)
#define FCOMBAT_HCOUNT_START (0x58)
#define FCOMBAT_HTOTAL (512-FCOMBAT_HCOUNT_START)
#define FCOMBAT_HBEND (12*8) // ??
#define FCOMBAT_HBSTART (52*8) //
#define FCOMBAT_VTOTAL (256)
#define FCOMBAT_VBEND (16)
#define FCOMBAT_VBSTART (240)
#define BACKGROUND_X_START 32
#define BACKGROUND_X_START_FLIP 72
#define VISIBLE_X_MIN (12*8)
#define VISIBLE_X_MAX (52*8)
#define VISIBLE_Y_MIN (2*8)
#define VISIBLE_Y_MAX (30*8)
class fcombat_state : public driver_device
{
public:
fcombat_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_videoram(*this, "videoram"),
m_spriteram(*this, "spriteram"),
m_bgdata_rom(*this, "bgdata"),
m_user2_region(*this, "user2"),
m_io_in(*this, "IN%u", 0U),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette")
{ }
void fcombat(machine_config &config);
void init_fcombat();
DECLARE_INPUT_CHANGED_MEMBER(coin_inserted);
private:
/* memory pointers */
required_shared_ptr<u8> m_videoram;
required_shared_ptr<u8> m_spriteram;
required_region_ptr<u8> m_bgdata_rom;
required_region_ptr<u8> m_user2_region;
required_ioport_array<2> m_io_in;
/* video-related */
tilemap_t *m_bgmap = nullptr;
u8 m_cocktail_flip = 0U;
u8 m_char_palette = 0U;
u8 m_sprite_palette = 0U;
u8 m_char_bank = 0U;
/* misc */
int m_fcombat_sh = 0;
int m_fcombat_sv = 0;
int m_tx = 0;
int m_ty = 0;
/* devices */
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
u8 protection_r();
u8 port01_r();
void e900_w(u8 data);
void ea00_w(u8 data);
void eb00_w(u8 data);
void ec00_w(u8 data);
void ed00_w(u8 data);
u8 e300_r();
void ee00_w(u8 data);
void videoreg_w(u8 data);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
void fcombat_palette(palette_device &palette) const;
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void audio_map(address_map &map);
void main_map(address_map &map);
};
#endif // MAME_INCLUDES_FCOMBAT_H

View File

@ -1,201 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Tomasz Slanina
/***************************************************************************
Jaleco fcombat
***************************************************************************/
#include "emu.h"
#include "fcombat.h"
TILE_GET_INFO_MEMBER(fcombat_state::get_bg_tile_info)
{
int tileno, palno; //32*16 x 32
//palno = (tile_index - (tile_index / 32 * 16) * 32 * 16) / 32;
tileno = m_bgdata_rom[tile_index];
palno = 0x18; //m_user2_region[tile_index] >> 3;
tileinfo.set(2, tileno, palno, 0);
}
/***************************************************************************
Convert the color PROMs into a more useable format.
The palette PROM is connected to the RGB output this way:
bit 7 -- 220 ohm resistor -- BLUE
-- 470 ohm resistor -- BLUE
-- 220 ohm resistor -- GREEN
-- 470 ohm resistor -- GREEN
-- 1 kohm resistor -- GREEN
-- 220 ohm resistor -- RED
-- 470 ohm resistor -- RED
bit 0 -- 1 kohm resistor -- RED
***************************************************************************/
void fcombat_state::fcombat_palette(palette_device &palette) const
{
const u8 *color_prom = memregion("proms")->base();
// create a lookup table for the palette
for (int i = 0; i < 0x20; i++)
{
int bit0, bit1, bit2;
// red component
bit0 = BIT(color_prom[i], 0);
bit1 = BIT(color_prom[i], 1);
bit2 = BIT(color_prom[i], 2);
const u8 r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// green component
bit0 = BIT(color_prom[i], 3);
bit1 = BIT(color_prom[i], 4);
bit2 = BIT(color_prom[i], 5);
const u8 g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// blue component
bit0 = 0;
bit1 = BIT(color_prom[i], 6);
bit2 = BIT(color_prom[i], 7);
const u8 b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
palette.set_indirect_color(i, rgb_t(r, g, b));
}
// color_prom now points to the beginning of the lookup table
color_prom += 0x20;
// fg chars/sprites
for (int i = 0; i < 0x200; i++)
{
const u8 ctabentry = (color_prom[(i & 0x1c0) | ((i & 3) << 4) | ((i >> 2) & 0x0f)] & 0x0f) | 0x10;
palette.set_pen_indirect(i, ctabentry);
}
// bg chars (this is not the full story... there are four layers mixed using another PROM
for (int i = 0x200; i < 0x300; i++)
{
const u8 ctabentry = color_prom[i] & 0x0f;
palette.set_pen_indirect(i, ctabentry);
}
}
/*************************************
*
* Video system startup
*
*************************************/
void fcombat_state::video_start()
{
m_bgmap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(fcombat_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 16, 16, 32 * 8 * 2, 32);
}
/*************************************
*
* Video register I/O
*
*************************************/
void fcombat_state::videoreg_w(u8 data)
{
/* bit 0 = flip screen and joystick input multiplexor */
m_cocktail_flip = data & 1;
/* bits 1-2 char lookup table bank */
m_char_palette = (data & 0x06) >> 1;
/* bits 3 char bank */
m_char_bank = (data & 0x08) >> 3;
/* bits 4-5 unused */
/* bits 6-7 sprite lookup table bank */
m_sprite_palette = 0;//(data & 0xc0) >> 6;
//popmessage("%08x",data);
}
u32 fcombat_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
/* draw background */
m_bgmap->set_scrolly(0, m_fcombat_sh);
m_bgmap->set_scrollx(0, m_fcombat_sv - 24);
m_bgmap->mark_all_dirty();
m_bgmap->draw(screen, bitmap, cliprect, 0, 0);
//draw_background(bitmap, cliprect);
/* draw sprites */
for (int i = 0; i < m_spriteram.bytes(); i += 4)
{
int flags = m_spriteram[i + 0];
int y = m_spriteram[i + 1] ^ 255;
int code = m_spriteram[i + 2] + ((flags & 0x20) << 3);
int x = m_spriteram[i + 3] * 2 + 72;
int xflip = flags & 0x80;
int yflip = flags & 0x40;
bool doubled = false;// flags & 0x10;
const bool wide = flags & 0x08;
int code2 = code;
int color = ((flags >> 1) & 0x03) | ((code >> 5) & 0x04) | (code & 0x08) | (m_sprite_palette * 16);
gfx_element *gfx = m_gfxdecode->gfx(1);
if (m_cocktail_flip)
{
x = 64 * 8 - gfx->width() - x;
y = 32 * 8 - gfx->height() - y;
if (wide) y -= gfx->height();
xflip = !xflip;
yflip = !yflip;
}
if (wide)
{
if (yflip)
code |= 0x10, code2 &= ~0x10;
else
code &= ~0x10, code2 |= 0x10;
gfx->transpen(bitmap,cliprect, code2, color, xflip, yflip, x, y + gfx->height(), 0);
}
if (flags & 0x10)
{
gfx->transpen(bitmap,cliprect, code2 + 16, color, xflip, yflip, x, y + gfx->height(), 0);
gfx->transpen(bitmap,cliprect, code2 + 16 * 2, color, xflip, yflip, x, y + 2 * gfx->height(), 0);
gfx->transpen(bitmap,cliprect, code2 + 16 * 3, color, xflip, yflip, x, y + 3 * gfx->height(), 0);
}
gfx->transpen(bitmap,cliprect, code, color, xflip, yflip, x, y, 0);
if (doubled) i += 4;
}
/* draw the visible text layer */
for (int sy = VISIBLE_Y_MIN/8; sy < VISIBLE_Y_MAX/8; sy++)
for (int sx = VISIBLE_X_MIN/8; sx < VISIBLE_X_MAX/8; sx++)
{
int x = m_cocktail_flip ? (63 * 8 - 8 * sx) : 8 * sx;
int y = m_cocktail_flip ? (31 * 8 - 8 * sy) : 8 * sy;
const int offs = sx + sy * 64;
m_gfxdecode->gfx(0)->transpen(bitmap,cliprect,
m_videoram[offs] + 256 * m_char_bank,
((m_videoram[offs] & 0xf0) >> 4) + m_char_palette * 16,
m_cocktail_flip, m_cocktail_flip, x, y, 0);
}
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders: Luca Elia
/***************************************************************************
Ginga NinkyouDen
@ -13,7 +14,7 @@ OSC. : 6.000MHz 3.579545MHz
* CTC uses MB-8873E (MC-6840)
Interesting routines (main cpu)
Interesting routines (main CPU)
-------------------------------
Interrupts: 1-7] d17a: clears 20018 etc.
@ -22,7 +23,7 @@ f4b2 print string: a1->(char)*,0x25(%) d7.w=color a0->screen (30000)
f5d6 print 7 digit BCD number: d0.l to (a1)+ color $3000
Interesting locations (main cpu)
Interesting locations (main CPU)
--------------------------------
20014 # of players (1-2)
@ -57,51 +58,388 @@ f5d6 print 7 digit BCD number: d0.l to (a1)+ color $3000
***************************************************************************/
#include "emu.h"
#include "ginganin.h"
#include "cpu/m68000/m68000.h"
#include "cpu/m6809/m6809.h"
#include "machine/6840ptm.h"
#include "machine/gen_latch.h"
#include "sound/ay8910.h"
#include "sound/ymopl.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "tilemap.h"
#define MAIN_CLOCK XTAL(6'000'000)
#define SOUND_CLOCK XTAL(3'579'545)
// configurable logging
#define LOG_VREGS (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_VREGS)
#include "logmacro.h"
#define LOGVREGS(...) LOGMASKED(LOG_VREGS, __VA_ARGS__)
/*
**
** Main cpu data
**
namespace {
class ginganin_state : public driver_device
{
public:
ginganin_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_txtram(*this, "txtram"),
m_spriteram(*this, "spriteram"),
m_vregs(*this, "vregs"),
m_fgram(*this, "fgram"),
m_bgrom(*this, "bgrom"),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
m_soundlatch(*this, "soundlatch")
{ }
void ginganin(machine_config &config);
void init_ginganin();
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
private:
// memory pointers
required_shared_ptr<u16> m_txtram;
required_shared_ptr<u16> m_spriteram;
required_shared_ptr<u16> m_vregs;
required_shared_ptr<u16> m_fgram;
required_region_ptr<u8> m_bgrom;
// video-related
tilemap_t *m_bg_tilemap = nullptr;
tilemap_t *m_fg_tilemap = nullptr;
tilemap_t *m_tx_tilemap = nullptr;
u16 m_layers_ctrl = 0;
u8 m_flipscreen = 0;
#ifdef MAME_DEBUG
int m_posx = 0;
int m_posy = 0;
#endif
// devices
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_audiocpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
required_device<generic_latch_8_device> m_soundlatch;
void fgram_w(offs_t offset, u16 data, u16 mem_mask = ~0);
void txtram_w(offs_t offset, u16 data, u16 mem_mask = ~0);
void vregs_w(offs_t offset, u16 data, u16 mem_mask = ~0);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
TILE_GET_INFO_MEMBER(get_fg_tile_info);
TILE_GET_INFO_MEMBER(get_txt_tile_info);
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
void main_map(address_map &map);
void sound_map(address_map &map);
};
// video
/**************************************************************************
Note: if MAME_DEBUG is defined, pressing Z with:
Q shows background
W shows foreground
E shows frontmost (text) layer
A shows sprites
Keys can be used together!
[Screen]
Visible Size: 256H x 240V
Dynamic Colors: 256 x 4
Color Space: 16R x 16G x 16B
[Scrolling layers]
Format (all layers): Offset: 0x400 0x000
Bit: fedc---- -------- Color
----ba98 76543210 Code
[Background]
Size: 8192 x 512 (static: stored in ROM)
Scrolling: X,Y (registers: $60006.w, $60004.w)
Tiles Size: 16 x 16
Tiles Number: $400
Colors: $300-$3ff
[Foreground]
Size: 4096 x 512
Scrolling: X,Y (registers: $60002.w, $60000.w)
Tiles Size: 16 x 16
Tiles Number: $400
Colors: $200-$2ff
[Frontmost]
Size: 256 x 256
Scrolling: -
Tiles Size: 8 x 8
Tiles Number: $200
Colors: $000-$0ff
[Sprites]
On Screen: 256
In ROM: $a00
Colors: $100-$1ff
Format: See Below
**************************************************************************/
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
// Background - Resides in ROM
static constexpr u8 BG_GFX = 0;
static constexpr u16 BG_NX = (16 * 32);
static constexpr u8 BG_NY = (16 * 2);
TILE_GET_INFO_MEMBER(ginganin_state::get_bg_tile_info)
{
const u32 code = m_bgrom[2 * tile_index + 0] * 256 + m_bgrom[2 * tile_index + 1];
tileinfo.set(BG_GFX,
code,
code >> 12,
0);
}
// Foreground - Resides in RAM
static constexpr u8 FG_GFX = 1;
static constexpr u16 FG_NX = (16 * 16);
static constexpr u8 FG_NY = (16 * 2);
TILE_GET_INFO_MEMBER(ginganin_state::get_fg_tile_info)
{
const u16 code = m_fgram[tile_index];
tileinfo.set(FG_GFX,
code,
code >> 12,
0);
}
void ginganin_state::fgram_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_fgram[offset]);
m_fg_tilemap->mark_tile_dirty(offset);
}
// Frontmost (text) Layer - Resides in RAM
static constexpr u8 TXT_GFX = 2;
static constexpr u8 TXT_NX = 32;
static constexpr u8 TXT_NY = 32;
TILE_GET_INFO_MEMBER(ginganin_state::get_txt_tile_info)
{
const u16 code = m_txtram[tile_index];
tileinfo.set(TXT_GFX,
code,
code >> 12,
0);
}
void ginganin_state::txtram_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_txtram[offset]);
m_tx_tilemap->mark_tile_dirty(offset);
}
void ginganin_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(ginganin_state::get_bg_tile_info)), TILEMAP_SCAN_COLS, 16, 16, BG_NX, BG_NY);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(ginganin_state::get_fg_tile_info)), TILEMAP_SCAN_COLS, 16, 16, FG_NX, FG_NY);
m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(ginganin_state::get_txt_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, TXT_NX, TXT_NY);
m_fg_tilemap->set_transparent_pen(15);
m_tx_tilemap->set_transparent_pen(15);
}
void ginganin_state::vregs_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_vregs[offset]);
data = m_vregs[offset];
switch (offset)
{
case 0:
m_fg_tilemap->set_scrolly(0, data);
break;
case 1:
m_fg_tilemap->set_scrollx(0, data);
break;
case 2:
m_bg_tilemap->set_scrolly(0, data);
break;
case 3:
m_bg_tilemap->set_scrollx(0, data);
break;
case 4:
m_layers_ctrl = data;
break;
/* case 5:
* break;
*/
case 6:
m_flipscreen = !(data & 1);
machine().tilemap().set_flip_all(m_flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
break;
case 7:
m_soundlatch->write(data);
m_audiocpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
break;
default:
LOGVREGS("CPU #0 PC %06X : Warning, videoreg %04X <- %04X\n", m_maincpu->pc(), offset, data);
}
}
/* --------------------------[ Sprites Format ]----------------------------
Offset: Values: Format:
0000.w y position fedc ba9- ---- ---- unused
---- ---8 ---- ---- subtract 256
---- ---- 7654 3210 position
0002.w x position See above
0004.w code f--- ---- ---- ---- y flip
-e-- ---- ---- ---- x flip
--dc ---- ---- ---- unused?
---- ba98 7654 3210 code
0006.w colour fedc ---- ---- ---- colour code
---- ba98 7654 3210 unused?
------------------------------------------------------------------------ */
void ginganin_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
for (int offs = 0; offs < (m_spriteram.bytes() >> 1); offs += 4)
{
int y = m_spriteram[offs + 0];
int x = m_spriteram[offs + 1];
const u32 code = m_spriteram[offs + 2];
const u16 attr = m_spriteram[offs + 3];
int flipx = code & 0x4000;
int flipy = code & 0x8000;
x = (x & 0xff) - (x & 0x100);
y = (y & 0xff) - (y & 0x100);
if (m_flipscreen)
{
x = 240 - x;
y = 240 - y;
flipx = !flipx;
flipy = !flipy;
}
m_gfxdecode->gfx(3)->transpen(bitmap, cliprect,
code & 0x3fff,
attr >> 12,
flipx, flipy,
x, y, 15);
}
}
u32 ginganin_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int layers_ctrl1 = m_layers_ctrl;
#ifdef MAME_DEBUG
if (machine().input().code_pressed(KEYCODE_Z))
{
int msk = 0;
if (machine().input().code_pressed(KEYCODE_Q)) { msk |= 0xfff1;}
if (machine().input().code_pressed(KEYCODE_W)) { msk |= 0xfff2;}
if (machine().input().code_pressed(KEYCODE_E)) { msk |= 0xfff4;}
if (machine().input().code_pressed(KEYCODE_A)) { msk |= 0xfff8;}
if (msk != 0) layers_ctrl1 &= msk;
#define SETSCROLL \
m_bg_tilemap->set_scrollx(0, m_posx); \
m_bg_tilemap->set_scrolly(0, m_posy); \
m_fg_tilemap->set_scrollx(0, m_posx); \
m_fg_tilemap->set_scrolly(0, m_posy); \
popmessage("B>%04X:%04X F>%04X:%04X",m_posx%(BG_NX*16),m_posy%(BG_NY*16),m_posx%(FG_NX*16),m_posy%(FG_NY*16));
if (machine().input().code_pressed(KEYCODE_L)) { m_posx +=8; SETSCROLL }
if (machine().input().code_pressed(KEYCODE_J)) { m_posx -=8; SETSCROLL }
if (machine().input().code_pressed(KEYCODE_K)) { m_posy +=8; SETSCROLL }
if (machine().input().code_pressed(KEYCODE_I)) { m_posy -=8; SETSCROLL }
if (machine().input().code_pressed(KEYCODE_H)) { m_posx = m_posy = 0; SETSCROLL }
}
#endif
if (layers_ctrl1 & 1)
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
else
bitmap.fill(0, cliprect);
if (layers_ctrl1 & 2)
m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
if (layers_ctrl1 & 8)
draw_sprites(bitmap, cliprect);
if (layers_ctrl1 & 4)
m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}
// machine
void ginganin_state::main_map(address_map &map)
{
// PC=0x408 ROM area 10000-13fff is written at POST with: 0000 0000 0000 0001,
// looks a debugging left-over for GFX patching (causes state garbage if hooked as RAM write mirror)
map(0x000000, 0x01ffff).rom().nopw();
map(0x020000, 0x023fff).ram();
map(0x030000, 0x0307ff).ram().w(FUNC(ginganin_state::txtram_w)).share("txtram");
map(0x040000, 0x0407ff).ram().share("spriteram");
map(0x030000, 0x0307ff).ram().w(FUNC(ginganin_state::txtram_w)).share(m_txtram);
map(0x040000, 0x0407ff).ram().share(m_spriteram);
map(0x050000, 0x0507ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette");
map(0x060000, 0x06000f).ram().w(FUNC(ginganin_state::vregs_w)).share("vregs");
map(0x068000, 0x06bfff).ram().w(FUNC(ginganin_state::fgram_w)).share("fgram");
map(0x060000, 0x06000f).ram().w(FUNC(ginganin_state::vregs_w)).share(m_vregs);
map(0x068000, 0x06bfff).ram().w(FUNC(ginganin_state::fgram_w)).share(m_fgram);
map(0x070000, 0x070001).portr("P1_P2");
map(0x070002, 0x070003).portr("DSW");
}
/*
**
** Sound cpu data
**
*/
void ginganin_state::sound_map(address_map &map)
{
map(0x0000, 0x07ff).ram();
@ -113,10 +451,8 @@ void ginganin_state::sound_map(address_map &map)
}
/* Input Ports */
static INPUT_PORTS_START( ginganin )
PORT_START("P1_P2") /* 70000.w */
PORT_START("P1_P2") // 70000.w
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY
@ -134,7 +470,7 @@ static INPUT_PORTS_START( ginganin )
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_START1 )
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START2 )
PORT_START("DSW") /* 70002.w */
PORT_START("DSW") // 70002.w
PORT_DIPNAME( 0x0007, 0x0007, DEF_STR( Coin_A ) )
PORT_DIPSETTING( 0x0000, DEF_STR( 5C_1C ) )
PORT_DIPSETTING( 0x0004, DEF_STR( 4C_1C ) )
@ -171,10 +507,10 @@ static INPUT_PORTS_START( ginganin )
PORT_DIPNAME( 0x0800, 0x0000, DEF_STR( Cabinet ) )
PORT_DIPSETTING( 0x0000, DEF_STR( Upright ) )
PORT_DIPSETTING( 0x0800, DEF_STR( Cocktail ) )
PORT_DIPNAME( 0x1000, 0x1000, DEF_STR( Unknown ) ) /* probably unused */
PORT_DIPNAME( 0x1000, 0x1000, DEF_STR( Unknown ) ) // probably unused
PORT_DIPSETTING( 0x1000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
PORT_DIPNAME( 0x2000, 0x2000, DEF_STR( Unknown ) ) /* it does something */
PORT_DIPNAME( 0x2000, 0x2000, DEF_STR( Unknown ) ) // it does something
PORT_DIPSETTING( 0x2000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
PORT_DIPNAME( 0x4000, 0x4000, DEF_STR( Flip_Screen ) )
@ -187,18 +523,11 @@ INPUT_PORTS_END
/*
**
** Gfx data
**
*/
static GFXDECODE_START( gfx_ginganin )
GFXDECODE_ENTRY( "gfx1", 0, gfx_8x8x4_col_2x2_group_packed_msb, 256*3, 16 ) /* [0] bg */
GFXDECODE_ENTRY( "gfx2", 0, gfx_8x8x4_col_2x2_group_packed_msb, 256*2, 16 ) /* [1] fg */
GFXDECODE_ENTRY( "gfx3", 0, gfx_8x8x4_packed_msb, 256*0, 16 ) /* [2] txt */
GFXDECODE_ENTRY( "gfx4", 0, gfx_8x8x4_col_2x2_group_packed_msb, 256*1, 16 ) /* [3] sprites */
GFXDECODE_ENTRY( "bgtiles", 0, gfx_8x8x4_col_2x2_group_packed_msb, 256*3, 16 )
GFXDECODE_ENTRY( "fgtiles", 0, gfx_8x8x4_col_2x2_group_packed_msb, 256*2, 16 )
GFXDECODE_ENTRY( "txttiles", 0, gfx_8x8x4_packed_msb, 256*0, 16 )
GFXDECODE_ENTRY( "sprites", 0, gfx_8x8x4_col_2x2_group_packed_msb, 256*1, 16 )
GFXDECODE_END
@ -214,27 +543,24 @@ void ginganin_state::machine_reset()
m_flipscreen = 0;
}
WRITE_LINE_MEMBER(ginganin_state::ptm_irq)
{
m_audiocpu->set_input_line(0, state ? ASSERT_LINE : CLEAR_LINE);
}
void ginganin_state::ginganin(machine_config &config)
{
/* basic machine hardware */
static constexpr XTAL MAIN_CLOCK = XTAL(6'000'000);
static constexpr XTAL SOUND_CLOCK = XTAL(3'579'545);
// basic machine hardware
M68000(config, m_maincpu, MAIN_CLOCK);
m_maincpu->set_addrmap(AS_PROGRAM, &ginganin_state::main_map);
m_maincpu->set_vblank_int("screen", FUNC(ginganin_state::irq1_line_hold)); /* ? (vectors 1-7 contain the same address) */
m_maincpu->set_vblank_int("screen", FUNC(ginganin_state::irq1_line_hold)); // ? (vectors 1-7 contain the same address)
MC6809(config, m_audiocpu, SOUND_CLOCK); // MBL68B09?
m_audiocpu->set_addrmap(AS_PROGRAM, &ginganin_state::sound_map);
ptm6840_device &ptm(PTM6840(config, "6840ptm", SOUND_CLOCK / 2));
ptm.set_external_clocks(0, 0, 0);
ptm.o1_callback().set(FUNC(ginganin_state::ptm_irq));
ptm.o1_callback().set_inputline(m_audiocpu, 0);
/* video hardware */
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
@ -246,14 +572,14 @@ void ginganin_state::ginganin(machine_config &config)
GFXDECODE(config, m_gfxdecode, m_palette, gfx_ginganin);
PALETTE(config, m_palette).set_format(palette_device::RGBx_444, 1024);
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
GENERIC_LATCH_8(config, m_soundlatch);
YM2149(config, "psg", SOUND_CLOCK / 2).add_route(ALL_OUTPUTS, "mono", 0.10);
Y8950(config, "ymsnd", SOUND_CLOCK).add_route(ALL_OUTPUTS, "mono", 1.0); /* The Y8950 is basically a YM3526 with ADPCM built in */
Y8950(config, "ymsnd", SOUND_CLOCK).add_route(ALL_OUTPUTS, "mono", 1.0); // The Y8950 is basically a YM3526 with ADPCM built in
}
@ -265,70 +591,70 @@ void ginganin_state::ginganin(machine_config &config)
***************************************************************************/
ROM_START( ginganin )
ROM_REGION( 0x20000, "maincpu", 0 ) /* main cpu */
ROM_REGION( 0x20000, "maincpu", 0 )
ROM_LOAD16_BYTE( "gn_02.bin", 0x00000, 0x10000, CRC(4a4e012f) SHA1(7c94a5b6b71e037af355f3aa4623be1f585db8dc) )
ROM_LOAD16_BYTE( "gn_01.bin", 0x00001, 0x10000, CRC(30256fcb) SHA1(dc15e0da88ae5cabe0150f7290508c3d58c06c11) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound cpu */
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "gn_05.bin", 0x00000, 0x10000, CRC(e76e10e7) SHA1(b16f10a1a01b7b04221c9bf1b0d157e936bc5fb5) )
ROM_REGION( 0x20000, "gfx1", 0 )
ROM_LOAD( "gn_15.bin", 0x000000, 0x10000, CRC(1b8ac9fb) SHA1(1e5ee2a565fa262f1e48c1088d84c6f42d84b4e3) ) /* bg */
ROM_REGION( 0x20000, "bgtiles", 0 )
ROM_LOAD( "gn_15.bin", 0x000000, 0x10000, CRC(1b8ac9fb) SHA1(1e5ee2a565fa262f1e48c1088d84c6f42d84b4e3) )
ROM_LOAD( "gn_14.bin", 0x010000, 0x10000, CRC(e73fe668) SHA1(fa39fddd7448d3fc6b539506e33b951db205afa1) )
ROM_REGION( 0x20000, "gfx2", 0 )
ROM_LOAD( "gn_12.bin", 0x000000, 0x10000, CRC(c134a1e9) SHA1(8bace0f0169e61f1b7254393fa9cad6dca09c335) ) /* fg */
ROM_REGION( 0x20000, "fgtiles", 0 )
ROM_LOAD( "gn_12.bin", 0x000000, 0x10000, CRC(c134a1e9) SHA1(8bace0f0169e61f1b7254393fa9cad6dca09c335) )
ROM_LOAD( "gn_13.bin", 0x010000, 0x10000, CRC(1d3bec21) SHA1(305823c78cad9288f918178e1c24cb0459ba2a6e) )
ROM_REGION( 0x04000, "gfx3", 0 )
ROM_LOAD( "gn_10.bin", 0x000000, 0x04000, CRC(ae371b2d) SHA1(d5e03b085586ed2bf40713f432bcf12e07318226) ) /* txt */
ROM_REGION( 0x04000, "txttiles", 0 )
ROM_LOAD( "gn_10.bin", 0x000000, 0x04000, CRC(ae371b2d) SHA1(d5e03b085586ed2bf40713f432bcf12e07318226) )
ROM_REGION( 0x50000, "gfx4", 0 )
ROM_LOAD( "gn_06.bin", 0x000000, 0x10000, CRC(bdc65835) SHA1(53222fc3ec15e641289abb754657b0d59b88b66b) ) /* sprites */
ROM_REGION( 0x50000, "sprites", 0 )
ROM_LOAD( "gn_06.bin", 0x000000, 0x10000, CRC(bdc65835) SHA1(53222fc3ec15e641289abb754657b0d59b88b66b) )
ROM_CONTINUE( 0x040000, 0x10000 )
ROM_LOAD( "gn_07.bin", 0x010000, 0x10000, CRC(c2b8eafe) SHA1(a042a200efd4e7361e9ab516085c9fc8067e28b4) )
ROM_LOAD( "gn_08.bin", 0x020000, 0x10000, CRC(f7c73c18) SHA1(102700e2217bcd1532af56ee6a00ad608c8217db) )
ROM_LOAD( "gn_09.bin", 0x030000, 0x10000, CRC(a5e07c3b) SHA1(cdda02cd847330575612cb33d1bb38a5d50a3e6d) )
ROM_REGION( 0x08000, "bgrom", 0 ) /* background tilemaps */
ROM_REGION( 0x08000, "bgrom", 0 )
ROM_LOAD( "gn_11.bin", 0x00000, 0x08000, CRC(f0d0e605) SHA1(0c541e8e036573be1d99ecb71fdb4568ca8cc269) )
ROM_REGION( 0x20000, "ymsnd", 0 ) /* samples */
ROM_REGION( 0x20000, "ymsnd", 0 )
ROM_LOAD( "gn_04.bin", 0x00000, 0x10000, CRC(0ed9133b) SHA1(77f628e8ec28016efac2d906146865ca4ec54bd5) )
ROM_LOAD( "gn_03.bin", 0x10000, 0x10000, CRC(f1ba222c) SHA1(780c0bd0045bac1e1bb3209576383db90504fbf3) )
ROM_END
ROM_START( ginganina )
ROM_REGION( 0x20000, "maincpu", 0 ) /* main cpu */
ROM_REGION( 0x20000, "maincpu", 0 )
ROM_LOAD16_BYTE( "2.bin", 0x00000, 0x10000, CRC(6da1d8a3) SHA1(ea81f2934fa7901563e886f3d600edd08ec0ea24) )
ROM_LOAD16_BYTE( "1.bin", 0x00001, 0x10000, CRC(0bd32d59) SHA1(5ab2c0e4a1d9cafbd3448d981103508debd7ed96) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound cpu */
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "gn_05.bin", 0x00000, 0x10000, CRC(e76e10e7) SHA1(b16f10a1a01b7b04221c9bf1b0d157e936bc5fb5) )
ROM_REGION( 0x20000, "gfx1", 0 )
ROM_LOAD( "gn_15.bin", 0x000000, 0x10000, CRC(1b8ac9fb) SHA1(1e5ee2a565fa262f1e48c1088d84c6f42d84b4e3) ) /* bg */
ROM_REGION( 0x20000, "bgtiles", 0 )
ROM_LOAD( "gn_15.bin", 0x000000, 0x10000, CRC(1b8ac9fb) SHA1(1e5ee2a565fa262f1e48c1088d84c6f42d84b4e3) )
ROM_LOAD( "gn_14.bin", 0x010000, 0x10000, CRC(e73fe668) SHA1(fa39fddd7448d3fc6b539506e33b951db205afa1) )
ROM_REGION( 0x20000, "gfx2", 0 )
ROM_LOAD( "gn_12.bin", 0x000000, 0x10000, CRC(c134a1e9) SHA1(8bace0f0169e61f1b7254393fa9cad6dca09c335) ) /* fg */
ROM_REGION( 0x20000, "fgtiles", 0 )
ROM_LOAD( "gn_12.bin", 0x000000, 0x10000, CRC(c134a1e9) SHA1(8bace0f0169e61f1b7254393fa9cad6dca09c335) )
ROM_LOAD( "gn_13.bin", 0x010000, 0x10000, CRC(1d3bec21) SHA1(305823c78cad9288f918178e1c24cb0459ba2a6e) )
ROM_REGION( 0x04000, "gfx3", 0 )
ROM_LOAD( "10.bin", 0x000000, 0x04000, CRC(48a20745) SHA1(69855b0402feca4ba9632142e569c652ca05b9fa) ) /* txt */
ROM_REGION( 0x04000, "txttiles", 0 )
ROM_LOAD( "10.bin", 0x000000, 0x04000, CRC(48a20745) SHA1(69855b0402feca4ba9632142e569c652ca05b9fa) )
ROM_REGION( 0x50000, "gfx4", 0 )
ROM_LOAD( "gn_06.bin", 0x000000, 0x10000, CRC(bdc65835) SHA1(53222fc3ec15e641289abb754657b0d59b88b66b) ) /* sprites */
ROM_REGION( 0x50000, "sprites", 0 )
ROM_LOAD( "gn_06.bin", 0x000000, 0x10000, CRC(bdc65835) SHA1(53222fc3ec15e641289abb754657b0d59b88b66b) )
ROM_CONTINUE( 0x040000, 0x10000 )
ROM_LOAD( "gn_07.bin", 0x010000, 0x10000, CRC(c2b8eafe) SHA1(a042a200efd4e7361e9ab516085c9fc8067e28b4) )
ROM_LOAD( "gn_08.bin", 0x020000, 0x10000, CRC(f7c73c18) SHA1(102700e2217bcd1532af56ee6a00ad608c8217db) )
ROM_LOAD( "gn_09.bin", 0x030000, 0x10000, CRC(a5e07c3b) SHA1(cdda02cd847330575612cb33d1bb38a5d50a3e6d) )
ROM_REGION( 0x08000, "bgrom", 0 ) /* background tilemaps */
ROM_REGION( 0x08000, "bgrom", 0 )
ROM_LOAD( "gn_11.bin", 0x00000, 0x08000, CRC(f0d0e605) SHA1(0c541e8e036573be1d99ecb71fdb4568ca8cc269) )
ROM_REGION( 0x20000, "ymsnd", 0 ) /* samples */
ROM_REGION( 0x20000, "ymsnd", 0 )
ROM_LOAD( "gn_04.bin", 0x00000, 0x10000, CRC(0ed9133b) SHA1(77f628e8ec28016efac2d906146865ca4ec54bd5) )
ROM_LOAD( "gn_03.bin", 0x10000, 0x10000, CRC(f1ba222c) SHA1(780c0bd0045bac1e1bb3209576383db90504fbf3) )
ROM_END
@ -337,13 +663,15 @@ ROM_END
void ginganin_state::init_ginganin()
{
// pending full removal of this patch ...
/* main cpu patches */
/* main CPU patches */
// u16 *rom = (u16 *)memregion("maincpu")->base();
/* avoid writes to rom getting to the log */
/* avoid writes to ROM getting to the log */
// rom[0x408 / 2] = 0x6000;
// rom[0x40a / 2] = 0x001c;
}
} // anonymous namespace
GAME( 1987, ginganin, 0, ginganin, ginganin, ginganin_state, init_ginganin, ROT0, "Jaleco", "Ginga NinkyouDen (set 1)", MACHINE_SUPPORTS_SAVE )
GAME( 1987, ginganina, ginganin, ginganin, ginganin, ginganin_state, init_ginganin, ROT0, "Jaleco", "Ginga NinkyouDen (set 2)", MACHINE_SUPPORTS_SAVE )

View File

@ -1,81 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Luca Elia
/*************************************************************************
Ginga NinkyouDen
*************************************************************************/
#ifndef MAME_INCLUDES_GINGANIN_H
#define MAME_INCLUDES_GINGANIN_H
#pragma once
#include "machine/gen_latch.h"
#include "emupal.h"
#include "tilemap.h"
class ginganin_state : public driver_device
{
public:
ginganin_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_txtram(*this, "txtram"),
m_spriteram(*this, "spriteram"),
m_vregs(*this, "vregs"),
m_fgram(*this, "fgram"),
m_bgrom(*this, "bgrom"),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
m_soundlatch(*this, "soundlatch")
{ }
void ginganin(machine_config &config);
void init_ginganin();
private:
/* memory pointers */
required_shared_ptr<u16> m_txtram;
required_shared_ptr<u16> m_spriteram;
required_shared_ptr<u16> m_vregs;
required_shared_ptr<u16> m_fgram;
required_region_ptr<u8> m_bgrom;
/* video-related */
tilemap_t *m_bg_tilemap = nullptr;
tilemap_t *m_fg_tilemap = nullptr;
tilemap_t *m_tx_tilemap = nullptr;
int m_layers_ctrl = 0;
int m_flipscreen = 0;
#ifdef MAME_DEBUG
int m_posx = 0;
int m_posy = 0;
#endif
/* devices */
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_audiocpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
required_device<generic_latch_8_device> m_soundlatch;
void fgram_w(offs_t offset, u16 data, u16 mem_mask = ~0);
void txtram_w(offs_t offset, u16 data, u16 mem_mask = ~0);
void vregs_w(offs_t offset, u16 data, u16 mem_mask = ~0);
DECLARE_WRITE_LINE_MEMBER(ptm_irq);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
TILE_GET_INFO_MEMBER(get_fg_tile_info);
TILE_GET_INFO_MEMBER(get_txt_tile_info);
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_sprites(bitmap_ind16 &bitmap,const rectangle &cliprect);
void main_map(address_map &map);
void sound_map(address_map &map);
};
#endif // MAME_INCLUDES_GINGANIN_H

View File

@ -1,280 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Luca Elia
/**************************************************************************
Ginga NinkyouDen
(C) 1987 Jaleco
driver by Luca Elia (l.elia@tin.it)
Note: if MAME_DEBUG is defined, pressing Z with:
Q shows background
W shows foreground
E shows frontmost (text) layer
A shows sprites
Keys can be used togheter!
[Screen]
Visible Size: 256H x 240V
Dynamic Colors: 256 x 4
Color Space: 16R x 16G x 16B
[Scrolling layers]
Format (all layers): Offset: 0x400 0x000
Bit: fedc---- -------- Color
----ba98 76543210 Code
[Background]
Size: 8192 x 512 (static: stored in ROM)
Scrolling: X,Y (registers: $60006.w, $60004.w)
Tiles Size: 16 x 16
Tiles Number: $400
Colors: $300-$3ff
[Foreground]
Size: 4096 x 512
Scrolling: X,Y (registers: $60002.w, $60000.w)
Tiles Size: 16 x 16
Tiles Number: $400
Colors: $200-$2ff
[Frontmost]
Size: 256 x 256
Scrolling: -
Tiles Size: 8 x 8
Tiles Number: $200
Colors: $000-$0ff
[Sprites]
On Screen: 256
In ROM: $a00
Colors: $100-$1ff
Format: See Below
**************************************************************************/
#include "emu.h"
#include "ginganin.h"
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
/* Background - Resides in ROM */
#define BG_GFX (0)
#define BG_NX (16*32)
#define BG_NY (16*2)
TILE_GET_INFO_MEMBER(ginganin_state::get_bg_tile_info)
{
const u32 code = m_bgrom[2 * tile_index + 0] * 256 + m_bgrom[2 * tile_index + 1];
tileinfo.set(BG_GFX,
code,
code >> 12,
0);
}
/* Foreground - Resides in RAM */
#define FG_GFX (1)
#define FG_NX (16*16)
#define FG_NY (16*2)
TILE_GET_INFO_MEMBER(ginganin_state::get_fg_tile_info)
{
const u16 code = m_fgram[tile_index];
tileinfo.set(FG_GFX,
code,
code >> 12,
0);
}
void ginganin_state::fgram_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_fgram[offset]);
m_fg_tilemap->mark_tile_dirty(offset);
}
/* Frontmost (text) Layer - Resides in RAM */
#define TXT_GFX (2)
#define TXT_NX (32)
#define TXT_NY (32)
TILE_GET_INFO_MEMBER(ginganin_state::get_txt_tile_info)
{
const u16 code = m_txtram[tile_index];
tileinfo.set(TXT_GFX,
code,
code >> 12,
0);
}
void ginganin_state::txtram_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_txtram[offset]);
m_tx_tilemap->mark_tile_dirty(offset);
}
void ginganin_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(ginganin_state::get_bg_tile_info)), TILEMAP_SCAN_COLS, 16, 16, BG_NX, BG_NY);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(ginganin_state::get_fg_tile_info)), TILEMAP_SCAN_COLS, 16, 16, FG_NX, FG_NY);
m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(ginganin_state::get_txt_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, TXT_NX, TXT_NY);
m_fg_tilemap->set_transparent_pen(15);
m_tx_tilemap->set_transparent_pen(15);
}
void ginganin_state::vregs_w(offs_t offset, u16 data, u16 mem_mask)
{
COMBINE_DATA(&m_vregs[offset]);
data = m_vregs[offset];
switch (offset)
{
case 0:
m_fg_tilemap->set_scrolly(0, data);
break;
case 1:
m_fg_tilemap->set_scrollx(0, data);
break;
case 2:
m_bg_tilemap->set_scrolly(0, data);
break;
case 3:
m_bg_tilemap->set_scrollx(0, data);
break;
case 4:
m_layers_ctrl = data;
break;
/* case 5:
* break;
*/
case 6:
m_flipscreen = !(data & 1);
machine().tilemap().set_flip_all(m_flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
break;
case 7:
m_soundlatch->write(data);
m_audiocpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
break;
default:
logerror("CPU #0 PC %06X : Warning, videoreg %04X <- %04X\n", m_maincpu->pc(), offset, data);
}
}
/* --------------------------[ Sprites Format ]----------------------------
Offset: Values: Format:
0000.w y position fedc ba9- ---- ---- unused
---- ---8 ---- ---- subtract 256
---- ---- 7654 3210 position
0002.w x position See above
0004.w code f--- ---- ---- ---- y flip
-e-- ---- ---- ---- x flip
--dc ---- ---- ---- unused?
---- ba98 7654 3210 code
0006.w colour fedc ---- ---- ---- colour code
---- ba98 7654 3210 unused?
------------------------------------------------------------------------ */
void ginganin_state::draw_sprites(bitmap_ind16 &bitmap,const rectangle &cliprect)
{
for (int offs = 0; offs < (m_spriteram.bytes() >> 1); offs += 4)
{
int y = m_spriteram[offs + 0];
int x = m_spriteram[offs + 1];
const u32 code = m_spriteram[offs + 2];
const u16 attr = m_spriteram[offs + 3];
int flipx = code & 0x4000;
int flipy = code & 0x8000;
x = (x & 0xff) - (x & 0x100);
y = (y & 0xff) - (y & 0x100);
if (m_flipscreen)
{
x = 240 - x;
y = 240 - y;
flipx = !flipx;
flipy = !flipy;
}
m_gfxdecode->gfx(3)->transpen(bitmap,cliprect,
code & 0x3fff,
attr >> 12,
flipx, flipy,
x,y,15);
}
}
u32 ginganin_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int layers_ctrl1 = m_layers_ctrl;
#ifdef MAME_DEBUG
if (machine().input().code_pressed(KEYCODE_Z))
{
int msk = 0;
if (machine().input().code_pressed(KEYCODE_Q)) { msk |= 0xfff1;}
if (machine().input().code_pressed(KEYCODE_W)) { msk |= 0xfff2;}
if (machine().input().code_pressed(KEYCODE_E)) { msk |= 0xfff4;}
if (machine().input().code_pressed(KEYCODE_A)) { msk |= 0xfff8;}
if (msk != 0) layers_ctrl1 &= msk;
#define SETSCROLL \
m_bg_tilemap->set_scrollx(0, m_posx); \
m_bg_tilemap->set_scrolly(0, m_posy); \
m_fg_tilemap->set_scrollx(0, m_posx); \
m_fg_tilemap->set_scrolly(0, m_posy); \
popmessage("B>%04X:%04X F>%04X:%04X",m_posx%(BG_NX*16),m_posy%(BG_NY*16),m_posx%(FG_NX*16),m_posy%(FG_NY*16));
if (machine().input().code_pressed(KEYCODE_L)) { m_posx +=8; SETSCROLL }
if (machine().input().code_pressed(KEYCODE_J)) { m_posx -=8; SETSCROLL }
if (machine().input().code_pressed(KEYCODE_K)) { m_posy +=8; SETSCROLL }
if (machine().input().code_pressed(KEYCODE_I)) { m_posy -=8; SETSCROLL }
if (machine().input().code_pressed(KEYCODE_H)) { m_posx = m_posy = 0; SETSCROLL }
}
#endif
if (layers_ctrl1 & 1)
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
else
bitmap.fill(0, cliprect);
if (layers_ctrl1 & 2)
m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
if (layers_ctrl1 & 8)
draw_sprites(bitmap, cliprect);
if (layers_ctrl1 & 4)
m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders: Tomasz Slanina
/*
Moero!! Pro Yakyuu Homerun Kyousou - (c) 1988 Jaleco
Dynamic Shoot Kyousou - (c) 1988 Jaleco
@ -16,7 +17,7 @@
homerun, dynashot and ganjaja use an extra soundchip for playing voice/samples
Todo :
- Dump homerun and dynashot sample rom
- Dump homerun and dynashot sample ROM
- Improve controls/DIP switches
- Fix sprite glitches in ganjaja Hop Step & Jump
- Fix sample playing in ganjaja Saisho wa Goo. The words 'rock', 'paper', scissors' are not played?
@ -109,14 +110,237 @@ This version of Homerun is not dumped.
*/
#include "emu.h"
#include "homerun.h"
#include "cpu/z80/z80.h"
#include "machine/i8255.h"
#include "sound/samples.h"
#include "sound/upd7759.h"
#include "sound/ymopn.h"
#include "speaker.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "tilemap.h"
namespace {
class homerun_state : public driver_device
{
public:
homerun_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_videoram(*this, "videoram"),
m_spriteram(*this, "spriteram"),
m_d7756(*this, "d7756"),
m_samples(*this, "samples"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_mainbank(*this, "mainbank")
{ }
void ganjaja(machine_config &config);
void dynashot(machine_config &config);
void homerun(machine_config &config);
DECLARE_READ_LINE_MEMBER(sprite0_r);
DECLARE_READ_LINE_MEMBER(homerun_d7756_busy_r);
DECLARE_CUSTOM_INPUT_MEMBER(ganjaja_hopper_status_r);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
private:
required_device<cpu_device> m_maincpu;
required_shared_ptr<u8> m_videoram;
required_shared_ptr<u8> m_spriteram;
required_device<upd7756_device> m_d7756;
optional_device<samples_device> m_samples;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_memory_bank m_mainbank;
u8 m_control = 0;
u8 m_sample = 0;
tilemap_t *m_tilemap = nullptr;
u8 m_gfx_ctrl = 0;
u16 m_scrollx = 0;
u16 m_scrolly = 0;
void control_w(u8 data);
void d7756_sample_w(u8 data);
void videoram_w(offs_t offset, u8 data);
void scrollhi_w(u8 data);
void scrolly_w(u8 data);
void scrollx_w(u8 data);
static rgb_t homerun_RGB332(u32 raw);
TILE_GET_INFO_MEMBER(get_tile_info);
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void banking_w(u8 data);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
void io_map(address_map &map);
void mem_map(address_map &map);
};
// video
/**************************************************************************/
READ_LINE_MEMBER(homerun_state::sprite0_r)
{
// sprite-0 vs background collision status, similar to NES
return (m_screen->vpos() > (m_spriteram[0] - 16 + 1)) ? 1 : 0;
}
void homerun_state::scrollhi_w(u8 data)
{
// d0: scroll y high bit
// d1: scroll x high bit
// other bits: ?
m_scrolly = (m_scrolly & 0xff) | (data << 8 & 0x100);
m_scrollx = (m_scrollx & 0xff) | (data << 7 & 0x100);
}
void homerun_state::scrolly_w(u8 data)
{
m_scrolly = (m_scrolly & 0xff00) | data;
}
void homerun_state::scrollx_w(u8 data)
{
m_scrollx = (m_scrollx & 0xff00) | data;
}
void homerun_state::banking_w(u8 data)
{
u8 const old = m_gfx_ctrl;
if (old ^ data)
{
if ((old ^ data) & 3)
{
// games do mid-screen gfx bank switching
int vpos = m_screen->vpos();
m_screen->update_partial(vpos);
}
// d0-d1: gfx bank
// d2-d4: ?
// d5-d7: prg bank
m_gfx_ctrl = data;
if ((old ^ m_gfx_ctrl) & 1)
m_tilemap->mark_all_dirty();
if ((old ^ m_gfx_ctrl) >> 5 & 7)
m_mainbank->set_entry(m_gfx_ctrl >> 5 & 7);
}
}
void homerun_state::videoram_w(offs_t offset, u8 data)
{
m_videoram[offset] = data;
m_tilemap->mark_tile_dirty(offset & 0xfff);
}
rgb_t homerun_state::homerun_RGB332(u32 raw)
{
/* from PCB photo:
bit 7: 470 ohm resistor \
bit 6: 220 ohm resistor - --> 470 ohm resistor --> blue
bit 5: 470 ohm resistor \
bit 4: 220 ohm resistor - --> 470 ohm resistor --> green
bit 3: 1 kohm resistor /
bit 2: 470 ohm resistor \
bit 1: 220 ohm resistor - --> 470 ohm resistor --> red
bit 0: 1 kohm resistor /
*/
// let's implement it the old fashioned way until it's found out how exactly the resnet is hooked up
u8 bit0, bit1, bit2;
bit0 = (raw >> 0) & 0x01;
bit1 = (raw >> 1) & 0x01;
bit2 = (raw >> 2) & 0x01;
int r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
bit0 = (raw >> 3) & 0x01;
bit1 = (raw >> 4) & 0x01;
bit2 = (raw >> 5) & 0x01;
int g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
bit0 = 0;
bit1 = (raw >> 6) & 0x01;
bit2 = (raw >> 7) & 0x01;
int b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
return rgb_t(r, g, b);
}
/**************************************************************************/
TILE_GET_INFO_MEMBER(homerun_state::get_tile_info)
{
u32 const tileno = (m_videoram[tile_index]) | ((m_videoram[tile_index | 0x1000] & 0x38) << 5) | ((m_gfx_ctrl & 1) << 11);
u16 const palno = (m_videoram[tile_index | 0x1000] & 0x07);
tileinfo.set(0, tileno, palno, 0);
}
void homerun_state::video_start()
{
m_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(homerun_state::get_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
save_item(NAME(m_gfx_ctrl));
save_item(NAME(m_scrolly));
save_item(NAME(m_scrollx));
}
void homerun_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
for (int offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4)
{
if (m_spriteram[offs + 0] == 0)
continue;
int const sy = m_spriteram[offs + 0] - 16 + 1;
int const sx = m_spriteram[offs + 3];
u32 const code = (m_spriteram[offs + 1]) | ((m_spriteram[offs + 2] & 0x8) << 5) | ((m_gfx_ctrl & 3) << 9);
u32 const color = (m_spriteram[offs + 2] & 0x07) | 8;
bool const flipx = (m_spriteram[offs + 2] & 0x40) >> 6;
bool const flipy = (m_spriteram[offs + 2] & 0x80) >> 7;
if (sy >= 0)
{
m_gfxdecode->gfx(1)->transpen(bitmap, cliprect, code, color, flipx, flipy, sx, sy, 0);
// wraparound x
m_gfxdecode->gfx(1)->transpen(bitmap, cliprect, code, color, flipx, flipy, sx - 256 , sy, 0);
}
}
}
u32 homerun_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_tilemap->set_scrolly(0, m_scrolly);
m_tilemap->set_scrollx(0, m_scrollx);
m_tilemap->draw(screen, bitmap, cliprect, 0, 0);
draw_sprites(bitmap, cliprect);
return 0;
}
// machine
/***************************************************************************
@ -137,7 +361,7 @@ void homerun_state::control_w(u8 data)
}
if (m_samples != nullptr)
{
// play MAME sample if a dump of the internal rom does not exist
// play MAME sample if a dump of the internal ROM does not exist
if (data & 0x20 & ~m_control)
m_samples->stop(0);
@ -164,9 +388,9 @@ void homerun_state::d7756_sample_w(u8 data)
void homerun_state::mem_map(address_map &map)
{
map(0x0000, 0x3fff).rom();
map(0x4000, 0x7fff).bankr("mainbank");
map(0x8000, 0x9fff).ram().w(FUNC(homerun_state::videoram_w)).share("videoram");
map(0xa000, 0xa0ff).ram().share("spriteram");
map(0x4000, 0x7fff).bankr(m_mainbank);
map(0x8000, 0x9fff).ram().w(FUNC(homerun_state::videoram_w)).share(m_videoram);
map(0xa000, 0xa0ff).ram().share(m_spriteram);
map(0xb000, 0xb03f).ram().w(m_palette, FUNC(palette_device::write8)).share("palette");
map(0xc000, 0xdfff).ram();
}
@ -189,11 +413,6 @@ READ_LINE_MEMBER(homerun_state::homerun_d7756_busy_r)
return m_samples->playing(0) ? 0 : 1;
}
READ_LINE_MEMBER(homerun_state::ganjaja_d7756_busy_r)
{
return m_d7756->busy_r();
}
CUSTOM_INPUT_MEMBER(homerun_state::ganjaja_hopper_status_r)
{
// gives hopper error if not 0
@ -251,7 +470,7 @@ static INPUT_PORTS_START( homerun )
PORT_DIPSETTING( 0x80, DEF_STR( 1C_1C ) )
PORT_DIPSETTING( 0x00, DEF_STR( 1C_2C ) )
// The manuals shows the following DIPs but they don't appear to do anything
// The manual shows the following DIPs but they don't appear to do anything
// so this could be for a different version which is not dumped.
//..PORT_DIPNAME( 0x70, 0x70, "Difficulty" ) PORT_DIPLOCATION("DIPSW:5,6,7")
//..PORT_DIPSETTING( 0x70, "1" )
@ -313,7 +532,7 @@ static INPUT_PORTS_START( ganjaja )
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNKNOWN ) // ?
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(homerun_state, sprite0_r)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(homerun_state, ganjaja_d7756_busy_r)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("d7756", upd7756_device, busy_r)
PORT_BIT( 0x36, IP_ACTIVE_HIGH, IPT_UNKNOWN )
PORT_START("IN1")
@ -357,7 +576,7 @@ INPUT_PORTS_END
***************************************************************************/
// homerun samples, taken from the Famicom version of Moero!! Pro Yakyuu
// note that this is the complete rom contents; not all samples are used in this game
// note that this is the complete ROM contents; not all samples are used in this game
static const char *const homerun_sample_names[] =
{
"*homerun",
@ -405,8 +624,8 @@ static const gfx_layout spritelayout =
};
static GFXDECODE_START( gfx_homerun )
GFXDECODE_ENTRY( "gfx1", 0, gfxlayout, 0, 16 )
GFXDECODE_ENTRY( "gfx2", 0, spritelayout, 0, 16 )
GFXDECODE_ENTRY( "tiles", 0, gfxlayout, 0, 16 )
GFXDECODE_ENTRY( "sprites", 0, spritelayout, 0, 16 )
GFXDECODE_END
@ -435,7 +654,7 @@ void homerun_state::machine_reset()
void homerun_state::dynashot(machine_config &config)
{
/* basic machine hardware */
// basic machine hardware
Z80(config, m_maincpu, XTAL(20'000'000) / 4);
m_maincpu->set_addrmap(AS_PROGRAM, &homerun_state::mem_map);
m_maincpu->set_addrmap(AS_IO, &homerun_state::io_map);
@ -446,7 +665,7 @@ void homerun_state::dynashot(machine_config &config)
ppi.out_pb_callback().set(FUNC(homerun_state::scrolly_w));
ppi.out_pc_callback().set(FUNC(homerun_state::scrollx_w));
/* video hardware */
// video hardware
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_raw(XTAL(20'000'000) / 4, 328, 0, 256, 253, 0, 240);
m_screen->set_screen_update(FUNC(homerun_state::screen_update));
@ -455,23 +674,22 @@ void homerun_state::dynashot(machine_config &config)
GFXDECODE(config, m_gfxdecode, m_palette, gfx_homerun);
PALETTE(config, m_palette).set_format(1, &homerun_state::homerun_RGB332, 16 * 4);
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
ym2203_device &ymsnd(YM2203(config, "ymsnd", XTAL(20'000'000) / 8));
ymsnd.port_a_read_callback().set_ioport("DSW");
ymsnd.port_b_write_callback().set(FUNC(homerun_state::banking_w));
ymsnd.add_route(ALL_OUTPUTS, "mono", 0.50);
UPD7756(config, m_d7756);
m_d7756->add_route(ALL_OUTPUTS, "mono", 0.75);
}
void homerun_state::homerun(machine_config &config)
{
dynashot(config);
/* sound hardware */
UPD7756(config, m_d7756);
m_d7756->add_route(ALL_OUTPUTS, "mono", 0.75);
SAMPLES(config, m_samples);
m_samples->set_channels(1);
m_samples->set_samples_names(homerun_sample_names);
@ -482,12 +700,8 @@ void homerun_state::ganjaja(machine_config &config)
{
dynashot(config);
/* basic machine hardware */
// basic machine hardware
m_maincpu->set_periodic_int(FUNC(homerun_state::irq0_line_hold), attotime::from_hz(4 * 60)); // ?
/* sound hardware */
UPD7756(config, m_d7756);
m_d7756->add_route(ALL_OUTPUTS, "mono", 0.75);
}
@ -498,10 +712,10 @@ ROM_START( homerun )
ROM_REGION( 0x20000, "maincpu", 0 )
ROM_LOAD( "homerun.ic43", 0x00000, 0x20000, CRC(e759e476) SHA1(ad4f356ff26209033320a3e6353e4d4d9beb59c1) )
ROM_REGION( 0x10000, "gfx1", 0 )
ROM_REGION( 0x10000, "tiles", 0 )
ROM_LOAD( "homerun.ic60", 0x00000, 0x10000, CRC(69a720d1) SHA1(0f0a4877578f358e9e829ece8c31e23f01adcf83) )
ROM_REGION( 0x20000, "gfx2", 0 )
ROM_REGION( 0x20000, "sprites", 0 )
ROM_LOAD( "homerun.ic120", 0x00000, 0x20000, CRC(52f0709b) SHA1(19e675bcccadb774f60ec5929fc1fb5cf0d3f617) )
ROM_REGION( 0x08000, "d7756", ROMREGION_ERASE00 )
@ -512,10 +726,10 @@ ROM_START( nhomerun )
ROM_REGION( 0x20000, "maincpu", 0 )
ROM_LOAD( "1.ic43", 0x00000, 0x20000, CRC(aed96d6d) SHA1(5cb3932f4cfa3f6c0134ac20a1747c562db31a65) )
ROM_REGION( 0x10000, "gfx1", 0 )
ROM_REGION( 0x10000, "tiles", 0 )
ROM_LOAD( "3.ic60", 0x00000, 0x10000, CRC(69a720d1) SHA1(0f0a4877578f358e9e829ece8c31e23f01adcf83) )
ROM_REGION( 0x20000, "gfx2", 0 )
ROM_REGION( 0x20000, "sprites", 0 )
ROM_LOAD( "2.ic120", 0x00000, 0x20000, CRC(57e9b757) SHA1(8190d690721005407a5b06d13d64e70301d1e925) )
ROM_REGION( 0x08000, "d7756", ROMREGION_ERASE00 )
@ -526,10 +740,10 @@ ROM_START( dynashot )
ROM_REGION( 0x20000, "maincpu", 0 )
ROM_LOAD( "1.ic43", 0x00000, 0x20000, CRC(bf3c9586) SHA1(439effbda305f5fa265e5897c81dc1447e5d867d) )
ROM_REGION( 0x10000, "gfx1", 0 )
ROM_REGION( 0x10000, "tiles", 0 )
ROM_LOAD( "3.ic60", 0x00000, 0x10000, CRC(77d6a608) SHA1(a31ff343a5d4d6f20301c030ecc2e252149bcf9d) )
ROM_REGION( 0x20000, "gfx2", 0 )
ROM_REGION( 0x20000, "sprites", 0 )
ROM_LOAD( "2.ic120", 0x00000, 0x20000, CRC(bedf7b98) SHA1(cb6c5fcaf8df5f5c7636c3c8f79b9dda78e30c2e) )
ROM_REGION( 0x08000, "d7756", ROMREGION_ERASE00 )
@ -541,16 +755,18 @@ ROM_START( ganjaja )
ROM_REGION( 0x20000, "maincpu", 0 )
ROM_LOAD( "1.ic43", 0x00000, 0x20000, CRC(dad57543) SHA1(dbd8b5cee33756ee5e3c41bf84c0f7141d3466dc) )
ROM_REGION( 0x10000, "gfx1", 0 )
ROM_REGION( 0x10000, "tiles", 0 )
ROM_LOAD( "ic60", 0x00000, 0x10000, CRC(855f6b28) SHA1(386411e88cf9bed54fe2073f0828d579cb1d04ee) )
ROM_REGION( 0x20000, "gfx2", 0 )
ROM_REGION( 0x20000, "sprites", 0 )
ROM_LOAD( "2.ic120", 0x00000, 0x20000, CRC(e65d4d57) SHA1(2ec9e5bdaa94b808573313b6eca657d798004b53) )
ROM_REGION( 0x08000, "d7756", 0 )
ROM_LOAD( "d77p56cr.ic98", 0x00000, 0x08000, CRC(06a234ac) SHA1(b4ceff3f9f78551cf4a085642e162e33b266f067) ) /* D77P56CR OTP rom (One-Time Programmable, note the extra P) */
ROM_LOAD( "d77p56cr.ic98", 0x00000, 0x08000, CRC(06a234ac) SHA1(b4ceff3f9f78551cf4a085642e162e33b266f067) ) // D77P56CR OTP rom (One-Time Programmable, note the extra P)
ROM_END
} // anonymous namespace
// YEAR NAME PARENT MACHINE INPUT STATE INIT ROT COMPANY FULLNAME FLAGS
GAME( 1988, nhomerun, 0, homerun, homerun, homerun_state, empty_init, ROT0, "Jaleco", "NEW Moero!! Pro Yakyuu Homerun Kyousou", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) // same as below but harder?

View File

@ -1,79 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Tomasz Slanina
/*************************************************************************
Jaleco Moero Pro Yakyuu Homerun hardware
*************************************************************************/
#include "sound/upd7759.h"
#include "sound/samples.h"
#include "emupal.h"
#include "screen.h"
#include "tilemap.h"
class homerun_state : public driver_device
{
public:
homerun_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_videoram(*this, "videoram"),
m_spriteram(*this, "spriteram"),
m_d7756(*this, "d7756"),
m_samples(*this, "samples"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_mainbank(*this, "mainbank")
{ }
void ganjaja(machine_config &config);
void dynashot(machine_config &config);
void homerun(machine_config &config);
DECLARE_READ_LINE_MEMBER(sprite0_r);
DECLARE_READ_LINE_MEMBER(homerun_d7756_busy_r);
DECLARE_READ_LINE_MEMBER(ganjaja_d7756_busy_r);
DECLARE_CUSTOM_INPUT_MEMBER(ganjaja_hopper_status_r);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
private:
required_device<cpu_device> m_maincpu;
required_shared_ptr<u8> m_videoram;
required_shared_ptr<u8> m_spriteram;
optional_device<upd7756_device> m_d7756;
optional_device<samples_device> m_samples;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_memory_bank m_mainbank;
u8 m_control = 0;
u8 m_sample = 0;
tilemap_t *m_tilemap = nullptr;
int m_gfx_ctrl = 0;
int m_scrollx = 0;
int m_scrolly = 0;
void control_w(u8 data);
void d7756_sample_w(u8 data);
void videoram_w(offs_t offset, u8 data);
void scrollhi_w(u8 data);
void scrolly_w(u8 data);
void scrollx_w(u8 data);
static rgb_t homerun_RGB332(u32 raw);
TILE_GET_INFO_MEMBER(get_tile_info);
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void banking_w(u8 data);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
void io_map(address_map &map);
void mem_map(address_map &map);
};

View File

@ -1,157 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Tomasz Slanina
/*************************************************************************
Jaleco Moero Pro Yakyuu Homerun hardware
*************************************************************************/
#include "emu.h"
#include "homerun.h"
/**************************************************************************/
READ_LINE_MEMBER(homerun_state::sprite0_r)
{
// sprite-0 vs background collision status, similar to NES
return (m_screen->vpos() > (m_spriteram[0] - 16 + 1)) ? 1 : 0;
}
void homerun_state::scrollhi_w(u8 data)
{
// d0: scroll y high bit
// d1: scroll x high bit
// other bits: ?
m_scrolly = (m_scrolly & 0xff) | (data << 8 & 0x100);
m_scrollx = (m_scrollx & 0xff) | (data << 7 & 0x100);
}
void homerun_state::scrolly_w(u8 data)
{
m_scrolly = (m_scrolly & 0xff00) | data;
}
void homerun_state::scrollx_w(u8 data)
{
m_scrollx = (m_scrollx & 0xff00) | data;
}
void homerun_state::banking_w(u8 data)
{
u8 const old = m_gfx_ctrl;
if (old ^ data)
{
if ((old ^ data) & 3)
{
// games do mid-screen gfx bank switching
int vpos = m_screen->vpos();
m_screen->update_partial(vpos);
}
// d0-d1: gfx bank
// d2-d4: ?
// d5-d7: prg bank
m_gfx_ctrl = data;
if ((old ^ m_gfx_ctrl) & 1)
m_tilemap->mark_all_dirty();
if ((old ^ m_gfx_ctrl) >> 5 & 7)
m_mainbank->set_entry(m_gfx_ctrl >> 5 & 7);
}
}
void homerun_state::videoram_w(offs_t offset, u8 data)
{
m_videoram[offset] = data;
m_tilemap->mark_tile_dirty(offset & 0xfff);
}
rgb_t homerun_state::homerun_RGB332(u32 raw)
{
/* from PCB photo:
bit 7: 470 ohm resistor \
bit 6: 220 ohm resistor - --> 470 ohm resistor --> blue
bit 5: 470 ohm resistor \
bit 4: 220 ohm resistor - --> 470 ohm resistor --> green
bit 3: 1 kohm resistor /
bit 2: 470 ohm resistor \
bit 1: 220 ohm resistor - --> 470 ohm resistor --> red
bit 0: 1 kohm resistor /
*/
// let's implement it the old fashioned way until it's found out how exactly the resnet is hooked up
u8 bit0, bit1, bit2;
bit0 = (raw >> 0) & 0x01;
bit1 = (raw >> 1) & 0x01;
bit2 = (raw >> 2) & 0x01;
int r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
bit0 = (raw >> 3) & 0x01;
bit1 = (raw >> 4) & 0x01;
bit2 = (raw >> 5) & 0x01;
int g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
bit0 = 0;
bit1 = (raw >> 6) & 0x01;
bit2 = (raw >> 7) & 0x01;
int b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
return rgb_t(r, g, b);
}
/**************************************************************************/
TILE_GET_INFO_MEMBER(homerun_state::get_tile_info)
{
u32 const tileno = (m_videoram[tile_index]) | ((m_videoram[tile_index | 0x1000] & 0x38) << 5) | ((m_gfx_ctrl & 1) << 11);
u16 const palno = (m_videoram[tile_index | 0x1000] & 0x07);
tileinfo.set(0, tileno, palno, 0);
}
void homerun_state::video_start()
{
m_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(homerun_state::get_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
save_item(NAME(m_gfx_ctrl));
save_item(NAME(m_scrolly));
save_item(NAME(m_scrollx));
}
void homerun_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
for (int offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4)
{
if (m_spriteram[offs + 0] == 0)
continue;
int const sy = m_spriteram[offs + 0] - 16 + 1;
int const sx = m_spriteram[offs + 3];
u32 const code = (m_spriteram[offs + 1]) | ((m_spriteram[offs + 2] & 0x8) << 5) | ((m_gfx_ctrl & 3) << 9);
u32 const color = (m_spriteram[offs + 2] & 0x07) | 8;
bool const flipx = (m_spriteram[offs + 2] & 0x40) >> 6;
bool const flipy = (m_spriteram[offs + 2] & 0x80) >> 7;
if (sy >= 0)
{
m_gfxdecode->gfx(1)->transpen(bitmap, cliprect, code, color, flipx, flipy, sx, sy, 0);
// wraparound x
m_gfxdecode->gfx(1)->transpen(bitmap, cliprect, code, color, flipx, flipy, sx - 256 , sy, 0);
}
}
}
u32 homerun_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_tilemap->set_scrolly(0, m_scrolly);
m_tilemap->set_scrollx(0, m_scrollx);
m_tilemap->draw(screen, bitmap, cliprect, 0, 0);
draw_sprites(bitmap, cliprect);
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders: Uki
/*****************************************************************************
Momoko 120% (c) 1986 Jaleco
@ -12,18 +13,18 @@
Notes
Real machine has some bugs.(escalator bug, sprite garbage)
It is not emulation bug.
The real machine has some bugs(escalator bug, sprite garbage).
They are not emulation bugs.
Flipped screen looks wrong, but it is correct.
Note that the game-breaking escalator bug only happens on an 8-way joystick,
it's safe to assume that this game dedicated cpanel was 4-way.
it's safe to assume that this game dedicated control panel was 4-way.
Stephh's notes (based on the game Z80 code and some tests) :
- Accoding to the "initialisation" routine (code at 0x2a23),
the "Bonus Life" Dip Switches shall be coded that way :
the "Bonus Life" Dip Switches shall be coded this way :
PORT_DIPNAME( 0x03, 0x03, "1st Bonus Life" )
PORT_DIPSETTING( 0x01, "20k" )
@ -46,16 +47,385 @@ Stephh's notes (based on the game Z80 code and some tests) :
*****************************************************************************/
#include "emu.h"
#include "momoko.h"
#include "cpu/z80/z80.h"
#include "machine/gen_latch.h"
#include "machine/watchdog.h"
#include "sound/ymopn.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
namespace {
class momoko_state : public driver_device
{
public:
momoko_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_spriteram(*this, "spriteram"),
m_videoram(*this, "videoram"),
m_bg_scrolly(*this, "bg_scrolly"),
m_bg_scrollx(*this, "bg_scrollx"),
m_bg_gfx(*this, "bg_gfx"),
m_bg_map(*this, "bg_map"),
m_bg_col_map(*this, "bg_col_map"),
m_fg_map(*this, "fg_map"),
m_proms(*this, "proms"),
m_bgbank(*this, "bgbank"),
m_io_fake(*this, "FAKE"),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette")
{ }
void momoko(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
private:
// memory pointers
required_shared_ptr<u8> m_spriteram;
required_shared_ptr<u8> m_videoram;
required_shared_ptr<u8> m_bg_scrolly;
required_shared_ptr<u8> m_bg_scrollx;
required_region_ptr<u8> m_bg_gfx;
required_region_ptr<u8> m_bg_map;
required_region_ptr<u8> m_bg_col_map;
required_region_ptr<u8> m_fg_map;
required_region_ptr<u8> m_proms;
required_memory_bank m_bgbank;
required_ioport m_io_fake;
// devices
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
// video-related
u8 m_fg_scrollx = 0;
u8 m_fg_scrolly = 0;
u8 m_fg_select = 0;
u8 m_text_scrolly = 0;
u8 m_text_mode = 0;
u8 m_bg_select = 0;
u8 m_bg_priority = 0;
u8 m_bg_mask = 0;
u8 m_fg_mask = 0;
u8 m_flipscreen = 0;
void bg_read_bank_w(u8 data);
void fg_scrollx_w(u8 data);
void fg_scrolly_w(u8 data);
void fg_select_w(u8 data);
void text_scrolly_w(u8 data);
void text_mode_w(u8 data);
void bg_scrollx_w(offs_t offset, u8 data);
void bg_scrolly_w(offs_t offset, u8 data);
void bg_select_w(u8 data);
void bg_priority_w(u8 data);
void flipscreen_w(u8 data);
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_bg_pri(bitmap_ind16 &bitmap, int chr, int col, int flipx, int flipy, int x, int y, int pri);
void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int start, int end, int flip);
void draw_text_tilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int flip);
void draw_fg_romtilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int flip);
void draw_bg_romtilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int flip, bool high);
void main_map(address_map &map);
void sound_map(address_map &map);
};
// video
/*******************************************************************************
Video consists of
- Sprites
- 2x ROM based tilemaps (bg and fg) with priority over some sprites
- 1x RAM based tilemap (text layer) (no wrapping?)
TODO:
- update to use tilemap system?
- check if any of this is common Jaleco/NMK etc. hardware and use shared
devices if possible
*******************************************************************************/
void momoko_state::fg_scrollx_w(u8 data)
{
m_fg_scrollx = data;
}
void momoko_state::fg_scrolly_w(u8 data)
{
m_fg_scrolly = data;
}
void momoko_state::fg_select_w(u8 data)
{
m_fg_select = data & 0x0f;
m_fg_mask = data & 0x10;
}
void momoko_state::text_scrolly_w(u8 data)
{
m_text_scrolly = data;
}
void momoko_state::text_mode_w(u8 data)
{
m_text_mode = data;
}
void momoko_state::bg_scrollx_w(offs_t offset, u8 data)
{
m_bg_scrollx[offset] = data;
}
void momoko_state::bg_scrolly_w(offs_t offset, u8 data)
{
m_bg_scrolly[offset] = data;
}
void momoko_state::bg_select_w(u8 data)
{
m_bg_select = data & 0x0f;
m_bg_mask = data & 0x10;
}
void momoko_state::bg_priority_w(u8 data)
{
m_bg_priority = data & 0x01;
}
void momoko_state::flipscreen_w(u8 data)
{
m_flipscreen = data & 0x01;
}
/****************************************************************************/
void momoko_state::draw_bg_pri(bitmap_ind16 &bitmap, int chr, int col, int flipx, int flipy, int x, int y, int pri)
{
for (int sy = 0; sy < 8; sy++)
{
const u32 gfxadr = chr * 16 + sy * 2;
for (int xx = 0; xx < 2; xx++)
{
u8 d0 = m_bg_gfx[gfxadr + xx * 4096];
u8 d1 = m_bg_gfx[gfxadr + xx * 4096 + 1];
for (int sx = 0; sx < 4; sx++)
{
const u8 dot = (d0 & 0x08) | ((d0 & 0x80) >> 5) | ((d1 & 0x08) >> 2) | ((d1 & 0x80) >> 7);
const int px = (flipx == 0) ? (sx + xx * 4 + x) : (7 - sx - xx * 4 + x);
const int py = (flipy == 0) ? (sy + y) : (7 - sy + y);
if (dot >= pri)
bitmap.pix(py, px) = col * 16 + dot + 256;
d0 <<= 1;
d1 <<= 1;
}
}
}
}
void momoko_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int start, int end, int flip)
{
for (int offs = start; offs < end; offs += 4)
{
int px, py;
u32 chr = m_spriteram[offs + 1] | ((m_spriteram[offs + 2] & 0x60) << 3);
chr = ((chr & 0x380) << 1) | (chr & 0x7f);
const int col = m_spriteram[offs + 2] & 0x07;
const int fx = ((m_spriteram[offs + 2] & 0x10) >> 4) ^ flip;
const int fy = ((m_spriteram[offs + 2] & 0x08) >> 3) ^ flip; // ???
const int x = m_spriteram[offs + 3];
const int y = m_spriteram[offs + 0];
if (flip == 0)
{
px = x;
py = 239 - y;
}
else
{
px = 248 - x;
py = y + 1;
}
m_gfxdecode->gfx(3)->transpen(bitmap, cliprect,
chr,
col,
!fx, fy,
px, py, 0);
}
}
void momoko_state::draw_text_tilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int flip)
{
for (int y = 16; y < 240; y++)
{
for (int x = 0; x < 32; x++)
{
int px, py, col;
int sy = y;
if (m_text_mode == 0)
col = m_proms[(sy >> 3) + 0x100] & 0x0f;
else
{
if (m_proms[y] < 0x08)
sy += m_text_scrolly;
col = (m_proms[y] & 0x07) + 0x10;
}
const int dy = sy & 7;
if (flip == 0)
{
px = x * 8;
py = y;
}
else
{
px = 248 - x * 8;
py = 255 - y;
}
const int ramoffset = (sy >> 3) * 32 + x;
if (ramoffset < 0x400) // high score table, no wrapping?
m_gfxdecode->gfx(0)->transpen(bitmap, cliprect,
m_videoram[ramoffset] * 8 + dy,
col,
flip, 0,
px, py, 0);
}
}
}
void momoko_state::draw_fg_romtilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int flip)
{
const int dx = (7 - m_fg_scrollx) & 7;
const int dy = (7 - m_fg_scrolly) & 7;
const int rx = m_fg_scrollx >> 3;
const int ry = m_fg_scrolly >> 3;
for (int y = 0; y < 29; y++)
{
for (int x = 0; x < 32; x++)
{
int px, py;
const int radr = ((ry + y + 34) & 0x3f) * 0x20 + ((rx + x) & 0x1f) + (m_fg_select & 3) * 0x800;
const u32 chr = m_fg_map[radr];
if (flip == 0)
{
px = 8 * x + dx - 6;
py = 8 * y + dy + 9;
}
else
{
px = 248 - (8 * x + dx - 8);
py = 248 - (8 * y + dy + 9);
}
m_gfxdecode->gfx(2)->transpen(bitmap, cliprect,
chr,
0, // color
flip, flip, // flip
px, py, 0);
}
}
}
void momoko_state::draw_bg_romtilemap(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect, int flip, bool high)
{
const int dx = (7 - m_bg_scrollx[0]) & 7;
const int dy = (7 - m_bg_scrolly[0]) & 7;
const int rx = (m_bg_scrollx[0] + m_bg_scrollx[1] * 256) >> 3;
const int ry = (m_bg_scrolly[0] + m_bg_scrolly[1] * 256) >> 3;
for (int y = 0; y < 29; y++)
{
for (int x = 0; x < 32; x++)
{
int px, py;
const int radr = ((ry + y + 2) & 0x3ff) * 128 + ((rx + x) & 0x7f);
u32 chr = m_bg_map[radr];
int col = m_bg_col_map[chr + m_bg_select * 512 + m_bg_priority * 256];
chr = chr + m_bg_select * 512;
if (flip == 0)
{
px = 8 * x + dx - 6;
py = 8 * y + dy + 9;
}
else
{
px = 248 - (8 * x + dx - 8);
py = 248 - (8 * y + dy + 9);
}
if (!high)
{
m_gfxdecode->gfx(1)->opaque(bitmap, cliprect,
chr,
col,
flip, flip,
px, py);
}
else
{
const u8 pri = (col & 0x10) >> 1;
if (pri != 0)
{
col = col & 0x0f;
draw_bg_pri(bitmap, chr, col, flip, flip, px, py, pri);
}
}
}
}
}
/****************************************************************************/
u32 momoko_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
const int flip = m_flipscreen ^ (m_io_fake->read() & 0x01);
// draw BG layer - all tiles
if (m_bg_mask == 0)
draw_bg_romtilemap(screen, bitmap, cliprect, flip, false);
else
bitmap.fill(256, cliprect);
// draw sprites (momoko)
draw_sprites(screen, bitmap, cliprect, 0, 9 * 4, flip);
// draw BG layer - high priority tiles
if (m_bg_mask == 0)
draw_bg_romtilemap(screen, bitmap, cliprect, flip, true);
// draw sprites (others)
draw_sprites(screen, bitmap, cliprect, 9 * 4, m_spriteram.bytes(), flip);
// draw text layer
draw_text_tilemap(screen, bitmap, cliprect, flip);
// draw FG layer
if (m_fg_mask == 0)
draw_fg_romtilemap(screen, bitmap, cliprect, flip);
return 0;
}
// machine
void momoko_state::bg_read_bank_w(u8 data)
{
m_bgbank->set_entry(data & 0x1f);
@ -63,12 +433,12 @@ void momoko_state::bg_read_bank_w(u8 data)
/****************************************************************************/
void momoko_state::momoko_map(address_map &map)
void momoko_state::main_map(address_map &map)
{
map(0x0000, 0xbfff).rom();
map(0xc000, 0xcfff).ram();
map(0xd064, 0xd0ff).ram().share("spriteram");
map(0xd400, 0xd400).portr("IN0").nopw(); /* interrupt ack? */
map(0xd064, 0xd0ff).ram().share(m_spriteram);
map(0xd400, 0xd400).portr("IN0").nopw(); // interrupt ack?
map(0xd402, 0xd402).portr("IN1").w(FUNC(momoko_state::flipscreen_w));
map(0xd404, 0xd404).w("watchdog", FUNC(watchdog_timer_device::reset_w));
map(0xd406, 0xd406).portr("DSW0").w("soundlatch", FUNC(generic_latch_8_device::write));
@ -77,24 +447,24 @@ void momoko_state::momoko_map(address_map &map)
map(0xdc00, 0xdc00).w(FUNC(momoko_state::fg_scrolly_w));
map(0xdc01, 0xdc01).w(FUNC(momoko_state::fg_scrollx_w));
map(0xdc02, 0xdc02).w(FUNC(momoko_state::fg_select_w));
map(0xe000, 0xe3ff).ram().share("videoram");
map(0xe000, 0xe3ff).ram().share(m_videoram);
map(0xe800, 0xe800).w(FUNC(momoko_state::text_scrolly_w));
map(0xe801, 0xe801).w(FUNC(momoko_state::text_mode_w));
map(0xf000, 0xffff).bankr("bgbank");
map(0xf000, 0xf001).w(FUNC(momoko_state::bg_scrolly_w)).share("bg_scrolly");
map(0xf002, 0xf003).w(FUNC(momoko_state::bg_scrollx_w)).share("bg_scrollx");
map(0xf000, 0xffff).bankr(m_bgbank);
map(0xf000, 0xf001).w(FUNC(momoko_state::bg_scrolly_w)).share(m_bg_scrolly);
map(0xf002, 0xf003).w(FUNC(momoko_state::bg_scrollx_w)).share(m_bg_scrollx);
map(0xf004, 0xf004).w(FUNC(momoko_state::bg_read_bank_w));
map(0xf006, 0xf006).w(FUNC(momoko_state::bg_select_w));
map(0xf007, 0xf007).w(FUNC(momoko_state::bg_priority_w));
}
void momoko_state::momoko_sound_map(address_map &map)
void momoko_state::sound_map(address_map &map)
{
map(0x0000, 0x7fff).rom();
map(0x8000, 0x87ff).ram();
map(0x9000, 0x9000).nopw(); /* unknown */
map(0x9000, 0x9000).nopw(); // unknown
map(0xa000, 0xa001).rw("ym1", FUNC(ym2203_device::read), FUNC(ym2203_device::write));
map(0xb000, 0xb000).nopw(); /* unknown */
map(0xb000, 0xb000).nopw(); // unknown
map(0xc000, 0xc001).rw("ym2", FUNC(ym2203_device::read), FUNC(ym2203_device::write));
}
@ -145,13 +515,13 @@ static INPUT_PORTS_START( momoko )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_START("DSW1")
PORT_DIPNAME( 0x03, 0x03, DEF_STR( Bonus_Life ) ) /* see notes */
PORT_DIPNAME( 0x03, 0x03, DEF_STR( Bonus_Life ) ) // see notes
PORT_DIPSETTING( 0x01, "20k" )
PORT_DIPSETTING( 0x03, "30k" )
PORT_DIPSETTING( 0x02, "50k" )
PORT_DIPSETTING( 0x00, "100k" )
PORT_DIPUNUSED( 0x04, IP_ACTIVE_LOW ) /* see notes */
PORT_DIPUNUSED( 0x08, IP_ACTIVE_LOW ) /* see notes */
PORT_DIPUNUSED( 0x04, IP_ACTIVE_LOW ) // see notes
PORT_DIPUNUSED( 0x08, IP_ACTIVE_LOW ) // see notes
PORT_DIPNAME( 0x10, 0x00, DEF_STR( Cabinet ) )
PORT_DIPSETTING( 0x00, DEF_STR( Upright ) )
PORT_DIPSETTING( 0x10, DEF_STR( Cocktail ) )
@ -171,9 +541,9 @@ INPUT_PORTS_END
static const gfx_layout charlayout =
{
8,8, /* 8*8 characters */
256, /* 256 characters */
2, /* 2 bits per pixel */
8,8, // 8*8 characters
256, // 256 characters
2, // 2 bits per pixel
{4, 0},
{0, 1, 2, 3, 256*8*8+0, 256*8*8+1, 256*8*8+2, 256*8*8+3},
{8*0, 8*1, 8*2, 8*3, 8*4, 8*5, 8*6, 8*7},
@ -182,9 +552,9 @@ static const gfx_layout charlayout =
static const gfx_layout spritelayout =
{
8,16, /* 8*16 characters */
2048-128, /* 1024 sprites ( ccc 0ccccccc ) */
4, /* 4 bits per pixel */
8,16, // 8*16 characters
2048-128, // 1024 sprites ( ccc 0ccccccc )
4, // 4 bits per pixel
{12,8,4,0},
{0, 1, 2, 3, 4096*8+0, 4096*8+1, 4096*8+2, 4096*8+3},
{0, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16,
@ -194,9 +564,9 @@ static const gfx_layout spritelayout =
static const gfx_layout tilelayout =
{
8,8, /* 8*8 characters */
8192-256, /* 4096 tiles ( cccc0 cccccccc ) */
4, /* 4 bits per pixel */
8,8, // 8*8 characters
8192-256, // 4096 tiles ( cccc0 cccccccc )
4, // 4 bits per pixel
{4,0,12,8},
{0, 1, 2, 3, 4096*8+0, 4096*8+1, 4096*8+2, 4096*8+3},
{0, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16},
@ -205,9 +575,9 @@ static const gfx_layout tilelayout =
static const gfx_layout charlayout1 =
{
8,1, /* 8*1 characters */
256*8, /* 2048 characters */
2, /* 2 bits per pixel */
8,1, // 8*1 characters
256*8, // 2048 characters
2, // 2 bits per pixel
{4, 0},
{0, 1, 2, 3, 256*8*8+0, 256*8*8+1, 256*8*8+2, 256*8*8+3},
{8*0},
@ -215,10 +585,10 @@ static const gfx_layout charlayout1 =
};
static GFXDECODE_START( gfx_momoko )
GFXDECODE_ENTRY( "text", 0x0000, charlayout1, 0, 24 ) /* TEXT */
GFXDECODE_ENTRY( "bg_gfx", 0x0000, tilelayout, 256, 16 ) /* BG */
GFXDECODE_ENTRY( "fg_gfx", 0x0000, charlayout, 0, 1 ) /* FG */
GFXDECODE_ENTRY( "spr_gfx", 0x0000, spritelayout, 128, 8 ) /* sprite */
GFXDECODE_ENTRY( "text", 0x0000, charlayout1, 0, 24 )
GFXDECODE_ENTRY( "bg_gfx", 0x0000, tilelayout, 256, 16 )
GFXDECODE_ENTRY( "fg_gfx", 0x0000, charlayout, 0, 1 )
GFXDECODE_ENTRY( "spr_gfx", 0x0000, spritelayout, 128, 8 )
GFXDECODE_END
/****************************************************************************/
@ -255,20 +625,20 @@ void momoko_state::machine_reset()
void momoko_state::momoko(machine_config &config)
{
/* basic machine hardware */
Z80(config, m_maincpu, XTAL(10'000'000)/2); /* 5.0MHz */
m_maincpu->set_addrmap(AS_PROGRAM, &momoko_state::momoko_map);
// basic machine hardware
Z80(config, m_maincpu, XTAL(10'000'000) / 2); // 5.0MHz
m_maincpu->set_addrmap(AS_PROGRAM, &momoko_state::main_map);
m_maincpu->set_vblank_int("screen", FUNC(momoko_state::irq0_line_hold));
z80_device &audiocpu(Z80(config, "audiocpu", XTAL(10'000'000)/4)); /* 2.5MHz */
audiocpu.set_addrmap(AS_PROGRAM, &momoko_state::momoko_sound_map);
z80_device &audiocpu(Z80(config, "audiocpu", XTAL(10'000'000) / 4)); // 2.5MHz
audiocpu.set_addrmap(AS_PROGRAM, &momoko_state::sound_map);
WATCHDOG_TIMER(config, "watchdog");
/* video hardware */
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500) /* not accurate */);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); // not accurate
screen.set_size(32*8, 32*8);
screen.set_visarea(1*8, 31*8-1, 2*8, 29*8-1);
screen.set_screen_update(FUNC(momoko_state::screen_update));
@ -278,7 +648,7 @@ void momoko_state::momoko(machine_config &config)
PALETTE(config, m_palette).set_format(palette_device::xRGB_444, 512);
m_palette->set_endianness(ENDIANNESS_BIG);
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
GENERIC_LATCH_8(config, "soundlatch");
@ -300,128 +670,131 @@ void momoko_state::momoko(machine_config &config)
/****************************************************************************/
ROM_START( momoko )
ROM_REGION( 0x10000, "maincpu", 0 ) /* main CPU */
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_LOAD( "momoko03.m6", 0x0000, 0x8000, CRC(386e26ed) SHA1(ad746ed1b87bafc5b4df9a28aade58cf894f4e7b) ) // age progression text in Japanese
ROM_LOAD( "momoko02.m5", 0x8000, 0x4000, CRC(4255e351) SHA1(27a0e8d8aea223d2128139582e3b66106f3608ef) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound CPU */
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "momoko01.u4", 0x0000, 0x8000, CRC(e8a6673c) SHA1(f8984b063929305c9058801202405e6d45254b5b) )
ROM_REGION( 0x2000, "text", 0 ) /* text */
ROM_REGION( 0x2000, "text", 0 )
ROM_LOAD( "momoko13.u4", 0x0000, 0x2000, CRC(2745cf5a) SHA1(3db7c6319cac63df1620ef25508c5c45eaa4b141) ) // On the FP-8631 PCB
ROM_REGION( 0x2000, "fg_gfx", 0 ) /* FG */
ROM_REGION( 0x2000, "fg_gfx", 0 )
ROM_LOAD( "momoko14.p2", 0x0000, 0x2000, CRC(cfccca05) SHA1(4ecff488a37ac76ecb9ecf8980bea30dcc9c9951) )
ROM_REGION( 0x10000, "spr_gfx", 0 ) /* sprite */
ROM_REGION( 0x10000, "spr_gfx", 0 )
ROM_LOAD16_BYTE( "momoko16.e5", 0x0000, 0x8000, CRC(fc6876fc) SHA1(b2d06bc01ef9f4db9bf8902d67f31ccbb0fea61a) ) // On the FP-8631 PCB
ROM_LOAD16_BYTE( "momoko17.e6", 0x0001, 0x8000, CRC(45dc0247) SHA1(1b2bd4197ab7d237966e037c249b5bd623646c0b) ) // On the FP-8631 PCB
ROM_REGION( 0x20000, "bg_gfx", 0 ) /* BG */
ROM_REGION( 0x20000, "bg_gfx", 0 )
ROM_LOAD16_BYTE( "momoko09.e8", 0x00000, 0x8000, CRC(9f5847c7) SHA1(6bc9a00622d8a23446294a8d5d467375c5719125) )
ROM_LOAD16_BYTE( "momoko11.c8", 0x00001, 0x8000, CRC(9c9fbd43) SHA1(7adfd7ea3dd6745c14e719883f1a86e0a3b3c0ff) )
ROM_LOAD16_BYTE( "momoko10.d8", 0x10000, 0x8000, CRC(ae17e74b) SHA1(f52657ea6b6ac518b70fd7b811d9699da27f67d9) )
ROM_LOAD16_BYTE( "momoko12.a8", 0x10001, 0x8000, CRC(1e29c9c4) SHA1(d78f102cefc9852b529dd317a76c7003ec2ad3d5) )
ROM_REGION( 0x20000, "bg_map", 0 ) /* BG map */
ROM_REGION( 0x20000, "bg_map", 0 )
ROM_LOAD( "momoko04.r8", 0x0000, 0x8000, CRC(3ab3c2c3) SHA1(d4a0d7f83bf64769e90a2c264c6114ac308cb8b5) )
ROM_LOAD( "momoko05.p8", 0x8000, 0x8000, CRC(757cdd2b) SHA1(3471b42dc6458a18894dbd0638f4fe43c86dd70d) )
ROM_LOAD( "momoko06.n8", 0x10000, 0x8000, CRC(20cacf8b) SHA1(e2b39abfc960e1c472e2bcf0cf06825c39941c03) )
ROM_LOAD( "momoko07.l8", 0x18000, 0x8000, CRC(b94b38db) SHA1(9c9e45bbeca7b6b8b0051b144fb31fceaf5d6906) )
ROM_REGION( 0x2000, "bg_col_map", 0 ) /* BG color/priority table */
ROM_REGION( 0x2000, "bg_col_map", 0 )
ROM_LOAD( "momoko08.h8", 0x0000, 0x2000, CRC(69b41702) SHA1(21b33b243dd6eaec8d41d9fd4d9e7faf2bd7f4d2) )
ROM_REGION( 0x4000, "fg_map", 0 ) /* FG map */
ROM_REGION( 0x4000, "fg_map", 0 )
ROM_LOAD( "momoko15.k2", 0x0000, 0x4000, CRC(8028f806) SHA1(c7450d48803082f64af67fe752b6f49b71b6ff48) ) // On the FP-8631 PCB
ROM_REGION( 0x0120, "proms", 0 ) /* TEXT color */
ROM_REGION( 0x0120, "proms", 0 ) // text color
ROM_LOAD( "momoko-c.bin", 0x0000, 0x0100, CRC(f35ccae0) SHA1(60b99dd3c96637dacba7e96a143b1a2d6ffd28b9) )
ROM_LOAD( "momoko-b.bin", 0x0100, 0x0020, CRC(427b0e5c) SHA1(aa2797b899571527cc96013fd3420b841954ee67) )
ROM_END
ROM_START( momokoe )
ROM_REGION( 0x10000, "maincpu", 0 ) /* main CPU */
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_LOAD( "3.m6", 0x0000, 0x8000, CRC(84053a7d) SHA1(6e8fb22bb48954f4fed2530991ebe5b872c9c089) ) // age progression text in English
ROM_LOAD( "2.m5", 0x8000, 0x4000, CRC(98ad397b) SHA1(b7ae218d0d397b1e258ec6d1f836cb998f984092) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound CPU */
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "momoko01.u4", 0x0000, 0x8000, CRC(e8a6673c) SHA1(f8984b063929305c9058801202405e6d45254b5b) )
ROM_REGION( 0x2000, "text", 0 ) /* text */
ROM_REGION( 0x2000, "text", 0 )
ROM_LOAD( "momoko13.u4", 0x0000, 0x2000, CRC(2745cf5a) SHA1(3db7c6319cac63df1620ef25508c5c45eaa4b141) ) // On the FP-8631 PCB
ROM_REGION( 0x2000, "fg_gfx", 0 ) /* FG */
ROM_REGION( 0x2000, "fg_gfx", 0 )
ROM_LOAD( "momoko14.p2", 0x0000, 0x2000, CRC(cfccca05) SHA1(4ecff488a37ac76ecb9ecf8980bea30dcc9c9951) )
ROM_REGION( 0x10000, "spr_gfx", 0 ) /* sprite */
ROM_REGION( 0x10000, "spr_gfx", 0 )
ROM_LOAD16_BYTE( "momoko16.e5", 0x0000, 0x8000, CRC(fc6876fc) SHA1(b2d06bc01ef9f4db9bf8902d67f31ccbb0fea61a) ) // On the FP-8631 PCB
ROM_LOAD16_BYTE( "momoko17.e6", 0x0001, 0x8000, CRC(45dc0247) SHA1(1b2bd4197ab7d237966e037c249b5bd623646c0b) ) // On the FP-8631 PCB
ROM_REGION( 0x20000, "bg_gfx", 0 ) /* BG */
ROM_REGION( 0x20000, "bg_gfx", 0 )
ROM_LOAD16_BYTE( "momoko09.e8", 0x00000, 0x8000, CRC(9f5847c7) SHA1(6bc9a00622d8a23446294a8d5d467375c5719125) )
ROM_LOAD16_BYTE( "momoko11.c8", 0x00001, 0x8000, CRC(9c9fbd43) SHA1(7adfd7ea3dd6745c14e719883f1a86e0a3b3c0ff) )
ROM_LOAD16_BYTE( "momoko10.d8", 0x10000, 0x8000, CRC(ae17e74b) SHA1(f52657ea6b6ac518b70fd7b811d9699da27f67d9) )
ROM_LOAD16_BYTE( "momoko12.a8", 0x10001, 0x8000, CRC(1e29c9c4) SHA1(d78f102cefc9852b529dd317a76c7003ec2ad3d5) )
ROM_REGION( 0x20000, "bg_map", 0 ) /* BG map */
ROM_REGION( 0x20000, "bg_map", 0 )
ROM_LOAD( "momoko04.r8", 0x0000, 0x8000, CRC(3ab3c2c3) SHA1(d4a0d7f83bf64769e90a2c264c6114ac308cb8b5) )
ROM_LOAD( "momoko05.p8", 0x8000, 0x8000, CRC(757cdd2b) SHA1(3471b42dc6458a18894dbd0638f4fe43c86dd70d) )
ROM_LOAD( "momoko06.n8", 0x10000, 0x8000, CRC(20cacf8b) SHA1(e2b39abfc960e1c472e2bcf0cf06825c39941c03) )
ROM_LOAD( "momoko07.l8", 0x18000, 0x8000, CRC(b94b38db) SHA1(9c9e45bbeca7b6b8b0051b144fb31fceaf5d6906) )
ROM_REGION( 0x2000, "bg_col_map", 0 ) /* BG color/priority table */
ROM_REGION( 0x2000, "bg_col_map", 0 )
ROM_LOAD( "momoko08.h8", 0x0000, 0x2000, CRC(69b41702) SHA1(21b33b243dd6eaec8d41d9fd4d9e7faf2bd7f4d2) )
ROM_REGION( 0x4000, "fg_map", 0 ) /* FG map */
ROM_REGION( 0x4000, "fg_map", 0 )
ROM_LOAD( "momoko15.k2", 0x0000, 0x4000, CRC(8028f806) SHA1(c7450d48803082f64af67fe752b6f49b71b6ff48) ) // On the FP-8631 PCB
ROM_REGION( 0x0120, "proms", 0 ) /* TEXT color */
ROM_REGION( 0x0120, "proms", 0 ) // text color
ROM_LOAD( "momoko-c.bin", 0x0000, 0x0100, CRC(f35ccae0) SHA1(60b99dd3c96637dacba7e96a143b1a2d6ffd28b9) )
ROM_LOAD( "momoko-b.bin", 0x0100, 0x0020, CRC(427b0e5c) SHA1(aa2797b899571527cc96013fd3420b841954ee67) )
ROM_END
ROM_START( momokob ) // bootleg board, almost exact copy of an original one
ROM_REGION( 0x10000, "maincpu", 0 ) /* main CPU */
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_LOAD( "3.bin", 0x0000, 0x8000, CRC(a18d7e78) SHA1(5d2dd498be3e22b5e8fc5ffe17e1ef463c1e9a02) ) // age progression text in Engrish, title screen in English
ROM_LOAD( "2.bin", 0x8000, 0x4000, CRC(2dcf50ed) SHA1(6d02cb86fce031859bc0a5a26ecf7a8c8b89dea3) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound CPU */
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "momoko01.u4", 0x0000, 0x8000, CRC(e8a6673c) SHA1(f8984b063929305c9058801202405e6d45254b5b) )
ROM_REGION( 0x2000, "text", 0 ) /* text */
ROM_REGION( 0x2000, "text", 0 )
ROM_LOAD( "momoko13.u4", 0x0000, 0x2000, CRC(2745cf5a) SHA1(3db7c6319cac63df1620ef25508c5c45eaa4b141) )
ROM_REGION( 0x2000, "fg_gfx", 0 ) /* FG */
ROM_REGION( 0x2000, "fg_gfx", 0 )
ROM_LOAD( "momoko14.p2", 0x0000, 0x2000, CRC(cfccca05) SHA1(4ecff488a37ac76ecb9ecf8980bea30dcc9c9951) )
ROM_REGION( 0x10000, "spr_gfx", 0 ) /* sprite */
ROM_REGION( 0x10000, "spr_gfx", 0 )
ROM_LOAD16_BYTE( "16.bin", 0x0000, 0x8000, CRC(49de49a1) SHA1(b4954286cba50332d4366a8160e9fbfd574c60ed) )
ROM_LOAD16_BYTE( "17.bin", 0x0001, 0x8000, CRC(f06a3d1a) SHA1(f377ffad958fdc9cff2baee70ce4ba9080b5fe0d) )
ROM_REGION( 0x20000, "bg_gfx", 0 ) /* BG */
ROM_REGION( 0x20000, "bg_gfx", 0 )
ROM_LOAD16_BYTE( "momoko09.e8", 0x00000, 0x8000, CRC(9f5847c7) SHA1(6bc9a00622d8a23446294a8d5d467375c5719125) )
ROM_LOAD16_BYTE( "momoko11.c8", 0x00001, 0x8000, CRC(9c9fbd43) SHA1(7adfd7ea3dd6745c14e719883f1a86e0a3b3c0ff) )
ROM_LOAD16_BYTE( "10.bin", 0x10000, 0x8000, CRC(68b9156d) SHA1(e157434d7ee33837ba35e720d221bf1eb21b7020) )
ROM_LOAD16_BYTE( "12.bin", 0x10001, 0x8000, CRC(c32f5e19) SHA1(488da565e20bf002ff3dffca1efedbdf29e6e559) )
ROM_REGION( 0x20000, "bg_map", 0 ) /* BG map */
ROM_REGION( 0x20000, "bg_map", 0 )
ROM_LOAD( "4.bin", 0x0000, 0x8000, CRC(1f0226d5) SHA1(6411e85c51e23dfe6c643692987dc7eeef37538f) )
ROM_LOAD( "momoko05.p8", 0x8000, 0x8000, CRC(757cdd2b) SHA1(3471b42dc6458a18894dbd0638f4fe43c86dd70d) )
ROM_LOAD( "momoko06.n8", 0x10000, 0x8000, CRC(20cacf8b) SHA1(e2b39abfc960e1c472e2bcf0cf06825c39941c03) )
ROM_LOAD( "momoko07.l8", 0x18000, 0x8000, CRC(b94b38db) SHA1(9c9e45bbeca7b6b8b0051b144fb31fceaf5d6906) )
ROM_REGION( 0x2000, "bg_col_map", 0 ) /* BG color/priority table */
ROM_REGION( 0x2000, "bg_col_map", 0 )
ROM_LOAD( "momoko08.h8", 0x0000, 0x2000, CRC(69b41702) SHA1(21b33b243dd6eaec8d41d9fd4d9e7faf2bd7f4d2) )
ROM_REGION( 0x4000, "fg_map", 0 ) /* FG map */
ROM_REGION( 0x4000, "fg_map", 0 )
ROM_LOAD( "momoko15.k2", 0x0000, 0x4000, CRC(8028f806) SHA1(c7450d48803082f64af67fe752b6f49b71b6ff48) )
ROM_REGION( 0x0120, "proms", 0 ) /* TEXT color */
ROM_REGION( 0x0120, "proms", 0 ) // text color
ROM_LOAD( "momoko-c.bin", 0x0000, 0x0100, CRC(f35ccae0) SHA1(60b99dd3c96637dacba7e96a143b1a2d6ffd28b9) )
ROM_LOAD( "momoko-b.bin", 0x0100, 0x0020, CRC(427b0e5c) SHA1(aa2797b899571527cc96013fd3420b841954ee67) )
ROM_END
} // anonymous namespace
GAME( 1986, momoko, 0, momoko, momoko, momoko_state, empty_init, ROT0, "Jaleco", "Momoko 120% (Japanese text)", MACHINE_SUPPORTS_SAVE )
GAME( 1986, momokoe, momoko, momoko, momoko, momoko_state, empty_init, ROT0, "Jaleco", "Momoko 120% (English text)", MACHINE_SUPPORTS_SAVE )
GAME( 1986, momokob, momoko, momoko, momoko, momoko_state, empty_init, ROT0, "bootleg", "Momoko 120% (bootleg)", MACHINE_SUPPORTS_SAVE )

View File

@ -1,89 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Uki
/*************************************************************************
Momoko 120%
*************************************************************************/
#ifndef MAME_INCLUDES_MOMOKO_H
#define MAME_INCLUDES_MOMOKO_H
#pragma once
#include "emupal.h"
class momoko_state : public driver_device
{
public:
momoko_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_spriteram(*this, "spriteram"),
m_videoram(*this, "videoram"),
m_bg_scrolly(*this, "bg_scrolly"),
m_bg_scrollx(*this, "bg_scrollx"),
m_bg_gfx(*this, "bg_gfx"),
m_bg_map(*this, "bg_map"),
m_bg_col_map(*this, "bg_col_map"),
m_fg_map(*this, "fg_map"),
m_proms(*this, "proms"),
m_bgbank(*this, "bgbank"),
m_io_fake(*this, "FAKE"),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette")
{ }
void momoko(machine_config &config);
private:
/* memory pointers */
required_shared_ptr<u8> m_spriteram;
required_shared_ptr<u8> m_videoram;
required_shared_ptr<u8> m_bg_scrolly;
required_shared_ptr<u8> m_bg_scrollx;
required_region_ptr<u8> m_bg_gfx;
required_region_ptr<u8> m_bg_map;
required_region_ptr<u8> m_bg_col_map;
required_region_ptr<u8> m_fg_map;
required_region_ptr<u8> m_proms;
required_memory_bank m_bgbank;
required_ioport m_io_fake;
/* video-related */
u8 m_fg_scrollx = 0;
u8 m_fg_scrolly = 0;
u8 m_fg_select = 0;
u8 m_text_scrolly = 0;
u8 m_text_mode = 0;
u8 m_bg_select = 0;
u8 m_bg_priority = 0;
u8 m_bg_mask = 0;
u8 m_fg_mask = 0;
u8 m_flipscreen = 0;
void bg_read_bank_w(u8 data);
void fg_scrollx_w(u8 data);
void fg_scrolly_w(u8 data);
void fg_select_w(u8 data);
void text_scrolly_w(u8 data);
void text_mode_w(u8 data);
void bg_scrollx_w(offs_t offset, u8 data);
void bg_scrolly_w(offs_t offset, u8 data);
void bg_select_w(u8 data);
void bg_priority_w(u8 data);
void flipscreen_w(u8 data);
virtual void machine_start() override;
virtual void machine_reset() override;
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_bg_pri(bitmap_ind16 &bitmap, int chr, int col, int flipx, int flipy, int x, int y, int pri);
void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int start, int end, int flip);
void draw_text_tilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int flip);
void draw_fg_romtilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int flip);
void draw_bg_romtilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int flip, bool high);
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
void momoko_map(address_map &map);
void momoko_sound_map(address_map &map);
};
#endif // MAME_INCLUDES_MOMOKO_H

View File

@ -1,289 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Uki
/*******************************************************************************
Momoko 120% (c) 1986 Jaleco
Video hardware driver by Uki 02/Mar/2001
Video consists of
- Sprites
- 2x ROM based tilemaps (bg and fg) with priority over some sprites
- 1x RAM based tilemap (text layer) (no wrapping?)
TODO:
- update to use tilemap system?
- check if any of this is common Jaleco/NMK etc. hardware and use shared
devices if possible
*******************************************************************************/
#include "emu.h"
#include "momoko.h"
void momoko_state::fg_scrollx_w(u8 data)
{
m_fg_scrollx = data;
}
void momoko_state::fg_scrolly_w(u8 data)
{
m_fg_scrolly = data;
}
void momoko_state::fg_select_w(u8 data)
{
m_fg_select = data & 0x0f;
m_fg_mask = data & 0x10;
}
void momoko_state::text_scrolly_w(u8 data)
{
m_text_scrolly = data;
}
void momoko_state::text_mode_w(u8 data)
{
m_text_mode = data;
}
void momoko_state::bg_scrollx_w(offs_t offset, u8 data)
{
m_bg_scrollx[offset] = data;
}
void momoko_state::bg_scrolly_w(offs_t offset, u8 data)
{
m_bg_scrolly[offset] = data;
}
void momoko_state::bg_select_w(u8 data)
{
m_bg_select = data & 0x0f;
m_bg_mask = data & 0x10;
}
void momoko_state::bg_priority_w(u8 data)
{
m_bg_priority = data & 0x01;
}
void momoko_state::flipscreen_w(u8 data)
{
m_flipscreen = data & 0x01;
}
/****************************************************************************/
void momoko_state::draw_bg_pri(bitmap_ind16 &bitmap, int chr, int col, int flipx, int flipy, int x, int y, int pri)
{
for (int sy = 0; sy < 8; sy++)
{
const u32 gfxadr = chr * 16 + sy * 2;
for (int xx = 0; xx < 2; xx++)
{
u8 d0 = m_bg_gfx[gfxadr + xx * 4096];
u8 d1 = m_bg_gfx[gfxadr + xx * 4096 + 1];
for (int sx = 0; sx < 4; sx++)
{
const u8 dot = (d0 & 0x08) | ((d0 & 0x80) >> 5) | ((d1 & 0x08) >> 2) | ((d1 & 0x80) >> 7);
const int px = (flipx == 0) ? (sx + xx * 4 + x) : (7 - sx - xx * 4 + x);
const int py = (flipy == 0) ? (sy + y) : (7 - sy + y);
if (dot >= pri)
bitmap.pix(py, px) = col * 16 + dot + 256;
d0 <<= 1;
d1 <<= 1;
}
}
}
}
void momoko_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int start, int end, int flip)
{
for (int offs = start; offs < end; offs += 4)
{
int px, py;
u32 chr = m_spriteram[offs + 1] | ((m_spriteram[offs + 2] & 0x60) << 3);
chr = ((chr & 0x380) << 1) | (chr & 0x7f);
int col = m_spriteram[offs + 2] & 0x07;
const int fx = ((m_spriteram[offs + 2] & 0x10) >> 4) ^ flip;
const int fy = ((m_spriteram[offs + 2] & 0x08) >> 3) ^ flip; /* ??? */
int x = m_spriteram[offs + 3];
int y = m_spriteram[offs + 0];
if (flip == 0)
{
px = x;
py = 239 - y;
}
else
{
px = 248 - x;
py = y + 1;
}
m_gfxdecode->gfx(3)->transpen(bitmap, cliprect,
chr,
col,
!fx, fy,
px, py, 0);
}
}
void momoko_state::draw_text_tilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int flip)
{
for (int y = 16; y < 240; y++)
{
for (int x = 0; x < 32; x++)
{
int px, py, col;
int sy = y;
if (m_text_mode == 0)
col = m_proms[(sy >> 3) + 0x100] & 0x0f;
else
{
if (m_proms[y] < 0x08)
sy += m_text_scrolly;
col = (m_proms[y] & 0x07) + 0x10;
}
int dy = sy & 7;
if (flip == 0)
{
px = x * 8;
py = y;
}
else
{
px = 248 - x * 8;
py = 255 - y;
}
int ramoffset = (sy >> 3) * 32 + x;
if (ramoffset < 0x400) // high score table, no wrapping?
m_gfxdecode->gfx(0)->transpen(bitmap, cliprect,
m_videoram[ramoffset] * 8 + dy,
col,
flip, 0,
px, py, 0);
}
}
}
void momoko_state::draw_fg_romtilemap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int flip)
{
int dx = (7 - m_fg_scrollx) & 7;
int dy = (7 - m_fg_scrolly) & 7;
int rx = m_fg_scrollx >> 3;
int ry = m_fg_scrolly >> 3;
for (int y = 0; y < 29; y++)
{
for (int x = 0; x < 32; x++)
{
int px, py;
const int radr = ((ry + y + 34) & 0x3f) * 0x20 + ((rx + x) & 0x1f) + (m_fg_select & 3) * 0x800;
const u32 chr = m_fg_map[radr];
if (flip == 0)
{
px = 8 * x + dx - 6;
py = 8 * y + dy + 9;
}
else
{
px = 248 - (8 * x + dx - 8);
py = 248 - (8 * y + dy + 9);
}
m_gfxdecode->gfx(2)->transpen(bitmap,cliprect,
chr,
0, /* color */
flip,flip, /* flip */
px,py,0);
}
}
}
void momoko_state::draw_bg_romtilemap(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect, int flip, bool high)
{
int dx = (7 - m_bg_scrollx[0]) & 7;
int dy = (7 - m_bg_scrolly[0]) & 7;
int rx = (m_bg_scrollx[0] + m_bg_scrollx[1] * 256) >> 3;
int ry = (m_bg_scrolly[0] + m_bg_scrolly[1] * 256) >> 3;
for (int y = 0; y < 29; y++)
{
for (int x = 0; x < 32; x++)
{
int px, py;
const int radr = ((ry + y + 2) & 0x3ff) * 128 + ((rx + x) & 0x7f);
u32 chr = m_bg_map[radr];
int col = m_bg_col_map[chr + m_bg_select * 512 + m_bg_priority * 256];
chr = chr + m_bg_select * 512;
if (flip == 0)
{
px = 8 * x + dx - 6;
py = 8 * y + dy + 9;
}
else
{
px = 248 - (8 * x + dx - 8);
py = 248 - (8 * y + dy + 9);
}
if (!high)
{
m_gfxdecode->gfx(1)->opaque(bitmap,cliprect,
chr,
col,
flip,flip,
px,py);
}
else
{
const u8 pri = (col & 0x10) >> 1;
if (pri != 0)
{
col = col & 0x0f;
draw_bg_pri(bitmap, chr, col, flip, flip, px, py, pri);
}
}
}
}
}
/****************************************************************************/
u32 momoko_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
const int flip = m_flipscreen ^ (m_io_fake->read() & 0x01);
/* draw BG layer - all tiles */
if (m_bg_mask == 0)
draw_bg_romtilemap(screen, bitmap, cliprect, flip, false);
else
bitmap.fill(256, cliprect);
/* draw sprites (momoko) */
draw_sprites(screen, bitmap, cliprect, 0, 9 * 4, flip);
/* draw BG layer - high priority tiles */
if (m_bg_mask == 0)
draw_bg_romtilemap(screen, bitmap, cliprect, flip, true);
/* draw sprites (others) */
draw_sprites(screen, bitmap, cliprect, 9*4, m_spriteram.bytes(), flip);
/* draw text layer */
draw_text_tilemap(screen, bitmap, cliprect, flip);
/* draw FG layer */
if (m_fg_mask == 0)
draw_fg_romtilemap(screen, bitmap, cliprect, flip);
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders: Luca Elia
/***************************************************************************
-= Sky Fox / Exerizer =-
@ -24,46 +25,325 @@ Verified Dip locations and recommended settings with manual
***************************************************************************/
#include "emu.h"
#include "skyfox.h"
#include "cpu/z80/z80.h"
#include "machine/gen_latch.h"
#include "sound/ymopn.h"
#include "video/resnet.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
namespace {
class skyfox_state : public driver_device
{
public:
skyfox_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_spriteram(*this, "spriteram"),
m_bgram(*this, "bgram"),
m_bgrom(*this, "tiles")
{ }
void skyfox(machine_config &config);
void init_skyfox();
DECLARE_INPUT_CHANGED_MEMBER(coin_inserted);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
private:
// devices/memory pointers
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_audiocpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_shared_ptr<uint8_t> m_spriteram;
required_shared_ptr<uint8_t> m_bgram;
required_region_ptr<uint8_t> m_bgrom;
uint8_t m_bg_ctrl = 0;
void bg_ctrl_w(uint8_t data);
void palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect);
void main_map(address_map &map);
void sound_map(address_map &map);
};
// video
/***************************************************************************
[ 1 Background ]
The stars in the background are not tile based (I think!) and
their rendering is entirely guesswork for now..
I draw a star for each horizontal line using 2 bytes in the
background ROM:
- the first byte seems a color / shape info
- the second byte seems a position info
The ROM holds 4 chunks of $2000 bytes. Most of the data does not
change between chunks, while the remaining part (which is rendered
to what seems a "milky way") pulsates in color and/or shape
to simulate the shimmering of stars (?!) if we draw one chunk only
and cycle through the four. Indeed, there's a register cycling
through 4 values.
Since the result kind of matches a screenshot we have, I feel the
drawn result is not that far from reality. On the other hand we
have a random arrangement of stars, so it's hard to tell for sure..
[ 256 Sprites ]
Sprites are 8 planes deep and can be 8x8, 16x16 or 32x32 pixels
in size. They are stored as 32x32x8 tiles in the ROMs.
***************************************************************************/
/***************************************************************************
Convert the color PROMs into a more useable format.
There are three 256x4 palette PROMs (one per gun).
The palette PROMs are connected to the RGB output this way:
bit 3 -- 110 ohm resistor -- RED/GREEN/BLUE
-- 220 ohm resistor -- RED/GREEN/BLUE
-- 680 ohm resistor -- RED/GREEN/BLUE
bit 0 -- 1.2kohm resistor -- RED/GREEN/BLUE
***************************************************************************/
static constexpr res_net_decode_info decode_info =
{
1,
0, 255, // start/end
// R, G, B,
{ 0, 0x100, 0x200, }, // offsets
{ 0, 0, 0, }, // shifts
{ 0xf, 0xf, 0xf, } // masks
};
static constexpr res_net_info net_info =
{
RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_TTL_OUT,
{
{ RES_NET_AMP_NONE, 0, 0, 4, { 1200, 680, 220, 110 } },
{ RES_NET_AMP_NONE, 0, 0, 4, { 1200, 680, 220, 110 } },
{ RES_NET_AMP_NONE, 0, 0, 4, { 1200, 680, 220, 110 } }
}
};
void skyfox_state::palette(palette_device &palette) const
{
uint8_t const *const color_prom = memregion("proms")->base();
std::vector<rgb_t> rgb;
compute_res_net_all(rgb, color_prom, decode_info, net_info);
palette.set_pen_colors(0, rgb);
}
/***************************************************************************
Sprites Drawing
Offset: Value:
03 Code: selects one of the 32x32 tiles in the ROMs.
(Tiles $80-ff are bankswitched to cover $180 tiles)
02 Code + Attr
7654 ---- Code (low 4 bits)
8x8 sprites use bits 7654 (since there are 16 8x8 tiles in the 32x32 one)
16x16 sprites use bits --54 (since there are 4 16x16 tiles in the 32x32 one)
32x32 sprites use no bits (since the 32x32 tile is already selected)
7--- 3--- Size
1--- 1--- : 32x32 sprites
0--- 1--- : 16x16 sprites
8x8 sprites otherwise
---- -2-- Flip Y
---- --1- Flip X
---- ---0 X Low Bit
00 Y
01 X (High 8 Bits)
***************************************************************************/
void skyfox_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
gfx_element *gfx = m_gfxdecode->gfx(0);
int const width = m_screen->width();
int const height = m_screen->height();
// The 32x32 tiles in the 80-ff range are bankswitched
int const shift = (m_bg_ctrl & 0x80) ? (4 - 1) : 4;
for (int offs = 0; offs < m_spriteram.bytes(); offs += 4)
{
int code = m_spriteram[offs + 3] << 8 | m_spriteram[offs + 2];
int flipx = code & 0x2;
int flipy = code & 0x4;
int y = m_spriteram[offs + 0];
int x = m_spriteram[offs + 1] << 1 | (code & 1);
int const high_code = ((code >> 4) & 0x7f0) + ((code & 0x8000) >> shift);
int low_code, n;
switch (code & 0x88)
{
case 0x88: n = 4; low_code = 0; break;
case 0x08: n = 2; low_code = (code & 0x20) >> 2 | (code & 0x10) >> 3; break;
default: n = 1; low_code = (code >> 4) & 0xf; break;
}
if (m_bg_ctrl & 1) // flipscreen
{
x = width - x - n * 8;
y = height - y - n * 8;
flipx = !flipx;
flipy = !flipy;
}
int xstart, ystart, xend, yend, xinc, yinc;
if (flipx) { xstart = n - 1; xend = -1; xinc = -1; }
else { xstart = 0; xend = n; xinc = +1; }
if (flipy) { ystart = n - 1; yend = -1; yinc = -1; }
else { ystart = 0; yend = n; yinc = +1; }
code = low_code + high_code;
for (int dy = ystart; dy != yend; dy += yinc)
{
for (int dx = xstart; dx != xend; dx += xinc, code++)
{
gfx->transpen(bitmap, cliprect, code, 0, flipx, flipy, dx * 8 + x, dy * 8 + y, 0xff);
// wraparound y - BTANB: large sprites exiting the screen sometimes reappear on the other edge
gfx->transpen(bitmap, cliprect, code, 0, flipx, flipy, dx * 8 + x, dy * 8 + y - 256, 0xff);
}
if (n == 2)
code += 2;
}
}
}
/***************************************************************************
Background Rendering
***************************************************************************/
void skyfox_state::draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// Blinking stops until the first star moves after turning on the power
bool const blinking = (m_bg_ctrl & 0x8);
/* Star pattern change. This will change when all star clusters go out of screen or when the player restarts.
When it changes, it will change color of the star clusters. */
int const pattern = (m_bg_ctrl & 0x6) >> 1;
for (int i = 0; i < 0x1000; i++)
{
// contains the position of stars from 0xd4e0 in RAM
int const ramoffset = 0xe0 + (i & 0xf) * 2;
int const pos = m_bgram[ramoffset + 1] * 2 + ((m_bgram[ramoffset] & 0x80) ? 1 : 0);
// ROM offset of star pattern
int const offs = (i * 2) % 0x2000 + pattern * 0x2000;
/* Adjusted with 1 pixel accuracy compared to PCB.
Confirmed that pixel and color pattern match in the "1UP START" screen. */
int const pen = m_bgrom[offs];
int const x = m_bgrom[offs + 1] * 2 + pos + 0x5b;
int const y = (i >> 4) + 1;
/* When flipscreen is enabled, scroll direction is flipped by only in-game subroutine.
This PCB does not seem to support background flip. */
/* This looks perfect at first glance.
but when strict compared on "1UP START" screen,
it seems the blinking pattern in each star may be different. */
if (((m_bg_ctrl >> 4) & 3) != (pen & 3) || !blinking)
bitmap.pix(y % 256, x % 512) = pen;
}
}
/***************************************************************************
Screen Drawing
***************************************************************************/
uint32_t skyfox_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(0xff, cliprect); // the bg is black
draw_background(bitmap, cliprect);
draw_sprites(bitmap, cliprect);
return 0;
}
// machine
/***************************************************************************
Main CPU
***************************************************************************/
void skyfox_state::output_w(offs_t offset, uint8_t data)
void skyfox_state::bg_ctrl_w(uint8_t data)
{
// TODO: untangle
switch (offset)
{
case 0:
m_bg_ctrl = data;
break;
case 1:
m_soundlatch->write(data);
break;
}
}
void skyfox_state::skyfox_map(address_map &map)
void skyfox_state::main_map(address_map &map)
{
map(0x0000, 0xbfff).rom();
map(0xc000, 0xcfff).ram();
map(0xd000, 0xd3ff).ram().share("spriteram");
map(0xd400, 0xd4ff).ram().share("bgram"); // For background stars
map(0xd000, 0xd3ff).ram().share(m_spriteram);
map(0xd400, 0xd4ff).ram().share(m_bgram); // For background stars
// TODO: verify if A11 is unconnected
map(0xd500, 0xdfff).ram();
map(0xe000, 0xe000).portr("INPUTS");
map(0xe001, 0xe001).portr("DSW0");
map(0xe002, 0xe002).portr("DSW1");
map(0xe008, 0xe009).w(FUNC(skyfox_state::output_w));
map(0xe008, 0xe008).w(FUNC(skyfox_state::bg_ctrl_w));
map(0xe009, 0xe009).w("soundlatch", FUNC(generic_latch_8_device::write));
// map(0xe00a, 0xe00e) // POST only?
map(0xe00f, 0xe00f).nopw(); // DMA trigger
map(0xf001, 0xf001).portr("DSW2");
@ -76,7 +356,7 @@ void skyfox_state::skyfox_map(address_map &map)
***************************************************************************/
void skyfox_state::skyfox_sound_map(address_map &map)
void skyfox_state::sound_map(address_map &map)
{
map(0x0000, 0x7fff).rom();
map(0x8000, 0x87ff).ram();
@ -84,7 +364,7 @@ void skyfox_state::skyfox_sound_map(address_map &map)
map(0xa000, 0xa001).rw("ym1", FUNC(ym2203_device::read), FUNC(ym2203_device::write));
// map(0xb000, 0xb001).nopw(); // ??
map(0xc000, 0xc001).rw("ym2", FUNC(ym2203_device::read), FUNC(ym2203_device::write));
map(0xb000, 0xb000).r(m_soundlatch, FUNC(generic_latch_8_device::read));
map(0xb000, 0xb000).r("soundlatch", FUNC(generic_latch_8_device::read));
}
@ -146,7 +426,7 @@ static INPUT_PORTS_START( skyfox )
PORT_DIPSETTING( 0x04, DEF_STR( 1C_2C ) )
PORT_DIPSETTING( 0x08, DEF_STR( 1C_3C ) )
PORT_DIPSETTING( 0x0c, DEF_STR( 1C_4C ) )
/* According to manual, there is also "SW2:4" which has to be always OFF */
// According to manual, there is also "SW2:4" which has to be always OFF
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
@ -187,7 +467,7 @@ INPUT_PORTS_END
support 8x8, 16x16 and 32x32 sprites. */
static GFXDECODE_START( gfx_skyfox )
GFXDECODE_ENTRY( "gfx1", 0, gfx_8x8x8_raw, 0, 1 ) // [0] Sprites
GFXDECODE_ENTRY( "sprites", 0, gfx_8x8x8_raw, 0, 1 )
GFXDECODE_END
@ -209,35 +489,35 @@ void skyfox_state::machine_reset()
void skyfox_state::skyfox(machine_config &config)
{
/* basic machine hardware */
Z80(config, m_maincpu, XTAL(8'000'000)/2); /* Verified at 4MHz */
m_maincpu->set_addrmap(AS_PROGRAM, &skyfox_state::skyfox_map);
// basic machine hardware
Z80(config, m_maincpu, XTAL(8'000'000) / 2); // Verified at 4MHz
m_maincpu->set_addrmap(AS_PROGRAM, &skyfox_state::main_map);
// IM0, never enables ei opcode
Z80(config, m_audiocpu, XTAL(14'318'181)/8); /* Verified at 1.789772MHz */
m_audiocpu->set_addrmap(AS_PROGRAM, &skyfox_state::skyfox_sound_map);
Z80(config, m_audiocpu, XTAL(14'318'181) / 8); // Verified at 1.789772MHz
m_audiocpu->set_addrmap(AS_PROGRAM, &skyfox_state::sound_map);
/* video hardware */
// video hardware
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
// TODO: legacy screen configuration with no vblank irq
m_screen->set_refresh_hz(62.65);
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500) /* not accurate */);
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); // not accurate
m_screen->set_size(512, 256);
m_screen->set_visarea(0+0x60, 320-1+0x60, 0+16, 256-1-16); // from $30*2 to $CC*2+8
m_screen->set_screen_update(FUNC(skyfox_state::screen_update_skyfox));
m_screen->set_screen_update(FUNC(skyfox_state::screen_update));
m_screen->set_palette(m_palette);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_skyfox);
PALETTE(config, m_palette, FUNC(skyfox_state::skyfox_palette), 256); // 256 static colors
PALETTE(config, m_palette, FUNC(skyfox_state::palette), 256); // 256 static colors
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
GENERIC_LATCH_8(config, m_soundlatch);
GENERIC_LATCH_8(config, "soundlatch");
YM2203(config, "ym1", XTAL(14'318'181)/8).add_route(ALL_OUTPUTS, "mono", 0.80); /* Verified at 1.789772MHz */
YM2203(config, "ym1", XTAL(14'318'181) / 8).add_route(ALL_OUTPUTS, "mono", 0.80); // Verified at 1.789772MHz
YM2203(config, "ym2", XTAL(14'318'181)/8).add_route(ALL_OUTPUTS, "mono", 0.80); /* Verified at 1.789772MHz */
YM2203(config, "ym2", XTAL(14'318'181) / 8).add_route(ALL_OUTPUTS, "mono", 0.80); // Verified at 1.789772MHz
}
@ -308,14 +588,14 @@ Video Board: Jaleco made in japan ER-8737
ROM_START( skyfox )
ROM_REGION( 0x10000, "maincpu", 0 ) /* Main Z80 Code */
ROM_REGION( 0x10000, "maincpu", 0 ) // Z80 code
ROM_LOAD( "skyfox1.bin", 0x00000, 0x8000, CRC(b4d4bb6f) SHA1(ed1cf6d91ca7170cb7d1c80b586c11164430fd49) )
ROM_LOAD( "skyfox2.bin", 0x08000, 0x8000, CRC(e15e0263) SHA1(005934327834aed46b17161aef82117ee508e9c4) ) // identical halves
ROM_REGION( 0x10000, "audiocpu", 0 ) /* Sound Z80 Code */
ROM_REGION( 0x10000, "audiocpu", 0 ) // Z80 code
ROM_LOAD( "skyfox9.bin", 0x00000, 0x8000, CRC(0b283bf5) SHA1(5b14d0beea689ee7e9174017e5a127435df4fbe3) )
ROM_REGION( 0x60000, "gfx1", 0 ) /* Sprites */
ROM_REGION( 0x60000, "sprites", 0 )
ROM_LOAD( "skyfox3.bin", 0x00000, 0x10000, CRC(3a17a929) SHA1(973fb36af416161e04a83d7869819d9b13df18cd) )
ROM_LOAD( "skyfox4.bin", 0x10000, 0x10000, CRC(358053bb) SHA1(589e3270eda0d44e73fbc7ac06e782f332920b39) )
ROM_LOAD( "skyfox5.bin", 0x20000, 0x10000, CRC(c1215a6e) SHA1(5ca30be8a68ac6a00907cc9e47ede0acec980f46) )
@ -323,24 +603,24 @@ ROM_START( skyfox )
ROM_LOAD( "skyfox7.bin", 0x40000, 0x10000, CRC(fa2ab5b4) SHA1(c0878b25dae28f7d49e14376ff885d1d4e3d5dfe) )
ROM_LOAD( "skyfox8.bin", 0x50000, 0x10000, CRC(0e3edc49) SHA1(3d1c59ecaabe1c9517203b7e814db41d5cff0cd4) )
ROM_REGION( 0x08000, "gfx2", 0 ) /* Background */
ROM_REGION( 0x08000, "tiles", 0 )
ROM_LOAD( "skyfox10.bin", 0x0000, 0x8000, CRC(19f58f9c) SHA1(6887216243b47152129448cbb4c7d52309feed03) )
ROM_REGION( 0x300, "proms", 0 ) /* Color Proms */
ROM_REGION( 0x300, "proms", 0 ) // colors
ROM_LOAD( "sfoxrprm.bin", 0x000, 0x100, CRC(79913c7f) SHA1(e64e6a3eb55f37984cb2597c8ffba6bc3bad49c7) ) // R
ROM_LOAD( "sfoxgprm.bin", 0x100, 0x100, CRC(fb73d434) SHA1(4a9bd61fbdce9441753c5921f95ead5c4655957e) ) // G
ROM_LOAD( "sfoxbprm.bin", 0x200, 0x100, CRC(60d2ab41) SHA1(e58a54f2aaee5c07136d5437e513d61fb18fbd9f) ) // B
ROM_END
ROM_START( exerizer )
ROM_REGION( 0x10000, "maincpu", 0 ) /* Main Z80 Code */
ROM_REGION( 0x10000, "maincpu", 0 ) // Z80 code
ROM_LOAD( "1.2v", 0x00000, 0x8000, CRC(5df72a5d) SHA1(ca35ac06f3702fd650a584da2f442fbc61c00fce) )
ROM_LOAD( "2.3v", 0x08000, 0x8000, CRC(e15e0263) SHA1(005934327834aed46b17161aef82117ee508e9c4) ) // 1-b
ROM_REGION( 0x10000, "audiocpu", 0 ) /* Sound Z80 Code */
ROM_REGION( 0x10000, "audiocpu", 0 ) // Z80 code
ROM_LOAD( "9.5n", 0x00000, 0x8000, CRC(0b283bf5) SHA1(5b14d0beea689ee7e9174017e5a127435df4fbe3) ) // 1-i
ROM_REGION( 0x60000, "gfx1", 0 ) /* Sprites */
ROM_REGION( 0x60000, "sprites", 0 )
ROM_LOAD( "3-1.7w", 0x00000, 0x10000, CRC(3a17a929) SHA1(973fb36af416161e04a83d7869819d9b13df18cd) )
ROM_LOAD( "4.7u", 0x10000, 0x10000, CRC(358053bb) SHA1(589e3270eda0d44e73fbc7ac06e782f332920b39) ) // 1-d
ROM_LOAD( "5-1.7t", 0x20000, 0x10000, CRC(c1215a6e) SHA1(5ca30be8a68ac6a00907cc9e47ede0acec980f46) )
@ -348,24 +628,24 @@ ROM_START( exerizer )
ROM_LOAD( "7.7p", 0x40000, 0x10000, CRC(c9bbfe5c) SHA1(ce3f7d32baa8bb0bfc110877b5b5f4648ee959ac) )
ROM_LOAD( "8.7n", 0x50000, 0x10000, CRC(0e3edc49) SHA1(3d1c59ecaabe1c9517203b7e814db41d5cff0cd4) ) // 1-h
ROM_REGION( 0x08000, "gfx2", 0 ) /* Background */
ROM_REGION( 0x08000, "tiles", 0 )
ROM_LOAD( "10.5e", 0x0000, 0x8000, CRC(19f58f9c) SHA1(6887216243b47152129448cbb4c7d52309feed03) ) // 1-j
ROM_REGION( 0x300, "proms", 0 ) /* Color Proms */
ROM_REGION( 0x300, "proms", 0 ) // colors
ROM_LOAD( "r.1c", 0x000, 0x100, CRC(79913c7f) SHA1(e64e6a3eb55f37984cb2597c8ffba6bc3bad49c7) ) // 2-bpr
ROM_LOAD( "g.1b", 0x100, 0x100, CRC(fb73d434) SHA1(4a9bd61fbdce9441753c5921f95ead5c4655957e) ) // 3-bpr
ROM_LOAD( "b.1d", 0x200, 0x100, CRC(60d2ab41) SHA1(e58a54f2aaee5c07136d5437e513d61fb18fbd9f) ) // 1-bpr
ROM_END
ROM_START( exerizerb )
ROM_REGION( 0x10000, "maincpu", 0 ) /* Main Z80 Code */
ROM_REGION( 0x10000, "maincpu", 0 ) // Z80 code
ROM_LOAD( "1-a", 0x00000, 0x8000, CRC(5df72a5d) SHA1(ca35ac06f3702fd650a584da2f442fbc61c00fce) )
ROM_LOAD( "skyfox2.bin", 0x08000, 0x8000, CRC(e15e0263) SHA1(005934327834aed46b17161aef82117ee508e9c4) ) // 1-b
ROM_REGION( 0x10000, "audiocpu", 0 ) /* Sound Z80 Code */
ROM_REGION( 0x10000, "audiocpu", 0 ) // Z80 code
ROM_LOAD( "skyfox9.bin", 0x00000, 0x8000, CRC(0b283bf5) SHA1(5b14d0beea689ee7e9174017e5a127435df4fbe3) ) // 1-i
ROM_REGION( 0x60000, "gfx1", 0 ) /* Sprites */
ROM_REGION( 0x60000, "sprites", 0 )
ROM_LOAD( "1-c", 0x00000, 0x10000, CRC(450e9381) SHA1(f99b2ca73f1e4ba91b8066bb6d28d33b66a3ee81) )
ROM_LOAD( "skyfox4.bin", 0x10000, 0x10000, CRC(358053bb) SHA1(589e3270eda0d44e73fbc7ac06e782f332920b39) ) // 1-d
ROM_LOAD( "1-e", 0x20000, 0x10000, CRC(50a38c60) SHA1(a4b8d530914d6c85b15940a7821b4365068de668) )
@ -373,21 +653,21 @@ ROM_START( exerizerb )
ROM_LOAD( "1-g", 0x40000, 0x10000, CRC(c9bbfe5c) SHA1(ce3f7d32baa8bb0bfc110877b5b5f4648ee959ac) )
ROM_LOAD( "skyfox8.bin", 0x50000, 0x10000, CRC(0e3edc49) SHA1(3d1c59ecaabe1c9517203b7e814db41d5cff0cd4) ) // 1-h
ROM_REGION( 0x08000, "gfx2", 0 ) /* Background */
ROM_REGION( 0x08000, "tiles", 0 )
ROM_LOAD( "skyfox10.bin", 0x0000, 0x8000, CRC(19f58f9c) SHA1(6887216243b47152129448cbb4c7d52309feed03) ) // 1-j
ROM_REGION( 0x300, "proms", 0 ) /* Color Proms */
ROM_REGION( 0x300, "proms", 0 ) // colors
ROM_LOAD( "sfoxrprm.bin", 0x000, 0x100, CRC(79913c7f) SHA1(e64e6a3eb55f37984cb2597c8ffba6bc3bad49c7) ) // 2-bpr
ROM_LOAD( "sfoxgprm.bin", 0x100, 0x100, CRC(fb73d434) SHA1(4a9bd61fbdce9441753c5921f95ead5c4655957e) ) // 3-bpr
ROM_LOAD( "sfoxbprm.bin", 0x200, 0x100, CRC(60d2ab41) SHA1(e58a54f2aaee5c07136d5437e513d61fb18fbd9f) ) // 1-bpr
ROM_END
/* Untangle the graphics: cut each 32x32x8 tile in 16 8x8x8 tiles */
// Untangle the graphics: cut each 32x32x8 tile in 16 8x8x8 tiles
void skyfox_state::init_skyfox()
{
uint8_t *rom = memregion("gfx1")->base();
uint8_t *end = rom + memregion("gfx1")->bytes();
uint8_t *rom = memregion("sprites")->base();
uint8_t *end = rom + memregion("sprites")->bytes();
uint8_t buf[32 * 32];
while (rom < end)
@ -400,6 +680,8 @@ void skyfox_state::init_skyfox()
}
}
} // anonymous namespace
GAME( 1987, skyfox, 0, skyfox, skyfox, skyfox_state, init_skyfox, ROT90, "Jaleco (Nichibutsu USA license)", "Sky Fox", MACHINE_SUPPORTS_SAVE )
GAME( 1987, exerizer, skyfox, skyfox, skyfox, skyfox_state, init_skyfox, ROT90, "Jaleco", "Exerizer (Japan)", MACHINE_SUPPORTS_SAVE )

View File

@ -1,63 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Luca Elia
/*************************************************************************
Skyfox
*************************************************************************/
#ifndef MAME_INCLUDES_SKYFOX_H
#define MAME_INCLUDES_SKYFOX_H
#pragma once
#include "machine/gen_latch.h"
#include "emupal.h"
#include "screen.h"
class skyfox_state : public driver_device
{
public:
skyfox_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_soundlatch(*this, "soundlatch"),
m_spriteram(*this, "spriteram"),
m_bgram(*this, "bgram")
{ }
void skyfox(machine_config &config);
void init_skyfox();
DECLARE_INPUT_CHANGED_MEMBER(coin_inserted);
private:
/* devices/memory pointers */
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_audiocpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_device<generic_latch_8_device> m_soundlatch;
required_shared_ptr<uint8_t> m_spriteram;
required_shared_ptr<uint8_t> m_bgram;
int m_bg_ctrl = 0;
void output_w(offs_t offset, uint8_t data);
virtual void machine_start() override;
virtual void machine_reset() override;
void skyfox_palette(palette_device &palette) const;
uint32_t screen_update_skyfox(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect );
void draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect);
void skyfox_map(address_map &map);
void skyfox_sound_map(address_map &map);
};
#endif // MAME_INCLUDES_SKYFOX_H

View File

@ -1,240 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Luca Elia
/***************************************************************************
-= Sky Fox / Exerizer =-
driver by Luca Elia (l.elia@tin.it)
[ 1 Background ]
The stars in the background are not tile based (I think!) and
their rendering is entirely guesswork for now..
I draw a star for each horizontal line using 2 bytes in the
background rom:
- the first byte seems a color / shape info
- the second byte seems a position info
The rom holds 4 chunks of $2000 bytes. Most of the data does not
change between chunks, while the remaining part (which is rendered
to what seems a "milky way") pulsates in color and/or shape
to simulate the shimmering of stars (?!) if we draw one chunk only
and cycle through the four. Indeed, there's a register cycling
through 4 values.
Since the result kind of matches a screenshot we have, I feel the
drawn result is not that far from reality. On the other hand we
have a random arrangement of stars, so it's hard to tell for sure..
[ 256 Sprites ]
Sprites are 8 planes deep and can be 8x8, 16x16 or 32x32 pixels
in size. They are stored as 32x32x8 tiles in the ROMs.
***************************************************************************/
#include "emu.h"
#include "video/resnet.h"
#include "skyfox.h"
/***************************************************************************
Convert the color PROMs into a more useable format.
There are three 256x4 palette PROMs (one per gun).
The palette PROMs are connected to the RGB output this way:
bit 3 -- 110 ohm resistor -- RED/GREEN/BLUE
-- 220 ohm resistor -- RED/GREEN/BLUE
-- 680 ohm resistor -- RED/GREEN/BLUE
bit 0 -- 1.2kohm resistor -- RED/GREEN/BLUE
***************************************************************************/
static constexpr res_net_decode_info skyfox_decode_info =
{
1,
0, 255, // start/end
// R, G, B,
{ 0, 0x100, 0x200, }, // offsets
{ 0, 0, 0, }, // shifts
{ 0xf, 0xf, 0xf, } // masks
};
static constexpr res_net_info skyfox_net_info =
{
RES_NET_VCC_5V | RES_NET_VBIAS_5V | RES_NET_VIN_TTL_OUT,
{
{ RES_NET_AMP_NONE, 0, 0, 4, { 1200, 680, 220, 110 } },
{ RES_NET_AMP_NONE, 0, 0, 4, { 1200, 680, 220, 110 } },
{ RES_NET_AMP_NONE, 0, 0, 4, { 1200, 680, 220, 110 } }
}
};
void skyfox_state::skyfox_palette(palette_device &palette) const
{
uint8_t const *const color_prom = memregion("proms")->base();
std::vector<rgb_t> rgb;
compute_res_net_all(rgb, color_prom, skyfox_decode_info, skyfox_net_info);
palette.set_pen_colors(0, rgb);
}
/***************************************************************************
Sprites Drawing
Offset: Value:
03 Code: selects one of the 32x32 tiles in the ROMs.
(Tiles $80-ff are bankswitched to cover $180 tiles)
02 Code + Attr
7654 ---- Code (low 4 bits)
8x8 sprites use bits 7654 (since there are 16 8x8 tiles in the 32x32 one)
16x16 sprites use bits --54 (since there are 4 16x16 tiles in the 32x32 one)
32x32 sprites use no bits (since the 32x32 tile is already selected)
7--- 3--- Size
1--- 1--- : 32x32 sprites
0--- 1--- : 16x16 sprites
8x8 sprites otherwise
---- -2-- Flip Y
---- --1- Flip X
---- ---0 X Low Bit
00 Y
01 X (High 8 Bits)
***************************************************************************/
void skyfox_state::draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect )
{
gfx_element *gfx = m_gfxdecode->gfx(0);
int width = m_screen->width();
int height = m_screen->height();
/* The 32x32 tiles in the 80-ff range are bankswitched */
int shift = (m_bg_ctrl & 0x80) ? (4 - 1) : 4;
for (int offs = 0; offs < m_spriteram.bytes(); offs += 4)
{
int xstart, ystart, xend, yend;
int xinc, yinc, dx, dy;
int low_code, high_code, n;
int code = m_spriteram[offs + 3] << 8 | m_spriteram[offs + 2];
int flipx = code & 0x2;
int flipy = code & 0x4;
int y = m_spriteram[offs + 0];
int x = m_spriteram[offs + 1] << 1 | (code & 1);
high_code = ((code >> 4) & 0x7f0) + ((code & 0x8000) >> shift);
switch (code & 0x88)
{
case 0x88: n = 4; low_code = 0; break;
case 0x08: n = 2; low_code = (code & 0x20) >> 2 | (code & 0x10) >> 3; break;
default: n = 1; low_code = (code >> 4) & 0xf; break;
}
if (m_bg_ctrl & 1) // flipscreen
{
x = width - x - n * 8;
y = height - y - n * 8;
flipx = !flipx;
flipy = !flipy;
}
if (flipx) { xstart = n - 1; xend = -1; xinc = -1; }
else { xstart = 0; xend = n; xinc = +1; }
if (flipy) { ystart = n - 1; yend = -1; yinc = -1; }
else { ystart = 0; yend = n; yinc = +1; }
code = low_code + high_code;
for (dy = ystart; dy != yend; dy += yinc)
{
for (dx = xstart; dx != xend; dx += xinc, code++)
{
gfx->transpen(bitmap, cliprect, code, 0, flipx, flipy, dx*8 + x, dy*8 + y, 0xff);
// wraparound y - BTANB: large sprites exiting the screen sometimes reappear on the other edge
gfx->transpen(bitmap, cliprect, code, 0, flipx, flipy, dx*8 + x, dy*8 + y - 256, 0xff);
}
if (n == 2)
code += 2;
}
}
}
/***************************************************************************
Background Rendering
***************************************************************************/
void skyfox_state::draw_background(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
uint8_t *rom = memregion("gfx2")->base();
/* Blinking stops until the first star moves after turning on the power */
bool blinking = (m_bg_ctrl & 0x8);
/* Star pattern change. This will change at when all star clusters to out of screen or when player restart.
When it changes, will change color of star clusters. */
int pattern = (m_bg_ctrl & 0x6) >> 1;
for (int i = 0; i < 0x1000; i++)
{
/* contains the position of stars from 0xd4e0 in RAM */
int ramoffset = 0xe0 + (i & 0xf) * 2;
int pos = m_bgram[ramoffset + 1] * 2 + ((m_bgram[ramoffset] & 0x80) ? 1 : 0);
/* ROM offset of star pattern */
int offs = (i * 2) % 0x2000 + pattern * 0x2000;
/* Adjusted with 1 pixel accuracy compared to PCB.
Confirmed that pixel and color pattern match in the "1UP START" screen. */
int pen = rom[offs];
int x = rom[offs + 1] * 2 + pos + 0x5b;
int y = (i >> 4) + 1;
/* When flipscreen is enabled, scroll direction is flipped by only in-game subroutine.
This PCB seems does not support background flip. */
/* This looks perfect at first glance.
but when strict compared on "1UP START" screen,
it seems the blinking pattern in each star may be different. */
if (((m_bg_ctrl >> 4) & 3) != (pen & 3) || !blinking)
bitmap.pix(y % 256, x % 512) = pen;
}
}
/***************************************************************************
Screen Drawing
***************************************************************************/
uint32_t skyfox_state::screen_update_skyfox(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(0xff, cliprect); // the bg is black
draw_background(bitmap, cliprect);
draw_sprites(bitmap, cliprect);
return 0;
}

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause
// copyright-holders: David Haywood
/***************************************************************************
Omori Battle Cross
@ -12,7 +13,7 @@
Its effect is the following :
* you need to insert at least one credit and start a game
* when the game is over, you can start another games WITHOUT
inserting another coins
inserting another coin
Note that the number of credits is decremented though.
Credits are BCD coded on 3 bytes (0x000000-0x999999) at addresses
0xa039 (LSB), 0xa03a and 0xa03b (MSB), but only the LSB is displayed.
@ -57,13 +58,13 @@
- missing starfield
- game speed, its seems to be controlled by the IRQ's, how fast should it
be? firing seems frustratingly inconsistant (better with PORT_IMPULSE)
- game speed, it seems to be controlled by the IRQ's, how fast should it
be? firing seems frustratingly inconsistent (better with PORT_IMPULSE)
- BG tilemap palette bits (in most cases paltte 0 is used,
only highlights ( battlex logo, hiscore table) uses different palettes(?).
- BG tilemap palette bits (in most cases palette 0 is used,
only highlights (battlex logo, hiscore table) use different palettes(?).
Current implementation gives different highlight colors than on real
hardware (i.e. battlex logo should have yellow highights)
hardware (i.e. battlex logo should have yellow highlights)
****************************************************************************
@ -82,21 +83,215 @@
#include "emu.h"
#include "battlex.h"
#include "cpu/z80/z80.h"
#include "sound/ay8910.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "tilemap.h"
INTERRUPT_GEN_MEMBER(battlex_state::battlex_interrupt)
namespace {
class battlex_state : public driver_device
{
public:
battlex_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
m_videoram(*this, "videoram"),
m_spriteram(*this, "spriteram")
{ }
void init_battlex();
void battlex(machine_config &config);
DECLARE_CUSTOM_INPUT_MEMBER(in0_b4_r);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
// devices
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
// memory pointers
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_spriteram;
tilemap_t *m_bg_tilemap = nullptr;
void io_map(address_map &map);
private:
// video-related
uint8_t m_scroll_lsb = 0U;
uint8_t m_scroll_msb = 0U;
uint8_t m_starfield_enabled = 0U;
uint8_t m_in0_b4 = 0U;
void palette_w(offs_t offset, uint8_t data);
void scroll_x_lsb_w(uint8_t data);
void scroll_x_msb_w(uint8_t data);
void scroll_starfield_w(uint8_t data);
void videoram_w(offs_t offset, uint8_t data);
void flipscreen_w(uint8_t data);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
INTERRUPT_GEN_MEMBER(interrupt);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
void main_map(address_map &map);
};
class dodgeman_state : public battlex_state
{
public:
using battlex_state::battlex_state;
void dodgeman(machine_config &config);
protected:
virtual void video_start() override;
private:
TILE_GET_INFO_MEMBER(get_bg_tile_info);
void io_map(address_map &map);
};
// video
void battlex_state::palette_w(offs_t offset, uint8_t data)
{
int const palette_num = offset / 8;
int const color_num = offset & 7;
m_palette->set_pen_color(offset, pal1bit(data >> 0), pal1bit(data >> 2), pal1bit(data >> 1));
// set darker colors
m_palette->set_pen_color(64 + palette_num * 16 + color_num, pal1bit(data >> 0), pal1bit(data >> 2), pal1bit(data >> 1));
m_palette->set_pen_color(64 + palette_num * 16 + color_num + 8, pal2bit((data >> 0) & 1), pal2bit((data >> 2) & 1), pal2bit((data >> 1) & 1));
}
void battlex_state::scroll_x_lsb_w(uint8_t data)
{
m_scroll_lsb = data;
}
void battlex_state::scroll_x_msb_w(uint8_t data)
{
m_scroll_msb = data;
}
void battlex_state::scroll_starfield_w(uint8_t data)
{
}
void battlex_state::videoram_w(offs_t offset, uint8_t data)
{
m_videoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset / 2);
}
void battlex_state::flipscreen_w(uint8_t data)
{
m_starfield_enabled = data & 0x10;
if (flip_screen() != (data >> 7))
{
flip_screen_set(data & 0x80);
machine().tilemap().mark_all_dirty();
}
}
TILE_GET_INFO_MEMBER(battlex_state::get_bg_tile_info)
{
int const tile = m_videoram[tile_index * 2] | (((m_videoram[tile_index * 2 + 1] & 0x01)) << 8);
int const color = (m_videoram[tile_index * 2 + 1] & 0x0e) >> 1; // high bits unused
tileinfo.set(0, tile, color, 0);
}
TILE_GET_INFO_MEMBER(dodgeman_state::get_bg_tile_info)
{
int const tile = m_videoram[tile_index * 2] | (((m_videoram[tile_index * 2 + 1] & 0x03)) << 8);
int const color = (m_videoram[tile_index * 2 + 1] & 0x0c) >> 2; // high bits unused
tileinfo.set(0, tile, color, 0);
}
void battlex_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(battlex_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
}
void dodgeman_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(dodgeman_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
}
void battlex_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
gfx_element *gfx = m_gfxdecode->gfx(1);
uint8_t const *source = m_spriteram;
uint8_t const *finish = m_spriteram + 0x200;
while (source < finish)
{
int sx = (source[0] & 0x7f) * 2 - (source[0] & 0x80) * 2;
int sy = source[3];
int const tile = source[2] ; // dodgeman has 0x100 sprites
int const color = source[1] & 0x07; // bits 3, 4, 5 also used during explosions
int flipy = source[1] & 0x80;
int flipx = source[1] & 0x40;
if (flip_screen())
{
sx = 240 - sx;
sy = 240 - sy;
flipx = !flipx;
flipy = !flipy;
}
gfx->transpen(bitmap, cliprect, tile, color, flipx, flipy, sx, sy, 0);
source += 4;
}
}
uint32_t battlex_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
if (!flip_screen())
m_bg_tilemap->set_scrollx(0, m_scroll_lsb | (m_scroll_msb << 8));
else
m_bg_tilemap->set_scrollx(0, m_scroll_lsb | (m_scroll_msb << 3));
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
draw_sprites(bitmap, cliprect);
return 0;
}
// machine
INTERRUPT_GEN_MEMBER(battlex_state::interrupt)
{
m_in0_b4 = 1;
device.execute().set_input_line(0, ASSERT_LINE);
}
CUSTOM_INPUT_MEMBER(battlex_state::battlex_in0_b4_r)
CUSTOM_INPUT_MEMBER(battlex_state::in0_b4_r)
{
uint32_t ret = m_in0_b4;
if (m_in0_b4)
@ -115,13 +310,13 @@ CUSTOM_INPUT_MEMBER(battlex_state::battlex_in0_b4_r)
*
*************************************/
void battlex_state::battlex_map(address_map &map)
void battlex_state::main_map(address_map &map)
{
map(0x0000, 0x5fff).rom();
map(0x8000, 0x8fff).ram().w(FUNC(battlex_state::battlex_videoram_w)).share("videoram");
map(0x9000, 0x91ff).ram().share("spriteram");
map(0x8000, 0x8fff).ram().w(FUNC(battlex_state::videoram_w)).share(m_videoram);
map(0x9000, 0x91ff).ram().share(m_spriteram);
map(0xa000, 0xa3ff).ram();
map(0xe000, 0xe03f).ram().w(FUNC(battlex_state::battlex_palette_w));
map(0xe000, 0xe03f).ram().w(FUNC(battlex_state::palette_w));
}
@ -132,18 +327,18 @@ void battlex_state::io_map(address_map &map)
map(0x01, 0x01).portr("SYSTEM");
map(0x02, 0x02).portr("INPUTS");
map(0x03, 0x03).portr("DSW2");
map(0x10, 0x10).w(FUNC(battlex_state::battlex_flipscreen_w));
map(0x10, 0x10).w(FUNC(battlex_state::flipscreen_w));
/* verify all of these */
// verify all of these
map(0x22, 0x23).w("ay1", FUNC(ay8910_device::data_address_w));
map(0x30, 0x30).w(FUNC(battlex_state::battlex_scroll_starfield_w));
map(0x32, 0x32).w(FUNC(battlex_state::battlex_scroll_x_lsb_w));
map(0x33, 0x33).w(FUNC(battlex_state::battlex_scroll_x_msb_w));
map(0x30, 0x30).w(FUNC(battlex_state::scroll_starfield_w));
map(0x32, 0x32).w(FUNC(battlex_state::scroll_x_lsb_w));
map(0x33, 0x33).w(FUNC(battlex_state::scroll_x_msb_w));
}
void battlex_state::dodgeman_io_map(address_map &map)
void dodgeman_state::io_map(address_map &map)
{
io_map(map);
battlex_state::io_map(map);
map(0x26, 0x27).w("ay2", FUNC(ay8910_device::data_address_w));
}
@ -154,7 +349,7 @@ void battlex_state::dodgeman_io_map(address_map &map)
*************************************/
static INPUT_PORTS_START( battlex )
PORT_START("DSW1") /* IN0 */
PORT_START("DSW1") // IN0
PORT_DIPNAME( 0x03, 0x00, DEF_STR( Coin_A ) )
PORT_DIPSETTING( 0x02, DEF_STR( 2C_1C ) )
PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) )
@ -166,7 +361,7 @@ static INPUT_PORTS_START( battlex )
PORT_DIPNAME( 0x08, 0x08, DEF_STR( Demo_Sounds ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x08, DEF_STR( On ) )
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(battlex_state, battlex_in0_b4_r)
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(battlex_state, in0_b4_r)
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Cabinet ) )
PORT_DIPSETTING( 0x20, DEF_STR( Upright ) )
PORT_DIPSETTING( 0x00, DEF_STR( Cocktail ) )
@ -175,7 +370,7 @@ static INPUT_PORTS_START( battlex )
PORT_DIPSETTING( 0x40, DEF_STR( On ) )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_START("SYSTEM") /* IN1 */
PORT_START("SYSTEM") // IN1
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_COIN1 )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_COIN2 )
// TODO: PORT_IMPULSE?
@ -186,7 +381,7 @@ static INPUT_PORTS_START( battlex )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNKNOWN )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN )
PORT_START("INPUTS") /* IN2 */
PORT_START("INPUTS") // IN2
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY
@ -196,7 +391,7 @@ static INPUT_PORTS_START( battlex )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_COCKTAIL
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_COCKTAIL
PORT_START("DSW2") /* IN3 */
PORT_START("DSW2") // IN3
PORT_DIPNAME( 0x07, 0x00, DEF_STR( Coin_B ) )
PORT_DIPSETTING( 0x07, DEF_STR( 3C_1C ) )
PORT_DIPSETTING( 0x05, DEF_STR( 2C_1C ) )
@ -252,8 +447,8 @@ static const gfx_layout battlex_spritelayout =
};
static GFXDECODE_START( gfx_battlex )
GFXDECODE_ENTRY( "gfx1", 0, gfx_8x8x4_packed_msb, 64, 8 )
GFXDECODE_ENTRY( "gfx2", 0, battlex_spritelayout, 0, 8 )
GFXDECODE_ENTRY( "tiles", 0, gfx_8x8x4_packed_msb, 64, 8 )
GFXDECODE_ENTRY( "sprites", 0, battlex_spritelayout, 0, 8 )
GFXDECODE_END
@ -265,7 +460,7 @@ GFXDECODE_END
void battlex_state::machine_start()
{
/* register for save states */
// register for save states
save_item(NAME(m_scroll_lsb));
save_item(NAME(m_scroll_msb));
save_item(NAME(m_starfield_enabled));
@ -282,39 +477,38 @@ void battlex_state::machine_reset()
void battlex_state::battlex(machine_config &config)
{
/* basic machine hardware */
Z80(config, m_maincpu, XTAL(10'000'000)/4 ); // ?
m_maincpu->set_addrmap(AS_PROGRAM, &battlex_state::battlex_map);
// basic machine hardware
Z80(config, m_maincpu, XTAL(10'000'000) / 4 ); // divider not verified
m_maincpu->set_addrmap(AS_PROGRAM, &battlex_state::main_map);
m_maincpu->set_addrmap(AS_IO, &battlex_state::io_map);
m_maincpu->set_periodic_int(FUNC(battlex_state::battlex_interrupt), attotime::from_hz(400)); /* controls game speed? */
m_maincpu->set_periodic_int(FUNC(battlex_state::interrupt), attotime::from_hz(400)); // controls game speed?
/* video hardware */
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_size(32*8, 32*8);
screen.set_visarea(0*8, 32*8-1, 2*8, 30*8-1);
screen.set_screen_update(FUNC(battlex_state::screen_update_battlex));
screen.set_screen_update(FUNC(battlex_state::screen_update));
screen.set_palette(m_palette);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_battlex);
PALETTE(config, m_palette).set_entries(64 + 128);
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
AY8910(config, "ay1", XTAL(10'000'000)/8).add_route(ALL_OUTPUTS, "mono", 0.40); // ?
AY8910(config, "ay1", XTAL(10'000'000) / 8).add_route(ALL_OUTPUTS, "mono", 0.40); // divider not verified
}
void battlex_state::dodgeman(machine_config &config)
void dodgeman_state::dodgeman(machine_config &config)
{
battlex(config);
m_maincpu->set_addrmap(AS_IO, &battlex_state::dodgeman_io_map);
m_maincpu->set_addrmap(AS_IO, &dodgeman_state::io_map);
MCFG_VIDEO_START_OVERRIDE(battlex_state, dodgeman)
AY8910(config, "ay2", XTAL(10'000'000)/8).add_route(ALL_OUTPUTS, "mono", 0.40); // ?
AY8910(config, "ay2", XTAL(10'000'000) / 8).add_route(ALL_OUTPUTS, "mono", 0.40); // divider not verified
}
@ -333,9 +527,9 @@ ROM_START( battlex )
ROM_LOAD( "p-rom5.2", 0x4000, 0x1000, CRC(ceb63d38) SHA1(92cab905d009c59115f52172ba7d01c8ff8991d7) )
ROM_LOAD( "p-rom6.1", 0x5000, 0x1000, CRC(6923f601) SHA1(e6c33cbd8d8679299d7b2c568d56f96ed3073971) )
ROM_REGION( 0x4000, "gfx1", ROMREGION_ERASE00 ) // filled in later
ROM_REGION( 0x4000, "tiles", ROMREGION_ERASE00 ) // filled in later
ROM_REGION( 0x3000, "gfx2", 0 )
ROM_REGION( 0x3000, "sprites", 0 )
ROM_LOAD( "1a_f.6f", 0x0000, 0x1000, CRC(2b69287a) SHA1(30c0edaec44118b95ec390bd41c1bd49a2802451) )
ROM_LOAD( "1a_h.6h", 0x1000, 0x1000, CRC(9f4c3bdd) SHA1(e921ecafefe54c033d05d9cd289808e971ac7940) )
ROM_LOAD( "1a_j.6j", 0x2000, 0x1000, CRC(c1345b05) SHA1(17194c8ec961990222bd295ff1d036a64f497b0e) )
@ -356,9 +550,9 @@ ROM_START( dodgeman )
ROM_LOAD( "dg4.2f", 0x4000, 0x001000, CRC(14169361) SHA1(86d3cd1fa0aa4f21029daea2eba99bdaa34372e8) )
ROM_LOAD( "dg5.1f", 0x5000, 0x001000, CRC(8f83ae2f) SHA1(daad41b61ba3d55531021d444bbe4acfc275cfc9) )
ROM_REGION( 0x8000, "gfx1", ROMREGION_ERASE00 ) // filled in later
ROM_REGION( 0x8000, "tiles", ROMREGION_ERASE00 ) // filled in later
ROM_REGION( 0x6000, "gfx2", ROMREGION_ERASE00 )
ROM_REGION( 0x6000, "sprites", ROMREGION_ERASE00 )
ROM_LOAD( "f.6f", 0x0000, 0x002000, CRC(dfaaf4c8) SHA1(1e09f1d72e7e5e6782d73ae60bca7982fc04df0e) )
ROM_LOAD( "h.6h", 0x2000, 0x002000, CRC(e2525ffe) SHA1(a17b608b4089014be381b26f16597b83d4a66ebd) )
ROM_LOAD( "j.6j", 0x4000, 0x002000, CRC(2731ee46) SHA1(15b9350e19f31b1cea99deb9935543777644e6a8) )
@ -381,8 +575,8 @@ void battlex_state::init_battlex()
{
uint8_t *colormask = memregion("user1")->base();
uint8_t *gfxdata = memregion("user2")->base();
uint8_t *dest = memregion("gfx1")->base();
int tile_size = memregion("gfx1")->bytes() / 32;
uint8_t *dest = memregion("tiles")->base();
int tile_size = memregion("tiles")->bytes() / 32;
int offset = 0;
for (int tile = 0; tile < tile_size; tile++)
@ -409,6 +603,9 @@ void battlex_state::init_battlex()
}
}
} // anonymous namespace
/*************************************
*
* Game driver
@ -416,4 +613,4 @@ void battlex_state::init_battlex()
*************************************/
GAME( 1982, battlex, 0, battlex, battlex, battlex_state, init_battlex, ROT180, "Omori Electric Co., Ltd.", "Battle Cross", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE | MACHINE_NO_COCKTAIL )
GAME( 1983, dodgeman, 0, dodgeman, dodgeman, battlex_state, init_battlex, ROT180, "Omori Electric Co., Ltd.", "Dodge Man", MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE | MACHINE_NO_COCKTAIL )
GAME( 1983, dodgeman, 0, dodgeman, dodgeman, dodgeman_state, init_battlex, ROT180, "Omori Electric Co., Ltd.", "Dodge Man", MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE | MACHINE_NO_COCKTAIL )

View File

@ -1,62 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood
/***************************************************************************
Battle Cross
***************************************************************************/
#include "emupal.h"
#include "tilemap.h"
class battlex_state : public driver_device
{
public:
battlex_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag),
m_videoram(*this, "videoram"),
m_spriteram(*this, "spriteram"),
m_maincpu(*this, "maincpu"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette") { }
void init_battlex();
void dodgeman(machine_config &config);
void battlex(machine_config &config);
DECLARE_CUSTOM_INPUT_MEMBER(battlex_in0_b4_r);
private:
uint8_t m_in0_b4 = 0U;
/* memory pointers */
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_spriteram;
/* video-related */
tilemap_t *m_bg_tilemap = nullptr;
uint8_t m_scroll_lsb = 0U;
uint8_t m_scroll_msb = 0U;
uint8_t m_starfield_enabled = 0U;
void battlex_palette_w(offs_t offset, uint8_t data);
void battlex_scroll_x_lsb_w(uint8_t data);
void battlex_scroll_x_msb_w(uint8_t data);
void battlex_scroll_starfield_w(uint8_t data);
void battlex_videoram_w(offs_t offset, uint8_t data);
void battlex_flipscreen_w(uint8_t data);
TILE_GET_INFO_MEMBER(get_bg_tile_info);
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
uint32_t screen_update_battlex(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
INTERRUPT_GEN_MEMBER(battlex_interrupt);
void draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect );
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
DECLARE_VIDEO_START(dodgeman);
TILE_GET_INFO_MEMBER(get_dodgeman_bg_tile_info);
void battlex_map(address_map &map);
void dodgeman_io_map(address_map &map);
void io_map(address_map &map);
};

View File

@ -1,122 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood
/***************************************************************************
Video emulation for Omori Battle Cross
***************************************************************************/
#include "emu.h"
#include "battlex.h"
void battlex_state::battlex_palette_w(offs_t offset, uint8_t data)
{
int palette_num = offset / 8;
int color_num = offset & 7;
m_palette->set_pen_color(offset, pal1bit(data >> 0), pal1bit(data >> 2), pal1bit(data >> 1));
/* set darker colors */
m_palette->set_pen_color(64+palette_num*16+color_num, pal1bit(data >> 0), pal1bit(data >> 2), pal1bit(data >> 1));
m_palette->set_pen_color(64+palette_num*16+color_num+8, pal2bit((data >> 0)&1), pal2bit((data >> 2)&1), pal2bit( (data >> 1) &1));
}
void battlex_state::battlex_scroll_x_lsb_w(uint8_t data)
{
m_scroll_lsb = data;
}
void battlex_state::battlex_scroll_x_msb_w(uint8_t data)
{
m_scroll_msb = data;
}
void battlex_state::battlex_scroll_starfield_w(uint8_t data)
{
}
void battlex_state::battlex_videoram_w(offs_t offset, uint8_t data)
{
m_videoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset / 2);
}
void battlex_state::battlex_flipscreen_w(uint8_t data)
{
m_starfield_enabled = data & 0x10;
if (flip_screen() != (data >> 7))
{
flip_screen_set(data & 0x80);
machine().tilemap().mark_all_dirty();
}
}
TILE_GET_INFO_MEMBER(battlex_state::get_bg_tile_info)
{
int tile = m_videoram[tile_index * 2] | (((m_videoram[tile_index * 2 + 1] & 0x01)) << 8);
int color = (m_videoram[tile_index * 2 + 1] & 0x0e) >> 1; // high bits unused
tileinfo.set(0, tile, color, 0);
}
TILE_GET_INFO_MEMBER(battlex_state::get_dodgeman_bg_tile_info)
{
int tile = m_videoram[tile_index * 2] | (((m_videoram[tile_index * 2 + 1] & 0x03)) << 8);
int color = (m_videoram[tile_index * 2 + 1] & 0x0c) >> 2; // high bits unused
tileinfo.set(0, tile, color, 0);
}
void battlex_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(battlex_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
}
void battlex_state::video_start_dodgeman()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(battlex_state::get_dodgeman_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 64, 32);
}
void battlex_state::draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect )
{
gfx_element *gfx = m_gfxdecode->gfx(1);
uint8_t *source = m_spriteram;
uint8_t *finish = m_spriteram + 0x200;
while (source < finish)
{
int sx = (source[0] & 0x7f) * 2 - (source[0] & 0x80) * 2;
int sy = source[3];
int tile = source[2] ; /* dodgeman has 0x100 sprites */
int color = source[1] & 0x07; /* bits 3,4,5 also used during explosions */
int flipy = source[1] & 0x80;
int flipx = source[1] & 0x40;
if (flip_screen())
{
sx = 240 - sx;
sy = 240 - sy;
flipx = !flipx;
flipy = !flipy;
}
gfx->transpen(bitmap,cliprect, tile, color, flipx, flipy, sx, sy, 0);
source += 4;
}
}
uint32_t battlex_state::screen_update_battlex(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
if (!flip_screen())
m_bg_tilemap->set_scrollx(0, m_scroll_lsb | (m_scroll_msb << 8));
else
m_bg_tilemap->set_scrollx(0, m_scroll_lsb | (m_scroll_msb << 3));
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
draw_sprites(bitmap, cliprect);
return 0;
}

View File

@ -48,6 +48,8 @@
#include "tilemap.h"
namespace {
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
@ -590,10 +592,12 @@ ROM_START( popper )
ROM_LOAD("p.m4", 0x20, 0x20, CRC(384de5c1) SHA1(892c89a01c11671c5708113b4e4c27b84be37ea6))
ROM_END
} // anonymous namespace
//**************************************************************************
// SYSTEM DRIVERS
//**************************************************************************
// YEAR NAME PARENT MACHINE INPUT CLASS INIT ROTATION COMPANY FULLNAME FLAGS
GAME( 1983, popper, 0, popper, popper, popper_state, empty_init, ROT90, "Omori", "Popper", MACHINE_SUPPORTS_SAVE )
GAME( 1983, popper, 0, popper, popper, popper_state, empty_init, ROT90, "Omori Electric Co., Ltd.", "Popper", MACHINE_SUPPORTS_SAVE )