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