summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu/nios2/nios2-mpu-descriptor.c
blob: 2c5231340f12c4dc8c5cae407f236ea4a12823f9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
 * Copyright (c) 2011 embedded brains GmbH.  All rights reserved.
 *
 *  embedded brains GmbH
 *  Obere Lagerstr. 30
 *  82178 Puchheim
 *  Germany
 *  <rtems@embedded-brains.de>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.com/license/LICENSE.
 *
 * $Id$
 */

#ifdef HAVE_CONFIG_H
  #include "config.h"
#endif

#include <rtems/score/nios2-utility.h>

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;
}