diff src/output.c @ 0:57495da01900

Initial checking of LWASM
author lost
date Fri, 03 Oct 2008 02:44:20 +0000
parents
children 34568fab6058
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/output.c	Fri Oct 03 02:44:20 2008 +0000
@@ -0,0 +1,164 @@
+/*
+ * output.c
+ *
+ * code for actually outputting the assembled code
+ */
+
+//#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+//#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#define __output_c_seen__
+//#include "instab.h"
+#include "lwasm.h"
+
+void write_code_raw(asmstate_t *as, FILE *of);
+void write_code_decb(asmstate_t *as, FILE *of);
+void write_code_rawrel(asmstate_t *as, FILE *of);
+
+void write_code(asmstate_t *as)
+{
+	FILE *of;
+	
+	if (as -> errorcount > 0)
+	{
+		fprintf(stderr, "Not doing output due to assembly errors.\n");
+		return;
+	}
+	
+	of = fopen(as -> outfile, "wb");
+	if (!of)
+	{
+		fprintf(stderr, "Cannot open '%s' for output", as -> outfile);
+		perror("");
+		return;
+	}
+
+	switch (as -> outformat)
+	{
+	case OUTPUT_RAW:
+		write_code_raw(as, of);
+		break;
+		
+	case OUTPUT_DECB:
+		write_code_decb(as, of);
+		break;
+		
+	case OUTPUT_RAWREL:
+		write_code_rawrel(as, of);
+		break;
+		
+	default:
+		fprintf(stderr, "BUG: unrecognized output format when generating output file\n");
+		fclose(of);
+		unlink(as -> outfile);
+		return;
+	}
+
+	fclose(of);
+}
+
+/*
+rawrel output treats an ORG directive as an offset from the start of the
+file. Undefined results will occur if an ORG directive moves the output
+pointer backward. This particular implementation uses "fseek" to handle
+ORG requests and to skip over RMBs.
+
+This simple brain damanged method simply does an fseek before outputting
+each instruction.
+*/
+void write_code_rawrel(asmstate_t *as, FILE *of)
+{
+	sourceline_t *cl;
+	
+	for (cl = as -> source_head; cl; cl = cl -> next)
+	{
+		if (cl -> nocode)
+			continue;
+		
+		fseek(of, cl -> addr, SEEK_SET);
+		fwrite(cl -> codebytes, cl -> numcodebytes, 1, of);
+	}
+}
+
+/*
+raw merely writes all the bytes directly to the file as is. ORG is just a
+reference for the assembler to handle absolute references. Multiple ORG
+statements will produce mostly useless results
+*/
+void write_code_raw(asmstate_t *as, FILE *of)
+{
+	sourceline_t *cl;
+	
+	for (cl = as -> source_head; cl; cl = cl -> next)
+	{
+		if (cl -> nocode && cl -> len > 0)
+		{
+			int i;
+			for (i = 0; i < cl -> len; i++)
+				fwrite("\0", 1, 1, of);
+			continue;
+		}
+		if (cl -> nocode)
+			continue;
+		
+		fwrite(cl -> codebytes, cl -> numcodebytes, 1, of);
+	}
+}
+
+void write_code_decb(asmstate_t *as, FILE *of)
+{
+	long preambloc;
+	sourceline_t *cl;
+	int blocklen = -1;
+	int nextcalc = -1;
+	unsigned char outbuf[5];
+	
+	for (cl = as -> source_head; cl; cl = cl -> next)
+	{
+		if (cl -> nocode)
+			continue;
+		if (cl -> addr != nextcalc && cl -> numcodebytes > 0)
+		{
+			// need preamble here
+			if (blocklen > 0)
+			{
+				fseek(of, preambloc, SEEK_SET);
+				outbuf[0] = (blocklen >> 8) & 0xFF;
+				outbuf[1] = blocklen & 0xFF;
+				fwrite(outbuf, 2, 1, of);
+				fseek(of, 0, SEEK_END);
+			}
+			blocklen = 0;
+			nextcalc = cl -> addr;
+			outbuf[0] = 0x00;
+			outbuf[1] = 0x00;
+			outbuf[2] = 0x00;
+			outbuf[3] = (nextcalc >> 8) & 0xFF;
+			outbuf[4] = nextcalc & 0xFF;
+			preambloc = ftell(of) + 1;
+			fwrite(outbuf, 5, 1, of);
+		}
+		nextcalc += cl -> numcodebytes;
+		fwrite(cl -> codebytes, cl -> numcodebytes, 1, of);
+		blocklen += cl -> numcodebytes;
+	}
+	if (blocklen > 0)
+	{
+		fseek(of, preambloc, SEEK_SET);
+		outbuf[0] = (blocklen >> 8) & 0xFF;
+		outbuf[1] = blocklen & 0xFF;
+		fwrite(outbuf, 2, 1, of);
+		fseek(of, 0, SEEK_END);
+	}
+	
+	// now write postamble
+	outbuf[0] = 0xFF;
+	outbuf[1] = 0x00;
+	outbuf[2] = 0x00;
+	outbuf[3] = (as -> execaddr >> 8) & 0xFF;
+	outbuf[4] = (as -> execaddr) & 0xFF;
+	fwrite(outbuf, 5, 1, of);
+}