原始版本

This commit is contained in:
冯佳
2025-06-19 21:56:46 +08:00
parent fe98e5f010
commit a4841450cf
4152 changed files with 1910684 additions and 0 deletions

View File

@ -0,0 +1,23 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
if rtconfig.PLATFORM in ['armcc', 'armclang']:
src += Glob('*_rvds.S')
if rtconfig.PLATFORM in ['gcc']:
src += Glob('*_init.S')
src += Glob('*_gcc.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,54 @@
#ifndef __ARMV7_H__
#define __ARMV7_H__
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#ifndef VFP_DATA_NR
#define VFP_DATA_NR 32
#endif
/* the exception stack without VFP registers */
struct rt_hw_exp_stack
{
unsigned long r0;
unsigned long r1;
unsigned long r2;
unsigned long r3;
unsigned long r4;
unsigned long r5;
unsigned long r6;
unsigned long r7;
unsigned long r8;
unsigned long r9;
unsigned long r10;
unsigned long fp;
unsigned long ip;
unsigned long sp;
unsigned long lr;
unsigned long pc;
unsigned long cpsr;
};
#define USERMODE 0x10
#define FIQMODE 0x11
#define IRQMODE 0x12
#define SVCMODE 0x13
#define MONITORMODE 0x16
#define ABORTMODE 0x17
#define HYPMODE 0x1b
#define UNDEFMODE 0x1b
#define MODEMASK 0x1f
#define NOINT 0xc0
#define T_Bit (1<<5)
#define F_Bit (1<<6)
#define I_Bit (1<<7)
#define A_Bit (1<<8)
#define E_Bit (1<<9)
#define J_Bit (1<<24)
#endif

View File

@ -0,0 +1,449 @@
/*
* Copyright (c) 2006 - 2021, RT-Thread Development Team
* Copyright (c) 2014 - 2020 Xilinx, Inc. All rights reserved.
* Copyright (c) 2021 WangHuachen. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
* 2021-05-10 WangHuachen add more functions
*/
#include <stdint.h>
#include <rthw.h>
#include <rtdef.h>
#include "xpseudo_asm_gcc.h"
#include "xreg_cortexr5.h"
#define IRQ_FIQ_MASK 0xC0 /* Mask IRQ and FIQ interrupts in cpsr */
typedef intptr_t INTPTR;
typedef rt_uint32_t u32;
#if defined (__GNUC__)
#define asm_inval_dc_line_mva_poc(param) __asm__ __volatile__("mcr " \
XREG_CP15_INVAL_DC_LINE_MVA_POC :: "r" (param))
#define asm_clean_inval_dc_line_sw(param) __asm__ __volatile__("mcr " \
XREG_CP15_CLEAN_INVAL_DC_LINE_SW :: "r" (param))
#define asm_clean_inval_dc_line_mva_poc(param) __asm__ __volatile__("mcr " \
XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC :: "r" (param))
#define asm_inval_ic_line_mva_pou(param) __asm__ __volatile__("mcr " \
XREG_CP15_INVAL_IC_LINE_MVA_POU :: "r" (param))
#elif defined (__ICCARM__)
#define asm_inval_dc_line_mva_poc(param) __asm volatile("mcr " \
XREG_CP15_INVAL_DC_LINE_MVA_POC :: "r" (param))
#define asm_clean_inval_dc_line_sw(param) __asm volatile("mcr " \
XREG_CP15_CLEAN_INVAL_DC_LINE_SW :: "r" (param))
#define asm_clean_inval_dc_line_mva_poc(param) __asm volatile("mcr " \
XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC :: "r" (param))
#define asm_inval_ic_line_mva_pou(param) __asm volatile("mcr " \
XREG_CP15_INVAL_IC_LINE_MVA_POU :: "r" (param))
#endif
void Xil_DCacheEnable(void);
void Xil_DCacheDisable(void);
void Xil_DCacheInvalidate(void);
void Xil_DCacheInvalidateRange(INTPTR adr, u32 len);
void Xil_DCacheFlush(void);
void Xil_DCacheFlushRange(INTPTR adr, u32 len);
void Xil_DCacheInvalidateLine(INTPTR adr);
void Xil_DCacheFlushLine(INTPTR adr);
void Xil_DCacheStoreLine(INTPTR adr);
void Xil_ICacheEnable(void);
void Xil_ICacheDisable(void);
void Xil_ICacheInvalidate(void);
void Xil_ICacheInvalidateRange(INTPTR adr, u32 len);
void Xil_ICacheInvalidateLine(INTPTR adr);
void Xil_DCacheEnable(void)
{
register u32 CtrlReg;
/* enable caches only if they are disabled */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
#endif
if ((CtrlReg & XREG_CP15_CONTROL_C_BIT) == 0x00000000U)
{
/* invalidate the Data cache */
Xil_DCacheInvalidate();
/* enable the Data cache */
CtrlReg |= (XREG_CP15_CONTROL_C_BIT);
mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
}
}
void Xil_DCacheDisable(void)
{
register u32 CtrlReg;
/* clean and invalidate the Data cache */
Xil_DCacheFlush();
/* disable the Data cache */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
#endif
CtrlReg &= ~(XREG_CP15_CONTROL_C_BIT);
mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
}
void Xil_DCacheInvalidate(void)
{
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
/*invalidate all D cache*/
mtcp(XREG_CP15_INVAL_DC_ALL, 0);
mtcpsr(currmask);
}
void Xil_DCacheInvalidateLine(INTPTR adr)
{
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
mtcp(XREG_CP15_INVAL_DC_LINE_MVA_POC, (adr & (~0x1F)));
/* Wait for invalidate to complete */
dsb();
mtcpsr(currmask);
}
void Xil_DCacheInvalidateRange(INTPTR adr, u32 len)
{
const u32 cacheline = 32U;
u32 end;
u32 tempadr = adr;
u32 tempend;
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
if (len != 0U)
{
end = tempadr + len;
tempend = end;
/* Select L1 Data cache in CSSR */
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0U);
if ((tempadr & (cacheline - 1U)) != 0U)
{
tempadr &= (~(cacheline - 1U));
Xil_DCacheFlushLine(tempadr);
}
if ((tempend & (cacheline - 1U)) != 0U)
{
tempend &= (~(cacheline - 1U));
Xil_DCacheFlushLine(tempend);
}
while (tempadr < tempend)
{
/* Invalidate Data cache line */
asm_inval_dc_line_mva_poc(tempadr);
tempadr += cacheline;
}
}
dsb();
mtcpsr(currmask);
}
void Xil_DCacheFlush(void)
{
register u32 CsidReg, C7Reg;
u32 CacheSize, LineSize, NumWays;
u32 Way, WayIndex, Set, SetIndex, NumSet;
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
/* Select cache level 0 and D cache in CSSR */
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
#if defined (__GNUC__)
CsidReg = mfcp(XREG_CP15_CACHE_SIZE_ID);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_CACHE_SIZE_ID, CsidReg);
#endif
/* Determine Cache Size */
CacheSize = (CsidReg >> 13U) & 0x000001FFU;
CacheSize += 0x00000001U;
CacheSize *= (u32)128; /* to get number of bytes */
/* Number of Ways */
NumWays = (CsidReg & 0x000003ffU) >> 3U;
NumWays += 0x00000001U;
/* Get the cacheline size, way size, index size from csidr */
LineSize = (CsidReg & 0x00000007U) + 0x00000004U;
NumSet = CacheSize / NumWays;
NumSet /= (0x00000001U << LineSize);
Way = 0U;
Set = 0U;
/* Invalidate all the cachelines */
for (WayIndex = 0U; WayIndex < NumWays; WayIndex++)
{
for (SetIndex = 0U; SetIndex < NumSet; SetIndex++)
{
C7Reg = Way | Set;
/* Flush by Set/Way */
asm_clean_inval_dc_line_sw(C7Reg);
Set += (0x00000001U << LineSize);
}
Set = 0U;
Way += 0x40000000U;
}
/* Wait for flush to complete */
dsb();
mtcpsr(currmask);
mtcpsr(currmask);
}
void Xil_DCacheFlushLine(INTPTR adr)
{
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
mtcp(XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC, (adr & (~0x1F)));
/* Wait for flush to complete */
dsb();
mtcpsr(currmask);
}
void Xil_DCacheFlushRange(INTPTR adr, u32 len)
{
u32 LocalAddr = adr;
const u32 cacheline = 32U;
u32 end;
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
if (len != 0x00000000U)
{
/* Back the starting address up to the start of a cache line
* perform cache operations until adr+len
*/
end = LocalAddr + len;
LocalAddr &= ~(cacheline - 1U);
while (LocalAddr < end)
{
/* Flush Data cache line */
asm_clean_inval_dc_line_mva_poc(LocalAddr);
LocalAddr += cacheline;
}
}
dsb();
mtcpsr(currmask);
}
void Xil_DCacheStoreLine(INTPTR adr)
{
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
mtcp(XREG_CP15_CLEAN_DC_LINE_MVA_POC, (adr & (~0x1F)));
/* Wait for store to complete */
dsb();
isb();
mtcpsr(currmask);
}
void Xil_ICacheEnable(void)
{
register u32 CtrlReg;
/* enable caches only if they are disabled */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
#endif
if ((CtrlReg & XREG_CP15_CONTROL_I_BIT) == 0x00000000U)
{
/* invalidate the instruction cache */
mtcp(XREG_CP15_INVAL_IC_POU, 0);
/* enable the instruction cache */
CtrlReg |= (XREG_CP15_CONTROL_I_BIT);
mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
}
}
void Xil_ICacheDisable(void)
{
register u32 CtrlReg;
dsb();
/* invalidate the instruction cache */
mtcp(XREG_CP15_INVAL_IC_POU, 0);
/* disable the instruction cache */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
#endif
CtrlReg &= ~(XREG_CP15_CONTROL_I_BIT);
mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
}
void Xil_ICacheInvalidate(void)
{
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 1);
/* invalidate the instruction cache */
mtcp(XREG_CP15_INVAL_IC_POU, 0);
/* Wait for invalidate to complete */
dsb();
mtcpsr(currmask);
}
void Xil_ICacheInvalidateLine(INTPTR adr)
{
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 1);
mtcp(XREG_CP15_INVAL_IC_LINE_MVA_POU, (adr & (~0x1F)));
/* Wait for invalidate to complete */
dsb();
mtcpsr(currmask);
}
void Xil_ICacheInvalidateRange(INTPTR adr, u32 len)
{
u32 LocalAddr = adr;
const u32 cacheline = 32U;
u32 end;
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
if (len != 0x00000000U)
{
/* Back the starting address up to the start of a cache line
* perform cache operations until adr+len
*/
end = LocalAddr + len;
LocalAddr = LocalAddr & ~(cacheline - 1U);
/* Select cache L0 I-cache in CSSR */
mtcp(XREG_CP15_CACHE_SIZE_SEL, 1U);
while (LocalAddr < end)
{
/* Invalidate L1 I-cache line */
asm_inval_ic_line_mva_pou(LocalAddr);
LocalAddr += cacheline;
}
}
/* Wait for invalidate to complete */
dsb();
mtcpsr(currmask);
}
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_INVALIDATE)
Xil_ICacheInvalidateRange((INTPTR)addr, size);
}
void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_FLUSH)
Xil_DCacheFlushRange((intptr_t)addr, size);
else if (ops == RT_HW_CACHE_INVALIDATE)
Xil_DCacheInvalidateRange((intptr_t)addr, size);
}
rt_base_t rt_hw_cpu_icache_status(void)
{
register u32 CtrlReg;
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
#endif
return CtrlReg & XREG_CP15_CONTROL_I_BIT;
}
rt_base_t rt_hw_cpu_dcache_status(void)
{
register u32 CtrlReg;
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
#endif
return CtrlReg & XREG_CP15_CONTROL_C_BIT;
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
*/
.section .text, "ax"
/*
* rt_base_t rt_hw_interrupt_disable();
*/
.globl rt_hw_interrupt_disable
rt_hw_interrupt_disable:
mrs r0, cpsr
cpsid if
bx lr
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
.globl rt_hw_interrupt_enable
rt_hw_interrupt_enable:
msr cpsr, r0
bx lr
/*
* void rt_hw_context_switch_to(rt_uint32 to);
* r0 --> to
*/
.globl rt_hw_context_switch_to
rt_hw_context_switch_to:
ldr sp, [r0] @ get new task stack pointer
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
ldmfd sp!, {r1} /* Restore floating point registers */
vmsr FPEXC, r1
ldmfd sp!, {r1}
vmsr FPSCR, r1
vldmia sp!, {d0-d15}
#endif
ldmfd sp!, {r4} @ pop new task spsr
msr spsr_cxsf, r4
ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc
.section .text.isr, "ax"
/*
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
* r0 --> from
* r1 --> to
*/
.globl rt_hw_context_switch
rt_hw_context_switch:
stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC)
stmfd sp!, {r0-r12, lr} @ push lr & register file
mrs r4, cpsr
tst lr, #0x01
beq _ARM_MODE
orr r4, r4, #0x20 @ it's thumb code
_ARM_MODE:
stmfd sp!, {r4} @ push cpsr
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
vstmdb sp!, {d0-d15} /* Store floating point registers */
vmrs r4, FPSCR
stmfd sp!,{r4}
vmrs r4, FPEXC
stmfd sp!,{r4}
#endif
str sp, [r0] @ store sp in preempted tasks TCB
ldr sp, [r1] @ get new task stack pointer
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
ldmfd sp!, {r1} /* Restore floating point registers */
vmsr FPEXC, r1
ldmfd sp!, {r1}
vmsr FPSCR, r1
vldmia sp!, {d0-d15}
#endif
ldmfd sp!, {r4} @ pop new task cpsr to spsr
msr spsr_cxsf, r4
ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr
/*
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
*/
.globl rt_thread_switch_interrupt_flag
.globl rt_interrupt_from_thread
.globl rt_interrupt_to_thread
.globl rt_hw_context_switch_interrupt
rt_hw_context_switch_interrupt:
ldr r2, =rt_thread_switch_interrupt_flag
ldr r3, [r2]
cmp r3, #1
beq _reswitch
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
str r3, [r2]
ldr r2, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
str r0, [r2]
_reswitch:
ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
str r1, [r2]
bx lr

