summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/machine
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/machine')
-rw-r--r--src/emu/machine/74145.c176
-rw-r--r--src/emu/machine/74145.h83
-rw-r--r--src/emu/machine/at29040a.c444
-rw-r--r--src/emu/machine/at29040a.h88
-rw-r--r--src/emu/machine/at45dbxx.c375
-rw-r--r--src/emu/machine/at45dbxx.h144
-rw-r--r--src/emu/machine/ay31015.c760
-rw-r--r--src/emu/machine/ay31015.h126
-rw-r--r--src/emu/machine/er59256.c259
-rw-r--r--src/emu/machine/er59256.h112
-rw-r--r--src/emu/machine/mc68328.c2872
-rw-r--r--src/emu/machine/mc68328.h568
-rw-r--r--src/emu/machine/mc6843.c863
-rw-r--r--src/emu/machine/mc6843.h59
-rw-r--r--src/emu/machine/mc6846.c671
-rw-r--r--src/emu/machine/mc6846.h82
-rw-r--r--src/emu/machine/mc6854.c1072
-rw-r--r--src/emu/machine/mc6854.h100
-rw-r--r--src/emu/machine/mm58274c.c552
-rw-r--r--src/emu/machine/mm58274c.h56
-rw-r--r--src/emu/machine/mos6530.c469
-rw-r--r--src/emu/machine/mos6530.h97
-rw-r--r--src/emu/machine/pcf8593.c283
-rw-r--r--src/emu/machine/pcf8593.h77
-rw-r--r--src/emu/machine/upd7002.c245
-rw-r--r--src/emu/machine/upd7002.h76
-rw-r--r--src/emu/machine/wd11c00_17.c496
-rw-r--r--src/emu/machine/wd11c00_17.h128
-rw-r--r--src/emu/machine/wd2010.c426
-rw-r--r--src/emu/machine/wd2010.h109
30 files changed, 11868 insertions, 0 deletions
diff --git a/src/emu/machine/74145.c b/src/emu/machine/74145.c
new file mode 100644
index 00000000000..eb3457a7cd8
--- /dev/null
+++ b/src/emu/machine/74145.c
@@ -0,0 +1,176 @@
+/*****************************************************************************
+ *
+ * machine/74145.c
+ *
+ * BCD-to-Decimal decoder
+ *
+ * __ __
+ * 0-| v |-VCC
+ * 1-| |-A
+ * 2-| |-B
+ * 3-| |-C
+ * 4-| |-D
+ * 5-| |-9
+ * 6-| |-8
+ * GND-|_____|-7
+ *
+ *
+ * Truth table
+ * _______________________________
+ * | Inputs | Outputs |
+ * | D C B A | 0 1 2 3 4 5 6 7 8 9 |
+ * |-------------------------------|
+ * | L L L L | L H H H H H H H H H |
+ * | L L L H | H L H H H H H H H H |
+ * | L L H L | H H L H H H H H H H |
+ * | L L H H | H H H L H H H H H H |
+ * | L H L L | H H H H L H H H H H |
+ * |-------------------------------|
+ * | L H L H | H H H H H L H H H H |
+ * | L H H L | H H H H H H L H H H |
+ * | L H H H | H H H H H H H L H H |
+ * | H L L L | H H H H H H H H L H |
+ * | H L L H | H H H H H H H H H L |
+ * |-------------------------------|
+ * | H L H L | H H H H H H H H H H |
+ * | H L H H | H H H H H H H H H H |
+ * | H H L L | H H H H H H H H H H |
+ * | H H L H | H H H H H H H H H H |
+ * | H H H L | H H H H H H H H H H |
+ * | H H H H | H H H H H H H H H H |
+ * -------------------------------
+ *
+ ****************************************************************************/
+
+#include "emu.h"
+#include "74145.h"
+#include "coreutil.h"
+
+/*****************************************************************************
+ GLOBAL VARIABLES
+*****************************************************************************/
+
+const ttl74145_interface default_ttl74145 =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+const device_type TTL74145 = &device_creator<ttl74145_device>;
+
+/***************************************************************************
+ DEVICE INTERFACE
+***************************************************************************/
+//-------------------------------------------------
+// ttl74145_device - constructor
+//-------------------------------------------------
+
+ttl74145_device::ttl74145_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, TTL74145, "TTL74145", tag, owner, clock)
+ , m_number(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ttl74145_device::device_start()
+{
+ /* resolve callbacks */
+ m_output_line_0_func.resolve(m_output_line_0_cb, *this);
+ m_output_line_1_func.resolve(m_output_line_1_cb, *this);
+ m_output_line_2_func.resolve(m_output_line_2_cb, *this);
+ m_output_line_3_func.resolve(m_output_line_3_cb, *this);
+ m_output_line_4_func.resolve(m_output_line_4_cb, *this);
+ m_output_line_5_func.resolve(m_output_line_5_cb, *this);
+ m_output_line_6_func.resolve(m_output_line_6_cb, *this);
+ m_output_line_7_func.resolve(m_output_line_7_cb, *this);
+ m_output_line_8_func.resolve(m_output_line_8_cb, *this);
+ m_output_line_9_func.resolve(m_output_line_9_cb, *this);
+
+ // register for state saving
+ save_item(NAME(m_number));
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void ttl74145_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const ttl74145_interface *intf = reinterpret_cast<const ttl74145_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<ttl74145_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_output_line_0_cb, 0, sizeof(m_output_line_0_cb));
+ memset(&m_output_line_1_cb, 0, sizeof(m_output_line_1_cb));
+ memset(&m_output_line_2_cb, 0, sizeof(m_output_line_2_cb));
+ memset(&m_output_line_3_cb, 0, sizeof(m_output_line_3_cb));
+ memset(&m_output_line_4_cb, 0, sizeof(m_output_line_4_cb));
+ memset(&m_output_line_5_cb, 0, sizeof(m_output_line_5_cb));
+ memset(&m_output_line_6_cb, 0, sizeof(m_output_line_6_cb));
+ memset(&m_output_line_7_cb, 0, sizeof(m_output_line_7_cb));
+ memset(&m_output_line_8_cb, 0, sizeof(m_output_line_8_cb));
+ memset(&m_output_line_9_cb, 0, sizeof(m_output_line_9_cb));
+ }
+}
+
+//-------------------------------------------------
+// device_start - device-specific reset
+//-------------------------------------------------
+
+void ttl74145_device::device_reset()
+{
+ m_number = 0;
+}
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+void ttl74145_device::write(UINT8 data)
+{
+ /* decode number */
+ UINT16 new_number = bcd_2_dec(data & 0x0f);
+
+ /* call output callbacks if the number changed */
+ if (new_number != m_number)
+ {
+ m_output_line_0_func(new_number == 0);
+ m_output_line_1_func(new_number == 1);
+ m_output_line_2_func(new_number == 2);
+ m_output_line_3_func(new_number == 3);
+ m_output_line_4_func(new_number == 4);
+ m_output_line_5_func(new_number == 5);
+ m_output_line_6_func(new_number == 6);
+ m_output_line_7_func(new_number == 7);
+ m_output_line_8_func(new_number == 8);
+ m_output_line_9_func(new_number == 9);
+ }
+
+ /* update state */
+ m_number = new_number;
+}
+
+
+UINT16 ttl74145_device::read()
+{
+ return (1 << m_number) & 0x3ff;
+}
diff --git a/src/emu/machine/74145.h b/src/emu/machine/74145.h
new file mode 100644
index 00000000000..71cfa9ba2ac
--- /dev/null
+++ b/src/emu/machine/74145.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+
+ TTL74145
+
+ BCD-to-Decimal decoder
+
+***************************************************************************/
+
+#ifndef __TTL74145_H__
+#define __TTL74145_H__
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+#define MCFG_TTL74145_ADD(_tag, _intf) \
+ MCFG_DEVICE_ADD(_tag, TTL74145, 0) \
+ MCFG_DEVICE_CONFIG(_intf)
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> ttl74145_interface
+
+struct ttl74145_interface
+{
+ devcb_write_line m_output_line_0_cb;
+ devcb_write_line m_output_line_1_cb;
+ devcb_write_line m_output_line_2_cb;
+ devcb_write_line m_output_line_3_cb;
+ devcb_write_line m_output_line_4_cb;
+ devcb_write_line m_output_line_5_cb;
+ devcb_write_line m_output_line_6_cb;
+ devcb_write_line m_output_line_7_cb;
+ devcb_write_line m_output_line_8_cb;
+ devcb_write_line m_output_line_9_cb;
+};
+
+// ======================> ttl74145_device
+
+class ttl74145_device : public device_t,
+ public ttl74145_interface
+{
+public:
+ // construction/destruction
+ ttl74145_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ UINT16 read();
+ void write(UINT8 data);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+private:
+ devcb_resolved_write_line m_output_line_0_func;
+ devcb_resolved_write_line m_output_line_1_func;
+ devcb_resolved_write_line m_output_line_2_func;
+ devcb_resolved_write_line m_output_line_3_func;
+ devcb_resolved_write_line m_output_line_4_func;
+ devcb_resolved_write_line m_output_line_5_func;
+ devcb_resolved_write_line m_output_line_6_func;
+ devcb_resolved_write_line m_output_line_7_func;
+ devcb_resolved_write_line m_output_line_8_func;
+ devcb_resolved_write_line m_output_line_9_func;
+
+ /* decoded number */
+ UINT16 m_number;
+};
+
+// device type definition
+extern const device_type TTL74145;
+
+//**************************************************************************
+// DEFAULT INTERFACES
+//**************************************************************************
+
+extern const ttl74145_interface default_ttl74145;
+
+
+#endif /* TTL74145 */
diff --git a/src/emu/machine/at29040a.c b/src/emu/machine/at29040a.c
new file mode 100644
index 00000000000..95982e67bf0
--- /dev/null
+++ b/src/emu/machine/at29040a.c
@@ -0,0 +1,444 @@
+/*
+ Atmel at29c040a flash EEPROM
+
+ 512k*8 FEEPROM, organized in pages of 256 bytes.
+
+ References:
+ Datasheets were found on Atmel's site (www.atmel.com)
+
+ Raphael Nabet 2003
+
+ September 2010: Rewritten as device
+ February 2012: Rewritten as class
+*/
+
+#include "at29040a.h"
+
+#define VERBOSE 2
+#define LOG logerror
+
+#define FEEPROM_SIZE 0x80000
+#define SECTOR_SIZE 0x00100
+#define BOOT_BLOCK_SIZE 0x04000
+
+#define ADDRESS_MASK 0x7ffff
+#define SECTOR_ADDRESS_MASK 0x7ff00
+#define BYTE_ADDRESS_MASK 0x000ff
+
+#define PRG_TIMER 1
+
+#define VERSION 0
+
+/*
+ Constructor.
+*/
+at29040a_device::at29040a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: device_t(mconfig, AT29040A, "ATMEL 29040A 512K*8 FEEPROM", tag, owner, clock),
+ device_nvram_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void at29040a_device::nvram_default()
+{
+ memset(m_eememory, 0, FEEPROM_SIZE+2);
+}
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+void at29040a_device::nvram_read(emu_file &file)
+{
+ file.read(m_eememory, FEEPROM_SIZE+2);
+}
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+void at29040a_device::nvram_write(emu_file &file)
+{
+ m_eememory[0] = VERSION;
+ file.write(m_eememory, FEEPROM_SIZE+2);
+}
+
+/*
+ programming timer callback
+*/
+void at29040a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (m_pgm)
+ {
+ case PGM_1:
+ /* programming cycle timeout */
+ if (VERBOSE>7) LOG("at29040a: Programming cycle timeout\n");
+ m_pgm = PGM_0;
+ break;
+
+ case PGM_2:
+ /* programming cycle start */
+ if (VERBOSE>7) LOG("at29040a: Sector write start\n");
+ m_pgm = PGM_3;
+ /* max delay 10ms, typical delay 5 to 7 ms */
+ m_programming_timer->adjust(attotime::from_msec(5));
+ break;
+
+ case PGM_3:
+ /* programming cycle end */
+ memcpy(m_eememory + 2 + (m_programming_last_offset & ~0xff), m_programming_buffer, SECTOR_SIZE);
+ if (VERBOSE>7) LOG("at29040a: Sector write completed at location %04x + 2\n", (m_programming_last_offset & ~0xff));
+ if (m_enabling_sdb)
+ {
+ m_sdp = true;
+ }
+ if (m_disabling_sdb)
+ {
+ m_sdp = false;
+ }
+ if (VERBOSE>7) LOG("at29040a: Software data protection = %d\n", m_sdp);
+
+ m_pgm = PGM_0;
+ m_enabling_sdb = false;
+ m_disabling_sdb = false;
+
+ break;
+
+ default:
+ if (VERBOSE>1) LOG("internal error in %s %d\n", __FILE__, __LINE__);
+ break;
+ }
+}
+
+void at29040a_device::sync_flags()
+{
+ if (m_lower_bbl) m_eememory[1] |= 0x04;
+ else m_eememory[1] &= ~0x04;
+
+ if (m_higher_bbl) m_eememory[1] |= 0x02;
+ else m_eememory[1] &= ~0x02;
+
+ if (m_sdp) m_eememory[1] |= 0x01;
+ else m_eememory[1] &= ~0x01;
+}
+
+/*
+ read a byte from FEEPROM
+*/
+READ8_MEMBER( at29040a_device::read )
+{
+ int reply;
+
+ offset &= ADDRESS_MASK;
+
+ /* reading in the midst of any command sequence cancels it (right???) */
+ m_cmd = CMD_0;
+ m_long_sequence = false;
+ // m_higher_bbl = true; // who says that?
+
+ sync_flags();
+
+ /* reading before the start of a programming cycle cancels it (right???) */
+ if (m_pgm == PGM_1)
+ {
+ // attempt to access a locked out boot block: cancel programming
+ // command if necessary
+ m_pgm = PGM_0;
+ m_enabling_sdb = false;
+ m_disabling_sdb = false;
+ m_programming_timer->adjust(attotime::never);
+ }
+
+ if (m_id_mode)
+ {
+ switch (offset)
+ {
+ case 0x00000:
+ reply = 0x1f; // Manufacturer code
+ break;
+
+ case 0x00001:
+ reply = 0xa4; // Device code
+ break;
+
+ case 0x00002:
+ reply = m_lower_bbl? 0xff : 0xfe;
+ break;
+
+ case 0x7fff2:
+ reply = m_higher_bbl? 0xff : 0xfe;
+ break;
+
+ default:
+ reply = 0;
+ break;
+ }
+ }
+ else if ((m_pgm == PGM_2) || (m_pgm == PGM_3))
+ {
+ if (m_pgm == PGM_2)
+ { // DATA* polling starts the programming cycle (right???)
+ m_pgm = PGM_3;
+ /* max delay 10ms, typical delay 5 to 7 ms */
+ m_programming_timer->adjust(attotime::from_msec(5));
+ }
+
+ reply = m_toggle_bit? 0x02 : 0x00;
+ m_toggle_bit = !m_toggle_bit;
+
+ if ((offset == m_programming_last_offset) && (! (m_programming_buffer[m_programming_last_offset & 0xff] & 0x01)))
+ reply |= 0x01;
+ }
+ else
+ reply = m_eememory[offset+2];
+
+ if (VERBOSE>7) LOG("at29040a: %05x -> %02x\n", offset, reply);
+
+ return reply;
+}
+
+/*
+ Write a byte to FEEPROM
+*/
+WRITE8_MEMBER( at29040a_device::write )
+{
+ offset &= ADDRESS_MASK;
+ if (VERBOSE>7) LOG("at29040a: %05x <- %02x\n", offset, data);
+
+ /* The special CFI commands assume a smaller address space according */
+ /* to the specification ("address format A14-A0") */
+ offs_t cfi_offset = offset & 0x7fff;
+
+ if (m_enabling_bbl)
+ {
+ if (VERBOSE>7) LOG("at29040a: Enabling boot block lockout\n");
+ m_enabling_bbl = false;
+
+ if ((offset == 0x00000) && (data == 0x00))
+ {
+ if (VERBOSE>7) LOG("at29040a: Enabling lower boot block lockout\n");
+ m_lower_bbl = true;
+ sync_flags();
+ return;
+ }
+ else
+ {
+ if ((offset == 0x7ffff) && (data == 0xff))
+ {
+ if (VERBOSE>7) LOG("at29040a: Enabling higher boot block lockout\n");
+ m_higher_bbl = true;
+ sync_flags();
+ return;
+ }
+ else
+ {
+ if (VERBOSE>1) LOG("at29040a: Invalid boot block specification: %05x/%02x\n", offset, data);
+ }
+ }
+ }
+
+ switch (m_cmd)
+ {
+ case CMD_0:
+ if ((cfi_offset == 0x5555) && (data == 0xaa))
+ {
+ if (VERBOSE>7) LOG("at29040a: Command sequence started\n");
+ m_cmd = CMD_1;
+ }
+ else
+ {
+ m_cmd = CMD_0;
+ m_long_sequence = false;
+ }
+ break;
+
+ case CMD_1:
+ if ((cfi_offset == 0x2aaa) && (data == 0x55))
+ {
+ m_cmd = CMD_2;
+ }
+ else
+ {
+ m_cmd = CMD_0;
+ m_long_sequence = false;
+ if (VERBOSE>7) LOG("at29040a: Command sequence aborted\n");
+ }
+ break;
+
+ case CMD_2:
+ if (cfi_offset == 0x5555)
+ {
+ if (!m_long_sequence)
+ if (VERBOSE>7) LOG("at29040a: Command sequence completed\n");
+
+ m_pgm = PGM_0;
+ m_enabling_sdb = false;
+ m_disabling_sdb = false;
+ m_programming_timer->adjust(attotime::never);
+
+ /* process command */
+ switch (data)
+ {
+ case 0x10:
+ /* Software chip erase */
+ if (m_long_sequence)
+ {
+ if (m_lower_bbl || m_higher_bbl)
+ {
+ if (VERBOSE>1) LOG("at29040a: Chip erase sequence deactivated due to previous boot block lockout.\n");
+ }
+ else
+ {
+ if (VERBOSE>7) LOG("at29040a: Erase chip\n");
+ memset(m_eememory+2, 0xff, FEEPROM_SIZE);
+ }
+ }
+ break;
+
+ case 0x20:
+ /* Software data protection disable */
+ if (VERBOSE>7) LOG("at29040a: Software data protection disable\n");
+ // The complete sequence is aa-55-80-aa-55-20
+ // so we need a 80 before, else the sequence is invalid
+ if (m_long_sequence)
+ {
+ m_pgm = PGM_1;
+ m_disabling_sdb = true;
+ /* set command timeout (right???) */
+ //m_programming_timer->adjust(attotime::from_usec(150), id, 0.);
+ }
+ break;
+
+ case 0x40:
+ /* Boot block lockout enable */
+ // Complete sequence is aa-55-80-aa-55-40
+ if (VERBOSE>7) LOG("at29040a: Boot block lockout enable\n");
+ if (m_long_sequence) m_enabling_bbl = true;
+ break;
+
+ case 0x80:
+ m_long_sequence = true;
+ break;
+
+ case 0x90:
+ /* Software product identification entry */
+ if (VERBOSE>7) LOG("at29040a: Identification mode (start)\n");
+ m_id_mode = true;
+ break;
+
+ case 0xa0:
+ /* Software data protection enable */
+ if (VERBOSE>7) LOG("at29040a: Software data protection enable\n");
+ m_pgm = PGM_1;
+ m_enabling_sdb = true;
+ /* set command timeout (right???) */
+ //m_programming_timer->adjust(attotime::from_usec(150), id, 0.);
+ break;
+
+ case 0xf0:
+ /* Software product identification exit */
+ if (VERBOSE>7) LOG("at29040a: Identification mode (end)\n");
+ m_id_mode = false;
+ break;
+ }
+ m_cmd = CMD_0;
+ if (data != 0x80) m_long_sequence = false;
+
+ /* return, because we don't want to write the EEPROM with the command byte */
+ return;
+ }
+ else
+ {
+ m_cmd = CMD_0;
+ m_long_sequence = false;
+ }
+ }
+ if ((m_pgm == PGM_2)
+ && ((offset & ~0xff) != (m_programming_last_offset & ~0xff)))
+ {
+ /* cancel current programming cycle */
+ if (VERBOSE>7) LOG("at29040a: invalid sector change (from %05x to %05x); cancel programming cycle\n",(offset & ~0xff), (m_programming_last_offset & ~0xff));
+ m_pgm = PGM_0;
+ m_enabling_sdb = false;
+ m_disabling_sdb = false;
+ m_programming_timer->adjust(attotime::never);
+ }
+
+ if (((m_pgm == PGM_0) && !m_sdp) // write directly
+ || (m_pgm == PGM_1)) // write after unlocking
+ {
+ if (((offset < BOOT_BLOCK_SIZE) && m_lower_bbl)
+ || ((offset >= FEEPROM_SIZE-BOOT_BLOCK_SIZE) && m_higher_bbl))
+ {
+ // attempt to access a locked out boot block: cancel programming
+ // command if necessary
+ if (VERBOSE>7) LOG("at29040a: attempt to access a locked out boot block: offset = %05x, lowblock=%d, highblock=%d\n", offset, m_lower_bbl, m_higher_bbl);
+
+ m_pgm = PGM_0;
+ m_enabling_sdb = false;
+ m_disabling_sdb = false;
+ }
+ else
+ { /* enter programming mode */
+ if (VERBOSE>7) LOG("at29040a: enter programming mode (m_pgm=%d)\n", m_pgm);
+ memset(m_programming_buffer, 0xff, SECTOR_SIZE);
+ m_pgm = PGM_2;
+ }
+ }
+ if (m_pgm == PGM_2)
+ {
+ /* write data to programming buffer */
+ if (VERBOSE>7) LOG("at29040a: Write data to programming buffer\n");
+ m_programming_buffer[offset & 0xff] = data;
+ m_programming_last_offset = offset;
+ m_programming_timer->adjust(attotime::from_usec(150)); // next byte must be written before the timer expires
+ }
+}
+
+void at29040a_device::device_start(void)
+{
+ m_programming_buffer = (UINT8*)malloc(SECTOR_SIZE);
+ m_programming_timer = timer_alloc(PRG_TIMER);
+
+ m_eememory = (UINT8*)malloc(FEEPROM_SIZE+2);
+}
+
+void at29040a_device::device_stop(void)
+{
+ free(m_programming_buffer);
+ free(m_eememory);
+}
+
+void at29040a_device::device_reset(void)
+{
+ if (m_eememory[0] != VERSION)
+ {
+ if (VERBOSE>1) LOG("AT29040A: Warning: Version mismatch; expected %d but found %d for %s. Resetting.\n", VERSION, m_eememory[0], tag());
+ m_eememory[0] = 0;
+ m_eememory[1] = 0;
+ }
+
+ m_lower_bbl = ((m_eememory[1] & 0x04)!=0);
+ m_higher_bbl = ((m_eememory[1] & 0x02)!=0);
+ m_sdp = ((m_eememory[1] & 0x01)!=0);
+
+ if (VERBOSE>7) LOG("at29040a (%s): LowerBBL = %d, HigherBBL = %d, SoftDataProt = %d\n", tag(), m_lower_bbl, m_higher_bbl, m_sdp);
+
+ m_id_mode = false;
+ m_cmd = CMD_0;
+ m_enabling_bbl = false;
+ m_long_sequence = false;
+ m_pgm = PGM_0;
+ m_enabling_sdb = false;
+ m_disabling_sdb = false;
+ m_toggle_bit = false;
+ m_programming_last_offset = 0;
+}
+
+const device_type AT29040A = &device_creator<at29040a_device>;
diff --git a/src/emu/machine/at29040a.h b/src/emu/machine/at29040a.h
new file mode 100644
index 00000000000..4a50e6e6b0c
--- /dev/null
+++ b/src/emu/machine/at29040a.h
@@ -0,0 +1,88 @@
+/*
+ ATMEL 29040a
+
+ Michael Zapf
+ September 2010: Rewritten as device
+ February 2012: Rewritten as class
+*/
+
+#ifndef __AT29040__
+#define __AT29040__
+
+#include "emu.h"
+
+extern const device_type AT29040A;
+
+/*
+ at29c40a state
+
+ Command states (CMD_0 is the initial state):
+ CMD_0: default state
+ CMD_1: state after writing aa to 5555
+ CMD_2: state after writing 55 to 2aaa
+
+ Programming states (s_programming_0 is the initial state):
+ PGM_0: default state
+ PGM_1: a program and enable/disable lock command has been executed, but programming has not actually started.
+ PGM_2: the programming buffer is being written to
+ PGM_3: the programming buffer is being burnt to flash ROM
+*/
+enum s_cmd_t
+{
+ CMD_0 = 0x0,
+ CMD_1 = 0x1,
+ CMD_2 = 0x2
+};
+
+enum s_pgm_t
+{
+ PGM_0 = 0x0,
+ PGM_1 = 0x1,
+ PGM_2 = 0x2,
+ PGM_3 = 0x3
+};
+
+class at29040a_device : public device_t, public device_nvram_interface
+{
+public:
+ at29040a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+protected:
+ virtual void device_start(void);
+ virtual void device_reset(void);
+ virtual void device_stop(void);
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ void nvram_default();
+ void nvram_read(emu_file &file);
+ void nvram_write(emu_file &file);
+
+private:
+ void sync_flags(void);
+
+ UINT8* m_eememory;
+
+ bool m_lower_bbl; /* set when lower boot block lockout is enabled */
+ bool m_higher_bbl; /* set when upper boot block lockout is enabled */
+ bool m_sdp; /* set when in software data protect mode */
+
+ bool m_id_mode; /* set when in chip id mode */
+ s_cmd_t m_cmd; /* command state */
+ bool m_enabling_bbl; /* set when a boot block lockout command is expecting its parameter */
+ bool m_long_sequence; /* set if 0x80 command has just been executed (some command require this prefix) */
+ s_pgm_t m_pgm; /* programming state */
+ bool m_enabling_sdb; /* set when a sdp enable command is in progress */
+ bool m_disabling_sdb; /* set when a sdp disable command is in progress */
+ bool m_dirty; /* set when the memory contents should be set */
+ bool m_toggle_bit; // indicates flashing in progress (toggles for each query)
+ UINT8* m_programming_buffer;
+ int m_programming_last_offset;
+ emu_timer* m_programming_timer;
+};
+
+#define MCFG_AT29040A_ADD(_tag ) \
+ MCFG_DEVICE_ADD(_tag, AT29040A, 0)
+
+#endif
diff --git a/src/emu/machine/at45dbxx.c b/src/emu/machine/at45dbxx.c
new file mode 100644
index 00000000000..0128ccf7469
--- /dev/null
+++ b/src/emu/machine/at45dbxx.c
@@ -0,0 +1,375 @@
+/*
+
+ Atmel Serial DataFlash
+
+ (c) 2001-2007 Tim Schuerewegen
+
+ AT45DB041 - 528 KByte
+ AT45DB081 - 1056 KByte
+ AT45DB161 - 2112 KByte
+
+*/
+
+#include "at45dbxx.h"
+
+#define LOG_LEVEL 1
+#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0)
+
+#define FLASH_CMD_52 0x52
+#define FLASH_CMD_57 0x57
+#define FLASH_CMD_60 0x60
+#define FLASH_CMD_82 0x82
+
+#define FLASH_MODE_XX 0 // unknown
+#define FLASH_MODE_SI 1 // input
+#define FLASH_MODE_SO 2 // output
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+const device_type AT45DB041 = &device_creator<at45db041_device>;
+const device_type AT45DB081 = &device_creator<at45db081_device>;
+const device_type AT45DB161 = &device_creator<at45db161_device>;
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// at45db041_device - constructor
+//-------------------------------------------------
+
+at45db041_device::at45db041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, AT45DB041, "AT45DB041", tag, owner, clock),
+ device_nvram_interface(mconfig, *this)
+{
+}
+
+
+at45db041_device::at45db041_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ device_nvram_interface(mconfig, *this)
+{
+}
+
+
+at45db081_device::at45db081_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : at45db041_device(mconfig, AT45DB081, "AT45DB081", tag, owner, clock)
+{
+}
+
+
+at45db161_device::at45db161_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : at45db041_device(mconfig, AT45DB161, "AT45DB161", tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void at45db041_device::device_start()
+{
+ m_size = num_pages() * page_size();
+ m_data = auto_alloc_array(machine(), UINT8, m_size);
+ m_buffer1 = auto_alloc_array(machine(), UINT8, page_size());
+ m_buffer2 = auto_alloc_array(machine(), UINT8, page_size());
+
+ // data
+ save_pointer(NAME(m_data), m_size);
+ // pins
+ save_item(NAME(m_pin.cs));
+ save_item(NAME(m_pin.sck));
+ save_item(NAME(m_pin.si));
+ save_item(NAME(m_pin.so));
+ save_item(NAME(m_pin.wp));
+ save_item(NAME(m_pin.reset));
+ save_item(NAME(m_pin.busy));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void at45db041_device::device_reset()
+{
+ _logerror( 1, ("at45dbxx_reset\n"));
+ // mode
+ m_mode = FLASH_MODE_SI;
+ // command
+ memset(&m_cmd.data[0], 0, sizeof(m_cmd.data));
+ m_cmd.size = 0;
+ // input/output
+ m_io.data = NULL;
+ m_io.size = 0;
+ m_io.pos = 0;
+ // pins
+ m_pin.cs = 0;
+ m_pin.sck = 0;
+ m_pin.si = 0;
+ m_pin.so = 0;
+ m_pin.wp = 0;
+ m_pin.reset = 0;
+ m_pin.busy = 0;
+ // output
+ m_so_byte = 0;
+ m_so_bits = 0;
+ // input
+ m_si_byte = 0;
+ m_si_bits = 0;
+}
+
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void at45db041_device::nvram_default()
+{
+ memset(m_data, 0xff, m_size);
+
+ if (region() != NULL)
+ {
+ UINT32 bytes = region()->bytes();
+ if (bytes > m_size)
+ bytes = m_size;
+
+ memcpy(m_data, region()->base(), bytes);
+ }
+}
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+void at45db041_device::nvram_read(emu_file &file)
+{
+ file.read(m_data, m_size);
+}
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+void at45db041_device::nvram_write(emu_file &file)
+{
+ file.write(m_data, m_size);
+}
+
+UINT8 at45db041_device::read_byte()
+{
+ UINT8 data;
+ // check mode
+ if ((m_mode != FLASH_MODE_SO) || (!m_io.data)) return 0;
+ // read byte
+ data = m_io.data[m_io.pos++];
+ _logerror( 2, ("at45dbxx_read_byte (%02X) (%03d/%03d)\n", data, m_io.pos, m_io.size));
+ if (m_io.pos == m_io.size) m_io.pos = 0;
+ return data;
+}
+
+void at45db041_device::flash_set_io(UINT8* data, UINT32 size, UINT32 pos)
+{
+ m_io.data = data;
+ m_io.size = size;
+ m_io.pos = pos;
+}
+
+UINT32 at45db041_device::flash_get_page_addr()
+{
+ return ((m_cmd.data[1] & 0x0F) << 7) | ((m_cmd.data[2] & 0xFE) >> 1);
+}
+
+UINT32 at45db041_device::flash_get_byte_addr()
+{
+ return ((m_cmd.data[2] & 0x01) << 8) | ((m_cmd.data[3] & 0xFF) >> 0);
+}
+
+UINT32 at45db081_device::flash_get_page_addr()
+{
+ return ((m_cmd.data[1] & 0x1F) << 7) | ((m_cmd.data[2] & 0xFE) >> 1);
+}
+
+UINT32 at45db161_device::flash_get_page_addr()
+{
+ return ((m_cmd.data[1] & 0x3F) << 6) | ((m_cmd.data[2] & 0xFC) >> 2);
+}
+
+UINT32 at45db161_device::flash_get_byte_addr()
+{
+ return ((m_cmd.data[2] & 0x03) << 8) | ((m_cmd.data[3] & 0xFF) >> 0);
+}
+
+void at45db041_device::write_byte(UINT8 data)
+{
+ // check mode
+ if (m_mode != FLASH_MODE_SI) return;
+ // process byte
+ if (m_cmd.size < 8)
+ {
+ UINT8 opcode;
+ _logerror( 2, ("at45dbxx_write_byte (%02X)\n", data));
+ // add to command buffer
+ m_cmd.data[m_cmd.size++] = data;
+ // check opcode
+ opcode = m_cmd.data[0];
+ switch (opcode)
+ {
+ // status register read
+ case FLASH_CMD_57 :
+ {
+ // 8 bits command
+ if (m_cmd.size == 1)
+ {
+ _logerror( 1, ("at45dbxx opcode %02X - status register read\n", opcode));
+ m_status = (m_status & 0xC7) | device_id(); // 80 = busy / 40 = compare fail
+ flash_set_io(&m_status, 1, 0);
+ m_mode = FLASH_MODE_SO;
+ m_cmd.size = 8;
+ }
+ }
+ break;
+ // main memory page to buffer 1 compare
+ case FLASH_CMD_60 :
+ {
+ // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits don't care
+ if (m_cmd.size == 4)
+ {
+ UINT32 page;
+ UINT8 comp;
+ page = flash_get_page_addr();
+ _logerror( 1, ("at45dbxx opcode %02X - main memory page to buffer 1 compare [%04X]\n", opcode, page));
+ comp = memcmp( m_data + page * page_size(), m_buffer1, page_size()) == 0 ? 0 : 1;
+ if (comp) m_status |= 0x40; else m_status &= ~0x40;
+ _logerror( 1, ("at45dbxx page compare %s\n", comp ? "failure" : "success"));
+ m_mode = FLASH_MODE_SI;
+ m_cmd.size = 8;
+ }
+ }
+ break;
+ // main memory page read
+ case FLASH_CMD_52 :
+ {
+ // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits buffer address + 32 bits don't care
+ if (m_cmd.size == 8)
+ {
+ UINT32 page, byte;
+ page = flash_get_page_addr();
+ byte = flash_get_byte_addr();
+ _logerror( 1, ("at45dbxx opcode %02X - main memory page read [%04X/%04X]\n", opcode, page, byte));
+ flash_set_io(m_data + page * page_size(), page_size(), byte);
+ m_mode = FLASH_MODE_SO;
+ m_cmd.size = 8;
+ }
+ }
+ break;
+ // main memory page program through buffer 1
+ case FLASH_CMD_82 :
+ {
+ // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits buffer address
+ if (m_cmd.size == 4)
+ {
+ UINT32 page, byte;
+ page = flash_get_page_addr();
+ byte = flash_get_byte_addr();
+ _logerror( 1, ("at45dbxx opcode %02X - main memory page program through buffer 1 [%04X/%04X]\n",opcode, page, byte));
+ flash_set_io(m_buffer1, page_size(), byte);
+ memset( m_buffer1, 0xFF, page_size());
+ m_mode = FLASH_MODE_SI;
+ m_cmd.size = 8;
+ }
+ }
+ break;
+ // other
+ default :
+ {
+ _logerror( 1, ("at45dbxx opcode %02X - unknown\n", opcode));
+ m_cmd.data[0] = 0;
+ m_cmd.size = 0;
+ }
+ break;
+ }
+ }
+ else
+ {
+ _logerror( 2, ("at45dbxx_write_byte (%02X) (%03d/%03d)\n", data, m_io.pos + 1, m_io.size));
+ // store byte
+ m_io.data[m_io.pos] = data;
+ m_io.pos++;
+ if (m_io.pos == m_io.size) m_io.pos = 0;
+ }
+}
+
+READ_LINE_MEMBER(at45db041_device::so_r)
+{
+ if (m_pin.cs == 0) return 0;
+ return m_pin.so;
+}
+
+WRITE_LINE_MEMBER(at45db041_device::si_w)
+{
+ if (m_pin.cs == 0) return;
+ m_pin.si = state;
+}
+
+WRITE_LINE_MEMBER(at45db041_device::cs_w)
+{
+ // check if changed
+ if (m_pin.cs == state) return;
+ // cs low-to-high
+ if (state != 0)
+ {
+ // complete program command
+ if ((m_cmd.size >= 4) && (m_cmd.data[0] == FLASH_CMD_82))
+ {
+ UINT32 page, byte;
+ page = flash_get_page_addr();
+ byte = flash_get_byte_addr();
+ _logerror( 1, ("at45dbxx - program data stored in buffer 1 into selected page in main memory [%04X/%04X]\n", page, byte));
+ memcpy( m_data + page * page_size(), m_buffer1, page_size());
+ }
+ // reset
+ at45db041_device::device_reset();
+ }
+ // save cs
+ m_pin.cs = state;
+}
+
+WRITE_LINE_MEMBER(at45db041_device::sck_w)
+{
+ // check if changed
+ if (m_pin.sck == state) return;
+ // sck high-to-low
+ if (state == 0)
+ {
+ // output (part 1)
+ if (m_so_bits == 8)
+ {
+ m_so_bits = 0;
+ m_so_byte = read_byte();
+ }
+ // input
+ if (m_pin.si) m_si_byte = m_si_byte | (1 << m_si_bits);
+ m_si_bits++;
+ if (m_si_bits == 8)
+ {
+ m_si_bits = 0;
+ write_byte(m_si_byte);
+ m_si_byte = 0;
+ }
+ // output (part 2)
+ m_pin.so = (m_so_byte >> m_so_bits) & 1;
+ m_so_bits++;
+ }
+ // save sck
+ m_pin.sck = state;
+}
diff --git a/src/emu/machine/at45dbxx.h b/src/emu/machine/at45dbxx.h
new file mode 100644
index 00000000000..1cc85cccadd
--- /dev/null
+++ b/src/emu/machine/at45dbxx.h
@@ -0,0 +1,144 @@
+/*
+
+ Atmel Serial DataFlash
+
+ (c) 2001-2007 Tim Schuerewegen
+
+ AT45DB041 - 528 KByte
+ AT45DB081 - 1056 KByte
+ AT45DB161 - 2112 KByte
+
+*/
+
+#ifndef _AT45DBXX_H_
+#define _AT45DBXX_H_
+
+#include "emu.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_AT45DB041_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, AT45DB041, 0)
+
+#define MCFG_AT45DB081_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, AT45DB081, 0)
+
+#define MCFG_AT45DB161_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, AT45DB161, 0)
+
+
+// ======================> at45db041_device
+
+class at45db041_device : public device_t,
+ public device_nvram_interface
+{
+public:
+ at45db041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ at45db041_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_WRITE_LINE_MEMBER(cs_w);
+ DECLARE_WRITE_LINE_MEMBER(sck_w);
+ DECLARE_WRITE_LINE_MEMBER(si_w);
+ DECLARE_READ_LINE_MEMBER(so_r);
+
+ UINT8 *get_ptr() { return m_data; }
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_nvram_interface overrides
+ virtual void nvram_default();
+ virtual void nvram_read(emu_file &file);
+ virtual void nvram_write(emu_file &file);
+
+protected:
+ virtual int num_pages() const { return 2048; }
+ virtual int page_size() const { return 264; }
+ virtual UINT8 device_id() const { return 0x18; }
+
+ UINT8 read_byte();
+ void flash_set_io(UINT8* data, UINT32 size, UINT32 pos);
+ virtual UINT32 flash_get_page_addr();
+ virtual UINT32 flash_get_byte_addr();
+ void write_byte(UINT8 data);
+
+ // internal state
+ UINT8 * m_data;
+ UINT32 m_size;
+ UINT8 m_mode;
+ UINT8 m_status;
+ UINT8 * m_buffer1;
+ UINT8 * m_buffer2;
+ UINT8 m_si_byte;
+ UINT8 m_si_bits;
+ UINT8 m_so_byte;
+ UINT8 m_so_bits;
+
+ struct AT45DBXX_PINS
+ {
+ int cs; // chip select
+ int sck; // serial clock
+ int si; // serial input
+ int so; // serial output
+ int wp; // write protect
+ int reset; // reset
+ int busy; // busy
+ } m_pin;
+
+ struct AT45DBXX_IO
+ {
+ UINT8 *data;
+ UINT32 size;
+ UINT32 pos;
+ } m_io;
+
+ struct AT45DBXX_CMD
+ {
+ UINT8 data[8];
+ UINT8 size;
+ } m_cmd;
+};
+
+// ======================> at45db081_device
+
+class at45db081_device : public at45db041_device
+{
+public:
+ at45db081_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual int num_pages() const { return 4096; }
+ virtual int page_size() const { return 264; }
+ virtual UINT8 device_id() const { return 0x20; }
+
+ virtual UINT32 flash_get_page_addr();
+};
+
+// ======================> at45db161_device
+
+class at45db161_device : public at45db041_device
+{
+public:
+ at45db161_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual int num_pages() const { return 4096; }
+ virtual int page_size() const { return 528; }
+ virtual UINT8 device_id() const { return 0x28; }
+
+ virtual UINT32 flash_get_page_addr();
+ virtual UINT32 flash_get_byte_addr();
+};
+
+
+// device type definition
+extern const device_type AT45DB041;
+extern const device_type AT45DB081;
+extern const device_type AT45DB161;
+
+#endif
diff --git a/src/emu/machine/ay31015.c b/src/emu/machine/ay31015.c
new file mode 100644
index 00000000000..3b46014de19
--- /dev/null
+++ b/src/emu/machine/ay31015.c
@@ -0,0 +1,760 @@
+/****************************************************************************
+
+ ay31015.c by Robbbert, May 2008. Bugs fixed by Judge.
+
+ Code for the AY-3-1014A, AY-3-1015(D), AY-5-1013(A), and AY-6-1013 UARTs
+ The HD6402 UART is compatible with the AY-3-1015 UART.
+
+ This is cycle-accurate according to the specifications.
+
+ It supports independent receive and transmit clocks,
+ and transmission and reception can occur simultaneously if desired.
+
+*****************************************************************************
+
+Differences between the chip types:
+- All units have pull-up resistors on the inputs, except for the AY-3-1014A which is CMOS-compatible.
+- AY-3-1014A and AY-3-1015 - 1.5 stop bits mode available.
+- Max baud rate of 30k, except AY-5-1013 which has 20k.
+- AY-5-1013 has extended temperature ratings.
+- AY-5-1013 and AY-6-1013 require a -12 volt supply on pin 2. Pin is not used otherwise.
+- AY-5-1013 and AY-6-1013 do not reset the received data register when XR pin is used.
+
+******************************************************************************
+
+It is not clear in the documentation as to which settings will reset the device.
+ To be safe, we will always reset whenever the control register changes.
+
+ Also, it not clear exactly what happens under various error conditions.
+
+********************************************************************************
+
+Device Data:
+
+* Common Controls:
+-- Pin 1 - Vcc - 5 volts
+-- Pin 2 - not used (on AY-5-1013 and AY-6-1013 this is Voo = -12 volts)
+-- Pin 3 - Gnd - 0 volts
+-- Pin 21 - XR - External Reset - resets all registers to initial state except for the control register
+-- Pin 35 - NP - No Parity - "1" will kill any parity processing
+-- Pin 36 - TSB - Number of Stop Bits - "0" = 1 stop bit; "1" = 2 stop bits. If "1", and 5 bits per character, then we have 1.5 stop bits
+-- pin 37 - NB1
+-- pin 38 - NB2 - Number of bits per character = NB1 + (NB2 * 2) + 5
+-- pin 39 - EPS - Odd or Even Parity Select - "0" = Odd parity; "1" = Even parity. Has no effect if NP is high.
+-- Pin 34 - CS - Control Strobe - Read NP, TSB, EPS, NB1, NB2 into the control register.
+
+Format of data stream:
+Start bit (low), Bit 0, Bit 1... highest bit, Parity bit (if enabled), 1-2 stop bits (high)
+
+
+* Receiver Controls:
+-- Pin 17 - RCP - Clock which is 16x the desired baud rate
+-- Pin 20 - SI - Serial input stream - "1" = Mark (waiting for input), "0" = Space (Start bit) initiates the transfer of a byte
+-- Pin 4 - RDE - "0" causes the received data to appear on RD1 to RD8.
+-- Pins 5 to 12 - RD8 to RD1 - These are the data lines (bits 7 to 0). Data is right-justified.
+-- Pin 16 - SWE - Status word enable - causes the status bits (PE, FE, OR, DAV, TBMT) to appear at the pins.
+-- Pin 19 - DAV - "1" indicates that a byte has been received by the UART, and should now be accepted by the computer
+-- Pin 18 - RDAV - "0" will force DAV low.
+-- Pin 13 - PE - Parity error - "1" indicates that a parity error occurred
+-- Pin 14 - FE - Framing error - "1" Indicates that the stop bit was missing
+-- Pin 15 - OR - overrun - "1" indicates that a new character has become available before the computer had accepted the previous character
+
+* Transmitter controls:
+-- Pin 40 - TCP - Clock which is 16x the desired baud rate
+-- Pin 25 - SO - Serial output stream - it will stay at "1" while no data is being transmitted
+-- Pins 26 to 33 - DB1 to DB8 - These are the data lines containing the byte to be sent
+-- Pin 23 - DS - Data Strobe - "0" will copy DB1 to DB8 into the transmit buffer
+-- Pin 22 - TBMT - Transmit buffer Empty - "1" indicates to the computer that another byte may be sent to the UART
+-- Pin 24 - EOC - End of Character - "0" means that a character is being sent.
+
+******************************************* COMMON CONTROLS ********************************************************/
+
+#include "emu.h"
+#include "ay31015.h"
+
+enum state_t
+{
+ IDLE,
+ START_BIT,
+ PROCESSING,
+ PARITY_BIT,
+ FIRST_STOP_BIT,
+ SECOND_STOP_BIT,
+ PREP_TIME
+};
+
+
+struct ay31015_t
+{
+ const ay31015_config *config;
+
+ int pins[41];
+
+ UINT8 control_reg;
+ UINT8 status_reg;
+ UINT16 second_stop_bit; // 0, 8, 16
+ UINT16 total_pulses; // bits * 16
+ UINT8 internal_sample;
+
+ state_t rx_state;
+ UINT8 rx_data; // byte being received
+ UINT8 rx_buffer; // received byte waiting to be accepted by computer
+ UINT8 rx_bit_count;
+ UINT8 rx_parity;
+ UINT16 rx_pulses; // total pulses left
+ double rx_clock;
+ emu_timer *rx_timer;
+
+ state_t tx_state;
+ UINT8 tx_data; // byte being sent
+ UINT8 tx_buffer; // next byte to send
+ UINT8 tx_parity;
+ UINT16 tx_pulses; // total pulses left
+ double tx_clock;
+ emu_timer *tx_timer;
+
+ devcb_resolved_read8 read_si; /* SI - pin 20 - This will be called whenever the SI pin is sampled. Optional */
+ devcb_resolved_write8 write_so; /* SO - pin 25 - This will be called whenever data is put on the SO pin. Optional */
+ devcb_resolved_write8 status_changed; /* This will be called whenever one of the status pins may have changed. Optional */
+};
+
+
+/* control reg */
+#define CONTROL_NB1 0x01
+#define CONTROL_NB2 0x02
+#define CONTROL_TSB 0x04
+#define CONTROL_EPS 0x08
+#define CONTROL_NP 0x10
+
+
+/* status reg */
+#define STATUS_TBMT 0x01
+#define STATUS_DAV 0x02
+#define STATUS_OR 0x04
+#define STATUS_FE 0x08
+#define STATUS_PE 0x10
+#define STATUS_EOC 0x20
+
+
+/*-------------------------------------------------
+ get_safe_token - safely gets the data
+-------------------------------------------------*/
+
+INLINE ay31015_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == AY31015);
+ return (ay31015_t *) downcast<ay31015_device *>(device)->token();
+}
+
+
+INLINE UINT8 ay31015_get_si( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ if ( !ay31015->read_si.isnull() )
+ ay31015->pins[AY31015_SI] = ay31015->read_si( 0 ) ? 1 : 0;
+
+ return ay31015->pins[AY31015_SI];
+}
+
+
+INLINE void ay31015_set_so( device_t *device, int data )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ ay31015->pins[AY31015_SO] = data ? 1 : 0;
+
+ if ( !ay31015->write_so.isnull() )
+ ay31015->write_so( 0, ay31015->pins[AY31015_SO] );
+}
+
+
+INLINE int ay31015_update_status_pin( ay31015_t *ay31015, UINT8 reg_bit, ay31015_output_pin_t pin )
+{
+ int new_value = ( ay31015->status_reg & reg_bit ) ? 1 : 0;
+
+ if ( new_value == ay31015->pins[pin] )
+ return 0;
+
+ ay31015->pins[pin] = new_value;
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ ay31015_update_status_pins - Update the status pins
+-------------------------------------------------*/
+static void ay31015_update_status_pins( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+ int status_pins_changed = 0;
+
+ /* Should status pins be updated? */
+ if ( ! ay31015->pins[AY31015_SWE] )
+ {
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_PE, AY31015_PE );
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_FE, AY31015_FE );
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_OR, AY31015_OR );
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_DAV, AY31015_DAV );
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_TBMT, AY31015_TBMT );
+ }
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_EOC, AY31015_EOC );
+
+ if ( status_pins_changed && !ay31015->status_changed.isnull() )
+ {
+ ay31015->status_changed( 0, status_pins_changed );
+ }
+}
+
+
+/*************************************************** RECEIVE CONTROLS *************************************************/
+
+
+/*-------------------------------------------------
+ ay31015_rx_process - convert serial to parallel
+-------------------------------------------------*/
+static TIMER_CALLBACK( ay31015_rx_process )
+{
+ device_t *device = (device_t *)ptr;
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ switch (ay31015->rx_state)
+ {
+ case PREP_TIME: // assist sync by ensuring high bit occurs
+ ay31015->rx_pulses--;
+ if (ay31015_get_si( device ))
+ ay31015->rx_state = IDLE;
+ return;
+
+ case IDLE:
+ ay31015->rx_pulses--;
+ if (!ay31015_get_si( device ))
+ {
+ ay31015->rx_state = START_BIT;
+ ay31015->rx_pulses = 16;
+ }
+ return;
+
+ case START_BIT:
+ ay31015->rx_pulses--;
+ if (ay31015->rx_pulses == 8) // start bit must be low at sample time
+ {
+ if ( ay31015_get_si( device ) )
+ ay31015->rx_state = IDLE;
+ }
+ else
+ if (!ay31015->rx_pulses) // end of start bit
+ {
+ ay31015->rx_state = PROCESSING;
+ ay31015->rx_pulses = ay31015->total_pulses;
+ ay31015->rx_bit_count = 0;
+ ay31015->rx_parity = 0;
+ ay31015->rx_data = 0;
+ }
+ return;
+
+ case PROCESSING:
+ ay31015->rx_pulses--;
+ if (!ay31015->rx_pulses) // end of a byte
+ {
+ ay31015->rx_pulses = 16;
+ if (ay31015->control_reg & CONTROL_NP) // see if we need to get a parity bit
+ ay31015->rx_state = FIRST_STOP_BIT;
+ else
+ ay31015->rx_state = PARITY_BIT;
+ }
+ else
+ if (!(ay31015->rx_pulses & 15)) // end of a bit
+ ay31015->rx_bit_count++;
+ else
+ if ((ay31015->rx_pulses & 15) == 8) // sample input stream
+ {
+ ay31015->internal_sample = ay31015_get_si( device );
+ ay31015->rx_parity ^= ay31015->internal_sample; // calculate cumulative parity
+ ay31015->rx_data |= ay31015->internal_sample << ay31015->rx_bit_count;
+ }
+ return;
+
+ case PARITY_BIT:
+ ay31015->rx_pulses--;
+
+ if (ay31015->rx_pulses == 8) // sample input stream
+ {
+ ay31015->rx_parity ^= ay31015_get_si( device ); // calculate cumulative parity
+ }
+ else
+ if (!ay31015->rx_pulses) // end of a byte
+ {
+ ay31015->rx_pulses = 16;
+ ay31015->rx_state = FIRST_STOP_BIT;
+
+ if ((!(ay31015->control_reg & CONTROL_EPS)) && (ay31015->rx_parity))
+ ay31015->rx_parity = 0; // odd parity, ok
+ else
+ if ((ay31015->control_reg & CONTROL_EPS) && (!ay31015->rx_parity))
+ ay31015->rx_parity = 0; // even parity, ok
+ else
+ ay31015->rx_parity = 1; // parity error
+ }
+ return;
+
+ case FIRST_STOP_BIT:
+ ay31015->rx_pulses--;
+ if (ay31015->rx_pulses == 8) // sample input stream
+ ay31015->internal_sample = ay31015_get_si( device );
+ else
+ if (ay31015->rx_pulses == 7) // set error flags
+ {
+ if (!ay31015->internal_sample)
+ {
+ ay31015->status_reg |= STATUS_FE; // framing error - the stop bit not high
+ ay31015->rx_state = PREP_TIME; // lost sync - start over
+ // return;
+ }
+ else
+ ay31015->status_reg &= ~STATUS_FE;
+
+ if ((ay31015->rx_parity) && (!(ay31015->control_reg & CONTROL_NP)))
+ ay31015->status_reg |= STATUS_PE; // parity error
+ else
+ ay31015->status_reg &= ~STATUS_PE;
+
+ if (ay31015->status_reg & STATUS_DAV)
+ ay31015->status_reg |= STATUS_OR; // overrun error - previous byte still in buffer
+ else
+ ay31015->status_reg &= ~STATUS_OR;
+
+ ay31015->rx_buffer = ay31015->rx_data; // bring received byte out for computer to read
+
+ ay31015_update_status_pins( device );
+ }
+ else
+ if (ay31015->rx_pulses == 6)
+ {
+ ay31015->status_reg |= STATUS_DAV; // tell computer that new byte is ready
+ ay31015_update_status_pins( device );
+ }
+ else
+ if (ay31015->rx_pulses == 4)
+ {
+ if (ay31015->second_stop_bit)
+ {
+ /* We should wait for the full first stop bit and
+ the beginning of the second stop bit */
+ ay31015->rx_state = SECOND_STOP_BIT;
+ ay31015->rx_pulses += ay31015->second_stop_bit - 7;
+ }
+ else
+ {
+ /* We have seen a STOP bit, go back to PREP_TIME */
+ ay31015->rx_state = PREP_TIME;
+ }
+ }
+ return;
+
+ case SECOND_STOP_BIT:
+ ay31015->rx_pulses--;
+ if (!ay31015->rx_pulses)
+ ay31015->rx_state = PREP_TIME;
+ return;
+
+ }
+}
+
+
+/*************************************************** TRANSMIT CONTROLS *************************************************/
+
+
+/*-------------------------------------------------
+ ay31015_tx_process - convert parallel to serial
+-------------------------------------------------*/
+static TIMER_CALLBACK( ay31015_tx_process )
+{
+ device_t *device = (device_t *)ptr;
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ UINT8 t1;
+ switch (ay31015->tx_state)
+ {
+ case IDLE:
+ if (!(ay31015->status_reg & STATUS_TBMT))
+ {
+ ay31015->tx_state = PREP_TIME; // When idle, see if a byte has been sent to us
+ ay31015->tx_pulses = 1;
+ }
+ return;
+
+ case PREP_TIME: // This phase lets the transmitter regain sync after an idle period
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses)
+ {
+ ay31015->tx_state = START_BIT;
+ ay31015->tx_pulses = 16;
+ }
+ return;
+
+ case START_BIT:
+ if (ay31015->tx_pulses == 16) // beginning of start bit
+ {
+ ay31015->tx_data = ay31015->tx_buffer; // load the shift register
+ ay31015->status_reg |= STATUS_TBMT; // tell computer that another byte can be sent to uart
+ ay31015_set_so( device, 0 ); /* start bit begins now (we are "spacing") */
+ ay31015->status_reg &= ~STATUS_EOC; // we are no longer idle
+ ay31015->tx_parity = 0;
+ ay31015_update_status_pins( device );
+ }
+
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses) // end of start bit
+ {
+ ay31015->tx_state = PROCESSING;
+ ay31015->tx_pulses = ay31015->total_pulses;
+ }
+ return;
+
+ case PROCESSING:
+ if (!(ay31015->tx_pulses & 15)) // beginning of a data bit
+ {
+ if (ay31015->tx_data & 1)
+ {
+ ay31015_set_so( device, 1 );
+ ay31015->tx_parity++; // calculate cumulative parity
+ }
+ else
+ ay31015_set_so( device, 0 );
+
+ ay31015->tx_data >>= 1; // adjust the shift register
+ }
+
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses) // all data bits sent
+ {
+ ay31015->tx_pulses = 16;
+ if (ay31015->control_reg & CONTROL_NP) // see if we need to make a parity bit
+ ay31015->tx_state = FIRST_STOP_BIT;
+ else
+ ay31015->tx_state = PARITY_BIT;
+ }
+
+ return;
+
+ case PARITY_BIT:
+ if (ay31015->tx_pulses == 16)
+ {
+ t1 = (ay31015->control_reg & CONTROL_EPS) ? 0 : 1;
+ t1 ^= (ay31015->tx_parity & 1);
+ if (t1)
+ ay31015_set_so( device, 1 ); /* extra bit to set the correct parity */
+ else
+ ay31015_set_so( device, 0 ); /* it was already correct */
+ }
+
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses)
+ {
+ ay31015->tx_state = FIRST_STOP_BIT;
+ ay31015->tx_pulses = 16;
+ }
+ return;
+
+ case FIRST_STOP_BIT:
+ if (ay31015->tx_pulses == 16)
+ ay31015_set_so( device, 1 ); /* create a stop bit (marking and soon idle) */
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses)
+ {
+ ay31015->status_reg |= STATUS_EOC; // character is completely sent
+ if (ay31015->second_stop_bit)
+ {
+ ay31015->tx_state = SECOND_STOP_BIT;
+ ay31015->tx_pulses = ay31015->second_stop_bit;
+ }
+ else
+ if (ay31015->status_reg & STATUS_TBMT)
+ ay31015->tx_state = IDLE; // if nothing to send, go idle
+ else
+ {
+ ay31015->tx_pulses = 16;
+ ay31015->tx_state = START_BIT; // otherwise immediately start next byte
+ }
+ ay31015_update_status_pins( device );
+ }
+ return;
+
+ case SECOND_STOP_BIT:
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses)
+ {
+ if (ay31015->status_reg & STATUS_TBMT)
+ ay31015->tx_state = IDLE; // if nothing to send, go idle
+ else
+ {
+ ay31015->tx_pulses = 16;
+ ay31015->tx_state = START_BIT; // otherwise immediately start next byte
+ }
+ }
+ return;
+
+ }
+}
+
+
+/*-------------------------------------------------
+ ay31015_reset - reset internal state
+-------------------------------------------------*/
+static void ay31015_reset( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ /* total pulses = 16 * data-bits */
+ UINT8 t1;
+
+ if ( ay31015->control_reg & CONTROL_NB2 )
+ t1 = ( ay31015->control_reg & CONTROL_NB1 ) ? 8 : 7;
+ else
+ t1 = ( ay31015->control_reg & CONTROL_NB1 ) ? 6 : 5;
+
+ ay31015->total_pulses = t1 << 4; /* total clock pulses to load a byte */
+ ay31015->second_stop_bit = ((ay31015->control_reg & CONTROL_TSB) ? 16 : 0); /* 2nd stop bit */
+ if ((t1 == 5) && (ay31015->second_stop_bit == 16))
+ ay31015->second_stop_bit = 8; /* 5 data bits and 2 stop bits = 1.5 stop bits */
+ ay31015->status_reg = STATUS_EOC | STATUS_TBMT;
+ ay31015->tx_data = 0;
+ ay31015->rx_state = PREP_TIME;
+ ay31015->tx_state = IDLE;
+ ay31015->pins[AY31015_SI] = 1;
+ ay31015_set_so( device, 1 );
+
+ if ( ay31015->config->type == AY_3_1015 )
+ ay31015->rx_data = 0;
+
+}
+
+
+/*-------------------------------------------------
+ ay31015_transfer_control_pins - transfers contents of controls pins to the control register
+-------------------------------------------------*/
+static void ay31015_transfer_control_pins( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+ UINT8 control = 0;
+
+ control |= ay31015->pins[AY31015_NP ] ? CONTROL_NP : 0;
+ control |= ay31015->pins[AY31015_TSB] ? CONTROL_TSB : 0;
+ control |= ay31015->pins[AY31015_NB1] ? CONTROL_NB1 : 0;
+ control |= ay31015->pins[AY31015_NB2] ? CONTROL_NB2 : 0;
+ control |= ay31015->pins[AY31015_EPS] ? CONTROL_EPS : 0;
+
+ if ( ay31015->control_reg != control )
+ {
+ ay31015->control_reg = control;
+ ay31015_reset( device );
+ }
+}
+
+
+/*-------------------------------------------------
+ ay31015_set_input_pin - set an input pin
+-------------------------------------------------*/
+void ay31015_set_input_pin( device_t *device, ay31015_input_pin_t pin, int data )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ data = data ? 1 : 0;
+
+ switch ( pin )
+ {
+ case AY31015_SWE:
+ ay31015->pins[pin] = data;
+ ay31015_update_status_pins( device );
+ break;
+ case AY31015_RDAV:
+ ay31015->pins[pin] = data;
+ if ( ! data )
+ {
+ ay31015->status_reg &= ~STATUS_DAV;
+ ay31015->pins[AY31015_DAV] = 0;
+ }
+ break;
+ case AY31015_SI:
+ ay31015->pins[pin] = data;
+ break;
+ case AY31015_XR:
+ ay31015->pins[pin] = data;
+ if ( data )
+ ay31015_reset( device );
+ break;
+ case AY31015_CS:
+ case AY31015_NP:
+ case AY31015_TSB:
+ case AY31015_NB1:
+ case AY31015_NB2:
+ case AY31015_EPS:
+ ay31015->pins[pin] = data;
+ if ( ay31015->pins[AY31015_CS] )
+ ay31015_transfer_control_pins( device );
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ ay31015_get_output_pin - get the status of an output pin
+-------------------------------------------------*/
+int ay31015_get_output_pin( device_t *device, ay31015_output_pin_t pin )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ return ay31015->pins[pin];
+}
+
+
+INLINE void ay31015_update_rx_timer( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ if ( ay31015->rx_clock > 0.0 )
+ {
+ ay31015->rx_timer->adjust( attotime::from_hz( ay31015->rx_clock ), 0, attotime::from_hz( ay31015->rx_clock ) );
+ }
+ else
+ {
+ ay31015->rx_timer->enable( 0 );
+ }
+}
+
+
+INLINE void ay31015_update_tx_timer( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ if ( ay31015->tx_clock > 0.0 )
+ {
+ ay31015->tx_timer->adjust( attotime::from_hz( ay31015->tx_clock ), 0, attotime::from_hz( ay31015->tx_clock ) );
+ }
+ else
+ {
+ ay31015->tx_timer->enable( 0 );
+ }
+}
+
+
+/*-------------------------------------------------
+ ay31015_set_receiver_clock - set receive clock
+-------------------------------------------------*/
+void ay31015_set_receiver_clock( device_t *device, double new_clock )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ ay31015->rx_clock = new_clock;
+ ay31015_update_rx_timer( device );
+}
+
+
+/*-------------------------------------------------
+ ay31015_set_transmitter_clock - set transmit clock
+-------------------------------------------------*/
+void ay31015_set_transmitter_clock( device_t *device, double new_clock )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ ay31015->tx_clock = new_clock;
+ ay31015_update_tx_timer( device );
+}
+
+
+/*-------------------------------------------------
+ ay31015_get_received_data - return a byte to the computer
+-------------------------------------------------*/
+UINT8 ay31015_get_received_data( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ return ay31015->rx_buffer;
+}
+
+
+/*-------------------------------------------------
+ ay31015_set_transmit_data - accept a byte to transmit, if able
+-------------------------------------------------*/
+void ay31015_set_transmit_data( device_t *device, UINT8 data )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ if (ay31015->status_reg & STATUS_TBMT)
+ {
+ ay31015->tx_buffer = data;
+ ay31015->status_reg &= ~STATUS_TBMT;
+ ay31015_update_status_pins( device );
+ }
+}
+
+
+static DEVICE_START(ay31015)
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ ay31015->config = (const ay31015_config*)device->static_config();
+
+ ay31015->read_si.resolve(ay31015->config->read_si_cb, *device);
+ ay31015->write_so.resolve(ay31015->config->write_so_cb, *device);
+ ay31015->status_changed.resolve(ay31015->config->status_changed_cb, *device);
+
+ ay31015->tx_clock = ay31015->config->transmitter_clock;
+ ay31015->rx_clock = ay31015->config->receiver_clock;
+
+ ay31015->rx_timer = device->machine().scheduler().timer_alloc(FUNC(ay31015_rx_process), (void *)device );
+ ay31015->tx_timer = device->machine().scheduler().timer_alloc(FUNC(ay31015_tx_process), (void *)device );
+
+ ay31015_update_rx_timer( device );
+ ay31015_update_tx_timer( device );
+}
+
+
+static DEVICE_RESET( ay31015 )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ ay31015->control_reg = 0;
+ ay31015->rx_data = 0;
+
+ ay31015_reset( device );
+}
+
+
+const device_type AY31015 = &device_creator<ay31015_device>;
+
+ay31015_device::ay31015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, AY31015, "AY-3-1015", tag, owner, clock)
+{
+ m_token = global_alloc_clear(ay31015_t);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void ay31015_device::device_config_complete()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ay31015_device::device_start()
+{
+ DEVICE_START_NAME( ay31015 )(this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void ay31015_device::device_reset()
+{
+ DEVICE_RESET_NAME( ay31015 )(this);
+}
diff --git a/src/emu/machine/ay31015.h b/src/emu/machine/ay31015.h
new file mode 100644
index 00000000000..44d5e2b57a0
--- /dev/null
+++ b/src/emu/machine/ay31015.h
@@ -0,0 +1,126 @@
+/* ay31015.h
+
+ Written for MESS by Robbbert on May 29th, 2008.
+
+*/
+
+#ifndef __AY31015_H_
+#define __AY31015_H_
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+
+enum ay31015_type_t
+{
+ /* For AY-3-1014A, AY-3-1015(D) and HD6402 variants */
+ AY_3_1015,
+
+ /* For AY-3-1014, AY-5-1013 and AY-6-1013 variants */
+ AY_5_1013
+};
+
+
+enum ay31015_input_pin_t
+{
+ AY31015_SWE=16, /* -SWE - Pin 16 - Status word enable */
+ AY31015_RDAV=18, /* -RDAV - Pin 18 - Reset data available */
+ AY31015_SI=20, /* SI - Pin 20 - Serial input */
+ AY31015_XR=21, /* XR - Pin 21 - External reset */
+ AY31015_CS=34, /* CS - Pin 34 - Control strobe */
+ AY31015_NP=35, /* NP - Pin 35 - No parity */
+ AY31015_TSB=36, /* TSB - Pin 36 - Number of stop bits */
+ AY31015_NB1=37, /* NB1 - Pin 37 - Number of bits #1 */
+ AY31015_NB2=38, /* NB2 - Pin 38 - Number of bits #2 */
+ AY31015_EPS=39 /* EPS - Pin 39 - Odd/Even parity select */
+};
+
+
+enum ay31015_output_pin_t
+{
+ AY31015_PE=13, /* PE - Pin 13 - Parity error */
+ AY31015_FE=14, /* FE - Pin 14 - Framing error */
+ AY31015_OR=15, /* OR - Pin 15 - Over-run */
+ AY31015_DAV=19, /* DAV - Pin 19 - Data available */
+ AY31015_TBMT=22, /* TBMT - Pin 22 - Transmit buffer empty */
+ AY31015_EOC=24, /* EOC - Pin 24 - End of character */
+ AY31015_SO=25 /* SO - Pin 25 - Serial output */
+};
+
+
+struct ay31015_config
+{
+ ay31015_type_t type; /* Type of chip */
+ double transmitter_clock; /* TCP - pin 40 */
+ double receiver_clock; /* RCP - pin 17 */
+ devcb_read8 read_si_cb; /* SI - pin 20 - This will be called whenever the SI pin is sampled. Optional */
+ devcb_write8 write_so_cb; /* SO - pin 25 - This will be called whenever data is put on the SO pin. Optional */
+ devcb_write8 status_changed_cb; /* This will be called whenever one of the status pins may have changed. Optional */
+};
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_AY31015_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, AY31015, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* Set an input pin */
+void ay31015_set_input_pin( device_t *device, ay31015_input_pin_t pin, int data );
+
+
+/* Get an output pin */
+int ay31015_get_output_pin( device_t *device, ay31015_output_pin_t pin );
+
+
+/* Set a new transmitter clock (new_clock is in Hz) */
+void ay31015_set_transmitter_clock( device_t *device, double new_clock );
+
+
+/* Set a new receiver clock (new_clock is in Hz) */
+void ay31015_set_receiver_clock( device_t *device, double new_clock );
+
+
+/* Reead the received data */
+/* The received data is available on RD8-RD1 (pins 5-12) */
+UINT8 ay31015_get_received_data( device_t *device );
+
+
+/* Set the transmitter buffer */
+/* The data to transmit is set on DB1-DB8 (pins 26-33) */
+void ay31015_set_transmit_data( device_t *device, UINT8 data );
+
+
+/***************************************************************************
+ DEVICE INTERFACE
+***************************************************************************/
+
+class ay31015_device : public device_t
+{
+public:
+ ay31015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~ay31015_device() { global_free(m_token); }
+
+ // access to legacy token
+ void *token() const { assert(m_token != NULL); return m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ // internal state
+ void *m_token;
+};
+
+extern const device_type AY31015;
+
+#endif
diff --git a/src/emu/machine/er59256.c b/src/emu/machine/er59256.c
new file mode 100644
index 00000000000..6eedb17a68a
--- /dev/null
+++ b/src/emu/machine/er59256.c
@@ -0,0 +1,259 @@
+/*********************************************************************
+
+ er59256.c
+
+ Microchip ER59256 serial eeprom.
+
+
+*********************************************************************/
+
+#include "emu.h"
+#include "er59256.h"
+
+/* LOGLEVEL 0=no logging, 1=just commands and data, 2=everything ! */
+
+#define LOGLEVEL 0
+
+#define LOG(level,...) if(LOGLEVEL>=level) logerror(__VA_ARGS__)
+#define LOG_BITS(bits) logerror("CS=%d CK=%d DI=%d DO=%d", (bits&CS_MASK) ? 1 : 0, (bits&CK_MASK) ? 1 : 0, (bits&DI_MASK) ? 1 : 0, (bits&DO_MASK) ? 1 : 0)
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct er59256_t
+{
+ /* The actual memory */
+ UINT16 eerom[EEROM_WORDS];
+
+ /* Bits as they appear on the io pins, current state */
+ UINT8 io_bits;
+
+ /* Bits as they appear on the io pins, previous state */
+ UINT8 old_io_bits;
+
+
+ /* the 16 bit shift in/out reg */
+ UINT16 in_shifter;
+ UINT32 out_shifter;
+
+ /* Count of bits received since last CS low->high */
+ UINT8 bitcount;
+
+ /* Command & addresss */
+ UINT8 command;
+
+ /* Write enable and write in progress flags */
+ UINT8 flags;
+};
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+************************************************************************/
+
+static void decode_command(er59256_t *er59256);
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE er59256_t *get_token(device_t *device)
+{
+ assert(device->type() == ER59256);
+ return (er59256_t *) downcast<er59256_device *>(device)->token();
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+void er59256_preload_rom(device_t *device, const UINT16 *rom_data, int count)
+{
+ er59256_t *er59256 = get_token(device);
+ int WordNo;
+
+ logerror("Preloading %d words of data\n",count);
+
+ if(count>EEROM_WORDS)
+ memcpy(&er59256->eerom,rom_data,count*2);
+ else
+ memcpy(&er59256->eerom,rom_data,EEROM_WORDS*2);
+
+ for(WordNo=0;WordNo<EEROM_WORDS;WordNo++)
+ logerror("%04X ",er59256->eerom[WordNo]);
+
+ logerror("\n");
+}
+
+UINT8 er59256_data_loaded(device_t *device)
+{
+ er59256_t *er59256 = get_token(device);
+
+ return (er59256->flags & FLAG_DATA_LOADED) ? 1 : 0;
+}
+
+/*-------------------------------------------------
+ DEVICE_START( er59256 )
+-------------------------------------------------*/
+
+static DEVICE_START( er59256 )
+{
+ er59256_t *er59256 = get_token(device);
+
+ memset(er59256, 0x00, sizeof(er59256_t));
+
+ // Start with rom defaulted to erased
+ memset(&er59256->eerom, 0xFF, EEROM_WORDS*2);
+
+ er59256->command=CMD_INVALID;
+
+ er59256->flags&= ~FLAG_DATA_LOADED;
+}
+
+static DEVICE_STOP( er59256 )
+{
+ /* Save contents of eerom */
+}
+
+void er59256_set_iobits(device_t *device, UINT8 newbits)
+{
+ er59256_t *er59256 = get_token(device);
+ //UINT32 bit;
+
+ // Make sure we only apply valid bits
+ newbits&=ALL_MASK;
+
+ if(LOGLEVEL>1)
+ {
+ logerror("er59256:newbits=%02X : ",newbits);
+ LOG_BITS(newbits);
+ logerror(" io_bits=%02X : ",er59256->io_bits);
+ LOG_BITS(er59256->io_bits);
+ logerror(" old_io_bits=%02X : ",er59256->old_io_bits);
+ LOG_BITS(er59256->old_io_bits);
+ logerror(" bitcount=%d, in_shifter=%04X, out_shifter=%05X, flags=%02X\n",er59256->bitcount,er59256->in_shifter,er59256->out_shifter,er59256->flags);
+ }
+ // Only do anything if the inputs have changed
+ if((newbits&IN_MASK)!=(er59256->io_bits&IN_MASK))
+ {
+ // save the current state, then set the new one, remembering to preserve data out
+ er59256->old_io_bits=er59256->io_bits;
+ er59256->io_bits=(newbits & ~DO_MASK) | (er59256->old_io_bits&DO_MASK);
+
+ if(CS_RISE(er59256))
+ {
+ er59256->flags&=~FLAG_START_BIT;
+ er59256->command=CMD_INVALID;
+ }
+
+ if(LOGLEVEL>1)
+ {
+ if(CK_RISE(er59256)) logerror("er59256:CK rise\n");
+ if(CS_RISE(er59256)) logerror("er59256:CS rise\n");
+ if(CK_FALL(er59256)) logerror("er59256:CK fall\n");
+ if(CS_FALL(er59256)) logerror("er59256:CS fall\n");
+ }
+
+ if(CK_RISE(er59256) && CS_VALID(er59256))
+ {
+ if((STARTED(er59256)==0) && (GET_DI(er59256)==1))
+ {
+ er59256->bitcount=0;
+ er59256->flags|=FLAG_START_BIT;
+ }
+ else
+ {
+ SHIFT_IN(er59256);
+ er59256->bitcount++;
+
+ if(er59256->bitcount==CMD_BITLEN)
+ decode_command(er59256);
+
+ if((er59256->bitcount==WRITE_BITLEN) && ((er59256->command & CMD_MASK)==CMD_WRITE))
+ {
+ er59256->eerom[er59256->command & ADDR_MASK]=er59256->in_shifter;
+ LOG(1,"er59256:write[%02X]=%04X\n",(er59256->command & ADDR_MASK),er59256->in_shifter);
+ er59256->command=CMD_INVALID;
+ }
+ LOG(1,"out_shifter=%05X, io_bits=%02X\n",er59256->out_shifter,er59256->io_bits);
+ SHIFT_OUT(er59256);
+ }
+
+ LOG(2,"io_bits:out=%02X\n",er59256->io_bits);
+ }
+ }
+}
+
+UINT8 er59256_get_iobits(device_t *device)
+{
+ er59256_t *er59256 = get_token(device);
+
+ return er59256->io_bits;
+}
+
+
+static void decode_command(er59256_t *er59256)
+{
+ er59256->out_shifter=0x0000;
+ er59256->command=(er59256->in_shifter & (CMD_MASK | ADDR_MASK));
+
+ switch(er59256->command & CMD_MASK)
+ {
+ case CMD_READ : er59256->out_shifter=er59256->eerom[er59256->command & ADDR_MASK];
+ LOG(1,"er59256:read[%02X]=%04X\n",(er59256->command&ADDR_MASK),er59256->eerom[er59256->command & ADDR_MASK]);
+ break;
+ case CMD_WRITE : break;
+ case CMD_ERASE : if (WRITE_ENABLED(er59256)) er59256->eerom[er59256->command & ADDR_MASK]=0xFF;
+ LOG(1,"er59256:erase[%02X]\n",(er59256->command&ADDR_MASK));
+ break;
+ case CMD_EWEN : er59256->flags|=FLAG_WRITE_EN;
+ LOG(1,"er59256:erase/write enabled\n");
+ break;
+ case CMD_EWDS : er59256->flags&=~FLAG_WRITE_EN;
+ LOG(1,"er59256:erase/write disabled\n");
+ break;
+ case CMD_ERAL : if (WRITE_ENABLED(er59256)) memset(&er59256->eerom, 0xFF, EEROM_WORDS*2);
+ LOG(1,"er59256:erase all\n");
+ break;
+ }
+
+ if ((er59256->command & CMD_MASK)!=CMD_WRITE)
+ er59256->command=CMD_INVALID;
+}
+
+const device_type ER59256 = &device_creator<er59256_device>;
+
+er59256_device::er59256_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ER59256, "Microchip ER59256 serial eeprom.", tag, owner, clock)
+{
+ m_token = global_alloc_clear(er59256_t);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void er59256_device::device_config_complete()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void er59256_device::device_start()
+{
+ DEVICE_START_NAME( er59256 )(this);
+}
+
+//-------------------------------------------------
+// device_stop - device-specific stop
+//-------------------------------------------------
+
+void er59256_device::device_stop()
+{
+ DEVICE_STOP_NAME( er59256 )(this);
+}
diff --git a/src/emu/machine/er59256.h b/src/emu/machine/er59256.h
new file mode 100644
index 00000000000..938a8872ee3
--- /dev/null
+++ b/src/emu/machine/er59256.h
@@ -0,0 +1,112 @@
+/*********************************************************************
+
+ er59256.h
+
+ Microchip ER59256 serial eeprom.
+
+
+*********************************************************************/
+
+#ifndef _ER59256_H_
+#define _ER59256_H_
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+class er59256_device : public device_t
+{
+public:
+ er59256_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~er59256_device() { global_free(m_token); }
+
+ // access to legacy token
+ void *token() const { assert(m_token != NULL); return m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_stop();
+private:
+ // internal state
+ void *m_token;
+};
+
+extern const device_type ER59256;
+
+
+#define MCFG_ER59256_ADD(_tag) \
+ MCFG_DEVICE_ADD((_tag), ER59256, 0)
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define EEROM_WORDS 0x10
+
+#define CK_SHIFT 0x00
+#define DI_SHIFT 0x01
+#define DO_SHIFT 0x02
+#define CS_SHIFT 0x03
+
+#define CK_MASK (1<<CK_SHIFT)
+#define DI_MASK (1<<DI_SHIFT)
+#define DO_MASK (1<<DO_SHIFT)
+#define CS_MASK (1<<CS_SHIFT)
+
+#define ALL_MASK (CK_MASK | DI_MASK | DO_MASK | CS_MASK)
+#define IN_MASK (CK_MASK | DI_MASK | CS_MASK)
+
+#define GET_CK(eep) ((eep->io_bits & CK_MASK) >> CK_SHIFT)
+#define GET_DI(eep) ((eep->io_bits & DI_MASK) >> DI_SHIFT)
+#define GET_DO(eep) ((eep->io_bits & DO_MASK) >> DO_SHIFT)
+#define GET_CS(eep) ((eep->io_bits & CS_MASK) >> CS_SHIFT)
+
+#define SET_CK(eep,data) eep->io_bits=((eep->io_bits & ~CK_MASK) | ((data & 0x01) << CK_SHIFT))
+#define SET_DI(eep,data) eep->io_bits=((eep->io_bits & ~DI_MASK) | ((data & 0x01) << DI_SHIFT))
+#define SET_DO(eep,data) eep->io_bits=((eep->io_bits & ~DO_MASK) | ((data & 0x01) << DO_SHIFT))
+#define SET_CS(eep,data) eep->io_bits=((eep->io_bits & ~CS_MASK) | ((data & 0x01) << CS_SHIFT))
+
+#define CK_RISE(eep) ((eep->io_bits & CK_MASK) & ~(eep->old_io_bits & CK_MASK))
+#define CS_RISE(eep) ((eep->io_bits & CS_MASK) & ~(eep->old_io_bits & CS_MASK))
+#define CS_VALID(eep) ((eep->io_bits & CS_MASK) & (eep->old_io_bits & CS_MASK))
+
+#define CK_FALL(eep) (~(eep->io_bits & CK_MASK) & (eep->old_io_bits & CK_MASK))
+#define CS_FALL(eep) (~(eep->io_bits & CS_MASK) & (eep->old_io_bits & CS_MASK))
+
+
+#define SHIFT_IN(eep) eep->in_shifter=(eep->in_shifter<<1) | GET_DI(eep)
+#define SHIFT_OUT(eep) SET_DO(eep,(eep->out_shifter & 0x10000)>>16); eep->out_shifter=(eep->out_shifter<<1)
+
+#define CMD_READ 0x80
+#define CMD_WRITE 0x40
+#define CMD_ERASE 0xC0
+#define CMD_EWEN 0x30
+#define CMD_EWDS 0x00
+#define CMD_ERAL 0x20
+#define CMD_INVALID 0xF0
+
+#define CMD_MASK 0xF0
+#define ADDR_MASK 0x0F
+
+// CMD_BITLEN is 1 start bit plus 4 command bits plus 4 address bits
+#define CMD_BITLEN 8
+#define DATA_BITLEN 16
+#define WRITE_BITLEN CMD_BITLEN+DATA_BITLEN
+
+#define FLAG_WRITE_EN 0x01
+#define FLAG_START_BIT 0x02
+#define FLAG_DATA_LOADED 0x04
+
+#define WRITE_ENABLED(eep) ((eep->flags & FLAG_WRITE_EN) ? 1 : 0)
+#define STARTED(eep) ((eep->flags & FLAG_START_BIT) ? 1 : 0)
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+void er59256_set_iobits(device_t *device, UINT8 newbits);
+UINT8 er59256_get_iobits(device_t *device);
+void er59256_preload_rom(device_t *device, const UINT16 *rom_data, int count);
+UINT8 er59256_data_loaded(device_t *device);
+#endif
diff --git a/src/emu/machine/mc68328.c b/src/emu/machine/mc68328.c
new file mode 100644
index 00000000000..e7039df5cad
--- /dev/null
+++ b/src/emu/machine/mc68328.c
@@ -0,0 +1,2872 @@
+/**********************************************************************
+
+ Motorola 68328 ("DragonBall") System-on-a-Chip implementation
+
+ By MooglyGuy
+ contact mooglyguy@gmail.com with licensing and usage questions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "cpu/m68000/m68000.h"
+#include "includes/mc68328.h"
+#include "mc68328.h"
+
+#define VERBOSE_LEVEL (0)
+
+INLINE void verboselog(running_machine &machine, int n_level, const char *s_fmt, ...)
+{
+ if( VERBOSE_LEVEL >= n_level )
+ {
+ va_list v;
+ char buf[ 32768 ];
+ va_start( v, s_fmt );
+ vsprintf( buf, s_fmt, v );
+ va_end( v );
+ logerror( "%s: %s", machine.describe_context(), buf );
+ }
+}
+
+static void mc68328_set_interrupt_line(device_t *device, UINT32 line, UINT32 active)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ device_t *cpu = device->machine().device(mc68328->iface->m68k_cpu_tag);
+
+ if(active)
+ {
+ mc68328->regs.ipr |= line;
+
+ if(!(mc68328->regs.imr & line) && !(mc68328->regs.isr & line))
+ {
+ mc68328->regs.isr |= line;
+
+ if(mc68328->regs.isr & INT_M68K_LINE7)
+ {
+ cpu->execute().set_input_line_and_vector(M68K_IRQ_7, ASSERT_LINE, mc68328->regs.ivr | 0x07);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE6)
+ {
+ cpu->execute().set_input_line_and_vector(M68K_IRQ_6, ASSERT_LINE, mc68328->regs.ivr | 0x06);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE5)
+ {
+ cpu->execute().set_input_line_and_vector(M68K_IRQ_5, ASSERT_LINE, mc68328->regs.ivr | 0x05);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE4)
+ {
+ cpu->execute().set_input_line_and_vector(M68K_IRQ_4, ASSERT_LINE, mc68328->regs.ivr | 0x04);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE3)
+ {
+ cpu->execute().set_input_line_and_vector(M68K_IRQ_3, ASSERT_LINE, mc68328->regs.ivr | 0x03);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE2)
+ {
+ cpu->execute().set_input_line_and_vector(M68K_IRQ_2, ASSERT_LINE, mc68328->regs.ivr | 0x02);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE1)
+ {
+ cpu->execute().set_input_line_and_vector(M68K_IRQ_1, ASSERT_LINE, mc68328->regs.ivr | 0x01);
+ }
+ }
+ }
+ else
+ {
+ mc68328->regs.isr &= ~line;
+
+ if((line & INT_M68K_LINE7) && !(mc68328->regs.isr & INT_M68K_LINE7))
+ {
+ cpu->execute().set_input_line(M68K_IRQ_7, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE6) && !(mc68328->regs.isr & INT_M68K_LINE6))
+ {
+ cpu->execute().set_input_line(M68K_IRQ_6, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE5) && !(mc68328->regs.isr & INT_M68K_LINE5))
+ {
+ cpu->execute().set_input_line(M68K_IRQ_5, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE4) && !(mc68328->regs.isr & INT_M68K_LINE4))
+ {
+ cpu->execute().set_input_line(M68K_IRQ_4, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE3) && !(mc68328->regs.isr & INT_M68K_LINE3))
+ {
+ cpu->execute().set_input_line(M68K_IRQ_3, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE2) && !(mc68328->regs.isr & INT_M68K_LINE2))
+ {
+ cpu->execute().set_input_line(M68K_IRQ_2, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE1) && !(mc68328->regs.isr & INT_M68K_LINE1))
+ {
+ cpu->execute().set_input_line(M68K_IRQ_1, CLEAR_LINE);
+ }
+ }
+}
+
+static void mc68328_poll_port_d_interrupts(device_t *device)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ UINT8 line_transitions = mc68328->regs.pddataedge & mc68328->regs.pdirqedge;
+ UINT8 line_holds = mc68328->regs.pddata &~ mc68328->regs.pdirqedge;
+ UINT8 line_interrupts = (line_transitions | line_holds) & mc68328->regs.pdirqen;
+
+ if(line_interrupts)
+ {
+ mc68328_set_interrupt_line(device, line_interrupts << 8, 1);
+ }
+ else
+ {
+ mc68328_set_interrupt_line(device, INT_KBDINTS, 0);
+ }
+}
+
+void mc68328_set_penirq_line(device_t *device, int state)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ if(state)
+ {
+ mc68328_set_interrupt_line(device, INT_PEN, 1);
+ }
+ else
+ {
+ mc68328->regs.ipr &= ~INT_PEN;
+ mc68328_set_interrupt_line(device, INT_PEN, 0);
+ }
+}
+
+void mc68328_set_port_d_lines(device_t *device, UINT8 state, int bit)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ UINT8 old_button_state = mc68328->regs.pddata;
+
+ if(state & (1 << bit))
+ {
+ mc68328->regs.pddata |= (1 << bit);
+ }
+ else
+ {
+ mc68328->regs.pddata &= ~(1 << bit);
+ }
+
+ mc68328->regs.pddataedge |= ~old_button_state & mc68328->regs.pddata;
+
+ mc68328_poll_port_d_interrupts(device);
+}
+
+static UINT32 mc68328_get_timer_frequency(device_t *device, UINT32 index)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ UINT32 frequency = 0;
+
+ switch(mc68328->regs.tctl[index] & TCTL_CLKSOURCE)
+ {
+ case TCTL_CLKSOURCE_SYSCLK:
+ frequency = 32768 * 506;
+ break;
+
+ case TCTL_CLKSOURCE_SYSCLK16:
+ frequency = (32768 * 506) / 16;
+ break;
+
+ case TCTL_CLKSOURCE_32KHZ4:
+ case TCTL_CLKSOURCE_32KHZ5:
+ case TCTL_CLKSOURCE_32KHZ6:
+ case TCTL_CLKSOURCE_32KHZ7:
+ frequency = 32768;
+ break;
+ }
+ frequency /= (mc68328->regs.tprer[index] + 1);
+
+ return frequency;
+}
+
+static void mc68328_maybe_start_timer(device_t *device, UINT32 index, UINT32 new_enable)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ if((mc68328->regs.tctl[index] & TCTL_TEN) == TCTL_TEN_ENABLE && (mc68328->regs.tctl[index] & TCTL_CLKSOURCE) > TCTL_CLKSOURCE_STOP)
+ {
+ if((mc68328->regs.tctl[index] & TCTL_CLKSOURCE) == TCTL_CLKSOURCE_TIN)
+ {
+ mc68328->gptimer[index]->adjust(attotime::never);
+ }
+ else if(mc68328->regs.tcmp[index] == 0)
+ {
+ mc68328->gptimer[index]->adjust(attotime::never);
+ }
+ else
+ {
+ UINT32 frequency = mc68328_get_timer_frequency(device, index);
+ attotime period = (attotime::from_hz(frequency) * mc68328->regs.tcmp[index]);
+
+ if(new_enable)
+ {
+ mc68328->regs.tcn[index] = 0x0000;
+ }
+
+ mc68328->gptimer[index]->adjust(period);
+ }
+ }
+ else
+ {
+ mc68328->gptimer[index]->adjust(attotime::never);
+ }
+}
+
+static void mc68328_timer_compare_event(device_t *device, UINT32 index)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ mc68328->regs.tcn[index] = mc68328->regs.tcmp[index];
+ mc68328->regs.tstat[index] |= TSTAT_COMP;
+
+ if((mc68328->regs.tctl[index] & TCTL_FRR) == TCTL_FRR_RESTART)
+ {
+ UINT32 frequency = mc68328_get_timer_frequency(device, index);
+
+ if(frequency > 0)
+ {
+ attotime period = attotime::from_hz(frequency) * mc68328->regs.tcmp[index];
+
+ mc68328->regs.tcn[index] = 0x0000;
+
+ mc68328->gptimer[index]->adjust(period);
+ }
+ else
+ {
+ mc68328->gptimer[index]->adjust(attotime::never);
+ }
+ }
+ else
+ {
+ UINT32 frequency = mc68328_get_timer_frequency(device, index);
+
+ if(frequency > 0)
+ {
+ attotime period = attotime::from_hz(frequency) * 0x10000;
+
+ mc68328->gptimer[index]->adjust(period);
+ }
+ else
+ {
+ mc68328->gptimer[index]->adjust(attotime::never);
+ }
+ }
+ if((mc68328->regs.tctl[index] & TCTL_IRQEN) == TCTL_IRQEN_ENABLE)
+ {
+ mc68328_set_interrupt_line(device, (index == 0) ? INT_TIMER1 : INT_TIMER2, 1);
+ }
+}
+
+static TIMER_CALLBACK( mc68328_timer1_hit )
+{
+ device_t *device = machine.device(MC68328_TAG);
+
+ mc68328_timer_compare_event(device, 0);
+}
+
+static TIMER_CALLBACK( mc68328_timer2_hit )
+{
+ device_t *device = machine.device(MC68328_TAG);
+
+ mc68328_timer_compare_event(device, 1);
+}
+
+static TIMER_CALLBACK( mc68328_pwm_transition )
+{
+ device_t *device = machine.device(MC68328_TAG);
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ if(mc68328->regs.pwmw >= mc68328->regs.pwmp || mc68328->regs.pwmw == 0 || mc68328->regs.pwmp == 0)
+ {
+ mc68328->pwm->adjust(attotime::never);
+ return;
+ }
+
+ if(((mc68328->regs.pwmc & PWMC_POL) == 0 && (mc68328->regs.pwmc & PWMC_PIN) != 0) ||
+ ((mc68328->regs.pwmc & PWMC_POL) != 0 && (mc68328->regs.pwmc & PWMC_PIN) == 0))
+ {
+ UINT32 frequency = 32768 * 506;
+ UINT32 divisor = 4 << (mc68328->regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot.
+ attotime period;
+
+ frequency /= divisor;
+ period = attotime::from_hz(frequency) * (mc68328->regs.pwmp - mc68328->regs.pwmw);
+
+ mc68328->pwm->adjust(period);
+
+ if(mc68328->regs.pwmc & PWMC_IRQEN)
+ {
+ mc68328_set_interrupt_line(device, INT_PWM, 1);
+ }
+ }
+ else
+ {
+ UINT32 frequency = 32768 * 506;
+ UINT32 divisor = 4 << (mc68328->regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot.
+ attotime period;
+
+ frequency /= divisor;
+ period = attotime::from_hz(frequency) * mc68328->regs.pwmw;
+
+ mc68328->pwm->adjust(period);
+ }
+
+ mc68328->regs.pwmc ^= PWMC_PIN;
+
+ if( !mc68328->out_pwm.isnull() )
+ {
+ mc68328->out_pwm( 0, (mc68328->regs.pwmc & PWMC_PIN) ? 1 : 0 );
+ }
+}
+
+static TIMER_CALLBACK( mc68328_rtc_tick )
+{
+ device_t *device = machine.device(MC68328_TAG);
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ if(mc68328->regs.rtcctl & RTCCTL_ENABLE)
+ {
+ UINT32 set_int = 0;
+
+ mc68328->regs.hmsr++;
+
+ if(mc68328->regs.rtcienr & RTCINT_SECOND)
+ {
+ set_int = 1;
+ mc68328->regs.rtcisr |= RTCINT_SECOND;
+ }
+
+ if((mc68328->regs.hmsr & 0x0000003f) == 0x0000003c)
+ {
+ mc68328->regs.hmsr &= 0xffffffc0;
+ mc68328->regs.hmsr += 0x00010000;
+
+ if(mc68328->regs.rtcienr & RTCINT_MINUTE)
+ {
+ set_int = 1;
+ mc68328->regs.rtcisr |= RTCINT_MINUTE;
+ }
+
+ if((mc68328->regs.hmsr & 0x003f0000) == 0x003c0000)
+ {
+ mc68328->regs.hmsr &= 0xffc0ffff;
+ mc68328->regs.hmsr += 0x0100000;
+
+ if((mc68328->regs.hmsr & 0x1f000000) == 0x18000000)
+ {
+ mc68328->regs.hmsr &= 0xe0ffffff;
+
+ if(mc68328->regs.rtcienr & RTCINT_DAY)
+ {
+ set_int = 1;
+ mc68328->regs.rtcisr |= RTCINT_DAY;
+ }
+ }
+ }
+
+ if(mc68328->regs.stpwtch != 0x003f)
+ {
+ mc68328->regs.stpwtch--;
+ mc68328->regs.stpwtch &= 0x003f;
+
+ if(mc68328->regs.stpwtch == 0x003f)
+ {
+ if(mc68328->regs.rtcienr & RTCINT_STOPWATCH)
+ {
+ set_int = 1;
+ mc68328->regs.rtcisr |= RTCINT_STOPWATCH;
+ }
+ }
+ }
+ }
+
+ if(mc68328->regs.hmsr == mc68328->regs.alarm)
+ {
+ if(mc68328->regs.rtcienr & RTCINT_ALARM)
+ {
+ set_int = 1;
+ mc68328->regs.rtcisr |= RTCINT_STOPWATCH;
+ }
+ }
+
+ if(set_int)
+ {
+ mc68328_set_interrupt_line(device, INT_RTC, 1);
+ }
+ else
+ {
+ mc68328_set_interrupt_line(device, INT_RTC, 0);
+ }
+ }
+}
+
+WRITE16_DEVICE_HANDLER( mc68328_w )
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ UINT32 address = offset << 1;
+ UINT16 temp16[4] = { 0 };
+ UINT32 imr_old = mc68328->regs.imr, imr_diff;
+
+ switch(address)
+ {
+ case 0x000:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff001) = %02x\n", data & 0x00ff);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: SCR = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x100:
+ verboselog(space.machine(), 2, "mc68328_w: GRPBASEA = %04x\n", data);
+ mc68328->regs.grpbasea = data;
+ break;
+
+ case 0x102:
+ verboselog(space.machine(), 2, "mc68328_w: GRPBASEB = %04x\n", data);
+ mc68328->regs.grpbaseb = data;
+ break;
+
+ case 0x104:
+ verboselog(space.machine(), 2, "mc68328_w: GRPBASEC = %04x\n", data);
+ mc68328->regs.grpbasec = data;
+ break;
+
+ case 0x106:
+ verboselog(space.machine(), 2, "mc68328_w: GRPBASED = %04x\n", data);
+ mc68328->regs.grpbased = data;
+ break;
+
+ case 0x108:
+ verboselog(space.machine(), 2, "mc68328_w: GRPMASKA = %04x\n", data);
+ mc68328->regs.grpmaska = data;
+ break;
+
+ case 0x10a:
+ verboselog(space.machine(), 2, "mc68328_w: GRPMASKB = %04x\n", data);
+ mc68328->regs.grpmaskb = data;
+ break;
+
+ case 0x10c:
+ verboselog(space.machine(), 2, "mc68328_w: GRPMASKC = %04x\n", data);
+ mc68328->regs.grpmaskc = data;
+ break;
+
+ case 0x10e:
+ verboselog(space.machine(), 2, "mc68328_w: GRPMASKD = %04x\n", data);
+ mc68328->regs.grpmaskd = data;
+ break;
+
+ case 0x110:
+ verboselog(space.machine(), 5, "mc68328_w: CSA0(0) = %04x\n", data);
+ mc68328->regs.csa0 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csa0 |= data & mem_mask;
+ break;
+
+ case 0x112:
+ verboselog(space.machine(), 5, "mc68328_w: CSA0(16) = %04x\n", data);
+ mc68328->regs.csa0 &= ~(mem_mask << 16);
+ mc68328->regs.csa0 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x114:
+ verboselog(space.machine(), 5, "mc68328_w: CSA1(0) = %04x\n", data);
+ mc68328->regs.csa1 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csa1 |= data & mem_mask;
+ break;
+
+ case 0x116:
+ verboselog(space.machine(), 5, "mc68328_w: CSA1(16) = %04x\n", data);
+ mc68328->regs.csa1 &= ~(mem_mask << 16);
+ mc68328->regs.csa1 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x118:
+ verboselog(space.machine(), 5, "mc68328_w: CSA2(0) = %04x\n", data);
+ mc68328->regs.csa2 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csa2 |= data & mem_mask;
+ break;
+
+ case 0x11a:
+ verboselog(space.machine(), 5, "mc68328_w: CSA2(16) = %04x\n", data);
+ mc68328->regs.csa2 &= ~(mem_mask << 16);
+ mc68328->regs.csa2 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x11c:
+ verboselog(space.machine(), 5, "mc68328_w: CSA3(0) = %04x\n", data);
+ mc68328->regs.csa3 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csa3 |= data & mem_mask;
+ break;
+
+ case 0x11e:
+ verboselog(space.machine(), 5, "mc68328_w: CSA3(16) = %04x\n", data);
+ mc68328->regs.csa3 &= ~(mem_mask << 16);
+ mc68328->regs.csa3 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x120:
+ verboselog(space.machine(), 5, "mc68328_w: CSB0(0) = %04x\n", data);
+ mc68328->regs.csb0 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csb0 |= data & mem_mask;
+ break;
+
+ case 0x122:
+ verboselog(space.machine(), 5, "mc68328_w: CSB0(16) = %04x\n", data);
+ mc68328->regs.csb0 &= ~(mem_mask << 16);
+ mc68328->regs.csb0 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x124:
+ verboselog(space.machine(), 5, "mc68328_w: CSB1(0) = %04x\n", data);
+ mc68328->regs.csb1 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csb1 |= data & mem_mask;
+ break;
+
+ case 0x126:
+ verboselog(space.machine(), 5, "mc68328_w: CSB1(16) = %04x\n", data);
+ mc68328->regs.csb1 &= ~(mem_mask << 16);
+ mc68328->regs.csb1 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x128:
+ verboselog(space.machine(), 5, "mc68328_w: CSB2(0) = %04x\n", data);
+ mc68328->regs.csb2 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csb2 |= data & mem_mask;
+ break;
+
+ case 0x12a:
+ verboselog(space.machine(), 5, "mc68328_w: CSB2(16) = %04x\n", data);
+ mc68328->regs.csb2 &= ~(mem_mask << 16);
+ mc68328->regs.csb2 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x12c:
+ verboselog(space.machine(), 5, "mc68328_w: CSB3(0) = %04x\n", data);
+ mc68328->regs.csb3 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csb3 |= data & mem_mask;
+ break;
+
+ case 0x12e:
+ verboselog(space.machine(), 5, "mc68328_w: CSB3(16) = %04x\n", data);
+ mc68328->regs.csb3 &= ~(mem_mask << 16);
+ mc68328->regs.csb3 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x130:
+ verboselog(space.machine(), 5, "mc68328_w: CSC0(0) = %04x\n", data);
+ mc68328->regs.csc0 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csc0 |= data & mem_mask;
+ break;
+
+ case 0x132:
+ verboselog(space.machine(), 5, "mc68328_w: CSC0(16) = %04x\n", data);
+ mc68328->regs.csc0 &= ~(mem_mask << 16);
+ mc68328->regs.csc0 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x134:
+ verboselog(space.machine(), 5, "mc68328_w: CSC1(0) = %04x\n", data);
+ mc68328->regs.csc1 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csc1 |= data & mem_mask;
+ break;
+
+ case 0x136:
+ verboselog(space.machine(), 5, "mc68328_w: CSC1(16) = %04x\n", data);
+ mc68328->regs.csc1 &= ~(mem_mask << 16);
+ mc68328->regs.csc1 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x138:
+ verboselog(space.machine(), 5, "mc68328_w: CSC2(0) = %04x\n", data);
+ mc68328->regs.csc2 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csc2 |= data & mem_mask;
+ break;
+
+ case 0x13a:
+ verboselog(space.machine(), 5, "mc68328_w: CSC2(16) = %04x\n", data);
+ mc68328->regs.csc2 &= ~(mem_mask << 16);
+ mc68328->regs.csc2 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x13c:
+ verboselog(space.machine(), 5, "mc68328_w: CSC3(0) = %04x\n", data);
+ mc68328->regs.csc3 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csc3 |= data & mem_mask;
+ break;
+
+ case 0x13e:
+ verboselog(space.machine(), 5, "mc68328_w: CSC3(16) = %04x\n", data);
+ mc68328->regs.csc3 &= ~(mem_mask << 16);
+ mc68328->regs.csc3 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x140:
+ verboselog(space.machine(), 5, "mc68328_w: CSD0(0) = %04x\n", data);
+ mc68328->regs.csd0 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csd0 |= data & mem_mask;
+ break;
+
+ case 0x142:
+ verboselog(space.machine(), 5, "mc68328_w: CSD0(16) = %04x\n", data);
+ mc68328->regs.csd0 &= ~(mem_mask << 16);
+ mc68328->regs.csd0 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x144:
+ verboselog(space.machine(), 5, "mc68328_w: CSD1(0) = %04x\n", data);
+ mc68328->regs.csd1 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csd1 |= data & mem_mask;
+ break;
+
+ case 0x146:
+ verboselog(space.machine(), 5, "mc68328_w: CSD1(16) = %04x\n", data);
+ mc68328->regs.csd1 &= ~(mem_mask << 16);
+ mc68328->regs.csd1 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x148:
+ verboselog(space.machine(), 5, "mc68328_w: CSD2(0) = %04x\n", data);
+ mc68328->regs.csd2 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csd2 |= data & mem_mask;
+ break;
+
+ case 0x14a:
+ verboselog(space.machine(), 5, "mc68328_w: CSD2(16) = %04x\n", data);
+ mc68328->regs.csd2 &= ~(mem_mask << 16);
+ mc68328->regs.csd2 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x14c:
+ verboselog(space.machine(), 5, "mc68328_w: CSD3(0) = %04x\n", data);
+ mc68328->regs.csd3 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csd3 |= data & mem_mask;
+ break;
+
+ case 0x14e:
+ verboselog(space.machine(), 5, "mc68328_w: CSD3(16) = %04x\n", data);
+ mc68328->regs.csd3 &= ~(mem_mask << 16);
+ mc68328->regs.csd3 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x200:
+ verboselog(space.machine(), 2, "mc68328_w: PLLCR = %04x\n", data);
+ mc68328->regs.pllcr = data;
+ break;
+
+ case 0x202:
+ verboselog(space.machine(), 2, "mc68328_w: PLLFSR = %04x\n", data);
+ mc68328->regs.pllfsr = data;
+ break;
+
+ case 0x206:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PCTLR = %02x\n", data & 0x00ff);
+ mc68328->regs.pctlr = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff206) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x300:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff301) = %02x\n", data & 0x00ff);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: IVR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.ivr = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x302:
+ verboselog(space.machine(), 2, "mc68328_w: ICR = %04x\n", data);
+ mc68328->regs.icr = data;
+ break;
+
+ case 0x304:
+ verboselog(space.machine(), 2, "mc68328_w: IMR(16) = %04x\n", data);
+ mc68328->regs.imr &= ~(mem_mask << 16);
+ mc68328->regs.imr |= (data & mem_mask) << 16;
+ mc68328->regs.isr &= ~((data & mem_mask) << 16);
+
+ imr_diff = imr_old ^ mc68328->regs.imr;
+ mc68328_set_interrupt_line(device, imr_diff, 0);
+ break;
+
+ case 0x306:
+ verboselog(space.machine(), 2, "mc68328_w: IMR(0) = %04x\n", data);
+ mc68328->regs.imr &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.imr |= data & mem_mask;
+ mc68328->regs.isr &= ~(data & mem_mask);
+
+ imr_diff = imr_old ^ mc68328->regs.imr;
+ mc68328_set_interrupt_line(device, imr_diff, 0);
+ break;
+
+ case 0x308:
+ {
+ verboselog(space.machine(), 2, "mc68328_w: IWR(16) = %04x\n", data);
+ mc68328->regs.iwr &= ~(mem_mask << 16);
+ mc68328->regs.iwr |= (data & mem_mask) << 16;
+ }
+ break;
+
+ case 0x30a:
+ verboselog(space.machine(), 2, "mc68328_w: IWR(0) = %04x\n", data);
+ mc68328->regs.iwr &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.iwr |= data & mem_mask;
+ break;
+
+ case 0x30c:
+ verboselog(space.machine(), 2, "mc68328_w: ISR(16) = %04x\n", data);
+ // Clear edge-triggered IRQ1
+ if((mc68328->regs.icr & ICR_ET1) == ICR_ET1 && (data & INT_IRQ1_SHIFT) == INT_IRQ1_SHIFT)
+ {
+ mc68328->regs.isr &= ~INT_IRQ1;
+ }
+
+ // Clear edge-triggered IRQ2
+ if((mc68328->regs.icr & ICR_ET2) == ICR_ET2 && (data & INT_IRQ2_SHIFT) == INT_IRQ2_SHIFT)
+ {
+ mc68328->regs.isr &= ~INT_IRQ2;
+ }
+
+ // Clear edge-triggered IRQ3
+ if((mc68328->regs.icr & ICR_ET3) == ICR_ET3 && (data & INT_IRQ3_SHIFT) == INT_IRQ3_SHIFT)
+ {
+ mc68328->regs.isr &= ~INT_IRQ3;
+ }
+
+ // Clear edge-triggered IRQ6
+ if((mc68328->regs.icr & ICR_ET6) == ICR_ET6 && (data & INT_IRQ6_SHIFT) == INT_IRQ6_SHIFT)
+ {
+ mc68328->regs.isr &= ~INT_IRQ6;
+ }
+
+ // Clear edge-triggered IRQ7
+ if((data & INT_IRQ7_SHIFT) == INT_IRQ7_SHIFT)
+ {
+ mc68328->regs.isr &= ~INT_IRQ7;
+ }
+ break;
+
+ case 0x30e:
+ verboselog(space.machine(), 2, "mc68328_w: ISR(0) = %04x (Ignored)\n", data);
+ break;
+
+ case 0x310:
+ verboselog(space.machine(), 2, "mc68328_w: IPR(16) = %04x (Ignored)\n");
+ break;
+
+ case 0x312:
+ verboselog(space.machine(), 2, "mc68328_w: IPR(0) = %04x (Ignored)\n");
+ break;
+
+ case 0x400:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PADATA = %02x\n", data & 0x00ff);
+ mc68328->regs.padata = data & 0x00ff;
+ if(!mc68328->out_port_a.isnull())
+ {
+ mc68328->out_port_a( 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PADIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.padir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x402:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PASEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pasel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff402) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x408:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PBDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pbdata = data & 0x00ff;
+ if(!mc68328->out_port_b.isnull())
+ {
+ mc68328->out_port_b( 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PBDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pbdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x40a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PBSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pbsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff40a) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x410:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PCDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pcdata = data & 0x00ff;
+ if(!mc68328->out_port_c.isnull())
+ {
+ mc68328->out_port_c( 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PCDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pcdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x412:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PCSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pcsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff412) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x418:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PDDATA = %02x\n", data & 0x00ff);
+
+ mc68328->regs.pddataedge &= ~(data & 0x00ff);
+ mc68328_poll_port_d_interrupts(device);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PDDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pddir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x41a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff41b) = %02x\n", data & 0x00ff);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PDPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pdpuen = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x41c:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PDIRQEN = %02x\n", data & 0x00ff);
+ mc68328->regs.pdirqen = data & 0x00ff;
+
+ mc68328_poll_port_d_interrupts(device);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PDPOL = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pdpol = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x41e:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PDIRQEDGE = %02x\n", data & 0x00ff);
+ mc68328->regs.pdirqedge = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff41e) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x420:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PEDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pedata = data & 0x00ff;
+ if(!mc68328->out_port_e.isnull())
+ {
+ mc68328->out_port_e( 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PEDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pedir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x422:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PESEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pesel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PEPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pepuen = (data >> 8) & 0x00ff;
+ mc68328->regs.pedata |= mc68328->regs.pepuen;
+ }
+ break;
+
+ case 0x428:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PFDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pfdata = data & 0x00ff;
+ if(!mc68328->out_port_f.isnull())
+ {
+ mc68328->out_port_f( 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PFDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pfdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x42a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PFSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pfsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PFPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pfpuen = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x430:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PGDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pgdata = data & 0x00ff;
+ if(!mc68328->out_port_g.isnull())
+ {
+ mc68328->out_port_g( 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PGDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pgdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x432:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PGSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pgsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PGPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pgpuen = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x438:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PJDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pjdata = data & 0x00ff;
+ if(!mc68328->out_port_j.isnull())
+ {
+ mc68328->out_port_j( 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PJDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pjdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x43a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PJSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pjsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfff43a) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x440:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PKDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pkdata = data & 0x00ff;
+ if(!mc68328->out_port_k.isnull())
+ {
+ mc68328->out_port_k( 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PKDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pkdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x442:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PKSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pksel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PKPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pgpuen = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x448:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PMDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pmdata = data & 0x00ff;
+ if(!mc68328->out_port_m.isnull())
+ {
+ mc68328->out_port_m( 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PMDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pmdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x44a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PMSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pmsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: PMPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pmpuen = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x500:
+ verboselog(space.machine(), 2, "mc68328_w: PWMC = %04x\n", data);
+
+ mc68328->regs.pwmc = data;
+
+ if(mc68328->regs.pwmc & PWMC_PWMIRQ)
+ {
+ mc68328_set_interrupt_line(device, INT_PWM, 1);
+ }
+
+ mc68328->regs.pwmc &= ~PWMC_LOAD;
+
+ if((mc68328->regs.pwmc & PWMC_PWMEN) != 0 && mc68328->regs.pwmw != 0 && mc68328->regs.pwmp != 0)
+ {
+ UINT32 frequency = 32768 * 506;
+ UINT32 divisor = 4 << (mc68328->regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot.
+ attotime period;
+ frequency /= divisor;
+ period = attotime::from_hz(frequency) * mc68328->regs.pwmw;
+ mc68328->pwm->adjust(period);
+ if(mc68328->regs.pwmc & PWMC_IRQEN)
+ {
+ mc68328_set_interrupt_line(device, INT_PWM, 1);
+ }
+ mc68328->regs.pwmc ^= PWMC_PIN;
+ }
+ else
+ {
+ mc68328->pwm->adjust(attotime::never);
+ }
+ break;
+
+ case 0x502:
+ verboselog(space.machine(), 2, "mc68328_w: PWMP = %04x\n", data);
+ mc68328->regs.pwmp = data;
+ break;
+
+ case 0x504:
+ verboselog(space.machine(), 2, "mc68328_w: PWMW = %04x\n", data);
+ mc68328->regs.pwmw = data;
+ break;
+
+ case 0x506:
+ verboselog(space.machine(), 2, "mc68328_w: PWMCNT = %04x\n", data);
+ mc68328->regs.pwmcnt = 0;
+ break;
+
+ case 0x600:
+ verboselog(space.machine(), 2, "mc68328_w: TCTL1 = %04x\n", data);
+ temp16[0] = mc68328->regs.tctl[0];
+ mc68328->regs.tctl[0] = data;
+ if((temp16[0] & TCTL_TEN) == (mc68328->regs.tctl[0] & TCTL_TEN))
+ {
+ mc68328_maybe_start_timer(device, 0, 0);
+ }
+ else if((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (mc68328->regs.tctl[0] & TCTL_TEN) == TCTL_TEN_ENABLE)
+ {
+ mc68328_maybe_start_timer(device, 0, 1);
+ }
+ break;
+
+ case 0x602:
+ verboselog(space.machine(), 2, "mc68328_w: TPRER1 = %04x\n", data);
+ mc68328->regs.tprer[0] = data;
+ mc68328_maybe_start_timer(device, 0, 0);
+ break;
+
+ case 0x604:
+ verboselog(space.machine(), 2, "mc68328_w: TCMP1 = %04x\n", data);
+ mc68328->regs.tcmp[0] = data;
+ mc68328_maybe_start_timer(device, 0, 0);
+ break;
+
+ case 0x606:
+ verboselog(space.machine(), 2, "mc68328_w: TCR1 = %04x (Ignored)\n", data);
+ break;
+
+ case 0x608:
+ verboselog(space.machine(), 2, "mc68328_w: TCN1 = %04x (Ignored)\n", data);
+ break;
+
+ case 0x60a:
+ verboselog(space.machine(), 5, "mc68328_w: TSTAT1 = %04x\n", data);
+ mc68328->regs.tstat[0] &= ~mc68328->regs.tclear[0];
+ if(!(mc68328->regs.tstat[0] & TSTAT_COMP))
+ {
+ mc68328_set_interrupt_line(device, INT_TIMER1, 0);
+ }
+ break;
+
+ case 0x60c:
+ verboselog(space.machine(), 2, "mc68328_w: TCTL2 = %04x\n", data);
+ temp16[0] = mc68328->regs.tctl[1];
+ mc68328->regs.tctl[1] = data;
+ if((temp16[0] & TCTL_TEN) == (mc68328->regs.tctl[1] & TCTL_TEN))
+ {
+ mc68328_maybe_start_timer(device, 1, 0);
+ }
+ else if((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (mc68328->regs.tctl[1] & TCTL_TEN) == TCTL_TEN_ENABLE)
+ {
+ mc68328_maybe_start_timer(device, 1, 1);
+ }
+ break;
+
+ case 0x60e:
+ verboselog(space.machine(), 2, "mc68328_w: TPRER2 = %04x\n", data);
+ mc68328->regs.tprer[1] = data;
+ mc68328_maybe_start_timer(device, 1, 0);
+ break;
+
+ case 0x610:
+ verboselog(space.machine(), 2, "mc68328_w: TCMP2 = %04x\n", data);
+ mc68328->regs.tcmp[1] = data;
+ mc68328_maybe_start_timer(device, 1, 0);
+ break;
+
+ case 0x612:
+ verboselog(space.machine(), 2, "mc68328_w: TCR2 = %04x (Ignored)\n", data);
+ break;
+
+ case 0x614:
+ verboselog(space.machine(), 2, "mc68328_w: TCN2 = %04x (Ignored)\n", data);
+ break;
+
+ case 0x616:
+ verboselog(space.machine(), 2, "mc68328_w: TSTAT2 = %04x\n", data);
+ mc68328->regs.tstat[1] &= ~mc68328->regs.tclear[1];
+ if(!(mc68328->regs.tstat[1] & TSTAT_COMP))
+ {
+ mc68328_set_interrupt_line(device, INT_TIMER2, 0);
+ }
+ break;
+
+ case 0x618:
+ verboselog(space.machine(), 2, "mc68328_w: WCTLR = %04x\n", data);
+ mc68328->regs.wctlr = data;
+ break;
+
+ case 0x61a:
+ verboselog(space.machine(), 2, "mc68328_w: WCMPR = %04x\n", data);
+ mc68328->regs.wcmpr = data;
+ break;
+
+ case 0x61c:
+ verboselog(space.machine(), 2, "mc68328_w: WCN = %04x (Ignored)\n", data);
+ break;
+
+ case 0x700:
+ verboselog(space.machine(), 2, "mc68328_w: SPISR = %04x\n", data);
+ mc68328->regs.spisr = data;
+ break;
+
+ case 0x800:
+ verboselog(space.machine(), 2, "mc68328_w: SPIMDATA = %04x\n", data);
+ if(!mc68328->out_spim.isnull())
+ {
+ mc68328->out_spim( 0, data, 0xffff );
+ }
+ else
+ {
+ mc68328->regs.spimdata = data;
+ }
+ break;
+
+ case 0x802:
+ verboselog(space.machine(), 2, "mc68328_w: SPIMCONT = %04x\n", data);
+ verboselog(space.machine(), 3, " Count = %d\n", data & SPIM_CLOCK_COUNT);
+ verboselog(space.machine(), 3, " Polarity = %s\n", (data & SPIM_POL) ? "Inverted" : "Active-high");
+ verboselog(space.machine(), 3, " Phase = %s\n", (data & SPIM_PHA) ? "Opposite" : "Normal");
+ verboselog(space.machine(), 3, " IRQ Enable = %s\n", (data & SPIM_IRQEN) ? "Enable" : "Disable");
+ verboselog(space.machine(), 3, " IRQ Pending = %s\n", (data & SPIM_SPIMIRQ) ? "Yes" : "No");
+ verboselog(space.machine(), 3, " Exchange = %s\n", (data & SPIM_XCH) ? "Initiate" : "Idle");
+ verboselog(space.machine(), 3, " SPIM Enable = %s\n", (data & SPIM_SPMEN) ? "Enable" : "Disable");
+ verboselog(space.machine(), 3, " Data Rate = Divide By %d\n", 1 << ((((data & SPIM_RATE) >> 13) & 0x0007) + 2) );
+ mc68328->regs.spimcont = data;
+ // $$HACK$$ We should probably emulate the ADS7843 A/D device properly.
+ if(data & SPIM_XCH)
+ {
+ mc68328->regs.spimcont &= ~SPIM_XCH;
+ if(mc68328->iface->spim_xch_trigger)
+ {
+ (mc68328->iface->spim_xch_trigger)( device );
+ }
+ if(data & SPIM_IRQEN)
+ {
+ mc68328->regs.spimcont |= SPIM_SPIMIRQ;
+ verboselog(space.machine(), 3, "Triggering SPIM Interrupt\n" );
+ mc68328_set_interrupt_line(device, INT_SPIM, 1);
+ }
+ }
+ if(!(data & SPIM_IRQEN))
+ {
+ mc68328_set_interrupt_line(device, INT_SPIM, 0);
+ }
+ break;
+
+ case 0x900:
+ verboselog(space.machine(), 2, "mc68328_w: USTCNT = %04x\n", data);
+ mc68328->regs.ustcnt = data;
+ break;
+
+ case 0x902:
+ verboselog(space.machine(), 2, "mc68328_w: UBAUD = %04x\n", data);
+ mc68328->regs.ubaud = data;
+ break;
+
+ case 0x904:
+ verboselog(space.machine(), 2, "mc68328_w: URX = %04x\n", data);
+ break;
+
+ case 0x906:
+ verboselog(space.machine(), 2, "mc68328_w: UTX = %04x\n", data);
+ break;
+
+ case 0x908:
+ verboselog(space.machine(), 2, "mc68328_w: UMISC = %04x\n", data);
+ mc68328->regs.umisc = data;
+ break;
+
+ case 0xa00:
+ verboselog(space.machine(), 2, "mc68328_w: LSSA(16) = %04x\n", data);
+ mc68328->regs.lssa &= ~(mem_mask << 16);
+ mc68328->regs.lssa |= (data & mem_mask) << 16;
+ verboselog(space.machine(), 3, " Address: %08x\n", mc68328->regs.lssa);
+ break;
+
+ case 0xa02:
+ verboselog(space.machine(), 2, "mc68328_w: LSSA(0) = %04x\n", data);
+ mc68328->regs.lssa &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.lssa |= data & mem_mask;
+ verboselog(space.machine(), 3, " Address: %08x\n", mc68328->regs.lssa);
+ break;
+
+ case 0xa04:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LVPW = %02x\n", data & 0x00ff);
+ mc68328->regs.lvpw = data & 0x00ff;
+ verboselog(space.machine(), 3, " Page Width: %d or %d\n", (mc68328->regs.lvpw + 1) * ((mc68328->regs.lpicf & 0x01) ? 8 : 16));
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa04) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa08:
+ verboselog(space.machine(), 2, "mc68328_w: LXMAX = %04x\n", data);
+ mc68328->regs.lxmax = data;
+ verboselog(space.machine(), 3, " Width: %d\n", (data & 0x03ff) + 1);
+ break;
+
+ case 0xa0a:
+ verboselog(space.machine(), 2, "mc68328_w: LYMAX = %04x\n", data);
+ mc68328->regs.lymax = data;
+ verboselog(space.machine(), 3, " Height: %d\n", (data & 0x03ff) + 1);
+ break;
+
+ case 0xa18:
+ verboselog(space.machine(), 2, "mc68328_w: LCXP = %04x\n", data);
+ mc68328->regs.lcxp = data;
+ verboselog(space.machine(), 3, " X Position: %d\n", data & 0x03ff);
+ switch(mc68328->regs.lcxp >> 14)
+ {
+ case 0:
+ verboselog(space.machine(), 3, " Cursor Control: Transparent\n");
+ break;
+
+ case 1:
+ verboselog(space.machine(), 3, " Cursor Control: Black\n");
+ break;
+
+ case 2:
+ verboselog(space.machine(), 3, " Cursor Control: Reverse\n");
+ break;
+
+ case 3:
+ verboselog(space.machine(), 3, " Cursor Control: Invalid\n");
+ break;
+ }
+ break;
+
+ case 0xa1a:
+ verboselog(space.machine(), 2, "mc68328_w: LCYP = %04x\n", data);
+ mc68328->regs.lcyp = data;
+ verboselog(space.machine(), 3, " Y Position: %d\n", data & 0x01ff);
+ break;
+
+ case 0xa1c:
+ verboselog(space.machine(), 2, "mc68328_w: LCWCH = %04x\n", data);
+ mc68328->regs.lcwch = data;
+ verboselog(space.machine(), 3, " Width: %d\n", (data >> 8) & 0x1f);
+ verboselog(space.machine(), 3, " Height: %d\n", data & 0x1f);
+ break;
+
+ case 0xa1e:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LBLKC = %02x\n", data & 0x00ff);
+ mc68328->regs.lblkc = data & 0x00ff;
+ verboselog(space.machine(), 3, " Blink Enable: %d\n", mc68328->regs.lblkc >> 7);
+ verboselog(space.machine(), 3, " Blink Divisor: %d\n", mc68328->regs.lblkc & 0x7f);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa1e) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa20:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LPOLCF = %02x\n", data & 0x00ff);
+ mc68328->regs.lpolcf = data & 0x00ff;
+ verboselog(space.machine(), 3, " LCD Shift Clock Polarity: %s\n", (mc68328->regs.lpicf & 0x08) ? "Active positive edge of LCLK" : "Active negative edge of LCLK");
+ verboselog(space.machine(), 3, " First-line marker polarity: %s\n", (mc68328->regs.lpicf & 0x04) ? "Active Low" : "Active High");
+ verboselog(space.machine(), 3, " Line-pulse polarity: %s\n", (mc68328->regs.lpicf & 0x02) ? "Active Low" : "Active High");
+ verboselog(space.machine(), 3, " Pixel polarity: %s\n", (mc68328->regs.lpicf & 0x01) ? "Active Low" : "Active High");
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LPICF = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.lpicf = (data >> 8) & 0x00ff;
+ switch((mc68328->regs.lpicf >> 1) & 0x03)
+ {
+ case 0:
+ verboselog(space.machine(), 3, " Bus Size: 1-bit\n");
+ break;
+
+ case 1:
+ verboselog(space.machine(), 3, " Bus Size: 2-bit\n");
+ break;
+
+ case 2:
+ verboselog(space.machine(), 3, " Bus Size: 4-bit\n");
+ break;
+
+ case 3:
+ verboselog(space.machine(), 3, " Bus Size: unused\n");
+ break;
+ }
+ verboselog(space.machine(), 3, " Gray scale enable: %d\n", mc68328->regs.lpicf & 0x01);
+ }
+ break;
+
+ case 0xa22:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LACDRC = %02x\n", data & 0x00ff);
+ mc68328->regs.lacdrc = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa22) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa24:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LPXCD = %02x\n", data & 0x00ff);
+ mc68328->regs.lpxcd = data & 0x00ff;
+ verboselog(space.machine(), 3, " Clock Divisor: %d\n", mc68328->regs.lpxcd + 1);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa24) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa26:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LCKCON = %02x\n", data & 0x00ff);
+ mc68328->regs.lckcon = data & 0x00ff;
+ verboselog(space.machine(), 3, " LCDC Enable: %d\n", (mc68328->regs.lckcon >> 7) & 0x01);
+ verboselog(space.machine(), 3, " DMA Burst Length: %d\n", ((mc68328->regs.lckcon >> 6) & 0x01) ? 16 : 8);
+ verboselog(space.machine(), 3, " DMA Bursting Clock Control: %d\n", ((mc68328->regs.lckcon >> 4) & 0x03) + 1);
+ verboselog(space.machine(), 3, " Bus Width: %d\n", ((mc68328->regs.lckcon >> 1) & 0x01) ? 8 : 16);
+ verboselog(space.machine(), 3, " Pixel Clock Divider Source: %s\n", (mc68328->regs.lckcon & 0x01) ? "PIX" : "SYS");
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa26) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa28:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LLBAR = %02x\n", data & 0x00ff);
+ mc68328->regs.llbar = data & 0x00ff;
+ verboselog(space.machine(), 3, " Address: %d\n", (mc68328->regs.llbar & 0x7f) * ((mc68328->regs.lpicf & 0x01) ? 8 : 16));
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa28) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa2a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LOTCR = %02x\n", data & 0x00ff);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa2a) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa2c:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LPOSR = %02x\n", data & 0x00ff);
+ mc68328->regs.lposr = data & 0x00ff;
+ verboselog(space.machine(), 3, " Byte Offset: %d\n", (mc68328->regs.lposr >> 3) & 0x01);
+ verboselog(space.machine(), 3, " Pixel Offset: %d\n", mc68328->regs.lposr & 0x07);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa2c) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa30:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_w: LFRCM = %02x\n", data & 0x00ff);
+ mc68328->regs.lfrcm = data & 0x00ff;
+ verboselog(space.machine(), 3, " X Modulation: %d\n", (mc68328->regs.lfrcm >> 4) & 0x0f);
+ verboselog(space.machine(), 3, " Y Modulation: %d\n", mc68328->regs.lfrcm & 0x0f);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_w: Unknown address (0xfffa30) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa32:
+ verboselog(space.machine(), 2, "mc68328_w: LGPMR = %04x\n", data);
+ mc68328->regs.lgpmr = data;
+ verboselog(space.machine(), 3, " Palette 0: %d\n", (mc68328->regs.lgpmr >> 8) & 0x07);
+ verboselog(space.machine(), 3, " Palette 1: %d\n", (mc68328->regs.lgpmr >> 12) & 0x07);
+ verboselog(space.machine(), 3, " Palette 2: %d\n", (mc68328->regs.lgpmr >> 0) & 0x07);
+ verboselog(space.machine(), 3, " Palette 3: %d\n", (mc68328->regs.lgpmr >> 4) & 0x07);
+ break;
+
+ case 0xb00:
+ verboselog(space.machine(), 2, "mc68328_w: HMSR(0) = %04x\n", data);
+ mc68328->regs.hmsr &= ~(mem_mask << 16);
+ mc68328->regs.hmsr |= (data & mem_mask) << 16;
+ mc68328->regs.hmsr &= 0x1f3f003f;
+ break;
+
+ case 0xb02:
+ verboselog(space.machine(), 2, "mc68328_w: HMSR(16) = %04x\n", data);
+ mc68328->regs.hmsr &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.hmsr |= data & mem_mask;
+ mc68328->regs.hmsr &= 0x1f3f003f;
+ break;
+
+ case 0xb04:
+ verboselog(space.machine(), 2, "mc68328_w: ALARM(0) = %04x\n", data);
+ mc68328->regs.alarm &= ~(mem_mask << 16);
+ mc68328->regs.alarm |= (data & mem_mask) << 16;
+ mc68328->regs.alarm &= 0x1f3f003f;
+ break;
+
+ case 0xb06:
+ verboselog(space.machine(), 2, "mc68328_w: ALARM(16) = %04x\n", data);
+ mc68328->regs.alarm &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.alarm |= data & mem_mask;
+ mc68328->regs.alarm &= 0x1f3f003f;
+ break;
+
+ case 0xb0c:
+ verboselog(space.machine(), 2, "mc68328_w: RTCCTL = %04x\n", data);
+ mc68328->regs.rtcctl = data & 0x00a0;
+ break;
+
+ case 0xb0e:
+ verboselog(space.machine(), 2, "mc68328_w: RTCISR = %04x\n", data);
+ mc68328->regs.rtcisr &= ~data;
+ if(mc68328->regs.rtcisr == 0)
+ {
+ mc68328_set_interrupt_line(device, INT_RTC, 0);
+ }
+ break;
+
+ case 0xb10:
+ verboselog(space.machine(), 2, "mc68328_w: RTCIENR = %04x\n", data);
+ mc68328->regs.rtcienr = data & 0x001f;
+ break;
+
+ case 0xb12:
+ verboselog(space.machine(), 2, "mc68328_w: STPWTCH = %04x\n", data);
+ mc68328->regs.stpwtch = data & 0x003f;
+ break;
+
+ default:
+ verboselog(space.machine(), 0, "mc68328_w: Unknown address (0x%06x) = %04x (%04x)\n", 0xfff000 + address, data, mem_mask);
+ break;
+ }
+}
+
+READ16_DEVICE_HANDLER( mc68328_r )
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ UINT16 temp16 = 0;
+ UINT32 address = offset << 1;
+
+ switch(address)
+ {
+ case 0x000:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff001)\n", mem_mask);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): SCR = %02x\n", mem_mask, mc68328->regs.scr);
+ return mc68328->regs.scr << 8;
+ }
+ break;
+
+ case 0x100:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASEA = %04x\n", mem_mask, mc68328->regs.grpbasea);
+ return mc68328->regs.grpbasea;
+
+ case 0x102:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASEB = %04x\n", mem_mask, mc68328->regs.grpbaseb);
+ return mc68328->regs.grpbaseb;
+
+ case 0x104:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASEC = %04x\n", mem_mask, mc68328->regs.grpbasec);
+ return mc68328->regs.grpbasec;
+
+ case 0x106:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): GRPBASED = %04x\n", mem_mask, mc68328->regs.grpbased);
+ return mc68328->regs.grpbased;
+
+ case 0x108:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKA = %04x\n", mem_mask, mc68328->regs.grpmaska);
+ return mc68328->regs.grpmaska;
+
+ case 0x10a:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKB = %04x\n", mem_mask, mc68328->regs.grpmaskb);
+ return mc68328->regs.grpmaskb;
+
+ case 0x10c:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKC = %04x\n", mem_mask, mc68328->regs.grpmaskc);
+ return mc68328->regs.grpmaskc;
+
+ case 0x10e:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): GRPMASKD = %04x\n", mem_mask, mc68328->regs.grpmaskd);
+ return mc68328->regs.grpmaskd;
+
+ case 0x110:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSA0(0) = %04x\n", mem_mask, mc68328->regs.csa0 & 0x0000ffff);
+ return mc68328->regs.csa0 & 0x0000ffff;
+
+ case 0x112:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSA0(16) = %04x\n", mem_mask, mc68328->regs.csa0 >> 16);
+ return mc68328->regs.csa0 >> 16;
+
+ case 0x114:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSA1(0) = %04x\n", mem_mask, mc68328->regs.csa1 & 0x0000ffff);
+ return mc68328->regs.csa1 & 0x0000ffff;
+
+ case 0x116:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSA1(16) = %04x\n", mem_mask, mc68328->regs.csa1 >> 16);
+ return mc68328->regs.csa1 >> 16;
+
+ case 0x118:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSA2(0) = %04x\n", mem_mask, mc68328->regs.csa2 & 0x0000ffff);
+ return mc68328->regs.csa2 & 0x0000ffff;
+
+ case 0x11a:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSA2(16) = %04x\n", mem_mask, mc68328->regs.csa2 >> 16);
+ return mc68328->regs.csa2 >> 16;
+
+ case 0x11c:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSA3(0) = %04x\n", mem_mask, mc68328->regs.csa3 & 0x0000ffff);
+ return mc68328->regs.csa3 & 0x0000ffff;
+
+ case 0x11e:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSA3(16) = %04x\n", mem_mask, mc68328->regs.csa3 >> 16);
+ return mc68328->regs.csa3 >> 16;
+
+ case 0x120:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSB0(0) = %04x\n", mem_mask, mc68328->regs.csb0 & 0x0000ffff);
+ return mc68328->regs.csb0 & 0x0000ffff;
+
+ case 0x122:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSB0(16) = %04x\n", mem_mask, mc68328->regs.csb0 >> 16);
+ return mc68328->regs.csb0 >> 16;
+
+ case 0x124:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSB1(0) = %04x\n", mem_mask, mc68328->regs.csb1 & 0x0000ffff);
+ return mc68328->regs.csb1 & 0x0000ffff;
+
+ case 0x126:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSB1(16) = %04x\n", mem_mask, mc68328->regs.csb1 >> 16);
+ return mc68328->regs.csb1 >> 16;
+
+ case 0x128:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSB2(0) = %04x\n", mem_mask, mc68328->regs.csb2 & 0x0000ffff);
+ return mc68328->regs.csb2 & 0x0000ffff;
+
+ case 0x12a:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSB2(16) = %04x\n", mem_mask, mc68328->regs.csb2 >> 16);
+ return mc68328->regs.csb2 >> 16;
+
+ case 0x12c:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSB3(0) = %04x\n", mem_mask, mc68328->regs.csb3 & 0x0000ffff);
+ return mc68328->regs.csb3 & 0x0000ffff;
+
+ case 0x12e:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSB3(16) = %04x\n", mem_mask, mc68328->regs.csb3 >> 16);
+ return mc68328->regs.csb3 >> 16;
+
+ case 0x130:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSC0(0) = %04x\n", mem_mask, mc68328->regs.csc0 & 0x0000ffff);
+ return mc68328->regs.csc0 & 0x0000ffff;
+
+ case 0x132:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSC0(16) = %04x\n", mem_mask, mc68328->regs.csc0 >> 16);
+ return mc68328->regs.csc0 >> 16;
+
+ case 0x134:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSC1(0) = %04x\n", mem_mask, mc68328->regs.csc1 & 0x0000ffff);
+ return mc68328->regs.csc1 & 0x0000ffff;
+
+ case 0x136:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSC1(16) = %04x\n", mem_mask, mc68328->regs.csc1 >> 16);
+ return mc68328->regs.csc1 >> 16;
+
+ case 0x138:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSC2(0) = %04x\n", mem_mask, mc68328->regs.csc2 & 0x0000ffff);
+ return mc68328->regs.csc2 & 0x0000ffff;
+
+ case 0x13a:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSC2(16) = %04x\n", mem_mask, mc68328->regs.csc2 >> 16);
+ return mc68328->regs.csc2 >> 16;
+
+ case 0x13c:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSC3(0) = %04x\n", mem_mask, mc68328->regs.csc3 & 0x0000ffff);
+ return mc68328->regs.csc3 & 0x0000ffff;
+
+ case 0x13e:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSC3(16) = %04x\n", mem_mask, mc68328->regs.csc3 >> 16);
+ return mc68328->regs.csc3 >> 16;
+
+ case 0x140:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSD0(0) = %04x\n", mem_mask, mc68328->regs.csd0 & 0x0000ffff);
+ return mc68328->regs.csd0 & 0x0000ffff;
+
+ case 0x142:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSD0(16) = %04x\n", mem_mask, mc68328->regs.csd0 >> 16);
+ return mc68328->regs.csd0 >> 16;
+
+ case 0x144:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSD1(0) = %04x\n", mem_mask, mc68328->regs.csd1 & 0x0000ffff);
+ return mc68328->regs.csd1 & 0x0000ffff;
+
+ case 0x146:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSD1(16) = %04x\n", mem_mask, mc68328->regs.csd1 >> 16);
+ return mc68328->regs.csd1 >> 16;
+
+ case 0x148:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSD2(0) = %04x\n", mem_mask, mc68328->regs.csd2 & 0x0000ffff);
+ return mc68328->regs.csd2 & 0x0000ffff;
+
+ case 0x14a:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSD2(16) = %04x\n", mem_mask, mc68328->regs.csd2 >> 16);
+ return mc68328->regs.csd2 >> 16;
+
+ case 0x14c:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSD3(0) = %04x\n", mem_mask, mc68328->regs.csd3 & 0x0000ffff);
+ return mc68328->regs.csd3 & 0x0000ffff;
+
+ case 0x14e:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): CSD3(16) = %04x\n", mem_mask, mc68328->regs.csd3 >> 16);
+ return mc68328->regs.csd3 >> 16;
+
+ case 0x200:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PLLCR = %04x\n", mem_mask, mc68328->regs.pllcr);
+ return mc68328->regs.pllcr;
+
+ case 0x202:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PLLFSR = %04x\n", mem_mask, mc68328->regs.pllfsr);
+ mc68328->regs.pllfsr ^= 0x8000;
+ return mc68328->regs.pllfsr;
+
+ case 0x206:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff206)\n", mem_mask);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PCTLR = %02x\n", mem_mask, mc68328->regs.pctlr);
+ return mc68328->regs.pctlr << 8;
+ }
+ break;
+
+ case 0x300:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff301)\n", mem_mask);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): IVR = %02x\n", mem_mask, mc68328->regs.ivr);
+ return mc68328->regs.ivr << 8;
+ }
+ break;
+
+ case 0x302:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): ICR = %04x\n", mem_mask, mc68328->regs.icr);
+ return mc68328->regs.icr;
+
+ case 0x304:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): IMR(16) = %04x\n", mem_mask, mc68328->regs.imr >> 16);
+ return mc68328->regs.imr >> 16;
+
+ case 0x306:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): IMR(0) = %04x\n", mem_mask, mc68328->regs.imr & 0x0000ffff);
+ return mc68328->regs.imr & 0x0000ffff;
+
+ case 0x308:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): IWR(16) = %04x\n", mem_mask, mc68328->regs.iwr >> 16);
+ return mc68328->regs.iwr >> 16;
+
+ case 0x30a:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): IWR(0) = %04x\n", mem_mask, mc68328->regs.iwr & 0x0000ffff);
+ return mc68328->regs.iwr & 0x0000ffff;
+
+ case 0x30c:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): ISR(16) = %04x\n", mem_mask, mc68328->regs.isr >> 16);
+ return mc68328->regs.isr >> 16;
+
+ case 0x30e:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): ISR(0) = %04x\n", mem_mask, mc68328->regs.isr & 0x0000ffff);
+ return mc68328->regs.isr & 0x0000ffff;
+
+ case 0x310:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): IPR(16) = %04x\n", mem_mask, mc68328->regs.ipr >> 16);
+ return mc68328->regs.ipr >> 16;
+
+ case 0x312:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): IPR(0) = %04x\n", mem_mask, mc68328->regs.ipr & 0x0000ffff);
+ return mc68328->regs.ipr & 0x0000ffff;
+
+ case 0x400:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PADATA = %02x\n", mem_mask, mc68328->regs.padata);
+ if(!mc68328->in_port_a.isnull())
+ {
+ return mc68328->in_port_a( 0 );
+ }
+ else
+ {
+ return mc68328->regs.padata;
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PADIR = %02x\n", mem_mask, mc68328->regs.padir);
+ return mc68328->regs.padir << 8;
+ }
+ break;
+
+ case 0x402:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PASEL = %02x\n", mem_mask, mc68328->regs.pasel);
+ return mc68328->regs.pasel;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff402)\n", mem_mask);
+ }
+ break;
+
+ case 0x408:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PBDATA = %02x\n", mem_mask, mc68328->regs.pbdata);
+ if(!mc68328->in_port_b.isnull())
+ {
+ return mc68328->in_port_b( 0 );
+ }
+ else
+ {
+ return mc68328->regs.pbdata;
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PBDIR = %02x\n", mem_mask, mc68328->regs.pbdir);
+ return mc68328->regs.pbdir << 8;
+ }
+ break;
+
+ case 0x40a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PBSEL = %02x\n", mem_mask, mc68328->regs.pbsel);
+ return mc68328->regs.pbsel;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff40a)\n", mem_mask);
+ }
+ break;
+
+ case 0x410:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PCDATA = %02x\n", mem_mask, mc68328->regs.pcdata);
+ if(!mc68328->in_port_c.isnull())
+ {
+ return mc68328->in_port_c( 0 );
+ }
+ else
+ {
+ return mc68328->regs.pcdata;
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PCDIR = %02x\n", mem_mask, mc68328->regs.pcdir);
+ return mc68328->regs.pcdir << 8;
+ }
+ break;
+
+ case 0x412:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PCSEL = %02x\n", mem_mask, mc68328->regs.pcsel);
+ return mc68328->regs.pcsel;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff412)\n", mem_mask);
+ }
+ break;
+
+ case 0x418:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PDDATA = %02x\n", mem_mask, mc68328->regs.pddata);
+ if(!mc68328->in_port_d.isnull())
+ {
+ return mc68328->in_port_d( 0 );
+ }
+ else
+ {
+ return mc68328->regs.pddata;
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PDDIR = %02x\n", mem_mask, mc68328->regs.pddir);
+ return mc68328->regs.pddir << 8;
+ }
+ break;
+
+ case 0x41a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff41b)\n", mem_mask);
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PDPUEN = %02x\n", mem_mask, mc68328->regs.pdpuen);
+ return mc68328->regs.pdpuen << 8;
+ }
+ break;
+
+ case 0x41c:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PDIRQEN = %02x\n", mem_mask, mc68328->regs.pdirqen);
+ return mc68328->regs.pdirqen;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PDPOL = %02x\n", mem_mask, mc68328->regs.pdpol);
+ return mc68328->regs.pdpol << 8;
+ }
+ break;
+
+ case 0x41e:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PDIRQEDGE = %02x\n", mem_mask, mc68328->regs.pdirqedge);
+ return mc68328->regs.pdirqedge;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff41e)\n", mem_mask);
+ }
+ break;
+
+ case 0x420:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PEDATA = %02x\n", mem_mask, mc68328->regs.pedata);
+ if(!mc68328->in_port_e.isnull())
+ {
+ return mc68328->in_port_e( 0 );
+ }
+ else
+ {
+ return mc68328->regs.pedata;
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PEDIR = %02x\n", mem_mask, mc68328->regs.pedir);
+ return mc68328->regs.pedir << 8;
+ }
+ break;
+
+ case 0x422:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PESEL = %02x\n", mem_mask, mc68328->regs.pesel);
+ return mc68328->regs.pesel;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PEPUEN = %02x\n", mem_mask, mc68328->regs.pepuen);
+ return mc68328->regs.pepuen << 8;
+ }
+ break;
+
+ case 0x428:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PFDATA = %02x\n", mem_mask, mc68328->regs.pfdata);
+ if(!mc68328->in_port_f.isnull())
+ {
+ return mc68328->in_port_f( 0 );
+ }
+ else
+ {
+ return mc68328->regs.pfdata;
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PFDIR = %02x\n", mem_mask, mc68328->regs.pfdir);
+ return mc68328->regs.pfdir << 8;
+ }
+ break;
+
+ case 0x42a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PFSEL = %02x\n", mem_mask, mc68328->regs.pfsel);
+ return mc68328->regs.pfsel;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PFPUEN = %02x\n", mem_mask, mc68328->regs.pfpuen);
+ return mc68328->regs.pfpuen << 8;
+ }
+ break;
+
+ case 0x430:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PGDATA = %02x\n", mem_mask, mc68328->regs.pgdata);
+ if(!mc68328->in_port_g.isnull())
+ {
+ return mc68328->in_port_g( 0 );
+ }
+ else
+ {
+ return mc68328->regs.pgdata;
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PGDIR = %02x\n", mem_mask, mc68328->regs.pgdir);
+ return mc68328->regs.pgdir << 8;
+ }
+ break;
+
+ case 0x432:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PGSEL = %02x\n", mem_mask, mc68328->regs.pgsel);
+ return mc68328->regs.pgsel;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PGPUEN = %02x\n", mem_mask, mc68328->regs.pgpuen);
+ return mc68328->regs.pgpuen << 8;
+ }
+ break;
+
+ case 0x438:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PJDATA = %02x\n", mem_mask, mc68328->regs.pjdata);
+ if(!mc68328->in_port_j.isnull())
+ {
+ return mc68328->in_port_j( 0 );
+ }
+ else
+ {
+ return mc68328->regs.pjdata;
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PJDIR = %02x\n", mem_mask, mc68328->regs.pjdir);
+ return mc68328->regs.pjdir << 8;
+ }
+ break;
+
+ case 0x43a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PJSEL = %02x\n", mem_mask, mc68328->regs.pjsel);
+ return mc68328->regs.pjsel;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfff43a)\n", mem_mask);
+ }
+ break;
+
+ case 0x440:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PKDATA = %02x\n", mem_mask, mc68328->regs.pkdata);
+ if(!mc68328->in_port_k.isnull())
+ {
+ return mc68328->in_port_k( 0 );
+ }
+ else
+ {
+ return mc68328->regs.pkdata;
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PKDIR = %02x\n", mem_mask, mc68328->regs.pkdir);
+ return mc68328->regs.pkdir << 8;
+ }
+ break;
+
+ case 0x442:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PKSEL = %02x\n", mem_mask, mc68328->regs.pksel);
+ return mc68328->regs.pksel;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PKPUEN = %02x\n", mem_mask, mc68328->regs.pkpuen);
+ return mc68328->regs.pkpuen << 8;
+ }
+ break;
+
+ case 0x448:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PMDATA = %02x\n", mem_mask, mc68328->regs.pmdata);
+ if(!mc68328->in_port_m.isnull())
+ {
+ return mc68328->in_port_m( 0 );
+ }
+ else
+ {
+ return mc68328->regs.pmdata;
+ }
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PMDIR = %02x\n", mem_mask, mc68328->regs.pmdir);
+ return mc68328->regs.pmdir << 8;
+ }
+ break;
+
+ case 0x44a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PMSEL = %02x\n", mem_mask, mc68328->regs.pmsel);
+ return mc68328->regs.pmsel;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PMPUEN = %02x\n", mem_mask, mc68328->regs.pmpuen);
+ return mc68328->regs.pmpuen << 8;
+ }
+ break;
+
+ case 0x500:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PWMC = %04x\n", mem_mask, mc68328->regs.pwmc);
+ temp16 = mc68328->regs.pwmc;
+ if(mc68328->regs.pwmc & PWMC_PWMIRQ)
+ {
+ mc68328->regs.pwmc &= ~PWMC_PWMIRQ;
+ mc68328_set_interrupt_line(device, INT_PWM, 0);
+ }
+ return temp16;
+
+ case 0x502:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PWMP = %04x\n", mem_mask, mc68328->regs.pwmp);
+ return mc68328->regs.pwmp;
+
+ case 0x504:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PWMW = %04x\n", mem_mask, mc68328->regs.pwmw);
+ return mc68328->regs.pwmw;
+
+ case 0x506:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): PWMCNT = %04x\n", mem_mask, mc68328->regs.pwmcnt);
+ return mc68328->regs.pwmcnt;
+
+ case 0x600:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TCTL1 = %04x\n", mem_mask, mc68328->regs.tctl[0]);
+ return mc68328->regs.tctl[0];
+
+ case 0x602:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TPRER1 = %04x\n", mem_mask, mc68328->regs.tprer[0]);
+ return mc68328->regs.tprer[0];
+
+ case 0x604:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TCMP1 = %04x\n", mem_mask, mc68328->regs.tcmp[0]);
+ return mc68328->regs.tcmp[0];
+
+ case 0x606:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TCR1 = %04x\n", mem_mask, mc68328->regs.tcr[0]);
+ return mc68328->regs.tcr[0];
+
+ case 0x608:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TCN1 = %04x\n", mem_mask, mc68328->regs.tcn[0]);
+ return mc68328->regs.tcn[0];
+
+ case 0x60a:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): TSTAT1 = %04x\n", mem_mask, mc68328->regs.tstat[0]);
+ mc68328->regs.tclear[0] |= mc68328->regs.tstat[0];
+ return mc68328->regs.tstat[0];
+
+ case 0x60c:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TCTL2 = %04x\n", mem_mask, mc68328->regs.tctl[1]);
+ return mc68328->regs.tctl[1];
+
+ case 0x60e:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TPREP2 = %04x\n", mem_mask, mc68328->regs.tprer[1]);
+ return mc68328->regs.tprer[1];
+
+ case 0x610:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TCMP2 = %04x\n", mem_mask, mc68328->regs.tcmp[1]);
+ return mc68328->regs.tcmp[1];
+
+ case 0x612:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TCR2 = %04x\n", mem_mask, mc68328->regs.tcr[1]);
+ return mc68328->regs.tcr[1];
+
+ case 0x614:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TCN2 = %04x\n", mem_mask, mc68328->regs.tcn[1]);
+ return mc68328->regs.tcn[1];
+
+ case 0x616:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): TSTAT2 = %04x\n", mem_mask, mc68328->regs.tstat[1]);
+ mc68328->regs.tclear[1] |= mc68328->regs.tstat[1];
+ return mc68328->regs.tstat[1];
+
+ case 0x618:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): WCTLR = %04x\n", mem_mask, mc68328->regs.wctlr);
+ return mc68328->regs.wctlr;
+
+ case 0x61a:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): WCMPR = %04x\n", mem_mask, mc68328->regs.wcmpr);
+ return mc68328->regs.wcmpr;
+
+ case 0x61c:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): WCN = %04x\n", mem_mask, mc68328->regs.wcn);
+ return mc68328->regs.wcn;
+
+ case 0x700:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): SPISR = %04x\n", mem_mask, mc68328->regs.spisr);
+ return mc68328->regs.spisr;
+
+ case 0x800:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): SPIMDATA = %04x\n", mem_mask, mc68328->regs.spimdata);
+ if(!mc68328->in_spim.isnull())
+ {
+ return mc68328->in_spim( 0, 0xffff );
+ }
+ return mc68328->regs.spimdata;
+
+ case 0x802:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): SPIMCONT = %04x\n", mem_mask, mc68328->regs.spimcont);
+ if(mc68328->regs.spimcont & SPIM_XCH)
+ {
+ mc68328->regs.spimcont &= ~SPIM_XCH;
+ mc68328->regs.spimcont |= SPIM_SPIMIRQ;
+ return ((mc68328->regs.spimcont | SPIM_XCH) &~ SPIM_SPIMIRQ);
+ }
+ return mc68328->regs.spimcont;
+
+ case 0x900:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): USTCNT = %04x\n", mem_mask, mc68328->regs.ustcnt);
+ return mc68328->regs.ustcnt;
+
+ case 0x902:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): UBAUD = %04x\n", mem_mask, mc68328->regs.ubaud);
+ return mc68328->regs.ubaud;
+
+ case 0x904:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): URX = %04x\n", mem_mask, mc68328->regs.urx);
+ return mc68328->regs.urx;
+
+ case 0x906:
+ verboselog(space.machine(), 5, "mc68328_r (%04x): UTX = %04x\n", mem_mask, mc68328->regs.utx);
+ return mc68328->regs.utx | UTX_FIFO_EMPTY | UTX_FIFO_HALF | UTX_TX_AVAIL;
+
+ case 0x908:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): UMISC = %04x\n", mem_mask, mc68328->regs.umisc);
+ return mc68328->regs.umisc;
+
+ case 0xa00:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LSSA(16) = %04x\n", mem_mask, mc68328->regs.lssa >> 16);
+ return mc68328->regs.lssa >> 16;
+
+ case 0xa02:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LSSA(0) = %04x\n", mem_mask, mc68328->regs.lssa & 0x0000ffff);
+ return mc68328->regs.lssa & 0x0000ffff;
+
+ case 0xa04:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LVPW = %02x\n", mem_mask, mc68328->regs.lvpw);
+ return mc68328->regs.lvpw;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa04)\n", mem_mask);
+ }
+ break;
+
+ case 0xa08:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LXMAX = %04x\n", mem_mask, mc68328->regs.lxmax);
+ return mc68328->regs.lxmax;
+
+ case 0xa0a:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LYMAX = %04x\n", mem_mask, mc68328->regs.lymax);
+ return mc68328->regs.lymax;
+
+ case 0xa18:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LCXP = %04x\n", mem_mask, mc68328->regs.lcxp);
+ return mc68328->regs.lcxp;
+
+ case 0xa1a:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LCYP = %04x\n", mem_mask, mc68328->regs.lcyp);
+ return mc68328->regs.lcyp;
+
+ case 0xa1c:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LCWCH = %04x\n", mem_mask, mc68328->regs.lcwch);
+ return mc68328->regs.lcwch;
+
+ case 0xa1e:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LBLKC = %02x\n", mem_mask, mc68328->regs.lblkc);
+ return mc68328->regs.lblkc;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa1e)\n", mem_mask);
+ }
+ break;
+
+ case 0xa20:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LPOLCF = %02x\n", mem_mask, mc68328->regs.lpolcf);
+ return mc68328->regs.lpolcf;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LPICF = %02x\n", mem_mask, mc68328->regs.lpicf);
+ return mc68328->regs.lpicf << 8;
+ }
+ break;
+
+ case 0xa22:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LACDRC = %02x\n", mem_mask, mc68328->regs.lacdrc);
+ return mc68328->regs.lacdrc;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa22)\n", mem_mask);
+ }
+ break;
+
+ case 0xa24:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LPXCD = %02x\n", mem_mask, mc68328->regs.lpxcd);
+ return mc68328->regs.lpxcd;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa24)\n", mem_mask);
+ }
+ break;
+
+ case 0xa26:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LCKCON = %02x\n", mem_mask, mc68328->regs.lckcon);
+ return mc68328->regs.lckcon;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa26)\n", mem_mask);
+ }
+ break;
+
+ case 0xa28:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LLBAR = %02x\n", mem_mask, mc68328->regs.llbar);
+ return mc68328->regs.llbar;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa28)\n", mem_mask);
+ }
+ break;
+
+ case 0xa2a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LOTCR = %02x\n", mem_mask, mc68328->regs.lotcr);
+ return mc68328->regs.lotcr;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa2a)\n", mem_mask);
+ }
+ break;
+
+ case 0xa2c:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LPOSR = %02x\n", mem_mask, mc68328->regs.lposr);
+ return mc68328->regs.lposr;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa2c)\n", mem_mask);
+ }
+ break;
+
+ case 0xa30:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LFRCM = %02x\n", mem_mask, mc68328->regs.lfrcm);
+ return mc68328->regs.lfrcm;
+ }
+ else
+ {
+ verboselog(space.machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa30)\n", mem_mask);
+ }
+ break;
+
+ case 0xa32:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): LGPMR = %04x\n", mem_mask, mc68328->regs.lgpmr);
+ return mc68328->regs.lgpmr;
+
+ case 0xb00:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): HMSR(0) = %04x\n", mem_mask, mc68328->regs.hmsr & 0x0000ffff);
+ return mc68328->regs.hmsr & 0x0000ffff;
+
+ case 0xb02:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): HMSR(16) = %04x\n", mem_mask, mc68328->regs.hmsr >> 16);
+ return mc68328->regs.hmsr >> 16;
+
+ case 0xb04:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): ALARM(0) = %04x\n", mem_mask, mc68328->regs.alarm & 0x0000ffff);
+ return mc68328->regs.alarm & 0x0000ffff;
+
+ case 0xb06:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): ALARM(16) = %04x\n", mem_mask, mc68328->regs.alarm >> 16);
+ return mc68328->regs.alarm >> 16;
+
+ case 0xb0c:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): RTCCTL = %04x\n", mem_mask, mc68328->regs.rtcctl);
+ return mc68328->regs.rtcctl;
+
+ case 0xb0e:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): RTCISR = %04x\n", mem_mask, mc68328->regs.rtcisr);
+ return mc68328->regs.rtcisr;
+
+ case 0xb10:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): RTCIENR = %04x\n", mem_mask, mc68328->regs.rtcienr);
+ return mc68328->regs.rtcienr;
+
+ case 0xb12:
+ verboselog(space.machine(), 2, "mc68328_r (%04x): STPWTCH = %04x\n", mem_mask, mc68328->regs.stpwtch);
+ return mc68328->regs.stpwtch;
+
+ default:
+ verboselog(space.machine(), 0, "mc68328_r (%04x): Unknown address (0x%06x)\n", mem_mask, 0xfff000 + address);
+ break;
+ }
+ return 0;
+}
+
+static DEVICE_RESET( mc68328 )
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ mc68328->regs.scr = 0x0c;
+ mc68328->regs.grpbasea = 0x0000;
+ mc68328->regs.grpbaseb = 0x0000;
+ mc68328->regs.grpbasec = 0x0000;
+ mc68328->regs.grpbased = 0x0000;
+ mc68328->regs.grpmaska = 0x0000;
+ mc68328->regs.grpmaskb = 0x0000;
+ mc68328->regs.grpmaskc = 0x0000;
+ mc68328->regs.grpmaskd = 0x0000;
+ mc68328->regs.csa0 = 0x00010006;
+ mc68328->regs.csa1 = 0x00010006;
+ mc68328->regs.csa2 = 0x00010006;
+ mc68328->regs.csa3 = 0x00010006;
+ mc68328->regs.csb0 = 0x00010006;
+ mc68328->regs.csb1 = 0x00010006;
+ mc68328->regs.csb2 = 0x00010006;
+ mc68328->regs.csb3 = 0x00010006;
+ mc68328->regs.csc0 = 0x00010006;
+ mc68328->regs.csc1 = 0x00010006;
+ mc68328->regs.csc2 = 0x00010006;
+ mc68328->regs.csc3 = 0x00010006;
+ mc68328->regs.csd0 = 0x00010006;
+ mc68328->regs.csd1 = 0x00010006;
+ mc68328->regs.csd2 = 0x00010006;
+ mc68328->regs.csd3 = 0x00010006;
+
+ mc68328->regs.pllcr = 0x2400;
+ mc68328->regs.pllfsr = 0x0123;
+ mc68328->regs.pctlr = 0x1f;
+
+ mc68328->regs.ivr = 0x00;
+ mc68328->regs.icr = 0x0000;
+ mc68328->regs.imr = 0x00ffffff;
+ mc68328->regs.iwr = 0x00ffffff;
+ mc68328->regs.isr = 0x00000000;
+ mc68328->regs.ipr = 0x00000000;
+
+ mc68328->regs.padir = 0x00;
+ mc68328->regs.padata = 0x00;
+ mc68328->regs.pasel = 0x00;
+ mc68328->regs.pbdir = 0x00;
+ mc68328->regs.pbdata = 0x00;
+ mc68328->regs.pbsel = 0x00;
+ mc68328->regs.pcdir = 0x00;
+ mc68328->regs.pcdata = 0x00;
+ mc68328->regs.pcsel = 0x00;
+ mc68328->regs.pddir = 0x00;
+ mc68328->regs.pddata = 0x00;
+ mc68328->regs.pdpuen = 0xff;
+ mc68328->regs.pdpol = 0x00;
+ mc68328->regs.pdirqen = 0x00;
+ mc68328->regs.pddataedge = 0x00;
+ mc68328->regs.pdirqedge = 0x00;
+ mc68328->regs.pedir = 0x00;
+ mc68328->regs.pedata = 0x00;
+ mc68328->regs.pepuen = 0x80;
+ mc68328->regs.pesel = 0x80;
+ mc68328->regs.pfdir = 0x00;
+ mc68328->regs.pfdata = 0x00;
+ mc68328->regs.pfpuen = 0xff;
+ mc68328->regs.pfsel = 0xff;
+ mc68328->regs.pgdir = 0x00;
+ mc68328->regs.pgdata = 0x00;
+ mc68328->regs.pgpuen = 0xff;
+ mc68328->regs.pgsel = 0xff;
+ mc68328->regs.pjdir = 0x00;
+ mc68328->regs.pjdata = 0x00;
+ mc68328->regs.pjsel = 0x00;
+ mc68328->regs.pkdir = 0x00;
+ mc68328->regs.pkdata = 0x00;
+ mc68328->regs.pkpuen = 0xff;
+ mc68328->regs.pksel = 0xff;
+ mc68328->regs.pmdir = 0x00;
+ mc68328->regs.pmdata = 0x00;
+ mc68328->regs.pmpuen = 0xff;
+ mc68328->regs.pmsel = 0xff;
+
+ mc68328->regs.pwmc = 0x0000;
+ mc68328->regs.pwmp = 0x0000;
+ mc68328->regs.pwmw = 0x0000;
+ mc68328->regs.pwmcnt = 0x0000;
+
+ mc68328->regs.tctl[0] = mc68328->regs.tctl[1] = 0x0000;
+ mc68328->regs.tprer[0] = mc68328->regs.tprer[1] = 0x0000;
+ mc68328->regs.tcmp[0] = mc68328->regs.tcmp[1] = 0xffff;
+ mc68328->regs.tcr[0] = mc68328->regs.tcr[1] = 0x0000;
+ mc68328->regs.tcn[0] = mc68328->regs.tcn[1] = 0x0000;
+ mc68328->regs.tstat[0] = mc68328->regs.tstat[1] = 0x0000;
+ mc68328->regs.wctlr = 0x0000;
+ mc68328->regs.wcmpr = 0xffff;
+ mc68328->regs.wcn = 0x0000;
+
+ mc68328->regs.spisr = 0x0000;
+
+ mc68328->regs.spimdata = 0x0000;
+ mc68328->regs.spimcont = 0x0000;
+
+ mc68328->regs.ustcnt = 0x0000;
+ mc68328->regs.ubaud = 0x003f;
+ mc68328->regs.urx = 0x0000;
+ mc68328->regs.utx = 0x0000;
+ mc68328->regs.umisc = 0x0000;
+
+ mc68328->regs.lssa = 0x00000000;
+ mc68328->regs.lvpw = 0xff;
+ mc68328->regs.lxmax = 0x03ff;
+ mc68328->regs.lymax = 0x01ff;
+ mc68328->regs.lcxp = 0x0000;
+ mc68328->regs.lcyp = 0x0000;
+ mc68328->regs.lcwch = 0x0101;
+ mc68328->regs.lblkc = 0x7f;
+ mc68328->regs.lpicf = 0x00;
+ mc68328->regs.lpolcf = 0x00;
+ mc68328->regs.lacdrc = 0x00;
+ mc68328->regs.lpxcd = 0x00;
+ mc68328->regs.lckcon = 0x40;
+ mc68328->regs.llbar = 0x3e;
+ mc68328->regs.lotcr = 0x3f;
+ mc68328->regs.lposr = 0x00;
+ mc68328->regs.lfrcm = 0xb9;
+ mc68328->regs.lgpmr = 0x1073;
+
+ mc68328->regs.hmsr = 0x00000000;
+ mc68328->regs.alarm = 0x00000000;
+ mc68328->regs.rtcctl = 0x00;
+ mc68328->regs.rtcisr = 0x00;
+ mc68328->regs.rtcienr = 0x00;
+ mc68328->regs.stpwtch = 0x00;
+
+ mc68328->rtc->adjust(attotime::from_hz(1), 0, attotime::from_hz(1));
+}
+
+static void mc68328_register_state_save(device_t *device)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ state_save_register_global(device->machine(), mc68328->regs.scr);
+ state_save_register_global(device->machine(), mc68328->regs.grpbasea);
+ state_save_register_global(device->machine(), mc68328->regs.grpbaseb);
+ state_save_register_global(device->machine(), mc68328->regs.grpbasec);
+ state_save_register_global(device->machine(), mc68328->regs.grpbased);
+ state_save_register_global(device->machine(), mc68328->regs.grpmaska);
+ state_save_register_global(device->machine(), mc68328->regs.grpmaskb);
+ state_save_register_global(device->machine(), mc68328->regs.grpmaskc);
+ state_save_register_global(device->machine(), mc68328->regs.grpmaskd);
+ state_save_register_global(device->machine(), mc68328->regs.csa0);
+ state_save_register_global(device->machine(), mc68328->regs.csa1);
+ state_save_register_global(device->machine(), mc68328->regs.csa2);
+ state_save_register_global(device->machine(), mc68328->regs.csa3);
+ state_save_register_global(device->machine(), mc68328->regs.csb0);
+ state_save_register_global(device->machine(), mc68328->regs.csb1);
+ state_save_register_global(device->machine(), mc68328->regs.csb2);
+ state_save_register_global(device->machine(), mc68328->regs.csb3);
+ state_save_register_global(device->machine(), mc68328->regs.csc0);
+ state_save_register_global(device->machine(), mc68328->regs.csc1);
+ state_save_register_global(device->machine(), mc68328->regs.csc2);
+ state_save_register_global(device->machine(), mc68328->regs.csc3);
+ state_save_register_global(device->machine(), mc68328->regs.csd0);
+ state_save_register_global(device->machine(), mc68328->regs.csd1);
+ state_save_register_global(device->machine(), mc68328->regs.csd2);
+ state_save_register_global(device->machine(), mc68328->regs.csd3);
+
+ state_save_register_global(device->machine(), mc68328->regs.pllcr);
+ state_save_register_global(device->machine(), mc68328->regs.pllfsr);
+ state_save_register_global(device->machine(), mc68328->regs.pctlr);
+
+ state_save_register_global(device->machine(), mc68328->regs.ivr);
+ state_save_register_global(device->machine(), mc68328->regs.icr);
+ state_save_register_global(device->machine(), mc68328->regs.imr);
+ state_save_register_global(device->machine(), mc68328->regs.iwr);
+ state_save_register_global(device->machine(), mc68328->regs.isr);
+ state_save_register_global(device->machine(), mc68328->regs.ipr);
+
+ state_save_register_global(device->machine(), mc68328->regs.padir);
+ state_save_register_global(device->machine(), mc68328->regs.padata);
+ state_save_register_global(device->machine(), mc68328->regs.pasel);
+ state_save_register_global(device->machine(), mc68328->regs.pbdir);
+ state_save_register_global(device->machine(), mc68328->regs.pbdata);
+ state_save_register_global(device->machine(), mc68328->regs.pbsel);
+ state_save_register_global(device->machine(), mc68328->regs.pcdir);
+ state_save_register_global(device->machine(), mc68328->regs.pcdata);
+ state_save_register_global(device->machine(), mc68328->regs.pcsel);
+ state_save_register_global(device->machine(), mc68328->regs.pddir);
+ state_save_register_global(device->machine(), mc68328->regs.pddata);
+ state_save_register_global(device->machine(), mc68328->regs.pdpuen);
+ state_save_register_global(device->machine(), mc68328->regs.pdpol);
+ state_save_register_global(device->machine(), mc68328->regs.pdirqen);
+ state_save_register_global(device->machine(), mc68328->regs.pddataedge);
+ state_save_register_global(device->machine(), mc68328->regs.pdirqedge);
+ state_save_register_global(device->machine(), mc68328->regs.pedir);
+ state_save_register_global(device->machine(), mc68328->regs.pedata);
+ state_save_register_global(device->machine(), mc68328->regs.pepuen);
+ state_save_register_global(device->machine(), mc68328->regs.pesel);
+ state_save_register_global(device->machine(), mc68328->regs.pfdir);
+ state_save_register_global(device->machine(), mc68328->regs.pfdata);
+ state_save_register_global(device->machine(), mc68328->regs.pfpuen);
+ state_save_register_global(device->machine(), mc68328->regs.pfsel);
+ state_save_register_global(device->machine(), mc68328->regs.pgdir);
+ state_save_register_global(device->machine(), mc68328->regs.pgdata);
+ state_save_register_global(device->machine(), mc68328->regs.pgpuen);
+ state_save_register_global(device->machine(), mc68328->regs.pgsel);
+ state_save_register_global(device->machine(), mc68328->regs.pjdir);
+ state_save_register_global(device->machine(), mc68328->regs.pjdata);
+ state_save_register_global(device->machine(), mc68328->regs.pjsel);
+ state_save_register_global(device->machine(), mc68328->regs.pkdir);
+ state_save_register_global(device->machine(), mc68328->regs.pkdata);
+ state_save_register_global(device->machine(), mc68328->regs.pkpuen);
+ state_save_register_global(device->machine(), mc68328->regs.pksel);
+ state_save_register_global(device->machine(), mc68328->regs.pmdir);
+ state_save_register_global(device->machine(), mc68328->regs.pmdata);
+ state_save_register_global(device->machine(), mc68328->regs.pmpuen);
+ state_save_register_global(device->machine(), mc68328->regs.pmsel);
+
+ state_save_register_global(device->machine(), mc68328->regs.pwmc);
+ state_save_register_global(device->machine(), mc68328->regs.pwmp);
+ state_save_register_global(device->machine(), mc68328->regs.pwmw);
+ state_save_register_global(device->machine(), mc68328->regs.pwmcnt);
+
+ state_save_register_global(device->machine(), mc68328->regs.tctl[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tctl[1]);
+ state_save_register_global(device->machine(), mc68328->regs.tprer[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tprer[1]);
+ state_save_register_global(device->machine(), mc68328->regs.tcmp[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tcmp[1]);
+ state_save_register_global(device->machine(), mc68328->regs.tcr[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tcr[1]);
+ state_save_register_global(device->machine(), mc68328->regs.tcn[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tcn[1]);
+ state_save_register_global(device->machine(), mc68328->regs.tstat[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tstat[1]);
+ state_save_register_global(device->machine(), mc68328->regs.wctlr);
+ state_save_register_global(device->machine(), mc68328->regs.wcmpr);
+ state_save_register_global(device->machine(), mc68328->regs.wcn);
+
+ state_save_register_global(device->machine(), mc68328->regs.spisr);
+
+ state_save_register_global(device->machine(), mc68328->regs.spimdata);
+ state_save_register_global(device->machine(), mc68328->regs.spimcont);
+
+ state_save_register_global(device->machine(), mc68328->regs.ustcnt);
+ state_save_register_global(device->machine(), mc68328->regs.ubaud);
+ state_save_register_global(device->machine(), mc68328->regs.urx);
+ state_save_register_global(device->machine(), mc68328->regs.utx);
+ state_save_register_global(device->machine(), mc68328->regs.umisc);
+
+ state_save_register_global(device->machine(), mc68328->regs.lssa);
+ state_save_register_global(device->machine(), mc68328->regs.lvpw);
+ state_save_register_global(device->machine(), mc68328->regs.lxmax);
+ state_save_register_global(device->machine(), mc68328->regs.lymax);
+ state_save_register_global(device->machine(), mc68328->regs.lcxp);
+ state_save_register_global(device->machine(), mc68328->regs.lcyp);
+ state_save_register_global(device->machine(), mc68328->regs.lcwch);
+ state_save_register_global(device->machine(), mc68328->regs.lblkc);
+ state_save_register_global(device->machine(), mc68328->regs.lpicf);
+ state_save_register_global(device->machine(), mc68328->regs.lpolcf);
+ state_save_register_global(device->machine(), mc68328->regs.lacdrc);
+ state_save_register_global(device->machine(), mc68328->regs.lpxcd);
+ state_save_register_global(device->machine(), mc68328->regs.lckcon);
+ state_save_register_global(device->machine(), mc68328->regs.llbar);
+ state_save_register_global(device->machine(), mc68328->regs.lotcr);
+ state_save_register_global(device->machine(), mc68328->regs.lposr);
+ state_save_register_global(device->machine(), mc68328->regs.lfrcm);
+ state_save_register_global(device->machine(), mc68328->regs.lgpmr);
+
+ state_save_register_global(device->machine(), mc68328->regs.hmsr);
+ state_save_register_global(device->machine(), mc68328->regs.alarm);
+ state_save_register_global(device->machine(), mc68328->regs.rtcctl);
+ state_save_register_global(device->machine(), mc68328->regs.rtcisr);
+ state_save_register_global(device->machine(), mc68328->regs.rtcienr);
+ state_save_register_global(device->machine(), mc68328->regs.stpwtch);
+}
+
+static DEVICE_START( mc68328 )
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ mc68328->iface = (const mc68328_interface*)device->static_config();
+
+ mc68328->out_port_a.resolve(mc68328->iface->out_port_a_func, *device);
+ mc68328->out_port_b.resolve(mc68328->iface->out_port_b_func, *device);
+ mc68328->out_port_c.resolve(mc68328->iface->out_port_c_func, *device);
+ mc68328->out_port_d.resolve(mc68328->iface->out_port_d_func, *device);
+ mc68328->out_port_e.resolve(mc68328->iface->out_port_e_func, *device);
+ mc68328->out_port_f.resolve(mc68328->iface->out_port_f_func, *device);
+ mc68328->out_port_g.resolve(mc68328->iface->out_port_g_func, *device);
+ mc68328->out_port_j.resolve(mc68328->iface->out_port_j_func, *device);
+ mc68328->out_port_k.resolve(mc68328->iface->out_port_k_func, *device);
+ mc68328->out_port_m.resolve(mc68328->iface->out_port_m_func, *device);
+
+ mc68328->in_port_a.resolve(mc68328->iface->in_port_a_func, *device);
+ mc68328->in_port_b.resolve(mc68328->iface->in_port_b_func, *device);
+ mc68328->in_port_c.resolve(mc68328->iface->in_port_c_func, *device);
+ mc68328->in_port_d.resolve(mc68328->iface->in_port_d_func, *device);
+ mc68328->in_port_e.resolve(mc68328->iface->in_port_e_func, *device);
+ mc68328->in_port_f.resolve(mc68328->iface->in_port_f_func, *device);
+ mc68328->in_port_g.resolve(mc68328->iface->in_port_g_func, *device);
+ mc68328->in_port_j.resolve(mc68328->iface->in_port_j_func, *device);
+ mc68328->in_port_k.resolve(mc68328->iface->in_port_k_func, *device);
+ mc68328->in_port_m.resolve(mc68328->iface->in_port_m_func, *device);
+
+ mc68328->out_pwm.resolve(mc68328->iface->out_pwm_func, *device);
+
+ mc68328->out_spim.resolve(mc68328->iface->out_spim_func, *device);
+ mc68328->in_spim.resolve(mc68328->iface->in_spim_func, *device);
+
+ mc68328->gptimer[0] = device->machine().scheduler().timer_alloc(FUNC(mc68328_timer1_hit));
+ mc68328->gptimer[1] = device->machine().scheduler().timer_alloc(FUNC(mc68328_timer2_hit));
+ mc68328->rtc = device->machine().scheduler().timer_alloc(FUNC(mc68328_rtc_tick));
+ mc68328->pwm = device->machine().scheduler().timer_alloc(FUNC(mc68328_pwm_transition));
+
+ mc68328_register_state_save(device);
+}
+
+const device_type MC68328 = &device_creator<mc68328_device>;
+
+mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MC68328, "Motorola MC68328 (DragonBall) Integrated Processor", tag, owner, clock)
+{
+ m_token = global_alloc_clear(mc68328_t);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void mc68328_device::device_config_complete()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc68328_device::device_start()
+{
+ DEVICE_START_NAME( mc68328 )(this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mc68328_device::device_reset()
+{
+ DEVICE_RESET_NAME( mc68328 )(this);
+}
diff --git a/src/emu/machine/mc68328.h b/src/emu/machine/mc68328.h
new file mode 100644
index 00000000000..1d3b9301c24
--- /dev/null
+++ b/src/emu/machine/mc68328.h
@@ -0,0 +1,568 @@
+/**********************************************************************
+
+ Motorola 68328 ("DragonBall") System-on-a-Chip private data
+
+ By MooglyGuy
+ contact mooglyguy@gmail.com with licensing and usage questions.
+
+**********************************************************************/
+
+#ifndef __MC68328_PRIVATE_H_
+#define __MC68328_PRIVATE_H_
+
+struct mc68328_regs_t
+{
+ // $(FF)FFF000
+ UINT8 scr; // System Control Register
+ UINT8 unused0[255];
+
+ // $(FF)FFF100
+ UINT16 grpbasea; // Chip Select Group A Base Register
+ UINT16 grpbaseb; // Chip Select Group B Base Register
+ UINT16 grpbasec; // Chip Select Group C Base Register
+ UINT16 grpbased; // Chip Select Group D Base Register
+ UINT16 grpmaska; // Chip Select Group A Mask Register
+ UINT16 grpmaskb; // Chip Select Group B Mask Register
+ UINT16 grpmaskc; // Chip Select Group C Mask Register
+ UINT16 grpmaskd; // Chip Select Group D Mask Register
+ UINT32 csa0; // Group A Chip Select 0 Register
+ UINT32 csa1; // Group A Chip Select 1 Register
+ UINT32 csa2; // Group A Chip Select 2 Register
+ UINT32 csa3; // Group A Chip Select 3 Register
+ UINT32 csb0; // Group B Chip Select 0 Register
+ UINT32 csb1; // Group B Chip Select 1 Register
+ UINT32 csb2; // Group B Chip Select 2 Register
+ UINT32 csb3; // Group B Chip Select 3 Register
+ UINT32 csc0; // Group C Chip Select 0 Register
+ UINT32 csc1; // Group C Chip Select 1 Register
+ UINT32 csc2; // Group C Chip Select 2 Register
+ UINT32 csc3; // Group C Chip Select 3 Register
+ UINT32 csd0; // Group D Chip Select 0 Register
+ UINT32 csd1; // Group D Chip Select 1 Register
+ UINT32 csd2; // Group D Chip Select 2 Register
+ UINT32 csd3; // Group D Chip Select 3 Register
+ UINT8 unused1[176];
+
+ // $(FF)FFF200
+ UINT16 pllcr; // PLL Control Register
+ UINT16 pllfsr; // PLL Frequency Select Register
+ UINT8 pad2[3];
+ UINT8 pctlr; // Power Control Register
+ UINT8 unused3[248];
+
+ // $(FF)FFF300
+ UINT8 ivr; // Interrupt Vector Register
+ UINT8 unused4[1];
+ UINT16 icr; // Interrupt Control Register
+ UINT32 imr; // Interrupt Mask Register
+ UINT32 iwr; // Interrupt Wakeup Enable Register
+ UINT32 isr; // Interrupt Status Register
+ UINT32 ipr; // Interrupt Pending Register
+ UINT8 unused5[236];
+
+ // $(FF)FFF400
+ UINT8 padir; // Port A Direction Register
+ UINT8 padata; // Port A Data Register
+ UINT8 unused6[1];
+ UINT8 pasel; // Port A Select Register
+ UINT8 unused7[4];
+
+ UINT8 pbdir; // Port B Direction Register
+ UINT8 pbdata; // Port B Data Register
+ UINT8 unused8[1];
+ UINT8 pbsel; // Port B Select Register
+ UINT8 unused9[4];
+
+ UINT8 pcdir; // Port C Direction Register
+ UINT8 pcdata; // Port C Data Register
+ UINT8 unused10[1];
+ UINT8 pcsel; // Port C Select Register
+ UINT8 unused11[4];
+
+ UINT8 pddir; // Port D Direction Register
+ UINT8 pddata; // Port D Data Register
+ UINT8 pdpuen; // Port D Pullup Enable Register
+ UINT8 unused12[1];
+ UINT8 pdpol; // Port D Polarity Register
+ UINT8 pdirqen; // Port D IRQ Enable Register
+ UINT8 pddataedge; // Port D Data Edge Level
+ UINT8 pdirqedge; // Port D IRQ Edge Register
+
+ UINT8 pedir; // Port E Direction Register
+ UINT8 pedata; // Port E Data Register
+ UINT8 pepuen; // Port E Pullup Enable Register
+ UINT8 pesel; // Port E Select Register
+ UINT8 unused14[4];
+
+ UINT8 pfdir; // Port F Direction Register
+ UINT8 pfdata; // Port F Data Register
+ UINT8 pfpuen; // Port F Pullup Enable Register
+ UINT8 pfsel; // Port F Select Register
+ UINT8 unused15[4];
+
+ UINT8 pgdir; // Port G Direction Register
+ UINT8 pgdata; // Port G Data Register
+ UINT8 pgpuen; // Port G Pullup Enable Register
+ UINT8 pgsel; // Port G Select Register
+ UINT8 unused16[4];
+
+ UINT8 pjdir; // Port J Direction Register
+ UINT8 pjdata; // Port J Data Register
+ UINT8 unused17[1];
+ UINT8 pjsel; // Port J Select Register
+ UINT8 unused18[4];
+ UINT8 pkdir; // Port K Direction Register
+ UINT8 pkdata; // Port K Data Register
+ UINT8 pkpuen; // Port K Pullup Enable Register
+ UINT8 pksel; // Port K Select Register
+ UINT8 unused19[4];
+
+ UINT8 pmdir; // Port M Direction Register
+ UINT8 pmdata; // Port M Data Register
+ UINT8 pmpuen; // Port M Pullup Enable Register
+ UINT8 pmsel; // Port M Select Register
+ UINT8 unused20[180];
+
+ // $(FF)FFF500
+ UINT16 pwmc; // PWM Control Register
+ UINT16 pwmp; // PWM Period Register
+ UINT16 pwmw; // PWM Width Register
+ UINT16 pwmcnt; // PWN Counter
+ UINT8 unused21[248];
+
+ // $(FF)FFF600
+ UINT16 tctl[2]; // Timer Control Register
+ UINT16 tprer[2]; // Timer Prescaler Register
+ UINT16 tcmp[2]; // Timer Compare Register
+ UINT16 tcr[2]; // Timer Capture Register
+ UINT16 tcn[2]; // Timer Counter
+ UINT16 tstat[2]; // Timer Status
+ UINT16 wctlr; // Watchdog Control Register
+ UINT16 wcmpr; // Watchdog Compare Register
+ UINT16 wcn; // Watchdog Counter
+ UINT8 tclear[2]; // Timer Clearable Status
+ UINT8 unused22[224];
+
+ // $(FF)FFF700
+ UINT16 spisr; // SPIS Register
+ UINT8 unused23[254];
+
+ // $(FF)FFF800
+ UINT16 spimdata; // SPIM Data Register
+ UINT16 spimcont; // SPIM Control/Status Register
+ UINT8 unused24[252];
+
+ // $(FF)FFF900
+ UINT16 ustcnt; // UART Status/Control Register
+ UINT16 ubaud; // UART Baud Control Register
+ UINT16 urx; // UART RX Register
+ UINT16 utx; // UART TX Register
+ UINT16 umisc; // UART Misc Register
+ UINT8 unused25[246];
+
+ // $(FF)FFFA00
+ UINT32 lssa; // Screen Starting Address Register
+ UINT8 unused26[1];
+ UINT8 lvpw; // Virtual Page Width Register
+ UINT8 unused27[2];
+ UINT16 lxmax; // Screen Width Register
+ UINT16 lymax; // Screen Height Register
+ UINT8 unused28[12];
+ UINT16 lcxp; // Cursor X Position
+ UINT16 lcyp; // Cursor Y Position
+ UINT16 lcwch; // Cursor Width & Height Register
+ UINT8 unused29[1];
+ UINT8 lblkc; // Blink Control Register
+ UINT8 lpicf; // Panel Interface Config Register
+ UINT8 lpolcf; // Polarity Config Register
+ UINT8 unused30[1];
+ UINT8 lacdrc; // ACD (M) Rate Control Register
+ UINT8 unused31[1];
+ UINT8 lpxcd; // Pixel Clock Divider Register
+ UINT8 unused32[1];
+ UINT8 lckcon; // Clocking Control Register
+ UINT8 unused33[1];
+ UINT8 llbar; // Last Buffer Address Register
+ UINT8 unused34[1];
+ UINT8 lotcr; // Octet Terminal Count Register
+ UINT8 unused35[1];
+ UINT8 lposr; // Panning Offset Register
+ UINT8 unused36[3];
+ UINT8 lfrcm; // Frame Rate Control Modulation Register
+ UINT16 lgpmr; // Gray Palette Mapping Register
+ UINT8 unused37[204];
+
+ // $(FF)FFFB00
+ UINT32 hmsr; // RTC Hours Minutes Seconds Register
+ UINT32 alarm; // RTC Alarm Register
+ UINT8 unused38[4];
+ UINT16 rtcctl; // RTC Control Register
+ UINT16 rtcisr; // RTC Interrupt Status Register
+ UINT16 rtcienr; // RTC Interrupt Enable Register
+ UINT16 stpwtch; // Stopwatch Minutes
+ UINT8 unused42[1260];
+};
+
+struct mc68328_t
+{
+ const mc68328_interface* iface;
+
+ mc68328_regs_t regs;
+
+ emu_timer *gptimer[2];
+ emu_timer *rtc;
+ emu_timer *pwm;
+
+ devcb_resolved_write8 out_port_a; /* 8-bit output */
+ devcb_resolved_write8 out_port_b; /* 8-bit output */
+ devcb_resolved_write8 out_port_c; /* 8-bit output */
+ devcb_resolved_write8 out_port_d; /* 8-bit output */
+ devcb_resolved_write8 out_port_e; /* 8-bit output */
+ devcb_resolved_write8 out_port_f; /* 8-bit output */
+ devcb_resolved_write8 out_port_g; /* 8-bit output */
+ devcb_resolved_write8 out_port_j; /* 8-bit output */
+ devcb_resolved_write8 out_port_k; /* 8-bit output */
+ devcb_resolved_write8 out_port_m; /* 8-bit output */
+
+ devcb_resolved_read8 in_port_a; /* 8-bit input */
+ devcb_resolved_read8 in_port_b; /* 8-bit input */
+ devcb_resolved_read8 in_port_c; /* 8-bit input */
+ devcb_resolved_read8 in_port_d; /* 8-bit input */
+ devcb_resolved_read8 in_port_e; /* 8-bit input */
+ devcb_resolved_read8 in_port_f; /* 8-bit input */
+ devcb_resolved_read8 in_port_g; /* 8-bit input */
+ devcb_resolved_read8 in_port_j; /* 8-bit input */
+ devcb_resolved_read8 in_port_k; /* 8-bit input */
+ devcb_resolved_read8 in_port_m; /* 8-bit input */
+
+ devcb_resolved_write8 out_pwm; /* 1-bit output */
+
+ devcb_resolved_write16 out_spim; /* 16-bit output */
+ devcb_resolved_read16 in_spim; /* 16-bit input */
+};
+
+#define SCR_BETO 0x80
+#define SCR_WPV 0x40
+#define SCR_PRV 0x20
+#define SCR_BETEN 0x10
+#define SCR_SO 0x08
+#define SCR_DMAP 0x04
+#define SCR_WDTH8 0x01
+
+#define ICR_POL6 0x0100
+#define ICR_POL3 0x0200
+#define ICR_POL2 0x0400
+#define ICR_POL1 0x0800
+#define ICR_ET6 0x1000
+#define ICR_ET3 0x2000
+#define ICR_ET2 0x4000
+#define ICR_ET1 0x8000
+
+#define INT_SPIM 0x000001
+#define INT_TIMER2 0x000002
+#define INT_UART 0x000004
+#define INT_WDT 0x000008
+#define INT_RTC 0x000010
+#define INT_RESERVED 0x000020
+#define INT_KB 0x000040
+#define INT_PWM 0x000080
+#define INT_INT0 0x000100
+#define INT_INT1 0x000200
+#define INT_INT2 0x000400
+#define INT_INT3 0x000800
+#define INT_INT4 0x001000
+#define INT_INT5 0x002000
+#define INT_INT6 0x004000
+#define INT_INT7 0x008000
+#define INT_KBDINTS 0x00ff00
+#define INT_IRQ1 0x010000
+#define INT_IRQ2 0x020000
+#define INT_IRQ3 0x040000
+#define INT_IRQ6 0x080000
+#define INT_PEN 0x100000
+#define INT_SPIS 0x200000
+#define INT_TIMER1 0x400000
+#define INT_IRQ7 0x800000
+
+#define INT_M68K_LINE1 (INT_IRQ1)
+#define INT_M68K_LINE2 (INT_IRQ2)
+#define INT_M68K_LINE3 (INT_IRQ3)
+#define INT_M68K_LINE4 (INT_INT0 | INT_INT1 | INT_INT2 | INT_INT3 | INT_INT4 | INT_INT5 | INT_INT6 | INT_INT7 | \
+ INT_PWM | INT_KB | INT_RTC | INT_WDT | INT_UART | INT_TIMER2 | INT_SPIM)
+#define INT_M68K_LINE5 (INT_PEN)
+#define INT_M68K_LINE6 (INT_IRQ6 | INT_TIMER1 | INT_SPIS)
+#define INT_M68K_LINE7 (INT_IRQ7)
+#define INT_M68K_LINE67 (INT_M68K_LINE6 | INT_M68K_LINE7)
+#define INT_M68K_LINE567 (INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7)
+#define INT_M68K_LINE4567 (INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7)
+#define INT_M68K_LINE34567 (INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7)
+#define INT_M68K_LINE234567 (INT_M68K_LINE2 | INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7)
+
+#define INT_IRQ1_SHIFT 0x000001
+#define INT_IRQ2_SHIFT 0x000002
+#define INT_IRQ3_SHIFT 0x000004
+#define INT_IRQ6_SHIFT 0x000008
+#define INT_PEN_SHIFT 0x000010
+#define INT_SPIS_SHIFT 0x000020
+#define INT_TIMER1_SHIFT 0x000040
+#define INT_IRQ7_SHIFT 0x000080
+
+#define INT_ACTIVE 1
+#define INT_INACTIVE 0
+
+#define GRPBASE_BASE_ADDR 0xfff0
+#define GRPBASE_VALID 0x0001
+
+#define GRPMASK_BASE_MASK 0xfff0
+
+#define CSAB_COMPARE 0xff000000
+#define CSAB_BSW 0x00010000
+#define CSAB_MASK 0x0000ff00
+#define CSAB_RO 0x00000008
+#define CSAB_WAIT 0x00000007
+
+#define CSCD_COMPARE 0xfff00000
+#define CSCD_BSW 0x00010000
+#define CSCD_MASK 0x0000fff0
+#define CSCD_RO 0x00000008
+#define CSCD_WAIT 0x00000007
+
+#define PLLCR_PIXCLK_SEL 0x3800
+#define PLLCR_PIXCLK_SEL_DIV2 0x0000
+#define PLLCR_PIXCLK_SEL_DIV4 0x0800
+#define PLLCR_PIXCLK_SEL_DIV8 0x1000
+#define PLLCR_PIXCLK_SEL_DIV16 0x1800
+#define PLLCR_PIXCLK_SEL_DIV1_0 0x2000
+#define PLLCR_PIXCLK_SEL_DIV1_1 0x2800
+#define PLLCR_PIXCLK_SEL_DIV1_2 0x3000
+#define PLLCR_PIXCLK_SEL_DIV1_3 0x3800
+#define PLLCR_SYSCLK_SEL 0x0700
+#define PLLCR_SYSCLK_SEL_DIV2 0x0000
+#define PLLCR_SYSCLK_SEL_DIV4 0x0100
+#define PLLCR_SYSCLK_SEL_DIV8 0x0200
+#define PLLCR_SYSCLK_SEL_DIV16 0x0300
+#define PLLCR_SYSCLK_SEL_DIV1_0 0x0400
+#define PLLCR_SYSCLK_SEL_DIV1_1 0x0500
+#define PLLCR_SYSCLK_SEL_DIV1_2 0x0600
+#define PLLCR_SYSCLK_SEL_DIV1_3 0x0700
+#define PLLCR_CLKEN 0x0010
+#define PLLCR_DISPLL 0x0008
+
+#define PLLFSR_CLK32 0x8000
+#define PLLFSR_PROT 0x4000
+#define PLLFSR_QCNT 0x0f00
+#define PLLFSR_PCNT 0x00ff
+
+#define PCTLR_PC_EN 0x80
+#define PCTLR_STOP 0x40
+#define PCTLR_WIDTH 0x1f
+
+#define CXP_CC 0xc000
+#define CXP_CC_XLU 0x0000
+#define CXP_CC_BLACK 0x4000
+#define CXP_CC_INVERSE 0x8000
+#define CXP_CC_INVALID 0xc000
+#define CXP_MASK 0x03ff
+
+#define CYP_MASK 0x01ff
+
+#define CWCH_CW 0x1f00
+#define CWCH_CH 0x001f
+
+#define BLKC_BKEN 0x80
+#define BLKC_BD 0x7f
+
+#define LPICF_PBSIZ 0x06
+#define LPICF_PBSIZ_1 0x00
+#define LPICF_PBSIZ_2 0x02
+#define LPICF_PBSIZ_4 0x04
+#define LPICF_PBSIZ_INVALID 0x06
+
+#define LPOLCF_LCKPOL 0x08
+#define LPOLCF_FLMPOL 0x04
+#define LPOLCF_LPPOL 0x02
+#define LPOLCF_PIXPOL 0x01
+
+#define LACDRC_MASK 0x0f
+
+#define LPXCD_MASK 0x3f
+
+#define LCKCON_LCDC_EN 0x80
+#define LCKCON_LCDON 0x80
+#define LCKCON_DMA16 0x40
+#define LCKCON_WS 0x30
+#define LCKCON_WS_1 0x00
+#define LCKCON_WS_2 0x10
+#define LCKCON_WS_3 0x20
+#define LCKCON_WS_4 0x30
+#define LCKCON_DWIDTH 0x02
+#define LCKCON_PCDS 0x01
+
+#define LBAR_MASK 0x7f
+
+#define LPOSR_BOS 0x08
+#define LPOSR_POS 0x07
+
+#define LFRCM_XMOD 0xf0
+#define LFRCM_YMOD 0x0f
+
+#define LGPMR_PAL1 0x7000
+#define LGPMR_PAL0 0x0700
+#define LGPMR_PAL3 0x0070
+#define LGPMR_PAL2 0x0007
+
+#define RTCHMSR_HOURS 0x1f000000
+#define RTCHMSR_MINUTES 0x003f0000
+#define RTCHMSR_SECONDS 0x0000003f
+
+#define RTCCTL_38_4 0x0020
+#define RTCCTL_ENABLE 0x0080
+
+#define RTCINT_STOPWATCH 0x0001
+#define RTCINT_MINUTE 0x0002
+#define RTCINT_ALARM 0x0004
+#define RTCINT_DAY 0x0008
+#define RTCINT_SECOND 0x0010
+
+#define RTCSTPWTCH_MASK 0x003f
+
+#define TCTL_TEN 0x0001
+#define TCTL_TEN_ENABLE 0x0001
+#define TCTL_CLKSOURCE 0x000e
+#define TCTL_CLKSOURCE_STOP 0x0000
+#define TCTL_CLKSOURCE_SYSCLK 0x0002
+#define TCTL_CLKSOURCE_SYSCLK16 0x0004
+#define TCTL_CLKSOURCE_TIN 0x0006
+#define TCTL_CLKSOURCE_32KHZ4 0x0008
+#define TCTL_CLKSOURCE_32KHZ5 0x000a
+#define TCTL_CLKSOURCE_32KHZ6 0x000c
+#define TCTL_CLKSOURCE_32KHZ7 0x000e
+#define TCTL_IRQEN 0x0010
+#define TCTL_IRQEN_ENABLE 0x0010
+#define TCTL_OM 0x0020
+#define TCTL_OM_ACTIVELOW 0x0000
+#define TCTL_OM_TOGGLE 0x0020
+#define TCTL_CAPTURE 0x00c0
+#define TCTL_CAPTURE_NOINT 0x0000
+#define TCTL_CAPTURE_RISING 0x0040
+#define TCTL_CAPTURE_FALLING 0x0080
+#define TCTL_CAPTURE_BOTH 0x00c0
+#define TCTL_FRR 0x0100
+#define TCTL_FRR_RESTART 0x0000
+#define TCTL_FRR_FREERUN 0x0100
+
+#define TSTAT_COMP 0x0001
+#define TSTAT_CAPT 0x0002
+
+#define WCTLR_WDRST 0x0008
+#define WCTLR_LOCK 0x0004
+#define WCTLR_FI 0x0002
+#define WCTLR_WDEN 0x0001
+
+#define USTCNT_UART_EN 0x8000
+#define USTCNT_RX_EN 0x4000
+#define USTCNT_TX_EN 0x2000
+#define USTCNT_RX_CLK_CONT 0x1000
+#define USTCNT_PARITY_EN 0x0800
+#define USTCNT_ODD_EVEN 0x0400
+#define USTCNT_STOP_BITS 0x0200
+#define USTCNT_8_7 0x0100
+#define USTCNT_GPIO_DELTA_EN 0x0080
+#define USTCNT_CTS_DELTA_EN 0x0040
+#define USTCNT_RX_FULL_EN 0x0020
+#define USTCNT_RX_HALF_EN 0x0010
+#define USTCNT_RX_RDY_EN 0x0008
+#define USTCNT_TX_EMPTY_EN 0x0004
+#define USTCNT_TX_HALF_EN 0x0002
+#define USTCNT_TX_AVAIL_EN 0x0001
+
+#define UBAUD_GPIO_DELTA 0x8000
+#define UBAUD_GPIO 0x4000
+#define UBAUD_GPIO_DIR 0x2000
+#define UBAUD_GPIO_SRC 0x1000
+#define UBAUD_BAUD_SRC 0x0800
+#define UBAUD_DIVIDE 0x0700
+#define UBAUD_DIVIDE_1 0x0000
+#define UBAUD_DIVIDE_2 0x0100
+#define UBAUD_DIVIDE_4 0x0200
+#define UBAUD_DIVIDE_8 0x0300
+#define UBAUD_DIVIDE_16 0x0400
+#define UBAUD_DIVIDE_32 0x0500
+#define UBAUD_DIVIDE_64 0x0600
+#define UBAUD_DIVIDE_128 0x0700
+#define UBAUD_PRESCALER 0x00ff
+
+#define URX_FIFO_FULL 0x8000
+#define URX_FIFO_HALF 0x4000
+#define URX_DATA_READY 0x2000
+#define URX_OVRUN 0x0800
+#define URX_FRAME_ERROR 0x0400
+#define URX_BREAK 0x0200
+#define URX_PARITY_ERROR 0x0100
+
+#define UTX_FIFO_EMPTY 0x8000
+#define UTX_FIFO_HALF 0x4000
+#define UTX_TX_AVAIL 0x2000
+#define UTX_SEND_BREAK 0x1000
+#define UTX_IGNORE_CTS 0x0800
+#define UTX_CTS_STATUS 0x0200
+#define UTX_CTS_DELTA 0x0100
+
+#define UMISC_CLK_SRC 0x4000
+#define UMISC_FORCE_PERR 0x2000
+#define UMISC_LOOP 0x1000
+#define UMISC_RTS_CONT 0x0080
+#define UMISC_RTS 0x0040
+#define UMISC_IRDA_ENABLE 0x0020
+#define UMISC_IRDA_LOOP 0x0010
+
+#define SPIS_SPIS_IRQ 0x8000
+#define SPIS_IRQEN 0x4000
+#define SPIS_ENPOL 0x2000
+#define SPIS_DATA_RDY 0x1000
+#define SPIS_OVRWR 0x0800
+#define SPIS_PHA 0x0400
+#define SPIS_POL 0x0200
+#define SPIS_SPISEN 0x0100
+
+#define SPIM_CLOCK_COUNT 0x000f
+#define SPIM_POL 0x0010
+#define SPIM_POL_HIGH 0x0000
+#define SPIM_POL_LOW 0x0010
+#define SPIM_PHA 0x0020
+#define SPIM_PHA_NORMAL 0x0000
+#define SPIM_PHA_OPPOSITE 0x0020
+#define SPIM_IRQEN 0x0040
+#define SPIM_SPIMIRQ 0x0080
+#define SPIM_XCH 0x0100
+#define SPIM_XCH_IDLE 0x0000
+#define SPIM_XCH_INIT 0x0100
+#define SPIM_SPMEN 0x0200
+#define SPIM_SPMEN_DISABLE 0x0000
+#define SPIM_SPMEN_ENABLE 0x0200
+#define SPIM_RATE 0xe000
+#define SPIM_RATE_4 0x0000
+#define SPIM_RATE_8 0x2000
+#define SPIM_RATE_16 0x4000
+#define SPIM_RATE_32 0x6000
+#define SPIM_RATE_64 0x8000
+#define SPIM_RATE_128 0xa000
+#define SPIM_RATE_256 0xc000
+#define SPIM_RATE_512 0xe000
+
+#define PWMC_PWMIRQ 0x8000
+#define PWMC_IRQEN 0x4000
+#define PWMC_LOAD 0x0100
+#define PWMC_PIN 0x0080
+#define PWMC_POL 0x0040
+#define PWMC_PWMEN 0x0010
+#define PWMC_CLKSEL 0x0007
+
+INLINE mc68328_t* mc68328_get_safe_token( device_t *device )
+{
+ assert( device != NULL );
+ assert( device->type() == MC68328 );
+ return (mc68328_t*) downcast<mc68328_device *>(device)->token();
+}
+
+#endif // __MC68328_PRIVATE_H_
diff --git a/src/emu/machine/mc6843.c b/src/emu/machine/mc6843.c
new file mode 100644
index 00000000000..a3a4660be3b
--- /dev/null
+++ b/src/emu/machine/mc6843.c
@@ -0,0 +1,863 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2007
+
+ Motorola 6843 Floppy Disk Controller emulation.
+
+**********************************************************************/
+
+/*
+ Main MC 6843 features are:
+ - single density floppies
+ - IBM 3740 compatible
+ - DMA-able
+ - high-level commands (including multi-sector read/write)
+
+ CLONES: HD 46503S seems to be a clone of MC 6843
+
+ BUGS
+ The driver was designed with Thomson computer emulation in mind
+ (CD 90-015 5"1/4 floppy controller) and works in this context.
+ It might work in other contexts but has currently shortcomings:
+ - DMA is not emulated
+ - Free-Format Read is not emulated
+ - Free-Format Write only supports track formatting, in a specific
+ format (FWF=1, Thomson-like sector formats)
+ - very rough timing: basically, there is a fixed delay between
+ a command request (CMR write) and its response (first byte
+ available, seek complete, etc.); there is no delay between
+ read / write
+ */
+
+
+#include "emu.h"
+#include "mc6843.h"
+#include "imagedev/flopdrv.h"
+
+
+/******************* parameters ******************/
+
+#define VERBOSE 0
+
+
+/******************* internal chip data structure ******************/
+
+struct mc6843_t
+{
+ /* interface */
+ const mc6843_interface* iface;
+
+ /* registers */
+ UINT8 CTAR; /* current track */
+ UINT8 CMR; /* command */
+ UINT8 ISR; /* interrupt status */
+ UINT8 SUR; /* set-up */
+ UINT8 STRA; /* status */
+ UINT8 STRB; /* status */
+ UINT8 SAR; /* sector address */
+ UINT8 GCR; /* general count */
+ UINT8 CCR; /* CRC control */
+ UINT8 LTAR; /* logical address track (=track destination) */
+
+ /* internal state */
+ UINT8 drive;
+ UINT8 side;
+ UINT8 data[128]; /* sector buffer */
+ UINT32 data_size; /* size of data */
+ UINT32 data_idx; /* current read/write position in data */
+ UINT32 data_id; /* chrd_id for sector write */
+ UINT8 index_pulse;
+
+ /* trigger delayed actions (bottom halves) */
+ emu_timer* timer_cont;
+
+};
+
+
+
+/* macro-command numbers */
+#define CMD_STZ 0x2 /* seek track zero */
+#define CMD_SEK 0x3 /* seek */
+#define CMD_SSR 0x4 /* single sector read */
+#define CMD_SSW 0x5 /* single sector write */
+#define CMD_RCR 0x6 /* read CRC */
+#define CMD_SWD 0x7 /* single sector write with delete data mark */
+#define CMD_MSW 0xd /* multiple sector write */
+#define CMD_MSR 0xc /* multiple sector read */
+#define CMD_FFW 0xb /* free format write */
+#define CMD_FFR 0xa /* free format read */
+
+/* coarse delays */
+#define DELAY_SEEK attotime::from_usec( 100 ) /* track seek time */
+#define DELAY_ADDR attotime::from_usec( 100 ) /* search-address time */
+
+
+
+static const char *const mc6843_cmd[16] =
+{
+ "---", "---", "STZ", "SEK", "SSR", "SSW", "RCR", "SWD",
+ "---", "---", "FFR", "FFW", "MSR", "MSW", "---", "---",
+};
+
+
+/******************* utility function and macros ********************/
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+
+INLINE mc6843_t* get_safe_token( device_t *device )
+{
+ assert( device != NULL );
+ assert( device->type() == MC6843 );
+ return (mc6843_t*) downcast<mc6843_device *>(device)->token();
+}
+
+
+/************************** floppy interface ****************************/
+
+
+
+static device_t* mc6843_floppy_image ( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ return floppy_get_device( device->machine(), mc6843->drive );
+}
+
+
+
+void mc6843_set_drive( device_t *device, int drive )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ mc6843->drive = drive;
+}
+
+
+
+void mc6843_set_side( device_t *device, int side )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ mc6843->side = side;
+}
+
+
+
+/* called after ISR or STRB has changed */
+static void mc6843_status_update( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ int irq = 0;
+
+ /* ISR3 */
+ if ( (mc6843->CMR & 0x40) || ! mc6843->STRB )
+ mc6843->ISR &= ~8;
+ else
+ mc6843->ISR |= 8;
+
+ /* interrupts */
+ if ( mc6843->ISR & 4 )
+ irq = 1; /* unmaskable */
+ if ( ! (mc6843->CMR & 0x80) )
+ {
+ /* maskable */
+ if ( mc6843->ISR & ~4 )
+ irq = 1;
+ }
+
+ if ( mc6843->iface->irq_func )
+ {
+ mc6843->iface->irq_func( device, irq );
+ LOG(( "mc6843_status_update: irq=%i (CMR=%02X, ISR=%02X)\n", irq, mc6843->CMR, mc6843->ISR ));
+ }
+}
+
+
+void mc6843_set_index_pulse ( device_t *device, int index_pulse )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ mc6843->index_pulse = index_pulse;
+}
+
+
+/* called at end of command */
+static void mc6843_cmd_end( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ int cmd = mc6843->CMR & 0x0f;
+ if ( ( cmd == CMD_STZ ) || ( cmd == CMD_SEK ) )
+ {
+ mc6843->ISR |= 0x02; /* set Settling Time Complete */
+ }
+ else
+ {
+ mc6843->ISR |= 0x01; /* set Macro Command Complete */
+ }
+ mc6843->STRA &= ~0x80; /* clear Busy */
+ mc6843->CMR &= 0xf0; /* clear command */
+ mc6843_status_update( device );
+}
+
+
+
+/* Seek Track Zero bottom half */
+static void mc6843_finish_STZ( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ device_t* img = mc6843_floppy_image( device );
+ int i;
+
+ /* seek to track zero */
+ for ( i=0; i<83; i++ )
+ {
+ if (floppy_tk00_r(img) == CLEAR_LINE)
+ break;
+ floppy_drive_seek( img, -1 );
+ }
+
+ LOG(( "%f mc6843_finish_STZ: actual=%i\n", device->machine().time().as_double(), floppy_drive_get_current_track( img ) ));
+
+ /* update state */
+ mc6843->CTAR = 0;
+ mc6843->GCR = 0;
+ mc6843->SAR = 0;
+ mc6843->STRB |= floppy_tk00_r(img) << 4;
+
+ mc6843_cmd_end( device );
+}
+
+
+
+/* Seek bottom half */
+static void mc6843_finish_SEK( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ device_t* img = mc6843_floppy_image( device );
+
+ /* seek to track */
+ floppy_drive_seek( img, mc6843->GCR - mc6843->CTAR );
+
+ LOG(( "%f mc6843_finish_SEK: from %i to %i (actual=%i)\n", device->machine().time().as_double(), mc6843->CTAR, mc6843->GCR, floppy_drive_get_current_track( img ) ));
+
+ /* update state */
+ mc6843->CTAR = mc6843->GCR;
+ mc6843->SAR = 0;
+ mc6843_cmd_end( device );
+}
+
+
+
+/* preamble to all sector read / write commands, returns 1 if found */
+static int mc6843_address_search( device_t *device, chrn_id* id )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ device_t* img = mc6843_floppy_image( device );
+ int r = 0;
+
+ while ( 1 )
+ {
+ if ( ( ! floppy_drive_get_next_id( img, mc6843->side, id ) ) || ( id->flags & ID_FLAG_CRC_ERROR_IN_ID_FIELD ) || ( id->N != 0 ) )
+ {
+ /* read address error */
+ LOG(( "%f mc6843_address_search: get_next_id failed\n", device->machine().time().as_double() ));
+ mc6843->STRB |= 0x0a; /* set CRC error & Sector Address Undetected */
+ mc6843_cmd_end( device );
+ return 0;
+ }
+
+ if ( id->C != mc6843->LTAR )
+ {
+ /* track mismatch */
+ LOG(( "%f mc6843_address_search: track mismatch: logical=%i real=%i\n", device->machine().time().as_double(), mc6843->LTAR, id->C ));
+ mc6843->data[0] = id->C; /* make the track number available to the CPU */
+ mc6843->STRA |= 0x20; /* set Track Not Equal */
+ mc6843_cmd_end( device );
+ return 0;
+ }
+
+ if ( id->R == mc6843->SAR )
+ {
+ /* found! */
+ LOG(( "%f mc6843_address_search: sector %i found on track %i\n", device->machine().time().as_double(), id->R, id->C ));
+ if ( ! (mc6843->CMR & 0x20) )
+ {
+ mc6843->ISR |= 0x04; /* if no DMA, set Status Sense */
+ }
+ return 1;
+ }
+
+ if ( floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) )
+ {
+ r++;
+ if ( r >= 4 )
+ {
+ /* time-out after 3 full revolutions */
+ LOG(( "%f mc6843_address_search: no sector %i found after 3 revolutions\n", device->machine().time().as_double(), mc6843->SAR ));
+ mc6843->STRB |= 0x08; /* set Sector Address Undetected */
+ mc6843_cmd_end( device );
+ return 0;
+ }
+ }
+ }
+
+ return 0; /* unreachable */
+}
+
+
+
+/* preamble specific to read commands (adds extra checks) */
+static int mc6843_address_search_read( device_t *device, chrn_id* id )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ if ( ! mc6843_address_search( device, id ) )
+ return 0;
+
+ if ( id->flags & ID_FLAG_CRC_ERROR_IN_DATA_FIELD )
+ {
+ LOG(( "%f mc6843_address_search_read: data CRC error\n", device->machine().time().as_double() ));
+ mc6843->STRB |= 0x06; /* set CRC error & Data Mark Undetected */
+ mc6843_cmd_end( device );
+ return 0;
+ }
+
+ if ( id->flags & ID_FLAG_DELETED_DATA )
+ {
+ LOG(( "%f mc6843_address_search_read: deleted data\n", device->machine().time().as_double() ));
+ mc6843->STRA |= 0x02; /* set Delete Data Mark Detected */
+ }
+
+ return 1;
+}
+
+
+
+
+/* Read CRC bottom half */
+static void mc6843_finish_RCR( device_t *device )
+{
+ chrn_id id;
+ if ( ! mc6843_address_search_read( device, &id ) )
+ return;
+ mc6843_cmd_end( device );
+}
+
+
+
+/* Single / Multiple Sector Read bottom half */
+static void mc6843_cont_SR( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ chrn_id id;
+ device_t* img = mc6843_floppy_image( device );
+
+ /* sector seek */
+ if ( ! mc6843_address_search_read( device, &id ) )
+ return;
+
+ /* sector read */
+ floppy_drive_read_sector_data( img, mc6843->side, id.data_id, mc6843->data, 128 );
+ mc6843->data_idx = 0;
+ mc6843->data_size = 128;
+ mc6843->STRA |= 0x01; /* set Data Transfer Request */
+ mc6843_status_update( device );
+}
+
+
+
+/* Single / Multiple Sector Write bottom half */
+static void mc6843_cont_SW( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ chrn_id id;
+
+ /* sector seek */
+ if ( ! mc6843_address_search( device, &id ) )
+ return;
+
+ /* setup sector write buffer */
+ mc6843->data_idx = 0;
+ mc6843->data_size = 128;
+ mc6843->STRA |= 0x01; /* set Data Transfer Request */
+ mc6843->data_id = id.data_id; /* for subsequent write sector command */
+ mc6843_status_update( device );
+}
+
+
+
+/* bottom halves, called to continue / finish a command after some delay */
+static TIMER_CALLBACK( mc6843_cont )
+{
+ device_t* device = (device_t*) ptr;
+ mc6843_t* mc6843 = get_safe_token( device );
+ int cmd = mc6843->CMR & 0x0f;
+
+ LOG(( "%f mc6843_cont: timer called for cmd=%s(%i)\n", device->machine().time().as_double(), mc6843_cmd[cmd], cmd ));
+
+ mc6843->timer_cont->adjust( attotime::never );
+
+ switch ( cmd )
+ {
+ case CMD_STZ: mc6843_finish_STZ( device ); break;
+ case CMD_SEK: mc6843_finish_SEK( device ); break;
+ case CMD_SSR: mc6843_cont_SR( device ); break;
+ case CMD_SSW: mc6843_cont_SW( device ); break;
+ case CMD_RCR: mc6843_finish_RCR( device ); break;
+ case CMD_SWD: mc6843_cont_SW( device ); break;
+ case CMD_MSW: mc6843_cont_SW( device ); break;
+ case CMD_MSR: mc6843_cont_SR( device ); break;
+ }
+}
+
+
+
+/************************** CPU interface ****************************/
+
+
+
+READ8_DEVICE_HANDLER ( mc6843_r )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ UINT8 data = 0;
+
+ switch ( offset ) {
+ case 0: /* Data Input Register (DIR) */
+ {
+ int cmd = mc6843->CMR & 0x0f;
+
+ LOG(( "%f $%04x mc6843_r: data input cmd=%s(%i), pos=%i/%i, GCR=%i, ",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ),
+ mc6843_cmd[cmd], cmd, mc6843->data_idx,
+ mc6843->data_size, mc6843->GCR ));
+
+ if ( cmd == CMD_SSR || cmd == CMD_MSR )
+ {
+ /* sector read */
+ assert( mc6843->data_size > 0 );
+ assert( mc6843->data_idx < mc6843->data_size );
+ assert( mc6843->data_idx < sizeof(mc6843->data) );
+ data = mc6843->data[ mc6843->data_idx ];
+ mc6843->data_idx++;
+
+ if ( mc6843->data_idx >= mc6843->data_size )
+ {
+ /* end of sector read */
+
+ mc6843->STRA &= ~0x01; /* clear Data Transfer Request */
+
+ if ( cmd == CMD_MSR )
+ {
+ /* schedule next sector in multiple sector read */
+ mc6843->GCR--;
+ mc6843->SAR++;
+ if ( mc6843->GCR == 0xff )
+ {
+ mc6843_cmd_end( device );
+ }
+ else if ( mc6843->SAR > 26 )
+
+ {
+ mc6843->STRB |= 0x08; /* set Sector Address Undetected */
+ mc6843_cmd_end( device );
+ }
+ else
+ {
+ mc6843->timer_cont->adjust( DELAY_ADDR );
+ }
+ }
+ else
+ {
+ mc6843_cmd_end( device );
+ }
+ }
+ }
+ else if ( cmd == 0 )
+ {
+ data = mc6843->data[0];
+ }
+ else
+ {
+ /* XXX TODO: other read modes */
+ data = mc6843->data[0];
+ logerror( "$%04x mc6843 read in unsupported command mode %i\n", space.machine().firstcpu->pcbase( ), cmd );
+ }
+
+ LOG(( "data=%02X\n", data ));
+
+ break;
+ }
+
+ case 1: /* Current-Track Address Register (CTAR) */
+ data = mc6843->CTAR;
+ LOG(( "%f $%04x mc6843_r: read CTAR %i (actual=%i)\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data,
+ floppy_drive_get_current_track( mc6843_floppy_image( device ) ) ));
+ break;
+
+ case 2: /* Interrupt Status Register (ISR) */
+ data = mc6843->ISR;
+ LOG(( "%f $%04x mc6843_r: read ISR %02X: cmd=%scomplete settle=%scomplete sense-rq=%i STRB=%i\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data,
+ (data & 1) ? "" : "not-" , (data & 2) ? "" : "not-",
+ (data >> 2) & 1, (data >> 3) & 1 ));
+
+ /* reset */
+ mc6843->ISR &= 8; /* keep STRB */
+ mc6843_status_update( device );
+ break;
+
+ case 3: /* Status Register A (STRA) */
+ {
+ /* update */
+ device_t* img = mc6843_floppy_image( device );
+ int flag = floppy_drive_get_flag_state( img, FLOPPY_DRIVE_READY);
+ mc6843->STRA &= 0xa3;
+ if ( flag & FLOPPY_DRIVE_READY )
+ mc6843->STRA |= 0x04;
+
+ mc6843->STRA |= !floppy_tk00_r(img) << 3;
+ mc6843->STRA |= !floppy_wpt_r(img) << 4;
+
+ if ( mc6843->index_pulse )
+ mc6843->STRA |= 0x40;
+
+ data = mc6843->STRA;
+ LOG(( "%f $%04x mc6843_r: read STRA %02X: data-rq=%i del-dta=%i ready=%i t0=%i wp=%i trk-dif=%i idx=%i busy=%i\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data,
+ data & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1,
+ (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1 ));
+ break;
+ }
+
+ case 4: /* Status Register B (STRB) */
+ data = mc6843->STRB;
+ LOG(( "%f $%04x mc6843_r: read STRB %02X: data-err=%i CRC-err=%i dta--mrk-err=%i sect-mrk-err=%i seek-err=%i fi=%i wr-err=%i hard-err=%i\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data,
+ data & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1,
+ (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1 ));
+
+ /* (partial) reset */
+ mc6843->STRB &= ~0xfb;
+ mc6843_status_update( device );
+ break;
+
+ case 7: /* Logical-Track Address Register (LTAR) */
+ data = mc6843->LTAR;
+ LOG(( "%f $%04x mc6843_r: read LTAR %i (actual=%i)\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data,
+ floppy_drive_get_current_track( mc6843_floppy_image( device ) ) ));
+ break;
+
+ default:
+ logerror( "$%04x mc6843 invalid read offset %i\n", space.machine().firstcpu->pcbase( ), offset );
+ }
+
+ return data;
+}
+
+WRITE8_DEVICE_HANDLER ( mc6843_w )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ switch ( offset ) {
+ case 0: /* Data Output Register (DOR) */
+ {
+ int cmd = mc6843->CMR & 0x0f;
+ int FWF = (mc6843->CMR >> 4) & 1;
+
+ LOG(( "%f $%04x mc6843_w: data output cmd=%s(%i), pos=%i/%i, GCR=%i, data=%02X\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ),
+ mc6843_cmd[cmd], cmd, mc6843->data_idx,
+ mc6843->data_size, mc6843->GCR, data ));
+
+ if ( cmd == CMD_SSW || cmd == CMD_MSW || cmd == CMD_SWD )
+ {
+ /* sector write */
+ assert( mc6843->data_size > 0 );
+ assert( mc6843->data_idx < mc6843->data_size );
+ assert( mc6843->data_idx < sizeof(mc6843->data) );
+ mc6843->data[ mc6843->data_idx ] = data;
+ mc6843->data_idx++;
+ if ( mc6843->data_idx >= mc6843->data_size )
+ {
+ /* end of sector write */
+ device_t* img = mc6843_floppy_image( device );
+
+ LOG(( "%f $%04x mc6843_w: write sector %i\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->data_id ));
+
+ floppy_drive_write_sector_data(
+ img, mc6843->side, mc6843->data_id,
+ mc6843->data, mc6843->data_size,
+ (cmd == CMD_SWD) ? ID_FLAG_DELETED_DATA : 0 );
+
+ mc6843->STRA &= ~0x01; /* clear Data Transfer Request */
+
+ if ( cmd == CMD_MSW )
+ {
+ mc6843->GCR--;
+ mc6843->SAR++;
+ if ( mc6843->GCR == 0xff )
+ {
+ mc6843_cmd_end( device );
+ }
+ else if ( mc6843->SAR > 26 )
+
+ {
+ mc6843->STRB |= 0x08; /* set Sector Address Undetected */
+ mc6843_cmd_end( device );
+ }
+ else
+ {
+ mc6843->timer_cont->adjust( DELAY_ADDR );
+ }
+ }
+ else
+ {
+ mc6843_cmd_end( device );
+ }
+ }
+ }
+ else if ( (cmd == CMD_FFW) && FWF )
+ {
+ /* assume we are formatting */
+ UINT8 nibble;
+ nibble =
+ (data & 0x01) |
+ ((data & 0x04) >> 1 )|
+ ((data & 0x10) >> 2 )|
+ ((data & 0x40) >> 3 );
+
+ assert( mc6843->data_idx < sizeof(mc6843->data) );
+
+ mc6843->data[mc6843->data_idx / 2] =
+ (mc6843->data[mc6843->data_idx / 2] << 4) | nibble;
+
+ if ( (mc6843->data_idx == 0) && (mc6843->data[0] == 0xfe ) )
+ {
+ /* address mark detected */
+ mc6843->data_idx = 2;
+ }
+ else if ( mc6843->data_idx == 9 )
+ {
+ /* address id field complete */
+ if ( (mc6843->data[2] == 0) && (mc6843->data[4] == 0) )
+ {
+ /* valid address id field */
+ device_t* img = mc6843_floppy_image( device );
+ UINT8 track = mc6843->data[1];
+ UINT8 sector = mc6843->data[3];
+ UINT8 filler = 0xe5; /* standard Thomson filler */
+ LOG(( "%f $%04x mc6843_w: address id detected track=%i sector=%i\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), track, sector));
+ floppy_drive_format_sector( img, mc6843->side, sector, track, 0, sector, 0, filler );
+ }
+ else
+ {
+ /* abort */
+ mc6843->data_idx = 0;
+ }
+ }
+ else if ( mc6843->data_idx > 0 )
+ {
+ /* accumulate address id field */
+ mc6843->data_idx++;
+ }
+ }
+ else if ( cmd == 0 )
+ {
+ /* nothing */
+ }
+ else
+ {
+ /* XXX TODO: other write modes */
+ logerror( "$%04x mc6843 write %02X in unsupported command mode %i (FWF=%i)\n", space.machine().firstcpu->pcbase( ), data, cmd, FWF );
+ }
+ break;
+ }
+
+ case 1: /* Current-Track Address Register (CTAR) */
+ mc6843->CTAR = data & 0x7f;
+ LOG(( "%f $%04x mc6843_w: set CTAR to %i %02X (actual=%i) \n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->CTAR, data,
+ floppy_drive_get_current_track( mc6843_floppy_image( device ) ) ));
+ break;
+
+ case 2: /* Command Register (CMR) */
+ {
+ int cmd = data & 15;
+
+ LOG(( "%f $%04x mc6843_w: set CMR to $%02X: cmd=%s(%i) FWF=%i DMA=%i ISR3-intr=%i fun-intr=%i\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ),
+ data, mc6843_cmd[cmd], cmd, (data >> 4) & 1, (data >> 5) & 1,
+ (data >> 6) & 1, (data >> 7) & 1 ));
+
+ /* sanitize state */
+ mc6843->STRA &= ~0x81; /* clear Busy & Data Transfer Request */
+ mc6843->data_idx = 0;
+ mc6843->data_size = 0;
+
+ /* commands are initiated by updating some flags and scheduling
+ a bottom-half (mc6843_cont) after some delay */
+
+ switch (cmd)
+ {
+ case CMD_SSW:
+ case CMD_SSR:
+ case CMD_SWD:
+ case CMD_RCR:
+ case CMD_MSR:
+ case CMD_MSW:
+ mc6843->STRA |= 0x80; /* set Busy */
+ mc6843->STRA &= ~0x22; /* clear Track Not Equal & Delete Data Mark Detected */
+ mc6843->STRB &= ~0x04; /* clear Data Mark Undetected */
+ mc6843->timer_cont->adjust( DELAY_ADDR );
+ break;
+ case CMD_STZ:
+ case CMD_SEK:
+ mc6843->STRA |= 0x80; /* set Busy */
+ mc6843->timer_cont->adjust( DELAY_SEEK );
+ break;
+ case CMD_FFW:
+ case CMD_FFR:
+ mc6843->data_idx = 0;
+ mc6843->STRA |= 0x01; /* set Data Transfer Request */
+ break;
+ }
+
+ mc6843->CMR = data;
+ mc6843_status_update( device );
+ break;
+ }
+
+ case 3: /* Set-Up Register (SUR) */
+ mc6843->SUR = data;
+
+ /* assume CLK freq = 1MHz (IBM 3740 compatibility) */
+ LOG(( "%f $%04x mc6843_w: set SUR to $%02X: head settling time=%fms, track-to-track seek time=%f\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ),
+ data, 4.096 * (data & 15), 1.024 * ((data >> 4) & 15) ));
+ break;
+
+ case 4: /* Sector Address Register (SAR) */
+ mc6843->SAR = data & 0x1f;
+ LOG(( "%f $%04x mc6843_w: set SAR to %i (%02X)\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->SAR, data ));
+ break;
+
+ case 5: /* General Count Register (GCR) */
+ mc6843->GCR = data & 0x7f;
+ LOG(( "%f $%04x mc6843_w: set GCR to %i (%02X)\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->GCR, data ));
+ break;
+
+ case 6: /* CRC Control Register (CCR) */
+ mc6843->CCR = data & 3;
+ LOG(( "%f $%04x mc6843_w: set CCR to %02X: CRC=%s shift=%i\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data,
+ (data & 1) ? "enabled" : "disabled", (data >> 1) & 1 ));
+ break;
+
+ case 7: /* Logical-Track Address Register (LTAR) */
+ mc6843->LTAR = data & 0x7f;
+ LOG(( "%f $%04x mc6843_w: set LTAR to %i %02X (actual=%i)\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6843->LTAR, data,
+ floppy_drive_get_current_track( mc6843_floppy_image( device ) ) ));
+ break;
+
+ default:
+ logerror( "$%04x mc6843 invalid write offset %i (data=$%02X)\n", space.machine().firstcpu->pcbase( ), offset, data );
+ }
+}
+
+
+
+/************************ reset *****************************/
+
+static DEVICE_RESET( mc6843 )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ int i;
+ LOG (( "mc6843 reset\n" ));
+
+ /* setup/reset floppy drive */
+ for ( i = 0; i < 4; i++ )
+ {
+ device_t * img = floppy_get_device( device->machine(), i );
+ floppy_mon_w(img, CLEAR_LINE);
+ floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
+ floppy_drive_set_rpm( img, 300. );
+ }
+
+ /* reset registers */
+ mc6843->CMR &= 0xf0; /* zero only command */
+ mc6843->ISR = 0;
+ mc6843->STRA &= 0x5c;
+ mc6843->SAR = 0;
+ mc6843->STRB &= 0x20;
+ mc6843_status_update( device );
+
+ mc6843->data_size = 0;
+ mc6843->data_idx = 0;
+ mc6843->timer_cont->adjust( attotime::never );
+}
+
+
+
+/************************ start *****************************/
+
+static DEVICE_START( mc6843 )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+
+ mc6843->iface = (const mc6843_interface*)device->static_config();
+
+ mc6843->timer_cont = device->machine().scheduler().timer_alloc(FUNC(mc6843_cont), (void*) device) ;
+
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CTAR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CMR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->ISR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->SUR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->STRA );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->STRB );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->SAR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->GCR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CCR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->LTAR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->drive );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->side );
+ state_save_register_item_array( device->machine(),"mc6843", device->tag(), 0, mc6843->data );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_size );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_idx );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_id );
+}
+
+
+const device_type MC6843 = &device_creator<mc6843_device>;
+
+mc6843_device::mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MC6843, "Motorola MC6843 floppy controller", tag, owner, clock)
+{
+ m_token = global_alloc_clear(mc6843_t);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void mc6843_device::device_config_complete()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc6843_device::device_start()
+{
+ DEVICE_START_NAME( mc6843 )(this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mc6843_device::device_reset()
+{
+ DEVICE_RESET_NAME( mc6843 )(this);
+}
diff --git a/src/emu/machine/mc6843.h b/src/emu/machine/mc6843.h
new file mode 100644
index 00000000000..677899c817f
--- /dev/null
+++ b/src/emu/machine/mc6843.h
@@ -0,0 +1,59 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2007
+
+ Motorola 6843 Floppy Disk Controller emulation.
+
+**********************************************************************/
+
+#ifndef MC6843_H
+#define MC6843_H
+
+class mc6843_device : public device_t
+{
+public:
+ mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~mc6843_device() { global_free(m_token); }
+
+ // access to legacy token
+ void *token() const { assert(m_token != NULL); return m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ // internal state
+ void *m_token;
+};
+
+extern const device_type MC6843;
+
+
+
+/* ---------- configuration ------------ */
+
+struct mc6843_interface
+{
+ void ( * irq_func ) ( device_t *device, int state );
+};
+
+
+#define MCFG_MC6843_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, MC6843, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_MC6843_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+
+/* ---------- functions ------------ */
+
+extern DECLARE_READ8_DEVICE_HANDLER ( mc6843_r );
+extern DECLARE_WRITE8_DEVICE_HANDLER ( mc6843_w );
+
+extern void mc6843_set_drive ( device_t *device, int drive );
+extern void mc6843_set_side ( device_t *device, int side );
+extern void mc6843_set_index_pulse ( device_t *device, int index_pulse );
+
+#endif
diff --git a/src/emu/machine/mc6846.c b/src/emu/machine/mc6846.c
new file mode 100644
index 00000000000..2db1709d9cd
--- /dev/null
+++ b/src/emu/machine/mc6846.c
@@ -0,0 +1,671 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2006
+
+ Motorola 6846 emulation.
+
+ The MC6846 chip provides ROM (2048 bytes), I/O (8-bit directional data port +
+ 2 control lines) and a programmable timer.
+ It may be interfaced with a M6809 cpu.
+ It is used in some Thomson computers.
+
+ Not yet implemented:
+ - external clock (CTC)
+ - latching of port on CP1
+ - gate input (CTG)
+ - timer comparison modes (frequency and pulse width)
+ - CP2 acknowledge modes
+
+**********************************************************************/
+
+#include "emu.h"
+#include "mc6846.h"
+
+#define VERBOSE 0
+
+
+
+/******************* internal chip data structure ******************/
+
+
+struct mc6846_t
+{
+ const mc6846_interface* iface;
+
+ /* registers */
+ UINT8 csr; /* 0,4: combination status register */
+ UINT8 pcr; /* 1: peripheral control register */
+ UINT8 ddr; /* 2: data direction register */
+ UINT8 pdr; /* 3: peripheral data register (last cpu write) */
+ UINT8 tcr; /* 5: timer control register */
+
+ /* lines */
+ UINT8 cp1; /* 1-bit input */
+ UINT8 cp2; /* 1-bit input/output: last external write */
+ UINT8 cp2_cpu; /* last cpu write */
+ UINT8 cto; /* 1-bit timer output (unmasked) */
+
+ /* internal state */
+ UINT8 time_MSB; /* MSB buffer register */
+ UINT8 csr0_to_be_cleared;
+ UINT8 csr1_to_be_cleared;
+ UINT8 csr2_to_be_cleared;
+ UINT16 latch; /* timer latch */
+ UINT16 preset; /* preset value */
+ UINT8 timer_started;
+
+ /* timers */
+ emu_timer *interval; /* interval programmable timer */
+ emu_timer *one_shot; /* 1-us x factor one-shot timer */
+
+ /* CPU write to the outside through chip */
+ devcb_resolved_write8 out_port; /* 8-bit output */
+ devcb_resolved_write8 out_cp1; /* 1-bit output */
+ devcb_resolved_write8 out_cp2; /* 1-bit output */
+
+ /* CPU read from the outside through chip */
+ devcb_resolved_read8 in_port; /* 8-bit input */
+
+ /* asynchronous timer output to outside world */
+ devcb_resolved_write8 out_cto; /* 1-bit output */
+
+ /* timer interrupt */
+ devcb_resolved_write_line irq;
+
+ int old_cif;
+ int old_cto;
+};
+
+
+
+/******************* utility function and macros ********************/
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+#define PORT \
+ ((mc6846->pdr & mc6846->ddr) | \
+ ((!mc6846->in_port.isnull() ? mc6846->in_port( 0 ) : 0) & \
+ ~mc6846->ddr))
+
+#define CTO \
+ ((MODE == 0x30 || (mc6846->tcr & 0x80)) ? mc6846->cto : 0)
+
+#define MODE (mc6846->tcr & 0x38)
+
+#define FACTOR ((mc6846->tcr & 4) ? 8 : 1)
+
+
+
+INLINE mc6846_t* get_safe_token( device_t *device )
+{
+ assert( device != NULL );
+ assert( device->type() == MC6846 );
+ return (mc6846_t*) downcast<mc6846_device *>(device)->token();
+}
+
+
+INLINE UINT16 mc6846_counter( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ if ( mc6846->timer_started )
+ {
+ attotime delay = mc6846->interval ->remaining( );
+ return delay.as_ticks(1000000) / FACTOR;
+ }
+ else
+ return mc6846->preset;
+}
+
+
+
+INLINE void mc6846_update_irq( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ int cif = 0;
+ /* composite interrupt flag */
+ if ( ( (mc6846->csr & 1) && (mc6846->tcr & 0x40) ) ||
+ ( (mc6846->csr & 2) && (mc6846->pcr & 1) ) ||
+ ( (mc6846->csr & 4) && (mc6846->pcr & 8) && ! (mc6846->pcr & 0x20) ) )
+ cif = 1;
+ if ( mc6846->old_cif != cif )
+ {
+ LOG (( "%f: mc6846 interrupt %i (time=%i cp1=%i cp2=%i)\n",
+ device->machine().time().as_double(), cif,
+ mc6846->csr & 1, (mc6846->csr >> 1 ) & 1, (mc6846->csr >> 2 ) & 1 ));
+ mc6846->old_cif = cif;
+ }
+ if ( cif )
+ {
+ mc6846->csr |= 0x80;
+ if ( !mc6846->irq.isnull() )
+ mc6846->irq( 1 );
+ }
+ else
+ {
+ mc6846->csr &= ~0x80;
+ if ( !mc6846->irq.isnull() )
+ mc6846->irq( 0 );
+ }
+}
+
+
+
+INLINE void mc6846_update_cto ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ int cto = CTO;
+ if ( cto != mc6846->old_cto )
+ {
+ LOG (( "%f: mc6846 CTO set to %i\n", device->machine().time().as_double(), cto ));
+ mc6846->old_cto = cto;
+ }
+ if ( !mc6846->out_cto.isnull() )
+ mc6846->out_cto( 0, cto );
+}
+
+
+
+INLINE void mc6846_timer_launch ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ int delay = FACTOR * (mc6846->preset+1);
+ LOG (( "%f: mc6846 timer launch called, mode=%i, preset=%i (x%i)\n", device->machine().time().as_double(), MODE, mc6846->preset, FACTOR ));
+
+ if ( ! (mc6846->tcr & 2) )
+ {
+ logerror( "mc6846 external clock CTC not implemented\n" );
+ }
+
+ switch( MODE )
+ {
+ case 0x00:
+ case 0x10: /* continuous */
+ mc6846->cto = 0;
+ break;
+
+ case 0x20: /* single-shot */
+ mc6846->cto = 0;
+ mc6846->one_shot->reset( attotime::from_usec(FACTOR) );
+ break;
+
+ case 0x30: /* cascaded single-shot */
+ break;
+
+ default:
+ logerror( "mc6846 timer mode %i not implemented\n", MODE );
+ mc6846->interval->reset( );
+ mc6846->timer_started = 0;
+ return;
+ }
+
+ mc6846->interval->reset( attotime::from_usec(delay) );
+ mc6846->timer_started = 1;
+
+ mc6846->csr &= ~1;
+ mc6846_update_cto( device );
+ mc6846_update_irq( device );
+}
+
+
+
+/******************* timer callbacks *********************************/
+
+static TIMER_CALLBACK( mc6846_timer_expire )
+{
+ device_t* device = (device_t*) ptr;
+ mc6846_t* mc6846 = get_safe_token( device );
+ int delay = FACTOR * (mc6846->latch+1);
+
+ LOG (( "%f: mc6846 timer expire called, mode=%i, latch=%i (x%i)\n", device->machine().time().as_double(), MODE, mc6846->latch, FACTOR ));
+
+ /* latch => counter */
+ mc6846->preset = mc6846->latch;
+
+ if ( ! (mc6846->tcr & 2) )
+ logerror( "mc6846 external clock CTC not implemented\n" );
+
+ switch ( MODE )
+ {
+ case 0x00:
+ case 0x10: /* continuous */
+ mc6846->cto = 1 ^ mc6846->cto;
+ break;
+
+ case 0x20: /* single-shot */
+ mc6846->cto = 0;
+ break;
+
+ case 0x30: /* cascaded single-shot */
+ mc6846->cto = ( mc6846->tcr & 0x80 ) ? 1 : 0;
+ break;
+
+ default:
+ logerror( "mc6846 timer mode %i not implemented\n", MODE );
+ mc6846->interval->reset( );
+ mc6846->timer_started = 0;
+ return;
+ }
+
+ mc6846->interval->reset( attotime::from_usec(delay) );
+
+ mc6846->csr |= 1;
+ mc6846_update_cto( device );
+ mc6846_update_irq( device );
+}
+
+
+
+static TIMER_CALLBACK( mc6846_timer_one_shot )
+{
+ device_t* device = (device_t*) ptr;
+ mc6846_t* mc6846 = get_safe_token( device );
+ LOG (( "%f: mc6846 timer one shot called\n", device->machine().time().as_double() ));
+
+ /* 1 micro second after one-shot launch, we put cto to high */
+ mc6846->cto = 1;
+ mc6846_update_cto( device );
+}
+
+
+
+/************************** CPU interface ****************************/
+
+
+READ8_DEVICE_HANDLER ( mc6846_r )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ switch ( offset )
+ {
+ case 0:
+ case 4:
+ LOG (( "$%04x %f: mc6846 CSR read $%02X intr=%i (timer=%i, cp1=%i, cp2=%i)\n",
+ space.machine().firstcpu->pcbase( ), space.machine().time().as_double(),
+ mc6846->csr, (mc6846->csr >> 7) & 1,
+ mc6846->csr & 1, (mc6846->csr >> 1) & 1, (mc6846->csr >> 2) & 1 ));
+ mc6846->csr0_to_be_cleared = mc6846->csr & 1;
+ mc6846->csr1_to_be_cleared = mc6846->csr & 2;
+ mc6846->csr2_to_be_cleared = mc6846->csr & 4;
+ return mc6846->csr;
+
+ case 1:
+ LOG (( "$%04x %f: mc6846 PCR read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->pcr ));
+ return mc6846->pcr;
+
+ case 2:
+ LOG (( "$%04x %f: mc6846 DDR read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->ddr ));
+ return mc6846->ddr;
+
+ case 3:
+ LOG (( "$%04x %f: mc6846 PORT read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), PORT ));
+ if ( ! (mc6846->pcr & 0x80) )
+ {
+ if ( mc6846->csr1_to_be_cleared )
+ mc6846->csr &= ~2;
+ if ( mc6846->csr2_to_be_cleared )
+ mc6846->csr &= ~4;
+ mc6846_update_irq( device );
+ mc6846->csr1_to_be_cleared = 0;
+ mc6846->csr2_to_be_cleared = 0;
+ }
+ return PORT;
+
+ case 5:
+ LOG (( "$%04x %f: mc6846 TCR read $%02X\n",space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->tcr ));
+ return mc6846->tcr;
+
+ case 6:
+ LOG (( "$%04x %f: mc6846 COUNTER hi read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846_counter( device ) >> 8 ));
+ if ( mc6846->csr0_to_be_cleared )
+ {
+ mc6846->csr &= ~1;
+ mc6846_update_irq( device );
+ }
+ mc6846->csr0_to_be_cleared = 0;
+ return mc6846_counter( device ) >> 8;
+
+ case 7:
+ LOG (( "$%04x %f: mc6846 COUNTER low read $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846_counter( device ) & 0xff ));
+ if ( mc6846->csr0_to_be_cleared )
+ {
+ mc6846->csr &= ~1;
+ mc6846_update_irq( device );
+ }
+ mc6846->csr0_to_be_cleared = 0;
+ return mc6846_counter( device ) & 0xff;
+
+ default:
+ logerror( "$%04x mc6846 invalid read offset %i\n", space.machine().firstcpu->pcbase( ), offset );
+ }
+ return 0;
+}
+
+
+
+WRITE8_DEVICE_HANDLER ( mc6846_w )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ switch ( offset )
+ {
+ case 0:
+ case 4:
+ /* CSR is read-only */
+ break;
+
+ case 1:
+ {
+ static const char *const cp2[8] =
+ {
+ "in,neg-edge", "in,neg-edge,intr", "in,pos-edge", "in,pos-edge,intr",
+ "out,intr-ack", "out,i/o-ack", "out,0", "out,1"
+ };
+ static const char *const cp1[8] =
+ {
+ "neg-edge", "neg-edge,intr", "pos-edge", "pos-edge,intr",
+ "latched,neg-edge", "latched,neg-edge,intr",
+ "latcged,pos-edge", "latcged,pos-edge,intr"
+ };
+ LOG (( "$%04x %f: mc6846 PCR write $%02X reset=%i cp2=%s cp1=%s\n",
+ space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data,
+ (data >> 7) & 1, cp2[ (data >> 3) & 7 ], cp1[ data & 7 ] ));
+
+ }
+ mc6846->pcr = data;
+ if ( data & 0x80 )
+ { /* data reset */
+ mc6846->pdr = 0;
+ mc6846->ddr = 0;
+ mc6846->csr &= ~6;
+ mc6846_update_irq( device );
+ }
+ if ( data & 4 )
+ logerror( "$%04x mc6846 CP1 latching not implemented\n", space.machine().firstcpu->pcbase( ) );
+ if (data & 0x20)
+ {
+ if (data & 0x10)
+ {
+ mc6846->cp2_cpu = (data >> 3) & 1;
+ if ( !mc6846->out_cp2.isnull() )
+ mc6846->out_cp2( 0, mc6846->cp2_cpu );
+ }
+ else
+ logerror( "$%04x mc6846 acknowledge not implemented\n", space.machine().firstcpu->pcbase( ) );
+ }
+ break;
+
+ case 2:
+ LOG (( "$%04x %f: mc6846 DDR write $%02X\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data ));
+ if ( ! (mc6846->pcr & 0x80) )
+ {
+ mc6846->ddr = data;
+ if ( !mc6846->out_port.isnull() )
+ mc6846->out_port( 0, mc6846->pdr & mc6846->ddr );
+ }
+ break;
+
+ case 3:
+ LOG (( "$%04x %f: mc6846 PORT write $%02X (mask=$%02X)\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data,mc6846->ddr ));
+ if ( ! (mc6846->pcr & 0x80) )
+ {
+ mc6846->pdr = data;
+ if ( !mc6846->out_port.isnull() )
+ mc6846->out_port( 0, mc6846->pdr & mc6846->ddr );
+ if ( mc6846->csr1_to_be_cleared && (mc6846->csr & 2) )
+ {
+ mc6846->csr &= ~2;
+ LOG (( "$%04x %f: mc6846 CP1 intr reset\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double() ));
+ }
+ if ( mc6846->csr2_to_be_cleared && (mc6846->csr & 4) )
+ {
+ mc6846->csr &= ~4;
+ LOG (( "$%04x %f: mc6846 CP2 intr reset\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double() ));
+ }
+ mc6846->csr1_to_be_cleared = 0;
+ mc6846->csr2_to_be_cleared = 0;
+ mc6846_update_irq( device );
+ }
+ break;
+
+ case 5:
+ {
+ static const char *const mode[8] =
+ {
+ "continuous", "cascaded", "continuous", "one-shot",
+ "freq-cmp", "freq-cmp", "pulse-cmp", "pulse-cmp"
+ };
+ LOG (( "$%04x %f: mc6846 TCR write $%02X reset=%i clock=%s scale=%i mode=%s out=%s\n",
+ space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), data,
+ (data >> 7) & 1, (data & 0x40) ? "extern" : "sys",
+ (data & 0x40) ? 1 : 8, mode[ (data >> 1) & 7 ],
+ (data & 1) ? "enabled" : "0" ));
+
+ mc6846->tcr = data;
+ if ( mc6846->tcr & 1 )
+ {
+ /* timer preset = initialization without launch */
+ mc6846->preset = mc6846->latch;
+ mc6846->csr &= ~1;
+ if ( MODE != 0x30 )
+ mc6846->cto = 0;
+ mc6846_update_cto( device );
+ mc6846->interval->reset( );
+ mc6846->one_shot->reset( );
+ mc6846->timer_started = 0;
+ }
+ else
+ {
+ /* timer launch */
+ if ( ! mc6846->timer_started )
+ mc6846_timer_launch( device );
+ }
+ mc6846_update_irq( device );
+ }
+ break;
+
+ case 6:
+ mc6846->time_MSB = data;
+ break;
+
+ case 7:
+ mc6846->latch = ( ((UINT16) mc6846->time_MSB) << 8 ) + data;
+ LOG (( "$%04x %f: mc6846 COUNT write %i\n", space.machine().firstcpu->pcbase( ), space.machine().time().as_double(), mc6846->latch ));
+ if (!(mc6846->tcr & 0x38))
+ {
+ /* timer initialization */
+ mc6846->preset = mc6846->latch;
+ mc6846->csr &= ~1;
+ mc6846_update_irq( device );
+ mc6846->cto = 0;
+ mc6846_update_cto( device );
+ /* launch only if started */
+ if (!(mc6846->tcr & 1))
+ mc6846_timer_launch( device );
+ }
+ break;
+
+ default:
+ logerror( "$%04x mc6846 invalid write offset %i\n", space.machine().firstcpu->pcbase( ), offset );
+ }
+}
+
+
+
+/******************** outside world interface ************************/
+
+
+
+void mc6846_set_input_cp1 ( device_t *device, int data )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ data = (data != 0 );
+ if ( data == mc6846->cp1 )
+ return;
+ mc6846->cp1 = data;
+ LOG (( "%f: mc6846 input CP1 set to %i\n", device->machine().time().as_double(), data ));
+ if (( data && (mc6846->pcr & 2)) || (!data && !(mc6846->pcr & 2)))
+ {
+ mc6846->csr |= 2;
+ mc6846_update_irq( device );
+ }
+}
+
+void mc6846_set_input_cp2 ( device_t *device, int data )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ data = (data != 0 );
+ if ( data == mc6846->cp2 )
+ return;
+ mc6846->cp2 = data;
+ LOG (( "%f: mc6846 input CP2 set to %i\n", device->machine().time().as_double(), data ));
+ if (mc6846->pcr & 0x20)
+ {
+ if (( data && (mc6846->pcr & 0x10)) || (!data && !(mc6846->pcr & 0x10)))
+ {
+ mc6846->csr |= 4;
+ mc6846_update_irq( device );
+ }
+ }
+}
+
+
+
+/************************ accessors **********************************/
+
+
+
+UINT8 mc6846_get_output_port ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ return PORT;
+}
+
+
+
+UINT8 mc6846_get_output_cto ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ return CTO;
+}
+
+
+
+UINT8 mc6846_get_output_cp2 ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ return mc6846->cp2_cpu;
+}
+
+
+
+UINT16 mc6846_get_preset ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ return mc6846->preset;
+}
+
+
+
+/************************ reset *****************************/
+
+
+static DEVICE_RESET( mc6846 )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ LOG (( "mc6846_reset\n" ));
+ mc6846->cto = 0;
+ mc6846->csr = 0;
+ mc6846->pcr = 0x80;
+ mc6846->ddr = 0;
+ mc6846->pdr = 0;
+ mc6846->tcr = 1;
+ mc6846->cp1 = 0;
+ mc6846->cp2 = 0;
+ mc6846->cp2_cpu = 0;
+ mc6846->latch = 0xffff;
+ mc6846->preset = 0xffff;
+ mc6846->time_MSB = 0;
+ mc6846->csr0_to_be_cleared = 0;
+ mc6846->csr1_to_be_cleared = 0;
+ mc6846->csr2_to_be_cleared = 0;
+ mc6846->timer_started = 0;
+ mc6846->interval->reset( );
+ mc6846->one_shot->reset( );
+}
+
+
+/************************ start *****************************/
+
+static DEVICE_START( mc6846 )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+
+ mc6846->iface = (const mc6846_interface*)device->static_config();
+ mc6846->interval = device->machine().scheduler().timer_alloc(FUNC(mc6846_timer_expire), (void*) device );
+ mc6846->one_shot = device->machine().scheduler().timer_alloc(FUNC(mc6846_timer_one_shot), (void*) device );
+
+ mc6846->out_port.resolve(mc6846->iface->out_port_func, *device); /* 8-bit output */
+ mc6846->out_cp1.resolve(mc6846->iface->out_cp1_func, *device); /* 1-bit output */
+ mc6846->out_cp2.resolve(mc6846->iface->out_cp2_func, *device); /* 1-bit output */
+
+ /* CPU read from the outside through chip */
+ mc6846->in_port.resolve(mc6846->iface->in_port_func, *device); /* 8-bit input */
+
+ /* asynchronous timer output to outside world */
+ mc6846->out_cto.resolve(mc6846->iface->out_cto_func, *device); /* 1-bit output */
+
+ /* timer interrupt */
+ mc6846->irq.resolve(mc6846->iface->irq_func, *device);
+
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->pcr );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->ddr );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->pdr );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->tcr );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp1 );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp2 );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp2_cpu );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cto );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->time_MSB );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr0_to_be_cleared );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr1_to_be_cleared );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr2_to_be_cleared );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->latch );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->preset );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->timer_started );
+}
+
+
+const device_type MC6846 = &device_creator<mc6846_device>;
+
+mc6846_device::mc6846_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MC6846, "Motorola MC6846 programmable timer", tag, owner, clock)
+{
+ m_token = global_alloc_clear(mc6846_t);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void mc6846_device::device_config_complete()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc6846_device::device_start()
+{
+ DEVICE_START_NAME( mc6846 )(this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mc6846_device::device_reset()
+{
+ DEVICE_RESET_NAME( mc6846 )(this);
+}
diff --git a/src/emu/machine/mc6846.h b/src/emu/machine/mc6846.h
new file mode 100644
index 00000000000..9e93c483038
--- /dev/null
+++ b/src/emu/machine/mc6846.h
@@ -0,0 +1,82 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2006
+
+ Motorola 6846 timer emulation.
+
+**********************************************************************/
+
+#ifndef MC6846_H
+#define MC6846_H
+
+class mc6846_device : public device_t
+{
+public:
+ mc6846_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~mc6846_device() { global_free(m_token); }
+
+ // access to legacy token
+ void *token() const { assert(m_token != NULL); return m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ // internal state
+ void *m_token;
+};
+
+extern const device_type MC6846;
+
+
+/* ---------- configuration ------------ */
+
+struct mc6846_interface
+{
+ /* CPU write to the outside through chip */
+ devcb_write8 out_port_func; /* 8-bit output */
+ devcb_write8 out_cp1_func; /* 1-bit output */
+ devcb_write8 out_cp2_func; /* 1-bit output */
+
+ /* CPU read from the outside through chip */
+ devcb_read8 in_port_func; /* 8-bit input */
+
+ /* asynchronous timer output to outside world */
+ devcb_write8 out_cto_func; /* 1-bit output */
+
+ /* timer interrupt */
+ devcb_write_line irq_func;
+};
+
+
+#define MCFG_MC6846_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, MC6846, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_MC6846_MODIFY(_tag, _intrf) \
+ MCFG_DEVICE_MODIFY(_tag) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_MC6846_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+
+/* ---------- functions ------------ */
+/* interface to CPU via address/data bus*/
+extern DECLARE_READ8_DEVICE_HANDLER ( mc6846_r );
+extern DECLARE_WRITE8_DEVICE_HANDLER ( mc6846_w );
+
+/* asynchronous write from outside world into interrupt-generating pins */
+extern void mc6846_set_input_cp1 ( device_t *device, int data );
+extern void mc6846_set_input_cp2 ( device_t *device, int data );
+
+/* polling from outside world */
+extern UINT8 mc6846_get_output_port ( device_t *device );
+extern UINT8 mc6846_get_output_cto ( device_t *device );
+extern UINT8 mc6846_get_output_cp2 ( device_t *device );
+
+/* partial access to internal state */
+extern UINT16 mc6846_get_preset ( device_t *device ); /* timer interval - 1 in us */
+
+#endif
diff --git a/src/emu/machine/mc6854.c b/src/emu/machine/mc6854.c
new file mode 100644
index 00000000000..f453647b60b
--- /dev/null
+++ b/src/emu/machine/mc6854.c
@@ -0,0 +1,1072 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2006
+
+ Motorola 6854 emulation.
+
+ The MC6854 chip is an Advanced Data-Link Controller (ADLC).
+ It provides a high-level network interface that can transimit frames with
+ arbitrary data and address length, and is compatible with the following
+ standards:
+ - ADCCP (Advanced Data Communication Control Procedure)
+ - HDLC (High-Level Data-Link Control)
+ - SDLC (Synchronous Data-Link Control)
+ It is designed to be interfaced with a M6800-family CPU.
+
+ It is used in the "Nano-network" extension of the Thomson computers to
+ link up to 32 computers at 500 Kbps.
+ Many networks involving one PC server and several MO5 or TO7/70 computers
+ were build in French schools in the 1980's to teach computer science.
+
+ TODO:
+ - CRC
+ - DMA mode
+ - loop mode
+ - status prioritization
+ - NRZI vs. NRZ coding
+ - FD output
+
+**********************************************************************/
+
+
+#include "emu.h"
+#include "mc6854.h"
+
+
+
+/******************* parameters ******************/
+
+
+
+#define VERBOSE 0
+
+
+#define MAX_FRAME_LENGTH 65536
+/* arbitrary value, you may need to enlarge it if you get truncated frames */
+
+#define FIFO_SIZE 3
+/* hardcoded size of the 6854 FIFO (this is a hardware limit) */
+
+#define FLAG 0x7e
+/* flag value, as defined by HDLC protocol: 01111110 */
+
+#define BIT_LENGTH attotime::from_hz( 500000 )
+
+
+
+/******************* internal chip data structure ******************/
+
+
+struct mc6854_t
+{
+ devcb_resolved_write_line out_irq_func;
+ devcb_resolved_read_line in_rxd_func;
+ devcb_resolved_write_line out_txd_func;
+ devcb_resolved_write_line out_rts_func;
+ devcb_resolved_write_line out_dtr_func;
+
+ /* interface */
+ const mc6854_interface* iface;
+
+ /* registers */
+ UINT8 cr1, cr2, cr3, cr4; /* control registers */
+ UINT8 sr1, sr2; /* status registers */
+
+ UINT8 cts, dcd;
+
+ /* transmit state */
+ UINT8 tstate;
+ UINT16 tfifo[FIFO_SIZE]; /* X x 8-bit FIFO + full & last marker bits */
+ UINT8 tones; /* counter for zero-insertion */
+ emu_timer *ttimer; /* when to ask for more data */
+
+ /* receive state */
+ UINT8 rstate;
+ UINT32 rreg; /* shift register */
+ UINT8 rones; /* count '1 bits */
+ UINT8 rsize; /* bits in the shift register */
+ UINT16 rfifo[FIFO_SIZE]; /* X x 8-bit FIFO + full & addr marker bits */
+
+ /* frame-based interface*/
+ UINT8 frame[MAX_FRAME_LENGTH];
+ UINT32 flen, fpos;
+
+};
+
+/* meaning of tstate / rtate:
+ 0 = idle / waiting for frame flag
+ 1 = flag sync
+ 2 = 8-bit address field(s)
+ 3-4 = 8-bit control field(s)
+ 5 = 8-bit logical control field(s)
+ 6 = variable-length data field(s)
+*/
+
+
+
+/******************* utility function and macros ********************/
+
+
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+
+/* control register 1 */
+
+#define AC ( mc6854->cr1 & 1 )
+#define FCTDRA ( mc6854->cr2 & 8 )
+/* extra register select bits */
+
+#define RRESET ( mc6854->cr1 & 0x40 )
+#define TRESET ( mc6854->cr1 & 0x80 )
+/* transmit / reset condition */
+
+#define RIE ( mc6854->cr1 & 2 )
+#define TIE ( mc6854->cr1 & 4 )
+/* interrupt enable */
+
+#define DISCONTINUE ( mc6854->cr1 & 0x20 )
+/* discontinue received frame */
+
+
+
+/* control register 2 */
+
+#define PSE ( mc6854->cr2 & 1 )
+/* prioritize status bits (TODO) */
+
+#define TWOBYTES ( mc6854->cr2 & 2 )
+/* two-bytes mode */
+
+#define FMIDLE ( mc6854->cr2 & 4 )
+/* flag time fill (vs. mark idle) */
+
+#define TLAST ( mc6854->cr2 & 0x10 )
+/* transmit last byte of frame */
+
+#define RTS ( mc6854->cr2 & 0x80 )
+/* request-to-send */
+
+
+
+/* control register 3 */
+
+#define LCF ( mc6854->cr3 & 1 )
+/* logical control field select */
+
+#define CEX ( mc6854->cr3 & 2 )
+/* control field is 16 bits instead of 8 */
+
+#define AEX ( mc6854->cr3 & 4 )
+/* extended address mode (vs normal 8-bit address mode) */
+
+#define IDL0 ( mc6854->cr3 & 8 )
+/* idle condition begins with a '0' instead of a '1" */
+
+#define FDSE ( mc6854->cr3 & 0x10 )
+/* enable the flag detect status in SR1 */
+
+#define LOOP ( mc6854->cr3 & 0x20 )
+/* loop mode */
+
+#define TST ( mc6854->cr3 & 0x40 )
+/* test mode (or go active on poll) */
+
+#define DTR ( mc6854->cr3 & 0x80 )
+/* data-transmit-ready (or loop on-line control) */
+
+
+
+/* control register 4 */
+
+#define TWOINTER ( mc6854->cr4 & 1 )
+/* both an openning and a closing inter-frame are sent */
+
+static const int word_length[4] = { 5, 6, 7, 8 };
+#define TWL word_length[ ( mc6854->cr4 >> 1 ) & 3 ]
+#define RWL word_length[ ( mc6854->cr4 >> 3 ) & 3 ]
+/* transmit / receive word length */
+
+#define ABT ( mc6854->cr4 & 0x20 )
+/* aborts */
+
+#define ABTEX ( mc6854->cr4 & 0x40 )
+/* abort generates 16 '1' bits instead of 8 */
+
+#define NRZ ( mc6854->cr4 & 0x80 )
+/* zero complement / non-zero complement data format */
+
+
+
+/* status register 1 */
+#define RDA 0x01 /* receiver data available */
+#define S2RQ 0x02 /* status register #2 read request */
+#define FD 0x04 /* flag detect */
+#define CTS 0x10 /* clear-to-send */
+#define TU 0x20 /* transmitter underrun */
+#define TDRA 0x40 /* transmitter data register available */
+#define IRQ 0x80 /* interrupt request */
+
+
+/* status register 2 */
+#define AP 0x01 /* address present */
+#define FV 0x02 /* frame valid */
+#define RIDLE 0x04 /* receiver idle */
+#define RABT 0x08 /* receiver abort */
+#define ERR 0x10 /* invalid frame error */
+#define DCD 0x20 /* data carrier detect (ignored) */
+#define OVRN 0x40 /* receiver overrun */
+#define RDA2 0x80 /* copy of RDA */
+
+
+
+INLINE mc6854_t* get_safe_token( device_t *device )
+{
+ assert( device != NULL );
+ assert( device->type() == MC6854 );
+ return (mc6854_t*) downcast<mc6854_device *>(device)->token();
+}
+
+
+/*********************** transmit ***********************/
+
+
+
+/* MC6854 fills bit queue */
+static void mc6854_send_bits( device_t *device, UINT32 data, int len, int zi )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ attotime expire;
+ int i;
+ if ( zi )
+ {
+ /* zero-insertion mode */
+ UINT32 d = 0;
+ int l = 0;
+ for ( i = 0; i < len; i++, data >>= 1, l++ )
+ {
+ if ( data & 1 )
+ {
+ d |= 1 << l;
+ mc6854->tones++;
+ if ( mc6854->tones == 5 )
+ {
+ /* insert a '0' after 5 consecutive '1" */
+ mc6854->tones = 0;
+ l++;
+ }
+ }
+ else
+ mc6854->tones = 0;
+ }
+ data = d;
+ len = l;
+ }
+ else
+ mc6854->tones = 0;
+
+ /* send bits */
+ if ( !mc6854->out_txd_func.isnull() )
+ {
+ for ( i = 0; i < len; i++, data >>= 1 )
+ mc6854->out_txd_func( data & 1 );
+ }
+
+ /* schedule when to ask the MC6854 for more bits */
+ expire = mc6854->ttimer ->remaining( );
+ if ( expire== attotime::never )
+ expire = attotime::zero;
+ mc6854->ttimer->reset( expire + (BIT_LENGTH * len));
+}
+
+
+
+/* CPU push -> tfifo[0] -> ... -> tfifo[FIFO_SIZE-1] -> pop */
+static void mc6854_tfifo_push( device_t *device, UINT8 data )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ int i;
+
+ if ( TRESET )
+ return;
+
+ /* push towards the rightmost free entry */
+ for ( i = FIFO_SIZE - 1; i >= 0; i-- )
+ {
+ if ( ! ( mc6854->tfifo[ i ] & 0x100 ) )
+ break;
+ }
+
+ if ( i >= 0 )
+ mc6854->tfifo[ i ] = data | 0x100;
+ else
+ logerror( "%f mc6854_tfifo_push: FIFO overrun\n", device->machine().time().as_double() );
+
+ /* start frame, if needed */
+ if ( ! mc6854->tstate )
+ {
+ LOG(( "%f mc6854_tfifo_push: start frame\n", device->machine().time().as_double() ));
+ mc6854->tstate = 2;
+ mc6854_send_bits( device, FLAG, 8, 0 );
+ }
+}
+
+
+
+/* CPU asks for normal frame termination */
+static void mc6854_tfifo_terminate( device_t *device )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+
+ /* mark most recently pushed byte as the last one of the frame */
+ int i;
+ for ( i = 0; i < FIFO_SIZE; i++ )
+ {
+ if ( mc6854->tfifo[ i ] & 0x100 )
+ {
+ mc6854->tfifo[ i ] |= 0x200;
+ break;
+ }
+ }
+}
+
+
+
+/* call-back to refill the bit-stream from the FIFO */
+static TIMER_CALLBACK(mc6854_tfifo_cb)
+{
+ device_t* device = (device_t*) ptr;
+ mc6854_t* mc6854 = get_safe_token( device );
+ int i, data = mc6854->tfifo[ FIFO_SIZE - 1 ];
+
+ if ( ! mc6854->tstate )
+ return;
+
+ /* shift FIFO to the right */
+ for ( i = FIFO_SIZE - 1; i > 0; i-- )
+ mc6854->tfifo[ i ] = mc6854->tfifo[ i - 1 ];
+ mc6854->tfifo[ 0 ] = 0;
+
+ if ( data & 0x100 )
+ {
+ /* got data */
+
+ int blen = 8;
+
+ switch ( mc6854->tstate )
+ {
+ case 2: /* 8-bit address field */
+ if ( ( data & 1 ) || ( ! AEX ) )
+ mc6854->tstate = 3;
+ LOG(( "%f mc6854_tfifo_cb: address field $%02X\n", machine.time().as_double(), data & 0xff ));
+ break;
+
+ case 3: /* 8-bit control field */
+ if ( CEX )
+ mc6854->tstate = 4;
+ else if ( LCF )
+ mc6854->tstate = 5;
+ else
+ mc6854->tstate = 6;
+ LOG(( "%f mc6854_tfifo_cb: control field $%02X\n", machine.time().as_double(), data & 0xff ));
+ break;
+
+ case 4: /* 8-bit extended control field (optional) */
+ if ( LCF )
+ mc6854->tstate = 5;
+ else
+ mc6854->tstate = 6;
+ LOG(( "%f mc6854_tfifo_cb: control field $%02X\n", machine.time().as_double(), data & 0xff ));
+ break;
+
+ case 5: /* 8-bit logical control (optional) */
+ if ( ! ( data & 0x80 ) )
+ mc6854->tstate = 6;
+ LOG(( "%f mc6854_tfifo_cb: logical control field $%02X\n", machine.time().as_double(), data & 0xff ));
+ break;
+
+ case 6: /* variable-length data */
+ blen = TWL;
+ LOG(( "%f mc6854_tfifo_cb: data field $%02X, %i bits\n", machine.time().as_double(), data & 0xff, blen ));
+ break;
+
+ default:
+ LOG(( "%f mc6854_tfifo_cb: state=%i\n", machine.time().as_double(), mc6854->tstate));
+ }
+
+ if ( mc6854->flen < MAX_FRAME_LENGTH )
+ mc6854->frame[ mc6854->flen++ ] = data;
+ else
+ logerror( "mc6854_tfifo_cb: truncated frame, max=%i\n", MAX_FRAME_LENGTH );
+
+ mc6854_send_bits( device, data, blen, 1 );
+ }
+ else
+ {
+ /* data underrun => abort */
+ logerror( "%f mc6854_tfifo_cb: FIFO underrun\n", machine.time().as_double() );
+ mc6854->sr1 |= TU;
+ mc6854->tstate = 0;
+ mc6854_send_bits( device, 0xffff, ABTEX ? 16 : 8, 0 );
+ mc6854->flen = 0;
+ }
+
+ /* close frame, if needed */
+ if ( data & 0x200 )
+ {
+ int len = mc6854->flen;
+
+ LOG(( "%f mc6854_tfifo_cb: end frame\n", machine.time().as_double() ));
+ mc6854_send_bits( device, 0xdeadbeef, 16, 1 ); /* send check-sum: TODO */
+ mc6854_send_bits( device, FLAG, 8, 0 ); /* send closing flag */
+
+ if ( mc6854->tfifo[ FIFO_SIZE - 1 ] & 0x100 )
+ {
+ /* re-open frame asap */
+ LOG(( "%f mc6854_tfifo_cb: start frame\n", machine.time().as_double() ));
+ if ( TWOINTER )
+ mc6854_send_bits( device, FLAG, 8, 0 );
+ }
+ else
+ mc6854->tstate = 0;
+
+ mc6854->flen = 0;
+ if ( mc6854->iface->out_frame )
+ mc6854->iface->out_frame( device, mc6854->frame, len );
+ }
+}
+
+
+
+static void mc6854_tfifo_clear( device_t *device )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ memset( mc6854->tfifo, 0, sizeof( mc6854->tfifo ) );
+ mc6854->tstate = 0;
+ mc6854->flen = 0;
+ mc6854->ttimer->reset( );
+}
+
+
+
+/*********************** receive ***********************/
+
+
+
+/* MC6854 pushes a field in the FIFO */
+static void mc6854_rfifo_push( device_t *device, UINT8 d )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ int i, blen = 8;
+ unsigned data = d;
+
+ switch ( mc6854->rstate )
+ {
+ case 0:
+ case 1:
+ case 2: /* 8-bit address field */
+ if ( ( data & 1 ) || ( ! AEX ) )
+ mc6854->rstate = 3;
+ else
+ mc6854->rstate = 2;
+ LOG(( "%f mc6854_rfifo_push: address field $%02X\n", device->machine().time().as_double(), data ));
+ data |= 0x400; /* address marker */
+ break;
+
+ case 3: /* 8-bit control field */
+ if ( CEX )
+ mc6854->rstate = 4;
+ else if ( LCF )
+ mc6854->rstate = 5;
+ else
+ mc6854->rstate = 6;
+ LOG(( "%f mc6854_rfifo_push: control field $%02X\n", device->machine().time().as_double(), data ));
+ break;
+
+ case 4: /* 8-bit extended control field (optional) */
+ if ( LCF )
+ mc6854->rstate = 5;
+ else
+ mc6854->rstate = 6;
+ LOG(( "%f mc6854_rfifo_push: control field $%02X\n", device->machine().time().as_double(), data ));
+ break;
+
+ case 5: /* 8-bit logical control (optional) */
+ if ( ! ( data & 0x80 ) )
+ mc6854->rstate = 6;
+ LOG(( "%f mc6854_rfifo_push: logical control field $%02X\n", device->machine().time().as_double(), data ));
+ break;
+
+ case 6: /* variable-length data */
+ blen = RWL;
+ data >>= 8 - blen;
+ LOG(( "%f mc6854_rfifo_push: data field $%02X, %i bits\n", device->machine().time().as_double(), data, blen ));
+ break;
+ }
+
+ /* no further FIFO fill until FV is cleared! */
+ if ( mc6854->sr2 & FV )
+ {
+ LOG(( "%f mc6854_rfifo_push: field not pushed\n", device->machine().time().as_double() ));
+ return;
+ }
+
+ data |= 0x100; /* entry full marker */
+
+ /* push towards the rightmost free entry */
+ for ( i = FIFO_SIZE - 1; i >= 0; i-- )
+ {
+ if ( ! ( mc6854->rfifo[ i ] & 0x100 ) )
+ break;
+ }
+
+ if ( i >= 0 )
+ mc6854->rfifo[ i ] = data | 0x100;
+ else
+ {
+ /* FIFO full */
+ mc6854->sr2 |= OVRN;
+ mc6854->rfifo[ 0 ] = data;
+ logerror( "%f mc6854_rfifo_push: FIFO overrun\n", device->machine().time().as_double() );
+ }
+
+ mc6854->rsize -= blen;
+}
+
+
+
+static void mc6854_rfifo_terminate( device_t *device )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ /* mark most recently pushed byte as the last one of the frame */
+ int i;
+ for ( i = 0; i < FIFO_SIZE; i++ )
+ {
+ if ( mc6854->rfifo[ i ] & 0x100 )
+ {
+ mc6854->tfifo[ i ] |= 0x200;
+ break;
+ }
+
+ }
+
+ mc6854->flen = 0;
+ mc6854->rstate = 1;
+}
+
+
+
+/* CPU pops the FIFO */
+static UINT8 mc6854_rfifo_pop( device_t *device )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ int i, data = mc6854->rfifo[ FIFO_SIZE - 1 ];
+
+ /* shift FIFO to the right */
+ for ( i = FIFO_SIZE - 1; i > 0; i -- )
+ mc6854->rfifo[ i ] = mc6854->rfifo[ i - 1 ];
+ mc6854->rfifo[ 0 ] = 0;
+
+ if ( mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x200 )
+ {
+ /* last byte in frame */
+ mc6854->sr2 |= FV; /* TODO: check CRC & set ERR instead of FV if error*/
+ }
+
+ /* auto-refill in frame mode */
+ if ( mc6854->flen > 0 )
+ {
+ mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] );
+ if ( mc6854->fpos == mc6854->flen )
+ mc6854_rfifo_terminate( device );
+ }
+
+ return data;
+}
+
+
+/* MC6854 makes fields from bits */
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_rx )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ int fieldlen = ( mc6854->rstate < 6 ) ? 8 : RWL;
+
+ if ( RRESET || (mc6854->sr2 & DCD) )
+ return;
+
+ if ( state )
+ {
+ mc6854->rones++;
+ mc6854->rreg = (mc6854->rreg >> 1) | 0x80000000;
+ if ( mc6854->rones >= 8 )
+ {
+ /* abort */
+ mc6854->rstate = 0;
+ mc6854->rsize = 0;
+ if ( mc6854->rstate > 1 )
+ {
+ /* only in-frame abort */
+ mc6854->sr2 |= RABT;
+ LOG(( "%f mc6854_receive_bit: abort\n", device->machine().time().as_double() ));
+ }
+ }
+ else
+ {
+ mc6854->rsize++;
+ if ( mc6854->rstate && mc6854->rsize >= fieldlen + 24 )
+ mc6854_rfifo_push( device, mc6854->rreg );
+ }
+ }
+ else if ( mc6854->rones == 5 )
+ {
+ /* discards '0' inserted after 5 '1' */
+ mc6854->rones = 0;
+ return;
+ }
+ else if ( mc6854->rones == 6 )
+ {
+ /* flag */
+ if ( FDSE )
+ mc6854->sr1 |= FD;
+
+ if ( mc6854->rstate > 1 )
+ {
+ /* end of frame */
+ mc6854->rreg >>= 1;
+ mc6854->rsize++;
+ if ( mc6854->rsize >= fieldlen + 24 ) /* last field */
+ mc6854_rfifo_push( device, mc6854->rreg );
+ mc6854_rfifo_terminate( device );
+ LOG(( "%f mc6854_receive_bit: end of frame\n", device->machine().time().as_double() ));
+ }
+ mc6854->rones = 0;
+ mc6854->rstate = 1;
+ mc6854->rsize = 0;
+ } else
+ {
+ mc6854->rones = 0;
+ mc6854->rreg >>= 1;
+ mc6854->rsize++;
+ if ( mc6854->rstate && mc6854->rsize >= fieldlen + 24 )
+ mc6854_rfifo_push( device, mc6854->rreg );
+ }
+}
+
+
+
+static void mc6854_rfifo_clear( device_t *device )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ memset( mc6854->rfifo, 0, sizeof( mc6854->rfifo ) );
+ mc6854->rstate = 0;
+ mc6854->rreg = 0;
+ mc6854->rsize = 0;
+ mc6854->rones = 0;
+ mc6854->flen = 0;
+}
+
+
+
+int mc6854_send_frame( device_t *device, UINT8* data, int len )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ if ( mc6854->rstate > 1 || mc6854->tstate > 1 || RTS )
+ return -1; /* busy */
+
+ if ( len > MAX_FRAME_LENGTH )
+ {
+ logerror( "mc6854_send_frame: truncated frame, size=%i, max=%i\n", len, MAX_FRAME_LENGTH );
+ len = MAX_FRAME_LENGTH;
+ }
+ else if ( len < 2 )
+ {
+ logerror( "mc6854_send_frame: frame too short, size=%i, min=2\n", len );
+ len = 2;
+ }
+ memcpy( mc6854->frame, data, len );
+ if ( FDSE )
+ mc6854->sr1 |= FD;
+ mc6854->flen = len;
+ mc6854->fpos = 0;
+ mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] );
+ mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] );
+ if ( mc6854->fpos == mc6854->flen )
+ mc6854_rfifo_terminate( device );
+ return 0;
+}
+
+
+
+/************************** CPU interface ****************************/
+
+
+
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_cts )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ if ( ! mc6854->cts && state )
+ mc6854->sr1 |= CTS;
+ mc6854->cts = state;
+
+ if ( mc6854->cts )
+ mc6854->sr1 |= CTS;
+ else
+ mc6854->sr1 &= ~CTS;
+}
+
+
+
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_dcd )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ if ( ! mc6854->dcd && state )
+ {
+ mc6854->sr2 |= DCD;
+ /* partial reset */
+ mc6854->rstate = 0;
+ mc6854->rreg = 0;
+ mc6854->rsize = 0;
+ mc6854->rones = 0;
+ }
+ mc6854->dcd = state;
+}
+
+
+
+static void mc6854_update_sr2( mc6854_t* mc6854 )
+{
+ /* update RDA */
+ mc6854->sr2 |= RDA2;
+ if ( ! (mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x100) )
+ mc6854->sr2 &= ~RDA2;
+ else if ( TWOBYTES && ! (mc6854->tfifo[ FIFO_SIZE - 2 ] & 0x100) )
+ mc6854->sr2 &= ~RDA2;
+
+ /* update AP */
+ if ( mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x400 )
+ mc6854->sr2 |= AP;
+ else
+ mc6854->sr2 &= ~AP;
+}
+
+
+
+static void mc6854_update_sr1( mc6854_t* mc6854 )
+{
+ mc6854_update_sr2( mc6854 );
+
+ /* update S2RQ */
+ if ( mc6854->sr2 & 0x7f )
+ mc6854->sr1 |= S2RQ;
+ else
+ mc6854->sr1 &= ~S2RQ;
+
+ /* update TRDA (always prioritized by CTS) */
+ if ( TRESET || ( mc6854->sr1 & CTS ) )
+ mc6854->sr1 &= ~TDRA;
+ else
+ {
+ mc6854->sr1 |= TDRA;
+ if ( mc6854->tfifo[ 0 ] & 0x100 )
+ mc6854->sr1 &= ~TDRA;
+ else if ( TWOBYTES && (mc6854->tfifo[ 1 ] & 0x100) )
+ mc6854->sr1 &= ~TDRA;
+ }
+
+ /* update RDA */
+ if ( mc6854->sr2 & RDA2 )
+ mc6854->sr1 |= RDA;
+ else
+ mc6854->sr1 &= ~RDA;
+
+ /* update IRQ */
+ mc6854->sr1 &= ~IRQ;
+ if ( RIE && (mc6854->sr1 & (TU | TDRA) ) )
+ mc6854->sr1 |= IRQ;
+ if ( TIE )
+ {
+ if ( mc6854->sr1 & (S2RQ | RDA | CTS) )
+ mc6854->sr1 |= IRQ;
+ if ( mc6854->sr2 & (ERR | FV | DCD | OVRN | RABT | RIDLE | AP) )
+ mc6854->sr1 |= IRQ;
+ }
+
+ mc6854->out_irq_func((mc6854->sr1 & IRQ) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+
+READ8_DEVICE_HANDLER ( mc6854_r )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ switch ( offset )
+ {
+ case 0: /* status register 1 */
+ mc6854_update_sr1( mc6854 );
+ LOG(( "%f $%04x mc6854_r: get SR1=$%02X (rda=%i,s2rq=%i,fd=%i,cts=%i,tu=%i,tdra=%i,irq=%i)\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->sr1,
+ ( mc6854->sr1 & RDA) ? 1 : 0, ( mc6854->sr1 & S2RQ) ? 1 : 0,
+ ( mc6854->sr1 & FD ) ? 1 : 0, ( mc6854->sr1 & CTS ) ? 1 : 0,
+ ( mc6854->sr1 & TU ) ? 1 : 0, ( mc6854->sr1 & TDRA) ? 1 : 0,
+ ( mc6854->sr1 & IRQ) ? 1 : 0 ));
+ return mc6854->sr1;
+
+ case 1: /* status register 2 */
+ mc6854_update_sr2( mc6854 );
+ LOG(( "%f $%04x mc6854_r: get SR2=$%02X (ap=%i,fv=%i,ridle=%i,rabt=%i,err=%i,dcd=%i,ovrn=%i,rda2=%i)\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->sr2,
+ ( mc6854->sr2 & AP ) ? 1 : 0, ( mc6854->sr2 & FV ) ? 1 : 0,
+ ( mc6854->sr2 & RIDLE) ? 1 : 0, ( mc6854->sr2 & RABT) ? 1 : 0,
+ ( mc6854->sr2 & ERR ) ? 1 : 0, ( mc6854->sr2 & DCD ) ? 1 : 0,
+ ( mc6854->sr2 & OVRN ) ? 1 : 0, ( mc6854->sr2 & RDA2) ? 1 : 0 ));
+ return mc6854->sr2;
+
+ case 2: /* receiver data register */
+ case 3:
+ {
+ UINT8 data = mc6854_rfifo_pop( device );
+ LOG(( "%f $%04x mc6854_r: get data $%02X\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data ));
+ return data;
+ }
+
+ default:
+ logerror( "$%04x mc6854 invalid read offset %i\n", space.machine().firstcpu->pcbase( ), offset );
+ }
+ return 0;
+}
+
+
+
+WRITE8_DEVICE_HANDLER ( mc6854_w )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ switch ( offset )
+ {
+ case 0: /* control register 1 */
+ mc6854->cr1 = data;
+ LOG(( "%f $%04x mc6854_w: set CR1=$%02X (ac=%i,irq=%c%c,%sreset=%c%c)\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr1,
+ AC ? 1 : 0,
+ RIE ? 'r' : '-', TIE ? 't' : '-',
+ DISCONTINUE ? "discontinue," : "",
+ RRESET ? 'r' : '-', TRESET ? 't' : '-'
+ ));
+ if ( mc6854->cr1 & 0xc )
+ logerror( "$%04x mc6854 DMA not handled (CR1=$%02X)\n",
+ space.machine().firstcpu->pcbase( ), mc6854->cr1 );
+ if ( DISCONTINUE )
+ {
+ /* abort receive FIFO but keeps shift register & synchro */
+ mc6854->rstate = 0;
+ memset( mc6854->rfifo, 0, sizeof( mc6854->rfifo ) );
+ }
+ if ( RRESET )
+ {
+ /* abort FIFO & synchro */
+ mc6854_rfifo_clear( device );
+ mc6854->sr1 &= ~FD;
+ mc6854->sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD);
+ if ( mc6854->dcd ) mc6854->sr2 |= DCD;
+ }
+ if ( TRESET )
+ {
+ mc6854_tfifo_clear( device );
+ mc6854->sr1 &= ~(TU | TDRA | CTS);
+ if ( mc6854->cts ) mc6854->sr1 |= CTS;
+ }
+ break;
+
+ case 1:
+ if ( AC )
+ {
+ /* control register 3 */
+ mc6854->cr3 = data;
+ LOG(( "%f $%04x mc6854_w: set CR3=$%02X (lcf=%i,aex=%i,idl=%i,fdse=%i,loop=%i,tst=%i,dtr=%i)\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr3,
+ LCF ? (CEX ? 16 : 8) : 0, AEX ? 1 : 0,
+ IDL0 ? 0 : 1, FDSE ? 1 : 0, LOOP ? 1 : 0,
+ TST ? 1 : 0, DTR ? 1 : 0
+ ));
+ if ( LOOP )
+ logerror( "$%04x mc6854 loop mode not handled (CR3=$%02X)\n", space.machine().firstcpu->pcbase( ), mc6854->cr3 );
+ if ( TST )
+ logerror( "$%04x mc6854 test mode not handled (CR3=$%02X)\n", space.machine().firstcpu->pcbase( ), mc6854->cr3 );
+
+ mc6854->out_dtr_func( DTR ? 1 : 0 );
+
+ }
+ else
+ {
+ /* control register 2 */
+ mc6854->cr2 = data;
+ LOG(( "%f $%04x mc6854_w: set CR2=$%02X (pse=%i,bytes=%i,fmidle=%i,%s,tlast=%i,clr=%c%c,rts=%i)\n",
+ space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr2,
+ PSE ? 1 : 0, TWOBYTES ? 2 : 1, FMIDLE ? 1 : 0,
+ FCTDRA ? "fc" : "tdra", TLAST ? 1 : 0,
+ data & 0x20 ? 'r' : '-', data & 0x40 ? 't' : '-',
+ RTS ? 1 : 0 ));
+ if ( PSE )
+ logerror( "$%04x mc6854 status prioritization not handled (CR2=$%02X)\n", space.machine().firstcpu->pcbase( ), mc6854->cr2 );
+ if ( TLAST )
+ mc6854_tfifo_terminate( device );
+ if ( data & 0x20 )
+ {
+ /* clear receiver status */
+ mc6854->sr1 &= ~FD;
+ mc6854->sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD);
+ if ( mc6854->dcd )
+ mc6854->sr2 |= DCD;
+ }
+ if ( data & 0x40 )
+ {
+ /* clear transmitter status */
+ mc6854->sr1 &= ~(TU | TDRA | CTS);
+ if ( mc6854->cts )
+ mc6854->sr1 |= CTS;
+ }
+
+ mc6854->out_rts_func( RTS ? 1 : 0 );
+ }
+ break;
+
+ case 2: /* transmitter data: continue data */
+ LOG(( "%f $%04xmc6854_w: push data=$%02X\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data ));
+ mc6854_tfifo_push( device, data );
+ break;
+
+ case 3:
+ if ( AC )
+ {
+ /* control register 4 */
+ mc6854->cr4 = data;
+ LOG(( "%f $%04x mc6854_w: set CR4=$%02X (interframe=%i,tlen=%i,rlen=%i,%s%s)\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), mc6854->cr4,
+ TWOINTER ? 2 : 1,
+ TWL, RWL,
+ ABT ? ( ABTEX ? "abort-ext," : "abort,") : "",
+ NRZ ? "nrz" : "nrzi" ));
+ if ( ABT )
+ {
+ mc6854->tstate = 0;
+ mc6854_send_bits( device, 0xffff, ABTEX ? 16 : 8, 0 );
+ mc6854->flen = 0;
+ }
+ }
+ else
+ {
+ /* transmitter data: last data */
+ LOG(( "%f $%04x mc6854_w: push last-data=$%02X\n", space.machine().time().as_double(), space.machine().firstcpu->pcbase( ), data ));
+ mc6854_tfifo_push( device, data );
+ mc6854_tfifo_terminate( device );
+ }
+ break;
+
+ default:
+ logerror( "$%04x mc6854 invalid write offset %i (data=$%02X)\n", space.machine().firstcpu->pcbase( ), offset, data );
+ }
+}
+
+WRITE_LINE_DEVICE_HANDLER( mc6854_rxc_w )
+{
+ // TODO
+}
+
+WRITE_LINE_DEVICE_HANDLER( mc6854_txc_w )
+{
+ // TODO
+}
+
+/************************ reset *****************************/
+
+static DEVICE_RESET( mc6854 )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ LOG (( "mc6854 reset\n" ));
+ mc6854->cr1 = 0xc0; /* reset condition */
+ mc6854->cr2 = 0;
+ mc6854->cr3 = 0;
+ mc6854->cr4 = 0;
+ mc6854->sr1 = 0;
+ mc6854->sr2 = 0;
+ mc6854->cts = 0;
+ mc6854->dcd = 0;
+ mc6854_tfifo_clear( device );
+ mc6854_rfifo_clear( device );
+}
+
+
+
+/************************ start *****************************/
+
+static DEVICE_START( mc6854 )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+
+ mc6854->iface = (const mc6854_interface*)device->static_config();
+ mc6854->out_irq_func.resolve(mc6854->iface->out_irq_func, *device);
+ mc6854->in_rxd_func.resolve(mc6854->iface->in_rxd_func, *device);
+ mc6854->out_txd_func.resolve(mc6854->iface->out_txd_func, *device);
+ mc6854->out_rts_func.resolve(mc6854->iface->out_rts_func, *device);
+ mc6854->out_dtr_func.resolve(mc6854->iface->out_dtr_func, *device);
+
+ mc6854->ttimer = device->machine().scheduler().timer_alloc(FUNC(mc6854_tfifo_cb), (void*) device );
+
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr1 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr2 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr3 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr4 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->sr1 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->sr2 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cts );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->dcd );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->tstate );
+ state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->tfifo );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->tones );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rstate );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rreg );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rones );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rsize );
+ state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->rfifo );
+ state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->frame );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->flen );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->fpos );
+}
+
+
+
+const device_type MC6854 = &device_creator<mc6854_device>;
+
+mc6854_device::mc6854_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MC6854, "Motorola MC6854 ADLC", tag, owner, clock)
+{
+ m_token = global_alloc_clear(mc6854_t);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void mc6854_device::device_config_complete()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc6854_device::device_start()
+{
+ DEVICE_START_NAME( mc6854 )(this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mc6854_device::device_reset()
+{
+ DEVICE_RESET_NAME( mc6854 )(this);
+}
diff --git a/src/emu/machine/mc6854.h b/src/emu/machine/mc6854.h
new file mode 100644
index 00000000000..e2c5ee3909c
--- /dev/null
+++ b/src/emu/machine/mc6854.h
@@ -0,0 +1,100 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2006
+
+ Motorola 6854 emulation (network interface).
+
+**********************************************************************/
+
+#ifndef MC6854_H
+#define MC6854_H
+
+class mc6854_device : public device_t
+{
+public:
+ mc6854_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~mc6854_device() { global_free(m_token); }
+
+ // access to legacy token
+ void *token() const { assert(m_token != NULL); return m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ // internal state
+ void *m_token;
+};
+
+extern const device_type MC6854;
+
+
+/* we provide two interfaces:
+ - a bit-based interface: out_tx, set_rx
+ - a frame-based interface: out_frame, send_frame
+
+ The bit-based interface is low-level and slow.
+ Use it to simulate the actual bits sent into the wires, e.g., to connect
+ the emulator to another bit-based emulated network device, or an actual
+ device.
+
+ The frame-based interface is higher-level and faster.
+ It passes bytes directly from one end to the other without bothering with
+ the actual bit-encoding, synchronization, and CRC.
+ Once completed, a frame is sent through out_frame. Aborted frames are not
+ transmitted at all. No start flag, stop flag, or crc bits are trasmitted.
+ send_frame makes a frame available to the CPU through the 6854 (it may
+ fail and return -1 if the 6854 is not ready to accept the frame; even
+ if the frame is accepted and 0 is returned, the CPU may abort it). Ony
+ full frames are accepted.
+*/
+
+
+/* ---------- configuration ------------ */
+
+struct mc6854_interface
+{
+ devcb_write_line out_irq_func; /* interrupt request */
+
+ /* low-level, bit-based interface */
+ devcb_read_line in_rxd_func; /* receive bit */
+ devcb_write_line out_txd_func; /* transmit bit */
+
+ /* high-level, frame-based interface */
+ void ( * out_frame ) ( device_t *device, UINT8* data, int length );
+
+ /* control lines */
+ devcb_write_line out_rts_func; /* 1 = transmitting, 0 = idle */
+ devcb_write_line out_dtr_func; /* 1 = data transmit ready, 0 = busy */
+};
+
+
+#define MCFG_MC6854_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, MC6854, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_MC6854_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+
+/* ---------- functions ------------ */
+/* interface to CPU via address/data bus*/
+extern DECLARE_READ8_DEVICE_HANDLER ( mc6854_r );
+extern DECLARE_WRITE8_DEVICE_HANDLER ( mc6854_w );
+
+/* low-level, bit-based interface */
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_rx );
+
+/* high-level, frame-based interface */
+extern int mc6854_send_frame( device_t *device, UINT8* data, int length ); /* ret -1 if busy */
+
+/* control lines */
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_cts ); /* 1 = clear-to-send, 0 = busy */
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_dcd ); /* 1 = carrier, 0 = no carrier */
+
+/* clock */
+WRITE_LINE_DEVICE_HANDLER( mc6854_rxc_w );
+WRITE_LINE_DEVICE_HANDLER( mc6854_txc_w );
+
+#endif
diff --git a/src/emu/machine/mm58274c.c b/src/emu/machine/mm58274c.c
new file mode 100644
index 00000000000..0b4d270e411
--- /dev/null
+++ b/src/emu/machine/mm58274c.c
@@ -0,0 +1,552 @@
+/***************************************************************************
+
+ mm58274c.c
+
+ mm58274c emulation
+
+ Reference:
+ * National Semiconductor MM58274C Microprocessor Compatible Real Time Clock
+ <http://www.national.com/ds/MM/MM58274C.pdf>
+
+ Todo:
+ * Clock initialization will only work with the BwG: we need to provide
+ a way to customize it.
+ * Save the config to NVRAM?
+ * Support interrupt pin output
+
+ Raphael Nabet, 2002
+
+***************************************************************************/
+
+#include "emu.h"
+#include "mm58274c.h"
+
+struct mm58274c_t
+{
+ const mm58274c_interface *intf;
+
+ int status; /* status register (*read* from address 0 = control register) */
+ int control; /* control register (*write* to address 0) */
+
+ int clk_set; /* clock setting register */
+ int int_ctl; /* interrupt control register */
+
+
+ int wday; /* day of the week (1-7 (1=day1 as set in init)) */
+ int years1; /* years (BCD: 0-99) */
+ int years2;
+ int months1; /* months (BCD: 1-12) */
+ int months2;
+ int days1; /* days (BCD: 1-31) */
+ int days2;
+ int hours1; /* hours (BCD : 0-23) */
+ int hours2;
+ int minutes1; /* minutes (BCD : 0-59) */
+ int minutes2;
+ int seconds1; /* seconds (BCD : 0-59) */
+ int seconds2;
+ int tenths; /* tenths of second (BCD : 0-9) */
+
+ emu_timer *increment_rtc;
+ emu_timer *interrupt_timer;
+};
+
+enum
+{
+ st_dcf = 0x8, /* data-changed flag */
+ st_if = 0x1, /* interrupt flag */
+
+ ctl_test = 0x8, /* test mode (0=normal, 1=test) (not emulated) */
+ ctl_clkstop = 0x4, /* clock start/stop (0=run, 1=stop) */
+ ctl_intsel = 0x2, /* interrupt select (0=clock setting register, 1=interrupt register) */
+ ctl_intstop = 0x1, /* interrupt start stop (0=interrupt run, 1=interrupt stop) */
+
+ clk_set_leap = 0xc, /* leap year counter (0 indicates a leap year) */
+ clk_set_leap_inc = 0x4, /* leap year increment */
+ clk_set_pm = 0x2, /* am/pm indicator (0 = am, 1 = pm, 0 in 24-hour mode) */
+ clk_set_24 = 0x1, /* 12/24-hour select bit (1= 24-hour mode) */
+
+ int_ctl_rpt = 0x8, /* 1 for repeated interrupt */
+ int_ctl_dly = 0x7 /* 0 no interrupt, 1 = .1 second, 2=.5, 3=1, 4=5, 5=10, 6=30, 7=60 */
+};
+
+
+INLINE mm58274c_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == MM58274C);
+
+ return (mm58274c_t *)downcast<mm58274c_device *>(device)->token();
+}
+
+static attotime interrupt_period_table(int val)
+{
+ switch(val)
+ {
+ case 0: return attotime::from_msec(0);
+ case 1: return attotime::from_msec(100);
+ case 2: return attotime::from_msec(500);
+ case 3: return attotime::from_seconds(1);
+ case 4: return attotime::from_seconds(5);
+ case 5: return attotime::from_seconds(10);
+ case 6: return attotime::from_seconds(30);
+ case 7: return attotime::from_seconds(60);
+ default: fatalerror("out of range\n");
+ }
+};
+
+READ8_DEVICE_HANDLER( mm58274c_r )
+{
+ mm58274c_t *mm58274c = get_safe_token(device);
+ int reply;
+
+ offset &= 0xf;
+
+ switch (offset)
+ {
+ case 0x0: /* Control Register */
+ reply = mm58274c->status;
+ mm58274c->status = 0;
+ break;
+
+ case 0x1: /* Tenths of Seconds */
+ reply = mm58274c->tenths;
+ break;
+
+ case 0x2: /* Units Seconds */
+ reply = mm58274c->seconds2;
+ break;
+
+ case 0x3: /* Tens Seconds */
+ reply = mm58274c->seconds1;
+ break;
+
+ case 0x04: /* Units Minutes */
+ reply = mm58274c->minutes2;
+ break;
+
+ case 0x5: /* Tens Minutes */
+ reply = mm58274c->minutes1;
+ break;
+
+ case 0x6: /* Units Hours */
+ reply = mm58274c->hours2;
+ break;
+
+ case 0x7: /* Tens Hours */
+ reply = mm58274c->hours1;
+ break;
+
+ case 0x8: /* Units Days */
+ reply = mm58274c->days2;
+ break;
+
+ case 0x9: /* Tens Days */
+ reply = mm58274c->days1;
+ break;
+
+ case 0xA: /* Units Months */
+ reply = mm58274c->months2;
+ break;
+
+ case 0xB: /* Tens Months */
+ reply = mm58274c->months1;
+ break;
+
+ case 0xC: /* Units Years */
+ reply = mm58274c->years2;
+ break;
+
+ case 0xD: /* Tens Years */
+ reply = mm58274c->years1;
+ break;
+
+ case 0xE: /* Day of Week */
+ reply = mm58274c->wday;
+ break;
+
+ case 0xF: /* Clock Setting & Interrupt Registers */
+ if (mm58274c->control & ctl_intsel)
+ /* interrupt register */
+ reply = mm58274c->int_ctl;
+ else
+ { /* clock setting register */
+ if (mm58274c->clk_set & clk_set_24)
+ /* 24-hour mode */
+ reply = mm58274c->clk_set & ~clk_set_pm;
+ else
+ /* 12-hour mode */
+ reply = mm58274c->clk_set;
+ }
+ break;
+
+ default:
+ reply = 0;
+ break;
+ }
+
+ return reply;
+}
+
+
+WRITE8_DEVICE_HANDLER (mm58274c_w)
+{
+ mm58274c_t *mm58274c = get_safe_token(device);
+
+ offset &= 0xf;
+ data &= 0xf;
+
+ switch (offset)
+ {
+ case 0x0: /* Control Register (test mode and interrupt not emulated) */
+ if ((! (mm58274c->control & ctl_intstop)) && (data & ctl_intstop))
+ /* interrupt stop */
+ mm58274c->interrupt_timer->enable(0);
+ else if ((mm58274c->control & ctl_intstop) && (! (data & ctl_intstop)))
+ {
+ /* interrupt run */
+ attotime period = interrupt_period_table(mm58274c->int_ctl & int_ctl_dly);
+
+ mm58274c->interrupt_timer->adjust(period, 0, mm58274c->int_ctl & int_ctl_rpt ? period : attotime::zero);
+ }
+ if (data & ctl_clkstop)
+ /* stopping the clock clears the tenth counter */
+ mm58274c->tenths = 0;
+ mm58274c->control = data;
+ break;
+
+ case 0x1: /* Tenths of Seconds: cannot be written */
+ break;
+
+ case 0x2: /* Units Seconds */
+ mm58274c->seconds2 = data;
+ break;
+
+ case 0x3: /* Tens Seconds */
+ mm58274c->seconds1 = data;
+ break;
+
+ case 0x4: /* Units Minutes */
+ mm58274c->minutes2 = data;
+ break;
+
+ case 0x5: /* Tens Minutes */
+ mm58274c->minutes1 = data;
+ break;
+
+ case 0x6: /* Units Hours */
+ mm58274c->hours2 = data;
+ break;
+
+ case 0x7: /* Tens Hours */
+ mm58274c->hours1 = data;
+ break;
+
+ case 0x8: /* Units Days */
+ mm58274c->days2 = data;
+ break;
+
+ case 0x9: /* Tens Days */
+ mm58274c->days1 = data;
+ break;
+
+ case 0xA: /* Units Months */
+ mm58274c->months2 = data;
+ break;
+
+ case 0xB: /* Tens Months */
+ mm58274c->months1 = data;
+ break;
+
+ case 0xC: /* Units Years */
+ mm58274c->years2 = data;
+ break;
+
+ case 0xD: /* Tens Years */
+ mm58274c->years1 = data;
+ break;
+
+ case 0xE: /* Day of Week */
+ mm58274c->wday = data;
+ break;
+
+ case 0xF: /* Clock Setting & Interrupt Registers */
+ if (mm58274c->control & ctl_intsel)
+ {
+ /* interrupt register (not emulated) */
+ mm58274c->int_ctl = data;
+ if (! (mm58274c->control & ctl_intstop))
+ {
+ /* interrupt run */
+ attotime period = interrupt_period_table(mm58274c->int_ctl & int_ctl_dly);
+
+ mm58274c->interrupt_timer->adjust(period, 0, mm58274c->int_ctl & int_ctl_rpt ? period : attotime::zero);
+ }
+ }
+ else
+ {
+ /* clock setting register */
+ mm58274c->clk_set = data;
+ #if 0
+ if (mm58274c->clk_set & clk_set_24)
+ /* 24-hour mode */
+ mm58274c->clk_set &= ~clk_set_pm;
+ #endif
+ }
+ break;
+ }
+}
+
+
+/*
+ Set RTC interrupt flag
+*/
+static TIMER_CALLBACK(rtc_interrupt_callback)
+{
+ device_t *device = (device_t *)ptr;
+ mm58274c_t *mm58274c = get_safe_token(device);
+ mm58274c->status |= st_if;
+}
+
+
+/*
+ Increment RTC clock (timed interrupt every 1/10s)
+*/
+
+static TIMER_CALLBACK(increment_rtc)
+{
+ device_t *device = (device_t *)ptr;
+ mm58274c_t *mm58274c = get_safe_token(device);
+ if (! (mm58274c->control & ctl_clkstop))
+ {
+ mm58274c->status |= st_dcf;
+
+ if ((++mm58274c->tenths) == 10)
+ {
+ mm58274c->tenths = 0;
+
+ if ((++mm58274c->seconds2) == 10)
+ {
+ mm58274c->seconds2 = 0;
+
+ if ((++mm58274c->seconds1) == 6)
+ {
+ mm58274c->seconds1 = 0;
+
+ if ((++mm58274c->minutes2) == 10)
+ {
+ mm58274c->minutes2 = 0;
+
+ if ((++mm58274c->minutes1) == 6)
+ {
+ mm58274c->minutes1 = 0;
+
+ if ((++mm58274c->hours2) == 10)
+ {
+ mm58274c->hours2 = 0;
+
+ mm58274c->hours1++;
+ }
+
+ /* handle wrap-around */
+ if ((! (mm58274c->clk_set & clk_set_24))
+ && ((mm58274c->hours1*10 + mm58274c->hours2) == 12))
+ {
+ mm58274c->clk_set ^= clk_set_pm;
+ }
+ if ((! (mm58274c->clk_set & clk_set_24))
+ && ((mm58274c->hours1*10 + mm58274c->hours2) == 13))
+ {
+ mm58274c->hours1 = 0;
+ mm58274c->hours2 = 1;
+ }
+
+ if ((mm58274c->clk_set & clk_set_24)
+ && ((mm58274c->hours1*10 + mm58274c->hours2) == 24))
+ {
+ mm58274c->hours1 = mm58274c->hours2 = 0;
+ }
+
+ /* increment day if needed */
+ if ((mm58274c->clk_set & clk_set_24)
+ ? ((mm58274c->hours1*10 + mm58274c->hours2) == 0)
+ : (((mm58274c->hours1*10 + mm58274c->hours2) == 12)
+ && (! (mm58274c->clk_set & clk_set_pm))))
+ {
+ int days_in_month;
+
+ if ((++mm58274c->days2) == 10)
+ {
+ mm58274c->days2 = 0;
+
+ mm58274c->days1++;
+ }
+
+ if ((++mm58274c->wday) == 8)
+ mm58274c->wday = 1;
+
+ {
+ static const int days_in_month_array[] =
+ {
+ 31,28,31, 30,31,30,
+ 31,31,30, 31,30,31
+ };
+
+ if (((mm58274c->months1*10 + mm58274c->months2) != 2) || (mm58274c->clk_set & clk_set_leap))
+ days_in_month = days_in_month_array[mm58274c->months1*10 + mm58274c->months2 - 1];
+ else
+ days_in_month = 29;
+ }
+
+
+ if ((mm58274c->days1*10 + mm58274c->days2) == days_in_month+1)
+ {
+ mm58274c->days1 = 0;
+ mm58274c->days2 = 1;
+
+ if ((++mm58274c->months2) == 10)
+ {
+ mm58274c->months2 = 0;
+
+ mm58274c->months1++;
+ }
+
+ if ((mm58274c->months1*10 + mm58274c->months2) == 13)
+ {
+ mm58274c->months1 = 0;
+ mm58274c->months2 = 1;
+
+ mm58274c->clk_set = (mm58274c->clk_set & ~clk_set_leap)
+ | ((mm58274c->clk_set + clk_set_leap_inc) & clk_set_leap);
+
+ if ((++mm58274c->years2) == 10)
+ {
+ mm58274c->years2 = 0;
+
+ if ((++mm58274c->years1) == 10)
+ mm58274c->years1 = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* Device Interface */
+
+static DEVICE_START( mm58274c )
+{
+ mm58274c_t *mm58274c = get_safe_token(device);
+
+ // validate arguments
+ assert(device != NULL);
+ assert(device->tag() != NULL);
+ assert(device->static_config() != NULL);
+
+ mm58274c->intf = (const mm58274c_interface*)device->static_config();
+ // register for state saving
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->status);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->control);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->clk_set);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->int_ctl);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->wday);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->years1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->years2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->months1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->months2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->days1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->days2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->hours1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->hours2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->minutes1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->minutes2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->seconds1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->seconds2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->tenths);
+
+ mm58274c->increment_rtc = device->machine().scheduler().timer_alloc(FUNC(increment_rtc), ((void*)device));
+ mm58274c->increment_rtc->adjust(attotime::zero, 0, attotime::from_msec(100));
+ mm58274c->interrupt_timer = device->machine().scheduler().timer_alloc(FUNC(rtc_interrupt_callback), ((void*)device));
+}
+
+
+static DEVICE_RESET( mm58274c )
+{
+ mm58274c_t *mm58274c = get_safe_token(device);
+ system_time systime;
+
+ /* get the current date/time from the core */
+ device->machine().current_datetime(systime);
+
+ mm58274c->clk_set = systime.local_time.year & 3 << 2;
+ if (mm58274c->intf->mode24)
+ mm58274c->clk_set |= clk_set_24;
+
+ /* The clock count starts on 1st January 1900 */
+ mm58274c->wday = 1 + ((systime.local_time.weekday - mm58274c->intf->day1)%7);
+ mm58274c->years1 = (systime.local_time.year / 10) % 10;
+ mm58274c->years2 = systime.local_time.year % 10;
+ mm58274c->months1 = (systime.local_time.month + 1) / 10;
+ mm58274c->months2 = (systime.local_time.month + 1) % 10;
+ mm58274c->days1 = systime.local_time.mday / 10;
+ mm58274c->days2 = systime.local_time.mday % 10;
+ if (!mm58274c->intf->mode24)
+ {
+ /* 12-hour mode */
+ if (systime.local_time.hour > 12)
+ {
+ systime.local_time.hour -= 12;
+ mm58274c->clk_set |= clk_set_pm;
+ }
+ if (systime.local_time.hour == 0)
+ systime.local_time.hour = 12;
+ }
+ mm58274c->hours1 = systime.local_time.hour / 10;
+ mm58274c->hours2 = systime.local_time.hour % 10;
+ mm58274c->minutes1 = systime.local_time.minute / 10;
+ mm58274c->minutes2 = systime.local_time.minute % 10;
+ mm58274c->seconds1 = systime.local_time.second / 10;
+ mm58274c->seconds2 = systime.local_time.second % 10;
+ mm58274c->tenths = 0;
+}
+
+const device_type MM58274C = &device_creator<mm58274c_device>;
+
+mm58274c_device::mm58274c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MM58274C, "National Semiconductor MM58274C", tag, owner, clock)
+{
+ m_token = global_alloc_clear(mm58274c_t);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void mm58274c_device::device_config_complete()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mm58274c_device::device_start()
+{
+ DEVICE_START_NAME( mm58274c )(this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mm58274c_device::device_reset()
+{
+ DEVICE_RESET_NAME( mm58274c )(this);
+}
diff --git a/src/emu/machine/mm58274c.h b/src/emu/machine/mm58274c.h
new file mode 100644
index 00000000000..983d501dc59
--- /dev/null
+++ b/src/emu/machine/mm58274c.h
@@ -0,0 +1,56 @@
+#ifndef MM58274C_H
+#define MM58274C_H
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+class mm58274c_device : public device_t
+{
+public:
+ mm58274c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~mm58274c_device() { global_free(m_token); }
+
+ // access to legacy token
+ void *token() const { assert(m_token != NULL); return m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ // internal state
+ void *m_token;
+};
+
+extern const device_type MM58274C;
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+/* interface */
+/*
+ Initializes the clock chip.
+ day1 must be set to a value from 0 (sunday), 1 (monday) ...
+ to 6 (saturday) and is needed to correctly retrieve the day-of-week
+ from the host system clock.
+*/
+struct mm58274c_interface
+{
+ int mode24; /* 24/12 mode */
+ int day1; /* first day of week */
+};
+
+DECLARE_READ8_DEVICE_HANDLER ( mm58274c_r );
+DECLARE_WRITE8_DEVICE_HANDLER( mm58274c_w );
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_MM58274C_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, MM58274C, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#endif /* MM58274C_H */
diff --git a/src/emu/machine/mos6530.c b/src/emu/machine/mos6530.c
new file mode 100644
index 00000000000..9075b9a2cb5
--- /dev/null
+++ b/src/emu/machine/mos6530.c
@@ -0,0 +1,469 @@
+/***************************************************************************
+
+ MIOT 6530 emulation
+
+The timer seems to follow these rules:
+- When the timer flag changes from 0 to 1 the timer continues to count
+ down at a 1 cycle rate.
+- When the timer is being read or written the timer flag is reset.
+- When the timer flag is set and the timer contents are 0, the counting
+ stops.
+
+From the operation of the KIM1 it expects the irqflag to be set whenever
+the unit is reset. This is something that is not clear from the datasheet
+and should be verified against real hardware.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "mos6530.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+enum
+{
+ TIMER_IDLE,
+ TIMER_COUNTING,
+ TIMER_FINISHING
+};
+
+#define TIMER_FLAG 0x80
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct mos6530_port
+{
+ devcb_resolved_read8 in_port_func;
+ devcb_resolved_write8 out_port_func;
+
+ UINT8 in;
+ UINT8 out;
+ UINT8 ddr;
+};
+
+
+struct mos6530_state
+{
+ devcb_resolved_write_line out_irq_func;
+
+ mos6530_port port[2];
+
+ UINT8 irqstate;
+ UINT8 irqenable;
+
+ UINT8 timershift;
+ UINT8 timerstate;
+ emu_timer * timer;
+
+ UINT32 clock;
+};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ get_safe_token - convert a device's token
+ into a mos6530_state
+-------------------------------------------------*/
+
+INLINE mos6530_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == MOS6530);
+ return (mos6530_state *)downcast<mos6530_device *>(device)->token();
+}
+
+
+/*-------------------------------------------------
+ update_irqstate - update the IRQ state
+ based on interrupt enables
+-------------------------------------------------*/
+
+INLINE void update_irqstate(device_t *device)
+{
+ mos6530_state *miot = get_safe_token(device);
+ UINT8 out = miot->port[1].out;
+
+ if ( miot->irqenable )
+ out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F );
+
+ if (!miot->port[1].out_port_func.isnull())
+ miot->port[1].out_port_func(0, out);
+ else
+ logerror("6530MIOT chip %s: Port B is being written to but has no handler.\n", device->tag());
+}
+
+
+/*-------------------------------------------------
+ get_timer - return the current timer value
+-------------------------------------------------*/
+
+INLINE UINT8 get_timer(mos6530_state *miot)
+{
+ /* if idle, return 0 */
+ if (miot->timerstate == TIMER_IDLE)
+ return 0;
+
+ /* if counting, return the number of ticks remaining */
+ else if (miot->timerstate == TIMER_COUNTING)
+ return miot->timer->remaining().as_ticks(miot->clock) >> miot->timershift;
+
+ /* if finishing, return the number of ticks without the shift */
+ else
+ return miot->timer->remaining().as_ticks(miot->clock);
+}
+
+
+/***************************************************************************
+ INTERNAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_end_callback - callback to process the
+ timer
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( timer_end_callback )
+{
+ device_t *device = (device_t *)ptr;
+ mos6530_state *miot = get_safe_token(device);
+
+ assert(miot->timerstate != TIMER_IDLE);
+
+ /* if we finished counting, switch to the finishing state */
+ if (miot->timerstate == TIMER_COUNTING)
+ {
+ miot->timerstate = TIMER_FINISHING;
+ miot->timer->adjust(attotime::from_ticks(256, miot->clock));
+
+ /* signal timer IRQ as well */
+ miot->irqstate |= TIMER_FLAG;
+ update_irqstate(device);
+ }
+
+ /* if we finished finishing, switch to the idle state */
+ else if (miot->timerstate == TIMER_FINISHING)
+ {
+ miot->timerstate = TIMER_IDLE;
+ miot->timer->adjust(attotime::never);
+ }
+}
+
+
+
+/***************************************************************************
+ I/O ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mos6530_w - master I/O write access
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER( mos6530_w )
+{
+ mos6530_state *miot = get_safe_token(device);
+
+ /* if A2 == 1, we are writing to the timer */
+ if (offset & 0x04)
+ {
+ static const UINT8 timershift[4] = { 0, 3, 6, 10 };
+ attotime curtime = space.machine().time();
+ INT64 target;
+
+ /* A0-A1 contain the timer divisor */
+ miot->timershift = timershift[offset & 3];
+
+ /* A3 contains the timer IRQ enable */
+ if (offset & 8)
+ miot->irqenable |= TIMER_FLAG;
+ else
+ miot->irqenable &= ~TIMER_FLAG;
+
+ /* writes here clear the timer flag */
+ if (miot->timerstate != TIMER_FINISHING || get_timer(miot) != 0xff)
+ miot->irqstate &= ~TIMER_FLAG;
+ update_irqstate(device);
+
+ /* update the timer */
+ miot->timerstate = TIMER_COUNTING;
+ target = curtime.as_ticks(miot->clock) + 1 + (data << miot->timershift);
+ miot->timer->adjust(attotime::from_ticks(target, miot->clock) - curtime);
+ }
+
+ /* if A2 == 0, we are writing to the I/O section */
+ else
+ {
+ /* A1 selects the port */
+ mos6530_port *port = &miot->port[(offset >> 1) & 1];
+
+ /* if A0 == 1, we are writing to the port's DDR */
+ if (offset & 1)
+ port->ddr = data;
+
+ /* if A0 == 0, we are writing to the port's output */
+ else
+ {
+ UINT8 olddata = port->out;
+ port->out = data;
+
+ if ( ( offset & 2 ) && miot->irqenable )
+ {
+ olddata = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( olddata & 0x7F );
+ data = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( data & 0x7F );
+ }
+
+ if (!port->out_port_func.isnull())
+ port->out_port_func(0, data);
+ else
+ logerror("6530MIOT chip %s: Port %c is being written to but has no handler. PC: %08X - %02X\n", device->tag(), 'A' + (offset & 1), space.machine().firstcpu->pc(), data);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ mos6530_r - master I/O read access
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( mos6530_r )
+{
+ mos6530_state *miot = get_safe_token(device);
+ UINT8 val = 0;
+
+ /* if A2 == 1 and A0 == 1, we are reading interrupt flags */
+ if ((offset & 0x05) == 0x05)
+ {
+ val = miot->irqstate;
+ }
+
+ /* if A2 == 1 and A0 == 0, we are reading the timer */
+ else if ((offset & 0x05) == 0x04)
+ {
+ val = get_timer(miot);
+
+ /* A3 contains the timer IRQ enable */
+ if (offset & 8)
+ miot->irqenable |= TIMER_FLAG;
+ else
+ miot->irqenable &= ~TIMER_FLAG;
+
+ /* implicitly clears the timer flag */
+ if (miot->timerstate != TIMER_FINISHING || val != 0xff)
+ miot->irqstate &= ~TIMER_FLAG;
+ update_irqstate(device);
+ }
+
+ /* if A2 == 0 and A0 == anything, we are reading from ports */
+ else
+ {
+ /* A1 selects the port */
+ mos6530_port *port = &miot->port[(offset >> 1) & 1];
+
+ /* if A0 == 1, we are reading the port's DDR */
+ if (offset & 1)
+ val = port->ddr;
+
+ /* if A0 == 0, we are reading the port as an input */
+ else
+ {
+ UINT8 out = port->out;
+
+ if ( ( offset & 2 ) && miot->irqenable )
+ out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F );
+
+ /* call the input callback if it exists */
+ if (!port->in_port_func.isnull())
+ {
+ port->in = port->in_port_func(0);
+ }
+ else
+ logerror("6530MIOT chip %s: Port %c is being read but has no handler. PC: %08X\n", device->tag(), 'A' + (offset & 1), space.machine().firstcpu->pc());
+
+ /* apply the DDR to the result */
+ val = (out & port->ddr) | (port->in & ~port->ddr);
+ }
+ }
+ return val;
+}
+
+
+/*-------------------------------------------------
+ mos6530_porta_in_set - set port A input
+ value
+-------------------------------------------------*/
+
+void mos6530_porta_in_set(device_t *device, UINT8 data, UINT8 mask)
+{
+ mos6530_state *miot = get_safe_token(device);
+ miot->port[0].in = (miot->port[0].in & ~mask) | (data & mask);
+}
+
+
+/*-------------------------------------------------
+ mos6530_portb_in_set - set port B input
+ value
+-------------------------------------------------*/
+
+void mos6530_portb_in_set(device_t *device, UINT8 data, UINT8 mask)
+{
+ mos6530_state *miot = get_safe_token(device);
+ miot->port[1].in = (miot->port[1].in & ~mask) | (data & mask);
+}
+
+
+/*-------------------------------------------------
+ mos6530_porta_in_get - return port A input
+ value
+-------------------------------------------------*/
+
+UINT8 mos6530_porta_in_get(device_t *device)
+{
+ mos6530_state *miot = get_safe_token(device);
+ return miot->port[0].in;
+}
+
+
+/*-------------------------------------------------
+ mos6530_portb_in_get - return port B input
+ value
+-------------------------------------------------*/
+
+UINT8 mos6530_portb_in_get(device_t *device)
+{
+ mos6530_state *miot = get_safe_token(device);
+ return miot->port[1].in;
+}
+
+
+/*-------------------------------------------------
+ mos6530_porta_in_get - return port A output
+ value
+-------------------------------------------------*/
+
+UINT8 mos6530_porta_out_get(device_t *device)
+{
+ mos6530_state *miot = get_safe_token(device);
+ return miot->port[0].out;
+}
+
+
+/*-------------------------------------------------
+ mos6530_portb_in_get - return port B output
+ value
+-------------------------------------------------*/
+
+UINT8 mos6530_portb_out_get(device_t *device)
+{
+ mos6530_state *miot = get_safe_token(device);
+ return miot->port[1].out;
+}
+
+
+/***************************************************************************
+ DEVICE INTERFACE
+***************************************************************************/
+
+static DEVICE_START( mos6530 )
+{
+ mos6530_state *miot = get_safe_token(device);
+ const mos6530_interface *intf = (const mos6530_interface*)device->static_config();
+
+ /* validate arguments */
+ assert(device != NULL);
+ assert(device->tag() != NULL);
+
+ /* set static values */
+ miot->clock = device->clock();
+
+ /* resolve callbacks */
+ miot->port[0].in_port_func.resolve(intf->in_pa_func, *device);
+ miot->port[1].in_port_func.resolve(intf->in_pb_func, *device);
+ miot->port[0].out_port_func.resolve(intf->out_pa_func, *device);
+ miot->port[1].out_port_func.resolve(intf->out_pb_func, *device);
+
+ /* allocate timers */
+ miot->timer = device->machine().scheduler().timer_alloc(FUNC(timer_end_callback), (void *)device);
+
+ /* register for save states */
+ device->save_item(NAME(miot->port[0].in));
+ device->save_item(NAME(miot->port[0].out));
+ device->save_item(NAME(miot->port[0].ddr));
+ device->save_item(NAME(miot->port[1].in));
+ device->save_item(NAME(miot->port[1].out));
+ device->save_item(NAME(miot->port[1].ddr));
+
+ device->save_item(NAME(miot->irqstate));
+ device->save_item(NAME(miot->irqenable));
+
+ device->save_item(NAME(miot->timershift));
+ device->save_item(NAME(miot->timerstate));
+}
+
+
+static DEVICE_RESET( mos6530 )
+{
+ mos6530_state *miot = get_safe_token(device);
+
+ /* reset I/O states */
+ miot->port[0].out = 0;
+ miot->port[0].ddr = 0;
+ miot->port[1].out = 0;
+ miot->port[1].ddr = 0;
+
+ /* reset IRQ states */
+ miot->irqenable = 0;
+ miot->irqstate = TIMER_FLAG;
+ update_irqstate(device);
+
+ /* reset timer states */
+ miot->timershift = 0;
+ miot->timerstate = TIMER_IDLE;
+ miot->timer->adjust(attotime::never);
+}
+
+
+const device_type MOS6530 = &device_creator<mos6530_device>;
+
+mos6530_device::mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MOS6530, "MOS6530", tag, owner, clock)
+{
+ m_token = global_alloc_clear(mos6530_state);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void mos6530_device::device_config_complete()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mos6530_device::device_start()
+{
+ DEVICE_START_NAME( mos6530 )(this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mos6530_device::device_reset()
+{
+ DEVICE_RESET_NAME( mos6530 )(this);
+}
diff --git a/src/emu/machine/mos6530.h b/src/emu/machine/mos6530.h
new file mode 100644
index 00000000000..99af148500c
--- /dev/null
+++ b/src/emu/machine/mos6530.h
@@ -0,0 +1,97 @@
+/**********************************************************************
+
+ MOS Technology 6530 Memory, I/O, Timer Array emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ Vss 1 |* \_/ | 40 PA1
+ PA0 2 | | 39 PA2
+ phi2 3 | | 38 PA3
+ RS0 4 | | 37 PA4
+ A9 5 | | 36 PA5
+ A8 6 | | 35 PA6
+ A7 7 | | 34 PA7
+ A6 8 | | 33 DB0
+ R/W 9 | | 32 DB1
+ A5 10 | MCS6530 | 31 DB2
+ A4 11 | | 30 DB3
+ A3 12 | | 29 DB4
+ A2 13 | | 28 DB5
+ A1 14 | | 27 DB6
+ A0 15 | | 26 DB7
+ _RES 16 | | 25 PB0
+ IRQ/PB7 17 | | 24 PB1
+ CS1/PB6 18 | | 23 PB2
+ CS2/PB5 19 | | 22 PB3
+ Vcc 20 |_____________| 21 PB4
+
+**********************************************************************/
+
+#ifndef __MIOT6530_H__
+#define __MIOT6530_H__
+
+/***************************************************************************
+ MACROS / CONSTANTS
+***************************************************************************/
+
+class mos6530_device : public device_t
+{
+public:
+ mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~mos6530_device() { global_free(m_token); }
+
+ // access to legacy token
+ void *token() const { assert(m_token != NULL); return m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ // internal state
+ void *m_token;
+};
+
+extern const device_type MOS6530;
+
+
+#define MCFG_MOS6530_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD((_tag), MOS6530, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define MOS6530_INTERFACE(name) \
+ const mos6530_interface (name) =
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct mos6530_interface
+{
+ devcb_read8 in_pa_func;
+ devcb_write8 out_pa_func;
+
+ devcb_read8 in_pb_func;
+ devcb_write8 out_pb_func;
+};
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+DECLARE_READ8_DEVICE_HANDLER( mos6530_r );
+DECLARE_WRITE8_DEVICE_HANDLER( mos6530_w );
+
+void mos6530_porta_in_set(device_t *device, UINT8 data, UINT8 mask);
+void mos6530_portb_in_set(device_t *device, UINT8 data, UINT8 mask);
+
+UINT8 mos6530_porta_in_get(device_t *device);
+UINT8 mos6530_portb_in_get(device_t *device);
+
+UINT8 mos6530_porta_out_get(device_t *device);
+UINT8 mos6530_portb_out_get(device_t *device);
+
+#endif
diff --git a/src/emu/machine/pcf8593.c b/src/emu/machine/pcf8593.c
new file mode 100644
index 00000000000..6dd6c894354
--- /dev/null
+++ b/src/emu/machine/pcf8593.c
@@ -0,0 +1,283 @@
+/*********************************************************************
+
+ Philips PCF8593 CMOS clock/calendar circuit
+
+ (c) 2001-2007 Tim Schuerewegen
+
+*********************************************************************/
+
+#include "pcf8593.h"
+
+
+/***************************************************************************
+ PARAMETERS/CONSTANTS/MACROS
+***************************************************************************/
+
+#define LOG_LEVEL 1
+#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0)
+
+// get/set date
+#define RTC_GET_DATE_YEAR ((m_data[5] >> 6) & 3)
+#define RTC_SET_DATE_YEAR(x) m_data[5] = (m_data[5] & 0x3F) | (((x) % 4) << 6)
+#define RTC_GET_DATE_MONTH bcd_to_integer( m_data[6])
+#define RTC_SET_DATE_MONTH(x) m_data[6] = convert_to_bcd( x)
+#define RTC_GET_DATE_DAY (bcd_to_integer( m_data[5] & 0x3F))
+#define RTC_SET_DATE_DAY(x) m_data[5] = (m_data[5] & 0xC0) | convert_to_bcd( x)
+
+// get/set time
+#define RTC_GET_TIME_HOUR bcd_to_integer( m_data[4])
+#define RTC_SET_TIME_HOUR(x) m_data[4] = convert_to_bcd( x)
+#define RTC_GET_TIME_MINUTE bcd_to_integer( m_data[3])
+#define RTC_SET_TIME_MINUTE(x) m_data[3] = convert_to_bcd( x)
+#define RTC_GET_TIME_SECOND bcd_to_integer( m_data[2])
+#define RTC_SET_TIME_SECOND(x) m_data[2] = convert_to_bcd( x)
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type PCF8593 = &device_creator<pcf8593_device>;
+
+
+//-------------------------------------------------
+// pcf8593_device - constructor
+//-------------------------------------------------
+
+pcf8593_device::pcf8593_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, PCF8593, "PCF8593 RTC", tag, owner, clock),
+ device_rtc_interface(mconfig, *this),
+ device_nvram_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void pcf8593_device::device_start()
+{
+ _logerror( 0, ("pcf8593_init\n"));
+ memset(m_register, 0, sizeof(m_register));
+ m_timer = timer_alloc(TIMER_UPDATE_COUNTER);
+ m_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void pcf8593_device::device_reset()
+{
+ _logerror( 0, ("pcf8593_reset\n"));
+ m_pin_scl = 1;
+ m_pin_sda = 1;
+ m_active = FALSE;
+ m_inp = 0;
+ m_mode = RTC_MODE_RECV;
+ m_bits = 0;
+ m_pos = 0;
+ clear_buffer_rx();
+ set_time(true, RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH, RTC_GET_DATE_DAY, 0, RTC_GET_TIME_HOUR, RTC_GET_TIME_MINUTE, RTC_GET_TIME_SECOND);
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void pcf8593_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_UPDATE_COUNTER:
+ _logerror( 2, ("pcf8593_timer_callback (%d)\n", param));
+ // check if counting is enabled
+ if (!(m_data[0] & 0x80))
+ advance_seconds();
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// rtc_clock_updated -
+//-------------------------------------------------
+
+void pcf8593_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
+{
+ RTC_SET_TIME_SECOND(second);
+ RTC_SET_TIME_MINUTE(minute);
+ RTC_SET_TIME_HOUR(hour);
+ RTC_SET_DATE_DAY(day);
+ RTC_SET_DATE_MONTH(month);
+ RTC_SET_DATE_YEAR(year);
+}
+
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void pcf8593_device::nvram_default()
+{
+ memset(m_data, 0, sizeof(m_data));
+}
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+void pcf8593_device::nvram_read(emu_file &file)
+{
+ file.read(m_data, sizeof(m_data));
+}
+
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+void pcf8593_device::nvram_write(emu_file &file)
+{
+ file.write(m_data, sizeof(m_data));
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_pin_scl
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER(pcf8593_device::scl_w)
+{
+ // send bit
+ if ((m_active) && (!m_pin_scl) && (state))
+ {
+ switch (m_mode)
+ {
+ // HOST -> RTC
+ case RTC_MODE_RECV :
+ {
+ // get bit
+ if (m_pin_sda) m_data_recv[m_data_recv_index] = m_data_recv[m_data_recv_index] | (0x80 >> m_bits);
+ m_bits++;
+ // bit 9 = end
+ if (m_bits > 8)
+ {
+ _logerror( 2, ("pcf8593_write_byte(%02X)\n", m_data_recv[m_data_recv_index]));
+ // enter receive mode when 1st byte = 0xA3
+ if ((m_data_recv[0] == 0xA3) && (m_data_recv_index == 0))
+ {
+ m_mode = RTC_MODE_SEND;
+ }
+ // A2 + xx = "read from pos xx" command
+ if ((m_data_recv[0] == 0xA2) && (m_data_recv_index == 1))
+ {
+ m_pos = m_data_recv[1];
+ }
+ // A2 + xx + .. = write byte
+ if ((m_data_recv[0] == 0xA2) && (m_data_recv_index >= 2))
+ {
+ UINT8 rtc_pos, rtc_val;
+ rtc_pos = m_data_recv[1] + (m_data_recv_index - 2);
+ rtc_val = m_data_recv[m_data_recv_index];
+ //if (rtc_pos == 0) rtc_val = rtc_val & 3; // what is this doing here?
+ m_data[rtc_pos] = rtc_val;
+ set_time(false, RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH, RTC_GET_DATE_DAY, 0, RTC_GET_TIME_HOUR, RTC_GET_TIME_MINUTE, RTC_GET_TIME_SECOND);
+ }
+ // next byte
+ m_bits = 0;
+ m_data_recv_index++;
+ }
+ }
+ break;
+ // RTC -> HOST
+ case RTC_MODE_SEND :
+ {
+ // set bit
+ m_inp = (m_data[m_pos] >> (7 - m_bits)) & 1;
+ m_bits++;
+ // bit 9 = end
+ if (m_bits > 8)
+ {
+ _logerror( 2, ("pcf8593_read_byte(%02X)\n", m_data[m_pos]));
+ // end ?
+ if (m_pin_sda)
+ {
+ _logerror( 2, ("pcf8593 end\n"));
+ m_mode = RTC_MODE_RECV;
+ clear_buffer_rx();
+ }
+ // next byte
+ m_bits = 0;
+ m_pos++;
+ }
+ }
+ break;
+ }
+ }
+ // save scl
+ m_pin_scl = state;
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_pin_sda_w
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER(pcf8593_device::sda_w)
+{
+ // clock is high
+ if (m_pin_scl)
+ {
+ // log init I2C
+ if (state) _logerror( 1, ("pcf8593 init i2c\n"));
+ // start condition (high to low when clock is high)
+ if ((!state) && (m_pin_sda))
+ {
+ _logerror( 1, ("pcf8593 start condition\n"));
+ m_active = TRUE;
+ m_bits = 0;
+ m_data_recv_index = 0;
+ clear_buffer_rx();
+ //m_pos = 0;
+ }
+ // stop condition (low to high when clock is high)
+ if ((state) && (!m_pin_sda))
+ {
+ _logerror( 1, ("pcf8593 stop condition\n"));
+ m_active = FALSE;
+ }
+ }
+ // save sda
+ m_pin_sda = state;
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_pin_sda_r
+-------------------------------------------------*/
+
+READ_LINE_MEMBER(pcf8593_device::sda_r)
+{
+ return m_inp;
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_clear_buffer_rx
+-------------------------------------------------*/
+
+void pcf8593_device::clear_buffer_rx()
+{
+ memset(&m_data_recv[0], 0, sizeof( m_data_recv));
+ m_data_recv_index = 0;
+}
diff --git a/src/emu/machine/pcf8593.h b/src/emu/machine/pcf8593.h
new file mode 100644
index 00000000000..887a68f219c
--- /dev/null
+++ b/src/emu/machine/pcf8593.h
@@ -0,0 +1,77 @@
+/*********************************************************************
+
+ Philips PCF8593 CMOS clock/calendar circuit
+
+ (c) 2001-2007 Tim Schuerewegen
+
+*********************************************************************/
+
+#ifndef __PCF8593_H__
+#define __PCF8593_H__
+
+#include "emu.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_PCF8593_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, PCF8593, 0)
+
+#define MCFG_PCF8593_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+
+// ======================> pcf8593_device
+
+class pcf8593_device : public device_t,
+ public device_rtc_interface,
+ public device_nvram_interface
+{
+public:
+ pcf8593_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_WRITE_LINE_MEMBER(scl_w);
+ DECLARE_WRITE_LINE_MEMBER(sda_w);
+ DECLARE_READ_LINE_MEMBER(sda_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);
+
+ // device_rtc_interface overrides
+ virtual bool rtc_feature_y2k() { return true; }
+ virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second);
+
+ // device_nvram_interface overrides
+ virtual void nvram_default();
+ virtual void nvram_read(emu_file &file);
+ virtual void nvram_write(emu_file &file);
+
+private:
+ void clear_buffer_rx();
+
+ static const device_timer_id TIMER_UPDATE_COUNTER = 0;
+
+ // internal state
+ UINT8 m_data[16];
+ int m_pin_scl;
+ int m_pin_sda;
+ int m_inp;
+ int m_active;
+ int m_bits;
+ UINT8 m_data_recv_index;
+ UINT8 m_data_recv[50];
+ UINT8 m_mode;
+ UINT8 m_pos;
+ emu_timer * m_timer;
+ enum { RTC_MODE_NONE, RTC_MODE_SEND, RTC_MODE_RECV };
+};
+
+// device type definition
+extern const device_type PCF8593;
+
+#endif /* __PCF8593_H__ */
diff --git a/src/emu/machine/upd7002.c b/src/emu/machine/upd7002.c
new file mode 100644
index 00000000000..84770daa1cf
--- /dev/null
+++ b/src/emu/machine/upd7002.c
@@ -0,0 +1,245 @@
+/******************************************************************************
+ uPD7002 Analogue to Digital Converter
+
+ MESS Driver By:
+
+ Gordon Jefferyes
+ mess_bbc@gjeffery.dircon.co.uk
+
+******************************************************************************/
+
+#include "emu.h"
+#include "upd7002.h"
+
+
+struct uPD7002_t
+{
+ /* Pointer to our interface */
+ const uPD7002_interface *intf;
+
+ /* Status Register
+ D0 and D1 define the currently selected input channel
+ D2 flag output
+ D3 0 = 8 bit mode 1 = 12 bit mode
+ D4 2nd MSB of conversion
+ D5 MSB of conversion
+ D6 0 = busy, 1 = not busy (~busy)
+ D7 0 = conversion completed, 1 = conversion not completed (~EOC)
+ */
+ int status;
+
+ /* High data byte
+ This byte contains the 8 most significant bits of the analogue to digital conversion. */
+ int data1;
+
+ /* Low data byte
+ In 12 bit mode: Bits 7 to 4 define the four low order bits of the conversion.
+ In 8 bit mode. All bits 7 to 4 are inaccurate.
+ Bits 3 to 0 are always set to low. */
+ int data0;
+
+
+ /* temporary store of the next A to D conversion */
+ int digitalvalue;
+
+ /* this counter is used to check a full end of conversion has been reached
+ if the uPD7002 is half way through one conversion and a new conversion is requested
+ the counter at the end of the first conversion will not match and not be processed
+ only then at the end of the second conversion will the conversion complete function run */
+ int conversion_counter;
+};
+
+
+/*****************************************************************************
+ Implementation
+*****************************************************************************/
+
+INLINE uPD7002_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == UPD7002);
+
+ return (uPD7002_t *)downcast<uPD7002_device *>(device)->token();
+}
+
+READ8_DEVICE_HANDLER ( uPD7002_EOC_r )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ return (uPD7002->status>>7)&0x01;
+}
+
+
+static TIMER_CALLBACK(uPD7002_conversioncomplete)
+{
+ device_t *device = (device_t *)ptr;
+ uPD7002_t *uPD7002 = get_safe_token(device);
+
+ int counter_value = param;
+ if (counter_value==uPD7002->conversion_counter)
+ {
+ // this really always does a 12 bit conversion
+ uPD7002->data1 = uPD7002->digitalvalue>>8;
+ uPD7002->data0 = uPD7002->digitalvalue&0xf0;
+
+ // set the status register with top 2 MSB, not busy and conversion complete
+ uPD7002->status = (uPD7002->status & 0x0f)|((uPD7002->data1 & 0xc0)>>2)|0x40;
+
+ // call the EOC function with EOC from status
+ // uPD7002_EOC_r(0) this has just been set to 0
+ if (uPD7002->intf->EOC_func) (uPD7002->intf->EOC_func)(device,0);
+ uPD7002->conversion_counter=0;
+ }
+}
+
+
+READ8_DEVICE_HANDLER ( uPD7002_r )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+
+ switch(offset&0x03)
+ {
+ case 0:
+ return uPD7002->status;
+
+ case 1:
+ return uPD7002->data1;
+
+ case 2: case 3:
+ return uPD7002->data0;
+ }
+ return 0;
+}
+
+
+
+WRITE8_DEVICE_HANDLER ( uPD7002_w )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ /* logerror("write to uPD7002 $%02X = $%02X\n",offset,data); */
+
+ switch(offset&0x03)
+ {
+ case 0:
+ /*
+ Data Latch/AD start
+ D0 and D1 together define which one of the four input channels is selected
+ D2 flag input, normally set to 0????
+ D3 defines whether an 8 (0) or 12 (1) bit resolution conversion should occur
+ D4 to D7 not used.
+
+ an 8 bit conversion typically takes 4ms
+ an 12 bit conversion typically takes 10ms
+
+ writing to this register will initiate a conversion.
+ */
+
+ /* set D6=0 busy ,D7=1 conversion not complete */
+ uPD7002->status=(data & 0x0f) | 0x80;
+
+ // call the EOC function with EOC from status
+ // uPD7002_EOC_r(0) this has just been set to 1
+ if (uPD7002->intf->EOC_func) uPD7002->intf->EOC_func(device, 1);
+
+ /* the uPD7002 works by sampling the analogue value at the start of the conversion
+ so it is read hear and stored until the end of the A to D conversion */
+
+ // this function should return a 16 bit value.
+ uPD7002->digitalvalue = uPD7002->intf->get_analogue_func(device, uPD7002->status & 0x03);
+
+ uPD7002->conversion_counter++;
+
+ // call a timer to start the conversion
+ if (uPD7002->status & 0x08)
+ {
+ // 12 bit conversion takes 10ms
+ space.machine().scheduler().timer_set(attotime::from_msec(10), FUNC(uPD7002_conversioncomplete), uPD7002->conversion_counter, (void *)device);
+ } else {
+ // 8 bit conversion takes 4ms
+ space.machine().scheduler().timer_set(attotime::from_msec(4), FUNC(uPD7002_conversioncomplete), uPD7002->conversion_counter, (void *)device);
+ }
+ break;
+
+ case 1: case 2:
+ /* Nothing */
+ break;
+
+ case 3:
+ /* Test Mode: Used for inspecting the device, The data input-output terminals assume an input
+ state and are connected to the A/D counter. Therefore, the A/D conversion data
+ read out after this is meaningless.
+ */
+ break;
+ }
+}
+
+/* Device Interface */
+
+static DEVICE_START( uPD7002 )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ // validate arguments
+
+ assert(device != NULL);
+ assert(device->tag() != NULL);
+ assert(device->static_config() != NULL);
+
+ uPD7002->intf = (const uPD7002_interface*)device->static_config();
+ uPD7002->status = 0;
+ uPD7002->data1 = 0;
+ uPD7002->data0 = 0;
+ uPD7002->digitalvalue = 0;
+ uPD7002->conversion_counter = 0;
+
+ // register for state saving
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->status);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->data1);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->data0);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->digitalvalue);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->conversion_counter);
+}
+
+static DEVICE_RESET( uPD7002 )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ uPD7002->status = 0;
+ uPD7002->data1 = 0;
+ uPD7002->data0 = 0;
+ uPD7002->digitalvalue = 0;
+ uPD7002->conversion_counter = 0;
+}
+
+const device_type UPD7002 = &device_creator<uPD7002_device>;
+
+uPD7002_device::uPD7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, UPD7002, "uPD7002", tag, owner, clock)
+{
+ m_token = global_alloc_clear(uPD7002_t);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void uPD7002_device::device_config_complete()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void uPD7002_device::device_start()
+{
+ DEVICE_START_NAME( uPD7002 )(this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void uPD7002_device::device_reset()
+{
+ DEVICE_RESET_NAME( uPD7002 )(this);
+}
diff --git a/src/emu/machine/upd7002.h b/src/emu/machine/upd7002.h
new file mode 100644
index 00000000000..d7456ed0f44
--- /dev/null
+++ b/src/emu/machine/upd7002.h
@@ -0,0 +1,76 @@
+/*****************************************************************************
+ *
+ * machine/upd7002.h
+ *
+ * uPD7002 Analogue to Digital Converter
+ *
+ * Driver by Gordon Jefferyes <mess_bbc@gjeffery.dircon.co.uk>
+ *
+ ****************************************************************************/
+
+#ifndef UPD7002_H_
+#define UPD7002_H_
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+class uPD7002_device : public device_t
+{
+public:
+ uPD7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~uPD7002_device() { global_free(m_token); }
+
+ // access to legacy token
+ void *token() const { assert(m_token != NULL); return m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ // internal state
+ void *m_token;
+};
+
+extern const device_type UPD7002;
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef int (*uPD7002_get_analogue_func)(device_t *device, int channel_number);
+#define UPD7002_GET_ANALOGUE(name) int name(device_t *device, int channel_number )
+
+typedef void (*uPD7002_eoc_func)(device_t *device, int data);
+#define UPD7002_EOC(name) void name(device_t *device, int data )
+
+
+struct uPD7002_interface
+{
+ uPD7002_get_analogue_func get_analogue_func;
+ uPD7002_eoc_func EOC_func;
+};
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* Standard handlers */
+
+DECLARE_READ8_DEVICE_HANDLER ( uPD7002_EOC_r );
+DECLARE_READ8_DEVICE_HANDLER ( uPD7002_r );
+DECLARE_WRITE8_DEVICE_HANDLER ( uPD7002_w );
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_UPD7002_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, UPD7002, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+
+#endif /* UPD7002_H_ */
diff --git a/src/emu/machine/wd11c00_17.c b/src/emu/machine/wd11c00_17.c
new file mode 100644
index 00000000000..58e956b311a
--- /dev/null
+++ b/src/emu/machine/wd11c00_17.c
@@ -0,0 +1,496 @@
+/**********************************************************************
+
+ Western Digital WD11C00-17 PC/XT Host Interface Logic Device
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/wd11c00_17.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 1
+
+
+// status register
+#define STATUS_IRQ 0x20
+#define STATUS_DRQ 0x10
+#define STATUS_BUSY 0x08
+#define STATUS_C_D 0x04
+#define STATUS_I_O 0x02
+#define STATUS_REQ 0x01
+
+
+// mask register
+#define MASK_IRQ 0x02
+#define MASK_DMA 0x01
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type WD11C00_17 = &device_creator<wd11c00_17_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void wd11c00_17_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const wd11c00_17_interface *intf = reinterpret_cast<const wd11c00_17_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<wd11c00_17_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq5_cb, 0, sizeof(m_out_irq5_cb));
+ memset(&m_out_drq3_cb, 0, sizeof(m_out_drq3_cb));
+ memset(&m_out_mr_cb, 0, sizeof(m_out_mr_cb));
+ memset(&m_out_busy_cb, 0, sizeof(m_out_busy_cb));
+ memset(&m_out_req_cb, 0, sizeof(m_out_req_cb));
+ memset(&m_out_ra3_cb, 0, sizeof(m_out_ra3_cb));
+ memset(&m_in_rd322_cb, 0, sizeof(m_in_rd322_cb));
+ memset(&m_in_ramcs_cb, 0, sizeof(m_in_ramcs_cb));
+ memset(&m_out_ramwr_cb, 0, sizeof(m_out_ramwr_cb));
+ memset(&m_in_cs1010_cb, 0, sizeof(m_in_cs1010_cb));
+ memset(&m_out_cs1010_cb, 0, sizeof(m_out_cs1010_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// check_interrupt -
+//-------------------------------------------------
+
+inline void wd11c00_17_device::check_interrupt()
+{
+ if (BIT(m_ra, 10))
+ {
+ m_status &= ~STATUS_DRQ;
+ }
+
+ int ra3 = BIT(m_ra, 3);
+
+ if (m_ra3 != ra3)
+ {
+ m_out_ra3_func(ra3 ? ASSERT_LINE : CLEAR_LINE);
+ m_ra3 = ra3;
+ }
+
+ int irq5 = ((m_status & STATUS_IRQ) && (m_mask & MASK_IRQ)) ? ASSERT_LINE : CLEAR_LINE;
+
+ if (m_irq5 != irq5)
+ {
+ m_out_irq5_func(irq5);
+ m_irq5 = irq5;
+ }
+
+ int drq3 = ((m_status & STATUS_DRQ) && (m_mask & MASK_DMA)) ? ASSERT_LINE : CLEAR_LINE;
+
+ if (m_drq3 != drq3)
+ {
+ m_out_drq3_func(drq3);
+ m_drq3 = drq3;
+ }
+
+ int busy = (m_status & STATUS_BUSY) ? 0 : 1;
+
+ if (m_busy != busy)
+ {
+ m_out_busy_func(busy);
+ m_busy = busy;
+ }
+
+ int req = (m_status & STATUS_REQ) ? 1 : 0;
+
+ if (m_req != req)
+ {
+ m_out_req_func(req);
+ m_req = req;
+ }
+}
+
+
+//-------------------------------------------------
+// increment_address -
+//-------------------------------------------------
+
+inline void wd11c00_17_device::increment_address()
+{
+ m_ra++;
+ check_interrupt();
+}
+
+
+//-------------------------------------------------
+// read_data -
+//-------------------------------------------------
+
+inline UINT8 wd11c00_17_device::read_data()
+{
+ UINT8 data = 0;
+
+ if (m_status & STATUS_BUSY)
+ {
+ data = m_in_ramcs_func(m_ra & 0x7ff);
+
+ increment_address();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write_data -
+//-------------------------------------------------
+
+inline void wd11c00_17_device::write_data(UINT8 data)
+{
+ if (m_status & STATUS_BUSY)
+ {
+ m_out_ramwr_func(m_ra & 0x7ff, data);
+
+ increment_address();
+ }
+}
+
+
+//-------------------------------------------------
+// software_reset -
+//-------------------------------------------------
+
+inline void wd11c00_17_device::software_reset()
+{
+ m_out_mr_func(ASSERT_LINE);
+ m_out_mr_func(CLEAR_LINE);
+
+ device_reset();
+}
+
+
+//-------------------------------------------------
+// select -
+//-------------------------------------------------
+
+inline void wd11c00_17_device::select()
+{
+ m_status = STATUS_BUSY | STATUS_C_D | STATUS_REQ;
+
+ check_interrupt();
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// wd11c00_17_device - constructor
+//-------------------------------------------------
+
+wd11c00_17_device::wd11c00_17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, WD11C00_17, "Western Digital WD11C00-17", tag, owner, clock),
+ m_status(0),
+ m_ra(0),
+ m_irq5(CLEAR_LINE),
+ m_drq3(CLEAR_LINE),
+ m_busy(1),
+ m_req(0),
+ m_ra3(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wd11c00_17_device::device_start()
+{
+ // resolve callbacks
+ m_out_irq5_func.resolve(m_out_irq5_cb, *this);
+ m_out_drq3_func.resolve(m_out_drq3_cb, *this);
+ m_out_mr_func.resolve(m_out_mr_cb, *this);
+ m_out_busy_func.resolve(m_out_busy_cb, *this);
+ m_out_req_func.resolve(m_out_req_cb, *this);
+ m_out_ra3_func.resolve(m_out_ra3_cb, *this);
+ m_in_rd322_func.resolve(m_in_rd322_cb, *this);
+ m_in_ramcs_func.resolve(m_in_ramcs_cb, *this);
+ m_out_ramwr_func.resolve(m_out_ramwr_cb, *this);
+ m_in_cs1010_func.resolve(m_in_cs1010_cb, *this);
+ m_out_cs1010_func.resolve(m_out_cs1010_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void wd11c00_17_device::device_reset()
+{
+ m_status &= ~(STATUS_IRQ | STATUS_DRQ | STATUS_BUSY);
+ m_mask = 0;
+ m_ra = 0;
+
+ check_interrupt();
+}
+
+
+//-------------------------------------------------
+// io_r -
+//-------------------------------------------------
+
+READ8_MEMBER( wd11c00_17_device::io_r )
+{
+ UINT8 data = 0xff;
+
+ switch (offset)
+ {
+ case 0: // Read Data, Board to Host
+ if (LOG) logerror("%s WD11C00-17 '%s' Read Data %03x:", machine().describe_context(), tag(), m_ra);
+ data = read_data();
+ if (LOG) logerror("%02x\n", data);
+ break;
+
+ case 1: // Read Board Hardware Status
+ data = m_status;
+ check_interrupt();
+ break;
+
+ case 2: // Read Drive Configuration Information
+ data = m_in_rd322_func(0);
+ break;
+
+ case 3: // Not Used
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// io_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wd11c00_17_device::io_w )
+{
+ switch (offset)
+ {
+ case 0: // Write Data, Host to Board
+ if (LOG) logerror("%s WD11C00-17 '%s' Write Data %03x:%02x\n", machine().describe_context(), tag(), m_ra, data);
+ write_data(data);
+ break;
+
+ case 1: // Board Software Reset
+ if (LOG) logerror("%s WD11C00-17 '%s' Software Reset\n", machine().describe_context(), tag());
+ software_reset();
+ break;
+
+ case 2: // Board Select
+ if (LOG) logerror("%s WD11C00-17 '%s' Select\n", machine().describe_context(), tag());
+ increment_address(); // HACK
+ select();
+ break;
+
+ case 3: // Set/Reset DMA, IRQ Masks
+ if (LOG) logerror("%s WD11C00-17 '%s' Mask IRQ %u DMA %u\n", machine().describe_context(), tag(), BIT(data, 1), BIT(data, 0));
+ m_mask = data;
+ check_interrupt();
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// dack_r -
+//-------------------------------------------------
+
+UINT8 wd11c00_17_device::dack_r()
+{
+ return read_data();
+}
+
+
+//-------------------------------------------------
+// dack_w -
+//-------------------------------------------------
+
+void wd11c00_17_device::dack_w(UINT8 data)
+{
+ write_data(data);
+}
+
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ8_MEMBER( wd11c00_17_device::read )
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case 0x00:
+ if (LOG) logerror("%s WD11C00-17 '%s' Read RAM %03x:", machine().describe_context(), tag(), m_ra);
+ data = read_data();
+ if (LOG) logerror("%02x\n", data);
+ break;
+
+ case 0x20:
+ data = m_in_cs1010_func(m_ra >> 8);
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wd11c00_17_device::write )
+{
+ switch (offset)
+ {
+ case 0x00:
+ if (LOG) logerror("%s WD11C00-17 '%s' Write RAM %03x:%02x\n", machine().describe_context(), tag(), m_ra, data);
+ write_data(data);
+ if (m_ra > 0x400) m_ecc_not_0 = 0; // HACK
+ break;
+
+ case 0x20:
+ m_out_cs1010_func(m_ra >> 8, data);
+ break;
+
+ case 0x60:
+ m_ra = (data & 0x07) << 8;
+ if (LOG) logerror("%s WD11C00-17 '%s' RA %03x\n", machine().describe_context(), tag(), m_ra);
+ check_interrupt();
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// ireq_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( wd11c00_17_device::ireq_w )
+{
+ if (LOG) logerror("%s WD11C00-17 '%s' IREQ %u\n", machine().describe_context(), tag(), state);
+
+ if (state) m_status |= STATUS_REQ; else m_status &= ~STATUS_REQ;
+
+ if (m_status & STATUS_BUSY)
+ {
+ if (state)
+ {
+ m_status |= STATUS_IRQ | STATUS_I_O;
+ }
+ else
+ {
+ if (m_status & STATUS_I_O)
+ {
+ m_status &= ~(STATUS_BUSY | STATUS_I_O);
+ }
+ }
+ }
+
+ check_interrupt();
+}
+
+
+//-------------------------------------------------
+// io_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( wd11c00_17_device::io_w )
+{
+ if (LOG) logerror("%s WD11C00-17 '%s' I/O %u\n", machine().describe_context(), tag(), state);
+
+ if (state) m_status |= STATUS_I_O; else m_status &= ~STATUS_I_O;
+}
+
+
+//-------------------------------------------------
+// cd_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( wd11c00_17_device::cd_w )
+{
+ if (LOG) logerror("%s WD11C00-17 '%s' C/D %u\n", machine().describe_context(), tag(), state);
+
+ if (state) m_status |= STATUS_C_D; else m_status &= ~STATUS_C_D;
+}
+
+
+//-------------------------------------------------
+// clct_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( wd11c00_17_device::clct_w )
+{
+ if (LOG) logerror("%s WD11C00-17 '%s' CLCT %u\n", machine().describe_context(), tag(), state);
+
+ if (state)
+ {
+ m_ra &= 0xff00;
+ check_interrupt();
+ }
+}
+
+
+//-------------------------------------------------
+// mode_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( wd11c00_17_device::mode_w )
+{
+ if (LOG) logerror("%s WD11C00-17 '%s' MODE %u\n", machine().describe_context(), tag(), state);
+
+ m_mode = state;
+ m_ecc_not_0 = state; // HACK
+}
+
+
+//-------------------------------------------------
+// busy_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( wd11c00_17_device::busy_r )
+{
+ return (m_status & STATUS_BUSY) ? 0 : 1;
+}
+
+
+//-------------------------------------------------
+// ecc_not_0_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( wd11c00_17_device::ecc_not_0_r )
+{
+ return m_ecc_not_0;
+}
diff --git a/src/emu/machine/wd11c00_17.h b/src/emu/machine/wd11c00_17.h
new file mode 100644
index 00000000000..cf043aa26cc
--- /dev/null
+++ b/src/emu/machine/wd11c00_17.h
@@ -0,0 +1,128 @@
+/**********************************************************************
+
+ Western Digital WD11C00-17 PC/XT Host Interface Logic Device
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WD11C00_17__
+#define __WD11C00_17__
+
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_WD11C00_17_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, WD11C00_17, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define WD11C00_17_INTERFACE(_name) \
+ const wd11c00_17_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> wd11c00_17_interface
+
+struct wd11c00_17_interface
+{
+ devcb_write_line m_out_irq5_cb;
+ devcb_write_line m_out_drq3_cb;
+ devcb_write_line m_out_mr_cb;
+ devcb_write_line m_out_busy_cb;
+ devcb_write_line m_out_req_cb;
+ devcb_write_line m_out_ra3_cb;
+ devcb_read8 m_in_rd322_cb;
+ devcb_read8 m_in_ramcs_cb;
+ devcb_write8 m_out_ramwr_cb;
+ devcb_read8 m_in_cs1010_cb;
+ devcb_write8 m_out_cs1010_cb;
+};
+
+
+// ======================> wd11c00_17_device
+
+class wd11c00_17_device : public device_t,
+ public wd11c00_17_interface
+{
+public:
+ // construction/destruction
+ wd11c00_17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( io_r );
+ DECLARE_WRITE8_MEMBER( io_w );
+
+ UINT8 dack_r();
+ void dack_w(UINT8 data);
+
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+ DECLARE_WRITE_LINE_MEMBER( ireq_w );
+ DECLARE_WRITE_LINE_MEMBER( io_w );
+ DECLARE_WRITE_LINE_MEMBER( cd_w );
+ DECLARE_WRITE_LINE_MEMBER( clct_w );
+ DECLARE_WRITE_LINE_MEMBER( mode_w );
+
+ DECLARE_READ_LINE_MEMBER( busy_r );
+ DECLARE_READ_LINE_MEMBER( ecc_not_0_r );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+private:
+ inline void check_interrupt();
+ inline void increment_address();
+ inline UINT8 read_data();
+ inline void write_data(UINT8 data);
+ inline void software_reset();
+ inline void select();
+
+ devcb_resolved_write_line m_out_irq5_func;
+ devcb_resolved_write_line m_out_drq3_func;
+ devcb_resolved_write_line m_out_mr_func;
+ devcb_resolved_write_line m_out_busy_func;
+ devcb_resolved_write_line m_out_req_func;
+ devcb_resolved_write_line m_out_ra3_func;
+ devcb_resolved_read8 m_in_rd322_func;
+ devcb_resolved_read8 m_in_ramcs_func;
+ devcb_resolved_write8 m_out_ramwr_func;
+ devcb_resolved_read8 m_in_cs1010_func;
+ devcb_resolved_write8 m_out_cs1010_func;
+
+ UINT8 m_status;
+ UINT8 m_mask;
+
+ offs_t m_ra;
+
+ int m_mode;
+ int m_ecc_not_0;
+
+ int m_irq5;
+ int m_drq3;
+ int m_busy;
+ int m_req;
+ int m_ra3;
+};
+
+
+// device type definition
+extern const device_type WD11C00_17;
+
+#endif
diff --git a/src/emu/machine/wd2010.c b/src/emu/machine/wd2010.c
new file mode 100644
index 00000000000..2cd62904222
--- /dev/null
+++ b/src/emu/machine/wd2010.c
@@ -0,0 +1,426 @@
+/**********************************************************************
+
+ Western Digital WD2010 Winchester Disk Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/wd2010.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 1
+
+
+// task file
+enum
+{
+ TASK_FILE_ERROR = 1,
+ TASK_FILE_WRITE_PRECOMP_CYLINDER = TASK_FILE_ERROR,
+ TASK_FILE_SECTOR_COUNT,
+ TASK_FILE_SECTOR_NUMBER,
+ TASK_FILE_CYLINDER_LOW,
+ TASK_FILE_CYLINDER_HIGH,
+ TASK_FILE_SDH_REGISTER,
+ TASK_FILE_STATUS,
+ TASK_FILE_COMMAND = TASK_FILE_STATUS
+};
+
+#define WRITE_PRECOMP_CYLINDER \
+ (m_task_file[TASK_FILE_WRITE_PRECOMP_CYLINDER] * 4)
+
+#define SECTOR_COUNT \
+ ((m_task_file[TASK_FILE_SECTOR_COUNT] + 1) * 256)
+
+#define SECTOR_NUMBER \
+ (m_task_file[TASK_FILE_SECTOR_NUMBER])
+
+#define CYLINDER \
+ (((m_task_file[TASK_FILE_CYLINDER_HIGH] & 0x07) << 8) | m_task_file[TASK_FILE_CYLINDER_LOW])
+
+#define HEAD \
+ (m_task_file[TASK_FILE_SDH_REGISTER] & 0x07)
+
+#define DRIVE \
+ ((m_task_file[TASK_FILE_SDH_REGISTER] >> 3) & 0x03)
+
+static const int SECTOR_SIZES[4] = { 256, 512, 1024, 128 };
+
+#define SECTOR_SIZE \
+ SECTOR_SIZES[(m_task_file[TASK_FILE_SDH_REGISTER] >> 5) & 0x03]
+
+
+// status register
+#define STATUS_BSY 0x80
+#define STATUS_RDY 0x40
+#define STATUS_WF 0x20
+#define STATUS_SC 0x10
+#define STATUS_DRQ 0x08
+#define STATUS_DWC 0x04
+#define STATUS_CIP 0x02
+#define STATUS_ERR 0x01
+
+
+// error register
+#define ERROR_BB 0x80
+#define ERROR_CRC_ECC 0x40
+#define ERROR_ID 0x10
+#define ERROR_AC 0x04
+#define ERROR_TK 0x02
+#define ERROR_DM 0x01
+
+
+// command register
+#define COMMAND_MASK 0xf0
+#define COMMAND_RESTORE 0x10
+#define COMMAND_SEEK 0x70
+#define COMMAND_READ_SECTOR 0x20
+#define COMMAND_WRITE_SECTOR 0x30
+#define COMMAND_SCAN_ID 0x40
+#define COMMAND_WRITE_FORMAT 0x50
+#define COMMAND_COMPUTE_CORRECTION 0x08
+#define COMMAND_SET_PARAMETER_MASK 0xfe
+#define COMMAND_SET_PARAMETER 0x00
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type WD2010 = &device_creator<wd2010_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void wd2010_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const wd2010_interface *intf = reinterpret_cast<const wd2010_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<wd2010_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_intrq_cb, 0, sizeof(m_out_intrq_cb));
+ memset(&m_out_bdrq_cb, 0, sizeof(m_out_bdrq_cb));
+ memset(&m_out_bcr_cb, 0, sizeof(m_out_bcr_cb));
+ memset(&m_in_bcs_cb, 0, sizeof(m_in_bcs_cb));
+ memset(&m_out_bcs_cb, 0, sizeof(m_out_bcs_cb));
+ memset(&m_out_dirin_cb, 0, sizeof(m_out_dirin_cb));
+ memset(&m_out_step_cb, 0, sizeof(m_out_step_cb));
+ memset(&m_out_rwc_cb, 0, sizeof(m_out_rwc_cb));
+ memset(&m_in_drdy_cb, 0, sizeof(m_in_drdy_cb));
+ memset(&m_in_index_cb, 0, sizeof(m_in_index_cb));
+ memset(&m_in_wf_cb, 0, sizeof(m_in_wf_cb));
+ memset(&m_in_tk000_cb, 0, sizeof(m_in_tk000_cb));
+ memset(&m_in_sc_cb, 0, sizeof(m_in_sc_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// wd2010_device - constructor
+//-------------------------------------------------
+
+wd2010_device::wd2010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, WD2010, "Western Digital WD2010", tag, owner, clock),
+ m_status(0),
+ m_error(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wd2010_device::device_start()
+{
+ // resolve callbacks
+ m_out_intrq_func.resolve(m_out_intrq_cb, *this);
+ m_out_bdrq_func.resolve(m_out_bdrq_cb, *this);
+ m_out_bcr_func.resolve(m_out_bcr_cb, *this);
+ m_in_bcs_func.resolve(m_in_bcs_cb, *this);
+ m_out_bcs_func.resolve(m_out_bcs_cb, *this);
+ m_out_dirin_func.resolve(m_out_dirin_cb, *this);
+ m_out_step_func.resolve(m_out_step_cb, *this);
+ m_out_rwc_func.resolve(m_out_rwc_cb, *this);
+ m_in_drdy_func.resolve(m_in_drdy_cb, *this);
+ m_in_index_func.resolve(m_in_index_cb, *this);
+ m_in_wf_func.resolve(m_in_wf_cb, *this);
+ m_in_tk000_func.resolve(m_in_tk000_cb, *this);
+ m_in_sc_func.resolve(m_in_sc_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void wd2010_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ8_MEMBER( wd2010_device::read )
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case TASK_FILE_ERROR:
+ data = m_error;
+ break;
+
+ case TASK_FILE_STATUS:
+ m_out_intrq_func(CLEAR_LINE);
+ data = m_status | STATUS_RDY | STATUS_SC;
+ break;
+
+ default:
+ data = m_task_file[offset];
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wd2010_device::write )
+{
+ m_task_file[offset] = data;
+
+ switch (offset)
+ {
+ case TASK_FILE_WRITE_PRECOMP_CYLINDER:
+ if (LOG) logerror("%s WD2010 '%s' Write Precomp Cylinder: %u\n", machine().describe_context(), tag(), WRITE_PRECOMP_CYLINDER);
+ break;
+
+ case TASK_FILE_SECTOR_COUNT:
+ if (LOG) logerror("%s WD2010 '%s' Sector Count: %u\n", machine().describe_context(), tag(), SECTOR_COUNT);
+ break;
+
+ case TASK_FILE_SECTOR_NUMBER:
+ if (LOG) logerror("%s WD2010 '%s' Sector Number: %u\n", machine().describe_context(), tag(), SECTOR_NUMBER);
+ break;
+
+ case TASK_FILE_CYLINDER_LOW:
+ if (LOG) logerror("%s WD2010 '%s' Cylinder Low: %u\n", machine().describe_context(), tag(), CYLINDER);
+ break;
+
+ case TASK_FILE_CYLINDER_HIGH:
+ if (LOG) logerror("%s WD2010 '%s' Cylinder Low: %u\n", machine().describe_context(), tag(), CYLINDER);
+ break;
+
+ case TASK_FILE_SDH_REGISTER:
+ if (LOG)
+ {
+ logerror("%s WD2010 '%s' Head: %u\n", machine().describe_context(), tag(), HEAD);
+ logerror("%s WD2010 '%s' Drive: %u\n", machine().describe_context(), tag(), DRIVE);
+ logerror("%s WD2010 '%s' Sector Size: %u\n", machine().describe_context(), tag(), SECTOR_SIZE);
+ }
+ break;
+
+ case TASK_FILE_COMMAND:
+ if (data == COMMAND_COMPUTE_CORRECTION)
+ {
+ if (LOG) logerror("%s WD2010 '%s' COMPUTE CORRECTION\n", machine().describe_context(), tag());
+ compute_correction(data);
+ }
+ else if ((data & COMMAND_SET_PARAMETER_MASK) == COMMAND_SET_PARAMETER)
+ {
+ if (LOG) logerror("%s WD2010 '%s' SET PARAMETER\n", machine().describe_context(), tag());
+ set_parameter(data);
+ }
+ else
+ {
+ switch (data & COMMAND_MASK)
+ {
+ case COMMAND_RESTORE:
+ if (LOG) logerror("%s WD2010 '%s' RESTORE\n", machine().describe_context(), tag());
+ restore(data);
+ break;
+
+ case COMMAND_SEEK:
+ if (LOG) logerror("%s WD2010 '%s' SEEK\n", machine().describe_context(), tag());
+ seek(data);
+ break;
+
+ case COMMAND_READ_SECTOR:
+ if (LOG) logerror("%s WD2010 '%s' READ SECTOR\n", machine().describe_context(), tag());
+ read_sector(data);
+ break;
+
+ case COMMAND_WRITE_SECTOR:
+ if (LOG) logerror("%s WD2010 '%s' WRITE SECTOR\n", machine().describe_context(), tag());
+ write_sector(data);
+ break;
+
+ case COMMAND_SCAN_ID:
+ if (LOG) logerror("%s WD2010 '%s' SCAN ID\n", machine().describe_context(), tag());
+ scan_id(data);
+ break;
+
+ case COMMAND_WRITE_FORMAT:
+ if (LOG) logerror("%s WD2010 '%s' WRITE FORMAT\n", machine().describe_context(), tag());
+ format(data);
+ break;
+ }
+ }
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// compute_correction -
+//-------------------------------------------------
+
+void wd2010_device::compute_correction(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// set_parameter -
+//-------------------------------------------------
+
+void wd2010_device::set_parameter(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// restore -
+//-------------------------------------------------
+
+void wd2010_device::restore(UINT8 data)
+{
+ // reset INTRQ, errors, set BUSY, CIP
+ m_out_intrq_func(CLEAR_LINE);
+ m_error = 0;
+ m_status = STATUS_BSY | STATUS_CIP;
+
+ // reset RWC, set direction=OUT, store step rate
+ m_out_rwc_func(0);
+ m_out_dirin_func(0);
+
+ int step_pulses = 0;
+
+ while (step_pulses < 2048)
+ {
+ while (!m_in_sc_func())
+ {
+ // drive not ready or write fault?
+ if (!m_in_drdy_func() || m_in_wf_func())
+ {
+ // pulse BCR, set AC, INTRQ, reset BSY, CIP
+ m_out_bcr_func(0);
+ m_out_bcr_func(1);
+ m_error = ERROR_AC;
+ m_status = (m_in_drdy_func() << 6) | (m_in_wf_func() << 5) | STATUS_ERR;
+ m_out_intrq_func(ASSERT_LINE);
+ return;
+ }
+ }
+
+ if (m_in_tk000_func())
+ {
+ // pulse BCR, set INTRQ, reset BSY, CIP
+ m_out_bcr_func(0);
+ m_out_bcr_func(1);
+ m_status &= ~(STATUS_BSY | STATUS_CIP);
+ m_out_intrq_func(ASSERT_LINE);
+ return;
+ }
+
+ if (step_pulses == 2047)
+ {
+ // set TK000 error
+ m_error = ERROR_TK;
+ m_status |= STATUS_ERR;
+
+ // pulse BCR, set INTRQ, reset BSY, CIP
+ m_out_bcr_func(0);
+ m_out_bcr_func(1);
+ m_status &= ~(STATUS_BSY | STATUS_CIP);
+ m_out_intrq_func(ASSERT_LINE);
+ return;
+ }
+
+ // issue a step pulse
+ m_out_step_func(1);
+ m_out_step_func(0);
+ step_pulses++;
+ }
+}
+
+
+//-------------------------------------------------
+// seek -
+//-------------------------------------------------
+
+void wd2010_device::seek(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// read_sector -
+//-------------------------------------------------
+
+void wd2010_device::read_sector(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// write_sector -
+//-------------------------------------------------
+
+void wd2010_device::write_sector(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// scan_id -
+//-------------------------------------------------
+
+void wd2010_device::scan_id(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// format -
+//-------------------------------------------------
+
+void wd2010_device::format(UINT8 data)
+{
+}
diff --git a/src/emu/machine/wd2010.h b/src/emu/machine/wd2010.h
new file mode 100644
index 00000000000..d6456384712
--- /dev/null
+++ b/src/emu/machine/wd2010.h
@@ -0,0 +1,109 @@
+/**********************************************************************
+
+ Western Digital WD2010 Winchester Disk Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WD2010__
+#define __WD2010__
+
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_WD2010_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, WD2010, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define WD2010_INTERFACE(_name) \
+ const wd2010_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> wd2010_interface
+
+struct wd2010_interface
+{
+ devcb_write_line m_out_intrq_cb;
+ devcb_write_line m_out_bdrq_cb;
+ devcb_write_line m_out_bcr_cb;
+ devcb_read8 m_in_bcs_cb;
+ devcb_write8 m_out_bcs_cb;
+ devcb_write_line m_out_dirin_cb;
+ devcb_write_line m_out_step_cb;
+ devcb_write_line m_out_rwc_cb;
+ devcb_read_line m_in_drdy_cb;
+ devcb_read_line m_in_index_cb;
+ devcb_read_line m_in_wf_cb;
+ devcb_read_line m_in_tk000_cb;
+ devcb_read_line m_in_sc_cb;
+};
+
+
+// ======================> wd2010_device
+
+class wd2010_device : public device_t,
+ public wd2010_interface
+{
+public:
+ // construction/destruction
+ wd2010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+private:
+ void compute_correction(UINT8 data);
+ void set_parameter(UINT8 data);
+ void restore(UINT8 data);
+ void seek(UINT8 data);
+ void read_sector(UINT8 data);
+ void write_sector(UINT8 data);
+ void scan_id(UINT8 data);
+ void format(UINT8 data);
+
+ devcb_resolved_write_line m_out_intrq_func;
+ devcb_resolved_write_line m_out_bdrq_func;
+ devcb_resolved_write_line m_out_bcr_func;
+ devcb_resolved_read8 m_in_bcs_func;
+ devcb_resolved_write8 m_out_bcs_func;
+ devcb_resolved_write_line m_out_dirin_func;
+ devcb_resolved_write_line m_out_step_func;
+ devcb_resolved_write_line m_out_rwc_func;
+ devcb_resolved_read_line m_in_drdy_func;
+ devcb_resolved_read_line m_in_index_func;
+ devcb_resolved_read_line m_in_wf_func;
+ devcb_resolved_read_line m_in_tk000_func;
+ devcb_resolved_read_line m_in_sc_func;
+
+ UINT8 m_status;
+ UINT8 m_error;
+ UINT8 m_task_file[8];
+};
+
+
+// device type definition
+extern const device_type WD2010;
+
+#endif