// license:BSD-3-Clause // copyright-holders:Curt Coder /********************************************************************** National Semiconductor NMC9306 256-Bit Serial EEPROM emulation **********************************************************************/ #include "emu.h" #include "nmc9306.h" //#define VERBOSE 1 #include "logmacro.h" //************************************************************************** // MACROS / CONSTANTS //************************************************************************** #define RAM_SIZE 32 // instructions enum { OTHER = 0, WRITE, // write register A3A2A1A0 READ, // read register A3A2A1A0 ERASE // erase register A3A2A1A0 }; // other instructions enum { EWDS = 0, // erase/write disable WRAL, // write all registers ERAL, // erase all registers EWEN // erase/write enable }; // states enum { STATE_IDLE = 0, STATE_COMMAND, STATE_ADDRESS, STATE_DATA_IN, STATE_DATA_OUT, STATE_ERASE }; //************************************************************************** // INLINE HELPERS //************************************************************************** // device type definition DEFINE_DEVICE_TYPE(NMC9306, nmc9306_device, "nmc9306", "NMC9306 EEPROM") //------------------------------------------------- // nmc9306_device - constructor //------------------------------------------------- inline uint16_t nmc9306_device::read(offs_t offset) { return m_register[offset]; } //------------------------------------------------- // nmc9306_device - constructor //------------------------------------------------- inline void nmc9306_device::write(offs_t offset, uint16_t data) { if (m_ewen) { m_register[offset] &= data; } } //------------------------------------------------- // nmc9306_device - constructor //------------------------------------------------- inline void nmc9306_device::erase(offs_t offset) { if (m_ewen) { m_register[offset] = 0xffff; } } //************************************************************************** // LIVE DEVICE //************************************************************************** //------------------------------------------------- // nmc9306_device - constructor //------------------------------------------------- nmc9306_device::nmc9306_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, NMC9306, tag, owner, clock), device_nvram_interface(mconfig, *this), m_state(STATE_IDLE), m_ewen(false) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void nmc9306_device::device_start() { memset(m_register, 0, sizeof(m_register)); // state saving save_item(NAME(m_bits)); save_item(NAME(m_state)); save_item(NAME(m_command)); save_item(NAME(m_address)); save_item(NAME(m_data)); save_item(NAME(m_ewen)); save_item(NAME(m_cs)); save_item(NAME(m_sk)); save_item(NAME(m_do)); save_item(NAME(m_di)); } //------------------------------------------------- // nvram_default - called to initialize NVRAM to // its default state //------------------------------------------------- void nmc9306_device::nvram_default() { } //------------------------------------------------- // nvram_read - called to read NVRAM from the // .nv file //------------------------------------------------- void nmc9306_device::nvram_read(emu_file &file) { file.read(m_register, RAM_SIZE); } //------------------------------------------------- // nvram_write - called to write NVRAM to the // .nv file //------------------------------------------------- void nmc9306_device::nvram_write(emu_file &file) { file.write(m_register, RAM_SIZE); } //------------------------------------------------- // cs_w - chip select input //------------------------------------------------- WRITE_LINE_MEMBER( nmc9306_device::cs_w ) { m_cs = state; } //------------------------------------------------- // ck_w - serial clock input //------------------------------------------------- WRITE_LINE_MEMBER( nmc9306_device::sk_w ) { m_sk = state; if (!m_cs || !m_sk) return; switch (m_state) { case STATE_IDLE: LOG("NMC9306 Idle %u\n", m_di); if (m_di) { // start bit received m_state = STATE_COMMAND; m_bits = 0; } break; case STATE_COMMAND: LOG("NMC9306 Command Bit %u\n", m_di); m_command <<= 1; m_command |= m_di; m_bits++; if (m_bits == 4) { m_state = STATE_ADDRESS; m_bits = 0; } break; case STATE_ADDRESS: LOG("NMC9306 Address Bit %u\n", m_di); m_address <<= 1; m_address |= m_di; m_bits++; if (m_bits == 4) { switch ((m_command >> 2) & 0x03) { case OTHER: switch (m_command & 0x03) { case EWDS: LOG("NMC9306 EWDS\n"); m_ewen = false; m_state = STATE_IDLE; break; case WRAL: LOG("NMC9306 WRAL\n"); break; case ERAL: LOG("NMC9306 ERAL\n"); break; case EWEN: LOG("NMC9306 EWEN\n"); m_ewen = true; m_state = STATE_IDLE; break; } break; case WRITE: LOG("NMC9306 WRITE %u\n", m_address & 0x0f); m_state = STATE_DATA_IN; break; case READ: LOG("NMC9306 READ %u\n", m_address & 0x0f); m_data = read(m_address & 0x0f); m_state = STATE_DATA_OUT; break; case ERASE: LOG("NMC9306 ERASE %u\n", m_address & 0x0f); erase(m_address & 0x0f); m_state = STATE_ERASE; break; } m_bits = 0; } break; case STATE_DATA_IN: LOG("NMC9306 Data Bit IN %u\n", m_di); m_data <<= 1; m_data |= m_di; m_bits++; if (m_bits == 16) { write(m_address & 0x0f, m_data); m_state = STATE_IDLE; } break; case STATE_DATA_OUT: LOG("NMC9306 Data Bit OUT %u\n", m_di); m_do = BIT(m_data, 15); m_data <<= 1; m_bits++; if (m_bits == 16) { m_state = STATE_IDLE; } break; } } //------------------------------------------------- // di_w - serial data input //------------------------------------------------- WRITE_LINE_MEMBER( nmc9306_device::di_w ) { m_di = state; } //------------------------------------------------- // do_r - serial data output //------------------------------------------------- READ_LINE_MEMBER( nmc9306_device::do_r ) { return m_do; }