OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [sw/] [example/] [coremark/] [ee_printf.c] - Blame information for rev 4

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 zero_gravi
/* File : barebones/ee_printf.c
2
        This file contains an implementation of ee_printf that only requires a method to output a char to a UART without pulling in library code.
3
 
4
This code is based on a file that contains the following:
5
 Copyright (C) 2002 Michael Ringgaard. All rights reserved.
6
 
7
 Redistribution and use in source and binary forms, with or without
8
 modification, are permitted provided that the following conditions
9
 are met:
10
 
11
 1. Redistributions of source code must retain the above copyright
12
    notice, this list of conditions and the following disclaimer.
13
 2. Redistributions in binary form must reproduce the above copyright
14
    notice, this list of conditions and the following disclaimer in the
15
    documentation and/or other materials provided with the distribution.
16
 3. Neither the name of the project nor the names of its contributors
17
    may be used to endorse or promote products derived from this software
18
    without specific prior written permission.
19
 
20
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 SUCH DAMAGE.
31
 
32
*/
33
 
34
#include <core_portme.h>
35
#include <neorv32.h>
36
#include <stdarg.h>
37
#include <stdbool.h>
38
#include <string.h>
39
 
40
#define ZEROPAD         (1<<0)  /* Pad with zero */
41
#define SIGN            (1<<1)  /* Unsigned/signed long */
42
#define PLUS            (1<<2)  /* Show plus */
43
#define SPACE           (1<<3)  /* Spacer */
44
#define LEFT            (1<<4)  /* Left justified */
45
#define HEX_PREP        (1<<5)  /* 0x */
46
#define UPPERCASE   (1<<6)      /* 'ABCDEF' */
47
 
48
#define is_digit(c) ((c) >= '0' && (c) <= '9')
49
 
50
/*
51
 Serial initialization and new line replacement is a direct copy from mbed_retarget.cpp
52
 If the static modifier were to be removed, this part of the code would not be necessary.
53
*/
54
//#include "hal/serial_api.h"
55
 
56
#if DEVICE_SERIAL
57
static serial_t stdio_uart = { 0 };
58
#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES
59
static char mbed_stdio_out_prev = 0;
60
#endif
61
#endif
62
 
63
/* module variable for keeping track of initialization */
64
static bool not_initialized = true;
65
 
66
static void init_serial()
67
{
68
    if (not_initialized)
69
    {
70
        not_initialized = false;
71
 
72
#if DEVICE_SERIAL
73
//      serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
74
#if MBED_CONF_PLATFORM_STDIO_BAUD_RATE
75
//      serial_baud(&stdio_uart, MBED_CONF_PLATFORM_STDIO_BAUD_RATE);
76
#endif
77
#endif
78
    }
79
}
80
 
81
#define MBED_INITIALIZE_PRINT(x) { init_serial(); }
82
#define MBED_PRINT_CHARACTER(x) { serial_putc(&stdio_uart, x); }
83
 
84
static char *lower_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
85
static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
86
 
87
static int ee_skip_atoi(const char **s)
88
{
89
  int i = 0;
90
  while (is_digit(**s)) i = i*10 + *((*s)++) - '0';
91
  return i;
92
}
93
 
