printf.c revision 8024:27ce7490bd3b
1/*
2 * Copyright (c) 2003, 2004
3 * The Regents of The University of Michigan
4 * All Rights Reserved
5 *
6 * This code is part of the M5 simulator, developed by Nathan Binkert,
7 * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions
8 * from Ron Dreslinski, Dave Greene, Lisa Hsu, Ali Saidi, and Andrew
9 * Schultz.
10 *
11 * Permission is granted to use, copy, create derivative works and
12 * redistribute this software and such derivative works for any purpose,
13 * so long as the copyright notice above, this grant of permission, and
14 * the disclaimer below appear in all copies made; and so long as the
15 * name of The University of Michigan is not used in any advertising or
16 * publicity pertaining to the use or distribution of this software
17 * without specific, written prior authorization.
18 *
19 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
20 * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT
21 * WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR
22 * IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF
24 * THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE FOR ANY DAMAGES,
25 * INCLUDING DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
26 * DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN CONNECTION
27 * WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
29 */
30
31/*
32 * Copyright 1993 Hewlett-Packard Development Company, L.P.
33 *
34 * Permission is hereby granted, free of charge, to any person
35 * obtaining a copy of this software and associated documentation
36 * files (the "Software"), to deal in the Software without
37 * restriction, including without limitation the rights to use, copy,
38 * modify, merge, publish, distribute, sublicense, and/or sell copies
39 * of the Software, and to permit persons to whom the Software is
40 * furnished to do so, subject to the following conditions:
41 *
42 * The above copyright notice and this permission notice shall be
43 * included in all copies or substantial portions of the Software.
44 *
45 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
49 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
50 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
51 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
52 * SOFTWARE.
53 */
54
55#include <sys/types.h>
56#include <stdarg.h>
57#include <stdint.h>
58#include "m5op.h"
59
60/* The string s is terminated by a '\0' */
61void
62PutString(const char *s)
63{
64    while (*s)
65        PutChar(*s++);
66}
67
68/* print c count times */
69void
70PutRepChar(char c, int count)
71{
72    while (count--)
73        PutChar(c);
74}
75
76/* put string reverse */
77void
78PutStringReverse(const char *s, int index)
79{
80    while (index-- > 0)
81        PutChar(s[index]);
82}
83
84/*
85 * prints value in radix, in a field width width, with fill
86 * character fill
87 * if radix is negative, print as signed quantity
88 * if width is negative, left justify
89 * if width is 0, use whatever is needed
90 * if fill is 0, use ' '
91 */
92void
93PutNumber(long value, int radix, int width, char fill)
94{
95    char buffer[40];
96    uint bufferindex = 0;
97    ulong uvalue;
98    ushort digit;
99    ushort left = 0;
100    ushort negative = 0;
101
102    if (fill == 0)
103        fill = ' ';
104
105    if (width < 0) {
106        width = -width;
107        left = 1;
108    }
109
110    if (width < 0 || width > 80)
111        width = 0;
112
113    if (radix < 0) {
114        radix = -radix;
115        if (value < 0) {
116            negative = 1;
117            value = -value;
118        }
119    }
120
121    switch (radix) {
122      case 8:
123      case 10:
124      case 16:
125        break;
126
127      default:
128        PutString("****");
129        return;
130    }
131
132    uvalue = value;
133
134    do {
135        if (radix != 16) {
136            digit = (ushort)(uvalue % radix);
137            uvalue /= radix;
138        } else {
139            digit = (ushort)(uvalue & 0xf);
140            uvalue = uvalue >> 4;
141        }
142        buffer[bufferindex] = digit + ((digit <= 9) ? '0' : ('A' - 10));
143        bufferindex += 1;
144    } while (uvalue != 0);
145
146  /* fill # ' ' and negative cannot happen at once */
147    if (negative) {
148        buffer[bufferindex] = '-';
149        bufferindex += 1;
150    }
151
152    if ((uint)width <= bufferindex) {
153        PutStringReverse(buffer, bufferindex);
154    } else {
155        width -= bufferindex;
156        if (!left)
157            PutRepChar(fill, width);
158        PutStringReverse(buffer, bufferindex);
159        if (left)
160            PutRepChar(fill, width);
161    }
162}
163
164ulong
165power(long base, long n)
166{
167    ulong p;
168
169    for (p = 1; n > 0; --n)
170        p = p * base;
171    return p;
172}
173
174void
175putFloat(double a, int fieldwidth, char fill)
176{
177    int i;
178    ulong b;
179
180    /*
181     *  Put out everything before the decimal place.
182     */
183    PutNumber(((ulong) a), 10, fieldwidth, fill);
184
185    /*
186     *  Output the decimal place.
187     */
188    PutChar('.' & 0x7f);
189
190    /*
191     *  Output the n digits after the decimal place.
192     */
193    for (i = 1; i < 6; i++) {
194        b = (ulong)(power(10, i) * (double)(a - (ulong) a));
195        PutChar((char)(b % 10) + '0');
196    }
197}
198
199const char *
200FormatItem(const char *f, va_list *ap)
201{
202    char c;
203    int fieldwidth = 0;
204    int leftjust = 0;
205    int radix = 0;
206    char fill = ' ';
207
208    if (*f == '0')
209        fill = '0';
210
211    while (c = *f++) {
212        if (c >= '0' && c <= '9') {
213            fieldwidth = (fieldwidth * 10) + (c - '0');
214        } else {
215            switch (c) {
216              case '\000':
217                return(--f);
218              case '%':
219                PutChar('%');
220                return(f);
221              case '-':
222                leftjust = 1;
223                break;
224              case 'c': {
225                  char a = (char)va_arg(*ap, int);
226
227                  if (leftjust)
228                      PutChar(a & 0x7f);
229                  if (fieldwidth > 0)
230                      PutRepChar(fill, fieldwidth - 1);
231                  if (!leftjust)
232                      PutChar(a & 0x7f);
233                  return(f);
234              }
235              case 's': {
236                  const char *a = va_arg(*ap, const char *);
237
238                  if (leftjust)
239                      PutString((const char *) a);
240                  if (fieldwidth > strlen((const char *) a))
241                      PutRepChar(fill, fieldwidth - strlen((const char *)a));
242                  if (!leftjust)
243                      PutString((const char *) a);
244                  return(f);
245              }
246              case 'd':
247                radix = -10;
248                break;
249              case 'u':
250                radix = 10;
251                break;
252              case 'x':
253                radix = 16;
254                break;
255              case 'X':
256                radix = 16;
257                break;
258              case 'o':
259                radix = 8;
260                break;
261              case 'f': {
262                  double a = va_arg(*ap, double);
263
264                  putFloat(a, fieldwidth, fill);
265                  return(f);
266              }
267              default:   /* unknown switch! */
268                radix = 3;
269                break;
270            }
271        }
272
273        if (radix)
274            break;
275    }
276
277    if (leftjust)
278        fieldwidth = -fieldwidth;
279
280    long a = va_arg(*ap, long);
281    PutNumber(a, radix, fieldwidth, fill);
282
283    return(f);
284}
285
286int
287printf(const char *f, ...)
288{
289    va_list ap;
290
291    va_start(ap, f);
292
293    while (*f) {
294        if (*f == '%')
295            f = FormatItem(f + 1, &ap);
296        else
297            PutChar(*f++);
298    }
299
300    if (*(f - 1) == '\n') {
301        /* add a line-feed (SimOS console output goes to shell */
302        PutChar('\r');
303    }
304
305    va_end(ap);         /* clean up */
306    return 0;
307}
308
309void
310panic(const char *f, ...)
311{
312    va_list ap;
313
314    va_start(ap, f);
315
316    printf("CONSOLE PANIC (looping): ");
317    while (*f) {
318        if (*f == '%')
319            f = FormatItem(f + 1, &ap);
320        else
321            PutChar(*f++);
322    }
323
324    va_end(ap);         /* clean up */
325    m5_panic();
326}
327