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 }, };