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