Browse code

Add initial Universal Machine emulator

Robert Cranston authored on 19/04/2026 22:10:36
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,65 @@
1
+#include <array>
2
+#include <cstdint>
3
+#include <cstdio>
4
+#include <cstdlib>
5
+#include <fstream>
6
+#include <iostream>
7
+#include <vector>
8
+
9
+void um(std::istream & scroll, std::istream & i, std::ostream & o)
10
+{
11
+    std::unitbuf(o);
12
+    using Chr   = std::uint8_t;
13
+    using Plt   = std::uint32_t;
14
+    auto  reg   = std::array<Plt, 8>();
15
+    auto  arr   = std::vector<std::vector<Plt>>(1);
16
+    auto  fng   = Plt(0);
17
+    auto  hlt   = false;
18
+    auto  alloc = [&](Plt c) { arr.emplace_back(c); return(Plt)arr.size()-1; };
19
+    auto  aband = [&](Plt c) { arr[c] = decltype(arr)::value_type();         };
20
+    #define PACK(IND) ((Plt)(Chr)ch[IND] << 8*(3-IND))
21
+    for (char ch[4]; scroll.read(ch, 4);)
22
+        arr[0].push_back(PACK(0) | PACK(1) | PACK(2) | PACK(3));
23
+    #undef PACK
24
+    while (!hlt)
25
+    {
26
+        #define UNPACK(POS, SIZ) ((plt >> POS) & ((Plt(1) << SIZ) - 1))
27
+        auto   plt = arr[0][fng++];
28
+        auto   num =     UNPACK(28,  4);
29
+        auto   val =     UNPACK( 0, 25);
30
+        auto & a   = reg[UNPACK( 6,  3)];
31
+        auto & b   = reg[UNPACK( 3,  3)];
32
+        auto & c   = reg[UNPACK( 0,  3)];
33
+        auto & d   = reg[UNPACK(25,  3)];
34
+        #undef UNPACK
35
+        switch (num)
36
+        {
37
+            case  0: a         = c ? b : a;       break; // CMOVE
38
+            case  1: a         = arr[b][c];       break; // LOAD
39
+            case  2: arr[a][b] = c;               break; // STOR
40
+            case  3: a         =   b + c;         break; // ADD
41
+            case  4: a         =   b * c;         break; // MUL
42
+            case  5: a         =   b / c;         break; // DIV
43
+            case  6: a         = ~(b & c);        break; // NAND
44
+            case  7: hlt       = true;            break; // HALT
45
+            case  8: b         = alloc(c);        break; // ALLOC
46
+            case  9:             aband(c);        break; // ABAND
47
+            case 10:             o.put(c);        break; // PUT
48
+            case 11: c         = i.get();         break; // GET
49
+            case 12: arr[0]    = arr[b]; fng = c; break; // EXEC
50
+            case 13: d         = val;             break; // VALUE
51
+        }
52
+    }
53
+}
54
+
55
+int main(int argc, char * argv[])
56
+{
57
+    if (argc != 2)
58
+        return std::fputs("Usage: um <scroll>\n", stderr), EXIT_FAILURE;
59
+    auto scroll = std::ifstream(argv[1], std::ios::binary);
60
+    if (scroll.fail())
61
+        return std::perror("Failed to read scroll"), EXIT_FAILURE;
62
+    if (scroll.peek(), scroll.eof())
63
+        return std::fputs("Empty scroll\n", stderr), EXIT_FAILURE;
64
+    um(scroll, std::cin, std::cout);
65
+}