aboutsummaryrefslogtreecommitdiff
path: root/pu2
diff options
context:
space:
mode:
Diffstat (limited to 'pu2')
-rw-r--r--pu2/Makefile3
-rw-r--r--pu2/code.i235
-rw-r--r--pu2/code/kernel.i246
-rw-r--r--pu2/code/lib.i237
-rw-r--r--pu2/code/main.i230
-rw-r--r--pu2/i2-syntax/syntaxes/i2.tmLanguage.json26
-rw-r--r--pu2/pu2.c407
-rw-r--r--pu2/pu2.out.c94
8 files changed, 542 insertions, 136 deletions
diff --git a/pu2/Makefile b/pu2/Makefile
index aa1f325..68fbcd0 100644
--- a/pu2/Makefile
+++ b/pu2/Makefile
@@ -1,6 +1,9 @@
build:
clang pu2.c -o pu2 -std=c89 -ffunction-sections -Wl,--gc-sections -O3 -march=native -mtune=native -flto -ffast-math -funroll-loops -fno-exceptions
+build_fast:
+ clang pu2.c -o pu2 -std=c89 -O0 -g
+
# i use this for building pu2 on a-Shell
build_wasi:
clang pu2.c -o pu2 -std=c89 -ffunction-sections -Wl,--gc-sections -O3 -ffast-math -funroll-loops -fno-exceptions -DPU2_BAD_CLOCK -DPU2_NO_ASM -DPU2_NO_MMAP -fno-rtti -fno-stack-protector -fomit-frame-pointer -Wno-format -Wno-#warnings
diff --git a/pu2/code.i2 b/pu2/code.i2
deleted file mode 100644
index b173469..0000000
--- a/pu2/code.i2
+++ /dev/null
@@ -1,35 +0,0 @@
-
-/*
-
- testing grounds for the ir2 assembler
- i still don't know whether it's a compiler, an IR emitter, or an assembler
- hmmm...
-
-*/
-
-macro puts(2) {
- @1 = 0; // write
- @2 = /1/; // ptr
- @3 = /2/; // size
- system();
-}
-
-macro putchar(1) {
- @1 = 0; // write
- @2 = 10; // ptr
- @3 = 1; // size
- @10 = /1/; // value
- system();
-}
-
-let count = 5;
-
-while (count) {
- count--;
-
- puts(["hello"], [5]);
- putchar([10]);
-}
-
-exit(0);
-
diff --git a/pu2/code/kernel.i2 b/pu2/code/kernel.i2
new file mode 100644
index 0000000..2da075c
--- /dev/null
+++ b/pu2/code/kernel.i2
@@ -0,0 +1,46 @@
+import lib.i2;
+
+// test - write memory, spawn process, read memory
+
+macro spawn_sudo(3) {
+ @1 = 3; // authorized feature
+ @2 = 0; // spawn process
+
+ @10 = 1; // target ring = 1
+ @11 = /1/; // memory start
+ @12 = /2/; // memory length
+ @13 = 1; // can spawn procs
+ @14 = 1; // can make syscalls
+ @15 = /3/; // time slice limit
+
+ system(); // interrupt
+}
+
+macro read_pmem(4) {
+ @1 = 3; // authorized feature
+ @2 = 2; // read memory
+ @10 = /1/; // target pid
+ @11 = /2/; // address
+ @12 = /3/; // length
+ @13 = /4/; // target
+
+ system(); // interrupt
+}
+
+/* write the actual program */
+@1007 = 10;
+@1010 = 1; @1011 = 3; // a = 3;
+@1012 = 17; @1013 = 9; // m[3] = 9;
+@1014 = 0; @1015 = 0; // halt
+spawn_sudo([1000], [16], [5]);
+
+let output = @2;
+let pid = @3;
+let exit_code = @4;
+let finished = @5;
+
+let read_out = 0;
+read_pmem([pid], [3], [1], [&read_out]);
+
+read_out += '0';
+putchar([read_out]); \ No newline at end of file
diff --git a/pu2/code/lib.i2 b/pu2/code/lib.i2
new file mode 100644
index 0000000..e619fd8
--- /dev/null
+++ b/pu2/code/lib.i2
@@ -0,0 +1,37 @@
+// standard library for i2
+
+macro puts(2) {
+ @1 = 0; // write
+ @2 = /1/; // ptr
+ @3 = /2/; // size
+ system(); // interrupt
+}
+
+macro putchar(1) {
+ @1 = 0; // write
+ @2 = 10; // ptr
+ @3 = 1; // size
+ @10 = /1/; // value
+ system(); // interrupt
+}
+
+// &str, out_dest
+macro strlen(2) {
+ @20 = /1/; // get reference to var
+ @21 = 0; // char count
+ @22 = *@20;
+ while(@22) {
+ @20++;
+ @22 = *@20;
+ @21++;
+ }
+
+ /2/ = @21;
+}
+
+macro print(1) {
+ strlen([/1/], [@3]);
+ @1 = 0; // write
+ @2 = /1/; // ptr
+ system(); // interrupt
+} \ No newline at end of file
diff --git a/pu2/code/main.i2 b/pu2/code/main.i2
new file mode 100644
index 0000000..8cc5615
--- /dev/null
+++ b/pu2/code/main.i2
@@ -0,0 +1,30 @@
+
+/*
+
+ testing grounds for the ir2 assembler
+ i still don't know whether it's a compiler, an IR emitter, or an assembler
+ hmmm...
+
+*/
+
+import lib.i2;
+
+let initial = 5;
+let count = initial;
+
+while (count) {
+ count--;
+
+ print(["hello "]);
+
+ // basically equivalent to putchar(initial - count + '0' - 1)
+ let index = initial;
+ index -= count;
+ index += 47; // '0' - 1
+ putchar([index]);
+
+ putchar([10]);
+}
+
+exit(0);
+
diff --git a/pu2/i2-syntax/syntaxes/i2.tmLanguage.json b/pu2/i2-syntax/syntaxes/i2.tmLanguage.json
index b1078e2..190711e 100644
--- a/pu2/i2-syntax/syntaxes/i2.tmLanguage.json
+++ b/pu2/i2-syntax/syntaxes/i2.tmLanguage.json
@@ -12,6 +12,9 @@
"include": "#block-comments"
},
{
+ "include": "#imports"
+ },
+ {
"include": "#macro-reference"
},
{
@@ -132,6 +135,27 @@
}
]
},
+ "imports": {
+ "begin": "\\b(import)\\b\\s+",
+ "beginCaptures": {
+ "1": {
+ "name": "keyword.control.import.i2"
+ }
+ },
+ "end": ";",
+ "endCaptures": {
+ "0": {
+ "name": "punctuation.separator.semicolon.i2"
+ }
+ },
+ "name": "meta.import.i2",
+ "patterns": [
+ {
+ "name": "constant.other.path.i2",
+ "match": "(?:\\./|/)?[A-Za-z0-9_./-]+\\.i2\\b"
+ }
+ ]
+ },
"braces": {
"name": "punctuation.section.block.i2",
"match": "[\\{\\}]"
@@ -146,7 +170,7 @@
},
"keywords": {
"name": "keyword.control.i2",
- "match": "\\b(?:macro|system|exit|let|while|if)\\b"
+ "match": "\\b(?:macro|system|exit|let|while|if|import)\\b"
},
"jump-call": {
"begin": "\\b(?:jmp|jz|jnz)\\s*\\(",
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);
}
diff --git a/pu2/pu2.out.c b/pu2/pu2.out.c
index 3091919..6922ccf 100644
--- a/pu2/pu2.out.c
+++ b/pu2/pu2.out.c
@@ -7,6 +7,7 @@
// - OLD_CLANG Use if your compiler version is not very up-to-date.
// - SPEED_IMPROVEMENT Almost doubles clock rate for the VM with a few optimizations.
// - EXTENDED_INSTRUCTION_SET Adds a few instructions which decrease token throughput for ir2. The high-level IR emitter will not work otherwise.
+ // - TIME_SLICE_SUPPORT Adds support for time slices, a way for the emulation layer to manage how long a pu2 program runs for. Only supported in the speed optimized version.
// clang-format on
/* -- BEGIN COMPILE TIME FLAGS -- */
@@ -17,6 +18,7 @@
// #define PU2_OLD_CLANG
#define PU2_SPEED_IMPROVEMENT
#define PU2_EXTENDED_INSTRUCTION_SET
+#define PU2_TIME_SLICE_SUPPORT
/* -- END COMPILE TIME FLAGS --*/
#ifdef PU2_NO_ASM
@@ -25,6 +27,7 @@
#define _GNU_SOURCE
#include <ctype.h>
+#include <limits.h>
#include <sched.h>
#include <stdlib.h>
#include <string.h>
@@ -46,12 +49,16 @@
// #define A my_custom_cpu_error_trap()
// ^ calls my_custom_cpu_error_trap()
-#define S (1 << 24)
+#define S (1 << 25)
#define J while
#define H !--c
#ifndef PU2_SPEED_IMPROVEMENT
+ #ifdef PU2_TIME_SLICE_SUPPORT
+ #error Time slices are not supported in the basic, codegolfed versions. Please remove this flag before compilation.
+ #endif
+
#ifndef PU2_EXTENDED_INSTRUCTION_SET
// clang-format off
@@ -77,15 +84,6 @@
exit(1); \
})
-// pu2 optimized for speed implements a few new instructions for speed,
-// and has a "bake" mode which will preprocess the memory and perform the required modifications.
-//
-// 14: nop
-// 15: m[imm] = m[a]
-// 16: a = m[imm]
-// 17: m[a] = imm
-// 18: m[a] = m[imm]
-
// not implemented yet, was lazy
// bake(int start, int end) {}
@@ -97,8 +95,7 @@
#define likely(JJ) (JJ)
#endif
-__attribute__((aligned(64))) int *m;
-int a, b, u, c;
+// __attribute__((aligned(64))) int *m;
typedef struct {
int c;
int v;
@@ -117,8 +114,9 @@ void set_affinity(int cpu) {
}
#endif
-void init_pu2() {
+int *init_pu2() {
// set_affinity(0);
+ int *m;
#ifndef PU2_NO_MMAP
const int S_val = S * sizeof(int);
@@ -135,15 +133,14 @@ void init_pu2() {
if (m == MAP_FAILED) {
perror("[warn] couldn't allocate pu2 memory");
printf(
- " ( hint: enable hugepages in your kernel settings\n `echo %i | "
- "sudo "
- "tee /proc/sys/vm/nr_hugepages` )",
+ " ( hint: enable hugepages in your kernel settings\n"
+ " `echo %i | sudo tee /proc/sys/vm/nr_hugepages` )",
page_count);
exit(1);
}
#else
- m = malloc(S * sizeof(int));
- if(m == NULL) {
+ m = calloc(S, sizeof(int));
+ if (m == NULL) {
perror("[error] failed to allocate pu2 memory");
exit(1);
}
@@ -151,15 +148,34 @@ void init_pu2() {
// size_t i;
// for (i = 0; i < page_count; i++) ((char *) m)[ i * hugepage_size ] = 0;
+
+ return m;
}
#define asm(...) __asm__(__VA_ARGS__)
-void __attribute__((hot, aligned(64))) pu2() {
- vminst *M2 = (vminst *) m;
- vminst *M = &M2[ m[ 7 ] >> 1 ];
+__attribute__((hot, aligned(64)))
+
+ #ifdef PU2_TIME_SLICE_SUPPORT
+pu2(int __time_slice, int *m, int mem_size)
+ #else
+pu2(int *m, int mem_size)
+ #endif
+{
+ #ifdef PU2_TIME_SLICE_SUPPORT
+TIME_SLICE_AGAIN:;
+ int time_slice = __time_slice != -1 ?: INT_MAX;
+ #endif
+
+ int a = 0, b = 0, c = 0, u = 0;
- static int s1, s2, s3;
+ vminst *M2 = (vminst *) m;
+ vminst *M = &M2[ m[ 7 ] >> 1 ];
+ vminst *M_END = M2 + mem_size;
+
+ m[ 8 ] = mem_size;
+
+ int s1 = 0, s2 = 0, s3 = 0;
static const __attribute__((aligned(64))) void *PRECOMPUTED_TABLE[]
= { &&PU2_END, &&C_ONE, &&C_TWO, &&C_THREE, &&C_FOUR,
@@ -168,9 +184,18 @@ void __attribute__((hot, aligned(64))) pu2() {
&&CB_FIFTEEN, &&CB_SIXTEEN, &&CB_SEVENTEEN, &&CB_EIGHTEEN, [32] = 0 };
static vminst inst __asm__("r21");
- while (1) {
+ #ifdef PU2_TIME_SLICE_SUPPORT
+ static int slice_i;
+ for (slice_i = 0; slice_i < time_slice; slice_i++)
+ #else
+ while (1)
+ #endif
+
+ {
PU2_START:
+ if (unlikely(M2 >= M_END)) return 0;
inst = *M++;
+ // printf("running [%li] [%i] [%i]\n", M - M2, inst.c, inst.v);
// if (unlikely(inst.c > 18)) A;
#ifndef PU2_NO_INTRINSICS
__builtin_prefetch(M + 1, 0, 3);
@@ -246,9 +271,8 @@ void __attribute__((hot, aligned(64))) pu2() {
goto PU2_START;
CB_FIFTEEN:
// if (unlikely(inst.v == 7)) M = M2 + (m[a] >> 1);
- // if (unlikely(inst.v == a)) goto PU2_START;
- m[ inst.v ] = m[ a ];
- // asm("mov %1, %0" : "=r"(m[inst.v]) : "r"(m[a]));
+ m[ inst.v ] = a;
+ // asm("mov %1, %0" : "=r"(m[inst.v]) : "r"(a));
goto PU2_START;
CB_SIXTEEN:
// asm("mov %1, %0" : "=r"(a) : "r"(m[inst.v]));
@@ -267,8 +291,17 @@ void __attribute__((hot, aligned(64))) pu2() {
goto PU2_START;
}
+ #ifdef PU2_TIME_SLICE_SUPPORT
+ // this is when time slice ends
+ if (__time_slice == -1) goto TIME_SLICE_AGAIN;
+ #endif
+
PU2_END:
+ // normal halt
m[ 7 ] = (M - M2) << 1;
+
+ // return remaining time
+ return __time_slice - slice_i;
}
#endif
@@ -289,6 +322,13 @@ PU2_END:
// 11 U2A: a = u
// 12 B2U: u = b
// 13 U2B: b = u
+// pu2 optimized for speed implements a few new instructions for speed,
+// and has a "bake" mode which will preprocess the memory and perform the required modifications.
+// 14 NOP: pc += imm
+// 15 CB1: m[imm] = a
+// 16 CB2: a = m[imm]
+// 17 CB3: m[a] = imm
+// 18 CB4: m[a] = m[imm]
// NOTE: Memory indexes less than 1024 should be considered as temporary/compute memory, and
// programs should be written at index 1024 and upwards.
@@ -305,7 +345,7 @@ PU2_END:
// therefore, i recommend you store a copy somewhere!
// clang-format off
-char*C="hltimmlodstrswpaddsubandnotacca2uu2ab2uu2bnopcb1cb2cb3",*Y[1<<10],*E,*L,i;*K;as2(char*I){J(c=*I++){if(c==35){J(*++I-10);c=*I++;}L=C;(!isspace(c)?c-39?c-125?c-123?c-64?({i=0,I--;J(i++,*L)strncmp(L,I,3)?L+=3:({I+=3;*K++=i-1;*K++=(i-2&&i-9)?0:strtol(I,&I,10);goto Q;});E=I;return 1;Q:;}):as2(Y[strtol(I,&I,10)]):({Y[strtol(I,&I,10)]=I+1;J(*I++-125);}):({break;}):({*K++=1;*K++=*I++;}):0);}}
+char*C="hltimmlodstrswpaddsubandnotacca2uu2ab2uu2bnopcb1cb2cb3",*Y[1<<10],*E,*L;c,i;*K;as2(char*I){J(c=*I++){if(c==35){J(*++I-10);c=*I++;}L=C;(!isspace(c)?c-39?c-125?c-123?c-64?({i=0,I--;J(i++,*L)strncmp(L,I,3)?L+=3:({I+=3;*K++=i-1;*K++=(i-2&&i-9)?0:strtol(I,&I,10);goto Q;});E=I;return 1;Q:;}):as2(Y[strtol(I,&I,10)]):({Y[strtol(I,&I,10)]=I+1;J(*I++-125);}):({break;}):({*K++=1;*K++=*I++;}):0);}}
// clang-format on
// #undef S