summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Curt Coder <curtcoder@mail.com>2011-03-28 20:15:05 +0000
committer Curt Coder <curtcoder@mail.com>2011-03-28 20:15:05 +0000
commit399c6e8c263fa6cac758a20fe7a52349b2281f9b (patch)
treeb00b464f69e3eed88621653419add5b883df0ab0 /src
parent90306a806ff3071d2ab79ad61893cc87a0242485 (diff)
Imported some common C++ devices from MESS to emu folder.
Diffstat (limited to 'src')
-rw-r--r--src/emu/emu.mak215
-rw-r--r--src/emu/machine/cdp1871.c319
-rw-r--r--src/emu/machine/cdp1871.h171
-rw-r--r--src/emu/machine/e0516.c263
-rw-r--r--src/emu/machine/e0516.h114
-rw-r--r--src/emu/machine/i8155.c653
-rw-r--r--src/emu/machine/i8155.h181
-rw-r--r--src/emu/machine/i8212.c180
-rw-r--r--src/emu/machine/i8212.h136
-rw-r--r--src/emu/machine/i8355.c269
-rw-r--r--src/emu/machine/i8355.h150
-rw-r--r--src/emu/machine/nmc9306.c365
-rw-r--r--src/emu/machine/nmc9306.h118
-rw-r--r--src/emu/machine/z8536.c610
-rw-r--r--src/emu/machine/z8536.h182
-rw-r--r--src/emu/video/crt9007.c1017
-rw-r--r--src/emu/video/crt9007.h233
-rw-r--r--src/emu/video/crt9021.c269
-rw-r--r--src/emu/video/crt9021.h144
-rw-r--r--src/emu/video/crt9212.c269
-rw-r--r--src/emu/video/crt9212.h148
-rw-r--r--src/emu/video/hd61830.c600
-rw-r--r--src/emu/video/hd61830.h156
23 files changed, 6660 insertions, 102 deletions
diff --git a/src/emu/emu.mak b/src/emu/emu.mak
index 8374b094439..539b3314a74 100644
--- a/src/emu/emu.mak
+++ b/src/emu/emu.mak
@@ -133,110 +133,121 @@ EMUDRIVEROBJS = \
$(EMUDRIVERS)/empty.o \
EMUMACHINEOBJS = \
- $(EMUMACHINE)/53c810.o \
- $(EMUMACHINE)/6522via.o \
- $(EMUMACHINE)/6526cia.o \
- $(EMUMACHINE)/6532riot.o \
- $(EMUMACHINE)/6821pia.o \
- $(EMUMACHINE)/6840ptm.o \
- $(EMUMACHINE)/6850acia.o \
- $(EMUMACHINE)/68681.o \
- $(EMUMACHINE)/74123.o \
- $(EMUMACHINE)/74148.o \
- $(EMUMACHINE)/74153.o \
- $(EMUMACHINE)/74181.o \
- $(EMUMACHINE)/7474.o \
- $(EMUMACHINE)/8042kbdc.o \
- $(EMUMACHINE)/8237dma.o \
- $(EMUMACHINE)/8255ppi.o \
- $(EMUMACHINE)/8257dma.o \
- $(EMUMACHINE)/adc083x.o \
- $(EMUMACHINE)/adc1038.o \
- $(EMUMACHINE)/adc1213x.o \
- $(EMUMACHINE)/am53cf96.o \
- $(EMUMACHINE)/at28c16.o \
- $(EMUMACHINE)/cdp1852.o \
- $(EMUMACHINE)/cr589.o \
- $(EMUMACHINE)/ds1302.o \
- $(EMUMACHINE)/ds2401.o \
- $(EMUMACHINE)/ds2404.o \
- $(EMUMACHINE)/eeprom.o \
- $(EMUMACHINE)/er2055.o \
- $(EMUMACHINE)/f3853.o \
- $(EMUMACHINE)/generic.o \
- $(EMUMACHINE)/i2cmem.o \
- $(EMUMACHINE)/i8243.o \
- $(EMUMACHINE)/i8255a.o \
- $(EMUMACHINE)/idectrl.o \
- $(EMUMACHINE)/ins8154.o \
- $(EMUMACHINE)/ins8250.o \
- $(EMUMACHINE)/intelfsh.o \
- $(EMUMACHINE)/k033906.o \
- $(EMUMACHINE)/k056230.o \
- $(EMUMACHINE)/latch8.o \
- $(EMUMACHINE)/ldcore.o \
- $(EMUMACHINE)/ldpr8210.o \
- $(EMUMACHINE)/ldv1000.o \
- $(EMUMACHINE)/ldvp931.o \
- $(EMUMACHINE)/mb14241.o \
- $(EMUMACHINE)/mb3773.o \
- $(EMUMACHINE)/mb87078.o \
- $(EMUMACHINE)/mc146818.o \
- $(EMUMACHINE)/mc68901.o \
- $(EMUMACHINE)/microtch.o \
- $(EMUMACHINE)/msm6242.o \
- $(EMUMACHINE)/nvram.o \
- $(EMUMACHINE)/pc16552d.o \
- $(EMUMACHINE)/pci.o \
- $(EMUMACHINE)/pd4990a.o \
- $(EMUMACHINE)/pic8259.o \
- $(EMUMACHINE)/pit8253.o \
- $(EMUMACHINE)/ram.o \
- $(EMUMACHINE)/roc10937.o \
- $(EMUMACHINE)/rp5h01.o \
- $(EMUMACHINE)/rtc65271.o \
- $(EMUMACHINE)/s3c2400.o \
- $(EMUMACHINE)/s3c2410.o \
- $(EMUMACHINE)/s3c2440.o \
- $(EMUMACHINE)/scsi.o \
- $(EMUMACHINE)/scsicd.o \
- $(EMUMACHINE)/scsidev.o \
- $(EMUMACHINE)/scsihd.o \
- $(EMUMACHINE)/secflash.o \
- $(EMUMACHINE)/smc91c9x.o \
- $(EMUMACHINE)/timekpr.o \
- $(EMUMACHINE)/tmp68301.o \
- $(EMUMACHINE)/tms6100.o \
- $(EMUMACHINE)/upd4701.o \
- $(EMUMACHINE)/wd33c93.o \
- $(EMUMACHINE)/x2212.o \
- $(EMUMACHINE)/x76f041.o \
- $(EMUMACHINE)/x76f100.o \
- $(EMUMACHINE)/z80ctc.o \
- $(EMUMACHINE)/z80dart.o \
- $(EMUMACHINE)/z80dma.o \
- $(EMUMACHINE)/z80pio.o \
- $(EMUMACHINE)/z80sio.o \
- $(EMUMACHINE)/z80sti.o \
+ $(EMUMACHINE)/53c810.o \
+ $(EMUMACHINE)/6522via.o \
+ $(EMUMACHINE)/6526cia.o \
+ $(EMUMACHINE)/6532riot.o \
+ $(EMUMACHINE)/6821pia.o \
+ $(EMUMACHINE)/6840ptm.o \
+ $(EMUMACHINE)/6850acia.o \
+ $(EMUMACHINE)/68681.o \
+ $(EMUMACHINE)/74123.o \
+ $(EMUMACHINE)/74148.o \
+ $(EMUMACHINE)/74153.o \
+ $(EMUMACHINE)/74181.o \
+ $(EMUMACHINE)/7474.o \
+ $(EMUMACHINE)/8042kbdc.o \
+ $(EMUMACHINE)/8237dma.o \
+ $(EMUMACHINE)/8255ppi.o \
+ $(EMUMACHINE)/8257dma.o \
+ $(EMUMACHINE)/adc083x.o \
+ $(EMUMACHINE)/adc1038.o \
+ $(EMUMACHINE)/adc1213x.o \
+ $(EMUMACHINE)/am53cf96.o \
+ $(EMUMACHINE)/at28c16.o \
+ $(EMUMACHINE)/cdp1852.o \
+ $(EMUMACHINE)/cdp1871.o \
+ $(EMUMACHINE)/cr589.o \
+ $(EMUMACHINE)/ds1302.o \
+ $(EMUMACHINE)/ds2401.o \
+ $(EMUMACHINE)/ds2404.o \
+ $(EMUMACHINE)/e0516.o \
+ $(EMUMACHINE)/eeprom.o \
+ $(EMUMACHINE)/er2055.o \
+ $(EMUMACHINE)/f3853.o \
+ $(EMUMACHINE)/generic.o \
+ $(EMUMACHINE)/i2cmem.o \
+ $(EMUMACHINE)/i8155.o \
+ $(EMUMACHINE)/i8212.o \
+ $(EMUMACHINE)/i8243.o \
+ $(EMUMACHINE)/i8255a.o \
+ $(EMUMACHINE)/i8355.o \
+ $(EMUMACHINE)/idectrl.o \
+ $(EMUMACHINE)/ins8154.o \
+ $(EMUMACHINE)/ins8250.o \
+ $(EMUMACHINE)/intelfsh.o \
+ $(EMUMACHINE)/k033906.o \
+ $(EMUMACHINE)/k056230.o \
+ $(EMUMACHINE)/latch8.o \
+ $(EMUMACHINE)/ldcore.o \
+ $(EMUMACHINE)/ldpr8210.o \
+ $(EMUMACHINE)/ldv1000.o \
+ $(EMUMACHINE)/ldvp931.o \
+ $(EMUMACHINE)/mb14241.o \
+ $(EMUMACHINE)/mb3773.o \
+ $(EMUMACHINE)/mb87078.o \
+ $(EMUMACHINE)/mc146818.o \
+ $(EMUMACHINE)/mc68901.o \
+ $(EMUMACHINE)/microtch.o \
+ $(EMUMACHINE)/msm6242.o \
+ $(EMUMACHINE)/nmc9306.o \
+ $(EMUMACHINE)/nvram.o \
+ $(EMUMACHINE)/pc16552d.o \
+ $(EMUMACHINE)/pci.o \
+ $(EMUMACHINE)/pd4990a.o \
+ $(EMUMACHINE)/pic8259.o \
+ $(EMUMACHINE)/pit8253.o \
+ $(EMUMACHINE)/ram.o \
+ $(EMUMACHINE)/roc10937.o \
+ $(EMUMACHINE)/rp5h01.o \
+ $(EMUMACHINE)/rtc65271.o \
+ $(EMUMACHINE)/s3c2400.o \
+ $(EMUMACHINE)/s3c2410.o \
+ $(EMUMACHINE)/s3c2440.o \
+ $(EMUMACHINE)/scsi.o \
+ $(EMUMACHINE)/scsicd.o \
+ $(EMUMACHINE)/scsidev.o \
+ $(EMUMACHINE)/scsihd.o \
+ $(EMUMACHINE)/secflash.o \
+ $(EMUMACHINE)/smc91c9x.o \
+ $(EMUMACHINE)/timekpr.o \
+ $(EMUMACHINE)/tmp68301.o \
+ $(EMUMACHINE)/tms6100.o \
+ $(EMUMACHINE)/upd4701.o \
+ $(EMUMACHINE)/wd33c93.o \
+ $(EMUMACHINE)/x2212.o \
+ $(EMUMACHINE)/x76f041.o \
+ $(EMUMACHINE)/x76f100.o \
+ $(EMUMACHINE)/z80ctc.o \
+ $(EMUMACHINE)/z80dart.o \
+ $(EMUMACHINE)/z80dma.o \
+ $(EMUMACHINE)/z80pio.o \
+ $(EMUMACHINE)/z80sio.o \
+ $(EMUMACHINE)/z80sti.o \
+ $(EMUMACHINE)/z8536.o \
EMUVIDEOOBJS = \
- $(EMUVIDEO)/generic.o \
- $(EMUVIDEO)/hd63484.o \
- $(EMUVIDEO)/mc6845.o \
- $(EMUVIDEO)/pc_vga.o \
- $(EMUVIDEO)/pc_video.o \
- $(EMUVIDEO)/poly.o \
- $(EMUVIDEO)/resnet.o \
- $(EMUVIDEO)/rgbutil.o \
- $(EMUVIDEO)/s2636.o \
- $(EMUVIDEO)/saa5050.o \
- $(EMUVIDEO)/tlc34076.o \
- $(EMUVIDEO)/tms34061.o \
- $(EMUVIDEO)/tms9927.o \
- $(EMUVIDEO)/tms9928a.o \
- $(EMUVIDEO)/v9938.o \
- $(EMUVIDEO)/vector.o \
- $(EMUVIDEO)/voodoo.o \
+ $(EMUVIDEO)/crt9007.o \
+ $(EMUVIDEO)/crt9021.o \
+ $(EMUVIDEO)/crt9212.o \
+ $(EMUVIDEO)/generic.o \
+ $(EMUVIDEO)/hd61830.o \
+ $(EMUVIDEO)/hd63484.o \
+ $(EMUVIDEO)/mc6845.o \
+ $(EMUVIDEO)/pc_vga.o \
+ $(EMUVIDEO)/pc_video.o \
+ $(EMUVIDEO)/poly.o \
+ $(EMUVIDEO)/resnet.o \
+ $(EMUVIDEO)/rgbutil.o \
+ $(EMUVIDEO)/s2636.o \
+ $(EMUVIDEO)/saa5050.o \
+ $(EMUVIDEO)/tlc34076.o \
+ $(EMUVIDEO)/tms34061.o \
+ $(EMUVIDEO)/tms9927.o \
+ $(EMUVIDEO)/tms9928a.o \
+ $(EMUVIDEO)/v9938.o \
+ $(EMUVIDEO)/vector.o \
+ $(EMUVIDEO)/voodoo.o \
EMUIMAGEDEVOBJS = \
$(EMUIMAGEDEV)/bitbngr.o \
diff --git a/src/emu/machine/cdp1871.c b/src/emu/machine/cdp1871.c
new file mode 100644
index 00000000000..1acacdf25da
--- /dev/null
+++ b/src/emu/machine/cdp1871.c
@@ -0,0 +1,319 @@
+/**********************************************************************
+
+ RCA CDP1871 Keyboard Encoder emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "cdp1871.h"
+#include "cpu/mcs48/mcs48.h"
+#include "machine/devhelpr.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+static const UINT8 CDP1871_KEY_CODES[4][11][8] =
+{
+ // normal
+ {
+ { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 },
+ { 0x38, 0x39, 0x3a, 0x3b, 0x2c, 0x2d, 0x2e, 0x2f },
+ { 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67 },
+ { 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f },
+ { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77 },
+ { 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f },
+ { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f },
+ { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 },
+ { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f },
+ { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 },
+ { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f }
+ },
+
+ // alpha
+ {
+ { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 },
+ { 0x38, 0x39, 0x3a, 0x3b, 0x2c, 0x2d, 0x2e, 0x2f },
+ { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 },
+ { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f },
+ { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57 },
+ { 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f },
+ { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f },
+ { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 },
+ { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f },
+ { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 },
+ { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f }
+ },
+
+ // shift
+ {
+ { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 },
+ { 0x28, 0x29, 0x2a, 0x2b, 0x3c, 0x3d, 0x3e, 0x3f },
+ { 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 },
+ { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f },
+ { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57 },
+ { 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f },
+ { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f },
+ { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 },
+ { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f },
+ { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 },
+ { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f }
+ },
+
+ // control
+ {
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
+ { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+ { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 },
+ { 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+ { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f },
+ { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 },
+ { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f },
+ { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 },
+ { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f }
+ }
+};
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type CDP1871 = cdp1871_device_config::static_alloc_device_config;
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+GENERIC_DEVICE_CONFIG_SETUP(cdp1871, "RCA CDP1871")
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void cdp1871_device_config::device_config_complete()
+{
+ // inherit a copy of the static data
+ const cdp1871_interface *intf = reinterpret_cast<const cdp1871_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<cdp1871_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&out_da_func, 0, sizeof(out_da_func));
+ memset(&out_rpt_func, 0, sizeof(out_rpt_func));
+ // m_in_d_func[]
+ memset(&in_shift_func, 0, sizeof(in_shift_func));
+ memset(&in_control_func, 0, sizeof(in_control_func));
+ memset(&in_alpha_func, 0, sizeof(in_alpha_func));
+ }
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// cdp1871_device - constructor
+//-------------------------------------------------
+
+cdp1871_device::cdp1871_device(running_machine &_machine, const cdp1871_device_config &config)
+ : device_t(_machine, config),
+ m_inhibit(false),
+ m_sense(0),
+ m_drive(0),
+ m_next_da(CLEAR_LINE),
+ m_next_rpt(CLEAR_LINE),
+ m_config(config)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cdp1871_device::device_start()
+{
+ // resolve callbacks
+ devcb_resolve_write_line(&m_out_da_func, &m_config.out_da_func, this);
+ devcb_resolve_write_line(&m_out_rpt_func, &m_config.out_rpt_func, this);
+ devcb_resolve_read8(&m_in_d_func[0], &m_config.in_d1_func, this);
+ devcb_resolve_read8(&m_in_d_func[1], &m_config.in_d2_func, this);
+ devcb_resolve_read8(&m_in_d_func[2], &m_config.in_d3_func, this);
+ devcb_resolve_read8(&m_in_d_func[3], &m_config.in_d4_func, this);
+ devcb_resolve_read8(&m_in_d_func[4], &m_config.in_d5_func, this);
+ devcb_resolve_read8(&m_in_d_func[5], &m_config.in_d6_func, this);
+ devcb_resolve_read8(&m_in_d_func[6], &m_config.in_d7_func, this);
+ devcb_resolve_read8(&m_in_d_func[7], &m_config.in_d8_func, this);
+ devcb_resolve_read8(&m_in_d_func[8], &m_config.in_d9_func, this);
+ devcb_resolve_read8(&m_in_d_func[9], &m_config.in_d10_func, this);
+ devcb_resolve_read8(&m_in_d_func[10], &m_config.in_d11_func, this);
+ devcb_resolve_read_line(&m_in_shift_func, &m_config.in_shift_func, this);
+ devcb_resolve_read_line(&m_in_control_func, &m_config.in_control_func, this);
+ devcb_resolve_read_line(&m_in_alpha_func, &m_config.in_alpha_func, this);
+
+ // set initial values
+ change_output_lines();
+
+ // allocate timers
+ m_scan_timer = timer_alloc();
+ m_scan_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
+
+ // register for state saving
+ save_item(NAME(m_inhibit));
+ save_item(NAME(m_sense));
+ save_item(NAME(m_drive));
+ save_item(NAME(m_shift));
+ save_item(NAME(m_control));
+ save_item(NAME(m_da));
+ save_item(NAME(m_next_da));
+ save_item(NAME(m_rpt));
+ save_item(NAME(m_next_rpt));
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void cdp1871_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ change_output_lines();
+ clock_scan_counters();
+ detect_keypress();
+}
+
+
+//-------------------------------------------------
+// change_output_lines - change output lines
+//-------------------------------------------------
+
+void cdp1871_device::change_output_lines()
+{
+ if (m_next_da != m_da)
+ {
+ m_da = m_next_da;
+
+ devcb_call_write_line(&m_out_da_func, m_da);
+ }
+
+ if (m_next_rpt != m_rpt)
+ {
+ m_rpt = m_next_rpt;
+
+ devcb_call_write_line(&m_out_rpt_func, m_rpt);
+ }
+}
+
+
+//-------------------------------------------------
+// clock_scan_counters - clock the keyboard
+// scan counters
+//-------------------------------------------------
+
+void cdp1871_device::clock_scan_counters()
+{
+ if (!m_inhibit)
+ {
+ m_sense++;
+
+ if (m_sense == 8)
+ {
+ m_sense = 0;
+ m_drive++;
+
+ if (m_drive == 11)
+ {
+ m_drive = 0;
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// detect_keypress - detect key press
+//-------------------------------------------------
+
+void cdp1871_device::detect_keypress()
+{
+ UINT8 data = 0;
+
+ data = devcb_call_read8(&m_in_d_func[m_drive], 0);
+
+ if (data == (1 << m_sense))
+ {
+ if (!m_inhibit)
+ {
+ m_shift = devcb_call_read_line(&m_in_shift_func);
+ m_control = devcb_call_read_line(&m_in_control_func);
+ m_inhibit = true;
+ m_next_da = ASSERT_LINE;
+ }
+ else
+ {
+ m_next_rpt = ASSERT_LINE;
+ }
+ }
+ else
+ {
+ m_inhibit = false;
+ m_next_rpt = CLEAR_LINE;
+ }
+}
+
+
+//-------------------------------------------------
+// data_r - keyboard data read
+//-------------------------------------------------
+
+READ8_MEMBER( cdp1871_device::data_r )
+{
+ int table = 0;
+ int alpha = devcb_call_read_line(&m_in_alpha_func);
+
+ if (m_control) table = 3; else if (m_shift) table = 2; else if (alpha) table = 1;
+
+ // reset DA on next TPB
+ m_next_da = CLEAR_LINE;
+
+ return CDP1871_KEY_CODES[table][m_drive][m_sense];
+}
+
+
+//-------------------------------------------------
+// da_r - data available
+//-------------------------------------------------
+
+READ_LINE_MEMBER( cdp1871_device::da_r )
+{
+ return m_da;
+}
+
+
+//-------------------------------------------------
+// rpt_r - keyboard repeat
+//-------------------------------------------------
+
+READ_LINE_MEMBER( cdp1871_device::rpt_r )
+{
+ return m_rpt;
+}
diff --git a/src/emu/machine/cdp1871.h b/src/emu/machine/cdp1871.h
new file mode 100644
index 00000000000..6d3a7fffc6d
--- /dev/null
+++ b/src/emu/machine/cdp1871.h
@@ -0,0 +1,171 @@
+/**********************************************************************
+
+ RCA CDP1871 Keyboard Encoder emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ D1 1 |* \_/ | 40 Vdd
+ D2 2 | | 39 SHIFT
+ D3 3 | | 38 CONTROL
+ D4 4 | | 37 ALPHA
+ D5 5 | | 36 DEBOUNCE
+ D6 6 | | 35 _RTP
+ D7 7 | | 34 TPB
+ D8 8 | | 33 _DA
+ D9 9 | | 32 BUS 7
+ D10 10 | CDP1871 | 31 BUS 6
+ D11 11 | | 30 BUS 5
+ S1 12 | | 29 BUS 4
+ S2 13 | | 28 BUS 3
+ S3 14 | | 27 BUS 2
+ S4 15 | | 26 BUS 1
+ S5 16 | | 25 BUS 0
+ S6 17 | | 24 CS4
+ S7 18 | | 23 CS3
+ S8 19 | | 22 CS2
+ Vss 20 |_____________| 21 _CS1
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __CDP1871__
+#define __CDP1871__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_CDP1871_ADD(_tag, _intrf, _clock) \
+ MCFG_DEVICE_ADD(_tag, CDP1871, _clock) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define CDP1871_INTERFACE(name) \
+ const cdp1871_interface (name)=
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> cdp1871_interface
+
+struct cdp1871_interface
+{
+ devcb_read8 in_d1_func;
+ devcb_read8 in_d2_func;
+ devcb_read8 in_d3_func;
+ devcb_read8 in_d4_func;
+ devcb_read8 in_d5_func;
+ devcb_read8 in_d6_func;
+ devcb_read8 in_d7_func;
+ devcb_read8 in_d8_func;
+ devcb_read8 in_d9_func;
+ devcb_read8 in_d10_func;
+ devcb_read8 in_d11_func;
+
+ devcb_read_line in_shift_func;
+ devcb_read_line in_control_func;
+ devcb_read_line in_alpha_func;
+
+ // this gets called for every change of the DA pin (pin 33)
+ devcb_write_line out_da_func;
+
+ // this gets called for every change of the RPT pin (pin 35)
+ devcb_write_line out_rpt_func;
+};
+
+
+// ======================> cdp1871_device_config
+
+class cdp1871_device_config : public device_config,
+ public cdp1871_interface
+{
+ friend class cdp1871_device;
+
+ // construction/destruction
+ cdp1871_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+protected:
+ // device_config overrides
+ virtual void device_config_complete();
+};
+
+
+// ======================> cdp1871_device
+
+class cdp1871_device : public device_t
+{
+ friend class cdp1871_device_config;
+
+ // construction/destruction
+ cdp1871_device(running_machine &_machine, const cdp1871_device_config &_config);
+
+public:
+ DECLARE_READ8_MEMBER( data_r );
+
+ DECLARE_READ_LINE_MEMBER( da_r );
+ DECLARE_READ_LINE_MEMBER( rpt_r );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ void change_output_lines();
+ void clock_scan_counters();
+ void detect_keypress();
+
+private:
+ devcb_resolved_write_line m_out_da_func;
+ devcb_resolved_write_line m_out_rpt_func;
+ devcb_resolved_read8 m_in_d_func[11];
+ devcb_resolved_read_line m_in_shift_func;
+ devcb_resolved_read_line m_in_control_func;
+ devcb_resolved_read_line m_in_alpha_func;
+
+ bool m_inhibit; // scan counter clock inhibit
+ int m_sense; // sense input scan counter
+ int m_drive; // modifier inputs
+
+ int m_shift; // latched shift modifier
+ int m_control; // latched control modifier
+
+ int m_da; // data available flag
+ int m_next_da; // next value of data available flag
+ int m_rpt; // repeat flag
+ int m_next_rpt; // next value of repeat flag
+
+ // timers
+ emu_timer *m_scan_timer; // keyboard scan timer
+
+ const cdp1871_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type CDP1871;
+
+
+
+#endif
diff --git a/src/emu/machine/e0516.c b/src/emu/machine/e0516.c
new file mode 100644
index 00000000000..05b7df778cd
--- /dev/null
+++ b/src/emu/machine/e0516.c
@@ -0,0 +1,263 @@
+/**********************************************************************
+
+ E05-16 Real Time Clock emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "e0516.h"
+#include "machine/devhelpr.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 1
+
+
+// states
+enum
+{
+ STATE_ADDRESS = 0,
+ STATE_DATA
+};
+
+
+// registers
+enum
+{
+ SECOND = 0,
+ MINUTE,
+ HOUR,
+ DAY,
+ MONTH,
+ DAY_OF_WEEK,
+ YEAR,
+ ALL
+};
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type E0516 = e0516_device_config::static_alloc_device_config;
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+GENERIC_DEVICE_CONFIG_SETUP(e0516, "E05-16")
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// e0516_device - constructor
+//-------------------------------------------------
+
+e0516_device::e0516_device(running_machine &_machine, const e0516_device_config &config)
+ : device_t(_machine, config),
+ m_config(config)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void e0516_device::device_start()
+{
+ // allocate timers
+ m_timer = timer_alloc();
+ m_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
+
+ // state saving
+ save_item(NAME(m_cs));
+ save_item(NAME(m_clk));
+ save_item(NAME(m_data_latch));
+ save_item(NAME(m_reg_latch));
+ save_item(NAME(m_read_write));
+ save_item(NAME(m_state));
+ save_item(NAME(m_bits));
+ save_item(NAME(m_dio));
+ save_item(NAME(m_register));
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific reset
+//-------------------------------------------------
+
+void e0516_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void e0516_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ m_register[SECOND]++;
+
+ if (m_register[SECOND] == 60)
+ {
+ m_register[SECOND] = 0;
+ m_register[MINUTE]++;
+ }
+
+ if (m_register[MINUTE] == 60)
+ {
+ m_register[MINUTE] = 0;
+ m_register[HOUR]++;
+ }
+
+ if (m_register[HOUR] == 24)
+ {
+ m_register[HOUR] = 0;
+ m_register[DAY]++;
+ m_register[DAY_OF_WEEK]++;
+ }
+
+ if (m_register[DAY_OF_WEEK] == 8)
+ {
+ m_register[DAY_OF_WEEK] = 1;
+ }
+
+ if (m_register[DAY] == 32)
+ {
+ m_register[DAY] = 1;
+ m_register[MONTH]++;
+ }
+
+ if (m_register[MONTH] == 13)
+ {
+ m_register[MONTH] = 1;
+ m_register[YEAR]++;
+ }
+}
+
+
+//-------------------------------------------------
+// cs_w - chip select input
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( e0516_device::cs_w )
+{
+ m_cs = state;
+
+ if (m_cs)
+ {
+ m_data_latch = 0;
+ m_reg_latch = 0;
+ m_bits = 0;
+ m_state = STATE_ADDRESS;
+ }
+}
+
+
+//-------------------------------------------------
+// clk_w - serial clock input
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( e0516_device::clk_w )
+{
+ m_clk = state;
+
+ if (m_cs || m_clk) return;
+
+ m_bits++;
+
+ if (m_state == STATE_ADDRESS)
+ {
+ if (LOG) logerror("E05-16 '%s' Command Bit %u\n", tag(), m_dio);
+
+ // command
+ m_reg_latch |= m_dio << 3;
+ m_reg_latch >>= 1;
+
+ if (m_bits == 4)
+ {
+ m_state = STATE_DATA;
+ m_bits = 0;
+
+ if (BIT(m_reg_latch, 0))
+ {
+ // load register value to data latch
+ m_data_latch = m_register[m_reg_latch >> 1];
+ }
+ }
+ }
+ else
+ {
+ // data
+ if (BIT(m_reg_latch, 0))
+ {
+ // read
+ if (LOG) logerror("E05-16 '%s' Data Bit OUT %u\n", tag(), m_dio);
+
+ m_dio = BIT(m_data_latch, 0);
+ m_data_latch >>= 1;
+ }
+ else
+ {
+ // write
+ if (LOG) logerror("E05-16 '%s' Data Bit IN %u\n", tag(), m_dio);
+
+ m_data_latch |= m_dio << 7;
+ m_data_latch >>= 1;
+ }
+
+ if (m_bits == 8)
+ {
+ m_state = STATE_ADDRESS;
+ m_bits = 0;
+
+ if (!BIT(m_reg_latch, 0))
+ {
+ // write latched data to register
+ m_register[m_reg_latch >> 1] = m_data_latch;
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// dio_w - serial data input
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( e0516_device::dio_w )
+{
+ m_dio = state;
+}
+
+
+//-------------------------------------------------
+// do_r - serial data output
+//-------------------------------------------------
+
+READ_LINE_MEMBER( e0516_device::dio_r )
+{
+ return m_dio;
+}
diff --git a/src/emu/machine/e0516.h b/src/emu/machine/e0516.h
new file mode 100644
index 00000000000..83c25db1582
--- /dev/null
+++ b/src/emu/machine/e0516.h
@@ -0,0 +1,114 @@
+/**********************************************************************
+
+ E05-16 Real Time Clock emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ Vdd1 1 |* \_/ | 16 Vdd2
+ OSC IN 2 | | 15 Clk
+ OSC OUT 3 | | 14 XOUT
+ _STOP 4 | E05-16 | 13 DI/O
+ _RESET 5 | E050-16 | 12 _SEC
+ _OUTSEL 6 | | 11 _MIN
+ _DAY 7 | | 10 _HRS
+ Vss 8 |_____________| 9 _CS
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __E0516__
+#define __E0516__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_E0516_ADD(_tag, _clock) \
+ MCFG_DEVICE_ADD(_tag, E0516, _clock)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// ======================> e0516_device_config
+
+class e0516_device_config : public device_config
+{
+ friend class e0516_device;
+
+ // construction/destruction
+ e0516_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+protected:
+};
+
+
+// ======================> e0516_device
+
+class e0516_device : public device_t
+{
+ friend class e0516_device_config;
+
+ // construction/destruction
+ e0516_device(running_machine &_machine, const e0516_device_config &_config);
+
+public:
+ DECLARE_WRITE_LINE_MEMBER( cs_w );
+ DECLARE_WRITE_LINE_MEMBER( clk_w );
+ DECLARE_WRITE_LINE_MEMBER( dio_w );
+ DECLARE_READ_LINE_MEMBER( dio_r );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ int m_cs; // chip select
+ int m_clk; // clock
+ int m_data_latch; // data latch
+ int m_reg_latch; // register latch
+ int m_read_write; // read/write data
+ int m_state; // state
+ int m_bits; // number of bits transferred
+ int m_dio; // data pin
+
+ UINT8 m_register[8]; // registers
+
+ // timers
+ emu_timer *m_timer;
+
+ const e0516_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type E0516;
+
+
+
+#endif
diff --git a/src/emu/machine/i8155.c b/src/emu/machine/i8155.c
new file mode 100644
index 00000000000..8b6bcfa9cfd
--- /dev/null
+++ b/src/emu/machine/i8155.c
@@ -0,0 +1,653 @@
+/**********************************************************************
+
+ Intel 8155 - 2048-Bit Static MOS RAM with I/O Ports and Timer emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - strobed mode
+
+*/
+
+#include "emu.h"
+#include "i8155.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 1
+
+enum
+{
+ REGISTER_COMMAND = 0,
+ REGISTER_STATUS = 0,
+ REGISTER_PORT_A,
+ REGISTER_PORT_B,
+ REGISTER_PORT_C,
+ REGISTER_TIMER_LOW,
+ REGISTER_TIMER_HIGH
+};
+
+enum
+{
+ PORT_A = 0,
+ PORT_B,
+ PORT_C,
+ PORT_COUNT
+};
+
+enum
+{
+ PORT_MODE_INPUT = 0,
+ PORT_MODE_OUTPUT,
+ PORT_MODE_STROBED_PORT_A, // not supported
+ PORT_MODE_STROBED // not supported
+};
+
+enum
+{
+ MEMORY = 0,
+ IO
+};
+
+#define COMMAND_PA 0x01
+#define COMMAND_PB 0x02
+#define COMMAND_PC_MASK 0x0c
+#define COMMAND_PC_ALT_1 0x00
+#define COMMAND_PC_ALT_2 0x0c
+#define COMMAND_PC_ALT_3 0x04 // not supported
+#define COMMAND_PC_ALT_4 0x08 // not supported
+#define COMMAND_IEA 0x10 // not supported
+#define COMMAND_IEB 0x20 // not supported
+#define COMMAND_TM_MASK 0xc0
+#define COMMAND_TM_NOP 0x00
+#define COMMAND_TM_STOP 0x40
+#define COMMAND_TM_STOP_AFTER_TC 0x80
+#define COMMAND_TM_START 0xc0
+
+#define STATUS_INTR_A 0x01 // not supported
+#define STATUS_A_BF 0x02 // not supported
+#define STATUS_INTE_A 0x04 // not supported
+#define STATUS_INTR_B 0x08 // not supported
+#define STATUS_B_BF 0x10 // not supported
+#define STATUS_INTE_B 0x20 // not supported
+#define STATUS_TIMER 0x40
+
+#define TIMER_MODE_MASK 0xc0
+#define TIMER_MODE_LOW 0x00
+#define TIMER_MODE_SQUARE_WAVE 0x40
+#define TIMER_MODE_SINGLE_PULSE 0x80
+#define TIMER_MODE_AUTOMATIC_RELOAD 0xc0
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type I8155 = i8155_device_config::static_alloc_device_config;
+
+
+// default address map
+static ADDRESS_MAP_START( i8155, AS_0, 8 )
+ AM_RANGE(0x00, 0xff) AM_RAM
+ADDRESS_MAP_END
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// i8155_device_config - constructor
+//-------------------------------------------------
+
+i8155_device_config::i8155_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+ : device_config(mconfig, static_alloc_device_config, "Intel 8155", tag, owner, clock),
+ device_config_memory_interface(mconfig, *this),
+ m_space_config("ram", ENDIANNESS_LITTLE, 8, 8, 0, NULL, *ADDRESS_MAP_NAME(i8155))
+{
+}
+
+
+//-------------------------------------------------
+// static_alloc_device_config - allocate a new
+// configuration object
+//-------------------------------------------------
+
+device_config *i8155_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+{
+ return global_alloc(i8155_device_config(mconfig, tag, owner, clock));
+}
+
+
+//-------------------------------------------------
+// alloc_device - allocate a new device object
+//-------------------------------------------------
+
+device_t *i8155_device_config::alloc_device(running_machine &machine) const
+{
+ return auto_alloc(&machine, i8155_device(machine, *this));
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *i8155_device_config::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void i8155_device_config::device_config_complete()
+{
+ // inherit a copy of the static data
+ const i8155_interface *intf = reinterpret_cast<const i8155_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<i8155_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&in_pa_func, 0, sizeof(in_pa_func));
+ memset(&out_pa_func, 0, sizeof(out_pa_func));
+ memset(&in_pb_func, 0, sizeof(in_pb_func));
+ memset(&out_pb_func, 0, sizeof(out_pb_func));
+ memset(&in_pc_func, 0, sizeof(in_pc_func));
+ memset(&out_pc_func, 0, sizeof(out_pc_func));
+ memset(&out_to_func, 0, sizeof(out_to_func));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+inline UINT8 i8155_device::get_timer_mode()
+{
+ return (m_count_length >> 8) & TIMER_MODE_MASK;
+}
+
+inline void i8155_device::timer_output()
+{
+ devcb_call_write_line(&m_out_to_func, m_to);
+
+ if (LOG) logerror("8155 '%s' Timer Output: %u\n", tag(), m_to);
+}
+
+inline void i8155_device::pulse_timer_output()
+{
+ m_to = 0; timer_output();
+ m_to = 1; timer_output();
+}
+
+inline int i8155_device::get_port_mode(int port)
+{
+ int mode = -1;
+
+ switch (port)
+ {
+ case PORT_A:
+ mode = (m_command & COMMAND_PA) ? PORT_MODE_OUTPUT : PORT_MODE_INPUT;
+ break;
+
+ case PORT_B:
+ mode = (m_command & COMMAND_PB) ? PORT_MODE_OUTPUT : PORT_MODE_INPUT;
+ break;
+
+ case PORT_C:
+ switch (m_command & COMMAND_PC_MASK)
+ {
+ case COMMAND_PC_ALT_1: mode = PORT_MODE_INPUT; break;
+ case COMMAND_PC_ALT_2: mode = PORT_MODE_OUTPUT; break;
+ case COMMAND_PC_ALT_3: mode = PORT_MODE_STROBED_PORT_A; break;
+ case COMMAND_PC_ALT_4: mode = PORT_MODE_STROBED; break;
+ }
+ break;
+ }
+
+ return mode;
+}
+
+inline UINT8 i8155_device::read_port(int port)
+{
+ UINT8 data = 0;
+
+ switch (port)
+ {
+ case PORT_A:
+ case PORT_B:
+ switch (get_port_mode(port))
+ {
+ case PORT_MODE_INPUT:
+ data = devcb_call_read8(&m_in_port_func[port], 0);
+ break;
+
+ case PORT_MODE_OUTPUT:
+ data = m_output[port];
+ break;
+ }
+ break;
+
+ case PORT_C:
+ switch (get_port_mode(PORT_C))
+ {
+ case PORT_MODE_INPUT:
+ data = devcb_call_read8(&m_in_port_func[port], 0) & 0x3f;
+ break;
+
+ case PORT_MODE_OUTPUT:
+ data = m_output[port] & 0x3f;
+ break;
+
+ default:
+ logerror("8155 '%s' Unsupported Port C mode!\n", tag());
+ }
+ break;
+ }
+
+ return data;
+}
+
+inline void i8155_device::write_port(int port, UINT8 data)
+{
+ switch (get_port_mode(port))
+ {
+ case PORT_MODE_OUTPUT:
+ m_output[port] = data;
+ devcb_call_write8(&m_out_port_func[port], 0, m_output[port]);
+ break;
+ }
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// i8155_device - constructor
+//-------------------------------------------------
+
+i8155_device::i8155_device(running_machine &_machine, const i8155_device_config &config)
+ : device_t(_machine, config),
+ device_memory_interface(_machine, config, *this),
+ m_config(config)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void i8155_device::device_start()
+{
+ // resolve callbacks
+ devcb_resolve_read8(&m_in_port_func[0], &m_config.in_pa_func, this);
+ devcb_resolve_read8(&m_in_port_func[1], &m_config.in_pb_func, this);
+ devcb_resolve_read8(&m_in_port_func[2], &m_config.in_pc_func, this);
+ devcb_resolve_write8(&m_out_port_func[0], &m_config.out_pa_func, this);
+ devcb_resolve_write8(&m_out_port_func[1], &m_config.out_pb_func, this);
+ devcb_resolve_write8(&m_out_port_func[2], &m_config.out_pc_func, this);
+ devcb_resolve_write_line(&m_out_to_func, &m_config.out_to_func, this);
+
+ // allocate timers
+ m_timer = timer_alloc();
+
+ // register for state saving
+ save_item(NAME(m_io_m));
+ save_item(NAME(m_ad));
+ save_item(NAME(m_command));
+ save_item(NAME(m_status));
+ save_item(NAME(m_output));
+ save_item(NAME(m_count_length));
+ save_item(NAME(m_counter));
+ save_item(NAME(m_to));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void i8155_device::device_reset()
+{
+ // clear output registers
+ m_output[PORT_A] = 0;
+ m_output[PORT_B] = 0;
+ m_output[PORT_C] = 0;
+
+ // set ports to input mode
+ register_w(REGISTER_COMMAND, m_command & ~(COMMAND_PA | COMMAND_PB | COMMAND_PC_MASK));
+
+ // clear timer flag
+ m_status &= ~STATUS_TIMER;
+
+ // stop counting
+ m_timer->enable(0);
+
+ // clear timer output
+ m_to = 1;
+ timer_output();
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void i8155_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ // count down
+ m_counter--;
+
+ if (get_timer_mode() == TIMER_MODE_LOW)
+ {
+ // pulse on every count
+ pulse_timer_output();
+ }
+
+ if (m_counter == 0)
+ {
+ if (LOG) logerror("8155 '%s' Timer Count Reached\n", tag());
+
+ switch (m_command & COMMAND_TM_MASK)
+ {
+ case COMMAND_TM_STOP_AFTER_TC:
+ // stop timer
+ m_timer->enable(0);
+
+ if (LOG) logerror("8155 '%s' Timer Stopped\n", tag());
+ break;
+ }
+
+ switch (get_timer_mode())
+ {
+ case TIMER_MODE_SQUARE_WAVE:
+ // toggle timer output
+ m_to = !m_to;
+ timer_output();
+ break;
+
+ case TIMER_MODE_SINGLE_PULSE:
+ // single pulse upon TC being reached
+ pulse_timer_output();
+
+ // clear timer mode setting
+ m_command &= ~COMMAND_TM_MASK;
+ break;
+
+ case TIMER_MODE_AUTOMATIC_RELOAD:
+ // automatic reload, i.e. single pulse every time TC is reached
+ pulse_timer_output();
+ break;
+ }
+
+ // set timer flag
+ m_status |= STATUS_TIMER;
+
+ // reload timer counter
+ m_counter = m_count_length & 0x3fff;
+ }
+}
+
+
+//-------------------------------------------------
+// io_r - register read
+//-------------------------------------------------
+
+READ8_MEMBER( i8155_device::io_r )
+{
+ UINT8 data = 0;
+
+ switch (offset & 0x03)
+ {
+ case REGISTER_STATUS:
+ data = m_status;
+
+ // clear timer flag
+ m_status &= ~STATUS_TIMER;
+ break;
+
+ case REGISTER_PORT_A:
+ data = read_port(PORT_A);
+ break;
+
+ case REGISTER_PORT_B:
+ data = read_port(PORT_B);
+ break;
+
+ case REGISTER_PORT_C:
+ data = read_port(PORT_C);
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// register_w - register write
+//-------------------------------------------------
+
+void i8155_device::register_w(int offset, UINT8 data)
+{
+ switch (offset & 0x07)
+ {
+ case REGISTER_COMMAND:
+ m_command = data;
+
+ if (LOG) logerror("8155 '%s' Port A Mode: %s\n", tag(), (data & COMMAND_PA) ? "output" : "input");
+ if (LOG) logerror("8155 '%s' Port B Mode: %s\n", tag(), (data & COMMAND_PB) ? "output" : "input");
+
+ if (LOG) logerror("8155 '%s' Port A Interrupt: %s\n", tag(), (data & COMMAND_IEA) ? "enabled" : "disabled");
+ if (LOG) logerror("8155 '%s' Port B Interrupt: %s\n", tag(), (data & COMMAND_IEB) ? "enabled" : "disabled");
+
+ switch (data & COMMAND_PC_MASK)
+ {
+ case COMMAND_PC_ALT_1:
+ if (LOG) logerror("8155 '%s' Port C Mode: Alt 1\n", tag());
+ break;
+
+ case COMMAND_PC_ALT_2:
+ if (LOG) logerror("8155 '%s' Port C Mode: Alt 2\n", tag());
+ break;
+
+ case COMMAND_PC_ALT_3:
+ if (LOG) logerror("8155 '%s' Port C Mode: Alt 3\n", tag());
+ break;
+
+ case COMMAND_PC_ALT_4:
+ if (LOG) logerror("8155 '%s' Port C Mode: Alt 4\n", tag());
+ break;
+ }
+
+ switch (data & COMMAND_TM_MASK)
+ {
+ case COMMAND_TM_NOP:
+ // do not affect counter operation
+ break;
+
+ case COMMAND_TM_STOP:
+ // NOP if timer has not started, stop counting if the timer is running
+ if (LOG) logerror("8155 '%s' Timer Command: Stop\n", tag());
+ m_timer->enable(0);
+ break;
+
+ case COMMAND_TM_STOP_AFTER_TC:
+ // stop immediately after present TC is reached (NOP if timer has not started)
+ if (LOG) logerror("8155 '%s' Timer Command: Stop after TC\n", tag());
+ break;
+
+ case COMMAND_TM_START:
+ if (LOG) logerror("8155 '%s' Timer Command: Start\n", tag());
+
+ if (m_timer->enabled())
+ {
+ // if timer is running, start the new mode and CNT length immediately after present TC is reached
+ }
+ else
+ {
+ // load mode and CNT length and start immediately after loading (if timer is not running)
+ m_counter = m_count_length;
+ m_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
+ }
+ break;
+ }
+ break;
+
+ case REGISTER_PORT_A:
+ write_port(PORT_A, data);
+ break;
+
+ case REGISTER_PORT_B:
+ write_port(PORT_B, data);
+ break;
+
+ case REGISTER_PORT_C:
+ write_port(PORT_C, data);
+ break;
+
+ case REGISTER_TIMER_LOW:
+ m_count_length = (m_count_length & 0xff00) | data;
+ if (LOG) logerror("8155 '%s' Count Length Low: %04x\n", tag(), m_count_length);
+ break;
+
+ case REGISTER_TIMER_HIGH:
+ m_count_length = (data << 8) | (m_count_length & 0xff);
+ if (LOG) logerror("8155 '%s' Count Length High: %04x\n", tag(), m_count_length);
+
+ switch (data & TIMER_MODE_MASK)
+ {
+ case TIMER_MODE_LOW:
+ // puts out LOW during second half of count
+ if (LOG) logerror("8155 '%s' Timer Mode: LOW\n", tag());
+ break;
+
+ case TIMER_MODE_SQUARE_WAVE:
+ // square wave, i.e. the period of the square wave equals the count length programmed with automatic reload at terminal count
+ if (LOG) logerror("8155 '%s' Timer Mode: Square wave\n", tag());
+ break;
+
+ case TIMER_MODE_SINGLE_PULSE:
+ // single pulse upon TC being reached
+ if (LOG) logerror("8155 '%s' Timer Mode: Single pulse\n", tag());
+ break;
+
+ case TIMER_MODE_AUTOMATIC_RELOAD:
+ // automatic reload, i.e. single pulse every time TC is reached
+ if (LOG) logerror("8155 '%s' Timer Mode: Automatic reload\n", tag());
+ break;
+ }
+ break;
+ }
+}
+
+//-------------------------------------------------
+// io_w - register write
+//-------------------------------------------------
+
+WRITE8_MEMBER( i8155_device::io_w )
+{
+ register_w(offset, data);
+}
+
+
+//-------------------------------------------------
+// memory_r - internal RAM read
+//-------------------------------------------------
+
+READ8_MEMBER( i8155_device::memory_r )
+{
+ return this->space()->read_byte(offset);
+}
+
+
+//-------------------------------------------------
+// memory_w - internal RAM write
+//-------------------------------------------------
+
+WRITE8_MEMBER( i8155_device::memory_w )
+{
+ this->space()->write_byte(offset, data);
+}
+
+
+//-------------------------------------------------
+// ale_w - address latch write
+//-------------------------------------------------
+
+WRITE8_MEMBER( i8155_device::ale_w )
+{
+ // I/O / memory select
+ m_io_m = BIT(offset, 0);
+
+ // address
+ m_ad = data;
+}
+
+
+//-------------------------------------------------
+// read - memory or I/O read
+//-------------------------------------------------
+
+READ8_MEMBER( i8155_device::read )
+{
+ UINT8 data = 0;
+
+ switch (m_io_m)
+ {
+ case MEMORY:
+ data = memory_r(space, m_ad);
+ break;
+
+ case IO:
+ data = io_r(space, m_ad);
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write - memory or I/O write
+//-------------------------------------------------
+
+WRITE8_MEMBER( i8155_device::write )
+{
+ switch (m_io_m)
+ {
+ case MEMORY:
+ memory_w(space, m_ad, data);
+ break;
+
+ case IO:
+ io_w(space, m_ad, data);
+ break;
+ }
+}
diff --git a/src/emu/machine/i8155.h b/src/emu/machine/i8155.h
new file mode 100644
index 00000000000..282791da933
--- /dev/null
+++ b/src/emu/machine/i8155.h
@@ -0,0 +1,181 @@
+/**********************************************************************
+
+ Intel 8155 - 2048-Bit Static MOS RAM with I/O Ports and Timer emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ PC3 1 |* \_/ | 40 Vcc
+ PC4 2 | | 39 PC2
+ TIMER IN 3 | | 38 PC1
+ RESET 4 | | 37 PC0
+ PC5 5 | | 36 PB7
+ _TIMER OUT 6 | | 35 PB6
+ IO/_M 7 | | 34 PB5
+ CE or _CE 8 | | 33 PB4
+ _RD 9 | | 32 PB3
+ _WR 10 | 8155 | 31 PB2
+ ALE 11 | 8156 | 30 PB1
+ AD0 12 | | 29 PB0
+ AD1 13 | | 28 PA7
+ AD2 14 | | 27 PA6
+ AD3 15 | | 26 PA5
+ AD4 16 | | 25 PA4
+ AD5 17 | | 24 PA3
+ AD6 18 | | 23 PA2
+ AD7 19 | | 22 PA1
+ Vss 20 |_____________| 21 PA0
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __I8155__
+#define __I8155__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_I8155_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD((_tag), I8155, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define I8155_INTERFACE(name) \
+ const i8155_interface (name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> i8155_interface
+
+struct i8155_interface
+{
+ devcb_read8 in_pa_func;
+ devcb_write8 out_pa_func;
+
+ devcb_read8 in_pb_func;
+ devcb_write8 out_pb_func;
+
+ devcb_read8 in_pc_func;
+ devcb_write8 out_pc_func;
+
+ // this gets called for each change of the TIMER OUT pin (pin 6)
+ devcb_write_line out_to_func;
+};
+
+
+
+// ======================> i8155_device_config
+
+class i8155_device_config : public device_config,
+ public device_config_memory_interface,
+ public i8155_interface
+{
+ friend class i8155_device;
+
+ // construction/destruction
+ i8155_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+protected:
+ // device_config overrides
+ virtual void device_config_complete();
+
+ // device_config_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // address space configurations
+ const address_space_config m_space_config;
+};
+
+
+
+// ======================> i8155_device
+
+class i8155_device : public device_t,
+ public device_memory_interface
+{
+ friend class i8155_device_config;
+
+ // construction/destruction
+ i8155_device(running_machine &_machine, const i8155_device_config &_config);
+
+public:
+ DECLARE_READ8_MEMBER( io_r );
+ DECLARE_WRITE8_MEMBER( io_w );
+
+ DECLARE_READ8_MEMBER( memory_r );
+ DECLARE_WRITE8_MEMBER( memory_w );
+
+ DECLARE_WRITE8_MEMBER( ale_w );
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ inline UINT8 get_timer_mode();
+ inline void timer_output();
+ inline void pulse_timer_output();
+ inline int get_port_mode(int port);
+ inline UINT8 read_port(int port);
+ inline void write_port(int port, UINT8 data);
+
+ void register_w(int offset, UINT8 data);
+
+private:
+ devcb_resolved_read8 m_in_port_func[3];
+ devcb_resolved_write8 m_out_port_func[3];
+ devcb_resolved_write_line m_out_to_func;
+
+ // CPU interface
+ int m_io_m; // I/O or memory select
+ UINT8 m_ad; // address
+
+ // registers
+ UINT8 m_command; // command register
+ UINT8 m_status; // status register
+ UINT8 m_output[3]; // output latches
+
+ // counter
+ UINT16 m_count_length; // count length register
+ UINT16 m_counter; // counter register
+ int m_to; // timer output
+
+ // timers
+ emu_timer *m_timer; // counter timer
+
+ const i8155_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type I8155;
+
+
+
+#endif
diff --git a/src/emu/machine/i8212.c b/src/emu/machine/i8212.c
new file mode 100644
index 00000000000..af98db9947e
--- /dev/null
+++ b/src/emu/machine/i8212.c
@@ -0,0 +1,180 @@
+/**********************************************************************
+
+ Intel 8212 8-Bit Input/Output Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "machine/devhelpr.h"
+#include "i8212.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type I8212 = i8212_device_config::static_alloc_device_config;
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+GENERIC_DEVICE_CONFIG_SETUP(i8212, "Intel 8212")
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void i8212_device_config::device_config_complete()
+{
+ // inherit a copy of the static data
+ const i8212_interface *intf = reinterpret_cast<const i8212_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<i8212_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&out_int_func, 0, sizeof(out_int_func));
+ memset(&in_di_func, 0, sizeof(in_di_func));
+ memset(&out_do_func, 0, sizeof(out_do_func));
+ }
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// i8212_device - constructor
+//-------------------------------------------------
+
+i8212_device::i8212_device(running_machine &_machine, const i8212_device_config &config)
+ : device_t(_machine, config),
+ m_md(I8212_MODE_INPUT),
+ m_stb(0),
+ m_config(config)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void i8212_device::device_start()
+{
+ // resolve callbacks
+ devcb_resolve_write_line(&m_out_int_func, &m_config.out_int_func, this);
+ devcb_resolve_read8(&m_in_di_func, &m_config.in_di_func, this);
+ devcb_resolve_write8(&m_out_do_func, &m_config.out_do_func, this);
+
+ // register for state saving
+ save_item(NAME(m_md));
+ save_item(NAME(m_stb));
+ save_item(NAME(m_data));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void i8212_device::device_reset()
+{
+ m_data = 0;
+
+ if (m_md == I8212_MODE_OUTPUT)
+ {
+ // output data
+ devcb_call_write8(&m_out_do_func, 0, m_data);
+ }
+}
+
+
+//-------------------------------------------------
+// data_r - data latch read
+//-------------------------------------------------
+
+READ8_MEMBER( i8212_device::data_r )
+{
+ // clear interrupt line
+ devcb_call_write_line(&m_out_int_func, CLEAR_LINE);
+
+ if (LOG) logerror("I8212 '%s' INT: %u\n", tag(), CLEAR_LINE);
+
+ return m_data;
+}
+
+
+//-------------------------------------------------
+// data_w - data latch write
+//-------------------------------------------------
+
+WRITE8_MEMBER( i8212_device::data_w )
+{
+ // latch data
+ m_data = data;
+
+ // output data
+ devcb_call_write8(&m_out_do_func, 0, m_data);
+}
+
+
+//-------------------------------------------------
+// md_w - mode write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( i8212_device::md_w )
+{
+ if (LOG) logerror("I8212 '%s' Mode: %s\n", tag(), state ? "output" : "input");
+
+ m_md = state;
+}
+
+
+//-------------------------------------------------
+// stb_w - data strobe write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( i8212_device::stb_w )
+{
+ if (LOG) logerror("I8212 '%s' STB: %u\n", tag(), state);
+
+ if (m_md == I8212_MODE_INPUT)
+ {
+ if (m_stb && !state)
+ {
+ // input data
+ m_data = devcb_call_read8(&m_in_di_func, 0);
+
+ // assert interrupt line
+ devcb_call_write_line(&m_out_int_func, ASSERT_LINE);
+
+ if (LOG) logerror("I8212 '%s' INT: %u\n", tag(), ASSERT_LINE);
+ }
+ }
+
+ m_stb = state;
+}
diff --git a/src/emu/machine/i8212.h b/src/emu/machine/i8212.h
new file mode 100644
index 00000000000..6390a4d6f7d
--- /dev/null
+++ b/src/emu/machine/i8212.h
@@ -0,0 +1,136 @@
+/**********************************************************************
+
+ Intel 8212 8-Bit Input/Output Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ _DS1 1 |* \_/ | 24 Vcc
+ MD 2 | | 23 _INT
+ DI1 3 | | 22 DI8
+ DO1 4 | | 21 DO8
+ DI2 5 | | 20 DI7
+ DO2 6 | 8212 | 19 DO7
+ DI3 7 | | 18 DI6
+ DO3 8 | | 17 DO6
+ DI4 9 | | 16 DI5
+ DO4 10 | | 15 DO5
+ STB 11 | | 14 _CLR
+ GND 12 |_____________| 13 DS2
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __I8212__
+#define __I8212__
+
+#include "emu.h"
+
+
+
+///*************************************************************************
+// MACROS / CONSTANTS
+///*************************************************************************
+
+enum
+{
+ I8212_MODE_INPUT = 0,
+ I8212_MODE_OUTPUT
+};
+
+
+
+///*************************************************************************
+// INTERFACE CONFIGURATION MACROS
+///*************************************************************************
+
+#define MCFG_I8212_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD((_tag), I8212, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define I8212_INTERFACE(name) \
+ const i8212_interface (name) =
+
+
+
+///*************************************************************************
+// TYPE DEFINITIONS
+///*************************************************************************
+
+// ======================> i8212_interface
+
+struct i8212_interface
+{
+ devcb_write_line out_int_func;
+
+ devcb_read8 in_di_func;
+ devcb_write8 out_do_func;
+};
+
+
+
+// ======================> i8212_device_config
+
+class i8212_device_config : public device_config,
+ public i8212_interface
+{
+ friend class i8212_device;
+
+ // construction/destruction
+ i8212_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+protected:
+ // device_config overrides
+ virtual void device_config_complete();
+};
+
+
+
+// ======================> i8212_device
+
+class i8212_device : public device_t
+{
+ friend class i8212_device_config;
+
+ // construction/destruction
+ i8212_device(running_machine &_machine, const i8212_device_config &_config);
+
+public:
+ DECLARE_READ8_MEMBER( data_r );
+ DECLARE_WRITE8_MEMBER( data_w );
+
+ DECLARE_WRITE_LINE_MEMBER( md_w );
+ DECLARE_WRITE_LINE_MEMBER( stb_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ devcb_resolved_write_line m_out_int_func;
+ devcb_resolved_read8 m_in_di_func;
+ devcb_resolved_write8 m_out_do_func;
+
+ int m_md; // mode
+ int m_stb; // strobe
+ UINT8 m_data; // data latch
+
+ const i8212_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type I8212;
+
+
+
+#endif
diff --git a/src/emu/machine/i8355.c b/src/emu/machine/i8355.c
new file mode 100644
index 00000000000..6c305793710
--- /dev/null
+++ b/src/emu/machine/i8355.c
@@ -0,0 +1,269 @@
+/**********************************************************************
+
+ Intel 8355 - 16,384-Bit ROM with I/O emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "i8355.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+enum
+{
+ REGISTER_PORT_A = 0,
+ REGISTER_PORT_B,
+ REGISTER_PORT_A_DDR,
+ REGISTER_PORT_B_DDR
+};
+
+enum
+{
+ PORT_A = 0,
+ PORT_B,
+ PORT_COUNT
+};
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type I8355 = i8355_device_config::static_alloc_device_config;
+
+
+// default address map
+static ADDRESS_MAP_START( i8355, AS_0, 8 )
+ AM_RANGE(0x000, 0x7ff) AM_ROM
+ADDRESS_MAP_END
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// i8355_device_config - constructor
+//-------------------------------------------------
+
+i8355_device_config::i8355_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+ : device_config(mconfig, static_alloc_device_config, "Intel 8355", tag, owner, clock),
+ device_config_memory_interface(mconfig, *this),
+ m_space_config("ram", ENDIANNESS_LITTLE, 8, 11, 0, NULL, *ADDRESS_MAP_NAME(i8355))
+{
+}
+
+
+//-------------------------------------------------
+// static_alloc_device_config - allocate a new
+// configuration object
+//-------------------------------------------------
+
+device_config *i8355_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+{
+ return global_alloc(i8355_device_config(mconfig, tag, owner, clock));
+}
+
+
+//-------------------------------------------------
+// alloc_device - allocate a new device object
+//-------------------------------------------------
+
+device_t *i8355_device_config::alloc_device(running_machine &machine) const
+{
+ return auto_alloc(&machine, i8355_device(machine, *this));
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *i8355_device_config::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void i8355_device_config::device_config_complete()
+{
+ // inherit a copy of the static data
+ const i8355_interface *intf = reinterpret_cast<const i8355_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<i8355_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&in_pa_func, 0, sizeof(in_pa_func));
+ memset(&out_pa_func, 0, sizeof(out_pa_func));
+ memset(&in_pb_func, 0, sizeof(in_pb_func));
+ memset(&out_pb_func, 0, sizeof(out_pb_func));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// read_port - read from input port
+//-------------------------------------------------
+
+inline UINT8 i8355_device::read_port(int port)
+{
+ UINT8 data = m_output[port] & m_ddr[port];
+
+ if (m_ddr[port] != 0xff)
+ {
+ data |= devcb_call_read8(&m_in_port_func[port], 0) & ~m_ddr[port];
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write_port - write to output port
+//-------------------------------------------------
+
+inline void i8355_device::write_port(int port, UINT8 data)
+{
+ m_output[port] = data;
+
+ devcb_call_write8(&m_out_port_func[port], 0, m_output[port] & m_ddr[port]);
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// i8355_device - constructor
+//-------------------------------------------------
+
+i8355_device::i8355_device(running_machine &_machine, const i8355_device_config &config)
+ : device_t(_machine, config),
+ device_memory_interface(_machine, config, *this),
+ m_config(config)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void i8355_device::device_start()
+{
+ // resolve callbacks
+ devcb_resolve_read8(&m_in_port_func[0], &m_config.in_pa_func, this);
+ devcb_resolve_read8(&m_in_port_func[1], &m_config.in_pb_func, this);
+ devcb_resolve_write8(&m_out_port_func[0], &m_config.out_pa_func, this);
+ devcb_resolve_write8(&m_out_port_func[1], &m_config.out_pb_func, this);
+
+ // register for state saving
+ save_item(NAME(m_output));
+ save_item(NAME(m_ddr));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void i8355_device::device_reset()
+{
+ // set ports to input mode
+ m_ddr[PORT_A] = 0;
+ m_ddr[PORT_B] = 0;
+}
+
+
+//-------------------------------------------------
+// io_r - register read
+//-------------------------------------------------
+
+READ8_MEMBER( i8355_device::io_r )
+{
+ int port = offset & 0x01;
+
+ UINT8 data = 0;
+
+ switch (offset & 0x03)
+ {
+ case REGISTER_PORT_A:
+ case REGISTER_PORT_B:
+ data = read_port(port);
+ break;
+
+ case REGISTER_PORT_A_DDR:
+ case REGISTER_PORT_B_DDR:
+ // write only
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// io_w - register write
+//-------------------------------------------------
+
+WRITE8_MEMBER( i8355_device::io_w )
+{
+ int port = offset & 0x01;
+
+ switch (offset & 0x03)
+ {
+ case REGISTER_PORT_A:
+ case REGISTER_PORT_B:
+ if (LOG) logerror("I8355 '%s' Port %c Write %02x\n", tag(), 'A' + port, data);
+
+ write_port(port, data);
+ break;
+
+ case REGISTER_PORT_A_DDR:
+ case REGISTER_PORT_B_DDR:
+ if (LOG) logerror("I8355 '%s' Port %c DDR: %02x\n", tag(), 'A' + port, data);
+
+ m_ddr[port] = data;
+ write_port(port, data);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// memory_r - internal ROM read
+//-------------------------------------------------
+
+READ8_MEMBER( i8355_device::memory_r )
+{
+ return this->space()->read_byte(offset);
+}
diff --git a/src/emu/machine/i8355.h b/src/emu/machine/i8355.h
new file mode 100644
index 00000000000..a332d4fa264
--- /dev/null
+++ b/src/emu/machine/i8355.h
@@ -0,0 +1,150 @@
+/**********************************************************************
+
+ Intel 8355 - 16,384-Bit ROM with I/O emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ _CE1 1 |* \_/ | 40 Vcc
+ CE2 2 | | 39 PB7
+ CLK 3 | | 38 PB6
+ RESET 4 | | 37 PB5
+ N.C. 5 | | 36 PB4
+ READY 6 | | 35 PB3
+ IO/_M 7 | | 34 PB2
+ _IOR 8 | | 33 PB1
+ _RD 9 | | 32 PB0
+ _IOW 10 | 8355 | 31 PA7
+ ALE 11 | 8355-2 | 30 PA6
+ AD0 12 | | 29 PA5
+ AD1 13 | | 28 PA4
+ AD2 14 | | 27 PA3
+ AD3 15 | | 26 PA2
+ AD4 16 | | 25 PA1
+ AD5 17 | | 24 PA0
+ AD6 18 | | 23 A10
+ AD7 19 | | 22 A9
+ Vss 20 |_____________| 21 A8
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __I8355__
+#define __I8355__
+
+#include "emu.h"
+
+
+
+///*************************************************************************
+// MACROS / CONSTANTS
+///*************************************************************************
+
+
+
+
+///*************************************************************************
+// INTERFACE CONFIGURATION MACROS
+///*************************************************************************
+
+#define MCFG_I8355_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD((_tag), I8355, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define I8355_INTERFACE(name) \
+ const i8355_interface (name) =
+
+
+
+///*************************************************************************
+// TYPE DEFINITIONS
+///*************************************************************************
+
+// ======================> i8355_interface
+
+struct i8355_interface
+{
+ devcb_read8 in_pa_func;
+ devcb_write8 out_pa_func;
+
+ devcb_read8 in_pb_func;
+ devcb_write8 out_pb_func;
+};
+
+
+
+// ======================> i8355_device_config
+
+class i8355_device_config : public device_config,
+ public device_config_memory_interface,
+ public i8355_interface
+{
+ friend class i8355_device;
+
+ // construction/destruction
+ i8355_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+protected:
+ // device_config overrides
+ virtual void device_config_complete();
+
+ // device_config_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // address space configurations
+ const address_space_config m_space_config;
+};
+
+
+
+// ======================> i8355_device
+
+class i8355_device : public device_t,
+ public device_memory_interface
+{
+ friend class i8355_device_config;
+
+ // construction/destruction
+ i8355_device(running_machine &_machine, const i8355_device_config &_config);
+
+public:
+ DECLARE_READ8_MEMBER( io_r );
+ DECLARE_WRITE8_MEMBER( io_w );
+
+ DECLARE_READ8_MEMBER( memory_r );
+ DECLARE_WRITE8_MEMBER( memory_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ inline UINT8 read_port(int port);
+ inline void write_port(int port, UINT8 data);
+
+private:
+ devcb_resolved_read8 m_in_port_func[2];
+ devcb_resolved_write8 m_out_port_func[2];
+
+ // registers
+ UINT8 m_output[2]; // output latches
+ UINT8 m_ddr[2]; // DDR latches
+
+ const i8355_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type I8355;
+
+
+
+#endif
diff --git a/src/emu/machine/nmc9306.c b/src/emu/machine/nmc9306.c
new file mode 100644
index 00000000000..2ea9c963365
--- /dev/null
+++ b/src/emu/machine/nmc9306.c
@@ -0,0 +1,365 @@
+/**********************************************************************
+
+ National Semiconductor NMC9306 256-Bit Serial EEPROM emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "nmc9306.h"
+#include "machine/devhelpr.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 1
+
+#define RAM_SIZE 32
+
+
+// instructions
+enum
+{
+ OTHER = 0,
+ WRITE, // write register A3A2A1A0
+ READ, // read register A3A2A1A0
+ ERASE // erase register A3A2A1A0
+};
+
+// other instructions
+enum
+{
+ EWDS = 0, // erase/write disable
+ WRAL, // write all registers
+ ERAL, // erase all registers
+ EWEN, // erase/write enable
+};
+
+// states
+enum
+{
+ STATE_IDLE = 0,
+ STATE_COMMAND,
+ STATE_ADDRESS,
+ STATE_DATA_IN,
+ STATE_DATA_OUT,
+ STATE_ERASE
+};
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type NMC9306 = nmc9306_device_config::static_alloc_device_config;
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// nmc9306_device_config - constructor
+//-------------------------------------------------
+
+nmc9306_device_config::nmc9306_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+ : device_config(mconfig, static_alloc_device_config, "NMC9306", tag, owner, clock),
+ device_config_nvram_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// static_alloc_device_config - allocate a new
+// configuration object
+//-------------------------------------------------
+
+device_config *nmc9306_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+{
+ return global_alloc(nmc9306_device_config(mconfig, tag, owner, clock));
+}
+
+
+//-------------------------------------------------
+// alloc_device - allocate a new device object
+//-------------------------------------------------
+
+device_t *nmc9306_device_config::alloc_device(running_machine &machine) const
+{
+ return auto_alloc(&machine, nmc9306_device(machine, *this));
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// nmc9306_device - constructor
+//-------------------------------------------------
+
+inline UINT16 nmc9306_device::read(offs_t offset)
+{
+ return m_register[offset];
+}
+
+
+//-------------------------------------------------
+// nmc9306_device - constructor
+//-------------------------------------------------
+
+inline void nmc9306_device::write(offs_t offset, UINT16 data)
+{
+ if (m_ewen)
+ {
+ m_register[offset] &= data;
+ }
+}
+
+
+//-------------------------------------------------
+// nmc9306_device - constructor
+//-------------------------------------------------
+
+inline void nmc9306_device::erase(offs_t offset)
+{
+ if (m_ewen)
+ {
+ m_register[offset] = 0xffff;
+ }
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nmc9306_device - constructor
+//-------------------------------------------------
+
+nmc9306_device::nmc9306_device(running_machine &_machine, const nmc9306_device_config &config)
+ : device_t(_machine, config),
+ device_nvram_interface(_machine, config, *this),
+ m_state(STATE_IDLE),
+ m_ewen(false),
+ m_config(config)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nmc9306_device::device_start()
+{
+ // state saving
+ save_item(NAME(m_bits));
+ save_item(NAME(m_state));
+ save_item(NAME(m_command));
+ save_item(NAME(m_address));
+ save_item(NAME(m_data));
+ save_item(NAME(m_ewen));
+ save_item(NAME(m_cs));
+ save_item(NAME(m_sk));
+ save_item(NAME(m_do));
+ save_item(NAME(m_di));
+}
+
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void nmc9306_device::nvram_default()
+{
+}
+
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+void nmc9306_device::nvram_read(emu_file &file)
+{
+ file.read(m_register, RAM_SIZE);
+}
+
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+void nmc9306_device::nvram_write(emu_file &file)
+{
+ file.write(m_register, RAM_SIZE);
+}
+
+
+//-------------------------------------------------
+// cs_w - chip select input
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( nmc9306_device::cs_w )
+{
+ m_cs = state;
+}
+
+
+//-------------------------------------------------
+// ck_w - serial clock input
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( nmc9306_device::sk_w )
+{
+ m_sk = state;
+
+ if (!m_cs || !m_sk) return;
+
+ switch (m_state)
+ {
+ case STATE_IDLE:
+ if (LOG) logerror("NMC9306 '%s' Idle %u\n", tag(), m_di);
+
+ if (m_di)
+ {
+ // start bit received
+ m_state = STATE_COMMAND;
+ m_bits = 0;
+ }
+ break;
+
+ case STATE_COMMAND:
+ if (LOG) logerror("NMC9306 '%s' Command Bit %u\n", tag(), m_di);
+
+ m_command <<= 1;
+ m_command |= m_di;
+ m_bits++;
+
+ if (m_bits == 4)
+ {
+ m_state = STATE_ADDRESS;
+ m_bits = 0;
+ }
+ break;
+
+ case STATE_ADDRESS:
+ if (LOG) logerror("NMC9306 '%s' Address Bit %u\n", tag(), m_di);
+
+ m_address <<= 1;
+ m_address |= m_di;
+ m_bits++;
+
+ if (m_bits == 4)
+ {
+ switch ((m_command >> 2) & 0x03)
+ {
+ case OTHER:
+ switch (m_command & 0x03)
+ {
+ case EWDS:
+ if (LOG) logerror("NMC9306 '%s' EWDS\n", tag());
+ m_ewen = false;
+ m_state = STATE_IDLE;
+ break;
+
+ case WRAL:
+ if (LOG) logerror("NMC9306 '%s' WRAL\n", tag());
+ break;
+
+ case ERAL:
+ if (LOG) logerror("NMC9306 '%s' ERAL\n", tag());
+ break;
+
+ case EWEN:
+ if (LOG) logerror("NMC9306 '%s' EWEN\n", tag());
+ m_ewen = true;
+ m_state = STATE_IDLE;
+ break;
+ }
+ break;
+
+ case WRITE:
+ if (LOG) logerror("NMC9306 '%s' WRITE %u\n", tag(), m_address & 0x0f);
+ m_state = STATE_DATA_IN;
+ break;
+
+ case READ:
+ if (LOG) logerror("NMC9306 '%s' READ %u\n", tag(), m_address & 0x0f);
+ m_data = read(m_address & 0x0f);
+ m_state = STATE_DATA_OUT;
+ break;
+
+ case ERASE:
+ if (LOG) logerror("NMC9306 '%s' ERASE %u\n", tag(), m_address & 0x0f);
+ erase(m_address & 0x0f);
+ m_state = STATE_ERASE;
+ break;
+ }
+
+ m_bits = 0;
+ }
+ break;
+
+ case STATE_DATA_IN:
+ if (LOG) logerror("NMC9306 '%s' Data Bit IN %u\n", tag(), m_di);
+
+ m_data <<= 1;
+ m_data |= m_di;
+ m_bits++;
+
+ if (m_bits == 16)
+ {
+ write(m_address & 0x0f, m_data);
+
+ m_state = STATE_IDLE;
+ }
+ break;
+
+ case STATE_DATA_OUT:
+ if (LOG) logerror("NMC9306 '%s' Data Bit OUT %u\n", tag(), m_di);
+
+ m_do = BIT(m_data, 15);
+ m_data <<= 1;
+ m_bits++;
+
+ if (m_bits == 16)
+ {
+ m_state = STATE_IDLE;
+ }
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// di_w - serial data input
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( nmc9306_device::di_w )
+{
+ m_di = state;
+}
+
+
+//-------------------------------------------------
+// do_r - serial data output
+//-------------------------------------------------
+
+READ_LINE_MEMBER( nmc9306_device::do_r )
+{
+ return m_do;
+}
diff --git a/src/emu/machine/nmc9306.h b/src/emu/machine/nmc9306.h
new file mode 100644
index 00000000000..aa9dfb20593
--- /dev/null
+++ b/src/emu/machine/nmc9306.h
@@ -0,0 +1,118 @@
+/**********************************************************************
+
+ National Semiconductor NMC9306 256-Bit Serial EEPROM emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ CS 1 |* \_/ | 8 Vcc
+ SK 2 | | 7 NC
+ DI 3 | | 6 NC
+ DO 4 |_____________| 5 GND
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __NMC9306__
+#define __NMC9306__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_NMC9306_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, NMC9306, 0)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// ======================> nmc9306_device_config
+
+class nmc9306_device_config : public device_config,
+ public device_config_nvram_interface
+{
+ friend class nmc9306_device;
+
+ // construction/destruction
+ nmc9306_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+protected:
+};
+
+
+// ======================> nmc9306_device
+
+class nmc9306_device : public device_t,
+ public device_nvram_interface
+{
+ friend class nmc9306_device_config;
+
+ // construction/destruction
+ nmc9306_device(running_machine &_machine, const nmc9306_device_config &_config);
+
+public:
+ DECLARE_WRITE_LINE_MEMBER( cs_w );
+ DECLARE_WRITE_LINE_MEMBER( sk_w );
+ DECLARE_WRITE_LINE_MEMBER( di_w );
+ DECLARE_READ_LINE_MEMBER( do_r );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+ // device_nvram_interface overrides
+ virtual void nvram_default();
+ virtual void nvram_read(emu_file &file);
+ virtual void nvram_write(emu_file &file);
+
+private:
+ inline UINT16 read(offs_t offset);
+ inline void write(offs_t offset, UINT16 data);
+ inline void erase(offs_t offset);
+
+ UINT16 m_register[16];
+
+ int m_bits;
+ int m_state;
+ UINT8 m_command;
+ UINT8 m_address;
+ UINT16 m_data;
+ bool m_ewen;
+ int m_cs;
+ int m_sk;
+ int m_do;
+ int m_di;
+
+ const nmc9306_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type NMC9306;
+
+
+
+#endif
diff --git a/src/emu/machine/z8536.c b/src/emu/machine/z8536.c
new file mode 100644
index 00000000000..e9d2d277b83
--- /dev/null
+++ b/src/emu/machine/z8536.c
@@ -0,0 +1,610 @@
+/**********************************************************************
+
+ Zilog Z8536 Counter/Timer and Parallel I/O emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "z8536.h"
+#include "machine/devhelpr.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+// states
+enum
+{
+ STATE_RESET = -1,
+ STATE_0,
+ STATE_1
+};
+
+
+// ports
+enum
+{
+ PORT_C = 0,
+ PORT_B,
+ PORT_A,
+ CONTROL
+};
+
+
+// registers
+enum
+{
+ MASTER_INTERRUPT_CONTROL = 0,
+ MASTER_CONFIGURATION_CONTROL,
+ PORT_A_INTERRUPT_VECTOR,
+ PORT_B_INTERRUPT_VECTOR,
+ COUNTER_TIMER_INTERRUPT_VECTOR,
+ PORT_C_DATA_PATH_POLARITY,
+ PORT_C_DATA_DIRECTION,
+ PORT_C_SPECIAL_IO_CONTROL,
+ PORT_A_COMMAND_AND_STATUS,
+ PORT_B_COMMAND_AND_STATUS,
+ COUNTER_TIMER_1_COMMAND_AND_STATUS,
+ COUNTER_TIMER_2_COMMAND_AND_STATUS,
+ COUNTER_TIMER_3_COMMAND_AND_STATUS,
+ PORT_A_DATA,
+ PORT_B_DATA,
+ PORT_C_DATA,
+ COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE,
+ COUNTER_TIMER_1_CURRENT_COUNT_LS_BYTE,
+ COUNTER_TIMER_2_CURRENT_COUNT_MS_BYTE,
+ COUNTER_TIMER_2_CURRENT_COUNT_LS_BYTE,
+ COUNTER_TIMER_3_CURRENT_COUNT_MS_BYTE,
+ COUNTER_TIMER_3_CURRENT_COUNT_LS_BYTE,
+ COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE,
+ COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE,
+ COUNTER_TIMER_2_TIME_CONSTANT_MS_BYTE,
+ COUNTER_TIMER_2_TIME_CONSTANT_LS_BYTE,
+ COUNTER_TIMER_3_TIME_CONSTANT_MS_BYTE,
+ COUNTER_TIMER_3_TIME_CONSTANT_LS_BYTE,
+ COUNTER_TIMER_1_MODE_SPECIFICATION,
+ COUNTER_TIMER_2_MODE_SPECIFICATION,
+ COUNTER_TIMER_3_MODE_SPECIFICATION,
+ CURRENT_VECTOR,
+ PORT_A_MODE_SPECIFICATION,
+ PORT_A_HANDSHAKE_SPECIFICATION,
+ PORT_A_DATA_PATH_POLARITY,
+ PORT_A_DATA_DIRECTION,
+ PORT_A_SPECIAL_IO_CONTROL,
+ PORT_A_PATTERN_POLARITY,
+ PORT_A_PATTERN_TRANSITION,
+ PORT_A_PATTERN_MASK,
+ PORT_B_MODE_SPECIFICATION,
+ PORT_B_HANDSHAKE_SPECIFICATION,
+ PORT_B_DATA_PATH_POLARITY,
+ PORT_B_DATA_DIRECTION,
+ PORT_B_SPECIAL_IO_CONTROL,
+ PORT_B_PATTERN_POLARITY,
+ PORT_B_PATTERN_TRANSITION,
+ PORT_B_PATTERN_MASK
+};
+
+
+// counter/timer link control
+enum
+{
+ LC_INDEPENDENT = 0,
+ LC_CT1_GATES_CT2,
+ LC_CT1_TRIGGERS_CT2,
+ LC_CT1_COUNTS_CT2
+};
+
+
+// port type select
+enum
+{
+ PTS_BIT = 0,
+ PTS_INPUT,
+ PTS_OUTPUT,
+ PTS_BIDIRECTIONAL
+};
+
+
+// pattern mode specification
+enum
+{
+ PMS_DISABLE = 0,
+ PMS_AND,
+ PMS_OR,
+ PMS_VECTOR
+};
+
+
+// handshake specification
+enum
+{
+ HTS_INTERLOCKED = 0,
+ HTS_STROBED,
+ HTS_PULSED,
+ HTS_3_WIRE
+};
+
+
+// request/wait specification
+enum
+{
+ RWS_DISABLED = 0,
+ RWS_OUTPUT_WAIT,
+ RWS_INPUT_WAIT = 3,
+ RWS_SPECIAL_REQUEST,
+ RWS_OUTPUT_REQUEST,
+ RWS_INPUT_REQUEST = 7
+};
+
+
+// pattern specification
+enum
+{
+ BIT_MASKED_OFF = 0,
+ ANY_TRANSITION,
+ ZERO = 4,
+ ONE,
+ ONE_TO_ZERO,
+ ZERO_TO_ONE
+};
+
+
+// output duty cycle
+enum
+{
+ DCS_PULSE,
+ DCS_ONE_SHOT,
+ DCS_SQUARE_WAVE,
+ DCS_DO_NOT_USE
+};
+
+
+// master interrupt control register
+#define MICR_RESET 0x01 // reset
+#define MICR_RJA 0x02 // right justified address
+#define MICR_CT_VIS 0x04 // counter/timer vector includes status
+#define MICR_PB_VIS 0x08 // port B vector includes status
+#define MICR_PA_VIS 0x10 // port A vector includes status
+#define MICR_NV 0x20 // no vector
+#define MICR_DLC 0x40 // disable lower chain
+#define MICR_MIE 0x80 // master interrupt enable
+
+
+// master configuration control register
+#define MCCR_LC_MASK 0x03 // counter/timer link controls
+#define MCCR_PAE 0x04 // port A enable
+#define MCCR_PLC 0x08 // port link control
+#define MCCR_PCE_CT3E 0x10 // port C and counter/timer 3 enable
+#define MCCR_CT2E 0x20 // counter/timer 2 enable
+#define MCCR_CT1E 0x40 // counter/timer 1 enable
+#define MCCR_PBE 0x80 // port B enable
+
+
+// port mode specification registers
+#define PMS_LPM 0x01 // latch on pattern match
+#define PMS_PMS_MASK 0x06 // pattern mode specification
+#define PMS_IMO 0x08 // interrupt on match only
+#define PMS_SB 0x10 // single buffer
+#define PMS_ITB 0x20 // interrupt on two bytes
+#define PMS_PTS_MASK 0xc0 // port type select
+
+
+// port handshake specification registers
+#define PHS_DTS_MASK 0x07 // deskew time specification
+#define PHS_RWS_MASK 0x38 // request/wait specification
+#define PHS_HTS_MASK 0xc0 // handshake type specification
+
+
+// port command and status registers
+#define PCS_IOE 0x01 // interrupt on error
+#define PCS_PMF 0x02 // pattern match flag (read only)
+#define PCS_IRF 0x04 // input register full (read only)
+#define PCS_ORE 0x08 // output register empty (read only)
+#define PCS_ERR 0x10 // interrupt error (read only)
+#define PCS_IP 0x20 // interrupt pending
+#define PCS_IE 0x40 // interrupt enable
+#define PCS_IUS 0x80 // interrupt under service
+
+
+// counter/timer mode specification registers
+#define CTMS_DCS_MASK 0x03 // output duty cycle
+#define CTMS_REB 0x04 // retrigger enable bit
+#define CTMS_EDE 0x08 // external gate enable
+#define CTMS_ETE 0x10 // external trigger enable
+#define CTMS_ECE 0x20 // external count enable
+#define CTMS_EOE 0x40 // external output enable
+#define CTMS_CSC 0x80 // continuous single cycle
+
+
+// counter/timer command and status registers
+#define CTCS_CIP 0x01 // count in progress (read only)
+#define CTCS_TCB 0x02 // trigger command bit (write only - read returns 0)
+#define CTCS_GCB 0x04 // gate command bit
+#define CTCS_RCC 0x08 // read counter control (read/set only - cleared by reading CCR LSB)
+#define CTCS_ERR 0x10 // interrupt error (read only)
+#define CTCS_IP 0x20 // interrupt pending
+#define CTCS_IE 0x40 // interrupt enable
+#define CTCS_IUS 0x80 // interrupt under service
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type Z8536 = z8536_device_config::static_alloc_device_config;
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+GENERIC_DEVICE_CONFIG_SETUP(z8536, "Zilog Z8536")
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void z8536_device_config::device_config_complete()
+{
+ // inherit a copy of the static data
+ const z8536_interface *intf = reinterpret_cast<const z8536_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<z8536_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_int_func, 0, sizeof(m_out_int_func));
+ memset(&m_in_pa_func, 0, sizeof(m_in_pa_func));
+ memset(&m_out_pa_func, 0, sizeof(m_out_pa_func));
+ memset(&m_in_pb_func, 0, sizeof(m_in_pb_func));
+ memset(&m_out_pb_func, 0, sizeof(m_out_pb_func));
+ memset(&m_in_pc_func, 0, sizeof(m_in_pc_func));
+ memset(&m_out_pc_func, 0, sizeof(m_out_pc_func));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// read_register - read from register
+//-------------------------------------------------
+
+inline UINT8 z8536_device::read_register(offs_t offset)
+{
+ UINT8 data = 0;
+
+ data = m_register[offset]; // HACK
+
+ switch (offset)
+ {
+ case PORT_A_DATA:
+ data = devcb_call_read8(&m_in_pa_func, 0);
+ break;
+
+ case PORT_B_DATA:
+ data = devcb_call_read8(&m_in_pb_func, 0);
+ break;
+
+ case PORT_C_DATA:
+ data = 0xf0 | (devcb_call_read8(&m_in_pc_func, 0) & 0x0f);
+ break;
+
+ default:
+ logerror("Z8536 '%s' Unimplemented read from register %u\n", tag(), offset);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// read_register - masked read from register
+//-------------------------------------------------
+
+inline UINT8 z8536_device::read_register(offs_t offset, UINT8 mask)
+{
+ return read_register(offset) & mask;
+}
+
+
+//-------------------------------------------------
+// write_register - write to register
+//-------------------------------------------------
+
+inline void z8536_device::write_register(offs_t offset, UINT8 data)
+{
+ switch (offset)
+ {
+ case MASTER_INTERRUPT_CONTROL:
+ if (data & MICR_RESET)
+ {
+ device_reset();
+ }
+ else if (m_state == STATE_RESET)
+ {
+ m_state = STATE_0;
+ }
+ break;
+
+ case PORT_A_DATA:
+ devcb_call_write8(&m_out_pa_func, 0, data);
+ break;
+
+ case PORT_B_DATA:
+ devcb_call_write8(&m_out_pb_func, 0, data);
+ break;
+
+ case PORT_C_DATA:
+ {
+ UINT8 mask = (data & 0xf0) | (data >> 4);
+
+ m_output[PORT_C] = (m_output[PORT_C] & mask) | ((data & 0x0f) & (mask ^ 0xff));
+
+ devcb_call_write8(&m_out_pc_func, 0, m_output[PORT_C]);
+ }
+ break;
+
+ default:
+ logerror("Z8536 '%s' Unimplemented write %02x to register %u\n", tag(), data, offset);
+ }
+
+ m_register[offset] = data; // HACK
+}
+
+
+//-------------------------------------------------
+// write_register - masked write to register
+//-------------------------------------------------
+
+inline void z8536_device::write_register(offs_t offset, UINT8 data, UINT8 mask)
+{
+ UINT8 combined_data = (data & mask) | (m_register[offset] & (mask ^ 0xff));
+
+ write_register(offset, combined_data);
+}
+
+
+//-------------------------------------------------
+// count -
+//-------------------------------------------------
+
+inline void z8536_device::count(device_timer_id id)
+{
+}
+
+
+//-------------------------------------------------
+// trigger -
+//-------------------------------------------------
+
+inline void z8536_device::trigger(device_timer_id id)
+{
+}
+
+
+//-------------------------------------------------
+// gate -
+//-------------------------------------------------
+
+inline void z8536_device::gate(device_timer_id id)
+{
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// z8536_device - constructor
+//-------------------------------------------------
+
+z8536_device::z8536_device(running_machine &_machine, const z8536_device_config &config)
+ : device_t(_machine, config),
+ m_config(config)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void z8536_device::device_start()
+{
+ // allocate timers
+ m_timer[TIMER_1] = timer_alloc(TIMER_1);
+ m_timer[TIMER_2] = timer_alloc(TIMER_2);
+ m_timer[TIMER_3] = timer_alloc(TIMER_3);
+
+ // resolve callbacks
+ devcb_resolve_write_line(&m_out_int_func, &m_config.m_out_int_func, this);
+ devcb_resolve_read8(&m_in_pa_func, &m_config.m_in_pa_func, this);
+ devcb_resolve_write8(&m_out_pa_func, &m_config.m_out_pa_func, this);
+ devcb_resolve_read8(&m_in_pb_func, &m_config.m_in_pb_func, this);
+ devcb_resolve_write8(&m_out_pb_func, &m_config.m_out_pb_func, this);
+ devcb_resolve_read8(&m_in_pc_func, &m_config.m_in_pc_func, this);
+ devcb_resolve_write8(&m_out_pc_func, &m_config.m_out_pc_func, this);
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific reset
+//-------------------------------------------------
+
+void z8536_device::device_reset()
+{
+ m_state = STATE_RESET;
+
+ for (int i = 0; i < 48; i++)
+ {
+ m_register[i] = 0;
+ }
+
+ m_register[MASTER_INTERRUPT_CONTROL] = MICR_RESET;
+ m_pointer = 0;
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void z8536_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_1:
+ count(TIMER_1);
+ break;
+
+ case TIMER_2:
+ count(TIMER_2);
+ break;
+
+ case TIMER_3:
+ count(TIMER_3);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// read - register read
+//-------------------------------------------------
+
+READ8_MEMBER( z8536_device::read )
+{
+ UINT8 data = 0;
+
+ if (m_state == STATE_RESET)
+ {
+ // read RESET bit
+ data = read_register(m_pointer, 0x01);
+ }
+ else
+ {
+ switch (offset & 0x03)
+ {
+ case PORT_C:
+ data = read_register(PORT_C_DATA);
+ break;
+
+ case PORT_B:
+ data = read_register(PORT_B_DATA);
+ break;
+
+ case PORT_A:
+ data = read_register(PORT_A_DATA);
+ break;
+
+ case CONTROL:
+ switch (m_state)
+ {
+ case STATE_1:
+ m_state = STATE_0;
+ // fallthru
+ case STATE_0:
+ data = read_register(m_pointer);
+ break;
+ }
+ break;
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write - register write
+//-------------------------------------------------
+
+WRITE8_MEMBER( z8536_device::write )
+{
+ if (m_state == STATE_RESET)
+ {
+ // write RESET bit
+ write_register(m_pointer, data, 0x01);
+ }
+ else
+ {
+ switch (offset & 0x03)
+ {
+ case PORT_C:
+ write_register(PORT_C_DATA, data);
+ break;
+
+ case PORT_B:
+ write_register(PORT_B_DATA, data);
+ break;
+
+ case PORT_A:
+ write_register(PORT_A_DATA, data);
+ break;
+
+ case CONTROL:
+ switch (m_state)
+ {
+ case STATE_0:
+ m_pointer = data;
+ m_state = STATE_1;
+ break;
+
+ case STATE_1:
+ write_register(m_pointer, data);
+ m_state = STATE_0;
+ }
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// intack_w - interrupt acknowledge
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( z8536_device::intack_w )
+{
+}
+
+
+//-------------------------------------------------
+// pb*_w - port B bits 0-7 write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( z8536_device::pb0_w ) { }
+WRITE_LINE_MEMBER( z8536_device::pb1_w ) { }
+WRITE_LINE_MEMBER( z8536_device::pb2_w ) { }
+WRITE_LINE_MEMBER( z8536_device::pb3_w ) { }
+WRITE_LINE_MEMBER( z8536_device::pb4_w ) { }
+WRITE_LINE_MEMBER( z8536_device::pb5_w ) { }
+WRITE_LINE_MEMBER( z8536_device::pb6_w ) { }
+WRITE_LINE_MEMBER( z8536_device::pb7_w ) { }
+
+
+//-------------------------------------------------
+// pc*_w - port C bits 0-3 write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( z8536_device::pc0_w ) { }
+WRITE_LINE_MEMBER( z8536_device::pc1_w ) { }
+WRITE_LINE_MEMBER( z8536_device::pc2_w ) { }
+WRITE_LINE_MEMBER( z8536_device::pc3_w ) { }
diff --git a/src/emu/machine/z8536.h b/src/emu/machine/z8536.h
new file mode 100644
index 00000000000..75f82f12988
--- /dev/null
+++ b/src/emu/machine/z8536.h
@@ -0,0 +1,182 @@
+/**********************************************************************
+
+ Zilog Z8536 Counter/Timer and Parallel I/O emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ D4 1 |* \_/ | 40 D3
+ D5 2 | | 39 D2
+ D6 3 | | 38 D1
+ D7 4 | | 37 D0
+ _RD 5 | | 36 _CE
+ _WR 6 | | 35 A1
+ GND 7 | | 34 A0
+ PB0 8 | | 33 PA0
+ PB1 9 | | 32 PA1
+ PB2 10 | Z8536 | 31 PA2
+ PB3 11 | | 30 PA3
+ PB4 12 | | 29 PA4
+ PB5 13 | | 28 PA5
+ PB6 14 | | 27 PA6
+ PB7 15 | | 26 PA7
+ PCLK 16 | | 25 _INTACK
+ IEI 17 | | 24 _INT
+ IEO 18 | | 23 +5 V
+ PC0 19 | | 22 PC3
+ PC1 20 |_____________| 21 PC2
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __Z8536__
+#define __Z8536__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_Z8536_ADD(_tag, _clock, _intrf) \
+ MCFG_DEVICE_ADD(_tag, Z8536, _clock) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define Z8536_INTERFACE(name) \
+ const z8536_interface (name)=
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> z8536_interface
+
+struct z8536_interface
+{
+ devcb_write_line m_out_int_func;
+
+ devcb_read8 m_in_pa_func;
+ devcb_write8 m_out_pa_func;
+
+ devcb_read8 m_in_pb_func;
+ devcb_write8 m_out_pb_func;
+
+ devcb_read8 m_in_pc_func;
+ devcb_write8 m_out_pc_func;
+};
+
+
+// ======================> z8536_device_config
+
+class z8536_device_config : public device_config,
+ public z8536_interface
+{
+ friend class z8536_device;
+
+ // construction/destruction
+ z8536_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+protected:
+ // device_config overrides
+ virtual void device_config_complete();
+};
+
+
+// ======================> z8536_device
+
+class z8536_device : public device_t
+{
+ friend class z8536_device_config;
+
+ // construction/destruction
+ z8536_device(running_machine &_machine, const z8536_device_config &_config);
+
+public:
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+ DECLARE_WRITE_LINE_MEMBER( intack_w );
+
+ DECLARE_WRITE_LINE_MEMBER( pb0_w );
+ DECLARE_WRITE_LINE_MEMBER( pb1_w );
+ DECLARE_WRITE_LINE_MEMBER( pb2_w );
+ DECLARE_WRITE_LINE_MEMBER( pb3_w );
+ DECLARE_WRITE_LINE_MEMBER( pb4_w );
+ DECLARE_WRITE_LINE_MEMBER( pb5_w );
+ DECLARE_WRITE_LINE_MEMBER( pb6_w );
+ DECLARE_WRITE_LINE_MEMBER( pb7_w );
+ DECLARE_WRITE_LINE_MEMBER( pc0_w );
+ DECLARE_WRITE_LINE_MEMBER( pc1_w );
+ DECLARE_WRITE_LINE_MEMBER( pc2_w );
+ DECLARE_WRITE_LINE_MEMBER( pc3_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ static const device_timer_id TIMER_1 = 0;
+ static const device_timer_id TIMER_2 = 1;
+ static const device_timer_id TIMER_3 = 2;
+
+ inline UINT8 read_register(offs_t offset);
+ inline UINT8 read_register(offs_t offset, UINT8 mask);
+ inline void write_register(offs_t offset, UINT8 data);
+ inline void write_register(offs_t offset, UINT8 data, UINT8 mask);
+
+ inline void count(device_timer_id id);
+ inline void trigger(device_timer_id id);
+ inline void gate(device_timer_id id);
+
+ devcb_resolved_write_line m_out_int_func;
+
+ devcb_resolved_read8 m_in_pa_func;
+ devcb_resolved_write8 m_out_pa_func;
+
+ devcb_resolved_read8 m_in_pb_func;
+ devcb_resolved_write8 m_out_pb_func;
+
+ devcb_resolved_read8 m_in_pc_func;
+ devcb_resolved_write8 m_out_pc_func;
+
+ int m_state;
+ UINT8 m_register[48];
+ UINT8 m_pointer;
+ UINT8 m_input[3];
+ UINT8 m_output[3];
+ UINT8 m_buffer[3];
+
+ // timers
+ emu_timer *m_timer[3];
+
+ const z8536_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type Z8536;
+
+
+
+#endif
diff --git a/src/emu/video/crt9007.c b/src/emu/video/crt9007.c
new file mode 100644
index 00000000000..f048f8929f2
--- /dev/null
+++ b/src/emu/video/crt9007.c
@@ -0,0 +1,1017 @@
+/**********************************************************************
+
+ SMC CRT9007 CRT Video Processor and Controller (VPAC) emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - cursor timer
+ - interrupts
+ - light pen
+ - frame timer
+ - non-DMA mode
+ - DMA mode
+ - cursor/blank skew
+ - sequential breaks
+ - interlaced mode
+ - smooth scroll
+ - page blank
+ - double height cursor
+ - row attributes
+ - pin configuration
+ - operation modes 0,4,7
+ - address modes 1,2,3
+ - light pen
+ - state saving
+
+*/
+
+#include "emu.h"
+#include "crt9007.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 1
+
+#define HAS_VALID_PARAMETERS \
+ (m_reg[0x00] && m_reg[0x01] && m_reg[0x07] && m_reg[0x08] && m_reg[0x09])
+
+#define CHARACTERS_PER_HORIZONTAL_PERIOD \
+ m_reg[0x00]
+
+#define CHARACTERS_PER_DATA_ROW \
+ (m_reg[0x01] + 1)
+
+#define HORIZONTAL_DELAY \
+ m_reg[0x02]
+
+#define HORIZONTAL_SYNC_WIDTH \
+ m_reg[0x03]
+
+#define VERTICAL_SYNC_WIDTH \
+ m_reg[0x04]
+
+#define VERTICAL_DELAY \
+ (m_reg[0x05] - 1)
+
+#define PIN_CONFIGURATION \
+ (m_reg[0x06] >> 6)
+
+#define CURSOR_SKEW \
+ ((m_reg[0x06] >> 3) & 0x07)
+
+#define BLANK_SKEW \
+ (m_reg[0x06] & 0x07)
+
+#define VISIBLE_DATA_ROWS_PER_FRAME \
+ (m_reg[0x07] + 1)
+
+#define SCAN_LINES_PER_DATA_ROW \
+ ((m_reg[0x08] & 0x1f) + 1)
+
+#define SCAN_LINES_PER_FRAME \
+ (((m_reg[0x08] << 3) & 0x0700) | m_reg[0x09])
+
+#define DMA_BURST_COUNT \
+ ((m_reg[0x0a] & 0x0f) + 1)
+
+#define DMA_BURST_DELAY \
+ ((((m_reg[0x0a] >> 4) & 0x07) + 1) % 8)
+
+#define DMA_DISABLE \
+ BIT(m_reg[0x0a], 7)
+
+#define SINGLE_HEIGHT_CURSOR \
+ BIT(m_reg[0x0b], 0)
+
+#define OPERATION_MODE \
+ ((m_reg[0x0b] >> 1) & 0x07)
+
+#define INTERLACE_MODE \
+ ((m_reg[0x0b] >> 4) & 0x03)
+
+#define PAGE_BLANK \
+ BIT(m_reg[0x0b], 6)
+
+#define TABLE_START \
+ (((m_reg[0x0d] << 8) & 0x3f00) | m_reg[0x0c])
+
+#define ADDRESS_MODE \
+ ((m_reg[0x0d] >> 6) & 0x03)
+
+#define AUXILIARY_ADDRESS_1 \
+ (((m_reg[0x0f] << 8) & 0x3f00) | m_reg[0x0e])
+
+#define ROW_ATTRIBUTES_1 \
+ ((m_reg[0x0f] >> 6) & 0x03)
+
+#define SEQUENTIAL_BREAK_1 \
+ m_reg[0x10]
+
+#define SEQUENTIAL_BREAK_2 \
+ m_reg[0x12]
+
+#define DATA_ROW_START \
+ m_reg[0x11]
+
+#define DATA_ROW_END \
+ m_reg[0x12]
+
+#define AUXILIARY_ADDRESS_2 \
+ (((m_reg[0x14] << 8) & 0x3f00) | m_reg[0x13])
+
+#define ROW_ATTRIBUTES_2 \
+ ((m_reg[0x14] >> 6) & 0x03)
+
+#define SMOOTH_SCROLL_OFFSET \
+ ((m_reg[0x17] >> 1) & 0x3f)
+
+#define SMOOTH_SCROLL_OFFSET_OVERFLOW \
+ BIT(m_reg[0x17], 7)
+
+#define VERTICAL_CURSOR \
+ m_reg[0x18]
+
+#define HORIZONTAL_CURSOR \
+ m_reg[0x19]
+
+#define INTERRUPT_ENABLE \
+ m_reg[0x1a]
+
+#define FRAME_TIMER \
+ BIT(m_reg[0x1a], 0)
+
+#define LIGHT_PEN_INTERRUPT \
+ BIT(m_reg[0x1a], 5)
+
+#define VERTICAL_RETRACE_INTERRUPT \
+ BIT(m_reg[0x1a], 6)
+
+#define VERTICAL_LIGHT_PEN \
+ m_reg[0x3b]
+
+#define HORIZONTAL_LIGHT_PEN \
+ m_reg[0x3c]
+
+
+// interlace
+enum
+{
+ NON_INTERLACED = 0,
+ ENHANCED_VIDEO_INTERFACE,
+ NORMAL_VIDEO_INTERFACE,
+};
+
+
+// operation modes
+enum
+{
+ OPERATION_MODE_REPETITIVE_MEMORY_ADDRESSING = 0, // not implemented
+ OPERATION_MODE_DOUBLE_ROW_BUFFER = 1,
+ OPERATION_MODE_SINGLE_ROW_BUFFER = 4, // not implemented
+ OPERATION_MODE_ATTRIBUTE_ASSEMBLE = 7 // not implemented
+};
+
+
+// addressing modes
+enum
+{
+ ADDRESS_MODE_SEQUENTIAL_ADDRESSING = 0,
+ ADDRESS_MODE_SEQUENTIAL_ROLL_ADDRESSING, // not implemented
+ ADDRESS_MODE_CONTIGUOUS_ROW_TABLE, // not implemented
+ ADDRESS_MODE_LINKED_LIST_ROW_TABLE // not implemented
+};
+
+
+// interrupt enable register bits
+const int IE_VERTICAL_RETRACE = 0x40;
+const int IE_LIGHT_PEN = 0x20;
+const int IE_FRAME_TIMER = 0x01;
+
+// status register bits
+const int STATUS_INTERRUPT_PENDING = 0x80;
+const int STATUS_VERTICAL_RETRACE = 0x40;
+const int STATUS_LIGHT_PEN_UPDATE = 0x20;
+const int STATUS_ODD_EVEN = 0x04;
+const int STATUS_FRAME_TIMER_OCCURRED = 0x01;
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type CRT9007 = crt9007_device_config::static_alloc_device_config;
+
+
+// default address map
+static ADDRESS_MAP_START( crt9007, AS_0, 8 )
+ AM_RANGE(0x0000, 0x3fff) AM_RAM
+ADDRESS_MAP_END
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// crt9007_device_config - constructor
+//-------------------------------------------------
+
+crt9007_device_config::crt9007_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+ : device_config(mconfig, static_alloc_device_config, "SMC CRT9007", tag, owner, clock),
+ device_config_memory_interface(mconfig, *this),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(crt9007))
+{
+}
+
+
+//-------------------------------------------------
+// static_alloc_device_config - allocate a new
+// configuration object
+//-------------------------------------------------
+
+device_config *crt9007_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+{
+ return global_alloc(crt9007_device_config(mconfig, tag, owner, clock));
+}
+
+
+//-------------------------------------------------
+// alloc_device - allocate a new device object
+//-------------------------------------------------
+
+device_t *crt9007_device_config::alloc_device(running_machine &machine) const
+{
+ return auto_alloc(&machine, crt9007_device(machine, *this));
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *crt9007_device_config::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void crt9007_device_config::device_config_complete()
+{
+ // inherit a copy of the static data
+ const crt9007_interface *intf = reinterpret_cast<const crt9007_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<crt9007_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&out_int_func, 0, sizeof(out_int_func));
+ memset(&out_dmar_func, 0, sizeof(out_dmar_func));
+ memset(&out_vs_func, 0, sizeof(out_vs_func));
+ memset(&out_hs_func, 0, sizeof(out_hs_func));
+ memset(&out_vlt_func, 0, sizeof(out_vlt_func));
+ memset(&out_curs_func, 0, sizeof(out_curs_func));
+ memset(&out_drb_func, 0, sizeof(out_drb_func));
+ memset(&out_cblank_func, 0, sizeof(out_cblank_func));
+ memset(&out_slg_func, 0, sizeof(out_slg_func));
+ memset(&out_sld_func, 0, sizeof(out_sld_func));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// readbyte - read a byte at the given address
+//-------------------------------------------------
+
+inline UINT8 crt9007_device::readbyte(offs_t address)
+{
+ return space()->read_byte(address);
+}
+
+
+//-------------------------------------------------
+// trigger_interrupt -
+//-------------------------------------------------
+
+inline void crt9007_device::trigger_interrupt(int line)
+{
+ if (INTERRUPT_ENABLE & line)
+ {
+ int status = m_status;
+
+ m_status |= STATUS_INTERRUPT_PENDING | line;
+
+ if (!(status & STATUS_INTERRUPT_PENDING))
+ {
+ if (LOG) logerror("CRT9007 '%s' INT 1\n", tag());
+ devcb_call_write_line(&m_out_int_func, ASSERT_LINE);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// update_cblank_line -
+//-------------------------------------------------
+
+inline void crt9007_device::update_cblank_line()
+{
+ int x = m_screen->hpos();
+ int y = m_screen->vpos();
+
+ // composite blank
+ int cblank = !(m_hs & m_vs);
+
+ if (m_cblank != cblank)
+ {
+ m_cblank = cblank;
+
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : CBLANK %u\n", tag(), y, x, m_cblank);
+
+ devcb_call_write_line(&m_out_cblank_func, m_cblank);
+ }
+}
+
+
+//-------------------------------------------------
+// update_hsync_timer -
+//-------------------------------------------------
+
+inline void crt9007_device::update_hsync_timer(int state)
+{
+ int y = m_screen->vpos();
+
+ int next_x = state ? m_hsync_start : m_hsync_end;
+ int next_y = state ? (y + 1) % SCAN_LINES_PER_FRAME : y;
+
+ attotime duration = m_screen->time_until_pos(next_y, next_x);
+
+ m_hsync_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_vsync_timer -
+//-------------------------------------------------
+
+inline void crt9007_device::update_vsync_timer(int state)
+{
+ int next_y = state ? m_vsync_start : m_vsync_end;
+
+ attotime duration = m_screen->time_until_pos(next_y, 0);
+
+ m_vsync_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_vlt_timer -
+//-------------------------------------------------
+
+inline void crt9007_device::update_vlt_timer(int state)
+{
+ // this signal is active during all visible scan lines and during the horizontal trace at vertical retrace
+ int y = m_screen->vpos();
+
+ int next_x = state ? m_vlt_end : m_vlt_start;
+ int next_y = state ? y : ((y == m_vlt_bottom) ? 0 : (y + 1));
+
+ attotime duration = m_screen->time_until_pos(next_y, next_x);
+
+ m_vlt_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_curs_timer -
+//-------------------------------------------------
+
+inline void crt9007_device::update_curs_timer(int state)
+{
+ // this signal is active for 1 character time for all scanlines within the data row
+ // TODO
+}
+
+
+//-------------------------------------------------
+// update_drb_timer -
+//-------------------------------------------------
+
+inline void crt9007_device::update_drb_timer(int state)
+{
+ // this signal is active for 1 full scan line (VLT edge to edge) at the top scan line of each new row
+ // there is 1 extra DRB signal during the 1st scanline of the vertical retrace interval
+ int y = m_screen->vpos();
+
+ int next_x = m_vlt_end;
+ int next_y = y ? y + 1 : y;
+
+ if (state)
+ {
+ if (y == 0)
+ {
+ next_y = VERTICAL_DELAY - 1;
+ }
+ else if (y == m_drb_bottom)
+ {
+ next_x = 0;
+ next_y = 0;
+ }
+ else
+ {
+ next_y = y + SCAN_LINES_PER_DATA_ROW - 1;
+ }
+ }
+
+ attotime duration = m_screen->time_until_pos(next_y, next_x);
+
+ m_drb_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_dma_timer -
+//-------------------------------------------------
+
+inline void crt9007_device::update_dma_timer()
+{
+ // TODO
+}
+
+
+//-------------------------------------------------
+// recompute_parameters -
+//-------------------------------------------------
+
+inline void crt9007_device::recompute_parameters()
+{
+ // check that necessary registers have been loaded
+ if (!HAS_VALID_PARAMETERS) return;
+
+ // screen dimensions
+ int horiz_pix_total = CHARACTERS_PER_HORIZONTAL_PERIOD * m_hpixels_per_column;
+ int vert_pix_total = SCAN_LINES_PER_FRAME;
+
+ // refresh rate
+ attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock()) * horiz_pix_total * vert_pix_total;
+
+ // horizontal sync
+ m_hsync_start = 0;
+ m_hsync_end = HORIZONTAL_SYNC_WIDTH * m_hpixels_per_column;
+
+ // visible line time
+ m_vlt_start = HORIZONTAL_DELAY * m_hpixels_per_column;
+ m_vlt_end = (HORIZONTAL_DELAY + CHARACTERS_PER_DATA_ROW) * m_hpixels_per_column;
+ m_vlt_bottom = VERTICAL_DELAY + (VISIBLE_DATA_ROWS_PER_FRAME * SCAN_LINES_PER_DATA_ROW) - 1;
+
+ // data row boundary
+ m_drb_bottom = VERTICAL_DELAY + (VISIBLE_DATA_ROWS_PER_FRAME * SCAN_LINES_PER_DATA_ROW) - SCAN_LINES_PER_DATA_ROW;
+
+ // vertical sync
+ m_vsync_start = 0;
+ m_vsync_end = VERTICAL_SYNC_WIDTH;
+
+ // visible area
+ rectangle visarea;
+
+ visarea.min_x = m_hsync_end;
+ visarea.max_x = horiz_pix_total - 1;
+
+ visarea.min_y = m_vsync_end;
+ visarea.max_y = vert_pix_total - 1;
+
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
+ logerror("CRT9007 '%s' Visible Area: (%u, %u) - (%u, %u)\n", tag(), visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y);
+ }
+
+ m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh);
+
+ m_hsync_timer->adjust(m_screen->time_until_pos(0, 0));
+ m_vsync_timer->adjust(m_screen->time_until_pos(0, 0));
+ m_vlt_timer->adjust(m_screen->time_until_pos(0, m_vlt_start), 1);
+ m_drb_timer->adjust(m_screen->time_until_pos(0, 0));
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// crt9007_device - constructor
+//-------------------------------------------------
+
+crt9007_device::crt9007_device(running_machine &_machine, const crt9007_device_config &config)
+ : device_t(_machine, config),
+ device_memory_interface(_machine, config, *this),
+ m_config(config)
+{
+ for (int i = 0; i < 0x3d; i++)
+ m_reg[i] = 0;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void crt9007_device::device_start()
+{
+ // allocate timers
+ m_hsync_timer = timer_alloc(TIMER_HSYNC);
+ m_vsync_timer = timer_alloc(TIMER_VSYNC);
+ m_vlt_timer = timer_alloc(TIMER_VLT);
+ m_curs_timer = timer_alloc(TIMER_CURS);
+ m_drb_timer = timer_alloc(TIMER_DRB);
+ m_dma_timer = timer_alloc(TIMER_DMA);
+
+ // resolve callbacks
+ devcb_resolve_write_line(&m_out_int_func, &m_config.out_int_func, this);
+ devcb_resolve_write_line(&m_out_dmar_func, &m_config.out_dmar_func, this);
+ devcb_resolve_write_line(&m_out_hs_func, &m_config.out_hs_func, this);
+ devcb_resolve_write_line(&m_out_vs_func, &m_config.out_vs_func, this);
+ devcb_resolve_write_line(&m_out_vlt_func, &m_config.out_vlt_func, this);
+ devcb_resolve_write_line(&m_out_curs_func, &m_config.out_curs_func, this);
+ devcb_resolve_write_line(&m_out_drb_func, &m_config.out_drb_func, this);
+ devcb_resolve_write_line(&m_out_cblank_func, &m_config.out_cblank_func, this);
+ devcb_resolve_write_line(&m_out_slg_func, &m_config.out_slg_func, this);
+ devcb_resolve_write_line(&m_out_sld_func, &m_config.out_sld_func, this);
+
+ // get the screen device
+ m_screen = machine->device<screen_device>(m_config.screen_tag);
+ assert(m_screen != NULL);
+
+ // set horizontal pixels per column
+ m_hpixels_per_column = m_config.hpixels_per_column;
+
+ // register for state saving
+// state_save_register_device_item(this, 0, );
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void crt9007_device::device_reset()
+{
+ m_disp = 0;
+
+ // HS = 1
+ devcb_call_write_line(&m_out_hs_func, 1);
+
+ // VS = 1
+ devcb_call_write_line(&m_out_vs_func, 1);
+
+ // CBLANK = 1
+ devcb_call_write_line(&m_out_cblank_func, 0);
+
+ // CURS = 0
+ devcb_call_write_line(&m_out_curs_func, 0);
+
+ // VLT = 0
+ devcb_call_write_line(&m_out_vlt_func, 0);
+
+ // DRB = 1
+ devcb_call_write_line(&m_out_drb_func, 1);
+
+ // INT = 0
+ devcb_call_write_line(&m_out_int_func, CLEAR_LINE);
+
+ // 28 (DMAR) = 0
+ devcb_call_write_line(&m_out_dmar_func, CLEAR_LINE);
+
+ // 29 (WBEN) = 0
+
+ // 30 (SLG) = 0
+ devcb_call_write_line(&m_out_slg_func, 0);
+
+ // 31 (SLD) = 0
+ devcb_call_write_line(&m_out_sld_func, 0);
+
+ // 32 (LPSTB) = 0
+}
+
+
+//-------------------------------------------------
+// device_clock_changed - handle clock change
+//-------------------------------------------------
+
+void crt9007_device::device_clock_changed()
+{
+ recompute_parameters();
+}
+
+
+//-------------------------------------------------
+// device_timer - handle timer events
+//-------------------------------------------------
+
+void crt9007_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ int x = m_screen->hpos();
+ int y = m_screen->vpos();
+
+ switch (id)
+ {
+ case TIMER_HSYNC:
+ m_hs = param;
+
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : HS %u\n", tag(), y, x, m_hs);
+
+ devcb_call_write_line(&m_out_hs_func, m_hs);
+
+ update_cblank_line();
+
+ update_hsync_timer(param);
+ break;
+
+ case TIMER_VSYNC:
+ m_vs = param;
+
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : VS %u\n", tag(), y, x, m_vs);
+
+ devcb_call_write_line(&m_out_vs_func, param);
+
+ if (m_vs)
+ {
+ // reset all other bits except Light Pen Update to logic 0
+ m_status &= STATUS_LIGHT_PEN_UPDATE;
+ }
+ else
+ {
+ trigger_interrupt(IE_VERTICAL_RETRACE);
+
+ update_cblank_line();
+ }
+
+ update_vsync_timer(param);
+ break;
+
+ case TIMER_VLT:
+ m_vlt = param;
+
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : VLT %u\n", tag(), y, x, m_vlt);
+
+ devcb_call_write_line(&m_out_vlt_func, param);
+
+ update_vlt_timer(param);
+ break;
+
+ case TIMER_CURS:
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : CURS %u\n", tag(), y, x, param);
+
+ devcb_call_write_line(&m_out_curs_func, param);
+
+ update_curs_timer(param);
+ break;
+
+ case TIMER_DRB:
+ m_drb = param;
+
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : DRB %u\n", tag(), y, x, m_drb);
+
+ devcb_call_write_line(&m_out_drb_func, param);
+
+ if (!m_drb && !DMA_DISABLE)
+ {
+ // start DMA burst sequence
+ m_dma_count = CHARACTERS_PER_DATA_ROW;
+ m_dma_burst = DMA_BURST_COUNT ? (DMA_BURST_COUNT * 4) : CHARACTERS_PER_DATA_ROW;
+ m_dma_delay = DMA_BURST_DELAY;
+ m_dmar = 1;
+
+ if (LOG) logerror("CRT9007 '%s' DMAR 1\n", tag());
+ devcb_call_write_line(&m_out_dmar_func, ASSERT_LINE);
+ }
+
+ update_drb_timer(param);
+ break;
+
+ case TIMER_DMA:
+ readbyte(AUXILIARY_ADDRESS_2);
+
+ update_dma_timer();
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// read - register read
+//-------------------------------------------------
+
+READ8_MEMBER( crt9007_device::read )
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case 0x15:
+ if (LOG) logerror("CRT9007 '%s' Start\n", tag());
+ m_disp = 1;
+ break;
+
+ case 0x16:
+ if (LOG) logerror("CRT9007 '%s' Reset\n", tag());
+ device_reset();
+ break;
+
+ case 0x38:
+ data = VERTICAL_CURSOR;
+ break;
+
+ case 0x39:
+ data = HORIZONTAL_CURSOR;
+ break;
+
+ case 0x3a:
+ data = m_status;
+
+ // reset interrupt pending bit
+ m_status &= ~STATUS_INTERRUPT_PENDING;
+ if (LOG) logerror("CRT9007 '%s' INT 0\n", tag());
+ devcb_call_write_line(&m_out_int_func, CLEAR_LINE);
+ break;
+
+ case 0x3b:
+ data = VERTICAL_LIGHT_PEN;
+ break;
+
+ case 0x3c:
+ data = HORIZONTAL_LIGHT_PEN;
+
+ // reset light pen update bit
+ m_status &= ~STATUS_LIGHT_PEN_UPDATE;
+ break;
+
+ default:
+ logerror("CRT9007 '%s' Read from Invalid Register: %02x!\n", tag(), offset);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write - register write
+//-------------------------------------------------
+
+WRITE8_MEMBER( crt9007_device::write )
+{
+ m_reg[offset] = data;
+
+ switch (offset)
+ {
+ case 0x00:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Characters per Horizontal Period: %u\n", tag(), CHARACTERS_PER_HORIZONTAL_PERIOD);
+ break;
+
+ case 0x01:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Characters per Data Row: %u\n", tag(), CHARACTERS_PER_DATA_ROW);
+ break;
+
+ case 0x02:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Horizontal Delay: %u\n", tag(), HORIZONTAL_DELAY);
+ break;
+
+ case 0x03:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Horizontal Sync Width: %u\n", tag(), HORIZONTAL_SYNC_WIDTH);
+ break;
+
+ case 0x04:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Vertical Sync Width: %u\n", tag(), VERTICAL_SYNC_WIDTH);
+ break;
+
+ case 0x05:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Vertical Delay: %u\n", tag(), VERTICAL_DELAY);
+ break;
+
+ case 0x06:
+ recompute_parameters();
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Pin Configuration: %u\n", tag(), PIN_CONFIGURATION);
+ logerror("CRT9007 '%s' Cursor Skew: %u\n", tag(), CURSOR_SKEW);
+ logerror("CRT9007 '%s' Blank Skew: %u\n", tag(), BLANK_SKEW);
+ }
+ break;
+
+ case 0x07:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Visible Data Rows per Frame: %u\n", tag(), VISIBLE_DATA_ROWS_PER_FRAME);
+ break;
+
+ case 0x08:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Scan Lines per Data Row: %u\n", tag(), SCAN_LINES_PER_DATA_ROW);
+ break;
+
+ case 0x09:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Scan Lines per Frame: %u\n", tag(), SCAN_LINES_PER_FRAME);
+ break;
+
+ case 0x0a:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' DMA Burst Count: %u\n", tag(), DMA_BURST_COUNT);
+ logerror("CRT9007 '%s' DMA Burst Delay: %u\n", tag(), DMA_BURST_DELAY);
+ logerror("CRT9007 '%s' DMA Disable: %u\n", tag(), DMA_DISABLE);
+ }
+ break;
+
+ case 0x0b:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' %s Height Cursor\n", tag(), SINGLE_HEIGHT_CURSOR ? "Single" : "Double");
+ logerror("CRT9007 '%s' Operation Mode: %u\n", tag(), OPERATION_MODE);
+ logerror("CRT9007 '%s' Interlace Mode: %u\n", tag(), INTERLACE_MODE);
+ logerror("CRT9007 '%s' %s Mechanism\n", tag(), PAGE_BLANK ? "Page Blank" : "Smooth Scroll");
+ }
+ break;
+
+ case 0x0c:
+ break;
+
+ case 0x0d:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Table Start Register: %04x\n", tag(), TABLE_START);
+ logerror("CRT9007 '%s' Address Mode: %u\n", tag(), ADDRESS_MODE);
+ }
+ break;
+
+ case 0x0e:
+ break;
+
+ case 0x0f:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Auxialiary Address Register 1: %04x\n", tag(), AUXILIARY_ADDRESS_1);
+ logerror("CRT9007 '%s' Row Attributes: %u\n", tag(), ROW_ATTRIBUTES_1);
+ }
+ break;
+
+ case 0x10:
+ if (LOG) logerror("CRT9007 '%s' Sequential Break Register 1: %u\n", tag(), SEQUENTIAL_BREAK_1);
+ break;
+
+ case 0x11:
+ if (LOG) logerror("CRT9007 '%s' Data Row Start Register: %u\n", tag(), DATA_ROW_START);
+ break;
+
+ case 0x12:
+ if (LOG) logerror("CRT9007 '%s' Data Row End/Sequential Break Register 2: %u\n", tag(), SEQUENTIAL_BREAK_2);
+ break;
+
+ case 0x13:
+ break;
+
+ case 0x14:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Auxiliary Address Register 2: %04x\n", tag(), AUXILIARY_ADDRESS_2);
+ logerror("CRT9007 '%s' Row Attributes: %u\n", tag(), ROW_ATTRIBUTES_2);
+ }
+ break;
+
+ case 0x15:
+ if (LOG) logerror("CRT9007 '%s' Start\n", tag());
+ m_disp = 1;
+ break;
+
+ case 0x16:
+ if (LOG) logerror("CRT9007 '%s' Reset\n", tag());
+ device_reset();
+ break;
+
+ case 0x17:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Smooth Scroll Offset: %u\n", tag(), SMOOTH_SCROLL_OFFSET);
+ logerror("CRT9007 '%s' Smooth Scroll Offset Overflow: %u\n", tag(), SMOOTH_SCROLL_OFFSET_OVERFLOW);
+ }
+ break;
+
+ case 0x18:
+ if (LOG) logerror("CRT9007 '%s' Vertical Cursor Register: %u\n", tag(), VERTICAL_CURSOR);
+ break;
+
+ case 0x19:
+ if (LOG) logerror("CRT9007 '%s' Horizontal Cursor Register: %u\n", tag(), HORIZONTAL_CURSOR);
+ break;
+
+ case 0x1a:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Frame Timer: %u\n", tag(), FRAME_TIMER);
+ logerror("CRT9007 '%s' Light Pen Interrupt: %u\n", tag(), LIGHT_PEN_INTERRUPT);
+ logerror("CRT9007 '%s' Vertical Retrace Interrupt: %u\n", tag(), VERTICAL_RETRACE_INTERRUPT);
+ }
+ break;
+
+ default:
+ logerror("CRT9007 '%s' Write to Invalid Register: %02x!\n", tag(), offset);
+ }
+}
+
+
+//-------------------------------------------------
+// ack_w - DMA acknowledge
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9007_device::ack_w )
+{
+ if (LOG) logerror("CRT9007 '%s' ACK: %u\n", tag(), state);
+
+ if (m_dmar && !m_ack && state)
+ {
+ // start DMA transfer
+ m_dma_timer->adjust(attotime::from_hz(clock()));
+ }
+
+ m_ack = state;
+}
+
+
+//-------------------------------------------------
+// lpstb_w - light pen strobe
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9007_device::lpstb_w )
+{
+ if (LOG) logerror("CRT9007 '%s' LPSTB: %u\n", tag(), state);
+
+ if (!m_lpstb && state)
+ {
+ // TODO latch current row/column position
+ }
+
+ m_lpstb = state;
+}
+
+
+//-------------------------------------------------
+// vlt_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( crt9007_device::vlt_r )
+{
+ return m_vlt;
+}
+
+
+//-------------------------------------------------
+// wben_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( crt9007_device::wben_r )
+{
+ return m_wben;
+}
+
+
+//-------------------------------------------------
+// set_hpixels_per_column -
+//-------------------------------------------------
+
+void crt9007_device::set_hpixels_per_column(int hpixels_per_column)
+{
+ m_hpixels_per_column = hpixels_per_column;
+ recompute_parameters();
+}
diff --git a/src/emu/video/crt9007.h b/src/emu/video/crt9007.h
new file mode 100644
index 00000000000..36aefa043cb
--- /dev/null
+++ b/src/emu/video/crt9007.h
@@ -0,0 +1,233 @@
+/**********************************************************************
+
+ SMC CRT9007 CRT Video Processor and Controller (VPAC) emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ VA2 1 |* \_/ | 40 GND
+ VA10 2 | | 39 VA9
+ VA3 3 | | 38 VA1
+ VA11 4 | | 37 VA8
+ VA12 5 | | 36 VA0
+ VA4 6 | | 35 CBLANK
+ VA13 7 | | 34 CURS
+ VA5 8 | | 33 ACK/_TSC
+ VA6 9 | | 32 _CSYNC/LPSTB
+ VA7 10 | CRT9007 | 31 SLD/SL0
+ VLT 11 | | 30 _SLG/SL1
+ _VS 12 | | 29 WBEN/SL2/_CSYNC
+ _HS 13 | | 28 DMAR/SL3/VBLANK
+ _CCLK 14 | | 27 INT
+ _DRB 15 | | 26 _RST
+ VD7 16 | | 25 _CS
+ VD6 17 | | 24 VD0
+ VD5 18 | | 23 VD1
+ VD4 19 | | 22 VD2
+ VD3 20 |_____________| 21 +5V
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __CRT9007__
+#define __CRT9007__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_CRT9007_ADD(_tag, _clock, _config, _map) \
+ MCFG_DEVICE_ADD(_tag, CRT9007, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_ADDRESS_MAP(AS_0, _map)
+
+
+#define CRT9007_INTERFACE(name) \
+ const crt9007_interface (name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// ======================> crt9007_interface
+
+struct crt9007_interface
+{
+ const char *screen_tag; /* screen we are acting on */
+ int hpixels_per_column; /* number of pixels per video memory address */
+
+ devcb_write_line out_int_func;
+ devcb_write_line out_dmar_func;
+
+ devcb_write_line out_vs_func;
+ devcb_write_line out_hs_func;
+
+ devcb_write_line out_vlt_func;
+ devcb_write_line out_curs_func;
+ devcb_write_line out_drb_func;
+ devcb_write_line out_cblank_func;
+
+ devcb_write_line out_slg_func;
+ devcb_write_line out_sld_func;
+};
+
+
+
+// ======================> crt9007_device_config
+
+class crt9007_device_config : public device_config,
+ public device_config_memory_interface,
+ public crt9007_interface
+{
+ friend class crt9007_device;
+
+ // construction/destruction
+ crt9007_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+protected:
+ // device_config overrides
+ virtual void device_config_complete();
+
+ // device_config_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // address space configurations
+ const address_space_config m_space_config;
+};
+
+
+
+// ======================> crt9007_device
+
+class crt9007_device : public device_t,
+ public device_memory_interface
+{
+ friend class crt9007_device_config;
+
+ // construction/destruction
+ crt9007_device(running_machine &_machine, const crt9007_device_config &_config);
+
+public:
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+ DECLARE_WRITE_LINE_MEMBER( ack_w );
+ DECLARE_WRITE_LINE_MEMBER( lpstb_w );
+ DECLARE_READ_LINE_MEMBER( vlt_r );
+ DECLARE_READ_LINE_MEMBER( wben_r );
+
+ void set_hpixels_per_column(int hpixels_per_column);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_clock_changed();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ static const device_timer_id TIMER_HSYNC = 0;
+ static const device_timer_id TIMER_VSYNC = 1;
+ static const device_timer_id TIMER_VLT = 2;
+ static const device_timer_id TIMER_CURS = 3;
+ static const device_timer_id TIMER_DRB = 4;
+ static const device_timer_id TIMER_DMA = 5;
+
+ inline UINT8 readbyte(offs_t address);
+
+ inline void trigger_interrupt(int line);
+ inline void update_cblank_line();
+ inline void update_hsync_timer(int state);
+ inline void update_vsync_timer(int state);
+ inline void update_vlt_timer(int state);
+ inline void update_curs_timer(int state);
+ inline void update_drb_timer(int state);
+ inline void update_dma_timer();
+
+ inline void recompute_parameters();
+
+ devcb_resolved_write_line m_out_int_func;
+ devcb_resolved_write_line m_out_dmar_func;
+ devcb_resolved_write_line m_out_hs_func;
+ devcb_resolved_write_line m_out_vs_func;
+ devcb_resolved_write_line m_out_vlt_func;
+ devcb_resolved_write_line m_out_curs_func;
+ devcb_resolved_write_line m_out_drb_func;
+ devcb_resolved_write_line m_out_cblank_func;
+ devcb_resolved_write_line m_out_slg_func;
+ devcb_resolved_write_line m_out_sld_func;
+
+ screen_device *m_screen;
+
+ // registers
+ UINT8 m_reg[0x3d];
+ UINT8 m_status;
+
+ int m_disp;
+ int m_hpixels_per_column;
+
+ // runtime variables, do not state save
+ int m_vsync_start;
+ int m_vsync_end;
+ int m_hsync_start;
+ int m_hsync_end;
+ int m_vlt_start;
+ int m_vlt_end;
+ int m_vlt_bottom;
+ int m_drb_bottom;
+ int m_hs;
+ int m_vs;
+ int m_cblank;
+ int m_vlt;
+ int m_drb;
+ int m_wben;
+ int m_slg;
+ int m_sld;
+ int m_lpstb;
+
+ // DMA
+ int m_dmar;
+ int m_ack;
+ int m_dma_count;
+ int m_dma_burst;
+ int m_dma_delay;
+
+ // timers
+ emu_timer *m_vsync_timer;
+ emu_timer *m_hsync_timer;
+ emu_timer *m_vlt_timer;
+ emu_timer *m_curs_timer;
+ emu_timer *m_drb_timer;
+ emu_timer *m_dma_timer;
+
+ const crt9007_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type CRT9007;
+
+
+
+#endif
diff --git a/src/emu/video/crt9021.c b/src/emu/video/crt9021.c
new file mode 100644
index 00000000000..13844f4808f
--- /dev/null
+++ b/src/emu/video/crt9021.c
@@ -0,0 +1,269 @@
+/**********************************************************************
+
+ SMC CRT9021 Video Attributes Controller (VAC) emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - attributes
+ - reverse video
+ - character blank
+ - character blink
+ - underline
+ - full/half intensity
+ - operation modes
+ - wide graphics
+ - thin graphics
+ - character mode w/o underline
+ - character mode w/underline
+ - double height characters
+ - double width characters
+ - parallel scan line
+ - serial scan line
+ - cursor
+ - underline
+ - blinking underline
+ - reverse video
+ - blinking reverse video
+ - programmable character blink rate (75/25 duty)
+ - programmable cursor blink rate (50/50 duty)
+ - data/attribute latches
+
+*/
+
+#include "emu.h"
+#include "crt9021.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 1
+
+
+// attributes
+enum
+{
+ ATTRIBUTE_REVID = 0x80,
+ ATTRIBUTE_INT = 0x40,
+ ATTRIBUTE_BLINK = 0x20,
+ ATTRIBUTE_MS1 = 0x10,
+ ATTRIBUTE_MS0 = 0x08,
+ ATTRIBUTE_CHABL = 0x04,
+ ATTRIBUTE_BKC = 0x02,
+ ATTRIBUTE_BLC = 0x01
+};
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type CRT9021 = crt9021_device_config::static_alloc_device_config;
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// crt9021_device_config - constructor
+//-------------------------------------------------
+
+crt9021_device_config::crt9021_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+ : device_config(mconfig, static_alloc_device_config, "SMC CRT9021", tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// static_alloc_device_config - allocate a new
+// configuration object
+//-------------------------------------------------
+
+device_config *crt9021_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+{
+ return global_alloc(crt9021_device_config(mconfig, tag, owner, clock));
+}
+
+
+//-------------------------------------------------
+// alloc_device - allocate a new device object
+//-------------------------------------------------
+
+device_t *crt9021_device_config::alloc_device(running_machine &machine) const
+{
+ return auto_alloc(&machine, crt9021_device(machine, *this));
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void crt9021_device_config::device_config_complete()
+{
+ // inherit a copy of the static data
+ const crt9021_interface *intf = reinterpret_cast<const crt9021_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<crt9021_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&in_data_func, 0, sizeof(in_data_func));
+ memset(&in_attr_func, 0, sizeof(in_attr_func));
+ memset(&in_atten_func, 0, sizeof(in_atten_func));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// crt9021_device - constructor
+//-------------------------------------------------
+
+crt9021_device::crt9021_device(running_machine &_machine, const crt9021_device_config &config)
+ : device_t(_machine, config),
+ m_config(config)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void crt9021_device::device_start()
+{
+ // allocate timers
+
+ // resolve callbacks
+ devcb_resolve_read8(&m_in_data_func, &m_config.in_data_func, this);
+ devcb_resolve_read8(&m_in_attr_func, &m_config.in_attr_func, this);
+ devcb_resolve_read_line(&m_in_atten_func, &m_config.in_atten_func, this);
+
+ // get the screen device
+ m_screen = machine->device<screen_device>(m_config.screen_tag);
+ assert(m_screen != NULL);
+
+ // register for state saving
+ save_item(NAME(m_slg));
+ save_item(NAME(m_sld));
+ save_item(NAME(m_cursor));
+ save_item(NAME(m_retbl));
+ save_item(NAME(m_vsync));
+}
+
+
+//-------------------------------------------------
+// device_clock_changed - handle clock change
+//-------------------------------------------------
+
+void crt9021_device::device_clock_changed()
+{
+}
+
+
+//-------------------------------------------------
+// device_timer - handle timer events
+//-------------------------------------------------
+
+void crt9021_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+}
+
+
+//-------------------------------------------------
+// slg_w - scan line gate
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9021_device::slg_w )
+{
+ if (LOG) logerror("CRT9021 '%s' SLG: %u\n", tag(), state);
+
+ m_slg = state;
+}
+
+
+//-------------------------------------------------
+// sld_w - scan line data
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9021_device::sld_w )
+{
+ if (LOG) logerror("CRT9021 '%s' SLG: %u\n", tag(), state);
+
+ if (!m_slg)
+ {
+ m_sld <<= 1;
+ m_sld |= state;
+ }
+}
+
+
+//-------------------------------------------------
+// cursor_w - cursor
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9021_device::cursor_w )
+{
+ if (LOG) logerror("CRT9021 '%s' CURSOR: %u\n", tag(), state);
+
+ m_cursor = state;
+}
+
+
+//-------------------------------------------------
+// retbl_w - retrace blank
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9021_device::retbl_w )
+{
+ if (LOG) logerror("CRT9021 '%s' RETBL: %u\n", tag(), state);
+
+ m_retbl = state;
+}
+
+
+//-------------------------------------------------
+// vsync_w - vertical sync
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9021_device::vsync_w )
+{
+ if (LOG) logerror("CRT9021 '%s' VSYNC: %u\n", tag(), state);
+
+ m_vsync = state;
+}
+
+
+//-------------------------------------------------
+// update_screen - update screen
+//-------------------------------------------------
+
+void crt9021_device::update_screen(bitmap_t *bitmap, const rectangle *cliprect)
+{
+}
diff --git a/src/emu/video/crt9021.h b/src/emu/video/crt9021.h
new file mode 100644
index 00000000000..20ff301f914
--- /dev/null
+++ b/src/emu/video/crt9021.h
@@ -0,0 +1,144 @@
+/**********************************************************************
+
+ SMC CRT9021 Video Attributes Controller (VAC) emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ D0 1 |* \_/ | 28 D1
+ MS0 2 | | 27 D2
+ MS1 3 | | 26 D3
+ REVID 4 | | 25 D4
+ CHABL 5 | | 24 D5
+ BLINK 6 | | 23 D6
+ INTIN 7 | CRT9021 | 22 D7
+ +5V 8 | | 21 _VSYNC
+ ATTEN 9 | | 20 GND
+ INTOUT 10 | | 19 SL0/SLD
+ CURSOR 11 | | 18 SL1/_SLG
+ RETBL 12 | | 17 SL2/BLC
+ _LD/SH 13 | | 16 SL3/BKC
+ VIDEO 14 |_____________| 15 VDC
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __CRT9021__
+#define __CRT9021__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_CRT9021_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, CRT9021, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define CRT9021_INTERFACE(name) \
+ const crt9021_interface (name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// ======================> crt9021_interface
+
+struct crt9021_interface
+{
+ const char *screen_tag; /* screen we are acting on */
+
+ devcb_read8 in_data_func;
+ devcb_read8 in_attr_func;
+
+ devcb_read_line in_atten_func;
+};
+
+
+
+// ======================> crt9021_device_config
+
+class crt9021_device_config : public device_config,
+ public crt9021_interface
+{
+ friend class crt9021_device;
+
+ // construction/destruction
+ crt9021_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+protected:
+ // device_config overrides
+ virtual void device_config_complete();
+};
+
+
+
+// ======================> crt9021_device
+
+class crt9021_device : public device_t
+{
+ friend class crt9021_device_config;
+
+ // construction/destruction
+ crt9021_device(running_machine &_machine, const crt9021_device_config &_config);
+
+public:
+ DECLARE_WRITE_LINE_MEMBER( slg_w );
+ DECLARE_WRITE_LINE_MEMBER( sld_w );
+ DECLARE_WRITE_LINE_MEMBER( cursor_w );
+ DECLARE_WRITE_LINE_MEMBER( retbl_w );
+ DECLARE_WRITE_LINE_MEMBER( vsync_w );
+
+ void update_screen(bitmap_t *bitmap, const rectangle *cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_clock_changed();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ devcb_resolved_read8 m_in_data_func;
+ devcb_resolved_read8 m_in_attr_func;
+ devcb_resolved_read_line m_in_atten_func;
+
+ screen_device *m_screen;
+
+ int m_slg;
+ int m_sld;
+ int m_cursor;
+ int m_retbl;
+ int m_vsync;
+
+ const crt9021_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type CRT9021;
+
+
+
+#endif
diff --git a/src/emu/video/crt9212.c b/src/emu/video/crt9212.c
new file mode 100644
index 00000000000..0a91fc8948a
--- /dev/null
+++ b/src/emu/video/crt9212.c
@@ -0,0 +1,269 @@
+/**********************************************************************
+
+ SMC CRT9212 Double Row Buffer (DRB) emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "crt9212.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 1
+
+
+#define REN \
+ devcb_call_read_line(&m_in_ren_func)
+
+#define WEN \
+ devcb_call_read_line(&m_in_wen_func)
+
+#define WEN2 \
+ devcb_call_read_line(&m_in_wen2_func)
+
+#define ROF(_state) \
+ devcb_call_write_line(&m_out_rof_func, _state);
+
+#define WOF(_state) \
+ devcb_call_write_line(&m_out_wof_func, _state);
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type CRT9212 = crt9212_device_config::static_alloc_device_config;
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// crt9212_device_config - constructor
+//-------------------------------------------------
+
+crt9212_device_config::crt9212_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+ : device_config(mconfig, static_alloc_device_config, "SMC CRT9212", tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// static_alloc_device_config - allocate a new
+// configuration object
+//-------------------------------------------------
+
+device_config *crt9212_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+{
+ return global_alloc(crt9212_device_config(mconfig, tag, owner, clock));
+}
+
+
+//-------------------------------------------------
+// alloc_device - allocate a new device object
+//-------------------------------------------------
+
+device_t *crt9212_device_config::alloc_device(running_machine &machine) const
+{
+ return auto_alloc(&machine, crt9212_device(machine, *this));
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void crt9212_device_config::device_config_complete()
+{
+ // inherit a copy of the static data
+ const crt9212_interface *intf = reinterpret_cast<const crt9212_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<crt9212_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&out_rof_func, 0, sizeof(out_rof_func));
+ memset(&out_wof_func, 0, sizeof(out_wof_func));
+ memset(&in_ren_func, 0, sizeof(in_ren_func));
+ memset(&in_wen_func, 0, sizeof(in_wen_func));
+ memset(&in_wen2_func, 0, sizeof(in_wen2_func));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// crt9212_device - constructor
+//-------------------------------------------------
+
+crt9212_device::crt9212_device(running_machine &_machine, const crt9212_device_config &config)
+ : device_t(_machine, config),
+ m_config(config)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void crt9212_device::device_start()
+{
+ // resolve callbacks
+ devcb_resolve_write_line(&m_out_rof_func, &m_config.out_rof_func, this);
+ devcb_resolve_write_line(&m_out_wof_func, &m_config.out_wof_func, this);
+ devcb_resolve_read_line(&m_in_ren_func, &m_config.in_ren_func, this);
+ devcb_resolve_read_line(&m_in_wen_func, &m_config.in_wen_func, this);
+ devcb_resolve_read_line(&m_in_wen2_func, &m_config.in_wen2_func, this);
+
+ // register for state saving
+ save_item(NAME(m_input));
+ save_item(NAME(m_output));
+ save_item(NAME(m_buffer));
+ save_item(NAME(m_rac));
+ save_item(NAME(m_wac));
+ save_item(NAME(m_tog));
+ save_item(NAME(m_clrcnt));
+ save_item(NAME(m_rclk));
+ save_item(NAME(m_wclk));
+}
+
+
+//-------------------------------------------------
+// read - buffer read
+//-------------------------------------------------
+
+READ8_MEMBER( crt9212_device::read )
+{
+ return m_output;
+}
+
+
+//-------------------------------------------------
+// write - buffer write
+//-------------------------------------------------
+
+WRITE8_MEMBER( crt9212_device::write )
+{
+ m_input = data;
+}
+
+
+//-------------------------------------------------
+// clrcnt_w - clear address counters
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9212_device::clrcnt_w )
+{
+ m_clrcnt = state;
+}
+
+
+//-------------------------------------------------
+// tog_w - toggle buffer
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9212_device::tog_w )
+{
+ m_tog = state;
+}
+
+
+//-------------------------------------------------
+// rclk_w - read clock
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9212_device::rclk_w )
+{
+ if (m_rclk && !state)
+ {
+ if (!m_clrcnt)
+ {
+ if (!m_tog)
+ {
+ // switch buffer
+ m_buffer = !m_buffer;
+
+ // clear write address counter
+ m_wac = 0;
+ WOF(0);
+ }
+ else
+ {
+ // clear read address counter
+ m_rac = 0;
+ ROF(0);
+ }
+ }
+ else
+ {
+ if (REN && (m_rac < CRT9212_RAM_SIZE))
+ {
+ //
+ m_output = m_ram[m_rac][!m_buffer];
+
+ // increment read address counter
+ m_rac++;
+
+ if (m_rac == CRT9212_RAM_SIZE)
+ {
+ // set read overflow
+ ROF(1);
+ }
+ }
+ }
+ }
+
+ m_rclk = state;
+}
+
+
+//-------------------------------------------------
+// wclk_w - write clock
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9212_device::wclk_w )
+{
+ if (!m_rclk && state)
+ {
+ if (WEN && WEN2 && (m_wac < CRT9212_RAM_SIZE))
+ {
+ //
+ m_ram[m_rac][m_buffer] = m_input;
+
+ // increment read address counter
+ m_wac++;
+
+ if (m_wac == CRT9212_RAM_SIZE)
+ {
+ // set write overflow
+ WOF(1);
+ }
+ }
+ }
+
+ m_wclk = state;
+}
diff --git a/src/emu/video/crt9212.h b/src/emu/video/crt9212.h
new file mode 100644
index 00000000000..e89432176ae
--- /dev/null
+++ b/src/emu/video/crt9212.h
@@ -0,0 +1,148 @@
+/**********************************************************************
+
+ SMC CRT9212 Double Row Buffer (DRB) emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ DIN2 1 |* \_/ | 28 DIN3
+ DIN1 2 | | 27 _WCLK
+ DIN0 3 | | 26 _OE
+ DOUT7 4 | | 25 WEN2
+ DOUT6 5 | | 24 WEN1
+ DOUT5 6 | | 23 GND
+ DOUT4 7 | CRT9212 | 22 ROF
+ Vcc 8 | | 21 WOF
+ DOUT3 9 | | 20 REN
+ DOUT2 10 | | 19 _CLRCNT
+ DOUT1 11 | | 18 _TOG
+ DOUT0 12 | | 17 _RCLK
+ DIN7 13 | | 16 DIN4
+ DIN6 14 |_____________| 15 DIN5
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __CRT9212__
+#define __CRT9212__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+const int CRT9212_RAM_SIZE = 135;
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_CRT9212_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, CRT9212, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define CRT9212_INTERFACE(name) \
+ const crt9212_interface (name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// ======================> crt9212_interface
+
+struct crt9212_interface
+{
+ devcb_write_line out_rof_func;
+ devcb_write_line out_wof_func;
+ devcb_read_line in_ren_func;
+ devcb_read_line in_wen_func;
+ devcb_read_line in_wen2_func;
+};
+
+
+
+// ======================> crt9212_device_config
+
+class crt9212_device_config : public device_config,
+ public crt9212_interface
+{
+ friend class crt9212_device;
+
+ // construction/destruction
+ crt9212_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+protected:
+ // device_config overrides
+ virtual void device_config_complete();
+};
+
+
+
+// ======================> crt9212_device
+
+class crt9212_device : public device_t
+{
+ friend class crt9212_device_config;
+
+ // construction/destruction
+ crt9212_device(running_machine &_machine, const crt9212_device_config &_config);
+
+public:
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+ DECLARE_WRITE_LINE_MEMBER( clrcnt_w );
+ DECLARE_WRITE_LINE_MEMBER( tog_w );
+ DECLARE_WRITE_LINE_MEMBER( rclk_w );
+ DECLARE_WRITE_LINE_MEMBER( wclk_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+private:
+ devcb_resolved_write_line m_out_rof_func;
+ devcb_resolved_write_line m_out_wof_func;
+ devcb_resolved_read_line m_in_ren_func;
+ devcb_resolved_read_line m_in_wen_func;
+ devcb_resolved_read_line m_in_wen2_func;
+
+ UINT8 m_ram[CRT9212_RAM_SIZE][2];
+
+ UINT8 m_input;
+ UINT8 m_output;
+
+ int m_buffer;
+ int m_rac;
+ int m_wac;
+ int m_tog;
+ int m_clrcnt;
+ int m_rclk;
+ int m_wclk;
+
+ const crt9212_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type CRT9212;
+
+
+
+#endif
diff --git a/src/emu/video/hd61830.c b/src/emu/video/hd61830.c
new file mode 100644
index 00000000000..6fceb8014cb
--- /dev/null
+++ b/src/emu/video/hd61830.c
@@ -0,0 +1,600 @@
+/**********************************************************************
+
+ HD61830 LCD Timing Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "hd61830.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+enum
+{
+ INSTRUCTION_MODE_CONTROL = 0,
+ INSTRUCTION_CHARACTER_PITCH,
+ INSTRUCTION_NUMBER_OF_CHARACTERS,
+ INSTRUCTION_NUMBER_OF_TIME_DIVISIONS,
+ INSTRUCTION_CURSOR_POSITION,
+ INSTRUCTION_DISPLAY_START_LOW = 8,
+ INSTRUCTION_DISPLAY_START_HIGH,
+ INSTRUCTION_CURSOR_ADDRESS_LOW,
+ INSTRUCTION_CURSOR_ADDRESS_HIGH,
+ INSTRUCTION_DISPLAY_DATA_WRITE,
+ INSTRUCTION_DISPLAY_DATA_READ,
+ INSTRUCTION_CLEAR_BIT,
+ INSTRUCTION_SET_BIT
+};
+
+static const int CYCLES[] =
+{
+ 4, 4, 4, 4, 4, -1, -1, -1, 4, 4, 4, 4, 6, 6, 36, 36
+};
+
+const int MODE_EXTERNAL_CG = 0x01;
+const int MODE_GRAPHIC = 0x02;
+const int MODE_CURSOR = 0x04;
+const int MODE_BLINK = 0x08;
+const int MODE_MASTER = 0x10;
+const int MODE_DISPLAY_ON = 0x20;
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type HD61830 = hd61830_device_config::static_alloc_device_config;
+
+
+// default address map
+static ADDRESS_MAP_START( hd61830, AS_0, 8 )
+ AM_RANGE(0x0000, 0xffff) AM_RAM
+ADDRESS_MAP_END
+
+
+// internal character generator ROM
+ROM_START( hd61830 )
+ ROM_REGION( 0x5c0, "hd61830", ROMREGION_LOADBYNAME ) // internal 7360-bit chargen ROM
+ ROM_LOAD( "hd61830.bin", 0x000, 0x5c0, BAD_DUMP CRC(06a934da) SHA1(bf3f074db5dc92e6f530cb18d6c013563099a87d) ) // typed in from manual
+ROM_END
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// hd61830_device_config - constructor
+//-------------------------------------------------
+
+hd61830_device_config::hd61830_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+ : device_config(mconfig, static_alloc_device_config, "Hitachi HD61830", tag, owner, clock),
+ device_config_memory_interface(mconfig, *this),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(hd61830))
+{
+ m_shortname = "hd61830";
+}
+
+
+//-------------------------------------------------
+// static_alloc_device_config - allocate a new
+// configuration object
+//-------------------------------------------------
+
+device_config *hd61830_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+{
+ return global_alloc(hd61830_device_config(mconfig, tag, owner, clock));
+}
+
+
+//-------------------------------------------------
+// alloc_device - allocate a new device object
+//-------------------------------------------------
+
+device_t *hd61830_device_config::alloc_device(running_machine &machine) const
+{
+ return auto_alloc(&machine, hd61830_device(machine, *this));
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *hd61830_device_config::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *hd61830_device_config::rom_region() const
+{
+ return ROM_NAME(hd61830);
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void hd61830_device_config::device_config_complete()
+{
+ // inherit a copy of the static data
+ const hd61830_interface *intf = reinterpret_cast<const hd61830_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<hd61830_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_in_rd_func, 0, sizeof(m_in_rd_func));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// readbyte - read a byte at the given address
+//-------------------------------------------------
+
+inline UINT8 hd61830_device::readbyte(offs_t address)
+{
+ return space()->read_byte(address);
+}
+
+
+//-------------------------------------------------
+// writebyte - write a byte at the given address
+//-------------------------------------------------
+
+inline void hd61830_device::writebyte(offs_t address, UINT8 data)
+{
+ space()->write_byte(address, data);
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// hd61830_device - constructor
+//-------------------------------------------------
+
+hd61830_device::hd61830_device(running_machine &_machine, const hd61830_device_config &config)
+ : device_t(_machine, config),
+ device_memory_interface(_machine, config, *this),
+ m_bf(false),
+ m_blink(0),
+ m_config(config)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void hd61830_device::device_start()
+{
+ // allocate timers
+ m_busy_timer = timer_alloc();
+
+ // resolve callbacks
+ devcb_resolve_read8(&m_in_rd_func, &m_config.m_in_rd_func, this);
+
+ m_screen = machine->device<screen_device>(m_config.screen_tag);
+
+ // register for state saving
+ save_item(NAME(m_bf));
+ save_item(NAME(m_ir));
+ save_item(NAME(m_mcr));
+ save_item(NAME(m_dor));
+ save_item(NAME(m_cac));
+ save_item(NAME(m_dsa));
+ save_item(NAME(m_vp));
+ save_item(NAME(m_hp));
+ save_item(NAME(m_hn));
+ save_item(NAME(m_nx));
+ save_item(NAME(m_cp));
+ save_item(NAME(m_blink));
+ save_item(NAME(m_cursor));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void hd61830_device::device_reset()
+{
+ // display off, slave mode
+ m_mcr &= ~(MODE_MASTER | MODE_DISPLAY_ON);
+
+ // default horizontal pitch
+ m_hp = 6;
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void hd61830_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ // clear busy flag
+ m_bf = false;
+}
+
+
+/*-------------------------------------------------
+ set_busy_flag - set busy flag and arm timer
+ to clear it later
+-------------------------------------------------*/
+
+void hd61830_device::set_busy_flag()
+{
+ // set busy flag
+ m_bf = true;
+
+ // adjust busy timer
+ m_busy_timer->adjust(attotime::from_usec(CYCLES[m_ir]));
+}
+
+
+//-------------------------------------------------
+// status_r - status register read
+//-------------------------------------------------
+
+READ8_MEMBER( hd61830_device::status_r )
+{
+ if (LOG) logerror("HD61830 '%s' Status Read: %s\n", tag(), m_bf ? "busy" : "ready");
+
+ return m_bf ? 0x80 : 0;
+}
+
+
+//-------------------------------------------------
+// control_w - instruction register write
+//-------------------------------------------------
+
+WRITE8_MEMBER( hd61830_device::control_w )
+{
+ m_ir = data;
+}
+
+
+//-------------------------------------------------
+// data_r - data register read
+//-------------------------------------------------
+
+READ8_MEMBER( hd61830_device::data_r )
+{
+ UINT8 data = m_dor;
+
+ if (LOG) logerror("HD61830 '%s' Display Data Read %02x\n", tag(), m_dor);
+
+ m_dor = readbyte(m_cac);
+
+ m_cac++;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// data_w - data register write
+//-------------------------------------------------
+
+WRITE8_MEMBER( hd61830_device::data_w )
+{
+ if (m_bf)
+ {
+ logerror("HD61830 '%s' Ignoring data write %02x due to business\n", tag(), data);
+ return;
+ }
+
+ switch (m_ir)
+ {
+ case INSTRUCTION_MODE_CONTROL:
+ m_mcr = data;
+
+ if (LOG)
+ {
+ logerror("HD61830 '%s' %s CG\n", tag(), (data & MODE_EXTERNAL_CG) ? "External" : "Internal");
+ logerror("HD61830 '%s' %s Display Mode\n", tag(), (data & MODE_GRAPHIC) ? "Graphic" : "Character");
+ logerror("HD61830 '%s' %s Mode\n", tag(), (data & MODE_MASTER) ? "Master" : "Slave");
+ logerror("HD61830 '%s' Cursor %s\n", tag(), (data & MODE_CURSOR) ? "On" : "Off");
+ logerror("HD61830 '%s' Blink %s\n", tag(), (data & MODE_BLINK) ? "On" : "Off");
+ logerror("HD61830 '%s' Display %s\n", tag(), (data & MODE_DISPLAY_ON) ? "On" : "Off");
+ }
+ break;
+
+ case INSTRUCTION_CHARACTER_PITCH:
+ m_hp = (data & 0x07) + 1;
+ m_vp = (data >> 4) + 1;
+
+ if (LOG) logerror("HD61830 '%s' Horizontal Character Pitch: %u\n", tag(), m_hp);
+ if (LOG) logerror("HD61830 '%s' Vertical Character Pitch: %u\n", tag(), m_vp);
+ break;
+
+ case INSTRUCTION_NUMBER_OF_CHARACTERS:
+ m_hn = (data & 0x7f) + 1;
+
+ if (LOG) logerror("HD61830 '%s' Number of Characters: %u\n", tag(), m_hn);
+ break;
+
+ case INSTRUCTION_NUMBER_OF_TIME_DIVISIONS:
+ m_nx = (data & 0x7f) + 1;
+
+ if (LOG) logerror("HD61830 '%s' Number of Time Divisions: %u\n", tag(), m_nx);
+ break;
+
+ case INSTRUCTION_CURSOR_POSITION:
+ m_cp = (data & 0x7f) + 1;
+
+ if (LOG) logerror("HD61830 '%s' Cursor Position: %u\n", tag(), m_cp);
+ break;
+
+ case INSTRUCTION_DISPLAY_START_LOW:
+ m_dsa = (m_dsa & 0xff00) | data;
+
+ if (LOG) logerror("HD61830 '%s' Display Start Address Low %04x\n", tag(), m_dsa);
+ break;
+
+ case INSTRUCTION_DISPLAY_START_HIGH:
+ m_dsa = (data << 8) | (m_dsa & 0xff);
+
+ if (LOG) logerror("HD61830 '%s' Display Start Address High %04x\n", tag(), m_dsa);
+ break;
+
+ case INSTRUCTION_CURSOR_ADDRESS_LOW:
+ if (BIT(m_cac, 7) && !BIT(data, 7))
+ {
+ m_cac = (((m_cac >> 8) + 1) << 8) | data;
+ }
+ else
+ {
+ m_cac = (m_cac & 0xff00) | data;
+ }
+
+ if (LOG) logerror("HD61830 '%s' Cursor Address Low %02x: %04x\n", tag(), data, m_cac);
+ break;
+
+ case INSTRUCTION_CURSOR_ADDRESS_HIGH:
+ m_cac = (data << 8) | (m_cac & 0xff);
+
+ if (LOG) logerror("HD61830 '%s' Cursor Address High %02x: %04x\n", tag(), data, m_cac);
+ break;
+
+ case INSTRUCTION_DISPLAY_DATA_WRITE:
+ writebyte(m_cac, data);
+
+ if (LOG) logerror("HD61830 '%s' Display Data Write %02x -> %04x row %u col %u\n", tag(), data, m_cac, m_cac / 40, m_cac % 40);
+
+ m_cac++;
+ break;
+
+ case INSTRUCTION_CLEAR_BIT:
+ {
+ int bit = data & 0x07;
+ UINT8 md = readbyte(m_cac);
+
+ md &= ~(1 << bit);
+
+ if (LOG) logerror("HD61830 '%s' Clear Bit %u at %04x\n", tag(), bit + 1, m_cac);
+
+ writebyte(m_cac, md);
+
+ m_cac++;
+ }
+ break;
+
+ case INSTRUCTION_SET_BIT:
+ {
+ int bit = data & 0x07;
+ UINT8 md = readbyte(m_cac);
+
+ md |= 1 << bit;
+
+ if (LOG) logerror("HD61830 '%s' Set Bit %u at %04x\n", tag(), bit + 1, m_cac);
+
+ writebyte(m_cac, md);
+
+ m_cac++;
+ }
+ break;
+
+ default:
+ logerror("HD61830 '%s' Illegal Instruction %02x!\n", tag(), m_ir);
+ return;
+ }
+
+ // burn cycles
+ set_busy_flag();
+}
+
+
+//-------------------------------------------------
+// draw_scanline - draw one graphics scanline
+//-------------------------------------------------
+
+void hd61830_device::draw_scanline(bitmap_t *bitmap, const rectangle *cliprect, int y, UINT16 ra)
+{
+ for (int sx = 0; sx < m_hn; sx++)
+ {
+ UINT8 data = readbyte(ra++);
+
+ for (int x = 0; x < m_hp; x++)
+ {
+ *BITMAP_ADDR16(bitmap, y, (sx * m_hp) + x) = BIT(data, x);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// update_graphics - draw graphics mode screen
+//-------------------------------------------------
+
+void hd61830_device::update_graphics(bitmap_t *bitmap, const rectangle *cliprect)
+{
+ for (int y = 0; y < m_nx; y++)
+ {
+ UINT16 rac1 = m_dsa + (y * m_hn);
+ UINT16 rac2 = rac1 + (m_nx * m_hn);
+
+ /* draw upper half scanline */
+ draw_scanline(bitmap, cliprect, y, rac1);
+
+ /* draw lower half scanline */
+ draw_scanline(bitmap, cliprect, y + m_nx, rac2);
+ }
+}
+
+
+//-------------------------------------------------
+// draw_char - draw a char
+//-------------------------------------------------
+
+void hd61830_device::draw_char(bitmap_t *bitmap, const rectangle *cliprect, UINT16 ma, int x, int y, UINT8 md)
+{
+ for (int cl = 0; cl < m_vp; cl++)
+ {
+ for (int cr = 0; cr < m_hp; cr++)
+ {
+ int sy = y * m_vp + cl;
+ int sx = x * m_hp + cr;
+ UINT8 data = 0;
+
+ if (m_mcr & MODE_EXTERNAL_CG)
+ {
+ data = devcb_call_read8(&m_in_rd_func, (cl << 12) | md);
+ }
+ else
+ {
+ UINT16 addr = 0;
+
+ if (md >= 0x20 && md < 0x80 && cl < 7)
+ {
+ // 5x7 characters 0x20..0x7f
+ addr = (md - 0x20) * 7 + cl;
+ }
+ else if (md >= 0xa0 && md < 0xe0 && cl < 7)
+ {
+ // 5x7 characters 0xa0..0xdf
+ addr = 96*7 + (md - 0xa0) * 7 + cl;
+ }
+ else if (md >= 0xe0 && cl < 11)
+ {
+ // 5x11 characters 0xe0..0xff
+ addr = 160*7 + (md - 0xe0) * 11 + cl;
+ }
+
+ data = subregion("hd61830")->u8(addr);
+ }
+
+ int cursor = m_mcr & MODE_CURSOR;
+ int blink = m_mcr & MODE_BLINK;
+
+ // cursor off
+ int pixel = BIT(data, cr);
+
+ if (blink && (ma == m_cac))
+ {
+ // cursor off, character blink
+ if (!cursor)
+ pixel = m_cursor ? pixel : 0;
+
+ // cursor blink
+ if (cursor && (cl == m_cp))
+ pixel = m_cursor ? 1 : 0;
+ }
+ else
+ {
+ // cursor on
+ if (cursor && (cl == m_cp))
+ pixel = m_cursor ? 1 : 0;
+ }
+
+ if (sy < m_screen->height() && sx < m_screen->width())
+ *BITMAP_ADDR16(bitmap, sy, sx) = pixel;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// update_text - draw text mode screen
+//-------------------------------------------------
+
+void hd61830_device::update_text(bitmap_t *bitmap, const rectangle *cliprect)
+{
+ for (int y = 0; y < (m_nx / m_vp); y++)
+ {
+ for (int x = 0; x < m_hn; x++)
+ {
+ UINT16 ma = y * m_hn + x;
+ UINT8 md = readbyte(ma);
+
+ draw_char(bitmap, cliprect, ma, x, y, md);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// update_screen - update screen
+//-------------------------------------------------
+
+void hd61830_device::update_screen(bitmap_t *bitmap, const rectangle *cliprect)
+{
+ if (m_mcr & MODE_DISPLAY_ON)
+ {
+ if (m_mcr & MODE_GRAPHIC)
+ {
+ update_graphics(bitmap, cliprect);
+ }
+ else
+ {
+ update_text(bitmap, cliprect);
+ }
+ }
+ else
+ {
+ bitmap_fill(bitmap, cliprect, 0);
+ }
+
+ m_blink++;
+
+ if (m_blink == 0x20)
+ {
+ m_blink = 0;
+ m_cursor = !m_cursor;
+ }
+}
diff --git a/src/emu/video/hd61830.h b/src/emu/video/hd61830.h
new file mode 100644
index 00000000000..12c793af5b1
--- /dev/null
+++ b/src/emu/video/hd61830.h
@@ -0,0 +1,156 @@
+/**********************************************************************
+
+ HD61830 LCD Timing Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __HD61830__
+#define __HD61830__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_HD61830_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, HD61830, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define HD61830_INTERFACE(name) \
+ const hd61830_interface (name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> hd61830_interface
+
+struct hd61830_interface
+{
+ const char *screen_tag;
+
+ devcb_read8 m_in_rd_func;
+};
+
+
+
+// ======================> hd61830_device_config
+
+class hd61830_device_config : public device_config,
+ public device_config_memory_interface,
+ public hd61830_interface
+{
+ friend class hd61830_device;
+
+ // construction/destruction
+ hd61830_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+
+public:
+ // allocators
+ static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
+ virtual device_t *alloc_device(running_machine &machine) const;
+
+ // optional information overrides
+ virtual const rom_entry *rom_region() const;
+
+protected:
+ // device_config overrides
+ virtual void device_config_complete();
+
+ // device_config_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+ // address space configurations
+ const address_space_config m_space_config;
+};
+
+
+
+// ======================> hd61830_device
+
+class hd61830_device : public device_t,
+ public device_memory_interface
+{
+ friend class hd61830_device_config;
+
+ // construction/destruction
+ hd61830_device(running_machine &_machine, const hd61830_device_config &_config);
+
+public:
+ DECLARE_READ8_MEMBER( status_r );
+ DECLARE_WRITE8_MEMBER( control_w );
+
+ DECLARE_READ8_MEMBER( data_r );
+ DECLARE_WRITE8_MEMBER( data_w );
+
+ void update_screen(bitmap_t *bitmap, const rectangle *cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ inline UINT8 readbyte(offs_t address);
+ inline void writebyte(offs_t address, UINT8 data);
+
+private:
+ void set_busy_flag();
+
+ void draw_scanline(bitmap_t *bitmap, const rectangle *cliprect, int y, UINT16 ra);
+ void update_graphics(bitmap_t *bitmap, const rectangle *cliprect);
+ void draw_char(bitmap_t *bitmap, const rectangle *cliprect, UINT16 ma, int x, int y, UINT8 md);
+ void update_text(bitmap_t *bitmap, const rectangle *cliprect);
+
+ devcb_resolved_read8 m_in_rd_func;
+
+ screen_device *m_screen;
+ emu_timer *m_busy_timer;
+ address_space *m_data;
+
+ bool m_bf; // busy flag
+
+ UINT8 m_ir; // instruction register
+ UINT8 m_mcr; // mode control register
+ UINT8 m_dor; // data output register
+
+ UINT16 m_dsa; // display start address
+ UINT16 m_cac; // cursor address counter
+
+ int m_vp; // vertical character pitch
+ int m_hp; // horizontal character pitch
+ int m_hn; // horizontal number of characters
+ int m_nx; // number of time divisions
+ int m_cp; // cursor position
+
+ int m_blink; // blink counter
+ int m_cursor; // cursor visible
+
+ const hd61830_device_config &m_config;
+};
+
+
+// device type definition
+extern const device_type HD61830;
+
+
+
+#endif