diff options
Diffstat (limited to 'src/devices/bus/intellec4/insdatastor.cpp')
-rw-r--r-- | src/devices/bus/intellec4/insdatastor.cpp | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/src/devices/bus/intellec4/insdatastor.cpp b/src/devices/bus/intellec4/insdatastor.cpp new file mode 100644 index 00000000000..a4114425844 --- /dev/null +++ b/src/devices/bus/intellec4/insdatastor.cpp @@ -0,0 +1,191 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb + +#include "emu.h" +#include "insdatastor.h" + + +DEFINE_DEVICE_TYPE_NS(INTELLEC4_INST_DATA_STORAGE, bus::intellec4, imm4_22_device, "intlc4_imm4_22", "Intel imm4-22 Instruction/Data Storage Module") + + +namespace bus { namespace intellec4 { + +namespace { + +INPUT_PORTS_START(imm4_22) + PORT_START("JUMPERS") + PORT_CONFNAME( 0x03, 0x01, "4002 RAM page" ) + PORT_CONFSETTING( 0x01, "1" ) + PORT_CONFSETTING( 0x02, "2" ) + PORT_CONFSETTING( 0x03, "3" ) + PORT_CONFNAME( 0x0c, 0x04, "PROM/GPIO page" ) + PORT_CONFSETTING( 0x04, "0x400-0x7FF" ) + PORT_CONFSETTING( 0x08, "0x800-0xBFF" ) + PORT_CONFSETTING( 0x0c, "0xC00-0xFFF" ) + PORT_CONFNAME( 0x10, 0x00, "PROM/GPIO mode" ) + PORT_CONFSETTING( 0x00, "All" ) + PORT_CONFSETTING( 0x10, "MON only" ) +INPUT_PORTS_END + +} // anonymous namespace + + +imm4_22_device::imm4_22_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, INTELLEC4_INST_DATA_STORAGE, tag, owner, clock) + , device_univ_card_interface(mconfig, *this) + , device_image_interface(mconfig, *this) + , m_jumpers(*this, "JUMPERS") + , m_ram_io_mapped(false) + , m_ram_page(0U), m_rom_page(0U), m_rom_mirror(false) + , m_prom() +{ + std::fill(std::begin(m_memory), std::end(m_memory), 0U); + std::fill(std::begin(m_status), std::end(m_status), 0U); +} + + +image_init_result imm4_22_device::call_load() +{ + if ((length() > 1024U) || (length() % 256U)) + return image_init_result::FAIL; + + allocate(); + if (fread(m_prom.get(), length()) != length()) + return image_init_result::FAIL; + + map_prom(); + + return image_init_result::PASS; +} + +void imm4_22_device::call_unload() +{ + unmap_prom(); +} + + +ioport_constructor imm4_22_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(imm4_22); +} + +void imm4_22_device::device_start() +{ + m_ram_io_mapped = false; + + allocate(); + + save_item(NAME(m_ram_page)); + save_item(NAME(m_rom_page)); + save_item(NAME(m_rom_mirror)); + save_item(NAME(m_memory)); + save_item(NAME(m_status)); + save_pointer(NAME(m_prom.get()), 1024U); +} + +void imm4_22_device::device_reset() +{ + map_ram_io(); +} + + +WRITE_LINE_MEMBER(imm4_22_device::reset_4002_in) +{ + // FIXME: this takes several cycles to actually erase everything, and prevents writes while asserted + if (!state) + { + std::fill(std::begin(m_memory), std::end(m_memory), 0U); + std::fill(std::begin(m_status), std::end(m_status), 0U); + } +} + + +WRITE8_MEMBER(imm4_22_device::ram_out) +{ + // GPIO write - hooking this up would be a pain with MAME as it is + logerror("4002 A%u out %X\n", 13U + (offset & 0x03U), data & 0x0fU); +} + +WRITE8_MEMBER(imm4_22_device::rom_out) +{ + // GPIO write - hooking this up would be a pain with MAME as it is + logerror("ROM %u out %X\n", (m_rom_page << 2) | ((offset >> 4) & 0x03U), data & 0x0fU); +} + +READ8_MEMBER(imm4_22_device::rom_in) +{ + // GPIO read - hooking this up would be a pain with MAME as it is + if (!machine().side_effect_disabled()) + logerror("ROM %u in\n", (m_rom_page << 2) | ((offset >> 4) & 0x03U)); + return 0x0fU; +} + + +void imm4_22_device::allocate() +{ + if (!m_prom) + { + m_prom = std::make_unique<u8 []>(1024U); + std::fill(m_prom.get(), m_prom.get() + 1024U, 0U); + } +} + +void imm4_22_device::map_ram_io() +{ + if (!m_ram_io_mapped) + { + static constexpr offs_t ram_start[3][4] = { + { 0x01U, 0x04U, 0x05U, 0x07U }, + { 0x02U, 0x04U, 0x06U, 0x07U }, + { 0x03U, 0x05U, 0x06U, 0x07U } }; + + m_ram_io_mapped = true; + + ioport_value const jumpers(m_jumpers->read()); + m_ram_page = jumpers & 0x03U; + m_rom_page = (jumpers >> 2) & 0x03U; + m_rom_mirror = BIT(~jumpers, 4); + + if ((1U > m_ram_page) || (3U < m_ram_page)) + throw emu_fatalerror("imm4_22_device: invalid RAM page %u", m_ram_page); + if ((1U > m_rom_page) || (3U < m_rom_page)) + throw emu_fatalerror("imm4_22_device: invalid PROM/GPIO page %u", m_rom_page); + + for (offs_t const start : ram_start[m_ram_page - 1U]) + { + memory_space().install_ram(start << 8, (start << 8) | 0x00ffU, m_memory); + status_space().install_ram(start << 6, (start << 6) | 0x003fU, m_status); + ram_ports_space().install_write_handler(start << 2, (start << 2) | 0x03U, write8_delegate(FUNC(imm4_22_device::ram_out), this)); + } + + offs_t const rom_ports_start(offs_t(m_rom_page) << 6); + offs_t const rom_ports_end(rom_ports_start | 0x003fU); + offs_t const rom_ports_mirror(m_rom_mirror ? 0x1f00U : 0x0700U); + rom_ports_space().install_readwrite_handler( + rom_ports_start, rom_ports_end, 0U, rom_ports_mirror, 0U, + read8_delegate(FUNC(imm4_22_device::rom_in), this), write8_delegate(FUNC(imm4_22_device::rom_out), this)); + + if (is_loaded()) + map_prom(); + } +} + +void imm4_22_device::map_prom() +{ + if (m_ram_io_mapped) + { + // FIXME: gimme a cookie! + // FIXME: if mirror is on, this will fight console RAM for the bus in 0x2000 region and also appear in the "two switches" 0x3000 region + rom_space().install_rom( + offs_t(m_rom_page) << 10, offs_t((offs_t(m_rom_page) << 10) | length()), m_rom_mirror ? 0x1000U : 0x0000U, + m_prom.get()); + } +} + +void imm4_22_device::unmap_prom() +{ + // FIXME: where's my magic cookie? + rom_space().unmap_read(offs_t(m_rom_page) << 10, (offs_t(m_rom_page) << 10) | 0x03ffU, m_rom_mirror ? 0x1000U : 0x0000U); +} + +} } // namespace bus::intellec4 |