A block is a kernel request, as ENGINE.md 3.3 has it: the node puts the
block's number and the address of 256 cells on its stack and writes the
request to port 0, and the kernel leaves the status there. The requests
are -1, read, and -2, write, the same for every node. v4/system/blocks.c
serves them from the kernel's block subsystem, which is v3's. The four
storage registers are gone from the engine.
The device that spoke block messages (4a505a15) is withdrawn with its
test and its message types: Captain Bob ruled on 2026-10-07 that it, a
node's own drive, and nodes with no storage had left the OS as designed
(docs/v4.0.0/MESH.md 8.5).
Hera no longer sends POST to the nodes she births: POST is the kernel's,
once. Every node has its kernel on port 0; it serves a node's blocks and,
for Hera alone, her requests for nodes and capsules.
Bare metal: the node boots and is POSTed against POST's own block RAM,
and the kernel's chain -- fast RAM, the ramdrive, the virtio disk -- is
set up after POST and before the prompt, as on the v3 path. The disk is
read and not written: nothing in v4 yet gives the owner's word that it
may be formatted. A hosted program has the chain's fast RAM, as hosted
v3 has with no disk. Error 17 is Storage refused.
make -C v4 test and sanitize pass at both widths; hosted-check passes on
three ISAs; amd64, aarch64 and riscv64 boot, POST 538 of 538, with the
typed session: logs/20261007-081603, -081839, -082226. The hashes are
the same on all six.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
123 lines
5.4 KiB
C
123 lines
5.4 KiB
C
/* mkimage.c -- build the capsule image (include/v4/image.h).
|
|
*
|
|
* 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 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>
|
|
#include <string.h>
|
|
|
|
#include "../tests/host_map.h"
|
|
|
|
static v4_node n;
|
|
static v4_text tx;
|
|
static v4_cell w_key, w_key_end;
|
|
|
|
static void die(const char *what, const char *detail)
|
|
{
|
|
fprintf(stderr, "mkimage: %s%s%s\n", what, detail ? ": " : "", detail ? 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)
|
|
{
|
|
for (; xt != 0; xt = n.mem[xt - 1]) n.mem[xt - 3] &= 31;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
static const char *const files[] = { "core.v4", "input.v4", "dict.v4", "codegen.v4", "compile.v4", "quit.v4", "forth.v4",
|
|
"numout.v4", "words.v4", "system.v4", "qmath.v4", "blocks.v4", "log.v4", "acl.v4" };
|
|
FILE *out;
|
|
v4_cell k, idle, faults, voc;
|
|
unsigned count = 0;
|
|
|
|
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));
|
|
if (v4_text_here(&tx) >= DICT_W) die("the capsule's code runs into the dictionary space", NULL);
|
|
idle = v4_text_word(&tx, "(IDLE)");
|
|
faults = v4_text_word(&tx, "(FAULTS)");
|
|
w_key = v4_text_word(&tx, "KEY");
|
|
w_key_end = v4_text_word(&tx, "CR");
|
|
|
|
/* the variables, as at switch-on */
|
|
n.mem[DP] = DICT_W * 4;
|
|
n.mem[LATEST] = v4_text_latest(&tx);
|
|
n.mem[STATE] = 0;
|
|
n.mem[CFP] = CFS_W;
|
|
n.mem[BASE] = 10;
|
|
n.mem[FENCE] = DICT_W;
|
|
n.mem[LOG_LEVEL] = 2;
|
|
n.mem[CONTEXT] = LATEST;
|
|
n.mem[CURRENT] = LATEST;
|
|
n.mem[SRC] = TIB;
|
|
|
|
/* The nucleus is the system as COLD finds it: COLD comes back to here,
|
|
* and FORGET will not go below it. What the capsules add at boot
|
|
* (v4/system/boot.c) is above it. */
|
|
n.mem[BOOT_CELLS] = n.mem[DP];
|
|
n.mem[BOOT_CELLS + 1] = n.mem[LATEST];
|
|
n.mem[FENCE] = (n.mem[DP] + 3) / 4;
|
|
/* and nothing of the building is left behind: the terminal is the input,
|
|
* no block is in a buffer, no word has an access control field set */
|
|
n.mem[NODE_ERROR] = 0;
|
|
n.mem[BLK] = 0; n.mem[SCR] = 0; n.mem[SRC] = TIB; n.mem[SRC_HOOK] = 0;
|
|
for (k = BVARS; k < BVARS + 6; k++) n.mem[k] = 0;
|
|
for (k = BUF0_W; k < BUF0_W + 2 * 256; k++) n.mem[k] = 0;
|
|
for (k = TIB_W; k < TIB_W + 260; k++) n.mem[k] = 0;
|
|
for (k = WBUF_W; k < WBUF_W + WBUF_CELLS; k++) n.mem[k] = 0;
|
|
for (k = PAD_W; k < PAD_W + 21; k++) n.mem[k] = 0;
|
|
n.mem[TO_IN] = 0; n.mem[SPAN] = 0;
|
|
clear_acl(n.mem[LATEST]);
|
|
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] = 1; /* nothing has ended badly */
|
|
HOST_MESSAGES_EMPTY(&n); /* nothing has been printed, no message waits */
|
|
|
|
/* 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, "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,\n %ld, %ld,\n %ld, %ld,\n", (long)idle, (long)faults, (long)PORT, (long)w_key, (long)w_key_end);
|
|
fprintf(out, " %ld, %ld, %ld,\n %ld, %ld,\n %ld,\n %ld, %ld,\n %ld, %ld\n};\n", (long)CONSOLE_TX, (long)CONSOLE_RX, (long)CONSOLE_ST,
|
|
(long)DSTACK_REG, (long)RSTACK_REG, (long)NODE_ERROR, (long)DP, (long)LATEST,
|
|
(long)BOOT_CELLS, (long)FENCE);
|
|
if (fclose(out) != 0) die("cannot write", 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;
|
|
}
|