View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
*/
#include <rthw.h>
#include <rtthread.h>
#include "zynqmp-r5.h"
void rt_hw_cpu_reset()
{
__REG32(ZynqMP_CRL_APB_BASEADDR + ZynqMP_CRL_APB_RESET_CTRL) |= ZynqMP_RESET_MASK;
while (1); /* loop forever and wait for reset to happen */
/* NEVER REACHED */
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef CPUPORT_H__
#define CPUPORT_H__
#ifdef RT_USING_SMP
typedef union {
unsigned long slock;
struct __arch_tickets {
unsigned short owner;
unsigned short next;
} tickets;
} rt_hw_spinlock_t;
#endif
#endif /*CPUPORT_H__*/

View File

@ -0,0 +1,209 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
*/
#include <rtthread.h>
#include "board.h"
#include "gic.h"
/* ZynqMP-RPU uses the Arm PL-390 generic interrupt controller that is
* compliant to the GICv1 architecture specification. */
struct arm_gic
{
rt_uint32_t offset;
rt_uint32_t dist_hw_base;
rt_uint32_t cpu_hw_base;
};
static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00)
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04)
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08)
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0c)
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10)
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14)
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18)
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000)
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004)
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080 + ((n)/32) * 4)
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100 + ((n)/32) * 4)
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180 + ((n)/32) * 4)
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200 + ((n)/32) * 4)
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280 + ((n)/32) * 4)
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300 + ((n)/32) * 4)
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400 + ((n)/4) * 4)
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800 + ((n)/4) * 4)
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00 + ((n)/16) * 4)
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00)
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8)
static unsigned int _gic_max_irq;
int arm_gic_get_active_irq(rt_uint32_t index)
{
int irq;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = GIC_CPU_INTACK(_gic_table[index].cpu_hw_base);
irq += _gic_table[index].offset;
return irq;
}
void arm_gic_ack(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1 << (irq % 32);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0);
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq;
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
}
void arm_gic_mask(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1 << (irq % 32);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0);
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
{
rt_uint32_t old_tgt;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0);
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
old_tgt &= ~(0x0FFUL << ((irq % 4)*8));
old_tgt |= cpumask << ((irq % 4)*8);
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
}
void arm_gic_umask(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1 << (irq % 32);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0);
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
}
void arm_gic_dump_type(rt_uint32_t index)
{
unsigned int gic_type;
gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n",
(GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4) & 0xf,
_gic_table[index].dist_hw_base,
_gic_max_irq,
gic_type & (1 << 10) ? "has" : "no",
gic_type);
}
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
{
unsigned int gic_type, i;
rt_uint32_t cpumask = 1 << 0;
RT_ASSERT(index < ARM_GIC_MAX_NR);
_gic_table[index].dist_hw_base = dist_base;
_gic_table[index].offset = irq_start;
/* Find out how many interrupts are supported. */
gic_type = GIC_DIST_TYPE(dist_base);
_gic_max_irq = ((gic_type & 0x1f) + 1) * 32;
/*
* The GIC only supports up to 1020 interrupt sources.
* Limit this to either the architected maximum, or the
* platform maximum.
*/
if (_gic_max_irq > 1020)
_gic_max_irq = 1020;
if (_gic_max_irq > ARM_GIC_NR_IRQS)
_gic_max_irq = ARM_GIC_NR_IRQS;
cpumask |= cpumask << 8;
cpumask |= cpumask << 16;
GIC_DIST_CTRL(dist_base) = 0x0;
/* Set all global interrupts to be level triggered, active low. */
for (i = 32; i < _gic_max_irq; i += 16)
GIC_DIST_CONFIG(dist_base, i) = 0x0;
/* Set all global interrupts to this CPU only. */
for (i = 32; i < _gic_max_irq; i += 4)
GIC_DIST_TARGET(dist_base, i) = cpumask;
/* Set priority on all interrupts. */
for (i = 0; i < _gic_max_irq; i += 4)
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0;
/* Disable all interrupts. */
for (i = 0; i < _gic_max_irq; i += 32)
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffff;
/* Enable interrupt. */
GIC_DIST_CTRL(dist_base) = 0x01;
return 0;
}
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
_gic_table[index].cpu_hw_base = cpu_base;
GIC_CPU_PRIMASK(cpu_base) = 0xf0;
/* Enable CPU interrupt */
GIC_CPU_CTRL(cpu_base) = 0x01;
return 0;
}
void arm_gic_trigger(rt_uint32_t index, int target_cpu, int irq)
{
unsigned int reg;
RT_ASSERT(irq <= 15);
RT_ASSERT(target_cpu <= 255);
reg = (target_cpu << 16) | irq;
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = reg;
}
void arm_gic_clear_sgi(rt_uint32_t index, int target_cpu, int irq)
{
/* SGI will be cleared automatically. */
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
*/
#ifndef __GIC_H__
#define __GIC_H__
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start);
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base);
void arm_gic_mask(rt_uint32_t index, int irq);
void arm_gic_umask(rt_uint32_t index, int irq);
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask);
int arm_gic_get_active_irq(rt_uint32_t index);
void arm_gic_ack(rt_uint32_t index, int irq);
void arm_gic_trigger(rt_uint32_t index, int target_cpu, int irq);
void arm_gic_clear_sgi(rt_uint32_t index, int target_cpu, int irq);
void arm_gic_dump_type(rt_uint32_t index);
#endif

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
*/
#include <rthw.h>
#include <rtthread.h>
#include "zynqmp-r5.h"
#include "interrupt.h"
#include "gic.h"
#define MAX_HANDLERS IRQ_ZynqMP_MAXNR
extern volatile rt_atomic_t rt_interrupt_nest;
/* exception and interrupt handler table */
struct rt_irq_desc isr_table[MAX_HANDLERS];
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
rt_uint32_t rt_thread_switch_interrupt_flag;
void rt_hw_interrupt_handle(int vector, void *param)
{
rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
}
void rt_hw_interrupt_init(void)
{
register rt_uint32_t idx;
/* the initialization is done in fsbl */
/* init exceptions table */
rt_memset(isr_table, 0x00, sizeof(isr_table));
for (idx = 0; idx < MAX_HANDLERS; idx++)
{
isr_table[idx].handler = rt_hw_interrupt_handle;
}
/* initialize ARM GIC */
arm_gic_dist_init(0, ZynqMP_GIC_DIST_BASE, 0);
arm_gic_cpu_init(0, ZynqMP_GIC_CPU_BASE);
/* init interrupt nest, and context in thread sp */
rt_interrupt_nest = 0;
rt_interrupt_from_thread = 0;
rt_interrupt_to_thread = 0;
rt_thread_switch_interrupt_flag = 0;
}
/**
* This function will mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_mask(int vector)
{
arm_gic_mask(0, vector);
}
/**
* This function will un-mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_umask(int vector)
{
arm_gic_umask(0, vector);
}
/**
* This function returns the active interrupt number.
* @param none
*/
int rt_hw_interrupt_get_irq(void)
{
return arm_gic_get_active_irq(0) & GIC_ACK_INTID_MASK;
}
/**
* This function acknowledges the interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_ack(int vector)
{
arm_gic_ack(0, vector);
}
/**
* This function will install a interrupt service routine to a interrupt.
* @param vector the interrupt number
* @param handler the interrupt service routine to be installed
* @param param the parameter for interrupt service routine
* @param name the interrupt name
*
* @return the old handler
*/
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void *param, const char *name)
{
rt_isr_handler_t old_handler = RT_NULL;
if (vector < MAX_HANDLERS)
{
old_handler = isr_table[vector].handler;
if (handler != RT_NULL)
{
#ifdef RT_USING_INTERRUPT_INFO
rt_snprintf(isr_table[vector].name, RT_NAME_MAX, "%s", name);
#endif /* RT_USING_INTERRUPT_INFO */
isr_table[vector].handler = handler;
isr_table[vector].param = param;
}
/* set the interrupt to this cpu */
arm_gic_set_cpu(0, vector, 1 << rt_cpu_get_smp_id());
}
return old_handler;
}
void rt_hw_interrupt_trigger(int vector)
{
arm_gic_trigger(0, 1 << rt_cpu_get_smp_id(), vector);
}
void rt_hw_interrupt_clear(int vector)
{
/* SGI will be cleared automatically. */
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
*/
#ifndef __INTERRUPT_H__
#define __INTERRUPT_H__
#include <rthw.h>
#include <board.h>
void rt_hw_interrupt_init(void);
void rt_hw_interrupt_mask(int vector);
void rt_hw_interrupt_umask(int vector);
int rt_hw_interrupt_get_irq(void);
void rt_hw_interrupt_trigger(int vector);
void rt_hw_interrupt_clear(int vector);
void rt_hw_interrupt_ack(int vector);
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void *param, const char *name);
#endif

View File

