diff --git a/docs/vc_patch.md b/docs/vc_patch.md index 38d0a3b87..1dbd022e0 100644 --- a/docs/vc_patch.md +++ b/docs/vc_patch.md @@ -83,8 +83,10 @@ Some commands may output a **value series**, which is a series of two-digit hexa - Literal numbers in decimal (base 10, e.g. "`42`"), hexadecimal (base 16, e.g. "`0x2a`"), or octal (base 8, e.g. "`052`"). They may start with a plus sign "`+`". Numbers should not be negative. - Comparison operators: "`==`" is 0, "`>`" is 1, "`<`" is 2, "`>=`" is 3, "`<=`" is 4, "`!=`" is 5, and "`||`" is 0x11. -- Symbol names from the two `.sym` files provided to `make_patch` may evaluate as their relative address or their absolute offset, depending on the command. (Addresses are relative to the symbol's bank for ROM addresses, or to 0x8000, the start of all RAM, for RAM addresses.) They may also be followed by a plus sign and a literal number that gets added to the value. -- "`@`" evaluates as the address or absolute offset of the current patch/hook label, depending on the command. +- Symbol names from the `.sym` file provided to `make_patch` may evaluate as their relative address or their absolute offset, depending on the command. (Addresses are relative to the symbol's bank for ROM addresses, or to 0x8000, the start of all RAM, for RAM addresses.) + - Symbol names may be preceded by a less-than sign "`<`" to take only the low byte, or a greater-than sign "`>`" to take only the high byte. + - Symbol names may be followed by a plus sign "`+`" and a literal number that gets added to the value. +- "`@`" evaluates as the relative address or absolute offset of the current patch/hook label, depending on the command. It maybe be preceded by a "`<`" or "`>`", or followed by a "`+`" literal, like symbol names. Any other characters are output as-is. diff --git a/tools/make_patch.c b/tools/make_patch.c index 06216ec7f..9682af39c 100644 --- a/tools/make_patch.c +++ b/tools/make_patch.c @@ -183,6 +183,16 @@ int parse_arg_value(const char *arg, bool absolute, const struct Symbol *symbols return parse_number(arg, 0); } + // Symbols may take the low or high part + enum { SYM_WHOLE, SYM_LOW, SYM_HIGH } part = SYM_WHOLE; + if (arg[0] == '<') { + part = SYM_LOW; + arg++; + } else if (arg[0] == '>') { + part = SYM_HIGH; + arg++; + } + // Symbols evaluate to their offset or address, plus an optional offset mod int offset_mod = 0; char *plus = strchr(arg, '+'); @@ -190,9 +200,13 @@ int parse_arg_value(const char *arg, bool absolute, const struct Symbol *symbols offset_mod = parse_number(plus, 0); *plus = '\0'; } + + // Symbols evaluate to their offset or address const char *sym_name = !strcmp(arg, "@") ? patch_name : arg; // "@" is the current patch label const struct Symbol *symbol = symbol_find(symbols, sym_name); - return (absolute ? symbol->offset : symbol->address) + offset_mod; + + int value = (absolute ? symbol->offset : symbol->address) + offset_mod; + return part == SYM_LOW ? value & 0xff : part == SYM_HIGH ? value >> 8 : value; } void interpret_command(char *command, const struct Symbol *current_hook, const struct Symbol *symbols, struct Buffer *patches, FILE *restrict new_rom, FILE *restrict orig_rom, FILE *restrict output) {