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