Add ER1400 serial EAROM device

This commit is contained in:
AJR 2017-12-31 11:39:28 -05:00
parent 8e7c99107d
commit 64524a652c
8 changed files with 415 additions and 0 deletions

View File

@ -968,6 +968,18 @@ if (MACHINES["EEPROMDEV"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/er1400.h,MACHINES["ER1400"] = true
---------------------------------------------------
if (MACHINES["ER1400"]~=null) then
files {
MAME_DIR .. "src/devices/machine/er1400.cpp",
MAME_DIR .. "src/devices/machine/er1400.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/er2055.h,MACHINES["ER2055"] = true

View File

@ -425,6 +425,7 @@ MACHINES["E0516"] = true
MACHINES["E05A03"] = true
MACHINES["E05A30"] = true
MACHINES["EEPROMDEV"] = true
--MACHINES["ER1400"] = true
MACHINES["ER2055"] = true
MACHINES["F3853"] = true
--MACHINES["HD63450"] = true

View File

@ -414,6 +414,7 @@ MACHINES["E0516"] = true
MACHINES["E05A03"] = true
MACHINES["E05A30"] = true
MACHINES["EEPROMDEV"] = true
MACHINES["ER1400"] = true
MACHINES["ER2055"] = true
MACHINES["F3853"] = true
MACHINES["HD63450"] = true

View File

@ -0,0 +1,294 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/***************************************************************************
GI ER1400 1400 Bit Serial Electrically Alterable Read-Only Memory
This device uses negative logic. The emulation uses logic levels for
all data, which means that inputs should be inverted if non-inverting
drivers are used and vice versa.
Vgg should be 35 volts below Vss. Logic one is output as 12 volts below
Vss. Vss represents logic zero, which is nominally GND but may be +12V.
The frequency of the input clock should be between 10 kHz and 17 kHz,
with a 3565% duty cycle when the device is in operation. The clock may
be left at logic zero when the device is in standby.
Write and erase times are 10 ms (min), 15 ms (typical), 24 ms (max).
***************************************************************************/
#include "emu.h"
#include "machine/er1400.h"
// device type definition
DEFINE_DEVICE_TYPE(ER1400, er1400_device, "er1400", "ER1400 Serial EAROM (100x14)")
//**************************************************************************
// ER1400 DEVICE
//**************************************************************************
//-------------------------------------------------
// er1400_device - constructor
//-------------------------------------------------
er1400_device::er1400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, ER1400, tag, owner, clock)
, device_nvram_interface(mconfig, *this)
, m_clock_input(0)
, m_code_input(0)
, m_data_input(0)
, m_data_output(0)
, m_write_time(attotime::never)
, m_erase_time(attotime::never)
, m_data_register(0)
, m_address_register(0)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void er1400_device::device_start()
{
save_item(NAME(m_clock_input));
save_item(NAME(m_code_input));
save_item(NAME(m_data_input));
save_item(NAME(m_data_output));
save_item(NAME(m_write_time));
save_item(NAME(m_erase_time));
save_item(NAME(m_data_register));
save_item(NAME(m_address_register));
m_data_array = std::make_unique<u16[]>(100);
save_pointer(m_data_array.get(), "m_data_array", 100);
}
//-------------------------------------------------
// nvram_default - called to initialize NVRAM to
// its default state
//-------------------------------------------------
void er1400_device::nvram_default()
{
// all locations erased
std::fill(&m_data_array[0], &m_data_array[100], 0x3fff);
}
//-------------------------------------------------
// nvram_read - called to read NVRAM from the
// .nv file
//-------------------------------------------------
void er1400_device::nvram_read(emu_file &file)
{
file.read(&m_data_array[0], 200);
}
//-------------------------------------------------
// nvram_write - called to write NVRAM to the
// specified file
//-------------------------------------------------
void er1400_device::nvram_write(emu_file &file)
{
file.write(&m_data_array[0], 200);
}
//-------------------------------------------------
// read_data - read addressed word into data
// register
//-------------------------------------------------
void er1400_device::read_data()
{
m_data_register = 0;
for (int tens = 10; tens < 20; tens++)
{
for (int units = 0; units < 10; units++)
{
if (BIT(m_address_register, tens) && BIT(m_address_register, units))
{
offs_t offset = 10 * (tens - 10) + units;
logerror("Reading data at %d into register\n", offset);
m_data_register |= m_data_array[offset];
}
}
}
}
//-------------------------------------------------
// write_data - write data register to addressed
// word (which must have been erased first)
//-------------------------------------------------
void er1400_device::write_data()
{
for (int tens = 10; tens < 20; tens++)
{
for (int units = 0; units < 10; units++)
{
if (BIT(m_address_register, tens) && BIT(m_address_register, units))
{
offs_t offset = 10 * (tens - 10) + units;
if ((m_data_array[offset] & ~m_data_register) != 0)
{
logerror("Writing data %04X at %d\n", m_data_register, offset);
m_data_array[offset] &= m_data_register;
}
}
}
}
}
//-------------------------------------------------
// erase_data - erase data at addressed word to
// all ones
//-------------------------------------------------
void er1400_device::erase_data()
{
for (int tens = 10; tens < 20; tens++)
{
for (int units = 0; units < 10; units++)
{
if (BIT(m_address_register, tens) && BIT(m_address_register, units))
{
offs_t offset = 10 * (tens - 10) + units;
if (m_data_array[offset] != 0x3fff)
{
logerror("Erasing data at %d\n", m_data_register, offset);
m_data_array[offset] = 0x3fff;
}
}
}
}
}
//-------------------------------------------------
// data_w - write data input line
//-------------------------------------------------
WRITE_LINE_MEMBER(er1400_device::data_w)
{
m_data_input = state;
}
//-------------------------------------------------
// c1_w - write to first control line
//-------------------------------------------------
WRITE_LINE_MEMBER(er1400_device::c1_w)
{
m_code_input = (m_code_input & 3) | (state << 2);
}
//-------------------------------------------------
// c2_w - write to second control line
//-------------------------------------------------
WRITE_LINE_MEMBER(er1400_device::c2_w)
{
m_code_input = (m_code_input & 5) | (state << 1);
}
//-------------------------------------------------
// c3_w - write to third control line
//-------------------------------------------------
WRITE_LINE_MEMBER(er1400_device::c3_w)
{
m_code_input = (m_code_input & 6) | state;
}
//-------------------------------------------------
// clock_w - write to clock line
//-------------------------------------------------
WRITE_LINE_MEMBER(er1400_device::clock_w)
{
if (m_clock_input == bool(state))
return;
m_clock_input = bool(state);
// Commands are clocked by a logical 1 -> 0 transition (i.e. rising edge)
if (!state)
{
m_data_output = false;
if (machine().time() >= m_write_time)
write_data();
if (m_code_input != 6)
m_write_time = attotime::never;
if (machine().time() >= m_erase_time)
erase_data();
if (m_code_input != 2)
m_erase_time = attotime::never;
switch (m_code_input)
{
case 0: // standby
break;
case 1: default: // not used
break;
case 2: // erase
if (m_erase_time == attotime::never)
m_erase_time = machine().time() + attotime::from_msec(15);
break;
case 3: // accept address
m_address_register = (m_address_register << 1) | m_data_input;
m_address_register &= 0xfffff;
break;
case 4: // read
read_data();
break;
case 5: // shift data out
m_data_output = BIT(m_data_register, 13);
m_data_register = (m_data_register & 0x1fff) << 1;
break;
case 6: // write
if (m_write_time == attotime::never)
m_write_time = machine().time() + attotime::from_msec(15);
break;
case 7: // accept data
m_data_register = (m_data_register & 0x1fff) << 1;
m_data_register |= m_data_input;
break;
}
}
}
//-------------------------------------------------
// data_r - read data line
//-------------------------------------------------
READ_LINE_MEMBER(er1400_device::data_r)
{
return m_data_input | m_data_output;
}

View File

@ -0,0 +1,82 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/***************************************************************************
GI ER1400 1400 Bit Serial Electrically Alterable Read-Only Memory
****************************************************************************
____ ____
(0) Vss 1 |* \_/ | 14 Vm (N.C.)
(-35) Vgg 2 | | 13 N.C.
N.C. 3 | | 12 Data I/O
N.C. 4 | ER 1400 | 11 N.C.
N.C. 5 | | 10 N.C.
Clock 6 | | 9 C3
C1 7 |___________| 8 C2
***************************************************************************/
#ifndef MAME_MACHINE_ER1400_H
#define MAME_MACHINE_ER1400_H
#pragma once
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> er1400_device
class er1400_device : public device_t, public device_nvram_interface
{
public:
// construction/destruction
er1400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
// line handlers
DECLARE_WRITE_LINE_MEMBER(data_w);
DECLARE_WRITE_LINE_MEMBER(c1_w);
DECLARE_WRITE_LINE_MEMBER(c2_w);
DECLARE_WRITE_LINE_MEMBER(c3_w);
DECLARE_WRITE_LINE_MEMBER(clock_w);
DECLARE_READ_LINE_MEMBER(data_r);
protected:
// device-level overrides
virtual void device_start() override;
// device_nvram_interface overrides
virtual void nvram_default() override;
virtual void nvram_read(emu_file &file) override;
virtual void nvram_write(emu_file &file) override;
private:
// internal helpers
void read_data();
void write_data();
void erase_data();
// nonvolatile data
std::unique_ptr<u16[]> m_data_array;
// input and output line states
bool m_clock_input;
u8 m_code_input;
bool m_data_input;
bool m_data_output;
// timing
attotime m_write_time;
attotime m_erase_time;
// internal registers
u16 m_data_register;
u32 m_address_register;
};
// device type definition
DECLARE_DEVICE_TYPE(ER1400, er1400_device)
#endif // MAME_DEVICES_MACHINE_ER1400_H

View File

@ -25,6 +25,7 @@
#include "cpu/i8085/i8085.h"
#include "cpu/z80/z80.h"
#include "machine/com8116.h"
#include "machine/er1400.h"
#include "machine/i8251.h"
#include "machine/timer.h"
#include "sound/beep.h"
@ -48,6 +49,7 @@ public:
m_speaker(*this, "beeper"),
m_uart(*this, "i8251"),
m_dbrg(*this, COM5016T_TAG),
m_nvr(*this, "nvr"),
m_p_ram(*this, "p_ram")
{
}
@ -57,6 +59,7 @@ public:
required_device<beep_device> m_speaker;
required_device<i8251_device> m_uart;
required_device<com8116_device> m_dbrg;
required_device<er1400_device> m_nvr;
DECLARE_READ8_MEMBER(vt100_flags_r);
DECLARE_WRITE8_MEMBER(vt100_keyboard_w);
DECLARE_READ8_MEMBER(vt100_keyboard_r);
@ -116,6 +119,8 @@ ADDRESS_MAP_END
READ8_MEMBER( vt100_state::vt100_flags_r )
{
uint8_t ret = 0;
ret |= !m_nvr->data_r() << 5;
ret |= m_crtc->lba7_r() << 6;
ret |= m_keyboard_int << 7;
return ret;
@ -182,6 +187,13 @@ WRITE8_MEMBER( vt100_state::vt100_baud_rate_w )
WRITE8_MEMBER( vt100_state::vt100_nvr_latch_w )
{
// data inverted due to negative logic
m_nvr->c3_w(!BIT(data, 3));
m_nvr->c2_w(!BIT(data, 2));
m_nvr->c1_w(!BIT(data, 1));
// C2 is used to disable pullup on data line
m_nvr->data_w(BIT(data, 2) ? 0 : !BIT(data, 0));
}
static ADDRESS_MAP_START(vt100_io, AS_IO, 8, vt100_state)
@ -367,6 +379,8 @@ void vt100_state::machine_reset()
output().set_value("l4_led", 1);
m_key_scan = 0;
vt100_nvr_latch_w(machine().dummy_space(), 0, 0);
}
READ8_MEMBER( vt100_state::vt100_read_video_ram_r )
@ -428,6 +442,7 @@ static MACHINE_CONFIG_START( vt100 )
MCFG_VT_CHARGEN("chargen")
MCFG_VT_VIDEO_RAM_CALLBACK(READ8(vt100_state, vt100_read_video_ram_r))
MCFG_VT_VIDEO_CLEAR_VIDEO_INTERRUPT_CALLBACK(WRITELINE(vt100_state, vt100_clear_video_interrupt))
MCFG_VT_VIDEO_LBA7_CALLBACK(DEVWRITELINE("nvr", er1400_device, clock_w))
MCFG_DEVICE_ADD("i8251", I8251, 0) // 2.7648Mhz phi-clock (not used for tx clock or rx clock?)
MCFG_I8251_TXD_HANDLER(DEVWRITELINE(RS232_TAG, rs232_port_device, write_txd))
@ -442,6 +457,8 @@ static MACHINE_CONFIG_START( vt100 )
MCFG_COM8116_FR_HANDLER(DEVWRITELINE("i8251", i8251_device, write_rxc))
MCFG_COM8116_FT_HANDLER(DEVWRITELINE("i8251", i8251_device, write_txc))
MCFG_DEVICE_ADD("nvr", ER1400, 0)
/* audio hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("beeper", BEEP, 786) // 7.945us per serial clock = ~125865.324hz, / 160 clocks per char = ~ 786 hz

View File

@ -78,6 +78,7 @@ vt100_video_device::vt100_video_device(const machine_config &mconfig, device_typ
, device_video_interface(mconfig, *this)
, m_read_ram(*this)
, m_write_clear_video_interrupt(*this)
, m_write_lba7(*this)
, m_char_rom(*this, finder_base::DUMMY_TAG)
, m_palette(*this, "palette")
{
@ -105,6 +106,7 @@ void vt100_video_device::device_start()
/* resolve callbacks */
m_read_ram.resolve_safe(0);
m_write_clear_video_interrupt.resolve_safe();
m_write_lba7.resolve_safe();
// LBA7 is scan line frequency update
m_lba7_change_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vt100_video_device::lba7_change), this));
@ -875,6 +877,7 @@ int rainbow_video_device::MHFU(int ASK)
TIMER_CALLBACK_MEMBER(vt100_video_device::lba7_change)
{
m_lba7 = (m_lba7) ? 0 : 1;
m_write_lba7(m_lba7);
}

