mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Let RGBASM write JR offsets in floating sections
This requires some special-casing for `jr @` because the `jr` opcode has already been emitted, but not the operand, so PC points to the middle. Moved the RGBLINK test to RGBASM's folder, and created a new RGBLINK test.
This commit is contained in:
@@ -49,6 +49,8 @@ static inline bool rpn_isSymbol(const struct Expression *expr)
|
|||||||
void rpn_Symbol(struct Expression *expr, char *tzSym);
|
void rpn_Symbol(struct Expression *expr, char *tzSym);
|
||||||
void rpn_Number(struct Expression *expr, uint32_t i);
|
void rpn_Number(struct Expression *expr, uint32_t i);
|
||||||
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
|
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
|
||||||
|
struct Symbol const *rpn_SymbolOf(struct Expression const *expr);
|
||||||
|
bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *sym);
|
||||||
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||||
const struct Expression *src1,
|
const struct Expression *src1,
|
||||||
const struct Expression *src2);
|
const struct Expression *src2);
|
||||||
|
|||||||
@@ -297,25 +297,28 @@ static int32_t shift(int32_t shiftee, int32_t amount)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct Symbol const *symbolOf(struct Expression const *expr)
|
struct Symbol const *rpn_SymbolOf(struct Expression const *expr)
|
||||||
{
|
{
|
||||||
if (!rpn_isSymbol(expr))
|
if (!rpn_isSymbol(expr))
|
||||||
return NULL;
|
return NULL;
|
||||||
return sym_FindSymbol((char *)expr->tRPN + 1);
|
return sym_FindSymbol((char *)expr->tRPN + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *sym)
|
||||||
|
{
|
||||||
|
/* Check if both expressions only refer to a single symbol */
|
||||||
|
struct Symbol const *sym1 = rpn_SymbolOf(src);
|
||||||
|
|
||||||
|
if (!sym1 || !sym || sym1->type != SYM_LABEL || sym->type != SYM_LABEL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return sym_GetSection(sym1) == sym_GetSection(sym);
|
||||||
|
}
|
||||||
|
|
||||||
static bool isDiffConstant(struct Expression const *src1,
|
static bool isDiffConstant(struct Expression const *src1,
|
||||||
struct Expression const *src2)
|
struct Expression const *src2)
|
||||||
{
|
{
|
||||||
/* Check if both expressions only refer to a single symbol */
|
return rpn_IsDiffConstant(src1, rpn_SymbolOf(src2));
|
||||||
struct Symbol const *symbol1 = symbolOf(src1);
|
|
||||||
struct Symbol const *symbol2 = symbolOf(src2);
|
|
||||||
|
|
||||||
if (!symbol1 || !symbol2
|
|
||||||
|| symbol1->type != SYM_LABEL || symbol2->type != SYM_LABEL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return sym_GetSection(symbol1) == sym_GetSection(symbol2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||||
@@ -428,8 +431,8 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
|
} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
|
||||||
struct Symbol const *symbol1 = symbolOf(src1);
|
struct Symbol const *symbol1 = rpn_SymbolOf(src1);
|
||||||
struct Symbol const *symbol2 = symbolOf(src2);
|
struct Symbol const *symbol2 = rpn_SymbolOf(src2);
|
||||||
|
|
||||||
expr->nVal = sym_GetValue(symbol1) - sym_GetValue(symbol2);
|
expr->nVal = sym_GetValue(symbol1) - sym_GetValue(symbol2);
|
||||||
expr->isKnown = true;
|
expr->isKnown = true;
|
||||||
|
|||||||
@@ -553,15 +553,21 @@ void out_PCRelByte(struct Expression *expr)
|
|||||||
{
|
{
|
||||||
checkcodesection();
|
checkcodesection();
|
||||||
reserveSpace(1);
|
reserveSpace(1);
|
||||||
|
struct Symbol const *pc = sym_FindSymbol("@");
|
||||||
|
|
||||||
if (!rpn_isKnown(expr) || pCurrentSection->nOrg == -1) {
|
if (!rpn_IsDiffConstant(expr, pc)) {
|
||||||
createPatch(PATCHTYPE_JR, expr);
|
createPatch(PATCHTYPE_JR, expr);
|
||||||
writebyte(0);
|
writebyte(0);
|
||||||
} else {
|
} else {
|
||||||
/* Target is relative to the byte *after* the operand */
|
struct Symbol const *sym = rpn_SymbolOf(expr);
|
||||||
uint16_t address = sym_GetPCValue() + 1;
|
/* The offset wraps (jump from ROM to HRAM, for example) */
|
||||||
/* The offset wraps (jump from ROM to HRAM, for loopexample) */
|
int16_t offset;
|
||||||
int16_t offset = expr->nVal - address;
|
|
||||||
|
/* Offset is relative to the byte *after* the operand */
|
||||||
|
if (sym == pc)
|
||||||
|
offset = -2; /* PC as operand to `jr` is lower than reference PC by 2 */
|
||||||
|
else
|
||||||
|
offset = sym_GetValue(sym) - (sym_GetValue(pc) + 1);
|
||||||
|
|
||||||
if (offset < -128 || offset > 127) {
|
if (offset < -128 || offset > 127) {
|
||||||
yyerror("jr target out of reach (expected -129 < %" PRId16 " < 128)",
|
yyerror("jr target out of reach (expected -129 < %" PRId16 " < 128)",
|
||||||
|
|||||||
7
test/asm/jr-@.asm
Normal file
7
test/asm/jr-@.asm
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
SECTION "fixed", ROM0[0]
|
||||||
|
jr @
|
||||||
|
; We need this section to be floating because RGBASM can know the value of PC
|
||||||
|
; otherwise, leading to different behavior
|
||||||
|
; FIXME: we rely on this landing at address 2, which isn't *guaranteed*...
|
||||||
|
SECTION "floating", ROM0
|
||||||
|
jr @
|
||||||
0
test/asm/jr-@.err
Normal file
0
test/asm/jr-@.err
Normal file
0
test/asm/jr-@.out
Normal file
0
test/asm/jr-@.out
Normal file
1
test/asm/jr-@.out.bin
Normal file
1
test/asm/jr-@.out.bin
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<18><18>
|
||||||
5
test/asm/jr-section.asm
Normal file
5
test/asm/jr-section.asm
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
SECTION "Test", ROM0
|
||||||
|
|
||||||
|
Label:
|
||||||
|
jr Label
|
||||||
|
PRINTV Label - @
|
||||||
0
test/asm/jr-section.err
Normal file
0
test/asm/jr-section.err
Normal file
1
test/asm/jr-section.out
Normal file
1
test/asm/jr-section.out
Normal file
@@ -0,0 +1 @@
|
|||||||
|
$FFFFFFFE
|
||||||
1
test/asm/jr-section.out.bin
Normal file
1
test/asm/jr-section.out.bin
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<18>
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
SECTION "fixed", ROM0[0]
|
SECTION "Floating", ROM0
|
||||||
jr @
|
; RGBASM knows how to compute `jr @` by itself, but this will evade it
|
||||||
; We need this section to be floating because RGBASM can know the value of PC
|
jr @ - 1 + 1
|
||||||
; otherwise, leading to different behavior
|
|
||||||
; FIXME: we rely on this landing at address 2, which isn't *guaranteed*...
|
|
||||||
SECTION "floating", ROM0
|
|
||||||
jr @
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<18><18>
|
<18>
|
||||||
Reference in New Issue
Block a user