blob: 9dffed148d920ea60b5322a5f6d5321243c52659 [file] [log] [blame]
/*---------------------------------------------------*/
/* 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++) {
#ifdef STDOUT_BASEADDRESS
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)--;
#ifdef STDOUT_BASEADDRESS
outbyte(*LocalPtr);
LocalPtr += 1;
#endif
}
/* Pad on right if needed */
/* CR 439175 - elided next stmt. Seemed bogus. */
/* par->len = strlen( lp) */
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 % 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) {
#ifdef STDOUT_BASEADDRESS
outbyte( outbuf[i] );
i--;
#endif
}
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__)
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;
s32 ResultIsDigit = 0;
charptr cptr;
n = 0;
cptr = *linep;
if(cptr != NULL){
ResultIsDigit = isdigit(((s32)*cptr));
}
while (ResultIsDigit != 0) {
if(cptr != NULL){
n = ((n*10) + (((s32)*cptr) - (s32)'0'));
cptr += 1;
if(cptr != NULL){
ResultIsDigit = isdigit(((s32)*cptr));
}
}
ResultIsDigit = isdigit(((s32)*cptr));
}
*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, ...) */
void xil_printf( const char8 *ctrl1, ...)
{
s32 Check;
#if defined (__aarch64__)
s32 long_flag;
#endif
s32 dot_flag;
params_t par;
char8 ch;
va_list argp;
char8 *ctrl = (char8 *)ctrl1;
va_start( argp, ctrl1);
while ((ctrl != NULL) && (*ctrl != (char8)0)) {
/* move format string chars to buffer until a */
/* format control is found. */
if (*ctrl != '%') {
#ifdef STDOUT_BASEADDRESS
outbyte(*ctrl);
ctrl += 1;
#endif
continue;
}
/* initialize all the flags for this format. */
dot_flag = 0;
#if defined (__aarch64__)
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 = *ctrl;
}
else {
ch = *ctrl;
}
if (isdigit((s32)ch) != 0) {
if (dot_flag != 0) {
par.num2 = getnum(&ctrl);
}
else {
if (ch == '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((s32)ch)) {
case '%':
#ifdef STDOUT_BASEADDRESS
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__)
long_flag = 1;
#endif
Check = 0;
break;
case 'u':
par.unsigned_flag = 1;
/* fall through */
case 'i':
case 'd':
#if defined (__aarch64__)
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__)
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__)
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':
#ifdef STDOUT_BASEADDRESS
outbyte( va_arg( argp, s32));
#endif
Check = 1;
break;
case '\\':
switch (*ctrl) {
case 'a':
#ifdef STDOUT_BASEADDRESS
outbyte( ((char8)0x07));
#endif
break;
case 'h':
#ifdef STDOUT_BASEADDRESS
outbyte( ((char8)0x08));
#endif
break;
case 'r':
#ifdef STDOUT_BASEADDRESS
outbyte( ((char8)0x0D));
#endif
break;
case 'n':
#ifdef STDOUT_BASEADDRESS
outbyte( ((char8)0x0D));
outbyte( ((char8)0x0A));
#endif
break;
default:
#ifdef STDOUT_BASEADDRESS
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;
}
va_end( argp);
}
/*---------------------------------------------------*/