View File

@ -23,6 +23,7 @@ public:
template <class Object> static devcb_base &set_ram_rd_callback(device_t &device, Object &&cb) { return downcast<vt100_video_device &>(device).m_read_ram.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_clear_video_irq_wr_callback(device_t &device, Object &&cb) { return downcast<vt100_video_device &>(device).m_write_clear_video_interrupt.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_lba7_wr_callback(device_t &device, Object &&cb) { return downcast<vt100_video_device &>(device).m_write_lba7.set_callback(std::forward<Object>(cb)); }
static void set_chargen_tag(device_t &device, const char *tag) { downcast<vt100_video_device &>(device).m_char_rom.set_tag(tag); }
@ -48,6 +49,7 @@ protected:
devcb_read8 m_read_ram;
devcb_write8 m_write_clear_video_interrupt;
devcb_write_line m_write_lba7;
int m_lba7;
@ -112,4 +114,7 @@ DECLARE_DEVICE_TYPE(RAINBOW_VIDEO, rainbow_video_device)
#define MCFG_VT_VIDEO_CLEAR_VIDEO_INTERRUPT_CALLBACK(_write) \
devcb = &vt100_video_device::set_clear_video_irq_wr_callback(*device, DEVCB_##_write);
#define MCFG_VT_VIDEO_LBA7_CALLBACK(_write) \
devcb = &vt100_video_device::set_lba7_wr_callback(*device, DEVCB_##_write);
#endif // MAME_VIDEO_VTVIDEO_H