/* Intel HEX read/write functions, Paul Stoffregen, paul@ece.orst.edu */
|
/* Intel HEX read/write functions, Paul Stoffregen, paul@ece.orst.edu */
|
/* This code is in the public domain. Please retain my name and */
|
/* This code is in the public domain. Please retain my name and */
|
/* email address in distributed copies, and let me know about any bugs */
|
/* email address in distributed copies, and let me know about any bugs */
|
|
|
/* I, Paul Stoffregen, give no warranty, expressed or implied for */
|
/* I, Paul Stoffregen, give no warranty, expressed or implied for */
|
/* this software and/or documentation provided, including, without */
|
/* this software and/or documentation provided, including, without */
|
/* limitation, warranty of merchantability and fitness for a */
|
/* limitation, warranty of merchantability and fitness for a */
|
/* particular purpose. */
|
/* particular purpose. */
|
|
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <string.h>
|
#include <string.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <ctype.h>
|
#include <ctype.h>
|
|
|
#ifndef MAX_MEMORY_SIZE
|
#ifndef MAX_MEMORY_SIZE
|
#define MAX_MEMORY_SIZE 65535
|
#define MAX_MEMORY_SIZE 65535
|
#endif
|
#endif
|
|
|
/* some ansi prototypes.. maybe ought to make a .h file */
|
/* some ansi prototypes.. maybe ought to make a .h file */
|
|
|
/* this loads an intel hex file into the memory[] array */
|
/* this loads an intel hex file into the memory[] array */
|
void load_file(char *filename);
|
int load_file(char *filename);
|
|
|
/* this writes a part of memory[] to an intel hex file */
|
/* this writes a part of memory[] to an intel hex file */
|
void save_file(char *command);
|
void save_file(char *command);
|
|
|
/* this is used by load_file to get each line of intex hex */
|
/* this is used by load_file to get each line of intex hex */
|
int parse_hex_line(char *theline, int bytes[], int *addr, int *num, int *code);
|
int parse_hex_line(char *theline, int bytes[], int *addr, int *num, int *code);
|
|
|
/* this does the dirty work of writing an intel hex file */
|
/* this does the dirty work of writing an intel hex file */
|
/* caution, static buffering is used, so it is necessary */
|
/* caution, static buffering is used, so it is necessary */
|
/* to call it with end=1 when finsihed to flush the buffer */
|
/* to call it with end=1 when finsihed to flush the buffer */
|
/* and close the file */
|
/* and close the file */
|
void hexout(FILE *fhex, int byte, int memory_location, int end);
|
void hexout(FILE *fhex, int byte, int memory_location, int end);
|
|
|
|
|
extern int memory[MAX_MEMORY_SIZE+1]; /* the memory is global */
|
extern int memory[MAX_MEMORY_SIZE+1]; /* the memory is global */
|
|
|
/* parses a line of intel hex code, stores the data in bytes[] */
|
/* parses a line of intel hex code, stores the data in bytes[] */
|
/* and the beginning address in addr, and returns a 1 if the */
|
/* and the beginning address in addr, and returns a 1 if the */
|
/* line was valid, or a 0 if an error occured. The variable */
|
/* line was valid, or a 0 if an error occured. The variable */
|
/* num gets the number of bytes that were stored into bytes[] */
|
/* num gets the number of bytes that were stored into bytes[] */
|
|
|
int parse_hex_line(theline, bytes, addr, num, code)
|
int parse_hex_line(theline, bytes, addr, num, code)
|
char *theline;
|
char *theline;
|
int *addr, *num, *code, bytes[];
|
int *addr, *num, *code, bytes[];
|
{
|
{
|
int sum, len, cksum;
|
int sum, len, cksum;
|
char *ptr;
|
char *ptr;
|
|
|
*num = 0;
|
*num = 0;
|
if (theline[0] != ':') return 0;
|
if (theline[0] != ':') return 0;
|
if (strlen(theline) < 11) return 0;
|
if (strlen(theline) < 11) return 0;
|
ptr = theline+1;
|
ptr = theline+1;
|
if (!sscanf(ptr, "%02x", &len)) return 0;
|
if (!sscanf(ptr, "%02x", &len)) return 0;
|
ptr += 2;
|
ptr += 2;
|
if ( strlen(theline) < (11 + (len * 2)) ) return 0;
|
if ( strlen(theline) < (11 + (len * 2)) ) return 0;
|
if (!sscanf(ptr, "%04x", addr)) return 0;
|
if (!sscanf(ptr, "%04x", addr)) return 0;
|
ptr += 4;
|
ptr += 4;
|
/* printf("Line: length=%d Addr=%d\n", len, *addr); */
|
/* printf("Line: length=%d Addr=%d\n", len, *addr); */
|
if (!sscanf(ptr, "%02x", code)) return 0;
|
if (!sscanf(ptr, "%02x", code)) return 0;
|
ptr += 2;
|
ptr += 2;
|
sum = (len & 255) + ((*addr >> 8) & 255) + (*addr & 255) + (*code & 255);
|
sum = (len & 255) + ((*addr >> 8) & 255) + (*addr & 255) + (*code & 255);
|
while(*num != len) {
|
while(*num != len) {
|
if (!sscanf(ptr, "%02x", &bytes[*num])) return 0;
|
if (!sscanf(ptr, "%02x", &bytes[*num])) return 0;
|
ptr += 2;
|
ptr += 2;
|
sum += bytes[*num] & 255;
|
sum += bytes[*num] & 255;
|
(*num)++;
|
(*num)++;
|
if (*num >= 256) return 0;
|
if (*num >= 256) return 0;
|
}
|
}
|
if (!sscanf(ptr, "%02x", &cksum)) return 0;
|
if (!sscanf(ptr, "%02x", &cksum)) return 0;
|
if ( ((sum & 255) + (cksum & 255)) & 255 ) return 0; /* checksum error */
|
if ( ((sum & 255) + (cksum & 255)) & 255 ) return 0; /* checksum error */
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/* loads an intel hex file into the global memory[] array */
|
/* loads an intel hex file into the global memory[] array */
|
/* filename is a string of the file to be opened */
|
/* filename is a string of the file to be opened */
|
|
|
void load_file(filename)
|
int load_file(filename)
|
char *filename;
|
char *filename;
|
{
|
{
|
char line[1000];
|
char line[1000];
|
FILE *fin;
|
FILE *fin;
|
int addr, n, status, bytes[256];
|
int addr, n, status, bytes[256];
|
int i, total=0, lineno=1;
|
int i, total=0, lineno=1;
|
int minaddr=65536, maxaddr=0;
|
int minaddr=65536, maxaddr=0;
|
|
|
if (strlen(filename) == 0) {
|
if (strlen(filename) == 0) {
|
printf(" Can't load a file without the filename.");
|
printf(" Can't load a file without the filename.");
|
printf(" '?' for help\n");
|
printf(" '?' for help\n");
|
return;
|
return 0;
|
}
|
}
|
fin = fopen(filename, "r");
|
fin = fopen(filename, "r");
|
if (fin == NULL) {
|
if (fin == NULL) {
|
printf(" Can't open file '%s' for reading.\n", filename);
|
printf(" Can't open file '%s' for reading.\n", filename);
|
//return;
|
//return;
|
exit(1);
|
exit(1);
|
}
|
}
|
while (!feof(fin) && !ferror(fin)) {
|
while (!feof(fin) && !ferror(fin)) {
|
line[0] = '\0';
|
line[0] = '\0';
|
fgets(line, 1000, fin);
|
fgets(line, 1000, fin);
|
if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
|
if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
|
if (line[strlen(line)-1] == '\r') line[strlen(line)-1] = '\0';
|
if (line[strlen(line)-1] == '\r') line[strlen(line)-1] = '\0';
|
if (parse_hex_line(line, bytes, &addr, &n, &status)) {
|
if (parse_hex_line(line, bytes, &addr, &n, &status)) {
|
if (status == 0) { /* data */
|
if (status == 0) { /* data */
|
for(i=0; i<=(n-1); i++) {
|
for(i=0; i<=(n-1); i++) {
|
memory[addr] = bytes[i] & 255;
|
memory[addr] = bytes[i] & 255;
|
total++;
|
total++;
|
if (addr < minaddr) minaddr = addr;
|
if (addr < minaddr) minaddr = addr;
|
if (addr > maxaddr) maxaddr = addr;
|
if (addr > maxaddr) maxaddr = addr;
|
addr++;
|
addr++;
|
}
|
}
|
}
|
}
|
if (status == 1) { /* end of file */
|
if (status == 1) { /* end of file */
|
fclose(fin);
|
fclose(fin);
|
printf(" Loaded %d bytes between:", total);
|
printf(" Loaded %d bytes between:", total);
|
printf(" %04X to %04X\n", minaddr, maxaddr);
|
printf(" %04X to %04X\n", minaddr, maxaddr);
|
return;
|
|
|
return maxaddr;
|
}
|
}
|
if (status == 2) ; /* begin of file */
|
if (status == 2) ; /* begin of file */
|
} else {
|
} else {
|
printf(" Error: '%s', line: %d\n", filename, lineno);
|
printf(" Error: '%s', line: %d\n", filename, lineno);
|
}
|
}
|
lineno++;
|
lineno++;
|
}
|
}
|
|
return maxaddr;//it should not reach here
|
}
|
}
|
|
|
|
|
/* the command string format is "S begin end filename" where */
|
/* the command string format is "S begin end filename" where */
|
/* "begin" and "end" are the locations to dump to the intel */
|
/* "begin" and "end" are the locations to dump to the intel */
|
/* hex file, specified in hexidecimal. */
|
/* hex file, specified in hexidecimal. */
|
|
|
void save_file(command)
|
void save_file(command)
|
char *command;
|
char *command;
|
{
|
{
|
int begin, end, addr;
|
int begin, end, addr;
|
char *ptr, filename[200];
|
char *ptr, filename[200];
|
FILE *fhex;
|
FILE *fhex;
|
|
|
ptr = command+1;
|
ptr = command+1;
|
while (isspace(*ptr)) ptr++;
|
while (isspace(*ptr)) ptr++;
|
if (*ptr == '\0') {
|
if (*ptr == '\0') {
|
printf(" Must specify address range and filename\n");
|
printf(" Must specify address range and filename\n");
|
return;
|
return;
|
}
|
}
|
if (sscanf(ptr, "%x%x%s", &begin, &end, filename) < 3) {
|
if (sscanf(ptr, "%x%x%s", &begin, &end, filename) < 3) {
|
printf(" Invalid addresses or filename,\n");
|
printf(" Invalid addresses or filename,\n");
|
printf(" usage: S begin_addr end_addr filename\n");
|
printf(" usage: S begin_addr end_addr filename\n");
|
printf(" the addresses must be hexidecimal format\n");
|
printf(" the addresses must be hexidecimal format\n");
|
return;
|
return;
|
}
|
}
|
begin &= MAX_MEMORY_SIZE;
|
begin &= MAX_MEMORY_SIZE;
|
end &= MAX_MEMORY_SIZE;
|
end &= MAX_MEMORY_SIZE;
|
if (begin > end) {
|
if (begin > end) {
|
printf(" Begin address must be less than end address.\n");
|
printf(" Begin address must be less than end address.\n");
|
return;
|
return;
|
}
|
}
|
fhex = fopen(filename, "w");
|
fhex = fopen(filename, "w");
|
if (fhex == NULL) {
|
if (fhex == NULL) {
|
printf(" Can't open '%s' for writing.\n", filename);
|
printf(" Can't open '%s' for writing.\n", filename);
|
return;
|
return;
|
}
|
}
|
for (addr=begin; addr <= end; addr++)
|
for (addr=begin; addr <= end; addr++)
|
hexout(fhex, memory[addr], addr, 0);
|
hexout(fhex, memory[addr], addr, 0);
|
hexout(fhex, 0, 0, 1);
|
hexout(fhex, 0, 0, 1);
|
printf("Memory %04X to %04X written to '%s'\n", begin, end, filename);
|
printf("Memory %04X to %04X written to '%s'\n", begin, end, filename);
|
}
|
}
|
|
|
|
|
/* produce intel hex file output... call this routine with */
|
/* produce intel hex file output... call this routine with */
|
/* each byte to output and it's memory location. The file */
|
/* each byte to output and it's memory location. The file */
|
/* pointer fhex must have been opened for writing. After */
|
/* pointer fhex must have been opened for writing. After */
|
/* all data is written, call with end=1 (normally set to 0) */
|
/* all data is written, call with end=1 (normally set to 0) */
|
/* so it will flush the data from its static buffer */
|
/* so it will flush the data from its static buffer */
|
|
|
#define MAXHEXLINE 32 /* the maximum number of bytes to put in one line */
|
#define MAXHEXLINE 32 /* the maximum number of bytes to put in one line */
|
|
|
void hexout(fhex, byte, memory_location, end)
|
void hexout(fhex, byte, memory_location, end)
|
FILE *fhex; /* the file to put intel hex into */
|
FILE *fhex; /* the file to put intel hex into */
|
int byte, memory_location, end;
|
int byte, memory_location, end;
|
{
|
{
|
static int byte_buffer[MAXHEXLINE];
|
static int byte_buffer[MAXHEXLINE];
|
static int last_mem, buffer_pos, buffer_addr;
|
static int last_mem, buffer_pos, buffer_addr;
|
static int writing_in_progress=0;
|
static int writing_in_progress=0;
|
register int i, sum;
|
register int i, sum;
|
|
|
if (!writing_in_progress) {
|
if (!writing_in_progress) {
|
/* initial condition setup */
|
/* initial condition setup */
|
last_mem = memory_location-1;
|
last_mem = memory_location-1;
|
buffer_pos = 0;
|
buffer_pos = 0;
|
buffer_addr = memory_location;
|
buffer_addr = memory_location;
|
writing_in_progress = 1;
|
writing_in_progress = 1;
|
}
|
}
|
|
|
if ( (memory_location != (last_mem+1)) || (buffer_pos >= MAXHEXLINE) \
|
if ( (memory_location != (last_mem+1)) || (buffer_pos >= MAXHEXLINE) \
|
|| ((end) && (buffer_pos > 0)) ) {
|
|| ((end) && (buffer_pos > 0)) ) {
|
/* it's time to dump the buffer to a line in the file */
|
/* it's time to dump the buffer to a line in the file */
|
fprintf(fhex, ":%02X%04X00", buffer_pos, buffer_addr);
|
fprintf(fhex, ":%02X%04X00", buffer_pos, buffer_addr);
|
sum = buffer_pos + ((buffer_addr>>8)&255) + (buffer_addr&255);
|
sum = buffer_pos + ((buffer_addr>>8)&255) + (buffer_addr&255);
|
for (i=0; i < buffer_pos; i++) {
|
for (i=0; i < buffer_pos; i++) {
|
fprintf(fhex, "%02X", byte_buffer[i]&255);
|
fprintf(fhex, "%02X", byte_buffer[i]&255);
|
sum += byte_buffer[i]&255;
|
sum += byte_buffer[i]&255;
|
}
|
}
|
fprintf(fhex, "%02X\n", (-sum)&255);
|
fprintf(fhex, "%02X\n", (-sum)&255);
|
buffer_addr = memory_location;
|
buffer_addr = memory_location;
|
buffer_pos = 0;
|
buffer_pos = 0;
|
}
|
}
|
|
|
if (end) {
|
if (end) {
|
fprintf(fhex, ":00000001FF\n"); /* end of file marker */
|
fprintf(fhex, ":00000001FF\n"); /* end of file marker */
|
fclose(fhex);
|
fclose(fhex);
|
writing_in_progress = 0;
|
writing_in_progress = 0;
|
}
|
}
|
|
|
last_mem = memory_location;
|
last_mem = memory_location;
|
byte_buffer[buffer_pos] = byte & 255;
|
byte_buffer[buffer_pos] = byte & 255;
|
buffer_pos++;
|
buffer_pos++;
|
}
|
}
|
|
|
|
|
|
|