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:
ISSOtm
2020-07-27 18:11:42 +02:00
parent b1adbcc77c
commit 762474d3ac
13 changed files with 47 additions and 25 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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
View 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
View File

0
test/asm/jr-@.out Normal file
View File

1
test/asm/jr-@.out.bin Normal file
View File

@@ -0,0 +1 @@
<18><18>

5
test/asm/jr-section.asm Normal file
View File

@@ -0,0 +1,5 @@
SECTION "Test", ROM0
Label:
jr Label
PRINTV Label - @

0
test/asm/jr-section.err Normal file
View File

1
test/asm/jr-section.out Normal file
View File

@@ -0,0 +1 @@
$FFFFFFFE

View File

@@ -0,0 +1 @@
<18>

View File

@@ -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 @

View File

@@ -1 +1 @@
<18><18> <18>