diff options
| author | 2025-08-28 17:40:20 +0330 | |
|---|---|---|
| committer | 2025-08-28 17:40:20 +0330 | |
| commit | 05491e6fb4b2d56841ad8fe2ab1b7371592ebe74 (patch) | |
| tree | 1c8e1d4221444238ddc7a24443173e52beb7a462 | |
| parent | pu3 poc5 (diff) | |
| -rw-r--r-- | README.md | 46 | ||||
| -rw-r--r-- | pu2/code/kernel.i2 | 1 | ||||
| -rw-r--r-- | pu2/pu2.c | 905 | ||||
| -rw-r--r-- | pu3/pu3.cpu.c | 143 |
4 files changed, 530 insertions, 565 deletions
@@ -1,18 +1,42 @@ -# pu2 ~~+ ppu!~~ -smaller, better, faster, compact-er! let's gooooo +# pu3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 +THIS IS PU3.<br> +well, it's in beta...<br> +but still, IT'S PU3 WOOOHOOO1?!?!!?!?!? -## pu2 +## what +cpu -### how does this workkk -to be humble, pretty clever stuff. (i forgor) +## what's it do +run bytecode fast -### WHAT IS PU2 -- CPU Emulator -- Assembler -- Test Suite +## why +pu2 was faster but needed more instructions. pu3 slashes inst count usage by about 3x -### instruction set -pu2 has less instructions than pu (aka pu1), [moon's note: wow it seems like i forgor to complete this sentence...] +## ir2? +ir2 stays. maybe i'll rebrand it to ir3, but for now it's ir2. on the beta branch (here) it supports targetting pu3! the tests work, but surely i missed some logic bugs still hidden inside. + +## GUIDE??? +pu3/pu3.cpu.c + +## I NEED MONEY +me too :< + +in my insatiable greed era + +~~# pu2 + ppu!~~ +~~smaller, better, faster, compact-er! let's gooooo~~ +~~## pu2~~ + +~~### how does this workkk~~ +~~to be humble, pretty clever stuff. (i forgor)~~ + +~~### WHAT IS PU2~~ +~~- CPU Emulator~~ +~~- Assembler~~ +~~- Test Suite~~ + +~~### instruction set~~ +~~pu2 has less instructions than pu (aka pu1), [moon's note: wow it seems like i forgor to complete this sentence...]~~ ~~## ppu~~ diff --git a/pu2/code/kernel.i2 b/pu2/code/kernel.i2 index 2da075c..ffdda7f 100644 --- a/pu2/code/kernel.i2 +++ b/pu2/code/kernel.i2 @@ -28,6 +28,7 @@ macro read_pmem(4) { } /* write the actual program */ +// NOTE: we switched to pu3. this is wrong :P @1007 = 10; @1010 = 1; @1011 = 3; // a = 3; @1012 = 17; @1013 = 9; // m[3] = 9; @@ -1,8 +1,11 @@ #define _POSIX_C_SOURCE 200809L -#include "pu2.out.c" // -#include <errno.h> +#include "../pu3/pu3.cpu.c" +// +#include <ctype.h> #include <libgen.h> +#include <limits.h> +#include <sched.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -10,16 +13,18 @@ #include <time.h> #include <unistd.h> -typedef char *string; -typedef unsigned char byte; -typedef byte bool; +#pragma clang diagnostic ignored "-Wparentheses" +#pragma clang diagnostic ignored "-Wreturn-type" +#pragma clang diagnostic ignored "-Wempty-body" +#pragma clang diagnostic error "-Wimplicit-function-declaration" + const bool true = 1; const bool false = 0; -string read_file(string path, int *out_size) { - FILE *f = fopen(path, "rb"); - string buf; - int size; +string read_file(string path, uint32_t *out_size) { + FILE *f = fopen(path, "rb"); + string buf; + uint32_t size; if (!f) return NULL; fseek(f, 0, SEEK_END); size = ftell(f); @@ -55,8 +60,8 @@ string canonicalize(string input) { return NULL; } - int absolute = (buf[ 0 ] == '/'); - char *saveptr; + uint32_t absolute = (buf[ 0 ] == '/'); + char *saveptr; for (tok = strtok_r(buf, "/", &saveptr); tok; tok = strtok_r(NULL, "/", &saveptr)) { if (!strcmp(tok, ".")) continue; else if (!strcmp(tok, "..")) { @@ -103,11 +108,11 @@ string canonicalize(string input) { return out; } -error_debug(string fail_point, string code, int sz) { - int error_pos = (int) (fail_point - code); - int i; +error_debug(string fail_point, string code, uint32_t sz) { + uint32_t error_pos = (uint32_t) (fail_point - code); + uint32_t i; - int line = 1, col = 1; + uint32_t line = 1, col = 1; for (i = 0; i < error_pos && i < sz; i++) { if (code[ i ] == '\n') { line++; @@ -117,14 +122,14 @@ error_debug(string fail_point, string code, int sz) { } } - int line_start = error_pos; + uint32_t line_start = error_pos; while (line_start > 0 && code[ line_start - 1 ] != '\n') { line_start--; } - int line_end = error_pos; + uint32_t line_end = error_pos; while (line_end < sz && code[ line_end ] != '\n' && code[ line_end ] != '\0') { line_end++; } - int tmp = line; - int lineno_width = 1; + uint32_t tmp = line; + uint32_t lineno_width = 1; while (tmp >= 10) { lineno_width++; tmp /= 10; @@ -165,10 +170,10 @@ long powi(long x, unsigned n) { } typedef struct { - int pid; - int ring_level; - int *memory; - int mem_size; + uint32_t pid; + uint32_t ring_level; + + pu3_ctx context; struct { bool spawn_process : 1; @@ -181,16 +186,19 @@ 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) { + bool time_finished; + uint32_t e_code; +} emu(uint32_t time_slice, uint32_t pid) { process_occupied[ pid ] = true; emu_process process = processes[ pid ]; - int *m = process.memory; + uint32_t *m = process.context.memory.memory_u32; while (1) { - int remaining_time = pu2(time_slice, m, process.mem_size); - int e_code = m[ 0 ]; + process.context.time_slice = time_slice; + uint32_t remaining_time = pu3(process.context); + uint32_t e_code = m[ 0 ]; + + // printf("exit code: %i\n", e_code); if (remaining_time <= 0 && time_slice != -1) { // process_occupied[ pid ] = false; @@ -202,12 +210,12 @@ struct emu_return { } // handle hardware interrupts - int int_code = m[ 1 ]; + uint32_t int_code = m[ 1 ]; // 0: output string if (int_code == 0) { - int ptr = m[ 2 ]; - int size = m[ 3 ], i = 0; + uint32_t ptr = m[ 2 ]; + uint32_t size = m[ 3 ], i = 0; while (size--) putchar(m[ ptr++ ]); } @@ -219,9 +227,9 @@ struct emu_return { // 2: arithmetics unit else if (int_code == 2) { - int op = m[ 2 ]; - int val1 = m[ 3 ]; - int val2 = m[ 4 ]; + uint32_t op = m[ 2 ]; + uint32_t val1 = m[ 3 ]; + uint32_t val2 = m[ 4 ]; m[ 2 ] = 0; @@ -254,16 +262,16 @@ struct emu_return { // permission features else if (int_code == 3) { - int op = m[ 2 ]; + uint32_t 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 ]; + uint32_t target_ring = m[ 10 ]; + uint32_t memory_start = m[ 11 ]; + uint32_t memory_length = m[ 12 ]; + uint32_t can_spawn_processes = m[ 13 ]; + uint32_t can_make_syscalls = m[ 14 ]; + uint32_t max_time_limit = m[ 15 ]; if (target_ring < process.ring_level) { // error - process cannot spawn a process on a lower ring level @@ -278,7 +286,7 @@ struct emu_return { goto HAD_ERROR; } - int new_pid = 0; + uint32_t new_pid = 0; for (new_pid = 0; new_pid < pid_count; new_pid++) { if (!process_occupied[ new_pid ]) goto FOUND; @@ -289,20 +297,19 @@ struct emu_return { goto HAD_ERROR; FOUND:; - - int *new_process_memory = calloc(memory_length, sizeof(int)); + pu3_ctx *__ctx = init_pu3(); 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, + .context = *__ctx, .permissions = { .make_syscall = !!can_make_syscalls, .spawn_process = !!can_spawn_processes } }; // copy memory - memcpy(new_process_memory, m + memory_start, memory_length * sizeof(int)); + memcpy( + __ctx->memory.memory_u32, m + memory_start, memory_length * sizeof(uint32_t)); // run process struct emu_return result = emu(max_time_limit, new_pid); @@ -314,8 +321,8 @@ struct emu_return { 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 ]; + uint32_t process_pid = m[ 10 ]; + uint32_t max_time_limit = m[ 11 ]; if (!process_occupied[ process_pid ]) { // error - process is not running, start/initialize it first @@ -338,10 +345,10 @@ struct emu_return { 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 ]; + uint32_t process_pid = m[ 10 ]; + uint32_t memory_address = m[ 11 ]; + uint32_t read_length = m[ 12 ]; + uint32_t target_location = m[ 13 ]; if (processes[ process_pid ].ring_level < processes[ pid ].ring_level || processes[ pid ].ring_level > 3) { @@ -351,17 +358,18 @@ struct emu_return { } // copy information - int *memory = processes[ process_pid ].memory; - memcpy(m + target_location, memory + memory_address, read_length * sizeof(int)); + uint32_t *memory = processes[ process_pid ].context.memory.memory_u32; + memcpy( + m + target_location, memory + memory_address, read_length * sizeof(uint32_t)); // 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 ]; + uint32_t process_pid = m[ 10 ]; + uint32_t memory_address = m[ 11 ]; + uint32_t write_length = m[ 12 ]; + uint32_t target_location = m[ 13 ]; if (processes[ process_pid ].ring_level < processes[ pid ].ring_level || processes[ pid ].ring_level > 3) { @@ -371,8 +379,9 @@ struct emu_return { } // write information - int *memory = processes[ process_pid ].memory; - memcpy(memory + memory_address, m + target_location, write_length * sizeof(int)); + uint32_t *memory = processes[ process_pid ].context.memory.memory_u32; + memcpy( + memory + memory_address, m + target_location, write_length * sizeof(uint32_t)); // done! m[ 2 ] = 0; @@ -400,18 +409,11 @@ skip_space(string *I) { } // IR parser for pu2's as2 -// clang-format off -struct { - int hlt, imm, lod, str, swp, add, sub, and, not, acc, a2u, u2a, b2u, u2b, nop, cb1, cb2, cb3, cb4; -} opcode = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 -}; -// clang-format on // use this instead of strdup'ing and allocating extra storage! typedef struct { - int len; - string ref; + uint32_t len; + string ref; } slice_t; typedef struct { @@ -420,8 +422,8 @@ typedef struct { } entry_t; typedef struct { - slice_t name; - int location; + slice_t name; + uint32_t location; } label_t; typedef struct { @@ -430,9 +432,9 @@ typedef struct { } macro_t; typedef struct { - slice_t name; - int *replace_location; // where to put the resolved address - string init_I; + slice_t name; + pu3_inst_t *replace_location; // where to put the resolved address + string init_I; } label_delegated_t; clean_slice_ref(slice_t *val) { free(val->ref); } @@ -465,7 +467,7 @@ clean_slice_ref(slice_t *val) { free(val->ref); } #define readd() ((used == new.len) ? (new.ref = realloc(new.ref, new.len *= 2)) : 0) #define scanvalue() \ ({ /* value scanner! numbers, characters, strings, variable derefs. */ \ - int value; \ + uint32_t value; \ if (isdigit(*I)) { \ value = strtol(I, &I, 10); \ } else if (*I == '\'') { \ @@ -473,9 +475,9 @@ clean_slice_ref(slice_t *val) { free(val->ref); } value = *I++; \ checkskip('\'', "couldn't find closing quote on character"); \ } else if (*I == '"') { \ - string str_start = ++I; \ - bool T = false; \ - int str_len = 0; \ + string str_start = ++I; \ + bool T = false; \ + uint32_t str_len = 0; \ while (*I != '"' || T) { \ if (*I == '\\') { \ T = !T; \ @@ -486,11 +488,11 @@ clean_slice_ref(slice_t *val) { free(val->ref); } } \ I++; \ str_len++; \ - int *dest_start = pointers.data -= str_len + 1; \ - int y; \ + uint32_t *dest_start = pointers.data -= str_len + 1; \ + uint32_t y; \ for (y = 0; y < str_len - 1; y++) { dest_start[ y ] = str_start[ y ]; } \ pointers.data[ -1 ] = 0; \ - value = pointers.data - storage.assembly_target; \ + value = pointers.data - (uint32_t *) storage.assembly_target; \ } else if (*I == '&') { \ I++; \ string starting_I = I; \ @@ -503,7 +505,7 @@ clean_slice_ref(slice_t *val) { free(val->ref); } }) #define scanvar() \ ({ /* memory scanner! finds @10, var_name */ \ - int value; \ + uint32_t value; \ if (*I == '@') { \ if (!isdigit(*++I)) run_err(I - 1, "expected memory index"); \ value = strtol(I, &I, 10); \ @@ -518,87 +520,36 @@ clean_slice_ref(slice_t *val) { free(val->ref); } #define varqual(F) ((F) == '@' || isalpha(F) || (F) == '_') #define litqual(F) (isdigit(F) || (F) == '\'' || (F) == '"' || (F) == '&') -#define p_cat(a, b) a##b -#define cat(a, b) p_cat(a, b) - -#define not_subpart_1(__a) -#define not_subpart_(__a) __a -#define not(val, ...) cat(not_subpart_, __VA_OPT__(1))(val) -#define op(mode, ...) emit(opcode.mode, not(0, __VA_ARGS__) __VA_ARGS__) - -#define store() (op(acc, 1), op(str)) -#define swap() op(swp) -#define imm(value) op(imm, value) -#define load() op(lod) -#define imm_in_mem(__mem, __imm) (imm(__mem), op(cb3, __imm)) -#define mov_mem_mem(__mem1, __mem2) (imm(__mem1), op(cb4, __mem2)) -#define mem_in_a(__mem) op(cb2, __mem) -#define a_in_mem(__mem) op(cb1, __mem) -#define deref_a() (op(b2u), swap(), load(), op(u2b)) - -wowie() { op(acc); } - -#define check_stack() (0) -#define perf_sp(__op) \ - (mem_in_a(storage.stack_pointer), \ - op(acc, 1), \ - op(u2b), \ - op(__op), \ - a_in_mem(storage.stack_pointer)) -#define inc_sp() perf_sp(add) -#define dec_sp() perf_sp(sub) - -#define push_imm(__imm) (mem_in_a(storage.stack_pointer), op(cb3, __imm), dec_sp()) -#define push_mem(__mem) (mem_in_a(storage.stack_pointer), op(cb4, __mem), dec_sp()) -#define pop_stack_a() (inc_sp(), mem_in_a(storage.stack_pointer), deref_a()) -// #define pop_stack_mem(__mem) - -#define perform_op(operation) \ - ({ \ - mem_in_a(mem2_index); \ - swap(); \ - mem_in_a(mem_index); \ - op(operation); \ - swap(); \ - imm(mem_index); \ - store(); \ - }) - string ERR; string ERR_code; struct ir2_pointers { - int *code; - int *data; - int *stack; - int stack_pointer; + pu3_inst_t *code; + uint32_t *data; + pu3_inst_t *stack; + uint32_t stack_pointer; } pointers; -init_ir2(int *target_mem, int max_size) { - static const int starting_code = 5000; +uint32_t init_ir2(pu3_inst_t *target_mem, pu3_inst_t max_size) { + static const pu3_inst_t starting_code = 5000; - pointers.stack = &target_mem[ 4998 ]; // stack is downward growing - pointers.stack_pointer = 4999; // stack pointer - pointers.code = &target_mem[ starting_code ]; // code pointer - pointers.data = &target_mem[ max_size - 1 ]; // data grows downwards + pointers.stack = &target_mem[ 4998 ]; // stack is downward growing + pointers.stack_pointer = 4999; // stack pointer + pointers.code = &target_mem[ starting_code ]; // code pointer + pointers.data = (uint32_t *) &target_mem[ max_size - 1 ]; // data grows downwards return starting_code; } -__attribute__((always_inline)) emit(int op, int val) { - *pointers.code++ = op; - *pointers.code++ = val; -} - -int ir2_depth = 0; +uint32_t ir2_depth = 0; #define space skip_space(&I) -bool has_jump_warned = false; +// bool has_jump_warned = false; bool has_useless_if_warned = false; bool has_false_while_warned = false; __ir2_get_var_loc(slice_t name, label_t variables[ 1 << 11 ], string error_I, string init_I) { - int j; + uint32_t j; for (j = 0; j < 1 << 11; j++) { label_t cur = variables[ j ]; if (cur.name.ref == NULL) break; @@ -610,13 +561,45 @@ __ir2_get_var_loc(slice_t name, label_t variables[ 1 << 11 ], string error_I, st } typedef struct { - int *assembly_target; + pu3_inst_t *assembly_target; macro_t *macros; label_t *labels; label_delegated_t *forward_refs; label_t *variables; } ir2_storage; +// #define IR2_INIT_COMPILE_TIME + +const int SPARES_LOC = 1005; + +#define write(inst) (*pointers.code++ = inst) +#define get(__opcode, lhs, rhs) build_inst(false, false, opcode.__opcode, lhs, rhs) +#define getde(__opcode, lhs, rhs) build_inst(false, true, opcode.__opcode, lhs, rhs) +#define getrev(__opcode, lhs, rhs) build_inst(true, false, opcode.__opcode, lhs, rhs) +#define getderev(__opcode, lhs, rhs) build_inst(true, true, opcode.__opcode, lhs, rhs) + +inline void mov_mem_mem(uint32_t indexL, uint32_t indexR) { + if (indexR > UINT16_MAX) { + // some trickery + write(getderev(mov, indexR, SPARES_LOC)); // *spare = *indexR + write(getde(mov, indexL, SPARES_LOC)); // *indexL = *spare + } else { + write(getde(mov, indexL, indexR)); // *indexL = *indexR + } +} + +inline void halt() { write(get(hlt, 0, 0)); } +inline void set_imm(uint32_t value) { write(getrev(mov, value, 0)); } +inline void imm_in_mem(uint32_t addr, uint32_t value) { + if (value > UINT16_MAX) { + // more trickery + write(getrev(mov, value, SPARES_LOC)); // *spare = value + write(getde(mov, addr, SPARES_LOC)); // *addr = *spare + } else { + write(get(mov, addr, value)); // *addr = value + } +} + string _ir2(string I, string filepath, ir2_storage storage) { char T; string init_I = I; @@ -665,8 +648,8 @@ string _ir2(string I, string filepath, ir2_storage storage) { slice_t name = scanword(); space; - int *m_index = --pointers.data; - int start_index = m_index - storage.assembly_target; + uint32_t *m_index = --pointers.data; + uint32_t start_index = m_index - (uint32_t *) storage.assembly_target; if (*I == ':') { I++; @@ -683,8 +666,8 @@ string _ir2(string I, string filepath, ir2_storage storage) { space; } -// comment out this flag to initialize values at runtime instead of compile-time -#define IR2_INIT_COMPILE_TIME + // comment out this flag to initialize values at runtime instead of compile-time + // #define IR2_INIT_COMPILE_TIME if (*I == ';') { // no starter value, just initialize it to zero @@ -705,7 +688,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { imm_in_mem(start_index, scanvalue()); #endif } else if (varqual(*I)) { // memory address - int mem_index = scanvar(); + uint32_t mem_index = scanvar(); mov_mem_mem(start_index, mem_index); } else { run_err(I, "expected compile-time constant, variable or memory index"); @@ -715,7 +698,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { checkskip(';', "expected semicolon after variable value"); } - int j; + uint32_t j; for (j = 0; j < 1 << 11; j++) { label_t cur = storage.variables[ j ]; @@ -760,8 +743,8 @@ string _ir2(string I, string filepath, ir2_storage storage) { free(dir); } - int out_size; - string text = read_file(full, &out_size); + uint32_t out_size; + string text = read_file(full, &out_size); if (text == NULL) { printf("failed to import \"%s\"\n", full); perror("unable to use import"); @@ -795,8 +778,8 @@ string _ir2(string I, string filepath, ir2_storage storage) { space; - string before = I; - int arg_count = strtol(I, &I, 10); + string before = I; + uint32_t arg_count = strtol(I, &I, 10); if (I == before) { run_err(I, "expected number (argument count) in macro definition parens"); } @@ -813,7 +796,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { checkskip('{', "expected open curly bracket in macro body"); // find open space in macros - int x; + uint32_t x; for (x = 0; x < (1 << 9); x++) { macro_t g = storage.macros[ x ]; if (g.data.key.ref == NULL) goto DONE; @@ -834,7 +817,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { g->data.value.len = 0; g->arg_count = arg_count; - int dep = 0; + uint32_t dep = 0; while (dep != 0 || *I != '}') { if (*I == '{') dep++; if (*I == '}') dep--; @@ -851,12 +834,15 @@ string _ir2(string I, string filepath, ir2_storage storage) { } // emit exit calls + // wow, this was ooold code. had to patch quite a few things here. if (strncmp("exit", I, 4) == 0 && !varqual(I[ 4 ])) { I += 4; + space; checkskip('(', "expected open paren on exit blob"); - string old = I; - int value = strtol(I, &I, 10); + string old = I; + uint32_t value = strtol(I, &I, 10); + space; if (old == I && *I != ')') { run_err(I - 1, "invalid input to exit blob, expected number"); } @@ -867,8 +853,8 @@ string _ir2(string I, string filepath, ir2_storage storage) { checkskip(';', "expected semicolon after call"); // actually emit stuff - if (old != I) imm(value); - op(hlt); + if (old != I) set_imm(value); + halt(); continue; } @@ -886,7 +872,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { checkskip(';', "expected semicolon after system blob"); imm_in_mem(0, 2); - op(hlt); + halt(); continue; } @@ -915,7 +901,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { while (lbdb->name.ref != NULL) { label_t cur = *lbdb++; if (cur.name.len == label.len && strncmp(cur.name.ref, label.ref, label.len) == 0) { - imm_in_mem(7, cur.location); + write(get(jmp, cur.location, 0)); goto FINISH_JMP; } } @@ -924,7 +910,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { // find delegations slot label_delegated_t *del; - int j; + uint32_t j; for (j = 0; j < 1 << 10; j++) { if (storage.forward_refs[ j ].name.ref == NULL) { // found one! @@ -940,7 +926,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { WRITE_DEL: - imm_in_mem(7, 0xDEAD10C4); // DEADLOCK - placeholder for the resolver + write(get(jmp, 0xDEAD10C4, 0)); // DEADLOCK - placeholder for the resolver del->replace_location = pointers.code - 1; // place of imm in code del->name = label; del->init_I = init_I; @@ -958,7 +944,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { space; checkskip('(', "expected open paren on %s blob", name); space; - int target_mem = scanvar(); + uint32_t target_mem = scanvar(); space; checkskip( @@ -993,13 +979,9 @@ string _ir2(string I, string filepath, ir2_storage storage) { label_t cur = *lbdb++; if (cur.name.len == label.len && strncmp(cur.name.ref, label.ref, label.len) == 0) { // emit j(n)z - mem_in_a(target_mem); - if (!was_jnz) op(not); - op(a2u); - imm(cur.location); - swap(); - imm(7); - op(str); + write(getderev(mov, SPARES_LOC, target_mem)); // *spare = *mem; + if (!was_jnz) write(get(not, SPARES_LOC, 0)); // *spare = !*spare; + write(getde(jnz, cur.location, SPARES_LOC)); // jmp(cur.location) if *spare; goto FINISH_JNZ; } @@ -1009,7 +991,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { // find delegations slot label_delegated_t *del; - int j; + uint32_t j; for (j = 0; j < 1 << 10; j++) { if (storage.forward_refs[ j ].name.ref == NULL) { // found one! @@ -1026,14 +1008,11 @@ string _ir2(string I, string filepath, ir2_storage storage) { WRITE_DEL_JNZ: // emit j(n)z - mem_in_a(target_mem); - if (!was_jnz) op(not); - op(a2u); - imm(0xDEAD10C4); // DEADLOCK - placeholder for the resolver - del->replace_location = pointers.code - 1; // place of imm in code - swap(); - imm(7); - op(str); + write(getderev(mov, SPARES_LOC, target_mem)); // *spare = *mem; + if (!was_jnz) write(get(not, SPARES_LOC, 0)); // *spare = !*spare; + write(getde(jnz, 0xDEAD10C4, SPARES_LOC)); // jmp(0xDEAD10C4) if *spare; // DEADLOCK - + // placeholder for the resolver + del->replace_location = pointers.code - 1; // place of jump in code del->name = label; del->init_I = init_I; @@ -1058,7 +1037,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { } // redundant if statement: always true / always false - int value = strtol(I, &I, 10); + uint32_t value = strtol(I, &I, 10); space; checkskip(')', "expected closing paren after if statement argument"); space; @@ -1071,13 +1050,14 @@ string _ir2(string I, string filepath, ir2_storage storage) { struct ir2_pointers pointers_B = pointers; // completely eliminate code generated in useless if statement - int *m2 = calloc(S, sizeof(int)); - label_t *variables_G = calloc(1 << 5, sizeof(label_t)); - pointers.data = pointers.code = m2; + uint32_t *m2 = calloc(S, sizeof(uint32_t)); + label_t *variables_G = calloc(1 << 5, sizeof(label_t)); + pointers.data = m2; + pointers.code = (uint64_t *) m2; ir2_storage useless_storage = storage; useless_storage.variables = variables_G; - useless_storage.assembly_target = m2; + useless_storage.assembly_target = (uint64_t *) m2; // get new I location string new_I = _ir2(I, filepath, useless_storage); @@ -1104,27 +1084,26 @@ string _ir2(string I, string filepath, ir2_storage storage) { space; } - int mem_index = scanvar(); + uint32_t mem_index = scanvar(); space; checkskip(')', "expected closing paren after if statement argument"); space; checkskip('{', "expected opening bracket for if statement body"); space; - mem_in_a(mem_index); - if (!was_negated) op(not); - op(a2u); - imm(0xDEAD10C4); // DEADLOCK - placeholder for the patchback - int *patchback = pointers.code - 1; - swap(); - imm(7); - op(str); + write(getderev(mov, SPARES_LOC, mem_index)); // *spare = *mem; + if (!was_negated) write(get(not, SPARES_LOC, 0)); // *spare = !*spare; + write(getde(jnz, 0xDEAD10C4, SPARES_LOC)); // jmp(cur.location) if *spare; + pu3_inst_t *patchback = pointers.code - 1; // handle the code stuff string new_I = _ir2(I, filepath, storage); I = new_I; - *patchback = pointers.code - storage.assembly_target; // patch the jump instruction + *patchback = getde( + jnz, + pointers.code - storage.assembly_target, + SPARES_LOC); // patch the jump instruction continue; } @@ -1137,7 +1116,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { ir2_depth++; if (isdigit(*I)) { - int value = strtol(I, &I, 10); + uint32_t value = strtol(I, &I, 10); space; checkskip(')', "expected closing paren after while loop argument"); @@ -1158,12 +1137,13 @@ string _ir2(string I, string filepath, ir2_storage storage) { struct ir2_pointers pointers_B = pointers; // completely eliminate code generated in useless while loop - int *m2 = calloc(S, sizeof(int)); - label_t *variables_G = calloc(1 << 5, sizeof(label_t)); - pointers.data = pointers.code = m2; + uint32_t *m2 = calloc(S, sizeof(uint32_t)); + label_t *variables_G = calloc(1 << 5, sizeof(label_t)); + pointers.data = m2; + pointers.code = (uint64_t *) m2; ir2_storage useless_storage = storage; - useless_storage.assembly_target = m2; + useless_storage.assembly_target = (uint64_t *) m2; useless_storage.variables = variables_G; // get new I location @@ -1177,12 +1157,12 @@ string _ir2(string I, string filepath, ir2_storage storage) { } else { // run forever! - int start = pointers.code - storage.assembly_target; + uint32_t start = pointers.code - storage.assembly_target; string new_I = _ir2(I, filepath, storage); I = new_I; - imm_in_mem(7, start); // always jump back to the start + write(get(jmp, start, 0)); // always jump back to the start } continue; @@ -1195,38 +1175,33 @@ string _ir2(string I, string filepath, ir2_storage storage) { space; } - int mem_index = scanvar(); + uint32_t mem_index = scanvar(); space; checkskip(')', "expected closing paren after while loop condition"); space; checkskip('{', "expected opening bracket for while loop body"); space; - mem_in_a(mem_index); - if (!was_negated) op(not); - op(a2u); - imm(0xDEAD10C4); // DEADLOCK - placeholder for the patchback - int *patchback = pointers.code - 1; - swap(); - imm(7); - op(str); + write(getderev(mov, mem_index, SPARES_LOC)); + if (!was_negated) write(get(not, SPARES_LOC, 0)); + write(getde(jnz, 0xDEAD10C4, SPARES_LOC)); + uint64_t *patchback = pointers.code - 1; - int start_index = pointers.code - storage.assembly_target; + uint32_t start_index = pointers.code - storage.assembly_target; // handle the code stuff string new_I = _ir2(I, filepath, storage); I = new_I; - *patchback = pointers.code - storage.assembly_target; // patch the jump instruction - // check the condition and jump back if true - mem_in_a(mem_index); - if (was_negated) op(not); - op(a2u); - imm(start_index); - swap(); - imm(7); - op(str); + write(getderev(mov, mem_index, SPARES_LOC)); + if (was_negated) write(get(not, SPARES_LOC, 0)); + write(getde(jnz, start_index, SPARES_LOC)); + + *patchback = getde( + jnz, + pointers.code - storage.assembly_target, + SPARES_LOC); // patch the jump instruction continue; } @@ -1241,7 +1216,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { I++; // this is a label! label_t *slot; - int j; + uint32_t j; for (j = 0; j < 1 << 10; j++) { if (storage.labels[ j ].name.ref != NULL) { if (storage.labels[ j ].name.len == name.len @@ -1271,8 +1246,8 @@ string _ir2(string I, string filepath, ir2_storage storage) { checkskip('(', "expected open paren after alphanumeric word (assuming this is a blob)"); space; - slice_t arguments[ 1 << 7 ]; - int arg_count = 0; + slice_t arguments[ 1 << 7 ]; + uint32_t arg_count = 0; string fail_I = I; @@ -1283,7 +1258,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { arguments[ arg_count ].len = 0; arguments[ arg_count ].ref = I; - int dep = 0; + uint32_t dep = 0; while (dep != 0 || *I != ']') { if (*I == '[') dep++; if (*I == ']') dep--; @@ -1320,7 +1295,7 @@ string _ir2(string I, string filepath, ir2_storage storage) { // done reading blob! check it and parse macro :) // find index - int i; + uint32_t i; for (i = 0; i < (1 << 9); i++) { macro_t cur = storage.macros[ i ]; if (cur.data.key.len != name.len) continue; @@ -1337,12 +1312,12 @@ string _ir2(string I, string filepath, ir2_storage storage) { storage.macros[ i ].arg_count, arg_count); } - slice_t target = storage.macros[ i ].data.value; - string N = target.ref; - string oldN = N; - memslice_t new = { target.len, malloc(target.len) }; - int used = 0; - bool needs_scan = true; + slice_t target = storage.macros[ i ].data.value; + string N = target.ref; + string oldN = N; + memslice_t new = { target.len, malloc(target.len) }; + uint32_t used = 0; + bool needs_scan = true; while (needs_scan) { needs_scan = false; @@ -1352,8 +1327,8 @@ string _ir2(string I, string filepath, ir2_storage storage) { if (*N == '/' && isdigit(N[ 1 ])) { N++; - string old = N - 1; - int index = strtol(N, &N, 10); + string old = N - 1; + uint32_t index = strtol(N, &N, 10); if (index > arg_count) { N--; @@ -1404,23 +1379,27 @@ string _ir2(string I, string filepath, ir2_storage storage) { if (!varqual(*I)) run_err(I, "expected memory index or variable after dereference"); } - string starting_qual = I; - int mem_index = scanvar(); + string starting_qual = I; + uint32_t mem_index = scanvar(); space; if (*I == '-' && I[ 1 ] == '-') { // decrement I += 2; space; checkskip(';', "expected semicolon"); - mem_in_a(mem_index); - if (lhs_deref) deref_a(); - op(acc, 1); - op(u2b); - op(sub); - swap(); - if (lhs_deref) mem_in_a(mem_index); - else { imm(mem_index); } - store(); + + if (lhs_deref) { + // *spare = *mem; + // *spare = **spare; + // *spare--; + // *mem = *spare; + write(getderev(mov, mem_index, SPARES_LOC)); + write(get(dmv, SPARES_LOC, 0)); + write(get(dec, SPARES_LOC, 0)); + write(getde(mov, mem_index, SPARES_LOC)); + } else { + write(get(dec, mem_index, 0)); + } continue; } @@ -1429,15 +1408,19 @@ string _ir2(string I, string filepath, ir2_storage storage) { I += 2; space; checkskip(';', "expected semicolon"); - mem_in_a(mem_index); - if (lhs_deref) deref_a(); - op(acc, 1); - op(u2b); - op(add); - swap(); - if (lhs_deref) mem_in_a(mem_index); - else { imm(mem_index); } - store(); + + if (lhs_deref) { + // *spare = *mem; + // *spare = **spare; + // *spare++; + // *mem = *spare; + write(getderev(mov, mem_index, SPARES_LOC)); + write(get(dmv, SPARES_LOC, 0)); + write(get(inc, SPARES_LOC, 0)); + write(getde(mov, mem_index, SPARES_LOC)); + } else { + write(get(inc, mem_index, 0)); + } continue; } @@ -1448,11 +1431,11 @@ string _ir2(string I, string filepath, ir2_storage storage) { checkskip('=', "expected assigment after memory blob (hint: only +-&! are supported)"); space; - if (mem_index == 7 && !has_jump_warned) { - has_jump_warned = true; - printf("\nwarn: writing to memory index 7 is equivalent to a jump\n"); - printf(" if this behavior is intended, use the jump blob instead.\n\n"); - } + // if (mem_index == 7 && !has_jump_warned) { + // has_jump_warned = true; + // printf("\nwarn: writing to memory index 7 is equivalent to a jump\n"); + // printf(" if this behavior is intended, use the jump blob instead.\n\n"); + // } if (*I == '*' || varqual(*I)) { bool rhs_deref = *I == '*'; @@ -1464,75 +1447,89 @@ string _ir2(string I, string filepath, ir2_storage storage) { } if ((lhs_deref || rhs_deref) && extra_op != '=') { - run_err(expr_I, "dereferencing is not possible with arithmetic. (i was lazy)"); + run_err( + expr_I, "dereferencing is not possible with arithmetic. (moon is lazy)"); } - int mem2_index = scanvar(); + uint32_t mem2_index = scanvar(); space; if (extra_op == '=') { 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(); + // **a = *b; + // **a = **b; + write(getderev(mov, mem2_index, SPARES_LOC)); + if (rhs_deref) write(getde(dmv, SPARES_LOC, 0)); + write(getde(ddm, mem_index, SPARES_LOC)); } else { if (rhs_deref) { - // m[a] = m[m[b]] - mem_in_a(mem2_index); - deref_a(); - a_in_mem(mem_index); + // *a = **b + write(getderev(mov, mem2_index, SPARES_LOC)); + write(getde(dmv, SPARES_LOC, 0)); + write(getde(mov, mem_index, SPARES_LOC)); } else { - // m[a] = m[b] + // *a = *b mov_mem_mem(mem_index, mem2_index); } } } else if (extra_op == '+') { - perform_op(add); + if (mem2_index > UINT16_MAX) { + write(getderev(mov, mem2_index, SPARES_LOC)); + write(getde(add, mem_index, SPARES_LOC)); + } else { + write(getde(add, mem_index, mem2_index)); + } } else if (extra_op == '-') { - perform_op(sub); + if (mem2_index > UINT16_MAX) { + write(getderev(mov, mem2_index, SPARES_LOC)); + write(getde(sub, mem_index, SPARES_LOC)); + } else { + write(getde(sub, mem_index, mem2_index)); + } } else if (extra_op == '&') { - perform_op(and); + if (mem2_index > UINT16_MAX) { + write(getderev(mov, mem2_index, SPARES_LOC)); + write(getde(and, mem_index, SPARES_LOC)); + } else { + write(getde(and, mem_index, mem2_index)); + } } else if (extra_op == '!') { // @1 != @2; (@1 = !@2) - mem_in_a(mem2_index); - op(not); - swap(); - imm(mem_index); - store(); + if (mem2_index > UINT16_MAX) { + write(getderev(mov, mem2_index, SPARES_LOC)); + write(getde(mov, mem_index, SPARES_LOC)); + write(get(not, mem_index, 0)); + } else { + write(getde(mov, mem_index, mem2_index)); + write(get(not, mem_index, 0)); + } } } else { - int imm = scanvalue(); + uint32_t imm = scanvalue(); if (extra_op == '=') { imm_in_mem(mem_index, imm); } else if (extra_op == '+') { - imm(imm); - swap(); - mem_in_a(mem_index); - op(add); - swap(); - imm(mem_index); - store(); + if (imm > UINT16_MAX) { + write(getrev(mov, imm, SPARES_LOC)); + write(get(add, mem_index, SPARES_LOC)); + } else { + write(get(add, mem_index, imm)); + } } else if (extra_op == '-') { - imm(imm); - swap(); - mem_in_a(mem_index); - op(sub); - swap(); - imm(mem_index); - store(); + if (imm > UINT16_MAX) { + write(getrev(mov, imm, SPARES_LOC)); + write(get(sub, mem_index, SPARES_LOC)); + } else { + write(get(sub, mem_index, imm)); + } } else if (extra_op == '&') { - imm(imm); - swap(); - mem_in_a(mem_index); - op(and); - swap(); - imm(mem_index); - store(); + if (imm > UINT16_MAX) { + write(getrev(mov, imm, SPARES_LOC)); + write(get(and, mem_index, SPARES_LOC)); + } else { + write(get(and, mem_index, imm)); + } } else if (extra_op == '!') { // @1 != 5; (@1 = !5;) imm_in_mem(mem_index, !imm); @@ -1551,11 +1548,11 @@ string _ir2(string I, string filepath, ir2_storage storage) { return 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; - const int fwd_n = 1 << 10; +ir2(string I, string filepath, pu3_inst_t *assembly_target) { + const uint32_t macros_n = 1 << 9; + const uint32_t labels_n = 1 << 10; + const uint32_t vars_n = 1 << 11; + const uint32_t fwd_n = 1 << 10; macro_t *macros = calloc(macros_n, sizeof(*macros)); label_t *labels = calloc(labels_n, sizeof(*labels)); @@ -1577,13 +1574,13 @@ ir2(string I, string filepath, int *assembly_target) { label_delegated_t cur = *curf++; // find label - int j; + uint32_t j; for (j = 0; j < labels_n; j++) { label_t clab = labels[ j ]; if (clab.name.len == cur.name.len && strncmp(clab.name.ref, cur.name.ref, cur.name.len) == 0) { // found it! - *cur.replace_location = clab.location; + set_dest_u32(*cur.replace_location, clab.location); goto REP_DONE; } } @@ -1600,164 +1597,68 @@ ir2(string I, string filepath, int *assembly_target) { free(forward_refs); } -string op_names[] = { "hlt", "imm", "lod", "str", "swp", "add", "sub", "and", "not", "acc", - "a2u", "u2a", "b2u", "u2b", "nop", "cb1", "cb2", "cb3", "cb4" }; - -unsigned long long rdtsc(void) { -#ifndef PU2_NO_ASM - unsigned hi, lo; - __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); - return ((unsigned long long) hi << 32) | lo; -#else - return 0; -#endif -} - -#ifndef PU2_BAD_CLOCK -clock_t ntime() { - struct timespec t; - clock_gettime(CLOCK_MONOTONIC_RAW, &t); - - return t.tv_nsec + t.tv_sec * 1e9; -} -#else -clock_t ntime() { - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000000 + tv.tv_usec * 1000; -} -#endif - -// bench: measure using clock() -double bench_cycle(int instr, int *m, int mem_size) { - int i; - 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 ] = 16; - c = 0; - - clock_t start = ntime(); - int wstart = rdtsc(); - pu2(-1, m, mem_size); - int wend = rdtsc(); - clock_t end = ntime(); - - double nanoseconds = (end - start); - double inst_count = (double) m[ 7 ] / 2; - double insts_per_ns = inst_count / nanoseconds; - double insts_per_s = insts_per_ns * 1e9; - - printf( - "%-8s | time: %.3fms | insts: %.0f (%li real) | ips: %.3fM inst/s\n", - op_names[ instr ], - nanoseconds / 1000000, - inst_count, - end - start, - insts_per_ns * 1e3); - - return insts_per_s / 1e6; // return M inst/s -} - -// bench2: measure using rdtsc -double bench2_cycle(int instr, int *m, int mem_size) { - unsigned long long start, end; - double vminst_count, cpu_cycles; - int i; - 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 ] = 16; - c = 0; - start = rdtsc(); - pu2(-1, m, mem_size); - end = rdtsc(); - cpu_cycles = (double) (end - start); - vminst_count = (double) m[ 7 ] / 2; - double cycles_per_inst = cpu_cycles / vminst_count; - - printf( - "%-6s | cycles/inst: %8.3f | cycles: %14.0f | insts: %12.0f\n", - op_names[ instr ], - cycles_per_inst, - cpu_cycles, - vminst_count); - return cycles_per_inst; -} - -sleep_nano(int nanoseconds) { - struct timespec req = { 0 }; - req.tv_sec = nanoseconds / 1000000000L; // Whole seconds - req.tv_nsec = nanoseconds % 1000000000L; // Remaining nanoseconds - - // nanosleep might be interrupted, so loop until it completes - while (nanosleep(&req, &req) == -1 && errno == EINTR) { - continue; // Continue with remaining time if interrupted - } -} - -#ifdef PU2_OLD_CLANG - #define inline() __attribute__((always_inline)) -#else - #define inline() [[clang::always_inline]] -#endif +volatile long out; -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, int *, int), const char *mode_label, int *m, int mem_size) { - double results[ 19 ]; - double sum = 0; - int count = 0; - int i; - - printf("\n=== pu2 benchmark (%s) ===\n", mode_label); - printf("op | result details\n"); - printf("---------------------------------------------\n"); - - for (i = 1; i < 19; i++) { - // printf("running: %s\n", op_names[ i ]); - results[ i ] = target(i, m, mem_size); - sum += results[ i ]; - count++; +void disassemble_pu3_inst(pu3_inst_t inst) { + byte op = get_scroll_byte(inst); + if (op > 15) { + printf("\033[1;31minvalid op\033[0m\n"); + return; } - sum /= count; - - printf("---------------------------------------------\n"); - - int start = rdtsc(); - sleep_milli(100); - int end = rdtsc(); - - double clock_speed_mhz = ((end - start) / 1e6) * 10; - - if (strcmp(mode_label, "time") == 0) { - // printf("average : %.3f M inst/s\n", sum); - printf("cpu clock : ~%.3f MHz (measured via rdtsc & msleep(100))\n", clock_speed_mhz); - printf("vm clock (i/s) : %.3fMHz (ipn, higher is better)\n", sum); - // printf("estimated : %.3f cycles per instruction (cpi, lower is better)\n", - // clock_speed_mhz / sum); - } else { - // mode_label == "rdtsc" - printf("average cycles/inst : %.3f cycles\n", sum); - // printf("cpu clock : ~%.3f MHz (measured via rdtsc & msleep(100))\n", - // clock_speed_mhz); - printf("estimated ipc : %.3f (1 / cycles_per_inst, higher is better)\n", 1.0 / sum); - // printf("estimated cpi : %.3f (cycles_per_inst, lower is better)\n", sum); + byte spare = get_spare(inst); + bool swap = (spare & 0x80); + bool deref = (spare & 0x40); + uint32_t dest = get_dest_u32(inst); + uint16_t data = get_data_u16(inst); + uint32_t lhs = swap ? data : (uint32_t) dest; + uint32_t rhs = swap ? (uint32_t) dest : data; + + const char *name = op_names[ op ]; + printf("\033[1;32m%-3s\033[0m ", name); + + switch (op) { + case 0: // nop + if (deref) printf("\033[1;33m[\033[0m"); + printf("\033[1;34m%i\033[0m", data); + if (deref) printf("\033[1;33m]\033[0m"); + break; + case 1: // hlt + break; + case 5: + case 6: + case 11: // inc, dec, not + printf("\033[1;33m[\033[0m\033[1;34m%i\033[0m\033[1;33m]\033[0m", dest); + break; + case 12: // jmp + printf("\033[1;34m%i\033[0m", dest); + break; + case 14: // dmv + printf("\033[1;33m[\033[0m\033[1;34m%i\033[0m\033[1;33m]\033[0m", lhs); + break; + case 13: // jnz + printf("\033[1;34m%i\033[0m, ", lhs); + if (deref) printf("\033[1;33m[\033[0m"); + printf("\033[1;34m%i\033[0m", rhs); + if (deref) printf("\033[1;33m]\033[0m"); + break; + case 15: // ddm + printf("\033[1;33m[[\033[0m\033[1;34m%i\033[0m\033[1;33m]]\033[0m, ", lhs); + printf("\033[1;33m[\033[0m"); + if (deref) printf("\033[1;33m[\033[0m"); + printf("\033[1;34m%i\033[0m", rhs); + if (deref) printf("\033[1;33m]\033[0m"); + printf("\033[1;33m]\033[0m"); + break; + default: // mov, add, sub, mul, lsh, rsh, and + printf("\033[1;33m[\033[0m\033[1;34m%i\033[0m\033[1;33m]\033[0m, ", lhs); + if (deref) printf("\033[1;33m[\033[0m"); + printf("\033[1;34m%i\033[0m", rhs); + if (deref) printf("\033[1;33m]\033[0m"); + break; } - printf("=== end benchmark ===\n\n"); + printf("\n"); } -volatile long out; - main(int argc, char **argv) { if (argc == 1) { printf( @@ -1769,70 +1670,50 @@ main(int argc, char **argv) { return 1; } - int *assembly_target = calloc(S, sizeof(int)); + pu3_ctx *__ctx = init_pu3(); + pu3_ctx ctx = *__ctx; if (strcmp(argv[ 1 ], "benchmark") == 0) { - 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; - unsigned aux; - unsigned long long t0 = rdtsc(); - int C; - for (C = 0; C < N; ++C) { - sum += 1; - __asm__ volatile(""); - } - unsigned long long t1 = rdtsc(); - out = sum; // single volatile write to make sum observable - printf( - "(absolute max) N=%llu cycles=%llu cycles/iter=%.6f\n", - (unsigned long long) N, - (unsigned long long) (t1 - t0), - (t1 - t0) / (double) N); - // benchmark(bench2_cycle, "rdtsc"); + pu3_benchmark(); exit(0); } - char *filename = argv[ 1 ]; - int file_size; - string contents = read_file(filename, &file_size); + char *filename = argv[ 1 ]; + uint32_t file_size; + string contents = read_file(filename, &file_size); if (contents == NULL) { perror("unable to open file"); exit(1); } - const int starting_code_ptr = init_ir2(assembly_target, S); + const uint32_t starting_code_ptr = init_ir2(ctx.memory.memory_u64, S); - int o_size; - long before = ntime(); - long cycles_bef = rdtsc(); - ir2(contents, filename, assembly_target); - long cycles_aft = rdtsc(); - long after = ntime(); - assembly_target[ 7 ] = starting_code_ptr; + uint32_t o_size; + long before = ntime(); + // long cycles_bef = rdtsc(); + ir2(contents, filename, ctx.memory.memory_u64); + // long cycles_aft = rdtsc(); + long after = ntime(); + *ctx.pc = starting_code_ptr; - /*int j = 0; - for(j = 0; j < 64; j++) { - printf("%i: %i %i\n", j, m[5000+j], m[5001+j]); - j++; - }*/ + // uint32_t j = 0; + // for(j = 0; j < 32; j++) { + // printf("%i: ", j); + // disassemble_pu3_inst(ctx.memory.memory_u64[starting_code_ptr + j]); + // } - // printf("assembly took %i milliseconds\n", (after - before)/1000); + printf("assembly took %li milliseconds\n", (after - before) / 1000); free(contents); - // int res_size = code - &m[ 4000 ]; + // uint32_t res_size = code - &m[ 4000 ]; // run the kernel (ring zero) forever (time slice -1) - int mem_size = S; + uint32_t mem_size = S; // pid zero - kernel processes[ 0 ] - = (emu_process) { .mem_size = S, - .memory = assembly_target, + = (emu_process) { .context = ctx, .ring_level = 0, .permissions = { .make_syscall = true, .spawn_process = true } }; diff --git a/pu3/pu3.cpu.c b/pu3/pu3.cpu.c index a10ca3f..40f395f 100644 --- a/pu3/pu3.cpu.c +++ b/pu3/pu3.cpu.c @@ -1,4 +1,5 @@ -#define _POSIX_C_SOURCE 200809L +#define _GNU_SOURCE +#define inline __attribute__((always_inline)) // #include <stdint.h> @@ -66,6 +67,28 @@ typedef uint64_t pu3_inst_t; #define set_data_u16(__v, __x) __v = (((__v) & 0xFFFF0000FFFFFFFFULL) | prep_data_u16(__x)) #define set_dest_u32(__v, __x) __v = (((__v) & 0xFFFFFFFF00000000ULL) | prep_dest_u32(__x)) +// clang-format off +struct { + uint32_t nop, hlt, mov, add, sub, inc, dec, mul, lsh, rsh, and, not, jmp, jnz, dmv, ddm; +} opcode = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; +typedef uint32_t pu3_opcode; +// clang-format on + +inline pu3_inst_t build_inst(bool swap, bool deref, pu3_opcode opcode, uint32_t lhs, uint16_t rhs) { + pu3_inst_t output = 0; + byte spare = ((swap & 1) << 7) | ((deref & 1) << 6); + byte op = opcode & 0b1111; + + set_spare(output, spare); + set_scroll_byte(output, op); + set_data_u16(output, rhs); + set_dest_u32(output, lhs); + + return output; +} + typedef struct { pu3_inst_t *memory_u64; uint32_t *memory_u32; @@ -76,7 +99,7 @@ typedef struct { uint32_t mem_size; uint32_t *pc; - uint32_t *time_slice; + uint32_t time_slice; } pu3_ctx; // instruct packing: @@ -87,25 +110,37 @@ typedef struct { // uint32_t dest; // } pu3_inst_t; -// instructions -// 0: nop -// 1: hlt -// 2: mov [target], src -// 3: add [target], src -// 4: sub [target], src -// 5: inc [target], ___ -// 6: dec [target], ___ -// 7: mul [target], src -// 8: lsh [target], src -// 9: rsh [target], src -// 10: and [target], src -// 11: not [target], src -// 12: jmp [target], src -// 13: jnz [target], src -// 14: ??? -// 15: ??? - -#define branchless(c, x, y) (((-(!!(c))) & (x)) | (~(-(!!(c))) & (y))) +// ------------------------------------------------------------------------------------------ +// instructions list +// 0: nop ________, ___ (( advances program counter by lhs )) +// 1: hlt ________, ___ (( stops the cpu )) +// 2: mov [target], src (( moves rhs to lhs )) +// 3: add [target], src (( adds rhs to lhs )) +// 4: sub [target], src (( subtracts rhs from lhs )) +// 5: inc [target], ___ (( increments lhs )) +// 6: dec [target], ___ (( decrements lhs )) +// 7: mul [target], src (( multiplies lhs by rhs )) +// 8: lsh [target], src (( left shifts lhs by rhs )) +// 9: rsh [target], src (( right shifts lhs by rhs )) +// 10: and [target], src (( logical ANDs lhs with rhs )) +// 11: not [target], src (( stores !*lhs in lhs )) +// 12: jmp [target], src (( jumps to lhs )) +// 13: jnz [target], src (( jumps to lhs if rhs is non-zero )) +// 14: dmv [target], ___ (( sets lhs to *lhs )) +// 15: ddm [target], src (( set m[m[lhs]] to m[rhs] )) +// ------------------------------------------------------------------------------------------ +// explanation +// we see lhs and rhs. these are, in order, the u32 dest and the u16 data. +// the following are executed, in order, in each cycle (if required): +// 1. lhs and rhs are swapped (to allow access to all of the u32 memory range)- +// -if the leftmost bit of spare is set. (spare & 0b10000000 != 0) +// 2. lhs is converted to memory[ lhs ] unconditionally +// 3. rhs is converted to memory[ rhs ] only if the second leftmmost bit of spare is set. +// (spare & 0b01000000 != 0) +// ------------------------------------------------------------------------------------------ +// WARNING: the fields left blank in the instruction list are NOT PROCESSED, +// this means they're ignored even if there's a dereference or a swap. +// ------------------------------------------------------------------------------------------ #define prep_raw() \ ({ \ @@ -115,17 +150,23 @@ typedef struct { #define prep_vals() \ ({ \ spare = get_spare(cur); \ - lhs = get_dest_u32(cur); \ - rhs = (uint32_t) get_data_u16(cur); \ - if (spare & 0x40) rhs = mem32[ rhs ]; \ if (unlikely(spare & 0x80)) { \ - out = lhs; \ - lhs = rhs; \ - rhs = out; \ + rhs = get_dest_u32(cur); \ + lhs = (uint32_t) get_data_u16(cur); \ + } else { \ + lhs = get_dest_u32(cur); \ + rhs = (uint32_t) get_data_u16(cur); \ } \ + if (spare & 0x40) rhs = mem32[ rhs ]; \ }) #define prep_only_left() ({ lhs = get_dest_u32(cur); }) +// spare = lhs; +// spare = *spare; +// + +void disassemble_pu3_inst(pu3_inst_t inst); + pu3(pu3_ctx ctx) { uint64_t i = 0; pu3_inst_t cur; @@ -150,7 +191,12 @@ pu3(pu3_ctx ctx) { pu3_start: i++; + if (unlikely(ctx.time_slice == i)) goto pu3_inst_1; cur = *pc++; + + // printf("%li: ", pc - mem64 - 1); + // disassemble_pu3_inst(cur); + #ifndef PU3_NO_INTRINSICS __builtin_prefetch(pc + 1, 0, 3); #endif @@ -210,8 +256,8 @@ pu3_inst_10: // and goto pu3_start; pu3_inst_11: // not - prep_vals(); - mem32[ lhs ] = !rhs; + prep_only_left(); + mem32[ lhs ] = !mem32[ lhs ]; goto pu3_start; pu3_inst_12: // jmp @@ -228,16 +274,19 @@ pu3_inst_14: // dmv prep_vals(); mem32[ lhs ] = mem32[ mem32[ lhs ] ]; goto pu3_start; -pu3_inst_15: // unused + +pu3_inst_15: // ddm + prep_vals(); + mem32[ mem32[ lhs ] ] = mem32[ rhs ]; goto pu3_start; pu3_inst_1: // hlt *ctx.pc = pc - mem64; - return *ctx.time_slice - i; + return ctx.time_slice - i; } const string op_names[] = { "nop", "hlt", "mov", "add", "sub", "inc", "dec", "mul", - "lsh", "rsh", "and", "not", "jmp", "jnz", "dmv", "???" }; + "lsh", "rsh", "and", "not", "jmp", "jnz", "dmv", "ddm" }; // bench: measure using clock() double bench_cycle(byte instr, pu3_ctx ctx) { @@ -277,24 +326,34 @@ double bench_cycle(byte instr, pu3_ctx ctx) { return insts_per_s / 1e6; // return M inst/s } -int main() { - const uint32_t SIZE = 1 << 23; +#define S 1 << 23 + +pu3_ctx *init_pu3() { + const uint32_t SIZE = S; let mem_arr = calloc(SIZE, sizeof(pu3_inst_t)); if (!mem_arr) { perror("memory allocation failed"); - return 1; + return NULL; } - pu3_ctx ctx = { .memory = { .memory_u64 = mem_arr, .memory_u32 = mem_arr }, - .mem_size = SIZE, - .pc = calloc(1, sizeof(uint32_t)), - .time_slice = calloc(1, sizeof(uint32_t)) }; + pu3_ctx *ctx = calloc(1, sizeof(pu3_ctx)); + *ctx = (pu3_ctx) { .memory = { .memory_u64 = mem_arr, .memory_u32 = mem_arr }, + .mem_size = SIZE, + .pc = calloc(1, sizeof(uint32_t)), + .time_slice = 0 }; + + return ctx; +} + +pu3_benchmark() { + pu3_ctx *__ctx = init_pu3(); + pu3_ctx ctx = *__ctx; int i; int total = 0; double benchs = 0; - for (i = 0; i < 15; i++) { + for (i = 0; i < 16; i++) { if (i == 1 || i == 12 || i == 13) continue; total++; benchs += bench_cycle(i, ctx); @@ -305,8 +364,8 @@ int main() { "TOTAL: %fMHz\n", benchs / total); - free(mem_arr); + free(ctx.memory.memory_u32); free(ctx.pc); - free(ctx.time_slice); + free(__ctx); return 0; }
\ No newline at end of file |
