mirror of
https://github.com/holub/mame
synced 2025-06-05 20:33:45 +03:00

appropriate, and to keep all global variables hanging off the machine structure. Once again, this means all state registration call sites have been touched: - state_save_register_global* now takes a machine parameter - state_save_register_item* now takes a machine parameter - added new state_save_register_device_item* which now uses the device name and tag to generate the base name Extended the fake sound devices to have more populated fields. Modified sound cores to use tags from the devices and simplified the start function. Renumbered CPU and sound get/set info constants to align with the device constants, and shared values where they were perfectly aligned. Set the type field in the fake device_configs for CPU and sound chips to a get_info stub which calls through to the CPU and sound specific get_info functions. This means the device_get_info() functions work for CPU and sound cores, even in their fake state. Changed device information getters from device_info() to device_get_info() to match the CPU and sound macros.
378 lines
8.7 KiB
C
378 lines
8.7 KiB
C
#include "driver.h"
|
|
#include "deprecat.h"
|
|
#include "eeprom.h"
|
|
|
|
#define VERBOSE 0
|
|
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
|
|
|
|
#define SERIAL_BUFFER_LENGTH 40
|
|
#define MEMORY_SIZE 1024
|
|
|
|
static const eeprom_interface *intf;
|
|
|
|
static int serial_count;
|
|
static UINT8 serial_buffer[SERIAL_BUFFER_LENGTH];
|
|
static UINT8 eeprom_data[MEMORY_SIZE];
|
|
static int eeprom_data_bits;
|
|
static int eeprom_read_address;
|
|
static int eeprom_clock_count;
|
|
static int latch,reset_line,clock_line,sending;
|
|
static int locked;
|
|
static int reset_delay;
|
|
|
|
/*
|
|
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 eeprom_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 eeprom_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 */
|
|
};
|
|
|
|
NVRAM_HANDLER( 93C46 )
|
|
{
|
|
if (read_or_write)
|
|
eeprom_save(file);
|
|
else
|
|
{
|
|
eeprom_init(&eeprom_interface_93C46);
|
|
if (file) eeprom_load(file);
|
|
}
|
|
}
|
|
|
|
NVRAM_HANDLER( 93C66B )
|
|
{
|
|
if (read_or_write)
|
|
eeprom_save(file);
|
|
else
|
|
{
|
|
eeprom_init(&eeprom_interface_93C66B);
|
|
if (file) eeprom_load(file);
|
|
}
|
|
}
|
|
|
|
void eeprom_init(const eeprom_interface *interface)
|
|
{
|
|
intf = interface;
|
|
|
|
if ((1 << intf->address_bits) * intf->data_bits / 8 > MEMORY_SIZE)
|
|
{
|
|
fatalerror("EEPROM larger than eeprom.c allows");
|
|
}
|
|
|
|
memset(eeprom_data,0xff,(1 << intf->address_bits) * intf->data_bits / 8);
|
|
serial_count = 0;
|
|
latch = 0;
|
|
reset_line = ASSERT_LINE;
|
|
clock_line = ASSERT_LINE;
|
|
eeprom_read_address = 0;
|
|
sending = 0;
|
|
if (intf->cmd_unlock) locked = 1;
|
|
else locked = 0;
|
|
|
|
state_save_register_global_array(Machine, eeprom_data);
|
|
state_save_register_global_array(Machine, serial_buffer);
|
|
state_save_register_global(Machine, clock_line);
|
|
state_save_register_global(Machine, reset_line);
|
|
state_save_register_global(Machine, locked);
|
|
state_save_register_global(Machine, serial_count);
|
|
state_save_register_global(Machine, latch);
|
|
state_save_register_global(Machine, reset_delay);
|
|
state_save_register_global(Machine, eeprom_clock_count);
|
|
state_save_register_global(Machine, eeprom_data_bits);
|
|
state_save_register_global(Machine, eeprom_read_address);
|
|
}
|
|
|
|
static void eeprom_write(int bit)
|
|
{
|
|
LOG(("EEPROM write bit %d\n",bit));
|
|
|
|
if (serial_count >= SERIAL_BUFFER_LENGTH-1)
|
|
{
|
|
logerror("error: EEPROM serial buffer overflow\n");
|
|
return;
|
|
}
|
|
|
|
serial_buffer[serial_count++] = (bit ? '1' : '0');
|
|
serial_buffer[serial_count] = 0; /* nul terminate so we can treat it as a string */
|
|
|
|
if ( (serial_count > intf->address_bits) &&
|
|
eeprom_command_match((char*)serial_buffer,intf->cmd_read,strlen((char*)serial_buffer)-intf->address_bits) )
|
|
{
|
|
int i,address;
|
|
|
|
address = 0;
|
|
for (i = serial_count-intf->address_bits;i < serial_count;i++)
|
|
{
|
|
address <<= 1;
|
|
if (serial_buffer[i] == '1') address |= 1;
|
|
}
|
|
if (intf->data_bits == 16)
|
|
eeprom_data_bits = (eeprom_data[2*address+0] << 8) + eeprom_data[2*address+1];
|
|
else
|
|
eeprom_data_bits = eeprom_data[address];
|
|
eeprom_read_address = address;
|
|
eeprom_clock_count = 0;
|
|
sending = 1;
|
|
serial_count = 0;
|
|
logerror("EEPROM read %04x from address %02x\n",eeprom_data_bits,address);
|
|
}
|
|
else if ( (serial_count > intf->address_bits) &&
|
|
eeprom_command_match((char*)serial_buffer,intf->cmd_erase,strlen((char*)serial_buffer)-intf->address_bits) )
|
|
{
|
|
int i,address;
|
|
|
|
address = 0;
|
|
for (i = serial_count-intf->address_bits;i < serial_count;i++)
|
|
{
|
|
address <<= 1;
|
|
if (serial_buffer[i] == '1') address |= 1;
|
|
}
|
|
logerror("EEPROM erase address %02x\n",address);
|
|
if (locked == 0)
|
|
{
|
|
if (intf->data_bits == 16)
|
|
{
|
|
eeprom_data[2*address+0] = 0x00;
|
|
eeprom_data[2*address+1] = 0x00;
|
|
}
|
|
else
|
|
eeprom_data[address] = 0x00;
|
|
}
|
|
else
|
|
logerror("Error: EEPROM is locked\n");
|
|
serial_count = 0;
|
|
}
|
|
else if ( (serial_count > (intf->address_bits + intf->data_bits)) &&
|
|
eeprom_command_match((char*)serial_buffer,intf->cmd_write,strlen((char*)serial_buffer)-(intf->address_bits + intf->data_bits)) )
|
|
{
|
|
int i,address,data;
|
|
|
|
address = 0;
|
|
for (i = serial_count-intf->data_bits-intf->address_bits;i < (serial_count-intf->data_bits);i++)
|
|
{
|
|
address <<= 1;
|
|
if (serial_buffer[i] == '1') address |= 1;
|
|
}
|
|
data = 0;
|
|
for (i = serial_count-intf->data_bits;i < serial_count;i++)
|
|
{
|
|
data <<= 1;
|
|
if (serial_buffer[i] == '1') data |= 1;
|
|
}
|
|
logerror("EEPROM write %04x to address %02x\n",data,address);
|
|
if (locked == 0)
|
|
{
|
|
if (intf->data_bits == 16)
|
|
{
|
|
eeprom_data[2*address+0] = data >> 8;
|
|
eeprom_data[2*address+1] = data & 0xff;
|
|
}
|
|
else
|
|
eeprom_data[address] = data;
|
|
}
|
|
else
|
|
logerror("Error: EEPROM is locked\n");
|
|
serial_count = 0;
|
|
}
|
|
else if ( eeprom_command_match((char*)serial_buffer,intf->cmd_lock,strlen((char*)serial_buffer)) )
|
|
{
|
|
logerror("EEPROM lock\n");
|
|
locked = 1;
|
|
serial_count = 0;
|
|
}
|
|
else if ( eeprom_command_match((char*)serial_buffer,intf->cmd_unlock,strlen((char*)serial_buffer)) )
|
|
{
|
|
logerror("EEPROM unlock\n");
|
|
locked = 0;
|
|
serial_count = 0;
|
|
}
|
|
}
|
|
|
|
static void eeprom_reset(void)
|
|
{
|
|
if (serial_count)
|
|
logerror("EEPROM reset, buffer = %s\n",serial_buffer);
|
|
|
|
serial_count = 0;
|
|
sending = 0;
|
|
reset_delay = intf->reset_delay; /* delay a little before returning setting data to 1 (needed by wbeachvl) */
|
|
}
|
|
|
|
|
|
void eeprom_write_bit(int bit)
|
|
{
|
|
LOG(("write bit %d\n",bit));
|
|
latch = bit;
|
|
}
|
|
|
|
int eeprom_read_bit(void)
|
|
{
|
|
int res;
|
|
|
|
if (sending)
|
|
res = (eeprom_data_bits >> intf->data_bits) & 1;
|
|
else
|
|
{
|
|
if (reset_delay > 0)
|
|
{
|
|
/* this is needed by wbeachvl */
|
|
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 eeprom_set_cs_line(int state)
|
|
{
|
|
LOG(("set reset line %d\n",state));
|
|
reset_line = state;
|
|
|
|
if (reset_line != CLEAR_LINE)
|
|
eeprom_reset();
|
|
}
|
|
|
|
void eeprom_set_clock_line(int state)
|
|
{
|
|
LOG(("set clock line %d\n",state));
|
|
if (state == PULSE_LINE || (clock_line == CLEAR_LINE && state != CLEAR_LINE))
|
|
{
|
|
if (reset_line == CLEAR_LINE)
|
|
{
|
|
if (sending)
|
|
{
|
|
if (eeprom_clock_count == intf->data_bits && intf->enable_multi_read)
|
|
{
|
|
eeprom_read_address = (eeprom_read_address + 1) & ((1 << intf->address_bits) - 1);
|
|
if (intf->data_bits == 16)
|
|
eeprom_data_bits = (eeprom_data[2*eeprom_read_address+0] << 8) + eeprom_data[2*eeprom_read_address+1];
|
|
else
|
|
eeprom_data_bits = eeprom_data[eeprom_read_address];
|
|
eeprom_clock_count = 0;
|
|
logerror("EEPROM read %04x from address %02x\n",eeprom_data_bits,eeprom_read_address);
|
|
}
|
|
eeprom_data_bits = (eeprom_data_bits << 1) | 1;
|
|
eeprom_clock_count++;
|
|
}
|
|
else
|
|
eeprom_write(latch);
|
|
}
|
|
}
|
|
|
|
clock_line = state;
|
|
}
|
|
|
|
|
|
void eeprom_load(mame_file *f)
|
|
{
|
|
mame_fread(f,eeprom_data,(1 << intf->address_bits) * intf->data_bits / 8);
|
|
}
|
|
|
|
void eeprom_save(mame_file *f)
|
|
{
|
|
mame_fwrite(f,eeprom_data,(1 << intf->address_bits) * intf->data_bits / 8);
|
|
}
|
|
|
|
void eeprom_set_data(const UINT8 *data, int length)
|
|
{
|
|
memcpy(eeprom_data, data, length);
|
|
}
|
|
|
|
void *eeprom_get_data_pointer(UINT32 *length, UINT32 *size)
|
|
{
|
|
if (length != NULL && intf != NULL)
|
|
*length = 1 << intf->address_bits;
|
|
if (size != NULL && intf != NULL)
|
|
*size = intf->data_bits / 8;
|
|
|
|
return eeprom_data;
|
|
}
|