summaryrefslogtreecommitdiff
path: root/Source/portable/SDCC/PIC18/portmacro.h
blob: 6d594cc7aa6d216abd863cdc85235a02393a3257 (plain)
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
363
364
365
366
367
368
369
370
371
372
/**
* #######################################################################################
* GAYE Abdoulaye Walsimou, <walsimou@walsimou.com>
* Copyright(C) 2009 GAYE Abdoulaye walsimou, <walsimou@walsimou.com>. All rights reserved.
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License
* (Version 2 or later) published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
* #######################################################################################
*
* \file         portmacro.h
* \brief        portmacro.h for PIC18 SDCC port as required for FreeRTOS
* \brief	It is based on existing PIC18 port.
* \author       GAYE Abdoulaye Walsimou, <walsimou@walsimou.com>
* \date         february 2009
* #######################################################################################
*/

#ifndef PORTMACRO_H
#define PORTMACRO_H

#include <pic18fregs.h>
#include <math.h>

/*-----------------------------------------------------------
 * Port specific definitions.
 *
 * The settings in this file configure FreeRTOS correctly for the
 * given hardware and compiler.
 *
 * These settings should not be altered.
 *-----------------------------------------------------------
 */

/* Type definitions. */
#define portCHAR		char
#define portFLOAT		float
#define portDOUBLE		double
#define portLONG		long
#define portINT                 int
#define portSHORT		short
#define portSTACK_TYPE		__data unsigned char
#define portBASE_TYPE		char

/* Some memory areas get saved as part of the task context.  These memory
area's get used by the compiler for temporary storage, especially when
performing mathematical operations, or when using 32bit data types.  This
constant defines the size of memory area which must be saved. */
#define portCOMPILER_MANAGED_MEMORY_SIZE	((unsigned portCHAR)20)


#if( configUSE_16_BIT_TICKS == 1 )
	typedef unsigned portSHORT portTickType;
	#define portMAX_DELAY ( portTickType ) 0xffff
#else
	typedef unsigned portLONG portTickType;
	#define portMAX_DELAY ( portTickType ) 0xffffffff
#endif
/*-----------------------------------------------------------*/

/* Hardware specifics. */
#define portBYTE_ALIGNMENT			1
#define portGLOBAL_INT_ENABLE_BIT		0x80
#define portSTACK_GROWTH			-1
#define portTICK_RATE_MS			(1000/configTICK_RATE_HZ)
/*-----------------------------------------------------------*/

/*
 * Critical section management.
 */
#define portDISABLE_INTERRUPTS()	INTCONbits.GIE = 0
#define portENABLE_INTERRUPTS()		INTCONbits.GIE = 1

/* Push the INTCON register onto the stack, then disable interrupts. */
#define portENTER_CRITICAL()	POSTDEC1 = INTCON; portDISABLE_INTERRUPTS()

/* Retrieve the INTCON register from the stack, and enable interrupts
if they were saved as being enabled.  Don't modify any other bits
within the INTCON register as these may have lagitimately have been
modified within the critical region. */
#define portEXIT_CRITICAL()							        \
_asm										        \
	MOVF	PREINC1, 1, 0;							        \
_endasm;									        \
if(INDF1&portGLOBAL_INT_ENABLE_BIT)						        \
{										        \
	portENABLE_INTERRUPTS();						        \
}
/*-----------------------------------------------------------*/

/* Task utilities. */
extern void vPortYield( void ) __naked;
#define portYIELD()				vPortYield()
/*-----------------------------------------------------------*/

/* Task function macros as described on the FreeRTOS.org WEB site. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/

/* Required by the kernel aware debugger. */
#ifdef __DEBUG
	#define portREMOVE_STATIC_QUALIFIER
#endif

#define portNOP() Nop()
/*
 * portSAVE_CONTEXT(ucForcedInterruptFlags):
 * Macro that pushes all the registers that make up the context of a task onto
 * the stack, then saves the new top of stack into the TCB.
 *
 * If this is called from an ISR then the interrupt enable bits must have been
 * set for the ISR to ever get called.  Therefore we want to save the INTCON
 * register with the enable bits forced to be set - and ucForcedInterruptFlags
 * must contain these bit settings.  This means the interrupts will again be
 * enabled when the interrupted task is switched back in.
 *
 * If this is called from a manual context switch (i.e. from a call to yield),
 * then we want to save the INTCON so it is restored with its current state,
 * and ucForcedInterruptFlags must be 0.  This allows a yield from within
 * a critical section.
 *
 * The compiler uses some locations at the bottom of the memory for temporary
 * storage during math and other computations.  This is especially true if
 * 32bit data types are utilised (as they are by the scheduler).  The .registers
 * section have to be stored in there entirety as part of a task context.
 * This macro stores from data address 0x00 to portCOMPILER_MANAGED_MEMORY_SIZE.
 * This is sufficient for the demo applications but you should check the map file
 * for your project to ensure this is sufficient for your needs.
 * It is not clear whether this size is fixed for all compilations or has the
 * potential to be program specific.
 */

