こんにちは。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/
今度は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