diff --git a/src/mame/drivers/mmagic.cpp b/src/mame/drivers/mmagic.cpp index ac9eb64d633..15304a604f5 100644 --- a/src/mame/drivers/mmagic.cpp +++ b/src/mame/drivers/mmagic.cpp @@ -53,18 +53,11 @@ #include "emupal.h" #include "speaker.h" #include "screen.h" - - -//************************************************************************** -// CONSTANTS / MACROS -//************************************************************************** +#include "tilemap.h" #define LOG_AUDIO 1 - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** +namespace { class mmagic_state : public driver_device { @@ -72,81 +65,226 @@ public: mmagic_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), + m_in(*this, "IN%u", 0), + m_analog(*this, "ANALOG%u", 0), m_screen(*this, "screen"), + m_gfxdecode(*this, "gfxdecode"), m_palette(*this, "palette"), + m_tilemap(*this, "tilemap"), m_samples(*this,"samples"), - m_vram(*this, "vram"), - m_tiles(*this, "tiles"), - m_colors(*this, "colors"), + m_tile_colors(*this, "colors"), m_ball_x(0x00), m_ball_y(0x00), - m_color(0x00), + m_tile_color_base(0x00), m_audio(0x00) { } - void mmagic(machine_config &config); + void config(machine_config& config) + { + // basic machine hardware + I8085A(config, m_maincpu, 6.144_MHz_XTAL); // NEC D8085A + m_maincpu->set_addrmap(AS_PROGRAM, &mmagic_state::mmagic_mem); + m_maincpu->set_addrmap(AS_IO, &mmagic_state::mmagic_io); + + // video hardware + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_raw(6.144_MHz_XTAL, 384, 0, 256, 264, 0, 192); + m_screen->set_screen_update(FUNC(mmagic_state::screen_update)); + + GFXDECODE(config, m_gfxdecode, m_palette, gfxdecode); + + PALETTE(config, m_palette, FUNC(mmagic_state::palette_init), 16); + + TILEMAP(config, m_tilemap, m_gfxdecode, 1, 8, 12, TILEMAP_SCAN_ROWS, 32, 16).set_info_callback(FUNC(mmagic_state::tile_get_info)); + + // sound hardware + SPEAKER(config, "mono").front_center(); + SAMPLES(config, m_samples); + m_samples->set_channels(1); + m_samples->set_samples_names(sample_names); + m_samples->add_route(ALL_OUTPUTS, "mono", 0.5); + // TODO: replace samples with SN76477 + discrete sound + } + +protected: + virtual void machine_start() override + { + save_item(NAME(m_ball_x)); + save_item(NAME(m_ball_y)); + save_item(NAME(m_tile_color_base)); + save_item(NAME(m_audio)); + } private: - uint8_t vblank_r(); - void ball_x_w(uint8_t data); - void ball_y_w(uint8_t data); - void color_w(uint8_t data); - void audio_w(uint8_t data); - - uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - - void mmagic_io(address_map &map); - void mmagic_mem(address_map &map); - - virtual void machine_start() override; - required_device m_maincpu; + required_ioport_array<2> m_in; + required_ioport_array<2> m_analog; required_device m_screen; + required_device m_gfxdecode; required_device m_palette; + required_device m_tilemap; required_device m_samples; - required_shared_ptr m_vram; - required_region_ptr m_tiles; - required_region_ptr m_colors; + required_region_ptr m_tile_colors; uint8_t m_ball_x; uint8_t m_ball_y; - uint8_t m_color; + uint8_t m_tile_color_base; uint8_t m_audio; + + // basic machine hardware + + void mmagic_mem(address_map& map) + { + map.unmap_value_high(); + map(0x0000, 0x17ff).rom(); + map(0x2000, 0x21ff).ram(); + map(0x3000, 0x31ff).ram().w(m_tilemap, FUNC(tilemap_device::write8)).share("tilemap"); + map(0x8002, 0x8002).w(FUNC(mmagic_state::ball_x_w)); + map(0x8003, 0x8003).w(FUNC(mmagic_state::ball_y_w)); + map(0x8004, 0x8004).r(FUNC(mmagic_state::vblank_r)); + } + + void ball_x_w(uint8_t data) + { + m_ball_x = data; + } + + void ball_y_w(uint8_t data) + { + m_ball_y = data; + } + + uint8_t vblank_r() + { + // bit 0 = vblank, other bits unused + return 0xfe | m_screen->vblank(); + } + + void mmagic_io(address_map& map) + { + map.global_mask(0xff); + map(0x80, 0x80).w(FUNC(mmagic_state::color_w)); + map(0x81, 0x81).w(FUNC(mmagic_state::audio_w)); + map(0x85, 0x85).r(FUNC(mmagic_state::paddle_r)); + map(0x86, 0x86).r(FUNC(mmagic_state::buttons_r)); + map(0x87, 0x87).portr("DIPSW"); + } + + void color_w(uint8_t data) + { + // bit 3 is flip screen + flip_screen_set(BIT(data, 3)); + + // bit 6 switches the palette (actually there is only a single differently colored tile) + int tile_color_base = BIT(data, 6) << 7; + if (m_tile_color_base != tile_color_base) + { + m_tilemap->mark_all_dirty(); + m_tile_color_base = tile_color_base; + } + + // other bits are always 0 + } + + void audio_w(uint8_t data) + { + if (LOG_AUDIO) + logerror("audio_w: %02x\n", data); + + data ^= 0xff; + if (data != m_audio) + { + if (BIT(data, 7)) + m_samples->start(0, m_audio & 7); + + m_audio = data; + } + } + + uint8_t paddle_r() + { + return flip_screen() ? m_analog[0]->read() : m_analog[1]->read(); + } + + uint8_t buttons_r() + { + return flip_screen() ? m_in[0]->read() : m_in[1]->read() | (m_in[0]->read() & ~1); + } + + // video hardware + + uint32_t screen_update(screen_device& screen, bitmap_rgb32& bitmap, const rectangle& cliprect) + { + m_tilemap->draw(screen, bitmap, cliprect, 0, 0); + + // draw ball (if not disabled) + if (m_ball_x != 0xff) + { + static const int BALL_SIZE = 4; + int ball_y = (m_ball_y >> 4) * 12 + (m_ball_y & 0x0f); + bitmap.plot_box(flip_screen() ? 255 - m_ball_x : m_ball_x, flip_screen() ? 191 - ball_y : ball_y, BALL_SIZE, BALL_SIZE, rgb_t::white()); + } + + return 0; + } + + void palette_init(palette_device& palette) const + { + for (int i = 0; i < 16; i++) + { + int const r = (!BIT(i, 0) && BIT(i, 1)) ? 0xff : 0x00; + int const g = (!BIT(i, 0) && BIT(i, 2)) ? 0xff : 0x00; + int const b = (!BIT(i, 0) && BIT(i, 3)) ? 0xff : 0x00; + + palette.set_pen_color(i, rgb_t(r, g, b)); + } + } + + static constexpr gfx_layout tile_layout = + { + 8, 12, /* 8 x 12 tiles */ + 128, /* 128 tiles */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + /* x offsets */ + { 3, 2, 1, 0, 7, 6, 5, 4 }, + /* y offsets */ + { 0 * 8, 1 * 8, 2 * 8, 3 * 8, 4 * 8, 5 * 8, 6 * 8, 7 * 8, 8 * 8, 9 * 8, 10 * 8, 11 * 8 }, + 16 * 8 /* every tile takes 16 bytes */ + }; + + static constexpr GFXDECODE_START(gfxdecode) + GFXDECODE_ENTRY("tiles", 0x0000, tile_layout, 0, 8) + GFXDECODE_END + + TILE_GET_INFO_MEMBER(tile_get_info) + { + uint32_t code = m_tilemap->basemem_read(tile_index) & 0x7f; + uint32_t color = m_tile_colors[code | m_tile_color_base]; + + tileinfo.set(0, code, color, 0); + } + + // sound hardware + + static constexpr const char* const sample_names[] = + { + "*mmagic", + "4", + "3", + "5", + "2", + "2-2", + "6", + "6-2", + "1", + nullptr + }; }; -//************************************************************************** -// ADDRESS MAPS -//************************************************************************** - -void mmagic_state::mmagic_mem(address_map &map) -{ - map.unmap_value_high(); - map(0x0000, 0x17ff).rom(); - map(0x2000, 0x21ff).ram(); - map(0x3000, 0x31ff).ram().share("vram"); - map(0x8002, 0x8002).w(FUNC(mmagic_state::ball_x_w)); - map(0x8003, 0x8003).w(FUNC(mmagic_state::ball_y_w)); - map(0x8004, 0x8004).r(FUNC(mmagic_state::vblank_r)); -} - -void mmagic_state::mmagic_io(address_map &map) -{ - map.global_mask(0xff); - map(0x80, 0x80).w(FUNC(mmagic_state::color_w)); - map(0x81, 0x81).w(FUNC(mmagic_state::audio_w)); - map(0x85, 0x85).portr("paddle"); - map(0x86, 0x86).portr("buttons"); - map(0x87, 0x87).portr("dipswitch"); -} - - -//************************************************************************** -// INPUTS -//************************************************************************** - static INPUT_PORTS_START( mmagic ) - PORT_START("dipswitch") + PORT_START("DIPSW") PORT_SERVICE_DIPLOC(0x01, IP_ACTIVE_LOW, "DSW:1") PORT_DIPNAME(0x06, 0x06, DEF_STR(Bonus_Life)) PORT_DIPLOCATION ("DSW:2,3") PORT_DIPSETTING(0x00, "30000") @@ -162,7 +300,7 @@ static INPUT_PORTS_START( mmagic ) PORT_DIPUNUSED_DIPLOC(0x40, IP_ACTIVE_LOW, "DSW:7" ) PORT_DIPUNUSED_DIPLOC(0x80, IP_ACTIVE_LOW, "DSW:8" ) - PORT_START("buttons") + PORT_START("IN0") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_START1) PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_START2) @@ -172,168 +310,17 @@ static INPUT_PORTS_START( mmagic ) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Debug?") // checked once at startup - PORT_START("paddle") + PORT_START("IN1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(2) + + PORT_START("ANALOG0") PORT_BIT(0xff, 0x80, IPT_PADDLE) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) PORT_CENTERDELTA(0) + + PORT_START("ANALOG1") + PORT_BIT(0xff, 0x80, IPT_PADDLE) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(30) PORT_KEYDELTA(30) PORT_CENTERDELTA(0) PORT_PLAYER(2) INPUT_PORTS_END -//************************************************************************** -// VIDEO EMULATION -//************************************************************************** - -uint8_t mmagic_state::vblank_r() -{ - uint8_t data = 0; - - // bit 0 = vblank - data |= m_screen->vblank() << 0; - - // other bits unused - data |= 0xfe; - - return data; -} - -void mmagic_state::ball_x_w(uint8_t data) -{ - m_ball_x = data; -} - -void mmagic_state::ball_y_w(uint8_t data) -{ - m_ball_y = data; -} - -void mmagic_state::color_w(uint8_t data) -{ - // bit 3 is always set - // bit 6 switches the palette (actually there is only a single differently colored tile) - // other bits are always 0 - m_color = data; -} - -uint32_t mmagic_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) -{ - // draw playfield - for (int y = 0; y < 192 / 12; y++) - { - for (int x = 0; x < 256 / 8; x++) - { - uint8_t code = m_vram[(y * 32) + x] & 0x7f; - - // normal palette 00..7f, alternate palette 80..ff - uint8_t color = m_colors[code | (BIT(m_color, 6) << 7)]; - - // draw one tile - for (int tx = 0; tx < 12; tx++) - { - uint8_t gfx = m_tiles[(code << 4) + tx]; - - bitmap.pix(y * 12 + tx, x * 8 + 0) = BIT(gfx, 4) ? rgb_t::black() : m_palette->pen_color(color); - bitmap.pix(y * 12 + tx, x * 8 + 1) = BIT(gfx, 5) ? rgb_t::black() : m_palette->pen_color(color); - bitmap.pix(y * 12 + tx, x * 8 + 2) = BIT(gfx, 6) ? rgb_t::black() : m_palette->pen_color(color); - bitmap.pix(y * 12 + tx, x * 8 + 3) = BIT(gfx, 7) ? rgb_t::black() : m_palette->pen_color(color); - - bitmap.pix(y * 12 + tx, x * 8 + 4) = BIT(gfx, 0) ? rgb_t::black() : m_palette->pen_color(color); - bitmap.pix(y * 12 + tx, x * 8 + 5) = BIT(gfx, 1) ? rgb_t::black() : m_palette->pen_color(color); - bitmap.pix(y * 12 + tx, x * 8 + 6) = BIT(gfx, 2) ? rgb_t::black() : m_palette->pen_color(color); - bitmap.pix(y * 12 + tx, x * 8 + 7) = BIT(gfx, 3) ? rgb_t::black() : m_palette->pen_color(color); - } - } - } - - // draw ball (if not disabled) - if (m_ball_x != 0xff) - { - static const int BALL_SIZE = 4; - int ball_y = (m_ball_y >> 4) * 12 + (m_ball_y & 0x0f); - bitmap.plot_box(m_ball_x - BALL_SIZE + 1, ball_y - BALL_SIZE + 1, BALL_SIZE, BALL_SIZE, rgb_t::white()); - } - - return 0; -} - - -//************************************************************************** -// AUDIO EMULATION -//************************************************************************** - -static const char *const mmagic_sample_names[] = -{ - "*mmagic", - "4", - "3", - "5", - "2", - "2-2", - "6", - "6-2", - "1", - nullptr -}; - -void mmagic_state::audio_w(uint8_t data) -{ - if (LOG_AUDIO) - logerror("audio_w: %02x\n", data); - - data ^= 0xff; - if (data != m_audio) - { - if (BIT(data, 7)) - m_samples->start(0, m_audio & 7); - - m_audio = data; - } -} - - -//************************************************************************** -// DRIVER INIT -//************************************************************************** - -void mmagic_state::machine_start() -{ - // register for save states - save_item(NAME(m_ball_x)); - save_item(NAME(m_ball_y)); - save_item(NAME(m_color)); - save_item(NAME(m_audio)); -} - - -//************************************************************************** -// MACHINE DEFINTIONS -//************************************************************************** - -void mmagic_state::mmagic(machine_config &config) -{ - // basic machine hardware - I8085A(config, m_maincpu, 6.144_MHz_XTAL); // NEC D8085A - m_maincpu->set_addrmap(AS_PROGRAM, &mmagic_state::mmagic_mem); - m_maincpu->set_addrmap(AS_IO, &mmagic_state::mmagic_io); - - // video hardware - SCREEN(config, m_screen, SCREEN_TYPE_RASTER); - m_screen->set_raw(6.144_MHz_XTAL, 384, 0, 256, 264, 0, 192); - m_screen->set_screen_update(FUNC(mmagic_state::screen_update)); - - PALETTE(config, m_palette, palette_device::RGB_3BIT); - - // sound hardware - SPEAKER(config, "mono").front_center(); - SAMPLES(config, m_samples); - m_samples->set_channels(1); - m_samples->set_samples_names(mmagic_sample_names); - m_samples->add_route(ALL_OUTPUTS, "mono", 0.5); - // TODO: replace samples with SN76477 + discrete sound -} - - -//************************************************************************** -// ROM DEFINITIONS -//************************************************************************** - ROM_START( mmagic ) ROM_REGION(0x1800, "maincpu", 0) ROM_LOAD("1ai.2a", 0x0000, 0x0400, CRC(ec772e2e) SHA1(7efc1bbb24b2ed73c518aea1c4ef4b9a93034e31)) @@ -342,20 +329,19 @@ ROM_START( mmagic ) ROM_LOAD("4ai.45a", 0x0c00, 0x0400, CRC(3048bd6c) SHA1(740051589f6ba44b2ee68edf76a3177bb973d78e)) ROM_LOAD("5ai.5a", 0x1000, 0x0400, CRC(2cab8f04) SHA1(203a3c005f18f968cd14c972bbb9fd7e0fc3b670)) // location 6a is unpopulated, if the "debug" switch is activated on bootup it would jump here + ROM_FILL(0x1400, 0x0400, 0xff) ROM_REGION(0x800, "tiles", 0) ROM_LOAD("6h.6hi", 0x000, 0x200, CRC(b6321b6f) SHA1(06611f7419d2982e006a3e81b79677e59e194f38)) ROM_LOAD("7h.7hi", 0x200, 0x200, CRC(9ec0e82c) SHA1(29983f690a1b6134bb1983921f42c14898788095)) ROM_LOAD("6j.6jk", 0x400, 0x200, CRC(7ce83302) SHA1(1870610ff07ab11622e183e04e3fce29328ff291)) + ROM_FILL(0x600, 0x200, 0xff) ROM_REGION(0x200, "colors", ROMREGION_INVERT) ROM_LOAD("7j.7jk", 0x000, 0x200, CRC(b7eb8e1c) SHA1(b65a8efb88668dcf1c1d00e31a9b15a67c2972c8)) ROM_END - -//************************************************************************** -// GAME DRIVERS -//************************************************************************** +} // anonymous namespace // YEAR NAME PARENT MACHINE INPUT CLASS INIT ROT COMPANY FULLNAME FLAGS -GAME( 1979, mmagic, 0, mmagic, mmagic, mmagic_state, empty_init, ROT270, "Nintendo", "Monkey Magic", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND ) +GAME( 1979, mmagic, 0, config, mmagic, mmagic_state, empty_init, ROT90, "Nintendo", "Monkey Magic", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND )