diff options
Diffstat (limited to 'src/emu/machine/eeprom.c')
-rw-r--r-- | src/emu/machine/eeprom.c | 480 |
1 files changed, 114 insertions, 366 deletions
diff --git a/src/emu/machine/eeprom.c b/src/emu/machine/eeprom.c index 1ef1cbb87a3..1138f1726c6 100644 --- a/src/emu/machine/eeprom.c +++ b/src/emu/machine/eeprom.c @@ -2,7 +2,38 @@ eeprom.c - Serial eeproms. + Base class for EEPROM devices. + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ @@ -24,61 +55,12 @@ // GLOBAL VARIABLES //************************************************************************** -// device type definition -const device_type SERIAL_EEPROM = &device_creator<serial_eeprom_device>; - -const serial_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, // enable_multi_read - 0 // reset_delay -// "*10001xxxx" // write all 1 00 01xxxx dddddddddddddddd -// "*10010xxxx" // erase all 1 00 10xxxx -}; - -const serial_eeprom_interface eeprom_interface_93C46_8bit = -{ - 7, // address bits 7 - 8, // data bits 8 - "*110", // read 1 10 aaaaaa - "*101", // write 1 01 aaaaaa dddddddd - "*111", // erase 1 11 aaaaaa - "*10000xxxx", // lock 1 00 00xxxx - "*10011xxxx", // unlock 1 00 11xxxx - 1, // enable_multi_read - 0 // reset_delay -// "*10001xxxx" // write all 1 00 01xxxx dddddddd -// "*10010xxxx" // erase all 1 00 10xxxx -}; - -const serial_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, // enable_multi_read - 0 // reset_delay -// "*10001xxxxxx", // write all -// "*10010xxxxxx", // erase all -}; - - -static ADDRESS_MAP_START( eeprom_map8, AS_PROGRAM, 8, serial_eeprom_device ) +static ADDRESS_MAP_START( eeprom_map8, AS_PROGRAM, 8, base_eeprom_device ) AM_RANGE(0x0000, 0x0fff) AM_RAM ADDRESS_MAP_END -static ADDRESS_MAP_START( eeprom_map16, AS_PROGRAM, 16, serial_eeprom_device ) +static ADDRESS_MAP_START( eeprom_map16, AS_PROGRAM, 16, base_eeprom_device ) AM_RANGE(0x0000, 0x07ff) AM_RAM ADDRESS_MAP_END @@ -89,40 +71,43 @@ ADDRESS_MAP_END //************************************************************************** //------------------------------------------------- -// serial_eeprom_device - constructor +// base_eeprom_device - constructor //------------------------------------------------- -serial_eeprom_device::serial_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, SERIAL_EEPROM, "Serial EEPROM", tag, owner, clock, "seeprom", __FILE__), +base_eeprom_device::base_eeprom_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file) + : device_t(mconfig, devtype, name, tag, owner, 0, shortname, file), device_memory_interface(mconfig, *this), device_nvram_interface(mconfig, *this), + m_cells(0), + m_address_bits(0), + m_data_bits(0), + m_default_data(0), m_default_data_size(0), m_default_value(0), - m_serial_count(0), - m_data_buffer(0), - m_read_address(0), - m_clock_count(0), - m_latch(0), - m_reset_line(CLEAR_LINE), - m_clock_line(CLEAR_LINE), - m_sending(0), - m_locked(false), - m_reset_counter(0) + m_default_value_set(false) { - m_default_data.u8 = NULL; - memset(downcast<serial_eeprom_interface *>(this), 0, sizeof(serial_eeprom_interface)); } //------------------------------------------------- -// static_set_interface - configuration helper -// to set the interface +// static_set_default_data - configuration helpers +// to set the default data //------------------------------------------------- -void serial_eeprom_device::static_set_interface(device_t &device, const serial_eeprom_interface &interface) +void base_eeprom_device::static_set_size(device_t &device, int cells, int cellbits) { - serial_eeprom_device &eeprom = downcast<serial_eeprom_device &>(device); - static_cast<serial_eeprom_interface &>(eeprom) = interface; + base_eeprom_device &eeprom = downcast<base_eeprom_device &>(device); + eeprom.m_cells = cells; + eeprom.m_data_bits = cellbits; + + // compute address bits (validation checks verify cells was an even power of 2) + cells--; + eeprom.m_address_bits = 0; + while (cells != 0) + { + cells >>= 1; + eeprom.m_address_bits++; + } // describe our address space if (eeprom.m_data_bits == 8) @@ -137,18 +122,18 @@ void serial_eeprom_device::static_set_interface(device_t &device, const serial_e // to set the default data //------------------------------------------------- -void serial_eeprom_device::static_set_default_data(device_t &device, const UINT8 *data, UINT32 size) +void base_eeprom_device::static_set_default_data(device_t &device, const UINT8 *data, UINT32 size) { - serial_eeprom_device &eeprom = downcast<serial_eeprom_device &>(device); - assert(eeprom.m_data_bits == 8); + base_eeprom_device &eeprom = downcast<base_eeprom_device &>(device); + assert(eeprom.m_cellbits == 8); eeprom.m_default_data.u8 = const_cast<UINT8 *>(data); eeprom.m_default_data_size = size; } -void serial_eeprom_device::static_set_default_data(device_t &device, const UINT16 *data, UINT32 size) +void base_eeprom_device::static_set_default_data(device_t &device, const UINT16 *data, UINT32 size) { - serial_eeprom_device &eeprom = downcast<serial_eeprom_device &>(device); - assert(eeprom.m_data_bits == 16); + base_eeprom_device &eeprom = downcast<base_eeprom_device &>(device); + assert(eeprom.m_cellbits == 16); eeprom.m_default_data.u16 = const_cast<UINT16 *>(data); eeprom.m_default_data_size = size / 2; } @@ -159,9 +144,37 @@ void serial_eeprom_device::static_set_default_data(device_t &device, const UINT1 // to set the default value //------------------------------------------------- -void serial_eeprom_device::static_set_default_value(device_t &device, UINT16 value) +void base_eeprom_device::static_set_default_value(device_t &device, UINT32 value) +{ + base_eeprom_device &eeprom = downcast<base_eeprom_device &>(device); + eeprom.m_default_value = value; + eeprom.m_default_value_set = true; +} + + +//------------------------------------------------- +// read_data - read data at the given address +//------------------------------------------------- + +UINT32 base_eeprom_device::read_data(offs_t address) +{ + if (m_data_bits == 16) + return m_addrspace[0]->read_word(address * 2); + else + return m_addrspace[0]->read_byte(address); +} + + +//------------------------------------------------- +// write_data - write data at the given address +//------------------------------------------------- + +void base_eeprom_device::write_data(offs_t address, UINT32 data) { - downcast<serial_eeprom_device &>(device).m_default_value = 0x10000 | value; + if (m_data_bits == 16) + m_addrspace[0]->write_word(address * 2, data); + else + m_addrspace[0]->write_byte(address, data); } @@ -170,10 +183,15 @@ void serial_eeprom_device::static_set_default_value(device_t &device, UINT16 val // on this device //------------------------------------------------- -void serial_eeprom_device::device_validity_check(validity_checker &valid) const +void base_eeprom_device::device_validity_check(validity_checker &valid) const { + // ensure the number of cells is an even power of 2 + if (m_cells != (1 << m_address_bits)) + mame_printf_error("Invalid EEPROM size %d specified\n", m_cells); + + // ensure only the sizes we support are requested if (m_data_bits != 8 && m_data_bits != 16) - mame_printf_error("Invalid data width %d specified\n", m_data_bits); + mame_printf_error("Invalid EEPROM data width %d specified\n", m_data_bits); } @@ -181,20 +199,8 @@ void serial_eeprom_device::device_validity_check(validity_checker &valid) const // device_start - device-specific startup //------------------------------------------------- -void serial_eeprom_device::device_start() +void base_eeprom_device::device_start() { - m_locked = (m_cmd_unlock != NULL); - - save_pointer(NAME(m_serial_buffer), SERIAL_BUFFER_LENGTH); - save_item(NAME(m_clock_line)); - save_item(NAME(m_reset_line)); - save_item(NAME(m_locked)); - save_item(NAME(m_serial_count)); - save_item(NAME(m_latch)); - save_item(NAME(m_reset_counter)); - save_item(NAME(m_clock_count)); - save_item(NAME(m_data_buffer)); - save_item(NAME(m_read_address)); } @@ -202,7 +208,7 @@ void serial_eeprom_device::device_start() // device_reset - device-specific reset //------------------------------------------------- -void serial_eeprom_device::device_reset() +void base_eeprom_device::device_reset() { } @@ -212,7 +218,7 @@ void serial_eeprom_device::device_reset() // any address spaces owned by this device //------------------------------------------------- -const address_space_config *serial_eeprom_device::memory_space_config(address_spacenum spacenum) const +const address_space_config *base_eeprom_device::memory_space_config(address_spacenum spacenum) const { return (spacenum == 0) ? &m_space_config : NULL; } @@ -223,31 +229,30 @@ const address_space_config *serial_eeprom_device::memory_space_config(address_sp // its default state //------------------------------------------------- -void serial_eeprom_device::nvram_default() +void base_eeprom_device::nvram_default() { UINT32 eeprom_length = 1 << m_address_bits; UINT32 eeprom_bytes = eeprom_length * m_data_bits / 8; - /* initialize to the default value */ - UINT16 default_value = 0xffff; - if (m_default_value != 0) - default_value = m_default_value; + // initialize to the default value + UINT32 default_value = m_default_value_set ? m_default_value : ~0; for (offs_t offs = 0; offs < eeprom_length; offs++) if (m_data_bits == 8) m_addrspace[0]->write_byte(offs, default_value); else m_addrspace[0]->write_word(offs * 2, default_value); - /* handle hard-coded data from the driver */ + // handle hard-coded data from the driver if (m_default_data.u8 != NULL) - for (offs_t offs = 0; offs < m_default_data_size; offs++) { + for (offs_t offs = 0; offs < m_default_data_size; offs++) + { if (m_data_bits == 8) m_addrspace[0]->write_byte(offs, m_default_data.u8[offs]); else m_addrspace[0]->write_word(offs * 2, m_default_data.u16[offs]); } - /* populate from a memory region if present */ + // populate from a memory region if present if (m_region != NULL) { if (m_region->bytes() != eeprom_bytes) @@ -271,16 +276,15 @@ void serial_eeprom_device::nvram_default() // .nv file //------------------------------------------------- -void serial_eeprom_device::nvram_read(emu_file &file) +void base_eeprom_device::nvram_read(emu_file &file) { UINT32 eeprom_length = 1 << m_address_bits; UINT32 eeprom_bytes = eeprom_length * m_data_bits / 8; - UINT8 *buffer = auto_alloc_array(machine(), UINT8, eeprom_bytes); + dynamic_buffer buffer(eeprom_bytes); file.read(buffer, eeprom_bytes); for (offs_t offs = 0; offs < eeprom_bytes; offs++) m_addrspace[0]->write_byte(offs, buffer[offs]); - auto_free(machine(), buffer); } @@ -289,269 +293,13 @@ void serial_eeprom_device::nvram_read(emu_file &file) // .nv file //------------------------------------------------- -void serial_eeprom_device::nvram_write(emu_file &file) +void base_eeprom_device::nvram_write(emu_file &file) { UINT32 eeprom_length = 1 << m_address_bits; UINT32 eeprom_bytes = eeprom_length * m_data_bits / 8; - UINT8 *buffer = auto_alloc_array(machine(), UINT8, eeprom_bytes); + dynamic_buffer buffer(eeprom_bytes); for (offs_t offs = 0; offs < eeprom_bytes; offs++) buffer[offs] = m_addrspace[0]->read_byte(offs); file.write(buffer, eeprom_bytes); - auto_free(machine(), buffer); -} - - - -//************************************************************************** -// READ/WRITE HANDLERS -//************************************************************************** - -WRITE_LINE_MEMBER( serial_eeprom_device::write_bit ) -{ - LOG(("write bit %d\n",state)); - m_latch = state; -} - - -READ_LINE_DEVICE_HANDLER( eeprom_read_bit ) -{ - return downcast<serial_eeprom_device *>(device)->read_bit(); -} - -READ_LINE_MEMBER( serial_eeprom_device::read_bit ) -{ - int res; - - if (m_sending) - res = (m_data_buffer >> m_data_bits) & 1; - else - { - if (m_reset_counter > 0) - { - /* this is needed by wbeachvl */ - m_reset_counter--; - res = 0; - } - else - res = 1; - } - - LOG(("read bit %d\n",res)); - - return res; -} - - - -WRITE_LINE_MEMBER( serial_eeprom_device::set_cs_line ) -{ - LOG(("set reset line %d\n",state)); - m_reset_line = state; - - if (m_reset_line != CLEAR_LINE) - { - if (m_serial_count) - logerror("EEPROM %s reset, buffer = %s\n", tag(), m_serial_buffer); - - m_serial_count = 0; - m_sending = 0; - m_reset_counter = m_reset_delay; /* delay a little before returning setting data to 1 (needed by wbeachvl) */ - } -} - - - -WRITE_LINE_MEMBER( serial_eeprom_device::set_clock_line ) -{ - LOG(("set clock line %d\n",state)); - if (state == PULSE_LINE || (m_clock_line == CLEAR_LINE && state != CLEAR_LINE)) - { - if (m_reset_line == CLEAR_LINE) - { - if (m_sending) - { - if (m_clock_count == m_data_bits && m_enable_multi_read) - { - m_read_address = (m_read_address + 1) & ((1 << m_address_bits) - 1); - if (m_data_bits == 16) - m_data_buffer = m_addrspace[0]->read_word(m_read_address * 2); - else - m_data_buffer = m_addrspace[0]->read_byte(m_read_address); - m_clock_count = 0; - logerror("EEPROM %s read %04x from address %02x\n", tag(), m_data_buffer, m_read_address); - } - m_data_buffer = (m_data_buffer << 1) | 1; - m_clock_count++; - } - else - write(m_latch); - } - } - - m_clock_line = state; -} - - - -//************************************************************************** -// INTERNAL HELPERS -//************************************************************************** - -void serial_eeprom_device::write(int bit) -{ - LOG(("EEPROM %s write bit %d\n", tag(), bit)); - - if (m_serial_count >= SERIAL_BUFFER_LENGTH-1) - { - logerror("error: EEPROM %s serial buffer overflow\n", tag()); - return; - } - - m_serial_buffer[m_serial_count++] = (bit ? '1' : '0'); - m_serial_buffer[m_serial_count] = 0; /* nul terminate so we can treat it as a string */ - - if ( (m_serial_count > m_address_bits) && - command_match((char*)(m_serial_buffer),m_cmd_read,strlen((char*)(m_serial_buffer))-m_address_bits) ) - { - int i,address; - - address = 0; - for (i = m_serial_count-m_address_bits;i < m_serial_count;i++) - { - address <<= 1; - if (m_serial_buffer[i] == '1') address |= 1; - } - if (m_data_bits == 16) - m_data_buffer = m_addrspace[0]->read_word(address * 2); - else - m_data_buffer = m_addrspace[0]->read_byte(address); - m_read_address = address; - m_clock_count = 0; - m_sending = 1; - m_serial_count = 0; - logerror("EEPROM %s read %04x from address %02x\n", tag(), m_data_buffer,address); - } - else if ( (m_serial_count > m_address_bits) && - command_match((char*)(m_serial_buffer),m_cmd_erase,strlen((char*)(m_serial_buffer))-m_address_bits) ) - { - int i,address; - - address = 0; - for (i = m_serial_count-m_address_bits;i < m_serial_count;i++) - { - address <<= 1; - if (m_serial_buffer[i] == '1') address |= 1; - } - logerror("EEPROM %s erase address %02x\n", tag(), address); - if (m_locked == 0) - { - if (m_data_bits == 16) - m_addrspace[0]->write_word(address * 2, 0xFFFF); - else - m_addrspace[0]->write_byte(address, 0xFF); - } - else - logerror("Error: EEPROM %s is locked\n", tag()); - m_serial_count = 0; - } - else if ( (m_serial_count > (m_address_bits + m_data_bits)) && - command_match((char*)(m_serial_buffer),m_cmd_write,strlen((char*)(m_serial_buffer))-(m_address_bits + m_data_bits)) ) - { - int i,address,data; - - address = 0; - for (i = m_serial_count-m_data_bits-m_address_bits;i < (m_serial_count-m_data_bits);i++) - { - address <<= 1; - if (m_serial_buffer[i] == '1') address |= 1; - } - data = 0; - for (i = m_serial_count-m_data_bits;i < m_serial_count;i++) - { - data <<= 1; - if (m_serial_buffer[i] == '1') data |= 1; - } - logerror("EEPROM %s write %04x to address %02x\n", tag(), data, address); - if (m_locked == 0) - { - if (m_data_bits == 16) - m_addrspace[0]->write_word(address * 2, data); - else - m_addrspace[0]->write_byte(address, data); - } - else - logerror("Error: EEPROM %s is locked\n", tag()); - m_serial_count = 0; - } - else if ( command_match((char*)(m_serial_buffer),m_cmd_lock,strlen((char*)(m_serial_buffer))) ) - { - logerror("EEPROM %s lock\n", tag()); - m_locked = 1; - m_serial_count = 0; - } - else if ( command_match((char*)(m_serial_buffer),m_cmd_unlock,strlen((char*)(m_serial_buffer))) ) - { - logerror("EEPROM %s unlock\n", tag()); - m_locked = 0; - m_serial_count = 0; - } -} - - -/* - 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. -*/ -bool serial_eeprom_device::command_match(const char *buf, const char *cmd, int len) -{ - if ( cmd == 0 ) return false; - if ( len == 0 ) return false; - - 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 false; - 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 false; - } - } - } - return (*cmd==0); } |