/** * @file * * @brief NIOS2 MPU Descriptor */ /* * Copyright (c) 2011 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Obere Lagerstr. 30 * 82178 Puchheim * Germany * * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include static bool _Nios2_Is_power_of_two( uint32_t size ) { bool ok = false; int i = 0; for ( i = 0; !ok && i < 32; ++i ) { ok = size == (1U << i); } return ok; } static bool _Nios2_Is_valid_base_and_end( const Nios2_MPU_Configuration *config, bool data, uint32_t base, uint32_t end, uint32_t *mask_or_limit ) { uint32_t size = end - base; uint32_t end_limit = data ? (1U << config->data_address_width) : (1U << config->instruction_address_width); uint32_t mask = data ? ((1U << config->data_region_size_log2)) - 1 : ((1U << config->instruction_region_size_log2)) - 1; bool ok = base < end && end <= end_limit && (base & mask) == 0 && (end & mask) == 0; if ( config->region_uses_limit ) { *mask_or_limit = end; } else { ok = ok && _Nios2_Is_power_of_two( size ); *mask_or_limit = (~(size - 1)) & NIOS2_MPUACC_MASK_MASK; } return ok; } static bool _Nios2_Is_valid_permission( bool data, int perm ) { int max = data ? 6 : 2; return 0 <= perm && perm <= max && (!data || (data && perm != 3)); } bool _Nios2_MPU_Setup_region_registers( const Nios2_MPU_Configuration *config, const Nios2_MPU_Region_descriptor *desc, uint32_t *mpubase, uint32_t *mpuacc ) { uint32_t base = (uint32_t) desc->base; uint32_t end = (uint32_t) desc->end; uint32_t mask_or_limit = 0; bool is_valid_base_and_end = _Nios2_Is_valid_base_and_end( config, desc->data, base, end, &mask_or_limit ); bool ok = is_valid_base_and_end && _Nios2_MPU_Is_valid_index( config, desc->index, desc->data ) && _Nios2_Is_valid_permission( desc->data, desc->perm ) && !(!desc->data && desc->cacheable) && !(desc->read && desc->write); if ( ok ) { *mpubase = (base & NIOS2_MPUBASE_BASE_MASK) | ((desc->index << NIOS2_MPUBASE_INDEX_OFFSET) & NIOS2_MPUBASE_INDEX_MASK) | (desc->data ? NIOS2_MPUBASE_D : 0); *mpuacc = mask_or_limit | (desc->cacheable ? NIOS2_MPUACC_C : 0) | ((desc->perm << NIOS2_MPUACC_PERM_OFFSET) & NIOS2_MPUACC_PERM_MASK) | (desc->read ? NIOS2_MPUACC_RD : 0) | (desc->write ? NIOS2_MPUACC_WR : 0); } return ok; } bool _Nios2_MPU_Get_region_descriptor( const Nios2_MPU_Configuration *config, int index, bool data, Nios2_MPU_Region_descriptor *desc ) { bool ok = _Nios2_MPU_Is_valid_index( config, index, data ); if ( ok ) { uint32_t mpubase; uint32_t mpuacc; _Nios2_MPU_Get_region_registers( index, data, &mpubase, &mpuacc ); desc->index = index; desc->base = (void *) (mpubase & NIOS2_MPUBASE_BASE_MASK); if ( config->region_uses_limit ) { desc->end = (void *) (mpuacc & NIOS2_MPUACC_LIMIT_MASK); } else { desc->end = (void *) ((mpuacc & NIOS2_MPUACC_MASK_MASK) + 1); } desc->perm = (mpuacc & NIOS2_MPUACC_PERM_MASK) >> NIOS2_MPUACC_PERM_OFFSET; desc->data = data; desc->cacheable = (mpuacc & NIOS2_MPUACC_C) != 0; desc->read = (mpuacc & NIOS2_MPUACC_RD) != 0; desc->write = (mpuacc & NIOS2_MPUACC_WR) != 0; } return ok; }