~grimmware/lc3

e045692fa8fa76e82551ee73c7445e08650e648b — glenda 2 years ago ab63cf5
Added rudimentary disassembler and broke out some data and utils
5 files changed, 243 insertions(+), 49 deletions(-)

A disasm.c
M lc3.c
M lc3.h
M mkfile
A util.c
A disasm.c => disasm.c +139 -0
@@ 0,0 1,139 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
#include "lc3.h"
#include "util.c"

int debug = 0;
char *imagefile;

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

int
printreg12(int op)
{
	switch(op){
	case OP_ADD:
	case OP_AND:
	case OP_LD:
	case OP_LDI:
	case OP_LDR:
	case OP_LEA:
	case OP_NOT:
	case OP_ST:
	case OP_STI:
	case OP_STR:
		return 1;
	default:
		return 0;
	}
}

int
printpcof9(u16int op)
{
	switch(op){
	case OP_BR:
	case OP_LD:
	case OP_LDI:
	case OP_LEA:
	case OP_ST:
	case OP_STI:
	case OP_STR:
		return 1;
	default:
		return 0;
	}
}

int
printreg9(u16int op)
{
	switch(op){
	case OP_ADD:
	case OP_AND:
	case OP_JMP:
	case OP_LDR:
	case OP_NOT:
		return 1;
	case OP_JSR: // dealt with in separate case
	default:
		return 0;
	}
}

void
main(int argc, char* argv[])
{
	int c;
	ARGBEGIN {
	case 'd':
		debug++;
		break;
	case 'f':
		imagefile = EARGF(usage());
		c = readimage(imagefile);
		if(c < 1) {
			exits("Could not read image file");
		}
		c = c/2;
	} ARGEND;
	u16int instr = 0x0000;
	for(int i = origin; i < origin + c; i++){
		instr = memread(i);
		if(instr == 0){
			print("\tNOP\n");
			continue;
		}
		u16int op = instr >> 12;
		if(op == OP_JSR) {
			if((instr >> 11) & 1)
				print("\tJSR\t0x%x\n", (instr & 0x7FF));
			else 
				print("\tJSRR\t%s\n", regname[(instr >> 6) & 0x7]);
			continue;
		} else if(op == OP_TRAP){
			print("\t%s\n", trap[instr & 0xFF]);
			continue;
		}
		if(op >= OP_COUNT)
			exits("Invalid opcode");
		print("\t%s", opcode[op]);
		if(printreg12(op)) {
			print("\t%s", regname[(instr >> 9) & 0x7]);
		} else if(op == OP_BR){
			u16int fl = (instr >> 9) & 0x7;
			if(fl & FL_POS)
				print("%c", 'p');
			if(fl & FL_ZRO)
				print("%c", 'z');
			if(fl & FL_NEG)
				print("%c", 'n');
		}
		if(printpcof9(op)){
			if(op == OP_BR)
				print("\t");
			else
				print(",");
			print("0x%x\n", (instr & 0x1FF));
			continue;
		} else if(printreg9(op)) {
			print(",%s\n", regname[(instr >> 6) & 0x7]);
			continue;
		}
		if(op == OP_ADD || op == OP_AND){
			if((instr >> 5) & 1)
				print(",0x%x", instr & 0x1F);
			else
				print(",%s", regname[instr & 0x7]);
		} else if(op == OP_STR | op == OP_LDR) {
			print(",0x%x", instr & 0x3f);
		}
		print("\n");
	}
	exits(nil);
}

M lc3.c => lc3.c +2 -44
@@ 3,10 3,7 @@
#include <libc.h>
#include <stdio.h>
#include "lc3.h"

u16int memory[MEMORY_MAX];
u16int reg[R_COUNT];

#include "util.c"

int debug = 0;
int consctl;


@@ 17,44 14,6 @@ usage(void)
	fprint(2, "lc3 -f FILE");
}

u16int
swap16(u16int x)
{
	return (x << 8) | (x >> 8);
}

int
readimage(char *file)
{
	int c;
	int f = open(file, OREAD);
	if(f == -1) return 0;
	u16int origin;
	read(f, &origin, sizeof(origin));
	origin = swap16(origin);
	c = read(f, memory + origin, MEMORY_MAX - origin);
	c+=origin;
	memory[c]=0x00;	
	while(c-- > origin)
		memory[c] = swap16(memory[c]);
	return c;
}

