mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
Add ER1400 serial EAROM device
This commit is contained in:
parent
8e7c99107d
commit
64524a652c
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
294
src/devices/machine/er1400.cpp
Normal file
294
src/devices/machine/er1400.cpp
Normal 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 35–65% 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;
|
||||
}
|
82
src/devices/machine/er1400.h
Normal file
82
src/devices/machine/er1400.h
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user