changeset 543:e10618b48e68

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.
author William Astle <lost@l-w.ca>
date Thu, 29 Sep 2022 13:59:42 -0600
parents f3018ed5e30e
children f12c767c363e
files lwasm/lwasm.h lwasm/main.c lwasm/output.c lwasm/pseudo.c
diffstat 4 files changed, 120 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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;
--- 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);
+}
--- 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;