Re: [rfc] mn10300: Add am33 support

Michael Snyder
2005-09-07T03:39:40Z

Kevin Buettner wrote:
> The following patch adds am33 support to mn10300-tdep.c.
>
> This code has various authors. I believe that Andrew Cagney, Jackie
> Smith Cashion, Alex Oliva, and myself all had a hand in writing bits
> of it. All of the above authors are (or were at the time the code was
> written) covered by Red Hat's copyright assignment.
>
> Comments?

Looks great! Thanks for pulling this together.
Michael

> * mn10300-tdep.c (am33_2_register_name): New function.
> (my_frame_is_in_sp, my_frame_is_in_fp, my_frame_is_last)
> (set_my_stack_size): Delete.
> (set_movm_offsets, set_reg_offsets): Rename the former to the
> latter. Update for handling am33.
> (mn10300_analyze_prologue): Update for handling am33. Also, make
> minor improvements in quality of prologue analysis.
> (mn10300_gdbarch_init): Add am33 support.
> * mn10300-tdep.h (E_NUM_REGS): Delete.
>
> Index: mn10300-tdep.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/mn10300-tdep.c,v
> retrieving revision 1.129
> diff -u -p -r1.129 mn10300-tdep.c
> --- mn10300-tdep.c 3 Sep 2005 01:12:21 -0000 1.129
> +++ mn10300-tdep.c 3 Sep 2005 01:20:45 -0000
> @@ -245,6 +245,22 @@ am33_register_name (int reg)
> return register_name (reg, regs, sizeof regs);
> }
>
> +static const char *
> +am33_2_register_name (int reg)
> +{
> + static char *regs[] =
> + {
> + "d0", "d1", "d2", "d3", "a0", "a1", "a2", "a3",
> + "sp", "pc", "mdr", "psw", "lir", "lar", "mdrq", "r0",
> + "r1", "r2", "r3", "r4", "r5", "r6", "r7", "ssp",
> + "msp", "usp", "mcrh", "mcrl", "mcvf", "fpcr", "", "",
> + "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
> + "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15",
> + "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23",
> + "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31"
> + };
> + return register_name (reg, regs, sizeof regs);
> +}
>
> static struct type *
> mn10300_register_type (struct gdbarch *gdbarch, int reg)
> @@ -279,54 +295,16 @@ mn10300_breakpoint_from_pc (CORE_ADDR *b
> return breakpoint;
> }
>
> -/*
> - * Frame Extra Info:
> - *
> - * status -- actually frame type (SP, FP, or last frame)
> - * stack size -- offset to the next frame
> - *
> - * The former might ultimately be stored in the frame_base.
> - * Seems like there'd be a way to store the later too.
> - *
> - * Temporarily supply empty stub functions as place holders.
> - */
> -
> -static void
> -my_frame_is_in_sp (struct frame_info *fi, void **this_cache)
> -{
> - struct trad_frame_cache *cache = mn10300_frame_unwind_cache (fi, this_cache);
> - trad_frame_set_this_base (cache,
> - frame_unwind_register_unsigned (fi,
> - E_SP_REGNUM));
> -}
> -
> -static void
> -my_frame_is_in_fp (struct frame_info *fi, void **this_cache)
> -{
> - struct trad_frame_cache *cache = mn10300_frame_unwind_cache (fi, this_cache);
> - trad_frame_set_this_base (cache,
> - frame_unwind_register_unsigned (fi,
> - E_A3_REGNUM));
> -}
> -
> -static void
> -my_frame_is_last (struct frame_info *fi)
> -{
> -}
> -
> -static void
> -set_my_stack_size (struct frame_info *fi, CORE_ADDR size)
> -{
> -}
> -
> -
> -/* Set offsets of registers saved by movm instruction.
> +/* Set offsets of saved registers.
> This is a helper function for mn10300_analyze_prologue. */
>
> static void
> -set_movm_offsets (struct frame_info *fi,
> +set_reg_offsets (struct frame_info *fi,
> void **this_cache,
> - int movm_args)
> + int movm_args,
> + int fpregmask,
> + int stack_extra_size,
> + int frame_in_fp)
> {
> struct trad_frame_cache *cache;
> int offset = 0;
> @@ -339,7 +317,38 @@ set_movm_offsets (struct frame_info *fi,
> if (cache == NULL)
> return;
>
> - base = trad_frame_get_this_base (cache);
> + if (frame_in_fp)
> + {
> + base = frame_unwind_register_unsigned (fi, E_A3_REGNUM);
> + }
> + else
> + {
> + base = frame_unwind_register_unsigned (fi, E_SP_REGNUM) + stack_extra_size;
> + }
> +
> + trad_frame_set_this_base (cache, base);
> +
> + if (AM33_MODE == 2)
> + {
> + /* If bit N is set in fpregmask, fsN is saved on the stack.
> + The floating point registers are saved in ascending order.
> + For example: fs16 <- Frame Pointer
> + fs17 Frame Pointer + 4 */
> + if (fpregmask != 0)
> + {
> + int i;
> + for (i = 0; i < 32; i++)
> + {
> + if (fpregmask & (1 << i))
> + {
> + trad_frame_set_reg_addr (cache, E_FS0_REGNUM + i, base + offset);
> + offset += 4;
> + }
> + }
> + }
> + }
> +
> +
> if (movm_args & movm_other_bit)
> {
> /* The `other' bit leaves a blank area of four bytes at the
> @@ -510,11 +519,14 @@ mn10300_analyze_prologue (struct frame_i
> CORE_ADDR pc)
> {
> CORE_ADDR func_addr, func_end, addr, stop;
> - long stack_size;
> + long stack_extra_size = 0;
> int imm_size;
> unsigned char buf[4];
> - int status, movm_args = 0;
> + int status;
> + int movm_args = 0;
> + int fpregmask = 0;
> char *name;
> + int frame_in_fp = 0;
>
> /* Use the PC in the frame if it's provided to look up the
> start of this function.
> @@ -526,8 +538,6 @@ mn10300_analyze_prologue (struct frame_i
> if (fi)
> {
> pc = (pc ? pc : get_frame_pc (fi));
> - /* At the start of a function our frame is in the stack pointer. */
> - my_frame_is_in_sp (fi, this_cache);
> }
>
> /* Find the start of this function. */
> @@ -540,15 +550,15 @@ mn10300_analyze_prologue (struct frame_i
> and I don't want to do that anyway. */
> if (status == 0)
> {
> - return pc;
> + addr = pc;
> + goto finish_prologue;
> }
>
> /* If we're in start, then give up. */
> if (strcmp (name, "start") == 0)
> {
> - if (fi != NULL)
> - my_frame_is_last (fi);
> - return pc;
> + addr = pc;
> + goto finish_prologue;
> }
>
> #if 0
> @@ -582,10 +592,6 @@ mn10300_analyze_prologue (struct frame_i
> }
> #endif
>
> - /* NOTE: from here on, we don't want to return without jumping to
> - finish_prologue. */
> -
> -
> /* Figure out where to stop scanning. */
> stop = fi ? pc : func_end;
>
> @@ -596,7 +602,7 @@ mn10300_analyze_prologue (struct frame_i
> addr = func_addr;
>
> /* Suck in two bytes. */
> - if (addr + 2 >= stop
> + if (addr + 2 > stop
> || (status = deprecated_read_memory_nobpt (addr, buf, 2)) != 0)
> goto finish_prologue;
>
> @@ -605,8 +611,6 @@ mn10300_analyze_prologue (struct frame_i
> so mark this as the bottom-most frame. */
> if (buf[0] == 0xf2 && (buf[1] & 0xf3) == 0xf0)
> {
> - if (fi)
> - my_frame_is_last (fi);
> goto finish_prologue;
> }
>
> @@ -632,6 +636,136 @@ mn10300_analyze_prologue (struct frame_i
> goto finish_prologue;
> }
>
> + if (AM33_MODE == 2)
> + {
> + /* Determine if any floating point registers are to be saved.
> + Look for one of the following three prologue formats:
> +
> + [movm [regs],(sp)] [movm [regs],(sp)] [movm [regs],(sp)]
> +
> + add -SIZE,sp add -SIZE,sp add -SIZE,sp
> + fmov fs#,(sp) mov sp,a0/a1 mov sp,a0/a1
> + fmov fs#,(#,sp) fmov fs#,(a0/a1+) add SIZE2,a0/a1
> + ... ... fmov fs#,(a0/a1+)
> + ... ... ...
> + fmov fs#,(#,sp) fmov fs#,(a0/a1+) fmov fs#,(a0/a1+)
> +
> + [mov sp,a3] [mov sp,a3]
> + [add -SIZE2,sp] [add -SIZE2,sp] */
> +
> + /* First, look for add -SIZE,sp (i.e. add imm8,sp (0xf8feXX)
> + or add imm16,sp (0xfafeXXXX)
> + or add imm32,sp (0xfcfeXXXXXXXX)) */
> + imm_size = 0;
> + if (buf[0] == 0xf8 && buf[1] == 0xfe)
> + imm_size = 1;
> + else if (buf[0] == 0xfa && buf[1] == 0xfe)
> + imm_size = 2;
> + else if (buf[0] == 0xfc && buf[1] == 0xfe)
> + imm_size = 4;
> + if (imm_size != 0)
> + {
> + /* An "add -#,sp" instruction has been found. "addr + 2 + imm_size"
> + is the address of the next instruction. Don't modify "addr" until
> + the next "floating point prologue" instruction is found. If this
> + is not a prologue that saves floating point registers we need to
> + be able to back out of this bit of code and continue with the
> + prologue analysis. */
> + if (addr + 2 + imm_size < stop)
> + {
> + status = deprecated_read_memory_nobpt (addr + 2 + imm_size, buf, 3);
> + if (status != 0)
> + goto finish_prologue;
> + if ((buf[0] & 0xfc) == 0x3c)
> + {
> + /* Occasionally, especially with C++ code, the "fmov"
> + instructions will be preceded by "mov sp,aN"
> + (aN => a0, a1, a2, or a3).
> +
> + This is a one byte instruction: mov sp,aN = 0011 11XX
> + where XX is the register number.
> +
> + Skip this instruction by incrementing addr. (We're
> + committed now.) The "fmov" instructions will have the
> + form "fmov fs#,(aN+)" in this case, but that will not
> + necessitate a change in the "fmov" parsing logic below. */
> +
> + addr++;
> +
> + if ((buf[1] & 0xfc) == 0x20)
> + {
> + /* Occasionally, especially with C++ code compiled with
> + the -fomit-frame-pointer or -O3 options, the
> + "mov sp,aN" instruction will be followed by an
> + "add #,aN" instruction. This indicates the
> + "stack_size", the size of the portion of the stack
> + containing the arguments. This instruction format is:
> + add #,aN = 0010 00XX YYYY YYYY
> + where XX is the register number
> + YYYY YYYY is the constant.
> + Note the size of the stack (as a negative number) in
> + the frame info structure. */
> + if (fi)
> + stack_extra_size += -buf[2];
> +
> + addr += 2;
> + }
> + }
> +
> + if ((buf[0] & 0xfc) == 0x3c ||
> + buf[0] == 0xf9 || buf[0] == 0xfb)
> + {
> + /* An "fmov" instruction has been found indicating that this
> + prologue saves floating point registers (or, as described
> + above, a "mov sp,aN" and possible "add #,aN" have been
> + found and we will assume an "fmov" follows). Process the
> + consecutive "fmov" instructions. */
> + for (addr += 2 + imm_size;;addr += imm_size)
> + {
> + int regnum;
> +
> + /* Read the "fmov" instruction. */
> + if (addr >= stop ||
> + (status = deprecated_read_memory_nobpt (addr, buf, 4)) != 0)
> + goto finish_prologue;
> +
> + if (buf[0] != 0xf9 && buf[0] != 0xfb)
> + break;
> +
> + /* Get the floating point register number from the
> + 2nd and 3rd bytes of the "fmov" instruction:
> + Machine Code: 0000 00X0 YYYY 0000 =>
> + Regnum: 000X YYYY */
> + regnum = (buf[1] & 0x02) << 3;
> + regnum |= ((buf[2] & 0xf0) >> 4) & 0x0f;
> +
> + /* Add this register number to the bit mask of floating
> + point registers that have been saved. */
> + fpregmask |= 1 << regnum;
> +
> + /* Determine the length of this "fmov" instruction.
> + fmov fs#,(sp) => 3 byte instruction
> + fmov fs#,(#,sp) => 4 byte instruction */
> + imm_size = (buf[0] == 0xf9) ? 3 : 4;
> + }
> + }
> + else
> + {
> + /* No "fmov" was found. Reread the two bytes at the original
> + "addr" to reset the state. */
> + status = deprecated_read_memory_nobpt (addr, buf, 2);
> + if (status != 0)
> + goto finish_prologue;
> + }
> + }
> + /* else the prologue consists entirely of an "add -SIZE,sp"
> + instruction. Handle this below. */
> + }
> + /* else no "add -SIZE,sp" was found indicating no floating point
> + registers are saved in this prologue. Do not increment addr. Pretend
> + this bit of code never happened. */
> + }
> +
> /* Now see if we set up a frame pointer via "mov sp,a3" */
> if (buf[0] == 0x3f)
> {
> @@ -640,7 +774,7 @@ mn10300_analyze_prologue (struct frame_i
> /* The frame pointer is now valid. */
> if (fi)
> {
> - my_frame_is_in_fp (fi, this_cache);
> + frame_in_fp = 1;
> }
>
> /* Quit now if we're beyond the stop point. */
> @@ -679,10 +813,8 @@ mn10300_analyze_prologue (struct frame_i
> if (status != 0)
> goto finish_prologue;
>
> - /* Note the size of the stack in the frame info structure. */
> - stack_size = extract_signed_integer (buf, imm_size);
> - if (fi)
> - set_my_stack_size (fi, stack_size);
> + /* Note the size of the stack. */
> + stack_extra_size += extract_signed_integer (buf, imm_size);
>
> /* We just consumed 2 + imm_size bytes. */
> addr += 2 + imm_size;
> @@ -694,7 +826,7 @@ mn10300_analyze_prologue (struct frame_i
> finish_prologue:
> /* Note if/where callee saved registers were saved. */
> if (fi)
> - set_movm_offsets (fi, this_cache, movm_args);
> + set_reg_offsets (fi, this_cache, movm_args, fpregmask, stack_extra_size, frame_in_fp);
> return addr;
> }
>
> @@ -975,6 +1107,7 @@ mn10300_gdbarch_init (struct gdbarch_inf
> {
> struct gdbarch *gdbarch;
> struct gdbarch_tdep *tdep;
> + int num_regs;
>
> arches = gdbarch_list_lookup_by_info (arches, &info);
> if (arches != NULL)
> @@ -989,10 +1122,18 @@ mn10300_gdbarch_init (struct gdbarch_inf
> case bfd_mach_mn10300:
> set_gdbarch_register_name (gdbarch, mn10300_generic_register_name);
> tdep->am33_mode = 0;
> + num_regs = 32;
> break;
> case bfd_mach_am33:
> set_gdbarch_register_name (gdbarch, am33_register_name);
> tdep->am33_mode = 1;
> + num_regs = 32;
> + break;
> + case bfd_mach_am33_2:
> + set_gdbarch_register_name (gdbarch, am33_2_register_name);
> + tdep->am33_mode = 2;
> + num_regs = 64;
> + set_gdbarch_fp0_regnum (gdbarch, 32);
> break;
> default:
> internal_error (__FILE__, __LINE__,
> @@ -1001,7 +1142,7 @@ mn10300_gdbarch_init (struct gdbarch_inf
> }
>
> /* Registers. */
> - set_gdbarch_num_regs (gdbarch, E_NUM_REGS);
> + set_gdbarch_num_regs (gdbarch, num_regs);
> set_gdbarch_register_type (gdbarch, mn10300_register_type);
> set_gdbarch_skip_prologue (gdbarch, mn10300_skip_prologue);
> set_gdbarch_read_pc (gdbarch, mn10300_read_pc);
> Index: mn10300-tdep.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/mn10300-tdep.h,v
> retrieving revision 1.5
> diff -u -p -r1.5 mn10300-tdep.h
> --- mn10300-tdep.h 2 Sep 2005 22:53:34 -0000 1.5
> +++ mn10300-tdep.h 3 Sep 2005 01:20:45 -0000
> @@ -51,8 +51,7 @@ enum {
> E_MCRL_REGNUM = 27,
> E_MCVF_REGNUM = 28,
> E_FPCR_REGNUM = 29,
> - E_FS0_REGNUM = 32,
> - E_NUM_REGS = 32
> + E_FS0_REGNUM = 32
> };
>
> enum movm_register_bits {
>
>