X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=ao-tools%2Flib%2Fao-hex.c;h=5cfc63c1347e999e70b7dd2da2e4c497b33925f1;hp=85acc07f59537c1e624d6b0000fd1146cc190ce5;hb=14204e3d147ad99cc249ad8de254809180fe5c38;hpb=ee07f1a0f8e431bebb3b948f6249f5f33413e966 diff --git a/ao-tools/lib/ao-hex.c b/ao-tools/lib/ao-hex.c index 85acc07f..5cfc63c1 100644 --- a/ao-tools/lib/ao-hex.c +++ b/ao-tools/lib/ao-hex.c @@ -20,8 +20,10 @@ #include #include #include +#include #include #include "ao-hex.h" +#include "ao-verbose.h" struct ao_hex_input { FILE *file; @@ -118,7 +120,7 @@ ao_hex_read_record(struct ao_hex_input *input) while (state != read_done) { c = getc(input->file); - if (c == EOF && state != read_white) { + if (c == EOF && state != read_white && state != read_marker) { ao_hex_error(input, "Unexpected EOF"); goto bail; } @@ -128,6 +130,8 @@ ao_hex_read_record(struct ao_hex_input *input) input->line++; switch (state) { case read_marker: + if (c == EOF) + return NULL; if (c != ':') { ao_hex_error(input, "Missing ':'"); goto bail; @@ -246,13 +250,20 @@ ao_hex_file_read(FILE *file, char *name) int done = 0; hex = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *), 1); + if (!hex) + return NULL; input.name = name; input.line = 1; input.file = file; while (!done) { record = ao_hex_read_record(&input); - if (!record) - goto bail; + if (!record) { + if (feof(input.file)) { + done = 1; + break; + } else + goto bail; + } if (hex->nrecord == srecord) { srecord *= 2; newhex = realloc(hex, @@ -263,8 +274,6 @@ ao_hex_file_read(FILE *file, char *name) hex = newhex; } hex->records[hex->nrecord++] = record; - if (record->type == AO_HEX_RECORD_EOF) - done = 1; } return hex; @@ -273,6 +282,92 @@ bail: return NULL; } +static struct ao_sym * +load_symbols(struct ao_hex_file *hex, + int *num_symbolsp) +{ + uint32_t extended_addr; + uint32_t addr; + int i; + struct ao_hex_record *record; + struct ao_sym *symbols = NULL; + struct ao_sym *symbol; + int num_symbols = 0; + int size_symbols = 0; + + extended_addr = 0; + for (i = 0; i < hex->nrecord; i++) { + record = hex->records[i]; + switch (record->type) { + case AO_HEX_RECORD_NORMAL: + addr = extended_addr + record->address; + break; + case AO_HEX_RECORD_EOF: + break; + case AO_HEX_RECORD_EXTENDED_ADDRESS_4: + if (record->length != 2) + goto bail; + extended_addr = ((record->data[0] << 8) | record->data[1]) << 4; + break; + case AO_HEX_RECORD_EXTENDED_ADDRESS_8: + if (record->length != 2) + goto bail; + extended_addr = (record->data[0] << 24) | (record->data[1] << 16); + break; + case AO_HEX_RECORD_SYMBOL: + addr = extended_addr + record->address; + if (num_symbols == size_symbols) { + struct ao_sym *new_symbols; + int new_size; + + if (!size_symbols) + new_size = 16; + else + new_size = size_symbols * 2; + new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym)); + if (!new_symbols) + goto bail; + + symbols = new_symbols; + size_symbols = new_size; + } + symbol = &symbols[num_symbols]; + memset(symbol, 0, sizeof (struct ao_sym)); + symbol->name = calloc(record->length + 1, 1); + if (!symbol->name) + goto bail; + memcpy(symbol->name, record->data, record->length); + symbol->addr = addr; + ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr); + num_symbols++; + break; + } + } + *num_symbolsp = num_symbols; + return symbols; +bail: + for (i = 0; i < num_symbols; i++) + free(symbols[i].name); + free(symbols); + return NULL; +} + +static void +ao_hex_record_set_checksum(struct ao_hex_record *record) +{ + uint8_t cksum = 0; + int i; + + cksum += record->length; + cksum += record->address >> 8; + cksum += record->address; + cksum += record->type; + for (i = 0; i < record->length; i++) + cksum += record->data[i]; + + record->checksum = -cksum; +} + struct ao_hex_image * ao_hex_image_create(struct ao_hex_file *hex) { @@ -286,6 +381,8 @@ ao_hex_image_create(struct ao_hex_file *hex) int length; + /* Find the address bounds of the file + */ base = 0xffffffff; bound = 0x0; extended_addr = 0; @@ -293,7 +390,7 @@ ao_hex_image_create(struct ao_hex_file *hex) uint32_t r_bound; record = hex->records[i]; switch (record->type) { - case 0: + case AO_HEX_RECORD_NORMAL: addr = extended_addr + record->address; r_bound = addr + record->length; if (addr < base) @@ -301,20 +398,21 @@ ao_hex_image_create(struct ao_hex_file *hex) if (r_bound > bound) bound = r_bound; break; - case 1: + case AO_HEX_RECORD_EOF: break; - case 2: + case AO_HEX_RECORD_EXTENDED_ADDRESS_4: if (record->length != 2) return NULL; extended_addr = ((record->data[0] << 8) | record->data[1]) << 4; break; - case 4: + case AO_HEX_RECORD_EXTENDED_ADDRESS_8: if (record->length != 2) return NULL; - extended_addr = ((record->data[0] << 8) | record->data[1]) << 16; + extended_addr = (record->data[0] << 24) | (record->data[1] << 16); + break; + case AO_HEX_RECORD_SYMBOL: break; } - } length = bound - base; image = calloc(sizeof(struct ao_hex_image) + length, 1); @@ -327,18 +425,20 @@ ao_hex_image_create(struct ao_hex_file *hex) for (i = 0; i < hex->nrecord; i++) { record = hex->records[i]; switch (record->type) { - case 0: + case AO_HEX_RECORD_NORMAL: addr = extended_addr + record->address; offset = addr - base; memcpy(image->data + offset, record->data, record->length); break; - case 1: + case AO_HEX_RECORD_EOF: break; - case 2: + case AO_HEX_RECORD_EXTENDED_ADDRESS_4: extended_addr = ((record->data[0] << 8) | record->data[1]) << 4; break; - case 4: - extended_addr = ((record->data[0] << 8) | record->data[1]) << 16; + case AO_HEX_RECORD_EXTENDED_ADDRESS_8: + extended_addr = (record->data[0] << 24) | (record->data[1] << 16); + break; + case AO_HEX_RECORD_SYMBOL: break; } } @@ -362,23 +462,165 @@ ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b) } struct ao_hex_image * -ao_hex_load(char *filename) +ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbolsp) { - FILE *file; + FILE *file; struct ao_hex_file *hex_file; - struct ao_hex_image *hex_image; + struct ao_hex_image *hex_image; file = fopen (filename, "r"); if (!file) - return 0; + return NULL; hex_file = ao_hex_file_read(file, filename); fclose(file); if (!hex_file) - return 0; + return NULL; hex_image = ao_hex_image_create(hex_file); if (!hex_image) - return 0; + return NULL; + + if (symbols) + *symbols = load_symbols(hex_file, num_symbolsp); + ao_hex_file_free(hex_file); return hex_image; } + +#define BYTES_PER_RECORD 32 + +static struct ao_hex_file * +ao_hex_file_create(struct ao_hex_image *image, struct ao_sym *symbols, int num_symbols) +{ + /* split data into n-byte-sized chunks */ + uint32_t data_records = (image->length + BYTES_PER_RECORD-1) / BYTES_PER_RECORD; + /* extended address and data for each block, EOF, address and data for each symbol */ + uint32_t total_records = data_records * 2 + 1 + num_symbols * 2; + uint32_t offset; + uint32_t address; + uint32_t length; + char *name; + struct ao_hex_file *hex_file; + int nrecord = 0; + int s; + struct ao_hex_record *record; + + hex_file = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *) * total_records, 1); + if (!hex_file) + return NULL; + + /* Add the data + */ + for (offset = 0; offset < image->length; offset += BYTES_PER_RECORD) { + uint32_t address = image->address + offset; + uint32_t length = image->length - offset; + + if (length > BYTES_PER_RECORD) + length = BYTES_PER_RECORD; + + record = calloc(sizeof (struct ao_hex_record) + 2, 1); + record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8; + record->address = 0; + record->length = 2; + record->data[0] = address >> 24; + record->data[1] = address >> 16; + ao_hex_record_set_checksum(record); + + hex_file->records[nrecord++] = record; + + record = calloc(sizeof (struct ao_hex_record) + length, 1); + record->type = AO_HEX_RECORD_NORMAL; + record->address = address; + record->length = length; + memcpy(record->data, image->data + offset, length); + ao_hex_record_set_checksum(record); + + hex_file->records[nrecord++] = record; + } + + /* Stick an EOF after the data + */ + record = calloc(sizeof (struct ao_hex_record), 1); + record->type = AO_HEX_RECORD_EOF; + record->address = 0; + record->length = 0; + record->data[0] = 0; + record->data[1] = 0; + ao_hex_record_set_checksum(record); + + hex_file->records[nrecord++] = record; + + /* Add the symbols + */ + + for (s = 0; s < num_symbols; s++) { + + name = symbols[s].name; + address = symbols[s].addr; + length = strlen (name); + + record = calloc(sizeof (struct ao_hex_record) + 2, 1); + record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8; + record->address = 0; + record->length = 2; + record->data[0] = address >> 24; + record->data[1] = address >> 16; + ao_hex_record_set_checksum(record); + + hex_file->records[nrecord++] = record; + + record = calloc(sizeof (struct ao_hex_record) + length, 1); + record->type = AO_HEX_RECORD_SYMBOL; + record->address = address; + record->length = length; + memcpy(record->data, name, length); + ao_hex_record_set_checksum(record); + + hex_file->records[nrecord++] = record; + } + + hex_file->nrecord = nrecord; + return hex_file; +} + +static bool +ao_hex_write_record(FILE *file, struct ao_hex_record *record) +{ + int i; + + fputc(':', file); + fprintf(file, "%02x", record->length); + fprintf(file, "%04x", record->address); + fprintf(file, "%02x", record->type); + for (i = 0; i < record->length; i++) + fprintf(file, "%02x", record->data[i]); + fprintf(file, "%02x", record->checksum); + fputc('\n', file); + return true; +} + +bool +ao_hex_save(FILE *file, struct ao_hex_image *image, + struct ao_sym *symbols, int num_symbols) +{ + struct ao_hex_file *hex_file; + int i; + bool ret = false; + + hex_file = ao_hex_file_create(image, symbols, num_symbols); + if (!hex_file) + goto create_failed; + + for (i = 0; i < hex_file->nrecord; i++) { + if (!ao_hex_write_record(file, hex_file->records[i])) + goto write_failed; + } + ret = true; + + if (fflush(file) != 0) + ret = false; +write_failed: + ao_hex_file_free(hex_file); +create_failed: + return ret; +}