1 // license:BSD-3-Clause
2 // copyright-holders:AJR
3 /***************************************************************************
4 
5     Kawasaki Steel (Kawatetsu) KP69 Interrupt Controller
6 
7     This macro cell is the sole provider of maskable interrupts for
8     KC80/KC82-based microcontrollers. It responds to the CPU's internal
9     IACK and EOI outputs (the latter associated with the RETI instruction)
10     with prioritized Mode 2 vectors and nested in-service lockouts. It
11     offers no support for polled operation or daisy-chaining other
12     interrupt controllers, but it does allow code to recognize spurious
13     interrupts.
14 
15     Each of the 16 interrupt sources may be programmed either as level-
16     triggered or edge-triggered, though the latter is required for
17     interrupts that are internal timer/counter outputs. These and the
18     interrupt vector register must be written first after a reset before
19     the mask and priority group registers can be defined, with no way of
20     returning to the initial mode once the vector has been set.
21 
22 ***************************************************************************/
23 
24 #include "emu.h"
25 #include "kp69.h"
26 
27 #define VERBOSE 0
28 #include "logmacro.h"
29 
30 // device type definition
31 DEFINE_DEVICE_TYPE(KP69, kp69_device, "kp69", "Kawasaki Steel KP69 Interrupt Controller")
32 
33 
34 //-------------------------------------------------
35 //  kp69_base_device - constructor
36 //-------------------------------------------------
37 
kp69_base_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,u32 clock)38 kp69_base_device::kp69_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
39 	: device_t(mconfig, type, tag, owner, clock)
40 	, device_z80daisy_interface(mconfig, *this)
41 	, m_int_callback(*this)
42 	, m_input_levels(0)
43 	, m_irr(0)
44 	, m_isr(0)
45 	, m_illegal_state(false)
46 	, m_ivr(0)
47 	, m_imr(0xffff)
48 	, m_ler(0)
49 	, m_pgr(0)
50 	, m_int_active(false)
51 {
52 }
53 
54 
55 //-------------------------------------------------
56 //  kp69_device - constructor
57 //-------------------------------------------------
58 
kp69_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)59 kp69_device::kp69_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
60 	: kp69_base_device(mconfig, KP69, tag, owner, clock)
61 	, m_ivr_written(false)
62 {
63 }
64 
65 
66 //-------------------------------------------------
67 //  device_resolve_objects - resolve objects that
68 //  may be needed for other devices to set
69 //  initial conditions at start time
70 //-------------------------------------------------
71 
device_resolve_objects()72 void kp69_base_device::device_resolve_objects()
73 {
74 	// Resolve output callback
75 	m_int_callback.resolve_safe();
76 }
77 
78 
79 //-------------------------------------------------
80 //  device_start - device-specific startup
81 //-------------------------------------------------
82 
device_start()83 void kp69_base_device::device_start()
84 {
85 	// Register state for saving
86 	save_item(NAME(m_input_levels));
87 	save_item(NAME(m_irr));
88 	save_item(NAME(m_isr));
89 	save_item(NAME(m_illegal_state));
90 	save_item(NAME(m_ivr));
91 	save_item(NAME(m_imr));
92 	save_item(NAME(m_ler));
93 	save_item(NAME(m_pgr));
94 	save_item(NAME(m_int_active));
95 }
96 
device_start()97 void kp69_device::device_start()
98 {
99 	kp69_base_device::device_start();
100 	save_item(NAME(m_ivr_written));
101 }
102 
103 
104 //-------------------------------------------------
105 //  add_to_state - debug state interface for MCU
106 //-------------------------------------------------
107 
add_to_state(device_state_interface & state,int index)108 void kp69_base_device::add_to_state(device_state_interface &state, int index)
109 {
110 	state.state_add(index, "IRR", m_irr, [this](u16 data) { set_irr(data); });
111 	state.state_add(index + 1, "ISR", m_isr, [this](u16 data) { set_isr(data); });
112 	state.state_add(index + 2, "IVR", m_ivr).mask(0xe0);
113 	state.state_add(index + 3, "LER", m_ler, [this](u16 data) { set_ler(data); });
114 	state.state_add(index + 4, "PGR", m_pgr, [this](u16 data) { set_pgr(data); });
115 	state.state_add(index + 5, "IMR", m_imr, [this](u16 data) { set_imr(data); });
116 }
117 
118 
119 //-------------------------------------------------
120 //  device_reset - device-specific reset
121 //-------------------------------------------------
122 
device_reset()123 void kp69_base_device::device_reset()
124 {
125 	// Reset inputs to level mode
126 	m_ler = 0;
127 
128 	// Mask all interrupts, cancel requests and end service
129 	m_imr = 0xffff;
130 	m_irr = 0;
131 	m_isr = 0;
132 	m_illegal_state = false;
133 
134 	// Reset priority groups
135 	m_pgr = 0;
136 
137 	// Deassert interrupt output
138 	set_int(false);
139 }
140 
device_reset()141 void kp69_device::device_reset()
142 {
143 	kp69_base_device::device_reset();
144 
145 	// Allow LER and IVR to be written first
146 	m_ivr_written = false;
147 }
148 
149 
150 //-------------------------------------------------
151 //  isrl_r - read lower 8 bits of ISR
152 //-------------------------------------------------
153 
isrl_r()154 u8 kp69_base_device::isrl_r()
155 {
156 	return m_isr & 0x00ff;
157 }
158 
159 
160 //-------------------------------------------------
161 //  isrh_r - read upper 8 bits of ISR
162 //-------------------------------------------------
163 
isrh_r()164 u8 kp69_base_device::isrh_r()
165 {
166 	return (m_isr & 0xff00) >> 8;
167 }
168 
169 
170 //-------------------------------------------------
171 //  imrl_r - read lower 8 bits of IMR
172 //-------------------------------------------------
173 
imrl_r()174 u8 kp69_base_device::imrl_r()
175 {
176 	return m_imr & 0x00ff;
177 }
178 
179 
180 //-------------------------------------------------
181 //  imrh_r - read upper 8 bits of IMR
182 //-------------------------------------------------
183 
imrh_r()184 u8 kp69_base_device::imrh_r()
185 {
186 	return (m_imr & 0xff00) >> 8;
187 }
188 
189 
190 //-------------------------------------------------
191 //  lerl_pgrl_w - write lower 8 bits of LER or PGR
192 //-------------------------------------------------
193 
lerl_pgrl_w(u8 data)194 void kp69_device::lerl_pgrl_w(u8 data)
195 {
196 	if (m_ivr_written)
197 		set_pgr((m_pgr & 0xff00) | data);
198 	else
199 		set_ler((m_ler & 0xff00) | data);
200 }
201 
202 
203 //-------------------------------------------------
204 //  lerh_pgrh_w - write upper 8 bits of LER or PGR
205 //-------------------------------------------------
206 
lerh_pgrh_w(u8 data)207 void kp69_device::lerh_pgrh_w(u8 data)
208 {
209 	if (m_ivr_written)
210 		set_pgr(u16(data) << 8 | (m_pgr & 0x00ff));
211 	else
212 		set_ler(u16(data) << 8 | (m_ler & 0x00ff));
213 }
214 
215 
216 //-------------------------------------------------
217 //  imrl_w - write lower 8 bits of IMR
218 //-------------------------------------------------
219 
imrl_w(u8 data)220 void kp69_device::imrl_w(u8 data)
221 {
222 	if (!m_ivr_written)
223 		logerror("%s: IMRL written before IVR\n", machine().describe_context());
224 
225 	set_imr((m_imr & 0xff00) | data);
226 }
227 
228 
229 //-------------------------------------------------
230 //  ivr_imrh_w - write IVR or upper 8 bits of IMR
231 //-------------------------------------------------
232 
ivr_imrh_w(u8 data)233 void kp69_device::ivr_imrh_w(u8 data)
234 {
235 	if (m_ivr_written)
236 		set_imr(u16(data) << 8 | (m_imr & 0x00ff));
237 	else
238 	{
239 		m_ivr = data & 0xe0;
240 		m_ivr_written = true;
241 	}
242 }
243 
244 
245 //-------------------------------------------------
246 //  int_active - determine whether or not the INT
247 //  output is currently active
248 //-------------------------------------------------
249 
int_active() const250 bool kp69_base_device::int_active() const
251 {
252 	if (m_illegal_state)
253 		return false;
254 
255 	// Compare priority of pending interrupt request with any being serviced
256 	if ((m_irr & m_pgr) != 0 || (m_isr & m_pgr) != 0)
257 		return (m_irr & ~m_isr & m_pgr) > (m_isr & m_pgr);
258 	else
259 		return (m_irr & ~m_isr) > m_isr;
260 }
261 
262 
263 //-------------------------------------------------
264 //  set_int - update the INT output state
265 //-------------------------------------------------
266 
set_int(bool active)267 void kp69_base_device::set_int(bool active)
268 {
269 	if (m_int_active != active)
270 	{
271 		m_int_active = active;
272 		m_int_callback(m_int_active ? ASSERT_LINE : CLEAR_LINE);
273 	}
274 }
275 
276 
277 //-------------------------------------------------
278 //  set_input_level - set the level state of one
279 //  out of 16 interrupt inputs
280 //-------------------------------------------------
281 
set_input_level(int level,bool state)282 void kp69_base_device::set_input_level(int level, bool state)
283 {
284 	if (!BIT(m_input_levels, level) && state)
285 	{
286 		m_input_levels |= 1 << level;
287 
288 		// Masked-out interrupts cannot be requested
289 		if (!BIT(m_irr, level) && !BIT(m_imr, level))
290 		{
291 			u16 old_ints = m_irr | m_isr;
292 			m_irr |= 1 << level;
293 			LOG("IRR[%d] asserted\n", level);
294 			if (!m_illegal_state && (1 << level) > (BIT(m_pgr, level) ? old_ints & m_pgr : old_ints))
295 				set_int(true);
296 		}
297 	}
298 	else if (BIT(m_input_levels, level) && !state)
299 	{
300 		m_input_levels &= ~(1 << level);
301 
302 		// Level-triggered interrupts may be deasserted
303 		if (!BIT(m_ler, level) && BIT(m_irr, level))
304 		{
305 			m_irr &= ~(1 << level);
306 			LOG("IRR[%d] cleared\n", level);
307 			if (!m_illegal_state)
308 				set_int(int_active());
309 		}
310 	}
311 }
312 
313 
314 //-------------------------------------------------
315 //  set_irr - write a new value to the Interrupt
316 //  Request Register (not accessible by software)
317 //-------------------------------------------------
318 
set_irr(u16 data)319 void kp69_base_device::set_irr(u16 data)
320 {
321 	m_irr = (data & ~m_imr & m_ler) | (m_irr & ~m_ler);
322 	set_int(int_active());
323 }
324 
325 
326 //-------------------------------------------------
327 //  set_isr - write a new value to the In Service
328 //  Register (not writable by software)
329 //-------------------------------------------------
330 
set_isr(u16 data)331 void kp69_base_device::set_isr(u16 data)
332 {
333 	m_isr = data;
334 	set_int(int_active());
335 }
336 
337 
338 //-------------------------------------------------
339 //  set_imr - write a new value to the Interrupt
340 //  Mask Register
341 //-------------------------------------------------
342 
set_imr(u16 data)343 void kp69_base_device::set_imr(u16 data)
344 {
345 	u16 old_irr = m_irr;
346 	m_imr = data;
347 	m_irr = (m_irr & ~data & m_ler) | (m_input_levels & ~data & ~m_ler);
348 	if (m_irr != old_irr)
349 	{
350 		bool active = int_active();
351 		if (active != m_int_active)
352 			LOG("%s: INT %s (IRR = %04X, was %04X)\n", machine().describe_context(), active ? "unmasked" : "masked out", m_irr, old_irr);
353 		set_int(active);
354 	}
355 }
356 
357 
358 //-------------------------------------------------
359 //  set_ler - write a new value to the Level/Edge
360 //  Register
361 //-------------------------------------------------
362 
set_ler(u16 data)363 void kp69_base_device::set_ler(u16 data)
364 {
365 	u16 old_irr = m_irr;
366 	m_irr = (m_input_levels & ~data) | (m_irr & m_ler & data);
367 	m_ler = data;
368 	if (m_irr != old_irr)
369 		set_int(int_active());
370 }
371 
372 
373 //-------------------------------------------------
374 //  set_pgr - write a new value to the Priority
375 //  Group Register
376 //-------------------------------------------------
377 
set_pgr(u16 data)378 void kp69_base_device::set_pgr(u16 data)
379 {
380 	if (m_pgr != data)
381 	{
382 		m_pgr = data;
383 		if (!m_illegal_state && m_isr != 0)
384 			set_int(int_active());
385 	}
386 }
387 
388 
389 //-------------------------------------------------
390 //  z80daisy_irq_state - return the overall IRQ
391 //  state for this device
392 //-------------------------------------------------
393 
z80daisy_irq_state()394 int kp69_base_device::z80daisy_irq_state()
395 {
396 	return m_int_active ? (Z80_DAISY_INT | Z80_DAISY_IEO) : Z80_DAISY_IEO;
397 }
398 
399 
400 //-------------------------------------------------
401 //  z80daisy_irq_ack - acknowledge an IRQ and
402 //  return the appropriate vector
403 //-------------------------------------------------
404 
z80daisy_irq_ack()405 int kp69_base_device::z80daisy_irq_ack()
406 {
407 	int level = -1;
408 
409 	// Restrict to high-priority interrupts if any of those are pending
410 	if ((m_irr & m_pgr) != 0)
411 	{
412 		level = 31 - count_leading_zeros(u32(m_irr & m_pgr));
413 		assert(level >= 0 && level < 16);
414 		if ((1 << level) < (m_isr & m_pgr))
415 			level = -1;
416 	}
417 	else if (m_irr != 0 && (m_isr & m_pgr) == 0)
418 	{
419 		level = 31 - count_leading_zeros(u32(m_irr));
420 		assert(level >= 0 && level < 16);
421 		if ((1 << level) < m_isr)
422 			level = -1;
423 	}
424 
425 	if (level != -1)
426 	{
427 		u8 vector = m_ivr | (level << 1);
428 		if (BIT(m_ler, level))
429 		{
430 			LOG("%s: IRR[%d] acknowledged and cleared (vector = %02X)\n", machine().describe_context(), level, vector);
431 			m_irr &= ~(1 << level);
432 		}
433 		else
434 			LOG("%s: IR[%d] acknowledged (vector = %02X)\n", machine().describe_context(), level, vector);
435 
436 		m_isr |= 1 << level;
437 		set_int(false);
438 
439 		return vector;
440 	}
441 
442 	// Illegal interrupt operation: same vector as IR[0] but ISR[0] not set
443 	LOG("%s: Illegal interrupt at IACK (vector = %02X)\n", machine().describe_context(), m_ivr);
444 	m_illegal_state = true;
445 	set_int(false);
446 	return m_ivr;
447 }
448 
449 
450 //-------------------------------------------------
451 //  z80daisy_irq_reti - clear the interrupt
452 //  pending state to allow other interrupts through
453 //-------------------------------------------------
454 
z80daisy_irq_reti()455 void kp69_base_device::z80daisy_irq_reti()
456 {
457 	if (m_illegal_state)
458 	{
459 		LOG("%s: End of illegal interrupt\n", machine().describe_context());
460 		m_illegal_state = false;
461 	}
462 	else if (m_isr != 0)
463 	{
464 		int level = 31 - count_leading_zeros(u32((m_isr & m_pgr) != 0 ? (m_isr & m_pgr) : m_isr));
465 		assert(level >= 0 && level < 16);
466 
467 		m_isr &= ~(1 << level);
468 		LOG("%s: EOI for ISR[%d]\n", machine().describe_context(), level);
469 	}
470 	else
471 	{
472 		logerror("%s: RETI before interrupt acknowledged\n", machine().describe_context());
473 		return;
474 	}
475 
476 	set_int(int_active());
477 }
478