mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
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:
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
29
man/rgbasm.5
29
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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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,17 +1126,28 @@ 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 == '_')
|
||||
if (state == READFRACTIONALPART_DIGITS) {
|
||||
if (c == '_') {
|
||||
continue;
|
||||
else if (c < '0' || c > '9')
|
||||
} 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");
|
||||
@@ -1147,17 +1159,33 @@ static uint32_t readFractionalPart(int32_t integer)
|
||||
}
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#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] <file>\n"
|
||||
" [-o out_file] [-p pad_value] [-Q precision] [-r depth]\n"
|
||||
" [-W warning] <file>\n"
|
||||
"Useful options:\n"
|
||||
" -E, --export-all export all labels\n"
|
||||
" -M, --dependfile <path> 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':
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)!
|
||||
|
||||
@@ -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
|
||||
|
||||
18
test/asm/opt-Q.asm
Normal file
18
test/asm/opt-Q.asm
Normal 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
7
test/asm/opt-Q.err
Normal 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
33
test/asm/opt-Q.out
Normal 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
|
||||
@@ -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}"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
warning: opt.asm(18): [-Wdiv]
|
||||
warning: opt.asm(20): [-Wdiv]
|
||||
Division of -2147483648 by -1 yields -2147483648
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
$80000000
|
||||
32 = 3.12500
|
||||
$80000000
|
||||
323d7 = 3.14000
|
||||
|
||||
Reference in New Issue
Block a user