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