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