/* Definitions of target machine for GNU compiler.  Amiga 68000/68020 version.
   Copyright (C) 1987, 1988 Free Software Foundation, Inc.

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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "tm-m68k.h"

/* See tm-m68k.h.  7 means 68020 with 68881.  */

#ifndef TARGET_DEFAULT
#define TARGET_DEFAULT 0
#endif

/* Define __HAVE_FPA__ or __HAVE_68881__ in preprocessor,
   according to the -m flags.
   This will control the use of inline 68881 insns in certain macros.
   Also inform the program which CPU this is for.  */

#if TARGET_DEFAULT & 02

/* -m68881 is the default */
#define CPP_SPEC \
"%{!msoft-float:-D__HAVE_68881__ }\
%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}"

#else
/* -msoft-float is the default, assume -mc68000 as well */
#define CPP_SPEC \
"%{m68881:-D__HAVE_68881__ }\
%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}"

#endif

/* These compiler options take an argument.  We ignore -target for now.  */

/* #define WORD_SWITCH_TAKES_ARG(STR)	(!strcmp (STR, "target")) */

/* -m68000 requires special flags to the assembler.  */

#if TARGET_DEFAULT & 01

#define ASM_SPEC \
 "%{m68000:-mc68010}%{mc68000:-mc68010}%{!mc68000:%{!m68000:-mc68020}}"

#else

#define ASM_SPEC \
 "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68010}}"

#endif

/* Names to predefine in the preprocessor for this target machine.  */

/* amiga/amigados are the new "standard" defines for the Amiga, MCH_AMIGA
 * was used before and is included for compatibility reasons */

#define CPP_PREDEFINES "-Dmc68000 -Damiga -Damigados -DMCH_AMIGA -DAMIGA"

/* STARTFILE_SPEC to include sun floating point initialization
   This is necessary (tr: Sun does it) for both the m68881 and the fpa
   routines.
   Note that includes knowledge of the default specs for gcc, ie. no
   args translates to the same effect as -m68881
   I'm not sure what would happen below if people gave contradictory
   arguments (eg. -msoft-float -mfpa) */

#define STARTFILE_SPEC					\
  "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}"

/* Specify library to handle `-a' basic block profiling.
   Control choice of libm.a (if user says -lm)
   based on fp arith default and options.  */

/* for now, no different math libraries exist, there probably *will*
 * be some in the future. */
#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}"

/* if debugging, tell the linker to output amiga-hunk symbols *and*
 * a BSD compatible debug hunk */

#define LINK_SPEC "%{g:-amiga-debug-hunk} "

/* Every structure or union's size must be a multiple of 2 bytes.  */

#define STRUCTURE_SIZE_BOUNDARY 16

/* This is BSD, so it wants DBX format.  */

#define DBX_DEBUGGING_INFO

/* This is how to output an assembler line defining a `double' constant.  */

