summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu/nios2/rtems/score/nios2-utility.h
blob: b99dd02cd226ebd3bdc34251e770f73ce72280b5 (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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
/*
 * 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.
 */

#ifndef _RTEMS_SCORE_NIOS2_UTILITY_H
#define _RTEMS_SCORE_NIOS2_UTILITY_H

#define NIOS2_CTLREG_INDEX_STATUS 0
#define NIOS2_CTLREG_INDEX_ESTATUS 1
#define NIOS2_CTLREG_INDEX_BSTATUS 2
#define NIOS2_CTLREG_INDEX_IENABLE 3
#define NIOS2_CTLREG_INDEX_IPENDING 4
#define NIOS2_CTLREG_INDEX_CPUID 5
#define NIOS2_CTLREG_INDEX_EXCEPTION 7
#define NIOS2_CTLREG_INDEX_PTEADDR 8
#define NIOS2_CTLREG_INDEX_TLBACC 9
#define NIOS2_CTLREG_INDEX_TLBMISC 10
#define NIOS2_CTLREG_INDEX_BADADDR 12
#define NIOS2_CTLREG_INDEX_CONFIG 13
#define NIOS2_CTLREG_INDEX_MPUBASE 14
#define NIOS2_CTLREG_INDEX_MPUACC 15

#define NIOS2_CONTEXT_OFFSET_R16 0
#define NIOS2_CONTEXT_OFFSET_R17 4
#define NIOS2_CONTEXT_OFFSET_R18 8
#define NIOS2_CONTEXT_OFFSET_R19 12
#define NIOS2_CONTEXT_OFFSET_R20 16
#define NIOS2_CONTEXT_OFFSET_R21 20
#define NIOS2_CONTEXT_OFFSET_R22 24
#define NIOS2_CONTEXT_OFFSET_R23 28
#define NIOS2_CONTEXT_OFFSET_FP 32
#define NIOS2_CONTEXT_OFFSET_STATUS 36
#define NIOS2_CONTEXT_OFFSET_SP 40
#define NIOS2_CONTEXT_OFFSET_RA 44
#define NIOS2_CONTEXT_OFFSET_THREAD_DISPATCH_DISABLED 48
#define NIOS2_CONTEXT_OFFSET_STACK_MPUBASE 52
#define NIOS2_CONTEXT_OFFSET_STACK_MPUACC 56

#define NIOS2_ISR_STATUS_MASK_IIC 0xfffffffe
#define NIOS2_ISR_STATUS_BITS_IIC 0x00000000

#define NIOS2_ISR_STATUS_MASK_EIC_IL 0xfffffc0f
#define NIOS2_ISR_STATUS_BITS_EIC_IL 0x000003f0

#define NIOS2_ISR_STATUS_MASK_EIC_RSIE 0xf7ffffff
#define NIOS2_ISR_STATUS_BITS_EIC_RSIE 0x00000000

#define NIOS2_STATUS_RSIE (1 << 23)
#define NIOS2_STATUS_NMI (1 << 22)
#define NIOS2_STATUS_PRS_OFFSET 16
#define NIOS2_STATUS_PRS_MASK (0x3f << NIOS2_STATUS_PRS_OFFSET)
#define NIOS2_STATUS_CRS_OFFSET 10
#define NIOS2_STATUS_CRS_MASK (0x3f << NIOS2_STATUS_CRS_OFFSET)
#define NIOS2_STATUS_IL_OFFSET 4
#define NIOS2_STATUS_IL_MASK (0x3f << NIOS2_STATUS_IL_OFFSET)
#define NIOS2_STATUS_IH (1 << 3)
#define NIOS2_STATUS_EH (1 << 2)
#define NIOS2_STATUS_U (1 << 1)
#define NIOS2_STATUS_PIE (1 << 0)

#define NIOS2_EXCEPTION_CAUSE_OFFSET 2
#define NIOS2_EXCEPTION_CAUSE_MASK (0x1f << NIOS2_EXCEPTION_CAUSE_OFFSET)

#define NIOS2_PTEADDR_PTBASE_OFFSET 22
#define NIOS2_PTEADDR_PTBASE_MASK (0x3ff << NIOS2_PTEADDR_PTBASE_OFFSET)
#define NIOS2_PTEADDR_VPN_OFFSET 2
#define NIOS2_PTEADDR_VPN_MASK (0xfffff << NIOS2_PTEADDR_VPN_OFFSET)

#define NIOS2_TLBACC_IG_OFFSET 25
#define NIOS2_TLBACC_IG_MASK (0x3ff << NIOS2_TLBACC_IG_OFFSET)
#define NIOS2_TLBACC_C (1 << 24)
#define NIOS2_TLBACC_R (1 << 23)
#define NIOS2_TLBACC_W (1 << 22)
#define NIOS2_TLBACC_X (1 << 21)
#define NIOS2_TLBACC_G (1 << 20)
#define NIOS2_TLBACC_PFN_OFFSET 2
#define NIOS2_TLBACC_PFN_MASK (0xfffff << NIOS2_TLBACC_PFN_OFFSET)

#define NIOS2_TLBMISC_WAY_OFFSET 20
#define NIOS2_TLBMISC_WAY_MASK (0xf << NIOS2_TLBMISC_WAY_OFFSET)
#define NIOS2_TLBMISC_RD (1 << 19)
#define NIOS2_TLBMISC_WE (1 << 18)
#define NIOS2_TLBMISC_PID_OFFSET 5
#define NIOS2_TLBMISC_PID_MASK (0x3fff << NIOS2_TLBMISC_PID_OFFSET)
#define NIOS2_TLBMISC_DBL (1 << 3)
#define NIOS2_TLBMISC_BAD (1 << 2)
#define NIOS2_TLBMISC_PERM (1 << 1)
#define NIOS2_TLBMISC_D (1 << 0)

#define NIOS2_CONFIG_ANI (1 << 1)
#define NIOS2_CONFIG_PE (1 << 0)

#define NIOS2_MPUBASE_BASE_OFFSET 6
#define NIOS2_MPUBASE_BASE_MASK (0x1ffffff << NIOS2_MPUBASE_BASE_OFFSET)
#define NIOS2_MPUBASE_INDEX_OFFSET 1

/* Avoid redefines with Altera HAL */
#define NIOS2_MPUBASE_INDEX_MASK (0x0000003e)

#define NIOS2_MPUBASE_D (1 << 0)

#define NIOS2_MPUACC_MASK_OFFSET 6

/* Avoid redefines with Altera HAL */
#define NIOS2_MPUACC_MASK_MASK (0x7fffffc0)

#define NIOS2_MPUACC_LIMIT_OFFSET 6

/* Avoid redefines with Altera HAL */
#define NIOS2_MPUACC_LIMIT_MASK (0xffffffc0)

#define NIOS2_MPUACC_C (1 << 5)
#define NIOS2_MPUACC_PERM_OFFSET 2

/* Avoid redefines with Altera HAL */
#define NIOS2_MPUACC_PERM_MASK (0x0000001c)

#define NIOS2_MPUACC_RD (1 << 1)
#define NIOS2_MPUACC_WR (1 << 0)

#ifndef ASM

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/**
 * @brief Nios II specific thread dispatch disabled indicator.
 *
 * This global variable is used by the interrupt dispatch support for the
 * external interrupt controller (EIC) with shadow registers.  This makes it
 * possible to do the thread dispatch after an interrupt without disabled
 * interrupts and thus probably reduce the maximum interrupt latency.  Its
 * purpose is to prevent unbounded stack usage of the interrupted thread.
 */
extern uint32_t _Nios2_Thread_dispatch_disabled;

/**
 * @brief This global symbol specifies the status register mask used to disable
 * interrupts.
 *
 * The board support package must provide a global symbol with this name to
 * specifiy the status register mask used in _CPU_ISR_Disable().
 */
extern char _Nios2_ISR_Status_mask [];

/**
 * @brief This symbol specifies the status register bits used to disable
 * interrupts.
 *
 * The board support package must provide a global symbol with this name to
 * specifiy the status register bits used in _CPU_ISR_Disable().
 */
extern char _Nios2_ISR_Status_bits [];

static inline void _Nios2_Flush_pipeline( void )
{
  __asm__ volatile ("flushp");
}

static inline uint32_t _Nios2_Get_ctlreg_status( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_STATUS );
}

