// license:BSD-3-Clause // copyright-holders:Tomasz Slanina #include "emu.h" #include "sda2006.h" //------------------------------------------------- // // Siemens SDA2006 512-bit (32x16) NV EEPROM // // TODO: // - 8/12 bit controll word selection (currently emulates only 8 bt one) // - INV pin // - better( and correct) state flow // - read mode, with reversed data stream // //------------------------------------------------- enum { CMD_WRITE, CMD_READ_REVERSED, CMD_READ, CMD_UNKNOWN }; #define EEPROM_CAPACITY 0x40 #define EEPROM_ADDRESS_MASK 0x1f // device type definition DEFINE_DEVICE_TYPE(SDA2006, sda2006_device, "sda2006", "SDA2006 EEPROM") //------------------------------------------------- // sda2006_device - constructor //------------------------------------------------- sda2006_device::sda2006_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, SDA2006, tag, owner, clock) , device_nvram_interface(mconfig, *this) , m_latch(0) , m_current_address(0) , m_eeprom_state() , m_read_stream_pos(0) , m_is_end_o_stream(false) , m_write_stream_length(0) , m_write_stream(0) , m_write_state(0) , m_clock_state(0) , m_region(*this, DEVICE_SELF) { } //------------------------------------------------- // device_validity_check - perform validity checks // on this device //------------------------------------------------- void sda2006_device::device_validity_check(validity_checker &valid) const { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void sda2006_device::device_start() { save_item(NAME(m_latch)); save_item(NAME(m_current_address)); save_item(NAME(m_eeprom_state)); save_item(NAME(m_read_stream_pos)); save_item(NAME(m_is_end_o_stream)); save_item(NAME(m_write_stream_length)); save_item(NAME(m_write_stream)); save_item(NAME(m_write_state)); save_item(NAME(m_clock_state)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void sda2006_device::device_reset() { m_current_address = 0; m_is_end_o_stream = false; m_write_stream_length = 0; m_write_stream = 0; m_write_state = 0; m_read_stream_pos = 0; m_eeprom_state = EEPROM_WRITE; m_clock_state = 0; } //------------------------------------------------- // nvram_default - called to initialize NVRAM to // its default state //------------------------------------------------- void sda2006_device::nvram_default() { // region always wins if (m_region.found()) { memcpy(m_eeprom_data, m_region->base(), EEPROM_CAPACITY); return; } for (auto & elem : m_eeprom_data) elem = 0xffff; } //------------------------------------------------- // nvram_read - called to read NVRAM from the // .nv file //------------------------------------------------- bool sda2006_device::nvram_read(util::read_stream &file) { auto const [err, actual] = read(file, m_eeprom_data, EEPROM_CAPACITY); return !err && (actual == EEPROM_CAPACITY); } //------------------------------------------------- // nvram_write - called to write NVRAM to the // .nv file //------------------------------------------------- bool sda2006_device::nvram_write(util::write_stream &file) { auto const [err, actual] = write(file, m_eeprom_data, EEPROM_CAPACITY); return !err; } int sda2006_device::read_data() { return m_latch^1; } void sda2006_device::write_data(int state) { m_latch = state; } void sda2006_device::write_enable(int state) { if( (m_write_state ^ state) && (!state)){ //falling edge m_is_end_o_stream = true; } m_write_state = state; } void sda2006_device::write_clock(int state) { if( (m_clock_state ^ state) && (!state)) { // falling edge if( m_eeprom_state == EEPROM_READ){ m_latch = (m_eeprom_data[m_current_address]>>(m_read_stream_pos))&1; ++m_read_stream_pos; if ( m_read_stream_pos == 16) { // end of read m_eeprom_state = EEPROM_WRITE; m_write_stream_length = 0; m_write_stream = 0; } } else { if( m_is_end_o_stream ){ // stream data = AAAAACCC (read) or DDDDDDDDDDDDDDDDAAAAACCC (write) uint32_t reversed_stream = 0; uint32_t mask = 1; uint32_t counter = m_write_stream_length; m_is_end_o_stream = false; m_write_stream_length = 0; while(counter>0){ reversed_stream<<=1; if (m_write_stream & mask) { reversed_stream |= 1; } mask <<= 1; --counter; } uint32_t command = bitswap<8>(m_write_stream, 7,6,5,4,3,0,1,2); switch (command&3){ case CMD_WRITE: m_eeprom_data[(reversed_stream>>16) & EEPROM_ADDRESS_MASK] = reversed_stream & 0xffff; break; case CMD_READ: m_current_address = reversed_stream & EEPROM_ADDRESS_MASK; m_read_stream_pos = 0; m_eeprom_state = EEPROM_READ; break; case CMD_READ_REVERSED: case CMD_UNKNOWN: break; } } else { if( m_write_state ) { m_write_stream = ( m_write_stream << 1 ) | m_latch; ++m_write_stream_length; } } } } m_clock_state = state; }