Account for .tbss alignment when adjusting start of relro
[deliverable/binutils-gdb.git] / sim / mn10300 / dv-mn103int.c
index 061b9b871ab8401c92e18df2dc236841c2208993..bbd6ceb0060fde91db120675654d10951ffe2237 100644 (file)
@@ -1,39 +1,39 @@
-/*  This file is part of the program GDB, the GU debugger.
+/*  This file is part of the program GDB, the GNU debugger.
     
-    Copyright (C) 1998 Free Software Foundation, Inc.
+    Copyright (C) 1998-2015 Free Software Foundation, Inc.
     Contributed by Cygnus Solutions.
     
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
+    the Free Software Foundation; either version 3 of the License, or
     (at your option) any later version.
-    
+
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
-    
+
     You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     
     */
 
 
 #include "sim-main.h"
-#include "hw-base.h"
+#include "hw-main.h"
+#include "sim-hw.h"
 
 /* DEVICE
 
    
-   mn103int - mn10300 interrupt controller
+   mn103int - mn103002 interrupt controller
 
    
    DESCRIPTION
 
    
-   Implements the mn10300 interrupt controller described in the
-   mn10300 user guide.
+   Implements the mn103002 interrupt controller described in the
+   mn103002 user guide.
 
 
    PROPERTIES
 
    reg = <icr-adr> <icr-siz> <iagr-adr> <iadr-siz> <extmd-adr> <extmd-siz>
 
-   Specify the address of the ICR (total of 25 registers), IAGR and
+   Specify the address of the ICR (total of 30 registers), IAGR and
    EXTMD registers (within the parent bus).
 
-   The reg property value `0x34000100 0x68 0x34000200 0x8 0x3400280
+   The reg property value `0x34000100 0x7C 0x34000200 0x8 0x3400280
    0x8' locates the interrupt controller at the addresses specified in
-   the mn10300 interrupt controller user guide.
+   the mn103002 interrupt controller user guide.
 
 
    PORTS
@@ -83,8 +83,8 @@
 
    int[0..100] (input)
 
-   Level or edge triggered interrupt input port.  Each of the 25
-   groups (0..24) can have up to 4 (0..3) interrupt inputs.  The
+   Level or edge triggered interrupt input port.  Each of the 30
+   groups (0..30) can have up to 4 (0..3) interrupt inputs.  The
    interpretation of a port event/value is determined by the
    configuration of the corresponding interrupt group.
 
    edges.  Instead any input port event is considered to be an
    interrupt trigger.
 
-   For level sensative interrupts, the interrupt controller ignores
+   For level sensitive interrupts, the interrupt controller ignores
    active HIGH/LOW settings and instead always interprets a nonzero
-   port value as an interupt assertion and a zero port value as a
+   port value as an interrupt assertion and a zero port value as a
    negation.
 
    */
 
 
