diff --git a/src/asm/lexer.c b/src/asm/lexer.c index 493b2fea14..c395694e5e 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -180,6 +180,9 @@ static struct KeywordMapping { {"BANK", T_OP_BANK}, {"ALIGN", T_OP_ALIGN}, + {"MIN", T_OP_MIN}, + {"MAX", T_OP_MAX}, + {"ROUND", T_OP_ROUND}, {"CEIL", T_OP_CEIL}, {"FLOOR", T_OP_FLOOR}, @@ -496,7 +499,7 @@ struct KeywordDictNode { uint16_t children[0x60 - ' ']; struct KeywordMapping const *keyword; /* Since the keyword structure is invariant, the min number of nodes is known at compile time */ -} keywordDict[350] = {0}; /* Make sure to keep this correct when adding keywords! */ +} keywordDict[353] = {0}; /* Make sure to keep this correct when adding keywords! */ /* Convert a char into its index into the dict */ static inline uint8_t dictIndex(char c) diff --git a/src/asm/parser.y b/src/asm/parser.y index 287b0e3e82..6f43a2aa98 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -441,6 +441,8 @@ enum { %type uconst %type rs_uconst %type const_3bit +%type min_args +%type max_args %type reloc_8bit %type reloc_8bit_no_str %type reloc_16bit @@ -493,6 +495,7 @@ enum { %token T_OP_DEF "DEF" %token T_OP_BANK "BANK" %token T_OP_ALIGN "ALIGN" +%token T_OP_MIN "MIN" T_OP_MAX "MAX" %token T_OP_SIN "SIN" T_OP_COS "COS" T_OP_TAN "TAN" %token T_OP_ASIN "ASIN" T_OP_ACOS "ACOS" T_OP_ATAN "ATAN" T_OP_ATAN2 "ATAN2" %token T_OP_FDIV "FDIV" @@ -1354,6 +1357,8 @@ relocexpr_no_str : scoped_anon_id { rpn_Symbol(&$$, $1); } lexer_ToggleStringExpansion(true); } + | T_OP_MIN T_LPAREN min_args T_RPAREN { rpn_Number(&$$, $3); } + | T_OP_MAX T_LPAREN max_args T_RPAREN { rpn_Number(&$$, $3); } | T_OP_ROUND T_LPAREN const T_RPAREN { rpn_Number(&$$, math_Round($3)); } @@ -1445,6 +1450,18 @@ const_no_str : relocexpr_no_str { } ; +min_args : const + | min_args T_COMMA const { + $$ = $1 < $3 ? $1 : $3; + } +; + +max_args : const + | max_args T_COMMA const { + $$ = $1 > $3 ? $1 : $3; + } +; + string : T_STRING | T_OP_STRSUB T_LPAREN string T_COMMA uconst T_COMMA uconst T_RPAREN { strsubUTF8($$, sizeof($$), $3, $5, $7); diff --git a/src/asm/rgbasm.5 b/src/asm/rgbasm.5 index e0956f2aa0..4c49200d51 100644 --- a/src/asm/rgbasm.5 +++ b/src/asm/rgbasm.5 @@ -444,6 +444,8 @@ String symbols are not expanded within the parentheses. .It Fn ISCONST arg Ta Returns 1 if Ar arg Ap s value is known by RGBASM (e.g. if it can be an argument to .Ic IF ) , or 0 if only RGBLINK can compute its value. +.It Fn MIN args... Ta Returns the minimum operand, given at least one numeric operand. +.It Fn MAX args... Ta Returns the maximum operand, given at least one numeric operand. .El .Sh SECTIONS Before you can start writing code, you must define a section. diff --git a/test/asm/math.asm b/test/asm/math.asm index 7411bb32d7..a225870c93 100644 --- a/test/asm/math.asm +++ b/test/asm/math.asm @@ -16,6 +16,14 @@ ENDM test (v 1) << (v 30) == (v $4000_0000) test (v 2)**(v 30) == (v $4000_0000) + assert MIN(42) == 42 + assert MIN(-10, 10) == -10 + assert MIN(2, 1, 4, 3) == 1 + + assert MAX(42) == 42 + assert MAX(-10, 10) == 10 + assert MAX(2, 1, 4, 3) == 4 + assert DIV(5.0, 2.0) == 2.5 assert DIV(-5.0, 2.0) == -2.5 assert DIV(-5.0, 0.0) == $8000_0000