From 4660a2b4a0c047b4d0fd1249502f95714ca0d65b Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sun, 5 Jul 2009 15:29:55 -0700 Subject: [PATCH] outbin: add support for Intel hex and Motorola S-records Add support for directly generating Intel hex or Motorola S-records. These formats are commonly used with ROM burners. Signed-off-by: H. Peter Anvin --- doc/nasmdoc.src | 26 +++++ output/outbin.c | 318 ++++++++++++++++++++++++++++++++++++++++++++++++++----- output/outform.h | 4 + 3 files changed, 319 insertions(+), 29 deletions(-) diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src index 5881349c..c077bb99 100644 --- a/doc/nasmdoc.src +++ b/doc/nasmdoc.src @@ -4565,6 +4565,32 @@ or \c{symbols} may be specified. Output may be directed to \c{stdout} brackets must be used. +\H{ithfmt} \i\c{ith}: \i{Intel Hex} Output + +The \c{ith} file format produces Intel Hex-format files. Just as the +\c{bin} format, this is a flat memory image format with no support for +relocation or linking. It is usually used with ROM programmers and +similar utilities. + +All options supported by the \c{bin} file format is also supported by +the \c{ith} file format. + +\c{ith} provides a default output file-name extension of \c{.ith}. + + +\H{srecfmt} \i\c{srec}: \i{Motorola S-Record} Output + +The \c{srec} file format produces Intel Hex-format files. Just as the +\c{bin} format, this is a flat memory image format with no support for +relocation or linking. It is usually used with ROM programmers and +similar utilities. + +All options supported by the \c{bin} file format is also supported by +the \c{srec} file format. + +\c{srec} provides a default output file-name extension of \c{.srec}. + + \H{objfmt} \i\c{obj}: \i{Microsoft OMF}\I{OMF} Object Files The \c{obj} file format (NASM calls it \c{obj} rather than \c{omf} diff --git a/output/outbin.c b/output/outbin.c index b3ebc2a8..6925201d 100644 --- a/output/outbin.c +++ b/output/outbin.c @@ -92,10 +92,10 @@ #ifdef OF_BIN -struct ofmt *bin_get_ofmt(); /* Prototype goes here since no header file. */ - static FILE *fp, *rf = NULL; static efunc error; +static struct ofmt *my_ofmt; +static void (*do_output)(void); /* Section flags keep track of which attributes the user has defined. */ #define START_DEFINED 0x001 @@ -592,26 +592,8 @@ static void bin_cleanup(int debuginfo) } /* Step 6: Write the section data to the output file. */ - - /* Write the progbits sections to the output file. */ - pend = origin; - for (s = sections; s; s = s->next) { - /* Skip non-progbits sections */ - if (!(s->flags & TYPE_PROGBITS)) - continue; - /* Skip zero-length sections */ - if (s->length == 0) - continue; - /* Pad the space between sections. */ - for (h = s->start - pend; h; h--) - fputc('\0', fp); - /* Write the section to the output file. */ - if (s->length > 0) - saa_fpwrite(s->contents, fp); - pend = s->start + s->length; - } - /* Done writing the file, so close it. */ - fclose(fp); + do_output(); + fclose(fp); /* Done with the output file */ /* Step 7: Generate the map file. */ @@ -1227,12 +1209,12 @@ static void bin_define_section_labels(void) /* section..start */ strcpy(label_name + base_len, ".start"); define_label(label_name, sec->start_index, 0L, - NULL, 0, 0, bin_get_ofmt(), error); + NULL, 0, 0, my_ofmt, error); /* section..vstart */ strcpy(label_name + base_len, ".vstart"); define_label(label_name, sec->vstart_index, 0L, - NULL, 0, 0, bin_get_ofmt(), error); + NULL, 0, 0, my_ofmt, error); nasm_free(label_name); } @@ -1394,6 +1376,20 @@ static void bin_filename(char *inname, char *outname, efunc error) outfile = outname; } +static void ith_filename(char *inname, char *outname, efunc error) +{ + standard_extension(inname, outname, ".ith", error); + infile = inname; + outfile = outname; +} + +static void srec_filename(char *inname, char *outname, efunc error) +{ + standard_extension(inname, outname, ".srec", error); + infile = inname; + outfile = outname; +} + static int32_t bin_segbase(int32_t segment) { return segment; @@ -1406,8 +1402,35 @@ static int bin_set_info(enum geninfo type, char **val) return 0; } +static void binfmt_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval); +struct ofmt of_bin, of_ith, of_srec; +static void do_output_bin(void); +static void do_output_ith(void); +static void do_output_srec(void); + static void bin_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) { + my_ofmt = &of_bin; + do_output = do_output_bin; + binfmt_init(afp, errfunc, ldef, eval); +} + +static void ith_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ + my_ofmt = &of_ith; + do_output = do_output_ith; + binfmt_init(afp, errfunc, ldef, eval); +} + +static void srec_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ + my_ofmt = &of_srec; + do_output = do_output_srec; + binfmt_init(afp, errfunc, ldef, eval); +} + +static void binfmt_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ fp = afp; error = errfunc; @@ -1438,6 +1461,213 @@ static void bin_init(FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) last_section->vstart_index = current_section = seg_alloc(); } +/* Generate binary file output */ +static void do_output_bin(void) +{ + struct Section *s; + uint64_t addr = origin; + + /* Write the progbits sections to the output file. */ + for (s = sections; s; s = s->next) { + /* Skip non-progbits sections */ + if (!(s->flags & TYPE_PROGBITS)) + continue; + /* Skip zero-length sections */ + if (s->length == 0) + continue; + + /* Pad the space between sections. */ + fwritezero(s->start - addr, fp); + + /* Write the section to the output file. */ + saa_fpwrite(s->contents, fp); + + /* Keep track of the current file position */ + addr = s->start + s->length; + } +} + +/* Generate Intel hex file output */ +static int write_ith_record(unsigned int len, uint16_t addr, + uint8_t type, void *data) +{ + char buf[1+2+4+2+255*2+2+2]; + char *p = buf; + uint8_t csum, *dptr = data; + unsigned int i; + + nasm_assert(len <= 255); + + csum = len + addr + (addr >> 8) + type; + for (i = 0; i < len; i++) + csum += dptr[i]; + csum = -csum; + + p += sprintf(p, ":%02X%04X%02X", len, addr, type); + for (i = 0; i < len; i++) + p += sprintf(p, "%02X", dptr[i]); + p += sprintf(p, "%02X\n", csum); + + if (fwrite(buf, 1, p-buf, fp) != (size_t)(p-buf)) + return -1; + + return 0; +} + +static void do_output_ith(void) +{ + uint8_t buf[32]; + struct Section *s; + uint64_t addr, last; + uint64_t length; + unsigned int chunk; + + /* Write the progbits sections to the output file. */ + last = 0; + for (s = sections; s; s = s->next) { + /* Skip non-progbits sections */ + if (!(s->flags & TYPE_PROGBITS)) + continue; + /* Skip zero-length sections */ + if (s->length == 0) + continue; + + addr = s->start; + length = s->length; + + while (length) { + if ((addr^last) & 0xffff0000) { + buf[0] = addr >> 24; + buf[1] = addr >> 16; + write_ith_record(2, 0, 4, buf); + } + + chunk = 32 - (addr & 31); + if (length < chunk) + chunk = length; + + saa_rnbytes(s->contents, buf, chunk); + write_ith_record(chunk, (uint16_t)addr, 0, buf); + + last = addr + chunk - 1; + addr += chunk; + length -= chunk; + } + } + + /* Write closing record */ + write_ith_record(0, 0, 1, NULL); +} + +/* Generate Motorola S-records */ +static int write_srecord(unsigned int len, unsigned int alen, + uint32_t addr, uint8_t type, void *data) +{ + char buf[2+2+8+255*2+2+2]; + char *p = buf; + uint8_t csum, *dptr = data; + unsigned int i; + + nasm_assert(len <= 255); + + switch (alen) { + case 2: + addr &= 0xffff; + break; + case 3: + addr &= 0xffffff; + break; + case 4: + break; + default: + nasm_assert(0); + break; + } + + csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24); + for (i = 0; i < len; i++) + csum += dptr[i]; + csum = 0xff-csum; + + p += sprintf(p, "S%c%02X%0*X", type, len+alen+1, alen*2, addr); + for (i = 0; i < len; i++) + p += sprintf(p, "%02X", dptr[i]); + p += sprintf(p, "%02X\n", csum); + + if (fwrite(buf, 1, p-buf, fp) != (size_t)(p-buf)) + return -1; + + return 0; +} + +static void do_output_srec(void) +{ + uint8_t buf[32]; + struct Section *s; + uint64_t addr, maxaddr; + uint64_t length; + int alen; + unsigned int chunk; + char dtype, etype; + + maxaddr = 0; + for (s = sections; s; s = s->next) { + /* Skip non-progbits sections */ + if (!(s->flags & TYPE_PROGBITS)) + continue; + /* Skip zero-length sections */ + if (s->length == 0) + continue; + + addr = s->start + s->length - 1; + if (addr > maxaddr) + maxaddr = addr; + } + + if (maxaddr <= 0xffff) { + alen = 2; + dtype = '1'; /* S1 = 16-bit data */ + etype = '9'; /* S9 = 16-bit end */ + } else if (maxaddr <= 0xffffff) { + alen = 3; + dtype = '2'; /* S2 = 24-bit data */ + etype = '8'; /* S8 = 24-bit end */ + } else { + alen = 4; + dtype = '3'; /* S3 = 32-bit data */ + etype = '7'; /* S7 = 32-bit end */ + } + + /* Write the progbits sections to the output file. */ + for (s = sections; s; s = s->next) { + /* Skip non-progbits sections */ + if (!(s->flags & TYPE_PROGBITS)) + continue; + /* Skip zero-length sections */ + if (s->length == 0) + continue; + + addr = s->start; + length = s->length; + + while (length) { + chunk = 32 - (addr & 31); + if (length < chunk) + chunk = length; + + saa_rnbytes(s->contents, buf, chunk); + write_srecord(chunk, alen, (uint32_t)addr, dtype, buf); + + addr += chunk; + length -= chunk; + } + } + + /* Write closing record */ + write_srecord(0, alen, 0, etype, NULL); +} + + struct ofmt of_bin = { "flat-form binary files (e.g. DOS .COM, .SYS)", "bin", @@ -1456,10 +1686,40 @@ struct ofmt of_bin = { bin_cleanup }; -/* This is needed for bin_define_section_labels() */ -struct ofmt *bin_get_ofmt(void) -{ - return &of_bin; -} +struct ofmt of_ith = { + "Intel Hex", + "ith", + OFMT_TEXT, + null_debug_arr, + &null_debug_form, + bin_stdmac, + ith_init, + bin_set_info, + bin_out, + bin_deflabel, + bin_secname, + bin_segbase, + bin_directive, + ith_filename, + bin_cleanup +}; + +struct ofmt of_srec = { + "Motorola S-records", + "srec", + 0, + null_debug_arr, + &null_debug_form, + bin_stdmac, + srec_init, + bin_set_info, + bin_out, + bin_deflabel, + bin_secname, + bin_segbase, + bin_directive, + srec_filename, + bin_cleanup +}; #endif /* #ifdef OF_BIN */ diff --git a/output/outform.h b/output/outform.h index 24a4e1b1..e96a4b97 100644 --- a/output/outform.h +++ b/output/outform.h @@ -250,6 +250,8 @@ * array based on the above defines */ extern struct ofmt of_bin; +extern struct ofmt of_ith; +extern struct ofmt of_srec; extern struct ofmt of_aout; extern struct ofmt of_aoutb; extern struct ofmt of_coff; @@ -268,6 +270,8 @@ extern struct ofmt of_dbg; struct ofmt *drivers[] = { #ifdef OF_BIN &of_bin, + &of_ith, + &of_srec, #endif #ifdef OF_AOUT &of_aout, -- 2.11.4.GIT