summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2019-06-16 13:13:36 -0400
committer AJR <ajrhacker@users.noreply.github.com>2019-06-16 13:13:36 -0400
commit927944810e8459fe6aaa6ce742a4e4ea7c62d11d (patch)
treee724f8b1369b177a5913abdac8838d0ac6c5a30a
parentd57439b609d2f1ae6b2679cae0ca2734c96d1e3a (diff)
tk2000: Add printer interface
-rw-r--r--src/mame/drivers/tk2000.cpp65
1 files changed, 34 insertions, 31 deletions
diff --git a/src/mame/drivers/tk2000.cpp b/src/mame/drivers/tk2000.cpp
index 38280fb3e63..6b0d3156d02 100644
--- a/src/mame/drivers/tk2000.cpp
+++ b/src/mame/drivers/tk2000.cpp
@@ -18,6 +18,7 @@
#include "video/apple2.h"
#include "cpu/m6502/m6502.h"
+#include "bus/centronics/ctronics.h"
#include "imagedev/cassette.h"
#include "machine/74259.h"
#include "machine/bankdev.h"
@@ -48,20 +49,14 @@ public:
m_ram(*this, RAM_TAG),
m_screen(*this, "screen"),
m_video(*this, A2_VIDEO_TAG),
- m_row0(*this, "ROW0"),
- m_row1(*this, "ROW1"),
- m_row2(*this, "ROW2"),
- m_row3(*this, "ROW3"),
- m_row4(*this, "ROW4"),
- m_row5(*this, "ROW5"),
- m_row6(*this, "ROW6"),
- m_row7(*this, "ROW7"),
+ m_row(*this, "ROW%u", 0U),
m_kbspecial(*this, "keyb_special"),
m_sysconfig(*this, "a2_config"),
m_speaker(*this, A2_SPEAKER_TAG),
m_cassette(*this, A2_CASSETTE_TAG),
m_upperbank(*this, A2_UPPERBANK_TAG),
- m_softlatch(*this, "softlatch")
+ m_softlatch(*this, "softlatch"),
+ m_printer(*this, "printer")
{ }
void tk2000(machine_config &config);
@@ -75,13 +70,14 @@ private:
required_device<ram_device> m_ram;
required_device<screen_device> m_screen;
required_device<a2_video_device> m_video;
- required_ioport m_row0, m_row1, m_row2, m_row3, m_row4, m_row5, m_row6, m_row7;
+ required_ioport_array<8> m_row;
required_ioport m_kbspecial;
required_ioport m_sysconfig;
required_device<speaker_sound_device> m_speaker;
required_device<cassette_image_device> m_cassette;
required_device<address_map_bank_device> m_upperbank;
required_device<addressable_latch_device> m_softlatch;
+ required_device<centronics_device> m_printer;
int m_speaker_state;
int m_cassette_state;
@@ -90,6 +86,7 @@ private:
uint8_t *m_ram_ptr;
int m_ram_size;
+ bool m_printer_busy;
TIMER_DEVICE_CALLBACK_MEMBER(apple2_interrupt);
@@ -97,6 +94,8 @@ private:
uint8_t ram_r(offs_t offset);
void ram_w(offs_t offset, uint8_t data);
+
+ DECLARE_WRITE_LINE_MEMBER(printer_busy_w);
void kbout_w(uint8_t data);
uint8_t kbin_r();
uint8_t casout_r();
@@ -108,7 +107,6 @@ private:
DECLARE_WRITE_LINE_MEMBER(color_w);
DECLARE_WRITE_LINE_MEMBER(motor_a_w);
DECLARE_WRITE_LINE_MEMBER(motor_b_w);
- DECLARE_WRITE_LINE_MEMBER(printer_strobe_w);
DECLARE_WRITE_LINE_MEMBER(rom_ram_w);
DECLARE_WRITE_LINE_MEMBER(ctrl_key_w);
uint8_t c080_r(offs_t offset);
@@ -134,11 +132,13 @@ void tk2000_state::machine_start()
m_speaker->level_w(m_speaker_state);
m_cassette_state = 0;
m_cassette->output(-1.0f);
+ m_printer_busy = false;
// setup save states
save_item(NAME(m_speaker_state));
save_item(NAME(m_cassette_state));
save_item(NAME(m_strobe));
+ save_item(NAME(m_printer_busy));
// setup video pointers
m_video->m_ram_ptr = m_ram_ptr;
@@ -180,28 +180,32 @@ uint32_t tk2000_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap
I/O
***************************************************************************/
+WRITE_LINE_MEMBER(tk2000_state::printer_busy_w)
+{
+ m_printer_busy = state;
+}
+
void tk2000_state::kbout_w(uint8_t data)
{
// write row mask for keyboard scan
- switch (data)
- {
- case 0:
- break;
-
- case 0x01: m_strobe = m_row0->read(); break;
- case 0x02: m_strobe = m_row1->read(); break;
- case 0x04: m_strobe = m_row2->read(); break;
- case 0x08: m_strobe = m_row3->read(); break;
- case 0x10: m_strobe = m_row4->read(); break;
- case 0x20: m_strobe = m_row5->read(); break;
- case 0x40: m_strobe = m_row6->read(); break;
- case 0x80: m_strobe = m_row7->read(); break;
- }
+ m_strobe = 0xff;
+ for (int i = 0; i < 8; i++)
+ if (BIT(data, i))
+ m_strobe &= m_row[i]->read();
+
+ m_printer->write_data0(BIT(data, 0));
+ m_printer->write_data1(BIT(data, 1));
+ m_printer->write_data2(BIT(data, 2));
+ m_printer->write_data3(BIT(data, 3));
+ m_printer->write_data4(BIT(data, 4));
+ m_printer->write_data5(BIT(data, 5));
+ m_printer->write_data6(BIT(data, 6));
+ m_printer->write_data7(BIT(data, 7));
}
uint8_t tk2000_state::kbin_r()
{
- return m_strobe;
+ return m_strobe | (m_printer_busy ? 0x40 : 0);
}
uint8_t tk2000_state::casout_r()
@@ -255,10 +259,6 @@ WRITE_LINE_MEMBER(tk2000_state::motor_b_w)
{
}
-WRITE_LINE_MEMBER(tk2000_state::printer_strobe_w)
-{
-}
-
WRITE_LINE_MEMBER(tk2000_state::rom_ram_w)
{
// 0 = ROM, 1 = RAM
@@ -597,7 +597,7 @@ void tk2000_state::tk2000(machine_config &config)
m_softlatch->q_out_cb<1>().set(FUNC(tk2000_state::motor_a_w));
m_softlatch->q_out_cb<2>().set(m_video, FUNC(a2_video_device::scr_w));
m_softlatch->q_out_cb<3>().set(FUNC(tk2000_state::motor_b_w));
- m_softlatch->q_out_cb<4>().set(FUNC(tk2000_state::printer_strobe_w));
+ m_softlatch->q_out_cb<4>().set(m_printer, FUNC(centronics_device::write_strobe));
m_softlatch->q_out_cb<5>().set(FUNC(tk2000_state::rom_ram_w));
m_softlatch->q_out_cb<7>().set(FUNC(tk2000_state::ctrl_key_w));
@@ -605,6 +605,9 @@ void tk2000_state::tk2000(machine_config &config)
CASSETTE(config, m_cassette);
m_cassette->set_default_state(CASSETTE_STOPPED);
+
+ CENTRONICS(config, m_printer, centronics_devices, nullptr);
+ m_printer->busy_handler().set(FUNC(tk2000_state::printer_busy_w));
}
/***************************************************************************
.cs { color: #8f5902; font-style: italic } /* Comment.Special */ .highlight .gd { color: #a40000 } /* Generic.Deleted */ .highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ .highlight .gr { color: #ef2929 } /* Generic.Error */ .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ .highlight .gi { color: #00A000 } /* Generic.Inserted */ .highlight .go { color: #000000; font-style: italic } /* Generic.Output */ .highlight .gp { color: #8f5902 } /* Generic.Prompt */ .highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ .highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ .highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */ .highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */ .highlight .ld { color: #000000 } /* Literal.Date */ .highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */ .highlight .s { color: #4e9a06 } /* Literal.String */ .highlight .na { color: #c4a000 } /* Name.Attribute */ .highlight .nb { color: #204a87 } /* Name.Builtin */ .highlight .nc { color: #000000 } /* Name.Class */ .highlight .no { color: #000000 } /* Name.Constant */ .highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */ .highlight .ni { color: #ce5c00 } /* Name.Entity */ .highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #000000 } /* Name.Function */ .highlight .nl { color: #f57900 } /* Name.Label */ .highlight .nn { color: #000000 } /* Name.Namespace */ .highlight .nx { color: #000000 } /* Name.Other */ .highlight .py { color: #000000 } /* Name.Property */ .highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #000000 } /* Name.Variable */ .highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */ .highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ .highlight .w { color: #f8f8f8 } /* Text.Whitespace */ .highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ .highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ .highlight .sc { color: #4e9a06 } /* Literal.String.Char */ .highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ .highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ .highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ .highlight .se { color: #4e9a06 } /* Literal.String.Escape */ .highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ .highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ .highlight .sx { color: #4e9a06 } /* Literal.String.Other */ .highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ .highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ .highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ .highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #000000 } /* Name.Function.Magic */ .highlight .vc { color: #000000 } /* Name.Variable.Class */ .highlight .vg { color: #000000 } /* Name.Variable.Global */ .highlight .vi { color: #000000 } /* Name.Variable.Instance */ .highlight .vm { color: #000000 } /* Name.Variable.Magic */ .highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    eepromser.h

    Serial EEPROM devices.

***************************************************************************/

#ifndef MAME_MACHINE_EEPROMSER_H
#define MAME_MACHINE_EEPROMSER_H

#pragma once

#include "eeprom.h"


//**************************************************************************
//  INTERFACE CONFIGURATION MACROS
//**************************************************************************

// optional enable for streaming reads
#define MCFG_EEPROM_SERIAL_ENABLE_STREAMING() \
	downcast<eeprom_serial_base_device &>(*device).enable_streaming(true);
// optional enable for output on falling clock
#define MCFG_EEPROM_SERIAL_ENABLE_OUTPUT_ON_FALLING_CLOCK() \
	downcast<eeprom_serial_base_device &>(*device).enable_output_on_falling_clock(true);

// standard 93CX6 class of 16-bit EEPROMs
#define MCFG_EEPROM_SERIAL_93C06_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C06_16BIT, 0)
#define MCFG_EEPROM_SERIAL_93C46_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C46_16BIT, 0)
#define MCFG_EEPROM_SERIAL_93C56_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C56_16BIT, 0)
#define MCFG_EEPROM_SERIAL_93C57_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C57_16BIT, 0)
#define MCFG_EEPROM_SERIAL_93C66_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C66_16BIT, 0)
#define MCFG_EEPROM_SERIAL_93C76_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C76_16BIT, 0)
#define MCFG_EEPROM_SERIAL_93C86_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C86_16BIT, 0)

// some manufacturers use pin 6 as an "ORG" pin which, when pulled low, configures memory for 8-bit accesses
#define MCFG_EEPROM_SERIAL_93C46_8BIT_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C46_8BIT, 0)
#define MCFG_EEPROM_SERIAL_93C56_8BIT_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C56_8BIT, 0)
#define MCFG_EEPROM_SERIAL_93C57_8BIT_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C57_8BIT, 0)
#define MCFG_EEPROM_SERIAL_93C66_8BIT_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C66_8BIT, 0)
#define MCFG_EEPROM_SERIAL_93C76_8BIT_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C76_8BIT, 0)
#define MCFG_EEPROM_SERIAL_93C86_8BIT_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C86_8BIT, 0)

// ER5911 has a separate ready pin, a reduced command set, and supports 8/16 bit out of the box
#define MCFG_EEPROM_SERIAL_ER5911_8BIT_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_ER5911_8BIT, 0)
#define MCFG_EEPROM_SERIAL_ER5911_16BIT_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_ER5911_16BIT, 0)

#define MCFG_EEPROM_SERIAL_MSM16911_8BIT_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_MSM16911_8BIT, 0)
#define MCFG_EEPROM_SERIAL_MSM16911_16BIT_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_MSM16911_16BIT, 0)

// Seiko S-29X90 class of 16-bit EEPROMs. They always use 13 address bits, despite needing only 6-8.
// The output is updated on the falling edge of the clock. Streaming is enabled
#define MCFG_EEPROM_SERIAL_S29190_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_S29190_16BIT, 0) \
	MCFG_EEPROM_SERIAL_ENABLE_OUTPUT_ON_FALLING_CLOCK() \
	MCFG_EEPROM_SERIAL_ENABLE_STREAMING()
#define MCFG_EEPROM_SERIAL_S29290_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_S29290_16BIT, 0) \
	MCFG_EEPROM_SERIAL_ENABLE_OUTPUT_ON_FALLING_CLOCK() \
	MCFG_EEPROM_SERIAL_ENABLE_STREAMING()
#define MCFG_EEPROM_SERIAL_S29390_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_S29390_16BIT, 0) \
	MCFG_EEPROM_SERIAL_ENABLE_OUTPUT_ON_FALLING_CLOCK() \
	MCFG_EEPROM_SERIAL_ENABLE_STREAMING()

// X24c44 16 bit ram/eeprom combo
#define MCFG_EEPROM_SERIAL_X24C44_ADD(_tag) \
	MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_X24C44_16BIT, 0)

