/* ".HEX" file output for gputils
Copyright 1998-2005 James Bowman, Craig Franklin
Copyright 2015-2016 Molnár Károly
*/
#include "stdhdr.h"
#include "libgputils.h"
/* mode flags */
enum mode_flags_e {
HMODE_ALL,
HMODE_LOW,
HMODE_HIGH,
HMODE_SWAP /* swap bytes for INHX16 format */
};
static int checksum;
static const char* newline;
static FILE* hex;
static MemBlock_t* memory;
/*------------------------------------------------------------------------------------------------*/
static void _new_record() {
fprintf(hex, ":");
checksum = 0;
}
/*------------------------------------------------------------------------------------------------*/
static void _write_byte(uint8_t Value) {
checksum += (int)Value;
fprintf(hex, "%02X", Value);
}
/*------------------------------------------------------------------------------------------------*/
/* Write big-endian word. */
static void _write_word(uint16_t Word) {
_write_byte((uint8_t)(Word >> 8));
_write_byte((uint8_t)Word);
}
/*------------------------------------------------------------------------------------------------*/
static void _start_record(unsigned Start, unsigned Len) {
_new_record();
_write_byte((uint8_t)Len);
_write_word((uint16_t)Start);
_write_byte(0);
}
/*------------------------------------------------------------------------------------------------*/
static void _end_record() {
_write_byte((uint8_t)(-checksum));
fprintf(hex, "%s", newline);
}
/*------------------------------------------------------------------------------------------------*/
static void _data_line(unsigned Start, unsigned Stop, enum mode_flags_e Mode) {
uint8_t byte;
if (Mode == HMODE_ALL) {
_start_record(Start, Stop - Start);
while (Start < Stop) {
if (!gp_mem_b_get(memory, Start++, &byte, NULL, NULL)) {
byte = 0xff;
}
_write_byte(byte);
}
}
else if (Mode == HMODE_SWAP) {
/* MPLINK 2.40, 3.80, 4.11 and 4.3x do not support INHX16 format.
* (FIXME I have no idea where it comes from or if it can be used
* for whatever purpose it was written for.) */
assert(((Start % 2) == 0) && ((Stop % 2) == 0));
_start_record(Start / 2, (Stop - Start) / 2);
while (Start < Stop) {
if (!gp_mem_b_get(memory, (Start++) ^ 1, &byte, NULL, NULL)) {
byte = 0xff;
}
_write_byte(byte);
}
}
else {
_start_record(Start, (Stop - Start) / (((Mode == HMODE_LOW) || (Mode == HMODE_HIGH)) ? 2 : 1));
if (Mode == HMODE_HIGH) {
++Start;
}
while (Start < Stop) {
if (!gp_mem_b_get(memory, Start, &byte, NULL, NULL)) {
byte = 0xff;
}
_write_byte(byte);
Start += 2;
}
}
_end_record();
}
/*------------------------------------------------------------------------------------------------*/
static void _seg_address_line(unsigned Segment) {
_new_record();
_write_byte(2);
_write_word(0);
_write_byte(4);
_write_word((uint16_t)Segment);
_end_record();
}
/*------------------------------------------------------------------------------------------------*/
static void _last_line(void) {
_new_record();
_write_byte(0);
_write_word(0);
_write_byte(1);
_end_record();
}
/*------------------------------------------------------------------------------------------------*/
static void _write_i_mem(enum formats Hex_format, enum mode_flags_e Mode, unsigned Core_mask) {
MemBlock_t* m;
int i;
int j;
int maximum;
uint8_t byte;
m = memory;
while (m) {
i = IMemAddrFromBase(m->base);
maximum = i + I_MEM_MAX;
if (Hex_format == INHX32) {
/* FIXME would mode swap require division by 2? */
_seg_address_line(m->base);
}
else {
assert(m->base == 0);
}
while (i < maximum) {
if (!gp_mem_b_get(memory, i, &byte, NULL, NULL)) {
++i;
}
else {
j = i;
while (gp_mem_b_get(memory, i, &byte, NULL, NULL)) {
++i;
if ((((Mode == HMODE_ALL) || (Mode == HMODE_SWAP)) && ((i & 0xf) == 0)) || ((i & 0x1f) == 0)) {
break;
}
}
#if 0
/* disabled for MPASM compatibility,
* regression test gpasm.mchip/asmfiles/szee16.asm */
if (Core_mask > 0xFF) {
/* Write complete instructions, so move start down and stop up to even address. */
if (j & 1) {
--j;
}
if (i & 1) {
++i;
}
}
#endif
/* Now we have a run of (i - j) occupied memory locations. */
/* Write the data to the file */
/* To be bug-for-bug compatible with MPASM 5.34 we ignore negative addresses. */
if (j >= 0) {
_data_line(j, i, Mode);
}
}
}
m = m->next;
}
_last_line();
}
/*------------------------------------------------------------------------------------------------*/
FUNC(bool) gp_writehex(const char* Base_filename, MemBlock_t* M,
enum formats Hex_format, int Num_errors,
bool Dos_newlines, unsigned Core_mask) {
char hex_filename[BUFSIZ];
char low_hex[BUFSIZ];
char high_hex[BUFSIZ];
memory = M;
newline = Dos_newlines ? "\r\n" : "\n";
/* build file names */
snprintf(hex_filename, sizeof(hex_filename), "%s.hex", Base_filename);
snprintf(low_hex, sizeof(low_hex), "%s.hxl", Base_filename);
snprintf(high_hex, sizeof(high_hex), "%s.hxh", Base_filename);
if (Num_errors > 0) {
/* Remove the hex files (if any). */
unlink(hex_filename);
unlink(low_hex);
unlink(high_hex);
return false;
}
/* No error: overwrite the hex file */
if (Hex_format == INHX8S) {
/* Write the low memory */
hex = fopen(low_hex, "wt");
if (hex == NULL) {
perror(low_hex);
return false;
}
_write_i_mem(Hex_format, HMODE_LOW, Core_mask);
fclose(hex);
/* Write the high memory. */
hex = fopen(high_hex, "wt");
if (hex == NULL) {
perror(high_hex);
return false;
}
_write_i_mem(Hex_format, HMODE_HIGH, Core_mask);
fclose(hex);
}
else if (Hex_format == INHX16) {
hex = fopen(hex_filename, "wt");
if (hex == NULL) {
perror(hex_filename);
return false;
}
_write_i_mem(Hex_format, HMODE_SWAP, Core_mask);
fclose(hex);
}
else {
hex = fopen(hex_filename, "wt");
if (!hex) {
perror(hex_filename);
return false;
}
_write_i_mem(Hex_format, HMODE_ALL, Core_mask);
fclose(hex);
}
return true;
}
/*------------------------------------------------------------------------------------------------*/
/* Scan the memory to see if it exceeds 32kB limit on INHX8M limit. */
FUNC(bool) gp_writehex_check(MemBlock_t* M, enum formats Hex_format) {
bool ok = true;
if (Hex_format != INHX32) {
while (M) {
if (M->base > 0) {
ok = false;
/* Superfluous to watch the further blocks. */
break;
}
M = M->next;
}
}
return ok;
}
Detected encoding: UTF-8 | 0
|