# HG changeset patch # User William Astle # Date 1664481582 21600 # Node ID e10618b48e6883371971ed6848c0de8344c25447 # Parent f3018ed5e30eac5d41f256719540d099c3bf3d7d Implement support for dragon format binaries Implement support for dragon format binaries. As an added bonus, also implement a variation on raw binaries which guarantees the whole binary fits in the file. These are the "dragon" and "abs" output formats. Based on code submitted by Mike Miller. diff -r f3018ed5e30e -r e10618b48e68 lwasm/lwasm.h --- a/lwasm/lwasm.h Wed Aug 17 17:06:30 2022 -0600 +++ b/lwasm/lwasm.h Thu Sep 29 13:59:42 2022 -0600 @@ -64,7 +64,9 @@ OUTPUT_SREC, // motorola SREC format OUTPUT_IHEX, // intel hex format OUTPUT_HEX, // generic hexadecimal format - OUTPUT_LWMOD // special module format for LW + OUTPUT_LWMOD, // special module format for LW + OUTPUT_DRAGON, // Dragon DOS binary + OUTPUT_ABS // absolute binary block }; enum lwasm_flags_e diff -r f3018ed5e30e -r e10618b48e68 lwasm/main.c --- a/lwasm/main.c Wed Aug 17 17:06:30 2022 -0600 +++ b/lwasm/main.c Thu Sep 29 13:59:42 2022 -0600 @@ -44,7 +44,7 @@ { { "output", 'o', "FILE", 0, "Output to FILE"}, { "debug", 'd', "LEVEL", lw_cmdline_opt_optional, "Set debug mode"}, - { "format", 'f', "TYPE", 0, "Select output format: decb, basic, raw, obj, os9, ihex, srec"}, + { "format", 'f', "TYPE", 0, "Select output format: decb, basic, raw, obj, os9, ihex, srec, dragon, abs"}, { "list", 'l', "FILE", lw_cmdline_opt_optional, "Generate list [to FILE]"}, { "list-nofiles", 0x104, 0, 0, "Omit file names in list output"}, { "symbols", 's', 0, lw_cmdline_opt_optional, "Generate symbol list in listing, no effect without --list"}, @@ -53,6 +53,8 @@ { "tabs", 't', "WIDTH", 0, "Set tab spacing in listing (0=don't expand tabs)" }, { "map", 'm', "FILE", lw_cmdline_opt_optional, "Generate map [to FILE]"}, { "decb", 'b', 0, 0, "Generate DECB .bin format output, equivalent of --format=decb"}, + { "dragon", 0x107, 0, 0, "Generate a Dragon DOS binary format, equivalent of --format=dragon"}, + { "abs", 0x108, 0, 0, "Generate absolute binary format, equivalent of --format=abs"}, { "raw", 'r', 0, 0, "Generate raw binary format output, equivalent of --format=raw"}, { "obj", 0x100, 0, 0, "Generate proprietary object file format for later linking, equivalent of --format=obj" }, { "depend", 0x101, 0, 0, "Output a dependency list to stdout; do not do any actual output though assembly is completed as usual" }, @@ -173,6 +175,14 @@ case 'b': as -> output_format = OUTPUT_DECB; break; + + case 0x107: + as -> output_format = OUTPUT_DRAGON; + break; + + case 0x108: + as -> output_format = OUTPUT_ABS; + break; case 'r': as -> output_format = OUTPUT_RAW; @@ -211,6 +221,10 @@ as -> output_format = OUTPUT_IHEX; else if (!strcasecmp(arg, "hex")) as -> output_format = OUTPUT_HEX; + else if (!strcasecmp(arg, "dragon")) + as -> output_format = OUTPUT_DRAGON; + else if (!strcasecmp(arg, "abs")) + as -> output_format = OUTPUT_ABS; else if (!strcasecmp(arg, "os9")) { as -> pragmas |= PRAGMA_DOLLARNOTLOCAL; diff -r f3018ed5e30e -r e10618b48e68 lwasm/output.c --- a/lwasm/output.c Wed Aug 17 17:06:30 2022 -0600 +++ b/lwasm/output.c Thu Sep 29 13:59:42 2022 -0600 @@ -44,6 +44,8 @@ void write_code_srec(asmstate_t *as, FILE *of); void write_code_ihex(asmstate_t *as, FILE *of); void write_code_lwmod(asmstate_t *as, FILE *of); +void write_code_dragon(asmstate_t *as, FILE *of); +void write_code_abs(asmstate_t *as, FILE *of); // this prevents warnings about not using the return value of fwrite() // r++ prevents the "set but not used" warnings; should be optimized out @@ -109,6 +111,14 @@ write_code_lwmod(as, of); break; + case OUTPUT_DRAGON: + write_code_dragon(as, of); + break; + + case OUTPUT_ABS: + write_code_abs(as, of); + break; + default: fprintf(stderr, "BUG: unrecognized output format when generating output file\n"); fclose(of); @@ -1259,3 +1269,94 @@ if (initsize) writebytes(initcode, initsize, 1, of); } + +void write_code_abs_calc(asmstate_t *as, unsigned int *start, unsigned int *length) +{ + line_t *cl; + unsigned int lowaddr = 65535; + unsigned int highaddr = 0; + char outbyte; + int outaddr, rc; + + // if not specified, calculate + for (cl = as -> line_head; cl; cl = cl -> next) + { + do + { + rc = fetch_output_byte(cl, &outbyte, &outaddr); + if (rc) + { + if (outaddr < lowaddr) + lowaddr = outaddr; + if (outaddr > highaddr) + highaddr = outaddr; + } + } + while (rc); + + *length = (lowaddr > highaddr) ? 0 : 1 + highaddr - lowaddr; + *start = (lowaddr > highaddr ) ? 0 : lowaddr; + } +} + +void write_code_abs_aux(asmstate_t *as, FILE *of, unsigned int start, unsigned int header_size) +{ + line_t *cl; + + char outbyte; + int outaddr, rc; + + for (cl = as -> line_head; cl; cl = cl -> next) + { + do + { + rc = fetch_output_byte(cl, &outbyte, &outaddr); + + // if first byte to write or output stream jumps address, seek + if (rc == -1) + { + fseek(of,(long int) header_size + outaddr - start, SEEK_SET); + } + if (rc) fputc(outbyte,of); + } + while (rc); + } + +} + +/* Write a DragonDOS binary file */ + +void write_code_dragon(asmstate_t *as, FILE *of) +{ + unsigned char headerbuf[9]; + unsigned int start, length; + + write_code_abs_calc(as, &start, &length); + + headerbuf[0] = 0x55; // magic $55 + headerbuf[1] = 0x02; // binary file + headerbuf[2] = (start >> 8) & 0xFF; + headerbuf[3] = (start) & 0xFF; + headerbuf[4] = (length >> 8) & 0xFF; + headerbuf[5] = (length) & 0xFF; + headerbuf[6] = (as -> execaddr >> 8) & 0xFF; + headerbuf[7] = (as -> execaddr) & 0xFF; + headerbuf[8] = 0xAA; // magic $AA + + writebytes(headerbuf, 9, 1, of); + + write_code_abs_aux(as, of, start, 9); + +} + +/* Write a monolithic binary block, respecting absolute address segments from ORG directives */ +/* Uses fseek, requires lowest code address and header offset size */ +/* Out of order ORG addresses are handled */ + +void write_code_abs(asmstate_t *as, FILE *of) +{ + unsigned int start, length; + + write_code_abs_calc(as, &start, &length); + write_code_abs_aux(as, of, start, 0); +} diff -r f3018ed5e30e -r e10618b48e68 lwasm/pseudo.c --- a/lwasm/pseudo.c Wed Aug 17 17:06:30 2022 -0600 +++ b/lwasm/pseudo.c Thu Sep 29 13:59:42 2022 -0600 @@ -102,7 +102,7 @@ as->endseen = 1; - if ((as -> output_format != OUTPUT_DECB) && (as -> output_format != OUTPUT_BASIC) && (as -> output_format != OUTPUT_LWMOD && (as -> output_format != OUTPUT_IHEX) && (as -> output_format != OUTPUT_SREC))) + if ((as -> output_format != OUTPUT_DECB) && (as -> output_format != OUTPUT_BASIC) && (as -> output_format != OUTPUT_LWMOD) && (as -> output_format != OUTPUT_IHEX) && (as -> output_format != OUTPUT_SREC) && (as -> output_format != OUTPUT_DRAGON) && (as -> output_format != OUTPUT_ABS)) { skip_operand(p); return;