static inline void _Nios2_Set_ctlreg_status( uint32_t value )
{
  __builtin_wrctl( NIOS2_CTLREG_INDEX_STATUS, (int) value );
}

static inline uint32_t _Nios2_Get_ctlreg_estatus( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_ESTATUS );
}

static inline void _Nios2_Set_ctlreg_estatus( uint32_t value )
{
  __builtin_wrctl( NIOS2_CTLREG_INDEX_ESTATUS, (int) value );
}

static inline uint32_t _Nios2_Get_ctlreg_bstatus( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_BSTATUS );
}

static inline void _Nios2_Set_ctlreg_bstatus( uint32_t value )
{
  __builtin_wrctl( NIOS2_CTLREG_INDEX_BSTATUS, (int) value );
}

static inline uint32_t _Nios2_Get_ctlreg_ienable( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_IENABLE );
}

static inline void _Nios2_Set_ctlreg_ienable( uint32_t value )
{
  __builtin_wrctl( NIOS2_CTLREG_INDEX_IENABLE, (int) value );
}

static inline uint32_t _Nios2_Get_ctlreg_ipending( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_IPENDING );
}

static inline uint32_t _Nios2_Get_ctlreg_cpuid( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_CPUID );
}

static inline uint32_t _Nios2_Get_ctlreg_exception( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_EXCEPTION );
}

