summaryrefslogtreecommitdiff
path: root/nuttx/arch/pjrc-8051/src/up_savecontext.c
blob: 83310534caca8d97413eb31c6c81b24f357e270e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/**************************************************************************
 * up_savecontext.c
 *
 *   Copyright (C) 2007 Gregory Nutt. All rights reserved.
 *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name Gregory Nutt nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 **************************************************************************/

/**************************************************************************
 * Included Files
 **************************************************************************/

#include <nuttx/config.h>
#include <sys/types.h>
#include <nuttx/irq.h>
#include "up_internal.h"

/**************************************************************************
 * Private Definitions
 **************************************************************************/

/**************************************************************************
 * Private Types
 **************************************************************************/

/**************************************************************************
 * Private Function Prototypes
 **************************************************************************/

/**************************************************************************
 * Global Variables
 **************************************************************************/

/**************************************************************************
 * Private Variables
 **************************************************************************/

/**************************************************************************
 * Private Functions
 **************************************************************************/

/**************************************************************************
 * Name: up_savestack
 *
 * Description:
 *   Save the entire interrupt stack contents in the provided context
 *   structure.
 *
 * Inputs:
 *   context - the context structure in which to save the stack info
 *
 * Return:
 *   None
 *
 * Assumptions:
 *   - Interrupts are disabled
 *
 **************************************************************************/

static void up_savestack(FAR struct xcptcontext *context, ubyte tos)
{
  /* Copy the current stack frame from internal RAM to XRAM. */

  ubyte nbytes     = tos - (STACK_BASE-1);
  NEAR ubyte *src  = (NEAR ubyte*)STACK_BASE;
  FAR  ubyte *dest = context->stack;

  context->nbytes = nbytes;
  while (nbytes--)
    {
      *dest++ = *src++;
    }
}

/**************************************************************************
 * Name: up_saveregs
 *
 * Description:
 *   Save the interrupt registers into the TCB.
 *
 * Inputs:
 *   context - the context structure in which to save the register info
 *
 * Return:
 *   None
 *
 * Assumptions:
 *   - Interrupts are disabled
 *
 **************************************************************************/

static void up_saveregs(FAR struct xcptcontext *context, ubyte tos)
{
  /* Copy the irq register save area into the TCB */

  FAR ubyte *src  = g_irqregs;
  FAR ubyte *dest = context->regs;
  ubyte nbytes    = REGS_SIZE;

  while (nbytes--)
    {
      *dest++ = *src++;
    }
}

/**************************************************************************
 * Public Functions
 **************************************************************************/

/**************************************************************************
 * Name: up_saveregisters
 *
 * Description:
 *   Save the current registers in the context save area.  This function
 *   is called from up_savecontext (below) and also from interrupt
 *   handling logic.
 *
 *   Note that this function does not save:
 *   a, dptr, ie - these are saved in the stack area
 *   sp - this can be inferred from g_irqtos or struct xcptontext.nbytes.
 *
 * Inputs:
 *   regs - the context register array in which to save the register info
 *
 * Return:
 *   None
 *
 **************************************************************************/

void up_saveregisters(FAR ubyte *regs) _naked
{
 _asm
	mov	a, b
	movx	@dptr, a
	inc	dptr
	mov	a, r2
	movx	@dptr, a
	inc	dptr
	mov	a, r3
	movx	@dptr, a
	inc	dptr
	mov	a, r4
	movx	@dptr, a
	inc	dptr
	mov	a, r5
	movx	@dptr, a
	inc	dptr
	mov	a, r6
	movx	@dptr, a
	inc	dptr
	mov	a, r7
	movx	@dptr, a
	inc	dptr
	mov	a, r0
	movx	@dptr, a
	inc	dptr
	mov	a, r1
	movx	@dptr, a
	inc	dptr
	mov	a, psw
	movx	@dptr, a
	clr	psw
	inc	dptr
	mov	a, _bp
	movx	@dptr, a
	ret
  _endasm;
}