@ -0,0 +1,288 @@
/******************************************************************************
* Copyright (c) 2014 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
* @file mpu.c
*
* This file contains initial configuration of the MPU.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------
* 5.00 pkp 02/20/14 First release
* 5.04 pkp 12/18/15 Updated MPU initialization as per the proper address map
* 6.00 pkp 06/27/16 moving the Init_MPU code to .boot section since it is a
* part of processor boot process
* 6.2 mus 01/27/17 Updated to support IAR compiler
* 7.1 mus 09/11/19 Added warning message if DDR size is not in power of 2.
* Fix for CR#1038577.
* 7.2 asa 04/08/20 Fix warning in the function Init_MPU.
* </pre>
*
* @note
*
* None.
*
******************************************************************************/
/***************************** Include Files *********************************/
#include <rtthread.h>
#include "zynqmp-r5.h"
#include "xreg_cortexr5.h"
#include "xpseudo_asm_gcc.h"
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
typedef rt_int32_t s32;
typedef rt_uint64_t u64;
typedef rt_uint32_t u32;
/************************** Constant Definitions *****************************/
/************************** Variable Definitions *****************************/
static const struct {
u64 size;
unsigned int encoding;
}region_size[] = {
{ 0x20, REGION_32B },
{ 0x40, REGION_64B },
{ 0x80, REGION_128B },
{ 0x100, REGION_256B },
{ 0x200, REGION_512B },
{ 0x400, REGION_1K },
{ 0x800, REGION_2K },
{ 0x1000, REGION_4K },
{ 0x2000, REGION_8K },
{ 0x4000, REGION_16K },
{ 0x8000, REGION_32K },
{ 0x10000, REGION_64K },
{ 0x20000, REGION_128K },
{ 0x40000, REGION_256K },
{ 0x80000, REGION_512K },
{ 0x100000, REGION_1M },
{ 0x200000, REGION_2M },
{ 0x400000, REGION_4M },
{ 0x800000, REGION_8M },
{ 0x1000000, REGION_16M },
{ 0x2000000, REGION_32M },
{ 0x4000000, REGION_64M },
{ 0x8000000, REGION_128M },
{ 0x10000000, REGION_256M },
{ 0x20000000, REGION_512M },
{ 0x40000000, REGION_1G },
{ 0x80000000, REGION_2G },
{ 0x100000000, REGION_4G },
};
/************************** Function Prototypes ******************************/
#if defined (__GNUC__)
void Init_MPU(void) __attribute__((__section__(".boot")));
static void Xil_SetAttribute(u32 addr, u32 reg_size,s32 reg_num, u32 attrib) __attribute__((__section__(".boot")));
static void Xil_DisableMPURegions(void) __attribute__((__section__(".boot")));
#elif defined (__ICCARM__)
#pragma default_function_attributes = @ ".boot"
void Init_MPU(void);
static void Xil_SetAttribute(u32 addr, u32 reg_size,s32 reg_num, u32 attrib);
static void Xil_DisableMPURegions(void);
#endif
/*****************************************************************************
*
* Initialize MPU for a given address map and Enabled the background Region in
* MPU with default memory attributes for rest of address range for Cortex R5
* processor.
*
* @param None.
*
* @return None.
*
*
******************************************************************************/
void Init_MPU(void)
{
u32 Addr;
u32 RegSize = 0U;
u32 Attrib;
u32 RegNum = 0, i, Offset = 0;
u64 size;
Xil_DisableMPURegions();
Addr = 0x00000000U;
#ifdef XPAR_PSU_R5_DDR_0_S_AXI_BASEADDR
/* If the DDR is present, configure region as per DDR size */
size = (XPAR_PSU_R5_DDR_0_S_AXI_HIGHADDR - XPAR_PSU_R5_DDR_0_S_AXI_BASEADDR) + 1;
if (size < 0x80000000) {
/* Lookup the size. */
for (i = 0; i < sizeof region_size / sizeof region_size[0]; i++) {
if (size <= region_size[i].size) {
RegSize = region_size[i].encoding;
/* Check if DDR size is in power of 2*/
if ( XPAR_PSU_R5_DDR_0_S_AXI_BASEADDR == 0x100000)
Offset = XPAR_PSU_R5_DDR_0_S_AXI_BASEADDR;
if (region_size[i].size > (size + Offset + 1)) {
rt_kprintf ("WARNING: DDR size mapped to Cortexr5 processor is not \
in power of 2. As processor allocates MPU regions size \
in power of 2, address range %llx to %x has been \
incorrectly mapped as normal memory \n", \
region_size[i].size - 1, ((u32)XPAR_PSU_R5_DDR_0_S_AXI_HIGHADDR + 1));
}
break;
}
}
} else {
/* if the DDR size is > 2GB, truncate it to 2GB */
RegSize = REGION_2G;
}
#else
/* For DDRless system, configure region for TCM */
RegSize = REGION_256K;
#endif
Attrib = NORM_NSHARED_WB_WA | PRIV_RW_USER_RW;
Xil_SetAttribute(Addr,RegSize,RegNum, Attrib);
RegNum++;
/*
* 1G of strongly ordered memory from 0x80000000 to 0xBFFFFFFF for PL.
* 512 MB - LPD-PL interface
* 256 MB - FPD-PL (HPM0) interface
* 256 MB - FPD-PL (HPM1) interface
*/
Addr = 0x80000000;
RegSize = REGION_1G;
Attrib = STRONG_ORDERD_SHARED | PRIV_RW_USER_RW ;
Xil_SetAttribute(Addr,RegSize,RegNum, Attrib);
RegNum++;
/* 512M of device memory from 0xC0000000 to 0xDFFFFFFF for QSPI */
Addr = 0xC0000000U;
RegSize = REGION_512M;
Attrib = DEVICE_NONSHARED | PRIV_RW_USER_RW ;
Xil_SetAttribute(Addr,RegSize,RegNum, Attrib);
RegNum++;
/* 256M of device memory from 0xE0000000 to 0xEFFFFFFF for PCIe Low */
Addr = 0xE0000000U;
RegSize = REGION_256M;
Attrib = DEVICE_NONSHARED | PRIV_RW_USER_RW ;
Xil_SetAttribute(Addr,RegSize,RegNum, Attrib);
RegNum++;
/* 16M of device memory from 0xF8000000 to 0xF8FFFFFF for STM_CORESIGHT */
Addr = 0xF8000000U;
RegSize = REGION_16M;
Attrib = DEVICE_NONSHARED | PRIV_RW_USER_RW ;
Xil_SetAttribute(Addr,RegSize,RegNum, Attrib);
RegNum++;
/* 1M of device memory from 0xF9000000 to 0xF90FFFFF for RPU_A53_GIC */
Addr = 0xF9000000U;
RegSize = REGION_1M;
Attrib = DEVICE_NONSHARED | PRIV_RW_USER_RW ;
Xil_SetAttribute(Addr,RegSize,RegNum, Attrib);
RegNum++;
/* 16M of device memory from 0xFD000000 to 0xFDFFFFFF for FPS slaves */
Addr = 0xFD000000U;
RegSize = REGION_16M;
Attrib = DEVICE_NONSHARED | PRIV_RW_USER_RW ;
Xil_SetAttribute(Addr,RegSize,RegNum, Attrib);
RegNum++;
/* 16M of device memory from 0xFE000000 to 0xFEFFFFFF for Upper LPS slaves */
Addr = 0xFE000000U;
RegSize = REGION_16M;
Attrib = DEVICE_NONSHARED | PRIV_RW_USER_RW ;
Xil_SetAttribute(Addr,RegSize,RegNum, Attrib);
RegNum++;
/*
* 16M of device memory from 0xFF000000 to 0xFFFFFFFF for Lower LPS slaves,
* CSU, PMU, TCM, OCM
*/
Addr = 0xFF000000U;
RegSize = REGION_16M;
Attrib = DEVICE_NONSHARED | PRIV_RW_USER_RW ;
Xil_SetAttribute(Addr,RegSize,RegNum, Attrib);
RegNum++;
/* 256K of OCM RAM from 0xFFFC0000 to 0xFFFFFFFF marked as normal memory */
Addr = 0xFFFC0000U;
RegSize = REGION_256K;
Attrib = NORM_NSHARED_WB_WA| PRIV_RW_USER_RW ;
Xil_SetAttribute(Addr,RegSize,RegNum, Attrib);
/* A total of 10 MPU regions are allocated with another 6 being free for users */
}
/*****************************************************************************
*
* Set the memory attributes for a section of memory with starting address addr
* of the region size defined by reg_size having attributes attrib of region number
* reg_num
*
* @param addr is the address for which attributes are to be set.
* @param attrib specifies the attributes for that memory region.
* @param reg_size specifies the size for that memory region.
* @param reg_num specifies the number for that memory region.
* @return None.
*
*
******************************************************************************/
static void Xil_SetAttribute(u32 addr, u32 reg_size,s32 reg_num, u32 attrib)
{
u32 Local_reg_size = reg_size;
Local_reg_size = Local_reg_size<<1U;
Local_reg_size |= REGION_EN;
dsb();
mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,reg_num);
isb();
mtcp(XREG_CP15_MPU_REG_BASEADDR,addr); /* Set base address of a region */
mtcp(XREG_CP15_MPU_REG_ACCESS_CTRL,attrib); /* Set the control attribute */
mtcp(XREG_CP15_MPU_REG_SIZE_EN,Local_reg_size); /* set the region size and enable it*/
dsb();
isb(); /* synchronize context on this processor */
}
/*****************************************************************************
*
* Disable all the MPU regions if any of them is enabled
*
* @param None.
*
* @return None.
*
*
******************************************************************************/
static void Xil_DisableMPURegions(void)
{
u32 Temp = 0U;
u32 Index = 0U;
for (Index = 0; Index <= 15; Index++) {
mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,Index);
#if defined (__GNUC__)
Temp = mfcp(XREG_CP15_MPU_REG_SIZE_EN);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_MPU_REG_SIZE_EN,Temp);
#endif
Temp &= (~REGION_EN);
dsb();
mtcp(XREG_CP15_MPU_REG_SIZE_EN,Temp);
dsb();
isb();
}
}
#if defined (__ICCARM__)
#pragma default_function_attributes =
#endif

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-09-23 Bernard the first version
* 2011-10-05 Bernard add thumb mode
* 2020-11-24 WangHuachen porting to zynqmp-r5
*/
#include <rtthread.h>
#include "armv7.h"
/**
* This function will initialize thread stack
*
* @param tentry the entry of thread
* @param parameter the parameter of entry
* @param stack_addr the beginning stack address
* @param texit the function will be called when thread exit
*
* @return stack address
*/
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
rt_uint8_t *stack_addr, void *texit)
{
rt_uint32_t *stk;
stack_addr += sizeof(rt_uint32_t);
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
stk = (rt_uint32_t *)stack_addr;
*(--stk) = (rt_uint32_t)tentry; /* entry point */
*(--stk) = (rt_uint32_t)texit; /* lr */
*(--stk) = 0xdeadbeef; /* r12 */
*(--stk) = 0xdeadbeef; /* r11 */
*(--stk) = 0xdeadbeef; /* r10 */
*(--stk) = 0xdeadbeef; /* r9 */
*(--stk) = 0xdeadbeef; /* r8 */
*(--stk) = 0xdeadbeef; /* r7 */
*(--stk) = 0xdeadbeef; /* r6 */
*(--stk) = 0xdeadbeef; /* r5 */
*(--stk) = 0xdeadbeef; /* r4 */
*(--stk) = 0xdeadbeef; /* r3 */
*(--stk) = 0xdeadbeef; /* r2 */
*(--stk) = 0xdeadbeef; /* r1 */
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
/* cpsr */
if ((rt_uint32_t)tentry & 0x01)
*(--stk) = SVCMODE | 0x20; /* thumb mode */
else
*(--stk) = SVCMODE; /* arm mode */
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
{
int i;
for (i = 0; i < VFP_DATA_NR; i++)
{
*(--stk) = 0;
}
/* FPSCR TODO: do we need to set the values other than 0? */
*(--stk) = 0;
/* FPEXC. Enable the FVP if no lazy stacking. */
*(--stk) = 0x40000000;
}
#endif
/* return task's current stack address */
return (rt_uint8_t *)stk;
}

View File

