diff options
| author | 2025-08-11 11:34:18 +0330 | |
|---|---|---|
| committer | 2025-08-11 11:34:18 +0330 | |
| commit | 2fc20ad0b11e60ecfacc653024f2b582acad6e86 (patch) | |
| tree | d7e3f793f32928e40a18c56d00875a5b8e74dc62 /pu.c | |
| parent | vscode theme extension (diff) | |
ir2 initial release!
Diffstat (limited to 'pu.c')
| -rw-r--r-- | pu.c | 419 |
1 files changed, 0 insertions, 419 deletions
@@ -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 |
