feat(v4.0.0): the nucleus is a capsule, sent to a node born empty
MESH.md step 2. A capsule of F18 code is the words a neighbour writes to a node's port: for each stretch of memory, "@p a! @p push", the address and count, "@p !+ unext" and the words; then a jump to the start. A node born empty executes that from its port, so it needs nothing in it beforehand. - capsule.h/.c: v4_capsule_write, any node's memory as such a capsule - mkimage writes the nucleus so, to capsules/v4/nucleus-64.f18, and the addresses a host needs as a C file; the memory image is no longer linked into either product - mkcapsule is unchanged: the nucleus capsule is a built file kept under capsules/, as BLOCK_MAP.md is, and is baked, hashed and signed with the rest - boot: the node is born empty (v4_image_born); the nucleus capsule is found, its hash and signature checked, and given to the node a word at a time as it reads its port; PARITY:V4_NUCLEUS carries its name and hash Verified: test_fabric.c (59 checks, both widths, and under ASan and UBSan): a memory with a programme and scattered words arrives word for word in an empty node and runs. The nucleus capsule rebuilds byte for byte. hosted-check passes on three ISAs; clean qemu with STARFORTH_V4=1 on amd64, aarch64 and riscv64 takes the nucleus in, passes POST (550 of 550) and answers lines typed at each prompt (logs/20261006-102421, -102706, -103048). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
9af442f793
commit
42610e844f
+27
-14
@@ -1,19 +1,21 @@
|
||||
/* mkimage.c -- build the capsule image (include/v4/image.h).
|
||||
*
|
||||
* mkimage OUTPUT.c
|
||||
* mkimage DESCRIPTION.c CAPSULE.f18
|
||||
*
|
||||
* Runs on the build machine. It assembles capsule/ *.v4 -- the nucleus,
|
||||
* docs/v4.0.0/NUCLEUS.md -- onto a host node with the memory map of
|
||||
* tests/host_map.h. It runs nothing: it writes every
|
||||
* word of the node's memory that is not zero, and the addresses a loader
|
||||
* needs, as a C file. No FORTH source is compiled here: what is not in the
|
||||
* nucleus is loaded from capsules when the system boots (v4/system/boot.c).
|
||||
* tests/host_map.h. It runs nothing. It writes the nucleus as a capsule
|
||||
* of F18 code (v4/include/v4/capsule.h) -- what is sent to an empty node's
|
||||
* port to make it a StarForth node -- and the addresses a host needs, as a
|
||||
* C file (v4/include/v4/image.h). No FORTH source is compiled here: what
|
||||
* is not in the nucleus is loaded from capsules when the system boots.
|
||||
*
|
||||
* The image is the same on every machine it is built on: nothing in it
|
||||
* depends on the build machine but the cell width this tool was compiled
|
||||
* for.
|
||||
*/
|
||||
#include "v4/image.h"
|
||||
#include "v4/capsule.h"
|
||||
#include "v4/text.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -31,6 +33,14 @@ static void die(const char *what, const char *detail)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* one word of the capsule, to the file */
|
||||
static void put_word(void *self, v4_cell word)
|
||||
{
|
||||
v4_ucell u = (v4_ucell)word;
|
||||
unsigned i;
|
||||
for (i = 0; i < V4_CELL_BITS / 8; i++) fputc((int)((u >> (8 * i)) & 0xFFu), (FILE *)self);
|
||||
}
|
||||
|
||||
/* every entry from xt back: no access control fields set */
|
||||
static void clear_acl(v4_cell xt)
|
||||
{
|
||||
@@ -45,7 +55,7 @@ int main(int argc, char **argv)
|
||||
v4_cell k, line, idle, faults, voc;
|
||||
unsigned count = 0;
|
||||
|
||||
if (argc != 2) die("usage: mkimage OUTPUT.c", NULL);
|
||||
if (argc != 3) die("usage: mkimage DESCRIPTION.c CAPSULE.f18", NULL);
|
||||
|
||||
if (!host_load(&tx, &n, files, (unsigned)(sizeof files / sizeof files[0]))) die("the capsule does not assemble", NULL);
|
||||
if (!v4_text_finish(&tx)) die("not everything is defined", v4_text_error(&tx));
|
||||
@@ -89,16 +99,19 @@ int main(int argc, char **argv)
|
||||
for (voc = n.mem[VOC_LINK]; voc != 0; voc = n.mem[voc + 1]) clear_acl(n.mem[voc]);
|
||||
if (!v4_node_guards_intact(&n)) die("the node's guards are damaged", NULL);
|
||||
|
||||
n.mem[LINE_STATUS] = V4_LINE_COMPLETED; /* idle, with nothing to report */
|
||||
|
||||
/* the nucleus as a capsule of F18 code: the words a neighbour writes to
|
||||
* an empty node's port, each in V4_CELL_BITS / 8 bytes, low byte first */
|
||||
out = fopen(argv[2], "wb");
|
||||
if (!out) die("cannot write", argv[2]);
|
||||
count = v4_capsule_write(&n, idle, put_word, out);
|
||||
if (fclose(out) != 0) die("cannot write", argv[2]);
|
||||
|
||||
out = fopen(argv[1], "w");
|
||||
if (!out) die("cannot write", argv[1]);
|
||||
fprintf(out, "/* Generated by v4/tools/mkimage.c from v4/capsule -- do not edit. */\n#include \"v4/image.h\"\n\n");
|
||||
fprintf(out, "static const v4_image_cell cells[] = {\n");
|
||||
for (k = 0; k < (v4_cell)V4_NODE_WORDS; k++)
|
||||
if (n.mem[k] != 0) {
|
||||
fprintf(out, " { %ld, (v4_cell)0x%llxULL },\n", (long)k, (unsigned long long)(v4_ucell)n.mem[k]);
|
||||
count++;
|
||||
}
|
||||
fprintf(out, "};\n\nconst v4_image v4_capsule_image = {\n cells, %uu,\n %uu, %uu, %uu, %uu,\n", count,
|
||||
fprintf(out, "const v4_image v4_capsule_image = {\n %uu, %uu, %uu, %uu,\n",
|
||||
(unsigned)V4_CELL_BITS, (unsigned)V4_NODE_WORDS, (unsigned)V4_DATA_RING, (unsigned)V4_RET_RING);
|
||||
fprintf(out, " %ld, %ld, %ld,\n %ld, %uu, %ld,\n %ld, %ld,\n %ld, %ld,\n", (long)line, (long)idle, (long)LINE_STATUS,
|
||||
(long)TIB, 1025u, (long)SPAN, (long)faults, (long)PORT, (long)w_key, (long)w_key_end);
|
||||
@@ -106,6 +119,6 @@ int main(int argc, char **argv)
|
||||
(long)DSTACK_REG, (long)RSTACK_REG, (long)NODE_ERROR, (long)STORAGE_REG, (long)DP, (long)LATEST,
|
||||
(long)BOOT_CELLS, (long)FENCE);
|
||||
if (fclose(out) != 0) die("cannot write", argv[1]);
|
||||
fprintf(stderr, "mkimage: %u words of memory, dictionary to word %ld, %d-bit cells -> %s\n", count, (long)((n.mem[DP] + 3) / 4), V4_CELL_BITS, argv[1]);
|
||||
fprintf(stderr, "mkimage: a capsule of %u words, dictionary to word %ld, %d-bit cells -> %s, %s\n", count, (long)((n.mem[DP] + 3) / 4), V4_CELL_BITS, argv[2], argv[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user