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 */

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);


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

@@ -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,



+ 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.

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)
{


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

@@ -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;
}

Loading…
Cancel
Save