@ -0,0 +1,428 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
* 2021-05-11 WangHuachen Added call to Xil_InitializeExistingMPURegConfig to
* initialize the MPU configuration table with the MPU
* configurations already set in Init_Mpu function.
*/
.equ Mode_USR, 0x10
.equ Mode_FIQ, 0x11
.equ Mode_IRQ, 0x12
.equ Mode_SVC, 0x13
.equ Mode_ABT, 0x17
.equ Mode_UND, 0x1B
.equ Mode_SYS, 0x1F
.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled
.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled
.equ UND_Stack_Size, 0x00000000
.equ SVC_Stack_Size, 0x00000000
.equ ABT_Stack_Size, 0x00000000
.equ FIQ_Stack_Size, 0x00000200
.equ IRQ_Stack_Size, 0x00000200
.equ USR_Stack_Size, 0x00000000
.set RPU_GLBL_CNTL, 0xFF9A0000
.set RPU_ERR_INJ, 0xFF9A0020
.set RPU_0_CFG, 0xFF9A0100
.set RPU_1_CFG, 0xFF9A0200
.set RST_LPD_DBG, 0xFF5E0240
.set BOOT_MODE_USER, 0xFF5E0200
.set fault_log_enable, 0x101
#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
.section .data.share.isr
/* stack */
.globl stack_start
.globl stack_top
.align 3
.bss
stack_start:
.rept ISR_Stack_Size
.long 0
.endr
stack_top:
.section .boot,"axS"
/* reset entry */
.globl _reset
_reset:
/* Initialize processor registers to 0 */
mov r0,#0
mov r1,#0
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
mov r6,#0
mov r7,#0
mov r8,#0
mov r9,#0
mov r10,#0
mov r11,#0
mov r12,#0
/* set the cpu to SVC32 mode and disable interrupt */
cpsid if, #Mode_SVC
/* setup stack */
bl stack_setup
/*
* Enable access to VFP by enabling access to Coprocessors 10 and 11.
* Enables Full Access i.e. in both privileged and non privileged modes
*/
mrc p15, 0, r0, c1, c0, 2 /* Read Coprocessor Access Control Register (CPACR) */
orr r0, r0, #(0xF << 20) /* Enable access to CP 10 & 11 */
mcr p15, 0, r0, c1, c0, 2 /* Write Coprocessor Access Control Register (CPACR) */
isb
/* enable fpu access */
vmrs r3, FPEXC
orr r1, r3, #(1<<30)
vmsr FPEXC, r1
/* clear the floating point register*/
mov r1,#0
vmov d0,r1,r1
vmov d1,r1,r1
vmov d2,r1,r1
vmov d3,r1,r1
vmov d4,r1,r1
vmov d5,r1,r1
vmov d6,r1,r1
vmov d7,r1,r1
vmov d8,r1,r1
vmov d9,r1,r1
vmov d10,r1,r1
vmov d11,r1,r1
vmov d12,r1,r1
vmov d13,r1,r1
vmov d14,r1,r1
vmov d15,r1,r1
#ifdef __SOFTFP__
/* Disable the FPU if SOFTFP is defined*/
vmsr FPEXC,r3
#endif
/* Disable MPU and caches */
mrc p15, 0, r0, c1, c0, 0 /* Read CP15 Control Register*/
bic r0, r0, #0x05 /* Disable MPU (M bit) and data cache (C bit) */
bic r0, r0, #0x1000 /* Disable instruction cache (I bit) */
dsb /* Ensure all previous loads/stores have completed */
mcr p15, 0, r0, c1, c0, 0 /* Write CP15 Control Register */
isb /* Ensure subsequent insts execute wrt new MPU settings */
/* Disable Branch prediction, TCM ECC checks */
mrc p15, 0, r0, c1, c0, 1 /* Read ACTLR */
orr r0, r0, #(0x1 << 17) /* Enable RSDIS bit 17 to disable the return stack */
orr r0, r0, #(0x1 << 16) /* Clear BP bit 15 and set BP bit 16:*/
bic r0, r0, #(0x1 << 15) /* Branch always not taken and history table updates disabled*/
orr r0, r0, #(0x1 << 27) /* Enable B1TCM ECC check */
orr r0, r0, #(0x1 << 26) /* Enable B0TCM ECC check */
orr r0, r0, #(0x1 << 25) /* Enable ATCM ECC check */
bic r0, r0, #(0x1 << 5) /* Generate abort on parity errors, with [5:3]=b 000*/
bic r0, r0, #(0x1 << 4)
bic r0, r0, #(0x1 << 3)
mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/
dsb /* Complete all outstanding explicit memory operations*/
/* Invalidate caches */
mov r0,#0 /* r0 = 0 */
dsb
mcr p15, 0, r0, c7, c5, 0 /* invalidate icache */
mcr p15, 0, r0, c15, c5, 0 /* Invalidate entire data cache*/
isb
/* enable fault log for lock step */
ldr r0,=RPU_GLBL_CNTL
ldr r1, [r0]
ands r1, r1, #0x8
/* branch to initialization if split mode*/
bne init
/* check for boot mode if in lock step, branch to init if JTAG boot mode*/
ldr r0,=BOOT_MODE_USER
ldr r1, [r0]
ands r1, r1, #0xF
beq init
/* reset the debug logic */
ldr r0,=RST_LPD_DBG
ldr r1, [r0]
orr r1, r1, #(0x1 << 4)
orr r1, r1, #(0x1 << 5)
str r1, [r0]
/* enable fault log */
ldr r0,=RPU_ERR_INJ
ldr r1,=fault_log_enable
ldr r2, [r0]
orr r2, r2, r1
str r2, [r0]
nop
nop
init:
bl Init_MPU /* Initialize MPU */
/* Enable Branch prediction */
mrc p15, 0, r0, c1, c0, 1 /* Read ACTLR*/
bic r0, r0, #(0x1 << 17) /* Clear RSDIS bit 17 to enable return stack*/
bic r0, r0, #(0x1 << 16) /* Clear BP bit 15 and BP bit 16:*/
bic r0, r0, #(0x1 << 15) /* Normal operation, BP is taken from the global history table.*/
orr r0, r0, #(0x1 << 14) /* Disable DBWR for errata 780125 */
mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/
/* Enable icahce and dcache */
mrc p15,0,r1,c1,c0,0
ldr r0, =0x1005
orr r1,r1,r0
dsb
mcr p15,0,r1,c1,c0,0 /* Enable cache */
isb /* isb flush prefetch buffer */
/* Set vector table in TCM/LOVEC */
mrc p15, 0, r0, c1, c0, 0
mvn r1, #0x2000
and r0, r0, r1
mcr p15, 0, r0, c1, c0, 0
/* Clear VINITHI to enable LOVEC on reset */
#if 1
ldr r0, =RPU_0_CFG
#else
ldr r0, =RPU_1_CFG
#endif
ldr r1, [r0]
bic r1, r1, #(0x1 << 2)
str r1, [r0]
/* enable asynchronous abort exception */
mrs r0, cpsr
bic r0, r0, #0x100
msr cpsr_xsf, r0
/* clear .bss */
mov r0,#0 /* get a zero */
ldr r1,=__bss_start /* bss start */
ldr r2,=__bss_end /* bss end */
bss_loop:
cmp r1,r2 /* check if data to clear */
strlo r0,[r1],#4 /* clear 4 bytes */
blo bss_loop /* loop until done */
/* call C++ constructors of global objects */
ldr r0, =__ctors_start__
ldr r1, =__ctors_end__
ctor_loop:
cmp r0, r1
beq ctor_end
ldr r2, [r0], #4
stmfd sp!, {r0-r1}
mov lr, pc
bx r2
ldmfd sp!, {r0-r1}
b ctor_loop
ctor_end:
bl Xil_InitializeExistingMPURegConfig /* Initialize MPU config */
/* start RT-Thread Kernel */
ldr pc, _entry
_entry:
.word entry
stack_setup:
ldr r0, =stack_top
@ Set the startup stack for svc
mov sp, r0
@ Enter Undefined Instruction Mode and set its Stack Pointer
msr cpsr_c, #Mode_UND|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #UND_Stack_Size
@ Enter Abort Mode and set its Stack Pointer
msr cpsr_c, #Mode_ABT|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #ABT_Stack_Size
@ Enter FIQ Mode and set its Stack Pointer
msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #FIQ_Stack_Size
@ Enter IRQ Mode and set its Stack Pointer
msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #IRQ_Stack_Size
@ Switch back to SVC
msr cpsr_c, #Mode_SVC|I_Bit|F_Bit
bx lr
.section .text.isr, "ax"
/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */
.align 5
.globl vector_fiq
vector_fiq:
stmfd sp!,{r0-r7,lr}
bl rt_hw_trap_fiq
ldmfd sp!,{r0-r7,lr}
subs pc,lr,#4
.globl rt_interrupt_enter
.globl rt_interrupt_leave
.globl rt_thread_switch_interrupt_flag
.globl rt_interrupt_from_thread
.globl rt_interrupt_to_thread
.align 5
.globl vector_irq
vector_irq:
stmfd sp!, {r0-r12,lr}
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
vstmdb sp!, {d0-d15} /* Store floating point registers */
vmrs r1, FPSCR
stmfd sp!,{r1}
vmrs r1, FPEXC
stmfd sp!,{r1}
#endif
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
@ if rt_thread_switch_interrupt_flag set, jump to
@ rt_hw_context_switch_interrupt_do and don't return
ldr r0, =rt_thread_switch_interrupt_flag
ldr r1, [r0]
cmp r1, #1
beq rt_hw_context_switch_interrupt_do
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
ldmfd sp!, {r1} /* Restore floating point registers */
vmsr FPEXC, r1
ldmfd sp!, {r1}
vmsr FPSCR, r1
vldmia sp!, {d0-d15}
#endif
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
rt_hw_context_switch_interrupt_do:
mov r1, #0 @ clear flag
str r1, [r0]
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
ldmfd sp!, {r1} /* Restore floating point registers */
vmsr FPEXC, r1
ldmfd sp!, {r1}
vmsr FPSCR, r1
vldmia sp!, {d0-d15}
#endif
mov r1, sp @ r1 point to {r0-r3} in stack
add sp, sp, #4*4
ldmfd sp!, {r4-r12,lr}@ reload saved registers
mrs r0, spsr @ get cpsr of interrupt thread
sub r2, lr, #4 @ save old task's pc to r2
@ Switch to SVC mode with no interrupt.
msr cpsr_c, #I_Bit|F_Bit|Mode_SVC
stmfd sp!, {r2} @ push old task's pc
stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4
ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt thread
stmfd sp!, {r1-r4} @ push old task's r0-r3
stmfd sp!, {r0} @ push old task's cpsr
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
vstmdb sp!, {d0-d15} /* Store floating point registers */
vmrs r1, FPSCR
stmfd sp!,{r1}
vmrs r1, FPEXC
stmfd sp!,{r1}
#endif
ldr r4, =rt_interrupt_from_thread
ldr r5, [r4]
str sp, [r5] @ store sp in preempted tasks's TCB
ldr r6, =rt_interrupt_to_thread
ldr r7, [r6]
ldr sp, [r7] @ get new task's stack pointer
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
ldmfd sp!, {r1} /* Restore floating point registers */
vmsr FPEXC, r1
ldmfd sp!, {r1}
vmsr FPSCR, r1
vldmia sp!, {d0-d15}
#endif
ldmfd sp!, {r4} @ pop new task's cpsr to spsr
msr spsr_cxsf, r4
ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr
.macro push_svc_reg
sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */
stmia sp, {r0 - r12} @/* Calling r0-r12 */
mov r0, sp
mrs r6, spsr @/* Save CPSR */
str lr, [r0, #15*4] @/* Push PC */
str r6, [r0, #16*4] @/* Push CPSR */
cps #Mode_SVC
str sp, [r0, #13*4] @/* Save calling SP */
str lr, [r0, #14*4] @/* Save calling PC */
.endm
.align 5
.globl vector_swi
vector_swi:
push_svc_reg
bl rt_hw_trap_swi
b .
.align 5
.globl vector_undef
vector_undef:
push_svc_reg
bl rt_hw_trap_undef
b .
.align 5
.globl vector_pabt
vector_pabt:
push_svc_reg
bl rt_hw_trap_pabt
b .
.align 5
.globl vector_dabt
vector_dabt:
push_svc_reg
bl rt_hw_trap_dabt
b .
.align 5
.globl vector_resv
vector_resv:
push_svc_reg
bl rt_hw_trap_resv
b .

View File

@ -0,0 +1,180 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
* 2020-11-24 WangHuachen porting to zynqmp-r5
*/
#include <rtthread.h>
#include <rthw.h>
#include <board.h>
#include "armv7.h"
#include "interrupt.h"
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
extern long list_thread(void);
#endif
/**
* this function will show registers of CPU
*
* @param regs the registers point
*/
void rt_hw_show_register (struct rt_hw_exp_stack *regs)
{
rt_kprintf("Execption:\n");
rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3);
rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7);
rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10);
rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip);
rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc);
rt_kprintf("cpsr:0x%08x\n", regs->cpsr);
}
/**
* When comes across an instruction which it cannot handle,
* it takes the undefined instruction trap.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_undef(struct rt_hw_exp_stack *regs)
{
rt_kprintf("undefined instruction:\n");
rt_hw_show_register(regs);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* The software interrupt instruction (SWI) is used for entering
* Supervisor mode, usually to request a particular supervisor
* function.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_swi(struct rt_hw_exp_stack *regs)
{
rt_kprintf("software interrupt:\n");
rt_hw_show_register(regs);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* An abort indicates that the current memory access cannot be completed,
* which occurs during an instruction prefetch.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs)
{
rt_kprintf("prefetch abort:\n");
rt_hw_show_register(regs);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* An abort indicates that the current memory access cannot be completed,
* which occurs during a data access.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs)
{
rt_kprintf("data abort:");
rt_hw_show_register(regs);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* Normally, system will never reach here
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_resv(struct rt_hw_exp_stack *regs)
{
rt_kprintf("reserved trap:\n");
rt_hw_show_register(regs);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
list_thread();
#endif
rt_hw_cpu_shutdown();
}
void rt_hw_trap_irq(void)
{
void *param;
int ir;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
ir = rt_hw_interrupt_get_irq();
if (ir == 1023)
{
/* Spurious interrupt */
return;
}
/* get interrupt service routine */
isr_func = isr_table[ir].handler;
#ifdef RT_USING_INTERRUPT_INFO
isr_table[ir].counter++;
#endif
if (isr_func)
{
/* Interrupt for myself. */
param = isr_table[ir].param;
/* turn to interrupt service routine */
isr_func(ir, param);
}
/* end of interrupt */
rt_hw_interrupt_ack(ir);
}
void rt_hw_trap_fiq(void)
{
void *param;
int ir;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
ir = rt_hw_interrupt_get_irq();
/* get interrupt service routine */
isr_func = isr_table[ir].handler;
param = isr_table[ir].param;
/* turn to interrupt service routine */
isr_func(ir, param);
/* end of interrupt */
rt_hw_interrupt_ack(ir);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
*/
.section .vectors, "ax"
.code 32
.globl system_vectors
system_vectors:
ldr pc, _vector_reset
ldr pc, _vector_undef
ldr pc, _vector_swi
ldr pc, _vector_pabt
ldr pc, _vector_dabt
ldr pc, _vector_resv
ldr pc, _vector_irq
ldr pc, _vector_fiq
.globl _reset
.globl vector_undef
.globl vector_swi
.globl vector_pabt
.globl vector_dabt
.globl vector_resv
.globl vector_irq
.globl vector_fiq
_vector_reset:
.word _reset
_vector_undef:
.word vector_undef
_vector_swi:
.word vector_swi
_vector_pabt:
.word vector_pabt
_vector_dabt:
.word vector_dabt
_vector_resv:
.word vector_resv
_vector_irq:
.word vector_irq
_vector_fiq:
.word vector_fiq
.balignl 16,0xdeadbeef

View File

@ -0,0 +1,54 @@
/******************************************************************************
* Copyright (c) 2015 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
* @file xil_mmu.h
* This file only includes xil_mpu.h which contains Xil_SetTlbAttributes API
* defined for MPU in R5. R5 does not have mmu and for usage of similar API
* the file has been created.
*
*
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------
* 5.0 pkp 2/12/15 Initial version
* </pre>
*
* @note
*
* None.
*
******************************************************************************/
#ifndef XIL_MMU_H
#define XIL_MMU_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/***************************** Include Files *********************************/
#include "xil_mpu.h"
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/************************** Constant Definitions *****************************/
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* XIL_MMU_H */

View File

@ -0,0 +1,637 @@
/******************************************************************************
*
* Copyright (C) 2014 - 2017 Xilinx, Inc. All rights reserved.
* Copyright (C) 2021 WangHuachen. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
*
******************************************************************************/
/*****************************************************************************/
/**
* @file xil_mpu.c
*
* This file provides APIs for enabling/disabling MPU and setting the memory
* attributes for sections, in the MPU translation table.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------
* 5.00 pkp 02/10/14 Initial version
* 6.2 mus 01/27/17 Updated to support IAR compiler
* 6.4 asa 08/16/17 Added many APIs for MPU access to make MPU usage
* user-friendly. The APIs added are: Xil_UpdateMPUConfig,
* Xil_GetMPUConfig, Xil_GetNumOfFreeRegions,
* Xil_GetNextMPURegion, Xil_DisableMPURegionByRegNum,
* Xil_GetMPUFreeRegMask, Xil_SetMPURegionByRegNum, and
* Xil_InitializeExistingMPURegConfig.
* Added a new array of structure of type XMpuConfig to
* represent the MPU configuration table.
* 6.8 aru 07/02/18 Returned the pointer instead of address
* of that pointer in Xil_MemMap().
* </pre>
*
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xil_cache.h"
#include "xpseudo_asm_gcc.h"
#include "xil_types.h"
#include "xil_mpu.h"
// #include "xdebug.h"
#include "xreg_cortexr5.h"
#include "xstatus.h"
#include <rtthread.h>
#define DBG_TAG "xil_mpu"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
extern void Xil_DCacheFlush(void);
extern void Xil_ICacheInvalidate(void);
extern void Xil_DCacheDisable(void);
extern void Xil_ICacheDisable(void);
extern void Xil_DCacheEnable(void);
extern void Xil_ICacheEnable(void);
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/************************** Constant Definitions *****************************/
#define MPU_REGION_SIZE_MIN 0x20
/************************** Variable Definitions *****************************/
static const struct {
u64 size;
unsigned int encoding;
}region_size[] = {
{ 0x20, REGION_32B },
{ 0x40, REGION_64B },
{ 0x80, REGION_128B },
{ 0x100, REGION_256B },
{ 0x200, REGION_512B },
{ 0x400, REGION_1K },
{ 0x800, REGION_2K },
{ 0x1000, REGION_4K },
{ 0x2000, REGION_8K },
{ 0x4000, REGION_16K },
{ 0x8000, REGION_32K },
{ 0x10000, REGION_64K },
{ 0x20000, REGION_128K },
{ 0x40000, REGION_256K },
{ 0x80000, REGION_512K },
{ 0x100000, REGION_1M },
{ 0x200000, REGION_2M },
{ 0x400000, REGION_4M },
{ 0x800000, REGION_8M },
{ 0x1000000, REGION_16M },
{ 0x2000000, REGION_32M },
{ 0x4000000, REGION_64M },
{ 0x8000000, REGION_128M },
{ 0x10000000, REGION_256M },
{ 0x20000000, REGION_512M },
{ 0x40000000, REGION_1G },
{ 0x80000000, REGION_2G },
{ 0x100000000, REGION_4G },
};
XMpu_Config Mpu_Config;
/************************** Function Prototypes ******************************/
void Xil_InitializeExistingMPURegConfig(void);
/*****************************************************************************/
/**
* @brief This function sets the memory attributes for a section covering
* 1MB, of memory in the translation table.
*
* @param Addr: 32-bit address for which memory attributes need to be set.
* @param attrib: Attribute for the given memory region.
* @return None.
*
*
******************************************************************************/
void Xil_SetTlbAttributes(INTPTR addr, u32 attrib)
{
INTPTR Localaddr = addr;
Localaddr &= (~(0xFFFFFU));
/* Setting the MPU region with given attribute with 1MB size */
Xil_SetMPURegion(Localaddr, 0x100000, attrib);
}
/*****************************************************************************/
/**
* @brief Set the memory attributes for a section of memory in the
* translation table.
*
* @param Addr: 32-bit address for which memory attributes need to be set..
* @param size: size is the size of the region.
* @param attrib: Attribute for the given memory region.
* @return None.
*
*
******************************************************************************/
u32 Xil_SetMPURegion(INTPTR addr, u64 size, u32 attrib)
{
u32 Regionsize = 0;
INTPTR Localaddr = addr;
u32 NextAvailableMemRegion;
unsigned int i;
NextAvailableMemRegion = Xil_GetNextMPURegion();
if (NextAvailableMemRegion == 0xFF) {
LOG_E("No regions available\r\n");
return XST_FAILURE;
}
Xil_DCacheFlush();
Xil_ICacheInvalidate();
mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,NextAvailableMemRegion);
isb();
/* Lookup the size. */
for (i = 0; i < sizeof region_size / sizeof region_size[0]; i++) {
if (size <= region_size[i].size) {
Regionsize = region_size[i].encoding;
break;
}
}
Localaddr &= ~(region_size[i].size - 1);
Regionsize <<= 1;
Regionsize |= REGION_EN;
dsb();
mtcp(XREG_CP15_MPU_REG_BASEADDR, Localaddr); /* Set base address of a region */
mtcp(XREG_CP15_MPU_REG_ACCESS_CTRL, attrib); /* Set the control attribute */
mtcp(XREG_CP15_MPU_REG_SIZE_EN, Regionsize); /* set the region size and enable it*/
dsb();
isb();
Xil_UpdateMPUConfig(NextAvailableMemRegion, Localaddr, Regionsize, attrib);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
* @brief Enable MPU for Cortex R5 processor. This function invalidates I
* cache and flush the D Caches, and then enables the MPU.
*
*
* @param None.
* @return None.
*
******************************************************************************/
void Xil_EnableMPU(void)
{
u32 CtrlReg, Reg;
s32 DCacheStatus=0, ICacheStatus=0;
/* enable caches only if they are disabled */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
#endif
if ((CtrlReg & XREG_CP15_CONTROL_C_BIT) != 0x00000000U) {
DCacheStatus=1;
}
if ((CtrlReg & XREG_CP15_CONTROL_I_BIT) != 0x00000000U) {
ICacheStatus=1;
}
if(DCacheStatus != 0) {
Xil_DCacheDisable();
}
if(ICacheStatus != 0){
Xil_ICacheDisable();
}
#if defined (__GNUC__)
Reg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,Reg);
#endif
Reg |= 0x00000001U;
dsb();
mtcp(XREG_CP15_SYS_CONTROL, Reg);
isb();
/* enable caches only if they are disabled in routine*/
if(DCacheStatus != 0) {
Xil_DCacheEnable();
}
if(ICacheStatus != 0) {
Xil_ICacheEnable();
}
}
/*****************************************************************************/
/**
* @brief Disable MPU for Cortex R5 processors. This function invalidates I
* cache and flush the D Caches, and then disabes the MPU.
*
* @param None.
*
* @return None.
*
******************************************************************************/
void Xil_DisableMPU(void)
{
u32 CtrlReg, Reg;
s32 DCacheStatus=0, ICacheStatus=0;
/* enable caches only if they are disabled */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
#endif
if ((CtrlReg & XREG_CP15_CONTROL_C_BIT) != 0x00000000U) {
DCacheStatus=1;
}
if ((CtrlReg & XREG_CP15_CONTROL_I_BIT) != 0x00000000U) {
ICacheStatus=1;
}
if(DCacheStatus != 0) {
Xil_DCacheDisable();
}
if(ICacheStatus != 0){
Xil_ICacheDisable();
}
mtcp(XREG_CP15_INVAL_BRANCH_ARRAY, 0);
#if defined (__GNUC__)
Reg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,Reg);
#endif
Reg &= ~(0x00000001U);
dsb();
mtcp(XREG_CP15_SYS_CONTROL, Reg);
isb();
/* enable caches only if they are disabled in routine*/
if(DCacheStatus != 0) {
Xil_DCacheEnable();
}
if(ICacheStatus != 0) {
Xil_ICacheEnable();
}
}
/*****************************************************************************/
/**
* @brief Update the MPU configuration for the requested region number in
* the global MPU configuration table.
*
* @param reg_num: The requested region number to be updated information for.
* @param address: 32 bit address for start of the region.
* @param size: Requested size of the region.
* @param attrib: Attribute for the corresponding region.
* @return XST_FAILURE: When the requested region number if 16 or more.
* XST_SUCCESS: When the MPU configuration table is updated.
*
*
******************************************************************************/
u32 Xil_UpdateMPUConfig(u32 reg_num, INTPTR address, u32 size, u32 attrib)
{
u32 ReturnVal = XST_SUCCESS;
u32 Tempsize = size;
u32 Index;
if (reg_num >= MAX_POSSIBLE_MPU_REGS) {
LOG_E("Invalid region number\r\n");
ReturnVal = XST_FAILURE;
goto exit;
}
if (size & REGION_EN) {
Mpu_Config[reg_num].RegionStatus = MPU_REG_ENABLED;
Mpu_Config[reg_num].BaseAddress = address;
Tempsize &= (~REGION_EN);
Tempsize >>= 1;
/* Lookup the size. */
for (Index = 0; Index <
sizeof region_size / sizeof region_size[0]; Index++) {
if (Tempsize <= region_size[Index].encoding) {
Mpu_Config[reg_num].Size = region_size[Index].size;
break;
}
}
Mpu_Config[reg_num].Attribute = attrib;
} else {
Mpu_Config[reg_num].RegionStatus = 0U;
Mpu_Config[reg_num].BaseAddress = 0U;
Mpu_Config[reg_num].Size = 0U;
Mpu_Config[reg_num].Attribute = 0U;
}
exit:
return ReturnVal;
}
/*****************************************************************************/
/**
* @brief The MPU configuration table is passed to the caller.
*
* @param mpuconfig: This is of type XMpu_Config which is an array of
* 16 entries of type structure representing the MPU config table
* @return none
*
*
******************************************************************************/
void Xil_GetMPUConfig (XMpu_Config mpuconfig) {
u32 Index = 0U;
while (Index < MAX_POSSIBLE_MPU_REGS) {
mpuconfig[Index].RegionStatus = Mpu_Config[Index].RegionStatus;
mpuconfig[Index].BaseAddress = Mpu_Config[Index].BaseAddress;
mpuconfig[Index].Attribute = Mpu_Config[Index].Attribute;
mpuconfig[Index].Size = Mpu_Config[Index].Size;
Index++;
}
}
/*****************************************************************************/
/**
* @brief Returns the total number of free MPU regions available.
*
* @param none
* @return Number of free regions available to users
*
*
******************************************************************************/
u32 Xil_GetNumOfFreeRegions (void) {
u32 Index = 0U;
int NumofFreeRegs = 0U;
while (Index < MAX_POSSIBLE_MPU_REGS) {
if (MPU_REG_DISABLED == Mpu_Config[Index].RegionStatus) {
NumofFreeRegs++;
}
Index++;
}
return NumofFreeRegs;
}
/*****************************************************************************/
/**
* @brief Returns the total number of free MPU regions available in the form
* of a mask. A bit of 1 in the returned 16 bit value represents the
* corresponding region number to be available.
* For example, if this function returns 0xC0000, this would mean, the
* regions 14 and 15 are available to users.
*
* @param none
* @return The free region mask as a 16 bit value
*
*
******************************************************************************/
u16 Xil_GetMPUFreeRegMask (void) {
u32 Index = 0U;
u16 FreeRegMask = 0U;
while (Index < MAX_POSSIBLE_MPU_REGS) {
if (MPU_REG_DISABLED == Mpu_Config[Index].RegionStatus) {
FreeRegMask |= (1U << Index);
}
Index++;
}
return FreeRegMask;
}
/*****************************************************************************/
/**
* @brief Disables the corresponding region number as passed by the user.
*
* @param reg_num: The region number to be disabled
* @return XST_SUCCESS: If the region could be disabled successfully
* XST_FAILURE: If the requested region number is 16 or more.
*
*
******************************************************************************/
u32 Xil_DisableMPURegionByRegNum (u32 reg_num) {
u32 Temp = 0U;
u32 ReturnVal = XST_FAILURE;
if (reg_num >= 16U) {
LOG_E("Invalid region number\r\n");
goto exit1;
}
Xil_DCacheFlush();
Xil_ICacheInvalidate();
mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,reg_num);
#if defined (__GNUC__)
Temp = mfcp(XREG_CP15_MPU_REG_SIZE_EN);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_MPU_REG_SIZE_EN,Temp);
#endif
Temp &= (~REGION_EN);
dsb();
mtcp(XREG_CP15_MPU_REG_SIZE_EN,Temp);
dsb();
isb();
Xil_UpdateMPUConfig(reg_num, 0U, 0U, 0U);
ReturnVal = XST_SUCCESS;
exit1:
return ReturnVal;
}
/*****************************************************************************/
/**
* @brief Enables the corresponding region number as passed by the user.
*
* @param reg_num: The region number to be enabled
* @param address: 32 bit address for start of the region.
* @param size: Requested size of the region.
* @param attrib: Attribute for the corresponding region.
* @return XST_SUCCESS: If the region could be created successfully
* XST_FAILURE: If the requested region number is 16 or more.
*
*
******************************************************************************/
u32 Xil_SetMPURegionByRegNum (u32 reg_num, INTPTR addr, u64 size, u32 attrib)
{
u32 ReturnVal = XST_SUCCESS;
INTPTR Localaddr = addr;
u32 Regionsize = 0;
u32 Index;
if (reg_num >= 16U) {
LOG_E("Invalid region number\r\n");
ReturnVal = XST_FAILURE;
goto exit2;
}
if (Mpu_Config[reg_num].RegionStatus == MPU_REG_ENABLED) {
LOG_E("Region already enabled\r\n");
ReturnVal = XST_FAILURE;
goto exit2;
}
Xil_DCacheFlush();
Xil_ICacheInvalidate();
mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,reg_num);
isb();
/* Lookup the size. */
for (Index = 0; Index <
sizeof region_size / sizeof region_size[0]; Index++) {
if (size <= region_size[Index].size) {
Regionsize = region_size[Index].encoding;
break;
}
}
Localaddr &= ~(region_size[Index].size - 1);
Regionsize <<= 1;
Regionsize |= REGION_EN;
dsb();
mtcp(XREG_CP15_MPU_REG_BASEADDR, Localaddr);
mtcp(XREG_CP15_MPU_REG_ACCESS_CTRL, attrib);
mtcp(XREG_CP15_MPU_REG_SIZE_EN, Regionsize);
dsb();
isb();
Xil_UpdateMPUConfig(reg_num, Localaddr, Regionsize, attrib);
exit2:
return ReturnVal;
}
/*****************************************************************************/
/**
* @brief Initializes the MPU configuration table that are setup in the
* R5 boot code in the Init_Mpu function called before C main.
*
* @param none
* @return none
*
*
******************************************************************************/
void Xil_InitializeExistingMPURegConfig(void)
{
u32 Index = 0U;
u32 Index1 = 0U;
u32 MPURegSize;
INTPTR MPURegBA;
u32 MPURegAttrib;
u32 Tempsize;
while (Index < MAX_POSSIBLE_MPU_REGS) {
mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,Index);
#if defined (__GNUC__)
MPURegSize = mfcp(XREG_CP15_MPU_REG_SIZE_EN);
MPURegBA = mfcp(XREG_CP15_MPU_REG_BASEADDR);
MPURegAttrib = mfcp(XREG_CP15_MPU_REG_ACCESS_CTRL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_MPU_REG_SIZE_EN,MPURegSize);
mfcp(XREG_CP15_MPU_REG_BASEADDR, MPURegBA);
mfcp(XREG_CP15_MPU_REG_ACCESS_CTRL, MPURegAttrib);
#endif
if (MPURegSize & REGION_EN) {
Mpu_Config[Index].RegionStatus = MPU_REG_ENABLED;
Mpu_Config[Index].BaseAddress = MPURegBA;
Mpu_Config[Index].Attribute = MPURegAttrib;
Tempsize = MPURegSize & (~REGION_EN);
Tempsize >>= 1;
for (Index1 = 0; Index1 <
(sizeof (region_size) / sizeof (region_size[0])); Index1++) {
if (Tempsize <= region_size[Index1].encoding) {
Mpu_Config[Index].Size = region_size[Index1].size;
break;
}
}
}
Index++;
}
}
/*****************************************************************************/
/**
* @brief Returns the next available free MPU region
*
* @param none
* @return The free MPU region available
*
*
******************************************************************************/
u32 Xil_GetNextMPURegion(void)
{
u32 Index = 0U;
u32 NextAvailableReg = 0xFF;
while (Index < MAX_POSSIBLE_MPU_REGS) {
if (Mpu_Config[Index].RegionStatus != MPU_REG_ENABLED) {
NextAvailableReg = Index;
break;
}
Index++;
}
return NextAvailableReg;
}
/*****************************************************************************/
/**
* @brief Memory mapping for Cortex r5.
*
* @param Physaddr is base physical address at which to start mapping.
* NULL in Physaddr masks possible mapping errors.
* @param size of region to be mapped.
* @param flags used to set translation table.
*
* @return Physaddr on success, NULL on error. Ambiguous if Physaddr==NULL
*
* @note: u32overflow() is defined for readability and (for __GNUC__) to
* - force the type of the check to be the same as the first argument
* - hide the otherwise unused third argument of the builtin
* - improve safety by choosing the explicit _uadd_ version.
* Consider __builtin_add_overflow_p() when available.
* Use an alternative (less optimal?) for compilers w/o the builtin.
*
******************************************************************************/
#ifdef __GNUC__
#define u32overflow(a, b) ({typeof(a) s; __builtin_uadd_overflow(a, b, &s); })
#else
#define u32overflow(a, b) ((a) > ((a) + (b)))
#endif /* __GNUC__ */
void *Xil_MemMap(UINTPTR Physaddr, size_t size, u32 flags)
{
size_t Regionsize = MPU_REGION_SIZE_MIN;
UINTPTR Basephysaddr = 0, end = Physaddr + size;
if (!flags)
return (void *)Physaddr;
if (u32overflow(Physaddr, size))
return NULL;
for ( ; Regionsize != 0; Regionsize <<= 1) {
if (Regionsize >= size) {
Basephysaddr = Physaddr & ~(Regionsize - 1);
if (u32overflow(Basephysaddr, Regionsize))
break;
if ((Basephysaddr + Regionsize) >= end)
return Xil_SetMPURegion(Basephysaddr,
Regionsize, flags) == XST_SUCCESS ?
(void *)Physaddr : NULL;
}
}
return NULL;
}