// pass-throughs to the base class for setting default data
#define MCFG_EEPROM_SERIAL_DATA MCFG_EEPROM_DATA
#define MCFG_EEPROM_SERIAL_DEFAULT_VALUE MCFG_EEPROM_DEFAULT_VALUE

#define MCFG_EEPROM_SERIAL_DO_CALLBACK(_devcb) \
	devcb = &downcast<eeprom_serial_base_device &>(*device).set_do_callback(DEVCB_##_devcb);


//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************


// ======================> eeprom_serial_base_device

class eeprom_serial_base_device : public eeprom_base_device
{
public:
	// inline configuration helpers
	void set_address_bits(int addrbits) { m_command_address_bits = addrbits; }
	void enable_streaming(bool enable) { m_streaming_enabled = enable; }
	void enable_output_on_falling_clock(bool enable) { m_output_on_falling_clock_enabled = enable; }
	template<class Object> devcb_base &set_do_callback(Object &&cb) { return m_do_cb.set_callback(std::forward<Object>(cb)); }

protected:
	// construction/destruction
	eeprom_serial_base_device(const machine_config &mconfig, device_type devtype, const char *tag, device_t *owner);

	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;

	// read interfaces differ between implementations

	// commands
	enum eeprom_command : u8
	{
		COMMAND_INVALID,
		COMMAND_READ,
		COMMAND_WRITE,
		COMMAND_ERASE,
		COMMAND_LOCK,
		COMMAND_UNLOCK,
		COMMAND_WRITEALL,
		COMMAND_ERASEALL,
		COMMAND_COPY_EEPROM_TO_RAM,
		COMMAND_COPY_RAM_TO_EEPROM
	};

	// states
	enum eeprom_state : u8
	{
		STATE_IN_RESET,
		STATE_WAIT_FOR_START_BIT,
		STATE_WAIT_FOR_COMMAND,
		STATE_READING_DATA,
		STATE_WAIT_FOR_DATA,
		STATE_WAIT_FOR_COMPLETION
	};

	// events
	enum eeprom_event : u8
	{
		EVENT_CS_RISING_EDGE = 1 << 0,
		EVENT_CS_FALLING_EDGE = 1 << 1,
		EVENT_CLK_RISING_EDGE = 1 << 2,
		EVENT_CLK_FALLING_EDGE = 1 << 3
	};

	// internal helpers
	void set_state(eeprom_state newstate);
	void execute_write_command();

	// subclass helpers
	void base_cs_write(int state);
	void base_clk_write(int state);
	void base_di_write(int state);
	int base_do_read();
	int base_ready_read();

	// subclass overrides
	virtual void handle_event(eeprom_event event);
	virtual void parse_command_and_address() = 0;
	virtual void execute_command();


	// configuration state
	uint8_t         m_command_address_bits;     // number of address bits in a command
	bool            m_streaming_enabled;        // true if streaming is enabled
	bool            m_output_on_falling_clock_enabled;  // true if the output pin is updated on the falling edge of the clock
	devcb_write_line m_do_cb;                   // callback to push state of DO line

	// runtime state
	eeprom_state    m_state;                    // current internal state
	uint8_t         m_cs_state;                 // state of the CS line
	attotime        m_last_cs_rising_edge_time; // time of the last CS rising edge
	uint8_t         m_oe_state;                 // state of the OE line
	uint8_t         m_clk_state;                // state of the CLK line
	uint8_t         m_di_state;                 // state of the DI line
	bool            m_locked;                   // are we locked against writes?
	uint32_t        m_bits_accum;               // number of bits accumulated
	uint32_t        m_command_address_accum;    // accumulator of command+address bits
	eeprom_command  m_command;                  // current command
	uint32_t        m_address;                  // current address extracted from command
	uint32_t        m_shift_register;           // holds data coming in/going out
};



// ======================> eeprom_serial_93cxx_device

class eeprom_serial_93cxx_device : public eeprom_serial_base_device
{
public:
	// read handlers
	DECLARE_READ_LINE_MEMBER(do_read);  // combined DO+READY/BUSY

	// write handlers
	DECLARE_WRITE_LINE_MEMBER(cs_write);        // CS signal (active high)
	DECLARE_WRITE_LINE_MEMBER(clk_write);       // CLK signal (active high)
	DECLARE_WRITE_LINE_MEMBER(di_write);        // DI

protected:
	// construction/destruction
	eeprom_serial_93cxx_device(const machine_config &mconfig, device_type devtype, const char *tag, device_t *owner);

	// subclass overrides
	virtual void parse_command_and_address() override;
};


// ======================> eeprom_serial_er5911_device

class eeprom_serial_er5911_device : public eeprom_serial_base_device
{
public:
	// read handlers
	DECLARE_READ_LINE_MEMBER(do_read);          // DO
	DECLARE_READ_LINE_MEMBER(ready_read);       // READY/BUSY only

	// write handlers
	DECLARE_WRITE_LINE_MEMBER(cs_write);        // CS signal (active high)
	DECLARE_WRITE_LINE_MEMBER(clk_write);       // CLK signal (active high)
	DECLARE_WRITE_LINE_MEMBER(di_write);        // DI

protected:
	// construction/destruction
	eeprom_serial_er5911_device(const machine_config &mconfig, device_type devtype, const char *tag, device_t *owner);

	// subclass overrides
	virtual void parse_command_and_address() override;
};


// ======================> eeprom_serial_x24c44_device

class eeprom_serial_x24c44_device : public eeprom_serial_base_device
{
		//async recall not implemented
		//async store not implemented
public:
	// read handlers
	DECLARE_READ_LINE_MEMBER(do_read);          // DO

	// write handlers
	DECLARE_WRITE_LINE_MEMBER(cs_write);        // CS signal (active high)
	DECLARE_WRITE_LINE_MEMBER(clk_write);       // CLK signal (active high)
	DECLARE_WRITE_LINE_MEMBER(di_write);        // DI

protected:
	// construction/destruction
	eeprom_serial_x24c44_device(const machine_config &mconfig, device_type devtype, const char *tag, device_t *owner);

	// subclass overrides
	virtual void parse_command_and_address() override;
	void handle_event(eeprom_event event) override;
	virtual void parse_command_and_address_2_bit();
	void execute_command() override;
	void copy_ram_to_eeprom();
	void copy_eeprom_to_ram();
	void device_start() override;
	uint8_t m_ram_length;
	uint16_t m_ram_data[16];
	uint16_t m_reading;
	uint8_t m_store_latch;
};



//**************************************************************************
//  DERIVED TYPES
//**************************************************************************

// macro for declaring a new device class
#define DECLARE_SERIAL_EEPROM_DEVICE(_baseclass, _lowercase, _uppercase, _bits) \
class eeprom_serial_##_lowercase##_##_bits##bit_device : public eeprom_serial_##_baseclass##_device \
{ \
public: \
	eeprom_serial_##_lowercase##_##_bits##bit_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); \
}; \
DECLARE_DEVICE_TYPE(EEPROM_SERIAL_##_uppercase##_##_bits##BIT, eeprom_serial_##_lowercase##_##_bits##bit_device)

// standard 93CX6 class of 16-bit EEPROMs
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c06, 93C06, 16)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c46, 93C46, 16)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c56, 93C56, 16)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c57, 93C57, 16)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c66, 93C66, 16)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c76, 93C76, 16)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c86, 93C86, 16)

