diff options
| author | 2025-08-28 17:40:20 +0330 | |
|---|---|---|
| committer | 2025-08-28 17:40:20 +0330 | |
| commit | 05491e6fb4b2d56841ad8fe2ab1b7371592ebe74 (patch) | |
| tree | 1c8e1d4221444238ddc7a24443173e52beb7a462 /pu3/pu3.cpu.c | |
| parent | pu3 poc5 (diff) | |
Diffstat (limited to 'pu3/pu3.cpu.c')
| -rw-r--r-- | pu3/pu3.cpu.c | 143 |
1 files changed, 101 insertions, 42 deletions
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 |