94
static char *ee_number(char *str, long num, int base, int size, int precision, int type)
95
{
96
  char c, sign, tmp[66];
97
  char *dig = lower_digits;
98
  int i;
99
 
100
  if (type & UPPERCASE)  dig = upper_digits;
101
  if (type & LEFT) type &= ~ZEROPAD;
102
  if (base < 2 || base > 36) return 0;
103
 
104
  c = (type & ZEROPAD) ? '0' : ' ';
105
  sign = 0;
106
  if (type & SIGN)
107
  {
108
    if (num < 0)
109
    {
110
      sign = '-';
111
      num = -num;
112
      size--;
113
    }
114
    else if (type & PLUS)
115
    {
116
      sign = '+';
117
      size--;
118
    }
119
    else if (type & SPACE)
120
    {
121
      sign = ' ';
122
      size--;
123
    }
124
  }
125
 
126
  if (type & HEX_PREP)
127
  {
128
    if (base == 16)
129
      size -= 2;
130
    else if (base == 8)
131
      size--;
132
  }
133
 
134
  i = 0;
135
 
136
  if (num == 0)
137
    tmp[i++] = '0';
138
  else
139
  {
140
    while (num != 0)
141
    {
142
      tmp[i++] = dig[((unsigned long) num) % (unsigned) base];
143
      num = ((unsigned long) num) / (unsigned) base;
144
    }
145
  }
146
 
147
  if (i > precision) precision = i;
148
  size -= precision;
149
  if (!(type & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' ';
150
  if (sign) *str++ = sign;
151
 
152
  if (type & HEX_PREP)
153
  {
154
    if (base == 8)
155
      *str++ = '0';
156
    else if (base == 16)
157
    {
158
      *str++ = '0';
159
      *str++ = lower_digits[33];
160
    }
161
  }
162
 
163
  if (!(type & LEFT)) while (size-- > 0) *str++ = c;
164
  while (i < precision--) *str++ = '0';
165
  while (i-- > 0) *str++ = tmp[i];
166
  while (size-- > 0) *str++ = ' ';
167
 
168
  return str;
169
}
170
 
171
static char *eaddr(char *str, unsigned char *addr, int size, int precision, int type)
172
{
173
  char tmp[24];
174
  char *dig = lower_digits;
175
  int i, len;
176
 
177
  if (type & UPPERCASE)  dig = upper_digits;
178
  len = 0;
179
  for (i = 0; i < 6; i++)
180
  {
181
    if (i != 0) tmp[len++] = ':';
182
    tmp[len++] = dig[addr[i] >> 4];
183
    tmp[len++] = dig[addr[i] & 0x0F];
184
  }
185
 
186
  if (!(type & LEFT)) while (len < size--) *str++ = ' ';
187
  for (i = 0; i < len; ++i) *str++ = tmp[i];
188
  while (len < size--) *str++ = ' ';
189
 
190
  return str;
191
}
192
 
193
static char *iaddr(char *str, unsigned char *addr, int size, int precision, int type)
194
{
195
  char tmp[24];
196
  int i, n, len;
197
 
198
  len = 0;
199
  for (i = 0; i < 4; i++)
200
  {
201
    if (i != 0) tmp[len++] = '.';
202
    n = addr[i];
203
 
204
    if (n == 0)
205
      tmp[len++] = lower_digits[0];
206
    else
207
    {
208
      if (n >= 100)
209
      {
210
        tmp[len++] = lower_digits[n / 100];
211
        n = n % 100;
212
        tmp[len++] = lower_digits[n / 10];
213
        n = n % 10;
214
      }
215
      else if (n >= 10)
216
      {
217
        tmp[len++] = lower_digits[n / 10];
218
        n = n % 10;
219
      }
220
 
221
      tmp[len++] = lower_digits[n];
222
    }
223
  }
224
 
225
  if (!(type & LEFT)) while (len < size--) *str++ = ' ';
226
  for (i = 0; i < len; ++i) *str++ = tmp[i];
227
  while (len < size--) *str++ = ' ';
228
 
229
  return str;
230
}
231
 
232
#if defined(HAS_FLOAT) && HAS_FLOAT == 1
233
 
234
static void ee_bufcpy(char *d, char *s, int count);
235
 
236
void ee_bufcpy(char *pd, char *ps, int count) {
237
        char *pe=ps+count;
238
        while (ps!=pe)
239
                *pd++=*ps++;
240
}
241
 
242
static void parse_float(double value, char *buffer, char fmt, int precision)
243
{
244
  int decpt, sign, exp, pos;
245
  char *fdigits = NULL;
246
  char cvtbuf[80];
247
  int capexp = 0;
248
  int magnitude;
249
 
250
  if (fmt == 'G' || fmt == 'E')
251
  {
252
    capexp = 1;
253
    fmt += 'a' - 'A';
254
  }
255
 
256
  if (fmt == 'g')
257
  {
258
    fdigits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf);
259
    magnitude = decpt - 1;
260
    if (magnitude < -4  ||  magnitude > precision - 1)
261
    {
262
      fmt = 'e';
263
      precision -= 1;
264
    }
265
    else
266
    {
267
      fmt = 'f';
268
      precision -= decpt;
269
    }
270
  }
271
 
272
  if (fmt == 'e')
273
  {
274
    fdigits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf);
275
 
276
    if (sign) *buffer++ = '-';
277
    *buffer++ = *fdigits;
278
    if (precision > 0) *buffer++ = '.';
279
    ee_bufcpy(buffer, fdigits + 1, precision);
280
    buffer += precision;
281
    *buffer++ = capexp ? 'E' : 'e';
282
 
283
    if (decpt == 0)
284
    {
285
      if (value == 0.0)
286
        exp = 0;
287
      else
288
        exp = -1;
289
    }
290
    else
291
      exp = decpt - 1;
292
 
293
    if (exp < 0)
294
    {
295
      *buffer++ = '-';
296
      exp = -exp;
297
    }
298
    else
299
      *buffer++ = '+';
300
 
301
    buffer[2] = (exp % 10) + '0';
302
    exp = exp / 10;
303
    buffer[1] = (exp % 10) + '0';
304
    exp = exp / 10;
305
    buffer[0] = (exp % 10) + '0';
306
    buffer += 3;
307
  }
308
  else if (fmt == 'f')
309
  {
310
    fdigits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf);
311
    if (sign) *buffer++ = '-';
312
    if (*fdigits)
313
    {
314
      if (decpt <= 0)
315
      {
316
        *buffer++ = '0';
317
        *buffer++ = '.';
318
        for (pos = 0; pos < -decpt; pos++) *buffer++ = '0';
319
        while (*fdigits) *buffer++ = *fdigits++;
320
      }
321
      else
322
      {
323
        pos = 0;
324
        while (*fdigits)
325
        {
326
          if (pos++ == decpt) *buffer++ = '.';
327
          *buffer++ = *fdigits++;
328
        }
329
      }
330
    }
331
    else
332
    {
333
      *buffer++ = '0';
334
      if (precision > 0)
335
      {
336
        *buffer++ = '.';
337
        for (pos = 0; pos < precision; pos++) *buffer++ = '0';
338
      }
339
    }
340
  }