// some manufacturers use pin 6 as an "ORG" pin which, when pulled low, configures memory for 8-bit accesses
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c46, 93C46, 8)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c56, 93C56, 8)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c57, 93C57, 8)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c66, 93C66, 8)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c76, 93C76, 8)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c86, 93C86, 8)

// ER5911 has a separate ready pin, a reduced command set, and supports 8/16 bit out of the box
DECLARE_SERIAL_EEPROM_DEVICE(er5911, er5911, ER5911, 8)
DECLARE_SERIAL_EEPROM_DEVICE(er5911, er5911, ER5911, 16)
DECLARE_SERIAL_EEPROM_DEVICE(er5911, msm16911, MSM16911, 8)
DECLARE_SERIAL_EEPROM_DEVICE(er5911, msm16911, MSM16911, 16)

// Seiko S-29X90 class of 16-bit EEPROMs. They always use 13 address bits, despite needing only 6-8.
// The output is updated on the falling edge of the clock. Streaming is enabled
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, s29190, S29190, 16)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, s29290, S29290, 16)
DECLARE_SERIAL_EEPROM_DEVICE(93cxx, s29390, S29390, 16)

// X24c44 16 bit 32byte ram/eeprom combo
DECLARE_SERIAL_EEPROM_DEVICE(x24c44, x24c44, X24C44, 16)

#endif // MAME_MACHINE_EEPROMSER_H