123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- /* This file is part of the program GDB, the GNU debugger.
-
- 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 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, see <http://www.gnu.org/licenses/>.
-
- */
- #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
- PORTS
- reset (input)
- Currently ignored.
- nmi (input)
- Deliver a non-maskable interrupt to the processor.
- level (input)
- Deliver a maskable interrupt of given level, corresponding to
- IP[5:0], to processor.
- BUGS
- When delivering an interrupt, this code assumes that there is only
- one processor (number 0).
- This code does not attempt to be efficient at handling pending
- interrupts. It simply schedules the interrupt delivery handler
- every instruction cycle until all pending interrupts go away. An
- alternative implementation might modify instructions that change
- the PSW and have them check to see if the change makes an interrupt
- delivery possible.
- */
- struct tx3904cpu {
- /* Pending interrupts for delivery by event handler */
- int pending_reset, pending_nmi, pending_level;
- struct hw_event* event;
- };
- /* input port ID's */
- enum {
- RESET_PORT,
- NMI_PORT,
- LEVEL_PORT,
- };
- static const struct hw_port_descriptor tx3904cpu_ports[] = {
- /* interrupt inputs */
- { "reset", RESET_PORT, 0, input_port, },
- { "nmi", NMI_PORT, 0, input_port, },
- { "level", LEVEL_PORT, 0, input_port, },
- { NULL, },
- };
- /* Finish off the partially created hw device. Attach our local
- callbacks. Wire up our port names etc */
- static hw_port_event_method tx3904cpu_port_event;
- static void
- tx3904cpu_finish (struct hw *me)
- {
- struct tx3904cpu *controller;
- controller = HW_ZALLOC (me, struct tx3904cpu);
- set_hw_data (me, controller);
- set_hw_ports (me, tx3904cpu_ports);
- set_hw_port_event (me, tx3904cpu_port_event);
- /* Initialize the pending interrupt flags */
- controller->pending_level = 0;
- controller->pending_reset = 0;
- controller->pending_nmi = 0;
- controller->event = NULL;
- }
- /* An event arrives on an interrupt port */
- static void
- deliver_tx3904cpu_interrupt (struct hw *me,
- void *data)
- {
- 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 = CPU_PC_GET (cpu);
- #define CPU cpu
- #define SD current_state
- if (controller->pending_reset)
- {
- controller->pending_reset = 0;
- 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) 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) 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 */
- {
- /* 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
- }
- static void
- tx3904cpu_port_event (struct hw *me,
- int my_port,
- struct hw *source,
- int source_port,
- int level)
- {
- 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)
- 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. */
- 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_descriptor dv_tx3904cpu_descriptor[] = {
- { "tx3904cpu", tx3904cpu_finish, },
- { NULL },
- };
|