| /* ------------------------------------------ |
| * Copyright (c) 2016, Synopsys, Inc. All rights reserved. |
| |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| |
| * 1) Redistributions of source code must retain the above copyright notice, this |
| * list of conditions and the following disclaimer. |
| |
| * 2) Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation and/or |
| * other materials provided with the distribution. |
| |
| * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may |
| * be used to endorse or promote products derived from this software without |
| * specific prior written permission. |
| |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * \version 2016.05 |
| * \date 2014-07-15 |
| * \author Wayne Ren(Wei.Ren@synopsys.com) |
| --------------------------------------------- */ |
| |
| /** |
| * \file |
| * \ingroup ARC_HAL_MISC_CACHE |
| * \brief header file of cache module |
| */ |
| |
| #ifndef _ARC_HAL_CACHE_H_ |
| #define _ARC_HAL_CACHE_H_ |
| |
| #include "inc/embARC_toolchain.h" |
| #include "inc/arc/arc.h" |
| #include "inc/arc/arc_builtin.h" |
| #include "inc/arc/arc_exception.h" |
| |
| /** |
| * \name instruction cache control register related definition |
| * \todo this definitions will be reviewed. |
| * @{ |
| */ |
| #define IC_CTRL_IC_ENABLE 0x0 /*!< enable instruction cache */ |
| #define IC_CTRL_IC_DISABLE 0x1 /*!< disable instruction cache */ |
| #define IC_CTRL_DIRECT_ACCESS 0x0 /*!< direct access mode */ |
| #define IC_CTRL_INDIRECT_ACCESS 0x20 /*!< indirect access mode */ |
| #define IC_CTRL_OP_SUCCEEDED 0x8 /*!< instruction cache operation succeeded */ |
| /** @} */ |
| |
| /** |
| * \name data cache control register related definition |
| * \todo this definition will be reviewed. |
| * @{ |
| */ |
| #define IC_CTRL_I |
| #define DC_CTRL_DC_ENABLE 0x0 /*!< enable data cache */ |
| #define DC_CTRL_DC_DISABLE 0x1 /*!< disable data cache */ |
| #define DC_CTRL_INVALID_ONLY 0x0 /*!< invalid data cache only */ |
| #define DC_CTRL_INVALID_FLUSH 0x40 /*!< invalid and flush data cache */ |
| #define DC_CTRL_ENABLE_FLUSH_LOCKED 0x80 /*!< the locked data cache can be flushed */ |
| #define DC_CTRL_DISABLE_FLUSH_LOCKED 0x0 /*!< the locked data cache cannot be flushed */ |
| #define DC_CTRL_FLUSH_STATUS 0x100 /*!< flush status */ |
| #define DC_CTRL_DIRECT_ACCESS 0x0 /*!< direct access mode */ |
| #define DC_CTRL_INDIRECT_ACCESS 0x20 /*!< indirect access mode */ |
| #define DC_CTRL_OP_SUCCEEDED 0x4 /*!< data cache operation succeeded */ |
| /** @} */ |
| |
| /** |
| * \name instruction cache related inline function |
| * @{ |
| */ |
| |
| /** |
| * \brief check whether instruction cache is available, |
| * 0 for not available, >0 for available |
| */ |
| Inline uint8_t icache_available(void) |
| { |
| return (_arc_aux_read(AUX_BCR_I_CACHE) & 0xF); |
| } |
| |
| /** |
| * \brief enable instruction cache |
| * \param[in] icache_en_mask operation mask |
| */ |
| Inline void icache_enable(uint32_t icache_en_mask) |
| { |
| if (!icache_available()) return; |
| _arc_aux_write(AUX_IC_CTRL, icache_en_mask); |
| } |
| |
| /** |
| * \brief disable instruction cache |
| */ |
| Inline void icache_disable(void) |
| { |
| if (!icache_available()) return; |
| _arc_aux_write(AUX_IC_CTRL, IC_CTRL_IC_DISABLE); |
| } |
| |
| /** |
| * \brief invalidate the entire instruction cache |
| */ |
| Inline void icache_invalidate(void) |
| { |
| if (!icache_available()) return; |
| /* invalidate the entire icache */ |
| _arc_aux_write(AUX_IC_IVIC, 0); |
| Asm("nop_s"); |
| Asm("nop_s"); |
| Asm("nop_s"); |
| } |
| |
| /** |
| * \brief invalidate specific cache line |
| * \param[in] address memory address |
| */ |
| Inline void icache_invalidate_line(uint32_t address) |
| { |
| if (!icache_available()) return; |
| _arc_aux_write(AUX_IC_IVIL, address); |
| /* the 3 nops are required by ARCv2 ISA */ |
| Asm("nop_s"); |
| Asm("nop_s"); |
| Asm("nop_s"); |
| } |
| |
| /** |
| * \brief lock specific cache line |
| * \param[in] address memory address |
| * \return 0, succeeded, -1, failed |
| */ |
| Inline int32_t icache_lock_line(uint32_t address) |
| { |
| if (!icache_available()) return -1; |
| _arc_aux_write(AUX_IC_LIL, address); |
| if(_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_OP_SUCCEEDED) { |
| return 0; |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * \brief set icache access mode |
| * \param[in] mode, access mode, 1: indirect access 0:direct access |
| */ |
| Inline void icache_access_mode(uint32_t mode) |
| { |
| if (!icache_available()) return; |
| if (mode) { |
| _arc_aux_write(AUX_IC_CTRL, _arc_aux_read(AUX_IC_CTRL) | IC_CTRL_INDIRECT_ACCESS); |
| } else { |
| _arc_aux_write(AUX_IC_CTRL, _arc_aux_read(AUX_IC_CTRL) & (~IC_CTRL_INDIRECT_ACCESS)); |
| } |
| } |
| |
| |
| /** @} */ |
| |
| /** |
| * \name data cache related inline functions |
| * @{ |
| */ |
| |
| /** |
| * \brief check whether data cache is available, |
| * 0 for not available, >0 for available |
| */ |
| Inline uint8_t dcache_available(void) |
| { |
| return (_arc_aux_read(AUX_BCR_D_CACHE) & 0xF); |
| } |
| |
| /** |
| * \brief invalidate the entire data cache |
| */ |
| Inline void dcache_invalidate(void) |
| { |
| if (!dcache_available()) return; |
| uint32_t status; |
| |
| status = cpu_lock_save(); |
| _arc_aux_write(AUX_DC_IVDC, 1); |
| /* wait for flush completion */ |
| while (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS); |
| cpu_unlock_restore(status); |
| } |
| |
| /** |
| * \brief invalidate the specific cache line |
| * \param[in] address memory address |
| */ |
| Inline void dcache_invalidate_line(uint32_t address) |
| { |
| if (!dcache_available()) return; |
| _arc_aux_write(AUX_DC_IVDL, address); |
| Asm("nop_s"); |
| Asm("nop_s"); |
| Asm("nop_s"); |
| } |
| |
| /** |
| * \brief enable data cache |
| * \param[in] dcache_en_mask operation mask |
| */ |
| Inline void dcache_enable(uint32_t dcache_en_mask) |
| { |
| if (!dcache_available()) return; |
| _arc_aux_write(AUX_DC_CTRL, dcache_en_mask); |
| } |
| |
| /** |
| * \brief disable data cache |
| */ |
| Inline void dcache_disable(void) |
| { |
| if (!dcache_available()) return; |
| _arc_aux_write(AUX_DC_CTRL, DC_CTRL_DC_DISABLE); |
| } |
| |
| /** |
| * \brief flush data cache |
| */ |
| Inline void dcache_flush(void) |
| { |
| if (!dcache_available()) return; |
| uint32_t status; |
| |
| status = cpu_lock_save(); |
| _arc_aux_write(AUX_DC_FLSH, 1); |
| /* wait for flush completion */ |
| while (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS); |
| cpu_unlock_restore(status); |
| } |
| |
| /** |
| * \brief flush the specific data cache line |
| * \param[in] address memory address |
| */ |
| Inline void dcache_flush_line(uint32_t address) |
| { |
| if (!dcache_available()) return; |
| |
| uint32_t status; |
| |
| status = cpu_lock_save(); |
| _arc_aux_write(AUX_DC_FLDL, address); |
| while (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS); |
| cpu_unlock_restore(status); |
| } |
| |
| /** |
| * \brief lock the specific data cache line |
| * \param[in] address memory address |
| * \return 0, succeeded, -1, failed |
| */ |
| Inline int dcache_lock_line(uint32_t address) |
| { |
| if (!dcache_available()) return -1; |
| _arc_aux_write(AUX_DC_LDL, address); |
| if(_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_OP_SUCCEEDED) { |
| return 0; |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * \brief set dcache access mode |
| * \param[in] mode, access mode, 1: indirect access 0:direct access |
| */ |
| Inline void dcache_access_mode(uint32_t mode) |
| { |
| if (!dcache_available()) return; |
| if (mode) { |
| _arc_aux_write(AUX_DC_CTRL, _arc_aux_read(AUX_DC_CTRL) | DC_CTRL_INDIRECT_ACCESS); |
| } else { |
| _arc_aux_write(AUX_DC_CTRL, _arc_aux_read(AUX_DC_CTRL) & (~DC_CTRL_INDIRECT_ACCESS)); |
| } |
| } |
| |
| /** @} */ |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * \name declarations of cache related functions |
| * @{ |
| */ |
| extern int32_t icache_invalidate_mlines(uint32_t start_addr, uint32_t size); |
| extern int32_t icache_lock_mlines(uint32_t start_addr, uint32_t size); |
| extern int32_t icache_direct_write(uint32_t cache_addr, uint32_t tag, uint32_t data); |
| extern int32_t icache_direct_read(uint32_t cache_addr, uint32_t *tag, uint32_t *data); |
| extern int32_t icache_indirect_read(uint32_t mem_addr, uint32_t *tag, uint32_t *data); |
| extern int32_t dcache_invalidate_mlines(uint32_t start_addr, uint32_t size); |
| extern int32_t dcache_flush_mlines(uint32_t start_addr, uint32_t size); |
| extern int32_t dcache_lock_mlines(uint32_t start_addr, uint32_t size); |
| extern int32_t dcache_direct_write(uint32_t cache_addr, uint32_t tag, uint32_t data); |
| extern int32_t dcache_direct_read(uint32_t cache_addr, uint32_t *tag, uint32_t *data); |
| extern int32_t dcache_indirect_read(uint32_t mem_addr, uint32_t *tag, uint32_t *data); |
| extern void arc_cache_init(void); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| /** @} */ |
| #endif /* _ARC_HAL_CACHE_H_ */ |