View File

@ -0,0 +1,129 @@
/******************************************************************************
*
* Copyright (C) 2014 - 2017 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
*
******************************************************************************/
/*****************************************************************************/
/**
* @file xil_mmu.h
*
* @addtogroup r5_mpu_apis Cortex R5 Processor MPU specific APIs
*
* MPU functions provides access to MPU operations such as enable MPU, disable
* MPU and set attribute for section of memory.
* Boot code invokes Init_MPU function to configure the MPU. A total of 10 MPU
* regions are allocated with another 6 being free for users. Overview of the
* memory attributes for different MPU regions is as given below,
*
*| | Memory Range | Attributes of MPURegion |
*|-----------------------|-------------------------|-----------------------------|
*| DDR | 0x00000000 - 0x7FFFFFFF | Normal write-back Cacheable |
*| PL | 0x80000000 - 0xBFFFFFFF | Strongly Ordered |
*| QSPI | 0xC0000000 - 0xDFFFFFFF | Device Memory |
*| PCIe | 0xE0000000 - 0xEFFFFFFF | Device Memory |
*| STM_CORESIGHT | 0xF8000000 - 0xF8FFFFFF | Device Memory |
*| RPU_R5_GIC | 0xF9000000 - 0xF90FFFFF | Device memory |
*| FPS | 0xFD000000 - 0xFDFFFFFF | Device Memory |
*| LPS | 0xFE000000 - 0xFFFFFFFF | Device Memory |
*| OCM | 0xFFFC0000 - 0xFFFFFFFF | Normal write-back Cacheable |
*
*
* @note
* For a system where DDR is less than 2GB, region after DDR and before PL is
* marked as undefined in translation table. Memory range 0xFE000000-0xFEFFFFFF is
* allocated for upper LPS slaves, where as memory region 0xFF000000-0xFFFFFFFF is
* allocated for lower LPS slaves.
*
* @{
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------
* 5.00 pkp 02/10/14 Initial version
* 6.4 asa 08/16/17 Added many APIs for MPU access to make MPU usage
* user-friendly. The APIs added are: Xil_UpdateMPUConfig,
* Xil_GetMPUConfig, Xil_GetNumOfFreeRegions,
* Xil_GetNextMPURegion, Xil_DisableMPURegionByRegNum,
* Xil_GetMPUFreeRegMask, Xil_SetMPURegionByRegNum, and
* Xil_InitializeExistingMPURegConfig.
* Added a new array of structure of type XMpuConfig to
* represent the MPU configuration table.
* </pre>
*
*
*
******************************************************************************/
#ifndef XIL_MPU_H
#define XIL_MPU_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include "xil_types.h"
/***************************** Include Files *********************************/
/***************** Macros (Inline Functions) Definitions *********************/
#define MPU_REG_DISABLED 0U
#define MPU_REG_ENABLED 1U
#define MAX_POSSIBLE_MPU_REGS 16U
/**************************** Type Definitions *******************************/
struct XMpuConfig{
u32 RegionStatus; /* Enabled or disabled */
INTPTR BaseAddress;/* MPU region base address */
u64 Size; /* MPU region size address */
u32 Attribute; /* MPU region size attribute */
};
typedef struct XMpuConfig XMpu_Config[MAX_POSSIBLE_MPU_REGS];
extern XMpu_Config Mpu_Config;
/************************** Constant Definitions *****************************/
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
void Xil_SetTlbAttributes(INTPTR Addr, u32 attrib);
void Xil_EnableMPU(void);
void Xil_DisableMPU(void);
u32 Xil_SetMPURegion(INTPTR addr, u64 size, u32 attrib);
u32 Xil_UpdateMPUConfig(u32 reg_num, INTPTR address, u32 size, u32 attrib);
void Xil_GetMPUConfig (XMpu_Config mpuconfig);
u32 Xil_GetNumOfFreeRegions (void);
u32 Xil_GetNextMPURegion(void);
u32 Xil_DisableMPURegionByRegNum (u32 reg_num);
u16 Xil_GetMPUFreeRegMask (void);
u32 Xil_SetMPURegionByRegNum (u32 reg_num, INTPTR addr, u64 size, u32 attrib);
void* Xil_MemMap(UINTPTR Physaddr, size_t size, u32 flags);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* XIL_MPU_H */
/**
* @} End of "addtogroup r5_mpu_apis".
*/