#pragma preproc_asm -
#define portSAVE_CONTEXT_GLOBAL_REGISTERS() _asm
        ;Save the status and WREG registers first, as these will get modified
        ;by the operations below.
        MOVFF	WREG,POSTDEC1
        MOVFF   STATUS,POSTDEC1
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define portSAVE_CONTEXT_HW_REGISTERS() _asm
        ;Store the necessary hardware registers to the stack.
        MOVFF	BSR,POSTDEC1
        MOVFF	FSR2L,POSTDEC1
        MOVFF	FSR2H,POSTDEC1
        MOVFF	FSR0L,POSTDEC1
        MOVFF	FSR0H,POSTDEC1
        MOVFF	TABLAT,POSTDEC1
        MOVFF	TBLPTRL,POSTDEC1
        MOVFF	TBLPTRH,POSTDEC1
        MOVFF	TBLPTRU,POSTDEC1
        MOVFF	PRODL,POSTDEC1
        MOVFF	PRODH,POSTDEC1
        MOVFF	PCLATH,POSTDEC1
        MOVFF	PCLATU,POSTDEC1
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define portSAVE_CONTEXT_DOT_REGISTERS_START() _asm
        ;Start to store .registers areas as described above.
        CLRF    FSR0L,ACCESS
        CLRF    FSR0H,ACCESS
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define portSAVE_CONTEXT_DOT_REGISTERS_END() _asm
        ;End store .registers areas as described above.
        MOVFF	INDF0,POSTDEC1
        MOVFF   FSR0L,POSTDEC1
        MOVFF   FSR0H,POSTDEC1
        ;Store the hardware stack pointer in a temp register (FSR0L) before we
        ;modify it.
        MOVFF	STKPTR,FSR0L
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define	portSAVE_CONTEXT_HWSTACK() _asm
        MOVFF	TOSL,POSTDEC1
        MOVFF	TOSH,POSTDEC1
        MOVFF	TOSU,POSTDEC1
        POP
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define	portSAVE_CONTEXT_END() _asm
        ;Store the number of addresses on the hardware stack (from the
        ;temporary register).
        MOVFF	FSR0L,POSTDEC1
        ;Save the new top of the software stack in the TCB.
        MOVFF	_pxCurrentTCB,FSR0L
        MOVFF	_pxCurrentTCB+1,FSR0H
        MOVFF	FSR1L,POSTINC0
        MOVFF	FSR1H,POSTINC0
_endasm
#pragma preproc_asm +

#define	portSAVE_CONTEXT(ucForcedInterruptFlags)				        \
{										        \
        portSAVE_CONTEXT_GLOBAL_REGISTERS();                                            \
        _asm                                                                            \
                MOVFF	INTCON,WREG                                                     \
        _endasm;                                                                        \
        _asm                                                                            \
                IORLW	ucForcedInterruptFlags                                          \
        _endasm;                                                                        \
        _asm                                                                            \
                MOVFF	WREG,POSTDEC1                                                   \
        _endasm;                                                                        \
	portDISABLE_INTERRUPTS();                                                       \
        portSAVE_CONTEXT_HW_REGISTERS();                                                \
        portSAVE_CONTEXT_DOT_REGISTERS_START();                                         \
        while(FSR0L<(unsigned portCHAR)(portCOMPILER_MANAGED_MEMORY_SIZE-1))            \
        {                                                                               \
                _asm                                                                    \
                        MOVFF	POSTINC0,POSTDEC1                                       \
                _endasm;                                                                \
        }                                                                               \
        portSAVE_CONTEXT_DOT_REGISTERS_END();                                           \
        while(STKPTR>(unsigned portCHAR)0)                                              \
        {                                                                               \
                portSAVE_CONTEXT_HWSTACK();                                             \
        }                                                                               \
        portSAVE_CONTEXT_END();                                                         \
}
/*-----------------------------------------------------------*/

/*
 * portRESTORE_CONTEXT():
 * This is the reverse of portSAVE_CONTEXT.  See portSAVE_CONTEXT for more
 * details.
 */
