aboutsummaryrefslogtreecommitdiff
path: root/pu2/pu2.c
diff options
context:
space:
mode:
Diffstat (limited to 'pu2/pu2.c')
-rw-r--r--pu2/pu2.c407
1 files changed, 334 insertions, 73 deletions
diff --git a/pu2/pu2.c b/pu2/pu2.c
index 101cf8d..9e1a07c 100644
--- a/pu2/pu2.c
+++ b/pu2/pu2.c
@@ -2,6 +2,7 @@
#include "pu2.out.c"
//
#include <errno.h>
+#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -9,7 +10,11 @@
#include <time.h>
#include <unistd.h>
-typedef char *string;
+typedef char *string;
+typedef unsigned char byte;
+typedef byte bool;
+const bool true = 1;
+const bool false = 0;
string read_file(string path, int *out_size) {
FILE *f = fopen(path, "rb");
@@ -96,12 +101,42 @@ long powi(long x, unsigned n) {
return p == 0 ? 0 : r;
}
-emu() {
+typedef struct {
+ int pid;
+ int ring_level;
+ int *memory;
+ int mem_size;
+
+ struct {
+ bool spawn_process : 1;
+ bool make_syscall : 1;
+ } permissions;
+} emu_process;
+
+#define pid_count 512
+emu_process processes[ pid_count ]; // maximum process count
+bool process_occupied[ pid_count ];
+
+struct emu_return {
+ bool time_finished;
+ int e_code;
+} emu(int time_slice, int pid) {
+ process_occupied[ pid ] = true;
+ emu_process process = processes[ pid ];
+ int *m = process.memory;
+
while (1) {
- pu2();
- int e_code = m[ 0 ];
+ int remaining_time = pu2(time_slice, m, process.mem_size);
+ int e_code = m[ 0 ];
- if (e_code != 2) return e_code;
+ if (remaining_time <= 0 && time_slice != -1) {
+ // process_occupied[ pid ] = false;
+ return (struct emu_return) { true, e_code };
+ }
+ if (e_code != 2) {
+ process_occupied[ pid ] = false;
+ return (struct emu_return) { false, e_code };
+ }
// handle hardware interrupts
int int_code = m[ 1 ];
@@ -144,7 +179,7 @@ emu() {
m[ 3 ] = val1 >> val2;
} else if (op == 5) {
// pow
- if (val1 == 2) m[ 3 ] = val1 << val2;
+ if (val1 == 2) m[ 3 ] = 1 << val2;
else { m[ 3 ] = powi(val1, val2); }
}
@@ -154,12 +189,147 @@ emu() {
}
}
+ // permission features
+ else if (int_code == 3) {
+ int op = m[ 2 ];
+
+ if (op == 0) {
+ // spawn process
+ int target_ring = m[ 10 ];
+ int memory_start = m[ 11 ];
+ int memory_length = m[ 12 ];
+ int can_spawn_processes = m[ 13 ];
+ int can_make_syscalls = m[ 14 ];
+ int max_time_limit = m[ 15 ];
+
+ if (target_ring < process.ring_level) {
+ // error - process cannot spawn a process on a lower ring level
+ m[ 2 ] = 2;
+ goto HAD_ERROR;
+ }
+
+ if ((can_spawn_processes && !(process.permissions.spawn_process & 0b1))
+ || (can_make_syscalls && !(process.permissions.make_syscall & 0b1))) {
+ // error - host process cannot elevate permissions of the spawning process
+ m[ 2 ] = 3;
+ goto HAD_ERROR;
+ }
+
+ int new_pid = 0;
+
+ for (new_pid = 0; new_pid < pid_count; new_pid++) {
+ if (!process_occupied[ new_pid ]) goto FOUND;
+ }
+
+ // error - process pool exhausted
+ m[ 2 ] = 2;
+ goto HAD_ERROR;
+
+ FOUND:;
+
+ int *new_process_memory = calloc(memory_length, sizeof(int));
+
+ process_occupied[ new_pid ] = true;
+ processes[ new_pid ]
+ = (emu_process) { .pid = new_pid,
+ .ring_level = target_ring,
+ .memory = new_process_memory,
+ .mem_size = memory_length,
+ .permissions = { .make_syscall = !!can_make_syscalls,
+ .spawn_process = !!can_spawn_processes } };
+
+ // copy memory
+ memcpy(new_process_memory, m + memory_start, memory_length * sizeof(int));
+
+ // run process
+ struct emu_return result = emu(max_time_limit, new_pid);
+
+ // store results
+ m[ 2 ] = 0;
+ m[ 3 ] = new_pid;
+ m[ 4 ] = result.e_code;
+ m[ 5 ] = result.time_finished;
+ } else if (op == 1) {
+ // resume process pid (if it's halted)
+ int process_pid = m[ 10 ];
+ int max_time_limit = m[ 11 ];
+
+ if (!process_occupied[ process_pid ]) {
+ // error - process is not running, start/initialize it first
+ m[ 2 ] = 2;
+ goto HAD_ERROR;
+ }
+
+ if (processes[ process_pid ].ring_level < processes[ pid ].ring_level) {
+ // error - cannot interact with higher-privileged process
+ m[ 2 ] = 3;
+ goto HAD_ERROR;
+ }
+
+ // run process
+ struct emu_return result = emu(max_time_limit, process_pid);
+
+ // store results
+ m[ 2 ] = 0;
+ m[ 3 ] = result.e_code;
+ m[ 4 ] = result.time_finished;
+ } else if (op == 2) {
+ // read memory from another process
+ int process_pid = m[ 10 ];
+ int memory_address = m[ 11 ];
+ int read_length = m[ 12 ];
+ int target_location = m[ 13 ];
+
+ if (processes[ process_pid ].ring_level < processes[ pid ].ring_level
+ || processes[ pid ].ring_level > 3) {
+ // error - cannot interact with higher-privileged process
+ m[ 2 ] = 2;
+ goto HAD_ERROR;
+ }
+
+ // copy information
+ int *memory = processes[ process_pid ].memory;
+ memcpy(m + target_location, memory + memory_address, read_length * sizeof(int));
+
+ // done!
+ m[ 2 ] = 0;
+ } else if (op == 3) {
+ // write memory to target process
+ int process_pid = m[ 10 ];
+ int memory_address = m[ 11 ];
+ int write_length = m[ 12 ];
+ int target_location = m[ 13 ];
+
+ if (processes[ process_pid ].ring_level < processes[ pid ].ring_level
+ || processes[ pid ].ring_level > 3) {
+ // error - cannot interact with higher-privileged process
+ m[ 2 ] = 2;
+ goto HAD_ERROR;
+ }
+
+ // write information
+ int *memory = processes[ process_pid ].memory;
+ memcpy(memory + memory_address, m + target_location, write_length * sizeof(int));
+
+ // done!
+ m[ 2 ] = 0;
+ }
+
+ else {
+ // unknown op, set m[2]
+ m[ 2 ] = 1;
+ }
+ }
+
else {
// unknown interrupt. what to do?
}
+ HAD_ERROR:
m[ 0 ] = 0;
}
+
+ process_occupied[ pid ] = false;
}
skip_space(string *I) {
@@ -175,11 +345,6 @@ struct {
};
// clang-format on
-typedef unsigned char byte;
-typedef byte bool;
-const bool true = 1;
-const bool false = 0;
-
// use this instead of strdup'ing and allocating extra storage!
typedef struct {
int len;
@@ -258,11 +423,11 @@ clean_slice_ref(slice_t *val) { free(val->ref); }
} \
I++; \
str_len++; \
- int *dest_start = Data -= str_len; \
+ int *dest_start = Data -= str_len + 1; \
int y; \
for (y = 0; y < str_len - 1; y++) { dest_start[ y ] = str_start[ y ]; } \
Data[ -1 ] = 0; \
- value = Data - m; \
+ value = Data - assembly_target; \
} else if (*I == '&') { \
I++; \
string starting_I = I; \
@@ -299,6 +464,8 @@ clean_slice_ref(slice_t *val) { free(val->ref); }
#define imm_in_mem(__mem, __imm) (imm(__mem), emit(opcode.cb3, __imm))
#define mov_mem_mem(__mem1, __mem2) (imm(__mem1), emit(opcode.cb4, __mem2))
#define mem_in_a(__mem) emit(opcode.cb2, __mem)
+#define a_in_mem(__mem) emit(opcode.cb1, __mem)
+#define deref_a() (op(b2u), swap(), load(), op(u2b))
#define perform_op(operation) \
({ \
mem_in_a(mem2_index); \
@@ -315,9 +482,9 @@ string ERR_code;
int *Code;
int *Data;
-init_ir2() {
- Code = &m[ 4000 ];
- Data = &m[ S - 1 ]; // grows downwards
+init_ir2(int *target_mem, int max_size) {
+ Code = &target_mem[ 4000 ];
+ Data = &target_mem[ max_size - 1 ]; // grows downwards
}
__attribute__((always_inline)) emit(int op, int val) {
@@ -347,6 +514,8 @@ __ir2_get_var_loc(slice_t name, label_t variables[ 1 << 11 ], string error_I, st
string _ir2(
string I,
+ string filepath,
+ int *assembly_target,
macro_t *macros,
label_t *labels,
label_delegated_t *forward_refs,
@@ -399,7 +568,7 @@ string _ir2(
space;
int *m_index = --Data;
- int start_index = m_index - m;
+ int start_index = m_index - assembly_target;
if (*I == ':') {
I++;
@@ -411,6 +580,7 @@ string _ir2(
"expected memory index in variable declaration (i think i remember this "
"one...)");
}
+ Data++; // free the taken space
start_index = strtol(I, &I, 10);
space;
}
@@ -437,7 +607,6 @@ string _ir2(
imm_in_mem(start_index, scanvalue());
#endif
} else if (varqual(*I)) { // memory address
- I++;
int mem_index = scanvar();
mov_mem_mem(start_index, mem_index);
} else {
@@ -469,6 +638,39 @@ string _ir2(
continue;
}
+ if (strncmp("import", I, 6) == 0 && isspace(I[ 6 ])) {
+ I += 6;
+ space;
+ slice_t path = { 0, I };
+ while (*I != ';') {
+ I++;
+ path.len++;
+ if (*I == 0 || *I == '\n')
+ run_err(path.ref, "reached invalid character / EOF whilst reading import path");
+ }
+ checkskip(';', "expected semicolon");
+
+ string output;
+ if (path.ref[ 0 ] == '/') asprintf(&output, "%.*s", path.len, path.ref);
+ else asprintf(&output, "%s/%.*s", dirname(filepath), path.len, path.ref);
+
+ int out_size;
+ string text = read_file(output, &out_size);
+ if (text == NULL) {
+ printf("failed to import \"%s\"\n", output);
+ perror("unable to use import");
+ free(output);
+ exit(1);
+ }
+
+ _ir2(text, filepath, assembly_target, macros, labels, forward_refs, variables);
+
+ free(output);
+ free(text);
+
+ continue;
+ }
+
// register macros
if (strncmp("macro", I, 5) == 0 && isspace(I[ 5 ])) {
I += 6;
@@ -543,7 +745,7 @@ string _ir2(
}
// emit exit calls
- if (strncmp("exit", I, 4) == 0) {
+ if (strncmp("exit", I, 4) == 0 && !varqual(I[ 4 ])) {
I += 4;
checkskip('(', "expected open paren on exit blob");
@@ -566,7 +768,7 @@ string _ir2(
}
// emit system
- if (strncmp("system", I, 6) == 0 && !isalnum(I[ 6 ])) {
+ if (strncmp("system", I, 6) == 0 && !varqual(I[ 6 ])) {
I += 6;
space;
checkskip('(', "expected open paren on system blob");
@@ -583,12 +785,12 @@ string _ir2(
continue;
}
- if (strncmp("jump", I, 4) == 0 && !isalnum(I[ 4 ])) {
+ if (strncmp("jump", I, 4) == 0 && !varqual(I[ 4 ])) {
I += 4;
goto PARSE_JUMP_BLOB;
}
- if (strncmp("jmp", I, 3) == 0 && !isalnum(I[ 3 ])) {
+ if (strncmp("jmp", I, 3) == 0 && !varqual(I[ 3 ])) {
I += 3;
PARSE_JUMP_BLOB:
space;
@@ -641,8 +843,8 @@ string _ir2(
continue;
}
- if ((strncmp("jnz", I, 3) == 0 && !isalnum(I[ 3 ]))
- || (strncmp("jz", I, 2) == 0 && !isalnum(I[ 2 ]))) {
+ if ((strncmp("jnz", I, 3) == 0 && !varqual(I[ 3 ]))
+ || (strncmp("jz", I, 2) == 0 && !varqual(I[ 2 ]))) {
bool was_jnz = !!strncmp("jz", I, 2);
string name = was_jnz ? "jnz" : "jz";
@@ -734,7 +936,7 @@ string _ir2(
continue;
}
- if (strncmp("if", I, 2) == 0 && !isalnum(I[ 2 ])) {
+ if (strncmp("if", I, 2) == 0 && !varqual(I[ 2 ])) {
// if statement
I += 2;
space;
@@ -769,7 +971,7 @@ string _ir2(
Data = Code = m2;
// get new I location
- string new_I = _ir2(I, macros, labels, forward_refs, variables_G);
+ string new_I = _ir2(I, filepath, m2, macros, labels, forward_refs, variables_G);
I = new_I;
// restore values
Code = Code_B;
@@ -779,8 +981,9 @@ string _ir2(
free(variables_G);
} else {
// just... i mean, i guess run the code..?
- string new_I = _ir2(I, macros, labels, forward_refs, variables);
- I = new_I;
+ string new_I = _ir2(
+ I, filepath, assembly_target, macros, labels, forward_refs, variables);
+ I = new_I;
}
continue;
@@ -810,15 +1013,16 @@ string _ir2(
op(str);
// handle the code stuff
- string new_I = _ir2(I, macros, labels, forward_refs, variables);
- I = new_I;
+ string new_I
+ = _ir2(I, filepath, assembly_target, macros, labels, forward_refs, variables);
+ I = new_I;
- *patchback = Code - m; // patch the jump instruction
+ *patchback = Code - assembly_target; // patch the jump instruction
continue;
}
- if (strncmp("while", I, 5) == 0 && !isalnum(I[ 5 ])) {
+ if (strncmp("while", I, 5) == 0 && !varqual(I[ 5 ])) {
I += 5;
space;
checkskip('(', "expected open paren for while loop");
@@ -853,7 +1057,7 @@ string _ir2(
Data = Code = m2;
// get new I location
- string new_I = _ir2(I, macros, labels, forward_refs, variables_G);
+ string new_I = _ir2(I, filepath, m2, macros, labels, forward_refs, variables_G);
I = new_I;
// restore values
Code = Code_B;
@@ -864,10 +1068,11 @@ string _ir2(
} else {
// run forever!
- int start = Code - m;
+ int start = Code - assembly_target;
- string new_I = _ir2(I, macros, labels, forward_refs, variables);
- I = new_I;
+ string new_I = _ir2(
+ I, filepath, assembly_target, macros, labels, forward_refs, variables);
+ I = new_I;
imm_in_mem(7, start); // always jump back to the start
}
@@ -898,13 +1103,14 @@ string _ir2(
imm(7);
op(str);
- int start_index = Code - m;
+ int start_index = Code - assembly_target;
// handle the code stuff
- string new_I = _ir2(I, macros, labels, forward_refs, variables);
- I = new_I;
+ string new_I
+ = _ir2(I, filepath, assembly_target, macros, labels, forward_refs, variables);
+ I = new_I;
- *patchback = Code - m; // patch the jump instruction
+ *patchback = Code - assembly_target; // patch the jump instruction
// check the condition and jump back if true
mem_in_a(mem_index);
@@ -946,7 +1152,7 @@ string _ir2(
FOUND_SLOT:
slot->name = name;
- slot->location = Code - m;
+ slot->location = Code - assembly_target;
continue;
}
@@ -1075,7 +1281,7 @@ string _ir2(
new.ref[ used ] = 0;
- _ir2(new.ref, macros, labels, forward_refs, variables);
+ _ir2(new.ref, filepath, assembly_target, macros, labels, forward_refs, variables);
continue;
}
@@ -1083,7 +1289,14 @@ string _ir2(
REST_AFTER_MACRO_CALL:
// handle assignments!
- if (varqual(T)) {
+ if (T == '*' || varqual(T)) {
+ bool lhs_deref = T == '*';
+ if (lhs_deref) {
+ I++;
+ space;
+ if (!varqual(*I)) run_err(I, "expected memory index or variable after dereference");
+ }
+
string starting_qual = I;
int mem_index = scanvar();
space;
@@ -1092,12 +1305,14 @@ string _ir2(
I += 2;
space;
checkskip(';', "expected semicolon");
- imm(1);
- swap();
mem_in_a(mem_index);
+ if (lhs_deref) deref_a();
+ emit(opcode.acc, 1);
+ op(u2b);
op(sub);
swap();
- imm(mem_index);
+ if (lhs_deref) mem_in_a(mem_index);
+ else { imm(mem_index); }
store();
continue;
@@ -1107,18 +1322,21 @@ string _ir2(
I += 2;
space;
checkskip(';', "expected semicolon");
- imm(1);
- swap();
mem_in_a(mem_index);
+ if (lhs_deref) deref_a();
+ emit(opcode.acc, 1);
+ op(u2b);
op(add);
swap();
- imm(mem_index);
+ if (lhs_deref) mem_in_a(mem_index);
+ else { imm(mem_index); }
store();
continue;
}
- char extra_op = '=';
+ string expr_I = I;
+ char extra_op = '=';
if (*I == '+' || *I == '-' || *I == '&' || *I == '!') extra_op = *I++;
checkskip('=', "expected assigment after memory blob (hint: only +-&! are supported)");
space;
@@ -1129,12 +1347,42 @@ string _ir2(
printf(" if this behavior is intended, use the jump blob instead.\n\n");
}
- if (varqual(*I)) {
+ if (*I == '*' || varqual(*I)) {
+ bool rhs_deref = *I == '*';
+ if (rhs_deref) {
+ I++;
+ space;
+ if (!varqual(*I))
+ run_err(I, "expected memory index or variable after dereference");
+ }
+
+ if ((lhs_deref || rhs_deref) && extra_op != '=') {
+ run_err(expr_I, "dereferencing is not possible with arithmetic. (i was lazy)");
+ }
+
int mem2_index = scanvar();
space;
if (extra_op == '=') {
- mov_mem_mem(mem_index, mem2_index);
+ if (lhs_deref) {
+ // m[m[a]] = m[b]
+ // m[m[a]] = m[m[b]]
+ mem_in_a(mem2_index);
+ if (rhs_deref) deref_a();
+ swap();
+ mem_in_a(mem_index);
+ store();
+ } else {
+ if (rhs_deref) {
+ // m[a] = m[m[b]]
+ mem_in_a(mem2_index);
+ deref_a();
+ a_in_mem(mem_index);
+ } else {
+ // m[a] = m[b]
+ mov_mem_mem(mem_index, mem2_index);
+ }
+ }
} else if (extra_op == '+') {
perform_op(add);
} else if (extra_op == '-') {
@@ -1196,7 +1444,7 @@ string _ir2(
return I;
}
-ir2(string I) {
+ir2(string I, string filepath, int *assembly_target) {
const int macros_n = 1 << 9;
const int labels_n = 1 << 10;
const int vars_n = 1 << 11;
@@ -1212,7 +1460,7 @@ ir2(string I) {
exit(1);
}
- _ir2(I, macros, labels, forward_refs, variables);
+ _ir2(I, filepath, assembly_target, macros, labels, forward_refs, variables);
label_delegated_t *curf = forward_refs;
// handle forward references!
@@ -1272,21 +1520,21 @@ clock_t ntime() {
#endif
// bench: measure using clock()
-double bench_cycle(int instr) {
+double bench_cycle(int instr, int *m, int mem_size) {
int i;
- for (i = 0; i < S - 2; i += 2) {
+ for (i = 16; i < S - 2; i += 2) {
m[ i ] = instr;
m[ i + 1 ] = 10;
}
m[ S - 2 ] = 0;
m[ S - 1 ] = 0;
- m[ 7 ] = 0;
+ m[ 7 ] = 16;
c = 0;
clock_t start = ntime();
int wstart = rdtsc();
- pu2();
+ pu2(-1, m, mem_size);
int wend = rdtsc();
clock_t end = ntime();
@@ -1307,20 +1555,20 @@ double bench_cycle(int instr) {
}
// bench2: measure using rdtsc
-double bench2_cycle(int instr) {
+double bench2_cycle(int instr, int *m, int mem_size) {
unsigned long long start, end;
double vminst_count, cpu_cycles;
int i;
- for (i = 0; i < S - 2; i += 2) {
+ for (i = 16; i < S - 2; i += 2) {
m[ i ] = instr;
m[ i + 1 ] = 5;
}
m[ S - 2 ] = 0;
m[ S - 1 ] = 0;
- m[ 7 ] = 0;
+ m[ 7 ] = 16;
c = 0;
start = rdtsc();
- pu2();
+ pu2(-1, m, mem_size);
end = rdtsc();
cpu_cycles = (double) (end - start);
vminst_count = (double) m[ 7 ] / 2;
@@ -1356,7 +1604,7 @@ inline() sleep_micro(int microseconds) { sleep_nano(microseconds * 1e3); }
inline() sleep_milli(int milliseconds) { sleep_nano(milliseconds * 1e6); }
// benchmark: run target for all opcodes and print summary
-benchmark(double (*target)(int), const char *mode_label) {
+benchmark(double (*target)(int, int *, int), const char *mode_label, int *m, int mem_size) {
double results[ 19 ];
double sum = 0;
int count = 0;
@@ -1368,7 +1616,7 @@ benchmark(double (*target)(int), const char *mode_label) {
for (i = 1; i < 19; i++) {
// printf("running: %s\n", op_names[ i ]);
- results[ i ] = target(i);
+ results[ i ] = target(i, m, mem_size);
sum += results[ i ];
count++;
}
@@ -1412,11 +1660,14 @@ main(int argc, char **argv) {
return 1;
}
- init_pu2();
- init_ir2();
+ int *assembly_target = calloc(S, sizeof(int));
+
+ init_ir2(assembly_target, S);
if (strcmp(argv[ 1 ], "benchmark") == 0) {
- benchmark(bench_cycle, "time");
+ int *m = init_pu2();
+ int mem_size = S;
+ benchmark(bench_cycle, "time", m, mem_size);
const long N = S / 2; // printably the same insts you report
long sum = 0;
@@ -1449,10 +1700,10 @@ main(int argc, char **argv) {
int o_size;
long before = ntime();
long cycles_bef = rdtsc();
- ir2(contents);
- long cycles_aft = rdtsc();
- long after = ntime();
- m[ 7 ] = 4000;
+ ir2(contents, filename, assembly_target);
+ long cycles_aft = rdtsc();
+ long after = ntime();
+ assembly_target[ 7 ] = 4000;
/*int j = 0;
for(j = 0; j < 64; j++) {
@@ -1464,7 +1715,17 @@ main(int argc, char **argv) {
free(contents);
- int res_size = Code - &m[ 4000 ];
+ // int res_size = Code - &m[ 4000 ];
+
+ // run the kernel (ring zero) forever (time slice -1)
+ int mem_size = S;
+
+ // pid zero - kernel
+ processes[ 0 ]
+ = (emu_process) { .mem_size = S,
+ .memory = assembly_target,
+ .ring_level = 0,
+ .permissions = { .make_syscall = true, .spawn_process = true } };
- emu();
+ emu(-1, 0);
}