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