📄 interrupts.c
字号:
/* interrupts.c -- 68HC11 Interrupts Emulation Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Written by Stephane Carrez (stcarrez@nerim.fr)This file is part of GDB, GAS, and the GNU binutils.GDB, GAS, and the GNU binutils are free software; you can redistributethem and/or modify them under the terms of the GNU General PublicLicense as published by the Free Software Foundation; either version1, or (at your option) any later version.GDB, GAS, and the GNU binutils are distributed in the hope that theywill be useful, but WITHOUT ANY WARRANTY; without even the impliedwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Seethe GNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this file; see the file COPYING. If not, write to the FreeSoftware 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. */ { M6811_INT_SCI, M6811_SCSR, M6811_TDRE, M6811_SCCR2, M6811_TIE }, { M6811_INT_SCI, M6811_SCSR, M6811_TC, M6811_SCCR2, M6811_TCIE }, { M6811_INT_SCI, M6811_SCSR, M6811_RDRF, M6811_SCCR2, M6811_RIE }, { M6811_INT_SCI, M6811_SCSR, M6811_IDLE, M6811_SCCR2, M6811_ILIE }, /* SPI interrupts. */ { M6811_INT_SPI, M6811_SPSR, M6811_SPIF, M6811_SPCR, M6811_SPIE }, /* Realtime interrupts. */ { M6811_INT_TCTN, M6811_TFLG2, M6811_TOF, M6811_TMSK2, M6811_TOI }, { M6811_INT_RT, M6811_TFLG2, M6811_RTIF, M6811_TMSK2, M6811_RTII }, /* Output compare interrupts. */ { M6811_INT_OUTCMP1, M6811_TFLG1, M6811_OC1F, M6811_TMSK1, M6811_OC1I }, { M6811_INT_OUTCMP2, M6811_TFLG1, M6811_OC2F, M6811_TMSK1, M6811_OC2I }, { M6811_INT_OUTCMP3, M6811_TFLG1, M6811_OC3F, M6811_TMSK1, M6811_OC3I }, { M6811_INT_OUTCMP4, M6811_TFLG1, M6811_OC4F, M6811_TMSK1, M6811_OC4I }, { M6811_INT_OUTCMP5, M6811_TFLG1, M6811_OC5F, M6811_TMSK1, M6811_OC5I }, /* Input compare interrupts. */ { 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 }#endif};#define TableSize(X) (sizeof X / sizeof(X[0]))#define CYCLES_MAX ((((signed64) 1) << 62) - 1)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. */voidinterrupts_initialize (SIM_DESC sd, struct _sim_cpu *proc){ struct interrupts *interrupts = &proc->cpu_interrupts; interrupts->cpu = proc; sim_add_option_table (sd, 0, interrupt_options);}/* Initialize the interrupts of the processor. */voidinterrupts_reset (struct interrupts *interrupts){ int i; interrupts->pending_mask = 0; 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; interrupts->last_mask_cycles = 0; interrupts->start_mask_cycle = -1; interrupts->xirq_start_mask_cycle = -1; interrupts->xirq_max_mask_cycles = 0; interrupts->xirq_min_mask_cycles = CYCLES_MAX; interrupts->xirq_last_mask_cycles = 0; for (i = 0; i < M6811_INT_NUMBER; i++) { interrupts->interrupt_order[i] = i; } /* 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)); /* In bootstrap mode, initialize the vector table to point to the RAM location. */ if (interrupts->cpu->cpu_mode == M6811_SMOD) { bfd_vma addr = interrupts->vectors_addr; uint16 vector = 0x0100 - 3 * (M6811_INT_NUMBER - 1); for (i = 0; i < M6811_INT_NUMBER; i++) { memory_write16 (interrupts->cpu, addr, vector); addr += 2; vector += 3; } }}static intfind_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_RCinterrupt_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 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. */voidinterrupts_update_pending (struct interrupts *interrupts){ int i; uint8 *ioregs; unsigned long clear_mask; unsigned long set_mask; clear_mask = 0; set_mask = 0; ioregs = &interrupts->cpu->ios[0]; for (i = 0; i < TableSize(idefs); i++) { struct interrupt_def *idef = &idefs[i]; uint8 data; /* Look if the interrupt is enabled. */ if (idef->enable_paddr) { data = ioregs[idef->enable_paddr]; if (!(data & idef->enabled_mask)) { /* Disable it. */ clear_mask |= (1 << idef->int_number); continue; } } /* Interrupt is enabled, see if it's there. */ data = ioregs[idef->int_paddr]; if (!(data & idef->int_mask)) { /* Disable it. */ clear_mask |= (1 << idef->int_number); continue; } /* Ok, raise it. */ set_mask |= (1 << idef->int_number); } /* Some interrupts are shared (M6811_INT_SCI) so clear
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -