fix(v4.0.0): POST leaves nothing, as v3 really does; and what the review of step 6b found
Captain Bob was told that v3 leaves the words POST's cases define in the
dictionary, and ruled that v4 should. That was false: v3's run_test_suite
puts the dictionary back after each word's cases (test_common.c:333,
:365). Shown that, he ruled that POST leaves nothing. The boot now
seals the system, runs POST, and has the node do COLD, whose printing is
not shown; PARITY:V4_SYSTEM is the system as sealed.
A case the node does not come back from ends POST there, named, with how
many were not run: it would have stalled the boot for hours, where the
capsule had ended it. The runner's test of it now uses a word that
really never ends.
hosted-check also requires that RS1 and T{ are unknown after boot, and
boots a program whose POST has failing cases (tests/post_cases_fail.c):
PARITY:FAIL, POST: FAILED, no prompt, none of a case's printing shown.
Comments and documents that still named the POST capsule or its two
hooks are brought up to date; NUCLEUS.md 6.3 says what v3 does, with the
lines, and how the wrong ruling came about.
make -C v4 test, sanitize and hosted-check pass; amd64, aarch64 and
riscv64 boot, POST 538 of 538, word_count=314, dict_hash
0x220ab283a504a3b3 on all six: logs/20261007-112638, -112901, -113220.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
eda6577a53
commit
18adf59091
+20
-4
@@ -27,7 +27,7 @@ CFLAGS ?= $(CSTD) $(WARN) $(OPT)
|
||||
HERE := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
|
||||
|
||||
SRCS := $(wildcard $(HERE)/src/*.c)
|
||||
TESTS := $(wildcard $(HERE)/tests/*.c)
|
||||
TESTS := $(wildcard $(HERE)/tests/test_*.c)
|
||||
|
||||
# Cell widths to build and verify. 32 is the F18/Zynq case, 64 the aarch64
|
||||
# host case; see DECOMPOSITION.md D-5.
|
||||
@@ -183,10 +183,11 @@ post79:
|
||||
# PARITY:OK, POST: PASSED and the prompt: the same hashes on every ISA. It
|
||||
# also checks that what the boot loaded is part of the system: after COLD
|
||||
# the capsule's words and the kernel's are still there, and FORGET refuses
|
||||
# them.
|
||||
# them; that POST has left nothing of itself or of what its cases defined;
|
||||
# and that a boot whose POST has a failing case fails.
|
||||
.PHONY: hosted hosted-check
|
||||
hosted: $(foreach i,$(HOSTED_ISAS),$(BINDIR)/starforth4-$(i))
|
||||
hosted-check: $(foreach i,$(HOSTED_ISAS),$(BINDIR)/boot-$(i).txt)
|
||||
hosted-check: $(foreach i,$(HOSTED_ISAS),$(BINDIR)/boot-$(i).txt) $(BINDIR)/starforth4-postfail
|
||||
@grep -q '^POST: PASSED$$' $(BINDIR)/boot-amd64.txt || { echo "hosted-check: no POST: PASSED"; exit 1; }
|
||||
@cmp $(BINDIR)/boot-amd64.txt $(BINDIR)/boot-aarch64.txt
|
||||
@cmp $(BINDIR)/boot-amd64.txt $(BINDIR)/boot-riscv64.txt
|
||||
@@ -194,7 +195,22 @@ hosted-check: $(foreach i,$(HOSTED_ISAS),$(BINDIR)/boot-$(i).txt)
|
||||
@grep -q '^ok> 0 12 ok$$' $(BINDIR)/cold-amd64.txt || { echo "hosted-check: COLD lost the capsule's words"; cat $(BINDIR)/cold-amd64.txt; exit 1; }
|
||||
@grep -q '^ok> Protected word$$' $(BINDIR)/cold-amd64.txt || { echo "hosted-check: a capsule word could be forgotten"; exit 1; }
|
||||
@grep -q '^ok> Goodbye!$$' $(BINDIR)/cold-amd64.txt || { echo "hosted-check: COLD lost BYE"; exit 1; }
|
||||
@echo "hosted-check: amd64, aarch64 and riscv64 boot identically"
|
||||
@printf 'RS1\nT{\nWORDS\n' | $(BINDIR)/starforth4-amd64 > $(BINDIR)/after-post-amd64.txt
|
||||
@grep -q "^ok> UNKNOWN WORD: 'RS1'$$" $(BINDIR)/after-post-amd64.txt || { echo "hosted-check: a word a POST case defined is still there"; exit 1; }
|
||||
@grep -q "^ok> UNKNOWN WORD: 'T{'$$" $(BINDIR)/after-post-amd64.txt || { echo "hosted-check: POST's harness is on the node"; exit 1; }
|
||||
@$(BINDIR)/starforth4-postfail < /dev/null > $(BINDIR)/postfail.txt; test $$? -ne 0 || { echo "hosted-check: a boot with a failing case did not fail"; exit 1; }
|
||||
@grep -q '^POST FAIL: fail.wrong out<5 5 $$' $(BINDIR)/postfail.txt || { echo "hosted-check: the failing case was not named"; cat $(BINDIR)/postfail.txt; exit 1; }
|
||||
@grep -q '^POST FAIL: fail.many out<QQQQ' $(BINDIR)/postfail.txt || { echo "hosted-check: the case that prints too much was not named"; exit 1; }
|
||||
@grep -q '^PARITY:V4_POST tests=4 pass=2 fail=2$$' $(BINDIR)/postfail.txt || { echo "hosted-check: the tally is wrong"; cat $(BINDIR)/postfail.txt; exit 1; }
|
||||
@grep -q '^POST: FAILED$$' $(BINDIR)/postfail.txt && grep -q '^PARITY:FAIL$$' $(BINDIR)/postfail.txt || { echo "hosted-check: no PARITY:FAIL, POST: FAILED"; exit 1; }
|
||||
@! grep -q '^ok> \|^5 5 $$\|PARITY:OK\|PARITY:V4_SYSTEM' $(BINDIR)/postfail.txt || { echo "hosted-check: a failed boot gave a prompt, or showed a case's printing"; exit 1; }
|
||||
@echo "hosted-check: amd64, aarch64 and riscv64 boot identically; a boot with a failing case fails"
|
||||
|
||||
# A hosted program whose POST has a case that fails (tests/post_cases_fail.c
|
||||
# in the place of system/post_cases.c): hosted-check boots it and requires
|
||||
# that the boot stops there. docs/v4.0.0/MESH.md step 6b, acceptance 4.
|
||||
$(BINDIR)/starforth4-postfail: $(BINDIR)/starforth4-amd64 $(HERE)/tests/post_cases_fail.c
|
||||
$(CC) $(SYSTEM_CFLAGS) -static $(BINDIR)/hosted-amd64.o $(BINDIR)/v4_image_64.c $(CAPSULE_DIR_C) $(ENGINE_SRCS) $(filter-out %/post_cases.c,$(SYSTEM_SRCS)) $(HERE)/tests/post_cases_fail.c $(BINDIR)/v3o-amd64/*.o -o $@
|
||||
|
||||
.PHONY: all test sanitize clean $(addprefix test-,$(WIDTHS))
|
||||
|
||||
|
||||
+9
-5
@@ -62,7 +62,7 @@ load `v4:forth79.4th`, pass POST and reach `ok>`, with the same lines:
|
||||
PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=... capsule_hash=0x97a655081b2af559 words=298
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=... dict_hash=...
|
||||
PARITY:V4_POST tests=538 pass=538 fail=0
|
||||
PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=... dict_hash=...
|
||||
PARITY:V4_SYSTEM word_count=314 dict_hash=...
|
||||
PARITY:OK
|
||||
POST: PASSED
|
||||
ok>
|
||||
@@ -174,10 +174,14 @@ and the v3 cases left out, are listed with reasons in
|
||||
The runner, `v4/system/post.c`, feeds each case to the node a line at a
|
||||
time, keeps what the node prints, reads its data stack from outside, and
|
||||
judges: an error exactly if one is expected, and otherwise the stack and
|
||||
every character printed. Nothing of POST is in the node's dictionary. What
|
||||
the cases define stays there, as in v3, and the system is sealed after
|
||||
POST. The boot then prints `PARITY:V4_SYSTEM word_count=N dict_hash=0x...`,
|
||||
and passes only if no case failed (`v4/system/boot.c`).
|
||||
every character printed. Nothing of POST is in the node's dictionary, and
|
||||
POST leaves nothing: the system is sealed before it, and afterwards the
|
||||
kernel puts the node back to the system as sealed, as v3 puts the
|
||||
dictionary back after each of its suites. The boot then prints
|
||||
`PARITY:V4_SYSTEM word_count=N dict_hash=0x...`, and passes only if no
|
||||
case failed (`v4/system/boot.c`). A case the node does not come back from
|
||||
ends POST there, named. `make -C v4 hosted-check` also boots a program
|
||||
whose POST has failing cases and requires that the boot fails.
|
||||
|
||||
Not tested: `KEY`, `EXPECT`, `QUERY` (the keyboard) and `QUIT` (it returns
|
||||
without ` ok`).
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
\ written here as text for the text assembler (v4/include/v4/text.h).
|
||||
\
|
||||
\ Constants the loader supplies: N-1 (cell bits - 1), NODE-ERROR, CONSOLE-TX,
|
||||
\ CONSOLE-RX, CONSOLE-STATUS, BASE, (EMIT-HOOK), (MSG), (REPLY), (ME), (OUT),
|
||||
\ CONSOLE-RX, CONSOLE-STATUS, BASE, (MSG), (REPLY), (ME), (OUT),
|
||||
\ (OUT^), (CONSOLE), (ROUTES), (ROUTE#), (ROUTE-DEFAULT), (PRINT-TO),
|
||||
\ (PRINT-PORT).
|
||||
\
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
*
|
||||
* 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...
|
||||
* PARITY:V4_POST tests=N pass=N fail=N (POST is the kernel's: v4/post.h)
|
||||
* PARITY:V4_SYSTEM word_count=N dict_hash=0x... (the system as sealed, after POST)
|
||||
* PARITY:OK
|
||||
* POST: PASSED
|
||||
*
|
||||
|
||||
+10
-3
@@ -37,7 +37,14 @@ extern const unsigned v4_post_case_count;
|
||||
* of it; and judges. A case passes when it ended in an error exactly if
|
||||
* one was expected and, if none was, its stack and its printing are what
|
||||
* the table has. It has ended in an error if any of its lines did. What
|
||||
* the cases define stays in the node's dictionary, as in v3. */
|
||||
* the cases define is still in the node's dictionary when the runner
|
||||
* returns: whoever runs POST puts the dictionary back afterwards, as v3
|
||||
* does after each of its suites (v3/src/test_runner/test_common.c,
|
||||
* run_test_suite: "to remove test-created words").
|
||||
*
|
||||
* If the node does not come back from a line -- it has stopped, or runs for
|
||||
* ever -- that case fails and POST ends there: the runner says which case
|
||||
* it was and how many were not run. */
|
||||
#define V4_POST_OUT 1024u /* the most of a case's printing that is kept */
|
||||
|
||||
typedef struct {
|
||||
@@ -54,8 +61,8 @@ typedef struct {
|
||||
typedef struct { unsigned tests, pass, fail; } v4_post_tally;
|
||||
|
||||
/* Run the cases. Prints "POST FAIL: name out<...> stack<...>" for each
|
||||
* failing case and then "PARITY:V4_POST tests=N pass=N fail=N". Returns 1
|
||||
* if none failed. */
|
||||
* failing case and then "PARITY:V4_POST tests=N pass=N fail=N", where tests
|
||||
* is how many were run. Returns 1 if every case was run and none failed. */
|
||||
int v4_post_run(const v4_post_host *h, const v4_post_case *cases, unsigned count, v4_post_tally *tally);
|
||||
|
||||
#endif /* V4_POST_H */
|
||||
|
||||
+21
-6
@@ -19,8 +19,9 @@ static const char *const boot_capsules[] = {
|
||||
};
|
||||
|
||||
/* POST is part of the boot, and is the kernel's (v4/include/v4/post.h;
|
||||
* docs/v4.0.0/NUCLEUS.md 6.3): when the capsules are in, the kernel feeds
|
||||
* its cases to the node and judges them, and the boot passes only if none
|
||||
* docs/v4.0.0/NUCLEUS.md 6.3): when the capsules are in and the system is
|
||||
* sealed, the kernel feeds its cases to the node and judges them, puts the
|
||||
* node back to the system as sealed, and the boot passes only if none
|
||||
* failed. -DV4_POST_AT_BOOT=0 leaves it out, for work on a vocabulary
|
||||
* that does not pass yet. */
|
||||
#ifndef V4_POST_AT_BOOT
|
||||
@@ -367,22 +368,36 @@ int v4_boot_run(const v4_boot *b)
|
||||
|
||||
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; }
|
||||
/* The kernel's words and the capsules are the system: COLD comes back
|
||||
* to here, and FORGET will not go below it. */
|
||||
v4_image_seal(b->n, b->im);
|
||||
|
||||
#if V4_POST_AT_BOOT
|
||||
{
|
||||
static const char cold[] = "COLD";
|
||||
v4_post_host host;
|
||||
v4_post_tally tally;
|
||||
unsigned printed = 0;
|
||||
int how;
|
||||
|
||||
host.self = (void *)b; host.n = b->n; host.line = post_line; host.say = post_say;
|
||||
if (!v4_post_run(&host, v4_post_cases, v4_post_case_count, &tally)) {
|
||||
say(b, "V4: POST reported failures\nPARITY:FAIL\nPOST: FAILED\n");
|
||||
return 0;
|
||||
}
|
||||
/* POST leaves nothing: the node is put back to the system as it was
|
||||
* sealed, as v3 puts the dictionary back after each of its suites
|
||||
* (v3/src/test_runner/test_common.c, run_test_suite). What COLD
|
||||
* prints is not shown. */
|
||||
v4_dstack_reset(&b->n->ds);
|
||||
how = run_line(b, cold, (unsigned)sizeof cold - 1u, (char *)cold, 0u, &printed);
|
||||
if (how != V4_TEXT_COMPLETED && how != V4_TEXT_QUIT) {
|
||||
say(b, "V4: the node did not come back to the system after POST\nPARITY:FAIL\nPOST: FAILED\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The kernel's words, the capsules and what POST's cases defined are
|
||||
* the system, as in v3: COLD comes back to here, and FORGET will not go
|
||||
* below it. */
|
||||
v4_image_seal(b->n, b->im);
|
||||
say(b, "PARITY:V4_SYSTEM word_count="); say_dec(b, word_count(b->n, b->im));
|
||||
say(b, " dict_hash="); say_hex(b, v4_boot_dict_hash(b->n, b->im));
|
||||
say(b, "\n");
|
||||
|
||||
+12
-2
@@ -44,18 +44,19 @@ int v4_post_run(const v4_post_host *h, const v4_post_case *cases, unsigned count
|
||||
for (i = 0; i < count; i++) {
|
||||
const v4_post_case *c = &cases[i];
|
||||
unsigned kept = 0, total = 0, len = 0, depth;
|
||||
int errored = 0, came_back = 1, ok, how;
|
||||
int errored = 0, came_back = 1, lost = 0, ok, how;
|
||||
|
||||
/* every case starts from the same state */
|
||||
v4_dstack_reset(&h->n->ds);
|
||||
how = h->line(h->self, state_line, (unsigned)sizeof state_line - 1u, out, 0u, &len);
|
||||
if (how < 0) lost = 1;
|
||||
if (how != V4_TEXT_COMPLETED) came_back = 0;
|
||||
v4_dstack_reset(&h->n->ds);
|
||||
|
||||
for (k = 0; came_back && k < c->line_count; k++) {
|
||||
len = 0;
|
||||
how = h->line(h->self, c->lines[k], length(c->lines[k]), out + kept, V4_POST_OUT - kept, &len);
|
||||
if (how < 0) { came_back = 0; break; }
|
||||
if (how < 0) { came_back = 0; lost = 1; break; }
|
||||
if (how == V4_TEXT_ERROR) errored = 1;
|
||||
total += len;
|
||||
kept = total < V4_POST_OUT ? total : V4_POST_OUT;
|
||||
@@ -95,6 +96,15 @@ int v4_post_run(const v4_post_host *h, const v4_post_case *cases, unsigned count
|
||||
say(h, "> stack<");
|
||||
for (k = depth < SHOWN_STACK ? depth : SHOWN_STACK; k-- > 0; ) { say_number(h, (long long)left[k]); say(h, " "); }
|
||||
say(h, ">\n");
|
||||
|
||||
/* The node did not come back from a line: it is stopped, or will
|
||||
* run for ever. Nothing more can be asked of it, so POST ends
|
||||
* here and says which case it was. */
|
||||
if (lost) {
|
||||
say(h, "POST: the node did not come back from "); say(h, c->name);
|
||||
say(h, "; "); say_number(h, (long long)(count - i - 1u)); say(h, " not run\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
say(h, "PARITY:V4_POST tests="); say_number(h, (long long)tally->tests);
|
||||
say(h, " pass="); say_number(h, (long long)tally->pass);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/* post_cases_fail.c -- a table of cases for the boot to fail on.
|
||||
* docs/v4.0.0/MESH.md step 6b, acceptance 4; v4/Makefile, hosted-check.
|
||||
*
|
||||
* Linked into a hosted program in the place of v4/system/post_cases.c, so
|
||||
* that the boot itself (v4/system/boot.c) is seen to stop on a failing
|
||||
* case, to keep what a case prints off the console, and to hold no more of
|
||||
* it than it has room for. It is not a test program of its own: the suite
|
||||
* does not build it.
|
||||
*/
|
||||
#include "v4/post.h"
|
||||
|
||||
static const char *const l_right[] = { "5 DUP . . CR" };
|
||||
static const char *const l_wrong[] = { "5 DUP . . CR" };
|
||||
static const char *const l_many[] = { ": MANY 2000 0 DO 81 EMIT LOOP ;", "MANY" };
|
||||
static const char *const l_two[] = { "65 EMIT", "66 EMIT" };
|
||||
|
||||
const v4_post_case v4_post_cases[] = {
|
||||
{ "fail.right", l_right, 1u, V4_POST_STACK, 0, 0u, "5 5 \012", 5u },
|
||||
{ "fail.wrong", l_wrong, 1u, V4_POST_STACK, 0, 0u, "5 6 \012", 5u },
|
||||
{ "fail.many", l_many, 2u, V4_POST_STACK, 0, 0u, "Q", 1u },
|
||||
{ "fail.twoline", l_two, 2u, V4_POST_STACK, 0, 0u, "AB", 2u },
|
||||
};
|
||||
|
||||
const unsigned v4_post_case_count = 4u;
|
||||
+23
-15
@@ -361,10 +361,11 @@ static const char *say(const char *input)
|
||||
}
|
||||
/* POST's RUNNER (v4/system/post.c), with these tests as its host: a line is
|
||||
* sent to the node as the console sends one, and what the node prints is
|
||||
* handed back and not shown. `post_lost` is the text of a line that is
|
||||
* never to come back, and `post_state_fails` makes the line that sets the
|
||||
* state end in an error; `post_said` is what the runner printed. */
|
||||
static const char *post_lost;
|
||||
* handed back and not shown. `post_step_limit` is how long a line may
|
||||
* take before the node is given up on, and `post_state_fails` makes the
|
||||
* line that sets the state end in an error; `post_said` is what the runner
|
||||
* printed. */
|
||||
static long post_step_limit = 40000000;
|
||||
static int post_state_fails;
|
||||
static char post_said[4096];
|
||||
static unsigned post_said_len;
|
||||
@@ -373,12 +374,11 @@ static int post_line(void *self, const char *text, unsigned text_len, char *o, u
|
||||
int ended;
|
||||
(void)self;
|
||||
*len = 0;
|
||||
if (post_lost && strlen(post_lost) == text_len && memcmp(post_lost, text, text_len) == 0) return -1;
|
||||
if (post_state_fails && text_len == 25 && memcmp(text, "DECIMAL FORTH DEFINITIONS", 25) == 0) text = "NOSUCHWORD-FOR-STATE ";
|
||||
if (!v4_message_text(&to_node, 0, 1, V4_MSG_TEXT, text, text_len)) return -1;
|
||||
to_sent = 0; from_node.count = 0;
|
||||
shown_len = 0; shown_dropped = 0;
|
||||
ended = run_line(40000000);
|
||||
ended = run_line(post_step_limit);
|
||||
if (ended != 1) return -1;
|
||||
*len = shown_dropped ? (unsigned)sizeof shown + 1u : shown_len;
|
||||
memcpy(o, shown, shown_len < cap ? shown_len : cap);
|
||||
@@ -1259,22 +1259,30 @@ int main(void)
|
||||
CHECK(post_one("many", "MANY", 0, V4_POST_STACK, 0, 0, big) == 0 && strstr(post_said, "POST FAIL: many ") != NULL, "a case that prints more than the runner keeps fails, by name");
|
||||
CHECK(post_one("after.many", "1 2 +", 0, V4_POST_STACK, three, 1, "") == 1, "and the next case is judged as usual");
|
||||
|
||||
/* a line that never comes back */
|
||||
post_lost = "LOST-LINE";
|
||||
/* output on more than one line of a case */
|
||||
CHECK(post_one("two.out", "65 EMIT", "66 EMIT", V4_POST_STACK, 0, 0, "AB") == 1 && post_one("two.out2", "65 EMIT", "66 EMIT", V4_POST_STACK, 0, 0, "AA") == 0,
|
||||
"what a case prints on its second line follows what it printed on its first");
|
||||
|
||||
/* a case the node does not come back from: POST stops there */
|
||||
CHECK(is(say(": SPIN BEGIN 0 UNTIL ;\n"), " ok\nok> "), "a word that never ends");
|
||||
{
|
||||
static const char *const la[] = { "1 2 +" }, *const lb[] = { "LOST-LINE" }, *const lc[] = { "65 EMIT" };
|
||||
static const char *const la[] = { "1 2 +" }, *const lb[] = { "SPIN" }, *const lc[] = { "65 EMIT" };
|
||||
static const v4_post_case three_cases[] = {
|
||||
{ "first", la, 1u, V4_POST_STACK, three, 1u, "", 0u },
|
||||
{ "lost", lb, 1u, V4_POST_STACK, 0, 0u, "", 0u },
|
||||
{ "last", lc, 1u, V4_POST_STACK, 0, 0u, "A", 1u },
|
||||
{ "spins", lb, 1u, V4_POST_STACK, 0, 0u, "", 0u },
|
||||
{ "never.run", lc, 1u, V4_POST_STACK, 0, 0u, "A", 1u },
|
||||
};
|
||||
v4_post_tally t;
|
||||
post_said_len = 0; post_said[0] = 0;
|
||||
CHECK(v4_post_run(&post_host, three_cases, 3, &t) == 0 && t.tests == 3 && t.pass == 2 && t.fail == 1
|
||||
&& strstr(post_said, "POST FAIL: lost ") != NULL && strstr(post_said, "PARITY:V4_POST tests=3 pass=2 fail=1\n") != NULL,
|
||||
"a line that does not come back fails its case; the others are still judged, and the run is not a pass: \"%s\"", post_said);
|
||||
post_step_limit = 2000000;
|
||||
CHECK(v4_post_run(&post_host, three_cases, 3, &t) == 0 && t.tests == 2 && t.pass == 1 && t.fail == 1,
|
||||
"the run is not a pass, and the case after it is not run: %u run, %u passed, %u failed", t.tests, t.pass, t.fail);
|
||||
CHECK(strstr(post_said, "POST FAIL: spins ") != NULL && strstr(post_said, "POST: the node did not come back from spins; 1 not run\n") != NULL
|
||||
&& strstr(post_said, "never.run") == NULL && strstr(post_said, "PARITY:V4_POST tests=2 pass=1 fail=1\n") != NULL,
|
||||
"it is named as the case the node did not come back from, with how many were not run: \"%s\"", post_said);
|
||||
post_step_limit = 40000000;
|
||||
}
|
||||
post_lost = 0;
|
||||
boot(); /* the node was left spinning */
|
||||
}
|
||||
|
||||
/* ---- nothing of POST is on the node (NUCLEUS.md 6.3) ---- */
|
||||
|
||||
@@ -344,7 +344,7 @@ int main(void)
|
||||
printf("v4 unit tests: V4_CELL_BITS=%d, V4_NODE_WORDS=%u\n", V4_CELL_BITS, (unsigned)V4_NODE_WORDS);
|
||||
if (V4_CELL_BITS != 64) {
|
||||
/* The capsules the unit is built from are the 64-bit products': the
|
||||
* expected results in post79.4th are v3's, on 64-bit cells, and the
|
||||
* expected results in POST's table are v3's, on 64-bit cells, and the
|
||||
* nucleus capsule is nucleus-64. POST has never been run on 32-bit
|
||||
* cells (docs/v4.0.0/MESH.md, step 5). */
|
||||
printf(" not run at this width: the capsules are the 64-bit products'\n");
|
||||
@@ -400,16 +400,30 @@ int main(void)
|
||||
}
|
||||
CHECK(strcmp(tell(10, "NODE-ME ."), "0 ") == 0 && refused == 0, "it asks where it is, and is answered");
|
||||
CHECK(load(10, "forth79.4th") == 0, "it takes in FORTH-79");
|
||||
CHECK(told(10, "(SEAL)"), "the nucleus and FORTH-79 are the system POST is run on");
|
||||
{
|
||||
static v4_cell before[V4_NODE_WORDS];
|
||||
v4_post_host host;
|
||||
v4_post_tally tally;
|
||||
host.self = 0; host.n = node_numbered(10); host.line = post_line; host.say = post_say;
|
||||
v4_node *hera = node_numbered(10);
|
||||
v4_cell here = hera->mem[DP] / 4, k, changed = 0, first = -1;
|
||||
uint64_t hash = v4_image_dict_hash(hera, &im);
|
||||
memcpy(before, hera->mem, sizeof before);
|
||||
host.self = 0; host.n = hera; host.line = post_line; host.say = post_say;
|
||||
CHECK(v4_post_run(&host, v4_post_cases, v4_post_case_count, &tally) && tally.tests == 538 && tally.pass == 538 && tally.fail == 0
|
||||
&& strstr(post_said, "PARITY:V4_POST tests=538 pass=538 fail=0\n") != NULL && strstr(post_said, "POST FAIL") == NULL,
|
||||
"and passes POST, which the kernel runs on her: %u of %u, %u failed; \"%s\"", tally.pass, tally.tests, tally.fail, post_said);
|
||||
CHECK(strcmp(tell(10, "RS1"), "42 42 \n") == 0, "while POST runs, what its cases define is on her: \"%s\"", printed);
|
||||
CHECK(strstr(tell(10, "COLD"), "Cold Start") != NULL, "the kernel puts her back to the system as it was sealed");
|
||||
CHECK(hera->mem[DP] == before[DP] && hera->mem[LATEST] == before[LATEST], "HERE and LATEST are where they were before POST");
|
||||
for (k = 0; k < here; k++) if (hera->mem[k] != before[k]) { if (first < 0) first = k; changed++; }
|
||||
/* What differs is the TTL in the entry of each word POST had interpreted: a count of uses left before
|
||||
* the word's access is checked again, which every use counts down (compile.v4, (ACL?)), as in v3. */
|
||||
printf(" after POST and COLD: %ld of the %ld cells below HERE differ from before POST (the first at %ld); dict_hash %s\n",
|
||||
(long)changed, (long)here, (long)first, v4_image_dict_hash(hera, &im) == hash ? "the same" : "differs");
|
||||
}
|
||||
CHECK(strstr(tell(10, "T{"), "UNKNOWN WORD") != NULL, "nothing of POST's harness is on her: \"%s\"", printed);
|
||||
CHECK(strcmp(tell(10, "RS1"), "42 42 \n") == 0, "what POST's cases defined is: \"%s\"", printed);
|
||||
CHECK(strstr(tell(10, "RS1"), "UNKNOWN WORD") != NULL && strstr(tell(10, "ZERO"), "UNKNOWN WORD") != NULL, "nor anything POST's cases defined: POST leaves nothing, as in v3: \"%s\"", printed);
|
||||
CHECK(load(10, "hera.4th") == 0, "and its own capsule, which makes it Hera");
|
||||
CHECK(told(10, "(SEAL)"), "that is the system it comes back to");
|
||||
|
||||
@@ -423,7 +437,6 @@ int main(void)
|
||||
CHECK(post_passed[10] == 0 && post_passed[11] == 0 && post_passed[12] == 0 && post_passed[13] == 0 && post_passed[14] == 0 && post_other == 0,
|
||||
"a node she births is not POSTed, and no node prints a POST tally: POST is the kernel's, once, on Hera: %u %u %u %u %u, %u failed",
|
||||
post_passed[10], post_passed[11], post_passed[12], post_passed[13], post_passed[14], post_other);
|
||||
CHECK(strstr(tell(10, "COLD"), "Cold Start") != NULL && strcmp(tell(10, "RS1"), "42 42 \n") == 0, "COLD on Hera comes back to a system that has what POST's cases defined: \"%s\"", printed);
|
||||
CHECK(parity_count == 4 && parity_number[0] == 11 && parity_number[1] == 12 && parity_number[2] == 13 && parity_number[3] == 14, "the parity of each was recorded: %u", parity_count);
|
||||
CHECK(parity_hash[0] == parity_hash[1] && parity_hash[1] == parity_hash[2] && parity_hash[2] == parity_hash[3],
|
||||
"and their dictionary hashes are the same: %016llx %016llx %016llx %016llx",
|
||||
|
||||
Reference in New Issue
Block a user