// license:BSD-3-Clause // copyright-holders:Curt Coder,AJR /********************************************************************** 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. **********************************************************************/ #include "emu.h" #include "i8212.h" //#define VERBOSE 1 #include "logmacro.h" //************************************************************************** // LIVE DEVICE //************************************************************************** // device type definition DEFINE_DEVICE_TYPE(I8212, i8212_device, "i8212", "Intel 8212 I/O Port") //------------------------------------------------- // i8212_device - constructor //------------------------------------------------- i8212_device::i8212_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, I8212, tag, owner, clock), m_write_int(*this), m_read_di(*this), m_write_do(*this), m_read_md(*this), m_stb(1), m_data(0) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void i8212_device::device_start() { // resolve callbacks 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_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 (get_mode() == mode::OUTPUT) { // output data m_write_do((offs_t)0, m_data); } } //------------------------------------------------- // read - data latch read //------------------------------------------------- READ8_MEMBER(i8212_device::read) { if (!machine().side_effects_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); // read latched data as interrupt vector return m_data; } //------------------------------------------------- // write - data latch write //------------------------------------------------- WRITE8_MEMBER(i8212_device::write) { // clear interrupt line m_write_int(CLEAR_LINE); 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); } } //------------------------------------------------- // strobe - data input strobe //------------------------------------------------- WRITE8_MEMBER(i8212_device::strobe) { if (get_mode() == mode::INPUT) { m_data = data; LOG("I8212: Writing %02X into latch (input mode)\n", data); } // assert interrupt line m_write_int(ASSERT_LINE); } //------------------------------------------------- // stb_w - data strobe write //------------------------------------------------- WRITE_LINE_MEMBER(i8212_device::stb_w) { // active on falling edge if (m_stb && !state) { if (get_mode() == mode::INPUT) { // input data m_data = m_read_di(0); LOG("I8212: Reading %02X into latch (input mode)\n", m_data); } // assert interrupt line m_write_int(ASSERT_LINE); } m_stb = state; }