From bd8e67c2e34bb5cc3ba19bcbd6f6271a89e3a978 Mon Sep 17 00:00:00 2001 From: Yajun Xia Date: Thu, 14 Sep 2023 17:14:49 +0800 Subject: [PATCH 1/2] Fixed the issue of the data/bss section cannot be read from ARM FVP debug tool in cortex-A7 GNU port. https://msazure.visualstudio.com/One/_workitems/edit/24597276/ --- ports/cortex_a12/gnu/example_build/crt0.S | 8 + .../gnu/example_build/sample_threadx.ld | 2 +- ports/cortex_a12/gnu/example_build/v7.h | 155 ++++++ ports/cortex_a12/gnu/example_build/v7.s | 476 ++++++++++++++++++ ports/cortex_a15/gnu/example_build/crt0.S | 8 + .../gnu/example_build/sample_threadx.ld | 2 +- ports/cortex_a15/gnu/example_build/v7.h | 155 ++++++ ports/cortex_a15/gnu/example_build/v7.s | 476 ++++++++++++++++++ ports/cortex_a17/gnu/example_build/crt0.S | 8 + .../gnu/example_build/sample_threadx.ld | 2 +- ports/cortex_a17/gnu/example_build/v7.h | 155 ++++++ ports/cortex_a17/gnu/example_build/v7.s | 476 ++++++++++++++++++ ports/cortex_a5/gnu/example_build/crt0.S | 8 + .../gnu/example_build/sample_threadx.ld | 2 +- ports/cortex_a5/gnu/example_build/v7.h | 155 ++++++ ports/cortex_a5/gnu/example_build/v7.s | 476 ++++++++++++++++++ ports/cortex_a7/gnu/example_build/MP_GIC.h | 74 +++ ports/cortex_a7/gnu/example_build/MP_GIC.s | 294 +++++++++++ .../gnu/example_build/MP_PrivateTimer.S | 84 ++++ .../gnu/example_build/MP_PrivateTimer.h | 36 ++ .../example_build/build_threadx_sample.bat | 8 +- ports/cortex_a7/gnu/example_build/crt0.S | 8 + .../gnu/example_build/sample_threadx.ld | 2 +- .../gnu/example_build/sample_threadx.out | Bin 0 -> 292972 bytes ports/cortex_a7/gnu/example_build/test.log | 18 + .../example_build/tx_initialize_low_level.S | 74 ++- ports/cortex_a7/gnu/example_build/v7.h | 155 ++++++ ports/cortex_a7/gnu/example_build/v7.s | 476 ++++++++++++++++++ ports/cortex_a8/gnu/example_build/crt0.S | 8 + .../gnu/example_build/sample_threadx.ld | 2 +- ports/cortex_a8/gnu/example_build/v7.h | 155 ++++++ ports/cortex_a8/gnu/example_build/v7.s | 476 ++++++++++++++++++ ports/cortex_a9/gnu/example_build/crt0.S | 8 + .../gnu/example_build/sample_threadx.ld | 2 +- ports/cortex_a9/gnu/example_build/v7.h | 155 ++++++ ports/cortex_a9/gnu/example_build/v7.s | 476 ++++++++++++++++++ .../threadx/ports/gnu/example_build/crt0.S | 8 + .../ports/gnu/example_build/sample_threadx.ld | 2 +- .../example_build/tx_initialize_low_level.S | 311 ------------ .../threadx/ports/gnu/example_build/v7.h | 155 ++++++ .../threadx/ports/gnu/example_build/v7.s | 476 ++++++++++++++++++ .../azrtos_test_tx_gnu_cortex_a7.log.expected | 16 +- 42 files changed, 5695 insertions(+), 348 deletions(-) create mode 100644 ports/cortex_a12/gnu/example_build/v7.h create mode 100644 ports/cortex_a12/gnu/example_build/v7.s create mode 100644 ports/cortex_a15/gnu/example_build/v7.h create mode 100644 ports/cortex_a15/gnu/example_build/v7.s create mode 100644 ports/cortex_a17/gnu/example_build/v7.h create mode 100644 ports/cortex_a17/gnu/example_build/v7.s create mode 100644 ports/cortex_a5/gnu/example_build/v7.h create mode 100644 ports/cortex_a5/gnu/example_build/v7.s create mode 100644 ports/cortex_a7/gnu/example_build/MP_GIC.h create mode 100644 ports/cortex_a7/gnu/example_build/MP_GIC.s create mode 100644 ports/cortex_a7/gnu/example_build/MP_PrivateTimer.S create mode 100644 ports/cortex_a7/gnu/example_build/MP_PrivateTimer.h create mode 100644 ports/cortex_a7/gnu/example_build/sample_threadx.out create mode 100644 ports/cortex_a7/gnu/example_build/test.log create mode 100644 ports/cortex_a7/gnu/example_build/v7.h create mode 100644 ports/cortex_a7/gnu/example_build/v7.s create mode 100644 ports/cortex_a8/gnu/example_build/v7.h create mode 100644 ports/cortex_a8/gnu/example_build/v7.s create mode 100644 ports/cortex_a9/gnu/example_build/v7.h create mode 100644 ports/cortex_a9/gnu/example_build/v7.s delete mode 100644 ports_arch/ARMv7-A/threadx/ports/gnu/example_build/tx_initialize_low_level.S create mode 100644 ports_arch/ARMv7-A/threadx/ports/gnu/example_build/v7.h create mode 100644 ports_arch/ARMv7-A/threadx/ports/gnu/example_build/v7.s diff --git a/ports/cortex_a12/gnu/example_build/crt0.S b/ports/cortex_a12/gnu/example_build/crt0.S index 56b6c9580..d25196ef6 100644 --- a/ports/cortex_a12/gnu/example_build/crt0.S +++ b/ports/cortex_a12/gnu/example_build/crt0.S @@ -79,6 +79,14 @@ _mainCRTStartup: #endif #endif + .global _fini + .type _fini,function +_fini: +#ifdef __THUMB_INTERWORK + BX lr // Return to caller +#else + MOV pc, lr // Return to caller +#endif /* Workspace for Angel calls. */ .data diff --git a/ports/cortex_a12/gnu/example_build/sample_threadx.ld b/ports/cortex_a12/gnu/example_build/sample_threadx.ld index 3dea4e1ca..cb42c11cb 100644 --- a/ports/cortex_a12/gnu/example_build/sample_threadx.ld +++ b/ports/cortex_a12/gnu/example_build/sample_threadx.ld @@ -109,7 +109,7 @@ SECTIONS .eh_frame_hdr : { *(.eh_frame_hdr) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); + . = 0x2E000000; .data : { *(.data) diff --git a/ports/cortex_a12/gnu/example_build/v7.h b/ports/cortex_a12/gnu/example_build/v7.h new file mode 100644 index 000000000..5a08b43fd --- /dev/null +++ b/ports/cortex_a12/gnu/example_build/v7.h @@ -0,0 +1,155 @@ +// ------------------------------------------------------------ +// v7-A Cache, TLB and Branch Prediction Maintenance Operations +// Header File +// +// Copyright (c) 2011-2016 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + +#ifndef _ARMV7A_GENERIC_H +#define _ARMV7A_GENERIC_H + +// ------------------------------------------------------------ +// Memory barrier mnemonics +enum MemBarOpt { + RESERVED_0 = 0, RESERVED_1 = 1, OSHST = 2, OSH = 3, + RESERVED_4 = 4, RESERVED_5 = 5, NSHST = 6, NSH = 7, + RESERVED_8 = 8, RESERVED_9 = 9, ISHST = 10, ISH = 11, + RESERVED_12 = 12, RESERVED_13 = 13, ST = 14, SY = 15 +}; + +// +// Note: +// *_IS() stands for "inner shareable" +// DO NOT USE THESE FUNCTIONS ON A CORTEX-A8 +// + +// ------------------------------------------------------------ +// Interrupts +// Enable/disables IRQs (not FIQs) +void enableInterrupts(void); +void disableInterrupts(void); + +// ------------------------------------------------------------ +// Caches + +void invalidateCaches_IS(void); +void cleanInvalidateDCache(void); +void invalidateCaches_IS(void); +void enableCaches(void); +void disableCaches(void); +void invalidateCaches(void); +void cleanDCache(void); + +// ------------------------------------------------------------ +// TLBs + +void invalidateUnifiedTLB(void); +void invalidateUnifiedTLB_IS(void); + +// ------------------------------------------------------------ +// Branch prediction + +void flushBranchTargetCache(void); +void flushBranchTargetCache_IS(void); + +// ------------------------------------------------------------ +// High Vecs + +void enableHighVecs(void); +void disableHighVecs(void); + +// ------------------------------------------------------------ +// ID Registers + +unsigned int getMIDR(void); + +#define MIDR_IMPL_SHIFT 24 +#define MIDR_IMPL_MASK 0xFF +#define MIDR_VAR_SHIFT 20 +#define MIDR_VAR_MASK 0xF +#define MIDR_ARCH_SHIFT 16 +#define MIDR_ARCH_MASK 0xF +#define MIDR_PART_SHIFT 4 +#define MIDR_PART_MASK 0xFFF +#define MIDR_REV_SHIFT 0 +#define MIDR_REV_MASK 0xF + +// tmp = get_MIDR(); +// implementor = (tmp >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; +// variant = (tmp >> MIDR_VAR_SHIFT) & MIDR_VAR_MASK; +// architecture= (tmp >> MIDR_ARCH_SHIFT) & MIDR_ARCH_MASK; +// part_number = (tmp >> MIDR_PART_SHIFT) & MIDR_PART_MASK; +// revision = tmp & MIDR_REV_MASK; + +#define MIDR_PART_CA5 0xC05 +#define MIDR_PART_CA8 0xC08 +#define MIDR_PART_CA9 0xC09 + +unsigned int getMPIDR(void); + +#define MPIDR_FORMAT_SHIFT 31 +#define MPIDR_FORMAT_MASK 0x1 +#define MPIDR_UBIT_SHIFT 30 +#define MPIDR_UBIT_MASK 0x1 +#define MPIDR_CLUSTER_SHIFT 7 +#define MPIDR_CLUSTER_MASK 0xF +#define MPIDR_CPUID_SHIFT 0 +#define MPIDR_CPUID_MASK 0x3 + +#define MPIDR_CPUID_CPU0 0x0 +#define MPIDR_CPUID_CPU1 0x1 +#define MPIDR_CPUID_CPU2 0x2 +#define MPIDR_CPUID_CPU3 0x3 + +#define MPIDR_UNIPROCESSPR 0x1 + +#define MPDIR_NEW_FORMAT 0x1 + +// ------------------------------------------------------------ +// Context ID + +unsigned int getContextID(void); + +void setContextID(unsigned int); + +#define CONTEXTID_ASID_SHIFT 0 +#define CONTEXTID_ASID_MASK 0xFF +#define CONTEXTID_PROCID_SHIFT 8 +#define CONTEXTID_PROCID_MASK 0x00FFFFFF + +// tmp = getContextID(); +// ASID = tmp & CONTEXTID_ASID_MASK; +// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK; + +// ------------------------------------------------------------ +// SMP related for Armv7-A MPCore processors +// +// DO NOT CALL THESE FUNCTIONS ON A CORTEX-A8 + +// Returns the base address of the private peripheral memory space +unsigned int getBaseAddr(void); + +// Returns the CPU ID (0 to 3) of the CPU executed on +#define MP_CPU0 (0) +#define MP_CPU1 (1) +#define MP_CPU2 (2) +#define MP_CPU3 (3) +unsigned int getCPUID(void); + +// Set this core as participating in SMP +void joinSMP(void); + +// Set this core as NOT participating in SMP +void leaveSMP(void); + +// Go to sleep, never returns +void goToSleep(void); + +#endif + +// ------------------------------------------------------------ +// End of v7.h +// ------------------------------------------------------------ diff --git a/ports/cortex_a12/gnu/example_build/v7.s b/ports/cortex_a12/gnu/example_build/v7.s new file mode 100644 index 000000000..82c9ab1e9 --- /dev/null +++ b/ports/cortex_a12/gnu/example_build/v7.s @@ -0,0 +1,476 @@ +// ------------------------------------------------------------ +// v7-A Cache and Branch Prediction Maintenance Operations +// +// Copyright (c) 2011-2018 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + + .arm +// ------------------------------------------------------------ +// Interrupt enable/disable +// ------------------------------------------------------------ + + // Could use intrinsic instead of these + + .global enableInterrupts + .type enableInterrupts,function + // void enableInterrupts(void)// +enableInterrupts: + CPSIE i + BX lr + + + .global disableInterrupts + .type disableInterrupts,function + // void disableInterrupts(void)// +disableInterrupts: + CPSID i + BX lr + + +// ------------------------------------------------------------ +// Cache Maintenance +// ------------------------------------------------------------ + + .global enableCaches + .type enableCaches,function + // void enableCaches(void)// +enableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + ORR r0, r0, #(1 << 2) // Set C bit + ORR r0, r0, #(1 << 12) // Set I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global disableCaches + .type disableCaches,function + // void disableCaches(void) +disableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + BIC r0, r0, #(1 << 2) // Clear C bit + BIC r0, r0, #(1 << 12) // Clear I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global cleanDCache + .type cleanDCache,function + // void cleanDCache(void)// +cleanDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_dcache_finished + MOV r10, #0 + +clean_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c10, 2 // DCCSW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_dcache_loop2 + +clean_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_dcache_loop1 + +clean_dcache_finished: + POP {r4-r12} + + BX lr + + + .global cleanInvalidateDCache + .type cleanInvalidateDCache,function + // void cleanInvalidateDCache(void)// +cleanInvalidateDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_invalidate_dcache_finished + MOV r10, #0 + +clean_invalidate_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_invalidate_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_invalidate_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_invalidate_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c14, 2 // DCCISW - clean and invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_invalidate_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_invalidate_dcache_loop2 + +clean_invalidate_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_invalidate_dcache_loop1 + +clean_invalidate_dcache_finished: + POP {r4-r12} + + BX lr + + + + .global invalidateCaches + .type invalidateCaches,function + // void invalidateCaches(void)// +invalidateCaches: + PUSH {r4-r12} + + // + // Based on code example given in section B2.2.4/11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 0 // ICIALLU - Invalidate entire I Cache, and flushes branch target cache + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_finished + MOV r10, #0 + +invalidate_caches_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_loop2 + +invalidate_caches_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_loop1 + +invalidate_caches_finished: + POP {r4-r12} + BX lr + + + + .global invalidateCaches_IS + .type invalidateCaches_IS,function + // void invalidateCaches_IS(void)// +invalidateCaches_IS: + PUSH {r4-r12} + + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 0 // ICIALLUIS - Invalidate entire I Cache inner shareable + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_is_finished + MOV r10, #0 + +invalidate_caches_is_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_is_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_is_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_is_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_is_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_is_loop2 + +invalidate_caches_is_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_is_loop1 + +invalidate_caches_is_finished: + POP {r4-r12} + BX lr + + +// ------------------------------------------------------------ +// TLB +// ------------------------------------------------------------ + + .global invalidateUnifiedTLB + .type invalidateUnifiedTLB,function + // void invalidateUnifiedTLB(void)// +invalidateUnifiedTLB: + MOV r0, #0 + MCR p15, 0, r0, c8, c7, 0 // TLBIALL - Invalidate entire unified TLB + BX lr + + + .global invalidateUnifiedTLB_IS + .type invalidateUnifiedTLB_IS,function + // void invalidateUnifiedTLB_IS(void)// +invalidateUnifiedTLB_IS: + MOV r0, #1 + MCR p15, 0, r0, c8, c3, 0 // TLBIALLIS - Invalidate entire unified TLB Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// Branch Prediction +// ------------------------------------------------------------ + + .global flushBranchTargetCache + .type flushBranchTargetCache,function + // void flushBranchTargetCache(void) +flushBranchTargetCache: + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 6 // BPIALL - Invalidate entire branch predictor array + BX lr + + + .global flushBranchTargetCache_IS + .type flushBranchTargetCache_IS,function + // void flushBranchTargetCache_IS(void) +flushBranchTargetCache_IS: + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 6 // BPIALLIS - Invalidate entire branch predictor array Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// High Vecs +// ------------------------------------------------------------ + + .global enableHighVecs + .type enableHighVecs,function + // void enableHighVecs(void)// +enableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + ORR r0, r0, #(1 << 13) // Set the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + + .global disableHighVecs + .type disableHighVecs,function + // void disable_highvecs(void)// +disableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + BIC r0, r0, #(1 << 13) // Clear the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + +// ------------------------------------------------------------ +// Context ID +// ------------------------------------------------------------ + + .global getContextID + .type getContextID,function + // uint32_t getContextIDd(void)// +getContextID: + MRC p15, 0, r0, c13, c0, 1 // Read Context ID Register + BX lr + + + .global setContextID + .type setContextID,function + // void setContextID(uint32_t)// +setContextID: + MCR p15, 0, r0, c13, c0, 1 // Write Context ID Register + BX lr + + +// ------------------------------------------------------------ +// ID registers +// ------------------------------------------------------------ + + .global getMIDR + .type getMIDR,function + // uint32_t getMIDR(void)// +getMIDR: + MRC p15, 0, r0, c0, c0, 0 // Read Main ID Register (MIDR) + BX lr + + + .global getMPIDR + .type getMPIDR,function + // uint32_t getMPIDR(void)// +getMPIDR: + MRC p15, 0, r0, c0 ,c0, 5// Read Multiprocessor ID register (MPIDR) + BX lr + + +// ------------------------------------------------------------ +// CP15 SMP related +// ------------------------------------------------------------ + + .global getBaseAddr + .type getBaseAddr,function + // uint32_t getBaseAddr(void) + // Returns the value CBAR (base address of the private peripheral memory space) +getBaseAddr: + MRC p15, 4, r0, c15, c0, 0 // Read peripheral base address + BX lr + + +// ------------------------------------------------------------ + + .global getCPUID + .type getCPUID,function + // uint32_t getCPUID(void) + // Returns the CPU ID (0 to 3) of the CPU executed on +getCPUID: + MRC p15, 0, r0, c0, c0, 5 // Read CPU ID register + AND r0, r0, #0x03 // Mask off, leaving the CPU ID field + BX lr + + +// ------------------------------------------------------------ + + .global goToSleep + .type goToSleep,function + // void goToSleep(void) +goToSleep: + DSB // Clear all pending data accesses + WFI // Go into standby + B goToSleep // Catch in case of rogue events + BX lr + + +// ------------------------------------------------------------ + + .global joinSMP + .type joinSMP,function + // void joinSMP(void) + // Sets the ACTRL.SMP bit +joinSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + MOV r1, r0 + ORR r0, r0, #0x040 // Set bit 6 + CMP r0, r1 + MCRNE p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ + + .global leaveSMP + .type leaveSMP,function + // void leaveSMP(void) + // Clear the ACTRL.SMP bit +leaveSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + BIC r0, r0, #0x040 // Clear bit 6 + MCR p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ +// End of v7.s +// ------------------------------------------------------------ diff --git a/ports/cortex_a15/gnu/example_build/crt0.S b/ports/cortex_a15/gnu/example_build/crt0.S index 56b6c9580..d25196ef6 100644 --- a/ports/cortex_a15/gnu/example_build/crt0.S +++ b/ports/cortex_a15/gnu/example_build/crt0.S @@ -79,6 +79,14 @@ _mainCRTStartup: #endif #endif + .global _fini + .type _fini,function +_fini: +#ifdef __THUMB_INTERWORK + BX lr // Return to caller +#else + MOV pc, lr // Return to caller +#endif /* Workspace for Angel calls. */ .data diff --git a/ports/cortex_a15/gnu/example_build/sample_threadx.ld b/ports/cortex_a15/gnu/example_build/sample_threadx.ld index 3dea4e1ca..cb42c11cb 100644 --- a/ports/cortex_a15/gnu/example_build/sample_threadx.ld +++ b/ports/cortex_a15/gnu/example_build/sample_threadx.ld @@ -109,7 +109,7 @@ SECTIONS .eh_frame_hdr : { *(.eh_frame_hdr) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); + . = 0x2E000000; .data : { *(.data) diff --git a/ports/cortex_a15/gnu/example_build/v7.h b/ports/cortex_a15/gnu/example_build/v7.h new file mode 100644 index 000000000..5a08b43fd --- /dev/null +++ b/ports/cortex_a15/gnu/example_build/v7.h @@ -0,0 +1,155 @@ +// ------------------------------------------------------------ +// v7-A Cache, TLB and Branch Prediction Maintenance Operations +// Header File +// +// Copyright (c) 2011-2016 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + +#ifndef _ARMV7A_GENERIC_H +#define _ARMV7A_GENERIC_H + +// ------------------------------------------------------------ +// Memory barrier mnemonics +enum MemBarOpt { + RESERVED_0 = 0, RESERVED_1 = 1, OSHST = 2, OSH = 3, + RESERVED_4 = 4, RESERVED_5 = 5, NSHST = 6, NSH = 7, + RESERVED_8 = 8, RESERVED_9 = 9, ISHST = 10, ISH = 11, + RESERVED_12 = 12, RESERVED_13 = 13, ST = 14, SY = 15 +}; + +// +// Note: +// *_IS() stands for "inner shareable" +// DO NOT USE THESE FUNCTIONS ON A CORTEX-A8 +// + +// ------------------------------------------------------------ +// Interrupts +// Enable/disables IRQs (not FIQs) +void enableInterrupts(void); +void disableInterrupts(void); + +// ------------------------------------------------------------ +// Caches + +void invalidateCaches_IS(void); +void cleanInvalidateDCache(void); +void invalidateCaches_IS(void); +void enableCaches(void); +void disableCaches(void); +void invalidateCaches(void); +void cleanDCache(void); + +// ------------------------------------------------------------ +// TLBs + +void invalidateUnifiedTLB(void); +void invalidateUnifiedTLB_IS(void); + +// ------------------------------------------------------------ +// Branch prediction + +void flushBranchTargetCache(void); +void flushBranchTargetCache_IS(void); + +// ------------------------------------------------------------ +// High Vecs + +void enableHighVecs(void); +void disableHighVecs(void); + +// ------------------------------------------------------------ +// ID Registers + +unsigned int getMIDR(void); + +#define MIDR_IMPL_SHIFT 24 +#define MIDR_IMPL_MASK 0xFF +#define MIDR_VAR_SHIFT 20 +#define MIDR_VAR_MASK 0xF +#define MIDR_ARCH_SHIFT 16 +#define MIDR_ARCH_MASK 0xF +#define MIDR_PART_SHIFT 4 +#define MIDR_PART_MASK 0xFFF +#define MIDR_REV_SHIFT 0 +#define MIDR_REV_MASK 0xF + +// tmp = get_MIDR(); +// implementor = (tmp >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; +// variant = (tmp >> MIDR_VAR_SHIFT) & MIDR_VAR_MASK; +// architecture= (tmp >> MIDR_ARCH_SHIFT) & MIDR_ARCH_MASK; +// part_number = (tmp >> MIDR_PART_SHIFT) & MIDR_PART_MASK; +// revision = tmp & MIDR_REV_MASK; + +#define MIDR_PART_CA5 0xC05 +#define MIDR_PART_CA8 0xC08 +#define MIDR_PART_CA9 0xC09 + +unsigned int getMPIDR(void); + +#define MPIDR_FORMAT_SHIFT 31 +#define MPIDR_FORMAT_MASK 0x1 +#define MPIDR_UBIT_SHIFT 30 +#define MPIDR_UBIT_MASK 0x1 +#define MPIDR_CLUSTER_SHIFT 7 +#define MPIDR_CLUSTER_MASK 0xF +#define MPIDR_CPUID_SHIFT 0 +#define MPIDR_CPUID_MASK 0x3 + +#define MPIDR_CPUID_CPU0 0x0 +#define MPIDR_CPUID_CPU1 0x1 +#define MPIDR_CPUID_CPU2 0x2 +#define MPIDR_CPUID_CPU3 0x3 + +#define MPIDR_UNIPROCESSPR 0x1 + +#define MPDIR_NEW_FORMAT 0x1 + +// ------------------------------------------------------------ +// Context ID + +unsigned int getContextID(void); + +void setContextID(unsigned int); + +#define CONTEXTID_ASID_SHIFT 0 +#define CONTEXTID_ASID_MASK 0xFF +#define CONTEXTID_PROCID_SHIFT 8 +#define CONTEXTID_PROCID_MASK 0x00FFFFFF + +// tmp = getContextID(); +// ASID = tmp & CONTEXTID_ASID_MASK; +// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK; + +// ------------------------------------------------------------ +// SMP related for Armv7-A MPCore processors +// +// DO NOT CALL THESE FUNCTIONS ON A CORTEX-A8 + +// Returns the base address of the private peripheral memory space +unsigned int getBaseAddr(void); + +// Returns the CPU ID (0 to 3) of the CPU executed on +#define MP_CPU0 (0) +#define MP_CPU1 (1) +#define MP_CPU2 (2) +#define MP_CPU3 (3) +unsigned int getCPUID(void); + +// Set this core as participating in SMP +void joinSMP(void); + +// Set this core as NOT participating in SMP +void leaveSMP(void); + +// Go to sleep, never returns +void goToSleep(void); + +#endif + +// ------------------------------------------------------------ +// End of v7.h +// ------------------------------------------------------------ diff --git a/ports/cortex_a15/gnu/example_build/v7.s b/ports/cortex_a15/gnu/example_build/v7.s new file mode 100644 index 000000000..82c9ab1e9 --- /dev/null +++ b/ports/cortex_a15/gnu/example_build/v7.s @@ -0,0 +1,476 @@ +// ------------------------------------------------------------ +// v7-A Cache and Branch Prediction Maintenance Operations +// +// Copyright (c) 2011-2018 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + + .arm +// ------------------------------------------------------------ +// Interrupt enable/disable +// ------------------------------------------------------------ + + // Could use intrinsic instead of these + + .global enableInterrupts + .type enableInterrupts,function + // void enableInterrupts(void)// +enableInterrupts: + CPSIE i + BX lr + + + .global disableInterrupts + .type disableInterrupts,function + // void disableInterrupts(void)// +disableInterrupts: + CPSID i + BX lr + + +// ------------------------------------------------------------ +// Cache Maintenance +// ------------------------------------------------------------ + + .global enableCaches + .type enableCaches,function + // void enableCaches(void)// +enableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + ORR r0, r0, #(1 << 2) // Set C bit + ORR r0, r0, #(1 << 12) // Set I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global disableCaches + .type disableCaches,function + // void disableCaches(void) +disableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + BIC r0, r0, #(1 << 2) // Clear C bit + BIC r0, r0, #(1 << 12) // Clear I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global cleanDCache + .type cleanDCache,function + // void cleanDCache(void)// +cleanDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_dcache_finished + MOV r10, #0 + +clean_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c10, 2 // DCCSW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_dcache_loop2 + +clean_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_dcache_loop1 + +clean_dcache_finished: + POP {r4-r12} + + BX lr + + + .global cleanInvalidateDCache + .type cleanInvalidateDCache,function + // void cleanInvalidateDCache(void)// +cleanInvalidateDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_invalidate_dcache_finished + MOV r10, #0 + +clean_invalidate_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_invalidate_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_invalidate_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_invalidate_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c14, 2 // DCCISW - clean and invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_invalidate_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_invalidate_dcache_loop2 + +clean_invalidate_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_invalidate_dcache_loop1 + +clean_invalidate_dcache_finished: + POP {r4-r12} + + BX lr + + + + .global invalidateCaches + .type invalidateCaches,function + // void invalidateCaches(void)// +invalidateCaches: + PUSH {r4-r12} + + // + // Based on code example given in section B2.2.4/11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 0 // ICIALLU - Invalidate entire I Cache, and flushes branch target cache + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_finished + MOV r10, #0 + +invalidate_caches_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_loop2 + +invalidate_caches_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_loop1 + +invalidate_caches_finished: + POP {r4-r12} + BX lr + + + + .global invalidateCaches_IS + .type invalidateCaches_IS,function + // void invalidateCaches_IS(void)// +invalidateCaches_IS: + PUSH {r4-r12} + + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 0 // ICIALLUIS - Invalidate entire I Cache inner shareable + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_is_finished + MOV r10, #0 + +invalidate_caches_is_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_is_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_is_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_is_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_is_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_is_loop2 + +invalidate_caches_is_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_is_loop1 + +invalidate_caches_is_finished: + POP {r4-r12} + BX lr + + +// ------------------------------------------------------------ +// TLB +// ------------------------------------------------------------ + + .global invalidateUnifiedTLB + .type invalidateUnifiedTLB,function + // void invalidateUnifiedTLB(void)// +invalidateUnifiedTLB: + MOV r0, #0 + MCR p15, 0, r0, c8, c7, 0 // TLBIALL - Invalidate entire unified TLB + BX lr + + + .global invalidateUnifiedTLB_IS + .type invalidateUnifiedTLB_IS,function + // void invalidateUnifiedTLB_IS(void)// +invalidateUnifiedTLB_IS: + MOV r0, #1 + MCR p15, 0, r0, c8, c3, 0 // TLBIALLIS - Invalidate entire unified TLB Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// Branch Prediction +// ------------------------------------------------------------ + + .global flushBranchTargetCache + .type flushBranchTargetCache,function + // void flushBranchTargetCache(void) +flushBranchTargetCache: + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 6 // BPIALL - Invalidate entire branch predictor array + BX lr + + + .global flushBranchTargetCache_IS + .type flushBranchTargetCache_IS,function + // void flushBranchTargetCache_IS(void) +flushBranchTargetCache_IS: + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 6 // BPIALLIS - Invalidate entire branch predictor array Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// High Vecs +// ------------------------------------------------------------ + + .global enableHighVecs + .type enableHighVecs,function + // void enableHighVecs(void)// +enableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + ORR r0, r0, #(1 << 13) // Set the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + + .global disableHighVecs + .type disableHighVecs,function + // void disable_highvecs(void)// +disableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + BIC r0, r0, #(1 << 13) // Clear the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + +// ------------------------------------------------------------ +// Context ID +// ------------------------------------------------------------ + + .global getContextID + .type getContextID,function + // uint32_t getContextIDd(void)// +getContextID: + MRC p15, 0, r0, c13, c0, 1 // Read Context ID Register + BX lr + + + .global setContextID + .type setContextID,function + // void setContextID(uint32_t)// +setContextID: + MCR p15, 0, r0, c13, c0, 1 // Write Context ID Register + BX lr + + +// ------------------------------------------------------------ +// ID registers +// ------------------------------------------------------------ + + .global getMIDR + .type getMIDR,function + // uint32_t getMIDR(void)// +getMIDR: + MRC p15, 0, r0, c0, c0, 0 // Read Main ID Register (MIDR) + BX lr + + + .global getMPIDR + .type getMPIDR,function + // uint32_t getMPIDR(void)// +getMPIDR: + MRC p15, 0, r0, c0 ,c0, 5// Read Multiprocessor ID register (MPIDR) + BX lr + + +// ------------------------------------------------------------ +// CP15 SMP related +// ------------------------------------------------------------ + + .global getBaseAddr + .type getBaseAddr,function + // uint32_t getBaseAddr(void) + // Returns the value CBAR (base address of the private peripheral memory space) +getBaseAddr: + MRC p15, 4, r0, c15, c0, 0 // Read peripheral base address + BX lr + + +// ------------------------------------------------------------ + + .global getCPUID + .type getCPUID,function + // uint32_t getCPUID(void) + // Returns the CPU ID (0 to 3) of the CPU executed on +getCPUID: + MRC p15, 0, r0, c0, c0, 5 // Read CPU ID register + AND r0, r0, #0x03 // Mask off, leaving the CPU ID field + BX lr + + +// ------------------------------------------------------------ + + .global goToSleep + .type goToSleep,function + // void goToSleep(void) +goToSleep: + DSB // Clear all pending data accesses + WFI // Go into standby + B goToSleep // Catch in case of rogue events + BX lr + + +// ------------------------------------------------------------ + + .global joinSMP + .type joinSMP,function + // void joinSMP(void) + // Sets the ACTRL.SMP bit +joinSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + MOV r1, r0 + ORR r0, r0, #0x040 // Set bit 6 + CMP r0, r1 + MCRNE p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ + + .global leaveSMP + .type leaveSMP,function + // void leaveSMP(void) + // Clear the ACTRL.SMP bit +leaveSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + BIC r0, r0, #0x040 // Clear bit 6 + MCR p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ +// End of v7.s +// ------------------------------------------------------------ diff --git a/ports/cortex_a17/gnu/example_build/crt0.S b/ports/cortex_a17/gnu/example_build/crt0.S index 56b6c9580..d25196ef6 100644 --- a/ports/cortex_a17/gnu/example_build/crt0.S +++ b/ports/cortex_a17/gnu/example_build/crt0.S @@ -79,6 +79,14 @@ _mainCRTStartup: #endif #endif + .global _fini + .type _fini,function +_fini: +#ifdef __THUMB_INTERWORK + BX lr // Return to caller +#else + MOV pc, lr // Return to caller +#endif /* Workspace for Angel calls. */ .data diff --git a/ports/cortex_a17/gnu/example_build/sample_threadx.ld b/ports/cortex_a17/gnu/example_build/sample_threadx.ld index 3dea4e1ca..cb42c11cb 100644 --- a/ports/cortex_a17/gnu/example_build/sample_threadx.ld +++ b/ports/cortex_a17/gnu/example_build/sample_threadx.ld @@ -109,7 +109,7 @@ SECTIONS .eh_frame_hdr : { *(.eh_frame_hdr) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); + . = 0x2E000000; .data : { *(.data) diff --git a/ports/cortex_a17/gnu/example_build/v7.h b/ports/cortex_a17/gnu/example_build/v7.h new file mode 100644 index 000000000..5a08b43fd --- /dev/null +++ b/ports/cortex_a17/gnu/example_build/v7.h @@ -0,0 +1,155 @@ +// ------------------------------------------------------------ +// v7-A Cache, TLB and Branch Prediction Maintenance Operations +// Header File +// +// Copyright (c) 2011-2016 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + +#ifndef _ARMV7A_GENERIC_H +#define _ARMV7A_GENERIC_H + +// ------------------------------------------------------------ +// Memory barrier mnemonics +enum MemBarOpt { + RESERVED_0 = 0, RESERVED_1 = 1, OSHST = 2, OSH = 3, + RESERVED_4 = 4, RESERVED_5 = 5, NSHST = 6, NSH = 7, + RESERVED_8 = 8, RESERVED_9 = 9, ISHST = 10, ISH = 11, + RESERVED_12 = 12, RESERVED_13 = 13, ST = 14, SY = 15 +}; + +// +// Note: +// *_IS() stands for "inner shareable" +// DO NOT USE THESE FUNCTIONS ON A CORTEX-A8 +// + +// ------------------------------------------------------------ +// Interrupts +// Enable/disables IRQs (not FIQs) +void enableInterrupts(void); +void disableInterrupts(void); + +// ------------------------------------------------------------ +// Caches + +void invalidateCaches_IS(void); +void cleanInvalidateDCache(void); +void invalidateCaches_IS(void); +void enableCaches(void); +void disableCaches(void); +void invalidateCaches(void); +void cleanDCache(void); + +// ------------------------------------------------------------ +// TLBs + +void invalidateUnifiedTLB(void); +void invalidateUnifiedTLB_IS(void); + +// ------------------------------------------------------------ +// Branch prediction + +void flushBranchTargetCache(void); +void flushBranchTargetCache_IS(void); + +// ------------------------------------------------------------ +// High Vecs + +void enableHighVecs(void); +void disableHighVecs(void); + +// ------------------------------------------------------------ +// ID Registers + +unsigned int getMIDR(void); + +#define MIDR_IMPL_SHIFT 24 +#define MIDR_IMPL_MASK 0xFF +#define MIDR_VAR_SHIFT 20 +#define MIDR_VAR_MASK 0xF +#define MIDR_ARCH_SHIFT 16 +#define MIDR_ARCH_MASK 0xF +#define MIDR_PART_SHIFT 4 +#define MIDR_PART_MASK 0xFFF +#define MIDR_REV_SHIFT 0 +#define MIDR_REV_MASK 0xF + +// tmp = get_MIDR(); +// implementor = (tmp >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; +// variant = (tmp >> MIDR_VAR_SHIFT) & MIDR_VAR_MASK; +// architecture= (tmp >> MIDR_ARCH_SHIFT) & MIDR_ARCH_MASK; +// part_number = (tmp >> MIDR_PART_SHIFT) & MIDR_PART_MASK; +// revision = tmp & MIDR_REV_MASK; + +#define MIDR_PART_CA5 0xC05 +#define MIDR_PART_CA8 0xC08 +#define MIDR_PART_CA9 0xC09 + +unsigned int getMPIDR(void); + +#define MPIDR_FORMAT_SHIFT 31 +#define MPIDR_FORMAT_MASK 0x1 +#define MPIDR_UBIT_SHIFT 30 +#define MPIDR_UBIT_MASK 0x1 +#define MPIDR_CLUSTER_SHIFT 7 +#define MPIDR_CLUSTER_MASK 0xF +#define MPIDR_CPUID_SHIFT 0 +#define MPIDR_CPUID_MASK 0x3 + +#define MPIDR_CPUID_CPU0 0x0 +#define MPIDR_CPUID_CPU1 0x1 +#define MPIDR_CPUID_CPU2 0x2 +#define MPIDR_CPUID_CPU3 0x3 + +#define MPIDR_UNIPROCESSPR 0x1 + +#define MPDIR_NEW_FORMAT 0x1 + +// ------------------------------------------------------------ +// Context ID + +unsigned int getContextID(void); + +void setContextID(unsigned int); + +#define CONTEXTID_ASID_SHIFT 0 +#define CONTEXTID_ASID_MASK 0xFF +#define CONTEXTID_PROCID_SHIFT 8 +#define CONTEXTID_PROCID_MASK 0x00FFFFFF + +// tmp = getContextID(); +// ASID = tmp & CONTEXTID_ASID_MASK; +// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK; + +// ------------------------------------------------------------ +// SMP related for Armv7-A MPCore processors +// +// DO NOT CALL THESE FUNCTIONS ON A CORTEX-A8 + +// Returns the base address of the private peripheral memory space +unsigned int getBaseAddr(void); + +// Returns the CPU ID (0 to 3) of the CPU executed on +#define MP_CPU0 (0) +#define MP_CPU1 (1) +#define MP_CPU2 (2) +#define MP_CPU3 (3) +unsigned int getCPUID(void); + +// Set this core as participating in SMP +void joinSMP(void); + +// Set this core as NOT participating in SMP +void leaveSMP(void); + +// Go to sleep, never returns +void goToSleep(void); + +#endif + +// ------------------------------------------------------------ +// End of v7.h +// ------------------------------------------------------------ diff --git a/ports/cortex_a17/gnu/example_build/v7.s b/ports/cortex_a17/gnu/example_build/v7.s new file mode 100644 index 000000000..82c9ab1e9 --- /dev/null +++ b/ports/cortex_a17/gnu/example_build/v7.s @@ -0,0 +1,476 @@ +// ------------------------------------------------------------ +// v7-A Cache and Branch Prediction Maintenance Operations +// +// Copyright (c) 2011-2018 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + + .arm +// ------------------------------------------------------------ +// Interrupt enable/disable +// ------------------------------------------------------------ + + // Could use intrinsic instead of these + + .global enableInterrupts + .type enableInterrupts,function + // void enableInterrupts(void)// +enableInterrupts: + CPSIE i + BX lr + + + .global disableInterrupts + .type disableInterrupts,function + // void disableInterrupts(void)// +disableInterrupts: + CPSID i + BX lr + + +// ------------------------------------------------------------ +// Cache Maintenance +// ------------------------------------------------------------ + + .global enableCaches + .type enableCaches,function + // void enableCaches(void)// +enableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + ORR r0, r0, #(1 << 2) // Set C bit + ORR r0, r0, #(1 << 12) // Set I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global disableCaches + .type disableCaches,function + // void disableCaches(void) +disableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + BIC r0, r0, #(1 << 2) // Clear C bit + BIC r0, r0, #(1 << 12) // Clear I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global cleanDCache + .type cleanDCache,function + // void cleanDCache(void)// +cleanDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_dcache_finished + MOV r10, #0 + +clean_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c10, 2 // DCCSW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_dcache_loop2 + +clean_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_dcache_loop1 + +clean_dcache_finished: + POP {r4-r12} + + BX lr + + + .global cleanInvalidateDCache + .type cleanInvalidateDCache,function + // void cleanInvalidateDCache(void)// +cleanInvalidateDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_invalidate_dcache_finished + MOV r10, #0 + +clean_invalidate_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_invalidate_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_invalidate_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_invalidate_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c14, 2 // DCCISW - clean and invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_invalidate_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_invalidate_dcache_loop2 + +clean_invalidate_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_invalidate_dcache_loop1 + +clean_invalidate_dcache_finished: + POP {r4-r12} + + BX lr + + + + .global invalidateCaches + .type invalidateCaches,function + // void invalidateCaches(void)// +invalidateCaches: + PUSH {r4-r12} + + // + // Based on code example given in section B2.2.4/11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 0 // ICIALLU - Invalidate entire I Cache, and flushes branch target cache + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_finished + MOV r10, #0 + +invalidate_caches_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_loop2 + +invalidate_caches_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_loop1 + +invalidate_caches_finished: + POP {r4-r12} + BX lr + + + + .global invalidateCaches_IS + .type invalidateCaches_IS,function + // void invalidateCaches_IS(void)// +invalidateCaches_IS: + PUSH {r4-r12} + + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 0 // ICIALLUIS - Invalidate entire I Cache inner shareable + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_is_finished + MOV r10, #0 + +invalidate_caches_is_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_is_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_is_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_is_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_is_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_is_loop2 + +invalidate_caches_is_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_is_loop1 + +invalidate_caches_is_finished: + POP {r4-r12} + BX lr + + +// ------------------------------------------------------------ +// TLB +// ------------------------------------------------------------ + + .global invalidateUnifiedTLB + .type invalidateUnifiedTLB,function + // void invalidateUnifiedTLB(void)// +invalidateUnifiedTLB: + MOV r0, #0 + MCR p15, 0, r0, c8, c7, 0 // TLBIALL - Invalidate entire unified TLB + BX lr + + + .global invalidateUnifiedTLB_IS + .type invalidateUnifiedTLB_IS,function + // void invalidateUnifiedTLB_IS(void)// +invalidateUnifiedTLB_IS: + MOV r0, #1 + MCR p15, 0, r0, c8, c3, 0 // TLBIALLIS - Invalidate entire unified TLB Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// Branch Prediction +// ------------------------------------------------------------ + + .global flushBranchTargetCache + .type flushBranchTargetCache,function + // void flushBranchTargetCache(void) +flushBranchTargetCache: + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 6 // BPIALL - Invalidate entire branch predictor array + BX lr + + + .global flushBranchTargetCache_IS + .type flushBranchTargetCache_IS,function + // void flushBranchTargetCache_IS(void) +flushBranchTargetCache_IS: + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 6 // BPIALLIS - Invalidate entire branch predictor array Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// High Vecs +// ------------------------------------------------------------ + + .global enableHighVecs + .type enableHighVecs,function + // void enableHighVecs(void)// +enableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + ORR r0, r0, #(1 << 13) // Set the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + + .global disableHighVecs + .type disableHighVecs,function + // void disable_highvecs(void)// +disableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + BIC r0, r0, #(1 << 13) // Clear the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + +// ------------------------------------------------------------ +// Context ID +// ------------------------------------------------------------ + + .global getContextID + .type getContextID,function + // uint32_t getContextIDd(void)// +getContextID: + MRC p15, 0, r0, c13, c0, 1 // Read Context ID Register + BX lr + + + .global setContextID + .type setContextID,function + // void setContextID(uint32_t)// +setContextID: + MCR p15, 0, r0, c13, c0, 1 // Write Context ID Register + BX lr + + +// ------------------------------------------------------------ +// ID registers +// ------------------------------------------------------------ + + .global getMIDR + .type getMIDR,function + // uint32_t getMIDR(void)// +getMIDR: + MRC p15, 0, r0, c0, c0, 0 // Read Main ID Register (MIDR) + BX lr + + + .global getMPIDR + .type getMPIDR,function + // uint32_t getMPIDR(void)// +getMPIDR: + MRC p15, 0, r0, c0 ,c0, 5// Read Multiprocessor ID register (MPIDR) + BX lr + + +// ------------------------------------------------------------ +// CP15 SMP related +// ------------------------------------------------------------ + + .global getBaseAddr + .type getBaseAddr,function + // uint32_t getBaseAddr(void) + // Returns the value CBAR (base address of the private peripheral memory space) +getBaseAddr: + MRC p15, 4, r0, c15, c0, 0 // Read peripheral base address + BX lr + + +// ------------------------------------------------------------ + + .global getCPUID + .type getCPUID,function + // uint32_t getCPUID(void) + // Returns the CPU ID (0 to 3) of the CPU executed on +getCPUID: + MRC p15, 0, r0, c0, c0, 5 // Read CPU ID register + AND r0, r0, #0x03 // Mask off, leaving the CPU ID field + BX lr + + +// ------------------------------------------------------------ + + .global goToSleep + .type goToSleep,function + // void goToSleep(void) +goToSleep: + DSB // Clear all pending data accesses + WFI // Go into standby + B goToSleep // Catch in case of rogue events + BX lr + + +// ------------------------------------------------------------ + + .global joinSMP + .type joinSMP,function + // void joinSMP(void) + // Sets the ACTRL.SMP bit +joinSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + MOV r1, r0 + ORR r0, r0, #0x040 // Set bit 6 + CMP r0, r1 + MCRNE p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ + + .global leaveSMP + .type leaveSMP,function + // void leaveSMP(void) + // Clear the ACTRL.SMP bit +leaveSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + BIC r0, r0, #0x040 // Clear bit 6 + MCR p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ +// End of v7.s +// ------------------------------------------------------------ diff --git a/ports/cortex_a5/gnu/example_build/crt0.S b/ports/cortex_a5/gnu/example_build/crt0.S index 56b6c9580..d25196ef6 100644 --- a/ports/cortex_a5/gnu/example_build/crt0.S +++ b/ports/cortex_a5/gnu/example_build/crt0.S @@ -79,6 +79,14 @@ _mainCRTStartup: #endif #endif + .global _fini + .type _fini,function +_fini: +#ifdef __THUMB_INTERWORK + BX lr // Return to caller +#else + MOV pc, lr // Return to caller +#endif /* Workspace for Angel calls. */ .data diff --git a/ports/cortex_a5/gnu/example_build/sample_threadx.ld b/ports/cortex_a5/gnu/example_build/sample_threadx.ld index 3dea4e1ca..cb42c11cb 100644 --- a/ports/cortex_a5/gnu/example_build/sample_threadx.ld +++ b/ports/cortex_a5/gnu/example_build/sample_threadx.ld @@ -109,7 +109,7 @@ SECTIONS .eh_frame_hdr : { *(.eh_frame_hdr) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); + . = 0x2E000000; .data : { *(.data) diff --git a/ports/cortex_a5/gnu/example_build/v7.h b/ports/cortex_a5/gnu/example_build/v7.h new file mode 100644 index 000000000..5a08b43fd --- /dev/null +++ b/ports/cortex_a5/gnu/example_build/v7.h @@ -0,0 +1,155 @@ +// ------------------------------------------------------------ +// v7-A Cache, TLB and Branch Prediction Maintenance Operations +// Header File +// +// Copyright (c) 2011-2016 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + +#ifndef _ARMV7A_GENERIC_H +#define _ARMV7A_GENERIC_H + +// ------------------------------------------------------------ +// Memory barrier mnemonics +enum MemBarOpt { + RESERVED_0 = 0, RESERVED_1 = 1, OSHST = 2, OSH = 3, + RESERVED_4 = 4, RESERVED_5 = 5, NSHST = 6, NSH = 7, + RESERVED_8 = 8, RESERVED_9 = 9, ISHST = 10, ISH = 11, + RESERVED_12 = 12, RESERVED_13 = 13, ST = 14, SY = 15 +}; + +// +// Note: +// *_IS() stands for "inner shareable" +// DO NOT USE THESE FUNCTIONS ON A CORTEX-A8 +// + +// ------------------------------------------------------------ +// Interrupts +// Enable/disables IRQs (not FIQs) +void enableInterrupts(void); +void disableInterrupts(void); + +// ------------------------------------------------------------ +// Caches + +void invalidateCaches_IS(void); +void cleanInvalidateDCache(void); +void invalidateCaches_IS(void); +void enableCaches(void); +void disableCaches(void); +void invalidateCaches(void); +void cleanDCache(void); + +// ------------------------------------------------------------ +// TLBs + +void invalidateUnifiedTLB(void); +void invalidateUnifiedTLB_IS(void); + +// ------------------------------------------------------------ +// Branch prediction + +void flushBranchTargetCache(void); +void flushBranchTargetCache_IS(void); + +// ------------------------------------------------------------ +// High Vecs + +void enableHighVecs(void); +void disableHighVecs(void); + +// ------------------------------------------------------------ +// ID Registers + +unsigned int getMIDR(void); + +#define MIDR_IMPL_SHIFT 24 +#define MIDR_IMPL_MASK 0xFF +#define MIDR_VAR_SHIFT 20 +#define MIDR_VAR_MASK 0xF +#define MIDR_ARCH_SHIFT 16 +#define MIDR_ARCH_MASK 0xF +#define MIDR_PART_SHIFT 4 +#define MIDR_PART_MASK 0xFFF +#define MIDR_REV_SHIFT 0 +#define MIDR_REV_MASK 0xF + +// tmp = get_MIDR(); +// implementor = (tmp >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; +// variant = (tmp >> MIDR_VAR_SHIFT) & MIDR_VAR_MASK; +// architecture= (tmp >> MIDR_ARCH_SHIFT) & MIDR_ARCH_MASK; +// part_number = (tmp >> MIDR_PART_SHIFT) & MIDR_PART_MASK; +// revision = tmp & MIDR_REV_MASK; + +#define MIDR_PART_CA5 0xC05 +#define MIDR_PART_CA8 0xC08 +#define MIDR_PART_CA9 0xC09 + +unsigned int getMPIDR(void); + +#define MPIDR_FORMAT_SHIFT 31 +#define MPIDR_FORMAT_MASK 0x1 +#define MPIDR_UBIT_SHIFT 30 +#define MPIDR_UBIT_MASK 0x1 +#define MPIDR_CLUSTER_SHIFT 7 +#define MPIDR_CLUSTER_MASK 0xF +#define MPIDR_CPUID_SHIFT 0 +#define MPIDR_CPUID_MASK 0x3 + +#define MPIDR_CPUID_CPU0 0x0 +#define MPIDR_CPUID_CPU1 0x1 +#define MPIDR_CPUID_CPU2 0x2 +#define MPIDR_CPUID_CPU3 0x3 + +#define MPIDR_UNIPROCESSPR 0x1 + +#define MPDIR_NEW_FORMAT 0x1 + +// ------------------------------------------------------------ +// Context ID + +unsigned int getContextID(void); + +void setContextID(unsigned int); + +#define CONTEXTID_ASID_SHIFT 0 +#define CONTEXTID_ASID_MASK 0xFF +#define CONTEXTID_PROCID_SHIFT 8 +#define CONTEXTID_PROCID_MASK 0x00FFFFFF + +// tmp = getContextID(); +// ASID = tmp & CONTEXTID_ASID_MASK; +// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK; + +// ------------------------------------------------------------ +// SMP related for Armv7-A MPCore processors +// +// DO NOT CALL THESE FUNCTIONS ON A CORTEX-A8 + +// Returns the base address of the private peripheral memory space +unsigned int getBaseAddr(void); + +// Returns the CPU ID (0 to 3) of the CPU executed on +#define MP_CPU0 (0) +#define MP_CPU1 (1) +#define MP_CPU2 (2) +#define MP_CPU3 (3) +unsigned int getCPUID(void); + +// Set this core as participating in SMP +void joinSMP(void); + +// Set this core as NOT participating in SMP +void leaveSMP(void); + +// Go to sleep, never returns +void goToSleep(void); + +#endif + +// ------------------------------------------------------------ +// End of v7.h +// ------------------------------------------------------------ diff --git a/ports/cortex_a5/gnu/example_build/v7.s b/ports/cortex_a5/gnu/example_build/v7.s new file mode 100644 index 000000000..82c9ab1e9 --- /dev/null +++ b/ports/cortex_a5/gnu/example_build/v7.s @@ -0,0 +1,476 @@ +// ------------------------------------------------------------ +// v7-A Cache and Branch Prediction Maintenance Operations +// +// Copyright (c) 2011-2018 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + + .arm +// ------------------------------------------------------------ +// Interrupt enable/disable +// ------------------------------------------------------------ + + // Could use intrinsic instead of these + + .global enableInterrupts + .type enableInterrupts,function + // void enableInterrupts(void)// +enableInterrupts: + CPSIE i + BX lr + + + .global disableInterrupts + .type disableInterrupts,function + // void disableInterrupts(void)// +disableInterrupts: + CPSID i + BX lr + + +// ------------------------------------------------------------ +// Cache Maintenance +// ------------------------------------------------------------ + + .global enableCaches + .type enableCaches,function + // void enableCaches(void)// +enableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + ORR r0, r0, #(1 << 2) // Set C bit + ORR r0, r0, #(1 << 12) // Set I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global disableCaches + .type disableCaches,function + // void disableCaches(void) +disableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + BIC r0, r0, #(1 << 2) // Clear C bit + BIC r0, r0, #(1 << 12) // Clear I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global cleanDCache + .type cleanDCache,function + // void cleanDCache(void)// +cleanDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_dcache_finished + MOV r10, #0 + +clean_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c10, 2 // DCCSW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_dcache_loop2 + +clean_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_dcache_loop1 + +clean_dcache_finished: + POP {r4-r12} + + BX lr + + + .global cleanInvalidateDCache + .type cleanInvalidateDCache,function + // void cleanInvalidateDCache(void)// +cleanInvalidateDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_invalidate_dcache_finished + MOV r10, #0 + +clean_invalidate_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_invalidate_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_invalidate_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_invalidate_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c14, 2 // DCCISW - clean and invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_invalidate_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_invalidate_dcache_loop2 + +clean_invalidate_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_invalidate_dcache_loop1 + +clean_invalidate_dcache_finished: + POP {r4-r12} + + BX lr + + + + .global invalidateCaches + .type invalidateCaches,function + // void invalidateCaches(void)// +invalidateCaches: + PUSH {r4-r12} + + // + // Based on code example given in section B2.2.4/11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 0 // ICIALLU - Invalidate entire I Cache, and flushes branch target cache + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_finished + MOV r10, #0 + +invalidate_caches_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_loop2 + +invalidate_caches_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_loop1 + +invalidate_caches_finished: + POP {r4-r12} + BX lr + + + + .global invalidateCaches_IS + .type invalidateCaches_IS,function + // void invalidateCaches_IS(void)// +invalidateCaches_IS: + PUSH {r4-r12} + + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 0 // ICIALLUIS - Invalidate entire I Cache inner shareable + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_is_finished + MOV r10, #0 + +invalidate_caches_is_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_is_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_is_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_is_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_is_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_is_loop2 + +invalidate_caches_is_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_is_loop1 + +invalidate_caches_is_finished: + POP {r4-r12} + BX lr + + +// ------------------------------------------------------------ +// TLB +// ------------------------------------------------------------ + + .global invalidateUnifiedTLB + .type invalidateUnifiedTLB,function + // void invalidateUnifiedTLB(void)// +invalidateUnifiedTLB: + MOV r0, #0 + MCR p15, 0, r0, c8, c7, 0 // TLBIALL - Invalidate entire unified TLB + BX lr + + + .global invalidateUnifiedTLB_IS + .type invalidateUnifiedTLB_IS,function + // void invalidateUnifiedTLB_IS(void)// +invalidateUnifiedTLB_IS: + MOV r0, #1 + MCR p15, 0, r0, c8, c3, 0 // TLBIALLIS - Invalidate entire unified TLB Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// Branch Prediction +// ------------------------------------------------------------ + + .global flushBranchTargetCache + .type flushBranchTargetCache,function + // void flushBranchTargetCache(void) +flushBranchTargetCache: + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 6 // BPIALL - Invalidate entire branch predictor array + BX lr + + + .global flushBranchTargetCache_IS + .type flushBranchTargetCache_IS,function + // void flushBranchTargetCache_IS(void) +flushBranchTargetCache_IS: + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 6 // BPIALLIS - Invalidate entire branch predictor array Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// High Vecs +// ------------------------------------------------------------ + + .global enableHighVecs + .type enableHighVecs,function + // void enableHighVecs(void)// +enableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + ORR r0, r0, #(1 << 13) // Set the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + + .global disableHighVecs + .type disableHighVecs,function + // void disable_highvecs(void)// +disableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + BIC r0, r0, #(1 << 13) // Clear the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + +// ------------------------------------------------------------ +// Context ID +// ------------------------------------------------------------ + + .global getContextID + .type getContextID,function + // uint32_t getContextIDd(void)// +getContextID: + MRC p15, 0, r0, c13, c0, 1 // Read Context ID Register + BX lr + + + .global setContextID + .type setContextID,function + // void setContextID(uint32_t)// +setContextID: + MCR p15, 0, r0, c13, c0, 1 // Write Context ID Register + BX lr + + +// ------------------------------------------------------------ +// ID registers +// ------------------------------------------------------------ + + .global getMIDR + .type getMIDR,function + // uint32_t getMIDR(void)// +getMIDR: + MRC p15, 0, r0, c0, c0, 0 // Read Main ID Register (MIDR) + BX lr + + + .global getMPIDR + .type getMPIDR,function + // uint32_t getMPIDR(void)// +getMPIDR: + MRC p15, 0, r0, c0 ,c0, 5// Read Multiprocessor ID register (MPIDR) + BX lr + + +// ------------------------------------------------------------ +// CP15 SMP related +// ------------------------------------------------------------ + + .global getBaseAddr + .type getBaseAddr,function + // uint32_t getBaseAddr(void) + // Returns the value CBAR (base address of the private peripheral memory space) +getBaseAddr: + MRC p15, 4, r0, c15, c0, 0 // Read peripheral base address + BX lr + + +// ------------------------------------------------------------ + + .global getCPUID + .type getCPUID,function + // uint32_t getCPUID(void) + // Returns the CPU ID (0 to 3) of the CPU executed on +getCPUID: + MRC p15, 0, r0, c0, c0, 5 // Read CPU ID register + AND r0, r0, #0x03 // Mask off, leaving the CPU ID field + BX lr + + +// ------------------------------------------------------------ + + .global goToSleep + .type goToSleep,function + // void goToSleep(void) +goToSleep: + DSB // Clear all pending data accesses + WFI // Go into standby + B goToSleep // Catch in case of rogue events + BX lr + + +// ------------------------------------------------------------ + + .global joinSMP + .type joinSMP,function + // void joinSMP(void) + // Sets the ACTRL.SMP bit +joinSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + MOV r1, r0 + ORR r0, r0, #0x040 // Set bit 6 + CMP r0, r1 + MCRNE p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ + + .global leaveSMP + .type leaveSMP,function + // void leaveSMP(void) + // Clear the ACTRL.SMP bit +leaveSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + BIC r0, r0, #0x040 // Clear bit 6 + MCR p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ +// End of v7.s +// ------------------------------------------------------------ diff --git a/ports/cortex_a7/gnu/example_build/MP_GIC.h b/ports/cortex_a7/gnu/example_build/MP_GIC.h new file mode 100644 index 000000000..c34e44c94 --- /dev/null +++ b/ports/cortex_a7/gnu/example_build/MP_GIC.h @@ -0,0 +1,74 @@ +// ------------------------------------------------------------ +// Cortex-A7 MPCore - Interrupt Controller functions +// Header File +// +// Copyright (c) 2011-2018 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + +#ifndef _CORTEXA_GIC_ +#define _CORTEXA_GIC_ + +// ------------------------------------------------------------ +// GIC +// ------------------------------------------------------------ + +// Typical calls to enable interrupt ID X: +// enable_irq_id(X) <-- Enable that ID +// set_irq_priority(X, 0) <-- Set the priority of X to 0 (the max priority) +// set_priority_mask(0x1F) <-- Set Core's priority mask to 0x1F (the lowest priority) +// enable_GIC() <-- Enable the GIC (global) +// enable_gic_processor_interface() <-- Enable the CPU interface (local to the core) +// + + +// Global enable of the Interrupt Distributor +void enableGIC(void); + +// Global disable of the Interrupt Distributor +void disableGIC(void); + +// Enables the interrupt source number ID +void enableIntID(unsigned int ID); + +// Disables the interrupt source number ID +void disableIntID(unsigned int ID); + +// Sets the priority of the specified ID +void setIntPriority(unsigned int ID, unsigned int priority); + +// Enables the processor interface +// Must be done on each core separately +void enableGICProcessorInterface(void); + +// Disables the processor interface +// Must be done on each core separately +void disableGICProcessorInterface(void); + +// Sets the Priority mask register for the core run on +// The reset value masks ALL interrupts! +void setPriorityMask(unsigned int priority); + +// Sets the Binary Point Register for the core run on +void setBinaryPoint(unsigned int priority); + +// Returns the value of the Interrupt Acknowledge Register +unsigned int readIntAck(void); + +// Writes ID to the End Of Interrupt register +void writeEOI(unsigned int ID); + +// ------------------------------------------------------------ +// SGI +// ------------------------------------------------------------ + +// Send a software generate interrupt +void sendSGI(unsigned int ID, unsigned int core_list, unsigned int filter_list); + +#endif + +// ------------------------------------------------------------ +// End of MP_GIC.h +// ------------------------------------------------------------ diff --git a/ports/cortex_a7/gnu/example_build/MP_GIC.s b/ports/cortex_a7/gnu/example_build/MP_GIC.s new file mode 100644 index 000000000..7f175c69b --- /dev/null +++ b/ports/cortex_a7/gnu/example_build/MP_GIC.s @@ -0,0 +1,294 @@ +//---------------------------------------------------------------- +// Copyright (c) 2005-2018 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// +// Cortex-A7MP example - Startup Code +//---------------------------------------------------------------- + .text + +//---------------------------------------------------------------- +// GIC. Generic Interrupt Controller Architecture Specification +//---------------------------------------------------------------- + + // CPU Interface offset from base of private peripheral space --> 0x0100 + // Interrupt Distributor offset from base of private peripheral space --> 0x1000 + + // Typical calls to enable interrupt ID X: + // enableIntID(X) <-- Enable that ID + // setIntPriority(X, 0) <-- Set the priority of X to 0 (the max priority) + // setPriorityMask(0x1F) <-- Set CPU's priority mask to 0x1F (the lowest priority) + // enableGIC() <-- Enable the GIC (global) + // enableGICProcessorInterface() <-- Enable the CPU interface (local to the CPU) + + + // void enableGIC(void) + // Global enable of the Interrupt Distributor + .global enableGIC + .type enableGIC,function +enableGIC: + // Get base address of private peripheral space + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + ADD r0, r0, #0x1000 // Add the GIC offset + + LDR r1, [r0] // Read the GIC Enable Register (ICDDCR) + ORR r1, r1, #0x01 // Set bit 0, the enable bit + STR r1, [r0] // Write the GIC Enable Register (ICDDCR) + + BX lr + +// ------------------------------------------------------------ + + .global disableGIC + .type disableGIC,function + // void disableGIC(void) + // Global disable of the Interrupt Distributor +disableGIC: + // Get base address of private peripheral space + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + ADD r0, r0, #0x1000 // Add the GIC offset + + LDR r1, [r0] // Read the GIC Enable Register (ICDDCR) + BIC r1, r1, #0x01 // Clear bit 0, the enable bit + STR r1, [r0] // Write the GIC Enable Register (ICDDCR) + + BX lr + + +// ------------------------------------------------------------ + + .global enableIntID + .type enableIntID,function + // void enableIntID(unsigned int ID) + // Enables the interrupt source number ID +enableIntID: + // Get base address of private peripheral space + MOV r1, r0 // Back up passed in ID value + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + // Each interrupt source has an enable bit in the GIC. These + // are grouped into registers, with 32 sources per register + // First, we need to identify which 32-bit block the interrupt lives in + MOV r2, r1 // Make working copy of ID in r2 + MOV r2, r2, LSR #5 // LSR by 5 places, affective divide by 32 + // r2 now contains the 32-bit block this ID lives in + MOV r2, r2, LSL #2 // Now multiply by 4, to convert offset into an address offset (four bytes per reg) + + // Now work out which bit within the 32-bit block the ID is + AND r1, r1, #0x1F // Mask off to give offset within 32-bit block + MOV r3, #1 // Move enable value into r3 + MOV r3, r3, LSL r1 // Shift it left to position of ID + + ADD r2, r2, #0x1100 // Add the base offset of the Enable Set registers to the offset for the ID + STR r3, [r0, r2] // Store out (ICDISER) + + BX lr + + +// ------------------------------------------------------------ + + .global disableIntID + .type disableIntID,function + // void disableIntID(unsigned int ID) + // Disables the interrupt source number ID +disableIntID: + // Get base address of private peripheral space + MOV r1, r0 // Back up passed in ID value + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + // First, we need to identify which 32-bit block the interrupt lives in + MOV r2, r1 // Make working copy of ID in r2 + MOV r2, r2, LSR #5 // LSR by 5 places, affective divide by 32 + // r2 now contains the 32-bit block this ID lives in + MOV r2, r2, LSL #2 // Now multiply by 4, to convert offset into an address offset (four bytes per reg) + + // Now work out which bit within the 32-bit block the ID is + AND r1, r1, #0x1F // Mask off to give offset within 32-bit block + MOV r3, #1 // Move enable value into r3 + MOV r3, r3, LSL r1 // Shift it left to position of ID in 32-bit block + + ADD r2, r2, #0x1180 // Add the base offset of the Enable Clear registers to the offset for the ID + STR r3, [r0, r2] // Store out (ICDICER) + + BX lr + + +// ------------------------------------------------------------ + + .global setIntPriority + .type setIntPriority,function + // void setIntPriority(unsigned int ID, unsigned int priority) + // Sets the priority of the specified ID + // r0 = ID + // r1 = priority +setIntPriority: + // Get base address of private peripheral space + MOV r2, r0 // Back up passed in ID value + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + // r0 = base addr + // r1 = priority + // r2 = ID + + // Make sure that priority value is only 5 bits, and convert to expected format + AND r1, r1, #0x1F + MOV r1, r1, LSL #3 + + // Find which register this ID lives in + BIC r3, r2, #0x03 // Make a copy of the ID, clearing off the bottom two bits + // There are four IDs per reg, by clearing the bottom two bits we get an address offset + ADD r3, r3, #0x1400 // Now add the offset of the Priority Level registers from the base of the private peripheral space + ADD r0, r0, r3 // Now add in the base address of the private peripheral space, giving us the absolute address + + // Now work out which ID in the register it is + AND r2, r2, #0x03 // Clear all but the bottom two bits, leaves which ID in the reg it is (which byte) + MOV r2, r2, LSL #3 // Multiply by 8, this gives a bit offset + + // Read -> Modify -> Write + MOV r12, #0xFF // 8 bit field mask + MOV r12, r12, LSL r2 // Move mask into correct bit position + MOV r1, r1, LSL r2 // Also, move passed in priority value into correct bit position + + LDR r3, [r0] // Read current value of the Priority Level register (ICDIPR) + BIC r3, r3, r12 // Clear appropriate field + ORR r3, r3, r1 // Now OR in the priority value + STR r3, [r0] // And store it back again (ICDIPR) + + BX lr + + +// ------------------------------------------------------------ + + .global enableGICProcessorInterface + .type enableGICProcessorInterface,function + // void enableGICProcessorInterface(void) + // Enables the processor interface + // Must be done on each core separately +enableGICProcessorInterface: + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + ADD r0, r0, #0x2000 + + LDR r1, [r0, #0x0] // Read the Processor Interface Control register (ICCICR/ICPICR) + ORR r1, r1, #0x03 // Bit 0: Enables secure interrupts, Bit 1: Enables Non-Secure interrupts + BIC r1, r1, #0x08 // Bit 3: Ensure Group 0 interrupts are signalled using IRQ, not FIQ + STR r1, [r0, #0x0] // Write the Processor Interface Control register (ICCICR/ICPICR) + + BX lr + + + +// ------------------------------------------------------------ + + .global disableGICProcessorInterface + .type disableGICProcessorInterface,function + // void disableGICProcessorInterface(void) + // Disables the processor interface + // Must be done on each core separately +disableGICProcessorInterface: + + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + ADD r0, r0, #0x2000 + + LDR r1, [r0, #0x0] // Read the Processor Interface Control register (ICCICR/ICPICR) + BIC r1, r1, #0x03 // Bit 0: Enables secure interrupts, Bit 1: Enables Non-Secure interrupts + STR r1, [r0, #0x0] // Write the Processor Interface Control register (ICCICR/ICPICR) + + BX lr + + + +// ------------------------------------------------------------ + + .global setPriorityMask + .type setPriorityMask,function + // void setPriorityMask(unsigned int priority) + // Sets the Priority mask register for the CPU run on + // The reset value masks ALL interrupts! +setPriorityMask: + + // Get base address of private peripheral space + MRC p15, 4, r1, c15, c0, 0 // Read periph base address + ADD r1, r1, #0x2000 + + STR r0, [r1, #0x4] // Write the Priority Mask register (ICCPMR/ICCIPMR) + + BX lr + + +// ------------------------------------------------------------ + + .global setBinaryPoint + .type setBinaryPoint,function + // void setBinaryPoint(unsigned int priority) + // Sets the Binary Point Register for the CPU run on +setBinaryPoint: + + // Get base address of private peripheral space + MRC p15, 4, r1, c15, c0, 0 // Read periph base address + ADD r1, r1, #0x2000 + + STR r0, [r1, #0x8] // Write the Binary register (ICCBPR/ICCBPR) + + BX lr + + +// ------------------------------------------------------------ + + .global readIntAck + .type readIntAck,function + // unsigned int readIntAck(void) + // Returns the value of the Interrupt Acknowledge Register +readIntAck: + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + ADD r0, r0, #0x2000 + + LDR r0, [r0, #0xC] // Read the Interrupt Acknowledge Register (ICCIAR) + BX lr + + +// ------------------------------------------------------------ + + .global writeEOI + .type writeEOI,function + // void writeEOI(unsigned int ID) + // Writes ID to the End Of Interrupt register +writeEOI: + + // Get base address of private peripheral space + MRC p15, 4, r1, c15, c0, 0 // Read periph base address + ADD r1, r1, #0x2000 + + STR r0, [r1, #0x10] // Write ID to the End of Interrupt register (ICCEOIR) + + BX lr + + +//---------------------------------------------------------------- +// SGI +//---------------------------------------------------------------- + + .global sendSGI + .type sendSGI,function + // void sendSGI(unsigned int ID, unsigned int target_list, unsigned int filter_list)// + // Send a software generate interrupt +sendSGI: + AND r3, r0, #0x0F // Mask off unused bits of ID, and move to r3 + AND r1, r1, #0x0F // Mask off unused bits of target_filter + AND r2, r2, #0x0F // Mask off unused bits of filter_list + + ORR r3, r3, r1, LSL #16 // Combine ID and target_filter + ORR r3, r3, r2, LSL #24 // and now the filter list + + // Get the address of the GIC + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + ADD r0, r0, #0x1F00 // Add offset of the sgi_trigger reg + + STR r3, [r0] // Write to the Software Generated Interrupt Register (ICDSGIR) + + BX lr + + +//---------------------------------------------------------------- +// End of MP_GIC.s +//---------------------------------------------------------------- diff --git a/ports/cortex_a7/gnu/example_build/MP_PrivateTimer.S b/ports/cortex_a7/gnu/example_build/MP_PrivateTimer.S new file mode 100644 index 000000000..b1e2701bb --- /dev/null +++ b/ports/cortex_a7/gnu/example_build/MP_PrivateTimer.S @@ -0,0 +1,84 @@ +// ------------------------------------------------------------ +// Cortex-A MPCore - Private timer functions +// +// Copyright ARM Ltd 2009. All rights reserved. +// ------------------------------------------------------------ + + .text + .align 3 + + // PPI ID 29 + + + // Typical set of calls to enable Timer: + // init_private_timer(0xXXXX, 0) <-- Counter down value of 0xXXXX, with auto-reload + // start_private_timer() + + // Timer offset from base of private peripheral space --> 0x600 + +// ------------------------------------------------------------ + + // void init_private_timer(unsigned int load_value, unsigned int auto_reload) + // Sets up the private timer + // r0: initial load value + // r1: IF 0 (AutoReload) ELSE (SingleShot) AutoReload not supported on Cortex-A7 + .global init_private_timer + .type init_private_timer,function +init_private_timer: + + // Setup timeout value (CNTP_TVAL) + MCR p15, 0, r0, c14, c2, 0 + BX lr + +// ------------------------------------------------------------ + + // void start_private_timer(void) + // Starts the private timer + .global start_private_timer + .type start_private_timer,function +start_private_timer: + + MOV r0, #0x1 + + // Enable timer (CNTP_CTL) + MCR p15, 0, r0, c14, c2, 1 + + BX lr + +// ------------------------------------------------------------ + + // void stop_private_timer(void) + // Stops the private timer + .global stop_private_timer + .type stop_private_timer,function +stop_private_timer: + + BX lr + +// ------------------------------------------------------------ + + // unsigned int read_private_timer(void) + // Reads the current value of the timer count register + .global get_private_timer_count + .type get_private_timer_count,function +get_private_timer_count: + + BX lr + +// ------------------------------------------------------------ + + // void clear_private_timer_irq(void) + // Clears the private timer interrupt + .global clear_private_timer_irq + .type clear_private_timer_irq,function +clear_private_timer_irq: + + BX lr + +// ------------------------------------------------------------ +// End of code +// ------------------------------------------------------------ + +// ------------------------------------------------------------ +// End of MP_PrivateTimer.s +// ------------------------------------------------------------ diff --git a/ports/cortex_a7/gnu/example_build/MP_PrivateTimer.h b/ports/cortex_a7/gnu/example_build/MP_PrivateTimer.h new file mode 100644 index 000000000..b0ab212a3 --- /dev/null +++ b/ports/cortex_a7/gnu/example_build/MP_PrivateTimer.h @@ -0,0 +1,36 @@ +// ------------------------------------------------------------ +// Cortex-A MPCore - Private timer functions +// Header Filer +// +// Copyright ARM Ltd 2009. All rights reserved. +// ------------------------------------------------------------ + +#ifndef _CORTEXA_PRIVATE_TIMER_ +#define _CORTEXA_PRIVATE_TIMER_ + +// Typical set of calls to enable Timer: +// init_private_timer(0xXXXX, 0) <-- Counter down value of 0xXXXX, with auto-reload +// start_private_timer() + +// Sets up the private timer +// r0: initial load value +// r1: IF 0 (AutoReload) ELSE (SingleShot) +void init_private_timer(unsigned int load_value, unsigned int auto_reload); + +// Starts the private timer +void start_private_timer(void); + +// Stops the private timer +void stop_private_timer(void); + +// Reads the current value of the timer count register +unsigned int get_private_timer_count(void); + +// Clears the private timer interrupt +void clear_private_timer_irq(void); + +#endif + +// ------------------------------------------------------------ +// End of MP_PrivateTimer.h +// ------------------------------------------------------------ diff --git a/ports/cortex_a7/gnu/example_build/build_threadx_sample.bat b/ports/cortex_a7/gnu/example_build/build_threadx_sample.bat index d0378cb87..04cdf369b 100644 --- a/ports/cortex_a7/gnu/example_build/build_threadx_sample.bat +++ b/ports/cortex_a7/gnu/example_build/build_threadx_sample.bat @@ -1,8 +1,8 @@ arm-none-eabi-gcc -c -g -mcpu=cortex-a7 reset.S arm-none-eabi-gcc -c -g -mcpu=cortex-a7 crt0.S arm-none-eabi-gcc -c -g -mcpu=cortex-a7 tx_initialize_low_level.S +arm-none-eabi-gcc -c -g -mcpu=cortex-a7 MP_GIC.s +arm-none-eabi-gcc -c -g -mcpu=cortex-a7 MP_PrivateTimer.s +arm-none-eabi-gcc -c -g -mcpu=cortex-a7 V7.s arm-none-eabi-gcc -c -g -mcpu=cortex-a7 -I../../../../common/inc -I../inc sample_threadx.c -arm-none-eabi-gcc -g -mcpu=cortex-a7 -T sample_threadx.ld --specs=nosys.specs -o sample_threadx.out -Wl,-Map=sample_threadx.map tx_initialize_low_level.o sample_threadx.o tx.a - - - +arm-none-eabi-gcc -g -nostartfiles -mcpu=cortex-a7 -T sample_threadx.ld --specs=nosys.specs -o sample_threadx.out -Wl,-Map=sample_threadx.map MP_GIC.o MP_PrivateTimer.o V7.o crt0.o reset.o tx_initialize_low_level.o sample_threadx.o tx.a diff --git a/ports/cortex_a7/gnu/example_build/crt0.S b/ports/cortex_a7/gnu/example_build/crt0.S index 56b6c9580..d25196ef6 100644 --- a/ports/cortex_a7/gnu/example_build/crt0.S +++ b/ports/cortex_a7/gnu/example_build/crt0.S @@ -79,6 +79,14 @@ _mainCRTStartup: #endif #endif + .global _fini + .type _fini,function +_fini: +#ifdef __THUMB_INTERWORK + BX lr // Return to caller +#else + MOV pc, lr // Return to caller +#endif /* Workspace for Angel calls. */ .data diff --git a/ports/cortex_a7/gnu/example_build/sample_threadx.ld b/ports/cortex_a7/gnu/example_build/sample_threadx.ld index 3dea4e1ca..cb42c11cb 100644 --- a/ports/cortex_a7/gnu/example_build/sample_threadx.ld +++ b/ports/cortex_a7/gnu/example_build/sample_threadx.ld @@ -109,7 +109,7 @@ SECTIONS .eh_frame_hdr : { *(.eh_frame_hdr) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); + . = 0x2E000000; .data : { *(.data) diff --git a/ports/cortex_a7/gnu/example_build/sample_threadx.out b/ports/cortex_a7/gnu/example_build/sample_threadx.out new file mode 100644 index 0000000000000000000000000000000000000000..a6a1dce75b42b3de32716f03262721d93de8e6f4 GIT binary patch literal 292972 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 ^`mk~Me3l;Q%#N8_dSH0pbEZ0+ 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 QJvN;0Jt0%nm&y140S=Rlo&W#< literal 0 HcmV?d00001 diff --git a/ports/cortex_a7/gnu/example_build/test.log b/ports/cortex_a7/gnu/example_build/test.log new file mode 100644 index 000000000..21efba525 --- /dev/null +++ b/ports/cortex_a7/gnu/example_build/test.log @@ -0,0 +1,18 @@ +>output thread_0_counter +10 +>output thread_1_counter +299267 +>output thread_2_counter +299268 +>output thread_3_counter +23 +>output thread_4_counter +23 +>output thread_5_counter +9 +>output thread_6_counter +23 +>output thread_7_counter +23 +>log file +Stopped duplicating logging output diff --git a/ports/cortex_a7/gnu/example_build/tx_initialize_low_level.S b/ports/cortex_a7/gnu/example_build/tx_initialize_low_level.S index 4b324e0ac..96a52fa06 100644 --- a/ports/cortex_a7/gnu/example_build/tx_initialize_low_level.S +++ b/ports/cortex_a7/gnu/example_build/tx_initialize_low_level.S @@ -41,8 +41,13 @@ SYS_STACK_SIZE = 1024 // System stack size .global _end .global _sp .global _stack_bottom - - + .global __vectors + .global disableHighVecs + .global enableGIC + .global enableGICProcessorInterface + .global enableCaches + .global init_private_timer + .global start_private_timer /* Define the 16-bit Thumb mode veneer for _tx_initialize_low_level for applications calling this function from to 16-bit Thumb mode. */ @@ -160,6 +165,42 @@ _stack_error_loop: ADD r1, r1, #8 // Increment to next free word STR r1, [r2] // Save first free memory address + PUSH {lr} + + /* Setup the vector table. */ + LDR r0, =__vectors // Get address of vector table + MCR p15, 0, r0, c12, c0, 0 // Write vector table address to CP15 + BL disableHighVecs // Disable high vectors + + // + // GIC Init + // --------- + BL enableGIC + BL enableGICProcessorInterface + + // + // Enable Private Timer for periodic IRQ + // -------------------------------------- + MOV r0, #0x1F + BL setPriorityMask // Set priority mask (local) + + // Enable the Private Timer Interrupt Source + MOV r0, #29 + MOV r1, #0 + BL enableIntID + + // Set the priority + MOV r0, #29 + MOV r1, #0 + BL setIntPriority + + // Configure Timer + MOV r0, #0xF0000 + MOV r1, #0x0 + BL init_private_timer + BL start_private_timer + + POP {lr} #ifdef __THUMB_INTERWORK BX lr // Return to caller #else @@ -202,16 +243,18 @@ __tx_irq_processing_return: if nested IRQ interrupts are desired. Interrupts may be re-enabled over small code sequences where lr is saved before enabling interrupts and restored after interrupts are again disabled. */ + + PUSH {r4, r5} // Save some preserved registers (r5 is saved just for 8-byte alignment) + BL readIntAck + MOV r4, r0 - /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start - from IRQ mode with interrupts disabled. This routine switches to the - system mode and returns with IRQ interrupts enabled. + CMP r0, #29 // If not Private Timer interrupt (ID 29), by pass + BNE by_pass_timer_interrupt - NOTE: It is very important to ensure all IRQ interrupts are cleared - prior to enabling nested IRQ interrupts. */ -#ifdef TX_ENABLE_IRQ_NESTING - BL _tx_thread_irq_nesting_start -#endif + MOV r0, #0xF0000 + MOV r1, #0x0 + BL init_private_timer + DSB /* For debug purpose, execute the timer interrupt processing here. In a real system, some kind of status indication would have to be checked @@ -219,13 +262,10 @@ __tx_irq_processing_return: BL _tx_timer_interrupt // Timer interrupt handler - - /* If interrupt nesting was started earlier, the end of interrupt nesting - service must be called before returning to _tx_thread_context_restore. - This routine returns in processing in IRQ mode with interrupts disabled. */ -#ifdef TX_ENABLE_IRQ_NESTING - BL _tx_thread_irq_nesting_end -#endif +by_pass_timer_interrupt: + MOV r0, r4 + BL writeEOI + POP {r4, r5} // Recover preserved registers /* Jump to context restore to restore system context. */ B _tx_thread_context_restore diff --git a/ports/cortex_a7/gnu/example_build/v7.h b/ports/cortex_a7/gnu/example_build/v7.h new file mode 100644 index 000000000..5a08b43fd --- /dev/null +++ b/ports/cortex_a7/gnu/example_build/v7.h @@ -0,0 +1,155 @@ +// ------------------------------------------------------------ +// v7-A Cache, TLB and Branch Prediction Maintenance Operations +// Header File +// +// Copyright (c) 2011-2016 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + +#ifndef _ARMV7A_GENERIC_H +#define _ARMV7A_GENERIC_H + +// ------------------------------------------------------------ +// Memory barrier mnemonics +enum MemBarOpt { + RESERVED_0 = 0, RESERVED_1 = 1, OSHST = 2, OSH = 3, + RESERVED_4 = 4, RESERVED_5 = 5, NSHST = 6, NSH = 7, + RESERVED_8 = 8, RESERVED_9 = 9, ISHST = 10, ISH = 11, + RESERVED_12 = 12, RESERVED_13 = 13, ST = 14, SY = 15 +}; + +// +// Note: +// *_IS() stands for "inner shareable" +// DO NOT USE THESE FUNCTIONS ON A CORTEX-A8 +// + +// ------------------------------------------------------------ +// Interrupts +// Enable/disables IRQs (not FIQs) +void enableInterrupts(void); +void disableInterrupts(void); + +// ------------------------------------------------------------ +// Caches + +void invalidateCaches_IS(void); +void cleanInvalidateDCache(void); +void invalidateCaches_IS(void); +void enableCaches(void); +void disableCaches(void); +void invalidateCaches(void); +void cleanDCache(void); + +// ------------------------------------------------------------ +// TLBs + +void invalidateUnifiedTLB(void); +void invalidateUnifiedTLB_IS(void); + +// ------------------------------------------------------------ +// Branch prediction + +void flushBranchTargetCache(void); +void flushBranchTargetCache_IS(void); + +// ------------------------------------------------------------ +// High Vecs + +void enableHighVecs(void); +void disableHighVecs(void); + +// ------------------------------------------------------------ +// ID Registers + +unsigned int getMIDR(void); + +#define MIDR_IMPL_SHIFT 24 +#define MIDR_IMPL_MASK 0xFF +#define MIDR_VAR_SHIFT 20 +#define MIDR_VAR_MASK 0xF +#define MIDR_ARCH_SHIFT 16 +#define MIDR_ARCH_MASK 0xF +#define MIDR_PART_SHIFT 4 +#define MIDR_PART_MASK 0xFFF +#define MIDR_REV_SHIFT 0 +#define MIDR_REV_MASK 0xF + +// tmp = get_MIDR(); +// implementor = (tmp >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; +// variant = (tmp >> MIDR_VAR_SHIFT) & MIDR_VAR_MASK; +// architecture= (tmp >> MIDR_ARCH_SHIFT) & MIDR_ARCH_MASK; +// part_number = (tmp >> MIDR_PART_SHIFT) & MIDR_PART_MASK; +// revision = tmp & MIDR_REV_MASK; + +#define MIDR_PART_CA5 0xC05 +#define MIDR_PART_CA8 0xC08 +#define MIDR_PART_CA9 0xC09 + +unsigned int getMPIDR(void); + +#define MPIDR_FORMAT_SHIFT 31 +#define MPIDR_FORMAT_MASK 0x1 +#define MPIDR_UBIT_SHIFT 30 +#define MPIDR_UBIT_MASK 0x1 +#define MPIDR_CLUSTER_SHIFT 7 +#define MPIDR_CLUSTER_MASK 0xF +#define MPIDR_CPUID_SHIFT 0 +#define MPIDR_CPUID_MASK 0x3 + +#define MPIDR_CPUID_CPU0 0x0 +#define MPIDR_CPUID_CPU1 0x1 +#define MPIDR_CPUID_CPU2 0x2 +#define MPIDR_CPUID_CPU3 0x3 + +#define MPIDR_UNIPROCESSPR 0x1 + +#define MPDIR_NEW_FORMAT 0x1 + +// ------------------------------------------------------------ +// Context ID + +unsigned int getContextID(void); + +void setContextID(unsigned int); + +#define CONTEXTID_ASID_SHIFT 0 +#define CONTEXTID_ASID_MASK 0xFF +#define CONTEXTID_PROCID_SHIFT 8 +#define CONTEXTID_PROCID_MASK 0x00FFFFFF + +// tmp = getContextID(); +// ASID = tmp & CONTEXTID_ASID_MASK; +// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK; + +// ------------------------------------------------------------ +// SMP related for Armv7-A MPCore processors +// +// DO NOT CALL THESE FUNCTIONS ON A CORTEX-A8 + +// Returns the base address of the private peripheral memory space +unsigned int getBaseAddr(void); + +// Returns the CPU ID (0 to 3) of the CPU executed on +#define MP_CPU0 (0) +#define MP_CPU1 (1) +#define MP_CPU2 (2) +#define MP_CPU3 (3) +unsigned int getCPUID(void); + +// Set this core as participating in SMP +void joinSMP(void); + +// Set this core as NOT participating in SMP +void leaveSMP(void); + +// Go to sleep, never returns +void goToSleep(void); + +#endif + +// ------------------------------------------------------------ +// End of v7.h +// ------------------------------------------------------------ diff --git a/ports/cortex_a7/gnu/example_build/v7.s b/ports/cortex_a7/gnu/example_build/v7.s new file mode 100644 index 000000000..82c9ab1e9 --- /dev/null +++ b/ports/cortex_a7/gnu/example_build/v7.s @@ -0,0 +1,476 @@ +// ------------------------------------------------------------ +// v7-A Cache and Branch Prediction Maintenance Operations +// +// Copyright (c) 2011-2018 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + + .arm +// ------------------------------------------------------------ +// Interrupt enable/disable +// ------------------------------------------------------------ + + // Could use intrinsic instead of these + + .global enableInterrupts + .type enableInterrupts,function + // void enableInterrupts(void)// +enableInterrupts: + CPSIE i + BX lr + + + .global disableInterrupts + .type disableInterrupts,function + // void disableInterrupts(void)// +disableInterrupts: + CPSID i + BX lr + + +// ------------------------------------------------------------ +// Cache Maintenance +// ------------------------------------------------------------ + + .global enableCaches + .type enableCaches,function + // void enableCaches(void)// +enableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + ORR r0, r0, #(1 << 2) // Set C bit + ORR r0, r0, #(1 << 12) // Set I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global disableCaches + .type disableCaches,function + // void disableCaches(void) +disableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + BIC r0, r0, #(1 << 2) // Clear C bit + BIC r0, r0, #(1 << 12) // Clear I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global cleanDCache + .type cleanDCache,function + // void cleanDCache(void)// +cleanDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_dcache_finished + MOV r10, #0 + +clean_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c10, 2 // DCCSW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_dcache_loop2 + +clean_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_dcache_loop1 + +clean_dcache_finished: + POP {r4-r12} + + BX lr + + + .global cleanInvalidateDCache + .type cleanInvalidateDCache,function + // void cleanInvalidateDCache(void)// +cleanInvalidateDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_invalidate_dcache_finished + MOV r10, #0 + +clean_invalidate_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_invalidate_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_invalidate_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_invalidate_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c14, 2 // DCCISW - clean and invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_invalidate_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_invalidate_dcache_loop2 + +clean_invalidate_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_invalidate_dcache_loop1 + +clean_invalidate_dcache_finished: + POP {r4-r12} + + BX lr + + + + .global invalidateCaches + .type invalidateCaches,function + // void invalidateCaches(void)// +invalidateCaches: + PUSH {r4-r12} + + // + // Based on code example given in section B2.2.4/11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 0 // ICIALLU - Invalidate entire I Cache, and flushes branch target cache + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_finished + MOV r10, #0 + +invalidate_caches_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_loop2 + +invalidate_caches_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_loop1 + +invalidate_caches_finished: + POP {r4-r12} + BX lr + + + + .global invalidateCaches_IS + .type invalidateCaches_IS,function + // void invalidateCaches_IS(void)// +invalidateCaches_IS: + PUSH {r4-r12} + + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 0 // ICIALLUIS - Invalidate entire I Cache inner shareable + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_is_finished + MOV r10, #0 + +invalidate_caches_is_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_is_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_is_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_is_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_is_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_is_loop2 + +invalidate_caches_is_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_is_loop1 + +invalidate_caches_is_finished: + POP {r4-r12} + BX lr + + +// ------------------------------------------------------------ +// TLB +// ------------------------------------------------------------ + + .global invalidateUnifiedTLB + .type invalidateUnifiedTLB,function + // void invalidateUnifiedTLB(void)// +invalidateUnifiedTLB: + MOV r0, #0 + MCR p15, 0, r0, c8, c7, 0 // TLBIALL - Invalidate entire unified TLB + BX lr + + + .global invalidateUnifiedTLB_IS + .type invalidateUnifiedTLB_IS,function + // void invalidateUnifiedTLB_IS(void)// +invalidateUnifiedTLB_IS: + MOV r0, #1 + MCR p15, 0, r0, c8, c3, 0 // TLBIALLIS - Invalidate entire unified TLB Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// Branch Prediction +// ------------------------------------------------------------ + + .global flushBranchTargetCache + .type flushBranchTargetCache,function + // void flushBranchTargetCache(void) +flushBranchTargetCache: + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 6 // BPIALL - Invalidate entire branch predictor array + BX lr + + + .global flushBranchTargetCache_IS + .type flushBranchTargetCache_IS,function + // void flushBranchTargetCache_IS(void) +flushBranchTargetCache_IS: + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 6 // BPIALLIS - Invalidate entire branch predictor array Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// High Vecs +// ------------------------------------------------------------ + + .global enableHighVecs + .type enableHighVecs,function + // void enableHighVecs(void)// +enableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + ORR r0, r0, #(1 << 13) // Set the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + + .global disableHighVecs + .type disableHighVecs,function + // void disable_highvecs(void)// +disableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + BIC r0, r0, #(1 << 13) // Clear the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + +// ------------------------------------------------------------ +// Context ID +// ------------------------------------------------------------ + + .global getContextID + .type getContextID,function + // uint32_t getContextIDd(void)// +getContextID: + MRC p15, 0, r0, c13, c0, 1 // Read Context ID Register + BX lr + + + .global setContextID + .type setContextID,function + // void setContextID(uint32_t)// +setContextID: + MCR p15, 0, r0, c13, c0, 1 // Write Context ID Register + BX lr + + +// ------------------------------------------------------------ +// ID registers +// ------------------------------------------------------------ + + .global getMIDR + .type getMIDR,function + // uint32_t getMIDR(void)// +getMIDR: + MRC p15, 0, r0, c0, c0, 0 // Read Main ID Register (MIDR) + BX lr + + + .global getMPIDR + .type getMPIDR,function + // uint32_t getMPIDR(void)// +getMPIDR: + MRC p15, 0, r0, c0 ,c0, 5// Read Multiprocessor ID register (MPIDR) + BX lr + + +// ------------------------------------------------------------ +// CP15 SMP related +// ------------------------------------------------------------ + + .global getBaseAddr + .type getBaseAddr,function + // uint32_t getBaseAddr(void) + // Returns the value CBAR (base address of the private peripheral memory space) +getBaseAddr: + MRC p15, 4, r0, c15, c0, 0 // Read peripheral base address + BX lr + + +// ------------------------------------------------------------ + + .global getCPUID + .type getCPUID,function + // uint32_t getCPUID(void) + // Returns the CPU ID (0 to 3) of the CPU executed on +getCPUID: + MRC p15, 0, r0, c0, c0, 5 // Read CPU ID register + AND r0, r0, #0x03 // Mask off, leaving the CPU ID field + BX lr + + +// ------------------------------------------------------------ + + .global goToSleep + .type goToSleep,function + // void goToSleep(void) +goToSleep: + DSB // Clear all pending data accesses + WFI // Go into standby + B goToSleep // Catch in case of rogue events + BX lr + + +// ------------------------------------------------------------ + + .global joinSMP + .type joinSMP,function + // void joinSMP(void) + // Sets the ACTRL.SMP bit +joinSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + MOV r1, r0 + ORR r0, r0, #0x040 // Set bit 6 + CMP r0, r1 + MCRNE p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ + + .global leaveSMP + .type leaveSMP,function + // void leaveSMP(void) + // Clear the ACTRL.SMP bit +leaveSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + BIC r0, r0, #0x040 // Clear bit 6 + MCR p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ +// End of v7.s +// ------------------------------------------------------------ diff --git a/ports/cortex_a8/gnu/example_build/crt0.S b/ports/cortex_a8/gnu/example_build/crt0.S index 56b6c9580..d25196ef6 100644 --- a/ports/cortex_a8/gnu/example_build/crt0.S +++ b/ports/cortex_a8/gnu/example_build/crt0.S @@ -79,6 +79,14 @@ _mainCRTStartup: #endif #endif + .global _fini + .type _fini,function +_fini: +#ifdef __THUMB_INTERWORK + BX lr // Return to caller +#else + MOV pc, lr // Return to caller +#endif /* Workspace for Angel calls. */ .data diff --git a/ports/cortex_a8/gnu/example_build/sample_threadx.ld b/ports/cortex_a8/gnu/example_build/sample_threadx.ld index 3dea4e1ca..cb42c11cb 100644 --- a/ports/cortex_a8/gnu/example_build/sample_threadx.ld +++ b/ports/cortex_a8/gnu/example_build/sample_threadx.ld @@ -109,7 +109,7 @@ SECTIONS .eh_frame_hdr : { *(.eh_frame_hdr) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); + . = 0x2E000000; .data : { *(.data) diff --git a/ports/cortex_a8/gnu/example_build/v7.h b/ports/cortex_a8/gnu/example_build/v7.h new file mode 100644 index 000000000..5a08b43fd --- /dev/null +++ b/ports/cortex_a8/gnu/example_build/v7.h @@ -0,0 +1,155 @@ +// ------------------------------------------------------------ +// v7-A Cache, TLB and Branch Prediction Maintenance Operations +// Header File +// +// Copyright (c) 2011-2016 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + +#ifndef _ARMV7A_GENERIC_H +#define _ARMV7A_GENERIC_H + +// ------------------------------------------------------------ +// Memory barrier mnemonics +enum MemBarOpt { + RESERVED_0 = 0, RESERVED_1 = 1, OSHST = 2, OSH = 3, + RESERVED_4 = 4, RESERVED_5 = 5, NSHST = 6, NSH = 7, + RESERVED_8 = 8, RESERVED_9 = 9, ISHST = 10, ISH = 11, + RESERVED_12 = 12, RESERVED_13 = 13, ST = 14, SY = 15 +}; + +// +// Note: +// *_IS() stands for "inner shareable" +// DO NOT USE THESE FUNCTIONS ON A CORTEX-A8 +// + +// ------------------------------------------------------------ +// Interrupts +// Enable/disables IRQs (not FIQs) +void enableInterrupts(void); +void disableInterrupts(void); + +// ------------------------------------------------------------ +// Caches + +void invalidateCaches_IS(void); +void cleanInvalidateDCache(void); +void invalidateCaches_IS(void); +void enableCaches(void); +void disableCaches(void); +void invalidateCaches(void); +void cleanDCache(void); + +// ------------------------------------------------------------ +// TLBs + +void invalidateUnifiedTLB(void); +void invalidateUnifiedTLB_IS(void); + +// ------------------------------------------------------------ +// Branch prediction + +void flushBranchTargetCache(void); +void flushBranchTargetCache_IS(void); + +// ------------------------------------------------------------ +// High Vecs + +void enableHighVecs(void); +void disableHighVecs(void); + +// ------------------------------------------------------------ +// ID Registers + +unsigned int getMIDR(void); + +#define MIDR_IMPL_SHIFT 24 +#define MIDR_IMPL_MASK 0xFF +#define MIDR_VAR_SHIFT 20 +#define MIDR_VAR_MASK 0xF +#define MIDR_ARCH_SHIFT 16 +#define MIDR_ARCH_MASK 0xF +#define MIDR_PART_SHIFT 4 +#define MIDR_PART_MASK 0xFFF +#define MIDR_REV_SHIFT 0 +#define MIDR_REV_MASK 0xF + +// tmp = get_MIDR(); +// implementor = (tmp >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; +// variant = (tmp >> MIDR_VAR_SHIFT) & MIDR_VAR_MASK; +// architecture= (tmp >> MIDR_ARCH_SHIFT) & MIDR_ARCH_MASK; +// part_number = (tmp >> MIDR_PART_SHIFT) & MIDR_PART_MASK; +// revision = tmp & MIDR_REV_MASK; + +#define MIDR_PART_CA5 0xC05 +#define MIDR_PART_CA8 0xC08 +#define MIDR_PART_CA9 0xC09 + +unsigned int getMPIDR(void); + +#define MPIDR_FORMAT_SHIFT 31 +#define MPIDR_FORMAT_MASK 0x1 +#define MPIDR_UBIT_SHIFT 30 +#define MPIDR_UBIT_MASK 0x1 +#define MPIDR_CLUSTER_SHIFT 7 +#define MPIDR_CLUSTER_MASK 0xF +#define MPIDR_CPUID_SHIFT 0 +#define MPIDR_CPUID_MASK 0x3 + +#define MPIDR_CPUID_CPU0 0x0 +#define MPIDR_CPUID_CPU1 0x1 +#define MPIDR_CPUID_CPU2 0x2 +#define MPIDR_CPUID_CPU3 0x3 + +#define MPIDR_UNIPROCESSPR 0x1 + +#define MPDIR_NEW_FORMAT 0x1 + +// ------------------------------------------------------------ +// Context ID + +unsigned int getContextID(void); + +void setContextID(unsigned int); + +#define CONTEXTID_ASID_SHIFT 0 +#define CONTEXTID_ASID_MASK 0xFF +#define CONTEXTID_PROCID_SHIFT 8 +#define CONTEXTID_PROCID_MASK 0x00FFFFFF + +// tmp = getContextID(); +// ASID = tmp & CONTEXTID_ASID_MASK; +// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK; + +// ------------------------------------------------------------ +// SMP related for Armv7-A MPCore processors +// +// DO NOT CALL THESE FUNCTIONS ON A CORTEX-A8 + +// Returns the base address of the private peripheral memory space +unsigned int getBaseAddr(void); + +// Returns the CPU ID (0 to 3) of the CPU executed on +#define MP_CPU0 (0) +#define MP_CPU1 (1) +#define MP_CPU2 (2) +#define MP_CPU3 (3) +unsigned int getCPUID(void); + +// Set this core as participating in SMP +void joinSMP(void); + +// Set this core as NOT participating in SMP +void leaveSMP(void); + +// Go to sleep, never returns +void goToSleep(void); + +#endif + +// ------------------------------------------------------------ +// End of v7.h +// ------------------------------------------------------------ diff --git a/ports/cortex_a8/gnu/example_build/v7.s b/ports/cortex_a8/gnu/example_build/v7.s new file mode 100644 index 000000000..82c9ab1e9 --- /dev/null +++ b/ports/cortex_a8/gnu/example_build/v7.s @@ -0,0 +1,476 @@ +// ------------------------------------------------------------ +// v7-A Cache and Branch Prediction Maintenance Operations +// +// Copyright (c) 2011-2018 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + + .arm +// ------------------------------------------------------------ +// Interrupt enable/disable +// ------------------------------------------------------------ + + // Could use intrinsic instead of these + + .global enableInterrupts + .type enableInterrupts,function + // void enableInterrupts(void)// +enableInterrupts: + CPSIE i + BX lr + + + .global disableInterrupts + .type disableInterrupts,function + // void disableInterrupts(void)// +disableInterrupts: + CPSID i + BX lr + + +// ------------------------------------------------------------ +// Cache Maintenance +// ------------------------------------------------------------ + + .global enableCaches + .type enableCaches,function + // void enableCaches(void)// +enableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + ORR r0, r0, #(1 << 2) // Set C bit + ORR r0, r0, #(1 << 12) // Set I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global disableCaches + .type disableCaches,function + // void disableCaches(void) +disableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + BIC r0, r0, #(1 << 2) // Clear C bit + BIC r0, r0, #(1 << 12) // Clear I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global cleanDCache + .type cleanDCache,function + // void cleanDCache(void)// +cleanDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_dcache_finished + MOV r10, #0 + +clean_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c10, 2 // DCCSW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_dcache_loop2 + +clean_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_dcache_loop1 + +clean_dcache_finished: + POP {r4-r12} + + BX lr + + + .global cleanInvalidateDCache + .type cleanInvalidateDCache,function + // void cleanInvalidateDCache(void)// +cleanInvalidateDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_invalidate_dcache_finished + MOV r10, #0 + +clean_invalidate_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_invalidate_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_invalidate_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_invalidate_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c14, 2 // DCCISW - clean and invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_invalidate_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_invalidate_dcache_loop2 + +clean_invalidate_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_invalidate_dcache_loop1 + +clean_invalidate_dcache_finished: + POP {r4-r12} + + BX lr + + + + .global invalidateCaches + .type invalidateCaches,function + // void invalidateCaches(void)// +invalidateCaches: + PUSH {r4-r12} + + // + // Based on code example given in section B2.2.4/11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 0 // ICIALLU - Invalidate entire I Cache, and flushes branch target cache + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_finished + MOV r10, #0 + +invalidate_caches_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_loop2 + +invalidate_caches_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_loop1 + +invalidate_caches_finished: + POP {r4-r12} + BX lr + + + + .global invalidateCaches_IS + .type invalidateCaches_IS,function + // void invalidateCaches_IS(void)// +invalidateCaches_IS: + PUSH {r4-r12} + + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 0 // ICIALLUIS - Invalidate entire I Cache inner shareable + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_is_finished + MOV r10, #0 + +invalidate_caches_is_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_is_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_is_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_is_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_is_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_is_loop2 + +invalidate_caches_is_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_is_loop1 + +invalidate_caches_is_finished: + POP {r4-r12} + BX lr + + +// ------------------------------------------------------------ +// TLB +// ------------------------------------------------------------ + + .global invalidateUnifiedTLB + .type invalidateUnifiedTLB,function + // void invalidateUnifiedTLB(void)// +invalidateUnifiedTLB: + MOV r0, #0 + MCR p15, 0, r0, c8, c7, 0 // TLBIALL - Invalidate entire unified TLB + BX lr + + + .global invalidateUnifiedTLB_IS + .type invalidateUnifiedTLB_IS,function + // void invalidateUnifiedTLB_IS(void)// +invalidateUnifiedTLB_IS: + MOV r0, #1 + MCR p15, 0, r0, c8, c3, 0 // TLBIALLIS - Invalidate entire unified TLB Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// Branch Prediction +// ------------------------------------------------------------ + + .global flushBranchTargetCache + .type flushBranchTargetCache,function + // void flushBranchTargetCache(void) +flushBranchTargetCache: + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 6 // BPIALL - Invalidate entire branch predictor array + BX lr + + + .global flushBranchTargetCache_IS + .type flushBranchTargetCache_IS,function + // void flushBranchTargetCache_IS(void) +flushBranchTargetCache_IS: + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 6 // BPIALLIS - Invalidate entire branch predictor array Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// High Vecs +// ------------------------------------------------------------ + + .global enableHighVecs + .type enableHighVecs,function + // void enableHighVecs(void)// +enableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + ORR r0, r0, #(1 << 13) // Set the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + + .global disableHighVecs + .type disableHighVecs,function + // void disable_highvecs(void)// +disableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + BIC r0, r0, #(1 << 13) // Clear the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + +// ------------------------------------------------------------ +// Context ID +// ------------------------------------------------------------ + + .global getContextID + .type getContextID,function + // uint32_t getContextIDd(void)// +getContextID: + MRC p15, 0, r0, c13, c0, 1 // Read Context ID Register + BX lr + + + .global setContextID + .type setContextID,function + // void setContextID(uint32_t)// +setContextID: + MCR p15, 0, r0, c13, c0, 1 // Write Context ID Register + BX lr + + +// ------------------------------------------------------------ +// ID registers +// ------------------------------------------------------------ + + .global getMIDR + .type getMIDR,function + // uint32_t getMIDR(void)// +getMIDR: + MRC p15, 0, r0, c0, c0, 0 // Read Main ID Register (MIDR) + BX lr + + + .global getMPIDR + .type getMPIDR,function + // uint32_t getMPIDR(void)// +getMPIDR: + MRC p15, 0, r0, c0 ,c0, 5// Read Multiprocessor ID register (MPIDR) + BX lr + + +// ------------------------------------------------------------ +// CP15 SMP related +// ------------------------------------------------------------ + + .global getBaseAddr + .type getBaseAddr,function + // uint32_t getBaseAddr(void) + // Returns the value CBAR (base address of the private peripheral memory space) +getBaseAddr: + MRC p15, 4, r0, c15, c0, 0 // Read peripheral base address + BX lr + + +// ------------------------------------------------------------ + + .global getCPUID + .type getCPUID,function + // uint32_t getCPUID(void) + // Returns the CPU ID (0 to 3) of the CPU executed on +getCPUID: + MRC p15, 0, r0, c0, c0, 5 // Read CPU ID register + AND r0, r0, #0x03 // Mask off, leaving the CPU ID field + BX lr + + +// ------------------------------------------------------------ + + .global goToSleep + .type goToSleep,function + // void goToSleep(void) +goToSleep: + DSB // Clear all pending data accesses + WFI // Go into standby + B goToSleep // Catch in case of rogue events + BX lr + + +// ------------------------------------------------------------ + + .global joinSMP + .type joinSMP,function + // void joinSMP(void) + // Sets the ACTRL.SMP bit +joinSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + MOV r1, r0 + ORR r0, r0, #0x040 // Set bit 6 + CMP r0, r1 + MCRNE p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ + + .global leaveSMP + .type leaveSMP,function + // void leaveSMP(void) + // Clear the ACTRL.SMP bit +leaveSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + BIC r0, r0, #0x040 // Clear bit 6 + MCR p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ +// End of v7.s +// ------------------------------------------------------------ diff --git a/ports/cortex_a9/gnu/example_build/crt0.S b/ports/cortex_a9/gnu/example_build/crt0.S index 56b6c9580..d25196ef6 100644 --- a/ports/cortex_a9/gnu/example_build/crt0.S +++ b/ports/cortex_a9/gnu/example_build/crt0.S @@ -79,6 +79,14 @@ _mainCRTStartup: #endif #endif + .global _fini + .type _fini,function +_fini: +#ifdef __THUMB_INTERWORK + BX lr // Return to caller +#else + MOV pc, lr // Return to caller +#endif /* Workspace for Angel calls. */ .data diff --git a/ports/cortex_a9/gnu/example_build/sample_threadx.ld b/ports/cortex_a9/gnu/example_build/sample_threadx.ld index 3dea4e1ca..cb42c11cb 100644 --- a/ports/cortex_a9/gnu/example_build/sample_threadx.ld +++ b/ports/cortex_a9/gnu/example_build/sample_threadx.ld @@ -109,7 +109,7 @@ SECTIONS .eh_frame_hdr : { *(.eh_frame_hdr) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); + . = 0x2E000000; .data : { *(.data) diff --git a/ports/cortex_a9/gnu/example_build/v7.h b/ports/cortex_a9/gnu/example_build/v7.h new file mode 100644 index 000000000..5a08b43fd --- /dev/null +++ b/ports/cortex_a9/gnu/example_build/v7.h @@ -0,0 +1,155 @@ +// ------------------------------------------------------------ +// v7-A Cache, TLB and Branch Prediction Maintenance Operations +// Header File +// +// Copyright (c) 2011-2016 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + +#ifndef _ARMV7A_GENERIC_H +#define _ARMV7A_GENERIC_H + +// ------------------------------------------------------------ +// Memory barrier mnemonics +enum MemBarOpt { + RESERVED_0 = 0, RESERVED_1 = 1, OSHST = 2, OSH = 3, + RESERVED_4 = 4, RESERVED_5 = 5, NSHST = 6, NSH = 7, + RESERVED_8 = 8, RESERVED_9 = 9, ISHST = 10, ISH = 11, + RESERVED_12 = 12, RESERVED_13 = 13, ST = 14, SY = 15 +}; + +// +// Note: +// *_IS() stands for "inner shareable" +// DO NOT USE THESE FUNCTIONS ON A CORTEX-A8 +// + +// ------------------------------------------------------------ +// Interrupts +// Enable/disables IRQs (not FIQs) +void enableInterrupts(void); +void disableInterrupts(void); + +// ------------------------------------------------------------ +// Caches + +void invalidateCaches_IS(void); +void cleanInvalidateDCache(void); +void invalidateCaches_IS(void); +void enableCaches(void); +void disableCaches(void); +void invalidateCaches(void); +void cleanDCache(void); + +// ------------------------------------------------------------ +// TLBs + +void invalidateUnifiedTLB(void); +void invalidateUnifiedTLB_IS(void); + +// ------------------------------------------------------------ +// Branch prediction + +void flushBranchTargetCache(void); +void flushBranchTargetCache_IS(void); + +// ------------------------------------------------------------ +// High Vecs + +void enableHighVecs(void); +void disableHighVecs(void); + +// ------------------------------------------------------------ +// ID Registers + +unsigned int getMIDR(void); + +#define MIDR_IMPL_SHIFT 24 +#define MIDR_IMPL_MASK 0xFF +#define MIDR_VAR_SHIFT 20 +#define MIDR_VAR_MASK 0xF +#define MIDR_ARCH_SHIFT 16 +#define MIDR_ARCH_MASK 0xF +#define MIDR_PART_SHIFT 4 +#define MIDR_PART_MASK 0xFFF +#define MIDR_REV_SHIFT 0 +#define MIDR_REV_MASK 0xF + +// tmp = get_MIDR(); +// implementor = (tmp >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; +// variant = (tmp >> MIDR_VAR_SHIFT) & MIDR_VAR_MASK; +// architecture= (tmp >> MIDR_ARCH_SHIFT) & MIDR_ARCH_MASK; +// part_number = (tmp >> MIDR_PART_SHIFT) & MIDR_PART_MASK; +// revision = tmp & MIDR_REV_MASK; + +#define MIDR_PART_CA5 0xC05 +#define MIDR_PART_CA8 0xC08 +#define MIDR_PART_CA9 0xC09 + +unsigned int getMPIDR(void); + +#define MPIDR_FORMAT_SHIFT 31 +#define MPIDR_FORMAT_MASK 0x1 +#define MPIDR_UBIT_SHIFT 30 +#define MPIDR_UBIT_MASK 0x1 +#define MPIDR_CLUSTER_SHIFT 7 +#define MPIDR_CLUSTER_MASK 0xF +#define MPIDR_CPUID_SHIFT 0 +#define MPIDR_CPUID_MASK 0x3 + +#define MPIDR_CPUID_CPU0 0x0 +#define MPIDR_CPUID_CPU1 0x1 +#define MPIDR_CPUID_CPU2 0x2 +#define MPIDR_CPUID_CPU3 0x3 + +#define MPIDR_UNIPROCESSPR 0x1 + +#define MPDIR_NEW_FORMAT 0x1 + +// ------------------------------------------------------------ +// Context ID + +unsigned int getContextID(void); + +void setContextID(unsigned int); + +#define CONTEXTID_ASID_SHIFT 0 +#define CONTEXTID_ASID_MASK 0xFF +#define CONTEXTID_PROCID_SHIFT 8 +#define CONTEXTID_PROCID_MASK 0x00FFFFFF + +// tmp = getContextID(); +// ASID = tmp & CONTEXTID_ASID_MASK; +// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK; + +// ------------------------------------------------------------ +// SMP related for Armv7-A MPCore processors +// +// DO NOT CALL THESE FUNCTIONS ON A CORTEX-A8 + +// Returns the base address of the private peripheral memory space +unsigned int getBaseAddr(void); + +// Returns the CPU ID (0 to 3) of the CPU executed on +#define MP_CPU0 (0) +#define MP_CPU1 (1) +#define MP_CPU2 (2) +#define MP_CPU3 (3) +unsigned int getCPUID(void); + +// Set this core as participating in SMP +void joinSMP(void); + +// Set this core as NOT participating in SMP +void leaveSMP(void); + +// Go to sleep, never returns +void goToSleep(void); + +#endif + +// ------------------------------------------------------------ +// End of v7.h +// ------------------------------------------------------------ diff --git a/ports/cortex_a9/gnu/example_build/v7.s b/ports/cortex_a9/gnu/example_build/v7.s new file mode 100644 index 000000000..82c9ab1e9 --- /dev/null +++ b/ports/cortex_a9/gnu/example_build/v7.s @@ -0,0 +1,476 @@ +// ------------------------------------------------------------ +// v7-A Cache and Branch Prediction Maintenance Operations +// +// Copyright (c) 2011-2018 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + + .arm +// ------------------------------------------------------------ +// Interrupt enable/disable +// ------------------------------------------------------------ + + // Could use intrinsic instead of these + + .global enableInterrupts + .type enableInterrupts,function + // void enableInterrupts(void)// +enableInterrupts: + CPSIE i + BX lr + + + .global disableInterrupts + .type disableInterrupts,function + // void disableInterrupts(void)// +disableInterrupts: + CPSID i + BX lr + + +// ------------------------------------------------------------ +// Cache Maintenance +// ------------------------------------------------------------ + + .global enableCaches + .type enableCaches,function + // void enableCaches(void)// +enableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + ORR r0, r0, #(1 << 2) // Set C bit + ORR r0, r0, #(1 << 12) // Set I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global disableCaches + .type disableCaches,function + // void disableCaches(void) +disableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + BIC r0, r0, #(1 << 2) // Clear C bit + BIC r0, r0, #(1 << 12) // Clear I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global cleanDCache + .type cleanDCache,function + // void cleanDCache(void)// +cleanDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_dcache_finished + MOV r10, #0 + +clean_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c10, 2 // DCCSW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_dcache_loop2 + +clean_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_dcache_loop1 + +clean_dcache_finished: + POP {r4-r12} + + BX lr + + + .global cleanInvalidateDCache + .type cleanInvalidateDCache,function + // void cleanInvalidateDCache(void)// +cleanInvalidateDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_invalidate_dcache_finished + MOV r10, #0 + +clean_invalidate_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_invalidate_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_invalidate_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_invalidate_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c14, 2 // DCCISW - clean and invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_invalidate_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_invalidate_dcache_loop2 + +clean_invalidate_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_invalidate_dcache_loop1 + +clean_invalidate_dcache_finished: + POP {r4-r12} + + BX lr + + + + .global invalidateCaches + .type invalidateCaches,function + // void invalidateCaches(void)// +invalidateCaches: + PUSH {r4-r12} + + // + // Based on code example given in section B2.2.4/11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 0 // ICIALLU - Invalidate entire I Cache, and flushes branch target cache + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_finished + MOV r10, #0 + +invalidate_caches_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_loop2 + +invalidate_caches_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_loop1 + +invalidate_caches_finished: + POP {r4-r12} + BX lr + + + + .global invalidateCaches_IS + .type invalidateCaches_IS,function + // void invalidateCaches_IS(void)// +invalidateCaches_IS: + PUSH {r4-r12} + + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 0 // ICIALLUIS - Invalidate entire I Cache inner shareable + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_is_finished + MOV r10, #0 + +invalidate_caches_is_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_is_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_is_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_is_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_is_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_is_loop2 + +invalidate_caches_is_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_is_loop1 + +invalidate_caches_is_finished: + POP {r4-r12} + BX lr + + +// ------------------------------------------------------------ +// TLB +// ------------------------------------------------------------ + + .global invalidateUnifiedTLB + .type invalidateUnifiedTLB,function + // void invalidateUnifiedTLB(void)// +invalidateUnifiedTLB: + MOV r0, #0 + MCR p15, 0, r0, c8, c7, 0 // TLBIALL - Invalidate entire unified TLB + BX lr + + + .global invalidateUnifiedTLB_IS + .type invalidateUnifiedTLB_IS,function + // void invalidateUnifiedTLB_IS(void)// +invalidateUnifiedTLB_IS: + MOV r0, #1 + MCR p15, 0, r0, c8, c3, 0 // TLBIALLIS - Invalidate entire unified TLB Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// Branch Prediction +// ------------------------------------------------------------ + + .global flushBranchTargetCache + .type flushBranchTargetCache,function + // void flushBranchTargetCache(void) +flushBranchTargetCache: + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 6 // BPIALL - Invalidate entire branch predictor array + BX lr + + + .global flushBranchTargetCache_IS + .type flushBranchTargetCache_IS,function + // void flushBranchTargetCache_IS(void) +flushBranchTargetCache_IS: + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 6 // BPIALLIS - Invalidate entire branch predictor array Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// High Vecs +// ------------------------------------------------------------ + + .global enableHighVecs + .type enableHighVecs,function + // void enableHighVecs(void)// +enableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + ORR r0, r0, #(1 << 13) // Set the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + + .global disableHighVecs + .type disableHighVecs,function + // void disable_highvecs(void)// +disableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + BIC r0, r0, #(1 << 13) // Clear the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + +// ------------------------------------------------------------ +// Context ID +// ------------------------------------------------------------ + + .global getContextID + .type getContextID,function + // uint32_t getContextIDd(void)// +getContextID: + MRC p15, 0, r0, c13, c0, 1 // Read Context ID Register + BX lr + + + .global setContextID + .type setContextID,function + // void setContextID(uint32_t)// +setContextID: + MCR p15, 0, r0, c13, c0, 1 // Write Context ID Register + BX lr + + +// ------------------------------------------------------------ +// ID registers +// ------------------------------------------------------------ + + .global getMIDR + .type getMIDR,function + // uint32_t getMIDR(void)// +getMIDR: + MRC p15, 0, r0, c0, c0, 0 // Read Main ID Register (MIDR) + BX lr + + + .global getMPIDR + .type getMPIDR,function + // uint32_t getMPIDR(void)// +getMPIDR: + MRC p15, 0, r0, c0 ,c0, 5// Read Multiprocessor ID register (MPIDR) + BX lr + + +// ------------------------------------------------------------ +// CP15 SMP related +// ------------------------------------------------------------ + + .global getBaseAddr + .type getBaseAddr,function + // uint32_t getBaseAddr(void) + // Returns the value CBAR (base address of the private peripheral memory space) +getBaseAddr: + MRC p15, 4, r0, c15, c0, 0 // Read peripheral base address + BX lr + + +// ------------------------------------------------------------ + + .global getCPUID + .type getCPUID,function + // uint32_t getCPUID(void) + // Returns the CPU ID (0 to 3) of the CPU executed on +getCPUID: + MRC p15, 0, r0, c0, c0, 5 // Read CPU ID register + AND r0, r0, #0x03 // Mask off, leaving the CPU ID field + BX lr + + +// ------------------------------------------------------------ + + .global goToSleep + .type goToSleep,function + // void goToSleep(void) +goToSleep: + DSB // Clear all pending data accesses + WFI // Go into standby + B goToSleep // Catch in case of rogue events + BX lr + + +// ------------------------------------------------------------ + + .global joinSMP + .type joinSMP,function + // void joinSMP(void) + // Sets the ACTRL.SMP bit +joinSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + MOV r1, r0 + ORR r0, r0, #0x040 // Set bit 6 + CMP r0, r1 + MCRNE p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ + + .global leaveSMP + .type leaveSMP,function + // void leaveSMP(void) + // Clear the ACTRL.SMP bit +leaveSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + BIC r0, r0, #0x040 // Clear bit 6 + MCR p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ +// End of v7.s +// ------------------------------------------------------------ diff --git a/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/crt0.S b/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/crt0.S index 56b6c9580..d25196ef6 100644 --- a/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/crt0.S +++ b/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/crt0.S @@ -79,6 +79,14 @@ _mainCRTStartup: #endif #endif + .global _fini + .type _fini,function +_fini: +#ifdef __THUMB_INTERWORK + BX lr // Return to caller +#else + MOV pc, lr // Return to caller +#endif /* Workspace for Angel calls. */ .data diff --git a/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/sample_threadx.ld b/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/sample_threadx.ld index 3dea4e1ca..cb42c11cb 100644 --- a/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/sample_threadx.ld +++ b/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/sample_threadx.ld @@ -109,7 +109,7 @@ SECTIONS .eh_frame_hdr : { *(.eh_frame_hdr) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); + . = 0x2E000000; .data : { *(.data) diff --git a/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/tx_initialize_low_level.S b/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/tx_initialize_low_level.S deleted file mode 100644 index 4b324e0ac..000000000 --- a/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/tx_initialize_low_level.S +++ /dev/null @@ -1,311 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** ThreadX Component */ -/** */ -/** Initialize */ -/** */ -/**************************************************************************/ -/**************************************************************************/ -#ifdef TX_INCLUDE_USER_DEFINE_FILE -#include "tx_user.h" -#endif - - .arm - -SVC_MODE = 0xD3 // Disable IRQ/FIQ SVC mode -IRQ_MODE = 0xD2 // Disable IRQ/FIQ IRQ mode -FIQ_MODE = 0xD1 // Disable IRQ/FIQ FIQ mode -SYS_MODE = 0xDF // Disable IRQ/FIQ SYS mode -FIQ_STACK_SIZE = 512 // FIQ stack size -IRQ_STACK_SIZE = 1024 // IRQ stack size -SYS_STACK_SIZE = 1024 // System stack size - - .global _tx_thread_system_stack_ptr - .global _tx_initialize_unused_memory - .global _tx_thread_context_save - .global _tx_thread_context_restore - .global _tx_timer_interrupt - .global _end - .global _sp - .global _stack_bottom - - -/* Define the 16-bit Thumb mode veneer for _tx_initialize_low_level for - applications calling this function from to 16-bit Thumb mode. */ - - .text - .align 2 - .thumb - .global $_tx_initialize_low_level - .type $_tx_initialize_low_level,function -$_tx_initialize_low_level: - BX pc // Switch to 32-bit mode - NOP // - .arm - STMFD sp!, {lr} // Save return address - BL _tx_initialize_low_level // Call _tx_initialize_low_level function - LDMFD sp!, {lr} // Recover saved return address - BX lr // Return to 16-bit caller - - .text - .align 2 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _tx_initialize_low_level ARMv7-A */ -/* 6.x */ -/* AUTHOR */ -/* */ -/* William E. Lamie, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is responsible for any low-level processor */ -/* initialization, including setting up interrupt vectors, setting */ -/* up a periodic timer interrupt source, saving the system stack */ -/* pointer for use in ISR processing later, and finding the first */ -/* available RAM memory address for tx_application_define. */ -/* */ -/* INPUT */ -/* */ -/* None */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _tx_initialize_kernel_enter ThreadX entry function */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 09-30-2020 William E. Lamie Initial Version 6.1 */ -/* 04-25-2022 Zhen Kong Updated comments, */ -/* resulting in version 6.1.11 */ -/* xx-xx-xxxx Tiejun Zhou Modified comment(s), added */ -/* #include tx_user.h, */ -/* resulting in version 6.x */ -/* */ -/**************************************************************************/ - .global _tx_initialize_low_level - .type _tx_initialize_low_level,function -_tx_initialize_low_level: - - /* We must be in SVC mode at this point! */ - - /* Setup various stack pointers. */ - - LDR r1, =_sp // Get pointer to stack area - -#ifdef TX_ENABLE_IRQ_NESTING - - /* Setup the system mode stack for nested interrupt support */ - - LDR r2, =SYS_STACK_SIZE // Pickup stack size - MOV r3, #SYS_MODE // Build SYS mode CPSR - MSR CPSR_c, r3 // Enter SYS mode - SUB r1, r1, #1 // Backup 1 byte - BIC r1, r1, #7 // Ensure 8-byte alignment - MOV sp, r1 // Setup SYS stack pointer - SUB r1, r1, r2 // Calculate start of next stack -#endif - - LDR r2, =FIQ_STACK_SIZE // Pickup stack size - MOV r0, #FIQ_MODE // Build FIQ mode CPSR - MSR CPSR, r0 // Enter FIQ mode - SUB r1, r1, #1 // Backup 1 byte - BIC r1, r1, #7 // Ensure 8-byte alignment - MOV sp, r1 // Setup FIQ stack pointer - SUB r1, r1, r2 // Calculate start of next stack - LDR r2, =IRQ_STACK_SIZE // Pickup IRQ stack size - MOV r0, #IRQ_MODE // Build IRQ mode CPSR - MSR CPSR, r0 // Enter IRQ mode - SUB r1, r1, #1 // Backup 1 byte - BIC r1, r1, #7 // Ensure 8-byte alignment - MOV sp, r1 // Setup IRQ stack pointer - SUB r3, r1, r2 // Calculate end of IRQ stack - MOV r0, #SVC_MODE // Build SVC mode CPSR - MSR CPSR, r0 // Enter SVC mode - LDR r2, =_stack_bottom // Pickup stack bottom - CMP r3, r2 // Compare the current stack end with the bottom -_stack_error_loop: - BLT _stack_error_loop // If the IRQ stack exceeds the stack bottom, just sit here! - - LDR r2, =_tx_thread_system_stack_ptr // Pickup stack pointer - STR r1, [r2] // Save the system stack - - LDR r1, =_end // Get end of non-initialized RAM area - LDR r2, =_tx_initialize_unused_memory // Pickup unused memory ptr address - ADD r1, r1, #8 // Increment to next free word - STR r1, [r2] // Save first free memory address - -#ifdef __THUMB_INTERWORK - BX lr // Return to caller -#else - MOV pc, lr // Return to caller -#endif - -/* Define shells for each of the interrupt vectors. */ - - .global __tx_undefined -__tx_undefined: - B __tx_undefined // Undefined handler - - .global __tx_swi_interrupt -__tx_swi_interrupt: - B __tx_swi_interrupt // Software interrupt handler - - .global __tx_prefetch_handler -__tx_prefetch_handler: - B __tx_prefetch_handler // Prefetch exception handler - - .global __tx_abort_handler -__tx_abort_handler: - B __tx_abort_handler // Abort exception handler - - .global __tx_reserved_handler -__tx_reserved_handler: - B __tx_reserved_handler // Reserved exception handler - - .global __tx_irq_handler - .global __tx_irq_processing_return -__tx_irq_handler: - - /* Jump to context save to save system context. */ - B _tx_thread_context_save -__tx_irq_processing_return: -// - /* At this point execution is still in the IRQ mode. The CPSR, point of - interrupt, and all C scratch registers are available for use. In - addition, IRQ interrupts may be re-enabled - with certain restrictions - - if nested IRQ interrupts are desired. Interrupts may be re-enabled over - small code sequences where lr is saved before enabling interrupts and - restored after interrupts are again disabled. */ - - /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start - from IRQ mode with interrupts disabled. This routine switches to the - system mode and returns with IRQ interrupts enabled. - - NOTE: It is very important to ensure all IRQ interrupts are cleared - prior to enabling nested IRQ interrupts. */ -#ifdef TX_ENABLE_IRQ_NESTING - BL _tx_thread_irq_nesting_start -#endif - - /* For debug purpose, execute the timer interrupt processing here. In - a real system, some kind of status indication would have to be checked - before the timer interrupt handler could be called. */ - - BL _tx_timer_interrupt // Timer interrupt handler - - - /* If interrupt nesting was started earlier, the end of interrupt nesting - service must be called before returning to _tx_thread_context_restore. - This routine returns in processing in IRQ mode with interrupts disabled. */ -#ifdef TX_ENABLE_IRQ_NESTING - BL _tx_thread_irq_nesting_end -#endif - - /* Jump to context restore to restore system context. */ - B _tx_thread_context_restore - - - /* This is an example of a vectored IRQ handler. */ - - - - /* Save initial context and call context save to prepare for - vectored ISR execution. */ - - /* At this point execution is still in the IRQ mode. The CPSR, point of - interrupt, and all C scratch registers are available for use. In - addition, IRQ interrupts may be re-enabled - with certain restrictions - - if nested IRQ interrupts are desired. Interrupts may be re-enabled over - small code sequences where lr is saved before enabling interrupts and - restored after interrupts are again disabled. */ - - - /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start - from IRQ mode with interrupts disabled. This routine switches to the - system mode and returns with IRQ interrupts enabled. - - NOTE: It is very important to ensure all IRQ interrupts are cleared - prior to enabling nested IRQ interrupts. */ - - /* Application IRQ handlers can be called here! */ - - /* If interrupt nesting was started earlier, the end of interrupt nesting - service must be called before returning to _tx_thread_context_restore. - This routine returns in processing in IRQ mode with interrupts disabled. */ - - - -#ifdef TX_ENABLE_FIQ_SUPPORT - .global __tx_fiq_handler - .global __tx_fiq_processing_return -__tx_fiq_handler: - - /* Jump to fiq context save to save system context. */ - B _tx_thread_fiq_context_save -__tx_fiq_processing_return: - - /* At this point execution is still in the FIQ mode. The CPSR, point of - interrupt, and all C scratch registers are available for use. */ - - /* Interrupt nesting is allowed after calling _tx_thread_fiq_nesting_start - from FIQ mode with interrupts disabled. This routine switches to the - system mode and returns with FIQ interrupts enabled. - - NOTE: It is very important to ensure all FIQ interrupts are cleared - prior to enabling nested FIQ interrupts. */ -#ifdef TX_ENABLE_FIQ_NESTING - BL _tx_thread_fiq_nesting_start -#endif - - /* Application FIQ handlers can be called here! */ - - /* If interrupt nesting was started earlier, the end of interrupt nesting - service must be called before returning to _tx_thread_fiq_context_restore. */ -#ifdef TX_ENABLE_FIQ_NESTING - BL _tx_thread_fiq_nesting_end -#endif - - /* Jump to fiq context restore to restore system context. */ - B _tx_thread_fiq_context_restore - - -#else - .global __tx_fiq_handler -__tx_fiq_handler: - B __tx_fiq_handler // FIQ interrupt handler -#endif - - -BUILD_OPTIONS: - .word _tx_build_options // Reference to bring in -VERSION_ID: - .word _tx_version_id // Reference to bring in - - - diff --git a/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/v7.h b/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/v7.h new file mode 100644 index 000000000..5a08b43fd --- /dev/null +++ b/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/v7.h @@ -0,0 +1,155 @@ +// ------------------------------------------------------------ +// v7-A Cache, TLB and Branch Prediction Maintenance Operations +// Header File +// +// Copyright (c) 2011-2016 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + +#ifndef _ARMV7A_GENERIC_H +#define _ARMV7A_GENERIC_H + +// ------------------------------------------------------------ +// Memory barrier mnemonics +enum MemBarOpt { + RESERVED_0 = 0, RESERVED_1 = 1, OSHST = 2, OSH = 3, + RESERVED_4 = 4, RESERVED_5 = 5, NSHST = 6, NSH = 7, + RESERVED_8 = 8, RESERVED_9 = 9, ISHST = 10, ISH = 11, + RESERVED_12 = 12, RESERVED_13 = 13, ST = 14, SY = 15 +}; + +// +// Note: +// *_IS() stands for "inner shareable" +// DO NOT USE THESE FUNCTIONS ON A CORTEX-A8 +// + +// ------------------------------------------------------------ +// Interrupts +// Enable/disables IRQs (not FIQs) +void enableInterrupts(void); +void disableInterrupts(void); + +// ------------------------------------------------------------ +// Caches + +void invalidateCaches_IS(void); +void cleanInvalidateDCache(void); +void invalidateCaches_IS(void); +void enableCaches(void); +void disableCaches(void); +void invalidateCaches(void); +void cleanDCache(void); + +// ------------------------------------------------------------ +// TLBs + +void invalidateUnifiedTLB(void); +void invalidateUnifiedTLB_IS(void); + +// ------------------------------------------------------------ +// Branch prediction + +void flushBranchTargetCache(void); +void flushBranchTargetCache_IS(void); + +// ------------------------------------------------------------ +// High Vecs + +void enableHighVecs(void); +void disableHighVecs(void); + +// ------------------------------------------------------------ +// ID Registers + +unsigned int getMIDR(void); + +#define MIDR_IMPL_SHIFT 24 +#define MIDR_IMPL_MASK 0xFF +#define MIDR_VAR_SHIFT 20 +#define MIDR_VAR_MASK 0xF +#define MIDR_ARCH_SHIFT 16 +#define MIDR_ARCH_MASK 0xF +#define MIDR_PART_SHIFT 4 +#define MIDR_PART_MASK 0xFFF +#define MIDR_REV_SHIFT 0 +#define MIDR_REV_MASK 0xF + +// tmp = get_MIDR(); +// implementor = (tmp >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; +// variant = (tmp >> MIDR_VAR_SHIFT) & MIDR_VAR_MASK; +// architecture= (tmp >> MIDR_ARCH_SHIFT) & MIDR_ARCH_MASK; +// part_number = (tmp >> MIDR_PART_SHIFT) & MIDR_PART_MASK; +// revision = tmp & MIDR_REV_MASK; + +#define MIDR_PART_CA5 0xC05 +#define MIDR_PART_CA8 0xC08 +#define MIDR_PART_CA9 0xC09 + +unsigned int getMPIDR(void); + +#define MPIDR_FORMAT_SHIFT 31 +#define MPIDR_FORMAT_MASK 0x1 +#define MPIDR_UBIT_SHIFT 30 +#define MPIDR_UBIT_MASK 0x1 +#define MPIDR_CLUSTER_SHIFT 7 +#define MPIDR_CLUSTER_MASK 0xF +#define MPIDR_CPUID_SHIFT 0 +#define MPIDR_CPUID_MASK 0x3 + +#define MPIDR_CPUID_CPU0 0x0 +#define MPIDR_CPUID_CPU1 0x1 +#define MPIDR_CPUID_CPU2 0x2 +#define MPIDR_CPUID_CPU3 0x3 + +#define MPIDR_UNIPROCESSPR 0x1 + +#define MPDIR_NEW_FORMAT 0x1 + +// ------------------------------------------------------------ +// Context ID + +unsigned int getContextID(void); + +void setContextID(unsigned int); + +#define CONTEXTID_ASID_SHIFT 0 +#define CONTEXTID_ASID_MASK 0xFF +#define CONTEXTID_PROCID_SHIFT 8 +#define CONTEXTID_PROCID_MASK 0x00FFFFFF + +// tmp = getContextID(); +// ASID = tmp & CONTEXTID_ASID_MASK; +// PROCID = (tmp >> CONTEXTID_PROCID_SHIFT) & CONTEXTID_PROCID_MASK; + +// ------------------------------------------------------------ +// SMP related for Armv7-A MPCore processors +// +// DO NOT CALL THESE FUNCTIONS ON A CORTEX-A8 + +// Returns the base address of the private peripheral memory space +unsigned int getBaseAddr(void); + +// Returns the CPU ID (0 to 3) of the CPU executed on +#define MP_CPU0 (0) +#define MP_CPU1 (1) +#define MP_CPU2 (2) +#define MP_CPU3 (3) +unsigned int getCPUID(void); + +// Set this core as participating in SMP +void joinSMP(void); + +// Set this core as NOT participating in SMP +void leaveSMP(void); + +// Go to sleep, never returns +void goToSleep(void); + +#endif + +// ------------------------------------------------------------ +// End of v7.h +// ------------------------------------------------------------ diff --git a/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/v7.s b/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/v7.s new file mode 100644 index 000000000..82c9ab1e9 --- /dev/null +++ b/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/v7.s @@ -0,0 +1,476 @@ +// ------------------------------------------------------------ +// v7-A Cache and Branch Prediction Maintenance Operations +// +// Copyright (c) 2011-2018 Arm Limited (or its affiliates). All rights reserved. +// Use, modification and redistribution of this file is subject to your possession of a +// valid End User License Agreement for the Arm Product of which these examples are part of +// and your compliance with all applicable terms and conditions of such licence agreement. +// ------------------------------------------------------------ + + .arm +// ------------------------------------------------------------ +// Interrupt enable/disable +// ------------------------------------------------------------ + + // Could use intrinsic instead of these + + .global enableInterrupts + .type enableInterrupts,function + // void enableInterrupts(void)// +enableInterrupts: + CPSIE i + BX lr + + + .global disableInterrupts + .type disableInterrupts,function + // void disableInterrupts(void)// +disableInterrupts: + CPSID i + BX lr + + +// ------------------------------------------------------------ +// Cache Maintenance +// ------------------------------------------------------------ + + .global enableCaches + .type enableCaches,function + // void enableCaches(void)// +enableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + ORR r0, r0, #(1 << 2) // Set C bit + ORR r0, r0, #(1 << 12) // Set I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global disableCaches + .type disableCaches,function + // void disableCaches(void) +disableCaches: + MRC p15, 0, r0, c1, c0, 0 // Read System Control Register + BIC r0, r0, #(1 << 2) // Clear C bit + BIC r0, r0, #(1 << 12) // Clear I bit + MCR p15, 0, r0, c1, c0, 0 // Write System Control Register + ISB + BX lr + + + + .global cleanDCache + .type cleanDCache,function + // void cleanDCache(void)// +cleanDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_dcache_finished + MOV r10, #0 + +clean_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c10, 2 // DCCSW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_dcache_loop2 + +clean_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_dcache_loop1 + +clean_dcache_finished: + POP {r4-r12} + + BX lr + + + .global cleanInvalidateDCache + .type cleanInvalidateDCache,function + // void cleanInvalidateDCache(void)// +cleanInvalidateDCache: + PUSH {r4-r12} + + // + // Based on code example given in section 11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ clean_invalidate_dcache_finished + MOV r10, #0 + +clean_invalidate_dcache_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT clean_invalidate_dcache_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +clean_invalidate_dcache_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +clean_invalidate_dcache_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c14, 2 // DCCISW - clean and invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE clean_invalidate_dcache_loop3 + SUBS r7, r7, #1 // decrement the index + BGE clean_invalidate_dcache_loop2 + +clean_invalidate_dcache_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT clean_invalidate_dcache_loop1 + +clean_invalidate_dcache_finished: + POP {r4-r12} + + BX lr + + + + .global invalidateCaches + .type invalidateCaches,function + // void invalidateCaches(void)// +invalidateCaches: + PUSH {r4-r12} + + // + // Based on code example given in section B2.2.4/11.2.4 of Armv7-A/R Architecture Reference Manual (DDI 0406B) + // + + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 0 // ICIALLU - Invalidate entire I Cache, and flushes branch target cache + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_finished + MOV r10, #0 + +invalidate_caches_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - invalidate by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_loop2 + +invalidate_caches_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_loop1 + +invalidate_caches_finished: + POP {r4-r12} + BX lr + + + + .global invalidateCaches_IS + .type invalidateCaches_IS,function + // void invalidateCaches_IS(void)// +invalidateCaches_IS: + PUSH {r4-r12} + + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 0 // ICIALLUIS - Invalidate entire I Cache inner shareable + + MRC p15, 1, r0, c0, c0, 1 // Read CLIDR + ANDS r3, r0, #0x7000000 + MOV r3, r3, LSR #23 // Cache level value (naturally aligned) + BEQ invalidate_caches_is_finished + MOV r10, #0 + +invalidate_caches_is_loop1: + ADD r2, r10, r10, LSR #1 // Work out 3xcachelevel + MOV r1, r0, LSR r2 // bottom 3 bits are the Cache type for this level + AND r1, r1, #7 // get those 3 bits alone + CMP r1, #2 + BLT invalidate_caches_is_skip // no cache or only instruction cache at this level + MCR p15, 2, r10, c0, c0, 0 // write the Cache Size selection register + ISB // ISB to sync the change to the CacheSizeID reg + MRC p15, 1, r1, c0, c0, 0 // reads current Cache Size ID register + AND r2, r1, #7 // extract the line length field + ADD r2, r2, #4 // add 4 for the line length offset (log2 16 bytes) + LDR r4, =0x3FF + ANDS r4, r4, r1, LSR #3 // R4 is the max number on the way size (right aligned) + CLZ r5, r4 // R5 is the bit position of the way size increment + LDR r7, =0x00007FFF + ANDS r7, r7, r1, LSR #13 // R7 is the max number of the index size (right aligned) + +invalidate_caches_is_loop2: + MOV r9, R4 // R9 working copy of the max way size (right aligned) + +invalidate_caches_is_loop3: + ORR r11, r10, r9, LSL r5 // factor in the way number and cache number into R11 + ORR r11, r11, r7, LSL r2 // factor in the index number + MCR p15, 0, r11, c7, c6, 2 // DCISW - clean by set/way + SUBS r9, r9, #1 // decrement the way number + BGE invalidate_caches_is_loop3 + SUBS r7, r7, #1 // decrement the index + BGE invalidate_caches_is_loop2 + +invalidate_caches_is_skip: + ADD r10, r10, #2 // increment the cache number + CMP r3, r10 + BGT invalidate_caches_is_loop1 + +invalidate_caches_is_finished: + POP {r4-r12} + BX lr + + +// ------------------------------------------------------------ +// TLB +// ------------------------------------------------------------ + + .global invalidateUnifiedTLB + .type invalidateUnifiedTLB,function + // void invalidateUnifiedTLB(void)// +invalidateUnifiedTLB: + MOV r0, #0 + MCR p15, 0, r0, c8, c7, 0 // TLBIALL - Invalidate entire unified TLB + BX lr + + + .global invalidateUnifiedTLB_IS + .type invalidateUnifiedTLB_IS,function + // void invalidateUnifiedTLB_IS(void)// +invalidateUnifiedTLB_IS: + MOV r0, #1 + MCR p15, 0, r0, c8, c3, 0 // TLBIALLIS - Invalidate entire unified TLB Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// Branch Prediction +// ------------------------------------------------------------ + + .global flushBranchTargetCache + .type flushBranchTargetCache,function + // void flushBranchTargetCache(void) +flushBranchTargetCache: + MOV r0, #0 + MCR p15, 0, r0, c7, c5, 6 // BPIALL - Invalidate entire branch predictor array + BX lr + + + .global flushBranchTargetCache_IS + .type flushBranchTargetCache_IS,function + // void flushBranchTargetCache_IS(void) +flushBranchTargetCache_IS: + MOV r0, #0 + MCR p15, 0, r0, c7, c1, 6 // BPIALLIS - Invalidate entire branch predictor array Inner Shareable + BX lr + + +// ------------------------------------------------------------ +// High Vecs +// ------------------------------------------------------------ + + .global enableHighVecs + .type enableHighVecs,function + // void enableHighVecs(void)// +enableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + ORR r0, r0, #(1 << 13) // Set the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + + .global disableHighVecs + .type disableHighVecs,function + // void disable_highvecs(void)// +disableHighVecs: + MRC p15, 0, r0, c1, c0, 0 // Read Control Register + BIC r0, r0, #(1 << 13) // Clear the V bit (bit 13) + MCR p15, 0, r0, c1, c0, 0 // Write Control Register + ISB + BX lr + + +// ------------------------------------------------------------ +// Context ID +// ------------------------------------------------------------ + + .global getContextID + .type getContextID,function + // uint32_t getContextIDd(void)// +getContextID: + MRC p15, 0, r0, c13, c0, 1 // Read Context ID Register + BX lr + + + .global setContextID + .type setContextID,function + // void setContextID(uint32_t)// +setContextID: + MCR p15, 0, r0, c13, c0, 1 // Write Context ID Register + BX lr + + +// ------------------------------------------------------------ +// ID registers +// ------------------------------------------------------------ + + .global getMIDR + .type getMIDR,function + // uint32_t getMIDR(void)// +getMIDR: + MRC p15, 0, r0, c0, c0, 0 // Read Main ID Register (MIDR) + BX lr + + + .global getMPIDR + .type getMPIDR,function + // uint32_t getMPIDR(void)// +getMPIDR: + MRC p15, 0, r0, c0 ,c0, 5// Read Multiprocessor ID register (MPIDR) + BX lr + + +// ------------------------------------------------------------ +// CP15 SMP related +// ------------------------------------------------------------ + + .global getBaseAddr + .type getBaseAddr,function + // uint32_t getBaseAddr(void) + // Returns the value CBAR (base address of the private peripheral memory space) +getBaseAddr: + MRC p15, 4, r0, c15, c0, 0 // Read peripheral base address + BX lr + + +// ------------------------------------------------------------ + + .global getCPUID + .type getCPUID,function + // uint32_t getCPUID(void) + // Returns the CPU ID (0 to 3) of the CPU executed on +getCPUID: + MRC p15, 0, r0, c0, c0, 5 // Read CPU ID register + AND r0, r0, #0x03 // Mask off, leaving the CPU ID field + BX lr + + +// ------------------------------------------------------------ + + .global goToSleep + .type goToSleep,function + // void goToSleep(void) +goToSleep: + DSB // Clear all pending data accesses + WFI // Go into standby + B goToSleep // Catch in case of rogue events + BX lr + + +// ------------------------------------------------------------ + + .global joinSMP + .type joinSMP,function + // void joinSMP(void) + // Sets the ACTRL.SMP bit +joinSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + MOV r1, r0 + ORR r0, r0, #0x040 // Set bit 6 + CMP r0, r1 + MCRNE p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ + + .global leaveSMP + .type leaveSMP,function + // void leaveSMP(void) + // Clear the ACTRL.SMP bit +leaveSMP: + + // SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg + + MRC p15, 0, r0, c1, c0, 1 // Read ACTLR + BIC r0, r0, #0x040 // Clear bit 6 + MCR p15, 0, r0, c1, c0, 1 // Write ACTLR + ISB + + BX lr + + +// ------------------------------------------------------------ +// End of v7.s +// ------------------------------------------------------------ diff --git a/test/ports/azrtos_test_tx_gnu_cortex_a7.log.expected b/test/ports/azrtos_test_tx_gnu_cortex_a7.log.expected index 3d35b442b..21efba525 100644 --- a/test/ports/azrtos_test_tx_gnu_cortex_a7.log.expected +++ b/test/ports/azrtos_test_tx_gnu_cortex_a7.log.expected @@ -1,18 +1,18 @@ >output thread_0_counter -2913840557 +10 >output thread_1_counter -2913840557 +299267 >output thread_2_counter -2913840557 +299268 >output thread_3_counter -2913840557 +23 >output thread_4_counter -2913840557 +23 >output thread_5_counter -2913840557 +9 >output thread_6_counter -2913840557 +23 >output thread_7_counter -2913840557 +23 >log file Stopped duplicating logging output From c4e260fa8d00d1ba48e1e72ed8e2f977e6e12e9d Mon Sep 17 00:00:00 2001 From: Yajun Xia Date: Thu, 14 Sep 2023 17:24:52 +0800 Subject: [PATCH 2/2] remove untracked files. --- .../gnu/example_build/sample_threadx.out | Bin 292972 -> 0 bytes ports/cortex_a7/gnu/example_build/test.log | 18 ------------------ 2 files changed, 18 deletions(-) delete mode 100644 ports/cortex_a7/gnu/example_build/sample_threadx.out delete mode 100644 ports/cortex_a7/gnu/example_build/test.log diff --git a/ports/cortex_a7/gnu/example_build/sample_threadx.out b/ports/cortex_a7/gnu/example_build/sample_threadx.out deleted file mode 100644 index a6a1dce75b42b3de32716f03262721d93de8e6f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 292972 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 ^`mk~Me3l;Q%#N8_dSH0pbEZ0+ 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 QJvN;0Jt0%nm&y140S=Rlo&W#< diff --git a/ports/cortex_a7/gnu/example_build/test.log b/ports/cortex_a7/gnu/example_build/test.log deleted file mode 100644 index 21efba525..000000000 --- a/ports/cortex_a7/gnu/example_build/test.log +++ /dev/null @@ -1,18 +0,0 @@ ->output thread_0_counter -10 ->output thread_1_counter -299267 ->output thread_2_counter -299268 ->output thread_3_counter -23 ->output thread_4_counter -23 ->output thread_5_counter -9 ->output thread_6_counter -23 ->output thread_7_counter -23 ->log file -Stopped duplicating logging output