diff --git a/include/asm/lexer.h b/include/asm/lexer.h index 9146094f..fccdc2dc 100644 --- a/include/asm/lexer.h +++ b/include/asm/lexer.h @@ -83,4 +83,11 @@ int yylex(void); void lexer_CaptureRept(struct CaptureBody *capture); void lexer_CaptureMacroBody(struct CaptureBody *capture); +#define INITIAL_DS_ARG_SIZE 2 +struct DsArgList { + size_t nbArgs; + size_t capacity; + struct Expression *args; +}; + #endif /* RGBDS_ASM_LEXER_H */ diff --git a/include/asm/section.h b/include/asm/section.h index 2799c983..219b682d 100644 --- a/include/asm/section.h +++ b/include/asm/section.h @@ -64,7 +64,7 @@ void out_AbsLongGroup(uint8_t const *s, int32_t length); void out_Skip(int32_t skip, bool ds); void out_String(char const *s); void out_RelByte(struct Expression *expr, uint32_t pcShift); -void out_RelBytes(struct Expression *expr, uint32_t n); +void out_RelBytes(uint32_t n, struct Expression *exprs, size_t size); void out_RelWord(struct Expression *expr, uint32_t pcShift); void out_RelLong(struct Expression *expr, uint32_t pcShift); void out_PCRelByte(struct Expression *expr, uint32_t pcShift); diff --git a/src/asm/parser.y b/src/asm/parser.y index 43eb2c66..287b0e3e 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -310,6 +310,33 @@ static void strfmt(char *dest, size_t destLen, char const *fmt, size_t nbArgs, s dest[i] = '\0'; } +static void initDsArgList(struct DsArgList *args) +{ + args->nbArgs = 0; + args->capacity = INITIAL_DS_ARG_SIZE; + args->args = malloc(args->capacity * sizeof(*args->args)); + if (!args->args) + fatalerror("Failed to allocate memory for ds arg list: %s\n", + strerror(errno)); +} + +static size_t nextDsArgListIndex(struct DsArgList *args) +{ + if (args->nbArgs == args->capacity) { + args->capacity = (args->capacity + 1) * 2; + args->args = realloc(args->args, args->capacity * sizeof(*args->args)); + if (!args->args) + fatalerror("realloc error while resizing ds arg list: %s\n", + strerror(errno)); + } + return args->nbArgs++; +} + +static void freeDsArgList(struct DsArgList *args) +{ + free(args->args); +} + static inline void failAssert(enum AssertionType type) { switch (type) { @@ -397,6 +424,7 @@ enum { struct SectionSpec sectSpec; struct MacroArgs *macroArg; enum AssertionType assertType; + struct DsArgList dsArgs; struct { int32_t start; int32_t stop; @@ -537,6 +565,8 @@ enum { %type sectmod %type macroargs +%type ds_args + %type for_args %token T_Z80_ADC "adc" T_Z80_ADD "add" T_Z80_AND "and" @@ -946,8 +976,23 @@ endu : T_POP_ENDU { sect_EndUnion(); } ; ds : T_POP_DS uconst { out_Skip($2, true); } - | T_POP_DS uconst T_COMMA reloc_8bit { - out_RelBytes(&$4, $2); + | T_POP_DS uconst T_COMMA ds_args { + out_RelBytes($2, $4.args, $4.nbArgs); + freeDsArgList(&$4); + } +; + +ds_args : reloc_8bit { + initDsArgList(&$$); + size_t i = nextDsArgListIndex(&$$); + + $$.args[i] = $1; + } + | ds_args T_COMMA reloc_8bit { + size_t i = nextDsArgListIndex(&$1); + + $1.args[i] = $3; + $$ = $1; } ; @@ -1265,7 +1310,7 @@ relocexpr_no_str : scoped_anon_id { rpn_Symbol(&$$, $1); } | relocexpr T_OP_XOR relocexpr { rpn_BinaryOp(RPN_XOR, &$$, &$1, &$3); } - | relocexpr T_OP_OR relocexpr { + | relocexpr T_OP_OR relocexpr { rpn_BinaryOp(RPN_OR, &$$, &$1, &$3); } | relocexpr T_OP_AND relocexpr { diff --git a/src/asm/rgbasm.5 b/src/asm/rgbasm.5 index ccda63c1..5718a13f 100644 --- a/src/asm/rgbasm.5 +++ b/src/asm/rgbasm.5 @@ -1239,10 +1239,13 @@ DW "H", "e", "l", "l", "o", "!" If you do not want this special handling, enclose the string in parentheses. .Pp .Ic DS -can also be used to fill a region of memory with some value. -The following produces 42 times the byte $FF: +can also be used to fill a region of memory with some repeated values. +For example: .Bd -literal -offset indent -DS 42, $FF +; outputs 3 bytes: $AA, $AA, $AA +DS 3, $AA +; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB +DS 7, $BB, $CC .Ed .Pp You can also use diff --git a/src/asm/section.c b/src/asm/section.c index 89818368..40c7a1c6 100644 --- a/src/asm/section.c +++ b/src/asm/section.c @@ -637,12 +637,14 @@ void out_RelByte(struct Expression *expr, uint32_t pcShift) * Output several copies of a relocatable byte. Checking will be done to see if * it is an absolute value in disguise. */ -void out_RelBytes(struct Expression *expr, uint32_t n) +void out_RelBytes(uint32_t n, struct Expression *exprs, size_t size) { checkcodesection(); reserveSpace(n); for (uint32_t i = 0; i < n; i++) { + struct Expression *expr = &exprs[i % size]; + if (!rpn_isKnown(expr)) { createPatch(PATCHTYPE_BYTE, expr, i); writebyte(0); @@ -650,7 +652,9 @@ void out_RelBytes(struct Expression *expr, uint32_t n) writebyte(expr->nVal); } } - rpn_Free(expr); + + for (size_t i = 0; i < size; i++) + rpn_Free(&exprs[i]); } /* diff --git a/test/asm/ds-@.asm b/test/asm/ds-@.asm index 6bbfe365..d7742672 100644 --- a/test/asm/ds-@.asm +++ b/test/asm/ds-@.asm @@ -1,14 +1,14 @@ SECTION "test fixed", ROM0[0] FixedStart: - ds 8, (@ - FixedStart) * 2 + zero - ds 8, (@ - FixedStart) * 2 + zero + ds 6, (@ - FixedStart) * 2 + zero + ds 10, (@ - FixedStart) + zero, (@ - FixedStart) * 3 + zero, (@ - FixedStart) * 4 + zero SECTION "test floating", ROM0 FloatingStart: - ds 8, (@ - FloatingStart) * 2 + zero - ds 8, (@ - FloatingStart) * 2 + zero + ds 6, (@ - FloatingStart) * 2 + zero + ds 10, (@ - FloatingStart) + zero, (@ - FloatingStart) * 3 + zero, (@ - FloatingStart) * 4 + zero SECTION "zero", ROM0[0] zero: diff --git a/test/asm/ds-@.out.bin b/test/asm/ds-@.out.bin index 5a0eb06c..42d39659 100644 Binary files a/test/asm/ds-@.out.bin and b/test/asm/ds-@.out.bin differ diff --git a/test/asm/ds-byte.asm b/test/asm/ds-byte.asm index dc95ef60..d612ab60 100644 --- a/test/asm/ds-byte.asm +++ b/test/asm/ds-byte.asm @@ -6,3 +6,4 @@ Label: ds 5, .other - Label - 5 ; Expressions should work... ds 60, .last - Label ; ...even if not constant .last + ds 11, $67, $89 diff --git a/test/asm/ds-byte.out.bin b/test/asm/ds-byte.out.bin index 6f4591e3..94880523 100644 --- a/test/asm/ds-byte.out.bin +++ b/test/asm/ds-byte.out.bin @@ -1 +1 @@ -****˙˙˙˙˙EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE \ No newline at end of file +****˙˙˙˙˙EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEg‰g‰g‰g‰g‰g \ No newline at end of file