diff options
-rw-r--r-- | README.textile | 44 | ||||
-rw-r--r-- | as.c | 149 | ||||
-rw-r--r-- | as.h | 37 | ||||
-rw-r--r-- | emu.c | 42 | ||||
-rw-r--r-- | test.s | 3 |
5 files changed, 275 insertions, 0 deletions
diff --git a/README.textile b/README.textile new file mode 100644 index 0000000..c554351 --- /dev/null +++ b/README.textile @@ -0,0 +1,44 @@ +h1. subleq assembler and emulator + +An assembler and emulator for the subleq OISC(One Instruction Set Computer) from "Wikipedia":https://en.wikipedia.org/wiki/One_instruction_set_computer#Subtract_and_branch_if_less_than_or_equal_to_zero. + +h2. Why? + +I got bored. + +h2. What does it do? + +There are two programs included. + +h3. as + +as is the subleq compiler. It will take an assembly file and assemble it into emu machine code. + +Run it as @./as <input file> <output file>@. + +You can use any of instructions on Wikipedia, along with: + +* NOP: Do nothing +* SUBLEQ: This instruction will be inserted into the output verbatim. If c is not given, it is assumed to be the next instruction. +* HALT: Stop the machine +* DATA: This can take up to three arguments, which will be inserted verbatim. Arguments not given will be assumed zero. + +h3. emu + +emu is the subleq computer emulator. + +Run it as @./emu <machine code file>@ + +The file will be mutated to represent the state of memory after the execution. + +h2. Building + +Compile everything with @make@, or @make as@ and @make emu@. Clean up with @make clean@. + +h2. Bugs + +@not@ is not yet implemented, as I haven't gotten around to converting it from subleq2 to subleq. PR accepted. + +h2. Future work + +More Instructions! PR accepted! @@ -0,0 +1,149 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "as.h" + +void gettoken(TOKEN* token, FILE* file) { + char i[10]; + int a, b, c; + char line[30]; + int res; + + if (fgets(line, 30, file) == NULL) { + if (feof(file)) { + token->eof = true; + token->valid = true; + } else { + token->eof = false; + token->valid = true; + } + } else { + res = sscanf(line, "%s %x, %x, %x", i, &a, &b, &c); + + if (!strncmp(i, "nop", 3)) token->i = NOP; + if (!strncmp(i, "subleq", 6)) token->i = SUBLEQ; + if (!strncmp(i, "sub", 3)) token->i = SUB; + if (!strncmp(i, "add", 3)) token->i = ADD; + if (!strncmp(i, "jmp", 3)) token->i = JMP; + if (!strncmp(i, "mov", 3)) token->i = MOV; + if (!strncmp(i, "beq", 3)) token->i = BEQ; + if (!strncmp(i, "not", 3)) token->i = NOT; + if (!strncmp(i, "halt", 4)) token->i = HALT; + if (!strncmp(i, "data", 4)) token->i = DATA; + + token->args = res - 1; + token->a = a; + token->b = b; + token->c = c; + token->eof = false; + token->valid = true; + } +} + +bool handletoken(FILE* file, int* pc, TOKEN* token) { + switch(token->i) { + case NOP: + if (token->args != 0) return false; + *pc += 3; out(file, Z, Z, *pc); + break; + case SUBLEQ: + switch (token->args) { + case 2: + *pc += 3; out(file, token->a, token->b, *pc); + break; + case 3: + *pc += 3; out(file, token->a, token->b, token->c); + break; + default: + return false; + } + break; + case SUB: + if (token->args != 2) return false; + *pc += 3; out(file, token->a, token->b, *pc); + break; + case ADD: + if (token->args != 2) return false; + *pc += 3; out(file, token->a, Z, *pc); + *pc += 3; out(file, Z, token->b, *pc); + *pc += 3; out(file, Z, Z, *pc); + break; + case MOV: + if (token->args != 2) return false; + *pc += 3; out(file, token->b, token->b, *pc); + *pc += 3; out(file, token->a, Z, *pc); + *pc += 3; out(file, Z, token->b, *pc); + *pc += 3; out(file, Z, Z, *pc); + break; + case BEQ: + if (token->args != 2) return false; + *pc += 3; out(file, token->b, Z, *pc + 3); + *pc += 3; out(file, Z, Z, *pc + 6); + *pc += 3; out(file, Z, Z, *pc); + *pc += 3; out(file, Z, token->b, token->c); + break; + case JMP: + if (token->args != 1) return false; + *pc += 3; out(file, Z, Z, token->a); + break; + case NOT: + if (token->args != 1) return false; + *pc += 3; + break; + case HALT: + *pc += 3; out(file, -1, -1, -1); + break; + case DATA: + *pc += 3; + switch (token->args) { + case 0: + out(file, 0, 0, 0); + break; + case 1: + out(file, token->a, 0, 0); + break; + case 2: + out(file, token->a, token->b, 0); + break; + case 3: + out(file, token->a, token->b, token->c); + } + } + return true; +} + +bool parse(TOKEN* token, FILE *out, FILE *in) { + int pc = PLEN; + int line = 0; + + while(true) { + line++; + gettoken(token, in); + if (token->eof) break; + if (!token->valid || !handletoken(out, &pc, token)) { + fprintf(stderr, "Error parsing line %d\n", line); + return false; + } + } + + return true; +} + +int main(int argc, char** argv) { + if (argc < 3) + return 1; + + int ret; + FILE *in = fopen(argv[1], "r"), *out = fopen(argv[2], "w"); + TOKEN* token = malloc(sizeof(token)); + + preamble(out); + ret = parse(token, out, in); + postamble(out); + + fclose(in); + fclose(out); + free(token); + + return !ret; +} @@ -0,0 +1,37 @@ +#define bool char +#define true 1 +#define false 0 + +typedef enum { + NOP, SUBLEQ, SUB, ADD, JMP, MOV, BEQ, NOT, HALT, DATA +} INSTRUCTION; + +typedef struct { + INSTRUCTION i; + int a, b, c; + int args; + bool eof; + bool valid; +} TOKEN; + +void out(FILE* file, int a, int b, int c) { + fwrite(&a, sizeof(int), 1, file); + fwrite(&b, sizeof(int), 1, file); + fwrite(&c, sizeof(int), 1, file); + fflush(file); +} + +#define PLEN 6 +#define Z 3 + +void preamble(FILE* file) { + // Jump over Z + out(file, 1, 1, PLEN); + // Z + out(file, 0, 0, 0); +} + +void postamble(FILE* file) { + // Halt + out(file, -1, -1, -1); +} @@ -0,0 +1,42 @@ +#include <stdlib.h> +#include <stdio.h> + +int main(int argc, char** argv) { + if (argc < 2) + return 1; + + FILE* file = fopen(argv[1], "r"); + fseek(file, 0, SEEK_END); + int flen = ftell(file) / 4; + fseek(file, 0, SEEK_SET); + + int* mem = calloc(flen, sizeof(int)); + fread(mem, sizeof(int), flen, file); + fclose(file); + + int a, b, c; + int pc = 0; + + while (pc >= 0) { + a = mem[pc]; + b = mem[pc + 1]; + c = mem[pc + 2]; + if (a < 0 || b < 0) + pc = -1; + else { + mem[b] = mem[b] - mem[a]; + if (mem[b] > 0) + pc += 3; + else + pc = c; + } + } + + file = fopen(argv[1], "w"); + fwrite(mem, sizeof(int), flen, file); + fflush(file); + fclose(file); + free(mem); + + return 0; +} @@ -0,0 +1,3 @@ +add 12, 13 +halt +data 3, 4 |