ref: eb5af70d79cd35d4383d7746a0190ce423119344
parent: cf19879281a953cbf754673be9a212c874971857
author: ISSOtm <eldredhabert0@gmail.com>
date: Sat Feb 5 06:27:41 EST 2022
Add unsigned right shift operator
--- a/include/linkdefs.h
+++ b/include/linkdefs.h
@@ -14,7 +14,7 @@
#define RGBDS_OBJECT_VERSION_STRING "RGB%1u"
#define RGBDS_OBJECT_VERSION_NUMBER 9U
-#define RGBDS_OBJECT_REV 8U
+#define RGBDS_OBJECT_REV 9U
enum AssertionType {
ASSERT_WARN,
@@ -49,6 +49,7 @@
RPN_SHL = 0x40,
RPN_SHR = 0x41,
+ RPN_USHR = 0x42,
RPN_BANK_SYM = 0x50,
RPN_BANK_SECT = 0x51,
--- a/include/opmath.h
+++ b/include/opmath.h
@@ -16,5 +16,6 @@
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_right(int32_t value, int32_t amount);
+int32_t op_shift_right_unsigned(int32_t value, int32_t amount);
#endif /* RGBDS_OP_MATH_H */
--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -1890,7 +1890,7 @@
return T_OP_LOGICLT;
}
- case '>': /* Either >>=, GT, GTE, or right shift */
+ case '>': /* Either >>=, GT, GTE, or either kind of right shift */
switch (peek()) {
case '=':
shiftChar();
@@ -1897,11 +1897,16 @@
return T_OP_LOGICGE;
case '>':
shiftChar();
- if (peek() == '=') {
+ switch (peek()) {
+ case '=':
shiftChar();
return T_POP_SHREQ;
+ case '>':
+ shiftChar();
+ return T_OP_USHR;
+ default:
+ return T_OP_SHR;
}
- return T_OP_SHR;
default:
return T_OP_LOGICGT;
}
--- a/src/asm/parser.y
+++ b/src/asm/parser.y
@@ -534,7 +534,7 @@
%token T_OP_LOGICNE "!=" T_OP_LOGICEQU "=="
%token T_OP_ADD "+" T_OP_SUB "-"
%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_NOT "~"
%left T_OP_LOGICOR
@@ -542,7 +542,7 @@
%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_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
%precedence NEG /* negation -- unary minus */
@@ -1476,6 +1476,9 @@
}
| relocexpr T_OP_SHR relocexpr {
rpn_BinaryOp(RPN_SHR, &$$, &$1, &$3);
+ }
+ | relocexpr T_OP_USHR relocexpr {
+ rpn_BinaryOp(RPN_USHR, &$$, &$1, &$3);
}
| relocexpr T_OP_MUL relocexpr {
rpn_BinaryOp(RPN_MUL, &$$, &$1, &$3);
--- a/src/asm/rgbasm.5
+++ b/src/asm/rgbasm.5
@@ -251,7 +251,9 @@
.It Li ** Ta Exponent
.It Li ~ + - Ta Unary complement/plus/minus
.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 Add/subtract
.It Li != == <= >= < > Ta Comparison
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -421,6 +421,19 @@
expr->val = op_shift_right(src1->val, src2->val);
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:
expr->val = uleft * uright;
break;
--- a/src/link/patch.c
+++ b/src/link/patch.c
@@ -265,6 +265,10 @@
value = popRPN();
value = op_shift_right(popRPN(), value);
break;
+ case RPN_USHR:
+ value = popRPN();
+ value = op_shift_right_unsigned(popRPN(), value);
+ break;
case RPN_BANK_SYM:
value = 0;
--- a/src/opmath.c
+++ b/src/opmath.c
@@ -86,3 +86,18 @@
// undefined, so use a left shift manually sign-extended
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;
+}
--- a/src/rgbds.5
+++ b/src/rgbds.5
@@ -241,6 +241,7 @@
.It Li $35 Ta Li <= comparison
.It Li $40 Ta Li << operator
.It Li $41 Ta Li >> operator
+.It Li $42 Ta Li >>> operator
.It Li $50 Ta Li BANK(symbol) ,
a
.Ar LONG
--- a/test/asm/shift.asm
+++ b/test/asm/shift.asm
@@ -1,6 +1,6 @@
macro test
; 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
PURGE expr
@@ -23,6 +23,9 @@
test -4 >> 1
test -4 >> 2
test -1 >> -9001
+
+ test $DEADBEEF >> 1
+ test $DEADBEEF >>> 1
SECTION "Zero", ROM0[0]
zero:
--- a/test/asm/shift.err
+++ b/test/asm/shift.err
@@ -24,3 +24,5 @@
Shifting right negative value -1
warning: shift.asm(25) -> shift.asm::test(8): [-Wshift-amount]
Shifting right by negative amount -9001
+warning: shift.asm(27) -> shift.asm::test(8): [-Wshift]
+ Shifting right negative value -559038737
--- a/test/asm/shift.out
+++ b/test/asm/shift.out
@@ -10,3 +10,5 @@
-4 >> 1 = $FFFFFFFE
-4 >> 2 = $FFFFFFFF
-1 >> -9001 = $0
+$DEADBEEF >> 1 = $EF56DF77
+$DEADBEEF >>> 1 = $6F56DF77
binary files a/test/asm/shift.out.bin b/test/asm/shift.out.bin differ