1/*
2 * Copyright (c) 2021  KT-Elektronik, Klaucke und Partner GmbH
3 * Copyright (c) 2024 Renesas Electronics Corporation
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include <zephyr/toolchain.h>
8#include <zephyr/linker/sections.h>
9#include <offsets_short.h>
10
11GTEXT(_z_rx_arch_switch)
12GTEXT(_switch_isr_wrapper)
13
14/* void z_rx_arch_switch(void *switch_to, void **switched_from)
15 *
16 * @brief switch between threads
17 *
18 * @param switch_to      (r1)  pointer to switch handle of the new thread
19 * @param switched_from  (r2)  pointer to pointer to switch handle of the old
20 *                             thread
21 *
22 * Thread-switching is treated differently depending on whether it is a
23 * cooperative switch triggered by old thread itself or a preemptive switch
24 * triggered by an interrupt (in this case the function has been called from an
25 * ISR).
26 */
27.section .text._z_rx_arch_switch
28.align 4
29_z_rx_arch_switch:
30
31	mvfc psw,r3
32	tst #0x130000, r3		/* test if PM, U or I bit are set*/
33	bz _z_rx_context_switch_isr	/* if none of them are set, this is an isr */
34
35	mov #_coop_switch_to,r3
36	mov r1,[r3]
37	mov #_coop_switched_from,r3
38	mov r2,[r3]
39
40	/* trigger unconditional interrupt dedicated to thread switching. The content of r1 and r2
41	 * will not change by invoking the interrupt so the parameters switch_to and switched_from
42	 * will be available in _z_rx_context_switch_isr, which has been entered into the vector
43	 * table as ISR for interrupt 1
44	 */
45	int #1
46
47	/* at this point, r0 points to the entry point, so RTS will enter it */
48	rts
49
50/* void switch_isr_wrapper(void)
51 *
52 * @brief isr for interrupt 1 as wrapper for _z_rx_context_switch_isr
53 *
54 * _z_rx_context_switch_isr ends in rts, so it does not return from the interrupt context
55 */
56.section .text._switch_isr_wrapper
57.align 4
58_switch_isr_wrapper:
59	pushm r1-r15
60
61	/* Save the accumulator. */
62	mvfachi r15 /* Accumulator high 32 bits. */
63	push r15
64	mvfacmi r15 /* Accumulator middle 32 bits. */
65	shll #16, r15  /* Shifted left as it is restored to the low order word.*/
66	push r15
67
68	mov #_coop_switch_to,r3
69	mov [r3],r1
70	mov #_coop_switched_from,r3
71	mov [r3],r2
72
73	bsr _z_rx_context_switch_isr
74
75	/* Restore the registers from the stack of the task pointed to by
76	pxCurrentTCB. */
77	pop r15
78	mvtaclo r15 /* Accumulator low 32 bits. */
79	pop r15
80	mvtachi r15 /* Accumulator high 32 bits. */
81
82	popm r1-r15
83	rte
84
85/* void z_rx_context_switch_isr(void *switch_to, void **switched_from)
86 *
87 * @brief switch between threads in the interrupt context
88 *
89 * @param switch_to      (r1)  pointer to switch handle of the new thread
90 * @param switched_from  (r2)  pointer to pointer to switch handle of the old thread
91 *
92 * since this is part of an ISR, PSW, PC and general registers of the old thread are already
93 * stored in the interrupt stack, so copy the corresponding part of the interrupt stack to the
94 * stack of the interrupted thread
95 */
96_z_rx_context_switch_isr:
97
98	/* store arguments switch_to and switched_from to registers r4 and r5 as
99	 * registers r2 and r3 are needed for the smovf operation */
100	mov r1,r4
101	mov r2,r5
102
103	/* set r2 (smovb source address) to the beginning of the interrupt stack */
104	mov #(_z_interrupt_stacks + CONFIG_ISR_STACK_SIZE)-1,r2
105
106	mvfc usp,r1	/* set r1 (smovb dest) to USP */
107
108	sub #1,r1	/* correct by one byte to use smovb compared to push/pop */
109
110	/* set r3 to number of bytes to move
111	*  Accumulator 64bit (4byte * 2)
112	*	15*4 byte for 15 general registers
113	*	+ PSW (4 byte)
114	*	+ PC (4 byte)
115	*/
116	mov #76,r3
117	smovb		/* block copy from interrupt stack to old thread stack */
118
119	add #1,r1	/* smovb leaves r1 pointing 1 byte before the stack */
120	add #1,r2	/* same with r2 */
121
122	mov r1,[r5]	/* store stack pointer of old thread in *switched_from */
123
124	mov r2,r1	/* set r1 (smovf dest) to the beginning of the interrupt stack */
125
126	mov r4,r2	/* set r2 (smovf source) to the sp of the new thread*/
127	mov #76,r3	/* set r3 to number of bytes to move  */
128
129	smovf		/* block copy from new thread stack to interrupt stack */
130
131	mvtc r2,usp	/* set USP to the new thread stack */
132
133#ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING
134	bsr _z_thread_mark_switched_in
135#endif
136
137	rts
138