448 lines
12 KiB
C
448 lines
12 KiB
C
/******************************************************************************
|
|
* Copyright (c) 1995 - 2022 Xilinx, Inc. All rights reserved.
|
|
* SPDX-License-Identifier: MIT
|
|
*******************************************************************************/
|
|
/*---------------------------------------------------*/
|
|
/* Modified from : */
|
|
/* Public Domain version of printf */
|
|
/* Rud Merriam, Compsult, Inc. Houston, Tx. */
|
|
/* For Embedded Systems Programming, 1991 */
|
|
/* */
|
|
/*---------------------------------------------------*/
|
|
#include "xil_printf.h"
|
|
#include "xil_types.h"
|
|
#include "xil_assert.h"
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
|
|
static void padding( const s32 l_flag,const struct params_s *par);
|
|
static void outs(const charptr lp, struct params_s *par);
|
|
static s32 getnum( charptr* linep);
|
|
|
|
typedef struct params_s {
|
|
s32 len;
|
|
s32 num1;
|
|
s32 num2;
|
|
char8 pad_character;
|
|
s32 do_padding;
|
|
s32 left_flag;
|
|
s32 unsigned_flag;
|
|
} params_t;
|
|
|
|
|
|
/*---------------------------------------------------*/
|
|
/* The purpose of this routine is to output data the */
|
|
/* same as the standard printf function without the */
|
|
/* overhead most run-time libraries involve. Usually */
|
|
/* the printf brings in many kilobytes of code and */
|
|
/* that is unacceptable in most embedded systems. */
|
|
/*---------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------*/
|
|
/* */
|
|
/* This routine puts pad characters into the output */
|
|
/* buffer. */
|
|
/* */
|
|
static void padding( const s32 l_flag, const struct params_s *par)
|
|
{
|
|
s32 i;
|
|
|
|
if ((par->do_padding != 0) && (l_flag != 0) && (par->len < par->num1)) {
|
|
i=(par->len);
|
|
for (; i<(par->num1); i++) {
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte( par->pad_character);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------*/
|
|
/* */
|
|
/* This routine moves a string to the output buffer */
|
|
/* as directed by the padding and positioning flags. */
|
|
/* */
|
|
static void outs(const charptr lp, struct params_s *par)
|
|
{
|
|
charptr LocalPtr;
|
|
LocalPtr = lp;
|
|
/* pad on left if needed */
|
|
if(LocalPtr != NULL) {
|
|
par->len = (s32)strlen( LocalPtr);
|
|
padding( !(par->left_flag), par);
|
|
/* Move string to the buffer */
|
|
while (((*LocalPtr) != (char8)0) && ((par->num2) != 0)) {
|
|
(par->num2)--;
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte(*LocalPtr);
|
|
#endif
|
|
LocalPtr += 1;
|
|
}
|
|
}
|
|
|
|
/* Pad on right if needed */
|
|
/* CR 439175 - elided next stmt. Seemed bogus. */
|
|
padding( par->left_flag, par);
|
|
}
|
|
|
|
/*---------------------------------------------------*/
|
|
/* */
|
|
/* This routine moves a number to the output buffer */
|
|
/* as directed by the padding and positioning flags. */
|
|
/* */
|
|
|
|
static void outnum( const s32 n, const s32 base, struct params_s *par)
|
|
{
|
|
s32 negative;
|
|
s32 i;
|
|
char8 outbuf[32];
|
|
const char8 digits[] = "0123456789ABCDEF";
|
|
u32 num;
|
|
for(i = 0; i<32; i++) {
|
|
outbuf[i] = '0';
|
|
}
|
|
|
|
/* Check if number is negative */
|
|
if ((par->unsigned_flag == 0) && (base == 10) && (n < 0L)) {
|
|
negative = 1;
|
|
num =(-(n));
|
|
}
|
|
else{
|
|
num = n;
|
|
negative = 0;
|
|
}
|
|
|
|
/* Build number (backwards) in outbuf */
|
|
i = 0;
|
|
do {
|
|
outbuf[i] = digits[(num % (u32)base)];
|
|
i++;
|
|
num /= base;
|
|
} while (num > 0U);
|
|
|
|
if (negative != 0) {
|
|
outbuf[i] = '-';
|
|
i++;
|
|
}
|
|
|
|
outbuf[i] = '\0';
|
|
i--;
|
|
|
|
/* Move the converted number to the buffer and */
|
|
/* add in the padding where needed. */
|
|
par->len = (s32)strlen(outbuf);
|
|
padding( !(par->left_flag), par);
|
|
while (&outbuf[i] >= outbuf) {
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte( outbuf[i] );
|
|
#endif
|
|
i--;
|
|
}
|
|
padding( par->left_flag, par);
|
|
}
|
|
/*---------------------------------------------------*/
|
|
/* */
|
|
/* This routine moves a 64-bit number to the output */
|
|
/* buffer as directed by the padding and positioning */
|
|
/* flags. */
|
|
/* */
|
|
#if defined (__aarch64__) || defined (__arch64__)
|
|
static void outnum1( const s64 n, const s32 base, params_t *par)
|
|
{
|
|
s32 negative;
|
|
s32 i;
|
|
char8 outbuf[64];
|
|
const char8 digits[] = "0123456789ABCDEF";
|
|
u64 num;
|
|
for(i = 0; i<64; i++) {
|
|
outbuf[i] = '0';
|
|
}
|
|
|
|
/* Check if number is negative */
|
|
if ((par->unsigned_flag == 0) && (base == 10) && (n < 0L)) {
|
|
negative = 1;
|
|
num =(-(n));
|
|
}
|
|
else{
|
|
num = (n);
|
|
negative = 0;
|
|
}
|
|
|
|
/* Build number (backwards) in outbuf */
|
|
i = 0;
|
|
do {
|
|
outbuf[i] = digits[(num % base)];
|
|
i++;
|
|
num /= base;
|
|
} while (num > 0);
|
|
|
|
if (negative != 0) {
|
|
outbuf[i] = '-';
|
|
i++;
|
|
}
|
|
|
|
outbuf[i] = '\0';
|
|
i--;
|
|
|
|
/* Move the converted number to the buffer and */
|
|
/* add in the padding where needed. */
|
|
par->len = (s32)strlen(outbuf);
|
|
padding( !(par->left_flag), par);
|
|
while (&outbuf[i] >= outbuf) {
|
|
outbyte( outbuf[i] );
|
|
i--;
|
|
}
|
|
padding( par->left_flag, par);
|
|
}
|
|
#endif
|
|
/*---------------------------------------------------*/
|
|
/* */
|
|
/* This routine gets a number from the format */
|
|
/* string. */
|
|
/* */
|
|
static s32 getnum(charptr* linep)
|
|
{
|
|
s32 n = 0;
|
|
s32 ResultIsDigit = 0;
|
|
charptr cptr = *linep;
|
|
|
|
while (cptr != NULL) {
|
|
ResultIsDigit = isdigit(((u8)*cptr));
|
|
if (ResultIsDigit == 0) {
|
|
break;
|
|
}
|
|
n = ((n*10) + (((s32)*cptr) - (s32)'0'));
|
|
cptr += 1;
|
|
}
|
|
|
|
*linep = ((charptr)(cptr));
|
|
return(n);
|
|
}
|
|
|
|
/*---------------------------------------------------*/
|
|
/* */
|
|
/* This routine operates just like a printf/sprintf */
|
|
/* routine. It outputs a set of data under the */
|
|
/* control of a formatting string. Not all of the */
|
|
/* standard C format control are supported. The ones */
|
|
/* provided are primarily those needed for embedded */
|
|
/* systems work. Primarily the floating point */
|
|
/* routines are omitted. Other formats could be */
|
|
/* added easily by following the examples shown for */
|
|
/* the supported formats. */
|
|
/* */
|
|
|
|
/* void esp_printf( const func_ptr f_ptr,
|
|
const charptr ctrl1, ...) */
|
|
#if defined (__aarch64__) && HYP_GUEST && EL1_NONSECURE && XEN_USE_PV_CONSOLE
|
|
void xil_printf( const char8 *ctrl1, ...){
|
|
XPVXenConsole_Printf(ctrl1);
|
|
}
|
|
#else
|
|
void xil_printf( const char8 *ctrl1, ...)
|
|
{
|
|
va_list argp;
|
|
|
|
va_start(argp, ctrl1);
|
|
|
|
xil_vprintf(ctrl1, argp);
|
|
|
|
va_end(argp);
|
|
}
|
|
#endif
|
|
|
|
/* This routine is equivalent to vprintf routine */
|
|
void xil_vprintf(const char8 *ctrl1, va_list argp)
|
|
{
|
|
s32 Check;
|
|
#if defined (__aarch64__) || defined (__arch64__)
|
|
s32 long_flag;
|
|
#endif
|
|
s32 dot_flag;
|
|
|
|
params_t par;
|
|
|
|
u8 ch;
|
|
char8 *ctrl = (char8 *)ctrl1;
|
|
|
|
while ((ctrl != NULL) && (*ctrl != (char8)0)) {
|
|
|
|
/* move format string chars to buffer until a */
|
|
/* format control is found. */
|
|
if (*ctrl != '%') {
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte(*ctrl);
|
|
#endif
|
|
ctrl += 1;
|
|
continue;
|
|
}
|
|
|
|
/* initialize all the flags for this format. */
|
|
dot_flag = 0;
|
|
#if defined (__aarch64__) || defined (__arch64__)
|
|
long_flag = 0;
|
|
#endif
|
|
par.unsigned_flag = 0;
|
|
par.left_flag = 0;
|
|
par.do_padding = 0;
|
|
par.pad_character = ' ';
|
|
par.num2=32767;
|
|
par.num1=0;
|
|
par.len=0;
|
|
|
|
try_next:
|
|
if(ctrl != NULL) {
|
|
ctrl += 1;
|
|
}
|
|
if(ctrl != NULL) {
|
|
ch = (u8)*ctrl;
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
if (isdigit(ch) != 0) {
|
|
if (dot_flag != 0) {
|
|
par.num2 = getnum(&ctrl);
|
|
}
|
|
else {
|
|
if (ch == (u8)'0') {
|
|
par.pad_character = '0';
|
|
}
|
|
if(ctrl != NULL) {
|
|
par.num1 = getnum(&ctrl);
|
|
}
|
|
par.do_padding = 1;
|
|
}
|
|
if(ctrl != NULL) {
|
|
ctrl -= 1;
|
|
}
|
|
goto try_next;
|
|
}
|
|
|
|
switch (tolower(ch)) {
|
|
case '%':
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte( '%');
|
|
#endif
|
|
Check = 1;
|
|
break;
|
|
|
|
case '-':
|
|
par.left_flag = 1;
|
|
Check = 0;
|
|
break;
|
|
|
|
case '.':
|
|
dot_flag = 1;
|
|
Check = 0;
|
|
break;
|
|
|
|
case 'l':
|
|
#if defined (__aarch64__) || defined (__arch64__)
|
|
long_flag = 1;
|
|
#endif
|
|
Check = 0;
|
|
break;
|
|
|
|
case 'u':
|
|
par.unsigned_flag = 1;
|
|
/* fall through */
|
|
case 'i':
|
|
case 'd':
|
|
#if defined (__aarch64__) || defined (__arch64__)
|
|
if (long_flag != 0){
|
|
outnum1((s64)va_arg(argp, s64), 10L, &par);
|
|
}
|
|
else {
|
|
outnum( va_arg(argp, s32), 10L, &par);
|
|
}
|
|
#else
|
|
outnum( va_arg(argp, s32), 10L, &par);
|
|
#endif
|
|
Check = 1;
|
|
break;
|
|
case 'p':
|
|
#if defined (__aarch64__) || defined (__arch64__)
|
|
par.unsigned_flag = 1;
|
|
outnum1((s64)va_arg(argp, s64), 16L, &par);
|
|
Check = 1;
|
|
break;
|
|
#endif
|
|
case 'X':
|
|
case 'x':
|
|
par.unsigned_flag = 1;
|
|
#if defined (__aarch64__) || defined (__arch64__)
|
|
if (long_flag != 0) {
|
|
outnum1((s64)va_arg(argp, s64), 16L, &par);
|
|
}
|
|
else {
|
|
outnum((s32)va_arg(argp, s32), 16L, &par);
|
|
}
|
|
#else
|
|
outnum((s32)va_arg(argp, s32), 16L, &par);
|
|
#endif
|
|
Check = 1;
|
|
break;
|
|
|
|
case 's':
|
|
outs( va_arg( argp, char *), &par);
|
|
Check = 1;
|
|
break;
|
|
|
|
case 'c':
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte( (char8)va_arg( argp, s32));
|
|
#endif
|
|
Check = 1;
|
|
break;
|
|
|
|
case '\\':
|
|
switch (*ctrl) {
|
|
case 'a':
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte( ((char8)0x07));
|
|
#endif
|
|
break;
|
|
case 'h':
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte( ((char8)0x08));
|
|
#endif
|
|
break;
|
|
case 'r':
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte( ((char8)0x0D));
|
|
#endif
|
|
break;
|
|
case 'n':
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte( ((char8)0x0D));
|
|
outbyte( ((char8)0x0A));
|
|
#endif
|
|
break;
|
|
default:
|
|
#if defined(STDOUT_BASEADDRESS) || defined(VERSAL_PLM)
|
|
outbyte( *ctrl);
|
|
#endif
|
|
break;
|
|
}
|
|
ctrl += 1;
|
|
Check = 0;
|
|
break;
|
|
|
|
default:
|
|
Check = 1;
|
|
break;
|
|
}
|
|
if(Check == 1) {
|
|
if(ctrl != NULL) {
|
|
ctrl += 1;
|
|
}
|
|
continue;
|
|
}
|
|
goto try_next;
|
|
}
|
|
}
|
|
/*---------------------------------------------------*/
|