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, RAMPZ
104    st  -y, r0
105
106    in  r0, SPL         ; Next store the hardware stack pointer.  The IAR...
107    st  -y, r0          ; ... compiler uses the hardware stack as a call stack ...
108    in  r0, SPH         ; ...  only.
109    st  -y, r0
110
111    st  -y, r1          ; Now store the rest of the registers.  Dont store the ...
112    st  -y, r2          ; ... the Y register here as it is used as the software
113    st  -y, r3          ; stack pointer and will get saved into the TCB.
114    st  -y, r4
115    st  -y, r5
116    st  -y, r6
117    st  -y, r7
118    st  -y, r8
119    st  -y, r9
120    st  -y, r10
121    st  -y, r11
122    st  -y, r12
123    st  -y, r13
124    st  -y, r14
125    st  -y, r15
126    st  -y, r16
127    st  -y, r17
128    st  -y, r18
129    st  -y, r19
130    st  -y, r20
131    st  -y, r21
132    st  -y, r22
133    st  -y, r23
134    st  -y, r24
135    st  -y, r25
136    st  -y, r26
137    st  -y, r27
138    st  -y, r30
139    st  -y, r31
140
141    lds r0, uxCriticalNesting
142    st  -y, r0                  ; Store the critical nesting counter.
143
144    lds r26, pxCurrentTCB       ; Finally save the software stack pointer (Y ...
145    lds r27, pxCurrentTCB + 1   ; ... register) into the TCB.
146    st  x+, r28
147    st  x+, r29
148
149    ENDM
150
151
152portRESTORE_CONTEXT MACRO
153    lds r26, pxCurrentTCB
154    lds r27, pxCurrentTCB + 1       ; Restore the software stack pointer from ...
155    ld  r28, x+                     ; the TCB into the software stack pointer (...
156    ld  r29, x+                     ; ... the Y register).
157
158    ld  r0, y+
159    sts uxCriticalNesting, r0
160
161    ld  r31, y+                     ; Restore the registers down to R0.  The Y
162    ld  r30, y+                     ; register is missing from this list as it
163    ld  r27, y+                     ; has already been restored.
164    ld  r26, y+
165    ld  r25, y+
166    ld  r24, y+
167    ld  r23, y+
168    ld  r22, y+
169    ld  r21, y+
170    ld  r20, y+
171    ld  r19, y+
172    ld  r18, y+
173    ld  r17, y+
174    ld  r16, y+
175    ld  r15, y+
176    ld  r14, y+
177    ld  r13, y+
178    ld  r12, y+
179    ld  r11, y+
180    ld  r10, y+
181    ld  r9, y+
182    ld  r8, y+
183    ld  r7, y+
184    ld  r6, y+
185    ld  r5, y+
186    ld  r4, y+
187    ld  r3, y+
188    ld  r2, y+
189    ld  r1, y+
190
191    ld  r0, y+                      ; The next thing on the stack is the ...
192    out SPH, r0                     ; ... hardware stack pointer.
193    ld  r0, y+
194    out SPL, r0
195
196    ld  r0, y+
197    out RAMPZ, r0
198
199    ld  r0, y+                      ; Next there is the SREG register.
200    out SREG, r0
201
202    ld  r0, y+                      ; Finally we have finished with r0, so restore r0.
203
204    ENDM
205
206
207
208; vPortYield(), vPortYieldFromTick() and vPortYieldFromISR()
209; -------------------------------------
210;
211; Manual and preemptive context switch functions respectively.
212; The IAR compiler does not fully support inline assembler,
213; so these are implemented here rather than the more usually
214; place of within port.c.
215
216vPortYield:
217    portSAVE_CONTEXT                ; Save the context of the current task.
218    call vTaskSwitchContext         ; Call the scheduler.
219    portRESTORE_CONTEXT             ; Restore the context of whichever task the ...
220    ret                             ; ... scheduler decided should run.
221
222vPortYieldFromTick:
223    CLR_INT INT_FLAGS, INT_MASK     ; Clear tick interrupt flag
224
225    portSAVE_CONTEXT                ; Save the context of the current task.
226    call xTaskIncrementTick         ; Call the timer tick function.
227    tst r16
228    breq SkipTaskSwitch
229    call vTaskSwitchContext         ; Call the scheduler.
230
231SkipTaskSwitch:
232    portRESTORE_CONTEXT             ; Restore the context of whichever task the ...
233    reti                            ; ... scheduler decided should run.
234
235vPortYieldFromISR:
236    portSAVE_CONTEXT                ; Save the context of the current task.
237    call vTaskSwitchContext         ; Call the scheduler.
238    portRESTORE_CONTEXT             ; Restore the context of whichever task the ...
239    reti                            ; ... scheduler decided should run.
240
241; vPortStart()
242; ------------
243;
244; Again due to the lack of inline assembler, this is required
245; to get access to the portRESTORE_CONTEXT macro.
246
247vPortStart:
248    portRESTORE_CONTEXT
249    ret
250
251; Just a filler for unused interrupt vectors.
252vNoISR:
253    reti
254
255    END
256