feat(v4.0.0): a node asks its kernel by a blocking write to its port
ENGINE.md step 2, the carrier. Ruled 2026-10-05 (V3-PARITY.md 1i), on DECOMPOSITION.md section 6: a write to a port blocks until the neighbour reads. - node: v4_node_port_attach, v4_node_port_served; a store to the port keeps the value as the request and blocks the node - exec: a blocked node executes nothing; served, it goes on from the opcode after the store, in the same instruction word; a fault meanwhile abandons the rest of the word - compile.v4: n KERNEL-WORD name makes a word whose body writes n to the port; its arguments and results are on the data stack - boot: the kernel's words are made by handing the node text, and requests are served between the node's opcodes; one no one serves is error 12 - BYE, the first kernel word: hosted it leaves the program, as hosted v3; on the lone node it is v3's cold restart - ENGINE.md 3a: multiuser, multitasking, preemptive and cooperative, and what that asks of the engine Verified: make -C v4 test passes at both widths, with tests/test_port.c; hosted-check passes on three ISAs; clean qemu with STARFORTH_V4=1 on amd64, aarch64 and riscv64 passes POST with the same hashes as hosted, and a kernel word no one serves and BYE typed at each prompt are answered (logs/20261005-185506, -185734, -190101; -185234 is an amd64 run in which those two lines were not typed). Not done: v3's own C functions serving a node. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5f1f60fc84
commit
8df6c16766
@@ -41,6 +41,18 @@ typedef struct {
|
||||
const v4_image *im; /* the nucleus */
|
||||
void (*out)(const char *text, unsigned len); /* the console */
|
||||
int (*key)(void); /* a character for a line that reads the keyboard, or 0: there is none */
|
||||
|
||||
/* THE KERNEL'S WORDS (docs/v4.0.0/ENGINE.md 3.3). `words` names them,
|
||||
* `word_count` of them; the boot makes each a word on the node (KERNEL-
|
||||
* WORD, v4/capsule/compile.v4) whose request number is its place in the
|
||||
* list, counting from 1. When the node writes a request to its port it
|
||||
* is blocked, and `serve` is called with the number: it takes the
|
||||
* word's arguments from the node's data stack and leaves its results
|
||||
* there, and when it returns the node goes on. A request that is not
|
||||
* in the list is an error on the node: 12, Argument out of range. */
|
||||
const char *const *words;
|
||||
unsigned word_count;
|
||||
void (*serve)(v4_node *n, unsigned request);
|
||||
} v4_boot;
|
||||
|
||||
/* What `key` returns when it has no character. */
|
||||
|
||||
@@ -36,6 +36,14 @@
|
||||
|
||||
typedef struct {
|
||||
v4_uheat_t anticlock;
|
||||
|
||||
/* A node blocked at its port in the middle of an instruction word
|
||||
* (node.h) goes on, when it has been served, from the slot after the
|
||||
* store: the word and the slot are kept here meanwhile. */
|
||||
int resume;
|
||||
v4_iword resume_iw;
|
||||
unsigned resume_slot;
|
||||
unsigned resume_faults; /* n->faults when it blocked: a fault since then means P is a handler and the rest of the word is abandoned */
|
||||
} v4_exec_state;
|
||||
|
||||
void v4_exec_reset(v4_exec_state *es);
|
||||
|
||||
@@ -40,6 +40,7 @@ typedef struct {
|
||||
unsigned tib_bytes; /* its size: a line may be one less */
|
||||
v4_cell span; /* word address of the variable SPAN */
|
||||
v4_cell fault_table; /* (FAULTS): where a fault goes */
|
||||
v4_cell port; /* word address of the node's port (node.h) */
|
||||
|
||||
/* KEY's code: a node whose P is in key_start .. key_end - 1 with no
|
||||
* character pending is waiting for one */
|
||||
|
||||
@@ -88,6 +88,13 @@ typedef struct {
|
||||
unsigned faults; /* how many there have been */
|
||||
int stopped; /* non-zero: faulted with no handler */
|
||||
|
||||
/* The port (DECOMPOSITION.md section 6): a write to it blocks the node
|
||||
* until its neighbour has taken what was written. See
|
||||
* v4_node_port_attach below. */
|
||||
v4_cell port; /* its word address, or -1: no port */
|
||||
int asking; /* non-zero: blocked, having written `request` */
|
||||
v4_cell request; /* what it wrote */
|
||||
|
||||
/* DSTACK-DEPTH and RSTACK-DEPTH (D-16). See v4_node_stack_regs_attach. */
|
||||
v4_cell dstack_reg; /* its word address, or -1 */
|
||||
v4_cell rstack_reg; /* its word address, or -1 */
|
||||
@@ -149,6 +156,28 @@ void v4_node_store(v4_node *n, v4_cell addr, v4_cell value);
|
||||
* Passing -1 detaches. The address is the caller's choice. */
|
||||
void v4_node_console_attach(v4_node *n, v4_cell addr);
|
||||
|
||||
/* THE PORT. A node reaches its neighbour through a port, and a port is an
|
||||
* address (DECOMPOSITION.md section 6): "a write blocks until the neighbour
|
||||
* reads. This is the GA144 model. No instruction is added."
|
||||
*
|
||||
* After v4_node_port_attach(n, addr), a store to word address `addr` does
|
||||
* not write memory: the node keeps the value in n->request, sets n->asking
|
||||
* and is blocked. A blocked node executes nothing -- v4_exec_step_word
|
||||
* returns 0 and changes nothing -- until its neighbour calls
|
||||
* v4_node_port_served(n). It then goes on from the opcode after the store,
|
||||
* in the same instruction word if there are any left.
|
||||
*
|
||||
* This is how a node asks its kernel for something (docs/v4.0.0/ENGINE.md
|
||||
* 3.3): the neighbour on the port is the kernel, what is written is the
|
||||
* number of the request, and the arguments and results are on the node's
|
||||
* data stack, which the kernel may use while the node is blocked. Only the
|
||||
* write is here. Nothing reads from a port yet, and a fetch from the
|
||||
* address is a fetch from memory.
|
||||
*
|
||||
* A node has no port until one is attached: v4_node_reset detaches it. */
|
||||
void v4_node_port_attach(v4_node *n, v4_cell addr);
|
||||
void v4_node_port_served(v4_node *n);
|
||||
|
||||
/* CONSOLE-RX and CONSOLE-STATUS, the console's receive side, on the
|
||||
* single-node model.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user