Browse Source

Implement block-crossing check.

master
Ben Kurtovic 9 years ago
parent
commit
a2e42e94d3
4 changed files with 54 additions and 29 deletions
  1. +5
    -4
      src/assembler/errors.c
  2. +1
    -0
      src/assembler/errors.h
  3. +1
    -1
      src/assembler/state.c
  4. +47
    -24
      src/assembler/tokenizer.c

+ 5
- 4
src/assembler/errors.c View File

@@ -10,7 +10,7 @@


/* Error strings */ /* Error strings */


static const char *asm_error_types[] = {
static const char *error_types[] = {
[ET_INCLUDE] = "include directive", [ET_INCLUDE] = "include directive",
[ET_PREPROC] = "preprocessor", [ET_PREPROC] = "preprocessor",
[ET_LAYOUT] = "memory layout", [ET_LAYOUT] = "memory layout",
@@ -18,7 +18,7 @@ static const char *asm_error_types[] = {
[ET_PARSER] = "instruction parser" [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_BAD_ARG] = "missing or invalid argument",
[ED_INC_RECURSION] = "infinite recursion detected", [ED_INC_RECURSION] = "infinite recursion detected",
[ED_INC_FILE_READ] = "couldn't read included file", [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_BOUNDS] = "location is out of bounds for the ROM size",
[ED_LYT_BLOCK0] = "block zero cannot be mapped into a nonzero slot", [ED_LYT_BLOCK0] = "block zero cannot be mapped into a nonzero slot",
[ED_LYT_SLOTS] = "multiple slot declarations for block directive", [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] = "location overlaps with instruction or data",
[ED_LYT_OVERLAP_HEAD] = "location overlaps with ROM header", [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; 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) { while (line) {
fprintf(file, "%s:%zu:\n", line->filename, line->lineno); fprintf(file, "%s:%zu:\n", line->filename, line->lineno);
fprintf(file, " %.*s\n", (int) line->length, line->data); fprintf(file, " %.*s\n", (int) line->length, line->data);


+ 1
- 0
src/assembler/errors.h View File

@@ -33,6 +33,7 @@ typedef enum {
ED_LYT_BOUNDS, ED_LYT_BOUNDS,
ED_LYT_BLOCK0, ED_LYT_BLOCK0,
ED_LYT_SLOTS, ED_LYT_SLOTS,
ED_LYT_BLOCK_CROSS,
ED_LYT_OVERLAP, ED_LYT_OVERLAP,
ED_LYT_OVERLAP_HEAD, ED_LYT_OVERLAP_HEAD,




+ 1
- 1
src/assembler/state.c View File

@@ -161,7 +161,7 @@ const ASMSymbol* asm_symtable_find(const ASMSymbolTable *tab, const char *key)
/* /*
Insert a symbol into the table. 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) void asm_symtable_insert(ASMSymbolTable *tab, ASMSymbol *symbol)
{ {


+ 47
- 24
src/assembler/tokenizer.c View File

@@ -14,6 +14,14 @@
/* Internal structs */ /* Internal structs */


typedef struct { 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]; int8_t slots[MMU_NUM_ROM_BANKS];
const ASMLine *lines[MMU_NUM_ROM_BANKS]; const ASMLine *lines[MMU_NUM_ROM_BANKS];
} ASMSlotInfo; } 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. 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; 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)) if (!dparse_uint32_t(&arg, line, DIR_ORIGIN))
return error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG); 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); return error_info_create(line, ET_PREPROC, ED_PP_ARG_RANGE);