341
 
342
  *buffer = '\0';
343
}
344
 
345
static void decimal_point(char *buffer)
346
{
347
  while (*buffer)
348
  {
349
    if (*buffer == '.') return;
350
    if (*buffer == 'e' || *buffer == 'E') break;
351
    buffer++;
352
  }
353
 
354
  if (*buffer)
355
  {
356
    int n = strnlen(buffer,256);
357
    while (n > 0)
358
    {
359
      buffer[n + 1] = buffer[n];
360
      n--;
361
    }
362
 
363
    *buffer = '.';
364
  }
365
  else
366
  {
367
    *buffer++ = '.';
368
    *buffer = '\0';
369
  }
370
}
371
 
372
static void cropzeros(char *buffer)
373
{
374
  char *stop;
375
 
376
  while (*buffer && *buffer != '.') buffer++;
377
  if (*buffer++)
378
  {
379
    while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++;
380
    stop = buffer--;
381
    while (*buffer == '0') buffer--;
382
    if (*buffer == '.') buffer--;
383
    while (buffer!=stop)
384
                *++buffer=0;
385
  }
386
}
387
 
388
static char *flt(char *str, double num, int size, int precision, char fmt, int flags)
389
{
390
  char tmp[80];
391
  char c, sign;
392
  int n, i;
393
 
394
  // Left align means no zero padding
395
  if (flags & LEFT) flags &= ~ZEROPAD;
396
 
397
  // Determine padding and sign char
398
  c = (flags & ZEROPAD) ? '0' : ' ';
399
  sign = 0;
400
  if (flags & SIGN)
401
  {
402
    if (num < 0.0)
403
    {
404
      sign = '-';
405
      num = -num;
406
      size--;
407
    }
408
    else if (flags & PLUS)
409
    {
410
      sign = '+';
411
      size--;
412
    }
413
    else if (flags & SPACE)
414
    {
415
      sign = ' ';
416
      size--;
417
    }
418
  }
419
 
420
  // Compute the precision value
421
  if (precision < 0)
422
    precision = 6; // Default precision: 6
423
 
424
  // Convert floating point number to text
425
  parse_float(num, tmp, fmt, precision);
426
 
427
  if ((flags & HEX_PREP) && precision == 0) decimal_point(tmp);
428
  if (fmt == 'g' && !(flags & HEX_PREP)) cropzeros(tmp);
429
 
430
  n = strnlen(tmp,256);
431
 
432
  // Output number with alignment and padding
433
  size -= n;
434
  if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' ';
435
  if (sign) *str++ = sign;
436
  if (!(flags & LEFT)) while (size-- > 0) *str++ = c;
437
  for (i = 0; i < n; i++) *str++ = tmp[i];
438
  while (size-- > 0) *str++ = ' ';
439
 
440
  return str;
441
}
442
 
443
#endif
444
 
