diff options
Diffstat (limited to 'pu2')
| -rw-r--r-- | pu2/Makefile | 3 | ||||
| -rw-r--r-- | pu2/code.i2 | 35 | ||||
| -rw-r--r-- | pu2/code/kernel.i2 | 46 | ||||
| -rw-r--r-- | pu2/code/lib.i2 | 37 | ||||
| -rw-r--r-- | pu2/code/main.i2 | 30 | ||||
| -rw-r--r-- | pu2/i2-syntax/syntaxes/i2.tmLanguage.json | 26 | ||||
| -rw-r--r-- | pu2/pu2.c | 407 | ||||
| -rw-r--r-- | pu2/pu2.out.c | 94 |
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*\\(", @@ -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 |