#undef ASM_OUTPUT_DOUBLE
#define ASM_OUTPUT_DOUBLE(FILE,VALUE)					\
  (isinf ((VALUE))							\
   ? fprintf (FILE, "\t.double 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \
   : fprintf (FILE, "\t.double 0r%.20e\n", (VALUE)))

/* This is how to output an assembler line defining a `float' constant.  */

#undef ASM_OUTPUT_FLOAT
#define ASM_OUTPUT_FLOAT(FILE,VALUE)					\
  (isinf ((VALUE))							\
   ? fprintf (FILE, "\t.single 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \
   : fprintf (FILE, "\t.single 0r%.20e\n", (VALUE)))

#undef ASM_OUTPUT_FLOAT_OPERAND
#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE)				\
  (isinf ((VALUE))							\
   ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \
   : fprintf (FILE, "#0r%.9g", (VALUE)))

#undef ASM_OUTPUT_DOUBLE_OPERAND
#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE)				\
  (isinf ((VALUE))							\
   ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \
   : fprintf (FILE, "#0r%.20g", (VALUE)))

/* use A5 as framepointer instead of A6, this makes A6 available as a
 * general purpose register, and can thus be used without problems in
 * direct library calls. */
#undef FRAME_POINTER_REGNUM
#define FRAME_POINTER_REGNUM 13
#undef ARG_POINTER_REGNUM
#define ARG_POINTER_REGNUM 13


#define CC_INCLUDE_DIR	"gcc:include"


#undef  FUNCTION_PROLOGUE
#define FUNCTION_PROLOGUE(FILE, SIZE)     \
{ register int regno;						\
  register int mask = 0;					\
  extern char call_used_regs[];					\
  int fsize = ((SIZE) + 3) & -4;				\
  if (frame_pointer_needed)					\
    { if (TARGET_68020 || fsize < 0x8000)			\
        fprintf (FILE, "\tlink a5,#%d\n", -fsize);		\
      else							\
	fprintf (FILE, "\tlink a5,#0\n\tsubl #%d,sp\n", fsize); }  \
  for (regno = 24; regno < 56; regno++)				\
    if (regs_ever_live[regno] && ! call_used_regs[regno])	\
      fprintf(FILE, "\tfpmoved %s, sp@-\n",			\
	      reg_names[regno]);				\
  for (regno = 16; regno < 24; regno++)				\
    if (regs_ever_live[regno] && ! call_used_regs[regno])	\
       mask |= 1 << (regno - 16);				\
  if ((mask & 0xff) != 0)					\
    fprintf (FILE, "\tfmovem #0x%x,sp@-\n", mask & 0xff);       \
  mask = 0;							\
  for (regno = 0; regno < 16; regno++)				\
    if (regs_ever_live[regno] && ! call_used_regs[regno])	\
       mask |= 1 << (15 - regno);				\
  if (frame_pointer_needed)					\
    mask &= ~ (1 << (15-FRAME_POINTER_REGNUM));			\
  if (exact_log2 (mask) >= 0)					\
    fprintf (FILE, "\tmovel %s,sp@-\n", reg_names[15 - exact_log2 (mask)]);  \
  else if (mask) fprintf (FILE, "\tmoveml #0x%x,sp@-\n", mask); }


#undef  FUNCTION_EPILOGUE
#define FUNCTION_EPILOGUE(FILE, SIZE) \
{ register int regno;						\
  register int mask, fmask;					\
  register int nregs;						\
  int offset, foffset, fpoffset;				\
  extern char call_used_regs[];					\
  extern int current_function_pops_args;			\
  extern int current_function_args_size;			\
  int fsize = ((SIZE) + 3) & -4;				\
  int big = 0;							\
  FUNCTION_EXTRA_EPILOGUE (FILE, SIZE);				\
  nregs = 0;  fmask = 0; fpoffset = 0;				\
  for (regno = 24 ; regno < 56 ; regno++)			\
    if (regs_ever_live[regno] && ! call_used_regs[regno])	\
      nregs++;							\
  fpoffset = nregs*8;						\
  nregs = 0;							\
  for (regno = 16; regno < 24; regno++)				\
    if (regs_ever_live[regno] && ! call_used_regs[regno])	\
      { nregs++; fmask |= 1 << (23 - regno); }			\
  foffset = fpoffset + nregs * 12;				\
  nregs = 0;  mask = 0;						\
  if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \
  for (regno = 0; regno < 16; regno++)				\
    if (regs_ever_live[regno] && ! call_used_regs[regno])	\
      { nregs++; mask |= 1 << regno; }				\
  offset = foffset + nregs * 4;					\
  if (offset + fsize >= 0x8000 					\
      && frame_pointer_needed 					\
      && (mask || fmask || fpoffset)) 				\
    { fprintf (FILE, "\tmovel #%d,a0\n", -fsize);		\
      fsize = 0, big = 1; }					\
  if (exact_log2 (mask) >= 0) {					\
    if (big)							\
      fprintf (FILE, "\tmovel a5@(-%d,a0:l),%s\n",		\
	       offset + fsize, reg_names[exact_log2 (mask)]);	\
    else if (! frame_pointer_needed)				\
      fprintf (FILE, "\tmovel sp@+,%s\n",			\
	       reg_names[exact_log2 (mask)]);			\
    else							\
      fprintf (FILE, "\tmovel a5@(-%d),%s\n",			\
	       offset + fsize, reg_names[exact_log2 (mask)]); }	\
  else if (mask) {						\
    if (big)							\
      fprintf (FILE, "\tmoveml a5@(-%d,a0:l),#0x%x\n",		\
	       offset + fsize, mask);				\
    else if (! frame_pointer_needed)				\
      fprintf (FILE, "\tmoveml sp@+,#0x%x\n", mask);		\
    else							\
      fprintf (FILE, "\tmoveml a5@(-%d),#0x%x\n",		\
	       offset + fsize, mask); }				\
  if (fmask) {							\
    if (big)							\
      fprintf (FILE, "\tfmovem a5@(-%d,a0:l),#0x%x\n",		\
	       foffset + fsize, fmask);				\
    else if (! frame_pointer_needed)				\
      fprintf (FILE, "\tfmovem sp@+,#0x%x\n", fmask);		\
    else							\
      fprintf (FILE, "\tfmovem a5@(-%d),#0x%x\n",		\
	       foffset + fsize, fmask); }			\
  if (fpoffset != 0)						\
    for (regno = 55; regno >= 24; regno--)			\
      if (regs_ever_live[regno] && ! call_used_regs[regno]) {	\
	if (big)						\
	  fprintf(FILE, "\tfpmoved a5@(-%d,a0:l), %s\n",	\
		  fpoffset + fsize, reg_names[regno]);		\
	else if (! frame_pointer_needed)			\
	  fprintf(FILE, "\tfpmoved sp@+, %s\n",			\
		  reg_names[regno]);				\
	else							\
	  fprintf(FILE, "\tfpmoved a5@(-%d), %s\n",		\
		  fpoffset + fsize, reg_names[regno]);		\
	fpoffset -= 8;						\
      }								\
  if (frame_pointer_needed)					\
    fprintf (FILE, "\tunlk a5\n");				\
  if (current_function_pops_args && current_function_args_size)	\
    fprintf (FILE, "\trtd #%d\n", current_function_args_size);	\
  else fprintf (FILE, "\trts\n"); }

