nrj.c (2903B)
1 /* NRJ (NOR and Reference Jump) OISC ANSI C emulator 2 * Created by Luxferre, 2022, public domain 3 * Build with: cc -Os -std=c89 -o nrj nrj.c */ 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <termios.h> 7 #include <unistd.h> 8 #include <sys/select.h> 9 #ifndef NRJWORD /* we emulate NRJ16 by default but this can be overridden */ 10 #define NRJWORD unsigned short 11 #endif 12 #define NRJWSIZE (sizeof(NRJWORD) << 3) 13 #define NRJSIZE (1 << NRJWSIZE) 14 #define MAXADDR ((NRJWORD) (NRJSIZE - 1)) 15 16 int kbhit() { /* our best attempt to detect a keypress on a POSIX system */ 17 struct timeval tv = { 0L, 0L }; 18 fd_set fds; 19 FD_ZERO(&fds); 20 FD_SET(0, &fds); 21 return select(1, &fds, NULL, NULL, &tv) > 0; 22 } 23 24 void nrj_in(NRJWORD *ctxid, NRJWORD *val) { /* context-dependent input handler */ 25 unsigned char c; 26 if(*ctxid == (NRJWORD) 0) /* for now, only emulate standard context id */ 27 *val = (NRJWORD) ((kbhit() && read(0, &c, 1) > -1) ? c : 0); 28 } 29 30 void nrj_out(NRJWORD *ctxid, NRJWORD *val) { /* context-dependent output handler */ 31 if(*ctxid == (NRJWORD) 0) /* for now, only emulate standard context id */ 32 putchar((unsigned char) *val); 33 } 34 35 void nrj_run(NRJWORD *mem, NRJWORD pc) { /* Main NRJ engine - just 12 lines of C within this function */ 36 while(pc != MAXADDR) { /* halt if jumped to the last word */ 37 if(mem[0]) { /* handle input if word 0 is set */ 38 nrj_in(&mem[2], &mem[mem[0]]); /* input a value to the location specified in word 0 */ 39 mem[0] = (NRJWORD) 0; /* clear word 0 */ 40 } 41 mem[mem[pc]] = (~(mem[mem[pc]] | mem[mem[pc+1]])) & MAXADDR; /* then perform the NOR operation */ 42 pc = mem[mem[pc+2]]; /* then perform the reference jump operation */ 43 if(mem[1]) { /* then handle output if word 1 is set */ 44 nrj_out(&mem[2], &mem[1]); /* output the value from the word 1 */ 45 mem[1] = (NRJWORD) 0; /* clear word 1 */ 46 } 47 } 48 } 49 50 struct termios tty_opts_backup, tty_opts_raw; /* terminal I/O helper definitions */ 51 void restore_term() {tcsetattr(0, TCSANOW, &tty_opts_backup);} 52 53 int main(int argc, char* argv[]) { /* emulator entry point: nrj program.bin */ 54 if(argc > 1) { 55 FILE *prog = fopen(argv[1], "rb"); 56 if(prog) { /* load the program and prepare the terminal */ 57 NRJWORD mem[NRJSIZE]; /* NRJ memory: word 0 - input, 1 - output, 2 - I/O context, 3 - program start */ 58 fseek(prog, 0, SEEK_END); 59 int flen = ftell(prog); 60 fseek(prog, 0, SEEK_SET); 61 fread(mem, sizeof(NRJWORD), flen/sizeof(NRJWORD), prog); 62 fclose(prog); 63 tcgetattr(0, &tty_opts_backup); 64 atexit(&restore_term); 65 cfmakeraw(&tty_opts_raw); 66 tcsetattr(0, TCSANOW, &tty_opts_raw); 67 nrj_run(mem, 3); /* now, start the engine */ 68 return 0; /* return the successful status to the outer OS */ 69 } 70 } /* otherwise bail out with an error */ 71 printf("NRJ%u: no valid program binary specified\r\n", (unsigned int) NRJWSIZE); 72 return 1; 73 }