aboutsummaryrefslogtreecommitdiff
path: root/pu.c
diff options
context:
space:
mode:
authorGravatar Moon Flower <moon@coffin.ir> 2025-08-11 11:34:18 +0330
committerGravatar Moon Flower <moon@coffin.ir> 2025-08-11 11:34:18 +0330
commit2fc20ad0b11e60ecfacc653024f2b582acad6e86 (patch)
treed7e3f793f32928e40a18c56d00875a5b8e74dc62 /pu.c
parentvscode theme extension (diff)
ir2 initial release!
Diffstat (limited to 'pu.c')
-rw-r--r--pu.c419
1 files changed, 0 insertions, 419 deletions
diff --git a/pu.c b/pu.c
deleted file mode 100644
index 3de2576..0000000
--- a/pu.c
+++ /dev/null
@@ -1,419 +0,0 @@
-#define _XOPEN_SOURCE 700
-#include <SDL2/SDL.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#pragma clang diagnostic ignored "-Wreturn-type"
-#pragma clang diagnostic ignored "-Wc23-extensions"
-#pragma clang diagnostic ignored "-Wnull-character"
-#pragma clang diagnostic ignored "-Wimplicit-int"
-#pragma clang diagnostic ignored "-Wparentheses"
-#pragma clang diagnostic ignored "-Wempty-body"
-
-// NOTE: If you want the CPU to crash when there is an illegal instruction, replace the useless "4"
-// in the code with "__builtin_trap()".
-// clang-format off
-#define S 1<<20
-#define H !--c?
-#define J while
-m[S],c,a;pu(){J(c=m[m[7]++])H*m=m[m[7]++]:c--<9?!a?m[c]=*m:0:8>(c-=8)?*m=m[c]:!(c-=8)?m[m[1]]=*m:H*m=a:H a+=*m:H a-=*m:H a=!a:H a=0:4;}
-// clang-format on
-
-// a is acc
-// first 8 memory bytes are registers actually
-// c is pc, read from m[7]
-
-// --- opcodes ---
-// 0 = halt DONE
-// 1 = const in r0 DONE
-// 2...9 = r0 in rX (only if acc is zero) DONE
-// 10...17 = rX in r0 DONE
-// 18 = r0 in m[r1] DONE
-// 19 = acc in r0 DONE
-// 20 = acc += r0 DONE
-// 21 = acc -= r0 DONE
-// 22 = acc = !acc DONE
-// 23 = acc = 0 DONE
-// for ops 2..9 and 10..17 it basically works like this: 2 handles r0, 3 r1, 4 r2, etc. 10 handles
-// r0, 11 r1, 12 r2 and so on.
-
-// compiler!
-// the switch skips whitespace. then, the beautiful loop thingymajigy emits bytecode.
-
-// clang-format off
-#define W case
-#define Q goto M;
-char R[]={
-#embed "t"
-};K;char*Y[1<<9];void*as(char*I,int*O){char*V;J(K=*I){V=R;switch(K){W 32:W 10:W 9:I++;Q;W 35:J(*++I!=10);Q W 40:I++;K=strtol(I,&I,10);Y[K]=I;J(*I++!=41);Q W 41:return O;W 64:O=as(Y[strtol(++I,&I,10)],O);if((long)O<0)return O;Q W 39:*O++=1;I++;*O++=*I++;Q}strncmp("con",I,3)?:({*O++=1,*O++=strtol(I+=3,&I,10);Q});J(*V)V+=3,(strncmp(V-3,I,3)?:({*O++=*V;I+=3;Q})),V+=2;return(char*)-(long)I;M:}return 0;}
-// clang-format on
-
-#undef Q
-#undef H
-#undef W
-#undef S
-#undef J
-
-#ifndef __WRAPPER
-
-SDL_Window *window = NULL;
-SDL_Renderer *renderer = NULL;
-
-// runs pu until exit code != 2,
-// that exit code is an interrupt for talking to the emulated hardware
-int emu() {
- while (1) {
- pu();
- int e_code = m[ 0 ];
-
- // Poll SDL events to handle window close, etc.
- SDL_Event event;
- while (SDL_PollEvent(&event)) {
- if (event.type == SDL_QUIT) {
- if (renderer) SDL_DestroyRenderer(renderer);
- if (window) SDL_DestroyWindow(window);
- SDL_Quit();
- return 0;
- }
- // Additional event handling can be added here if needed.
- }
-
- if (e_code != 2) {
- if (renderer) SDL_DestroyRenderer(renderer);
- if (window) SDL_DestroyWindow(window);
- SDL_Quit();
- return e_code;
- }
-
- // handle hardware interrupts
- int int_code = m[ 1 ];
-
- // 0: output string
- if (int_code == 0) {
- int ptr = m[ 2 ];
- int size = m[ 3 ], i = 0;
-
- for (; i < size; i++) putchar(m[ ptr++ ]);
- while (size--) putchar(m[ ptr++ ]);
- }
-
- // 1: input character
- else if (int_code == 1) {
- m[ 2 ] = getchar();
- }
-
- // 2: graphics operations via SDL2
- else if (int_code == 2) {
- int gfx_op = m[ 2 ];
- switch (gfx_op) {
- case 0: // Initialize window (parameters: width in m[3], height in m[4])
- {
- int width = m[ 3 ];
- int height = m[ 4 ];
- if (SDL_Init(SDL_INIT_VIDEO) < 0) {
- fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
- m[ 0 ] = 1; // Set e_code to indicate error
- break;
- }
- window = SDL_CreateWindow(
- "PU VM Graphics",
- SDL_WINDOWPOS_CENTERED,
- SDL_WINDOWPOS_CENTERED,
- width,
- height,
- 0);
- if (!window) {
- fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError());
- m[ 0 ] = 1; // Set e_code to indicate error
- break;
- }
- renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
- if (!renderer) {
- fprintf(stderr, "SDL_CreateRenderer failed: %s\n", SDL_GetError());
- m[ 0 ] = 1; // Set e_code to indicate error
- break;
- }
-
- break;
- }
- case 1: // Set draw color (parameters: r in m[3], g in m[4], b in m[5], a in m[6])
- {
- Uint8 r = (Uint8) m[ 3 ];
- Uint8 g = (Uint8) m[ 4 ];
- Uint8 b = (Uint8) m[ 5 ];
- Uint8 a = (Uint8) m[ 6 ];
- SDL_SetRenderDrawColor(renderer, r, g, b, a);
- break;
- }
- case 2: // Clear screen
- SDL_RenderClear(renderer);
- break;
- case 3: // Present (flip buffers)
- SDL_RenderPresent(renderer);
- break;
- case 4: // Draw point (parameters: x in m[3], y in m[4])
- {
- int x = m[ 3 ];
- int y = m[ 4 ];
- SDL_RenderDrawPoint(renderer, x, y);
- break;
- }
- case 5: // Draw line (parameters: x1 in m[3], y1 in m[4], x2 in m[5], y2 in m[6])
- {
- int x1 = m[ 3 ];
- int y1 = m[ 4 ];
- int x2 = m[ 5 ];
- int y2 = m[ 6 ];
- SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
- break;
- }
- case 6: // Fill rectangle (parameters: x in m[3], y in m[4], w in m[5], h in m[6])
- {
- int x = m[ 3 ];
- int y = m[ 4 ];
- int w = m[ 5 ];
- int h = m[ 6 ];
- SDL_Rect rect = { x, y, w, h };
- SDL_RenderFillRect(renderer, &rect);
- break;
- }
- case 7: // Draw rectangle outline (parameters: x in m[3], y in m[4], w in m[5], h in
- // m[6])
- {
- int x = m[ 3 ];
- int y = m[ 4 ];
- int w = m[ 5 ];
- int h = m[ 6 ];
- SDL_Rect rect = { x, y, w, h };
- SDL_RenderDrawRect(renderer, &rect);
- break;
- }
- case 8: // Quit graphics
- if (renderer) SDL_DestroyRenderer(renderer);
- if (window) SDL_DestroyWindow(window);
- SDL_Quit();
- renderer = NULL;
- window = NULL;
- break;
- default:
- // Unknown graphics operation; ignored for simplicity.
- break;
- }
- }
-
- else {
- // unknown interrupt. what to do?
- }
-
- m[ 0 ] = 0;
- }
-}
-
-char R_backup[] = "hlt\0 ar1\2 ar2\3 ar3\4 ar4\5 ar5\6 ar6\7 ar7\x8 ar8\x9 r1a\xA r2a\xB r3a\xC "
- "r4a\xD r5a\xE r6a\xF r7a\20 r8a\21 mem\22 aca\23 add\24 sub\25 not\26 clr\27";
-
-void error_debug(char *fail_point, char *code, int sz) {
- if ((long) fail_point >= 0) return;
-
- fail_point = (char *) -(long) fail_point;
- int error_pos = (int) (fail_point - code);
- int i;
-
- int line = 1, col = 1;
- for (i = 0; i < error_pos && i < sz; i++) {
- if (code[ i ] == '\n') {
- line++;
- col = 1;
- } else {
- col++;
- }
- }
-
- fprintf(
- stderr,
- "\x1b[1m\x1b[31merror:\x1b[0m "
- "\x1b[1massembly failed\x1b[0m "
- "at \x1b[36mline %d\x1b[0m, \x1b[36mcolumn %d\x1b[0m "
- "(\x1b[33mposition %d\x1b[0m):\n",
- line,
- col,
- error_pos);
-
- int line_start = error_pos;
- while (line_start > 0 && code[ line_start - 1 ] != '\n') { line_start--; }
-
- int line_end = error_pos;
- while (line_end < sz && code[ line_end ] != '\n' && code[ line_end ] != '\0') { line_end++; }
-
- fprintf(stderr, " \x1b[1m");
- for (i = line_start; i < line_end; i++) { fputc(code[ i ], stderr); }
- fprintf(stderr, "\x1b[0m\n");
-
- fprintf(stderr, " ");
- for (i = line_start; i < error_pos; i++) { fputc((code[ i ] == '\t') ? '\t' : ' ', stderr); }
- fprintf(stderr, "\x1b[1m\x1b[31m^\x1b[0m \x1b[90mparsing stopped here\x1b[0m\n");
-}
-
-int main(int argc, char **argv) {
- if (access("t", F_OK)) {
- // patch the instruction table incase you removed it.
- printf("you've deleted `t`! i'll write it again for you.\n\n");
- FILE *fp = fopen("t", "w+");
- fwrite(R_backup, 1, sizeof(R_backup), fp);
- fclose(fp);
- memcpy(R, R_backup, sizeof(R_backup));
- }
-
- if (argc == 1) {
- printf(
- "Usage:\n"
- " %s run <filename>: Execute a file\n"
- " %s repl: Open in REPL mode",
- argv[ 0 ],
- argv[ 0 ]);
- exit(1);
- }
-
- if (argc == 2 && !strcmp(argv[ 1 ], "repl")) {
- printf("\npu repl\n"
- "| code is inserted at address 1024\n"
- "| submit RUN to execute the code.\n"
- "| submit CLEAR to erase history.\n"
- "| submit SAVE to write contents to repl.pu\n"
- "| submit LOAD to fetch contents from repl.pu\n"
- "\n");
-
- char *code = malloc(1);
- *code = '\n';
- size_t size = 0;
-
- while (1) {
- printf("%li > ", size);
- char *line;
- size_t _len;
- size_t len = getline(&line, &_len, stdin);
-
- if (len == 1) continue;
-
- if (len == 4 && strncmp(line, "run", 3) == 0) {
- memset(m, 0, 8);
- m[ 7 ] = 1024;
- emu();
- int i;
- for (i = 0; i < 16; i++) printf("%i ", m[ 1024 + i ]);
- printf("\n\n");
- continue;
- }
-
- if (len == 5 && strncmp(line, "save", 4) == 0) {
- FILE *fd = fopen("repl.pu", "w+");
- fwrite(code, 1, size, fd);
- fclose(fd);
- printf("saved %li bytes.\n", size);
-
- continue;
- }
-
- if (len == 5 && strncmp(line, "load", 4) == 0) {
- FILE *fp = fopen("repl.pu", "r");
- fseek(fp, 0, SEEK_END);
- int sz = ftell(fp);
- rewind(fp);
- char *saved = malloc(sz + 1);
- fread(saved, 1, sz, fp);
- saved[ sz ] = 0;
- fclose(fp);
-
- free(code);
- code = saved;
- size = sz;
- printf("loaded %i bytes.\n", sz);
-
- goto SKIP_STRAIGHT;
- }
-
- if (len == 6 && strncmp(line, "clear", 5) == 0) {
- printf("-- code cleared\n");
- free(code);
- code = malloc(1);
- size = 0;
- continue;
- }
-
- if (len == 7 && strncmp(line, "status", 6) == 0) {
- printf(
- "\nregisters\n"
- "r1: %i r2: %i\n"
- "r3: %i r4: %i\n"
- "r5: %i r6: %i\n"
- "r7: %i pc: %i\n\n",
- m[ 0 ],
- m[ 1 ],
- m[ 2 ],
- m[ 3 ],
- m[ 4 ],
- m[ 5 ],
- m[ 6 ],
- m[ 7 ]);
-
- continue;
- }
-
- char *old_code = malloc(size);
- memcpy(old_code, code, size);
-
- code = realloc(code, size += len);
- memcpy(&code[ size - len ], line, len);
-
- SKIP_STRAIGHT:
-
- char *exit_code = as(code, &m[ 1024 ]);
-
- if (exit_code != 0) {
- printf("\n");
- error_debug(exit_code, code, size);
- printf("\n");
-
- free(code);
- code = old_code;
- size -= len;
- continue;
- }
-
- free(old_code);
- }
-
- exit(0);
- }
-
- if (argc == 3 && strcmp(argv[ 1 ], "run") != 0) {
- printf("Invalid mode - Only supported modes are 'run' and 'repl'\n");
- return;
- }
-
- // read code
- FILE *fp = fopen(argv[ 2 ], "r");
- fseek(fp, 0, SEEK_END);
- int sz = ftell(fp);
- rewind(fp);
- char code[ sz + 1 ];
- fread(code, 1, sz, fp);
- code[ sz ] = 0;
- fclose(fp);
-
- // set pc
- m[ 7 ] = 1024;
- // assemble
- char *fail_point = as(code, &m[ 1024 ]);
-
- if (fail_point != 0) {
- error_debug(fail_point, code, sz);
- return;
- }
-
- // run emulation
- emu();
-}
-#endif \ No newline at end of file