~grimmware/lc3

5e4a12875100bcbca66619d784ebb5c8d0411b96 — glenda 2 years ago 3ebe86d
Did a bunch of work on the assembler
3 files changed, 180 insertions(+), 1 deletions(-)

A asm.c
M mkfile
A tests/test.asm
A asm.c => asm.c +170 -0
@@ 0,0 1,170 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
#include "lc3.h"
#define MAXLINE 256
#define MAXTOKEN 32
#define MAXSYMBOL 128
#define MAXARGS 3

typedef struct Line Line;
struct Line {
	char	label[MAXTOKEN];
	u16int	op;
	u16int	arg1;
	u16int	arg2;
	u16int	arg3;
};

typedef struct Symbol Symbol;
struct Symbol {
	char	*label;
	u16int	addr;
};

Symbol symtab[MAXSYMBOL];

int debug = 0;
int symcount = 0;
int lineno = 1;
u16int orig, pc = 0x3000;
char *asmfile;


void
usage(void)
{
	fprint(2, "lc3 -f FILE");
}

void
*emalloc(ulong size)
{
	void *p;
	p = malloc(size);
	if(p != 0)
		return p;
	fprint(2, "Could not allocate memory!\n");
	exits("Could not allocate memory!");
	return p;
}

int
gettoken(char **t, char *l)
{
	char *c;
	
	for(c = l; *c != '\t' && *c != '\n'; c++){
		if(c-l > MAXTOKEN){
			fprint(2, "Token too long on line %d\n", lineno);
			exits("Token too long");
		}
	}
	vlong len = c - l;
	*t = realloc(*t, sizeof(*t) * (len + 1));
	**t = 0;
	strncat(*t, l, len);
	return len;
}

int
parseline(char *l)
{
	int pos = 0;
	int c = 0;
	char *t = nil;
	while(l[0] && pos < MAXARGS){
		if(l[0] == ';' || l[0] == '\n') return 0;
		if(l[0] == ' ' || l[0] == '\t') {
			l++;
			pos++;
		} else if(pos == 0 && l[0] != '\t'){
			// It's a label
			symtab[symcount].addr = pc;
			l += gettoken(&t, l);
			symtab[symcount].label = t;
			symcount++;
			pos++;
		} else if(pos == 1){
			// It's an instruction or directive
			c = gettoken(&t, l);
			if(c == 0) return 0;
 			l += c;
			print("TOKEN: %s\n", t);
			if(strcmp(t,".END") == 0) {
				return -1;
			} else if(strcmp(t,".ORIG") == 0){
				//FIXME: only supporting hex for now
				l+=2; //skipping hex number indicator to raw number
				gettoken(&t, l);
				// re-use c
				c = (int) strtol(t, 0, 16);
				pc = origin = c;
				if(pc != c) { // not a valid u16int
					fprint(2, ".ORIG argument too large\n");
					exits("Orig too big");
				}
				if(debug)
					print("updated origin to %x\n", origin);
				return 0;
			} else if(strcmp(t,"NOP") == 0) {
				pc++;
				pos++;
				return 1;
			} else {
				fprint(
					2,
					"%s:%d Invalid instruction or directive: %s\n",
					asmfile,
					lineno,
					t
				);
				exits("Syntax error");
			}
		} else if(pos==2){
			return 1;
		}
	}
	fprint(2, "Should not get here\n");
	return -1;
}

void
parse(FILE *fh)
{
	char l[MAXLINE] = {0};
	while(fgets(l, MAXLINE, fh) != nil){
		if(parseline(l) < 0) break;
		lineno++;
	}
}

void
main(int argc, char* argv[])
{
	FILE *in, *out;

	ARGBEGIN {
	case 'd':
		debug++;
		break;
	case 'f':
		asmfile = EARGF(usage());
	} ARGEND;

	in = fopen(asmfile, "r");
	parse(in);
	if(debug){
		print("Symbol table:\n");
		print("No.\tLabel\tAddr\n");
		for(int i = 0; i < symcount; i++){
			print(
				"%d\t%s\t\%04x\n",
				i,
				symtab[i].label,
				symtab[i].addr
			);
		}
	}
	exits(nil);
}

M mkfile => mkfile +1 -1
@@ 1,6 1,6 @@
</$objtype/mkfile

TARG=lc3 disasm
TARG=lc3 disasm asm
BIN=/$objtype/bin/lc3
HFILES=lc3.h


A tests/test.asm => tests/test.asm +9 -0
@@ 0,0 1,9 @@
	.ORIG	x4000
; ignore me
MAIN	NOP
	NOP	;whatever
	NOP
JUNK	NOP
	.END
	ADD	r0,x1
w