diff options
| author | 2025-08-11 11:34:18 +0330 | |
|---|---|---|
| committer | 2025-08-11 11:34:18 +0330 | |
| commit | 2fc20ad0b11e60ecfacc653024f2b582acad6e86 (patch) | |
| tree | d7e3f793f32928e40a18c56d00875a5b8e74dc62 /pu1 | |
| parent | vscode theme extension (diff) | |
ir2 initial release!
Diffstat (limited to 'pu1')
| -rw-r--r-- | pu1/code.pasm | 23 | ||||
| -rw-r--r-- | pu1/pasm-syntax/package.json | 26 | ||||
| -rw-r--r-- | pu1/pasm-syntax/pasm-syntax-0.0.1.vsix | bin | 0 -> 2163 bytes | |||
| -rw-r--r-- | pu1/pasm-syntax/syntaxes/pasm.tmLanguage.json | 145 | ||||
| -rw-r--r-- | pu1/pu.c | 419 | ||||
| -rw-r--r-- | pu1/pu.out.c | bin | 0 -> 1405 bytes | |||
| -rw-r--r-- | pu1/putest.c | 380 | ||||
| -rw-r--r-- | pu1/repl.pu | 1 | ||||
| -rw-r--r-- | pu1/t | bin | 0 -> 115 bytes |
9 files changed, 994 insertions, 0 deletions
diff --git a/pu1/code.pasm b/pu1/code.pasm new file mode 100644 index 0000000..94f37c5 --- /dev/null +++ b/pu1/code.pasm @@ -0,0 +1,23 @@ +(1 ar4 con 60 ar2 r4a mem con 1 ar4 con 60 ar3 con 0 ar2 con 2 hlt) +(2 con 255 ar7 con 2 ar2 con 1 ar3 con 2 hlt) + +# init sdl (1000, 600) +con 0 ar3 con 2 ar2 con 1000 ar4 con 600 ar5 con 2 hlt + +# set color to 200,200,0,255 +con 200 ar4 con 200 ar5 con 0 ar6 @2 + +# save spot +r8a ar6 + +# clear screen +con 2 ar2 con 2 ar3 con 2 hlt + +# present screen +con 2 ar2 con 3 ar3 con 2 hlt + +# jump-back +r6a ar8 + +# quit +con 0 hlt diff --git a/pu1/pasm-syntax/package.json b/pu1/pasm-syntax/package.json new file mode 100644 index 0000000..d287cc2 --- /dev/null +++ b/pu1/pasm-syntax/package.json @@ -0,0 +1,26 @@ +{ + "name": "pasm-syntax", + "displayName": "PASM Syntax", + "description": "Syntax highlighting for PASM custom assembly", + "version": "0.0.1", + "engines": { + "vscode": "^1.50.0" + }, + "categories": ["Programming Languages"], + "contributes": { + "languages": [ + { + "id": "pasm", + "aliases": ["PASM", "pasm"], + "extensions": [".pasm"] + } + ], + "grammars": [ + { + "language": "pasm", + "scopeName": "source.pasm", + "path": "./syntaxes/pasm.tmLanguage.json" + } + ] + } +} diff --git a/pu1/pasm-syntax/pasm-syntax-0.0.1.vsix b/pu1/pasm-syntax/pasm-syntax-0.0.1.vsix Binary files differnew file mode 100644 index 0000000..e94bb8b --- /dev/null +++ b/pu1/pasm-syntax/pasm-syntax-0.0.1.vsix diff --git a/pu1/pasm-syntax/syntaxes/pasm.tmLanguage.json b/pu1/pasm-syntax/syntaxes/pasm.tmLanguage.json new file mode 100644 index 0000000..e0df85e --- /dev/null +++ b/pu1/pasm-syntax/syntaxes/pasm.tmLanguage.json @@ -0,0 +1,145 @@ +{ + "name": "PASM", + "scopeName": "source.pasm", + "fileTypes": [ + "pasm" + ], + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#macro" + }, + { + "include": "#instruction" + }, + { + "include": "#register" + }, + { + "include": "#number" + } + ], + "repository": { + "comment": { + "patterns": [ + { + "name": "comment.line.number-sign.pasm", + "match": "#.*$" + } + ] + }, + "macro": { + "patterns": [ + { + "name": "meta.macro.pasm", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.macro.begin.pasm" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.macro.end.pasm" + } + }, + "patterns": [ + { + "include": "#instruction" + }, + { + "include": "#register" + }, + { + "include": "#number" + }, + { + "include": "#comment" + } + ] + }, + { + "name": "keyword.other.macro.pasm", + "match": "@\\d+" + } + ] + }, + "instruction": { + "patterns": [ + { + "name": "meta.instruction.ar.pasm", + "captures": { + "1": { + "name": "keyword.instruction.prefix.ar.pasm" + }, + "2": { + "name": "string.quoted.double.pasm" + } + }, + "match": "\\b(ar)([1-8])\\b" + }, + { + "name": "meta.instruction.r.pasm", + "captures": { + "1": { + "name": "keyword.instruction.prefix.r.pasm" + }, + "2": { + "name": "constant.numeric.instruction-number.r.pasm" + }, + "3": { + "name": "keyword.instruction.suffix.a.pasm" + } + }, + "match": "\\b(r)([1-8])(a)\\b" + }, + { + "name": "keyword.instruction.simple.pasm", + "match": "\\b(hlt|con|mem|aca|add|sub|not|clr)\\b" + } + ] + }, + "register": { + "patterns": [ + { + "name": "meta.register.ar.pasm", + "captures": { + "1": { + "name": "variable.other.register.prefix.ar.pasm" + }, + "2": { + "name": "constant.numeric.register-number.ar.pasm" + } + }, + "match": "\\b(ar)([1-8])\\b" + }, + { + "name": "meta.register.r.pasm", + "captures": { + "1": { + "name": "variable.other.register.prefix.r.pasm" + }, + "2": { + "name": "constant.numeric.register-number.r.pasm" + }, + "3": { + "name": "variable.other.register.suffix.a.pasm" + } + }, + "match": "\\b(r)([1-8])(a)\\b" + } + ] + }, + "number": { + "patterns": [ + { + "name": "constant.numeric.decimal.pasm", + "match": "\\b\\d+\\b" + } + ] + } + } +}
\ No newline at end of file diff --git a/pu1/pu.c b/pu1/pu.c new file mode 100644 index 0000000..f182e65 --- /dev/null +++ b/pu1/pu.c @@ -0,0 +1,419 @@ +#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 +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"; + +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"); +} + +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 diff --git a/pu1/pu.out.c b/pu1/pu.out.c Binary files differnew file mode 100644 index 0000000..c62b50a --- /dev/null +++ b/pu1/pu.out.c diff --git a/pu1/putest.c b/pu1/putest.c new file mode 100644 index 0000000..013a48b --- /dev/null +++ b/pu1/putest.c @@ -0,0 +1,380 @@ +#include <stdio.h> +#include <string.h> + +#define __WRAPPER +#include "pu.out.c" + +/* ─── color & statistics ──────────────────────────────────────────────────── */ +#define COLOR_RED "\x1b[1;31m" +#define COLOR_BLUE "\033[1;34m" +#define COLOR_SUM "\033[1;33m" +#define COLOR_RESET "\x1b[0m" + +static int tests_run = 0; +static int tests_passed = 0; + +/* PASS if cond true, else FAIL; color and bump counters */ +#define PRINT_RESULT(cond) \ + do { \ + tests_run++; \ + if (cond) { \ + tests_passed++; \ + printf(COLOR_BLUE "PASS" COLOR_RESET "\n"); \ + } else { \ + printf(COLOR_RED "FAIL" COLOR_RESET "\n"); \ + } \ + } while (0) +/* ───────────────────────────────────────────────────────────────────────── */ + +void reset() { + memset(m, 0, sizeof(m)); + a = 0; + c = 0; +} + +void test_opcode_0() { + printf("Testing opcode 0 (hlt)... "); + reset(); + m[ 0 ] = 0; + m[ 7 ] = 0; + pu(); + PRINT_RESULT(1); +} + +void test_opcode_1() { + printf("Testing opcode 1 (const in r0)... "); + reset(); + m[ 0 ] = 1; + m[ 1 ] = 42; + m[ 2 ] = 0; + m[ 7 ] = 0; + pu(); + PRINT_RESULT(m[ 0 ] == 42); +} + +void test_opcode_2() { + printf("Testing opcode 4 (r0 in r2 if acc zero)... "); + reset(); + m[ 0 ] = 123; + a = 0; + m[ 10 ] = 4; + m[ 11 ] = 0; + m[ 7 ] = 10; + pu(); + PRINT_RESULT(m[ 2 ] == 123); +} + +void test_opcode_2_zero_acc() { + printf("Testing opcode 4 with zero acc (should not store)... "); + reset(); + m[ 0 ] = 123; + m[ 2 ] = 999; + a = 1; + m[ 10 ] = 4; + m[ 11 ] = 0; + m[ 7 ] = 10; + pu(); + PRINT_RESULT(m[ 2 ] == 999); +} + +void test_opcode_10() { + printf("Testing opcode 12 (r2 in r0)... "); + reset(); + m[ 2 ] = 456; + m[ 10 ] = 12; + m[ 11 ] = 0; + m[ 7 ] = 10; + pu(); + PRINT_RESULT(m[ 0 ] == 456); +} + +void test_opcode_18() { + printf("Testing opcode 18 (r0 in m[r1])... "); + reset(); + m[ 0 ] = 789; + m[ 1 ] = 100; + m[ 10 ] = 18; + m[ 11 ] = 0; + m[ 7 ] = 10; + pu(); + PRINT_RESULT(m[ 100 ] == 789); +} + +void test_opcode_19() { + printf("Testing opcode 19 (acc in r0)... "); + reset(); + a = 555; + m[ 10 ] = 19; + m[ 11 ] = 0; + m[ 7 ] = 10; + pu(); + PRINT_RESULT(m[ 0 ] == 555); +} + +void test_opcode_20() { + printf("Testing opcode 20 (acc += r0)... "); + reset(); + a = 10; + m[ 0 ] = 5; + m[ 10 ] = 20; + m[ 11 ] = 0; + m[ 7 ] = 10; + pu(); + PRINT_RESULT(a == 15); +} + +void test_opcode_21() { + printf("Testing opcode 21 (acc -= r0)... "); + reset(); + a = 20; + m[ 0 ] = 7; + m[ 10 ] = 21; + m[ 11 ] = 0; + m[ 7 ] = 10; + pu(); + PRINT_RESULT(a == 13); +} + +void test_opcode_22() { + printf("Testing opcode 22 (acc = !acc)... "); + reset(); + a = 5; + m[ 10 ] = 22; + m[ 11 ] = 0; + m[ 7 ] = 10; + pu(); + PRINT_RESULT(a == 0); +} + +void test_opcode_23() { + printf("Testing opcode 23 (acc = 0)... "); + reset(); + a = 999; + m[ 10 ] = 23; + m[ 11 ] = 0; + m[ 7 ] = 10; + pu(); + PRINT_RESULT(a == 0); +} + +/* ─── assembler support ───────────────────────────────────────────────────── */ + +i; +int check_output(int* O, int* expected, int len, const char* test_name) { + for (i = 0; i < len; i++) { + if (O[ i ] != expected[ i ]) { + printf( + "%s: output[%d]=%d (expected %d): " COLOR_RED "FAIL" COLOR_RESET "\n", + test_name, + i, + O[ i ], + expected[ i ]); + return 0; + } + } + return 1; +} + +void reset_output(int* O, int size) { memset(O, 0, size * sizeof(int)); } + +void test_hlt() { + printf("Testing hlt (opcode 0)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 0 }; + char* ret = as("hlt", O); + ok = (ret == 0 && check_output(O, exp, 1, "hlt")); + PRINT_RESULT(ok); +} + +void test_con() { + printf("Testing con 123 (opcode 1, 123)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 1, 123 }; + char* ret = as("con 123", O); + ok = (ret == 0 && check_output(O, exp, 2, "con")); + PRINT_RESULT(ok); +} + +void test_ar1() { + printf("Testing ar1 (opcode 2)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 2 }; + char* ret = as("ar1", O); + ok = (ret == 0 && check_output(O, exp, 1, "ar1")); + PRINT_RESULT(ok); +} + +void test_ar8() { + printf("Testing ar8 (opcode 9)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 9 }; + char* ret = as("ar8", O); + ok = (ret == 0 && check_output(O, exp, 1, "ar8")); + PRINT_RESULT(ok); +} + +void test_r1a() { + printf("Testing r1a (opcode 10)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 10 }; + char* ret = as("r1a", O); + ok = (ret == 0 && check_output(O, exp, 1, "r1a")); + PRINT_RESULT(ok); +} + +void test_r8a() { + printf("Testing r8a (opcode 17)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 17 }; + char* ret = as("r8a", O); + ok = (ret == 0 && check_output(O, exp, 1, "r8a")); + PRINT_RESULT(ok); +} + +void test_mem() { + printf("Testing mem (opcode 18)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 18 }; + char* ret = as("mem", O); + ok = (ret == 0 && check_output(O, exp, 1, "mem")); + PRINT_RESULT(ok); +} + +void test_aca() { + printf("Testing aca (opcode 19)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 19 }; + char* ret = as("aca", O); + ok = (ret == 0 && check_output(O, exp, 1, "aca")); + PRINT_RESULT(ok); +} + +void test_add() { + printf("Testing add (opcode 20)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 20 }; + char* ret = as("add", O); + ok = (ret == 0 && check_output(O, exp, 1, "add")); + PRINT_RESULT(ok); +} + +void test_sub() { + printf("Testing sub (opcode 21)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 21 }; + char* ret = as("sub", O); + ok = (ret == 0 && check_output(O, exp, 1, "sub")); + PRINT_RESULT(ok); +} + +void test_not() { + printf("Testing not (opcode 22)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 22 }; + char* ret = as("not", O); + ok = (ret == 0 && check_output(O, exp, 1, "not")); + PRINT_RESULT(ok); +} + +void test_clr() { + printf("Testing clr (opcode 23)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 23 }; + char* ret = as("clr", O); + ok = (ret == 0 && check_output(O, exp, 1, "clr")); + PRINT_RESULT(ok); +} + +void test_multi_instruction() { + printf("Testing multi-instruction (hlt con 123 ar1 clr)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 0, 1, 123, 2, 23 }; + char* ret = as("hlt con 123 ar1 clr", O); + ok = (ret == 0 && check_output(O, exp, 5, "multi-instruction")); + PRINT_RESULT(ok); +} + +void test_whitespace() { + printf("Testing whitespace handling (hlt \\t\\n con 456 \\n clr)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 0, 1, 456, 23 }; + char* ret = as("hlt \t\n con 456 \n clr", O); + ok = (ret == 0 && check_output(O, exp, 4, "whitespace")); + PRINT_RESULT(ok); +} + +void test_comment() { + printf("Testing comment handling (should ignore line)... "); + int O[ 10 ], ok; + reset_output(O, 10); + int exp[] = { 1, 90 }; + char* ret = as("# hello\ncon 90", O); + ok = (ret == 0 && check_output(O, exp, 2, "comment")); + PRINT_RESULT(ok); +} + +void test_error() { + printf("Testing error case (invalid instruction)... "); + int O[ 10 ], ok; + reset_output(O, 10); + char* ret = as("xyz", O); + ok = (ret != 0); + PRINT_RESULT(ok); +} + +int main() { + printf(COLOR_SUM "Running CPU unit tests...\n\n" COLOR_RESET); + + test_opcode_0(); + test_opcode_1(); + test_opcode_2(); + test_opcode_2_zero_acc(); + test_opcode_10(); + test_opcode_18(); + test_opcode_19(); + test_opcode_20(); + test_opcode_21(); + test_opcode_22(); + test_opcode_23(); + + printf(COLOR_SUM "\nRunning assembler unit tests...\n\n" COLOR_RESET); + + test_hlt(); + test_con(); + test_ar1(); + test_ar8(); + test_r1a(); + test_r8a(); + test_mem(); + test_aca(); + test_add(); + test_sub(); + test_not(); + test_clr(); + test_multi_instruction(); + test_whitespace(); + test_comment(); + test_error(); + + printf( + "\nTotal tests run: %d, passed: %d, failed: %d\n", + tests_run, + tests_passed, + tests_run - tests_passed); + + return 0; +} diff --git a/pu1/repl.pu b/pu1/repl.pu new file mode 100644 index 0000000..2cb3020 --- /dev/null +++ b/pu1/repl.pu @@ -0,0 +1 @@ +con 5 Binary files differ |
