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