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"