/* sk_v4.c -- StarForth v4 on bare metal: one host node at a prompt. * * The node is the golden model of the F18-derived engine (v4/src). It comes * up as the hosted v4 system does, by v4_boot_run (v4/include/v4/boot.h): * the machine's ROM assembles the system from its source, then the capsules * from the directory baked into this kernel are loaded, each checked and its * parity line printed, then the prompt. * docs/v4.0.0/NUCLEUS.md. This file is all the kernel adds: * * - what the node prints goes to the kernel's console; * - the prompt, and the line: it is read and edited here and handed to the * node whole (docs/v4.0.0/ENGINE.md 3.1), and how it ended is said here; * - blocks are kept in memory, and are gone at power-off. * * This is the lone node, started before the kernel's fleet and beside it. * It goes when the node is brought up in the VM's place (ENGINE.md step 4). * * Nothing of the v3 VM is started. docs/v4.0.0/DECOMPOSITION.md. */ #include "starkernel/v4/sk_v4.h" #include "starkernel/console.h" #include "starkernel/arch.h" #include "v4/boot.h" #include "block_subsystem.h" #define SK_V4_LINE 255u /* what the line editor here takes */ static v4_node sk_v4_node; static v4_exec_state sk_v4_es; static v4_heat sk_v4_heat; static v4_image sk_v4_image; static char sk_v4_text[SK_V4_LINE + 1u]; /* POST's block RAM, as the v3 path has (sk_vm_bootstrap.c, sk_post_blk_ram): * the node boots and is POSTed with these blocks, 1 to 2047 and nothing * above them, and the kernel's real chain is set up afterwards. */ static uint8_t sk_v4_post_blk_ram[BLK_RAM_BLOCKS * BLK_FORTH_SIZE]; static void sk_v4_out(const char *text, unsigned len) { unsigned i; for (i = 0; i < len; i++) console_putc(text[i]); } /* a character for a line that reads the keyboard, when there is one */ static int sk_v4_key(void) { int c = console_getc(); return c < 0 ? V4_BOOT_KEY_NONE : c; } /* THE KERNEL'S WORDS for the lone node. BYE is v3's (mama_word_bye): a cold * restart. v3's reaps Hera's children first; the lone node is started * before there is a fleet, so there are none. The rest of the kernel's * words come when the node is brought up in the VM's place (ENGINE.md * step 4), where v3's own functions serve them. */ static const char *const sk_v4_words[] = { "BYE" }; static void sk_v4_serve(v4_node *node, unsigned request) { (void)node; if (request == 1) { console_println("BYE: cold restart"); arch_cold_reset(); } } /* Read a line from the keyboard: characters are echoed, backspace rubs one * out, Enter ends it. Returns its length. */ static unsigned sk_v4_readline(void) { unsigned len = 0; for (;;) { int c = console_getc(); if (c < 0) continue; if (c == '\r' || c == '\n') { console_putc('\n'); return len; } if (c == 8 || c == 127) { if (len > 0) { len--; console_putc(8); console_putc(' '); console_putc(8); } } else if (c >= 32 && c < 127 && len < SK_V4_LINE) { sk_v4_text[len++] = (char)c; console_putc((char)c); } } } void sk_v4_run(void (*chain)(void)) { v4_boot boot; console_println("StarForth v4: one host node, the F18-derived engine"); sk_v4_image = v4_map_image; boot.n = &sk_v4_node; boot.es = &sk_v4_es; boot.h = &sk_v4_heat; boot.im = &sk_v4_image; boot.out = sk_v4_out; boot.key = sk_v4_key; boot.words = sk_v4_words; boot.word_count = sizeof sk_v4_words / sizeof sk_v4_words[0]; boot.serve = sk_v4_serve; blk_subsys_init(sk_v4_post_blk_ram, sizeof(sk_v4_post_blk_ram)); if (!v4_boot_run(&boot)) { console_println("StarForth v4: not started"); for (;;) { } } if (chain) { /* the blocks are other blocks now: what the node has in its two * buffers is POST's, and is let go */ chain(); if (v4_boot_line(&boot, "EMPTY-BUFFERS", 13) != V4_TEXT_COMPLETED) { console_println("StarForth v4: the node did not let go of POST's blocks"); for (;;) { } } } /* The prompt is the host's: read a line, hand it to the node, say how it * ended. */ for (;;) { unsigned len; int how; console_puts("ok> "); len = sk_v4_readline(); how = v4_boot_line(&boot, sk_v4_text, len); /* The line is waiting for an answer no one here can send. The next * line typed breaks the wait: the line that was waiting ends in an * error, and then the line just typed is done (v4/boot.h). */ while (how == V4_BOOT_LINE_WAITING) { len = sk_v4_readline(); how = v4_boot_line(&boot, sk_v4_text, len); if (how == V4_TEXT_ERROR) console_puts(" ERROR\nok> "); else if (how == V4_TEXT_COMPLETED) console_puts(" ok\nok> "); else break; how = v4_boot_line(&boot, 0, 0); } if (how == V4_TEXT_COMPLETED) console_puts(" ok\n"); else if (how == V4_TEXT_ERROR) console_puts(" ERROR\n"); else if (how == V4_BOOT_LINE_REFUSED) console_puts("Message refused\n ERROR\n"); /* the node's wire is full: error 19's words */ else if (how == V4_BOOT_LINE_STOPPED) { console_println("StarForth v4: the node stopped on a fault"); for (;;) { } } } }