mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Add unsigned right shift operator
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#define RGBDS_OBJECT_VERSION_STRING "RGB%1u"
|
#define RGBDS_OBJECT_VERSION_STRING "RGB%1u"
|
||||||
#define RGBDS_OBJECT_VERSION_NUMBER 9U
|
#define RGBDS_OBJECT_VERSION_NUMBER 9U
|
||||||
#define RGBDS_OBJECT_REV 8U
|
#define RGBDS_OBJECT_REV 9U
|
||||||
|
|
||||||
enum AssertionType {
|
enum AssertionType {
|
||||||
ASSERT_WARN,
|
ASSERT_WARN,
|
||||||
@@ -49,6 +49,7 @@ enum RPNCommand {
|
|||||||
|
|
||||||
RPN_SHL = 0x40,
|
RPN_SHL = 0x40,
|
||||||
RPN_SHR = 0x41,
|
RPN_SHR = 0x41,
|
||||||
|
RPN_USHR = 0x42,
|
||||||
|
|
||||||
RPN_BANK_SYM = 0x50,
|
RPN_BANK_SYM = 0x50,
|
||||||
RPN_BANK_SECT = 0x51,
|
RPN_BANK_SECT = 0x51,
|
||||||
|
|||||||
@@ -16,5 +16,6 @@ int32_t op_modulo(int32_t dividend, int32_t divisor);
|
|||||||
int32_t op_exponent(int32_t base, uint32_t power);
|
int32_t op_exponent(int32_t base, uint32_t power);
|
||||||
int32_t op_shift_left(int32_t value, int32_t amount);
|
int32_t op_shift_left(int32_t value, int32_t amount);
|
||||||
int32_t op_shift_right(int32_t value, int32_t amount);
|
int32_t op_shift_right(int32_t value, int32_t amount);
|
||||||
|
int32_t op_shift_right_unsigned(int32_t value, int32_t amount);
|
||||||
|
|
||||||
#endif /* RGBDS_OP_MATH_H */
|
#endif /* RGBDS_OP_MATH_H */
|
||||||
|
|||||||
@@ -1890,18 +1890,23 @@ static int yylex_NORMAL(void)
|
|||||||
return T_OP_LOGICLT;
|
return T_OP_LOGICLT;
|
||||||
}
|
}
|
||||||
|
|
||||||
case '>': /* Either >>=, GT, GTE, or right shift */
|
case '>': /* Either >>=, GT, GTE, or either kind of right shift */
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case '=':
|
case '=':
|
||||||
shiftChar();
|
shiftChar();
|
||||||
return T_OP_LOGICGE;
|
return T_OP_LOGICGE;
|
||||||
case '>':
|
case '>':
|
||||||
shiftChar();
|
shiftChar();
|
||||||
if (peek() == '=') {
|
switch (peek()) {
|
||||||
|
case '=':
|
||||||
shiftChar();
|
shiftChar();
|
||||||
return T_POP_SHREQ;
|
return T_POP_SHREQ;
|
||||||
|
case '>':
|
||||||
|
shiftChar();
|
||||||
|
return T_OP_USHR;
|
||||||
|
default:
|
||||||
|
return T_OP_SHR;
|
||||||
}
|
}
|
||||||
return T_OP_SHR;
|
|
||||||
default:
|
default:
|
||||||
return T_OP_LOGICGT;
|
return T_OP_LOGICGT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -534,7 +534,7 @@ enum {
|
|||||||
%token T_OP_LOGICNE "!=" T_OP_LOGICEQU "=="
|
%token T_OP_LOGICNE "!=" T_OP_LOGICEQU "=="
|
||||||
%token T_OP_ADD "+" T_OP_SUB "-"
|
%token T_OP_ADD "+" T_OP_SUB "-"
|
||||||
%token T_OP_OR "|" T_OP_XOR "^" T_OP_AND "&"
|
%token T_OP_OR "|" T_OP_XOR "^" T_OP_AND "&"
|
||||||
%token T_OP_SHL "<<" T_OP_SHR ">>"
|
%token T_OP_SHL "<<" T_OP_SHR ">>" T_OP_USHR ">>>"
|
||||||
%token T_OP_MUL "*" T_OP_DIV "/" T_OP_MOD "%"
|
%token T_OP_MUL "*" T_OP_DIV "/" T_OP_MOD "%"
|
||||||
%token T_OP_NOT "~"
|
%token T_OP_NOT "~"
|
||||||
%left T_OP_LOGICOR
|
%left T_OP_LOGICOR
|
||||||
@@ -542,7 +542,7 @@ enum {
|
|||||||
%left T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE T_OP_LOGICEQU
|
%left T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE T_OP_LOGICEQU
|
||||||
%left T_OP_ADD T_OP_SUB
|
%left T_OP_ADD T_OP_SUB
|
||||||
%left T_OP_OR T_OP_XOR T_OP_AND
|
%left T_OP_OR T_OP_XOR T_OP_AND
|
||||||
%left T_OP_SHL T_OP_SHR
|
%left T_OP_SHL T_OP_SHR T_OP_USHR
|
||||||
%left T_OP_MUL T_OP_DIV T_OP_MOD
|
%left T_OP_MUL T_OP_DIV T_OP_MOD
|
||||||
|
|
||||||
%precedence NEG /* negation -- unary minus */
|
%precedence NEG /* negation -- unary minus */
|
||||||
@@ -1477,6 +1477,9 @@ relocexpr_no_str : scoped_anon_id { rpn_Symbol(&$$, $1); }
|
|||||||
| relocexpr T_OP_SHR relocexpr {
|
| relocexpr T_OP_SHR relocexpr {
|
||||||
rpn_BinaryOp(RPN_SHR, &$$, &$1, &$3);
|
rpn_BinaryOp(RPN_SHR, &$$, &$1, &$3);
|
||||||
}
|
}
|
||||||
|
| relocexpr T_OP_USHR relocexpr {
|
||||||
|
rpn_BinaryOp(RPN_USHR, &$$, &$1, &$3);
|
||||||
|
}
|
||||||
| relocexpr T_OP_MUL relocexpr {
|
| relocexpr T_OP_MUL relocexpr {
|
||||||
rpn_BinaryOp(RPN_MUL, &$$, &$1, &$3);
|
rpn_BinaryOp(RPN_MUL, &$$, &$1, &$3);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,7 +251,9 @@ A great number of operators you can use in expressions are available (listed fro
|
|||||||
.It Li ** Ta Exponent
|
.It Li ** Ta Exponent
|
||||||
.It Li ~ + - Ta Unary complement/plus/minus
|
.It Li ~ + - Ta Unary complement/plus/minus
|
||||||
.It Li * / % Ta Multiply/divide/modulo
|
.It Li * / % Ta Multiply/divide/modulo
|
||||||
.It Li << >> Ta Shift left/right
|
.It Li << Ta Shift left
|
||||||
|
.It Li >> Ta Signed shift right (sign-extension)
|
||||||
|
.It Li >>> Ta Unsigned shift right (zero-extension)
|
||||||
.It Li & \&| ^ Ta Binary and/or/xor
|
.It Li & \&| ^ Ta Binary and/or/xor
|
||||||
.It Li + - Ta Add/subtract
|
.It Li + - Ta Add/subtract
|
||||||
.It Li != == <= >= < > Ta Comparison
|
.It Li != == <= >= < > Ta Comparison
|
||||||
|
|||||||
@@ -421,6 +421,19 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
|||||||
|
|
||||||
expr->val = op_shift_right(src1->val, src2->val);
|
expr->val = op_shift_right(src1->val, src2->val);
|
||||||
break;
|
break;
|
||||||
|
case RPN_USHR:
|
||||||
|
if (src2->val < 0)
|
||||||
|
warning(WARNING_SHIFT_AMOUNT,
|
||||||
|
"Shifting right by negative amount %" PRId32 "\n",
|
||||||
|
src2->val);
|
||||||
|
|
||||||
|
if (src2->val >= 32)
|
||||||
|
warning(WARNING_SHIFT_AMOUNT,
|
||||||
|
"Shifting right by large amount %" PRId32 "\n",
|
||||||
|
src2->val);
|
||||||
|
|
||||||
|
expr->val = op_shift_right_unsigned(src1->val, src2->val);
|
||||||
|
break;
|
||||||
case RPN_MUL:
|
case RPN_MUL:
|
||||||
expr->val = uleft * uright;
|
expr->val = uleft * uright;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -265,6 +265,10 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
value = popRPN();
|
value = popRPN();
|
||||||
value = op_shift_right(popRPN(), value);
|
value = op_shift_right(popRPN(), value);
|
||||||
break;
|
break;
|
||||||
|
case RPN_USHR:
|
||||||
|
value = popRPN();
|
||||||
|
value = op_shift_right_unsigned(popRPN(), value);
|
||||||
|
break;
|
||||||
|
|
||||||
case RPN_BANK_SYM:
|
case RPN_BANK_SYM:
|
||||||
value = 0;
|
value = 0;
|
||||||
|
|||||||
15
src/opmath.c
15
src/opmath.c
@@ -86,3 +86,18 @@ int32_t op_shift_right(int32_t value, int32_t amount)
|
|||||||
// undefined, so use a left shift manually sign-extended
|
// undefined, so use a left shift manually sign-extended
|
||||||
return ((uint32_t)value >> amount) | amount_high_bits;
|
return ((uint32_t)value >> amount) | amount_high_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t op_shift_right_unsigned(int32_t value, int32_t amount)
|
||||||
|
{
|
||||||
|
// Repeat the easy cases here to avoid INT_MIN funny business
|
||||||
|
if (amount == 0)
|
||||||
|
return value;
|
||||||
|
if (value == 0 || amount <= -32)
|
||||||
|
return 0;
|
||||||
|
if (amount > 31)
|
||||||
|
return (value < 0) ? -1 : 0;
|
||||||
|
if (amount < 0)
|
||||||
|
return op_shift_left(value, -amount);
|
||||||
|
|
||||||
|
return (uint32_t)value >> amount;
|
||||||
|
}
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ with some bytes being special prefixes for integers and symbols.
|
|||||||
.It Li $35 Ta Li <= comparison
|
.It Li $35 Ta Li <= comparison
|
||||||
.It Li $40 Ta Li << operator
|
.It Li $40 Ta Li << operator
|
||||||
.It Li $41 Ta Li >> operator
|
.It Li $41 Ta Li >> operator
|
||||||
|
.It Li $42 Ta Li >>> operator
|
||||||
.It Li $50 Ta Li BANK(symbol) ,
|
.It Li $50 Ta Li BANK(symbol) ,
|
||||||
a
|
a
|
||||||
.Ar LONG
|
.Ar LONG
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
macro test
|
macro test
|
||||||
; Test the rpn system, as well as the linker...
|
; Test the rpn system, as well as the linker...
|
||||||
DEF expr EQUS STRRPL(STRRPL("\1 + zero)", "<<", "<< ("), ">>", ">> (")
|
DEF expr EQUS STRRPL(STRRPL("\1 + zero)", "<< ", "<< ("), ">> ", ">> (")
|
||||||
dl expr
|
dl expr
|
||||||
PURGE expr
|
PURGE expr
|
||||||
|
|
||||||
@@ -24,5 +24,8 @@ section "test", ROM0[0]
|
|||||||
test -4 >> 2
|
test -4 >> 2
|
||||||
test -1 >> -9001
|
test -1 >> -9001
|
||||||
|
|
||||||
|
test $DEADBEEF >> 1
|
||||||
|
test $DEADBEEF >>> 1
|
||||||
|
|
||||||
SECTION "Zero", ROM0[0]
|
SECTION "Zero", ROM0[0]
|
||||||
zero:
|
zero:
|
||||||
|
|||||||
@@ -24,3 +24,5 @@ warning: shift.asm(25) -> shift.asm::test(8): [-Wshift]
|
|||||||
Shifting right negative value -1
|
Shifting right negative value -1
|
||||||
warning: shift.asm(25) -> shift.asm::test(8): [-Wshift-amount]
|
warning: shift.asm(25) -> shift.asm::test(8): [-Wshift-amount]
|
||||||
Shifting right by negative amount -9001
|
Shifting right by negative amount -9001
|
||||||
|
warning: shift.asm(27) -> shift.asm::test(8): [-Wshift]
|
||||||
|
Shifting right negative value -559038737
|
||||||
|
|||||||
@@ -10,3 +10,5 @@
|
|||||||
-4 >> 1 = $FFFFFFFE
|
-4 >> 1 = $FFFFFFFE
|
||||||
-4 >> 2 = $FFFFFFFF
|
-4 >> 2 = $FFFFFFFF
|
||||||
-1 >> -9001 = $0
|
-1 >> -9001 = $0
|
||||||
|
$DEADBEEF >> 1 = $EF56DF77
|
||||||
|
$DEADBEEF >>> 1 = $6F56DF77
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user