*offset = arg; *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 success, return NULL and add the location to the overlap table.
On failure, return an ErrorInfo object. On failure, return an ErrorInfo object.
*/ */
static ErrorInfo* check_layout( 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; const ASMLine *clash = NULL;

if (loc->offset + loc->length > size) {
if (loc->offset + loc->length > li->size) {
clash = &bounds_sentinel; clash = &bounds_sentinel;
} else { } else {
for (size_t i = 0; i < loc->length; i++) { 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; break;
} }
} }
@@ -221,15 +229,23 @@ static ErrorInfo* check_layout(
(clash == &header_sentinel) ? ED_LYT_OVERLAP_HEAD : (clash == &header_sentinel) ? ED_LYT_OVERLAP_HEAD :
(clash == &bounds_sentinel) ? ED_LYT_BOUNDS : ED_LYT_OVERLAP); (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) if (clash != &header_sentinel && clash != &bounds_sentinel)
error_info_append(ei, clash); error_info_append(ei, clash);
return ei; 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++) for (size_t i = 0; i < loc->length; i++)
overlap_table[loc->offset + i] = line;
li->overlap_table[loc->offset + i] = line;
return NULL; return NULL;
} }


@@ -242,25 +258,28 @@ static ErrorInfo* check_layout(
*/ */
ErrorInfo* tokenize(AssemblerState *state) 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() OUT_OF_MEMORY()


ErrorInfo *ei = NULL; ErrorInfo *ei = NULL;
ASMInstruction dummy_inst = {.next = NULL}, *inst, *prev_inst = &dummy_inst; ASMInstruction dummy_inst = {.next = NULL}, *inst, *prev_inst = &dummy_inst;
ASMData dummy_data = {.next = NULL}, *data, *prev_data = &dummy_data; 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; size_t offset = 0;
ASMSlotInfo si = {.lines = {0}}; ASMSlotInfo si = {.lines = {0}};


for (size_t i = 0; i < HEADER_SIZE; i++) 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); memset(si.slots, -1, MMU_NUM_ROM_BANKS);


while (line) { while (line) {
if (line->is_label) { if (line->is_label) {
if (offset >= size) {
if (offset >= li.size) {
ei = error_info_create(line, ET_LAYOUT, ED_LYT_BOUNDS); ei = error_info_create(line, ET_LAYOUT, ED_LYT_BOUNDS);
goto cleanup; goto cleanup;
} }
@@ -272,12 +291,16 @@ ErrorInfo* tokenize(AssemblerState *state)
if (IS_DIRECTIVE(line, DIR_ORIGIN)) { if (IS_DIRECTIVE(line, DIR_ORIGIN)) {
if ((ei = handle_origin_directive(line, &offset))) if ((ei = handle_origin_directive(line, &offset)))
goto cleanup; goto cleanup;
origin = line;

li.origin = line;
li.bank = offset / MMU_ROM_BANK_SIZE;
} }
else if (IS_DIRECTIVE(line, DIR_BLOCK)) { else if (IS_DIRECTIVE(line, DIR_BLOCK)) {
if ((ei = handle_block_directive(line, &offset, &si))) if ((ei = handle_block_directive(line, &offset, &si)))
goto cleanup; goto cleanup;
origin = line;

li.origin = line;
li.bank = offset / MMU_ROM_BANK_SIZE;
} }
else { else {
if ((ei = parse_data(line, &data, offset))) if ((ei = parse_data(line, &data, offset)))
@@ -287,7 +310,7 @@ ErrorInfo* tokenize(AssemblerState *state)
prev_data->next = data; prev_data->next = data;
prev_data = 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; goto cleanup;
} }
} }
@@ -299,7 +322,7 @@ ErrorInfo* tokenize(AssemblerState *state)
prev_inst->next = inst; prev_inst->next = inst;
prev_inst = 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; goto cleanup;
} }
line = line->next; line = line->next;
@@ -308,6 +331,6 @@ ErrorInfo* tokenize(AssemblerState *state)
cleanup: cleanup:
state->instructions = dummy_inst.next; state->instructions = dummy_inst.next;
state->data = dummy_data.next; state->data = dummy_data.next;
free(overlap_table);
free(li.overlap_table);
return ei; return ei;
} }

Loading…
Cancel
Save