static inline uint32_t _Nios2_Get_ctlreg_pteaddr( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_PTEADDR );
}

static inline void _Nios2_Set_ctlreg_pteaddr( uint32_t value )
{
  __builtin_wrctl( NIOS2_CTLREG_INDEX_PTEADDR, (int) value );
}

static inline uint32_t _Nios2_Get_ctlreg_tlbacc( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_TLBACC );
}

static inline void _Nios2_Set_ctlreg_tlbacc( uint32_t value )
{
  __builtin_wrctl( NIOS2_CTLREG_INDEX_TLBACC, (int) value );
}

static inline uint32_t _Nios2_Get_ctlreg_tlbmisc( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_TLBMISC );
}

static inline void _Nios2_Set_ctlreg_tlbmisc( uint32_t value )
{
  __builtin_wrctl( NIOS2_CTLREG_INDEX_TLBMISC, (int) value );
}

static inline uint32_t _Nios2_Get_ctlreg_badaddr( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_BADADDR );
}

static inline uint32_t _Nios2_Get_ctlreg_config( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_CONFIG );
}

static inline void _Nios2_Set_ctlreg_config( uint32_t value )
{
  __builtin_wrctl( NIOS2_CTLREG_INDEX_CONFIG, (int) value );
}

static inline uint32_t _Nios2_Get_ctlreg_mpubase( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_MPUBASE );
}

static inline void _Nios2_Set_ctlreg_mpubase( uint32_t value )
{
  __builtin_wrctl( NIOS2_CTLREG_INDEX_MPUBASE, (int) value );
}

static inline uint32_t _Nios2_Get_ctlreg_mpuacc( void )
{
  return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_MPUACC );
}

static inline void _Nios2_Set_ctlreg_mpuacc( uint32_t value )
{
  __builtin_wrctl( NIOS2_CTLREG_INDEX_MPUACC, (int) value );
}

static inline uint32_t _Nios2_ISR_Get_status_mask( void )
{
  return (uint32_t) &_Nios2_ISR_Status_mask [0];
}

static inline uint32_t _Nios2_ISR_Get_status_bits( void )
{
  return (uint32_t) &_Nios2_ISR_Status_bits [0];
}

static inline bool _Nios2_Has_internal_interrupt_controller( void )
{
  return _Nios2_ISR_Get_status_mask() == NIOS2_ISR_STATUS_MASK_IIC;
}

/*
 *  @brief Nios2 ISR Set level
 *
 */
uint32_t _Nios2_ISR_Set_level( uint32_t new_level, uint32_t status );

typedef struct {
  int data_address_width;
  int instruction_address_width;
  int data_region_size_log2;
  int instruction_region_size_log2;
  int data_region_count;
  int instruction_region_count;
  int data_index_for_stack_protection;
  bool region_uses_limit;
  bool enable_data_cache_for_stack;
} Nios2_MPU_Configuration;

void _Nios2_MPU_Set_configuration( const Nios2_MPU_Configuration *config );

const Nios2_MPU_Configuration *_Nios2_MPU_Get_configuration( void );

typedef enum {
  NIOS2_MPU_INST_PERM_SVR_NONE_USER_NONE = 0,
  NIOS2_MPU_INST_PERM_SVR_EXECUTE_USER_NONE,
  NIOS2_MPU_INST_PERM_SVR_EXECUTE_USER_EXECUTE,
  NIOS2_MPU_DATA_PERM_SVR_NONE_USER_NONE = 0,
  NIOS2_MPU_DATA_PERM_SVR_READONLY_USER_NONE,
  NIOS2_MPU_DATA_PERM_SVR_READONLY_USER_READONLY,
  NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_NONE = 4,
  NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_READONLY,
  NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_READWRITE
} Nios2_MPU_Region_permissions;

typedef struct {
  int index;
  const void *base;
  const void *end;
  Nios2_MPU_Region_permissions perm;
  bool data;
  bool cacheable;
  bool read;
  bool write;
} Nios2_MPU_Region_descriptor;

#define NIOS2_MPU_REGION_DESC_INST( index, base, end ) \
  { \
    (index), (base), (end), NIOS2_MPU_INST_PERM_SVR_EXECUTE_USER_NONE, \
    false, false, false, true \
  }

#define NIOS2_MPU_REGION_DESC_DATA_RO( index, base, end ) \
  { \
    (index), (base), (end), NIOS2_MPU_DATA_PERM_SVR_READONLY_USER_NONE, \
    true, true, false, true \
  }

