diff options
author | David Edelsohn <dje.gcc@gmail.com> | 1997-04-17 10:54:07 +0000 |
---|---|---|
committer | David Edelsohn <dje.gcc@gmail.com> | 1997-04-17 10:54:07 +0000 |
commit | 1ad886c9280e0ba6c567a88cab30a0fa94edf517 (patch) | |
tree | e215e1b26cfee4a75662334250500984469510d5 | |
parent | 1d77e69d4a314da4c5b0e63d6eecd083cd3c5d52 (diff) | |
download | gdb-1ad886c9280e0ba6c567a88cab30a0fa94edf517.zip gdb-1ad886c9280e0ba6c567a88cab30a0fa94edf517.tar.gz gdb-1ad886c9280e0ba6c567a88cab30a0fa94edf517.tar.bz2 |
* Makefile.in (SIM_OBJS): Add sim-load.o.
* interp.c (sim_kind, myname): New static locals.
(sim_open): Set sim_kind, myname. Ignore -E arg.
(sim_load): Return SIM_RC. New arg abfd. Call sim_load_file to
load file into simulator. Set start address from bfd.
(sim_create_inferior): Return SIM_RC. Delete arg start_address.
-rw-r--r-- | sim/v850/ChangeLog | 9 | ||||
-rw-r--r-- | sim/v850/interp.c | 751 |
2 files changed, 649 insertions, 111 deletions
diff --git a/sim/v850/ChangeLog b/sim/v850/ChangeLog index 79e5593..72d507d 100644 --- a/sim/v850/ChangeLog +++ b/sim/v850/ChangeLog @@ -1,3 +1,12 @@ +Thu Apr 17 03:53:18 1997 Doug Evans <dje@canuck.cygnus.com> + + * Makefile.in (SIM_OBJS): Add sim-load.o. + * interp.c (sim_kind, myname): New static locals. + (sim_open): Set sim_kind, myname. Ignore -E arg. + (sim_load): Return SIM_RC. New arg abfd. Call sim_load_file to + load file into simulator. Set start address from bfd. + (sim_create_inferior): Return SIM_RC. Delete arg start_address. + Wed Apr 16 19:53:55 1997 Andrew Cagney <cagney@b1.cygnus.com> * simops.c (OP_10007E0): Only provide system calls SYS_execv, diff --git a/sim/v850/interp.c b/sim/v850/interp.c index 77b7c66..d1aa8eb 100644 --- a/sim/v850/interp.c +++ b/sim/v850/interp.c @@ -1,11 +1,61 @@ #include <signal.h> #include "sysdep.h" #include "bfd.h" -#include "remote-sim.h" -#include "callback.h" #include "v850_sim.h" +enum interrupt_type +{ + int_none, + int_reset, + int_nmi, + int_intov1, + int_intp10, + int_intp11, + int_intp12, + int_intp13, + int_intcm4, + num_int_types +}; + +enum interrupt_cond_type +{ + int_cond_none, + int_cond_pc, + int_cond_time +}; + +struct interrupt_generator +{ + enum interrupt_type type; + enum interrupt_cond_type cond_type; + int number; + int address; + int time; + int enabled; + struct interrupt_generator *next; +}; + +char *interrupt_names[] = { + "", + "reset", + "nmi", + "intov1", + "intp10", + "intp11", + "intp12", + "intp13", + "intcm4", + NULL +}; + +struct interrupt_generator *intgen_list; + +/* True if a non-maskable (such as NMI or reset) interrupt generator + is present. */ + +static int have_nm_generator; + #ifndef INLINE #ifdef __GNUC__ #define INLINE inline @@ -14,11 +64,20 @@ #endif #endif -#define MEM_SIZE 18 /* V850 memory size is 18 bits XXX */ +/* These default values correspond to expected usage for the chip. */ + +SIM_ADDR rom_size = 0x8000; +SIM_ADDR low_end = 0x200000; +SIM_ADDR high_start = 0xffe000; + +SIM_ADDR high_base; host_callback *v850_callback; + int v850_debug; +static SIM_OPEN_KIND sim_kind; +static char *myname; uint32 OP[4]; @@ -35,6 +94,7 @@ static void do_format_9_10 PARAMS ((uint32)); static void init_system PARAMS ((void)); #define MAX_HASH 63 + struct hash_entry { struct hash_entry *next; @@ -55,12 +115,15 @@ hash(insn) || (insn & 0x0700) == 0x0600 || (insn & 0x0780) == 0x0700) return (insn & 0x07e0) >> 5; + if ((insn & 0x0700) == 0x0300 || (insn & 0x0700) == 0x0400 || (insn & 0x0700) == 0x0500) return (insn & 0x0780) >> 7; + if ((insn & 0x07c0) == 0x0780) return (insn & 0x07c0) >> 6; + return (insn & 0x07e0) >> 5; } @@ -76,7 +139,7 @@ lookup_hash (ins) { if (h->next == NULL) { - (*v850_callback->printf_filtered) (v850_callback, "ERROR looking up hash for %x\n", ins); + (*v850_callback->printf_filtered) (v850_callback, "ERROR looking up hash for 0x%x, PC=0x%x\n", ins, PC); exit(1); } h = h->next; @@ -84,6 +147,9 @@ lookup_hash (ins) return (h); } +/* FIXME These would more efficient to use than load_mem/store_mem, + but need to be changed to use the memory map. */ + uint8 get_byte (x) uint8 *x; @@ -138,6 +204,92 @@ put_word (addr, data) a[3] = (data >> 24) & 0xff; } +uint8 * +map (addr) + SIM_ADDR addr; +{ + uint8 *p; + + /* Mask down to 24 bits. */ + addr &= 0xffffff; + + if (addr < low_end) + { + /* "Mirror" the addresses below 1MB. */ + if (addr < 0x100000) + addr &= (rom_size - 1); + else + addr += (rom_size - 0x100000); + return (uint8 *) (addr + State.mem); + } + else if (addr >= high_start) + { + /* If in the peripheral I/O region, mirror 1K region across 4K, + and similarly if in the internal RAM region. */ + if (addr >= 0xfff000) + addr &= 0xfff3ff; + else if (addr >= 0xffe000) + addr &= 0xffe3ff; + return (uint8 *) (addr - high_start + high_base + State.mem); + } + else + { + /* Signal a memory error. */ + State.exception = SIGSEGV; + /* Point to a location not in main memory - renders invalid + addresses harmless until we get back to main insn loop. */ + return (uint8 *) &(State.dummy_mem); + } +} + +uint32 +load_mem (addr, len) + SIM_ADDR addr; + int len; +{ + uint8 *p = map (addr); + + switch (len) + { + case 1: + return p[0]; + case 2: + return p[1] << 8 | p[0]; + case 4: + return p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0]; + default: + abort (); + } +} + +void +store_mem (addr, len, data) + SIM_ADDR addr; + int len; + uint32 data; +{ + uint8 *p = map (addr); + + switch (len) + { + case 1: + p[0] = data; + return; + case 2: + p[0] = data; + p[1] = data >> 8; + return; + case 4: + p[0] = data; + p[1] = data >> 8; + p[2] = data >> 16; + p[3] = data >> 24; + return; + default: + abort (); + } +} + static void do_format_1_2 (insn) uint32 insn; @@ -241,19 +393,82 @@ sim_size (power) int power; { + int totsize; + if (State.mem) + free (State.mem); + + totsize = rom_size + (low_end - 0x100000) + (0x1000000 - high_start); + + high_base = rom_size + (low_end - 0x100000); + + State.mem = (uint8 *) calloc (1, totsize); + if (!State.mem) { - free (State.mem); + (*v850_callback->printf_filtered) (v850_callback, "Allocation of main memory failed.\n"); + exit (1); } +} - State.mem = (uint8 *)calloc(1,1<<MEM_SIZE); - if (!State.mem) +void +sim_set_memory_map (spec) + char *spec; +{ + char *reststr, *nreststr; + SIM_ADDR new_low_end, new_high_start; + + new_low_end = low_end; + new_high_start = high_start; + if (! strncmp (spec, "hole=", 5)) { - (*v850_callback->printf_filtered) (v850_callback, "Memory allocation failed.\n"); - exit(1); + new_low_end = sim_parse_number (spec + 5, &reststr); + if (new_low_end < 0x100000) + { + (*v850_callback->printf_filtered) (v850_callback, + "Low end must be at least 0x100000\n"); + return; + } + if (*reststr == ',') + { + ++reststr; + new_high_start = sim_parse_number (reststr, &nreststr); + /* FIXME Check high_start also */ + } + (*v850_callback->printf_filtered) (v850_callback, + "Hole goes from 0x%x to 0x%x\n", + new_low_end, new_high_start); + } + else + { + (*v850_callback->printf_filtered) (v850_callback, "Invalid specification for memory map, must be `hole=<m>[,<n>]'\n"); + } + + if (new_low_end != low_end || new_high_start != high_start) + { + low_end = new_low_end; + high_start = new_high_start; + if (State.mem) + { + (*v850_callback->printf_filtered) (v850_callback, "Reconfiguring memory (old contents will be lost)\n"); + sim_size (1); + } } } +/* Parse a number in hex, octal, or decimal form. */ + +int +sim_parse_number (str, rest) + char *str, **rest; +{ + if (str[0] == '0' && str[1] == 'x') + return strtol (str, rest, 16); + else if (str[0] == '0') + return strtol (str, rest, 16); + else + return strtol (str, rest, 10); +} + static void init_system () { @@ -262,35 +477,45 @@ init_system () } int -sim_write (addr, buffer, size) +sim_write (sd, addr, buffer, size) + SIM_DESC sd; SIM_ADDR addr; unsigned char *buffer; int size; { int i; + init_system (); for (i = 0; i < size; i++) - { - State.mem[i+addr] = buffer[i]; - } + store_mem (addr + i, 1, buffer[i]); + return size; } -void -sim_open (args) - char *args; +SIM_DESC +sim_open (kind,argv) + SIM_OPEN_KIND kind; + char **argv; { struct simops *s; struct hash_entry *h; - if (args != NULL) + char **p; + + sim_kind = kind; + myname = argv[0]; + + for (p = argv + 1; *p; ++p) { + if (strcmp (*p, "-E") == 0) + ++p; /* ignore endian spec */ + else #ifdef DEBUG - if (strcmp (args, "-t") == 0) + if (strcmp (*p, "-t") == 0) v850_debug = DEBUG; else #endif - (*v850_callback->printf_filtered) (v850_callback, "ERROR: unsupported option(s): %s\n",args); + (*v850_callback->printf_filtered) (v850_callback, "ERROR: unsupported option(s): %s\n",*p); } /* put all the opcodes in the hash table */ @@ -304,18 +529,22 @@ sim_open (args) if (h->ops) { - h->next = calloc(1,sizeof(struct hash_entry)); + h->next = (struct hash_entry *) calloc(1,sizeof(struct hash_entry)); h = h->next; } h->ops = s; h->mask = s->mask; h->opcode = s->opcode; } + + /* fudge our descriptor for now */ + return (SIM_DESC) 1; } void -sim_close (quitting) +sim_close (sd, quitting) + SIM_DESC sd; int quitting; { /* nothing to do */ @@ -335,111 +564,229 @@ sim_set_profile_size (n) (*v850_callback->printf_filtered) (v850_callback, "sim_set_profile_size %d\n", n); } +time_t start_time; + +static void do_interrupt PARAMS ((enum interrupt_type)); + void -sim_resume (step, siggnal) +sim_resume (sd, step, siggnal) + SIM_DESC sd; int step, siggnal; { uint32 inst, opcode; reg_t oldpc; + struct interrupt_generator *intgen; + time_t now; - PC = State.sregs[0]; + if (step) + State.exception = SIGTRAP; + else + State.exception = 0; - if (step) - State.exception = SIGTRAP; - else - State.exception = 0; - - do - { - inst = RLW (PC); - oldpc = PC; - opcode = (inst & 0x07e0) >> 5; - if ((opcode & 0x30) == 0 - || (opcode & 0x38) == 0x10) - { - do_format_1_2 (inst & 0xffff); - PC += 2; - } - else if ((opcode & 0x3C) == 0x18 - || (opcode & 0x3C) == 0x1C - || (opcode & 0x3C) == 0x20 - || (opcode & 0x3C) == 0x24 - || (opcode & 0x3C) == 0x28) - { - do_format_4 (inst & 0xffff); - PC += 2; - } - else if ((opcode & 0x3C) == 0x2C) - { - do_format_3 (inst & 0xffff); - /* No PC update, it's done in the instruction. */ - } - else if ((opcode & 0x38) == 0x30) - { - do_format_6 (inst); - PC += 4; - } - else if ((opcode & 0x3C) == 0x38) - { - do_format_7 (inst); - PC += 4; - } - else if ((opcode & 0x3E) == 0x3C) - { - do_format_5 (inst); - /* No PC update, it's done in the instruction. */ - } - else if ((opcode & 0x3F) == 0x3E) - { - do_format_8 (inst); - PC += 4; - } - else - { - do_format_9_10 (inst); - PC += 4; - } - } - while (!State.exception); - - State.sregs[0] = PC; + time (&start_time); + + do + { + /* Fetch the current instruction. */ + inst = RLW (PC); + oldpc = PC; + opcode = (inst & 0x07e0) >> 5; + + /* Decode the opcode field. */ + if ((opcode & 0x30) == 0 + || (opcode & 0x38) == 0x10) + { + do_format_1_2 (inst & 0xffff); + PC += 2; + } + else if ((opcode & 0x3C) == 0x18 + || (opcode & 0x3C) == 0x1C + || (opcode & 0x3C) == 0x20 + || (opcode & 0x3C) == 0x24 + || (opcode & 0x3C) == 0x28) + { + do_format_4 (inst & 0xffff); + PC += 2; + } + else if ((opcode & 0x3C) == 0x2C) + { + do_format_3 (inst & 0xffff); + /* No PC update, it's done in the instruction. */ + } + else if ((opcode & 0x38) == 0x30) + { + do_format_6 (inst); + PC += 4; + } + else if ((opcode & 0x3C) == 0x38) + { + do_format_7 (inst); + PC += 4; + } + else if ((opcode & 0x3E) == 0x3C) + { + do_format_5 (inst); + /* No PC update, it's done in the instruction. */ + } + else if ((opcode & 0x3F) == 0x3E) + { + do_format_8 (inst); + PC += 4; + } + else + { + do_format_9_10 (inst); + PC += 4; + } + + /* Check for and handle pending interrupts. */ + if (intgen_list && (have_nm_generator || !(PSW & PSW_ID))) + { + intgen = NULL; + for (intgen = intgen_list; intgen != NULL; intgen = intgen->next) + { + if (intgen->cond_type == int_cond_pc + && oldpc == intgen->address + && intgen->enabled) + { + break; + } + else if (intgen->cond_type == int_cond_time + && intgen->enabled) + { + time (&now); + if (((long) now - (long) start_time) > intgen->time) + { + intgen->enabled = 0; + break; + } + } + } + if (intgen) + do_interrupt (intgen->type); + } + else if (State.pending_nmi) + { + State.pending_nmi = 0; + do_interrupt (int_nmi); + } + } + while (!State.exception); +} + +static void +do_interrupt (inttype) + enum interrupt_type inttype; +{ + /* Disable further interrupts. */ + PSW |= PSW_ID; + /* Indicate that we're doing interrupt not exception processing. */ + PSW &= ~PSW_EP; + if (inttype == int_reset) + { + PC = 0; + PSW = 0x20; + ECR = 0; + /* (Might be useful to init other regs with random values.) */ + } + else if (inttype == int_nmi) + { + if (PSW & PSW_NP) + { + /* We're already working on an NMI, so this one must wait + around until the previous one is done. The processor + ignores subsequent NMIs, so we don't need to count them. */ + State.pending_nmi = 1; + } + else + { + FEPC = PC; + FEPSW = PSW; + /* Set the FECC part of the ECR. */ + ECR &= 0x0000ffff; + ECR |= 0x10; + PSW |= PSW_NP; + PC = 0x10; + } + } + else + { + EIPC = PC; + EIPSW = PSW; + /* Clear the EICC part of the ECR, will set below. */ + ECR &= 0xffff0000; + switch (inttype) + { + case int_intov1: + PC = 0x80; + ECR |= 0x80; + break; + case int_intp10: + PC = 0x90; + ECR |= 0x90; + break; + case int_intp11: + PC = 0xa0; + ECR |= 0xa0; + break; + case int_intp12: + PC = 0xb0; + ECR |= 0xb0; + break; + case int_intp13: + PC = 0xc0; + ECR |= 0xc0; + break; + case int_intcm4: + PC = 0xd0; + ECR |= 0xd0; + break; + default: + /* Should never be possible. */ + abort (); + break; + } + } } int -sim_trace () +sim_trace (sd) + SIM_DESC sd; { #ifdef DEBUG v850_debug = DEBUG; #endif - sim_resume (0, 0); + sim_resume (sd, 0, 0); return 1; } void -sim_info (verbose) +sim_info (sd, verbose) + SIM_DESC sd; int verbose; { (*v850_callback->printf_filtered) (v850_callback, "sim_info\n"); } -void -sim_create_inferior (start_address, argv, env) - SIM_ADDR start_address; +SIM_RC +sim_create_inferior (sd, argv, env) + SIM_DESC sd; char **argv; char **env; { - PC = start_address; + return SIM_RC_OK; } - void -sim_kill () +sim_kill (sd) + SIM_DESC sd; { /* nothing to do */ } void -sim_set_callbacks(p) +sim_set_callbacks (sd, p) + SIM_DESC sd; host_callback *p; { v850_callback = p; @@ -448,21 +795,28 @@ sim_set_callbacks(p) /* All the code for exiting, signals, etc needs to be revamped. This is enough to get c-torture limping though. */ + void -sim_stop_reason (reason, sigrc) +sim_stop_reason (sd, reason, sigrc) + SIM_DESC sd; enum sim_stop *reason; int *sigrc; { - - *reason = sim_stopped; - if (State.exception == SIGQUIT) - *sigrc = 0; + if (State.exception == SIG_V850_EXIT) + { + *reason = sim_exited; + *sigrc = State.regs[7]; + } else - *sigrc = State.exception; + { + *reason = sim_stopped; + *sigrc = State.exception; + } } void -sim_fetch_register (rn, memory) +sim_fetch_register (sd, rn, memory) + SIM_DESC sd; int rn; unsigned char *memory; { @@ -470,7 +824,8 @@ sim_fetch_register (rn, memory) } void -sim_store_register (rn, memory) +sim_store_register (sd, rn, memory) + SIM_DESC sd; int rn; unsigned char *memory; { @@ -478,31 +833,205 @@ sim_store_register (rn, memory) } int -sim_read (addr, buffer, size) +sim_read (sd, addr, buffer, size) + SIM_DESC sd; SIM_ADDR addr; unsigned char *buffer; int size; { int i; for (i = 0; i < size; i++) - { - buffer[i] = State.mem[addr + i]; - } + buffer[i] = load_mem (addr + i, 1); + return size; } +int current_intgen_number = 1; + void -sim_do_command (cmd) +sim_set_interrupt (spec) + char *spec; +{ + int i, num; + char **argv; + struct interrupt_generator *intgen, *tmpgen; + extern char **buildargv (); + + argv = buildargv (spec); + + if (*argv && ! strcmp (*argv, "add")) + { + /* Create a new interrupt generator object. */ + intgen = (struct interrupt_generator *) + malloc (sizeof(struct interrupt_generator)); + intgen->type = int_none; + intgen->cond_type = int_cond_none; + intgen->address = 0; + intgen->time = 0; + intgen->enabled = 0; + ++argv; + /* Match on interrupt type name. */ + for (i = 0; i < num_int_types; ++i) + { + if (*argv && ! strcmp (*argv, interrupt_names[i])) + { + intgen->type = i; + break; + } + } + if (intgen->type == int_none) + { + (*v850_callback->printf_filtered) (v850_callback, "Interrupt type unknown; known types are\n"); + for (i = 0; i < num_int_types; ++i) + { + (*v850_callback->printf_filtered) (v850_callback, " %s", interrupt_names[i]); + } + (*v850_callback->printf_filtered) (v850_callback, "\n"); + free (intgen); + return; + } + ++argv; + intgen->address = 0; + intgen->time = 0; + if (*argv && ! strcmp (*argv, "pc")) + { + intgen->cond_type = int_cond_pc; + ++argv; + intgen->address = sim_parse_number (*argv, NULL); + } + else if (*argv && ! strcmp (*argv, "time")) + { + intgen->cond_type = int_cond_time; + ++argv; + intgen->time = sim_parse_number (*argv, NULL); + } + else + { + (*v850_callback->printf_filtered) (v850_callback, "Condition type must be `pc' or `time'.\n"); + free (intgen); + return; + } + /* We now have a valid interrupt generator. Number it and add + to the list of generators. */ + intgen->number = current_intgen_number++; + intgen->enabled = 1; + intgen->next = intgen_list; + intgen_list = intgen; + (*v850_callback->printf_filtered) (v850_callback, "Interrupt generator %d (NMI) at pc=0x%x, time=%d.\n", intgen_list->number, intgen_list->address, intgen_list->time); + } + else if (*argv && !strcmp (*argv, "remove")) + { + ++argv; + num = sim_parse_number (*argv, NULL); + tmpgen = NULL; + if (intgen_list) + { + if (intgen_list->number == num) + { + tmpgen = intgen_list; + intgen_list = intgen_list->next; + } + else + { + for (intgen = intgen_list; intgen != NULL; intgen = intgen->next) + { + if (intgen->next != NULL && intgen->next->number == num) + { + tmpgen = intgen->next; + intgen->next = intgen->next->next; + break; + } + } + } + if (tmpgen) + free (tmpgen); + else + (*v850_callback->printf_filtered) (v850_callback, + "No interrupt generator numbered %d, ignoring.\n", num); + } + } + else if (*argv && !strcmp (*argv, "info")) + { + if (intgen_list) + { + for (intgen = intgen_list; intgen != NULL; intgen = intgen->next) + (*v850_callback->printf_filtered) (v850_callback, + "Interrupt generator %d (%s) at pc=0x%x/time=%d%s.\n", + intgen->number, + interrupt_names[intgen->type], + intgen->address, + intgen->time, + (intgen->enabled ? "" : " (disabled)")); + } + else + { + (*v850_callback->printf_filtered) (v850_callback, "No interrupt generators defined.\n"); + } + + } + else + { + (*v850_callback->printf_filtered) (v850_callback, + "Invalid interrupt command, must be one of `add', `remove', or `info'.\n"); + } + /* Cache the presence of a non-maskable generator. */ + have_nm_generator = 0; + for (intgen = intgen_list; intgen != NULL; intgen = intgen->next) + { + if (intgen->type == int_nmi || intgen->type == int_reset) + { + have_nm_generator = 1; + break; + } + } +} + +void +sim_do_command (sd, cmd) + SIM_DESC sd; char *cmd; -{ - (*v850_callback->printf_filtered) (v850_callback, "sim_do_command: %s\n", cmd); +{ + char *mm_cmd = "memory-map"; + char *int_cmd = "interrupt"; + + if (! strncmp (cmd, mm_cmd, strlen (mm_cmd)) + && strchr (" ", cmd[strlen(mm_cmd)])) + sim_set_memory_map (cmd + strlen(mm_cmd) + 1); + + else if (! strncmp (cmd, int_cmd, strlen (int_cmd)) + && strchr (" ", cmd[strlen(int_cmd)])) + sim_set_interrupt (cmd + strlen(int_cmd) + 1); + + else if (! strcmp (cmd, "help")) + { + (*v850_callback->printf_filtered) (v850_callback, "V850 simulator commands:\n\n"); + (*v850_callback->printf_filtered) (v850_callback, "interrupt add <inttype> { pc | time } <value> -- Set up an interrupt generator\n"); + (*v850_callback->printf_filtered) (v850_callback, "interrupt remove <n> -- Remove an existing interrupt generator\n"); + (*v850_callback->printf_filtered) (v850_callback, "interrupt info -- List all the interrupt generators\n"); + (*v850_callback->printf_filtered) (v850_callback, "memory-map hole=<m>,<n> -- Set the memory map to have a hole between <m> and <n>\n"); + (*v850_callback->printf_filtered) (v850_callback, "\n"); + } + else + (*v850_callback->printf_filtered) (v850_callback, "\"%s\" is not a valid V850 simulator command.\n", + cmd); } -int -sim_load (prog, from_tty) +SIM_RC +sim_load (sd, prog, abfd, from_tty) + SIM_DESC sd; char *prog; + bfd *abfd; int from_tty; { - /* Return nonzero so GDB will handle it. */ - return 1; + extern bfd *sim_load_file (); /* ??? Don't know where this should live. */ + bfd *prog_bfd; + + prog_bfd = sim_load_file (sd, myname, v850_callback, prog, abfd, + sim_kind == SIM_OPEN_DEBUG); + if (prog_bfd == NULL) + return SIM_RC_FAIL; + PC = bfd_get_start_address (prog_bfd); + if (abfd == NULL) + bfd_close (prog_bfd); + return SIM_RC_OK; } |