#include "amode.h"
#include "error.h"
#include "expr.h"
+#include "fltpoint.h"
#include "listing.h"
#include "mach.h"
#include "macro.h"
#include "sect.h"
#include "symbol.h"
#include "token.h"
-#include "math.h"
-#include "sect.h"
#define DEF_KW
#include "kwtab.h"
D_quad(eval);
break;
case SIZS:
+ // 32-bit float size
if (m6502)
return error(in_6502mode);
if (!defined)
{
- float vv = 0;
AddFixup(FU_FLOATSING, sloc, exprbuf);
-
- D_single(vv);
+ D_long(0);
}
else
{
if (tdb)
MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
- D_single(eval);
+ PTR ptr;
+ ptr.u64 = &eval;
+ uint32_t ieee754 = FloatToIEEE754((float)*ptr.dp);
+ D_long(ieee754);
}
break;
case SIZD:
+ // 64-bit double size
if (m6502)
return error(in_6502mode);
if (!defined)
{
- double vv = 0;
AddFixup(FU_FLOATDOUB, sloc, exprbuf);
-
- D_double(vv);
+ D_quad(0LL);
}
else
{
if (tdb)
MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
- double vv = *(double *)&eval;
- D_double(vv);
+ PTR ptr;
+ ptr.u64 = &eval;
+ uint64_t ieee754 = DoubleToIEEE754(*ptr.dp);
+ D_quad(ieee754);
}
break;
if (m6502)
return error(in_6502mode);
+ uint8_t extDbl[12];
+ memset(extDbl, 0, 12);
+
if (!defined)
{
- double vv = 0;
AddFixup(FU_FLOATEXT, sloc, exprbuf);
-
- D_extend(vv);
+ D_extend(extDbl);
}
else
{
if (tdb)
MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
- float vv = *(double *)&eval;
- D_extend(vv);
+ PTR ptr;
+ ptr.u64 = &eval;
+ DoubleToExtended(*ptr.dp, extDbl);
+ D_extend(extDbl);
}
break;
#include "eagen.h"
#include "amode.h"
-#include "sect.h"
-#include "mark.h"
#include "error.h"
+#include "fltpoint.h"
#include "mach.h"
+#include "mark.h"
#include "riscasm.h"
#include "sect.h"
#include "token.h"
vbd = (uint32_t)aNbdexval;
wbd = (WORD)(aNbdexattr & DEFINED);
tdbbd = (WORD)(aNbdexattr & TDB);
+ uint8_t extDbl[12];
switch (amN)
{
// 68881/68882/68040 only
if (w)
{
- float vv;
if (tdb)
MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
- vv = (float)v;
-
- D_single(vv);
+ // The value passed back from expr() is an internal C double;
+ // so we have to access it as such then convert it to an
+ // IEEE-754 float so we can store it as such in the instruction
+ // stream here.
+ PTR p;
+ p.u64 = &aNexval;
+ float f = (float)*p.dp;
+ uint32_t ieee754 = FloatToIEEE754(f);
+ D_long(ieee754);
}
else
{
- float vv = 0;
AddFixup(FU_FLOATSING, sloc, aNexpr);
-
- D_single(vv);
+ D_long(0); // IEEE-754 zero is all zeroes
}
break;
// 68881/68882/68040 only
if (w)
{
- double vv;
- unsigned long long vvv;
if (tdb)
MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
- // We want to store the IEE754 float into ram from a generic
- // 32-bit int. First, convert it to double float, then cast
- // that to 64-bit, then convert to big endian (if needed)
- // and then store it (phew!)
- vv = *(float *)&aNexval;
- vvv = BYTESWAP64(*(unsigned long long *)&vv);
-
- D_double(vvv);
+ PTR p;
+ p.u64 = &aNexval;
+ double d = *p.dp;
+ uint64_t ieee754 = DoubleToIEEE754(d);
+ D_quad(ieee754);
}
else
{
- unsigned long long vvv = 0;
AddFixup(FU_FLOATDOUB, sloc, aNexpr);
-
- D_double(vvv);
+ D_quad(0LL); // IEEE-754 zero is all zeroes
}
break;
// 68881/68882/68040 only
if (w)
{
- long double vv;
if (tdb)
MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
- // We want to store the IEE754 float into ram from a generic
- // 32-bit int. First, convert it to double float, then cast
- // that to 96-bit, then convert to big endian (if needed)
- // and then store it (phew!)
- vv = (double)aNexval;
-
- //*chptr++ = (char)((*(unsigned long long *)&vv) >> 32) | 0x80 /* assume that the number is normalised */;
- D_extend(vv);
+ PTR p;
+ p.u64 = &aNexval;
+ DoubleToExtended(*p.dp, extDbl);
+ D_extend(extDbl);
}
else
{
- long double vvv = 0;
AddFixup(FU_FLOATDOUB, sloc, aNexpr);
-
- D_extend(vvv);
+ memset(extDbl, 0, 12);
+ D_extend(extDbl);
}
break;
else
{
// Arrange for fixup later on
- AddFixup(FU_WORD|FU_SEXT, sloc, aNbexpr);
+ AddFixup(FU_WORD | FU_SEXT, sloc, aNbexpr);
D_word(0);
}
}
}
}
// Deposit od (if not suppressed)
- if ((aNexten&7)==EXT_IISPRE0 || (aNexten&7)==EXT_IISPREN
- || (aNexten&7)==EXT_IISNOIN || (aNexten&7)==EXT_IISPOSN)
+ if ((aNexten & 7) == EXT_IISPRE0 || (aNexten & 7) == EXT_IISPREN
+ || (aNexten & 7) == EXT_IISNOIN || (aNexten & 7) == EXT_IISPOSN)
{
// Don't deposit anything (suppressed)
}
- else if ((aNexten&7)==EXT_IISPREW
- || (aNexten&7)==EXT_IISPOSW || (aNexten&7)==EXT_IISNOIW)
+ else if ((aNexten & 7) == EXT_IISPREW
+ || (aNexten & 7) == EXT_IISPOSW || (aNexten & 7) == EXT_IISNOIW)
{
// Deposit word od
if (w)
else
{
// Arrange for fixup later on
- AddFixup(FU_WORD|FU_SEXT, sloc, aNexpr);
+ AddFixup(FU_WORD | FU_SEXT, sloc, aNexpr);
D_word(0);
}
}
else
{
// Arrange for fixup later on
- AddFixup(FU_LONG|FU_SEXT, sloc, aNexpr);
+ AddFixup(FU_LONG | FU_SEXT, sloc, aNexpr);
D_long(0);
}
}
-//
+
// RMAC - Reboot's Macro Assembler for all Atari computers
// EXPR.C - Expression Analyzer
// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
break;
case FCONST:
ptk.u32 = tok;
- *evalTokenBuffer.u32++ = CONST;
+ *evalTokenBuffer.u32++ = FCONST;
*evalTokenBuffer.u64++ = *ptk.u64++;
tok = ptk.u32;
break;
}
if (sy->sattr & DEFINED)
- {
*++sval = sy->svalue; // Push symbol's value
- }
else
- {
*++sval = 0; // 0 for undefined symbols
- }
*++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
sym_seg = (WORD)(sy->sattr & TDB);
break;
+
case CONST:
*++sval = *tk.u64++;
//printf("evexpr(): CONST = %lX\n", *sval);
*++sattr = ABS | DEFINED; // Push simple attribs
break;
+
case FCONST:
-//printf("evexpr(): FCONST = %i\n", *tk.u32);
- *((double *)sval) = *((double *)tk.u32);
- tk.u32 += 2;
+//printf("evexpr(): FCONST = %lf\n", *tk.dp);
+ // Even though it's a double, we can treat it like a uint64_t since
+ // we're just moving the bits around.
+ *++sval = *tk.u64++;
*++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
break;
+
case ACONST:
//printf("evexpr(): ACONST = %i\n", *tk.u32);
*++sval = *tk.u32++; // Push value
//
// [1] + : Error
// - : ABS
+
case '+':
//printf("evexpr(): +\n");
--sval; // Pop value
--sattr; // Pop attrib
//printf("--> N+N: %i + %i = ", *sval, sval[1]);
- // Extract float attributes from both terms and pack them
- // into a single value
- attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
- attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
- if (attr == (FLOAT | (FLOAT >> 1)))
- {
- // Float + Float
- double * dst = (double *)sval;
- double * src = (double *)(sval + 1);
- *dst += *src;
- }
- else if (attr == FLOAT)
+ // Since adding an int to a fp value promotes it to a fp value, we
+ // don't care whether it's first or second; we cast to to a double
+ // regardless.
+ if (attr == FLOAT)
{
- // Float + Int
- double * dst = (double *)sval;
- uint64_t * src = (uint64_t *)(sval + 1);
- *dst += *src;
- }
- else if (attr == FLOAT >> 1)
- {
- // Int + Float
- uint64_t * dst = (uint64_t *)sval;
- double * src = (double *)(sval + 1);
- *(double *)dst = *src + *dst;
+ PTR p;
+ p.u64 = sval;
+ double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
+ p.u64++;
+ double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
+ *(double *)sval = fpval1 + fpval2;
}
else
{
//printf("%i\n", *sval);
if (!(*sattr & TDB))
- *sattr = sattr[1] | attr2;
+ *sattr = sattr[1] | attr;
else if (sattr[1] & TDB)
return error(seg_error);
break;
+
case '-':
//printf("evexpr(): -\n");
--sval; // Pop value
--sattr; // Pop attrib
//printf("--> N-N: %i - %i = ", *sval, sval[1]);
- // Extract float attributes from both terms and pack them
- // into a single value
- attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
- attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
- if (attr == (FLOAT | (FLOAT >> 1)))
- {
- // Float - Float
- double * dst = (double *)sval;
- double * src = (double *)(sval + 1);
- *dst -= *src;
- }
- else if (attr == FLOAT)
- {
- // Float - Int
- double * dst = (double *)sval;
- uint64_t * src = (uint64_t *)(sval + 1);
- *dst -= *src;
- }
- else if (attr == FLOAT >> 1)
+ // Since subtracting an int to a fp value promotes it to a fp
+ // value, we don't care whether it's first or second; we cast to to
+ // a double regardless.
+ if (attr == FLOAT)
{
- // Int - Float
- uint64_t * dst = (uint64_t *)sval;
- double * src = (double *)(sval + 1);
- *(double *)dst = *dst - *src;
+ PTR p;
+ p.u64 = sval;
+ double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
+ p.u64++;
+ double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
+ *(double *)sval = fpval1 - fpval2;
}
else
{
- *sval -= sval[1]; // Compute value
+ *sval -= sval[1];
}
-
//printf("%i\n", *sval);
+ *sattr |= attr; // Inherit FLOAT attribute
attr = (WORD)(*sattr & TDB);
#if 0
printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
#endif
- *sattr |= attr2; // Inherit FLOAT attribute
// If symbol1 is ABS, take attributes from symbol2
if (!attr)
*sattr = sattr[1];
*sattr &= ~TDB;
break;
+
// Unary operators only work on ABS items
case UNMINUS:
//printf("evexpr(): UNMINUS\n");
if (*sattr & FLOAT)
{
- double *dst = (double *)sval;
+ double * dst = (double *)sval;
*dst = -*dst;
*sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
}
else
{
- *sval = -(int)*sval;
+ *sval = -(int64_t)*sval;
*sattr = ABS | DEFINED; // Expr becomes absolute
}
+
break;
+
case '!':
//printf("evexpr(): !\n");
if (*sattr & TDB)
*sval = !*sval;
*sattr = ABS | DEFINED; // Expr becomes absolute
break;
+
case '~':
//printf("evexpr(): ~\n");
if (*sattr & TDB)
*sval = ~*sval;
*sattr = ABS | DEFINED; // Expr becomes absolute
break;
+
// Comparison operators must have two values that
// are in the same segment, but that's the only requirement.
case LE:
if ((*sattr & TDB) != (sattr[1] & TDB))
return error(seg_error);
- // Extract float attributes from both terms and pack them
- // into a single value
- attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
- if (attr == (FLOAT | (FLOAT >> 1)))
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
{
- // Float <= Float
- double * dst = (double *)sval;
- double * src = (double *)(sval + 1);
- *sval = *dst <= *src;
- }
- else if (attr == FLOAT)
- {
- // Float <= Int
- double * dst = (double *)sval;
- uint64_t * src = (uint64_t *)(sval + 1);
- *sval = *dst <= *src;
- }
- else if (attr == FLOAT >> 1)
- {
- // Int <= Float
- uint64_t * dst = (uint64_t *)sval;
- double * src = (double *)(sval + 1);
- *sval = *dst <= *src;
+ PTR p;
+ p.u64 = sval;
+ double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
+ p.u64++;
+ double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
+ *sval = (fpval1 <= fpval2);
}
else
{
- *sval = *sval <= sval[1];
+ *sval = (*sval <= sval[1]);
}
*sattr = ABS | DEFINED;
break;
+
case GE:
//printf("evexpr(): GE\n");
sattr--;
if ((*sattr & TDB) != (sattr[1] & TDB))
return error(seg_error);
- // Extract float attributes from both terms and pack them
- // into a single value
- attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
- if (attr == (FLOAT | (FLOAT >> 1)))
- {
- // Float >= Float
- double * dst = (double *)sval;
- double * src = (double *)(sval + 1);
- *sval = *dst >= *src;
- }
- else if (attr == FLOAT)
- {
- // Float >= Int
- double * dst = (double *)sval;
- uint64_t * src = (uint64_t *)(sval + 1);
- *sval = *dst >= *src;
- }
- else if (attr == FLOAT >> 1)
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
{
- // Int >= Float
- uint64_t * dst = (uint64_t *)sval;
- double * src = (double *)(sval + 1);
- *sval = *dst >= *src;
+ PTR p;
+ p.u64 = sval;
+ double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
+ p.u64++;
+ double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
+ *sval = (fpval1 >= fpval2);
}
- else if (attr == 0)
+ else
{
- *sval = *sval >= sval[1];
+ *sval = (*sval >= sval[1]);
}
- else
- *sattr = ABS | DEFINED;
+ *sattr = ABS | DEFINED;
break;
+
case '>':
//printf("evexpr(): >\n");
sattr--;
if ((*sattr & TDB) != (sattr[1] & TDB))
return error(seg_error);
- // Extract float attributes from both terms and pack them
- // into a single value
- attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
- if (attr == (FLOAT | (FLOAT >> 1)))
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
{
- // Float > Float
- double * dst = (double *)sval;
- double * src = (double *)(sval + 1);
- *sval = *dst > *src;
- }
- else if (attr == FLOAT)
- {
- // Float > Int
- double * dst = (double *)sval;
- uint64_t * src = (uint64_t *)(sval + 1);
- *sval = *dst > *src;
- }
- else if (attr == FLOAT >> 1)
- {
- // Int > Float
- uint64_t * dst = (uint64_t *)sval;
- double * src = (double *)(sval + 1);
- *sval = *dst > *src;
+ PTR p;
+ p.u64 = sval;
+ double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
+ p.u64++;
+ double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
+ *sval = (fpval1 > fpval2);
}
else
{
- *sval = *sval > sval[1];
+ *sval = (*sval > sval[1]);
}
*sattr = ABS | DEFINED;
-
break;
+
case '<':
//printf("evexpr(): <\n");
sattr--;
if ((*sattr & TDB) != (sattr[1] & TDB))
return error(seg_error);
- // Extract float attributes from both terms and pack them
- // into a single value
- attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
- if (attr == (FLOAT | (FLOAT >> 1)))
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
{
- // Float < Float
- double * dst = (double *)sval;
- double * src = (double *)(sval + 1);
- *sval = *dst < *src;
- }
- else if (attr == FLOAT)
- {
- // Float < Int
- double * dst = (double *)sval;
- uint64_t * src = (uint64_t *)(sval + 1);
- *sval = *dst < *src;
- }
- else if (attr == FLOAT >> 1)
- {
- // Int < Float
- uint64_t * dst = (uint64_t *)sval;
- double * src = (double *)(sval + 1);
- *sval = *dst < *src;
+ PTR p;
+ p.u64 = sval;
+ double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
+ p.u64++;
+ double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
+ *sval = (fpval1 < fpval2);
}
else
{
- *sval = *sval < sval[1];
+ *sval = (*sval < sval[1]);
}
- *sattr = ABS | DEFINED;
-
+ *sattr = ABS | DEFINED; // Expr forced to ABS
break;
+
case NE:
//printf("evexpr(): NE\n");
sattr--;
if ((*sattr & TDB) != (sattr[1] & TDB))
return error(seg_error);
- // Extract float attributes from both terms and pack them
- // into a single value
- attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
- if (attr == (FLOAT | (FLOAT >> 1)))
- {
- // Float <> Float
- return error("comparison for equality with float types not allowed.");
- }
- else if (attr == FLOAT)
- {
- // Float <> Int
- return error("comparison for equality with float types not allowed.");
- }
- else if (attr == FLOAT >> 1)
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
{
- // Int != Float
- return error("comparison for equality with float types not allowed.");
+ PTR p;
+ p.u64 = sval;
+ double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
+ p.u64++;
+ double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
+ *sval = (fpval1 != fpval2);
}
else
{
- *sval = *sval != sval[1];
+ *sval = (*sval != sval[1]);
}
- *sattr = ABS | DEFINED;
-
+ *sattr = ABS | DEFINED; // Expr forced to ABS
break;
+
case '=':
//printf("evexpr(): =\n");
sattr--;
if ((*sattr & TDB) != (sattr[1] & TDB))
return error(seg_error);
- // Extract float attributes from both terms and pack them
- // into a single value
- attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
- if (attr == (FLOAT | (FLOAT >> 1)))
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
{
- // Float = Float
- double * dst = (double *)sval;
- double * src = (double *)(sval + 1);
- *sval = *src == *dst;
- }
- else if (attr == FLOAT)
- {
- // Float = Int
- return error("equality with float ");
- }
- else if (attr == FLOAT >> 1)
- {
- // Int == Float
- uint64_t * dst = (uint64_t *)sval;
- double * src = (double *)(sval + 1);
- *sval = *src == *dst;
+ PTR p;
+ p.u64 = sval;
+ double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
+ p.u64++;
+ double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
+ *sval = (fpval1 == fpval2);
}
else
{
- *sval = *sval == sval[1];
+ *sval = (*sval == sval[1]);
}
- *sattr = ABS | DEFINED;
+ *sattr = ABS | DEFINED; // Expr forced to ABS
break;
+
// All other binary operators must have two ABS items to work with.
// They all produce an ABS value.
default:
{
case '*':
sval--;
- sattr--; // Pop attrib
+ sattr--;
//printf("--> NxN: %i x %i = ", *sval, sval[1]);
- // Extract float attributes from both terms and pack them
- // into a single value
- attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
- attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
- if (attr == (FLOAT | (FLOAT >> 1)))
- {
- // Float * Float
- double * dst = (double *)sval;
- double * src = (double *)(sval + 1);
- *dst *= *src;
- }
- else if (attr == FLOAT)
- {
- // Float * Int
- double * dst = (double *)sval;
- uint64_t * src = (uint64_t *)(sval + 1);
- *dst *= *src;
- }
- else if (attr == FLOAT >> 1)
+ // Since multiplying an int to a fp value promotes it to a fp
+ // value, we don't care whether it's first or second; it will
+ // be cast to a double regardless.
+/*
+An open question here is do we promote ints to floats as signed or unsigned? It makes a difference if, say, the int is put in as -1 but is promoted to a double as $FFFFFFFFFFFFFFFF--you get very different results that way! For now, we promote as signed until proven detrimental otherwise.
+*/
+ if (attr == FLOAT)
{
- // Int * Float
- uint64_t * dst = (uint64_t *)sval;
- double * src = (double *)(sval + 1);
- *(double *)dst = *src * *dst;
+ PTR p;
+ p.u64 = sval;
+ double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
+ p.u64++;
+ double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
+ *(double *)sval = fpval1 * fpval2;
}
else
{
}
//printf("%i\n", *sval);
- *sattr = ABS | DEFINED; // Expr becomes absolute
- *sattr |= attr2;
-
+ *sattr = ABS | DEFINED | attr; // Expr becomes absolute
break;
+
case '/':
sval--;
- sattr--; // Pop attrib
-
-
+ sattr--;
//printf("--> N/N: %i / %i = ", sval[0], sval[1]);
- // Extract float attributes from both terms and pack them
- // into a single value
- attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
- attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT
-
- if (attr == (FLOAT | (FLOAT >> 1)))
- {
- // Float / Float
- double * dst = (double *)sval;
- double * src = (double *)(sval + 1);
-
- if (*src == 0)
- return error("divide by zero");
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
- *dst = *dst / *src;
- }
- else if (attr == FLOAT)
- {
- // Float / Int
- double * dst = (double *)sval;
- uint64_t * src = (uint64_t *)(sval + 1);
-
- if (*src == 0)
- return error("divide by zero");
-
- *dst = *dst / *src;
- }
- else if (attr == FLOAT >> 1)
+ if (attr == FLOAT)
{
- // Int / Float
- uint64_t * dst=(uint64_t *)sval;
- double * src=(double *)(sval + 1);
+ PTR p;
+ p.u64 = sval;
+ double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
+ p.u64++;
+ double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
- if (*src == 0)
+ if (fpval2 == 0)
return error("divide by zero");
- *(double *)dst = *dst / *src;
+ *(double *)sval = fpval1 / fpval2;
}
else
{
// ints.
*sval = (int32_t)sval[0] / (int32_t)sval[1];
}
-
- *sattr = ABS | DEFINED; // Expr becomes absolute
- *sattr |= attr2;
-
//printf("%i\n", *sval);
+
+ *sattr = ABS | DEFINED | attr; // Expr becomes absolute
break;
+
case '%':
sval--;
- sattr--; // Pop attrib
+ sattr--;
if ((*sattr | sattr[1]) & FLOAT)
return error("floating point numbers not allowed with operator '%'.");
if (sval[1] == 0)
return error("mod (%) by zero");
- *sattr = ABS | DEFINED; // Expr becomes absolute
*sval %= sval[1];
+ *sattr = ABS | DEFINED; // Expr becomes absolute
break;
+
case SHL:
sval--;
sattr--; // Pop attrib
if ((*sattr | sattr[1]) & FLOAT)
return error("floating point numbers not allowed with operator '<<'.");
- *sattr = ABS | DEFINED; // Expr becomes absolute
*sval <<= sval[1];
+ *sattr = ABS | DEFINED; // Expr becomes absolute
break;
+
case SHR:
sval--;
sattr--; // Pop attrib
if ((*sattr | sattr[1]) & FLOAT)
return error("floating point numbers not allowed with operator '>>'.");
- *sattr = ABS | DEFINED; // Expr becomes absolute
*sval >>= sval[1];
+ *sattr = ABS | DEFINED; // Expr becomes absolute
break;
+
case '&':
sval--;
sattr--; // Pop attrib
if ((*sattr | sattr[1]) & FLOAT)
return error("floating point numbers not allowed with operator '&'.");
- *sattr = ABS | DEFINED; // Expr becomes absolute
*sval &= sval[1];
+ *sattr = ABS | DEFINED; // Expr becomes absolute
break;
+
case '^':
sval--;
sattr--; // Pop attrib
if ((*sattr | sattr[1]) & FLOAT)
return error("floating point numbers not allowed with operator '^'.");
- *sattr = ABS | DEFINED; // Expr becomes absolute
*sval ^= sval[1];
+ *sattr = ABS | DEFINED; // Expr becomes absolute
break;
+
case '|':
sval--;
- sattr--; // Pop attrib
+ sattr--;
if ((*sattr | sattr[1]) & FLOAT)
return error("floating point numbers not allowed with operator '|'.");
- *sattr = ABS | DEFINED; // Expr becomes absolute
*sval |= sval[1];
+ *sattr = ABS | DEFINED; // Expr becomes absolute
break;
+
default:
- interror(5); // Bad operator in expression stream
+ // Bad operator in expression stream (this should never happen!)
+ interror(5);
}
}
}
if (a_esym != NULL)
*a_esym = esym;
- // sym_seg added in 1.0.16 to solve a problem with forward symbols in
- // expressions where absolute values also existed. The absolutes were
- // overiding the symbol segments and not being included :(
- //*a_attr = *sattr | sym_seg; // Copy value + attrib
-
- *a_attr = *sattr; // Copy value + attrib
+ // Copy value + attrib into return variables
*a_value = *sval;
+ *a_attr = *sattr;
return OK;
}
--- /dev/null
+//
+// Floating point to IEEE-754 conversion routines
+//
+// by James Hammons
+// (C) 2018 Underground Software
+//
+// Since there are no guarantees vis-a-vis floating point numbers in C, we have
+// to utilize routines like the following in order to guarantee that the thing
+// we get out of the C compiler is an honest-to-God IEEE-754 style floating
+// point number (since that's what the Motorola processors that we target
+// expect).
+//
+
+#include "fltpoint.h"
+#include <float.h>
+#include <math.h>
+
+//
+// Check for IEEE-754 conformance (C99 compilers should be OK here)
+//
+// The reason we do this is mainly to ensure consistency across all platforms,
+// even those that still haven't implemented C99 compliance after other
+// compilers have had them for decades. The long and the short of it is, there
+// are no guarantees for floating point implementations across platforms the
+// way there is for ints (in <stdint.h>, for example) and so we have to be
+// careful that bad assumptions vis-a-vis floating point numbers don't creep
+// into the codebase and cause problems similar to the ones we had when adding
+// proper 64-bit support. Hence, the following ugliness...
+//
+// IEEE-745 expects the following for floats and doubles:
+// float: exponent is 8 bits, mantissa is 24 bits
+// double: exponent is 11 bits, mantissa is 53 bits
+// FLT_RADIX should be 2
+#ifdef FLT_RADIX
+ #if FLT_RADIX != 2
+ #error "FLT_RADIX: Your compiler sucks. Get a real one."
+ #endif
+#endif
+#ifdef FLT_MANT_DIG
+ #if FLT_MANT_DIG != 24
+ #error "FLT_MANT_DIG: Your compiler sucks. Get a real one."
+ #endif
+#endif
+#ifdef DBL_MANT_DIG
+ #if DBL_MANT_DIG != 53
+ #error "DBL_MANT_DIG: Your compiler sucks. Get a real one."
+ #endif
+#endif
+#ifdef FLT_MAX_EXP
+ #if FLT_MAX_EXP != 128
+ #error "FLT_MAX_EXP: Your compiler sucks. Get a real one."
+ #endif
+#endif
+#ifdef DBL_MAX_EXP
+ #if DBL_MAX_EXP != 1024
+ #error "DBL_MAX_EXP: Your compiler sucks. Get a real one."
+ #endif
+#endif
+//
+// So if we get here, we can be pretty sure that a float is 4 bytes and a
+// double is 8. IEEE-754? Maaaaaaaaybe. But we don't have to worry about that
+// so much, as long as the token stream is OK (floats are 4 bytes, doubles are
+// 8).
+//
+
+
+uint32_t FloatToIEEE754(float f)
+{
+ uint32_t sign = (f < 0 ? 0x80000000 : 0);
+
+ // Split the float into normalized mantissa (range: (-1, -0.5], 0,
+ // [+0.5, +1)) and base-2 exponent
+ // d = mantissa * (2 ^ exponent) *exactly* for FLT_RADIX=2
+ // Also, since we want the mantissa to be non-inverted (2's complemented),
+ // we make sure to pass in a positive number (floats/doubles are not 2's
+ // complemented) as we already captured the sign bit above.
+ int32_t exponent;
+ float mantissa = frexpf((f < 0 ? -f : f), &exponent);
+
+ // Set the exponent bias for IEEE-754 floats
+ exponent += 0x7E;
+
+ // Check for zero, set the proper exponent if so (zero exponent means no
+ // implied leading one)
+ if (f == 0)
+ exponent = 0;
+
+ // Extract most significant 24 bits of mantissa
+ mantissa = ldexpf(mantissa, 24);
+
+ // Convert to an unsigned int
+ uint32_t ieeeVal = truncf(mantissa);
+
+ // ieeeVal now has the mantissa in binary format, *including* the leading 1
+ // bit; so we have to strip that bit out, since in IEEE-754, it's implied.
+ ieeeVal &= 0x007FFFFF;
+
+ // Finally, add in the other parts to make a proper IEEE-754 float
+ ieeeVal |= sign | ((exponent & 0xFF) << 23);
+
+ return ieeeVal;
+}
+
+
+uint64_t DoubleToIEEE754(double d)
+{
+ uint64_t sign = (d < 0 ? 0x8000000000000000LL : 0);
+ int32_t exponent;
+
+ // Split double into normalized mantissa (range: (-1, -0.5], 0, [+0.5, +1))
+ // and base-2 exponent
+ // d = mantissa * (2 ^ exponent) *exactly* for FLT_RADIX=2
+ // Also, since we want the mantissa to be non-inverted (2's complemented),
+ // we make sure to pass in a positive number (floats/doubles are not 2's
+ // complemented) as we already captured the sign bit above.
+ double mantissa = frexp((d < 0 ? -d : d), &exponent);
+
+ // Set the exponent bias for IEEE-754 doubles
+ exponent += 0x3FE;
+
+ // Check for zero, set the proper exponent if so
+ if (d == 0)
+ exponent = 0;
+
+ // Extract most significant 53 bits of mantissa
+ mantissa = ldexp(mantissa, 53);
+
+ // Convert to an unsigned int
+ uint64_t ieeeVal = trunc(mantissa);
+
+ // ieeeVal now has the mantissa in binary format, *including* the leading 1
+ // bit; so we have to strip that bit out, since in IEEE-754, it's implied.
+ ieeeVal &= 0x000FFFFFFFFFFFFF;
+
+ // Finally, add in the other parts to make a proper IEEE-754 double
+ ieeeVal |= sign | ((uint64_t)(exponent & 0x7FF) << 52);
+
+ return ieeeVal;
+}
+
+
+void DoubleToExtended(double d, uint8_t out[])
+{
+ int32_t exponent;
+ double mantissa = frexp((d < 0 ? -d : d), &exponent);
+ exponent += 0x3FFF;
+
+ if (d == 0)
+ exponent = 0;
+
+ mantissa = ldexp(mantissa, 64);
+ uint64_t intMant = trunc(mantissa);
+
+ // Motorola extended floating point is 96 bits, so we pack it into the
+ // 12-byte array that's passed in. The format is as follows: 1 bit (sign),
+ // 15 bits (exponent w/$3FFF bias), 16 bits of zero, 64 bits of mantissa.
+ out[0] = (d < 0 ? 0x80 : 0x00) | ((exponent >> 8) & 0x7F);
+ out[1] = exponent & 0xFF;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = (intMant >> 56) & 0xFF;
+ out[5] = (intMant >> 48) & 0xFF;
+ out[6] = (intMant >> 40) & 0xFF;
+ out[7] = (intMant >> 32) & 0xFF;
+ out[8] = (intMant >> 24) & 0xFF;
+ out[9] = (intMant >> 16) & 0xFF;
+ out[10] = (intMant >> 8) & 0xFF;
+ out[11] = intMant & 0xFF;
+}
+
--- /dev/null
+//
+// Cross-platform floating point handling
+//
+
+#include <stdint.h>
+
+uint32_t FloatToIEEE754(float f);
+uint64_t DoubleToIEEE754(double d);
+void DoubleToExtended(double d, uint8_t out[]);
+
#include "direct.h"
#include "eagen.h"
#include "error.h"
+#include "expr.h"
#include "procln.h"
#include "riscasm.h"
#include "sect.h"
#include "token.h"
-#include "expr.h"
#define DEF_KW
#include "kwtab.h"
#CFLAGS = -std=$(STD) -D_DEFAULT_SOURCE -g -D__GCCUNIX__ -I. -O2 -MMD
CFLAGS = -std=$(STD) -D_DEFAULT_SOURCE -g -D__GCCUNIX__ -I. -O2
-SRCS = 6502.c amode.c debug.c direct.c eagen.c error.c expr.c listing.c mach.c macro.c mark.c object.c procln.c riscasm.c rmac.c sect.c symbol.c token.c
+SRCS = 6502.c amode.c debug.c direct.c eagen.c error.c expr.c fltpoint.c listing.c mach.c macro.c mark.c object.c procln.c riscasm.c rmac.c sect.c symbol.c token.c
-OBJS = 6502.o amode.o debug.o direct.o eagen.o error.o expr.o listing.o mach.o macro.o mark.o object.o procln.o riscasm.o rmac.o sect.o symbol.o token.o
+OBJS = 6502.o amode.o debug.o direct.o eagen.o error.o expr.o fltpoint.o listing.o mach.o macro.o mark.o object.o procln.o riscasm.o rmac.o sect.o symbol.o token.o
#
# Build everything
expr.o : expr.c expr.h
$(CC) $(CFLAGS) -c expr.c
+fltpoint.o : fltpoint.c fltpoint.h
+ $(CC) $(CFLAGS) -c fltpoint.c
+
listing.o : listing.c listing.h
$(CC) $(CFLAGS) -c listing.c
$(CC) $(CFLAGS) -c token.c
rmac : $(OBJS)
- $(CC) $(CFLAGS) -o rmac $(OBJS)
+ $(CC) $(CFLAGS) -o rmac $(OBJS) -lm
#
# Clean build environment
token.h
direct.o: direct.c direct.h rmac.h symbol.h 6502.h amode.h error.h expr.h \
listing.h mach.h macro.h mark.h procln.h token.h riscasm.h sect.h \
- kwtab.h
+ kwtab.h fltpoint.h
eagen.o: eagen.c eagen.h rmac.h symbol.h amode.h sect.h mark.h error.h \
- mach.h riscasm.h eagen0.c
+ mach.h riscasm.h eagen0.c fltpoint.h
error.o: error.c error.h rmac.h symbol.h token.h listing.h
expr.o: expr.c expr.h rmac.h symbol.h direct.h error.h listing.h mach.h \
procln.h token.h riscasm.h sect.h kwtab.h
ssize = sy_assign(NULL, NULL); // Assign index numbers to the symbols
tds = sect[TEXT].sloc + sect[DATA].sloc; // Get size of TEXT and DATA segment
- buf = malloc(0x600000); // Allocate 6mb object file image memory
+ buf = malloc(0x800000); // Allocate 8MB object file image memory
if (buf == NULL)
{
return ERROR;
}
- memset(buf, 0, 0x600000); // Clear allocated memory
+ memset(buf, 0, 0x800000); // Clear allocated memory
objImage = buf; // Set global object image pointer
strtable = malloc(0x200000); // Allocate 2MB string table buffer
}
sy->sattr |= eattr | EQUATED; // Symbol inherits value and attributes
- sy->svalue = (uint32_t)eval;
+ sy->svalue = eval;
if (list_flag) // Put value in listing
listvalue((uint32_t)eval);
//
// TARGET SPECIFIC BUILD SETTINGS
//
-#if defined(WIN32) || defined (WIN64)
+#if defined(WIN32) || defined(WIN64)
#include <io.h>
#include <fcntl.h>
// Release platform - windows
#define _OPEN_FLAGS _O_TRUNC|_O_CREAT|_O_BINARY|_O_RDWR
#define _OPEN_INC _O_RDONLY|_O_BINARY
#define _PERM_MODE _S_IREAD|_S_IWRITE
+
#ifdef _MSC_VER
#if _MSC_VER > 1000
#pragma warning(disable:4996)
#include <sys/fcntl.h>
#include <unistd.h>
- // Release platform - mac OS-X or Linux
- #define PLATFORM "OSX/Linux"
+ // Release platform - Linux or mac OS-X
+ #define PLATFORM "Linux/OSX"
#define _OPEN_FLAGS O_TRUNC|O_CREAT|O_RDWR
#define _OPEN_INC O_RDONLY
#define _PERM_MODE S_IRUSR|S_IWUSR
// WARNING WARNING WARNING
#define DO_PRAGMA(x) _Pragma (#x)
#define WARNING(desc) DO_PRAGMA(message (#desc))
-#else
+
+ #else
+
// Release platform - not specified
#include <sys/fcntl.h>
#define PLATFORM "Unknown"
#define DO_PRAGMA(x) _Pragma (#x)
#define WARNING(desc) DO_PRAGMA(message (#desc))
#endif
+
#endif
+
//
// Endian related, for safe handling of endian-sensitive data
// USAGE: GETBExx() is *always* an rvalue, a = pointer to a uint8_t,
uint32_t lw; // LONG (for some reason)
SYM ** sy; // SYM pointer
TOKEN * tk; // TOKEN pointer
- double * dp; // Double pointer (temporary!)
+ double * dp; // Double pointer
+ int64_t * i64; // 64-bit signed int pointer
};
// Symbol spaces
// SECT.H - Code Generation, Fixups and Section Management
// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
-// Source utilised with the kind permission of Landon Dyer
+// Source utilized with the kind permission of Landon Dyer
//
#ifndef __SECT_H__
#include "rmac.h"
-// Macros to deposit code in the current section
+// Macros to deposit code in the current section (in Big Endian)
// D_rword deposits a "6502" format (low, high) word (01).
#define D_byte(b) {*chptr++=(uint8_t)(b); sloc++; ch_size++; \
if(orgactive) orgaddr++;}
sloc += 8; ch_size += 8; if(orgactive) orgaddr += 8;}
#define D_rword(w) {*chptr++=(uint8_t)(w); *chptr++=(uint8_t)((w)>>8); \
sloc+=2; ch_size+=2;if(orgactive) orgaddr += 2;}
-#define D_single(w) {chcheck(4);*chptr++ = ((char *)&w)[3]; \
- *chptr++ = ((char *)&w)[2]; \
- *chptr++ = ((char *)&w)[1]; \
- *chptr++=((char *)&w)[0]; \
- sloc+=4; ch_size += 4; if(orgactive) orgaddr += 4;}
-#define D_double(w) {chcheck(8);*chptr++=(char)((*(unsigned long long *)&w)); \
- *chptr++=(char)((*(unsigned long long *)&w)>>8); \
- *chptr++=(char)((*(unsigned long long *)&w)>>16); \
- *chptr++=(char)((*(unsigned long long *)&w)>>24); \
- *chptr++=(char)((*(unsigned long long *)&w)>>32); \
- *chptr++=(char)((*(unsigned long long *)&w)>>40); \
- *chptr++=(char)((*(unsigned long long *)&w)>>48); \
- *chptr++=(char)((*(unsigned long long *)&w)>>56); \
- sloc+=8; ch_size += 8; if(orgactive) orgaddr += 8;}
-#ifdef _MSC_VER
-#define D_extend(w) {chcheck(12); *chptr++ = (char)((*(unsigned long long *)&w) >> 56); \
-*chptr++ = (char)(((*(unsigned long long *)&w) >> (52)) & 0xf); \
-*chptr++ = (char)(0); \
-*chptr++ = (char)(0); \
-*chptr++ = (char)(((*(unsigned long long *)&w) >> (48 - 3))|0x80 /* assume that the number is normalised */); \
-*chptr++ = (char)((*(unsigned long long *)&w) >> (40 - 3)); \
-*chptr++ = (char)((*(unsigned long long *)&w) >> (32 - 3)); \
-*chptr++ = (char)((*(unsigned long long *)&w) >> (24 - 3)); \
-*chptr++ = (char)((*(unsigned long long *)&w) >> (16 - 3)); \
-*chptr++ = (char)((*(unsigned long long *)&w) >> (8 - 3)); \
-*chptr++ = (char)((*(unsigned long long *)&w << 3)); \
-*chptr++=(char)(0); \
- sloc+=12; ch_size += 12; if(orgactive) orgaddr += 12;}
-#elif defined(LITTLE_ENDIAN)
-#define D_extend(w) {chcheck(12);*chptr++=((char *)&w)[0]; \
- *chptr++=((char *)&w)[1]; \
- *chptr++=((char *)&w)[2]; \
- *chptr++=((char *)&w)[3]; \
- *chptr++=((char *)&w)[4]; \
- *chptr++=((char *)&w)[5]; \
- *chptr++=((char *)&w)[6]; \
- *chptr++=((char *)&w)[7]; \
- *chptr++=((char *)&w)[8]; \
- *chptr++=((char *)&w)[9]; \
- *chptr++=((char *)&w)[10]; \
- *chptr++=((char *)&w)[11]; \
- sloc+=12; ch_size += 12; if(orgactive) orgaddr += 12;}
-
-#else
-
-WARNING(Please implement a non-byte swapped D_extend!)
-//stopgap for now, until this can be implemented proppa-ly :-P
-#define D_extend(w) {chcheck(12); chptr+=12; sloc+=12; ch_size+=12; if(orgactive) orgaddr +=12;}
-
-#endif
+// This macro expects to get an array of uint8_ts with the hi bits in a[0] and
+// the low bits in a[11] (Big Endian).
+#define D_extend(a) {memcpy(chptr, a, 12); chptr+=12; sloc+=12, ch_size+=12;\
+ if (orgactive) orgaddr+=12;}
+
// Fill n bytes with zeroes
#define D_ZEROFILL(n) {memset(chptr, 0, n); chptr+=n; sloc+=n; ch_size+=n;\
if (orgactive) orgaddr+=n;}
strcpy(ln2, "external");
else
{
- sprintf(ln2, "%08X", q->svalue);
+ sprintf(ln2, "%016lX", q->svalue);
ToUppercase(ln2);
}
uint16_t sattr; // Attribute bits
uint32_t sattre; // Extended attribute bits
uint16_t senv; // Enviroment number
- uint32_t svalue; // Symbol value
+ uint64_t svalue; // Symbol value (now 64-bit)
uint8_t * sname; // * -> Symbol's print-name
LLIST * lineList; // * -> Macro's linked list of lines
LLIST * last; // * -> end of macro linked list
else if ((int)chrtab[*(ln + 1)] & DIGIT)
{
// Hey, more digits after the dot, so we assume it's a
- // floating point number of some kind
-#if 0
- double fract = 10;
- ln++;
- f = (double)v;
-
- while ((int)chrtab[*ln] & DIGIT)
- {
- f = f + (double)(*ln++ - '0') / fract;
- fract *= 10;
- }
-#else
- // Here we parse the whole floating point number
+ // floating point number of some kind... numEnd will point
+ // to the first non-float character after it's done
char * numEnd;
errno = 0;
double f = strtod(numStart, &numEnd);
if (errno != 0)
return error("floating point parse error");
-#endif
+ // N.B.: We use the C compiler's internal double
+ // representation for all internal float calcs and
+ // are reasonably sure that the size of said double
+ // is 8 bytes long (which we check for in fltpoint.c)
*tk.u32++ = FCONST;
-// Shamus: Well, this is all kinds of icky--not the least of which is that unlike uintNN_t types, we have no guarantees of any kind when it comes to the size of floating point numbers in C (as far as I know of). If there is, we need to use those kinds here, or else figure out at runtime what sizes we're dealing with and act accordingly. To be fair, this is OK as long as the double type is less than 64 bits wide, but again, there's no guarantee that it isn't. :-/
*tk.dp = f;
tk.u64++;
continue;
printf("[COLON]");
else if (t == CONST)
printf("[CONST]");
+ else if (t == FCONST)
+ printf("[FCONST]");
else if (t == ACONST)
printf("[ACONST]");
else if (t == STRING)
printf("[CONST: $%lX]", *tp.u64);
t += 2;
}
+ else if (*t == FCONST)
+ {
+ PTR tp;
+ tp.u32 = t + 1;
+ printf("[FCONST: $%lX]", *tp.u64);
+ t += 2;
+ }
else if (*t == ACONST)
{
printf("[ACONST: $%X, $%X]", (uint32_t)t[1], (uint32_t)t[2]);
// Release Information
#define MAJOR 1 // Major version number
-#define MINOR 10 // Minor version number
-#define PATCH 2 // Patch release number
+#define MINOR 11 // Minor version number
+#define PATCH 0 // Patch release number
#endif // __VERSION_H__