/* mkrom.c -- build the ROM, off the node, as a bitstream is built. * * mkrom OUT.c OUT.sym MAP.f18 SOURCE.f18... * * docs/v4.0.0/MACHINE.md section 2. The ROM is F18 code, written in the * text assembler's notation (include/v4/text.h) in capsules/v4/rom, and this * is the only thing built off the node. It assembles MAP.f18 (the memory * map's constants, from tools/mkmap.c) and then each SOURCE in the order * given, at the ROM's base address, and writes: * OUT.c the ROM: const v4_cell v4_rom_[] and its length * OUT.sym every word of it, "NAME ADDRESS" a line, for the tests * * This tool is built with a node whose RAM reaches over the ROM's range * (V4_NODE_WORDS = the host's RAM plus its ROM range, V4_ROM_WORDS = 0), so * the assembler can lay the ROM down where it will run; ROM_ORIGIN is the * host's RAM size, which is where the ROM starts on the machine. The * assembler's branch placement depends only on the top of the address space, * which is the same either way. */ #include "v4/text.h" #include #include #ifndef ROM_ORIGIN #error "ROM_ORIGIN must be the host node's RAM size" #endif #ifndef ROM_RANGE #error "ROM_RANGE must be the host node's ROM range, in words" #endif static v4_node n; static v4_text tx; static void die(const char *what, const char *detail) { fprintf(stderr, "mkrom: %s%s%s\n", what, detail ? ": " : "", detail ? detail : ""); exit(1); } /* a cell as a C constant of the cell's type, with no implementation-defined conversion */ static void put_cell(FILE *f, v4_cell v) { #if V4_CELL_BITS == 64 if (v == (v4_cell)((v4_ucell)1 << 63)) fprintf(f, "(-9223372036854775807LL - 1)"); else fprintf(f, "%lldLL", (long long)v); #else if (v == (v4_cell)((v4_ucell)1 << 31)) fprintf(f, "(-2147483647L - 1)"); else fprintf(f, "%ldL", (long)v); #endif } int main(int argc, char **argv) { FILE *out; v4_cell here, a; int i; unsigned s; if (argc < 5) die("usage: mkrom OUT.c OUT.sym MAP.f18 SOURCE.f18...", NULL); if ((v4_ucell)V4_NODE_WORDS != (v4_ucell)ROM_ORIGIN + (v4_ucell)ROM_RANGE) die("built with the wrong node size: RAM must reach over the ROM's range", NULL); v4_node_reset(&n); v4_text_begin(&tx, &n, ROM_ORIGIN); for (i = 3; i < argc; i++) if (!v4_text_assemble_file(&tx, argv[i])) die("does not assemble", v4_text_error(&tx)); if (!v4_text_finish(&tx)) die("not everything is defined", v4_text_error(&tx)); here = v4_text_here(&tx); if (here - (v4_cell)ROM_ORIGIN > (v4_cell)ROM_RANGE) die("the ROM is larger than its range", NULL); out = fopen(argv[1], "w"); if (!out) die("cannot write", argv[1]); fprintf(out, "/* Generated by v4/tools/mkrom.c from capsules/v4/rom -- do not edit. */\n#include \"v4/cell.h\"\n\n"); fprintf(out, "const v4_cell v4_rom_%d[] = {\n", V4_CELL_BITS); for (a = ROM_ORIGIN; a < here; a++) { fprintf(out, " "); put_cell(out, n.mem[a]); fprintf(out, ",\n"); } if (here == ROM_ORIGIN) fprintf(out, " 0\n"); fprintf(out, "};\nconst unsigned v4_rom_%d_words = %ldu;\n", V4_CELL_BITS, (long)(here - (v4_cell)ROM_ORIGIN)); if (fclose(out) != 0) die("cannot write", argv[1]); out = fopen(argv[2], "w"); if (!out) die("cannot write", argv[2]); for (s = 0; s < tx.nsym; s++) if (tx.sym[s].kind == 1) fprintf(out, "%s %ld\n", tx.pool + tx.sym[s].name, (long)tx.sym[s].value); if (fclose(out) != 0) die("cannot write", argv[2]); fprintf(stderr, "mkrom: a ROM of %ld words, %d-bit cells -> %s\n", (long)(here - (v4_cell)ROM_ORIGIN), V4_CELL_BITS, argv[1]); return 0; }