#include typedef signed char Sint8; typedef unsigned char Uint8; typedef unsigned short Uint16; typedef struct { Uint8 ptr[2]; Uint8 stk[2][0x100]; } Uxn; static Uxn u; static Uint16 console_vector; static Uint8 ram[0x10000]; static Uint8 dev[0x100]; /* @|IO */ static Uint8 dei(Uint8 port) { return dev[port]; } static void deo(Uint8 port, Uint8 val) { dev[port] = val; switch(port) { case 0x11: console_vector = dev[0x10] << 8 | val; return; case 0x18: fputc(val, stdout); return; case 0x19: fputc(val, stderr); return; } } /* @|Primitives */ /* clang-format off */ #define Get1(o) u.stk[r][(Uint8)(u.ptr[r] - (o))] #define Get2(o) (Get1(o) << 8 | Get1(o - 1)) #define Getx(off8,off16) d ? Get2(off16) : Get1(off8) #define Put1(s,v) u.stk[s][u.ptr[s]++] = v #define Putx(s,v) { const int t = v; if(d) Put1(s, t >> 8); Put1(s, t); } /* clang-format on */ /* @|Core */ static unsigned int uxn_eval(Uint16 start_pc) { Uint16 pc = start_pc; for(;;) { const int instr = ram[pc++]; const int opc = instr & 0x1f; if(opc) { const int k = instr >> 7; const int d = (instr >> 5) & 1; const int r = (instr >> 6) & 1; switch(opc) { case 0x01: { const int x = Getx(1, 2); if(!k) u.ptr[r] -= d + 1; Putx(r, x + 1); } break; case 0x02: { if(!k) u.ptr[r] -= d + 1; } break; case 0x03: { const int x = Getx(1, 2); if(!k) u.ptr[r] -= 2 << d; Putx(r, x); } break; case 0x04: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Putx(r, x); Putx(r, y); } break; case 0x05: { const int x = Getx(1, 2); const int y = Getx(2, 4); const int z = Getx(3, 6); if(!k) u.ptr[r] -= 3 << d; Putx(r, y); Putx(r, x); Putx(r, z); } break; case 0x06: { const int x = Getx(1, 2); if(!k) u.ptr[r] -= d + 1; Putx(r, x); Putx(r, x); } break; case 0x07: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Putx(r, y); Putx(r, x); Putx(r, y); } break; case 0x08: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Put1(r, x == y); } break; case 0x09: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Put1(r, y != x); } break; case 0x0a: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Put1(r, y > x); } break; case 0x0b: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Put1(r, y < x); } break; case 0x0c: { const int x = Getx(1, 2); if(!k) u.ptr[r] -= d + 1; pc = d ? x : pc + (Sint8)x; } break; case 0x0d: { const int x = Getx(1, 2); const int y = Get1(d + 2); if(!k) u.ptr[r] -= d + 2; if(y) pc = d ? x : pc + (Sint8)x; } break; case 0x0e: { const int x = Getx(1, 2); if(!k) u.ptr[r] -= d + 1; Put1(!r, pc >> 8), Put1(!r, pc); pc = d ? x : pc + (Sint8)x; } break; case 0x0f: { const int x = Getx(1, 2); if(!k) u.ptr[r] -= d + 1; Putx(!r, x); } break; case 0x10: { const int x = Get1(1); if(!k) u.ptr[r] -= 1; Put1(r, ram[x]); if(d) Put1(r, ram[(Uint8)(x + 1)]); } break; case 0x11: { const int x = Get1(1); const int y = Getx(2, 3); if(!k) u.ptr[r] -= d + 2; if(d) ram[x] = y >> 8, ram[(Uint8)(x + 1)] = y; else ram[x] = y; } break; case 0x12: { const int x = Get1(1); const int y = pc + (Sint8)x; if(!k) u.ptr[r] -= 1; Put1(r, ram[y]); if(d) Put1(r, ram[(Uint16)(y + 1)]); } break; case 0x13: { const int x = Get1(1); const int y = Getx(2, 3); const int z = pc + (Sint8)x; if(!k) u.ptr[r] -= d + 2; if(d) ram[z] = y >> 8, ram[(Uint16)(z + 1)] = y; else ram[z] = y; } break; case 0x14: { const int x = Get2(2); if(!k) u.ptr[r] -= 2; Put1(r, ram[x]); if(d) Put1(r, ram[(Uint16)(x + 1)]); } break; case 0x15: { const int x = Get2(2); const int y = Getx(3, 4); if(!k) u.ptr[r] -= d + 3; ram[x] = d ? y >> 8 : y; if(d) ram[(Uint16)(x + 1)] = y; } break; case 0x16: { const int x = Get1(1); if(!k) u.ptr[r] -= 1; Put1(r, dei(x)); if(d) Put1(r, dei(x + 1)); } break; case 0x17: { const int x = Get1(1); const int y = Getx(2, 3); if(!k) u.ptr[r] -= d + 2; if(d) deo(x, y >> 8); deo(d ? x + 1 : x, y); } break; case 0x18: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Putx(r, y + x); } break; case 0x19: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Putx(r, y - x); } break; case 0x1a: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Putx(r, y * x); } break; case 0x1b: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Putx(r, x ? y / x : 0); } break; case 0x1c: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Putx(r, y & x); } break; case 0x1d: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Putx(r, y | x); } break; case 0x1e: { const int x = Getx(1, 2); const int y = Getx(2, 4); if(!k) u.ptr[r] -= 2 << d; Putx(r, y ^ x); } break; case 0x1f: { const int x = Get1(1); const int y = Getx(2, 3); if(!k) u.ptr[r] -= d + 2; Putx(r, (y >> (x & 0x0f)) << (x >> 4)); } break; } } else switch(instr) { case 0x00: return 1; case 0x20: { const int a = ram[pc] << 8 | ram[pc + 1]; const int b = u.stk[0][--u.ptr[0]]; pc += 2; if(b) pc += a; } break; case 0x40: { const int a = ram[pc] << 8 | ram[pc + 1]; pc += 2 + a; } break; case 0x60: { const int a = ram[pc] << 8 | ram[pc + 1]; pc += 2; Put1(1, (pc >> 8)), Put1(1, pc); pc += a; } break; case 0x80: Put1(0, ram[pc++]); break; case 0xa0: Put1(0, ram[pc++]), Put1(0, ram[pc++]); break; case 0xc0: Put1(1, ram[pc++]); break; case 0xe0: Put1(1, ram[pc++]), Put1(1, ram[pc++]); break; } } } static void console_input(int c, unsigned int type) { dev[0x12] = (Uint8)c; dev[0x17] = (Uint8)type; if(console_vector) uxn_eval(console_vector); } int main(int argc, char **argv) { FILE *f; if(argc < 2) return 1; else if(!(f = fopen(argv[1], "rb"))) return 1; if(!fread(&ram[0x100], 1, 0xff00, f)) { fclose(f); return 1; } dev[0x17] = argc > 2; if(uxn_eval(0x100) && console_vector) { int i = 2; for(; i < argc; i++) { char c, *p = argv[i]; while(!dev[0x0f] && (c = *p++)) console_input(c, 2); console_input('\n', 3 + (i == argc - 1)); } while(!dev[0x0f]) { char c = fgetc(stdin); if(feof(stdin)) break; console_input(c, 1); } console_input('\n', 4); } return dev[0x0f] & 0x7f; }