1 /**************************************************************************//**
2 * @file retarget.c
3 * @version V3.00
4 * @brief M480 Series Debug Port and Semihost Setting Source File
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
8 ******************************************************************************/
9
10
11 #include <stdio.h>
12 #include "NuMicro.h"
13
14 #if defined ( __CC_ARM )
15 #if (__ARMCC_VERSION < 400000)
16 #else
17 /* Insist on keeping widthprec, to avoid X propagation by benign code in C-lib */
18 #pragma import _printf_widthprec
19 #endif
20 #endif
21 /* Uncomment this line to disable all printf and getchar. getchar() will always return 0x00*/
22 /* #define DISABLE_UART */
23
24 #if defined(DEBUG_ENABLE_SEMIHOST)
25 #ifndef DISABLE_UART
26 #define DISABLE_UART
27 #endif
28 #endif
29
30 #define DEBUG_PORT UART0
31 /*---------------------------------------------------------------------------------------------------------*/
32 /* Global variables */
33 /*---------------------------------------------------------------------------------------------------------*/
34 #if !(defined(__ICCARM__) && (__VER__ >= 6010000))
35 # if (__ARMCC_VERSION < 6040000)
36 struct __FILE
37 {
38 int handle; /* Add whatever you need here */
39 };
40 # endif
41 #elif(__VER__ >= 8000000)
42 struct __FILE
43 {
44 int handle; /* Add whatever you need here */
45 };
46 #endif
47 FILE __stdout;
48 FILE __stdin;
49
50
51 enum { r0, r1, r2, r3, r12, lr, pc, psr};
52
53 /**
54 * @brief Helper function to dump register while hard fault occurred
55 * @param[in] stack pointer points to the dumped registers in SRAM
56 * @return None
57 * @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr
58 */
stackDump(uint32_t stack[])59 static void stackDump(uint32_t stack[])
60 {
61 printf("r0 = 0x%x\n", stack[r0]);
62 printf("r1 = 0x%x\n", stack[r1]);
63 printf("r2 = 0x%x\n", stack[r2]);
64 printf("r3 = 0x%x\n", stack[r3]);
65 printf("r12 = 0x%x\n", stack[r12]);
66 printf("lr = 0x%x\n", stack[lr]);
67 printf("pc = 0x%x\n", stack[pc]);
68 printf("psr = 0x%x\n", stack[psr]);
69 }
70
71 /**
72 * @brief Hard fault handler
73 * @param[in] stack pointer points to the dumped registers in SRAM
74 * @return None
75 * @details Replace while(1) at the end of this function with chip reset if WDT is not enabled for end product
76 */
Hard_Fault_Handler(uint32_t stack[])77 void Hard_Fault_Handler(uint32_t stack[])
78 {
79 printf("In Hard Fault Handler\n");
80
81 stackDump(stack);
82 /* Replace while(1) with chip reset if WDT is not enabled for end product */
83 while(1);
84 /* SYS->IPRST0 = SYS_IPRST0_CHIPRST_Msk; */
85 }
86
87
88
89 /*---------------------------------------------------------------------------------------------------------*/
90 /* Routine to write a char */
91 /*---------------------------------------------------------------------------------------------------------*/
92
93 #if defined(DEBUG_ENABLE_SEMIHOST)
94 /* The static buffer is used to speed up the semihost */
95 static char g_buf[16];
96 static char g_buf_len = 0;
97
98 /* Make sure won't goes here only because --gnu is defined , so
99 add !__CC_ARM and !__ICCARM__ checking */
100 # if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)
101
102 # elif defined(__ICCARM__) // IAR
103
SH_End(void)104 void SH_End(void)
105 {
106 asm("MOVS R0,#1 \n" /*; Set return value to 1 */
107 "BX lr \n" /*; Return */
108 );
109 }
110
SH_ICE(void)111 void SH_ICE(void)
112 {
113 asm("CMP R2,#0 \n"
114 "BEQ SH_End \n"
115 "STR R0,[R2] \n" /*; Save the return value to *pn32Out_R0 */
116 );
117 }
118
119 /**
120 *
121 * @brief The function to process semihosted command
122 * @param[in] n32In_R0 : semihost register 0
123 * @param[in] n32In_R1 : semihost register 1
124 * @param[out] pn32Out_R0: semihost register 0
125 * @retval 0: No ICE debug
126 * @retval 1: ICE debug
127 *
128 */
SH_DoCommand(int32_t n32In_R0,int32_t n32In_R1,int32_t * pn32Out_R0)129 int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
130 {
131 asm("BKPT 0xAB \n" /*; This instruction will cause ICE trap or system HardFault */
132 "B SH_ICE \n"
133 "SH_HardFault: \n" /*; Captured by HardFault */
134 "MOVS R0,#0 \n" /*; Set return value to 0 */
135 "BX lr \n" /*; Return */
136 );
137
138 return 1; /*; Return 1 when it is trap by ICE */
139 }
140
141 /**
142 * @brief Get LR value and branch to Hard_Fault_Handler function
143 * @param None
144 * @return None
145 * @details This function is use to get LR value and branch to Hard_Fault_Handler function.
146 */
Get_LR_and_Branch(void)147 void Get_LR_and_Branch(void)
148 {
149 asm("MOV R1, LR \n" /*; LR current value */
150 "B Hard_Fault_Handler \n"
151 );
152 }
153
154 /**
155 * @brief Get MSP value and branch to Get_LR_and_Branch function
156 * @param None
157 * @return None
158 * @details This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
159 */
Stack_Use_MSP(void)160 void Stack_Use_MSP(void)
161 {
162 asm("MRS R0, MSP \n" /*; read MSP */
163 "B Get_LR_and_Branch \n"
164 );
165 }
166
167 /**
168 * @brief Get stack pointer value and branch to Get_LR_and_Branch function
169 * @param None
170 * @return None
171 * @details This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
172 */
HardFault_Handler_Ret(void)173 void HardFault_Handler_Ret(void)
174 {
175 asm("MOVS r0, #4 \n"
176 "MOV r1, LR \n"
177 "TST r0, r1 \n" /*; check LR bit 2 */
178 "BEQ Stack_Use_MSP \n" /*; stack use MSP */
179 "MRS R0, PSP \n" /*; stack use PSP, read PSP */
180 "B Get_LR_and_Branch \n"
181 );
182 }
183
184 /**
185 * @brief This function is implemented to support semihost
186 * @param None
187 * @returns None
188 * @details This function is implement to support semihost message print.
189 *
190 */
SP_Read_Ready(void)191 void SP_Read_Ready(void)
192 {
193 asm("LDR R1, [R0, #24] \n" /*; Get previous PC */
194 "LDRH R3, [R1] \n" /*; Get instruction */
195 "LDR R2, [pc, #8] \n" /*; The special BKPT instruction */
196 "CMP R3, R2 \n" /*; Test if the instruction at previous PC is BKPT */
197 "BNE HardFault_Handler_Ret \n" /*; Not BKPT */
198 "ADDS R1, #4 \n" /*; Skip BKPT and next line */
199 "STR R1, [R0, #24] \n" /*; Save previous PC */
200 "BX lr \n" /*; Return */
201 "DCD 0xBEAB \n" /*; BKPT instruction code */
202 "B HardFault_Handler_Ret \n"
203 );
204 }
205
206 /**
207 * @brief Get stack pointer value and branch to Get_LR_and_Branch function
208 * @param None
209 * @return None
210 * @details This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
211 */
SP_is_PSP(void)212 void SP_is_PSP(void)
213 {
214 asm(
215 "MRS R0, PSP \n" /*; stack use PSP, read PSP */
216 "B Get_LR_and_Branch \n"
217
218 );
219 }
220
221 /**
222 * @brief This HardFault handler is implemented to support semihost
223 *
224 * @param None
225 *
226 * @returns None
227 *
228 * @details This function is implement to support semihost message print.
229 *
230 */
HardFault_Handler(void)231 void HardFault_Handler (void)
232 {
233 asm("MOV R0, lr \n"
234 "LSLS R0, #29 \n" /*; Check bit 2 */
235 "BMI SP_is_PSP \n" /*; previous stack is PSP */
236 "MRS R0, MSP \n" /*; previous stack is MSP, read MSP */
237 "B SP_Read_Ready \n"
238 );
239
240 while(1);
241 }
242
243 # else
244
245 /**
246 * @brief This HardFault handler is implemented to support semihost
247 * @param None
248 * @returns None
249 * @details This function is implement to support semihost message print.
250 *
251 */
HardFault_Handler(void)252 __asm int32_t HardFault_Handler(void)
253 {
254 MOV R0, LR
255 LSLS R0, #29 /*; Check bit 2 */
256 BMI SP_is_PSP /*; previous stack is PSP */
257 MRS R0, MSP /*; previous stack is MSP, read MSP */
258 B SP_Read_Ready
259 SP_is_PSP
260 MRS R0, PSP /*; Read PSP */
261
262 SP_Read_Ready
263 LDR R1, [R0, #24] /*; Get previous PC */
264 LDRH R3, [R1] /*; Get instruction */
265 LDR R2, =0xBEAB /*; The special BKPT instruction */
266 CMP R3, R2 /*; Test if the instruction at previous PC is BKPT */
267 BNE HardFault_Handler_Ret /*; Not BKPT */
268
269 ADDS R1, #4 /*; Skip BKPT and next line */
270 STR R1, [R0, #24] /*; Save previous PC */
271
272 BX LR /*; Return */
273 HardFault_Handler_Ret
274
275 /* TODO: Implement your own hard fault handler here. */
276 MOVS r0, #4
277 MOV r1, LR
278 TST r0, r1 /*; check LR bit 2 */
279 BEQ Stack_Use_MSP /*; stack use MSP */
280 MRS R0, PSP ;stack use PSP /*; stack use PSP, read PSP */
281 B Get_LR_and_Branch
282 Stack_Use_MSP
283 MRS R0, MSP ; stack use MSP /*; read MSP */
284 Get_LR_and_Branch
285 MOV R1, LR ; LR current value /*; LR current value */
286 LDR R2,=__cpp(Hard_Fault_Handler) /*; branch to Hard_Fault_Handler */
287 BX R2
288
289 B .
290
291 ALIGN
292 }
293
294 /**
295 *
296 * @brief The function to process semihosted command
297 * @param[in] n32In_R0 : semihost register 0
298 * @param[in] n32In_R1 : semihost register 1
299 * @param[out] pn32Out_R0: semihost register 0
300 * @retval 0: No ICE debug
301 * @retval 1: ICE debug
302 *
303 */
SH_DoCommand(int32_t n32In_R0,int32_t n32In_R1,int32_t * pn32Out_R0)304 __asm int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
305 {
306 BKPT 0xAB /*; Wait ICE or HardFault */
307 /*; ICE will step over BKPT directly
308 ; HardFault will step BKPT and the next line */
309 B SH_ICE
310
311 SH_HardFault /*; Captured by HardFault */
312 MOVS R0, #0 /*; Set return value to 0 */
313 BX lr /*; Return */
314
315 SH_ICE /*; Captured by ICE */
316 /*; Save return value */
317 CMP R2, #0
318 BEQ SH_End
319 STR R0, [R2] /*; Save the return value to *pn32Out_R0 */
320
321 SH_End
322 MOVS R0, #1 /*; Set return value to 1 */
323 BX lr /*; Return */
324 }
325 #endif
326
327 #else // ndef DEBUG_ENABLE_SEMIHOST
328
329 /* Make sure won't goes here only because --gnu is defined , so
330 add !__CC_ARM and !__ICCARM__ checking */
331 # if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)
332
333 /**
334 * @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
335 *
336 * @param None
337 *
338 * @returns None
339 *
340 * @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
341 *
342 */
HardFault_Handler(void)343 void HardFault_Handler(void)
344 {
345 asm("MOVS r0, #4 \n"
346 "MOV r1, LR \n"
347 "TST r0, r1 \n" /*; check LR bit 2 */
348 "BEQ 1f \n" /*; stack use MSP */
349 "MRS R0, PSP \n" /*; stack use PSP, read PSP */
350 "MOV R1, LR \n" /*; LR current value */
351 "B Hard_Fault_Handler \n"
352 "1: \n"
353 "MRS R0, MSP \n" /*; LR current value */
354 "B Hard_Fault_Handler \n"
355 ::[Hard_Fault_Handler] "r" (Hard_Fault_Handler) // input
356 );
357 while(1);
358 }
359
360 # elif defined(__ICCARM__)
361
Get_LR_and_Branch(void)362 void Get_LR_and_Branch(void)
363 {
364 asm("MOV R1, LR \n" /*; LR current value */
365 "B Hard_Fault_Handler \n"
366 );
367 }
368
Stack_Use_MSP(void)369 void Stack_Use_MSP(void)
370 {
371 asm("MRS R0, MSP \n" /*; read MSP */
372 "B Get_LR_and_Branch \n"
373 );
374 }
375
376 /**
377 * @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
378 *
379 * @param None
380 *
381 * @returns None
382 *
383 * @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
384 *
385 */
HardFault_Handler(void)386 void HardFault_Handler(void)
387 {
388 asm("MOVS r0, #4 \n"
389 "MOV r1, LR \n"
390 "TST r0, r1 \n" /*; check LR bit 2 */
391 "BEQ Stack_Use_MSP \n" /*; stack use MSP */
392 "MRS R0, PSP \n" /*; stack use PSP, read PSP */
393 "B Get_LR_and_Branch \n"
394 );
395
396 while(1);
397 }
398
399 # else
400
401 /**
402 * @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
403 *
404 * @param None
405 *
406 * @return None
407 *
408 * @details The function extracts the location of stack frame and passes it to Hard_Fault_Handler function as a pointer
409 *
410 */
HardFault_Handler(void)411 __asm int32_t HardFault_Handler(void)
412 {
413 MOVS r0, #4
414 MOV r1, LR
415 TST r0, r1 /*; check LR bit 2 */
416 BEQ Stack_Use_MSP /*; stack use MSP */
417 MRS R0, PSP /*; stack use PSP, read PSP */
418 B Get_LR_and_Branch
419 Stack_Use_MSP
420 MRS R0, MSP /*; read MSP */
421 Get_LR_and_Branch
422 MOV R1, LR /*; LR current value */
423 LDR R2,=__cpp(Hard_Fault_Handler) /*; branch to Hard_Fault_Handler */
424 BX R2
425 }
426
427 #endif
428
429 #endif
430
431 #ifndef DISABLE_UART
432 /**
433 * @brief Routine to send a char
434 *
435 * @param[in] ch Character to send to debug port.
436 *
437 * @returns Send value from UART debug port
438 *
439 * @details Send a target char to UART debug port .
440 */
441 #ifndef NONBLOCK_PRINTF
SendChar_ToUART(int ch)442 static void SendChar_ToUART(int ch)
443 {
444 while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
445
446 if(ch == '\n')
447 {
448 DEBUG_PORT->DAT = '\r';
449 while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
450 }
451 DEBUG_PORT->DAT = ch;
452 }
453
454 #else
455 /* Non-block implement of send char */
456 #define BUF_SIZE 2048
SendChar_ToUART(int ch)457 static void SendChar_ToUART(int ch)
458 {
459 static uint8_t u8Buf[BUF_SIZE] = {0};
460 static int32_t i32Head = 0;
461 static int32_t i32Tail = 0;
462 int32_t i32Tmp;
463
464 /* Only flush the data in buffer to UART when ch == 0 */
465 if(ch)
466 {
467 /* Push char */
468 if(ch == '\n')
469 {
470 i32Tmp = i32Head+1;
471 if(i32Tmp > BUF_SIZE) i32Tmp = 0;
472 if(i32Tmp != i32Tail)
473 {
474 u8Buf[i32Head] = '\r';
475 i32Head = i32Tmp;
476 }
477 }
478
479 i32Tmp = i32Head+1;
480 if(i32Tmp > BUF_SIZE) i32Tmp = 0;
481 if(i32Tmp != i32Tail)
482 {
483 u8Buf[i32Head] = ch;
484 i32Head = i32Tmp;
485 }
486 }
487 else
488 {
489 if(i32Tail == i32Head)
490 return;
491 }
492
493 /* pop char */
494 do
495 {
496 i32Tmp = i32Tail + 1;
497 if(i32Tmp > BUF_SIZE) i32Tmp = 0;
498
499 if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) == 0)
500 {
501 DEBUG_PORT->DAT = u8Buf[i32Tail];
502 i32Tail = i32Tmp;
503 }
504 else
505 break; /* FIFO full */
506 }while(i32Tail != i32Head);
507 }
508 #endif /* else for NONBLOCK_PRINTF */
509
510 #endif /* if not def DISABLE_UART */
511
512 /**
513 * @brief Routine to send a char
514 *
515 * @param[in] ch Character to send to debug port.
516 *
517 * @returns Send value from UART debug port or semihost
518 *
519 * @details Send a target char to UART debug port or semihost.
520 */
SendChar(int ch)521 static void SendChar(int ch)
522 {
523 #if defined(DEBUG_ENABLE_SEMIHOST)
524 g_buf[g_buf_len++] = ch;
525 g_buf[g_buf_len] = '\0';
526 if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0')
527 {
528 /* Send the char */
529 if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0)
530 {
531 g_buf_len = 0;
532 return;
533 }
534 else
535 {
536 #ifndef DISABLE_UART
537 int i;
538
539 for(i = 0; i < g_buf_len; i++)
540 SendChar_ToUART(g_buf[i]);
541 #endif
542 g_buf_len = 0;
543 }
544 }
545 #else
546 #ifndef DISABLE_UART
547 SendChar_ToUART(ch);
548 #endif
549 #endif
550 }
551
552 /**
553 * @brief Routine to get a char
554 *
555 * @param None
556 *
557 * @returns Get value from UART debug port or semihost
558 *
559 * @details Wait UART debug port or semihost to input a char.
560 */
GetChar(void)561 static char GetChar(void)
562 {
563 #ifdef DEBUG_ENABLE_SEMIHOST
564 # if defined (__CC_ARM)
565 int nRet;
566 while(SH_DoCommand(0x101, 0, &nRet) != 0)
567 {
568 if(nRet != 0)
569 {
570 SH_DoCommand(0x07, 0, &nRet);
571 return (char)nRet;
572 }
573 }
574 # else
575 int nRet;
576 while(SH_DoCommand(0x7, 0, &nRet) != 0)
577 {
578 if(nRet != 0)
579 return (char)nRet;
580 }
581 # endif
582 return (0);
583 #else
584 #ifndef DISABLE_UART
585 while(1)
586 {
587 if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
588 {
589 return (DEBUG_PORT->DAT);
590 }
591 }
592 #else
593 return 0;
594 #endif
595 #endif
596 }
597
598 /**
599 * @brief Check any char input from UART
600 *
601 * @param None
602 *
603 * @retval 1: No any char input
604 * @retval 0: Have some char input
605 *
606 * @details Check UART RSR RX EMPTY or not to determine if any char input from UART
607 */
608
kbhit(void)609 int kbhit(void)
610 {
611 #ifndef DISABLE_UART
612 return !((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0);
613 #else
614 return 0;
615 #endif
616 }
617 /**
618 * @brief Check if debug message finished
619 *
620 * @param None
621 *
622 * @retval 1: Message is finished
623 * @retval 0: Message is transmitting.
624 *
625 * @details Check if message finished (FIFO empty of debug port)
626 */
627
IsDebugFifoEmpty(void)628 int IsDebugFifoEmpty(void)
629 {
630 #ifndef DISABLE_UART
631 return ((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXEMPTYF_Msk) != 0);
632 #else
633 return 1;
634 #endif
635 }
636
637 /**
638 * @brief C library retargetting
639 *
640 * @param[in] ch Character to send to debug port.
641 *
642 * @returns None
643 *
644 * @details Check if message finished (FIFO empty of debug port)
645 */
646
_ttywrch(int ch)647 void _ttywrch(int ch)
648 {
649 SendChar(ch);
650 return;
651 }
652
653
654 /**
655 * @brief Write character to stream
656 *
657 * @param[in] ch Character to be written. The character is passed as its int promotion.
658 * @param[in] stream Pointer to a FILE object that identifies the stream where the character is to be written.
659 *
660 * @returns If there are no errors, the same character that has been written is returned.
661 * If an error occurs, EOF is returned and the error indicator is set (see ferror).
662 *
663 * @details Writes a character to the stream and advances the position indicator.\n
664 * The character is written at the current position of the stream as indicated \n
665 * by the internal position indicator, which is then advanced one character.
666 *
667 * @note The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/fputc/.
668 *
669 *
670 */
671
fputc(int ch,FILE * stream)672 int fputc(int ch, FILE *stream)
673 {
674 SendChar(ch);
675 return ch;
676 }
677
678 #if defined (__GNUC__) && !defined(__ARMCC_VERSION)
679
_write(int fd,char * ptr,int len)680 int _write (int fd, char *ptr, int len)
681 {
682 int i = len;
683
684 while(i--)
685 {
686 while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
687
688 if(*ptr == '\n')
689 {
690 DEBUG_PORT->DAT = '\r';
691 while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
692 }
693
694 DEBUG_PORT->DAT = *ptr++;
695
696 }
697 return len;
698 }
699
_read(int fd,char * ptr,int len)700 int _read (int fd, char *ptr, int len)
701 {
702
703 while((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) != 0);
704 *ptr = DEBUG_PORT->DAT;
705 return 1;
706
707
708 }
709
710 #else
711 /**
712 * @brief Get character from UART debug port or semihosting input
713 *
714 * @param[in] stream Pointer to a FILE object that identifies the stream on which the operation is to be performed.
715 *
716 * @returns The character read from UART debug port or semihosting
717 *
718 * @details For get message from debug port or semihosting.
719 *
720 */
721
fgetc(FILE * stream)722 int fgetc(FILE *stream)
723 {
724 return (GetChar());
725 }
726
727 /**
728 * @brief Check error indicator
729 *
730 * @param[in] stream Pointer to a FILE object that identifies the stream.
731 *
732 * @returns If the error indicator associated with the stream was set, the function returns a nonzero value.
733 * Otherwise, it returns a zero value.
734 *
735 * @details Checks if the error indicator associated with stream is set, returning a value different
736 * from zero if it is. This indicator is generally set by a previous operation on the stream that failed.
737 *
738 * @note The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/ferror/.
739 *
740 */
741
ferror(FILE * stream)742 int ferror(FILE *stream)
743 {
744 return EOF;
745 }
746 #endif
747 #ifdef DEBUG_ENABLE_SEMIHOST
748 # ifdef __ICCARM__
__exit(int return_code)749 void __exit(int return_code)
750 {
751
752 /* Check if link with ICE */
753 if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
754 {
755 /* Make sure all message is print out */
756 while(IsDebugFifoEmpty() == 0);
757 }
758 label:
759 goto label; /* endless loop */
760 }
761 # else
_sys_exit(int return_code)762 void _sys_exit(int return_code)
763 {
764
765 /* Check if link with ICE */
766 if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
767 {
768 /* Make sure all message is print out */
769 while(IsDebugFifoEmpty() == 0);
770 }
771 label:
772 goto label; /* endless loop */
773 }
774 # endif
775 #endif
776