Home | History | Annotate | Line # | Download | only in mn10300
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, &reg))
    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 					 &reg.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 				   &reg.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