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