#define NIOS2_MPU_REGION_DESC_DATA_RW( index, base, end ) \
  { \
    (index), (base), (end), NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_NONE, \
    true, true, false, true \
  }

#define NIOS2_MPU_REGION_DESC_DATA_IO( index, base, end ) \
  { \
    (index), (base), (end), NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_NONE, \
    true, false, false, true \
  }

static inline int _Nios2_MPU_Get_region_count(
  const Nios2_MPU_Configuration *config,
  bool data
)
{
  return data ?
    config->data_region_count
      : config->instruction_region_count;
}

static inline bool _Nios2_MPU_Is_valid_index(
  const Nios2_MPU_Configuration *config,
  int index,
  bool data
)
{
  return 0 <= index
    && index < _Nios2_MPU_Get_region_count( config, data );
}

bool _Nios2_MPU_Setup_region_registers(
  const Nios2_MPU_Configuration *config,
  const Nios2_MPU_Region_descriptor *desc,
  uint32_t *mpubase,
  uint32_t *mpuacc
);

/**
 * @brief Nios2 MPU Get region descriptor.
 *
 */
bool _Nios2_MPU_Get_region_descriptor(
  const Nios2_MPU_Configuration *config,
  int index,
  bool data,
  Nios2_MPU_Region_descriptor *desc
);

/**
 * @brief Seaches the region table part for a disabled region.
 *
 * The table will be searched between indices @a begin and @a end.  The @a end
 * index is not part of the search range.  If @a end is negative, then the
 * region count will be used.  Thus a @a begin of 0 and a @a end of -1 will
 * specifiy the complete table.
 *
 * @retval -1 No disabled region is available.
 * @retval other Index of disabled region.
 */
int _Nios2_MPU_Get_disabled_region_index(
  const Nios2_MPU_Configuration *config,
  bool data,
  int begin,
  int end
);

/**
 * @brief Adds a region according to region descriptor @a desc.
 *
 * If @a force is true, then an enabled region will be overwritten.
 *
 * @retval true Successful operation.
 * @retval false Invalid region descriptor or region already in use.
 */
bool _Nios2_MPU_Add_region(
  const Nios2_MPU_Configuration *config,
  const Nios2_MPU_Region_descriptor *desc,
  bool force
);

static inline void _Nios2_MPU_Get_region_registers(
  int index,
  bool data,
  uint32_t *mpubase,
  uint32_t *mpuacc
)
{
  uint32_t base = (uint32_t)
    (((index << NIOS2_MPUBASE_INDEX_OFFSET) & NIOS2_MPUBASE_INDEX_MASK)
      | (data ? NIOS2_MPUBASE_D : 0));

  _Nios2_Set_ctlreg_mpubase( base );
  _Nios2_Set_ctlreg_mpuacc( NIOS2_MPUACC_RD );
  _Nios2_Flush_pipeline();
  *mpubase = _Nios2_Get_ctlreg_mpubase() | base;
  *mpuacc = _Nios2_Get_ctlreg_mpuacc();
}

static inline void _Nios2_MPU_Set_region_registers(
  uint32_t mpubase,
  uint32_t mpuacc
)
{
  _Nios2_Set_ctlreg_mpubase( mpubase );
  _Nios2_Set_ctlreg_mpuacc( mpuacc );
  _Nios2_Flush_pipeline();
}

static inline void _Nios2_MPU_Enable( void )
{
  uint32_t config = _Nios2_Get_ctlreg_config();

  _Nios2_Set_ctlreg_config( config | NIOS2_CONFIG_PE );
}

static inline uint32_t _Nios2_MPU_Disable( void )
{
  uint32_t config = _Nios2_Get_ctlreg_config();
  uint32_t config_pe = NIOS2_CONFIG_PE;

  _Nios2_Set_ctlreg_config( config & ~config_pe );

  return config;
}

static inline void _Nios2_MPU_Restore( uint32_t config )
{
  _Nios2_Set_ctlreg_config( config );
}

/*
 *  @brief Nios2 MPU Disable Protected
 *
 */
uint32_t _Nios2_MPU_Disable_protected( void );

void _Nios2_MPU_Reset( const Nios2_MPU_Configuration *config );

#ifdef __cplusplus
}
#endif /* __cplusplus */

#else /* ASM */

	.macro	NIOS2_ASM_DISABLE_INTERRUPTS new_status, current_status
	movhi	\new_status, %hiadj(_Nios2_ISR_Status_mask)
	addi	\new_status, \new_status, %lo(_Nios2_ISR_Status_mask)
	and	\new_status, \current_status, \new_status
	ori	\new_status, \new_status, %lo(_Nios2_ISR_Status_bits)
	wrctl	status, \new_status
	.endm

#endif /* ASM */

#endif /* _RTEMS_SCORE_NIOS2_UTILITY_H */