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..7c3a01bfd --- /dev/null +++ b/ports/cortex_a7/gnu/example_build/MP_PrivateTimer.S @@ -0,0 +1,85 @@ +// ------------------------------------------------------------ +// 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 + +// ------------------------------------------------------------ + + .global init_private_timer + .type init_private_timer,function + // 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) +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 d280eeb77..04cdf369b 100644 --- a/ports/cortex_a7/gnu/example_build/build_threadx_sample.bat +++ b/ports/cortex_a7/gnu/example_build/build_threadx_sample.bat @@ -2,9 +2,7 @@ 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 -nostartfiles -mcpu=cortex-a7 -T sample_threadx.ld --specs=nosys.specs -o sample_threadx.out -Wl,-Map=sample_threadx.map MP_GIC.o V7.o crt0.o reset.o 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/tx_initialize_low_level.S b/ports/cortex_a7/gnu/example_build/tx_initialize_low_level.S index 4b324e0ac..4a9488964 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,57 @@ _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) + + // [EL] Change start - don't enable interrupts here! + //CPSIE i // Clear CPSR I bit + // [EL] Change end + + // 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 + + // + // Enable receipt of SGI 0 + // ------------------------ + MOV r0, #0x0 // ID + BL enableIntID + + // Set the priority + MOV r0, #0x0 // ID + MOV r1, #0x0 // Priority + BL setIntPriority + + POP {lr} #ifdef __THUMB_INTERWORK BX lr // Return to caller #else @@ -202,16 +258,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 +277,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_a8/gnu/example_build/MP_PrivateTimer.S b/ports/cortex_a8/gnu/example_build/MP_PrivateTimer.S new file mode 100644 index 000000000..7c3a01bfd --- /dev/null +++ b/ports/cortex_a8/gnu/example_build/MP_PrivateTimer.S @@ -0,0 +1,85 @@ +// ------------------------------------------------------------ +// 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 + +// ------------------------------------------------------------ + + .global init_private_timer + .type init_private_timer,function + // 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) +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_a8/gnu/example_build/MP_PrivateTimer.h b/ports/cortex_a8/gnu/example_build/MP_PrivateTimer.h new file mode 100644 index 000000000..b0ab212a3 --- /dev/null +++ b/ports/cortex_a8/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_a8/gnu/example_build/build_threadx_sample.bat b/ports/cortex_a8/gnu/example_build/build_threadx_sample.bat index d34f7bea8..ad30a7d70 100644 --- a/ports/cortex_a8/gnu/example_build/build_threadx_sample.bat +++ b/ports/cortex_a8/gnu/example_build/build_threadx_sample.bat @@ -2,7 +2,7 @@ arm-none-eabi-gcc -c -g -mcpu=cortex-a8 reset.S arm-none-eabi-gcc -c -g -mcpu=cortex-a8 crt0.S arm-none-eabi-gcc -c -g -mcpu=cortex-a8 tx_initialize_low_level.S arm-none-eabi-gcc -c -g -mcpu=cortex-a8 MP_GIC.s +arm-none-eabi-gcc -c -g -mcpu=cortex-a8 MP_PrivateTimer.s arm-none-eabi-gcc -c -g -mcpu=cortex-a8 V7.s arm-none-eabi-gcc -c -g -mcpu=cortex-a8 -I../../../../common/inc -I../inc sample_threadx.c -arm-none-eabi-gcc -g -nostartfiles -mcpu=cortex-a8 -T sample_threadx.ld --specs=nosys.specs -o sample_threadx.out -Wl,-Map=sample_threadx.map MP_GIC.o V7.o crt0.o reset.o tx_initialize_low_level.o sample_threadx.o tx.a - +arm-none-eabi-gcc -g -nostartfiles -mcpu=cortex-a8 -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_a8/gnu/example_build/tx_initialize_low_level.S b/ports/cortex_a8/gnu/example_build/tx_initialize_low_level.S index 4b324e0ac..4a9488964 100644 --- a/ports/cortex_a8/gnu/example_build/tx_initialize_low_level.S +++ b/ports/cortex_a8/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,57 @@ _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) + + // [EL] Change start - don't enable interrupts here! + //CPSIE i // Clear CPSR I bit + // [EL] Change end + + // 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 + + // + // Enable receipt of SGI 0 + // ------------------------ + MOV r0, #0x0 // ID + BL enableIntID + + // Set the priority + MOV r0, #0x0 // ID + MOV r1, #0x0 // Priority + BL setIntPriority + + POP {lr} #ifdef __THUMB_INTERWORK BX lr // Return to caller #else @@ -202,16 +258,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 +277,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_a9/gnu/example_build/MP_GIC.S b/ports/cortex_a9/gnu/example_build/MP_GIC.S new file mode 100644 index 000000000..d23bca237 --- /dev/null +++ b/ports/cortex_a9/gnu/example_build/MP_GIC.S @@ -0,0 +1,515 @@ +// ------------------------------------------------------------ +// Cortex-A MPCore - Interrupt Controller functions +// +// 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. +// ------------------------------------------------------------ + + + .text + .cfi_sections .debug_frame // put stack frame info into .debug_frame instead of .eh_frame + + +// ------------------------------------------------------------ +// GIC +// ------------------------------------------------------------ + + // 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: + // disableIntID(X) <-- Disable 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) + + + .global enableGIC + // void enableGIC(void) + // Global enable of the Interrupt Distributor + .type enableGIC, "function" + .cfi_startproc +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 + .cfi_endproc + + +// ------------------------------------------------------------ + + .global disableGIC + // void disableGIC(void) + // Global disable of the Interrupt Distributor + .type disableGIC, "function" + .cfi_startproc +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 + .cfi_endproc + + +// ------------------------------------------------------------ + + .global enableIntID + // void enableIntID(uint32_t ID) + // Enables the interrupt source number ID + .type enableIntID, "function" + .cfi_startproc +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 + .cfi_endproc + + +// ------------------------------------------------------------ + + .global disableIntID + // void disableIntID(uint32_t ID) + // Disables the interrupt source number ID + .type disableIntID, "function" + .cfi_startproc +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 + .cfi_endproc + + +// ------------------------------------------------------------ + + .global setIntPriority + // void setIntPriority(uint32_t ID, uint32_t priority) + // Sets the priority of the specified ID + // r0 = ID + // r1 = priority + .type setIntPriority, "function" + .cfi_startproc +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 + 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 + .cfi_endproc + + +// ------------------------------------------------------------ + + .global getIntPriority + // uint32_t getIntPriority(void) + // Returns the priority of the specified ID + .type getIntPriority, "function" + .cfi_startproc +getIntPriority: + + // TBD + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global setIntTarget + // void setIntTarget(uint32_t ID, uint32_t target) + // Sets the target CPUs of the specified ID + .type setIntTarget, "function" + .cfi_startproc +setIntTarget: + + // Get base address of private peripheral space + MRC p15, 4, r2, c15, c0, 0 // Read periph base address + + // r0 = ID + // r1 = target + // r2 = base addr + + // Clear unused bits + AND r1, r1, #0xF + + // Find which register this ID lives in + BIC r3, r0, #0x03 // Make a copy of the ID, clearing the bottom 2 bits + // There are four IDs per reg, by clearing the bottom two bits we get an address offset + ADD r3, r3, #0x1800 // Now add the offset of the Target registers from the base of the private peripheral space + ADD r2, r2, 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 r0, r0, #0x03 // Clear all but the bottom two bits, leaves which ID in the reg it is (which byte) + MOV r0, r0, LSL #3 // Multiply by 8, this gives a bit offset + + // Read -> Modify -> Write + MOV r12, #0xFF // 8 bit field mask + MOV r12, r12, LSL r0 // Move mask into correct bit position + MOV r1, r1, LSL r0 // Also, move passed in target value into correct bit position + + LDR r3, [r2] // Read current value of the Target register + BIC r3, r3, r12 // Clear appropriate field + ORR r3, r3, r1 // Now OR in the target value + STR r3, [r2] // And store it back again + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global getIntTarget + // uint32_t getIntTarget(uint32_t ID) + // Returns the target CPUs of the specified ID + .type getIntTarget, "function" + .cfi_startproc +getIntTarget: + + // TBD + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global enableGICProcessorInterface + // void enableGICProcessorInterface(void) + // Enables the processor interface + // Must be done on each core separately + .type enableGICProcessorInterface, "function" + .cfi_startproc +enableGICProcessorInterface: + + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + LDR r1, [r0, #0x100] // Read the Processor Interface Control register (ICCICR/ICPICR) + ORR r1, r1, #0x03 // Bit 0: Enables secure interrupts, Bit 1: Enables Non-Secure interrupts + STR r1, [r0, #0x100] // Write the Processor Interface Control register (ICCICR/ICPICR) + + BX lr + .cfi_endproc + + + +// ------------------------------------------------------------ + + .global disableGICProcessorInterface + // void disableGICProcessorInterface(void) + // Disables the processor interface + // Must be done on each core separately + .type disableGICProcessorInterface, "function" + .cfi_startproc +disableGICProcessorInterface: + + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + LDR r1, [r0, #0x100] // 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, #0x100] // Write the Processor Interface Control register (ICCICR/ICPICR) + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global setPriorityMask + // void setPriorityMask(uint32_t priority) + // Sets the Priority mask register for the CPU run on + // The reset value masks ALL interrupts! + .type setPriorityMask, "function" + .cfi_startproc +setPriorityMask: + MRC p15, 4, r1, c15, c0, 0 // Read periph base address + + STR r0, [r1, #0x0104] // Write the Priority Mask register + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global setBinaryPoint + // void setBinaryPoint(uint32_t priority) + // Sets the Binary Point Register for the CPU run on + .type setBinaryPoint, "function" + .cfi_startproc +setBinaryPoint: + MRC p15, 4, r1, c15, c0, 0 // Read periph base address + + STR r0, [r1, #0x0108] // Write the Priority Mask register (ICCPMR/ICCIPMR) + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global readIntAck + // uint32_t readIntAck(void) + // Returns the value of the Interrupt Acknowledge Register + .type readIntAck, "function" + .cfi_startproc +readIntAck: + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + LDR r0, [r0, #0x010C] // Read the Interrupt Acknowledge Register + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global writeEOI + // void writeEOI(uint32_t ID) + // Writes ID to the End Of Interrupt register + .type writeEOI, "function" + .cfi_startproc +writeEOI: + MRC p15, 4, r1, c15, c0, 0 // Read periph base address + + STR r0, [r1, #0x0110] // Write ID to the End of Interrupt register + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ +// SGI +// ------------------------------------------------------------ + + .global sendSGI + // void sendSGI(uint32_t ID, uint32_t target_list, uint32_t filter_list) + // Send a software generate interrupt + .type sendSGI, "function" + .cfi_startproc +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 + .cfi_endproc + + +// ------------------------------------------------------------ +// TrustZone +// ------------------------------------------------------------ + + .global enableSecureFIQs + // void enableSecureFIQs(void) + // Enables the sending of secure interrupts as FIQs + .type enableSecureFIQs, "function" + .cfi_startproc +enableSecureFIQs: + + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + LDR r1, [r0, #0x100] // Read the Processor Interface Control register + ORR r1, r1, #0x08 // Bit 3: Controls whether secure interrupts are signalled as IRQs or FIQs + STR r1, [r0, #0x100] // Write the Processor Interface Control register + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global disableSecureFIQs + // void disableSecureFIQs(void) + // Disables the sending of secure interrupts as FIQs + .type disableSecureFIQs, "function" + .cfi_startproc +disableSecureFIQs: + + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + LDR r1, [r0, #0x100] // Read the Processor Interface Control register + BIC r1, r1, #0x08 // Bit 3: Controls whether secure interrupts are signalled as IRQs or FIQs + STR r1, [r0, #0x100] // Write the Processor Interface Control register + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global makeIntSecure + // void makeIntSecure(uint32_t ID) + // Sets the specified ID as being Secure + // r0 - ID + .type makeIntSecure, "function" + .cfi_startproc +makeIntSecure: + + MRC p15, 4, r1, c15, c0, 0 // Read periph base address + + // Each interrupt source has a secutiy 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, r0 // 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 r0, r0, #0x1F // Mask off to give offset within 32-bit block + MOV r3, #1 // Move enable value into r3 + MOV r3, r3, LSL r0 // Shift it left to position of ID + + ADD r2, r2, #0x1080 // Add the base offset of the Interrupt Configuration registers to the offset for the ID + + LDR r0, [r1, r2] // Read appropriate Interrupt Configuration + BIC r0, r0, r3 // Clear bit (0 = secure) + STR r0, [r1, r2] // Store out + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global makeIntNonSecure + // void makeIntNonSecure(uint32_t ID) + // Sets the specified ID as being non-secure + // r0 - ID + .type makeIntNonSecure, "function" + .cfi_startproc +makeIntNonSecure: + + MRC p15, 4, r1, c15, c0, 0 // Read periph base address + + // Each interrupt source has a secutiy 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, r0 // 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 r0, r0, #0x1F // Mask off to give offset within 32-bit block + MOV r3, #1 // Move enable value into r3 + MOV r3, r3, LSL r0 // Shift it left to position of ID + + ADD r2, r2, #0x1080 // Add the base offset of the Interrupt Configuration registers to the offset for the ID + + LDR r0, [r1, r2] // Read appropriate Interrupt Configuration + ORR r0, r0, r3 // Set bit (1 = secure) + STR r0, [r1, r2] // Store out + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ + + .global getIntSecurity + // uint32_t getIntSecurity(uint32_t ID, uint32_t security) + // Returns the security of the specified ID + .type getIntSecurity, "function" + .cfi_startproc +getIntSecurity: + + // TBD + + BX lr + .cfi_endproc + + +// ------------------------------------------------------------ +// End of MP_GIC.s +// ------------------------------------------------------------ diff --git a/ports/cortex_a9/gnu/example_build/MP_GIC.h b/ports/cortex_a9/gnu/example_build/MP_GIC.h new file mode 100644 index 000000000..1d0476112 --- /dev/null +++ b/ports/cortex_a9/gnu/example_build/MP_GIC.h @@ -0,0 +1,120 @@ +// ------------------------------------------------------------ +// Cortex-A 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_H +#define _CORTEXA_GIC_H + +#define SPURIOUS (255) + +// PPI IDs: +#define MPCORE_PPI_PRIVATE_TIMER (29) +#define MPCORE_PPI_PRIVATE_WD (30) +#define MPCORE_PPI_GLOBAL_TIMER (27) +#define MPCORE_PPI_LEGACY_IRQ (31) +#define MPCORE_PPI_LEGACY_FIQ (28) + +// ------------------------------------------------------------ +// GIC +// ------------------------------------------------------------ + +// 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 Core's priority mask to 0x1F (the lowest priority) +// enableGIC() <-- Enable the GIC (global) +// enableGICProcessorInterface() <-- 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); + +// 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! +// +// NOTE: Bits 2:0 of this register are SBZ, the function does perform any shifting! +void setPriorityMask(unsigned int priority); + +// Sets the Binary Point Register for the core run on +void setBinaryPoint(unsigned int priority); + +// Sets the priority of the specified ID +void setIntPriority(unsigned int ID, unsigned int priority); + +// Returns the priority of the specified ID +unsigned int getIntPriority(unsigned int ID, unsigned int priority); + +#define MPCORE_IC_TARGET_NONE (0x0) +#define MPCORE_IC_TARGET_CPU0 (0x1) +#define MPCORE_IC_TARGET_CPU1 (0x2) +#define MPCORE_IC_TARGET_CPU2 (0x4) +#define MPCORE_IC_TARGET_CPU3 (0x8) + +// Sets the target CPUs of the specified ID +// For 'target' use one of the above defines +void setIntTarget(unsigned int ID, unsigned int target); + +// Returns the target CPUs of the specified ID +unsigned int getIntTarget(unsigned int ID); + +// 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); + +// ------------------------------------------------------------ +// TrustZone +// ------------------------------------------------------------ + +// Enables the sending of secure interrupts as FIQs +void enableSecureFIQs(void); + +// Disables the sending of secure interrupts as FIQs +void disableSecureFIQs(void); + +// Sets the specified ID as secure +void makeIntSecure(unsigned int ID); + +// Set the specified ID as non-secure +void makeIntNonSecure(unsigned int ID); + +// Returns the security of the specified ID +unsigned int getIntSecurity(unsigned int ID); + +#endif + +// ------------------------------------------------------------ +// End of MP_GIC.h +// ------------------------------------------------------------ diff --git a/ports/cortex_a9/gnu/example_build/MP_PrivateTimer.S b/ports/cortex_a9/gnu/example_build/MP_PrivateTimer.S new file mode 100644 index 000000000..2077d9177 --- /dev/null +++ b/ports/cortex_a9/gnu/example_build/MP_PrivateTimer.S @@ -0,0 +1,118 @@ +// ------------------------------------------------------------ +// 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 + +// ------------------------------------------------------------ + + .global init_private_timer + .type init_private_timer,function + // 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) +init_private_timer: + + // Get base address of private perpherial space + MOV r2, r0 // Make a copy of r0 before corrupting + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + // Set the load value + STR r2, [r0, #0x600] + + // Control register bit layout + // Bit 0 - Enable + // Bit 1 - Auto-Reload // see DE681117 + // Bit 2 - IRQ Generation + + // Form control reg value + CMP r1, #0 // Check whether to enable auto-reload + MOVNE r2, #0x04 // No auto-reload + MOVEQ r2, #0x06 // With auto-reload + + // Store to control register + STR r2, [r0, #0x608] + + BX lr + +// ------------------------------------------------------------ + + // void start_private_timer(void) + // Starts the private timer + .global start_private_timer + .type start_private_timer,function +start_private_timer: + + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + LDR r1, [r0, #0x608] // Read control reg + ORR r1, r1, #0x01 // Set enable bit + STR r1, [r0, #0x608] // Write modified value back + + BX lr + +// ------------------------------------------------------------ + + // void stop_private_timer(void) + // Stops the private timer + .global stop_private_timer + .type stop_private_timer,function +stop_private_timer: + + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + LDR r1, [r0, #0x608] // Read control reg + BIC r1, r1, #0x01 // Clear enable bit + STR r1, [r0, #0x608] // Write modified value back + + 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: + + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + LDR r0, [r0, #0x604] // Read count register + + 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: + MRC p15, 4, r0, c15, c0, 0 // Read periph base address + + // Clear the interrupt by writing 0x1 to the Timer's Interrupt Status register + MOV r1, #1 + STR r1, [r0, #0x60C] + + BX lr + +// ------------------------------------------------------------ +// End of code +// ------------------------------------------------------------ + +// ------------------------------------------------------------ +// End of MP_PrivateTimer.s +// ------------------------------------------------------------ diff --git a/ports/cortex_a9/gnu/example_build/MP_PrivateTimer.h b/ports/cortex_a9/gnu/example_build/MP_PrivateTimer.h new file mode 100644 index 000000000..b0ab212a3 --- /dev/null +++ b/ports/cortex_a9/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_a9/gnu/example_build/build_threadx_sample.bat b/ports/cortex_a9/gnu/example_build/build_threadx_sample.bat index 1a5586302..4a10070f6 100644 --- a/ports/cortex_a9/gnu/example_build/build_threadx_sample.bat +++ b/ports/cortex_a9/gnu/example_build/build_threadx_sample.bat @@ -1,6 +1,8 @@ arm-none-eabi-gcc -c -g -mcpu=cortex-a9 reset.S arm-none-eabi-gcc -c -g -mcpu=cortex-a9 crt0.S arm-none-eabi-gcc -c -g -mcpu=cortex-a9 tx_initialize_low_level.S +arm-none-eabi-gcc -c -g -mcpu=cortex-a9 MP_GIC.s +arm-none-eabi-gcc -c -g -mcpu=cortex-a9 MP_PrivateTimer.s +arm-none-eabi-gcc -c -g -mcpu=cortex-a9 V7.s arm-none-eabi-gcc -c -g -mcpu=cortex-a9 -I../../../../common/inc -I../inc sample_threadx.c -arm-none-eabi-gcc -g -mcpu=cortex-a8 -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-a9 -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_a9/gnu/example_build/tx_initialize_low_level.S b/ports/cortex_a9/gnu/example_build/tx_initialize_low_level.S index 4b324e0ac..8e4a43617 100644 --- a/ports/cortex_a9/gnu/example_build/tx_initialize_low_level.S +++ b/ports/cortex_a9/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,57 @@ _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) + + // [EL] Change start - don't enable interrupts here! + //CPSIE i // Clear CPSR I bit + // [EL] Change end + + // 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 + + // + // Enable receipt of SGI 0 + // ------------------------ + MOV r0, #0x0 // ID + BL enableIntID + + // Set the priority + MOV r0, #0x0 // ID + MOV r1, #0x0 // Priority + BL setIntPriority + + POP {lr} #ifdef __THUMB_INTERWORK BX lr // Return to caller #else @@ -202,16 +258,16 @@ __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 + BL clear_private_timer_irq + 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 +275,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_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 1b39ea660..000000000 --- a/ports_arch/ARMv7-A/threadx/ports/gnu/example_build/tx_initialize_low_level.S +++ /dev/null @@ -1,363 +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 - .global __vectors - .global disableHighVecs - .global enableGIC - .global enableGICProcessorInterface - .global enableCaches -/* 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 - - 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) - - // [EL] Change start - don't enable interrupts here! - //CPSIE i // Clear CPSR I bit - // [EL] Change end - - // 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 - MCR p15, 0, r0, c14, c2, 0 // Setup timeout value (CNTP_TVAL) - MOV r0, #0x1 - MCR p15, 0, r0, c14, c2, 1 // Enable timer (CNTP_CTL) - - // - // Enable receipt of SGI 0 - // ------------------------ - MOV r0, #0x0 // ID - BL enableIntID - - // Set the priority - MOV r0, #0x0 // ID - MOV r1, #0x0 // Priority - BL setIntPriority - - POP {lr} -#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. */ - - PUSH {r4, r5} // Save some preserved registers (r5 is saved just for 8-byte alignment) - BL readIntAck - MOV r4, r0 - - CMP r0, #29 // If not Private Timer interrupt (ID 29), by pass - BNE by_pass_timer_interrupt - - MOV r0, #0xF0000 - MCR p15, 0, r0, c14, c2, 0 // Setup timeout value (CNTP_TVAL) - DSB - - /* 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 - -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 - - - /* 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 - - -