diff options
| author | 2025-08-26 18:43:15 +0330 | |
|---|---|---|
| committer | 2025-08-26 18:43:15 +0330 | |
| commit | e4dfc38d6041d3d5c5d90d757e2e87aa6f1db391 (patch) | |
| tree | 9e7ff15318f186ba05bfb557036c5d42c4c8e0cc /pu3/pu3.cpu.c | |
| parent | small changes (diff) | |
pu3 poc
Diffstat (limited to 'pu3/pu3.cpu.c')
| -rw-r--r-- | pu3/pu3.cpu.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/pu3/pu3.cpu.c b/pu3/pu3.cpu.c new file mode 100644 index 0000000..39d4a1d --- /dev/null +++ b/pu3/pu3.cpu.c @@ -0,0 +1,152 @@ +#define _POSIX_C_SOURCE 200809L +// + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <time.h> +#include <unistd.h> + +// -- disable use of compiler intrinsics +// #define PU3_NO_INTRINSICS +// -- inaccurate clocks +// #define PU3_BAD_CLOCK + +#ifndef PU3_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 + +// it is time +// the thing you've none been waiting for +// pu3 + +typedef char *string; +typedef unsigned char byte; +typedef byte bool; + +typedef struct { + byte __spare[ 1 ]; + byte op; + uint16_t data; + uint32_t dest; +} pu3_inst_t; + +typedef union { + pu3_inst_t inst_struct; + uint64_t inst_num; +} pu3_inst_u; + +typedef struct { + pu3_inst_u *memory; + uint32_t mem_size; + uint32_t *pc; + uint32_t *time_slice; +} pu3_ctx; + +// instructions +// 0: nop +// 1: halt +// 2: mov [target], src + +pu3(pu3_ctx ctx) { + static uint32_t i; + static pu3_inst_t cur; + + pu3_inst_u *pc = ctx.memory + *ctx.pc; + + static const __attribute__((aligned(64))) void *GOTO_TABLE[] = { + &&inst_0, + &&pu3_end, + &&inst_2, + }; + +pu3_start: + cur = pc->inst_struct; + pc++; + +#ifndef PU3_NO_INTRINSICS + __builtin_prefetch(pc + 1, 0, 3); +#endif +#define get_data() ((cur.op & 0b10000000) ? (ctx.memory[ cur.data ].inst_num) : (cur.data)) + + // 1 - 4: opcode + // 5: data_type [0 = constant, 1 = memory] + + // [5] [ ] [ ] [ ] [1] [2] [3] [4] + goto *GOTO_TABLE[ cur.op & 0b1111 ]; + +inst_0: // nop + pc += cur.dest; + goto pu3_start; + +inst_1: // halt + // unused, we just jump to break + +inst_2: // mov + ctx.memory[ cur.dest ].inst_num = get_data(); + goto pu3_start; + +pu3_end: + *ctx.pc = pc - ctx.memory; + return *ctx.time_slice - i; +} + +const string op_names[] = { "nop", "halt", "mov" }; + +// bench: measure using clock() +double bench_cycle(byte instr, pu3_ctx ctx) { + int i; + for (i = 16; i < ctx.mem_size; i++) { + ctx.memory[ i ].inst_struct.op = instr & 0b1111; + ctx.memory[ i ].inst_struct.dest = 5; + ctx.memory[ i ].inst_struct.data = 6; + + if (i == ctx.mem_size - 1) ctx.memory[ i ].inst_struct.op = 1; + } + ctx.memory[ i ].inst_struct.op = 0; + *ctx.pc = 8; + + clock_t start = ntime(); + // int wstart = rdtsc(); + pu3(ctx); + // int wend = rdtsc(); + clock_t end = ntime(); + + double nanoseconds = (end - start); + double inst_count = *ctx.pc - 8; + 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 +} + +main() { + static const uint32_t SIZE = 1 << 24; + + pu3_ctx ctx = { .memory = calloc(SIZE, sizeof(pu3_inst_u)), + .mem_size = SIZE, + .pc = calloc(1, sizeof(uint32_t)), + .time_slice = calloc(1, sizeof(uint32_t)) }; + + bench_cycle(2, ctx); +}
\ No newline at end of file |
