Muxleq

From Esolang
Jump to navigation Jump to search

MUXLEQ is an experiment in adding a single instruction to Subleq in order to greatly speed up the virtual machine by howerj. Most programs that will run under Subleq will run under MUXLEQ. It adds an instruction that also takes three operands and performs a multiplexing operation on them (hence the name). This allows greatly sped up loading, storing, and naturally bitwise operations. This is not the only experiment in adding an instruction to Subleq (or other OISC variants), for example the paper Subleq(-): An Area-Efficient Two-Instruction-Set Computer describes a two instruction variant that instead adds a bit-reversal function that greatly speeds up some code and should be trivial to implement in hardware given an already working Subleq implementation.

MUXLEQ is capable of running SUBLEQ eFORTH a full blown programming language, along with a modified variant that runs faster on the MUXLEQ machine. The modified version of SUBLEQ eForth is available in the MUXLEQ repo

The Pseudo-code for the machine is:

while pc >= 0:
	a = m[pc + 0]
	b = m[pc + 1]
	c = m[pc + 2]
	pc = pc + 3
	if a == -1:
		m[b] = get_byte()
	else if b == -1:
		put_byte(m[a])
	else if c != -1 and c < 0:
       c = abs(c)
		m[b] = (m[a] & ~m[c]) | (m[b] & m[c])
	else:
		r = m[b] - m[a]
		if r <= 0:
			pc = c
		m[b] = r

And a 16-bit implementation in C:

#include <stdint.h>
#include <stdio.h>

typedef uint16_t u16;
static const u16 n = -1;
static u16 m[1<<16], prog = 0, pc = 0;

int main(int argc, char **argv) {
	if (setvbuf(stdout, NULL, _IONBF, 0) < 0)
		return 1;
	for (long i = 1, d = 0; i < argc; i++) {
		FILE *f = fopen(argv[i], "rb");
		if (!f)
			return 2;
		while (fscanf(f, "%ld,", &d) > 0)
			m[prog++] = d;
		if (fclose(f) < 0)
			return 3;
	}
	for (pc = 0; pc < 32768;) {
		u16 a = m[pc++], b = m[pc++], c = m[pc++];
		if (a == n) {
			m[b] = getchar();
		} else if (b == n) {
			if (putchar(m[a]) < 0)
				return 3;
		} else if (c & 0x8000 && c != n) {
			u16 mc = m[c & 0x7FFF];
			m[b] = (m[a] & ~mc) | (m[b] & mc);
		} else {
			u16 r = m[b] - m[a];
			if (r == 0 || r & 32768)
				pc = c;
			m[b] = r;
		}
	}
	return 0;
}

That does not rely on any signed arithmetic and should be very portable.

With a multiplexing operation it becomes trivial to implement the bitwise operators AND, OR, XOR, Invert and even loading and storing.