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:
rajames
2026-10-05 19:03:03 -04:00
co-authored by Claude Opus 5.5
parent 5f1f60fc84
commit 8df6c16766
21 changed files with 908 additions and 21 deletions
+18 -8
View File
@@ -59,19 +59,20 @@ State, 2026-10-05, after `ENGINE.md` step 1: all six builds start the nucleus,
load `v4:forth79.4th`, pass POST and reach `ok>`, with the same lines:
```
PARITY:V4_NUCLEUS words=295 image_hash=0x3b5a9a7a2f7c5361
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=... dict_hash=0xc45c4db43ea0b1f1
PARITY:V4_NUCLEUS words=296 image_hash=0x736921433a2e0e97
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=... dict_hash=0x01a3a48159f28a3e
PARITY:V4_POST tests=550 pass=550 fail=0
PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=... dict_hash=0x88df0873060da73e
PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=... dict_hash=0x212b7b70848080e7
PARITY:OK
POST: PASSED
ok>
```
Bare-metal logs: `logs/20261005-180922/amd64/`, `logs/20261005-181152/aarch64/`,
`logs/20261005-181541/riscv64/`. On each, three lines were then typed at the
Bare-metal logs: `logs/20261005-185506/amd64/`, `logs/20261005-185734/aarch64/`,
`logs/20261005-190101/riscv64/`. On each, six lines were then typed at the
prompt through the serial port — a definition, its use with the capsule's
`U*`, and an unknown word — and each answered as the hosted binary does. The
`U*`, an unknown word, a kernel word no one serves, and `BYE` — and each
was answered as the hosted binary answers it. The
capsules were unsigned (no signing key on this machine).
**A node is handed a line** (`docs/v4.0.0/ENGINE.md` 3.1). It does not read
@@ -84,10 +85,19 @@ may be 1024 characters, a block. `v4_line_begin`, `v4_line_done` and
`v4_boot_line` (`v4/system/boot.c`) is the one loop the hosted binary, the
kernel and the capsule loader all run it with.
**A node asks its kernel by writing to its port** (`ENGINE.md` 3.3). The
write blocks the node until it has been served. A kernel word is a
dictionary entry made by `n KERNEL-WORD name`, whose body writes `n` to the
port; its arguments and results are on the data stack. `BYE` is the one
kernel word so far. A node can be stopped between any two instruction
words and is blocked while it waits at its port, which is what a system of
many users and tasks, preemptive and cooperative, needs of it
(`ENGINE.md` 3a).
**This is still the lone node.** On bare metal `kernel_main.c` starts it
before the fleet tables, beside the kernel's own system and not in the VM's
place. `ENGINE.md` sets out the steps from here; step 1 is the only one
done. `V3-PARITY.md` records the rulings it is built from.
place. `ENGINE.md` sets out the steps from here; step 1 is done and step 2 is
part done. `V3-PARITY.md` records the rulings it is built from.
**What this does not yet show.** `forth79.4th` holds two definitions, `U*`
and `U/MOD`. Every other word is still in the assembled nucleus, so POST is
+14
View File
@@ -246,6 +246,20 @@ header ; immediate compile-only
LATEST (FLAGS) a! @ -3 and !
jump LEFT-BRACKET
\ ( n -- ) KERNEL-WORD xxx A WORD THAT ASKS THE KERNEL (docs/v4.0.0/
\ ENGINE.md 3.3). xxx is made a word whose whole body is "write n to the
\ port": n is the number of a request, the port is the node's way to its
\ kernel, and the write blocks the node until the kernel has served it
\ (DECOMPOSITION.md section 6). xxx's arguments are whatever it finds on
\ the data stack and its results are what the kernel leaves there. This is
\ what a word that is a C function in v3 -- BIRTH, BLOCK, BYE -- is on a
\ node. Not FORTH-79 and not in v3, where such a word is registered from C.
\ The constant (PORT) is the port's word address.
header KERNEL-WORD
: KERNEL-WORD
COLON (LIT,) (PORT) (LIT,) 30 (OP,) 14 (OP,) \ n port b! !b
jump SEMICOLON
\ FORTH-79: return from the definition at this point
header EXIT immediate compile-only
: EXIT 0 jump (OP,)
+12
View File
@@ -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. */
+8
View File
@@ -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);
+1
View File
@@ -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 */
+29
View File
@@ -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.
*
+30 -5
View File
@@ -87,6 +87,10 @@ static int stack_faulted(v4_node *n, unsigned op)
void v4_exec_reset(v4_exec_state *es)
{
es->anticlock = 0;
es->resume = 0;
es->resume_iw = 0;
es->resume_slot = 0;
es->resume_faults = 0;
}
void v4_exec_op(v4_node *n, v4_exec_state *es, v4_heat *h,
@@ -244,11 +248,21 @@ unsigned v4_exec_step_word(v4_node *n, v4_exec_state *es, v4_heat *h)
unsigned executed = 0;
unsigned slot = 0;
/* D-14: a node that faulted with no handler has stopped; and P itself
* may be what is outside memory. */
if (n->stopped || faulted(n, n->p)) return 0;
iw = fetch_iword(n, n->p);
n->p = add_wrap(n->p, 1);
/* D-14: a node that faulted with no handler has stopped. A node that
* has written to its port is blocked until it has been served. */
if (n->stopped || n->asking) return 0;
if (es->resume && es->resume_faults != n->faults) es->resume = 0; /* it faulted while blocked: P is the handler */
if (es->resume) {
/* served: the rest of the word the store was in */
es->resume = 0;
iw = es->resume_iw;
slot = es->resume_slot;
} else {
/* P itself may be what is outside memory */
if (faulted(n, n->p)) return 0;
iw = fetch_iword(n, n->p);
n->p = add_wrap(n->p, 1);
}
while (slot < V4_SLOT_COUNT) {
unsigned op = v4_iword_op(iw, slot);
@@ -264,6 +278,17 @@ unsigned v4_exec_step_word(v4_node *n, v4_exec_state *es, v4_heat *h)
}
executed++;
if (n->asking) {
/* The store was to the port. The node is blocked here; what is
* left of the word waits until it has been served. */
if (slot + 1 < V4_SLOT_COUNT) {
es->resume = 1;
es->resume_iw = iw;
es->resume_slot = slot + 1;
es->resume_faults = n->faults;
}
break;
}
if (again) {
/* Same word, slot 0, no refetch and P untouched: an `@p` or `!p`
* inside a unext loop therefore walks the words that follow, as
+1
View File
@@ -24,6 +24,7 @@ int v4_image_boot(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im,
v4_node_stack_regs_attach(n, im->dstack_reg, im->rstack_reg);
v4_node_error_attach(n, im->node_error);
v4_node_fault_attach(n, im->fault_table);
v4_node_port_attach(n, im->port);
if (disk && blocks) v4_node_storage_attach(n, im->storage_reg, disk, blocks);
n->mem[im->line_status] = V4_LINE_COMPLETED;
+16
View File
@@ -17,6 +17,7 @@ void v4_node_reset(v4_node *n)
v4_node_fault_attach(n, -1);
v4_node_stack_regs_attach(n, -1, -1);
v4_node_error_attach(n, -1);
v4_node_port_attach(n, -1);
v4_node_storage_attach(n, -1, 0, 0);
}
@@ -119,6 +120,9 @@ void v4_node_store(v4_node *n, v4_cell addr, v4_cell value)
n->console_dropped++;
return;
}
/* The port: the node keeps what it wrote and is blocked until its
* neighbour has taken it. -1 when no port is attached. */
if (addr == n->port) { n->request = value; n->asking = 1; return; }
/* The stack registers: a store empties the stack. -1 when not attached. */
if (addr == n->dstack_reg) { v4_dstack_clear(&n->ds); return; }
if (addr == n->rstack_reg) { v4_rstack_clear(&n->rs); return; }
@@ -177,3 +181,15 @@ void v4_node_console_attach(v4_node *n, v4_cell addr)
n->console_len = 0;
n->console_dropped = 0;
}
void v4_node_port_attach(v4_node *n, v4_cell addr)
{
n->port = addr;
n->asking = 0;
n->request = 0;
}
void v4_node_port_served(v4_node *n)
{
n->asking = 0;
}
+26
View File
@@ -152,6 +152,18 @@ int v4_boot_line(const v4_boot *b, const char *text, unsigned 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 (b->serve && n->request >= 1 && n->request <= (v4_cell)b->word_count) {
b->serve(n, (unsigned)n->request);
v4_node_port_served(n);
} else {
/* a request no one serves is an error, as any other (D-18):
* 12, Argument out of range */
v4_node_port_served(n);
v4_node_store(n, n->error_reg, 12); /* a store to NODE-ERROR raises it */
}
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 */
int c = b->key ? b->key() : V4_BOOT_KEY_END;
@@ -261,6 +273,20 @@ int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks)
say(b, " image_hash="); say_hex(b, image_hash(b->im));
say(b, "\n");
/* the kernel's words, before any capsule that might use one */
for (i = 0; i < b->word_count; i++) {
char text[64];
unsigned at = 0, k, num = i + 1, div = 1;
while (num / div >= 10) div *= 10;
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) {
say(b, "V4: kernel word "); say(b, b->words[i]); say(b, " could not be made\nPARITY:FAIL\nPOST: FAILED\n");
return 0;
}
}
for (i = 0; i < sizeof boot_capsules / sizeof boot_capsules[0]; i++)
if (!load_capsule(b, boot_capsules[i])) { say(b, "PARITY:FAIL\nPOST: FAILED\n"); return 0; }
#if V4_POST_AT_BOOT
+2
View File
@@ -68,6 +68,7 @@
#define EMIT_HOOK (BUF0_W - 7) /* the xt of a word EMIT gives its character to, or 0: the console */
#define CATCH (BUF0_W - 8) /* non-zero: a line's error is recorded here, -1, and the line ends " ok" */
#define LINE_STATUS (BUF0_W - 9) /* how the last line ended: 0 QUIT, 1 completed, 2 an error */
#define PORT (BUF0_W - 10) /* the node's port: a write to it blocks until its neighbour, the kernel, has served it */
#define LOG_LEVEL (BUF0_W - 5) /* the level at or below which a message is printed */
#define BOOT_CELLS (BVARS + 14) /* (BOOT): DP and LATEST as the loader left them, 2 cells */
#define BUF0_W (BVARS - 2 * 256) /* the two block buffers, 256 cells each */
@@ -144,6 +145,7 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned
v4_text_constant(tx, "(EMIT-HOOK)", EMIT_HOOK);
v4_text_constant(tx, "(CATCH)", CATCH);
v4_text_constant(tx, "(LINE-STATUS)", LINE_STATUS);
v4_text_constant(tx, "(PORT)", PORT);
v4_text_constant(tx, "BLOCK-NUMBER", STORAGE_REG);
v4_text_constant(tx, "BLOCK-ADDRESS", STORAGE_REG + 1);
v4_text_constant(tx, "BLOCK-COMMAND", STORAGE_REG + 2);
+142
View File
@@ -0,0 +1,142 @@
/* test_port.c -- the node's port: a write blocks the node until its
* neighbour has served it (node.h; DECOMPOSITION.md section 6).
*
* At the level of opcodes: no word of the vocabulary is defined here.
*/
#include "v4/asm.h"
#include "v4/testcode.h"
#include <stdio.h>
#include <string.h>
static int failures = 0, checks = 0;
#define CHECK(c,...) do{checks++; if(!(c)){failures++; printf("FAIL %s:%d: ",__FILE__,__LINE__); printf(__VA_ARGS__); printf("\n");}}while(0)
/* The memory map is open (D-4); the test chooses the address. */
#define PORT ((v4_cell)(V4_NODE_WORDS - 9u))
#define MARK ((v4_cell)0x1234)
#define HOME ((v4_cell)8) /* where a word returns to when the test called it */
static v4_node n;
static v4_exec_state es;
static v4_heat h;
static v4_asm as;
#define O(name) v4_asm_op(&as, V4_OP_##name)
#define LIT(v) v4_asm_lit(&as, (v4_cell)(v))
static void start(v4_cell word)
{
v4_dstack_reset(&n.ds);
v4_rstack_reset(&n.rs);
v4_exec_reset(&es);
v4_heat_reset(&h);
v4_rstack_push(&n.rs, HOME);
n.p = word;
}
/* Run until the node is blocked, is back at HOME, or `max` words. */
static unsigned run(unsigned max)
{
unsigned words = 0;
while (words < max && !n.asking && n.p != HOME) { (void)v4_exec_step_word(&n, &es, &h); words++; }
return words;
}
int main(void)
{
v4_cell w_ask, w_mid, w_two;
v4_uheat_t clock;
printf("v4 port tests: V4_CELL_BITS=%d\n", V4_CELL_BITS);
v4_asm_begin(&as, &n, 16);
/* what KERNEL-WORD lays down: the request, the port, b! !b ; */
w_ask = v4_asm_label(&as);
LIT(7); LIT(PORT); O(BANG_B); O(STORE_B); O(SEMI);
/* a write with more of the instruction word after it: dup + */
w_mid = v4_asm_label(&as);
LIT(5); LIT(PORT); O(BANG_B); O(STORE_B); O(DUP); O(ADD); O(SEMI);
/* two writes one after the other */
w_two = v4_asm_label(&as);
LIT(PORT); O(BANG_B); LIT(1); O(STORE_B); LIT(2); O(STORE_B); O(SEMI);
CHECK(v4_asm_ok(&as), "the test words assemble");
/* ---- no port: the address is memory ---- */
v4_node_reset(&n);
v4_asm_begin(&as, &n, 16);
w_ask = v4_asm_label(&as);
LIT(7); LIT(PORT); O(BANG_B); O(STORE_B); O(SEMI);
w_mid = v4_asm_label(&as);
LIT(5); LIT(PORT); O(BANG_B); O(STORE_B); O(DUP); O(ADD); O(SEMI);
w_two = v4_asm_label(&as);
LIT(PORT); O(BANG_B); LIT(1); O(STORE_B); LIT(2); O(STORE_B); O(SEMI);
CHECK(n.port == -1 && !n.asking, "a node has no port until one is attached");
n.mem[PORT] = MARK;
start(w_ask);
(void)run(100);
CHECK(n.p == HOME && !n.asking && n.mem[PORT] == 7, "with none, a store to the address writes memory and the word returns");
/* ---- the write blocks ---- */
v4_node_port_attach(&n, PORT);
n.mem[PORT] = MARK;
start(w_ask);
v4_dstack_push(&n.ds, 11);
v4_dstack_push(&n.ds, 22);
(void)run(100);
CHECK(n.asking && n.request == 7, "a store to the port blocks the node, with what it wrote: %ld", (long)n.request);
CHECK(n.mem[PORT] == MARK, "and does not write memory");
CHECK(n.p != HOME, "the word has not returned");
CHECK(n.ds.depth == 2, "what was on the data stack is there for its neighbour");
clock = es.anticlock;
CHECK(v4_exec_step_word(&n, &es, &h) == 0 && v4_exec_step_word(&n, &es, &h) == 0, "a blocked node executes nothing");
CHECK(es.anticlock == clock && n.asking, "however often it is stepped: the anti-clock does not move");
/* the neighbour takes two values and leaves one, then says it is served */
{
v4_cell b = v4_dstack_pop(&n.ds), a = v4_dstack_pop(&n.ds);
v4_dstack_push(&n.ds, a + b);
}
v4_node_port_served(&n);
(void)run(100);
CHECK(n.p == HOME && !n.asking, "served, the word goes on and returns");
CHECK(n.ds.depth == 1 && v4_dstack_pop(&n.ds) == 33, "with what its neighbour left on the stack");
/* ---- the rest of the instruction word waits ---- */
start(w_mid);
v4_dstack_push(&n.ds, 100); /* to be replaced while the node is blocked */
(void)run(100);
CHECK(n.asking && n.request == 5, "blocked in the middle of an instruction word");
(void)v4_dstack_pop(&n.ds);
v4_dstack_push(&n.ds, 21); /* the neighbour's result */
v4_node_port_served(&n);
(void)run(100);
CHECK(n.p == HOME && n.ds.depth == 1 && v4_dstack_pop(&n.ds) == 42,
"the opcodes after the store run when it is served, on what the neighbour left: dup + of 21");
/* ---- one write after another ---- */
start(w_two);
(void)run(100);
CHECK(n.asking && n.request == 1, "the first write blocks");
v4_node_port_served(&n);
(void)run(100);
CHECK(n.asking && n.request == 2, "served, the node runs to the second and blocks again");
v4_node_port_served(&n);
(void)run(100);
CHECK(n.p == HOME && !n.asking, "and returns when that is served");
/* ---- a fault while blocked abandons the rest of the word ---- */
start(w_mid);
v4_dstack_push(&n.ds, 1);
(void)run(100);
CHECK(n.asking, "blocked again");
v4_node_port_served(&n);
v4_node_fault(&n, V4_FAULT_RAISED, 12); /* no handler attached: the node stops */
CHECK(v4_exec_step_word(&n, &es, &h) == 0 && n.stopped, "a node its neighbour faults does not go on with the word");
/* ---- detaching ---- */
v4_node_reset(&n);
CHECK(n.port == -1 && !n.asking, "reset detaches the port");
printf(" %d checks, %d failures\n", checks, failures);
return failures != 0;
}
+16
View File
@@ -31,6 +31,20 @@ static int console_key(void)
return c == EOF ? V4_BOOT_KEY_END : c;
}
/* THE KERNEL'S WORDS, for a node that is a Linux program: the words that
* are C in hosted v3 because only the host can do them. */
static const char *const kernel_words[] = { "BYE" };
static int leaving;
static void serve(v4_node *node, unsigned request)
{
(void)node;
if (request == 1) { /* BYE ( -- ): as hosted v3, say so and leave */
fputs("Goodbye!\n", stdout);
leaving = 1;
}
}
/* The prompt is the host's, as it is the kernel's REPL's for a v3 VM: read a
* line, hand it to the node, say how it ended. */
int main(void)
@@ -40,6 +54,7 @@ int main(void)
boot.n = &n; boot.es = &es; boot.h = &h; boot.im = &v4_capsule_image;
boot.out = console_out; boot.key = console_key;
boot.words = kernel_words; boot.word_count = sizeof kernel_words / sizeof kernel_words[0]; boot.serve = serve;
if (!v4_boot_run(&boot, disk, BLOCKS)) { fflush(stdout); return 1; }
for (;;) {
@@ -53,6 +68,7 @@ int main(void)
if (len && line[len - 1] == '\n') len--;
how = v4_boot_line(&boot, line, (unsigned)len);
if (how == V4_LINE_COMPLETED) fputs(" ok\n", stdout);
if (leaving) { fflush(stdout); return 0; }
else if (how == V4_LINE_ERROR) fputs(" ERROR\n", stdout);
else if (how == V4_BOOT_LINE_TOO_LONG) fputs("Line too long\n ERROR\n", stdout);
else if (how == V4_BOOT_LINE_NO_INPUT) { putchar('\n'); return 0; }
+2 -2
View File
@@ -100,8 +100,8 @@ int main(int argc, char **argv)
}
fprintf(out, "};\n\nconst v4_image v4_capsule_image = {\n cells, %uu,\n %uu, %uu, %uu, %uu,\n", count,
(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,\n %ld, %ld,\n", (long)line, (long)idle, (long)LINE_STATUS,
(long)TIB, 1025u, (long)SPAN, (long)faults, (long)w_key, (long)w_key_end);
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);
fprintf(out, " %ld, %ld, %ld,\n %ld, %ld,\n %ld,\n %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)STORAGE_REG, (long)DP, (long)LATEST);
if (fclose(out) != 0) die("cannot write", argv[1]);