int
memread(u16int addr)
{
	return memory[addr];
}

u16int
signextend(u16int x, u16int count)
{
	if((x >> (count-1)) & 1) {
		x |= (0xFFFF << count);
	}
	return x;
}

void
updateflags(u16int r)
{


@@ 277,8 236,7 @@ main(int argc, char* argv[])
	consctl = open("/dev/consctl", OWRITE);
	if(consctl == -1) exits("can't open /dev/consctl: %r\n");	// exactly one cond flag should be set at all times
	reg[R_COND] = FL_ZRO;
	enum { PC_START = OFFSET };
	reg[R_PC] = PC_START;
	reg[R_PC] = origin;

	int running = 1;
	while (running)

M lc3.h => lc3.h +57 -1
@@ 16,6 16,20 @@ enum
	R_COUNT
};

static const char* const regname[] =
{
	[R_R0]		= "R0",
	[R_R1]		= "R1",
	[R_R2]		= "R2",
	[R_R3]		= "R3",
	[R_R4]		= "R4",
	[R_R5]		= "R5",
	[R_R6]		= "R6",
	[R_R7]		= "R7",
	[R_PC]		= "PC",
	[R_COND]	= "COND"
};

enum
{
	OP_BR = 0,	// branch


@@ 33,7 47,28 @@ enum
	OP_JMP,		// jump
	OP_RES,		// reserved (unused)
	OP_LEA,		// load effective address
	OP_TRAP		// execute trap
	OP_TRAP,	// execute trap
	OP_COUNT
};

static const char* const opcode[] =
{
	[OP_BR]		= "BR",		// branch
	[OP_ADD]	= "ADD",	// add
	[OP_LD]		= "LD",		// load
	[OP_ST]		= "ST",		// store
	[OP_JSR]	= "JSR",	// jump register
	[OP_AND]	= "AND",	// bitwise and
	[OP_LDR]	= "LDR",	// load register
	[OP_STR]	= "STR",	// store register
	[OP_RTI]	= "RTI",	// unused
	[OP_NOT]	= "NOT",	// bitwise not
	[OP_LDI]	= "LDI",	// load indirect
	[OP_STI]	= "STI",	// store indirect
	[OP_JMP]	= "JMP",	// jump
	[OP_RES]	= "RES",	// reserved (unused)
	[OP_LEA]	= "LEA",	// load effective address
	[OP_TRAP]	= "TRAP"	// execute trap
};

enum


@@ 43,6 78,13 @@ enum
	FL_NEG = 1 << 2,	// N
};

static const char* const flag[] =
{
	[FL_POS] = "p",
	[FL_ZRO] = "z",
	[FL_NEG] = "n"
};

enum
{
	TRAP_GETC = 0x20,


@@ 52,3 94,17 @@ enum
	TRAP_PUTSP,
	TRAP_HALT
};

static const char* const trap[] =
{
	[TRAP_GETC]	= "GETC",
	[TRAP_OUT]	= "OUT",
	[TRAP_PUTS]	= "PUTS",
	[TRAP_IN]	= "IN",
	[TRAP_PUTSP]	= "PUTSP",
	[TRAP_HALT]	= "HALT"
};

u16int memory[MEMORY_MAX];
u16int reg[R_COUNT];
u16int origin = 0;

M mkfile => mkfile +8 -4
@@ 1,10 1,14 @@
</$objtype/mkfile

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

default:V: all

</sys/src/cmd/mkone
</sys/src/cmd/mkmany

install:V:
	mkdir -p $BIN
	for (i in $TARG)
		mk $MKFLAGS $i.install

A util.c => util.c +37 -0
@@ 0,0 1,37 @@
u16int
swap16(u16int x)
{
	return (x << 8) | (x >> 8);
}

int
readimage(char *file)
{
	int c;
	int f = open(file, OREAD);
	if(f == -1) return 0;
	read(f, &origin, sizeof(origin));
	origin = swap16(origin);
	c = read(f, memory + origin, MEMORY_MAX - origin);
	int progsize = c;
	c+=origin;
	memory[c]=0x00;	
	while(c-- > origin)
		memory[c] = swap16(memory[c]);
	return progsize;
}

int
memread(u16int addr)
{
	return memory[addr];
}

u16int
signextend(u16int x, u16int count)
{
	if((x >> (count-1)) & 1) {
		x |= (0xFFFF << count);
	}
	return x;
}