diff --git a/hash/vic1001_cart.xml b/hash/vic1001_cart.xml
index 52abdce116f..3fd6dbf0701 100644
--- a/hash/vic1001_cart.xml
+++ b/hash/vic1001_cart.xml
@@ -3908,4 +3908,18 @@
+
+
+ Data 20 Display Manager
+ 1982
+ Data 20 Corporation
+
+
+
+
+
+
+
+
+
diff --git a/hash/vic1001_flop.xml b/hash/vic1001_flop.xml
index 52df6a600a3..725cd688de0 100644
--- a/hash/vic1001_flop.xml
+++ b/hash/vic1001_flop.xml
@@ -71,4 +71,17 @@
+
+ Data 20 Display Manager
+ 1982
+ Data 20 Corporation
+
+
+
+
+
+
+
+
+
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index 9902d41b3b5..51ddfa5e87f 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -1427,6 +1427,8 @@ if (BUSES["VIC20"]~=null) then
MAME_DIR .. "src/devices/bus/vic20/vic1112.h",
MAME_DIR .. "src/devices/bus/vic20/vic1210.cpp",
MAME_DIR .. "src/devices/bus/vic20/vic1210.h",
+ MAME_DIR .. "src/devices/bus/vic20/videopak.cpp",
+ MAME_DIR .. "src/devices/bus/vic20/videopak.h",
MAME_DIR .. "src/devices/bus/vic20/speakeasy.cpp",
MAME_DIR .. "src/devices/bus/vic20/speakeasy.h",
MAME_DIR .. "src/devices/bus/vic20/user.cpp",
diff --git a/src/devices/bus/vic20/exp.cpp b/src/devices/bus/vic20/exp.cpp
index a07e623f72a..d465279c91e 100644
--- a/src/devices/bus/vic20/exp.cpp
+++ b/src/devices/bus/vic20/exp.cpp
@@ -202,6 +202,7 @@ void vic20_expansion_slot_device::cd_w(address_space &space, offs_t offset, uint
#include "vic1111.h"
#include "vic1112.h"
#include "vic1210.h"
+#include "videopak.h"
#include "speakeasy.h"
SLOT_INTERFACE_START( vic20_expansion_cards )
@@ -211,6 +212,7 @@ SLOT_INTERFACE_START( vic20_expansion_cards )
SLOT_INTERFACE("16k", VIC1111)
SLOT_INTERFACE("fe3", VIC20_FE3)
SLOT_INTERFACE("speakez", VIC20_SPEAKEASY)
+ SLOT_INTERFACE("videopak", VIC20_VIDEO_PAK)
// the following need ROMs from the software list
SLOT_INTERFACE_INTERNAL("standard", VIC20_STD)
diff --git a/src/devices/bus/vic20/videopak.cpp b/src/devices/bus/vic20/videopak.cpp
new file mode 100644
index 00000000000..ecf3355bab8
--- /dev/null
+++ b/src/devices/bus/vic20/videopak.cpp
@@ -0,0 +1,336 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/**********************************************************************
+
+ Data 20 Corporation Video Pak cartridge emulation
+ aka Data 20 Display Manager aka Protecto 40/80
+
+**********************************************************************/
+
+#include "videopak.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define VIDEORAM_SIZE 0x800
+#define RAM_SIZE 0x10000
+
+#define MC6845_TAG "mc6845"
+#define MC6845_SCREEN_TAG "screen80"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIC20_VIDEO_PAK = &device_creator;
+
+
+//-------------------------------------------------
+// ROM( videopak )
+//-------------------------------------------------
+
+ROM_START( videopak )
+ ROM_REGION( 0x800, MC6845_TAG, 0 )
+ // ROM has been borrowed from the C64 XL80 cartridge
+ ROM_LOAD( "chargen", 0x000, 0x800, BAD_DUMP CRC(9edf5e58) SHA1(4b244e6d94a7653a2e52c351589f0b469119fb04) )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const tiny_rom_entry *vic20_video_pak_t::device_rom_region() const
+{
+ return ROM_NAME( videopak );
+}
+
+//-------------------------------------------------
+// mc6845
+//-------------------------------------------------
+
+MC6845_UPDATE_ROW( vic20_video_pak_t::crtc_update_row )
+{
+ const pen_t *pen = m_palette->pens();
+
+ for (int column = 0; column < x_count; column++)
+ {
+ uint8_t code = m_videoram[((ma + column) & 0x7ff)];
+ uint16_t addr = (code << 3) | (ra & 0x07);
+ uint8_t data = m_char_rom->base()[addr & 0x7ff];
+
+ if (column == cursor_x)
+ {
+ data = 0xff;
+ }
+
+ for (int bit = 0; bit < 8; bit++)
+ {
+ int x = (column * 8) + bit;
+ int color = BIT(data, 7) && de;
+
+ bitmap.pix32(vbp + y, hbp + x) = pen[color];
+
+ data <<= 1;
+ }
+ }
+}
+
+//-------------------------------------------------
+// GFXDECODE( vic20_video_pak )
+//-------------------------------------------------
+
+static GFXDECODE_START( vic20_video_pak )
+ GFXDECODE_ENTRY(MC6845_TAG, 0x0000, gfx_8x8x1, 0, 1)
+GFXDECODE_END
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( vic20_video_pak )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( vic20_video_pak )
+ MCFG_SCREEN_ADD_MONOCHROME(MC6845_SCREEN_TAG, RASTER, rgb_t::white())
+ MCFG_SCREEN_UPDATE_DEVICE(MC6845_TAG, h46505_device, screen_update)
+ MCFG_SCREEN_SIZE(80*8, 24*8)
+ MCFG_SCREEN_VISIBLE_AREA(0, 80*8-1, 0, 24*8-1)
+ MCFG_SCREEN_REFRESH_RATE(50)
+
+ MCFG_GFXDECODE_ADD("gfxdecode", "palette", vic20_video_pak)
+ MCFG_PALETTE_ADD_MONOCHROME("palette")
+
+ MCFG_MC6845_ADD(MC6845_TAG, H46505, MC6845_SCREEN_TAG, XTAL_14_31818MHz / 8)
+ MCFG_MC6845_SHOW_BORDER_AREA(true)
+ MCFG_MC6845_CHAR_WIDTH(8)
+ MCFG_MC6845_UPDATE_ROW_CB(vic20_video_pak_t, crtc_update_row)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor vic20_video_pak_t::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( vic20_video_pak );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// vic20_video_pak_t - constructor
+//-------------------------------------------------
+
+vic20_video_pak_t::vic20_video_pak_t(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, VIC20_VIDEO_PAK, "Data 20 Video Pak", tag, owner, clock, "videopak", __FILE__),
+ device_vic20_expansion_card_interface(mconfig, *this),
+ m_crtc(*this, MC6845_TAG),
+ m_palette(*this, "palette"),
+ m_char_rom(*this, MC6845_TAG),
+ m_videoram(*this, "videoram"),
+ m_ram(*this, "ram")
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vic20_video_pak_t::device_start()
+{
+ // allocate memory
+ m_videoram.allocate(VIDEORAM_SIZE);
+ m_ram.allocate(RAM_SIZE);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void vic20_video_pak_t::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// vic20_cd_r - cartridge data read
+//-------------------------------------------------
+
+uint8_t vic20_video_pak_t::vic20_cd_r(address_space &space, offs_t offset, uint8_t data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3)
+{
+ if (!m_ram_enable)
+ {
+ if (m_bank_size)
+ {
+ if (!blk1)
+ {
+ offs_t addr = m_bank_msb << 15 | m_bank_lsb << 14 | offset;
+
+ data = m_ram[addr];
+ }
+
+ if (!blk2)
+ {
+ offs_t addr = m_bank_msb << 15 | m_bank_lsb << 14 | 0x2000 | offset;
+
+ data = m_ram[addr];
+ }
+ }
+ else
+ {
+ if (!blk1)
+ {
+ offs_t addr = m_bank_msb << 15 | offset;
+
+ data = m_ram[addr];
+ }
+
+ if (!blk2)
+ {
+ offs_t addr = m_bank_msb << 15 | 0x2000 | offset;
+
+ data = m_ram[addr];
+ }
+
+ if (!blk3)
+ {
+ offs_t addr = m_bank_msb << 15 | 0x4000 | offset;
+
+ data = m_ram[addr];
+ }
+ }
+ }
+
+ if (!blk5)
+ {
+ switch ((offset >> 11) & 0x03)
+ {
+ case 0:
+ data = m_blk5[offset & 0x7ff];
+ break;
+
+ case 3:
+ data = m_videoram[offset & 0x7ff];
+ break;
+ }
+ }
+
+ if (!io2)
+ {
+ if (offset == 0x1bf9)
+ {
+ data = m_crtc->register_r(space, 0);
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// vic20_cd_w - cartridge data write
+//-------------------------------------------------
+
+void vic20_video_pak_t::vic20_cd_w(address_space &space, offs_t offset, uint8_t data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3)
+{
+ if (!m_ram_enable)
+ {
+ if (m_bank_size)
+ {
+ if (!blk1)
+ {
+ offs_t addr = m_bank_msb << 15 | m_bank_lsb << 14 | offset;
+
+ m_ram[addr] = data;
+ }
+
+ if (!blk2)
+ {
+ offs_t addr = m_bank_msb << 15 | m_bank_lsb << 14 | 0x2000 | offset;
+
+ m_ram[addr] = data;
+ }
+ }
+ else
+ {
+ if (!blk1)
+ {
+ offs_t addr = m_bank_msb << 15 | offset;
+
+ m_ram[addr] = data;
+ }
+
+ if (!blk2)
+ {
+ offs_t addr = m_bank_msb << 15 | 0x2000 | offset;
+
+ m_ram[addr] = data;
+ }
+
+ if (!blk3)
+ {
+ offs_t addr = m_bank_msb << 15 | 0x4000 | offset;
+
+ m_ram[addr] = data;
+ }
+ }
+ }
+
+ if (!blk5)
+ {
+ switch ((offset >> 11) & 0x03)
+ {
+ case 3:
+ m_videoram[offset & 0x7ff] = data;
+ break;
+ }
+ }
+
+ if (!io2)
+ {
+ switch (offset)
+ {
+ case 0x1bf8:
+ m_crtc->address_w(space, 0, data);
+ break;
+
+ case 0x1bf9:
+ m_crtc->register_w(space, 0, data);
+ break;
+
+ case 0x1bfc:
+ /*
+
+ bit description
+
+ 0 0 = upper case, 1 = lower case
+ 1 bank size: 0 = 2x24KB, 1 = 4x16KB
+ 2 16KB mode address LSB
+ 3 memory address MSB
+ 4 0 = enable RAM, 1 = disable RAM
+ 5 0 = 40 columns, 1 = 80 columns (Data 20 Video Manager)
+
+ */
+
+ m_case = BIT(data, 0);
+ m_bank_size = BIT(data, 1);
+ m_bank_lsb = BIT(data, 2);
+ m_bank_msb = BIT(data, 3);
+ m_ram_enable = BIT(data, 4);
+ m_columns = BIT(data, 5);
+ break;
+ }
+ }
+}
diff --git a/src/devices/bus/vic20/videopak.h b/src/devices/bus/vic20/videopak.h
new file mode 100644
index 00000000000..5d1e46f2005
--- /dev/null
+++ b/src/devices/bus/vic20/videopak.h
@@ -0,0 +1,71 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/**********************************************************************
+
+ Data 20 Corporation Video Pak cartridge emulation
+ aka Data 20 Display Manager aka Protecto 40/80
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIC20_VIDEO_PAK__
+#define __VIC20_VIDEO_PAK__
+
+
+#include "emu.h"
+#include "exp.h"
+#include "video/mc6845.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> vic20_video_pak_t
+
+class vic20_video_pak_t : public device_t,
+ public device_vic20_expansion_card_interface
+{
+public:
+ // construction/destruction
+ vic20_video_pak_t(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // optional information overrides
+ virtual const tiny_rom_entry *device_rom_region() const override;
+ virtual machine_config_constructor device_mconfig_additions() const override;
+
+ // not really public
+ MC6845_UPDATE_ROW( crtc_update_row );
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_vic20_expansion_card_interface overrides
+ virtual uint8_t vic20_cd_r(address_space &space, offs_t offset, uint8_t data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) override;
+ virtual void vic20_cd_w(address_space &space, offs_t offset, uint8_t data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) override;
+
+private:
+ required_device m_crtc;
+ required_device m_palette;
+ required_memory_region m_char_rom;
+ optional_shared_ptr m_videoram;
+ optional_shared_ptr m_ram;
+
+ bool m_case;
+ bool m_bank_size;
+ bool m_bank_lsb;
+ bool m_bank_msb;
+ bool m_ram_enable;
+ bool m_columns;
+};
+
+
+// device type definition
+extern const device_type VIC20_VIDEO_PAK;
+
+
+#endif