aboutsummaryrefslogtreecommitdiff
path: root/src/micro/port_linux.c
diff options
context:
space:
mode:
authorGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
committerGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
commitecc350ca5c2eb50be8309c5f14f8bf0d87db9a02 (patch)
tree70e0af76a1b13affff7c6cc8aac7b3e6ef960478 /src/micro/port_linux.c
a
Diffstat (limited to 'src/micro/port_linux.c')
-rw-r--r--src/micro/port_linux.c284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/micro/port_linux.c b/src/micro/port_linux.c
new file mode 100644
index 0000000..e6c8847
--- /dev/null
+++ b/src/micro/port_linux.c
@@ -0,0 +1,284 @@
+/* Linux port: stdin/stdout a byte at a time, the syscalls, diagnostics
+ on stderr. same behaviour as io_linux.c plus core.c's hostcall.
+ 1..6 are files, getenv and unix time. 7 exits the process, 8 is a
+ counter, 9 reports the machine size. */
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef _WIN32
+#include <io.h>
+#include <process.h>
+#ifndef O_BINARY
+#define O_BINARY _O_BINARY
+#endif
+#if defined(_MSC_VER)
+#define open _open
+#define close _close
+#define read _read
+#define write _write
+#endif
+#else
+#include <unistd.h>
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "micro_port.h"
+#include "bops.h"
+
+/* the machine's memory: a block that grows by realloc, zero in the new part. the
+ base can move on a grow, which micro.c takes into account (it re-reads m). */
+static Cell *lmem;
+static UCell lcap;
+
+Cell *micro_mem_alloc(UCell words)
+{
+ Cell *n;
+ if (words <= lcap && lmem) return lmem;
+ if (words > ((UCell)-1) / sizeof(Cell)) return NULL;
+ n = realloc(lmem, words * sizeof(Cell));
+ if (!n) return NULL;
+ memset(n + lcap, 0, (words - lcap) * sizeof(Cell));
+ lmem = n;
+ lcap = words;
+ return n;
+}
+
+int micro_getc(void)
+{
+ int c = getchar();
+ return c == EOF ? -1 : c;
+}
+
+int micro_eof(void)
+{
+ int c = getchar();
+ if (c == EOF) return 1;
+ ungetc(c, stdin);
+ return 0;
+}
+
+void micro_putc(int c) { putchar(c & 255); }
+
+void micro_msg(const char *s) { fputs(s, stderr); }
+
+static int zcstr(Cell *mem, Cell addr, char *dst, int max)
+{
+ int i = 0, c;
+ if (max < 1) return -1;
+ if ((UCell)addr >= (UCell)micro_mem_words()) { dst[0] = 0; return -1; }
+ while (i < max - 1 && (UCell)(addr + i) < (UCell)micro_mem_words()) {
+ c = (int)mem[addr + i];
+ if (!c) break;
+ dst[i++] = (char)c;
+ }
+ dst[i] = 0;
+ return i;
+}
+
+static int inmem(Cell a) { return (UCell)a < (UCell)micro_mem_words(); }
+
+/* the command line and the environment, kept for ops 21 to 24: the same
+ contract as src/core/core.c. a program read from stdin has no file name, so
+ argv[0] is <eval>. */
+#ifndef _WIN32
+extern char **environ;
+#endif
+static int zy_argc;
+static char **zy_argv;
+static int zy_envc;
+static char **zy_envp;
+
+static void zy_args(int argc, char **argv)
+{
+ char **e;
+ int n = 0;
+#ifdef _WIN32
+ e = _environ;
+#else
+ e = environ;
+#endif
+ while (e && e[n]) n++;
+ zy_envp = e; zy_envc = n;
+ zy_argv = argv;
+ zy_argc = argc > 0 ? argc : 1;
+}
+
+/* copy entry a of a char ** into vm words, one character per word, terminated
+ like SYS_GETENV. a zero buffer asks for the length only. lead, when given,
+ replaces entry zero. */
+static Cell vecstr(Cell *mem, char **v, int count, Cell a, Cell b, Cell c, const char *lead)
+{
+ char *e;
+ int i = 0;
+ if (a < 0 || a >= (Cell)count) return -1;
+ e = (a == 0 && lead) ? (char *)lead : v[a];
+ if (!e) return -1;
+ if (!b) { while (e[i]) i++; return i; }
+ if (c < 1 || !inmem(b)) return -1;
+ while (e[i] && i < c - 1 && inmem(b + i)) { mem[b + i] = (unsigned char)e[i]; i++; }
+ if (inmem(b + i)) mem[b + i] = 0;
+ return i;
+}
+
+static Cell host_rand(void)
+{
+ static uint64_t s;
+ if (!s) s = (uint64_t)time(0) ^ 0x9E3779B97F4A7C15ull;
+ if (!s) s = 0x9E3779B97F4A7C15ull;
+ s ^= s << 13; s ^= s >> 7; s ^= s << 17;
+ if ((Cell)s == -1) s ^= 0x100;
+ return (Cell)s;
+}
+
+static int memory_words(const char *name, UCell fallback, UCell *words)
+{
+ const char *s = getenv(name);
+ char *end;
+ unsigned long long value;
+ if (!s) { *words = fallback; return 1; }
+ errno = 0;
+ value = strtoull(s, &end, 10);
+ if (errno || end == s || *end || !value || value > 0x7fffffffULL) return 0;
+ *words = (UCell)value;
+ return 1;
+}
+
+Cell micro_syscall(Cell *mem, Cell op, Cell a, Cell b, Cell c)
+{
+ char path[1024], tmp[512];
+ int n, i, got;
+ switch (op) {
+ case 1:
+ if (zcstr(mem, a, path, 1024) < 0) return -1;
+ if (b == 1) return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+ return open(path, O_RDONLY | O_BINARY);
+ case 2:
+ return close((int)a);
+ case 3:
+ if (c < 0 || !inmem(b)) return -1;
+ n = 0;
+ while (n < c) {
+ i = (int)(c - n);
+ if (i > 512) i = 512;
+ if (!inmem(b + n)) break;
+ if (!inmem(b + n + i - 1)) i = (int)(micro_mem_words() - (b + n));
+ if (i <= 0) break;
+ got = (int)read((int)a, tmp, (size_t)i);
+ if (got <= 0) break;
+ for (i = 0; i < got; i++) mem[b + n + i] = (unsigned char)tmp[i];
+ n += got;
+ }
+ return n;
+ case 4:
+ if (c < 0 || !inmem(b)) return -1;
+ n = 0;
+ while (n < c) {
+ i = (int)(c - n);
+ if (i > 512) i = 512;
+ if (!inmem(b + n)) break;
+ if (!inmem(b + n + i - 1)) i = (int)(micro_mem_words() - (b + n));
+ if (i <= 0) break;
+ for (got = 0; got < i; got++) tmp[got] = (char)mem[b + n + got];
+ got = (int)write((int)a, tmp, (size_t)i);
+ if (got <= 0) break;
+ n += got;
+ }
+ return n;
+ case 5: {
+ char *e;
+ if (zcstr(mem, a, path, 1024) < 0) return -1;
+ e = getenv(path);
+ if (!e) return -1;
+ if (c < 1 || !inmem(b)) return -1;
+ i = 0;
+ while (e[i] && i < c - 1 && inmem(b + i)) { mem[b + i] = (unsigned char)e[i]; i++; }
+ if (inmem(b + i)) mem[b + i] = 0;
+ return i;
+ }
+ case 6:
+ return (Cell)time(0);
+ case 7:
+ exit((int)a);
+ case 8:
+ return host_rand();
+ case 9:
+ if (a == 0) return micro_mem_words();
+ if (a == 1) return HEAP_LO;
+ if (a == 2) return HEAP_HI;
+ if (a == 3) return (Cell)micro_mem_words() * 8;
+ return -1;
+ case 10:
+ if (bop_cstr(mem, a, path, 1024, micro_mem_words()) < 0) return -1;
+ if (b == 1) return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+ return open(path, O_RDONLY | O_BINARY);
+ case 11:
+ if (c < 0 || (c > 0 && !bop_ok(b, 1, micro_mem_words()))) return -1;
+ n = 0;
+ while (n < c) {
+ i = (int)(c - n);
+ if (i > 512) i = 512;
+ i = bop_span(b + n, i, micro_mem_words());
+ if (i <= 0) break;
+ got = (int)read((int)a, tmp, (size_t)i);
+ if (got <= 0) break;
+ for (i = 0; i < got; i++) bop_put1(mem, b + n + i, (unsigned char)tmp[i]);
+ n += got;
+ }
+ return n;
+ case 12:
+ if (c < 0 || (c > 0 && !bop_ok(b, 1, micro_mem_words()))) return -1;
+ n = 0;
+ while (n < c) {
+ i = (int)(c - n);
+ if (i > 512) i = 512;
+ i = bop_span(b + n, i, micro_mem_words());
+ if (i <= 0) break;
+ for (got = 0; got < i; got++) tmp[got] = (char)bop_load(mem, b + n + got, 1);
+ got = (int)write((int)a, tmp, (size_t)i);
+ if (got <= 0) break;
+ n += got;
+ }
+ return n;
+ case 13: {
+ char *e;
+ if (bop_cstr(mem, a, path, 1024, micro_mem_words()) < 0) return -1;
+ e = getenv(path);
+ if (!e) return -1;
+ if (c < 1 || !bop_ok(b, 1, micro_mem_words())) return -1;
+ i = 0;
+ while (e[i] && i < c - 1 && bop_ok(b + i, 1, micro_mem_words())) { bop_put1(mem, b + i, (unsigned char)e[i]); i++; }
+ if (bop_ok(b + i, 1, micro_mem_words())) bop_put1(mem, b + i, 0);
+ return i;
+ }
+ case 21:
+ return (Cell)zy_argc;
+ case 22:
+ return vecstr(mem, zy_argv, zy_argc, a, b, c, "<eval>");
+ case 23:
+ return (Cell)zy_envc;
+ case 24:
+ return vecstr(mem, zy_envp, zy_envc, a, b, c, 0);
+ default:
+ return -1;
+ }
+}
+
+int main(int argc, char **argv) {
+ UCell initial, limit;
+#ifdef _WIN32
+ _setmode(_fileno(stdin), _O_BINARY);
+ _setmode(_fileno(stdout), _O_BINARY);
+#endif
+ zy_args(argc, argv);
+ if (!memory_words("TINYVM_MEMORY_WORDS", MICRO_MW_INIT, &initial) ||
+ !memory_words("TINYVM_MAX_MEMORY_WORDS", MICRO_MW_LIMIT, &limit) ||
+ initial > limit || !micro_memory_config(initial, limit)) {
+ fputs("micro: invalid memory configuration\n", stderr);
+ return 1;
+ }
+ return micro_run();
+}