/* * cache handling * * This file is part of BaS_gcc. * * BaS_gcc 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. * * BaS_gcc 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 BaS_gcc. If not, see . * * Copyright 2010 - 2012 F. Aschwanden * Copyright 2011 - 2012 V. Riviere * Copyright 2012 M. Froeschle * */ #include "cache.h" void cacr_set(uint32_t value) { extern uint32_t rt_cacr[]; rt_cacr[0] = value; __asm__ __volatile__("movec %0, cacr\n\t" : /* output */ : "r" (rt_cacr[0]) : /* clobbers */); } uint32_t cacr_get(void) { extern uint32_t rt_cacr[]; return rt_cacr[0]; } void flush_and_invalidate_caches(void) { __asm__ ( " clr.l d0\n\t" " clr.l d1\n\t" " move.l d0,a0\n\t" "cfa_setloop:\n\t" " cpushl bc,(a0) | flush\n\t" " lea 0x10(a0),a0 | index+1\n\t" " addq.l #1,d1 | index+1\n\t" " cmpi.w #512,d1 | all sets?\n\t" " bne.s cfa_setloop | no->\n\t" " clr.l d1\n\t" " addq.l #1,d0\n\t" " move.l d0,a0\n\t" " cmpi.w #4,d0 | all ways?\n\t" " bne.s cfa_setloop | no->\n\t" /* input */ : /* output */ : /* clobber */ : "d0", "d1", "a0" ); } /* * flush and invalidate a specific memory region from the instruction cache */ void flush_icache_range(void *address, size_t size) { uint32_t set; uint32_t start_set; uint32_t end_set; void *endaddr = address + size; start_set = (uint32_t) address & _ICACHE_SET_MASK; end_set = (uint32_t) endaddr & _ICACHE_SET_MASK; if (start_set > end_set) { /* from the begining to the lowest address */ for (set = 0; set <= end_set; set += (0x10 - 3)) { asm volatile("cpushl ic,(%0)\n\t" "addq.l #1,%0\n\t" "cpushl ic,(%0)\n\t" "addq.l #1,%0\n\t" "cpushl ic,(%0)\n\t" "addq.l #1,%0\n\t" "cpushl ic,(%0)" : "=a" (set) : "a" (set)); } /* next loop will finish the cache ie pass the hole */ end_set = LAST_ICACHE_ADDR; } for (set = start_set; set <= end_set; set += (0x10 - 3)) { asm volatile("cpushl ic,(%0)\n\t" "addq.l #1,%0\n\t" "cpushl ic,(%0)\n\t" "addq%.l #1,%0\n\t" "cpushl ic,(%0)\n\t" "addq.l #1,%0\n\t" "cpushl ic,(%0)" : "=a" (set) : "a" (set)); } } /* * flush and invalidate a specific region from the data cache */ void flush_dcache_range(void *address, size_t size) { unsigned long set; unsigned long start_set; unsigned long end_set; void *endaddr; endaddr = address + size; start_set = (uint32_t) address & _DCACHE_SET_MASK; end_set = (uint32_t) endaddr & _DCACHE_SET_MASK; if (start_set > end_set) { /* from the begining to the lowest address */ for (set = 0; set <= end_set; set += (0x10 - 3)) { asm volatile("cpushl dc,(%0)\n\t" "addq.l #1,%0\n\t" "cpushl dc,(%0)\n\t" "addq.l #1,%0\n\t" "cpushl dc,(%0)\n\t" "addq.l #1,%0\n\t" "cpushl dc,(%0)" : "=a" (set) : "a" (set)); } /* next loop will finish the cache ie pass the hole */ end_set = LAST_DCACHE_ADDR; } for (set = start_set; set <= end_set; set += (0x10 - 3)) { asm volatile("cpushl dc,(%0)\n\t" "addq.l #1,%0\n\t" "cpushl dc,(%0)\n\t" "addq%.l #1,%0\n\t" "cpushl dc,(%0)\n\t" "addq.l #1,%0\n\t" "cpushl dc,(%0)" : "=a" (set) : "a" (set)); } }