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