diff options
Diffstat (limited to 'sim/mn10300/interp.c')
-rw-r--r-- | sim/mn10300/interp.c | 477 |
1 files changed, 398 insertions, 79 deletions
diff --git a/sim/mn10300/interp.c b/sim/mn10300/interp.c index e3a7745..039bd17 100644 --- a/sim/mn10300/interp.c +++ b/sim/mn10300/interp.c @@ -1,14 +1,46 @@ #include <signal.h> + +#if WITH_COMMON +#include "sim-main.h" +#else +#include "mn10300_sim.h" +#endif + #include "sysdep.h" #include "bfd.h" +#include "sim-assert.h" + + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#include "bfd.h" + +#ifndef INLINE +#ifdef __GNUC__ +#define INLINE inline +#else +#define INLINE +#endif +#endif -#include "mn10300_sim.h" host_callback *mn10300_callback; int mn10300_debug; static SIM_OPEN_KIND sim_kind; static char *myname; +#if WITH_COMMON +#else static void dispatch PARAMS ((uint32, uint32, int)); static long hash PARAMS ((long)); static void init_system PARAMS ((void)); @@ -169,63 +201,6 @@ dispatch (insn, extension, length) PC += length; } -/* 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; -{ - return *x; -} - -uint16 -get_half (x) - uint8 *x; -{ - uint8 *a = x; - return (a[1] << 8) + (a[0]); -} - -uint32 -get_word (x) - uint8 *x; -{ - uint8 *a = x; - return (a[3]<<24) + (a[2]<<16) + (a[1]<<8) + (a[0]); -} - -void -put_byte (addr, data) - uint8 *addr; - uint8 data; -{ - uint8 *a = addr; - a[0] = data; -} - -void -put_half (addr, data) - uint8 *addr; - uint16 data; -{ - uint8 *a = addr; - a[0] = data & 0xff; - a[1] = (data >> 8) & 0xff; -} - -void -put_word (addr, data) - uint8 *addr; - uint32 data; -{ - uint8 *a = addr; - a[0] = data & 0xff; - a[1] = (data >> 8) & 0xff; - a[2] = (data >> 16) & 0xff; - a[3] = (data >> 24) & 0xff; -} - void sim_size (power) int power; @@ -283,6 +258,7 @@ compare_simops (arg1, arg2) return 0; } + SIM_DESC sim_open (kind, cb, abfd, argv) SIM_OPEN_KIND kind; @@ -825,11 +801,16 @@ sim_info (sd, verbose) } SIM_RC -sim_create_inferior (sd, argv, env) +sim_create_inferior (sd, abfd, argv, env) SIM_DESC sd; + struct _bfd *abfd; char **argv; char **env; { + if (abfd != NULL) + PC = bfd_get_start_address (abfd); + else + PC = 0; return SIM_RC_OK; } @@ -860,24 +841,6 @@ sim_stop_reason (sd, reason, sigrc) *sigrc = State.exception; } -void -sim_fetch_register (sd, rn, memory) - SIM_DESC sd; - int rn; - unsigned char *memory; -{ - put_word (memory, State.regs[rn]); -} - -void -sim_store_register (sd, rn, memory) - SIM_DESC sd; - int rn; - unsigned char *memory; -{ - State.regs[rn] = get_word (memory); -} - int sim_read (sd, addr, buffer, size) SIM_DESC sd; @@ -911,11 +874,367 @@ sim_load (sd, prog, abfd, from_tty) bfd *prog_bfd; prog_bfd = sim_load_file (sd, myname, mn10300_callback, prog, abfd, - sim_kind == SIM_OPEN_DEBUG); + sim_kind == SIM_OPEN_DEBUG, + 0, sim_write); 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; } +#endif /* not WITH_COMMON */ + + +#if WITH_COMMON + +/* For compatibility */ +SIM_DESC simulator; + +/* mn10300 interrupt model */ + +enum interrupt_type +{ + int_reset, + int_nmi, + int_intov1, + int_intp10, + int_intp11, + int_intp12, + int_intp13, + int_intcm4, + num_int_types +}; + +char *interrupt_names[] = { + "reset", + "nmi", + "intov1", + "intp10", + "intp11", + "intp12", + "intp13", + "intcm4", + NULL +}; + + +static void +do_interrupt (sd, data) + SIM_DESC sd; + void *data; +{ +#if 0 + char **interrupt_name = (char**)data; + enum interrupt_type inttype; + inttype = (interrupt_name - STATE_WATCHPOINTS (sd)->interrupt_names); + + /* For a hardware reset, drop everything and jump to the start + address */ + if (inttype == int_reset) + { + PC = 0; + PSW = 0x20; + ECR = 0; + sim_engine_restart (sd, NULL, NULL, NULL_CIA); + } + + /* Deliver an NMI when allowed */ + 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. + Just keep re-scheduling a single NMI until it manages to + be delivered */ + if (STATE_CPU (sd, 0)->pending_nmi != NULL) + sim_events_deschedule (sd, STATE_CPU (sd, 0)->pending_nmi); + STATE_CPU (sd, 0)->pending_nmi = + sim_events_schedule (sd, 1, do_interrupt, data); + return; + } + else + { + /* NMI can be delivered. Do not deschedule pending_nmi as + that, if still in the event queue, is a second NMI that + needs to be delivered later. */ + FEPC = PC; + FEPSW = PSW; + /* Set the FECC part of the ECR. */ + ECR &= 0x0000ffff; + ECR |= 0x10; + PSW |= PSW_NP; + PSW &= ~PSW_EP; + PSW |= PSW_ID; + PC = 0x10; + sim_engine_restart (sd, NULL, NULL, NULL_CIA); + } + } + + /* deliver maskable interrupt when allowed */ + if (inttype > int_nmi && inttype < num_int_types) + { + if ((PSW & PSW_NP) || (PSW & PSW_ID)) + { + /* Can't deliver this interrupt, reschedule it for later */ + sim_events_schedule (sd, 1, do_interrupt, data); + return; + } + else + { + /* save context */ + EIPC = PC; + EIPSW = PSW; + /* Disable further interrupts. */ + PSW |= PSW_ID; + /* Indicate that we're doing interrupt not exception processing. */ + PSW &= ~PSW_EP; + /* 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. */ + sim_engine_abort (sd, NULL, NULL_CIA, + "do_interrupt - internal error - bad switch"); + break; + } + } + sim_engine_restart (sd, NULL, NULL, NULL_CIA); + } + + /* some other interrupt? */ + sim_engine_abort (sd, NULL, NULL_CIA, + "do_interrupt - internal error - interrupt %d unknown", + inttype); +#endif /* 0 */ +} + +/* These default values correspond to expected usage for the chip. */ + +SIM_DESC +sim_open (kind, cb, abfd, argv) + SIM_OPEN_KIND kind; + host_callback *cb; + struct _bfd *abfd; + char **argv; +{ + SIM_DESC sd = sim_state_alloc (kind, cb); + int mach; + mn10300_callback = cb; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + + /* for compatibility */ + simulator = sd; + + /* FIXME: should be better way of setting up interrupts */ + STATE_WATCHPOINTS (sd)->pc = &(PC); + STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC); + STATE_WATCHPOINTS (sd)->interrupt_handler = do_interrupt; + STATE_WATCHPOINTS (sd)->interrupt_names = interrupt_names; + + if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) + return 0; + + /* Allocate core managed memory */ + + /* "Mirror" the ROM addresses below 1MB. */ + sim_do_command (sd, "memory region 0,0x100000"); + + /* 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; + } + + /* 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); */ + + return sd; +} + + +void +sim_close (sd, quitting) + SIM_DESC sd; + int quitting; +{ + sim_module_uninstall (sd); +} + + +SIM_RC +sim_create_inferior (sd, prog_bfd, argv, env) + SIM_DESC sd; + struct _bfd *prog_bfd; + char **argv; + char **env; +{ + memset (&State, 0, sizeof (State)); + if (prog_bfd != NULL) { + PC = bfd_get_start_address (prog_bfd); + } else { + PC = 0; + } + CIA_SET (STATE_CPU (sd, 0), (unsigned64) PC); + + return SIM_RC_OK; +} + +void +sim_do_command (sd, cmd) + SIM_DESC sd; + char *cmd; +{ + char *mm_cmd = "memory-map"; + char *int_cmd = "interrupt"; + + if (sim_args_command (sd, cmd) != SIM_RC_OK) + { + if (strncmp (cmd, mm_cmd, strlen (mm_cmd) == 0)) + sim_io_eprintf (sd, "`memory-map' command replaced by `sim memory'\n"); + else if (strncmp (cmd, int_cmd, strlen (int_cmd)) == 0) + sim_io_eprintf (sd, "`interrupt' command replaced by `sim watch'\n"); + else + sim_io_eprintf (sd, "Unknown command `%s'\n", cmd); + } +} +#endif /* WITH_COMMON */ + +/* 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; +{ + return *x; +} + +uint16 +get_half (x) + uint8 *x; +{ + uint8 *a = x; + return (a[1] << 8) + (a[0]); +} + +uint32 +get_word (x) + uint8 *x; +{ + uint8 *a = x; + return (a[3]<<24) + (a[2]<<16) + (a[1]<<8) + (a[0]); +} + +void +put_byte (addr, data) + uint8 *addr; + uint8 data; +{ + uint8 *a = addr; + a[0] = data; +} + +void +put_half (addr, data) + uint8 *addr; + uint16 data; +{ + uint8 *a = addr; + a[0] = data & 0xff; + a[1] = (data >> 8) & 0xff; +} + +void +put_word (addr, data) + uint8 *addr; + uint32 data; +{ + uint8 *a = addr; + a[0] = data & 0xff; + a[1] = (data >> 8) & 0xff; + a[2] = (data >> 16) & 0xff; + a[3] = (data >> 24) & 0xff; +} + +int +sim_fetch_register (sd, rn, memory, length) + SIM_DESC sd; + int rn; + unsigned char *memory; + int length; +{ + put_word (memory, State.regs[rn]); + return -1; +} + +int +sim_store_register (sd, rn, memory, length) + SIM_DESC sd; + int rn; + unsigned char *memory; + int length; +{ + State.regs[rn] = get_word (memory); + return -1; +} |