diff options
Diffstat (limited to 'libgcc/config/mep/tramp.c')
-rw-r--r-- | libgcc/config/mep/tramp.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/libgcc/config/mep/tramp.c b/libgcc/config/mep/tramp.c new file mode 100644 index 00000000000..bf484ca4e95 --- /dev/null +++ b/libgcc/config/mep/tramp.c @@ -0,0 +1,103 @@ +/* Trampoline support for MeP + Copyright (C) 2004, 2007 Free Software Foundation, Inc. + Contributed by Red Hat Inc. + +This file 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 3 of the License, or (at your +option) any later version. + +This file 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* + 7a0a ldc $10,$pc + c0ae000a lw $0,10($10) + caae000e lw $10,14($10) + 10ae jmp $10 + 00000000 static chain + 00000000 function address +*/ + +static inline int +cache_config_register(void) { + int rv; + asm ("ldc\t%0, $ccfg" : "=r" (rv)); + return rv; +} + +#define ICACHE_SIZE ((cache_config_register() >> 16) & 0x7f) +#define DCACHE_SIZE (cache_config_register() & 0x7f) + +#define ICACHE_DATA_BASE 0x00300000 +#define ICACHE_TAG_BASE 0x00310000 +#define DCACHE_DATA_BASE 0x00320000 +#define DCACHE_TAG_BASE 0x00330000 + +static inline void +flush_dcache (int addr) +{ + asm volatile ("cache\t0, (%0)" : : "r" (addr)); +} + +void +__mep_trampoline_helper (unsigned long *tramp, + int function_address, + int static_chain); + +void +__mep_trampoline_helper (unsigned long *tramp, + int function_address, + int static_chain) +{ + int dsize, isize; + +#ifdef __LITTLE_ENDIAN__ + tramp[0] = 0xc0ae7a0a; + tramp[1] = 0xcaae000a; + tramp[2] = 0x10ae000e; +#else + tramp[0] = 0x7a0ac0ae; + tramp[1] = 0x000acaae; + tramp[2] = 0x000e10ae; +#endif + tramp[3] = static_chain; + tramp[4] = function_address; + + dsize = DCACHE_SIZE; + isize = ICACHE_SIZE; + + if (dsize) + { + flush_dcache ((int)tramp); + flush_dcache ((int)tramp+16); + } + + if (isize) + { + int imask = (isize * 1024) - 1; + int tmask = ~imask; + unsigned int i; + volatile unsigned int *tags; + + imask &= 0xffe0; + + for (i=(unsigned int)tramp; i<(unsigned int)tramp+20; i+=16) + { + tags = (unsigned int *)(ICACHE_TAG_BASE + (i & imask)); + if ((*tags & tmask) == (i & tmask)) + *tags &= ~1; + } + } +} |