Implement opt Q for fixed-point precision, and q literals (e.g. 12.34q8) (#958)

Fixes #957

Co-authored-by: ISSOtm <eldredhabert0@gmail.com>
This commit is contained in:
Rangi
2022-09-04 18:47:32 -04:00
committed by GitHub
parent 889302a9e2
commit 98a6dffbca
20 changed files with 253 additions and 56 deletions

View File

@@ -39,6 +39,7 @@ _rgbasm_completions() {
[M]="dependfile:glob-*.mk *.d" [M]="dependfile:glob-*.mk *.d"
[o]="output:glob-*.o" [o]="output:glob-*.o"
[p]="pad-value:unk" [p]="pad-value:unk"
[Q]="q-precision:unk"
[r]="recursion-depth:unk" [r]="recursion-depth:unk"
[W]="warning:warning" [W]="warning:warning"
) )

View File

@@ -56,6 +56,7 @@ local args=(
'*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'" '*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
'(-o --output)'{-o,--output}'+[Output file]:output file:_files' '(-o --output)'{-o,--output}'+[Output file]:output file:_files'
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:' '(-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:' '(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:'
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbasm_warnings' '(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbasm_warnings'

View File

@@ -11,6 +11,9 @@
#include <stdint.h> #include <stdint.h>
extern uint8_t fixPrecision;
double fix_PrecisionFactor(void);
void fix_Print(int32_t i); void fix_Print(int32_t i);
int32_t fix_Sin(int32_t i); int32_t fix_Sin(int32_t i);
int32_t fix_Cos(int32_t i); int32_t fix_Cos(int32_t i);

View File

@@ -14,7 +14,8 @@
void opt_B(char const chars[2]); void opt_B(char const chars[2]);
void opt_G(char const chars[4]); 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_L(bool optimize);
void opt_W(char const *flag); void opt_W(char const *flag);
void opt_Parse(char const *option); void opt_Parse(char const *option);

View File

@@ -25,6 +25,7 @@
.Op Fl MQ Ar target_file .Op Fl MQ Ar target_file
.Op Fl o Ar out_file .Op Fl o Ar out_file
.Op Fl p Ar pad_value .Op Fl p Ar pad_value
.Op Fl Q Ar fix_precision
.Op Fl r Ar recursion_depth .Op Fl r Ar recursion_depth
.Op Fl W Ar warning .Op Fl W Ar warning
.Ar .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 .It Fl p Ar pad_value , Fl Fl pad-value Ar pad_value
When padding an image, pad with this value. When padding an image, pad with this value.
The default is 0x00. 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 .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. Specifies the recursion depth past which RGBASM will assume being in an infinite loop.
The default is 64. The default is 64.

View File

@@ -208,13 +208,14 @@ section.
The instructions in the macro-language generally require constant expressions. The instructions in the macro-language generally require constant expressions.
.Ss Numeric formats .Ss Numeric formats
There are a number of 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 Sy Format type Ta Sy Prefix Ta Sy Accepted characters
.It Hexadecimal Ta $ Ta 0123456789ABCDEF .It Hexadecimal Ta $ Ta 0123456789ABCDEF
.It Decimal Ta none Ta 0123456789 .It Decimal Ta none Ta 0123456789
.It Octal Ta & Ta 01234567 .It Octal Ta & Ta 01234567
.It Binary Ta % Ta 01 .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 Character constant Ta none Ta \(dqABYZ\(dq
.It Gameboy graphics Ta \` Ta 0123 .It Gameboy graphics Ta \` Ta 0123
.El .El
@@ -301,9 +302,19 @@ and
.Ic \&! .Ic \&!
returns 1 if the operand was 0, and 0 otherwise. returns 1 if the operand was 0, and 0 otherwise.
.Ss Fixed-point expressions .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. Fixed-point numbers are basically normal (32-bit) integers, which count fractions instead of whole numbers.
The upper 16 bits are used for the integer part and the lower 16 bits are used for the fraction (65536ths). They offer better precision than integers but limit the range of values.
Since they are still akin to integers, you can use them in normal integer expressions, and some integer operators like 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 + .Sq +
and and
.Sq - .Sq -
@@ -317,9 +328,9 @@ delim $$
.EN .EN
.Bl -column -offset indent "ATAN2(x, y)" .Bl -column -offset indent "ATAN2(x, y)"
.It Sy Name Ta Sy Operation .It Sy Name Ta Sy Operation
.It Fn DIV x y Ta $x \[di] y$ .It Fn DIV x y Ta Fixed-point division $( x \[di] y ) \[mu] ( 2 ^ precision )$
.It Fn MUL x y Ta $x \[mu] y$ .It Fn MUL x y Ta Fixed-point multiplication $( x \[mu] y ) \[di] ( 2 ^ precision )$
.It Fn FMOD x y Ta $x % y$ .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 POW x y Ta $x$ to the $y$ power
.It Fn LOG x y Ta Logarithm of $x$ to the base $y$ .It Fn LOG x y Ta Logarithm of $x$ to the base $y$
.It Fn ROUND x Ta Round $x$ to the nearest integer .It Fn ROUND x Ta Round $x$ to the nearest integer
@@ -2034,7 +2045,7 @@ POPO
The options that The options that
.Ic OPT .Ic OPT
can modify are currently: can modify are currently:
.Cm b , g , p , r , h , L , .Cm b , g , p , Q , r , h , L ,
and and
.Cm W . .Cm W .
The Boolean flag options The Boolean flag options

View File

@@ -17,17 +17,24 @@
#include "asm/symbol.h" #include "asm/symbol.h"
#include "asm/warning.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 #ifndef M_PI
#define M_PI 3.14159265358979323846 #define M_PI 3.14159265358979323846
#endif #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) void fix_Print(int32_t i)
{ {
uint32_t u = i; uint32_t u = i;
@@ -38,7 +45,7 @@ void fix_Print(int32_t i)
sign = "-"; 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); ((uint32_t)(fix2double(u) * 100000 + 0.5)) % 100000);
} }

View File

@@ -15,6 +15,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "asm/fixpoint.h"
#include "asm/format.h" #include "asm/format.h"
#include "asm/warning.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') { } else if (fmt->type == 'f') {
// Special case for fixed-point // 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; size_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
if (fracWidth > 255) { if (fracWidth > 255) {
@@ -234,7 +235,8 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
fracWidth = 255; fracWidth = 255;
} }
snprintf(valueBuf, sizeof(valueBuf), "%.*f", (int)fracWidth, value / 65536.0); snprintf(valueBuf, sizeof(valueBuf), "%.*f", (int)fracWidth,
value / fix_PrecisionFactor());
} else { } else {
char const *spec = fmt->type == 'd' ? "%" PRId32 char const *spec = fmt->type == 'd' ? "%" PRId32
: fmt->type == 'u' ? "%" PRIu32 : fmt->type == 'u' ? "%" PRIu32

View File

@@ -27,6 +27,7 @@
#include "platform.h" // For `ssize_t` #include "platform.h" // For `ssize_t`
#include "asm/lexer.h" #include "asm/lexer.h"
#include "asm/fixpoint.h"
#include "asm/format.h" #include "asm/format.h"
#include "asm/fstack.h" #include "asm/fstack.h"
#include "asm/macro.h" #include "asm/macro.h"
@@ -1125,17 +1126,28 @@ static uint32_t readNumber(int radix, uint32_t baseValue)
return value; return value;
} }
static uint32_t readFractionalPart(int32_t integer) static uint32_t readFractionalPart(uint32_t integer)
{ {
uint32_t value = 0, divisor = 1; uint32_t value = 0, divisor = 1;
uint8_t precision = 0;
enum {
READFRACTIONALPART_DIGITS,
READFRACTIONALPART_PRECISION,
READFRACTIONALPART_PRECISION_DIGITS,
} state = READFRACTIONALPART_DIGITS;
for (;; shiftChar()) { for (;; shiftChar()) {
int c = peek(); int c = peek();
if (c == '_') if (state == READFRACTIONALPART_DIGITS) {
if (c == '_') {
continue; continue;
else if (c < '0' || c > '9') } else if (c == 'q' || c == 'Q') {
state = READFRACTIONALPART_PRECISION;
continue;
} else if (c < '0' || c > '9') {
break; break;
}
if (divisor > (UINT32_MAX - (c - '0')) / 10) { if (divisor > (UINT32_MAX - (c - '0')) / 10) {
warning(WARNING_LARGE_CONSTANT, warning(WARNING_LARGE_CONSTANT,
"Precision of fixed-point constant is too large\n"); "Precision of fixed-point constant is too large\n");
@@ -1147,17 +1159,33 @@ static uint32_t readFractionalPart(int32_t integer)
} }
value = value * 10 + (c - '0'); value = value * 10 + (c - '0');
divisor *= 10; 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');
}
} }
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"); 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 // 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]; char binDigits[2];
@@ -1741,6 +1769,8 @@ static int yylex_SKIP_TO_ENDC(void); // forward declaration for yylex_NORMAL
static int yylex_NORMAL(void) static int yylex_NORMAL(void)
{ {
uint32_t num = 0;
for (;;) { for (;;) {
int c = nextChar(); int c = nextChar();
char secondChar; char secondChar;
@@ -1912,10 +1942,12 @@ static int yylex_NORMAL(void)
case '7': case '7':
case '8': case '8':
case '9': case '9':
yylval.constValue = readNumber(10, c - '0'); num = readNumber(10, c - '0');
if (peek() == '.') { if (peek() == '.') {
shiftChar(); shiftChar();
yylval.constValue = readFractionalPart(yylval.constValue); yylval.constValue = readFractionalPart(num);
} else {
yylval.constValue = num;
} }
return T_NUMBER; return T_NUMBER;

View File

@@ -19,6 +19,7 @@
#include <time.h> #include <time.h>
#include "asm/charmap.h" #include "asm/charmap.h"
#include "asm/fixpoint.h"
#include "asm/format.h" #include "asm/format.h"
#include "asm/fstack.h" #include "asm/fstack.h"
#include "asm/lexer.h" #include "asm/lexer.h"
@@ -86,7 +87,7 @@ static char *make_escape(char const *str)
} }
// Short options // 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 // Variables for the long-only options
static int depType; // Variants of `-M` static int depType; // Variants of `-M`
@@ -116,6 +117,7 @@ static struct option const longopts[] = {
{ "MQ", required_argument, &depType, 'Q' }, { "MQ", required_argument, &depType, 'Q' },
{ "output", required_argument, NULL, 'o' }, { "output", required_argument, NULL, 'o' },
{ "pad-value", required_argument, NULL, 'p' }, { "pad-value", required_argument, NULL, 'p' },
{ "q-precision", required_argument, NULL, 'Q' },
{ "recursion-depth", required_argument, NULL, 'r' }, { "recursion-depth", required_argument, NULL, 'r' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{ "verbose", no_argument, NULL, 'v' }, { "verbose", no_argument, NULL, 'v' },
@@ -128,7 +130,8 @@ static void print_usage(void)
fputs( fputs(
"Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-i path]\n" "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" " [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n"
" [-o out_file] [-p pad_value] [-r depth] [-W warning] <file>\n" " [-o out_file] [-p pad_value] [-Q precision] [-r depth]\n"
" [-W warning] <file>\n"
"Useful options:\n" "Useful options:\n"
" -E, --export-all export all labels\n" " -E, --export-all export all labels\n"
" -M, --dependfile <path> set the output dependency file\n" " -M, --dependfile <path> set the output dependency file\n"
@@ -170,6 +173,7 @@ int main(int argc, char *argv[])
opt_B("01"); opt_B("01");
opt_G("0123"); opt_G("0123");
opt_P(0); opt_P(0);
opt_Q(16);
haltnop = true; haltnop = true;
warnOnHaltNop = true; warnOnHaltNop = true;
optimizeLoads = true; optimizeLoads = true;
@@ -250,17 +254,34 @@ int main(int argc, char *argv[])
out_SetFileName(musl_optarg); out_SetFileName(musl_optarg);
break; break;
unsigned long fill; unsigned long padByte;
case 'p': case 'p':
fill = strtoul(musl_optarg, &ep, 0); padByte = strtoul(musl_optarg, &ep, 0);
if (musl_optarg[0] == '\0' || *ep != '\0') if (musl_optarg[0] == '\0' || *ep != '\0')
errx("Invalid argument for option 'p'"); errx("Invalid argument for option 'p'");
if (fill > 0xFF) if (padByte > 0xFF)
errx("Argument for option 'p' must be between 0 and 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; break;
case 'r': case 'r':

View File

@@ -14,6 +14,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "asm/fixpoint.h"
#include "asm/fstack.h" #include "asm/fstack.h"
#include "asm/lexer.h" #include "asm/lexer.h"
#include "asm/main.h" #include "asm/main.h"
@@ -23,7 +24,8 @@
struct OptStackEntry { struct OptStackEntry {
char binary[2]; char binary[2];
char gbgfx[4]; char gbgfx[4];
int32_t fillByte; uint8_t fixPrecision;
uint8_t fillByte;
bool haltnop; bool haltnop;
bool warnOnHaltNop; bool warnOnHaltNop;
bool optimizeLoads; bool optimizeLoads;
@@ -47,9 +49,14 @@ void opt_G(char const chars[4])
lexer_SetGfxDigits(chars); 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) void opt_R(size_t newDepth)
@@ -103,18 +110,41 @@ void opt_Parse(char *s)
case 'p': case 'p':
if (strlen(&s[1]) <= 2) { if (strlen(&s[1]) <= 2) {
int result; int result;
unsigned int fillchar; unsigned int padByte;
result = sscanf(&s[1], "%x", &fillchar); result = sscanf(&s[1], "%x", &padByte);
if (result != EOF && result != 1) if (result != 1)
error("Invalid argument for option 'p'\n"); error("Invalid argument for option 'p'\n");
else if (padByte > 0xFF)
error("Argument for option 'p' must be between 0 and 0xFF\n");
else else
opt_P(fillchar); opt_P(padByte);
} else { } else {
error("Invalid argument for option 'p'\n"); error("Invalid argument for option 'p'\n");
} }
break; 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': { case 'r': {
++s; // Skip 'r' ++s; // Skip 'r'
while (isblank(*s)) while (isblank(*s))
@@ -231,6 +261,8 @@ void opt_Push(void)
entry->gbgfx[2] = gfxDigits[2]; entry->gbgfx[2] = gfxDigits[2];
entry->gbgfx[3] = gfxDigits[3]; entry->gbgfx[3] = gfxDigits[3];
entry->fixPrecision = fixPrecision; // Pulled from fixpoint.h
entry->fillByte = fillByte; // Pulled from section.h entry->fillByte = fillByte; // Pulled from section.h
entry->haltnop = haltnop; // Pulled from main.h entry->haltnop = haltnop; // Pulled from main.h
@@ -259,6 +291,7 @@ void opt_Pop(void)
opt_B(entry->binary); opt_B(entry->binary);
opt_G(entry->gbgfx); opt_G(entry->gbgfx);
opt_P(entry->fillByte); opt_P(entry->fillByte);
opt_Q(entry->fixPrecision);
opt_H(entry->warnOnHaltNop); opt_H(entry->warnOnHaltNop);
opt_h(entry->haltnop); opt_h(entry->haltnop);
opt_L(entry->optimizeLoads); opt_L(entry->optimizeLoads);

View File

@@ -12,3 +12,11 @@ fl = 6.283185
fr = MUL(20.0, 0.32) fr = MUL(20.0, 0.32)
println "32% of 20 = {f:fr} (~{.2f:fr}) (~~{.0f:fr})" 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

View File

@@ -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)!

View File

@@ -4,3 +4,5 @@
`16.12`: 16.119995 -> $00101eb8 `16.12`: 16.119995 -> $00101eb8
`6.283185`: 6.283188 -> $0006487f `6.283185`: 6.283188 -> $0006487f
32% of 20 = 6.40015 (~6.40) (~~6) 32% of 20 = 6.40015 (~6.40) (~~6)
Q8 $140 Q16 $14000 Q24 $1400000
$14000

18
test/asm/opt-Q.asm Normal file
View File

@@ -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

7
test/asm/opt-Q.err Normal file
View File

@@ -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)!

33
test/asm/opt-Q.out Normal file
View File

@@ -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

View File

@@ -3,11 +3,13 @@ SECTION "test", ROM0
opt !h, !L ; already the default, but tests parsing "!" opt !h, !L ; already the default, but tests parsing "!"
pusho pusho
opt p42, h, L, Wno-div opt p42, Q.4, h, L, Wno-div
ds 1 ds 1
ld [$ff88], a ld [$ff88], a
halt halt
println $8000_0000 / -1 println $8000_0000 / -1
def n = 3.14
println "{x:n} = {f:n}"
popo popo
opt H, l opt H, l
@@ -16,3 +18,5 @@ popo
ld [$ff88], a ld [$ff88], a
halt halt
println $8000_0000 / -1 println $8000_0000 / -1
def n = 3.14
println "{x:n} = {f:n}"

View File

@@ -1,2 +1,2 @@
warning: opt.asm(18): [-Wdiv] warning: opt.asm(20): [-Wdiv]
Division of -2147483648 by -1 yields -2147483648 Division of -2147483648 by -1 yields -2147483648

View File

@@ -1,2 +1,4 @@
$80000000 $80000000
32 = 3.12500
$80000000 $80000000
323d7 = 3.14000