blob: e53f9ee04b19a83d1d77fd6ef8acc54b0f12a188 [file] [log] [blame]
/* ------------------------------------------
* 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_ */