こんにちは。NoMaYです。Azure RTOSでRXマイコンが使えるようになったのですね。コンパイラはGNURXが使われていました。Getting started with the Renesas Starter Kit+ for RX65N-2MB (英文です。)02/05/2021 Ryan Winterdocs.microsoft.com/ja-jp/samples/azure-rtos/getting-started/getting-started-with-the-renesas-starter-kit-for-rx65n-2mb/
カーネル内でTX_DISABLEをgrepしてみると以下の通りでした。やはりそれなりにあちらこちらにありますね。続く。カーネル内でTX_DISABLEをgrep (カーネル内ということでlibs/threadx/フォルダ内のみです)
libs/threadx/common/inc/tx_thread.h(228): TX_DISABLE /libs/threadx/common/inc/tx_thread.h(241): TX_DISABLE /libs/threadx/common/inc/tx_thread.h(247): TX_DISABLE /libs/threadx/common/src/txe_block_pool_create.c(121): TX_DISABLElibs/threadx/common/src/txe_block_pool_create.c(148): TX_DISABLElibs/threadx/common/src/txe_byte_pool_create.c(119): TX_DISABLElibs/threadx/common/src/txe_byte_pool_create.c(147): TX_DISABLElibs/threadx/common/src/txe_event_flags_create.c(116): TX_DISABLElibs/threadx/common/src/txe_event_flags_create.c(144): TX_DISABLElibs/threadx/common/src/txe_mutex_create.c(117): TX_DISABLElibs/threadx/common/src/txe_mutex_create.c(145): TX_DISABLElibs/threadx/common/src/txe_queue_create.c(119): TX_DISABLElibs/threadx/common/src/txe_queue_create.c(147): TX_DISABLElibs/threadx/common/src/txe_semaphore_create.c(116): TX_DISABLElibs/threadx/common/src/txe_semaphore_create.c(144): TX_DISABLElibs/threadx/common/src/txe_thread_create.c(132): TX_DISABLElibs/threadx/common/src/txe_thread_create.c(202): TX_DISABLElibs/threadx/common/src/txe_timer_create.c(122): TX_DISABLElibs/threadx/common/src/txe_timer_create.c(150): TX_DISABLElibs/threadx/common/src/tx_block_allocate.c(106): TX_DISABLElibs/threadx/common/src/tx_block_pool_cleanup.c(94): TX_DISABLElibs/threadx/common/src/tx_block_pool_cleanup.c(201): TX_DISABLElibs/threadx/common/src/tx_block_pool_create.c(153): TX_DISABLElibs/threadx/common/src/tx_block_pool_delete.c(90): TX_DISABLElibs/threadx/common/src/tx_block_pool_delete.c(156): TX_DISABLElibs/threadx/common/src/tx_block_pool_delete.c(195): TX_DISABLElibs/threadx/common/src/tx_block_pool_info_get.c(89): TX_DISABLElibs/threadx/common/src/tx_block_pool_performance_info_get.c(112): TX_DISABLElibs/threadx/common/src/tx_block_pool_performance_system_info_get.c(89): TX_DISABLElibs/threadx/common/src/tx_block_pool_prioritize.c(90): TX_DISABLElibs/threadx/common/src/tx_block_pool_prioritize.c(162): TX_DISABLElibs/threadx/common/src/tx_block_release.c(91): TX_DISABLElibs/threadx/common/src/tx_byte_allocate.c(110): TX_DISABLElibs/threadx/common/src/tx_byte_allocate.c(179): TX_DISABLElibs/threadx/common/src/tx_byte_pool_cleanup.c(94): TX_DISABLElibs/threadx/common/src/tx_byte_pool_cleanup.c(200): TX_DISABLElibs/threadx/common/src/tx_byte_pool_create.c(147): TX_DISABLElibs/threadx/common/src/tx_byte_pool_delete.c(94): TX_DISABLElibs/threadx/common/src/tx_byte_pool_delete.c(160): TX_DISABLElibs/threadx/common/src/tx_byte_pool_delete.c(199): TX_DISABLElibs/threadx/common/src/tx_byte_pool_info_get.c(89): TX_DISABLElibs/threadx/common/src/tx_byte_pool_performance_info_get.c(121): TX_DISABLElibs/threadx/common/src/tx_byte_pool_performance_system_info_get.c(98): TX_DISABLElibs/threadx/common/src/tx_byte_pool_prioritize.c(90): TX_DISABLElibs/threadx/common/src/tx_byte_pool_prioritize.c(162): TX_DISABLElibs/threadx/common/src/tx_byte_pool_search.c(106): TX_DISABLElibs/threadx/common/src/tx_byte_pool_search.c(261): TX_DISABLElibs/threadx/common/src/tx_byte_release.c(106): TX_DISABLElibs/threadx/common/src/tx_byte_release.c(240): TX_DISABLElibs/threadx/common/src/tx_byte_release.c(328): TX_DISABLElibs/threadx/common/src/tx_event_flags_cleanup.c(95): TX_DISABLElibs/threadx/common/src/tx_event_flags_cleanup.c(225): TX_DISABLElibs/threadx/common/src/tx_event_flags_create.c(91): TX_DISABLElibs/threadx/common/src/tx_event_flags_delete.c(90): TX_DISABLElibs/threadx/common/src/tx_event_flags_delete.c(156): TX_DISABLElibs/threadx/common/src/tx_event_flags_delete.c(195): TX_DISABLElibs/threadx/common/src/tx_event_flags_get.c(108): TX_DISABLElibs/threadx/common/src/tx_event_flags_get.c(386): TX_DISABLElibs/threadx/common/src/tx_event_flags_info_get.c(91): TX_DISABLElibs/threadx/common/src/tx_event_flags_performance_info_get.c(113): TX_DISABLElibs/threadx/common/src/tx_event_flags_performance_system_info_get.c(90): TX_DISABLElibs/threadx/common/src/tx_event_flags_set.c(114): TX_DISABLElibs/threadx/common/src/tx_event_flags_set.c(312): TX_DISABLElibs/threadx/common/src/tx_event_flags_set.c(355): TX_DISABLElibs/threadx/common/src/tx_event_flags_set.c(554): TX_DISABLElibs/threadx/common/src/tx_event_flags_set.c(580): TX_DISABLElibs/threadx/common/src/tx_event_flags_set_notify.c(91): TX_DISABLElibs/threadx/common/src/tx_misra.c(280): TX_DISABLElibs/threadx/common/src/tx_misra.c(293): TX_DISABLElibs/threadx/common/src/tx_misra.c(299): TX_DISABLElibs/threadx/common/src/tx_mutex_cleanup.c(94): TX_DISABLElibs/threadx/common/src/tx_mutex_cleanup.c(202): TX_DISABLElibs/threadx/common/src/tx_mutex_cleanup.c(271): TX_DISABLElibs/threadx/common/src/tx_mutex_cleanup.c(304): TX_DISABLElibs/threadx/common/src/tx_mutex_create.c(93): TX_DISABLElibs/threadx/common/src/tx_mutex_delete.c(94): TX_DISABLElibs/threadx/common/src/tx_mutex_delete.c(177): TX_DISABLElibs/threadx/common/src/tx_mutex_delete.c(192): TX_DISABLElibs/threadx/common/src/tx_mutex_delete.c(231): TX_DISABLElibs/threadx/common/src/tx_mutex_get.c(92): TX_DISABLElibs/threadx/common/src/tx_mutex_info_get.c(90): TX_DISABLElibs/threadx/common/src/tx_mutex_performance_info_get.c(118): TX_DISABLElibs/threadx/common/src/tx_mutex_performance_system_info_get.c(95): TX_DISABLElibs/threadx/common/src/tx_mutex_prioritize.c(93): TX_DISABLElibs/threadx/common/src/tx_mutex_prioritize.c(165): TX_DISABLElibs/threadx/common/src/tx_mutex_priority_change.c(110): TX_DISABLElibs/threadx/common/src/tx_mutex_priority_change.c(206): TX_DISABLElibs/threadx/common/src/tx_mutex_priority_change.c(241): TX_DISABLElibs/threadx/common/src/tx_mutex_put.c(104): TX_DISABLElibs/threadx/common/src/tx_mutex_put.c(296): TX_DISABLElibs/threadx/common/src/tx_mutex_put.c(355): TX_DISABLElibs/threadx/common/src/tx_mutex_put.c(396): TX_DISABLElibs/threadx/common/src/tx_mutex_put.c(604): TX_DISABLElibs/threadx/common/src/tx_queue_cleanup.c(94): TX_DISABLElibs/threadx/common/src/tx_queue_cleanup.c(213): TX_DISABLElibs/threadx/common/src/tx_queue_create.c(120): TX_DISABLElibs/threadx/common/src/tx_queue_delete.c(89): TX_DISABLElibs/threadx/common/src/tx_queue_delete.c(155): TX_DISABLElibs/threadx/common/src/tx_queue_delete.c(194): TX_DISABLElibs/threadx/common/src/tx_queue_flush.c(92): TX_DISABLElibs/threadx/common/src/tx_queue_flush.c(159): TX_DISABLElibs/threadx/common/src/tx_queue_flush.c(192): TX_DISABLElibs/threadx/common/src/tx_queue_front_send.c(102): TX_DISABLElibs/threadx/common/src/tx_queue_info_get.c(88): TX_DISABLElibs/threadx/common/src/tx_queue_performance_info_get.c(114): TX_DISABLElibs/threadx/common/src/tx_queue_performance_system_info_get.c(95): TX_DISABLElibs/threadx/common/src/tx_queue_prioritize.c(90): TX_DISABLElibs/threadx/common/src/tx_queue_prioritize.c(162): TX_DISABLElibs/threadx/common/src/tx_queue_receive.c(101): TX_DISABLElibs/threadx/common/src/tx_queue_receive.c(283): TX_DISABLElibs/threadx/common/src/tx_queue_send.c(102): TX_DISABLElibs/threadx/common/src/tx_queue_send_notify.c(91): TX_DISABLElibs/threadx/common/src/tx_semaphore_ceiling_put.c(97): TX_DISABLElibs/threadx/common/src/tx_semaphore_cleanup.c(95): TX_DISABLElibs/threadx/common/src/tx_semaphore_cleanup.c(203): TX_DISABLElibs/threadx/common/src/tx_semaphore_create.c(92): TX_DISABLElibs/threadx/common/src/tx_semaphore_delete.c(90): TX_DISABLElibs/threadx/common/src/tx_semaphore_delete.c(156): TX_DISABLElibs/threadx/common/src/tx_semaphore_delete.c(195): TX_DISABLElibs/threadx/common/src/tx_semaphore_get.c(91): TX_DISABLElibs/threadx/common/src/tx_semaphore_info_get.c(89): TX_DISABLElibs/threadx/common/src/tx_semaphore_performance_info_get.c(112): TX_DISABLElibs/threadx/common/src/tx_semaphore_performance_system_info_get.c(90): TX_DISABLElibs/threadx/common/src/tx_semaphore_prioritize.c(90): TX_DISABLElibs/threadx/common/src/tx_semaphore_prioritize.c(162): TX_DISABLElibs/threadx/common/src/tx_semaphore_put.c(91): TX_DISABLElibs/threadx/common/src/tx_semaphore_put_notify.c(91): TX_DISABLElibs/threadx/common/src/tx_thread_create.c(219): TX_DISABLElibs/threadx/common/src/tx_thread_create.c(360): TX_DISABLElibs/threadx/common/src/tx_thread_delete.c(88): TX_DISABLElibs/threadx/common/src/tx_thread_entry_exit_notify.c(93): TX_DISABLElibs/threadx/common/src/tx_thread_identify.c(85): TX_DISABLElibs/threadx/common/src/tx_thread_info_get.c(92): TX_DISABLElibs/threadx/common/src/tx_thread_performance_info_get.c(130): TX_DISABLElibs/threadx/common/src/tx_thread_performance_system_info_get.c(112): TX_DISABLElibs/threadx/common/src/tx_thread_preemption_change.c(114): TX_DISABLElibs/threadx/common/src/tx_thread_preemption_change.c(270): TX_DISABLElibs/threadx/common/src/tx_thread_priority_change.c(100): TX_DISABLElibs/threadx/common/src/tx_thread_priority_change.c(234): TX_DISABLElibs/threadx/common/src/tx_thread_relinquish.c(97): TX_DISABLElibs/threadx/common/src/tx_thread_reset.c(88): TX_DISABLElibs/threadx/common/src/tx_thread_reset.c(144): TX_DISABLElibs/threadx/common/src/tx_thread_resume.c(111): TX_DISABLElibs/threadx/common/src/tx_thread_resume.c(191): TX_DISABLElibs/threadx/common/src/tx_thread_shell_entry.c(96): TX_DISABLElibs/threadx/common/src/tx_thread_shell_entry.c(128): TX_DISABLElibs/threadx/common/src/tx_thread_sleep.c(84): TX_DISABLElibs/threadx/common/src/tx_thread_stack_analyze.c(85): TX_DISABLElibs/threadx/common/src/tx_thread_stack_analyze.c(149): TX_DISABLElibs/threadx/common/src/tx_thread_stack_error_handler.c(93): TX_DISABLElibs/threadx/common/src/tx_thread_stack_error_handler.c(113): TX_DISABLElibs/threadx/common/src/tx_thread_stack_error_notify.c(117): TX_DISABLElibs/threadx/common/src/tx_thread_suspend.c(91): TX_DISABLElibs/threadx/common/src/tx_thread_suspend.c(165): TX_DISABLElibs/threadx/common/src/tx_thread_suspend.c(244): TX_DISABLElibs/threadx/common/src/tx_thread_suspend.c(564): TX_DISABLElibs/threadx/common/src/tx_thread_suspend.c(808): TX_DISABLElibs/threadx/common/src/tx_thread_system_resume.c(112): TX_DISABLElibs/threadx/common/src/tx_thread_system_resume.c(552): TX_DISABLElibs/threadx/common/src/tx_thread_system_suspend.c(121): TX_DISABLElibs/threadx/common/src/tx_thread_system_suspend.c(429): TX_DISABLElibs/threadx/common/src/tx_thread_system_suspend.c(660): TX_DISABLElibs/threadx/common/src/tx_thread_terminate.c(97): TX_DISABLElibs/threadx/common/src/tx_thread_terminate.c(192): TX_DISABLElibs/threadx/common/src/tx_thread_terminate.c(239): TX_DISABLElibs/threadx/common/src/tx_thread_terminate.c(268): TX_DISABLElibs/threadx/common/src/tx_thread_terminate.c(290): TX_DISABLElibs/threadx/common/src/tx_thread_timeout.c(93): TX_DISABLElibs/threadx/common/src/tx_thread_time_slice.c(106): TX_DISABLElibs/threadx/common/src/tx_thread_time_slice_change.c(87): TX_DISABLElibs/threadx/common/src/tx_thread_wait_abort.c(87): TX_DISABLElibs/threadx/common/src/tx_thread_wait_abort.c(219): TX_DISABLElibs/threadx/common/src/tx_timer_activate.c(83): TX_DISABLElibs/threadx/common/src/tx_timer_change.c(82): TX_DISABLElibs/threadx/common/src/tx_timer_create.c(100): TX_DISABLElibs/threadx/common/src/tx_timer_deactivate.c(89): TX_DISABLElibs/threadx/common/src/tx_timer_delete.c(82): TX_DISABLElibs/threadx/common/src/tx_timer_expiration_process.c(112): TX_DISABLElibs/threadx/common/src/tx_timer_expiration_process.c(140): TX_DISABLElibs/threadx/common/src/tx_timer_expiration_process.c(196): TX_DISABLElibs/threadx/common/src/tx_timer_expiration_process.c(361): TX_DISABLElibs/threadx/common/src/tx_timer_info_get.c(93): TX_DISABLElibs/threadx/common/src/tx_timer_performance_info_get.c(115): TX_DISABLElibs/threadx/common/src/tx_timer_performance_system_info_get.c(93): TX_DISABLElibs/threadx/common/src/tx_timer_thread_entry.c(114): TX_DISABLElibs/threadx/common/src/tx_timer_thread_entry.c(146): TX_DISABLElibs/threadx/common/src/tx_timer_thread_entry.c(311): TX_DISABLElibs/threadx/common/src/tx_timer_thread_entry.c(424): TX_DISABLElibs/threadx/common/src/tx_time_get.c(87): TX_DISABLElibs/threadx/common/src/tx_time_set.c(80): TX_DISABLElibs/threadx/common/src/tx_trace_enable.c(223): TX_DISABLElibs/threadx/common/src/tx_trace_enable.c(383): TX_DISABLElibs/threadx/common/src/tx_trace_interrupt_control.c(82): TX_DISABLElibs/threadx/common/src/tx_trace_isr_enter_insert.c(89): TX_DISABLElibs/threadx/common/src/tx_trace_isr_enter_insert.c(105): TX_DISABLElibs/threadx/common/src/tx_trace_isr_exit_insert.c(89): TX_DISABLElibs/threadx/common/src/tx_trace_isr_exit_insert.c(105): TX_DISABLElibs/threadx/common/src/tx_trace_object_register.c(293): TX_DISABLElibs/threadx/common/src/tx_trace_object_unregister.c(128): TX_DISABLElibs/threadx/common/src/tx_trace_user_event_insert.c(86): TX_DISABLElibs/threadx/ports/rxv3/ccrx/inc/tx_port.h(243): #define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable();libs/threadx/ports/rxv3/ccrx/inc/tx_port.h(265): #define TX_BLOCK_POOL_DISABLE TX_DISABLElibs/threadx/ports/rxv3/ccrx/inc/tx_port.h(266): #define TX_BYTE_POOL_DISABLE TX_DISABLElibs/threadx/ports/rxv3/ccrx/inc/tx_port.h(267): #define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLElibs/threadx/ports/rxv3/ccrx/inc/tx_port.h(268): #define TX_MUTEX_DISABLE TX_DISABLElibs/threadx/ports/rxv3/ccrx/inc/tx_port.h(269): #define TX_QUEUE_DISABLE TX_DISABLElibs/threadx/ports/rxv3/ccrx/inc/tx_port.h(270): #define TX_SEMAPHORE_DISABLE TX_DISABLElibs/threadx/utility/low_power/tx_low_power.c(96): TX_DISABLElibs/threadx/utility/low_power/tx_low_power.c(300): TX_DISABLElibs/threadx/utility/low_power/tx_low_power.c(431): TX_DISABLE
試しに libs/threadx/common/src/tx_semaphore_get.c を覗いてみました。やはり割り込み禁止にした状態でゴソゴソそれなりにやっていることがありますね。続く。libs/threadx/common/src/tx_semaphore_get.c (正直なところ何をやっているのかは分かりません)
UINT _tx_semaphore_get(TX_SEMAPHORE *semaphore_ptr, ULONG wait_option){TX_INTERRUPT_SAVE_AREATX_THREAD *thread_ptr;TX_THREAD *next_thread;TX_THREAD *previous_thread;UINT status; /* Default the status to TX_SUCCESS. */ status = TX_SUCCESS; /* Disable interrupts to get an instance from the semaphore. */ TX_DISABLE#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO /* Increment the total semaphore get counter. */ _tx_semaphore_performance_get_count++; /* Increment the number of attempts to get this semaphore. */ semaphore_ptr -> tx_semaphore_performance_get_count++;#endif /* If trace is enabled, insert this event into the trace buffer. */ TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_GET, semaphore_ptr, wait_option, semaphore_ptr -> tx_semaphore_count, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), TX_TRACE_SEMAPHORE_EVENTS) /* Log this kernel call. */ TX_EL_SEMAPHORE_GET_INSERT /* Determine if there is an instance of the semaphore. */ if (semaphore_ptr -> tx_semaphore_count != ((ULONG) 0)) { /* Decrement the semaphore count. */ semaphore_ptr -> tx_semaphore_count--; /* Restore interrupts. */ TX_RESTORE } /* Determine if the request specifies suspension. */ else if (wait_option != TX_NO_WAIT) { /* Determine if the preempt disable flag is non-zero. */ if (_tx_thread_preempt_disable != ((UINT) 0)) { /* Restore interrupts. */ TX_RESTORE /* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */ status = TX_NO_INSTANCE; } else { /* Prepare for suspension of this thread. */#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO /* Increment the total semaphore suspensions counter. */ _tx_semaphore_performance_suspension_count++; /* Increment the number of suspensions on this semaphore. */ semaphore_ptr -> tx_semaphore_performance_suspension_count++;#endif /* Pickup thread pointer. */ TX_THREAD_GET_CURRENT(thread_ptr) /* Setup cleanup routine pointer. */ thread_ptr -> tx_thread_suspend_cleanup = &(_tx_semaphore_cleanup); /* Setup cleanup information, i.e. this semaphore control block. */ thread_ptr -> tx_thread_suspend_control_block = (VOID *) semaphore_ptr;#ifndef TX_NOT_INTERRUPTABLE /* Increment the suspension sequence number, which is used to identify this suspension event. */ thread_ptr -> tx_thread_suspension_sequence++;#endif /* Setup suspension list. */ if (semaphore_ptr -> tx_semaphore_suspended_count == TX_NO_SUSPENSIONS) { /* No other threads are suspended. Setup the head pointer and just setup this threads pointers to itself. */ semaphore_ptr -> tx_semaphore_suspension_list = thread_ptr; thread_ptr -> tx_thread_suspended_next = thread_ptr; thread_ptr -> tx_thread_suspended_previous = thread_ptr; } else { /* This list is not NULL, add current thread to the end. */ next_thread = semaphore_ptr -> tx_semaphore_suspension_list; thread_ptr -> tx_thread_suspended_next = next_thread; previous_thread = next_thread -> tx_thread_suspended_previous; thread_ptr -> tx_thread_suspended_previous = previous_thread; previous_thread -> tx_thread_suspended_next = thread_ptr; next_thread -> tx_thread_suspended_previous = thread_ptr; } /* Increment the number of suspensions. */ semaphore_ptr -> tx_semaphore_suspended_count++; /* Set the state to suspended. */ thread_ptr -> tx_thread_state = TX_SEMAPHORE_SUSP;#ifdef TX_NOT_INTERRUPTABLE /* Call actual non-interruptable thread suspension routine. */ _tx_thread_system_ni_suspend(thread_ptr, wait_option); /* Restore interrupts. */ TX_RESTORE#else /* Set the suspending flag. */ thread_ptr -> tx_thread_suspending = TX_TRUE; /* Setup the timeout period. */ thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; /* Temporarily disable preemption. */ _tx_thread_preempt_disable++; /* Restore interrupts. */ TX_RESTORE /* Call actual thread suspension routine. */ _tx_thread_system_suspend(thread_ptr);#endif /* Return the completion status. */ status = thread_ptr -> tx_thread_suspend_status; } } else { /* Restore interrupts. */ TX_RESTORE /* Immediate return, return error completion. */ status = TX_NO_INSTANCE; } /* Return completion status. */ return(status);}
今度はTick割り込みとContext Switching割り込みを覗いてみました。割り込みルーチン先頭で割り込み許可にしているわけではありませんでした。(なお、Context Switching割り込みは、あくまでContext Switchingする処理なので、例えば、ユーザがセマフォを操作して、RTOSがセマフォを制御して、RTOSがタスクの優先度を変化させて、RTOSがタスクを実行可能状態へ遷移させ、RTOSが実行可能タスクのリストに追加して、といった処理の流れの部分は含んで無いです。)続く。libs/threadx/ports/rxv3/ccrx/src/tx_timer_interrupt.src (FITのCMTモジュールと結合する都合によりサブルーチンです)
;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; /* Check if we must trigger a context switch. */ MOV.L #__tx_thread_preempt_disable, R1 ; Load prempt disable flag. MOV.L [R1], R1 CMP #0, R1 BNE __tx_timer_not_ts_expiration ; Skip if prempt disabled. MOV.L #__tx_thread_execute_ptr, R1 MOV.L [R1], R1 MOV.L #__tx_thread_current_ptr, R2 MOV.L [R2], R2 CMP R1, R2 BEQ __tx_timer_not_ts_expiration MOV.L #SWI0, R1 MOV.L #1, [R1]; };__tx_timer_not_ts_expiration:__tx_timer_nothing_expired: POPM R1-R5 POPM R14-R15; RTS ; Return to point of interrupt;;}
src/hardware_setup.c (FITのCMTモジュールと結合する都合によりコールバックルーチンです)
/* CMT Timer callback used as the system tick. */void timer_callback(void * pdata){ _tx_timer_interrupt();}void platform_setup(void){ uint32_t chan; /* Create periodic timer for the system tick. */ R_CMT_CreatePeriodic(TX_TIMER_TICKS_PER_SECOND, timer_callback, &chan); }
libs/threadx/ports/rxv3/ccrx/src/tx_thread_schedule.src (こちらは割り込みルーチンです)
; 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
libs/threadx/ports/rxv3/ccrx/src/tx_thread_contex_save.src
;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;; };}
libs/threadx/ports/rxv3/ccrx/src/tx_thread_contex_restore.src
;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.IF __DPFPU == 1 MOV.L 144[R2], R4 ; Get tx_thread_fpu_enable. CMP #0, R4 BEQ __tx_thread_preempt_restore_fpu_skip DPUSHM.D DR0-DR15 ; Save FPU register bank if tx_thread_fpu_enable is not 0. DPUSHM.L DPSW-DECNT__tx_thread_preempt_restore_fpu_skip:.ENDIF;; /* 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; };;}
libs/threadx/ports/rxv3/ccrx/src/tx_thread_schedule.src
;VOID _tx_thread_schedule(VOID);{ .GLB __tx_thread_schedule__tx_thread_schedule:;;; /* Wait for a thread to execute. */; do; { MOV.L #__tx_thread_execute_ptr, R1 ; Address of thread to executer ptr__tx_thread_schedule_loop: SETPSW I ; Enable interrupts CLRPSW I ; Disable interrupts MOV.L [R1],R2 ; Pickup next thread to execute CMP #0,R2 ; Is it NULL? BNE __tx_thread_thread_ready ; Not NULL, schedule the thread ; Idle system - no thread is ready .IF TX_LOW_POWER==1 MOV.L #__tx_thread_preempt_disable, R1 ; Load prempt disable flag. MOV.L [R1], R2 ADD #1, R2 ; Disable preemption while enter/exit MOV.L R2, [R1] BSR _tx_low_power_enter ; Possibly enter low power mode.ENDIF.IF TX_ENABLE_WAIT==1 WAIT ; Wait for interrupt.ENDIF.IF TX_LOW_POWER==1 CLRPSW I ; Disable interrupts (because WAIT enables interrupts) BSR _tx_low_power_exit ; Possibly exit low power mode MOV.L #__tx_thread_preempt_disable, R1 ; Load prempt disable flag. MOV.L [R1], R2 SUB #1, R2 ; Enable preemption MOV.L R2, [R1] MOV.L #__tx_thread_execute_ptr, R1 ; Address of thread to executer ptr.ENDIF BRA __tx_thread_schedule_loop ; Idle system, keep checking__tx_thread_thread_ready:;; }; while(_tx_thread_execute_ptr == TX_NULL);; ; /* Yes! We have a thread to execute. Note that interrupts are locked out at this point. */;; /* 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;.IF __DPFPU == 1 MOV.L 144[R2], R1 ; Get tx_thread_fpu_enable. CMP #0, R1 BEQ __tx_thread_schedule_fpu_skip DPOPM.L DPSW-DECNT ; Restore FPU register bank if tx_thread_fpu_enable is not 0. DPOPM.D DR0-DR15__tx_thread_schedule_fpu_skip:.ENDIF 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 ;;}
なお、Context Switching割り込みですが、以下の部分で割り込み許可の窓を開けているようです。RXコアをWAIT状態に入れる前処理の`おまじない`としてでしょうか。ちがうかな、よくよく見ると、割り込み処理内でループしているようですので、WAITがどうのこうの関係無しに、ユーザ割り込み全般を待ち受けるような構造なのかな。続く?libs/threadx/ports/rxv3/ccrx/src/tx_thread_schedule.src (1つ前の投稿の最後のソースの前半です)
;VOID _tx_thread_schedule(VOID);{ .GLB __tx_thread_schedule__tx_thread_schedule:;;; /* Wait for a thread to execute. */; do; { MOV.L #__tx_thread_execute_ptr, R1 ; Address of thread to executer ptr__tx_thread_schedule_loop: SETPSW I ; Enable interrupts CLRPSW I ; Disable interrupts MOV.L [R1],R2 ; Pickup next thread to execute CMP #0,R2 ; Is it NULL? BNE __tx_thread_thread_ready ; Not NULL, schedule the thread ; Idle system - no thread is ready .IF TX_LOW_POWER==1 MOV.L #__tx_thread_preempt_disable, R1 ; Load prempt disable flag. MOV.L [R1], R2 ADD #1, R2 ; Disable preemption while enter/exit MOV.L R2, [R1] BSR _tx_low_power_enter ; Possibly enter low power mode.ENDIF.IF TX_ENABLE_WAIT==1 WAIT ; Wait for interrupt.ENDIF.IF TX_LOW_POWER==1 CLRPSW I ; Disable interrupts (because WAIT enables interrupts) BSR _tx_low_power_exit ; Possibly exit low power mode MOV.L #__tx_thread_preempt_disable, R1 ; Load prempt disable flag. MOV.L [R1], R2 SUB #1, R2 ; Enable preemption MOV.L R2, [R1] MOV.L #__tx_thread_execute_ptr, R1 ; Address of thread to executer ptr.ENDIF BRA __tx_thread_schedule_loop ; Idle system, keep checking__tx_thread_thread_ready:;; }; while(_tx_thread_execute_ptr == TX_NULL);; ; /* Yes! We have a thread to execute. Note that interrupts are locked out at this point. */;…以後省略…
こんにちは。NoMaYです。以前に別スレッドにURLを書いた個人事業主?さんが、こういう記事を執筆されていました。Azure RTOS習得(1):習得方針2022年5月27日 WithHappyhappytech.jp/wordpress/2022/05/27/azure-rtos-acquisition-1-acquisition-policy/なお、これに続く記事はSTM32特化の記事です。ちなみに、Azure RTOSについてではありませんが、RAマイコンの記事も執筆されています。
こんにちは。NoMaYです。RXコア向けのAzure RTOSカーネルではPSWのIビットでカーネル内の割り込みの禁止/許可を制御していますが、Cortex-Mコア向けのAzure RTOSカーネルではRXコアのPSWのIPLフィールドと同様の意味合いのもので制御することが出来るようになっていますね。(ですので、FreeRTOSカーネルと同様なことが出来る。) ルネサスさんは認識済みだろうか、、、Cortex-M port: TX_PORT_USE_BASEPRI and TX_PORT_BASEPRI has no effect on assembly codegithub.com/azure-rtos/threadx/issues/168