diff options
Diffstat (limited to 'ao-tools/lib/ao-hex.c')
| -rw-r--r-- | ao-tools/lib/ao-hex.c | 286 | 
1 files changed, 264 insertions, 22 deletions
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 <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; @@ -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; +}  | 