#pragma preproc_asm -
#define portRESTORE_CONTEXT_GET_PXCURRENTTCB() _asm
        ;Set FSR0 to point to pxCurrentTCB.
        MOVFF   _pxCurrentTCB,FSR0L
        MOVFF   _pxCurrentTCB+1,FSR0H
        ;De-reference FSR0 to set the address it holds into FSR1.
        ;(i.e. pxCurrentTCB->pxTopOfStack)
        MOVFF	POSTINC0,FSR1L
        MOVFF	POSTINC0,FSR1H
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define portRESTORE_CONTEXT_GET_STACKDEPTH() _asm
        ;How many return addresses are there on the hardware stack?
        MOVFF	PREINC1, FSR0L
        ;(Above FSR0L is used as temp register.)
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define portRESTORE_CONTEXT_FILL_HWSTACK() _asm
        PUSH
        MOVF	PREINC1,0,ACCESS
        MOVWF	TOSU,ACCESS
        MOVF	PREINC1,0,ACCESS
        MOVWF	TOSH,ACCESS
        MOVF	PREINC1,0,ACCESS
        MOVWF	TOSL,ACCESS
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define portRESTORE_CONTEXT_DOT_REGISTERS_START() _asm
        ;Start to restore the .registers section.
        MOVFF   PREINC1,FSR0H
        MOVFF   PREINC1,FSR0L
        ;Use WREG as temp register
        CLRF    FSR2L,ACCESS
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define portRESTORE_CONTEXT_DOT_REGISTERS_END() _asm
        ;End to restore the .registers section.
       MOVFF   PREINC1,INDF0
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define portRESTORE_CONTEXT_HW_REGISTERS() _asm
        ;Restore the other registers forming the tasks context.
        MOVFF	PREINC1, PCLATU
        MOVFF	PREINC1, PCLATH
        MOVFF	PREINC1, PRODH
        MOVFF	PREINC1, PRODL
        MOVFF	PREINC1, TBLPTRU
        MOVFF	PREINC1, TBLPTRH
        MOVFF	PREINC1, TBLPTRL
        MOVFF	PREINC1, TABLAT
        MOVFF	PREINC1, FSR0H
        MOVFF	PREINC1, FSR0L
        MOVFF	PREINC1, FSR2H
        MOVFF	PREINC1, FSR2L
        MOVFF	PREINC1, BSR
        ;The next byte is the INTCON register.  Read this into WREG as some
        ;manipulation is required.
        MOVFF	PREINC1, WREG
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define portRESTORE_CONTEXT_RETFIE() _asm
	;From the INTCON register, only the interrupt enable bits form part
	;of the tasks context.  It is perfectly legitimate for another task to
	;have modified any other bits.  We therefore only restore the top two bits.
        MOVFF	PREINC1, STATUS
        MOVFF	PREINC1, WREG
        ;Return enabling interrupts.
        RETFIE	0
_endasm
#pragma preproc_asm +

#pragma preproc_asm -
#define portRESTORE_CONTEXT_RETURN() _asm
        MOVFF	PREINC1, STATUS
        MOVFF	PREINC1, W
        ;Return without effecting interrupts.  The context may have
        ;been saved from a critical region.
        RETURN	0
_endasm
#pragma preproc_asm +

#define portRESTORE_CONTEXT()                                                           \
{			                                                                \
        portRESTORE_CONTEXT_GET_PXCURRENTTCB();                                         \
        portRESTORE_CONTEXT_GET_STACKDEPTH();                                           \
        STKPTR = 0;                                                                     \
	while( STKPTR < FSR0L)                                                          \
	{                                                                               \
              portRESTORE_CONTEXT_FILL_HWSTACK();                                       \
	}                                                                               \
        portRESTORE_CONTEXT_DOT_REGISTERS_START();                                      \
        while(FSR2L<(unsigned portCHAR)(portCOMPILER_MANAGED_MEMORY_SIZE-1))            \
        {                                                                               \
                _asm                                                                    \
                        MOVFF	PREINC1,POSTDEC0                                        \
                _endasm;                                                                \
                _asm                                                                    \
                        INCF    FSR2L,F,ACCESS                                          \
                _endasm;                                                                \
        }                                                                               \
        portRESTORE_CONTEXT_DOT_REGISTERS_END();                                        \
        portRESTORE_CONTEXT_HW_REGISTERS();                                             \
	if(WREG & portGLOBAL_INTERRUPT_FLAG)                                            \
	{                                                                               \
                portRESTORE_CONTEXT_RETFIE();				                \
	}								                \
	else								                \
	{								                \
                portRESTORE_CONTEXT_RETURN();                                           \
	}                                                                               \
}

#endif /*PORTMACRO_H*/