⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 avr.c

📁 gcc3.2.1源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Subroutines for insn-output.c for ATMEL AVR micro controllers   Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.   Contributed by Denis Chertykov (denisc@overta.ru)   This file is part of GNU CC.   GNU CC 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, or (at your option)   any later version.      GNU CC 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 GNU CC; see the file COPYING.  If not, write to   the Free Software Foundation, 59 Temple Place - Suite 330,   Boston, MA 02111-1307, USA.  */#include "config.h"#include "system.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "reload.h"#include "tree.h"#include "expr.h"#include "toplev.h"#include "obstack.h"#include "function.h"#include "recog.h"#include "tm_p.h"#include "target.h"#include "target-def.h"/* Maximal allowed offset for an address in the LD command */#define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))static int    avr_naked_function_p PARAMS ((tree));static int    interrupt_function_p PARAMS ((tree));static int    signal_function_p    PARAMS ((tree));static int    sequent_regs_live    PARAMS ((void));static const char * ptrreg_to_str  PARAMS ((int));static const char * cond_string    PARAMS ((enum rtx_code));static int    avr_num_arg_regs     PARAMS ((enum machine_mode, tree));static int    out_adj_frame_ptr    PARAMS ((FILE *, int));static int    out_set_stack_ptr    PARAMS ((FILE *, int, int));static RTX_CODE compare_condition  PARAMS ((rtx insn));static int    compare_sign_p       PARAMS ((rtx insn));static int    reg_was_0            PARAMS ((rtx insn, rtx op));static int    io_address_p         PARAMS ((rtx x, int size));void          debug_hard_reg_set   PARAMS ((HARD_REG_SET set));static tree   avr_handle_progmem_attribute PARAMS ((tree *, tree, tree, int, bool *));static tree   avr_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));const struct attribute_spec avr_attribute_table[];static bool   avr_assemble_integer PARAMS ((rtx, unsigned int, int));static void   avr_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void   avr_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));/* Allocate registers from r25 to r8 for parameters for function calls */#define FIRST_CUM_REG 26/* Temporary register RTX (gen_rtx (REG,QImode,TMP_REGNO)) */rtx tmp_reg_rtx;/* Zeroed register RTX (gen_rtx (REG,QImode,ZERO_REGNO)) */rtx zero_reg_rtx;/* RTX for register which will be used for loading immediate values to   r0-r15 registers.  */rtx ldi_reg_rtx;/* AVR register names {"r0", "r1", ..., "r31"} */static const char *const avr_regnames[] = REGISTER_NAMES;/* This holds the last insn address.  */static int last_insn_address = 0;/* Commands count in the compiled file */static int commands_in_file;/* Commands in the functions prologues in the compiled file */static int commands_in_prologues;/* Commands in the functions epilogues in the compiled file */static int commands_in_epilogues;/* Prologue/Epilogue size in words */static int prologue_size;static int epilogue_size;/* Size of all jump tables in the current function, in words.  */static int jump_tables_size;/* Initial stack value specified by the `-minit-stack=' option */const char *avr_init_stack = "__stack";/* Default MCU name */const char *avr_mcu_name = "avr2";/* More than 8K of program memory: use "call" and "jmp".  */int avr_mega_p = 0;/* Enhanced core: use "movw", "mul", ...  */int avr_enhanced_p = 0;enum avr_arch {  AVR1 = 1,  AVR2,  AVR3,  AVR4,  AVR5};struct mcu_type_s {  const char *const name;  const enum avr_arch arch;};/* List of all known AVR MCU types - if updated, it has to be kept   in sync in several places (FIXME: is there a better way?):    - here    - avr.h (CPP_SPEC, LINK_SPEC, CRT_BINUTILS_SPECS)    - t-avr (MULTILIB_MATCHES)    - gas/config/tc-avr.c    - avr-libc  */static const struct mcu_type_s avr_mcu_types[] = {    /* Classic, <= 8K.  */  { "avr2",      AVR2 },  { "at90s2313", AVR2 },  { "at90s2323", AVR2 },  { "attiny22",  AVR2 },  { "at90s2333", AVR2 },  { "at90s2343", AVR2 },  { "at90s4414", AVR2 },  { "at90s4433", AVR2 },  { "at90s4434", AVR2 },  { "at90s8515", AVR2 },  { "at90c8534", AVR2 },  { "at90s8535", AVR2 },    /* Classic, > 8K.  */  { "avr3",      AVR3 },  { "atmega103", AVR3 },  { "atmega603", AVR3 },  { "at43usb320", AVR3 },  { "at76c711",  AVR3 },    /* Enhanced, <= 8K.  */  { "avr4",      AVR4 },  { "atmega8",   AVR4 },  { "atmega83",  AVR4 },  { "atmega85",  AVR4 },    /* Enhanced, > 8K.  */  { "avr5",      AVR5 },  { "atmega16",  AVR5 },  { "atmega161", AVR5 },  { "atmega163", AVR5 },  { "atmega32",  AVR5 },  { "atmega323", AVR5 },  { "atmega64",  AVR5 },  { "atmega128", AVR5 },  { "at43usb355", AVR5 },  { "at94k",     AVR5 },    /* Assembler only.  */  { "avr1",      AVR1 },  { "at90s1200", AVR1 },  { "attiny10",  AVR1 },  { "attiny11",  AVR1 },  { "attiny12",  AVR1 },  { "attiny15",  AVR1 },  { "attiny28",  AVR1 },  { NULL, 0 }};int avr_case_values_threshold = 30000;/* Initialize the GCC target structure.  */#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"#undef TARGET_ASM_INTEGER#define TARGET_ASM_INTEGER avr_assemble_integer#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE avr_attribute_tablestruct gcc_target targetm = TARGET_INITIALIZER;voidavr_override_options (){  const struct mcu_type_s *t;  for (t = avr_mcu_types; t->name; t++)    if (strcmp (t->name, avr_mcu_name) == 0)      break;  if (!t->name)    {      fprintf (stderr, "unknown MCU `%s' specified\nKnown MCU names:\n",	       avr_mcu_name);      for (t = avr_mcu_types; t->name; t++)	fprintf (stderr,"   %s\n", t->name);    }  switch (t->arch)    {    case AVR1:    default:      error ("MCU `%s' not supported", avr_mcu_name);      /* ... fall through ... */    case AVR2: avr_enhanced_p = 0; avr_mega_p = 0; break;    case AVR3: avr_enhanced_p = 0; avr_mega_p = 1; break;    case AVR4: avr_enhanced_p = 1; avr_mega_p = 0; break;    case AVR5: avr_enhanced_p = 1; avr_mega_p = 1; break;    }  if (optimize && !TARGET_NO_TABLEJUMP)    avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17;}/* Initialize TMP_REG_RTX and ZERO_REG_RTX */voidavr_init_once (){  tmp_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));  memset (tmp_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));  PUT_CODE (tmp_reg_rtx, REG);  PUT_MODE (tmp_reg_rtx, QImode);  XINT (tmp_reg_rtx, 0) = TMP_REGNO;  zero_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));  memset (zero_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));  PUT_CODE (zero_reg_rtx, REG);  PUT_MODE (zero_reg_rtx, QImode);  XINT (zero_reg_rtx, 0) = ZERO_REGNO;  ldi_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));  memset (ldi_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));  PUT_CODE (ldi_reg_rtx, REG);  PUT_MODE (ldi_reg_rtx, QImode);  XINT (ldi_reg_rtx, 0) = LDI_REG_REGNO;}/*  return register class from register number */static const int reg_class_tab[]={  GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,  GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,  GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,  GENERAL_REGS, /* r0 - r15 */  LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,  LD_REGS,                      /* r16 - 23 */  ADDW_REGS,ADDW_REGS,          /* r24,r25 */  POINTER_X_REGS,POINTER_X_REGS, /* r26,27 */  POINTER_Y_REGS,POINTER_Y_REGS, /* r28,r29 */  POINTER_Z_REGS,POINTER_Z_REGS, /* r30,r31 */  STACK_REG,STACK_REG           /* SPL,SPH */};/* Return register class for register R */enum reg_classavr_regno_reg_class (r)     int r;{  if (r <= 33)    return reg_class_tab[r];  return ALL_REGS;}/* A C expression which defines the machine-dependent operand   constraint letters for register classes.  If C is such a   letter, the value should be the register class corresponding to   it.  Otherwise, the value should be `NO_REGS'.  The register   letter `r', corresponding to class `GENERAL_REGS', will not be   passed to this macro; you do not need to handle it.  */enum reg_classavr_reg_class_from_letter  (c)     int c;{  switch (c)    {    case 't' : return R0_REG;    case 'b' : return BASE_POINTER_REGS;    case 'e' : return POINTER_REGS;    case 'w' : return ADDW_REGS;    case 'd' : return LD_REGS;    case 'l' : return NO_LD_REGS;    case 'a' : return SIMPLE_LD_REGS;    case 'x' : return POINTER_X_REGS;    case 'y' : return POINTER_Y_REGS;    case 'z' : return POINTER_Z_REGS;    case 'q' : return STACK_REG;    default: break;    }  return NO_REGS;}/* Return non-zero if FUNC is a naked function.  */static intavr_naked_function_p (func)     tree func;{  tree a;  if (TREE_CODE (func) != FUNCTION_DECL)    abort ();    a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));  return a != NULL_TREE;}/* Return nonzero if FUNC is an interrupt function as specified   by the "interrupt" attribute.  */static intinterrupt_function_p (func)     tree func;{  tree a;  if (TREE_CODE (func) != FUNCTION_DECL)    return 0;  a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));  return a != NULL_TREE;}/* Return nonzero if FUNC is a signal function as specified   by the "signal" attribute.  */static intsignal_function_p (func)     tree func;{  tree a;  if (TREE_CODE (func) != FUNCTION_DECL)    return 0;  a = lookup_attribute ("signal", DECL_ATTRIBUTES (func));  return a != NULL_TREE;}/* Compute offset between arg_pointer and frame_pointer */intinitial_elimination_offset (from, to)     int from;     int to;{  int reg;  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)    return 0;  else    {      int interrupt_func_p = interrupt_function_p (current_function_decl);      int signal_func_p = signal_function_p (current_function_decl);      int leaf_func_p = leaf_function_p ();      int offset= frame_pointer_needed ? 2 : 0;      for (reg = 0; reg < 32; ++reg)	{	  if ((!leaf_func_p && (call_used_regs[reg]				&& (interrupt_func_p || signal_func_p)))	      || (regs_ever_live[reg]		  && (!call_used_regs[reg] || interrupt_func_p || signal_func_p)		  && ! (frame_pointer_needed			&& (reg == REG_Y || reg == (REG_Y+1)))))	    {	      ++offset;	    }	}      return get_frame_size () + 2 + 1 + offset;    }  return 0;}/* This function checks sequence of live registers */static intsequent_regs_live (){  int reg;  int live_seq=0;  int cur_seq=0;  for (reg = 0; reg < 18; ++reg)    {      if (!call_used_regs[reg])	{	  if (regs_ever_live[reg])	    {	      ++live_seq;	      ++cur_seq;	    }	  else	    cur_seq = 0;	}    }  if (!frame_pointer_needed)    {      if (regs_ever_live[REG_Y])	{	  ++live_seq;	  ++cur_seq;	}      else	cur_seq = 0;      if (regs_ever_live[REG_Y+1])	{	  ++live_seq;	  ++cur_seq;	}      else	cur_seq = 0;    }  else    {      cur_seq += 2;      live_seq += 2;    }  return (cur_seq == live_seq) ? live_seq : 0;}/* Output to FILE the asm instructions to adjust the frame pointer by   ADJ (r29:r28 -= ADJ;) which can be positive (prologue) or negative   (epilogue).  Returns the number of instructions generated.  */static intout_adj_frame_ptr (file, adj)     FILE *file;     int adj;{  int size = 0;  if (adj)    {      if (TARGET_TINY_STACK)	{	  if (adj < -63 || adj > 63)	    warning ("large frame pointer change (%d) with -mtiny-stack", adj);	  /* The high byte (r29) doesn't change - prefer "subi" (1 cycle)	     over "sbiw" (2 cycles, same size).  */	  fprintf (file, (AS2 (subi, r28, %d) CR_TAB), adj);	  size++;	}      else if (adj < -63 || adj > 63)	{	  fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB			  AS2 (sbci, r29, hi8(%d)) CR_TAB),		   adj, adj);	  size += 2;	}      else if (adj < 0)	{	  fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj);	  size++;	}      else	{	  fprintf (file, (AS2 (sbiw, r28, %d) CR_TAB), adj);	  size++;	}    }  return size;}/* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL,   handling various cases of interrupt enable flag state BEFORE and AFTER   (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags.   Returns the number of instructions generated.  */static intout_set_stack_ptr (file, before, after)     FILE *file;     int before;     int after;{  int do_sph, do_cli, do_save, do_sei, lock_sph, size;  /* The logic here is so that -mno-interrupts actually means     "it is safe to write SPH in one instruction, then SPL in the     next instruction, without disabling interrupts first".     The after != -1 case (interrupt/signal) is not affected.  */  do_sph = !TARGET_TINY_STACK;  lock_sph = do_sph && !TARGET_NO_INTERRUPTS;  do_cli = (before != 0 && (after == 0 || lock_sph));  do_save = (do_cli && before == -1 && after == -1);  do_sei = ((do_cli || before != 1) && after == 1);  size = 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -