TNeo
v1.09
arch
pic24_dspic
tn_arch_pic24.h
Go to the documentation of this file.
1
/*******************************************************************************
2
*
3
* TNeo: real-time kernel initially based on TNKernel
4
*
5
* TNKernel: copyright 2004, 2013 Yuri Tiomkin.
6
* PIC32-specific routines: copyright 2013, 2014 Anders Montonen.
7
* TNeo: copyright 2014 Dmitry Frank.
8
*
9
* TNeo was born as a thorough review and re-implementation of
10
* TNKernel. The new kernel has well-formed code, inherited bugs are fixed
11
* as well as new features being added, and it is tested carefully with
12
* unit-tests.
13
*
14
* API is changed somewhat, so it's not 100% compatible with TNKernel,
15
* hence the new name: TNeo.
16
*
17
* Permission to use, copy, modify, and distribute this software in source
18
* and binary forms and its documentation for any purpose and without fee
19
* is hereby granted, provided that the above copyright notice appear
20
* in all copies and that both that copyright notice and this permission
21
* notice appear in supporting documentation.
22
*
23
* THIS SOFTWARE IS PROVIDED BY THE DMITRY FRANK AND CONTRIBUTORS "AS IS"
24
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DMITRY FRANK OR CONTRIBUTORS BE
27
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33
* THE POSSIBILITY OF SUCH DAMAGE.
34
*
35
******************************************************************************/
36
37
/**
38
*
39
* \file
40
*
41
* PIC24/dsPIC architecture-dependent routines
42
*
43
*/
44
45
#ifndef _TN_ARCH_PIC24_H
46
#define _TN_ARCH_PIC24_H
47
48
49
/*******************************************************************************
50
* INCLUDED FILES
51
******************************************************************************/
52
53
//-- Include `tn_common_macros.h` for `_TN_STRINGIFY_MACRO()`
54
#include "../../core/tn_common_macros.h"
55
#include "../../core/tn_cfg_dispatch.h"
56
57
//-- include macros for atomic assess to structure bit fields so that
58
// application can use it too.
59
#include "
tn_arch_pic24_bfa.h
"
60
61
62
#ifdef __cplusplus
63
extern
"C"
{
/*}*/
64
#endif
65
66
67
68
/*******************************************************************************
69
* ARCH-DEPENDENT DEFINITIONS
70
******************************************************************************/
71
72
#ifndef DOXYGEN_SHOULD_SKIP_THIS
73
74
#define _TN_PIC24_INTSAVE_DATA_INVALID 0xffff
75
76
#if TN_DEBUG
77
# define _TN_PIC24_INTSAVE_CHECK() \
78
{ \
79
if (TN_INTSAVE_VAR == _TN_PIC24_INTSAVE_DATA_INVALID){ \
80
_TN_FATAL_ERROR(""); \
81
} \
82
}
83
#else
84
# define _TN_PIC24_INTSAVE_CHECK()
/* nothing */
85
#endif
86
87
/**
88
* FFS - find first set bit. Used in `_find_next_task_to_run()` function.
89
* Say, for `0xa8` it should return `3`.
90
*
91
* May be not defined: in this case, naive algorithm will be used.
92
*/
93
#define _TN_FFS(x) _tn_p24_ffs_asm(x)
94
int
_tn_p24_ffs_asm(
int
x);
95
96
/**
97
* Used by the kernel as a signal that something really bad happened.
98
* Indicates TNeo bugs as well as illegal kernel usage
99
* (e.g. sleeping in the idle task callback)
100
*
101
* Typically, set to assembler instruction that causes debugger to halt.
102
*/
103
#define _TN_FATAL_ERRORF(error_msg, ...) \
104
{__asm__ volatile(".pword 0xDA4000"); __asm__ volatile ("nop");}
105
106
107
108
/**
109
* \def TN_ARCH_STK_ATTR_BEFORE
110
*
111
* Compiler-specific attribute that should be placed **before** declaration of
112
* array used for stack. It is needed because there are often additional
113
* restrictions applied to alignment of stack, so, to meet them, stack arrays
114
* need to be declared with these macros.
115
*
116
* @see TN_ARCH_STK_ATTR_AFTER
117
*/
118
119
/**
120
* \def TN_ARCH_STK_ATTR_AFTER
121
*
122
* Compiler-specific attribute that should be placed **after** declaration of
123
* array used for stack. It is needed because there are often additional
124
* restrictions applied to alignment of stack, so, to meet them, stack arrays
125
* need to be declared with these macros.
126
*
127
* @see TN_ARCH_STK_ATTR_BEFORE
128
*/
129
130
#if defined (__C30__)
131
# define TN_ARCH_STK_ATTR_BEFORE
132
# define TN_ARCH_STK_ATTR_AFTER
133
#else
134
# error "Unknown compiler"
135
#endif
136
137
/**
138
* Minimum task's stack size, in words, not in bytes; includes a space for
139
* context plus for parameters passed to task's body function.
140
*/
141
#define TN_MIN_STACK_SIZE (25 \
142
+ _TN_EDS_STACK_ADD \
143
+ _TN_STACK_OVERFLOW_SIZE_ADD \
144
)
145
146
/**
147
* Some devices have two registers: DSRPAG and DSWPAG instead of PSVPAG.
148
* If __HAS_EDS__ is defined, device has two these registers,
149
* so we should take this in account.
150
*/
151
#ifdef __HAS_EDS__
152
# define _TN_EDS_STACK_ADD 1
153
#else
154
# define _TN_EDS_STACK_ADD 0
155
#endif
156
157
158
/**
159
* Width of `int` type.
160
*/
161
#define TN_INT_WIDTH 16
162
163
/**
164
* Unsigned integer type whose size is equal to the size of CPU register.
165
* Typically it's plain `unsigned int`.
166
*/
167
typedef
unsigned
int
TN_UWord
;
168
169
/**
170
* Unsigned integer type that is able to store pointers.
171
* We need it because some platforms don't define `uintptr_t`.
172
* Typically it's `unsigned int`.
173
*/
174
typedef
unsigned
int
TN_UIntPtr
;
175
176
177
/**
178
* Maximum number of priorities available, this value usually matches
179
* `#TN_INT_WIDTH`.
180
*
181
* @see TN_PRIORITIES_CNT
182
*/
183
#define TN_PRIORITIES_MAX_CNT TN_INT_WIDTH
184
185
/**
186
* Value for infinite waiting, usually matches `ULONG_MAX`,
187
* because `#TN_TickCnt` is declared as `unsigned long`.
188
*/
189
#define TN_WAIT_INFINITE (TN_TickCnt)0xFFFFFFFF
190
191
/**
192
* Value for initializing the task's stack
193
*/
194
#define TN_FILL_STACK_VAL 0xFEED
195
196
197
198
/**
199
* Variable name that is used for storing interrupts state
200
* by macros TN_INTSAVE_DATA and friends
201
*/
202
#define TN_INTSAVE_VAR tn_save_status_reg
203
204
/**
205
* Declares variable that is used by macros `TN_INT_DIS_SAVE()` and
206
* `TN_INT_RESTORE()` for storing status register value.
207
*
208
* It is good idea to initially set it to some invalid value,
209
* and if TN_DEBUG is non-zero, check it in TN_INT_RESTORE().
210
* Then, we can catch bugs if someone tries to restore interrupts status
211
* without saving it first.
212
*
213
* @see `TN_INT_DIS_SAVE()`
214
* @see `TN_INT_RESTORE()`
215
*/
216
#define TN_INTSAVE_DATA \
217
TN_UWord TN_INTSAVE_VAR = _TN_PIC24_INTSAVE_DATA_INVALID;
218
219
/**
220
* The same as `#TN_INTSAVE_DATA` but for using in ISR together with
221
* `TN_INT_IDIS_SAVE()`, `TN_INT_IRESTORE()`.
222
*
223
* @see `TN_INT_IDIS_SAVE()`
224
* @see `TN_INT_IRESTORE()`
225
*/
226
#define TN_INTSAVE_DATA_INT TN_INTSAVE_DATA
227
228
/**
229
* \def TN_INT_DIS_SAVE()
230
*
231
* Disable interrupts and return previous value of status register,
232
* atomically. Similar `tn_arch_sr_save_int_dis()`, but implemented
233
* as a macro, so it is potentially faster.
234
*
235
* Uses `#TN_INTSAVE_DATA` as a temporary storage.
236
*
237
* @see `#TN_INTSAVE_DATA`
238
* @see `tn_arch_sr_save_int_dis()`
239
*/
240
241
/**
242
* \def TN_INT_RESTORE()
243
*
244
* Restore previously saved status register.
245
* Similar to `tn_arch_sr_restore()`, but implemented as a macro,
246
* so it is potentially faster.
247
*
248
* Uses `#TN_INTSAVE_DATA` as a temporary storage.
249
*
250
* @see `#TN_INTSAVE_DATA`
251
* @see `tn_arch_sr_save_int_dis()`
252
*/
253
254
# define TN_INT_DIS_SAVE() TN_INTSAVE_VAR = tn_arch_sr_save_int_dis()
255
# define TN_INT_RESTORE() _TN_PIC24_INTSAVE_CHECK(); \
256
tn_arch_sr_restore(TN_INTSAVE_VAR)
257
258
/**
259
* The same as `TN_INT_DIS_SAVE()` but for using in ISR.
260
*
261
* Uses `#TN_INTSAVE_DATA_INT` as a temporary storage.
262
*
263
* @see `#TN_INTSAVE_DATA_INT`
264
*/
265
#define TN_INT_IDIS_SAVE() TN_INT_DIS_SAVE()
266
267
/**
268
* The same as `TN_INT_RESTORE()` but for using in ISR.
269
*
270
* Uses `#TN_INTSAVE_DATA_INT` as a temporary storage.
271
*
272
* @see `#TN_INTSAVE_DATA_INT`
273
*/
274
#define TN_INT_IRESTORE() TN_INT_RESTORE()
275
276
/**
277
* Returns nonzero if interrupts are disabled, zero otherwise.
278
*/
279
#define TN_IS_INT_DISABLED() (_tn_arch_is_int_disabled())
280
281
/**
282
* Pend context switch from interrupt.
283
*/
284
#define _TN_CONTEXT_SWITCH_IPEND_IF_NEEDED() \
285
_tn_context_switch_pend_if_needed()
286
287
/**
288
* Converts size in bytes to size in `#TN_UWord`.
289
* For 32-bit platforms, we should shift it by 2 bit to the right;
290
* for 16-bit platforms, we should shift it by 1 bit to the right.
291
*/
292
#define _TN_SIZE_BYTES_TO_UWORDS(size_in_bytes) ((size_in_bytes) >> 1)
293
294
#if TN_FORCED_INLINE
295
# define _TN_INLINE inline __attribute__ ((always_inline))
296
#else
297
# define _TN_INLINE inline
298
#endif
299
300
#define _TN_STATIC_INLINE static _TN_INLINE
301
302
#define _TN_VOLATILE_WORKAROUND
/* nothing */
303
304
//-- internal interrupt macro stuff {{{
305
306
#if TN_CHECK_PARAM
307
308
/**
309
* Check whether priority is too high. On PIC24 port, we have a range of
310
* interrupt priorities (let's call this range as "system priority"), and
311
* kernel functions are allowed to call only from ISRs with priority in this
312
* range.
313
*
314
* As a result, the kernel (almost) never disables ALL interrupts: when it
315
* modifies critical data, it disables just interrupts with system priority.
316
*
317
* The "almost" is because it disables interrupts for 4-8 cycles when it modifies
318
* stack pointer and SPLIM, because they should always correspond.
319
*/
320
# define _TN_SOFT_ISR_PRIORITY_CHECK() \
321
" \n" \
322
" mov #0xE0, W0 \n" \
323
" and _SR, WREG \n" \
324
" lsr W0, #5, W0 \n" \
325
" cp W0, #" _TN_STRINGIFY_MACRO(TN_P24_SYS_IPL) " \n" \
326
" bra leu, 1f \n" \
327
\
328
/* Interrupt priority is too high. Halt the debugger here. */
\
329
" .pword 0xDA4000 \n" \
330
" nop \n" \
331
"1: \n" \
332
/* Interrupt priority is ok, go on now. */
\
333
334
#else
335
# define _TN_SOFT_ISR_PRIORITY_CHECK()
/* nothing */
336
#endif
337
338
339
#define _TN_SOFT_ISR_PROLOGUE \
340
" \n" \
341
\
342
/* we need to use a couple of registers, so, save them. */
\
343
" push w0; \n" \
344
" push w1; \n" \
345
\
346
/* if TN_CHECK_PARAM is enabled, check if interrupt priority is */
\
347
/* too high. See macro _TN_SOFT_ISR_PRIORITY_CHECK() above for */
\
348
/* details. */
\
349
_TN_SOFT_ISR_PRIORITY_CHECK() \
350
\
351
/* before playing with SP and SPLIM, we need to disable system */
\
352
/* interrupts. NOTE that 'disi' instruction does not disable */
\
353
/* interrupts with priority 7, so, system interrupt priority should */
\
354
/* never be 7. */
\
355
\
356
" disi #8; \n" \
357
\
358
/* check if SP is already inside the interrupt stack: */
\
359
/* we check it by checking if SPLIM is set to _tn_p24_int_splim */
\
360
" mov __tn_p24_int_splim, w0; \n" \
361
" cp SPLIM; \n" \
362
" bra z, 1f; \n" \
363
\
364
/* SP is not inside the interrupt stack. We should set it. */
\
365
" \n" \
366
" mov SPLIM, w1; \n" \
367
" mov w0, SPLIM; \n" \
368
" mov w15, w0; \n" \
369
" mov __tn_p24_int_stack_low_addr, w15; \n" \
370
\
371
/* Interrupts should be re-enabled here. */
\
372
/* We just switched to interrupt stack. */
\
373
/* we need to push previous stack pointer and SPLIM there. */
\
374
" push w0; \n"
/* push task's SP */
\
375
" push w1; \n"
/* push task's SPLIM */
\
376
" bra 2f; \n" \
377
"1: \n" \
378
/* Interrupt stack is already active (it happens when interrupts */
\
379
/* nest) */
\
380
/* Just push SP and SPLIM so that stack contents will be compatible */
\
381
/* with the case of non-nested interrupt */
\
382
" push w15; \n"
/* push SP */
\
383
" push SPLIM; \n"
/* push SPLIM */
\
384
"2: \n" \
385
" \n" \
386
387
388
#define _TN_SOFT_ISR_CALL \
389
/* before we call user-provided ISR, we need to imitate interrupt */
\
390
/* call, i.e. store SR to the stack. It is done below, */
\
391
/* at the label 1: */
\
392
" rcall 1f; \n"
393
394
#define _TN_SOFT_ISR_EPILOGUE \
395
/* we got here when we just returned from user-provided ISR. */
\
396
/* now, we need to restore previous SPLIM and SP, and we should */
\
397
/* disable interrupts because they could nest, and if SPLIM and SP */
\
398
/* don't correspond, system crashes. */
\
399
" disi #4; \n" \
400
" pop w1; \n"
/* pop SPLIM */
\
401
" pop w0; \n"
/* pop SP */
\
402
" mov w1, SPLIM; \n" \
403
" mov w0, w15; \n" \
404
\
405
/* now, interrupts should be enabled back. */
\
406
/* here we just need to restore w0 and w1 that we saved and used in */
\
407
/* _TN_SOFT_ISR_PROLOGUE */
\
408
" pop w1; \n" \
409
" pop w0; \n" \
410
\
411
/* finally, return from the ISR. */
\
412
" retfie; \n" \
413
"1: \n" \
414
/* we got here by rcall when we are about to call user-provided ISR. */
\
415
/* 'rcall' saves program counter to the stack, but we need to */
\
416
/* imitate interrupt, so, we manually save SR there. */
\
417
" mov SR, w0; \n" \
418
" mov.b w0, [w15-1]; \n" \
419
\
420
/* now, we eventually proceed to user-provided ISR. */
\
421
/* When it returns, we get above to the macro _TN_SOFT_ISR_EPILOGUE */
\
422
/* (because 'rcall' saved this address to the stack) */
\
423
424
425
426
#define _tn_soft_isr_internal(_func, _psv, _shadow) \
427
void __attribute__(( \
428
__interrupt__( \
429
__preprologue__( \
430
_TN_SOFT_ISR_PROLOGUE \
431
_TN_SOFT_ISR_CALL \
432
_TN_SOFT_ISR_EPILOGUE \
433
) \
434
), \
435
_psv, \
436
_shadow \
437
)) \
438
_func(void)
439
440
441
// }}}
442
443
#define _TN_ARCH_STACK_PT_TYPE _TN_ARCH_STACK_PT_TYPE__EMPTY
444
#define _TN_ARCH_STACK_DIR _TN_ARCH_STACK_DIR__ASC
445
446
#endif //-- DOXYGEN_SHOULD_SKIP_THIS
447
448
449
450
451
452
453
454
455
456
457
/**
458
* ISR wrapper macro for software context saving.
459
*
460
* Usage looks like the following:
461
*
462
* \code{.c}
463
* tn_p24_soft_isr(_T1Interrupt, auto_psv)
464
* {
465
* //-- clear interrupt flag
466
* IFS0bits.T1IF = 0;
467
*
468
* //-- do something useful
469
* }
470
* \endcode
471
*
472
* Which should be used for system interrupts, instead of standard way:
473
*
474
* \code{.c}
475
* void __attribute__((__interrupt__, auto_psv)) _T1Interrupt(void)
476
* \endcode
477
*
478
* Where `_T1Interrupt` is the usual PIC24/dsPIC ISR name,
479
* and `auto_psv` (or `no_auto_psv`) is the usual attribute argument for
480
* interrupt.
481
*
482
*
483
*/
484
#define tn_p24_soft_isr(_func, _psv) _tn_soft_isr_internal(_func, _psv, )
485
486
487
488
489
#ifdef __cplusplus
490
}
/* extern "C" */
491
#endif
492
493
#endif // _TN_ARCH_PIC24_H
494
tn_arch_pic24_bfa.h
TN_UWord
unsigned int TN_UWord
Unsigned integer type whose size is equal to the size of CPU register.
Definition:
tn_arch_example.h:105
TN_UIntPtr
unsigned int TN_UIntPtr
Unsigned integer type that is able to store pointers.
Definition:
tn_arch_example.h:112
Generated on Sat Dec 28 2024 20:20:49 for TNeo by
1.8.17