diff options
| author | Scott Larson <[email protected]> | 2021-01-08 13:31:36 -0800 |
|---|---|---|
| committer | Scott Larson <[email protected]> | 2021-01-08 13:31:36 -0800 |
| commit | f108ebdbafc16dc1725f4afbab73ac6084ee4302 (patch) | |
| tree | f1b857b03a3b7d787761523d51f53b7eb30d7b4e /ports | |
| parent | b0e9b132b59ab703f19b4588ed785c9c8e7a1072 (diff) | |
update to v6.1.3
Diffstat (limited to 'ports')
67 files changed, 14657 insertions, 170 deletions
diff --git a/ports/arc_em/metaware/src/tx_timer_interrupt.s b/ports/arc_em/metaware/src/tx_timer_interrupt.s index 67b06941..27141e01 100644 --- a/ports/arc_em/metaware/src/tx_timer_interrupt.s +++ b/ports/arc_em/metaware/src/tx_timer_interrupt.s @@ -35,7 +35,7 @@ ;/* FUNCTION RELEASE */ ;/* */ ;/* _tx_timer_interrupt ARCv2_EM/MetaWare */ -;/* 6.1 */ +;/* 6.1.3 */ ;/* AUTHOR */ ;/* */ ;/* William E. Lamie, Microsoft Corporation */ @@ -72,6 +72,10 @@ ;/* DATE NAME DESCRIPTION */ ;/* */ ;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* 12-31-2020 Scott Larson Modified comment(s), remove */ +;/* unneeded load of */ +;/* _tx_thread_preempt_disable, */ +;/* resulting in version 6.1.3 */ ;/* */ ;/**************************************************************************/ ;VOID _tx_timer_interrupt(VOID) @@ -187,7 +191,6 @@ __tx_something_expired: ; { ; ld r2, [gp, _tx_timer_expired@sda] ; Pickup timer expired flag - ld r4, [gp, _tx_thread_preempt_disable@sda] ; Pickup preempt disable breq r2, 0, __tx_timer_dont_activate ; If not set, skip expiration processing ; ; /* Process the timer expiration. */ diff --git a/ports/arc_hs/metaware/src/tx_timer_interrupt.s b/ports/arc_hs/metaware/src/tx_timer_interrupt.s index 663e9060..fdb70898 100644 --- a/ports/arc_hs/metaware/src/tx_timer_interrupt.s +++ b/ports/arc_hs/metaware/src/tx_timer_interrupt.s @@ -35,7 +35,7 @@ ;/* FUNCTION RELEASE */ ;/* */ ;/* _tx_timer_interrupt ARC_HS/MetaWare */ -;/* 6.1 */ +;/* 6.1.3 */ ;/* AUTHOR */ ;/* */ ;/* William E. Lamie, Microsoft Corporation */ @@ -72,6 +72,10 @@ ;/* DATE NAME DESCRIPTION */ ;/* */ ;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* 12-31-2020 Scott Larson Modified comment(s), remove */ +;/* unneeded load of */ +;/* _tx_thread_preempt_disable, */ +;/* resulting in version 6.1.3 */ ;/* */ ;/**************************************************************************/ ;VOID _tx_timer_interrupt(VOID) @@ -187,7 +191,6 @@ __tx_something_expired: ; { ; ld r2, [gp, _tx_timer_expired@sda] ; Pickup timer expired flag - ld r4, [gp, _tx_thread_preempt_disable@sda] ; Pickup preempt disable breq r2, 0, __tx_timer_dont_activate ; If not set, skip expiration processing ; ; /* Process the timer expiration. */ diff --git a/ports/cortex_a35/ac6/example_build/sample_threadx/.settings/language.settings.xml b/ports/cortex_a35/ac6/example_build/sample_threadx/.settings/language.settings.xml deleted file mode 100644 index 16ac1af8..00000000 --- a/ports/cortex_a35/ac6/example_build/sample_threadx/.settings/language.settings.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<project> - - <configuration id="com.arm.eclipse.build.config.v6.exe.debug.base.515451048" name="Debug"> - - <extension point="org.eclipse.cdt.core.LanguageSettingsProvider"> - - <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> - - <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> - - <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - - <provider class="com.arm.eclipse.builder.armcc.discovery.ArmCompiler6LanguageSettingsProvider" console="false" env-hash="-890320463837788586" id="com.arm.eclipse.builder.armcc.v6.langprovider" keep-relative-paths="false" name="Arm Compiler 6 Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> - - <language-scope id="com.arm.eclipse.builder.armcc.lang.c.ac6"/> - - <language-scope id="com.arm.eclipse.builder.armcc.lang.cpp.ac6"/> - - </provider> - - </extension> - - </configuration> - - <configuration id="com.arm.eclipse.build.config.v6.exe.release.base.262471578" name="Release"> - - <extension point="org.eclipse.cdt.core.LanguageSettingsProvider"> - - <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> - - <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> - - <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - - <provider class="com.arm.eclipse.builder.armcc.discovery.ArmCompiler6LanguageSettingsProvider" console="false" env-hash="-936373864897685072" id="com.arm.eclipse.builder.armcc.v6.langprovider" keep-relative-paths="false" name="Arm Compiler 6 Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> - - <language-scope id="com.arm.eclipse.builder.armcc.lang.c.ac6"/> - - <language-scope id="com.arm.eclipse.builder.armcc.lang.cpp.ac6"/> - - </provider> - - </extension> - - </configuration> - -</project> diff --git a/ports/cortex_a35/ac6/example_build/tx/.settings/language.settings.xml b/ports/cortex_a35/ac6/example_build/tx/.settings/language.settings.xml deleted file mode 100644 index 830dd5dd..00000000 --- a/ports/cortex_a35/ac6/example_build/tx/.settings/language.settings.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<project> - - <configuration id="com.arm.eclipse.build.config.v6.lib.debug.base.332565915" name="Debug"> - - <extension point="org.eclipse.cdt.core.LanguageSettingsProvider"> - - <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> - - <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> - - <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - - <provider class="com.arm.eclipse.builder.armcc.discovery.ArmCompiler6LanguageSettingsProvider" console="false" env-hash="-890320463837788586" id="com.arm.eclipse.builder.armcc.v6.langprovider" keep-relative-paths="false" name="Arm Compiler 6 Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> - - <language-scope id="com.arm.eclipse.builder.armcc.lang.c.ac6"/> - - <language-scope id="com.arm.eclipse.builder.armcc.lang.cpp.ac6"/> - - </provider> - - </extension> - - </configuration> - - <configuration id="com.arm.eclipse.build.config.v6.lib.release.base.979090268" name="Release"> - - <extension point="org.eclipse.cdt.core.LanguageSettingsProvider"> - - <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> - - <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> - - <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> - - <provider class="com.arm.eclipse.builder.armcc.discovery.ArmCompiler6LanguageSettingsProvider" console="false" env-hash="-936373864897685072" id="com.arm.eclipse.builder.armcc.v6.langprovider" keep-relative-paths="false" name="Arm Compiler 6 Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true"> - - <language-scope id="com.arm.eclipse.builder.armcc.lang.c.ac6"/> - - <language-scope id="com.arm.eclipse.builder.armcc.lang.cpp.ac6"/> - - </provider> - - </extension> - - </configuration> - -</project> diff --git a/ports/cortex_m23/gnu/example_build/build_threadx.bat b/ports/cortex_m23/gnu/example_build/build_threadx.bat new file mode 100644 index 00000000..822d45f2 --- /dev/null +++ b/ports/cortex_m23/gnu/example_build/build_threadx.bat @@ -0,0 +1,235 @@ +del tx.a +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_initialize_low_level.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_thread_context_restore.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_thread_context_save.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_thread_interrupt_control.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_thread_interrupt_disable.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_thread_interrupt_restore.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_thread_schedule.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_thread_secure_stack_allocate.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_thread_secure_stack_free.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_thread_stack_build.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_thread_system_return.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE ../src/tx_timer_interrupt.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../src/txe_thread_secure_stack_allocate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../src/txe_thread_secure_stack_free.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../src/tx_thread_stack_error_handler.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../src/tx_thread_stack_error_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_block_allocate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_block_pool_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_block_pool_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_block_pool_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_block_pool_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_block_pool_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_block_pool_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_block_pool_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_block_pool_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_block_release.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_allocate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_pool_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_pool_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_pool_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_pool_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_pool_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_pool_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_pool_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_pool_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_pool_search.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_byte_release.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_event_flags_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_event_flags_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_event_flags_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_event_flags_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_event_flags_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_event_flags_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_event_flags_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_event_flags_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_event_flags_set.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_event_flags_set_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_initialize_high_level.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_initialize_kernel_enter.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_initialize_kernel_setup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_priority_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_mutex_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_flush.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_front_send.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_receive.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_send.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_queue_send_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_ceiling_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_semaphore_put_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_entry_exit_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_identify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_preemption_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_priority_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_relinquish.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_reset.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_resume.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_shell_entry.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_sleep.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_stack_analyze.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_suspend.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_system_preempt_check.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_system_resume.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_system_suspend.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_terminate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_time_slice.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_time_slice_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_timeout.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_thread_wait_abort.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_time_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_time_set.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_activate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_deactivate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_expiration_process.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_system_activate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_system_deactivate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_timer_thread_entry.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_enable.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_disable.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_interrupt_control.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_isr_enter_insert.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_isr_exit_insert.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_object_register.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_object_unregister.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_user_event_insert.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_buffer_full_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_event_filter.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/tx_trace_event_unfilter.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_block_allocate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_block_pool_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_block_pool_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_block_pool_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_block_pool_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_block_release.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_byte_allocate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_byte_pool_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_byte_pool_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_byte_pool_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_byte_pool_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_byte_release.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_event_flags_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_event_flags_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_event_flags_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_event_flags_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_event_flags_set.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_event_flags_set_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_mutex_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_mutex_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_mutex_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_mutex_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_mutex_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_mutex_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_queue_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_queue_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_queue_flush.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_queue_front_send.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_queue_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_queue_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_queue_receive.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_queue_send.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_queue_send_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_semaphore_ceiling_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_semaphore_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_semaphore_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_semaphore_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_semaphore_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_semaphore_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_semaphore_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_semaphore_put_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_entry_exit_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_preemption_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_priority_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_relinquish.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_reset.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_resume.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_suspend.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_terminate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_time_slice_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_thread_wait_abort.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_timer_activate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_timer_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_timer_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_timer_deactivate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_timer_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m23 -DTX_SINGLE_MODE_NON_SECURE -I../../../../common/inc -I../inc ../../../../common/src/txe_timer_info_get.c +arm-none-eabi-ar -r tx.a tx_thread_secure_stack_allocate.o txe_thread_secure_stack_allocate.o tx_thread_secure_stack_free.o txe_thread_secure_stack_free.o +arm-none-eabi-ar -r tx.a tx_thread_stack_build.o tx_thread_schedule.o tx_thread_system_return.o tx_thread_context_save.o tx_thread_context_restore.o tx_timer_interrupt.o tx_thread_interrupt_control.o +arm-none-eabi-ar -r tx.a tx_thread_interrupt_disable.o tx_thread_interrupt_restore.o tx_initialize_low_level.o +arm-none-eabi-ar -r tx.a tx_block_allocate.o tx_block_pool_cleanup.o tx_block_pool_create.o tx_block_pool_delete.o tx_block_pool_info_get.o +arm-none-eabi-ar -r tx.a tx_block_pool_initialize.o tx_block_pool_performance_info_get.o tx_block_pool_performance_system_info_get.o tx_block_pool_prioritize.o +arm-none-eabi-ar -r tx.a tx_block_release.o tx_byte_allocate.o tx_byte_pool_cleanup.o tx_byte_pool_create.o tx_byte_pool_delete.o tx_byte_pool_info_get.o +arm-none-eabi-ar -r tx.a tx_byte_pool_initialize.o tx_byte_pool_performance_info_get.o tx_byte_pool_performance_system_info_get.o tx_byte_pool_prioritize.o +arm-none-eabi-ar -r tx.a tx_byte_pool_search.o tx_byte_release.o tx_event_flags_cleanup.o tx_event_flags_create.o tx_event_flags_delete.o tx_event_flags_get.o +arm-none-eabi-ar -r tx.a tx_event_flags_info_get.o tx_event_flags_initialize.o tx_event_flags_performance_info_get.o tx_event_flags_performance_system_info_get.o +arm-none-eabi-ar -r tx.a tx_event_flags_set.o tx_event_flags_set_notify.o tx_initialize_high_level.o tx_initialize_kernel_enter.o tx_initialize_kernel_setup.o +arm-none-eabi-ar -r tx.a tx_mutex_cleanup.o tx_mutex_create.o tx_mutex_delete.o tx_mutex_get.o tx_mutex_info_get.o tx_mutex_initialize.o tx_mutex_performance_info_get.o +arm-none-eabi-ar -r tx.a tx_mutex_performance_system_info_get.o tx_mutex_prioritize.o tx_mutex_priority_change.o tx_mutex_put.o tx_queue_cleanup.o tx_queue_create.o +arm-none-eabi-ar -r tx.a tx_queue_delete.o tx_queue_flush.o tx_queue_front_send.o tx_queue_info_get.o tx_queue_initialize.o tx_queue_performance_info_get.o +arm-none-eabi-ar -r tx.a tx_queue_performance_system_info_get.o tx_queue_prioritize.o tx_queue_receive.o tx_queue_send.o tx_queue_send_notify.o tx_semaphore_ceiling_put.o +arm-none-eabi-ar -r tx.a tx_semaphore_cleanup.o tx_semaphore_create.o tx_semaphore_delete.o tx_semaphore_get.o tx_semaphore_info_get.o tx_semaphore_initialize.o +arm-none-eabi-ar -r tx.a tx_semaphore_performance_info_get.o tx_semaphore_performance_system_info_get.o tx_semaphore_prioritize.o tx_semaphore_put.o tx_semaphore_put_notify.o +arm-none-eabi-ar -r tx.a tx_thread_create.o tx_thread_delete.o tx_thread_entry_exit_notify.o tx_thread_identify.o tx_thread_info_get.o tx_thread_initialize.o +arm-none-eabi-ar -r tx.a tx_thread_performance_info_get.o tx_thread_performance_system_info_get.o tx_thread_preemption_change.o tx_thread_priority_change.o tx_thread_relinquish.o +arm-none-eabi-ar -r tx.a tx_thread_reset.o tx_thread_resume.o tx_thread_shell_entry.o tx_thread_sleep.o tx_thread_stack_analyze.o tx_thread_stack_error_handler.o +arm-none-eabi-ar -r tx.a tx_thread_stack_error_notify.o tx_thread_suspend.o tx_thread_system_preempt_check.o tx_thread_system_resume.o tx_thread_system_suspend.o +arm-none-eabi-ar -r tx.a tx_thread_terminate.o tx_thread_time_slice.o tx_thread_time_slice_change.o tx_thread_timeout.o tx_thread_wait_abort.o tx_time_get.o +arm-none-eabi-ar -r tx.a tx_time_set.o tx_timer_activate.o tx_timer_change.o tx_timer_create.o tx_timer_deactivate.o tx_timer_delete.o tx_timer_expiration_process.o +arm-none-eabi-ar -r tx.a tx_timer_info_get.o tx_timer_initialize.o tx_timer_performance_info_get.o tx_timer_performance_system_info_get.o tx_timer_system_activate.o +arm-none-eabi-ar -r tx.a tx_timer_system_deactivate.o tx_timer_thread_entry.o tx_trace_enable.o tx_trace_disable.o tx_trace_initialize.o tx_trace_interrupt_control.o +arm-none-eabi-ar -r tx.a tx_trace_isr_enter_insert.o tx_trace_isr_exit_insert.o tx_trace_object_register.o tx_trace_object_unregister.o tx_trace_user_event_insert.o +arm-none-eabi-ar -r tx.a tx_trace_buffer_full_notify.o tx_trace_event_filter.o tx_trace_event_unfilter.o +arm-none-eabi-ar -r tx.a txe_block_allocate.o txe_block_pool_create.o txe_block_pool_delete.o txe_block_pool_info_get.o txe_block_pool_prioritize.o txe_block_release.o +arm-none-eabi-ar -r tx.a txe_byte_allocate.o txe_byte_pool_create.o txe_byte_pool_delete.o txe_byte_pool_info_get.o txe_byte_pool_prioritize.o txe_byte_release.o +arm-none-eabi-ar -r tx.a txe_event_flags_create.o txe_event_flags_delete.o txe_event_flags_get.o txe_event_flags_info_get.o txe_event_flags_set.o +arm-none-eabi-ar -r tx.a txe_event_flags_set_notify.o txe_mutex_create.o txe_mutex_delete.o txe_mutex_get.o txe_mutex_info_get.o txe_mutex_prioritize.o +arm-none-eabi-ar -r tx.a txe_mutex_put.o txe_queue_create.o txe_queue_delete.o txe_queue_flush.o txe_queue_front_send.o txe_queue_info_get.o txe_queue_prioritize.o +arm-none-eabi-ar -r tx.a txe_queue_receive.o txe_queue_send.o txe_queue_send_notify.o txe_semaphore_ceiling_put.o txe_semaphore_create.o txe_semaphore_delete.o +arm-none-eabi-ar -r tx.a txe_semaphore_get.o txe_semaphore_info_get.o txe_semaphore_prioritize.o txe_semaphore_put.o txe_semaphore_put_notify.o txe_thread_create.o +arm-none-eabi-ar -r tx.a txe_thread_delete.o txe_thread_entry_exit_notify.o txe_thread_info_get.o txe_thread_preemption_change.o txe_thread_priority_change.o +arm-none-eabi-ar -r tx.a txe_thread_relinquish.o txe_thread_reset.o txe_thread_resume.o txe_thread_suspend.o txe_thread_terminate.o txe_thread_time_slice_change.o +arm-none-eabi-ar -r tx.a txe_thread_wait_abort.o txe_timer_activate.o txe_timer_change.o txe_timer_create.o txe_timer_deactivate.o txe_timer_delete.o txe_timer_info_get.o diff --git a/ports/cortex_m23/gnu/inc/tx_port.h b/ports/cortex_m23/gnu/inc/tx_port.h index 69acde04..bb9c05a9 100644 --- a/ports/cortex_m23/gnu/inc/tx_port.h +++ b/ports/cortex_m23/gnu/inc/tx_port.h @@ -26,7 +26,7 @@ /* PORT SPECIFIC C INFORMATION RELEASE */ /* */ /* tx_port.h Cortex-M23/GNU */ -/* 6.1 */ +/* 6.1.3 */ /* */ /* AUTHOR */ /* */ @@ -48,6 +48,10 @@ /* DATE NAME DESCRIPTION */ /* */ /* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 12-31-2020 Scott Larson Modified comment(s), */ +/* remove unneeded headers, */ +/* use builtins, */ +/* resulting in version 6.1.3 */ /* */ /**************************************************************************/ @@ -67,8 +71,6 @@ #include <stdlib.h> #include <string.h> -#include <arm_compat.h> -#include "ARMCM23_TZ.h" /* For intrinsic functions. */ /* Define ThreadX basic types for this port. */ @@ -275,8 +277,6 @@ ULONG _tx_misra_time_stamp_get(VOID); #ifndef TX_MISRA_ENABLE -//register unsigned int _ipsr __asm ("MRS %[result], ipsr" : [result] "=r" (_ipsr) : ); -inline static unsigned int _get_ipsr(void); inline static unsigned int _get_ipsr(void) { unsigned int _ipsr; @@ -352,7 +352,7 @@ extern void _tx_thread_secure_stack_initialize(void); #ifndef TX_DISABLE_INLINE -#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __clz(__rbit((m))); +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __builtin_ctz(m); #endif @@ -364,41 +364,73 @@ extern void _tx_thread_secure_stack_initialize(void); is used to define a local function save area for the disable and restore macros. */ -#ifdef TX_DISABLE_INLINE +#ifndef TX_DISABLE_INLINE -UINT _tx_thread_interrupt_disable(VOID); -VOID _tx_thread_interrupt_restore(UINT previous_posture); +/* Define GNU specific macros, with in-line assembly for performance. */ -#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save; +__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void) +{ -#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable(); +unsigned int primask_value; -#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save); + __asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) ); + __asm__ volatile (" CPSID i" : : : "memory" ); + return(primask_value); +} -#else +__attribute__( ( always_inline ) ) static inline void __restore_interrupts(unsigned int primask_value) +{ -#define TX_INTERRUPT_SAVE_AREA unsigned int was_masked; -#define TX_DISABLE was_masked = __disable_irq(); -#define TX_RESTORE if (was_masked == 0) __enable_irq(); + __asm__ volatile (" MSR PRIMASK,%0": : "r" (primask_value): "memory" ); +} -#define _tx_thread_system_return _tx_thread_system_return_inline +__attribute__( ( always_inline ) ) static inline unsigned int __get_primask_value(void) +{ + +unsigned int primask_value; + __asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) ); + return(primask_value); +} -static void _tx_thread_system_return_inline(void) +__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void) { -unsigned int was_masked; + __asm__ volatile (" CPSIE i": : : "memory" ); +} + + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; - /* Set PendSV to invoke ThreadX scheduler. */ *((ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); if (_get_ipsr() == 0) { - was_masked = __disable_irq(); - __enable_irq(); - if (was_masked != 0) - __disable_irq(); + interrupt_save = __get_primask_value(); + __enable_interrupts(); + __restore_interrupts(interrupt_save); } } + + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupts(interrupt_save); + + +/* Redefine _tx_thread_system_return for improved performance. */ + +#define _tx_thread_system_return _tx_thread_system_return_inline + + +#else + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE); +#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save); #endif @@ -406,7 +438,7 @@ unsigned int was_masked; #ifdef TX_THREAD_INIT CHAR _tx_version_id[] = - "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX Cortex-M23/GNU Version 6.1 *"; + "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX Cortex-M23/GNU Version 6.1.3 *"; #else #ifdef TX_MISRA_ENABLE extern CHAR _tx_version_id[100]; diff --git a/ports/cortex_m23/gnu/readme_threadx.txt b/ports/cortex_m23/gnu/readme_threadx.txt index fa581684..e5dacfec 100644 --- a/ports/cortex_m23/gnu/readme_threadx.txt +++ b/ports/cortex_m23/gnu/readme_threadx.txt @@ -5,12 +5,12 @@ 1. Building the ThreadX run-time Library - +An example .bat file is in the example_build directory. 2. Demonstration System - +No demonstration example is provided. 3. System Initialization @@ -127,6 +127,18 @@ For generic code revision information, please refer to the readme_threadx_generi file, which is included in your distribution. The following details the revision information associated with this specific port of ThreadX: +12-31-2020 The following files were + changed/added for port specific version 6.1.3: + + + tx_port.h Remove unneeded include files, + use builtin functions, + modified comments. + + tx_thread_secure_stack.c Remove unneeded include file, + use inline get/set functions, + modified comments. + 09-30-2020 Initial ThreadX 6.1 version for Cortex-M23 using GNU tools. diff --git a/ports/cortex_m23/gnu/src/tx_thread_secure_stack.c b/ports/cortex_m23/gnu/src/tx_thread_secure_stack.c index 9ca7ccff..0e8cbde0 100644 --- a/ports/cortex_m23/gnu/src/tx_thread_secure_stack.c +++ b/ports/cortex_m23/gnu/src/tx_thread_secure_stack.c @@ -29,7 +29,6 @@ #define TX_SOURCE_CODE -#include "ARMCM23_TZ.h" /* For intrinsic functions. */ #include "tx_secure_interface.h" /* Interface for NS code. */ /* Minimum size of secure stack. */ @@ -63,7 +62,7 @@ typedef struct TX_THREAD_SECURE_STACK_INFO_STRUCT /* FUNCTION RELEASE */ /* */ /* _tx_thread_secure_stack_initialize Cortex-M23/GNU */ -/* 6.1.1 */ +/* 6.1.3 */ /* AUTHOR */ /* */ /* Scott Larson, Microsoft Corporation */ @@ -82,10 +81,7 @@ typedef struct TX_THREAD_SECURE_STACK_INFO_STRUCT /* */ /* CALLS */ /* */ -/* __get_CONTROL Intrinsic to get CONTROL */ -/* __set_CONTROL Intrinsic to set CONTROL */ -/* __set_PSPLIM Intrinsic to set PSP limit */ -/* __set_PSP Intrinsic to set PSP */ +/* None */ /* */ /* CALLED BY */ /* */ @@ -98,19 +94,25 @@ typedef struct TX_THREAD_SECURE_STACK_INFO_STRUCT /* 09-30-2020 Scott Larson Initial Version 6.1 */ /* 10-16-2020 Scott Larson Modified comment(s), */ /* resulting in version 6.1.1 */ +/* 12-31-2020 Scott Larson Modified comment(s), and */ +/* fixed M23 GCC build, */ +/* resulting in version 6.1.3 */ /* */ /**************************************************************************/ __attribute__((cmse_nonsecure_entry)) void _tx_thread_secure_stack_initialize(void) { + ULONG control; /* Set secure mode to use PSP. */ - __set_CONTROL(__get_CONTROL() | 2); + asm volatile("MRS %0, CONTROL" : "=r" (control)); /* Get CONTROL register. */ + control |= 2; /* Use PSP. */ + asm volatile("MSR CONTROL, %0" :: "r" (control)); /* Set CONTROL register. */ /* Set process stack pointer and stack limit to 0 to throw exception when a thread without a secure stack calls a secure function that tries to use secure stack. */ - __set_PSPLIM(0); - __set_PSP(0); + asm volatile("MSR PSPLIM, %0" :: "r" (0)); + asm volatile("MSR PSP, %0" :: "r" (0)); return; } @@ -122,7 +124,7 @@ void _tx_thread_secure_stack_initialize(void) /* FUNCTION RELEASE */ /* */ /* _tx_thread_secure_mode_stack_allocate Cortex-M23/GNU */ -/* 6.1.1 */ +/* 6.1.3 */ /* AUTHOR */ /* */ /* Scott Larson, Microsoft Corporation */ @@ -145,13 +147,9 @@ void _tx_thread_secure_stack_initialize(void) /* */ /* CALLS */ /* */ -/* __get_IPSR Intrinsic to get IPSR */ /* calloc Compiler's calloc function */ /* malloc Compiler's malloc function */ /* free Compiler's free() function */ -/* __set_PSPLIM Intrinsic to set PSP limit */ -/* __set_PSP Intrinsic to set PSP */ -/* __TZ_get_PSPLIM_NS Intrinsic to get NS PSP */ /* */ /* CALLED BY */ /* */ @@ -165,6 +163,10 @@ void _tx_thread_secure_stack_initialize(void) /* 10-16-2020 Scott Larson Modified comment(s), */ /* added stack sealing, */ /* resulting in version 6.1.1 */ +/* 12-31-2020 Scott Larson Modified comment(s), and */ +/* fixed M23 GCC build, */ +/* resulting in version 6.1.3 */ + /* */ /**************************************************************************/ __attribute__((cmse_nonsecure_entry)) @@ -173,12 +175,14 @@ UINT _tx_thread_secure_mode_stack_allocate(TX_THREAD *thread_ptr, ULONG stack UINT status; TX_THREAD_SECURE_STACK_INFO *info_ptr; UCHAR *stack_mem; -ULONG sp; +ULONG ipsr; +ULONG psplim_ns; status = TX_SUCCESS; /* Make sure function is called from interrupt (threads should not call). */ - if (__get_IPSR() == 0) + asm volatile("MRS %0, IPSR" : "=r" (ipsr)); /* Get IPSR register. */ + if (ipsr == 0) { status = TX_CALLER_ERROR; } @@ -217,14 +221,13 @@ ULONG sp; /* Save info pointer in thread. */ thread_ptr -> tx_thread_secure_stack_context = info_ptr; - /* Check if this thread is running by looking at PSP_NS and seeing if it is within - the stack_start and stack_end range. */ - sp = __TZ_get_PSP_NS(); - if(sp > ((ULONG) thread_ptr -> tx_thread_stack_start) && sp < ((ULONG) thread_ptr -> tx_thread_stack_end)) + /* Check if this thread is running by looking at its stack start and PSPLIM_NS */ + asm volatile("MRS %0, PSPLIM_NS" : "=r" (psplim_ns)); /* Get PSPLIM_NS register. */ + if(((ULONG) thread_ptr -> tx_thread_stack_start & 0xFFFFFFF8) == psplim_ns) { /* If this thread is running, set Secure PSP and PSPLIM. */ - __set_PSPLIM((ULONG)(info_ptr -> tx_thread_secure_stack_limit)); - __set_PSP((ULONG)(info_ptr -> tx_thread_secure_stack_ptr)); + asm volatile("MSR PSPLIM, %0" :: "r" ((ULONG)(info_ptr -> tx_thread_secure_stack_limit))); + asm volatile("MSR PSP, %0" :: "r" ((ULONG)(info_ptr -> tx_thread_secure_stack_ptr))); } } @@ -252,7 +255,7 @@ ULONG sp; /* FUNCTION RELEASE */ /* */ /* _tx_thread_secure_mode_stack_free Cortex-M23/GNU */ -/* 6.1.1 */ +/* 6.1.3 */ /* AUTHOR */ /* */ /* Scott Larson, Microsoft Corporation */ @@ -273,7 +276,6 @@ ULONG sp; /* */ /* CALLS */ /* */ -/* __get_IPSR Intrinsic to get IPSR */ /* free Compiler's free() function */ /* */ /* CALLED BY */ @@ -287,6 +289,9 @@ ULONG sp; /* 09-30-2020 Scott Larson Initial Version 6.1 */ /* 10-16-2020 Scott Larson Modified comment(s), */ /* resulting in version 6.1.1 */ +/* 12-31-2020 Scott Larson Modified comment(s), and */ +/* fixed M23 GCC build, */ +/* resulting in version 6.1.3 */ /* */ /**************************************************************************/ __attribute__((cmse_nonsecure_entry)) @@ -294,14 +299,16 @@ UINT _tx_thread_secure_mode_stack_free(TX_THREAD *thread_ptr) { UINT status; TX_THREAD_SECURE_STACK_INFO *info_ptr; - +ULONG ipsr; + status = TX_SUCCESS; /* Pickup stack info from thread. */ info_ptr = thread_ptr -> tx_thread_secure_stack_context; /* Make sure function is called from interrupt (threads should not call). */ - if (__get_IPSR() == 0) + asm volatile("MRS %0, IPSR" : "=r" (ipsr)); /* Get IPSR register. */ + if (ipsr == 0) { status = TX_CALLER_ERROR; } @@ -335,7 +342,7 @@ TX_THREAD_SECURE_STACK_INFO *info_ptr; /* FUNCTION RELEASE */ /* */ /* _tx_thread_secure_stack_context_save Cortex-M23/GNU */ -/* 6.1.1 */ +/* 6.1.3 */ /* AUTHOR */ /* */ /* Scott Larson, Microsoft Corporation */ @@ -354,10 +361,7 @@ TX_THREAD_SECURE_STACK_INFO *info_ptr; /* */ /* CALLS */ /* */ -/* __get_IPSR Intrinsic to get IPSR */ -/* __get_PSP Intrinsic to get PSP */ -/* __set_PSPLIM Intrinsic to set PSP limit */ -/* __set_PSP Intrinsic to set PSP */ +/* None */ /* */ /* CALLED BY */ /* */ @@ -370,6 +374,9 @@ TX_THREAD_SECURE_STACK_INFO *info_ptr; /* 09-30-2020 Scott Larson Initial Version 6.1 */ /* 10-16-2020 Scott Larson Modified comment(s), */ /* resulting in version 6.1.1 */ +/* 12-31-2020 Scott Larson Modified comment(s), and */ +/* fixed M23 GCC build, */ +/* resulting in version 6.1.3 */ /* */ /**************************************************************************/ __attribute__((cmse_nonsecure_entry)) @@ -377,9 +384,11 @@ void _tx_thread_secure_stack_context_save(TX_THREAD *thread_ptr) { TX_THREAD_SECURE_STACK_INFO *info_ptr; ULONG sp; - +ULONG ipsr; + /* This function should be called from scheduler only. */ - if (__get_IPSR() == 0) + asm volatile("MRS %0, IPSR" : "=r" (ipsr)); /* Get IPSR register. */ + if (ipsr == 0) { return; } @@ -394,7 +403,7 @@ ULONG sp; } /* Check that stack pointer is in range */ - sp = __get_PSP(); + asm volatile("MRS %0, PSP" : "=r" (sp)); /* Get PSP register. */ if ((sp < (ULONG)info_ptr -> tx_thread_secure_stack_limit) || (sp > (ULONG)info_ptr -> tx_thread_secure_stack_start)) { @@ -406,8 +415,8 @@ ULONG sp; /* Set process stack pointer and stack limit to 0 to throw exception when a thread without a secure stack calls a secure function that tries to use secure stack. */ - __set_PSPLIM(0); - __set_PSP(0); + asm volatile("MSR PSPLIM, %0" :: "r" (0)); + asm volatile("MSR PSP, %0" :: "r" (0)); return; } @@ -419,7 +428,7 @@ ULONG sp; /* FUNCTION RELEASE */ /* */ /* _tx_thread_secure_stack_context_restore Cortex-M23/GNU */ -/* 6.1.1 */ +/* 6.1.3 */ /* AUTHOR */ /* */ /* Scott Larson, Microsoft Corporation */ @@ -438,9 +447,7 @@ ULONG sp; /* */ /* CALLS */ /* */ -/* __get_IPSR Intrinsic to get IPSR */ -/* __set_PSPLIM Intrinsic to set PSP limit */ -/* __set_PSP Intrinsic to set PSP */ +/* None */ /* */ /* CALLED BY */ /* */ @@ -453,15 +460,20 @@ ULONG sp; /* 09-30-2020 Scott Larson Initial Version 6.1 */ /* 10-16-2020 Scott Larson Modified comment(s), */ /* resulting in version 6.1.1 */ +/* 12-31-2020 Scott Larson Modified comment(s), and */ +/* fixed M23 GCC build, */ +/* resulting in version 6.1.3 */ /* */ /**************************************************************************/ __attribute__((cmse_nonsecure_entry)) void _tx_thread_secure_stack_context_restore(TX_THREAD *thread_ptr) { TX_THREAD_SECURE_STACK_INFO *info_ptr; +ULONG ipsr; /* This function should be called from scheduler only. */ - if (__get_IPSR() == 0) + asm volatile("MRS %0, IPSR" : "=r" (ipsr)); /* Get IPSR register. */ + if (ipsr == 0) { return; } @@ -476,8 +488,8 @@ TX_THREAD_SECURE_STACK_INFO *info_ptr; } /* Set stack pointer and limit. */ - __set_PSPLIM((ULONG)info_ptr -> tx_thread_secure_stack_limit); - __set_PSP ((ULONG)info_ptr -> tx_thread_secure_stack_ptr); + asm volatile("MSR PSPLIM, %0" :: "r" ((ULONG)info_ptr -> tx_thread_secure_stack_limit)); + asm volatile("MSR PSP, %0" :: "r" ((ULONG)info_ptr -> tx_thread_secure_stack_ptr)); return; } diff --git a/ports/rxv2/ccrx/inc/tx_port.h b/ports/rxv2/ccrx/inc/tx_port.h new file mode 100644 index 00000000..21931297 --- /dev/null +++ b/ports/rxv2/ccrx/inc/tx_port.h @@ -0,0 +1,281 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h RX/CCRX */ +/* 6.1.3 */ +/* */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Express Logic, Inc. */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE + + +/* Yes, include the user defines in tx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "tx_user.h" +#endif + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef short SHORT; +typedef unsigned short USHORT; + + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during + thread creation is less than this value, the thread create call will return an error. */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK 256 /* Minimum stack size for this port */ +#endif + + +/* Define the system timer thread's default stack size and priority. These are only applicable + if TX_TIMER_PROCESS_IN_ISR is not defined. */ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE ++_tx_trace_simulated_time +#endif +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + + +/* Define the port specific options for the _tx_build_options variable. This variable indicates + how the ThreadX library was built. */ + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS 0 + + +/* Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. */ + +#define TX_INLINE_INITIALIZATION + + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif + + +/* Define the TX_THREAD control block extensions for this port. The main reason + for the multiple macros is so that backward compatibility can be maintained with + existing ThreadX kernel awareness modules. */ + +#define TX_THREAD_EXTENSION_0 +#define TX_THREAD_EXTENSION_1 +#define TX_THREAD_EXTENSION_2 +#define TX_THREAD_EXTENSION_3 + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + + +/* Define ThreadX interrupt lockout and restore macros for protection on + access of critical kernel information. The restore interrupt macro must + restore the interrupt posture of the running thread prior to the value + present prior to the disable macro. In most cases, the save area macro + is used to define a local function save area for the disable and restore + macros. */ + +/* UINT _tx_thread_interrupt_control(UINT new_posture); */ + +#pragma inline_asm _tx_thread_interrupt_disable +static UINT _tx_thread_interrupt_disable(void){ + MVFC PSW,R1 ; + CLRPSW I ; +} + + +#pragma inline_asm _tx_thread_interrupt_restore +static void _tx_thread_interrupt_restore(UINT old_posture){ + MVFC PSW, R2 ; + BTST #16,r1 ; + BMC #16,r2 ; + MVTC r2,PSW ; +} + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable(); + + +#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save); + + +#define _tx_thread_system_return _tx_thread_system_return_inline + +static void _tx_thread_system_return_inline(void) +{ + UINT interrupt_save; + + interrupt_save = _tx_thread_interrupt_disable(); + + *((volatile UCHAR *)(0x872E0u)) = 1u; + + _tx_thread_interrupt_restore(interrupt_save); +} + + +#ifndef TX_THREAD_GET_SYSTEM_STATE + +#pragma inline_asm _get_psw +static UINT _get_psw(void){ + MVFC PSW,R1 ; +} + +extern volatile ULONG _tx_thread_system_state; +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | ((~_get_psw()) & (1u << 17u))) +#endif + + + +/* Define the interrupt lockout macros for each ThreadX object. */ + +#define TX_BLOCK_POOL_DISABLE TX_DISABLE +#define TX_BYTE_POOL_DISABLE TX_DISABLE +#define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLE +#define TX_MUTEX_DISABLE TX_DISABLE +#define TX_QUEUE_DISABLE TX_DISABLE +#define TX_SEMAPHORE_DISABLE TX_DISABLE + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX RX/CCRX Version 6.1.3 *"; +#else +extern CHAR _tx_version_id[]; +#endif + + +#endif + diff --git a/ports/rxv2/ccrx/readme_threadx.txt b/ports/rxv2/ccrx/readme_threadx.txt new file mode 100644 index 00000000..c496fbb3 --- /dev/null +++ b/ports/rxv2/ccrx/readme_threadx.txt @@ -0,0 +1,175 @@ + Microsoft's Azure RTOS ThreadX for Renesas RXv2 + + Using the CC-RX Tools + +1. Building the ThreadX run-time Library + +Please see the Samples repository on GitHub for the Azure RTOS demonstrations +for the RXv2. + + +2. Demonstration System + +Please see the Samples repository on GitHub for the Azure RTOS demonstrations +for the RXv2 + + +3. System Initialization + +The system entry point using Renesas tools is at the label _PowerON_Reset_PC. +Use the resetprg.c file that comes with your release. Most notable is that Threadx +applications run in supervisor mode and do not use user mode. Hence switching to +user mode has been commented out. + +The vector area is set up using either intprg.c or in the file tx_initialize_low_level.src. +The file tx_initialize_low_level.src is responsible for setting up various system data +structures, interrupt vectors, and a periodic timer. This is the ideal place add +application specific hardware initialization code. + +ThreadX utilizes CMT0 as a periodic timer interrupt source. The CMT0 interrupt is +typically setup for 10ms periodic interrupts and the interrupt priority level is set to +level 7. You may change any of the timer parameters to suit your needs. + +In addition, _tx_initialize_low_level determines the first available address for use by +the application, which is supplied as the sole input parameter to your application +definition function, tx_application_define(). The mechanism is implemented by creating the +FREEMEM section, this section should be linked last in the RAM area. tx_initialize_low_level +will pick up the starting label of this section and put it in the global variable: +_tx_initialize_unused_memory + + +4. Context Switch, Register Usage and Stack Frames + +The RXv2 port for ThreadX uses the first software interrupt, SWINT, i.e., interrupt #17, +to perform context switch. This ISR is thus reserved when using ThreadX and the SWINT +should not be manipulated in any way by the application. The port will setup the +interrupt within _tx_initialize_low_level and the compiler will automatically install +the necessary interrupt vector. As such no additional initialization is necessary by the +application. + +The following defines the saved context stack frame used by the ThreadX port. The +state of the CPU registers at the time of a context switch is saved on the running +thread's stack The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + + Offset Interrupted Stack Frame + + 0x00 1 + 0x04 ACC0 + 0x08 ACC1 + 0x0C R6 + 0x10 R7 + 0x14 R8 + 0x18 R9 + 0x1C R10 + 0x20 R11 + 0x24 R12 + 0x28 R13 + 0x2C FPSW + 0x30 R14 + 0x34 R15 + 0x38 R3 + 0x3C R4 + 0x40 R5 + 0x44 R1 + 0x48 R2 + 0x4C PC - return address + 0x50 PSW + +Note: By default ccrx does not save the state of the accumulator registers ACC0 and ACC1 +when entering an ISR. This means that if the ISR uses any of the DSP instructions the +content of those registers could be corrupted. Saving and restoring of the acummulators +can be enabled by adding the -save_acc command line option. + + +5. Improving Performance + +The distribution version of ThreadX is built without any compiler +optimizations. This makes it easy to debug because you can trace or set +breakpoints inside of ThreadX itself. Of course, this costs some +performance. To make ThreadX run faster, you can change the ThreadX Library +project to disable debug information and enable the desired optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by +compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING +defined before tx_api.h is included. + + +6. Timer Processing + +Timer processign is performed by calling __tx_timer_interrupt(). This should usually be done +from within the callback of a periodic timer with a period of 100Hz. In the sample projects +a Renesas Fit CMT periodic timer module (rx_cmt) is used as the timer source. + + +7. Interrupt Handling + +Interrupt handling is unaffected by the ThreadX port as such user interrupts can be +written according to the toolchain's documentation. It is recommended not to use interrupt +priority 15 as this is the priority of the context switch interrupt. However using interrupt +priority 15 won't cause any negative side effectd but doing so may may slightly reduce +performance. Please refer to the toolchain documentation for additional details on how to +define interupt service routines. + + +8. Execution Profiling + +The RX port adds support for the Execution Profiling Kit (EPK). The EPK consists +of the files tx_execution_profile.c and tx_execution_profile.h. See the documentation +of the EPK for generic usage details. + +To add the EPK to your RXv2 release make the following modifications: + +* Enable the following define for both the Threadx library and the application +TX_ENABLE_EXECUTION_CHANGE_NOTIFY + +* in tx_port.h, change around line 183 +change #define TX_THREAD_EXTENSION_3 +into #include "tx_execution_profile.h" + +* Setup CMT1 as a free running 16 bit timer. + +* In tx_execution_profile.h, change following around line 74: + +#ifdef TX_EXECUTION_64BIT_TIME +typedef unsigned long long EXECUTION_TIME; +#define TX_THREAD_EXTENSION_3 unsigned long long tx_thread_execution_time_total; \ + unsigned long long tx_thread_execution_time_last_start; +#define TX_EXECUTION_MAX_TIME_SOURCE 0xFFFFFFFFFFFFFFFF +#else +typedef unsigned long EXECUTION_TIME; +#define TX_THREAD_EXTENSION_3 unsigned long tx_thread_execution_time_total; \ + unsigned long tx_thread_execution_time_last_start; +#define TX_EXECUTION_MAX_TIME_SOURCE 0xFFFF +#endif + +/* Define basic constants for the execution profile kit. */ + +#define TX_EXECUTION_TIME_SOURCE (EXECUTION_TIME) *((USHORT *) 0x8800A) + +Rebuild the Threadx library and the application. +Refer to the EPK documentation how to interpret the results. + + +9. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + + +12-31-2020 Initial ThreadX release for the RXv2 using CC-RXX tools, version 6.1.3 + + +Copyright(c) 1996-2020 Microsoft Corporation + + +https://azure.com/rtos + + + +www.expresslogic.com
\ No newline at end of file diff --git a/ports/rxv2/ccrx/src/tx_initialize_low_level.src b/ports/rxv2/ccrx/src/tx_initialize_low_level.src new file mode 100644 index 00000000..72b297bf --- /dev/null +++ b/ports/rxv2/ccrx/src/tx_initialize_low_level.src @@ -0,0 +1,101 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; + + .GLB __tx_initialize_unused_memory + + IPR03 .EQU 87303H + IEN03 .EQU 87203H + + .SECTION P,CODE + +; +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_initialize_low_level RX/CCRX */ +;/* 6.1.3 */ +;/* 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 */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ + + .GLB __tx_initialize_low_level +__tx_initialize_low_level: +; +; /* Save the first available memory address. */ +; _tx_initialize_unused_memory = (VOID_PTR) &free_mem_start; +; + MOV.L #free_mem_start, R1 ; Pickup unused memory address + MOV.L #__tx_initialize_unused_memory,R2 + MOV.L R1,[R2] ; Save first free memory address + +; /* Set priority of SWINT to 1. */ + MOV.L #IPR03, r1 + MOV.L #1, r2 + MOV.B r2, [r1] + +; /* Enable SWINT. */ + MOV.L #IEN03,r1 + MOV.B [r1], r2 + OR #(1 << 3), r2 + MOV.B r2, [r1] + + RTS + + .SECTION FREEMEM ,DATA, ALIGN=4 +free_mem_start: + .BLKL 8 ; this section is last in the link map so we can access the end of RAM memory + + .END diff --git a/ports/rxv2/ccrx/src/tx_thread_context_restore.src b/ports/rxv2/ccrx/src/tx_thread_context_restore.src new file mode 100644 index 00000000..9601dfda --- /dev/null +++ b/ports/rxv2/ccrx/src/tx_thread_context_restore.src @@ -0,0 +1,207 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; +; + .GLB __tx_thread_system_state + .GLB __tx_thread_current_ptr + .GLB __tx_thread_system_stack_ptr + .GLB __tx_thread_execute_ptr + .GLB __tx_timer_time_slice + .GLB __tx_thread_schedule + .GLB __tx_thread_preempt_disable +; + .SECTION P,CODE +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_context_restore RX/CCRX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function restores the interrupt context if it is processing a */ +;/* nested interrupt. If not, it returns to the interrupt thread if no */ +;/* preemption is necessary. Otherwise, if preemption is necessary or */ +;/* if no thread was running, the function returns to the scheduler. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_schedule Thread scheduling routine */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ISRs Interrupt Service Routines */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_context_restore(VOID) +;{ + .GLB __tx_thread_context_restore +__tx_thread_context_restore: +; +; /* Lockout interrupts. */ + + CLRPSW I ; disable interrupts + +; /* Determine if interrupts are nested. */ +; if (--_tx_thread_system_state) +; { + + MOV.L #__tx_thread_system_state, R1 + MOV.L [R1], R2 + SUB #1, R2 + MOV.L R2,[R1] + BEQ __tx_thread_not_nested_restore + +; +; /* Interrupts are nested. */ +; +; /* Recover the saved registers from the interrupt stack +; and return to the point of interrupt. */ +; +__tx_thread_nested_restore: + POPC FPSW ; restore FPU status + POPM R14-R15 ; restore R14-R15 + POPM R3-R5 ; restore R3-R5 + POPM R1-R2 ; restore R1-R2 + RTE ; return to point of interrupt, restore PSW including IPL +; } + +__tx_thread_not_nested_restore: +; +; /* Determine if a thread was interrupted and no preemption is required. */ +; else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr) +; || (_tx_thread_preempt_disable)) +; { + + MOV.L #__tx_thread_current_ptr, R1 ; Pickup current thread ptr address + MOV.L [R1], R2 + CMP #0, R2 + BEQ __tx_thread_idle_system_restore + + MOV.L #__tx_thread_preempt_disable, R3 ; pick up preempt disable flag + MOV.L [R3], R3 + CMP #0, R3 + BNE __tx_thread_no_preempt_restore ; if pre-empt disable flag set, we simply return to the original point of interrupt regardless + + MOV.L #__tx_thread_execute_ptr, R3 ; (_tx_thread_current_ptr != _tx_thread_execute_ptr) + CMP [R3], R2 + BNE __tx_thread_preempt_restore ; jump to pre-empt restoring +; +__tx_thread_no_preempt_restore: + SETPSW U ; user stack + POPC FPSW ; restore FPU status + POPM R14-R15 ; restore R14-R15 + POPM R3-R5 ; restore R3-R5 + POPM R1-R2 ; restore R1-R2 + RTE ; return to point of interrupt, restore PSW including IPL + +; } +; else +; { + +__tx_thread_preempt_restore: + +; /* Save the remaining time-slice and disable it. */ +; if (_tx_timer_time_slice) +; { + + MOV.L #__tx_timer_time_slice, R3 ; Pickup time-slice address + MOV.L [R3],R4 ; Pickup actual time-slice + CMP #0, R4 + BEQ __tx_thread_dont_save_ts ; no time slice to save +; +; _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; +; _tx_timer_time_slice = 0; +; + MOV.L R4,24[R2] ; Save thread's time slice + MOV.L #0,R4 ; Clear value + MOV.L R4,[R3] ; Disable global time slice flag +; } +__tx_thread_dont_save_ts: +; +; /* Now store the remaining registers! */ + + SETPSW U ; user stack + PUSHM R6-R13 + + MVFACGU #0, A1, R4 ; Save accumulators. + MVFACHI #0, A1, R5 + MVFACLO #0, A1, R6 + PUSHM R4-R6 + MVFACGU #0, A0, R4 + MVFACHI #0, A0, R5 + MVFACLO #0, A0, R6 + PUSHM R4-R6 + + MOV.L #1, R3 ; indicate interrupt stack frame + PUSH.L R3 + +; +; /* Clear the current task pointer. */ +; _tx_thread_current_ptr = TX_NULL; +; R1 -> _tx_thread_current_ptr +; R2 -> *_tx_thread_current_ptr + + MOV.L R0,8[R2] ; Save thread's stack pointer in thread control block + MOV.L #0,R2 ; Build NULL value + MOV.L R2,[R1] ; Set current thread to NULL + +; /* Return to the scheduler. */ +; _tx_thread_schedule(); + +__tx_thread_idle_system_restore: + MVTC #0, PSW ; reset interrupt priority level to 0 + BRA __tx_thread_schedule ; jump to scheduler +; } +; +;} +; + .END + diff --git a/ports/rxv2/ccrx/src/tx_thread_context_save.src b/ports/rxv2/ccrx/src/tx_thread_context_save.src new file mode 100644 index 00000000..26e94078 --- /dev/null +++ b/ports/rxv2/ccrx/src/tx_thread_context_save.src @@ -0,0 +1,171 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; + .GLB __tx_thread_system_state + .GLB __tx_thread_current_ptr + .GLB __tx_thread_system_stack_ptr + + .SECTION P,CODE +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_context_save RX/CCRX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function saves the context of an executing thread in the */ +;/* beginning of interrupt processing. The function also ensures that */ +;/* the system stack is used upon return to the calling ISR. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ISRs */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_context_save(VOID) +;{ + .GLB __tx_thread_context_save +__tx_thread_context_save: +; +; /* Upon entry to this routine, it is assumed that interrupts are locked +; out and the (interrupt) stack frame looks like the following: +; +; (lower address) SP -> [return address of this call] +; SP+4 -> Saved R1 +; SP+8 -> Saved R2 +; SP+12-> Interrupted PC +; SP+16-> Interrupted PSW +; +; /* Check for a nested interrupt condition. */ +; if (_tx_thread_system_state++) +; { +; + + MOV.L #__tx_thread_system_state, R1 ; pick up address of system state + MOV.L [R1], R2 ; pick up system state + CMP #0, R2 ; 0 -> no nesting + BEQ __tx_thread_not_nested_save +; +; /* Nested interrupt condition. */ +; + ADD #1, r2 ; _tx_thread_system_state++ + MOV.L r2, [r1] + +; +; /* Save the rest of the scratch registers on the interrupt stack and return to the +; calling ISR. */ + POP R1 ; recuperate return address from stack + PUSHM R3-R5 + PUSHM R14-R15 + PUSHC FPSW ; (top) FPSW, R14, R15, R3, R4, R5, R1, R2, PC, PSW (bottom) + JMP R1 ; return address was preserved in R1 + +; +__tx_thread_not_nested_save: +; } +; +; /* Otherwise, not nested, check to see if a thread was running. */ +; else if (_tx_thread_current_ptr) +; { +; + ADD #1, R2 ; _tx_thread_system_state++ + MOV.L R2, [R1] + + MOV.L #__tx_thread_current_ptr, R2 ; Pickup current thread pointer + MOV.L [R2], R2 + CMP #0,R2 ; Is it NULL? + BEQ __tx_thread_idle_system_save ; Yes, idle system is running - idle restore +; +; /* Move stack frame over to the current threads stack. */ +; /* complete stack frame with registers not saved yet (R3-R5, R14-R15, FPSW) */ +; + MVFC USP, R1 ; pick up user stack pointer + MOV.L 16[R0], R2 + MOV.L R2, [-R1] ; save PSW on thread stack + MOV.L 12[R0], R2 + MOV.L R2, [-R1] ; save PC on thread stack + MOV.L 8[R0], R2 + MOV.L R2, [-R1] ; save R2 on thread stack + MOV.L 4[R0], R2 + MOV.L R2, [-R1] ; save R1 on thread stack + MOV.L R5, [-R1] ; save R5 on thread stack + MOV.L R4, [-R1] ; save R4 on thread stack + MOV.L R3, [-R1] ; save R3 on thread stack + MOV.L R15, [-R1] ; save R15 on thread stack + MOV.L R14, [-R1] ; save R14 on thread stack + MVFC FPSW, R3 + MOV.L R3, [-R1] ; save FPSW on thread stack + + POP R2 ; pick up return address from interrupt stack + ADD #16, R0, R0 ; correct interrupt stack pointer back to the bottom + MVTC R1, USP ; set user/thread stack pointer + JMP R2 ; return to ISR + +; } +; else +; { +; +__tx_thread_idle_system_save: +; +; /* Interrupt occurred in the scheduling loop. */ +; + POP R1 ; pick up return address + ADD #16, R0, R0 ; correct interrupt stack pointer back to the bottom (PC), don't care about saved registers + JMP R1 ; return to caller +; +; } +;} + .END + diff --git a/ports/rxv2/ccrx/src/tx_thread_interrupt_control.src b/ports/rxv2/ccrx/src/tx_thread_interrupt_control.src new file mode 100644 index 00000000..39168c1d --- /dev/null +++ b/ports/rxv2/ccrx/src/tx_thread_interrupt_control.src @@ -0,0 +1,96 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +; +; + .SECTION P,CODE +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_interrupt_control RX/CCRX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is responsible for changing the interrupt lockout */ +;/* posture of the system. */ +;/* */ +;/* INPUT */ +;/* */ +;/* new_posture New interrupt lockout posture */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* old_posture Old interrupt lockout posture */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* Application Code */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;UINT _tx_thread_interrupt_control(UINT new_posture) +;{ + +.GLB __tx_thread_interrupt_control +__tx_thread_interrupt_control: +; +; /* Pickup current interrupt lockout posture. */ +; + + MVFC PSW, R2 ; Save PSW to R2 + MOV.L R2, R3 ; Make a copy of PSW in r3 + +; +; /* Apply the new interrupt posture. */ +; + + BTST #16, R1 ; test I bit of PSW of "new posture" + BMNE #16, R2 ; conditionally set I bit of intermediate posture + + MVTC R2, PSW ; save intermediate posture to PSW + + MOV.L R3,R1 ; Get original SR + RTS ; Return to caller +;} + .END + diff --git a/ports/rxv2/ccrx/src/tx_thread_schedule.src b/ports/rxv2/ccrx/src/tx_thread_schedule.src new file mode 100644 index 00000000..a34c12f5 --- /dev/null +++ b/ports/rxv2/ccrx/src/tx_thread_schedule.src @@ -0,0 +1,180 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; +; + .GLB __tx_thread_execute_ptr + .GLB __tx_thread_current_ptr + .GLB __tx_timer_time_slice +; + .SECTION P,CODE + +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_schedule RX/CCRX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function waits for a thread control block pointer to appear in */ +;/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +;/* in the variable, the corresponding thread is resumed. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* _tx_initialize_kernel_enter ThreadX entry function */ +;/* _tx_thread_system_return Return to system from thread */ +;/* _tx_thread_context_restore Restore thread's context */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_schedule(VOID) +;{ + .GLB __tx_thread_schedule +__tx_thread_schedule: +; +; /* Enable interrupts. */ +; + SETPSW I +; +; /* Wait for a thread to execute. */ +; do +; { + MOV.L #__tx_thread_execute_ptr, R1 ; Address of thread to executer ptr +__tx_thread_schedule_loop: + MOV.L [R1],R2 ; Pickup next thread to execute + CMP #0,R2 ; Is it NULL? + BEQ __tx_thread_schedule_loop ; Yes, idle system, keep checking +; +; } +; while(_tx_thread_execute_ptr == TX_NULL); +; +; /* Yes! We have a thread to execute. Lockout interrupts and +; transfer control to it. */ +; + CLRPSW I ; disable interrupts +; +; /* Setup the current thread pointer. */ +; _tx_thread_current_ptr = _tx_thread_execute_ptr; +; + MOV.L #__tx_thread_current_ptr, R3 + MOV.L R2,[R3] ; Setup current thread pointer +; +; /* Increment the run count for this thread. */ +; _tx_thread_current_ptr -> tx_thread_run_count++; +; + MOV.L 4[R2],R3 ; Pickup run count + ADD #1,R3 ; Increment run counter + MOV.L R3,4[R2] ; Store it back in control block +; +; /* Setup time-slice, if present. */ +; _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice; +; + MOV.L 24[R2],R3 ; Pickup thread time-slice + MOV.L #__tx_timer_time_slice,R4 ; Pickup pointer to time-slice + MOV.L R3, [R4] ; Setup time-slice +; +; /* Switch to the thread's stack. */ +; SP = _tx_thread_execute_ptr -> tx_thread_stack_ptr; + SETPSW U ; user stack mode + MOV.L 8[R2],R0 ; Pickup stack pointer +; +; /* Determine if an interrupt frame or a synchronous task suspension frame +; is present. */ +; + POP R1 ; Pickup stack type + CMP #1, R1 ; Is it an interrupt stack? + BNE __tx_thread_synch_return ; No, a synchronous return frame is present. + + POPM R1-R3 ; Restore accumulators. + MVTACLO R3, A0 + MVTACHI R2, A0 + MVTACGU R1, A0 + POPM R1-R3 + MVTACLO R3, A1 + MVTACHI R2, A1 + MVTACGU R1, A1 + + POPM R6-R13 ; Recover interrupt stack frame + POPC FPSW + POPM R14-R15 + POPM R3-R5 + POPM R1-R2 + RTE ; return to point of interrupt, this restores PC and PSW + +__tx_thread_synch_return: + POPC PSW + POPM R6-R13 ; Recover solicited stack frame + RTS +; +;} + + +.GLB __tx_thread_context_save +.GLB __tx_thread_context_restore + +; Software triggered interrupt used to perform context switches. +; The priority of this interrupt is set to the lowest priority within +; tx_initialize_low_level() and triggered by ThreadX when calling +; _tx_thread_system_return(). +.RVECTOR 27, _tx_software_interrupt_entry +.GLB _tx_software_interrupt_entry +_tx_software_interrupt_entry: + + PUSHM R1-R2 + + BSR __tx_thread_context_save + + BRA __tx_thread_context_restore + + .END diff --git a/ports/rxv2/ccrx/src/tx_thread_stack_build.src b/ports/rxv2/ccrx/src/tx_thread_stack_build.src new file mode 100644 index 00000000..38da71c9 --- /dev/null +++ b/ports/rxv2/ccrx/src/tx_thread_stack_build.src @@ -0,0 +1,155 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +; +; + .SECTION P,CODE +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_stack_build RX/CCRX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function builds a stack frame on the supplied thread's stack. */ +;/* The stack frame results in a fake interrupt return to the supplied */ +;/* function pointer. */ +;/* */ +;/* INPUT */ +;/* */ +;/* thread_ptr Pointer to thread control blk */ +;/* function_ptr Pointer to return function */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* _tx_thread_create Create thread service */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +;{ + .GLB __tx_thread_stack_build +__tx_thread_stack_build: +; +; +; /* Build an interrupt frame. The form of the fake interrupt stack +; on the Renesas RX should look like the following after it is built: +; +; Stack Top: 1 Interrupt stack frame type +; ACC0 +; ACC1 +; R6 +; R7 +; R8 +; R9 +; R10 +; R11 +; R12 +; R13 +; FPSW +; R14 +; R15 +; R3 +; R4 +; R5 +; R1 +; R2 +; PC +; PSW + +; +; Stack Bottom: (higher memory address) */ +; + MOV.L 16[R1],R3 ; Pickup end of stack area + BCLR #0, R3 ; mask for 4-byte alignment + BCLR #1, R3 +; +; /* Build the stack frame. */ +; + MOV.L #30000h, R4 + MOV.L R4, [-R3] ; initial PSW (SVC mode, U flag set) + MOV.L R2, [-R3] ; initial PC + MOV.L #0, R4 + MOV.L R4,[-R3] ; initial R2 ... + MOV.L R4,[-R3] ; initial R1 ... + MOV.L R4,[-R3] ; initial R5 ... + MOV.L R4,[-R3] ; initial R4 ... + MOV.L R4,[-R3] ; initial R3 ... + MOV.L R4,[-R3] ; initial R15 ... + MOV.L R4,[-R3] ; initial R14 ... + MVFC FPSW, r4 + MOV.L R4, [-R3] ; initial FPSW + MOV.L #0, R4 + MOV.L R4,[-R3] ; initial R13 ... + MOV.L R4,[-R3] ; initial R12 ... + MOV.L R4,[-R3] ; initial R11 ... + MOV.L R4,[-R3] ; initial R10 ... + MOV.L R4,[-R3] ; initial R9 ... + MOV.L R4,[-R3] ; initial R8 ... + MOV.L R4,[-R3] ; initial R7 ... + MOV.L R4,[-R3] ; initial R6 ... + + MOV.L R4,[-R3] ; Accumulator 1 + MOV.L R4,[-R3] + MOV.L R4,[-R3] + + MOV.L R4,[-R3] ; Accumulator 0 + MOV.L R4,[-R3] + MOV.L R4,[-R3] + + MOV.L #1, R4 + MOV.L R4,[-R3] ; indicate interrupt stack frame +; /* Setup stack pointer. */ +; thread_ptr -> tx_thread_stack_ptr = R1; + MOV.L R3, 8[R1] + ; store initial SP in thread control block + RTS + +;} + .END + diff --git a/ports/rxv2/ccrx/src/tx_thread_system_return.src b/ports/rxv2/ccrx/src/tx_thread_system_return.src new file mode 100644 index 00000000..fb70a970 --- /dev/null +++ b/ports/rxv2/ccrx/src/tx_thread_system_return.src @@ -0,0 +1,127 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; +; + .GLB __tx_thread_current_ptr + .GLB __tx_timer_time_slice + .GLB __tx_thread_schedule + + .SECTION P,CODE +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_system_return RX/CCRX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is target processor specific. It is used to transfer */ +;/* control from a thread back to the system. Only a minimal context */ +;/* is saved since the compiler assumes temp registers are going to get */ +;/* slicked by a function call anyway. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_schedule Thread scheduling loop */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ThreadX components */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_system_return(VOID) +;{ + .GLB __tx_thread_system_return +__tx_thread_system_return: +; +; /* Save call save registers on the stack. */ +; + PUSHM R6-R13 + PUSHC PSW + MOV.L #0, R1 + PUSH.L R1 ; solicited stack frame +; +; /* Lockout interrupts. */ +; + CLRPSW I ; Lockout interrupts +; +; /* Save current stack in current Thread controle block. */ +; _tx_thread_current_ptr -> tx_thread_stack_ptr = SP; + MOV.L #__tx_thread_current_ptr, R2 + MOV.L [R2], R3 + MOV.L R0, 8[R3] + + MOV.L #__tx_timer_time_slice, R4 + MOV.L [R4], R5 + +; /* Determine if the time-slice is active. */ +; if (_tx_timer_time_slice) +; { +; + CMP #0,R5 ; Is a time-slice present? + BEQ __tx_thread_dont_save_ts ; No, don't save the time-slice +; +; /* Save time-slice for the thread and clear the current time-slice. */ + ; _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; + MOV.L R5,24[R3] +; _tx_timer_time_slice = 0; +; + MOV.L R1, [R4] ; Disable the time-slice +; +; } +__tx_thread_dont_save_ts: +; +; /* Clear the current thread pointer. */ +; _tx_thread_current_ptr = TX_NULL; +; + MOV.L R1, [R2] + BRA __tx_thread_schedule +;} + .END + diff --git a/ports/rxv2/ccrx/src/tx_timer_interrupt.src b/ports/rxv2/ccrx/src/tx_timer_interrupt.src new file mode 100644 index 00000000..cf88b6c1 --- /dev/null +++ b/ports/rxv2/ccrx/src/tx_timer_interrupt.src @@ -0,0 +1,251 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Timer */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_timer.h" +;#include "tx_thread.h" +; +; +;Define Assembly language external references... +; + .GLB __tx_timer_time_slice + .GLB __tx_timer_system_clock + .GLB __tx_timer_current_ptr + .GLB __tx_timer_list_start + .GLB __tx_timer_list_end + .GLB __tx_timer_expired_time_slice + .GLB __tx_timer_expired + .GLB __tx_timer_expiration_process + .GLB __tx_thread_context_save + .GLB __tx_thread_time_slice + .GLB __tx_thread_context_restore +; + .SECTION P,CODE +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_timer_interrupt RX/CCRX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function processes the hardware timer interrupt. This */ +;/* processing includes incrementing the system clock and checking for */ +;/* time slice and/or timer expiration. If either is found, the */ +;/* interrupt context save/restore functions are called along with the */ +;/* expiration functions. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_context_save Save interrupted context */ +;/* _tx_timer_expiration_process Timer expiration processing */ +;/* _tx_thread_time_slice Time slice interrupted thread */ +;/* _tx_thread_context_restore Restore interrupted context */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* interrupt vector */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_timer_interrupt(VOID) +;{ + .GLB __tx_timer_interrupt +__tx_timer_interrupt: +; +; /* Upon entry to this routine, it is assumed that all interrupts are locked +; out and the stack looks like the following: +; SP+4 -> Interrupted PC +; SP+8-> Interrupted SR +; */ +; +; /* Increment the system clock. */ +; _tx_timer_system_clock++; +; + PUSHM R14-R15 + PUSHM R1-R5 + + MOV.L #__tx_timer_system_clock, R1 ; Pickup address of system clock + MOV.L [R1], R2 ; Pickup system clock + ADD #1, R2 ; Increment system clock + MOV.L R2,[R1] ; Store new system clock +; +; /* Test for time-slice expiration. */ +; if (_tx_timer_time_slice) +; { +; + MOV.L #__tx_timer_time_slice, R1 ; Pickup address of time slice + MOV.L [R1], R2 ; Pickup the current time slice + CMP #0, R2 ; Is a time slice active? + BEQ __tx_timer_no_time_slice ; No, skip timer slice processing +; +; /* Decrement the time_slice. */ +; _tx_timer_time_slice--; +; + SUB #1, R2 ; Decrement the time-slice + MOV.L R2, [R1] ; Store time-slice +; +; /* Check for expiration. */ +; if (__tx_timer_time_slice == 0) +; + CMP #0, R2 ; Has it expired? + BNE __tx_timer_no_time_slice ; No, time-slice has not expired +; +; /* Set the time-slice expired flag. */ +; _tx_timer_expired_time_slice = TX_TRUE; +; + MOV.L #__tx_timer_expired_time_slice, R1 ; Pickup address of expired time-slice + MOV.L #1, R2 ; Build expired value + MOV.L R2, [R1] ; Set expired time slice variable +; } +; +__tx_timer_no_time_slice: +; +; /* Test for timer expiration. */ +; if (*_tx_timer_current_ptr) +; { +; + MOV.L #__tx_timer_current_ptr, R1 ; Pickup address of current timer ptr + MOV.L [R1], R2 ; Pickup current pointer + MOV.L [R2+], R1 ; pickup timer list entry, _tx_timer_current_ptr++ + CMP #0, R1 ; Is timer pointer NULL? + BEQ __tx_timer_no_timer ; Yes, no timer has expired + +; +; /* Set expiration flag. */ +; _tx_timer_expired = TX_TRUE; +; + MOV.L #__tx_timer_expired,R2 ; Build address of expired flag + MOV.L #1, R1 ; Build expired value + MOV.L R1, [R2] + BRA __tx_timer_done ; Finished with timer processing +; +; } +; else +; { +__tx_timer_no_timer: +; +; /* No timer expired, increment the timer pointer. */ +; _tx_timer_current_ptr++; +; +; /* R2 already contains __tx_timer_current_ptr++ */ +; +; /* Check for wrap-around. */ +; if (_tx_timer_current_ptr == _tx_timer_list_end) +; + MOV.L #__tx_timer_list_end, R1 ; Pickup the timer list end ptr + MOV.L [R1], R1 ; Pickup actual timer list end + CMP R1, R2 ; Are we at list end? + BNE __tx_timer_skip_wrap ; No, don't move pointer to the + ; top of the list +; +; /* Wrap to beginning of list. */ +; _tx_timer_current_ptr = _tx_timer_list_start; +; + MOV.L #__tx_timer_list_start, R2 ; Pickup the timer list start ptr + MOV.L [R2], R2 ; Pickup the start of the list +; } +; +__tx_timer_skip_wrap: + MOV.L #__tx_timer_current_ptr,R1 + MOV.L R2, [R1] ; store in updated pointer in _tx_timer_current_ptr + +__tx_timer_done: +; +; /* See if anything has expired. */ +; if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) +; { +; + MOV.L #__tx_timer_expired_time_slice, R1 ; Pickup expired time slice addr + MOV.L [R1], R1 ; Pickup expired time slice + MOV.L #__tx_timer_expired, R2 ; Pickup expired timer flag address + MOV.L [R2], R2 ; Pickup actual flag + OR R1, R2 ; Or flags together + BEQ __tx_timer_nothing_expired ; If Z set, nothing has expired + +__tx_something_expired: +; /* Did a timer expire? */ +; if (_tx_timer_expired) +; { + MOV.L #__tx_timer_expired,R1 ; Pickup expired flag address + MOV.L [R1], R1 ; Pickup expired flag + CMP #0,R1 ; Is the expired timer flag set? + BEQ __tx_timer_dont_activate ; No, skip timer activation +; +; /* Process timer expiration. */ +; _tx_timer_expiration_process(); +; + BSR __tx_timer_expiration_process ; Call the timer expiration handling routine +; +; } +__tx_timer_dont_activate: +; +; /* Did time slice expire? */ +; if (_tx_timer_expired_time_slice) +; { +; + MOV.L #__tx_timer_expired_time_slice, R1 ; Pickup time-slice expired flag addr + MOV.L [R1], R1 ; Pickup actual flag + CMP #0,R1 ; Has time-slice expired? + BEQ __tx_timer_not_ts_expiration ; No, skip time-slice expiration +; +; /* Time slice interrupted thread. */ +; _tx_thread_time_slice(); + + BSR __tx_thread_time_slice ; Call time-slice processing +; } +; +__tx_timer_not_ts_expiration: + +__tx_timer_nothing_expired: + + POPM R1-R5 + POPM R14-R15 +; + RTS ; return to point of interrupt +; +;} + + .END + diff --git a/ports/rxv2/gnu/inc/tx_port.h b/ports/rxv2/gnu/inc/tx_port.h new file mode 100644 index 00000000..57841625 --- /dev/null +++ b/ports/rxv2/gnu/inc/tx_port.h @@ -0,0 +1,264 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h RX/GNURX */ +/* 6.1.3 */ +/* */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Express Logic, Inc. */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + +#include <string.h> +//#include <intrinsics.h> + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE + + +/* Yes, include the user defines in tx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "tx_user.h" +#endif + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef short SHORT; +typedef unsigned short USHORT; + + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during + thread creation is less than this value, the thread create call will return an error. */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK 256 /* Minimum stack size for this port */ +#endif + + +/* Define the system timer thread's default stack size and priority. These are only applicable + if TX_TIMER_PROCESS_IN_ISR is not defined. */ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + + +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE ++_tx_trace_simulated_time +#endif +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + + +/* Define the port specific options for the _tx_build_options variable. This variable indicates + how the ThreadX library was built. */ + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS 0 + + +/* Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. */ + +#define TX_INLINE_INITIALIZATION + + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif + + +/* Define the TX_THREAD control block extensions for this port. The main reason + for the multiple macros is so that backward compatibility can be maintained with + existing ThreadX kernel awareness modules. */ + +#define TX_THREAD_EXTENSION_0 +#define TX_THREAD_EXTENSION_1 +#define TX_THREAD_EXTENSION_2 +#define TX_THREAD_EXTENSION_3 + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + +/* Define ThreadX interrupt lockout and restore macros for protection on + access of critical kernel information. The restore interrupt macro must + restore the interrupt posture of the running thread prior to the value + present prior to the disable macro. In most cases, the save area macro + is used to define a local function save area for the disable and restore + macros. */ + +#ifdef TX_DISABLE_INLINE + +UINT _tx_thread_interrupt_disable(VOID); +VOID _tx_thread_interrupt_restore(UINT previous_posture); + +#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable(); + +#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save); + +#else + +#define TX_INTERRUPT_SAVE_AREA UCHAR interrupt_save; +#define TX_DISABLE {interrupt_save = ((UCHAR)__builtin_rx_mvfc(0u) && 0x8u); __builtin_rx_clrpsw(8u);}; +#define TX_RESTORE {if(interrupt_save != 0u) {__builtin_rx_setpsw(8u);}}; + +#define _tx_thread_system_return _tx_thread_system_return_inline + +static void _tx_thread_system_return_inline(void) +{ + TX_INTERRUPT_SAVE_AREA + + TX_DISABLE + + *((volatile UCHAR *)(0x872E0u)) = 1u; + + TX_RESTORE +} + +#endif + + +/* Define the interrupt lockout macros for each ThreadX object. */ + +#define TX_BLOCK_POOL_DISABLE TX_DISABLE +#define TX_BYTE_POOL_DISABLE TX_DISABLE +#define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLE +#define TX_MUTEX_DISABLE TX_DISABLE +#define TX_QUEUE_DISABLE TX_DISABLE +#define TX_SEMAPHORE_DISABLE TX_DISABLE + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX RX/GNURX Version 6.1.3 *"; +#else +extern CHAR _tx_version_id[]; +#endif + +#endif + diff --git a/ports/rxv2/gnu/readme_threadx.txt b/ports/rxv2/gnu/readme_threadx.txt new file mode 100644 index 00000000..5baf5961 --- /dev/null +++ b/ports/rxv2/gnu/readme_threadx.txt @@ -0,0 +1,168 @@ + Microsoft's Azure RTOS ThreadX for Renesas RXv2 + + Using the GNU Tools + + +1. Building the ThreadX run-time Library + +Please see the Samples repository on GitHub for the Azure RTOS demonstrations +for the RXv2. + + +2. Demonstration System + + +Please see the Samples repository on GitHub for the Azure RTOS demonstrations +for the RXv2. + + +3. System Initialization + +The system entry point using the GNU tools is at the label _PowerON_Reset. + +The vector area is setup in the file tx_initialize_low_level.S. This file is also +responsible for setting up various system data structures, interrupt vectors, and +the periodic timer interrupt. This file is also an ideal place to add additional hardware +initialization code. + +The ThreadX demonstration for the RXv2 utilizes CMT0 as a periodic timer interrupt +source. The CMT0 interrupt is typically setup for 10ms periodic interrupts and the +interrupt priority level is set to level 7. You may change any of the timer +parameters as needed. Increasing the timer interrupt frequency increases the overhead +of the timer handling code on the system. + +In addition, _tx_initialize_low_level determines the first available address for use +by the application, which is supplied as the sole input parameter to your application +definition function, tx_application_define. The first available memory is determined +by the location of the '_end' label the is defined in the linker script. +'_end' should reference the first memory AFTER all other RAM +sections in your linker control file. + + +4. Context Switch, Register Usage and Stack Frames + +The RXv2 port for ThreadX uses the first software interrupt, SWINT, i.e., interrupt #17, +to perform context switch. This ISR is thus reserved when using ThreadX and the SWINT +should not be manipulated in any way by the application. The port will setup the +interrupt within _tx_initialize_low_level and the compiler will automatically install +the necessary interrupt vector. As such no additional initialization is necessary by the +application. + +The following defines the saved context stack frame used by the ThreadX port. The +state of the CPU registers at the time of a context switch is saved on the running +thread's stack The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + + Offset Interrupted Stack Frame + + 0x00 1 + 0x04 ACC0 + 0x08 ACC1 + 0x0C R6 + 0x10 R7 + 0x14 R8 + 0x18 R9 + 0x1C R10 + 0x20 R11 + 0x24 R12 + 0x28 R13 + 0x2C FPSW + 0x30 R14 + 0x34 R15 + 0x38 R3 + 0x3C R4 + 0x40 R5 + 0x44 R1 + 0x48 R2 + 0x4C PC - return address + 0x50 PSW + +Note: By default GNURX does not save the state of the accumulator registers ACC0 and ACC1 +when entering an ISR. This means that if the ISR uses any of the DSP instructions the +content of those registers could be corrupted. Saving and restoring of the acummulators +can be enabled by adding the -msave-acc-in-interrupts command line option. + + +5. Improving Performance + +The distribution version of ThreadX is built without any compiler optimizations. This +makes it easy to debug because you can trace or set breakpoints inside of ThreadX itself. +Of course, this costs some performance. To make ThreadX run faster, you can change the +ThreadX Library project to disable debug information and enable the desired optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by compiling your +application code with the symbol TX_DISABLE_ERROR_CHECKING defined before tx_api.h +is included. + + +6. Timer Processing + +Timer processign is performed by calling __tx_timer_interrupt(). This should usually be done +from within the callback of a periodic timer with a period of 100Hz. In the sample projects +a Renesas Fit CMT periodic timer module (rx_cmt) is used as the timer source. + + +7. Interrupt Handling + +Interrupt handling is unaffected by the ThreadX port as such user interrupts can be +written according to the toolchain's documentation. It is recommended not to use interrupt +priority 15 as this is the priority of the context switch interrupt. However using interrupt +priority 15 won't cause any negative side effectd but doing so may may slightly reduce +performance. Please refer to the toolchain documentation for additional details on how to +define interupt service routines. + + +8. Execution Profiling + +The RX port adds support for the Execution Profiling Kit (EPK). The EPK consists +of the files tx_execution_profile.c and tx_execution_profile.h. See the documentation +of the EPK for generic usage details. + +To add the EPK to your RXv2 release make the following modifications: + +* Enable the following define for both the Threadx library and the application +TX_ENABLE_EXECUTION_CHANGE_NOTIFY + +* in tx_port.h, change around line 183 +change #define TX_THREAD_EXTENSION_3 +into #include "tx_execution_profile.h" + +* Setup CMT1 as a free running 16 bit timer. + +* In tx_execution_profile.h, change following around line 74: + +#ifdef TX_EXECUTION_64BIT_TIME +typedef unsigned long long EXECUTION_TIME; +#define TX_THREAD_EXTENSION_3 unsigned long long tx_thread_execution_time_total; \ + unsigned long long tx_thread_execution_time_last_start; +#define TX_EXECUTION_MAX_TIME_SOURCE 0xFFFFFFFFFFFFFFFF +#else +typedef unsigned long EXECUTION_TIME; +#define TX_THREAD_EXTENSION_3 unsigned long tx_thread_execution_time_total; \ + unsigned long tx_thread_execution_time_last_start; +#define TX_EXECUTION_MAX_TIME_SOURCE 0xFFFF +#endif + +/* Define basic constants for the execution profile kit. */ + +#define TX_EXECUTION_TIME_SOURCE (EXECUTION_TIME) *((USHORT *) 0x8800A) + +Rebuild the Threadx library and the application. +Refer to the EPK documentation how to interpret the results. + + +9. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + + +12-31-2020 Initial ThreadX release for the RXv2 using GNURX tools, version 6.1.3 + + +Copyright(c) 1996-2020 Microsoft Corporation + + +https://azure.com/rtos + diff --git a/ports/rxv2/gnu/src/tx_initialize_low_level.S b/ports/rxv2/gnu/src/tx_initialize_low_level.S new file mode 100644 index 00000000..197ae936 --- /dev/null +++ b/ports/rxv2/gnu/src/tx_initialize_low_level.S @@ -0,0 +1,93 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; + + .text + +; +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_initialize_low_level RX/GNURX */ +;/* 6.1.3 */ +;/* 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 */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ + .global __tx_initialize_low_level +__tx_initialize_low_level: + +; +; /* Save the first available memory address. */ +; _tx_initialize_unused_memory = (VOID_PTR) &free_mem_start; +; + MOV.L #_end, R1 ; Pickup unused memory address + MOV.L #__tx_initialize_unused_memory, R2 + MOV.L R1,[R2] ; Save first free memory address + +; /* Set priority of SWINT to 1. */ + MOV.L #0x87303, r1 + MOV.L #1, r2 + MOV.B r2, [r1] + +; /* Enable SWINT. */ + MOV.L #0x87203,r1 + MOV.B [r1], r2 + OR #(1 << 3), r2 + MOV.B r2, [r1] + + RTS + + + .end diff --git a/ports/rxv2/gnu/src/tx_thread_context_restore.S b/ports/rxv2/gnu/src/tx_thread_context_restore.S new file mode 100644 index 00000000..c2799838 --- /dev/null +++ b/ports/rxv2/gnu/src/tx_thread_context_restore.S @@ -0,0 +1,207 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; +; + .global __tx_thread_system_state + .global __tx_thread_current_ptr + .global __tx_thread_system_stack_ptr + .global __tx_thread_execute_ptr + .global __tx_timer_time_slice + .global __tx_thread_schedule + .global __tx_thread_preempt_disable + + .text + +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_context_restore RX/GNURX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function restores the interrupt context if it is processing a */ +;/* nested interrupt. If not, it returns to the interrupt thread if no */ +;/* preemption is necessary. Otherwise, if preemption is necessary or */ +;/* if no thread was running, the function returns to the scheduler. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_schedule Thread scheduling routine */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ISRs Interrupt Service Routines */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_context_restore(VOID) +;{ + .global __tx_thread_context_restore +__tx_thread_context_restore: +; +; /* Lockout interrupts. */ + + CLRPSW I ; disable interrupts + +; /* Determine if interrupts are nested. */ +; if (--_tx_thread_system_state) +; { + + MOV.L #__tx_thread_system_state, R1 + MOV.L [R1], R2 + SUB #1, R2 + MOV.L R2,[R1] + BEQ __tx_thread_not_nested_restore + +; +; /* Interrupts are nested. */ +; +; /* Recover the saved registers from the interrupt stack +; and return to the point of interrupt. */ +; +__tx_thread_nested_restore: + POPC FPSW ; restore FPU status + POPM R14-R15 ; restore R14-R15 + POPM R3-R5 ; restore R3-R5 + POPM R1-R2 ; restore R1-R2 + RTE ; return to point of interrupt, restore PSW including IPL +; } + +__tx_thread_not_nested_restore: +; +; /* Determine if a thread was interrupted and no preemption is required. */ +; else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr) +; || (_tx_thread_preempt_disable)) +; { + + MOV.L #__tx_thread_current_ptr, R1 ; Pickup current thread ptr address + MOV.L [R1], R2 + CMP #0, R2 + BEQ __tx_thread_idle_system_restore + + MOV.L #__tx_thread_preempt_disable, R3 ; pick up preempt disable flag + MOV.L [R3], R3 + CMP #0, R3 + BNE __tx_thread_no_preempt_restore ; if pre-empt disable flag set, we simply return to the original point of interrupt regardless + + MOV.L #__tx_thread_execute_ptr, R3 ; (_tx_thread_current_ptr != _tx_thread_execute_ptr) + CMP [R3], R2 + BNE __tx_thread_preempt_restore ; jump to pre-empt restoring +; +__tx_thread_no_preempt_restore: + SETPSW U ; user stack + POPC FPSW ; restore FPU status + POPM R14-R15 ; restore R14-R15 + POPM R3-R5 ; restore R3-R5 + POPM R1-R2 ; restore R1-R2 + RTE ; return to point of interrupt, restore PSW including IPL + +; } +; else +; { + +__tx_thread_preempt_restore: + +; /* Save the remaining time-slice and disable it. */ +; if (_tx_timer_time_slice) +; { + + MOV.L #__tx_timer_time_slice, R3 ; Pickup time-slice address + MOV.L [R3],R4 ; Pickup actual time-slice + CMP #0, R4 + BEQ __tx_thread_dont_save_ts ; no time slice to save +; +; _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; +; _tx_timer_time_slice = 0; +; + MOV.L R4,24[R2] ; Save thread's time slice + MOV.L #0,R4 ; Clear value + MOV.L R4,[R3] ; Disable global time slice flag +; } +__tx_thread_dont_save_ts: +; +; /* Now store the remaining registers! */ + + SETPSW U ; user stack + PUSHM R6-R13 + + MVFACGU #0, A1, R4 ; Save accumulators. + MVFACHI #0, A1, R5 + MVFACLO #0, A1, R6 + PUSHM R4-R6 + MVFACGU #0, A0, R4 + MVFACHI #0, A0, R5 + MVFACLO #0, A0, R6 + PUSHM R4-R6 + + MOV.L #1, R3 ; indicate interrupt stack frame + PUSH.L R3 + +; +; /* Clear the current task pointer. */ +; _tx_thread_current_ptr = TX_NULL; +; R1 -> _tx_thread_current_ptr +; R2 -> *_tx_thread_current_ptr + + MOV.L R0,8[R2] ; Save thread's stack pointer in thread control block + MOV.L #0,R2 ; Build NULL value + MOV.L R2,[R1] ; Set current thread to NULL + +; /* Return to the scheduler. */ +; _tx_thread_schedule(); + +__tx_thread_idle_system_restore: + MVTC #0, PSW ; reset interrupt priority level to 0 + BRA __tx_thread_schedule ; jump to scheduler +; } +; +;} +; + .end diff --git a/ports/rxv2/gnu/src/tx_thread_context_save.S b/ports/rxv2/gnu/src/tx_thread_context_save.S new file mode 100644 index 00000000..cae38615 --- /dev/null +++ b/ports/rxv2/gnu/src/tx_thread_context_save.S @@ -0,0 +1,171 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; + .global __tx_thread_system_state + .global __tx_thread_current_ptr + .global __tx_thread_system_stack_ptr + + .text +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_context_save RX/GNURX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function saves the context of an executing thread in the */ +;/* beginning of interrupt processing. The function also ensures that */ +;/* the system stack is used upon return to the calling ISR. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ISRs */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_context_save(VOID) +;{ + .global __tx_thread_context_save +__tx_thread_context_save: +; +; /* Upon entry to this routine, it is assumed that interrupts are locked +; out and the (interrupt) stack frame looks like the following: +; +; (lower address) SP -> [return address of this call] +; SP+4 -> Saved R1 +; SP+8 -> Saved R2 +; SP+12-> Interrupted PC +; SP+16-> Interrupted PSW +; +; /* Check for a nested interrupt condition. */ +; if (_tx_thread_system_state++) +; { +; + + MOV.L #__tx_thread_system_state, R1 ; pick up address of system state + MOV.L [R1], R2 ; pick up system state + CMP #0, R2 ; 0 -> no nesting + BEQ __tx_thread_not_nested_save +; +; /* Nested interrupt condition. */ +; + ADD #1, r2 ; _tx_thread_system_state++ + MOV.L r2, [r1] + +; +; /* Save the rest of the scratch registers on the interrupt stack and return to the +; calling ISR. */ + POP R1 ; recuperate return address from stack + PUSHM R3-R5 + PUSHM R14-R15 + PUSHC FPSW ; (top) FPSW, R14, R15, R3, R4, R5, R1, R2, PC, PSW (bottom) + JMP R1 ; return address was preserved in R1 + +; +__tx_thread_not_nested_save: +; } +; +; /* Otherwise, not nested, check to see if a thread was running. */ +; else if (_tx_thread_current_ptr) +; { +; + ADD #1, R2 ; _tx_thread_system_state++ + MOV.L R2, [R1] + + MOV.L #__tx_thread_current_ptr, R2 ; Pickup current thread pointer + MOV.L [R2], R2 + CMP #0,R2 ; Is it NULL? + BEQ __tx_thread_idle_system_save ; Yes, idle system is running - idle restore +; +; /* Move stack frame over to the current threads stack. */ +; /* complete stack frame with registers not saved yet (R3-R5, R14-R15, FPSW) */ +; + MVFC USP, R1 ; pick up user stack pointer + MOV.L 16[R0], R2 + MOV.L R2, [-R1] ; save PSW on thread stack + MOV.L 12[R0], R2 + MOV.L R2, [-R1] ; save PC on thread stack + MOV.L 8[R0], R2 + MOV.L R2, [-R1] ; save R2 on thread stack + MOV.L 4[R0], R2 + MOV.L R2, [-R1] ; save R1 on thread stack + MOV.L R5, [-R1] ; save R5 on thread stack + MOV.L R4, [-R1] ; save R4 on thread stack + MOV.L R3, [-R1] ; save R3 on thread stack + MOV.L R15, [-R1] ; save R15 on thread stack + MOV.L R14, [-R1] ; save R14 on thread stack + MVFC FPSW, R3 + MOV.L R3, [-R1] ; save FPSW on thread stack + + POP R2 ; pick up return address from interrupt stack + ADD #16, R0, R0 ; correct interrupt stack pointer back to the bottom + MVTC R1, USP ; set user/thread stack pointer + JMP R2 ; return to ISR + +; } +; else +; { +; +__tx_thread_idle_system_save: +; +; /* Interrupt occurred in the scheduling loop. */ +; + POP R1 ; pick up return address + ADD #16, R0, R0 ; correct interrupt stack pointer back to the bottom (PC), don't care about saved registers + JMP R1 ; return to caller +; +; } +;} + .end + diff --git a/ports/rxv2/gnu/src/tx_thread_interrupt_control.S b/ports/rxv2/gnu/src/tx_thread_interrupt_control.S new file mode 100644 index 00000000..096c0568 --- /dev/null +++ b/ports/rxv2/gnu/src/tx_thread_interrupt_control.S @@ -0,0 +1,96 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +; +; + .text +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_interrupt_control RX/GNURX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is responsible for changing the interrupt lockout */ +;/* posture of the system. */ +;/* */ +;/* INPUT */ +;/* */ +;/* new_posture New interrupt lockout posture */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* old_posture Old interrupt lockout posture */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* Application Code */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;UINT _tx_thread_interrupt_control(UINT new_posture) +;{ + + .global __tx_thread_interrupt_control +__tx_thread_interrupt_control: +; +; /* Pickup current interrupt lockout posture. */ +; + + MVFC PSW, R2 ; Save PSW to R2 + MOV.L R2, R3 ; Make a copy of PSW in r3 + +; +; /* Apply the new interrupt posture. */ +; + + BTST #16, R1 ; test I bit of PSW of "new posture" + BMNE #16, R2 ; conditionally set I bit of intermediate posture + + MVTC R2, PSW ; save intermediate posture to PSW + + MOV.L R3,R1 ; Get original SR + RTS ; Return to caller +;} + .end + diff --git a/ports/rxv2/gnu/src/tx_thread_schedule.S b/ports/rxv2/gnu/src/tx_thread_schedule.S new file mode 100644 index 00000000..c48840e7 --- /dev/null +++ b/ports/rxv2/gnu/src/tx_thread_schedule.S @@ -0,0 +1,180 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; +; + .global __tx_thread_execute_ptr + .global __tx_thread_current_ptr + .global __tx_timer_time_slice +; + .text + +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_schedule RX/GNURX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function waits for a thread control block pointer to appear in */ +;/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +;/* in the variable, the corresponding thread is resumed. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* _tx_initialize_kernel_enter ThreadX entry function */ +;/* _tx_thread_system_return Return to system from thread */ +;/* _tx_thread_context_restore Restore thread's context */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_schedule(VOID) +;{ + .global __tx_thread_schedule +__tx_thread_schedule: +; +; /* Enable interrupts. */ +; + SETPSW I +; +; /* Wait for a thread to execute. */ +; do +; { + MOV.L #__tx_thread_execute_ptr, R1 ; Address of thread to executer ptr +__tx_thread_schedule_loop: + MOV.L [R1],R2 ; Pickup next thread to execute + CMP #0,R2 ; Is it NULL? + BEQ __tx_thread_schedule_loop ; Yes, idle system, keep checking +; +; } +; while(_tx_thread_execute_ptr == TX_NULL); +; +; /* Yes! We have a thread to execute. Lockout interrupts and +; transfer control to it. */ +; + CLRPSW I ; disable interrupts +; +; /* Setup the current thread pointer. */ +; _tx_thread_current_ptr = _tx_thread_execute_ptr; +; + MOV.L #__tx_thread_current_ptr, R3 + MOV.L R2,[R3] ; Setup current thread pointer +; +; /* Increment the run count for this thread. */ +; _tx_thread_current_ptr -> tx_thread_run_count++; +; + MOV.L 4[R2],R3 ; Pickup run count + ADD #1,R3 ; Increment run counter + MOV.L R3,4[R2] ; Store it back in control block +; +; /* Setup time-slice, if present. */ +; _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice; +; + MOV.L 24[R2],R3 ; Pickup thread time-slice + MOV.L #__tx_timer_time_slice,R4 ; Pickup pointer to time-slice + MOV.L R3, [R4] ; Setup time-slice +; +; /* Switch to the thread's stack. */ +; SP = _tx_thread_execute_ptr -> tx_thread_stack_ptr; + SETPSW U ; user stack mode + MOV.L 8[R2],R0 ; Pickup stack pointer +; +; /* Determine if an interrupt frame or a synchronous task suspension frame +; is present. */ +; + POP R1 ; Pickup stack type + CMP #1, R1 ; Is it an interrupt stack? + BNE __tx_thread_synch_return ; No, a synchronous return frame is present. + + POPM R1-R3 ; Restore accumulators. + MVTACLO R3, A0 + MVTACHI R2, A0 + MVTACGU R1, A0 + POPM R1-R3 + MVTACLO R3, A1 + MVTACHI R2, A1 + MVTACGU R1, A1 + + POPM R6-R13 ; Recover interrupt stack frame + POPC FPSW + POPM R14-R15 + POPM R3-R5 + POPM R1-R2 + RTE ; return to point of interrupt, this restores PC and PSW + +__tx_thread_synch_return: + POPC PSW + POPM R6-R13 ; Recover solicited stack frame + RTS +; +;} + + +.global __tx_thread_context_save +.global __tx_thread_context_restore + + +; Software triggered interrupt used to perform context switches. +; The priority of this interrupt is set to the lowest priority within +; tx_initialize_low_level() and triggered by ThreadX when calling +; _tx_thread_system_return(). +.global $tableentry$27$.rvectors +$tableentry$27$.rvectors: + + PUSHM R1-R2 + + BSR __tx_thread_context_save + + BRA __tx_thread_context_restore + + .end diff --git a/ports/rxv2/gnu/src/tx_thread_stack_build.S b/ports/rxv2/gnu/src/tx_thread_stack_build.S new file mode 100644 index 00000000..752372bf --- /dev/null +++ b/ports/rxv2/gnu/src/tx_thread_stack_build.S @@ -0,0 +1,155 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +; +; + .text +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_stack_build RX/GNURX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function builds a stack frame on the supplied thread's stack. */ +;/* The stack frame results in a fake interrupt return to the supplied */ +;/* function pointer. */ +;/* */ +;/* INPUT */ +;/* */ +;/* thread_ptr Pointer to thread control blk */ +;/* function_ptr Pointer to return function */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* _tx_thread_create Create thread service */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +;{ + .global __tx_thread_stack_build +__tx_thread_stack_build: +; +; +; /* Build an interrupt frame. The form of the fake interrupt stack +; on the Renesas RX should look like the following after it is built: +; +; Stack Top: 1 Interrupt stack frame type +; ACC0 +; ACC1 +; R6 +; R7 +; R8 +; R9 +; R10 +; R11 +; R12 +; R13 +; FPSW +; R14 +; R15 +; R3 +; R4 +; R5 +; R1 +; R2 +; PC +; PSW + +; +; Stack Bottom: (higher memory address) */ +; + MOV.L 16[R1],R3 ; Pickup end of stack area + BCLR #0, R3 ; mask for 4-byte alignment + BCLR #1, R3 +; +; /* Build the stack frame. */ +; + MOV.L #30000h, R4 + MOV.L R4, [-R3] ; initial PSW (SVC mode, U flag set) + MOV.L R2, [-R3] ; initial PC + MOV.L #0, R4 + MOV.L R4,[-R3] ; initial R2 ... + MOV.L R4,[-R3] ; initial R1 ... + MOV.L R4,[-R3] ; initial R5 ... + MOV.L R4,[-R3] ; initial R4 ... + MOV.L R4,[-R3] ; initial R3 ... + MOV.L R4,[-R3] ; initial R15 ... + MOV.L R4,[-R3] ; initial R14 ... + MVFC FPSW, r4 + MOV.L R4, [-R3] ; initial FPSW + MOV.L #0, R4 + MOV.L R4,[-R3] ; initial R13 ... + MOV.L R4,[-R3] ; initial R12 ... + MOV.L R4,[-R3] ; initial R11 ... + MOV.L R4,[-R3] ; initial R10 ... + MOV.L R4,[-R3] ; initial R9 ... + MOV.L R4,[-R3] ; initial R8 ... + MOV.L R4,[-R3] ; initial R7 ... + MOV.L R4,[-R3] ; initial R6 ... + + MOV.L R4,[-R3] ; Accumulator 1 + MOV.L R4,[-R3] + MOV.L R4,[-R3] + + MOV.L R4,[-R3] ; Accumulator 0 + MOV.L R4,[-R3] + MOV.L R4,[-R3] + + MOV.L #1, R4 + MOV.L R4,[-R3] ; indicate interrupt stack frame +; /* Setup stack pointer. */ +; thread_ptr -> tx_thread_stack_ptr = R1; + MOV.L R3, 8[R1] + ; store initial SP in thread control block + RTS + +;} + .end + diff --git a/ports/rxv2/gnu/src/tx_thread_system_return.S b/ports/rxv2/gnu/src/tx_thread_system_return.S new file mode 100644 index 00000000..baa5314a --- /dev/null +++ b/ports/rxv2/gnu/src/tx_thread_system_return.S @@ -0,0 +1,127 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; +; + .global __tx_thread_current_ptr + .global __tx_timer_time_slice + .global __tx_thread_schedule + + .text +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_system_return RX/GNURX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is target processor specific. It is used to transfer */ +;/* control from a thread back to the system. Only a minimal context */ +;/* is saved since the compiler assumes temp registers are going to get */ +;/* slicked by a function call anyway. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_schedule Thread scheduling loop */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ThreadX components */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_system_return(VOID) +;{ + .GLB __tx_thread_system_return +__tx_thread_system_return: +; +; /* Save call save registers on the stack. */ +; + PUSHM R6-R13 + PUSHC PSW + MOV.L #0, R1 + PUSH.L R1 ; solicited stack frame +; +; /* Lockout interrupts. */ +; + CLRPSW I ; Lockout interrupts +; +; /* Save current stack in current Thread controle block. */ +; _tx_thread_current_ptr -> tx_thread_stack_ptr = SP; + MOV.L #__tx_thread_current_ptr, R2 + MOV.L [R2], R3 + MOV.L R0, 8[R3] + + MOV.L #__tx_timer_time_slice, R4 + MOV.L [R4], R5 + +; /* Determine if the time-slice is active. */ +; if (_tx_timer_time_slice) +; { +; + CMP #0,R5 ; Is a time-slice present? + BEQ __tx_thread_dont_save_ts ; No, don't save the time-slice +; +; /* Save time-slice for the thread and clear the current time-slice. */ + ; _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; + MOV.L R5,24[R3] +; _tx_timer_time_slice = 0; +; + MOV.L R1, [R4] ; Disable the time-slice +; +; } +__tx_thread_dont_save_ts: +; +; /* Clear the current thread pointer. */ +; _tx_thread_current_ptr = TX_NULL; +; + MOV.L R1, [R2] + BRA __tx_thread_schedule +;} + .end + diff --git a/ports/rxv2/gnu/src/tx_timer_interrupt.S b/ports/rxv2/gnu/src/tx_timer_interrupt.S new file mode 100644 index 00000000..3511e2c8 --- /dev/null +++ b/ports/rxv2/gnu/src/tx_timer_interrupt.S @@ -0,0 +1,251 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Timer */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_timer.h" +;#include "tx_thread.h" +; +; +;Define Assembly language external references... +; + .global __tx_timer_time_slice + .global __tx_timer_system_clock + .global __tx_timer_current_ptr + .global __tx_timer_list_start + .global __tx_timer_list_end + .global __tx_timer_expired_time_slice + .global __tx_timer_expired + .global __tx_timer_expiration_process + .global __tx_thread_context_save + .global __tx_thread_time_slice + .global __tx_thread_context_restore +; + .SECTION P,CODE +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_timer_interrupt RX/GNURX */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function processes the hardware timer interrupt. This */ +;/* processing includes incrementing the system clock and checking for */ +;/* time slice and/or timer expiration. If either is found, the */ +;/* interrupt context save/restore functions are called along with the */ +;/* expiration functions. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_context_save Save interrupted context */ +;/* _tx_timer_expiration_process Timer expiration processing */ +;/* _tx_thread_time_slice Time slice interrupted thread */ +;/* _tx_thread_context_restore Restore interrupted context */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* interrupt vector */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_timer_interrupt(VOID) +;{ + .global __tx_timer_interrupt +__tx_timer_interrupt: +; +; /* Upon entry to this routine, it is assumed that all interrupts are locked +; out and the stack looks like the following: +; SP+4 -> Interrupted PC +; SP+8-> Interrupted SR +; */ +; +; /* Increment the system clock. */ +; _tx_timer_system_clock++; +; + PUSHM R14-R15 + PUSHM R1-R5 + + MOV.L #__tx_timer_system_clock, R1 ; Pickup address of system clock + MOV.L [R1], R2 ; Pickup system clock + ADD #1, R2 ; Increment system clock + MOV.L R2,[R1] ; Store new system clock +; +; /* Test for time-slice expiration. */ +; if (_tx_timer_time_slice) +; { +; + MOV.L #__tx_timer_time_slice, R1 ; Pickup address of time slice + MOV.L [R1], R2 ; Pickup the current time slice + CMP #0, R2 ; Is a time slice active? + BEQ __tx_timer_no_time_slice ; No, skip timer slice processing +; +; /* Decrement the time_slice. */ +; _tx_timer_time_slice--; +; + SUB #1, R2 ; Decrement the time-slice + MOV.L R2, [R1] ; Store time-slice +; +; /* Check for expiration. */ +; if (__tx_timer_time_slice == 0) +; + CMP #0, R2 ; Has it expired? + BNE __tx_timer_no_time_slice ; No, time-slice has not expired +; +; /* Set the time-slice expired flag. */ +; _tx_timer_expired_time_slice = TX_TRUE; +; + MOV.L #__tx_timer_expired_time_slice, R1 ; Pickup address of expired time-slice + MOV.L #1, R2 ; Build expired value + MOV.L R2, [R1] ; Set expired time slice variable +; } +; +__tx_timer_no_time_slice: +; +; /* Test for timer expiration. */ +; if (*_tx_timer_current_ptr) +; { +; + MOV.L #__tx_timer_current_ptr, R1 ; Pickup address of current timer ptr + MOV.L [R1], R2 ; Pickup current pointer + MOV.L [R2+], R1 ; pickup timer list entry, _tx_timer_current_ptr++ + CMP #0, R1 ; Is timer pointer NULL? + BEQ __tx_timer_no_timer ; Yes, no timer has expired + +; +; /* Set expiration flag. */ +; _tx_timer_expired = TX_TRUE; +; + MOV.L #__tx_timer_expired,R2 ; Build address of expired flag + MOV.L #1, R1 ; Build expired value + MOV.L R1, [R2] + BRA __tx_timer_done ; Finished with timer processing +; +; } +; else +; { +__tx_timer_no_timer: +; +; /* No timer expired, increment the timer pointer. */ +; _tx_timer_current_ptr++; +; +; /* R2 already contains __tx_timer_current_ptr++ */ +; +; /* Check for wrap-around. */ +; if (_tx_timer_current_ptr == _tx_timer_list_end) +; + MOV.L #__tx_timer_list_end, R1 ; Pickup the timer list end ptr + MOV.L [R1], R1 ; Pickup actual timer list end + CMP R1, R2 ; Are we at list end? + BNE __tx_timer_skip_wrap ; No, don't move pointer to the + ; top of the list +; +; /* Wrap to beginning of list. */ +; _tx_timer_current_ptr = _tx_timer_list_start; +; + MOV.L #__tx_timer_list_start, R2 ; Pickup the timer list start ptr + MOV.L [R2], R2 ; Pickup the start of the list +; } +; +__tx_timer_skip_wrap: + MOV.L #__tx_timer_current_ptr,R1 + MOV.L R2, [R1] ; store in updated pointer in _tx_timer_current_ptr + +__tx_timer_done: +; +; /* See if anything has expired. */ +; if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) +; { +; + MOV.L #__tx_timer_expired_time_slice, R1 ; Pickup expired time slice addr + MOV.L [R1], R1 ; Pickup expired time slice + MOV.L #__tx_timer_expired, R2 ; Pickup expired timer flag address + MOV.L [R2], R2 ; Pickup actual flag + OR R1, R2 ; Or flags together + BEQ __tx_timer_nothing_expired ; If Z set, nothing has expired + +__tx_something_expired: +; /* Did a timer expire? */ +; if (_tx_timer_expired) +; { + MOV.L #__tx_timer_expired,R1 ; Pickup expired flag address + MOV.L [R1], R1 ; Pickup expired flag + CMP #0,R1 ; Is the expired timer flag set? + BEQ __tx_timer_dont_activate ; No, skip timer activation +; +; /* Process timer expiration. */ +; _tx_timer_expiration_process(); +; + BSR __tx_timer_expiration_process ; Call the timer expiration handling routine +; +; } +__tx_timer_dont_activate: +; +; /* Did time slice expire? */ +; if (_tx_timer_expired_time_slice) +; { +; + MOV.L #__tx_timer_expired_time_slice, R1 ; Pickup time-slice expired flag addr + MOV.L [R1], R1 ; Pickup actual flag + CMP #0,R1 ; Has time-slice expired? + BEQ __tx_timer_not_ts_expiration ; No, skip time-slice expiration +; +; /* Time slice interrupted thread. */ +; _tx_thread_time_slice(); + + BSR __tx_thread_time_slice ; Call time-slice processing +; } +; +__tx_timer_not_ts_expiration: + +__tx_timer_nothing_expired: + + POPM R1-R5 + POPM R14-R15 +; + RTS ; return to point of interrupt +; +;} + + .end + diff --git a/ports/rxv2/iar/inc/tx_port.h b/ports/rxv2/iar/inc/tx_port.h new file mode 100644 index 00000000..14b9728f --- /dev/null +++ b/ports/rxv2/iar/inc/tx_port.h @@ -0,0 +1,273 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h RX/IAR */ +/* 6.1.3 */ +/* */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Express Logic, Inc. */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + +#include <string.h> +#include <intrinsics.h> + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE + + +/* Yes, include the user defines in tx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "tx_user.h" +#endif + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef short SHORT; +typedef unsigned short USHORT; + + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during + thread creation is less than this value, the thread create call will return an error. */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK 256 /* Minimum stack size for this port */ +#endif + + +/* Define the system timer thread's default stack size and priority. These are only applicable + if TX_TIMER_PROCESS_IN_ISR is not defined. */ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + + +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE ++_tx_trace_simulated_time +#endif +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + + +/* Define the port specific options for the _tx_build_options variable. This variable indicates + how the ThreadX library was built. */ + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS 0 + + +/* Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. */ + +#define TX_INLINE_INITIALIZATION + + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif + + +/* Define the TX_THREAD control block extensions for this port. The main reason + for the multiple macros is so that backward compatibility can be maintained with + existing ThreadX kernel awareness modules. */ + +#define TX_THREAD_EXTENSION_0 +#define TX_THREAD_EXTENSION_1 +#define TX_THREAD_EXTENSION_2 +#define TX_THREAD_EXTENSION_3 + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + +/* Define ThreadX interrupt lockout and restore macros for protection on + access of critical kernel information. The restore interrupt macro must + restore the interrupt posture of the running thread prior to the value + present prior to the disable macro. In most cases, the save area macro + is used to define a local function save area for the disable and restore + macros. */ + +#ifdef TX_DISABLE_INLINE + +UINT _tx_thread_interrupt_disable(VOID); +VOID _tx_thread_interrupt_restore(UINT previous_posture); + +#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable(); + +#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save); + +#else + +#define TX_INTERRUPT_SAVE_AREA __istate_t interrupt_save; +#define TX_DISABLE {interrupt_save = __get_interrupt_state();__disable_interrupt();}; +#define TX_RESTORE {__set_interrupt_state(interrupt_save);}; + +#define _tx_thread_system_return _tx_thread_system_return_inline + +static void _tx_thread_system_return_inline(void) +{ + TX_INTERRUPT_SAVE_AREA + + TX_DISABLE + + *((volatile UCHAR *)(0x872E0u)) = 1u; + + TX_RESTORE +} + +#endif + + +#ifndef TX_THREAD_GET_SYSTEM_STATE + +extern volatile ULONG _tx_thread_system_state; +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | ((~__get_PSW_register()) & (1u << 17u))) +#endif + + + +/* Define the interrupt lockout macros for each ThreadX object. */ + +#define TX_BLOCK_POOL_DISABLE TX_DISABLE +#define TX_BYTE_POOL_DISABLE TX_DISABLE +#define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLE +#define TX_MUTEX_DISABLE TX_DISABLE +#define TX_QUEUE_DISABLE TX_DISABLE +#define TX_SEMAPHORE_DISABLE TX_DISABLE + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX RX/IAR Version 6.1.3 *"; +#else +extern CHAR _tx_version_id[]; +#endif + + +#endif + diff --git a/ports/rxv2/iar/readme_threadx.txt b/ports/rxv2/iar/readme_threadx.txt new file mode 100644 index 00000000..0c0afd29 --- /dev/null +++ b/ports/rxv2/iar/readme_threadx.txt @@ -0,0 +1,163 @@ + Microsoft's Azure RTOS ThreadX for Renesas RXv2 + + Using the IAR Tools + + +1. Building the ThreadX run-time Library + +Please see the Samples repository on GitHub for the Azure RTOS demonstrations +for the RXv2. + + +2. Demonstration System + +Please see the Samples repository on GitHub for the Azure RTOS demonstrations +for the RXv2. + + +3. System Initialization + +The system entry point using the IAR tools is at the label __iar_program_start. + +The vector area is setup in the file tx_initialize_low_level.s. This file is also +responsible for setting up various system data structures, interrupt vectors, and +the periodic timer interrupt. This file is also an ideal place add hardware +initialization code. + +The ThreadX demonstration for the RXv2 utilizes CMT0 as a periodic timer interrupt +source. The CMT0 interrupt is typically setup for 10ms periodic interrupts and the +interrupt priority level is set to level 7. You may change any of the timer +parameters as needed. + +In addition, _tx_initialize_low_level determines the first available address for use +by the application, which is supplied as the sole input parameter to your application +definition function, tx_application_define. The first available memory is determined +by the location of the FREEMEM section so it should be placed AFTER all other RAM +sections in your linker control file. + + +4. Context Switch, Register Usage and Stack Frames + +The RXv2 port for ThreadX uses the first software interrupt, SWINT, i.e., interrupt #17, +to perform context switch. This ISR is thus reserved when using ThreadX and the SWINT +should not be manipulated in any way by the application. The port will setup the +interrupt within _tx_initialize_low_level and the compiler will automatically install +the necessary interrupt vector. As such no additional initialization is necessary by the +application. + +The following defines the saved context stack frame used by the ThreadX port. The +state of the CPU registers at the time of a context switch is saved on the running +thread's stack The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + + Offset Interrupted Stack Frame + + 0x00 1 + 0x04 ACC0 + 0x08 ACC1 + 0x0C R6 + 0x10 R7 + 0x14 R8 + 0x18 R9 + 0x1C R10 + 0x20 R11 + 0x24 R12 + 0x28 R13 + 0x2C FPSW + 0x30 R14 + 0x34 R15 + 0x38 R3 + 0x3C R4 + 0x40 R5 + 0x44 R1 + 0x48 R2 + 0x4C PC - return address + 0x50 PSW + +Note: By default IAR does not save the state of the accumulator registers ACC0 and ACC1 +when entering an ISR. This means that if the ISR uses any of the DSP instructions the +content of those registers could be corrupted. Saving and restoring of the acummulators +can be enabled by adding the --save_acc command line option. + + +5. Improving Performance + +The distribution version of ThreadX is built without any compiler optimizations. This +makes it easy to debug because you can trace or set breakpoints inside of ThreadX itself. +Of course, this costs some performance. To make ThreadX run faster, you can change the +ThreadX Library project to disable debug information and enable the desired optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by compiling your +application code with the symbol TX_DISABLE_ERROR_CHECKING defined before tx_api.h +is included. + + +6. Timer Processing + +Timer processign is performed by calling __tx_timer_interrupt(). This should usually be done +from within the callback of a periodic timer with a period of 100Hz. In the sample projects +a Renesas Fit CMT periodic timer module (rx_cmt) is used as the timer source. + + +7. Interrupt Handling + +Interrupt handling is unaffected by the ThreadX port as such user interrupts can be +written according to the toolchain's documentation. It is recommended not to use interrupt +priority 15 as this is the priority of the context switch interrupt. However using interrupt +priority 15 won't cause any negative side effectd but doing so may may slightly reduce +performance. Please refer to the toolchain documentation for additional details on how to +define interupt service routines. + + +8. Execution Profiling + +The RX port adds support for the Execution Profiling Kit (EPK). The EPK consists +of the files tx_execution_profile.c and tx_execution_profile.h. See the documentation +of the EPK for generic usage details. + +To add the EPK to your RXv2 release make the following modifications: + +* Enable the following define for both the Threadx library and the application +TX_ENABLE_EXECUTION_CHANGE_NOTIFY + +* in tx_port.h, change around line 183 +change #define TX_THREAD_EXTENSION_3 +into #include "tx_execution_profile.h" + +* Setup CMT1 as a free running 16 bit timer. + +* In tx_execution_profile.h, change following around line 74: + +#ifdef TX_EXECUTION_64BIT_TIME +typedef unsigned long long EXECUTION_TIME; +#define TX_THREAD_EXTENSION_3 unsigned long long tx_thread_execution_time_total; \ + unsigned long long tx_thread_execution_time_last_start; +#define TX_EXECUTION_MAX_TIME_SOURCE 0xFFFFFFFFFFFFFFFF +#else +typedef unsigned long EXECUTION_TIME; +#define TX_THREAD_EXTENSION_3 unsigned long tx_thread_execution_time_total; \ + unsigned long tx_thread_execution_time_last_start; +#define TX_EXECUTION_MAX_TIME_SOURCE 0xFFFF +#endif + +/* Define basic constants for the execution profile kit. */ + +#define TX_EXECUTION_TIME_SOURCE (EXECUTION_TIME) *((USHORT *) 0x8800A) + +Rebuild the Threadx library and the application. +Refer to the EPK documentation how to interpret the results. + + +9. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +12-31-2020 Initial ThreadX release for the RXv2using IAR tools, version 6.1.3 + + +Copyright(c) 1996-2020 Microsoft Corporation + + +https://azure.com/rtos
\ No newline at end of file diff --git a/ports/rxv2/iar/src/tx_initialize_low_level.s b/ports/rxv2/iar/src/tx_initialize_low_level.s new file mode 100644 index 00000000..49336a57 --- /dev/null +++ b/ports/rxv2/iar/src/tx_initialize_low_level.s @@ -0,0 +1,99 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; + + extern __tx_initialize_unused_memory + + section .text:CODE:ROOT + +; +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_initialize_low_level RX/IAR */ +;/* 6.1.3 */ +;/* 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 */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ + public __tx_initialize_low_level + +__tx_initialize_low_level: + +; /* Save the first available memory address. */ +; _tx_initialize_unused_memory = (VOID_PTR) &free_mem_start; +; + MOV.L #__tx_free_memory_start, R1 ; Pickup unused memory address + MOV.L #__tx_initialize_unused_memory,R2 + MOV.L R1,[R2] ; Save first free memory address + +; /* Set priority of SWINT to 1. */ + MOV.L #0x87303, r1 + MOV.L #1, r2 + MOV.B r2, [r1] + +; /* Enable SWINT. */ + MOV.L #0x87203, r1 + MOV.B [r1], r2 + OR #(1 << 3), r2 + MOV.B r2, [r1] + + RTS + + section FREEMEM:DATA + public __tx_free_memory_start +__tx_free_memory_start + DS32 4 + + END diff --git a/ports/rxv2/iar/src/tx_thread_context_restore.s b/ports/rxv2/iar/src/tx_thread_context_restore.s new file mode 100644 index 00000000..491dae82 --- /dev/null +++ b/ports/rxv2/iar/src/tx_thread_context_restore.s @@ -0,0 +1,205 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; +; + extern __tx_thread_system_state + extern __tx_thread_current_ptr + extern __tx_thread_preempt_disable + extern __tx_thread_execute_ptr + extern __tx_timer_time_slice + extern __tx_thread_schedule + + section .text:CODE:ROOT + +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_context_restore RX/IAR */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function restores the interrupt context if it is processing a */ +;/* nested interrupt. If not, it returns to the interrupt thread if no */ +;/* preemption is necessary. Otherwise, if preemption is necessary or */ +;/* if no thread was running, the function returns to the scheduler. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_schedule Thread scheduling routine */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ISRs Interrupt Service Routines */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ + public __tx_thread_context_restore + +__tx_thread_context_restore: +; +; /* Lockout interrupts. */ + + CLRPSW I ; disable interrupts + +; /* Determine if interrupts are nested. */ +; if (--_tx_thread_system_state) +; { + + MOV.L #__tx_thread_system_state, R1 + MOV.L [R1], R2 + SUB #1, R2 + MOV.L R2,[R1] + BEQ __tx_thread_not_nested_restore + +; +; /* Interrupts are nested. */ +; +; /* Recover the saved registers from the interrupt stack +; and return to the point of interrupt. */ +; +__tx_thread_nested_restore: + POPC FPSW ; restore FPU status + POPM R14-R15 ; restore R14-R15 + POPM R3-R5 ; restore R3-R5 + POPM R1-R2 ; restore R1-R2 + RTE ; return to point of interrupt, restore PSW including IPL +; } + +__tx_thread_not_nested_restore: +; +; /* Determine if a thread was interrupted and no preemption is required. */ +; else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr) +; || (_tx_thread_preempt_disable)) +; { + + MOV.L #__tx_thread_current_ptr, R1 ; Pickup current thread ptr address + MOV.L [R1], R2 + CMP #0, R2 + BEQ __tx_thread_idle_system_restore + + MOV.L #__tx_thread_preempt_disable, R3 ; pick up preempt disable flag + MOV.L [R3], R3 + CMP #0, R3 + BNE __tx_thread_no_preempt_restore ; if pre-empt disable flag set, we simply return to the original point of interrupt regardless + + MOV.L #__tx_thread_execute_ptr, R3 ; (_tx_thread_current_ptr != _tx_thread_execute_ptr) + CMP [R3], R2 + BNE __tx_thread_preempt_restore ; jump to pre-empt restoring +; +__tx_thread_no_preempt_restore: + SETPSW U ; user stack + POPC FPSW ; restore FPU status + POPM R14-R15 ; restore R14-R15 + POPM R3-R5 ; restore R3-R5 + POPM R1-R2 ; restore R1-R2 + RTE ; return to point of interrupt, restore PSW including IPL + +; } +; else +; { + +__tx_thread_preempt_restore: + +; /* Save the remaining time-slice and disable it. */ +; if (_tx_timer_time_slice) +; { + + MOV.L #__tx_timer_time_slice, R3 ; Pickup time-slice address + MOV.L [R3],R4 ; Pickup actual time-slice + CMP #0, R4 + BEQ __tx_thread_dont_save_ts ; no time slice to save +; +; _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; +; _tx_timer_time_slice = 0; +; + MOV.L R4,24[R2] ; Save thread's time slice + MOV.L #0,R4 ; Clear value + MOV.L R4,[R3] ; Disable global time slice flag +; } +__tx_thread_dont_save_ts: +; +; /* Now store the remaining registers! */ + + SETPSW U ; user stack + PUSHM R6-R13 + + MVFACGU #0, A1, R4 ; Save accumulators. + MVFACHI #0, A1, R5 + MVFACLO #0, A1, R6 + PUSHM R4-R6 + MVFACGU #0, A0, R4 + MVFACHI #0, A0, R5 + MVFACLO #0, A0, R6 + PUSHM R4-R6 + + MOV.L #1, R3 ; indicate interrupt stack frame + PUSH.L R3 + +; +; /* Clear the current task pointer. */ +; _tx_thread_current_ptr = TX_NULL; +; R1 -> _tx_thread_current_ptr +; R2 -> *_tx_thread_current_ptr + + MOV.L R0,8[R2] ; Save thread's stack pointer in thread control block + MOV.L #0,R2 ; Build NULL value + MOV.L R2,[R1] ; Set current thread to NULL + +; /* Return to the scheduler. */ +; _tx_thread_schedule(); + +__tx_thread_idle_system_restore: + MVTC #0, PSW ; reset interrupt priority level to 0 + BRA __tx_thread_schedule ; jump to scheduler +; } +; +;} +; + END diff --git a/ports/rxv2/iar/src/tx_thread_context_save.s b/ports/rxv2/iar/src/tx_thread_context_save.s new file mode 100644 index 00000000..218f65cd --- /dev/null +++ b/ports/rxv2/iar/src/tx_thread_context_save.s @@ -0,0 +1,170 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; + extern __tx_thread_system_state + extern __tx_thread_current_ptr + + section .text:CODE:ROOT + ;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_context_save RX/IAR */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function saves the context of an executing thread in the */ +;/* beginning of interrupt processing. The function also ensures that */ +;/* the system stack is used upon return to the calling ISR. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ISRs */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_context_save(VOID) +;{ + public __tx_thread_context_save + +__tx_thread_context_save: +; +; /* Upon entry to this routine, it is assumed that interrupts are locked +; out and the (interrupt) stack frame looks like the following: +; +; (lower address) SP -> [return address of this call] +; SP+4 -> Saved R1 +; SP+8 -> Saved R2 +; SP+12-> Interrupted PC +; SP+16-> Interrupted PSW +; +; /* Check for a nested interrupt condition. */ +; if (_tx_thread_system_state++) +; { +; + + MOV.L #__tx_thread_system_state, R1 ; pick up address of system state + MOV.L [R1], R2 ; pick up system state + CMP #0, R2 ; 0 -> no nesting + BEQ __tx_thread_not_nested_save +; +; /* Nested interrupt condition. */ +; + ADD #1, r2 ; _tx_thread_system_state++ + MOV.L r2, [r1] + +; +; /* Save the rest of the scratch registers on the interrupt stack and return to the +; calling ISR. */ + POP R1 ; recuperate return address from stack + PUSHM R3-R5 + PUSHM R14-R15 + PUSHC FPSW ; (top) FPSW, R14, R15, R3, R4, R5, R1, R2, PC, PSW (bottom) + JMP R1 ; return address was preserved in R1 + +; +__tx_thread_not_nested_save: +; } +; +; /* Otherwise, not nested, check to see if a thread was running. */ +; else if (_tx_thread_current_ptr) +; { +; + ADD #1, R2 ; _tx_thread_system_state++ + MOV.L R2, [R1] + + MOV.L #__tx_thread_current_ptr, R2 ; Pickup current thread pointer + MOV.L [R2], R2 + CMP #0,R2 ; Is it NULL? + BEQ __tx_thread_idle_system_save ; Yes, idle system is running - idle restore +; +; /* Move stack frame over to the current threads stack. */ +; /* complete stack frame with registers not saved yet (R3-R5, R14-R15, FPSW) */ +; + MVFC USP, R1 ; pick up user stack pointer + MOV.L 16[R0], R2 + MOV.L R2, [-R1] ; save PSW on thread stack + MOV.L 12[R0], R2 + MOV.L R2, [-R1] ; save PC on thread stack + MOV.L 8[R0], R2 + MOV.L R2, [-R1] ; save R2 on thread stack + MOV.L 4[R0], R2 + MOV.L R2, [-R1] ; save R1 on thread stack + MOV.L R5, [-R1] ; save R5 on thread stack + MOV.L R4, [-R1] ; save R4 on thread stack + MOV.L R3, [-R1] ; save R3 on thread stack + MOV.L R15, [-R1] ; save R15 on thread stack + MOV.L R14, [-R1] ; save R14 on thread stack + MVFC FPSW, R3 + MOV.L R3, [-R1] ; save FPSW on thread stack + + POP R2 ; pick up return address from interrupt stack + ADD #16, R0, R0 ; correct interrupt stack pointer back to the bottom + MVTC R1, USP ; set user/thread stack pointer + JMP R2 ; return to ISR + +; } +; else +; { +; +__tx_thread_idle_system_save: +; +; /* Interrupt occurred in the scheduling loop. */ +; + POP R1 ; pick up return address + ADD #16, R0, R0 ; correct interrupt stack pointer back to the bottom (PC), don't care about saved registers + JMP R1 ; return to caller +; +; } +;} + END diff --git a/ports/rxv2/iar/src/tx_thread_interrupt_control.s b/ports/rxv2/iar/src/tx_thread_interrupt_control.s new file mode 100644 index 00000000..bd8474df --- /dev/null +++ b/ports/rxv2/iar/src/tx_thread_interrupt_control.s @@ -0,0 +1,93 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +; + section .text:CODE:ROOT +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_interrupt_control RX/IAR */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is responsible for changing the interrupt lockout */ +;/* posture of the system. */ +;/* */ +;/* INPUT */ +;/* */ +;/* new_posture New interrupt lockout posture */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* old_posture Old interrupt lockout posture */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* Application Code */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;UINT _tx_thread_interrupt_control(UINT new_posture) +;{ + public __tx_thread_interrupt_control +__tx_thread_interrupt_control: +; +; /* Pickup current interrupt lockout posture. */ +; + + MVFC PSW, R2 ; Save PSW to R2 + MOV.L R2, R3 ; Make a copy of PSW in r3 + +; +; /* Apply the new interrupt posture. */ +; + + BTST #16, R1 ; test I bit of PSW of "new posture" + BMNE #16, R2 ; conditionally set I bit of intermediate posture + + MVTC R2, PSW ; save intermediate posture to PSW + + MOV.L R3,R1 ; Get original SR + RTS ; Return to caller +;} + END diff --git a/ports/rxv2/iar/src/tx_thread_schedule.s b/ports/rxv2/iar/src/tx_thread_schedule.s new file mode 100644 index 00000000..9de14be1 --- /dev/null +++ b/ports/rxv2/iar/src/tx_thread_schedule.s @@ -0,0 +1,179 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +;#include "tx_timer.h" +; +; + extern __tx_thread_execute_ptr + extern __tx_thread_current_ptr + extern __tx_timer_time_slice + + section .text:CODE:ROOT + +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_schedule RX/IAR */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function waits for a thread control block pointer to appear in */ +;/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +;/* in the variable, the corresponding thread is resumed. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* _tx_initialize_kernel_enter ThreadX entry function */ +;/* _tx_thread_system_return Return to system from thread */ +;/* _tx_thread_context_restore Restore thread's context */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_schedule(VOID) +;{ + public __tx_thread_schedule + +__tx_thread_schedule: +; +; /* Enable interrupts. */ +; + SETPSW I +; +; /* Wait for a thread to execute. */ +; do +; { + MOV.L #__tx_thread_execute_ptr, R1 ; Address of thread to executer ptr +__tx_thread_schedule_loop: + MOV.L [R1],R2 ; Pickup next thread to execute + CMP #0,R2 ; Is it NULL? + BEQ __tx_thread_schedule_loop ; Yes, idle system, keep checking +; +; } +; while(_tx_thread_execute_ptr == TX_NULL); +; +; /* Yes! We have a thread to execute. Lockout interrupts and +; transfer control to it. */ +; + CLRPSW I ; disable interrupts +; +; /* Setup the current thread pointer. */ +; _tx_thread_current_ptr = _tx_thread_execute_ptr; +; + MOV.L #__tx_thread_current_ptr, R3 + MOV.L R2,[R3] ; Setup current thread pointer +; +; /* Increment the run count for this thread. */ +; _tx_thread_current_ptr -> tx_thread_run_count++; +; + MOV.L 4[R2],R3 ; Pickup run count + ADD #1,R3 ; Increment run counter + MOV.L R3,4[R2] ; Store it back in control block +; +; /* Setup time-slice, if present. */ +; _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice; +; + MOV.L 24[R2],R3 ; Pickup thread time-slice + MOV.L #__tx_timer_time_slice,R4 ; Pickup pointer to time-slice + MOV.L R3, [R4] ; Setup time-slice +; +; /* Switch to the thread's stack. */ +; SP = _tx_thread_execute_ptr -> tx_thread_stack_ptr; + SETPSW U ; user stack mode + MOV.L 8[R2],R0 ; Pickup stack pointer +; +; /* Determine if an interrupt frame or a synchronous task suspension frame +; is present. */ +; + POP R1 ; Pickup stack type + CMP #1, R1 ; Is it an interrupt stack? + BNE __tx_thread_synch_return ; No, a synchronous return frame is present. + + POPM R1-R3 ; Restore accumulators. + MVTACLO R3, A0 + MVTACHI R2, A0 + MVTACGU R1, A0 + POPM R1-R3 + MVTACLO R3, A1 + MVTACHI R2, A1 + MVTACGU R1, A1 + + POPM R6-R13 ; Recover interrupt stack frame + POPC FPSW + POPM R14-R15 + POPM R3-R5 + POPM R1-R2 + RTE ; return to point of interrupt, this restores PC and PSW + +__tx_thread_synch_return: + POPC PSW + POPM R6-R13 ; Recover solicited stack frame + RTS +; +;} + + extern __tx_thread_context_save + extern __tx_thread_context_restore + +; Software triggered interrupt used to perform context switches. +; The priority of this interrupt is set to the lowest priority within +; tx_initialize_low_level() and triggered by ThreadX when calling +; _tx_thread_system_return(). + public ___interrupt_27 +___interrupt_27: + + PUSHM R1-R2 + + BSR __tx_thread_context_save + + BRA __tx_thread_context_restore + + END diff --git a/ports/rxv2/iar/src/tx_thread_stack_build.s b/ports/rxv2/iar/src/tx_thread_stack_build.s new file mode 100644 index 00000000..688f0bc8 --- /dev/null +++ b/ports/rxv2/iar/src/tx_thread_stack_build.s @@ -0,0 +1,147 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; + + section .text:CODE:ROOT + +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_stack_build RX/IAR */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function builds a stack frame on the supplied thread's stack. */ +;/* The stack frame results in a fake interrupt return to the supplied */ +;/* function pointer. */ +;/* */ +;/* INPUT */ +;/* */ +;/* thread_ptr Pointer to thread control blk */ +;/* function_ptr Pointer to return function */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* _tx_thread_create Create thread service */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ + + public __tx_thread_stack_build + +__tx_thread_stack_build: +; +; +; /* Build an interrupt frame. The form of the fake interrupt stack +; on the Renesas RX should look like the following after it is built: +; +; Stack Top: 1 Interrupt stack frame type +; ACC0 +; ACC1 +; R6 +; R7 +; R8 +; R9 +; R10 +; R11 +; R12 +; R13 +; FPSW +; R14 +; R15 +; R3 +; R4 +; R5 +; R1 +; R2 +; PC +; PSW + +; +; Stack Bottom: (higher memory address) */ +; + MOV.L 16[R1],R3 ; Pickup end of stack area + BCLR #0, R3 ; mask for 4-byte alignment + BCLR #1, R3 +; +; /* Build the stack frame. */ +; + MOV.L #30000h, R4 + MOV.L R4, [-R3] ; initial PSW (SVC mode, U flag set) + MOV.L R2, [-R3] ; initial PC + MOV.L #0, R4 + MOV.L R4,[-R3] ; initial R2 ... + MOV.L R4,[-R3] ; initial R1 ... + MOV.L R4,[-R3] ; initial R5 ... + MOV.L R4,[-R3] ; initial R4 ... + MOV.L R4,[-R3] ; initial R3 ... + MOV.L R4,[-R3] ; initial R15 ... + MOV.L R4,[-R3] ; initial R14 ... + MVFC FPSW, r4 + MOV.L R4, [-R3] ; initial FPSW + MOV.L #0, R4 + MOV.L R4,[-R3] ; initial R13 ... + MOV.L R4,[-R3] ; initial R12 ... + MOV.L R4,[-R3] ; initial R11 ... + MOV.L R4,[-R3] ; initial R10 ... + MOV.L R4,[-R3] ; initial R9 ... + MOV.L R4,[-R3] ; initial R8 ... + MOV.L R4,[-R3] ; initial R7 ... + MOV.L R4,[-R3] ; initial R6 ... + + MOV.L R4,[-R3] ; Accumulator 1 + MOV.L R4,[-R3] + MOV.L R4,[-R3] + + MOV.L R4,[-R3] ; Accumulator 0 + MOV.L R4,[-R3] + MOV.L R4,[-R3] + + MOV.L #1, R4 + MOV.L R4,[-R3] ; indicate interrupt stack frame +; /* Setup stack pointer. */ +; thread_ptr -> tx_thread_stack_ptr = R1; + MOV.L R3, 8[R1] + ; store initial SP in thread control block + RTS + +;} + + END diff --git a/ports/rxv2/iar/src/tx_thread_system_return.s b/ports/rxv2/iar/src/tx_thread_system_return.s new file mode 100644 index 00000000..808e345e --- /dev/null +++ b/ports/rxv2/iar/src/tx_thread_system_return.s @@ -0,0 +1,74 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ + + section .text:CODE:ROOT + + ;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_system_return RX/IAR */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is target processor specific. It is used to transfer */ +;/* control from a thread back to the system. Only a minimal context */ +;/* is saved since the compiler assumes temp registers are going to get */ +;/* slicked by a function call anyway. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_schedule Thread scheduling loop */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ThreadX components */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ + + public __tx_thread_system_return + +__tx_thread_system_return: + + BRA __tx_thread_system_return + + RTS + + END diff --git a/ports/rxv2/iar/src/tx_timer_interrupt.s b/ports/rxv2/iar/src/tx_timer_interrupt.s new file mode 100644 index 00000000..645f73b4 --- /dev/null +++ b/ports/rxv2/iar/src/tx_timer_interrupt.s @@ -0,0 +1,235 @@ +;/**************************************************************************/ +;/* */ +;/* 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 */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ + + extern __tx_timer_expiration_process + extern __tx_timer_system_clock + extern __tx_timer_expired_time_slice + extern __tx_timer_current_ptr + extern __tx_timer_expired + extern __tx_timer_list_start + extern __tx_timer_time_slice + extern __tx_timer_list_end + extern __tx_thread_time_slice + + section .text:CODE:ROOT + +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_timer_interrupt RX/IAR */ +;/* 6.1.3 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function processes the hardware timer interrupt. This */ +;/* processing includes incrementing the system clock and checking for */ +;/* time slice and/or timer expiration. If either is found, the */ +;/* interrupt context save/restore functions are called along with the */ +;/* expiration functions. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_context_save Save interrupted context */ +;/* _tx_timer_expiration_process Timer expiration processing */ +;/* _tx_thread_time_slice Time slice interrupted thread */ +;/* _tx_thread_context_restore Restore interrupted context */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* interrupt vector */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 12-31-2020 William E. Lamie Initial Version 6.1.3 */ +;/* */ +;/**************************************************************************/ + + public __tx_timer_interrupt +__tx_timer_interrupt: +; +; /* Upon entry to this routine, it is assumed that all interrupts are locked +; out and the stack looks like the following: +; SP+4 -> Interrupted PC +; SP+8-> Interrupted SR +; */ +; +; /* Increment the system clock. */ +; _tx_timer_system_clock++; +; + PUSHM R14-R15 + PUSHM R1-R5 + + MOV.L #__tx_timer_system_clock, R1 ; Pickup address of system clock + MOV.L [R1], R2 ; Pickup system clock + ADD #1, R2 ; Increment system clock + MOV.L R2,[R1] ; Store new system clock +; +; /* Test for time-slice expiration. */ +; if (_tx_timer_time_slice) +; { +; + MOV.L #__tx_timer_time_slice, R1 ; Pickup address of time slice + MOV.L [R1], R2 ; Pickup the current time slice + CMP #0, R2 ; Is a time slice active? + BEQ __tx_timer_no_time_slice ; No, skip timer slice processing +; +; /* Decrement the time_slice. */ +; _tx_timer_time_slice--; +; + SUB #1, R2 ; Decrement the time-slice + MOV.L R2, [R1] ; Store time-slice +; +; /* Check for expiration. */ +; if (__tx_timer_time_slice == 0) +; + CMP #0, R2 ; Has it expired? + BNE __tx_timer_no_time_slice ; No, time-slice has not expired +; +; /* Set the time-slice expired flag. */ +; _tx_timer_expired_time_slice = TX_TRUE; +; + MOV.L #__tx_timer_expired_time_slice, R1 ; Pickup address of expired time-slice + MOV.L #1, R2 ; Build expired value + MOV.L R2, [R1] ; Set expired time slice variable +; } +; +__tx_timer_no_time_slice: +; +; /* Test for timer expiration. */ +; if (*_tx_timer_current_ptr) +; { +; + MOV.L #__tx_timer_current_ptr, R1 ; Pickup address of current timer ptr + MOV.L [R1], R2 ; Pickup current pointer + MOV.L [R2+], R1 ; pickup timer list entry, _tx_timer_current_ptr++ + CMP #0, R1 ; Is timer pointer NULL? + BEQ __tx_timer_no_timer ; Yes, no timer has expired + +; +; /* Set expiration flag. */ +; _tx_timer_expired = TX_TRUE; +; + MOV.L #__tx_timer_expired,R2 ; Build address of expired flag + MOV.L #1, R1 ; Build expired value + MOV.L R1, [R2] + BRA __tx_timer_done ; Finished with timer processing +; +; } +; else +; { +__tx_timer_no_timer: +; +; /* No timer expired, increment the timer pointer. */ +; _tx_timer_current_ptr++; +; +; /* R2 already contains __tx_timer_current_ptr++ */ +; +; /* Check for wrap-around. */ +; if (_tx_timer_current_ptr == _tx_timer_list_end) +; + MOV.L #__tx_timer_list_end, R1 ; Pickup the timer list end ptr + MOV.L [R1], R1 ; Pickup actual timer list end + CMP R1, R2 ; Are we at list end? + BNE __tx_timer_skip_wrap ; No, don't move pointer to the + ; top of the list +; +; /* Wrap to beginning of list. */ +; _tx_timer_current_ptr = _tx_timer_list_start; +; + MOV.L #__tx_timer_list_start, R2 ; Pickup the timer list start ptr + MOV.L [R2], R2 ; Pickup the start of the list +; } +; +__tx_timer_skip_wrap: + MOV.L #__tx_timer_current_ptr,R1 + MOV.L R2, [R1] ; store in updated pointer in _tx_timer_current_ptr + +__tx_timer_done: +; +; /* See if anything has expired. */ +; if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) +; { +; + MOV.L #__tx_timer_expired_time_slice, R1 ; Pickup expired time slice addr + MOV.L [R1], R1 ; Pickup expired time slice + MOV.L #__tx_timer_expired, R2 ; Pickup expired timer flag address + MOV.L [R2], R2 ; Pickup actual flag + OR R1, R2 ; Or flags together + BEQ __tx_timer_nothing_expired ; If Z set, nothing has expired + +__tx_something_expired: +; /* Did a timer expire? */ +; if (_tx_timer_expired) +; { + MOV.L #__tx_timer_expired,R1 ; Pickup expired flag address + MOV.L [R1], R1 ; Pickup expired flag + CMP #0,R1 ; Is the expired timer flag set? + BEQ __tx_timer_dont_activate ; No, skip timer activation +; +; /* Process timer expiration. */ +; _tx_timer_expiration_process(); +; + BSR __tx_timer_expiration_process ; Call the timer expiration handling routine +; +; } +__tx_timer_dont_activate: +; +; /* Did time slice expire? */ +; if (_tx_timer_expired_time_slice) +; { +; + MOV.L #__tx_timer_expired_time_slice, R1 ; Pickup time-slice expired flag addr + MOV.L [R1], R1 ; Pickup actual flag + CMP #0,R1 ; Has time-slice expired? + BEQ __tx_timer_not_ts_expiration ; No, skip time-slice expiration +; +; /* Time slice interrupted thread. */ +; _tx_thread_time_slice(); + + BSR __tx_thread_time_slice ; Call time-slice processing +; } +; +__tx_timer_not_ts_expiration: + +__tx_timer_nothing_expired: + + POPM R1-R5 + POPM R14-R15 +; + RTS ; return to point of interrupt +; +;} + END
\ No newline at end of file diff --git a/ports/xtensa/xcc/CMakeLists.txt b/ports/xtensa/xcc/CMakeLists.txt new file mode 100644 index 00000000..31768e58 --- /dev/null +++ b/ports/xtensa/xcc/CMakeLists.txt @@ -0,0 +1,36 @@ + +target_sources(${PROJECT_NAME} + PRIVATE + # {{BEGIN_TARGET_SOURCES}} + ${CMAKE_CURRENT_LIST_DIR}/src/tx_clib_lock.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_low_level.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_xtensa_stack_error_handler.c + ${CMAKE_CURRENT_LIST_DIR}/src/xtensa_context.S + ${CMAKE_CURRENT_LIST_DIR}/src/xtensa_coproc_handler.S + ${CMAKE_CURRENT_LIST_DIR}/src/xtensa_init.c + ${CMAKE_CURRENT_LIST_DIR}/src/xtensa_intr_asm.S + ${CMAKE_CURRENT_LIST_DIR}/src/xtensa_intr.c + ${CMAKE_CURRENT_LIST_DIR}/src/xtensa_intr_wrapper.c + ${CMAKE_CURRENT_LIST_DIR}/src/xtensa_overlay_os_hook.c + ${CMAKE_CURRENT_LIST_DIR}/src/xtensa_vectors.S + ${CMAKE_CURRENT_LIST_DIR}/src/xtensa_vectors_xea3.S + + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) + +set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/src/xtensa_vectors_xea3.S + TARGET_DIRECTORY ${PROJECT_NAME} + PROPERTIES COMPILE_OPTIONS "-mtext-section-literals") + diff --git a/ports/xtensa/xcc/example_build/demo_threadx.c b/ports/xtensa/xcc/example_build/demo_threadx.c new file mode 100644 index 00000000..5bec9cc8 --- /dev/null +++ b/ports/xtensa/xcc/example_build/demo_threadx.c @@ -0,0 +1,377 @@ +/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight + threads of different priorities, using a message queue, semaphore, mutex, event flags group, + byte pool, and block pool. */ + +#include <stdio.h> +#include <xtensa/xtutil.h> + +#include "tx_api.h" + +#define DEMO_STACK_SIZE 1024 +#define DEMO_BYTE_POOL_SIZE 9120 +#define DEMO_BLOCK_POOL_SIZE 100 +#define DEMO_QUEUE_SIZE 100 + + +/* Define the ThreadX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; +TX_THREAD thread_2; +TX_THREAD thread_3; +TX_THREAD thread_4; +TX_THREAD thread_5; +TX_THREAD thread_6; +TX_THREAD thread_7; +TX_QUEUE queue_0; +TX_SEMAPHORE semaphore_0; +TX_MUTEX mutex_0; +TX_EVENT_FLAGS_GROUP event_flags_0; +TX_BYTE_POOL byte_pool_0; +TX_BLOCK_POOL block_pool_0; +UCHAR memory_area[DEMO_BYTE_POOL_SIZE]; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG thread_1_messages_sent; +ULONG thread_2_counter; +ULONG thread_2_messages_received; +ULONG thread_3_counter; +ULONG thread_4_counter; +ULONG thread_5_counter; +ULONG thread_6_counter; +ULONG thread_7_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void thread_2_entry(ULONG thread_input); +void thread_3_and_4_entry(ULONG thread_input); +void thread_5_entry(ULONG thread_input); +void thread_6_and_7_entry(ULONG thread_input); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer = TX_NULL; + + + /* Create a byte memory pool from which to allocate the thread stacks. */ + tx_byte_pool_create(&byte_pool_0, "byte pool 0", memory_area, DEMO_BYTE_POOL_SIZE); + + /* Put system definition stuff in here, e.g. thread creates and other assorted + create information. */ + + /* Allocate the stack for thread 0. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); + + + /* Allocate the stack for thread 1. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 1 and 2. These threads pass information through a ThreadX + message queue. It is also interesting to note that these threads have a time + slice. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 2. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 3. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore. + An interesting thing here is that both threads share the same instruction area. */ + tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 4. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 5. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create thread 5. This thread simply pends on an event flag which will be set + by thread_0. */ + tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 6. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */ + tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 7. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the message queue. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT); + + /* Create the message queue shared by threads 1 and 2. */ + tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG)); + + /* Create the semaphore used by threads 3 and 4. */ + tx_semaphore_create(&semaphore_0, "semaphore 0", 1); + + /* Create the event flags group used by threads 1 and 5. */ + tx_event_flags_create(&event_flags_0, "event flags 0"); + + /* Create the mutex used by thread 6 and 7 without priority inheritance. */ + tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT); + + /* Allocate the memory for a small block pool. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT); + + /* Create a block memory pool to allocate a message buffer from. */ + tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE); + + /* Allocate a block and release the block memory. */ + tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT); + + /* Release the block back to the pool. */ + tx_block_release(pointer); +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sits in while-forever-sleep loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_0_counter++; + + /* Sleep for 10 ticks. */ + tx_thread_sleep(10); + + /* Set event flag 0 to wakeup thread 5. */ + status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Print something to show we are making progress. This should use the print + function from libxtutil which is thread-safe. */ + printf("%u %u %u\n", thread_0_counter, thread_1_counter, thread_2_counter); + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sends messages to a queue shared by thread 2. */ + while(1) + { + + /* Increment the thread counter. */ + thread_1_counter++; + + /* Send message to queue 0. */ + status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER); + + /* Check completion status. */ + if (status != TX_SUCCESS) + break; + + /* Increment the message sent. */ + thread_1_messages_sent++; + } +} + + +void thread_2_entry(ULONG thread_input) +{ + +ULONG received_message; +UINT status; + + /* This thread retrieves messages placed on the queue by thread 1. */ + while(1) + { + + /* Increment the thread counter. */ + thread_2_counter++; + + /* Retrieve a message from the queue. */ + status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER); + + /* Check completion status and make sure the message is what we + expected. */ + if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received)) + break; + + /* Otherwise, all is okay. Increment the received message count. */ + thread_2_messages_received++; + } +} + + +void thread_3_and_4_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 3 and thread 4. As the loop + below shows, these function compete for ownership of semaphore_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 3) + thread_3_counter++; + else + thread_4_counter++; + + /* Get the semaphore with suspension. */ + status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the semaphore. */ + tx_thread_sleep(2); + + /* Release the semaphore. */ + status = tx_semaphore_put(&semaphore_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_5_entry(ULONG thread_input) +{ + +UINT status; +ULONG actual_flags; + + + /* This thread simply waits for an event in a forever loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_5_counter++; + + /* Wait for event flag 0. */ + status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR, + &actual_flags, TX_WAIT_FOREVER); + + /* Check status. */ + if ((status != TX_SUCCESS) || (actual_flags != 0x1)) + break; + } +} + + +void thread_6_and_7_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 6 and thread 7. As the loop + below shows, these function compete for ownership of mutex_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 6) + thread_6_counter++; + else + thread_7_counter++; + + /* Get the mutex with suspension. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Get the mutex again with suspension. This shows + that an owning thread may retrieve the mutex it + owns multiple times. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the mutex. */ + tx_thread_sleep(2); + + /* Release the mutex. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Release the mutex again. This will actually + release ownership since it was obtained twice. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} diff --git a/ports/xtensa/xcc/inc/tx_api_asm.h b/ports/xtensa/xcc/inc/tx_api_asm.h new file mode 100644 index 00000000..1840ffce --- /dev/null +++ b/ports/xtensa/xcc/inc/tx_api_asm.h @@ -0,0 +1,67 @@ + +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains macro constants for ThreadX API structures */ +/* and enums that need to be used in assembly coded port sources. */ +/* Most of these constants are derived from definitions in tx_api.h. */ +/* Only the constants that are needed are included here to reduce */ +/* the maintenance required when the structures or enums change. */ +/* Structure offsets depend on the compiler, so are tools-specific, */ +/* which usually means port-specific since a compiler's struct */ +/* packing rules depend on properties of the target architecture. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +#ifndef TX_API_ASM_H +#define TX_API_ASM_H + +#include "tx_port.h" + +/* API input parameters and general constants. */ + +#define TX_TRUE 1 +#define TX_FALSE 0 +#define TX_NULL 0 + +/* ThreadX thread control block structure. */ +// typedef struct TX_THREAD_STRUCT +// { + +#define tx_thread_run_count 0x04 +#define tx_thread_stack_ptr 0x08 +#define tx_thread_stack_end 0x10 +#define tx_thread_time_slice 0x18 +#define tx_thread_new_time_slice 0x1C +#define tx_thread_solicited 0x28 + +#ifdef TX_THREAD_SAFE_CLIB + #define tx_real_thread_entry 0x2C + #define tx_thread_clib_ptr 0x30 + #define tx_thread_cp_state 0x34 +#else + #define tx_thread_cp_state 0x2C +#endif + +// } + +#endif /* TX_API_ASM_H */ + diff --git a/ports/xtensa/xcc/inc/tx_port.h b/ports/xtensa/xcc/inc/tx_port.h new file mode 100644 index 00000000..9438a7c8 --- /dev/null +++ b/ports/xtensa/xcc/inc/tx_port.h @@ -0,0 +1,479 @@ + +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/* Comment this out to disable thread-safe C library support. */ +#define TX_THREAD_SAFE_CLIB 1 + +/* Include the glue to Xtensa-generic parts of this ThreadX port. */ +#include "xtensa_rtos.h" + +/* Parts of this file should not been seen by assembler sources. */ +#ifndef __ASSEMBLER__ + +/* Some generic C sources call memset() and need this (else compiler warns). + Until the generic sources take care of this, do it here. */ + +#include <string.h> + + +/* Define compiler library include files and library-specific macros. */ + +/* + Thread-safety support for the supported C libraries. At this time + only the newlib and Xtensa C libraries are supported. + + The C library reent structure can be quite large so it is placed + at the end of TX_THREAD, and a pointer to it is defined near the + beginning of TX_THREAD where assembly code can easily get to it + at a fixed offset. +*/ + +#ifdef TX_THREAD_SAFE_CLIB +struct TX_THREAD_STRUCT; + +extern char *_tx_clib_heap_start, *_tx_clib_heap_end; +extern void _tx_clib_reent_init (struct TX_THREAD_STRUCT *thread_ptr); +extern void _tx_clib_reent_cleanup (struct TX_THREAD_STRUCT *thread_ptr, int partial); +extern void _tx_clib_thread_setup(struct TX_THREAD_STRUCT *thread_ptr); + +#include <sys/reent.h> + +#define TX_CLIB_THREAD_EXTENSION \ + VOID (*tx_real_thread_entry)(ULONG id); /* Actual entry point */ \ + struct _reent * tx_thread_clib_ptr; /* C lib reentrancy ptr */ +#define TX_CLIB_THREAD_EXTENSION_END \ + struct _reent tx_thread_clib_reent; /* C lib reentrancy struct */ +#define TX_CLIB_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_CLIB_THREAD_DELETE_EXTENSION(thread_ptr) +#define TX_CLIB_THREAD_EXIT_EXTENSION(thread_ptr) +#define TX_THREAD_CLIB_EXTENSION(thread_ptr) \ + _tx_clib_thread_setup(thread_ptr); +#else +#define TX_CLIB_THREAD_EXTENSION +#define TX_CLIB_THREAD_EXTENSION_END +#define TX_CLIB_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_CLIB_THREAD_DELETE_EXTENSION(thread_ptr) +#define TX_CLIB_THREAD_EXIT_EXTENSION(thread_ptr) +#define TX_THREAD_CLIB_EXTENSION(thread_ptr) +#endif + + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef short SHORT; +typedef unsigned short USHORT; + + +#endif /* #ifndef __ASSEMBLER__ */ + + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* + Define the minimum stack size for a thread on this processor. + If the size supplied during thread creation is less than TX_MINIMUM_STACK, + the thread create call will return an error. The minimum allows for a + thread whose entry function makes no calls and needs no local frame. + TX_MINIMUM_STACK_BASIC allows the entry function to at least call + tx_thread_relinquish(). An extra 0x10 bytes is allowed in all cases to + allow for stack pointer alignment to 16 bytes. There is an additional premium + for the stack checking functionality of TX_ENABLE_STACK_CHECKING. + In Xtensa, all these amounts depend on the function call ABI used by the + configuration (in general, Call0 ABI needs about 0x20 bytes less stack space + per function call frame). These amounts assume no compiler optimization (-O0). + Optimization usually requires less stack. + + TX_MINIMUM_STACK_BASIC is a MINIMUM for threads that call tx_thread_relinquish() + only. Threads that do more, and in particular call C library functions such as + printf(), need much more stack space and it is up to the application developer + to determine how much. +*/ + +#ifdef __XTENSA_CALL0_ABI__ + /* Call0 ABI */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK (XT_STK_FRMSZ + 0x10) +#endif +#ifdef TX_ENABLE_STACK_CHECKING +#define TX_STACK_CHECK_PREMIUM 0x30 +#else +#define TX_STACK_CHECK_PREMIUM 0 +#endif +#ifndef TX_MINIMUM_STACK_BASIC +#define TX_MINIMUM_STACK_BASIC (XT_STK_FRMSZ + 0x70 + TX_STACK_CHECK_PREMIUM) +#endif + +#else /* Windowed ABI */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK (XT_STK_FRMSZ + 0x20) +#endif +#ifdef TX_ENABLE_STACK_CHECKING +#define TX_STACK_CHECK_PREMIUM 0x50 +#else +#define TX_STACK_CHECK_PREMIUM 0 +#endif +#ifndef TX_MINIMUM_STACK_BASIC +#define TX_MINIMUM_STACK_BASIC (XT_STK_FRMSZ + 0x100 + TX_STACK_CHECK_PREMIUM) +#endif + +#endif + +/* + Minimum stack size for the ThreadX system stack on this processor. + This is just a useful starting point for an application, it is not + checked by ThreadX. The minimum system stack size allows for the + possible depth of interrupt nesting (XCHAL_EXCM_LEVEL-1 interrupt + stack frames and XCHAL_EXCM_LEVEL interrupt handlers including timer), + assuming very basic interrupt handlers (allows 1 call12). It needs to + be increased to support the application's real interrupt handlers (and + timer interrupt if TX_TIMER_PROCESS_IN_ISR). The system stack is located + where the stack pointer is inside tx_kernel_enter() which is usually from + main(), and so is determined by the development tools. It grows downward + toward the first available memory pointer passed to tx_application_define(). + An application should allow sufficient space for the system stack. + + For XEA3, allow a minimum of XCHAL_NUM_INTLEVELS nested interrupts. The stack + frames are minimal-sized and may need to be increased to support real applications. +*/ + +#if XCHAL_HAVE_XEA3 +#define TX_SYSTEM_STACK_MINIMUM (XCHAL_NUM_INTLEVELS * 0x40) +#ifndef TX_SYSTEM_STACK_SIZE +#if TX_SYSTEM_STACK_MINIMUM > 2048 +#define TX_SYSTEM_STACK_SIZE TX_SYSTEM_STACK_MINIMUM +#else +#define TX_SYSTEM_STACK_SIZE 2048 +#endif +#endif +#else +#define TX_SYSTEM_STACK_MINIMUM (((XCHAL_EXCM_LEVEL-1) * (0x40 + XT_STK_FRMSZ)) + 0x40) +#ifndef TX_SYSTEM_STACK_SIZE +#define TX_SYSTEM_STACK_SIZE 4096 +#endif +#endif + +/* + Define the system timer thread's default stack size and priority. + These are only applicable if TX_TIMER_PROCESS_IN_ISR is not defined. +*/ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#ifdef __XTENSA_CALL0_ABI__ +#define TX_TIMER_THREAD_STACK_SIZE (TX_MINIMUM_STACK_BASIC + 0x100) +#else +#define TX_TIMER_THREAD_STACK_SIZE (TX_MINIMUM_STACK_BASIC + 0x200) +#endif +#endif + + +/* Parts of this file should not been seen by assembler sources. */ +#ifndef __ASSEMBLER__ + + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + + +/* Define various constants for the ThreadX Xtensa port. */ + +#if XCHAL_HAVE_XEA3 +#define TX_INT_DISABLE 0x8 /* Disable interrupts value */ +#define TX_INT_ENABLE 0x0 /* Enable interrupt value */ +#else +#define TX_INT_DISABLE XCHAL_EXCM_LEVEL /* Disable interrupts value */ +#define TX_INT_ENABLE 0x0 /* Enable interrupt value */ +#endif + + +/* + Define the clock source for trace event entry time stamp. The following + two item are port specific. For example, if the time source is at the + address 0x0a800024 and is 16-bits in size, the clock source constants + would be: + + #define TX_TRACE_TIME_SOURCE *((ULONG *) 0x0a800024) + #define TX_TRACE_TIME_MASK 0x0000FFFFUL +*/ + +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE ++_tx_trace_simulated_time +#endif +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + + +/* + Define the port specific options for the _tx_build_options variable. + This variable indicates how the ThreadX library was built. +*/ + +#if defined(XT_SIMULATOR) || !defined(XT_BOARD) +#define TX_XT_OPT_SIMULATOR (1UL << 0) +#else +#define TX_XT_OPT_SIMULATOR 0 +#endif + +#if defined(XT_BOARD) +#define TX_XT_OPT_BOARD (1UL << 1) +#else +#define TX_XT_OPT_BOARD 0 +#endif + +#if defined(XT_INTEXC_HOOKS) +#define TX_XT_OPT_INTEXC_HOOKS (1UL << 2) +#else +#define TX_XT_OPT_INTEXC_HOOKS 0 +#endif + +#if defined(TX_THREAD_SAFE_CLIB) +#define TX_XT_OPT_CLIB (1UL << 3) +#else +#define TX_XT_OPT_CLIB 0 +#endif + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS (TX_XT_OPT_SIMULATOR | TX_XT_OPT_BOARD \ + | TX_XT_OPT_INTEXC_HOOKS | TX_XT_OPT_CLIB) + + +/* + Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. +*/ + +#define TX_INLINE_INITIALIZATION + + +/* + Determine whether or not stack checking is enabled. By default, ThreadX + stack checking is disabled. When the following is defined, ThreadX thread + stack checking is enabled. If enabled (TX_ENABLE_STACK_CHECKING is defined), + the TX_DISABLE_STACK_FILLING define is canceled, thereby forcing the stack + fill which is necessary for the stack checking logic. +*/ + +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif + + +/* + Define the TX_THREAD control block extensions for this port. The main + reason for the multiple macros is so that backward compatibility can + be maintained with existing ThreadX kernel awareness modules. +*/ + +#if XCHAL_CP_NUM > 0 +#define TX_CP_THREAD_EXTENSION \ + /* Co-proc state save areas, with padding for alignment: */ \ + UINT tx_thread_cp_state[(XT_CP_SIZE+3)/4]; +#else +#define TX_CP_THREAD_EXTENSION +#endif + +#define TX_THREAD_EXTENSION_0 \ + /* These extensions needs to be accessed from assembly code at context switches */ \ + UINT tx_thread_solicited; /* Non-zero indicates solicited entry */ \ + TX_CLIB_THREAD_EXTENSION /* Ptr to C library re-ent struct */ \ + TX_CP_THREAD_EXTENSION /* Coprocessor state save areas */ + +#define TX_THREAD_EXTENSION_1 \ + TX_CLIB_THREAD_EXTENSION_END + +#define TX_THREAD_EXTENSION_2 + +/* Execution profile related */ +#define TX_THREAD_EXTENSION_3 \ + unsigned long long tx_thread_execution_time_total; \ + unsigned long tx_thread_execution_time_last_start; + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + +#if XCHAL_CP_NUM > 0 +extern void _xt_coproc_release(void * coproc_sa_base); + +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) \ + _xt_coproc_release(&thread_ptr->tx_thread_cp_state); +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) \ + _xt_coproc_release(&thread_ptr->tx_thread_cp_state); +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) \ + _xt_coproc_release(&thread_ptr->tx_thread_cp_state); +#define TX_THREAD_CP_EXTENSION(thread_ptr) \ + /* Initialize XT_CP_ASA ptr to aligned save area: */ \ + /* NOTE: keep this matched with xtensa_context.h. */ \ + thread_ptr->tx_thread_cp_state[0] = 0; \ + thread_ptr->tx_thread_cp_state[1] = 0; \ + thread_ptr->tx_thread_cp_state[2] = \ + ((((UINT)thread_ptr->tx_thread_cp_state)+12+XCHAL_TOTAL_SA_ALIGN-1) \ + & -XCHAL_TOTAL_SA_ALIGN); +#else +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_CP_EXTENSION(thread_ptr) +#endif + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) \ + TX_THREAD_CLIB_EXTENSION(thread_ptr) \ + TX_THREAD_CP_EXTENSION(thread_ptr) + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + + +/* + Define ThreadX interrupt lockout and restore macros for protection + on access of critical kernel information. The restore interrupt macro + must restore the interrupt posture of the running thread prior to the + value present prior to the disable macro. In most cases, the save area + macro is used to define a local function save area for the disable and + restore macros. +*/ + +extern unsigned int _tx_thread_interrupt_control(unsigned int new_posture); + +#define TX_INTERRUPT_SAVE_AREA register unsigned int interrupt_save; + +#ifdef TX_DISABLE_INLINE_MACROS +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE); +#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save); +#else +#define TX_DISABLE interrupt_save = xthal_disable_interrupts(); +#define TX_RESTORE xthal_restore_interrupts(interrupt_save); +#endif + + +/* Define the interrupt lockout macros for each ThreadX object. */ + +#define TX_BLOCK_POOL_DISABLE TX_DISABLE +#define TX_BYTE_POOL_DISABLE TX_DISABLE +#define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLE +#define TX_MUTEX_DISABLE TX_DISABLE +#define TX_QUEUE_DISABLE TX_DISABLE +#define TX_SEMAPHORE_DISABLE TX_DISABLE + + +#if XCHAL_HAVE_XEA3 +/* Variables that keep track of the timer and software interrupt numbers in use. */ +extern int xt_sw_intnum; +extern int xt_timer_intnum; +#endif + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) Microsoft Corporation. * Azure RTOS Xtensa Version 6.1.3 *"; +#else +extern CHAR _tx_version_id[]; +#endif + +#endif /* #ifndef __ASSEMBLER__ */ + +#endif + diff --git a/ports/xtensa/xcc/inc/tx_user.h b/ports/xtensa/xcc/inc/tx_user.h new file mode 100644 index 00000000..db17d428 --- /dev/null +++ b/ports/xtensa/xcc/inc/tx_user.h @@ -0,0 +1,257 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_user.h PORTABLE C */ +/* 6.0.1 */ +/* */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains user defines for configuring ThreadX in specific */ +/* ways. This file will have an effect only if the application and */ +/* ThreadX library are built with TX_INCLUDE_USER_DEFINE_FILE defined. */ +/* Note that all the defines in this file may also be made on the */ +/* command line when building ThreadX library and application objects. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */ +/* */ +/**************************************************************************/ + +#ifndef TX_USER_H +#define TX_USER_H + + +/* Define various build options for the ThreadX port. The application should either make changes + here by commenting or un-commenting the conditional compilation defined OR supply the defines + though the compiler's equivalent of the -D option. + + For maximum speed, the following should be defined: + + TX_MAX_PRIORITIES 32 + TX_DISABLE_PREEMPTION_THRESHOLD + TX_DISABLE_REDUNDANT_CLEARING + TX_DISABLE_NOTIFY_CALLBACKS + TX_NOT_INTERRUPTABLE + TX_TIMER_PROCESS_IN_ISR + TX_REACTIVATE_INLINE + TX_DISABLE_STACK_FILLING + TX_INLINE_THREAD_RESUME_SUSPEND + + For minimum size, the following should be defined: + + TX_MAX_PRIORITIES 32 + TX_DISABLE_PREEMPTION_THRESHOLD + TX_DISABLE_REDUNDANT_CLEARING + TX_DISABLE_NOTIFY_CALLBACKS + TX_NOT_INTERRUPTABLE + TX_TIMER_PROCESS_IN_ISR + + Of course, many of these defines reduce functionality and/or change the behavior of the + system in ways that may not be worth the trade-off. For example, the TX_TIMER_PROCESS_IN_ISR + results in faster and smaller code, however, it increases the amount of processing in the ISR. + In addition, some services that are available in timers are not available from ISRs and will + therefore return an error if this option is used. This may or may not be desirable for a + given application. */ + + +/* Override various options with default values already assigned in tx_port.h. Please also refer + to tx_port.h for descriptions on each of these options. */ + +/* +#define TX_MAX_PRIORITIES 32 +#define TX_MINIMUM_STACK ???? +#define TX_THREAD_USER_EXTENSION ???? +#define TX_TIMER_THREAD_STACK_SIZE ???? +#define TX_TIMER_THREAD_PRIORITY ???? +*/ + +/* Determine if timer expirations (application timers, timeouts, and tx_thread_sleep calls + should be processed within the a system timer thread or directly in the timer ISR. + By default, the timer thread is used. When the following is defined, the timer expiration + processing is done directly from the timer ISR, thereby eliminating the timer thread control + block, stack, and context switching to activate it. */ + +/* +#define TX_TIMER_PROCESS_IN_ISR +*/ + +/* Determine if in-line timer reactivation should be used within the timer expiration processing. + By default, this is disabled and a function call is used. When the following is defined, + reactivating is performed in-line resulting in faster timer processing but slightly larger + code size. */ + +/* +#define TX_REACTIVATE_INLINE +*/ + +/* Determine is stack filling is enabled. By default, ThreadX stack filling is enabled, + which places an 0xEF pattern in each byte of each thread's stack. This is used by + debuggers with ThreadX-awareness and by the ThreadX run-time stack checking feature. */ + +/* +#define TX_DISABLE_STACK_FILLING +*/ + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +/* +#define TX_ENABLE_STACK_CHECKING +*/ + +/* Determine if preemption-threshold should be disabled. By default, preemption-threshold is + enabled. If the application does not use preemption-threshold, it may be disabled to reduce + code size and improve performance. */ + +/* +#define TX_DISABLE_PREEMPTION_THRESHOLD +*/ + +/* Determine if global ThreadX variables should be cleared. If the compiler startup code clears + the .bss section prior to ThreadX running, the define can be used to eliminate unnecessary + clearing of ThreadX global variables. */ + +/* +#define TX_DISABLE_REDUNDANT_CLEARING +*/ + +/* Determine if no timer processing is required. This option will help eliminate the timer + processing when not needed. The user will also have to comment out the call to + tx_timer_interrupt, which is typically made from assembly language in + tx_initialize_low_level. Note: if TX_NO_TIMER is used, the define TX_TIMER_PROCESS_IN_ISR + must also be used. */ + +/* +#define TX_NO_TIMER +#ifndef TX_TIMER_PROCESS_IN_ISR +#define TX_TIMER_PROCESS_IN_ISR +#endif +*/ + +/* Determine if the notify callback option should be disabled. By default, notify callbacks are + enabled. If the application does not use notify callbacks, they may be disabled to reduce + code size and improve performance. */ + +/* +#define TX_DISABLE_NOTIFY_CALLBACKS +*/ + + +/* Determine if the tx_thread_resume and tx_thread_suspend services should have their internal + code in-line. This results in a larger image, but improves the performance of the thread + resume and suspend services. */ + +/* +#define TX_INLINE_THREAD_RESUME_SUSPEND +*/ + + +/* Determine if the internal ThreadX code is non-interruptable. This results in smaller code + size and less processing overhead, but increases the interrupt lockout time. */ + +/* +#define TX_NOT_INTERRUPTABLE +*/ + + +/* Determine if the trace event logging code should be enabled. This causes slight increases in + code size and overhead, but provides the ability to generate system trace information which + is available for viewing in TraceX. */ + +/* +#define TX_ENABLE_EVENT_TRACE +*/ + + +/* Determine if block pool performance gathering is required by the application. When the following is + defined, ThreadX gathers various block pool performance information. */ + +/* +#define TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if byte pool performance gathering is required by the application. When the following is + defined, ThreadX gathers various byte pool performance information. */ + +/* +#define TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if event flags performance gathering is required by the application. When the following is + defined, ThreadX gathers various event flags performance information. */ + +/* +#define TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if mutex performance gathering is required by the application. When the following is + defined, ThreadX gathers various mutex performance information. */ + +/* +#define TX_MUTEX_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if queue performance gathering is required by the application. When the following is + defined, ThreadX gathers various queue performance information. */ + +/* +#define TX_QUEUE_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if semaphore performance gathering is required by the application. When the following is + defined, ThreadX gathers various semaphore performance information. */ + +/* +#define TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if thread performance gathering is required by the application. When the following is + defined, ThreadX gathers various thread performance information. */ + +/* +#define TX_THREAD_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if timer performance gathering is required by the application. When the following is + defined, ThreadX gathers various timer performance information. */ + +/* +#define TX_TIMER_ENABLE_PERFORMANCE_INFO +*/ + +#endif + diff --git a/ports/xtensa/xcc/inc/xtensa_api.h b/ports/xtensa/xcc/inc/xtensa_api.h new file mode 100644 index 00000000..10255838 --- /dev/null +++ b/ports/xtensa/xcc/inc/xtensa_api.h @@ -0,0 +1,125 @@ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/* Xtensa-specific API for RTOS ports. */ +/**************************************************************************/ + +#ifndef XTENSA_API_H +#define XTENSA_API_H + +#include <xtensa/hal.h> + +#include "xtensa_context.h" + + +/* Typedef for C-callable interrupt handler function */ +typedef void (*xt_handler)(void *); + +/* Typedef for C-callable exception handler function */ +typedef void (*xt_exc_handler)(XtExcFrame *); + + +/* +------------------------------------------------------------------------------- + Call this function to set a handler for the specified exception. + + n - Exception number (type) + f - Handler function address, NULL to uninstall handler. + + The handler will be passed a pointer to the exception frame, which is created + on the stack of the thread that caused the exception. + + If the handler returns, the thread context will be restored and the faulting + instruction will be retried. Any values in the exception frame that are + modified by the handler will be restored as part of the context. For details + of the exception frame structure see xtensa_context.h. +------------------------------------------------------------------------------- +*/ +extern xt_exc_handler xt_set_exception_handler(uint32_t n, xt_exc_handler f); + + +/* +------------------------------------------------------------------------------- + Call this function to set a handler for the specified interrupt. + + n - Interrupt number. + f - Handler function address, NULL to uninstall handler. + arg - Argument to be passed to handler. +------------------------------------------------------------------------------- +*/ +extern xt_handler xt_set_interrupt_handler(uint32_t n, xt_handler f, void * arg); + + +/* +------------------------------------------------------------------------------- + Call this function to enable the specified interrupt. + + intnum - Interrupt number to be enabled. + + Returns: Nothing. +------------------------------------------------------------------------------- +*/ +extern void xt_interrupt_enable(uint32_t intnum); + + +/* +------------------------------------------------------------------------------- + Call this function to disable the specified interrupt. + + intnum - Interrupt number to be disabled. + + Returns: Nothing. +------------------------------------------------------------------------------- +*/ +extern void xt_interrupt_disable(uint32_t intnum); + + +/* +------------------------------------------------------------------------------- + Call this function to trigger the specified (s/w) interrupt. + + intnum - Interrupt number to be triggered. + + Returns: Nothing. +------------------------------------------------------------------------------- +*/ +extern void xt_interrupt_trigger(uint32_t intnum); + + +/* +------------------------------------------------------------------------------- + Call this function to clear the specified (s/w or edge-triggered) + interrupt. + + intnum - Interrupt number to be cleared. + +Returns: Nothing. +------------------------------------------------------------------------------- +*/ +extern void xt_interrupt_clear(uint32_t intnum); + + +#endif /* XTENSA_API_H */ + diff --git a/ports/xtensa/xcc/inc/xtensa_context.h b/ports/xtensa/xcc/inc/xtensa_context.h new file mode 100644 index 00000000..c2f76afa --- /dev/null +++ b/ports/xtensa/xcc/inc/xtensa_context.h @@ -0,0 +1,561 @@ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/************************************************************************** + + XTENSA CONTEXT FRAMES AND MACROS FOR RTOS ASSEMBLER SOURCES + + This header contains definitions and macros for use primarily by Xtensa + RTOS assembly source files. It includes and uses the Xtensa hardware + abstraction layer (HAL) to deal with config specifics. It may also be + included in C source files. + + NOTE: The Xtensa architecture requires stack pointer alignment to 16 bytes. + +***************************************************************************/ + +#ifndef XTENSA_CONTEXT_H +#define XTENSA_CONTEXT_H + +#ifdef __ASSEMBLER__ +#include <xtensa/coreasm.h> +#endif + +#include <xtensa/config/tie.h> +#include <xtensa/corebits.h> +#include <xtensa/config/system.h> + +#if defined (__ASSEMBLER__) +#include "tx_api_asm.h" +#endif + + +/* Align a value up to nearest n-byte boundary, where n is a power of 2. */ +#define ALIGNUP(n, val) (((val) + (n)-1) & -(n)) + + +/* +------------------------------------------------------------------------------- + Macros that help define structures for both C and assembler. +------------------------------------------------------------------------------- +*/ +#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) + +#define XSTRUCT_BEGIN .pushsection .text; .struct 0 +#define XSTRUCT_FIELD(ctype,size,asname,name) asname: .space size +#define XSTRUCT_AFIELD(ctype,size,asname,name,n) asname: .space (size)*(n) +#define XSTRUCT_END(sname) sname##Size:; .popsection + +#else + +#define XSTRUCT_BEGIN typedef struct { +#define XSTRUCT_FIELD(ctype,size,asname,name) ctype name; +#define XSTRUCT_AFIELD(ctype,size,asname,name,n) ctype name[n]; +#define XSTRUCT_END(sname) } sname; + +#endif //_ASMLANGUAGE || __ASSEMBLER__ + + +/* +------------------------------------------------------------------------------- + INTERRUPT/EXCEPTION STACK FRAME FOR A THREAD OR NESTED INTERRUPT + + A stack frame of this structure is allocated for any interrupt or exception. + It goes on the current stack. If the RTOS has a system stack for handling + interrupts, every thread stack must allow space for just one interrupt stack + frame, then nested interrupt stack frames go on the system stack. + + The frame includes basic registers (explicit) and "extra" registers introduced + by user TIE or the use of the MAC16 option in the user's Xtensa config. + The frame size is minimized by omitting regs not applicable to user's config. + + For Windowed ABI, this stack frame includes the interruptee's base save area, + another base save area to manage gcc nested functions, and a little temporary + space to help manage the spilling of the register windows. +------------------------------------------------------------------------------- +*/ + +#if XCHAL_HAVE_XEA2 + +XSTRUCT_BEGIN +XSTRUCT_FIELD (long, 4, XT_STK_EXIT, exit) /* exit point for dispatch */ +XSTRUCT_FIELD (long, 4, XT_STK_PC, pc) /* return PC */ +XSTRUCT_FIELD (long, 4, XT_STK_PS, ps) /* return PS */ +XSTRUCT_FIELD (long, 4, XT_STK_A0, a0) +XSTRUCT_FIELD (long, 4, XT_STK_A1, a1) /* stack pointer before interrupt */ +XSTRUCT_FIELD (long, 4, XT_STK_A2, a2) +XSTRUCT_FIELD (long, 4, XT_STK_A3, a3) +XSTRUCT_FIELD (long, 4, XT_STK_A4, a4) +XSTRUCT_FIELD (long, 4, XT_STK_A5, a5) +XSTRUCT_FIELD (long, 4, XT_STK_A6, a6) +XSTRUCT_FIELD (long, 4, XT_STK_A7, a7) +XSTRUCT_FIELD (long, 4, XT_STK_A8, a8) +XSTRUCT_FIELD (long, 4, XT_STK_A9, a9) +XSTRUCT_FIELD (long, 4, XT_STK_A10, a10) +XSTRUCT_FIELD (long, 4, XT_STK_A11, a11) +XSTRUCT_FIELD (long, 4, XT_STK_A12, a12) +XSTRUCT_FIELD (long, 4, XT_STK_A13, a13) +XSTRUCT_FIELD (long, 4, XT_STK_A14, a14) +XSTRUCT_FIELD (long, 4, XT_STK_A15, a15) +XSTRUCT_FIELD (long, 4, XT_STK_SAR, sar) +XSTRUCT_FIELD (long, 4, XT_STK_EXCCAUSE, exccause) +XSTRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr) +#if XCHAL_HAVE_LOOPS +XSTRUCT_FIELD (long, 4, XT_STK_LBEG, lbeg) +XSTRUCT_FIELD (long, 4, XT_STK_LEND, lend) +XSTRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount) +#endif +#if XCHAL_HAVE_EXCLUSIVE +XSTRUCT_FIELD (long, 4, XT_STK_ATOMCTL, atomctl) +#endif +#ifndef __XTENSA_CALL0_ABI__ +/* Temporary space for saving stuff during window spill */ +XSTRUCT_FIELD (long, 4, XT_STK_TMP0, tmp0) +XSTRUCT_FIELD (long, 4, XT_STK_TMP1, tmp1) +XSTRUCT_FIELD (long, 4, XT_STK_TMP2, tmp2) +#endif +#ifdef XT_USE_SWPRI +/* Storage for virtual priority mask */ +XSTRUCT_FIELD (long, 4, XT_STK_VPRI, vpri) +#endif +#ifdef XT_USE_OVLY +/* Storage for overlay state */ +XSTRUCT_FIELD (long, 4, XT_STK_OVLY, ovly) +#endif +XSTRUCT_END(XtExcFrame) + +#endif /* XCHAL_HAVE_XEA2 */ + +#if XCHAL_HAVE_XEA3 + +XSTRUCT_BEGIN +XSTRUCT_FIELD (long, 4, XT_STK_ATOMCTL, atomctl) +XSTRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount) +XSTRUCT_FIELD (long, 4, XT_STK_LEND, lend) +XSTRUCT_FIELD (long, 4, XT_STK_LBEG, lbeg) +XSTRUCT_FIELD (long, 4, XT_STK_PC, pc) +XSTRUCT_FIELD (long, 4, XT_STK_PS, ps) +XSTRUCT_FIELD (long, 4, XT_STK_EXCCAUSE, exccause) +XSTRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr) +#ifdef __XTENSA_CALL0_ABI__ +XSTRUCT_FIELD (long, 4, XT_STK_A0, a0) +XSTRUCT_FIELD (long, 4, XT_STK_A1, a1) +XSTRUCT_FIELD (long, 4, XT_STK_A2, a2) +XSTRUCT_FIELD (long, 4, XT_STK_A3, a3) +XSTRUCT_FIELD (long, 4, XT_STK_A4, a4) +XSTRUCT_FIELD (long, 4, XT_STK_A5, a5) +XSTRUCT_FIELD (long, 4, XT_STK_A6, a6) +XSTRUCT_FIELD (long, 4, XT_STK_A7, a7) +#endif +XSTRUCT_FIELD (long, 4, XT_STK_A8, a8) +XSTRUCT_FIELD (long, 4, XT_STK_A9, a9) +XSTRUCT_FIELD (long, 4, XT_STK_A10, a10) +XSTRUCT_FIELD (long, 4, XT_STK_A11, a11) +XSTRUCT_FIELD (long, 4, XT_STK_A12, a12) +XSTRUCT_FIELD (long, 4, XT_STK_A13, a13) +XSTRUCT_FIELD (long, 4, XT_STK_A14, a14) +XSTRUCT_FIELD (long, 4, XT_STK_A15, a15) +#ifdef __XTENSA_WINDOWED_ABI__ +XSTRUCT_AFIELD(long, 4, XT_STK_SPILL, spill, 8) +#endif +XSTRUCT_END(XtExcFrame) + +#endif /* XCHAL_HAVE_XEA3 */ + +#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) +#define XT_STK_NEXT1 XtExcFrameSize +#else +#define XT_STK_NEXT1 sizeof(XtExcFrame) +#endif + + +/* Allocate extra storage if needed for non-CP TIE state. Allow for alignment + padding as needed. + */ +#if XCHAL_EXTRA_SA_SIZE != 0 + +#if XCHAL_EXTRA_SA_ALIGN <= 16 +#define XT_STK_EXTRA ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1) +#else +/* If need more alignment than stack, add space for dynamic alignment */ +#define XT_STK_EXTRA (ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1) + XCHAL_EXTRA_SA_ALIGN) +#endif +#define XT_STK_NEXT2 (XT_STK_EXTRA + XCHAL_EXTRA_SA_SIZE) + +#else + +/* No extra storage required */ +#define XT_STK_NEXT2 XT_STK_NEXT1 + +#endif + + +#if XCHAL_HAVE_XEA3 + +/* Total frame size */ +#define XT_STK_FRMSZ (ALIGNUP(0x10, XT_STK_NEXT2)) + +/* Exception/interrupt frame size */ +#define XT_STK_XFRM_SZ XT_STK_NEXT1 + +/* Extra save area size (including alignment padding) */ +#define XT_STK_XTRA_SZ (XT_STK_FRMSZ - XT_STK_XFRM_SZ) + +/* Alignment padding area size */ +#if XCHAL_EXTRA_SA_SIZE != 0 +#define XT_STK_ALIGN_SZ (XT_STK_EXTRA - XT_STK_NEXT1) +#endif + +#else + +/* +------------------------------------------------------------------------------- + This is the frame size. Add space for 4 registers (interruptee's base save + area) and some space for gcc nested functions if any. +------------------------------------------------------------------------------- +*/ +#define XT_STK_FRMSZ (ALIGNUP(0x10, XT_STK_NEXT2) + 0x20) + +#endif + +/* +------------------------------------------------------------------------------- + CO-PROCESSOR STATE SAVE AREA FOR A THREAD + + The RTOS must provide an area per thread to save the state of co-processors + when that thread does not have control. Co-processors are context-switched + lazily (on demand) only when a new thread uses a co-processor instruction, + otherwise a thread retains ownership of the co-processor even when it loses + control of the processor. An Xtensa co-processor exception is triggered when + any co-processor instruction is executed by a thread that is not the owner, + and the context switch of that co-processor is then peformed by the handler. + Ownership represents which thread's state is currently in the co-processor. + + Co-processors may not be used by interrupt or exception handlers. If an + co-processor instruction is executed by an interrupt or exception handler, + the co-processor exception handler will trigger a kernel panic and freeze. + This restriction is introduced to reduce the overhead of saving and restoring + co-processor state (which can be quite large) and in particular remove that + overhead from interrupt handlers. + + The co-processor state save area may be in any convenient per-thread location + such as in the thread control block or above the thread stack area. It need + not be in the interrupt stack frame since interrupts don't use co-processors. + + Along with the save area for each co-processor, two bitmasks with flags per + co-processor (laid out as in the CPENABLE reg) help manage context-switching + co-processors as efficiently as possible: + + XT_CPENABLE + The contents of a non-running thread's CPENABLE register. + It represents the co-processors owned (and whose state is still needed) + by the thread. When a thread is preempted, its CPENABLE is saved here. + When a thread solicits a context-swtich, its CPENABLE is cleared - the + compiler has saved the (caller-saved) co-proc state if it needs to. + When a non-running thread loses ownership of a CP, its bit is cleared. + When a thread runs, it's XT_CPENABLE is loaded into the CPENABLE reg. + Avoids co-processor exceptions when no change of ownership is needed. + + XT_CPSTORED + A bitmask with the same layout as CPENABLE, a bit per co-processor. + Indicates whether the state of each co-processor is saved in the state + save area. When a thread enters the kernel, only the state of co-procs + still enabled in CPENABLE is saved. When the co-processor exception + handler assigns ownership of a co-processor to a thread, it restores + the saved state only if this bit is set, and clears this bit. + + XT_CP_CS_ST + A bitmask with the same layout as CPENABLE, a bit per co-processor. + Indicates whether callee-saved state is saved in the state save area. + Callee-saved state is saved by itself on a solicited context switch, + and restored when needed by the coprocessor exception handler. + Unsolicited switches will cause the entire coprocessor to be saved + when necessary. + + XT_CP_ASA + Pointer to the aligned save area. Allows it to be aligned more than + the overall save area (which might only be stack-aligned or TCB-aligned). + Especially relevant for Xtensa cores configured with a very large data + path that requires alignment greater than 16 bytes (ABI stack alignment). +------------------------------------------------------------------------------- +*/ + +#if XCHAL_CP_NUM > 0 + +/* Offsets of each coprocessor save area within the 'aligned save area': */ +#define XT_CP0_SA 0 +#define XT_CP1_SA ALIGNUP(XCHAL_CP1_SA_ALIGN, XT_CP0_SA + XCHAL_CP0_SA_SIZE) +#define XT_CP2_SA ALIGNUP(XCHAL_CP2_SA_ALIGN, XT_CP1_SA + XCHAL_CP1_SA_SIZE) +#define XT_CP3_SA ALIGNUP(XCHAL_CP3_SA_ALIGN, XT_CP2_SA + XCHAL_CP2_SA_SIZE) +#define XT_CP4_SA ALIGNUP(XCHAL_CP4_SA_ALIGN, XT_CP3_SA + XCHAL_CP3_SA_SIZE) +#define XT_CP5_SA ALIGNUP(XCHAL_CP5_SA_ALIGN, XT_CP4_SA + XCHAL_CP4_SA_SIZE) +#define XT_CP6_SA ALIGNUP(XCHAL_CP6_SA_ALIGN, XT_CP5_SA + XCHAL_CP5_SA_SIZE) +#define XT_CP7_SA ALIGNUP(XCHAL_CP7_SA_ALIGN, XT_CP6_SA + XCHAL_CP6_SA_SIZE) +#define XT_CP_SA_SIZE ALIGNUP(16, XT_CP7_SA + XCHAL_CP7_SA_SIZE) + +/* Offsets within the overall save area: */ +#define XT_CPENABLE 0 /* (2 bytes) coprocessors active for this thread */ +#define XT_CPSTORED 2 /* (2 bytes) coprocessors saved for this thread */ +#define XT_CP_CS_ST 4 /* (2 bytes) coprocessor callee-saved regs stored for this thread */ +#define XT_CP_ASA 8 /* (4 bytes) ptr to aligned save area */ +/* Overall size allows for dynamic alignment: */ +#define XT_CP_SIZE (12 + XT_CP_SA_SIZE + XCHAL_TOTAL_SA_ALIGN) +#else +#define XT_CP_SIZE 0 +#endif + + +/* +------------------------------------------------------------------------------- + MACROS TO HANDLE ABI SPECIFICS OF FUNCTION ENTRY AND RETURN + + Convenient where the frame size requirements are the same for both ABIs. + ENTRY(sz), RET(sz) are for framed functions (have locals or make calls). + ENTRY0, RET0 are for frameless functions (no locals, no calls). + + where size = size of stack frame in bytes (must be >0 and aligned to 16). + For framed functions the frame is created and the return address saved at + base of frame (Call0 ABI) or as determined by hardware (Windowed ABI). + For frameless functions, there is no frame and return address remains in a0. + Note: Because CPP macros expand to a single line, macros requiring multi-line + expansions are implemented as assembler macros. +------------------------------------------------------------------------------- +*/ + +#ifdef __ASSEMBLER__ +#ifdef __XTENSA_CALL0_ABI__ + /* Call0 */ + #define ENTRY(sz) entry1 sz + .macro entry1 size=0x10 + addi sp, sp, -\size + s32i a0, sp, 0 + .endm + #define ENTRY0 + #define RET(sz) ret1 sz + .macro ret1 size=0x10 + l32i a0, sp, 0 + addi sp, sp, \size + ret + .endm + #define RET0 ret +#else + /* Windowed */ +#if XCHAL_HAVE_XEA3 + #define ENTRY(sz) entry sp, (sz + 0x20) + #define ENTRY0 entry sp, 0x20 +#else + #define ENTRY(sz) entry sp, (sz + 0x10) + #define ENTRY0 entry sp, 0x10 +#endif + #define RET(sz) retw + #define RET0 retw +#endif +#endif + + +/* +------------------------------------------------------------------------------- + This flag is meant for internal use. Have all interrupts be dispatched via a + common wrapper, which takes care of doing some OS-specific stuff common to + all interrupt handlers. Said stuff cannot safely be handled in the RTOS_ENTER + and RTOS_EXIT macros. +------------------------------------------------------------------------------- +*/ +#if (defined TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || (defined XT_INTEXC_HOOKS) +#define XT_USE_INT_WRAPPER 1 +#else +#define XT_USE_INT_WRAPPER 0 +#endif + +#if XCHAL_HAVE_XEA3 +#ifdef XT_USE_SWPRI +//#warning "Software prioritization of interrupts (XT_USE_SWPRI) not supported for XEA3." +#endif + +#ifdef __ASSEMBLER__ + + // RTOS-specific entry macro. Use only a8, a12-a14. + + .macro XT_RTOS_INT_ENTER + + .endm + + // RTOS-specific exit macro. Use only a8-a14. + // (In call0, a15 holds user SP, must be preserved) + + .macro XT_RTOS_INT_EXIT + + // Check nesting count and branch on nest state. + movi a8, _tx_thread_system_state + movi a9, _tx_thread_execute_ptr // a9 <- &_tx_thread_execute_ptr (new) + movi a10, _tx_thread_preempt_disable // a10 <- &_tx_thread_preempt_disable + l32i a8, a8, 0 + bnez a8, .Lnested // state != 0 means nested + + movi a8, _tx_thread_current_ptr // a8 <- &_tx_thread_current_ptr (old) + l32i a9, a9, 0 // a9 <- _tx_thread_execute_ptr + l32i a11, a8, 0 // a11 <- _tx_thread_current_ptr + beqz a11, .Lsched // no old thread, go to scheduler + l32i a10, a10, 0 // a10 <- _tx_thread_preempt_disable + beq a11, a9, .Lnested // no change, restore current thread + bgei a10, 1, .Lnested // no preemption, restore current thread + + // Preemption, save remaining state of current (outgoing) thread + + movi a12, _tx_timer_time_slice // a12 <- &_tx_timer_time_slice + addi a10, a1, -XT_STK_FRMSZ + s32i a10, a11, tx_thread_stack_ptr // save outgoing thread stack pointer + l32i a10, a12, 0 // a10 <- _tx_timer_time_slice + s32i a10, a11, tx_thread_time_slice // save outgoing time slice value + movi a10, 0 + s32i a10, a12, 0 // disable time slice + s32i a10, a11, tx_thread_solicited // mark as preempted + s32i a10, a8, 0 // Clear _tx_thread_current_ptr +#if XCHAL_CP_NUM > 0 + rsr a12, CPENABLE // Save and clear CPENABLE + s16i a12, a11, tx_thread_cp_state + XT_CPENABLE + wsr a10, CPENABLE +#endif + + // Save non-CP TIE state if any +#if XCHAL_EXTRA_SA_SIZE > 0 + addi a10, a1, -XT_STK_FRMSZ + XT_STK_ALIGN_SZ // where to save +#if XCHAL_EXTRA_SA_ALIGN > 16 + movi a12, -XCHAL_EXTRA_SA_ALIGN + and a10, a10, a12 // align dynamically >16 bytes +#endif + xchal_ncp_store a10, a11, a12, a13, a14 +#endif + + // If windowed ABI, a0-a7 was not saved by dispatch code. + // These don't go into the exception frame, but below the + // exception frame pointer. + +#ifdef __XTENSA_WINDOWED_ABI__ + addi a10, a1, -XT_STK_FRMSZ -32 + s32i a0, a10, 0 + s32i a2, a10, 8 + s32i a3, a10, 12 + s32i a4, a10, 16 + s32i a5, a10, 20 + s32i a6, a10, 24 + s32i a7, a10, 28 +#endif + +.Lsched: + // When we get here, interrupts are disabled, a8 = &_tx_thread_current_ptr, + // a9 = _tx_thread_execute_ptr + movi a9, _tx_thread_execute_ptr // a9 <- &_tx_thread_execute_ptr (new) + l32i a9, a9, 0 // a9 <- _tx_thread_execute_ptr + s32i a9, a8, 0 // _tx_thread_current_ptr = _tx_thread_execute_ptr + beqz a9, _xt_idle // go idle if _tx_thread_execute_ptr == 0 + l32i a10, a9, tx_thread_run_count + l32i a11, a9, tx_thread_time_slice + movi a12, _tx_timer_time_slice + addi a10, a10, 1 + s32i a10, a9, tx_thread_run_count + s32i a11, a12, 0 // _tx_timer_time_slice = _tx_thread_current_ptr->tx_thread_time_slice + +#ifdef TX_THREAD_SAFE_CLIB + #if XSHAL_CLIB == XTHAL_CLIB_NEWLIB + movi a10, _impure_ptr + #elif XSHAL_CLIB == XTHAL_CLIB_XCLIB + movi a10, _reent_ptr + #else + #error TX_THREAD_SAFE_CLIB defined with unsupported C library. + #endif + l32i a11, a9, tx_thread_clib_ptr + s32i a11, a10, 0 +#endif + +#if XCHAL_CP_NUM > 0 + l16ui a10, a9, tx_thread_cp_state + XT_CPENABLE + wsr a10, CPENABLE // restore CPENABLE +#endif + + l32i a1, a9, tx_thread_stack_ptr // SP = _tx_thread_execute_ptr->tx_thread_stack_ptr + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + // Call the thread entry function to indicate the thread is executing. + // SP should be pointing to a safe region at this point. +#ifdef __XTENSA_CALL0_ABI__ + call0 _tx_execution_thread_enter +#else + call8 _tx_execution_thread_enter +#endif +#endif + + l32i a2, a9, tx_thread_solicited // a2 = solicited flag + beqz a2, 1f + + // Solicited restore + addi a1, a1, XT_STK_FRMSZ // restore original SP + addi a2, a1, -XT_STK_XFRM_SZ + l32i a3, a2, XT_STK_PC // a3 = return PC + + movi a2, PS_DI + xps a2, a2 // disable interrupts + movi a2, 0 + wsr.ms a2 // restore normal DISPST + rsync + jx a3 // return to yield point + +1: + // Preempt restore +#if XCHAL_EXTRA_SA_SIZE > 0 + addi a10, a1, XT_STK_ALIGN_SZ // where to restore from +#if XCHAL_EXTRA_SA_ALIGN > 16 + movi a12, -XCHAL_EXTRA_SA_ALIGN + and a10, a10, a12 // align dynamically >16 bytes +#endif + xchal_ncp_load a10, a11, a12, a13, a14 +#endif + +#ifdef __XTENSA_WINDOWED_ABI__ + // Restore a0-a7 for windowed ABI + addi a8, a1, -32 + l32i a0, a8, 0 + l32i a2, a8, 8 + l32i a3, a8, 12 + l32i a4, a8, 16 + l32i a5, a8, 20 + l32i a6, a8, 24 + l32i a7, a8, 28 +#else + // For call0, dispatch exit code expects a15 = original SP + addi a15, a1, XT_STK_FRMSZ +#endif + + addi a1, a1, XT_STK_FRMSZ // set up SP for dispatch exit + +.Lnested: + // Return to the current saved context. + + .endm + +#endif /* __ASSEMBLER__ */ +#endif /* XCHAL_HAVE_XEA3 */ + +#endif /* XTENSA_CONTEXT_H */ + diff --git a/ports/xtensa/xcc/inc/xtensa_rtos.h b/ports/xtensa/xcc/inc/xtensa_rtos.h new file mode 100644 index 00000000..03db1849 --- /dev/null +++ b/ports/xtensa/xcc/inc/xtensa_rtos.h @@ -0,0 +1,204 @@ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/************************************************************************** + + RTOS-SPECIFIC INFORMATION FOR XTENSA RTOS ASSEMBLER SOURCES + + This header is the primary glue between generic Xtensa RTOS support + sources and a specific RTOS port for Xtensa. It contains definitions + and macros for use primarily by Xtensa assembly coded source files. + + Macros in this header map callouts from generic Xtensa files to specific + RTOS functions. It may also be included in C source files. + + Xtensa RTOS ports support all RTOS-compatible configurations of the Xtensa + architecture, using the Xtensa hardware abstraction layer (HAL) to deal + with configuration specifics. + + Should be included by all Xtensa generic and RTOS port-specific sources. + +***************************************************************************/ + +#ifndef XTENSA_RTOS_H +#define XTENSA_RTOS_H + +#ifdef __ASSEMBLER__ +#include <xtensa/coreasm.h> +#else +#include <stdint.h> +#include <xtensa/config/core.h> +#endif + +#include <xtensa/corebits.h> +#include <xtensa/config/system.h> +#include <xtensa/simcall.h> + +/* +Include any RTOS specific definitions that are needed by this header. +*/ +#include "tx_user.h" + +/* +Name of RTOS (for messages). +*/ +#define XT_RTOS_NAME ThreadX + +/* +Check some Xtensa configuration requirements and report error if not met. +Error messages can be customize to the RTOS port. +*/ + +#if !XCHAL_HAVE_XEA2 && !XCHAL_HAVE_XEA3 +#error "ThreadX/Xtensa requires Xtensa Exception Architecture v2 (XEA2) or higher." +#endif + + +/*************************************************************************** + +RTOS CALLOUT MACROS MAPPED TO RTOS PORT-SPECIFIC FUNCTIONS. + +Define callout macros used in generic Xtensa code to interact with the RTOS. +The macros are simply the function names for use in calls from assembler code. +Some of these functions may call back to generic functions in xtensa_context.h . + +***************************************************************************/ + +/* +Inform RTOS of entry into an interrupt handler that will affect it. +Allows RTOS to manage switch to any system stack and count nesting level. +Called after minimal context has been saved, with interrupts disabled. +RTOS port can call0 _xt_context_save to save the rest of the context. +May only be called from assembly code by the 'call0' instruction. +*/ +// void XT_RTOS_INT_ENTER(void) +#define XT_RTOS_INT_ENTER _tx_thread_context_save + +/* +Inform RTOS of completion of an interrupt handler, and give control to +RTOS to perform thread/task scheduling, switch back from any system stack +and restore the context, and return to the exit dispatcher saved in the +stack frame at XT_STK_EXIT. RTOS port can call0 _xt_context_restore +to save the context saved in XT_RTOS_INT_ENTER via _xt_context_save, +leaving only a minimal part of the context to be restored by the exit +dispatcher. This function does not return to the place it was called from. +May only be called from assembly code by the 'call0' instruction. +*/ +// void XT_RTOS_INT_EXIT(void) +#define XT_RTOS_INT_EXIT _tx_thread_context_restore + +/* +Convenience macros to disable and enable interrupts. +*/ +#if XCHAL_HAVE_XEA3 +#define XT_INTS_DISABLE(reg) movi reg, PS_DI; xps reg, reg +#define XT_INTS_ENABLE(reg) wsr reg, PS; rsync +#else +#define XT_INTS_DISABLE(reg) rsil reg, XCHAL_EXCM_LEVEL +#define XT_INTS_ENABLE(reg) wsr reg, PS; rsync +#endif + +/* +Inform RTOS of the occurrence of a tick timer interrupt. +If RTOS has no tick timer, leave XT_RTOS_TIMER_INT undefined. +May be coded in or called from C or assembly, per ABI conventions. +*/ +#ifndef TX_NO_TIMER +// void XT_RTOS_TIMER_INT(void) +#define XT_RTOS_TIMER_INT _tx_timer_interrupt +#endif + +/* +Return in a15 the base address of the co-processor state save area for the +thread that triggered a co-processor exception, or 0 if no thread was running. +The state save area is structured as defined in xtensa_context.h and has size +XT_CP_SIZE. Co-processor instructions should only be used in thread code, never +in interrupt handlers or the RTOS kernel. May only be called from assembly code +and by the 'call0' instruction. A result of 0 indicates an unrecoverable error. +The implementation may use only a2-4, a15 (all other regs must be preserved). +*/ +// void* XT_RTOS_CP_STATE(void) +#define XT_RTOS_CP_STATE _tx_thread_coproc_state + + +/*************************************************************************** + +HOOKS TO DYNAMICALLY INSTALL INTERRUPT AND EXCEPTION HANDLERS PER LEVEL. + +This Xtensa RTOS port provides hooks for dynamically installing exception +and interrupt handlers to facilitate automated testing where each test +case can install its own handler for user exceptions and each interrupt +priority (level). This consists of an array of function pointers indexed +by interrupt priority, with index 0 being the user exception handler hook. +Each entry in the array is initially 0, and may be replaced by a function +pointer of type XT_INTEXC_HOOK. A handler may be uninstalled by installing 0. + +The handler for low and medium priority obeys ABI conventions so may be coded +in C. For the exception handler, the cause is the contents of the EXCCAUSE +reg, and the result is -1 if handled, else the cause (still needs handling). +For interrupt handlers, the cause is a mask of pending enabled interrupts at +that level, and the result is the same mask with the bits for the handled +interrupts cleared (those not cleared still need handling). This allows a test +case to either pre-handle or override the default handling for the exception +or interrupt level (see xtensa_vectors.S). + +High priority handlers (including NMI) must be coded in assembly, are always +called by 'call0' regardless of ABI, must preserve all registers except a0, +and must not use or modify the interrupted stack. The hook argument 'cause' +is not passed and the result is ignored, so as not to burden the caller with +saving and restoring a2 (it assumes only one interrupt per level - see the +discussion in high priority interrupts in xtensa_vectors.S). The handler +therefore should be coded to prototype 'void h(void)' even though it plugs +into an array of handlers of prototype 'uint32_t h(uint32_t)'. + +To enable interrupt/exception hooks, compile the RTOS with '-DXT_INTEXC_HOOKS'. + +***************************************************************************/ + +#define XT_INTEXC_HOOK_NUM (1 + XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI) + +#ifndef __ASSEMBLER__ +typedef uint32_t (*XT_INTEXC_HOOK)(uint32_t cause); +extern volatile XT_INTEXC_HOOK _xt_intexc_hooks[XT_INTEXC_HOOK_NUM]; +#endif + + +/*************************************************************************** + +CONVENIENCE INCLUSIONS. + +Ensures RTOS specific files need only include this one Xtensa-generic header. +These headers are included last so they can use the RTOS definitions above. + +***************************************************************************/ + +#include "xtensa_context.h" + +#ifdef XT_RTOS_TIMER_INT +#include "xtensa_timer.h" +#endif + + +#endif /* XTENSA_RTOS_H */ + diff --git a/ports/xtensa/xcc/inc/xtensa_timer.h b/ports/xtensa/xcc/inc/xtensa_timer.h new file mode 100644 index 00000000..d5a29ed5 --- /dev/null +++ b/ports/xtensa/xcc/inc/xtensa_timer.h @@ -0,0 +1,157 @@ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/************************************************************************** + XTENSA INFORMATION FOR RTOS TICK TIMER AND CLOCK FREQUENCY + + This header contains timer related definitions and macros for use by + Xtensa RTOS source files. It includes and uses the Xtensa hardware + abstraction layer (HAL) to deal with config specifics. + + If the RTOS has no timer interrupt, then there is no tick timer and the + clock frequency is irrelevant, so all of these macros are left undefined + and the Xtensa core configuration need not have a timer. +***************************************************************************/ + +#ifndef XTENSA_TIMER_H +#define XTENSA_TIMER_H + +#include "xtensa_rtos.h" /* in case this wasn't included directly */ + +#ifdef XT_RTOS_TIMER_INT /* skip all this stuff if no timer int */ + +#ifdef __ASSEMBLER__ +#include <xtensa/coreasm.h> +#else +#include <xtensa/tie/xt_timer.h> +#endif + +#include <xtensa/corebits.h> +#include <xtensa/config/system.h> + + +#if XCHAL_HAVE_XEA3 + +/* +If the user has not specified a timer by defining XT_TIMER_INDEX, then +select timer 0. +*/ +#ifndef XT_TIMER_INDEX +#define XT_TIMER_INDEX 0 +#endif + +#else /* XEA2 */ + +/* +Select timer to use for periodic tick, and determine its interrupt number +and priority. User may specify a timer by defining XT_TIMER_INDEX with -D, +in which case its validity is checked (it must exist in this core and must +not be on a high priority interrupt - an error will be reported in invalid). +Otherwise select the first low or medium priority interrupt timer available. +*/ +#ifndef XT_TIMER_INDEX + #if XCHAL_TIMER3_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER3_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 3 + #endif + #endif + #if XCHAL_TIMER2_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 2 + #endif + #endif + #if XCHAL_TIMER1_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 1 + #endif + #endif + #if XCHAL_TIMER0_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 0 + #endif + #endif +#endif + +#endif /* XCHAL_HAVE_XEA3 */ + +#ifndef XT_TIMER_INDEX + #error "There is no suitable timer in this Xtensa configuration." +#endif + +#define XT_CCOMPARE (CCOMPARE + XT_TIMER_INDEX) +#define XT_TIMER_INTNUM XCHAL_TIMER_INTERRUPT(XT_TIMER_INDEX) +#define XT_TIMER_INTPRI XCHAL_INT_LEVEL(XT_TIMER_INTNUM) + +#if XCHAL_HAVE_XEA2 +#define XT_TIMER_INTEN (1 << XT_TIMER_INTNUM) +#endif + +#if XT_TIMER_INDEX == 0 +#define XT_WSR_CCOMPARE XT_WSR_CCOMPARE0 +#elif XT_TIMER_INDEX == 1 +#define XT_WSR_CCOMPARE XT_WSR_CCOMPARE1 +#elif XT_TIMER_INDEX == 2 +#define XT_WSR_CCOMPARE XT_WSR_CCOMPARE2 +#endif + +#if XT_TIMER_INTNUM == XTHAL_TIMER_UNCONFIGURED + #error "The timer selected by XT_TIMER_INDEX does not exist in this core." +#elif !XCHAL_HAVE_XEA3 && (XT_TIMER_INTPRI > XCHAL_EXCM_LEVEL) + #error "The timer interrupt cannot be high priority (use medium or low)." +#endif + +/* +Default number of timer ticks per second. This can be redefined as required +either by editing here or by overriding from the command line during build. +*/ +#ifndef XT_TICK_PER_SEC +#define XT_TICK_PER_SEC 100 +#endif + +/* +Set processor clock frequency and determine clock divisor for timer tick. +If using a supported board via the board-independent API defined in xtbsp.h, +this may be left undefined but XT_BOARD must be defined. The frequency and +tick divisor will be computed during run-time initialization. +*/ +#ifndef XT_BOARD +#ifndef XT_CLOCK_FREQ +#define XT_CLOCK_FREQ 1000000 +#endif +#define XT_TICK_DIVISOR (XT_CLOCK_FREQ / XT_TICK_PER_SEC) +#else +#ifndef __ASSEMBLER__ +extern uint32_t xt_tick_divisor; +extern void xt_tick_divisor_init(void); +#endif +#define XT_TICK_DIVISOR xt_tick_divisor +#endif /* XT_BOARD */ + +#endif /* XT_RTOS_TIMER_INT */ +#endif /* XTENSA_TIMER_H */ + diff --git a/ports/xtensa/xcc/readme_threadx.txt b/ports/xtensa/xcc/readme_threadx.txt new file mode 100644 index 00000000..90fc92d7 --- /dev/null +++ b/ports/xtensa/xcc/readme_threadx.txt @@ -0,0 +1,1015 @@ + Microsoft's ThreadX for Xtensa Configurable Processors + + Using the Xtensa Tools + +1. Xtensa Configuration Requirements and Restrictions + +The Xtensa configurable architecture supports a vast space of processor +features. This port of ThreadX to the Xtensa architecture is based on +a Cadence Design Systems RTOS porting layer that takes care of Xtensa specifics +that are common to most embedded real-time operating systems. It supports all +Xtensa features (including context-switching custom processor extensions +defined in the TIE language) with certain minimum requirements. You +must use Xtensa Tools to compile and link ThreadX for your particular +configuration. ThreadX uses the Xtensa Hardware Abstraction Layer (HAL) +to adapt your ThreadX compilation to your particular Xtensa processor +configuration. ThreadX also provides optional thread-safe support for +the Xtensa C library and the newlib C library distributed with Xtensa Tools +(for use in threads only, not in interrupt handlers). + +ThreadX for Xtensa configurable processors requires the following minimum +processor configuration options: +- Timer interrupt option with at least one interruptible timer for ThreadX. +- Interrupt option (implied by the timer interrupt option). +- Xtensa Exception Architecture 2 (XEA2) or Exception Architecture 3 (XEA3). + Please note that XEA1 is NOT supported. + +Minimal support for certain evaluation boards is provided via a board +independent "XTBSP" API implemented by a board specific library. This +provides the board clock frequency and basic polled drivers for the display +and console I/O device (usually a UART), and ThreadX can be built to +take advantage of these (note: it is not specific to ThreadX and is not a +traditional RTOS "board support package" with RTOS specific interrupt-driven +drivers). Note that ThreadX can run on any Xtensa board without +this board support (a "raw" platform), but you will have to provide the +clock frequency and drivers for any on-board devices you want to use. + + +2. Building the ThreadX run-time Library + +By default, you will build for the Xtensa instruction set simulator. If +you have a supported emulation board, you can build to run on that. You +can also build to run on a raw Xtensa core with no "board support", a +good starting point for supporting your own target platform. Cadence Design Systems +recommends doing functional development on the simulator because it +is easier to debug with, then move to a board if/when you need to test +hardware drivers or real-time performance. + +ThreadX/Xtensa comes with a Makefile as well as DOS .bat file, taking +advantage of xt-make, a version of GNU make that comes with Xtensa Tools +(you can just as well use generic GNU make if you have it installed). +The Makefile works on any host platform and provides for incremental builds. +The .bat file works on DOS/Windows only and always cleans before building. +The build for each target platform is placed in a sub-directory so several +platform builds can coexist even with incremental rebuilds. + +First, make sure you have installed Xtensa Tools and your processor +configuration, and be sure that Xtensa Tools are in your search path. + +If you wish to build for an evaluation board that is supported by an +external package, be sure the appropriate package is installed. See the +introduction (section 0) to determine if you need an external package. +If you are using an external board package, set the environment variable +XTENSA_BOARDS to the absolute path of the root of the installed support +package (or you can pass this to xt-make commands on the command line). +eg. XTENSA_BOARDS = C:\usr\xtensa\RB-2007.1-xtav60 for Avnet LX60 board. +You do not need to set XTENSA_BOARDS if using a Cadence Design Systems supported +board with Xtensa Tools RB-2007.2 and up (support is bundled with the tools). + +Next, change directories to the ThreadX installation directory, as follows: + +> cd c:\threadx\xtensa\gnu + +Now build the ThreadX library (tx.a) by executing the build_threadx.bat +batch file (or using the Makefile directly) while inside the threadx +directory, as follows: + +> build_threadx.bat + +which always builds for the simulator (but you can edit it), or + +> xt-make + +which by default builds for the simulator (PLATFORM=sim), or either of + +> xt-make PLATFORM=board BOARD=<board> +or +> xt-make BOARD=<board> + +which builds for a specified supported board (note PLATFORM=board is +default when BOARD is defined). eg. BOARD=xtav60 for the Avnet LX60 +(XT-AV60) board. + +> xt-make PLATFORM=raw + +which builds for a raw Xtensa core with no "board support". + +> xt-make PLATFORM=gdbio + +Provides some very slow I/O support through the xt-gdb debugger. +For GDBIO to work, xt-gdb must remain connected to the target. + +If you are building for an Xtensa processor configuration that is not the +default you selected when you installed Xtensa Tools, you need to define the +environment variable XTENSA_CORE. If your configuration is not in the +default registry you selected when you installed Xtensa Tools, you also +need to define the environment variable XTENSA_SYSTEM. See tools manuals. +You can avoid defining these in your environment if you pass the variables +you need to redefine into xt-make as follows: + +> xt-make XTENSA_CORE=<your_config_name> XTENSA_SYSTEM=<your_registry> ... + +There are more details about build options in the comment in the Makefile. + +At this point, all the ThreadX objects are located in a library file: tx.a . +This file must be linked with your application in order to use ThreadX. +This library and all the intermediate object files are placed in a platform +specific sub-directory named the same as BOARD or PLATFORM (if BOARD is not +defined), for example "sim", "xtkc705". + +To build ThreadX with thread-safe C library support, define TX_THREAD_SAFE_CLIB +in your build, as described in section 5 and in the Makefile. Please note +that the C library is only safe for use in threads, not in interrupt handlers. +It may also safely be used in tx_application_define (after tx_kernel_enter, +before threads are running). + + +3. Demonstration System + +The ThreadX demonstration is designed to execute under Xtensa instruction set +simulator (ISS) or on a supported evaluation board programmed with your Xtensa +processor configuration. + +Building the demonstration is easy, simply execute the build_threadx_demo.bat +batch file while inside threadx directory, as follows: + +> build_threadx_demo.bat + +or + +> xt-make demo + +Be sure to set or pass into xt-make the variables described in section 2 above +for building the ThreadX library, including the PLATFORM or BOARD you want to +run on. + +This compiles demo_threadx.c (which is the demonstration application) and links +it with the ThreadX objects in tx.a. The resulting file demo_threadx.out is a +ELF binary file that can be downloaded and executed on the target. + +The demo binary appears in the platform specific sub-directory described earlier. +For the following commands, change to that directory or prepend it as the path +of demo_threadx.out. + + +To execute on the simulator: + +> xt-run [--turbo] demo_threadx.out + +The option --turbo provides much faster, but non-cycle-accurate simulation. +Refer to the Xtensa simulator user manual for further simulator options. + + +To execute on the simulator using the Xplorer GUI based debugger: + +> xplorer --debug demo_threadx.out + + +To execute on a supported evaluation board, download demo_threadx.out per +instructions in the tools manuals. Be sure the board has been programmed +with the correct configuration and is set up to boot from RAM and debug +a downloaded program! Optionally you may connect a terminal or terminal +emulator to the serial port on the board with settings as described in +the board user manual, and see the output of printf on the terminal (if +the demo was compiled with DEMO_USE_PRINTF or DEMO_USE_XTUTIL). + +To obtain I/O on a "raw" platform such as an unsupported board, you need +to provide low level I/O drivers (eg. inbyte() and outbyte() for character +I/O if you want to use printf etc.). You can run "raw" executables on +any Xtensa platform, including simulator and any board, but you will not +see any behavior specific to the platform (eg. display, printed output, +stopping simulation at end of program). You can, while debugging, use a +debugger mechanism called GDBIO to obtain basic I/O. Use PLATFORM=GDBIO +on your xt-make command line - this is the same as "raw" except it links +some stubs that communicate through the debugger. It is very slow! + +WARNING: It is tempting to add printf calls to other threads in the demo. +If you modify the code in any way, you may need adjust affected threads' +stack sizes. This is especially true if you add a printf call. See 4.5. + + +4. System Initialization + +4.1 ThreadX Kernel + +ThreadX uses the reset vector and low level initialization from the Xtensa +libraries provided by the linker support package (LSP). It does not provide +its own reset vector (which would have to be maintained with tools upgrades). + +ThreadX is initialized by tx_kernel_enter which is usually called from +main. The primary initialization function is _tx_initialize_low_level +and is located in the file tx_initialize_low_level.c. This function is +responsible for setting up various system data structures. Interrupt and +exception vectors are linked into your program and installed at load time +(they are not dynamically installed). The interrupt and exception vectors +for the ThreadX Xtensa port are defined in xtensa_vectors.S (for XEA2) and +xtensa_vectors_xea3.S (for XEA3). + +4.2 Memory Allocation + +In addition, _tx_initialize_low_level also determines the first available +address for use by the application. By default, the first available address +is assumed to be above all linker-allocated sections at symbol _end. This +is passed to the application definition function, tx_application_define. +This is a convenience to the application developer. Ultimately the developer +has full control over memory allocation and can choose to use this or not. +The top of available memory is not provided and should be obtained from the +tools if needed. + +4.3 Location and Extent of System (Interrupt) Stack + +ThreadX/Xtensa supports a user-definable system stack. By default, the +top of the system stack is defined by the symbol _xt_interrupt_stack_top. +See the file xtensa_intr_asm.S for the default system stack definition. +This stack may be resized and/or relocated according to the application +needs. The application developer must ensure that the system stack is +sized appropriately for the application. All interrupts handled by +ThreadX will use the system stack. Handlers written in assembly must +not switch to the system stack, since it will not be possible to detect +whether the stack is currently in use. + +The macro TX_SYSTEM_STACK_SIZE defines the size of the system stack. +As a convenience, a macro TX_MINIMUM_STACK_SYSTEM is provided with the +minimum size required for the system stack. This is based on the maximum +possible interrupt nesting level per the Xtensa processor configuration, +assuming very simple C handlers that do not call deeper than one or two +levels. If the application uses more complex handlers, it will be +necessary to add to this value (accounting for nesting) to determine +the space required for the system stack. + +4.4 Location and Extent of C Library Heap + +If the optional thread-safe support for the C library is used, memory +for the heap is allocated like this: by default, half the space between +the first available memory address and the end of system memory is +made available to the heap. + +The heap location and limit are available in two global variables, and +can be fully customized in tx_application_define by assigning to them: + + _tx_clib_heap_start Base address of heap. + _tx_clib_heap_end Upper limit address to which heap can grow. + +This must be done BEFORE any C library calls. It is advised that it be +done at the beginning of tx_application_define. + +Please note that when the thread-safe C library support is used, the heap +is not initialized before tx_kernel_enter has been called, so malloc will +fail. It is recommended to avoid C library calls that use the heap (such +as printf) outside of ThreadX (eg. in main). The C library is NOT safe +for use in interrupt or exception handlers, so this should be avoided. + +4.5 Thread Stack Sizes + +The application must ensure that every thread has enough space for its +stack. This must account for the deepest call depth and allow for one +interrupt stack frame as defined in xtensa_context.h . Several factors +influence the size of the stack required, including compiler optimization +level (-O0 is worst), use of TX_ENABLE_STACK_CHECKING option, and of +course your Xtensa configuration. Some stack size guidelines and macros +are provided in tx_port.h assuming no optimization (default, -O0). + +Threads that call C library functions may need larger stacks than those +that don't. In particular, use of printf requires a very large stack and +will usually cause a stack overflow if inserted in a thread without +enlarging its stack size. See DEMO_STACK_SIZE_PRINTF in demo_threadx.c +for a guideline. Use printf with care! + + +5. Assembler / Compiler Switches + +The following are compiler switches used in building the ThreadX library +and demonstration system. These can be supplied by editing the Makefile +or by overriding the COPT or CFLAGS variables in the make command line +(eg. make COPT="-O2 -DTX_THREAD_SAFE_CLIB"). More details in Makefile. + +Compiler Switch Meaning + + -g Specifies debug information. + -c Specifies object code generation. + -On Sets compiler optimization level n (default -O0). + -mlongcalls Allows assembler and linker to convert call + instructions to longer indirect call sequences + when target is out of range. + -x assembler-with-cpp Passes .s and .S files through C preprocessor. + -Dmacro Define a preprocessor macro with no value. + -Dmacro=value Define a preprocessor macro with a value. + +Application Defines (preprocessor macros definable with the -D option): + + TX_THREAD_SAFE_CLIB Enable support for thread-safe C library. + Only the Xtensa C library and the newlib library + are supported for thread-safe operation. + When this is enabled, half the available memory + space is allocated by default, below the system + stack, for the heap. The heap size and location + can be customized in tx_application_define. + Default off. + + NOTE: Thread safe support for Xtensa C library requires Xtensa Tools + version RF-2015.2 or later. + + TX_ENABLE_STACK_CHECKING Enable generic ThreadX support for stack + overflow checking. This can help avoid long + debugging sessions or customer support calls + by identifying many crashes caused by stack + overflow. Use of this option adds a small + premium to the required thread stack sizes + (the premium is included by the stack size + convenience macros defined in tx_port.h). + + TX_NO_TIMER Enable generic ThreadX footprint reduction when + no periodic tick is needed. The Xtensa port also + reduces footprint by removing all code related + to timer interrupts. Related XT_* options below + (XT_CLOCK_FREQ, XT_TICK_PER_SEC, XT_TIMER_INDEX) + have no effect under TX_NO_TIMER. + + All generic ThreadX options in tx_user.h may also be defined with -D. + + Note, the above defines are not specific to Xtensa processors, so + their names begin with "TX_". Defines below are unique to the Xtensa + port so have names beginning with "XT_". + + XT_SIMULATOR Set this if building to run on the simulator. + Takes advantage of certain simulator control + and reporting facilities, and adjusts timing + of periodic tick to provide a more acceptable + performance in simulation (see XT_CLOCK_FREQ). + Set by default unless PLATFORM is overridden. + + XT_BOARD=board Set this if building for a supported board. + The value should be the identifier of a board + supported in the Xtensa Tools or an external + package (eg. XT_BOARD=xtkc705 for the Xilinx + KC705 board). If the board is supported by an + external package, the variable XTENSA_BOARDS + should point to the root of the package. Set by + provided Makefile when PLATFORM=board and BOARD + is defined (eg. PLATFORM=board BOARD=xtkc705). + + XT_CLOCK_FREQ=freq Specifies the target processor's clock + frequency in Hz. Used primarily to set the + timer that generates the periodic interrupt. + Defaults are provided and may be edited in + xtensa_timer.h (see comments there also). + Default for simulator provides more acceptable + performance, but cannot provide real-time + performance due to variation in simulation + speed per host platform and insufficient + cycles between interrupts to process them. + Supported board platforms by default leave + this undefined and compute the clock frequency + at initialization unless this is explicitly + defined. + + XT_TICK_PER_SEC=n Specifies the frequency of the periodic tick. + + XT_TIMER_INDEX=n Specifies which timer to use for ThreadX. + Set this if your Xtensa processor configuration + provides more than one suitable timer and you + want to override the default. See xtensa_timer.h. + + XT_INTEXC_HOOKS Enables hooks in interrupt vector handlers + to support dynamic installation of exception + and interrupt handlers. Used by automatic + regression test programs. Disabled by default. + + XT_USE_OVLY Enable code overlay support. + + XT_USE_SWPRI Enable software prioritization of interrupts. + Enabling this will prioritize interrupts with + higher bit numbers over those with lower bit + numbers at the same level. This works only for + low and medium priority interrupts that can be + dispatched to C handlers. + + TX_SYSTEM_STACK_SIZE=n Specify the size of the interrupt stack, which + is the stack that all interrupt handlers switch + to while handling interrupts. See the section + describing the interrupt stack for more details. + + +6. Register Usage and Stack Frames + +The Xtensa architecture specifies two ABIs that determine how the general +purpose registers a0-a15 are used: the windowed ABI, and the Call0 ABI. +The choice of ABI is made when configuring the processor or its associated +software. Xtensa processors may have other special registers (including +coprocessor registers and other TIE "states") that are independent of this +choice of ABI. See Xtensa documentation for more details. + +In the windowed ABI the registers of the current window are used as follows: + a0 = return address + a1 = stack pointer (alias sp) + a2 = first argument and result of call (in simple cases) + a3-7 = second through sixth arguments of call (in simple cases). + Note that complex or large arguments are passed on the + stack. Details are in the Xtensa Tools manuals. + a8-a15 = available for use as temporaries. + +There are no callee-save registers. The windowed hardware automatically +saves registers a0-a3 on a call4, a0-a8 on a call8, a0-a12 on a call12, +by rotating the register window. Hardware triggers window overflow and +underflow exceptions as necessary when registers outside the current +window need to be spilled to preallocated space in the stack frame, or +restored. Complete details are in the Xtensa manuals. The entire windowed +register file is saved and restored on interrupt or thread context switch. +Note that only call0 and call8 are available in XEA3 Windowed ABI. + +The Call0 ABI does not make use of register windows, relying instead +on a fixed set of 16 registers without window rotation. +The Call0 ABI is more conventional and uses registers as follows: + a0 = return address + a1 = stack pointer (alias sp) + a2 = first argument and result of call (in simple cases) + a3-7 = second through sixth arguments of call (in simple cases). + Note that complex or large arguments are passed on the + stack. Details are in the Xtensa Tools manuals. + a8-a11 = scratch. + a12-a15 = callee-save (a function must preserve these for its caller). + +On a ThreadX API call, callee-save registers are saved only when a thread +context switch occurs, and other registers are not saved at all (the caller +does not expect them to be preserved). On an interrupt, callee-saved +registers might only be saved and restored when a thread context-switch +occurs, but all other registers are always saved and restored. + +An Xtensa processor has other special registers independent of the ABI, +depending on the configuration (including coprocessor registers and other +TIE state) that are part of the thread context. ThreadX preserves all such +registers over an unsolicited context-switch triggered by an interrupt +(including time-slice expiry). However it does NOT preserve these over +a solicited context-switch during a ThreadX API call. This bears some +explanation. These special registers are either ignored by the compiler +or treated as caller-saved, meaning that if kept "live" over a function +call (ie. need to be preserved) they must be saved and restored by the +caller. Since solicited entry to ThreadX is always made by a function +call, ThreadX assumes the caller has saved any of these registers that are +"live". ThreadX avoids a lot of overhead by not having to save and restore +every special register (there can be many) on every solicited context switch. + +As a consequence, the application developer should NOT assume that special +registers are preserved over a ThreadX API call such as tx_thread_sleep. +If multiple threads use a register, the caller must save and restore it. + +The saved context stack frames for context switches that occur as a result +of interrupt handling (interrupt frame) or from thread-level API calls +(solicited frame) are described in human readable form in xtensa_context.h . +All suspended threads have one of these two types of stack frames. The top +of the suspended thread's stack is pointed to by tx_thread_stack_ptr in the +associated thread control block TX_THREAD. An Xtensa architecture port-specific +extension to the thread control block tx_thread_solicited contains 1 for a +thread that is currently suspended from an API call, otherwise contains 0. + + +7. Improving Performance, Footprint, or Ease of Debugging + +The distribution version of ThreadX is built with debug (-g) and without +compiler optimizations (-O0). This makes debugging easier inside ThreadX +itself. Of course, -O0 costs some performance. To make ThreadX run faster, +you can change the Makefile to enable the desired optimizations or set +a predefined optimization level (-O<level>) . + +Maximum performance is achieved with -O3, but that might increase footprint +substantially. A good compromise is -O2. If code size is a concern, -Os may +yield better results. See the compiler manual for details. + +You can eliminate the ThreadX basic API error checking by compiling your +application code with the symbol TX_DISABLE_ERROR_CHECKING defined before +tx_api.h is included. + +The Xtensa architecture port-specific assembly files are coded with no +file-scope labels inside functions (all labels inside functions begin with +".L"). This allows a profiler to accurately associate an address with a +function, and also allows the debugger's stack trace to show the correct +function wherever the program counter is within that function. However +there are some tradeoffs in debugging. Local (".L") labels are not +visible to the debugger, so the following limitations may be observed +during debugging: +- You cannot set a breakpoint on a local label inside a function. +- Disassembly will show the entire function, but will get out of sync and + show incorrect opcodes if it crosses any padding before an aligned local + branch target (".L" label, not ".Ln"). Restart disassembly specifying an + address range explicitly between points where there is padding. +Since ThreadX is provided in source form, it is not difficult to remove +the ".L" and ".Ln" prefixes from local labels if you want them visible. +They can also be made visible by passing the '-L' option to the assembler +and linker (see the assembler and linker manuals for details). + + +8. Interrupt and Exception Handling + +NOTE: The material in this section is mostly an overview. For a more +detailed explanation please refer to the Xtensa ISA manual and the System +Software manual. + +ThreadX provides a complete set of efficient exception and first-level +interrupt handlers installed at the appropriate exception and interrupt +vector locations. The XEA2 architecture supports several different +classes of exceptions and interrupts. Being a configurable architecture, +many of these are optional, and the vector locations are determined by +your processor configuration. The handlers provided use conditional +compilation to adapt to your processor configuration and include only +the code that is needed. + +Xtensa vector locations may reside almost anywhere, including in ROM. +And the amount of code space available at each of these locations is +often very small (e.g. due to following vectors). A small stub of code +installed at the vector jumps to the corresponding handler, usually in RAM. +The exception and interrupt handlers are defined in xtensa_vectors.S . +They are not specific to ThreadX, but call into ThreadX where appropriate +via macros defined in xtensa_rtos.h . + +Interrupt/Exception Handling in XEA2 +------------------------------------ + +The handlers provided for low and medium priority interrupts are just +dispatchers that save relevant state and call user-definable handlers. +See the files xtensa_vectors.S and xtensa_api.h for more details of how +to create and install application-specific user interrupt handlers. +Similarly, user-defined handlers can be installed for exceptions (other +than a few which are always handled by the OS). + +The high priority interrupt handlers provided may be considered templates +into which the application adds code to service specific interrupts. +The places where application handlers should be inserted are tagged with +the comment "USER_EDIT" in xtensa_vectors.S. + +This ThreadX port supports strict priority-based nesting of interrupts. +An interrupt may only nest on top of one of strictly lower priority. +Equal priority interrupts concurrently pending are handled in an +application-defined sequence before any lower priority interrupts +are handled. During interrupt and exception handling, the processor's +interrupt level (PS.INTLEVEL) is used to control the interrupt priority +level that can be accepted; interrupt sources are not controlled +individually by ThreadX (the application is free to access the INTENABLE +register directly to enable/disable individual interrupts, e.g. using +Xtensa HAL services). This approach provides the most deterministic +bounds on interrupt latency (for a given priority) and system stack depth. + +Software prioritization of interrupts at the same priority is controlled +by the definition of XT_USE_SWPRI. See above for a description of this +parameter. + +Interrupt and Exception Handling in XEA3 +---------------------------------------- + +In XEA3 no distinction is made between low, medium and high priority interrupt +levels. Interrupts at all levels up to the highest (NMI) level can be dispatched +to handlers written in C. Interrupts are dispatched by the XEA3 dispatcher and +the handlers are found from a handler table. Handlers are installed into the +handler table by calling xt_set_interrupt_handler. As there is no concept of +a high priority interrupt any longer, handlers can only be specified per +interrupt, not per level. Since all levels can be handled in C, the value of +EXCM_LEVEL is set to the highest possible level (NMI level). +Software prioritization is not available for XEA3. + + +The following subsections describe the handling of each class of exception +and interrupt in more detail. Many have nothing to do with ThreadX but are +mentioned because there is code to handle them in xtensa_vectors.S. + +8.1 User Exception and Interrupt Handler (Low/Medium Priority) + + All Xtensa 'general exceptions' come to the user, kernel, or double + exception vector. The exception type is identified by the EXCCAUSE + special register (level 1 interrupts are one particular cause of a + general exception). This port sets up PS to direct all such exceptions + to the user vector. Exceptions taken at the other two vectors usually + indicate a kernel or application bug. + + In XEA3, everything except a double exception will come to a common + vector. This vector saves the requisite processor state and then checks + for the highest priority interrupt to dispatch. If no interrupts are + pending then a check is made for exceptions. + + Level 1 interrupts are identified at the beginning of the handler + and are dispatched to a dedicated handler. Then, syscall and alloca + exceptions are identified and dispatched to special handlers described + below. After this, coprocessor exceptions are identified and dispatched + to the coprocessor handler. + + Any remaining exceptions are processed as follows: + + Having allocated the exception stack frame, the user exception handler + calls _tx_thread_context_save, which saves the rest of the interrupt + context. After this the handler sets up a C environment and enables + the high-priority class of interrupts (which do not interact with + ThreadX), then reads EXCCAUSE and uses the cause (number) to index + into a table of user-specified handlers. The correct handler is then + called. If the handler returns, the context is restored and control + is returned to the code that caused the exception. The user-defined + handler may alter the saved context, or any other system state, that + allows the faulting instruction to be retried. + + If the cause is a level 1 (low-priority) or medium-priority interrupt, + the handler enables all interrupts above that priority level after + saving the thread context and switching to the interrupt stack if it + is not a nested interrupt. It then sets up the environment for C code + and then calls the handler (found in the handler table) for the + interrupt number. If the user has not specified a handler, then the + default handler will be called, which will terminate the program. + + If the interrupt is for the system timer, it calls a special interrupt + handler for the system timer tick, which calls _tx_timer_interrupt then + clears its bit from the mask. This interrupt cannot be hooked by the + user-defined handler. + + Finally, the handler calls _tx_thread_context_restore to allow ThreadX + to perform any scheduling necessary and return either to the interrupted + thread or another. + + If software prioritization is enabled, the handler will re-enable all + interrupts at the same level that are numerically higher than the current + one, before calling the user handler. This allows a higher priority + interrupt to pre-empt the lower priority handler. + +8.2 Medium Priority Interrupt Handlers (XEA2) + + Medium priority interrupts are those at levels 2 up to XCHAL_EXCM_LEVEL, + a configuration-specific maximum interrupt level affected by the global + 'exception mode' bit in the processor status word (PS.EXCM). + Interrupt levels above XCHAL_EXCM_LEVEL are of the high-priority class. + The Xtensa hardware documentation considers medium priority interrupts + to be a special case of high-priority interrupts, but from a software + perspective they are very different. + + Dispatch of medium-priority interrupts is discussed in the section + above. + +8.3 High Priority Interrupt Handlers (XEA2) + + High priority interrupts are those strictly above XCHAL_EXCM_LEVEL, + a configuration-specific maximum interrupt level affected by the + global 'exception mode' bit in the processor status word (PS.EXCM). + High priority handlers may not directly interact with ThreadX at all, + and are described here only for the sake of completeness. They must + be coded in assembler (may not be coded in C) and are intended to be + used for handling extremely high frequency hardware events that need + to be handled in only a few cycles. A high priority interrupt handler + may trigger a software interrupt at a medium or low priority level to + occasionally signal ThreadX. Please see Xtensa documentation. + + There is a separate vector and a few special registers for each high + priority interrupt, providing for fast dispatch and efficient nesting + on top of lower priority interrupts. Handlers are templates included + only for the vectors that exist in your Xtensa processor configuration. + These templates are written for only one interrupt per high priority + level to minimize latency servicing very fast time-critical interrupts. + The vector code jumps to the corresponding first-level interrupt handler, + which then executes application-provided assembler code before returning + quickly to the interrupted thread or lower priority handler. + +8.4 Kernel Exception Handler (XEA2) + + Kernel mode is not used in this port of ThreadX, and therefore kernel + exceptions should not happen. A stub is provided for the vector that + triggers the debugger (if connected) or calls _xt_panic to freeze the + processor should a kernel exception occur. + +8.5 Alloca Exception Handler + + Alloca exceptions are generated by the 'movsp' instruction, which + is used only in the windowed ABI. Its purpose is to allocate some + space on top of the stack. Because the window hardware may have + spilled some registers to the 16 byte "base save" area below the + stack pointer, it is necessary to protect those values. The alloca + handler accomplishes this quickly without setting up an interrupt + frame or entering ThreadX, by emulating a register underflow and + re-executing 'movsp'. + +8.6 Syscall Exception Handler + + Syscall exceptions are generated by a 'syscall' instruction. + The windowed ABI specifies that executing this instruction with + a value of zero in register a2 must spill any unsaved registers + in the windowed register file to their pre-determined locations + on the caller's stack. The handler does exactly that, and skips + over the 'syscall' instruction before returning to the caller. + If a2 is non-zero, the handler returns a2 == -1 to the caller. + +8.7 Co-Processor Exception Handler + + A coprocessor exception is generated when a thread accesses a + coprocessor that it does not "own". Ownership represents which + thread's state is currently in the coprocessor. Co-processors are + context-switched "lazily" (on demand) only when a non-owning thread + uses a coprocessor instruction, otherwise a thread retains ownership + even when it is preempted from the main processor. The coprocessor + exception handler performs the context-switch and manages ownership. + + Co-processors may not be used by any code outside the context of a + thread. A coprocessor exception triggered by code that is not part + of a running thread is a fatal error and ThreadX/Xtensa will panic. + This restriction is intended to reduce the overhead of saving and + restoring coprocessor state (which can be quite large) and in + particular remove that overhead from interrupt handlers. It also + reduces the thread stack size requirement by allowing coprocessor + state to be saved in the thread control block rather than the stack. + +8.8 Debug Exception Handler + + A debug exception is caused as a result of running code, such as by + a 'break' instruction or hardware breakpoints and watchpoints, or + as a result of an external debug interrupt, such as from an OCD based + debugger or multiprocessor debug events ("breakin/breakout"). If the + processor is running in OCD mode under control of an OCD-based debugger, + the trigger event immediately halts the processor and gives control to + the OCD debugger. Otherwise control is transferred to the debug vector. + The debug vector handler calls the simulator if running on the ISS, + which then takes control and interacts with any attached debugger. + If running on hardware and not in OCD mode, debug exceptions are not + expected, so the debug handler calls _xt_panic to freeze the processor. + +8.9 Double Exception Handler + + A double exception is a general exception that happens while the + processor is in exception mode (PS.EXCM set), and thus indicates a + bug in kernel code. The double exception vector handler triggers + the debugger (if connected) or calls _xt_panic to freeze the + processor. + +8.10 Window Overflow and Underflow Exception Handlers + + Window overflow and underflow handlers are required for use of the + windowed ABI. Each has its own dedicated vector and highly optimized + code that is independent of OS. See Xtensa documentation for details. + +8.11 Hooks for Dynamic Installation of Handlers + + Optional hooks are provided in the user exception and low level + interrupt handler and all medium and high priority interrupt handlers, + to dynamically install a handler function (which may be coded in C, + unless in a high-priority interrupt handler). These hooks are enabled + and used by automatic regression tests, they are not part of a normal + ThreadX build. However an application is free to take advantage of + them. The interrupt/exception hooks are described in xtensa_rtos.h . + + It is recommended that the application not make use of these hooks, but + rather use xt_set_interrupt_handler() and xt_set_exception_handler() + to install application-specific handlers. This method is more convenient + and allows arguments to be passed to the handlers. Software prioritization + of interrupts works only with this method. See xtensa_api.h for details. + +9. Overlay Support (XEA2 only) + +ThreadX supports the overlay feature of the Xtensa toolsuite. To enable overlay support, +the ThreadX library should be built with XT_USE_OVLY defined. In addition, the linker +command line must use the overlay library via the -loverlay linker option and the +xtensa_overlay_os_hook.o object file must be explicitly specified in order to override +the overlay libary version. + +You will also need to generate a custom LSP for overlay use. Please reference the +Xtensa System Software Reference and Xtenas Linker Support Packages (LSPs) for more +information on using overlays. + + +10. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +04/26/2019 ThreadX Xtensa version 5.12. This release adds support for the Xtensa XEA3 + exception architecture and the Xtensa NX processor family. The following + changes/enhancements are included: + + Makefile Changes to support building for Xtensa + XEA3 configurations. + xtensa_vectors_xea3.S New file added, interrupt and exception + dispatch code for XEA3. + + tx_api_asm.h Changes and additions to support the Xtensa + tx_port.h XEA3 exception architecture. + xtensa_api.h + xtensa_context.h + xtensa_rtos.h + xtensa_timer.h + tx_initialize_low_level.c + tx_thread_context_restore.S + tx_thread_context_save.S + tx_thread_interrupt_control.c + tx_thread_schedule.S + tx_thread_stack_build.S + tx_thread_system_return.S + tx_timer_interrupt.S + tx_xtensa_stack_error_handler.c + xtensa_context.S + xtensa_coproc_handler.S + xtensa_init.c + xtensa_intr.c + xtensa_intr_asm.S + xtensa_intr_wrapper.c + xtensa_vectors.S + +08/01/2017 ThreadX Xtensa version 5.11. This release includes the following changes + and enhancements/modifications: + + Makefile Build execution profile module only + if the module has been selected. + tx_api_asm.h Changed field offsets for Xtensa- + specific fields in TCB. + tx_clib_lock.c Added thread wrapper function to handle + C library setup and cleanup properly. + tx_port.h Redefined macros as required as part of + the redesigned C library thread safety support. + tx_xtensa_stack_error_handler.c Included required headers. + xtensa_intr_asm.S Placed interrupt stack explicitly in .data + section. + xtensa_intr.c Fixed return values for set exception handler + and set interrupt handler functions. + xtensa_overlay_os_hook.c Added conditions so that code is now compiled + only if overlay option is selected. + xtensa_timer.h Include TIE header files conditionally. + *.h Modified comment(s). + *.S Modified comment(s). + +03/22/2016 ThreadX Xtensa version 5.10. This release includes the following changes + and enhancements: separate user-configurable interrupt stack, support for + Xtensa C library (xclib) thread safety, minor changes to the support for + the Execution Profile kit, and minor changes to remove some compiler warnings. + This release includes the following modifications: + + tx_port.h Added support for XCLIB C library thread safety, + added support for separate interrupt stack, + added support Execution Profile Kit (EPK), and + updated version string. + tx_initialize_low_level.S Replaced by tx_initialize_low_level.c, added + support for XCLIB C library thread safety, + added support for separate interrupt stack and + moved setup of thread stack check callback in here + from demo program. + tx_thread_context_restore.S Added support for Execution Profile Kit (EPK). + tx_thread_schedule.S Added support for Execution Profile Kit (EPK), and + added support for XCLIB C library thread safety. + tx_thread_system_return.S Added support for Execution Profile Kit (EPK). + tx_api_asm.h Added support for XCLIB C library thread safety. + tx_clib_lock.c Added support for XCLIB C library thread safety. + xtensa_api.h Corrected issues with function declarations. + xtensa_context.h Corrected build errors when TX_NO_TIMER defined. + xtensa_intr_asm.S Added support for separate interrupt stack. + xtensa_overlay_os_hook.c Corrected compiler warnings. + xtensa_vectors.S Added support for Execution Profile Kit (EPK), and + added compiler warnings. + xtensa_timer.h Added timer related defines to simplify timer setup code. + Makefile Various misc updates, removed some obsolete targets. + tx_intr_demo.c Added support for XCLIB C library thread safety. + *.h Modified comment(s). + *.S Modified comment(s). + +06/01/2015 ThreadX Xtensa version 5.9. This release includes the following modifications: + + tx_port.h Changed default timer thread stack size logic, + updated coprocessor support, and updated + version string. + tx_initialize_low_level.S Modified timer setup. + tx_thread_schedule.S Added setup for timing test option. + tx_thread_stack_build.S Added virtual priority mask setup. + tx_thread_system_return.S Added support for coprocessor save. + xtensa_context.h Added additional interrupt support, including + coprocessor save/restore. + xtensa_context.S Added additional interrupt support, including + coprocessor save/restore. + xtensa_overlay_os_hook.c Added include of overlay.h. + xtensa_vectors.S Added new interrupt support and functionality. + xtensa_api.h Added new file for this release. + xtensa_intr.c Added new file for this release. + xtensa_intr_asm.S Added new file for this release. + *.h Modified comment(s). + *.S Modified comment(s). + +07/31/2014 ThreadX Xtensa version 5.8. This release includes the following modifications: + + tx_port.h Added in-line interrupt disable and + restore macros, and updated version string. + tx_thread_system_return.S Added context save optimization. + xtensa_context.h Added overlay support. + xtensa_context.S Added overlay support. + xtensa_overlay_os_hook.c Added new file for overlay support. + *.h Modified comment(s). + *.S Modified comment(s). + +10/01/2011 ThreadX Xtensa version 5.7. This release includes the following modifications: + + tx_port.h Updated version string. + tx_thread_context_restore.S Changed to 16-bit save of tx_thread_cp_state. + tx_thread_schedule.S Changed to 16-bit restore of tx_thread_cp_state. + tx_thread_system_return.S Changed to 16-bit save of tx_thread_cp_state. + xtensa_context.h Modified alignment constants and macros. + xtensa_context.S Removed initial alignment adjustment. + *.h Modified comment(s). + *.S Modified comment(s). + +07/15/2011 ThreadX Xtensa version 5.6. This release includes the following modifications: + + tx_port.h Modified control block and thread processing + extensions to be compatible with all cores, + and updated version string. + + tx_clib_lock.c Added code to not use priority inheritance when + running the regression testsuite. + tx_timer_interrupt.S Added code to optionally call user timer ISR. + xtensa_timer.h Adjusted timer for testsuite to pass under + simulation. + xtensa_vectors.S Fixed several issues in coprocessor context + switch code. + *.S Modified comment(s). + +01/28/2011 ThreadX Xtensa version 5.5. This release includes the following modifications: + + tx_port.h Changed version ID and added alignment padding. + tx_thread_stack_build.s Added code to clear solicited stack frame flag. + xtensa_context.h Added logic to support Xtensa processors with + load/store units wider than 128-bits + xtensa_context.s Added logic to support Xtensa processors with + load/store units wider than 128-bits + xtensa_vectors.s Added logic to support Xtensa processors with + load/store units wider than 128-bits + *.s Modified comment(s). + +05/01/2010 ThreadX Xtensa version 5.4. This release includes the following modifications: + + tx_port.h Changed version ID. + tx_thread_system_return.s Changed code to preserve current time-slice value. + *.s Modified comment(s). + +07/15/2009 ThreadX Xtensa version 5.3. It includes the following modifications: + + tx_port.h Added include of string.h, added GDBIO + constants, and modified version ID string. + tx_clib_lock.c Added include of stdlib.h. + tx_thread_context_save.S Added "XCHAL_CP_NUM > 0" conditional around + _tx_thread_coproc_state function definition. + tx_thread_schedule.S Removed #else conditional and replaced RET + macro with assembly code. + tx_thread_system_return.S Replaced ENTRY macro with assembly code. + xtensa_context.h Modified call frame offsets. + xtensa_timer.h Modified timer constants and added extern + for _xt_tick_diviso_init function. + xtensa_vectors.S Replaced exit macros. + tx*.h Modified comment(s). + tx*.c Modified comment(s). + tx*.S Modified comment(s). + +06/18/2008 ThreadX Xtensa version 5.2. It includes the following modifications: + + tx_port.h Added "extern" to the interrupt control + function prototype, and modified + version ID string. + tx_api_asm.h Fixed bug whereby tx_thread_cp_state + was off by 1 word and overlapped + tx_thread_name if TX_THREAD_SAFE_CLIB + was not defined. + xtensa_vectors.S Strengthened syncs for strict ISA + conformance. Aligned exit dispatchers. + tx*.h Modified comment(s). + tx*.c Modified comment(s). + tx*.S Modified comment(s). + +04/02/2007 ThreadX Xtensa version 5.1. This release adds minor enhancements + and supports evaluation boards via a new board independent "XTBSP" + API (allowing ThreadX to take advantage of any supported board) + and deprecates board-specific code for the obsolete XT2000. + It includes the following modifications: + + tx_port.h Co-proc check uses XCHAL_CP_NUM, + deprecated XT_XT2000 option, + included tx_user.h first, and + made TX_MAX_PRIORITIES visible + to assembler code. + tx_xtensa_stack_error_handler.c Accessed board's display via API + and deprecated XT_XT2000 option. + tx_initialize_low_level.S Co-proc check uses XCHAL_CP_NUM, + modified timer setup and + supported TX_NO_TIMER. + tx_thread_context_restore.S Co-proc check uses XCHAL_CP_NUM. + tx_thread_schedule.S Co-proc check uses XCHAL_CP_NUM. + tx_thread_system_return.S Co-proc check uses XCHAL_CP_NUM. + tx_timer_interrupt.S Use tick divisor computed via + API and support TX_NO_TIMER. + xtensa_context.h Co-proc check uses XCHAL_CP_NUM. + xtensa_context.S Co-proc check uses XCHAL_CP_NUM. + xtensa_init.c Added new initialization code to + set tick timer using board API. + xtensa_rtos.h Allowed tx_user.h macros to + affect Xtensa-generic macros and + supported TX_NO_TIMER. + xtensa_timer.h Updated timer configuration + logic and supported TX_NO_TIMER. + xtensa_vectors.S Co-proc check uses XCHAL_CP_NUM + and updated logic for long jumps + and supported TX_NO_TIMER. + tx*.h Modified comment(s). + tx*.c Modified comment(s). + tx*.S Modified comment(s). + +10/10/2006 Initial ThreadX version for Xtensa configurable processors + and Diamond pre-configured processors using Xtensa Tools. + + +Copyright(c) 1996-2020 Microsoft Corporation + + +https://azure.com/rtos + diff --git a/ports/xtensa/xcc/src/tx_clib_lock.c b/ports/xtensa/xcc/src/tx_clib_lock.c new file mode 100644 index 00000000..072cbd52 --- /dev/null +++ b/ports/xtensa/xcc/src/tx_clib_lock.c @@ -0,0 +1,406 @@ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains the interface functions to provide thread-safe */ +/* operation of the C library. Both newlib and the Xtensa C Library */ +/* are supported. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +#include "tx_api.h" /* TX_THREAD_SAFE_CLIB may be defined by tx_port.h */ +#include "tx_thread.h" +#include "tx_initialize.h" + +/* Xtensa specific */ +#include <xtensa/config/system.h> + +#ifdef TX_THREAD_SAFE_CLIB /* this file is only needed if using C lib */ + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> + + +#if XSHAL_CLIB == XTHAL_CLIB_NEWLIB + +#include <malloc.h> + +/* NOTE: should have been declared in reent.h... */ +extern void _wrapup_reent(struct _reent * ptr); + +/* Mutex used for all C library protection */ +TX_MUTEX clib_lock_mutex; + + +/**************************************************************************/ +/* __malloc_lock - called by the malloc() family of routines when they */ +/* need to lock the memory pool. A call to malloc() may call this */ +/* function recursively. */ +/**************************************************************************/ +void +__malloc_lock (struct _reent * ptr) +{ + if (_tx_thread_system_state != TX_INITIALIZE_IS_FINISHED) { + return; + } + + tx_mutex_get (&clib_lock_mutex, TX_WAIT_FOREVER); +} + +/**************************************************************************/ +/* __malloc_unlock - called by the malloc() family of routines when */ +/* need to unlock the memory pool. */ +/**************************************************************************/ +void +__malloc_unlock (struct _reent * ptr) +{ + if (_tx_thread_system_state != TX_INITIALIZE_IS_FINISHED) { + return; + } + +#ifndef THREADX_TESTSUITE /* see THREADX_TESTSUITE comments below */ + tx_mutex_prioritize (&clib_lock_mutex); /* is this at all necessary? */ +#endif + tx_mutex_put (&clib_lock_mutex); +} + + +/**************************************************************************/ +/* __env_lock - called by the setenv() family of routines when they */ +/* need to modify the environment. A call to setenv() may call this */ +/* function recursively. */ +/**************************************************************************/ +void +__env_lock (struct _reent * ptr) +{ + if (_tx_thread_system_state != TX_INITIALIZE_IS_FINISHED) { + return; + } + + tx_mutex_get (&clib_lock_mutex, TX_WAIT_FOREVER); +} + +/**************************************************************************/ +/* __env_unlock - called by the setenv() family of routines when they */ +/* need to unlock the environment. */ +/**************************************************************************/ +void +__env_unlock (struct _reent * ptr) +{ + if (_tx_thread_system_state != TX_INITIALIZE_IS_FINISHED) { + return; + } + + tx_mutex_prioritize (&clib_lock_mutex); + tx_mutex_put (&clib_lock_mutex); +} + +#endif /* XSHAL_CLIB == XTHAL_CLIB_NEWLIB */ + +#if XSHAL_CLIB == XTHAL_CLIB_XCLIB + +#include <errno.h> +#include <sys/reent.h> + +#define XT_NUM_CLIB_LOCKS (_MAX_LOCK + FOPEN_MAX) + +typedef TX_MUTEX * _Rmtx; + +static TX_MUTEX xclib_locks[XT_NUM_CLIB_LOCKS]; +static uint32_t lcnt; + +/* Override this and set to nonzero to enable locking. */ +int32_t _xclib_use_mt = 1; + + +/**************************************************************************/ +/* _Mtxinit - initialize a lock. Called once for each lock. */ +/**************************************************************************/ +void +_Mtxinit (_Rmtx * mtx) +{ + TX_MUTEX * lock; + + if (lcnt >= XT_NUM_CLIB_LOCKS) { + /* Fatal error */ + } + + lock = &(xclib_locks[lcnt]); + lcnt++; + + /* See notes for newlib case below. */ +#ifdef THREADX_TESTSUITE + tx_mutex_create (lock, "Clib lock", 0); +#else + tx_mutex_create (lock, "Clib lock", TX_INHERIT); +#endif + + *mtx = lock; +} + +/**************************************************************************/ +/* _Mtxdst - destroy a lock. Called once for each lock. */ +/**************************************************************************/ +void +_Mtxdst (_Rmtx * mtx) +{ + if ((mtx) && (*mtx)) { + tx_mutex_delete (*mtx); + } +} + +/**************************************************************************/ +/* _Mtxlock - acquire lock. */ +/**************************************************************************/ +void +_Mtxlock (_Rmtx * mtx) +{ + if ((mtx) && (*mtx)) { + tx_mutex_get (*mtx, TX_WAIT_FOREVER); + } +} + +/**************************************************************************/ +/* _Mtxunlock - release a lock. */ +/**************************************************************************/ +void +_Mtxunlock (_Rmtx * mtx) +{ + if ((mtx) && (*mtx)) { + tx_mutex_put (*mtx); + } +} + +#endif /* XSHAL_CLIB == XTHAL_CLIB_XCLIB */ + + +/**************************************************************************/ +/* _sbrk_r - heap allocator. This function is called when the memory */ +/* allocator needs a new chunk of memory. */ +/* The bounds of the heap area are global variables so that customer */ +/* startup code can easily override them if needed. */ +/* */ +/* _tx_clib_heap_start is the start of memory assigned to the heap */ +/* or 0 (NULL) if no memory is assigned (in */ +/* that case all calls to malloc will fail). */ +/* */ +/* _tx_clib_heap_end is the end of memory assigned to the heap */ +/* or 0 (NULL) if no memory is assigned. If a */ +/* nonzero start value is set then a nonzero */ +/* end value must be set. */ +/**************************************************************************/ + +char * _tx_clib_heap_start = NULL; +char * _tx_clib_heap_end = NULL; + +void * +_sbrk_r (struct _reent * reent, int32_t incr) +{ + static char * heap_ptr; + char * new_heap_ptr; + char * alloc_ptr; + + /* The heap is bound by _tx_clib_heap_{start,end}. */ + if (heap_ptr == NULL) { + heap_ptr = _tx_clib_heap_start; + } + + new_heap_ptr = heap_ptr + incr; + if ((heap_ptr == NULL) || /* no heap */ + (new_heap_ptr >= _tx_clib_heap_end) || /* heap exhausted */ + (new_heap_ptr < heap_ptr)) { /* wraparound */ + reent->_errno = ENOMEM; + return (void *) -1; + } + + alloc_ptr = heap_ptr; + heap_ptr = new_heap_ptr; + return (void *) alloc_ptr; +} + + +/**************************************************************************/ +/* _tx_clib_init - initialize C library thread safety support. */ +/* Called by _tx_initialize_low_level(). */ +/**************************************************************************/ +void +_tx_clib_init (void) +{ +#if XSHAL_CLIB == XTHAL_CLIB_NEWLIB +#ifdef THREADX_TESTSUITE + /* Priority inheritance causes printf() (which calls malloc() + which calls __malloc_unlock() which calls tx_mutex_put() + which calls _tx_mutex_priority_change() if TX_INHERIT is set) + which causes the task to suspend and resume which sometimes + changes execution order in the very sensitive testsuite + and makes it fail. So, for the testsuite, don't request + priority inheritance (it doesn't need it in any case). */ + tx_mutex_create (&clib_lock_mutex, "Clib lock", 0); +#else + tx_mutex_create (&clib_lock_mutex, "Clib lock", TX_INHERIT); +#endif +#endif /* NEWLIB */ + +#if XSHAL_CLIB == XTHAL_CLIB_XCLIB + /* Nothing. */ +#endif /* XCLIB */ +} + + +/**************************************************************************/ +/* _tx_clib_reent_init - initialize C library thread reent structure. */ +/* Called by tx_thread_create() to init per-thread C library state. */ +/**************************************************************************/ +void +_tx_clib_reent_init (TX_THREAD * thread_ptr) +{ + if (thread_ptr == NULL) { + /* Should never happen */ + return; + } + +#if XSHAL_CLIB == XTHAL_CLIB_NEWLIB + struct _reent * reent = &(thread_ptr->tx_thread_clib_reent); + + memset (reent, 0, sizeof(struct _reent)); + _REENT_INIT_PTR (reent); + thread_ptr->tx_thread_clib_ptr = reent; +#endif + +#if XSHAL_CLIB == XTHAL_CLIB_XCLIB + thread_ptr->tx_thread_clib_ptr = &(thread_ptr->tx_thread_clib_reent); + _init_reent (thread_ptr->tx_thread_clib_ptr); +#endif +} + + +/**************************************************************************/ +/* _tx_clib_reent_cleanup - clean up C library thread reent structure. */ +/* Called by tx_thread_delete() to clean up per-thread C library state */ +/* and free any allocated memory (partial = 0). */ +/* Called by tx_thread_shell_entry and tx_thread_terminate to perform */ +/* "atexit" processing and clean up stdio, but leaving the rest of the */ +/* structure intact so the thread can be restarted (partial = 1). */ +/**************************************************************************/ +void +_tx_clib_reent_cleanup (TX_THREAD * thread_ptr, int32_t partial) +{ +#if XSHAL_CLIB == XTHAL_CLIB_NEWLIB + struct _reent * reent = &(thread_ptr->tx_thread_clib_reent); + FILE * fp = &(reent->__sf[0]); + int32_t i; + + /* Avoid closing stdin,stdout,stderr so other threads can still use them. */ + for (i = 0; i < 3; i++) { + fp->_close = NULL; + fp++; + } + + if (partial != 0) { + /* Perform "atexit" processing and clean up stdio. */ + _wrapup_reent (reent); + } + else { + /* Free all the heap memory allocated in the reent structure. + ThreadX requires that the thread has either exited or been + terminated before it can be deleted so we can assume that + _wrapup_reent has already been called for this thread. */ + _reclaim_reent (reent); + } +#endif + +#if XSHAL_CLIB == XTHAL_CLIB_XCLIB + /* Unused, keep compiler happy */ + (void) partial; + + /* File handle table is global; no allocated memory in struct. */ + thread_ptr->tx_thread_clib_ptr = 0; +#endif +} + + +/**************************************************************************/ +/* _xt_wrapper - thread wrapper to handle C library init/cleanup. */ +/* If C library thread safety is enabled, every thread is invoked */ +/* via this wrapper in order to handle thread context setup/cleanup. */ +/**************************************************************************/ +void +_xt_thread_wrapper (ULONG arg) +{ + TX_INTERRUPT_SAVE_AREA + TX_THREAD * thread_ptr = _tx_thread_current_ptr; + + /* No use for this parameter */ + (void) arg; + + /* Init the C library thread context */ + _tx_clib_reent_init (thread_ptr); + + /* Disable interrupts around the global context ptr update */ + TX_DISABLE + +#if XSHAL_CLIB == XTHAL_CLIB_NEWLIB + _impure_ptr = thread_ptr->tx_thread_clib_ptr; +#endif +#if XSHAL_CLIB == XTHAL_CLIB_XCLIB + _reent_ptr = thread_ptr->tx_thread_clib_ptr; +#endif + + TX_RESTORE + + /* Call actual thread entry point */ + (thread_ptr->tx_real_thread_entry)(thread_ptr->tx_thread_entry_parameter); + + /* Clean up C library thread context */ + _tx_clib_reent_cleanup(thread_ptr, 1); + _tx_clib_reent_cleanup(thread_ptr, 0); +} + + +/**************************************************************************/ +/* _tx_clib_thread_setup - Xtensa-specific thread setup actions. */ +/* This function will be called only if thread safe C library usage */ +/* is enabled. It inserts the wrapper as the thread entry point and */ +/* saves the actual entry point for later use. */ +/**************************************************************************/ +void +_tx_clib_thread_setup (TX_THREAD * thread_ptr) +{ + thread_ptr->tx_real_thread_entry = thread_ptr->tx_thread_entry; + thread_ptr->tx_thread_entry = &(_xt_thread_wrapper); +} + +#endif /* TX_THREAD_SAFE_CLIB */ + diff --git a/ports/xtensa/xcc/src/tx_initialize_low_level.c b/ports/xtensa/xcc/src/tx_initialize_low_level.c new file mode 100644 index 00000000..d7082db0 --- /dev/null +++ b/ports/xtensa/xcc/src/tx_initialize_low_level.c @@ -0,0 +1,187 @@ +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + + +#include "tx_api.h" +#include "tx_port.h" +#include "xtensa_api.h" + +#if XCHAL_HAVE_ISL || XCHAL_HAVE_KSL || XCHAL_HAVE_PSL +#include <xtensa/tie/xt_exception_dispatch.h> +#endif + + +#if XCHAL_HAVE_XEA3 +int32_t xt_sw_intnum = -1; +int32_t xt_timer_intnum = -1; +#endif + + +/**************************************************************************/ +/* */ +/* 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. */ +/* It also sets the default heap region for the optional C library. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ +VOID _tx_initialize_low_level(VOID) +{ + extern char _xt_interrupt_stack_top; + extern void _tx_timer_interrupt(void *); + extern void * _tx_thread_system_stack_ptr; + extern void * _tx_initialize_unused_memory; + extern char _end; + + #ifdef TX_THREAD_SAFE_CLIB + extern char __stack; + extern void _tx_clib_init(void); + #endif + + #if XCHAL_CP_NUM > 0 + extern void _xt_coproc_init(void); + extern void _xt_coproc_exc(XtExcFrame * fp); + #endif + + #ifdef TX_ENABLE_STACK_CHECKING + extern VOID _tx_xtensa_stack_error_handler(TX_THREAD * thread); + #endif + + #if XCHAL_HAVE_XEA3 + extern void xt_sched_handler(void * arg); + int32_t i; + #endif + + TX_INTERRUPT_SAVE_AREA + + /* Disable interrupts - don't want any that interact with ThreadX yet. */ + TX_DISABLE + + /* + Disable stack limit checking if present. Whatever was set up earlier + is not going to work for us. + */ +#if XCHAL_HAVE_KSL + XT_WSR_KSL(0); +#endif +#if XCHAL_HAVE_ISL + XT_WSR_ISL(0); +#endif + + /* Save the system stack pointer. */ + _tx_thread_system_stack_ptr = &(_xt_interrupt_stack_top); + + /* Save the first available memory address. */ + _tx_initialize_unused_memory = (void *)(((UINT)&_end + 15) & ~0xF); + + #ifdef TX_THREAD_SAFE_CLIB + /* + Pre-allocate default memory region for the C library heap. + Bisect the region from first available memory to end of system memory, + align to 16 byte boundary, and allocate the heap in the upper half. + */ + _tx_clib_heap_end = &(__stack); + _tx_clib_heap_start = + (void *)(((UINT)_tx_initialize_unused_memory/2 + (UINT)_tx_clib_heap_end/2) & ~0xF); + #endif + + #if XCHAL_CP_NUM > 0 + /* + Initialize co-processor management for threads. Leave CPENABLE alone. + This is called from a normal Xtensa single-threaded run-time environment + before multi-threading has commenced. All co-processors are enabled. + It is important NOT to clear CPENABLE yet because tx_application_define() + is user code which might use a co-processor. The co-processor exception + handler does not expect to be called outside a thread. + */ + _xt_coproc_init(); + + #if XCHAL_HAVE_XEA3 + /* Install the coprocessor exception handler. */ + xt_set_exception_handler(EXCCAUSE_CP_DISABLED, _xt_coproc_exc); + #endif + #endif + + #if XCHAL_HAVE_XEA3 + /* Select a software interrupt to use for scheduling. */ + for (i = 0; i < XCHAL_NUM_INTERRUPTS; i++) { + if ((Xthal_inttype[i] == XTHAL_INTTYPE_SOFTWARE) && (Xthal_intlevel[i] == 1)) { + xt_sw_intnum = i; + break; + } + } + + if (xt_sw_intnum == -1) { + __asm__ volatile ("break 1, 1"); + } + + /* Set the interrupt handler and enable the interrupt. */ + xt_set_interrupt_handler(xt_sw_intnum, xt_sched_handler, 0); + xt_interrupt_enable(xt_sw_intnum); + #endif + + #ifndef TX_NO_TIMER + + /* Compute tick divisor if clock freq is not compile-time constant. */ + #ifndef XT_CLOCK_FREQ + _xt_tick_divisor_init(); + #endif + + /* Set up the periodic tick timer (assume enough time to complete init). */ + #ifdef XT_CLOCK_FREQ + XT_WSR_CCOMPARE(XT_RSR_CCOUNT() + XT_TICK_DIVISOR); + #else + XT_WSR_CCOMPARE(XT_RSR_CCOUNT() + _xt_tick_divisor); + #endif + + #if XCHAL_HAVE_XEA3 + xt_timer_intnum = XT_TIMER_INTNUM; + xt_set_interrupt_handler(xt_timer_intnum, _tx_timer_interrupt, 0); + #endif + + /* Enable the timer interrupt at the device level. */ + xt_interrupt_enable(XT_TIMER_INTNUM); + + #endif /* TX_NO_TIMER */ + + /* Initialize C library thread safety support. */ + #ifdef TX_THREAD_SAFE_CLIB + _tx_clib_init(); + #endif + + /* Install stack overflow notification callback. */ + #ifdef TX_ENABLE_STACK_CHECKING + tx_thread_stack_error_notify(_tx_xtensa_stack_error_handler); + #endif +} + diff --git a/ports/xtensa/xcc/src/tx_thread_context_restore.S b/ports/xtensa/xcc/src/tx_thread_context_restore.S new file mode 100644 index 00000000..aa628751 --- /dev/null +++ b/ports/xtensa/xcc/src/tx_thread_context_restore.S @@ -0,0 +1,216 @@ +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#include "xtensa_rtos.h" +#include "tx_api_asm.h" + + +#if XCHAL_HAVE_XEA2 + + .text + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function restores the interrupt context if it is processing a */ +/* nested interrupt. If not, it returns to the interrupt thread if no */ +/* preemption is necessary. Otherwise, if preemption is necessary or */ +/* if no thread was running, the function returns to the scheduler. */ +/* */ +/* RELEASE HISTORY */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +// VOID _tx_thread_context_restore(VOID) +// { + .globl _tx_thread_context_restore + .type _tx_thread_context_restore,@function + .align 4 +_tx_thread_context_restore: + + /* + Please note: Control flow might seem strange. This is because it has been + optimized to avoid taken branches in the longest normal path (the critical + one for worst-case latency), presumed to be a non-nested interrupt that + preempts) and to hide pipeline interlock cycles where possible. + */ + + /* Lockout interrupts. */ + XT_INTS_DISABLE(a0) + + #ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + /* Call the ISR exit function to indicate an ISR is complete. */ + #ifdef __XTENSA_CALL0_ABI__ + call0 _tx_execution_isr_exit + #else + call8 _tx_execution_isr_exit + #endif + #endif + + /* Determine if interrupts are nested. */ + // if (--_tx_thread_system_state) + // { + + movi a2, _tx_thread_system_state /* a2 = & interrupt nesting count */ + l32i a3, a2, 0 /* decrement interrupt nesting count */ + addi a3, a3, -1 + s32i a3, a2, 0 + bnez a3, .L_tx_thread_nested_restore + + // } + +.Ln_tx_thread_not_nested_restore: + + /* Determine if a thread was interrupted and no preemption is required. */ + // else if (((_tx_thread_current_ptr) + // && (_tx_thread_current_ptr == _tx_thread_execute_ptr)) + // || (_tx_thread_preempt_disable)) + // { + + movi a0, _tx_thread_current_ptr /* a0 = &_tx_thread_current_ptr */ + l32i a2, a0, 0 /* a2 = _tx_thread_current_ptr (old) */ + movi a3, _tx_thread_execute_ptr + beqz a2, .L_tx_thread_idle_system_restore + + l32i a3, a3, 0 /* a3 = _tx_thread_execute_ptr (new) */ + beq a3, a2, .L_tx_thread_no_preempt_restore + + movi a3, _tx_thread_preempt_disable + l32i a3, a3, 0 /* a3 = _tx_thread_preempt_disable */ + + // /* the no-preempt case has moved down so we fall-thru to preempt */ + bgei a3, 1, .L_tx_thread_no_preempt_restore + + // } + // else + // { + +.Ln_tx_thread_preempt_restore: + + /* Save remaining context on the thread's stack. */ + l32i a3, a2, tx_thread_stack_ptr /* a3 = thread's stack ptr */ + + /* Store standard preserved registers. */ + /* + Call0 ABI callee-saved regs a12-15 need to be saved before preemption. + However a12-13 were saved for scratch by _tx_thread_context_save(). + */ + #ifdef __XTENSA_CALL0_ABI__ /* Call0: now save callee-save regs */ + s32i a14, a3, XT_STK_A14 + s32i a15, a3, XT_STK_A15 + #endif + + /* Save the remaining time-slice and disable it. */ + // if (_tx_timer_time_slice) + // { + movi a3, _tx_timer_time_slice /* a3 = &_tx_timer_time_slice */ + l32i a4, a3, 0 /* a4 = _tx_timer_time_slice */ + beqz a4, .L_tx_thread_dont_save_ts + + // _tx_thread_current_ptr -> tx_thread_time_slice + // = _tx_timer_time_slice; + // _tx_timer_time_slice = 0; */ + s32i a4, a2, tx_thread_time_slice + movi a4, 0 + s32i a4, a3, 0 + + // } + +.L_tx_thread_dont_save_ts: + + /* Clear the current task pointer. */ + // _tx_thread_current_ptr = TX_NULL; + s32i a4, a0, 0 /* a4 == 0 == TX_NULL */ + + #if XCHAL_CP_NUM > 0 + /* Save CPENABLE in thread's co-processor save area, and clear CPENABLE. */ + rsr a3, CPENABLE + s16i a3, a2, tx_thread_cp_state + XT_CPENABLE + wsr a4, CPENABLE /* disable all co-processors */ + #endif + +.L_tx_thread_idle_system_restore: + + /* + Return via the scheduler. + Scheduler returns eventually to this function's caller as if called by it. + At this point we are still on the system stack. + */ + // _tx_thread_schedule(); + call0 _tx_thread_schedule /* never returns here */ + + // } + + /* Flow never falls through here. */ + +.L_tx_thread_no_preempt_restore: + + /* Restore interrupted thread. */ + + /* Pickup the saved stack pointer. */ + // SP = _tx_thread_current_ptr -> tx_thread_stack_ptr; + l32i sp, a2, tx_thread_stack_ptr + +.L_tx_thread_nested_restore: + + /* Recover the saved context and return to the point of interrupt. */ + + call0 _xt_context_restore + + /* + Must return via the exit dispatcher corresponding to the entrypoint + from which this was called. Interruptee's A0, A1, PS, PC are restored + and the interrupt stack frame is deallocated in the exit dispatcher. + At this point we are on the thread's stack. + */ + l32i a0, sp, XT_STK_EXIT + ret + +// } + +#endif /* XCHAL_HAVE_XEA2 */ + diff --git a/ports/xtensa/xcc/src/tx_thread_context_save.S b/ports/xtensa/xcc/src/tx_thread_context_save.S new file mode 100644 index 00000000..4025ea66 --- /dev/null +++ b/ports/xtensa/xcc/src/tx_thread_context_save.S @@ -0,0 +1,157 @@ +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#include "xtensa_rtos.h" +#include "tx_api_asm.h" + + +#if XCHAL_HAVE_XEA2 + + .text + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function saves the context of an executing thread in the */ +/* beginning of interrupt processing. The function also ensures that */ +/* the system stack is used upon return to the calling ISR. */ +/* */ +/* Interrupts remain disabled and no exceptions are triggered! */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +// VOID _tx_thread_context_save(VOID) +// { + .globl _tx_thread_context_save + .type _tx_thread_context_save,@function + .align 4 +_tx_thread_context_save: + + /* + Please note: Control flow might seem strange. This is because it has been + optimized to avoid taken branches in the longest normal path (the critical + one for worst-case latency), presumed to be a non-nested interrupt and + non-idle) and to hide pipeline interlock cycles where possible. + */ + + /* + Save a couple of scratch regs to work with that are preserved over the + call to _xt_context_save. The latter assumes the interruptee's values + of these are already saved and these regs contain different data to be + preserved, so doesn't save them in the stack frame, and thereby requires + that its caller have already saved them in the interrupt stack frame. + We end up with a12 = return address, a13 and a0 are scratch. + */ + s32i a12, sp, XT_STK_A12 + s32i a13, sp, XT_STK_A13 + + /* Check for a nested interrupt condition and increment nesting count. */ + // if (_tx_thread_system_state++) + // { + movi a13, _tx_thread_system_state /* a13 = & interrupt nesting count */ + mov a12, a0 /* a12 = save ret addr (free a0) */ + l32i a0, a13, 0 /* increment interrupt nesting count */ + addi a0, a0, 1 + s32i a0, a13, 0 + bnei a0, 1, .L_tx_thread_nested_save /* was !=0 before increment? */ + + // } + +.Ln_tx_thread_not_nested_save: + + /* Otherwise, not nested, check to see if a thread was running. */ + // else + // { + // if (_tx_thread_current_ptr) + // { + movi a0, _tx_thread_current_ptr + l32i a13, a0, 0 /* a13 = current thread ctrl blk */ + beqz a13, .L_tx_thread_idle_system_save + + /* Save the rest of the interrupted context. */ + call0 _xt_context_save + + /* Save the current stack pointer in the thread's control block. */ + // _tx_thread_current_ptr -> tx_thread_stack_ptr = sp; + s32i sp, a13, tx_thread_stack_ptr + + // } + /* Switch to the system stack and return to ISR. */ + +.L_tx_thread_idle_system_save: + + /* + If interrupted in the idle state, it's not necessary to save any context. + But even in the idle case where we are already on the system stack, it is + necessary to reset the (system) stack pointer so a series of consecutive + interrupts in the idle state do not keep moving the SP downward. + */ + + // sp = _tx_thread_system_stack_ptr; + movi a13, _tx_thread_system_stack_ptr + mov a0, a12 /* retrieve return address */ + l32i sp, a13, 0 + + ret + // } + +.L_tx_thread_nested_save: + /* Nested interrupt condition. */ + /* Save the rest of the interrupted context and return to ISR. */ + call0 _xt_context_save + + mov a0, a12 /* retrieve return address */ + ret + +// } + +#endif /* XCHAL_HAVE_XEA2 */ + diff --git a/ports/xtensa/xcc/src/tx_thread_interrupt_control.c b/ports/xtensa/xcc/src/tx_thread_interrupt_control.c new file mode 100644 index 00000000..1a9d42c3 --- /dev/null +++ b/ports/xtensa/xcc/src/tx_thread_interrupt_control.c @@ -0,0 +1,81 @@ +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#include "tx_api.h" +#include "xtensa_rtos.h" + + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* NOTE: In earlier versions this was implemented in assembly. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +UINT _tx_thread_interrupt_control(UINT new_posture) +{ +#if XCHAL_HAVE_XEA2 + UINT ret = XT_RSIL(15); + + XT_WSR_PS((ret & ~0xF) | (new_posture & 0xF)); + XT_RSYNC(); + return ret & 0xF; +#else + UINT ret = xthal_disable_interrupts(); + + xthal_restore_interrupts(new_posture); + return ret; +#endif +} + diff --git a/ports/xtensa/xcc/src/tx_thread_schedule.S b/ports/xtensa/xcc/src/tx_thread_schedule.S new file mode 100644 index 00000000..287c3530 --- /dev/null +++ b/ports/xtensa/xcc/src/tx_thread_schedule.S @@ -0,0 +1,253 @@ +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#include "tx_port.h" +#include "xtensa_rtos.h" +#include "tx_api_asm.h" + + .text + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function waits for a thread control block pointer to appear in */ +/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +/* in the variable, the corresponding thread is resumed. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +// VOID _tx_thread_schedule(VOID) +// { + .globl _tx_thread_schedule + .type _tx_thread_schedule,@function + .align 4 +_tx_thread_schedule: + +#if XCHAL_HAVE_XEA3 + + /* Skip "entry" - nothing to save, never returns. */ + + movi a2, PS_STACK_KERNEL | PS_DI /* Set PS.STACK = Kernel and */ + movi a3, PS_STACK_MASK | PS_DI_MASK /* disable interrupts. */ + xps a2, a3 + +#ifdef __XTENSA_CALL0_ABI__ + mov a15, a1 /* Dispatch code expects a15 = old SP */ +#endif + + movi a0, _xt_dispatch + 3 /* Jump to dispatch code. It will */ + ret /* check for ready thread or idle */ + /* and handle accordingly. */ + + ill /* Should never get back here. */ + +#else + + /* + Note on Windowed ABI: + Callers of this don't expect it to return to them. Most use 'call0'. + The only windowed (C) caller is _tx_initialize_kernel_enter(). + There are no args or results to pass. So we don't really care if the + window gets rotated. We can omit the 'entry' altogether and avoid the + need for a special "no entry" entrypoint to this function. + */ + + #ifdef XT_ENABLE_TIMING_TEST_HACK + /* For timing_test "TS" numbers. INTERNAL USE ONLY. */ + /* Always use CALL0. We may be here with windowing disabled. */ + .extern scheduler_return + call0 scheduler_return + #endif + + /* + Wait for a thread to execute (Idle Loop). + First ensure interrupts (except hi-pri) are disabled so result + of reading _tx_thread_execute_ptr can't change before testing. + While there's no thread ready, enable interrupts and wait in a + low power state, then disable interrupts and repeat the test. + */ + // do + // { + movi a3, _tx_thread_execute_ptr +.L_tx_thread_schedule_loop: /* Idle Loop. */ + XT_INTS_DISABLE(a2) /* disable interrupts if not already */ + l32i a2, a3, 0 /* a2 = _tx_thread_execute_ptr */ + bnez a2, .L_tx_thread_schedule_ready + waiti 0 /* enable interrupts and wait for */ + /* interrupt in low power state */ + j .L_tx_thread_schedule_loop + + // } + // while(_tx_thread_execute_ptr == TX_NULL); + +.L_tx_thread_schedule_ready: + + /* Yes! We have a thread to execute. Lockout interrupts and + transfer control to it. Interrupts are already disabled. */ + + /* Setup the current thread pointer. */ + // _tx_thread_current_ptr = _tx_thread_execute_ptr; + movi a3, _tx_thread_current_ptr + l32i a0, a2, tx_thread_run_count + s32i a2, a3, 0 /* a2 = _tx_thread_current_ptr (TCB) */ + + /* Increment the run count for this thread. */ + // _tx_thread_current_ptr -> tx_thread_run_count++; + addi a3, a0, 1 + movi a0, _tx_timer_time_slice + s32i a3, a2, tx_thread_run_count + + /* Setup time-slice, if present. */ + // _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice; + l32i a3, a2, tx_thread_time_slice + s32i a3, a0, 0 + + #ifdef TX_THREAD_SAFE_CLIB + // Load library-specific global context ptr address. */ + + #if XSHAL_CLIB == XTHAL_CLIB_NEWLIB + movi a0, _impure_ptr + #elif XSHAL_CLIB == XTHAL_CLIB_XCLIB + movi a0, _reent_ptr + #else + #error TX_THREAD_SAFE_CLIB defined with unsupported C library. + #endif + + l32i a3, a2, tx_thread_clib_ptr + s32i a3, a0, 0 /* point to thread's reent struct */ + #endif + + /* Switch to the thread's stack. */ + // SP = _tx_thread_execute_ptr -> tx_thread_stack_ptr; + l32i sp, a2, tx_thread_stack_ptr + + #ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + /* Call the thread entry function to indicate the thread is executing. */ + #ifdef __XTENSA_CALL0_ABI__ + call0 _tx_execution_thread_enter + #else + call8 _tx_execution_thread_enter + #endif + #endif + + /* Determine if an interrupt frame or a synchronous task suspension frame + is present. */ + l32i a3, a2, tx_thread_solicited + bnez a3, .L_tx_thread_synch_return + +.Ln_tx_thread_asynch_return: + + #if XCHAL_CP_NUM > 0 + /* Restore thread's CPENABLE (enable co-processors this thread owns). */ + l16ui a3, a2, tx_thread_cp_state + XT_CPENABLE + wsr a3, CPENABLE + #endif + + /* Here we return from unsolicited entry with an interrupt stack frame. */ + call0 _xt_context_restore + + /* In Call0 ABI, restore callee-saved regs (A12, A13 already restored). */ + #ifdef __XTENSA_CALL0_ABI__ + l32i a14, sp, XT_STK_A14 + l32i a15, sp, XT_STK_A15 + #endif + + #if XCHAL_CP_NUM > 0 + rsync /* ensure wsr.CPENABLE has completed */ + #endif + + /* + This does not return to its caller, but to the selected thread. + Must return via the exit dispatcher corresponding to the entrypoint + from which this was called. Interruptee's A0, A1, PS, PC are restored + and the interrupt stack frame is deallocated in the exit dispatcher. + */ + l32i a0, sp, XT_STK_EXIT + ret + +.L_tx_thread_synch_return: + + /* Here we return from a solicited entry with a solicited stack frame. */ + movi a0, TX_FALSE + l32i a3, sp, XT_STK_PS + s32i a0, a2, tx_thread_solicited + + #ifdef __XTENSA_CALL0_ABI__ + l32i a12, sp, XT_STK_A12 + l32i a13, sp, XT_STK_A13 + l32i a14, sp, XT_STK_A14 + l32i a15, sp, XT_STK_A15 + #endif + + l32i a0, sp, XT_STK_PC /* return address */ + + #if XCHAL_CP_NUM > 0 + /* CPENABLE should already be clear (it was cleared on entry to kernel). */ + rsync /* ensure wsr.CPENABLE has completed */ + #endif + + wsr a3, PS /* no need to sync PS, delay is OK */ + + /* This does not return to its caller, but to the selected thread. */ + #ifdef __XTENSA_CALL0_ABI__ + /* 'addi sp, sp, imm' could turn into 'addmi, addi' sequence and make */ + /* the sp briefly point to an illegal stack location. Avoid that. */ + addi a2, sp, XT_STK_FRMSZ + mov sp, a2 + ret + #else + retw + #endif + +#endif /* XCHAL_HAVE_XEA3 */ +// } + diff --git a/ports/xtensa/xcc/src/tx_thread_stack_build.S b/ports/xtensa/xcc/src/tx_thread_stack_build.S new file mode 100644 index 00000000..688e947d --- /dev/null +++ b/ports/xtensa/xcc/src/tx_thread_stack_build.S @@ -0,0 +1,158 @@ +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#include "xtensa_rtos.h" +#include "tx_api_asm.h" + + .text + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a stack frame on the supplied thread's stack. */ +/* The stack frame looks like an interrupt frame or a solicited frame */ +/* depending on the exception architecture of the target hardware. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + .globl _tx_thread_stack_build + .type _tx_thread_stack_build,@function + .align 4 +_tx_thread_stack_build: + + ENTRY0 + + /* Get logical base of stack area (top). */ + l32i a5, a2, tx_thread_stack_end /* get top-1 of stack area */ + addi a5, a5, 1 /* undo the -1 */ + srli a5, a5, 4 /* force 16-byte alignment */ + slli a5, a5, 4 /* a5 = post-dispatch SP (frame top) */ + + /* Allocate space for the frame (frame size is already 16-byte aligned). */ + addi a4, a5, -XT_STK_FRMSZ /* a4 = pre-dispatch SP (frame base) */ + + /* Set the thread's SP. */ + s32i a4, a2, tx_thread_stack_ptr + +#if !XCHAL_HAVE_XEA2 + addi a4, a4, XT_STK_XTRA_SZ /* a4 = base of exception frame */ +#endif + + /* Clear the entire frame. (XEA3: only exception frame) */ + movi a6, 0 /* a6 = 0 */ + mov a7, a4 /* a7 = ptr to current word */ +1: s32i a6, a7, 0 /* clear current word */ + addi a7, a7, 4 /* point to next word */ + bltu a7, a5, 1b /* repeat until frame top */ + +#if XCHAL_HAVE_XEA2 + s32i a5, a4, XT_STK_A1 /* save post-dispatch SP in frame */ +#endif + + /* Indicate a solicited or interrupted stack frame. */ +#if XCHAL_HAVE_XEA2 + movi a7, 0 /* interrupted */ +#else + movi a7, 0 /* solicited */ +#endif + s32i a7, a2, tx_thread_solicited + + /* + Terminate GDB backtrace in this thread at the "return function" by ensuring + it's A0 == 0. Since frame was cleared, don't need to do this explicitly. + s32i a6, a4, XT_STK_A0 + */ + + /* Set the return address to the return function. */ + /* Start thread via user exception exit dispatcher (could use any). */ +#if XCHAL_HAVE_XEA2 + movi a5, _xt_user_exit + s32i a5, a4, XT_STK_EXIT +#else + movi a5, 0 + s32i a5, a4, XT_STK_ATOMCTL +#endif + + s32i a3, a4, XT_STK_PC + + /* + Set thread's initial PS for C code, all int levels enabled. + XEA2: Since we dispatch via level 1 (_xt_user_exit), must set PS.EXCM, + which will be cleared by 'rfe' after the dispatcher, to prevent + interrupts happening when PS is restored during the exit dispatcher. + XEA3: nothing special, other than setting the thread stack type. + */ +#if XCHAL_HAVE_XEA2 + #ifdef __XTENSA_CALL0_ABI__ + movi a6, PS_UM | PS_EXCM + #else + movi a6, PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1) /* pretend 'call4' */ + #endif +#else + movi a6, PS_STACK_FIRSTKER +#endif + s32i a6, a4, XT_STK_PS + +#if XCHAL_HAVE_XEA2 + #ifdef XT_USE_SWPRI + /* Set the initial virtual priority mask value to all 1's */ + movi a3, -1 + s32i a3, a4, XT_STK_VPRI + #endif +#endif + + RET0 + +// } + diff --git a/ports/xtensa/xcc/src/tx_thread_system_return.S b/ports/xtensa/xcc/src/tx_thread_system_return.S new file mode 100644 index 00000000..e90109c1 --- /dev/null +++ b/ports/xtensa/xcc/src/tx_thread_system_return.S @@ -0,0 +1,287 @@ +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#include "xtensa_rtos.h" +#include "tx_api_asm.h" + + .text + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the system. Only a minimal context */ +/* is saved since the compiler assumes temp registers are going to get */ +/* slicked by a function call anyway. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +// VOID _tx_thread_system_return(VOID) +// { + .globl _tx_thread_system_return + .type _tx_thread_system_return,@function + .align 4 +_tx_thread_system_return: + /* + Set up solicited stack frame and save minimal context (including a0). + Since this is solicited, no need to save regs compiler doesn't preserve. + */ + +#if XCHAL_HAVE_XEA3 + #ifdef __XTENSA_CALL0_ABI__ + addi sp, sp, -16 + #else + entry sp, 48 + #endif + s32i a0, sp, 0 /* save return address */ +#else + #ifdef __XTENSA_CALL0_ABI__ + addi a2, sp, -XT_STK_FRMSZ /* avoid addi/addmi relaxation that */ + mov sp, a2 /* might temporarily move sp up */ + #else + entry sp, XT_STK_FRMSZ + #endif +#endif + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + /* Call the thread exit function to indicate the thread is no longer executing. */ +#ifdef __XTENSA_CALL0_ABI__ + call0 _tx_execution_thread_exit +#else + call8 _tx_execution_thread_exit +#endif +#endif + +#if XCHAL_HAVE_XEA3 + +#ifdef __XTENSA_CALL0_ABI__ + +#else + ssai 0 + spillw /* spill all registers */ +#endif + + /* + Save register state into exception frame. This is safe to do with + interrupts enabled, but we will have to revert SP to point above + the exception frame because that is what the dispatch code expects. + Must disable interrupts before that. + */ + + movi a0, .Lret + rsr.ps a2 + addi sp, sp, -XT_STK_XFRM_SZ + s32i a0, sp, XT_STK_PC /* save return PC */ + s32i a2, sp, XT_STK_PS /* save PS */ +#ifdef __XTENSA_CALL0_ABI__ + s32i a12, sp, XT_STK_A12 /* callee-saved registers */ + s32i a13, sp, XT_STK_A13 + s32i a14, sp, XT_STK_A14 + s32i a15, sp, XT_STK_A15 +#endif + + movi a2, PS_STACK_KERNEL | PS_DI /* Set PS.STACK = Kernel and */ + movi a8, PS_STACK_MASK | PS_DI_MASK /* disable interrupts. */ + xps a2, a8 + + movi a3, _tx_thread_current_ptr /* a3 = &_tx_thread_current_ptr */ + movi a2, TX_TRUE + l32i a4, a3, 0 /* a4 = _tx_thread_current_ptr */ + movi a5, 0 + s32i a2, a4, tx_thread_solicited /* mark as solicited switch */ + +#if XCHAL_CP_NUM > 0 + /* Save coprocessor callee-saved state (if any). At this point CPENABLE */ + /* should still reflect which CPs were in use (enabled). */ + call0 _xt_coproc_savecs + + /* Clear CPENABLE and give up all co-procs. */ + s16i a5, a4, tx_thread_cp_state + XT_CPENABLE + wsr a5, CPENABLE /* disable all co-processors */ +#endif + + addi sp, sp, XT_STK_XFRM_SZ /* restore SP */ + addi a2, sp, -XT_STK_FRMSZ + s32i a2, a4, tx_thread_stack_ptr /* Save SP in TCB */ + +#ifdef __XTENSA_CALL0_ABI__ + mov a15, sp /* Dispatch code expects a15 = old a1 */ +#endif + + s32i a5, a3, 0 /* Clear _tx_thread_current_ptr */ + + movi a0, _xt_dispatch + 3 /* Jump to dispatch code */ + ret + + /* Execution returns here. Interrupts should be disabled. */ + /* NOTE: we expect original SP to have been restored. */ + + .align 4 + +.Lret: + addi sp, sp, -XT_STK_XFRM_SZ /* Prepare to restore state */ + l32i a2, sp, XT_STK_PS /* Retrieve PS value */ +#ifdef __XTENSA_CALL0_ABI__ + l32i a12, sp, XT_STK_A12 /* Callee-saved registers */ + l32i a13, sp, XT_STK_A13 + l32i a14, sp, XT_STK_A14 + l32i a15, sp, XT_STK_A15 +#endif + addi sp, sp, XT_STK_XFRM_SZ + wsr.ps a2 /* Safe to enable interrupts */ + rsync + +#ifdef __XTENSA_CALL0_ABI__ + l32i a0, sp, 0 + addi sp, sp, 16 + ret +#else + l32i a0, sp, 0 + retw +#endif + +#else /* XEA1 or XEA2 */ + + rsr a2, PS + s32i a0, sp, XT_STK_PC + s32i a2, sp, XT_STK_PS + #ifdef __XTENSA_CALL0_ABI__ + s32i a12, sp, XT_STK_A12 + s32i a13, sp, XT_STK_A13 + s32i a14, sp, XT_STK_A14 + s32i a15, sp, XT_STK_A15 + #else + /* + Spill register windows. Calling xthal_window_spill() causes extra spills and + reloads, so we set things up to call the _nw version instead to save cycles. + */ + movi a6, ~(PS_WOE_MASK|PS_INTLEVEL_MASK) // (using a6 ensures any window using this a4..a7 is spilled) + mov a4, a0 // save a0 + and a2, a2, a6 // clear WOE, INTLEVEL + addi a2, a2, XCHAL_EXCM_LEVEL // set INTLEVEL + wsr a2, PS + rsync + call0 xthal_window_spill_nw + l32i a0, sp, XT_STK_PS + wsr a0, PS // Restore PS value + rsync + #endif + + #if XCHAL_CP_NUM > 0 + /* Save coprocessor callee-saved state (if any). At this point CPENABLE */ + /* should still reflect which CPs were in use (enabled). */ + call0 _xt_coproc_savecs + #endif + + /* + We do not return directly from this function to its caller. + Register usage from here on: + a0 = scratch (return address has been saved in stack frame) + a1 = stack ptr (thread, then system) + a2 = &_tx_thread_current_ptr + a3 = _tx_thread_current_ptr (thread control block) + a4 = &_tx_timer_time_slice + */ + + /* Lock out interrupts (except hi-pri). */ + /* Grab thread control block of current thread. */ + movi a2, _tx_thread_current_ptr /* a2 = &_tx_thread_current_ptr */ + XT_INTS_DISABLE(a0) + l32i a3, a2, 0 /* a3 points to TCB */ + + /* Mark as having solicited entry to kernel (used on exit). */ + movi a0, TX_TRUE + s32i a0, a3, tx_thread_solicited + + /* Save current stack and switch to system stack. */ + // _tx_thread_current_ptr -> tx_thread_stack_ptr = SP; + // SP = _tx_thread_system_stack_ptr; + movi a5, _tx_thread_system_stack_ptr /* a5 = & system stack ptr */ + s32i sp, a3, tx_thread_stack_ptr + movi a4, _tx_timer_time_slice /* a4 = &_tx_timer_time_slice */ + l32i sp, a5, 0 /* sp = system stack ptr */ + + /* Determine if the time-slice is active. */ + // if (_tx_timer_time_slice) + // { + l32i a0, a4, 0 + beqz a0, .L_tx_thread_dont_save_ts + + /* Save time-slice for the thread and clear current time-slice. */ + // _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; + // _tx_timer_time_slice = 0; + s32i a0, a3, tx_thread_time_slice + movi a0, 0 /* a0 == 0 == TX_NULL */ + s32i a0, a4, 0 + + // } + +.L_tx_thread_dont_save_ts: + + /* Clear the current thread pointer. */ + // _tx_thread_current_ptr = TX_NULL; + s32i a0, a2, 0 /* a0 == 0 == TX_NULL */ + + #if XCHAL_CP_NUM > 0 + /* Clear CPENABLE and give up all co-procs. */ + s16i a0, a3, tx_thread_cp_state + XT_CPENABLE + wsr a0, CPENABLE /* disable all co-processors */ + #endif + + /* + Return via the scheduler. + Scheduler returns eventually to this function's caller as if called by it. + */ + call0 _tx_thread_schedule /* never returns here */ + +#endif /* XCHAL_HAVE_XEA3 */ +// } + diff --git a/ports/xtensa/xcc/src/tx_timer_interrupt.S b/ports/xtensa/xcc/src/tx_timer_interrupt.S new file mode 100644 index 00000000..6fcc5d36 --- /dev/null +++ b/ports/xtensa/xcc/src/tx_timer_interrupt.S @@ -0,0 +1,277 @@ +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#include "xtensa_rtos.h" +#include "tx_api_asm.h" + +#ifndef TX_NO_TIMER + + .text + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* interrupt context save/restore functions are called along with the */ +/* expiration functions. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +// VOID _tx_timer_interrupt(VOID) +// { + .globl _tx_timer_interrupt + .type _tx_timer_interrupt,@function + .align 4 +_tx_timer_interrupt: + + #ifdef __XTENSA_CALL0_ABI__ + /* Define local variable spill offsets in stack frame for Call0 ABI. */ + #define __tx_timer_interrupt_a0 0 /* ENTRY()/RET() saves/restores */ + #define __tx_timer_interrupt_a2 4 /* preserve a2 */ + #define __tx_timer_interrupt_a3 8 /* preserve a3 */ + #endif + + ENTRY(16) + + .globl tx_timer_user_isr + .weak tx_timer_user_isr + movi a2, tx_timer_user_isr + beqz a2, 1f + #ifdef __XTENSA_CALL0_ABI__ + callx0 a2 + #else + callx8 a2 + #endif +1: + + /* + Xtensa timers work by comparing a cycle counter with a preset value. + Once the match occurs an interrupt is generated, and the handler has + to set a new cycle count into the comparator. To avoid clock drift + due to interrupt latency, the new cycle count is computed from the old, + not the time the interrupt was serviced. However if a timer interrupt + is ever serviced more than one tick late, it is necessary to process + multiple ticks until the new cycle count is in the future, otherwise + the next timer interrupt would not occur until after the cycle counter + had wrapped (2^32 cycles later). + + do { + ticks++; + old_ccompare = read_ccompare_i(); + write_ccompare_i( old_ccompare + divisor ); + service one tick; + diff = read_ccount() - old_ccompare; + } while ( diff > divisor ); + */ + +.L_tx_timer_catchup: + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + movi a2, _tx_timer_system_clock /* a2 = &_tx_timer_system_clock */ + l32i a3, a2, 0 /* a3 = _tx_timer_system_clock++ */ + addi a3, a3, 1 + s32i a3, a2, 0 + + /* Update the timer comparator for the next tick. */ + #ifdef XT_CLOCK_FREQ + movi a2, XT_TICK_DIVISOR /* a2 = comparator increment */ + #else + movi a3, _xt_tick_divisor + l32i a2, a3, 0 /* a2 = comparator increment */ + #endif + rsr a3, XT_CCOMPARE /* a3 = old comparator value */ + add a4, a3, a2 /* a4 = new comparator value */ + wsr a4, XT_CCOMPARE /* update comp. and clear interrupt */ + esync + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + movi a4, _tx_timer_time_slice /* a4 = &_tx_timer_time_slice */ + l32i a5, a4, 0 /* a5 = _tx_timer_time_slice */ + beqz a5, .L_tx_timer_no_time_slice + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + addi a5, a5, -1 + s32i a5, a4, 0 + + /* Check for expiration. */ + // if (_tx_timer_time_slice == 0) + bnez a5, .L_tx_timer_no_time_slice + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + movi a4, _tx_timer_expired_time_slice + movi a5, TX_TRUE + s32i a5, a4, 0 + + // } + +.L_tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + movi a4, _tx_timer_current_ptr /* a4 = &_tx_timer_current_ptr */ + l32i a5, a4, 0 /* a5 = _tx_timer_current_ptr */ + l32i a6, a5, 0 /* a6 = *_tx_timer_current_ptr */ + beqz a6, .L_tx_timer_no_timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + movi a6, _tx_timer_expired + movi a7, TX_TRUE + s32i a7, a6, 0 + j .L_tx_timer_done + + // } + // else + // { + +.L_tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + movi a6, _tx_timer_list_end + l32i a6, a6, 0 /* a6 = _tx_timer_list_end */ + addi a5, a5, 4 /* a5 = ++_tx_timer_current_ptr */ + bne a5, a6, .L_tx_timer_skip_wrap + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + movi a6, _tx_timer_list_start + l32i a5, a6, 0 /* a5 = _tx_timer_list_start */ + +.L_tx_timer_skip_wrap: + + s32i a5, a4, 0 /* _tx_timer_current_ptr = a5 */ + // } + +.L_tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + #ifdef __XTENSA_CALL0_ABI__ + /* Preserve a2 and a3 across calls. */ + s32i a2, sp, __tx_timer_interrupt_a2 + s32i a3, sp, __tx_timer_interrupt_a3 + #endif + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + movi a4, _tx_timer_expired + l32i a5, a4, 0 + beqz a5, .L_tx_timer_dont_activate + + /* Call the timer expiration processing. */ + // _tx_timer_expiration_process(); + #ifdef __XTENSA_CALL0_ABI__ + call0 _tx_timer_expiration_process + #else + call8 _tx_timer_expiration_process + #endif + + // } + +.L_tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + movi a4, _tx_timer_expired_time_slice + l32i a5, a4, 0 + beqz a5, .L_tx_timer_not_ts_expiration + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + #ifdef __XTENSA_CALL0_ABI__ + call0 _tx_thread_time_slice + #else + call8 _tx_thread_time_slice + #endif + + // } + +.L_tx_timer_not_ts_expiration: + + #ifdef __XTENSA_CALL0_ABI__ + /* Restore a2 and a3. */ + l32i a2, sp, __tx_timer_interrupt_a2 + l32i a3, sp, __tx_timer_interrupt_a3 + #endif + + // } + +.Ln_tx_timer_nothing_expired: + + /* Check if we need to process more ticks to catch up. */ + esync /* ensure comparator update complete */ + rsr a4, CCOUNT /* a4 = cycle count */ + sub a4, a4, a3 /* diff = ccount - old comparator */ + blt a2, a4, .L_tx_timer_catchup /* repeat while diff > divisor */ + + RET(16) + +// } + +#endif /* TX_NO_TIMER */ + diff --git a/ports/xtensa/xcc/src/tx_xtensa_stack_error_handler.c b/ports/xtensa/xcc/src/tx_xtensa_stack_error_handler.c new file mode 100644 index 00000000..2d14dd7a --- /dev/null +++ b/ports/xtensa/xcc/src/tx_xtensa_stack_error_handler.c @@ -0,0 +1,123 @@ +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Support for Xtensa applications */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#include "tx_user.h" + +#ifdef TX_ENABLE_STACK_CHECKING + +/* Include necessary system files. */ + +#include "tx_api.h" + +#include "xtensa_rtos.h" +#ifdef XT_BOARD +#include <xtensa/xtbsp.h> +#endif +#ifdef XT_SIMULATOR +#include <xtensa/simcall.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* Callback to notify of a stack overflow when registered with */ +/* tx_stack_error_notify and stack checking is enabled (ThreadX */ +/* is compiled with TX_ENABLE_STACK_CHECKING defined). */ +/* */ +/* The handler notifies the user in any/all of the following ways: */ +/* - A message via the simulator (extremely reliable, simulator only). */ +/* - A message on the board's display (emulation board only). */ +/* - A message to stdout (uses low-level write to avoid printf which */ +/* is large and would trash state the user might want to examine). */ +/* The most reliable methods are done first. Several might work. */ +/* */ +/* After notifying the user as best it can, the handler stops the */ +/* application in the most reliable of the following ways: */ +/* - Passes control to the debugger (if attached). */ +/* - Terminates the simulation (simulator only). */ +/* - Panics. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + +VOID _tx_xtensa_stack_error_handler(TX_THREAD * thread) +{ + #ifdef XT_SIMULATOR + register int32_t sc __asm__ ("a2") = SYS_log_msg; + register char * msg __asm__ ("a3") + = "**** Stack overflow in thread 0x%08x.\n"; + register TX_THREAD * thd __asm__ ("a4") = thread; + __asm__ volatile ("simcall" :: "a" (sc), "a" (msg), "a" (thd) ); + #endif + + #ifdef XT_BOARD + xtbsp_display_string("StkOflow"); + #endif + + write(1, "**** Stack overflow in thread \"", 31); + write(1, thread->tx_thread_name, strlen(thread->tx_thread_name)); + write(1, "\"\n", 2); + + #ifdef XT_SIMULATOR + sc = SYS_gdb_abort; + __asm__ volatile ("simcall"); /* control to debugger or exit */ + #else + __asm__ volatile ("break 1, 15"); /* control to debugger or panic */ + #endif +} + +#endif /* TX_ENABLE_STACK_CHECKING */ + diff --git a/ports/xtensa/xcc/src/xtensa_context.S b/ports/xtensa/xcc/src/xtensa_context.S new file mode 100644 index 00000000..af3138aa --- /dev/null +++ b/ports/xtensa/xcc/src/xtensa_context.S @@ -0,0 +1,433 @@ +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* XTENSA CONTEXT SAVE AND RESTORE ROUTINES */ +/* */ +/* Low-level functions for handling generic context save and restore of */ +/* registers not specifically addressed by the interrupt vectors and */ +/* handlers. Those registers (not handled by these functions) are PC, PS, */ +/* A0, A1 (SP). Except for the calls to RTOS functions, this code is */ +/* generic to Xtensa. */ +/* */ +/* Note that in Call0 ABI, interrupt handlers are expected to preserve */ +/* the callee-save regs (A12-A15), which is always the case if the */ +/* handlers are coded in C. However A12, A13 are made available as */ +/* scratch registers for interrupt dispatch code, so are presumed saved */ +/* anyway, and are always restored even in Call0 ABI. Only A14, A15 are */ +/* truly handled as callee-save regs. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + + +#include "xtensa_rtos.h" + +#ifdef XT_USE_OVLY +#include <xtensa/overlay_os_asm.h> +#endif + + .text + +#if XCHAL_HAVE_XEA2 + +/*************************************************************************** + + _xt_context_save + + !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !! + +Saves all Xtensa processor state except PC, PS, A0, A1 (SP), A12, A13, in the +interrupt stack frame defined in xtensa_rtos.h. +Its counterpart is _xt_context_restore (which also restores A12, A13). + +Caller is expected to have saved PC, PS, A0, A1 (SP), A12, A13 in the frame. +This function preserves A12 & A13 in order to provide the caller with 2 scratch +regs that need not be saved over the call to this function. The choice of which +2 regs to provide is governed by xthal_window_spill_nw and xthal_save_extra_nw, +to avoid moving data more than necessary. Caller can assign regs accordingly. + +Entry Conditions: + A0 = Return address in caller. + A1 = Stack pointer of interrupted thread or handler ("interruptee"). + Original A12, A13 have already been saved in the interrupt stack frame. + Other processor state except PC, PS, A0, A1 (SP), A12, A13, is as at the + point of interruption. + If windowed ABI, PS.EXCM = 1 (exceptions disabled). + +Exit conditions: + A0 = Return address in caller. + A1 = Stack pointer of interrupted thread or handler ("interruptee"). + A12, A13 as at entry (preserved). + If windowed ABI, PS.EXCM = 1 (exceptions disabled). + +***************************************************************************/ + + .global _xt_context_save + .type _xt_context_save,@function + .align 4 +_xt_context_save: + + s32i a2, sp, XT_STK_A2 + s32i a3, sp, XT_STK_A3 + s32i a4, sp, XT_STK_A4 + s32i a5, sp, XT_STK_A5 + s32i a6, sp, XT_STK_A6 + s32i a7, sp, XT_STK_A7 + s32i a8, sp, XT_STK_A8 + s32i a9, sp, XT_STK_A9 + s32i a10, sp, XT_STK_A10 + s32i a11, sp, XT_STK_A11 + + /* + Call0 ABI callee-saved regs a12-15 do not need to be saved here. + a12-13 are the caller's responsibility so it can use them as scratch. + So only need to save a14-a15 here for Windowed ABI (not Call0). + */ + #ifndef __XTENSA_CALL0_ABI__ + s32i a14, sp, XT_STK_A14 + s32i a15, sp, XT_STK_A15 + #endif + + rsr a3, SAR + s32i a3, sp, XT_STK_SAR + + #if XCHAL_HAVE_LOOPS + rsr a3, LBEG + s32i a3, sp, XT_STK_LBEG + rsr a3, LEND + s32i a3, sp, XT_STK_LEND + rsr a3, LCOUNT + s32i a3, sp, XT_STK_LCOUNT + #endif + + #if XCHAL_HAVE_EXCLUSIVE + /* Save and clear state of ATOMCTL */ + movi a3, 0 + getex a3 + s32i a3, sp, XT_STK_ATOMCTL + #endif + + #if XT_USE_SWPRI + /* Save virtual priority mask */ + movi a3, _xt_vpri_mask + l32i a3, a3, 0 + s32i a3, sp, XT_STK_VPRI + #endif + + #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__) + mov a9, a0 /* preserve ret addr */ + #endif + + #ifndef __XTENSA_CALL0_ABI__ + /* + To spill the reg windows, temp. need pre-interrupt stack ptr and a4-15. + Need to save a9,12,13 temporarily (in frame temps) and recover originals. + Interrupts need to be disabled below XCHAL_EXCM_LEVEL and window overflow + and underflow exceptions disabled (assured by PS.EXCM == 1). + */ + s32i a12, sp, XT_STK_TMP0 /* temp. save stuff in stack frame */ + s32i a13, sp, XT_STK_TMP1 + s32i a9, sp, XT_STK_TMP2 + + /* + Save the overlay state if we are supporting overlays. Since we just saved + three registers, we can conveniently use them here. Note that as of now, + overlays only work for windowed calling ABI. + */ + #ifdef XT_USE_OVLY + l32i a9, sp, XT_STK_PC /* recover saved PC */ + _xt_overlay_get_state a9, a12, a13 + s32i a9, sp, XT_STK_OVLY /* save overlay state */ + #endif + + l32i a12, sp, XT_STK_A12 /* recover original a9,12,13 */ + l32i a13, sp, XT_STK_A13 + l32i a9, sp, XT_STK_A9 + addi sp, sp, XT_STK_FRMSZ /* restore the interruptee's SP */ + call0 xthal_window_spill_nw /* preserves only a4,5,8,9,12,13 */ + addi sp, sp, -XT_STK_FRMSZ + l32i a12, sp, XT_STK_TMP0 /* recover stuff from stack frame */ + l32i a13, sp, XT_STK_TMP1 + l32i a9, sp, XT_STK_TMP2 + #endif + + #if XCHAL_EXTRA_SA_SIZE > 0 + /* + NOTE: Normally the xthal_save_extra_nw macro only affects address + registers a2-a5. It is theoretically possible for Xtensa processor + designers to write TIE that causes more address registers to be + affected, but it is generally unlikely. If that ever happens, + more registers need to be saved/restored around this macro invocation. + Here we assume a9,12,13 are preserved. + Future Xtensa tools releases might limit the regs that can be affected. + */ + addi a2, sp, XT_STK_EXTRA /* where to save it */ + # if XCHAL_EXTRA_SA_ALIGN > 16 + movi a3, -XCHAL_EXTRA_SA_ALIGN + and a2, a2, a3 /* align dynamically >16 bytes */ + # endif + call0 xthal_save_extra_nw /* destroys a0,2,3,4,5 */ + #endif + + #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__) + mov a0, a9 /* retrieve ret addr */ + #endif + + ret + +/******************************************************************************* + +_xt_context_restore + + !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !! + +Restores all Xtensa processor state except PC, PS, A0, A1 (SP) (and in Call0 +ABI, A14, A15 which are preserved by all interrupt handlers) from an interrupt +stack frame defined in xtensa_rtos.h . +Its counterpart is _xt_context_save (whose caller saved A12, A13). + +Caller is responsible to restore PC, PS, A0, A1 (SP). + +Entry Conditions: + A0 = Return address in caller. + A1 = Stack pointer of interrupted thread or handler ("interruptee"). + +Exit conditions: + A0 = Return address in caller. + A1 = Stack pointer of interrupted thread or handler ("interruptee"). + Other processor state except PC, PS, A0, A1 (SP), is as at the point + of interruption. + +*******************************************************************************/ + + .global _xt_context_restore + .type _xt_context_restore,@function + .align 4 +_xt_context_restore: + + #if XCHAL_EXTRA_SA_SIZE > 0 + /* + NOTE: Normally the xthal_restore_extra_nw macro only affects address + registers a2-a5. It is theoretically possible for Xtensa processor + designers to write TIE that causes more address registers to be + affected, but it is generally unlikely. If that ever happens, + more registers need to be saved/restored around this macro invocation. + Here we only assume a13 is preserved. + Future Xtensa tools releases might limit the regs that can be affected. + */ + mov a13, a0 /* preserve ret addr */ + addi a2, sp, XT_STK_EXTRA /* where to find it */ + # if XCHAL_EXTRA_SA_ALIGN > 16 + movi a3, -XCHAL_EXTRA_SA_ALIGN + and a2, a2, a3 /* align dynamically >16 bytes */ + # endif + call0 xthal_restore_extra_nw /* destroys a0,2,3,4,5 */ + mov a0, a13 /* retrieve ret addr */ + #endif + + #if XCHAL_HAVE_LOOPS + l32i a2, sp, XT_STK_LBEG + l32i a3, sp, XT_STK_LEND + wsr a2, LBEG + l32i a2, sp, XT_STK_LCOUNT + wsr a3, LEND + wsr a2, LCOUNT + #endif + + #if XCHAL_HAVE_EXCLUSIVE + /* Restore state of ATOMCTL */ + l32i a2, sp, XT_STK_ATOMCTL + getex a2 + #endif + + #ifdef XT_USE_OVLY + /* + If we are using overlays, this is a good spot to check if we need + to restore an overlay for the incoming task. Here we have a bunch + of registers to spare. Note that this step is going to use a few + bytes of storage below SP (SP-20 to SP-32) if an overlay is going + to be restored. + */ + l32i a2, sp, XT_STK_PC /* retrieve PC */ + l32i a3, sp, XT_STK_PS /* retrieve PS */ + l32i a4, sp, XT_STK_OVLY /* retrieve overlay state */ + l32i a5, sp, XT_STK_A1 /* retrieve stack ptr */ + _xt_overlay_check_map a2, a3, a4, a5, a6 + s32i a2, sp, XT_STK_PC /* save updated PC */ + s32i a3, sp, XT_STK_PS /* save updated PS */ + #endif + + #ifdef XT_USE_SWPRI + /* Restore virtual interrupt priority and interrupt enable */ + movi a3, _xt_intdata + l32i a4, a3, 0 /* a4 = _xt_intenable */ + l32i a5, sp, XT_STK_VPRI /* a5 = saved _xt_vpri_mask */ + and a4, a4, a5 + wsr a4, INTENABLE /* update INTENABLE */ + s32i a5, a3, 4 /* restore _xt_vpri_mask */ + #endif + + l32i a3, sp, XT_STK_SAR + l32i a2, sp, XT_STK_A2 + wsr a3, SAR + l32i a3, sp, XT_STK_A3 + l32i a4, sp, XT_STK_A4 + l32i a5, sp, XT_STK_A5 + l32i a6, sp, XT_STK_A6 + l32i a7, sp, XT_STK_A7 + l32i a8, sp, XT_STK_A8 + l32i a9, sp, XT_STK_A9 + l32i a10, sp, XT_STK_A10 + l32i a11, sp, XT_STK_A11 + + /* + Call0 ABI callee-saved regs a12-15 do not need to be restored here. + However a12-13 were saved for scratch before XT_RTOS_INT_ENTER(), + so need to be restored anyway, despite being callee-saved in Call0. + */ + l32i a12, sp, XT_STK_A12 + l32i a13, sp, XT_STK_A13 + #ifndef __XTENSA_CALL0_ABI__ + l32i a14, sp, XT_STK_A14 + l32i a15, sp, XT_STK_A15 + #endif + + ret + +#endif /* XCHAL_HAVE_XEA3 */ + + +/******************************************************************************* + +_xt_coproc_init + +Initializes global co-processor management data, setting all co-processors +to "unowned". Leaves CPENABLE as it found it (does NOT clear it). + +Called during initialization of the RTOS, before any threads run. + +This may be called from normal Xtensa single-threaded application code which +might use co-processors. The Xtensa run-time initialization enables all +co-processors. They must remain enabled here, else a co-processor exception +might occur outside of a thread, which the exception handler doesn't expect. + +Entry Conditions: + Xtensa single-threaded run-time environment is in effect. + No thread is yet running. + +Exit conditions: + None. + +Obeys ABI conventions per prototype: + void _xt_coproc_init(void) + +*******************************************************************************/ + +#if XCHAL_CP_NUM > 0 + + .global _xt_coproc_init + .type _xt_coproc_init,@function + .align 4 +_xt_coproc_init: + ENTRY0 + + /* Initialize thread co-processor ownerships to 0 (unowned). */ + movi a2, _xt_coproc_owner_sa /* a2 = base of owner array */ + addi a3, a2, XCHAL_CP_MAX << 2 /* a3 = top+1 of owner array */ + movi a4, 0 /* a4 = 0 (unowned) */ +1: s32i a4, a2, 0 + addi a2, a2, 4 + bltu a2, a3, 1b + + RET0 + +#endif + + +/******************************************************************************* + +_xt_coproc_release + +Releases any and all co-processors owned by a given thread. The thread is +identified by it's co-processor state save area defined in xtensa_context.h . + +Must be called before a thread's co-proc save area is deleted to avoid +memory corruption when the exception handler tries to save the state. +May be called when a thread terminates or completes but does not delete +the co-proc save area, to avoid the exception handler having to save the +thread's co-proc state before another thread can use it (optimization). + +Entry Conditions: + A2 = Pointer to base of co-processor state save area. + +Exit conditions: + None. + +Obeys ABI conventions per prototype: + void _xt_coproc_release(void * coproc_sa_base) + +*******************************************************************************/ + +#if XCHAL_CP_NUM > 0 + + .global _xt_coproc_release + .type _xt_coproc_release,@function + .align 4 +_xt_coproc_release: + ENTRY0 /* a2 = base of save area */ + + movi a3, _xt_coproc_owner_sa /* a3 = base of owner array */ + addi a4, a3, XCHAL_CP_MAX << 2 /* a4 = top+1 of owner array */ + movi a5, 0 /* a5 = 0 (unowned) */ + +#if XCHAL_HAVE_XEA3 + movi a6, PS_DI + xps a6, a6 /* lock interrupts */ +#else + rsil a6, XCHAL_EXCM_LEVEL /* lock interrupts */ +#endif + +1: l32i a7, a3, 0 /* a7 = owner at a3 */ + bne a2, a7, 2f /* if (coproc_sa_base == owner) */ + s32i a5, a3, 0 /* owner = unowned */ +2: addi a3, a3, 1<<2 /* a3 = next entry in owner array */ + bltu a3, a4, 1b /* repeat until end of array */ + +3: + wsr a6, PS /* restore interrupts */ + rsync + + RET0 + +#endif + diff --git a/ports/xtensa/xcc/src/xtensa_coproc_handler.S b/ports/xtensa/xcc/src/xtensa_coproc_handler.S new file mode 100644 index 00000000..ee55e471 --- /dev/null +++ b/ports/xtensa/xcc/src/xtensa_coproc_handler.S @@ -0,0 +1,578 @@ +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* Xtensa coprocessor handling routines. This code is only active if */ +/* one or more coprocessors are present. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + + +#include <xtensa/config/specreg.h> +#include <xtensa/coreasm.h> + +#include "xtensa_context.h" +#include "xtensa_rtos.h" + + +#if XCHAL_CP_NUM > 0 + +//----------------------------------------------------------------------------- +// Coprocessor related state and precomputed values. +//----------------------------------------------------------------------------- + +// Table of coprocessor owners, identified by thread's CP save area pointer. +// Zero means coprocessor is not owned. + + .data + .global _xt_coproc_owner_sa + .align 16,,XCHAL_CP_MAX << 2 // minimize crossing cache boundaries +_xt_coproc_owner_sa: + .rept XCHAL_CP_MAX + .word 0 + .endr + +// Bitmask table for CP n's enable bit, indexed by coprocessor number. + + .section .rodata, "a" + .global _xt_coproc_mask + .align 16,,8 // try to keep it all in one cache line + .set i, 0 +_xt_coproc_mask: + .rept XCHAL_CP_MAX + .long (i<<16) | (1<<i) // upper 16-bits = i, lower = bitmask + .set i, i+1 + .endr + +// Offset to CP n save area in thread's CP save area. + + .global _xt_coproc_sa_offset + .align 16 // minimize crossing cache boundaries +_xt_coproc_sa_offset: + .word XT_CP0_SA, XT_CP1_SA, XT_CP2_SA, XT_CP3_SA + .word XT_CP4_SA, XT_CP5_SA, XT_CP6_SA, XT_CP7_SA + + +//----------------------------------------------------------------------------- +// _xt_coproc_handler +// +// Handles coprocessor exceptions and manages lazy context switching between +// multiple threads sharing the coprocessor(s). +// Register use: +// a0 - on entry, return address (must have been called via call0). +// a1 - pointing to valid exception stack frame. +// a2 - on entry, must hold coprocessor index. On exit, 0 if OK. +// a3-a15 - may all be used and trashed by this routine. +//----------------------------------------------------------------------------- + + .text + .align 4 + .global _xt_coproc_handler + +_xt_coproc_handler: + + mov a7, a0 // a7 = return address + mov a5, a2 // a5 = CP index n + + // Get coprocessor state save area of new owner thread + call0 XT_RTOS_CP_STATE // a15 = new owner's save area + beqz a15, .L_xt_coproc_invalid // not in a thread (invalid) + l32i a4, a15, XT_CP_ASA // actual save area address + beqz a4, .L_xt_coproc_invalid // thread has no save area + + // Enable the co-processor's bit in CPENABLE + movi a0, _xt_coproc_mask + rsr a4, CPENABLE // a4 = CPENABLE + addx4 a0, a5, a0 // a0 = &_xt_coproc_mask[n] + l32i a0, a0, 0 // a0 = (n << 16) | (1 << n) + movi a3, _xt_coproc_owner_sa + extui a2, a0, 0, 16 // coprocessor bitmask portion + or a4, a4, a2 // a4 = CPENABLE | (1 << n) + wsr a4, CPENABLE + + // Get old coprocessor owner thread (save area ptr) and assign new one + addx4 a3, a5, a3 // a3 = &_xt_coproc_owner_sa[n] + l32i a2, a3, 0 // a2 = old owner's save area + s32i a15, a3, 0 // _xt_coproc_owner_sa[n] = new + rsync // ensure wsr.CPENABLE is complete + + // Do we need to context-switch this coprocessor ? + beq a15, a2, .L_xt_coproc_done // new owner == old, we're done + + // if no old owner then nothing to save + beqz a2, .L_check_new + + // If old owner not actively using CP then nothing to save. + l16ui a4, a2, XT_CPENABLE // a4 = old owner's CPENABLE + bnone a4, a0, .L_check_new // old owner not using CP + +.L_save_old: + // We need to save old owner's coprocessor state + movi a5, _xt_coproc_sa_offset + + // Mark old owner state as no longer active (CPENABLE bit n clear) + xor a4, a4, a0 // clear CP in old owner's CPENABLE + s16i a4, a2, XT_CPENABLE // update old owner's CPENABLE + + extui a4, a0, 16, 5 // a4 = CP index = n + addx4 a5, a4, a5 // a5 = &_xt_coproc_sa_offset[n] + + // Mark old owner state as saved (CPSTORED bit n set) + l16ui a4, a2, XT_CPSTORED // a4 = old owner's CPSTORED + l32i a5, a5, 0 // a5 = XT_CP[n]_SA offset + or a4, a4, a0 // set CP in old owner's CPSTORED + s16i a4, a2, XT_CPSTORED // update old owner's CPSTORED + l32i a2, a2, XT_CP_ASA // ptr to actual (aligned) save area + extui a3, a0, 16, 5 // a3 = CP index = n + add a2, a2, a5 // a2 = old owner's area for CP n + + // The config-specific HAL macro invoked below destroys a2-a6. + // It is theoretically possible for Xtensa processor designers to write TIE + // that causes more address registers to be affected, but it is generally + // unlikely. If that ever happens, more registers needs to be saved/restored + // around this macro invocation, and the value in a15 needs to be recomputed. + + xchal_cpi_store_funcbody + +.L_check_new: + // Check if any state has to be restored for new owner. + // NOTE: a15 = new owner's save area, cannot be zero when we get here. + + l16ui a3, a15, XT_CPSTORED // a3 = new owner's CPSTORED + movi a4, _xt_coproc_sa_offset + bnone a3, a0, .L_check_cs // full CP not saved, check callee-saved + xor a3, a3, a0 // CPSTORED bit is set, clear it + s16i a3, a15, XT_CPSTORED // update new owner's CPSTORED + + // Adjust new owner's save area pointers to area for CP n. + extui a3, a0, 16, 5 // a3 = CP index = n + addx4 a4, a3, a4 // a4 = &_xt_coproc_sa_offset[n] + l32i a4, a4, 0 // a4 = XT_CP[n]_SA + l32i a5, a15, XT_CP_ASA // ptr to actual (aligned) save area + add a2, a4, a5 // a2 = new owner's area for CP + + // The config-specific HAL macro invoked below destroys a2-a6. + // It is theoretically possible for Xtensa processor designers to write TIE + // that causes more address registers to be affected, but it is generally + // unlikely. If that ever happens, more registers needs to be saved/restored + // around this macro invocation. + + xchal_cpi_load_funcbody + +.L_xt_coproc_done: + movi a2, 0 // a2 <- 0 == OK +.L_xt_coproc_err: + mov a0, a7 // return address + ret + +.L_check_cs: + // a0 = CP mask in low bits, a15 = new owner's save area. + l16ui a2, a15, XT_CP_CS_ST // a2 = mask of CPs saved + bnone a2, a0, .L_xt_coproc_done // if no match then done + and a2, a2, a0 // a2 = which CPs to restore + extui a2, a2, 0, 8 // extract low 8 bits + call0 _xt_coproc_restorecs // restore CP registers + j .L_xt_coproc_done + +.L_xt_coproc_invalid: + // Coprocessor exception occurred outside a thread or the thread + // did not allocate space to save coprocessor state. Return error. + movi a2, 1 + j .L_xt_coproc_err + + +//----------------------------------------------------------------------------- +// _tx_thread_coproc_state +// +// Helper function to return the save area for the current thread, if any. +// Returns, in a15, the pointer to the save area if any, else zero. +// If in interrupt context, returns zero. Only uses a15. +// Must be called only via call0. +//----------------------------------------------------------------------------- + + .global _tx_thread_coproc_state + .type _tx_thread_coproc_state,@function + .align 4 + +_tx_thread_coproc_state: + + // return ( _tx_thread_system_state == 0 && _tx_thread_current_ptr != 0 + // ? (&_tx_thread_current_ptr->tx_thread_cp_state) : 0 ) + + movi a15, _tx_thread_system_state // check if interrupt state + l32i a15, a15, 0 + bnez a15, 1f + movi a15, _tx_thread_current_ptr // check if thread running + l32i a15, a15, 0 + beqz a15, 2f + + // Return base address of current thread's co-prcoessor save area. + addi a15, a15, tx_thread_cp_state + ret +1: + movi a15, 0 // return error +2: + ret + + +//----------------------------------------------------------------------------- +// _xt_coproc_savecs +// +// If there is a current thread and it has a coprocessor state save area, then +// save all callee-saved state into this area. This function is called from the +// solicited context switch handler. It calls a system-specific function to get +// the coprocessor save area base address. +// +// Entry conditions: +// - The thread being switched out is still the current thread. +// - CPENABLE state reflects which coprocessors are active. +// - Registers have been saved/spilled already. +// +// Exit conditions: +// - All necessary CP callee-saved state has been saved. +// - Registers a7-a15 have been trashed. +// +// Must be called from assembly code only, using CALL0. +//----------------------------------------------------------------------------- + + .global _xt_coproc_savecs + .type _xt_coproc_savecs,@function + .align 4 +_xt_coproc_savecs: + + // At entry, CPENABLE should be showing which CPs are enabled. + + rsr a11, CPENABLE // a11 = which CPs are enabled + beqz a11, .Ldone // quick exit if none + mov a14, a0 // save return address + call0 XT_RTOS_CP_STATE // get address of CP save area + mov a0, a14 // restore return address + beqz a15, .Ldone // if none then nothing to do + l32i a14, a15, XT_CP_ASA // a14 = base of aligned save area + beqz a14, .Ldone // no save area, nothing to do + s16i a11, a15, XT_CP_CS_ST // save mask of CPs being stored + movi a13, _xt_coproc_sa_offset // array of CP save offsets + l32i a15, a15, XT_CP_ASA // a15 = base of aligned save area + +#if XCHAL_CP0_SA_SIZE + bbci.l a11, 0, 2f // CP 0 not enabled + l32i a14, a13, 0 // a14 = _xt_coproc_sa_offset[0] + add a12, a14, a15 // a12 = save area for CP 0 + xchal_cp0_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP1_SA_SIZE + bbci.l a11, 1, 2f // CP 1 not enabled + l32i a14, a13, 4 // a14 = _xt_coproc_sa_offset[1] + add a12, a14, a15 // a12 = save area for CP 1 + xchal_cp1_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP2_SA_SIZE + bbci.l a11, 2, 2f + l32i a14, a13, 8 + add a12, a14, a15 + xchal_cp2_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP3_SA_SIZE + bbci.l a11, 3, 2f + l32i a14, a13, 12 + add a12, a14, a15 + xchal_cp3_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP4_SA_SIZE + bbci.l a11, 4, 2f + l32i a14, a13, 16 + add a12, a14, a15 + xchal_cp4_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP5_SA_SIZE + bbci.l a11, 5, 2f + l32i a14, a13, 20 + add a12, a14, a15 + xchal_cp5_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP6_SA_SIZE + bbci.l a11, 6, 2f + l32i a14, a13, 24 + add a12, a14, a15 + xchal_cp6_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP7_SA_SIZE + bbci.l a11, 7, 2f + l32i a14, a13, 28 + add a12, a14, a15 + xchal_cp7_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +.Ldone: + ret + + +//----------------------------------------------------------------------------- +// _xt_coproc_restorecs +// +// Restore any callee-saved coprocessor state for the incoming thread. +// This function is called from coprocessor exception handling, when giving +// ownership to a thread that solicited a context switch earlier. It calls a +// system-specific function to get the coprocessor save area base address. +// +// Entry conditions: +// - The incoming thread is set as the current thread. +// - CPENABLE is set up correctly for all required coprocessors. +// - a2 = mask of coprocessors to be restored. +// +// Exit conditions: +// - All necessary CP callee-saved state has been restored. +// - CPENABLE - unchanged. +// - Registers a2, a8-a15 have been trashed. +// +// Must be called from assembly code only, using CALL0. +//----------------------------------------------------------------------------- + + .global _xt_coproc_restorecs + .type _xt_coproc_restorecs,@function + .align 4 +_xt_coproc_restorecs: + + mov a14, a0 // save return address + call0 XT_RTOS_CP_STATE // get address of CP save area + mov a0, a14 // restore return address + beqz a15, .Ldone2 // if none then nothing to do + l32i a14, a15, XT_CP_ASA // a14 = base of aligned save area + beqz a14, .Ldone2 // no save area, nothing to do + l16ui a13, a15, XT_CP_CS_ST // a13 = which CPs have been saved + xor a13, a13, a2 // clear the ones being restored + s16i a13, a15, XT_CP_CS_ST // update saved CP mask + movi a13, _xt_coproc_sa_offset // array of CP save offsets + l32i a15, a15, XT_CP_ASA // a15 = base of aligned save area + +#if XCHAL_CP0_SA_SIZE + bbci.l a2, 0, 2f // CP 0 not enabled + l32i a14, a13, 0 // a14 = _xt_coproc_sa_offset[0] + add a12, a14, a15 // a12 = save area for CP 0 + xchal_cp0_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP1_SA_SIZE + bbci.l a2, 1, 2f // CP 1 not enabled + l32i a14, a13, 4 // a14 = _xt_coproc_sa_offset[1] + add a12, a14, a15 // a12 = save area for CP 1 + xchal_cp1_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP2_SA_SIZE + bbci.l a2, 2, 2f + l32i a14, a13, 8 + add a12, a14, a15 + xchal_cp2_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP3_SA_SIZE + bbci.l a2, 3, 2f + l32i a14, a13, 12 + add a12, a14, a15 + xchal_cp3_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP4_SA_SIZE + bbci.l a2, 4, 2f + l32i a14, a13, 16 + add a12, a14, a15 + xchal_cp4_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP5_SA_SIZE + bbci.l a2, 5, 2f + l32i a14, a13, 20 + add a12, a14, a15 + xchal_cp5_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP6_SA_SIZE + bbci.l a2, 6, 2f + l32i a14, a13, 24 + add a12, a14, a15 + xchal_cp6_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP7_SA_SIZE + bbci.l a2, 7, 2f + l32i a14, a13, 28 + add a12, a14, a15 + xchal_cp7_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +.Ldone2: + ret + + +#if XCHAL_HAVE_XEA3 + +//----------------------------------------------------------------------------- +// For XEA3, coprocessor exceptions come here. This is a wrapper function that +// calls _xt_coproc_handler() to do the actual work. Since the handler can be +// interrupted make sure that no context switch occurs. +//----------------------------------------------------------------------------- + + .text + .global _xt_coproc_exc + .type _xt_coproc_exc,@function + .align 4 + +_xt_coproc_exc: +#ifdef __XTENSA_CALL0_ABI__ + addi a1, a1, -16 // reserve 16 bytes on stack + s32i a0, a1, 0 // save return address + s32i a2, a1, 4 // save a2 + s32i a15, a1, 8 // must save a15 (see dispatch) + l32i a2, a1, 4 + l32i a3, a2, XT_STK_EXCCAUSE // a3 <- exccause + extui a2, a3, 8, 4 // a2 <- CP index + call0 _xt_coproc_handler + l32i a0, a1, 0 // restore return address + l32i a15, a1, 8 // restore a15 + addi a1, a1, 16 + ret +#else + entry a1, 48 // reserve 16 bytes on stack + s32i a0, a1, 0 // save return address + l32i a3, a2, XT_STK_EXCCAUSE // a3 <- exccause + extui a2, a3, 8, 4 // a2 <- CP index + call0 _xt_coproc_handler + l32i a0, a1, 0 // restore return address + retw +#endif + +#endif // XCHAL_HAVE_XEA3 + + +#if XCHAL_HAVE_XEA2 + +//----------------------------------------------------------------------------- +// XEA2 coprocessor exception dispatcher. Save enough state to be able to call +// the coprocessor handler, then restore and return. +//----------------------------------------------------------------------------- + + .text + .global _xt_coproc_exc + .type _xt_coproc_exc,@function + .align 4 + +_xt_coproc_exc: + + mov a0, sp // Allocate stack frame + addi sp, sp, -XT_STK_FRMSZ + s32i a0, sp, XT_STK_A1 // save SP +#if XCHAL_HAVE_WINDOWED + s32e a0, sp, -12 // for debug backtrace +#endif + rsr a0, PS + s32i a0, sp, XT_STK_PS // save PS + rsr a0, EPC_1 + s32i a0, sp, XT_STK_PC // save PC + rsr a0, EXCSAVE_1 + s32i a0, sp, XT_STK_A0 // retrieve and save a0 +#if XCHAL_HAVE_WINDOWED + s32e a0, sp, -16 // for debug backtrace +#endif + s32i a2, sp, XT_STK_A2 + s32i a3, sp, XT_STK_A3 + s32i a4, sp, XT_STK_A4 + s32i a5, sp, XT_STK_A5 + s32i a6, sp, XT_STK_A6 + s32i a7, sp, XT_STK_A7 + s32i a8, sp, XT_STK_A8 + s32i a9, sp, XT_STK_A9 + s32i a10, sp, XT_STK_A10 + s32i a11, sp, XT_STK_A11 + s32i a12, sp, XT_STK_A12 + s32i a13, sp, XT_STK_A13 + s32i a14, sp, XT_STK_A14 + s32i a15, sp, XT_STK_A15 + + rsr a3, EXCCAUSE // a3 <- exccause + addi a2, a3, -EXCCAUSE_CP0_DISABLED // a2 <- CP index + call0 _xt_coproc_handler + + mov a0, a2 // save return value + l32i a2, sp, XT_STK_A2 + l32i a3, sp, XT_STK_A3 + l32i a4, sp, XT_STK_A4 + l32i a5, sp, XT_STK_A5 + l32i a6, sp, XT_STK_A6 + l32i a7, sp, XT_STK_A7 + l32i a8, sp, XT_STK_A8 + l32i a9, sp, XT_STK_A9 + l32i a10, sp, XT_STK_A10 + l32i a11, sp, XT_STK_A11 + l32i a12, sp, XT_STK_A12 + l32i a13, sp, XT_STK_A13 + l32i a14, sp, XT_STK_A14 + l32i a15, sp, XT_STK_A15 + bnez a0, .Lfail // abort if failure + l32i a0, sp, XT_STK_PC + wsr a0, EPC_1 // restore PC + l32i a0, sp, XT_STK_PS + wsr a0, PS // restore PS + l32i a0, sp, XT_STK_A0 + addi a1, a1, XT_STK_FRMSZ // deallocate stack frame + rfe + +.Lfail: + call0 _xt_panic + +#endif // XCHAL_HAVE_XEA2 + +#endif // XCHAL_CP_NUM > 0 + diff --git a/ports/xtensa/xcc/src/xtensa_init.c b/ports/xtensa/xcc/src/xtensa_init.c new file mode 100644 index 00000000..0359028c --- /dev/null +++ b/ports/xtensa/xcc/src/xtensa_init.c @@ -0,0 +1,67 @@ +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* Xtensa initialization routines. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + + +#ifdef XT_BOARD +#include <xtensa/xtbsp.h> +#endif + +#include "xtensa_rtos.h" + + +#ifdef XT_RTOS_TIMER_INT +#ifndef XT_CLOCK_FREQ + +uint32_t _xt_tick_divisor = 0; /* cached number of cycles per tick */ + +/* +Compute and initialize at run-time the tick divisor (the number of +processor clock cycles in an RTOS tick, used to set the tick timer). +Called when the processor clock frequency is not known at compile-time. +*/ +void _xt_tick_divisor_init(void) +{ + #ifdef XT_BOARD + _xt_tick_divisor = xtbsp_clock_freq_hz() / XT_TICK_PER_SEC; + #else + #error "No way to obtain processor clock frequency" + #endif /* XT_BOARD */ +} + +#endif /* XT_CLOCK_FREQ */ +#endif /* XT_RTOS_TIMER_INT */ + diff --git a/ports/xtensa/xcc/src/xtensa_intr.c b/ports/xtensa/xcc/src/xtensa_intr.c new file mode 100644 index 00000000..c5f320cb --- /dev/null +++ b/ports/xtensa/xcc/src/xtensa_intr.c @@ -0,0 +1,213 @@ +/******************************************************************************* +Copyright (c) 2006-2019 Cadence Design Systems Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + +/****************************************************************************** + Xtensa-specific interrupt and exception functions for RTOS ports. + Also see xtensa_intr_asm.S. +******************************************************************************/ + +#include <stdlib.h> + +#include <xtensa/config/core.h> +#include <xtensa/core-macros.h> + +#include "xtensa_api.h" + + +#if XCHAL_HAVE_EXCEPTIONS + +/* Handler table is in xtensa_intr_asm.S */ + +extern xt_exc_handler _xt_exception_table[XCHAL_EXCCAUSE_NUM]; + + +/* + Default handler for unhandled exceptions. +*/ +void xt_unhandled_exception(XtExcFrame *frame) +{ + (void) frame; /* Keep compiler happy */ + exit(-1); +} + + +/* + This function registers a handler for the specified exception. + The function returns the address of the previous handler. + On error, it returns 0. +*/ +xt_exc_handler xt_set_exception_handler(uint32_t n, xt_exc_handler f) +{ + xt_exc_handler old; + + if (n >= XCHAL_EXCCAUSE_NUM) { + return 0; /* invalid exception number */ + } + + old = _xt_exception_table[n]; + + if (f != NULL) { + _xt_exception_table[n] = f; + } + else { + _xt_exception_table[n] = &xt_unhandled_exception; + } + + return old; +} + +#endif + +#if XCHAL_HAVE_INTERRUPTS + +#if XCHAL_HAVE_XEA2 +/* Defined in xtensa_intr_asm.S */ +extern uint32_t _xt_intenable; +extern uint32_t _xt_vpri_mask; +#endif + +/* Handler table is in xtensa_intr_asm.S */ + +typedef struct xt_handler_table_entry { + void * handler; + void * arg; +} xt_handler_table_entry; + +#if (XT_USE_INT_WRAPPER || XCHAL_HAVE_XEA3) +extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS + 1]; +#else +extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS]; +#endif + + +/* + Default handler for unhandled interrupts. +*/ +void xt_unhandled_interrupt(void * arg) +{ + (void) arg; /* Keep compiler happy */ + exit(-1); +} + + +/* + This function registers a handler for the specified interrupt. The "arg" + parameter specifies the argument to be passed to the handler when it is + invoked. The function returns the address of the previous handler. + On error, it returns 0. +*/ +xt_handler xt_set_interrupt_handler(uint32_t n, xt_handler f, void * arg) +{ + xt_handler_table_entry * entry; + xt_handler old; + + if (n >= XCHAL_NUM_INTERRUPTS) { + return 0; /* invalid interrupt number */ + } + +#if XCHAL_HAVE_XEA2 + if (Xthal_intlevel[n] > XCHAL_EXCM_LEVEL) { + return 0; /* priority level too high to safely handle in C */ + } +#endif + +#if (XT_USE_INT_WRAPPER || XCHAL_HAVE_XEA3) + entry = _xt_interrupt_table + n + 1; +#else + entry = _xt_interrupt_table + n; +#endif + old = entry->handler; + + if (f != NULL) { + entry->handler = f; + entry->arg = arg; + } + else { + entry->handler = &xt_unhandled_interrupt; + entry->arg = (void*)n; + } + + return old; +} + + +/* + This function enables the interrupt whose number is specified as + the argument. +*/ +void xt_interrupt_enable(uint32_t intnum) +{ +#if XCHAL_HAVE_XEA2 + uint32_t ps = XT_RSIL(15); + + // New INTENABLE = (_xt_intenable | mask) & _xt_vpri_mask. + _xt_intenable |= (1 << intnum); + XT_WSR_INTENABLE(_xt_intenable & _xt_vpri_mask); + XT_WSR_PS(ps); + XT_RSYNC(); +#else + xthal_interrupt_enable(intnum); +#endif +} + + +/* + This function disables the interrupt whose number is specified as + the argument. +*/ +void xt_interrupt_disable(uint32_t intnum) +{ +#if XCHAL_HAVE_XEA2 + uint32_t ps = XT_RSIL(15); + + // New INTENABLE = (_xt_intenable & ~mask) & _xt_vpri_mask. + _xt_intenable &= ~(1 << intnum); + XT_WSR_INTENABLE(_xt_intenable & _xt_vpri_mask); + XT_WSR_PS(ps); + XT_RSYNC(); +#else + xthal_interrupt_disable(intnum); +#endif +} + + +/* + This function triggers the specified interrupt. +*/ +void xt_interrupt_trigger(uint32_t intnum) +{ + xthal_interrupt_trigger(intnum); +} + + +/* + This function clears the specified interrupt. +*/ +void xt_interrupt_clear(uint32_t intnum) +{ + xthal_interrupt_clear(intnum); +} + + +#endif /* XCHAL_HAVE_INTERRUPTS */ + diff --git a/ports/xtensa/xcc/src/xtensa_intr_asm.S b/ports/xtensa/xcc/src/xtensa_intr_asm.S new file mode 100644 index 00000000..78fd8a70 --- /dev/null +++ b/ports/xtensa/xcc/src/xtensa_intr_asm.S @@ -0,0 +1,156 @@ +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* Xtensa interrupt handling data and assembly routines. */ +/* Also see xtensa_intr.c. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + + +#include <xtensa/hal.h> +#include <xtensa/config/core.h> + +#include "tx_port.h" +#include "xtensa_context.h" + +#if XCHAL_HAVE_INTERRUPTS + +/* +------------------------------------------------------------------------------- + INTENABLE virtualization information. +------------------------------------------------------------------------------- +*/ + +#if XCHAL_HAVE_XEA2 + + .data + .global _xt_intdata + .align 8 +_xt_intdata: + .global _xt_intenable + .type _xt_intenable,@object + .size _xt_intenable,4 + .global _xt_vpri_mask + .type _xt_vpri_mask,@object + .size _xt_vpri_mask,4 + +_xt_intenable: .word 0 /* Virtual INTENABLE */ +_xt_vpri_mask: .word 0xFFFFFFFF /* Virtual priority mask */ + +#endif + +/* +------------------------------------------------------------------------------- + System interrupt stack. +------------------------------------------------------------------------------- +*/ + +#if (XCHAL_HAVE_XEA2 || XCHAL_HAVE_ISB) + .data +#else + .section .intr.top, "aw" +#endif + + .global _xt_interrupt_stack + .global _xt_interrupt_stack_top + .align 16 + +_xt_interrupt_stack: + .space TX_SYSTEM_STACK_SIZE +_xt_interrupt_stack_top: + + +/* +------------------------------------------------------------------------------- + Table of C-callable interrupt handlers for each interrupt. For XEA2 configs, + not all slots can be filled, because interrupts at level > EXCM_LEVEL will + not be dispatched to a C handler by default. +------------------------------------------------------------------------------- +*/ + +#if (XCHAL_HAVE_XEA2 || XCHAL_HAVE_ISB) + .data +#else + .section .intr.data, "aw" +#endif + + .global _xt_interrupt_table + .align 16 + +_xt_interrupt_table: + +/* +------------------------------------------------------------------------------- + If using the interrupt wrapper, make the first entry in the interrupt table + point to the wrapper (XEA3) or leave it empty (XEA2). +------------------------------------------------------------------------------- +*/ +#if XCHAL_HAVE_XEA3 + .word xt_interrupt_wrapper + .word 0 +#elif XT_USE_INT_WRAPPER + .word 0 + .word 0 +#endif + + .set i, 0 + .rept XCHAL_NUM_INTERRUPTS + .word xt_unhandled_interrupt /* handler address */ + .word i /* handler arg (default: intnum) */ + .set i, i+1 + .endr + +#endif /* XCHAL_HAVE_INTERRUPTS */ + + +#if XCHAL_HAVE_EXCEPTIONS + +/* +------------------------------------------------------------------------------- + Table of C-callable exception handlers for each exception. Note that not all + slots will be active, because some exceptions (e.g. coprocessor exceptions) + are always handled by the OS and cannot be hooked by user handlers. +------------------------------------------------------------------------------- +*/ + + .data + .global _xt_exception_table + .align 4 + +_xt_exception_table: + .rept XCHAL_EXCCAUSE_NUM + .word xt_unhandled_exception /* handler address */ + .endr + +#endif + diff --git a/ports/xtensa/xcc/src/xtensa_intr_wrapper.c b/ports/xtensa/xcc/src/xtensa_intr_wrapper.c new file mode 100644 index 00000000..ff70f4ea --- /dev/null +++ b/ports/xtensa/xcc/src/xtensa_intr_wrapper.c @@ -0,0 +1,125 @@ +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* Xtensa-specific interrupt handler wrapper. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + + +#include <xtensa/config/core.h> +#include <xtensa/core-macros.h> + +#include "xtensa_rtos.h" +#include "xtensa_api.h" + +#include "tx_api.h" +#include "tx_thread.h" + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY +#include "tx_execution_profile.h" +#endif + + +#if (XCHAL_HAVE_XEA3 && XCHAL_HAVE_INTERRUPTS) + +/* Table of interrupt hooks. Used for testing ONLY. */ +#ifdef XT_INTEXC_HOOKS +volatile XT_INTEXC_HOOK _xt_intexc_hooks[XT_INTEXC_HOOK_NUM]; +#endif + + +/* Handler table is in xtensa_intr_asm.S */ + +typedef struct xt_handler_table_entry { + void * handler; + void * arg; +} xt_handler_table_entry; + +extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS + 1]; +extern int32_t xt_sw_intnum; + +static int32_t xt_wflag; + + +/**************************************************************************/ +/* Wrapper for interrupt handlers. Argument is (intnum << 2). */ +/* Execution comes here from the dispatch code if the wrapper is */ +/* enabled. */ +/**************************************************************************/ +void +xt_interrupt_wrapper(void * arg) +{ + uint32_t intnum = (uint32_t)(arg) >> 2; + xt_handler_table_entry * entry; + xt_handler handler; + + /* Increment interrupt nest counter. */ + _tx_thread_system_state++; + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + /* Call the ISR enter function to indicate an ISR is executing. */ + _tx_execution_isr_enter(); +#endif + + /* Load handler address and argument from table. Note that the + first entry in the table points to this wrapper, so we have + to skip ahead one. + */ + entry = _xt_interrupt_table + intnum + 1; + handler = (xt_handler) entry->handler; + + (*handler)(entry->arg); + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + /* Call the ISR exit function to indicate an ISR is complete. */ + _tx_execution_isr_exit(); +#endif + + /* If a context switch is pending, trigger the SW interrupt + to process the switch. Set an internal flag so we don't + trigger the sw interrupt again when handling it. + */ + if (xt_wflag != 0) { + xt_wflag = 0; + } + else if (_tx_thread_current_ptr != _tx_thread_execute_ptr) { + xt_wflag = 1; + xt_interrupt_trigger(xt_sw_intnum); + } + + /* Decrement interrupt nest counter. */ + _tx_thread_system_state--; +} + +#endif /* XCHAL_HAVE_XEA3 && XCHAL_HAVE_INTERRUPTS */ + diff --git a/ports/xtensa/xcc/src/xtensa_overlay_os_hook.c b/ports/xtensa/xcc/src/xtensa_overlay_os_hook.c new file mode 100644 index 00000000..8fd92701 --- /dev/null +++ b/ports/xtensa/xcc/src/xtensa_overlay_os_hook.c @@ -0,0 +1,109 @@ +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* Xtensa overlay manager OS hooks for ThreadX. XEA2 only. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + + +#ifdef XT_USE_OVLY + +#include <xtensa/overlay.h> +#include "tx_api.h" + + +/* Required to work around a bug in the overlay header. */ +#ifdef XT_DISABLE_OVERLAYS +#undef xt_overlay_fatal_error +#define xt_overlay_fatal_error(id) +#endif + + +/* Mutex object that controls access to the overlay. Currently only one + * overlay region is supported so one mutex suffices. + */ +static TX_MUTEX xt_overlay_mutex; + + +/**************************************************************************/ +/* This function should be overridden to provide OS specific init such */ +/* as the creation of a mutex lock that can be used for overlay locking. */ +/* Typically this mutex would be set up with priority inheritance. See */ +/* overlay manager documentation for more details. */ +/**************************************************************************/ +void +xt_overlay_init_os(void) +{ + /* Create the mutex for overlay access. Priority inheritance is + * required. + */ + UINT status = + tx_mutex_create (&xt_overlay_mutex, "xt_overlay_lock", TX_INHERIT); + + if (status != TX_SUCCESS) { + xt_overlay_fatal_error (-1); + } +} + + +/**************************************************************************/ +/* This function locks access to shared overlay resources, typically */ +/* by acquiring a mutex. */ +/**************************************************************************/ +void +xt_overlay_lock(void) +{ + UINT status = tx_mutex_get (&xt_overlay_mutex, TX_WAIT_FOREVER); + + if (status != TX_SUCCESS) { + xt_overlay_fatal_error (-1); + } +} + + +/**************************************************************************/ +/* This function releases access to shared overlay resources, typically */ +/* by unlocking a mutex. */ +/**************************************************************************/ +void +xt_overlay_unlock(void) +{ + UINT status = tx_mutex_put (&xt_overlay_mutex); + + if (status != TX_SUCCESS) { + xt_overlay_fatal_error (-1); + } +} + +#endif /* XT_USE_OVLY */ + diff --git a/ports/xtensa/xcc/src/xtensa_vectors.S b/ports/xtensa/xcc/src/xtensa_vectors.S new file mode 100644 index 00000000..b115abf5 --- /dev/null +++ b/ports/xtensa/xcc/src/xtensa_vectors.S @@ -0,0 +1,1696 @@ +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* Xtensa exception and interrupt dispatch for XEA2. */ +/* */ +/* Interrupt handlers and user exception handlers support interaction */ +/* with the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT */ +/* before and after calling the user's specific interrupt handlers. */ +/* */ +/* Users can install application-specific interrupt handlers for low and */ +/* medium priority interrupts, by calling xt_set_interrupt_handler(). */ +/* These handlers can be written in C and must follow the C calling */ +/* convention. The handler table is indexed by the interrupt number. */ +/* Each handler may be provided with an argument. */ +/* */ +/* Note that the system timer interrupt is handled specially, and is */ +/* dispatched to the RTOS-specific handler. This timer cannot be hooked */ +/* by application code. */ +/* */ +/* Optional hooks are also provided to install a handler per level at */ +/* run-time, made available by compiling this source file with */ +/* '-DXT_INTEXC_HOOKS' (useful for automated testing). */ +/* */ +/* Search for locations marked USER_EDIT for helpful comments on where */ +/* to insert application-specific code and how to write them. */ +/* */ +/* Users can install application-specific exception handlers in the */ +/* same way, by calling xt_set_exception_handler(). One handler slot is */ +/* provided for each exception type. Note that some exceptions are */ +/* handled by the porting layer itself, and cannot be taken over by */ +/* application code. These are the alloca, syscall, and coprocessor */ +/* exceptions. */ +/* */ +/* Exception handlers can be written in C, and must follow C calling */ +/* convention. Each handler is passed a pointer to an exception frame as */ +/* its single argument. The exception frame is created on the stack and */ +/* holds the saved context of the thread that took the exception. If the */ +/* handler returns, the context will be restored and the instruction */ +/* that caused the exception will be retried. If the handler makes any */ +/* changes to the saved state in the exception frame, the changes will */ +/* be applied when restoring the context. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + + +#include "xtensa_rtos.h" + + +#if XCHAL_HAVE_XEA2 + +/* Enable stack backtrace across exception/interrupt - see below */ +#define XT_DEBUG_BACKTRACE 1 + + +/* +-------------------------------------------------------------------------------- + Defines used to access _xtos_interrupt_table. +-------------------------------------------------------------------------------- +*/ +#define XIE_HANDLER 0 +#define XIE_ARG 4 +#define XIE_SIZE 8 + +/* +-------------------------------------------------------------------------------- + Macro extract_msb - return the input with only the highest bit set. + + Input : "ain" - Input value, clobbered. + Output : "aout" - Output value, has only one bit set, MSB of "ain". + The two arguments must be different AR registers. +-------------------------------------------------------------------------------- +*/ + + .macro extract_msb aout ain +1: + addi \aout, \ain, -1 /* aout = ain - 1 */ + and \ain, \ain, \aout /* ain = ain & aout */ + bnez \ain, 1b /* repeat until ain == 0 */ + addi \aout, \aout, 1 /* return aout + 1 */ + .endm + +/* +-------------------------------------------------------------------------------- + Macro dispatch_c_isr - dispatch interrupts to user ISRs. + This will dispatch to user handlers (if any) that are registered in the + XTOS dispatch table (_xtos_interrupt_table). These handlers would have + been registered by calling _xtos_set_interrupt_handler(). There is one + exception - the timer interrupt used by the OS will not be dispatched + to a user handler - this must be handled by the caller of this macro. + + Level triggered and software interrupts are automatically deasserted by + this code. + + ASSUMPTIONS: + -- PS.INTLEVEL is set to "level" at entry + -- PS.EXCM = 0, C calling enabled + + NOTE: For CALL0 ABI, a12-a15 have not yet been saved. + + NOTE: This macro will use registers a0 and a2-a6. The arguments are: + level -- interrupt level + mask -- interrupt bitmask for this level +-------------------------------------------------------------------------------- +*/ + + .macro dispatch_c_isr level mask + + /* Get mask of pending, enabled interrupts at this level into a2. */ + +.L_xt_user_int_&level&: + rsr a2, INTENABLE + rsr a3, INTERRUPT + movi a4, \mask + and a2, a2, a3 + and a2, a2, a4 + beqz a2, 9f /* nothing to do */ + + /* This bit of code provides a nice debug backtrace in the debugger. + It does take a few more instructions, so undef XT_DEBUG_BACKTRACE + if you want to save the cycles. + */ + #if XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + rsr a0, EPC_1 + \level - 1 /* return address */ + movi a4, 0xC0000000 /* constant with top 2 bits set (call size) */ + or a0, a0, a4 /* set top 2 bits */ + addx2 a0, a4, a0 /* clear top bit -- simulating call4 size */ + #endif + #endif + + #ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + /* Call the ISR enter function to indicate an ISR is executing. */ + #ifdef __XTENSA_CALL0_ABI__ + call0 _tx_execution_isr_enter + #else + call4 _tx_execution_isr_enter + #endif + #endif + + #ifdef XT_INTEXC_HOOKS + /* Call interrupt hook if present to (pre)handle interrupts. */ + movi a4, _xt_intexc_hooks + l32i a4, a4, \level << 2 + beqz a4, 2f + #ifdef __XTENSA_CALL0_ABI__ + callx0 a4 + beqz a2, 9f + #else + mov a6, a2 + callx4 a4 + beqz a6, 9f + mov a2, a6 + #endif +2: + #endif + + /* Now look up in the dispatch table and call user ISR if any. */ + /* If multiple bits are set then MSB has highest priority. */ + + extract_msb a4, a2 /* a4 = MSB of a2, a2 trashed */ + + #ifdef XT_USE_SWPRI + /* Enable all interrupts at this level that are numerically higher + than the one we just selected, since they are treated as higher + priority. + */ + movi a3, \mask /* a3 = all interrupts at this level */ + add a2, a4, a4 /* a2 = a4 << 1 */ + addi a2, a2, -1 /* a2 = mask of 1's <= a4 bit */ + and a2, a2, a3 /* a2 = mask of all bits <= a4 at this level */ + movi a3, _xt_intdata + l32i a6, a3, 4 /* a6 = _xt_vpri_mask */ + neg a2, a2 + addi a2, a2, -1 /* a2 = mask to apply */ + and a5, a6, a2 /* mask off all bits <= a4 bit */ + s32i a5, a3, 4 /* update _xt_vpri_mask */ + rsr a3, INTENABLE + and a3, a3, a2 /* mask off all bits <= a4 bit */ + wsr a3, INTENABLE + rsil a3, \level - 1 /* lower interrupt level by 1 */ + #endif + + wsr a4, INTCLEAR /* clear sw or edge-triggered interrupt */ + + #ifndef TX_NO_TIMER + movi a3, XT_TIMER_INTEN /* a3 = timer interrupt bit */ + beq a3, a4, 7f /* if timer interrupt then skip table */ + #endif + + find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */ + + movi a4, _xt_interrupt_table + addx8 a3, a3, a4 /* a3 = address of interrupt table entry */ + l32i a4, a3, XIE_HANDLER /* a4 = handler address */ + #ifdef __XTENSA_CALL0_ABI__ + mov a12, a6 /* save in callee-saved reg */ + l32i a2, a3, XIE_ARG /* a2 = handler arg */ + callx0 a4 /* call handler */ + mov a2, a12 + #else + mov a2, a6 /* save in windowed reg */ + l32i a6, a3, XIE_ARG /* a6 = handler arg */ + callx4 a4 /* call handler */ + #endif + + #ifdef XT_USE_SWPRI + j 8f + #else + j .L_xt_user_int_&level& /* check for more interrupts */ + #endif + +7: + + #ifndef TX_NO_TIMER + .ifeq XT_TIMER_INTPRI - \level +.L_xt_user_int_timer_&level&: + /* + Interrupt handler for the RTOS tick timer if at this level. + We'll be reading the interrupt state again after this call + so no need to preserve any registers except a6 (vpri_mask). + */ + + #ifdef __XTENSA_CALL0_ABI__ + mov a12, a6 + call0 XT_RTOS_TIMER_INT + mov a2, a12 + #else + mov a2, a6 + call4 XT_RTOS_TIMER_INT + #endif + .endif + #endif + + #ifdef XT_USE_SWPRI + j 8f + #else + j .L_xt_user_int_&level& /* check for more interrupts */ + #endif + + #ifdef XT_USE_SWPRI +8: + /* + Restore old value of _xt_vpri_mask from a2. Also update INTENABLE from + virtual _xt_intenable which _could_ have changed during interrupt + processing. But before that, raise the interrupt level back again. + */ + + rsil a3, \level + movi a3, _xt_intdata + l32i a4, a3, 0 /* a4 = _xt_intenable */ + s32i a2, a3, 4 /* update _xt_vpri_mask */ + and a4, a4, a2 /* a4 = masked intenable */ + wsr a4, INTENABLE /* update INTENABLE */ + #endif + +9: + /* done */ + + #if XCHAL_HAVE_EXCLUSIVE + /* Clear any local exclusive monitors. */ + clrex + #endif + + .endm + + +/* +-------------------------------------------------------------------------------- + Panic handler. + Should be reached by call0 (preferable) or jump only. If call0, a0 says where + from. If on simulator, display panic message and abort, else loop indefinitely. +-------------------------------------------------------------------------------- +*/ + + .text + .global _xt_panic + .type _xt_panic,@function + .align 4 + +_xt_panic: + #ifdef XT_SIMULATOR + addi a4, a0, -3 /* point to call0 */ + movi a3, _xt_panic_message + movi a2, SYS_log_msg + simcall + movi a2, SYS_gdb_abort + simcall + #else + rsil a2, XCHAL_EXCM_LEVEL /* disable all low & med ints */ +1: j 1b /* loop infinitely */ + #endif + + .section .rodata, "a" + .align 4 + +_xt_panic_message: + .string "\n*** _xt_panic() was called from 0x%08x or jumped to. ***\n" + + +/* +-------------------------------------------------------------------------------- + Hooks to dynamically install handlers for exceptions and interrupts. + Allows automated regression frameworks to install handlers per test. + Consists of an array of function pointers indexed by interrupt level, + with index 0 containing the entry for user exceptions. + Initialized with all 0s, meaning no handler is installed at each level. + See comment in xtensa_rtos.h for more details. +-------------------------------------------------------------------------------- +*/ + + #ifdef XT_INTEXC_HOOKS + .data + .global _xt_intexc_hooks + .type _xt_intexc_hooks,@object + .align 4 + +_xt_intexc_hooks: + .fill XT_INTEXC_HOOK_NUM, 4, 0 + #endif + + +/* +-------------------------------------------------------------------------------- + EXCEPTION AND LEVEL 1 INTERRUPT VECTORS AND LOW LEVEL HANDLERS + (except window exception vectors). + + Each vector goes at a predetermined location according to the Xtensa + hardware configuration, which is ensured by its placement in a special + section known to the Xtensa linker support package (LSP). It performs + the minimum necessary before jumping to the handler in the .text section. + + The corresponding handler goes in the normal .text section. It sets up + the appropriate stack frame, saves a few vector-specific registers and + calls XT_RTOS_INT_ENTER to save the rest of the interrupted context + and enter the RTOS, then sets up a C environment. It then calls the + user's interrupt handler code (which may be coded in C) and finally + calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling. + + While XT_RTOS_INT_EXIT does not return directly to the interruptee, + eventually the RTOS scheduler will want to dispatch the interrupted + task or handler. The scheduler will return to the exit point that was + saved in the interrupt stack frame at XT_STK_EXIT. +-------------------------------------------------------------------------------- +*/ + + +/* +-------------------------------------------------------------------------------- +Debug Exception. +-------------------------------------------------------------------------------- +*/ + +#if XCHAL_HAVE_DEBUG + + .begin literal_prefix .DebugExceptionVector + .section .DebugExceptionVector.text, "ax" + .global _DebugExceptionVector + .align 4 + +_DebugExceptionVector: + + #ifdef XT_SIMULATOR + /* + In the simulator, let the debugger (if any) handle the debug exception, + or simply stop the simulation: + */ + wsr a2, EXCSAVE+XCHAL_DEBUGLEVEL /* save a2 where sim expects it */ + movi a2, SYS_gdb_enter_sktloop + simcall /* have ISS handle debug exc. */ + #elif 0 /* change condition to 1 to use the HAL minimal debug handler */ + wsr a3, EXCSAVE+XCHAL_DEBUGLEVEL + movi a3, xthal_debugexc_defhndlr_nw /* use default debug handler */ + jx a3 + #else + wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* save original a0 somewhere */ + call0 _xt_panic /* does not return */ + rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */ + #endif + + .end literal_prefix + +#endif + +/* +-------------------------------------------------------------------------------- +Double Exception. +Double exceptions are not a normal occurrence. They indicate a bug of some kind. +-------------------------------------------------------------------------------- +*/ + +#ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR + + .begin literal_prefix .DoubleExceptionVector + .section .DoubleExceptionVector.text, "ax" + .global _DoubleExceptionVector + .align 4 + +_DoubleExceptionVector: + + #if XCHAL_HAVE_DEBUG + break 1, 4 /* unhandled double exception */ + #endif + call0 _xt_panic /* does not return */ + rfde /* make a0 point here not later */ + + .end literal_prefix + +#endif /* XCHAL_DOUBLEEXC_VECTOR_VADDR */ + +/* +-------------------------------------------------------------------------------- +Kernel Exception (including Level 1 Interrupt from kernel mode). +-------------------------------------------------------------------------------- +*/ + + .begin literal_prefix .KernelExceptionVector + .section .KernelExceptionVector.text, "ax" + .global _KernelExceptionVector + .align 4 + +_KernelExceptionVector: + + wsr a0, EXCSAVE_1 /* preserve a0 */ + call0 _xt_kernel_exc /* kernel exception handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .text + .align 4 + +_xt_kernel_exc: + #if XCHAL_HAVE_DEBUG + break 1, 0 /* unhandled kernel exception */ + #endif + call0 _xt_panic /* does not return */ + rfe /* make a0 point here not there */ + + +/* +-------------------------------------------------------------------------------- +User Exception (including Level 1 Interrupt from user mode). +-------------------------------------------------------------------------------- +*/ + + .begin literal_prefix .UserExceptionVector + .section .UserExceptionVector.text, "ax" + .global _UserExceptionVector + .type _UserExceptionVector,@function + .align 4 + +_UserExceptionVector: + + wsr a0, EXCSAVE_1 /* preserve a0 */ + call0 _xt_user_exc /* user exception handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + +/* +-------------------------------------------------------------------------------- + Insert some waypoints for jumping beyond the signed 8-bit range of + conditional branch instructions, so the conditional branchces to specific + exception handlers are not taken in the mainline. Saves some cycles in the + mainline. +-------------------------------------------------------------------------------- +*/ + + .text + + #if XCHAL_HAVE_WINDOWED + .align 4 +_xt_to_alloca_exc: + call0 _xt_alloca_exc /* in window vectors section */ + /* never returns here - call0 is used as a jump (see note at top) */ + #endif + + .align 4 +_xt_to_syscall_exc: + call0 _xt_syscall_exc + /* never returns here - call0 is used as a jump (see note at top) */ + + #if XCHAL_CP_NUM > 0 + .align 4 +_xt_to_coproc_exc: + call0 _xt_coproc_exc + /* never returns here - call0 is used as a jump (see note at top) */ + #endif + + +/* +-------------------------------------------------------------------------------- + User exception handler. +-------------------------------------------------------------------------------- +*/ + + .type _xt_user_exc,@function + .align 4 + +_xt_user_exc: + + /* If level 1 interrupt then jump to the dispatcher */ + rsr a0, EXCCAUSE + beqi a0, EXCCAUSE_LEVEL1_INTERRUPT, _xt_lowint1 + + /* Handle any coprocessor exceptions. Rely on the fact that exception + numbers above EXCCAUSE_CP0_DISABLED all relate to the coprocessors. + */ + #if XCHAL_CP_NUM > 0 + bgeui a0, EXCCAUSE_CP0_DISABLED, _xt_to_coproc_exc + #endif + + /* Handle alloca and syscall exceptions */ + #if XCHAL_HAVE_WINDOWED + beqi a0, EXCCAUSE_ALLOCA, _xt_to_alloca_exc + #endif + beqi a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc + + /* Handle all other exceptions. All can have user-defined handlers. */ + /* NOTE: we'll stay on the user stack for exception handling. */ + + /* Allocate exception frame and save minimal context. */ + mov a0, sp + addi sp, sp, -XT_STK_FRMSZ + s32i a0, sp, XT_STK_A1 + #if XCHAL_HAVE_WINDOWED + s32e a0, sp, -12 /* for debug backtrace */ + #endif + rsr a0, PS /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_1 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_1 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + #if XCHAL_HAVE_WINDOWED + s32e a0, sp, -16 /* for debug backtrace */ + #endif + s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ + s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ + call0 _xt_context_save + + /* Save exc cause and vaddr into exception frame */ + rsr a0, EXCCAUSE + s32i a0, sp, XT_STK_EXCCAUSE + rsr a0, EXCVADDR + s32i a0, sp, XT_STK_EXCVADDR + + /* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM + #else + movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE + #endif + wsr a0, PS + + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + rsr a0, EPC_1 /* return address for debug backtrace */ + movi a5, 0xC0000000 /* constant with top 2 bits set (call size) */ + rsync /* wait for WSR.PS to complete */ + or a0, a0, a5 /* set top 2 bits */ + addx2 a0, a5, a0 /* clear top bit -- thus simulating call4 size */ + #else + rsync /* wait for WSR.PS to complete */ + #endif + #endif + + rsr a2, EXCCAUSE /* recover exc cause */ + + #ifdef XT_INTEXC_HOOKS + /* + Call exception hook to pre-handle exceptions (if installed). + Pass EXCCAUSE in a2, and check result in a2 (if -1, skip default handling). + */ + movi a4, _xt_intexc_hooks + l32i a4, a4, 0 /* user exception hook index 0 */ + beqz a4, 1f +.Ln_xt_user_exc_call_hook: + #ifdef __XTENSA_CALL0_ABI__ + callx0 a4 + beqi a2, -1, .L_xt_user_done + #else + mov a6, a2 + callx4 a4 + beqi a6, -1, .L_xt_user_done + mov a2, a6 + #endif +1: + #endif + + rsr a2, EXCCAUSE /* recover exc cause */ + movi a3, _xt_exception_table + addx4 a4, a2, a3 /* a4 = address of exception table entry */ + l32i a4, a4, 0 /* a4 = handler address */ + #ifdef __XTENSA_CALL0_ABI__ + mov a2, sp /* a2 = pointer to exc frame */ + callx0 a4 /* call handler */ + #else + mov a6, sp /* a6 = pointer to exc frame */ + callx4 a4 /* call handler */ + #endif + +.L_xt_user_done: + + /* Restore context and return */ + call0 _xt_context_restore + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, PS + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_1 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove exception frame */ + rsync /* ensure PS and EPC written */ + rfe /* PS.EXCM is cleared */ + + +/* +-------------------------------------------------------------------------------- + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. +-------------------------------------------------------------------------------- +*/ + + .global _xt_user_exit + .type _xt_user_exit,@function + .align 4 +_xt_user_exit: + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, PS + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_1 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure PS and EPC written */ + rfe /* PS.EXCM is cleared */ + + +/* +-------------------------------------------------------------------------------- +Syscall Exception Handler (jumped to from User Exception Handler). +Syscall 0 is required to spill the register windows (no-op in Call 0 ABI). +Only syscall 0 is handled here. Other syscalls return -1 to caller in a2. +-------------------------------------------------------------------------------- +*/ + + .text + .type _xt_syscall_exc,@function + .align 4 +_xt_syscall_exc: + + #ifdef __XTENSA_CALL0_ABI__ + /* + Save minimal regs for scratch. Syscall 0 does nothing in Call0 ABI. + Use a minimal stack frame (16B) to save A2 & A3 for scratch. + PS.EXCM could be cleared here, but unlikely to improve worst-case latency. + rsr a0, PS + addi a0, a0, -PS_EXCM_MASK + wsr a0, PS + */ + addi sp, sp, -16 + s32i a2, sp, 8 + s32i a3, sp, 12 + #else /* Windowed ABI */ + /* + Save necessary context and spill the register windows. + PS.EXCM is still set and must remain set until after the spill. + Reuse context save function though it saves more than necessary. + For this reason, a full interrupt stack frame is allocated. + */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ + s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ + call0 _xt_context_save + #endif + + /* + Grab the interruptee's PC and skip over the 'syscall' instruction. + If it's at the end of a zero-overhead loop and it's not on the last + iteration, decrement loop counter and skip to beginning of loop. + */ + rsr a2, EPC_1 /* a2 = PC of 'syscall' */ + addi a3, a2, 3 /* ++PC */ + #if XCHAL_HAVE_LOOPS + rsr a0, LEND /* if (PC == LEND */ + bne a3, a0, 1f + rsr a0, LCOUNT /* && LCOUNT != 0) */ + beqz a0, 1f /* { */ + addi a0, a0, -1 /* --LCOUNT */ + rsr a3, LBEG /* PC = LBEG */ + wsr a0, LCOUNT /* } */ + #endif +1: wsr a3, EPC_1 /* update PC */ + + /* Restore interruptee's context and return from exception. */ + #ifdef __XTENSA_CALL0_ABI__ + l32i a2, sp, 8 + l32i a3, sp, 12 + addi sp, sp, 16 + #else + call0 _xt_context_restore + addi sp, sp, XT_STK_FRMSZ + #endif + movi a0, -1 + movnez a2, a0, a2 /* return -1 if not syscall 0 */ + rsr a0, EXCSAVE_1 + rfe + + +/* +------------------------------------------------------------------------------- + Level 1 interrupt dispatch. Assumes stack frame has not been allocated yet. +------------------------------------------------------------------------------- +*/ + + .text + .type _xt_lowint1,@function + .align 4 + +_xt_lowint1: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, PS /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_1 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_1 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + movi a0, _xt_user_exit /* save exit point for dispatch */ + s32i a0, sp, XT_STK_EXIT + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(1) | PS_UM + #else + movi a0, PS_INTLEVEL(1) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 1 XCHAL_INTLEVEL1_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + +/* +------------------------------------------------------------------------------- + MEDIUM PRIORITY (LEVEL 2+) INTERRUPT VECTORS AND LOW LEVEL HANDLERS. + + Medium priority interrupts are by definition those with priority greater + than 1 and not greater than XCHAL_EXCM_LEVEL. These are disabled by + setting PS.EXCM and therefore can easily support a C environment for + handlers in C, and interact safely with an RTOS. + + Each vector goes at a predetermined location according to the Xtensa + hardware configuration, which is ensured by its placement in a special + section known to the Xtensa linker support package (LSP). It performs + the minimum necessary before jumping to the handler in the .text section. + + The corresponding handler goes in the normal .text section. It sets up + the appropriate stack frame, saves a few vector-specific registers and + calls XT_RTOS_INT_ENTER to save the rest of the interrupted context + and enter the RTOS, then sets up a C environment. It then calls the + user's interrupt handler code (which may be coded in C) and finally + calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling. + + While XT_RTOS_INT_EXIT does not return directly to the interruptee, + eventually the RTOS scheduler will want to dispatch the interrupted + task or handler. The scheduler will return to the exit point that was + saved in the interrupt stack frame at XT_STK_EXIT. +------------------------------------------------------------------------------- +*/ + +#if XCHAL_EXCM_LEVEL >= 2 + + .begin literal_prefix .Level2InterruptVector + .section .Level2InterruptVector.text, "ax" + .global _Level2Vector + .type _Level2Vector,@function + .align 4 +_Level2Vector: + wsr a0, EXCSAVE_2 /* preserve a0 */ + call0 _xt_medint2 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .text + .type _xt_medint2,@function + .align 4 +_xt_medint2: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, EPS_2 /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_2 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_2 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + movi a0, _xt_medint2_exit /* save exit point for dispatch */ + s32i a0, sp, XT_STK_EXIT + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(2) | PS_UM + #else + movi a0, PS_INTLEVEL(2) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 2 XCHAL_INTLEVEL2_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + /* + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. + */ + .global _xt_medint2_exit + .type _xt_medint2_exit,@function + .align 4 +_xt_medint2_exit: + /* Restore only level-specific regs (the rest were already restored) */ + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, EPS_2 + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_2 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure EPS and EPC written */ + rfi 2 + +#endif /* Level 2 */ + +#if XCHAL_EXCM_LEVEL >= 3 + + .begin literal_prefix .Level3InterruptVector + .section .Level3InterruptVector.text, "ax" + .global _Level3Vector + .type _Level3Vector,@function + .align 4 +_Level3Vector: + wsr a0, EXCSAVE_3 /* preserve a0 */ + call0 _xt_medint3 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .text + .type _xt_medint3,@function + .align 4 +_xt_medint3: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, EPS_3 /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_3 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_3 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + movi a0, _xt_medint3_exit /* save exit point for dispatch */ + s32i a0, sp, XT_STK_EXIT + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(3) | PS_UM + #else + movi a0, PS_INTLEVEL(3) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 3 XCHAL_INTLEVEL3_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + /* + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. + */ + .global _xt_medint3_exit + .type _xt_medint3_exit,@function + .align 4 +_xt_medint3_exit: + /* Restore only level-specific regs (the rest were already restored) */ + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, EPS_3 + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_3 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure EPS and EPC written */ + rfi 3 + +#endif /* Level 3 */ + +#if XCHAL_EXCM_LEVEL >= 4 + + .begin literal_prefix .Level4InterruptVector + .section .Level4InterruptVector.text, "ax" + .global _Level4Vector + .type _Level4Vector,@function + .align 4 +_Level4Vector: + wsr a0, EXCSAVE_4 /* preserve a0 */ + call0 _xt_medint4 /* load interrupt handler */ + + .end literal_prefix + + .text + .type _xt_medint4,@function + .align 4 +_xt_medint4: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, EPS_4 /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_4 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_4 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + movi a0, _xt_medint4_exit /* save exit point for dispatch */ + s32i a0, sp, XT_STK_EXIT + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(4) | PS_UM + #else + movi a0, PS_INTLEVEL(4) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 4 XCHAL_INTLEVEL4_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + /* + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. + */ + .global _xt_medint4_exit + .type _xt_medint4_exit,@function + .align 4 +_xt_medint4_exit: + /* Restore only level-specific regs (the rest were already restored) */ + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, EPS_4 + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_4 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure EPS and EPC written */ + rfi 4 + +#endif /* Level 4 */ + +#if XCHAL_EXCM_LEVEL >= 5 + + .begin literal_prefix .Level5InterruptVector + .section .Level5InterruptVector.text, "ax" + .global _Level5Vector + .type _Level5Vector,@function + .align 4 +_Level5Vector: + wsr a0, EXCSAVE_5 /* preserve a0 */ + call0 _xt_medint5 /* load interrupt handler */ + + .end literal_prefix + + .text + .type _xt_medint5,@function + .align 4 +_xt_medint5: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, EPS_5 /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_5 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_5 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + movi a0, _xt_medint5_exit /* save exit point for dispatch */ + s32i a0, sp, XT_STK_EXIT + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(5) | PS_UM + #else + movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 5 XCHAL_INTLEVEL5_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + /* + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. + */ + .global _xt_medint5_exit + .type _xt_medint5_exit,@function + .align 4 +_xt_medint5_exit: + /* Restore only level-specific regs (the rest were already restored) */ + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, EPS_5 + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_5 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure EPS and EPC written */ + rfi 5 + +#endif /* Level 5 */ + +#if XCHAL_EXCM_LEVEL >= 6 + + .begin literal_prefix .Level6InterruptVector + .section .Level6InterruptVector.text, "ax" + .global _Level6Vector + .type _Level6Vector,@function + .align 4 +_Level6Vector: + wsr a0, EXCSAVE_6 /* preserve a0 */ + call0 _xt_medint6 /* load interrupt handler */ + + .end literal_prefix + + .text + .type _xt_medint6,@function + .align 4 +_xt_medint6: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, EPS_6 /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_6 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_6 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + movi a0, _xt_medint6_exit /* save exit point for dispatch */ + s32i a0, sp, XT_STK_EXIT + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(6) | PS_UM + #else + movi a0, PS_INTLEVEL(6) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 6 XCHAL_INTLEVEL6_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + /* + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. + */ + .global _xt_medint6_exit + .type _xt_medint6_exit,@function + .align 4 +_xt_medint6_exit: + /* Restore only level-specific regs (the rest were already restored) */ + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, EPS_6 + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_6 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure EPS and EPC written */ + rfi 6 + +#endif /* Level 6 */ + + +/******************************************************************************* + +HIGH PRIORITY (LEVEL > XCHAL_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS + +High priority interrupts are by definition those with priorities greater +than XCHAL_EXCM_LEVEL. This includes non-maskable (NMI). High priority +interrupts cannot interact with the RTOS, that is they must save all regs +they use and not call any RTOS function. + +A further restriction imposed by the Xtensa windowed architecture is that +high priority interrupts must not modify the stack area even logically +"above" the top of the interrupted stack (they need to provide their +own stack or static save area). + +Cadence Design Systems recommends high priority interrupt handlers be coded in assembly +and used for purposes requiring very short service times. + +Here are templates for high priority (level 2+) interrupt vectors. +They assume only one interrupt per level to avoid the burden of identifying +which interrupts at this level are pending and enabled. This allows for +minimum latency and avoids having to save/restore a2 in addition to a0. +If more than one interrupt per high priority level is configured, this burden +is on the handler which in any case must provide a way to save and restore +registers it uses without touching the interrupted stack. + +Each vector goes at a predetermined location according to the Xtensa +hardware configuration, which is ensured by its placement in a special +section known to the Xtensa linker support package (LSP). It performs +the minimum necessary before jumping to the handler in the .text section. + +*******************************************************************************/ + +/* +Currently only shells for high priority interrupt handlers are provided +here. However a template and example can be found in the Cadence Design Systems tools +documentation: "Microprocessor Programmer's Guide". +*/ + +#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2 + + .begin literal_prefix .Level2InterruptVector + .section .Level2InterruptVector.text, "ax" + .global _Level2Vector + .type _Level2Vector,@function + .align 4 +_Level2Vector: + wsr a0, EXCSAVE_2 /* preserve a0 */ + call0 _xt_highint2 /* load interrupt handler */ + + .end literal_prefix + + .text + .type _xt_highint2,@function + .align 4 +_xt_highint2: + + #ifdef XT_INTEXC_HOOKS + /* Call interrupt hook if present to (pre)handle interrupts. */ + movi a0, _xt_intexc_hooks + l32i a0, a0, 2<<2 + beqz a0, 1f +.Ln_xt_highint2_call_hook: + callx0 a0 /* must NOT disturb stack! */ +1: + #endif + + /* USER_EDIT: + ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE. + */ + + .align 4 +.L_xt_highint2_exit: + rsr a0, EXCSAVE_2 /* restore a0 */ + rfi 2 + +#endif /* Level 2 */ + +#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3 + + .begin literal_prefix .Level3InterruptVector + .section .Level3InterruptVector.text, "ax" + .global _Level3Vector + .type _Level3Vector,@function + .align 4 +_Level3Vector: + wsr a0, EXCSAVE_3 /* preserve a0 */ + call0 _xt_highint3 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .text + .type _xt_highint3,@function + .align 4 +_xt_highint3: + + #ifdef XT_INTEXC_HOOKS + /* Call interrupt hook if present to (pre)handle interrupts. */ + movi a0, _xt_intexc_hooks + l32i a0, a0, 3<<2 + beqz a0, 1f +.Ln_xt_highint3_call_hook: + callx0 a0 /* must NOT disturb stack! */ +1: + #endif + + /* USER_EDIT: + ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE. + */ + + .align 4 +.L_xt_highint3_exit: + rsr a0, EXCSAVE_3 /* restore a0 */ + rfi 3 + +#endif /* Level 3 */ + +#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4 + + .begin literal_prefix .Level4InterruptVector + .section .Level4InterruptVector.text, "ax" + .global _Level4Vector + .type _Level4Vector,@function + .align 4 +_Level4Vector: + wsr a0, EXCSAVE_4 /* preserve a0 */ + call0 _xt_highint4 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .text + .type _xt_highint4,@function + .align 4 +_xt_highint4: + + #ifdef XT_INTEXC_HOOKS + /* Call interrupt hook if present to (pre)handle interrupts. */ + movi a0, _xt_intexc_hooks + l32i a0, a0, 4<<2 + beqz a0, 1f +.Ln_xt_highint4_call_hook: + callx0 a0 /* must NOT disturb stack! */ +1: + #endif + + /* USER_EDIT: + ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE. + */ + + .align 4 +.L_xt_highint4_exit: + rsr a0, EXCSAVE_4 /* restore a0 */ + rfi 4 + +#endif /* Level 4 */ + +#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5 + + .begin literal_prefix .Level5InterruptVector + .section .Level5InterruptVector.text, "ax" + .global _Level5Vector + .type _Level5Vector,@function + .align 4 +_Level5Vector: + wsr a0, EXCSAVE_5 /* preserve a0 */ + call0 _xt_highint5 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .text + .type _xt_highint5,@function + .align 4 +_xt_highint5: + + #ifdef XT_INTEXC_HOOKS + /* Call interrupt hook if present to (pre)handle interrupts. */ + movi a0, _xt_intexc_hooks + l32i a0, a0, 5<<2 + beqz a0, 1f +.Ln_xt_highint5_call_hook: + callx0 a0 /* must NOT disturb stack! */ +1: + #endif + + /* USER_EDIT: + ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE. + */ + + .align 4 +.L_xt_highint5_exit: + rsr a0, EXCSAVE_5 /* restore a0 */ + rfi 5 + +#endif /* Level 5 */ + +#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6 + + .begin literal_prefix .Level6InterruptVector + .section .Level6InterruptVector.text, "ax" + .global _Level6Vector + .type _Level6Vector,@function + .align 4 +_Level6Vector: + wsr a0, EXCSAVE_6 /* preserve a0 */ + call0 _xt_highint6 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .text + .type _xt_highint6,@function + .align 4 +_xt_highint6: + + #ifdef XT_INTEXC_HOOKS + /* Call interrupt hook if present to (pre)handle interrupts. */ + movi a0, _xt_intexc_hooks + l32i a0, a0, 6<<2 + beqz a0, 1f +.Ln_xt_highint6_call_hook: + callx0 a0 /* must NOT disturb stack! */ +1: + #endif + + /* USER_EDIT: + ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE. + */ + + .align 4 +.L_xt_highint6_exit: + rsr a0, EXCSAVE_6 /* restore a0 */ + rfi 6 + +#endif /* Level 6 */ + +#if XCHAL_HAVE_NMI + + .begin literal_prefix .NMIExceptionVector + .section .NMIExceptionVector.text, "ax" + .global _NMIExceptionVector + .type _NMIExceptionVector,@function + .align 4 +_NMIExceptionVector: + wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */ + call0 _xt_nmi /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .text + .type _xt_nmi,@function + .align 4 +_xt_nmi: + + #ifdef XT_INTEXC_HOOKS + /* Call interrupt hook if present to (pre)handle interrupts. */ + movi a0, _xt_intexc_hooks + l32i a0, a0, XCHAL_NMILEVEL<<2 + beqz a0, 1f +.Ln_xt_nmi_call_hook: + callx0 a0 /* must NOT disturb stack! */ +1: + #endif + + /* USER_EDIT: + ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE. + */ + + .align 4 +.L_xt_nmi_exit: + rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */ + rfi XCHAL_NMILEVEL + +#endif /* NMI */ + + +/******************************************************************************* + +WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION HANDLER + +Here is the code for each window overflow/underflow exception vector and +(interspersed) efficient code for handling the alloca exception cause. +Window exceptions are handled entirely in the vector area and are very +tight for performance. The alloca exception is also handled entirely in +the window vector area so comes at essentially no cost in code size. +Users should never need to modify them and Cadence Design Systems recommends +they do not. + +Window handlers go at predetermined vector locations according to the +Xtensa hardware configuration, which is ensured by their placement in a +special section known to the Xtensa linker support package (LSP). Since +their offsets in that section are always the same, the LSPs do not define +a section per vector. + +These things are coded for XEA2 only (XEA1 is not supported). + +Note on Underflow Handlers: +The underflow handler for returning from call[i+1] to call[i] +must preserve all the registers from call[i+1]'s window. +In particular, a0 and a1 must be preserved because the RETW instruction +will be reexecuted (and may even underflow if an intervening exception +has flushed call[i]'s registers). +Registers a2 and up may contain return values. + +*******************************************************************************/ + +#if XCHAL_HAVE_WINDOWED + + .section .WindowVectors.text, "ax" + +/* +-------------------------------------------------------------------------------- +Window Overflow Exception for Call4. + +Invoked if a call[i] referenced a register (a4-a15) +that contains data from ancestor call[j]; +call[j] had done a call4 to call[j+1]. +On entry here: + window rotated to call[j] start point; + a0-a3 are registers to be saved; + a4-a15 must be preserved; + a5 is call[j+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0x0 + .global _WindowOverflow4 +_WindowOverflow4: + + s32e a0, a5, -16 /* save a0 to call[j+1]'s stack frame */ + s32e a1, a5, -12 /* save a1 to call[j+1]'s stack frame */ + s32e a2, a5, -8 /* save a2 to call[j+1]'s stack frame */ + s32e a3, a5, -4 /* save a3 to call[j+1]'s stack frame */ + rfwo /* rotates back to call[i] position */ + +/* +-------------------------------------------------------------------------------- +Window Underflow Exception for Call4 + +Invoked by RETW returning from call[i+1] to call[i] +where call[i]'s registers must be reloaded (not live in ARs); +where call[i] had done a call4 to call[i+1]. +On entry here: + window rotated to call[i] start point; + a0-a3 are undefined, must be reloaded with call[i].reg[0..3]; + a4-a15 must be preserved (they are call[i+1].reg[0..11]); + a5 is call[i+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0x40 + .global _WindowUnderflow4 +_WindowUnderflow4: + + l32e a0, a5, -16 /* restore a0 from call[i+1]'s stack frame */ + l32e a1, a5, -12 /* restore a1 from call[i+1]'s stack frame */ + l32e a2, a5, -8 /* restore a2 from call[i+1]'s stack frame */ + l32e a3, a5, -4 /* restore a3 from call[i+1]'s stack frame */ + rfwu + +/* +-------------------------------------------------------------------------------- +Handle alloca exception generated by interruptee executing 'movsp'. +This uses space between the window vectors, so is essentially "free". +All interruptee's regs are intact except a0 which is saved in EXCSAVE_1, +and PS.EXCM has been set by the exception hardware (can't be interrupted). +The fact the alloca exception was taken means the registers associated with +the base-save area have been spilled and will be restored by the underflow +handler, so those 4 registers are available for scratch. +The code is optimized to avoid unaligned branches and minimize cache misses. +-------------------------------------------------------------------------------- +*/ + + .align 4 + .global _xt_alloca_exc +_xt_alloca_exc: + + rsr a0, WINDOWBASE /* grab WINDOWBASE before rotw changes it */ + rotw -1 /* WINDOWBASE goes to a4, new a0-a3 are scratch */ + rsr a2, PS + extui a3, a2, PS_OWB_SHIFT, PS_OWB_BITS + xor a3, a3, a4 /* bits changed from old to current windowbase */ + rsr a4, EXCSAVE_1 /* restore original a0 (now in a4) */ + slli a3, a3, PS_OWB_SHIFT + xor a2, a2, a3 /* flip changed bits in old window base */ + wsr a2, PS /* update PS.OWB to new window base */ + rsync + + _bbci.l a4, 31, _WindowUnderflow4 + rotw -1 /* original a0 goes to a8 */ + _bbci.l a8, 30, _WindowUnderflow8 + rotw -1 + j _WindowUnderflow12 + +/* +-------------------------------------------------------------------------------- +Window Overflow Exception for Call8 + +Invoked if a call[i] referenced a register (a4-a15) +that contains data from ancestor call[j]; +call[j] had done a call8 to call[j+1]. +On entry here: + window rotated to call[j] start point; + a0-a7 are registers to be saved; + a8-a15 must be preserved; + a9 is call[j+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0x80 + .global _WindowOverflow8 +_WindowOverflow8: + + s32e a0, a9, -16 /* save a0 to call[j+1]'s stack frame */ + l32e a0, a1, -12 /* a0 <- call[j-1]'s sp + (used to find end of call[j]'s frame) */ + s32e a1, a9, -12 /* save a1 to call[j+1]'s stack frame */ + s32e a2, a9, -8 /* save a2 to call[j+1]'s stack frame */ + s32e a3, a9, -4 /* save a3 to call[j+1]'s stack frame */ + s32e a4, a0, -32 /* save a4 to call[j]'s stack frame */ + s32e a5, a0, -28 /* save a5 to call[j]'s stack frame */ + s32e a6, a0, -24 /* save a6 to call[j]'s stack frame */ + s32e a7, a0, -20 /* save a7 to call[j]'s stack frame */ + rfwo /* rotates back to call[i] position */ + +/* +-------------------------------------------------------------------------------- +Window Underflow Exception for Call8 + +Invoked by RETW returning from call[i+1] to call[i] +where call[i]'s registers must be reloaded (not live in ARs); +where call[i] had done a call8 to call[i+1]. +On entry here: + window rotated to call[i] start point; + a0-a7 are undefined, must be reloaded with call[i].reg[0..7]; + a8-a15 must be preserved (they are call[i+1].reg[0..7]); + a9 is call[i+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0xC0 + .global _WindowUnderflow8 +_WindowUnderflow8: + + l32e a0, a9, -16 /* restore a0 from call[i+1]'s stack frame */ + l32e a1, a9, -12 /* restore a1 from call[i+1]'s stack frame */ + l32e a2, a9, -8 /* restore a2 from call[i+1]'s stack frame */ + l32e a7, a1, -12 /* a7 <- call[i-1]'s sp + (used to find end of call[i]'s frame) */ + l32e a3, a9, -4 /* restore a3 from call[i+1]'s stack frame */ + l32e a4, a7, -32 /* restore a4 from call[i]'s stack frame */ + l32e a5, a7, -28 /* restore a5 from call[i]'s stack frame */ + l32e a6, a7, -24 /* restore a6 from call[i]'s stack frame */ + l32e a7, a7, -20 /* restore a7 from call[i]'s stack frame */ + rfwu + +/* +-------------------------------------------------------------------------------- +Window Overflow Exception for Call12 + +Invoked if a call[i] referenced a register (a4-a15) +that contains data from ancestor call[j]; +call[j] had done a call12 to call[j+1]. +On entry here: + window rotated to call[j] start point; + a0-a11 are registers to be saved; + a12-a15 must be preserved; + a13 is call[j+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0x100 + .global _WindowOverflow12 +_WindowOverflow12: + + s32e a0, a13, -16 /* save a0 to call[j+1]'s stack frame */ + l32e a0, a1, -12 /* a0 <- call[j-1]'s sp + (used to find end of call[j]'s frame) */ + s32e a1, a13, -12 /* save a1 to call[j+1]'s stack frame */ + s32e a2, a13, -8 /* save a2 to call[j+1]'s stack frame */ + s32e a3, a13, -4 /* save a3 to call[j+1]'s stack frame */ + s32e a4, a0, -48 /* save a4 to end of call[j]'s stack frame */ + s32e a5, a0, -44 /* save a5 to end of call[j]'s stack frame */ + s32e a6, a0, -40 /* save a6 to end of call[j]'s stack frame */ + s32e a7, a0, -36 /* save a7 to end of call[j]'s stack frame */ + s32e a8, a0, -32 /* save a8 to end of call[j]'s stack frame */ + s32e a9, a0, -28 /* save a9 to end of call[j]'s stack frame */ + s32e a10, a0, -24 /* save a10 to end of call[j]'s stack frame */ + s32e a11, a0, -20 /* save a11 to end of call[j]'s stack frame */ + rfwo /* rotates back to call[i] position */ + +/* +-------------------------------------------------------------------------------- +Window Underflow Exception for Call12 + +Invoked by RETW returning from call[i+1] to call[i] +where call[i]'s registers must be reloaded (not live in ARs); +where call[i] had done a call12 to call[i+1]. +On entry here: + window rotated to call[i] start point; + a0-a11 are undefined, must be reloaded with call[i].reg[0..11]; + a12-a15 must be preserved (they are call[i+1].reg[0..3]); + a13 is call[i+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0x140 + .global _WindowUnderflow12 +_WindowUnderflow12: + + l32e a0, a13, -16 /* restore a0 from call[i+1]'s stack frame */ + l32e a1, a13, -12 /* restore a1 from call[i+1]'s stack frame */ + l32e a2, a13, -8 /* restore a2 from call[i+1]'s stack frame */ + l32e a11, a1, -12 /* a11 <- call[i-1]'s sp + (used to find end of call[i]'s frame) */ + l32e a3, a13, -4 /* restore a3 from call[i+1]'s stack frame */ + l32e a4, a11, -48 /* restore a4 from end of call[i]'s stack frame */ + l32e a5, a11, -44 /* restore a5 from end of call[i]'s stack frame */ + l32e a6, a11, -40 /* restore a6 from end of call[i]'s stack frame */ + l32e a7, a11, -36 /* restore a7 from end of call[i]'s stack frame */ + l32e a8, a11, -32 /* restore a8 from end of call[i]'s stack frame */ + l32e a9, a11, -28 /* restore a9 from end of call[i]'s stack frame */ + l32e a10, a11, -24 /* restore a10 from end of call[i]'s stack frame */ + l32e a11, a11, -20 /* restore a11 from end of call[i]'s stack frame */ + rfwu + +#endif /* XCHAL_HAVE_WINDOWED */ + +#endif /* XCHAL_HAVE_XEA2 */ + diff --git a/ports/xtensa/xcc/src/xtensa_vectors_xea3.S b/ports/xtensa/xcc/src/xtensa_vectors_xea3.S new file mode 100644 index 00000000..5596a75c --- /dev/null +++ b/ports/xtensa/xcc/src/xtensa_vectors_xea3.S @@ -0,0 +1,392 @@ +/**************************************************************************/ +/* Copyright (c) Cadence Design Systems, Inc. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* DESCRIPTION */ +/* */ +/* Xtensa exception and interrupt dispatch for XEA3. */ +/* */ +/* Interrupt handlers and user exception handlers support interaction */ +/* with the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT */ +/* before and after calling the user's specific interrupt handlers. */ +/* */ +/* Users can install application-specific interrupt handlers by calling */ +/* xt_set_interrupt_handler(). These handlers can be written in C and */ +/* must follow the C calling convention. The handler table is indexed by */ +/* the interrupt number. Each handler may be provided with an argument. */ +/* */ +/* Users can install application-specific exception handlers in the */ +/* same way, by calling xt_set_exception_handler(). One handler slot is */ +/* provided for each exception type. Note that some exceptions are */ +/* handled by the porting layer itself, and cannot be taken over by */ +/* application code. These are the alloca, syscall, and coprocessor */ +/* exceptions. */ +/* */ +/* Exception handlers can be written in C, and must follow C calling */ +/* convention. Each handler is passed a pointer to an exception frame as */ +/* its single argument. The exception frame is created on the stack and */ +/* holds the saved context of the thread that took the exception. If the */ +/* handler returns, the context will be restored and the instruction */ +/* that caused the exception will be retried. If the handler makes any */ +/* changes to the saved state in the exception frame, the changes will */ +/* be applied when restoring the context. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */ +/* */ +/**************************************************************************/ + + +#include <xtensa/config/core.h> +#include <xtensa/coreasm.h> + +#if XCHAL_HAVE_XEA3 + +#include "xtensa_context.h" + +#if (XCHAL_HW_VERSION < XTENSA_HWVERSION_RH_2016_2) +#error Xtensa HW earlier than RH_2016.2 not supported. +#endif + + +//----------------------------------------------------------------------------- +// The entry point vectors are common for call0 and windowed configurations. +//----------------------------------------------------------------------------- + + .extern _DoubleExceptionHandler + .extern _xtos_exc_dispatch + + .section .DispatchVector.text, "ax" +#if XCHAL_HAVE_VECBASE + .align 64 // 64-byte alignment needed when vecbase +#else // is relocatable + .align 4 +#endif + + .org 0 // Fixed offset for Reset Vector + .global _DispatchVector + .weak _DispatchVector + +_DispatchVector: + j _JumpToResetHandler + + .org 3 // Reserved + .local _Reserved1 + +_Reserved1: + ill + + .org 6 // Fixed offset for Double Exception Vector + .global _DoubleExceptionVector + .weak _DoubleExceptionVector + +_DoubleExceptionVector: + j _DoubleExceptionHandler + + .org 9 // Reserved + .local _Reserved2 + +_Reserved2: + ill + +//----------------------------------------------------------------------------- +// Start of dispatch code. +//----------------------------------------------------------------------------- + + .org 12 // Fixed offset for Tailchain entry point + .global _xt_dispatch + +_xt_dispatch: +#ifdef __XTENSA_CALL0_ABI__ + + // NOTE: for call0, a15 is expected to be holding the previous stack pointer + // when we get to the Tailchain segment. + + s32si.x4 a2, a15 // Select interrupt, a2 <- (intnum << 2) + movi a0, 0 + l32dis.it a0, a0 // a0 <- wrapper addr (handler_table[0]) + s32stk a9, a15, 96 // Set new stack pointer +#if XT_STK_XTRA_SZ + addi a1, a1, -XT_STK_XTRA_SZ // Adjust for extra save area +#endif + s32dis.h a0, a0 // Jump to handler if interrupt else fall through + // Note this also clears local exclusive monitor + +#else // windowed + + s32si.x4 a10, a1 // Select interrupt, a10 <- (intnum << 2) + movi a8, 0 + l32dis.it a8, a8 // a8 <- wrapper addr (handler_table[0]) + s32stk a9, a1, 96 // Set new stack pointer +#if XT_STK_XTRA_SZ + addi a9, a9, -XT_STK_XTRA_SZ // Adjust for extra save area +#endif + s32dis.h a8, a8 // Jump to handler if interrupt else fall through + // Note this also clears local exclusive monitor + +#endif // __XTENSA_CALL0_ABI__ + +.Lexit: + j _xt_exit + +#ifndef __XTENSA_CALL0_ABI__ + .org 36 // Fixed offset for Underflow segment + .global _xt_underflow + +_xt_underflow: + l32e a8, a1, -64 // a8 <- [a1-32] + l32e a9, a1, -64 // a9 <- [a1-28] + l32e a10, a1, -64 // a10 <- [a1-24] + l32e a11, a1, -64 // a11 <- [a1-20] + l32e a12, a1, -64 // a12 <- [a1-16] + l32e a13, a1, -64 // a13 <- [a1-12] + l32e a14, a1, -64 // a14 <- [a1-8] + l32e a15, a1, -64 // a15 <- [a1-4] ; Return (branch to EPC) +#endif + + .org 60 // Fixed offset for Save/Overflow segment + .global _xt_save + +_xt_save: +#ifdef __XTENSA_CALL0_ABI__ + s32e a0, a1, -64 // [a1-64] <- a0 + s32e a2, a1, -48 // [a1-56] <- a2 ; a2 <- EPC + s32e a3, a1, -64 // [a1-52] <- a3 + s32e a4, a1, -64 // [a1-48] <- a4 + s32e a5, a1, -64 // [a1-44] <- a5 + s32e a6, a1, -64 // [a1-40] <- a6 + s32e a7, a1, -64 // [a1-36] <- a7 +#else + .global _xt_overflow +_xt_overflow: +#endif + s32e a8, a1, -52 // [a1-32] <- a8 ; a8 <- ExcVAddr + s32e a9, a1, -28 // [a1-28] <- a9 ; a9 <- PS/SAR + s32e a10, a1, -48 // [a1-24] <- a10 ; a10 <- EPC + s32e a11, a1, -24 // [a1-20] <- a11 ; a11 <- ExcCause + s32e a12, a1, -44 // [a1-16] <- a12 ; a12 <- LBEG + s32e a13, a1, -40 // [a1-12] <- a13 ; a13 <- LEND + s32e a14, a1, -36 // [a1-8] <- a14 ; a14 <- LCOUNT + s32e a15, a1, -32 // [a1-4] <- a15 ; a15 <- a1 + // If Overflow then return (branch to EPC) + +_xt_entry: + s32e a8, a1, -4 // [a1-68] <- a8 (ExcVAddr) + s32e a11, a1, -8 // [a1-72] <- a11 (ExcCause) +#if XCHAL_HAVE_LOOPS + s32e a12, a1, -20 // [a1-84] <- a12 (LBEG) + s32e a13, a1, -24 // [a1-88] <- a13 (LEND) + s32e a14, a1, -28 // [a1-92] <- a14 (LCOUNT) +#endif +#if XCHAL_HAVE_EXCLUSIVE + movi a12, 0 + getex a12 + s32e a12, a1, -32 // [a1-96] <- a12 (ATOMCTL) +#endif + + j 1f // make room for literals + + .align 4 + .literal_position + +.Le1: + .word _xt_exception_table + +1: + // Call OS-specific code for additional work to be done. Stay on interruptee's + // stack in case more saves are required into stack frame. + // NOTE: OS-specific code can use a8, a12-a14, (+a2-a7: call0, a15: windowed). + // ALL other registers must be preserved. + + XT_RTOS_INT_ENTER + + // This sequence checks the interrupt controller and loads the interrupt + // number if available, and also loads the wrapper handler address. + // If there is an interrupt, execution will branch to the wrapper which + // will then forward to the correct handler. + // All this happens only if there is a pending interrupt. If not, execution + // falls through to exception handling. + +#ifdef __XTENSA_CALL0_ABI__ + + s32si.x4 a2, a1 // [a1-80] <- a2 (EPC) ; a2 <- (intnum << 2) + movi a0, 0 + l32dis.it a0, a0 // a0 <- wrapper addr (handler_table[0]) + s32stk a9, a1, 96 // [a1-76] <- a9 (PS/SAR) ; a1 = a1-96 +#if XT_STK_XTRA_SZ + addi a1, a1, -XT_STK_XTRA_SZ // Adjust for extra save area +#endif + s32dis.h a0, a0 // Jump to handler if interrupt else fall through + +#else // windowed + + s32si.x4 a10, a1 // [a1-80] <- a10 (EPC) ; a10 <- (intnum << 2) + movi a8, 0 + l32dis.it a8, a8 // a8 <- wrapper addr (handler_table[0]) + s32stk a9, a1, 96 // [a1-76] <- a9 (PS/SAR) ; a9 = a1-96 +#if XT_STK_XTRA_SZ + addi a9, a9, -XT_STK_XTRA_SZ // Adjust for extra save area +#endif + s32dis.h a8, a8 // Jump to handler if interrupt else fall through + +#endif // __XTENSA_CALL0_ABI__ + + // At this point we have: + // (note window has rotated for windowed ABI) + // a0 holds return address (Tailchain+3) + // For call0: + // a11 holds ExcCause, also saved in [oldsp - 72] + // a15 holds exception SP, a1 points to exception frame + // For windowed: + // a3 holds ExcCause, also saved in [oldsp - 72] + // a1 points to exception frame + + .global _xt_exception + +_xt_exception: + l32r a2, .Le1 // Load exc table address +#ifdef __XTENSA_CALL0_ABI__ + mov a3, a11 // Copy exception cause to a3 +#endif + extui a4, a3, 0, 4 // Extract exception cause + addx4 a2, a4, a2 // Index into exc table + l32i a4, a2, 0 // Load handler address +#if XT_STK_XTRA_SZ + addi a2, a1, XT_STK_XTRA_SZ // Argument = Exception frame ptr +#else + mov a2, a1 // Argument = Exception frame ptr +#endif + jx a4 // Return directly from handler + + // Exit/restore sequence + + .global _xt_exit + +_xt_exit: +#ifdef __XTENSA_CALL0_ABI__ + mov a1, a15 // Restore stack pointer +#endif + + // Run OS-specific code to determine what to restore. + // Interrupts will remain disabled through this sequence. + // WARNING: stack pointer may change within this macro + // so all restores off the stack must happen afterwards. + + XT_RTOS_INT_EXIT + + .global _xt_restore + +_xt_restore: + // Some loads must happen before DISPST = Restore, as these + // will not be accessible via L32E once DISPST = Restore. + +#if XCHAL_HAVE_EXCLUSIVE + l32e a12, a1, -32 // a12 <- [a1-96] (ATOMCTL) + getex a12 +#endif + l32e a10, a1, -12 // a10 <- [a1-76] (PS/SAR) + l32e a12, a1, -20 // a12 <- [a1-84] (LBEG) + l32e a13, a1, -24 // a13 <- [a1-88] (LEND) + l32e a14, a1, -28 // a14 <- [a1-92] (LCOUNT) + l32dis.epc a11, a1 // a11 <- [a1-80] (EPC) + // If interrupt goto tailchain else fall through + +#ifdef __XTENSA_CALL0_ABI__ + l32e a0, a1, -64 // a0 <- [a1-64] + l32e a2, a1, -64 // a2 <- [a1-56] + l32e a3, a1, -64 // a3 <- [a1-52] + l32e a4, a1, -64 // a4 <- [a1-48] + l32e a5, a1, -64 // a5 <- [a1-44] + l32e a6, a1, -64 // a6 <- [a1-40] + l32e a7, a1, -64 // a7 <- [a1-36] +#endif + + // Important: the following restrictions must be observed: + // 1) The LCOUNT register must be restored after LBEG/LEND. + // 2) There must be at least 3 instructions between the LCOUNT + // restore and the last L32E (the one that branches). + + l32e a12, a1, -44 // LBEG <- a12, a12 <- [a1-16] + l32e a13, a1, -40 // LEND <- a13, a13 <- [a1-12] + l32e a14, a1, -36 // LCOUNT <- a14, a14 <- [a1-8] + l32e a8, a1, -64 // a8 <- [a1-32] + l32e a9, a1, -64 // a9 <- [a1-28] + l32e a10, a1, -60 // PS/SAR <- a10, a10 <- [a1-24] + l32e a11, a1, -48 // EPC <- a11, a11 <- [a1-20] + l32e a15, a1, -64 // a15 <- [a1-4], Branch to EPC if no interrupt + // If interrupt, branch to Tailchain + + +//----------------------------------------------------------------------------- +// Branch to reset handler code from here. Use CALL0 as a branch, will expand +// to CALLX0 if needed when built with the -mlongcalls option. +//----------------------------------------------------------------------------- + + .align 4 + .local _JumpToResetHandler + +_JumpToResetHandler: + call0 _ResetHandler + + +//----------------------------------------------------------------------------- +// Idle loop. On interrupt, no state needs saving. +//----------------------------------------------------------------------------- + + .align 4 + .global _xt_idle + +_xt_idle: + movi a14, _xt_interrupt_stack_top + mov a1, a14 // a1 <- Top of interrupt stack + movi a14, 0 // 0 = Normal + wsr.ms a14 // Set DISPST = Normal + rsync + waiti 0 // Wait for interrupt + memw // HW erratum 569 + + +//----------------------------------------------------------------------------- +// Scheduler interrupt handler. Triggered by context switch. At this time only +// useful for windowed ABI to spill register windows. +//----------------------------------------------------------------------------- + + .align 4 + .global xt_sched_handler + +xt_sched_handler: +#ifdef __XTENSA_WINDOWED_ABI__ + entry a1, 32 + ssai 1 + spillw + retw +#else + ret +#endif + +#endif // XCHAL_HAVE_XEA3 + |
