Paul Pan
7b33e4213a
1. add test soft 2. modify verilator (TODO: crossbar need to replace) 3. fix CP0: now CU0 is always 1 4. Controller: cacheop 5. Controller: fix TEN 6. mycpu_top fix CP0_i 7. fix AXI.sv 8. fix AXIReader.sv 9. fix AXIWriter.sv: getting the correct data and length 10. MU: fix cache writeback, fix mem data mux, fix writer address, fix read request
519 lines
12 KiB
C
519 lines
12 KiB
C
#ifdef FLOATINGPT
|
||
#define MAX_FCONVERSION 512 /* largest possible real conversion */
|
||
#define MAX_EXPT 5 /* largest possible exponent field */
|
||
#define MAX_FRACT 39 /* largest possible fraction field */
|
||
|
||
#define TESTFLAG(x) 0
|
||
|
||
|
||
|
||
typedef double rtype;
|
||
extern double modf(double, double *);
|
||
|
||
static void dtoa (char *dbuf, rtype arg, int fmtch, int width, int prec);
|
||
#endif
|
||
/*
|
||
* int vsprintf(d,s,ap)
|
||
*/
|
||
int
|
||
vsprintf (char *d, const char *s, va_list ap)
|
||
{
|
||
const char *t;
|
||
char *p, *dst, tmp[40];
|
||
unsigned int n;
|
||
int fmt, trunc, haddot, width, base, longlong;
|
||
#ifdef FLOATINGPT
|
||
double dbl;
|
||
|
||
#endif
|
||
|
||
dst = d;
|
||
for (; *s;) {
|
||
if (*s == '%') {
|
||
s++;
|
||
fmt = FMT_RJUST;
|
||
width = trunc = haddot = longlong = 0;
|
||
for (; *s; s++) {
|
||
if (strchr ("dobpxXulscefg%", *s))
|
||
break;
|
||
else if (*s == '-')
|
||
fmt = FMT_LJUST;
|
||
else if (*s == '0')
|
||
fmt = FMT_RJUST0;
|
||
else if (*s == '~')
|
||
fmt = FMT_CENTER;
|
||
else if (*s == '*') {
|
||
if (haddot)
|
||
trunc = va_arg (ap, int);
|
||
else
|
||
width = va_arg (ap, int);
|
||
} else if (*s >= '1' && *s <= '9') {
|
||
for (t = s; isdigit (*s); s++);
|
||
strncpy (tmp, t, s - t);
|
||
tmp[s - t] = '\0';
|
||
atob (&n, tmp, 10);
|
||
if (haddot)
|
||
trunc = n;
|
||
else
|
||
width = n;
|
||
s--;
|
||
} else if (*s == '.')
|
||
haddot = 1;
|
||
}
|
||
if (*s == '%') {
|
||
*d++ = '%';
|
||
*d = 0;
|
||
} else if (*s == 's') {
|
||
p = va_arg (ap, char *);
|
||
|
||
if (p)
|
||
strcpy (d, p);
|
||
else
|
||
strcpy (d, "(null)");
|
||
} else if (*s == 'c') {
|
||
n = va_arg (ap, int);
|
||
*d = n;
|
||
d[1] = 0;
|
||
} else {
|
||
if (*s == 'l') {
|
||
if (*++s == 'l') {
|
||
longlong = 1;
|
||
++s;
|
||
}
|
||
}
|
||
if (strchr ("dobpxXu", *s)) {
|
||
if (*s == 'd')
|
||
base = -10;
|
||
else if (*s == 'u')
|
||
base = 10;
|
||
else if (*s == 'x' || *s == 'X')
|
||
base = 16;
|
||
else if(*s == 'p') {
|
||
base = 16;
|
||
*d++ = '0';
|
||
*d++ = 'x';
|
||
fmt = FMT_RJUST0;
|
||
width = 8;
|
||
}
|
||
else if (*s == 'o')
|
||
base = 8;
|
||
else if (*s == 'b')
|
||
base = 2;
|
||
#ifdef HAVE_QUAD
|
||
if (longlong)
|
||
llbtoa(d, va_arg (ap, quad_t),
|
||
base);
|
||
#else
|
||
if (longlong)
|
||
{
|
||
long x=va_arg (ap, long long);
|
||
btoa(d, (long)x,
|
||
base);
|
||
}
|
||
|
||
#endif
|
||
else
|
||
btoa(d, va_arg (ap, int), base);
|
||
|
||
if (*s == 'X')
|
||
strtoupper(d);
|
||
}
|
||
#ifdef FLOATINGPT
|
||
else if (strchr ("eEfgG", *s)) {
|
||
dbl = va_arg(ap, double);
|
||
dtoa (d, dbl, *s, width, trunc);
|
||
trunc = 0;
|
||
}
|
||
#endif
|
||
}
|
||
if (trunc)
|
||
d[trunc] = 0;
|
||
if (width)
|
||
str_fmt (d, width, fmt);
|
||
for (; *d; d++);
|
||
s++;
|
||
} else
|
||
*d++ = *s++;
|
||
}
|
||
*d = 0;
|
||
return (d - dst);
|
||
}
|
||
|
||
#ifdef FLOATINGPT
|
||
/*
|
||
* Floating point output, cvt() onward lifted from BSD sources:
|
||
*
|
||
* Copyright (c) 1990 The Regents of the University of California.
|
||
* All rights reserved.
|
||
*
|
||
* This code is derived from software contributed to Berkeley by
|
||
* Chris Torek.
|
||
*
|
||
* Redistribution and use in source and binary forms, with or without
|
||
* modification, are permitted provided that the following conditions
|
||
* are met:
|
||
* 1. Redistributions of source code must retain the above copyright
|
||
* notice, this list of conditions and the following disclaimer.
|
||
* 2. Redistributions in binary form must reproduce the above copyright
|
||
* notice, this list of conditions and the following disclaimer in the
|
||
* documentation and/or other materials provided with the distribution.
|
||
* 3. All advertising materials mentioning features or use of this software
|
||
* must display the following acknowledgement:
|
||
* This product includes software developed by the University of
|
||
* California, Berkeley and its contributors.
|
||
* 4. Neither the name of the University nor the names of its contributors
|
||
* may be used to endorse or promote products derived from this software
|
||
* without specific prior written permission.
|
||
*
|
||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
* SUCH DAMAGE.
|
||
*/
|
||
|
||
|
||
#define to_char(n) ((n) + '0')
|
||
#define to_digit(c) ((c) - '0')
|
||
#define _isNan(arg) ((arg) != (arg))
|
||
|
||
static int cvt (rtype arg, int prec, char *signp, int fmtch,
|
||
char *startp, char *endp);
|
||
static char *round (double fract, int *exp, char *start, char *end,
|
||
char ch, char *signp);
|
||
static char *exponent(char *p, int exp, int fmtch);
|
||
|
||
|
||
/*
|
||
* _finite arg not Infinity or Nan
|
||
*/
|
||
static int _finite(rtype d)
|
||
{
|
||
#if ENDIAN == ENDIAN_LITTLE
|
||
struct IEEEdp {
|
||
unsigned manl:32;
|
||
unsigned manh:20;
|
||
unsigned exp:11;
|
||
unsigned sign:1;
|
||
} *ip;
|
||
#else
|
||
struct IEEEdp {
|
||
unsigned sign:1;
|
||
unsigned exp:11;
|
||
unsigned manh:20;
|
||
unsigned manl:32;
|
||
} *ip;
|
||
#endif
|
||
|
||
ip = (struct IEEEdp *)&d;
|
||
return (ip->exp != 0x7ff);
|
||
}
|
||
|
||
|
||
static void dtoa (char *dbuf, rtype arg, int fmtch, int width, int prec)
|
||
{
|
||
char buf[MAX_FCONVERSION+1], *cp;
|
||
char sign;
|
||
int size;
|
||
|
||
if( !_finite(arg) ) {
|
||
if( _isNan(arg) )
|
||
strcpy (dbuf, "NaN");
|
||
else if( arg < 0)
|
||
strcpy (dbuf, "-Infinity");
|
||
else
|
||
strcpy (dbuf, "Infinity");
|
||
return;
|
||
}
|
||
|
||
if (prec == 0)
|
||
prec = 6;
|
||
else if (prec > MAX_FRACT)
|
||
prec = MAX_FRACT;
|
||
|
||
/* leave room for sign at start of buffer */
|
||
cp = buf + 1;
|
||
|
||
/*
|
||
* cvt may have to round up before the "start" of
|
||
* its buffer, i.e. ``intf("%.2f", (double)9.999);'';
|
||
* if the first character is still NUL, it did.
|
||
* softsign avoids negative 0 if _double < 0 but
|
||
* no significant digits will be shown.
|
||
*/
|
||
*cp = '\0';
|
||
size = cvt (arg, prec, &sign, fmtch, cp, buf + sizeof(buf));
|
||
if (*cp == '\0')
|
||
cp++;
|
||
|
||
if (sign)
|
||
*--cp = sign, size++;
|
||
|
||
cp[size] = 0;
|
||
memcpy (dbuf, cp, size + 1);
|
||
}
|
||
|
||
|
||
static int
|
||
cvt(rtype number, int prec, char *signp, int fmtch, char *startp, char *endp)
|
||
{
|
||
register char *p, *t;
|
||
register double fract;
|
||
double integer, tmp;
|
||
int dotrim, expcnt, gformat;
|
||
|
||
dotrim = expcnt = gformat = 0;
|
||
if (number < 0) {
|
||
number = -number;
|
||
*signp = '-';
|
||
} else
|
||
*signp = 0;
|
||
|
||
fract = modf(number, &integer);
|
||
|
||
/* get an extra slot for rounding. */
|
||
t = ++startp;
|
||
|
||
/*
|
||
* get integer portion of number; put into the end of the buffer; the
|
||
* .01 is added for modf(356.0 / 10, &integer) returning .59999999...
|
||
*/
|
||
for (p = endp - 1; integer; ++expcnt) {
|
||
tmp = modf(integer / 10, &integer);
|
||
*p-- = to_char((int)((tmp + .01) * 10));
|
||
}
|
||
switch (fmtch) {
|
||
case 'f':
|
||
/* reverse integer into beginning of buffer */
|
||
if (expcnt)
|
||
for (; ++p < endp; *t++ = *p);
|
||
else
|
||
*t++ = '0';
|
||
/*
|
||
* if precision required or alternate flag set, add in a
|
||
* decimal point.
|
||
*/
|
||
if (prec || TESTFLAG(ALTERNATE_FORM))
|
||
*t++ = '.';
|
||
/* if requires more precision and some fraction left */
|
||
if (fract) {
|
||
if (prec)
|
||
do {
|
||
fract = modf(fract * 10, &tmp);
|
||
*t++ = to_char((int)tmp);
|
||
} while (--prec && fract);
|
||
if (fract)
|
||
startp = round(fract, (int *)NULL, startp,
|
||
t - 1, (char)0, signp);
|
||
}
|
||
for (; prec--; *t++ = '0');
|
||
break;
|
||
case 'e':
|
||
case 'E':
|
||
eformat: if (expcnt) {
|
||
*t++ = *++p;
|
||
if (prec || TESTFLAG(ALTERNATE_FORM))
|
||
*t++ = '.';
|
||
/* if requires more precision and some integer left */
|
||
for (; prec && ++p < endp; --prec)
|
||
*t++ = *p;
|
||
/*
|
||
* if done precision and more of the integer component,
|
||
* round using it; adjust fract so we don't re-round
|
||
* later.
|
||
*/
|
||
if (!prec && ++p < endp) {
|
||
fract = 0;
|
||
startp = round((double)0, &expcnt, startp,
|
||
t - 1, *p, signp);
|
||
}
|
||
/* adjust expcnt for digit in front of decimal */
|
||
--expcnt;
|
||
}
|
||
/* until first fractional digit, decrement exponent */
|
||
else if (fract) {
|
||
/* adjust expcnt for digit in front of decimal */
|
||
for (expcnt = -1;; --expcnt) {
|
||
fract = modf(fract * 10, &tmp);
|
||
if (tmp)
|
||
break;
|
||
}
|
||
*t++ = to_char((int)tmp);
|
||
if (prec || TESTFLAG(ALTERNATE_FORM))
|
||
*t++ = '.';
|
||
}
|
||
else {
|
||
*t++ = '0';
|
||
if (prec || TESTFLAG(ALTERNATE_FORM))
|
||
*t++ = '.';
|
||
}
|
||
/* if requires more precision and some fraction left */
|
||
if (fract) {
|
||
if (prec)
|
||
do {
|
||
fract = modf(fract * 10, &tmp);
|
||
*t++ = to_char((int)tmp);
|
||
} while (--prec && fract);
|
||
if (fract)
|
||
startp = round(fract, &expcnt, startp,
|
||
t - 1, (char)0, signp);
|
||
}
|
||
/* if requires more precision */
|
||
for (; prec--; *t++ = '0');
|
||
|
||
/* unless alternate flag, trim any g/G format trailing 0's */
|
||
if (gformat && !TESTFLAG(ALTERNATE_FORM)) {
|
||
while (t > startp && *--t == '0');
|
||
if (*t == '.')
|
||
--t;
|
||
++t;
|
||
}
|
||
t = exponent(t, expcnt, fmtch);
|
||
break;
|
||
case 'g':
|
||
case 'G':
|
||
/* a precision of 0 is treated as a precision of 1. */
|
||
if (!prec)
|
||
++prec;
|
||
/*
|
||
* ``The style used depends on the value converted; style e
|
||
* will be used only if the exponent resulting from the
|
||
* conversion is less than -4 or greater than the precision.''
|
||
* -- ANSI X3J11
|
||
*/
|
||
if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
|
||
/*
|
||
* g/G format counts "significant digits, not digits of
|
||
* precision; for the e/E format, this just causes an
|
||
* off-by-one problem, i.e. g/G considers the digit
|
||
* before the decimal point significant and e/E doesn't
|
||
* count it as precision.
|
||
*/
|
||
--prec;
|
||
fmtch -= 2; /* G->E, g->e */
|
||
gformat = 1;
|
||
goto eformat;
|
||
}
|
||
/*
|
||
* reverse integer into beginning of buffer,
|
||
* note, decrement precision
|
||
*/
|
||
if (expcnt)
|
||
for (; ++p < endp; *t++ = *p, --prec);
|
||
else
|
||
*t++ = '0';
|
||
/*
|
||
* if precision required or alternate flag set, add in a
|
||
* decimal point. If no digits yet, add in leading 0.
|
||
*/
|
||
if (prec || TESTFLAG(ALTERNATE_FORM)) {
|
||
dotrim = 1;
|
||
*t++ = '.';
|
||
}
|
||
else
|
||
dotrim = 0;
|
||
/* if requires more precision and some fraction left */
|
||
if (fract) {
|
||
if (prec) {
|
||
do {
|
||
fract = modf(fract * 10, &tmp);
|
||
*t++ = to_char((int)tmp);
|
||
} while(!tmp && !expcnt);
|
||
while (--prec && fract) {
|
||
fract = modf(fract * 10, &tmp);
|
||
*t++ = to_char((int)tmp);
|
||
}
|
||
}
|
||
if (fract)
|
||
startp = round(fract, (int *)NULL, startp,
|
||
t - 1, (char)0, signp);
|
||
}
|
||
/* alternate format, adds 0's for precision, else trim 0's */
|
||
if (TESTFLAG(ALTERNATE_FORM))
|
||
for (; prec--; *t++ = '0');
|
||
else if (dotrim) {
|
||
while (t > startp && *--t == '0');
|
||
if (*t != '.')
|
||
++t;
|
||
}
|
||
}
|
||
return (t - startp);
|
||
}
|
||
|
||
|
||
static char *
|
||
round(double fract, int *exp, char *start, char *end, char ch, char *signp)
|
||
{
|
||
double tmp;
|
||
|
||
if (fract)
|
||
(void)modf(fract * 10, &tmp);
|
||
else
|
||
tmp = to_digit(ch);
|
||
if (tmp > 4)
|
||
for (;; --end) {
|
||
if (*end == '.')
|
||
--end;
|
||
if (++*end <= '9')
|
||
break;
|
||
*end = '0';
|
||
if (end == start) {
|
||
if (exp) { /* e/E; increment exponent */
|
||
*end = '1';
|
||
++*exp;
|
||
}
|
||
else { /* f; add extra digit */
|
||
*--end = '1';
|
||
--start;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
/* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
|
||
else if (*signp == '-')
|
||
for (;; --end) {
|
||
if (*end == '.')
|
||
--end;
|
||
if (*end != '0')
|
||
break;
|
||
if (end == start)
|
||
*signp = 0;
|
||
}
|
||
return (start);
|
||
}
|
||
|
||
static char *
|
||
exponent(char *p, int exp, int fmtch)
|
||
{
|
||
char *t;
|
||
char expbuf[MAX_FCONVERSION];
|
||
|
||
*p++ = fmtch;
|
||
if (exp < 0) {
|
||
exp = -exp;
|
||
*p++ = '-';
|
||
}
|
||
else
|
||
*p++ = '+';
|
||
t = expbuf + MAX_FCONVERSION;
|
||
if (exp > 9) {
|
||
do {
|
||
*--t = to_char(exp % 10);
|
||
} while ((exp /= 10) > 9);
|
||
*--t = to_char(exp);
|
||
for (; t < expbuf + MAX_FCONVERSION; *p++ = *t++);
|
||
}
|
||
else {
|
||
*p++ = '0';
|
||
*p++ = to_char(exp);
|
||
}
|
||
return (p);
|
||
}
|
||
#endif /* FLOATINGPT */
|