diff --git a/hash/microvision.xml b/hash/microvision.xml index a408cfd30ed..076f824bb76 100644 --- a/hash/microvision.xml +++ b/hash/microvision.xml @@ -106,7 +106,7 @@ The "overlay" feature indicates screen/keypad overlay - + @@ -123,10 +123,10 @@ The "overlay" feature indicates screen/keypad overlay - + - + diff --git a/src/mame/drivers/mephisto_montec.cpp b/src/mame/drivers/mephisto_montec.cpp index e44b637c45f..1ac523cfeb9 100644 --- a/src/mame/drivers/mephisto_montec.cpp +++ b/src/mame/drivers/mephisto_montec.cpp @@ -14,6 +14,7 @@ TODO: - split driver into several files? + - megaiv/smondial leds are tri-color - why are megaiv/smondial2 beeps noisy? - add Monte Carlo IV (non-LE) - add MM 1000 module diff --git a/src/mame/drivers/microvsn.cpp b/src/mame/drivers/microvsn.cpp index 83b4d7e7263..d7b5230d397 100644 --- a/src/mame/drivers/microvsn.cpp +++ b/src/mame/drivers/microvsn.cpp @@ -1,7 +1,7 @@ // license:BSD-3-Clause // copyright-holders:Wilbert Pol, hap // thanks-to:Dan Boris, Kevin Horton, Sean Riddle -/*************************************************************************** +/****************************************************************************** Milton Bradley MicroVision, handheld game console @@ -11,21 +11,16 @@ Hardware notes: - no CPU on console, it is on the cartridge 12 games were released, all of them have a TMS1100 MCU. The first couple of -games had an I8021 MCU at first, but Milton Bradley switched to TMS1100. - -Since the microcontrollers were on the cartridges it was possible to have -different clocks on different games. -The Connect Four I8021 game is clocked at around 2MHz. The TMS1100 versions -of the games were clocked at around 500KHz, 550KHz, or 350KHz. +games had an Intel 8021 MCU at first, but Milton Bradley switched to TMS1100. Each game had a screen- and keypad overlay attached to it, MAME external artwork is recommended. It's also advised to disable screen filtering, eg. with -prescale, or on Windows simply -video gdi. TODO: -- Finish support for i8021 based cartridges +- dump/add remaining 8021 cartridges -****************************************************************************/ +******************************************************************************/ #include "emu.h" @@ -33,6 +28,7 @@ TODO: #include "bus/generic/slot.h" #include "cpu/mcs48/mcs48.h" #include "cpu/tms1000/tms1100.h" +#include "machine/timer.h" #include "sound/dac.h" #include "sound/volt_reg.h" #include "video/hlcd0488.h" @@ -43,21 +39,21 @@ TODO: #include "screen.h" #include "speaker.h" -//#define VERBOSE 1 -#include "logmacro.h" +namespace { class microvision_state : public driver_device { public: microvision_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), - m_dac( *this, "dac" ), - m_i8021( *this, "i8021_cpu" ), m_tms1100( *this, "tms1100_cpu" ), + m_i8021( *this, "i8021_cpu" ), m_lcd(*this, "lcd"), m_lcd_pwm(*this, "lcd_pwm"), + m_dac( *this, "dac" ), m_cart(*this, "cartslot"), + m_paddle_timer(*this, "paddle_timer"), m_inputs(*this, "COL%u", 0), m_paddle(*this, "PADDLE"), m_conf(*this, "CONF"), @@ -69,56 +65,25 @@ public: DECLARE_INPUT_CHANGED_MEMBER(conf_changed) { apply_settings(); } protected: - static constexpr device_timer_id TIMER_PADDLE = 0; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - virtual void machine_start() override; virtual void machine_reset() override; + virtual void device_post_load() override { apply_settings(); } private: - uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - - DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart_load); - - // i8021 interface - DECLARE_WRITE8_MEMBER(i8021_p0_write); - DECLARE_WRITE8_MEMBER(i8021_p1_write); - DECLARE_WRITE8_MEMBER(i8021_p2_write); - DECLARE_READ_LINE_MEMBER(i8021_t1_read); - DECLARE_READ8_MEMBER(i8021_bus_read); - - // TMS1100 interface - DECLARE_READ8_MEMBER(tms1100_read_k); - DECLARE_WRITE16_MEMBER(tms1100_write_o); - DECLARE_WRITE16_MEMBER(tms1100_write_r); - u32 tms1100_decode_micro(offs_t offset); - - required_device m_dac; - optional_device m_i8021; optional_device m_tms1100; + optional_device m_i8021; required_device m_lcd; required_device m_lcd_pwm; + required_device m_dac; required_device m_cart; + required_device m_paddle_timer; required_ioport_array<3> m_inputs; required_ioport m_paddle; required_ioport m_conf; output_finder<> m_overlay_out; - // Timers - emu_timer *m_paddle_timer; - - // i8021 variables - uint8_t m_p0; - uint8_t m_p2; - uint8_t m_t1; - - // tms1100 variables - uint16_t m_r; - uint16_t m_o; - - // generic variables - DECLARE_WRITE16_MEMBER(lcd_output_w); - + u32 tms1100_decode_micro(offs_t offset); + DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart_load); void apply_settings(void); u8 m_pla_auto; @@ -126,238 +91,51 @@ private: u16 m_button_mask; bool m_paddle_auto; bool m_paddle_on; -}; + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + DECLARE_WRITE16_MEMBER(lcd_output_w) { m_lcd_pwm->matrix(offset, data); } + + // TMS1100 interface + DECLARE_READ8_MEMBER(tms1100_k_r); + DECLARE_WRITE16_MEMBER(tms1100_o_w); + DECLARE_WRITE16_MEMBER(tms1100_r_w); + + u16 m_r = 0; + + // Intel 8021 interface + DECLARE_READ8_MEMBER(i8021_p0_r); + DECLARE_WRITE8_MEMBER(i8021_p0_w); + DECLARE_WRITE8_MEMBER(i8021_p1_w); + DECLARE_WRITE8_MEMBER(i8021_p2_w); + DECLARE_READ_LINE_MEMBER(i8021_t1_r); + + u8 m_p0 = 0xff; + u8 m_p2 = 0xff; +}; void microvision_state::machine_start() { - m_paddle_timer = timer_alloc(TIMER_PADDLE); m_overlay_out.resolve(); + // register for savestates + save_item(NAME(m_r)); save_item(NAME(m_p0)); save_item(NAME(m_p2)); - save_item(NAME(m_t1)); - save_item(NAME(m_r)); - save_item(NAME(m_o)); -} + // don't save: m_pla_auto, m_overlay_auto, m_paddle_auto, + // m_button_mask, m_paddle_on +} void microvision_state::machine_reset() { apply_settings(); - - m_o = 0; - m_r = 0; - m_p0 = 0; - m_p2 = 0; - m_t1 = 0; - - m_paddle_timer->adjust(attotime::never); } -uint32_t microvision_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) -{ - for (int y = 0; y < 16; y++) - { - for (int x = 0; x < 16; x++) - { - // simulate LCD persistence - int p = m_lcd_pwm->read_element_bri(y ^ 15, x ^ 15) * 25000; - p = (p > 255) ? 0 : p ^ 255; - - bitmap.pix32(y, x) = p << 16 | p << 8 | p; - } - } - - return 0; -} - - - -WRITE16_MEMBER( microvision_state::lcd_output_w ) -{ - m_lcd_pwm->matrix(offset, data); -} - - -void microvision_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - switch ( id ) - { - case TIMER_PADDLE: - m_t1 = 0; - break; - } -} - - -/* - x--- ---- KEY3 - -x-- ---- KEY4 - --x- ---- KEY5 - ---x ---- KEY6 - ---- x--- - ---- -x-- KEY0 - ---- --x- KEY1 - ---- ---x KEY2 -*/ -WRITE8_MEMBER( microvision_state::i8021_p0_write ) -{ - LOG( "p0_write: %02x\n", data ); - - m_p0 = data; -} - - -/* - x--- ---- LCD3 - -x-- ---- LCD2 - --x- ---- LCD1 - ---x ---- LCD0 - ---- --x- LCD5 - ---- ---x LCD4 -*/ -WRITE8_MEMBER( microvision_state::i8021_p1_write ) -{ - LOG( "p1_write: %02x\n", data ); - - m_lcd->data_w(data >> 4 & 0xf); - m_lcd->latch_pulse_w(BIT(data, 0)); - m_lcd->data_clk_w(BIT(data, 1)); -} - - -/* ----- xx-- CAP2 (paddle) ----- --x- SPKR1 ----- ---x SPKR0 -*/ -WRITE8_MEMBER( microvision_state::i8021_p2_write ) -{ - LOG( "p2_write: %02x\n", data ); - - m_p2 = data; - - m_dac->write(m_p2 & 0x03); - - if ( m_p2 & 0x0c ) - { - m_t1 = 1; - // Stop paddle timer - m_paddle_timer->adjust( attotime::never ); - } - else - { - // Start paddle timer (min is 160uS, max is 678uS) - uint8_t paddle = 255 - ioport("PADDLE")->read(); - m_paddle_timer->adjust( attotime::from_usec(160 + ( 518 * paddle ) / 255 ) ); - } -} - - -READ_LINE_MEMBER( microvision_state::i8021_t1_read ) -{ - return m_t1; -} - - -READ8_MEMBER( microvision_state::i8021_bus_read ) -{ - uint8_t data = m_p0; - - uint8_t col0 = ioport("COL0")->read(); - uint8_t col1 = ioport("COL1")->read(); - uint8_t col2 = ioport("COL2")->read(); - - // Row scanning - if ( ! ( m_p0 & 0x80 ) ) - { - uint8_t t = ( ( col0 & 0x01 ) << 2 ) | ( ( col1 & 0x01 ) << 1 ) | ( col2 & 0x01 ); - - data &= ( t ^ 0xFF ); - } - if ( ! ( m_p0 & 0x40 ) ) - { - uint8_t t = ( ( col0 & 0x02 ) << 1 ) | ( col1 & 0x02 ) | ( ( col2 & 0x02 ) >> 1 ); - - data &= ( t ^ 0xFF ); - } - if ( ! ( m_p0 & 0x20 ) ) - { - uint8_t t = ( col0 & 0x04 ) | ( ( col1 & 0x04 ) >> 1 ) | ( ( col2 & 0x04 ) >> 2 ); - - data &= ( t ^ 0xFF ); - } - if ( ! ( m_p0 & 0x10 ) ) - { - uint8_t t = ( ( col0 & 0x08 ) >> 1 ) | ( ( col1 & 0x08 ) >> 2 ) | ( ( col2 & 0x08 ) >> 3 ); - - data &= ( t ^ 0xFF ); - } - return data; -} - - -READ8_MEMBER( microvision_state::tms1100_read_k ) -{ - uint8_t data = 0; - - LOG("read_k\n"); - - // multiplexed inputs - for (int i = 0; i < 3; i++) - if (BIT(m_r, i + 8)) - data |= m_inputs[i]->read() & (m_button_mask >> (i * 4) & 0xf); - - // K8: paddle capacitor - if (m_paddle_on) - { - u8 paddle = m_paddle_timer->enabled() ? 0 : BIT(m_r, 2); - return paddle << 3 | data; - } - else - return data; -} - - -WRITE16_MEMBER( microvision_state::tms1100_write_o ) -{ - LOG("write_o: %04x\n", data); - - // O0-O3: LCD data - m_lcd->data_w(data & 0xf); -} - - - -WRITE16_MEMBER( microvision_state::tms1100_write_r ) -{ - LOG("write_r: %04x\n", data); - - // R2: charge paddle capacitor - if (~m_r & data & 4 && m_paddle_on) - { - // range is ~360us to ~2663us (measured on 4952-79 REV B PCB) - // note that the games don't use the whole range, so there's a deadzone around the edges - float step = (2000 - 500) / 255.0; // approximate it - m_paddle_timer->adjust(attotime::from_usec(500 + m_paddle->read() * step)); - } - - // R0: speaker lead 2 - // R1: speaker lead 1 (GND on some carts) - m_dac->write((BIT(data, 0) << 1) | BIT(data, 1)); - - // R6: LCD latch pulse - // R7: LCD data clock - m_lcd->latch_pulse_w(BIT(data, 6)); - m_lcd->data_clk_w(BIT(data, 7)); - - // R8-R10: input mux - m_r = data; -} - +/****************************************************************************** + Cartridge Init +******************************************************************************/ static const u16 microvision_output_pla[2][0x20] = { @@ -424,7 +202,7 @@ DEVICE_IMAGE_LOAD_MEMBER(microvision_state::cart_load) m_cart->common_load_rom(m_cart->get_rom_base(), size, "rom"); // set default settings - u32 clock = (size == 0x400) ? 2000000 : 500000; + u32 clock = (size == 0x400) ? 3500000 : 500000; m_pla_auto = 0; m_overlay_auto = 0; m_paddle_auto = false; @@ -467,8 +245,31 @@ void microvision_state::apply_settings() // overlay physically restricts button panel switch (overlay) { + case 1: case 5: + m_button_mask = 0x454; + break; + case 2: case 8: case 10: + m_button_mask = 0x555; + break; + case 3: + m_button_mask = 0x858; + break; + case 4: + m_button_mask = 0xaea; + break; + case 6: + m_button_mask = 0xaaa; + break; + case 11: + m_button_mask = 0xafa; + break; + case 12: + m_button_mask = 0x404; + break; + default: m_button_mask = 0xfff; + break; } u8 pla = ((conf & 0x18) == 0x10) ? m_pla_auto : (conf >> 3 & 1); @@ -478,6 +279,155 @@ void microvision_state::apply_settings() } + +/****************************************************************************** + Video +******************************************************************************/ + +uint32_t microvision_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + for (int y = 0; y < 16; y++) + { + for (int x = 0; x < 16; x++) + { + // simulate LCD persistence + int p = m_lcd_pwm->read_element_bri(y ^ 15, x ^ 15) * 25000; + p = (p > 255) ? 0 : p ^ 255; + + bitmap.pix32(y, x) = p << 16 | p << 8 | p; + } + } + + return 0; +} + + + +/****************************************************************************** + I/O +******************************************************************************/ + +// TMS1100 interface + +READ8_MEMBER(microvision_state::tms1100_k_r) +{ + u8 data = 0; + + // multiplexed inputs + for (int i = 0; i < 3; i++) + if (BIT(m_r, i + 8)) + data |= m_inputs[i]->read() & (m_button_mask >> (i * 4) & 0xf); + + // K8: paddle capacitor + if (m_paddle_on) + { + u8 paddle = m_paddle_timer->enabled() ? 0 : BIT(m_r, 2); + return paddle << 3 | data; + } + else + return data; +} + +WRITE16_MEMBER(microvision_state::tms1100_o_w) +{ + // O0-O3: LCD data + m_lcd->data_w(data & 0xf); +} + +WRITE16_MEMBER(microvision_state::tms1100_r_w) +{ + // R2: charge paddle capacitor when high + if (~m_r & data & 4 && m_paddle_on) + { + // note that the games don't use the whole range, so there's a deadzone around the edges + const float step = (2000 - 500) / 255.0; // approximation + m_paddle_timer->adjust(attotime::from_usec(500 + m_paddle->read() * step)); + } + + // R0: speaker lead 2 + // R1: speaker lead 1 (GND on some carts) + m_dac->write((BIT(data, 0) << 1) | BIT(data, 1)); + + // R6: LCD latch pulse + // R7: LCD data clock + m_lcd->latch_pulse_w(BIT(data, 6)); + m_lcd->data_clk_w(BIT(data, 7)); + + // R8-R10: input mux + m_r = data; +} + + +// Intel 8021 interface + +READ8_MEMBER( microvision_state::i8021_p0_r ) +{ + u8 in[3]; + for (int i = 0; i < 3; i++) + in[i] = m_inputs[i]->read() & (m_button_mask >> (i * 4) & 0xf); + + u8 data = 0; + + // P00-P02: multiplexed inputs from P04-P07 + for (int i = 0; i < 3; i++) + if (~(m_p0 >> 4) & in[i]) + data |= 1 << i; + + // P04-P07: multiplexed inputs from P00-P02 + for (int i = 0; i < 3; i++) + if (BIT(~m_p0, i)) + data |= in[i] << 4; + + return ~data & m_p0; +} + +WRITE8_MEMBER(microvision_state::i8021_p0_w) +{ + // P0-P2, P4-P7: input mux + m_p0 = data; +} + +WRITE8_MEMBER(microvision_state::i8021_p1_w) +{ + // P14-P17: lcd data + m_lcd->data_w(data >> 4 & 0xf); + + // P10: lcd latch pulse + // P11: lcd data clk + m_lcd->latch_pulse_w(BIT(data, 0)); + m_lcd->data_clk_w(BIT(data, 1)); +} + +WRITE8_MEMBER(microvision_state::i8021_p2_w) +{ + // P20: speaker lead 1 + // P21: speaker lead 2 + m_dac->write(data & 3); + + // P22,P23: charge paddle capacitor when low + if (m_p2 & 0xc && (data & 0xc) == 0 && m_paddle_on) + { + const float step = (1000 - 10) / 255.0; // approximation + m_paddle_timer->adjust(attotime::from_usec(10 + (m_paddle->read() ^ 0xff) * step)); + } + + m_p2 = data; +} + +READ_LINE_MEMBER(microvision_state::i8021_t1_r) +{ + // T1: paddle capacitor (active low) + int active = (m_p2 & 0xc) ? 1 : 0; + active |= m_paddle_timer->enabled() ? 1 : 0; + return (m_paddle_on) ? active : 1; +} + + + +/****************************************************************************** + Input Ports +******************************************************************************/ + static INPUT_PORTS_START( microvision ) PORT_START("COL0") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON12 ) PORT_CODE(KEYCODE_C) @@ -515,22 +465,29 @@ static INPUT_PORTS_START( microvision ) INPUT_PORTS_END + +/****************************************************************************** + Machine Configs +******************************************************************************/ + void microvision_state::microvision(machine_config &config) { /* basic machine hardware */ - I8021(config, m_i8021, 0); - m_i8021->bus_out_cb().set(FUNC(microvision_state::i8021_p0_write)); - m_i8021->p1_out_cb().set(FUNC(microvision_state::i8021_p1_write)); - m_i8021->p2_out_cb().set(FUNC(microvision_state::i8021_p2_write)); - m_i8021->t1_in_cb().set(FUNC(microvision_state::i8021_t1_read)); - m_i8021->bus_in_cb().set(FUNC(microvision_state::i8021_bus_read)); - TMS1100(config, m_tms1100, 0); m_tms1100->set_output_pla(microvision_output_pla[0]); m_tms1100->set_decode_micro().set(FUNC(microvision_state::tms1100_decode_micro)); - m_tms1100->k().set(FUNC(microvision_state::tms1100_read_k)); - m_tms1100->o().set(FUNC(microvision_state::tms1100_write_o)); - m_tms1100->r().set(FUNC(microvision_state::tms1100_write_r)); + m_tms1100->k().set(FUNC(microvision_state::tms1100_k_r)); + m_tms1100->o().set(FUNC(microvision_state::tms1100_o_w)); + m_tms1100->r().set(FUNC(microvision_state::tms1100_r_w)); + + I8021(config, m_i8021, 0); + m_i8021->bus_in_cb().set(FUNC(microvision_state::i8021_p0_r)); + m_i8021->bus_out_cb().set(FUNC(microvision_state::i8021_p0_w)); + m_i8021->p1_out_cb().set(FUNC(microvision_state::i8021_p1_w)); + m_i8021->p2_out_cb().set(FUNC(microvision_state::i8021_p2_w)); + m_i8021->t1_in_cb().set(FUNC(microvision_state::i8021_t1_r)); + + TIMER(config, "paddle_timer").configure_generic(nullptr); /* video hardware */ HLCD0488(config, m_lcd); @@ -561,6 +518,11 @@ void microvision_state::microvision(machine_config &config) } + +/****************************************************************************** + ROM Definitions +******************************************************************************/ + ROM_START( microvsn ) // nothing here yet, ROM is on the cartridge ROM_REGION( 0x400, "i8021_cpu", ROMREGION_ERASE00 ) @@ -569,5 +531,13 @@ ROM_START( microvsn ) ROM_REGION( 365, "tms1100_cpu:opla", ROMREGION_ERASE00 ) ROM_END +} // anonymous namespace -CONS( 1979, microvsn, 0, 0, microvision, microvision, microvision_state, empty_init, "Milton Bradley", "MicroVision", MACHINE_NOT_WORKING | MACHINE_REQUIRES_ARTWORK ) + + +/****************************************************************************** + Drivers +******************************************************************************/ + +// YEAR NAME PARENT CMP MACHINE INPUT CLASS INIT COMPANY, FULLNAME, FLAGS +CONS( 1979, microvsn, 0, 0, microvision, microvision, microvision_state, empty_init, "Milton Bradley", "MicroVision", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE | MACHINE_REQUIRES_ARTWORK ) diff --git a/src/mame/drivers/sag.cpp b/src/mame/drivers/sag.cpp index c58e9fa3de2..5a3caf8468f 100644 --- a/src/mame/drivers/sag.cpp +++ b/src/mame/drivers/sag.cpp @@ -1,7 +1,7 @@ // license:BSD-3-Clause // copyright-holders:hap // thanks-to:Kevin Horton, Sean Riddle -/*************************************************************************** +/****************************************************************************** Entex Select-A-Game Machine, handheld game console. Technically, the main unit is the peripheral(buttons, display, speaker, power), @@ -32,7 +32,7 @@ are played, Space Invader 2 is an exception. TODO: - add the rest of the games -***************************************************************************/ +******************************************************************************/ #include "emu.h"