summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ithabs.c210
1 files changed, 210 insertions, 0 deletions
diff --git a/ithabs.c b/ithabs.c
new file mode 100644
index 0000000..e8ee8fa
--- /dev/null
+++ b/ithabs.c
@@ -0,0 +1,210 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <inttypes.h>
+
+#define MAXLINE BUFSIZ
+
+static long gethex(char **p, uint8_t *csum)
+{
+ unsigned int v;
+ int chi;
+
+ if ( !sscanf(*p, "%02x%n", &v, &chi) )
+ return -1L;
+
+ if ( csum )
+ *csum += v;
+ *p += chi;
+
+ return v;
+}
+
+static void parse_line(char *p, uint8_t *data, uint8_t *isset)
+{
+ uint8_t csum;
+ int databytes, type, checksum;
+ int a1, a2, d;
+ int n;
+ uint16_t address;
+ uint8_t buf[256];
+
+ csum = 0;
+
+ if ( (databytes = gethex(&p, &csum)) < 0 )
+ return;
+
+ if ( (a1 = gethex(&p, &csum)) < 0 )
+ return;
+ if ( (a2 = gethex(&p, &csum)) < 0 )
+ return;
+
+ address = ((uint16_t)a1 << 8) + a2;
+
+ if ( (type = gethex(&p, &csum)) < 0 || type != 0x00 )
+ return;
+
+ for ( n = 0 ; n < databytes ; n++ ) {
+ if ( (d = gethex(&p, &csum)) < 0 )
+ return;
+
+ buf[n] = d;
+ }
+
+
+ if ( (checksum = gethex(&p, NULL)) < 0 )
+ return;
+
+ if ( checksum != (uint8_t) -csum )
+ return;
+
+ memcpy(data+address, buf, databytes);
+ memset(isset+address, 1, databytes);
+}
+
+static void readith(FILE *in, uint8_t *data, uint8_t *isset)
+{
+ char buffer[MAXLINE];
+
+ while ( fgets(buffer, sizeof buffer, in) ) {
+ if ( buffer[0] != ':' )
+ continue;
+
+ parse_line(buffer+1, data, isset);
+ }
+}
+
+static void write_buffer(FILE *out, uint8_t *buf, int buf_len, int buf_address, int *spaceinrecord_ptr)
+{
+ int spaceinrecord = *spaceinrecord_ptr;
+ struct abs_data_hdr {
+ uint8_t type; /* 0 for data */
+ uint8_t data_bytes;
+ uint8_t zero; /* Reserved */
+ uint8_t addrh;
+ uint8_t addrhx;
+ uint8_t addrl;
+ uint8_t addrlx;
+ } hdr;
+ uint8_t csum;
+ int i;
+
+ memset(&hdr, 0, sizeof hdr);
+
+ csum = 0;
+ for ( i = 0 ; i < buf_len ; i++ )
+ csum += buf[i];
+
+ hdr.data_bytes = buf_len;
+ hdr.addrh = buf_address >> 8;
+ hdr.addrhx = ~hdr.addrh;
+ hdr.addrl = buf_address;
+ hdr.addrlx = ~hdr.addrl;
+
+ fwrite(&hdr, 1, sizeof hdr, out);
+ fwrite(buf, 1, buf_len, out);
+ putc(csum, out);
+
+ spaceinrecord -= (buf_len + sizeof hdr + 1);
+
+ if ( spaceinrecord < sizeof hdr + 4 ) {
+ putc(0xff, out);
+ spaceinrecord--;
+ putc(0x00, out);
+ spaceinrecord--;
+
+ while ( spaceinrecord-- )
+ putc(0xee, out);
+
+ spaceinrecord = 253;
+ }
+
+ *spaceinrecord_ptr = spaceinrecord;
+}
+
+static void
+writeabs(FILE *out, uint8_t *data, uint8_t *isset, uint16_t entry_point)
+{
+ int spaceinrecord = 253;
+ int lastaddr = -999;
+ int addr;
+ uint8_t buf[256];
+ int buf_address = 0;
+ int buf_len = 0;
+ struct abs_entry_hdr {
+ uint8_t type; /* 0 for data */
+ uint8_t data_bytes; /* 0 for the entry point */
+ uint8_t zero; /* Reserved */
+ uint8_t addrh;
+ uint8_t addrhx;
+ uint8_t addrl;
+ uint8_t addrlx;
+ } hdr;
+
+ for ( addr = 0 ; addr < 65536 ; addr++ ) {
+ if ( isset[addr] ) {
+ if ( buf_len && (spaceinrecord < (buf_len+11) ||
+ addr != lastaddr+1) ) {
+ /* Write previous buffer head */
+ write_buffer(out, buf, buf_len, buf_address, &spaceinrecord);
+ buf_len = 0;
+ }
+
+ if ( !buf_len )
+ buf_address = addr;
+ buf[buf_len++] = data[addr];
+ lastaddr = addr;
+ }
+ }
+
+ if ( buf_len )
+ write_buffer(out, buf, buf_len, buf_address, &spaceinrecord);
+
+ /* Write entry point */
+ write_buffer(out, NULL, 0, entry_point, &spaceinrecord);
+
+ /* Pad to end of record */
+ while ( spaceinrecord-- )
+ putc(0xee, out);
+}
+
+/* This obviously assumes a modern computer... */
+int ithabs(FILE *in, FILE *out, uint16_t entry_point)
+{
+ uint8_t data[65536]; /* All the data read from the file */
+ uint8_t isset[65536]; /* To write or not to write... */
+
+ memset(data, 0, 65536);
+ memset(isset, 0, 65536);
+
+ readith(in, data, isset);
+ writeabs(out, data, isset, entry_point);
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *in, *out;
+ uint16_t entry_point;
+
+ if ( argc != 4 ) {
+ fprintf(stderr, "Usage: %s input output entrypoint\n", argv[0]);
+ exit(1);
+ }
+
+ in = fopen(argv[1], "rt");
+ if ( !in ) {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ out = fopen(argv[2], "wb");
+ if ( !out ) {
+ perror(argv[2]);
+ exit(1);
+ }
+
+ entry_point = (uint16_t)strtoul(argv[3], NULL, 0);
+
+ return !ithabs(in, out, entry_point);
+}
+