feat(v4.0.0): the block words are the kernel's -- v3's way in full
Ruled 2026-10-07. BLOCK, BUFFER, UPDATE, SAVE-BUFFERS and EMPTY-BUFFERS are each one kernel request on port 0, by block number only. The node has a window of four slots in its memory, as a v3 VM has; the kernel copies blocks into it, keeps the record of which block is in which slot, and decides when a block is written (v4/system/blocks.c). The node keeps no record and gives the kernel no address, so a request cannot overwrite the node's code. When a block is written stays FORTH-79's: UPDATE marks it. When the chain of devices changes the slots are let go, as in v3. The window is 512 cells more than the two buffers were; the dictionary space ends that much lower, at 13824. MESH.md 8.5 had said, from the review, that a v3 VM's BLOCK is the kernel's buffer. It is not, and the section now says what was reported, what v3 does, and what was ruled. make -C v4 test, sanitize and hosted-check pass; amd64, aarch64 and riscv64 boot, POST 538 of 538, the same hashes on all six: logs/20261007-092835, -093112, -093456. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7f4d946d2e
commit
9bfd5071d2
+3
-3
@@ -51,15 +51,15 @@ node_size = $(if $(findstring /test_host_,$(1)),-DV4_NODE_WORDS=$(HOST_WORDS) -D
|
||||
|
||||
# BLOCKS (docs/v4.0.0/MESH.md section 8). A node asks its kernel for a
|
||||
# block, and system/blocks.c serves it from the kernel's block subsystem,
|
||||
# which is v3's and is built as v3 builds it. Tests named test_blocks*.c
|
||||
# and test_host_*.c link them. V3_BLOCK_SRCS is all of v3 that the block
|
||||
# which is v3's and is built as v3 builds it. Tests named
|
||||
# test_host_*.c link them. V3_BLOCK_SRCS is all of v3 that the block
|
||||
# subsystem needs: its two device back ends, the log and the clock.
|
||||
ROOT_DIR := $(abspath $(HERE)/..)
|
||||
V3_BLOCK_SRCS := $(addprefix $(ROOT_DIR)/v3/src/,block_subsystem.c blkio_ram.c blkio_file.c log.c platform/platform_init.c platform/linux/time.c)
|
||||
V3_CFLAGS := -std=gnu99 -Wall $(OPT) -I$(ROOT_DIR)/v3/include -I$(ROOT_DIR)/kernel/include
|
||||
BLOCKS_SRC := $(HERE)/system/blocks.c
|
||||
V3_INC := -isystem $(ROOT_DIR)/v3/include -isystem $(ROOT_DIR)/kernel/include
|
||||
uses_blocks = $(or $(findstring /test_blocks,$(1)),$(findstring /test_host_,$(1)))
|
||||
uses_blocks = $(findstring /test_host_,$(1))
|
||||
blocks_inc = $(if $(call uses_blocks,$(1)),$(V3_INC))
|
||||
|
||||
$(BINDIR)/v3blocks.o: $(V3_BLOCK_SRCS) $(wildcard $(ROOT_DIR)/v3/include/*.h) $(HERE)/Makefile
|
||||
|
||||
+8
-5
@@ -133,11 +133,14 @@ The two products are not yet this: they become the five nodes at steps 8
|
||||
and 9.
|
||||
A node she births is not POSTed: POST is the kernel's, once, on Hera.
|
||||
|
||||
**Blocks** (`MESH.md` step 6). A node asks its kernel for a block, as a v3
|
||||
VM does: `BLOCK` and its family keep two buffers, and the word beneath them
|
||||
writes a request to port 0 with the block's number and the buffer's address
|
||||
on the stack (`v4/include/v4/blocks.h`). `v4/system/blocks.c` serves it from
|
||||
the kernel's block subsystem, which is v3's (`v3/src/block_subsystem.c`):
|
||||
**Blocks** (`MESH.md` step 6). The block words are the kernel's, as they
|
||||
are for a v3 VM: `BLOCK`, `BUFFER`, `UPDATE`, `SAVE-BUFFERS` and
|
||||
`EMPTY-BUFFERS` each write one request to port 0, by block number only
|
||||
(`v4/include/v4/blocks.h`). The node has a window of four slots in its
|
||||
memory; the kernel copies blocks into it, keeps the record of what is in
|
||||
it, and decides when a block is written (`v4/system/blocks.c`). The blocks
|
||||
are the kernel's block subsystem's, which is v3's
|
||||
(`v3/src/block_subsystem.c`):
|
||||
one chain, the same blocks at the same numbers for every node. A hosted
|
||||
program has the chain's fast RAM, blocks 1 to 2047. On bare metal the chain
|
||||
is fast RAM, the ramdrive and the virtio disk; the disk is read and not yet
|
||||
|
||||
+29
-67
@@ -4,103 +4,65 @@
|
||||
\ EMPTY-BUFFERS LIST LOAD SCR BLK, and v3's FLUSH THRU and --> . Part of the
|
||||
\ compiler capsule; rests on everything before it.
|
||||
\
|
||||
\ STORAGE IS THE KERNEL'S (docs/v4.0.0/MESH.md section 8, ENGINE.md 3.3). A
|
||||
\ node only ever asks for a block by number, and it asks its kernel: with
|
||||
\ the number and the word address of 256 cells on the data stack it writes
|
||||
\ the request to port 0, where its kernel is, and when the write has been
|
||||
\ served the status is on the stack in their place -- 0 it worked, 2 it was
|
||||
\ refused, 3 there is no such block.
|
||||
\
|
||||
\ THE BUFFERS. There are two, of 256 cells each, so two blocks can be in
|
||||
\ memory at once -- one can be copied to another. A buffer is given to the
|
||||
\ block that asks for one, turn about; if it held a block that was UPDATEd,
|
||||
\ that block is written first. BLOCK and BUFFER give a byte address, as PAD
|
||||
\ and TIB are: what C@ CMOVE and TYPE take.
|
||||
\ STORAGE IS THE KERNEL'S (docs/v4.0.0/MESH.md section 8, ENGINE.md 3.3), as
|
||||
\ it is for a v3 VM. A node only ever asks for a block by number, and it
|
||||
\ asks its kernel: it writes a request to port 0, where its kernel is, and
|
||||
\ when the write has been served the answer is on the data stack. The
|
||||
\ node has a window in its memory, four slots of 256 cells; the kernel
|
||||
\ keeps the record of which block is in which slot, does the copying, and
|
||||
\ decides when a block is written. The requests (v4/include/v4/blocks.h):
|
||||
\ BLOCK# ( n -- waddr status ) the slot holding block n
|
||||
\ BUFFER# ( n -- waddr status ) a slot for block n, not read
|
||||
\ UPDATE# ( -- status ) the block last asked for is changed
|
||||
\ SAVE-BUFFERS# ( -- status ) every changed block is written
|
||||
\ EMPTY-BUFFERS# ( -- ) every slot is let go
|
||||
\ The status is 0, or 2 storage refused (error 17), or 3 there is no such
|
||||
\ block (error 13). BLOCK and BUFFER give a byte address, as PAD and TIB
|
||||
\ are: what C@ CMOVE and TYPE take.
|
||||
\
|
||||
\ Constants the loader supplies:
|
||||
\ BLOCK-READ# BLOCK-WRITE# the numbers of the kernel's two requests
|
||||
\ BUF0 BUF1 word addresses of the two buffers
|
||||
\ (B) word address of six cells: (B)+0 the block in buffer 0, or 0
|
||||
\ (B)+1 whether it has been UPDATEd (B)+2 (B)+3 the same for
|
||||
\ buffer 1 (B)+4 which buffer was asked for last, 0 or 2
|
||||
\ (B)+5 the block number while a buffer is found for it
|
||||
\ BLOCK# BUFFER# UPDATE# SAVE-BUFFERS# EMPTY-BUFFERS# the requests' numbers
|
||||
\ SCR word address of the variable: the block LIST showed last
|
||||
\ BLK (SRC) (SRC-HOOK) see input.v4
|
||||
|
||||
header SCR inline : SCR' SCR ;
|
||||
header BLK inline : BLK' BLK ;
|
||||
|
||||
\ ( i -- addr ) the word address of buffer i, where i is 0 or 2
|
||||
: (BUF) if Z drop BUF1 ; Z: drop BUF0 ;
|
||||
|
||||
\ ( command i -- ) read buffer i's block from storage, command 1, or
|
||||
\ write it, command 2: a request of this node's kernel ( n waddr -- status ).
|
||||
\ If it did not work nothing is in the buffer, and it is an error: 17 if
|
||||
\ storage refused, 13 if there is no such block.
|
||||
: (DEVICE)
|
||||
dup push SWAP push \ i R: i command
|
||||
dup (B) + a! @ SWAP (BUF) \ n waddr
|
||||
pop -1 + if RD drop BLOCK-WRITE# jump ASK
|
||||
RD: drop BLOCK-READ#
|
||||
ASK: (PORT) b! !b \ status
|
||||
pop SWAP \ i status
|
||||
if FINE
|
||||
push (B) + a! 0 !+ 0 ! pop
|
||||
-2 + if E17 drop NODE-ERROR b! 13 !b ;
|
||||
\ ( status -- ) a request that did not work is an error
|
||||
: (B-ERR)
|
||||
if FINE -2 + if E17 drop NODE-ERROR b! 13 !b ;
|
||||
E17: drop NODE-ERROR b! 17 !b ;
|
||||
FINE: drop drop ;
|
||||
FINE: drop ;
|
||||
|
||||
\ ( i -- ) if buffer i's block has been UPDATEd, write it
|
||||
: (SAVE)
|
||||
dup (B) + 1 + a! @ if CLEAN
|
||||
drop 0 ! 2 SWAP jump (DEVICE)
|
||||
CLEAN: drop drop ;
|
||||
|
||||
\ ( n -- i flag ) the buffer for block n: the one that has it, flag -1; or
|
||||
\ the other of the one asked for last, its old block written if need be and
|
||||
\ n's number put on it, flag 0 -- what it holds is not block n yet. A block
|
||||
\ number below 1 is an error (code 13).
|
||||
: (FIND-BUF)
|
||||
-if POS jump BAD
|
||||
POS: if BAD
|
||||
(B)+5 a! !
|
||||
(B) a! @ (B)+5 a! @ xor if HIT0 drop
|
||||
(B)+2 a! @ (B)+5 a! @ xor if HIT2 drop
|
||||
(B)+4 a! @ 2 xor dup ! \ the other one
|
||||
dup (SAVE)
|
||||
dup (B) + a! (B)+5 b! @b !+ 0 ! \ its block now, not updated
|
||||
0 ;
|
||||
HIT0: drop 0 (B)+4 a! ! 0 -1 ;
|
||||
HIT2: drop 2 (B)+4 a! ! 2 -1 ;
|
||||
BAD: drop NODE-ERROR b! 13 !b 0 -1 ;
|
||||
\ ( waddr status -- baddr ) the slot's byte address, or the error
|
||||
: (B-GOT)
|
||||
if OK SWAP drop jump (B-ERR)
|
||||
OK: drop 2* 2* ;
|
||||
|
||||
\ ( n -- baddr ) FORTH-79: the address of a buffer assigned to block n.
|
||||
\ What the buffer holds is not read from storage.
|
||||
header BUFFER
|
||||
: BUFFER (FIND-BUF) drop (BUF) 2* 2* ;
|
||||
: BUFFER BUFFER# (PORT) b! !b jump (B-GOT)
|
||||
|
||||
\ ( n -- baddr ) FORTH-79: the address of a buffer that holds block n,
|
||||
\ read from storage if it is not already in one.
|
||||
header BLOCK
|
||||
: BLOCK
|
||||
(FIND-BUF) if READ drop (BUF) 2* 2* ;
|
||||
READ: drop drop \ which buffer is in (B)+4: nothing waits on the stack
|
||||
1 (B)+4 a! @ (DEVICE) (B)+4 a! @ (BUF) 2* 2* ;
|
||||
: BLOCK BLOCK# (PORT) b! !b jump (B-GOT)
|
||||
|
||||
\ FORTH-79: mark the block most recently asked for as changed, so that it is
|
||||
\ written before its buffer is used for another.
|
||||
header UPDATE
|
||||
: UPDATE (B)+4 a! @ (B) + a! @+ if NONE drop -1 ! ; NONE: drop ;
|
||||
: UPDATE UPDATE# (PORT) b! !b jump (B-ERR)
|
||||
|
||||
\ FORTH-79: write every block that has been UPDATEd.
|
||||
header SAVE-BUFFERS
|
||||
: SAVE-BUFFERS 0 (SAVE) 2 jump (SAVE)
|
||||
: SAVE-BUFFERS SAVE-BUFFERS# (PORT) b! !b jump (B-ERR)
|
||||
\ As v3: the same.
|
||||
header FLUSH
|
||||
: FLUSH jump SAVE-BUFFERS
|
||||
\ FORTH-79: forget what is in the buffers; nothing is written.
|
||||
header EMPTY-BUFFERS
|
||||
: EMPTY-BUFFERS (B) a! 0 !+ 0 !+ 0 !+ 0 ! ;
|
||||
: EMPTY-BUFFERS EMPTY-BUFFERS# (PORT) b! !b ;
|
||||
|
||||
\ ---- LIST ----------------------------------------------------------------------
|
||||
\ ( n -- ) as v3: a new line, "Block n", then sixteen lines of 64
|
||||
|
||||
+58
-19
@@ -4,42 +4,81 @@
|
||||
*
|
||||
* A node only ever asks for a block by number, and it asks the kernel: a
|
||||
* request written to the port where its kernel is, as any kernel word is.
|
||||
* There are two, the same for every node,
|
||||
* This is v3's way (v3/src/word_source/block_words.c). The node has a
|
||||
* WINDOW in its memory, V4_BLOCK_SLOTS slots of 256 cells, as a v3 VM has
|
||||
* four slots of 1 KiB at the top of its memory. The kernel keeps the
|
||||
* record of which block is in which slot and does all the copying, and it
|
||||
* writes into the window and nowhere else in the node. The requests, the
|
||||
* same for every node:
|
||||
*
|
||||
* V4_REQ_BLOCK_READ ( n waddr -- status ) block n into the 256 cells at waddr
|
||||
* V4_REQ_BLOCK_WRITE ( n waddr -- status ) block n from them
|
||||
* V4_REQ_BLOCK ( n -- waddr status ) the slot that holds block n, read
|
||||
* from storage if it is not in one
|
||||
* V4_REQ_BUFFER ( n -- waddr status ) a slot for block n, of zeros if it
|
||||
* is not in one: nothing is read
|
||||
* V4_REQ_UPDATE ( -- status ) the block most recently asked for
|
||||
* is marked changed
|
||||
* V4_REQ_SAVE_BUFFERS ( -- status ) every block marked is written
|
||||
* V4_REQ_EMPTY_BUFFERS ( -- ) every slot is let go; nothing is
|
||||
* written
|
||||
*
|
||||
* and their numbers are below zero: the requests a host names for its own
|
||||
* words (KERNEL-WORD) count up from 1. The status is 0, or
|
||||
* V4_BLOCK_REFUSED -- the cells are not all in the node's memory, or
|
||||
* storage will not have it, or the stack did not hold both arguments, in
|
||||
* which case the status is all that is left on it -- or V4_BLOCK_RANGE,
|
||||
* there is no such block.
|
||||
* Their numbers are below zero: the requests a host names for its own
|
||||
* words (KERNEL-WORD) count up from 1.
|
||||
*
|
||||
* waddr is the word address of the slot, or 0 when the status is not 0.
|
||||
* The status is 0; or V4_BLOCK_RANGE, there is no such block; or
|
||||
* V4_BLOCK_REFUSED: storage would not have a block that had to be written,
|
||||
* the stack did not hold the request's argument, or the window is not all
|
||||
* in the node's memory.
|
||||
*
|
||||
* WHEN A BLOCK IS WRITTEN is FORTH-79's: UPDATE marks it, and it is written
|
||||
* by SAVE-BUFFERS or when its slot is wanted for another block. (v3's
|
||||
* UPDATE copies the slot to the kernel at once; the standard is followed.)
|
||||
* A slot whose block is not marked is taken before one whose block is. A
|
||||
* block that storage would not take is let go of: its slot is empty.
|
||||
*
|
||||
* When the kernel's chain of devices changes, everything in the slots is
|
||||
* let go and nothing of it is written, as v3 does (blk_vm_check_epoch).
|
||||
*
|
||||
* A block is 1024 bytes and 256 cells, four bytes to a cell, the first
|
||||
* lowest, whatever the cell width: a read leaves the rest of each cell
|
||||
* zero, and a write takes the low 32 bits.
|
||||
* lowest, whatever the cell width: a block read leaves the rest of each
|
||||
* cell zero, and a write takes the low 32 bits.
|
||||
*
|
||||
* The blocks are the kernel's block subsystem's (v3/src/block_subsystem.c):
|
||||
* the device chain, the metadata and the map are its, as they were. Who
|
||||
* may have which block is not checked here yet (MESH.md 8.4).
|
||||
* The blocks are the kernel's block subsystem's (v3/src/block_subsystem.c).
|
||||
* Who may have which block is not checked here yet (MESH.md 8.4).
|
||||
*/
|
||||
#ifndef V4_BLOCKS_H
|
||||
#define V4_BLOCKS_H
|
||||
|
||||
#include "v4/node.h"
|
||||
|
||||
#define V4_REQ_BLOCK_READ (-1)
|
||||
#define V4_REQ_BLOCK_WRITE (-2)
|
||||
#define V4_REQ_BLOCK (-1)
|
||||
#define V4_REQ_BUFFER (-2)
|
||||
#define V4_REQ_UPDATE (-3)
|
||||
#define V4_REQ_SAVE_BUFFERS (-4)
|
||||
#define V4_REQ_EMPTY_BUFFERS (-5)
|
||||
|
||||
#define V4_BLOCK_OK 0
|
||||
#define V4_BLOCK_REFUSED 2
|
||||
#define V4_BLOCK_RANGE 3
|
||||
|
||||
/* If `request` is one of the two, serve it for the node, whose data stack
|
||||
* holds its arguments and is left holding its status, and return 1.
|
||||
#define V4_BLOCK_SLOTS 4u
|
||||
|
||||
/* What the kernel keeps for one node. */
|
||||
typedef struct {
|
||||
v4_cell window; /* word address of the first slot */
|
||||
uint32_t block[V4_BLOCK_SLOTS]; /* the block in each slot; 0: none */
|
||||
unsigned char changed[V4_BLOCK_SLOTS]; /* UPDATEd and not yet written */
|
||||
unsigned next; /* where the search for a slot to take begins */
|
||||
int last; /* the slot most recently asked for; -1: none */
|
||||
uint64_t epoch; /* the chain as it was when the slots were filled */
|
||||
} v4_blocks;
|
||||
|
||||
/* A node's window is at `window`, and nothing is in it. */
|
||||
void v4_blocks_init(v4_blocks *w, v4_cell window);
|
||||
|
||||
/* If `request` is one of the five, serve it for the node and return 1.
|
||||
* Otherwise touch nothing and return 0. The node is stopped, blocked at
|
||||
* its port, when this is called. */
|
||||
int v4_blocks_serve(v4_node *n, v4_cell request);
|
||||
int v4_blocks_serve(v4_blocks *w, v4_node *n, v4_cell request);
|
||||
|
||||
#endif /* V4_BLOCKS_H */
|
||||
|
||||
@@ -54,6 +54,10 @@ typedef struct {
|
||||
* that loads capsules when it boots sets them again when it has
|
||||
* (v4_image_seal). */
|
||||
v4_cell boot_cells, fence;
|
||||
|
||||
/* the block window: the word address of the slots the kernel copies
|
||||
* blocks into (v4/blocks.h) */
|
||||
v4_cell block_window;
|
||||
} v4_image;
|
||||
|
||||
/* The description of the nucleus built from v4/capsule (the generated file
|
||||
|
||||
+126
-33
@@ -6,48 +6,141 @@
|
||||
#include "v4/blocks.h"
|
||||
#include "block_subsystem.h"
|
||||
|
||||
int v4_blocks_serve(v4_node *n, v4_cell request)
|
||||
static void let_go(v4_blocks *w)
|
||||
{
|
||||
v4_cell addr, num;
|
||||
uint32_t block;
|
||||
uint8_t *b;
|
||||
unsigned i;
|
||||
for (i = 0; i < V4_BLOCK_SLOTS; i++) { w->block[i] = 0; w->changed[i] = 0; }
|
||||
w->next = 0;
|
||||
w->last = -1;
|
||||
}
|
||||
|
||||
void v4_blocks_init(v4_blocks *w, v4_cell window)
|
||||
{
|
||||
w->window = window;
|
||||
w->epoch = blk_subsys_epoch();
|
||||
let_go(w);
|
||||
}
|
||||
|
||||
static v4_cell slot_addr(const v4_blocks *w, unsigned s)
|
||||
{
|
||||
return w->window + (v4_cell)(s * V4_BLOCK_CELLS);
|
||||
}
|
||||
|
||||
/* The block in slot s is written. Whether or not storage takes it, it is
|
||||
* no longer marked. */
|
||||
static int write_slot(v4_blocks *w, v4_node *n, unsigned s)
|
||||
{
|
||||
uint8_t *b = blk_get_buffer(w->block[s], 1);
|
||||
v4_cell at = slot_addr(w, s);
|
||||
unsigned i;
|
||||
|
||||
w->changed[s] = 0;
|
||||
if (!b) return V4_BLOCK_REFUSED;
|
||||
for (i = 0; i < V4_BLOCK_CELLS; i++) {
|
||||
v4_ucell c = (v4_ucell)n->mem[at + (v4_cell)i];
|
||||
b[4u * i] = (uint8_t)(c & 0xFFu);
|
||||
b[4u * i + 1u] = (uint8_t)((c >> 8) & 0xFFu);
|
||||
b[4u * i + 2u] = (uint8_t)((c >> 16) & 0xFFu);
|
||||
b[4u * i + 3u] = (uint8_t)((c >> 24) & 0xFFu);
|
||||
}
|
||||
return (blk_update(w->block[s]) == BLK_OK && blk_flush(w->block[s]) == BLK_OK) ? V4_BLOCK_OK : V4_BLOCK_REFUSED;
|
||||
}
|
||||
|
||||
/* A slot to put a block in: an empty one, or one whose block is not marked,
|
||||
* or, with every one marked, the next in turn, its block written first.
|
||||
* *status is not V4_BLOCK_OK if that write was refused; the slot is empty
|
||||
* all the same. */
|
||||
static unsigned take_slot(v4_blocks *w, v4_node *n, int *status)
|
||||
{
|
||||
unsigned i, s;
|
||||
|
||||
*status = V4_BLOCK_OK;
|
||||
for (i = 0; i < V4_BLOCK_SLOTS; i++) if (w->block[i] == 0) return i;
|
||||
for (i = 0; i < V4_BLOCK_SLOTS; i++) {
|
||||
s = (w->next + i) % V4_BLOCK_SLOTS;
|
||||
if (!w->changed[s]) break;
|
||||
}
|
||||
if (i == V4_BLOCK_SLOTS) {
|
||||
s = w->next;
|
||||
*status = write_slot(w, n, s);
|
||||
}
|
||||
w->next = (s + 1u) % V4_BLOCK_SLOTS;
|
||||
w->block[s] = 0;
|
||||
w->changed[s] = 0;
|
||||
if (w->last == (int)s) w->last = -1;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* BLOCK and BUFFER: ( n -- waddr status ) */
|
||||
static void slot_for(v4_blocks *w, v4_node *n, int read)
|
||||
{
|
||||
v4_cell num, at;
|
||||
uint32_t block;
|
||||
unsigned i, s;
|
||||
int status;
|
||||
|
||||
if (request != V4_REQ_BLOCK_READ && request != V4_REQ_BLOCK_WRITE) return 0;
|
||||
if (n->ds.depth < 2u) { /* not both arguments: nothing is done with what is there */
|
||||
v4_dstack_reset(&n->ds);
|
||||
if (n->ds.depth < 1u) { v4_dstack_reset(&n->ds); v4_dstack_push(&n->ds, 0); v4_dstack_push(&n->ds, (v4_cell)V4_BLOCK_REFUSED); return; }
|
||||
num = v4_dstack_pop(&n->ds);
|
||||
block = (uint32_t)num;
|
||||
if (num < 1 || (uint64_t)num > 0xFFFFFFFFull || !blk_is_valid(block)) {
|
||||
v4_dstack_push(&n->ds, 0); v4_dstack_push(&n->ds, (v4_cell)V4_BLOCK_RANGE);
|
||||
return;
|
||||
}
|
||||
for (s = 0; s < V4_BLOCK_SLOTS && w->block[s] != block; s++) { }
|
||||
if (s == V4_BLOCK_SLOTS) {
|
||||
const uint8_t *b = 0;
|
||||
s = take_slot(w, n, &status);
|
||||
if (status == V4_BLOCK_OK && read) {
|
||||
b = blk_get_buffer(block, 0);
|
||||
if (!b) status = V4_BLOCK_REFUSED;
|
||||
}
|
||||
if (status != V4_BLOCK_OK) { v4_dstack_push(&n->ds, 0); v4_dstack_push(&n->ds, (v4_cell)status); return; }
|
||||
at = slot_addr(w, s);
|
||||
for (i = 0; i < V4_BLOCK_CELLS; i++)
|
||||
n->mem[at + (v4_cell)i] = b ? (v4_cell)((v4_ucell)b[4u * i] | ((v4_ucell)b[4u * i + 1u] << 8)
|
||||
| ((v4_ucell)b[4u * i + 2u] << 16) | ((v4_ucell)b[4u * i + 3u] << 24))
|
||||
: 0;
|
||||
w->block[s] = block;
|
||||
w->changed[s] = 0;
|
||||
}
|
||||
w->last = (int)s;
|
||||
v4_dstack_push(&n->ds, slot_addr(w, s));
|
||||
v4_dstack_push(&n->ds, (v4_cell)V4_BLOCK_OK);
|
||||
}
|
||||
|
||||
int v4_blocks_serve(v4_blocks *w, v4_node *n, v4_cell request)
|
||||
{
|
||||
unsigned s;
|
||||
int status = V4_BLOCK_OK;
|
||||
|
||||
if (request > V4_REQ_BLOCK || request < V4_REQ_EMPTY_BUFFERS) return 0;
|
||||
|
||||
/* the chain is not what it was: what the slots hold is of no chain now */
|
||||
if (blk_subsys_epoch() != w->epoch) { let_go(w); w->epoch = blk_subsys_epoch(); }
|
||||
|
||||
if (request == V4_REQ_EMPTY_BUFFERS) { let_go(w); return 1; }
|
||||
|
||||
/* the window is all in the node's memory, or nothing is done */
|
||||
if (!v4_node_addr_ok(w->window) || !v4_node_addr_ok(w->window + (v4_cell)(V4_BLOCK_SLOTS * V4_BLOCK_CELLS - 1u))) {
|
||||
if (request == V4_REQ_BLOCK || request == V4_REQ_BUFFER) {
|
||||
if (n->ds.depth >= 1u) (void)v4_dstack_pop(&n->ds);
|
||||
v4_dstack_push(&n->ds, 0);
|
||||
}
|
||||
v4_dstack_push(&n->ds, (v4_cell)V4_BLOCK_REFUSED);
|
||||
return 1;
|
||||
}
|
||||
addr = v4_dstack_pop(&n->ds);
|
||||
num = v4_dstack_pop(&n->ds);
|
||||
block = (uint32_t)num;
|
||||
|
||||
if (!v4_node_addr_ok(addr) || !v4_node_addr_ok(addr + (v4_cell)(V4_BLOCK_CELLS - 1u))) {
|
||||
status = V4_BLOCK_REFUSED;
|
||||
} else if (num < 1 || (uint64_t)num > 0xFFFFFFFFull || !blk_is_valid(block)) {
|
||||
status = V4_BLOCK_RANGE;
|
||||
} else if (request == V4_REQ_BLOCK_READ) {
|
||||
b = blk_get_buffer(block, 0);
|
||||
status = b ? V4_BLOCK_OK : V4_BLOCK_REFUSED;
|
||||
if (b)
|
||||
for (i = 0; i < V4_BLOCK_CELLS; i++)
|
||||
n->mem[addr + (v4_cell)i] = (v4_cell)((v4_ucell)b[4u * i] | ((v4_ucell)b[4u * i + 1u] << 8)
|
||||
| ((v4_ucell)b[4u * i + 2u] << 16) | ((v4_ucell)b[4u * i + 3u] << 24));
|
||||
} else {
|
||||
b = blk_get_buffer(block, 1);
|
||||
status = V4_BLOCK_REFUSED;
|
||||
if (b) {
|
||||
for (i = 0; i < V4_BLOCK_CELLS; i++) {
|
||||
v4_ucell w = (v4_ucell)n->mem[addr + (v4_cell)i];
|
||||
b[4u * i] = (uint8_t)(w & 0xFFu);
|
||||
b[4u * i + 1u] = (uint8_t)((w >> 8) & 0xFFu);
|
||||
b[4u * i + 2u] = (uint8_t)((w >> 16) & 0xFFu);
|
||||
b[4u * i + 3u] = (uint8_t)((w >> 24) & 0xFFu);
|
||||
if (request == V4_REQ_BLOCK) { slot_for(w, n, 1); return 1; }
|
||||
if (request == V4_REQ_BUFFER) { slot_for(w, n, 0); return 1; }
|
||||
if (request == V4_REQ_UPDATE) {
|
||||
if (w->last >= 0 && w->block[w->last] != 0) w->changed[w->last] = 1;
|
||||
} else { /* SAVE-BUFFERS */
|
||||
for (s = 0; s < V4_BLOCK_SLOTS; s++)
|
||||
if (w->block[s] != 0 && w->changed[s] && write_slot(w, n, s) != V4_BLOCK_OK) {
|
||||
status = V4_BLOCK_REFUSED;
|
||||
w->block[s] = 0;
|
||||
if (w->last == (int)s) w->last = -1;
|
||||
}
|
||||
if (blk_update(block) == BLK_OK && blk_flush(block) == BLK_OK) status = V4_BLOCK_OK;
|
||||
}
|
||||
}
|
||||
v4_dstack_push(&n->ds, (v4_cell)status);
|
||||
return 1;
|
||||
|
||||
+5
-1
@@ -117,6 +117,9 @@ static void post_watch(char c)
|
||||
#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 */
|
||||
|
||||
/* What the kernel keeps of the node's block window (blocks.h). */
|
||||
static v4_blocks boot_blocks;
|
||||
|
||||
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 */
|
||||
@@ -131,7 +134,7 @@ int v4_boot_line(const v4_boot *b, const char *text, unsigned len)
|
||||
if (n->stopped) return V4_BOOT_LINE_STOPPED;
|
||||
|
||||
if (n->asking && n->ask_port == KERNEL_PORT) { /* a request: the kernel's turn */
|
||||
if (v4_blocks_serve(n, n->request)) { /* a block, as for any node */
|
||||
if (v4_blocks_serve(&boot_blocks, n, n->request)) { /* a block, as for any node */
|
||||
v4_node_port_served(n);
|
||||
} else if (b->serve && n->request >= 1 && n->request <= (v4_cell)b->word_count) {
|
||||
b->serve(n, (unsigned)n->request);
|
||||
@@ -352,6 +355,7 @@ int v4_boot_run(const v4_boot *b)
|
||||
* when it is written: the node need never wait before writing to them
|
||||
* (node.h, v4_node_port_status) */
|
||||
v4_node_port_status(b->n, 0, 1u << KERNEL_PORT | 1u << CONSOLE_PORT);
|
||||
v4_blocks_init(&boot_blocks, b->im->block_window);
|
||||
if (!load_nucleus(b)) { say(b, "PARITY:FAIL\nPOST: FAILED\n"); return 0; }
|
||||
|
||||
/* the kernel's words, before any capsule that might use one */
|
||||
|
||||
+8
-9
@@ -59,7 +59,7 @@
|
||||
#define HEND ((HBUF_W + 16) * 4)
|
||||
#define XVARS (HBUF_W - 4) /* (X): words.v4, 4 cells */
|
||||
#define QBASE (XVARS - 40) /* the Q words' and DUMP's scratch cells, 39 in all */
|
||||
#define BVARS (QBASE - 16) /* blocks.v4: (B) 6 cells, then SCR BLK (SRC) (SRC-HOOK) */
|
||||
#define BVARS (QBASE - 16) /* blocks.v4: 6 cells not used now, then SCR BLK (SRC) (SRC-HOOK) */
|
||||
#define SCR (BVARS + 6)
|
||||
#define BLK (BVARS + 7)
|
||||
#define SRC (BVARS + 8)
|
||||
@@ -99,8 +99,7 @@
|
||||
#define WORD_FORGOTTEN (BUF0_W - 12) /* the xt of the word that is told when entries go, or 0 */
|
||||
#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 */
|
||||
#define BUF1_W (BUF0_W + 256)
|
||||
#define BUF0_W (BVARS - (v4_cell)(V4_BLOCK_SLOTS * V4_BLOCK_CELLS)) /* the block window: the kernel's slots, 256 cells each (v4/blocks.h) */
|
||||
/* the ports' ten addresses and the two that follow them end below BUF0_W - 20 */
|
||||
typedef char host_map_ports_fit[(V4_PORTS <= 8u) ? 1 : -1];
|
||||
/* Nothing printed and no message waiting: a node's variables for them, as at switch-on. */
|
||||
@@ -116,7 +115,7 @@ typedef char host_map_ports_fit[(V4_PORTS <= 8u) ? 1 : -1];
|
||||
#define DICT_W ((v4_cell)8192)
|
||||
#endif
|
||||
#ifndef DICT_END_W
|
||||
#define DICT_END_W ((v4_cell)14336)
|
||||
#define DICT_END_W ((v4_cell)13824) /* 512 cells lower than it was: the block window is four slots now */
|
||||
#endif
|
||||
/* the messages waiting are above the dictionary */
|
||||
typedef char host_map_queue_fits[(MQ_W >= DICT_END_W) ? 1 : -1];
|
||||
@@ -169,7 +168,6 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned
|
||||
v4_text_constant(tx, "(S)", SVARS);
|
||||
v4_text_constant(tx, "(W)", WVARS);
|
||||
v4_text_constant(tx, "(X)", XVARS);
|
||||
v4_text_constant(tx, "(B)", BVARS);
|
||||
v4_text_constant(tx, "(BOOT)", BOOT_CELLS);
|
||||
v4_text_constant(tx, "(LOG-LEVEL)", LOG_LEVEL);
|
||||
v4_text_constant(tx, "(ACL-HOOK)", ACL_HOOK);
|
||||
@@ -209,10 +207,11 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned
|
||||
v4_text_constant(tx, "(OUT)", OUT_W);
|
||||
v4_text_constant(tx, "(WORD-DEFINED)", WORD_DEFINED);
|
||||
v4_text_constant(tx, "(WORD-FORGOTTEN)", WORD_FORGOTTEN);
|
||||
v4_text_constant(tx, "BLOCK-READ#", V4_REQ_BLOCK_READ); /* the kernel's two block requests (v4/blocks.h) */
|
||||
v4_text_constant(tx, "BLOCK-WRITE#", V4_REQ_BLOCK_WRITE);
|
||||
v4_text_constant(tx, "BUF0", BUF0_W);
|
||||
v4_text_constant(tx, "BUF1", BUF1_W);
|
||||
v4_text_constant(tx, "BLOCK#", V4_REQ_BLOCK); /* the kernel's block requests (v4/blocks.h) */
|
||||
v4_text_constant(tx, "BUFFER#", V4_REQ_BUFFER);
|
||||
v4_text_constant(tx, "UPDATE#", V4_REQ_UPDATE);
|
||||
v4_text_constant(tx, "SAVE-BUFFERS#", V4_REQ_SAVE_BUFFERS);
|
||||
v4_text_constant(tx, "EMPTY-BUFFERS#", V4_REQ_EMPTY_BUFFERS);
|
||||
v4_text_constant(tx, "(Q/)", QBASE); /* 5 cells */
|
||||
v4_text_constant(tx, "(QE)", QBASE + 5); /* 8 */
|
||||
v4_text_constant(tx, "(QR)", QBASE + 13); /* 5 */
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/* test_blocks.c -- the kernel serves a node's block requests.
|
||||
* docs/v4.0.0/MESH.md sections 8.2 and 8.3.
|
||||
*
|
||||
* A node, stopped, with a number and an address on its data stack; the
|
||||
* blocks are v3's block subsystem (v3/src/block_subsystem.c): its fast RAM
|
||||
* and a device of 64 blocks.
|
||||
*/
|
||||
#include "v4/blocks.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "block_subsystem.h"
|
||||
|
||||
extern void sf_time_init(void);
|
||||
extern void log_set_level(int level);
|
||||
|
||||
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)
|
||||
|
||||
#define DEVICE_BLOCKS 64u
|
||||
#define BUF 100
|
||||
static unsigned char ram[(size_t)BLK_RAM_BLOCKS * BLK_FORTH_SIZE], dev[DEVICE_BLOCKS * BLK_FORTH_SIZE];
|
||||
static v4_node n;
|
||||
|
||||
static v4_cell ask(v4_cell request, v4_cell block, v4_cell addr)
|
||||
{
|
||||
v4_dstack_push(&n.ds, 7777);
|
||||
v4_dstack_push(&n.ds, block);
|
||||
v4_dstack_push(&n.ds, addr);
|
||||
if (!v4_blocks_serve(&n, request)) return -100;
|
||||
{
|
||||
v4_cell status = v4_dstack_pop(&n.ds);
|
||||
return v4_dstack_pop(&n.ds) == 7777 ? status : -200; /* what was under its arguments is still there */
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned i;
|
||||
v4_cell top = (v4_cell)V4_NODE_WORDS;
|
||||
|
||||
printf("v4 block request tests: V4_CELL_BITS=%d, V4_NODE_WORDS=%u\n", V4_CELL_BITS, (unsigned)V4_NODE_WORDS);
|
||||
sf_time_init();
|
||||
log_set_level(-1);
|
||||
CHECK(blk_subsys_init(ram, sizeof ram) == BLK_OK && blk_subsys_add_raw_device(dev, DEVICE_BLOCKS) == BLK_OK, "the kernel's chain: fast RAM and a device of 64 blocks");
|
||||
v4_node_reset(&n);
|
||||
|
||||
/* ---- a block is written and read ---- */
|
||||
for (i = 0; i < V4_BLOCK_CELLS; i++) n.mem[BUF + i] = (v4_cell)((v4_ucell)0x41424344u + i);
|
||||
#if V4_CELL_BITS > 32
|
||||
n.mem[BUF + 5] = (v4_cell)0x7766554433221100LL; /* only its low 32 bits are the block's */
|
||||
#endif
|
||||
CHECK(ask(V4_REQ_BLOCK_WRITE, 2050, BUF) == V4_BLOCK_OK, "a block is written");
|
||||
CHECK(dev[2 * 1024] == 0x44 && dev[2 * 1024 + 1] == 0x43 && dev[2 * 1024 + 2] == 0x42 && dev[2 * 1024 + 3] == 0x41 && dev[2 * 1024 + 4] == 0x45,
|
||||
"block 2050 is the device's third, four bytes to a cell, the first lowest");
|
||||
CHECK(dev[1 * 1024 + 1023] == 0 && dev[3 * 1024] == 0, "and no other block was touched");
|
||||
for (i = 0; i < V4_BLOCK_CELLS; i++) n.mem[400 + i] = -1;
|
||||
CHECK(ask(V4_REQ_BLOCK_READ, 2050, 400) == V4_BLOCK_OK, "it is read");
|
||||
for (i = 0; i < V4_BLOCK_CELLS && (i == 5 || n.mem[400 + i] == (v4_cell)((v4_ucell)0x41424344u + i)); i++) { }
|
||||
CHECK(i == V4_BLOCK_CELLS, "as it was written: cell %u differs", i);
|
||||
#if V4_CELL_BITS > 32
|
||||
CHECK(n.mem[400 + 5] == (v4_cell)0x33221100, "the rest of each cell is zero");
|
||||
#else
|
||||
CHECK(n.mem[400 + 5] == (v4_cell)((v4_ucell)0x41424344u + 5u), "cell 5 as the others");
|
||||
#endif
|
||||
CHECK(n.mem[399] == 0 && n.mem[400 + V4_BLOCK_CELLS] == 0, "256 cells and no more");
|
||||
n.mem[BUF] = 0x5A;
|
||||
CHECK(ask(V4_REQ_BLOCK_WRITE, 20, BUF) == V4_BLOCK_OK && ram[((size_t)20 + BLK_FORTH_SYS_RESERVED) * 1024] == 0x5A, "a block below 2048 is the chain's fast RAM");
|
||||
|
||||
/* ---- numbers that are no block ---- */
|
||||
CHECK(ask(V4_REQ_BLOCK_READ, 0, 400) == V4_BLOCK_RANGE, "0 is no block");
|
||||
CHECK(ask(V4_REQ_BLOCK_READ, -1, 400) == V4_BLOCK_RANGE && ask(V4_REQ_BLOCK_WRITE, -5, BUF) == V4_BLOCK_RANGE, "nor is a number below it");
|
||||
CHECK(ask(V4_REQ_BLOCK_READ, 2111, 400) == V4_BLOCK_OK && ask(V4_REQ_BLOCK_READ, 2112, 400) == V4_BLOCK_RANGE, "the device's last block is, and the one after it is not");
|
||||
CHECK(ask(V4_REQ_BLOCK_WRITE, 2112, BUF) == V4_BLOCK_RANGE, "nor can it be written");
|
||||
#if V4_CELL_BITS > 32
|
||||
CHECK(ask(V4_REQ_BLOCK_READ, (v4_cell)0x100000014LL, 400) == V4_BLOCK_RANGE, "a number 32 bits do not hold is no block, whatever its low bits are");
|
||||
#endif
|
||||
|
||||
/* ---- cells that are not in the node's memory ---- */
|
||||
n.mem[top - 1] = 123;
|
||||
CHECK(ask(V4_REQ_BLOCK_READ, 2050, top - 255) == V4_BLOCK_REFUSED && n.mem[top - 1] == 123, "256 cells that run past the end of memory are refused, and nothing is read");
|
||||
CHECK(ask(V4_REQ_BLOCK_READ, 2050, top - 256) == V4_BLOCK_OK, "the last 256 cells are not");
|
||||
CHECK(ask(V4_REQ_BLOCK_READ, 2050, -1) == V4_BLOCK_REFUSED && ask(V4_REQ_BLOCK_WRITE, 2050, top) == V4_BLOCK_REFUSED, "an address below 0, or at the end, is refused");
|
||||
CHECK(dev[2 * 1024] == 0x44, "and nothing was written");
|
||||
|
||||
/* ---- a request with too little on the stack ---- */
|
||||
{
|
||||
unsigned char before = dev[2 * 1024];
|
||||
v4_cell low = n.mem[0];
|
||||
v4_dstack_reset(&n.ds);
|
||||
CHECK(v4_blocks_serve(&n, V4_REQ_BLOCK_READ) && n.ds.depth == 1 && v4_dstack_pop(&n.ds) == V4_BLOCK_REFUSED, "a request with nothing on the stack is refused, and the status is all that is left");
|
||||
v4_dstack_push(&n.ds, 2050);
|
||||
CHECK(v4_blocks_serve(&n, V4_REQ_BLOCK_WRITE) && n.ds.depth == 1 && v4_dstack_pop(&n.ds) == V4_BLOCK_REFUSED, "and so is one with a single value");
|
||||
CHECK(dev[2 * 1024] == before && n.mem[0] == low, "nothing was read or written");
|
||||
}
|
||||
|
||||
/* ---- what v3 wrote ---- */
|
||||
{
|
||||
uint8_t *b = blk_get_buffer(2070, 1);
|
||||
CHECK(b != 0, "v3 gives a buffer for block 2070");
|
||||
if (b) { memset(b, 'V', BLK_FORTH_SIZE); CHECK(blk_update(2070) == BLK_OK && blk_flush(2070) == BLK_OK, "and v3 writes it"); }
|
||||
CHECK(ask(V4_REQ_BLOCK_READ, 2070, 400) == V4_BLOCK_OK && n.mem[400] == (v4_cell)0x56565656 && n.mem[400 + 255] == (v4_cell)0x56565656, "what v3's own calls wrote is what the node reads");
|
||||
}
|
||||
|
||||
/* ---- what is not a block request ---- */
|
||||
v4_dstack_push(&n.ds, 11); v4_dstack_push(&n.ds, 22);
|
||||
CHECK(!v4_blocks_serve(&n, 5) && !v4_blocks_serve(&n, 0) && !v4_blocks_serve(&n, -3) && v4_dstack_pop(&n.ds) == 22 && v4_dstack_pop(&n.ds) == 11,
|
||||
"any other request is not served here, and the stack is as it was");
|
||||
|
||||
printf(" %d checks, %d failures\n", checks, failures);
|
||||
return failures ? 1 : 0;
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/* test_blocks.c -- the kernel serves a node's block requests.
|
||||
* docs/v4.0.0/MESH.md sections 8.2 and 8.3.
|
||||
*
|
||||
* A host node, stopped, with what a request takes on its data stack; the blocks
|
||||
* are v3's block subsystem (v3/src/block_subsystem.c): its fast RAM and a
|
||||
* device of 64 blocks. The window is four slots of 256 cells in the node's
|
||||
* memory, and the kernel keeps the record of what is in them.
|
||||
*/
|
||||
#include "v4/blocks.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "block_subsystem.h"
|
||||
|
||||
extern void sf_time_init(void);
|
||||
extern void log_set_level(int level);
|
||||
|
||||
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)
|
||||
|
||||
#define DEVICE_BLOCKS 64u
|
||||
#define WINDOW 200
|
||||
static unsigned char ram[(size_t)BLK_RAM_BLOCKS * BLK_FORTH_SIZE], dev[DEVICE_BLOCKS * BLK_FORTH_SIZE];
|
||||
static v4_node n;
|
||||
static v4_blocks w;
|
||||
static v4_cell got_addr;
|
||||
|
||||
/* a request that takes a block's number: its status, and the address in got_addr */
|
||||
static v4_cell ask(v4_cell request, v4_cell block)
|
||||
{
|
||||
v4_cell status;
|
||||
v4_dstack_reset(&n.ds);
|
||||
v4_dstack_push(&n.ds, 7777);
|
||||
v4_dstack_push(&n.ds, block);
|
||||
if (!v4_blocks_serve(&w, &n, request)) return -100;
|
||||
status = v4_dstack_pop(&n.ds);
|
||||
got_addr = v4_dstack_pop(&n.ds);
|
||||
return (v4_dstack_pop(&n.ds) == 7777 && n.ds.depth == 0) ? status : -200; /* what was under its argument is still there */
|
||||
}
|
||||
/* a request that takes nothing: its status */
|
||||
static v4_cell tell(v4_cell request)
|
||||
{
|
||||
v4_dstack_reset(&n.ds);
|
||||
v4_dstack_push(&n.ds, 7777);
|
||||
if (!v4_blocks_serve(&w, &n, request)) return -100;
|
||||
if (request == V4_REQ_EMPTY_BUFFERS) return (v4_dstack_pop(&n.ds) == 7777 && n.ds.depth == 0) ? 0 : -200;
|
||||
{
|
||||
v4_cell status = v4_dstack_pop(&n.ds);
|
||||
return (v4_dstack_pop(&n.ds) == 7777 && n.ds.depth == 0) ? status : -200;
|
||||
}
|
||||
}
|
||||
static int in_window(v4_cell a) { return a >= WINDOW && a < WINDOW + (v4_cell)(V4_BLOCK_SLOTS * V4_BLOCK_CELLS) && (a - WINDOW) % (v4_cell)V4_BLOCK_CELLS == 0; }
|
||||
static unsigned char *chain_block(unsigned num) { return num < 2048u ? ram + ((size_t)num + BLK_FORTH_SYS_RESERVED) * 1024u : dev + (size_t)(num - 2048u) * 1024u; }
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned i;
|
||||
v4_cell a, b;
|
||||
|
||||
printf("v4 block request tests: V4_CELL_BITS=%d, V4_NODE_WORDS=%u\n", V4_CELL_BITS, (unsigned)V4_NODE_WORDS);
|
||||
sf_time_init();
|
||||
log_set_level(-1);
|
||||
CHECK(blk_subsys_init(ram, sizeof ram) == BLK_OK && blk_subsys_add_raw_device(dev, DEVICE_BLOCKS) == BLK_OK, "the kernel's chain: fast RAM and a device of 64 blocks");
|
||||
v4_node_reset(&n);
|
||||
v4_blocks_init(&w, WINDOW);
|
||||
|
||||
/* ---- BLOCK: the block is copied into a slot of the window ---- */
|
||||
memset(chain_block(2050), 'A', 1024);
|
||||
chain_block(2050)[1] = 'B';
|
||||
n.mem[WINDOW - 1] = 111; n.mem[WINDOW + V4_BLOCK_SLOTS * V4_BLOCK_CELLS] = 222;
|
||||
CHECK(ask(V4_REQ_BLOCK, 2050) == V4_BLOCK_OK && in_window(got_addr), "BLOCK gives the address of a slot of the window");
|
||||
a = got_addr;
|
||||
CHECK(n.mem[a] == (v4_cell)0x41414241 && n.mem[a + 255] == (v4_cell)0x41414141, "holding the block, four bytes to a cell, the first lowest, the rest of each cell zero");
|
||||
chain_block(2050)[0] = 'Z';
|
||||
CHECK(ask(V4_REQ_BLOCK, 2050) == V4_BLOCK_OK && got_addr == a && n.mem[a] == (v4_cell)0x41414241, "a block already in a slot is given as it is there, and not read again");
|
||||
CHECK(ask(V4_REQ_BLOCK, 20) == V4_BLOCK_OK && in_window(got_addr) && got_addr != a, "another block is put in another slot");
|
||||
CHECK(n.mem[WINDOW - 1] == 111 && n.mem[WINDOW + V4_BLOCK_SLOTS * V4_BLOCK_CELLS] == 222, "nothing outside the window is written");
|
||||
|
||||
/* ---- UPDATE marks; nothing is written until SAVE-BUFFERS ---- */
|
||||
CHECK(ask(V4_REQ_BLOCK, 2051) == V4_BLOCK_OK, "block 2051 is asked for");
|
||||
b = got_addr;
|
||||
n.mem[b] = (v4_cell)0x64636261;
|
||||
#if V4_CELL_BITS > 32
|
||||
n.mem[b + 1] = (v4_cell)0x7766554433221100LL; /* only its low 32 bits are the block's */
|
||||
#endif
|
||||
CHECK(tell(V4_REQ_UPDATE) == V4_BLOCK_OK && chain_block(2051)[0] == 0, "UPDATE marks it, and it is not written yet");
|
||||
CHECK(tell(V4_REQ_SAVE_BUFFERS) == V4_BLOCK_OK && memcmp(chain_block(2051), "abcd", 4) == 0, "SAVE-BUFFERS writes it");
|
||||
#if V4_CELL_BITS > 32
|
||||
CHECK(chain_block(2051)[4] == 0x00 && chain_block(2051)[7] == 0x33 && chain_block(2051)[8] == 0, "the low 32 bits of each cell, and no more");
|
||||
#endif
|
||||
CHECK(chain_block(2050)[0] == 'Z' && chain_block(2050)[1] == 'B', "a block that was not UPDATEd is not written");
|
||||
n.mem[b] = (v4_cell)0x31313131;
|
||||
CHECK(tell(V4_REQ_SAVE_BUFFERS) == V4_BLOCK_OK && chain_block(2051)[0] == 'a', "nor is one changed again and not UPDATEd again");
|
||||
CHECK(tell(V4_REQ_UPDATE) == V4_BLOCK_OK, "UPDATE is of the block most recently asked for");
|
||||
CHECK(ask(V4_REQ_BLOCK, 2050) == V4_BLOCK_OK && tell(V4_REQ_UPDATE) == V4_BLOCK_OK && tell(V4_REQ_SAVE_BUFFERS) == V4_BLOCK_OK
|
||||
&& chain_block(2051)[0] == '1' && chain_block(2050)[0] == 'A', "two UPDATEd blocks are both written, each from its own slot");
|
||||
|
||||
/* ---- EMPTY-BUFFERS forgets, and writes nothing ---- */
|
||||
n.mem[a] = (v4_cell)0x58585858;
|
||||
CHECK(ask(V4_REQ_BLOCK, 2050) == V4_BLOCK_OK && tell(V4_REQ_UPDATE) == V4_BLOCK_OK && tell(V4_REQ_EMPTY_BUFFERS) == 0 && tell(V4_REQ_SAVE_BUFFERS) == V4_BLOCK_OK
|
||||
&& chain_block(2050)[0] == 'A', "EMPTY-BUFFERS forgets an UPDATEd block: it is not written");
|
||||
CHECK(tell(V4_REQ_UPDATE) == V4_BLOCK_OK && tell(V4_REQ_SAVE_BUFFERS) == V4_BLOCK_OK, "UPDATE with no block asked for does nothing");
|
||||
chain_block(2050)[0] = 'Q';
|
||||
CHECK(ask(V4_REQ_BLOCK, 2050) == V4_BLOCK_OK && (n.mem[got_addr] & 0xFF) == 'Q', "and the block is read again when it is next asked for");
|
||||
|
||||
/* ---- BUFFER: a slot for the block, not read ---- */
|
||||
(void)tell(V4_REQ_EMPTY_BUFFERS);
|
||||
CHECK(ask(V4_REQ_BUFFER, 2060) == V4_BLOCK_OK && in_window(got_addr) && n.mem[got_addr] == 0 && n.mem[got_addr + 255] == 0, "BUFFER gives a slot of zeros, as v3's does");
|
||||
n.mem[got_addr] = (v4_cell)0x62626262;
|
||||
CHECK(tell(V4_REQ_UPDATE) == V4_BLOCK_OK && tell(V4_REQ_SAVE_BUFFERS) == V4_BLOCK_OK && chain_block(2060)[0] == 'b' && chain_block(2060)[4] == 0, "and what is put in it is written");
|
||||
CHECK(ask(V4_REQ_BLOCK, 2060) == V4_BLOCK_OK && n.mem[got_addr] == (v4_cell)0x62626262, "BLOCK then finds it in its slot");
|
||||
|
||||
/* ---- more blocks than slots ---- */
|
||||
(void)tell(V4_REQ_EMPTY_BUFFERS);
|
||||
for (i = 0; i < V4_BLOCK_SLOTS; i++) {
|
||||
CHECK(ask(V4_REQ_BLOCK, 2100 + (v4_cell)i) == V4_BLOCK_OK, "block %u is asked for", 2100 + i);
|
||||
n.mem[got_addr] = (v4_cell)(0x30303030 + i);
|
||||
}
|
||||
CHECK(tell(V4_REQ_UPDATE) == V4_BLOCK_OK, "the last of them is UPDATEd");
|
||||
CHECK(ask(V4_REQ_BLOCK, 2110) == V4_BLOCK_OK && chain_block(2100 + V4_BLOCK_SLOTS - 1)[0] == 0, "one more takes a slot whose block was not UPDATEd, and nothing is written");
|
||||
for (i = 0; i < V4_BLOCK_SLOTS; i++) { (void)ask(V4_REQ_BLOCK, 2100 + (v4_cell)i); n.mem[got_addr] = (v4_cell)(0x30303030 + i); (void)tell(V4_REQ_UPDATE); }
|
||||
for (i = 0; i < V4_BLOCK_SLOTS && chain_block(2100 + i)[0] == 0; i++) { }
|
||||
CHECK(i == V4_BLOCK_SLOTS, "with every slot UPDATEd nothing is written until a slot is wanted");
|
||||
{
|
||||
unsigned written = 0;
|
||||
CHECK(ask(V4_REQ_BLOCK, 2111) == V4_BLOCK_OK, "one more block is asked for");
|
||||
for (i = 0; i < V4_BLOCK_SLOTS; i++) if (chain_block(2100 + i)[0] != 0) written++;
|
||||
CHECK(written >= 1, "and the block whose slot it took was written first: %u written", written);
|
||||
}
|
||||
(void)tell(V4_REQ_EMPTY_BUFFERS);
|
||||
|
||||
/* ---- numbers that are no block ---- */
|
||||
CHECK(ask(V4_REQ_BLOCK, 0) == V4_BLOCK_RANGE && got_addr == 0, "0 is no block");
|
||||
CHECK(ask(V4_REQ_BLOCK, -1) == V4_BLOCK_RANGE && ask(V4_REQ_BUFFER, -5) == V4_BLOCK_RANGE, "nor is a number below it");
|
||||
CHECK(ask(V4_REQ_BLOCK, 2111) == V4_BLOCK_OK && ask(V4_REQ_BLOCK, 2112) == V4_BLOCK_RANGE && ask(V4_REQ_BUFFER, 2112) == V4_BLOCK_RANGE, "the device's last block is, and the one after it is not");
|
||||
#if V4_CELL_BITS > 32
|
||||
CHECK(ask(V4_REQ_BLOCK, (v4_cell)0x100000014LL) == V4_BLOCK_RANGE, "a number 32 bits do not hold is no block, whatever its low bits are");
|
||||
#endif
|
||||
|
||||
/* ---- a request with too little on the stack ---- */
|
||||
v4_dstack_reset(&n.ds);
|
||||
CHECK(v4_blocks_serve(&w, &n, V4_REQ_BLOCK) && n.ds.depth == 2 && v4_dstack_pop(&n.ds) == V4_BLOCK_REFUSED && v4_dstack_pop(&n.ds) == 0,
|
||||
"BLOCK with nothing on the stack is refused: no address, and the status");
|
||||
|
||||
/* ---- a window that is not in the node's memory ---- */
|
||||
{
|
||||
v4_blocks bad;
|
||||
v4_cell top = (v4_cell)V4_NODE_WORDS, status;
|
||||
v4_blocks_init(&bad, top - (v4_cell)(V4_BLOCK_SLOTS * V4_BLOCK_CELLS) + 1);
|
||||
n.mem[top - 1] = 123;
|
||||
v4_dstack_reset(&n.ds); v4_dstack_push(&n.ds, 2050);
|
||||
CHECK(v4_blocks_serve(&bad, &n, V4_REQ_BLOCK), "a request with a window that runs past the end of memory is served");
|
||||
status = v4_dstack_pop(&n.ds);
|
||||
CHECK(status == V4_BLOCK_REFUSED && v4_dstack_pop(&n.ds) == 0 && n.mem[top - 1] == 123, "by being refused, with nothing written");
|
||||
}
|
||||
|
||||
/* ---- the chain changes: what is in the slots is let go, as v3 does ---- */
|
||||
(void)tell(V4_REQ_EMPTY_BUFFERS);
|
||||
CHECK(ask(V4_REQ_BLOCK, 2070) == V4_BLOCK_OK && (n.mem[got_addr] = (v4_cell)0x59595959) != 0 && tell(V4_REQ_UPDATE) == V4_BLOCK_OK, "a block is in a slot, UPDATEd");
|
||||
{
|
||||
static unsigned char more[4 * 1024];
|
||||
CHECK(blk_subsys_add_raw_device(more, 4) == BLK_OK, "a device joins the chain");
|
||||
memset(chain_block(2070), 'N', 1024);
|
||||
CHECK(tell(V4_REQ_SAVE_BUFFERS) == V4_BLOCK_OK && chain_block(2070)[0] == 'N', "what was in the slots is not written to the chain as it now is");
|
||||
CHECK(ask(V4_REQ_BLOCK, 2070) == V4_BLOCK_OK && (n.mem[got_addr] & 0xFF) == 'N', "and the block is read again");
|
||||
}
|
||||
|
||||
/* ---- what is not a block request ---- */
|
||||
v4_dstack_reset(&n.ds);
|
||||
v4_dstack_push(&n.ds, 11); v4_dstack_push(&n.ds, 22);
|
||||
CHECK(!v4_blocks_serve(&w, &n, 5) && !v4_blocks_serve(&w, &n, 0) && !v4_blocks_serve(&w, &n, -6) && v4_dstack_pop(&n.ds) == 22 && v4_dstack_pop(&n.ds) == 11,
|
||||
"any other request is not served here, and the stack is as it was");
|
||||
|
||||
printf(" %d checks, %d failures\n", checks, failures);
|
||||
return failures ? 1 : 0;
|
||||
}
|
||||
+23
-10
@@ -78,7 +78,7 @@ static char out[V4_CONSOLE_CAP + 1];
|
||||
#define REFUSING_FIRST "2112" /* its first block */
|
||||
static unsigned char ram[RAM_BYTES], common_dev[DISK_BLOCKS * V4_BLOCK_BYTES], refusing_dev[REFUSING_BLOCKS * V4_BLOCK_BYTES];
|
||||
#define disk (ram + (size_t)BLK_FORTH_SYS_RESERVED * BLK_FORTH_SIZE)
|
||||
static unsigned long block_requests; /* how many the node has made */
|
||||
static v4_blocks kblocks; /* what the kernel keeps of the node's block window */
|
||||
|
||||
extern void sf_time_init(void);
|
||||
extern void log_set_level(int level);
|
||||
@@ -122,7 +122,7 @@ static v4_cell last_request;
|
||||
static void kernel_serve(void)
|
||||
{
|
||||
last_request = n.request;
|
||||
if (v4_blocks_serve(&n, n.request)) { block_requests++; return; } /* a block, as for any node (blocks.h) */
|
||||
if (v4_blocks_serve(&kblocks, &n, n.request)) return; /* a block, as for any node (blocks.h) */
|
||||
if (n.request == 1) {
|
||||
v4_cell xt = v4_dstack_pop(&n.ds);
|
||||
if (known_n < 1024) known[known_n++] = xt;
|
||||
@@ -266,6 +266,7 @@ static void boot_with(unsigned depth)
|
||||
n.mem[SRC] = TIB;
|
||||
for (v4_cell k = BVARS; k < BVARS + 14; k++) if (k != SRC) n.mem[k] = 0; /* empty buffers, SCR and BLK 0, no hook */
|
||||
memset(ram, 0, sizeof ram); memset(common_dev, 0, sizeof common_dev);
|
||||
v4_blocks_init(&kblocks, BUF0_W);
|
||||
v4_node_console_input_attach(&n, CONSOLE_RX, CONSOLE_ST);
|
||||
v4_node_fault_attach(&n, w_fault);
|
||||
v4_node_error_attach(&n, NODE_ERROR);
|
||||
@@ -1175,9 +1176,10 @@ int main(void)
|
||||
boot();
|
||||
CHECK(is(say(REFUSING_FIRST " BLOCK DROP UPDATE SAVE-BUFFERS 65 EMIT\n"), "Storage refused\n ERROR\nok> "), "a write storage will not take says so, and the prompt returns");
|
||||
{
|
||||
unsigned long before = block_requests;
|
||||
CHECK(is(say(REFUSING_FIRST " BLOCK DROP\n"), " ok\nok> ") && block_requests == before + 1, "the buffer was emptied: the next BLOCK asks the kernel again");
|
||||
CHECK(is(say(REFUSING_FIRST " BLOCK DROP\n"), " ok\nok> ") && block_requests == before + 1, "and the one after finds it in the buffer");
|
||||
unsigned k, held = 0;
|
||||
for (k = 0; k < V4_BLOCK_SLOTS; k++) if (kblocks.block[k] == 2112u) held++;
|
||||
CHECK(held == 0, "the block storage would not take is let go: no slot holds it");
|
||||
CHECK(is(say(REFUSING_FIRST " BLOCK C@ .\n"), "0 ok\nok> "), "and the next BLOCK reads it from storage again");
|
||||
}
|
||||
|
||||
/* ---- blocks: text loaded from storage ---- */
|
||||
@@ -1225,11 +1227,22 @@ int main(void)
|
||||
"an UPDATEd block is not written yet");
|
||||
CHECK(is(say("FLUSH\n"), " ok\nok> ") && disk[3 * V4_BLOCK_BYTES] == 'H' && disk[3 * V4_BLOCK_BYTES + 1] == ' ' && disk[3 * V4_BLOCK_BYTES + 1023] == 'I'
|
||||
&& disk[2 * V4_BLOCK_BYTES + 1023] == 0 && disk[4 * V4_BLOCK_BYTES] == 0, "FLUSH writes it, all 1024 bytes and no others");
|
||||
CHECK(is(say("74 3 BLOCK C! UPDATE 4 BLOCK DROP\n"), " ok\nok> ") && disk[3 * V4_BLOCK_BYTES] == 'H', "with two buffers a second block does not disturb it");
|
||||
CHECK(is(say("5 BLOCK DROP\n"), " ok\nok> ") && disk[3 * V4_BLOCK_BYTES] == 'J', "a third takes its buffer, and it is written first");
|
||||
CHECK(is(say("EMPTY-BUFFERS 74 3 BLOCK C! UPDATE 4 BLOCK DROP 5 BLOCK DROP 6 BLOCK DROP\n"), " ok\nok> ") && disk[3 * V4_BLOCK_BYTES] == 'H',
|
||||
"with four slots three more blocks do not disturb it");
|
||||
CHECK(is(say("7 BLOCK DROP\n"), " ok\nok> ") && disk[3 * V4_BLOCK_BYTES] == 'H', "a fifth takes the slot of a block that was not UPDATEd, and nothing is written");
|
||||
CHECK(is(say("77 4 BLOCK C! UPDATE 77 5 BLOCK C! UPDATE 77 6 BLOCK C! UPDATE\n"), " ok\nok> ") && disk[3 * V4_BLOCK_BYTES] == 'H'
|
||||
&& disk[4 * V4_BLOCK_BYTES] != 'M' && disk[5 * V4_BLOCK_BYTES] != 'M' && disk[6 * V4_BLOCK_BYTES] != 'M', "four UPDATEd blocks fill the slots, and none is written yet");
|
||||
{
|
||||
unsigned written;
|
||||
CHECK(is(say("8 BLOCK DROP\n"), " ok\nok> "), "one more block is asked for");
|
||||
written = (disk[3 * V4_BLOCK_BYTES] == 'J') + (disk[4 * V4_BLOCK_BYTES] == 'M') + (disk[5 * V4_BLOCK_BYTES] == 'M') + (disk[6 * V4_BLOCK_BYTES] == 'M');
|
||||
CHECK(written == 1, "it takes the slot of one of them, and that one is written first: %u written", written);
|
||||
}
|
||||
CHECK(is(say("FLUSH\n"), " ok\nok> ") && disk[3 * V4_BLOCK_BYTES] == 'J' && disk[4 * V4_BLOCK_BYTES] == 'M' && disk[5 * V4_BLOCK_BYTES] == 'M' && disk[6 * V4_BLOCK_BYTES] == 'M',
|
||||
"FLUSH writes the rest");
|
||||
CHECK(is(say("3 BLOCK C@ . 75 3 BLOCK C! UPDATE EMPTY-BUFFERS FLUSH 3 BLOCK C@ .\n"), "74 74 ok\nok> ") && disk[3 * V4_BLOCK_BYTES] == 'J',
|
||||
"EMPTY-BUFFERS forgets a change without writing it");
|
||||
CHECK(is(say("76 3 BLOCK C! 5 BLOCK DROP 6 BLOCK DROP 3 BLOCK C@ .\n"), "74 ok\nok> "), "a change without UPDATE is lost when the buffer is taken");
|
||||
CHECK(is(say("76 3 BLOCK C! 5 BLOCK DROP 6 BLOCK DROP 7 BLOCK DROP 8 BLOCK DROP 3 BLOCK C@ .\n"), "74 ok\nok> "), "a change without UPDATE is lost when the slot is taken");
|
||||
CHECK(is(say("3 BLOCK 4 BLOCK 1024 CMOVE UPDATE SAVE-BUFFERS\n"), " ok\nok> ") && memcmp(disk + 3 * V4_BLOCK_BYTES, disk + 4 * V4_BLOCK_BYTES, V4_BLOCK_BYTES) == 0
|
||||
&& disk[4 * V4_BLOCK_BYTES] == 'J', "two blocks in memory at once: one copied to the other");
|
||||
put_block(40, "this is on the device");
|
||||
@@ -1238,7 +1251,7 @@ int main(void)
|
||||
{
|
||||
v4_cell k, wide = 0;
|
||||
(void)say("3 BLOCK DROP\n");
|
||||
for (k = 0; k < 2 * 256; k++) if ((v4_ucell)n.mem[BUF0_W + k] > 0xFFFFFFFFu) wide = 1;
|
||||
for (k = 0; k < (v4_cell)(V4_BLOCK_SLOTS * V4_BLOCK_CELLS); k++) if ((v4_ucell)n.mem[BUF0_W + k] > 0xFFFFFFFFu) wide = 1;
|
||||
CHECK(!wide, "a block's bytes are four to a cell at every cell width");
|
||||
}
|
||||
{
|
||||
@@ -1396,7 +1409,7 @@ int main(void)
|
||||
&& is(say("4 LOG-LEVEL!\n"), " ok\nok> "), "a vocabulary, a base, a block, a screen, a log level");
|
||||
CHECK(is(say("1 2 COLD 65 EMIT\n"), "FORTH-79 Cold Start\nSystem initialized.\n ok\nok> "), "COLD says so");
|
||||
CHECK(n.mem[DP] == dp && n.mem[LATEST] == capsule_latest && n.mem[CONTEXT] == LATEST && n.mem[CURRENT] == LATEST && n.mem[VOC_LINK] == 0
|
||||
&& n.mem[BASE] == 10 && n.mem[SCR] == 0 && n.mem[BVARS] == 0 && n.mem[FENCE] == dp / 4 && n.mem[LOG_LEVEL] == 2, "and everything is as the loader left it");
|
||||
&& n.mem[BASE] == 10 && n.mem[SCR] == 0 && kblocks.block[0] == 0 && kblocks.block[1] == 0 && kblocks.block[2] == 0 && kblocks.block[3] == 0 && n.mem[FENCE] == dp / 4 && n.mem[LOG_LEVEL] == 2, "and everything is as the loader left it");
|
||||
CHECK(is(say("KEEPME\n"), "UNKNOWN WORD: 'KEEPME'\n ERROR\nok> ") && is(say("VV\n"), "UNKNOWN WORD: 'VV'\n ERROR\nok> ")
|
||||
&& is(say(".S : NEW 16 . ; NEW\n"), "<0> \n16 ok\nok> "), "what was defined is gone, and the system works");
|
||||
}
|
||||
|
||||
@@ -113,9 +113,11 @@ static uint64_t parity_hash[8];
|
||||
/* THE KERNEL, for a node that is not Hera: on its port 0 it serves the
|
||||
* node's blocks, and no other request (MESH.md 8.3). */
|
||||
static unsigned refused;
|
||||
static v4_blocks node_blocks[PLACES]; /* what the kernel keeps of each node's block window, by where the node is in the pool */
|
||||
static int node_kernel_take(void *self, v4_cell value)
|
||||
{
|
||||
if (!v4_blocks_serve((v4_node *)self, value)) refused++;
|
||||
v4_fabric_node *x = (v4_fabric_node *)self;
|
||||
if (!v4_blocks_serve(&node_blocks[x - pool], &x->n, value)) refused++;
|
||||
return 1;
|
||||
}
|
||||
static v4_device node_kernel[PLACES];
|
||||
@@ -135,8 +137,9 @@ static int host_born(void *self)
|
||||
v4_node_stack_regs_attach(&pool[k].n, DSTACK_REG, RSTACK_REG);
|
||||
v4_node_error_attach(&pool[k].n, NODE_ERROR);
|
||||
v4_node_fault_attach(&pool[k].n, w_fault);
|
||||
v4_blocks_init(&node_blocks[k], BUF0_W);
|
||||
if (k != 0) { /* Hera's kernel is wired where she is made */
|
||||
node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k].n;
|
||||
node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k];
|
||||
if (!v4_fabric_wire_device(&f, (unsigned)place, 0, &node_kernel[k])) return -1;
|
||||
}
|
||||
return place;
|
||||
@@ -187,7 +190,7 @@ static int kernel_give(void *self, v4_cell *value) /* the nucleus, to a nod
|
||||
static int kernel_take(void *self, v4_cell value) /* a request */
|
||||
{
|
||||
(void)self;
|
||||
if (v4_blocks_serve(&v4_fabric_node_at(&f, hera_place)->n, value)) return 1; /* a block, as for any node */
|
||||
if (v4_blocks_serve(&node_blocks[0], &pool[0].n, value)) return 1; /* a block, as for any node; Hera is the first in the pool */
|
||||
if (value < FIRST_REQUEST || !v4_manage_serve(&manage, hera_place, (unsigned)(value - FIRST_REQUEST))) refused++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
+3
-3
@@ -88,7 +88,7 @@ int main(int argc, char **argv)
|
||||
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 = BUF0_W; k < BUF0_W + (v4_cell)(V4_BLOCK_SLOTS * V4_BLOCK_CELLS); 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;
|
||||
@@ -113,9 +113,9 @@ int main(int argc, char **argv)
|
||||
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,
|
||||
fprintf(out, " %ld, %ld, %ld,\n %ld, %ld,\n %ld,\n %ld, %ld,\n %ld, %ld,\n %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);
|
||||
(long)BOOT_CELLS, (long)FENCE, (long)BUF0_W);
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user