diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/emu.mak | 2 | ||||
-rw-r--r-- | src/emu/machine/eepromdev.c | 456 | ||||
-rw-r--r-- | src/emu/machine/eepromdev.h | 72 | ||||
-rw-r--r-- | src/emu/machine/i2cmemdev.c | 492 | ||||
-rw-r--r-- | src/emu/machine/i2cmemdev.h | 46 |
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 |