From f87cc5c6714ffe8e06ecf199f669e4dbcf4fffc0 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Thu, 16 Nov 2017 19:53:02 +0700 Subject: 28fxxx: initial commit for new flash memory device (#2805) Implementation of 28F010 and family flash memory devices. These are not compatible with the JEDEC-standard flash command protocol implemented in intelfsh. --- scripts/src/machine.lua | 12 +++ scripts/target/mame/mess.lua | 1 + src/devices/machine/28fxxx.cpp | 236 +++++++++++++++++++++++++++++++++++++++++ src/devices/machine/28fxxx.h | 84 +++++++++++++++ 4 files changed, 333 insertions(+) create mode 100644 src/devices/machine/28fxxx.cpp create mode 100644 src/devices/machine/28fxxx.h diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index cedd7a02e55..085d59d01c6 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -3301,3 +3301,15 @@ if (MACHINES["ADC0844"]~=null) then MAME_DIR .. "src/devices/machine/adc0844.h", } end + +--------------------------------------------------- +-- +--@src/devices/machine/28fxxx.h,MACHINES["28FXXX"] = true +--------------------------------------------------- + +if (MACHINES["28FXXX"]~=null) then + files { + MAME_DIR .. "src/devices/machine/28fxxx.cpp", + MAME_DIR .. "src/devices/machine/28fxxx.h", + } +end diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 6e7df8aa1cd..1f35d3bb525 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -619,6 +619,7 @@ MACHINES["I82586"] = true MACHINES["INPUT_MERGER"] = true -- MACHINES["K054321"] = true MACHINES["ADC0844"] = true +MACHINES["28FXXX"] = true -------------------------------------------------- -- specify available bus cores diff --git a/src/devices/machine/28fxxx.cpp b/src/devices/machine/28fxxx.cpp new file mode 100644 index 00000000000..9ef279dcd44 --- /dev/null +++ b/src/devices/machine/28fxxx.cpp @@ -0,0 +1,236 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * An implementation of the 28Fxxx flash memory devices, fabricated by many + * suppliers including Intel, Atmel, AMD, SGS, TI and Toshiba. Range includes: + * + * Part Bits Org. + * ------ ----- ------ + * 28F256 256K 32Kx8 + * 28F512 512K 64Kx8 + * 28F010 1024K 128Kx8 + * 28F020 2048K 256Kx8 + * 28F040 4096K 512Kx8 + * + * These devices use a JEDEC-standard pinout allowing them to be fitted to a + * standard EPROM socket, but have their own command set which is not + * compatible with the set implemented by the intelfsh devices. It appears the + * command set used here is a variation on the one defined by JEDEC standard + * 21-C, as "dual power supply eeprom command set", in figure 3.5.1-11 on page + * 23, here: https://www.jedec.org/system/files/docs/3_05_01R14.pdf + * + * This implementation has been developed primarily against Intel's datasheet, + * with some minor adjustments to match details in the AMD equivalent. + * + * TODO + * - implement more variants + * - testing in systems other than InterPro + * + */ + +#include "emu.h" +#include "28fxxx.h" + +#define VERBOSE 0 +#include "logmacro.h" + +// manufacturer codes defined by JEDEC: https://www.jedec.org/system/files/docs/JEP106AV.pdf +enum manufacturer_codes +{ + MFG_AMD = 0x01, + MFG_INTEL = 0x89, +}; + +DEFINE_DEVICE_TYPE(INTEL_28F010, intel_28f010_device, "intel_28f010", "Intel 28F010 1024K (128K x 8) CMOS Flash Memory") +DEFINE_DEVICE_TYPE(AMD_28F010, amd_28f010_device, "amd_28f010", "Am28F010 1 Megabit (128K x 8-Bit) CMOS 12.0 Volt, Bulk Erase Flash Memory") + +ALLOW_SAVE_TYPE(base_28fxxx_device::state); + +base_28fxxx_device::base_28fxxx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 size, u8 manufacturer_code, u8 device_code) + : device_t(mconfig, type, tag, owner, clock) + , device_nvram_interface(mconfig, *this) + , m_region(*this, DEVICE_SELF) + , m_size(size) + , m_manufacturer_code(manufacturer_code) + , m_device_code(device_code) + , m_program_power(CLEAR_LINE) + , m_state(STATE_READ_MEMORY) +{ + assert_always((m_size & (m_size - 1)) == 0, "memory size must be an exact power of two"); +} + +intel_28f010_device::intel_28f010_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : base_28fxxx_device(mconfig, INTEL_28F010, tag, owner, clock, 0x20000, MFG_INTEL, 0xb4) +{ +} + +amd_28f010_device::amd_28f010_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : base_28fxxx_device(mconfig, AMD_28F010, tag, owner, clock, 0x20000, MFG_AMD, 0xa7) +{ +} + +void base_28fxxx_device::device_start() +{ + m_data = std::make_unique(m_size); + + save_item(NAME(m_program_power)); + save_pointer(NAME(m_data.get()), m_size); + + save_item(NAME(m_state)); + save_item(NAME(m_address_latch)); +} + +void base_28fxxx_device::nvram_default() +{ + if (m_region.found()) + { + u32 bytes = m_region->bytes(); + if (bytes > m_size) + bytes = m_size; + + for (offs_t offs = 0; offs < bytes; offs++) + m_data[offs] = m_region->as_u8(offs); + } + else + erase(); +} + +void base_28fxxx_device::nvram_read(emu_file &file) +{ + file.read(m_data.get(), m_size); +} + +void base_28fxxx_device::nvram_write(emu_file &file) +{ + file.write(m_data.get(), m_size); +} + +void base_28fxxx_device::erase() +{ + memset(m_data.get(), 0xff, m_size); +} + +READ8_MEMBER(base_28fxxx_device::read) +{ + switch (m_state) + { + case STATE_READ_MEMORY: + return m_data.get()[offset & (m_size - 1)]; + + case STATE_READ_IDENTIFIER: + switch (offset) + { + case 0: return m_manufacturer_code; + case 1: return m_device_code; + } + LOG("unknown read identifier offset 0x%08x (%s)\n", offset, machine().describe_context()); + return space.unmap(); + + case STATE_ERASE_VERIFY: + return m_data.get()[m_address_latch]; + + case STATE_PROGRAM_VERIFY: + return m_data.get()[m_address_latch]; + + default: + LOG("unexpected read offset 0x%08x mask 0x%08x state %d (%s)\n", offset, mem_mask, m_state, machine().describe_context()); + return space.unmap(); + } +} + +WRITE8_MEMBER(base_28fxxx_device::write) +{ + // writes are ignored unless Vpp is asserted + if (!m_program_power) + return; + + switch (m_state) + { + case STATE_ERASE_SETUP: + if (data == ERASE) + { + LOG("erase command initiated (%s)\n", machine().describe_context()); + erase(); + m_state = STATE_ERASE; + } + else if (data == RESET) + { + LOG("erase command reset (%s)\n", machine().describe_context()); + m_state = STATE_READ_MEMORY; + } + else + LOG("unexpected command 0x%02x in erase setup state (%s)\n", data, machine().describe_context()); + break; + + case STATE_ERASE: + if (data == ERASE_VERIFY) + { + m_address_latch = offset & (m_size - 1); + m_state = STATE_ERASE_VERIFY; + } + else + LOG("unexpected command 0x%02x in erase state (%s)\n", data, machine().describe_context()); + break; + + case STATE_PROGRAM_SETUP: + m_address_latch = offset & (m_size - 1); + + LOG("programming address 0x%08x data 0x%02x\n", m_address_latch, data); + + // bits can only be written from uncharged (logical 1) to charged (logical 0) state + m_data.get()[m_address_latch] &= data; + + m_state = STATE_PROGRAM; + break; + + case STATE_PROGRAM: + if (data == PROGRAM_VERIFY) + m_state = STATE_PROGRAM_VERIFY; + else if (data == RESET) + { + LOG("program command reset (%s)\n", machine().describe_context()); + + m_state = STATE_READ_MEMORY; + } + else + LOG("unexpected command 0x%02x in program state (%s)\n", data, machine().describe_context()); + break; + + default: + // start a new command + switch (data) + { + case READ_MEMORY: + m_state = STATE_READ_MEMORY; + break; + + case READ_IDENTIFIER: + case READ_IDENTIFIER_ALT: + m_state = STATE_READ_IDENTIFIER; + break; + + case ERASE: + m_state = STATE_ERASE_SETUP; + break; + + case ERASE_VERIFY: + m_address_latch = offset & (m_size - 1); + m_state = STATE_ERASE_VERIFY; + break; + + case PROGRAM: + m_state = STATE_PROGRAM_SETUP; + break; + + case RESET: + m_state = STATE_READ_MEMORY; + break; + + default: + LOG("unexpected command 0x%02x in state %d (%s)\n", data, m_state, machine().describe_context()); + break; + } + break; + } +} diff --git a/src/devices/machine/28fxxx.h b/src/devices/machine/28fxxx.h new file mode 100644 index 00000000000..313cda82873 --- /dev/null +++ b/src/devices/machine/28fxxx.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_MACHINE_28FXXX_H +#define MAME_MACHINE_28FXXX_H + +#pragma once + +class base_28fxxx_device : public device_t, public device_nvram_interface +{ +public: + enum commands + { + READ_MEMORY = 0x00, + ERASE = 0x20, + PROGRAM = 0x40, + READ_IDENTIFIER_ALT = 0x80, // defined in AMD datasheet, but not Intel + READ_IDENTIFIER = 0x90, + ERASE_VERIFY = 0xa0, + PROGRAM_VERIFY = 0xc0, + RESET = 0xff + }; + + DECLARE_WRITE_LINE_MEMBER(vpp) { m_program_power = state; } + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + +protected: + base_28fxxx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 size, u8 manufacturer_code, u8 device_code); + + virtual void device_start() override; + + virtual void nvram_default() override; + virtual void nvram_read(emu_file &file) override; + virtual void nvram_write(emu_file &file) override; + + optional_memory_region m_region; + +private: + void erase(); + + // device specific parameters + const u32 m_size; + const u8 m_manufacturer_code; + const u8 m_device_code; + + // accessible device state + int m_program_power; + std::unique_ptr m_data; + + // internal state + enum state : u8 + { + STATE_READ_MEMORY, + STATE_READ_IDENTIFIER, + STATE_ERASE_SETUP, + STATE_ERASE, + STATE_ERASE_RESET, + STATE_ERASE_VERIFY, + STATE_PROGRAM_SETUP, + STATE_PROGRAM, + STATE_PROGRAM_VERIFY + }; + state m_state; + + u32 m_address_latch; +}; + +class intel_28f010_device : public base_28fxxx_device +{ +public: + intel_28f010_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +class amd_28f010_device : public base_28fxxx_device +{ +public: + amd_28f010_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +DECLARE_DEVICE_TYPE(INTEL_28F010, intel_28f010_device) +DECLARE_DEVICE_TYPE(AMD_28F010, amd_28f010_device) + +#endif // MAME_MACHINE_28FXXX_H -- cgit v1.2.3