1 /**************************************************************************//**
2  * @file     retarget.c
3  * @version  V3.00
4  * @brief    Debug Port and Semihost Setting Source File
5  *
6  * @copyright SPDX-License-Identifier: Apache-2.0
7  * @copyright Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
8  ******************************************************************************/
9 
10 
11 #include <stdio.h>
12 #include "NuMicro.h"
13 
14 
15 __attribute__((weak, noreturn))
16 void __aeabi_assert(const char* expr, const char* file, int line);
17 
18 #if defined (__ICCARM__)
19 # pragma diag_suppress=Pm150
20 #endif
21 
22 
23 #if defined ( __CC_ARM   )
24 #if (__ARMCC_VERSION < 400000)
25 #else
26 /* Insist on keeping widthprec, to avoid X propagation by benign code in C-lib */
27 #pragma import _printf_widthprec
28 #endif
29 #endif
30 
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 
48 #ifdef __MICROLIB
49 FILE __stdout;
50 FILE __stdin;
51 
52 void abort(void);
53 
54 __attribute__((weak, noreturn))
__aeabi_assert(const char * expr,const char * file,int line)55 void __aeabi_assert(const char* expr, const char* file, int line)
56 {
57     char str[12], * p;
58 
59     fputs("*** assertion failed: ", stderr);
60     fputs(expr, stderr);
61     fputs(", file ", stderr);
62     fputs(file, stderr);
63     fputs(", line ", stderr);
64 
65     p = str + sizeof(str);
66     *--p = '\0';
67     *--p = '\n';
68     while(line > 0)
69     {
70         *--p = '0' + (line % 10);
71         line /= 10;
72     }
73     fputs(p, stderr);
74 
75     abort();
76 }
77 
78 
79 __attribute__((weak))
abort(void)80 void abort(void)
81 {
82     for(;;);
83 }
84 
85 #else
86 # if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
87 __asm("  .global __ARM_use_no_argv\n");
88 __asm("  .global __use_no_semihosting\n");
89 
90 
91 FILE __stdout;
92 FILE __stdin;
93 FILE __stderr;
94 
95 void _sys_exit(int return_code)__attribute__((noreturn));
_sys_exit(int return_code)96 void _sys_exit(int return_code)
97 {
98     (void) return_code;
99     while(1);
100 }
101 
102 
103 # endif
104 #endif
105 
106 
107 
108 
109 #if (defined(__ARMCC_VERSION) || defined(__ICCARM__))
110 extern int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0);
111 
112 #if defined( __ICCARM__ )
113 __WEAK
114 #else
115 __attribute__((weak))
116 #endif
117 uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp);
118 
119 #endif
120 
121 int kbhit(void);
122 int IsDebugFifoEmpty(void);
123 void _ttywrch(int ch);
124 int fputc(int ch, FILE *stream);
125 
126 #if (defined(__ARMCC_VERSION) || defined(__ICCARM__))
127 int fgetc(FILE *stream);
128 int ferror(FILE *stream);
129 #endif
130 
131 char GetChar(void);
132 void SendChar_ToUART(int ch);
133 void SendChar(int ch);
134 
135 #if defined(DEBUG_ENABLE_SEMIHOST)
136 #if (defined(__ARMCC_VERSION) || defined(__ICCARM__))
137 /* The static buffer is used to speed up the semihost */
138 static char g_buf[16];
139 static uint8_t g_buf_len = 0;
140 static volatile int32_t g_ICE_Conneced = 1;
141 
142 
143 int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0);
144 void _sys_exit(int return_code)__attribute__((noreturn));
145 
146 /**
147  * @brief    This function is called by Hardfault handler.
148  * @param    None
149  * @returns  None
150  * @details  This function is called by Hardfault handler and check if it is caused by __BKPT or not.
151  *
152  */
153 
ProcessHardFault(uint32_t lr,uint32_t msp,uint32_t psp)154 uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp)
155 {
156     uint32_t *sp = NULL;
157     uint32_t inst;
158 
159     /* Check the used stack */
160     if(lr & 0x40)
161     {
162         /* Secure stack used */
163         if(lr & 4)
164             sp = (uint32_t *)psp;
165         else
166             sp = (uint32_t *)msp;
167 
168     }
169 #if defined (__ARM_FEATURE_CMSE) &&  (__ARM_FEATURE_CMSE == 3U)
170     else
171     {
172         /* Non-secure stack used */
173         if(lr & 4)
174             sp = (uint32_t *)__TZ_get_PSP_NS();
175         else
176             sp = (uint32_t *)__TZ_get_MSP_NS();
177 
178     }
179 #endif
180 
181     /* Get the instruction caused the hardfault */
182     inst = M16(sp[6]);
183 
184 
185     if(inst == 0xBEAB)
186     {
187         /*
188             If the instruction is 0xBEAB, it means it is caused by BKPT without ICE connected.
189             We still return for output/input message to UART.
190         */
191         g_ICE_Conneced = 0; // Set a flag for ICE offline
192         sp[6] += 2; // return to next instruction
193         return lr;  // Keep lr in R0
194     }
195 
196     /* It is casued by hardfault (Not semihost). Just process the hard fault here. */
197     /* TODO: Implement your hardfault handle code here */
198 
199     /*
200     printf("  HardFault!\n\n");
201     printf("r0  = 0x%x\n", sp[0]);
202     printf("r1  = 0x%x\n", sp[1]);
203     printf("r2  = 0x%x\n", sp[2]);
204     printf("r3  = 0x%x\n", sp[3]);
205     printf("r12 = 0x%x\n", sp[4]);
206     printf("lr  = 0x%x\n", sp[5]);
207     printf("pc  = 0x%x\n", sp[6]);
208     printf("psr = 0x%x\n", sp[7]);
209     */
210 
211     while(1) {}
212 
213 }
214 
215 
216 
217 /**
218  *
219  * @brief      The function to process semihosted command
220  * @param[in]  n32In_R0  : semihost register 0
221  * @param[in]  n32In_R1  : semihost register 1
222  * @param[out] pn32Out_R0: semihost register 0
223  * @retval     0: No ICE debug
224  * @retval     1: ICE debug
225  *
226  */
227 
SH_Return(int32_t n32In_R0,int32_t n32In_R1,int32_t * pn32Out_R0)228 int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
229 {
230     (void)n32In_R1;
231 
232     if(g_ICE_Conneced)
233     {
234         if(pn32Out_R0)
235             *pn32Out_R0 = n32In_R0;
236 
237         return 1;
238     }
239     return 0;
240 }
241 
242 
243 
244 #endif
245 #else // defined(DEBUG_ENABLE_SEMIHOST)
246 
247 int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0);
248 
249 #if defined( __ICCARM__ )
250 __WEAK
251 #else
252 __attribute__((weak))
253 #endif
ProcessHardFault(uint32_t lr,uint32_t msp,uint32_t psp)254 uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp)
255 {
256     uint32_t *sp = NULL;
257     uint32_t i;
258     uint32_t u32Reg;
259     uint32_t inst, addr, taddr, tdata;
260     int32_t secure;
261     uint32_t rm, rn, rt, imm5, imm8;
262 
263     /* It is casued by hardfault. Just process the hard fault */
264     /* TODO: Implement your hardfault handle code here */
265 
266 
267     /* Check the used stack */
268     secure = (lr & 0x40ul) ? 1 : 0;
269     if(secure)
270     {
271         /* Secure stack used */
272         if(lr & 4UL)
273         {
274             sp = (uint32_t *)psp;
275         }
276         else
277         {
278             sp = (uint32_t *)msp;
279         }
280 
281     }
282 #if defined (__ARM_FEATURE_CMSE) &&  (__ARM_FEATURE_CMSE == 3)
283     else
284     {
285         /* Non-secure stack used */
286         if(lr & 4)
287             sp = (uint32_t *)(__TZ_get_PSP_NS());
288         else
289             sp = (uint32_t *)(__TZ_get_MSP_NS());
290 
291     }
292 #endif
293 
294     /*
295         r0  = sp[0]
296         r1  = sp[1]
297         r2  = sp[2]
298         r3  = sp[3]
299         r12 = sp[4]
300         lr  = sp[5]
301         pc  = sp[6]
302         psr = sp[7]
303     */
304 
305 
306     printf("HardFault @ 0x%08x\n", sp[6]);
307     /* Get the instruction caused the hardfault */
308     addr = sp[6];
309     inst = M16(addr);
310 
311     printf("HardFault Analysis:\n");
312 
313     printf("Instruction code = %x\n", inst);
314 
315     if((!secure) && ((addr & NS_OFFSET) == 0))
316     {
317         printf("Non-secure CPU try to fetch secure code\n");
318     }
319     else if(inst == 0xBEAB)
320     {
321         printf("Execute BKPT without ICE connected\n");
322     }
323     else if((inst >> 12) == 5)
324     {
325         /* 0101xx Load/store (register offset) on page C2-327 of armv8m ref */
326         rm = (inst >> 6) & 0x7;
327         rn = (inst >> 3) & 0x7;
328         rt = inst & 0x7;
329 
330         printf("LDR/STR rt=%x rm=%x rn=%x\n", rt, rm, rn);
331         taddr = sp[rn] + sp[rm];
332         tdata = sp[rt];
333         printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
334                (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
335 
336     }
337     else if((inst >> 13) == 3)
338     {
339         /* 011xxx    Load/store word/byte (immediate offset) on page C2-327 of armv8m ref */
340         imm5 = (inst >> 6) & 0x1f;
341         rn = (inst >> 3) & 0x7;
342         rt = inst & 0x7;
343 
344         printf("LDR/STR rt=%x rn=%x imm5=%x\n", rt, rn, imm5);
345         taddr = sp[rn] + imm5;
346         tdata = sp[rt];
347         printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
348                (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
349     }
350     else if((inst >> 12) == 8)
351     {
352         /* 1000xx    Load/store halfword (immediate offset) on page C2-328 */
353         imm5 = (inst >> 6) & 0x1f;
354         rn = (inst >> 3) & 0x7;
355         rt = inst & 0x7;
356 
357         printf("LDRH/STRH rt=%x rn=%x imm5=%x\n", rt, rn, imm5);
358         taddr = sp[rn] + imm5;
359         tdata = sp[rt];
360         printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
361                (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
362 
363     }
364     else if((inst >> 12) == 9)
365     {
366         /* 1001xx    Load/store (SP-relative) on page C2-328 */
367         imm8 = inst & 0xff;
368         rt = (inst >> 8) & 0x7;
369 
370         printf("LDRH/STRH rt=%x imm8=%x\n", rt, imm8);
371         taddr = sp[6] + imm8;
372         tdata = sp[rt];
373         printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
374                (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
375     }
376     else
377     {
378         printf("Unexpected instruction\n");
379     }
380 
381 
382     u32Reg = SCU->PVINTSTS;
383     if(u32Reg)
384     {
385         char const *master[] = {"CPU", 0, 0, "PDMA0", "SDH0", "CRPT", "USBH", 0, 0, 0, 0, "PDMA1"};
386         char const *ipname[] = {"APB0", "APB1", 0, 0, "GPIO", "EBI", "USBH", "CRC", "SDH0", 0, "PDMA0", "PDMA1"
387                                 , "SRAM0", "SRAM1", "FMC", "FLASH", "SCU", "SYS", "CRPT", "KS", "SIORAM"
388                                };
389         const uint8_t info[] = {0x34, 0x3C, 0, 0, 0x44, 0x4C, 0x54, 0x5C, 0x64, 0, 0x74, 0x7C, 0x84, 0x8C, 0x94, 0x9C, 0xA4, 0xAC, 0xB4, 0xBC, 0xC4};
390 
391         /* Get violation address and source */
392         for(i = 0; i < sizeof(ipname); i++)
393         {
394             if(u32Reg & (1 << i))
395             {
396                 printf("%s(0x%08x) Violation! ", ipname[i], M32(SCU_BASE + info[i] + 4));
397                 printf("Caused by %s\n", master[M32(SCU_BASE + (uint32_t)info[i])]);
398                 break;
399             }
400         }
401     }
402 
403 
404     /* Or *sp to remove compiler warning */
405     while(1U | *sp) {}
406 
407     return lr;
408 }
409 
410 
SH_Return(int32_t n32In_R0,int32_t n32In_R1,int32_t * pn32Out_R0)411 int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
412 {
413     (void)n32In_R0;
414     (void)n32In_R1;
415     (void)pn32Out_R0;
416     return 0;
417 }
418 
419 #endif /* defined(DEBUG_ENABLE_SEMIHOST) */
420 
421 
422 /**
423  * @brief    Routine to send a char
424  *
425  * @param[in] ch  A character data writes to debug port
426  *
427  * @returns  Send value from UART debug port
428  *
429  * @details  Send a target char to UART debug port .
430  */
431 #ifndef NONBLOCK_PRINTF
SendChar_ToUART(int ch)432 void SendChar_ToUART(int ch)
433 {
434     if((char)ch == '\n')
435     {
436         while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) {}
437         DEBUG_PORT->DAT = '\r';
438     }
439 
440     while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) {}
441     DEBUG_PORT->DAT = (uint32_t)ch;
442 }
443 
444 #else
445 /* Non-block implement of send char */
446 # define BUF_SIZE    512
SendChar_ToUART(int ch)447 void SendChar_ToUART(int ch)
448 {
449     static uint8_t u8Buf[BUF_SIZE] = {0};
450     static int32_t i32Head = 0;
451     static int32_t i32Tail = 0;
452     int32_t i32Tmp;
453 
454     /* Only flush the data in buffer to UART when ch == 0 */
455     if(ch)
456     {
457         if(ch == '\n')
458         {
459             i32Tmp = i32Head + 1;
460             if(i32Tmp > BUF_SIZE) i32Tmp = 0;
461             if(i32Tmp != i32Tail)
462             {
463                 u8Buf[i32Head] = '\r';
464                 i32Head = i32Tmp;
465             }
466         }
467 
468         // Push char
469         i32Tmp = i32Head + 1;
470         if(i32Tmp > BUF_SIZE) i32Tmp = 0;
471         if(i32Tmp != i32Tail)
472         {
473             u8Buf[i32Head] = ch;
474             i32Head = i32Tmp;
475         }
476 
477     }
478     else
479     {
480         if(i32Tail == i32Head)
481             return;
482     }
483 
484     // pop char
485     do
486     {
487         i32Tmp = i32Tail + 1;
488         if(i32Tmp > BUF_SIZE) i32Tmp = 0;
489 
490         if((DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk) == 0)
491         {
492             DEBUG_PORT->DATA = u8Buf[i32Tail];
493             i32Tail = i32Tmp;
494         }
495         else
496             break; // FIFO full
497     }
498     while(i32Tail != i32Head);
499 }
500 #endif
501 
502 /**
503  * @brief    Routine to send a char
504  *
505  * @param[in] ch A character data writes to debug port
506  *
507  * @returns  Send value from UART debug port or semihost
508  *
509  * @details  Send a target char to UART debug port or semihost.
510  */
SendChar(int ch)511 void SendChar(int ch)
512 {
513 #if defined(DEBUG_ENABLE_SEMIHOST)
514 
515     g_buf[g_buf_len++] = (char)ch;
516     g_buf[g_buf_len] = '\0';
517     if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0')
518     {
519         /* Send the char */
520         if(g_ICE_Conneced)
521         {
522 
523             if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0)
524             {
525                 g_buf_len = 0;
526 
527                 return;
528             }
529         }
530         else
531         {
532 # if (DEBUG_ENABLE_SEMIHOST == 2) // Re-direct to UART Debug Port only when DEBUG_ENABLE_SEMIHOST=2
533             int i;
534 
535             for(i = 0; i < g_buf_len; i++)
536                 SendChar_ToUART(g_buf[i]);
537             g_buf_len = 0;
538 # endif
539         }
540     }
541 #else
542     SendChar_ToUART(ch);
543 #endif
544 }
545 
546 /**
547  * @brief    Routine to get a char
548  *
549  * @param    None
550  *
551  * @returns  Get value from UART debug port or semihost
552  *
553  * @details  Wait UART debug port or semihost to input a char.
554  */
GetChar(void)555 char GetChar(void)
556 {
557 #ifdef DEBUG_ENABLE_SEMIHOST
558 # if defined (__ICCARM__)
559     int nRet;
560     while(SH_DoCommand(0x7, 0, &nRet) != 0)
561     {
562         if(nRet != 0)
563             return (char)nRet;
564     }
565 # else
566     int nRet;
567     while(SH_DoCommand(0x101, 0, &nRet) != 0)
568     {
569         if(nRet != 0)
570         {
571             SH_DoCommand(0x07, 0, &nRet);
572             return (char)nRet;
573         }
574     }
575 
576 
577 # if (DEBUG_ENABLE_SEMIHOST == 2) // Re-direct to UART Debug Port only when DEBUG_ENABLE_SEMIHOST=2
578 
579     /* Use debug port when ICE is not connected at semihost mode */
580     while(!g_ICE_Conneced)
581     {
582         if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
583         {
584             return (DEBUG_PORT->DAT);
585         }
586     }
587 # endif
588 
589 # endif
590     return (0);
591 #else
592 
593     while(1)
594     {
595         if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0U)
596         {
597             return ((char)DEBUG_PORT->DAT);
598         }
599     }
600 
601 #endif
602 }
603 
604 /**
605  * @brief    Check any char input from UART
606  *
607  * @param    None
608  *
609  * @retval   1: No any char input
610  * @retval   0: Have some char input
611  *
612  * @details  Check UART RSR RX EMPTY or not to determine if any char input from UART
613  */
614 
kbhit(void)615 int kbhit(void)
616 {
617     return !((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0U);
618 }
619 /**
620  * @brief    Check if debug message finished
621  *
622  * @param    None
623  *
624  * @retval   1: Message is finished
625  * @retval   0: Message is transmitting.
626  *
627  * @details  Check if message finished (FIFO empty of debug port)
628  */
629 
IsDebugFifoEmpty(void)630 int IsDebugFifoEmpty(void)
631 {
632     return ((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXEMPTYF_Msk) != 0U);
633 }
634 
635 /**
636  * @brief    C library retargetting
637  *
638  * @param[in]  ch  Write a character data
639  *
640  * @returns  None
641  *
642  * @details  Check if message finished (FIFO empty of debug port)
643  */
644 
_ttywrch(int ch)645 void _ttywrch(int ch)
646 {
647     SendChar(ch);
648     return;
649 }
650 
651 
652 /**
653  * @brief      Write character to stream
654  *
655  * @param[in]  ch       Character to be written. The character is passed as its int promotion.
656  * @param[in]  stream   Pointer to a FILE object that identifies the stream where the character is to be written.
657  *
658  * @returns    If there are no errors, the same character that has been written is returned.
659  *             If an error occurs, EOF is returned and the error indicator is set (see ferror).
660  *
661  * @details    Writes a character to the stream and advances the position indicator.\n
662  *             The character is written at the current position of the stream as indicated \n
663  *             by the internal position indicator, which is then advanced one character.
664  *
665  * @note       The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/fputc/.
666  *
667  *
668  */
669 
fputc(int ch,FILE * stream)670 int fputc(int ch, FILE *stream)
671 {
672     (void)stream;
673     SendChar(ch);
674     return ch;
675 }
676 
677 
678 #if (defined(__GNUC__) && !defined(__ARMCC_VERSION))
679 
680 #if !defined(OS_USE_SEMIHOSTING)
_write(int fd,char * ptr,int len)681 int _write(int fd, char *ptr, int len)
682 {
683     int i = len;
684 
685     while(i--)
686     {
687         if(*ptr == '\n')
688         {
689             while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
690             DEBUG_PORT->DAT = '\r';
691         }
692 
693         while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
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 #endif
710 
711 #else
712 /**
713  * @brief      Get character from UART debug port or semihosting input
714  *
715  * @param[in]  stream   Pointer to a FILE object that identifies the stream on which the operation is to be performed.
716  *
717  * @returns    The character read from UART debug port or semihosting
718  *
719  * @details    For get message from debug port or semihosting.
720  *
721  */
722 
fgetc(FILE * stream)723 int fgetc(FILE *stream)
724 {
725     (void)stream;
726     return ((int)GetChar());
727 }
728 
729 /**
730  * @brief      Check error indicator
731  *
732  * @param[in]  stream   Pointer to a FILE object that identifies the stream.
733  *
734  * @returns    If the error indicator associated with the stream was set, the function returns a nonzero value.
735  *             Otherwise, it returns a zero value.
736  *
737  * @details    Checks if the error indicator associated with stream is set, returning a value different
738  *             from zero if it is. This indicator is generally set by a previous operation on the stream that failed.
739  *
740  * @note       The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/ferror/.
741  *
742  */
743 
ferror(FILE * stream)744 int ferror(FILE *stream)
745 {
746     (void)stream;
747     return EOF;
748 }
749 #endif
750 
751 #ifdef DEBUG_ENABLE_SEMIHOST
752 # ifdef __ICCARM__
__exit(int return_code)753 void __exit(int return_code)
754 {
755 
756     /* Check if link with ICE */
757     if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
758     {
759         /* Make sure all message is print out */
760         while(IsDebugFifoEmpty() == 0);
761     }
762 label:
763     goto label;  /* endless loop */
764 }
765 # else
_sys_exit(int return_code)766 void _sys_exit(int return_code)
767 {
768     (void)return_code;
769     /* Check if link with ICE */
770     if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
771     {
772         /* Make sure all message is print out */
773         while(IsDebugFifoEmpty() == 0);
774     }
775 label:
776     goto label;  /* endless loop */
777 }
778 # endif
779 #endif
780