diff --git a/docs/rgbds.5.html b/docs/rgbds.5.html
index 4ea892e5..93a6f218 100644
--- a/docs/rgbds.5.html
+++ b/docs/rgbds.5.html
@@ -121,6 +121,7 @@ REPT NumberOfSections
BYTE Type ; 0 = BYTE patch.
; 1 = little endian WORD patch.
; 2 = little endian LONG patch.
+ ; 3 = JR offset value BYTE patch.
LONG RPNSize ; Size of the buffer with the RPN.
; expression.
diff --git a/include/linkdefs.h b/include/linkdefs.h
index 3fb5c0a7..b0ec4ee9 100644
--- a/include/linkdefs.h
+++ b/include/linkdefs.h
@@ -66,7 +66,8 @@ enum eSymbolType {
enum ePatchType {
PATCH_BYTE = 0x00,
PATCH_WORD_L = 0x01,
- PATCH_LONG_L = 0x02
+ PATCH_LONG_L = 0x02,
+ PATCH_BYTE_JR = 0x03
};
#endif /* RGBDS_LINKDEFS_H */
diff --git a/src/asm/asmy.y b/src/asm/asmy.y
index accfd083..ab7769df 100644
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -455,7 +455,6 @@ static void updateUnion(void)
%type const_3bit
%type const_8bit
%type const_16bit
-%type const_PCrel
%type sectiontype
%type string
@@ -1116,14 +1115,6 @@ constlist_32bit_entry_single : /* empty */
}
;
-const_PCrel : relocconst
- {
- if (!rpn_isPCRelative(&$1))
- yyerror("Expression must be PC-relative");
- $$ = $1;
- }
-;
-
const_8bit : relocconst
{
if( (!rpn_isReloc(&$1)) && (($1.nVal < -128) || ($1.nVal > 255)) )
@@ -1612,12 +1603,12 @@ z80_jp : T_Z80_JP const_16bit
}
;
-z80_jr : T_Z80_JR const_PCrel
+z80_jr : T_Z80_JR const_16bit
{
out_AbsByte(0x18);
out_PCRelByte(&$2);
}
- | T_Z80_JR ccode comma const_PCrel
+ | T_Z80_JR ccode comma const_16bit
{
out_AbsByte(0x20 | ($2 << 3));
out_PCRelByte(&$4);
diff --git a/src/asm/output.c b/src/asm/output.c
index 53569eb3..db85c0d7 100644
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -593,7 +593,7 @@ void out_SetFileName(char *s)
}
/*
- * Find a section by name and type. If it doesn't exist, create it
+ * Find a section by name and type. If it doesn't exist, create it
*/
struct Section *out_FindSection(char *pzName, uint32_t secttype, int32_t org,
int32_t bank, int32_t alignment)
@@ -764,7 +764,7 @@ void out_String(char *s)
}
/*
- * Output a relocatable byte. Checking will be done to see if it
+ * Output a relocatable byte. Checking will be done to see if it
* is an absolute value in disguise.
*/
void out_RelByte(struct Expression *expr)
@@ -803,7 +803,7 @@ void out_AbsWord(int32_t b)
}
/*
- * Output a relocatable word. Checking will be done to see if
+ * Output a relocatable word. Checking will be done to see if
* it's an absolute value in disguise.
*/
void out_RelWord(struct Expression *expr)
@@ -847,7 +847,7 @@ void out_AbsLong(int32_t b)
}
/*
- * Output a relocatable longword. Checking will be done to see if
+ * Output a relocatable longword. Checking will be done to see if
* is an absolute value in disguise.
*/
void out_RelLong(struct Expression *expr)
@@ -875,19 +875,31 @@ void out_RelLong(struct Expression *expr)
}
/*
- * Output a PC-relative byte
+ * Output a PC-relative relocatable byte. Checking will be done to see if it
+ * is an absolute value in disguise.
*/
void out_PCRelByte(struct Expression *expr)
{
- int32_t b = expr->nVal;
-
checkcodesection();
checksectionoverflow(1);
- b = (b & 0xFFFF) - (nPC + 1);
- if (nPass == 2 && (b < -128 || b > 127))
- yyerror("PC-relative value must be 8-bit");
+ if (rpn_isReloc(expr)) {
+ if (nPass == 2) {
+ pCurrentSection->tData[nPC] = 0;
+ createpatch(PATCH_BYTE_JR, expr);
+ }
+ pCurrentSection->nPC += 1;
+ nPC += 1;
+ pPCSymbol->nValue += 1;
+ } else {
+ int32_t b = expr->nVal;
- out_AbsByte(b);
+ b = (int16_t)((b & 0xFFFF) - (nPC + 1));
+
+ if (nPass == 2 && ((b < -128) || (b > 127)))
+ yyerror("PC-relative value must be 8-bit");
+
+ out_AbsByte(b & 0xFF);
+ }
rpn_Reset(expr);
}
diff --git a/src/link/patch.c b/src/link/patch.c
index e8f405b6..3c600a91 100644
--- a/src/link/patch.c
+++ b/src/link/patch.c
@@ -267,6 +267,7 @@ void Patch(void)
pPatch = pSect->pPatches;
while (pPatch) {
int32_t t;
+ int32_t nPatchOrg;
nPC = pSect->nOrg + pPatch->nOffset;
t = calcrpn(pPatch);
@@ -306,6 +307,24 @@ void Patch(void)
pSect->pData[pPatch->nOffset + 3] =
(t >> 24) & 0xFF;
break;
+ case PATCH_BYTE_JR:
+ /* Calculate absolute address of the patch */
+ nPatchOrg = pSect->nOrg + pPatch->nOffset;
+
+ /* t contains the destination of the jump */
+ t = (int16_t)((t & 0xFFFF) - (nPatchOrg + 1));
+
+ if (t >= -128 && t <= 255) {
+ t &= 0xFF;
+ pSect->pData[pPatch->nOffset] =
+ (uint8_t)t;
+ } else {
+ errx(1,
+ "%s(%ld) : Value must be 8-bit",
+ pPatch->pzFilename,
+ pPatch->nLineNo);
+ }
+ break;
}
pPatch = pPatch->pNext;
diff --git a/src/rgbds.5 b/src/rgbds.5
index 30d80743..8bfa3dab 100644
--- a/src/rgbds.5
+++ b/src/rgbds.5
@@ -113,6 +113,7 @@ REPT NumberOfSections
BYTE Type ; 0 = BYTE patch.
; 1 = little endian WORD patch.
; 2 = little endian LONG patch.
+ ; 3 = JR offset value BYTE patch.
LONG RPNSize ; Size of the buffer with the RPN.
; expression.