summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/m950x0.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/m950x0.cpp')
-rw-r--r--src/devices/machine/m950x0.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/devices/machine/m950x0.cpp b/src/devices/machine/m950x0.cpp
new file mode 100644
index 00000000000..9d42166804c
--- /dev/null
+++ b/src/devices/machine/m950x0.cpp
@@ -0,0 +1,207 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/***************************************************************************
+
+ m950x0.cpp
+
+ STmicro M95010/20/40 SPI-bus EEPROM
+
+ Common characteristics:
+ - 16-byte page size
+ - Write protection selectable in quarter, half, or full sizes
+
+ Part variants with a -DF designation have additional support for an
+ identification page, which is not currently emulated.
+
+ Sizes:
+ M95010 - 1kbit
+ M95020 - 2kbit
+ M95040 - 4kbit, slightly altered instructions for 9th address bit
+
+ Current issues:
+ - Implementation currently operates in a parallel manner, rather than
+ serial.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "m950x0.h"
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(M95010, m95010_device, "m95010", "STmicro M95010 1kbit SPI EEPROM")
+DEFINE_DEVICE_TYPE(M95020, m95020_device, "m95020", "STmicro M95020 2kbit SPI EEPROM")
+DEFINE_DEVICE_TYPE(M95040, m95040_device, "m95040", "STmicro M95040 4kbit SPI EEPROM")
+
+m950x0_device::m950x0_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, int capacity)
+ : eeprom_base_device(mconfig, type, tag, owner)
+ , m_check_a8(capacity > 0x100)
+ , m_addr_mask((uint16_t)capacity - 1)
+ , m_state(STATE_IDLE)
+{
+ size(capacity, 8);
+}
+
+m95010_device::m95010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : m950x0_device(mconfig, M95010, tag, owner, 0x80)
+{
+}
+
+m95020_device::m95020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : m950x0_device(mconfig, M95020, tag, owner, 0x100)
+{
+}
+
+m95040_device::m95040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : m950x0_device(mconfig, M95040, tag, owner, 0x200)
+{
+}
+
+void m950x0_device::device_start()
+{
+ eeprom_base_device::device_start();
+
+ save_item(NAME(m_state));
+ save_item(NAME(m_selected));
+ save_item(NAME(m_status));
+ save_item(NAME(m_addr));
+}
+
+void m950x0_device::device_reset()
+{
+ eeprom_base_device::device_reset();
+
+ m_state = STATE_IDLE;
+ m_selected = false;
+ m_status = 0xf0;
+ m_addr = 0;
+}
+
+uint8_t m950x0_device::access(uint8_t data)
+{
+ if (!m_selected)
+ return 0;
+
+ uint8_t response = 0;
+
+ switch (m_state)
+ {
+ case STATE_IDLE:
+ process_instruction(data);
+ break;
+
+ case STATE_RDSR:
+ response = m_status;
+ m_state = STATE_IDLE;
+ LOG("Status Register read, value: %02x\n", response);
+ break;
+
+ case STATE_WRSR:
+ m_status &= 0xf0;
+ m_status |= data & 0x0f;
+ m_state = STATE_IDLE;
+ LOG("Status Register write, new value: %02x\n", m_status);
+ break;
+
+ case STATE_READ_ADDR:
+ m_addr |= data;
+ m_state = STATE_READ_DATA;
+ LOG("Read command, starting address: %03x, entering read-data state\n", m_addr);
+ break;
+
+ case STATE_WRITE_ADDR:
+ m_addr |= data;
+ m_state = STATE_WRITE_DATA;
+ LOG("Write command, starting address: %03x, entering write-data state\n", m_addr);
+ break;
+
+ case STATE_READ_DATA:
+ response = (uint8_t)internal_read(m_addr);
+ LOG("Read command, data: %02x, at address %03x\n", response, m_addr);
+ m_addr++;
+ m_addr &= m_addr_mask;
+ break;
+
+ case STATE_WRITE_DATA:
+ internal_write(m_addr, data);
+ LOG("Write command, data: %02x to address %03x\n", data, m_addr);
+ m_addr++;
+ m_addr &= m_addr_mask;
+ break;
+ }
+
+ return response;
+}
+
+void m950x0_device::process_instruction(const uint8_t insn)
+{
+ switch (insn)
+ {
+ case INSN_WREN0:
+ case INSN_WREN1:
+ LOG("Instruction: Write enable\n");
+ m_status |= (1 << STATUS_WEL_BIT);
+ break;
+
+ case INSN_WRDI0:
+ case INSN_WRDI1:
+ LOG("Instruction: Write disable\n");
+ m_status &= ~(1 << STATUS_WEL_BIT);
+ break;
+
+ case INSN_RDSR0:
+ case INSN_RDSR1:
+ LOG("Instruction: Read status register\n");
+ m_state = STATE_RDSR;
+ break;
+
+ case INSN_WRSR0:
+ case INSN_WRSR1:
+ LOG("Instruction: Write status register\n");
+ m_state = STATE_WRSR;
+ break;
+
+ case INSN_READ0:
+ LOG("Instruction: Read, A8=0\n");
+ m_state = STATE_READ_ADDR;
+ break;
+ case INSN_READ1:
+ LOG("Instruction: Read, A8=1\n");
+ m_state = STATE_READ_ADDR;
+ if (m_check_a8)
+ m_addr |= 0x100;
+ break;
+
+ case INSN_WRITE0:
+ LOG("Instruction: Write, A8=0\n");
+ m_state = STATE_WRITE_ADDR;
+ break;
+ case INSN_WRITE1:
+ LOG("Instruction: Write, A8=1\n");
+ m_state = STATE_WRITE_ADDR;
+ if (m_check_a8)
+ m_addr |= 0x100;
+ break;
+
+ default:
+ LOG("Unrecognized instruction byte: %02x, deselecting\n", insn);
+ m_selected = false;
+ break;
+ }
+}
+
+void m950x0_device::select_w(int selected)
+{
+ if (m_selected == (bool)selected)
+ return;
+
+ m_selected = (bool)selected;
+
+ if (!selected)
+ {
+ LOG("Deselected, resetting address to 0 and entering idle state.\n");
+ m_state = STATE_IDLE;
+ m_addr = 0;
+ }
+}