View File

@ -0,0 +1,249 @@
/******************************************************************************
*
* Copyright (C) 2014 - 2016 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xpseudo_asm_gcc.h
*
* This header file contains macros for using inline assembler code. It is
* written specifically for the GNU compiler.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- -------- -------- -----------------------------------------------
* 5.00 pkp 05/21/14 First release
* 6.0 mus 07/27/16 Consolidated file for a53,a9 and r5 processors
* </pre>
*
******************************************************************************/
#ifndef XPSEUDO_ASM_GCC_H /* prevent circular inclusions */
#define XPSEUDO_ASM_GCC_H /* by using protection macros */
/***************************** Include Files ********************************/
#include <rtdef.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/************************** Constant Definitions ****************************/
/**************************** Type Definitions ******************************/
/***************** Macros (Inline Functions) Definitions ********************/
/* necessary for pre-processor */
#define stringify(s) tostring(s)
#define tostring(s) #s
#if defined (__aarch64__)
/* pseudo assembler instructions */
#define mfcpsr() ({rt_uint32_t rval = 0U; \
asm volatile("mrs %0, DAIF" : "=r" (rval));\
rval;\
})
#define mtcpsr(v) __asm__ __volatile__ ("msr DAIF, %0" : : "r" (v))
#define cpsiei() //__asm__ __volatile__("cpsie i\n")
#define cpsidi() //__asm__ __volatile__("cpsid i\n")
#define cpsief() //__asm__ __volatile__("cpsie f\n")
#define cpsidf() //__asm__ __volatile__("cpsid f\n")
#define mtgpr(rn, v) /*__asm__ __volatile__(\
"mov r" stringify(rn) ", %0 \n"\
: : "r" (v)\
)*/
#define mfgpr(rn) /*({rt_uint32_t rval; \
__asm__ __volatile__(\
"mov %0,r" stringify(rn) "\n"\
: "=r" (rval)\
);\
rval;\
})*/
/* memory synchronization operations */
/* Instruction Synchronization Barrier */
#define isb() __asm__ __volatile__ ("isb sy")
/* Data Synchronization Barrier */
#define dsb() __asm__ __volatile__("dsb sy")
/* Data Memory Barrier */
#define dmb() __asm__ __volatile__("dmb sy")
/* Memory Operations */
#define ldr(adr) ({u64 rval; \
__asm__ __volatile__(\
"ldr %0,[%1]"\
: "=r" (rval) : "r" (adr)\
);\
rval;\
})
#define mfelrel3() ({u64 rval = 0U; \
asm volatile("mrs %0, ELR_EL3" : "=r" (rval));\
rval;\
})
#define mtelrel3(v) __asm__ __volatile__ ("msr ELR_EL3, %0" : : "r" (v))
#else
/* pseudo assembler instructions */
#define mfcpsr() ({rt_uint32_t rval = 0U; \
__asm__ __volatile__(\
"mrs %0, cpsr\n"\
: "=r" (rval)\
);\
rval;\
})
#define mtcpsr(v) __asm__ __volatile__(\
"msr cpsr,%0\n"\
: : "r" (v)\
)
#define cpsiei() __asm__ __volatile__("cpsie i\n")
#define cpsidi() __asm__ __volatile__("cpsid i\n")
#define cpsief() __asm__ __volatile__("cpsie f\n")
#define cpsidf() __asm__ __volatile__("cpsid f\n")
#define mtgpr(rn, v) __asm__ __volatile__(\
"mov r" stringify(rn) ", %0 \n"\
: : "r" (v)\
)
#define mfgpr(rn) ({rt_uint32_t rval; \
__asm__ __volatile__(\
"mov %0,r" stringify(rn) "\n"\
: "=r" (rval)\
);\
rval;\
})
/* memory synchronization operations */
/* Instruction Synchronization Barrier */
#define isb() __asm__ __volatile__ ("isb" : : : "memory")
/* Data Synchronization Barrier */
#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
/* Data Memory Barrier */
#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
/* Memory Operations */
#define ldr(adr) ({rt_uint32_t rval; \
__asm__ __volatile__(\
"ldr %0,[%1]"\
: "=r" (rval) : "r" (adr)\
);\
rval;\
})
#endif
#define ldrb(adr) ({rt_uint8_t rval; \
__asm__ __volatile__(\
"ldrb %0,[%1]"\
: "=r" (rval) : "r" (adr)\
);\
rval;\
})
#define str(adr, val) __asm__ __volatile__(\
"str %0,[%1]\n"\
: : "r" (val), "r" (adr)\
)
#define strb(adr, val) __asm__ __volatile__(\
"strb %0,[%1]\n"\
: : "r" (val), "r" (adr)\
)
/* Count leading zeroes (clz) */
#define clz(arg) ({rt_uint8_t rval; \
__asm__ __volatile__(\
"clz %0,%1"\
: "=r" (rval) : "r" (arg)\
);\
rval;\
})
#if defined (__aarch64__)
#define mtcpdc(reg,val) __asm__ __volatile__("dc " #reg ",%0" : : "r" (val))
#define mtcpic(reg,val) __asm__ __volatile__("ic " #reg ",%0" : : "r" (val))
#define mtcpicall(reg) __asm__ __volatile__("ic " #reg)
#define mtcptlbi(reg) __asm__ __volatile__("tlbi " #reg)
#define mtcpat(reg,val) __asm__ __volatile__("at " #reg ",%0" : : "r" (val))
/* CP15 operations */
#define mfcp(reg) ({u64 rval = 0U;\
__asm__ __volatile__("mrs %0, " #reg : "=r" (rval));\
rval;\
})
#define mtcp(reg,val) __asm__ __volatile__("msr " #reg ",%0" : : "r" (val))
#else
/* CP15 operations */
#define mtcp(rn, v) __asm__ __volatile__(\
"mcr " rn "\n"\
: : "r" (v)\
);
#define mfcp(rn) ({rt_uint32_t rval = 0U; \
__asm__ __volatile__(\
"mrc " rn "\n"\
: "=r" (rval)\
);\
rval;\
})
#endif
/************************** Variable Definitions ****************************/
/************************** Function Prototypes *****************************/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* XPSEUDO_ASM_GCC_H */

