#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
#include "ao-hex.h"
+#include "ao-verbose.h"
struct ao_hex_input {
FILE *file;
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;
}
input->line++;
switch (state) {
case read_marker:
+ if (c == EOF)
+ return NULL;
if (c != ':') {
ao_hex_error(input, "Missing ':'");
goto bail;
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,
hex = newhex;
}
hex->records[hex->nrecord++] = record;
- if (record->type == AO_HEX_RECORD_EOF)
- done = 1;
}
return hex;
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)
{
int length;
+ /* Find the address bounds of the file
+ */
base = 0xffffffff;
bound = 0x0;
extended_addr = 0;
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)
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);
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;
}
}
free(image);
}
+uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; }
+uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
+
+struct ao_hex_image *
+ao_hex_image_cat(struct ao_hex_image *a, struct ao_hex_image *b)
+{
+ struct ao_hex_image *n;
+ uint32_t base, bound;
+ uint32_t length;
+
+ base = min(a->address, b->address);
+ bound = max(a->address + a->length, b->address + b->length);
+ length = bound - base;
+
+ n = calloc (sizeof (struct ao_hex_image) + length, 1);
+ if (!n)
+ return NULL;
+ n->address = base;
+ n->length = length;
+ memset(n->data, 0xff, length);
+ memcpy(n->data + a->address - n->address, a->data, a->length);
+ memcpy(n->data + b->address - n->address, b->data, b->length);
+ return n;
+}
+
int
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;
+}