X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Fmn10300%2Fdv-mn103int.c;h=3ada029c54eca0c5460dee42291fc953f8155d69;hb=9b254dd1ce46c19dde1dde5b8d1e22e862dfacce;hp=061b9b871ab8401c92e18df2dc236841c2208993;hpb=6100784a60a46ce81f1264a630cf003f74df78ce;p=deliverable%2Fbinutils-gdb.git
diff --git a/sim/mn10300/dv-mn103int.c b/sim/mn10300/dv-mn103int.c
index 061b9b871a..3ada029c54 100644
--- a/sim/mn10300/dv-mn103int.c
+++ b/sim/mn10300/dv-mn103int.c
@@ -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, 2007, 2008 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 .
*/
#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
@@ -41,12 +41,12 @@
reg =
- 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.
@@ -100,15 +100,15 @@
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 },
};