mirror of
https://github.com/holub/mame
synced 2025-04-22 08:22:15 +03:00
i8212: Device overhaul (nw)
- Change the mode setting from a line write to an input callback. This is based on the observation that MD is nearly always tied to either Vcc or GND on actual hardware. - Make the mode a scoped enumeration. - Add strobed write handler for input mode. This allows the device to be hooked up in supstarf in place of generic_latch_8_device. - Add interrupt acknowledge callback for future use. - Add extensive introductory comments.
This commit is contained in:
parent
51dfc76af8
commit
2ad6b11191
@ -1,8 +1,40 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Curt Coder
|
||||
// copyright-holders:Curt Coder,AJR
|
||||
/**********************************************************************
|
||||
|
||||
Intel 8212 8-Bit Input/Output Port emulation
|
||||
Intel 8212/3212 8-Bit Input/Output Port (Multi-Mode Latch Buffer)
|
||||
|
||||
The Intel 8212 was one of the first in a line of bipolar Schottky
|
||||
peripherals released early on for the 8080. Many of these were
|
||||
assigned alternate part numbers in the 3200 series to identify
|
||||
them with Intel's 3001/3002 bipolar bit-slice processing elements.
|
||||
|
||||
The 8212's MD pin is typically tied to either GND or Vcc to fix
|
||||
the chip in one of its two operating modes. In the input mode
|
||||
(MD = L), data is latched on the falling edge of STB, and the
|
||||
three-state outputs are enabled by a combination of two chip
|
||||
select inputs of opposite polarities. In the output mode (MD = H),
|
||||
data is latched on the falling edge of chip selection, and outputs
|
||||
are always enabled. The service request flip-flop is clocked on
|
||||
the falling edge of STB to produce the INT output, and is reset by
|
||||
either chip selection or the active-low CLR input, the latter
|
||||
also resetting the latched data to zero.
|
||||
|
||||
The 8212 in output mode was often used with the 8080 to latch the
|
||||
status word and with the 8085 to latch the lower address bits.
|
||||
|
||||
RCA's CDP1852 is an almost pin-for-pin CMOS counterpart to the
|
||||
8212. The control lines of the CDP1852, however, work slightly
|
||||
differently, especially in output mode.
|
||||
|
||||
When TI second-sourced the 8080A, they cloned the 8212 as the
|
||||
SN74S412 (and numbered their versions of the 8224, 8228 and 8338
|
||||
similarly). While simpler octal latches from the 7400 series such
|
||||
as 74LS273, 74LS373 and 74LS374 became far more common and widely
|
||||
used, even when a separate service request flip-flop needed to be
|
||||
coupled, the Fairchild Advanced Schottky TTL (FAST) evolution of
|
||||
the 7400 series had both inverting (74F432) and non-inverting
|
||||
(74F412) versions of this device.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
@ -19,7 +51,7 @@
|
||||
//**************************************************************************
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(I8212, i8212_device, "i8212", "Intel 8212 I/O")
|
||||
DEFINE_DEVICE_TYPE(I8212, i8212_device, "i8212", "Intel 8212 I/O Port")
|
||||
|
||||
//-------------------------------------------------
|
||||
// i8212_device - constructor
|
||||
@ -30,8 +62,8 @@ i8212_device::i8212_device(const machine_config &mconfig, const char *tag, devic
|
||||
m_write_int(*this),
|
||||
m_read_di(*this),
|
||||
m_write_do(*this),
|
||||
m_md(MODE_INPUT),
|
||||
m_stb(0), m_data(0)
|
||||
m_read_md(*this),
|
||||
m_stb(1), m_data(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -46,23 +78,37 @@ void i8212_device::device_start()
|
||||
m_write_int.resolve_safe();
|
||||
m_read_di.resolve_safe(0);
|
||||
m_write_do.resolve_safe();
|
||||
m_read_md.resolve_safe(0);
|
||||
|
||||
// register for state saving
|
||||
save_item(NAME(m_md));
|
||||
save_item(NAME(m_stb));
|
||||
save_item(NAME(m_data));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// get_mode - resolve device mode
|
||||
//-------------------------------------------------
|
||||
|
||||
i8212_device::mode i8212_device::get_mode()
|
||||
{
|
||||
return m_read_md() ? mode::OUTPUT : mode::INPUT;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void i8212_device::device_reset()
|
||||
{
|
||||
// clear interrupt line
|
||||
m_write_int(CLEAR_LINE);
|
||||
|
||||
// clear latched data
|
||||
m_data = 0;
|
||||
|
||||
if (m_md == MODE_OUTPUT)
|
||||
if (get_mode() == mode::OUTPUT)
|
||||
{
|
||||
// output data
|
||||
m_write_do((offs_t)0, m_data);
|
||||
@ -74,13 +120,28 @@ void i8212_device::device_reset()
|
||||
// read - data latch read
|
||||
//-------------------------------------------------
|
||||
|
||||
READ8_MEMBER( i8212_device::read )
|
||||
READ8_MEMBER(i8212_device::read)
|
||||
{
|
||||
if (!machine().side_effect_disabled())
|
||||
{
|
||||
// clear interrupt line
|
||||
m_write_int(CLEAR_LINE);
|
||||
}
|
||||
|
||||
return m_data;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// inta_cb - data latch read (INTA triggered)
|
||||
//-------------------------------------------------
|
||||
|
||||
IRQ_CALLBACK_MEMBER(i8212_device::inta_cb)
|
||||
{
|
||||
// clear interrupt line
|
||||
m_write_int(CLEAR_LINE);
|
||||
|
||||
LOG("I8212 INT: %u\n", CLEAR_LINE);
|
||||
|
||||
// read latched data as interrupt vector
|
||||
return m_data;
|
||||
}
|
||||
|
||||
@ -89,25 +150,37 @@ READ8_MEMBER( i8212_device::read )
|
||||
// write - data latch write
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( i8212_device::write )
|
||||
WRITE8_MEMBER(i8212_device::write)
|
||||
{
|
||||
// latch data
|
||||
m_data = data;
|
||||
// clear interrupt line
|
||||
m_write_int(CLEAR_LINE);
|
||||
|
||||
// output data
|
||||
m_write_do((offs_t)0, m_data);
|
||||
if (get_mode() == mode::OUTPUT)
|
||||
{
|
||||
// latch data
|
||||
m_data = data;
|
||||
LOG("I8212: Writing %02X into latch (output mode)\n", data);
|
||||
|
||||
// output data
|
||||
m_write_do((offs_t)0, m_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// md_w - mode write
|
||||
// strobe - data input strobe
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE_LINE_MEMBER( i8212_device::md_w )
|
||||
WRITE8_MEMBER(i8212_device::strobe)
|
||||
{
|
||||
LOG("I8212 Mode: %s\n", state ? "output" : "input");
|
||||
if (get_mode() == mode::INPUT)
|
||||
{
|
||||
m_data = data;
|
||||
LOG("I8212: Writing %02X into latch (input mode)\n", data);
|
||||
}
|
||||
|
||||
m_md = state;
|
||||
// assert interrupt line
|
||||
m_write_int(ASSERT_LINE);
|
||||
}
|
||||
|
||||
|
||||
@ -115,22 +188,20 @@ WRITE_LINE_MEMBER( i8212_device::md_w )
|
||||
// stb_w - data strobe write
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE_LINE_MEMBER( i8212_device::stb_w )
|
||||
WRITE_LINE_MEMBER(i8212_device::stb_w)
|
||||
{
|
||||
LOG("I8212 STB: %u\n", state);
|
||||
|
||||
if (m_md == MODE_INPUT)
|
||||
// active on falling edge
|
||||
if (m_stb && !state)
|
||||
{
|
||||
if (m_stb && !state)
|
||||
if (get_mode() == mode::INPUT)
|
||||
{
|
||||
// input data
|
||||
m_data = m_read_di(0);
|
||||
|
||||
// assert interrupt line
|
||||
m_write_int(ASSERT_LINE);
|
||||
|
||||
LOG("I8212 INT: %u\n", ASSERT_LINE);
|
||||
LOG("I8212: Reading %02X into latch (input mode)\n", m_data);
|
||||
}
|
||||
|
||||
// assert interrupt line
|
||||
m_write_int(ASSERT_LINE);
|
||||
}
|
||||
|
||||
m_stb = state;
|
||||
|
@ -1,8 +1,8 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Curt Coder
|
||||
// copyright-holders:Curt Coder,AJR
|
||||
/**********************************************************************
|
||||
|
||||
Intel 8212 8-Bit Input/Output Port emulation
|
||||
Intel 8212/3212 8-Bit Input/Output Port (Multi-Mode Latch Buffer)
|
||||
|
||||
**********************************************************************
|
||||
_____ _____
|
||||
@ -12,7 +12,7 @@
|
||||
DO1 4 | | 21 DO8
|
||||
DI2 5 | | 20 DI7
|
||||
DO2 6 | 8212 | 19 DO7
|
||||
DI3 7 | | 18 DI6
|
||||
DI3 7 | 3212 | 18 DI6
|
||||
DO3 8 | | 17 DO6
|
||||
DI4 9 | | 16 DI5
|
||||
DO4 10 | | 15 DO5
|
||||
@ -42,6 +42,9 @@
|
||||
#define MCFG_I8212_DO_CALLBACK(_write) \
|
||||
devcb = &i8212_device::set_do_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_I8212_MD_CALLBACK(_read) \
|
||||
devcb = &i8212_device::set_md_rd_callback(*device, DEVCB_##_read);
|
||||
|
||||
|
||||
|
||||
///*************************************************************************
|
||||
@ -52,6 +55,12 @@
|
||||
|
||||
class i8212_device : public device_t
|
||||
{
|
||||
enum class mode : u8
|
||||
{
|
||||
INPUT,
|
||||
OUTPUT
|
||||
};
|
||||
|
||||
public:
|
||||
// construction/destruction
|
||||
i8212_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
@ -59,12 +68,19 @@ public:
|
||||
template <class Object> static devcb_base &set_int_wr_callback(device_t &device, Object &&cb) { return downcast<i8212_device &>(device).m_write_int.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> static devcb_base &set_di_rd_callback(device_t &device, Object &&cb) { return downcast<i8212_device &>(device).m_read_di.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> static devcb_base &set_do_wr_callback(device_t &device, Object &&cb) { return downcast<i8212_device &>(device).m_write_do.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> static devcb_base &set_md_rd_callback(device_t &device, Object &&cb) { return downcast<i8212_device &>(device).m_read_md.set_callback(std::forward<Object>(cb)); }
|
||||
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
DECLARE_WRITE8_MEMBER( write );
|
||||
// data read handlers
|
||||
DECLARE_READ8_MEMBER(read);
|
||||
IRQ_CALLBACK_MEMBER(inta_cb);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( md_w );
|
||||
DECLARE_WRITE_LINE_MEMBER( stb_w );
|
||||
// data write handlers
|
||||
DECLARE_WRITE8_MEMBER(write);
|
||||
DECLARE_WRITE8_MEMBER(strobe);
|
||||
|
||||
// line write handlers
|
||||
DECLARE_WRITE_LINE_MEMBER(md_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(stb_w);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
@ -72,19 +88,16 @@ protected:
|
||||
virtual void device_reset() override;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
MODE_INPUT = 0,
|
||||
MODE_OUTPUT
|
||||
};
|
||||
// helpers
|
||||
mode get_mode();
|
||||
|
||||
devcb_write_line m_write_int;
|
||||
devcb_read8 m_read_di;
|
||||
devcb_write8 m_write_do;
|
||||
devcb_read_line m_read_md;
|
||||
|
||||
int m_md; // mode
|
||||
int m_stb; // strobe
|
||||
uint8_t m_data; // data latch
|
||||
uint8_t m_data; // data latch
|
||||
};
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "emu.h"
|
||||
#include "cpu/i8085/i8085.h"
|
||||
#include "cpu/mcs48/mcs48.h"
|
||||
#include "machine/gen_latch.h"
|
||||
#include "machine/i8212.h"
|
||||
#include "sound/ay8910.h"
|
||||
#include "speaker.h"
|
||||
|
||||
@ -45,7 +45,7 @@ private:
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<cpu_device> m_soundcpu;
|
||||
required_device_array<ay8910_device, 2> m_psg;
|
||||
required_device_array<generic_latch_8_device, 2> m_soundlatch;
|
||||
required_device_array<i8212_device, 2> m_soundlatch;
|
||||
|
||||
u8 m_port1_data;
|
||||
bool m_pcs[2];
|
||||
@ -54,7 +54,7 @@ private:
|
||||
|
||||
static ADDRESS_MAP_START(main_map, AS_PROGRAM, 8, supstarf_state)
|
||||
AM_RANGE(0x0000, 0x3fff) AM_ROM
|
||||
AM_RANGE(0x8000, 0x8000) AM_DEVREAD("soundlatch1", generic_latch_8_device, read) AM_DEVWRITE("soundlatch2", generic_latch_8_device, write)
|
||||
AM_RANGE(0x8000, 0x8000) AM_DEVREAD("soundlatch1", i8212_device, read) AM_DEVWRITE("soundlatch2", i8212_device, strobe)
|
||||
AM_RANGE(0xc000, 0xc7ff) AM_RAM // 5517 (2Kx8) at IC11
|
||||
ADDRESS_MAP_END
|
||||
|
||||
@ -102,7 +102,7 @@ WRITE8_MEMBER(supstarf_state::psg_latch_w)
|
||||
}
|
||||
|
||||
if (m_latch_select)
|
||||
m_soundlatch[0]->write(space, 0, data);
|
||||
m_soundlatch[0]->strobe(space, 0, data);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(supstarf_state::port1_w)
|
||||
@ -177,11 +177,13 @@ static MACHINE_CONFIG_START(supstarf)
|
||||
MCFG_MCS48_PORT_P2_OUT_CB(WRITE8(supstarf_state, port2_w))
|
||||
MCFG_MCS48_PORT_T1_IN_CB(READLINE(supstarf_state, phase_detect_r))
|
||||
|
||||
MCFG_GENERIC_LATCH_8_ADD("soundlatch1")
|
||||
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("maincpu", I8085_RST55_LINE))
|
||||
MCFG_DEVICE_ADD("soundlatch1", I8212, 0)
|
||||
MCFG_I8212_MD_CALLBACK(GND)
|
||||
MCFG_I8212_INT_CALLBACK(INPUTLINE("maincpu", I8085_RST55_LINE))
|
||||
|
||||
MCFG_GENERIC_LATCH_8_ADD("soundlatch2")
|
||||
MCFG_GENERIC_LATCH_DATA_PENDING_CB(INPUTLINE("soundcpu", MCS48_INPUT_IRQ))
|
||||
MCFG_DEVICE_ADD("soundlatch2", I8212, 0)
|
||||
MCFG_I8212_MD_CALLBACK(GND)
|
||||
MCFG_I8212_INT_CALLBACK(INPUTLINE("soundcpu", MCS48_INPUT_IRQ))
|
||||
//MCFG_DEVCB_CHAIN_OUTPUT(INPUTLINE("maincpu", I8085_READY_LINE))
|
||||
|
||||
MCFG_SPEAKER_STANDARD_MONO("mono")
|
||||
|
Loading…
Reference in New Issue
Block a user