feat(v4.0.0): a node is sent text as a message and sends back what it prints
MESH.md step 3. The ports are the transport; the message is what is transported: to, from, type, heat and TTL, ACL tag, sequence, length, then text four characters to a word. - quit.v4: a node with nothing to do is blocked reading "any port"; text for it is interpreted; (FINISH) sends what it printed and then how the text ended, and it waits again - core.v4: EMIT keeps what is printed, (FLUSH-OUT) and (HDR) send it to the sender on the port the message came on. EMIT still needs one free data cell and no more; it works on the return stack and in A and B - message.h/.c: the same format for whatever is on a port and is not a node - boot.c: the boot is the node's console on port 1 and its kernel on port 0 - the prompt tests are a console that speaks messages - gone: v4_line_begin, v4_line_done, v4_line_status; writing a node's input buffer and setting its P from outside; any use of CONSOLE-TX Verified: make -C v4 test (test_host_quit.c 1283 checks, the full-stack figures unchanged) and make -C v4 sanitize pass; hosted-check passes on three ISAs with POST 550 of 550; clean qemu with STARFORTH_V4=1 passes POST and answers lines typed at each prompt on amd64, aarch64 and riscv64 (logs/20261006-110551, -111621, -111341). -110837 is an aarch64 run ended by the test wrapper's limit while still in UEFI firmware; it shows nothing about v4. Not done: KEY, EXPECT and QUERY still read the console's input registers; a message not for this node is let go (step 4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
42610e844f
commit
a041b401ea
+56
-16
@@ -5,6 +5,7 @@
|
||||
* which only a whole system has.
|
||||
*/
|
||||
#include "v4/boot.h"
|
||||
#include "v4/message.h"
|
||||
#include "starkernel/capsule.h"
|
||||
#include "starkernel/capsule_generated.h"
|
||||
#include "starkernel/capsule_sig.h"
|
||||
@@ -126,22 +127,29 @@ static void post_watch(char c)
|
||||
post_len = 0;
|
||||
}
|
||||
|
||||
/* The boot is the node's neighbour on two of its ports. On port 0 it is
|
||||
* the kernel: the node writes the number of a request there (ENGINE.md
|
||||
* 3.3). On port 1 it is the console: it writes the node a message of text
|
||||
* and reads back messages of what the node printed and of how the text
|
||||
* ended (message.h). */
|
||||
#define KERNEL_PORT 0u
|
||||
#define CONSOLE_PORT 1u
|
||||
#define CONSOLE_ID 1 /* the console's number as a sender; the node's is 0 until it is given one */
|
||||
|
||||
int v4_boot_line(const v4_boot *b, const char *text, unsigned len)
|
||||
{
|
||||
static v4_message out, in; /* one line at a time: the boot is not re-entered */
|
||||
v4_node *n = b->n;
|
||||
uint64_t steps = 0;
|
||||
unsigned i;
|
||||
unsigned sent = 0, i;
|
||||
|
||||
if (!v4_line_begin(n, b->im, text, len)) return V4_BOOT_LINE_TOO_LONG;
|
||||
if (!v4_message_text(&out, 0, CONSOLE_ID, V4_MSG_TEXT, text, len)) return V4_BOOT_LINE_TOO_LONG;
|
||||
in.count = 0;
|
||||
for (;;) {
|
||||
(void)v4_exec_step_word(n, b->es, b->h);
|
||||
if (n->console_len) {
|
||||
for (i = 0; i < n->console_len; i++) post_watch((char)n->console[i]);
|
||||
b->out((const char *)n->console, n->console_len);
|
||||
n->console_len = 0;
|
||||
}
|
||||
if (n->stopped) return V4_BOOT_LINE_STOPPED;
|
||||
if (n->asking) { /* blocked at its port: the kernel's turn */
|
||||
|
||||
if (n->asking && n->ask_port == KERNEL_PORT) { /* a request: the kernel's turn */
|
||||
if (b->serve && n->request >= 1 && n->request <= (v4_cell)b->word_count) {
|
||||
b->serve(n, (unsigned)n->request);
|
||||
v4_node_port_served(n);
|
||||
@@ -153,8 +161,34 @@ int v4_boot_line(const v4_boot *b, const char *text, unsigned len)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (v4_line_done(n, b->im)) return v4_line_status(n, b->im);
|
||||
if (v4_image_waiting(n, b->im)) { /* the line is reading the keyboard */
|
||||
if (n->asking && n->ask_port == CONSOLE_PORT) { /* a word of a message from the node */
|
||||
v4_cell word = n->request;
|
||||
v4_node_port_served(n);
|
||||
if (v4_message_word(&in, word)) {
|
||||
unsigned chars = v4_message_length(&in);
|
||||
if (v4_message_type(&in) == V4_MSG_OUTPUT) {
|
||||
for (i = 0; i < chars; i++) {
|
||||
char c = v4_message_char(&in, i);
|
||||
post_watch(c);
|
||||
b->out(&c, 1);
|
||||
}
|
||||
} else if (v4_message_type(&in) == V4_MSG_DONE) {
|
||||
return (int)in.word[V4_MSG_HEADER];
|
||||
}
|
||||
in.count = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (n->asking) return V4_BOOT_LINE_STOPPED; /* a port with nothing on it */
|
||||
|
||||
if (n->reading && !n->given) {
|
||||
if (sent < out.count && (n->read_port == CONSOLE_PORT || n->read_port == V4_PORT_ANY)) {
|
||||
v4_node_port_give(n, CONSOLE_PORT, out.word[sent++]); /* a word of the message to the node */
|
||||
continue;
|
||||
}
|
||||
return V4_BOOT_LINE_STOPPED; /* waiting for what will not come */
|
||||
}
|
||||
if (v4_image_waiting(n, b->im)) { /* the text is reading the keyboard */
|
||||
int c = b->key ? b->key() : V4_BOOT_KEY_END;
|
||||
unsigned char ch = (unsigned char)c;
|
||||
if (c == V4_BOOT_KEY_END) return V4_BOOT_LINE_NO_INPUT;
|
||||
@@ -225,10 +259,10 @@ static int load_capsule(const v4_boot *b, const char *name)
|
||||
if (len) {
|
||||
for (i = 0; i < len; i++) text[i] = (char)p[i];
|
||||
int how = v4_boot_line(b, text, len);
|
||||
if (how != V4_LINE_COMPLETED) {
|
||||
if (how != V4_TEXT_COMPLETED) {
|
||||
say_where(b, name, block, line);
|
||||
say(b, how == V4_LINE_ERROR ? " ended in an error: "
|
||||
: how == V4_LINE_QUIT ? " ended with QUIT: "
|
||||
say(b, how == V4_TEXT_ERROR ? " ended in an error: "
|
||||
: how == V4_TEXT_QUIT ? " ended with QUIT: "
|
||||
: how == V4_BOOT_LINE_NO_INPUT ? " reads the keyboard: "
|
||||
: " stopped the node: ");
|
||||
b->out(text, len); say(b, "\n");
|
||||
@@ -289,7 +323,9 @@ static int load_nucleus(const v4_boot *b)
|
||||
if (!p || cap->length % CELL_BYTES != 0) { say(b, "V4: capsule " NUCLEUS_NAME " is not whole words\n"); return 0; }
|
||||
words = cap->length / CELL_BYTES;
|
||||
|
||||
while (at < words || !v4_line_done(n, b->im)) {
|
||||
/* until it has taken every word and is waiting for a message: reading
|
||||
* its ports again, but from its memory now and not from the port */
|
||||
while (at < words || !(n->reading && !n->given && n->p != b->im->port + (v4_cell)V4_PORT_ANY)) {
|
||||
(void)v4_exec_step_word(n, b->es, b->h);
|
||||
if (n->stopped || n->asking || ++steps > STEP_LIMIT) {
|
||||
say(b, "V4: the node did not take the nucleus in\n");
|
||||
@@ -298,7 +334,11 @@ static int load_nucleus(const v4_boot *b)
|
||||
if (n->reading && !n->given) {
|
||||
v4_ucell word = 0;
|
||||
unsigned i;
|
||||
if (at >= words) { say(b, "V4: the node wants more than the nucleus holds\n"); return 0; }
|
||||
if (at >= words) {
|
||||
if (n->p != b->im->port + (v4_cell)V4_PORT_ANY) break; /* it is waiting for a message */
|
||||
say(b, "V4: the node wants more than the nucleus holds\n");
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < CELL_BYTES; i++) word |= (v4_ucell)p[at * CELL_BYTES + i] << (8 * i);
|
||||
v4_node_port_give(n, 0, (v4_cell)word);
|
||||
at++;
|
||||
@@ -335,7 +375,7 @@ int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks)
|
||||
for (; div; div /= 10) text[at++] = (char)('0' + num / div % 10);
|
||||
for (k = 0; " KERNEL-WORD "[k]; k++) text[at++] = " KERNEL-WORD "[k];
|
||||
for (k = 0; b->words[i][k] && at < sizeof text; k++) text[at++] = b->words[i][k];
|
||||
if (b->words[i][k] || v4_boot_line(b, text, at) != V4_LINE_COMPLETED) {
|
||||
if (b->words[i][k] || v4_boot_line(b, text, at) != V4_TEXT_COMPLETED) {
|
||||
say(b, "V4: kernel word "); say(b, b->words[i]); say(b, " could not be made\nPARITY:FAIL\nPOST: FAILED\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user