OSDN Git Service

チケット #25999 「SIOポートのピン割り当ての変更」に対応
[toppersasp4lpc/asp.git] / asp / arch / arm_m_gcc / common / core_config.h
1 /*
2  *  TOPPERS/ASP Kernel
3  *      Toyohashi Open Platform for Embedded Real-Time Systems/
4  *      Advanced Standard Profile Kernel
5  * 
6  *  Copyright (C) 2008-2011 by Embedded and Real-Time Systems Laboratory
7  *              Graduate School of Information Science, Nagoya Univ., JAPAN
8  * 
9  *  上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
10  *  ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
11  *  変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
12  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
13  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
14  *      スコード中に含まれていること.
15  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
16  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
17  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
18  *      の無保証規定を掲載すること.
19  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
20  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
21  *      と.
22  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
23  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
24  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
25  *        報告すること.
26  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
27  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
28  *      また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
29  *      由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
30  *      免責すること.
31  * 
32  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
33  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
34  *  に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
35  *  アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
36  *  の責任を負わない.
37  * 
38  *  @(#) $Id: core_config.h 2198 2011-07-25 16:57:14Z ertl-honda $
39  */
40
41 /*
42  *              プロセッサ依存モジュール(ARM-M用)
43  *
44  *  このインクルードファイルは,target_config.h(または,そこからインク
45  *  ルードされるファイル)のみからインクルードされる.他のファイルから
46  *  直接インクルードしてはならない.
47  */
48
49 #ifndef TOPPERS_CORE_CONFIG_H
50 #define TOPPERS_CORE_CONFIG_H
51
52 #ifndef TOPPERS_MACRO_ONLY
53
54 /*
55  *  プロセッサの特殊命令のインライン関数定義
56  */
57 #include "core_insn.h"
58
59 /*
60  *  ターゲット依存のオブジェクト属性
61  */
62 #define TARGET_INHATR  TA_NONKERNEL /* ターゲット定義の割込みハンドラ属性 */
63
64 /*
65  *  エラーチェック方法の指定
66  */
67 #define CHECK_STKSZ_ALIGN       8       /* スタックサイズのアライン単位 */
68 #define CHECK_FUNC_ALIGN        1       /* 関数のアライン単位 */
69 #define CHECK_FUNC_NONNULL              /* 関数の非NULLチェック */
70 #define CHECK_STACK_ALIGN       8       /* スタック領域のアライン単位 */
71 #define CHECK_STACK_NONNULL             /* スタック領域の非NULLチェック */
72 #define CHECK_MPF_ALIGN         4       /* 固定長メモリプール領域のアライン単位 */
73 #define CHECK_MPF_NONNULL               /* 固定長メモリプール領域の非NULLチェック */
74 #define CHECK_MB_ALIGN          4       /* 管理領域のアライン単位 */
75
76 /*
77  *  非タスクコンテキスト用のスタック初期値
78  */
79 #define TOPPERS_ISTKPT(istk, istksz) ((STK_T *)((char_t *)(istk) + (istksz)))
80
81 /*
82  *  タスクコンテキストブロックの定義
83  */
84 typedef struct task_context_block {
85         void    *sp;            /* スタックポインタ */
86         FP              pc;                     /* プログラムカウンタ */
87 } TSKCTXB;
88
89 #endif /* TOPPERS_MACRO_ONLY */
90
91 #ifndef TOPPERS_MACRO_ONLY
92 /*
93  *  コンテキストの参照
94  *
95  */
96 Inline bool_t
97 sense_context(void)
98 {
99         /*
100          *  PSPが有効ならタスクコンテキスト,MSPが有効なら非タスクコンテキスト
101          *  とする. 
102          */
103         if ((get_control() & CONTROL_PSP) == CONTROL_PSP){
104                 return false;
105         }
106         else {
107                 return true;
108         }
109 }
110
111 #endif /* TOPPERS_MACRO_ONLY */
112
113 /*
114  *  TOPPERS標準割込み処理モデルの実現
115  *
116  *  割込み優先度マスクとしては,BASEPRIを用いる.全割込みを禁止する
117  *  機能として,FAULTMASKやPRIMASKがあるが,カーネル管理外の割込みを
118  *  サポートするため,これらはCPUロックのために用いない.
119  *  そのため,BASEPRIを用いて擬似的にCPUロックフラグを実現する.
120  *
121  *  まず,CPUロック状態を管理すための変数(lock_flag)を用意する.
122  *
123  *  CPUロックフラグがクリアされている間は,BASEPRIをモデル上の割込み
124  *  優先度マスクの値に設定する.この間は,モデル上の割込み優先度マス
125  *  クは,BASEPRIを用いる.
126  * 
127  *  それに対してCPUロックフラグがセットされいる間は,BASEPRIを,カーネ
128  *  ル管理外のものを除くすべての割込み要求をマスクする値(TIPM_LOCK)と,
129  *  モデル上の割込み優先度マスクとの高い方に設定する.この間のモデル上
130  *  の割込み優先度マスクは,そのための変数(saved_iipm, 内部表現で保持)
131  *  を用意して保持する.
132  */
133
134 /*
135  *  割込み優先度マスクの外部表現と内部表現の変換
136  *
137  *  アセンブリ言語のソースファイルからインクルードする場合のために,
138  *  CASTを使用
139  *  割込み優先度のビット幅(TBITW_IPRI)が 8 の場合は,内部優先度 255
140  *  は,外部優先度 -1 に対応する.
141  */
142 #define EXT_IPM(iipm)   (CAST(PRI,((iipm >> (8 - TBITW_IPRI)) - (1 << TBITW_IPRI))))       /* 内部表現を外部表現に */
143 #define INT_IPM(ipm)    (((1 << TBITW_IPRI) - CAST(uint8_t, -(ipm)))  << (8 - TBITW_IPRI)) /* 外部表現を内部表現に */
144
145 /*
146  *  CPUロック状態での割込み優先度マスク
147  */
148 #define TIPM_LOCK    TMIN_INTPRI
149
150 /*
151  *  CPUロック状態での割込み優先度マスクの内部表現
152  *
153  *  TIPM_LOCKは,CPUロック状態でのBASEPRIの値.カーネル管理外のものを
154  *  除くすべての割込みをマスクする値に定義する.  
155  */
156 #define IIPM_LOCK    INT_IPM(TIPM_LOCK)
157
158 /*
159  *  TIPM_ENAALL(割込み優先度マスク全解除)の内部表現
160  *
161  *  BASEPRIに '0' を設定することで,全割込みを許可する.
162  */
163 #define IIPM_ENAALL  (0)
164
165
166 #ifndef TOPPERS_MACRO_ONLY
167
168 /*
169  *  CPUロックフラグ実現のための変数
170  * 
171  *  これらの変数は,CPUロック状態の時のみ書き換えてもよいとする.
172  *  インライン関数中で,アクセスの順序が変化しないよう,volatile を指定. 
173  */
174 extern volatile bool_t  lock_flag;    /* CPUロックフラグの値を保持する変数 */
175 extern volatile uint32_t saved_iipm;  /* 割込み優先度をマスクする変数 */
176
177 /*
178  *  CPUロック状態への移行
179  *
180  *  BASEPRI(ハードウェアの割込み優先度マスク)を,saved_iipmに保存し,
181  *  カーネル管理外のものを除くすべての割込みをマスクする値(TIPM_LOCK)
182  *  に設定する.また,lock_flagをtrueにする.
183  *
184  *  BASEPRIが,最初からTIPM_LOCKと同じかそれより高い場合には,それを
185  *  saved_iipmに保存するのみで,TIPM_LOCKには設定しない.これは,モデル
186  *  上の割込み優先度マスクが,TIPM_LOCKと同じかそれより高いレベルに設定
187  *  されている状態にあたる.
188  *
189  *  この関数は,CPUロック状態(lock_flagがtrueの状態)で呼ばれることは
190  *  ないものと想定している.
191  */
192 Inline void
193 x_lock_cpu(void)
194 {
195         uint32_t iipm;
196
197         /*
198          *  get_basepri()の返り値を直接saved_iipmに保存せず,一時変数iipm
199          *  を用いているのは,get_baespri()を呼んだ直後に割込みが発生し,
200          *  起動された割込み処理でsaved_iipmが変更される可能性があるためで
201          *  ある.
202          */
203         iipm = get_basepri();
204         /*
205          *  BASEPRIレジスタは値が小さいほど優先度が高いが,IIPM_ENAALL が
206          *  '0'であるため,単純に優先度比較だけでは不十分である.
207          */
208         if ((IIPM_LOCK < iipm) || (IIPM_ENAALL == iipm)) {
209                 set_basepri(IIPM_LOCK);
210         }
211         saved_iipm = iipm;
212         lock_flag = true;
213         /* クリティカルセクションの前後でメモリが書き換わる可能性がある */
214         Asm("":::"memory");
215 }
216
217 #define t_lock_cpu()    x_lock_cpu()
218 #define i_lock_cpu()    x_lock_cpu()
219
220 /*
221  *  CPUロック状態の解除
222  *
223  *  lock_flagをfalseにし,IPM(ハードウェアの割込み優先度マスク)を,
224  *  saved_iipmに保存した値に戻す.
225  *
226  *  この関数は,CPUロック状態(lock_flagがtrueの状態)でのみ呼ばれるも
227  *  のと想定している.
228  */
229 Inline void
230 x_unlock_cpu(void)
231 {
232         /* クリティカルセクションの前後でメモリが書き換わる可能性がある */
233         Asm("":::"memory");
234         lock_flag = false;
235         set_basepri(saved_iipm);
236 }
237
238 #define t_unlock_cpu()    x_unlock_cpu()
239 #define i_unlock_cpu()    x_unlock_cpu()
240
241 /*
242  *  CPUロック状態の参照
243  */
244 Inline bool_t
245 x_sense_lock(void)
246 {
247         return(lock_flag);
248 }
249
250 #define t_sense_lock()    x_sense_lock()
251 #define i_sense_lock()    x_sense_lock()
252
253 /*
254  *  chg_ipmで有効な割込み優先度の範囲の判定
255  *
256  *  TMIN_INTPRIの値によらず,chg_ipmでは,-(1 << TBITW_IPRI)〜TIPM_ENAALL(=0)
257  *  の範囲に設定できることとする(ターゲット定義の拡張).
258  *  割込み優先度のビット幅(TBITW_IPRI)が 8 の場合は,-256 〜 0 が指定可能である.
259  *   
260  */
261 #define VALID_INTPRI_CHGIPM(intpri) \
262                                 ((-((1 << TBITW_IPRI) - 1) <= (intpri) && (intpri) <= TIPM_ENAALL))
263
264 /*
265  * (モデル上の)割込み優先度マスクの設定
266  *
267  *  CPUロックフラグがクリアされている時は,ハードウェアの割込み優先度マ
268  *  スクを設定する.CPUロックフラグがセットされている時は,saved_iipm
269  *  を設定し,さらに,ハードウェアの割込み優先度マスクを,設定しようと
270  *  した(モデル上の)割込み優先度マスクとTIPM_LOCKの高い方に設定する.
271  */
272 Inline void
273 x_set_ipm(PRI intpri)
274 {
275         uint8_t   iipm = INT_IPM(intpri);
276
277         if (intpri == TIPM_ENAALL){
278                 iipm = IIPM_ENAALL;
279         }
280
281         if (!lock_flag) {
282                 set_basepri(iipm);
283         }
284         else {
285                 saved_iipm = iipm;
286                 set_basepri(iipm < IIPM_LOCK ? iipm : IIPM_LOCK);
287         }
288 }
289
290 #define t_set_ipm(intpri)    x_set_ipm(intpri)
291 #define i_set_ipm(intpri)    x_set_ipm(intpri)
292
293 /*
294  * (モデル上の)割込み優先度マスクの参照
295  *
296  *  CPUロックフラグがクリアされている時はハードウェアの割込み優先度マ
297  *  スクを,セットされている時はsaved_iipmを参照する.
298  */
299 Inline PRI
300 x_get_ipm(void)
301 {
302         uint8_t iipm;
303
304         if (!lock_flag) {
305                 iipm = get_basepri();
306         }
307         else {
308                 iipm = saved_iipm;
309         }
310
311         if (iipm == IIPM_ENAALL) {
312                 return(TIPM_ENAALL);
313         }
314         else {
315                 return(EXT_IPM(iipm));
316         }
317 }
318
319 #define t_get_ipm()    x_get_ipm()
320 #define i_get_ipm()    x_get_ipm()
321
322 /*
323  *  SVCハンドラ(core_support.S)
324  */
325 extern void svc_handler(void);
326
327 /*
328  *  スタートアップルーチン(start.S)
329  */
330 extern void _start(void);
331
332 /*
333  *  最高優先順位タスクへのディスパッチ(core_support.S)
334  *
335  *  dispatchは,タスクコンテキストから呼び出されたサービスコール処理か
336  *  ら呼び出すべきもので,タスクコンテキスト・CPUロック状態・ディスパッ
337  *  チ許可状態・(モデル上の)割込み優先度マスク全解除状態で呼び出さな
338  *  ければならない.
339  */
340 extern void dispatch(void);
341
342 /*
343  *  ディスパッチャの動作開始(core_support.S)
344  *
345  *  start_dispatchは,カーネル起動時に呼び出すべきもので,すべての割込
346  *  みを禁止した状態(割込みロック状態と同等の状態)で呼び出さなければ
347  *  ならない.
348  */
349 extern void start_dispatch(void) NoReturn;
350
351 /*
352  *  現在のコンテキストを捨ててディスパッチ(core_support.S)
353  *
354  *  exit_and_dispatchは,ext_tskから呼び出すべきもので,タスクコンテキ
355  *  スト・CPUロック状態・ディスパッチ許可状態・(モデル上の)割込み優先
356  *  度マスク全解除状態で呼び出さなければならない.
357  */
358 extern void exit_and_dispatch(void) NoReturn;
359
360 /*
361  *  カーネルの終了処理の呼出し(core_support.S)
362  *
363  *  call_exit_kernelは,カーネルの終了時に呼び出すべきもので,非タスク
364  *  コンテキストに切り換えて,カーネルの終了処理(exit_kernel)を呼び出
365  *  す.
366  */
367 extern void call_exit_kernel(void) NoReturn;
368
369 /*
370  *  タスクコンテキストの初期化
371  *
372  *  タスクが休止状態から実行できる状態に移行する時に呼ばれる.この時点
373  *  でスタック領域を使ってはならない.
374  *
375  *  activate_contextを,インライン関数ではなくマクロ定義としているのは,
376  *  この時点ではTCBが定義されていないためである.
377  */
378 extern void    start_r(void);
379
380 #define activate_context(p_tcb)                                         \
381 {                                                                       \
382     (p_tcb)->tskctxb.sp = (void *)((char_t *)((p_tcb)->p_tinib->stk)    \
383                                         + (p_tcb)->p_tinib->stksz);     \
384     (p_tcb)->tskctxb.pc = (void *) start_r;                             \
385 }
386
387 /*
388  *  calltexは使用しない
389  */
390 #define OMIT_CALLTEX
391
392 /*
393  *  割込み番号・割込みハンドラ番号
394  *
395  *  割込みハンドラ番号(inhno)と割込み番号(intno)は,割り込み発生時に
396  *  EPSRに設定される例外番号とする. 
397  */
398
399 /*
400  *  割込み番号の範囲の判定
401  */
402 #define VALID_INTNO(intno)           ((TMIN_INTNO <= (intno)) && ((intno) <= TMAX_INTNO))
403 #define VALID_INTNO_DISINT(intno)    VALID_INTNO(intno)
404 #define VALID_INTNO_CFGINT(intno)    VALID_INTNO(intno)
405
406 /*
407  *  割込みハンドラの設定
408  *
409  *  ベクトル番号inhnoの割込みハンドラの起動番地int_entryに設定する.割込み
410  *  ハンドラテーブル
411  */
412 Inline void
413 x_define_inh(INHNO inhno, FP int_entry)
414 {
415
416 }
417
418 /*
419  *  割込みハンドラの出入口処理の生成マクロ
420  *
421  */
422 #define INT_ENTRY(inhno, inthdr)    inthdr
423 #define INTHDR_ENTRY(inhno, inhno_num, inthdr) extern void inthdr(void);
424
425 /*
426  *  割込み要求禁止フラグ
427  */
428
429 /*
430  *  割込み属性が設定されているかを判別するための変数(kernel_cfg.c)
431  */
432 extern const uint32_t   bitpat_cfgint[];
433
434 /*
435  *  割込み要求禁止フラグのセット
436  *
437  *  割込み属性が設定されていない割込み要求ラインに対して割込み要求禁止
438  *  フラグをクリアしようとした場合には,falseを返す.  
439  */
440 Inline bool_t
441 x_disable_int(INTNO intno)
442 {
443         uint32_t tmp;
444
445         /*
446          *  割込み属性が設定されていない場合
447          */
448         if ((bitpat_cfgint[intno >> 5] & (1 << (intno & 0x1f))) == 0x00) {
449                 return(false);
450         }
451
452         if (intno == IRQNO_SYSTICK) {
453                 tmp = sil_rew_mem((void *)SYSTIC_CONTROL_STATUS);
454                 tmp &= ~SYSTIC_TICINT;
455                 sil_wrw_mem((void *)SYSTIC_CONTROL_STATUS, tmp);
456         }else {
457                 tmp = intno - 16;
458                 sil_wrw_mem((void *)((uint32_t *)NVIC_CLRENA0 + (tmp >> 5)),
459                                         (1 << (tmp & 0x1f)));
460         }
461
462         return(true);
463 }
464
465 #define t_disable_int(intno) x_disable_int(intno)
466 #define i_disable_int(intno) x_disable_int(intno)
467
468 /*
469  *  割込み要求禁止フラグの解除
470  *
471  *  割込み属性が設定されていない割込み要求ラインに対して割込み要求禁止
472  *  フラグをクリアしようとした場合には,falseを返す.
473  */
474 Inline bool_t
475 x_enable_int(INTNO intno)
476 {
477         uint32_t tmp;
478
479         /*
480          *  割込み属性が設定されていない場合
481          */
482         if ((bitpat_cfgint[intno >> 5] & (1 << (intno & 0x1f))) == 0x00) {
483                 return(false);
484         }
485
486         if (intno == IRQNO_SYSTICK) {
487                 tmp = sil_rew_mem((void *)SYSTIC_CONTROL_STATUS);
488                 tmp |= SYSTIC_TICINT;
489                 sil_wrw_mem((void *)SYSTIC_CONTROL_STATUS, tmp);
490         }else {
491                 tmp = intno - 16;
492                 sil_wrw_mem((void *)((uint32_t *)NVIC_SETENA0 + (tmp >> 5)),
493                                         (1 << (tmp & 0x1f)));
494         }
495     
496         return(true);
497 }
498
499 #define t_enable_int(intno) x_enable_int(intno)
500 #define i_enable_int(intno) x_enable_int(intno)
501
502 /*
503  *  割込み要求ラインの属性の設定
504  */
505 extern void x_config_int(INTNO intno, ATR intatr, PRI intpri);
506
507 /*
508  *  割込みハンドラ入口で必要なIRC操作
509  */
510 Inline void
511 i_begin_int(INTNO intno)
512 {
513 }
514
515 /*
516  *  割込みハンドラの出口で必要なIRC操作
517  */
518 Inline void
519 i_end_int(INTNO intno)
520 {
521 }
522
523 /*
524  *  CPU例外ハンドラ関係
525  */ 
526
527 /*
528  *  CPU例外ハンドラ番号
529  */
530 #define VALID_EXCNO_DEFEXC(excno)    (TMIN_EXCNO <= (excno) && (excno) <= TMAX_EXCNO)
531
532 /*
533  *  CPU例外ハンドラの許可
534  */
535 extern void enable_exc(EXCNO excno);
536
537 /*
538  *  CPU例外ハンドラの禁止
539  */
540 extern void disable_exc(EXCNO excno);
541
542 /*
543  *  CPU例外ハンドラの設定
544  */
545 Inline void
546 x_define_exc(EXCNO excno, FP exc_entry)
547 {
548         /*
549          *  一部の例外は許可を行う必要がある
550          */
551         enable_exc(excno);
552 }
553
554 /*
555  *  CPU例外ハンドラの入口処理の生成マクロ
556  */
557 #define EXC_ENTRY(excno, exchdr)    exchdr
558 #define EXCHDR_ENTRY(excno, excno_num, exchdr) extern void exchdr(void *p_excinf);
559
560 /*
561  *  CPU例外の発生した時のコンテキストの参照
562  *
563  *  CPU例外の発生した時のコンテキストが,タスクコンテキストの時にfalse,
564  *  そうでない時にtrueを返す.
565  */
566 Inline bool_t
567 exc_sense_context(void *p_excinf)
568 {
569         uint32_t exc_return;
570
571         exc_return = *((uint32_t *)p_excinf + P_EXCINF_OFFSET_EXC_RETURN);
572         if ((exc_return & EXC_RETURN_PSP) == EXC_RETURN_PSP){
573                 return false;
574         }
575         else {
576                 return true;
577         }
578 }
579
580 /*
581  *  CPU例外の発生した時のIPM(ハードウェアの割込み優先度マスク,内部表
582  *  現)の参照
583  */
584 Inline uint32_t
585 exc_get_iipm(void *p_excinf)
586 {
587         return(*((uint32_t *)p_excinf + P_EXCINF_OFFSET_BASEPRI));
588 }
589
590 /*
591  *  CPU例外の発生した時のコンテキストと割込みのマスク状態の参照
592  *
593  *  CPU例外の発生した時のシステム状態が,カーネル実行中でなく,タスクコ
594  *  ンテキストであり,割込みロック状態でなく,CPUロック状態でなく,(モ
595  *  デル上の)割込み優先度マスク全解除状態である時にtrue,そうでない時
596  *  にfalseを返す(CPU例外がカーネル管理外の割込み処理中で発生した場合
597  *  にもfalseを返す).
598  *
599  *  PU例外の発生した時のBASEPRI(ハードウェアの割込み優先度マスク)
600  *  がすべての割込みを許可する状態であることをチェックすることで,カー
601  *  ネル実行中でないこと,割込みロック状態でないこと,CPUロック状態でな
602  *  いこと,(モデル上の)割込み優先度マスク全解除状態であることの4つの
603  *  条件をチェックすることができる(CPU例外が発生した時のlock_flagを参
604  *  照する必要はない).
605  */
606 Inline bool_t
607 exc_sense_intmask(void *p_excinf)
608 {
609         return(!exc_sense_context(p_excinf)
610                    && (exc_get_iipm(p_excinf) == IIPM_ENAALL));
611 }
612
613 /*
614  *  CPU例外エントリ(core_support.S)
615  */
616 extern void core_exc_entry(void);
617
618 /*
619  *  割込みエントリ(core_support.S)
620  */
621 extern void core_int_entry(void);
622
623 /*
624  *  プロセッサ依存の初期化
625  */
626 extern void core_initialize(void);
627
628 /*
629  *  プロセッサ依存の終了時処理
630  */
631 extern void core_terminate(void);
632
633 /*
634  * 登録されていない例外が発生すると呼び出される
635  */
636 extern void default_exc_handler(void *p_excinf);
637
638 /*
639  * 未登録の割込みが発生した場合に呼び出される
640  */
641 extern void default_int_handler(void *p_excinf);
642
643 #endif /* TOPPERS_MACRO_ONLY */
644 #endif /* TOPPERS_CORE_CONFIG_H */