From a2e42e94d33b4e7f124a51b61f15e6a469168b41 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 27 Apr 2015 13:25:36 -0500 Subject: [PATCH] Implement block-crossing check. --- src/assembler/errors.c | 9 +++--- src/assembler/errors.h | 1 + src/assembler/state.c | 2 +- src/assembler/tokenizer.c | 71 +++++++++++++++++++++++++++++++---------------- 4 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/assembler/errors.c b/src/assembler/errors.c index 0294e37..6d9da59 100644 --- a/src/assembler/errors.c +++ b/src/assembler/errors.c @@ -10,7 +10,7 @@ /* Error strings */ -static const char *asm_error_types[] = { +static const char *error_types[] = { [ET_INCLUDE] = "include directive", [ET_PREPROC] = "preprocessor", [ET_LAYOUT] = "memory layout", @@ -18,7 +18,7 @@ static const char *asm_error_types[] = { [ET_PARSER] = "instruction parser" }; -static const char *asm_error_descs[] = { +static const char *error_descs[] = { [ED_INC_BAD_ARG] = "missing or invalid argument", [ED_INC_RECURSION] = "infinite recursion detected", [ED_INC_FILE_READ] = "couldn't read included file", @@ -34,6 +34,7 @@ static const char *asm_error_descs[] = { [ED_LYT_BOUNDS] = "location is out of bounds for the ROM size", [ED_LYT_BLOCK0] = "block zero cannot be mapped into a nonzero slot", [ED_LYT_SLOTS] = "multiple slot declarations for block directive", + [ED_LYT_BLOCK_CROSS] = "instruction or data extends past block boundary", [ED_LYT_OVERLAP] = "location overlaps with instruction or data", [ED_LYT_OVERLAP_HEAD] = "location overlaps with ROM header", @@ -129,8 +130,8 @@ void error_info_print(const ErrorInfo *einfo, FILE *file) { ASMErrorLine *line = einfo->line; - fprintf(file, "error: %s: %s\n", asm_error_types[einfo->type], - asm_error_descs[einfo->desc]); + fprintf(file, "error: %s: %s\n", error_types[einfo->type], + error_descs[einfo->desc]); while (line) { fprintf(file, "%s:%zu:\n", line->filename, line->lineno); fprintf(file, " %.*s\n", (int) line->length, line->data); diff --git a/src/assembler/errors.h b/src/assembler/errors.h index 1e28444..53f7fe5 100644 --- a/src/assembler/errors.h +++ b/src/assembler/errors.h @@ -33,6 +33,7 @@ typedef enum { ED_LYT_BOUNDS, ED_LYT_BLOCK0, ED_LYT_SLOTS, + ED_LYT_BLOCK_CROSS, ED_LYT_OVERLAP, ED_LYT_OVERLAP_HEAD, diff --git a/src/assembler/state.c b/src/assembler/state.c index 8d31fc8..a6fe1a4 100644 --- a/src/assembler/state.c +++ b/src/assembler/state.c @@ -161,7 +161,7 @@ const ASMSymbol* asm_symtable_find(const ASMSymbolTable *tab, const char *key) /* Insert a symbol into the table. - TODO: return boolean on success instead of void. + This doesn't check for duplicate keys, so you must do that beforehand. */ void asm_symtable_insert(ASMSymbolTable *tab, ASMSymbol *symbol) { diff --git a/src/assembler/tokenizer.c b/src/assembler/tokenizer.c index 30125dc..a3bf20e 100644 --- a/src/assembler/tokenizer.c +++ b/src/assembler/tokenizer.c @@ -14,6 +14,14 @@ /* Internal structs */ typedef struct { + size_t size; + const ASMLine **overlap_table; + const ASMLine *origin; + uint8_t bank; + bool cross_blocks; +} ASMLayoutInfo; + +typedef struct { int8_t slots[MMU_NUM_ROM_BANKS]; const ASMLine *lines[MMU_NUM_ROM_BANKS]; } ASMSlotInfo; @@ -33,7 +41,7 @@ static inline uint16_t map_into_slot(size_t offset, int8_t slot) /* Return the default slot associated with a given memory bank. */ -static inline int8_t default_bank_slot(size_t bank) +static inline int8_t default_bank_slot(uint8_t bank) { return bank > 2 ? 2 : bank; } @@ -84,7 +92,7 @@ static ErrorInfo* handle_origin_directive(const ASMLine *line, size_t *offset) if (!dparse_uint32_t(&arg, line, DIR_ORIGIN)) return error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG); - if (arg >= MMU_NUM_ROM_BANKS * MMU_ROM_BANK_SIZE) + if (arg >= ROM_SIZE_MAX) return error_info_create(line, ET_PREPROC, ED_PP_ARG_RANGE); *offset = arg; @@ -193,24 +201,24 @@ static ErrorInfo* parse_instruction( } /* - Check if the given location overlaps with any existing objects. + Check if the given object location is legal. + + Checks include ROM size bounding, overlapping with existing objects, and + block-crossing assuming the .cross_blocks directive has not been specified. On success, return NULL and add the location to the overlap table. On failure, return an ErrorInfo object. */ static ErrorInfo* check_layout( - const ASMLine **overlap_table, size_t size, const ASMLocation *loc, - const ASMLine *line, const ASMLine *origin) + ASMLayoutInfo *li, const ASMLocation *loc, const ASMLine *line) { - // TODO: never let boundaries cross without state->cross_blocks const ASMLine *clash = NULL; - - if (loc->offset + loc->length > size) { + if (loc->offset + loc->length > li->size) { clash = &bounds_sentinel; } else { for (size_t i = 0; i < loc->length; i++) { - if (overlap_table[loc->offset + i]) { - clash = overlap_table[loc->offset + i]; + if (li->overlap_table[loc->offset + i]) { + clash = li->overlap_table[loc->offset + i]; break; } } @@ -221,15 +229,23 @@ static ErrorInfo* check_layout( (clash == &header_sentinel) ? ED_LYT_OVERLAP_HEAD : (clash == &bounds_sentinel) ? ED_LYT_BOUNDS : ED_LYT_OVERLAP); - if (origin) - error_info_append(ei, origin); + if (li->origin) + error_info_append(ei, li->origin); if (clash != &header_sentinel && clash != &bounds_sentinel) error_info_append(ei, clash); return ei; } + uint8_t bank = (loc->offset + loc->length - 1) / MMU_ROM_BANK_SIZE; + if (bank != li->bank && !li->cross_blocks) { + ErrorInfo *ei = error_info_create(line, ET_LAYOUT, ED_LYT_BLOCK_CROSS); + if (li->origin) + error_info_append(ei, li->origin); + return ei; + } + for (size_t i = 0; i < loc->length; i++) - overlap_table[loc->offset + i] = line; + li->overlap_table[loc->offset + i] = line; return NULL; } @@ -242,25 +258,28 @@ static ErrorInfo* check_layout( */ ErrorInfo* tokenize(AssemblerState *state) { - size_t size = state->rom_size ? state->rom_size : ROM_SIZE_MAX; - const ASMLine **overlap_table = calloc(size, sizeof(const ASMLine*)); - if (!overlap_table) + ASMLayoutInfo li = { + .size = state->rom_size ? state->rom_size : ROM_SIZE_MAX, + .origin = NULL, .bank = 0, .cross_blocks = state->cross_blocks + }; + li.overlap_table = calloc(li.size, sizeof(const ASMLine*)); + if (!li.overlap_table) OUT_OF_MEMORY() ErrorInfo *ei = NULL; ASMInstruction dummy_inst = {.next = NULL}, *inst, *prev_inst = &dummy_inst; ASMData dummy_data = {.next = NULL}, *data, *prev_data = &dummy_data; - const ASMLine *line = state->lines, *origin = NULL; + const ASMLine *line = state->lines; size_t offset = 0; ASMSlotInfo si = {.lines = {0}}; for (size_t i = 0; i < HEADER_SIZE; i++) - overlap_table[state->header.offset + i] = &header_sentinel; + li.overlap_table[state->header.offset + i] = &header_sentinel; memset(si.slots, -1, MMU_NUM_ROM_BANKS); while (line) { if (line->is_label) { - if (offset >= size) { + if (offset >= li.size) { ei = error_info_create(line, ET_LAYOUT, ED_LYT_BOUNDS); goto cleanup; } @@ -272,12 +291,16 @@ ErrorInfo* tokenize(AssemblerState *state) if (IS_DIRECTIVE(line, DIR_ORIGIN)) { if ((ei = handle_origin_directive(line, &offset))) goto cleanup; - origin = line; + + li.origin = line; + li.bank = offset / MMU_ROM_BANK_SIZE; } else if (IS_DIRECTIVE(line, DIR_BLOCK)) { if ((ei = handle_block_directive(line, &offset, &si))) goto cleanup; - origin = line; + + li.origin = line; + li.bank = offset / MMU_ROM_BANK_SIZE; } else { if ((ei = parse_data(line, &data, offset))) @@ -287,7 +310,7 @@ ErrorInfo* tokenize(AssemblerState *state) prev_data->next = data; prev_data = data; - if ((ei = check_layout(overlap_table, size, &data->loc, line, origin))) + if ((ei = check_layout(&li, &data->loc, line))) goto cleanup; } } @@ -299,7 +322,7 @@ ErrorInfo* tokenize(AssemblerState *state) prev_inst->next = inst; prev_inst = inst; - if ((ei = check_layout(overlap_table, size, &inst->loc, line, origin))) + if ((ei = check_layout(&li, &inst->loc, line))) goto cleanup; } line = line->next; @@ -308,6 +331,6 @@ ErrorInfo* tokenize(AssemblerState *state) cleanup: state->instructions = dummy_inst.next; state->data = dummy_data.next; - free(overlap_table); + free(li.overlap_table); return ei; }