Files
nrj-oisc/nrj.c
T

74 lines
2.8 KiB
C
Raw Normal View History

/* NRJ (NOR and Reference Jump) OISC ANSI C emulator
2022-08-22 19:55:24 +03:00
* Created by Luxferre, 2022, public domain
* Build with: cc -Os -std=c89 -o nrj nrj.c */
2022-08-19 21:55:12 +03:00
#include <stdlib.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
2022-08-23 09:30:47 +03:00
#ifndef NRJWORD /* we emulate NRJ16 by default but this can be overridden */
2022-08-19 21:55:12 +03:00
#define NRJWORD unsigned short
#endif
2022-08-22 20:16:44 +03:00
#define NRJWSIZE (sizeof(NRJWORD) << 3)
2022-08-22 18:36:26 +03:00
#define NRJSIZE (1 << NRJWSIZE)
2022-08-22 08:20:51 +03:00
#define MAXADDR ((NRJWORD) (NRJSIZE - 1))
2022-08-19 21:55:12 +03:00
2022-08-22 20:27:21 +03:00
int kbhit() { /* our best attempt to detect a keypress on a POSIX system */
2022-08-19 21:55:12 +03:00
struct timeval tv = { 0L, 0L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
return select(1, &fds, NULL, NULL, &tv) > 0;
}
2022-08-22 19:55:24 +03:00
void nrj_in(NRJWORD *ctxid, NRJWORD *val) { /* context-dependent input handler */
2022-08-22 18:36:26 +03:00
unsigned char c;
2022-08-23 09:30:47 +03:00
if(*ctxid == (NRJWORD) 0) /* for now, only emulate standard context id */
*val = (NRJWORD) ((kbhit() && read(0, &c, 1) > -1) ? c : 0);
2022-08-19 21:55:12 +03:00
}
2022-08-22 19:55:24 +03:00
void nrj_out(NRJWORD *ctxid, NRJWORD *val) { /* context-dependent output handler */
2022-08-19 21:55:12 +03:00
if(*ctxid == (NRJWORD) 0) /* for now, only emulate standard context id */
putchar((unsigned char) *val);
}
2022-08-22 19:55:24 +03:00
void nrj_run(NRJWORD *mem, NRJWORD pc) { /* Main NRJ engine - just 12 lines of C within this function */
while(pc != MAXADDR) { /* halt if jumped to the last word */
2022-08-23 09:30:47 +03:00
if(mem[0]) { /* handle input if word 0 is set */
nrj_in(&mem[2], &mem[mem[0]]); /* input a value to the location specified in word 0 */
mem[0] = (NRJWORD) 0; /* clear word 0 */
2022-08-22 19:55:24 +03:00
}
mem[mem[pc]] = (~(mem[mem[pc]] | mem[mem[pc+1]])) & MAXADDR; /* then perform the NOR operation */
pc = mem[mem[pc+2]]; /* then perform the reference jump operation */
2022-08-23 09:30:47 +03:00
if(mem[1]) { /* then handle output if word 1 is set */
2022-09-02 19:57:59 +03:00
nrj_out(&mem[2], &mem[1]); /* output the value from the word 1 */
2022-08-23 09:30:47 +03:00
mem[1] = (NRJWORD) 0; /* clear word 1 */
2022-08-19 21:55:12 +03:00
}
}
}
struct termios tty_opts_backup, tty_opts_raw; /* terminal I/O helper definitions */
2022-08-23 09:30:47 +03:00
void restore_term() {tcsetattr(0, TCSANOW, &tty_opts_backup);}
2022-08-22 19:55:24 +03:00
2022-08-23 09:30:47 +03:00
int main(int argc, char* argv[]) { /* emulator entry point: nrj program.bin */
2022-08-22 18:36:26 +03:00
if(argc > 1) {
FILE *prog = fopen(argv[1], "rb");
2022-08-23 09:30:47 +03:00
if(prog) { /* load the program and prepare the terminal */
NRJWORD mem[NRJSIZE]; /* NRJ memory: word 0 - input, 1 - output, 2 - I/O context, 3 - program start */
2022-08-22 18:36:26 +03:00
fseek(prog, 0, SEEK_END);
int flen = ftell(prog);
fseek(prog, 0, SEEK_SET);
2022-09-02 19:57:59 +03:00
fread(mem, sizeof(NRJWORD), flen/sizeof(NRJWORD), prog);
2022-08-22 18:36:26 +03:00
fclose(prog);
2022-08-23 09:30:47 +03:00
tcgetattr(0, &tty_opts_backup);
2022-08-22 18:36:26 +03:00
atexit(&restore_term);
cfmakeraw(&tty_opts_raw);
2022-08-23 09:30:47 +03:00
tcsetattr(0, TCSANOW, &tty_opts_raw);
nrj_run(mem, 3); /* now, start the engine */
return 0; /* return the successful status to the outer OS */
2022-08-22 18:36:26 +03:00
}
} /* otherwise bail out with an error */
printf("NRJ%u: no valid program binary specified\r\n", (unsigned int) NRJWSIZE);
return 1;
2022-08-19 21:55:12 +03:00
}