]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/mips/dv-tx3904cpu.c
Update years in copyright notice for the GDB files.
[thirdparty/binutils-gdb.git] / sim / mips / dv-tx3904cpu.c
index f756f22c37f586873d8ff8a586fcf72d20523a50..3ede7d358547e937848d2ebfa2b300e940ae300f 100644 (file)
@@ -1,27 +1,26 @@
-/*  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-2013 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"
 
 /* DEVICE
 
@@ -82,6 +81,7 @@
 struct tx3904cpu {
   /* Pending interrupts for delivery by event handler */
   int pending_reset, pending_nmi, pending_level;
+  struct hw_event* event;
 };
 
 
@@ -109,7 +109,7 @@ static const struct hw_port_descriptor tx3904cpu_ports[] = {
 /* Finish off the partially created hw device.  Attach our local
    callbacks.  Wire up our port names etc */
 
-static hw_port_event_callback tx3904cpu_port_event;
+static hw_port_event_method tx3904cpu_port_event;
 
 
 
@@ -127,6 +127,7 @@ tx3904cpu_finish (struct hw *me)
   controller->pending_level = 0;
   controller->pending_reset = 0;
   controller->pending_nmi = 0;
+  controller->event = NULL;
 }
 
 
@@ -138,8 +139,8 @@ deliver_tx3904cpu_interrupt (struct hw *me,
                            void *data)
 {
   struct tx3904cpu *controller = hw_data (me);
-  SIM_DESC simulator = hw_system (me);
-  sim_cpu *cpu = STATE_CPU (simulator, 0); /* NB: fix CPU 0. */
+  SIM_DESC sd = hw_system (me);
+  sim_cpu *cpu = STATE_CPU (sd, 0); /* NB: fix CPU 0. */
   address_word cia = CIA_GET (cpu);
 
 #define CPU cpu
@@ -163,24 +164,31 @@ deliver_tx3904cpu_interrupt (struct hw *me,
                 controller->pending_level,
                 (long) CIA_GET (cpu), (long) SR));
 
-      /* Don't overwrite the CAUSE field since we have no good place to clear
-        it again.  The specs allow it to be zero by the time the interrupt
-        handler is invoked. */
-      /* CAUSE &= ~ (cause_IP_mask << cause_IP_shift);
-        CAUSE |= (controller->pending_level & cause_IP_mask) << cause_IP_shift; */
+      /* Clear CAUSE register.  It may stay this way if the interrupt
+        was cleared with a negative pending_level. */
+      CAUSE &= ~ (cause_IP_mask << cause_IP_shift);
 
-      /* check for enabled / unmasked interrupts */
-      if((SR & status_IEc) &&
-        (controller->pending_level & ((SR >> status_IM_shift) & status_IM_mask)))
+      if(controller->pending_level > 0) /* interrupt set */
        {
-         controller->pending_level = 0;
-         SignalExceptionInterrupt();
-       }
-      else
-       {
-         /* reschedule soon */
-         hw_event_queue_schedule (me, 1, deliver_tx3904cpu_interrupt, NULL);
-       }
+         /* set hardware-interrupt subfields of CAUSE register */
+         CAUSE |= (controller->pending_level & cause_IP_mask) << cause_IP_shift;
+
+         /* check for enabled / unmasked interrupts */
+         if((SR & status_IEc) &&
+            (controller->pending_level & ((SR >> status_IM_shift) & status_IM_mask)))
+           {
+             controller->pending_level = 0;
+             SignalExceptionInterrupt(0 /* dummy value */);
+           }
+         else
+           {
+             /* reschedule soon */
+             if(controller->event != NULL)
+               hw_event_queue_deschedule(me, controller->event);
+             controller->event =
+               hw_event_queue_schedule (me, 1, deliver_tx3904cpu_interrupt, NULL);
+           }
+       } /* interrupt set */
     }
 #undef CPU cpu
 #undef SD current_state
@@ -209,7 +217,11 @@ tx3904cpu_port_event (struct hw *me,
       break;
       
     case LEVEL_PORT:
-      controller->pending_level |= level; /* accumulate bits until they are cleared */
+      /* level == 0 means that the interrupt was cleared */
+      if(level == 0)
+       controller->pending_level = -1; /* signal end of interrupt */
+      else
+       controller->pending_level = level;
       HW_TRACE ((me, "port-in level=%d", level));
       break;
       
@@ -220,11 +232,14 @@ tx3904cpu_port_event (struct hw *me,
 
   /* Schedule an event to be delivered immediately after current
      instruction. */
-  hw_event_queue_schedule (me, 0, deliver_tx3904cpu_interrupt, NULL);
+  if(controller->event != NULL)
+    hw_event_queue_deschedule(me, controller->event);
+  controller->event =
+    hw_event_queue_schedule (me, 0, deliver_tx3904cpu_interrupt, NULL);
 }
 
 
-const struct hw_device_descriptor dv_tx3904cpu_descriptor[] = {
+const struct hw_descriptor dv_tx3904cpu_descriptor[] = {
   { "tx3904cpu", tx3904cpu_finish, },
   { NULL },
 };