URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [branches/] [oc/] [insight/] [gdb/] [or1k-tdep.c] - Rev 1771
Go to most recent revision | Compare with Previous | Blame | View Log
/* Target-dependent code for the or1k architecture, for GDB, the GNU Debugger. Copyright 1988-1999, Free Software Foundation, Inc. Contributed by Alessandro Forin(af@cs.cmu.edu at CMU and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin. This file is part of GDB. 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 2 of the License, 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "gdb_string.h" #include "frame.h" #include "inferior.h" #include "symtab.h" #include "value.h" #include "gdbcmd.h" #include "language.h" #include "gdbcore.h" #include "symfile.h" #include "objfiles.h" #include "gdbtypes.h" #include "target.h" #include "opcode/or32.h" /* *INDENT-OFF* */ /* Group reg name size. See or1k_reg_names. */ int or1k_group_name_sizes[OR1K_NUM_SPR_GROUPS] = { 64, 0, 0, 0, 0, 0, (24+32+32), 0, 0, 0 }; /* Generated reg names. See or1k_internal_reg_name. */ int or1k_spr_valid_aliases[OR1K_NUM_SPR_GROUPS] = { 64, 515, 0, 0, 0, 0, (24+32+32), 0, 0, 0 }; /* Register names. */ char *or1k_reg_names[] = { /* group 0 - general*/ "?", "VR", "UPR", "SR", "EPCR0", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "EPCR0", "EPCR1", "EPCR2", "EPCR3", "EPCR4", "EPCR5", "EPCR6", "EPCR7", "EPCR8", "EPCR9", "EPCR10", "EPCR11", "EPCR12", "EPCR13", "EPCR14", "EPCR15", "EEAR0","EEAR1", "EEAR2", "EEAR3", "EEAR4", "EEAR5", "EEAR6", "EEAR7", "EEAR8", "EEAR9", "EEAR10", "EEAR11", "EEAR12", "EEAR13", "EEAR14", "EEAR15", "ESR0", "ESR1", "ESR2", "ESR3", "ESR4", "ESR5", "ESR6", "ESR7", "ESR8", "ESR9", "ESR10", "ESR11", "ESR12", "ESR13", "ESR14", "ESR15", /* group 1 - Data MMU - not listed, generated */ /* group 6 - debug */ "DVR0", "DVR1", "DVR2", "DVR3", "DVR4", "DVR5", "DVR6", "DVR7", "DCR0", "DCR1", "DCR2", "DCR3", "DCR4", "DCR5", "DCR6", "DCR7", "DMR1", "DMR2", "DCWR0", "DCWR1", "DSR", "DRR", "PC", "?", /* general purpose registers */ "ZERO", "SP", "FP", "A0", "A1", "A2", "A3", "A4", "A5", "LR", "R10", "RV", "R12", "R13", "R14", "R15", "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31", /* vector/floating point registers */ "VFA0", "VFA1", "VFA2", "VFA3", "VFA4", "VFA5", "VFRV ", "VFR7", "VFR8", "VFR9", "VFR10", "VFR11", "VFR12", "VFR13", "VFR14", "VFR15", "VFR16", "VFR17", "VFR18", "VFR19", "VFR20", "VFR21", "VFR22", "VFR23", "VFR24", "VFR25", "VFR26", "VFR27", "VFR28", "VFR29", "VFR30", "VFR31" }; static char *or1k_group_names[] = { "SYS", "DMMU", "IMMU", "DCACHE", "ICACHE", "MAC", "DEBUG", "PERF", "POWER", "PIC", "TIMER" }; /* *INDENT-ON* */ /* The list of available "set or1k " and "show or1k " commands */ static struct cmd_list_element *setor1kcmdlist = NULL; static struct cmd_list_element *showor1kcmdlist = NULL; /* List of all saved register addresses, produced by skip_prologue. Relative address to sp, not used if 0. */ static int or1k_saved_reg_addr[NUM_REGS]; /* Converts regno to sprno. or1k debug unit has GPRs mapped to SPRs, which are not compact, so we are mapping them for GDB. */ int or1k_regnum_to_sprnum (int regno) { if (regno < MAX_GPR_REGS + MAX_VF_REGS) return SPR_REG(SPR_DEBUG_GROUP, regno + SPR_GPR); if (regno == PC_REGNUM) return PC_SPRNUM; if (regno == PS_REGNUM) return SR_SPRNUM; if (regno == CCR_REGNUM) return CCR_SPRNUM(0); error ("Invalid register number!"); } /* Builds and returns register name. */ static char tmp_name[16]; static char * or1k_internal_register_name (i) int i; { int group = i >> SPR_GROUP_SIZE_BITS; int index = i & (SPR_GROUP_SIZE - 1); switch (group) { /* Names covered in or1k_reg_names. */ case 0: case 6: { int group_start = 0; for (i = 0; i < group; i++) group_start += or1k_group_name_sizes[i]; if (index >= or1k_group_name_sizes[group]) { sprintf (tmp_name, "SPR%i_%i", group, index); return (char *)&tmp_name; } else return or1k_reg_names[group_start + index]; } /* Build names for MMU group. */ case 1: if (index < 256) { sprintf (tmp_name, "DTLBMR%i", index); return (char *)&tmp_name; } index -= 256; if (index < 256) { sprintf (tmp_name, "DTLBTR%i", index); return (char *)&tmp_name; } index -= 256; switch (index) { case 0: return "DMMUCR"; case 1: return "DMMUPR"; case 2: return "DTLBEIR"; default: sprintf (tmp_name, "SPR1_%i", index+512); return (char *)&tmp_name; } default: sprintf (tmp_name, "SPR%i_%i", group, index); return (char *)&tmp_name; } } /* Get register index in group from name. Negative if no match. */ static int or1k_regno_from_name (group, name) int group; char *name; { int i; if (toupper(name[0]) == 'S' && toupper(name[1]) == 'P' && toupper(name[2]) == 'R') { char *ptr_c; name += 3; i = (int) strtoul (name, &ptr_c, 10); if (*ptr_c != '_' || i != group) return -1; ptr_c++; i = (int) strtoul (name, &ptr_c, 10); if (*ptr_c) return -1; else return i; } for (i = 0; i < or1k_spr_valid_aliases[group]; i++) { char *s; s = or1k_internal_register_name (SPR_REG(group, i)); if (strcasecmp (name, s) == 0) return i; } return -1; } #define OR1K_BREAKPOINT_STRUCT {0x21, 0x00, 0x00, 0x00} /* Resturs gdb register name. */ char * or1k_register_name (regno) int regno; { return or1k_internal_register_name (REGNUM_TO_SPRNUM(regno)); } /* Given the address at which to insert a breakpoint (BP_ADDR), what will that breakpoint be? For or1k, we have a breakpoint instruction. Since all or1k instructions are 32 bits, this is all we need, regardless of address. K is not used. */ unsigned char * or1k_breakpoint_from_pc (bp_addr, bp_size) CORE_ADDR * bp_addr; int *bp_size; { static char breakpoint[] = OR1K_BREAKPOINT_STRUCT; *bp_size = OR1K_INSTLEN; return breakpoint; } /* Given a return value in `regbuf' with a type `valtype', extract and copy its value into `valbuf'. */ void or1k_extract_return_value (valtype, regbuf, valbuf) struct type *valtype; char regbuf[REGISTER_BYTES]; char *valbuf; { if (TYPE_CODE_FLT == TYPE_CODE (valtype)) memcpy (valbuf, ®buf[REGISTER_BYTE (VFRV_REGNUM)], TYPE_LENGTH (valtype)); else memcpy (valbuf, ®buf[REGISTER_BYTE (RV_REGNUM)], TYPE_LENGTH (valtype)); } /* The or1k cc defines the following prologue: 00000000 <_proc1>: 0: d7 e1 17 e4 l.sw 0xffffffe4(r1),r2 4: 9c 41 00 00 l.addi r2,r1,0x0 8: 9c 21 ff e8 l.addi r1,r1,0xffffffe8 c: d7 e2 1f f8 l.sw 0xfffffff8(r2),r3 10: d7 e2 27 f4 l.sw 0xfffffff4(r2),r4 14: 84 82 ff f8 l.lwz r4,0xfffffff8(r2) 18: 9d 24 00 00 l.addi r9,r4,0x0 1c: 00 00 00 02 l.j 0x2 20: 15 00 00 00 l.nop 00000024 <_L2>: 24: 84 41 ff fc l.lwz r2,0xfffffffc(r1) 28: 48 00 58 00 l.jalr r11 2c: 9c 21 00 18 l.addi r1,r1,0x18 */ CORE_ADDR or1k_skip_prologue (CORE_ADDR pc) { unsigned long inst; CORE_ADDR skip_pc; CORE_ADDR func_addr, func_end; struct symtab_and_line sal; int i; int offset = 0; for (i = 0; i < MAX_GPR_REGS; i++) or1k_saved_reg_addr[i] = -1; /* Is there a prologue? */ inst = or1k_fetch_instruction (pc); if (inst & 0xfc1ff800 != 0xd4011000) return pc; /* l.sw I(r1),r2 */ or1k_saved_reg_addr[2] = offset++; inst = or1k_fetch_instruction (pc + OR1K_INSTLEN); if (inst & 0xFFFF0000 != 0x9c410000) return pc; /* l.addi r2,r1,I */ pc += 2 * OR1K_INSTLEN; inst = or1k_fetch_instruction (pc); if (inst & 0xFFFF0000 != 0x9c210000) return pc; /* l.addi r1,r1,I */ pc += OR1K_INSTLEN; /* Skip stored registers. */ inst = or1k_fetch_instruction (pc); while (inst & 0xfc1ff800 != 0xd4020000) /* l.sw 0x0(r2),rx */ { /* get saved reg. */ or1k_saved_reg_addr[(inst >> 11) & 0x1f] = offset++; pc += OR1K_INSTLEN; inst = or1k_fetch_instruction (pc); } return pc; } /* Determines whether this function has frame. */ int or1k_frameless_function_invocation (struct frame_info *fi) { CORE_ADDR func_start, after_prologue; int frameless; func_start = (get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET); after_prologue = SKIP_PROLOGUE (func_start); /* If we don't skip pc, we don't have even shortest possible prologue. */ frameless = (after_prologue <= func_start); return frameless; } /* Given a GDB frame, determine the address of the calling function's frame. This will be used to create a new GDB frame struct, and then INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame. */ CORE_ADDR or1k_frame_chain (frame) struct frame_info *frame; { CORE_ADDR fp; if (USE_GENERIC_DUMMY_FRAMES) { if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)) return frame->frame; /* dummy frame same as caller's frame */ } if (inside_entry_file (frame->pc) || frame->pc == entry_point_address ()) return 0; if (frame->signal_handler_caller) fp = read_memory_integer (frame->frame, 4); else if (frame->next != NULL && frame->next->signal_handler_caller && FRAMELESS_FUNCTION_INVOCATION (frame)) /* A frameless function interrupted by a signal did not change the frame pointer. */ fp = FRAME_FP (frame); else fp = read_memory_integer (frame->frame, 4); if (USE_GENERIC_DUMMY_FRAMES) { CORE_ADDR fpp, lr; lr = read_register (LR_REGNUM); if (lr == entry_point_address ()) if (fp != 0 && (fpp = read_memory_integer (fp, 4)) != 0) if (PC_IN_CALL_DUMMY (lr, fpp, fpp)) return fpp; } return fp; } /* The code to store, into a struct frame_saved_regs, the addresses of the saved registers of frame described by FRAME_INFO. This includes special registers such as pc and fp saved in special ways in the stack frame. sp is even more special: the address we return for it IS the sp for the next frame. */ void or1k_init_saved_regs (struct frame_info *fi) { CORE_ADDR frame_addr; int i; frame_saved_regs_zalloc (fi); /* Skip prologue sets or1k_saved_reg_addr[], we will use it later. */ or1k_skip_prologue (get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET); for (i = 0; i < NUM_GPR_REGS+NUM_VF_REGS; i++) if (or1k_saved_reg_addr[i] >= 0) fi->saved_regs[i] = fi->frame + or1k_saved_reg_addr[i]; } static CORE_ADDR read_next_frame_reg (fi, regno) struct frame_info *fi; int regno; { for (; fi; fi = fi->next) { /* We have to get the saved sp from the sigcontext if it is a signal handler frame. */ if (regno == SP_REGNUM && !fi->signal_handler_caller) return fi->frame; else { if (fi->saved_regs == NULL) or1k_init_saved_regs (fi); if (fi->saved_regs[regno]) return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), OR1K_GPR_REGSIZE); } } return read_register (regno); } /* Find the caller of this frame. We do this by seeing if LR_REGNUM is saved in the stack anywhere, otherwise we get it from the registers. */ CORE_ADDR or1k_frame_saved_pc (fi) struct frame_info *fi; { CORE_ADDR saved_pc; /* We have to get the saved pc from the sigcontext if it is a signal handler frame. */ if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) saved_pc = read_memory_integer (fi->frame, OR1K_GPR_REGSIZE); else saved_pc = read_next_frame_reg (fi, PC_REGNUM); return ADDR_BITS_REMOVE (saved_pc); } /* Discard from the stack the innermost frame, restoring all registers. */ void or1k_pop_frame () { register int regnum; struct frame_info *frame = get_current_frame (); CORE_ADDR new_sp = FRAME_FP (frame); write_register (PC_REGNUM, FRAME_SAVED_PC (frame)); if (frame->saved_regs == NULL) or1k_init_saved_regs (frame); for (regnum = 0; regnum < NUM_REGS; regnum++) { if (regnum != SP_REGNUM && regnum != PC_REGNUM && frame->saved_regs[regnum] >= 0) write_register (regnum, read_memory_integer (frame->saved_regs[regnum], OR1K_GPR_REGSIZE)); } write_register (SP_REGNUM, new_sp); flush_cached_frames (); } CORE_ADDR or1k_push_arguments (nargs, args, sp, struct_return, struct_addr) int nargs; value_ptr *args; CORE_ADDR sp; int struct_return; CORE_ADDR struct_addr; { int argreg; int float_argreg; int argnum; int len = 0; int stack_offset = 0; /* Initialize the integer and float register pointers. */ argreg = A0_REGNUM; float_argreg = VFA0_REGNUM; /* The struct_return pointer occupies the RV value register. */ if (struct_return) write_register (RV_REGNUM, struct_addr); /* Now load as many as possible of the first arguments into registers, and push the rest onto the stack. Loop thru args from first to last. */ for (argnum = 0; argnum < nargs; argnum++) { char *val; char valbuf[MAX_REGISTER_RAW_SIZE]; value_ptr arg = args[argnum]; struct type *arg_type = check_typedef (VALUE_TYPE (arg)); int len = TYPE_LENGTH (arg_type); enum type_code typecode = TYPE_CODE (arg_type); /* The EABI passes structures that do not fit in a register by reference. In all other cases, pass the structure by value. */ if (len > OR1K_GPR_REGSIZE && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) { store_address (valbuf, OR1K_GPR_REGSIZE, VALUE_ADDRESS (arg)); typecode = TYPE_CODE_PTR; len = OR1K_GPR_REGSIZE; val = valbuf; } else { val = (char *) VALUE_CONTENTS (arg); if (typecode == TYPE_CODE_FLT /* Doubles are not stored in regs on 32b target. */ && len <= OR1K_VF_REGSIZE && OR1K_VF_PRESENT) { if (float_argreg <= OR1K_LAST_FP_ARG_REGNUM) { CORE_ADDR regval = extract_address (val, len); write_register (float_argreg++, regval); } else { write_memory ((CORE_ADDR) sp, val, OR1K_VF_REGSIZE); sp -= OR1K_STACK_ALIGN; } } else { if (argreg <= OR1K_LAST_ARG_REGNUM) { CORE_ADDR regval = extract_address (val, len); write_register (argreg++, regval); } else { write_memory ((CORE_ADDR) sp, val, OR1K_GPR_REGSIZE); sp -= OR1K_STACK_ALIGN; } } } } /* Return adjusted stack pointer. */ return sp; } /* Return nonzero when instruction has delay slot. */ static int is_delayed (insn) unsigned long insn; { int i; for (i = 0; i < num_opcodes; ++i) if ((or32_opcodes[i].flags & OR32_IF_DELAY) && (or32_opcode_match (insn, or32_opcodes[i].encoding))) break; return (i < num_opcodes); } int or1k_step_skips_delay (pc) CORE_ADDR pc; { char buf[OR1K_INSTLEN]; if (target_read_memory (pc, buf, OR1K_INSTLEN) != 0) /* If error reading memory, guess that it is not a delayed branch. */ return 0; return is_delayed ((unsigned long) extract_unsigned_integer (buf, OR1K_INSTLEN)); } CORE_ADDR or1k_push_return_address (pc, sp) CORE_ADDR pc; CORE_ADDR sp; { /* Set the return address register to point to the entry point of the program, where a breakpoint lies in wait. */ write_register (LR_REGNUM, CALL_DUMMY_ADDRESS ()); return sp; } /* Root of all "set or1k "/"show or1k " commands. This will eventually be used for all OR1K-specific commands. */ static void show_or1k_command PARAMS ((char *, int)); static void show_or1k_command (args, from_tty) char *args; int from_tty; { help_list (showor1kcmdlist, "show or1k ", all_commands, gdb_stdout); } static void set_or1k_command PARAMS ((char *, int)); static void set_or1k_command (args, from_tty) char *args; int from_tty; { printf_unfiltered ("\"set or1k\" must be followed by an appropriate subcommand.\n"); help_list (setor1kcmdlist, "set or1k ", all_commands, gdb_stdout); } static char * parse_spr_params (args, group, index) char *args; int *group, *index; { *index = -1; if (args) { int i; char *ptr_c; /* Check if group number was supplied. */ ptr_c = args; while (*ptr_c != ' ' && *ptr_c != 0) ptr_c++; *ptr_c = 0; *group = (int) strtoul (args, &ptr_c, 0); if (*ptr_c != 0) { *group = OR1K_NUM_SPR_GROUPS; /* check for group name */ for (i = 0; i < OR1K_NUM_SPR_GROUPS; i++) if (strcasecmp (or1k_group_names[i], args) == 0) { *group = i; break; } /* Invalid group => check all register names in all groups. */ if (*group >= OR1K_NUM_SPR_GROUPS) { for (i = 0; i < OR1K_NUM_SPR_GROUPS; i++) { int regno; regno = or1k_regno_from_name (i, args); if (regno >= 0) { *group = i; *index = regno; } } } } if (*group < 0 || *group >= OR1K_NUM_SPR_GROUPS) error ("Invalid group or register.\n"); if (*index < 0) { args += strlen(args) + 1; ptr_c = args; while (*ptr_c != ' ' && *ptr_c != 0) ptr_c++; *ptr_c = 0; *index = (int) strtoul (args, &ptr_c, 0); if (*ptr_c != 0) *index = or1k_regno_from_name (*group, args); if (*index < 0) { for (i = 0; i < or1k_spr_valid_aliases[*group]; i++) printf_unfiltered ("%s\t", or1k_internal_register_name (SPR_REG(*group, i))); printf_unfiltered ("\n"); return args + strlen(args) + 1; } } } else /* No parameters - print groups */ { int i; printf_unfiltered ("No parameter supplied. Valid groups are:\n"); for (i = 0; i < OR1K_NUM_SPR_GROUPS; i++) printf_unfiltered ("%s\t", or1k_group_names[i]); printf_unfiltered ("\nSingle register name or register name or number after the group can be also supplied.\n"); } return args + strlen(args) + 1; } /* SPR register info. */ void info_spr_cmd (char *args, int from_tty) { int group, index; parse_spr_params (args, &group, &index); if (index >= 0) { printf_unfiltered ("%s.%s (SPR%i_%i) set to %i(%X), was:%i(%X)\n", or1k_group_names[group], or1k_internal_register_name (SPR_REG(group, index)), group, index, or1k_read_reg (SPR_REG(group, index))); } } /* Set SPR register. */ void spr_cmd (char *args, int from_tty) { int group, index; char *nargs = parse_spr_params (args, &group, &index); /* Any arguments left? */ if (args + strlen(args) >= nargs) error ("Invalid register value."); if (index >= 0) { unsigned long prev; unsigned long value; char *ptr_c; prev = or1k_read_reg (SPR_REG(group, index)); ptr_c = nargs; while (*ptr_c != ' ' && *ptr_c != 0) ptr_c++; *ptr_c = 0; value = strtoul (nargs, &ptr_c, 0); if (*ptr_c != 0) error ("Invalid register value."); printf_unfiltered ("%s.%s (SPR%i_%i) set to %i(%X), was:%i(%X)\n", or1k_group_names[group], or1k_internal_register_name (SPR_REG(group, index)), group, index, value, value, prev, prev); } } /* Calls extended command on target. */ void sim_command (char *args, int from_tty) { or1k_sim_cmd (args, from_tty); } void _initialize_or1k_tdep () { struct cmd_list_element *c; /* Add root prefix command for all "set or1k"/"show or1k" commands */ add_prefix_cmd ("or1k", no_class, set_or1k_command, "Various OR1K specific commands.", &setor1kcmdlist, "set or1k ", 0, &setlist); add_prefix_cmd ("or1k", no_class, show_or1k_command, "Various OR1K specific commands.", &showor1kcmdlist, "show or1k ", 0, &showlist); /* Commands to show information about the sprs. */ add_cmd ("spr", class_info, info_spr_cmd, "Show information about the spr registers.", &infolist); c = add_cmd ("spr", class_support, spr_cmd, "Set specified SPR register.", &cmdlist); add_com ("sim", class_obscure, sim_command, "Send a extended command to the simulator."); }
Go to most recent revision | Compare with Previous | Blame | View Log