summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/generic_spi_flash.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/generic_spi_flash.cpp')
-rw-r--r--src/devices/machine/generic_spi_flash.cpp199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/devices/machine/generic_spi_flash.cpp b/src/devices/machine/generic_spi_flash.cpp
new file mode 100644
index 00000000000..7421004bf2e
--- /dev/null
+++ b/src/devices/machine/generic_spi_flash.cpp
@@ -0,0 +1,199 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+#include "emu.h"
+#include "generic_spi_flash.h"
+
+#define LOG_SPI (1U << 1)
+
+#define VERBOSE (0)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(GENERIC_SPI_FLASH, generic_spi_flash_device, "generic_spi_flash", "Generic SPI Flash handling")
+
+generic_spi_flash_device::generic_spi_flash_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, GENERIC_SPI_FLASH, tag, owner, clock)
+ , device_nvram_interface(mconfig, *this)
+{
+}
+
+void generic_spi_flash_device::device_start()
+{
+ save_item(NAME(m_spiaddr));
+ save_item(NAME(m_spi_state));
+ save_item(NAME(m_spilatch));
+ save_item(NAME(m_spidir));
+}
+
+void generic_spi_flash_device::device_reset()
+{
+ m_spiaddr = 0;
+ m_spi_state = 0;
+ m_spilatch = 0;
+ m_spidir = false;
+}
+
+void generic_spi_flash_device::write(uint8_t data)
+{
+ if (!m_spidir) // Send to SPI
+ {
+ switch (m_spi_state)
+ {
+ case READY_FOR_COMMAND:
+ if (data == 0x03)
+ {
+ m_spi_state = READY_FOR_ADDRESS2;
+ }
+ else if (data == 0x05)
+ {
+ m_spi_state = READY_FOR_STATUS_READ;
+ }
+ else if (data == 0x0b)
+ {
+ m_spi_state = READY_FOR_HSADDRESS2;
+ }
+ else if (data == 0x06)
+ {
+ // write enable
+ m_spi_state = READY_FOR_COMMAND;
+ }
+ else if (data == 0x04)
+ {
+ // write disable
+ m_spi_state = READY_FOR_COMMAND;
+ }
+ else if (data == 0x02)
+ {
+ // page program
+ m_spi_state = READY_FOR_WRITEADDRESS2;
+ }
+ else if (data == 0x20)
+ {
+ // erase 4k sector
+ m_spi_state = READY_FOR_COMMAND;
+ }
+ else
+ {
+ fatalerror("SPI set to unknown mode %02x\n", data);
+ }
+ break;
+
+ case READY_FOR_WRITEADDRESS2:
+ m_spiaddr = (m_spiaddr & 0x00ffff) | (data << 16);
+ m_spi_state = READY_FOR_WRITEADDRESS1;
+ break;
+
+ case READY_FOR_WRITEADDRESS1:
+ m_spiaddr = (m_spiaddr & 0xff00ff) | (data << 8);
+ m_spi_state = READY_FOR_WRITEADDRESS0;
+ break;
+
+ case READY_FOR_WRITEADDRESS0:
+ m_spiaddr = (m_spiaddr & 0xffff00) | (data);
+ m_spi_state = READY_FOR_WRITE;
+ LOGMASKED(LOG_SPI, "SPI set to page WRITE mode with address %08x\n", m_spiaddr);
+ break;
+
+ case READY_FOR_WRITE:
+ LOGMASKED(LOG_SPI, "Write SPI data %02x\n", data);
+
+ m_spiptr[(m_spiaddr++) & (m_length-1)] = data;
+
+ break;
+
+
+ case READY_FOR_ADDRESS2:
+ m_spiaddr = (m_spiaddr & 0x00ffff) | (data << 16);
+ m_spi_state = READY_FOR_ADDRESS1;
+ break;
+
+ case READY_FOR_ADDRESS1:
+ m_spiaddr = (m_spiaddr & 0xff00ff) | (data << 8);
+ m_spi_state = READY_FOR_ADDRESS0;
+ break;
+
+ case READY_FOR_ADDRESS0:
+ m_spiaddr = (m_spiaddr & 0xffff00) | (data);
+ m_spi_state = READY_FOR_READ;
+ m_spidir = 1;
+ LOGMASKED(LOG_SPI, "SPI set to READ mode with address %08x\n", m_spiaddr);
+ break;
+
+ case READY_FOR_HSADDRESS2:
+ m_spiaddr = (m_spiaddr & 0x00ffff) | (data << 16);
+ m_spi_state = READY_FOR_HSADDRESS1;
+ break;
+
+ case READY_FOR_HSADDRESS1:
+ m_spiaddr = (m_spiaddr & 0xff00ff) | (data << 8);
+ m_spi_state = READY_FOR_HSADDRESS0;
+ break;
+
+ case READY_FOR_HSADDRESS0:
+ m_spiaddr = (m_spiaddr & 0xffff00) | (data);
+ m_spi_state = READY_FOR_HSDUMMY;
+ break;
+
+ case READY_FOR_HSDUMMY:
+ m_spi_state = READY_FOR_READ;
+ m_spidir = 1;
+ LOGMASKED(LOG_SPI, "SPI set to High Speed READ mode with address %08x\n", m_spiaddr);
+ break;
+
+ case READY_FOR_SECTORERASEADDRESS2:
+ m_spiaddr = (m_spiaddr & 0x00ffff) | (data << 16);
+ m_spi_state = READY_FOR_SECTORERASEADDRESS1;
+ break;
+
+ case READY_FOR_SECTORERASEADDRESS1:
+ m_spiaddr = (m_spiaddr & 0xff00ff) | (data << 8);
+ m_spi_state = READY_FOR_SECTORERASEADDRESS0;
+ break;
+
+ case READY_FOR_SECTORERASEADDRESS0:
+ m_spiaddr = (m_spiaddr & 0xffff00) | (data);
+ LOGMASKED(LOG_SPI, "SPI set to Erase Sector with address %08x\n", m_spiaddr);
+ break;
+
+ }
+ }
+ else
+ {
+ if (m_spi_state == READY_FOR_READ)
+ {
+ m_spilatch = m_spiptr[(m_spiaddr++) & (m_length-1)];
+ }
+ else if (m_spi_state == READY_FOR_STATUS_READ)
+ {
+ m_spilatch = 0x00;
+ }
+ else
+ {
+ m_spilatch = 0x00;
+ }
+ }
+}
+
+
+
+void generic_spi_flash_device::nvram_default()
+{
+}
+
+bool generic_spi_flash_device::nvram_read(util::read_stream &file)
+{
+ if (m_spiptr == nullptr)
+ {
+ return false;
+ }
+
+ auto const [err, actual] = util::read(file, m_spiptr, m_length);
+ return !err && (actual == m_length);
+}
+
+bool generic_spi_flash_device::nvram_write(util::write_stream &file)
+{
+ auto const [err, actual] = util::write(file, m_spiptr, m_length);
+ return !err;
+}
+