diff options
| author | 2026-10-12 08:46:23 +0330 | |
|---|---|---|
| committer | 2026-10-12 08:46:23 +0330 | |
| commit | ecc350ca5c2eb50be8309c5f14f8bf0d87db9a02 (patch) | |
| tree | 70e0af76a1b13affff7c6cc8aac7b3e6ef960478 /src/micro/micro.c | |
a
Diffstat (limited to 'src/micro/micro.c')
| -rw-r--r-- | src/micro/micro.c | 643 |
1 files changed, 643 insertions, 0 deletions
diff --git a/src/micro/micro.c b/src/micro/micro.c new file mode 100644 index 0000000..4542bd8 --- /dev/null +++ b/src/micro/micro.c @@ -0,0 +1,643 @@ +/* portable microcore. the base machine from core.c — memory, the two stacks, + the 22 opcodes, call/ret, and the genome — without the jit, llvm, o3, or + the enhancement optimizer. + + `/` `%` `<<` and every other custom opcode are installed at runtime + (opcode 21). the genome's own idiv, imod, ishl, lfa and outside arrive + that way, and so do programs that declare enhance. this file lowers a + recipe or a straight-line vm body into a flat list of micro-ops and runs + that list. there is no constant folding and no multiply-high rewrite of + division; the results match, the list is just longer. install kind 2 is + an o3 region: it is accepted and ignored, and the ordinary bytecode of + that region runs instead, which is the same program the full interpreter + would run if the region did not lift. + + no libc in this file. stdint.h is freestanding. 64-bit division is the + compiler's runtime. bss must be zero before micro_run. + + memory size and the map come from memmap.h (the default is 1,048,576 + words). a smaller board compiles this file against the headers src/tools/genmap + writes, and against the genome built for that same map. */ +#include <stdint.h> +#ifdef USE_LSP_GENOME +#include "lsp_genome.h" +#elif defined(GENOME_H) +#include GENOME_H +#else +#include "genome.h" +#endif +#include "micro_port.h" +#include "fops.h" +#include "bops.h" +#define NENH 512 +#define XOP0 22 +#define XPOOL 4096 +#define MAXOPS 128 +#define MAXV 256 + +enum { + U_LI, U_MOV, U_ADD, U_SUB, U_MUL, U_SDIV, U_UDIV, U_SREM, U_UREM, + U_AND, U_OR, U_XOR, U_SHL, U_SHR, U_SAR, U_NEG, U_NOT, + U_LT, U_LTU, U_EQ, U_NE, U_MIN, U_MAX, U_MINU, U_MAXU, + U_MULHS, U_MULHU, U_CLZ, U_ABS, U_SEL, U_LD, U_ST, + U_CTZ, U_POPCNT, U_BSWAP, U_ROTL, U_ROTR, U_F2S, U_S2F, U_N +}; +static const char *const uname[U_N] = { + "li", "mov", "add", "sub", "mul", "sdiv", "udiv", "srem", "urem", + "and", "or", "xor", "shl", "shr", "sar", "neg", "not", + "lt", "ltu", "eq", "ne", "min", "max", "minu", "maxu", + "mulhs", "mulhu", "clz", "abs", "sel", "ld", "st", + "ctz", "popcnt", "bswap", "rotl", "rotr", "f2s", "s2f" +}; +static const signed char uarity[U_N] = { + 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, + 1, 1, 1, 2, 2, 1, 1 +}; + +typedef struct { + unsigned char op, a, b, c; + unsigned short d; + Cell imm; +} Xop; +typedef struct { + unsigned char live, nin, nout; + unsigned short n, at, nv; + unsigned short out[8]; +} Enh; + +/* the machine: m is mw words, and grows on demand through the port (micro_mem_alloc). + every access goes through m and mw, which the port's memory may move under. */ +static Cell *m; +static UCell mw; +static UCell memory_initial = MICRO_MW_INIT, memory_limit = MICRO_MW_LIMIT; +int micro_memory_config(UCell initial, UCell limit) +{ + if (m || initial < MICRO_MW_INIT || limit < initial || limit > 0x7fffffff) return 0; + memory_initial = initial; memory_limit = limit; return 1; +} +static Xop xops[XPOOL]; +static int xuse; +static Enh enh[NENH]; +static Xop build[MAXOPS]; +static int bn, bnv, berr; +static Cell xv[MAXV]; +static int jflag; +static int jknown; /* 0 until something asks for the end-of-input flag: the probe reads the port, so it waits for the first ask */ + +UCell micro_mem_words(void) { return mw; } +static int inmem(Cell a) { return (UCell)a < mw; } +static Cell ld(Cell a) { return inmem(a) ? m[a] : 0; } +static Cell b_load(Cell addr, int n) +{ + if (!bop_ok(addr, n, mw)) return 0; + return bop_load(m, addr, n); +} +static void b_store(Cell addr, Cell val, int n) +{ + Cell out[2], w0; + int nw, i; + if (!bop_ok(addr, n, mw)) return; + nw = bop_merge(m, addr, val, n, out, &w0); + for (i = 0; i < nw; i++) if (inmem(w0 + i)) m[w0 + i] = out[i]; +} + +/* the run's sentinel pcs: each names why a run stopped that is not a halt. they + are negative, so no address in memory is one of them. */ +#define PC_DATA_OVERFLOW (-3) +#define PC_RETURN_OVERFLOW (-4) +#define PC_PAST_END (-5) +#define PC_BAD_OP (-6) +#define PC_HALT (-7) /* the zero word: the program's halt, not an error */ +static int bad_op; + +/* grows the machine to at least words words, through the port. the contents stay, + and the new words are zero. 1 on success, 0 when the port has no more memory. */ +static int mem_grow_words(UCell words) +{ + Cell *n; + if (words <= mw && m) return 1; + if (words > memory_limit) return 0; + n = micro_mem_alloc(words); + if (!n) return 0; + m = n; + mw = words; + return 1; +} + +/* the heap asks for more memory (syscall 9, a = 4, b = words). answers the new + size in words, or -1 when the port cannot give it */ +static Cell mem_grow_request(Cell words) +{ + if (words < 0) return -1; + if (!mem_grow_words((UCell)words)) return -1; + return (Cell)mw; +} +static int stack_memory_grow(UCell words) { return mem_grow_words(words); } +#include "stack.h" + +static Cell mulhu(UCell a, UCell b) +{ + UCell a0 = a & 0xffffffffull, a1 = a >> 32, b0 = b & 0xffffffffull, b1 = b >> 32; + UCell p0 = a0 * b0, p1 = a1 * b0, p2 = a0 * b1, p3 = a1 * b1; + UCell mid = (p0 >> 32) + (p1 & 0xffffffffull) + (p2 & 0xffffffffull); + return (Cell)(p3 + (p1 >> 32) + (p2 >> 32) + (mid >> 32)); +} +static Cell mulhs(Cell a, Cell b) +{ + Cell hi = mulhu((UCell)a, (UCell)b); + if (a < 0) hi -= b; + if (b < 0) hi -= a; + return hi; +} +static Cell sar(Cell v, int n) +{ + if (n <= 0) return v; + if (v < 0) return (Cell)(((UCell)v >> n) | (~(UCell)0 << (64 - n))); + return (Cell)((UCell)v >> n); +} +static Cell ev(int op, Cell a, Cell b, Cell c) +{ + UCell ua = (UCell)a, ub = (UCell)b; + int sh = (int)(b & 63); + switch (op) { + case U_MOV: return a; + case U_ADD: return (Cell)(ua + ub); + case U_SUB: return (Cell)(ua - ub); + case U_MUL: return (Cell)(ua * ub); + case U_SDIV: return b == 0 ? 0 : (a == (Cell)((UCell)1 << 63) && b == -1) ? a : a / b; + case U_UDIV: return b == 0 ? 0 : (Cell)(ua / ub); + case U_SREM: return b == 0 ? a : (a == (Cell)((UCell)1 << 63) && b == -1) ? 0 : a % b; + case U_UREM: return b == 0 ? a : (Cell)(ua % ub); + case U_AND: return a & b; + case U_OR: return a | b; + case U_XOR: return a ^ b; + case U_SHL: return (Cell)(ua << sh); + case U_SHR: return (Cell)(ua >> sh); + case U_SAR: return sar(a, sh); + case U_NEG: return (Cell)(0ull - ua); + case U_NOT: return ~a; + case U_LT: return a < b; + case U_LTU: return ua < ub; + case U_EQ: return a == b; + case U_NE: return a != b; + case U_MIN: return a < b ? a : b; + case U_MAX: return a > b ? a : b; + case U_MINU: return ua < ub ? a : b; + case U_MAXU: return ua > ub ? a : b; + case U_MULHS: return mulhs(a, b); + case U_MULHU: return mulhu(ua, ub); + case U_CLZ: { + int n = 0; + if (!ua) return 64; + while (!(ua & ((UCell)1 << 63))) { ua <<= 1; n++; } + return n; + } + case U_ABS: return a < 0 ? (Cell)(0ull - ua) : a; + case U_CTZ: { int n = 0; if (!ua) return 64; while (!(ua & 1)) { ua >>= 1; n++; } return n; } + case U_POPCNT: { int n = 0; while (ua) { ua &= ua - 1; n++; } return n; } + case U_BSWAP: { UCell r = 0; int i; for (i = 0; i < 8; i++) { r = (r << 8) | (ua & 0xff); ua >>= 8; } return (Cell)r; } + case U_ROTL: return (Cell)((ua << sh) | (ua >> ((64 - sh) & 63))); + case U_ROTR: return (Cell)((ua >> sh) | (ua << ((64 - sh) & 63))); + case U_F2S: return (Cell)fop_f2s((uint64_t)a); + case U_S2F: return (Cell)fop_s2f((uint64_t)a); + case U_SEL: return a ? b : c; + } + return 0; +} + +static int vnew(int op, int a, int b, int c, Cell imm) +{ + Xop *u; + if (berr) return 0; + if (bn >= MAXOPS || bnv >= MAXV) { berr = -5; return 0; } + u = &build[bn++]; + u->op = (unsigned char)op; + u->a = (unsigned char)a; + u->b = (unsigned char)b; + u->c = (unsigned char)c; + u->d = (unsigned short)bnv; + u->imm = imm; + return bnv++; +} +static int seq(const char *a, const char *b) +{ + while (*a && *a == *b) { a++; b++; } + return *a == *b; +} +static int findop(const char *s) +{ + int i; + for (i = 0; i < U_N; i++) if (seq(uname[i], s)) return i; + return -1; +} +static int parse_num(const char *t, Cell *o) +{ + int sign = 1, base = 10, d; + UCell n = 0; + if (*t == '-') { sign = -1; t++; } + else if (*t == '+') t++; + if (*t == '0' && (t[1] == 'x' || t[1] == 'X')) { base = 16; t += 2; } + else if (*t == '0' && t[1]) base = 8; + if (!*t) return -1; + for (; *t; t++) { + if (*t >= '0' && *t <= '9') d = *t - '0'; + else if (*t >= 'a' && *t <= 'f') d = *t - 'a' + 10; + else if (*t >= 'A' && *t <= 'F') d = *t - 'A' + 10; + else return -1; + if (d >= base) return -1; + n = n * (UCell)base + (UCell)d; + } + *o = sign < 0 ? (Cell)(0ull - n) : (Cell)n; + return 0; +} +static int regn(const char *t) +{ + int r = 0; + if (t[0] != 'r' || t[1] < '0' || t[1] > '9') return -1; + t++; + while (*t >= '0' && *t <= '9') { + r = r * 10 + *t++ - '0'; + if (r > 15) return -2; + } + return r; +} +static int named(Cell names, int nin, const char *t) +{ + int i, j; + Cell s; + for (i = 0; i < nin && names; i++) { + s = ld(names + i); + j = 0; + while (ld(s + j) && ld(s + j) == (unsigned char)t[j]) j++; + if (!ld(s + j) && !t[j]) return i; + } + return -1; +} +static int rget(int *cur, int r) +{ + if (cur[r] < 0) cur[r] = vnew(U_LI, 0, 0, 0, 0); + return cur[r]; +} + +static int parse_recipe(Cell src, Cell names, int nin, int nout, int *out) +{ + int cur[16], i, n, k, op, args[3], na, dst, isst, nt, rr, v; + char tok[8][32]; + Cell p = src, x; + for (i = 0; i < 16; i++) cur[i] = i < nin ? i : -1; + bn = 0; bnv = nin; berr = 0; + for (;;) { + nt = 0; + for (;;) { + int c = (int)ld(p); + while (c == ' ' || c == '\t' || c == '\r') c = (int)ld(++p); + if (!c || c == '\n' || c == ';') break; + if (c == '=') { + if (nt < 8) { tok[nt][0] = '='; tok[nt][1] = 0; nt++; } + p++; + continue; + } + n = 0; + while (c && c != ' ' && c != '\t' && c != '\n' && c != ';' && c != '=' && c != '\r') { + if (n < 31) tok[nt < 8 ? nt : 7][n++] = (char)c; + c = (int)ld(++p); + } + if (nt < 8) tok[nt++][n] = 0; + } + if (nt) { + isst = seq(tok[0], "st"); + if (!isst && (nt < 3 || !seq(tok[1], "="))) return -2; + dst = -1; + if (!isst) { + rr = regn(tok[0]); + if (rr == -2) return -2; + dst = rr >= 0 ? rr : named(names, nin, tok[0]); + if (dst < 0 || dst > 15) return -2; + } + k = isst ? 1 : 2; + op = -1; + if (!isst && nt > 3) { + op = findop(tok[k]); + if (op < 0) return -2; + k++; + } + if (isst) op = U_ST; + na = 0; + for (; k < nt; k++) { + char *t = tok[k]; + v = -1; + if (na >= 3) return -2; + rr = regn(t); + if (rr == -2) return -2; + if (rr >= 0) v = rget(cur, rr); + else if ((t[0] >= '0' && t[0] <= '9') || t[0] == '-' || t[0] == '+') { + if (parse_num(t, &x)) return -2; + v = vnew(U_LI, 0, 0, 0, x); + } else { + i = named(names, nin, t); + if (i < 0) return -2; + v = rget(cur, i); + } + if (berr) return berr; + args[na++] = v; + } + if (op < 0) { + if (na != 1) return -2; + cur[dst] = args[0]; + } else { + if (na != (op == U_LI ? 0 : uarity[op])) { + if (!(op == U_LI && na == 1)) return -2; + } + if (op == U_LI) cur[dst] = na ? args[0] : vnew(U_LI, 0, 0, 0, 0); + else if (op == U_MOV) { if (na != 1) return -2; cur[dst] = args[0]; } + else if (op == U_ST) vnew(U_ST, args[0], args[1], 0, 0); + else cur[dst] = vnew(op, args[0], na > 1 ? args[1] : 0, na > 2 ? args[2] : 0, 0); + if (berr) return berr; + } + } + if (!ld(p)) break; + p++; + } + for (i = 0; i < nout; i++) { + if (cur[i] < 0) cur[i] = vnew(U_LI, 0, 0, 0, 0); + out[i] = cur[i]; + } + return berr; +} + +static int lower_vm(Cell a, Cell len, int nin, int nout, int *out) +{ + static const int map[] = { U_ADD, U_SUB, U_MUL, U_AND, U_OR, U_XOR, U_SAR, U_LT }; + int st[256], sp = 0, i, k, x, y, j; + Cell w; + if ((UCell)len > 100000) return -5; + bn = 0; bnv = nin; berr = 0; + for (i = 0; i < nin; i++) st[sp++] = i; + for (i = 0; i < (int)len; i++) { + w = ld(a + i); + if (w & 1) { + if (sp >= 256) return -4; + st[sp++] = vnew(U_LI, 0, 0, 0, w >> 1); + if (berr) return berr; + continue; + } + k = (int)(w >> 1); + if (k == 9) break; + switch (k) { + case 1: + if (sp < 1) return -4; + st[sp - 1] = vnew(U_LD, st[sp - 1], 0, 0, 0); + break; + case 2: + if (sp < 2) return -4; + vnew(U_ST, st[sp - 1], st[sp - 2], 0, 0); + sp -= 2; + break; + case 3: + if (sp < 1) return -4; + x = st[sp - 1]; + if (x < nin) return -4; + for (j = 0; j < bn && build[j].d != (unsigned)x; j++); + if (j == bn || build[j].op != U_LI) return -4; + y = (int)build[j].imm; + if (y < 0 || y >= sp - 1) return -4; + st[sp - 1] = st[sp - 2 - y]; + break; + case 4: + if (sp < 1) return -4; + sp--; + break; + case 5: + if (sp < 2) return -4; + x = st[sp - 1]; st[sp - 1] = st[sp - 2]; st[sp - 2] = x; + break; + case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: + if (sp < 2) return -4; + x = st[sp - 1]; y = st[sp - 2]; sp -= 2; + st[sp++] = vnew(map[k - 13], y, x, 0, 0); + break; + default: + return -4; + } + if (berr) return berr; + } + if (sp != nout) return -4; + for (i = 0; i < nout; i++) out[i] = st[i]; + return berr; +} + +static int commit(int slot, int nin, int nout, int *out) +{ + Enh *e = &enh[slot]; + int base = xuse, i; + if (berr) return berr; + if (e->live && (int)e->at + (int)e->n == xuse) base = e->at; + if (base + bn > XPOOL) return -5; + if (e->live && (int)e->at + (int)e->n == xuse) xuse = e->at; + e->at = (unsigned short)xuse; + e->n = (unsigned short)bn; + e->nv = (unsigned short)bnv; + e->nin = (unsigned char)nin; + e->nout = (unsigned char)nout; + for (i = 0; i < nout; i++) e->out[i] = (unsigned short)out[i]; + for (i = 0; i < bn; i++) xops[xuse++] = build[i]; + e->live = 1; + return 0; +} + +static int install(Cell d) +{ + Cell slot, kind, nin, nout, pay, len, names; + int out[8], r; + if (!inmem(d) || !inmem(d + 6)) return -1; + slot = m[d]; kind = m[d + 1]; nin = m[d + 2]; nout = m[d + 3]; + pay = m[d + 4]; len = m[d + 5]; names = m[d + 6]; + if (kind == 2) return 0; + if ((UCell)slot >= NENH || (UCell)nin > 8 || (UCell)nout > 8 || (kind != 0 && kind != 1)) return -1; + r = kind == 0 ? parse_recipe(pay, names, (int)nin, (int)nout, out) + : lower_vm(pay, len, (int)nin, (int)nout, out); + if (r) return r; + return commit((int)slot, (int)nin, (int)nout, out); +} + +static int xrun(Enh *e, int s) +{ + int i, j; + Xop *u; + for (i = 0; i < e->nv && i < MAXV; i++) xv[i] = 0; + for (j = 0; j < e->nin; j++) xv[j] = m[s + e->nin - 1 - j]; + for (i = 0; i < e->n; i++) { + u = &xops[e->at + i]; + if (u->op == U_LI) xv[u->d] = u->imm; + else if (u->op == U_LD) xv[u->d] = ld(xv[u->a]); + else if (u->op == U_ST) { if (inmem(xv[u->a])) m[xv[u->a]] = xv[u->b]; } + else xv[u->d] = ev(u->op, xv[u->a], xv[u->b], xv[u->c]); + } + s = s + e->nin - e->nout; + for (j = 0; j < e->nout; j++) m[s + e->nout - 1 - j] = xv[e->out[j]]; + return s; +} + +/* a run suspends when the port has no input yet but more may come (streaming, + see micro_port.h): micro_getc returns MICRO_WAIT, the getc is run again on + micro_resume, and the stacks wait where they are */ +static int sus_p, sus_s, sus_r; + +static int run_from(int p, int s, int r) +{ + int op; + Cell w, a, b; + while ((UCell)p < mw) { + if (s < stack_data_limit() || r > stack_return_limit()) { + Cell sp = s, rp = r; int ret = r > stack_return_limit(); + if (!stack_control || stack_expand(ret, stack_get(ret ? SC_RETURN_TOP : SC_DATA_TOP) - stack_get(ret ? SC_RETURN_LOW : SC_DATA_LOW) + 1, &sp, &rp) < 0) { + p = ret ? PC_RETURN_OVERFLOW : PC_DATA_OVERFLOW; break; + } + s = (int)sp; r = (int)rp; + } + w = m[p++]; + if (w & 1) { m[--s] = w >> 1; continue; } + a = m[s]; b = m[s + 1]; + switch ((int)(w >> 1)) { + case 1: m[s] = ld(a); break; + case 2: + if (a == SYSGATE) { + /* a call can grow the memory and move m, so the result is stored after the call */ + Cell result; + if (b == 9 && m[a + 1] == 6) result = stack_register(m[a + 2]) ? 0 : -1; + else if (b == 9 && (m[a + 1] == 7 || m[a + 1] == 8)) { + Cell sp = s + 2, rp = r; + result = stack_expand(m[a + 1] == 8, m[a + 2], &sp, &rp); + s = (int)sp; r = (int)rp; m[a] = result; break; + } + else if (b == 9 && m[a + 1] == 9) result = m[a + 2] > 0 && (UCell)m[a + 2] <= mw ? (Cell)mw : -1; + else if (b == 9 && m[a + 1] == 4) result = mem_grow_request(m[a + 2]); + else if (b == 9 && m[a + 1] == 5) { + Cell limit = m[a + 2]; + if (limit < 0 || (UCell)limit < mw || limit > 0x7fffffff) result = -1; + else { memory_limit = (UCell)limit; result = limit; } + } else result = micro_syscall(m, b, m[a + 1], m[a + 2], m[a + 3]); + m[a] = result; + s += 2; + break; + } + if (inmem(a)) m[a] = b; + s += 2; + break; + case 3: m[s] = ld((Cell)s + 1 + a); break; + case 4: s++; break; + case 5: m[s] = b; m[s + 1] = a; break; + case 6: m[r++] = p; p = (int)a; s++; break; + case 7: p = (int)a; s++; break; + case 8: if (!b) p = (int)a; s += 2; break; + case 9: p = (int)m[--r]; break; + case 10: { + int ch = micro_getc(); + if (ch == MICRO_WAIT) { sus_p = p - 1; sus_s = s; sus_r = r; return MICRO_SUSPENDED; } + m[--s] = (Cell)(signed char)ch; + jflag = micro_eof(); + jknown = 1; + break; + } + case 11: + if (!jknown) { jflag = micro_eof(); jknown = 1; } + m[--s] = jflag; + break; + case 12: micro_putc((int)a); s++; break; + case 13: m[++s] = b + a; break; + case 14: m[++s] = b - a; break; + case 15: m[++s] = b * a; break; + case 16: m[++s] = b & a; break; + case 17: m[++s] = b | a; break; + case 18: m[++s] = b ^ a; break; + case 19: m[++s] = sar(b, (int)(a & 63)); break; + case 20: m[++s] = b < a; break; + case 21: m[s] = install(a); break; + case 600: + if ((UCell)p >= mw) { p = PC_PAST_END; break; } + m[--s] = m[p++]; + break; + case 601: m[++s] = (Cell)fop_add((uint64_t)b, (uint64_t)a); break; + case 602: m[++s] = (Cell)fop_sub((uint64_t)b, (uint64_t)a); break; + case 603: m[++s] = (Cell)fop_mul((uint64_t)b, (uint64_t)a); break; + case 604: m[++s] = (Cell)fop_div((uint64_t)b, (uint64_t)a); break; + case 605: m[++s] = fop_eq((uint64_t)b, (uint64_t)a); break; + case 606: m[++s] = fop_lt((uint64_t)b, (uint64_t)a); break; + case 607: m[++s] = fop_le((uint64_t)b, (uint64_t)a); break; + case 608: m[s] = (Cell)fop_i2f(a); break; + case 609: m[s] = fop_f2i((uint64_t)a); break; + case 610: { + char buf[400]; int n = fop_format((uint64_t)a, buf), ci; + for (ci = 0; ci < n; ci++) micro_putc(buf[ci]); + s++; + break; + } + case 618: { + char buf[400]; + int n = fop_format_mode((uint64_t)m[s + 2], a, b, buf), ci; + for (ci = 0; ci < n; ci++) micro_putc(buf[ci]); + s += 3; + break; + } + case 611: + m[s] = inmem(a) ? (Cell)fop_parse_words(m + a, mw - (UCell)a) : 0; + break; + case 612: m[s] = b_load(a, 1); break; + case 613: b_store(a, b, 1); s += 2; break; + case 614: m[s] = b_load(a, 2); break; + case 615: b_store(a, b, 2); s += 2; break; + case 616: m[s] = b_load(a, 4); break; + case 617: b_store(a, b, 4); s += 2; break; + case 619: { Cell t = s; m[--s] = t; break; } + case 620: { /* a native call: there is no native code here, so pop the arguments and answer -1 */ + int n = 0; + Cell sig = (UCell)a < mw - 2 ? m[a + 1] : 0; + while (n < 15 && ((sig >> (4 * (n + 1))) & 15)) n++; + s += n; + m[s] = -1; + break; } + default: + op = (int)(w >> 1); + if (op >= XOP0 && op < XOP0 + NENH && enh[op - XOP0].live) s = xrun(&enh[op - XOP0], s); + else if (op == 0) p = PC_HALT; + else { bad_op = op; p = PC_BAD_OP; } + } + } + if (p == PC_DATA_OVERFLOW) { micro_msg("zy: data stack overflow\n"); return 2; } + if (p == PC_RETURN_OVERFLOW) { micro_msg("zy: return stack overflow\n"); return 2; } + if (p == PC_PAST_END) { micro_msg("zy: the program counter is past the end of memory\n"); return 2; } + if (p == PC_BAD_OP) { + char msg[96]; int n = 0, k, neg = bad_op < 0, v = bad_op < 0 ? -bad_op : bad_op; + const char *head = "zy: unknown opcode "; + while (head[n]) { msg[n] = head[n]; n++; } + if (neg) msg[n++] = '-'; + { char dg[12]; int nd = 0; do { dg[nd++] = (char)('0' + v % 10); v /= 10; } while (v); for (k = nd; k > 0; k--) msg[n++] = dg[k - 1]; } + msg[n++] = '\n'; msg[n] = 0; + micro_msg(msg); + return 2; + } + return 0; +} + +static int run(int p) { return run_from(p, DS0, RS0); } + +/* goes on from a run that suspended for input (MICRO_SUSPENDED), once the port + has input for it. the result is as micro_run's */ +int micro_resume(void) { return run_from(sus_p, sus_s, sus_r); } + +int micro_run(void) +{ + int i; + if (!mem_grow_words(memory_initial)) { + micro_msg("zy: no memory for the machine\n"); + return 1; + } + if ((UCell)GORG + (UCell)GLEN > mw || (UCell)GORG + (UCell)GLEN > (UCell)FBOT) { + micro_msg("zy: genome does not fit\n"); + return 1; + } + for (i = 0; i < GLEN; i++) m[GORG + i] = genome[i]; + jknown = 0; + return run(GORG); +} |
