// license:BSD-3-Clause
// copyright-holders:AJR
/**********************************************************************
RST interrupt vector buffer
The hardware circuit emulated by this device, which is generally
made of various TTL gates and buffers, combines three independent
interrupt request lines into a single level trigger and also
generates a 8080-compatible RST opcode vector when the CPU
acknowledges the interrupt, reflecting the current state of all
three inputs.
The positive version of this device treats all of its inputs and
outputs as active high, in accordance with 8080 convention and
some actual practice. An active-low IRQ would need to be supplied
for a Z80, which may be used with this type of circuit in IM 0,
though the negative polarity of the Z80 IRQ is not currently
accounted for by MAME.
Table of interrupt vectors for positive version:
Active Vector Instruction Address of
inputs fetched executed service routine
------- ------- ----------- ---------------
1 only CF RST 1 0008
2 only D7 RST 2 0010
4 only E7 RST 4 0020
1 and 2 DF RST 3 0018
1 and 4 EF RST 5 0028
2 and 4 F7 RST 6 0030
1, 2, 4 FF RST 7 0038
An alternate version of this device buffers the logical negative
of the request lines. This variant is primarily associated with
Z80-based sound systems. Here the inputs, asserted singly, will
produce a RST 18H, RST 28H or RST 30H interrupt (using Zilog
rather than Intel syntax). When multiple request lines are active
at once, the result is equivalent to the logical AND of the
corresponding base vectors.
This type of circuit features no built-in edge triggers or
prioritization. Since its inputs are not latched, a spurious
interrupt may occur if one or more lines are asserted just long
enough for the CPU to accept the interrupt, but deasserted before
the CPU's interrupt acknowledge cycle completes. In the positive
version, the vector placed on the bus (C7) is a RST 0 instruction,
which (after the return address is pushed onto the stack) will
transfer control to 0000 as if the CPU had just been reset. The
negative version provides a more useful vector (RST 7/RST 38H)
for spurious interrupts, but will still generate RST 0 if all
three inputs are active at once, though this situation cannot
occur if the buffer only admits two request lines (as is
generally the case with this version).
**********************************************************************/
#include "emu.h"
#include "machine/rstbuf.h"
// device type definition
DEFINE_DEVICE_TYPE(RST_POS_BUFFER, rst_pos_buffer_device, "rst_pos_buffer", "RST Interrupt Buffer (positive modification)")
DEFINE_DEVICE_TYPE(RST_NEG_BUFFER, rst_neg_buffer_device, "rst_neg_buffer", "RST Interrupt Buffer (negative modification)")
//**************************************************************************
// RST INTERRUPT BUFFER DEVICE
//**************************************************************************
//-------------------------------------------------
// rst_buffer_device - constructor
//-------------------------------------------------
rst_buffer_device::rst_buffer_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
, m_int_cb(*this)
, m_input_buffer(0)
{
}
//-------------------------------------------------
// rst_pos_buffer_device - constructor
//-------------------------------------------------
rst_pos_buffer_device::rst_pos_buffer_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: rst_buffer_device(mconfig, RST_POS_BUFFER, tag, owner, clock)
{
}
//-------------------------------------------------
// rst_neg_buffer_device - constructor
//-------------------------------------------------
rst_neg_buffer_device::rst_neg_buffer_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: rst_buffer_device(mconfig, RST_NEG_BUFFER, tag, owner, clock)
{
}
//-------------------------------------------------
// device_resolve_objects - resolve objects that
// may be needed for other devices to set
// initial conditions at start time
//-------------------------------------------------
void rst_buffer_device::device_resolve_objects()
{
m_int_cb.resolve_safe();
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void rst_buffer_device::device_start()
{
// save input state
save_item(NAME(m_input_buffer));
}
//-------------------------------------------------
// sync_set_input - synchronize asserted input
//-------------------------------------------------
TIMER_CALLBACK_MEMBER(rst_buffer_device::sync_set_input)
{
if (m_input_buffer == 0)
{
// assert interrupt when one line becomes active
m_input_buffer = param;
m_int_cb(1);
}
else
m_input_buffer |= param;
}
//-------------------------------------------------
// sync_clear_input - synchronize cleared input
//-------------------------------------------------
TIMER_CALLBACK_MEMBER(rst_buffer_device::sync_clear_input)
{
if (m_input_buffer == param)
{
// deassert interrupt when no more lines are active
m_input_buffer = 0;
m_int_cb(0);
}
else
m_input_buffer &= ~param;
}
//-------------------------------------------------
// sync_input - helper to synchronize input lines
//-------------------------------------------------
void rst_buffer_device::sync_input(bool state, u8 mask)
{
if (state)
machine().scheduler().synchronize(timer_expired_delegate(FUNC(rst_pos_buffer_device::sync_set_input), this), mask);
else
machine().scheduler().synchronize(timer_expired_delegate(FUNC(rst_pos_buffer_device::sync_clear_input), this), mask);
}
//-------------------------------------------------
// inta_cb - provide vector when interrupt is
// acknowledged by CPU
//-------------------------------------------------
IRQ_CALLBACK_MEMBER(rst_buffer_device::inta_cb)
{
return get_vector();
}