summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/rstbuf.cpp
blob: 9e13d72743a8114eca1282452e42ba19cedb0822 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// 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();
}