445
static int ee_vsprintf(char *buf, const char *fmt, va_list args)
446
{
447
  int len;
448
  unsigned long num;
449
  int i, base;
450
  char *str;
451
  char *s;
452
 
453
  int flags;            // Flags to number()
454
 
455
  int field_width;      // Width of output field
456
  int precision;        // Min. # of digits for integers; max number of chars for from string
457
  int qualifier;        // 'h', 'l', or 'L' for integer fields
458
 
459
  for (str = buf; *fmt; fmt++)
460
  {
461
    if (*fmt != '%')
462
    {
463
      *str++ = *fmt;
464
      continue;
465
    }
466
 
467
    // Process flags
468
    flags = 0;
469
repeat:
470
    fmt++; // This also skips first '%'
471
    switch (*fmt)
472
    {
473
      case '-': flags |= LEFT; goto repeat;
474
      case '+': flags |= PLUS; goto repeat;
475
      case ' ': flags |= SPACE; goto repeat;
476
      case '#': flags |= HEX_PREP; goto repeat;
477
      case '0': flags |= ZEROPAD; goto repeat;
478
    }
479
 
480
    // Get field width
481
    field_width = -1;
482
    if (is_digit(*fmt))
483
      field_width = ee_skip_atoi(&fmt);
484
    else if (*fmt == '*')
485
    {
486
      fmt++;
487
      field_width = va_arg(args, int);
488
      if (field_width < 0)
489
      {
490
        field_width = -field_width;
491
        flags |= LEFT;
492
      }
493
    }
494
 
495
    // Get the precision
496
    precision = -1;
497
    if (*fmt == '.')
498
    {
499
      ++fmt;
500
      if (is_digit(*fmt))
501
        precision = ee_skip_atoi(&fmt);
502
      else if (*fmt == '*')
503
      {
504
        ++fmt;
505
        precision = va_arg(args, int);
506
      }
507
      if (precision < 0) precision = 0;
508
    }
509
 
510
    // Get the conversion qualifier
511
    qualifier = -1;
512
    if (*fmt == 'l' || *fmt == 'L')
513
    {
514
      qualifier = *fmt;
515
      fmt++;
516
    }
517
 
518
    // Default base
519
    base = 10;
520
 
521
    switch (*fmt)
522
    {
523
      case 'c':
524
        if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' ';
525
        *str++ = (unsigned char) va_arg(args, int);
526
        while (--field_width > 0) *str++ = ' ';
527
        continue;
528
 
529
      case 's':
530
        s = va_arg(args, char *);
531
        if (!s) s = "<NULL>";
532
        len = strnlen(s, precision);
533
        if (!(flags & LEFT)) while (len < field_width--) *str++ = ' ';
534
        for (i = 0; i < len; ++i) *str++ = *s++;
535
        while (len < field_width--) *str++ = ' ';
536
        continue;
537
 
538
      case 'p':
539
        if (field_width == -1)
540
        {
541
          field_width = 2 * sizeof(void *);
542
          flags |= ZEROPAD;
543
        }
544
        str = ee_number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags);
545
        continue;
546
 
547
      case 'A':
548
        flags |= UPPERCASE;
549
 
550
      case 'a':
551
        if (qualifier == 'l')
552
          str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
553
        else
554
          str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
555
        continue;
556
 
557
      // Integer number formats - set up the flags and "break"
558
      case 'o':
559
        base = 8;
560
        break;
561
 
562
      case 'X':
563
        flags |= UPPERCASE;
564
 
565
      case 'x':
566
        base = 16;
567
        break;
568
 
569
      case 'd':
570
      case 'i':
571
        flags |= SIGN;
572
 
573
      case 'u':
574
        break;
575
 
576
#if defined(HAS_FLOAT) && HAS_FLOAT == 1
577
 
578
      case 'f':
579
        str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN);
580
        continue;
581
 
582
#endif
583
 
584
      default:
585
        if (*fmt != '%') *str++ = '%';
586
        if (*fmt)
587
          *str++ = *fmt;
588
        else
589
          --fmt;
590
        continue;
591
    }
592
 
593
    if (qualifier == 'l')
594
      num = va_arg(args, unsigned long);
595
    else if (flags & SIGN)
596
      num = va_arg(args, int);
597
    else
598
      num = va_arg(args, unsigned int);
599
 
600
    str = ee_number(str, num, base, field_width, precision, flags);
601
  }
602
 
603
  *str = '\0';
604
  return str - buf;
605
}
606
 
607
void uart_send_char(char c) {
608
  // this is Mbed OS putc to standard uart
609
  //MBED_PRINT_CHARACTER(c);
610
  if (c == '\n')
611
    neorv32_uart_putc('\r');
612
  neorv32_uart_putc(c);
613
}
614
 
615
int ee_printf(const char *fmt, ...)
616
{
617
  MBED_INITIALIZE_PRINT();
618
 
619
  char buf[15*80],*p;
620
  va_list args;
621
  int n=0;
622
 
623
  va_start(args, fmt);
624
  ee_vsprintf(buf, fmt, args);
625
  va_end(args);
626
  p=buf;
627
  while (*p) {
628
        uart_send_char(*p);
629
        n++;
630
        p++;
631
  }
632
 
633
  return n;
634
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.