diff options
Diffstat (limited to 'src/micro/port_win.c')
| -rw-r--r-- | src/micro/port_win.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/src/micro/port_win.c b/src/micro/port_win.c new file mode 100644 index 0000000..8e3ef74 --- /dev/null +++ b/src/micro/port_win.c @@ -0,0 +1,268 @@ +/* Windows port for the microcore: stdin/stdout a byte at a time, the syscalls, + diagnostics on stderr. same behaviour as io_win.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> +#include <io.h> +#include <process.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "micro_port.h" +#include "bops.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 + +/* 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 = _fgetc_nolock(stdin); + return c == EOF ? -1 : c; +} + +int micro_eof(void) +{ + int c = _fgetc_nolock(stdin); + if (c == EOF) return 1; + _ungetc_nolock(c, stdin); + return 0; +} + +void micro_putc(int c) { _fputc_nolock(c & 255, stdout); } + +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>. */ +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 = _environ; + int n = 0; + 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; + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); + 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(); +} |
