diff options
author | Stephane Carrez <stcarrez@nerim.fr> | 2002-03-07 18:59:38 +0000 |
---|---|---|
committer | Stephane Carrez <stcarrez@nerim.fr> | 2002-03-07 18:59:38 +0000 |
commit | 261289656f5d50f63fb39e917569b6a00ecf438d (patch) | |
tree | 03525efe846b41b4f455ba52457744ea3031a61d /sim/m68hc11/interrupts.c | |
parent | aa066ac86af343df3f305d72379378917390d391 (diff) | |
download | gdb-261289656f5d50f63fb39e917569b6a00ecf438d.zip gdb-261289656f5d50f63fb39e917569b6a00ecf438d.tar.gz gdb-261289656f5d50f63fb39e917569b6a00ecf438d.tar.bz2 |
* interrupts.c (interrupts_reset): New function, setup interrupt
vector address according to cpu mode.
(interrupts_initialize): Move reset portion to the above.
(interrupt_names): New table to give a name to interrupts.
(idefs): Handle pulse accumulator interrupts.
(interrupts_info): Print the interrupt history.
(interrupt_option_handler): New function.
(interrupt_options): New table of options.
(interrupts_update_pending): Keep track of when interrupts are
raised and implement breakpoint-on-raise-interrupt.
(interrupts_process): Keep track of when interrupts are taken
and implement breakpoint-on-interrupt.
* interrupts.h (struct interrupt_history): Define.
(struct interrupt): Keep track of the interrupt history.
(interrupts_reset): Declare.
(interrupts_initialize): Update prototype.
* m68hc11_sim.c (cpu_reset): Reset interrupts.
(cpu_initialize): Cleanup.
Diffstat (limited to 'sim/m68hc11/interrupts.c')
-rw-r--r-- | sim/m68hc11/interrupts.c | 302 |
1 files changed, 285 insertions, 17 deletions
diff --git a/sim/m68hc11/interrupts.c b/sim/m68hc11/interrupts.c index 5c7f5e2..5844c74 100644 --- a/sim/m68hc11/interrupts.c +++ b/sim/m68hc11/interrupts.c @@ -1,5 +1,5 @@ /* interrupts.c -- 68HC11 Interrupts Emulation - Copyright 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Written by Stephane Carrez (stcarrez@worldnet.fr) This file is part of GDB, GAS, and the GNU binutils. @@ -19,6 +19,43 @@ along with this file; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sim-main.h" +#include "sim-options.h" + +static const char *interrupt_names[] = { + "R1", + "R2", + "R3", + "R4", + "R5", + "R6", + "R7", + "R8", + "R9", + "R10", + "R11", + + "SCI", + "SPI", + "AINPUT", + "AOVERFLOW", + "TOVERFLOW", + "OUT5", + "OUT4", + "OUT3", + "OUT2", + "OUT1", + "INC3", + "INC2", + "INC1", + "RT", + "IRQ", + "XIRQ", + "SWI", + "ILL", + "COPRESET", + "COPFAIL", + "RESET" +}; struct interrupt_def idefs[] = { /* Serial interrupts. */ @@ -45,6 +82,10 @@ struct interrupt_def idefs[] = { { M6811_INT_INCMP1, M6811_TFLG1, M6811_IC1F, M6811_TMSK1, M6811_IC1I }, { M6811_INT_INCMP2, M6811_TFLG1, M6811_IC2F, M6811_TMSK1, M6811_IC2I }, { M6811_INT_INCMP3, M6811_TFLG1, M6811_IC3F, M6811_TMSK1, M6811_IC3I }, + + /* Pulse accumulator. */ + { M6811_INT_AINPUT, M6811_TFLG2, M6811_PAIF, M6811_TMSK2, M6811_PAII }, + { M6811_INT_AOVERFLOW,M6811_TFLG2, M6811_PAOVF, M6811_TMSK2, M6811_PAOVI}, #if 0 { M6811_INT_COPRESET, M6811_CONFIG, M6811_NOCOP, 0, 0 }, { M6811_INT_COPFAIL, M6811_CONFIG, M6811_NOCOP, 0, 0 } @@ -54,16 +95,55 @@ struct interrupt_def idefs[] = { #define TableSize(X) (sizeof X / sizeof(X[0])) #define CYCLES_MAX ((((signed64) 1) << 62) - 1) -/* Initialize the interrupts of the processor. */ -int -interrupts_initialize (struct _sim_cpu *proc) +enum +{ + OPTION_INTERRUPT_INFO = OPTION_START, + OPTION_INTERRUPT_CATCH, + OPTION_INTERRUPT_CLEAR +}; + +static DECLARE_OPTION_HANDLER (interrupt_option_handler); + +static const OPTION interrupt_options[] = +{ + { {"interrupt-info", no_argument, NULL, OPTION_INTERRUPT_INFO }, + '\0', NULL, "Print information about interrupts", + interrupt_option_handler }, + { {"interrupt-catch", required_argument, NULL, OPTION_INTERRUPT_CATCH }, + '\0', "NAME[,MODE]", + "Catch interrupts when they are raised or taken\n" + "NAME Name of the interrupt\n" + "MODE Optional mode (`taken' or `raised')", + interrupt_option_handler }, + { {"interrupt-clear", required_argument, NULL, OPTION_INTERRUPT_CLEAR }, + '\0', "NAME", "No longer catch the interrupt", + interrupt_option_handler }, + + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + +/* Initialize the interrupts module. */ +void +interrupts_initialize (SIM_DESC sd, struct _sim_cpu *proc) { struct interrupts *interrupts = &proc->cpu_interrupts; - int i; interrupts->cpu = proc; + + sim_add_option_table (sd, 0, interrupt_options); +} + +/* Initialize the interrupts of the processor. */ +void +interrupts_reset (struct interrupts *interrupts) +{ + int i; + interrupts->pending_mask = 0; - interrupts->vectors_addr = 0xffc0; + if (interrupts->cpu->cpu_mode & M6811_SMOD) + interrupts->vectors_addr = 0xbfc0; + else + interrupts->vectors_addr = 0xffc0; interrupts->nb_interrupts_raised = 0; interrupts->min_mask_cycles = CYCLES_MAX; interrupts->max_mask_cycles = 0; @@ -78,12 +158,111 @@ interrupts_initialize (struct _sim_cpu *proc) { interrupts->interrupt_order[i] = i; } - return 0; + + /* Clear the interrupt history table. */ + interrupts->history_index = 0; + memset (interrupts->interrupts_history, 0, + sizeof (interrupts->interrupts_history)); + + memset (interrupts->interrupts, 0, + sizeof (interrupts->interrupts)); +} + +static int +find_interrupt (const char *name) +{ + int i; + + if (name) + for (i = 0; i < M6811_INT_NUMBER; i++) + if (strcasecmp (name, interrupt_names[i]) == 0) + return i; + + return -1; } +static SIM_RC +interrupt_option_handler (SIM_DESC sd, sim_cpu *cpu, + int opt, char *arg, int is_command) +{ + char *p; + int mode; + int id; + struct interrupts *interrupts; + + if (cpu == 0) + cpu = STATE_CPU (sd, 0); + + interrupts = &cpu->cpu_interrupts; + switch (opt) + { + case OPTION_INTERRUPT_INFO: + for (id = 0; id < M6811_INT_NUMBER; id++) + { + sim_io_eprintf (sd, "%-10.10s ", interrupt_names[id]); + switch (interrupts->interrupts[id].stop_mode) + { + case SIM_STOP_WHEN_RAISED: + sim_io_eprintf (sd, "catch raised "); + break; + + case SIM_STOP_WHEN_TAKEN: + sim_io_eprintf (sd, "catch taken "); + break; + + case SIM_STOP_WHEN_RAISED | SIM_STOP_WHEN_TAKEN: + sim_io_eprintf (sd, "catch all "); + break; + + default: + sim_io_eprintf (sd, " "); + break; + } + sim_io_eprintf (sd, "%ld\n", + interrupts->interrupts[id].raised_count); + } + break; + + case OPTION_INTERRUPT_CATCH: + p = strchr (arg, ','); + if (p) + *p++ = 0; + + mode = SIM_STOP_WHEN_RAISED; + id = find_interrupt (arg); + if (id < 0) + sim_io_eprintf (sd, "Interrupt name not recognized: %s\n", arg); + + if (p && strcasecmp (p, "raised") == 0) + mode = SIM_STOP_WHEN_RAISED; + else if (p && strcasecmp (p, "taken") == 0) + mode = SIM_STOP_WHEN_TAKEN; + else if (p && strcasecmp (p, "all") == 0) + mode = SIM_STOP_WHEN_RAISED | SIM_STOP_WHEN_TAKEN; + else if (p) + { + sim_io_eprintf (sd, "Invalid argument: %s\n", p); + break; + } + if (id >= 0) + interrupts->interrupts[id].stop_mode = mode; + break; + + case OPTION_INTERRUPT_CLEAR: + mode = SIM_STOP_WHEN_RAISED; + id = find_interrupt (arg); + if (id < 0) + sim_io_eprintf (sd, "Interrupt name not recognized: %s\n", arg); + else + interrupts->interrupts[id].stop_mode = 0; + break; + } + + return SIM_RC_OK; +} /* Update the mask of pending interrupts. This operation must be called - when the state of some 68HC11 IO registers changes. It looks the + when the state of some 68HC11 IO register changes. It looks the different registers that indicate a pending interrupt (timer, SCI, SPI, ...) and records the interrupt if it's there and enabled. */ void @@ -132,6 +311,35 @@ interrupts_update_pending (struct interrupts *interrupts) the interrupts before setting the new ones. */ interrupts->pending_mask &= ~clear_mask; interrupts->pending_mask |= set_mask; + + /* Keep track of when the interrupt is raised by the device. + Also implements the breakpoint-on-interrupt. */ + if (set_mask) + { + signed64 cycle = cpu_current_cycle (interrupts->cpu); + int must_stop = 0; + + for (i = 0; i < M6811_INT_NUMBER; i++) + { + if (!(set_mask & (1 << i))) + continue; + + interrupts->interrupts[i].cpu_cycle = cycle; + if (interrupts->interrupts[i].stop_mode & SIM_STOP_WHEN_RAISED) + { + must_stop = 1; + sim_io_printf (CPU_STATE (interrupts->cpu), + "Interrupt %s raised\n", + interrupt_names[i]); + } + } + if (must_stop) + sim_engine_halt (CPU_STATE (interrupts->cpu), + interrupts->cpu, + 0, cpu_get_pc (interrupts->cpu), + sim_stopped, + SIM_SIGTRAP); + } } @@ -251,7 +459,21 @@ interrupts_process (struct interrupts *interrupts) if (id >= 0) { uint16 addr; - + struct interrupt_history *h; + + /* Implement the breakpoint-on-interrupt. */ + if (interrupts->interrupts[id].stop_mode & SIM_STOP_WHEN_TAKEN) + { + sim_io_printf (CPU_STATE (interrupts->cpu), + "Interrupt %s will be handled\n", + interrupt_names[id]); + sim_engine_halt (CPU_STATE (interrupts->cpu), + interrupts->cpu, + 0, cpu_get_pc (interrupts->cpu), + sim_stopped, + SIM_SIGTRAP); + } + cpu_push_all (interrupts->cpu); addr = memory_read16 (interrupts->cpu, interrupts->vectors_addr + id * 2); @@ -267,6 +489,17 @@ interrupts_process (struct interrupts *interrupts) cpu_set_ccr_I (interrupts->cpu, 1); } + /* Update the interrupt history table. */ + h = &interrupts->interrupts_history[interrupts->history_index]; + h->type = id; + h->taken_cycle = cpu_current_cycle (interrupts->cpu); + h->raised_cycle = interrupts->interrupts[id].cpu_cycle; + + if (interrupts->history_index >= MAX_INT_HISTORY-1) + interrupts->history_index = 0; + else + interrupts->history_index++; + interrupts->nb_interrupts_raised++; cpu_add_cycles (interrupts->cpu, 14); return 1; @@ -281,12 +514,11 @@ interrupts_raise (struct interrupts *interrupts, enum M6811_INT number) interrupts->nb_interrupts_raised ++; } - - void interrupts_info (SIM_DESC sd, struct interrupts *interrupts) { signed64 t; + int i; sim_io_printf (sd, "Interrupts Info:\n"); sim_io_printf (sd, " Interrupts raised: %lu\n", @@ -300,21 +532,21 @@ interrupts_info (SIM_DESC sd, struct interrupts *interrupts) if (t > interrupts->max_mask_cycles) interrupts->max_mask_cycles = t; - sim_io_printf (sd, " Current interrupts masked sequence: %s\n", + sim_io_printf (sd, " Current interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); } t = interrupts->min_mask_cycles == CYCLES_MAX ? interrupts->max_mask_cycles : interrupts->min_mask_cycles; - sim_io_printf (sd, " Shortest interrupts masked sequence: %s\n", + sim_io_printf (sd, " Shortest interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); t = interrupts->max_mask_cycles; - sim_io_printf (sd, " Longest interrupts masked sequence: %s\n", + sim_io_printf (sd, " Longest interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); t = interrupts->last_mask_cycles; - sim_io_printf (sd, " Last interrupts masked sequence: %s\n", + sim_io_printf (sd, " Last interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); if (interrupts->xirq_start_mask_cycle >= 0) @@ -332,14 +564,50 @@ interrupts_info (SIM_DESC sd, struct interrupts *interrupts) t = interrupts->xirq_min_mask_cycles == CYCLES_MAX ? interrupts->xirq_max_mask_cycles : interrupts->xirq_min_mask_cycles; - sim_io_printf (sd, " XIRQ Min interrupts masked sequence: %s\n", + sim_io_printf (sd, " XIRQ Min interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); t = interrupts->xirq_max_mask_cycles; - sim_io_printf (sd, " XIRQ Max interrupts masked sequence: %s\n", + sim_io_printf (sd, " XIRQ Max interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); t = interrupts->xirq_last_mask_cycles; sim_io_printf (sd, " XIRQ Last interrupts masked sequence: %s\n", cycle_to_string (interrupts->cpu, t)); + + if (interrupts->pending_mask) + { + sim_io_printf (sd, " Pending interrupts : "); + for (i = 0; i < M6811_INT_NUMBER; i++) + { + enum M6811_INT int_number = interrupts->interrupt_order[i]; + + if (interrupts->pending_mask & (1 << int_number)) + { + sim_io_printf (sd, "%s ", interrupt_names[int_number]); + } + } + sim_io_printf (sd, "\n"); + } + + for (i = 0; i < MAX_INT_HISTORY; i++) + { + int which; + struct interrupt_history *h; + signed64 dt; + + which = interrupts->history_index - i - 1; + if (which < 0) + which += MAX_INT_HISTORY; + h = &interrupts->interrupts_history[which]; + if (h->taken_cycle == 0) + break; + + dt = h->taken_cycle - h->raised_cycle; + sim_io_printf (sd, "%2d %-10.10s %30.30s ", i, + interrupt_names[h->type], + cycle_to_string (interrupts->cpu, h->taken_cycle)); + sim_io_printf (sd, "%s\n", + cycle_to_string (interrupts->cpu, dt)); + } } |