dv-mn103int.c revision 1.10 1 1.1 christos /* This file is part of the program GDB, the GNU debugger.
2 1.1 christos
3 1.10 christos Copyright (C) 1998-2023 Free Software Foundation, Inc.
4 1.1 christos Contributed by Cygnus Solutions.
5 1.1 christos
6 1.1 christos This program is free software; you can redistribute it and/or modify
7 1.1 christos it under the terms of the GNU General Public License as published by
8 1.1 christos the Free Software Foundation; either version 3 of the License, or
9 1.1 christos (at your option) any later version.
10 1.1 christos
11 1.1 christos This program is distributed in the hope that it will be useful,
12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 1.1 christos GNU General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>.
18 1.1 christos
19 1.1 christos */
20 1.1 christos
21 1.10 christos /* This must come before any other includes. */
22 1.10 christos #include "defs.h"
23 1.1 christos
24 1.1 christos #include "sim-main.h"
25 1.1 christos #include "hw-main.h"
26 1.1 christos #include "sim-hw.h"
27 1.1 christos
28 1.1 christos /* DEVICE
29 1.1 christos
30 1.1 christos
31 1.1 christos mn103int - mn103002 interrupt controller
32 1.1 christos
33 1.1 christos
34 1.1 christos DESCRIPTION
35 1.1 christos
36 1.1 christos
37 1.1 christos Implements the mn103002 interrupt controller described in the
38 1.1 christos mn103002 user guide.
39 1.1 christos
40 1.1 christos
41 1.1 christos PROPERTIES
42 1.1 christos
43 1.1 christos
44 1.1 christos reg = <icr-adr> <icr-siz> <iagr-adr> <iadr-siz> <extmd-adr> <extmd-siz>
45 1.1 christos
46 1.1 christos Specify the address of the ICR (total of 30 registers), IAGR and
47 1.1 christos EXTMD registers (within the parent bus).
48 1.1 christos
49 1.1 christos The reg property value `0x34000100 0x7C 0x34000200 0x8 0x3400280
50 1.1 christos 0x8' locates the interrupt controller at the addresses specified in
51 1.1 christos the mn103002 interrupt controller user guide.
52 1.1 christos
53 1.1 christos
54 1.1 christos PORTS
55 1.1 christos
56 1.1 christos
57 1.1 christos nmi (output)
58 1.1 christos
59 1.1 christos Non-maskable interrupt output port. An event on this output ports
60 1.1 christos indicates a NMI request from the interrupt controller. The value
61 1.1 christos attached to the event should be ignored.
62 1.1 christos
63 1.1 christos
64 1.1 christos level (output)
65 1.1 christos
66 1.1 christos Maskable interrupt level output port. An event on this output port
67 1.1 christos indicates a maskable interrupt request at the specified level. The
68 1.1 christos event value defines the level being requested.
69 1.1 christos
70 1.1 christos The interrupt controller will generate an event on this port
71 1.1 christos whenever there is a change to the internal state of the interrupt
72 1.1 christos controller.
73 1.1 christos
74 1.1 christos
75 1.1 christos ack (input)
76 1.1 christos
77 1.1 christos Signal from processor indicating that a maskable interrupt has been
78 1.1 christos accepted and the interrupt controller should latch the IAGR with
79 1.1 christos value of the current highest priority interrupting group.
80 1.1 christos
81 1.1 christos The event value is the interrupt level being accepted by the
82 1.1 christos processor. It should be consistent with the most recent LEVEL sent
83 1.1 christos to the processor from the interrupt controller.
84 1.1 christos
85 1.1 christos
86 1.1 christos int[0..100] (input)
87 1.1 christos
88 1.1 christos Level or edge triggered interrupt input port. Each of the 30
89 1.1 christos groups (0..30) can have up to 4 (0..3) interrupt inputs. The
90 1.1 christos interpretation of a port event/value is determined by the
91 1.1 christos configuration of the corresponding interrupt group.
92 1.1 christos
93 1.1 christos For convenience, numerous aliases to these interrupt inputs are
94 1.1 christos provided.
95 1.1 christos
96 1.1 christos
97 1.1 christos BUGS
98 1.1 christos
99 1.1 christos
100 1.1 christos For edge triggered interrupts, the interrupt controller does not
101 1.1 christos differentiate between POSITIVE (rising) and NEGATIVE (falling)
102 1.1 christos edges. Instead any input port event is considered to be an
103 1.1 christos interrupt trigger.
104 1.1 christos
105 1.1 christos For level sensitive interrupts, the interrupt controller ignores
106 1.1 christos active HIGH/LOW settings and instead always interprets a nonzero
107 1.1 christos port value as an interrupt assertion and a zero port value as a
108 1.1 christos negation.
109 1.1 christos
110 1.1 christos */
111 1.1 christos
112 1.1 christos
113 1.1 christos /* The interrupt groups - numbered according to mn103002 convention */
114 1.1 christos
115 1.1 christos enum mn103int_trigger {
116 1.1 christos ACTIVE_LOW,
117 1.1 christos ACTIVE_HIGH,
118 1.1 christos POSITIVE_EDGE,
119 1.1 christos NEGATIVE_EDGE,
120 1.1 christos };
121 1.1 christos
122 1.1 christos enum mn103int_type {
123 1.1 christos NMI_GROUP,
124 1.1 christos LEVEL_GROUP,
125 1.1 christos };
126 1.1 christos
127 1.1 christos struct mn103int_group {
128 1.1 christos int gid;
129 1.1 christos int level;
130 1.1 christos unsigned enable;
131 1.1 christos unsigned request;
132 1.1 christos unsigned input;
133 1.1 christos enum mn103int_trigger trigger;
134 1.1 christos enum mn103int_type type;
135 1.1 christos };
136 1.1 christos
137 1.1 christos enum {
138 1.1 christos FIRST_NMI_GROUP = 0,
139 1.1 christos LAST_NMI_GROUP = 1,
140 1.1 christos FIRST_LEVEL_GROUP = 2,
141 1.1 christos LAST_LEVEL_GROUP = 30,
142 1.1 christos NR_GROUPS,
143 1.1 christos };
144 1.1 christos
145 1.1 christos enum {
146 1.1 christos LOWEST_LEVEL = 7,
147 1.1 christos };
148 1.1 christos
149 1.1 christos /* The interrupt controller register address blocks */
150 1.1 christos
151 1.1 christos struct mn103int_block {
152 1.1 christos unsigned_word base;
153 1.1 christos unsigned_word bound;
154 1.1 christos };
155 1.1 christos
156 1.1 christos enum { ICR_BLOCK, IAGR_BLOCK, EXTMD_BLOCK, NR_BLOCKS };
157 1.1 christos
158 1.1 christos
159 1.1 christos struct mn103int {
160 1.1 christos struct mn103int_block block[NR_BLOCKS];
161 1.1 christos struct mn103int_group group[NR_GROUPS];
162 1.1 christos unsigned interrupt_accepted_group;
163 1.1 christos };
164 1.1 christos
165 1.1 christos
166 1.1 christos
167 1.1 christos /* output port ID's */
168 1.1 christos
169 1.1 christos enum {
170 1.1 christos NMI_PORT,
171 1.1 christos LEVEL_PORT,
172 1.1 christos };
173 1.1 christos
174 1.1 christos
175 1.1 christos /* input port ID's */
176 1.1 christos
177 1.1 christos enum {
178 1.1 christos G0_PORT = 0,
179 1.1 christos G1_PORT = 4,
180 1.1 christos G2_PORT = 8,
181 1.1 christos G3_PORT = 12,
182 1.1 christos G4_PORT = 16,
183 1.1 christos G5_PORT = 20,
184 1.1 christos G6_PORT = 24,
185 1.1 christos G7_PORT = 28,
186 1.1 christos G8_PORT = 32,
187 1.1 christos G9_PORT = 36,
188 1.1 christos G10_PORT = 40,
189 1.1 christos G11_PORT = 44,
190 1.1 christos G12_PORT = 48,
191 1.1 christos G13_PORT = 52,
192 1.1 christos G14_PORT = 56,
193 1.1 christos G15_PORT = 60,
194 1.1 christos G16_PORT = 64,
195 1.1 christos G17_PORT = 68,
196 1.1 christos G18_PORT = 72,
197 1.1 christos G19_PORT = 76,
198 1.1 christos G20_PORT = 80,
199 1.1 christos G21_PORT = 84,
200 1.1 christos G22_PORT = 88,
201 1.1 christos G23_PORT = 92,
202 1.1 christos IRQ0_PORT = G23_PORT,
203 1.1 christos G24_PORT = 96,
204 1.1 christos G25_PORT = 100,
205 1.1 christos G26_PORT = 104,
206 1.1 christos G27_PORT = 108,
207 1.1 christos IRQ4_PORT = G27_PORT,
208 1.1 christos G28_PORT = 112,
209 1.1 christos G29_PORT = 116,
210 1.1 christos G30_PORT = 120,
211 1.1 christos NR_G_PORTS = 124,
212 1.1 christos ACK_PORT,
213 1.1 christos };
214 1.1 christos
215 1.1 christos static const struct hw_port_descriptor mn103int_ports[] = {
216 1.1 christos
217 1.1 christos /* interrupt outputs */
218 1.1 christos
219 1.1 christos { "nmi", NMI_PORT, 0, output_port, },
220 1.1 christos { "level", LEVEL_PORT, 0, output_port, },
221 1.1 christos
222 1.1 christos /* interrupt ack (latch) input from cpu */
223 1.1 christos
224 1.1 christos { "ack", ACK_PORT, 0, input_port, },
225 1.1 christos
226 1.1 christos /* interrupt inputs (as names) */
227 1.1 christos
228 1.1 christos { "nmirq", G0_PORT + 0, 0, input_port, },
229 1.1 christos { "watchdog", G0_PORT + 1, 0, input_port, },
230 1.1 christos { "syserr", G0_PORT + 2, 0, input_port, },
231 1.1 christos
232 1.1 christos { "timer-0-underflow", G2_PORT, 0, input_port, },
233 1.1 christos { "timer-1-underflow", G3_PORT, 0, input_port, },
234 1.1 christos { "timer-2-underflow", G4_PORT, 0, input_port, },
235 1.1 christos { "timer-3-underflow", G5_PORT, 0, input_port, },
236 1.1 christos { "timer-4-underflow", G6_PORT, 0, input_port, },
237 1.1 christos { "timer-5-underflow", G7_PORT, 0, input_port, },
238 1.1 christos { "timer-6-underflow", G8_PORT, 0, input_port, },
239 1.1 christos
240 1.1 christos { "timer-6-compare-a", G9_PORT, 0, input_port, },
241 1.1 christos { "timer-6-compare-b", G10_PORT, 0, input_port, },
242 1.1 christos
243 1.1 christos { "dma-0-end", G12_PORT, 0, input_port, },
244 1.1 christos { "dma-1-end", G13_PORT, 0, input_port, },
245 1.1 christos { "dma-2-end", G14_PORT, 0, input_port, },
246 1.1 christos { "dma-3-end", G15_PORT, 0, input_port, },
247 1.1 christos
248 1.1 christos { "serial-0-receive", G16_PORT, 0, input_port, },
249 1.1 christos { "serial-0-transmit", G17_PORT, 0, input_port, },
250 1.1 christos
251 1.1 christos { "serial-1-receive", G18_PORT, 0, input_port, },
252 1.1 christos { "serial-1-transmit", G19_PORT, 0, input_port, },
253 1.1 christos
254 1.1 christos { "serial-2-receive", G20_PORT, 0, input_port, },
255 1.1 christos { "serial-2-transmit", G21_PORT, 0, input_port, },
256 1.1 christos
257 1.1 christos { "irq-0", G23_PORT, 0, input_port, },
258 1.1 christos { "irq-1", G24_PORT, 0, input_port, },
259 1.1 christos { "irq-2", G25_PORT, 0, input_port, },
260 1.1 christos { "irq-3", G26_PORT, 0, input_port, },
261 1.1 christos { "irq-4", G27_PORT, 0, input_port, },
262 1.1 christos { "irq-5", G28_PORT, 0, input_port, },
263 1.1 christos { "irq-6", G29_PORT, 0, input_port, },
264 1.1 christos { "irq-7", G30_PORT, 0, input_port, },
265 1.1 christos
266 1.1 christos /* interrupt inputs (as generic numbers) */
267 1.1 christos
268 1.1 christos { "int", 0, NR_G_PORTS, input_port, },
269 1.1 christos
270 1.1 christos { NULL, },
271 1.1 christos };
272 1.1 christos
273 1.1 christos
274 1.1 christos /* Macros for extracting/restoring the various register bits */
275 1.1 christos
276 1.1 christos #define EXTRACT_ID(X) (LSEXTRACTED8 ((X), 3, 0))
277 1.1 christos #define INSERT_ID(X) (LSINSERTED8 ((X), 3, 0))
278 1.1 christos
279 1.1 christos #define EXTRACT_IR(X) (LSEXTRACTED8 ((X), 7, 4))
280 1.1 christos #define INSERT_IR(X) (LSINSERTED8 ((X), 7, 4))
281 1.1 christos
282 1.1 christos #define EXTRACT_IE(X) (LSEXTRACTED8 ((X), 3, 0))
283 1.1 christos #define INSERT_IE(X) (LSINSERTED8 ((X), 3, 0))
284 1.1 christos
285 1.1 christos #define EXTRACT_LV(X) (LSEXTRACTED8 ((X), 6, 4))
286 1.1 christos #define INSERT_LV(X) (LSINSERTED8 ((X), 6, 4))
287 1.1 christos
288 1.1 christos
289 1.1 christos
290 1.1 christos /* Finish off the partially created hw device. Attach our local
291 1.1 christos callbacks. Wire up our port names etc */
292 1.1 christos
293 1.1 christos static hw_io_read_buffer_method mn103int_io_read_buffer;
294 1.1 christos static hw_io_write_buffer_method mn103int_io_write_buffer;
295 1.1 christos static hw_port_event_method mn103int_port_event;
296 1.1 christos static hw_ioctl_method mn103int_ioctl;
297 1.1 christos
298 1.1 christos
299 1.1 christos
300 1.1 christos static void
301 1.1 christos attach_mn103int_regs (struct hw *me,
302 1.1 christos struct mn103int *controller)
303 1.1 christos {
304 1.1 christos int i;
305 1.1 christos if (hw_find_property (me, "reg") == NULL)
306 1.1 christos hw_abort (me, "Missing \"reg\" property");
307 1.1 christos for (i = 0; i < NR_BLOCKS; i++)
308 1.1 christos {
309 1.1 christos unsigned_word attach_address;
310 1.1 christos int attach_space;
311 1.1 christos unsigned attach_size;
312 1.1 christos reg_property_spec reg;
313 1.1 christos if (!hw_find_reg_array_property (me, "reg", i, ®))
314 1.1 christos hw_abort (me, "\"reg\" property must contain three addr/size entries");
315 1.1 christos hw_unit_address_to_attach_address (hw_parent (me),
316 1.1 christos ®.address,
317 1.1 christos &attach_space,
318 1.1 christos &attach_address,
319 1.1 christos me);
320 1.1 christos controller->block[i].base = attach_address;
321 1.1 christos hw_unit_size_to_attach_size (hw_parent (me),
322 1.1 christos ®.size,
323 1.1 christos &attach_size, me);
324 1.1 christos controller->block[i].bound = attach_address + (attach_size - 1);
325 1.1 christos hw_attach_address (hw_parent (me),
326 1.1 christos 0,
327 1.1 christos attach_space, attach_address, attach_size,
328 1.1 christos me);
329 1.1 christos }
330 1.1 christos }
331 1.1 christos
332 1.1 christos static void
333 1.1 christos mn103int_finish (struct hw *me)
334 1.1 christos {
335 1.1 christos int gid;
336 1.1 christos struct mn103int *controller;
337 1.1 christos
338 1.1 christos controller = HW_ZALLOC (me, struct mn103int);
339 1.1 christos set_hw_data (me, controller);
340 1.1 christos set_hw_io_read_buffer (me, mn103int_io_read_buffer);
341 1.1 christos set_hw_io_write_buffer (me, mn103int_io_write_buffer);
342 1.1 christos set_hw_ports (me, mn103int_ports);
343 1.1 christos set_hw_port_event (me, mn103int_port_event);
344 1.1 christos me->to_ioctl = mn103int_ioctl;
345 1.1 christos
346 1.1 christos /* Attach ourself to our parent bus */
347 1.1 christos attach_mn103int_regs (me, controller);
348 1.1 christos
349 1.1 christos /* Initialize all the groups according to their default configuration */
350 1.1 christos for (gid = 0; gid < NR_GROUPS; gid++)
351 1.1 christos {
352 1.1 christos struct mn103int_group *group = &controller->group[gid];
353 1.1 christos group->trigger = NEGATIVE_EDGE;
354 1.1 christos group->gid = gid;
355 1.1 christos if (FIRST_NMI_GROUP <= gid && gid <= LAST_NMI_GROUP)
356 1.1 christos {
357 1.1 christos group->enable = 0xf;
358 1.1 christos group->type = NMI_GROUP;
359 1.1 christos }
360 1.1 christos else if (FIRST_LEVEL_GROUP <= gid && gid <= LAST_LEVEL_GROUP)
361 1.1 christos {
362 1.1 christos group->enable = 0x0;
363 1.1 christos group->type = LEVEL_GROUP;
364 1.1 christos }
365 1.1 christos else
366 1.1 christos hw_abort (me, "internal error - unknown group id");
367 1.1 christos }
368 1.1 christos }
369 1.1 christos
370 1.1 christos
371 1.1 christos
372 1.1 christos /* Perform the nasty work of figuring out which of the interrupt
373 1.1 christos groups should have its interrupt delivered. */
374 1.1 christos
375 1.1 christos static int
376 1.1 christos find_highest_interrupt_group (struct hw *me,
377 1.1 christos struct mn103int *controller)
378 1.1 christos {
379 1.1 christos int gid;
380 1.1 christos int selected;
381 1.1 christos
382 1.1 christos /* FIRST_NMI_GROUP (group zero) is used as a special default value
383 1.1 christos when searching for an interrupt group.*/
384 1.1 christos selected = FIRST_NMI_GROUP;
385 1.1 christos controller->group[FIRST_NMI_GROUP].level = 7;
386 1.1 christos
387 1.1 christos for (gid = FIRST_LEVEL_GROUP; gid <= LAST_LEVEL_GROUP; gid++)
388 1.1 christos {
389 1.1 christos struct mn103int_group *group = &controller->group[gid];
390 1.1 christos if ((group->request & group->enable) != 0)
391 1.1 christos {
392 1.1 christos /* Remember, lower level, higher priority. */
393 1.1 christos if (group->level < controller->group[selected].level)
394 1.1 christos {
395 1.1 christos selected = gid;
396 1.1 christos }
397 1.1 christos }
398 1.1 christos }
399 1.1 christos return selected;
400 1.1 christos }
401 1.1 christos
402 1.1 christos
403 1.1 christos /* Notify the processor of an interrupt level update */
404 1.1 christos
405 1.1 christos static void
406 1.1 christos push_interrupt_level (struct hw *me,
407 1.1 christos struct mn103int *controller)
408 1.1 christos {
409 1.1 christos int selected = find_highest_interrupt_group (me, controller);
410 1.1 christos int level = controller->group[selected].level;
411 1.1 christos HW_TRACE ((me, "port-out - selected=%d level=%d", selected, level));
412 1.1 christos hw_port_event (me, LEVEL_PORT, level);
413 1.1 christos }
414 1.1 christos
415 1.1 christos
416 1.1 christos /* An event arrives on an interrupt port */
417 1.1 christos
418 1.1 christos static void
419 1.1 christos mn103int_port_event (struct hw *me,
420 1.1 christos int my_port,
421 1.1 christos struct hw *source,
422 1.1 christos int source_port,
423 1.1 christos int level)
424 1.1 christos {
425 1.1 christos struct mn103int *controller = hw_data (me);
426 1.1 christos
427 1.1 christos switch (my_port)
428 1.1 christos {
429 1.1 christos
430 1.1 christos case ACK_PORT:
431 1.1 christos {
432 1.1 christos int selected = find_highest_interrupt_group (me, controller);
433 1.1 christos if (controller->group[selected].level != level)
434 1.1 christos hw_abort (me, "botched level synchronisation");
435 1.1 christos controller->interrupt_accepted_group = selected;
436 1.1 christos HW_TRACE ((me, "port-event port=ack level=%d - selected=%d",
437 1.1 christos level, selected));
438 1.1 christos break;
439 1.1 christos }
440 1.1 christos
441 1.1 christos default:
442 1.1 christos {
443 1.1 christos int gid;
444 1.1 christos int iid;
445 1.1 christos struct mn103int_group *group;
446 1.1 christos unsigned interrupt;
447 1.1 christos if (my_port > NR_G_PORTS)
448 1.1 christos hw_abort (me, "Event on unknown port %d", my_port);
449 1.1 christos
450 1.1 christos /* map the port onto an interrupt group */
451 1.1 christos gid = (my_port % NR_G_PORTS) / 4;
452 1.1 christos group = &controller->group[gid];
453 1.1 christos iid = (my_port % 4);
454 1.1 christos interrupt = 1 << iid;
455 1.1 christos
456 1.1 christos /* update our cached input */
457 1.1 christos if (level)
458 1.1 christos group->input |= interrupt;
459 1.1 christos else
460 1.1 christos group->input &= ~interrupt;
461 1.1 christos
462 1.1 christos /* update the request bits */
463 1.1 christos switch (group->trigger)
464 1.1 christos {
465 1.1 christos case ACTIVE_LOW:
466 1.1 christos case ACTIVE_HIGH:
467 1.1 christos if (level)
468 1.1 christos group->request |= interrupt;
469 1.1 christos break;
470 1.1 christos case NEGATIVE_EDGE:
471 1.1 christos case POSITIVE_EDGE:
472 1.1 christos group->request |= interrupt;
473 1.1 christos }
474 1.1 christos
475 1.1 christos /* force a corresponding output */
476 1.1 christos switch (group->type)
477 1.1 christos {
478 1.1 christos
479 1.1 christos case NMI_GROUP:
480 1.1 christos {
481 1.1 christos /* for NMI's the event is the trigger */
482 1.1 christos HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - NMI",
483 1.1 christos my_port, gid, iid));
484 1.1 christos if ((group->request & group->enable) != 0)
485 1.1 christos {
486 1.1 christos HW_TRACE ((me, "port-out NMI"));
487 1.1 christos hw_port_event (me, NMI_PORT, 1);
488 1.1 christos }
489 1.1 christos break;
490 1.1 christos }
491 1.1 christos
492 1.1 christos case LEVEL_GROUP:
493 1.1 christos {
494 1.1 christos /* if an interrupt is now pending */
495 1.1 christos HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - INT",
496 1.1 christos my_port, gid, iid));
497 1.1 christos push_interrupt_level (me, controller);
498 1.1 christos break;
499 1.1 christos }
500 1.1 christos }
501 1.1 christos break;
502 1.1 christos }
503 1.1 christos
504 1.1 christos }
505 1.1 christos }
506 1.1 christos
507 1.1 christos /* Read/write to to an ICR (group control register) */
508 1.1 christos
509 1.1 christos static struct mn103int_group *
510 1.1 christos decode_group (struct hw *me,
511 1.1 christos struct mn103int *controller,
512 1.1 christos unsigned_word base,
513 1.1 christos unsigned_word *offset)
514 1.1 christos {
515 1.1 christos int gid = (base / 4) % NR_GROUPS;
516 1.1 christos *offset = (base % 4);
517 1.1 christos return &controller->group[gid];
518 1.1 christos }
519 1.1 christos
520 1.10 christos static uint8_t
521 1.1 christos read_icr (struct hw *me,
522 1.1 christos struct mn103int *controller,
523 1.1 christos unsigned_word base)
524 1.1 christos {
525 1.1 christos unsigned_word offset;
526 1.1 christos struct mn103int_group *group = decode_group (me, controller, base, &offset);
527 1.10 christos uint8_t val = 0;
528 1.1 christos switch (group->type)
529 1.1 christos {
530 1.1 christos
531 1.1 christos case NMI_GROUP:
532 1.1 christos switch (offset)
533 1.1 christos {
534 1.1 christos case 0:
535 1.1 christos val = INSERT_ID (group->request);
536 1.1 christos HW_TRACE ((me, "read-icr group=%d:0 nmi 0x%02x",
537 1.1 christos group->gid, val));
538 1.1 christos break;
539 1.1 christos default:
540 1.1 christos break;
541 1.1 christos }
542 1.1 christos break;
543 1.1 christos
544 1.1 christos case LEVEL_GROUP:
545 1.1 christos switch (offset)
546 1.1 christos {
547 1.1 christos case 0:
548 1.1 christos val = (INSERT_IR (group->request)
549 1.1 christos | INSERT_ID (group->request & group->enable));
550 1.1 christos HW_TRACE ((me, "read-icr group=%d:0 level 0x%02x",
551 1.1 christos group->gid, val));
552 1.1 christos break;
553 1.1 christos case 1:
554 1.1 christos val = (INSERT_LV (group->level)
555 1.1 christos | INSERT_IE (group->enable));
556 1.1 christos HW_TRACE ((me, "read-icr level-%d:1 level 0x%02x",
557 1.1 christos group->gid, val));
558 1.1 christos break;
559 1.1 christos }
560 1.1 christos break;
561 1.1 christos
562 1.1 christos default:
563 1.1 christos break;
564 1.1 christos
565 1.1 christos }
566 1.1 christos
567 1.1 christos return val;
568 1.1 christos }
569 1.1 christos
570 1.1 christos static void
571 1.1 christos write_icr (struct hw *me,
572 1.1 christos struct mn103int *controller,
573 1.1 christos unsigned_word base,
574 1.10 christos uint8_t val)
575 1.1 christos {
576 1.1 christos unsigned_word offset;
577 1.1 christos struct mn103int_group *group = decode_group (me, controller, base, &offset);
578 1.1 christos switch (group->type)
579 1.1 christos {
580 1.1 christos
581 1.1 christos case NMI_GROUP:
582 1.1 christos switch (offset)
583 1.1 christos {
584 1.1 christos case 0:
585 1.1 christos HW_TRACE ((me, "write-icr group=%d:0 nmi 0x%02x",
586 1.1 christos group->gid, val));
587 1.1 christos group->request &= ~EXTRACT_ID (val);
588 1.1 christos break;
589 1.1 christos /* Special backdoor access to SYSEF flag from CPU. See
590 1.1 christos interp.c:program_interrupt(). */
591 1.1 christos case 3:
592 1.1 christos HW_TRACE ((me, "write-icr-special group=%d:0 nmi 0x%02x",
593 1.1 christos group->gid, val));
594 1.1 christos group->request |= EXTRACT_ID (val);
595 1.1 christos default:
596 1.1 christos break;
597 1.1 christos }
598 1.1 christos break;
599 1.1 christos
600 1.1 christos case LEVEL_GROUP:
601 1.1 christos switch (offset)
602 1.1 christos {
603 1.1 christos case 0: /* request/detect */
604 1.1 christos /* Clear any ID bits and then set them according to IR */
605 1.1 christos HW_TRACE ((me, "write-icr group=%d:0 level 0x%02x %x:%x:%x",
606 1.1 christos group->gid, val,
607 1.1 christos group->request, EXTRACT_IR (val), EXTRACT_ID (val)));
608 1.1 christos group->request =
609 1.1 christos ((EXTRACT_IR (val) & EXTRACT_ID (val))
610 1.1 christos | (EXTRACT_IR (val) & group->request)
611 1.1 christos | (~EXTRACT_IR (val) & ~EXTRACT_ID (val) & group->request));
612 1.1 christos break;
613 1.1 christos case 1: /* level/enable */
614 1.1 christos HW_TRACE ((me, "write-icr group=%d:1 level 0x%02x",
615 1.1 christos group->gid, val));
616 1.1 christos group->level = EXTRACT_LV (val);
617 1.1 christos group->enable = EXTRACT_IE (val);
618 1.1 christos break;
619 1.1 christos default:
620 1.1 christos /* ignore */
621 1.1 christos break;
622 1.1 christos }
623 1.1 christos push_interrupt_level (me, controller);
624 1.1 christos break;
625 1.1 christos
626 1.1 christos default:
627 1.1 christos break;
628 1.1 christos
629 1.1 christos }
630 1.1 christos }
631 1.1 christos
632 1.1 christos
633 1.1 christos /* Read the IAGR (Interrupt accepted group register) */
634 1.1 christos
635 1.10 christos static uint8_t
636 1.1 christos read_iagr (struct hw *me,
637 1.1 christos struct mn103int *controller,
638 1.1 christos unsigned_word offset)
639 1.1 christos {
640 1.10 christos uint8_t val;
641 1.1 christos switch (offset)
642 1.1 christos {
643 1.1 christos case 0:
644 1.1 christos {
645 1.1 christos if (!(controller->group[controller->interrupt_accepted_group].request
646 1.1 christos & controller->group[controller->interrupt_accepted_group].enable))
647 1.1 christos {
648 1.1 christos /* oops, lost the request */
649 1.1 christos val = 0;
650 1.1 christos HW_TRACE ((me, "read-iagr:0 lost-0"));
651 1.1 christos }
652 1.1 christos else
653 1.1 christos {
654 1.1 christos val = (controller->interrupt_accepted_group << 2);
655 1.1 christos HW_TRACE ((me, "read-iagr:0 %d", (int) val));
656 1.1 christos }
657 1.1 christos break;
658 1.1 christos }
659 1.1 christos case 1:
660 1.1 christos val = 0;
661 1.1 christos HW_TRACE ((me, "read-iagr:1 %d", (int) val));
662 1.1 christos break;
663 1.1 christos default:
664 1.1 christos val = 0;
665 1.1 christos HW_TRACE ((me, "read-iagr 0x%08lx bad offset", (long) offset));
666 1.1 christos break;
667 1.1 christos }
668 1.1 christos return val;
669 1.1 christos }
670 1.1 christos
671 1.1 christos
672 1.1 christos /* Reads/writes to the EXTMD (external interrupt trigger configuration
673 1.1 christos register) */
674 1.1 christos
675 1.1 christos static struct mn103int_group *
676 1.1 christos external_group (struct mn103int *controller,
677 1.1 christos unsigned_word offset)
678 1.1 christos {
679 1.1 christos switch (offset)
680 1.1 christos {
681 1.1 christos case 0:
682 1.1 christos return &controller->group[IRQ0_PORT/4];
683 1.1 christos case 1:
684 1.1 christos return &controller->group[IRQ4_PORT/4];
685 1.1 christos default:
686 1.1 christos return NULL;
687 1.1 christos }
688 1.1 christos }
689 1.1 christos
690 1.10 christos static uint8_t
691 1.1 christos read_extmd (struct hw *me,
692 1.1 christos struct mn103int *controller,
693 1.1 christos unsigned_word offset)
694 1.1 christos {
695 1.1 christos int gid;
696 1.10 christos uint8_t val = 0;
697 1.1 christos struct mn103int_group *group = external_group (controller, offset);
698 1.1 christos if (group != NULL)
699 1.1 christos {
700 1.1 christos for (gid = 0; gid < 4; gid++)
701 1.1 christos {
702 1.1 christos val |= (group[gid].trigger << (gid * 2));
703 1.1 christos }
704 1.1 christos }
705 1.1 christos HW_TRACE ((me, "read-extmd 0x%02lx", (long) val));
706 1.1 christos return val;
707 1.1 christos }
708 1.1 christos
709 1.1 christos static void
710 1.1 christos write_extmd (struct hw *me,
711 1.1 christos struct mn103int *controller,
712 1.1 christos unsigned_word offset,
713 1.10 christos uint8_t val)
714 1.1 christos {
715 1.1 christos int gid;
716 1.1 christos struct mn103int_group *group = external_group (controller, offset);
717 1.1 christos if (group != NULL)
718 1.1 christos {
719 1.1 christos for (gid = 0; gid < 4; gid++)
720 1.1 christos {
721 1.1 christos group[gid].trigger = (val >> (gid * 2)) & 0x3;
722 1.1 christos /* MAYBE: interrupts already pending? */
723 1.1 christos }
724 1.1 christos }
725 1.1 christos HW_TRACE ((me, "write-extmd 0x%02lx", (long) val));
726 1.1 christos }
727 1.1 christos
728 1.1 christos
729 1.1 christos /* generic read/write */
730 1.1 christos
731 1.1 christos static int
732 1.1 christos decode_addr (struct hw *me,
733 1.1 christos struct mn103int *controller,
734 1.1 christos unsigned_word address,
735 1.1 christos unsigned_word *offset)
736 1.1 christos {
737 1.1 christos int i;
738 1.1 christos for (i = 0; i < NR_BLOCKS; i++)
739 1.1 christos {
740 1.1 christos if (address >= controller->block[i].base
741 1.1 christos && address <= controller->block[i].bound)
742 1.1 christos {
743 1.1 christos *offset = address - controller->block[i].base;
744 1.1 christos return i;
745 1.1 christos }
746 1.1 christos }
747 1.1 christos hw_abort (me, "bad address");
748 1.1 christos return -1;
749 1.1 christos }
750 1.1 christos
751 1.1 christos static unsigned
752 1.1 christos mn103int_io_read_buffer (struct hw *me,
753 1.1 christos void *dest,
754 1.1 christos int space,
755 1.1 christos unsigned_word base,
756 1.1 christos unsigned nr_bytes)
757 1.1 christos {
758 1.1 christos struct mn103int *controller = hw_data (me);
759 1.10 christos uint8_t *buf = dest;
760 1.1 christos unsigned byte;
761 1.1 christos /* HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); */
762 1.1 christos for (byte = 0; byte < nr_bytes; byte++)
763 1.1 christos {
764 1.1 christos unsigned_word address = base + byte;
765 1.1 christos unsigned_word offset;
766 1.1 christos switch (decode_addr (me, controller, address, &offset))
767 1.1 christos {
768 1.1 christos case ICR_BLOCK:
769 1.1 christos buf[byte] = read_icr (me, controller, offset);
770 1.1 christos break;
771 1.1 christos case IAGR_BLOCK:
772 1.1 christos buf[byte] = read_iagr (me, controller, offset);
773 1.1 christos break;
774 1.1 christos case EXTMD_BLOCK:
775 1.1 christos buf[byte] = read_extmd (me, controller, offset);
776 1.1 christos break;
777 1.1 christos default:
778 1.1 christos hw_abort (me, "bad switch");
779 1.1 christos }
780 1.1 christos }
781 1.1 christos return nr_bytes;
782 1.1 christos }
783 1.1 christos
784 1.1 christos static unsigned
785 1.1 christos mn103int_io_write_buffer (struct hw *me,
786 1.1 christos const void *source,
787 1.1 christos int space,
788 1.1 christos unsigned_word base,
789 1.1 christos unsigned nr_bytes)
790 1.1 christos {
791 1.1 christos struct mn103int *controller = hw_data (me);
792 1.10 christos const uint8_t *buf = source;
793 1.1 christos unsigned byte;
794 1.1 christos /* HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); */
795 1.1 christos for (byte = 0; byte < nr_bytes; byte++)
796 1.1 christos {
797 1.1 christos unsigned_word address = base + byte;
798 1.1 christos unsigned_word offset;
799 1.1 christos switch (decode_addr (me, controller, address, &offset))
800 1.1 christos {
801 1.1 christos case ICR_BLOCK:
802 1.1 christos write_icr (me, controller, offset, buf[byte]);
803 1.1 christos break;
804 1.1 christos case IAGR_BLOCK:
805 1.1 christos /* not allowed */
806 1.1 christos break;
807 1.1 christos case EXTMD_BLOCK:
808 1.1 christos write_extmd (me, controller, offset, buf[byte]);
809 1.1 christos break;
810 1.1 christos default:
811 1.1 christos hw_abort (me, "bad switch");
812 1.1 christos }
813 1.1 christos }
814 1.1 christos return nr_bytes;
815 1.1 christos }
816 1.1 christos
817 1.1 christos static int
818 1.1 christos mn103int_ioctl(struct hw *me,
819 1.1 christos hw_ioctl_request request,
820 1.1 christos va_list ap)
821 1.1 christos {
822 1.1 christos struct mn103int *controller = (struct mn103int *)hw_data(me);
823 1.1 christos controller->group[0].request = EXTRACT_ID(4);
824 1.1 christos mn103int_port_event(me, 2 /* nmi_port(syserr) */, NULL, 0, 0);
825 1.1 christos return 0;
826 1.1 christos }
827 1.1 christos
828 1.1 christos
829 1.1 christos const struct hw_descriptor dv_mn103int_descriptor[] = {
830 1.1 christos { "mn103int", mn103int_finish, },
831 1.1 christos { NULL },
832 1.1 christos };
833