/**************************************************************************
 * Name: up_savecontext
 *
 * Description:
 *   Push the current execution context onto the stack, then save the
 *   entire stack contents in the provided context structure.
 *
 * Inputs:
 *   context - the context structure in which to save the stack info
 *
 * Return:
 *   0 = Normal state save return
 *   1 = This is the matching return from up_restorecontext()
 *
 **************************************************************************/

ubyte up_savecontext(FAR struct xcptcontext *context) _naked
{
 _asm
	/* Create the stack frame that we want when it is time to restore
	 * this context.  The return address will be the return address
	 * of this function, the return value will be zero.
         *
         * ...
         * return address (2 bytes, already on the stack)
         * register a=0   (1 byte)
         * register ie    (1 byte)
         * register dptr  (2 bytes)
	 */

	clr	a
	push	acc	/* ACC = 0 */
	push	ie
	mov	a, #1
	push	acc	/* DPL = 1 */
	clr	a
	push	acc	/* DPH = 0 */

	/* Dump the stack contents before they are occupied into XRAM */

#ifdef CONFIG_SWITCH_FRAME_DUMP
	push	dpl
	push	dph
	lcall	_up_dumpstack
	pop	dph
	pop	dpl
#endif
	/* Disable interrupts while we create a snapshot of the stack
         * and registers.  At this point, we have 5 bytes on the stack
	 * to account for.
         */

	push	ie
	mov	ea, 0

	/* Save the registers in the context save area */

	push	dpl
	push	dph
	mov	a, #XCPT_REGS
	add	a, dpl
	mov	dpl, a
	clr	a
	addc	a, dph
	mov	dph, a
	lcall	_up_saveregisters
	pop	dph
	pop	dpl

#ifdef CONFIG_SWITCH_FRAME_DUMP
	/* Save the address of the context structure.  We will
	 * need this later to dump the saved frame.  Now we have
	 * 7 bytes on the stack to account for.
	 */

	push	dpl
	push	dph

	/* Push the top of frame stack pointer.  We need to
	 * decrement the current SP value by three to account
	 * for dpst+IE on the stack above the end of the frame.
	 */

	mov	a, sp
	subb	a, #3
#else
	/* Push the top of frame stack pointer.  We need to
	 * decrement the current stack pointer by one to account
	 * for IE that we saved on the stack.
	 */

	mov	a, sp
	dec	a
#endif
	push	acc

	/* Copy the current stack frame from internal RAM to XRAM. */

	lcall	_up_savestack
	pop	acc

	/* Dump the contents of the saved frame after it has been
	 * copied from  memory/registers.
	 */

#ifdef CONFIG_SWITCH_FRAME_DUMP
	pop	dph
	pop	dpl
	push	dpl
	push	dph
	lcall	_up_dumpframe
	pop	dph
	pop	dpl
	lcall	_up_dumpstack
#endif

	/* Restore the interrupt state */

	pop	ie

	/* Now that we have a snapshot of the desired stack frame saved,
	 * we can release the stack frame (all but the return address)
	 */

	mov	a, sp
	subb	a, #4
	mov	sp, a
	mov	dpl,#0
	ret
  _endasm;
}

/**************************************************************************
 * Name: up_saveirqcontext
 *
 * Description:
 *   The interrupt context was saved in g_irqtos and g_irqregs when the
 *   interrupt was taken.  If a context switch from the interrupted task
 *   will be made at the interrupt level, then these saved values must be
 *   copied into the TCB.
 *
 * Inputs:
 *   context - the structure in which to save the context info
 *
 * Return:
 *   None
 *
 * Assumptions:
 *   - Interrupts are disabled
 *
 **************************************************************************/

void up_saveirqcontext(FAR struct xcptcontext *context)
{
  /* Save the number of bytes in the stack */

   context->nbytes = g_irqtos - (STACK_BASE-1);

  /* Copy the current stack frame from internal RAM to XRAM. */

  up_savestack(context, g_irqtos);

  /* Copy the saved registers into the TCB */

  up_saveregisters(context->regs);
}