static int option_to_interrupt_nr (SIM_DESC sd, int option) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); int interrupt_nr = ((option - OPTION_WATCH_OP) % (watch->nr_interrupts + 1)); return interrupt_nr; }
static int type_to_option (SIM_DESC sd, watchpoint_type type, int interrupt_nr) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); return ((type * (watch->nr_interrupts + 1)) + interrupt_nr + OPTION_WATCH_OP); }
/* Break an option number into its op/int-nr */ static watchpoint_type option_to_type (SIM_DESC sd, int option) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); watchpoint_type type = ((option - OPTION_WATCH_OP) / (watch->nr_interrupts + 1)); SIM_ASSERT (type >= 0 && type < nr_watchpoint_types); return type; }
static const char * interrupt_nr_to_str (SIM_DESC sd, int interrupt_nr) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); if (interrupt_nr < 0) return "(invalid-interrupt)"; else if (interrupt_nr >= watch->nr_interrupts) return "breakpoint"; else return watch->interrupt_names[interrupt_nr]; }
static SIM_RC sim_watchpoint_init (SIM_DESC sd) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); sim_watch_point *point; /* NOTE: Do not need to de-schedule any previous watchpoints as sim-events has already done this */ /* schedule any watchpoints enabled by command line options */ for (point = watch->points; point != NULL; point = point->next) { schedule_watchpoint (sd, point); } return SIM_RC_OK; }
static void handle_watchpoint (SIM_DESC sd, void *data) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); sim_watch_point *point = (sim_watch_point *) data; int interrupt_nr = point->interrupt_nr; if (point->is_periodic) /* reschedule this event before processing it */ schedule_watchpoint (sd, point); else do_watchpoint_delete (sd, point->ident, invalid_watchpoint); if (point->interrupt_nr == watch->nr_interrupts) sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGINT); else watch->interrupt_handler (sd, &watch->interrupt_names[interrupt_nr]); }
static SIM_RC do_watchpoint_create (SIM_DESC sd, watchpoint_type type, int opt, char *arg) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); sim_watch_point **point; /* create the watchpoint */ point = &watch->points; while ((*point) != NULL) point = &(*point)->next; (*point) = ZALLOC (sim_watch_point); /* fill in the details */ (*point)->ident = ++(watch->last_point_nr); (*point)->type = option_to_type (sd, opt); (*point)->interrupt_nr = option_to_interrupt_nr (sd, opt); /* prefixes to arg - +== periodic, !==not or outside */ (*point)->is_within = 1; while (1) { if (arg[0] == '+') (*point)->is_periodic = 1; else if (arg[0] == '!') (*point)->is_within = 0; else break; arg++; } (*point)->arg0 = strtoul (arg, &arg, 0); if (arg[0] == ',') (*point)->arg0 = strtoul (arg, NULL, 0); else (*point)->arg1 = (*point)->arg0; /* schedule it */ schedule_watchpoint (sd, (*point)); return SIM_RC_OK; }
static void do_watchpoint_info (SIM_DESC sd) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); sim_watch_point *point; sim_io_printf (sd, "Watchpoints:\n"); for (point = watch->points; point != NULL; point = point->next) { sim_io_printf (sd, "%3d: watch %s %s ", point->ident, watchpoint_type_to_str (sd, point->type), interrupt_nr_to_str (sd, point->interrupt_nr)); if (point->is_periodic) sim_io_printf (sd, "+"); if (!point->is_within) sim_io_printf (sd, "!"); sim_io_printf (sd, "0x%lx", point->arg0); if (point->arg1 != point->arg0) sim_io_printf (sd, ",0x%lx", point->arg1); sim_io_printf (sd, "\n"); } }
static SIM_RC schedule_watchpoint (SIM_DESC sd, sim_watch_point *point) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); switch (point->type) { case pc_watchpoint: point->event = sim_events_watch_sim (sd, watch->pc, watch->sizeof_pc, 0/* host-endian */, point->is_within, point->arg0, point->arg1, /* PC in arg0..arg1 */ handle_watchpoint, point); return SIM_RC_OK; case clock_watchpoint: point->event = sim_events_watch_clock (sd, point->arg0, /* ms time */ handle_watchpoint, point); return SIM_RC_OK; case cycles_watchpoint: point->event = sim_events_schedule (sd, point->arg0, /* time */ handle_watchpoint, point); return SIM_RC_OK; default: sim_engine_abort (sd, NULL, NULL_CIA, "handle_watchpoint - internal error - bad switch"); return SIM_RC_FAIL; } return SIM_RC_OK; }
static SIM_RC do_watchpoint_delete (SIM_DESC sd, int ident, watchpoint_type type) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); sim_watch_point **entry = &watch->points; SIM_RC status = SIM_RC_FAIL; while ((*entry) != NULL) { if ((*entry)->ident == ident || (*entry)->type == type) { sim_watch_point *dead = (*entry); (*entry) = (*entry)->next; sim_events_deschedule (sd, dead->event); free (dead); status = SIM_RC_OK; } else entry = &(*entry)->next; } return status; }
SIM_RC sim_watchpoint_install (SIM_DESC sd) { sim_watchpoints *watch = STATE_WATCHPOINTS (sd); SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); /* the basic command set */ sim_module_add_init_fn (sd, sim_watchpoint_init); sim_add_option_table (sd, NULL, watchpoint_options); /* fill in some details */ if (watch->interrupt_names == NULL) watch->interrupt_names = default_interrupt_names; watch->nr_interrupts = 0; while (watch->interrupt_names[watch->nr_interrupts] != NULL) watch->nr_interrupts++; /* generate more advansed commands */ { OPTION *int_options = NZALLOC (OPTION, 1 + (watch->nr_interrupts + 1) * nr_watchpoint_types); int interrupt_nr; for (interrupt_nr = 0; interrupt_nr <= watch->nr_interrupts; interrupt_nr++) { watchpoint_type type; for (type = 0; type < nr_watchpoint_types; type++) { char *name; int nr = interrupt_nr * nr_watchpoint_types + type; OPTION *option = &int_options[nr]; if (asprintf (&name, "watch-%s-%s", watchpoint_type_to_str (sd, type), interrupt_nr_to_str (sd, interrupt_nr)) < 0) return SIM_RC_FAIL; option->opt.name = name; option->opt.has_arg = required_argument; option->opt.val = type_to_option (sd, type, interrupt_nr); option->doc = ""; option->doc_name = ""; option->handler = watchpoint_option_handler; } } /* adjust first few entries so that they contain real documentation, the first entry includes a list of actions. */ { const char *prefix = "Watch the simulator, take ACTION in COUNT cycles (`+' for every COUNT cycles), ACTION is"; char *doc; int len = strlen (prefix) + 1; for (interrupt_nr = 0; interrupt_nr <= watch->nr_interrupts; interrupt_nr++) len += strlen (interrupt_nr_to_str (sd, interrupt_nr)) + 1; doc = NZALLOC (char, len); strcpy (doc, prefix); for (interrupt_nr = 0; interrupt_nr <= watch->nr_interrupts; interrupt_nr++) { strcat (doc, " "); strcat (doc, interrupt_nr_to_str (sd, interrupt_nr)); } int_options[0].doc_name = "watch-cycles-ACTION"; int_options[0].arg = "[+]COUNT"; int_options[0].doc = doc; } int_options[1].doc_name = "watch-pc-ACTION"; int_options[1].arg = "[!]ADDRESS"; int_options[1].doc = "Watch the PC, take ACTION when matches ADDRESS (in range ADDRESS,ADDRESS), `!' negates test"; int_options[2].doc_name = "watch-clock-ACTION"; int_options[2].arg = "[+]MILLISECONDS"; int_options[2].doc = "Watch the clock, take ACTION after MILLISECONDS (`+' for every MILLISECONDS)"; sim_add_option_table (sd, NULL, int_options); } return SIM_RC_OK; }
SIM_DESC sim_open (SIM_OPEN_KIND kind, host_callback *callback, struct bfd *abfd, char **argv) { char c; int i; SIM_DESC sd = sim_state_alloc (kind, callback); /* The cpu data is kept in a separately allocated chunk of memory. */ if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK) { free_state (sd); return 0; } { /* XXX: Only first core gets profiled ? */ SIM_CPU *cpu = STATE_CPU (sd, 0); STATE_WATCHPOINTS (sd)->pc = &PCREG; STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PCREG); } if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) { free_state (sd); return 0; } /* XXX: Default to the Virtual environment. */ if (STATE_ENVIRONMENT (sd) == ALL_ENVIRONMENT) STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT; /* These options override any module options. Obviously ambiguity should be avoided, however the caller may wish to augment the meaning of an option. */ #define e_sim_add_option_table(sd, options) \ do { \ extern const OPTION options[]; \ sim_add_option_table (sd, NULL, options); \ } while (0) e_sim_add_option_table (sd, bfin_mmu_options); e_sim_add_option_table (sd, bfin_mach_options); /* getopt will print the error message so we just have to exit if this fails. FIXME: Hmmm... in the case of gdb we need getopt to call print_filtered. */ if (sim_parse_args (sd, argv) != SIM_RC_OK) { free_state (sd); return 0; } /* Allocate external memory if none specified by user. Use address 4 here in case the user wanted address 0 unmapped. */ if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0) { bu16 emuexcpt = 0x25; sim_do_commandf (sd, "memory-size 0x%lx", BFIN_DEFAULT_MEM_SIZE); sim_write (sd, 0, (void *)&emuexcpt, 2); } /* Check for/establish the a reference program image. */ if (sim_analyze_program (sd, (STATE_PROG_ARGV (sd) != NULL ? *STATE_PROG_ARGV (sd) : NULL), abfd) != SIM_RC_OK) { free_state (sd); return 0; } /* Establish any remaining configuration options. */ if (sim_config (sd) != SIM_RC_OK) { free_state (sd); return 0; } if (sim_post_argv_init (sd) != SIM_RC_OK) { free_state (sd); return 0; } /* CPU specific initialization. */ for (i = 0; i < MAX_NR_PROCESSORS; ++i) { SIM_CPU *cpu = STATE_CPU (sd, i); bfin_initialize_cpu (sd, cpu); } return sd; }
SIM_DESC sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv) { int i; SIM_DESC sd = sim_state_alloc (kind, cb); mn10300_callback = cb; SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); /* The cpu data is kept in a separately allocated chunk of memory. */ if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK) return 0; /* for compatibility */ simulator = sd; /* FIXME: should be better way of setting up interrupts. For moment, only support watchpoints causing a breakpoint (gdb halt). */ STATE_WATCHPOINTS (sd)->pc = &(PC); STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC); STATE_WATCHPOINTS (sd)->interrupt_handler = NULL; STATE_WATCHPOINTS (sd)->interrupt_names = NULL; if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) return 0; sim_add_option_table (sd, NULL, mn10300_options); /* Allocate core managed memory */ sim_do_command (sd, "memory region 0,0x100000"); sim_do_command (sd, "memory region 0x40000000,0x200000"); /* getopt will print the error message so we just have to exit if this fails. FIXME: Hmmm... in the case of gdb we need getopt to call print_filtered. */ if (sim_parse_args (sd, argv) != SIM_RC_OK) { /* Uninstall the modules to avoid memory leaks, file descriptor leaks, etc. */ sim_module_uninstall (sd); return 0; } if ( NULL != board && (strcmp(board, BOARD_AM32) == 0 ) ) { /* environment */ STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT; sim_do_command (sd, "memory region 0x44000000,0x40000"); sim_do_command (sd, "memory region 0x48000000,0x400000"); /* device support for mn1030002 */ /* interrupt controller */ sim_hw_parse (sd, "/mn103int@0x34000100/reg 0x34000100 0x7C 0x34000200 0x8 0x34000280 0x8"); /* DEBUG: NMI input's */ sim_hw_parse (sd, "/glue@0x30000000/reg 0x30000000 12"); sim_hw_parse (sd, "/glue@0x30000000 > int0 nmirq /mn103int"); sim_hw_parse (sd, "/glue@0x30000000 > int1 watchdog /mn103int"); sim_hw_parse (sd, "/glue@0x30000000 > int2 syserr /mn103int"); /* DEBUG: ACK input */ sim_hw_parse (sd, "/glue@0x30002000/reg 0x30002000 4"); sim_hw_parse (sd, "/glue@0x30002000 > int ack /mn103int"); /* DEBUG: LEVEL output */ sim_hw_parse (sd, "/glue@0x30004000/reg 0x30004000 8"); sim_hw_parse (sd, "/mn103int > nmi int0 /glue@0x30004000"); sim_hw_parse (sd, "/mn103int > level int1 /glue@0x30004000"); /* DEBUG: A bunch of interrupt inputs */ sim_hw_parse (sd, "/glue@0x30006000/reg 0x30006000 32"); sim_hw_parse (sd, "/glue@0x30006000 > int0 irq-0 /mn103int"); sim_hw_parse (sd, "/glue@0x30006000 > int1 irq-1 /mn103int"); sim_hw_parse (sd, "/glue@0x30006000 > int2 irq-2 /mn103int"); sim_hw_parse (sd, "/glue@0x30006000 > int3 irq-3 /mn103int"); sim_hw_parse (sd, "/glue@0x30006000 > int4 irq-4 /mn103int"); sim_hw_parse (sd, "/glue@0x30006000 > int5 irq-5 /mn103int"); sim_hw_parse (sd, "/glue@0x30006000 > int6 irq-6 /mn103int"); sim_hw_parse (sd, "/glue@0x30006000 > int7 irq-7 /mn103int"); /* processor interrupt device */ /* the device */ sim_hw_parse (sd, "/mn103cpu@0x20000000"); sim_hw_parse (sd, "/mn103cpu@0x20000000/reg 0x20000000 0x42"); /* DEBUG: ACK output wired upto a glue device */ sim_hw_parse (sd, "/glue@0x20002000"); sim_hw_parse (sd, "/glue@0x20002000/reg 0x20002000 4"); sim_hw_parse (sd, "/mn103cpu > ack int0 /glue@0x20002000"); /* DEBUG: RESET/NMI/LEVEL wired up to a glue device */ sim_hw_parse (sd, "/glue@0x20004000"); sim_hw_parse (sd, "/glue@0x20004000/reg 0x20004000 12"); sim_hw_parse (sd, "/glue@0x20004000 > int0 reset /mn103cpu"); sim_hw_parse (sd, "/glue@0x20004000 > int1 nmi /mn103cpu"); sim_hw_parse (sd, "/glue@0x20004000 > int2 level /mn103cpu"); /* REAL: The processor wired up to the real interrupt controller */ sim_hw_parse (sd, "/mn103cpu > ack ack /mn103int"); sim_hw_parse (sd, "/mn103int > level level /mn103cpu"); sim_hw_parse (sd, "/mn103int > nmi nmi /mn103cpu"); /* PAL */ /* the device */ sim_hw_parse (sd, "/pal@0x31000000"); sim_hw_parse (sd, "/pal@0x31000000/reg 0x31000000 64"); sim_hw_parse (sd, "/pal@0x31000000/poll? true"); /* DEBUG: PAL wired up to a glue device */ sim_hw_parse (sd, "/glue@0x31002000"); sim_hw_parse (sd, "/glue@0x31002000/reg 0x31002000 16"); sim_hw_parse (sd, "/pal@0x31000000 > countdown int0 /glue@0x31002000"); sim_hw_parse (sd, "/pal@0x31000000 > timer int1 /glue@0x31002000"); sim_hw_parse (sd, "/pal@0x31000000 > int int2 /glue@0x31002000"); sim_hw_parse (sd, "/glue@0x31002000 > int0 int3 /glue@0x31002000"); sim_hw_parse (sd, "/glue@0x31002000 > int1 int3 /glue@0x31002000"); sim_hw_parse (sd, "/glue@0x31002000 > int2 int3 /glue@0x31002000"); /* REAL: The PAL wired up to the real interrupt controller */ sim_hw_parse (sd, "/pal@0x31000000 > countdown irq-0 /mn103int"); sim_hw_parse (sd, "/pal@0x31000000 > timer irq-1 /mn103int"); sim_hw_parse (sd, "/pal@0x31000000 > int irq-2 /mn103int"); /* 8 and 16 bit timers */ sim_hw_parse (sd, "/mn103tim@0x34001000/reg 0x34001000 36 0x34001080 100 0x34004000 16"); /* Hook timer interrupts up to interrupt controller */ sim_hw_parse (sd, "/mn103tim > timer-0-underflow timer-0-underflow /mn103int"); sim_hw_parse (sd, "/mn103tim > timer-1-underflow timer-1-underflow /mn103int"); sim_hw_parse (sd, "/mn103tim > timer-2-underflow timer-2-underflow /mn103int"); sim_hw_parse (sd, "/mn103tim > timer-3-underflow timer-3-underflow /mn103int"); sim_hw_parse (sd, "/mn103tim > timer-4-underflow timer-4-underflow /mn103int"); sim_hw_parse (sd, "/mn103tim > timer-5-underflow timer-5-underflow /mn103int"); sim_hw_parse (sd, "/mn103tim > timer-6-underflow timer-6-underflow /mn103int"); sim_hw_parse (sd, "/mn103tim > timer-6-compare-a timer-6-compare-a /mn103int"); sim_hw_parse (sd, "/mn103tim > timer-6-compare-b timer-6-compare-b /mn103int"); /* Serial devices 0,1,2 */ sim_hw_parse (sd, "/mn103ser@0x34000800/reg 0x34000800 48"); sim_hw_parse (sd, "/mn103ser@0x34000800/poll? true"); /* Hook serial interrupts up to interrupt controller */ sim_hw_parse (sd, "/mn103ser > serial-0-receive serial-0-receive /mn103int"); sim_hw_parse (sd, "/mn103ser > serial-0-transmit serial-0-transmit /mn103int"); sim_hw_parse (sd, "/mn103ser > serial-1-receive serial-1-receive /mn103int"); sim_hw_parse (sd, "/mn103ser > serial-1-transmit serial-1-transmit /mn103int"); sim_hw_parse (sd, "/mn103ser > serial-2-receive serial-2-receive /mn103int"); sim_hw_parse (sd, "/mn103ser > serial-2-transmit serial-2-transmit /mn103int"); sim_hw_parse (sd, "/mn103iop@0x36008000/reg 0x36008000 8 0x36008020 8 0x36008040 0xc 0x36008060 8 0x36008080 8"); /* Memory control registers */ sim_do_command (sd, "memory region 0x32000020,0x30"); /* Cache control register */ sim_do_command (sd, "memory region 0x20000070,0x4"); /* Cache purge regions */ sim_do_command (sd, "memory region 0x28400000,0x800"); sim_do_command (sd, "memory region 0x28401000,0x800"); /* DMA registers */ sim_do_command (sd, "memory region 0x32000100,0xF"); sim_do_command (sd, "memory region 0x32000200,0xF"); sim_do_command (sd, "memory region 0x32000400,0xF"); sim_do_command (sd, "memory region 0x32000800,0xF"); } else { if (board != NULL) { sim_io_eprintf (sd, "Error: Board `%s' unknown.\n", board); return 0; } } /* check for/establish the a reference program image */ if (sim_analyze_program (sd, (STATE_PROG_ARGV (sd) != NULL ? *STATE_PROG_ARGV (sd) : NULL), abfd) != SIM_RC_OK) { sim_module_uninstall (sd); return 0; } /* establish any remaining configuration options */ if (sim_config (sd) != SIM_RC_OK) { sim_module_uninstall (sd); return 0; } if (sim_post_argv_init (sd) != SIM_RC_OK) { /* Uninstall the modules to avoid memory leaks, file descriptor leaks, etc. */ sim_module_uninstall (sd); return 0; } /* set machine specific configuration */ /* STATE_CPU (sd, 0)->psw_mask = (PSW_NP | PSW_EP | PSW_ID | PSW_SAT */ /* | PSW_CY | PSW_OV | PSW_S | PSW_Z); */ /* CPU specific initialization. */ for (i = 0; i < MAX_NR_PROCESSORS; ++i) { SIM_CPU *cpu = STATE_CPU (sd, i); CPU_PC_FETCH (cpu) = mn10300_pc_get; CPU_PC_STORE (cpu) = mn10300_pc_set; } return sd; }