From 98a6dffbca71cf33225e07014c1c1793e45c8e00 Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Sun, 4 Sep 2022 18:47:32 -0400 Subject: [PATCH] Implement `opt Q` for fixed-point precision, and `q` literals (e.g. `12.34q8`) (#958) Fixes #957 Co-authored-by: ISSOtm --- contrib/bash_compl/_rgbasm.bash | 1 + contrib/zsh_compl/_rgbasm | 1 + include/asm/fixpoint.h | 3 ++ include/asm/opt.h | 3 +- man/rgbasm.1 | 8 ++++ man/rgbasm.5 | 29 ++++++++---- src/asm/fixpoint.c | 23 ++++++---- src/asm/format.c | 6 ++- src/asm/lexer.c | 74 +++++++++++++++++++++--------- src/asm/main.c | 33 ++++++++++--- src/asm/opt.c | 47 ++++++++++++++++--- test/asm/fixed-point-precision.asm | 8 ++++ test/asm/fixed-point-precision.err | 3 ++ test/asm/fixed-point-precision.out | 2 + test/asm/opt-Q.asm | 18 ++++++++ test/asm/opt-Q.err | 7 +++ test/asm/opt-Q.out | 33 +++++++++++++ test/asm/opt.asm | 6 ++- test/asm/opt.err | 2 +- test/asm/opt.out | 2 + 20 files changed, 253 insertions(+), 56 deletions(-) create mode 100644 test/asm/opt-Q.asm create mode 100644 test/asm/opt-Q.err create mode 100644 test/asm/opt-Q.out diff --git a/contrib/bash_compl/_rgbasm.bash b/contrib/bash_compl/_rgbasm.bash index 892fe4c0..33b48386 100755 --- a/contrib/bash_compl/_rgbasm.bash +++ b/contrib/bash_compl/_rgbasm.bash @@ -39,6 +39,7 @@ _rgbasm_completions() { [M]="dependfile:glob-*.mk *.d" [o]="output:glob-*.o" [p]="pad-value:unk" + [Q]="q-precision:unk" [r]="recursion-depth:unk" [W]="warning:warning" ) diff --git a/contrib/zsh_compl/_rgbasm b/contrib/zsh_compl/_rgbasm index 11ad0a78..a32be84d 100644 --- a/contrib/zsh_compl/_rgbasm +++ b/contrib/zsh_compl/_rgbasm @@ -56,6 +56,7 @@ local args=( '*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'" '(-o --output)'{-o,--output}'+[Output file]:output file:_files' '(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:' + '(-Q --q-precision)'{-Q,--q-precision}'+[Set fixed-point precision]:precision:' '(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:' '(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbasm_warnings' diff --git a/include/asm/fixpoint.h b/include/asm/fixpoint.h index 7d8c8e6d..6fc5ac29 100644 --- a/include/asm/fixpoint.h +++ b/include/asm/fixpoint.h @@ -11,6 +11,9 @@ #include +extern uint8_t fixPrecision; + +double fix_PrecisionFactor(void); void fix_Print(int32_t i); int32_t fix_Sin(int32_t i); int32_t fix_Cos(int32_t i); diff --git a/include/asm/opt.h b/include/asm/opt.h index 5cbe6874..f9e9345b 100644 --- a/include/asm/opt.h +++ b/include/asm/opt.h @@ -14,7 +14,8 @@ void opt_B(char const chars[2]); void opt_G(char const chars[4]); -void opt_P(uint8_t fill); +void opt_P(uint8_t padByte); +void opt_Q(uint8_t precision); void opt_L(bool optimize); void opt_W(char const *flag); void opt_Parse(char const *option); diff --git a/man/rgbasm.1 b/man/rgbasm.1 index 390aef17..bd229d71 100644 --- a/man/rgbasm.1 +++ b/man/rgbasm.1 @@ -25,6 +25,7 @@ .Op Fl MQ Ar target_file .Op Fl o Ar out_file .Op Fl p Ar pad_value +.Op Fl Q Ar fix_precision .Op Fl r Ar recursion_depth .Op Fl W Ar warning .Ar @@ -148,6 +149,13 @@ Write an object file to the given filename. .It Fl p Ar pad_value , Fl Fl pad-value Ar pad_value When padding an image, pad with this value. The default is 0x00. +.It Fl Q Ar fix_precision , Fl Fl q-precision Ar fix_precision +Use this as the precision of fixed-point numbers after the decimal point, unless they specify their own precision. +The default is 16, so fixed-point numbers are Q16.16 (since they are 32-bit integers). +The argument may start with a +.Ql \&. +to match the Q notation, for example, +.Ql Fl Q Ar .16 . .It Fl r Ar recursion_depth , Fl Fl recursion-depth Ar recursion_depth Specifies the recursion depth past which RGBASM will assume being in an infinite loop. The default is 64. diff --git a/man/rgbasm.5 b/man/rgbasm.5 index 08a1f8c6..d22e6f73 100644 --- a/man/rgbasm.5 +++ b/man/rgbasm.5 @@ -208,13 +208,14 @@ section. The instructions in the macro-language generally require constant expressions. .Ss Numeric formats There are a number of numeric formats. -.Bl -column -offset indent "Fixed point (Q16.16)" "Prefix" +.Bl -column -offset indent "Precise fixed-point" "Prefix" .It Sy Format type Ta Sy Prefix Ta Sy Accepted characters .It Hexadecimal Ta $ Ta 0123456789ABCDEF .It Decimal Ta none Ta 0123456789 .It Octal Ta & Ta 01234567 .It Binary Ta % Ta 01 -.It Fixed point (Q16.16) Ta none Ta 01234.56789 +.It Fixed-point Ta none Ta 01234.56789 +.It Precise fixed-point Ta none Ta 12.34q8 .It Character constant Ta none Ta \(dqABYZ\(dq .It Gameboy graphics Ta \` Ta 0123 .El @@ -301,9 +302,19 @@ and .Ic \&! returns 1 if the operand was 0, and 0 otherwise. .Ss Fixed-point expressions -Fixed-point numbers are basically normal (32-bit) integers, which count 65536ths instead of entire units, offering better precision than integers but limiting the range of values. -The upper 16 bits are used for the integer part and the lower 16 bits are used for the fraction (65536ths). -Since they are still akin to integers, you can use them in normal integer expressions, and some integer operators like +Fixed-point numbers are basically normal (32-bit) integers, which count fractions instead of whole numbers. +They offer better precision than integers but limit the range of values. +By default, the upper 16 bits are used for the integer part and the lower 16 bits are used for the fraction (65536ths). +The default number of fractional bits can be changed with the +.Fl Q +command-line option. +You can also specify a precise fixed-point value by appending a +.Dq q +to it followed by the number of fractional bits, such as +.Ql 12.34q8 . +.Pp +Since fixed-point values are still just integers, you can use them in normal integer expressions. +Some integer operators like .Sq + and .Sq - @@ -317,9 +328,9 @@ delim $$ .EN .Bl -column -offset indent "ATAN2(x, y)" .It Sy Name Ta Sy Operation -.It Fn DIV x y Ta $x \[di] y$ -.It Fn MUL x y Ta $x \[mu] y$ -.It Fn FMOD x y Ta $x % y$ +.It Fn DIV x y Ta Fixed-point division $( x \[di] y ) \[mu] ( 2 ^ precision )$ +.It Fn MUL x y Ta Fixed-point multiplication $( x \[mu] y ) \[di] ( 2 ^ precision )$ +.It Fn FMOD x y Ta Fixed-point modulo $( x % y ) \[di] ( 2 ^ precision )$ .It Fn POW x y Ta $x$ to the $y$ power .It Fn LOG x y Ta Logarithm of $x$ to the base $y$ .It Fn ROUND x Ta Round $x$ to the nearest integer @@ -2034,7 +2045,7 @@ POPO The options that .Ic OPT can modify are currently: -.Cm b , g , p , r , h , L , +.Cm b , g , p , Q , r , h , L , and .Cm W . The Boolean flag options diff --git a/src/asm/fixpoint.c b/src/asm/fixpoint.c index 27648f34..4c12b5da 100644 --- a/src/asm/fixpoint.c +++ b/src/asm/fixpoint.c @@ -17,17 +17,24 @@ #include "asm/symbol.h" #include "asm/warning.h" -#define fix2double(i) ((double)((i) / 65536.0)) -#define double2fix(d) ((int32_t)round((d) * 65536.0)) - -// pi radians == 32768 fixed-point "degrees" -#define fdeg2rad(f) ((f) * (M_PI / 32768.0)) -#define rad2fdeg(r) ((r) * (32768.0 / M_PI)) - #ifndef M_PI #define M_PI 3.14159265358979323846 #endif +#define fix2double(i) ((double)((i) / fix_PrecisionFactor())) +#define double2fix(d) ((int32_t)round((d) * fix_PrecisionFactor())) + +// pi*2 radians == 2**fixPrecision fixed-point "degrees" +#define fdeg2rad(f) ((f) * (M_PI * 2) / fix_PrecisionFactor()) +#define rad2fdeg(r) ((r) * fix_PrecisionFactor() / (M_PI * 2)) + +uint8_t fixPrecision; + +double fix_PrecisionFactor(void) +{ + return pow(2.0, fixPrecision); +} + void fix_Print(int32_t i) { uint32_t u = i; @@ -38,7 +45,7 @@ void fix_Print(int32_t i) sign = "-"; } - printf("%s%" PRIu32 ".%05" PRIu32, sign, u >> 16, + printf("%s%" PRIu32 ".%05" PRIu32, sign, u >> fixPrecision, ((uint32_t)(fix2double(u) * 100000 + 0.5)) % 100000); } diff --git a/src/asm/format.c b/src/asm/format.c index 52d6a07f..6f14c80d 100644 --- a/src/asm/format.c +++ b/src/asm/format.c @@ -15,6 +15,7 @@ #include #include +#include "asm/fixpoint.h" #include "asm/format.h" #include "asm/warning.h" @@ -225,7 +226,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin } else if (fmt->type == 'f') { // Special case for fixed-point - // Default fractional width (C's is 6 for "%f"; here 5 is enough) + // Default fractional width (C's is 6 for "%f"; here 5 is enough for Q16.16) size_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5; if (fracWidth > 255) { @@ -234,7 +235,8 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin fracWidth = 255; } - snprintf(valueBuf, sizeof(valueBuf), "%.*f", (int)fracWidth, value / 65536.0); + snprintf(valueBuf, sizeof(valueBuf), "%.*f", (int)fracWidth, + value / fix_PrecisionFactor()); } else { char const *spec = fmt->type == 'd' ? "%" PRId32 : fmt->type == 'u' ? "%" PRIu32 diff --git a/src/asm/lexer.c b/src/asm/lexer.c index fb07bec8..ec3171c0 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -27,6 +27,7 @@ #include "platform.h" // For `ssize_t` #include "asm/lexer.h" +#include "asm/fixpoint.h" #include "asm/format.h" #include "asm/fstack.h" #include "asm/macro.h" @@ -1125,39 +1126,66 @@ static uint32_t readNumber(int radix, uint32_t baseValue) return value; } -static uint32_t readFractionalPart(int32_t integer) +static uint32_t readFractionalPart(uint32_t integer) { uint32_t value = 0, divisor = 1; + uint8_t precision = 0; + enum { + READFRACTIONALPART_DIGITS, + READFRACTIONALPART_PRECISION, + READFRACTIONALPART_PRECISION_DIGITS, + } state = READFRACTIONALPART_DIGITS; for (;; shiftChar()) { int c = peek(); - if (c == '_') - continue; - else if (c < '0' || c > '9') - break; - if (divisor > (UINT32_MAX - (c - '0')) / 10) { - warning(WARNING_LARGE_CONSTANT, - "Precision of fixed-point constant is too large\n"); - // Discard any additional digits - shiftChar(); - while (c = peek(), (c >= '0' && c <= '9') || c == '_') + if (state == READFRACTIONALPART_DIGITS) { + if (c == '_') { + continue; + } else if (c == 'q' || c == 'Q') { + state = READFRACTIONALPART_PRECISION; + continue; + } else if (c < '0' || c > '9') { + break; + } + if (divisor > (UINT32_MAX - (c - '0')) / 10) { + warning(WARNING_LARGE_CONSTANT, + "Precision of fixed-point constant is too large\n"); + // Discard any additional digits shiftChar(); - break; + while (c = peek(), (c >= '0' && c <= '9') || c == '_') + shiftChar(); + break; + } + value = value * 10 + (c - '0'); + divisor *= 10; + } else { + if (c == '.' && state == READFRACTIONALPART_PRECISION) { + state = READFRACTIONALPART_PRECISION_DIGITS; + continue; + } else if (c < '0' || c > '9') { + break; + } + precision = precision * 10 + (c - '0'); } - value = value * 10 + (c - '0'); - divisor *= 10; } - if (integer > INT16_MAX || integer < INT16_MIN) + if (precision == 0) { + if (state >= READFRACTIONALPART_PRECISION) + error("Invalid fixed-point constant, no significant digits after 'q'\n"); + precision = fixPrecision; + } else if (precision > 31) { + error("Fixed-point constant precision must be between 1 and 31\n"); + precision = fixPrecision; + } + + if (integer >= ((uint32_t)1 << (precision - 1))) warning(WARNING_LARGE_CONSTANT, "Magnitude of fixed-point constant is too large\n"); - // Cast to unsigned avoids UB if shifting discards bits - integer = (uint32_t)integer << 16; // Cast to unsigned avoids undefined overflow behavior - uint16_t fractional = (uint16_t)round(value * 65536.0 / divisor); + uint32_t fractional = (uint32_t)round((double)value / divisor * pow(2.0, precision)); - return (uint32_t)integer | (fractional * (integer >= 0 ? 1 : -1)); + return (integer << precision) | fractional; } char binDigits[2]; @@ -1741,6 +1769,8 @@ static int yylex_SKIP_TO_ENDC(void); // forward declaration for yylex_NORMAL static int yylex_NORMAL(void) { + uint32_t num = 0; + for (;;) { int c = nextChar(); char secondChar; @@ -1912,10 +1942,12 @@ static int yylex_NORMAL(void) case '7': case '8': case '9': - yylval.constValue = readNumber(10, c - '0'); + num = readNumber(10, c - '0'); if (peek() == '.') { shiftChar(); - yylval.constValue = readFractionalPart(yylval.constValue); + yylval.constValue = readFractionalPart(num); + } else { + yylval.constValue = num; } return T_NUMBER; diff --git a/src/asm/main.c b/src/asm/main.c index c9e825a8..a1cefb11 100644 --- a/src/asm/main.c +++ b/src/asm/main.c @@ -19,6 +19,7 @@ #include #include "asm/charmap.h" +#include "asm/fixpoint.h" #include "asm/format.h" #include "asm/fstack.h" #include "asm/lexer.h" @@ -86,7 +87,7 @@ static char *make_escape(char const *str) } // Short options -static const char *optstring = "b:D:Eg:Hhi:LlM:o:p:r:VvW:w"; +static const char *optstring = "b:D:Eg:Hhi:LlM:o:p:Q:r:VvW:w"; // Variables for the long-only options static int depType; // Variants of `-M` @@ -116,6 +117,7 @@ static struct option const longopts[] = { { "MQ", required_argument, &depType, 'Q' }, { "output", required_argument, NULL, 'o' }, { "pad-value", required_argument, NULL, 'p' }, + { "q-precision", required_argument, NULL, 'Q' }, { "recursion-depth", required_argument, NULL, 'r' }, { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, @@ -128,7 +130,8 @@ static void print_usage(void) fputs( "Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-i path]\n" " [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n" -" [-o out_file] [-p pad_value] [-r depth] [-W warning] \n" +" [-o out_file] [-p pad_value] [-Q precision] [-r depth]\n" +" [-W warning] \n" "Useful options:\n" " -E, --export-all export all labels\n" " -M, --dependfile set the output dependency file\n" @@ -170,6 +173,7 @@ int main(int argc, char *argv[]) opt_B("01"); opt_G("0123"); opt_P(0); + opt_Q(16); haltnop = true; warnOnHaltNop = true; optimizeLoads = true; @@ -250,17 +254,34 @@ int main(int argc, char *argv[]) out_SetFileName(musl_optarg); break; - unsigned long fill; + unsigned long padByte; case 'p': - fill = strtoul(musl_optarg, &ep, 0); + padByte = strtoul(musl_optarg, &ep, 0); if (musl_optarg[0] == '\0' || *ep != '\0') errx("Invalid argument for option 'p'"); - if (fill > 0xFF) + if (padByte > 0xFF) errx("Argument for option 'p' must be between 0 and 0xFF"); - opt_P(fill); + opt_P(padByte); + break; + + unsigned long precision; + const char *precisionArg; + case 'Q': + precisionArg = musl_optarg; + if (precisionArg[0] == '.') + precisionArg++; + precision = strtoul(precisionArg, &ep, 0); + + if (musl_optarg[0] == '\0' || *ep != '\0') + errx("Invalid argument for option 'Q'"); + + if (precision < 1 || precision > 31) + errx("Argument for option 'Q' must be between 1 and 31"); + + opt_Q(precision); break; case 'r': diff --git a/src/asm/opt.c b/src/asm/opt.c index b406b54a..e31afd54 100644 --- a/src/asm/opt.c +++ b/src/asm/opt.c @@ -14,6 +14,7 @@ #include #include +#include "asm/fixpoint.h" #include "asm/fstack.h" #include "asm/lexer.h" #include "asm/main.h" @@ -23,7 +24,8 @@ struct OptStackEntry { char binary[2]; char gbgfx[4]; - int32_t fillByte; + uint8_t fixPrecision; + uint8_t fillByte; bool haltnop; bool warnOnHaltNop; bool optimizeLoads; @@ -47,9 +49,14 @@ void opt_G(char const chars[4]) lexer_SetGfxDigits(chars); } -void opt_P(uint8_t fill) +void opt_P(uint8_t padByte) { - fillByte = fill; + fillByte = padByte; +} + +void opt_Q(uint8_t precision) +{ + fixPrecision = precision; } void opt_R(size_t newDepth) @@ -103,18 +110,41 @@ void opt_Parse(char *s) case 'p': if (strlen(&s[1]) <= 2) { int result; - unsigned int fillchar; + unsigned int padByte; - result = sscanf(&s[1], "%x", &fillchar); - if (result != EOF && result != 1) + result = sscanf(&s[1], "%x", &padByte); + if (result != 1) error("Invalid argument for option 'p'\n"); + else if (padByte > 0xFF) + error("Argument for option 'p' must be between 0 and 0xFF\n"); else - opt_P(fillchar); + opt_P(padByte); } else { error("Invalid argument for option 'p'\n"); } break; + const char *precisionArg; + case 'Q': + precisionArg = &s[1]; + if (precisionArg[0] == '.') + precisionArg++; + if (strlen(precisionArg) <= 2) { + int result; + unsigned int precision; + + result = sscanf(precisionArg, "%u", &precision); + if (result != 1) + error("Invalid argument for option 'Q'\n"); + else if (precision < 1 || precision > 31) + error("Argument for option 'Q' must be between 1 and 31\n"); + else + opt_Q(precision); + } else { + error("Invalid argument for option 'Q'\n"); + } + break; + case 'r': { ++s; // Skip 'r' while (isblank(*s)) @@ -231,6 +261,8 @@ void opt_Push(void) entry->gbgfx[2] = gfxDigits[2]; entry->gbgfx[3] = gfxDigits[3]; + entry->fixPrecision = fixPrecision; // Pulled from fixpoint.h + entry->fillByte = fillByte; // Pulled from section.h entry->haltnop = haltnop; // Pulled from main.h @@ -259,6 +291,7 @@ void opt_Pop(void) opt_B(entry->binary); opt_G(entry->gbgfx); opt_P(entry->fillByte); + opt_Q(entry->fixPrecision); opt_H(entry->warnOnHaltNop); opt_h(entry->haltnop); opt_L(entry->optimizeLoads); diff --git a/test/asm/fixed-point-precision.asm b/test/asm/fixed-point-precision.asm index 84438ec2..757738e9 100644 --- a/test/asm/fixed-point-precision.asm +++ b/test/asm/fixed-point-precision.asm @@ -12,3 +12,11 @@ fl = 6.283185 fr = MUL(20.0, 0.32) println "32% of 20 = {f:fr} (~{.2f:fr}) (~~{.0f:fr})" + +q8 = 1.25q8 +q16 = 1.25Q16 +q24 = 1.25q.24 + println "Q8 ${x:q8} Q16 ${x:q16} Q24 ${x:q24}" + +qerr = 1.25q32 + println qerr diff --git a/test/asm/fixed-point-precision.err b/test/asm/fixed-point-precision.err index e69de29b..e0234c6d 100644 --- a/test/asm/fixed-point-precision.err +++ b/test/asm/fixed-point-precision.err @@ -0,0 +1,3 @@ +error: fixed-point-precision.asm(21): + Fixed-point constant precision must be between 1 and 31 +error: Assembly aborted (1 error)! diff --git a/test/asm/fixed-point-precision.out b/test/asm/fixed-point-precision.out index ad3b15e3..c17b2fd6 100644 --- a/test/asm/fixed-point-precision.out +++ b/test/asm/fixed-point-precision.out @@ -4,3 +4,5 @@ `16.12`: 16.119995 -> $00101eb8 `6.283185`: 6.283188 -> $0006487f 32% of 20 = 6.40015 (~6.40) (~~6) +Q8 $140 Q16 $14000 Q24 $1400000 +$14000 diff --git a/test/asm/opt-Q.asm b/test/asm/opt-Q.asm new file mode 100644 index 00000000..2dd0f9ba --- /dev/null +++ b/test/asm/opt-Q.asm @@ -0,0 +1,18 @@ +MACRO test + PUSHO + OPT Q\1 + print STRFMT("Q%4s", "\1") + def n = 1.14159 + println STRFMT(" -> %032b", n) + POPO +ENDM + + for x, 1, 32 + if x < 16 + test .{d:x} + else + test {d:x} + endc + endr + test .0 ; error + test 32 ; error diff --git a/test/asm/opt-Q.err b/test/asm/opt-Q.err new file mode 100644 index 00000000..58e656cc --- /dev/null +++ b/test/asm/opt-Q.err @@ -0,0 +1,7 @@ +warning: opt-Q.asm(10) -> opt-Q.asm::REPT~1(12) -> opt-Q.asm::test(5): [-Wlarge-constant] + Magnitude of fixed-point constant is too large +error: opt-Q.asm(17) -> opt-Q.asm::test(3): + Argument for option 'Q' must be between 1 and 31 +error: opt-Q.asm(18) -> opt-Q.asm::test(3): + Argument for option 'Q' must be between 1 and 31 +error: Assembly aborted (2 errors)! diff --git a/test/asm/opt-Q.out b/test/asm/opt-Q.out new file mode 100644 index 00000000..f48bd64f --- /dev/null +++ b/test/asm/opt-Q.out @@ -0,0 +1,33 @@ +Q .1 -> 00000000000000000000000000000010 +Q .2 -> 00000000000000000000000000000101 +Q .3 -> 00000000000000000000000000001001 +Q .4 -> 00000000000000000000000000010010 +Q .5 -> 00000000000000000000000000100101 +Q .6 -> 00000000000000000000000001001001 +Q .7 -> 00000000000000000000000010010010 +Q .8 -> 00000000000000000000000100100100 +Q .9 -> 00000000000000000000001001001000 +Q .10 -> 00000000000000000000010010010001 +Q .11 -> 00000000000000000000100100100010 +Q .12 -> 00000000000000000001001001000100 +Q .13 -> 00000000000000000010010010001000 +Q .14 -> 00000000000000000100100100010000 +Q .15 -> 00000000000000001001001000100000 +Q 16 -> 00000000000000010010010000111111 +Q 17 -> 00000000000000100100100001111110 +Q 18 -> 00000000000001001001000011111101 +Q 19 -> 00000000000010010010000111111010 +Q 20 -> 00000000000100100100001111110100 +Q 21 -> 00000000001001001000011111101000 +Q 22 -> 00000000010010010000111111010000 +Q 23 -> 00000000100100100001111110011111 +Q 24 -> 00000001001001000011111100111110 +Q 25 -> 00000010010010000111111001111100 +Q 26 -> 00000100100100001111110011111000 +Q 27 -> 00001001001000011111100111110000 +Q 28 -> 00010010010000111111001111100000 +Q 29 -> 00100100100001111110011111000000 +Q 30 -> 01001001000011111100111110000001 +Q 31 -> 10010010000111111001111100000010 +Q .0 -> 00000000000000010010010000111111 +Q 32 -> 00000000000000010010010000111111 diff --git a/test/asm/opt.asm b/test/asm/opt.asm index 5cb02402..d42b2caf 100644 --- a/test/asm/opt.asm +++ b/test/asm/opt.asm @@ -3,11 +3,13 @@ SECTION "test", ROM0 opt !h, !L ; already the default, but tests parsing "!" pusho - opt p42, h, L, Wno-div + opt p42, Q.4, h, L, Wno-div ds 1 ld [$ff88], a halt println $8000_0000 / -1 + def n = 3.14 + println "{x:n} = {f:n}" popo opt H, l @@ -16,3 +18,5 @@ popo ld [$ff88], a halt println $8000_0000 / -1 + def n = 3.14 + println "{x:n} = {f:n}" diff --git a/test/asm/opt.err b/test/asm/opt.err index 6432e66e..5336c550 100644 --- a/test/asm/opt.err +++ b/test/asm/opt.err @@ -1,2 +1,2 @@ -warning: opt.asm(18): [-Wdiv] +warning: opt.asm(20): [-Wdiv] Division of -2147483648 by -1 yields -2147483648 diff --git a/test/asm/opt.out b/test/asm/opt.out index 62e5a6fb..57af58b0 100644 --- a/test/asm/opt.out +++ b/test/asm/opt.out @@ -1,2 +1,4 @@ $80000000 +32 = 3.12500 $80000000 +323d7 = 3.14000