Added assembled examples and a C99 reference implementation

This commit is contained in:
Luxferre
2025-04-23 10:05:29 +03:00
parent 6bc0a916eb
commit 29c84356f9
7 changed files with 403 additions and 0 deletions
+8
View File
@@ -254,6 +254,9 @@ repository, or even by hand (by numbering lines, resolving the labels and
replacing mnemonics with corresponding opcodes). The "Hellorld!" example only replacing mnemonics with corresponding opcodes). The "Hellorld!" example only
works on the platforms supporting I/O port 1 (character output). works on the platforms supporting I/O port 1 (character output).
If you just want to test an implementation, assembled MU8 machine code files
(in the plaintext format) are stored in the `examples/assembled` subdirectory.
Reference implementations Reference implementations
------------------------- -------------------------
@@ -266,6 +269,11 @@ Reference implementations
character input port correctly on desktop OSes but falls back to a simple character input port correctly on desktop OSes but falls back to a simple
stream file read in case the library is not found). Accepts a file name to stream file read in case the library is not found). Accepts a file name to
preload a MU8 (plain text) machine code program from the OS command line. preload a MU8 (plain text) machine code program from the OS command line.
* [ISO C99 implementation](mu808.c): supports the entire specification the
same way as the Python implementation, and also makes use of the optimized
`fma()` call that appeared in the C99 standard. Accepts a file name to preload
a MU8 machine code program from the OS command line. Compile the source with:
`cc -std=c99 -O2 -s -lm -o mu808 mu808.c`
### Assembler reference implementations ### Assembler reference implementations
+9
View File
@@ -0,0 +1,9 @@
1 5 100 0 1
2 4 2 3 0
3 9 2 1 4
4 5 1 0 5
5 7 5 4 5
6 13 1 5 5
7 7 0 3 5
8 13 0 5 5
9 3 5 5 0
+19
View File
@@ -0,0 +1,19 @@
1 5 72 0 1
2 5 101 0 2
3 5 108 0 3
4 5 108 0 4
5 5 111 0 5
6 5 114 0 6
7 5 108 0 7
8 5 100 0 8
9 5 33 0 9
10 5 10 0 10
11 5 1 0 50
12 5 1 0 10
13 5 10 0 11
14 5 12 0 12
15 6 2 10 12
16 3 12 12 1
17 8 11 50 11
18 7 50 50 10
19 1 1 11 14
+49
View File
@@ -0,0 +1,49 @@
1 5 0 0 10
2 5 0 0 11
3 5 0 0 12
4 5 0 0 13
5 5 0 0 14
6 5 0 0 15
7 5 1 0 50
8 4 1 2 0
9 6 1 1 3
10 7 0 3 3
11 6 1 2 4
12 7 0 4 4
13 6 1 2 5
14 7 0 1 5
15 7 1 50 10
16 7 2 50 11
17 7 3 50 12
18 7 4 50 13
19 7 5 50 14
20 7 50 50 15
21 6 1 3 6
22 7 4 50 6
23 1 1 6 8
24 8 15 50 15
25 6 1 15 1
26 7 0 14 1
27 6 1 11 5
28 7 0 10 5
29 8 1 5 6
30 6 1 15 3
31 7 0 12 3
32 6 1 10 4
33 7 0 10 4
34 8 3 4 3
35 9 6 3 21
36 6 1 10 1
37 7 0 21 1
38 8 11 1 1
39 9 1 15 20
40 6 1 11 2
41 7 0 11 2
42 6 1 15 5
43 7 0 13 5
44 8 5 2 2
45 6 1 3 1
46 7 0 2 1
47 12 0 1 1
48 9 6 1 22
49 3 20 22 0
+63
View File
@@ -0,0 +1,63 @@
1 5 1 0 50
2 5 10 0 52
3 5 16 2500 53
4 5 7480 0 54
5 5 3 4483 55
6 5 2900 0 56
7 5 1930 0 40
8 5 100 0 57
9 7 0 57 40
10 5 1609 0 41
11 5 7260 0 42
12 5 4444 0 30
13 5 5555 0 31
14 5 6666 0 32
15 5 7777 0 33
16 5 8888 0 34
17 5 26 6667 0
18 5 9 7300 0
19 5 4 4445 0
20 5 0 4500 0
21 3 40 42 0
22 5 0 0 2
23 1 4 42 28
24 4 1 1 0
25 6 1 1 2
26 7 0 55 2
27 6 1 42 3
28 7 54 50 3
29 8 3 2 4
30 9 3 4 1
31 13 1 1 1
32 7 0 56 1
33 8 41 1 41
34 7 53 50 41
35 6 1 41 3
36 7 0 52 3
37 8 40 3 40
38 8 42 2 42
39 1 1 42 41
40 5 0 0 42
41 1 1 40 43
42 5 0 0 40
43 8 40 52 1
44 1 1 1 21
45 3 40 42 0
46 8 41 39 1
47 1 1 1 50
48 3 34 34 0
49 1 6 0 63
50 8 41 38 1
51 1 1 1 54
52 3 33 33 0
53 1 6 0 63
54 8 41 37 1
55 1 1 1 58
56 3 32 32 0
57 1 6 0 63
58 8 41 36 1
59 1 1 1 62
60 3 31 31 0
61 1 6 0 63
62 3 30 30 0
63 0 0 0 0
+60
View File
@@ -0,0 +1,60 @@
1 5 0 0 60
2 5 1 0 61
3 5 2 0 62
4 5 3 0 63
5 5 4 0 64
6 5 5 0 65
7 5 6 0 66
8 5 7 0 67
9 5 8 0 68
10 5 9 0 69
11 5 1 0 50
12 5 4 0 11
13 5 60 0 70
14 5 80 0 71
15 5 10 0 3
16 5 9 0 1
17 15 0 1 1
18 7 70 50 1
19 5 2 0 2
20 6 2 1 2
21 8 2 3 4
22 1 0 4 16
23 2 0 3 1
24 6 0 0 0
25 6 1 11 1
26 7 71 50 1
27 5 2 0 5
28 6 2 5 1
29 8 11 50 11
30 1 1 11 16
31 5 0 1000 51
32 5 7 0 11
33 4 91 94 0
34 5 90 0 70
35 5 0 0 20
36 5 4 0 21
37 5 4 0 22
38 6 1 21 15
39 7 71 50 15
40 6 1 22 16
41 7 70 50 16
42 2 15 16 50
43 8 0 0 0
44 1 5 1 50
45 8 21 22 2
46 1 5 2 49
47 7 50 50 20
48 1 6 0 50
49 7 51 50 20
50 8 22 50 22
51 1 1 22 38
52 8 21 50 21
53 1 1 21 37
54 3 20 20 0
55 5 4 0 7
56 8 20 7 1
57 1 0 1 60
58 8 11 50 11
59 1 1 11 33
60 3 81 84 0
+195
View File
@@ -0,0 +1,195 @@
/**
* mu808: an ultralight numeric-only VM
* ANSI C99 reference implementation
* Compile with: cc -std=c99 -O2 -s -lm -o mu808 mu808.c
* See the README.md file for all documentation
* Created by Luxferre in 2025, released into public domain
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* POSIX-specific terminal stuff for unbuffered input for I/O port 2 */
#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#define NLC "\n"
#include <unistd.h>
#include <termios.h>
struct termios orig_termios;
void disable_raw_mode() {
tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
}
void enable_raw_mode() {
tcgetattr(STDIN_FILENO, &orig_termios);
atexit(disable_raw_mode);
struct termios raw = orig_termios;
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
raw.c_oflag &= ~(OPOST);
raw.c_cflag |= (CS8);
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}
#else
#define NLC "\r\n"
void disable_raw_mode() {}
void enable_raw_mode() {}
#endif
/* core memory */
#ifndef MEMLIMIT
#define MEMLIMIT 16384
#endif
#define ushort unsigned short
ushort PMEM[MEMLIMIT*4] = {0}; /* program memory */
double DMEM[MEMLIMIT] = {0.0}; /* data memory */
static unsigned int runlimit = MEMLIMIT;
static unsigned char traceflag = 0;
static unsigned int runcount = 0;
/* port output function */
void portout(ushort port, double data) {
if(port == 0) /* standard numeric output port */
printf("%f" NLC, data);
else if(port == 1) /* character output port */
fputc(((int)floor(data)) & 255, stdout);
}
/* port input function */
double portin(ushort port) {
double val = 0.0;
if(port == 0) /* standard numeric input port */
scanf("%lf", &val);
else if(port == 2) { /* character input port */
enable_raw_mode();
val = (double) (fgetc(stdin) & 255);
disable_raw_mode();
}
return val;
}
/* instruction line execution function (the main mu808 logic is defined here) */
void ilexec(ushort lno, ushort cmd, ushort x, ushort y, ushort z) {
unsigned char halt = 0, data_override = 0, bcheck;
ushort i;
double v1, v2, v3;
while(halt == 0) {
if(traceflag) printf("PC: %hu INSTR: %hu %hu %hu %hu" NLC, lno, cmd, x, y, z);
DMEM[0] = data_override = 0; /* force the value at 0 to be always 0 */
bcheck = (x < MEMLIMIT) && (y < MEMLIMIT) && (z < MEMLIMIT);
if(bcheck) {
v1 = DMEM[x]; v2 = DMEM[y]; v3 = DMEM[z]; /* prefetch the memory values */
if(cmd == 1) { /* JMP */
if((v2 == 0 && x == 0) || (v2 > 0 && x == 1) || (v2 < 0 && x == 2) \
|| (v2 >= 0 && x == 3) || (v2 <= 0 && x == 4) || (v2 != 0 && x == 5) \
|| x == 6) { halt = 0; lno = z - 1; }
else if((v2 == 0 && x == 7) || (v2 > 0 && x == 8) || (v2 < 0 && x == 9) \
|| (v2 >= 0 && x == 10) || (v2 <= 0 && x == 11) || (v2 != 0 && x == 12) \
|| x == 13) { halt = 0; lno = (int)floor(v3) - 1; }
} else if(cmd == 2) data_override = 1; /* IAT */
else if(cmd == 3) for(i=x;i<=y;i++) portout(z, DMEM[i]); /* OUT */
else if(cmd == 4) for(i=x;i<=y;i++) DMEM[i] = portin(z); /* INP */
else if(cmd == 5) DMEM[z] = (x % 10000) + (y % 10000) / 10000.0; /* SET */
else if(cmd == 6) { /* CPY */
if(x == 0) DMEM[z] = y;
else if(x == 1) DMEM[z] = v2;
else if(v2 < MEMLIMIT && v3 < MEMLIMIT)
DMEM[(int)floor(v3)] = DMEM[(int)floor(v2)];
} else if(cmd == 7) DMEM[z] = fma(v3, v2, v1); /* FMA */
else if(cmd == 8) DMEM[z] = v1 - v2; /* SUB */
else if(cmd == 9) DMEM[z] = (v2 == 0) ? 0 : (v1 / v2); /* DIV */
else if(cmd == 10) DMEM[z] = (v2 == 0) ? floor(v1) : fmod(v1, v2); /* MDF */
else if(cmd == 11) DMEM[z] = fabs(v2); /* ABS */
else if(cmd == 12) DMEM[z] = sqrt(fabs(v2)); /* SQR */
else if(cmd == 13) { /* NEL */
if(x == 0) DMEM[z] = exp(v2);
else DMEM[z] = (v2 == 0) ? 0 : log(fabs(v2));
} else if(cmd == 14) { /* TRI */
if(x == 0) DMEM[z] = sin(v2);
else if(x == 1) DMEM[z] = cos(v2);
else DMEM[z] = atan(v2);
} else if(cmd == 15) { /* RND */
v1 = floor(v1);
DMEM[z] = v1 + (rand() % (int)(floor(v2) + 1 - v1));
}
}
lno++; /* increment the program counter */
if(lno >= MEMLIMIT || lno < 1 || (runlimit > 0 && runcount > runlimit)) {
halt = 1;
if(traceflag) puts("Memory limit or runlimit hit, halting...");
} else { /* fetch the next instruction */
runcount++;
if(data_override && bcheck) {
cmd = PMEM[lno << 2];
x = ((int) floor(v1)) % MEMLIMIT;
y = ((int) floor(v2)) % MEMLIMIT;
z = ((int) floor(v3)) % MEMLIMIT;
} else {
cmd = PMEM[lno << 2];
x = PMEM[(lno << 2) + 1];
y = PMEM[(lno << 2) + 2];
z = PMEM[(lno << 2) + 3];
}
}
}
}
/* instruction line entry function */
void ilenter(int lno, ushort cmd, ushort x, ushort y, ushort z) {
if(lno > 0) { /* record the instruction in memory */
PMEM[lno << 2] = cmd;
PMEM[(lno << 2) + 1] = x;
PMEM[(lno << 2) + 2] = y;
PMEM[(lno << 2) + 3] = z;
} else if(lno == 0) { /* immediate execution */
runcount = 0;
ilexec(lno, cmd, x, y, z);
} else if(lno == -1) { /* display a range of instructions from cmd to x */
if(cmd < MEMLIMIT && x < MEMLIMIT) for(y=cmd;y<=x;y++) {
z = y << 2;
printf("@%hu:\t%hu %hu %hu %hu" NLC,
y, PMEM[z], PMEM[z+1], PMEM[z+2], PMEM[z+3]);
}
} else if(lno == -2) { /* clear a range of data or instructions from x to y */
if(cmd < MEMLIMIT && x < MEMLIMIT) for(z=x;z<=y;z++) {
if(cmd == 0)
PMEM[z<<2] = PMEM[(z<<2)+1] = PMEM[(z<<2)+2] = PMEM[(z<<2)+3] = 0;
else DMEM[z] = 0.0;
}
} else if(lno == -3) { /* tracing on/off */
if(cmd == 0) {traceflag = 0; puts("Tracing off");}
else {traceflag = 1; puts("Tracing on");}
} else if(lno == -4) {
printf("Runlimit set to %u" NLC, runlimit = cmd);
} else if(lno == -5) {puts("Bye!"); exit(0);}
}
/* entry point to the VM REPL */
void main(int argc, char* argv[]) {
srand(time(NULL));
printf("mu808 v1 by Luxferre" NLC "PROGMEM: %u steps" NLC "DATAMEM: %u floats" NLC,
MEMLIMIT, MEMLIMIT);
int lno; /* line number can be negative at this point */
ushort cmd, x, y, z; /* commands and their parameters */
if(argc > 1) { /* preload the file from a command line parameter */
FILE *fd = fopen(argv[1], "r");
if(fd != NULL) { /* opened successfully */
while(!feof(fd)) {
fscanf(fd, "%d %hu %hu %hu %hu", &lno, &cmd, &x, &y, &z); /* read the five numbers */
ilenter(lno, cmd, x, y, z); /* run the entry routine */
}
fclose(fd);
} else puts("Warning: no file could be preloaded!");
}
while(1) { /* main interactive loop */
printf("> ");
lno = cmd = x = y = z = 0;
scanf("%d %hu %hu %hu %hu", &lno, &cmd, &x, &y, &z); /* read the five numbers */
while(getchar() != '\n'); /* ignore the rest of the line */
ilenter(lno, cmd, x, y, z); /* run the entry routine */
}
}