diff --git a/kk_ihex_write.c b/kk_ihex_write.c index 9ed8dfd..bf9ae6c 100644 --- a/kk_ihex_write.c +++ b/kk_ihex_write.c @@ -10,10 +10,11 @@ #include "kk_ihex_write.h" -static const char IHEX_START = ':'; +#define IHEX_START ':' + static const char IHEX_NEWLINE[] = IHEX_NEWLINE_STRING; -#define ADDRESS_HIGH_MASK 0xFFFF0000U +#define ADDRESS_HIGH_MASK ((ihex_address_t) 0xFFFF0000U) #define ADDRESS_HIGH_BYTES(addr) ((addr) >> 16) #define HEX_DIGIT(n) ((n) + ( ((n) < 10) ? '0' : ('A' - 10))) @@ -30,9 +31,9 @@ ihex_init (struct ihex_state * const ihex) { #ifndef IHEX_DISABLE_SEGMENTS ihex->segment = 0; #endif - ihex->length = 0; ihex->flags = 0; ihex->line_length = IHEX_DEFAULT_OUTPUT_LINE_LENGTH; + ihex->length = 0; } static char * @@ -63,18 +64,63 @@ ihex_buffer_newline (char *w) { return w; } -// Write the contents of the data buffer to w, increment address, and reset -// data length. Return pointer to one past the last character written to w -// (w is not NUL-terminated). +static void +ihex_write_end_of_file (struct ihex_state * const ihex) { + char *w = line_buffer; + *w++ = IHEX_START; // : +#if 0 + for (unsigned int i = 7; i; --i) { + *w++ = '0'; + } + *w++ = '1'; + *w++ = 'F'; + *w++ = 'F'; +#else + w = ihex_buffer_byte(w, 0); // length + w = ihex_buffer_byte(w, 0); // address msb + w = ihex_buffer_byte(w, 0); // address lsb + w = ihex_buffer_byte(w, IHEX_END_OF_FILE_RECORD); // record type + w = ihex_buffer_byte(w, ~IHEX_END_OF_FILE_RECORD + 1); // checksum +#endif + w = ihex_buffer_newline(w); + ihex_flush_buffer(ihex, line_buffer, w); +} -static char * -ihex_buffer_data (char *w, struct ihex_state * const ihex) { +static void +ihex_write_extended_address (struct ihex_state * const ihex, + const ihex_segment_t address, + const enum ihex_record_type type) { + char *w = line_buffer; + unsigned int sum = type + 2; + + *w++ = IHEX_START; // : + w = ihex_buffer_byte(w, 2); // length + w = ihex_buffer_byte(w, 0); // 16-bit address msb + w = ihex_buffer_byte(w, 0); // 16-bit address lsb + w = ihex_buffer_byte(w, type); // record type + w = ihex_buffer_word(w, address, &sum); // high bytes of address + w = ihex_buffer_byte(w, ~sum + 1); // checksum + w = ihex_buffer_newline(w); + ihex_flush_buffer(ihex, line_buffer, w); +} + +// Write out `ihex->data` +// +static void +ihex_write_data (struct ihex_state * const ihex) { unsigned int len = ihex->length; unsigned int sum = len; uint8_t *r = ihex->data; + char *w = line_buffer; if (!len) { - return w; + return; + } + + if (ihex->flags & IHEX_FLAG_ADDRESS_OVERFLOW) { + ihex_write_extended_address(ihex, ADDRESS_HIGH_BYTES(ihex->address), + IHEX_EXTENDED_LINEAR_ADDRESS_RECORD); + ihex->flags &= ~IHEX_FLAG_ADDRESS_OVERFLOW; } // : @@ -89,7 +135,7 @@ ihex_buffer_data (char *w, struct ihex_state * const ihex) { unsigned int addr = ihex->address & 0xFFFFU; ihex->address += len; if ((0xFFFFU - addr) < len) { - // signal overflow (need to write extended address record) + // signal address overflow (need to write extended address) ihex->flags |= IHEX_FLAG_ADDRESS_OVERFLOW; } w = ihex_buffer_word(w, addr, &sum); @@ -107,59 +153,17 @@ ihex_buffer_data (char *w, struct ihex_state * const ihex) { } while (--len); // checksum - sum = 0x100U - (sum & 0xFFU); - w = ihex_buffer_byte(w, sum); + w = ihex_buffer_byte(w, ~sum + 1U); - return ihex_buffer_newline(w); -} - -static char * -ihex_buffer_extended_address (char *w, const ihex_segment_t address, - const enum ihex_record_type type) { - unsigned int sum = type + 2; - - *w++ = IHEX_START; // : - w = ihex_buffer_byte(w, 2); // length - w = ihex_buffer_byte(w, 0); // address msb - w = ihex_buffer_byte(w, 0); // address lsb - w = ihex_buffer_byte(w, type); // record type - w = ihex_buffer_word(w, address, &sum); // high bytes of 32-bit address - w = ihex_buffer_byte(w, 0x100U - sum); // checksum - return ihex_buffer_newline(w); -} - -// Write an end of file record to w, return a pointer to one past the -// last character written to w (which is not NUL-terminated). - -static char * -ihex_buffer_end_of_file (char *w) { - *w++ = IHEX_START; // : - w = ihex_buffer_byte(w, 0); // length - w = ihex_buffer_byte(w, 0); // address msb - w = ihex_buffer_byte(w, 0); // address lsb - w = ihex_buffer_byte(w, IHEX_END_OF_FILE_RECORD); // record type - w = ihex_buffer_byte(w, 0x100U - IHEX_END_OF_FILE_RECORD); // checksum - return ihex_buffer_newline(w); -} - -static void -ihex_check_address_overflow (struct ihex_state *ihex) { - if (ihex->flags & IHEX_FLAG_ADDRESS_OVERFLOW) { - char *w = ihex_buffer_extended_address(line_buffer, - ADDRESS_HIGH_BYTES(ihex->address), - IHEX_EXTENDED_LINEAR_ADDRESS_RECORD); - ihex_flush_buffer(ihex, line_buffer, w); - ihex->flags &= ~IHEX_FLAG_ADDRESS_OVERFLOW; - } + w = ihex_buffer_newline(w); + ihex_flush_buffer(ihex, line_buffer, w); } void ihex_write_at_address (struct ihex_state *ihex, ihex_address_t address) { if (ihex->length) { - ihex_check_address_overflow(ihex); // flush any existing data - char *w = ihex_buffer_data(line_buffer, ihex); - ihex_flush_buffer(ihex, line_buffer, w); + ihex_write_data(ihex); } if ((ihex->address & ADDRESS_HIGH_MASK) != (address & ADDRESS_HIGH_MASK)) { ihex->flags |= IHEX_FLAG_ADDRESS_OVERFLOW; @@ -186,42 +190,32 @@ ihex_write_at_segment (struct ihex_state *ihex, ihex_segment_t segment, ihex_add ihex_write_at_address(ihex, address); if (ihex->segment != segment) { // clear segment - char *w = ihex_buffer_extended_address(line_buffer, - (ihex->segment = segment), - IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD); - ihex_flush_buffer(ihex, line_buffer, w); + ihex_write_extended_address(ihex, (ihex->segment = segment), + IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD); } } #endif void -ihex_write_byte (struct ihex_state *ihex, uint8_t byte) { - ihex->data[(ihex->length)++] = byte; - if (ihex->length >= ihex->line_length) { - ihex_check_address_overflow(ihex); - char *w = ihex_buffer_data(line_buffer, ihex); - ihex_flush_buffer(ihex, line_buffer, w); +ihex_write_byte (struct ihex_state *ihex, unsigned int byte) { + if (ihex->line_length <= ihex->length) { + ihex_write_data(ihex); } + ihex->data[(ihex->length)++] = byte; } void ihex_end_write (struct ihex_state *ihex) { - char *w; - if (ihex->length) { - ihex_check_address_overflow(ihex); - w = ihex_buffer_data(line_buffer, ihex); - ihex_flush_buffer(ihex, line_buffer, w); - } - w = ihex_buffer_end_of_file(line_buffer); - ihex_flush_buffer(ihex, line_buffer, w); + ihex_write_data(ihex); // flush any remaining data + ihex_write_end_of_file(ihex); } void ihex_write_bytes (struct ihex_state *ihex, uint8_t *data, unsigned int count) { uint8_t *r = data; while (count) { - unsigned int i = ihex->line_length - ihex->length; - if (i) { + if (ihex->line_length > ihex->length) { + unsigned int i = ihex->line_length - ihex->length; uint8_t *w = &(ihex->data[ihex->length]); i = (i > count) ? count : i; count -= i; @@ -229,13 +223,9 @@ ihex_write_bytes (struct ihex_state *ihex, uint8_t *data, unsigned int count) { do { *w++ = *r++; } while (--i); + } else { + ihex_write_data(ihex); } - if (ihex->length >= ihex->line_length) { - char *w; - ihex_check_address_overflow(ihex); - w = ihex_buffer_data(line_buffer, ihex); - ihex_flush_buffer(ihex, line_buffer, w); - } - } while (count); + } } diff --git a/kk_ihex_write.h b/kk_ihex_write.h index 0417578..f5621d0 100644 --- a/kk_ihex_write.h +++ b/kk_ihex_write.h @@ -91,7 +91,7 @@ void ihex_init(struct ihex_state * const ihex); void ihex_write_at_address(struct ihex_state *ihex, ihex_address_t address); // Write a single byte -void ihex_write_byte(struct ihex_state *ihex, uint8_t b); +void ihex_write_byte(struct ihex_state *ihex, unsigned int b); // Write `count` bytes from `data` void ihex_write_bytes(struct ihex_state *ihex, uint8_t *data, unsigned int count);