+ On the Hitachi SH architecture, there are four registers (R4 to R7)
+ which are dedicated for passing function arguments. Up to the first
+ four arguments (depending on size) may go into these registers.
+ The rest go on the stack.
+
+ Arguments that are smaller than 4 bytes will still take up a whole
+ register or a whole 32-bit word on the stack, and will be
+ right-justified in the register or the stack word. This includes
+ chars, shorts, and small aggregate types.
+
+ Arguments that are larger than 4 bytes may be split between two or
+ more registers. If there are not enough registers free, an argument
+ may be passed partly in a register (or registers), and partly on the
+ stack. This includes doubles, long longs, and larger aggregates.
+ As far as I know, there is no upper limit to the size of aggregates
+ that will be passed in this way; in other words, the convention of
+ passing a pointer to a large aggregate instead of a copy is not used.
+
+ An exceptional case exists for struct arguments (and possibly other
+ aggregates such as arrays) if the size is larger than 4 bytes but
+ not a multiple of 4 bytes. In this case the argument is never split
+ between the registers and the stack, but instead is copied in its
+ entirety onto the stack, AND also copied into as many registers as
+ there is room for. In other words, space in registers permitting,
+ two copies of the same argument are passed in. As far as I can tell,
+ only the one on the stack is used, although that may be a function
+ of the level of compiler optimization. I suspect this is a compiler
+ bug. Arguments of these odd sizes are left-justified within the
+ word (as opposed to arguments smaller than 4 bytes, which are
+ right-justified).
+
+ If the function is to return an aggregate type such as a struct, it
+ is either returned in the normal return value register R0 (if its
+ size is no greater than one byte), or else the caller must allocate
+ space into which the callee will copy the return value (if the size
+ is greater than one byte). In this case, a pointer to the return
+ value location is passed into the callee in register R2, which does
+ not displace any of the other arguments passed in via registers R4
+ to R7. */
+
+static CORE_ADDR
+sh_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ int stack_offset, stack_alloc;
+ int argreg;
+ int argnum;
+ struct type *type;
+ CORE_ADDR regval;
+ char *val;
+ char valbuf[4];
+ int len;
+ int odd_sized_struct;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ /* first force sp to a 4-byte alignment */
+ sp = sp & ~3;
+
+ /* The "struct return pointer" pseudo-argument has its own dedicated
+ register */
+ if (struct_return)
+ write_register (STRUCT_RETURN_REGNUM, struct_addr);
+
+ /* Now make sure there's space on the stack */
+ for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
+ stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
+ sp -= stack_alloc; /* make room on stack for args */
+
+ /* Now load as many as possible of the first arguments into
+ registers, and push the rest onto the stack. There are 16 bytes
+ in four registers available. Loop thru args from first to last. */
+
+ argreg = tdep->ARG0_REGNUM;
+ for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
+ {
+ type = VALUE_TYPE (args[argnum]);
+ len = TYPE_LENGTH (type);
+ memset (valbuf, 0, sizeof (valbuf));
+ if (len < 4)
+ {
+ /* value gets right-justified in the register or stack word */
+ memcpy (valbuf + (4 - len),
+ (char *) VALUE_CONTENTS (args[argnum]), len);
+ val = valbuf;
+ }
+ else
+ val = (char *) VALUE_CONTENTS (args[argnum]);
+
+ if (len > 4 && (len & 3) != 0)
+ odd_sized_struct = 1; /* such structs go entirely on stack */
+ else
+ odd_sized_struct = 0;
+ while (len > 0)
+ {
+ if (argreg > tdep->ARGLAST_REGNUM
+ || odd_sized_struct)
+ {
+ /* must go on the stack */
+ write_memory (sp + stack_offset, val, 4);
+ stack_offset += 4;
+ }
+ /* NOTE WELL!!!!! This is not an "else if" clause!!!
+ That's because some *&^%$ things get passed on the stack
+ AND in the registers! */
+ if (argreg <= tdep->ARGLAST_REGNUM)
+ {
+ /* there's room in a register */
+ regval = extract_address (val, REGISTER_RAW_SIZE (argreg));
+ write_register (argreg++, regval);
+ }
+ /* Store the value 4 bytes at a time. This means that things
+ larger than 4 bytes may go partly in registers and partly
+ on the stack. */
+ len -= REGISTER_RAW_SIZE (argreg);
+ val += REGISTER_RAW_SIZE (argreg);
+ }
+ }
+ return sp;
+}
+
+/* R2-R9 for integer types and integer equivalent (char, pointers) and
+ non-scalar (struct, union) elements (even if the elements are
+ floats).
+ FR0-FR11 for single precision floating point (float)
+ DR0-DR10 for double precision floating point (double)
+
+ If a float is argument number 3 (for instance) and arguments number
+ 1,2, and 4 are integer, the mapping will be:
+ arg1 -->R2, arg2 --> R3, arg3 -->FR0, arg4 --> R5. I.e. R4 is not used.
+
+ If a float is argument number 10 (for instance) and arguments number
+ 1 through 10 are integer, the mapping will be:
+ arg1->R2, arg2->R3, arg3->R4, arg4->R5, arg5->R6, arg6->R7, arg7->R8,
+ arg8->R9, arg9->(0,SP)stack(8-byte aligned), arg10->FR0, arg11->stack(16,SP).
+ I.e. there is hole in the stack.
+
+ Different rules apply for variable arguments functions, and for functions
+ for which the prototype is not known. */
+
+static CORE_ADDR
+sh64_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ int stack_offset, stack_alloc;
+ int int_argreg;
+ int float_argreg;
+ int double_argreg;
+ int float_arg_index = 0;
+ int double_arg_index = 0;
+ int argnum;
+ struct type *type;
+ CORE_ADDR regval;
+ char *val;
+ char valbuf[8];
+ char valbuf_tmp[8];
+ int len;
+ int argreg_size;
+ int fp_args[12];
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ memset (fp_args, 0, sizeof (fp_args));
+
+ /* first force sp to a 8-byte alignment */
+ sp = sp & ~7;
+
+ /* The "struct return pointer" pseudo-argument has its own dedicated
+ register */
+
+ if (struct_return)
+ write_register (STRUCT_RETURN_REGNUM, struct_addr);
+
+ /* Now make sure there's space on the stack */
+ for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
+ stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 7) & ~7);
+ sp -= stack_alloc; /* make room on stack for args */
+
+ /* Now load as many as possible of the first arguments into
+ registers, and push the rest onto the stack. There are 64 bytes
+ in eight registers available. Loop thru args from first to last. */
+
+ int_argreg = tdep->ARG0_REGNUM;
+ float_argreg = FP0_REGNUM;
+ double_argreg = tdep->DR0_REGNUM;
+
+ for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
+ {
+ type = VALUE_TYPE (args[argnum]);
+ len = TYPE_LENGTH (type);
+ memset (valbuf, 0, sizeof (valbuf));
+
+ if (TYPE_CODE (type) != TYPE_CODE_FLT)
+ {
+ argreg_size = REGISTER_RAW_SIZE (int_argreg);
+
+ if (len < argreg_size)
+ {
+ /* value gets right-justified in the register or stack word */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ memcpy (valbuf + argreg_size - len,
+ (char *) VALUE_CONTENTS (args[argnum]), len);
+ else
+ memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
+
+ val = valbuf;
+ }
+ else
+ val = (char *) VALUE_CONTENTS (args[argnum]);
+
+ while (len > 0)
+ {
+ if (int_argreg > tdep->ARGLAST_REGNUM)
+ {
+ /* must go on the stack */
+ write_memory (sp + stack_offset, val, argreg_size);
+ stack_offset += 8;/*argreg_size;*/
+ }
+ /* NOTE WELL!!!!! This is not an "else if" clause!!!
+ That's because some *&^%$ things get passed on the stack
+ AND in the registers! */
+ if (int_argreg <= tdep->ARGLAST_REGNUM)
+ {
+ /* there's room in a register */
+ regval = extract_address (val, argreg_size);
+ write_register (int_argreg, regval);
+ }
+ /* Store the value 8 bytes at a time. This means that
+ things larger than 8 bytes may go partly in registers
+ and partly on the stack. FIXME: argreg is incremented
+ before we use its size. */
+ len -= argreg_size;
+ val += argreg_size;
+ int_argreg++;
+ }
+ }
+ else
+ {
+ val = (char *) VALUE_CONTENTS (args[argnum]);
+ if (len == 4)
+ {
+ /* Where is it going to be stored? */
+ while (fp_args[float_arg_index])
+ float_arg_index ++;
+
+ /* Now float_argreg points to the register where it
+ should be stored. Are we still within the allowed
+ register set? */
+ if (float_arg_index <= tdep->FLOAT_ARGLAST_REGNUM)
+ {
+ /* Goes in FR0...FR11 */
+ write_register_gen (FP0_REGNUM + float_arg_index, val);
+ fp_args[float_arg_index] = 1;
+ /* Skip the corresponding general argument register. */
+ int_argreg ++;
+ }
+ else
+ ;
+ /* Store it as the integers, 8 bytes at the time, if
+ necessary spilling on the stack. */
+
+ }
+ else if (len == 8)
+ {
+ /* Where is it going to be stored? */
+ while (fp_args[double_arg_index])
+ double_arg_index += 2;
+ /* Now double_argreg points to the register
+ where it should be stored.
+ Are we still within the allowed register set? */
+ if (double_arg_index < tdep->FLOAT_ARGLAST_REGNUM)
+ {
+ /* Goes in DR0...DR10 */
+ /* The numbering of the DRi registers is consecutive,
+ i.e. includes odd numbers. */
+ int double_register_offset = double_arg_index / 2;
+ int regnum = tdep->DR0_REGNUM +
+ double_register_offset;
+#if 0
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ {
+ memset (valbuf_tmp, 0, sizeof (valbuf_tmp));
+ REGISTER_CONVERT_TO_VIRTUAL (regnum,
+ type, val, valbuf_tmp);
+ val = valbuf_tmp;
+ }
+#endif
+ /* Note: must use write_register_gen here instead
+ of regcache_write, because regcache_write works
+ only for real registers, not pseudo.
+ write_register_gen will call the gdbarch
+ function to do register writes, and that will
+ properly know how to deal with pseudoregs. */
+ write_register_gen (regnum, val);
+ fp_args[double_arg_index] = 1;
+ fp_args[double_arg_index + 1] = 1;
+ /* Skip the corresponding general argument register. */
+ int_argreg ++;
+ }
+ else
+ ;
+ /* Store it as the integers, 8 bytes at the time, if
+ necessary spilling on the stack. */
+ }
+ }
+ }
+ return sp;
+}
+
+/* Function: push_return_address (pc)
+ Set up the return address for the inferior function call.
+ Needed for targets where we don't actually execute a JSR/BSR instruction */
+
+static CORE_ADDR
+sh_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+{
+ write_register (gdbarch_tdep (current_gdbarch)->PR_REGNUM,
+ CALL_DUMMY_ADDRESS ());
+ return sp;
+}
+
+/* Function: fix_call_dummy
+ Poke the callee function's address into the destination part of
+ the CALL_DUMMY. The address is actually stored in a data word
+ following the actualy CALL_DUMMY instructions, which will load
+ it into a register using PC-relative addressing. This function
+ expects the CALL_DUMMY to look like this:
+
+ mov.w @(2,PC), R8
+ jsr @R8
+ nop
+ trap
+ <destination>
+ */
+
+#if 0
+void
+sh_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+ struct value **args, struct type *type, int gcc_p)
+{
+ *(unsigned long *) (dummy + 8) = fun;
+}
+#endif
+
+static int
+sh_coerce_float_to_double (struct type *formal, struct type *actual)
+{
+ return 1;
+}
+
+/* Find a function's return value in the appropriate registers (in
+ regbuf), and copy it into valbuf. 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. */
+static void
+sh_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ int return_register = R0_REGNUM;
+ int offset;
+
+ if (len <= 4)
+ {
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = REGISTER_BYTE (return_register) + 4 - len;
+ else
+ offset = REGISTER_BYTE (return_register);
+ memcpy (valbuf, regbuf + offset, len);
+ }
+ else if (len <= 8)
+ {
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = REGISTER_BYTE (return_register) + 8 - len;
+ else
+ offset = REGISTER_BYTE (return_register);
+ memcpy (valbuf, regbuf + offset, len);
+ }
+ else
+ error ("bad size for return value");
+}
+
+static void
+sh3e_sh4_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+{
+ int return_register;
+ int offset;
+ int len = TYPE_LENGTH (type);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ return_register = FP0_REGNUM;
+ else
+ return_register = R0_REGNUM;
+
+ if (len == 8 && TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ DOUBLEST val;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ floatformat_to_doublest (&floatformat_ieee_double_littlebyte_bigword,
+ (char *) regbuf + REGISTER_BYTE (return_register),
+ &val);
+ else
+ floatformat_to_doublest (&floatformat_ieee_double_big,
+ (char *) regbuf + REGISTER_BYTE (return_register),
+ &val);
+ store_floating (valbuf, len, val);
+ }
+ else if (len <= 4)
+ {
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = REGISTER_BYTE (return_register) + 4 - len;
+ else
+ offset = REGISTER_BYTE (return_register);
+ memcpy (valbuf, regbuf + offset, len);
+ }
+ else if (len <= 8)
+ {
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = REGISTER_BYTE (return_register) + 8 - len;
+ else
+ offset = REGISTER_BYTE (return_register);
+ memcpy (valbuf, regbuf + offset, len);
+ }
+ else
+ error ("bad size for return value");
+}
+
+static void
+sh64_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+{
+ int offset;
+ int return_register;
+ int len = TYPE_LENGTH (type);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ if (len == 4)
+ {
+ /* Return value stored in FP0_REGNUM */
+ return_register = FP0_REGNUM;
+ offset = REGISTER_BYTE (return_register);
+ memcpy (valbuf, (char *) regbuf + offset, len);
+ }
+ else if (len == 8)
+ {
+ /* return value stored in DR0_REGNUM */
+ DOUBLEST val;
+
+ return_register = tdep->DR0_REGNUM;
+ offset = REGISTER_BYTE (return_register);
+
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ floatformat_to_doublest (&floatformat_ieee_double_littlebyte_bigword,
+ (char *) regbuf + offset, &val);
+ else
+ floatformat_to_doublest (&floatformat_ieee_double_big,
+ (char *) regbuf + offset, &val);
+ store_floating (valbuf, len, val);
+ }
+ }
+ else
+ {
+ if (len <= 8)
+ {
+ /* Result is in register 2. If smaller than 8 bytes, it is padded
+ at the most significant end. */
+ return_register = tdep->RETURN_REGNUM;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = REGISTER_BYTE (return_register) +
+ REGISTER_RAW_SIZE (return_register) - len;
+ else
+ offset = REGISTER_BYTE (return_register);
+ memcpy (valbuf, (char *) regbuf + offset, len);
+ }
+ else
+ error ("bad size for return value");
+ }
+}
+
+/* Write into appropriate registers a function return value
+ of type TYPE, given in virtual format.
+ If the architecture is sh4 or sh3e, store a function's return value
+ in the R0 general register or in the FP0 floating point register,
+ depending on the type of the return value. In all the other cases
+ the result is stored in r0, left-justified. */
+static void
+sh_default_store_return_value (struct type *type, char *valbuf)
+{
+ char buf[32]; /* more than enough... */
+
+ if (TYPE_LENGTH (type) < REGISTER_RAW_SIZE (R0_REGNUM))
+ {
+ /* Add leading zeros to the value. */
+ memset (buf, 0, REGISTER_RAW_SIZE (R0_REGNUM));
+ memcpy (buf + REGISTER_RAW_SIZE (R0_REGNUM) - TYPE_LENGTH (type),
+ valbuf, TYPE_LENGTH (type));
+ write_register_bytes (REGISTER_BYTE (R0_REGNUM), buf,
+ REGISTER_RAW_SIZE (R0_REGNUM));
+ }
+ else
+ write_register_bytes (REGISTER_BYTE (R0_REGNUM), valbuf,
+ TYPE_LENGTH (type));
+}
+
+static void
+sh3e_sh4_store_return_value (struct type *type, char *valbuf)
+{
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ write_register_bytes (REGISTER_BYTE (FP0_REGNUM),
+ valbuf, TYPE_LENGTH (type));
+ else
+ sh_default_store_return_value (type, valbuf);
+}
+
+static void
+sh64_store_return_value (struct type *type, char *valbuf)
+{
+ char buf[64]; /* more than enough... */
+ int len = TYPE_LENGTH (type);
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ if (len == 4)
+ {
+ /* Return value stored in FP0_REGNUM */
+ write_register_gen (FP0_REGNUM, valbuf);
+ }
+ if (len == 8)
+ {
+ /* return value stored in DR0_REGNUM */
+ /* FIXME: Implement */
+ }
+ }
+ else
+ {
+ int return_register = gdbarch_tdep (current_gdbarch)->RETURN_REGNUM;
+ int offset = 0;
+
+ if (len <= REGISTER_RAW_SIZE (return_register))
+ {
+ /* Pad with zeros. */
+ memset (buf, 0, REGISTER_RAW_SIZE (return_register));
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ offset = 0; /*REGISTER_RAW_SIZE (return_register) - len;*/
+ else
+ offset = REGISTER_RAW_SIZE (return_register) - len;
+
+ memcpy (buf + offset, valbuf, len);
+ write_register_gen (return_register, buf);
+ }
+ else
+ write_register_gen (return_register, valbuf);
+ }
+}
+
+/* Print the registers in a form similar to the E7000 */
+
+static void
+sh_generic_show_regs (void)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
+ paddr (read_register (PC_REGNUM)),
+ (long) read_register (tdep->SR_REGNUM),
+ (long) read_register (tdep->PR_REGNUM),
+ (long) read_register (MACH_REGNUM),
+ (long) read_register (MACL_REGNUM));
+
+ printf_filtered ("GBR=%08lx VBR=%08lx",
+ (long) read_register (GBR_REGNUM),
+ (long) read_register (VBR_REGNUM));
+
+ printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0),
+ (long) read_register (1),
+ (long) read_register (2),
+ (long) read_register (3),
+ (long) read_register (4),
+ (long) read_register (5),
+ (long) read_register (6),
+ (long) read_register (7));
+ printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (8),
+ (long) read_register (9),
+ (long) read_register (10),
+ (long) read_register (11),
+ (long) read_register (12),
+ (long) read_register (13),
+ (long) read_register (14),
+ (long) read_register (15));
+}
+
+static void
+sh3_show_regs (void)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
+ paddr (read_register (PC_REGNUM)),
+ (long) read_register (tdep->SR_REGNUM),
+ (long) read_register (tdep->PR_REGNUM),
+ (long) read_register (MACH_REGNUM),
+ (long) read_register (MACL_REGNUM));
+
+ printf_filtered ("GBR=%08lx VBR=%08lx",
+ (long) read_register (GBR_REGNUM),
+ (long) read_register (VBR_REGNUM));
+ printf_filtered (" SSR=%08lx SPC=%08lx",
+ (long) read_register (tdep->SSR_REGNUM),
+ (long) read_register (tdep->SPC_REGNUM));
+
+ printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0),
+ (long) read_register (1),
+ (long) read_register (2),
+ (long) read_register (3),
+ (long) read_register (4),
+ (long) read_register (5),
+ (long) read_register (6),
+ (long) read_register (7));
+ printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (8),
+ (long) read_register (9),
+ (long) read_register (10),
+ (long) read_register (11),
+ (long) read_register (12),
+ (long) read_register (13),
+ (long) read_register (14),
+ (long) read_register (15));
+}
+
+
+static void
+sh3e_show_regs (void)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
+ paddr (read_register (PC_REGNUM)),
+ (long) read_register (tdep->SR_REGNUM),
+ (long) read_register (tdep->PR_REGNUM),
+ (long) read_register (MACH_REGNUM),
+ (long) read_register (MACL_REGNUM));
+
+ printf_filtered ("GBR=%08lx VBR=%08lx",
+ (long) read_register (GBR_REGNUM),
+ (long) read_register (VBR_REGNUM));
+ printf_filtered (" SSR=%08lx SPC=%08lx",
+ (long) read_register (tdep->SSR_REGNUM),
+ (long) read_register (tdep->SPC_REGNUM));
+ printf_filtered (" FPUL=%08lx FPSCR=%08lx",
+ (long) read_register (tdep->FPUL_REGNUM),
+ (long) read_register (tdep->FPSCR_REGNUM));
+
+ printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0),
+ (long) read_register (1),
+ (long) read_register (2),
+ (long) read_register (3),
+ (long) read_register (4),
+ (long) read_register (5),
+ (long) read_register (6),
+ (long) read_register (7));
+ printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (8),
+ (long) read_register (9),
+ (long) read_register (10),
+ (long) read_register (11),
+ (long) read_register (12),
+ (long) read_register (13),
+ (long) read_register (14),
+ (long) read_register (15));
+
+ printf_filtered (("FP0-FP7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
+ (long) read_register (FP0_REGNUM + 0),
+ (long) read_register (FP0_REGNUM + 1),
+ (long) read_register (FP0_REGNUM + 2),
+ (long) read_register (FP0_REGNUM + 3),
+ (long) read_register (FP0_REGNUM + 4),
+ (long) read_register (FP0_REGNUM + 5),
+ (long) read_register (FP0_REGNUM + 6),
+ (long) read_register (FP0_REGNUM + 7));
+ printf_filtered (("FP8-FP15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
+ (long) read_register (FP0_REGNUM + 8),
+ (long) read_register (FP0_REGNUM + 9),
+ (long) read_register (FP0_REGNUM + 10),
+ (long) read_register (FP0_REGNUM + 11),
+ (long) read_register (FP0_REGNUM + 12),
+ (long) read_register (FP0_REGNUM + 13),
+ (long) read_register (FP0_REGNUM + 14),
+ (long) read_register (FP0_REGNUM + 15));
+}
+
+static void
+sh3_dsp_show_regs (void)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
+ paddr (read_register (PC_REGNUM)),
+ (long) read_register (tdep->SR_REGNUM),
+ (long) read_register (tdep->PR_REGNUM),
+ (long) read_register (MACH_REGNUM),
+ (long) read_register (MACL_REGNUM));
+
+ printf_filtered ("GBR=%08lx VBR=%08lx",
+ (long) read_register (GBR_REGNUM),
+ (long) read_register (VBR_REGNUM));
+
+ printf_filtered (" SSR=%08lx SPC=%08lx",
+ (long) read_register (tdep->SSR_REGNUM),
+ (long) read_register (tdep->SPC_REGNUM));
+
+ printf_filtered (" DSR=%08lx",
+ (long) read_register (tdep->DSR_REGNUM));
+
+ printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0),
+ (long) read_register (1),
+ (long) read_register (2),
+ (long) read_register (3),
+ (long) read_register (4),
+ (long) read_register (5),
+ (long) read_register (6),
+ (long) read_register (7));
+ printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (8),
+ (long) read_register (9),
+ (long) read_register (10),
+ (long) read_register (11),
+ (long) read_register (12),
+ (long) read_register (13),
+ (long) read_register (14),
+ (long) read_register (15));
+
+ printf_filtered ("A0G=%02lx A0=%08lx M0=%08lx X0=%08lx Y0=%08lx RS=%08lx MOD=%08lx\n",
+ (long) read_register (tdep->A0G_REGNUM) & 0xff,
+ (long) read_register (tdep->A0_REGNUM),
+ (long) read_register (tdep->M0_REGNUM),
+ (long) read_register (tdep->X0_REGNUM),
+ (long) read_register (tdep->Y0_REGNUM),
+ (long) read_register (tdep->RS_REGNUM),
+ (long) read_register (tdep->MOD_REGNUM));
+ printf_filtered ("A1G=%02lx A1=%08lx M1=%08lx X1=%08lx Y1=%08lx RE=%08lx\n",
+ (long) read_register (tdep->A1G_REGNUM) & 0xff,
+ (long) read_register (tdep->A1_REGNUM),
+ (long) read_register (tdep->M1_REGNUM),
+ (long) read_register (tdep->X1_REGNUM),
+ (long) read_register (tdep->Y1_REGNUM),
+ (long) read_register (tdep->RE_REGNUM));
+}
+
+static void
+sh4_show_regs (void)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ int pr = read_register (tdep->FPSCR_REGNUM) & 0x80000;
+ printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
+ paddr (read_register (PC_REGNUM)),
+ (long) read_register (tdep->SR_REGNUM),
+ (long) read_register (tdep->PR_REGNUM),
+ (long) read_register (MACH_REGNUM),
+ (long) read_register (MACL_REGNUM));
+
+ printf_filtered ("GBR=%08lx VBR=%08lx",
+ (long) read_register (GBR_REGNUM),
+ (long) read_register (VBR_REGNUM));
+ printf_filtered (" SSR=%08lx SPC=%08lx",
+ (long) read_register (tdep->SSR_REGNUM),
+ (long) read_register (tdep->SPC_REGNUM));
+ printf_filtered (" FPUL=%08lx FPSCR=%08lx",
+ (long) read_register (tdep->FPUL_REGNUM),
+ (long) read_register (tdep->FPSCR_REGNUM));
+
+ printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0),
+ (long) read_register (1),
+ (long) read_register (2),
+ (long) read_register (3),
+ (long) read_register (4),
+ (long) read_register (5),
+ (long) read_register (6),
+ (long) read_register (7));
+ printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (8),
+ (long) read_register (9),
+ (long) read_register (10),
+ (long) read_register (11),
+ (long) read_register (12),
+ (long) read_register (13),
+ (long) read_register (14),
+ (long) read_register (15));
+
+ printf_filtered ((pr
+ ? "DR0-DR6 %08lx%08lx %08lx%08lx %08lx%08lx %08lx%08lx\n"
+ : "FP0-FP7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
+ (long) read_register (FP0_REGNUM + 0),
+ (long) read_register (FP0_REGNUM + 1),
+ (long) read_register (FP0_REGNUM + 2),
+ (long) read_register (FP0_REGNUM + 3),
+ (long) read_register (FP0_REGNUM + 4),
+ (long) read_register (FP0_REGNUM + 5),
+ (long) read_register (FP0_REGNUM + 6),
+ (long) read_register (FP0_REGNUM + 7));
+ printf_filtered ((pr
+ ? "DR8-DR14 %08lx%08lx %08lx%08lx %08lx%08lx %08lx%08lx\n"
+ : "FP8-FP15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
+ (long) read_register (FP0_REGNUM + 8),
+ (long) read_register (FP0_REGNUM + 9),
+ (long) read_register (FP0_REGNUM + 10),
+ (long) read_register (FP0_REGNUM + 11),
+ (long) read_register (FP0_REGNUM + 12),
+ (long) read_register (FP0_REGNUM + 13),
+ (long) read_register (FP0_REGNUM + 14),
+ (long) read_register (FP0_REGNUM + 15));
+}
+
+static void
+sh_dsp_show_regs (void)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
+ paddr (read_register (PC_REGNUM)),
+ (long) read_register (tdep->SR_REGNUM),
+ (long) read_register (tdep->PR_REGNUM),
+ (long) read_register (MACH_REGNUM),
+ (long) read_register (MACL_REGNUM));
+
+ printf_filtered ("GBR=%08lx VBR=%08lx",
+ (long) read_register (GBR_REGNUM),
+ (long) read_register (VBR_REGNUM));
+
+ printf_filtered (" DSR=%08lx",
+ (long) read_register (tdep->DSR_REGNUM));
+
+ printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0),
+ (long) read_register (1),
+ (long) read_register (2),
+ (long) read_register (3),
+ (long) read_register (4),
+ (long) read_register (5),
+ (long) read_register (6),
+ (long) read_register (7));
+ printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (8),
+ (long) read_register (9),
+ (long) read_register (10),
+ (long) read_register (11),
+ (long) read_register (12),
+ (long) read_register (13),
+ (long) read_register (14),
+ (long) read_register (15));
+
+ printf_filtered ("A0G=%02lx A0=%08lx M0=%08lx X0=%08lx Y0=%08lx RS=%08lx MOD=%08lx\n",
+ (long) read_register (tdep->A0G_REGNUM) & 0xff,
+ (long) read_register (tdep->A0_REGNUM),
+ (long) read_register (tdep->M0_REGNUM),
+ (long) read_register (tdep->X0_REGNUM),
+ (long) read_register (tdep->Y0_REGNUM),
+ (long) read_register (tdep->RS_REGNUM),
+ (long) read_register (tdep->MOD_REGNUM));
+ printf_filtered ("A1G=%02lx A1=%08lx M1=%08lx X1=%08lx Y1=%08lx RE=%08lx\n",
+ (long) read_register (tdep->A1G_REGNUM) & 0xff,
+ (long) read_register (tdep->A1_REGNUM),
+ (long) read_register (tdep->M1_REGNUM),
+ (long) read_register (tdep->X1_REGNUM),
+ (long) read_register (tdep->Y1_REGNUM),
+ (long) read_register (tdep->RE_REGNUM));
+}
+
+static void
+sh64_show_media_regs (void)
+{
+ int i;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ printf_filtered ("PC=%s SR=%016llx \n",
+ paddr (read_register (PC_REGNUM)),
+ (long long) read_register (tdep->SR_REGNUM));
+
+ printf_filtered ("SSR=%016llx SPC=%016llx \n",
+ (long long) read_register (tdep->SSR_REGNUM),
+ (long long) read_register (tdep->SPC_REGNUM));
+ printf_filtered ("FPSCR=%016lx\n ",
+ (long) read_register (tdep->FPSCR_REGNUM));
+
+ for (i = 0; i < 64; i = i + 4)
+ printf_filtered ("\nR%d-R%d %016llx %016llx %016llx %016llx\n",
+ i, i + 3,
+ (long long) read_register (i + 0),
+ (long long) read_register (i + 1),
+ (long long) read_register (i + 2),
+ (long long) read_register (i + 3));
+
+ printf_filtered ("\n");
+
+ for (i = 0; i < 64; i = i + 8)
+ printf_filtered ("FR%d-FR%d %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ i, i + 7,
+ (long) read_register (FP0_REGNUM + i + 0),
+ (long) read_register (FP0_REGNUM + i + 1),
+ (long) read_register (FP0_REGNUM + i + 2),
+ (long) read_register (FP0_REGNUM + i + 3),
+ (long) read_register (FP0_REGNUM + i + 4),
+ (long) read_register (FP0_REGNUM + i + 5),
+ (long) read_register (FP0_REGNUM + i + 6),
+ (long) read_register (FP0_REGNUM + i + 7));
+}
+
+static void
+sh64_show_compact_regs (void)
+{
+ int i;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ printf_filtered ("PC=%s \n",
+ paddr (read_register (tdep->PC_C_REGNUM)));
+
+ printf_filtered ("GBR=%08lx MACH=%08lx MACL=%08lx PR=%08lx T=%08lx\n",
+ (long) read_register (tdep->GBR_C_REGNUM),
+ (long) read_register (tdep->MACH_C_REGNUM),
+ (long) read_register (tdep->MACL_C_REGNUM),
+ (long) read_register (tdep->PR_C_REGNUM),
+ (long) read_register (tdep->T_C_REGNUM));
+ printf_filtered ("FPSCR=%08lx FPUL=%08lx\n",
+ (long) read_register (tdep->FPSCR_REGNUM),
+ (long) read_register (tdep->FPUL_REGNUM));
+
+ for (i = 0; i < 16; i = i + 4)
+ printf_filtered ("\nR%d-R%d %08lx %08lx %08lx %08lx\n",
+ i, i + 3,
+ (long) read_register (i + 0),
+ (long) read_register (i + 1),
+ (long) read_register (i + 2),
+ (long) read_register (i + 3));
+
+ printf_filtered ("\n");
+
+ for (i = 0; i < 16; i = i + 8)
+ printf_filtered ("FR%d-FR%d %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ i, i + 7,
+ (long) read_register (FP0_REGNUM + i + 0),
+ (long) read_register (FP0_REGNUM + i + 1),
+ (long) read_register (FP0_REGNUM + i + 2),
+ (long) read_register (FP0_REGNUM + i + 3),
+ (long) read_register (FP0_REGNUM + i + 4),
+ (long) read_register (FP0_REGNUM + i + 5),
+ (long) read_register (FP0_REGNUM + i + 6),
+ (long) read_register (FP0_REGNUM + i + 7));
+}
+
+/*FIXME!!! This only shows the registers for shmedia, excluding the
+ pseudo registers. */
+static void
+sh64_show_regs (void)
+{
+ if (pc_is_isa32 (selected_frame->pc))
+ sh64_show_media_regs ();
+ else
+ sh64_show_compact_regs ();
+}
+
+void sh_show_regs_command (char *args, int from_tty)
+{
+ if (sh_show_regs)
+ (*sh_show_regs)();
+}
+
+/* Index within `registers' of the first byte of the space for
+ register N. */
+static int
+sh_default_register_byte (int reg_nr)
+{
+ return (reg_nr * 4);
+}
+
+static int
+sh_sh4_register_byte (int reg_nr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->DR_LAST_REGNUM)
+ return (dr_reg_base_num (reg_nr) * 4);
+ else if (reg_nr >= tdep->FV0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ return (fv_reg_base_num (reg_nr) * 4);
+ else
+ return (reg_nr * 4);
+}
+
+/* *INDENT-OFF* */
+/*
+ SH MEDIA MODE (ISA 32)
+ general registers (64-bit) 0-63
+0 r0, r1, r2, r3, r4, r5, r6, r7,
+64 r8, r9, r10, r11, r12, r13, r14, r15,
+128 r16, r17, r18, r19, r20, r21, r22, r23,
+192 r24, r25, r26, r27, r28, r29, r30, r31,
+256 r32, r33, r34, r35, r36, r37, r38, r39,
+320 r40, r41, r42, r43, r44, r45, r46, r47,
+384 r48, r49, r50, r51, r52, r53, r54, r55,
+448 r56, r57, r58, r59, r60, r61, r62, r63,
+
+ pc (64-bit) 64
+512 pc,
+
+ status reg., saved status reg., saved pc reg. (64-bit) 65-67
+520 sr, ssr, spc,
+
+ target registers (64-bit) 68-75
+544 tr0, tr1, tr2, tr3, tr4, tr5, tr6, tr7,
+
+ floating point state control register (32-bit) 76
+608 fpscr,
+
+ single precision floating point registers (32-bit) 77-140
+612 fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
+644 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
+676 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
+708 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31,
+740 fr32, fr33, fr34, fr35, fr36, fr37, fr38, fr39,
+772 fr40, fr41, fr42, fr43, fr44, fr45, fr46, fr47,
+804 fr48, fr49, fr50, fr51, fr52, fr53, fr54, fr55,
+836 fr56, fr57, fr58, fr59, fr60, fr61, fr62, fr63,
+
+TOTAL SPACE FOR REGISTERS: 868 bytes
+
+From here on they are all pseudo registers: no memory allocated.
+REGISTER_BYTE returns the register byte for the base register.
+
+ double precision registers (pseudo) 141-172
+ dr0, dr2, dr4, dr6, dr8, dr10, dr12, dr14,
+ dr16, dr18, dr20, dr22, dr24, dr26, dr28, dr30,
+ dr32, dr34, dr36, dr38, dr40, dr42, dr44, dr46,
+ dr48, dr50, dr52, dr54, dr56, dr58, dr60, dr62,
+
+ floating point pairs (pseudo) 173-204
+ fp0, fp2, fp4, fp6, fp8, fp10, fp12, fp14,
+ fp16, fp18, fp20, fp22, fp24, fp26, fp28, fp30,
+ fp32, fp34, fp36, fp38, fp40, fp42, fp44, fp46,
+ fp48, fp50, fp52, fp54, fp56, fp58, fp60, fp62,
+
+ floating point vectors (4 floating point regs) (pseudo) 205-220
+ fv0, fv4, fv8, fv12, fv16, fv20, fv24, fv28,
+ fv32, fv36, fv40, fv44, fv48, fv52, fv56, fv60,
+
+ SH COMPACT MODE (ISA 16) (all pseudo) 221-272
+ r0_c, r1_c, r2_c, r3_c, r4_c, r5_c, r6_c, r7_c,
+ r8_c, r9_c, r10_c, r11_c, r12_c, r13_c, r14_c, r15_c,
+ pc_c,
+ gbr_c, mach_c, macl_c, pr_c, t_c,
+ fpscr_c, fpul_c,
+ fr0_c, fr1_c, fr2_c, fr3_c, fr4_c, fr5_c, fr6_c, fr7_c,
+ fr8_c, fr9_c, fr10_c, fr11_c, fr12_c, fr13_c, fr14_c, fr15_c
+ dr0_c, dr2_c, dr4_c, dr6_c, dr8_c, dr10_c, dr12_c, dr14_c
+ fv0_c, fv4_c, fv8_c, fv12_c
+*/
+/* *INDENT-ON* */
+static int
+sh_sh64_register_byte (int reg_nr)
+{
+ int base_regnum = -1;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ /* If it is a pseudo register, get the number of the first floating
+ point register that is part of it. */
+ if (reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->DR_LAST_REGNUM)
+ base_regnum = dr_reg_base_num (reg_nr);
+
+ else if (reg_nr >= tdep->FPP0_REGNUM
+ && reg_nr <= tdep->FPP_LAST_REGNUM)
+ base_regnum = fpp_reg_base_num (reg_nr);
+
+ else if (reg_nr >= tdep->FV0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ base_regnum = fv_reg_base_num (reg_nr);
+
+ /* sh compact pseudo register. FPSCR is a pathological case, need to
+ treat it as special. */
+ else if ((reg_nr >= tdep->R0_C_REGNUM
+ && reg_nr <= tdep->FV_LAST_C_REGNUM)
+ && reg_nr != tdep->FPSCR_C_REGNUM)
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+
+ /* Now return the offset in bytes within the register cache. */
+ /* sh media pseudo register, i.e. any of DR, FFP, FV registers. */
+ if (reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ return (base_regnum - FP0_REGNUM + 1) * 4
+ + (tdep->TR7_REGNUM + 1) * 8;
+
+ /* sh compact pseudo register: general register */
+ if ((reg_nr >= tdep->R0_C_REGNUM
+ && reg_nr <= tdep->R_LAST_C_REGNUM))
+ return (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ ? base_regnum * 8 + 4
+ : base_regnum * 8);
+
+ /* sh compact pseudo register: */
+ if (reg_nr == tdep->PC_C_REGNUM
+ || reg_nr == tdep->GBR_C_REGNUM
+ || reg_nr == tdep->MACL_C_REGNUM
+ || reg_nr == tdep->PR_C_REGNUM)
+ return (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ ? base_regnum * 8 + 4
+ : base_regnum * 8);
+
+ if (reg_nr == tdep->MACH_C_REGNUM)
+ return base_regnum * 8;
+
+ if (reg_nr == tdep->T_C_REGNUM)
+ return base_regnum * 8; /* FIXME??? how do we get bit 0? Do we have to? */
+
+ /* sh compact pseudo register: floating point register */
+ else if (reg_nr >=tdep->FP0_C_REGNUM
+ && reg_nr <= tdep->FV_LAST_C_REGNUM)
+ return (base_regnum - FP0_REGNUM) * 4
+ + (tdep->TR7_REGNUM + 1) * 8 + 4;
+
+ else if (reg_nr == tdep->FPSCR_C_REGNUM)
+ /* This is complicated, for now return the beginning of the
+ architectural FPSCR register. */
+ return (tdep->TR7_REGNUM + 1) * 8;
+
+ else if (reg_nr == tdep->FPUL_C_REGNUM)
+ return ((base_regnum - FP0_REGNUM) * 4 +
+ (tdep->TR7_REGNUM + 1) * 8 + 4);
+
+ /* It is not a pseudo register. */
+ /* It is a 64 bit register. */
+ else if (reg_nr <= tdep->TR7_REGNUM)
+ return reg_nr * 8;
+
+ /* It is a 32 bit register. */
+ else
+ if (reg_nr == tdep->FPSCR_REGNUM)
+ return (tdep->FPSCR_REGNUM * 8);
+
+ /* It is floating point 32-bit register */
+ else
+ return ((tdep->TR7_REGNUM + 1) * 8
+ + (reg_nr - FP0_REGNUM + 1) * 4);
+}
+
+/* Number of bytes of storage in the actual machine representation for
+ register REG_NR. */
+static int
+sh_default_register_raw_size (int reg_nr)
+{
+ return 4;
+}
+
+static int
+sh_sh4_register_raw_size (int reg_nr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->DR_LAST_REGNUM)
+ return 8;
+ else if (reg_nr >= tdep->FV0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ return 16;
+ else
+ return 4;
+}
+
+static int
+sh_sh64_register_raw_size (int reg_nr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if ((reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->DR_LAST_REGNUM)
+ || (reg_nr >= tdep->FPP0_REGNUM
+ && reg_nr <= tdep->FPP_LAST_REGNUM)
+ || (reg_nr >= tdep->DR0_C_REGNUM
+ && reg_nr <= tdep->DR_LAST_C_REGNUM)
+ || (reg_nr <= tdep->TR7_REGNUM))
+ return 8;
+
+ else if ((reg_nr >= tdep->FV0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ || (reg_nr >= tdep->FV0_C_REGNUM
+ && reg_nr <= tdep->FV_LAST_C_REGNUM))
+ return 16;
+
+ else /* this covers also the 32-bit SH compact registers. */
+ return 4;
+}
+
+/* Number of bytes of storage in the program's representation
+ for register N. */
+static int
+sh_register_virtual_size (int reg_nr)
+{
+ return 4;
+}
+
+/* ??????? FIXME */
+static int
+sh_sh64_register_virtual_size (int reg_nr)
+{
+ if (reg_nr >= FP0_REGNUM
+ && reg_nr <= gdbarch_tdep (current_gdbarch)->FP_LAST_REGNUM)
+ return 4;
+ else
+ return 8;
+}
+
+/* Return the GDB type object for the "standard" data type
+ of data in register N. */
+static struct type *
+sh_sh3e_register_virtual_type (int reg_nr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if ((reg_nr >= FP0_REGNUM
+ && (reg_nr <= tdep->FP_LAST_REGNUM))
+ || (reg_nr == tdep->FPUL_REGNUM))
+ return builtin_type_float;
+ else
+ return builtin_type_int;
+}
+
+static struct type *
+sh_sh4_build_float_register_type (int high)
+{
+ struct type *temp;
+
+ temp = create_range_type (NULL, builtin_type_int, 0, high);
+ return create_array_type (NULL, builtin_type_float, temp);
+}
+
+static struct type *
+sh_sh4_register_virtual_type (int reg_nr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if ((reg_nr >= FP0_REGNUM
+ && (reg_nr <= tdep->FP_LAST_REGNUM))
+ || (reg_nr == tdep->FPUL_REGNUM))
+ return builtin_type_float;
+ else if (reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->DR_LAST_REGNUM)
+ return builtin_type_double;
+ else if (reg_nr >= tdep->FV0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ return sh_sh4_build_float_register_type (3);
+ else
+ return builtin_type_int;
+}
+
+static struct type *
+sh_sh64_register_virtual_type (int reg_nr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if ((reg_nr >= FP0_REGNUM
+ && reg_nr <= tdep->FP_LAST_REGNUM)
+ || (reg_nr >= tdep->FP0_C_REGNUM
+ && reg_nr <= tdep->FP_LAST_C_REGNUM))
+ return builtin_type_float;
+ else if ((reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->DR_LAST_REGNUM)
+ || (reg_nr >= tdep->DR0_C_REGNUM
+ && reg_nr <= tdep->DR_LAST_C_REGNUM))
+ return builtin_type_double;
+ else if (reg_nr >= tdep->FPP0_REGNUM
+ && reg_nr <= tdep->FPP_LAST_REGNUM)
+ return sh_sh4_build_float_register_type (1);
+ else if ((reg_nr >= tdep->FV0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ ||(reg_nr >= tdep->FV0_C_REGNUM
+ && reg_nr <= tdep->FV_LAST_C_REGNUM))
+ return sh_sh4_build_float_register_type (3);
+ else if (reg_nr == tdep->FPSCR_REGNUM)
+ return builtin_type_int;
+ else if (reg_nr >= tdep->R0_C_REGNUM
+ && reg_nr < tdep->FP0_C_REGNUM)
+ return builtin_type_int;
+ else
+ return builtin_type_long_long;
+}
+
+static struct type *
+sh_default_register_virtual_type (int reg_nr)
+{
+ return builtin_type_int;
+}
+
+/* On the sh4, the DRi pseudo registers are problematic if the target
+ is little endian. When the user writes one of those registers, for
+ instance with 'ser var $dr0=1', we want the double to be stored
+ like this:
+ fr0 = 0x00 0x00 0x00 0x00 0x00 0xf0 0x3f
+ fr1 = 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+
+ This corresponds to little endian byte order & big endian word
+ order. However if we let gdb write the register w/o conversion, it
+ will write fr0 and fr1 this way:
+ fr0 = 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ fr1 = 0x00 0x00 0x00 0x00 0x00 0xf0 0x3f
+ because it will consider fr0 and fr1 as a single LE stretch of memory.
+
+ To achieve what we want we must force gdb to store things in
+ floatformat_ieee_double_littlebyte_bigword (which is defined in
+ include/floatformat.h and libiberty/floatformat.c.
+
+ In case the target is big endian, there is no problem, the
+ raw bytes will look like:
+ fr0 = 0x3f 0xf0 0x00 0x00 0x00 0x00 0x00
+ fr1 = 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+
+ The other pseudo registers (the FVs) also don't pose a problem
+ because they are stored as 4 individual FP elements. */
+
+static void
+sh_sh4_register_convert_to_virtual (int regnum, struct type *type,
+ char *from, char *to)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (regnum >= tdep->DR0_REGNUM
+ && regnum <= tdep->DR_LAST_REGNUM)
+ {
+ DOUBLEST val;
+ floatformat_to_doublest (&floatformat_ieee_double_littlebyte_bigword, from, &val);
+ store_floating (to, TYPE_LENGTH (type), val);
+ }
+ else
+ error ("sh_register_convert_to_virtual called with non DR register number");
+}
+
+void
+sh_sh64_register_convert_to_virtual (int regnum, struct type *type,
+ char *from, char *to)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (TARGET_BYTE_ORDER != BFD_ENDIAN_LITTLE)
+ {
+ /* It is a no-op. */
+ memcpy (to, from, REGISTER_RAW_SIZE (regnum));
+ return;
+ }
+
+ if ((regnum >= tdep->DR0_REGNUM
+ && regnum <= tdep->DR_LAST_REGNUM)
+ || (regnum >= tdep->DR0_C_REGNUM
+ && regnum <= tdep->DR_LAST_C_REGNUM))
+ {
+ DOUBLEST val;
+ floatformat_to_doublest (&floatformat_ieee_double_littlebyte_bigword, from, &val);
+ store_floating(to, TYPE_LENGTH(type), val);
+ }
+ else
+ error("sh_register_convert_to_virtual called with non DR register number");
+}
+
+static void
+sh_sh4_register_convert_to_raw (struct type *type, int regnum,
+ char *from, char *to)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (regnum >= tdep->DR0_REGNUM
+ && regnum <= tdep->DR_LAST_REGNUM)
+ {
+ DOUBLEST val = extract_floating (from, TYPE_LENGTH(type));
+ floatformat_from_doublest (&floatformat_ieee_double_littlebyte_bigword, &val, to);
+ }
+ else
+ error("sh_register_convert_to_raw called with non DR register number");
+}
+
+void
+sh_sh64_register_convert_to_raw (struct type *type, int regnum,
+ char *from, char *to)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (TARGET_BYTE_ORDER != BFD_ENDIAN_LITTLE)
+ {
+ /* It is a no-op. */
+ memcpy (to, from, REGISTER_RAW_SIZE (regnum));
+ return;
+ }
+
+ if ((regnum >= tdep->DR0_REGNUM
+ && regnum <= tdep->DR_LAST_REGNUM)
+ || (regnum >= tdep->DR0_C_REGNUM
+ && regnum <= tdep->DR_LAST_C_REGNUM))
+ {
+ DOUBLEST val = extract_floating (from, TYPE_LENGTH(type));
+ floatformat_from_doublest (&floatformat_ieee_double_littlebyte_bigword, &val, to);
+ }
+ else
+ error("sh_register_convert_to_raw called with non DR register number");
+}
+
+void
+sh_pseudo_register_read (int reg_nr, char *buffer)
+{
+ int base_regnum, portion;
+ char *temp_buffer = (char*) alloca (MAX_REGISTER_RAW_SIZE);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->DR_LAST_REGNUM)
+ {
+ base_regnum = dr_reg_base_num (reg_nr);
+
+ /* Build the value in the provided buffer. */
+ /* Read the real regs for which this one is an alias. */
+ for (portion = 0; portion < 2; portion++)
+ regcache_read (base_regnum + portion,
+ temp_buffer
+ + REGISTER_RAW_SIZE (base_regnum) * portion);
+ /* We must pay attention to the endiannes. */
+ sh_sh4_register_convert_to_virtual (reg_nr,
+ REGISTER_VIRTUAL_TYPE (reg_nr),
+ temp_buffer, buffer);
+ }
+ else if (reg_nr >= tdep->FV0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ {
+ base_regnum = fv_reg_base_num (reg_nr);
+
+ /* Read the real regs for which this one is an alias. */
+ for (portion = 0; portion < 4; portion++)
+ regcache_read (base_regnum + portion,
+ buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+}
+
+static void
+sh4_register_read (struct gdbarch *gdbarch, int reg_nr, char *buffer)
+{
+ if (reg_nr >= 0 && reg_nr < gdbarch_tdep (current_gdbarch)->DR0_REGNUM)
+ /* It is a regular register. */
+ regcache_read (reg_nr, buffer);
+ else
+ /* It is a pseudo register and we need to construct its value */
+ sh_pseudo_register_read (reg_nr, buffer);
+}
+
+static void
+sh64_pseudo_register_read (int reg_nr, char *buffer)
+{
+ int base_regnum;
+ int portion;
+ int offset = 0;
+ char *temp_buffer = (char*) alloca (MAX_REGISTER_RAW_SIZE);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->DR_LAST_REGNUM)
+ {
+ base_regnum = dr_reg_base_num (reg_nr);
+
+ /* Build the value in the provided buffer. */
+ /* DR regs are double precision registers obtained by
+ concatenating 2 single precision floating point registers. */
+ for (portion = 0; portion < 2; portion++)
+ regcache_read (base_regnum + portion,
+ temp_buffer
+ + REGISTER_RAW_SIZE (base_regnum) * portion);
+
+ /* We must pay attention to the endiannes. */
+ sh_sh64_register_convert_to_virtual (reg_nr, REGISTER_VIRTUAL_TYPE (reg_nr),
+ temp_buffer, buffer);
+
+ }
+
+ else if (reg_nr >= tdep->FPP0_REGNUM
+ && reg_nr <= tdep->FPP_LAST_REGNUM)
+ {
+ base_regnum = fpp_reg_base_num (reg_nr);
+
+ /* Build the value in the provided buffer. */
+ /* FPP regs are pairs of single precision registers obtained by
+ concatenating 2 single precision floating point registers. */
+ for (portion = 0; portion < 2; portion++)
+ regcache_read (base_regnum + portion,
+ buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+
+ else if (reg_nr >= tdep->FV0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ {
+ base_regnum = fv_reg_base_num (reg_nr);
+
+ /* Build the value in the provided buffer. */
+ /* FV regs are vectors of single precision registers obtained by
+ concatenating 4 single precision floating point registers. */
+ for (portion = 0; portion < 4; portion++)
+ regcache_read (base_regnum + portion,
+ buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+
+ /* sh compact pseudo registers. 1-to-1 with a shmedia register */
+ else if (reg_nr >= tdep->R0_C_REGNUM
+ && reg_nr <= tdep->T_C_REGNUM)
+ {
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+
+ /* Build the value in the provided buffer. */
+ regcache_read (base_regnum, temp_buffer);
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = 4;
+ memcpy (buffer, temp_buffer + offset, 4); /* get LOWER 32 bits only????*/
+ }
+
+ else if (reg_nr >= tdep->FP0_C_REGNUM
+ && reg_nr <= tdep->FP_LAST_C_REGNUM)
+ {
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+
+ /* Build the value in the provided buffer. */
+ /* Floating point registers map 1-1 to the media fp regs,
+ they have the same size and endienness. */
+ regcache_read (base_regnum, buffer);
+ }
+
+ else if (reg_nr >= tdep->DR0_C_REGNUM
+ && reg_nr <= tdep->DR_LAST_C_REGNUM)
+ {
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+
+ /* DR_C regs are double precision registers obtained by
+ concatenating 2 single precision floating point registers. */
+ for (portion = 0; portion < 2; portion++)
+ regcache_read (base_regnum + portion,
+ temp_buffer
+ + REGISTER_RAW_SIZE (base_regnum) * portion);
+
+ /* We must pay attention to the endiannes. */
+ sh_sh64_register_convert_to_virtual (reg_nr, REGISTER_VIRTUAL_TYPE (reg_nr),
+ temp_buffer, buffer);
+ }
+
+ else if (reg_nr >= tdep->FV0_C_REGNUM
+ && reg_nr <= tdep->FV_LAST_C_REGNUM)
+ {
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+
+ /* Build the value in the provided buffer. */
+ /* FV_C regs are vectors of single precision registers obtained by
+ concatenating 4 single precision floating point registers. */
+ for (portion = 0; portion < 4; portion++)
+ regcache_read (base_regnum + portion,
+ buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+
+ else if (reg_nr == tdep->FPSCR_C_REGNUM)
+ {
+ int fpscr_base_regnum;
+ int sr_base_regnum;
+ unsigned int fpscr_value;
+ unsigned int sr_value;
+ unsigned int fpscr_c_value;
+ unsigned int fpscr_c_part1_value;
+ unsigned int fpscr_c_part2_value;
+
+ fpscr_base_regnum = tdep->FPSCR_REGNUM;
+ sr_base_regnum = tdep->SR_REGNUM;
+
+ /* Build the value in the provided buffer. */
+ /* FPSCR_C is a very weird register that contains sparse bits
+ from the FPSCR and the SR architectural registers.
+ Specifically: */
+ /* *INDENT-OFF* */
+ /*
+ FPSRC_C bit
+ 0 Bit 0 of FPSCR
+ 1 reserved
+ 2-17 Bit 2-18 of FPSCR
+ 18-20 Bits 12,13,14 of SR
+ 21-31 reserved
+ */
+ /* *INDENT-ON* */
+ /* Get FPSCR into a local buffer */
+ regcache_read (fpscr_base_regnum, temp_buffer);
+ /* Get value as an int. */
+ fpscr_value = extract_unsigned_integer (temp_buffer, 4);
+ /* Get SR into a local buffer */
+ regcache_read (sr_base_regnum, temp_buffer);
+ /* Get value as an int. */
+ sr_value = extract_unsigned_integer (temp_buffer, 4);
+ /* Build the new value. */
+ fpscr_c_part1_value = fpscr_value & 0x3fffd;
+ fpscr_c_part2_value = (sr_value & 0x7000) << 6;
+ fpscr_c_value = fpscr_c_part1_value | fpscr_c_part2_value;
+ /* Store that in out buffer!!! */
+ store_unsigned_integer (buffer, 4, fpscr_c_value);
+ /* FIXME There is surely an endianness gotcha here. */
+ }
+
+ else if (reg_nr == tdep->FPUL_C_REGNUM)
+ {
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+
+ /* FPUL_C register is floating point register 32,
+ same size, same endianness. */
+ regcache_read (base_regnum, buffer);
+ }
+}
+
+static void
+sh64_register_read (struct gdbarch *gdbarch, int reg_nr, char *buffer)
+{
+
+ if (reg_nr >= 0 && reg_nr < gdbarch_tdep (current_gdbarch)->DR0_REGNUM)
+ /* It is a regular register. */
+ regcache_read (reg_nr, buffer);
+ else
+ /* It is a pseudo register and we need to construct its value */
+ sh64_pseudo_register_read (reg_nr, buffer);
+}
+
+void
+sh_pseudo_register_write (int reg_nr, char *buffer)
+{
+ int base_regnum, portion;
+ char *temp_buffer = (char*) alloca (MAX_REGISTER_RAW_SIZE);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->DR_LAST_REGNUM)
+ {
+ base_regnum = dr_reg_base_num (reg_nr);
+
+ /* We must pay attention to the endiannes. */
+ sh_sh4_register_convert_to_raw (REGISTER_VIRTUAL_TYPE (reg_nr), reg_nr,
+ buffer, temp_buffer);
+
+ /* Write the real regs for which this one is an alias. */
+ for (portion = 0; portion < 2; portion++)
+ regcache_write (base_regnum + portion,
+ temp_buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+ else if (reg_nr >= tdep->FV0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ {
+ base_regnum = fv_reg_base_num (reg_nr);
+
+ /* Write the real regs for which this one is an alias. */
+ for (portion = 0; portion < 4; portion++)
+ regcache_write (base_regnum + portion,
+ buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+}
+
+static void
+sh4_register_write (struct gdbarch *gdbarch, int reg_nr, char *buffer)
+{
+ if (reg_nr >= 0 && reg_nr < gdbarch_tdep (current_gdbarch)->DR0_REGNUM)
+ /* It is a regular register. */
+ regcache_write (reg_nr, buffer);
+ else
+ /* It is a pseudo register and we need to construct its value */
+ sh_pseudo_register_write (reg_nr, buffer);
+}
+
+void
+sh64_pseudo_register_write (int reg_nr, char *buffer)
+{
+ int base_regnum, portion;
+ int offset;
+ char *temp_buffer = (char*) alloca (MAX_REGISTER_RAW_SIZE);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (reg_nr >= tdep->DR0_REGNUM
+ && reg_nr <= tdep->DR_LAST_REGNUM)
+ {
+ base_regnum = dr_reg_base_num (reg_nr);
+ /* We must pay attention to the endiannes. */
+ sh_sh64_register_convert_to_raw (REGISTER_VIRTUAL_TYPE (reg_nr), reg_nr,
+ buffer, temp_buffer);
+
+
+ /* Write the real regs for which this one is an alias. */
+ for (portion = 0; portion < 2; portion++)
+ regcache_write (base_regnum + portion,
+ temp_buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+
+ else if (reg_nr >= tdep->FPP0_REGNUM
+ && reg_nr <= tdep->FPP_LAST_REGNUM)
+ {
+ base_regnum = fpp_reg_base_num (reg_nr);
+
+ /* Write the real regs for which this one is an alias. */
+ for (portion = 0; portion < 2; portion++)
+ regcache_write (base_regnum + portion,
+ buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+
+ else if (reg_nr >= tdep->FV0_REGNUM
+ && reg_nr <= tdep->FV_LAST_REGNUM)
+ {
+ base_regnum = fv_reg_base_num (reg_nr);
+
+ /* Write the real regs for which this one is an alias. */
+ for (portion = 0; portion < 4; portion++)
+ regcache_write (base_regnum + portion,
+ buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+
+ /* sh compact general pseudo registers. 1-to-1 with a shmedia
+ register but only 4 bytes of it. */
+ else if (reg_nr >= tdep->R0_C_REGNUM
+ && reg_nr <= tdep->T_C_REGNUM)
+ {
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+ /* reg_nr is 32 bit here, and base_regnum is 64 bits. */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = 4;
+ else
+ offset = 0;
+ /* Let's read the value of the base register into a temporary
+ buffer, so that overwriting the last four bytes with the new
+ value of the pseudo will leave the upper 4 bytes unchanged. */
+ regcache_read (base_regnum, temp_buffer);
+ /* Write as an 8 byte quantity */
+ memcpy (temp_buffer + offset, buffer, 4);
+ regcache_write (base_regnum, temp_buffer);
+ }
+
+ /* sh floating point compact pseudo registers. 1-to-1 with a shmedia
+ registers. Both are 4 bytes. */
+ else if (reg_nr >= tdep->FP0_C_REGNUM
+ && reg_nr <= tdep->FP_LAST_C_REGNUM)
+ {
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+ regcache_write (base_regnum, buffer);
+ }
+
+ else if (reg_nr >= tdep->DR0_C_REGNUM
+ && reg_nr <= tdep->DR_LAST_C_REGNUM)
+ {
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+ for (portion = 0; portion < 2; portion++)
+ {
+ /* We must pay attention to the endiannes. */
+ sh_sh64_register_convert_to_raw (REGISTER_VIRTUAL_TYPE (reg_nr), reg_nr,
+ buffer, temp_buffer);
+
+ regcache_write (base_regnum + portion,
+ temp_buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+ }
+
+ else if (reg_nr >= tdep->FV0_C_REGNUM
+ && reg_nr <= tdep->FV_LAST_C_REGNUM)
+ {
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+
+ for (portion = 0; portion < 4; portion++)
+ {
+ regcache_write (base_regnum + portion,
+ buffer + REGISTER_RAW_SIZE (base_regnum) * portion);
+ }
+ }
+
+ else if (reg_nr == tdep->FPSCR_C_REGNUM)
+ {
+ int fpscr_base_regnum;
+ int sr_base_regnum;
+ unsigned int fpscr_value;
+ unsigned int sr_value;
+ unsigned int old_fpscr_value;
+ unsigned int old_sr_value;
+ unsigned int fpscr_c_value;
+ unsigned int fpscr_mask;
+ unsigned int sr_mask;
+
+ fpscr_base_regnum = tdep->FPSCR_REGNUM;
+ sr_base_regnum = tdep->SR_REGNUM;
+
+ /* FPSCR_C is a very weird register that contains sparse bits
+ from the FPSCR and the SR architectural registers.
+ Specifically: */
+ /* *INDENT-OFF* */
+ /*
+ FPSRC_C bit
+ 0 Bit 0 of FPSCR
+ 1 reserved
+ 2-17 Bit 2-18 of FPSCR
+ 18-20 Bits 12,13,14 of SR
+ 21-31 reserved
+ */
+ /* *INDENT-ON* */
+ /* Get value as an int. */
+ fpscr_c_value = extract_unsigned_integer (buffer, 4);
+
+ /* Build the new values. */
+ fpscr_mask = 0x0003fffd;
+ sr_mask = 0x001c0000;
+
+ fpscr_value = fpscr_c_value & fpscr_mask;
+ sr_value = (fpscr_value & sr_mask) >> 6;
+
+ regcache_read (fpscr_base_regnum, temp_buffer);
+ old_fpscr_value = extract_unsigned_integer (temp_buffer, 4);
+ old_fpscr_value &= 0xfffc0002;
+ fpscr_value |= old_fpscr_value;
+ store_unsigned_integer (temp_buffer, 4, fpscr_value);
+ regcache_write (fpscr_base_regnum, temp_buffer);
+
+ regcache_read (sr_base_regnum, temp_buffer);
+ old_sr_value = extract_unsigned_integer (temp_buffer, 4);
+ old_sr_value &= 0xffff8fff;
+ sr_value |= old_sr_value;
+ store_unsigned_integer (temp_buffer, 4, sr_value);
+ regcache_write (sr_base_regnum, temp_buffer);
+ }
+
+ else if (reg_nr == tdep->FPUL_C_REGNUM)
+ {
+ base_regnum = sh64_compact_reg_base_num (reg_nr);
+ regcache_write (base_regnum, buffer);
+ }
+}
+
+static void
+sh64_register_write (struct gdbarch *gdbarch, int reg_nr, char *buffer)
+{
+ if (reg_nr >= 0 && reg_nr < gdbarch_tdep (current_gdbarch)->DR0_REGNUM)
+ /* It is a regular register. */
+ regcache_write (reg_nr, buffer);
+ else
+ /* It is a pseudo register and we need to construct its value */
+ sh64_pseudo_register_write (reg_nr, buffer);
+}
+
+/* Floating point vector of 4 float registers. */
+static void
+do_fv_register_info (int fv_regnum)
+{
+ int first_fp_reg_num = fv_reg_base_num (fv_regnum);
+ printf_filtered ("fv%d\t0x%08x\t0x%08x\t0x%08x\t0x%08x\n",
+ fv_regnum - gdbarch_tdep (current_gdbarch)->FV0_REGNUM,
+ (int) read_register (first_fp_reg_num),
+ (int) read_register (first_fp_reg_num + 1),
+ (int) read_register (first_fp_reg_num + 2),
+ (int) read_register (first_fp_reg_num + 3));
+}
+
+/* Floating point vector of 4 float registers, compact mode. */
+static void
+do_fv_c_register_info (int fv_regnum)
+{
+ int first_fp_reg_num = sh64_compact_reg_base_num (fv_regnum);
+ printf_filtered ("fv%d_c\t0x%08x\t0x%08x\t0x%08x\t0x%08x\n",
+ fv_regnum - gdbarch_tdep (current_gdbarch)->FV0_C_REGNUM,
+ (int) read_register (first_fp_reg_num),
+ (int) read_register (first_fp_reg_num + 1),
+ (int) read_register (first_fp_reg_num + 2),
+ (int) read_register (first_fp_reg_num + 3));
+}
+
+/* Pairs of single regs. The DR are instead double precision
+ registers. */
+static void
+do_fpp_register_info (int fpp_regnum)
+{
+ int first_fp_reg_num = fpp_reg_base_num (fpp_regnum);
+
+ printf_filtered ("fpp%d\t0x%08x\t0x%08x\n",
+ fpp_regnum - gdbarch_tdep (current_gdbarch)->FPP0_REGNUM,
+ (int) read_register (first_fp_reg_num),
+ (int) read_register (first_fp_reg_num + 1));
+}
+
+/* Double precision registers. */
+static void
+do_dr_register_info (int dr_regnum)
+{
+ int first_fp_reg_num = dr_reg_base_num (dr_regnum);
+
+ printf_filtered ("dr%d\t0x%08x%08x\n",
+ dr_regnum - gdbarch_tdep (current_gdbarch)->DR0_REGNUM,
+ (int) read_register (first_fp_reg_num),
+ (int) read_register (first_fp_reg_num + 1));
+}
+
+/* Double precision registers, compact mode. */
+static void
+do_dr_c_register_info (int dr_regnum)
+{
+ int first_fp_reg_num = sh64_compact_reg_base_num (dr_regnum);
+
+ printf_filtered ("dr%d_c\t0x%08x%08x\n",
+ dr_regnum - gdbarch_tdep (current_gdbarch)->DR0_C_REGNUM,
+ (int) read_register (first_fp_reg_num),
+ (int) read_register (first_fp_reg_num +1));
+}
+
+/* General register in compact mode. */
+static void
+do_r_c_register_info (int r_c_regnum)
+{
+ int regnum = sh64_compact_reg_base_num (r_c_regnum);
+
+ printf_filtered ("r%d_c\t0x%08x\n",
+ r_c_regnum - gdbarch_tdep (current_gdbarch)->R0_C_REGNUM,
+ /*FIXME!!!*/ (int) read_register (regnum));
+}
+
+/* FIXME:!! THIS SHOULD TAKE CARE OF GETTING THE RIGHT PORTION OF THE
+ shmedia REGISTERS. */
+/* Control registers, compact mode. */
+static void
+do_cr_c_register_info (int cr_c_regnum)
+{
+ switch (cr_c_regnum)
+ {
+ case 237: printf_filtered ("pc_c\t0x%08x\n", (int) read_register (cr_c_regnum));
+ break;
+ case 238: printf_filtered ("gbr_c\t0x%08x\n", (int) read_register (cr_c_regnum));
+ break;
+ case 239: printf_filtered ("mach_c\t0x%08x\n", (int) read_register (cr_c_regnum));
+ break;
+ case 240: printf_filtered ("macl_c\t0x%08x\n", (int) read_register (cr_c_regnum));
+ break;
+ case 241: printf_filtered ("pr_c\t0x%08x\n", (int) read_register (cr_c_regnum));
+ break;
+ case 242: printf_filtered ("t_c\t0x%08x\n", (int) read_register (cr_c_regnum));
+ break;
+ case 243: printf_filtered ("fpscr_c\t0x%08x\n", (int) read_register (cr_c_regnum));
+ break;
+ case 244: printf_filtered ("fpul_c\t0x%08x\n", (int)read_register (cr_c_regnum));
+ break;
+ }
+}
+
+static void
+sh_do_pseudo_register (int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (regnum < NUM_REGS || regnum >= NUM_REGS + NUM_PSEUDO_REGS)
+ internal_error (__FILE__, __LINE__,
+ "Invalid pseudo register number %d\n", regnum);
+ else if (regnum >= tdep->DR0_REGNUM
+ && regnum < tdep->DR_LAST_REGNUM)
+ do_dr_register_info (regnum);
+ else if (regnum >= tdep->FV0_REGNUM
+ && regnum <= tdep->FV_LAST_REGNUM)
+ do_fv_register_info (regnum);
+}
+
+static void
+sh_do_fp_register (int regnum)
+{ /* do values for FP (float) regs */
+ char *raw_buffer;
+ double flt; /* double extracted from raw hex data */
+ int inv;
+ int j;
+
+ /* Allocate space for the float. */
+ raw_buffer = (char *) alloca (REGISTER_RAW_SIZE (FP0_REGNUM));
+
+ /* Get the data in raw format. */
+ if (!frame_register_read (selected_frame, regnum, raw_buffer))
+ error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum));
+
+ /* Get the register as a number */
+ flt = unpack_double (builtin_type_float, raw_buffer, &inv);
+
+ /* Print the name and some spaces. */
+ fputs_filtered (REGISTER_NAME (regnum), gdb_stdout);
+ print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), gdb_stdout);
+
+ /* Print the value. */
+ if (inv)
+ printf_filtered ("<invalid float>");
+ else
+ printf_filtered ("%-10.9g", flt);
+
+ /* Print the fp register as hex. */
+ printf_filtered ("\t(raw 0x");
+ for (j = 0; j < REGISTER_RAW_SIZE (regnum); j++)
+ {
+ register int idx = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? j
+ : REGISTER_RAW_SIZE (regnum) - 1 - j;
+ printf_filtered ("%02x", (unsigned char) raw_buffer[idx]);
+ }
+ printf_filtered (")");
+ printf_filtered ("\n");
+}
+
+static void
+sh64_do_pseudo_register (int regnum)
+{
+ /* All the sh64-compact mode registers are pseudo registers. */
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (regnum < NUM_REGS
+ || regnum >= NUM_REGS + NUM_PSEUDO_REGS_SH_MEDIA + NUM_PSEUDO_REGS_SH_COMPACT)
+ internal_error (__FILE__, __LINE__,
+ "Invalid pseudo register number %d\n", regnum);
+
+ else if ((regnum >= tdep->DR0_REGNUM
+ && regnum <= tdep->DR_LAST_REGNUM))
+ do_dr_register_info (regnum);
+
+ else if ((regnum >= tdep->DR0_C_REGNUM
+ && regnum <= tdep->DR_LAST_C_REGNUM))
+ do_dr_c_register_info (regnum);
+
+ else if ((regnum >= tdep->FV0_REGNUM
+ && regnum <= tdep->FV_LAST_REGNUM))
+ do_fv_register_info (regnum);
+
+ else if ((regnum >= tdep->FV0_C_REGNUM
+ && regnum <= tdep->FV_LAST_C_REGNUM))
+ do_fv_c_register_info (regnum);
+
+ else if (regnum >= tdep->FPP0_REGNUM
+ && regnum <= tdep->FPP_LAST_REGNUM)
+ do_fpp_register_info (regnum);
+
+ else if (regnum >= tdep->R0_C_REGNUM
+ && regnum <= tdep->R_LAST_C_REGNUM)
+ do_r_c_register_info (regnum); /* FIXME, this function will not print the right format */
+
+ else if (regnum >= tdep->FP0_C_REGNUM
+ && regnum <= tdep->FP_LAST_C_REGNUM)
+ sh_do_fp_register (regnum); /* this should work also for pseudoregs */
+
+ else if (regnum >= tdep->PC_C_REGNUM
+ && regnum <= tdep->FPUL_C_REGNUM)
+ do_cr_c_register_info (regnum);
+
+}
+
+static void
+sh_do_register (int regnum)
+{
+ char raw_buffer[MAX_REGISTER_RAW_SIZE];
+
+ fputs_filtered (REGISTER_NAME (regnum), gdb_stdout);
+ print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), gdb_stdout);
+
+ /* Get the data in raw format. */
+ if (!frame_register_read (selected_frame, regnum, raw_buffer))
+ printf_filtered ("*value not available*\n");
+
+ val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0, 0,
+ gdb_stdout, 'x', 1, 0, Val_pretty_default);
+ printf_filtered ("\t");
+ val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0, 0,
+ gdb_stdout, 0, 1, 0, Val_pretty_default);
+ printf_filtered ("\n");
+}
+
+static void
+sh_print_register (int regnum)
+{
+ if (regnum < 0 || regnum >= NUM_REGS + NUM_PSEUDO_REGS)
+ internal_error (__FILE__, __LINE__,
+ "Invalid register number %d\n", regnum);
+
+ else if (regnum >= 0 && regnum < NUM_REGS)
+ {
+ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT)
+ sh_do_fp_register (regnum); /* FP regs */
+ else
+ sh_do_register (regnum); /* All other regs */
+ }
+
+ else if (regnum < NUM_REGS + NUM_PSEUDO_REGS)
+ do_pseudo_register (regnum);
+}
+
+void
+sh_do_registers_info (int regnum, int fpregs)
+{
+ if (regnum != -1) /* do one specified register */
+ {
+ if (*(REGISTER_NAME (regnum)) == '\0')
+ error ("Not a valid register for the current processor type");
+
+ sh_print_register (regnum);
+ }
+ else
+ /* do all (or most) registers */
+ {
+ regnum = 0;
+ while (regnum < NUM_REGS)
+ {
+ /* If the register name is empty, it is undefined for this
+ processor, so don't display anything. */
+ if (REGISTER_NAME (regnum) == NULL
+ || *(REGISTER_NAME (regnum)) == '\0')
+ {
+ regnum++;
+ continue;
+ }
+
+ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT)
+ {
+ if (fpregs)
+ {
+ /* true for "INFO ALL-REGISTERS" command */
+ sh_do_fp_register (regnum); /* FP regs */
+ regnum ++;
+ }
+ else
+ regnum += (gdbarch_tdep (current_gdbarch)->FP_LAST_REGNUM - FP0_REGNUM); /* skip FP regs */
+ }
+ else
+ {
+ sh_do_register (regnum); /* All other regs */
+ regnum++;
+ }
+ }
+
+ if (fpregs)
+ while (regnum < NUM_REGS + NUM_PSEUDO_REGS)
+ {
+ do_pseudo_register (regnum);
+ regnum++;
+ }
+ }
+}
+
+void
+sh_compact_do_registers_info (int regnum, int fpregs)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ if (regnum != -1) /* do one specified register */
+ {
+ if (*(REGISTER_NAME (regnum)) == '\0')
+ error ("Not a valid register for the current processor type");
+
+ if (regnum >= 0 && regnum < tdep->R0_C_REGNUM)
+ error ("Not a valid register for the current processor mode.");
+
+ sh_print_register (regnum);
+ }
+ else
+ /* do all compact registers */
+ {
+ regnum = tdep->R0_C_REGNUM;
+ while (regnum < NUM_REGS + NUM_PSEUDO_REGS)
+ {
+ do_pseudo_register (regnum);
+ regnum++;
+ }
+ }
+}
+
+void
+sh64_do_registers_info (int regnum, int fpregs)
+{
+ if (pc_is_isa32 (selected_frame->pc))
+ sh_do_registers_info (regnum, fpregs);
+ else
+ sh_compact_do_registers_info (regnum, fpregs);
+}
+
+#ifdef SVR4_SHARED_LIBS
+
+/* Fetch (and possibly build) an appropriate link_map_offsets structure
+ for native i386 linux targets using the struct offsets defined in
+ link.h (but without actual reference to that file).
+
+ This makes it possible to access i386-linux shared libraries from
+ a gdb that was not built on an i386-linux host (for cross debugging).
+ */
+
+struct link_map_offsets *
+sh_linux_svr4_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = 0;
+
+ if (lmp == 0)
+ {
+ lmp = &lmo;
+
+ lmo.r_debug_size = 8; /* 20 not actual size but all we need */
+
+ lmo.r_map_offset = 4;
+ lmo.r_map_size = 4;
+
+ lmo.link_map_size = 20; /* 552 not actual size but all we need */
+
+ lmo.l_addr_offset = 0;
+ lmo.l_addr_size = 4;
+
+ lmo.l_name_offset = 4;
+ lmo.l_name_size = 4;
+
+ lmo.l_next_offset = 12;
+ lmo.l_next_size = 4;
+
+ lmo.l_prev_offset = 16;
+ lmo.l_prev_size = 4;
+ }
+
+ return lmp;
+}
+#endif /* SVR4_SHARED_LIBS */
+
+\f
+/* This table matches the indices assigned to enum sh_osabi. Keep
+ them in sync. */
+static const char * const sh_osabi_names[] =
+{
+ "<unknown>",
+ "GNU/Linux",
+ "NetBSD ELF",
+ NULL
+};
+
+static void
+process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+{
+ enum sh_osabi *os_ident_ptr = obj;
+ const char *name;
+ unsigned int sectsize;
+
+ name = bfd_get_section_name (abfd, sect);
+ sectsize = bfd_section_size (abfd, sect);
+
+ if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0)
+ {
+ unsigned int name_length, data_length, note_type;
+ char *note;
+
+ /* If the section is larger than this, it's probably not what we are
+ looking for. */
+ if (sectsize > 128)
+ sectsize = 128;
+
+ note = alloca (sectsize);
+
+ bfd_get_section_contents (abfd, sect, note,
+ (file_ptr) 0, (bfd_size_type) sectsize);
+
+ name_length = bfd_h_get_32 (abfd, note);
+ data_length = bfd_h_get_32 (abfd, note + 4);
+ note_type = bfd_h_get_32 (abfd, note + 8);
+
+ if (name_length == 4 && data_length == 16 && note_type == NT_GNU_ABI_TAG
+ && strcmp (note + 12, "GNU") == 0)
+ {
+ int os_number = bfd_h_get_32 (abfd, note + 16);
+
+ /* The case numbers are from abi-tags in glibc. */
+ switch (os_number)
+ {
+ case GNU_ABI_TAG_LINUX:
+ *os_ident_ptr = SH_OSABI_LINUX;
+ break;
+
+ case GNU_ABI_TAG_HURD:
+ internal_error
+ (__FILE__, __LINE__,
+ "process_note_abi_sections: Hurd objects not supported");
+ break;
+
+ case GNU_ABI_TAG_SOLARIS:
+ internal_error
+ (__FILE__, __LINE__,
+ "process_note_abi_sections: Solaris objects not supported");
+ break;
+
+ default:
+ internal_error
+ (__FILE__, __LINE__,
+ "process_note_abi_sections: unknown OS number %d",
+ os_number);
+ }
+ }
+ }
+ /* NetBSD uses a similar trick. */
+ else if (strcmp (name, ".note.netbsd.ident") == 0 && sectsize > 0)
+ {
+ unsigned int name_length, desc_length, note_type;
+ char *note;
+
+ /* If the section is larger than this, it's probably not what we are
+ looking for. */
+ if (sectsize > 128)
+ sectsize = 128;
+
+ note = alloca (sectsize);
+
+ bfd_get_section_contents (abfd, sect, note,
+ (file_ptr) 0, (bfd_size_type) sectsize);
+
+ name_length = bfd_h_get_32 (abfd, note);
+ desc_length = bfd_h_get_32 (abfd, note + 4);
+ note_type = bfd_h_get_32 (abfd, note + 8);
+
+ if (name_length == 7 && desc_length == 4 && note_type == NT_NETBSD_IDENT
+ && strcmp (note + 12, "NetBSD") == 0)
+ /* XXX Should we check the version here?
+ Probably not necessary yet. */
+ *os_ident_ptr = SH_OSABI_NETBSD_ELF;
+ }
+}
+
+static int
+get_elfosabi (bfd *abfd)
+{
+ int elfosabi;
+ enum sh_osabi sh_osabi = SH_OSABI_UNKNOWN;
+
+ elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+ switch (elfosabi)
+ {
+ case ELFOSABI_NONE:
+ /* When elfosabi is 0 (ELFOSABI_NONE), this is supposed to indicate
+ that we're on a SYSV system. However, some systems use note sections
+ to record OS/ABI info, but leave e_ident[EI_OSABI] zero. So we
+ have to check the note sections too. */
+ bfd_map_over_sections (abfd,
+ process_note_abi_tag_sections,
+ &sh_osabi);
+ break;
+
+ case ELFOSABI_NETBSD:
+ sh_osabi = SH_OSABI_NETBSD_ELF;
+ break;
+
+ case ELFOSABI_LINUX:
+ sh_osabi = SH_OSABI_LINUX;
+ break;
+ }
+
+ return (sh_osabi);
+}
+
+struct sh_osabi_handler
+{
+ struct sh_osabi_handler *next;
+ enum sh_osabi abi;
+ void (*init_osabi)(struct gdbarch_info, struct gdbarch *);
+};
+
+struct sh_osabi_handler *sh_osabi_handler_list = NULL;
+
+void
+sh_gdbarch_register_os_abi (enum sh_osabi abi,
+ void (*init_osabi)(struct gdbarch_info,
+ struct gdbarch *))
+{
+ struct sh_osabi_handler **handler_p;
+
+ for (handler_p = &sh_osabi_handler_list; *handler_p != NULL;
+ handler_p = &(*handler_p)->next)
+ {
+ if ((*handler_p)->abi == abi)
+ {
+ internal_error
+ (__FILE__, __LINE__,
+ "sh_gdbarch_register_os_abi: A handler for this ABI variant "
+ "(%d) has already been registered", (int) abi);
+ /* If user wants to continue, override previous definition. */
+ (*handler_p)->init_osabi = init_osabi;
+ return;
+ }
+ }
+
+ (*handler_p)
+ = (struct sh_osabi_handler *) xmalloc (sizeof (struct sh_osabi_handler));
+ (*handler_p)->next = NULL;
+ (*handler_p)->abi = abi;
+ (*handler_p)->init_osabi = init_osabi;
+}
+
+static gdbarch_init_ftype sh_gdbarch_init;
+
+static struct gdbarch *
+sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ static LONGEST sh_call_dummy_words[] = {0};
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+ gdbarch_register_name_ftype *sh_register_name;
+ gdbarch_store_return_value_ftype *sh_store_return_value;
+ gdbarch_register_virtual_type_ftype *sh_register_virtual_type;
+ enum sh_osabi sh_osabi = SH_OSABI_UNKNOWN;
+ struct sh_osabi_handler *osabi_handler;
+
+ /* Try to determine the ABI of the object we are loading. */
+
+ if (info.abfd != NULL)
+ {
+ switch (bfd_get_flavour (info.abfd))
+ {
+ case bfd_target_elf_flavour:
+ sh_osabi = get_elfosabi (info.abfd);
+ break;
+
+ default:
+ /* Just leave it as "unkown". */
+ break;
+ }
+ }
+
+ /* Find a candidate among the list of pre-declared architectures. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* Make sure the ABI selection matches. */
+ tdep = gdbarch_tdep (arches->gdbarch);
+ if (tdep && tdep->sh_osabi == sh_osabi)
+ return arches->gdbarch;
+ }
+
+ /* None found, create a new architecture from the information
+ provided. */
+ tdep = XMALLOC (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ tdep->sh_osabi = sh_osabi;
+ if (sh_osabi < SH_OSABI_INVALID)
+ tdep->osabi_name = sh_osabi_names[sh_osabi];
+ else
+ {
+ internal_error (__FILE__, __LINE__, "Invalid setting of sh_osabi %d",
+ (int) sh_osabi);
+ tdep->osabi_name = "<invalid>";
+ }
+
+ /* Initialize the register numbers that are not common to all the
+ variants to -1, if necessary thse will be overwritten in the case
+ statement below. */
+ tdep->FPUL_REGNUM = -1;
+ tdep->FPSCR_REGNUM = -1;
+ tdep->PR_REGNUM = 17;
+ tdep->SR_REGNUM = 22;
+ tdep->DSR_REGNUM = -1;
+ tdep->FP_LAST_REGNUM = -1;
+ tdep->A0G_REGNUM = -1;
+ tdep->A0_REGNUM = -1;
+ tdep->A1G_REGNUM = -1;
+ tdep->A1_REGNUM = -1;
+ tdep->M0_REGNUM = -1;
+ tdep->M1_REGNUM = -1;
+ tdep->X0_REGNUM = -1;
+ tdep->X1_REGNUM = -1;
+ tdep->Y0_REGNUM = -1;
+ tdep->Y1_REGNUM = -1;
+ tdep->MOD_REGNUM = -1;
+ tdep->RS_REGNUM = -1;
+ tdep->RE_REGNUM = -1;
+ tdep->SSR_REGNUM = -1;
+ tdep->SPC_REGNUM = -1;
+ tdep->DR0_REGNUM = -1;
+ tdep->DR_LAST_REGNUM = -1;
+ tdep->FV0_REGNUM = -1;
+ tdep->FV_LAST_REGNUM = -1;
+ tdep->ARG0_REGNUM = 4;
+ tdep->ARGLAST_REGNUM = 7;
+ tdep->RETURN_REGNUM = 0;
+ tdep->FLOAT_ARGLAST_REGNUM = -1;
+
+ tdep->sh_abi = SH_ABI_UNKNOWN;
+
+ set_gdbarch_fp0_regnum (gdbarch, -1);
+ set_gdbarch_num_pseudo_regs (gdbarch, 0);
+ set_gdbarch_max_register_raw_size (gdbarch, 4);
+ set_gdbarch_max_register_virtual_size (gdbarch, 4);
+ set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_num_regs (gdbarch, SH_DEFAULT_NUM_REGS);
+ set_gdbarch_sp_regnum (gdbarch, 15);
+ set_gdbarch_fp_regnum (gdbarch, 14);
+ set_gdbarch_pc_regnum (gdbarch, 16);
+ set_gdbarch_register_size (gdbarch, 4);
+ set_gdbarch_register_bytes (gdbarch, SH_DEFAULT_NUM_REGS * 4);
+ set_gdbarch_do_registers_info (gdbarch, sh_do_registers_info);
+ set_gdbarch_breakpoint_from_pc (gdbarch, sh_breakpoint_from_pc);
+ set_gdbarch_frame_chain (gdbarch, sh_frame_chain);
+ set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
+ set_gdbarch_init_extra_frame_info (gdbarch, sh_init_extra_frame_info);
+ set_gdbarch_extract_return_value (gdbarch, sh_extract_return_value);
+ set_gdbarch_push_arguments (gdbarch, sh_push_arguments);
+ set_gdbarch_store_struct_return (gdbarch, sh_store_struct_return);
+ set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention);
+ set_gdbarch_extract_struct_value_address (gdbarch, sh_extract_struct_value_address);
+ set_gdbarch_pop_frame (gdbarch, sh_pop_frame);
+ set_gdbarch_print_insn (gdbarch, gdb_print_insn_sh);
+ skip_prologue_hard_way = sh_skip_prologue_hard_way;
+ do_pseudo_register = sh_do_pseudo_register;
+
+ switch (info.bfd_arch_info->mach)
+ {
+ case bfd_mach_sh:
+ sh_register_name = sh_sh_register_name;
+ sh_show_regs = sh_generic_show_regs;
+ sh_store_return_value = sh_default_store_return_value;
+ sh_register_virtual_type = sh_default_register_virtual_type;
+ set_gdbarch_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs);
+ set_gdbarch_register_raw_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_virtual_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_byte (gdbarch, sh_default_register_byte);
+ break;
+ case bfd_mach_sh2:
+ sh_register_name = sh_sh_register_name;
+ sh_show_regs = sh_generic_show_regs;
+ sh_store_return_value = sh_default_store_return_value;
+ sh_register_virtual_type = sh_default_register_virtual_type;
+ set_gdbarch_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs);
+ set_gdbarch_register_raw_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_virtual_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_byte (gdbarch, sh_default_register_byte);
+ break;
+ case bfd_mach_sh_dsp:
+ sh_register_name = sh_sh_dsp_register_name;
+ sh_show_regs = sh_dsp_show_regs;
+ sh_store_return_value = sh_default_store_return_value;
+ sh_register_virtual_type = sh_default_register_virtual_type;
+ set_gdbarch_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs);
+ set_gdbarch_register_raw_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_virtual_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_byte (gdbarch, sh_default_register_byte);
+ tdep->DSR_REGNUM = 24;
+ tdep->A0G_REGNUM = 25;
+ tdep->A0_REGNUM = 26;
+ tdep->A1G_REGNUM = 27;
+ tdep->A1_REGNUM = 28;
+ tdep->M0_REGNUM = 29;
+ tdep->M1_REGNUM = 30;
+ tdep->X0_REGNUM = 31;
+ tdep->X1_REGNUM = 32;
+ tdep->Y0_REGNUM = 33;
+ tdep->Y1_REGNUM = 34;
+ tdep->MOD_REGNUM = 40;
+ tdep->RS_REGNUM = 43;
+ tdep->RE_REGNUM = 44;
+ break;
+ case bfd_mach_sh3:
+ sh_register_name = sh_sh3_register_name;
+ sh_show_regs = sh3_show_regs;
+ sh_store_return_value = sh_default_store_return_value;
+ sh_register_virtual_type = sh_default_register_virtual_type;
+ set_gdbarch_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs);
+ set_gdbarch_register_raw_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_virtual_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_byte (gdbarch, sh_default_register_byte);
+ tdep->SSR_REGNUM = 41;
+ tdep->SPC_REGNUM = 42;
+ break;
+ case bfd_mach_sh3e:
+ sh_register_name = sh_sh3e_register_name;
+ sh_show_regs = sh3e_show_regs;
+ sh_store_return_value = sh3e_sh4_store_return_value;
+ sh_register_virtual_type = sh_sh3e_register_virtual_type;
+ set_gdbarch_frame_init_saved_regs (gdbarch, sh_fp_frame_init_saved_regs);
+ set_gdbarch_register_raw_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_virtual_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_byte (gdbarch, sh_default_register_byte);
+ set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
+ set_gdbarch_fp0_regnum (gdbarch, 25);
+ tdep->FPUL_REGNUM = 23;
+ tdep->FPSCR_REGNUM = 24;
+ tdep->FP_LAST_REGNUM = 40;
+ tdep->SSR_REGNUM = 41;
+ tdep->SPC_REGNUM = 42;
+ break;
+ case bfd_mach_sh3_dsp:
+ sh_register_name = sh_sh3_dsp_register_name;
+ sh_show_regs = sh3_dsp_show_regs;
+ sh_store_return_value = sh_default_store_return_value;
+ sh_register_virtual_type = sh_default_register_virtual_type;
+ set_gdbarch_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs);
+ set_gdbarch_register_raw_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_virtual_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_byte (gdbarch, sh_default_register_byte);
+ tdep->DSR_REGNUM = 24;
+ tdep->A0G_REGNUM = 25;
+ tdep->A0_REGNUM = 26;
+ tdep->A1G_REGNUM = 27;
+ tdep->A1_REGNUM = 28;
+ tdep->M0_REGNUM = 29;
+ tdep->M1_REGNUM = 30;
+ tdep->X0_REGNUM = 31;
+ tdep->X1_REGNUM = 32;
+ tdep->Y0_REGNUM = 33;
+ tdep->Y1_REGNUM = 34;
+ tdep->MOD_REGNUM = 40;
+ tdep->RS_REGNUM = 43;
+ tdep->RE_REGNUM = 44;
+ tdep->SSR_REGNUM = 41;
+ tdep->SPC_REGNUM = 42;
+ break;
+ case bfd_mach_sh4:
+ sh_register_name = sh_sh4_register_name;
+ sh_show_regs = sh4_show_regs;
+ sh_store_return_value = sh3e_sh4_store_return_value;
+ sh_register_virtual_type = sh_sh4_register_virtual_type;
+ set_gdbarch_frame_init_saved_regs (gdbarch, sh_fp_frame_init_saved_regs);
+ set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
+ set_gdbarch_fp0_regnum (gdbarch, 25);
+ set_gdbarch_register_raw_size (gdbarch, sh_sh4_register_raw_size);
+ set_gdbarch_register_virtual_size (gdbarch, sh_sh4_register_raw_size);
+ set_gdbarch_register_byte (gdbarch, sh_sh4_register_byte);
+ set_gdbarch_num_pseudo_regs (gdbarch, 12);
+ set_gdbarch_max_register_raw_size (gdbarch, 4 * 4);
+ set_gdbarch_max_register_virtual_size (gdbarch, 4 * 4);
+ set_gdbarch_register_read (gdbarch, sh4_register_read);
+ set_gdbarch_register_write (gdbarch, sh4_register_write);
+ tdep->FPUL_REGNUM = 23;
+ tdep->FPSCR_REGNUM = 24;
+ tdep->FP_LAST_REGNUM = 40;
+ tdep->SSR_REGNUM = 41;
+ tdep->SPC_REGNUM = 42;
+ tdep->DR0_REGNUM = 59;
+ tdep->DR_LAST_REGNUM = 66;
+ tdep->FV0_REGNUM = 67;
+ tdep->FV_LAST_REGNUM = 70;
+ break;
+ case bfd_mach_sh5:
+ tdep->PR_REGNUM = 18;
+ tdep->SR_REGNUM = 65;
+ tdep->FPSCR_REGNUM = SIM_SH64_FPCSR_REGNUM;
+ tdep->FP_LAST_REGNUM = SIM_SH64_FR0_REGNUM + SIM_SH64_NR_FP_REGS - 1;
+ tdep->SSR_REGNUM = SIM_SH64_SSR_REGNUM;
+ tdep->SPC_REGNUM = SIM_SH64_SPC_REGNUM;
+ tdep->TR7_REGNUM = SIM_SH64_TR0_REGNUM + 7;
+ tdep->FPP0_REGNUM = 173;
+ tdep->FPP_LAST_REGNUM = 204;
+ tdep->DR0_REGNUM = 141;
+ tdep->DR_LAST_REGNUM = 172;
+ tdep->FV0_REGNUM = 205;
+ tdep->FV_LAST_REGNUM = 220;
+ tdep->R0_C_REGNUM = 221;
+ tdep->R_LAST_C_REGNUM = 236;
+ tdep->PC_C_REGNUM = 237;
+ tdep->GBR_C_REGNUM = 238;
+ tdep->MACH_C_REGNUM = 239;
+ tdep->MACL_C_REGNUM = 240;
+ tdep->PR_C_REGNUM = 241;
+ tdep->T_C_REGNUM = 242;
+ tdep->FPSCR_C_REGNUM = 243;
+ tdep->FPUL_C_REGNUM = 244;
+ tdep->FP0_C_REGNUM = 245;
+ tdep->FP_LAST_C_REGNUM = 260;
+ tdep->DR0_C_REGNUM = 261;
+ tdep->DR_LAST_C_REGNUM = 268;
+ tdep->FV0_C_REGNUM = 269;
+ tdep->FV_LAST_C_REGNUM = 272;
+ tdep->ARG0_REGNUM = 2;
+ tdep->ARGLAST_REGNUM = 9;
+ tdep->RETURN_REGNUM = 2;
+ tdep->FLOAT_ARGLAST_REGNUM = 11;
+
+ set_gdbarch_num_pseudo_regs (gdbarch, NUM_PSEUDO_REGS_SH_MEDIA + NUM_PSEUDO_REGS_SH_COMPACT);
+ set_gdbarch_fp0_regnum (gdbarch, SIM_SH64_FR0_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, 64);
+
+ /* Determine the ABI */
+ if (bfd_get_arch_size (info.abfd) == 64)
+ {
+ /* If the ABI is the 64-bit one, it can only be sh-media. */
+ tdep->sh_abi = SH_ABI_64;
+ set_gdbarch_ptr_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ }
+ else
+ {
+ /* If the ABI is the 32-bit one it could be either media or
+ compact. */
+ tdep->sh_abi = SH_ABI_32;
+ set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ }
+
+ /* the number of real registers is the same whether we are in
+ ISA16(compact) or ISA32(media). */
+ set_gdbarch_num_regs (gdbarch, SIM_SH64_NR_REGS);
+ set_gdbarch_register_size (gdbarch, 8); /*????*/
+ set_gdbarch_register_bytes (gdbarch,
+ ((SIM_SH64_NR_FP_REGS + 1) * 4)
+ + (SIM_SH64_NR_REGS - SIM_SH64_NR_FP_REGS -1) * 8);
+
+ sh_register_name = sh_sh64_register_name;
+ sh_show_regs = sh64_show_regs;
+ sh_register_virtual_type = sh_sh64_register_virtual_type;
+ sh_store_return_value = sh64_store_return_value;
+ skip_prologue_hard_way = sh64_skip_prologue_hard_way;
+ do_pseudo_register = sh64_do_pseudo_register;
+ set_gdbarch_register_raw_size (gdbarch, sh_sh64_register_raw_size);
+ set_gdbarch_register_virtual_size (gdbarch, sh_sh64_register_raw_size);
+ set_gdbarch_register_byte (gdbarch, sh_sh64_register_byte);
+ /* This seems awfully wrong!*/
+ /*set_gdbarch_max_register_raw_size (gdbarch, 8);*/
+ /* should include the size of the pseudo regs. */
+ set_gdbarch_max_register_raw_size (gdbarch, 4 * 4);
+ /* Or should that go in the virtual_size? */
+ /*set_gdbarch_max_register_virtual_size (gdbarch, 8);*/
+ set_gdbarch_max_register_virtual_size (gdbarch, 4 * 4);
+ set_gdbarch_register_read (gdbarch, sh64_register_read);
+ set_gdbarch_register_write (gdbarch, sh64_register_write);
+
+ set_gdbarch_do_registers_info (gdbarch, sh64_do_registers_info);
+ set_gdbarch_frame_init_saved_regs (gdbarch, sh64_nofp_frame_init_saved_regs);
+ set_gdbarch_breakpoint_from_pc (gdbarch, sh_sh64_breakpoint_from_pc);
+ set_gdbarch_init_extra_frame_info (gdbarch, sh64_init_extra_frame_info);
+ set_gdbarch_frame_chain (gdbarch, sh64_frame_chain);
+ set_gdbarch_get_saved_register (gdbarch, sh64_get_saved_register);
+ set_gdbarch_extract_return_value (gdbarch, sh64_extract_return_value);
+ set_gdbarch_push_arguments (gdbarch, sh64_push_arguments);
+ /*set_gdbarch_store_struct_return (gdbarch, sh64_store_struct_return);*/
+ set_gdbarch_extract_struct_value_address (gdbarch, sh64_extract_struct_value_address);
+ set_gdbarch_use_struct_convention (gdbarch, sh64_use_struct_convention);
+ set_gdbarch_pop_frame (gdbarch, sh64_pop_frame);
+ set_gdbarch_elf_make_msymbol_special (gdbarch,
+ sh64_elf_make_msymbol_special);
+ break;
+ default:
+ sh_register_name = sh_generic_register_name;
+ sh_show_regs = sh_generic_show_regs;
+ sh_store_return_value = sh_default_store_return_value;
+ sh_register_virtual_type = sh_default_register_virtual_type;
+ set_gdbarch_frame_init_saved_regs (gdbarch, sh_nofp_frame_init_saved_regs);
+ set_gdbarch_register_raw_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_virtual_size (gdbarch, sh_default_register_raw_size);
+ set_gdbarch_register_byte (gdbarch, sh_default_register_byte);
+ break;
+ }
+
+ set_gdbarch_read_pc (gdbarch, generic_target_read_pc);
+ set_gdbarch_write_pc (gdbarch, generic_target_write_pc);
+ set_gdbarch_read_fp (gdbarch, generic_target_read_fp);
+ set_gdbarch_read_sp (gdbarch, generic_target_read_sp);
+ set_gdbarch_write_sp (gdbarch, generic_target_write_sp);
+
+ set_gdbarch_register_name (gdbarch, sh_register_name);
+ set_gdbarch_register_virtual_type (gdbarch, sh_register_virtual_type);
+
+ set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);/*??should be 8?*/
+
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
+ set_gdbarch_call_dummy_length (gdbarch, 0);
+ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+ set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1); /*???*/
+ set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
+ set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+ set_gdbarch_pc_in_call_dummy (gdbarch, generic_pc_in_call_dummy);
+ set_gdbarch_call_dummy_words (gdbarch, sh_call_dummy_words);
+ set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (sh_call_dummy_words));
+ set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+ set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
+ set_gdbarch_coerce_float_to_double (gdbarch,
+ sh_coerce_float_to_double);
+
+ set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+ set_gdbarch_push_return_address (gdbarch, sh_push_return_address);
+
+ set_gdbarch_store_return_value (gdbarch, sh_store_return_value);
+ set_gdbarch_skip_prologue (gdbarch, sh_skip_prologue);
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+ set_gdbarch_function_start_offset (gdbarch, 0);
+
+ set_gdbarch_frame_args_skip (gdbarch, 0);
+ set_gdbarch_frameless_function_invocation (gdbarch, frameless_look_for_prologue);
+ set_gdbarch_frame_chain_valid (gdbarch, generic_file_frame_chain_valid);
+ set_gdbarch_frame_saved_pc (gdbarch, sh_frame_saved_pc);
+ set_gdbarch_frame_args_address (gdbarch, default_frame_address);
+ set_gdbarch_frame_locals_address (gdbarch, default_frame_address);
+ set_gdbarch_saved_pc_after_call (gdbarch, sh_saved_pc_after_call);
+ set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+ set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+
+ /* Hook in ABI-specific overrides, if they have been registered. If
+ the ABI is unknown, this is probably an embedded target, so we
+ should not warn about this situation. */
+ if (sh_osabi != SH_OSABI_UNKNOWN)
+ {
+ for (osabi_handler = sh_osabi_handler_list; osabi_handler != NULL;
+ osabi_handler = osabi_handler->next)
+ if (osabi_handler->abi == sh_osabi)
+ break;
+
+ if (osabi_handler)
+ osabi_handler->init_osabi (info, gdbarch);
+ else
+ {
+ /* We assume that if GDB_MULTI_ARCH is less than
+ GDB_MULTI_ARCH_TM that an ABI variant can be supported by
+ overriding definitions in this file. */
+ if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
+ fprintf_filtered
+ (gdb_stderr,
+ "A handler for the ABI variant \"%s\" is not built into this "
+ "configuration of GDB. "
+ "Attempting to continue with the default SuperH settings",
+ sh_osabi_names[sh_osabi]);
+ }
+ }
+
+ return gdbarch;
+}
+
+static void
+sh_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (tdep == NULL)
+ return;
+
+ if (tdep->osabi_name != NULL)
+ fprintf_unfiltered (file, "sh_dump_tdep: OS ABI = %s\n", tdep->osabi_name);
+ else
+ internal_error (__FILE__, __LINE__,
+ "sh_dump_tdep: illegal setting of tdep->sh_osabi (%d)",
+ (int) tdep->sh_osabi);
+}
+
+void
+_initialize_sh_tdep (void)
+{
+ struct cmd_list_element *c;
+
+ gdbarch_register (bfd_arch_sh, sh_gdbarch_init, sh_dump_tdep);