summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/vtech/memexp
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-09-13 08:41:44 +0200
committer Miodrag Milanovic <mmicko@gmail.com>2015-09-13 08:41:44 +0200
commitf88cefad27a1737c76e09d99c9fb43e173506081 (patch)
tree2d8167d03579c46e226471747eb4407bd00ed6fa /src/devices/bus/vtech/memexp
parente92ac9e0fa8e99869894bea00589bbb526be30aa (diff)
Move all devices into separate part of src tree (nw)
Diffstat (limited to 'src/devices/bus/vtech/memexp')
-rw-r--r--src/devices/bus/vtech/memexp/carts.c19
-rw-r--r--src/devices/bus/vtech/memexp/carts.h23
-rw-r--r--src/devices/bus/vtech/memexp/floppy.c298
-rw-r--r--src/devices/bus/vtech/memexp/floppy.h66
-rw-r--r--src/devices/bus/vtech/memexp/memexp.c108
-rw-r--r--src/devices/bus/vtech/memexp/memexp.h125
-rw-r--r--src/devices/bus/vtech/memexp/memory.c166
-rw-r--r--src/devices/bus/vtech/memexp/memory.h94
-rw-r--r--src/devices/bus/vtech/memexp/rs232.c104
-rw-r--r--src/devices/bus/vtech/memexp/rs232.h50
-rw-r--r--src/devices/bus/vtech/memexp/wordpro.c65
-rw-r--r--src/devices/bus/vtech/memexp/wordpro.h39
12 files changed, 1157 insertions, 0 deletions
diff --git a/src/devices/bus/vtech/memexp/carts.c b/src/devices/bus/vtech/memexp/carts.c
new file mode 100644
index 00000000000..dc40d0e8a57
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/carts.c
@@ -0,0 +1,19 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best
+/***************************************************************************
+
+ VTech Laser/VZ Memory Expansion Slot Devices
+
+***************************************************************************/
+
+#include "carts.h"
+
+SLOT_INTERFACE_START( memexp_slot_carts )
+ SLOT_INTERFACE("floppy", FLOPPY_CONTROLLER)
+ SLOT_INTERFACE("laser110_16k", LASER110_16K)
+ SLOT_INTERFACE("laser210_16k", LASER210_16K)
+ SLOT_INTERFACE("laser310_16k", LASER310_16K)
+ SLOT_INTERFACE("laser_64k", LASER_64K)
+ SLOT_INTERFACE("rs232", RS232_INTERFACE)
+ SLOT_INTERFACE("wordpro", WORDPRO)
+SLOT_INTERFACE_END
diff --git a/src/devices/bus/vtech/memexp/carts.h b/src/devices/bus/vtech/memexp/carts.h
new file mode 100644
index 00000000000..a1e86987a31
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/carts.h
@@ -0,0 +1,23 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best
+/***************************************************************************
+
+ VTech Laser/VZ Memory Expansion Slot Devices
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __VTECH_MEMEXP_CARTS_H__
+#define __VTECH_MEMEXP_CARTS_H__
+
+#include "emu.h"
+
+#include "floppy.h"
+#include "memory.h"
+#include "rs232.h"
+#include "wordpro.h"
+
+SLOT_INTERFACE_EXTERN( memexp_slot_carts );
+
+#endif // __VTECH_MEMEXP_CARTS_H__
diff --git a/src/devices/bus/vtech/memexp/floppy.c b/src/devices/bus/vtech/memexp/floppy.c
new file mode 100644
index 00000000000..ef169703035
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/floppy.c
@@ -0,0 +1,298 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best, Olivier Galibert
+/***************************************************************************
+
+ VTech Laser/VZ Floppy Controller Cartridge
+
+ Laser DD 20
+ Dick Smith Electronics X-7304
+
+***************************************************************************/
+
+#include "floppy.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type FLOPPY_CONTROLLER = &device_creator<floppy_controller_device>;
+
+DEVICE_ADDRESS_MAP_START(map, 8, floppy_controller_device)
+ AM_RANGE(0, 0) AM_WRITE(latch_w)
+ AM_RANGE(1, 1) AM_READ(shifter_r)
+ AM_RANGE(2, 2) AM_READ(rd_r)
+ AM_RANGE(3, 3) AM_READ(wpt_r)
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( floppy )
+ ROM_REGION(0x3000, "software", 0)
+ ROM_LOAD("vzdos.rom", 0x0000, 0x2000, CRC(b6ed6084) SHA1(59d1cbcfa6c5e1906a32704fbf0d9670f0d1fd8b))
+ROM_END
+
+const rom_entry *floppy_controller_device::device_rom_region() const
+{
+ return ROM_NAME( floppy );
+}
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+static SLOT_INTERFACE_START( laser_floppies )
+ SLOT_INTERFACE("525", FLOPPY_525_SSSD)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( floppy_controller )
+ MCFG_MEMEXP_SLOT_ADD("mem")
+ MCFG_FLOPPY_DRIVE_ADD("0", laser_floppies, "525", floppy_image_device::default_floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("1", laser_floppies, "525", floppy_image_device::default_floppy_formats)
+MACHINE_CONFIG_END
+
+machine_config_constructor floppy_controller_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( floppy_controller );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// floppy_controller_device - constructor
+//-------------------------------------------------
+
+floppy_controller_device::floppy_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, FLOPPY_CONTROLLER, "Laser/VZ Floppy Disk Controller", tag, owner, clock, "laserfdc", __FILE__),
+ device_memexp_interface(mconfig, *this),
+ m_memexp(*this, "mem"),
+ m_floppy0(*this, "0"),
+ m_floppy1(*this, "1")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void floppy_controller_device::device_start()
+{
+ save_item(NAME(m_latch));
+ save_item(NAME(m_shifter));
+ save_item(NAME(m_latching_inverter));
+ save_item(NAME(m_current_cyl));
+ save_item(NAME(m_last_latching_inverter_update_time));
+ save_item(NAME(m_write_start_time));
+ save_item(NAME(m_write_position));
+
+ // TODO: save m_write_buffer and rebuild m_floppy after load
+
+ UINT8 *bios = memregion("software")->base();
+
+ // Obvious bugs... must have worked by sheer luck and very subtle
+ // timings. Our current z80 is not subtle enough.
+
+ bios[0x1678] = 0x75;
+ bios[0x1688] = 0x85;
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void floppy_controller_device::device_reset()
+{
+ m_memexp->set_io_space(m_slot->m_io);
+ m_memexp->set_program_space(m_slot->m_program);
+
+ m_slot->m_program->install_rom(0x4000, 0x5fff, memregion("software")->base());
+
+ m_slot->m_io->install_device(0x10, 0x1f, *this, &floppy_controller_device::map);
+
+ m_latch = 0x00;
+ m_floppy = NULL;
+ m_current_cyl = 0;
+ m_shifter = 0x00;
+ m_latching_inverter = false;
+ m_last_latching_inverter_update_time = machine().time();
+ m_write_start_time = attotime::never;
+ m_write_position = 0;
+ memset(m_write_buffer, 0, sizeof(m_write_buffer));
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+// latch at +0 is linked to:
+// bits 0-3: track step motor phases
+// bit 5: write data (flux reversal on every level change)
+// bit 6: !write request
+// bits 4,7: floppy select
+
+WRITE8_MEMBER(floppy_controller_device::latch_w)
+{
+ UINT8 diff = m_latch ^ data;
+ m_latch = data;
+
+ floppy_image_device *newflop = NULL;
+ if(m_latch & 0x10)
+ newflop = m_floppy0->get_device();
+ else if(m_latch & 0x80)
+ newflop = m_floppy1->get_device();
+
+ if(newflop != m_floppy) {
+ update_latching_inverter();
+ flush_writes();
+ if(m_floppy) {
+ m_floppy->mon_w(1);
+ m_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
+ }
+ if(newflop) {
+ newflop->set_rpm(85);
+ newflop->mon_w(0);
+ newflop->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(floppy_controller_device::index_callback), this));
+ m_current_cyl = newflop->get_cyl() << 1;
+ }
+ m_floppy = newflop;
+ }
+
+ if(m_floppy) {
+ int cph = m_current_cyl & 3;
+ int pcyl = m_current_cyl;
+ if(!(m_latch & (1 << cph))) {
+ if(m_current_cyl < 84*2 && (m_latch & (1 << ((cph+1) & 3))))
+ m_current_cyl++;
+ if(m_current_cyl && (m_latch & (1 << ((cph+3) & 3))))
+ m_current_cyl--;
+ if(m_current_cyl != pcyl && !(m_current_cyl & 1)) {
+ m_floppy->dir_w(m_current_cyl < pcyl);
+ m_floppy->stp_w(true);
+ m_floppy->stp_w(false);
+ m_floppy->stp_w(true);
+ }
+ }
+ }
+
+ if(diff & 0x40) {
+ if(!(m_latch & 0x40)) {
+ m_write_start_time = machine().time();
+ m_write_position = 0;
+ if(m_floppy)
+ m_floppy->set_write_splice(m_write_start_time);
+
+ } else {
+ update_latching_inverter();
+ flush_writes();
+ m_write_start_time = attotime::never;
+ }
+ }
+ if(!(m_latch & 0x40) && (diff & 0x20)) {
+ if(m_write_position == ARRAY_LENGTH(m_write_buffer)) {
+ update_latching_inverter();
+ flush_writes(true);
+ }
+ m_write_buffer[m_write_position++] = machine().time();
+ }
+}
+
+
+// The read data line is connected to a flip/flop with inverted input
+// connected to the input. That means it inverts its value on every
+// floppy flux reversal. We'll call it a latching inverter.
+//
+// The latching inverter is connected to a 8-bits shift register. On
+// reading the shifter address we get:
+// - the inverted inverter output is shifted through the lsb of the shift register
+// - the inverter is cleared
+
+READ8_MEMBER(floppy_controller_device::shifter_r)
+{
+ update_latching_inverter();
+ m_shifter = (m_shifter << 1) | !m_latching_inverter;
+ m_latching_inverter = false;
+ return m_shifter;
+}
+
+
+// Linked to the latching inverter on bit 7, rest is floating
+READ8_MEMBER(floppy_controller_device::rd_r)
+{
+ update_latching_inverter();
+ return m_latching_inverter ? 0x80 : 0x00;
+}
+
+
+// Linked to wp signal on bit 7, rest is floating
+READ8_MEMBER(floppy_controller_device::wpt_r)
+{
+ return m_floppy && m_floppy->wpt_r() ? 0x80 : 0x00;
+}
+
+void floppy_controller_device::update_latching_inverter()
+{
+ attotime now = machine().time();
+ if(!m_floppy) {
+ m_last_latching_inverter_update_time = now;
+ return;
+ }
+
+ attotime when = m_last_latching_inverter_update_time;
+ for(;;) {
+ when = m_floppy->get_next_transition(when);
+ if(when == attotime::never || when > now)
+ break;
+ m_latching_inverter = !m_latching_inverter;
+ }
+ m_last_latching_inverter_update_time = now;
+}
+
+void floppy_controller_device::index_callback(floppy_image_device *floppy, int state)
+{
+ update_latching_inverter();
+ flush_writes(true);
+}
+
+void floppy_controller_device::flush_writes(bool keep_margin)
+{
+ if(!m_floppy || m_write_start_time == attotime::never)
+ return;
+
+ // Beware of time travel. Index pulse callback (which flushes)
+ // can be called with a machine().time() inferior to the last
+ // m_write_buffer value if the calling cpu instructions are not
+ // suspendable.
+
+ attotime limit = machine().time();
+ int kept_pos = m_write_position;
+ int kept_count = 0;
+ while(kept_pos > 0 && m_write_buffer[kept_pos-1] >= limit) {
+ kept_pos--;
+ kept_count++;
+ }
+
+ if(keep_margin) {
+ attotime last = kept_pos ? m_write_buffer[kept_pos-1] : m_write_start_time;
+ attotime delta = limit-last;
+ delta = delta / 2;
+ limit = limit - delta;
+ }
+ m_write_position -= kept_count;
+ if(m_write_position && m_write_buffer[0] == m_write_start_time) {
+ if(m_write_position)
+ memmove(m_write_buffer, m_write_buffer+1, sizeof(m_write_buffer[0])*(m_write_position-1));
+ m_write_position--;
+ }
+ m_floppy->write_flux(m_write_start_time, limit, m_write_position, m_write_buffer);
+ m_write_start_time = limit;
+
+ if(kept_count != 0)
+ memmove(m_write_buffer, m_write_buffer+kept_pos, kept_count*sizeof(m_write_buffer[0]));
+ m_write_position = kept_count;
+}
diff --git a/src/devices/bus/vtech/memexp/floppy.h b/src/devices/bus/vtech/memexp/floppy.h
new file mode 100644
index 00000000000..91c332332c1
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/floppy.h
@@ -0,0 +1,66 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best, Olivier Galibert
+/***************************************************************************
+
+ VTech Laser/VZ Floppy Controller Cartridge
+
+ Laser DD 20
+ Dick Smith Electronics X-7304
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __VTECH_MEMEXP_FLOPPY_H__
+#define __VTECH_MEMEXP_FLOPPY_H__
+
+#include "emu.h"
+#include "memexp.h"
+#include "imagedev/floppy.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> floppy_controller_device
+
+class floppy_controller_device : public device_t, public device_memexp_interface
+{
+public:
+ // construction/destruction
+ floppy_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_ADDRESS_MAP(map, 8);
+
+ DECLARE_WRITE8_MEMBER(latch_w);
+ DECLARE_READ8_MEMBER(shifter_r);
+ DECLARE_READ8_MEMBER(rd_r);
+ DECLARE_READ8_MEMBER(wpt_r);
+
+protected:
+ virtual const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual void device_start();
+ virtual void device_reset();
+
+ required_device<memexp_slot_device> m_memexp;
+ required_device<floppy_connector> m_floppy0, m_floppy1;
+ floppy_image_device *m_floppy;
+
+ UINT8 m_latch, m_shifter;
+ bool m_latching_inverter;
+ int m_current_cyl;
+ attotime m_last_latching_inverter_update_time;
+ attotime m_write_start_time, m_write_buffer[32];
+ int m_write_position;
+
+ void index_callback(floppy_image_device *floppy, int state);
+ void update_latching_inverter();
+ void flush_writes(bool keep_margin = false);
+};
+
+// device type definition
+extern const device_type FLOPPY_CONTROLLER;
+
+#endif // __VTECH_MEMEXP_FLOPPY_H__
diff --git a/src/devices/bus/vtech/memexp/memexp.c b/src/devices/bus/vtech/memexp/memexp.c
new file mode 100644
index 00000000000..d41b2d073b7
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/memexp.c
@@ -0,0 +1,108 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best
+/***************************************************************************
+
+ VTech Laser/VZ Memory Expansion Slot
+
+ 44-pin slot
+
+***************************************************************************/
+
+#include "memexp.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type MEMEXP_SLOT = &device_creator<memexp_slot_device>;
+
+
+//**************************************************************************
+// SLOT DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// memexp_slot_device - constructor
+//-------------------------------------------------
+
+memexp_slot_device::memexp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, MEMEXP_SLOT, "Memory Expansion Slot", tag, owner, clock, "memexp_slot", __FILE__),
+ device_slot_interface(mconfig, *this),
+ m_program(NULL),
+ m_io(NULL),
+ m_cart(NULL),
+ m_int_handler(*this),
+ m_nmi_handler(*this),
+ m_reset_handler(*this)
+{
+}
+
+//-------------------------------------------------
+// memexp_slot_device - destructor
+//-------------------------------------------------
+
+memexp_slot_device::~memexp_slot_device()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void memexp_slot_device::device_start()
+{
+ // resolve callbacks
+ m_int_handler.resolve_safe();
+ m_nmi_handler.resolve_safe();
+ m_reset_handler.resolve_safe();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void memexp_slot_device::device_reset()
+{
+}
+
+//-------------------------------------------------
+// set_program_space - set address space we are attached to
+//-------------------------------------------------
+
+void memexp_slot_device::set_program_space(address_space *program)
+{
+ m_program = program;
+}
+
+//-------------------------------------------------
+// set_io_space - set address space we are attached to
+//-------------------------------------------------
+
+void memexp_slot_device::set_io_space(address_space *io)
+{
+ m_io = io;
+}
+
+
+//**************************************************************************
+// CARTRIDGE INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_memexp_interface - constructor
+//-------------------------------------------------
+
+device_memexp_interface::device_memexp_interface(const machine_config &mconfig, device_t &device) :
+ device_slot_card_interface(mconfig, device)
+{
+ m_slot = dynamic_cast<memexp_slot_device *>(device.owner());
+}
+
+//-------------------------------------------------
+// ~device_memexp_interface - destructor
+//-------------------------------------------------
+
+device_memexp_interface::~device_memexp_interface()
+{
+}
diff --git a/src/devices/bus/vtech/memexp/memexp.h b/src/devices/bus/vtech/memexp/memexp.h
new file mode 100644
index 00000000000..d0de2049b5b
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/memexp.h
@@ -0,0 +1,125 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best
+/***************************************************************************
+
+ VTech Laser/VZ Memory Expansion Slot
+
+ 44-pin slot
+
+ 22 GND 23 NC
+ 21 +5VDC 24 A11
+ 20 /IORQ 25 A12
+ 19 /RD 26 A13
+ 18 /NMI 27 A14
+ 17 /WAIT 28 A15
+ 16 /MI 29 CLK
+ 15 /RFSH 30 D4
+ 14 D7 31 D3
+ 13 D2 32 D5
+ 12 A1 33 D6
+ 11 A2 34 NC
+ 10 A3 35 A0
+ 9 A4 36 D0
+ 8 A5 37 D1
+ 7 A6 38 /INT
+ 6 A7 39 /HALT
+ 5 A8 40 /MERQ
+ 4 A9 41 /WR
+ 3 A10 42 /NC
+ 2 /RESET 43 +9VDC
+ 1 GND 44 NC
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __VTECH_MEMEXP_H__
+#define __VTECH_MEMEXP_H__
+
+#include "emu.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_MEMEXP_SLOT_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, MEMEXP_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(memexp_slot_carts, NULL, false)
+
+#define MCFG_MEMEXP_SLOT_INT_HANDLER(_devcb) \
+ devcb = &memexp_device::set_int_handler(*device, DEVCB_##_devcb);
+
+#define MCFG_MEMEXP_SLOT_NMI_HANDLER(_devcb) \
+ devcb = &memexp_device::set_nmi_handler(*device, DEVCB_##_devcb);
+
+#define MCFG_MEMEXP_SLOT_RESET_HANDLER(_devcb) \
+ devcb = &memexp_device::set_reset_handler(*device, DEVCB_##_devcb);
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class device_memexp_interface;
+
+class memexp_slot_device : public device_t, public device_slot_interface
+{
+public:
+ // construction/destruction
+ memexp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~memexp_slot_device();
+
+ void set_program_space(address_space *program);
+ void set_io_space(address_space *io);
+
+ // callbacks
+ template<class _Object> static devcb_base &set_int_handler(device_t &device, _Object object)
+ { return downcast<memexp_slot_device &>(device).m_int_handler.set_callback(object); }
+
+ template<class _Object> static devcb_base &set_nmi_handler(device_t &device, _Object object)
+ { return downcast<memexp_slot_device &>(device).m_nmi_handler.set_callback(object); }
+
+ template<class _Object> static devcb_base &set_reset_handler(device_t &device, _Object object)
+ { return downcast<memexp_slot_device &>(device).m_reset_handler.set_callback(object); }
+
+ // called from cart device
+ DECLARE_WRITE_LINE_MEMBER( int_w ) { m_int_handler(state); }
+ DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_nmi_handler(state); }
+ DECLARE_WRITE_LINE_MEMBER( reset_w ) { m_reset_handler(state); }
+
+ address_space *m_program;
+ address_space *m_io;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ device_memexp_interface *m_cart;
+
+private:
+ devcb_write_line m_int_handler;
+ devcb_write_line m_nmi_handler;
+ devcb_write_line m_reset_handler;
+};
+
+// class representing interface-specific live memexp device
+class device_memexp_interface : public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ device_memexp_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_memexp_interface();
+
+protected:
+ memexp_slot_device *m_slot;
+};
+
+// device type definition
+extern const device_type MEMEXP_SLOT;
+
+// include here so drivers don't need to
+#include "carts.h"
+
+#endif // __VTECH_MEMEXP_H__
diff --git a/src/devices/bus/vtech/memexp/memory.c b/src/devices/bus/vtech/memexp/memory.c
new file mode 100644
index 00000000000..5b4b9d71701
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/memory.c
@@ -0,0 +1,166 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best
+/***************************************************************************
+
+ VTech Laser/VZ Laser Memory Expansions
+
+***************************************************************************/
+
+#include "memory.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type LASER110_16K = &device_creator<laser110_16k_device>;
+const device_type LASER210_16K = &device_creator<laser210_16k_device>;
+const device_type LASER310_16K = &device_creator<laser310_16k_device>;
+const device_type LASER_64K = &device_creator<laser_64k_device>;
+
+
+//**************************************************************************
+// LASER 110 16K DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// laser110_16k_device - constructor
+//-------------------------------------------------
+
+laser110_16k_device::laser110_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, LASER110_16K, "Laser 110/200/VZ-200 16k Memory", tag, owner, clock, "laser110_16k", __FILE__),
+ device_memexp_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void laser110_16k_device::device_start()
+{
+ m_ram.resize(16 * 1024);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void laser110_16k_device::device_reset()
+{
+ m_slot->m_program->install_ram(0x8000, 0xbfff, &m_ram[0]);
+}
+
+
+//**************************************************************************
+// LASER 210 16K DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// laser210_16k_device - constructor
+//-------------------------------------------------
+
+laser210_16k_device::laser210_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, LASER210_16K, "Laser 210/VZ-200 (DSE) 16k Memory", tag, owner, clock, "laser210_16k", __FILE__),
+ device_memexp_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void laser210_16k_device::device_start()
+{
+ m_ram.resize(16 * 1024);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void laser210_16k_device::device_reset()
+{
+ m_slot->m_program->install_ram(0x9000, 0xcfff, &m_ram[0]);
+}
+
+
+//**************************************************************************
+// VZ300 16K DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// laser310_16k_device - constructor
+//-------------------------------------------------
+
+laser310_16k_device::laser310_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, LASER310_16K, "Laser 310/VZ-300 16k Memory", tag, owner, clock, "laser310_16k", __FILE__),
+ device_memexp_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void laser310_16k_device::device_start()
+{
+ m_ram.resize(16 * 1024);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void laser310_16k_device::device_reset()
+{
+ m_slot->m_program->install_ram(0xb800, 0xf7ff, &m_ram[0]);
+}
+
+
+//**************************************************************************
+// VZ300 64K DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// laser_64k_device - constructor
+//-------------------------------------------------
+
+laser_64k_device::laser_64k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, LASER_64K, "Laser/VZ 64k Memory", tag, owner, clock, "laser_64k", __FILE__),
+ device_memexp_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void laser_64k_device::device_start()
+{
+ m_ram.resize(64 * 1024);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void laser_64k_device::device_reset()
+{
+ // fixed first bank
+ m_slot->m_program->install_ram(0x8000, 0xbfff, &m_ram[0]);
+
+ // other banks
+ m_slot->m_program->install_readwrite_bank(0xc000, 0xffff, tag());
+
+ membank(tag())->configure_entries(0, 4, &m_ram[0], 0x4000);
+ membank(tag())->set_entry(1);
+
+ // bank switch
+ m_slot->m_io->install_write_handler(0x70, 0x7f, write8_delegate(FUNC(laser_64k_device::bankswitch_w), this));
+}
+
+WRITE8_MEMBER( laser_64k_device::bankswitch_w )
+{
+ membank(tag())->set_entry(data & 0x03);
+}
diff --git a/src/devices/bus/vtech/memexp/memory.h b/src/devices/bus/vtech/memexp/memory.h
new file mode 100644
index 00000000000..e45d65c83fe
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/memory.h
@@ -0,0 +1,94 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best
+/***************************************************************************
+
+ VTech Laser/VZ Memory Expansions
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __VTECH_MEMEXP_MEMORY__
+#define __VTECH_MEMEXP_MEMORY__
+
+#include "emu.h"
+#include "memexp.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> laser110_16k_device
+
+class laser110_16k_device : public device_t, public device_memexp_interface
+{
+public:
+ // construction/destruction
+ laser110_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ std::vector<UINT8> m_ram;
+};
+
+// ======================> laser210_16k_device
+
+class laser210_16k_device : public device_t, public device_memexp_interface
+{
+public:
+ // construction/destruction
+ laser210_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ std::vector<UINT8> m_ram;
+};
+
+// ======================> laser310_16k_device
+
+class laser310_16k_device : public device_t, public device_memexp_interface
+{
+public:
+ // construction/destruction
+ laser310_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ std::vector<UINT8> m_ram;
+};
+
+// ======================> laser_64k_device
+
+class laser_64k_device : public device_t, public device_memexp_interface
+{
+public:
+ // construction/destruction
+ laser_64k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_WRITE8_MEMBER( bankswitch_w );
+
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ std::vector<UINT8> m_ram;
+};
+
+// device type definition
+extern const device_type LASER110_16K;
+extern const device_type LASER210_16K;
+extern const device_type LASER310_16K;
+extern const device_type LASER_64K;
+
+#endif // __VTECH_MEMEXP_MEMORY__
diff --git a/src/devices/bus/vtech/memexp/rs232.c b/src/devices/bus/vtech/memexp/rs232.c
new file mode 100644
index 00000000000..bd74662c9f5
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/rs232.c
@@ -0,0 +1,104 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best
+/***************************************************************************
+
+ Dick Smith VZ-200/300 RS-232 Cartridge
+
+***************************************************************************/
+
+#include "rs232.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type RS232_INTERFACE = &device_creator<rs232_interface_device>;
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( rs232 )
+ ROM_REGION(0x800, "software", 0)
+ ROM_LOAD("rs232_v15.ic2", 0x000, 0x800, CRC(6545260d) SHA1(4042f6f1e09e383f3c92f628c6187dc5f072fdb2))
+ROM_END
+
+const rom_entry *rs232_interface_device::device_rom_region() const
+{
+ return ROM_NAME( rs232 );
+}
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( rs232 )
+ MCFG_RS232_PORT_ADD("rs232", default_rs232_devices, NULL)
+ MCFG_RS232_RXD_HANDLER(WRITELINE(rs232_interface_device, rs232_rx_w))
+MACHINE_CONFIG_END
+
+machine_config_constructor rs232_interface_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( rs232 );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// wordpro_device - constructor
+//-------------------------------------------------
+
+rs232_interface_device::rs232_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, RS232_INTERFACE, "DSE VZ-200/300 RS-232 Interface", tag, owner, clock, "vz_rs232", __FILE__),
+ device_memexp_interface(mconfig, *this),
+ m_rs232(*this, "rs232"),
+ m_rx(1)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void rs232_interface_device::device_start()
+{
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void rs232_interface_device::device_reset()
+{
+ // program
+ m_slot->m_program->install_rom(0x4000, 0x47ff, 0, 0x800, memregion("software")->base());
+
+ // data
+ m_slot->m_program->install_read_handler(0x5000, 0x57ff, read8_delegate(FUNC(rs232_interface_device::receive_data_r), this));
+ m_slot->m_program->install_write_handler(0x5800, 0x5fff, write8_delegate(FUNC(rs232_interface_device::transmit_data_w), this));
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+WRITE_LINE_MEMBER( rs232_interface_device::rs232_rx_w )
+{
+ m_rx = state;
+}
+
+READ8_MEMBER( rs232_interface_device::receive_data_r )
+{
+ return 0x7f | (m_rx << 7);
+}
+
+WRITE8_MEMBER( rs232_interface_device::transmit_data_w )
+{
+ m_rs232->write_txd(!BIT(data, 7));
+}
diff --git a/src/devices/bus/vtech/memexp/rs232.h b/src/devices/bus/vtech/memexp/rs232.h
new file mode 100644
index 00000000000..c89133e5a33
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/rs232.h
@@ -0,0 +1,50 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best
+/***************************************************************************
+
+ Dick Smith VZ-200/300 RS-232 Cartridge
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __VTECH_MEMEXP_RS232_H__
+#define __VTECH_MEMEXP_RS232_H__
+
+#include "emu.h"
+#include "memexp.h"
+#include "bus/rs232/rs232.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> rs232_interface_device
+
+class rs232_interface_device : public device_t, public device_memexp_interface
+{
+public:
+ // construction/destruction
+ rs232_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_WRITE_LINE_MEMBER( rs232_rx_w );
+ DECLARE_READ8_MEMBER( receive_data_r );
+ DECLARE_WRITE8_MEMBER( transmit_data_w );
+
+protected:
+ virtual const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ required_device<rs232_port_device> m_rs232;
+
+ int m_rx;
+};
+
+// device type definition
+extern const device_type RS232_INTERFACE;
+
+#endif // __VTECH_MEMEXP_RS232_H__
diff --git a/src/devices/bus/vtech/memexp/wordpro.c b/src/devices/bus/vtech/memexp/wordpro.c
new file mode 100644
index 00000000000..1a038bcf0ac
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/wordpro.c
@@ -0,0 +1,65 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best
+/***************************************************************************
+
+ Dick Smith VZ-300 WordPro Cartridge
+
+***************************************************************************/
+
+#include "wordpro.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type WORDPRO = &device_creator<wordpro_device>;
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( wordpro )
+ ROM_REGION(0x3000, "software", 0)
+ ROM_LOAD("wordpro.u3", 0x0000, 0x1000, CRC(c37ea780) SHA1(03f56711e08d88e7b523c0ef9c2a5af83ee7ad05))
+ ROM_LOAD("wordpro.u4", 0x1000, 0x1000, CRC(2e3a8c45) SHA1(a9d48d809f39a3478496a6d3ddd728bd0b4efc37))
+ ROM_LOAD("wordpro.u5", 0x2000, 0x1000, CRC(2a336802) SHA1(b4de50f943243f18a2bfabef354b76d77178c189))
+ROM_END
+
+const rom_entry *wordpro_device::device_rom_region() const
+{
+ return ROM_NAME( wordpro );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// wordpro_device - constructor
+//-------------------------------------------------
+
+wordpro_device::wordpro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, WORDPRO, "DSE VZ-300 WordPro", tag, owner, clock, "wordpro", __FILE__),
+ device_memexp_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wordpro_device::device_start()
+{
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void wordpro_device::device_reset()
+{
+ m_slot->m_program->install_rom(0x6000, 0x67ff, memregion("software")->base());
+ m_slot->m_program->install_rom(0xd000, 0xffff, memregion("software")->base());
+}
diff --git a/src/devices/bus/vtech/memexp/wordpro.h b/src/devices/bus/vtech/memexp/wordpro.h
new file mode 100644
index 00000000000..8626787f16e
--- /dev/null
+++ b/src/devices/bus/vtech/memexp/wordpro.h
@@ -0,0 +1,39 @@
+// license:GPL-2.0+
+// copyright-holders:Dirk Best
+/***************************************************************************
+
+ Dick Smith VZ-300 WordPro Cartridge
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __VTECH_MEMEXP_WORDPRO_H__
+#define __VTECH_MEMEXP_WORDPRO_H__
+
+#include "emu.h"
+#include "memexp.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> wordpro_device
+
+class wordpro_device : public device_t, public device_memexp_interface
+{
+public:
+ // construction/destruction
+ wordpro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual const rom_entry *device_rom_region() const;
+ virtual void device_start();
+ virtual void device_reset();
+};
+
+// device type definition
+extern const device_type WORDPRO;
+
+#endif // __VTECH_MEMEXP_WORDPRO_H__