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