This is just one file and working simulator. I posted the work I've done so far. (attached again) Actually, I'm planning to do this (unless someone will pick it up before me), but hell busy now.
~d > I don't have much time right now, but maybe you could commit a > "gdb-current" tree with the bits you have done (and a big fat "DOES > NOT WORK YET" disclaimer), and see if someone picks it up... > > > Regards, -- /******************************************************************** ("`-''-/").___..--''"`-._ (\ Dimmy the Wild UA1ACZ `6_ 6 ) `-. ( ).`-.__.`) Enterprise Information Sys (_Y_.)' ._ ) `._ `. ``-..-' Nevsky prospekt, 20 / 44 _..`--'_..-_/ /--'_.' ,' Saint Petersburg, Russia (il),-'' (li),' ((!.-' +7 (812) 3468202, 5585314 ********************************************************************/
/* Target-dependent code for Atmel AVR, for GDB. Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "gdbcmd.h" #include "gdbcore.h" #include "inferior.h" #include "symfile.h" #include "arch-utils.h" #include "regcache.h" #include "gdb_string.h" #undef XMALLOC #define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE))) #undef EXTRACT_INSN #define EXTRACT_INSN(addr) extract_unsigned_integer(addr,2) #undef INSURE_ADDR #define INSURE_ADDR(x) ((x)&0x00fffful) #define MSP430_PC_REGNUM 0 #define MSP430_SP_REGNUM 1 #define MSP430_FP_REGNUM 1 /* is Ok for now. */ #define MSP430_FIRST_PSEUDO_REG 16 #define MSP430_NUM_REGS 16 #define MSP430_RETVAL_REGNUM 15 #define MSP430_LAST_ARGREG 12 #define MSP430_FIRST_ARGREG 15 /* The registers of the msp430 processors */ static const char *msp430_register_names[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }; /* patterns */ static unsigned short eint = 0xd232; static unsigned short push_rn = 0x1200; /* bitmask: push rX */ static unsigned short load_fp = 0x4104; /* match: mov r1, r4 */ static unsigned short sub_val = 0x8031; /* sub #VAL, r1 , VAL is not one of the consts. */ static unsigned short sub_2 = 0x8321; static unsigned short sub_4 = 0x8221; static unsigned short sub_8 = 0x8231; static unsigned short load_ap = 0x4105; /* match: mov r1, r5 */ static unsigned short add_val = 0x5035; /* followed by add value */ static unsigned short add_2 = 0x5325; static unsigned short add_4 = 0x5225; static unsigned short add_8 = 0x5235; static unsigned short init_sp = 0x4031; /* followed by value ... XXX assume no stupid things happen */ static const char * msp430_register_name (int regnum) { if (regnum < 0) return NULL; if (regnum >= MSP430_FIRST_PSEUDO_REG) return NULL; return msp430_register_names[regnum]; } static CORE_ADDR msp430_read_pc (ptid_t ptid) { return read_register_pid (MSP430_PC_REGNUM, ptid); } static void msp430_write_pc (ptid_t ptid) { write_register_pid (MSP430_PC_REGNUM, pc, ptid); } static CORE_ADDR msp430_read_fp (void) { /* I whish to have here something like: read_register (extra_frame_info->fp_regnum). However, right after prologue, even if r4 has been eliminated r4==r1: push Rn sub #XX, r1 ; adjust stack val. mov r1, r4 ; load r4 (paradoxial frame pointer) So, if there is no call around current PC which performs some pushes of long arg list, the following will be correct. However this will be broken in two cases: 1. va_arg, long arg list calls: call(arg1, arg2, arg3,...); => push argN ; r1 now is broken! ... ; so, stepping though asm insn push arg2 ; may result (if r1 being used as FP) push arg1 ; wrong args list and everything else call #call sub #(2*N), r1 ; since FP will be just fine. 2. The same, but arg on stack: ... push X(r1) ; henceforth r1 is broken again push Y(r4) ; the same if r4 is a FP */ return read_register (MSP430_SP_REGNUM); } static CORE_ADDR msp430_read_sp (void) { read_register (MSP430_SP_REGNUM); } static void msp430_write_sp (CORE_ADDR val) { write_register (MSP430_SP_REGNUM, INSURE_ADDR (val)); } static int msp430_register_byte (int regnum) { if (regnum >= MSP430_FIRST_PSEUDO_REG) return 32; return regnum * 2; } static int msp430_register_raw_size (int regnum) { return 2; /* all registers are 2 bytes wide. */ } static int msp430_register_virtual_size (int regnum) { return return TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (regnum)); } static struct type * msp430_register_virtual_type (int regnum) { if (regnum >= MSP430_FIRST_PSEUDO_REG) return builtin_type_void; return builtin_type_unsigned_short; } static CORE_ADDR msp430_call_dummy_address (void) { return entry_point_address (); } void msp430_extract_return_value (struct type *type, char *regbuf, char *valbuf) { /* Copy the return value (starting) in RETVAL_REGNUM to VALBUF. */ /* Only getting the first byte! if len = 1, we need the last byte of the register, not the first. */ memcpy (valbuf, regbuf + REGISTER_BYTE (MSP430_RETVAL_REGNUM) + (TYPE_LENGTH (type) < 8 ? 8 - TYPE_LENGTH (type) : 0), TYPE_LENGTH (type)); } void msp430_store_return_value (struct type *type, char *valbuf) { int value_size; int return_size; int offset; char *zeros; value_size = TYPE_LENGTH (type); /* Return value fits into registers. */ return_size = (value_size + REGISTER_SIZE - 1) & ~(REGISTER_SIZE - 1); offset = REGISTER_BYTE (MSP430_RETVAL_REGNUM) + (return_size - value_size); zeros = alloca (return_size); memset (zeros, 0, return_size); write_register_bytes (REGISTER_BYTE (MSP430_RETVAL_REGNUM), zeros, return_size); write_register_bytes (offset, valbuf, value_size); } static void msp430_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) { /* mspgcc stores struct ret addr at r15 */ write_register (MSP430_RETVAL_REGNUM, addr); } CORE_ADDR msp430_extract_struct_value_address (char *regbuf) { return extract_address (regbuf + REGISTER_BYTE (MSP430_FIRST_ARGREG), REGISTER_SIZE); } /* Find the value of register REGNUM in frame FI. */ CORE_ADDR msp430_find_callers_reg (struct frame_info * fi, int regnum) { for (; fi != NULL; fi = get_next_frame (fi)) { if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), get_frame_base (fi), get_frame_base (fi))) return INSURE_ADDR (deprecated_read_register_dummy (get_frame_pc (fi), get_frame_base (fi), regnum)); else if (get_frame_saved_regs (fi)[regnum] != 0) return INSURE_ADDR (read_memory_integer (get_frame_saved_regs (fi)[regnum], REGISTER_SIZE)); } return read_register (regnum); } /* Find the saved pc in frame FI. */ CORE_ADDR msp430_frame_saved_pc (struct frame_info * fi) { if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), get_frame_base (fi), get_frame_base (fi))) return deprecated_read_register_dummy (get_frame_pc (fi), get_frame_base (fi), MSP430_PC_REGNUM); else return INSURE_ADDR (msp430_find_callers_reg (fi, MSP430_PR_REGNUM)); } /* SCAN prologue. */ /* Additional info that we use for managing frames */ struct frame_extra_info { CORE_ADDR entry_addr; int framesize; int fp_regnum; int num_saved_regs; int reti; }; /* * THIS SHOULD BE WRITTEN!!!!!!!!!!!!!!!!!!!!!!!! */ static void msp430_scan_prologue (struct frame_info *fi) { CORE_ADDR func_start, func_end, addr, stop; int status; int pc; char *name; if(fi) { pc = get_frame_pc (fi); get_frame_extra_info (fi)->framereg = MSP430_FP_REGNUM; status = find_pc_partial_function(pc, &name, &func_start, &func_end); if(status) { } } } CORE_ADDR msp430_push_arguments (int nargs, struct value ** args, CORE_ADDR sp, unsigned char struct_return, CORE_ADDR struct_addr) { int argreg; int argnum; struct stack_arg { int len; char *val; } *stack_args; int nstack_args = 0; stack_args = (struct stack_arg *) alloca (nargs * sizeof (struct stack_arg)); argreg = MSP430_FIRST_ARGREG; sp &= ~1; if (struct_return) write_register (argreg--, struct_addr); for (argnum = 0; argnum < nargs; argnum++) { char *val = (char *) VALUE_CONTENTS (args[argnum]); int len = TYPE_LENGTH (VALUE_TYPE (args[argnum])); struct type *type = VALUE_TYPE (args[argnum]); int olen; msp430_insn_debug (("MSP430 PUSH: argreg=%d; len=%d; %s\n", argreg, len, TYPE_CODE (type) == TYPE_CODE_STRUCT ? "struct" : "not struct")); /* Arguments larger than a register must start in an even numbered register. */ olen = len; if (TYPE_CODE (type) != TYPE_CODE_STRUCT && len > REGISTER_SIZE && argreg % 2) { msp430_insn_debug (("MSP430 PUSH: %d > REGISTER_SIZE: and %s is not even\n", len, msp430_register_names[argreg])); argreg--; } if ((argreg >= MSP430_LAST_ARGREG && len <= (-MSP430_LAST_ARGREG + argreg + 1) * REGISTER_SIZE) || (TYPE_CODE (type) == TYPE_CODE_STRUCT)) { /* Something that will fit entirely into registers (or a struct which may be split between registers and stack). */ msp430_insn_debug (("MSP430 PUSH: arg %d going into regs\n", argnum)); if (TYPE_CODE (type) == TYPE_CODE_STRUCT && olen < REGISTER_SIZE) { /* Small structs must be right aligned within the register, the most significant bits are undefined. */ write_register (argreg, extract_unsigned_integer (val, len)); argreg--; len = 0; } while (len > 0 && argreg >= MSP430_LAST_ARGREG) { write_register (argreg, extract_unsigned_integer (val, REGISTER_SIZE)); argreg--; val += REGISTER_SIZE; len -= REGISTER_SIZE; } /* Any remainder for the stack is noted below... */ } else if (TYPE_CODE (VALUE_TYPE (args[argnum])) != TYPE_CODE_STRUCT && len > REGISTER_SIZE) { /* All subsequent args go onto the stack. */ msp430_insn_debug (("MSP430 PUSH: does not fit into regs, going onto stack\n")); argnum = MSP430_LAST_ARGREG - 1; } if (len > 0) { /* Note that this must be saved onto the stack */ msp430_insn_debug (("MSP430 PUSH: adding arg %d to stack\n", argnum)); stack_args[nstack_args].val = val; stack_args[nstack_args].len = len; nstack_args++; } } /* We're done with registers and stack allocation. Now do the actual stack pushes. */ while (nstack_args--) { sp -= stack_args[nstack_args].len; write_memory (sp, stack_args[nstack_args].val, stack_args[nstack_args].len); } /* Return adjusted stack pointer. */ return sp; } void msp430_pop_frame (void) { int rn; CORE_ADDR ret; struct frame_info *fi = get_current_frame (); if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), get_frame_base (fi), get_frame_base (fi))) generic_pop_dummy_frame (); else { /* Write out the PC we saved. */ ret = FRAME_SAVED_PC (fi); write_register (MSP430_PC_REGNUM, ret); /* Restore any saved registers. */ for (rn = 4; rn < MSP430_NUM_REGS; rn++) { if (get_frame_saved_regs (fi)[rn] != 0) { ULONGEST value; value = read_memory_unsigned_integer (get_frame_saved_regs (fi)[rn], REGISTER_SIZE); write_register (rn, value); } } if (get_frame_extra_info (fi)->reti) { ULONGEST value; value = read_memory_unsigned_integer (fi->saved_regs[2], REGISTER_SIZE); write_register (2, value); } /* Actually cut back the stack. */ write_register (MSP430_SP_REGNUM, (FRAME_FP (fi)) + 2); } /* Finally, throw away any cached frame information. */ flush_cached_frames (); } CORE_ADDR msp430_saved_pc_after_call (struct frame_info * frame) { unsigned char m1, m2; unsigned int sp = read_register (MSP430_SP_REGNUM); m1 = 0xff & read_memory_unsigned_integer (sp + 0, 1); m2 = 0xff & read_memory_unsigned_integer (sp + 1, 1); return 0xffff & (m1 | ((unsigned long)m2 << 8)); } CORE_ADDR msp430_push_return_address (CORE_ADDR pc, CORE_ADDR sp) { write_register (PC_REGNUM, CALL_DUMMY_ADDRESS ()); return sp; } unsigned char * msp430_breakpoint_from_pc (CORE_ADDR * bp_addr, int *bp_size) { static char breakpoint[] = { 0x00, 0x00 }; *bp_size = 2; return breakpoint; } CORE_ADDR msp430_frame_args_address (struct frame_info * fi) { return INSURE_ADDR(get_frame_base (fi) + 2 + get_frame_extra_info (fi)->reti); } CORE_ADDR msp430_frame_locals_address (struct frame_info * fi) { return INSURE_ADDR(get_frame_base (fi) - get_frame_extra_info (fi)->framesize); } static struct gdbarch * msp430_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; static LONGEST msp430_call_dummy_words[] = { 0 }; /* Find a candidate among the list of pre-declared architectures. */ arches = gdbarch_list_lookup_by_info (arches, &info); if (arches != NULL) return arches->gdbarch; /* None found, create a new architecture from the information provided. */ tdep = XMALLOC (struct gdbarch_tdep); gdbarch = gdbarch_alloc (&info, tdep); set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default); /* If we ever need to differentiate the device types, do it here. Currently, all targets are equial */ switch (info.bfd_arch_info->mach) { default: break; } set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT); set_gdbarch_int_bit (gdbarch, 2 * TARGET_CHAR_BIT); set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT); set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT); set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT); set_gdbarch_addr_bit (gdbarch, 32); set_gdbarch_bfd_vma_bit (gdbarch, 32); /* FIXME: TRoth/2002-02-18: Is this needed? */ set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT); set_gdbarch_double_bit (gdbarch, 4 * TARGET_CHAR_BIT); set_gdbarch_long_double_bit (gdbarch, 4 * TARGET_CHAR_BIT); set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little); set_gdbarch_double_format (gdbarch, &floatformat_ieee_single_little); set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_single_little); set_gdbarch_read_pc (gdbarch, msp430_read_pc); set_gdbarch_write_pc (gdbarch, msp430_write_pc); set_gdbarch_read_fp (gdbarch, msp430_read_fp); set_gdbarch_read_sp (gdbarch, msp430_read_sp); set_gdbarch_write_sp (gdbarch, msp430_write_sp); set_gdbarch_num_regs (gdbarch, MSP430_NUM_REGS); set_gdbarch_sp_regnum (gdbarch, MSP430_SP_REGNUM); set_gdbarch_fp_regnum (gdbarch, MSP430_FP_REGNUM); set_gdbarch_pc_regnum (gdbarch, MSP430_PC_REGNUM); set_gdbarch_register_name (gdbarch, msp430_register_name); set_gdbarch_register_size (gdbarch, 2); set_gdbarch_register_bytes (gdbarch, MSP430_NUM_REGS * 2); set_gdbarch_register_byte (gdbarch, msp430_register_byte); set_gdbarch_register_raw_size (gdbarch, msp430_register_raw_size); set_gdbarch_max_register_raw_size (gdbarch, 2); set_gdbarch_register_virtual_size (gdbarch, msp430_register_virtual_size); set_gdbarch_max_register_virtual_size (gdbarch, 2); set_gdbarch_register_virtual_type (gdbarch, msp430_register_virtual_type); set_gdbarch_print_insn (gdbarch, print_insn_msp430); set_gdbarch_call_dummy_address (gdbarch, msp430_call_dummy_address); set_gdbarch_call_dummy_start_offset (gdbarch, 0); set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1); set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0); set_gdbarch_call_dummy_length (gdbarch, 0); set_gdbarch_call_dummy_p (gdbarch, 1); set_gdbarch_call_dummy_words (gdbarch, msp430_call_dummy_words); set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0); set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy); set_gdbarch_deprecated_extract_return_value (gdbarch, msp430_extract_return_value); set_gdbarch_push_arguments (gdbarch, msp430_push_arguments); set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame); set_gdbarch_push_return_address (gdbarch, msp430_push_return_address); set_gdbarch_pop_frame (gdbarch, msp430_pop_frame); set_gdbarch_deprecated_store_return_value (gdbarch, msp430_store_return_value); set_gdbarch_use_struct_convention (gdbarch, generic_use_struct_convention); set_gdbarch_store_struct_return (gdbarch, msp430_store_struct_return); set_gdbarch_deprecated_extract_struct_value_address (gdbarch, msp430_extract_struct_value_address); set_gdbarch_breakpoint_from_pc (gdbarch, msp430_breakpoint_from_pc); /******************************************/ /*** ?????? PROBABLY INCORRECT ***/ set_gdbarch_frame_init_saved_regs (gdbarch, msp430_scan_prologue); set_gdbarch_init_extra_frame_info (gdbarch, msp430_init_extra_frame_info); set_gdbarch_frame_saved_pc (gdbarch, msp430_frame_saved_pc); set_gdbarch_frame_args_address (gdbarch, msp430_frame_args_address); set_gdbarch_frame_locals_address (gdbarch, msp430_frame_locals_address); set_gdbarch_saved_pc_after_call (gdbarch, msp430_saved_pc_after_call); set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown); return gdbarch; }