URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k/branches/oc/insight
- from Rev 106 to Rev 1765
- ↔ Reverse comparison
Rev 106 → Rev 1765
/gdb/config/or1k/tm-or1k.h
0,0 → 1,476
/* Definitions to target GDB to or1k targets. |
Copyright 2001 Free Software Foundation, Inc. |
|
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. */ |
|
#ifndef TM_OR1K_H |
#define TM_OR1K_H |
|
#ifndef TARGET_OR1K |
#define TARGET_OR1K |
#endif |
|
struct value; |
|
struct struct_or1k_implementation |
{ |
/* Implementation version. */ |
unsigned int VR; |
/* Units present. */ |
unsigned int UPR; |
/* Number of total available matchpoints in this implementation. */ |
unsigned int num_matchpoints; |
/* Number of registers. */ |
unsigned int num_gpr_regs; |
unsigned int num_vf_regs; |
int vf_present; |
}; |
|
struct or1k_target_ops |
{ |
/* Name this target type. */ |
char *to_shortname; |
|
/* Init target. */ |
void (*to_init) PARAMS ((char *args)); |
/* Destruct target. */ |
void (*to_done) PARAMS ((void)); |
|
/* Read SPR register. |
Does not fail, places error no. in err instead or call error(). */ |
unsigned int (*to_read_spr_reg) PARAMS ((unsigned int regno)); |
/* Write SPR register. |
Does not fail, places error no. in err instead or call error(). */ |
void (*to_write_spr_reg) PARAMS ((unsigned int regno, unsigned int value)); |
|
/* Read TAP register. |
Does not fail, places error no. in err instead or call error(). */ |
unsigned int (*to_read_tap_reg) PARAMS ((unsigned int regno)); |
/* Write TAP register. |
Does not fail, places error no. in err instead or call error(). */ |
void (*to_write_tap_reg) PARAMS ((unsigned int regno, unsigned int value)); |
|
/* Executes extended command on the target. */ |
void (*to_exec_command) PARAMS ((char *args, int from_tty)); |
|
/* Associated target_ops. */ |
struct target_ops *gdb_ops; |
/* Should be OPS_MAGIC. */ |
int to_magic; |
}; |
|
|
#define DEFAULT_PROMPT "(or1k) " |
|
/* Special purpose regisers. */ |
#define SPR_GROUP_SIZE_BITS (16) |
#define SPR_GROUP_SIZE (1 << SPR_GROUP_SIZE_BITS) |
#define SPR_SYSTEM_GROUP (0) |
#define SPR_DEBUG_GROUP (6) |
#define SPR_GPR (24) |
#define SPR_VFPR (24+32) |
#define OR1K_NUM_SPR_GROUPS 11 |
|
/* Define register values. */ |
#define SPR_REG(group, index) (((group) << SPR_GROUP_SIZE_BITS) + (index)) |
|
#define VR_SPRNUM SPR_REG(SPR_SYSTEM_GROUP, 1) |
#define UPR_SPRNUM SPR_REG(SPR_SYSTEM_GROUP, 2) |
#define SR_SPRNUM SPR_REG(SPR_SYSTEM_GROUP, 3) |
#define CCR_SPRNUM(cid) SPR_REG(SPR_SYSTEM_GROUP, 4+cid) |
#define DVR0_SPRNUM SPR_REG(SPR_DEBUG_GROUP, 0) |
#define DCR0_SPRNUM SPR_REG(SPR_DEBUG_GROUP, 8) |
#define DMR1_SPRNUM SPR_REG(SPR_DEBUG_GROUP, 16) |
#define DMR2_SPRNUM SPR_REG(SPR_DEBUG_GROUP, 17) |
#define DCWR0_SPRNUM SPR_REG(SPR_DEBUG_GROUP, 18) |
#define DCWR1_SPRNUM SPR_REG(SPR_DEBUG_GROUP, 19) |
#define DSR_SPRNUM SPR_REG(SPR_DEBUG_GROUP, 20) |
#define DRR_SPRNUM SPR_REG(SPR_DEBUG_GROUP, 21) |
#define PC_SPRNUM SPR_REG(SPR_DEBUG_GROUP, 22) |
#define ZERO_REGNUM (0) |
#define SP_REGNUM (1) |
#define FP_REGNUM (2) |
#define A0_REGNUM (3) |
#define A5_REGNUM (8) |
#define LR_REGNUM (9) |
#define RV_REGNUM (11) |
#define VFA0_REGNUM (32+0) |
#define VFA5_REGNUM (32+5) |
#define VFRV_REGNUM (32+6) |
#define PC_REGNUM (64+0) |
#define PS_REGNUM (64+1) |
#define CCR_REGNUM (64+2) |
|
extern int or1k_regnum_to_sprnum PARAMS ((int regno)); |
#define REGNUM_TO_SPRNUM(regno) (or1k_regnum_to_sprnum(regno)) |
|
/* Defines for SPR bits. */ |
#define DMR1_ST (0x00400000) |
|
#define DRR_BE (0x00000001) |
#define DRR_SCE (0x00000002) |
#define DRR_RE (0x00000004) |
#define DRR_IME (0x00000008) |
#define DRR_DME (0x00000010) |
#define DRR_HPINTE (0x00000020) |
#define DRR_IIE (0x00000040) |
#define DRR_AE (0x00000080) |
#define DRR_LPINTE (0x00000100) |
#define DRR_IPFE (0x00000200) |
#define DRR_DPFE (0x00000400) |
#define DRR_BUSEE (0x00000800) |
#define DRR_RSTE (0x00001000) |
|
/* Number of matchpoints */ |
|
#define NUM_MATCHPOINTS (or1k_implementation.num_matchpoints) |
|
/* Number of machine GPR registers */ |
|
#define NUM_GPR_REGS (or1k_implementation.num_gpr_regs) |
#define MAX_GPR_REGS (32) |
|
/* Number of machine VF registers */ |
|
#define NUM_VF_REGS (or1k_implementation.num_vf_regs) |
#define MAX_VF_REGS (32) |
|
/* gdb mapping of registers */ |
#ifndef NUM_REGS |
#define NUM_REGS (MAX_GPR_REGS+MAX_VF_REGS+3) |
#endif |
|
/* Can act like a little or big endian. */ |
|
#if !defined (TARGET_BYTE_ORDER_DEFAULT) |
#define TARGET_BYTE_ORDER_DEFAULT BIG_ENDIAN |
#define TARGET_BYTE_ORDER_SELECTABLE_P (1) |
#endif |
|
/* Size (in bytes) of registers. */ |
|
#define OR1K_SPR_REGSIZE (4) |
#define OR1K_VF_REGSIZE (8) |
#define OR1K_GPR_REGSIZE ((OR1K_64BIT_IMPLEMENTATION)?(8):(4)) |
|
#define OR1K_IS_GPR(N) ((N) >= 0 && (N) < NUM_GPR_REGS) |
#define OR1K_IS_VF(N) ((N) >= NUM_GPR_REGS && (N) < NUM_GPR_REGS + NUM_VF_REGS) |
|
/* Register representation is the same as in memory. */ |
|
#define REGISTER_CONVERTIBLE(N) (0) |
|
/* Given the register index, return the name of the corresponding |
register. */ |
|
extern char *or1k_register_name PARAMS ((int regno)); |
#define REGISTER_NAME(regno) or1k_register_name (regno) |
|
/* Is this implementation 64 or 32 bit. |
WARNING: gdb or1k port is not yet prepared for 64b implementations! */ |
#define OR1K_64BIT_IMPLEMENTATION 0 |
|
/* Number of bytes of storage in the actual machine representation for |
register N. NOTE: This indirectly defines the register size |
transfered by the GDB protocol. If we have 64bit processor |
implementation, GPR register raw size is 8B, otherwise 4B. */ |
#define REGISTER_RAW_SIZE(N) ((OR1K_IS_GPR(N)?((OR1K_64BIT_IMPLEMENTATION)?\ |
(8):(4)):(OR1K_SPR_REGSIZE))) |
|
/* Number of bytes of storage in the program's representation |
for register N. Same as RAW_SIZE. */ |
|
#define REGISTER_VIRTUAL_SIZE(N) TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (N)) |
|
/* Return the GDB type object for the "standard" data type of data in |
register N. */ |
|
#ifndef REGISTER_VIRTUAL_TYPE |
#define REGISTER_VIRTUAL_TYPE(N) ((OR1K_IS_GPR(N))?(\ |
(OR1K_64BIT_IMPLEMENTATION)?(builtin_type_int64):(builtin_type_int)\ |
):(builtin_type_uint32)) |
#endif |
|
|
/* Largest value REGISTER_RAW_SIZE can have. */ |
|
#define MAX_REGISTER_RAW_SIZE ((OR1K_64BIT_IMPLEMENTATION)?(8):(4)) |
|
/* Largest value REGISTER_VIRTUAL_SIZE can have. */ |
|
#define MAX_REGISTER_VIRTUAL_SIZE ((OR1K_64BIT_IMPLEMENTATION)?(8):(4)) |
|
#define REGISTER_SIZE (MAX_REGISTER_VIRTUAL_SIZE) |
|
/* ABI uses R3 through R8 for args. */ |
#define OR1K_LAST_ARG_REGNUM (A5_REGNUM) |
#define OR1K_NUM_ARG_REGS (6) |
/* ABI uses VFR0 through VFR5 for float args. */ |
#define OR1K_LAST_FP_ARG_REGNUM (VFA5_REGNUM) |
#define OR1K_NUM_FP_ARG_REGS (6) |
|
/* Should not store into R0. */ |
|
#define CANNOT_STORE_REGISTER(N) ((N) == 0) |
|
/* Index within `registers' of the first byte of the space for |
register N. */ |
|
#define REGISTER_BYTE(N) ((N) * OR1K_SPR_REGSIZE) |
|
/* Total amount of space needed to store our copies of the machine's |
register state, the array `registers'. */ |
|
#define REGISTER_BYTES (NUM_REGS * OR1K_SPR_REGSIZE) |
|
/* BREAKPOINT_FROM_PC uses the program counter value to determine whether a |
16- or 32-bit breakpoint should be used. It returns a pointer |
to a string of bytes that encode a breakpoint instruction, stores |
the length of the string to *lenptr, and adjusts the pc (if necessary) to |
point to the actual memory location where the breakpoint should be |
inserted. */ |
extern unsigned char *or1k_breakpoint_from_pc PARAMS ((CORE_ADDR *bp_addr, int *bp_size)); |
#define BREAKPOINT_FROM_PC(pcptr, lenptr) or1k_breakpoint_from_pc (pcptr, lenptr) |
|
/* Amount PC must be decremented by after a breakpoint. |
This is often the number of bytes in BREAKPOINT |
but not always. */ |
|
#define DECR_PC_AFTER_BREAK 0 |
|
/* Amount PC must be decremented by after a breakpoint. |
This is often the number of bytes in BREAKPOINT |
but not always. */ |
|
#define DECR_PC_AFTER_BREAK 0 |
|
/* Extract from an array REGBUF containing the (raw) register state |
a function return value of type TYPE, and copy that, in virtual format, |
into VALBUF. */ |
|
extern void or1k_extract_return_value PARAMS ((struct type *, char[], char *)); |
#define EXTRACT_RETURN_VALUE(TYPE, REGBUF, VALBUF) \ |
or1k_extract_return_value (TYPE, REGBUF, VALBUF) |
|
/* Write into appropriate registers a function return value |
of type TYPE, given in virtual format. */ |
|
#define STORE_RETURN_VALUE(TYPE,VALBUF) \ |
{\ |
if (TYPE_CODE (TYPE) == TYPE_CODE_FLT)\ |
write_register_bytes (REGISTER_BYTE (VFRV_REGNUM), VALBUF, TYPE_LENGTH (TYPE));\ |
else\ |
write_register_bytes (REGISTER_BYTE (RV_REGNUM), VALBUF, TYPE_LENGTH (TYPE));\ |
} |
|
/* Extract from an array REGBUF containing the (raw) register state |
the address in which a function should return its structure value, |
as a CORE_ADDR (or an expression that can be used as one). */ |
/* The address is passed in a0 upon entry to the function, but when |
the function exits, the compiler has copied the value to v0. This |
convention is specified by the System V ABI, so I think we can rely |
on it. */ |
|
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \ |
(extract_address (REGBUF + REGISTER_BYTE (RV_REGNUM), \ |
REGISTER_RAW_SIZE (RV_REGNUM))) |
|
#define EXTRACT_STRUCT_VALUE_ADDRESS_P 1 |
|
/* Advance PC across any function entry prologue instructions |
to reach some "real" code. */ |
extern CORE_ADDR or1k_skip_prologue PARAMS ((CORE_ADDR addr)); |
#define SKIP_PROLOGUE(pc) (or1k_skip_prologue (pc)) |
|
/* FRAMES */ |
|
#define FRAME_ARGS_ADDRESS(fi) (fi)->frame |
|
#define FRAME_LOCALS_ADDRESS(fi) (fi)->frame |
|
/* FRAME_CHAIN takes a frame's nominal address |
and produces the frame's chain-pointer. */ |
|
#define FRAME_CHAIN(thisframe) (CORE_ADDR) or1k_frame_chain (thisframe) |
extern CORE_ADDR or1k_frame_chain PARAMS ((struct frame_info *)); |
|
/* Discard from the stack the innermost frame, restoring all registers. */ |
|
extern void or1k_pop_frame PARAMS ((void)); |
#define POP_FRAME or1k_pop_frame() |
|
|
/* Return number of args passed to a frame. |
Can return -1, meaning no way to tell. */ |
|
#define FRAME_NUM_ARGS(fi) (-1) |
|
/* Return number of bytes at start of arglist that are not really args. */ |
|
#define FRAME_ARGS_SKIP 0 |
|
/* Put here 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. */ |
|
extern void or1k_init_saved_regs PARAMS ((struct frame_info *)); |
#define FRAME_INIT_SAVED_REGS(frame_info) or1k_init_saved_regs (frame_info); |
|
/* Saved Pc. */ |
|
extern CORE_ADDR or1k_frame_saved_pc PARAMS ((struct frame_info *)); |
#define FRAME_SAVED_PC(FRAME) (or1k_frame_saved_pc(FRAME)) |
|
/* Set the return address register to point to the entry |
point of the program, where a breakpoint lies in wait. */ |
|
extern CORE_ADDR or1k_push_return_address PARAMS ((CORE_ADDR pc, CORE_ADDR sp)); |
#define PUSH_RETURN_ADDRESS(PC, SP) (or1k_push_return_address ((PC), (SP))) |
|
/* Immediately after a function call, return the saved pc. |
Can't always go through the frames for this because on some machines |
the new frame is not set up until the new function executes |
some instructions. */ |
|
#define SAVED_PC_AFTER_CALL(frame) read_register(LR_REGNUM) |
|
/* Offset from address of function to start of its code. |
Zero on most machines. */ |
|
#define FUNCTION_START_OFFSET (0) |
|
/* Floating point is IEEE compliant */ |
#define IEEE_FLOAT |
|
/* Is floating/vector unit present. */ |
#define OR1K_VF_PRESENT (or1k_implementation.vf_present) |
|
#define INIT_FRAME_PC /* Not necessary */ |
|
/* Stack grows downward. */ |
#define INNER_THAN(lhs,rhs) ((lhs) < (rhs)) |
|
/* Size of stack entry - in bytes. */ |
#define OR1K_STACK_ALIGN (8) |
/* Maximum struct size, that is still stored onto stack. */ |
#define OR1K_STRUCT_CONV_SIZE (8) |
#define STACK_ALIGN(addr) OR1K_STACK_ALIGN |
|
#define USE_STRUCT_CONVENTION(gcc_p, type) (TYPE_LENGTH (type) > OR1K_STRUCT_CONV_SIZE) |
|
/* Stack must be aligned on 32-bit boundaries when synthesizing |
function calls. PUSH_ARGUMENTS will handle it. */ |
extern CORE_ADDR or1k_push_arguments PARAMS ((int, struct value **, CORE_ADDR, int, CORE_ADDR)); |
#define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \ |
(or1k_push_arguments((nargs), (args), (sp), (struct_return), (struct_addr))) |
|
/* Return non-zero if PC points to an instruction which will cause a step |
to execute both the instruction at PC and an instruction at PC+4. */ |
extern int or1k_step_skips_delay PARAMS ((CORE_ADDR)); |
#define STEP_SKIPS_DELAY_P (1) |
#define STEP_SKIPS_DELAY(pc) (or1k_step_skips_delay (pc)) |
|
/* DUMMY CALLS */ |
#define USE_GENERIC_DUMMY_FRAMES 1 |
#define CALL_DUMMY {0} |
#define CALL_DUMMY_START_OFFSET (0) |
#define CALL_DUMMY_BREAKPOINT_OFFSET (0) |
#define SIZEOF_CALL_DUMMY_WORDS (0) |
#define CALL_DUMMY_LOCATION AT_ENTRY_POINT |
#define FIX_CALL_DUMMY(DUMMY, START, FUNADDR, NARGS, ARGS, TYPE, GCCP) |
|
/* Return a location where we can set a breakpoint that will be hit |
when an inferior function call returns. This is normally the |
program's entry point. */ |
#define CALL_DUMMY_ADDRESS() entry_point_address () |
#define SAVE_DUMMY_FRAME_TOS(SP) generic_save_dummy_frame_tos (SP) |
#define PC_IN_CALL_DUMMY(PC, SP, FP) generic_pc_in_call_dummy (PC, SP, FP) |
#define PUSH_DUMMY_FRAME generic_push_dummy_frame () |
|
/* Definitions and declarations used by or1k dependent files. */ |
#define OR1K_INSTLEN 4 /* Length of an instruction */ |
typedef unsigned long t_inst; /* Integer big enough to hold an instruction */ |
|
|
|
/* Defined in remote-or1k.c */ |
|
/* Target state names. */ |
extern const char *status_name[]; |
/* Target state. */ |
enum target_status |
{ |
TARGET_UNDEFINED, |
TARGET_CONNECTING, |
TARGET_DISCONNECTING, |
TARGET_RUNNING, |
TARGET_STOPPED |
}; |
|
#define REG_SPACE 0x00000000 |
#define REG_SPACE_END 0x7FFFFFFF |
#define MEM_SPACE 0x80000000 |
#define MEM_SPACE_END 0xFFFFFFFF |
|
/* Compare conditions for DCRx registers. */ |
|
enum enum_compare_condition |
{ |
CC_MASKED, CC_EQUAL, CC_LESS, CC_LESSE, CC_GREATE, CC_NEQUAL |
}; |
|
/* Compare operand to compare DVRx to. */ |
|
enum enum_compare_to |
{ |
CT_DISABLED, CT_FETCH, CT_LEA, CT_SEA, CT_LDATA, CT_SDATA |
}; |
|
|
/* DRCx struct */ |
struct dcr_struct |
{ |
int dp:1; |
enum enum_compare_condition cc:3; |
int sc:1; |
enum enum_compare_to ct:3; |
}; |
|
/* Possible errors are listed here. */ |
|
enum enum_errors |
{ |
ERR_NONE, ERR_CRC |
}; |
|
extern const char *or1k_err_name PARAMS ((int e)); |
|
extern struct struct_or1k_implementation or1k_implementation; |
extern unsigned int or1k_fetch_instruction PARAMS ((CORE_ADDR addr)); |
extern void or1k_fetch_registers PARAMS ((int regno)); |
|
/* Sets register/memory regno to data. */ |
extern void or1k_write_reg PARAMS ((unsigned int regno, unsigned int data)); |
|
/* Sets register/memory regno to data. */ |
extern unsigned int or1k_read_reg PARAMS ((unsigned int regno)); |
extern int err; |
|
#endif /* TM_OR1K_H */ |
/gdb/config/or1k/tm-or32.h
0,0 → 1,26
/* Definitions to target GDB to or1200 targets. |
Copyright 2001 Free Software Foundation, Inc. |
|
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. */ |
|
#ifndef TM_OR32_H |
#define TM_OR32_H |
|
#include "or1k/tm-or1k.h" |
|
#endif TM_OR32_H |
/gdb/remote-or1k.c
0,0 → 1,955
/* Remote debugging interface for various or1k debugging protocols. |
Copyright 1993-1995, 2000 Free Software Foundation, Inc. |
Contributed by Cygnus Support. Written by Marko Mlinar |
<markom@opencores.org> |
|
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 "inferior.h" |
#include "bfd.h" |
#include "symfile.h" |
#include "gdb_wait.h" |
#include "gdbcmd.h" |
#include "gdbcore.h" |
#include "target.h" |
#include "remote-utils.h" |
#include "gdb_string.h" |
#include "tm.h" |
|
#include <signal.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <sys/ioctl.h> |
#include <fcntl.h> |
|
extern void jtag_init PARAMS ((char * args)); |
extern unsigned int jtag_read_reg PARAMS ((unsigned int regno)); |
extern void jtag_write_reg PARAMS ((unsigned int regno, unsigned int data)); |
extern unsigned int jtag_read_tap_reg PARAMS ((unsigned int regno)); |
extern void jtag_write_tap_reg PARAMS ((unsigned int regno, unsigned int data)); |
extern void jtag_done PARAMS ((void)); |
|
struct target_ops or1k_jtag_ops; |
static struct or1k_target_ops or1k_target_jtag = |
{ |
"jtag", |
jtag_init, |
jtag_done, |
jtag_read_reg, |
jtag_write_reg, |
jtag_read_tap_reg, |
jtag_write_tap_reg, |
NULL, |
&or1k_jtag_ops, |
OPS_MAGIC |
}; |
|
struct target_ops or1k_sim_ops; |
static struct or1k_target_ops or1k_target_sim = |
{ |
"simulator", |
NULL, |
NULL, |
NULL, |
NULL, |
NULL, |
NULL, |
NULL, |
&or1k_sim_ops, |
OPS_MAGIC |
}; |
|
struct target_ops or1k_dummy_ops; |
static struct or1k_target_ops or1k_target_dummy = |
{ |
"dummy", |
NULL, |
NULL, |
NULL, |
NULL, |
NULL, |
NULL, |
NULL, |
&or1k_dummy_ops, |
OPS_MAGIC |
}; |
|
const char *str_err[] = |
{ |
"None", "CRC error" |
}; |
|
const char *status_name[] = |
{ |
"UNDEFINED", "CONNECTING", "DISCONNECTING", "RUNNING", "STOPPED" |
}; |
|
/* Implementation specific information. Set by or1k_initialize. */ |
struct struct_or1k_implementation or1k_implementation; |
|
/* Current target status. */ |
static enum target_status or1k_status = TARGET_UNDEFINED; |
|
/* The target vector. */ |
struct target_ops or1k_dummy_ops, or1k_jtag_ops, or1k_sim_ops; |
|
/* Currently active target description (if or1k_is_open == 1) */ |
static struct target_ops *current_ops; |
|
/* Currently active or1k target operations. */ |
static struct or1k_target_ops *current_or1k_target = NULL; |
|
/* Set to 1 if the target is open. */ |
static int or1k_is_open = 0; |
|
/* Error last occured, zero = ok. */ |
static int err = 0; |
|
/* Number of interrupts while waiting for process. */ |
static int interrupt_count = 0; |
|
/* Current register values. */ |
static unsigned int dmr1 = 0; |
static unsigned int dmr2 = 0; |
static unsigned int dsr = 0; |
static unsigned int drr = 0; |
|
/* Current watchpoints. */ |
static int dvr[8]; |
static struct dcr_struct dcr[8]; |
|
/* Handle low-level error that we can't recover from. Note that just |
error()ing out from target_wait or some such low-level place will cause |
all hell to break loose--the rest of GDB will tend to get left in an |
inconsistent state. */ |
|
static NORETURN void |
or1k_error (char *string,...) |
{ |
va_list args; |
|
va_start (args, string); |
|
target_terminal_ours (); |
wrap_here (""); /* Force out any buffered output */ |
gdb_flush (gdb_stdout); |
if (error_pre_print) |
fprintf_filtered (gdb_stderr, error_pre_print); |
vfprintf_filtered (gdb_stderr, string, args); |
fprintf_filtered (gdb_stderr, "\n"); |
va_end (args); |
gdb_flush (gdb_stderr); |
|
/* Clean up in such a way that or1k_close won't try to talk to the |
board (it almost surely won't work since we weren't able to talk to |
it). */ |
or1k_is_open = 0; |
|
printf_unfiltered ("Ending remote or1k debugging.\n"); |
target_mourn_inferior (); |
|
return_to_top_level (RETURN_ERROR); |
} |
|
const char * |
or1k_err_name (e) |
int e; |
{ |
return str_err[e]; |
} |
|
/* putc_readable - print a character, displaying non-printable chars in |
^x notation or in hex. */ |
|
static void |
fputc_readable (ch, file) |
int ch; |
struct ui_file *file; |
{ |
if (ch == '\n') |
fputc_unfiltered ('\n', file); |
else if (ch == '\r') |
fprintf_unfiltered (file, "\\r"); |
else if (ch < 0x20) /* ASCII control character */ |
fprintf_unfiltered (file, "^%c", ch + '@'); |
else if (ch >= 0x7f) /* non-ASCII characters (rubout or greater) */ |
fprintf_unfiltered (file, "[%02x]", ch & 0xff); |
else |
fputc_unfiltered (ch, file); |
} |
|
|
/* puts_readable - print a string, displaying non-printable chars in |
^x notation or in hex. */ |
|
static void |
fputs_readable (string, file) |
char *string; |
struct ui_file *file; |
{ |
int c; |
|
while ((c = *string++) != '\0') |
fputc_readable (c, file); |
} |
|
/* Sets register/memory regno to data. */ |
|
void |
or1k_write_reg (regno, data) |
unsigned int regno; |
unsigned int data; |
{ |
if (current_or1k_target != NULL && current_or1k_target->to_write_spr_reg != NULL) |
current_or1k_target->to_write_spr_reg (regno, data); |
} |
|
/* Reads register/memory from regno. */ |
|
unsigned int |
or1k_read_reg (regno) |
unsigned int regno; |
{ |
if (current_or1k_target != NULL && current_or1k_target->to_read_spr_reg != NULL) |
return current_or1k_target->to_read_spr_reg (regno); |
else |
return 0x1234; |
} |
|
/* Stalls the CPU. */ |
|
static void |
or1k_stall () |
{ |
//!!! or1k_write_tap_reg (xxx, xxx); |
} |
|
/* Unstalls the CPU. */ |
|
static void |
or1k_unstall () |
{ |
//!!! or1k_write_tap_reg (xxx, xxx); |
} |
|
static void |
or1k_set_undefined_cleanups (arg) |
PTR arg; |
{ |
or1k_status = TARGET_UNDEFINED; |
} |
|
/* Initialize a new connection to the or1k board, and make sure we are |
really connected. */ |
|
static void |
or1k_init (args) |
char *args; |
{ |
struct cleanup *old_cleanups = make_cleanup (or1k_set_undefined_cleanups, NULL); |
int i; |
|
/* What is this code doing here? I don't see any way it can happen, and |
it might mean or1k_initializing didn't get cleared properly. |
So I'll make it a warning. */ |
|
if (or1k_status == TARGET_CONNECTING) |
{ |
warning ("internal error: or1k_initialize called twice"); |
return; |
} |
|
or1k_status = TARGET_CONNECTING; |
or1k_stall (); |
if (current_or1k_target != NULL && current_or1k_target->to_init != NULL) |
current_or1k_target->to_init (args); |
|
/* Determine implementation configuration. */ |
or1k_implementation.VR = or1k_read_reg (VR_SPRNUM); |
or1k_implementation.UPR = or1k_read_reg (UPR_SPRNUM); |
|
/* Determine max number of supported matchpoints. */ |
or1k_implementation.num_matchpoints = 2; |
or1k_implementation.num_gpr_regs = 32; |
/*!!! FINISH */ |
|
|
/* Is implementation supported? */ |
|
/* First we should have system and debug groups implemented. */ |
if (or1k_implementation.VR & (1 << SPR_SYSTEM_GROUP) == 0) |
error ("System group should be available in the or1k implementation."); |
if (or1k_implementation.VR & (1 << SPR_DEBUG_GROUP) == 0) |
error ("Debug group should be available in the or1k implementation."); |
|
|
|
/* Delete break, watch, catch points. */ |
for(i = 0; i < NUM_MATCHPOINTS; i++) |
or1k_write_reg (DCR0_SPRNUM + i, 0); |
|
dmr1 = 0; |
or1k_write_reg (DMR1_SPRNUM, dmr1); |
dmr2 = 0; |
or1k_write_reg (DMR2_SPRNUM, dmr2); |
if (err != 0) |
error ("Cannot connect."); |
|
/* Stop when breakpoint occurs. */ |
or1k_write_reg (DSR_SPRNUM, 0x1000); |
|
do_cleanups (old_cleanups); |
|
/* This should cause an error if not connected. */ |
or1k_fetch_registers (-1); |
|
set_current_frame (create_new_frame (read_fp (), read_pc ())); |
select_frame (get_current_frame (), 0); |
} |
|
/* Kill the process running on the board. */ |
|
void |
or1k_kill () |
{ |
if (or1k_status != TARGET_RUNNING) |
return; |
or1k_status = TARGET_UNDEFINED; |
/* HW STEP. Set DMR1_ST. */ |
dmr1 |= DMR1_ST; |
or1k_write_reg (DMR1_SPRNUM, dmr1); |
dmr1 &= ~DMR1_ST; |
or1k_stall(); |
or1k_status = TARGET_UNDEFINED; |
|
inferior_pid = 0; |
} |
|
/* Open a connection to the remote board. */ |
|
static void |
or1k_open (name, from_tty) |
char *name; |
int from_tty; |
{ |
or1k_init (name); |
|
/* Switch to using remote target now. */ |
current_ops = current_or1k_target->gdb_ops; |
or1k_is_open = 1; |
push_target (current_ops); |
|
/* FIXME: Should we call start_remote here? */ |
|
/* This is really the job of start_remote however, that makes an assumption |
that the target is about to print out a status message of some sort. That |
doesn't happen here (in fact, it may not be possible to get the monitor to |
send the appropriate packet). */ |
|
flush_cached_frames (); |
registers_changed (); |
stop_pc = read_pc (); |
set_current_frame (create_new_frame (read_fp (), stop_pc)); |
select_frame (get_current_frame (), 0); |
print_stack_frame (selected_frame, -1, 1); |
} |
|
/* Close a connection to the remote board. */ |
|
static void |
or1k_close (quitting) |
int quitting; |
{ |
if (or1k_is_open) |
{ |
or1k_kill (); |
if (current_or1k_target != NULL && current_or1k_target->to_done != NULL) |
current_or1k_target->to_done (); |
current_or1k_target = NULL; |
} |
generic_mourn_inferior (); |
} |
|
/* Detach from the remote board. */ |
|
static void |
or1k_detach (args, from_tty) |
char *args; |
int from_tty; |
{ |
if (args) |
error ("Argument given to \"detach\" when remotely debugging."); |
|
pop_target (); |
|
or1k_close (1); |
|
if (from_tty) |
printf_unfiltered ("Ending remote or1k debugging.\n"); |
} |
|
/* Resume execution of the target process. STEP says whether to single-step |
or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given |
to the target, or zero for no signal. */ |
|
static void |
or1k_resume (pid, step, siggnal) |
int pid, step; |
enum target_signal siggnal; |
{ |
if (or1k_status != TARGET_STOPPED) |
if (or1k_status == TARGET_RUNNING) |
error ("Program is already running."); |
else |
error ("The program is not being run."); |
|
/* Clear reason register for later. */ |
or1k_write_reg (DRR_SPRNUM, 0); |
|
if (step) |
{ |
/* HW STEP. Set DMR1_ST. */ |
dmr1 |= DMR1_ST; |
or1k_write_reg (DMR1_SPRNUM, dmr1); |
dmr1 &= ~DMR1_ST; |
} |
|
/* Run the target. */ |
or1k_unstall (); |
or1k_status = TARGET_RUNNING; |
} |
|
/* Wait until the remote stops, and return a wait status. */ |
|
static int |
or1k_wait (pid, status) |
int pid; |
struct target_waitstatus *status; |
{ |
interrupt_count = 0; |
|
/* If we have not sent a single step or continue command, then the |
board is waiting for us to do something. Return a status |
indicating that it is stopped. */ |
if (or1k_status != TARGET_RUNNING) |
{ |
if (or1k_status != TARGET_STOPPED) |
error("Target in invalid state."); |
status->kind = TARGET_WAITKIND_STOPPED; |
status->value.sig = TARGET_SIGNAL_TRAP; |
return 0; |
} |
|
if (err) |
or1k_error ("Remote failure: %s", or1k_err_name (err)); |
|
/* Wait for or1k DRR register to be nonzero. */ |
do |
{ |
drr = or1k_read_reg (DRR_SPRNUM); |
usleep (10); |
} |
while (drr == 0); |
|
status->kind = TARGET_WAITKIND_STOPPED; |
|
if (drr & DRR_RSTE) |
status->value.sig = TARGET_SIGNAL_REALTIME_33; |
else if (drr & DRR_BUSEE) |
status->value.sig = TARGET_SIGNAL_BUS; |
else if (drr & DRR_DPFE) |
status->value.sig = TARGET_SIGNAL_REALTIME_34; |
else if (drr & DRR_IPFE) |
status->value.sig = TARGET_SIGNAL_REALTIME_35; |
else if (drr & DRR_LPINTE) |
status->value.sig = TARGET_SIGNAL_INT; |
else if (drr & DRR_AE) |
status->value.sig = TARGET_SIGNAL_REALTIME_36; |
else if (drr & DRR_IIE) |
status->value.sig = TARGET_SIGNAL_ILL; |
else if (drr & DRR_HPINTE) |
status->value.sig = TARGET_SIGNAL_INT; |
else if (drr & DRR_DME) |
status->value.sig = TARGET_SIGNAL_REALTIME_37; |
else if (drr & DRR_IME) |
status->value.sig = TARGET_SIGNAL_REALTIME_38; |
else if (drr & DRR_RE) |
status->value.sig = TARGET_SIGNAL_REALTIME_39; |
else if (drr & DRR_SCE) |
status->value.sig = TARGET_SIGNAL_REALTIME_40; |
else if (drr & DRR_BE) |
status->value.sig = TARGET_SIGNAL_TRAP; |
else |
{ |
status->value.sig = TARGET_SIGNAL_UNKNOWN; |
warning ("Invalid exception occured."); |
} |
|
or1k_status = TARGET_STOPPED; |
|
/* If the stop PC is in the _exit function, assume |
we hit the 'break 0x3ff' instruction in _exit, so this |
is not a normal breakpoint. */ |
{ |
char *func_name; |
CORE_ADDR func_start; |
CORE_ADDR pc = read_pc (); |
|
find_pc_partial_function (pc, &func_name, &func_start, NULL); |
if (func_name != NULL && strcmp (func_name, "_exit") == 0 |
&& func_start == pc) |
status->kind = TARGET_WAITKIND_EXITED; |
} |
return 0; |
} |
|
/* Fetch a word from the target board. */ |
|
static unsigned int |
or1k_fetch_word (addr) |
CORE_ADDR addr; |
{ |
return or1k_read_reg (addr + MEM_SPACE); |
} |
|
/* Store a word to the target board. Returns errno code or zero for |
success. */ |
static int |
or1k_store_word (addr, val) |
CORE_ADDR addr; |
unsigned int val; |
{ |
or1k_write_reg (addr + MEM_SPACE, val); |
return err; |
} |
|
/* Fetch the remote registers. */ |
|
void |
or1k_fetch_registers (regno) |
int regno; |
{ |
unsigned int val; |
|
if (regno == -1) |
{ |
for (regno = 0; regno < NUM_REGS; regno++) |
or1k_fetch_registers (regno); |
return; |
} |
|
if (regno >= NUM_REGS) |
error("Invalid register number!"); |
|
/* Convert to SPRNUM and read. */ |
val = or1k_read_reg (REGNUM_TO_SPRNUM(regno) + REG_SPACE); |
|
{ |
char buf[MAX_REGISTER_RAW_SIZE]; |
|
/* We got the number the register holds, but gdb expects to see a |
value in the target byte ordering. */ |
store_unsigned_integer (buf, REGISTER_RAW_SIZE (regno), val); |
supply_register (regno, buf); |
} |
if (err) |
or1k_error ("Can't read register %d(%i): %s", regno, REGNUM_TO_SPRNUM(regno) + REG_SPACE, or1k_err_name (err)); |
} |
|
/* Fetch and return instruction from the specified location. */ |
|
unsigned int |
or1k_fetch_instruction (addr) |
CORE_ADDR addr; |
{ |
char buf[OR1K_INSTLEN]; |
int status; |
|
status = read_memory_nobpt (addr, buf, OR1K_INSTLEN); |
if (status) |
memory_error (status, addr); |
return extract_unsigned_integer (buf, OR1K_INSTLEN); |
} |
|
static void |
or1k_prepare_to_store () |
{ |
} |
|
/* Store remote register(s). */ |
|
static void |
or1k_store_registers (regno) |
int regno; |
{ |
if (regno == -1) |
{ |
for (regno = 0; regno < NUM_REGS; regno++) |
or1k_store_registers (regno); |
return; |
} |
|
if (regno >= NUM_REGS) |
error("Invalid register number!"); |
|
or1k_write_reg (REGNUM_TO_SPRNUM(regno) + REG_SPACE, or1k_read_reg (REGNUM_TO_SPRNUM(regno) + REG_SPACE)); |
if (err) |
or1k_error ("Can't write register %d(%i): %s", regno, REGNUM_TO_SPRNUM(regno) + REG_SPACE, or1k_err_name (err)); |
} |
|
/* Read or write LEN bytes from inferior memory at MEMADDR, |
transferring to or from debugger address MYADDR. Write to inferior |
if SHOULD_WRITE is nonzero. Returns length of data written or |
read; 0 for error. Note that protocol gives us the correct value |
for a longword, since it transfers values in ASCII. We want the |
byte values, so we have to swap the longword values. */ |
|
static int |
or1k_xfer_memory (memaddr, myaddr, len, write, ignore) |
CORE_ADDR memaddr; |
char *myaddr; |
int len; |
int write; |
struct target_ops *ignore; |
{ |
register int i; |
/* Round starting address down to longword boundary. */ |
register CORE_ADDR addr = memaddr & ~3; |
/* Round ending address up; get number of longwords that makes. */ |
register int count = (((memaddr + len) - addr) + 3) / 4; |
/* Allocate buffer of that many longwords. */ |
register char *buffer = alloca (count * 4); |
|
int status; |
|
if (memaddr >= MEM_SPACE) |
error("Invalid address"); |
|
if (write) |
{ |
/* Fill start and end extra bytes of buffer with existing data. */ |
if (addr != memaddr || len < 4) |
{ |
/* Need part of initial word -- fetch it. */ |
store_unsigned_integer (&buffer[0], 4, or1k_fetch_word (addr)); |
} |
|
if (count > 1) |
{ |
/* Need part of last word -- fetch it. FIXME: we do this even |
if we don't need it. */ |
store_unsigned_integer (&buffer[(count - 1) * 4], 4, |
or1k_fetch_word (addr + (count - 1) * 4)); |
} |
|
/* Copy data to be written over corresponding part of buffer */ |
|
memcpy ((char *) buffer + (memaddr & 3), myaddr, len); |
|
/* Write the entire buffer. */ |
|
for (i = 0; i < count; i++, addr += 4) |
{ |
status = or1k_store_word (addr, |
extract_unsigned_integer (&buffer[i * 4], 4)); |
/* Report each kilobyte (we download 32-bit words at a time) */ |
if (i % 256 == 255) |
{ |
printf_unfiltered ("*"); |
gdb_flush (gdb_stdout); |
} |
if (status) |
{ |
errno = status; |
return 0; |
} |
/* FIXME: Do we want a QUIT here? */ |
} |
if (count >= 256) |
printf_unfiltered ("\n"); |
} |
else |
{ |
/* Read all the longwords */ |
for (i = 0; i < count; i++, addr += 4) |
{ |
store_unsigned_integer (&buffer[i * 4], 4, or1k_fetch_word (addr)); |
QUIT; |
} |
|
/* Copy appropriate bytes out of the buffer. */ |
memcpy (myaddr, buffer + (memaddr & 3), len); |
} |
return len; |
} |
|
/* Print info on this target. */ |
|
static void |
or1k_files_info (ignore) |
struct target_ops *ignore; |
{ |
char *file = "nothing"; |
|
if (exec_bfd) |
file = bfd_get_filename (exec_bfd); |
|
printf_filtered ("or1k_files_info: file \"%s\"\n", file); |
|
if (exec_bfd) |
{ |
printf_filtered ("\tAttached to %s running program %s\n", |
target_shortname, file); |
} |
/* Print target info. */ |
printf_filtered ("Status: %s\n", status_name[or1k_status]); |
} |
|
|
/* We can write a breakpoint and read the shadow contents in one |
operation. */ |
|
/* Tell whether we can support a hardware breakpoint. */ |
static int |
or1k_can_use_hardware_breakpoint () |
{ |
int i; |
/* Search for unused breakpoint. */ |
for (i = 0; i < NUM_MATCHPOINTS; i++) |
if (dcr[i].dp == 0) |
return 1; |
return 0; |
} |
|
/* Insert a breakpoint. On targets that don't have built-in breakpoint |
support, we read the contents of the target location and stash it, |
then overwrite it with a breakpoint instruction. ADDR is the target |
location in the target machine. CONTENTS_CACHE is a pointer to |
memory allocated for saving the target contents. It is guaranteed |
by the caller to be long enough to save sizeof BREAKPOINT bytes (this |
is accomplished via BREAKPOINT_MAX). */ |
|
static int |
or1k_insert_breakpoint (addr, contents_cache) |
CORE_ADDR addr; |
char *contents_cache; |
{ |
if (or1k_can_use_hardware_breakpoint()) |
return set_breakpoint (addr); |
else |
return memory_insert_breakpoint (addr, contents_cache); |
} |
|
static int |
or1k_remove_breakpoint (addr, contents_cache) |
CORE_ADDR addr; |
char *contents_cache; |
{ |
/* First try to remove HW breakpoint at address */ |
if (clear_breakpoint (addr)) |
return memory_remove_breakpoint (addr, contents_cache); |
else |
return 0; |
} |
|
/* Insert a breakpoint. */ |
|
int |
set_breakpoint (addr) |
CORE_ADDR addr; |
{ |
int i; |
unsigned int u; |
/* Search for unused breakpoint. */ |
for (i = 0; i < NUM_MATCHPOINTS; i++) |
if (dcr[i].dp == 0) break; |
if (i >= NUM_MATCHPOINTS) return 1; |
dvr[i] = addr; |
dcr[i].dp = 1; |
dcr[i].cc = CC_EQUAL; |
dcr[i].sc = 0; |
dcr[i].ct = CT_FETCH; |
or1k_write_reg (DVR0_SPRNUM + i, dvr[i]); |
memcpy (&u, &dcr[i], sizeof(dcr[i])); |
or1k_write_reg (DCR0_SPRNUM + i, u); |
return 0; |
} |
|
/* Clear a breakpoint. */ |
|
int |
clear_breakpoint (addr) |
CORE_ADDR addr; |
{ |
int i; |
unsigned int u; |
/* Search for matching breakpoint. */ |
for (i = 0; i < NUM_MATCHPOINTS; i++) |
if ((dcr[i].dp == 1) && (dvr[i] == addr) && (dcr[i].cc == CC_EQUAL) |
&& (dcr[i].sc == 0) && (dcr[i].ct == CT_FETCH)) break; |
|
if (i >= NUM_MATCHPOINTS) return 1; |
dcr[i].dp = 0; |
memcpy (&u, &dcr[i], sizeof(dcr[i])); |
or1k_write_reg (DCR0_SPRNUM + i, u); |
return 0; |
} |
|
/* Start running on the target board. */ |
|
static void |
or1k_create_inferior (execfile, args, env) |
char *execfile; |
char *args; |
char **env; |
{ |
CORE_ADDR entry_pt; |
|
if (args && *args) |
{ |
warning ("\ |
Can't pass arguments to remote OR1K board; arguments ignored."); |
/* And don't try to use them on the next "run" command. */ |
execute_command ("set args", 0); |
} |
|
if (execfile == 0 || exec_bfd == 0) |
error ("No executable file specified"); |
|
or1k_kill (); |
remove_breakpoints (); |
|
entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd); |
init_wait_for_inferior (); |
|
/* FIXME: Should we set inferior_pid here? */ |
//inferior_pid = 42; |
insert_breakpoints (); /* Needed to get correct instruction in cache */ |
clear_proceed_status (); |
or1k_status = TARGET_STOPPED; |
proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0); |
} |
|
/* Clean up after a process. Actually nothing to do. */ |
|
static void |
or1k_mourn_inferior () |
{ |
generic_mourn_inferior (); |
} |
|
static void |
or1k_dummy_open (name, from_tty) |
char *name; |
int from_tty; |
{ |
target_preopen (from_tty); |
if (or1k_is_open) |
unpush_target (current_ops); |
current_or1k_target = &or1k_target_dummy; |
or1k_open (name, from_tty); |
} |
|
static void |
or1k_jtag_open (name, from_tty) |
char *name; |
int from_tty; |
{ |
target_preopen (from_tty); |
if (or1k_is_open) |
unpush_target (current_ops); |
current_or1k_target = &or1k_target_jtag; |
or1k_open (name, from_tty); |
} |
|
static void |
or1k_sim_open (name, from_tty) |
char *name; |
int from_tty; |
{ |
/* target_preopen (from_tty); - do we need this ? */ |
if (or1k_is_open) |
unpush_target (current_ops); |
current_or1k_target = &or1k_target_sim; |
or1k_open (name, from_tty); |
} |
|
/* Executes command on the target. */ |
|
void |
or1k_sim_cmd (char *args, int from_tty) |
{ |
if (current_or1k_target != NULL && current_or1k_target->to_exec_command != NULL) |
current_or1k_target->to_exec_command (args, from_tty); |
else |
error ("Command not supported on this target. "); |
} |
|
void |
_initialize_remote_or1k () |
{ |
/* Initialize the fields in or1k_ops that are common to all targets. */ |
or1k_dummy_ops.to_close = or1k_close; |
or1k_dummy_ops.to_detach = or1k_detach; |
or1k_dummy_ops.to_resume = or1k_resume; |
or1k_dummy_ops.to_wait = or1k_wait; |
or1k_dummy_ops.to_fetch_registers = or1k_fetch_registers; |
or1k_dummy_ops.to_store_registers = or1k_store_registers; |
or1k_dummy_ops.to_prepare_to_store = or1k_prepare_to_store; |
or1k_dummy_ops.to_xfer_memory = or1k_xfer_memory; |
or1k_dummy_ops.to_files_info = or1k_files_info; |
or1k_dummy_ops.to_insert_breakpoint = or1k_insert_breakpoint; |
or1k_dummy_ops.to_remove_breakpoint = or1k_remove_breakpoint; |
or1k_dummy_ops.to_kill = or1k_kill; |
or1k_dummy_ops.to_load = generic_load; |
or1k_dummy_ops.to_create_inferior = or1k_create_inferior; |
or1k_dummy_ops.to_mourn_inferior = or1k_mourn_inferior; |
or1k_dummy_ops.to_stratum = process_stratum; |
or1k_dummy_ops.to_has_all_memory = 0; /* We can access memory while program is running. */ |
or1k_dummy_ops.to_has_memory = 1; |
or1k_dummy_ops.to_has_stack = 1; |
or1k_dummy_ops.to_has_registers = 1; |
or1k_dummy_ops.to_has_execution = 1; |
or1k_dummy_ops.to_magic = OPS_MAGIC; |
//or1k_ops.to_wait = or1k_wait; |
|
/* Copy the common fields to all target vectors. */ |
or1k_jtag_ops = or1k_sim_ops = or1k_dummy_ops; |
|
/* Initialize target-specific fields in the target vectors adn add targets. */ |
or1k_jtag_ops.to_shortname = "jtag"; |
or1k_jtag_ops.to_longname = "Remote or1k debugging over JTAG port"; |
or1k_jtag_ops.to_doc = "\ |
Debug a board using the OR1K remote debugging protocol over a parallel line.\n\ |
The argument is the device it is connected to or, if it contains a colon,\n"; |
or1k_jtag_ops.to_open = or1k_jtag_open; |
add_target (&or1k_jtag_ops); |
|
or1k_dummy_ops.to_shortname = "dummy"; |
or1k_dummy_ops.to_longname = "Dummy target"; |
or1k_dummy_ops.to_doc = "Actually no real target attached - more like /dev/null.\n"; |
or1k_dummy_ops.to_open = or1k_dummy_open; |
add_target (&or1k_dummy_ops); |
|
or1k_sim_ops.to_shortname = "sim"; |
or1k_sim_ops.to_longname = "Remote or1k debugging using architecture simulator"; |
or1k_sim_ops.to_doc = "Debug using an architecture simulator.\n"; |
or1k_sim_ops.to_open = or1k_sim_open; |
add_target (&or1k_sim_ops); |
} |
/gdb/or1k-tdep.c
0,0 → 1,731
/* 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."); |
} |