nrj-oisc

NOR and Reference Jump OISC platform
git clone git://git.luxferre.top/nrj-oisc.git
Log | Files | Refs | README

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 }