diff options
Diffstat (limited to 'sim/cr16/interp.c')
-rw-r--r-- | sim/cr16/interp.c | 1448 |
1 files changed, 1448 insertions, 0 deletions
diff --git a/sim/cr16/interp.c b/sim/cr16/interp.c new file mode 100644 index 0000000..f6397c5 --- /dev/null +++ b/sim/cr16/interp.c @@ -0,0 +1,1448 @@ +/* Simulation code for the CR16 processor. + Copyright (C) 2008 Free Software Foundation, Inc. + Contributed by M Ranga Swami Reddy <MR.Swami.Reddy@nsc.com> + + This file is part of GDB, the GNU debugger. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <signal.h> +#include "sysdep.h" +#include "bfd.h" +#include "gdb/callback.h" +#include "gdb/remote-sim.h" + +#include "cr16_sim.h" +#include "gdb/sim-cr16.h" +#include "gdb/signals.h" +#include "opcode/cr16.h" + +enum _leftright { LEFT_FIRST, RIGHT_FIRST }; + +static char *myname; +static SIM_OPEN_KIND sim_kind; +int cr16_debug; + +/* Set this to true to get the previous segment layout. */ + +int old_segment_mapping; + +host_callback *cr16_callback; +unsigned long ins_type_counters[ (int)INS_MAX ]; + +uint32 OP[4]; +uint32 sign_flag; + +static int init_text_p = 0; +/* non-zero if we opened prog_bfd */ +static int prog_bfd_was_opened_p; +bfd *prog_bfd; +asection *text; +bfd_vma text_start; +bfd_vma text_end; + +static void get_operands PARAMS ((operand_desc *s, uint64 mcode, int isize)); +static void do_run PARAMS ((inst *ins, uint64 mc)); +static char *add_commas PARAMS ((char *buf, int sizeof_buf, unsigned long value)); +extern void sim_set_profile PARAMS ((int n)); +extern void sim_set_profile_size PARAMS ((int n)); +static INLINE uint8 *map_memory (unsigned phys_addr); + +#ifdef NEED_UI_LOOP_HOOK +/* How often to run the ui_loop update, when in use */ +#define UI_LOOP_POLL_INTERVAL 0x14000 + +/* Counter for the ui_loop_hook update */ +static long ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL; + +/* Actual hook to call to run through gdb's gui event loop */ +extern int (*deprecated_ui_loop_hook) PARAMS ((int signo)); +#endif /* NEED_UI_LOOP_HOOK */ + +#ifndef INLINE +#if defined(__GNUC__) && defined(__OPTIMIZE__) +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +INLINE static void +get_operands (operand_desc *s, uint64 ins, int isize) +{ + uint32 i, opn = 0, start_bit = 0, op_type = 0; + int32 op_size = 0, mask = 0; + + if (isize == 1) /* Trunkcate the extra 16 bits of INS. */ + ins = ins >> 16; + + for (i=0; i < 3; ++i,++opn) + { + if ((s[opn].op_type == dummy) || (s[opn].op_type > cr16_num_optab)) + break; + else + op_type = s[opn].op_type; + + start_bit = s[opn].shift; + op_size = cr16_optab[op_type].bit_size; + + switch (op_type) + { + case imm3: case imm4: case imm5: case imm6: + { + if (isize == 1) + OP[i] = ((ins >> 4) & ((1 << op_size) -1)); + else + OP[i] = ((ins >> (32 - start_bit)) & ((1 << op_size) -1)); + + if (OP[i] & ((long)1 << (op_size -1))) + { + sign_flag = 1; + OP[i] = ~(OP[i]) + 1; + } + OP[i] = (unsigned long int)(OP[i] & (((long)1 << op_size) -1)); + } + break; + + case uimm3: case uimm3_1: case uimm4_1: + if (isize == 1) + OP[i] = ((ins >> 4) & ((1 << op_size) -1)); + else + OP[i] = ((ins >> (32 - start_bit)) & ((1 << op_size) -1)); + break; + + case uimm4: + switch (isize) + { + case 1: + if (start_bit == 20) + OP[i] = ((ins >> 4) & ((1 << op_size) -1)); + else + OP[i] = (ins & ((1 << op_size) -1)); + break; + case 2: + OP[i] = ((ins >> start_bit) & ((1 << op_size) -1)); + break; + case 3: + OP[i] = ((ins >> (start_bit + 16)) & ((1 << op_size) -1)); + break; + default: + OP[i] = ((ins >> start_bit) & ((1 << op_size) -1)); + break; + } + break; + + case imm16: case uimm16: + OP[i] = ins & 0xFFFF; + break; + + case uimm20: case imm20: + OP[i] = ins & (((long)1 << op_size) - 1); + break; + + case imm32: case uimm32: + OP[i] = ins & 0xFFFFFFFF; + break; + + case uimm5: break; /*NOT USED. */ + OP[i] = ins & ((1 << op_size) - 1); break; + + case disps5: + OP[i] = (ins >> 4) & ((1 << 4) - 1); + OP[i] = (OP[i] * 2) + 2; + if (OP[i] & ((long)1 << 5)) + { + sign_flag = 1; + OP[i] = ~(OP[i]) + 1; + OP[i] = (unsigned long int)(OP[i] & 0x1F); + } + break; + + case dispe9: + OP[i] = ((((ins >> 8) & 0xf) << 4) | (ins & 0xf)); + OP[i] <<= 1; + if (OP[i] & ((long)1 << 8)) + { + sign_flag = 1; + OP[i] = ~(OP[i]) + 1; + OP[i] = (unsigned long int)(OP[i] & 0xFF); + } + break; + + case disps17: + OP[i] = (ins & 0xFFFF); + if (OP[i] & 1) + { + OP[i] = (OP[i] & 0xFFFE); + sign_flag = 1; + OP[i] = ~(OP[i]) + 1; + OP[i] = (unsigned long int)(OP[i] & 0xFFFF); + } + break; + + case disps25: + if (isize == 2) + OP[i] = (ins & 0xFFFFFF); + else + OP[i] = (ins & 0xFFFF) | (((ins >> 24) & 0xf) << 16) | + (((ins >> 16) & 0xf) << 20); + + if (OP[i] & 1) + { + OP[i] = (OP[i] & 0xFFFFFE); + sign_flag = 1; + OP[i] = ~(OP[i]) + 1; + OP[i] = (unsigned long int)(OP[i] & 0xFFFFFF); + } + break; + + case abs20: + if (isize == 3) + OP[i] = (ins) & 0xFFFFF; + else + OP[i] = (ins >> start_bit) & 0xFFFFF; + break; + case abs24: + if (isize == 3) + OP[i] = ((ins & 0xFFFF) | (((ins >> 16) & 0xf) << 20) + | (((ins >> 24) & 0xf) << 16)); + else + OP[i] = (ins >> 16) & 0xFFFFFF; + break; + + case rra: + case rbase: break; /* NOT USED. */ + case rbase_disps20: case rbase_dispe20: + case rpbase_disps20: case rpindex_disps20: + OP[i] = ((((ins >> 24)&0xf) << 16)|((ins) & 0xFFFF)); + OP[++i] = (ins >> 16) & 0xF; /* get 4 bit for reg. */ + break; + case rpbase_disps0: + OP[i] = 0; /* 4 bit disp const. */ + OP[++i] = (ins) & 0xF; /* get 4 bit for reg. */ + break; + case rpbase_dispe4: + OP[i] = ((ins >> 8) & 0xF) * 2; /* 4 bit disp const. */ + OP[++i] = (ins) & 0xF; /* get 4 bit for reg. */ + break; + case rpbase_disps4: + OP[i] = ((ins >> 8) & 0xF); /* 4 bit disp const. */ + OP[++i] = (ins) & 0xF; /* get 4 bit for reg. */ + break; + case rpbase_disps16: + OP[i] = (ins) & 0xFFFF; + OP[++i] = (ins >> 16) & 0xF; /* get 4 bit for reg. */ + break; + case rpindex_disps0: + OP[i] = 0; + OP[++i] = (ins >> 4) & 0xF; /* get 4 bit for reg. */ + OP[++i] = (ins >> 8) & 0x1; /* get 1 bit for index-reg. */ + break; + case rpindex_disps14: + OP[i] = (ins) & 0x3FFF; + OP[++i] = (ins >> 14) & 0x1; /* get 1 bit for index-reg. */ + OP[++i] = (ins >> 16) & 0xF; /* get 4 bit for reg. */ + case rindex7_abs20: + case rindex8_abs20: + OP[i] = (ins) & 0xFFFFF; + OP[++i] = (ins >> 24) & 0x1; /* get 1 bit for index-reg. */ + OP[++i] = (ins >> 20) & 0xF; /* get 4 bit for reg. */ + break; + case regr: case regp: case pregr: case pregrp: + switch(isize) + { + case 1: + if (start_bit == 20) OP[i] = (ins >> 4) & 0xF; + else if (start_bit == 16) OP[i] = ins & 0xF; + break; + case 2: OP[i] = (ins >> start_bit) & 0xF; break; + case 3: OP[i] = (ins >> (start_bit + 16)) & 0xF; break; + } + break; + case cc: + { + if (isize == 1) OP[i] = (ins >> 4) & 0xF; + else if (isize == 2) OP[i] = (ins >> start_bit) & 0xF; + else OP[i] = (ins >> (start_bit + 16)) & 0xF; + break; + } + default: break; + } + + /* For ESC on uimm4_1 operand */ + if (op_type == uimm4_1) + if (OP[i] == 9) + OP[i] = -1; + } + /* FIXME: for tracing, update values that need to be updated each + instruction decode cycle */ +#if 0 // DEBUG + (*cr16_callback->printf_filtered) (cr16_callback, "OP0=0x%X\t,OP1=0x%X\t,OP2=0x%X\t,OP3=0X%X\n",OP[0],OP[1],OP[2],OP[3]); +#endif + State.trace.psw = PSR; + +} + +bfd_vma +decode_pc () +{ + asection *s; + if (!init_text_p && prog_bfd != NULL) + { + init_text_p = 1; + for (s = prog_bfd->sections; s; s = s->next) + if (strcmp (bfd_get_section_name (prog_bfd, s), ".text") == 0) + { + text = s; + text_start = bfd_get_section_vma (prog_bfd, s); + text_end = text_start + bfd_section_size (prog_bfd, s); + break; + } + } + + return (PC) + text_start; +} + + + +static void +do_run(inst *instruction, uint64 mcode) +{ + struct simops *s= Simops; + char func[12]="\0"; +#ifdef DEBUG + if ((cr16_debug & DEBUG_INSTRUCTION) != 0) + (*cr16_callback->printf_filtered) (cr16_callback, "do_long 0x%x\n", instruction); +#endif + + /* Re-set OP list */ + OP[0] = OP[1] = OP[2] = OP[3] = sign_flag = 0; + + /* for push/pop/pushrtn with RA instructions */ + if ((INST_HAS_REG_LIST) && (mcode & 0x800000)) + OP[2] = 1; /* Set 1 for RA operand */ + + get_operands (&instruction->operands, mcode, instruction->size); + + State.ins_type = instruction->flags; + //ins_type_counters[ (int)State.ins_type ]++; + sprintf(func,"OP_%X_%X",instruction->match,(32 - instruction->match_bits)); + /* Check for appropriate opcode function */ + for ( ;s->opcode!=0;s++) + { + if (strcmp(s->fname,func) == 0) + break; + } + (s->func)(); +} + +static char * +add_commas(char *buf, int sizeof_buf, unsigned long value) +{ + int comma = 3; + char *endbuf = buf + sizeof_buf - 1; + + *--endbuf = '\0'; + do { + if (comma-- == 0) + { + *--endbuf = ','; + comma = 2; + } + + *--endbuf = (value % 10) + '0'; + } while ((value /= 10) != 0); + + return endbuf; +} + +void +sim_size (int power) +{ + int i; + for (i = 0; i < IMEM_SEGMENTS; i++) + { + if (State.mem.insn[i]) + free (State.mem.insn[i]); + } + for (i = 0; i < DMEM_SEGMENTS; i++) + { + if (State.mem.data[i]) + free (State.mem.data[i]); + } + for (i = 0; i < UMEM_SEGMENTS; i++) + { + if (State.mem.unif[i]) + free (State.mem.unif[i]); + } + /* Always allocate dmem segment 0. This contains the IMAP and DMAP + registers. */ + State.mem.data[0] = calloc (1, SEGMENT_SIZE); +} + +/* For tracing - leave info on last access around. */ +static char *last_segname = "invalid"; +static char *last_from = "invalid"; +static char *last_to = "invalid"; + +enum + { + IMAP0_OFFSET = 0xff00, + DMAP0_OFFSET = 0xff08, + DMAP2_SHADDOW = 0xff04, + DMAP2_OFFSET = 0xff0c + }; + +static void +set_dmap_register (int reg_nr, unsigned long value) +{ + uint8 *raw = map_memory (SIM_CR16_MEMORY_DATA + + DMAP0_OFFSET + 2 * reg_nr); + WRITE_16 (raw, value); +#ifdef DEBUG + if ((cr16_debug & DEBUG_MEMORY)) + { + (*cr16_callback->printf_filtered) + (cr16_callback, "mem: dmap%d=0x%04lx\n", reg_nr, value); + } +#endif +} + +static unsigned long +dmap_register (void *regcache, int reg_nr) +{ + uint8 *raw = map_memory (SIM_CR16_MEMORY_DATA + + DMAP0_OFFSET + 2 * reg_nr); + return READ_16 (raw); +} + +static void +set_imap_register (int reg_nr, unsigned long value) +{ + uint8 *raw = map_memory (SIM_CR16_MEMORY_DATA + + IMAP0_OFFSET + 2 * reg_nr); + WRITE_16 (raw, value); +#ifdef DEBUG + if ((cr16_debug & DEBUG_MEMORY)) + { + (*cr16_callback->printf_filtered) + (cr16_callback, "mem: imap%d=0x%04lx\n", reg_nr, value); + } +#endif +} + +static unsigned long +imap_register (void *regcache, int reg_nr) +{ + uint8 *raw = map_memory (SIM_CR16_MEMORY_DATA + + IMAP0_OFFSET + 2 * reg_nr); + return READ_16 (raw); +} + +enum + { + HELD_SPI_IDX = 0, + HELD_SPU_IDX = 1 + }; + +static unsigned long +spu_register (void) +{ + return GPR (SP_IDX); +} + +static unsigned long +spi_register (void) +{ + return GPR (SP_IDX); +} + +static void +set_spi_register (unsigned long value) +{ + SET_GPR (SP_IDX, value); +} + +static void +set_spu_register (unsigned long value) +{ + SET_GPR (SP_IDX, value); +} + +/* Given a virtual address in the DMAP address space, translate it + into a physical address. */ + +unsigned long +sim_cr16_translate_dmap_addr (unsigned long offset, + int nr_bytes, + unsigned long *phys, + void *regcache, + unsigned long (*dmap_register) (void *regcache, + int reg_nr)) +{ + short map; + int regno; + last_from = "logical-data"; + if (offset >= DMAP_BLOCK_SIZE * SIM_CR16_NR_DMAP_REGS) + { + /* Logical address out side of data segments, not supported */ + return 0; + } + regno = (offset / DMAP_BLOCK_SIZE); + offset = (offset % DMAP_BLOCK_SIZE); + +#if 1 + if ((offset % DMAP_BLOCK_SIZE) + nr_bytes > DMAP_BLOCK_SIZE) + { + /* Don't cross a BLOCK boundary */ + nr_bytes = DMAP_BLOCK_SIZE - (offset % DMAP_BLOCK_SIZE); + } + map = dmap_register (regcache, regno); + if (regno == 3) + { + /* Always maps to data memory */ + int iospi = (offset / 0x1000) % 4; + int iosp = (map >> (4 * (3 - iospi))) % 0x10; + last_to = "io-space"; + *phys = (SIM_CR16_MEMORY_DATA + (iosp * 0x10000) + 0xc000 + offset); + } + else + { + int sp = ((map & 0x3000) >> 12); + int segno = (map & 0x3ff); + switch (sp) + { + case 0: /* 00: Unified memory */ + *phys = SIM_CR16_MEMORY_UNIFIED + (segno * DMAP_BLOCK_SIZE) + offset; + last_to = "unified"; + break; + case 1: /* 01: Instruction Memory */ + *phys = SIM_CR16_MEMORY_INSN + (segno * DMAP_BLOCK_SIZE) + offset; + last_to = "chip-insn"; + break; + case 2: /* 10: Internal data memory */ + *phys = SIM_CR16_MEMORY_DATA + (segno << 16) + (regno * DMAP_BLOCK_SIZE) + offset; + last_to = "chip-data"; + break; + case 3: /* 11: Reserved */ + return 0; + } + } +#endif + return nr_bytes; +} + +/* Given a virtual address in the IMAP address space, translate it + into a physical address. */ + +unsigned long +sim_cr16_translate_imap_addr (unsigned long offset, + int nr_bytes, + unsigned long *phys, + void *regcache, + unsigned long (*imap_register) (void *regcache, + int reg_nr)) +{ + short map; + int regno; + int sp; + int segno; + last_from = "logical-insn"; + if (offset >= (IMAP_BLOCK_SIZE * SIM_CR16_NR_IMAP_REGS)) + { + /* Logical address outside of IMAP segments, not supported */ + return 0; + } + regno = (offset / IMAP_BLOCK_SIZE); + offset = (offset % IMAP_BLOCK_SIZE); + if (offset + nr_bytes > IMAP_BLOCK_SIZE) + { + /* Don't cross a BLOCK boundary */ + nr_bytes = IMAP_BLOCK_SIZE - offset; + } + map = imap_register (regcache, regno); + sp = (map & 0x3000) >> 12; + segno = (map & 0x007f); + switch (sp) + { + case 0: /* 00: unified memory */ + *phys = SIM_CR16_MEMORY_UNIFIED + (segno << 17) + offset; + last_to = "unified"; + break; + case 1: /* 01: instruction memory */ + *phys = SIM_CR16_MEMORY_INSN + (IMAP_BLOCK_SIZE * regno) + offset; + last_to = "chip-insn"; + break; + case 2: /*10*/ + /* Reserved. */ + return 0; + case 3: /* 11: for testing - instruction memory */ + offset = (offset % 0x800); + *phys = SIM_CR16_MEMORY_INSN + offset; + if (offset + nr_bytes > 0x800) + /* don't cross VM boundary */ + nr_bytes = 0x800 - offset; + last_to = "test-insn"; + break; + } + return nr_bytes; +} + +unsigned long +sim_cr16_translate_addr (unsigned long memaddr, + int nr_bytes, + unsigned long *targ_addr, + void *regcache, + unsigned long (*dmap_register) (void *regcache, + int reg_nr), + unsigned long (*imap_register) (void *regcache, + int reg_nr)) +{ + unsigned long phys; + unsigned long seg; + unsigned long off; + + last_from = "unknown"; + last_to = "unknown"; + + seg = (memaddr >> 24); + off = (memaddr & 0xffffffL); + + /* However, if we've asked to use the previous generation of segment + mapping, rearrange the segments as follows. */ + + if (old_segment_mapping) + { + switch (seg) + { + case 0x00: /* DMAP translated memory */ + seg = 0x10; + break; + case 0x01: /* IMAP translated memory */ + seg = 0x11; + break; + case 0x10: /* On-chip data memory */ + seg = 0x02; + break; + case 0x11: /* On-chip insn memory */ + seg = 0x01; + break; + case 0x12: /* Unified memory */ + seg = 0x00; + break; + } + } + + switch (seg) + { + case 0x00: /* Physical unified memory */ + last_from = "phys-unified"; + last_to = "unified"; + phys = SIM_CR16_MEMORY_UNIFIED + off; + if ((off % SEGMENT_SIZE) + nr_bytes > SEGMENT_SIZE) + nr_bytes = SEGMENT_SIZE - (off % SEGMENT_SIZE); + break; + + case 0x01: /* Physical instruction memory */ + last_from = "phys-insn"; + last_to = "chip-insn"; + phys = SIM_CR16_MEMORY_INSN + off; + if ((off % SEGMENT_SIZE) + nr_bytes > SEGMENT_SIZE) + nr_bytes = SEGMENT_SIZE - (off % SEGMENT_SIZE); + break; + + case 0x02: /* Physical data memory segment */ + last_from = "phys-data"; + last_to = "chip-data"; + phys = SIM_CR16_MEMORY_DATA + off; + if ((off % SEGMENT_SIZE) + nr_bytes > SEGMENT_SIZE) + nr_bytes = SEGMENT_SIZE - (off % SEGMENT_SIZE); + break; + + case 0x10: /* in logical data address segment */ + nr_bytes = sim_cr16_translate_dmap_addr (off, nr_bytes, &phys, regcache, + dmap_register); + break; + + case 0x11: /* in logical instruction address segment */ + nr_bytes = sim_cr16_translate_imap_addr (off, nr_bytes, &phys, regcache, + imap_register); + break; + + default: + return 0; + } + + *targ_addr = phys; + return nr_bytes; +} + +/* Return a pointer into the raw buffer designated by phys_addr. It + is assumed that the client has already ensured that the access + isn't going to cross a segment boundary. */ + +uint8 * +map_memory (unsigned phys_addr) +{ + uint8 **memory; + uint8 *raw; + unsigned offset; + int segment = ((phys_addr >> 24) & 0xff); + + switch (segment) + { + + case 0x00: /* Unified memory */ + { + memory = &State.mem.unif[(phys_addr / SEGMENT_SIZE) % UMEM_SEGMENTS]; + last_segname = "umem"; + break; + } + + case 0x01: /* On-chip insn memory */ + { + memory = &State.mem.insn[(phys_addr / SEGMENT_SIZE) % IMEM_SEGMENTS]; + last_segname = "imem"; + break; + } + + case 0x02: /* On-chip data memory */ + { + if ((phys_addr & 0xff00) == 0xff00) + { + phys_addr = (phys_addr & 0xffff); + if (phys_addr == DMAP2_SHADDOW) + { + phys_addr = DMAP2_OFFSET; + last_segname = "dmap"; + } + else + last_segname = "reg"; + } + else + last_segname = "dmem"; + memory = &State.mem.data[(phys_addr / SEGMENT_SIZE) % DMEM_SEGMENTS]; + break; + } + + default: + /* OOPS! */ + last_segname = "scrap"; + return State.mem.fault; + } + + if (*memory == NULL) + { + *memory = calloc (1, SEGMENT_SIZE); + if (*memory == NULL) + { + (*cr16_callback->printf_filtered) (cr16_callback, "Malloc failed.\n"); + return State.mem.fault; + } + } + + offset = (phys_addr % SEGMENT_SIZE); + raw = *memory + offset; + return raw; +} + +/* Transfer data to/from simulated memory. Since a bug in either the + simulated program or in gdb or the simulator itself may cause a + bogus address to be passed in, we need to do some sanity checking + on addresses to make sure they are within bounds. When an address + fails the bounds check, treat it as a zero length read/write rather + than aborting the entire run. */ + +static int +xfer_mem (SIM_ADDR virt, + unsigned char *buffer, + int size, + int write_p) +{ + uint8 *memory; + unsigned long phys; + int phys_size; + phys_size = sim_cr16_translate_addr (virt, size, &phys, NULL, + dmap_register, imap_register); + if (phys_size == 0) + return 0; + + memory = map_memory (phys); + +#ifdef DEBUG + if ((cr16_debug & DEBUG_INSTRUCTION) != 0) + { + (*cr16_callback->printf_filtered) + (cr16_callback, + "sim_%s %d bytes: 0x%08lx (%s) -> 0x%08lx (%s) -> 0x%08lx (%s)\n", + (write_p ? "write" : "read"), + phys_size, virt, last_from, + phys, last_to, + (long) memory, last_segname); + } +#endif + + if (write_p) + { + memcpy (memory, buffer, phys_size); + } + else + { + memcpy (buffer, memory, phys_size); + } + + return phys_size; +} + + +int +sim_write (sd, addr, buffer, size) + SIM_DESC sd; + SIM_ADDR addr; + unsigned char *buffer; + int size; +{ + /* FIXME: this should be performing a virtual transfer */ + return xfer_mem( addr, buffer, size, 1); +} + +int +sim_read (sd, addr, buffer, size) + SIM_DESC sd; + SIM_ADDR addr; + unsigned char *buffer; + int size; +{ + /* FIXME: this should be performing a virtual transfer */ + return xfer_mem( addr, buffer, size, 0); +} + + +SIM_DESC +sim_open (SIM_OPEN_KIND kind, struct host_callback_struct *callback, struct bfd *abfd, char **argv) +{ + struct simops *s; + static int init_p = 0; + char **p; + + sim_kind = kind; + cr16_callback = callback; + myname = argv[0]; + old_segment_mapping = 0; + + /* NOTE: This argument parsing is only effective when this function + is called by GDB. Standalone argument parsing is handled by + sim/common/run.c. */ +#if 0 + for (p = argv + 1; *p; ++p) + { + if (strcmp (*p, "-oldseg") == 0) + old_segment_mapping = 1; +#ifdef DEBUG + else if (strcmp (*p, "-t") == 0) + cr16_debug = DEBUG; + else if (strncmp (*p, "-t", 2) == 0) + cr16_debug = atoi (*p + 2); +#endif + else + (*cr16_callback->printf_filtered) (cr16_callback, "ERROR: unsupported option(s): %s\n",*p); + } +#endif + + /* reset the processor state */ + if (!State.mem.data[0]) + sim_size (1); + sim_create_inferior ((SIM_DESC) 1, NULL, NULL, NULL); + + /* Fudge our descriptor. */ + return (SIM_DESC) 1; +} + + +void +sim_close (sd, quitting) + SIM_DESC sd; + int quitting; +{ + if (prog_bfd != NULL && prog_bfd_was_opened_p) + { + bfd_close (prog_bfd); + prog_bfd = NULL; + prog_bfd_was_opened_p = 0; + } +} + +void +sim_set_profile (int n) +{ + (*cr16_callback->printf_filtered) (cr16_callback, "sim_set_profile %d\n",n); +} + +void +sim_set_profile_size (int n) +{ + (*cr16_callback->printf_filtered) (cr16_callback, "sim_set_profile_size %d\n",n); +} + +uint8 * +dmem_addr (uint32 offset) +{ + unsigned long phys; + uint8 *mem; + int phys_size; + + /* Note: DMEM address range is 0..0x10000. Calling code can compute + things like ``0xfffe + 0x0e60 == 0x10e5d''. Since offset's type + is uint16 this is modulo'ed onto 0x0e5d. */ + + phys_size = sim_cr16_translate_dmap_addr (offset, 1, &phys, NULL, + dmap_register); + if (phys_size == 0) + { + mem = State.mem.fault; + } + else + mem = map_memory (phys); +#ifdef DEBUG + if ((cr16_debug & DEBUG_MEMORY)) + { + (*cr16_callback->printf_filtered) + (cr16_callback, + "mem: 0x%08x (%s) -> 0x%08lx %d (%s) -> 0x%08lx (%s)\n", + offset, last_from, + phys, phys_size, last_to, + (long) mem, last_segname); + } +#endif + return mem; +} + +uint8 * +imem_addr (uint32 offset) +{ + unsigned long phys; + uint8 *mem; + int phys_size = sim_cr16_translate_imap_addr (offset, 1, &phys, NULL, + imap_register); + if (phys_size == 0) + { + return State.mem.fault; + } + mem = map_memory (phys); +#ifdef DEBUG + if ((cr16_debug & DEBUG_MEMORY)) + { + (*cr16_callback->printf_filtered) + (cr16_callback, + "mem: 0x%08x (%s) -> 0x%08lx %d (%s) -> 0x%08lx (%s)\n", + offset, last_from, + phys, phys_size, last_to, + (long) mem, last_segname); + } +#endif + return mem; +} + +static int stop_simulator = 0; + +int +sim_stop (sd) + SIM_DESC sd; +{ + stop_simulator = 1; + return 1; +} + + +/* Run (or resume) the program. */ +void +sim_resume (SIM_DESC sd, int step, int siggnal) +{ + uint32 mask = 0, ins_found = 0; + uint64 mcode=0; + uint8 *iaddr; + +#ifdef DEBUG +// (*cr16_callback->printf_filtered) (cr16_callback, "sim_resume (%d,%d) PC=0x%x\n",step,siggnal,PC); +#endif + + State.exception = 0; + if (step) + sim_stop (sd); + + switch (siggnal) + { + case 0: + break; +#ifdef SIGBUS + case SIGBUS: +#endif + case SIGSEGV: + SET_PC (PC); + SET_PSR (PSR); + JMP (AE_VECTOR_START); + SLOT_FLUSH (); + break; + case SIGILL: + SET_PC (PC); + SET_PSR (PSR); + SET_HW_PSR ((PSR & (PSR_C_BIT))); + JMP (RIE_VECTOR_START); + SLOT_FLUSH (); + break; + default: + /* just ignore it */ + break; + } + + do + { + iaddr = imem_addr ((uint32)PC); + ins_found = 0; + if (iaddr == State.mem.fault) + { + State.exception = SIGBUS; + break; + } + + mcode = get_longword( iaddr ); + + State.pc_changed = 0; + + /* Start searching from end of instruction table. */ + const inst *instruction = &cr16_instruction[NUMOPCODES - 2]; + + /* Loop over instruction table until a full match is found. */ + while (instruction >= cr16_instruction) + { + mask = (((1 << (32 - instruction->match_bits)) -1) << + instruction->match_bits); + + /* Adjuest mask for branch with 2 word instructions. */ + if ((IS_INSN_MNEMONIC("b") && instruction->size == 2)) + mask = 0xff0f0000; + + if ((mcode & mask) == (BIN(instruction->match, instruction->match_bits))) + { + ins_found = 1; + break; + } + else + instruction--; + } + +#if CR16_DEBUG + (*cr16_callback->printf_filtered) (cr16_callback, "INS: PC=0x%X, mcode=0x%X\n",PC,mcode); +#endif + if ((mcode == 0x0L) /*|| (!ins_found )*/) + { + State.exception = SIG_CR16_EXIT; /* exit trap */ + break; + } + + /* Check if the ins_found is '0', then set illigel instruction trap */ + if ( !ins_found ) + State.exception = SIGILL; + else + { + /* For 3 word instructions only */ + if (instruction->size == 3) + { + iaddr = imem_addr ((uint32)PC + 2); + mcode = (mcode << 16) | get_longword( iaddr ); + } + + do_run(instruction, mcode); + } + + /* If the PC of the current instruction matches RPT_E then + schedule a branch to the loop start. If one of those + instructions happens to be a branch, than that instruction + will be ignored */ + if (!State.pc_changed) + { + switch (instruction->size) + { + case 1: + SET_PC (PC + 2); /* For 1 word instructions */ + break; + case 2: + SET_PC (PC + 4); /* For 2 word instructions */ + break; + case 3: + SET_PC (PC + 6); /* For 3 word instructions */ + break; + default: break; + } + + } + + /* Check for a breakpoint trap on this instruction. This + overrides any pending branches or loops */ +#if 0 + if (PSR_DB && PC == DBS) + { + SET_BPC (PC); + SET_BPSR (PSR); + SET_PC (SDBT_VECTOR_START); + } +#endif + + /* Writeback all the DATA / PC changes */ + SLOT_FLUSH (); + +#ifdef NEED_UI_LOOP_HOOK + if (deprecated_ui_loop_hook != NULL && ui_loop_hook_counter-- < 0) + { + ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL; + deprecated_ui_loop_hook (0); + } +#endif /* NEED_UI_LOOP_HOOK */ + } + while ( !State.exception && !stop_simulator); + + if (step && !State.exception) + State.exception = SIGTRAP; +} + +void +sim_set_trace (void) +{ +#ifdef DEBUG + cr16_debug = DEBUG; +#endif +} + +void +sim_info (SIM_DESC sd, int verbose) +{ + char buf1[40]; + char buf2[40]; + char buf3[40]; + char buf4[40]; + char buf5[40]; +#if 0 + unsigned long left = ins_type_counters[ (int)INS_LEFT ] + ins_type_counters[ (int)INS_LEFT_COND_EXE ]; + unsigned long left_nops = ins_type_counters[ (int)INS_LEFT_NOPS ]; + unsigned long left_parallel = ins_type_counters[ (int)INS_LEFT_PARALLEL ]; + unsigned long left_cond = ins_type_counters[ (int)INS_LEFT_COND_TEST ]; + unsigned long left_total = left + left_parallel + left_cond + left_nops; + + unsigned long right = ins_type_counters[ (int)INS_RIGHT ] + ins_type_counters[ (int)INS_RIGHT_COND_EXE ]; + unsigned long right_nops = ins_type_counters[ (int)INS_RIGHT_NOPS ]; + unsigned long right_parallel = ins_type_counters[ (int)INS_RIGHT_PARALLEL ]; + unsigned long right_cond = ins_type_counters[ (int)INS_RIGHT_COND_TEST ]; + unsigned long right_total = right + right_parallel + right_cond + right_nops; + + unsigned long unknown = ins_type_counters[ (int)INS_UNKNOWN ]; + unsigned long ins_long = ins_type_counters[ (int)INS_LONG ]; + unsigned long parallel = ins_type_counters[ (int)INS_PARALLEL ]; + unsigned long leftright = ins_type_counters[ (int)INS_LEFTRIGHT ]; + unsigned long rightleft = ins_type_counters[ (int)INS_RIGHTLEFT ]; + unsigned long cond_true = ins_type_counters[ (int)INS_COND_TRUE ]; + unsigned long cond_false = ins_type_counters[ (int)INS_COND_FALSE ]; + unsigned long cond_jump = ins_type_counters[ (int)INS_COND_JUMP ]; + unsigned long cycles = ins_type_counters[ (int)INS_CYCLES ]; + unsigned long total = (unknown + left_total + right_total + ins_long); + + int size = strlen (add_commas (buf1, sizeof (buf1), total)); + int parallel_size = strlen (add_commas (buf1, sizeof (buf1), + (left_parallel > right_parallel) ? left_parallel : right_parallel)); + int cond_size = strlen (add_commas (buf1, sizeof (buf1), (left_cond > right_cond) ? left_cond : right_cond)); + int nop_size = strlen (add_commas (buf1, sizeof (buf1), (left_nops > right_nops) ? left_nops : right_nops)); + int normal_size = strlen (add_commas (buf1, sizeof (buf1), (left > right) ? left : right)); + + (*cr16_callback->printf_filtered) (cr16_callback, + "executed %*s left instruction(s), %*s normal, %*s parallel, %*s EXExxx, %*s nops\n", + size, add_commas (buf1, sizeof (buf1), left_total), + normal_size, add_commas (buf2, sizeof (buf2), left), + parallel_size, add_commas (buf3, sizeof (buf3), left_parallel), + cond_size, add_commas (buf4, sizeof (buf4), left_cond), + nop_size, add_commas (buf5, sizeof (buf5), left_nops)); + + (*cr16_callback->printf_filtered) (cr16_callback, + "executed %*s right instruction(s), %*s normal, %*s parallel, %*s EXExxx, %*s nops\n", + size, add_commas (buf1, sizeof (buf1), right_total), + normal_size, add_commas (buf2, sizeof (buf2), right), + parallel_size, add_commas (buf3, sizeof (buf3), right_parallel), + cond_size, add_commas (buf4, sizeof (buf4), right_cond), + nop_size, add_commas (buf5, sizeof (buf5), right_nops)); + + if (ins_long) + (*cr16_callback->printf_filtered) (cr16_callback, + "executed %*s long instruction(s)\n", + size, add_commas (buf1, sizeof (buf1), ins_long)); + + if (parallel) + (*cr16_callback->printf_filtered) (cr16_callback, + "executed %*s parallel instruction(s)\n", + size, add_commas (buf1, sizeof (buf1), parallel)); + + if (leftright) + (*cr16_callback->printf_filtered) (cr16_callback, + "executed %*s instruction(s) encoded L->R\n", + size, add_commas (buf1, sizeof (buf1), leftright)); + + if (rightleft) + (*cr16_callback->printf_filtered) (cr16_callback, + "executed %*s instruction(s) encoded R->L\n", + size, add_commas (buf1, sizeof (buf1), rightleft)); + + if (unknown) + (*cr16_callback->printf_filtered) (cr16_callback, + "executed %*s unknown instruction(s)\n", + size, add_commas (buf1, sizeof (buf1), unknown)); + + if (cond_true) + (*cr16_callback->printf_filtered) (cr16_callback, + "executed %*s instruction(s) due to EXExxx condition being true\n", + size, add_commas (buf1, sizeof (buf1), cond_true)); + + if (cond_false) + (*cr16_callback->printf_filtered) (cr16_callback, + "skipped %*s instruction(s) due to EXExxx condition being false\n", + size, add_commas (buf1, sizeof (buf1), cond_false)); + + if (cond_jump) + (*cr16_callback->printf_filtered) (cr16_callback, + "skipped %*s instruction(s) due to conditional branch succeeding\n", + size, add_commas (buf1, sizeof (buf1), cond_jump)); + + (*cr16_callback->printf_filtered) (cr16_callback, + "executed %*s cycle(s)\n", + size, add_commas (buf1, sizeof (buf1), cycles)); + + (*cr16_callback->printf_filtered) (cr16_callback, + "executed %*s total instructions\n", + size, add_commas (buf1, sizeof (buf1), total)); +#endif +} + +SIM_RC +sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **env) +{ + bfd_vma start_address; + + /* reset all state information */ + memset (&State.regs, 0, (int)&State.mem - (int)&State.regs); + + /* There was a hack here to copy the values of argc and argv into r0 + and r1. The values were also saved into some high memory that + won't be overwritten by the stack (0x7C00). The reason for doing + this was to allow the 'run' program to accept arguments. Without + the hack, this is not possible anymore. If the simulator is run + from the debugger, arguments cannot be passed in, so this makes + no difference. */ + + /* set PC */ + if (abfd != NULL) + start_address = bfd_get_start_address (abfd); + else + start_address = 0x0; +#ifdef DEBUG + if (cr16_debug) + (*cr16_callback->printf_filtered) (cr16_callback, "sim_create_inferior: PC=0x%lx\n", (long) start_address); +#endif + SET_CREG (PC_CR, start_address); + + SLOT_FLUSH (); + return SIM_RC_OK; +} + + +void +sim_set_callbacks (p) + host_callback *p; +{ + cr16_callback = p; +} + +void +sim_stop_reason (sd, reason, sigrc) + SIM_DESC sd; + enum sim_stop *reason; + int *sigrc; +{ +/* (*cr16_callback->printf_filtered) (cr16_callback, "sim_stop_reason: PC=0x%x\n",PC<<2); */ + + switch (State.exception) + { + case SIG_CR16_STOP: /* stop instruction */ + *reason = sim_stopped; + *sigrc = 0; + break; + + case SIG_CR16_EXIT: /* exit trap */ + *reason = sim_exited; + *sigrc = GPR (2); + break; + + case SIG_CR16_BUS: + *reason = sim_stopped; + *sigrc = TARGET_SIGNAL_BUS; + break; +// +// case SIG_CR16_IAD: +// *reason = sim_stopped; +// *sigrc = TARGET_SIGNAL_IAD; +// break; + + default: /* some signal */ + *reason = sim_stopped; + if (stop_simulator && !State.exception) + *sigrc = TARGET_SIGNAL_INT; + else + *sigrc = State.exception; + break; + } + + stop_simulator = 0; +} + +int +sim_fetch_register (sd, rn, memory, length) + SIM_DESC sd; + int rn; + unsigned char *memory; + int length; +{ + int size; + switch ((enum sim_cr16_regs) rn) + { + case SIM_CR16_R0_REGNUM: + case SIM_CR16_R1_REGNUM: + case SIM_CR16_R2_REGNUM: + case SIM_CR16_R3_REGNUM: + case SIM_CR16_R4_REGNUM: + case SIM_CR16_R5_REGNUM: + case SIM_CR16_R6_REGNUM: + case SIM_CR16_R7_REGNUM: + case SIM_CR16_R8_REGNUM: + case SIM_CR16_R9_REGNUM: + case SIM_CR16_R10_REGNUM: + case SIM_CR16_R11_REGNUM: + WRITE_16 (memory, GPR (rn - SIM_CR16_R0_REGNUM)); + size = 2; + break; + case SIM_CR16_R12_REGNUM: + case SIM_CR16_R13_REGNUM: + case SIM_CR16_R14_REGNUM: + case SIM_CR16_R15_REGNUM: + //WRITE_32 (memory, GPR (rn - SIM_CR16_R0_REGNUM)); + write_longword (memory, GPR (rn - SIM_CR16_R0_REGNUM)); + size = 4; + break; + case SIM_CR16_PC_REGNUM: + case SIM_CR16_ISP_REGNUM: + case SIM_CR16_USP_REGNUM: + case SIM_CR16_INTBASE_REGNUM: + case SIM_CR16_PSR_REGNUM: + case SIM_CR16_CFG_REGNUM: + case SIM_CR16_DBS_REGNUM: + case SIM_CR16_DCR_REGNUM: + case SIM_CR16_DSR_REGNUM: + case SIM_CR16_CAR0_REGNUM: + case SIM_CR16_CAR1_REGNUM: + //WRITE_32 (memory, CREG (rn - SIM_CR16_PC_REGNUM)); + write_longword (memory, CREG (rn - SIM_CR16_PC_REGNUM)); + size = 4; + break; + default: + size = 0; + break; + } + return size; +} + +int +sim_store_register (sd, rn, memory, length) + SIM_DESC sd; + int rn; + unsigned char *memory; + int length; +{ + int size; + switch ((enum sim_cr16_regs) rn) + { + case SIM_CR16_R0_REGNUM: + case SIM_CR16_R1_REGNUM: + case SIM_CR16_R2_REGNUM: + case SIM_CR16_R3_REGNUM: + case SIM_CR16_R4_REGNUM: + case SIM_CR16_R5_REGNUM: + case SIM_CR16_R6_REGNUM: + case SIM_CR16_R7_REGNUM: + case SIM_CR16_R8_REGNUM: + case SIM_CR16_R9_REGNUM: + case SIM_CR16_R10_REGNUM: + case SIM_CR16_R11_REGNUM: + SET_GPR (rn - SIM_CR16_R0_REGNUM, READ_16 (memory)); + size = 2; + break; + case SIM_CR16_R12_REGNUM: + case SIM_CR16_R13_REGNUM: + case SIM_CR16_R14_REGNUM: + case SIM_CR16_R15_REGNUM: + SET_GPR32 (rn - SIM_CR16_R0_REGNUM, get_longword (memory)); + size = 4; + break; + case SIM_CR16_PC_REGNUM: + case SIM_CR16_ISP_REGNUM: + case SIM_CR16_USP_REGNUM: + case SIM_CR16_INTBASE_REGNUM: + case SIM_CR16_PSR_REGNUM: + case SIM_CR16_CFG_REGNUM: + case SIM_CR16_DBS_REGNUM: + case SIM_CR16_DCR_REGNUM: + case SIM_CR16_DSR_REGNUM: + case SIM_CR16_CAR0_REGNUM: + case SIM_CR16_CAR1_REGNUM: + SET_CREG (rn - SIM_CR16_PC_REGNUM, get_longword (memory)); + size = 4; + break; + default: + size = 0; + break; + } + SLOT_FLUSH (); + return size; +} + + +void +sim_do_command (sd, cmd) + SIM_DESC sd; + char *cmd; +{ + (*cr16_callback->printf_filtered) (cr16_callback, "sim_do_command: %s\n",cmd); +} + +SIM_RC +sim_load (SIM_DESC sd, char *prog, struct bfd *abfd, int from_tty) +{ + extern bfd *sim_load_file (); /* ??? Don't know where this should live. */ + + if (prog_bfd != NULL && prog_bfd_was_opened_p) + { + bfd_close (prog_bfd); + prog_bfd_was_opened_p = 0; + } + prog_bfd = sim_load_file (sd, myname, cr16_callback, prog, abfd, + sim_kind == SIM_OPEN_DEBUG, + 1/*LMA*/, sim_write); + if (prog_bfd == NULL) + return SIM_RC_FAIL; + prog_bfd_was_opened_p = abfd == NULL; + return SIM_RC_OK; +} |