/* TRASHCANARCHIST'S SHITVM(tm) - CC0 LICENSE IT'S NOT MY FAULT IF THIS BREAKS YOUR SHIT */ #include #include #include #include #define OPSIZE 4 uint16_t printchar(char c) { printf("%c", c); return c; } uint16_t (*ports[16])(uint16_t) = {&printchar}; int main(int argc, char **argv) { uint8_t mem[65537]; uint16_t r[256]; uint16_t pc = 0x8000; uint16_t top = 15; uint16_t *stack = malloc(sizeof(uint16_t) * (top + 1)); uint16_t sp = 0; uint8_t port = 0; const char *bin_name; FILE *bin; size_t binsize; bool running = true; mem[65536] = '\0'; if (argc == 1) bin_name = "hello.c16"; else if (argc == 2) bin_name = argv[1]; bin = fopen(bin_name, "r"); if (bin == NULL) { fprintf(stderr, "Error opening \"%s\"\n", bin_name); exit(EXIT_FAILURE); } binsize = fread(mem + 0x8000, sizeof(uint8_t), 65536, bin); if (ferror(bin) != 0) { fprintf(stderr, "Error loading \"%s\" (ferror %d)\n", bin_name, ferror(bin)); exit(EXIT_FAILURE); } fclose(bin); while (running) { uint8_t advance = 1; uint8_t o = mem[pc]; uint8_t x = mem[pc + 1]; uint8_t y = mem[pc + 2]; uint8_t z = mem[pc + 3]; uint16_t m = x << 8 | y; uint16_t n = y << 8 | z; uint32_t opcode = o << 24 | x << 16 | y << 8 | z; switch (o) { case 0x00: // flow switch (x) { case 0x00: // SPOP r if (sp == 0) running = false; else { r[y] = stack[sp]; sp -= 1; } break; case 0x01: // SPSH sp += 1; if (sp > top) { top += 1; stack = realloc(stack, sizeof(uint16_t) * (top + 1)); } stack[sp] = pc + OPSIZE; break; case 0x02: // JMP n pc = n; advance = 0; break; case 0x03: // JMP r pc = r[y]; advance = 0; break; case 0x04: // SZ r if (r[y] == 0) advance++; break; case 0x05: // SNZ r if (r[y] != 0) advance++; break; case 0x06: // SEQ r r if (r[y] == r[z]) advance++; break; case 0x07: // SNEQ r r if (r[y] != r[z]) advance++; break; /* ____ _,.-'`_ o `;__, _.-'` '---' ' no steppy on sneq */ } break; // ASSIGNMENT case 0x05: // SET @n r mem[m] = r[z]; break; case 0x07: // SET @n @r mem[m] = mem[r[z]]; break; case 0x08: // SET r n reg[x] = n; break; case 0x09: // SET @r n mem[r[x]] = n; break; case 0x0A: // SET r @n r = mem[n]; break; case 0x0B: // SET @r @n mem[r[x]] = mem[n]; break; case 0x0C: // SET r r r[x] = r[y]; break; case 0x0D: // SET @r r mem[r[x]] = r[y]; break; case 0x0E: // SET r @r r[x] = mem[r[y]]; break; case 0x0F: // SET @r @r mem[r[x]] = mem[r[y]]; break; case 0x10: // ops switch (x) { case 0x00: // OR r r r[y] |= r[z]; break; case 0x01: // AND r r r[y] &= r[z]; break; case 0x02: // XOR r r r[y] ^= r[z]; break; case 0x03: // ADD r r if (r[y] & r[z] >> 7) r[0xFF] = 1; r[y] += r[z]; break; case 0x04: // SUB r r if (r[y] > r[z]) r[0xFF] = 1; r[y] -= r[z]; break; case 0x05: // SHR r r r[0xFF] = r[y] & ((z << 1) - 1); r[y] >>= r[z]; break; case 0x06: // SHL r r r[0xFF] = r[y] >> (32 - r[z]); r[y] <<= r[z]; break; } break; case 0x18: // SWAP @n r mem[m] ^= r[z]; r[z] ^= mem[m]; mem[m] ^= r[z]; break; case 0x19: // SWAP @n @r mem[m] ^= mem[r[z]]; mem[r[z]] ^= mem[m]; mem[m] ^= mem[r[z]]; break; case 0x1A: // SWAP r @n r[y] ^= mem[n]; mem[n] ^= r[y]; r[y] ^= mem[n]; break; case 0x1B: // SWAP @r @n mem[r[x]] ^= mem[n]; mem[n] ^= mem[r[x]]; mem[r[x]] ^= mem[n]; break; case 0x1C: // SWAP r r r[x] ^= r[y]; r[y] ^= r[x]; r[x] ^= r[y]; break; case 0x1D: // SWAP @r r mem[r[x]] ^= r[y]; r[y] ^= mem[r[x]]; mem[r[x]] ^= r[y]; break; case 0x1E: // SWAP r @r r[x] ^= mem[r[y]]; mem[r[y]] ^= r[x]; r[x] ^= mem[r[y]]; break; case 0x1F: // SWAP @r @r mem[r[x]] ^= mem[r[y]]; mem[r[y]] ^= mem[r[x]]; mem[r[x]] ^= mem[r[y]]; break; case 0x20: // RAND r r[x] = rand(); break; case 0x21: // OUT r r[x] = (*ports[port])(r[x]); break; case 0x22: // OUT r r r[x] = (*ports[r[y]])(r[x]); break; case 0x23: // PORT r port = r[x]; break; } pc += advance * OPSIZE; } }