summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/microvsn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/microvsn.c')
-rw-r--r--src/mame/drivers/microvsn.c707
1 files changed, 707 insertions, 0 deletions
diff --git a/src/mame/drivers/microvsn.c b/src/mame/drivers/microvsn.c
new file mode 100644
index 00000000000..e322bf47615
--- /dev/null
+++ b/src/mame/drivers/microvsn.c
@@ -0,0 +1,707 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol
+/***************************************************************************
+
+ Milton Bradley MicroVision
+
+ To Do:
+ * Add support for the paddle control
+ * Finish support for i8021 based cartridges
+
+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 300KHz.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+#include "cpu/tms0980/tms0980.h"
+#include "sound/dac.h"
+#include "rendlay.h"
+
+#include "bus/generic/slot.h"
+#include "bus/generic/carts.h"
+
+
+#define LOG 0
+
+
+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, "maincpu1" ),
+ m_tms1100( *this, "maincpu2" ),
+ m_cart(*this, "cartslot")
+ { }
+
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+ DECLARE_PALETTE_INIT(microvision);
+ DECLARE_MACHINE_START(microvision);
+ DECLARE_MACHINE_RESET(microvision);
+
+ void screen_vblank(screen_device &screen, bool state);
+ DECLARE_DEVICE_IMAGE_LOAD_MEMBER( microvsn_cart );
+
+ // i8021 interface
+ DECLARE_WRITE8_MEMBER(i8021_p0_write);
+ DECLARE_WRITE8_MEMBER(i8021_p1_write);
+ DECLARE_WRITE8_MEMBER(i8021_p2_write);
+ DECLARE_READ8_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);
+
+ // enums
+ enum cpu_type
+ {
+ CPU_TYPE_I8021,
+ CPU_TYPE_TMS1100
+ };
+
+ enum pcb_type
+ {
+ PCB_TYPE_4952_REV_A,
+ PCB_TYPE_4952_9_REV_B,
+ PCB_TYPE_4971_REV_C,
+ PCB_TYPE_7924952D02,
+ PCB_TYPE_UNKNOWN
+ };
+
+ enum rc_type
+ {
+ RC_TYPE_100PF_21_0K,
+ RC_TYPE_100PF_23_2K,
+ RC_TYPE_100PF_39_4K,
+ RC_TYPE_UNKNOWN
+ };
+
+ cpu_type m_cpu_type;
+ pcb_type m_pcb_type;
+ rc_type m_rc_type;
+
+protected:
+ required_device<dac_device> m_dac;
+ required_device<cpu_device> m_i8021;
+ required_device<cpu_device> m_tms1100;
+ required_device<generic_slot_device> m_cart;
+
+ // Timers
+ static const device_timer_id TIMER_PADDLE = 0;
+ emu_timer *m_paddle_timer;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ // i8021 variables
+ UINT8 m_p0;
+ UINT8 m_p2;
+ UINT8 m_t1;
+
+ // tms1100 variables
+ UINT16 m_r;
+ UINT16 m_o;
+
+ // generic variables
+ void update_lcd();
+ void lcd_write(UINT8 control, UINT8 data);
+ void speaker_write(UINT8 speaker);
+ bool m_pla;
+
+ UINT8 m_lcd_latch[8];
+ UINT8 m_lcd_holding_latch[8];
+ UINT8 m_lcd_latch_index;
+ UINT8 m_lcd[16][16];
+ UINT8 m_lcd_control_old;
+};
+
+
+PALETTE_INIT_MEMBER(microvision_state,microvision)
+{
+ palette.set_pen_color( 15, 0x00, 0x00, 0x00 );
+ palette.set_pen_color( 14, 0x11, 0x11, 0x11 );
+ palette.set_pen_color( 13, 0x22, 0x22, 0x22 );
+ palette.set_pen_color( 12, 0x33, 0x33, 0x33 );
+ palette.set_pen_color( 11, 0x44, 0x44, 0x44 );
+ palette.set_pen_color( 10, 0x55, 0x55, 0x55 );
+ palette.set_pen_color( 9, 0x66, 0x66, 0x66 );
+ palette.set_pen_color( 8, 0x77, 0x77, 0x77 );
+ palette.set_pen_color( 7, 0x88, 0x88, 0x88 );
+ palette.set_pen_color( 6, 0x99, 0x99, 0x99 );
+ palette.set_pen_color( 5, 0xaa, 0xaa, 0xaa );
+ palette.set_pen_color( 4, 0xbb, 0xbb, 0xbb );
+ palette.set_pen_color( 3, 0xcc, 0xcc, 0xcc );
+ palette.set_pen_color( 2, 0xdd, 0xdd, 0xdd );
+ palette.set_pen_color( 1, 0xee, 0xee, 0xee );
+ palette.set_pen_color( 0, 0xff, 0xff, 0xff );
+}
+
+
+MACHINE_START_MEMBER(microvision_state, microvision)
+{
+ m_paddle_timer = timer_alloc(TIMER_PADDLE);
+
+ 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));
+ save_item(NAME(m_lcd_latch));
+ save_item(NAME(m_lcd_latch_index));
+ save_item(NAME(m_lcd));
+ save_item(NAME(m_lcd_control_old));
+ save_item(NAME(m_pla));
+ save_item(NAME(m_lcd_holding_latch));
+}
+
+
+MACHINE_RESET_MEMBER(microvision_state, microvision)
+{
+ for( int i = 0; i < 8; i++ )
+ {
+ m_lcd_latch[i] = 0;
+ }
+
+ for( int i = 0; i < 16; i++ )
+ {
+ for ( int j = 0; j < 16; j++ )
+ {
+ m_lcd[i][j] = 0;
+ }
+ }
+
+ m_o = 0;
+ m_r = 0;
+ m_p0 = 0;
+ m_p2 = 0;
+ m_t1 = 0;
+
+ m_paddle_timer->adjust( attotime::never );
+
+ switch ( m_cpu_type )
+ {
+ case CPU_TYPE_I8021:
+ m_i8021->resume( SUSPEND_REASON_DISABLE );
+ m_tms1100->suspend( SUSPEND_REASON_DISABLE, 0 );
+ break;
+
+ case CPU_TYPE_TMS1100:
+ m_i8021->suspend( SUSPEND_REASON_DISABLE, 0 );
+ m_tms1100->resume( SUSPEND_REASON_DISABLE );
+
+ switch ( m_rc_type )
+ {
+ case RC_TYPE_100PF_21_0K:
+ static_set_clock( m_tms1100, 550000 );
+ break;
+
+ case RC_TYPE_100PF_23_2K:
+ case RC_TYPE_UNKNOWN: // Default to most occurring setting
+ static_set_clock( m_tms1100, 500000 );
+ break;
+
+ case RC_TYPE_100PF_39_4K:
+ static_set_clock( m_tms1100, 300000 );
+ break;
+ }
+ break;
+ }
+}
+
+
+void microvision_state::update_lcd()
+{
+ UINT16 row = ( m_lcd_holding_latch[0] << 12 ) | ( m_lcd_holding_latch[1] << 8 ) | ( m_lcd_holding_latch[2] << 4 ) | m_lcd_holding_latch[3];
+ UINT16 col = ( m_lcd_holding_latch[4] << 12 ) | ( m_lcd_holding_latch[5] << 8 ) | ( m_lcd_holding_latch[6] << 4 ) | m_lcd_holding_latch[7];
+
+ if (LOG) logerror("row = %04x, col = %04x\n", row, col );
+ for ( int i = 0; i < 16; i++ )
+ {
+ UINT16 temp = row;
+
+ for ( int j = 0; j < 16; j++ )
+ {
+ if ( ( temp & col ) & 0x8000 )
+ {
+ m_lcd[j][i] = 15;
+ }
+ temp <<= 1;
+ }
+ col <<= 1;
+ }
+}
+
+
+UINT32 microvision_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ for ( UINT8 i = 0; i < 16; i++ )
+ {
+ for ( UINT8 j = 0; j < 16; j++ )
+ {
+ bitmap.pix16(i,j) = m_lcd [i] [j];
+ }
+ }
+
+ return 0;
+}
+
+
+void microvision_state::screen_vblank(screen_device &screen, bool state)
+{
+ if ( state )
+ {
+ for ( int i = 0; i < 16; i++ )
+ {
+ for ( int j= 0; j < 16; j++ )
+ {
+ if ( m_lcd[i][j] )
+ {
+ m_lcd[i][j]--;
+ }
+ }
+ }
+ update_lcd();
+ }
+}
+
+
+/*
+control is signals LCD5 LCD4
+ LCD5 = -Data Clk on 0488
+ LCD4 = Latch pulse on 0488
+ LCD3 = Data 0
+ LCD2 = Data 1
+ LCD1 = Data 2
+ LCD0 = Data 3
+data is signals LCD3 LCD2 LCD1 LCD0
+*/
+void microvision_state::lcd_write(UINT8 control, UINT8 data)
+{
+ // Latch pulse, when high, resets the %8 latch address counter
+ if ( control & 0x01 ) {
+ m_lcd_latch_index = 0;
+ }
+
+ // The addressed latches load when -Data Clk is low
+ if ( ! ( control & 0x02 ) ) {
+ m_lcd_latch[ m_lcd_latch_index & 0x07 ] = data & 0x0f;
+ }
+
+ // The latch address counter is incremented on rising edges of -Data Clk
+ if ( ( ! ( m_lcd_control_old & 0x02 ) ) && ( control & 0x02 ) ) {
+ // Check if Latch pule is low
+ if ( ! ( control & 0x01 ) ) {
+ m_lcd_latch_index++;
+ }
+ }
+
+ // A parallel transfer of data from the addressed latches to the holding latches occurs
+ // whenever Latch Pulse is high and -Data Clk is high
+ if ( control == 3 ) {
+ for ( int i = 0; i < 8; i++ ) {
+ m_lcd_holding_latch[i] = m_lcd_latch[i];
+ }
+ update_lcd();
+ }
+
+ m_lcd_control_old = control;
+}
+
+
+/*
+speaker is SPKR1 SPKR0
+*/
+void microvision_state::speaker_write(UINT8 speaker)
+{
+ const INT8 speaker_level[4] = { 0, 127, -128, 0 };
+
+ m_dac->write_signed8( speaker_level[ speaker & 0x03 ] );
+}
+
+
+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 )
+{
+ if (LOG) logerror( "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 )
+{
+ if (LOG) logerror( "p1_write: %02x\n", data );
+
+ lcd_write( data & 0x03, data >> 4 );
+}
+
+
+/*
+---- xx-- CAP2 (paddle)
+---- --x- SPKR1
+---- ---x SPKR0
+*/
+WRITE8_MEMBER( microvision_state::i8021_p2_write )
+{
+ if (LOG) logerror( "p2_write: %02x\n", data );
+
+ m_p2 = data;
+
+ speaker_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 paddle = 255 - ioport("PADDLE")->read();
+ m_paddle_timer->adjust( attotime::from_usec(160 + ( 518 * paddle ) / 255 ) );
+ }
+}
+
+
+READ8_MEMBER( microvision_state::i8021_t1_read )
+{
+ return m_t1;
+}
+
+
+READ8_MEMBER( microvision_state::i8021_bus_read )
+{
+ UINT8 data = m_p0;
+
+ UINT8 col0 = ioport("COL0")->read();
+ UINT8 col1 = ioport("COL1")->read();
+ UINT8 col2 = ioport("COL2")->read();
+
+ // Row scanning
+ if ( ! ( m_p0 & 0x80 ) )
+ {
+ UINT8 t = ( ( col0 & 0x01 ) << 2 ) | ( ( col1 & 0x01 ) << 1 ) | ( col2 & 0x01 );
+
+ data &= ( t ^ 0xFF );
+ }
+ if ( ! ( m_p0 & 0x40 ) )
+ {
+ UINT8 t = ( ( col0 & 0x02 ) << 1 ) | ( col1 & 0x02 ) | ( ( col2 & 0x02 ) >> 1 );
+
+ data &= ( t ^ 0xFF );
+ }
+ if ( ! ( m_p0 & 0x20 ) )
+ {
+ UINT8 t = ( col0 & 0x04 ) | ( ( col1 & 0x04 ) >> 1 ) | ( ( col2 & 0x04 ) >> 2 );
+
+ data &= ( t ^ 0xFF );
+ }
+ if ( ! ( m_p0 & 0x10 ) )
+ {
+ UINT8 t = ( ( col0 & 0x08 ) >> 1 ) | ( ( col1 & 0x08 ) >> 2 ) | ( ( col2 & 0x08 ) >> 3 );
+
+ data &= ( t ^ 0xFF );
+ }
+ return data;
+}
+
+
+READ8_MEMBER( microvision_state::tms1100_read_k )
+{
+ UINT8 data = 0;
+
+ if (LOG) logerror("read_k\n");
+
+ if ( m_r & 0x100 )
+ {
+ data |= ioport("COL0")->read();
+ }
+ if ( m_r & 0x200 )
+ {
+ data |= ioport("COL1")->read();
+ }
+ if ( m_r & 0x400 )
+ {
+ data |= ioport("COL2")->read();
+ }
+ return data;
+}
+
+
+WRITE16_MEMBER( microvision_state::tms1100_write_o )
+{
+ if (LOG) logerror("write_o: %04x\n", data);
+
+ m_o = data;
+
+ lcd_write( ( m_r >> 6 ) & 0x03, m_o & 0x0f );
+}
+
+
+/*
+x-- ---- ---- KEY2
+-x- ---- ---- KEY1
+--x ---- ---- KEY0
+--- x--- ---- LCD5
+--- -x-- ---- LCD4
+--- ---- --x- SPKR0
+--- ---- ---x SPKR1
+*/
+WRITE16_MEMBER( microvision_state::tms1100_write_r )
+{
+ if (LOG) logerror("write_r: %04x\n", data);
+
+ m_r = data;
+
+ speaker_write( ( ( m_r & 0x01 ) << 1 ) | ( ( m_r & 0x02 ) >> 1 ) );
+ lcd_write( ( m_r >> 6 ) & 0x03, m_o & 0x0f );
+}
+
+
+static const UINT16 microvision_output_pla_0[0x20] =
+{
+ /* O output PLA configuration currently unknown */
+ 0x00, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E,
+ 0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+static const UINT16 microvision_output_pla_1[0x20] =
+{
+ /* O output PLA configuration currently unknown */
+ /* Reversed bit order */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+DEVICE_IMAGE_LOAD_MEMBER(microvision_state, microvsn_cart)
+{
+ UINT8 *rom1 = memregion("maincpu1")->base();
+ UINT8 *rom2 = memregion("maincpu2")->base();
+ UINT32 file_size = m_cart->common_get_size("rom");
+ m_pla = 0;
+
+ if ( file_size != 1024 && file_size != 2048 )
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Invalid rom file size");
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* Read cartridge */
+ if (image.software_entry() == NULL)
+ {
+ if (image.fread(rom1, file_size) != file_size)
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unable to fully read from file");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ {
+ // Copy rom contents
+ memcpy(rom1, image.get_software_region("rom"), file_size);
+
+ // Get PLA type
+ const char *pla = image.get_feature("pla");
+
+ if (pla)
+ m_pla = 1;
+
+ tms1xxx_cpu_device::set_output_pla(m_tms1100, m_pla ? microvision_output_pla_1 : microvision_output_pla_0);
+
+ // Set default setting for PCB type and RC type
+ m_pcb_type = microvision_state::PCB_TYPE_UNKNOWN;
+ m_rc_type = microvision_state::RC_TYPE_UNKNOWN;
+
+ // Detect settings for PCB type
+ const char *pcb = image.get_feature("pcb");
+
+ if (pcb)
+ {
+ static const struct { const char *pcb_name; microvision_state::pcb_type pcbtype; } pcb_types[] =
+ {
+ { "4952 REV-A", microvision_state::PCB_TYPE_4952_REV_A },
+ { "4952-79 REV-B", microvision_state::PCB_TYPE_4952_9_REV_B },
+ { "4971-REV-C", microvision_state::PCB_TYPE_4971_REV_C },
+ { "7924952D02", microvision_state::PCB_TYPE_7924952D02 }
+ };
+
+ for (int i = 0; i < ARRAY_LENGTH(pcb_types) && m_pcb_type == microvision_state::PCB_TYPE_UNKNOWN; i++)
+ {
+ if (!core_stricmp(pcb, pcb_types[i].pcb_name))
+ {
+ m_pcb_type = pcb_types[i].pcbtype;
+ }
+ }
+ }
+
+ // Detect settings for RC types
+ const char *rc = image.get_feature("rc");
+
+ if (rc)
+ {
+ static const struct { const char *rc_name; microvision_state::rc_type rctype; } rc_types[] =
+ {
+ { "100pf/21.0K", microvision_state::RC_TYPE_100PF_21_0K },
+ { "100pf/23.2K", microvision_state::RC_TYPE_100PF_23_2K },
+ { "100pf/39.4K", microvision_state::RC_TYPE_100PF_39_4K }
+ };
+
+ for (int i = 0; i < ARRAY_LENGTH(rc_types) && m_rc_type == microvision_state::RC_TYPE_UNKNOWN; i++)
+ {
+ if (!core_stricmp(rc, rc_types[i].rc_name))
+ {
+ m_rc_type = rc_types[i].rctype;
+ }
+ }
+ }
+ }
+
+ // Mirror rom data to maincpu2 region
+ memcpy(rom2, rom1, file_size);
+
+ // Based on file size select cpu:
+ // - 1024 -> I8021
+ // - 2048 -> TI TMS1100
+
+ switch (file_size)
+ {
+ case 1024:
+ m_cpu_type = microvision_state::CPU_TYPE_I8021;
+ break;
+
+ case 2048:
+ m_cpu_type = microvision_state::CPU_TYPE_TMS1100;
+ break;
+ }
+ return IMAGE_INIT_PASS;
+}
+
+
+static INPUT_PORTS_START( microvision )
+ PORT_START("COL0")
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_CODE(KEYCODE_3) PORT_NAME("B01")
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON4) PORT_CODE(KEYCODE_E) PORT_NAME("B04")
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON7) PORT_CODE(KEYCODE_D) PORT_NAME("B07")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON10) PORT_CODE(KEYCODE_C) PORT_NAME("B10")
+
+ PORT_START("COL1")
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_CODE(KEYCODE_4) PORT_NAME("B02")
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON5) PORT_CODE(KEYCODE_R) PORT_NAME("B05")
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON8) PORT_CODE(KEYCODE_F) PORT_NAME("B08")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON11) PORT_CODE(KEYCODE_V) PORT_NAME("B11")
+
+ PORT_START("COL2")
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_CODE(KEYCODE_5) PORT_NAME("B03")
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON6) PORT_CODE(KEYCODE_T) PORT_NAME("B06")
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON9) PORT_CODE(KEYCODE_G) PORT_NAME("B09")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON12) PORT_CODE(KEYCODE_B) PORT_NAME("B12")
+
+ PORT_START("PADDLE")
+ PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_PLAYER(1) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_MINMAX(0, 255)
+INPUT_PORTS_END
+
+
+static ADDRESS_MAP_START( microvision_8021_io, AS_IO, 8, microvision_state )
+ AM_RANGE( 0x00, 0xFF ) AM_WRITE( i8021_p0_write )
+ AM_RANGE( MCS48_PORT_P0, MCS48_PORT_P0 ) AM_WRITE( i8021_p0_write )
+ AM_RANGE( MCS48_PORT_P1, MCS48_PORT_P1 ) AM_WRITE( i8021_p1_write )
+ AM_RANGE( MCS48_PORT_P2, MCS48_PORT_P2 ) AM_WRITE( i8021_p2_write )
+ AM_RANGE( MCS48_PORT_T1, MCS48_PORT_T1 ) AM_READ( i8021_t1_read )
+ AM_RANGE( MCS48_PORT_BUS, MCS48_PORT_BUS ) AM_READ( i8021_bus_read )
+ADDRESS_MAP_END
+
+
+static MACHINE_CONFIG_START( microvision, microvision_state )
+ MCFG_CPU_ADD("maincpu1", I8021, 2000000) // approximately
+ MCFG_CPU_IO_MAP( microvision_8021_io )
+ MCFG_CPU_ADD("maincpu2", TMS1100, 500000) // most games seem to be running at approximately this speed
+ MCFG_TMS1XXX_OUTPUT_PLA( microvision_output_pla_0 )
+ MCFG_TMS1XXX_READ_K_CB( READ8( microvision_state, tms1100_read_k ) )
+ MCFG_TMS1XXX_WRITE_O_CB( WRITE16( microvision_state, tms1100_write_o ) )
+ MCFG_TMS1XXX_WRITE_R_CB( WRITE16( microvision_state, tms1100_write_r ) )
+
+ MCFG_SCREEN_ADD("screen", LCD)
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(0)
+ MCFG_QUANTUM_TIME(attotime::from_hz(60))
+
+ MCFG_MACHINE_START_OVERRIDE(microvision_state, microvision )
+ MCFG_MACHINE_RESET_OVERRIDE(microvision_state, microvision )
+
+ MCFG_SCREEN_UPDATE_DRIVER(microvision_state, screen_update)
+ MCFG_SCREEN_VBLANK_DRIVER(microvision_state, screen_vblank)
+ MCFG_SCREEN_SIZE(16, 16)
+ MCFG_SCREEN_VISIBLE_AREA(0, 15, 0, 15)
+ MCFG_SCREEN_PALETTE("palette")
+
+ MCFG_PALETTE_ADD("palette", 16)
+ MCFG_PALETTE_INIT_OWNER(microvision_state,microvision)
+
+ MCFG_DEFAULT_LAYOUT(layout_lcd)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("dac", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
+
+ MCFG_GENERIC_CARTSLOT_ADD("cartslot", generic_plain_slot, "microvision_cart")
+ MCFG_GENERIC_MANDATORY
+ MCFG_GENERIC_LOAD(microvision_state, microvsn_cart)
+
+ /* Software lists */
+ MCFG_SOFTWARE_LIST_ADD("cart_list","microvision")
+MACHINE_CONFIG_END
+
+
+ROM_START( microvsn )
+ ROM_REGION( 0x800, "maincpu1", ROMREGION_ERASE00 )
+ ROM_REGION( 0x800, "maincpu2", ROMREGION_ERASE00 )
+ ROM_REGION( 867, "maincpu2:mpla", 0 )
+ ROM_LOAD( "tms1100_default_mpla.pla", 0, 867, CRC(62445fc9) SHA1(d6297f2a4bc7a870b76cc498d19dbb0ce7d69fec) ) // verified for: pinball, blockbuster, bowling
+
+ ROM_REGION( 365, "maincpu2:opla", ROMREGION_ERASE00 )
+ROM_END
+
+
+CONS( 1979, microvsn, 0, 0, microvision, microvision, driver_device, 0, "Milton Bradley", "MicroVision", MACHINE_NOT_WORKING )