summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/emu/emu.mak2
-rw-r--r--src/emu/machine/eepromdev.c456
-rw-r--r--src/emu/machine/eepromdev.h72
-rw-r--r--src/emu/machine/i2cmemdev.c492
-rw-r--r--src/emu/machine/i2cmemdev.h46
5 files changed, 1068 insertions, 0 deletions
diff --git a/src/emu/emu.mak b/src/emu/emu.mak
index 716014619be..0c6268a879d 100644
--- a/src/emu/emu.mak
+++ b/src/emu/emu.mak
@@ -132,10 +132,12 @@ EMUMACHINEOBJS = \
$(EMUMACHINE)/ds2401.o \
$(EMUMACHINE)/ds2404.o \
$(EMUMACHINE)/eeprom.o \
+ $(EMUMACHINE)/eepromdev.o \
$(EMUMACHINE)/f3853.o \
$(EMUMACHINE)/generic.o \
$(EMUMACHINE)/i8243.o \
$(EMUMACHINE)/i2cmem.o \
+ $(EMUMACHINE)/i2cmemdev.o \
$(EMUMACHINE)/idectrl.o \
$(EMUMACHINE)/intelfsh.o \
$(EMUMACHINE)/latch8.o \
diff --git a/src/emu/machine/eepromdev.c b/src/emu/machine/eepromdev.c
new file mode 100644
index 00000000000..71723a73b6f
--- /dev/null
+++ b/src/emu/machine/eepromdev.c
@@ -0,0 +1,456 @@
+/*
+ * Serial eeproms
+ *
+ */
+
+#include "driver.h"
+#include "machine/eepromdev.h"
+
+#define VERBOSE 0
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+#define SERIAL_BUFFER_LENGTH 40
+#define MEMORY_SIZE 1024
+
+typedef struct _eeprom_state eeprom_state;
+struct _eeprom_state
+{
+ const eeprom_interface *intf;
+ int serial_count;
+ UINT8 serial_buffer[SERIAL_BUFFER_LENGTH];
+ UINT8 eeprom_data[MEMORY_SIZE];
+ int eeprom_data_bits;
+ int eeprom_read_address;
+ int eeprom_clock_count;
+ int latch,reset_line,clock_line,sending;
+ int locked;
+ int reset_delay;
+};
+
+/*-------------------------------------------------
+ get_safe_token - makes sure that the passed
+ in device is, in fact, an I2C memory
+-------------------------------------------------*/
+
+INLINE eeprom_state *get_safe_token(const device_config *device)
+{
+ assert( device != NULL );
+ assert( device->token != NULL );
+ assert( device->type == EEPROM );
+
+ return (eeprom_state *)device->token;
+}
+
+/*
+ eeprom_command_match:
+
+ Try to match the first (len) digits in the EEPROM serial buffer
+ string (*buf) with an EEPROM command string (*cmd).
+ Return non zero if a match was found.
+
+ The serial buffer only contains '0' or '1' (e.g. "1001").
+ The command can contain: '0' or '1' or these wildcards:
+
+ 'x' : match both '0' and '1'
+ "*1": match "1", "01", "001", "0001" etc.
+ "*0": match "0", "10", "110", "1110" etc.
+
+ Note: (cmd) may be NULL. Return 0 (no match) in this case.
+*/
+static int eeprom_command_match(const char *buf, const char *cmd, int len)
+{
+ if ( cmd == 0 ) return 0;
+ if ( len == 0 ) return 0;
+
+ for (;len>0;)
+ {
+ char b = *buf;
+ char c = *cmd;
+
+ if ((b==0) || (c==0))
+ return (b==c);
+
+ switch ( c )
+ {
+ case '0':
+ case '1':
+ if (b != c) return 0;
+ case 'X':
+ case 'x':
+ buf++;
+ len--;
+ cmd++;
+ break;
+
+ case '*':
+ c = cmd[1];
+ switch( c )
+ {
+ case '0':
+ case '1':
+ if (b == c) { cmd++; }
+ else { buf++; len--; }
+ break;
+ default: return 0;
+ }
+ }
+ }
+ return (*cmd==0);
+}
+
+
+const eeprom_interface eepromdev_interface_93C46 =
+{
+ 6, // address bits 6
+ 16, // data bits 16
+ "*110", // read 1 10 aaaaaa
+ "*101", // write 1 01 aaaaaa dddddddddddddddd
+ "*111", // erase 1 11 aaaaaa
+ "*10000xxxx", // lock 1 00 00xxxx
+ "*10011xxxx", // unlock 1 00 11xxxx
+ 1,
+// "*10001xxxx" // write all 1 00 01xxxx dddddddddddddddd
+// "*10010xxxx" // erase all 1 00 10xxxx
+};
+
+const eeprom_interface eepromdev_interface_93C66B =
+{
+ 8, /* address bits */
+ 16, /* data bits */
+ "*110", /* read command */
+ "*101", /* write command */
+ "*111", /* erase command */
+ "*10000xxxxxx", /* lock command */
+ "*10011xxxxxx", /* unlock command */
+ 1,
+// "*10001xxxxxx", /* write all */
+// "*10010xxxxxx", /* erase all */
+};
+
+static void eeprom_write(eeprom_state *c, int bit)
+{
+ LOG(("EEPROM write bit %d\n",bit));
+
+ if (c->serial_count >= SERIAL_BUFFER_LENGTH-1)
+ {
+ logerror("error: EEPROM serial buffer overflow\n");
+ return;
+ }
+
+ c->serial_buffer[c->serial_count++] = (bit ? '1' : '0');
+ c->serial_buffer[c->serial_count] = 0; /* nul terminate so we can treat it as a string */
+
+ if ( (c->serial_count > c->intf->address_bits) &&
+ eeprom_command_match((char*)(c->serial_buffer),c->intf->cmd_read,strlen((char*)(c->serial_buffer))-c->intf->address_bits) )
+ {
+ int i,address;
+
+ address = 0;
+ for (i = c->serial_count-c->intf->address_bits;i < c->serial_count;i++)
+ {
+ address <<= 1;
+ if (c->serial_buffer[i] == '1') address |= 1;
+ }
+ if (c->intf->data_bits == 16)
+ c->eeprom_data_bits = (c->eeprom_data[2*address+0] << 8) + c->eeprom_data[2*address+1];
+ else
+ c->eeprom_data_bits = c->eeprom_data[address];
+ c->eeprom_read_address = address;
+ c->eeprom_clock_count = 0;
+ c->sending = 1;
+ c->serial_count = 0;
+logerror("EEPROM read %04x from address %02x\n",c->eeprom_data_bits,address);
+ }
+ else if ( (c->serial_count > c->intf->address_bits) &&
+ eeprom_command_match((char*)(c->serial_buffer),c->intf->cmd_erase,strlen((char*)(c->serial_buffer))-c->intf->address_bits) )
+ {
+ int i,address;
+
+ address = 0;
+ for (i = c->serial_count-c->intf->address_bits;i < c->serial_count;i++)
+ {
+ address <<= 1;
+ if (c->serial_buffer[i] == '1') address |= 1;
+ }
+logerror("EEPROM erase address %02x\n",address);
+ if (c->locked == 0)
+ {
+ if (c->intf->data_bits == 16)
+ {
+ c->eeprom_data[2*address+0] = 0x00;
+ c->eeprom_data[2*address+1] = 0x00;
+ }
+ else
+ c->eeprom_data[address] = 0x00;
+ }
+ else
+logerror("Error: EEPROM is locked\n");
+ c->serial_count = 0;
+ }
+ else if ( (c->serial_count > (c->intf->address_bits + c->intf->data_bits)) &&
+ eeprom_command_match((char*)(c->serial_buffer),c->intf->cmd_write,strlen((char*)(c->serial_buffer))-(c->intf->address_bits + c->intf->data_bits)) )
+ {
+ int i,address,data;
+
+ address = 0;
+ for (i = c->serial_count-c->intf->data_bits-c->intf->address_bits;i < (c->serial_count-c->intf->data_bits);i++)
+ {
+ address <<= 1;
+ if (c->serial_buffer[i] == '1') address |= 1;
+ }
+ data = 0;
+ for (i = c->serial_count-c->intf->data_bits;i < c->serial_count;i++)
+ {
+ data <<= 1;
+ if (c->serial_buffer[i] == '1') data |= 1;
+ }
+logerror("EEPROM write %04x to address %02x\n",data,address);
+ if (c->locked == 0)
+ {
+ if (c->intf->data_bits == 16)
+ {
+ c->eeprom_data[2*address+0] = data >> 8;
+ c->eeprom_data[2*address+1] = data & 0xff;
+ }
+ else
+ c->eeprom_data[address] = data;
+ }
+ else
+logerror("Error: EEPROM is locked\n");
+ c->serial_count = 0;
+ }
+ else if ( eeprom_command_match((char*)(c->serial_buffer),c->intf->cmd_lock,strlen((char*)(c->serial_buffer))) )
+ {
+logerror("EEPROM lock\n");
+ c->locked = 1;
+ c->serial_count = 0;
+ }
+ else if ( eeprom_command_match((char*)(c->serial_buffer),c->intf->cmd_unlock,strlen((char*)(c->serial_buffer))) )
+ {
+logerror("EEPROM unlock\n");
+ c->locked = 0;
+ c->serial_count = 0;
+ }
+}
+
+static void eeprom_reset(eeprom_state *c)
+{
+ if (c->serial_count)
+ logerror("EEPROM reset, buffer = %s\n",c->serial_buffer);
+
+ c->serial_count = 0;
+ c->sending = 0;
+ c->reset_delay = c->intf->reset_delay; /* delay a little before returning setting data to 1 (needed by wbeachvl) */
+}
+
+
+void eepromdev_write_bit(const device_config *device, int bit)
+{
+ eeprom_state *c = get_safe_token(device);
+
+ LOG(("write bit %d\n",bit));
+ c->latch = bit;
+}
+
+int eepromdev_read_bit(const device_config *device)
+{
+ eeprom_state *c = get_safe_token(device);
+ int res;
+
+ if (c->sending)
+ res = (c->eeprom_data_bits >> c->intf->data_bits) & 1;
+ else
+ {
+ if (c->reset_delay > 0)
+ {
+ /* this is needed by wbeachvl */
+ c->reset_delay--;
+ res = 0;
+ }
+ else
+ res = 1;
+ }
+
+ LOG(("read bit %d\n",res));
+
+ return res;
+}
+
+/*CUSTOM_INPUT( eeprom_bit_r )
+{
+ return eeprom_read_bit();
+}*/
+
+void eepromdev_set_cs_line(const device_config *device, int state)
+{
+ eeprom_state *c = get_safe_token(device);
+
+ LOG(("set reset line %d\n",state));
+ c->reset_line = state;
+
+ if (c->reset_line != CLEAR_LINE)
+ eeprom_reset(c);
+}
+
+void eepromdev_set_clock_line(const device_config *device, int state)
+{
+ eeprom_state *c = get_safe_token(device);
+
+ LOG(("set clock line %d\n",state));
+ if (state == PULSE_LINE || (c->clock_line == CLEAR_LINE && state != CLEAR_LINE))
+ {
+ if (c->reset_line == CLEAR_LINE)
+ {
+ if (c->sending)
+ {
+ if (c->eeprom_clock_count == c->intf->data_bits && c->intf->enable_multi_read)
+ {
+ c->eeprom_read_address = (c->eeprom_read_address + 1) & ((1 << c->intf->address_bits) - 1);
+ if (c->intf->data_bits == 16)
+ c->eeprom_data_bits = (c->eeprom_data[2*c->eeprom_read_address+0] << 8) + c->eeprom_data[2*c->eeprom_read_address+1];
+ else
+ c->eeprom_data_bits = c->eeprom_data[c->eeprom_read_address];
+ c->eeprom_clock_count = 0;
+logerror("EEPROM read %04x from address %02x\n",c->eeprom_data_bits,c->eeprom_read_address);
+ }
+ c->eeprom_data_bits = (c->eeprom_data_bits << 1) | 1;
+ c->eeprom_clock_count++;
+ }
+ else
+ eeprom_write(c,c->latch);
+ }
+ }
+
+ c->clock_line = state;
+}
+
+
+void eepromdev_load(const device_config *device, mame_file *f)
+{
+ eeprom_state *c = get_safe_token(device);
+
+ mame_fread(f, c->eeprom_data, (1 << c->intf->address_bits) * c->intf->data_bits / 8);
+}
+
+void eepromdev_save(const device_config *device, mame_file *f)
+{
+ eeprom_state *c = get_safe_token(device);
+
+ mame_fwrite(f, c->eeprom_data, (1 << c->intf->address_bits) * c->intf->data_bits / 8);
+}
+
+void eepromdev_set_data(const device_config *device, const UINT8 *data, int length)
+{
+ eeprom_state *c = get_safe_token(device);
+
+ assert(length <= ((1 << c->intf->address_bits) * c->intf->data_bits / 8));
+ memcpy(c->eeprom_data, data, length);
+}
+
+void *eepromdev_get_data_pointer(const device_config *device, UINT32 *length, UINT32 *size)
+{
+ eeprom_state *c = get_safe_token(device);
+
+ if (length != NULL && c->intf != NULL)
+ *length = 1 << c->intf->address_bits;
+ if (size != NULL && c->intf != NULL)
+ *size = c->intf->data_bits / 8;
+
+ return c->eeprom_data;
+}
+
+static DEVICE_NVRAM( eeprom )
+{
+ const eeprom_config *config = device->inline_config;
+
+ if (read_or_write)
+ eepromdev_save(device, file);
+ else
+ if (file)
+ eepromdev_load(device, file);
+ else
+ if ((config->default_data != NULL) && (config->default_data_size != 0))
+ eepromdev_set_data(device, config->default_data, config->default_data_size);
+}
+
+static DEVICE_START(eeprom)
+{
+ eeprom_state *c = get_safe_token(device);
+ const eeprom_config *config;
+
+ /* validate some basic stuff */
+ assert(device != NULL);
+ assert(device->inline_config != NULL);
+ assert(device->machine != NULL);
+ assert(device->machine->config != NULL);
+
+ config = device->inline_config;
+
+ c->intf = config->pinterface;
+
+ if ((1 << c->intf->address_bits) * c->intf->data_bits / 8 > MEMORY_SIZE)
+ {
+ fatalerror("EEPROM larger than eepromdev.c allows");
+ }
+
+ memset(c->eeprom_data, 0xff, (1 << c->intf->address_bits) * c->intf->data_bits / 8);
+ if ((config->default_data != NULL) && (config->default_data_size != 0))
+ eepromdev_set_data(device, config->default_data, config->default_data_size);
+ c->serial_count = 0;
+ c->latch = 0;
+ c->reset_line = ASSERT_LINE;
+ c->clock_line = ASSERT_LINE;
+ c->eeprom_read_address = 0;
+ c->sending = 0;
+ if (c->intf->cmd_unlock) c->locked = 1;
+ else c->locked = 0;
+
+ state_save_register_device_item_pointer( device, 0, c->eeprom_data, MEMORY_SIZE);
+ state_save_register_device_item_pointer( device, 0, c->serial_buffer, SERIAL_BUFFER_LENGTH);
+ state_save_register_device_item( device, 0, c->clock_line);
+ state_save_register_device_item( device, 0, c->reset_line);
+ state_save_register_device_item( device, 0, c->locked);
+ state_save_register_device_item( device, 0, c->serial_count);
+ state_save_register_device_item( device, 0, c->latch);
+ state_save_register_device_item( device, 0, c->reset_delay);
+ state_save_register_device_item( device, 0, c->eeprom_clock_count);
+ state_save_register_device_item( device, 0, c->eeprom_data_bits);
+ state_save_register_device_item( device, 0, c->eeprom_read_address);
+}
+
+static DEVICE_RESET(eeprom)
+{
+}
+
+static DEVICE_SET_INFO(eeprom)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+DEVICE_GET_INFO(eeprom)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(eeprom_state); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(eeprom_config); break;
+ case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_SET_INFO: info->set_info = DEVICE_SET_INFO_NAME(eeprom); break;
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(eeprom); break;
+ case DEVINFO_FCT_STOP: /* nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(eeprom); break;
+ case DEVINFO_FCT_NVRAM: info->nvram = DEVICE_NVRAM_NAME(eeprom); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "EEPROM"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "EEPROM"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
+ }
+}
diff --git a/src/emu/machine/eepromdev.h b/src/emu/machine/eepromdev.h
new file mode 100644
index 00000000000..cbb96dfb61c
--- /dev/null
+++ b/src/emu/machine/eepromdev.h
@@ -0,0 +1,72 @@
+/*
+ * Serial eeproms
+ *
+ */
+
+#if !defined( EEPROMDEV_H )
+#define EEPROMDEV_H ( 1 )
+
+typedef struct _eeprom_interface eeprom_interface;
+struct _eeprom_interface
+{
+ int address_bits; /* EEPROM has 2^address_bits cells */
+ int data_bits; /* every cell has this many bits (8 or 16) */
+ const char *cmd_read; /* read command string, e.g. "0110" */
+ const char *cmd_write; /* write command string, e.g. "0111" */
+ const char *cmd_erase; /* erase command string, or 0 if n/a */
+ const char *cmd_lock; /* lock command string, or 0 if n/a */
+ const char *cmd_unlock; /* unlock command string, or 0 if n/a */
+ int enable_multi_read; /* set to 1 to enable multiple values to be read from one read command */
+ int reset_delay; /* number of times eeprom_read_bit() should return 0 after a reset, */
+ /* before starting to return 1. */
+};
+
+typedef struct _eeprom_config eeprom_config;
+struct _eeprom_config
+{
+ eeprom_interface *pinterface;
+ UINT8 *default_data;
+ int default_data_size;
+};
+
+/* 93C46 */
+extern const eeprom_interface eepromdev_interface_93C46;
+
+/* 93C66B */
+extern const eeprom_interface eepromdev_interface_93C66B;
+
+#define EEPROM DEVICE_GET_INFO_NAME(eeprom)
+DEVICE_GET_INFO(eeprom);
+
+#define MDRV_EEPROM_ADD(_tag, _interface, _data_size, _data) \
+ MDRV_DEVICE_ADD(_tag, EEPROM, 0) \
+ MDRV_DEVICE_CONFIG_DATAPTR(eeprom_config, pinterface, &_interface) \
+ MDRV_EEPROM_DATA(_data, _data_size)
+
+#define MDRV_EEPROM_93C46_ADD(_tag, _data_size, _data) \
+ MDRV_EEPROM_ADD(_tag, eepromdev_interface_93C46, _data_size, _data)
+
+#define MDRV_EEPROM_93C66B_ADD(_tag, _data_size, _data) \
+ MDRV_EEPROM_ADD(_tag, eepromdev_interface_93C66B, _data_size, _data)
+
+#define MDRV_EEPROM_DATA(_data, _size) \
+ MDRV_DEVICE_CONFIG_DATAPTR(eeprom_config, default_data, &_data) \
+ MDRV_DEVICE_CONFIG_DATA32(eeprom_config, default_data_size, _size)
+
+#define MDRV_EEPROM_REMOVE(_tag) \
+ MDRV_DEVICE_REMOVE(_tag, EEPROM)
+
+
+void eepromdev_write_bit( const device_config *device, int bit );
+int eepromdev_read_bit( const device_config *device );
+//CUSTOM_INPUT( eeprom_bit_r );
+void eepromdev_set_cs_line( const device_config *device, int state );
+void eepromdev_set_clock_line( const device_config *device, int state );
+
+void eepromdev_load( const device_config *device, mame_file *file );
+void eepromdev_save( const device_config *device, mame_file *file );
+
+void eepromdev_set_data( const device_config *device, const UINT8 *data, int length );
+void *eepromdev_get_data_pointer( const device_config *device, UINT32 *length, UINT32 *size );
+
+#endif
diff --git a/src/emu/machine/i2cmemdev.c b/src/emu/machine/i2cmemdev.c
new file mode 100644
index 00000000000..cc0f98d3654
--- /dev/null
+++ b/src/emu/machine/i2cmemdev.c
@@ -0,0 +1,492 @@
+/*
+ I2C Memory
+
+Generic ram/rom/eeprom/flash on an i2c bus. Supports specifying the slave address,
+the data size & the page size for writing.
+
+inputs:
+ e0,e1,e2 lower 3 bits of the slave address
+ sda serial data
+ scl serial clock
+ wc write protect
+
+outputs:
+ sda serial data
+
+The memory address is only 8 bits, devices larger than this have multiple slave addresses.
+The top five address bits are set at manufacture time, two values are standard.
+Up to 4096 bytes can be addressed.
+
+*/
+
+#include "driver.h"
+#include "machine/i2cmemdev.h"
+
+#define VERBOSE_LEVEL ( 0 )
+
+INLINE void ATTR_PRINTF(3,4) 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", cpuexec_describe_context(machine), buf );
+ }
+}
+
+#define STATE_IDLE ( 0 )
+#define STATE_DEVSEL ( 1 )
+#define STATE_BYTEADDR ( 2 )
+#define STATE_DATAIN ( 3 )
+#define STATE_DATAOUT ( 4 )
+
+#define DEVSEL_RW ( 1 )
+#define DEVSEL_ADDRESS ( 0xfe )
+
+typedef struct _i2cmem_state i2cmem_state;
+struct _i2cmem_state
+{
+ int slave_address;
+ int scl;
+ int sdaw;
+ int e0;
+ int e1;
+ int e2;
+ int wc;
+ int sdar;
+ int state;
+ int bits;
+ int shift;
+ int devsel;
+ int byteaddr;
+ unsigned char *data;
+ int data_size;
+ unsigned char *page;
+ int page_offset;
+ int page_size;
+ int readmode;
+};
+
+/*-------------------------------------------------
+ get_safe_token - makes sure that the passed
+ in device is, in fact, an I2C memory
+-------------------------------------------------*/
+
+INLINE i2cmem_state *get_safe_token( const device_config *device )
+{
+ assert( device != NULL );
+ assert( device->token != NULL );
+ assert( device->type == I2CMEM );
+
+ return (i2cmem_state *)device->token;
+}
+
+static int select_device( i2cmem_state *c )
+{
+ int device = ( c->slave_address & 0xf0 ) | ( c->e2 << 3 ) | ( c->e1 << 2 ) | ( c->e0 << 1 );
+ int mask = DEVSEL_ADDRESS & ~( ( c->data_size - 1 ) >> 7 );
+
+ if( ( c->devsel & mask ) == ( device & mask ) )
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int data_offset( i2cmem_state *c )
+{
+ return ( ( ( c->devsel << 7 ) & 0xff00 ) | ( c->byteaddr & 0xff ) ) & ( c->data_size - 1 );
+}
+
+void i2cmemdev_write( const device_config *device, int line, int data )
+{
+ i2cmem_state *c = get_safe_token( device );
+
+ switch( line )
+ {
+ case I2CMEM_E0:
+ if( c->e0 != data )
+ {
+ c->e0 = data;
+ verboselog( device->machine, 2, "i2cmem_write( I2CMEM_E0, %d )\n", c->e0 );
+ }
+ break;
+
+ case I2CMEM_E1:
+ if( c->e1 != data )
+ {
+ c->e1 = data;
+ verboselog( device->machine, 2, "i2cmem_write( I2CMEM_E1, %d )\n", c->e1 );
+ }
+ break;
+
+ case I2CMEM_E2:
+ if( c->e2 != data )
+ {
+ c->e2 = data;
+ verboselog( device->machine, 2, "i2cmem_write( I2CMEM_E2, %d )\n", c->e2 );
+ }
+ break;
+
+ case I2CMEM_SDA:
+ if( c->sdaw != data )
+ {
+ c->sdaw = data;
+ verboselog( device->machine, 2, "i2cmem_write( I2CMEM_SDA, %d )\n", c->sdaw );
+
+ if( c->scl )
+ {
+ if( c->sdaw )
+ {
+ verboselog( device->machine, 1, "i2cmem stop\n");
+ c->state = STATE_IDLE;
+ c->byteaddr = 0;
+ }
+ else
+ {
+ verboselog( device->machine, 2, "i2cmem start\n");
+ c->state = STATE_DEVSEL;
+ c->bits = 0;
+ }
+
+ c->sdar = 1;
+ }
+ }
+ break;
+
+ case I2CMEM_SCL:
+ if( c->scl != data )
+ {
+ c->scl = data;
+ verboselog( device->machine, 2, "i2cmem_write( I2CMEM_SCL, %d )\n", c->scl );
+
+ switch( c->state )
+ {
+ case STATE_DEVSEL:
+ case STATE_BYTEADDR:
+ case STATE_DATAIN:
+ if( c->bits < 8 )
+ {
+ if( c->scl )
+ {
+ c->shift = ( ( c->shift << 1 ) | c->sdaw ) & 0xff;
+ c->bits++;
+ }
+ }
+ else
+ {
+ if( c->scl )
+ {
+ switch( c->state )
+ {
+ case STATE_DEVSEL:
+ c->devsel = c->shift;
+
+ if( !select_device( c ) )
+ {
+ verboselog( device->machine, 1, "i2cmem devsel %02x: not this device\n", c->devsel );
+ c->state = STATE_IDLE;
+ }
+ else if( ( c->devsel & DEVSEL_RW ) == 0 )
+ {
+ verboselog( device->machine, 1, "i2cmem devsel %02x: write\n", c->devsel );
+ c->state = STATE_BYTEADDR;
+ }
+ else
+ {
+ verboselog( device->machine, 1, "i2cmem devsel %02x: read\n", c->devsel );
+ c->state = STATE_DATAOUT;
+ }
+ break;
+
+ case STATE_BYTEADDR:
+ c->byteaddr = c->shift;
+ c->page_offset = 0;
+
+ verboselog( device->machine, 1, "i2cmem byteaddr %02x\n", c->byteaddr );
+
+ c->state = STATE_DATAIN;
+ break;
+
+ case STATE_DATAIN:
+ if( c->wc )
+ {
+ verboselog( device->machine, 0, "i2cmem write not enabled\n");
+ c->state = STATE_IDLE;
+ }
+ else if( c->page_size > 0 )
+ {
+ c->page[ c->page_offset ] = c->shift;
+ verboselog( device->machine, 1, "i2cmem page[ %04x ] <- %02x\n", c->page_offset, c->page[ c->page_offset ] );
+
+ c->page_offset++;
+ if( c->page_offset == c->page_size )
+ {
+ int offset = data_offset( c ) & ~( c->page_size - 1 );
+
+ memcpy( &c->data[ offset ], c->page, c->page_size );
+ verboselog( device->machine, 1, "i2cmem data[ %04x to %04x ] = page\n", offset, offset + c->page_size - 1 );
+
+ c->page_offset = 0;
+ }
+ }
+ else
+ {
+ int offset = data_offset( c );
+
+ c->data[ offset ] = c->shift;
+ verboselog( device->machine, 1, "i2cmem data[ %04x ] <- %02x\n", offset, c->data[ offset ] );
+
+ c->byteaddr++;
+ }
+ break;
+ }
+
+ c->bits++;
+ }
+ else
+ {
+ if( c->bits == 8 )
+ {
+ c->sdar = 0;
+ }
+ else
+ {
+ c->bits = 0;
+ c->sdar = 1;
+ }
+ }
+ }
+ break;
+
+ case STATE_DATAOUT:
+ if( c->bits < 8 )
+ {
+ if( c->scl )
+ {
+ if( c->bits == 0 )
+ {
+ int offset = data_offset( c );
+
+ c->shift = c->data[ offset ];
+ verboselog( device->machine, 1, "i2cmem data[ %04x ] -> %02x\n", offset, c->data[ offset ] );
+ c->byteaddr++;
+ }
+
+ c->sdar = ( c->shift >> 7 ) & 1;
+
+ c->shift = ( c->shift << 1 ) & 0xff;
+ c->bits++;
+ }
+ }
+ else
+ {
+ if( c->scl )
+ {
+ if( c->sdaw )
+ {
+ verboselog( device->machine, 1, "i2cmem sleep\n");
+ c->state = STATE_IDLE;
+ }
+
+ c->bits++;
+ }
+ else
+ {
+ if( c->bits == 8 )
+ {
+ c->sdar = 1;
+ }
+ else
+ {
+ c->bits = 0;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case I2CMEM_WC:
+ if( c->wc != data )
+ {
+ c->wc = data;
+ verboselog( device->machine, 2, "i2cmem_write( I2CMEM_WC, %d )\n", c->wc );
+ }
+ break;
+
+ default:
+ verboselog( device->machine, 0, "i2cmem_write( %d, %d ) invalid line\n", line, data );
+ break;
+ }
+}
+
+int i2cmemdev_read( const device_config *device, int line )
+{
+ i2cmem_state *c = get_safe_token( device );
+
+ switch( line )
+ {
+ case I2CMEM_SDA:
+ if (c->readmode == 0)
+ {
+ verboselog( device->machine, 2, "i2cmem_read( I2CMEM_SDA ) %d\n", c->sdar & c->sdaw );
+ return c->sdar & c->sdaw;
+ }
+ else
+ {
+ verboselog( device->machine, 2, "i2cmem_read( I2CMEM_SDA ) %d\n", c->sdar );
+ return c->sdar;
+ }
+
+ default:
+ verboselog( device->machine, 0, "i2cmem_read( %d ) invalid line\n", line );
+ break;
+ }
+
+ return 0;
+}
+
+void i2cmemdev_set_read_mode( const device_config *device, int mode )
+{
+ i2cmem_state *c = get_safe_token( device );
+
+ c->readmode = mode;
+}
+
+/*-------------------------------------------------
+ device start callback
+-------------------------------------------------*/
+
+static DEVICE_START( i2cmem )
+{
+ i2cmem_state *c = get_safe_token( device );
+ const i2cmem_config *config;
+ unsigned char *page = NULL;
+
+ /* validate some basic stuff */
+ assert( device != NULL );
+ assert( device->inline_config != NULL );
+ assert( device->machine != NULL );
+ assert( device->machine->config != NULL );
+
+ config = device->inline_config;
+
+ c->scl = 0;
+ c->sdaw = 0;
+ c->e0 = 0;
+ c->e1 = 0;
+ c->e2 = 0;
+ c->wc = 0;
+ c->sdar = 1;
+ c->state = STATE_IDLE;
+ c->bits = 0;
+ c->shift = 0;
+ c->devsel = 0;
+ c->byteaddr = 0;
+ c->readmode = 0;
+
+ if( config != NULL )
+ {
+ c->data = auto_malloc( config->data_size );
+ if( config->data != NULL )
+ memcpy(c->data, config->data, config->data_size);
+
+ if( config->page_size > 0 )
+ page = auto_malloc( config->page_size );
+
+ c->slave_address = config->slave_address;
+ c->data_size = config->data_size;
+ c->page_size = config->page_size;
+ c->page = page;
+ }
+
+ state_save_register_device_item( device, 0, c->scl );
+ state_save_register_device_item( device, 0, c->sdaw );
+ state_save_register_device_item( device, 0, c->e0 );
+ state_save_register_device_item( device, 0, c->e1 );
+ state_save_register_device_item( device, 0, c->e2 );
+ state_save_register_device_item( device, 0, c->wc );
+ state_save_register_device_item( device, 0, c->sdar );
+ state_save_register_device_item( device, 0, c->state );
+ state_save_register_device_item( device, 0, c->bits );
+ state_save_register_device_item( device, 0, c->shift );
+ state_save_register_device_item( device, 0, c->devsel );
+ state_save_register_device_item( device, 0, c->byteaddr );
+ state_save_register_device_item_pointer( device, 0, c->data, c->data_size );
+ state_save_register_device_item( device, 0, c->readmode );
+}
+
+/*-------------------------------------------------
+ device reset callback
+-------------------------------------------------*/
+
+static DEVICE_RESET( i2cmem )
+{
+}
+
+static DEVICE_NVRAM( i2cmem )
+{
+ const i2cmem_config *config = device->inline_config;
+ i2cmem_state *c = get_safe_token( device );
+
+ if( read_or_write )
+ {
+ mame_fwrite( file, c->data, c->data_size );
+ }
+ else if( file )
+ {
+ mame_fread( file, c->data, c->data_size );
+ }
+ else
+ {
+ if( config->data != NULL )
+ memcpy( c->data, config->data, config->data_size );
+ }
+}
+
+/*-------------------------------------------------
+ device set info callback
+-------------------------------------------------*/
+
+static DEVICE_SET_INFO( i2cmem )
+{
+ switch ( state )
+ {
+ /* no parameters to set */
+ }
+}
+
+/*-------------------------------------------------
+ device get info callback
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( i2cmem )
+{
+ switch ( state )
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof( i2cmem_state ); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof( i2cmem_config ); break;
+ case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_SET_INFO: info->set_info = DEVICE_SET_INFO_NAME( i2cmem ); break;
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( i2cmem ); break;
+ case DEVINFO_FCT_STOP: /* nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( i2cmem ); break;
+ case DEVINFO_FCT_NVRAM: info->nvram = DEVICE_NVRAM_NAME( i2cmem ); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy( info->s, "I2CMEM" ); break;
+ case DEVINFO_STR_FAMILY: strcpy( info->s, "EEPROM" ); break;
+ case DEVINFO_STR_VERSION: strcpy( info->s, "1.0" ); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy( info->s, __FILE__ ); break;
+ case DEVINFO_STR_CREDITS: strcpy( info->s, "Copyright Nicola Salmoria and the MAME Team" ); break;
+ }
+}
diff --git a/src/emu/machine/i2cmemdev.h b/src/emu/machine/i2cmemdev.h
new file mode 100644
index 00000000000..bf8939f883a
--- /dev/null
+++ b/src/emu/machine/i2cmemdev.h
@@ -0,0 +1,46 @@
+/*
+ * I2C Memory
+ *
+ */
+
+#if !defined( I2CMEMDEV_H )
+#define I2CMEMDEV_H ( 1 )
+
+#define I2CMEM_E0 ( 1 )
+#define I2CMEM_E1 ( 2 )
+#define I2CMEM_E2 ( 3 )
+#define I2CMEM_SDA ( 5 )
+#define I2CMEM_SCL ( 6 )
+#define I2CMEM_WC ( 7 )
+
+#define I2CMEM_SLAVE_ADDRESS ( 0xa0 )
+#define I2CMEM_SLAVE_ADDRESS_ALT ( 0xb0 )
+
+typedef struct _i2cmem_config i2cmem_config;
+struct _i2cmem_config
+{
+ const int slave_address;
+ const int page_size;
+ const int data_size;
+ const char *data;
+};
+
+#define I2CMEM DEVICE_GET_INFO_NAME(i2cmem)
+DEVICE_GET_INFO(i2cmem);
+
+#define MDRV_I2CMEM_ADD(_tag, _slave_address, _page_size, _data_size, _data) \
+ MDRV_DEVICE_ADD(_tag, I2CMEM, 0) \
+ MDRV_DEVICE_CONFIG_DATA32(i2cmem_config, slave_address, _slave_address) \
+ MDRV_DEVICE_CONFIG_DATA32(i2cmem_config, page_size, _page_size) \
+ MDRV_DEVICE_CONFIG_DATA32(i2cmem_config, data_size, _data_size) \
+ MDRV_DEVICE_CONFIG_DATAPTR(i2cmem_config, data, _data)
+
+#define MDRV_I2CMEM_REMOVE(_tag) \
+ MDRV_DEVICE_REMOVE(_tag, I2CMEM)
+
+
+void i2cmemdev_write( const device_config *device, int line, int data );
+int i2cmemdev_read( const device_config *device, int line );
+void i2cmemdev_set_read_mode( const device_config *device, int mode );
+
+#endif