aboutsummaryrefslogtreecommitdiff
path: root/src/tools/genmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/genmap.c')
-rw-r--r--src/tools/genmap.c858
1 files changed, 858 insertions, 0 deletions
diff --git a/src/tools/genmap.c b/src/tools/genmap.c
new file mode 100644
index 0000000..dc1971c
--- /dev/null
+++ b/src/tools/genmap.c
@@ -0,0 +1,858 @@
+/* one layout for every memory size. addresses in a genome are literals, so
+ each size is its own image. this tool writes that image's memmap.h and
+ the runtime (and, for a compiler build, compiler.zc) with the same const
+ names as the checked-in 1,048,576-word sources.
+
+ run from the repo root:
+
+ cc -O2 src/tools/genmap.c -o genmap
+ ./genmap --preset small -o build/small
+ ./genmap --preset run -o build/run
+ ./genmap --preset default --check
+
+ ./genmap --mode compiler --heap-lo 8192 --heap 20480 --types 8192 --genome 245760 --frame 2048 --return 512 --mark 512 --data 3072 --snap-cap 1000 --quote-cap 300 -o build/small
+ ./genmap --mode run --words 20480 -o build/run
+
+ --preset default puts the code area, the compiler tables, the genome and
+ the stacks first and the heap last, so the heap can grow at run time up to
+ the total memory size (PW is where the fixed part ends; the host's MW is
+ the total). --preset fixed is the historical 1M map (a fixed heap below
+ the frame pointer, types at the top of it). --mode packs from the bottom. omitting
+ --words rounds MW up to a multiple of 4096, which is what the arm64 jit
+ needs in order to encode cmp xn, #MW. the checked-in sources stay the
+ default map; --check fails if they drift from that preset. */
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <errno.h>
+#ifdef _WIN32
+#include <direct.h>
+#endif
+
+static int align_up(int x, int a) { return (x + a - 1) & ~(a - 1); }
+
+static void die(const char *m) { fprintf(stderr, "genmap: %s\n", m); exit(1); }
+
+static int parse_num(const char *s)
+{
+ char *e;
+ long v;
+ if (!s || !*s) die("missing number");
+ v = strtol(s, &e, 0);
+ if (*e || v <= 0 || v > 0x7fffffff) die("bad number");
+ return (int)v;
+}
+
+static char *slurp(const char *path)
+{
+ FILE *f = fopen(path, "rb");
+ long n; char *b;
+ if (!f) { perror(path); exit(1); }
+ if (fseek(f, 0, SEEK_END) || (n = ftell(f)) < 0 || fseek(f, 0, SEEK_SET)) die("seek");
+ b = malloc((size_t)n + 1);
+ if (!b || fread(b, 1, (size_t)n, f) != (size_t)n) die("read");
+ b[n] = 0;
+ fclose(f);
+ return b;
+}
+
+static void emit_file(const char *path, const char *s)
+{
+ FILE *f = fopen(path, "wb");
+ if (!f) { perror(path); exit(1); }
+ fputs(s, f);
+ if (fclose(f)) die("write");
+}
+
+/* replace the text between the line that is `begin` and the next line that
+ is `end`. the marker lines stay. */
+static char *splice(const char *src, const char *begin, const char *end, const char *repl)
+{
+ const char *a = strstr(src, begin), *b;
+ char *out; size_t n, nr;
+ if (!a) { fprintf(stderr, "genmap: missing %s\n", begin); exit(1); }
+ a += strlen(begin);
+ if (*a == '\n') a++;
+ b = strstr(a, end);
+ if (!b) { fprintf(stderr, "genmap: missing %s\n", end); exit(1); }
+ nr = strlen(repl);
+ n = (size_t)(a - src) + nr + strlen(b) + 1;
+ out = malloc(n);
+ if (!out) die("oom");
+ memcpy(out, src, (size_t)(a - src));
+ memcpy(out + (a - src), repl, nr);
+ strcpy(out + (a - src) + nr, b);
+ return out;
+}
+
+static char *replace_all(const char *src, const char *from, const char *to)
+{
+ const char *p = src, *hit;
+ size_t nf = strlen(from), nt = strlen(to), n = 0, count = 0;
+ char *out, *w;
+ while ((hit = strstr(p, from))) { count++; p = hit + nf; }
+ if (!count) { fprintf(stderr, "genmap: missing %s\n", from); exit(1); }
+ out = malloc(strlen(src) + count * (nt - nf) + 1);
+ if (!out) die("oom");
+ p = src; w = out;
+ while ((hit = strstr(p, from))) {
+ memcpy(w, p, (size_t)(hit - p)); w += hit - p;
+ memcpy(w, to, nt); w += nt;
+ p = hit + nf;
+ n++;
+ }
+ strcpy(w, p);
+ (void)n;
+ return out;
+}
+
+typedef struct {
+ int MW, HEAP_LO, HEAP_HI, ZFP, GORG, FBOT, FTOP, RS0, MARK0, MARKN, DSLO, DSHI;
+ int TW, CODE_END, GROW; /* TW: total words (MW is where the fixed map ends); CODE_END: program words end */
+ int IHN, R_IH, R_POOL, R_POOLEND, NS, R_SYM;
+ int sname, skind, sval, ssig, sflag, sfix, snext;
+ int NL, lname, lslot, lhome, lstate, lowner, lused, larr, lown;
+ int NF, fsite, fnext, R_SNAP, R_QBUF, R_SRC, R_SEQ;
+ int bname, bprec, bseq, blen, uname, useq, ulen, aname, abin, kops;
+ int R_CTX, R_LOOP, R_ASM, cend, glen_need, typesz;
+ int ASM_LABELS, ASM_REFS, ASM_WORDS, EXIT_WORDS;
+ int ENUM_MEMBERS, TAGGED_ENUMS, STRUCT_METHODS, GENERATED_WORDS;
+ int RANGE_FACTS, JOIN_PATHS, O3_REGIONS;
+ const char *name;
+} Map;
+
+/* what actually differs between builds. zero means "use the mode default"
+ except where a preset fills the field itself before layout. */
+typedef struct {
+ const char *name;
+ int compiler;
+ int words;
+ int heap_lo, heap, types, zfp_pad;
+ int heap_top, code_end, total; /* heap above the stacks, free to grow up to total words */
+ int genome, frame, ret, mark, data;
+ int ihn, pool, ns, nl, nf, snap, qbuf, src, seq, ctx, loop;
+ int snap_cap, quote_cap; /* 0 keeps the source caps (8000 and 2700) */
+ int binary, unary, assignments, keywords;
+ int asm_labels, asm_refs, exits;
+ int enum_members, tagged_enums, struct_methods, generated_words;
+ int facts, paths, regions;
+ int type_formula; /* 0 keeps ZFP-16384; else the copy says ZFP-N */
+} Spec;
+
+static void need(int cond, const char *m) { if (!cond) die(m); }
+
+static void check_common(const Map *m)
+{
+ need(m->MW && (m->MW % 4096) == 0, "MW must be a positive multiple of 4096");
+ need(m->HEAP_LO >= 256 && m->HEAP_HI > m->HEAP_LO, "heap");
+ need(m->HEAP_HI - m->HEAP_LO >= 8 && ((m->HEAP_HI - m->HEAP_LO) & 7) == 0, "heap size must be a multiple of eight words");
+ if (m->GROW) {
+ need(m->HEAP_LO == m->MW, "a growing heap starts where the fixed map ends");
+ need(m->TW >= m->HEAP_HI && (m->TW % 4096) == 0, "total memory");
+ need(m->CODE_END >= 256 && m->ZFP >= m->CODE_END && m->ZFP + 8 < m->MW, "frame pointer");
+ } else {
+/* the historical map sets ZFP == HEAP_HI: the type area overlaps the heap */
+ need(m->ZFP >= m->HEAP_HI && m->ZFP + 8 < m->MW, "frame pointer");
+ }
+ need(m->GORG > m->ZFP + 8, "genome overlaps the frame pointer");
+ need(m->GORG + m->glen_need <= m->FBOT, "genome reservation collides with the frame stack");
+ need(m->FBOT + 64 < m->FTOP && m->FTOP == m->RS0, "frame stack");
+ need(m->MARK0 >= m->FTOP + 64 && m->MARK0 + m->MARKN <= m->DSLO, "mark stack");
+ need(m->DSHI == m->MW - 16 && m->DSHI - m->DSLO >= 1100 + 1024, "data stack");
+ need(m->DSLO > m->MARK0, "data stack overlaps the mark stack");
+}
+
+static void tables_tight(Spec *s)
+{
+ s->ihn = 2048; s->pool = 16384; s->ns = 1280; s->nl = 512; s->nf = 2048;
+ s->snap = 1024; s->qbuf = 1024; s->src = 1024; s->seq = 1024;
+ s->ctx = 1024; s->loop = 512;
+}
+
+/* the default map's tables: room for a large program and for several generic
+ libraries, in words nobody touches until a program needs them */
+static void tables_big(Spec *s)
+{
+ s->ihn = 32768; s->pool = 0x40000; s->ns = 16384; s->nl = 512; s->nf = 32768;
+ s->snap = 16384; s->qbuf = 16384; s->src = 1024; s->seq = 2048;
+ s->ctx = 2048; s->loop = 1024;
+}
+
+static void tables_historical(Spec *s)
+{
+ s->ihn = 8192; s->pool = 0x9F00; s->ns = 4096; s->nl = 512; s->nf = 8192;
+ s->snap = 8192; s->qbuf = 8192; s->src = 1024; s->seq = 2048;
+ s->ctx = 2048; s->loop = 1024;
+}
+
+static void preset_small(Spec *s)
+{
+ memset(s, 0, sizeof *s);
+ s->name = "small";
+ s->compiler = 1;
+ s->heap_top = 1; s->code_end = 8192; s->total = 0x8000000;
+ s->heap_lo = 8192; s->heap = 20480; s->types = 8192;
+ s->genome = 245760; s->frame = 2048; s->ret = 512; s->mark = 512; s->data = 3072;
+ tables_tight(s);
+ s->snap_cap = 1000; s->quote_cap = 300; s->snap = 1000; s->qbuf = 900; s->type_formula = 8192;
+}
+
+static void preset_run(Spec *s)
+{
+ memset(s, 0, sizeof *s);
+ s->name = "run";
+ s->heap_top = 1; s->code_end = 512; s->total = 0x8000000;
+ s->heap_lo = 512; s->heap = 16384; s->zfp_pad = 32;
+ s->genome = 15600; s->frame = 1024; s->ret = 256; s->mark = 256; s->data = 2560;
+}
+
+static void preset_default(Spec *s)
+{
+ memset(s, 0, sizeof *s);
+ s->name = "default";
+ s->compiler = 1;
+ s->heap_top = 1; s->code_end = 0x80000; s->types = 65536;
+ s->heap = 0x60000; s->total = 0x8000000;
+ s->genome = 0x50000; s->frame = 0x40000; s->ret = 0x10000; s->mark = 0x8000;
+ s->data = 0x7FF0;
+ tables_big(s);
+}
+
+/* the map before the heap moved to the top: a fixed heap between the code and
+ the frame pointer, the type records at the end of it, 1,081,344 words */
+static void preset_fixed(Spec *s)
+{
+ memset(s, 0, sizeof *s);
+ s->name = "fixed";
+ s->compiler = 1;
+ s->words = 0x108000;
+ s->heap_lo = 0x40000; s->heap = 0x60000;
+ s->genome = 0x28000; s->frame = 0x10000; s->ret = 0x8000; s->mark = 0x4000;
+ tables_historical(s);
+}
+
+/* the language server: the compiler's own growing map. the document store, the
+ diagnostics and the check's sets are heap blocks now, so nothing in the server
+ is at a fixed address and the heap grows with the documents */
+static void preset_lsp(Spec *s)
+{
+ preset_default(s);
+ s->name = "lsp";
+}
+
+static void mode_defaults(Spec *s, int compiler)
+{
+ memset(s, 0, sizeof *s);
+ s->name = compiler ? "compiler" : "run";
+ s->compiler = compiler;
+ if (compiler) {
+ s->heap_top = 1; s->code_end = 8192; s->total = 0x8000000;
+ s->heap_lo = 8192; s->heap = 20480; s->types = 8192; s->type_formula = 8192;
+ s->genome = 245760; s->frame = 2048; s->ret = 512; s->mark = 512; s->data = 3072;
+ tables_tight(s);
+ } else {
+ s->heap_top = 1; s->code_end = 512; s->total = 0x8000000;
+ s->heap_lo = 512; s->heap = 16384; s->zfp_pad = 32;
+ s->genome = 15600; s->frame = 1024; s->ret = 256; s->mark = 256; s->data = 2560;
+ }
+}
+
+/* pack every region from the bottom. a requested MW larger than that keeps
+ the same bases and gives the spare words to the data stack. */
+static void check_layout_size(const Spec *s)
+{
+ long long size = (s->heap_top ? s->code_end : s->heap_lo) + (long long)s->heap + s->types + s->zfp_pad;
+ size += (long long)s->genome + s->frame + s->ret + s->mark + s->data + 8192;
+ if (s->compiler) {
+ size += (long long)s->ihn + s->pool + 8LL * s->ns + 10LL * s->nl + 2LL * s->nf;
+ size += (long long)s->snap + s->qbuf + s->src + s->seq + s->ctx + s->loop;
+ size += 4LL * (s->binary ? s->binary : 64) + 3LL * (s->unary ? s->unary : 32);
+ size += 2LL * (s->assignments ? s->assignments : 64) + (s->keywords ? s->keywords : 512);
+ size += 2LL * (s->asm_labels ? s->asm_labels : 64) + 2LL * (s->asm_refs ? s->asm_refs : 256);
+ size += s->exits ? s->exits : 2560;
+ }
+ need(size <= 0x7fffffff, "layout is too large");
+ if (s->words && s->heap_top) need((long long)s->words + s->heap + 4095 <= 0x7fffffff, "heap end is too large");
+}
+
+static void layout(const Spec *s, Map *m)
+{
+ int a;
+ check_layout_size(s);
+ memset(m, 0, sizeof *m);
+ m->name = s->name;
+ m->glen_need = s->genome;
+ m->typesz = s->types;
+ if (s->heap_top) {
+ m->GROW = 1;
+ m->CODE_END = s->code_end;
+ m->ZFP = m->CODE_END + s->types + s->zfp_pad;
+ } else {
+ m->HEAP_LO = s->heap_lo;
+ m->HEAP_HI = s->heap_lo + s->heap;
+ m->CODE_END = m->HEAP_LO;
+ m->ZFP = m->HEAP_HI + s->types + s->zfp_pad;
+ }
+ if (s->compiler) {
+ m->IHN = s->ihn; m->NS = s->ns; m->NL = s->nl; m->NF = s->nf;
+ a = m->ZFP + 256;
+ m->R_IH = a; a += m->IHN;
+ m->R_POOL = a; a += s->pool; m->R_POOLEND = a; a += 256;
+ m->R_SYM = m->sname = a; a += m->NS;
+ m->skind = a; a += m->NS;
+ m->sval = a; a += m->NS;
+ m->ssig = a; a += m->NS;
+ m->sflag = a; a += m->NS;
+ m->sfix = a; a += m->NS;
+ m->snext = a; a += m->NS;
+ m->lname = a; a += m->NL;
+ m->lslot = a; a += m->NL;
+ m->lhome = a; a += m->NL;
+ m->lstate = a; a += m->NL;
+ m->lowner = a; a += m->NL;
+ m->lused = a; a += m->NL;
+ m->larr = a; a += m->NL;
+ m->lown = a; a += m->NL;
+ m->fsite = a; a += m->NF;
+ m->fnext = a; a += m->NF;
+ m->R_SNAP = a; a += s->snap;
+ m->R_QBUF = a; a += s->qbuf;
+ m->R_SRC = a; a += s->src;
+ m->R_SEQ = a; a += s->seq;
+ {
+ int binary = s->binary ? s->binary : 64, unary = s->unary ? s->unary : 32;
+ int assignments = s->assignments ? s->assignments : 64, keywords = s->keywords ? s->keywords : 512;
+ m->bname = a; a += binary;
+ m->bprec = a; a += binary;
+ m->bseq = a; a += binary;
+ m->blen = a; a += binary;
+ m->uname = a; a += unary;
+ m->useq = a; a += unary;
+ m->ulen = a; a += unary;
+ m->aname = a; a += assignments;
+ m->abin = a; a += assignments;
+ a += 32;
+ m->kops = a; a += keywords;
+ }
+ m->R_CTX = a; a += s->ctx;
+ m->R_LOOP = a; a += s->loop;
+ m->R_ASM = a;
+ m->ASM_LABELS = s->asm_labels ? s->asm_labels : 64;
+ m->ASM_REFS = s->asm_refs ? s->asm_refs : 256;
+ {
+ long long words = 2LL * m->ASM_LABELS + 2LL * m->ASM_REFS;
+ need(words <= 0x7fffff00, "assembly reservation is too large");
+ m->ASM_WORDS = align_up((int)words, 256);
+ if (!s->asm_labels && !s->asm_refs) m->ASM_WORDS = 1024;
+ }
+ m->EXIT_WORDS = s->exits ? s->exits : 2560;
+ m->ENUM_MEMBERS = s->enum_members ? s->enum_members : 128;
+ m->TAGGED_ENUMS = s->tagged_enums ? s->tagged_enums : 16;
+ m->STRUCT_METHODS = s->struct_methods ? s->struct_methods : 32;
+ m->GENERATED_WORDS = s->generated_words ? s->generated_words : 8192;
+ m->RANGE_FACTS = s->facts ? s->facts : 32; m->JOIN_PATHS = s->paths ? s->paths : 64; m->O3_REGIONS = s->regions ? s->regions : 10;
+ need(m->O3_REGIONS <= 0x7fffffff / 67, "region reservation is too large");
+ need(m->ENUM_MEMBERS <= 0x10000000, "enum member reservation is too large");
+ m->cend = m->R_ASM + m->ASM_WORDS + m->NL + m->NL + m->NS + m->EXIT_WORDS;
+ m->GORG = align_up(m->cend + 256, 256);
+ } else {
+ m->GORG = align_up(m->ZFP + 64, 256);
+ }
+ m->FBOT = m->GORG + m->glen_need;
+ m->FTOP = m->FBOT + s->frame;
+ m->RS0 = m->FTOP;
+ m->MARK0 = m->FTOP + s->ret;
+ m->MARKN = s->mark;
+ m->DSLO = m->MARK0 + m->MARKN;
+ if (s->words) {
+ m->MW = s->words;
+ m->DSHI = m->MW - 16;
+ if (s->data && m->DSHI - m->DSLO < s->data) die("memory size too small for the data stack");
+ } else {
+ m->DSHI = m->DSLO + s->data;
+ m->MW = align_up(m->DSHI + 16, 4096);
+ m->DSHI = m->MW - 16;
+ }
+ m->TW = m->MW;
+ if (s->heap_top) {
+ m->HEAP_LO = m->MW;
+ m->HEAP_HI = m->HEAP_LO + s->heap;
+ m->TW = s->total > m->HEAP_HI ? s->total : align_up(m->HEAP_HI, 4096);
+ }
+ check_common(m);
+ if (s->types) need(m->ZFP == (s->heap_top ? m->CODE_END : m->HEAP_HI) + s->types + s->zfp_pad, "type area");
+}
+
+static void hexdef(char **p, char *end, const char *n, int v)
+{
+ int k = snprintf(*p, (size_t)(end - *p), "const %s = 0x%X;\n", n, v);
+ if (k < 0 || *p + k >= end) die("const block");
+ *p += k;
+}
+
+static char *rt_block(const Map *m)
+{
+ char buf[2048], *p = buf;
+ hexdef(&p, buf + sizeof buf, "MW", m->MW);
+ hexdef(&p, buf + sizeof buf, "CODE_END", m->CODE_END);
+ hexdef(&p, buf + sizeof buf, "HEAP_LO", m->HEAP_LO);
+ hexdef(&p, buf + sizeof buf, "HEAP_HI", m->HEAP_HI);
+ hexdef(&p, buf + sizeof buf, "HEAP_GROW", m->GROW);
+ hexdef(&p, buf + sizeof buf, "ZFP", m->ZFP);
+ hexdef(&p, buf + sizeof buf, "GORG", m->GORG);
+ hexdef(&p, buf + sizeof buf, "FBOT", m->FBOT);
+ hexdef(&p, buf + sizeof buf, "FTOP", m->FTOP);
+ hexdef(&p, buf + sizeof buf, "RS0", m->RS0);
+ hexdef(&p, buf + sizeof buf, "MARK0", m->MARK0);
+ hexdef(&p, buf + sizeof buf, "MARKN", m->MARKN);
+ hexdef(&p, buf + sizeof buf, "DSLO", m->DSLO);
+ hexdef(&p, buf + sizeof buf, "DSHI", m->DSHI);
+ hexdef(&p, buf + sizeof buf, "MAGIC", 0x2B7E1516);
+ return strdup(buf);
+}
+
+static char *cc_block(const Map *m)
+{
+ char buf[4096], *p = buf;
+ hexdef(&p, buf + sizeof buf, "IHN", m->IHN);
+ hexdef(&p, buf + sizeof buf, "R_IH", m->R_IH);
+ hexdef(&p, buf + sizeof buf, "R_POOL", m->R_POOL);
+ hexdef(&p, buf + sizeof buf, "R_POOLEND", m->R_POOLEND);
+ hexdef(&p, buf + sizeof buf, "NS", m->NS);
+ hexdef(&p, buf + sizeof buf, "R_SYM", m->R_SYM);
+ hexdef(&p, buf + sizeof buf, "sname_BASE", m->sname);
+ hexdef(&p, buf + sizeof buf, "skind_BASE", m->skind);
+ hexdef(&p, buf + sizeof buf, "sval_BASE", m->sval);
+ hexdef(&p, buf + sizeof buf, "ssig_BASE", m->ssig);
+ hexdef(&p, buf + sizeof buf, "sflag_BASE", m->sflag);
+ hexdef(&p, buf + sizeof buf, "sfix_BASE", m->sfix);
+ hexdef(&p, buf + sizeof buf, "snext_BASE", m->snext);
+ hexdef(&p, buf + sizeof buf, "NL", m->NL);
+ hexdef(&p, buf + sizeof buf, "lname_BASE", m->lname);
+ hexdef(&p, buf + sizeof buf, "lslot_BASE", m->lslot);
+ hexdef(&p, buf + sizeof buf, "lhome_BASE", m->lhome);
+ hexdef(&p, buf + sizeof buf, "lstate_BASE", m->lstate);
+ hexdef(&p, buf + sizeof buf, "lowner_BASE", m->lowner);
+ hexdef(&p, buf + sizeof buf, "lused_BASE", m->lused);
+ hexdef(&p, buf + sizeof buf, "larr_BASE", m->larr);
+ hexdef(&p, buf + sizeof buf, "lown_BASE", m->lown);
+ hexdef(&p, buf + sizeof buf, "NF", m->NF);
+ hexdef(&p, buf + sizeof buf, "fsite_BASE", m->fsite);
+ hexdef(&p, buf + sizeof buf, "fnext_BASE", m->fnext);
+ hexdef(&p, buf + sizeof buf, "R_SNAP_BASE", m->R_SNAP);
+ hexdef(&p, buf + sizeof buf, "R_QBUF_BASE", m->R_QBUF);
+ hexdef(&p, buf + sizeof buf, "R_SRC_BASE", m->R_SRC);
+ hexdef(&p, buf + sizeof buf, "R_SEQ_BASE", m->R_SEQ);
+ hexdef(&p, buf + sizeof buf, "bname_BASE", m->bname);
+ hexdef(&p, buf + sizeof buf, "bprec_BASE", m->bprec);
+ hexdef(&p, buf + sizeof buf, "bseq_BASE", m->bseq);
+ hexdef(&p, buf + sizeof buf, "blen_BASE", m->blen);
+ hexdef(&p, buf + sizeof buf, "uname_BASE", m->uname);
+ hexdef(&p, buf + sizeof buf, "useq_BASE", m->useq);
+ hexdef(&p, buf + sizeof buf, "ulen_BASE", m->ulen);
+ hexdef(&p, buf + sizeof buf, "aname_BASE", m->aname);
+ hexdef(&p, buf + sizeof buf, "abin_BASE", m->abin);
+ hexdef(&p, buf + sizeof buf, "kops_BASE", m->kops);
+ hexdef(&p, buf + sizeof buf, "R_CTX_BASE", m->R_CTX);
+ hexdef(&p, buf + sizeof buf, "R_LOOP_BASE", m->R_LOOP);
+ hexdef(&p, buf + sizeof buf, "R_ASM", m->R_ASM);
+ hexdef(&p, buf + sizeof buf, "ASM_LABELS", m->ASM_LABELS);
+ hexdef(&p, buf + sizeof buf, "ASM_REFS", m->ASM_REFS);
+ hexdef(&p, buf + sizeof buf, "ASM_WORDS", m->ASM_WORDS);
+ hexdef(&p, buf + sizeof buf, "EXIT_WORDS", m->EXIT_WORDS);
+ hexdef(&p, buf + sizeof buf, "ENUM_MEMBERS", m->ENUM_MEMBERS);
+ hexdef(&p, buf + sizeof buf, "TAGGED_ENUMS", m->TAGGED_ENUMS);
+ hexdef(&p, buf + sizeof buf, "STRUCT_METHODS", m->STRUCT_METHODS);
+ hexdef(&p, buf + sizeof buf, "GENERATED_WORDS", m->GENERATED_WORDS);
+ hexdef(&p, buf + sizeof buf, "RANGE_FACTS", m->RANGE_FACTS);
+ hexdef(&p, buf + sizeof buf, "JOIN_PATHS", m->JOIN_PATHS);
+ hexdef(&p, buf + sizeof buf, "O3_REGIONS", m->O3_REGIONS);
+ return strdup(buf);
+}
+
+static void write_memmap(const char *dir, const Map *m)
+{
+ char path[512], buf[4096];
+ snprintf(path, sizeof path, "%s/memmap.h", dir);
+ snprintf(buf, sizeof buf,
+ "/* generated by src/tools/genmap for the %s profile. do not edit. */\n"
+ "#ifndef MEMMAP_H\n#define MEMMAP_H\n"
+ "#define PW 0x%X\n#define CODE_END 0x%X\n#define HEAP_LO 0x%X\n#define HEAP_HI 0x%X\n"
+ "#define HEAP_GROW %d\n"
+ "#ifndef MW\n#define MW 0x%X\n#endif\n"
+ "#if MW < HEAP_HI\n#error MW is below the end of the initial heap\n#endif\n"
+ "#define ZFP 0x%X\n"
+ "#ifdef GORG\n#if GORG != 0x%X\n#error genome GORG does not match this map\n#endif\n"
+ "#else\n#define GORG 0x%X\n#endif\n"
+ "#define FBOT 0x%X\n#define FTOP 0x%X\n#define RS0 0x%X\n"
+ "#define MARK0 0x%X\n#define MARKN 0x%X\n"
+ "#define DSLO 0x%X\n#define DSHI 0x%X\n"
+ "#define DS0 DSHI\n#define SYSGATE (ZFP + 2)\n"
+ "#define DSLIM (DSLO + 1100)\n#define RSLIM (MARK0 - 8)\n"
+ "#endif\n",
+ m->name, m->MW, m->CODE_END, m->HEAP_LO, m->HEAP_HI, m->GROW, m->TW, m->ZFP, m->GORG, m->GORG,
+ m->FBOT, m->FTOP, m->RS0, m->MARK0, m->MARKN, m->DSLO, m->DSHI);
+ emit_file(path, buf);
+}
+
+static char *map_txt(const Map *m)
+{
+ char buf[2048];
+ int n;
+ n = snprintf(buf, sizeof buf,
+ "profile %s\nMW %d (%lld bytes)\nprogram 0 .. %d\nheap %d .. %d (%d words)\n",
+ m->name, m->TW, (long long)m->TW * 8, m->CODE_END, m->HEAP_LO, m->HEAP_HI, m->HEAP_HI - m->HEAP_LO);
+ if (m->GROW)
+ n += snprintf(buf + n, sizeof buf - n, "fixed map ends at %d; the heap grows up to %d\n", m->MW, m->TW);
+ if (m->typesz)
+ n += snprintf(buf + n, sizeof buf - n, "types %d .. %d (%d words)\n", m->ZFP - m->typesz, m->ZFP, m->typesz);
+ n += snprintf(buf + n, sizeof buf - n, "ZFP %d SYSGATE %d\n", m->ZFP, m->ZFP + 2);
+ if (m->R_ASM) {
+ int ltype = m->R_ASM + m->ASM_WORDS;
+ int rexit = ltype + m->NL + m->NL + m->NS;
+ n += snprintf(buf + n, sizeof buf - n,
+ "compiler tables %d .. %d\nltype %d R_EXIT %d .. %d\n",
+ m->R_IH, m->cend, ltype, rexit, rexit + m->EXIT_WORDS);
+ }
+ snprintf(buf + n, sizeof buf - n,
+ "GORG %d reserved through %d\nframe %d .. %d\nreturn %d .. %d\nmark %d .. %d (%d)\ndata %d .. %d\n",
+ m->GORG, m->GORG + m->glen_need, m->FBOT, m->FTOP, m->FTOP, m->MARK0,
+ m->MARK0, m->MARK0 + m->MARKN, m->MARKN, m->DSLO, m->DSHI);
+ return strdup(buf);
+}
+
+static void write_map_txt(const char *dir, const char *txt)
+{
+ char path[512];
+ snprintf(path, sizeof path, "%s/map.txt", dir);
+ emit_file(path, txt);
+ fputs(txt, stderr);
+}
+
+static void mkdir1(const char *dir)
+{
+#ifdef _WIN32
+ char tmp[512];
+ char *p;
+ snprintf(tmp, sizeof(tmp), "%s", dir);
+ for (p = tmp; *p; p++) {
+ if (*p == '/' || *p == '\\') {
+ char save = *p;
+ *p = 0;
+ if (*tmp) _mkdir(tmp);
+ *p = save;
+ }
+ }
+ if (_mkdir(dir) && errno != EEXIST) { perror(dir); exit(1); }
+#else
+ if (mkdir(dir, 0755) && errno != EEXIST) { perror(dir); exit(1); }
+#endif
+}
+
+static char *between(const char *src, const char *begin, const char *end)
+{
+ const char *a = strstr(src, begin), *b;
+ char *out; size_t n;
+ if (!a) return 0;
+ a += strlen(begin);
+ b = strstr(a, end);
+ if (!b || b < a) return 0;
+ n = (size_t)(b - a);
+ out = malloc(n + 1);
+ if (!out) die("oom");
+ memcpy(out, a, n);
+ out[n] = 0;
+ return out;
+}
+
+static int token_hex(const char *text, const char *name, int *out)
+{
+ const char *p = text;
+ size_t n = strlen(name);
+ while ((p = strstr(p, name))) {
+ int before_ok = p == text || !(isalnum((unsigned char)p[-1]) || p[-1] == '_');
+ int after_ok = !(isalnum((unsigned char)p[n]) || p[n] == '_');
+ if (before_ok && after_ok) {
+ const char *q = p + n;
+ while (*q == ' ' || *q == '\t') q++;
+ if (*q == '=') { q++; while (*q == ' ' || *q == '\t') q++; }
+ if (q[0] == '0' && (q[1] == 'x' || q[1] == 'X')) {
+ *out = (int)strtol(q, 0, 16);
+ return 1;
+ }
+ if (isdigit((unsigned char)*q)) {
+ *out = (int)strtol(q, 0, 10);
+ return 1;
+ }
+ }
+ p += n;
+ }
+ return 0;
+}
+
+static void expect_hex(const char *text, const char *where, const char *name, int want)
+{
+ int got;
+ if (!token_hex(text, name, &got) || got != want) {
+ fprintf(stderr, "genmap: %s %s is 0x%X in the layout", where, name, want);
+ if (token_hex(text, name, &got)) fprintf(stderr, " and 0x%X in the source", got);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+}
+
+/* the lfa immediate the checked-in rt.zc carries: the default map's ZFP */
+#define DEFAULT_ZFP 589824
+
+static void check_sources(const Map *m)
+{
+ char lfa_old[64];
+ FILE *mf = fopen("memmap.h", "rb");
+ const char *mm_path = mf ? (fclose(mf), "memmap.h") : "src/core/memmap.h";
+ char *rt = slurp("src/runtime/rt.zc"), *cc = slurp("src/compiler/compiler.zc"), *mm = slurp(mm_path);
+ char *rtb = between(rt, "// @map-rt", "// @end-map");
+ char *ccb = between(cc, "// @map-cc", "// @end-map");
+ static const char *rt_names[] = {
+ "MW", "CODE_END", "HEAP_LO", "HEAP_HI", "HEAP_GROW", "ZFP", "GORG", "FBOT", "FTOP", "RS0",
+ "MARK0", "MARKN", "DSLO", "DSHI", "MAGIC", 0
+ };
+ static const char *cc_names[] = {
+ "IHN", "R_IH", "R_POOL", "R_POOLEND", "NS", "R_SYM",
+ "sname_BASE", "skind_BASE", "sval_BASE", "ssig_BASE", "sflag_BASE", "sfix_BASE", "snext_BASE",
+ "NL", "lname_BASE", "lslot_BASE", "lhome_BASE", "lstate_BASE", "lowner_BASE", "lused_BASE", "larr_BASE", "lown_BASE",
+ "NF", "fsite_BASE", "fnext_BASE", "R_SNAP_BASE", "R_QBUF_BASE", "R_SRC_BASE", "R_SEQ_BASE",
+ "bname_BASE", "bprec_BASE", "bseq_BASE", "blen_BASE", "uname_BASE", "useq_BASE", "ulen_BASE", "aname_BASE", "abin_BASE", "kops_BASE",
+ "R_CTX_BASE", "R_LOOP_BASE", "R_ASM", "ASM_LABELS", "ASM_REFS", "ASM_WORDS", "EXIT_WORDS", "ENUM_MEMBERS", "TAGGED_ENUMS", "STRUCT_METHODS", "GENERATED_WORDS", "RANGE_FACTS", "JOIN_PATHS", "O3_REGIONS", 0
+ };
+ int rt_vals[] = {
+ m->MW, m->CODE_END, m->HEAP_LO, m->HEAP_HI, m->GROW, m->ZFP, m->GORG, m->FBOT, m->FTOP, m->RS0,
+ m->MARK0, m->MARKN, m->DSLO, m->DSHI, 0x2B7E1516
+ };
+ int cc_vals[] = {
+ m->IHN, m->R_IH, m->R_POOL, m->R_POOLEND, m->NS, m->R_SYM,
+ m->sname, m->skind, m->sval, m->ssig, m->sflag, m->sfix, m->snext,
+ m->NL, m->lname, m->lslot, m->lhome, m->lstate, m->lowner, m->lused, m->larr, m->lown,
+ m->NF, m->fsite, m->fnext, m->R_SNAP, m->R_QBUF, m->R_SRC, m->R_SEQ,
+ m->bname, m->bprec, m->bseq, m->blen, m->uname, m->useq, m->ulen, m->aname, m->abin, m->kops,
+ m->R_CTX, m->R_LOOP, m->R_ASM, m->ASM_LABELS, m->ASM_REFS, m->ASM_WORDS, m->EXIT_WORDS, m->ENUM_MEMBERS, m->TAGGED_ENUMS, m->STRUCT_METHODS, m->GENERATED_WORDS, m->RANGE_FACTS, m->JOIN_PATHS, m->O3_REGIONS
+ };
+ int i;
+ if (!rtb || !ccb) die("map markers missing from the checked-in sources");
+ snprintf(lfa_old, sizeof lfa_old, "ld %d", DEFAULT_ZFP);
+ if (!strstr(rt, lfa_old)) die("src/runtime/rt.zc no longer has the default lfa immediate");
+ if (!strstr(cc, "ZFP - 16384")) die("src/compiler/compiler.zc lost its initial type-area formula");
+ for (i = 0; rt_names[i]; i++) expect_hex(rtb, "src/runtime/rt.zc", rt_names[i], rt_vals[i]);
+ for (i = 0; rt_names[i]; i++) {
+ if (!strcmp(rt_names[i], "MAGIC") || !strcmp(rt_names[i], "HEAP_GROW")) continue;
+ expect_hex(mm, mm_path, !strcmp(rt_names[i], "MW") ? "PW" : rt_names[i], rt_vals[i]);
+ }
+ if (m->R_ASM) for (i = 0; cc_names[i]; i++) expect_hex(ccb, "src/compiler/compiler.zc", cc_names[i], cc_vals[i]);
+ free(rt); free(cc); free(mm); free(rtb); free(ccb);
+}
+
+static void write_sources(const char *dir, const Spec *s, const Map *m)
+{
+ char path[512], lfa[64], formula[64], snap[64], quote[64];
+ char *rt, *block, *spliced, *done;
+ rt = slurp("src/runtime/rt.zc");
+ block = rt_block(m);
+ spliced = splice(rt, "// @map-rt", "// @end-map", block);
+ snprintf(lfa, sizeof lfa, "ld %d", m->ZFP);
+ { char old[64]; snprintf(old, sizeof old, "ld %d", DEFAULT_ZFP); done = replace_all(spliced, old, lfa); }
+ snprintf(path, sizeof path, "%s/rt.zc", dir);
+ emit_file(path, done);
+ free(rt); free(block); free(spliced); free(done);
+ if (!s->compiler) return;
+ {
+ char *cc = slurp("src/compiler/compiler.zc");
+ block = cc_block(m);
+ spliced = splice(cc, "// @map-cc", "// @end-map", block);
+ if (s->type_formula) {
+ snprintf(formula, sizeof formula, "ZFP - %d", s->type_formula);
+ done = replace_all(spliced, "ZFP - 16384", formula);
+ free(spliced); spliced = done;
+ }
+ snprintf(path, sizeof path, "%s/compiler.zc", dir);
+ emit_file(path, spliced);
+ free(cc); free(block); free(spliced);
+ }
+}
+
+static void usage_status(int status)
+{
+ fprintf(stderr,
+ "usage: genmap --preset small|run|default|fixed|lsp [-o DIR] [--check]\n"
+ " genmap --mode compiler|run [-o DIR] [--words N] [options]\n"
+ " genmap small|run DIR\n"
+ "options:\n"
+ " --code N --total N --heap N --heap-lo N --types N --zfp-pad N --genome N\n"
+ " --frame N --return N --mark N --data N\n"
+ " --hash N --pool N --symbols N --locals N --fwd N\n"
+ " --snap N --quote N --src N --seq N --ctx N --loop N\n"
+ " --binary N --unary N --assignments N --keywords N\n"
+ " --asm-labels N --asm-refs N --exit N\n"
+ " --enum-members N --tagged-enums N --methods N --generated-text N\n"
+ " --facts N --paths N --regions N\n"
+ " --snap-cap N --quote-cap N --name LABEL\n"
+ "--preset default has a growing heap above the stacks; fixed is the old 1,081,344-word map.\n"
+ "--grow lets a map with a fixed size get bigger when its genome needs more room.\n"
+ "--mode packs a compiler or a run-only image; spare words go to the data stack.\n"
+ "--check compares that layout to memmap.h and the checked-in const blocks.\n");
+ exit(status);
+}
+
+static void usage(void) { usage_status(1); }
+
+static int take(int argc, char **argv, int *i)
+{
+ if (*i + 1 >= argc) usage();
+ return parse_num(argv[++*i]);
+}
+
+int main(int argc, char **argv)
+{
+ Spec s; Map m;
+ if (argc == 2 && !strcmp(argv[1], "--help")) usage_status(0);
+ const char *outdir = 0, *preset = 0, *mode = 0;
+ int check = 0, grow = 0, i, have = 0;
+ int total = 0, set_total = 0, set_words = 0, set_heap = 0, set_heap_lo = 0, set_types = 0, set_zfp = 0;
+ int code = 0, binary = 0, unary = 0, assignments = 0, keywords = 0;
+ int asm_labels = 0, asm_refs = 0, exits = 0;
+ int enum_members = 0, tagged_enums = 0, struct_methods = 0, generated_words = 0;
+ int facts = 0, paths = 0, regions = 0;
+ int set_genome = 0, set_frame = 0, set_ret = 0, set_mark = 0, set_data = 0;
+ int words = 0, heap = 0, heap_lo = 0, types = 0, zfp_pad = 0;
+ int genome = 0, frame = 0, ret = 0, mark = 0, data = 0;
+ int set_ihn = 0, set_pool = 0, set_ns = 0, set_nl = 0, set_nf = 0;
+ int set_snap = 0, set_qbuf = 0, set_src = 0, set_seq = 0, set_ctx = 0, set_loop = 0;
+ int set_snap_cap = 0, set_quote_cap = 0;
+ int ihn = 0, pool = 0, ns = 0, nl = 0, nf = 0, snap = 0, qbuf = 0, srcn = 0, seq = 0, ctx = 0, loop = 0;
+ int snap_cap = 0, quote_cap = 0, set_name = 0;
+ const char *s_name = 0;
+ char *txt;
+
+ if (argc == 3 && argv[1][0] != '-' && (strcmp(argv[1], "small") == 0 || strcmp(argv[1], "run") == 0)) {
+ preset = argv[1];
+ outdir = argv[2];
+ } else {
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--preset") == 0) { if (++i >= argc) usage(); preset = argv[i]; }
+ else if (strcmp(argv[i], "--mode") == 0) { if (++i >= argc) usage(); mode = argv[i]; }
+ else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--out") == 0) { if (++i >= argc) usage(); outdir = argv[i]; }
+ else if (strcmp(argv[i], "--check") == 0) check = 1;
+ else if (strcmp(argv[i], "--grow") == 0) grow = 1;
+ else if (strcmp(argv[i], "--words") == 0) { words = take(argc, argv, &i); set_words = 1; }
+ else if (strcmp(argv[i], "--total") == 0) { total = take(argc, argv, &i); set_total = 1; }
+ else if (strcmp(argv[i], "--code") == 0) code = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--binary") == 0) binary = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--unary") == 0) unary = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--assignments") == 0) assignments = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--keywords") == 0) keywords = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--asm-labels") == 0) asm_labels = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--asm-refs") == 0) asm_refs = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--exit") == 0) exits = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--enum-members") == 0) enum_members = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--tagged-enums") == 0) tagged_enums = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--methods") == 0) struct_methods = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--generated-text") == 0) generated_words = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--facts") == 0) facts = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--paths") == 0) paths = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--regions") == 0) regions = take(argc, argv, &i);
+ else if (strcmp(argv[i], "--heap") == 0) { heap = take(argc, argv, &i); set_heap = 1; }
+ else if (strcmp(argv[i], "--heap-lo") == 0) { heap_lo = take(argc, argv, &i); set_heap_lo = 1; }
+ else if (strcmp(argv[i], "--types") == 0) { types = take(argc, argv, &i); set_types = 1; }
+ else if (strcmp(argv[i], "--zfp-pad") == 0) { zfp_pad = take(argc, argv, &i); set_zfp = 1; }
+ else if (strcmp(argv[i], "--genome") == 0) { genome = take(argc, argv, &i); set_genome = 1; }
+ else if (strcmp(argv[i], "--frame") == 0) { frame = take(argc, argv, &i); set_frame = 1; }
+ else if (strcmp(argv[i], "--return") == 0) { ret = take(argc, argv, &i); set_ret = 1; }
+ else if (strcmp(argv[i], "--mark") == 0) { mark = take(argc, argv, &i); set_mark = 1; }
+ else if (strcmp(argv[i], "--data") == 0) { data = take(argc, argv, &i); set_data = 1; }
+ else if (strcmp(argv[i], "--hash") == 0) { ihn = take(argc, argv, &i); set_ihn = 1; }
+ else if (strcmp(argv[i], "--pool") == 0) { pool = take(argc, argv, &i); set_pool = 1; }
+ else if (strcmp(argv[i], "--symbols") == 0) { ns = take(argc, argv, &i); set_ns = 1; }
+ else if (strcmp(argv[i], "--locals") == 0) { nl = take(argc, argv, &i); set_nl = 1; }
+ else if (strcmp(argv[i], "--fwd") == 0) { nf = take(argc, argv, &i); set_nf = 1; }
+ else if (strcmp(argv[i], "--snap") == 0) { snap = take(argc, argv, &i); set_snap = 1; }
+ else if (strcmp(argv[i], "--quote") == 0) { qbuf = take(argc, argv, &i); set_qbuf = 1; }
+ else if (strcmp(argv[i], "--src") == 0) { srcn = take(argc, argv, &i); set_src = 1; }
+ else if (strcmp(argv[i], "--seq") == 0) { seq = take(argc, argv, &i); set_seq = 1; }
+ else if (strcmp(argv[i], "--ctx") == 0) { ctx = take(argc, argv, &i); set_ctx = 1; }
+ else if (strcmp(argv[i], "--loop") == 0) { loop = take(argc, argv, &i); set_loop = 1; }
+ else if (strcmp(argv[i], "--snap-cap") == 0) { snap_cap = take(argc, argv, &i); set_snap_cap = 1; }
+ else if (strcmp(argv[i], "--quote-cap") == 0) { quote_cap = take(argc, argv, &i); set_quote_cap = 1; }
+ else if (strcmp(argv[i], "--name") == 0) { if (++i >= argc) usage(); s_name = argv[i]; set_name = 1; }
+ else usage();
+ }
+ }
+ if (preset && mode) die("pass --preset or --mode, not both");
+ if (!preset && !mode) usage();
+ if (preset) {
+ if (strcmp(preset, "small") == 0) preset_small(&s);
+ else if (strcmp(preset, "run") == 0) preset_run(&s);
+ else if (strcmp(preset, "default") == 0) preset_default(&s);
+ else if (strcmp(preset, "lsp") == 0) preset_lsp(&s);
+ else if (strcmp(preset, "fixed") == 0) preset_fixed(&s);
+ else die("preset is small, run, default, fixed or lsp");
+ } else {
+ if (strcmp(mode, "compiler") == 0) mode_defaults(&s, 1);
+ else if (strcmp(mode, "run") == 0) mode_defaults(&s, 0);
+ else die("mode is compiler or run");
+ }
+ if (set_words) s.words = words;
+ if (set_total) s.total = total;
+ if (set_heap) s.heap = heap;
+ if (set_heap_lo) { s.heap_lo = heap_lo; if (s.heap_top) s.code_end = heap_lo; }
+ if (code) { if (s.heap_top) s.code_end = code; else s.heap_lo = code; }
+ s.binary = binary; s.unary = unary; s.assignments = assignments; s.keywords = keywords;
+ s.asm_labels = asm_labels; s.asm_refs = asm_refs; s.exits = exits;
+ s.enum_members = enum_members; s.tagged_enums = tagged_enums; s.struct_methods = struct_methods; s.generated_words = generated_words;
+ s.facts = facts; s.paths = paths; s.regions = regions;
+ if (set_types) { s.types = types; s.type_formula = types == 16384 ? 0 : types; }
+ if (set_zfp) s.zfp_pad = zfp_pad;
+ if (set_genome) s.genome = genome;
+ if (set_frame) s.frame = frame;
+ if (set_ret) s.ret = ret;
+ if (set_mark) s.mark = mark;
+ if (set_data) s.data = data;
+ if (set_ihn) s.ihn = ihn;
+ if (set_pool) s.pool = pool;
+ if (set_ns) s.ns = ns;
+ if (set_nl) s.nl = nl;
+ if (set_nf) s.nf = nf;
+ if (set_snap) s.snap = snap;
+ if (set_qbuf) s.qbuf = qbuf;
+ if (set_src) s.src = srcn;
+ if (set_seq) s.seq = seq;
+ if (set_ctx) s.ctx = ctx;
+ if (set_loop) s.loop = loop;
+ if (set_snap_cap) s.snap = snap_cap;
+ if (set_quote_cap) { if (quote_cap > 0x7fffffff / 3) die("quote size overflow"); s.qbuf = quote_cap * 3; }
+ if (set_name) s.name = s_name;
+ /* --grow: a preset with a fixed memory size gets as many words as its layout needs. the
+ fixed size stays when it is big enough, so a program that fits builds the same map as
+ before and a bigger genome moves the top of memory up instead of failing */
+ if (grow && s.words) {
+ Spec t = s; Map probe;
+ t.words = 0;
+ if (!t.data) t.data = 16368;
+ layout(&t, &probe);
+ if (probe.MW > s.words) s.words = probe.MW;
+ }
+ if (s.compiler && (!s.ihn || !s.pool || !s.ns || !s.nl || !s.nf)) die("compiler tables are empty");
+ layout(&s, &m);
+ txt = map_txt(&m);
+ if (check) check_sources(&m);
+ if (outdir) {
+ mkdir1(outdir);
+ write_memmap(outdir, &m);
+ write_map_txt(outdir, txt);
+ write_sources(outdir, &s, &m);
+ have = 1;
+ }
+ if (!have && !check) usage();
+ if (check && !outdir) fputs(txt, stdout);
+ free(txt);
+ return 0;
+}