Jakash3’s Bytecode Language

This will be the bytecode interpreter for an upcoming assembly language called orgASM. Bytecode documentation is found in the help message.
orgasm.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void help() {
	puts(
		"orgASM bytecode interpreter - by Jakash3\n"
		"Supply filename containing bytecode as argument.\n\n"
		"Bytecode documentation:\n"
		"0x00       Increment byte at data pointer\n"
		"0x01       Increment data pointer\n"
		"0x02       Increment loaded byte\n"
		"0x10       Decrement byte at data pointer\n"
		"0x11       Decrement data pointer\n"
		"0x12       Decrement loaded byte\n"
		"0x20       Add loaded byte to byte at data pointer\n"
		"0x21       Add loaded byte to data pointer\n"
		"0x22 0x??  Add specified byte to loaded byte\n"
		"0x30       Subtract loaded byte from byte at data pointer\n"
		"0x31       Subtract loaded byte from data pointer\n"
		"0x32 0x??  Subtract specified byte from loaded byte\n"
		"0x40       Compare loaded byte with byte at data pointer\n"
		"0x41       Compare loaded byte with data pointer\n"
		"0x42 0x??  Compare loaded byte with specified byte\n"
		"0x50       Jump to offset pointed to by loaded byte\n"
		"0x51 0x??  Jump to specified offset\n"
		"0x60       Jump if zero to offset pointed to by loaded byte\n"
		"0x61 0x??  Jump if zero to specified offset\n"
		"0x70       Jump if not zero to offset pointed to by loaded byte\n"
		"0x71 0x??  Jump if not zero to specified offset\n"
		"0x80       Load byte at data pointer\n"
		"0x81       Load value of data pointer\n"
		"0x82       Load 1 byte of user input\n"
		"0x90       Print byte at data pointer\n"
		"0x91       Print data pointer value\n"
		"0x92       Print loaded byte\n"
		"0xA0       Set byte at data pointer to loaded byte\n"
		"0xA1       Set data pointer to loaded byte\n"
		"0xA2 0x??  Set loaded byte to specified byte\n"
		"0xFF       Exit\n"
	);
	exit(0);
}

void fail(const char* errmsg) { puts(errmsg); exit(1); }

int main(int argc, char** argv) {
	if (argc < 2) help();
	FILE* f;
	if (!(f = fopen(argv[1], "rb")))
		fail("Could not open file!");
	unsigned char c;
	int i;
	int regs[4];
	char input[4];
	unsigned char data[256];
	regs[0] = (int)data;
	regs[1] = 0;
	memset(data, 0, 256);
	while (!feof(f)) {
		c = fgetc(f);
		i = c % 0x10;
		c -= i;
		switch (c) {
			case 0x00:
				if (!i) *((char*)regs[i]) += 1;
				else (regs[i])++;
				regs[3] = regs[i];
				break;
			case 0x10:
				if (!i) *((char*)regs[i]) -= 1;
				else (regs[i])--;
				regs[3] = regs[i];
				break;
			case 0x20:
				if (!i) *((char*)regs[i]) += regs[2];
				else if (i == 2) { c = fgetc(f); regs[2] += c; }
				else regs[i] += regs[2];
				regs[3] = regs[i];
				break;
			case 0x30:
				if (!i) *((char*)regs[i]) -= regs[2];
				else if (i == 2) { c = fgetc(f); regs[2] -= c; }
				else regs[i] -= regs[2];
				regs[3] = regs[i];
				break;
			case 0x40:
				if (!i) regs[3] = regs[2] - *((char*)regs[0]);
				else if (i == 2) { c = fgetc(f); regs[3] = regs[2] - c; }
				else regs[3] = regs[2] - regs[i];
				break;
			case 0x50:
				if (!i) fseek(f, regs[2], SEEK_SET);
				else { c = fgetc(f); fseek(f, (int)c, SEEK_SET); }
				break;
			case 0x60:
				if (regs[3]) { fgetc(f); break; }
				if (!i) fseek(f, regs[2], SEEK_SET);
				else { c = fgetc(f); fseek(f, (int)c, SEEK_SET); }
				break;
			case 0x70:
				if (!regs[3]) { fgetc(f); break; }
				if (!i) fseek(f, regs[2], SEEK_SET);
				else { c = fgetc(f); fseek(f, (int)c, SEEK_SET); }
				break;
			case 0x80:
				if (!i) regs[2] = *((char*)regs[i]);
				else if (i == 2) { gets(input); regs[2] = input[0]; }
				else regs[2] = regs[i];
				regs[3] = regs[2];
				break;
			case 0x90:
				if (!i) putchar(*((char*)regs[i]));
				else putchar(regs[i]);
				break;
			case 0xA0:
				if (!i) *((char*)regs[i]) = regs[2];
				else if (i == 2) { c = fgetc(f); regs[2] = c; }
				else regs[i] = regs[2];
				break;
			default:
				exit(1);
		}
		regs[0] = (int)data + regs[1];
	}
	fclose(f);
	return 0;
}

Example usage to print the letter ‘A’ 21 times
Bash shell:

# First we compile orgasm.c
gcc -o orgasm orgasm.c
# Let's make a file containing bytecode
printf "\xA2\x41\xA0\xA2\x15\x90\x12\x71\x05\xFF">test
# Run it
./orgasm test
AAAAAAAAAAAAAAAAAAAAA

So basically, you have one register, one data pointer, and a 256 byte memory map. A lot of operations deal with the loaded byte in the single register. The instructions for comparing the loaded byte with something will set the zero bit on or off to indicate if the values are equal or not equal. This goes with the conditional jump if zero or jump if not zero instructions.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: