/* This file is part of the program GDB, the GNU debugger.
-
- Copyright (C) 1998 Free Software Foundation, Inc.
+
+ Copyright (C) 1998-2022 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/>.
+
*/
+/* This must come before any other includes. */
+#include "defs.h"
#include "sim-main.h"
#include "hw-main.h"
/* DEVICE
-
+
tx3904cpu - tx3904 cpu virtual device
-
+
DESCRIPTION
-
+
Implements the external tx3904 functionality. This includes the
delivery of of interrupts generated from other devices and the
handling of device specific registers.
PROPERTIES
-
+
none
struct tx3904cpu {
/* Pending interrupts for delivery by event handler */
int pending_reset, pending_nmi, pending_level;
+ struct hw_event* event;
};
-/* input port ID's */
+/* input port ID's */
enum {
RESET_PORT,
controller->pending_level = 0;
controller->pending_reset = 0;
controller->pending_nmi = 0;
+ controller->event = NULL;
}
struct tx3904cpu *controller = hw_data (me);
SIM_DESC sd = hw_system (me);
sim_cpu *cpu = STATE_CPU (sd, 0); /* NB: fix CPU 0. */
- address_word cia = CIA_GET (cpu);
+ address_word cia = CPU_PC_GET (cpu);
#define CPU cpu
-#define SD current_state
+#define SD sd
if (controller->pending_reset)
{
controller->pending_reset = 0;
- HW_TRACE ((me, "reset pc=0x%08lx", (long) CIA_GET (cpu)));
+ HW_TRACE ((me, "reset pc=0x%08lx", (long) CPU_PC_GET (cpu)));
SignalExceptionNMIReset();
}
else if (controller->pending_nmi)
{
controller->pending_nmi = 0;
- HW_TRACE ((me, "nmi pc=0x%08lx", (long) CIA_GET (cpu)));
+ HW_TRACE ((me, "nmi pc=0x%08lx", (long) CPU_PC_GET (cpu)));
SignalExceptionNMIReset();
}
else if (controller->pending_level)
{
HW_TRACE ((me, "interrupt level=%d pc=0x%08lx sr=0x%08lx",
controller->pending_level,
- (long) CIA_GET (cpu), (long) SR));
+ (long) CPU_PC_GET (cpu), (long) SR));
/* 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);
- if(controller->pending_level > 0) /* interrupt set */
+ if (controller->pending_level > 0) /* interrupt set */
{
/* 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) &&
+ if ((SR & status_IEc) &&
(controller->pending_level & ((SR >> status_IM_shift) & status_IM_mask)))
{
controller->pending_level = 0;
- SignalExceptionInterrupt();
+ SignalExceptionInterrupt(0 /* dummy value */);
}
else
{
/* reschedule soon */
- hw_event_queue_schedule (me, 1, deliver_tx3904cpu_interrupt, NULL);
+ 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
+#undef CPU
+#undef SD
}
struct tx3904cpu *controller = hw_data (me);
switch (my_port)
- {
+ {
case RESET_PORT:
controller->pending_reset = 1;
HW_TRACE ((me, "port-in reset"));
break;
-
+
case NMI_PORT:
controller->pending_nmi = 1;
HW_TRACE ((me, "port-in nmi"));
break;
-
+
case LEVEL_PORT:
/* level == 0 means that the interrupt was cleared */
- if(level == 0)
+ 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;
-
+
default:
hw_abort (me, "bad switch");
break;
/* 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);
}