eggert@AI.MIT.EDU (Paul Eggert) (06/14/89)
Here is a tm- file for the Omron Luna, which is a 68030 Integrated Solutions machine. The compiler compiles itself correctly under UNIOS-B 4.3BSD UNIX: 1.21R, with USE_GAS either set (the default) or unset. Perhaps this file should replace the old tm-isi68.h; or perhaps you'd like to call it tm-luna.h. Although the machine is a 68030, there's little evidence that it's anything but a 68020, so I think this same file will work with 68020s too. ================================================================ /* Definitions of target machine for GNU compiler. ISI 68020 version. Copyright (C) 1988, 1989 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. */ /* Define USE_GAS if GCC is supposed to work with the GNU assembler. Use ISI's assembler otherwise. Warning: ISI's assembler is buggy, and to work around the bugs we must generate slower code. */ #define USE_GAS #include "tm-m68k.h" /* See tm-m68k.h. 7 means 68020 with 68881. */ #define TARGET_DEFAULT 7 /* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. This will control the use of inline 68881 insns in certain macros. */ #define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__}" /* If the 68881 is used, link must load libmc.a instead of libc.a */ #define LIB_SPEC "%{msoft-float:%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}%{!msoft-float:%{!p:%{!pg:-lmc}}%{p:-lmc_p}%{pg:-lmc_p}}" /* Names to predefine in the preprocessor for this target machine. */ #define CPP_PREDEFINES "-Dieeep754 -Dis68k -Dmc68000 -Dunix" /* This is BSD, so it wants DBX format. */ #define DBX_DEBUGGING_INFO /* Override parts of tm-m68k.h. */ #undef FUNCTION_VALUE #undef LIBCALL_VALUE #undef FUNCTION_VALUE_REGNO_P #undef ASM_FILE_START /* If TARGET_68881, return SF and DF values in f0 instead of d0. */ #define FUNCTION_VALUE(VALTYPE,FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) #define LIBCALL_VALUE(MODE) \ gen_rtx (REG, (MODE), ((TARGET_68881 && ((MODE) == SFmode || (MODE) == DFmode)) ? 16 : 0)) /* 1 if N is a possible register number for a function value. D0 may be used, and F0 as well if -m68881 is specified. */ #define FUNCTION_VALUE_REGNO_P(N) \ ((N) == 0 || (TARGET_68881 && (N) == 16)) #ifdef USE_GAS /* Also output something to cause the correct _doprnt to be loaded. */ #define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n.globl fltused\n") #else /* Also output something to cause the correct _doprnt to be loaded. */ #define ASM_FILE_START(FILE) fprintf (FILE, ".globl fltused\n") /* The assembler doesn't understand tstl a0; generate slower code instead. */ #define ISI_OV /* The assembler requires a special flag. */ #define ASM_SPEC "-20" #undef FUNCTION_PROLOGUE #undef FUNCTION_EPILOGUE #undef REGISTER_NAMES #undef ASM_OUTPUT_SKIP #undef ASM_OUTPUT_DOUBLE #undef ASM_OUTPUT_FLOAT_OPERAND #undef ASM_OUTPUT_DOUBLE_OPERAND #undef PRINT_OPERAND #undef PRINT_OPERAND_ADDRESS /* The assembler requires 'fmovemx'; it does not understand 'fmovem'. */ #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 a6,#%d\n", -fsize); \ else \ fprintf (FILE, "\tlink a6,#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, "\tfmovemx #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); } #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; \ 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 a6@(-%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 a6@(-%d),%s\n", \ offset + fsize, reg_names[exact_log2 (mask)]); } \ else if (mask) { \ if (big) \ fprintf (FILE, "\tmoveml a6@(-%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 a6@(-%d),#0x%x\n", \ offset + fsize, mask); } \ if (fmask) { \ if (big) \ fprintf (FILE, "\tfmovemx a6@(-%d,a0:l),#0x%x\n", \ foffset + fsize, fmask); \ else if (! frame_pointer_needed) \ fprintf (FILE, "\tfmovemx sp@+,#0x%x\n", fmask); \ else \ fprintf (FILE, "\tfmovemx a6@(-%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 a6@(-%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 a6@(-%d), %s\n", \ fpoffset + fsize, reg_names[regno]); \ fpoffset -= 8; \ } \ if (frame_pointer_needed) \ fprintf (FILE, "\tunlk a6\n"); \ if (current_function_pops_args && current_function_args_size) \ fprintf (FILE, "\trtd #%d\n", current_function_args_size); \ else fprintf (FILE, "\trts\n"); } /* How to refer to registers in assembler output. */ #define REGISTER_NAMES \ {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", } /* How to output floats and doubles. */ #define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ fprintf (FILE, "\t.double 0d%.20g\n", (VALUE)) #define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ fprintf (FILE, "#0f%.9g", (VALUE)) #define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ fprintf (FILE, "#0d%.20g", (VALUE)) /* How to skip n bytes in the output. */ #define ASM_OUTPUT_SKIP(FILE,SIZE) \ fprintf (FILE, "\t.space %d\n", (SIZE)) /* The assembler does not allow '#' before bit fields. */ #define PRINT_OPERAND(FILE, X, CODE) \ { int i; \ if (CODE == '.') ; \ else if (CODE == '#') fprintf (FILE, "#"); \ else if (CODE == '-') fprintf (FILE, "sp@-"); \ else if (CODE == '+') fprintf (FILE, "sp@+"); \ else if (CODE == '@') fprintf (FILE, "sp@"); \ else if (CODE == '!') fprintf (FILE, "cc"); \ else if (GET_CODE (X) == REG) \ { if (REGNO (X) < 16 && (CODE == 'y' || CODE == 'x') && GET_MODE (X) == DFmode) \ fprintf (FILE, "%s:%s", reg_names[REGNO (X)], reg_names[REGNO (X)+1]); \ else \ fprintf (FILE, "%s", reg_names[REGNO (X)]); \ } \ else if (GET_CODE (X) == MEM) \ { \ output_address (XEXP (X, 0)); \ if (CODE == 'd' && ! TARGET_68020 \ && CONSTANT_ADDRESS_P (XEXP (X, 0))) \ fprintf (FILE, ":l"); \ } \ else if ((CODE == 'y' || CODE == 'w') \ && GET_CODE(X) == CONST_DOUBLE \ && (i = standard_sun_fpa_constant_p (X))) \ fprintf (FILE, "%%%d", i & 0x1ff); \ else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ { union { double d; int i[2]; } u; \ union { float f; int i; } u1; \ u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ u1.f = u.d; \ if (CODE == 'f') \ ASM_OUTPUT_FLOAT_OPERAND (FILE, u1.f); \ else \ fprintf (FILE, "#0x%x", u1.i); } \ else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ { union { double d; int i[2]; } u; \ u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ ASM_OUTPUT_DOUBLE_OPERAND (FILE, u.d); } \ else if (CODE == 'b') output_addr_const (FILE, X); \ else { putc ('#', FILE); output_addr_const (FILE, X); }} /* The assembler uses "*S" instead of ":S" for a scale factor S, and requires "0," before an index register with zero offset. Also, because it cannot assemble a byte-size displacement from an indexed jump, we must generate a slower word-size displacement instead. */ #define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ { register rtx reg1, reg2, breg, ireg; \ register rtx addr = ADDR; \ rtx offset; \ switch (GET_CODE (addr)) \ { \ case REG: \ fprintf (FILE, "%s@", reg_names[REGNO (addr)]); \ break; \ case PRE_DEC: \ fprintf (FILE, "%s@-", reg_names[REGNO (XEXP (addr, 0))]); \ break; \ case POST_INC: \ fprintf (FILE, "%s@+", reg_names[REGNO (XEXP (addr, 0))]); \ break; \ case PLUS: \ reg1 = 0; reg2 = 0; \ ireg = 0; breg = 0; \ offset = 0; \ if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ { \ offset = XEXP (addr, 0); \ addr = XEXP (addr, 1); \ } \ else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ { \ offset = XEXP (addr, 1); \ addr = XEXP (addr, 0); \ } \ if (GET_CODE (addr) != PLUS) ; \ else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ { \ reg1 = XEXP (addr, 0); \ addr = XEXP (addr, 1); \ } \ else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ { \ reg1 = XEXP (addr, 1); \ addr = XEXP (addr, 0); \ } \ else if (GET_CODE (XEXP (addr, 0)) == MULT) \ { \ reg1 = XEXP (addr, 0); \ addr = XEXP (addr, 1); \ } \ else if (GET_CODE (XEXP (addr, 1)) == MULT) \ { \ reg1 = XEXP (addr, 1); \ addr = XEXP (addr, 0); \ } \ else if (GET_CODE (XEXP (addr, 0)) == REG) \ { \ reg1 = XEXP (addr, 0); \ addr = XEXP (addr, 1); \ } \ else if (GET_CODE (XEXP (addr, 1)) == REG) \ { \ reg1 = XEXP (addr, 1); \ addr = XEXP (addr, 0); \ } \ if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ || GET_CODE (addr) == SIGN_EXTEND) \ { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ /* for OLD_INDEXING \ else if (GET_CODE (addr) == PLUS) \ { \ if (GET_CODE (XEXP (addr, 0)) == REG) \ { \ reg2 = XEXP (addr, 0); \ addr = XEXP (addr, 1); \ } \ else if (GET_CODE (XEXP (addr, 1)) == REG) \ { \ reg2 = XEXP (addr, 1); \ addr = XEXP (addr, 0); \ } \ } \ */ \ if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ || GET_CODE (reg1) == MULT)) \ || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ { breg = reg2; ireg = reg1; } \ else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ { breg = reg1; ireg = reg2; } \ if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ { int scale = 1; \ if (GET_CODE (ireg) == MULT) \ { scale = INTVAL (XEXP (ireg, 1)); \ ireg = XEXP (ireg, 0); } \ if (GET_CODE (ireg) == SIGN_EXTEND) \ fprintf (FILE, "pc@(L%d:w,%s:w", \ CODE_LABEL_NUMBER (XEXP (addr, 0)), \ reg_names[REGNO (XEXP (ireg, 0))]); \ else \ fprintf (FILE, "pc@(L%d:w,%s:l", \ CODE_LABEL_NUMBER (XEXP (addr, 0)), \ reg_names[REGNO (ireg)]); \ if (scale != 1) fprintf (FILE, "*%d", scale); \ putc (')', FILE); \ break; } \ if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ { fprintf (FILE, "pc@(L%d:w,%s:l", \ CODE_LABEL_NUMBER (XEXP (addr, 0)), \ reg_names[REGNO (breg)]); \ putc (')', FILE); \ break; } \ if (ireg != 0 || breg != 0) \ { int scale = 1; \ if (breg == 0) \ abort (); \ if (addr && GET_CODE (addr) == LABEL_REF) abort (); \ fprintf (FILE, "%s@(", reg_names[REGNO (breg)]); \ if (addr != 0) \ output_addr_const (FILE, addr); \ else \ putc ('0', FILE); \ if (ireg != 0) \ putc (',', FILE); \ if (ireg != 0 && GET_CODE (ireg) == MULT) \ { scale = INTVAL (XEXP (ireg, 1)); \ ireg = XEXP (ireg, 0); } \ if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ fprintf (FILE, "%s:w", reg_names[REGNO (XEXP (ireg, 0))]); \ else if (ireg != 0) \ fprintf (FILE, "%s:l", reg_names[REGNO (ireg)]); \ if (scale != 1) fprintf (FILE, "*%d", scale); \ putc (')', FILE); \ break; \ } \ else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ { fprintf (FILE, "pc@(L%d:w,%s:l)", \ CODE_LABEL_NUMBER (XEXP (addr, 0)), \ reg_names[REGNO (reg1)]); \ break; } \ default: \ if (GET_CODE (addr) == CONST_INT \ && INTVAL (addr) < 0x8000 \ && INTVAL (addr) >= -0x8000) \ fprintf (FILE, "%d:w", INTVAL (addr)); \ else \ output_addr_const (FILE, addr); \ }} #endif /* USE_GAS */