aboutsummaryrefslogtreecommitdiff
path: root/sim/cris/dv-cris.c
diff options
context:
space:
mode:
authorHans-Peter Nilsson <hp@axis.com>2006-04-03 03:01:45 +0000
committerHans-Peter Nilsson <hp@axis.com>2006-04-03 03:01:45 +0000
commitaad3b3cbc1391fb0091d03b252bd53fbd1d2dd84 (patch)
treed084f6526cd6241af91f2bb5c097a86b07a71a87 /sim/cris/dv-cris.c
parent4c3a323bb9b03802339b28311c228a5152829474 (diff)
downloadgdb-aad3b3cbc1391fb0091d03b252bd53fbd1d2dd84.zip
gdb-aad3b3cbc1391fb0091d03b252bd53fbd1d2dd84.tar.gz
gdb-aad3b3cbc1391fb0091d03b252bd53fbd1d2dd84.tar.bz2
* cris/dv-cris.c, cris/dv-rv.c, cris/rvdummy.c: New files.
* cris/Makefile.in (CONFIG_DEVICES): Remove redundant setting. (dv-cris.o, dv-rv.o rvdummy$(EXEEXT), rvdummy.o): New rules. (all): Depend on rvdummy$(EXEEXT). * cris/configure.ac: Call SIM_AC_OPTION_WARNINGS. Check for sys/socket.h and sys/select.h. Call SIM_AC_OPTION_HARDWARE, default off. * cris/configure: Regenerate. * cris/cris-sim.h (cris_have_900000xxif): Declare here. (enum cris_interrupt_type, crisv10deliver_interrupt) (crisv32deliver_interrupt: New declarations. * cris/cris-tmpl.c [WITH_HW] (MY (f_model_insn_after)): Call sim_events_tickn and set state-events member work_pending when it's time for the next event. [WITH_HW] (MY (f_specific_init)): Set CPU-model-specific interrupt-delivery function. * cris/crisv10f.c (MY (deliver_interrupt)): New function. * cris/crisv32f.c (MY (deliver_interrupt)): New function. * cris/devices.c: Include hw-device.h. (device_io_read_buffer) [WITH_HW]: Call hw_io_read_buffer. (device_io_write_buffer): Only perform 0x900000xx-functions if cris_have_900000xxif is nonzero. Else if WITH_HW defined, call hw_io_write_buffer. Add return 0 last in function. * cris/sim-if.c (cris_have_900000xxif): Now global. (sim_open) [WITH_HW]: Clear deliver_interrupt cpu member. Force "-model" option, effectively. * cris/sim-main.h (cris_interrupt_delivery_fn): New type. (struct _sim_cpu) [WITH_HW]: New member deliver_interrupt.
Diffstat (limited to 'sim/cris/dv-cris.c')
-rw-r--r--sim/cris/dv-cris.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/sim/cris/dv-cris.c b/sim/cris/dv-cris.c
new file mode 100644
index 0000000..b98a6b7
--- /dev/null
+++ b/sim/cris/dv-cris.c
@@ -0,0 +1,314 @@
+/* The CRIS interrupt framework for GDB, the GNU Debugger.
+
+ Copyright 2006 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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
+ (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. */
+
+#include "sim-main.h"
+#include "hw-main.h"
+
+/* DEVICE
+
+ CRIS cpu virtual device (very rudimental; generic enough for all
+ currently used CRIS versions).
+
+
+ DESCRIPTION
+
+ Implements the external CRIS functionality. This includes the
+ delivery of interrupts generated from other devices.
+
+
+ PROPERTIES
+
+ vec-for-int = <int-a> <vec-a> <int-b> <vec-b> ...
+ These are the translations to interrupt vector for values appearing
+ on the "int" port, as pairs of the value and the corresponding
+ vector. Defaults to no translation. All values that may appear on
+ the "int" port must be defined, or the device aborts.
+
+ multiple-int = ("abort" | "ignore_previous" | <vector>)
+ If multiple interrupt values are dispatched, this property decides
+ what to do. The value is either a number corresponding to the
+ vector to use, or the string "abort" to cause a hard abort, or the
+ string "ignore_previous", to silently use the new vector instead.
+ The default is "abort".
+
+
+ PORTS
+
+ int (input)
+ Interrupt port. An event with a non-zero value on this port causes
+ an interrupt. If, after an event but before the interrupt has been
+ properly dispatched, a non-zero value appears that is different
+ after mapping than the previous, then the property multiple_int
+ decides what to do.
+
+ FIXME: reg port so internal registers can be read. Requires
+ chip-specific versions, though. Ports "nmi" and "reset".
+
+
+ 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.
+ It also works around a bug in sim_events_process when doing so.
+ */
+
+/* Keep this an enum for simple addition of "reset" and "nmi". */
+enum
+ {
+ INT_PORT,
+ };
+
+static const struct hw_port_descriptor cris_ports[] =
+ {
+ { "int", INT_PORT, 0, input_port },
+ { NULL, 0, 0, 0 }
+ };
+
+struct cris_vec_tr
+ {
+ unsigned32 portval, vec;
+ };
+
+enum cris_multiple_ints
+ {
+ cris_multint_abort,
+ cris_multint_ignore_previous,
+ cris_multint_vector
+ };
+
+struct cris_hw
+ {
+ struct hw_event *pending_handler;
+ unsigned32 pending_vector;
+ struct cris_vec_tr *int_to_vec;
+ enum cris_multiple_ints multi_int_action;
+ unsigned32 multiple_int_vector;
+ };
+
+/* An event function, calling the actual CPU-model-specific
+ interrupt-delivery function. */
+
+static void
+deliver_cris_interrupt (struct hw *me, void *data)
+{
+ struct cris_hw *crishw = hw_data (me);
+ SIM_DESC simulator = hw_system (me);
+ sim_cpu *cpu = STATE_CPU (simulator, 0);
+ unsigned int intno = crishw->pending_vector;
+
+ if (CPU_CRIS_DELIVER_INTERRUPT (cpu) (cpu, CRIS_INT_INT, intno))
+ {
+ crishw->pending_vector = 0;
+ crishw->pending_handler = NULL;
+ return;
+ }
+
+ {
+ /* Bug workaround: at time T with a pending number of cycles N to
+ process, if re-scheduling an event at time T+M, M < N,
+ sim_events_process gets stuck at T (updating the "time" to
+ before the event rather than after the event, or somesuch).
+
+ Hacking this locally is thankfully easy: if we see the same
+ simulation time, increase the number of cycles. Do this every
+ time we get here, until a new time is seen (supposedly unstuck
+ re-delivery). (Fixing in SIM/GDB source will hopefully then
+ also be easier, having a tangible test-case.) */
+ static signed64 last_events_time = 0;
+ static signed64 delta = 1;
+ signed64 this_events_time = hw_event_queue_time (me);
+
+ if (this_events_time == last_events_time)
+ delta++;
+ else
+ {
+ delta = 1;
+ last_events_time = this_events_time;
+ }
+
+ crishw->pending_handler
+ = hw_event_queue_schedule (me, delta, deliver_cris_interrupt, NULL);
+ }
+}
+
+
+/* A port-event function for events arriving to an interrupt port. */
+
+static void
+cris_port_event (struct hw *me,
+ int my_port,
+ struct hw *source,
+ int source_port,
+ int intparam)
+{
+ struct cris_hw *crishw = hw_data (me);
+ unsigned32 vec;
+
+ /* A few placeholders; only the INT port is implemented. */
+ switch (my_port)
+ {
+ case INT_PORT:
+ HW_TRACE ((me, "INT value=0x%x", intparam));
+ break;
+
+ default:
+ hw_abort (me, "bad switch");
+ break;
+ }
+
+ if (intparam == 0)
+ return;
+
+ if (crishw->int_to_vec != NULL)
+ {
+ unsigned int i;
+ for (i = 0; crishw->int_to_vec[i].portval != 0; i++)
+ if (crishw->int_to_vec[i].portval == intparam)
+ break;
+
+ if (crishw->int_to_vec[i].portval == 0)
+ hw_abort (me, "unsupported value for int port: 0x%x", intparam);
+
+ vec = crishw->int_to_vec[i].vec;
+ }
+ else
+ vec = (unsigned32) intparam;
+
+ if (crishw->pending_vector != 0)
+ {
+ if (vec == crishw->pending_vector)
+ return;
+
+ switch (crishw->multi_int_action)
+ {
+ case cris_multint_abort:
+ hw_abort (me, "int 0x%x (0x%x) while int 0x%x hasn't been delivered",
+ vec, intparam, crishw->pending_vector);
+ break;
+
+ case cris_multint_ignore_previous:
+ break;
+
+ case cris_multint_vector:
+ vec = crishw->multiple_int_vector;
+ break;
+
+ default:
+ hw_abort (me, "bad switch");
+ }
+ }
+
+ crishw->pending_vector = vec;
+
+ /* Schedule our event handler *now*. */
+ if (crishw->pending_handler == NULL)
+ crishw->pending_handler
+ = hw_event_queue_schedule (me, 0, deliver_cris_interrupt, NULL);
+}
+
+/* Instance initializer function. */
+
+static void
+cris_finish (struct hw *me)
+{
+ struct cris_hw *crishw;
+ const struct hw_property *vec_for_int;
+ const struct hw_property *multiple_int;
+
+ crishw = HW_ZALLOC (me, struct cris_hw);
+ set_hw_data (me, crishw);
+ set_hw_ports (me, cris_ports);
+ set_hw_port_event (me, cris_port_event);
+
+ vec_for_int = hw_find_property (me, "vec-for-int");
+ if (vec_for_int != NULL)
+ {
+ unsigned32 vecsize;
+ unsigned32 i;
+
+ if (hw_property_type (vec_for_int) != array_property)
+ hw_abort (me, "property \"vec-for-int\" has the wrong type");
+
+ vecsize = hw_property_sizeof_array (vec_for_int) / sizeof (signed_cell);
+
+ if ((vecsize % 2) != 0)
+ hw_abort (me, "translation vector does not consist of even pairs");
+
+ crishw->int_to_vec
+ = hw_malloc (me, (vecsize/2 + 1) * sizeof (crishw->int_to_vec[0]));
+
+ for (i = 0; i < vecsize/2; i++)
+ {
+ signed_cell portval_sc;
+ signed_cell vec_sc;
+
+ if (!hw_find_integer_array_property (me, "vec-for-int", i*2,
+ &portval_sc)
+ || !hw_find_integer_array_property (me, "vec-for-int", i*2 + 1,
+ &vec_sc)
+ || portval_sc < 0
+ || vec_sc < 0)
+ hw_abort (me, "no valid vector translation pair %u", i);
+
+ crishw->int_to_vec[i].portval = (unsigned32) portval_sc;
+ crishw->int_to_vec[i].vec = (unsigned32) vec_sc;
+ }
+
+ crishw->int_to_vec[i].portval = 0;
+ crishw->int_to_vec[i].vec = 0;
+ }
+
+ multiple_int = hw_find_property (me, "multiple-int");
+ if (multiple_int != NULL)
+ {
+ if (hw_property_type (multiple_int) == integer_property)
+ {
+ crishw->multiple_int_vector
+ = hw_find_integer_property (me, "multiple-int");
+ crishw->multi_int_action = cris_multint_vector;
+ }
+ else
+ {
+ const char *action = hw_find_string_property (me, "multiple-int");
+
+ if (action == NULL)
+ hw_abort (me, "property \"multiple-int\" has the wrong type");
+
+ if (strcmp (action, "abort") == 0)
+ crishw->multi_int_action = cris_multint_abort;
+ else if (strcmp (action, "ignore_previous") == 0)
+ crishw->multi_int_action = cris_multint_ignore_previous;
+ else
+ hw_abort (me, "property \"multiple-int\" must be one of <vector number>\n"
+ "\"abort\" and \"ignore_previous\", not \"%s\"", action);
+ }
+ }
+ else
+ crishw->multi_int_action = cris_multint_abort;
+}
+
+const struct hw_descriptor dv_cris_descriptor[] = {
+ { "cris", cris_finish, },
+ { NULL },
+};