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
@@ -5,7 +5,7 @@
|
||||
* (kernel/src/v4/sk_v4.c) both call v4_boot_run and differ only in where
|
||||
* the text goes. So the two start the same way and print the same lines:
|
||||
*
|
||||
* PARITY:V4_NUCLEUS words=N image_hash=0x...
|
||||
* PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0x... capsule_hash=0x... words=N
|
||||
* PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x... capsule_hash=0x... dict_hash=0x...
|
||||
* PARITY:V4_POST tests=N pass=N fail=N (printed by the POST capsule)
|
||||
* PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0x... capsule_hash=0x... dict_hash=0x...
|
||||
@@ -59,8 +59,8 @@ typedef struct {
|
||||
#define V4_BOOT_KEY_NONE (-1) /* not yet: it is asked again */
|
||||
#define V4_BOOT_KEY_END (-2) /* and there never will be */
|
||||
|
||||
/* Start the node from the nucleus image, with `disk` as its block storage
|
||||
* (see v4_image_boot), and load the capsules. Returns 1 with the node idle,
|
||||
/* A node is born empty, with `disk` as its block storage (v4_image_born);
|
||||
* it is sent the nucleus through its port; and the capsules are loaded. Returns 1 with the node idle,
|
||||
* waiting to be handed a line; or 0, the failure printed. It prints no
|
||||
* prompt: that is the host's. */
|
||||
int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/* capsule.h -- a capsule of F18 code: what a neighbour writes to a node's
|
||||
* port to put a programme into it and start it. docs/v4.0.0/MESH.md
|
||||
* section 5.
|
||||
*
|
||||
* A node newly born has nothing in it and executes what arrives at its port
|
||||
* (node.h). So a capsule of F18 code is not a format a node has to
|
||||
* understand: it is the words themselves, in the order they are sent. For
|
||||
* each stretch of memory that is not zero,
|
||||
*
|
||||
* @p a! @p push the node executes this from its port,
|
||||
* address takes these two as its literals,
|
||||
* count - 1
|
||||
* @p !+ unext and then this: each word that follows is fetched
|
||||
* the words ... from the port and stored
|
||||
*
|
||||
* and at the end
|
||||
*
|
||||
* jump start
|
||||
*
|
||||
* This is the F18's own way of loading a node through a port. Nothing here
|
||||
* knows what the programme is: StarForth's nucleus is one such capsule
|
||||
* (v4/tools/mkimage.c), and anything written for the node is another.
|
||||
*/
|
||||
#ifndef V4_CAPSULE_H
|
||||
#define V4_CAPSULE_H
|
||||
|
||||
#include "v4/node.h"
|
||||
|
||||
/* Write the capsule that makes a node's memory what `n`'s is, and starts it
|
||||
* at `start`: `out` is called with each word in turn. Words of `n` that
|
||||
* are zero are not sent -- a node is born with its memory zero. Returns
|
||||
* how many words were written. */
|
||||
unsigned v4_capsule_write(const v4_node *n, v4_cell start,
|
||||
void (*out)(void *self, v4_cell word), void *self);
|
||||
|
||||
#endif /* V4_CAPSULE_H */
|
||||
+21
-25
@@ -1,31 +1,24 @@
|
||||
/* image.h -- a capsule image: the host node's memory with the vocabulary in
|
||||
* it, and what a loader needs to know to start it.
|
||||
/* image.h -- the StarForth nucleus, as its host knows it: where things are
|
||||
* in a node that has taken it in, and how a line is handed to that node.
|
||||
*
|
||||
* The compiler capsule is text (capsule/ *.v4) and FORTH source (capsule/
|
||||
* *.fth). tools/mkimage.c assembles the one and has a node compile the
|
||||
* other, on the build machine, and writes what the node's memory then holds
|
||||
* as a C file. A system that is to run the vocabulary -- the hosted binary,
|
||||
* the bare-metal kernel -- links that file and calls v4_image_boot: it needs
|
||||
* no assembler, no files and no C library.
|
||||
* The nucleus is text (capsule/ *.v4). tools/mkimage.c assembles it on the
|
||||
* build machine and writes two things:
|
||||
*
|
||||
* An image is for one cell width, one node size and one pair of stack sizes;
|
||||
* v4_image_boot refuses an image the engine was not built for.
|
||||
* - the nucleus as a capsule of F18 code (capsule.h), which is put into
|
||||
* an empty node through its port. It is a capsule like any other: in
|
||||
* the capsule directory, with a name, a hash and a signature
|
||||
* (capsules/v4/nucleus-<width>.f18). docs/v4.0.0/MESH.md section 5.
|
||||
* - this description of it, a C file: the addresses a host needs.
|
||||
*
|
||||
* A description is for one cell width, one node size and one pair of stack
|
||||
* sizes; v4_image_born refuses one the engine was not built for.
|
||||
*/
|
||||
#ifndef V4_IMAGE_H
|
||||
#define V4_IMAGE_H
|
||||
|
||||
#include "v4/exec.h"
|
||||
|
||||
/* one word of memory that is not zero */
|
||||
typedef struct {
|
||||
v4_cell addr;
|
||||
v4_cell value;
|
||||
} v4_image_cell;
|
||||
|
||||
typedef struct {
|
||||
const v4_image_cell *cells; /* every non-zero word of memory, in address order */
|
||||
unsigned count;
|
||||
|
||||
/* what the image was built for */
|
||||
unsigned cell_bits, node_words, data_ring, ret_ring;
|
||||
|
||||
@@ -66,7 +59,8 @@ typedef struct {
|
||||
v4_cell boot_cells, fence;
|
||||
} v4_image;
|
||||
|
||||
/* The image built from v4/capsule (the generated file defines it). */
|
||||
/* The description of the nucleus built from v4/capsule (the generated file
|
||||
* defines it). */
|
||||
extern const v4_image v4_capsule_image;
|
||||
|
||||
/* The system is complete: what is in the dictionary now is what COLD comes
|
||||
@@ -78,11 +72,13 @@ void v4_image_seal(v4_node *n, const v4_image *im);
|
||||
#define V4_LINE_COMPLETED 1 /* the host says " ok" */
|
||||
#define V4_LINE_ERROR 2 /* the message is printed; the host says " ERROR" */
|
||||
|
||||
/* Reset `n`, load the image into it, attach its registers -- with `disk`,
|
||||
* `blocks` blocks of 1024 bytes, as its block storage, or none if `disk` is
|
||||
* 0 -- and leave it idle, waiting to be handed a line. Returns 1, or 0 if
|
||||
* the image is not for this build of the engine (nothing is then done). */
|
||||
int v4_image_boot(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im,
|
||||
/* A node newly born (node.h), with the registers the nucleus expects of the
|
||||
* node it runs on -- and `disk`, `blocks` blocks of 1024 bytes, as its block
|
||||
* storage, or none if `disk` is 0. Its memory is empty and it is blocked
|
||||
* reading its ports: the nucleus is yet to be sent to it. Returns 1, or 0
|
||||
* if the description is not for this build of the engine (nothing is then
|
||||
* done). */
|
||||
int v4_image_born(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im,
|
||||
unsigned char *disk, unsigned blocks);
|
||||
|
||||
/* Hand the node `len` characters of text to interpret. Returns 1, or 0 if
|
||||
|
||||
Reference in New Issue
Block a user