-/* The interrupt groups - numbered according to mn10300 convention */
+/* The interrupt groups - numbered according to mn103002 convention */
 
 enum mn103int_trigger {
   ACTIVE_LOW,
@@ -119,10 +119,11 @@ enum mn103int_trigger {
 
 enum mn103int_type {
   NMI_GROUP,
-  INT_GROUP,
+  LEVEL_GROUP,
 };
 
 struct mn103int_group {
+  int gid;
   int level;
   unsigned enable;
   unsigned request;
@@ -134,8 +135,8 @@ struct mn103int_group {
 enum {
   FIRST_NMI_GROUP = 0,
   LAST_NMI_GROUP = 1,
-  FIRST_INT_GROUP = 2,
-  LAST_INT_GROUP = 24,
+  FIRST_LEVEL_GROUP = 2,
+  LAST_LEVEL_GROUP = 30,
   NR_GROUPS,
 };
 
@@ -196,8 +197,16 @@ enum {
   G21_PORT = 84,
   G22_PORT = 88,
   G23_PORT = 92,
+  IRQ0_PORT = G23_PORT,
   G24_PORT = 96,
-  NR_G_PORTS = 100,
+  G25_PORT = 100,
+  G26_PORT = 104,
+  G27_PORT = 108,
+  IRQ4_PORT = G27_PORT,
+  G28_PORT = 112,
+  G29_PORT = 116,
+  G30_PORT = 120,
+  NR_G_PORTS = 124,
   ACK_PORT,
 };
 
@@ -218,62 +227,39 @@ static const struct hw_port_descriptor mn103int_ports[] = {
   { "watchdog", G0_PORT + 1, 0, input_port, },
   { "syserr", G0_PORT + 2, 0, input_port, },
 
-  { "timer-0-underflow", G2_PORT + 0, 0, input_port, },
-  { "timer-1-underflow", G2_PORT + 1, 0, input_port, },
-  { "timer-2-underflow", G2_PORT + 2, 0, input_port, },
-  { "timer-3-underflow", G2_PORT + 3, 0, input_port, },
-  { "timer-4-underflow", G3_PORT + 0, 0, input_port, },
-  { "timer-5-underflow", G3_PORT + 1, 0, input_port, },
-  { "timer-6-underflow", G3_PORT + 2, 0, input_port, },
-  { "timer-7-underflow", G3_PORT + 3, 0, input_port, },
-
-  { "timer-8-underflow", G4_PORT + 0, 0, input_port, },
-  { "timer-8-compare-a", G4_PORT + 1, 0, input_port, },
-  { "timer-8-compare-b", G4_PORT + 2, 0, input_port, },
-
-  { "timer-9-underflow", G5_PORT + 0, 0, input_port, },
-  { "timer-9-compare-a", G5_PORT + 1, 0, input_port, },
-  { "timer-9-compare-b", G5_PORT + 2, 0, input_port, },
-
-  { "timer-10-underflow", G6_PORT + 0, 0, input_port, },
-  { "timer-10-compare-a", G6_PORT + 1, 0, input_port, },
-  { "timer-10-compare-b", G6_PORT + 2, 0, input_port, },
-  { "timer-10-compare-c", G6_PORT + 3, 0, input_port, },
-
-  { "timer-11-underflow", G7_PORT + 0, 0, input_port, },
-  { "timer-11-compare-a", G7_PORT + 1, 0, input_port, },
-  { "timer-11-compare-b", G7_PORT + 2, 0, input_port, },
-  { "timer-11-compare-c", G7_PORT + 3, 0, input_port, },
-
-  { "timer-12-underflow", G8_PORT + 0, 0, input_port, },
-  { "timer-12-compare-a", G8_PORT + 1, 0, input_port, },
-  { "timer-12-compare-b", G8_PORT + 2, 0, input_port, },
-  { "timer-12-compare-c", G8_PORT + 3, 0, input_port, },
-
-  { "timer-11-compare-d", G9_PORT + 0, 0, input_port, },
-  { "timer-12-compare-d", G9_PORT + 1, 0, input_port, },
-
-  { "dma-0-end", G10_PORT, 0, input_port, },
-  { "dma-1-end", G11_PORT, 0, input_port, },
-  { "dma-2-end", G12_PORT, 0, input_port, },
-  { "dma-3-end", G13_PORT, 0, input_port, },
-
-  { "serial-0-recieve", G14_PORT + 0, 0, input_port, },
-  { "serial-0-transmit", G14_PORT + 1, 0, input_port, },
-
-  { "serial-1-recieve", G15_PORT + 0, 0, input_port, },
-  { "serial-1-transmit", G15_PORT + 1, 0, input_port, },
-
-  { "irq-0", G16_PORT, 0, input_port, },
-  { "irq-1", G17_PORT, 0, input_port, },
-  { "irq-2", G18_PORT, 0, input_port, },
-  { "irq-3", G19_PORT, 0, input_port, },
-  { "irq-4", G20_PORT, 0, input_port, },
-  { "irq-5", G21_PORT, 0, input_port, },
-  { "irq-6", G22_PORT, 0, input_port, },
-  { "irq-7", G23_PORT, 0, input_port, },
-
-  { "ad-end", G24_PORT, 0, input_port, },
+  { "timer-0-underflow", G2_PORT, 0, input_port, },
+  { "timer-1-underflow", G3_PORT, 0, input_port, },
+  { "timer-2-underflow", G4_PORT, 0, input_port, },
+  { "timer-3-underflow", G5_PORT, 0, input_port, },
+  { "timer-4-underflow", G6_PORT, 0, input_port, },
+  { "timer-5-underflow", G7_PORT, 0, input_port, },
+  { "timer-6-underflow", G8_PORT, 0, input_port, },
+
+  { "timer-6-compare-a", G9_PORT, 0, input_port, },
+  { "timer-6-compare-b", G10_PORT, 0, input_port, },
+
+  { "dma-0-end", G12_PORT, 0, input_port, },
+  { "dma-1-end", G13_PORT, 0, input_port, },
+  { "dma-2-end", G14_PORT, 0, input_port, },
+  { "dma-3-end", G15_PORT, 0, input_port, },
+
+  { "serial-0-receive",  G16_PORT, 0, input_port, },
+  { "serial-0-transmit", G17_PORT, 0, input_port, },
+
+  { "serial-1-receive",  G18_PORT, 0, input_port, },
+  { "serial-1-transmit", G19_PORT, 0, input_port, },
+
+  { "serial-2-receive",  G20_PORT, 0, input_port, },
+  { "serial-2-transmit", G21_PORT, 0, input_port, },
+
+  { "irq-0", G23_PORT, 0, input_port, },
+  { "irq-1", G24_PORT, 0, input_port, },
+  { "irq-2", G25_PORT, 0, input_port, },
+  { "irq-3", G26_PORT, 0, input_port, },
+  { "irq-4", G27_PORT, 0, input_port, },
+  { "irq-5", G28_PORT, 0, input_port, },
+  { "irq-6", G29_PORT, 0, input_port, },
+  { "irq-7", G30_PORT, 0, input_port, },
 
   /* interrupt inputs (as generic numbers) */
 
@@ -302,9 +288,12 @@ static const struct hw_port_descriptor mn103int_ports[] = {
 /* Finish off the partially created hw device.  Attach our local
    callbacks.  Wire up our port names etc */
 
-static hw_io_read_buffer_callback mn103int_io_read_buffer;
-static hw_io_write_buffer_callback mn103int_io_write_buffer;
-static hw_port_event_callback mn103int_port_event;
+static hw_io_read_buffer_method mn103int_io_read_buffer;
+static hw_io_write_buffer_method mn103int_io_write_buffer;
+static hw_port_event_method mn103int_port_event;
+static hw_ioctl_method mn103int_ioctl;
+
+
 
 static void
 attach_mn103int_regs (struct hw *me,
@@ -350,6 +339,7 @@ mn103int_finish (struct hw *me)
   set_hw_io_write_buffer (me, mn103int_io_write_buffer);
   set_hw_ports (me, mn103int_ports);
   set_hw_port_event (me, mn103int_port_event);
+  me->to_ioctl = mn103int_ioctl;
 
   /* Attach ourself to our parent bus */
   attach_mn103int_regs (me, controller);
@@ -358,15 +348,17 @@ mn103int_finish (struct hw *me)
   for (gid = 0; gid < NR_GROUPS; gid++)
     {
       struct mn103int_group *group = &controller->group[gid];
-      group->enable = 0xf;
       group->trigger = NEGATIVE_EDGE;
+      group->gid = gid;
       if (FIRST_NMI_GROUP <= gid && gid <= LAST_NMI_GROUP)
        {
+         group->enable = 0xf;
          group->type = NMI_GROUP;
        }
-      else if (FIRST_INT_GROUP <= gid && gid <= LAST_INT_GROUP)
+      else if (FIRST_LEVEL_GROUP <= gid && gid <= LAST_LEVEL_GROUP)
        {
-         group->type = INT_GROUP;
+         group->enable = 0x0;
+         group->type = LEVEL_GROUP;
        }
       else
        hw_abort (me, "internal error - unknown group id");
@@ -386,16 +378,17 @@ find_highest_interrupt_group (struct hw *me,
   int selected;
 
   /* FIRST_NMI_GROUP (group zero) is used as a special default value
-     when searching for an interrupt group */
+     when searching for an interrupt group.*/
   selected = FIRST_NMI_GROUP; 
   controller->group[FIRST_NMI_GROUP].level = 7;
   
-  for (gid = FIRST_INT_GROUP; gid <= LAST_INT_GROUP; gid++)
+  for (gid = FIRST_LEVEL_GROUP; gid <= LAST_LEVEL_GROUP; gid++)
     {
       struct mn103int_group *group = &controller->group[gid];
       if ((group->request & group->enable) != 0)
        {
-         if (group->level > controller->group[selected].level)
+         /* Remember, lower level, higher priority.  */
+         if (group->level < controller->group[selected].level)
            {
              selected = gid;
            }
@@ -414,7 +407,7 @@ push_interrupt_level (struct hw *me,
   int selected = find_highest_interrupt_group (me, controller);
   int level = controller->group[selected].level;
   HW_TRACE ((me, "port-out - selected=%d level=%d", selected, level));
-  hw_port_event (me, LEVEL_PORT, level, NULL, NULL_CIA);
+  hw_port_event (me, LEVEL_PORT, level);
 }
 
 
@@ -425,9 +418,7 @@ mn103int_port_event (struct hw *me,
                     int my_port,
                     struct hw *source,
                     int source_port,
-                    int level,
-                    sim_cpu *processor,
-                    sim_cia cia)
+                    int level)
 {
   struct mn103int *controller = hw_data (me);
 
@@ -491,12 +482,12 @@ mn103int_port_event (struct hw *me,
              if ((group->request & group->enable) != 0)
                {
                  HW_TRACE ((me, "port-out NMI"));
-                 hw_port_event (me, NMI_PORT, 0, NULL, NULL_CIA);
+                 hw_port_event (me, NMI_PORT, 1);
                }
              break;
            }
              
-         case INT_GROUP:
+         case LEVEL_GROUP:
            {
              /* if an interrupt is now pending */
              HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - INT",
@@ -513,12 +504,24 @@ mn103int_port_event (struct hw *me,
 
 /* Read/write to to an ICR (group control register) */
 
+static struct mn103int_group *
+decode_group (struct hw *me,
+             struct mn103int *controller,
+             unsigned_word base,
+             unsigned_word *offset)
+{
+  int gid = (base / 4) % NR_GROUPS;
+  *offset = (base % 4);
+  return &controller->group[gid];
+}
+
 static unsigned8
 read_icr (struct hw *me,
          struct mn103int *controller,
-         struct mn103int_group *group,
-         unsigned_word offset)
+         unsigned_word base)
 {
+  unsigned_word offset;
+  struct mn103int_group *group = decode_group (me, controller, base, &offset);
   unsigned8 val = 0;
   switch (group->type)
     {
@@ -528,25 +531,35 @@ read_icr (struct hw *me,
        {
        case 0:
          val = INSERT_ID (group->request);
-         HW_TRACE ((me, "read-icr 0x%02x", val));
+         HW_TRACE ((me, "read-icr group=%d:0 nmi 0x%02x",
+                    group->gid, val));
+         break;
+       default:
          break;
        }
       break;
 
-    case INT_GROUP:
+    case LEVEL_GROUP:
       switch (offset)
        {
        case 0:
          val = (INSERT_IR (group->request)
                 | INSERT_ID (group->request & group->enable));
-         HW_TRACE ((me, "read-icr 0:0x%02x", val));
+         HW_TRACE ((me, "read-icr group=%d:0 level 0x%02x",
+                    group->gid, val));
          break;
        case 1:
          val = (INSERT_LV (group->level)
                 | INSERT_IE (group->enable));
-         HW_TRACE ((me, "read-icr 1:0x%02x", val));
+         HW_TRACE ((me, "read-icr level-%d:1 level 0x%02x",
+                    group->gid, val));
          break;
        }
+      break;
+
+    default:
+      break;
+
     }
 
   return val;
@@ -555,10 +568,11 @@ read_icr (struct hw *me,
 static void
 write_icr (struct hw *me,
           struct mn103int *controller,
-          struct mn103int_group *group,
-          unsigned_word offset,
-                unsigned8 val)
+          unsigned_word base,
+          unsigned8 val)
 {
+  unsigned_word offset;
+  struct mn103int_group *group = decode_group (me, controller, base, &offset);
   switch (group->type)
     {
 
@@ -566,25 +580,37 @@ write_icr (struct hw *me,
       switch (offset)
        {
        case 0:
-         HW_TRACE ((me, "write-icr 0x%02x", val));
+         HW_TRACE ((me, "write-icr group=%d:0 nmi 0x%02x",
+                    group->gid, val));
          group->request &= ~EXTRACT_ID (val);
          break;
+         /* Special backdoor access to SYSEF flag from CPU.  See
+             interp.c:program_interrupt(). */
+       case 3:
+         HW_TRACE ((me, "write-icr-special group=%d:0 nmi 0x%02x",
+                    group->gid, val));
+         group->request |= EXTRACT_ID (val);
        default:
          break;
        }
       break;
 
-    case INT_GROUP:
+    case LEVEL_GROUP:
       switch (offset)
        {
        case 0: /* request/detect */
          /* Clear any ID bits and then set them according to IR */
-         HW_TRACE ((me, "write-icr 0:0x%02x", val));
-         group->request &= EXTRACT_ID (val);
-         group->request |= EXTRACT_IR (val) & EXTRACT_ID (val);
+         HW_TRACE ((me, "write-icr group=%d:0 level 0x%02x %x:%x:%x",
+                    group->gid, val,
+                    group->request, EXTRACT_IR (val), EXTRACT_ID (val)));
+         group->request =
+           ((EXTRACT_IR (val) & EXTRACT_ID (val))
+            | (EXTRACT_IR (val) & group->request)
+            | (~EXTRACT_IR (val) & ~EXTRACT_ID (val) & group->request));
          break;
        case 1: /* level/enable */
-         HW_TRACE ((me, "write-icr 1:0x%02x", val));
+         HW_TRACE ((me, "write-icr group=%d:1 level 0x%02x",
+                    group->gid, val));
          group->level = EXTRACT_LV (val);
          group->enable = EXTRACT_IE (val);
          break;
@@ -595,6 +621,9 @@ write_icr (struct hw *me,
       push_interrupt_level (me, controller);
       break;
 
+    default:
+      break;
+
     }
 }
 
@@ -611,15 +640,28 @@ read_iagr (struct hw *me,
     {
     case 0:
       {
-       val = (controller->interrupt_accepted_group << 2);
-       if (!(controller->group[val].request
-             & controller->group[val].enable))
-         /* oops, lost the request */
-         val = 0;
+       if (!(controller->group[controller->interrupt_accepted_group].request
+             & controller->group[controller->interrupt_accepted_group].enable))
+         {
+           /* oops, lost the request */
+           val = 0;
+           HW_TRACE ((me, "read-iagr:0 lost-0"));
+         }
+       else
+         {
+           val = (controller->interrupt_accepted_group << 2);
+           HW_TRACE ((me, "read-iagr:0 %d", (int) val));
+         }
        break;
       }
+    case 1:
+      val = 0;
+      HW_TRACE ((me, "read-iagr:1 %d", (int) val));
+      break;
     default:
       val = 0;
+      HW_TRACE ((me, "read-iagr 0x%08lx bad offset", (long) offset));
+      break;
     }
   return val;
 }
@@ -635,9 +677,9 @@ external_group (struct mn103int *controller,
   switch (offset)
     {
     case 0:
-      return &controller->group[16];
+      return &controller->group[IRQ0_PORT/4];
     case 1:
-      return &controller->group[20];
+      return &controller->group[IRQ4_PORT/4];
     default:
       return NULL;
     }
@@ -658,6 +700,7 @@ read_extmd (struct hw *me,
          val |= (group[gid].trigger << (gid * 2));
        }
     }
+  HW_TRACE ((me, "read-extmd 0x%02lx", (long) val));
   return val;
 }
 
@@ -677,6 +720,7 @@ write_extmd (struct hw *me,
          /* MAYBE: interrupts already pending? */
        }
     }
+  HW_TRACE ((me, "write-extmd 0x%02lx", (long) val));
 }
 
 
@@ -685,56 +729,48 @@ write_extmd (struct hw *me,
 static int
 decode_addr (struct hw *me,
             struct mn103int *controller,
-            unsigned_word addr)
+            unsigned_word address,
+            unsigned_word *offset)
 {
   int i;
   for (i = 0; i < NR_BLOCKS; i++)
     {
-      if (addr >= controller->block[i].base
-         && addr <= controller->block[i].bound)
-       return i;
+      if (address >= controller->block[i].base
+         && address <= controller->block[i].bound)
+       {
+         *offset = address - controller->block[i].base;
+         return i;
+       }
     }
   hw_abort (me, "bad address");
   return -1;
 }
 
-static struct mn103int_group *
-decode_group (struct hw *me,
-             struct mn103int *controller,
-             unsigned_word addr)
-{
-  unsigned_word offset = (addr - controller->block[ICR_BLOCK].base);
-  int gid = (offset / 8) % NR_GROUPS;
-  return &controller->group[gid];
-}
-
 static unsigned
 mn103int_io_read_buffer (struct hw *me,
                         void *dest,
                         int space,
                         unsigned_word base,
-                        unsigned nr_bytes,
-                        sim_cpu *processor,
-                        sim_cia cia)
+                        unsigned nr_bytes)
 {
   struct mn103int *controller = hw_data (me);
   unsigned8 *buf = dest;
   unsigned byte;
+  /* HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); */
   for (byte = 0; byte < nr_bytes; byte++)
     {
       unsigned_word address = base + byte;
-      switch (decode_addr (me, controller, address))
+      unsigned_word offset;
+      switch (decode_addr (me, controller, address, &offset))
        {
        case ICR_BLOCK:
-         buf[byte] = read_icr (me, controller,
-                               decode_group (me, controller, address),
-                               address);
+         buf[byte] = read_icr (me, controller, offset);
          break;
        case IAGR_BLOCK:
-         buf[byte] = read_iagr (me, controller, address);
+         buf[byte] = read_iagr (me, controller, offset);
          break;
        case EXTMD_BLOCK:
-         buf[byte] = read_extmd (me, controller, address);
+         buf[byte] = read_extmd (me, controller, offset);
          break;
        default:
          hw_abort (me, "bad switch");
@@ -748,28 +784,26 @@ mn103int_io_write_buffer (struct hw *me,
                          const void *source,
                          int space,
                          unsigned_word base,
-                         unsigned nr_bytes,
-                         sim_cpu *cpu,
-                         sim_cia cia)
+                         unsigned nr_bytes)
 {
   struct mn103int *controller = hw_data (me);
   const unsigned8 *buf = source;
   unsigned byte;
+  /* HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); */
   for (byte = 0; byte < nr_bytes; byte++)
     {
       unsigned_word address = base + byte;
-      switch (decode_addr (me, controller, address))
+      unsigned_word offset;
+      switch (decode_addr (me, controller, address, &offset))
        {
        case ICR_BLOCK:
-         write_icr (me, controller,
-                    decode_group (me, controller, address),
-                    address, buf[byte]);
+         write_icr (me, controller, offset, buf[byte]);
          break;
        case IAGR_BLOCK:
          /* not allowed */
          break;
        case EXTMD_BLOCK:
-         write_extmd (me, controller, address, buf[byte]);
+         write_extmd (me, controller, offset, buf[byte]);
          break;
        default:
          hw_abort (me, "bad switch");
@@ -778,8 +812,19 @@ mn103int_io_write_buffer (struct hw *me,
   return nr_bytes;
 }     
 
+static int
+mn103int_ioctl(struct hw *me,
+              hw_ioctl_request request,
+              va_list ap)
+{
+  struct mn103int *controller = (struct mn103int *)hw_data(me);
+  controller->group[0].request = EXTRACT_ID(4);
+  mn103int_port_event(me, 2 /* nmi_port(syserr) */, NULL, 0, 0);
+  return 0;
+}
+
 
-const struct hw_device_descriptor dv_mn103int_descriptor[] = {
+const struct hw_descriptor dv_mn103int_descriptor[] = {
   { "mn103int", mn103int_finish, },
   { NULL },
 };
This page took 0.031373 seconds and 4 git commands to generate.