View File

@ -0,0 +1,419 @@
/******************************************************************************
* Copyright (c) 2014 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xreg_cortexr5.h
*
* This header file contains definitions for using inline assembler code. It is
* written specifically for the GNU, IAR, ARMCC compiler.
*
* All of the ARM Cortex R5 GPRs, SPRs, and Debug Registers are defined along
* with the positions of the bits within the registers.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- -------- -------- -----------------------------------------------
* 5.00 pkp 02/10/14 Initial version
* </pre>
*
******************************************************************************/
#ifndef XREG_CORTEXR5_H /* prevent circular inclusions */
#define XREG_CORTEXR5_H /* by using protection macros */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* GPRs */
#define XREG_GPR0 r0
#define XREG_GPR1 r1
#define XREG_GPR2 r2
#define XREG_GPR3 r3
#define XREG_GPR4 r4
#define XREG_GPR5 r5
#define XREG_GPR6 r6
#define XREG_GPR7 r7
#define XREG_GPR8 r8
#define XREG_GPR9 r9
#define XREG_GPR10 r10
#define XREG_GPR11 r11
#define XREG_GPR12 r12
#define XREG_GPR13 r13
#define XREG_GPR14 r14
#define XREG_GPR15 r15
#define XREG_CPSR cpsr
/* Coprocessor number defines */
#define XREG_CP0 0
#define XREG_CP1 1
#define XREG_CP2 2
#define XREG_CP3 3
#define XREG_CP4 4
#define XREG_CP5 5
#define XREG_CP6 6
#define XREG_CP7 7
#define XREG_CP8 8
#define XREG_CP9 9
#define XREG_CP10 10
#define XREG_CP11 11
#define XREG_CP12 12
#define XREG_CP13 13
#define XREG_CP14 14
#define XREG_CP15 15
/* Coprocessor control register defines */
#define XREG_CR0 cr0
#define XREG_CR1 cr1
#define XREG_CR2 cr2
#define XREG_CR3 cr3
#define XREG_CR4 cr4
#define XREG_CR5 cr5
#define XREG_CR6 cr6
#define XREG_CR7 cr7
#define XREG_CR8 cr8
#define XREG_CR9 cr9
#define XREG_CR10 cr10
#define XREG_CR11 cr11
#define XREG_CR12 cr12
#define XREG_CR13 cr13
#define XREG_CR14 cr14
#define XREG_CR15 cr15
/* Current Processor Status Register (CPSR) Bits */
#define XREG_CPSR_THUMB_MODE 0x20U
#define XREG_CPSR_MODE_BITS 0x1FU
#define XREG_CPSR_SYSTEM_MODE 0x1FU
#define XREG_CPSR_UNDEFINED_MODE 0x1BU
#define XREG_CPSR_DATA_ABORT_MODE 0x17U
#define XREG_CPSR_SVC_MODE 0x13U
#define XREG_CPSR_IRQ_MODE 0x12U
#define XREG_CPSR_FIQ_MODE 0x11U
#define XREG_CPSR_USER_MODE 0x10U
#define XREG_CPSR_IRQ_ENABLE 0x80U
#define XREG_CPSR_FIQ_ENABLE 0x40U
#define XREG_CPSR_N_BIT 0x80000000U
#define XREG_CPSR_Z_BIT 0x40000000U
#define XREG_CPSR_C_BIT 0x20000000U
#define XREG_CPSR_V_BIT 0x10000000U
/*MPU region definitions*/
#define REGION_32B 0x00000004U
#define REGION_64B 0x00000005U
#define REGION_128B 0x00000006U
#define REGION_256B 0x00000007U
#define REGION_512B 0x00000008U
#define REGION_1K 0x00000009U
#define REGION_2K 0x0000000AU
#define REGION_4K 0x0000000BU
#define REGION_8K 0x0000000CU
#define REGION_16K 0x0000000DU
#define REGION_32K 0x0000000EU
#define REGION_64K 0x0000000FU
#define REGION_128K 0x00000010U
#define REGION_256K 0x00000011U
#define REGION_512K 0x00000012U
#define REGION_1M 0x00000013U
#define REGION_2M 0x00000014U
#define REGION_4M 0x00000015U
#define REGION_8M 0x00000016U
#define REGION_16M 0x00000017U
#define REGION_32M 0x00000018U
#define REGION_64M 0x00000019U
#define REGION_128M 0x0000001AU
#define REGION_256M 0x0000001BU
#define REGION_512M 0x0000001CU
#define REGION_1G 0x0000001DU
#define REGION_2G 0x0000001EU
#define REGION_4G 0x0000001FU
#define REGION_EN 0x00000001U
#define SHAREABLE 0x00000004U /*shareable */
#define STRONG_ORDERD_SHARED 0x00000000U /*strongly ordered, always shareable*/
#define DEVICE_SHARED 0x00000001U /*device, shareable*/
#define DEVICE_NONSHARED 0x00000010U /*device, non shareable*/
#define NORM_NSHARED_WT_NWA 0x00000002U /*Outer and Inner write-through, no write-allocate non-shareable*/
#define NORM_SHARED_WT_NWA 0x00000006U /*Outer and Inner write-through, no write-allocate shareable*/
#define NORM_NSHARED_WB_NWA 0x00000003U /*Outer and Inner write-back, no write-allocate non shareable*/
#define NORM_SHARED_WB_NWA 0x00000007U /*Outer and Inner write-back, no write-allocate shareable*/
#define NORM_NSHARED_NCACHE 0x00000008U /*Outer and Inner Non cacheable non shareable*/
#define NORM_SHARED_NCACHE 0x0000000CU /*Outer and Inner Non cacheable shareable*/
#define NORM_NSHARED_WB_WA 0x0000000BU /*Outer and Inner write-back non shared*/
#define NORM_SHARED_WB_WA 0x0000000FU /*Outer and Inner write-back shared*/
/* inner and outer cache policies can be combined for different combinations */
#define NORM_IN_POLICY_NCACHE 0x00000020U /*inner non cacheable*/
#define NORM_IN_POLICY_WB_WA 0x00000021U /*inner write back write allocate*/
#define NORM_IN_POLICY_WT_NWA 0x00000022U /*inner write through no write allocate*/
#define NORM_IN_POLICY_WB_NWA 0x00000023U /*inner write back no write allocate*/
#define NORM_OUT_POLICY_NCACHE 0x00000020U /*outer non cacheable*/
#define NORM_OUT_POLICY_WB_WA 0x00000028U /*outer write back write allocate*/
#define NORM_OUT_POLICY_WT_NWA 0x00000030U /*outer write through no write allocate*/
#define NORM_OUT_POLICY_WB_NWA 0x00000038U /*outer write back no write allocate*/
#define NO_ACCESS (0x00000000U<<8U) /*No access*/
#define PRIV_RW_USER_NA (0x00000001U<<8U) /*Privileged access only*/
#define PRIV_RW_USER_RO (0x00000002U<<8U) /*Writes in User mode generate permission faults*/
#define PRIV_RW_USER_RW (0x00000003U<<8U) /*Full Access*/
#define PRIV_RO_USER_NA (0x00000005U<<8U) /*Privileged eead only*/
#define PRIV_RO_USER_RO (0x00000006U<<8U) /*Privileged/User read-only*/
#define EXECUTE_NEVER (0x00000001U<<12U) /* Bit 12*/
/* CP15 defines */
/* C0 Register defines */
#define XREG_CP15_MAIN_ID "p15, 0, %0, c0, c0, 0"
#define XREG_CP15_CACHE_TYPE "p15, 0, %0, c0, c0, 1"
#define XREG_CP15_TCM_TYPE "p15, 0, %0, c0, c0, 2"
#define XREG_CP15_TLB_TYPE "p15, 0, %0, c0, c0, 3"
#define XREG_CP15_MPU_TYPE "p15, 0, %0, c0, c0, 4"
#define XREG_CP15_MULTI_PROC_AFFINITY "p15, 0, %0, c0, c0, 5"
#define XREG_CP15_PROC_FEATURE_0 "p15, 0, %0, c0, c1, 0"
#define XREG_CP15_PROC_FEATURE_1 "p15, 0, %0, c0, c1, 1"
#define XREG_CP15_DEBUG_FEATURE_0 "p15, 0, %0, c0, c1, 2"
#define XREG_CP15_MEMORY_FEATURE_0 "p15, 0, %0, c0, c1, 4"
#define XREG_CP15_MEMORY_FEATURE_1 "p15, 0, %0, c0, c1, 5"
#define XREG_CP15_MEMORY_FEATURE_2 "p15, 0, %0, c0, c1, 6"
#define XREG_CP15_MEMORY_FEATURE_3 "p15, 0, %0, c0, c1, 7"
#define XREG_CP15_INST_FEATURE_0 "p15, 0, %0, c0, c2, 0"
#define XREG_CP15_INST_FEATURE_1 "p15, 0, %0, c0, c2, 1"
#define XREG_CP15_INST_FEATURE_2 "p15, 0, %0, c0, c2, 2"
#define XREG_CP15_INST_FEATURE_3 "p15, 0, %0, c0, c2, 3"
#define XREG_CP15_INST_FEATURE_4 "p15, 0, %0, c0, c2, 4"
#define XREG_CP15_INST_FEATURE_5 "p15, 0, %0, c0, c2, 5"
#define XREG_CP15_CACHE_SIZE_ID "p15, 1, %0, c0, c0, 0"
#define XREG_CP15_CACHE_LEVEL_ID "p15, 1, %0, c0, c0, 1"
#define XREG_CP15_AUXILARY_ID "p15, 1, %0, c0, c0, 7"
#define XREG_CP15_CACHE_SIZE_SEL "p15, 2, %0, c0, c0, 0"
/* C1 Register Defines */
#define XREG_CP15_SYS_CONTROL "p15, 0, %0, c1, c0, 0"
#define XREG_CP15_AUX_CONTROL "p15, 0, %0, c1, c0, 1"
#define XREG_CP15_CP_ACCESS_CONTROL "p15, 0, %0, c1, c0, 2"
/* XREG_CP15_CONTROL bit defines */
#define XREG_CP15_CONTROL_TE_BIT 0x40000000U
#define XREG_CP15_CONTROL_AFE_BIT 0x20000000U
#define XREG_CP15_CONTROL_TRE_BIT 0x10000000U
#define XREG_CP15_CONTROL_NMFI_BIT 0x08000000U
#define XREG_CP15_CONTROL_EE_BIT 0x02000000U
#define XREG_CP15_CONTROL_HA_BIT 0x00020000U
#define XREG_CP15_CONTROL_RR_BIT 0x00004000U
#define XREG_CP15_CONTROL_V_BIT 0x00002000U
#define XREG_CP15_CONTROL_I_BIT 0x00001000U
#define XREG_CP15_CONTROL_Z_BIT 0x00000800U
#define XREG_CP15_CONTROL_SW_BIT 0x00000400U
#define XREG_CP15_CONTROL_B_BIT 0x00000080U
#define XREG_CP15_CONTROL_C_BIT 0x00000004U
#define XREG_CP15_CONTROL_A_BIT 0x00000002U
#define XREG_CP15_CONTROL_M_BIT 0x00000001U
/* C2 Register Defines */
/* Not Used */
/* C3 Register Defines */
/* Not Used */
/* C4 Register Defines */
/* Not Used */
/* C5 Register Defines */
#define XREG_CP15_DATA_FAULT_STATUS "p15, 0, %0, c5, c0, 0"
#define XREG_CP15_INST_FAULT_STATUS "p15, 0, %0, c5, c0, 1"
#define XREG_CP15_AUX_DATA_FAULT_STATUS "p15, 0, %0, c5, c1, 0"
#define XREG_CP15_AUX_INST_FAULT_STATUS "p15, 0, %0, c5, c1, 1"
/* C6 Register Defines */
#define XREG_CP15_DATA_FAULT_ADDRESS "p15, 0, %0, c6, c0, 0"
#define XREG_CP15_INST_FAULT_ADDRESS "p15, 0, %0, c6, c0, 2"
#define XREG_CP15_MPU_REG_BASEADDR "p15, 0, %0, c6, c1, 0"
#define XREG_CP15_MPU_REG_SIZE_EN "p15, 0, %0, c6, c1, 2"
#define XREG_CP15_MPU_REG_ACCESS_CTRL "p15, 0, %0, c6, c1, 4"
#define XREG_CP15_MPU_MEMORY_REG_NUMBER "p15, 0, %0, c6, c2, 0"
/* C7 Register Defines */
#define XREG_CP15_NOP "p15, 0, %0, c7, c0, 4"
#define XREG_CP15_INVAL_IC_POU "p15, 0, %0, c7, c5, 0"
#define XREG_CP15_INVAL_IC_LINE_MVA_POU "p15, 0, %0, c7, c5, 1"
/* The CP15 register access below has been deprecated in favor of the new
* isb instruction in Cortex R5.
*/
#define XREG_CP15_INST_SYNC_BARRIER "p15, 0, %0, c7, c5, 4"
#define XREG_CP15_INVAL_BRANCH_ARRAY "p15, 0, %0, c7, c5, 6"
#define XREG_CP15_INVAL_BRANCH_ARRAY_LINE "p15, 0, %0, c7, c5, 7"
#define XREG_CP15_INVAL_DC_LINE_MVA_POC "p15, 0, %0, c7, c6, 1"
#define XREG_CP15_INVAL_DC_LINE_SW "p15, 0, %0, c7, c6, 2"
#define XREG_CP15_CLEAN_DC_LINE_MVA_POC "p15, 0, %0, c7, c10, 1"
#define XREG_CP15_CLEAN_DC_LINE_SW "p15, 0, %0, c7, c10, 2"
#define XREG_CP15_INVAL_DC_ALL "p15, 0, %0, c15, c5, 0"
/* The next two CP15 register accesses below have been deprecated in favor
* of the new dsb and dmb instructions in Cortex R5.
*/
#define XREG_CP15_DATA_SYNC_BARRIER "p15, 0, %0, c7, c10, 4"
#define XREG_CP15_DATA_MEMORY_BARRIER "p15, 0, %0, c7, c10, 5"
#define XREG_CP15_CLEAN_DC_LINE_MVA_POU "p15, 0, %0, c7, c11, 1"
#define XREG_CP15_NOP2 "p15, 0, %0, c7, c13, 1"
#define XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC "p15, 0, %0, c7, c14, 1"
#define XREG_CP15_CLEAN_INVAL_DC_LINE_SW "p15, 0, %0, c7, c14, 2"
/* C8 Register Defines */
/* Not Used */
/* C9 Register Defines */
#define XREG_CP15_ATCM_REG_SIZE_ADDR "p15, 0, %0, c9, c1, 1"
#define XREG_CP15_BTCM_REG_SIZE_ADDR "p15, 0, %0, c9, c1, 0"
#define XREG_CP15_TCM_SELECTION "p15, 0, %0, c9, c2, 0"
#define XREG_CP15_PERF_MONITOR_CTRL "p15, 0, %0, c9, c12, 0"
#define XREG_CP15_COUNT_ENABLE_SET "p15, 0, %0, c9, c12, 1"
#define XREG_CP15_COUNT_ENABLE_CLR "p15, 0, %0, c9, c12, 2"
#define XREG_CP15_V_FLAG_STATUS "p15, 0, %0, c9, c12, 3"
#define XREG_CP15_SW_INC "p15, 0, %0, c9, c12, 4"
#define XREG_CP15_EVENT_CNTR_SEL "p15, 0, %0, c9, c12, 5"
#define XREG_CP15_PERF_CYCLE_COUNTER "p15, 0, %0, c9, c13, 0"
#define XREG_CP15_EVENT_TYPE_SEL "p15, 0, %0, c9, c13, 1"
#define XREG_CP15_PERF_MONITOR_COUNT "p15, 0, %0, c9, c13, 2"
#define XREG_CP15_USER_ENABLE "p15, 0, %0, c9, c14, 0"
#define XREG_CP15_INTR_ENABLE_SET "p15, 0, %0, c9, c14, 1"
#define XREG_CP15_INTR_ENABLE_CLR "p15, 0, %0, c9, c14, 2"
/* C10 Register Defines */
/* Not used */
/* C11 Register Defines */
/* Not used */
/* C12 Register Defines */
/* Not used */
/* C13 Register Defines */
#define XREG_CP15_CONTEXT_ID "p15, 0, %0, c13, c0, 1"
#define USER_RW_THREAD_PID "p15, 0, %0, c13, c0, 2"
#define USER_RO_THREAD_PID "p15, 0, %0, c13, c0, 3"
#define USER_PRIV_THREAD_PID "p15, 0, %0, c13, c0, 4"
/* C14 Register Defines */
/* not used */
/* C15 Register Defines */
#define XREG_CP15_SEC_AUX_CTRL "p15, 0, %0, c15, c0, 0"
/* MPE register definitions */
#define XREG_FPSID c0
#define XREG_FPSCR c1
#define XREG_MVFR1 c6
#define XREG_MVFR0 c7
#define XREG_FPEXC c8
#define XREG_FPINST c9
#define XREG_FPINST2 c10
/* FPSID bits */
#define XREG_FPSID_IMPLEMENTER_BIT (24U)
#define XREG_FPSID_IMPLEMENTER_MASK (0x000000FFU << FPSID_IMPLEMENTER_BIT)
#define XREG_FPSID_SOFTWARE (0X00000001U << 23U)
#define XREG_FPSID_ARCH_BIT (16U)
#define XREG_FPSID_ARCH_MASK (0x0000000FU << FPSID_ARCH_BIT)
#define XREG_FPSID_PART_BIT (8U)
#define XREG_FPSID_PART_MASK (0x000000FFU << FPSID_PART_BIT)
#define XREG_FPSID_VARIANT_BIT (4U)
#define XREG_FPSID_VARIANT_MASK (0x0000000FU << FPSID_VARIANT_BIT)
#define XREG_FPSID_REV_BIT (0U)
#define XREG_FPSID_REV_MASK (0x0000000FU << FPSID_REV_BIT)
/* FPSCR bits */
#define XREG_FPSCR_N_BIT (0X00000001U << 31U)
#define XREG_FPSCR_Z_BIT (0X00000001U << 30U)
#define XREG_FPSCR_C_BIT (0X00000001U << 29U)
#define XREG_FPSCR_V_BIT (0X00000001U << 28U)
#define XREG_FPSCR_QC (0X00000001U << 27U)
#define XREG_FPSCR_AHP (0X00000001U << 26U)
#define XREG_FPSCR_DEFAULT_NAN (0X00000001U << 25U)
#define XREG_FPSCR_FLUSHTOZERO (0X00000001U << 24U)
#define XREG_FPSCR_ROUND_NEAREST (0X00000000U << 22U)
#define XREG_FPSCR_ROUND_PLUSINF (0X00000001U << 22U)
#define XREG_FPSCR_ROUND_MINUSINF (0X00000002U << 22U)
#define XREG_FPSCR_ROUND_TOZERO (0X00000003U << 22U)
#define XREG_FPSCR_RMODE_BIT (22U)
#define XREG_FPSCR_RMODE_MASK (0X00000003U << FPSCR_RMODE_BIT)
#define XREG_FPSCR_STRIDE_BIT (20U)
#define XREG_FPSCR_STRIDE_MASK (0X00000003U << FPSCR_STRIDE_BIT)
#define XREG_FPSCR_LENGTH_BIT (16U)
#define XREG_FPSCR_LENGTH_MASK (0X00000007U << FPSCR_LENGTH_BIT)
#define XREG_FPSCR_IDC (0X00000001U << 7U)
#define XREG_FPSCR_IXC (0X00000001U << 4U)
#define XREG_FPSCR_UFC (0X00000001U << 3U)
#define XREG_FPSCR_OFC (0X00000001U << 2U)
#define XREG_FPSCR_DZC (0X00000001U << 1U)
#define XREG_FPSCR_IOC (0X00000001U << 0U)
/* MVFR0 bits */
#define XREG_MVFR0_RMODE_BIT (28U)
#define XREG_MVFR0_RMODE_MASK (0x0000000FU << XREG_MVFR0_RMODE_BIT)
#define XREG_MVFR0_SHORT_VEC_BIT (24U)
#define XREG_MVFR0_SHORT_VEC_MASK (0x0000000FU << XREG_MVFR0_SHORT_VEC_BIT)
#define XREG_MVFR0_SQRT_BIT (20U)
#define XREG_MVFR0_SQRT_MASK (0x0000000FU << XREG_MVFR0_SQRT_BIT)
#define XREG_MVFR0_DIVIDE_BIT (16U)
#define XREG_MVFR0_DIVIDE_MASK (0x0000000FU << XREG_MVFR0_DIVIDE_BIT)
#define XREG_MVFR0_EXEC_TRAP_BIT (12U)
#define XREG_MVFR0_EXEC_TRAP_MASK (0x0000000FU << XREG_MVFR0_EXEC_TRAP_BIT)
#define XREG_MVFR0_DP_BIT (8U)
#define XREG_MVFR0_DP_MASK (0x0000000FU << XREG_MVFR0_DP_BIT)
#define XREG_MVFR0_SP_BIT (4U)
#define XREG_MVFR0_SP_MASK (0x0000000FU << XREG_MVFR0_SP_BIT)
#define XREG_MVFR0_A_SIMD_BIT (0U)
#define XREG_MVFR0_A_SIMD_MASK (0x0000000FU << MVFR0_A_SIMD_BIT)
/* FPEXC bits */
#define XREG_FPEXC_EX (0X00000001U << 31U)
#define XREG_FPEXC_EN (0X00000001U << 30U)
#define XREG_FPEXC_DEX (0X00000001U << 29U)
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* XREG_CORTEXR5_H */