1;/*
2; * FreeRTOS Kernel V11.1.0
3; * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4; *
5; * SPDX-License-Identifier: MIT
6; *
7; * Permission is hereby granted, free of charge, to any person obtaining a copy of
8; * this software and associated documentation files (the "Software"), to deal in
9; * the Software without restriction, including without limitation the rights to
10; * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11; * the Software, and to permit persons to whom the Software is furnished to do so,
12; * subject to the following conditions:
13; *
14; * The above copyright notice and this permission notice shall be included in all
15; * copies or substantial portions of the Software.
16; *
17; * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18; * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19; * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20; * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21; * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22; * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23; *
24; * https://www.FreeRTOS.org
25; * https://github.com/FreeRTOS
26; *
27; */
28
29#include "porthardware.h"
30
31; Declare all extern symbols here - including any ISRs that are referenced in
32; the vector table.
33
34; ISR functions
35; -------------
36EXTERN TICK_INT
37
38; Functions used by scheduler
39; ---------------------------
40EXTERN vTaskSwitchContext
41EXTERN pxCurrentTCB
42EXTERN xTaskIncrementTick
43EXTERN uxCriticalNesting
44
45; Functions implemented in this file
46; ----------------------------------
47PUBLIC vPortYield
48PUBLIC vPortYieldFromTick
49PUBLIC vPortYieldFromISR
50PUBLIC vPortStart
51
52; Interrupt vector table.
53; -----------------------
54;
55; For simplicity the RTOS tick interrupt routine uses the __task keyword.
56; As the IAR compiler does not permit a function to be declared using both
57; __task and __interrupt, the use of __task necessitates that the interrupt
58; vector table be setup manually.
59;
60; To write an ISR, implement the ISR function using the __interrupt keyword
61; but do not install the interrupt using the "#pragma vector=ABC" method.
62; Instead manually place the name of the ISR in the vector table using an
63; ORG and jmp instruction as demonstrated below.
64; You will also have to add an EXTERN statement at the top of the file.
65
66    ASEG
67
68    ORG TICK_INT_vect                   ; Vector address
69        jmp TICK_INT                    ; ISR
70
71    RSEG CODE
72
73CLR_INT MACRO  FLAG_REG, FLAG_MASK
74    st -y, r16
75    ldi r16, FLAG_MASK
76    sts FLAG_REG, r16
77    ld r16, y+
78
79    ENDM
80
81; Saving and Restoring a Task Context and Task Switching
82; ------------------------------------------------------
83;
84; The IAR compiler does not fully support inline assembler, so saving and
85; restoring a task context has to be written in an asm file.
86;
87; vPortYield() and vPortYieldFromTick() are usually written in C.  Doing
88; so in this case would required calls to be made to portSAVE_CONTEXT() and
89; portRESTORE_CONTEXT().  This is dis-advantageous as the context switch
90; function would require two extra jump and return instructions over the
91; WinAVR equivalent.
92;
93; To avoid this I have opted to implement both vPortYield() and
94; vPortYieldFromTick() in this assembly file.  For convenience
95; portSAVE_CONTEXT and portRESTORE_CONTEXT are implemented as macros.
96
97portSAVE_CONTEXT MACRO
98    st  -y, r0          ; First save the r0 register - we need to use this.
99    in  r0, SREG        ; Obtain the SREG value so we can disable interrupts...
100    cli                 ; ... as soon as possible.
101    st  -y, r0          ; Store the SREG as it was before we disabled interrupts.
102
103    in  r0, SPL         ; Next store the hardware stack pointer.  The IAR...
104    st  -y, r0          ; ... compiler uses the hardware stack as a call stack ...
105    in  r0, SPH         ; ...  only.
106    st  -y, r0
107
108    st  -y, r1          ; Now store the rest of the registers.  Dont store the ...
109    st  -y, r2          ; ... the Y register here as it is used as the software
110    st  -y, r3          ; stack pointer and will get saved into the TCB.
111    st  -y, r4
112    st  -y, r5
113    st  -y, r6
114    st  -y, r7
115    st  -y, r8
116    st  -y, r9
117    st  -y, r10
118    st  -y, r11
119    st  -y, r12
120    st  -y, r13
121    st  -y, r14
122    st  -y, r15
123    st  -y, r16
124    st  -y, r17
125    st  -y, r18
126    st  -y, r19
127    st  -y, r20
128    st  -y, r21
129    st  -y, r22
130    st  -y, r23
131    st  -y, r24
132    st  -y, r25
133    st  -y, r26
134    st  -y, r27
135    st  -y, r30
136    st  -y, r31
137
138    lds r0, uxCriticalNesting
139    st  -y, r0                  ; Store the critical nesting counter.
140
141    lds r26, pxCurrentTCB       ; Finally save the software stack pointer (Y ...
142    lds r27, pxCurrentTCB + 1   ; ... register) into the TCB.
143    st  x+, r28
144    st  x+, r29
145
146    ENDM
147
148
149portRESTORE_CONTEXT MACRO
150    lds r26, pxCurrentTCB
151    lds r27, pxCurrentTCB + 1       ; Restore the software stack pointer from ...
152    ld  r28, x+                     ; the TCB into the software stack pointer (...
153    ld  r29, x+                     ; ... the Y register).
154
155    ld  r0, y+
156    sts uxCriticalNesting, r0
157
158    ld  r31, y+                     ; Restore the registers down to R0.  The Y
159    ld  r30, y+                     ; register is missing from this list as it
160    ld  r27, y+                     ; has already been restored.
161    ld  r26, y+
162    ld  r25, y+
163    ld  r24, y+
164    ld  r23, y+
165    ld  r22, y+
166    ld  r21, y+
167    ld  r20, y+
168    ld  r19, y+
169    ld  r18, y+
170    ld  r17, y+
171    ld  r16, y+
172    ld  r15, y+
173    ld  r14, y+
174    ld  r13, y+
175    ld  r12, y+
176    ld  r11, y+
177    ld  r10, y+
178    ld  r9, y+
179    ld  r8, y+
180    ld  r7, y+
181    ld  r6, y+
182    ld  r5, y+
183    ld  r4, y+
184    ld  r3, y+
185    ld  r2, y+
186    ld  r1, y+
187
188    ld  r0, y+                      ; The next thing on the stack is the ...
189    out SPH, r0                     ; ... hardware stack pointer.
190    ld  r0, y+
191    out SPL, r0
192
193    ld  r0, y+                      ; Next there is the SREG register.
194    out SREG, r0
195
196    ld  r0, y+                      ; Finally we have finished with r0, so restore r0.
197
198    ENDM
199
200
201
202; vPortYield(), vPortYieldFromTick() and vPortYieldFromISR()
203; -------------------------------------
204;
205; Manual and preemptive context switch functions respectively.
206; The IAR compiler does not fully support inline assembler,
207; so these are implemented here rather than the more usually
208; place of within port.c.
209
210vPortYield:
211    portSAVE_CONTEXT                ; Save the context of the current task.
212    call vTaskSwitchContext         ; Call the scheduler.
213    portRESTORE_CONTEXT             ; Restore the context of whichever task the ...
214    ret                             ; ... scheduler decided should run.
215
216vPortYieldFromTick:
217    CLR_INT INT_FLAGS, INT_MASK     ; Clear tick interrupt flag
218
219    portSAVE_CONTEXT                ; Save the context of the current task.
220    call xTaskIncrementTick         ; Call the timer tick function.
221    tst r16
222    breq SkipTaskSwitch
223    call vTaskSwitchContext         ; Call the scheduler.
224
225SkipTaskSwitch:
226    portRESTORE_CONTEXT             ; Restore the context of whichever task the ...
227    reti                            ; ... scheduler decided should run.
228
229vPortYieldFromISR:
230    portSAVE_CONTEXT                ; Save the context of the current task.
231    call vTaskSwitchContext         ; Call the scheduler.
232    portRESTORE_CONTEXT             ; Restore the context of whichever task the ...
233    reti                            ; ... scheduler decided should run.
234
235; vPortStart()
236; ------------
237;
238; Again due to the lack of inline assembler, this is required
239; to get access to the portRESTORE_CONTEXT macro.
240
241vPortStart:
242        portRESTORE_CONTEXT
243        ret
244
245; Just a filler for unused interrupt vectors.
246vNoISR:
247    reti
248
249END
250